* image.c: Pacify --enable-gcc-warnings.
[bpt/emacs.git] / src / image.c
index 348f6a8..86780c6 100644 (file)
@@ -30,13 +30,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #endif
 
 #include <setjmp.h>
-
 #include <c-ctype.h>
 
-/* This makes the fields of a Display accessible, in Xlib header files.  */
-
-#define XLIB_ILLEGAL_ACCESS
-
 #include "lisp.h"
 #include "frame.h"
 #include "window.h"
@@ -92,10 +87,11 @@ typedef struct w32_bitmap_record Bitmap_Record;
 #define x_defined_color w32_defined_color
 #define DefaultDepthOfScreen(screen) (one_w32_display_info.n_cbits)
 
-/* Version of libpng that we were compiled with, or -1 if no PNG
-   support was compiled in.  This is tested by w32-win.el to correctly
-   set up the alist used to search for PNG libraries.  */
-Lisp_Object Qlibpng_version;
+/* Versions of libpng and libgif that we were compiled with, or -1 if
+   no PNG/GIF support was compiled in.  This is tested by w32-win.el
+   to correctly set up the alist used to search for the respective
+   image libraries.  */
+Lisp_Object Qlibpng_version, Qlibgif_version;
 #endif /* HAVE_NTGUI */
 
 #ifdef HAVE_NS
@@ -145,7 +141,7 @@ static Lisp_Object QCmax_width, QCmax_height;
 
 #ifdef HAVE_NS
 /* Use with images created by ns_image_for_XPM.  */
-unsigned long
+static unsigned long
 XGetPixel (XImagePtr ximage, int x, int y)
 {
   return ns_get_pixel (ximage, x, y);
@@ -153,7 +149,7 @@ XGetPixel (XImagePtr ximage, int x, int y)
 
 /* Use with images created by ns_image_for_XPM; alpha set to 1;
    pixel is assumed to be in RGB form.  */
-void
+static void
 XPutPixel (XImagePtr ximage, int x, int y, unsigned long pixel)
 {
   ns_put_pixel (ximage, x, y, pixel);
@@ -166,13 +162,13 @@ XPutPixel (XImagePtr ximage, int x, int y, unsigned long pixel)
 int
 x_bitmap_height (struct frame *f, ptrdiff_t id)
 {
-  return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height;
+  return FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].height;
 }
 
 int
 x_bitmap_width (struct frame *f, ptrdiff_t id)
 {
-  return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width;
+  return FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].width;
 }
 
 #if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
@@ -180,7 +176,7 @@ ptrdiff_t
 x_bitmap_pixmap (struct frame *f, ptrdiff_t id)
 {
   /* HAVE_NTGUI needs the explicit cast here.  */
-  return (ptrdiff_t) FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
+  return (ptrdiff_t) FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
 }
 #endif
 
@@ -188,7 +184,7 @@ x_bitmap_pixmap (struct frame *f, ptrdiff_t id)
 int
 x_bitmap_mask (struct frame *f, ptrdiff_t id)
 {
-  return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].mask;
+  return FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].mask;
 }
 #endif
 
@@ -197,7 +193,7 @@ x_bitmap_mask (struct frame *f, ptrdiff_t id)
 static ptrdiff_t
 x_allocate_bitmap_record (struct frame *f)
 {
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
   ptrdiff_t i;
 
   if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
@@ -218,7 +214,7 @@ x_allocate_bitmap_record (struct frame *f)
 void
 x_reference_bitmap (struct frame *f, ptrdiff_t id)
 {
-  ++FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
+  ++FRAME_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
 }
 
 /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS.  */
@@ -226,7 +222,7 @@ x_reference_bitmap (struct frame *f, ptrdiff_t id)
 ptrdiff_t
 x_create_bitmap_from_data (struct frame *f, char *bits, unsigned int width, unsigned int height)
 {
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
   ptrdiff_t id;
 
 #ifdef HAVE_X_WINDOWS
@@ -240,8 +236,8 @@ x_create_bitmap_from_data (struct frame *f, char *bits, unsigned int width, unsi
 #ifdef HAVE_NTGUI
   Pixmap bitmap;
   bitmap = CreateBitmap (width, height,
-                        FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_planes,
-                        FRAME_X_DISPLAY_INFO (XFRAME (frame))->n_cbits,
+                        FRAME_DISPLAY_INFO (XFRAME (frame))->n_planes,
+                        FRAME_DISPLAY_INFO (XFRAME (frame))->n_cbits,
                         bits);
   if (! bitmap)
     return -1;
@@ -285,7 +281,7 @@ x_create_bitmap_from_data (struct frame *f, char *bits, unsigned int width, unsi
 ptrdiff_t
 x_create_bitmap_from_file (struct frame *f, Lisp_Object file)
 {
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
 
 #ifdef HAVE_NTGUI
   return -1;  /* W32_TODO : bitmap support */
@@ -384,7 +380,7 @@ free_bitmap_record (Display_Info *dpyinfo, Bitmap_Record *bm)
 void
 x_destroy_bitmap (struct frame *f, ptrdiff_t id)
 {
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
 
   if (id > 0)
     {
@@ -459,7 +455,7 @@ x_create_bitmap_mask (struct frame *f, ptrdiff_t id)
   unsigned long x, y, xp, xm, yp, ym;
   GC gc;
 
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
 
   if (!(id > 0))
     return;
@@ -563,7 +559,6 @@ static void x_emboss (struct frame *, struct image *);
 static void x_build_heuristic_mask (struct frame *, struct image *,
                                     Lisp_Object);
 #ifdef WINDOWSNT
-extern Lisp_Object Vlibrary_cache;
 #define CACHE_IMAGE_TYPE(type, status) \
   do { Vlibrary_cache = Fcons (Fcons (type, status), Vlibrary_cache); } while (0)
 #else
@@ -1042,7 +1037,7 @@ void
 prepare_image_for_display (struct frame *f, struct image *img)
 {
   /* We're about to display IMG, so set its timestamp to `now'.  */
-  img->timestamp = current_emacs_time ();
+  img->timestamp = current_timespec ();
 
   /* If IMG doesn't have a pixmap yet, load it now, using the image
      type dependent loader function.  */
@@ -1481,7 +1476,7 @@ clear_image_cache (struct frame *f, Lisp_Object filter)
       else if (INTEGERP (Vimage_cache_eviction_delay))
        {
          /* Free cache based on timestamp.  */
-         EMACS_TIME old, t;
+         struct timespec old, t;
          double delay;
          ptrdiff_t nimages = 0;
 
@@ -1496,13 +1491,13 @@ clear_image_cache (struct frame *f, Lisp_Object filter)
            delay = 1600 * delay / nimages / nimages;
          delay = max (delay, 1);
 
-         t = current_emacs_time ();
-         old = sub_emacs_time (t, EMACS_TIME_FROM_DOUBLE (delay));
+         t = current_timespec ();
+         old = timespec_sub (t, dtotimespec (delay));
 
          for (i = 0; i < c->used; ++i)
            {
              struct image *img = c->images[i];
-             if (img && EMACS_TIME_LT (img->timestamp, old))
+             if (img && timespec_cmp (img->timestamp, old) < 0)
                {
                  free_image (f, img);
                  ++nfreed;
@@ -1765,7 +1760,7 @@ lookup_image (struct frame *f, Lisp_Object spec)
     }
 
   /* We're using IMG, so set its timestamp to `now'.  */
-  img->timestamp = current_emacs_time ();
+  img->timestamp = current_timespec ();
 
   /* Value is the image id.  */
   return img->id;
@@ -2713,10 +2708,13 @@ xbm_read_bitmap_data (struct frame *f, unsigned char *contents, unsigned char *e
      LA1 = xbm_scan (&s, end, buffer, &value)
 
 #define expect(TOKEN)          \
-     if (LA1 != (TOKEN))       \
-       goto failure;           \
-     else                      \
-       match ()
+  do                           \
+    {                          \
+      if (LA1 != (TOKEN))      \
+       goto failure;           \
+      match ();                        \
+    }                          \
+  while (0)
 
 #define expect_ident(IDENT)                                    \
      if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
@@ -3424,7 +3422,7 @@ xpm_image_p (Lisp_Object object)
 ptrdiff_t
 x_create_bitmap_from_xpm_data (struct frame *f, const char **bits)
 {
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
   ptrdiff_t id;
   int rc;
   XpmAttributes attrs;
@@ -3976,10 +3974,13 @@ xpm_load_image (struct frame *f,
      LA1 = xpm_scan (&s, end, &beg, &len)
 
 #define expect(TOKEN)          \
-     if (LA1 != (TOKEN))       \
-       goto failure;           \
-     else                      \
-       match ()
+  do                           \
+    {                          \
+      if (LA1 != (TOKEN))      \
+       goto failure;           \
+      match ();                        \
+    }                          \
+  while (0)
 
 #define expect_ident(IDENT)                                    \
      if (LA1 == XPM_TK_IDENT \
@@ -4325,7 +4326,7 @@ lookup_rgb_color (struct frame *f, int r, int g, int b)
      two orders of magnitude.  Freeing colors on TrueColor visuals is
      a nop, and pixel colors specify RGB values directly.  See also
      the Xlib spec, chapter 3.1.  */
-  dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  dpyinfo = FRAME_DISPLAY_INFO (f);
   if (dpyinfo->red_bits > 0)
     {
       unsigned long pr, pg, pb;
@@ -4820,7 +4821,7 @@ x_edge_detection (struct frame *f, struct image *img, Lisp_Object matrix,
 static void
 x_disable_image (struct frame *f, struct image *img)
 {
-  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
 #ifdef HAVE_NTGUI
   int n_planes = dpyinfo->n_planes * dpyinfo->n_cbits;
 #else
@@ -4932,7 +4933,7 @@ x_build_heuristic_mask (struct frame *f, struct image *img, Lisp_Object how)
   int row_width;
 #endif /* HAVE_NTGUI */
   int x, y;
-  bool rc, use_img_background;
+  bool use_img_background;
   unsigned long bg = 0;
 
   if (img->mask)
@@ -4941,9 +4942,8 @@ x_build_heuristic_mask (struct frame *f, struct image *img, Lisp_Object how)
 #ifndef HAVE_NTGUI
 #ifndef HAVE_NS
   /* Create an image and pixmap serving as mask.  */
-  rc = image_create_x_image_and_pixmap (f, img, img->width, img->height, 1,
-                                       &mask_img, 1);
-  if (!rc)
+  if (! image_create_x_image_and_pixmap (f, img, img->width, img->height, 1,
+                                        &mask_img, 1))
     return;
 #endif /* !HAVE_NS */
 #else
@@ -7203,7 +7203,21 @@ gif_image_p (Lisp_Object object)
 
 #ifdef HAVE_GIF
 
+/* Giflib before 5.0 didn't define these macros.  */
+#ifndef GIFLIB_MAJOR
+#define GIFLIB_MAJOR 4
+#endif
+
 #if defined (HAVE_NTGUI)
+
+/* Giflib before 5.0 didn't define these macros (used only if HAVE_NTGUI).  */
+#ifndef GIFLIB_MINOR
+#define GIFLIB_MINOR 0
+#endif
+#ifndef GIFLIB_RELEASE
+#define GIFLIB_RELEASE 0
+#endif
+
 /* winuser.h might define DrawText to DrawTextA or DrawTextW.
    Undefine before redefining to avoid a preprocessor warning.  */
 #ifdef DrawText
@@ -7220,14 +7234,19 @@ gif_image_p (Lisp_Object object)
 
 #endif /* HAVE_NTGUI */
 
-
 #ifdef WINDOWSNT
 
 /* GIF library details.  */
 DEF_IMGLIB_FN (int, DGifCloseFile, (GifFileType *));
 DEF_IMGLIB_FN (int, DGifSlurp, (GifFileType *));
+#if GIFLIB_MAJOR < 5
 DEF_IMGLIB_FN (GifFileType *, DGifOpen, (void *, InputFunc));
 DEF_IMGLIB_FN (GifFileType *, DGifOpenFileName, (const char *));
+#else
+DEF_IMGLIB_FN (GifFileType *, DGifOpen, (void *, InputFunc, int *));
+DEF_IMGLIB_FN (GifFileType *, DGifOpenFileName, (const char *, int *));
+DEF_IMGLIB_FN (char *, GifErrorString, (int));
+#endif
 
 static bool
 init_gif_functions (void)
@@ -7241,6 +7260,9 @@ init_gif_functions (void)
   LOAD_IMGLIB_FN (library, DGifSlurp);
   LOAD_IMGLIB_FN (library, DGifOpen);
   LOAD_IMGLIB_FN (library, DGifOpenFileName);
+#if GIFLIB_MAJOR >= 5
+  LOAD_IMGLIB_FN (library, GifErrorString);
+#endif
   return 1;
 }
 
@@ -7250,6 +7272,9 @@ init_gif_functions (void)
 #define fn_DGifSlurp           DGifSlurp
 #define fn_DGifOpen            DGifOpen
 #define fn_DGifOpenFileName    DGifOpenFileName
+#if 5 <= GIFLIB_MAJOR
+# define fn_GifErrorString     GifErrorString
+#endif
 
 #endif /* WINDOWSNT */
 
@@ -7306,6 +7331,9 @@ 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))
     {
@@ -7317,12 +7345,22 @@ gif_load (struct frame *f, struct image *img)
        }
 
       /* Open the GIF file.  */
+#if GIFLIB_MAJOR < 5
       gif = fn_DGifOpenFileName (SSDATA (file));
       if (gif == NULL)
        {
          image_error ("Cannot open `%s'", file, Qnil);
          return 0;
        }
+#else
+      gif = fn_DGifOpenFileName (SSDATA (file), &gif_err);
+      if (gif == NULL)
+       {
+         image_error ("Cannot open `%s': %s",
+                      file, build_string (fn_GifErrorString (gif_err)));
+         return 0;
+       }
+#endif
     }
   else
     {
@@ -7338,12 +7376,22 @@ gif_load (struct frame *f, struct image *img)
       memsrc.len = SBYTES (specified_data);
       memsrc.index = 0;
 
+#if GIFLIB_MAJOR < 5
       gif = fn_DGifOpen (&memsrc, gif_read_from_memory);
       if (!gif)
        {
          image_error ("Cannot open memory source `%s'", img->spec, Qnil);
          return 0;
        }
+#else
+      gif = fn_DGifOpen (&memsrc, gif_read_from_memory, &gif_err);
+      if (!gif)
+       {
+         image_error ("Cannot open memory source `%s': %s",
+                      img->spec, build_string (fn_GifErrorString (gif_err)));
+         return 0;
+       }
+#endif
     }
 
   /* Before reading entire contents, check the declared image size. */
@@ -7524,7 +7572,7 @@ gif_load (struct frame *f, struct image *img)
            {
              while (subimg_height <= row)
                {
-                 lint_assume (pass < 3);
+                 assume (pass < 3);
                  row = interlace_start[++pass];
                }
 
@@ -7869,10 +7917,86 @@ imagemagick_filename_hint (Lisp_Object spec, char hint_buffer[MaxTextExtent])
    follow.  If following images have non-transparent colors, these are
    composed "on top" of the master image.  So, in general, one has to
    compute ann the preceding images to be able to display a particular
-   sub-image.  */
+   sub-image.
+
+   Computing all the preceding images is too slow, so we maintain a
+   cache of previously computed images.  We have to maintain a cache
+   separate from the image cache, because the images may be scaled
+   before display. */
+
+struct animation_cache
+{
+  MagickWand *wand;
+  int index;
+  struct timespec update_time;
+  struct animation_cache *next;
+  char signature[FLEXIBLE_ARRAY_MEMBER];
+};
+
+static struct animation_cache *animation_cache = NULL;
 
-static MagickWand *animation_cache = NULL;
-static int animation_index = 0;
+static struct animation_cache *
+imagemagick_create_cache (char *signature)
+{
+  struct animation_cache *cache
+    = xmalloc (offsetof (struct animation_cache, signature)
+              + strlen (signature) + 1);
+  cache->wand = 0;
+  cache->index = 0;
+  cache->next = 0;
+  strcpy (cache->signature, signature);
+  return cache;
+}
+
+/* Discard cached images that haven't been used for a minute. */
+static void
+imagemagick_prune_animation_cache (void)
+{
+  struct animation_cache **pcache = &animation_cache;
+  struct timespec old = timespec_sub (current_timespec (),
+                                     make_timespec (60, 0));
+
+  while (*pcache)
+    {
+      struct animation_cache *cache = *pcache;
+      if (timespec_cmp (old, cache->update_time) <= 0)
+       pcache = &cache->next;
+      else
+       {
+         if (cache->wand)
+           DestroyMagickWand (cache->wand);
+         *pcache = cache->next;
+         xfree (cache);
+       }
+    }
+}
+
+static struct animation_cache *
+imagemagick_get_animation_cache (MagickWand *wand)
+{
+  char *signature = MagickGetImageSignature (wand);
+  struct animation_cache *cache;
+  struct animation_cache **pcache = &animation_cache;
+
+  imagemagick_prune_animation_cache ();
+
+  while (1)
+    {
+      cache = *pcache;
+      if (! cache)
+       {
+          *pcache = cache = imagemagick_create_cache (signature);
+          break;
+        }
+      if (strcmp (signature, cache->signature) == 0)
+       break;
+      pcache = &cache->next;
+    }
+
+  DestroyString (signature);
+  cache->update_time = current_timespec ();
+  return cache;
+}
 
 static MagickWand *
 imagemagick_compute_animated_image (MagickWand *super_wand, int ino)
@@ -7880,18 +8004,23 @@ imagemagick_compute_animated_image (MagickWand *super_wand, int ino)
   int i;
   MagickWand *composite_wand;
   size_t dest_width, dest_height;
+  struct animation_cache *cache = imagemagick_get_animation_cache (super_wand);
 
   MagickSetIteratorIndex (super_wand, 0);
 
-  if (ino == 0 || animation_cache == NULL)
-    composite_wand = MagickGetImage (super_wand);
+  if (ino == 0 || cache->wand == NULL || cache->index > ino)
+    {
+      composite_wand = MagickGetImage (super_wand);
+      if (cache->wand)
+       DestroyMagickWand (cache->wand);
+    }
   else
-    composite_wand = animation_cache;
+    composite_wand = cache->wand;
 
   dest_width = MagickGetImageWidth (composite_wand);
   dest_height = MagickGetImageHeight (composite_wand);
 
-  for (i = max (1, animation_index + 1); i <= ino; i++)
+  for (i = max (1, cache->index + 1); i <= ino; i++)
     {
       MagickWand *sub_wand;
       PixelIterator *source_iterator, *dest_iterator;
@@ -7900,6 +8029,7 @@ imagemagick_compute_animated_image (MagickWand *super_wand, int ino)
       ssize_t source_left, source_top;
       MagickPixelPacket pixel;
       DisposeType dispose;
+      ptrdiff_t lines = 0;
 
       MagickSetIteratorIndex (super_wand, i);
       sub_wand = MagickGetImage (super_wand);
@@ -7907,17 +8037,7 @@ imagemagick_compute_animated_image (MagickWand *super_wand, int ino)
       MagickGetImagePage (sub_wand, &source_width, &source_height,
                          &source_left, &source_top);
 
-      /* Sanity check.  The sub-image should not be bigger than the
-        base image.  */
-      if (source_height + source_top > dest_height)
-       {
-         DestroyMagickWand (composite_wand);
-         DestroyMagickWand (sub_wand);
-         animation_cache = NULL;
-         image_error ("Inconsinstent animation size", Qnil, Qnil);
-         return NULL;
-       }
-
+      /* This flag says how to handle transparent pixels.  */
       dispose = MagickGetImageDispose (sub_wand);
 
       source_iterator = NewPixelIterator (sub_wand);
@@ -7925,7 +8045,7 @@ imagemagick_compute_animated_image (MagickWand *super_wand, int ino)
        {
          DestroyMagickWand (composite_wand);
          DestroyMagickWand (sub_wand);
-         animation_cache = NULL;
+         cache->wand = NULL;
          image_error ("Imagemagick pixel iterator creation failed",
                       Qnil, Qnil);
          return NULL;
@@ -7937,25 +8057,35 @@ imagemagick_compute_animated_image (MagickWand *super_wand, int ino)
          DestroyMagickWand (composite_wand);
          DestroyMagickWand (sub_wand);
          DestroyPixelIterator (source_iterator);
-         animation_cache = NULL;
+         cache->wand = NULL;
          image_error ("Imagemagick pixel iterator creation failed",
                       Qnil, Qnil);
          return NULL;
        }
 
-      /* The sub-image may not start at origo, so move the destination
+      /* The sub-image may not start at origin, so move the destination
         iterator to where the sub-image should start. */
-      PixelSetIteratorRow (dest_iterator, source_top);
+      if (source_top > 0)
+       {
+         PixelSetIteratorRow (dest_iterator, source_top);
+         lines = source_top;
+       }
 
       while ((source = PixelGetNextIteratorRow (source_iterator, &source_width))
             != NULL)
        {
          ptrdiff_t x;
+
+         /* Sanity check.  This shouldn't happen, but apparently
+            does in some pictures.  */
+         if (++lines >= dest_height)
+           break;
+
          dest = PixelGetNextIteratorRow (dest_iterator, &dest_width);
          for (x = 0; x < source_width; x++)
            {
              /* Sanity check.  This shouldn't happen, but apparently
-                does in some pictures.  */
+                also does in some pictures.  */
              if (x + source_left > dest_width)
                break;
              /* Normally we only copy over non-transparent pixels,
@@ -7968,7 +8098,7 @@ imagemagick_compute_animated_image (MagickWand *super_wand, int ino)
                  PixelSetMagickColor (dest[x + source_left], &pixel);
                }
            }
-         PixelSyncIterator(dest_iterator);
+         PixelSyncIterator (dest_iterator);
        }
 
       DestroyPixelIterator (source_iterator);
@@ -7978,8 +8108,8 @@ imagemagick_compute_animated_image (MagickWand *super_wand, int ino)
 
   /* Cache a copy for the next iteration.  The current wand will be
      destroyed by the caller. */
-  animation_cache = CloneMagickWand (composite_wand);
-  animation_index = ino;
+  cache->wand = CloneMagickWand (composite_wand);
+  cache->index = ino;
 
   return composite_wand;
 }
@@ -8007,7 +8137,6 @@ imagemagick_load_image (struct frame *f, struct image *img,
   XImagePtr ximg;
   int x, y;
   MagickWand *image_wand;
-  MagickWand *ping_wand;
   PixelIterator *iterator;
   PixelWand **pixels, *bg_wand = NULL;
   MagickPixelPacket  pixel;
@@ -8030,60 +8159,38 @@ imagemagick_load_image (struct frame *f, struct image *img,
   MagickWandGenesis ();
   image = image_spec_value (img->spec, QCindex, NULL);
   ino = INTEGERP (image) ? XFASTINT (image) : 0;
-  ping_wand = NewMagickWand ();
-  /* MagickSetResolution (ping_wand, 2, 2);   (Bug#10112)  */
+  image_wand = NewMagickWand ();
 
   if (filename)
-    status = MagickPingImage (ping_wand, filename);
+    status = MagickReadImage (image_wand, filename);
   else
     {
       filename_hint = imagemagick_filename_hint (img->spec, hint_buffer);
-      MagickSetFilename (ping_wand, filename_hint);
-      status = MagickPingImageBlob (ping_wand, contents, size);
+      MagickSetFilename (image_wand, filename_hint);
+      status = MagickReadImageBlob (image_wand, contents, size);
     }
 
   if (status == MagickFalse)
     {
-      imagemagick_error (ping_wand);
-      DestroyMagickWand (ping_wand);
+      imagemagick_error (image_wand);
+      DestroyMagickWand (image_wand);
       return 0;
     }
 
-  if (ino < 0 || ino >= MagickGetNumberImages (ping_wand))
+  if (ino < 0 || ino >= MagickGetNumberImages (image_wand))
     {
       image_error ("Invalid image number `%s' in image `%s'",
                   image, img->spec);
-      DestroyMagickWand (ping_wand);
+      DestroyMagickWand (image_wand);
       return 0;
     }
 
-  if (MagickGetNumberImages (ping_wand) > 1)
+  if (MagickGetNumberImages (image_wand) > 1)
     img->lisp_data =
       Fcons (Qcount,
-             Fcons (make_number (MagickGetNumberImages (ping_wand)),
+             Fcons (make_number (MagickGetNumberImages (image_wand)),
                     img->lisp_data));
 
-  DestroyMagickWand (ping_wand);
-
-  /* Now we know how many images are inside the file.  If it's not a
-     bundle, the number is one.  Load the image data.  */
-
-  image_wand = NewMagickWand ();
-
-  if (filename)
-    status = MagickReadImage (image_wand, filename);
-  else
-    {
-      MagickSetFilename (image_wand, filename_hint);
-      status = MagickReadImageBlob (image_wand, contents, size);
-    }
-
-  if (status == MagickFalse)
-    {
-      imagemagick_error (image_wand);
-      goto imagemagick_error;
-    }
-
   /* If we have an animated image, get the new wand based on the
      "super-wand". */
   if (MagickGetNumberImages (image_wand) > 1)
@@ -8532,7 +8639,9 @@ DEF_IMGLIB_FN (int, gdk_pixbuf_get_n_channels, (const GdkPixbuf *));
 DEF_IMGLIB_FN (gboolean, gdk_pixbuf_get_has_alpha, (const GdkPixbuf *));
 DEF_IMGLIB_FN (int, gdk_pixbuf_get_bits_per_sample, (const GdkPixbuf *));
 
+#if ! GLIB_CHECK_VERSION (2, 36, 0)
 DEF_IMGLIB_FN (void, g_type_init, (void));
+#endif
 DEF_IMGLIB_FN (void, g_object_unref, (gpointer));
 DEF_IMGLIB_FN (void, g_error_free, (GError *));
 
@@ -8564,7 +8673,9 @@ init_svg_functions (void)
   LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_has_alpha);
   LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_bits_per_sample);
 
+#if ! GLIB_CHECK_VERSION (2, 36, 0)
   LOAD_IMGLIB_FN (gobject, g_type_init);
+#endif
   LOAD_IMGLIB_FN (gobject, g_object_unref);
   LOAD_IMGLIB_FN (glib, g_error_free);
 
@@ -8589,7 +8700,9 @@ init_svg_functions (void)
 #define fn_gdk_pixbuf_get_has_alpha      gdk_pixbuf_get_has_alpha
 #define fn_gdk_pixbuf_get_bits_per_sample gdk_pixbuf_get_bits_per_sample
 
+#if ! GLIB_CHECK_VERSION (2, 36, 0)
 #define fn_g_type_init                    g_type_init
+#endif
 #define fn_g_object_unref                 g_object_unref
 #define fn_g_error_free                   g_error_free
 #endif /* !WINDOWSNT  */
@@ -8674,9 +8787,12 @@ svg_load_image (struct frame *f,         /* Pointer to emacs frame structure.  *
   int x;
   int y;
 
-  /* g_type_init is a glib function that must be called prior to using
-     gnome type library functions.  */
+#if ! GLIB_CHECK_VERSION (2, 36, 0)
+  /* g_type_init is a glib function that must be called prior to
+     using gnome type library functions (obsolete since 2.36.0).  */
   fn_g_type_init ();
+#endif
+
   /* Make a handle to a new rsvg object.  */
   rsvg_handle = fn_rsvg_handle_new ();
 
@@ -9287,6 +9403,16 @@ non-numeric, there is no explicit limit on the size of images.  */);
        make_number (PNG_LIBPNG_VER)
 #else
        make_number (-1)
+#endif
+       );
+  DEFSYM (Qlibgif_version, "libgif-version");
+  Fset (Qlibgif_version,
+#ifdef HAVE_GIF
+       make_number (GIFLIB_MAJOR * 10000
+                    + GIFLIB_MINOR * 100
+                    + GIFLIB_RELEASE)
+#else
+       make_number (-1)
 #endif
        );
 #endif