aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog4
-rw-r--r--src/image.c232
2 files changed, 129 insertions, 107 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 7452b53da5b..6afb661e759 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,7 @@
12011-06-06 Chong Yidong <cyd@stupidchicken.com>
2
3 * image.c (gif_load): Implement gif89a spec "no disposal" method.
4
12011-06-06 Paul Eggert <eggert@cs.ucla.edu> 52011-06-06 Paul Eggert <eggert@cs.ucla.edu>
2 6
3 Cons<->int and similar integer overflow fixes (Bug#8794). 7 Cons<->int and similar integer overflow fixes (Bug#8794).
diff --git a/src/image.c b/src/image.c
index a179568cb85..cdf05c78764 100644
--- a/src/image.c
+++ b/src/image.c
@@ -7074,22 +7074,19 @@ static const int interlace_increment[] = {8, 8, 4, 2};
7074static int 7074static int
7075gif_load (struct frame *f, struct image *img) 7075gif_load (struct frame *f, struct image *img)
7076{ 7076{
7077 Lisp_Object file, specified_file; 7077 Lisp_Object file;
7078 Lisp_Object specified_data; 7078 int rc, width, height, x, y, i, j;
7079 int rc, width, height, x, y, i;
7080 boolean transparent_p = 0;
7081 XImagePtr ximg; 7079 XImagePtr ximg;
7082 ColorMapObject *gif_color_map; 7080 ColorMapObject *gif_color_map;
7083 unsigned long pixel_colors[256]; 7081 unsigned long pixel_colors[256];
7084 GifFileType *gif; 7082 GifFileType *gif;
7085 Lisp_Object image; 7083 int image_height, image_width;
7086 int ino, image_height, image_width;
7087 gif_memory_source memsrc; 7084 gif_memory_source memsrc;
7088 unsigned char *raster; 7085 Lisp_Object specified_bg = image_spec_value (img->spec, QCbackground, NULL);
7089 unsigned int transparency_color_index IF_LINT (= 0); 7086 Lisp_Object specified_file = image_spec_value (img->spec, QCfile, NULL);
7090 7087 Lisp_Object specified_data = image_spec_value (img->spec, QCdata, NULL);
7091 specified_file = image_spec_value (img->spec, QCfile, NULL); 7088 unsigned long bgcolor = 0;
7092 specified_data = image_spec_value (img->spec, QCdata, NULL); 7089 int idx;
7093 7090
7094 if (NILP (specified_data)) 7091 if (NILP (specified_data))
7095 { 7092 {
@@ -7140,40 +7137,31 @@ gif_load (struct frame *f, struct image *img)
7140 7137
7141 /* Read entire contents. */ 7138 /* Read entire contents. */
7142 rc = fn_DGifSlurp (gif); 7139 rc = fn_DGifSlurp (gif);
7143 if (rc == GIF_ERROR) 7140 if (rc == GIF_ERROR || gif->ImageCount <= 0)
7144 { 7141 {
7145 image_error ("Error reading `%s'", img->spec, Qnil); 7142 image_error ("Error reading `%s'", img->spec, Qnil);
7146 fn_DGifCloseFile (gif); 7143 fn_DGifCloseFile (gif);
7147 return 0; 7144 return 0;
7148 } 7145 }
7149 7146
7150 image = image_spec_value (img->spec, QCindex, NULL); 7147 /* Which sub-image are we to display? */
7151 ino = INTEGERP (image) ? XFASTINT (image) : 0; 7148 {
7152 if (ino >= gif->ImageCount) 7149 Lisp_Object index = image_spec_value (img->spec, QCindex, NULL);
7153 { 7150 idx = INTEGERP (index) ? XFASTINT (index) : 0;
7154 image_error ("Invalid image number `%s' in image `%s'", 7151 if (idx < 0 || idx >= gif->ImageCount)
7155 image, img->spec);
7156 fn_DGifCloseFile (gif);
7157 return 0;
7158 }
7159
7160 for (i = 0; i < gif->SavedImages[ino].ExtensionBlockCount; i++)
7161 if ((gif->SavedImages[ino].ExtensionBlocks[i].Function
7162 == GIF_LOCAL_DESCRIPTOR_EXTENSION)
7163 && gif->SavedImages[ino].ExtensionBlocks[i].ByteCount == 4
7164 /* Transparency enabled? */
7165 && gif->SavedImages[ino].ExtensionBlocks[i].Bytes[0] & 1)
7166 { 7152 {
7167 transparent_p = 1; 7153 image_error ("Invalid image number `%s' in image `%s'",
7168 transparency_color_index 7154 index, img->spec);
7169 = (unsigned char) gif->SavedImages[ino].ExtensionBlocks[i].Bytes[3]; 7155 fn_DGifCloseFile (gif);
7156 return 0;
7170 } 7157 }
7158 }
7171 7159
7172 img->corners[TOP_CORNER] = gif->SavedImages[ino].ImageDesc.Top; 7160 img->corners[TOP_CORNER] = gif->SavedImages[idx].ImageDesc.Top;
7173 img->corners[LEFT_CORNER] = gif->SavedImages[ino].ImageDesc.Left; 7161 img->corners[LEFT_CORNER] = gif->SavedImages[idx].ImageDesc.Left;
7174 image_height = gif->SavedImages[ino].ImageDesc.Height; 7162 image_height = gif->SavedImages[idx].ImageDesc.Height;
7175 img->corners[BOT_CORNER] = img->corners[TOP_CORNER] + image_height; 7163 img->corners[BOT_CORNER] = img->corners[TOP_CORNER] + image_height;
7176 image_width = gif->SavedImages[ino].ImageDesc.Width; 7164 image_width = gif->SavedImages[idx].ImageDesc.Width;
7177 img->corners[RIGHT_CORNER] = img->corners[LEFT_CORNER] + image_width; 7165 img->corners[RIGHT_CORNER] = img->corners[LEFT_CORNER] + image_width;
7178 7166
7179 width = img->width = max (gif->SWidth, 7167 width = img->width = max (gif->SWidth,
@@ -7197,44 +7185,10 @@ gif_load (struct frame *f, struct image *img)
7197 return 0; 7185 return 0;
7198 } 7186 }
7199 7187
7200 /* Allocate colors. */ 7188 /* Clear the part of the screen image not covered by the image.
7201 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap; 7189 Full animated GIF support requires more here (see the gif89 spec,
7202 if (!gif_color_map) 7190 disposal methods). Let's simply assume that the part not covered
7203 gif_color_map = gif->SColorMap; 7191 by a sub-image is in the frame's background color. */
7204 init_color_table ();
7205 memset (pixel_colors, 0, sizeof pixel_colors);
7206
7207 if (gif_color_map)
7208 for (i = 0; i < gif_color_map->ColorCount; ++i)
7209 {
7210 if (transparent_p && transparency_color_index == i)
7211 {
7212 Lisp_Object specified_bg
7213 = image_spec_value (img->spec, QCbackground, NULL);
7214 pixel_colors[i] = STRINGP (specified_bg)
7215 ? x_alloc_image_color (f, img, specified_bg,
7216 FRAME_BACKGROUND_PIXEL (f))
7217 : FRAME_BACKGROUND_PIXEL (f);
7218 }
7219 else
7220 {
7221 int r = gif_color_map->Colors[i].Red << 8;
7222 int g = gif_color_map->Colors[i].Green << 8;
7223 int b = gif_color_map->Colors[i].Blue << 8;
7224 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
7225 }
7226 }
7227
7228#ifdef COLOR_TABLE_SUPPORT
7229 img->colors = colors_in_color_table (&img->ncolors);
7230 free_color_table ();
7231#endif /* COLOR_TABLE_SUPPORT */
7232
7233 /* Clear the part of the screen image that are not covered by
7234 the image from the GIF file. Full animated GIF support
7235 requires more than can be done here (see the gif89 spec,
7236 disposal methods). Let's simply assume that the part
7237 not covered by a sub-image is in the frame's background color. */
7238 for (y = 0; y < img->corners[TOP_CORNER]; ++y) 7192 for (y = 0; y < img->corners[TOP_CORNER]; ++y)
7239 for (x = 0; x < width; ++x) 7193 for (x = 0; x < width; ++x)
7240 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); 7194 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
@@ -7251,55 +7205,119 @@ gif_load (struct frame *f, struct image *img)
7251 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); 7205 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
7252 } 7206 }
7253 7207
7254 /* Read the GIF image into the X image. We use a local variable 7208 /* Read the GIF image into the X image. */
7255 `raster' here because RasterBits below is a char *, and invites
7256 problems with bytes >= 0x80. */
7257 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
7258
7259 if (gif->SavedImages[ino].ImageDesc.Interlace)
7260 {
7261 int pass;
7262 int row = interlace_start[0];
7263 7209
7264 pass = 0; 7210 /* FIXME: With the current implementation, loading an animated gif
7211 is quadratic in the number of animation frames, since each frame
7212 is a separate struct image. We must provide a way for a single
7213 gif_load call to construct and save all animation frames. */
7265 7214
7266 for (y = 0; y < image_height; y++) 7215 init_color_table ();
7216 if (STRINGP (specified_bg))
7217 bgcolor = x_alloc_image_color (f, img, specified_bg,
7218 FRAME_BACKGROUND_PIXEL (f));
7219 for (j = 0; j <= idx; ++j)
7220 {
7221 /* We use a local variable `raster' here because RasterBits is a
7222 char *, which invites problems with bytes >= 0x80. */
7223 struct SavedImage *subimage = gif->SavedImages + j;
7224 unsigned char *raster = (unsigned char *) subimage->RasterBits;
7225 int transparency_color_index = -1;
7226 int disposal = 0;
7227
7228 /* Find the Graphic Control Extension block for this sub-image.
7229 Extract the disposal method and transparency color. */
7230 for (i = 0; i < subimage->ExtensionBlockCount; i++)
7267 { 7231 {
7268 if (row >= image_height) 7232 ExtensionBlock *extblock = subimage->ExtensionBlocks + i;
7269 {
7270 row = interlace_start[++pass];
7271 while (row >= image_height)
7272 row = interlace_start[++pass];
7273 }
7274 7233
7275 for (x = 0; x < image_width; x++) 7234 if ((extblock->Function == GIF_LOCAL_DESCRIPTOR_EXTENSION)
7235 && extblock->ByteCount == 4
7236 && extblock->Bytes[0] & 1)
7276 { 7237 {
7277 int c = raster[(y * image_width) + x]; 7238 /* From gif89a spec: 1 = "keep in place", 2 = "restore
7278 XPutPixel (ximg, x + img->corners[LEFT_CORNER], 7239 to background". Treat any other value like 2. */
7279 row + img->corners[TOP_CORNER], pixel_colors[c]); 7240 disposal = (extblock->Bytes[0] >> 2) & 7;
7241 transparency_color_index = extblock->Bytes[3];
7242 break;
7280 } 7243 }
7281
7282 row += interlace_increment[pass];
7283 } 7244 }
7284 } 7245
7285 else 7246 /* We can't "keep in place" the first subimage. */
7286 { 7247 if (j == 0)
7287 for (y = 0; y < image_height; ++y) 7248 disposal = 2;
7288 for (x = 0; x < image_width; ++x) 7249
7250 /* Allocate subimage colors. */
7251 memset (pixel_colors, 0, sizeof pixel_colors);
7252 gif_color_map = subimage->ImageDesc.ColorMap;
7253 if (!gif_color_map)
7254 gif_color_map = gif->SColorMap;
7255
7256 if (gif_color_map)
7257 for (i = 0; i < gif_color_map->ColorCount; ++i)
7289 { 7258 {
7290 int c = raster[y * image_width + x]; 7259 if (transparency_color_index == i)
7291 XPutPixel (ximg, x + img->corners[LEFT_CORNER], 7260 pixel_colors[i] = STRINGP (specified_bg)
7292 y + img->corners[TOP_CORNER], pixel_colors[c]); 7261 ? bgcolor : FRAME_BACKGROUND_PIXEL (f);
7262 else
7263 {
7264 int r = gif_color_map->Colors[i].Red << 8;
7265 int g = gif_color_map->Colors[i].Green << 8;
7266 int b = gif_color_map->Colors[i].Blue << 8;
7267 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
7268 }
7293 } 7269 }
7270
7271 /* Apply the pixel values. */
7272 if (gif->SavedImages[j].ImageDesc.Interlace)
7273 {
7274 int row, pass;
7275
7276 for (y = 0, row = interlace_start[0], pass = 0;
7277 y < image_height;
7278 y++, row += interlace_increment[pass])
7279 {
7280 if (row >= image_height)
7281 {
7282 row = interlace_start[++pass];
7283 while (row >= image_height)
7284 row = interlace_start[++pass];
7285 }
7286
7287 for (x = 0; x < image_width; x++)
7288 {
7289 int c = raster[y * image_width + x];
7290 if (transparency_color_index != c || disposal != 1)
7291 XPutPixel (ximg, x + img->corners[LEFT_CORNER],
7292 row + img->corners[TOP_CORNER], pixel_colors[c]);
7293 }
7294 }
7295 }
7296 else
7297 {
7298 for (y = 0; y < image_height; ++y)
7299 for (x = 0; x < image_width; ++x)
7300 {
7301 int c = raster[y * image_width + x];
7302 if (transparency_color_index != c || disposal != 1)
7303 XPutPixel (ximg, x + img->corners[LEFT_CORNER],
7304 y + img->corners[TOP_CORNER], pixel_colors[c]);
7305 }
7306 }
7294 } 7307 }
7295 7308
7309#ifdef COLOR_TABLE_SUPPORT
7310 img->colors = colors_in_color_table (&img->ncolors);
7311 free_color_table ();
7312#endif /* COLOR_TABLE_SUPPORT */
7313
7296 /* Save GIF image extension data for `image-metadata'. 7314 /* Save GIF image extension data for `image-metadata'.
7297 Format is (count IMAGES extension-data (FUNCTION "BYTES" ...)). */ 7315 Format is (count IMAGES extension-data (FUNCTION "BYTES" ...)). */
7298 img->data.lisp_val = Qnil; 7316 img->data.lisp_val = Qnil;
7299 if (gif->SavedImages[ino].ExtensionBlockCount > 0) 7317 if (gif->SavedImages[idx].ExtensionBlockCount > 0)
7300 { 7318 {
7301 ExtensionBlock *ext = gif->SavedImages[ino].ExtensionBlocks; 7319 ExtensionBlock *ext = gif->SavedImages[idx].ExtensionBlocks;
7302 for (i = 0; i < gif->SavedImages[ino].ExtensionBlockCount; i++, ext++) 7320 for (i = 0; i < gif->SavedImages[idx].ExtensionBlockCount; i++, ext++)
7303 /* Append (... FUNCTION "BYTES") */ 7321 /* Append (... FUNCTION "BYTES") */
7304 img->data.lisp_val = Fcons (make_unibyte_string (ext->Bytes, ext->ByteCount), 7322 img->data.lisp_val = Fcons (make_unibyte_string (ext->Bytes, ext->ByteCount),
7305 Fcons (make_number (ext->Function), 7323 Fcons (make_number (ext->Function),