Commit a378391a authored by Matthias Clasen's avatar Matthias Clasen Committed by Matthias Clasen
Browse files

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.
parent 1a3ba4fd
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,7 +391,9 @@ 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) {
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_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);
/* 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));
gdk_pixbuf_fill (area,
(gif_anim->bg_red << 24) |
(gif_anim->bg_green << 16) |
(gif_anim->bg_blue << 8));
g_object_unref (area);
if (prev_clipped_width > 0 && prev_clipped_height > 0) {
/* Clear area of previous frame to background */
GdkPixbuf *area;
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);
}
} 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;
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));
f->revert = gdk_pixbuf_copy (area);
g_object_unref (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,
clipped_width,
clipped_height);
f->revert = gdk_pixbuf_copy (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);
}
}
}
......@@ -1164,7 +1185,10 @@ gif_init (GifContext *context)
context->animation->bg_red = 0;
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
......
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