use dynwind_begin and dynwind_end
[bpt/emacs.git] / src / image.c
index 38a9227..7fa2884 100644 (file)
@@ -1,6 +1,6 @@
 /* Functions for image support on window system.
 
-Copyright (C) 1989, 1992-2013 Free Software Foundation, Inc.
+Copyright (C) 1989, 1992-2014 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -21,13 +21,11 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "sysstdio.h"
 #include <unistd.h>
 
-#ifdef HAVE_PNG
-#if defined HAVE_LIBPNG_PNG_H
-# include <libpng/png.h>
-#else
+/* Include this before including <setjmp.h> to work around bugs with
+   older libpng; see Bug#17429.  */
+#if defined HAVE_PNG && !defined HAVE_NS
 # include <png.h>
 #endif
-#endif
 
 #include <setjmp.h>
 #include <c-ctype.h>
@@ -160,6 +158,7 @@ XPutPixel (XImagePtr ximage, int x, int y, unsigned long pixel)
 
 /* Functions to access the contents of a bitmap, given an id.  */
 
+#ifdef HAVE_X_WINDOWS
 static int
 x_bitmap_height (struct frame *f, ptrdiff_t id)
 {
@@ -171,6 +170,7 @@ x_bitmap_width (struct frame *f, ptrdiff_t id)
 {
   return FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].width;
 }
+#endif
 
 #if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
 ptrdiff_t
@@ -264,7 +264,7 @@ x_create_bitmap_from_data (struct frame *f, char *bits, unsigned int width, unsi
 
 #ifdef HAVE_X_WINDOWS
   dpyinfo->bitmaps[id - 1].pixmap = bitmap;
-  dpyinfo->bitmaps[id - 1].have_mask = 0;
+  dpyinfo->bitmaps[id - 1].have_mask = false;
   dpyinfo->bitmaps[id - 1].depth = 1;
 #endif /* HAVE_X_WINDOWS */
 
@@ -327,7 +327,9 @@ x_create_bitmap_from_file (struct frame *f, Lisp_Object file)
     }
 
   /* Search bitmap-file-path for the file, if appropriate.  */
-  if (openp (Vx_bitmap_file_path, file, Qnil, &found, make_number (R_OK)) < 0)
+  if (openp (Vx_bitmap_file_path, file, Qnil, &found,
+            make_number (R_OK), false)
+      < 0)
     return -1;
 
   filename = SSDATA (found);
@@ -339,7 +341,7 @@ x_create_bitmap_from_file (struct frame *f, Lisp_Object file)
 
   id = x_allocate_bitmap_record (f);
   dpyinfo->bitmaps[id - 1].pixmap = bitmap;
-  dpyinfo->bitmaps[id - 1].have_mask = 0;
+  dpyinfo->bitmaps[id - 1].have_mask = false;
   dpyinfo->bitmaps[id - 1].refcount = 1;
   dpyinfo->bitmaps[id - 1].file = xlispstrdup (file);
   dpyinfo->bitmaps[id - 1].depth = 1;
@@ -515,7 +517,7 @@ x_create_bitmap_mask (struct frame *f, ptrdiff_t id)
             width, height);
   XFreeGC (FRAME_X_DISPLAY (f), gc);
 
-  dpyinfo->bitmaps[id - 1].have_mask = 1;
+  dpyinfo->bitmaps[id - 1].have_mask = true;
   dpyinfo->bitmaps[id - 1].mask = mask;
 
   XDestroyImage (ximg);
@@ -996,6 +998,11 @@ free_image (struct frame *f, struct image *img)
 
       c->images[img->id] = NULL;
 
+      /* Windows NT redefines 'free', but in this file, we need to
+         avoid the redefinition.  */
+#ifdef WINDOWSNT
+#undef free
+#endif
       /* Free resources, then free IMG.  */
       img->type->free (f, img);
       xfree (img);
@@ -1229,7 +1236,23 @@ image_background_transparent (struct image *img, struct frame *f, XImagePtr_or_D
   return img->background_transparent;
 }
 
-\f
+#if defined (HAVE_PNG) || defined (HAVE_NS) \
+  || defined (HAVE_IMAGEMAGICK) || defined (HAVE_RSVG)
+
+/* Store F's background color into *BGCOLOR.  */
+static void
+x_query_frame_background_color (struct frame *f, XColor *bgcolor)
+{
+#ifndef HAVE_NS
+  bgcolor->pixel = FRAME_BACKGROUND_PIXEL (f);
+  x_query_color (f, bgcolor);
+#else
+  ns_query_color (FRAME_BACKGROUND_COLOR (f), bgcolor, 1);
+#endif
+}
+
+#endif /* HAVE_PNG || HAVE_NS || HAVE_IMAGEMAGICK || HAVE_RSVG */
+
 /***********************************************************************
                  Helper functions for X image types
  ***********************************************************************/
@@ -1799,37 +1822,6 @@ cache_image (struct frame *f, struct image *img)
   img->prev = NULL;
   c->buckets[i] = img;
 }
-
-
-/* Call FN on every image in the image cache of frame F.  Used to mark
-   Lisp Objects in the image cache.  */
-
-/* Mark Lisp objects in image IMG.  */
-
-static void
-mark_image (struct image *img)
-{
-  mark_object (img->spec);
-  mark_object (img->dependencies);
-
-  if (!NILP (img->lisp_data))
-    mark_object (img->lisp_data);
-}
-
-
-void
-mark_image_cache (struct image_cache *c)
-{
-  if (c)
-    {
-      ptrdiff_t i;
-      for (i = 0; i < c->used; ++i)
-       if (c->images[i])
-         mark_image (c->images[i]);
-    }
-}
-
-
 \f
 /***********************************************************************
                          X / NS / W32 support code
@@ -1928,7 +1920,7 @@ x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth,
     }
 
   /* Allocate image raster.  */
-  (*ximg)->data = xmalloc ((*ximg)->bytes_per_line * height);
+  (*ximg)->data = xmalloc_atomic ((*ximg)->bytes_per_line * height);
 
   /* Allocate a pixmap of the same size.  */
   *pixmap = XCreatePixmap (display, window, width, height, depth);
@@ -2017,6 +2009,7 @@ x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth,
       XSETINT (errcode, err);
       image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
       x_destroy_x_image (*ximg);
+      *ximg = NULL;
       return 0;
     }
 
@@ -2242,7 +2235,7 @@ x_find_image_file (Lisp_Object file)
                       Vx_bitmap_file_path);
 
   /* Try to find FILE in data-directory/images, then x-bitmap-file-path.  */
-  fd = openp (search_path, file, Qnil, &file_found, Qnil);
+  fd = openp (search_path, file, Qnil, &file_found, Qnil, false);
 
   if (fd == -1)
     file_found = Qnil;
@@ -2270,7 +2263,7 @@ slurp_file (char *file, ptrdiff_t *size)
 
   if (fp)
     {
-      ptrdiff_t count = SPECPDL_INDEX ();
+      dynwind_begin ();
       record_unwind_protect_ptr (fclose_unwind, fp);
 
       if (fstat (fileno (fp), &st) == 0
@@ -2289,7 +2282,7 @@ slurp_file (char *file, ptrdiff_t *size)
            }
        }
 
-      unbind_to (count, Qnil);
+      dynwind_end ();
     }
 
   return buf;
@@ -2795,7 +2788,7 @@ xbm_read_bitmap_data (struct frame *f, unsigned char *contents, unsigned char *e
     }
   bytes_per_line = (*width + 7) / 8 + padding_p;
   nbytes = bytes_per_line * *height;
-  p = *data = xmalloc (nbytes);
+  p = *data = xmalloc_atomic (nbytes);
 
   if (v10)
     {
@@ -3446,7 +3439,7 @@ x_create_bitmap_from_xpm_data (struct frame *f, const char **bits)
 
   id = x_allocate_bitmap_record (f);
   dpyinfo->bitmaps[id - 1].pixmap = bitmap;
-  dpyinfo->bitmaps[id - 1].have_mask = 1;
+  dpyinfo->bitmaps[id - 1].have_mask = true;
   dpyinfo->bitmaps[id - 1].mask = mask;
   dpyinfo->bitmaps[id - 1].file = NULL;
   dpyinfo->bitmaps[id - 1].height = attrs.height;
@@ -3694,7 +3687,8 @@ xpm_load (struct frame *f, struct image *img)
 #endif /* HAVE_NTGUI */
 
       /* Remember allocated colors.  */
-      img->colors = xnmalloc (attrs.nalloc_pixels, sizeof *img->colors);
+      img->colors = xnmalloc_atomic (attrs.nalloc_pixels,
+                                     sizeof *img->colors);
       img->ncolors = attrs.nalloc_pixels;
       for (i = 0; i < attrs.nalloc_pixels; ++i)
        {
@@ -3950,9 +3944,7 @@ xpm_str_to_color_key (const char *s)
 {
   int i;
 
-  for (i = 0;
-       i < sizeof xpm_color_key_strings / sizeof xpm_color_key_strings[0];
-       i++)
+  for (i = 0; i < ARRAYELTS (xpm_color_key_strings); i++)
     if (strcmp (xpm_color_key_strings[i], s) == 0)
       return i;
   return -1;
@@ -3974,7 +3966,7 @@ xpm_load_image (struct frame *f,
   Lisp_Object (*get_color_table) (Lisp_Object, const unsigned char *, int);
   Lisp_Object frame, color_symbols, color_table;
   int best_key;
-  bool have_mask = 0;
+  bool have_mask = false;
   XImagePtr ximg = NULL, mask_img = NULL;
 
 #define match() \
@@ -4146,7 +4138,7 @@ xpm_load_image (struct frame *f,
 #ifndef HAVE_NS
          XPutPixel (mask_img, x, y,
                     (!EQ (color_val, Qt) ? PIX_MASK_DRAW
-                     : (have_mask = 1, PIX_MASK_RETAIN)));
+                     : (have_mask = true, PIX_MASK_RETAIN)));
 #else
           if (EQ (color_val, Qt))
             ns_set_alpha (ximg, x, y, 0);
@@ -4491,7 +4483,7 @@ colors_in_color_table (int *n)
     }
   else
     {
-      colors = xmalloc (ct_colors_allocated * sizeof *colors);
+      colors = xmalloc_atomic (ct_colors_allocated * sizeof *colors);
       *n = ct_colors_allocated;
 
       for (i = j = 0; i < CT_SIZE; ++i)
@@ -5213,6 +5205,7 @@ pbm_load (struct frame *f, struct image *img)
       image_error ("Not a PBM image: `%s'", img->spec, Qnil);
     error:
       xfree (contents);
+      img->pixmap = NO_PIXMAP;
       return 0;
     }
 
@@ -5502,7 +5495,7 @@ png_image_p (Lisp_Object object)
 #endif /* HAVE_PNG || HAVE_NS */
 
 
-#ifdef HAVE_PNG
+#if defined HAVE_PNG && !defined HAVE_NS
 
 #ifdef WINDOWSNT
 /* PNG library details.  */
@@ -5534,7 +5527,7 @@ DEF_IMGLIB_FN (void, png_read_end, (png_structp, png_infop));
 DEF_IMGLIB_FN (void, png_error, (png_structp, png_const_charp));
 
 #if (PNG_LIBPNG_VER >= 10500)
-DEF_IMGLIB_FN (void, png_longjmp, (png_structp, int));
+DEF_IMGLIB_FN (void, png_longjmp, (png_structp, int)) PNG_NORETURN;
 DEF_IMGLIB_FN (jmp_buf *, png_set_longjmp_fn, (png_structp, png_longjmp_ptr, size_t));
 #endif /* libpng version >= 1.5 */
 
@@ -5606,24 +5599,26 @@ init_png_functions (void)
 
 #endif /* WINDOWSNT */
 
-/* Possibly inefficient/inexact substitutes for _setjmp and _longjmp.
-   Do not use sys_setjmp, as PNG supports only jmp_buf.  The _longjmp
-   substitute may munge the signal mask, but that should be OK here.
-   MinGW (MS-Windows) uses _setjmp and defines setjmp to _setjmp in
-   the system header setjmp.h; don't mess up that.  */
-#ifndef HAVE__SETJMP
-# define _setjmp(j) setjmp (j)
-# define _longjmp longjmp
+/* Fast implementations of setjmp and longjmp.  Although setjmp and longjmp
+   will do, POSIX _setjmp and _longjmp (if available) are often faster.
+   Do not use sys_setjmp, as PNG supports only jmp_buf.
+   It's OK if the longjmp substitute restores the signal mask.  */
+#ifdef HAVE__SETJMP
+# define FAST_SETJMP(j) _setjmp (j)
+# define FAST_LONGJMP _longjmp
+#else
+# define FAST_SETJMP(j) setjmp (j)
+# define FAST_LONGJMP longjmp
 #endif
 
-#if (PNG_LIBPNG_VER < 10500)
-#define PNG_LONGJMP(ptr) (_longjmp ((ptr)->jmpbuf, 1))
+#if PNG_LIBPNG_VER < 10500
+#define PNG_LONGJMP(ptr) FAST_LONGJMP ((ptr)->jmpbuf, 1)
 #define PNG_JMPBUF(ptr) ((ptr)->jmpbuf)
 #else
 /* In libpng version 1.5, the jmpbuf member is hidden. (Bug#7908)  */
-#define PNG_LONGJMP(ptr) (fn_png_longjmp ((ptr), 1))
+#define PNG_LONGJMP(ptr) fn_png_longjmp (ptr, 1)
 #define PNG_JMPBUF(ptr) \
-  (*fn_png_set_longjmp_fn ((ptr), _longjmp, sizeof (jmp_buf)))
+  (*fn_png_set_longjmp_fn (ptr, FAST_LONGJMP, sizeof (jmp_buf)))
 #endif
 
 /* Error and warning handlers installed when the PNG library
@@ -5808,7 +5803,7 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
 
   /* Set error jump-back.  We come back here when the PNG library
      detects an error.  */
-  if (_setjmp (PNG_JMPBUF (png_ptr)))
+  if (FAST_SETJMP (PNG_JMPBUF (png_ptr)))
     {
     error:
       if (c->png_ptr)
@@ -5878,43 +5873,23 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
       /* png_color_16 *image_bg; */
       Lisp_Object specified_bg
        = image_spec_value (img->spec, QCbackground, NULL);
-      int shift = (bit_depth == 16) ? 0 : 8;
+      XColor color;
 
-      if (STRINGP (specified_bg))
+      /* If the user specified a color, try to use it; if not, use the
+        current frame background, ignoring any default background
+        color set by the image.  */
+      if (STRINGP (specified_bg)
+         ? x_defined_color (f, SSDATA (specified_bg), &color, false)
+         : (x_query_frame_background_color (f, &color), true))
        /* The user specified `:background', use that.  */
        {
-         XColor color;
-         if (x_defined_color (f, SSDATA (specified_bg), &color, 0))
-           {
-             png_color_16 user_bg;
-
-             memset (&user_bg, 0, sizeof user_bg);
-             user_bg.red = color.red >> shift;
-             user_bg.green = color.green >> shift;
-             user_bg.blue = color.blue >> shift;
-
-             fn_png_set_background (png_ptr, &user_bg,
-                                    PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
-           }
-       }
-      else
-       {
-         /* We use the current frame background, ignoring any default
-            background color set by the image.  */
-#if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
-         XColor color;
-         png_color_16 frame_background;
-
-         color.pixel = FRAME_BACKGROUND_PIXEL (f);
-         x_query_color (f, &color);
-
-         memset (&frame_background, 0, sizeof frame_background);
-         frame_background.red = color.red >> shift;
-         frame_background.green = color.green >> shift;
-         frame_background.blue = color.blue >> shift;
-#endif /* HAVE_X_WINDOWS */
+         int shift = bit_depth == 16 ? 0 : 8;
+         png_color_16 bg = { 0 };
+         bg.red = color.red >> shift;
+         bg.green = color.green >> shift;
+         bg.blue = color.blue >> shift;
 
-         fn_png_set_background (png_ptr, &frame_background,
+         fn_png_set_background (png_ptr, &bg,
                                 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
        }
     }
@@ -5937,8 +5912,8 @@ png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
   if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof *rows < height
       || min (PTRDIFF_MAX, SIZE_MAX) / sizeof *pixels / height < row_bytes)
     memory_full (SIZE_MAX);
-  c->pixels = pixels = xmalloc (sizeof *pixels * row_bytes * height);
-  c->rows = rows = xmalloc (height * sizeof *rows);
+  c->pixels = pixels = xmalloc_atomic (sizeof *pixels * row_bytes * height);
+  c->rows = rows = xmalloc_atomic (height * sizeof *rows);
   for (i = 0; i < height; ++i)
     rows[i] = pixels + i * row_bytes;
 
@@ -6056,9 +6031,8 @@ png_load (struct frame *f, struct image *img)
   return png_load_body (f, img, &c);
 }
 
-#else /* HAVE_PNG */
+#elif defined HAVE_NS
 
-#ifdef HAVE_NS
 static bool
 png_load (struct frame *f, struct image *img)
 {
@@ -6066,10 +6040,8 @@ png_load (struct frame *f, struct image *img)
                         image_spec_value (img->spec, QCfile, NULL),
                         image_spec_value (img->spec, QCdata, NULL));
 }
-#endif  /* HAVE_NS */
 
-
-#endif /* !HAVE_PNG */
+#endif /* HAVE_NS */
 
 
 \f
@@ -6256,9 +6228,6 @@ struct my_jpeg_error_mgr
       MY_JPEG_INVALID_IMAGE_SIZE,
       MY_JPEG_CANNOT_CREATE_X
     } failure_code;
-#ifdef lint
-  FILE *fp;
-#endif
 };
 
 
@@ -6463,7 +6432,6 @@ jpeg_file_src (j_decompress_ptr cinfo, FILE *fp)
   src->mgr.next_input_byte = NULL;
 }
 
-
 /* Load image IMG for use on frame F.  Patterned after example.c
    from the JPEG lib.  */
 
@@ -6473,7 +6441,8 @@ jpeg_load_body (struct frame *f, struct image *img,
 {
   Lisp_Object file, specified_file;
   Lisp_Object specified_data;
-  FILE *fp = NULL;
+  /* The 'volatile' silences a bogus diagnostic; see GCC bug 54561.  */
+  FILE * IF_LINT (volatile) fp = NULL;
   JSAMPARRAY buffer;
   int row_stride, x, y;
   XImagePtr ximg = NULL;
@@ -6506,8 +6475,6 @@ jpeg_load_body (struct frame *f, struct image *img,
       return 0;
     }
 
-  IF_LINT (mgr->fp = fp);
-
   /* Customize libjpeg's error handling to call my_error_exit when an
      error is detected.  This function will perform a longjmp.  */
   mgr->cinfo.err = fn_jpeg_std_error (&mgr->pub);
@@ -6546,9 +6513,6 @@ jpeg_load_body (struct frame *f, struct image *img,
       return 0;
     }
 
-  /* Silence a bogus diagnostic; see GCC bug 54561.  */
-  IF_LINT (fp = mgr->fp);
-
   /* Create the JPEG decompression object.  Let it read from fp.
         Read the JPEG image header.  */
   fn_jpeg_CreateDecompress (&mgr->cinfo, JPEG_LIB_VERSION, sizeof *&mgr->cinfo);
@@ -7050,7 +7014,7 @@ tiff_load (struct frame *f, struct image *img)
       return 0;
     }
 
-  buf = xmalloc (sizeof *buf * width * height);
+  buf = xmalloc_atomic (sizeof *buf * width * height);
 
   rc = fn_TIFFReadRGBAImage (tiff, width, height, buf, 0);
 
@@ -7256,7 +7220,11 @@ gif_image_p (Lisp_Object object)
 #ifdef WINDOWSNT
 
 /* GIF library details.  */
+#if 5 < GIFLIB_MAJOR + (1 <= GIFLIB_MINOR)
+DEF_IMGLIB_FN (int, DGifCloseFile, (GifFileType *, int *));
+#else
 DEF_IMGLIB_FN (int, DGifCloseFile, (GifFileType *));
+#endif
 DEF_IMGLIB_FN (int, DGifSlurp, (GifFileType *));
 #if GIFLIB_MAJOR < 5
 DEF_IMGLIB_FN (GifFileType *, DGifOpen, (void *, InputFunc));
@@ -7326,6 +7294,22 @@ gif_read_from_memory (GifFileType *file, GifByteType *buf, int len)
   return len;
 }
 
+static int
+gif_close (GifFileType *gif, int *err)
+{
+  int retval;
+
+#if 5 < GIFLIB_MAJOR + (1 <= GIFLIB_MINOR)
+  retval = fn_DGifCloseFile (gif, err);
+#else
+  retval = fn_DGifCloseFile (gif);
+#if GIFLIB_MAJOR >= 5
+  if (err)
+    *err = gif->Error;
+#endif
+#endif
+  return retval;
+}
 
 /* Load GIF image IMG for use on frame F.  Value is true if
    successful.  */
@@ -7350,9 +7334,7 @@ gif_load (struct frame *f, struct image *img)
   Lisp_Object specified_data = image_spec_value (img->spec, QCdata, NULL);
   unsigned long bgcolor = 0;
   EMACS_INT idx;
-#if GIFLIB_MAJOR >= 5
   int gif_err;
-#endif
 
   if (NILP (specified_data))
     {
@@ -7420,7 +7402,7 @@ gif_load (struct frame *f, struct image *img)
   if (!check_image_size (f, gif->SWidth, gif->SHeight))
     {
       image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
-      fn_DGifCloseFile (gif);
+      gif_close (gif, NULL);
       return 0;
     }
 
@@ -7429,7 +7411,7 @@ gif_load (struct frame *f, struct image *img)
   if (rc == GIF_ERROR || gif->ImageCount <= 0)
     {
       image_error ("Error reading `%s'", img->spec, Qnil);
-      fn_DGifCloseFile (gif);
+      gif_close (gif, NULL);
       return 0;
     }
 
@@ -7441,7 +7423,7 @@ gif_load (struct frame *f, struct image *img)
       {
        image_error ("Invalid image number `%s' in image `%s'",
                     image_number, img->spec);
-       fn_DGifCloseFile (gif);
+       gif_close (gif, NULL);
        return 0;
       }
   }
@@ -7459,7 +7441,7 @@ gif_load (struct frame *f, struct image *img)
   if (!check_image_size (f, width, height))
     {
       image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
-      fn_DGifCloseFile (gif);
+      gif_close (gif, NULL);
       return 0;
     }
 
@@ -7477,7 +7459,7 @@ gif_load (struct frame *f, struct image *img)
             && 0 <= subimg_left && subimg_left <= width - subimg_width))
        {
          image_error ("Subimage does not fit in image", Qnil, Qnil);
-         fn_DGifCloseFile (gif);
+         gif_close (gif, NULL);
          return 0;
        }
     }
@@ -7485,7 +7467,7 @@ gif_load (struct frame *f, struct image *img)
   /* Create the X image and pixmap.  */
   if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
     {
-      fn_DGifCloseFile (gif);
+      gif_close (gif, NULL);
       return 0;
     }
 
@@ -7584,7 +7566,7 @@ gif_load (struct frame *f, struct image *img)
          }
 
       /* Apply the pixel values.  */
-      if (gif->SavedImages[j].ImageDesc.Interlace)
+      if (GIFLIB_MAJOR < 5 && gif->SavedImages[j].ImageDesc.Interlace)
        {
          int row, pass;
 
@@ -7656,7 +7638,18 @@ gif_load (struct frame *f, struct image *img)
                            Fcons (make_number (gif->ImageCount),
                                   img->lisp_data));
 
-  fn_DGifCloseFile (gif);
+  if (gif_close (gif, &gif_err) == GIF_ERROR)
+    {
+#if 5 <= GIFLIB_MAJOR
+      char *error_text = fn_GifErrorString (gif_err);
+
+      if (error_text)
+       image_error ("Error closing `%s': %s",
+                    img->spec, build_string (error_text));
+#else
+      image_error ("Error closing `%s'", img->spec, Qnil);
+#endif
+    }
 
   /* Maybe fill in the background field while we have ximg handy. */
   if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
@@ -7904,7 +7897,7 @@ imagemagick_error (MagickWand *wand)
   image_error ("ImageMagick error: %s",
               build_string (description),
               Qnil);
-  description = (char *) MagickRelinquishMemory (description);
+  MagickRelinquishMemory (description);
 }
 
 /* Possibly give ImageMagick some extra help to determine the image
@@ -8230,14 +8223,7 @@ imagemagick_load_image (struct frame *f, struct image *img,
     specified_bg = image_spec_value (img->spec, QCbackground, NULL);
     if (!STRINGP (specified_bg)
        || !x_defined_color (f, SSDATA (specified_bg), &bgcolor, 0))
-      {
-#ifndef HAVE_NS
-       bgcolor.pixel = FRAME_BACKGROUND_PIXEL (f);
-       x_query_color (f, &bgcolor);
-#else
-       ns_query_color (FRAME_BACKGROUND_COLOR (f), &bgcolor, 1);
-#endif
-      }
+      x_query_frame_background_color (f, &bgcolor);
 
     bg_wand = NewPixelWand ();
     PixelSetRed   (bg_wand, (double) bgcolor.red   / 65535);
@@ -8389,6 +8375,7 @@ imagemagick_load_image (struct frame *f, struct image *img,
 #endif /* HAVE_MAGICKEXPORTIMAGEPIXELS */
     {
       size_t image_height;
+      MagickRealType color_scale = 65535.0 / QuantumRange;
 
       /* Try to create a x pixmap to hold the imagemagick pixmap.  */
       if (!image_create_x_image_and_pixmap (f, img, width, height, 0,
@@ -8429,9 +8416,9 @@ imagemagick_load_image (struct frame *f, struct image *img,
               PixelGetMagickColor (pixels[x], &pixel);
               XPutPixel (ximg, x, y,
                          lookup_rgb_color (f,
-                                           pixel.red,
-                                           pixel.green,
-                                           pixel.blue));
+                                          color_scale * pixel.red,
+                                          color_scale * pixel.green,
+                                          color_scale * pixel.blue));
             }
         }
       DestroyPixelIterator (iterator);
@@ -8532,7 +8519,6 @@ and `imagemagick-types-inhibit'.  */)
   ExceptionInfo ex;
   char **imtypes;
   size_t i;
-  Lisp_Object Qimagemagicktype;
 
   GetExceptionInfo(&ex);
   imtypes = GetMagickList ("*", &numf, &ex);
@@ -8540,9 +8526,12 @@ and `imagemagick-types-inhibit'.  */)
 
   for (i = 0; i < numf; i++)
     {
-      Qimagemagicktype = intern (imtypes[i]);
-      typelist = Fcons (Qimagemagicktype, typelist);
+      Lisp_Object imagemagicktype = intern (imtypes[i]);
+      typelist = Fcons (imagemagicktype, typelist);
+      imtypes[i] = MagickRelinquishMemory (imtypes[i]);
     }
+
+  MagickRelinquishMemory (imtypes);
   return Fnreverse (typelist);
 }
 
@@ -8650,7 +8639,6 @@ DEF_IMGLIB_FN (void, rsvg_handle_get_dimensions, (RsvgHandle *, RsvgDimensionDat
 DEF_IMGLIB_FN (gboolean, rsvg_handle_write, (RsvgHandle *, const guchar *, gsize, GError **));
 DEF_IMGLIB_FN (gboolean, rsvg_handle_close, (RsvgHandle *, GError **));
 DEF_IMGLIB_FN (GdkPixbuf *, rsvg_handle_get_pixbuf, (RsvgHandle *));
-DEF_IMGLIB_FN (void *, rsvg_handle_set_size_callback, (RsvgHandle *, RsvgSizeFunc, gpointer, GDestroyNotify));
 
 DEF_IMGLIB_FN (int, gdk_pixbuf_get_width, (const GdkPixbuf *));
 DEF_IMGLIB_FN (int, gdk_pixbuf_get_height, (const GdkPixbuf *));
@@ -8672,13 +8660,18 @@ Lisp_Object Qgdk_pixbuf, Qglib, Qgobject;
 static bool
 init_svg_functions (void)
 {
-  HMODULE library, gdklib, glib, gobject;
+  HMODULE library, gdklib = NULL, glib = NULL, gobject = NULL;
 
   if (!(glib = w32_delayed_load (Qglib))
       || !(gobject = w32_delayed_load (Qgobject))
       || !(gdklib = w32_delayed_load (Qgdk_pixbuf))
       || !(library = w32_delayed_load (Qsvg)))
-    return 0;
+    {
+      if (gdklib)  FreeLibrary (gdklib);
+      if (gobject) FreeLibrary (gobject);
+      if (glib)    FreeLibrary (glib);
+      return 0;
+    }
 
   LOAD_IMGLIB_FN (library, rsvg_handle_new);
   LOAD_IMGLIB_FN (library, rsvg_handle_get_dimensions);
@@ -8866,14 +8859,7 @@ svg_load_image (struct frame *f,         /* Pointer to emacs frame structure.  *
   specified_bg = image_spec_value (img->spec, QCbackground, NULL);
   if (!STRINGP (specified_bg)
       || !x_defined_color (f, SSDATA (specified_bg), &background, 0))
-    {
-#ifndef HAVE_NS
-      background.pixel = FRAME_BACKGROUND_PIXEL (f);
-      x_query_color (f, &background);
-#else
-      ns_query_color (FRAME_BACKGROUND_COLOR (f), &background, 1);
-#endif
-    }
+    x_query_frame_background_color (f, &background);
 
   /* SVG pixmaps specify transparency in the last byte, so right
      shift 8 bits to get rid of it, since emacs doesn't support
@@ -9361,6 +9347,8 @@ reset_image_types (void)
 void
 syms_of_image (void)
 {
+#include "image.x"
+
   /* Initialize this only once; it will be reset before dumping.  */
   image_types = NULL;
 
@@ -9494,21 +9482,6 @@ non-numeric, there is no explicit limit on the size of images.  */);
 #endif /* HAVE_NTGUI  */
 #endif /* HAVE_RSVG  */
 
-  defsubr (&Sinit_image_library);
-#ifdef HAVE_IMAGEMAGICK
-  defsubr (&Simagemagick_types);
-#endif
-  defsubr (&Sclear_image_cache);
-  defsubr (&Simage_flush);
-  defsubr (&Simage_size);
-  defsubr (&Simage_mask_p);
-  defsubr (&Simage_metadata);
-
-#ifdef GLYPH_DEBUG
-  defsubr (&Simagep);
-  defsubr (&Slookup_image);
-#endif
-
   DEFVAR_BOOL ("cross-disabled-images", cross_disabled_images,
     doc: /* Non-nil means always draw a cross over disabled images.
 Disabled images are those having a `:conversion disabled' property.