From e013fb340c50dd99676ccc4552fd6aae2e319aa8 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Sun, 21 Aug 2011 22:34:23 -0400 Subject: [PATCH] Fix animated gif segfault and frame clearing bug. * src/image.c (gif_load): Don't assume that each subimage has the same dimensions as the base image. Handle disposal method that is "undefined" by the gif spec. Fixes: debbugs:9335 --- src/ChangeLog | 6 ++++++ src/image.c | 54 +++++++++++++++++++++++++++------------------------ 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 82d75d39b40..243a39af45d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2011-08-22 Chong Yidong + + * image.c (gif_load): Don't assume that each subimage has the same + dimensions as the base image. Handle disposal method that is + "undefined" by the gif spec (Bug#9335). + 2011-08-20 Chong Yidong * eval.c (Fsignal): Handle `debug' symbol in error handler (Bug#9329). diff --git a/src/image.c b/src/image.c index d1091aec6f3..65be22b087a 100644 --- a/src/image.c +++ b/src/image.c @@ -7139,7 +7139,6 @@ gif_load (struct frame *f, struct image *img) ColorMapObject *gif_color_map; unsigned long pixel_colors[256]; GifFileType *gif; - int image_height, image_width; gif_memory_source memsrc; Lisp_Object specified_bg = image_spec_value (img->spec, QCbackground, NULL); Lisp_Object specified_file = image_spec_value (img->spec, QCfile, NULL); @@ -7216,19 +7215,13 @@ gif_load (struct frame *f, struct image *img) } } - img->corners[TOP_CORNER] = gif->SavedImages[idx].ImageDesc.Top; - img->corners[LEFT_CORNER] = gif->SavedImages[idx].ImageDesc.Left; - image_height = gif->SavedImages[idx].ImageDesc.Height; - img->corners[BOT_CORNER] = img->corners[TOP_CORNER] + image_height; - image_width = gif->SavedImages[idx].ImageDesc.Width; - img->corners[RIGHT_CORNER] = img->corners[LEFT_CORNER] + image_width; + width = img->width = gif->SWidth; + height = img->height = gif->SHeight; - width = img->width = max (gif->SWidth, - max (gif->Image.Left + gif->Image.Width, - img->corners[RIGHT_CORNER])); - height = img->height = max (gif->SHeight, - max (gif->Image.Top + gif->Image.Height, - img->corners[BOT_CORNER])); + img->corners[TOP_CORNER] = gif->SavedImages[0].ImageDesc.Top; + img->corners[LEFT_CORNER] = gif->SavedImages[0].ImageDesc.Left; + img->corners[BOT_CORNER] = img->corners[TOP_CORNER] + height; + img->corners[RIGHT_CORNER] = img->corners[LEFT_CORNER] + width; if (!check_image_size (f, width, height)) { @@ -7283,6 +7276,10 @@ gif_load (struct frame *f, struct image *img) unsigned char *raster = (unsigned char *) subimage->RasterBits; int transparency_color_index = -1; int disposal = 0; + int subimg_width = subimage->ImageDesc.Width; + int subimg_height = subimage->ImageDesc.Height; + int subimg_top = subimage->ImageDesc.Top; + int subimg_left = subimage->ImageDesc.Left; /* Find the Graphic Control Extension block for this sub-image. Extract the disposal method and transparency color. */ @@ -7306,6 +7303,13 @@ gif_load (struct frame *f, struct image *img) if (j == 0) disposal = 2; + /* For disposal == 0, the spec says "No disposal specified. The + decoder is not required to take any action." In practice, it + seems we need to treat this like "keep in place", see e.g. + http://upload.wikimedia.org/wikipedia/commons/3/37/Clock.gif */ + if (disposal == 0) + disposal = 1; + /* Allocate subimage colors. */ memset (pixel_colors, 0, sizeof pixel_colors); gif_color_map = subimage->ImageDesc.ColorMap; @@ -7333,34 +7337,34 @@ gif_load (struct frame *f, struct image *img) int row, pass; for (y = 0, row = interlace_start[0], pass = 0; - y < image_height; + y < subimg_height; y++, row += interlace_increment[pass]) { - if (row >= image_height) + if (row >= subimg_height) { row = interlace_start[++pass]; - while (row >= image_height) + while (row >= subimg_height) row = interlace_start[++pass]; } - for (x = 0; x < image_width; x++) + for (x = 0; x < subimg_width; x++) { - int c = raster[y * image_width + x]; + int c = raster[y * subimg_width + x]; if (transparency_color_index != c || disposal != 1) - XPutPixel (ximg, x + img->corners[LEFT_CORNER], - row + img->corners[TOP_CORNER], pixel_colors[c]); + XPutPixel (ximg, x + subimg_left, row + subimg_top, + pixel_colors[c]); } } } else { - for (y = 0; y < image_height; ++y) - for (x = 0; x < image_width; ++x) + for (y = 0; y < subimg_height; ++y) + for (x = 0; x < subimg_width; ++x) { - int c = raster[y * image_width + x]; + int c = raster[y * subimg_width + x]; if (transparency_color_index != c || disposal != 1) - XPutPixel (ximg, x + img->corners[LEFT_CORNER], - y + img->corners[TOP_CORNER], pixel_colors[c]); + XPutPixel (ximg, x + subimg_left, y + subimg_top, + pixel_colors[c]); } } } -- 2.39.2