Consult libpng-config more consistently.
[bpt/emacs.git] / src / image.c
index 68d78fc..c26c0db 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.
 
@@ -22,21 +22,12 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <unistd.h>
 
 #ifdef HAVE_PNG
-#if defined HAVE_LIBPNG_PNG_H
-# include <libpng/png.h>
-#else
 # include <png.h>
 #endif
-#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 +83,12 @@ 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, libgif, and libjpeg 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, Qlibjpeg_version;
+
 #endif /* HAVE_NTGUI */
 
 #ifdef HAVE_NS
@@ -145,7 +138,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 +146,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);
@@ -163,24 +156,26 @@ XPutPixel (XImagePtr ximage, int x, int y, unsigned long pixel)
 
 /* Functions to access the contents of a bitmap, given an id.  */
 
-int
+#ifdef HAVE_X_WINDOWS
+static 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
+static 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;
 }
+#endif
 
 #if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
 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 +183,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 +192,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 +213,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 +221,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 +235,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;
@@ -267,7 +262,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 */
 
@@ -285,7 +280,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 */
@@ -330,7 +325,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);
@@ -342,7 +339,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;
@@ -384,7 +381,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 +456,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;
@@ -518,7 +515,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);
@@ -563,7 +560,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 +1038,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 +1477,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 +1492,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;
@@ -1525,7 +1521,7 @@ clear_image_cache (struct frame *f, Lisp_Object filter)
                clear_current_matrices (fr);
            }
 
-         ++windows_or_buffers_changed;
+         windows_or_buffers_changed = 19;
        }
 
       unblock_input ();
@@ -1765,7 +1761,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;
@@ -2021,6 +2017,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;
     }
 
@@ -2246,7 +2243,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;
@@ -2461,7 +2458,7 @@ xbm_image_p (Lisp_Object object)
                }
              else if (BOOL_VECTOR_P (elt))
                {
-                 if (XBOOL_VECTOR (elt)->size < width)
+                 if (bool_vector_size (elt) < width)
                    return 0;
                }
              else
@@ -2476,7 +2473,7 @@ xbm_image_p (Lisp_Object object)
        }
       else if (BOOL_VECTOR_P (data))
        {
-         if (XBOOL_VECTOR (data)->size / height < width)
+         if (bool_vector_size (data) / height < width)
            return 0;
        }
       else
@@ -2713,10 +2710,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) \
@@ -3027,13 +3027,13 @@ xbm_load (struct frame *f, struct image *img)
                  if (STRINGP (line))
                    memcpy (p, SDATA (line), nbytes);
                  else
-                   memcpy (p, XBOOL_VECTOR (line)->data, nbytes);
+                   memcpy (p, bool_vector_data (line), nbytes);
                }
            }
          else if (STRINGP (data))
            bits = SSDATA (data);
          else
-           bits = (char *) XBOOL_VECTOR (data)->data;
+           bits = (char *) bool_vector_data (data);
 
 #ifdef HAVE_NTGUI
           {
@@ -3424,7 +3424,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;
@@ -3447,7 +3447,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;
@@ -3591,6 +3591,12 @@ xpm_load (struct frame *f, struct image *img)
        }
 
 #ifdef HAVE_NTGUI
+#ifdef WINDOWSNT
+      /* FILE is encoded in UTF-8, but image libraries on Windows
+        support neither UTF-8 nor UTF-16 encoded file names.  So we
+        need to re-encode it in ANSI.  */
+      file = ansi_encode_filename (file);
+#endif
       /* XpmReadFileToPixmap is not available in the Windows port of
         libxpm.  But XpmReadFileToImage almost does what we want.  */
       rc = fn_XpmReadFileToImage (&hdc, SDATA (file),
@@ -3945,9 +3951,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;
@@ -3969,17 +3973,20 @@ 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() \
      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 \
@@ -4138,7 +4145,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);
@@ -4325,7 +4332,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 +4827,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 +4939,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 +4948,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
@@ -5105,6 +5111,27 @@ pbm_image_p (Lisp_Object object)
 }
 
 
+/* Get next char skipping comments in Netpbm header.  Returns -1 at
+   end of input.  */
+
+static int
+pbm_next_char (unsigned char **s, unsigned char *end)
+{
+  int c = -1;
+
+  while (*s < end && (c = *(*s)++, c == '#'))
+    {
+      /* Skip to the next line break.  */
+      while (*s < end && (c = *(*s)++, c != '\n' && c != '\r'))
+        ;
+
+      c = -1;
+    }
+
+  return c;
+}
+
+
 /* Scan a decimal number from *S and return it.  Advance *S while
    reading the number.  END is the end of the string.  Value is -1 at
    end of input.  */
@@ -5114,28 +5141,16 @@ pbm_scan_number (unsigned char **s, unsigned char *end)
 {
   int c = 0, val = -1;
 
-  while (*s < end)
-    {
-      /* Skip white-space.  */
-      while (*s < end && (c = *(*s)++, c_isspace (c)))
-       ;
+  /* Skip white-space.  */
+  while ((c = pbm_next_char (s, end)) != -1 && c_isspace (c))
+    ;
 
-      if (c == '#')
-       {
-         /* Skip comment to end of line.  */
-         while (*s < end && (c = *(*s)++, c != '\n'))
-           ;
-       }
-      else if (c_isdigit (c))
-       {
-         /* Read decimal number.  */
-         val = c - '0';
-         while (*s < end && (c = *(*s)++, c_isdigit (c)))
-           val = 10 * val + c - '0';
-         break;
-       }
-      else
-       break;
+  if (c_isdigit (c))
+    {
+      /* Read decimal number.  */
+      val = c - '0';
+      while ((c = pbm_next_char (s, end)) != -1 && c_isdigit (c))
+        val = 10 * val + c - '0';
     }
 
   return val;
@@ -5197,6 +5212,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;
     }
 
@@ -5518,7 +5534,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 */
 
@@ -5590,24 +5606,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
@@ -5792,7 +5810,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)
@@ -6240,9 +6258,6 @@ struct my_jpeg_error_mgr
       MY_JPEG_INVALID_IMAGE_SIZE,
       MY_JPEG_CANNOT_CREATE_X
     } failure_code;
-#ifdef lint
-  FILE *fp;
-#endif
 };
 
 
@@ -6457,7 +6472,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;
@@ -6490,8 +6506,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);
@@ -6530,9 +6544,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);
@@ -6958,6 +6969,9 @@ tiff_load (struct frame *f, struct image *img)
          image_error ("Cannot find image file `%s'", specified_file, Qnil);
          return 0;
        }
+#ifdef WINDOWSNT
+      file = ansi_encode_filename (file);
+#endif
 
       /* Try to open the image file.  */
       tiff = fn_TIFFOpen (SSDATA (file), "r");
@@ -7204,6 +7218,7 @@ gif_image_p (Lisp_Object object)
 #ifdef HAVE_GIF
 
 #if defined (HAVE_NTGUI)
+
 /* winuser.h might define DrawText to DrawTextA or DrawTextW.
    Undefine before redefining to avoid a preprocessor warning.  */
 #ifdef DrawText
@@ -7214,20 +7229,38 @@ gif_image_p (Lisp_Object object)
 #include <gif_lib.h>
 #undef DrawText
 
+/* 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
+
 #else /* HAVE_NTGUI */
 
 #include <gif_lib.h>
 
 #endif /* HAVE_NTGUI */
 
+/* Giflib before 5.0 didn't define these macros.  */
+#ifndef GIFLIB_MAJOR
+#define GIFLIB_MAJOR 4
+#endif
 
 #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 +7274,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 +7286,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 +7345,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))
     {
@@ -7315,14 +7357,27 @@ gif_load (struct frame *f, struct image *img)
          image_error ("Cannot find image file `%s'", specified_file, Qnil);
          return 0;
        }
+#ifdef WINDOWSNT
+      file = ansi_encode_filename (file);
+#endif
 
       /* 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 +7393,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. */
@@ -7514,7 +7579,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;
 
@@ -7523,10 +7588,7 @@ gif_load (struct frame *f, struct image *img)
               y++, row += interlace_increment[pass])
            {
              while (subimg_height <= row)
-               {
-                 lint_assume (pass < 3);
-                 row = interlace_start[++pass];
-               }
+               row = interlace_start[++pass];
 
              for (x = 0; x < subimg_width; x++)
                {
@@ -7837,7 +7899,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
@@ -7878,11 +7940,11 @@ imagemagick_filename_hint (Lisp_Object spec, char hint_buffer[MaxTextExtent])
 
 struct animation_cache
 {
-  char *signature;
   MagickWand *wand;
   int index;
-  EMACS_TIME update_time;
+  struct timespec update_time;
   struct animation_cache *next;
+  char signature[FLEXIBLE_ARRAY_MEMBER];
 };
 
 static struct animation_cache *animation_cache = NULL;
@@ -7890,11 +7952,13 @@ static struct animation_cache *animation_cache = NULL;
 static struct animation_cache *
 imagemagick_create_cache (char *signature)
 {
-  struct animation_cache *cache = xmalloc (sizeof *cache);
-  cache->signature = 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;
 }
 
@@ -7903,17 +7967,16 @@ static void
 imagemagick_prune_animation_cache (void)
 {
   struct animation_cache **pcache = &animation_cache;
-  EMACS_TIME old = sub_emacs_time (current_emacs_time (),
-                                  make_emacs_time (60, 0));
+  struct timespec old = timespec_sub (current_timespec (),
+                                     make_timespec (60, 0));
 
   while (*pcache)
     {
       struct animation_cache *cache = *pcache;
-      if (EMACS_TIME_LE (old, cache->update_time))
+      if (timespec_cmp (old, cache->update_time) <= 0)
        pcache = &cache->next;
       else
        {
-         DestroyString (cache->signature);
          if (cache->wand)
            DestroyMagickWand (cache->wand);
          *pcache = cache->next;
@@ -7930,24 +7993,22 @@ imagemagick_get_animation_cache (MagickWand *wand)
   struct animation_cache **pcache = &animation_cache;
 
   imagemagick_prune_animation_cache ();
-  cache = animation_cache;
 
-  for (pcache = &animation_cache; *pcache; pcache = &cache->next)
+  while (1)
     {
       cache = *pcache;
       if (! cache)
        {
-         *pcache = cache = imagemagick_create_cache (signature);
-         break;
-       }
+          *pcache = cache = imagemagick_create_cache (signature);
+          break;
+        }
       if (strcmp (signature, cache->signature) == 0)
-       {
-         DestroyString (signature);
-         break;
-       }
+       break;
+      pcache = &cache->next;
     }
 
-  cache->update_time = current_emacs_time ();
+  DestroyString (signature);
+  cache->update_time = current_timespec ();
   return cache;
 }
 
@@ -8039,7 +8100,7 @@ imagemagick_compute_animated_image (MagickWand *super_wand, int ino)
            {
              /* Sanity check.  This shouldn't happen, but apparently
                 also does in some pictures.  */
-             if (x + source_left > dest_width)
+             if (x + source_left > dest_width - 1)
                break;
              /* Normally we only copy over non-transparent pixels,
                 but if the disposal method is "Background", then we
@@ -8425,6 +8486,9 @@ imagemagick_load (struct frame *f, struct image *img)
          image_error ("Cannot find image file `%s'", file_name, Qnil);
          return 0;
        }
+#ifdef WINDOWSNT
+      file = ansi_encode_filename (file);
+#endif
       success_p = imagemagick_load_image (f, img, 0, 0, SSDATA (file));
     }
   /* Else its not a file, its a lisp object.  Load the image from a
@@ -8473,7 +8537,10 @@ and `imagemagick-types-inhibit'.  */)
     {
       Qimagemagicktype = intern (imtypes[i]);
       typelist = Fcons (Qimagemagicktype, typelist);
+      imtypes[i] = MagickRelinquishMemory (imtypes[i]);
     }
+
+  MagickRelinquishMemory (imtypes);
   return Fnreverse (typelist);
 }
 
@@ -8581,7 +8648,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 *));
@@ -8592,7 +8658,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 *));
 
@@ -8601,13 +8669,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);
@@ -8624,7 +8697,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);
 
@@ -8649,7 +8724,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  */
@@ -8734,9 +8811,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 ();
 
@@ -9347,6 +9427,24 @@ 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
+        );
+  DEFSYM (Qlibjpeg_version, "libjpeg-version");
+  Fset (Qlibjpeg_version,
+#if HAVE_JPEG
+       make_number (JPEG_LIB_VERSION)
+#else
+       make_number (-1)
 #endif
        );
 #endif
@@ -9421,7 +9519,7 @@ A cross is always drawn on black & white displays.  */);
 
   DEFVAR_LISP ("x-bitmap-file-path", Vx_bitmap_file_path,
     doc: /* List of directories to search for window system bitmap files.  */);
-  Vx_bitmap_file_path = decode_env_path (0, PATH_BITMAPS);
+  Vx_bitmap_file_path = decode_env_path (0, PATH_BITMAPS, 0);
 
   DEFVAR_LISP ("image-cache-eviction-delay", Vimage_cache_eviction_delay,
     doc: /* Maximum time after which images are removed from the cache.