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>
|
2003-06-21 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
* io-gif.c: Merge from 2.2: Fix update_func() arguments and accept empty
|
* io-gif.c: Merge from 2.2: Fix update_func() arguments and accept empty
|
||||||
|
|||||||
@ -391,7 +391,9 @@ gdk_pixbuf_gif_anim_frame_composite (GdkPixbufGifAnim *gif_anim,
|
|||||||
|
|
||||||
while (tmp != NULL) {
|
while (tmp != NULL) {
|
||||||
GdkPixbufFrame *f = tmp->data;
|
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->need_recomposite) {
|
||||||
if (f->composited) {
|
if (f->composited) {
|
||||||
g_object_unref (f->composited);
|
g_object_unref (f->composited);
|
||||||
@ -419,26 +421,17 @@ gdk_pixbuf_gif_anim_frame_composite (GdkPixbufGifAnim *gif_anim,
|
|||||||
(gif_anim->bg_green << 16) |
|
(gif_anim->bg_green << 16) |
|
||||||
(gif_anim->bg_blue << 8));
|
(gif_anim->bg_blue << 8));
|
||||||
|
|
||||||
gdk_pixbuf_composite (f->pixbuf,
|
if (clipped_width > 0 && clipped_height > 0)
|
||||||
f->composited,
|
gdk_pixbuf_composite (f->pixbuf,
|
||||||
f->x_offset,
|
f->composited,
|
||||||
f->y_offset,
|
f->x_offset,
|
||||||
gdk_pixbuf_get_width (f->pixbuf),
|
f->y_offset,
|
||||||
gdk_pixbuf_get_height (f->pixbuf),
|
clipped_width,
|
||||||
f->x_offset, f->y_offset,
|
clipped_height,
|
||||||
1.0, 1.0,
|
f->x_offset, f->y_offset,
|
||||||
GDK_INTERP_BILINEAR,
|
1.0, 1.0,
|
||||||
255);
|
GDK_INTERP_BILINEAR,
|
||||||
#if 0
|
255);
|
||||||
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 (f->action == GDK_PIXBUF_FRAME_REVERT)
|
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");
|
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;
|
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
|
/* Init f->composited with what we should have after the previous
|
||||||
* frame
|
* frame
|
||||||
*/
|
*/
|
||||||
@ -457,66 +453,71 @@ gdk_pixbuf_gif_anim_frame_composite (GdkPixbufGifAnim *gif_anim,
|
|||||||
f->composited = gdk_pixbuf_copy (prev_frame->composited);
|
f->composited = gdk_pixbuf_copy (prev_frame->composited);
|
||||||
|
|
||||||
} else if (prev_frame->action == GDK_PIXBUF_FRAME_DISPOSE) {
|
} else if (prev_frame->action == GDK_PIXBUF_FRAME_DISPOSE) {
|
||||||
GdkPixbuf *area;
|
|
||||||
|
|
||||||
f->composited = gdk_pixbuf_copy (prev_frame->composited);
|
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,
|
||||||
area = gdk_pixbuf_new_subpixbuf (f->composited,
|
prev_frame->x_offset,
|
||||||
prev_frame->x_offset,
|
prev_frame->y_offset,
|
||||||
prev_frame->y_offset,
|
prev_clipped_width,
|
||||||
gdk_pixbuf_get_width (prev_frame->pixbuf),
|
prev_clipped_height);
|
||||||
gdk_pixbuf_get_height (prev_frame->pixbuf));
|
|
||||||
|
gdk_pixbuf_fill (area,
|
||||||
gdk_pixbuf_fill (area,
|
(gif_anim->bg_red << 24) |
|
||||||
(gif_anim->bg_red << 24) |
|
(gif_anim->bg_green << 16) |
|
||||||
(gif_anim->bg_green << 16) |
|
(gif_anim->bg_blue << 8));
|
||||||
(gif_anim->bg_blue << 8));
|
|
||||||
|
g_object_unref (area);
|
||||||
g_object_unref (area);
|
}
|
||||||
|
|
||||||
} else if (prev_frame->action == GDK_PIXBUF_FRAME_REVERT) {
|
} else if (prev_frame->action == GDK_PIXBUF_FRAME_REVERT) {
|
||||||
f->composited = gdk_pixbuf_copy (prev_frame->composited);
|
f->composited = gdk_pixbuf_copy (prev_frame->composited);
|
||||||
|
if (prev_clipped_width > 0 && prev_clipped_height > 0) {
|
||||||
/* Copy in the revert frame */
|
/* Copy in the revert frame */
|
||||||
gdk_pixbuf_copy_area (prev_frame->revert,
|
gdk_pixbuf_copy_area (prev_frame->revert,
|
||||||
0, 0,
|
0, 0,
|
||||||
gdk_pixbuf_get_width (prev_frame->revert),
|
gdk_pixbuf_get_width (prev_frame->revert),
|
||||||
gdk_pixbuf_get_height (prev_frame->revert),
|
gdk_pixbuf_get_height (prev_frame->revert),
|
||||||
f->composited,
|
f->composited,
|
||||||
prev_frame->x_offset,
|
prev_frame->x_offset,
|
||||||
prev_frame->y_offset);
|
prev_frame->y_offset);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
g_warning ("Unknown revert action for GIF frame");
|
g_warning ("Unknown revert action for GIF frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f->revert == NULL &&
|
if (f->revert == NULL &&
|
||||||
f->action == GDK_PIXBUF_FRAME_REVERT) {
|
f->action == GDK_PIXBUF_FRAME_REVERT) {
|
||||||
/* We need to save the contents before compositing */
|
if (clipped_width > 0 && clipped_height > 0) {
|
||||||
GdkPixbuf *area;
|
/* We need to save the contents before compositing */
|
||||||
|
GdkPixbuf *area;
|
||||||
area = gdk_pixbuf_new_subpixbuf (f->composited,
|
|
||||||
f->x_offset,
|
area = gdk_pixbuf_new_subpixbuf (f->composited,
|
||||||
f->y_offset,
|
f->x_offset,
|
||||||
gdk_pixbuf_get_width (f->pixbuf),
|
f->y_offset,
|
||||||
gdk_pixbuf_get_height (f->pixbuf));
|
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 */
|
if (clipped_width > 0 && clipped_height > 0) {
|
||||||
gdk_pixbuf_composite (f->pixbuf,
|
/* Put current frame onto f->composited */
|
||||||
f->composited,
|
gdk_pixbuf_composite (f->pixbuf,
|
||||||
f->x_offset,
|
f->composited,
|
||||||
f->y_offset,
|
f->x_offset,
|
||||||
gdk_pixbuf_get_width (f->pixbuf),
|
f->y_offset,
|
||||||
gdk_pixbuf_get_height (f->pixbuf),
|
clipped_width,
|
||||||
f->x_offset, f->y_offset,
|
clipped_height,
|
||||||
1.0, 1.0,
|
f->x_offset, f->y_offset,
|
||||||
GDK_INTERP_NEAREST,
|
1.0, 1.0,
|
||||||
255);
|
GDK_INTERP_NEAREST,
|
||||||
|
255);
|
||||||
|
}
|
||||||
|
|
||||||
f->need_recomposite = FALSE;
|
f->need_recomposite = FALSE;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -410,8 +410,8 @@ gif_get_extension (GifContext *context)
|
|||||||
if (!strncmp (context->block_buf, "NETSCAPE2.0", 11) ||
|
if (!strncmp (context->block_buf, "NETSCAPE2.0", 11) ||
|
||||||
!strncmp (context->block_buf, "ANIMEXTS1.0", 11)) {
|
!strncmp (context->block_buf, "ANIMEXTS1.0", 11)) {
|
||||||
context->in_loop_extension = TRUE;
|
context->in_loop_extension = TRUE;
|
||||||
context->block_count = 0;
|
|
||||||
}
|
}
|
||||||
|
context->block_count = 0;
|
||||||
}
|
}
|
||||||
if (context->in_loop_extension) {
|
if (context->in_loop_extension) {
|
||||||
do {
|
do {
|
||||||
@ -777,6 +777,49 @@ set_need_recomposite (gpointer data, gpointer user_data)
|
|||||||
frame->need_recomposite = TRUE;
|
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
|
static int
|
||||||
gif_get_lzw (GifContext *context)
|
gif_get_lzw (GifContext *context)
|
||||||
@ -863,25 +906,8 @@ gif_get_lzw (GifContext *context)
|
|||||||
|
|
||||||
context->frame->bg_transparent = (context->gif89.transparent == context->background_index);
|
context->frame->bg_transparent = (context->gif89.transparent == context->background_index);
|
||||||
|
|
||||||
{
|
context->animation->n_frames ++;
|
||||||
/* Update animation size */
|
context->animation->frames = g_list_append (context->animation->frames, context->frame);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Only call prepare_func for the first frame */
|
/* Only call prepare_func for the first frame */
|
||||||
if (context->animation->frames->next == NULL) {
|
if (context->animation->frames->next == NULL) {
|
||||||
@ -893,6 +919,7 @@ gif_get_lzw (GifContext *context)
|
|||||||
/* Otherwise init frame with last frame */
|
/* Otherwise init frame with last frame */
|
||||||
GList *link;
|
GList *link;
|
||||||
GdkPixbufFrame *prev_frame;
|
GdkPixbufFrame *prev_frame;
|
||||||
|
gint x, y, w, h;
|
||||||
|
|
||||||
link = g_list_find (context->animation->frames, context->frame);
|
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_gif_anim_frame_composite (context->animation, prev_frame);
|
||||||
|
|
||||||
gdk_pixbuf_copy_area (prev_frame->composited,
|
x = context->frame->x_offset;
|
||||||
context->frame->x_offset,
|
y = context->frame->y_offset;
|
||||||
context->frame->y_offset,
|
w = gdk_pixbuf_get_width (context->frame->pixbuf);
|
||||||
gdk_pixbuf_get_width (context->frame->pixbuf),
|
h = gdk_pixbuf_get_height (context->frame->pixbuf);
|
||||||
gdk_pixbuf_get_height (context->frame->pixbuf),
|
if (clip_frame (context, &x, &y, &w, &h))
|
||||||
context->frame->pixbuf,
|
gdk_pixbuf_copy_area (prev_frame->composited,
|
||||||
0, 0);
|
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 (bound_flag && context->update_func) {
|
||||||
if (lower_bound <= upper_bound && first_pass == context->draw_pass) {
|
if (lower_bound <= upper_bound && first_pass == context->draw_pass) {
|
||||||
(* context->update_func)
|
maybe_update (context,
|
||||||
(context->frame->pixbuf,
|
context->frame->x_offset,
|
||||||
context->frame->x_offset,
|
context->frame->y_offset + lower_bound,
|
||||||
context->frame->y_offset + lower_bound,
|
gdk_pixbuf_get_width (context->frame->pixbuf),
|
||||||
gdk_pixbuf_get_width (context->frame->pixbuf),
|
upper_bound - lower_bound);
|
||||||
upper_bound - lower_bound,
|
|
||||||
context->user_data);
|
|
||||||
} else {
|
} else {
|
||||||
if (lower_bound <= upper_bound) {
|
if (lower_bound <= upper_bound) {
|
||||||
(* context->update_func)
|
maybe_update (context,
|
||||||
(context->frame->pixbuf,
|
context->frame->x_offset,
|
||||||
context->frame->x_offset,
|
context->frame->y_offset,
|
||||||
context->frame->y_offset,
|
gdk_pixbuf_get_width (context->frame->pixbuf),
|
||||||
gdk_pixbuf_get_width (context->frame->pixbuf),
|
gdk_pixbuf_get_height (context->frame->pixbuf));
|
||||||
gdk_pixbuf_get_height (context->frame->pixbuf),
|
|
||||||
context->user_data);
|
|
||||||
} else {
|
} else {
|
||||||
(* context->update_func)
|
maybe_update (context,
|
||||||
(context->frame->pixbuf,
|
context->frame->x_offset,
|
||||||
context->frame->x_offset,
|
context->frame->y_offset,
|
||||||
context->frame->y_offset,
|
gdk_pixbuf_get_width (context->frame->pixbuf),
|
||||||
gdk_pixbuf_get_width (context->frame->pixbuf),
|
upper_bound);
|
||||||
upper_bound,
|
maybe_update (context,
|
||||||
context->user_data);
|
context->frame->x_offset,
|
||||||
(* context->update_func)
|
context->frame->y_offset + lower_bound,
|
||||||
(context->frame->pixbuf,
|
gdk_pixbuf_get_width (context->frame->pixbuf),
|
||||||
context->frame->x_offset,
|
gdk_pixbuf_get_height (context->frame->pixbuf) - lower_bound);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1164,7 +1185,10 @@ gif_init (GifContext *context)
|
|||||||
context->animation->bg_red = 0;
|
context->animation->bg_red = 0;
|
||||||
context->animation->bg_green = 0;
|
context->animation->bg_green = 0;
|
||||||
context->animation->bg_blue = 0;
|
context->animation->bg_blue = 0;
|
||||||
|
|
||||||
|
context->animation->width = context->width;
|
||||||
|
context->animation->height = context->height;
|
||||||
|
|
||||||
if (context->has_global_cmap) {
|
if (context->has_global_cmap) {
|
||||||
gif_set_get_colormap (context);
|
gif_set_get_colormap (context);
|
||||||
} else {
|
} else {
|
||||||
@ -1200,19 +1224,6 @@ gif_get_frame_info (GifContext *context)
|
|||||||
context->x_offset = LM_to_uint (buf[0], buf[1]);
|
context->x_offset = LM_to_uint (buf[0], buf[1]);
|
||||||
context->y_offset = LM_to_uint (buf[2], buf[3]);
|
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 &&
|
if (context->animation->frames == NULL &&
|
||||||
context->gif89.disposal == 3) {
|
context->gif89.disposal == 3) {
|
||||||
/* First frame can't have "revert to previous" as its
|
/* First frame can't have "revert to previous" as its
|
||||||
|
|||||||
Reference in New Issue
Block a user