]> code.delx.au - gnu-emacs/blobdiff - src/image.c
Really fix last change.
[gnu-emacs] / src / image.c
index f2778165ece9dccd0b1b5c1d111ebe7259bffdf2..1c9b262c8cb59054f399fb8bc9b295320f06f590 100644 (file)
@@ -19,7 +19,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 #include <stdio.h>
-#include <math.h>
 #include <unistd.h>
 
 #ifdef HAVE_PNG
@@ -50,11 +49,19 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "termhooks.h"
 #include "font.h"
 
-#ifdef HAVE_X_WINDOWS
-#include "xterm.h"
-#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
+#endif /* HAVE_SYS_STAT_H */
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+
+#ifdef HAVE_WINDOW_SYSTEM
+#include TERM_HEADER
+#endif /* HAVE_WINDOW_SYSTEM */
 
+#ifdef HAVE_X_WINDOWS
 #define COLOR_TABLE_SUPPORT 1
 
 typedef struct x_bitmap_record Bitmap_Record;
@@ -67,11 +74,8 @@ typedef struct x_bitmap_record Bitmap_Record;
 #define PIX_MASK_DRAW  1
 #endif /* HAVE_X_WINDOWS */
 
-
 #ifdef HAVE_NTGUI
 #include "w32.h"
-#include "w32term.h"
-
 /* W32_TODO : Color tables on W32.  */
 #undef COLOR_TABLE_SUPPORT
 
@@ -84,15 +88,9 @@ typedef struct w32_bitmap_record Bitmap_Record;
 #define PIX_MASK_RETAIN        0
 #define PIX_MASK_DRAW  1
 
-#define FRAME_X_VISUAL(f) FRAME_X_DISPLAY_INFO (f)->visual
 #define x_defined_color w32_defined_color
 #define DefaultDepthOfScreen(screen) (one_w32_display_info.n_cbits)
 
-/* Functions from w32term.c that depend on XColor (so can't go in w32term.h
-   without modifying lots of files).  */
-extern void x_query_colors (struct frame *f, XColor *colors, int ncolors);
-extern void x_query_color (struct frame *f, XColor *color);
-
 /* 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.  */
@@ -100,10 +98,6 @@ Lisp_Object Qlibpng_version;
 #endif /* HAVE_NTGUI */
 
 #ifdef HAVE_NS
-#include "nsterm.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-
 #undef COLOR_TABLE_SUPPORT
 
 typedef struct ns_bitmap_record Bitmap_Record;
@@ -117,10 +111,8 @@ typedef struct ns_bitmap_record Bitmap_Record;
 #define PIX_MASK_RETAIN        0
 #define PIX_MASK_DRAW  1
 
-#define FRAME_X_VISUAL FRAME_NS_DISPLAY_INFO (f)->visual
 #define x_defined_color(f, name, color_def, alloc) \
   ns_defined_color (f, name, color_def, alloc, 0)
-#define FRAME_X_SCREEN(f) 0
 #define DefaultDepthOfScreen(screen) x_display_list->n_planes
 #endif /* HAVE_NS */
 
@@ -415,9 +407,9 @@ x_destroy_bitmap (FRAME_PTR f, ptrdiff_t id)
 
       if (--bm->refcount == 0)
        {
-         BLOCK_INPUT;
+         block_input ();
          free_bitmap_record (dpyinfo, bm);
-         UNBLOCK_INPUT;
+         unblock_input ();
        }
     }
 }
@@ -478,19 +470,19 @@ x_create_bitmap_mask (struct frame *f, ptrdiff_t id)
   width = x_bitmap_width (f, id);
   height = x_bitmap_height (f, id);
 
-  BLOCK_INPUT;
+  block_input ();
   ximg = XGetImage (FRAME_X_DISPLAY (f), pixmap, 0, 0, width, height,
                    ~0, ZPixmap);
 
   if (!ximg)
     {
-      UNBLOCK_INPUT;
+      unblock_input ();
       return -1;
     }
 
   result = x_create_x_image_and_pixmap (f, width, height, 1, &mask_img, &mask);
 
-  UNBLOCK_INPUT;
+  unblock_input ();
   if (!result)
     {
       XDestroyImage (ximg);
@@ -522,7 +514,7 @@ x_create_bitmap_mask (struct frame *f, ptrdiff_t id)
        }
     }
 
-  eassert (interrupt_input_blocked);
+  eassert (input_blocked_p ());
   gc = XCreateGC (FRAME_X_DISPLAY (f), mask, 0, NULL);
   XPutImage (FRAME_X_DISPLAY (f), mask, gc, mask_img, 0, 0, 0, 0,
             width, height);
@@ -569,8 +561,8 @@ static Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
 
 /* Function prototypes.  */
 
-static Lisp_Object define_image_type (struct image_type *type, int loaded);
-static struct image_type *lookup_image_type (Lisp_Object symbol);
+static struct image_type *define_image_type (struct image_type *);
+static struct image_type *lookup_image_type (Lisp_Object);
 static void image_error (const char *format, Lisp_Object, Lisp_Object);
 static void x_laplace (struct frame *, struct image *);
 static void x_emboss (struct frame *, struct image *);
@@ -589,46 +581,47 @@ static int x_build_heuristic_mask (struct frame *, struct image *,
 /* Define a new image type from TYPE.  This adds a copy of TYPE to
    image_types and caches the loading status of TYPE.  */
 
-static Lisp_Object
-define_image_type (struct image_type *type, int loaded)
+static struct image_type *
+define_image_type (struct image_type *type)
 {
-  Lisp_Object success;
+  struct image_type *p = NULL;
+  Lisp_Object target_type = *type->type;
+  int type_valid = 1;
 
-  if (!loaded)
-    success = Qnil;
-  else
+  block_input ();
+
+  for (p = image_types; p; p = p->next)
+    if (EQ (*p->type, target_type))
+      goto done;
+
+  if (type->init)
+    {
+#ifdef HAVE_NTGUI
+      /* If we failed to load the library before, don't try again.  */
+      Lisp_Object tested = Fassq (target_type, Vlibrary_cache);
+      if (CONSP (tested) && NILP (XCDR (tested)))
+       type_valid = 0;
+      else
+#endif
+       {
+         type_valid = type->init ();
+         CACHE_IMAGE_TYPE (target_type, type_valid ? Qt : Qnil);
+       }
+    }
+
+  if (type_valid)
     {
       /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
          The initialized data segment is read-only.  */
-      struct image_type *p = xmalloc (sizeof *p);
-      memcpy (p, type, sizeof *p);
+      p = xmalloc (sizeof *p);
+      *p = *type;
       p->next = image_types;
       image_types = p;
-      success = Qt;
     }
 
-  CACHE_IMAGE_TYPE (*type->type, success);
-  return success;
-}
-
-
-/* Look up image type SYMBOL, and return a pointer to its image_type
-   structure.  Value is null if SYMBOL is not a known image type.  */
-
-static inline struct image_type *
-lookup_image_type (Lisp_Object symbol)
-{
-  struct image_type *type;
-
-  /* We must initialize the image-type if it hasn't been already.  */
-  if (NILP (Finit_image_library (symbol, Vdynamic_library_alist)))
-    return 0;                  /* unimplemented */
-
-  for (type = image_types; type; type = type->next)
-    if (EQ (symbol, *type->type))
-      break;
-
-  return type;
+ done:
+  unblock_input ();
+  return p;
 }
 
 
@@ -848,7 +841,7 @@ parse_image_spec (Lisp_Object spec, struct image_keyword *keywords,
          break;
 
        default:
-         abort ();
+         emacs_abort ();
          break;
        }
 
@@ -1330,9 +1323,9 @@ x_clear_image_1 (struct frame *f, struct image *img, int pixmap_p, int mask_p,
 static void
 x_clear_image (struct frame *f, struct image *img)
 {
-  BLOCK_INPUT;
+  block_input ();
   x_clear_image_1 (f, img, 1, 1, 1);
-  UNBLOCK_INPUT;
+  unblock_input ();
 }
 
 
@@ -1487,7 +1480,7 @@ clear_image_cache (struct frame *f, Lisp_Object filter)
 
       /* Block input so that we won't be interrupted by a SIGIO
         while being in an inconsistent state.  */
-      BLOCK_INPUT;
+      block_input ();
 
       if (!NILP (filter))
        {
@@ -1553,7 +1546,7 @@ clear_image_cache (struct frame *f, Lisp_Object filter)
          ++windows_or_buffers_changed;
        }
 
-      UNBLOCK_INPUT;
+      unblock_input ();
     }
 }
 
@@ -1718,7 +1711,7 @@ lookup_image (struct frame *f, Lisp_Object spec)
   /* If not found, create a new image and cache it.  */
   if (img == NULL)
     {
-      BLOCK_INPUT;
+      block_input ();
       img = make_image (spec, hash);
       cache_image (f, img);
       img->load_failed_p = img->type->load (f, img) == 0;
@@ -1789,7 +1782,7 @@ lookup_image (struct frame *f, Lisp_Object spec)
            postprocess_image (f, img);
        }
 
-      UNBLOCK_INPUT;
+      unblock_input ();
     }
 
   /* We're using IMG, so set its timestamp to `now'.  */
@@ -1942,7 +1935,7 @@ x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth,
   Window window = FRAME_X_WINDOW (f);
   Screen *screen = FRAME_X_SCREEN (f);
 
-  eassert (interrupt_input_blocked);
+  eassert (input_blocked_p ());
 
   if (depth <= 0)
     depth = DefaultDepthOfScreen (screen);
@@ -2080,7 +2073,7 @@ x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth,
 static void
 x_destroy_x_image (XImagePtr ximg)
 {
-  eassert (interrupt_input_blocked);
+  eassert (input_blocked_p ());
   if (ximg)
     {
 #ifdef HAVE_X_WINDOWS
@@ -2109,7 +2102,7 @@ x_put_x_image (struct frame *f, XImagePtr ximg, Pixmap pixmap, int width, int he
 #ifdef HAVE_X_WINDOWS
   GC gc;
 
-  eassert (interrupt_input_blocked);
+  eassert (input_blocked_p ());
   gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
   XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height);
   XFreeGC (FRAME_X_DISPLAY (f), gc);
@@ -2264,6 +2257,7 @@ static struct image_type xbm_type =
   xbm_image_p,
   xbm_load,
   x_clear_image,
+  NULL,
   NULL
 };
 
@@ -3053,6 +3047,12 @@ static const struct image_keyword xpm_format[XPM_LAST] =
   {":background",      IMAGE_STRING_OR_NIL_VALUE,              0}
 };
 
+#ifdef HAVE_NTGUI
+static int init_xpm_functions (void);
+#else
+#define init_xpm_functions NULL
+#endif
+
 /* Structure describing the image type XPM.  */
 
 static struct image_type xpm_type =
@@ -3061,6 +3061,7 @@ static struct image_type xpm_type =
   xpm_image_p,
   xpm_load,
   x_clear_image,
+  init_xpm_functions,
   NULL
 };
 
@@ -3261,11 +3262,11 @@ DEF_IMGLIB_FN (int, XpmReadFileToImage, (Display *, char *, xpm_XImage **,
 DEF_IMGLIB_FN (void, XImageFree, (xpm_XImage *));
 
 static int
-init_xpm_functions (Lisp_Object libraries)
+init_xpm_functions (void)
 {
   HMODULE library;
 
-  if (!(library = w32_delayed_load (libraries, Qxpm)))
+  if (!(library = w32_delayed_load (Qxpm)))
     return 0;
 
   LOAD_IMGLIB_FN (library, XpmFreeAttributes);
@@ -4305,12 +4306,12 @@ lookup_pixel_color (struct frame *f, unsigned long pixel)
       x_query_color (f, &color);
       rc = x_alloc_nearest_color (f, cmap, &color);
 #else
-      BLOCK_INPUT;
+      block_input ();
       cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
       color.pixel = pixel;
       XQueryColor (NULL, cmap, &color);
       rc = x_alloc_nearest_color (f, cmap, &color);
-      UNBLOCK_INPUT;
+      unblock_input ();
 #endif /* HAVE_X_WINDOWS */
 
       if (rc)
@@ -4983,6 +4984,7 @@ static struct image_type pbm_type =
   pbm_image_p,
   pbm_load,
   x_clear_image,
+  NULL,
   NULL
 };
 
@@ -5389,6 +5391,12 @@ static const struct image_keyword png_format[PNG_LAST] =
   {":background",      IMAGE_STRING_OR_NIL_VALUE,              0}
 };
 
+#ifdef HAVE_NTGUI
+static int init_png_functions (void);
+#else
+#define init_png_functions NULL
+#endif
+
 /* Structure describing the image type `png'.  */
 
 static struct image_type png_type =
@@ -5397,6 +5405,7 @@ static struct image_type png_type =
   png_image_p,
   png_load,
   x_clear_image,
+  init_png_functions,
   NULL
 };
 
@@ -5455,11 +5464,11 @@ DEF_IMGLIB_FN (jmp_buf *, png_set_longjmp_fn, (png_structp, png_longjmp_ptr, siz
 #endif /* libpng version >= 1.5 */
 
 static int
-init_png_functions (Lisp_Object libraries)
+init_png_functions (void)
 {
   HMODULE library;
 
-  if (!(library = w32_delayed_load (libraries, Qpng)))
+  if (!(library = w32_delayed_load (Qpng)))
     return 0;
 
   LOAD_IMGLIB_FN (library, png_get_io_ptr);
@@ -5522,15 +5531,24 @@ init_png_functions (Lisp_Object libraries)
 
 #endif /* HAVE_NTGUI */
 
+/* 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
+#endif
 
 #if (PNG_LIBPNG_VER < 10500)
-#define PNG_LONGJMP(ptr) (longjmp ((ptr)->jmpbuf, 1))
+#define PNG_LONGJMP(ptr) (_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_JMPBUF(ptr) \
-  (*fn_png_set_longjmp_fn ((ptr), longjmp, sizeof (jmp_buf)))
+  (*fn_png_set_longjmp_fn ((ptr), _longjmp, sizeof (jmp_buf)))
 #endif
 
 /* Error and warning handlers installed when the PNG library
@@ -5599,20 +5617,31 @@ png_read_from_file (png_structp png_ptr, png_bytep data, png_size_t length)
 /* Load PNG image IMG for use on frame F.  Value is non-zero if
    successful.  */
 
+struct png_load_context
+{
+  /* These are members so that longjmp doesn't munge local variables.  */
+  png_struct *png_ptr;
+  png_info *info_ptr;
+  png_info *end_info;
+  FILE *fp;
+  png_byte *pixels;
+  png_byte **rows;
+};
+
 static int
-png_load (struct frame *f, struct image *img)
+png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
 {
   Lisp_Object file, specified_file;
   Lisp_Object specified_data;
   int x, y;
   ptrdiff_t i;
   XImagePtr ximg, mask_img = NULL;
-  png_struct *png_ptr = NULL;
+  png_struct *png_ptr;
   png_info *info_ptr = NULL, *end_info = NULL;
-  FILE *volatile fp = NULL;
+  FILE *fp = NULL;
   png_byte sig[8];
-  png_byte * volatile pixels = NULL;
-  png_byte ** volatile rows = NULL;
+  png_byte *pixels = NULL;
+  png_byte **rows = NULL;
   png_uint_32 width, height;
   int bit_depth, color_type, interlace_type;
   png_byte channels;
@@ -5679,41 +5708,47 @@ png_load (struct frame *f, struct image *img)
   png_ptr = fn_png_create_read_struct (PNG_LIBPNG_VER_STRING,
                                       NULL, my_png_error,
                                       my_png_warning);
-  if (!png_ptr)
+  if (png_ptr)
     {
-      if (fp) fclose (fp);
-      return 0;
+      info_ptr = fn_png_create_info_struct (png_ptr);
+      end_info = fn_png_create_info_struct (png_ptr);
     }
 
-  info_ptr = fn_png_create_info_struct (png_ptr);
-  if (!info_ptr)
+  c->png_ptr = png_ptr;
+  c->info_ptr = info_ptr;
+  c->end_info = end_info;
+  c->fp = fp;
+  c->pixels = pixels;
+  c->rows = rows;
+
+  if (! (info_ptr && end_info))
     {
-      fn_png_destroy_read_struct (&png_ptr, NULL, NULL);
-      if (fp) fclose (fp);
-      return 0;
+      fn_png_destroy_read_struct (&c->png_ptr, &c->info_ptr, &c->end_info);
+      png_ptr = 0;
     }
-
-  end_info = fn_png_create_info_struct (png_ptr);
-  if (!end_info)
+  if (! png_ptr)
     {
-      fn_png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
       if (fp) fclose (fp);
       return 0;
     }
 
   /* Set error jump-back.  We come back here when the PNG library
      detects an error.  */
-  if (setjmp (PNG_JMPBUF (png_ptr)))
+  if (_setjmp (PNG_JMPBUF (png_ptr)))
     {
     error:
-      if (png_ptr)
-        fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
-      xfree (pixels);
-      xfree (rows);
-      if (fp) fclose (fp);
+      if (c->png_ptr)
+       fn_png_destroy_read_struct (&c->png_ptr, &c->info_ptr, &c->end_info);
+      xfree (c->pixels);
+      xfree (c->rows);
+      if (c->fp)
+       fclose (c->fp);
       return 0;
     }
 
+  /* Silence a bogus diagnostic; see GCC bug 54561.  */
+  IF_LINT (fp = c->fp);
+
   /* Read image info.  */
   if (!NILP (specified_data))
     fn_png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
@@ -5829,8 +5864,8 @@ png_load (struct frame *f, struct image *img)
   if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof *rows < height
       || min (PTRDIFF_MAX, SIZE_MAX) / sizeof *pixels / height < row_bytes)
     memory_full (SIZE_MAX);
-  pixels = xmalloc (sizeof *pixels * row_bytes * height);
-  rows = xmalloc (height * sizeof *rows);
+  c->pixels = pixels = xmalloc (sizeof *pixels * row_bytes * height);
+  c->rows = rows = xmalloc (height * sizeof *rows);
   for (i = 0; i < height; ++i)
     rows[i] = pixels + i * row_bytes;
 
@@ -5840,7 +5875,7 @@ png_load (struct frame *f, struct image *img)
   if (fp)
     {
       fclose (fp);
-      fp = NULL;
+      c->fp = NULL;
     }
 
   /* Create an image and pixmap serving as mask if the PNG image
@@ -5915,7 +5950,7 @@ png_load (struct frame *f, struct image *img)
 #endif /* COLOR_TABLE_SUPPORT */
 
   /* Clean up.  */
-  fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
+  fn_png_destroy_read_struct (&c->png_ptr, &c->info_ptr, &c->end_info);
   xfree (rows);
   xfree (pixels);
 
@@ -5944,6 +5979,13 @@ png_load (struct frame *f, struct image *img)
   return 1;
 }
 
+static int
+png_load (struct frame *f, struct image *img)
+{
+  struct png_load_context c;
+  return png_load_body (f, img, &c);
+}
+
 #else /* HAVE_PNG */
 
 #ifdef HAVE_NS
@@ -6008,6 +6050,12 @@ static const struct image_keyword jpeg_format[JPEG_LAST] =
   {":background",      IMAGE_STRING_OR_NIL_VALUE,              0}
 };
 
+#ifdef HAVE_NTGUI
+static int init_jpeg_functions (void);
+#else
+#define init_jpeg_functions NULL
+#endif
+
 /* Structure describing the image type `jpeg'.  */
 
 static struct image_type jpeg_type =
@@ -6016,6 +6064,7 @@ static struct image_type jpeg_type =
   jpeg_image_p,
   jpeg_load,
   x_clear_image,
+  init_jpeg_functions,
   NULL
 };
 
@@ -6071,11 +6120,11 @@ DEF_IMGLIB_FN (struct jpeg_error_mgr *, jpeg_std_error, (struct jpeg_error_mgr *
 DEF_IMGLIB_FN (boolean, jpeg_resync_to_restart, (j_decompress_ptr, int));
 
 static int
-init_jpeg_functions (Lisp_Object libraries)
+init_jpeg_functions (void)
 {
   HMODULE library;
 
-  if (!(library = w32_delayed_load (libraries, Qjpeg)))
+  if (!(library = w32_delayed_load (Qjpeg)))
     return 0;
 
   LOAD_IMGLIB_FN (library, jpeg_finish_decompress);
@@ -6113,7 +6162,20 @@ jpeg_resync_to_restart_wrapper (j_decompress_ptr cinfo, int desired)
 struct my_jpeg_error_mgr
 {
   struct jpeg_error_mgr pub;
-  jmp_buf setjmp_buffer;
+  sys_jmp_buf setjmp_buffer;
+
+  /* The remaining members are so that longjmp doesn't munge local
+     variables.  */
+  struct jpeg_decompress_struct cinfo;
+  enum
+    {
+      MY_JPEG_ERROR_EXIT,
+      MY_JPEG_INVALID_IMAGE_SIZE,
+      MY_JPEG_CANNOT_CREATE_X
+    } failure_code;
+#ifdef lint
+  FILE *fp;
+#endif
 };
 
 
@@ -6121,7 +6183,8 @@ static _Noreturn void
 my_error_exit (j_common_ptr cinfo)
 {
   struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
-  longjmp (mgr->setjmp_buffer, 1);
+  mgr->failure_code = MY_JPEG_ERROR_EXIT;
+  sys_longjmp (mgr->setjmp_buffer, 1);
 }
 
 
@@ -6189,7 +6252,7 @@ our_memory_skip_input_data (j_decompress_ptr cinfo, long int num_bytes)
    reading the image.  */
 
 static void
-jpeg_memory_src (j_decompress_ptr cinfo, JOCTET *data, unsigned int len)
+jpeg_memory_src (j_decompress_ptr cinfo, JOCTET *data, ptrdiff_t len)
 {
   struct jpeg_source_mgr *src;
 
@@ -6327,17 +6390,15 @@ jpeg_file_src (j_decompress_ptr cinfo, FILE *fp)
    from the JPEG lib.  */
 
 static int
-jpeg_load (struct frame *f, struct image *img)
+jpeg_load_body (struct frame *f, struct image *img,
+               struct my_jpeg_error_mgr *mgr)
 {
-  struct jpeg_decompress_struct cinfo;
-  struct my_jpeg_error_mgr mgr;
   Lisp_Object file, specified_file;
   Lisp_Object specified_data;
-  FILE * volatile fp = NULL;
+  FILE *fp = NULL;
   JSAMPARRAY buffer;
   int row_stride, x, y;
   XImagePtr ximg = NULL;
-  int rc;
   unsigned long *colors;
   int width, height;
 
@@ -6367,26 +6428,37 @@ jpeg_load (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.  */
-  cinfo.err = fn_jpeg_std_error (&mgr.pub);
-  mgr.pub.error_exit = my_error_exit;
-
-  if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
+  mgr->cinfo.err = fn_jpeg_std_error (&mgr->pub);
+  mgr->pub.error_exit = my_error_exit;
+  if (sys_setjmp (mgr->setjmp_buffer))
     {
-      if (rc == 1)
+      switch (mgr->failure_code)
        {
-         /* Called from my_error_exit.  Display a JPEG error.  */
-         char buf[JMSG_LENGTH_MAX];
-         cinfo.err->format_message ((j_common_ptr) &cinfo, buf);
-         image_error ("Error reading JPEG image `%s': %s", img->spec,
-                      build_string (buf));
+       case MY_JPEG_ERROR_EXIT:
+         {
+           char buf[JMSG_LENGTH_MAX];
+           mgr->cinfo.err->format_message ((j_common_ptr) &mgr->cinfo, buf);
+           image_error ("Error reading JPEG image `%s': %s", img->spec,
+                        build_string (buf));
+           break;
+         }
+
+       case MY_JPEG_INVALID_IMAGE_SIZE:
+         image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
+         break;
+
+       case MY_JPEG_CANNOT_CREATE_X:
+         break;
        }
 
       /* Close the input file and destroy the JPEG object.  */
       if (fp)
-       fclose ((FILE *) fp);
-      fn_jpeg_destroy_decompress (&cinfo);
+       fclose (fp);
+      fn_jpeg_destroy_decompress (&mgr->cinfo);
 
       /* If we already have an XImage, free that.  */
       x_destroy_x_image (ximg);
@@ -6396,46 +6468,52 @@ jpeg_load (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 (&cinfo, JPEG_LIB_VERSION, sizeof (cinfo));
+  fn_jpeg_CreateDecompress (&mgr->cinfo, JPEG_LIB_VERSION, sizeof *&mgr->cinfo);
 
   if (NILP (specified_data))
-    jpeg_file_src (&cinfo, (FILE *) fp);
+    jpeg_file_src (&mgr->cinfo, fp);
   else
-    jpeg_memory_src (&cinfo, SDATA (specified_data),
+    jpeg_memory_src (&mgr->cinfo, SDATA (specified_data),
                     SBYTES (specified_data));
 
-  fn_jpeg_read_header (&cinfo, 1);
+  fn_jpeg_read_header (&mgr->cinfo, 1);
 
   /* Customize decompression so that color quantization will be used.
         Start decompression.  */
-  cinfo.quantize_colors = 1;
-  fn_jpeg_start_decompress (&cinfo);
-  width = img->width = cinfo.output_width;
-  height = img->height = cinfo.output_height;
+  mgr->cinfo.quantize_colors = 1;
+  fn_jpeg_start_decompress (&mgr->cinfo);
+  width = img->width = mgr->cinfo.output_width;
+  height = img->height = mgr->cinfo.output_height;
 
   if (!check_image_size (f, width, height))
     {
-      image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
-      longjmp (mgr.setjmp_buffer, 2);
+      mgr->failure_code = MY_JPEG_INVALID_IMAGE_SIZE;
+      sys_longjmp (mgr->setjmp_buffer, 1);
     }
 
   /* Create X image and pixmap.  */
   if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
-    longjmp (mgr.setjmp_buffer, 2);
+    {
+      mgr->failure_code = MY_JPEG_CANNOT_CREATE_X;
+      sys_longjmp (mgr->setjmp_buffer, 1);
+    }
 
   /* Allocate colors.  When color quantization is used,
-     cinfo.actual_number_of_colors has been set with the number of
-     colors generated, and cinfo.colormap is a two-dimensional array
-     of color indices in the range 0..cinfo.actual_number_of_colors.
+     mgr->cinfo.actual_number_of_colors has been set with the number of
+     colors generated, and mgr->cinfo.colormap is a two-dimensional array
+     of color indices in the range 0..mgr->cinfo.actual_number_of_colors.
      No more than 255 colors will be generated.  */
   {
     int i, ir, ig, ib;
 
-    if (cinfo.out_color_components > 2)
+    if (mgr->cinfo.out_color_components > 2)
       ir = 0, ig = 1, ib = 2;
-    else if (cinfo.out_color_components > 1)
+    else if (mgr->cinfo.out_color_components > 1)
       ir = 0, ig = 1, ib = 0;
     else
       ir = 0, ig = 0, ib = 0;
@@ -6445,15 +6523,15 @@ jpeg_load (struct frame *f, struct image *img)
        a default color, and we don't have to care about which colors
        can be freed safely, and which can't.  */
     init_color_table ();
-    colors = alloca (cinfo.actual_number_of_colors * sizeof *colors);
+    colors = alloca (mgr->cinfo.actual_number_of_colors * sizeof *colors);
 
-    for (i = 0; i < cinfo.actual_number_of_colors; ++i)
+    for (i = 0; i < mgr->cinfo.actual_number_of_colors; ++i)
       {
        /* Multiply RGB values with 255 because X expects RGB values
           in the range 0..0xffff.  */
-       int r = cinfo.colormap[ir][i] << 8;
-       int g = cinfo.colormap[ig][i] << 8;
-       int b = cinfo.colormap[ib][i] << 8;
+       int r = mgr->cinfo.colormap[ir][i] << 8;
+       int g = mgr->cinfo.colormap[ig][i] << 8;
+       int b = mgr->cinfo.colormap[ib][i] << 8;
        colors[i] = lookup_rgb_color (f, r, g, b);
       }
 
@@ -6465,21 +6543,21 @@ jpeg_load (struct frame *f, struct image *img)
   }
 
   /* Read pixels.  */
-  row_stride = width * cinfo.output_components;
-  buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
-                                   row_stride, 1);
+  row_stride = width * mgr->cinfo.output_components;
+  buffer = mgr->cinfo.mem->alloc_sarray ((j_common_ptr) &mgr->cinfo,
+                                        JPOOL_IMAGE, row_stride, 1);
   for (y = 0; y < height; ++y)
     {
-      fn_jpeg_read_scanlines (&cinfo, buffer, 1);
-      for (x = 0; x < cinfo.output_width; ++x)
+      fn_jpeg_read_scanlines (&mgr->cinfo, buffer, 1);
+      for (x = 0; x < mgr->cinfo.output_width; ++x)
        XPutPixel (ximg, x, y, colors[buffer[0][x]]);
     }
 
   /* Clean up.  */
-  fn_jpeg_finish_decompress (&cinfo);
-  fn_jpeg_destroy_decompress (&cinfo);
+  fn_jpeg_finish_decompress (&mgr->cinfo);
+  fn_jpeg_destroy_decompress (&mgr->cinfo);
   if (fp)
-    fclose ((FILE *) fp);
+    fclose (fp);
 
   /* Maybe fill in the background field while we have ximg handy. */
   if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
@@ -6492,6 +6570,13 @@ jpeg_load (struct frame *f, struct image *img)
   return 1;
 }
 
+static int
+jpeg_load (struct frame *f, struct image *img)
+{
+  struct my_jpeg_error_mgr mgr;
+  return jpeg_load_body (f, img, &mgr);
+}
+
 #else /* HAVE_JPEG */
 
 #ifdef HAVE_NS
@@ -6557,6 +6642,12 @@ static const struct image_keyword tiff_format[TIFF_LAST] =
   {":index",           IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0}
 };
 
+#ifdef HAVE_NTGUI
+static int init_tiff_functions (void);
+#else
+#define init_tiff_functions NULL
+#endif
+
 /* Structure describing the image type `tiff'.  */
 
 static struct image_type tiff_type =
@@ -6565,6 +6656,7 @@ static struct image_type tiff_type =
   tiff_image_p,
   tiff_load,
   x_clear_image,
+  init_tiff_functions,
   NULL
 };
 
@@ -6605,11 +6697,11 @@ DEF_IMGLIB_FN (void, TIFFClose, (TIFF *));
 DEF_IMGLIB_FN (int, TIFFSetDirectory, (TIFF *, tdir_t));
 
 static int
-init_tiff_functions (Lisp_Object libraries)
+init_tiff_functions (void)
 {
   HMODULE library;
 
-  if (!(library = w32_delayed_load (libraries, Qtiff)))
+  if (!(library = w32_delayed_load (Qtiff)))
     return 0;
 
   LOAD_IMGLIB_FN (library, TIFFSetErrorHandler);
@@ -7005,6 +7097,12 @@ static const struct image_keyword gif_format[GIF_LAST] =
   {":background",      IMAGE_STRING_OR_NIL_VALUE,              0}
 };
 
+#ifdef HAVE_NTGUI
+static int init_gif_functions (void);
+#else
+#define init_gif_functions NULL
+#endif
+
 /* Structure describing the image type `gif'.  */
 
 static struct image_type gif_type =
@@ -7013,6 +7111,7 @@ static struct image_type gif_type =
   gif_image_p,
   gif_load,
   gif_clear_image,
+  init_gif_functions,
   NULL
 };
 
@@ -7071,11 +7170,11 @@ DEF_IMGLIB_FN (GifFileType *, DGifOpen, (void *, InputFunc));
 DEF_IMGLIB_FN (GifFileType *, DGifOpenFileName, (const char *));
 
 static int
-init_gif_functions (Lisp_Object libraries)
+init_gif_functions (void)
 {
   HMODULE library;
 
-  if (!(library = w32_delayed_load (libraries, Qgif)))
+  if (!(library = w32_delayed_load (Qgif)))
     return 0;
 
   LOAD_IMGLIB_FN (library, DGifCloseFile);
@@ -7495,6 +7594,12 @@ static struct image_keyword imagemagick_format[IMAGEMAGICK_LAST] =
     {":crop",          IMAGE_DONT_CHECK_VALUE_TYPE,            0}
   };
 
+#ifdef HAVE_NTGUI
+static int init_imagemagick_functions (void);
+#else
+#define init_imagemagick_functions NULL
+#endif
+
 /* Structure describing the image type for any image handled via
    ImageMagick.  */
 
@@ -7504,6 +7609,7 @@ static struct image_type imagemagick_type =
     imagemagick_image_p,
     imagemagick_load,
     imagemagick_clear_image,
+    init_imagemagick_functions,
     NULL
   };
 
@@ -8042,22 +8148,23 @@ static const struct image_keyword svg_format[SVG_LAST] =
   {":background",      IMAGE_STRING_OR_NIL_VALUE,              0}
 };
 
+#ifdef HAVE_NTGUI
+static int init_svg_functions (void);
+#else
+#define init_svg_functions NULL
+#endif
+
 /* Structure describing the image type `svg'.  Its the same type of
    structure defined for all image formats, handled by emacs image
    functions.  See struct image_type in dispextern.h.  */
 
 static struct image_type svg_type =
 {
-  /* An identifier showing that this is an image structure for the SVG format.  */
   &Qsvg,
-  /* Handle to a function that can be used to identify a SVG file.  */
   svg_image_p,
-  /* Handle to function used to load a SVG file.  */
   svg_load,
-  /* Handle to function to free sresources for SVG.  */
   x_clear_image,
-  /* An internal field to link to the next image type in a list of
-     image types, will be filled in when registering the format.  */
+  init_svg_functions,
   NULL
 };
 
@@ -8106,14 +8213,14 @@ DEF_IMGLIB_FN (void, g_error_free);
 Lisp_Object Qgdk_pixbuf, Qglib, Qgobject;
 
 static int
-init_svg_functions (Lisp_Object libraries)
+init_svg_functions (void)
 {
   HMODULE library, gdklib, glib, gobject;
 
-  if (!(glib = w32_delayed_load (libraries, Qglib))
-      || !(gobject = w32_delayed_load (libraries, Qgobject))
-      || !(gdklib = w32_delayed_load (libraries, Qgdk_pixbuf))
-      || !(library = w32_delayed_load (libraries, Qsvg)))
+  if (!(glib = w32_delayed_load (Qglib))
+      || !(gobject = w32_delayed_load (Qgobject))
+      || !(gdklib = w32_delayed_load (Qgdk_pixbuf))
+      || !(library = w32_delayed_load (Qsvg)))
     return 0;
 
   LOAD_IMGLIB_FN (library, rsvg_handle_new);
@@ -8445,6 +8552,7 @@ static struct image_type gs_type =
   gs_image_p,
   gs_load,
   gs_clear_image,
+  NULL,
   NULL
 };
 
@@ -8537,11 +8645,11 @@ gs_load (struct frame *f, struct image *img)
   if (x_check_image_size (0, img->width, img->height))
     {
       /* Only W32 version did BLOCK_INPUT here.  ++kfs */
-      BLOCK_INPUT;
+      block_input ();
       img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
                                   img->width, img->height,
                                   DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
-      UNBLOCK_INPUT;
+      unblock_input ();
     }
 
   if (!img->pixmap)
@@ -8617,7 +8725,7 @@ x_kill_gs_process (Pixmap pixmap, struct frame *f)
     {
       XImagePtr ximg;
 
-      BLOCK_INPUT;
+      block_input ();
 
       /* Try to get an XImage for img->pixmep.  */
       ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
@@ -8660,15 +8768,15 @@ x_kill_gs_process (Pixmap pixmap, struct frame *f)
        image_error ("Cannot get X image of `%s'; colors will not be freed",
                     img->spec, Qnil);
 
-      UNBLOCK_INPUT;
+      unblock_input ();
     }
 #endif /* HAVE_X_WINDOWS */
 
   /* Now that we have the pixmap, compute mask and transform the
      image if requested.  */
-  BLOCK_INPUT;
+  block_input ();
   postprocess_image (f, img);
-  UNBLOCK_INPUT;
+  unblock_input ();
 }
 
 #endif /* HAVE_GHOSTSCRIPT */
@@ -8707,80 +8815,72 @@ DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
                            Initialization
  ***********************************************************************/
 
-#ifdef HAVE_NTGUI
-/* Image types that rely on external libraries are loaded dynamically
-   if the library is available.  */
-#define CHECK_LIB_AVAILABLE(image_type, init_lib_fn, libraries) \
-  define_image_type (image_type, init_lib_fn (libraries))
-#else
-#define CHECK_LIB_AVAILABLE(image_type, init_lib_fn, libraries) \
-  define_image_type (image_type, 1)
-#endif /* HAVE_NTGUI */
-
-DEFUN ("init-image-library", Finit_image_library, Sinit_image_library, 2, 2, 0,
+DEFUN ("init-image-library", Finit_image_library, Sinit_image_library, 1, 1, 0,
        doc: /* Initialize image library implementing image type TYPE.
 Return non-nil if TYPE is a supported image type.
 
-Image types pbm and xbm are prebuilt; other types are loaded here.
-Libraries to load are specified in alist LIBRARIES (usually, the value
-of `dynamic-library-alist', which see).  */)
-  (Lisp_Object type, Lisp_Object libraries)
+If image libraries are loaded dynamically (currently only the case on
+MS-Windows), load the library for TYPE if it is not yet loaded, using
+the library file(s) specified by `dynamic-library-alist'.  */)
+  (Lisp_Object type)
 {
-#ifdef HAVE_NTGUI
-  /* Don't try to reload the library.  */
-  Lisp_Object tested = Fassq (type, Vlibrary_cache);
-  if (CONSP (tested))
-    return XCDR (tested);
-#endif
+  return lookup_image_type (type) ? Qt : Qnil;
+}
 
+/* Look up image type TYPE, and return a pointer to its image_type
+   structure.  Return 0 if TYPE is not a known image type.  */
+
+static struct image_type *
+lookup_image_type (Lisp_Object type)
+{
   /* Types pbm and xbm are built-in and always available.  */
-  if (EQ (type, Qpbm) || EQ (type, Qxbm))
-    return Qt;
+  if (EQ (type, Qpbm))
+    return define_image_type (&pbm_type);
+
+  if (EQ (type, Qxbm))
+    return define_image_type (&xbm_type);
 
 #if defined (HAVE_XPM) || defined (HAVE_NS)
   if (EQ (type, Qxpm))
-    return CHECK_LIB_AVAILABLE (&xpm_type, init_xpm_functions, libraries);
+    return define_image_type (&xpm_type);
 #endif
 
 #if defined (HAVE_JPEG) || defined (HAVE_NS)
   if (EQ (type, Qjpeg))
-    return CHECK_LIB_AVAILABLE (&jpeg_type, init_jpeg_functions, libraries);
+    return define_image_type (&jpeg_type);
 #endif
 
 #if defined (HAVE_TIFF) || defined (HAVE_NS)
   if (EQ (type, Qtiff))
-    return CHECK_LIB_AVAILABLE (&tiff_type, init_tiff_functions, libraries);
+    return define_image_type (&tiff_type);
 #endif
 
 #if defined (HAVE_GIF) || defined (HAVE_NS)
   if (EQ (type, Qgif))
-    return CHECK_LIB_AVAILABLE (&gif_type, init_gif_functions, libraries);
+    return define_image_type (&gif_type);
 #endif
 
 #if defined (HAVE_PNG) || defined (HAVE_NS)
   if (EQ (type, Qpng))
-    return CHECK_LIB_AVAILABLE (&png_type, init_png_functions, libraries);
+    return define_image_type (&png_type);
 #endif
 
 #if defined (HAVE_RSVG)
   if (EQ (type, Qsvg))
-    return CHECK_LIB_AVAILABLE (&svg_type, init_svg_functions, libraries);
+    return define_image_type (&svg_type);
 #endif
 
 #if defined (HAVE_IMAGEMAGICK)
   if (EQ (type, Qimagemagick))
-    return CHECK_LIB_AVAILABLE (&imagemagick_type, init_imagemagick_functions,
-                                libraries);
+    return define_image_type (&imagemagick_type);
 #endif
 
 #ifdef HAVE_GHOSTSCRIPT
   if (EQ (type, Qpostscript))
-    return CHECK_LIB_AVAILABLE (&gs_type, init_gs_functions, libraries);
+    return define_image_type (&gs_type);
 #endif
 
-  /* If the type is not recognized, avoid testing it ever again.  */
-  CACHE_IMAGE_TYPE (type, Qnil);
-  return Qnil;
+  return NULL;
 }
 
 void
@@ -8811,15 +8911,6 @@ as a ratio to the frame height and width.  If the value is
 non-numeric, there is no explicit limit on the size of images.  */);
   Vmax_image_size = make_float (MAX_IMAGE_SIZE);
 
-  DEFSYM (Qpbm, "pbm");
-  ADD_IMAGE_TYPE (Qpbm);
-
-  DEFSYM (Qxbm, "xbm");
-  ADD_IMAGE_TYPE (Qxbm);
-
-  define_image_type (&xbm_type, 1);
-  define_image_type (&pbm_type, 1);
-
   DEFSYM (Qcount, "count");
   DEFSYM (Qextension_data, "extension-data");
   DEFSYM (Qdelay, "delay");
@@ -8863,6 +8954,12 @@ non-numeric, there is no explicit limit on the size of images.  */);
        );
 #endif
 
+  DEFSYM (Qpbm, "pbm");
+  ADD_IMAGE_TYPE (Qpbm);
+
+  DEFSYM (Qxbm, "xbm");
+  ADD_IMAGE_TYPE (Qxbm);
+
 #if defined (HAVE_XPM) || defined (HAVE_NS)
   DEFSYM (Qxpm, "xpm");
   ADD_IMAGE_TYPE (Qxpm);