* gnu.h (gnu_bits): Xpm version of the new Emacs icon.
[bpt/emacs.git] / src / image.c
index 1067227..aec66eb 100644 (file)
@@ -1,6 +1,6 @@
 /* Functions for image support on window system.
-   Copyright (C) 1989, 92, 93, 94, 95, 96, 97, 98, 99, 2000,01,02,03,04
-     Free Software Foundation.
+   Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+                 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -16,13 +16,13 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 #include <config.h>
-#include <signal.h>
 #include <stdio.h>
 #include <math.h>
+#include <ctype.h>
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
@@ -49,16 +49,13 @@ Boston, MA 02111-1307, USA.  */
 #define COLOR_TABLE_SUPPORT 1
 
 typedef struct x_bitmap_record Bitmap_Record;
-typedef XImage * XImagePtr;
-typedef XImagePtr XImagePtr_or_DC;
 #define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y)
 #define NO_PIXMAP None
-#define PNG_BG_COLOR_SHIFT 0
 
 #define RGB_PIXEL_COLOR unsigned long
 
-#define PIX_MASK_RETAIN(f) 0
-#define PIX_MASK_DRAW(f) 1
+#define PIX_MASK_RETAIN        0
+#define PIX_MASK_DRAW  1
 #endif /* HAVE_X_WINDOWS */
 
 
@@ -69,16 +66,13 @@ typedef XImagePtr XImagePtr_or_DC;
 #undef COLOR_TABLE_SUPPORT
 
 typedef struct w32_bitmap_record Bitmap_Record;
-typedef XImage *XImagePtr;
-typedef HDC XImagePtr_or_DC;
 #define GET_PIXEL(ximg, x, y) GetPixel(ximg, x, y)
 #define NO_PIXMAP 0
-#define PNG_BG_COLOR_SHIFT 0
 
 #define RGB_PIXEL_COLOR COLORREF
 
-#define PIX_MASK_RETAIN(f) 0
-#define PIX_MASK_DRAW(f) 1
+#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
@@ -88,33 +82,41 @@ typedef HDC XImagePtr_or_DC;
 
 #ifdef MAC_OS
 #include "macterm.h"
+#include <sys/stat.h>
 #ifndef MAC_OSX
 #include <alloca.h>
+#include <sys/param.h>
 #endif
+#if TARGET_API_MAC_CARBON
 #ifdef MAC_OSX
-#include <sys/stat.h>
 #include <QuickTime/QuickTime.h>
-#else /* not MAC_OSX */
+#else  /* not MAC_OSX */
+#include <QuickTime.h>
+#endif /* not MAC_OSX */
+#else  /* not TARGET_API_MAC_CARBON */
 #include <Windows.h>
 #include <Gestalt.h>
 #include <TextUtils.h>
-#endif /* not MAC_OSX */
+#include <ImageCompression.h>
+#include <QuickTimeComponents.h>
+#endif /* not TARGET_API_MAC_CARBON */
 
 /* MAC_TODO : Color tables on Mac.  */
 #undef COLOR_TABLE_SUPPORT
 
-/* Mac equivalent of XImage.  */
-typedef Pixmap XImagePtr;
 #define ZPixmap 0              /* arbitrary */
 typedef struct mac_bitmap_record Bitmap_Record;
 
-typedef XImagePtr XImagePtr_or_DC;
 #define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y)
 #define NO_PIXMAP 0
-#define PNG_BG_COLOR_SHIFT 8
 
 #define RGB_PIXEL_COLOR unsigned long
 
+/* A black pixel in a mask bitmap/pixmap means ``draw a source
+   pixel''.  A white pixel means ``retain the current pixel''. */
+#define PIX_MASK_DRAW  RGB_TO_ULONG(0,0,0)
+#define PIX_MASK_RETAIN        RGB_TO_ULONG(255,255,255)
+
 #define FRAME_X_VISUAL(f) FRAME_X_DISPLAY_INFO (f)->visual
 #define x_defined_color mac_defined_color
 #define DefaultDepthOfScreen(screen) (one_mac_display_info.n_planes)
@@ -184,14 +186,43 @@ XPutPixel (ximage, x, y, pixel)
      int x, y;
      unsigned long pixel;
 {
-  RGBColor color;
+  PixMapHandle pixmap = GetGWorldPixMap (ximage);
+  short depth = GetPixDepth (pixmap);
+
+  if (depth == 32)
+    {
+      char *base_addr = GetPixBaseAddr (pixmap);
+      short row_bytes = GetPixRowBytes (pixmap);
+
+      ((unsigned long *) (base_addr + y * row_bytes))[x] = pixel;
+    }
+  else if (depth == 1)
+    {
+      char *base_addr = GetPixBaseAddr (pixmap);
+      short row_bytes = GetPixRowBytes (pixmap);
+
+      if (pixel == PIX_MASK_DRAW)
+       base_addr[y * row_bytes + x / 8] |= (1 << 7) >> (x & 7);
+      else
+       base_addr[y * row_bytes + x / 8] &= ~((1 << 7) >> (x & 7));
+    }
+  else
+    {
+      CGrafPtr old_port;
+      GDHandle old_gdh;
+      RGBColor color;
+
+      GetGWorld (&old_port, &old_gdh);
+      SetGWorld (ximage, NULL);
+
+      color.red = RED16_FROM_ULONG (pixel);
+      color.green = GREEN16_FROM_ULONG (pixel);
+      color.blue = BLUE16_FROM_ULONG (pixel);
 
-  SetGWorld (ximage, NULL);
+      SetCPixel (x, y, &color);
 
-  color.red = RED16_FROM_ULONG (pixel);
-  color.green = GREEN16_FROM_ULONG (pixel);
-  color.blue = BLUE16_FROM_ULONG (pixel);
-  SetCPixel (x, y, &color);
+      SetGWorld (old_port, old_gdh);
+    }
 }
 
 static unsigned long
@@ -199,12 +230,40 @@ XGetPixel (ximage, x, y)
      XImagePtr ximage;
      int x, y;
 {
-  RGBColor color;
+  PixMapHandle pixmap = GetGWorldPixMap (ximage);
+  short depth = GetPixDepth (pixmap);
+
+  if (depth == 32)
+    {
+      char *base_addr = GetPixBaseAddr (pixmap);
+      short row_bytes = GetPixRowBytes (pixmap);
+
+      return ((unsigned long *) (base_addr + y * row_bytes))[x];
+    }
+  else if (depth == 1)
+    {
+      char *base_addr = GetPixBaseAddr (pixmap);
+      short row_bytes = GetPixRowBytes (pixmap);
+
+      if (base_addr[y * row_bytes + x / 8] & (1 << (~x & 7)))
+       return PIX_MASK_DRAW;
+      else
+       return PIX_MASK_RETAIN;
+    }
+  else
+    {
+      CGrafPtr old_port;
+      GDHandle old_gdh;
+      RGBColor color;
+
+      GetGWorld (&old_port, &old_gdh);
+      SetGWorld (ximage, NULL);
 
-  SetGWorld (ximage, NULL);
+      GetCPixel (x, y, &color);
 
-  GetCPixel (x, y, &color);
-  return RGB_TO_ULONG (color.red >> 8, color.green >> 8, color.blue >> 8);
+      SetGWorld (old_port, old_gdh);
+      return RGB_TO_ULONG (color.red >> 8, color.green >> 8, color.blue >> 8);
+    }
 }
 
 static void
@@ -213,7 +272,7 @@ XDestroyImage (ximg)
 {
   UnlockPixels (GetGWorldPixMap (ximg));
 }
-#endif
+#endif /* MAC_OS */
 
 
 /* Functions to access the contents of a bitmap, given an id.  */
@@ -605,6 +664,18 @@ x_create_bitmap_mask (f, id)
 
 static struct image_type *image_types;
 
+/* A list of symbols, one for each supported image type.  */
+
+Lisp_Object Vimage_types;
+
+/* An alist of image types and libraries that implement the type.  */
+
+Lisp_Object Vimage_library_alist;
+
+/* Cache for delayed-loading image types.  */
+
+static Lisp_Object Vimage_type_cache;
+
 /* The symbol `xbm' which is used as the type symbol for XBM images.  */
 
 Lisp_Object Qxbm;
@@ -613,6 +684,7 @@ Lisp_Object Qxbm;
 
 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
 extern Lisp_Object QCdata, QCtype;
+extern Lisp_Object Qcenter;
 Lisp_Object QCascent, QCmargin, QCrelief;
 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
 Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
@@ -620,7 +692,6 @@ Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
 /* Other symbols.  */
 
 Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
-Lisp_Object Qcenter;
 
 /* Time in seconds after which images should be removed from the cache
    if not displayed.  */
@@ -629,7 +700,7 @@ Lisp_Object Vimage_cache_eviction_delay;
 
 /* Function prototypes.  */
 
-static void define_image_type P_ ((struct image_type *type));
+static Lisp_Object define_image_type P_ ((struct image_type *type, int loaded));
 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
 static void x_laplace P_ ((struct frame *, struct image *));
@@ -637,21 +708,37 @@ static void x_emboss P_ ((struct frame *, struct image *));
 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
                                       Lisp_Object));
 
+#define CACHE_IMAGE_TYPE(type, status) \
+  do { Vimage_type_cache = Fcons (Fcons (type, status), Vimage_type_cache); } while (0)
+
+#define ADD_IMAGE_TYPE(type) \
+  do { Vimage_types = Fcons (type, Vimage_types); } while (0)
 
 /* Define a new image type from TYPE.  This adds a copy of TYPE to
-   image_types and adds the symbol *TYPE->type to Vimage_types.  */
+   image_types and caches the loading status of TYPE.  */
 
-static void
-define_image_type (type)
+static Lisp_Object
+define_image_type (type, loaded)
      struct image_type *type;
+     int loaded;
 {
-  /* 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 = (struct image_type *) xmalloc (sizeof *p);
-  bcopy (type, p, sizeof *p);
-  p->next = image_types;
-  image_types = p;
-  Vimage_types = Fcons (*p->type, Vimage_types);
+  Lisp_Object success;
+
+  if (!loaded)
+    success = Qnil;
+  else
+    {
+      /* 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 = (struct image_type *) xmalloc (sizeof *p);
+      bcopy (type, p, sizeof *p);
+      p->next = image_types;
+      image_types = p;
+      success = Qt;
+    }
+
+  CACHE_IMAGE_TYPE (*type->type, success);
+  return success;
 }
 
 
@@ -664,6 +751,10 @@ lookup_image_type (symbol)
 {
   struct image_type *type;
 
+  /* We must initialize the image-type if it hasn't been already.  */
+  if (NILP (Finit_image_library (symbol, Vimage_library_alist)))
+    return 0;                  /* unimplemented */
+
   for (type = image_types; type; type = type->next)
     if (EQ (symbol, *type->type))
       break;
@@ -1008,7 +1099,10 @@ or omitted means use the selected frame.  */)
 
 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
 static void free_image P_ ((struct frame *f, struct image *img));
+static int check_image_size P_ ((struct frame *f, int width, int height));
 
+#define MAX_IMAGE_SIZE 6.0
+Lisp_Object Vmax_image_size;
 
 /* Allocate and return a new image structure for image specification
    SPEC.  SPEC has a hash value of HASH.  */
@@ -1060,6 +1154,39 @@ free_image (f, img)
     }
 }
 
+/* Return 1 if the given widths and heights are valid for display;
+   otherwise, return 0. */
+
+int
+check_image_size (f, width, height)
+     struct frame *f;
+     int width;
+     int height;
+{
+  int w, h;
+
+  if (width <= 0 || height <= 0)
+    return 0;
+
+  if (INTEGERP (Vmax_image_size))
+    w = h = XINT (Vmax_image_size);
+  else if (FLOATP (Vmax_image_size))
+    {
+      if (f != NULL)
+       {
+         w = FRAME_PIXEL_WIDTH (f);
+         h = FRAME_PIXEL_HEIGHT (f);
+       }
+      else
+       w = h = 1024;  /* Arbitrary size for unknown frame. */
+      w = (int) (XFLOAT_DATA (Vmax_image_size) * w);
+      h = (int) (XFLOAT_DATA (Vmax_image_size) * h);
+    }
+  else
+    return 1;
+
+  return (width <= w && height <= h);
+}
 
 /* Prepare image IMG for display on frame F.  Must be called before
    drawing an image.  */
@@ -1086,13 +1213,21 @@ prepare_image_for_display (f, img)
    drawn in face FACE.  */
 
 int
-image_ascent (img, face)
+image_ascent (img, face, slice)
      struct image *img;
      struct face *face;
+     struct glyph_slice *slice;
 {
-  int height = img->height + img->vmargin;
+  int height;
   int ascent;
 
+  if (slice->height == img->height)
+    height = img->height + img->vmargin;
+  else if (slice->y == 0)
+    height = slice->height + img->vmargin;
+  else
+    height = slice->height;
+
   if (img->ascent == CENTERED_IMAGE_ASCENT)
     {
       if (face->font)
@@ -1179,7 +1314,7 @@ four_corners_best (ximg, width, height)
 /* Return the `background' field of IMG.  If IMG doesn't have one yet,
    it is guessed heuristically.  If non-zero, XIMG is an existing
    XImage object (or device context with the image selected on W32) to
-   use for the heuristic.  */ 
+   use for the heuristic.  */
 
 RGB_PIXEL_COLOR
 image_background (img, f, ximg)
@@ -1212,7 +1347,7 @@ image_background (img, f, ximg)
 
       if (free_ximg)
        Destroy_Image (ximg, prev);
-      
+
       img->background_valid = 1;
     }
 
@@ -1253,7 +1388,7 @@ image_background_transparent (img, f, mask)
            }
 
          img->background_transparent
-           = (four_corners_best (mask, img->width, img->height) == PIX_MASK_RETAIN (f));
+           = (four_corners_best (mask, img->width, img->height) == PIX_MASK_RETAIN);
 
          if (free_mask)
            Destroy_Image (mask, prev);
@@ -1609,6 +1744,12 @@ lookup_image (f, spec)
     if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
       break;
 
+  if (img && img->load_failed_p)
+    {
+      free_image (f, img);
+      img = NULL;
+    }
+
   /* If not found, create a new image and cache it.  */
   if (img == NULL)
     {
@@ -1767,7 +1908,7 @@ forall_images_in_image_cache (f, fn)
 #ifdef HAVE_NTGUI
 
 /* Macro for defining functions that will be loaded from image DLLs.  */
-#define DEF_IMGLIB_FN(func) FARPROC fn_##func
+#define DEF_IMGLIB_FN(func) int (FAR CDECL *fn_##func)()
 
 /* Macro for loading those image functions from the library.  */
 #define LOAD_IMGLIB_FN(lib,func) {                                     \
@@ -1775,6 +1916,33 @@ forall_images_in_image_cache (f, fn)
     if (!fn_##func) return 0;                                          \
   }
 
+/* Load a DLL implementing an image type.
+   The `image-library-alist' variable associates a symbol,
+   identifying  an image type, to a list of possible filenames.
+   The function returns NULL if no library could be loaded for
+   the given image type, or if the library was previously loaded;
+   else the handle of the DLL.  */
+static HMODULE
+w32_delayed_load (Lisp_Object libraries, Lisp_Object type)
+{
+  HMODULE library = NULL;
+
+  if (CONSP (libraries) && NILP (Fassq (type, Vimage_type_cache)))
+    {
+      Lisp_Object dlls = Fassq (type, libraries);
+
+      if (CONSP (dlls))
+        for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
+          {
+            CHECK_STRING_CAR (dlls);
+            if (library = LoadLibrary (SDATA (XCAR (dlls))))
+              break;
+          }
+    }
+
+  return library;
+}
+
 #endif /* HAVE_NTGUI */
 
 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
@@ -1898,7 +2066,8 @@ x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
      and store its handle in *pixmap.  */
   *pixmap = CreateDIBSection (hdc, &((*ximg)->info),
                              (depth < 16) ? DIB_PAL_COLORS : DIB_RGB_COLORS,
-                             &((*ximg)->data), NULL, 0);
+                             /* casting avoids a GCC warning */
+                             (void **)&((*ximg)->data), NULL, 0);
 
   /* Realize display palette and garbage all frames. */
   release_frame_dc (f, hdc);
@@ -1928,7 +2097,6 @@ x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
   *pixmap = XCreatePixmap (display, window, width, height, depth);
   if (*pixmap == NO_PIXMAP)
     {
-      x_destroy_x_image (*ximg);
       *ximg = NULL;
       image_error ("Unable to create X pixmap", Qnil, Qnil);
       return 0;
@@ -2005,7 +2173,6 @@ x_put_x_image (f, ximg, pixmap, width, height)
                              File Handling
  ***********************************************************************/
 
-static Lisp_Object x_find_image_file P_ ((Lisp_Object));
 static unsigned char *slurp_file P_ ((char *, int *));
 
 
@@ -2013,7 +2180,7 @@ static unsigned char *slurp_file P_ ((char *, int *));
    x-bitmap-file-path.  Value is the full name of the file found, or
    nil if not found.  */
 
-static Lisp_Object
+Lisp_Object
 x_find_image_file (file)
      Lisp_Object file;
 {
@@ -2053,7 +2220,7 @@ slurp_file (file, size)
 
   if (stat (file, &st) == 0
       && (fp = fopen (file, "rb")) != NULL
-      && (buf = (char *) xmalloc (st.st_size),
+      && (buf = (unsigned char *) xmalloc (st.st_size),
          fread (buf, 1, st.st_size, fp) == st.st_size))
     {
       *size = st.st_size;
@@ -2092,10 +2259,8 @@ find_image_fsspec (specified_file, file, fss)
      Lisp_Object specified_file, *file;
      FSSpec *fss;
 {
-#if TARGET_API_MAC_CARBON
+#if MAC_OSX
   FSRef fsr;
-#else
-  Str255 mac_pathname;
 #endif
   OSErr err;
 
@@ -2104,15 +2269,12 @@ find_image_fsspec (specified_file, file, fss)
     return fnfErr;             /* file or directory not found;
                                   incomplete pathname */
   /* Try to open the image file.  */
-#if TARGET_API_MAC_CARBON
+#if MAC_OSX
   err = FSPathMakeRef (SDATA (*file), &fsr, NULL);
   if (err == noErr)
     err = FSGetCatalogInfo (&fsr, kFSCatInfoNone, NULL, NULL, fss, NULL);
 #else
-  if (posix_to_mac_pathname (SDATA (*file), mac_pathname, MAXPATHLEN+1) == 0)
-    return fnfErr;
-  c2pstr (mac_pathname);
-  err = FSMakeFSSpec (0, 0, mac_pathname, fss);
+  err = posix_pathname_to_fsspec (SDATA (*file), fss);
 #endif
   return err;
 }
@@ -2129,6 +2291,7 @@ image_load_qt_1 (f, img, type, fss, dh)
   GraphicsImportComponent gi;
   Rect rect;
   int width, height;
+  ImageDescriptionHandle desc_handle;
   short draw_all_pixels;
   Lisp_Object specified_bg;
   XColor color;
@@ -2164,14 +2327,22 @@ image_load_qt_1 (f, img, type, fss, dh)
          goto error;
        }
     }
-  err = GraphicsImportGetNaturalBounds (gi, &rect);
-  if (err != noErr)
+  err = GraphicsImportGetImageDescription (gi, &desc_handle);
+  if (err != noErr || desc_handle == NULL)
     {
       image_error ("Error reading `%s'", img->spec, Qnil);
       goto error;
     }
-  width = img->width = rect.right - rect.left;
-  height = img->height = rect.bottom - rect.top;
+  width = img->width = (*desc_handle)->width;
+  height = img->height = (*desc_handle)->height;
+  DisposeHandle ((Handle)desc_handle);
+
+  if (!check_image_size (f, width, height))
+    {
+      image_error ("Invalid image size", Qnil, Qnil);
+      goto error;
+    }
+
   err = GraphicsImportDoesDrawAllPixels (gi, &draw_all_pixels);
 #if 0
   /* Don't check the error code here.  It may have an undocumented
@@ -2199,6 +2370,10 @@ image_load_qt_1 (f, img, type, fss, dh)
     goto error;
   if (draw_all_pixels != graphicsImporterDrawsAllPixels)
     {
+      CGrafPtr old_port;
+      GDHandle old_gdh;
+
+      GetGWorld (&old_port, &old_gdh);
       SetGWorld (ximg, NULL);
       bg_color.red = color.red;
       bg_color.green = color.green;
@@ -2210,6 +2385,7 @@ image_load_qt_1 (f, img, type, fss, dh)
 #else
       EraseRect (&(ximg->portRect));
 #endif
+      SetGWorld (old_port, old_gdh);
     }
   GraphicsImportSetGWorld (gi, ximg, NULL);
   GraphicsImportDraw (gi);
@@ -2343,8 +2519,7 @@ image_load_quartz2d (f, img, png_p)
          UNGCPRO;
          return 0;
        }
-      path = CFStringCreateWithCString (NULL, SDATA (file),
-                                       kCFStringEncodingUTF8);
+      path = cfstring_create_with_string (file);
       url = CFURLCreateWithFileSystemPath (NULL, path,
                                           kCFURLPOSIXPathStyle, 0);
       CFRelease (path);
@@ -2369,6 +2544,16 @@ image_load_quartz2d (f, img, png_p)
       image_error ("Error reading image `%s'", img->spec, Qnil);
       return 0;
     }
+  width = img->width = CGImageGetWidth (image);
+  height = img->height = CGImageGetHeight (image);
+
+  if (!check_image_size (f, width, height))
+    {
+      CGImageRelease (image);
+      UNGCPRO;
+      image_error ("Invalid image size", Qnil, Qnil);
+      return 0;
+    }
 
   if (png_p)
     {
@@ -2382,8 +2567,7 @@ image_load_quartz2d (f, img, png_p)
          color.blue = BLUE16_FROM_ULONG (color.pixel);
        }
     }
-  width = img->width = CGImageGetWidth (image);
-  height = img->height = CGImageGetHeight (image);
+
   if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
     {
       CGImageRelease (image);
@@ -2427,7 +2611,8 @@ static int xbm_load P_ ((struct frame *f, struct image *img));
 static int xbm_load_image P_ ((struct frame *f, struct image *img,
                               unsigned char *, unsigned char *));
 static int xbm_image_p P_ ((Lisp_Object object));
-static int xbm_read_bitmap_data P_ ((unsigned char *, unsigned char *,
+static int xbm_read_bitmap_data P_ ((struct frame *f,
+                                    unsigned char *, unsigned char *,
                                     int *, int *, unsigned char **));
 static int xbm_file_p P_ ((Lisp_Object));
 
@@ -2815,7 +3000,8 @@ Create_Pixmap_From_Bitmap_Data(f, img, data, fg, bg, non_default_colors)
    CONTENTS looks like an in-memory XBM file.  */
 
 static int
-xbm_read_bitmap_data (contents, end, width, height, data)
+xbm_read_bitmap_data (f, contents, end, width, height, data)
+     struct frame *f;
      unsigned char *contents, *end;
      int *width, *height;
      unsigned char **data;
@@ -2868,7 +3054,7 @@ xbm_read_bitmap_data (contents, end, width, height, data)
       expect (XBM_TK_NUMBER);
     }
 
-  if (*width < 0 || *height < 0)
+  if (!check_image_size (f, *width, *height))
     goto failure;
   else if (data == NULL)
     goto success;
@@ -2905,7 +3091,7 @@ xbm_read_bitmap_data (contents, end, width, height, data)
 
   bytes_per_line = (*width + 7) / 8 + padding_p;
   nbytes = bytes_per_line * *height;
-  p = *data = (char *) xmalloc (nbytes);
+  p = *data = (unsigned char *) xmalloc (nbytes);
 
   if (v10)
     {
@@ -2972,7 +3158,7 @@ xbm_load_image (f, img, contents, end)
   unsigned char *data;
   int success_p = 0;
 
-  rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
+  rc = xbm_read_bitmap_data (f, contents, end, &img->width, &img->height, &data);
   if (rc)
     {
       unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
@@ -2998,7 +3184,7 @@ xbm_load_image (f, img, contents, end)
          non_default_colors = 1;
        }
 
-      Create_Pixmap_From_Bitmap_Data (f, img, data, 
+      Create_Pixmap_From_Bitmap_Data (f, img, data,
                                      foreground, background,
                                      non_default_colors);
       xfree (data);
@@ -3026,7 +3212,7 @@ xbm_file_p (data)
 {
   int w, h;
   return (STRINGP (data)
-         && xbm_read_bitmap_data (SDATA (data),
+         && xbm_read_bitmap_data (NULL, SDATA (data),
                                   (SDATA (data)
                                    + SBYTES (data)),
                                   &w, &h, NULL));
@@ -3172,28 +3358,36 @@ xbm_load (f, img)
                              XPM images
  ***********************************************************************/
 
-#ifdef HAVE_XPM
+#if defined (HAVE_XPM) || defined (MAC_OS)
 
 static int xpm_image_p P_ ((Lisp_Object object));
 static int xpm_load P_ ((struct frame *f, struct image *img));
 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
 
+#endif /* HAVE_XPM || MAC_OS */
+
+#ifdef HAVE_XPM
 #ifdef HAVE_NTGUI
 /* Indicate to xpm.h that we don't have Xlib.  */
 #define FOR_MSW
 /* simx.h in xpm defines XColor and XImage differently than Emacs.  */
+/* It also defines Display the same way as Emacs, but gcc 3.3 still barfs.  */
 #define XColor xpm_XColor
 #define XImage xpm_XImage
+#define Display xpm_Display
 #define PIXEL_ALREADY_TYPEDEFED
 #include "X11/xpm.h"
 #undef FOR_MSW
 #undef XColor
 #undef XImage
+#undef Display
 #undef PIXEL_ALREADY_TYPEDEFED
 #else
 #include "X11/xpm.h"
 #endif /* HAVE_NTGUI */
+#endif /* HAVE_XPM */
 
+#if defined (HAVE_XPM) || defined (MAC_OS)
 /* The symbol `xpm' identifying XPM-format images.  */
 
 Lisp_Object Qxpm;
@@ -3463,13 +3657,12 @@ DEF_IMGLIB_FN (XpmCreateImageFromBuffer);
 DEF_IMGLIB_FN (XpmReadFileToImage);
 DEF_IMGLIB_FN (XImageFree);
 
-
 static int
-init_xpm_functions (void)
+init_xpm_functions (Lisp_Object libraries)
 {
   HMODULE library;
 
-  if (!(library = LoadLibrary ("libXpm.dll")))
+  if (!(library = w32_delayed_load (libraries, Qxpm)))
     return 0;
 
   LOAD_IMGLIB_FN (library, XpmFreeAttributes);
@@ -3521,10 +3714,47 @@ xpm_image_p (object)
              || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
 }
 
+#endif /* HAVE_XPM || MAC_OS */
+
+#if defined (HAVE_XPM) && defined (HAVE_X_WINDOWS)
+int
+x_create_bitmap_from_xpm_data (f, bits)
+     struct frame *f;
+     char **bits;
+{
+  Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  int id, rc;
+  XpmAttributes attrs;
+  Pixmap bitmap, mask;
+
+  bzero (&attrs, sizeof attrs);
+
+  rc = XpmCreatePixmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                               bits, &bitmap, &mask, &attrs);
+  if (rc != XpmSuccess)
+    return -1;
+
+  id = x_allocate_bitmap_record (f);
+
+  dpyinfo->bitmaps[id - 1].pixmap = bitmap;
+  dpyinfo->bitmaps[id - 1].have_mask = 1;
+  dpyinfo->bitmaps[id - 1].mask = mask;
+  dpyinfo->bitmaps[id - 1].file = NULL;
+  dpyinfo->bitmaps[id - 1].height = attrs.height;
+  dpyinfo->bitmaps[id - 1].width = attrs.width;
+  dpyinfo->bitmaps[id - 1].depth = attrs.depth;
+  dpyinfo->bitmaps[id - 1].refcount = 1;
+
+  XpmFreeAttributes (&attrs);
+  return id;
+}
+#endif /* HAVE_X_WINDOWS */
 
 /* Load image IMG which will be displayed on frame F.  Value is
    non-zero if successful.  */
 
+#ifdef HAVE_XPM
+
 static int
 xpm_load (f, img)
      struct frame *f;
@@ -3756,116 +3986,588 @@ xpm_load (f, img)
 
 #endif /* HAVE_XPM */
 
-\f
-/***********************************************************************
-                            Color table
- ***********************************************************************/
+#ifdef MAC_OS
 
-#ifdef COLOR_TABLE_SUPPORT
+/* XPM support functions for Mac OS where libxpm is not available.
+   Only XPM version 3 (without any extensions) is supported.  */
+
+static int xpm_scan P_ ((unsigned char **, unsigned char *,
+                        unsigned char **, int *));
+static Lisp_Object xpm_make_color_table_v
+  P_ ((void (**) (Lisp_Object, unsigned char *, int, Lisp_Object),
+       Lisp_Object (**) (Lisp_Object, unsigned char *, int)));
+static void xpm_put_color_table_v P_ ((Lisp_Object, unsigned char *,
+                                      int, Lisp_Object));
+static Lisp_Object xpm_get_color_table_v P_ ((Lisp_Object,
+                                             unsigned char *, int));
+static Lisp_Object xpm_make_color_table_h
+  P_ ((void (**) (Lisp_Object, unsigned char *, int, Lisp_Object),
+       Lisp_Object (**) (Lisp_Object, unsigned char *, int)));
+static void xpm_put_color_table_h P_ ((Lisp_Object, unsigned char *,
+                                      int, Lisp_Object));
+static Lisp_Object xpm_get_color_table_h P_ ((Lisp_Object,
+                                             unsigned char *, int));
+static int xpm_str_to_color_key P_ ((char *));
+static int xpm_load_image P_ ((struct frame *, struct image *,
+                              unsigned char *, unsigned char *));
 
-/* An entry in the color table mapping an RGB color to a pixel color.  */
+/* Tokens returned from xpm_scan.  */
 
-struct ct_color
+enum xpm_token
 {
-  int r, g, b;
-  unsigned long pixel;
-
-  /* Next in color table collision list.  */
-  struct ct_color *next;
+  XPM_TK_IDENT = 256,
+  XPM_TK_STRING,
+  XPM_TK_EOF
 };
 
-/* The bucket vector size to use.  Must be prime.  */
-
-#define CT_SIZE 101
-
-/* Value is a hash of the RGB color given by R, G, and B.  */
+/* Scan an XPM data and return a character (< 256) or a token defined
+   by enum xpm_token above.  *S and END are the start (inclusive) and
+   the end (exclusive) addresses of the data, respectively.  Advance
+   *S while scanning.  If token is either XPM_TK_IDENT or
+   XPM_TK_STRING, *BEG and *LEN are set to the start address and the
+   length of the corresponding token, respectively.  */
 
-#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
+static int
+xpm_scan (s, end, beg, len)
+     unsigned char **s, *end, **beg;
+     int *len;
+{
+  int c;
 
-/* The color hash table.  */
+  while (*s < end)
+    {
+      /* Skip white-space.  */
+      while (*s < end && (c = *(*s)++, isspace (c)))
+       ;
 
-struct ct_color **ct_table;
+      /* gnus-pointer.xpm uses '-' in its identifier.
+        sb-dir-plus.xpm uses '+' in its identifier.  */
+      if (isalpha (c) || c == '_' || c == '-' || c == '+')
+       {
+         *beg = *s - 1;
+         while (*s < end &&
+                (c = **s, isalnum (c) || c == '_' || c == '-' || c == '+'))
+             ++*s;
+         *len = *s - *beg;
+         return XPM_TK_IDENT;
+       }
+      else if (c == '"')
+       {
+         *beg = *s;
+         while (*s < end && **s != '"')
+           ++*s;
+         *len = *s - *beg;
+         if (*s < end)
+           ++*s;
+         return XPM_TK_STRING;
+       }
+      else if (c == '/')
+       {
+         if (*s < end && **s == '*')
+           {
+             /* C-style comment.  */
+             ++*s;
+             do
+               {
+                 while (*s < end && *(*s)++ != '*')
+                   ;
+               }
+             while (*s < end && **s != '/');
+             if (*s < end)
+               ++*s;
+           }
+         else
+           return c;
+       }
+      else
+       return c;
+    }
 
-/* Number of entries in the color table.  */
+  return XPM_TK_EOF;
+}
 
-int ct_colors_allocated;
+/* Functions for color table lookup in XPM data.  A Key is a string
+   specifying the color of each pixel in XPM data.  A value is either
+   an integer that specifies a pixel color, Qt that specifies
+   transparency, or Qnil for the unspecified color.  If the length of
+   the key string is one, a vector is used as a table.  Otherwise, a
+   hash table is used.  */
 
-/* Initialize the color table.  */
+static Lisp_Object
+xpm_make_color_table_v (put_func, get_func)
+     void (**put_func) (Lisp_Object, unsigned char *, int, Lisp_Object);
+     Lisp_Object (**get_func) (Lisp_Object, unsigned char *, int);
+{
+  *put_func = xpm_put_color_table_v;
+  *get_func = xpm_get_color_table_v;
+  return Fmake_vector (make_number (256), Qnil);
+}
 
 static void
-init_color_table ()
+xpm_put_color_table_v (color_table, chars_start, chars_len, color)
+     Lisp_Object color_table;
+     unsigned char *chars_start;
+     int chars_len;
+     Lisp_Object color;
 {
-  int size = CT_SIZE * sizeof (*ct_table);
-  ct_table = (struct ct_color **) xmalloc (size);
-  bzero (ct_table, size);
-  ct_colors_allocated = 0;
+  XVECTOR (color_table)->contents[*chars_start] = color;
 }
 
+static Lisp_Object
+xpm_get_color_table_v (color_table, chars_start, chars_len)
+     Lisp_Object color_table;
+     unsigned char *chars_start;
+     int chars_len;
+{
+  return XVECTOR (color_table)->contents[*chars_start];
+}
 
-/* Free memory associated with the color table.  */
+static Lisp_Object
+xpm_make_color_table_h (put_func, get_func)
+     void (**put_func) (Lisp_Object, unsigned char *, int, Lisp_Object);
+     Lisp_Object (**get_func) (Lisp_Object, unsigned char *, int);
+{
+  *put_func = xpm_put_color_table_h;
+  *get_func = xpm_get_color_table_h;
+  return make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
+                         make_float (DEFAULT_REHASH_SIZE),
+                         make_float (DEFAULT_REHASH_THRESHOLD),
+                         Qnil, Qnil, Qnil);
+}
 
 static void
-free_color_table ()
+xpm_put_color_table_h (color_table, chars_start, chars_len, color)
+     Lisp_Object color_table;
+     unsigned char *chars_start;
+     int chars_len;
+     Lisp_Object color;
 {
-  int i;
-  struct ct_color *p, *next;
+  struct Lisp_Hash_Table *table = XHASH_TABLE (color_table);
+  unsigned hash_code;
+  Lisp_Object chars = make_unibyte_string (chars_start, chars_len);
 
-  for (i = 0; i < CT_SIZE; ++i)
-    for (p = ct_table[i]; p; p = next)
-      {
-       next = p->next;
-       xfree (p);
-      }
+  hash_lookup (table, chars, &hash_code);
+  hash_put (table, chars, color, hash_code);
+}
 
-  xfree (ct_table);
-  ct_table = NULL;
+static Lisp_Object
+xpm_get_color_table_h (color_table, chars_start, chars_len)
+     Lisp_Object color_table;
+     unsigned char *chars_start;
+     int chars_len;
+{
+  struct Lisp_Hash_Table *table = XHASH_TABLE (color_table);
+  int i = hash_lookup (table, make_unibyte_string (chars_start, chars_len),
+                      NULL);
+
+  return i >= 0 ? HASH_VALUE (table, i) : Qnil;
 }
 
+enum xpm_color_key {
+  XPM_COLOR_KEY_S,
+  XPM_COLOR_KEY_M,
+  XPM_COLOR_KEY_G4,
+  XPM_COLOR_KEY_G,
+  XPM_COLOR_KEY_C
+};
 
-/* Value is a pixel color for RGB color R, G, B on frame F.  If an
-   entry for that color already is in the color table, return the
-   pixel color of that entry.  Otherwise, allocate a new color for R,
-   G, B, and make an entry in the color table.  */
+static char xpm_color_key_strings[][4] = {"s", "m", "g4", "g", "c"};
 
-static unsigned long
-lookup_rgb_color (f, r, g, b)
-     struct frame *f;
-     int r, g, b;
+static int
+xpm_str_to_color_key (s)
+     char *s;
 {
-  unsigned hash = CT_HASH_RGB (r, g, b);
-  int i = hash % CT_SIZE;
-  struct ct_color *p;
-  Display_Info *dpyinfo;
+  int i;
 
-  /* Handle TrueColor visuals specially, which improves performance by
-     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);
-  if (dpyinfo->red_bits > 0)
-    {
-      unsigned long pr, pg, pb;
+  for (i = 0;
+       i < sizeof xpm_color_key_strings / sizeof xpm_color_key_strings[0];
+       i++)
+    if (strcmp (xpm_color_key_strings[i], s) == 0)
+      return i;
+  return -1;
+}
 
-      /* Apply gamma-correction like normal color allocation does.  */
-      if (f->gamma)
-       {
-         XColor color;
-         color.red = r, color.green = g, color.blue = b;
-         gamma_correct (f, &color);
-         r = color.red, g = color.green, b = color.blue;
-       }
+static int
+xpm_load_image (f, img, contents, end)
+     struct frame *f;
+     struct image *img;
+     unsigned char *contents, *end;
+{
+  unsigned char *s = contents, *beg, *str;
+  unsigned char buffer[BUFSIZ];
+  int width, height, x, y;
+  int num_colors, chars_per_pixel;
+  int len, LA1;
+  void (*put_color_table) (Lisp_Object, unsigned char *, int, Lisp_Object);
+  Lisp_Object (*get_color_table) (Lisp_Object, unsigned char *, int);
+  Lisp_Object frame, color_symbols, color_table;
+  int best_key, have_mask = 0;
+  XImagePtr ximg = NULL, mask_img = NULL;
 
-      /* Scale down RGB values to the visual's bits per RGB, and shift
-        them to the right position in the pixel color.  Note that the
-        original RGB values are 16-bit values, as usual in X.  */
-      pr = (r >> (16 - dpyinfo->red_bits))   << dpyinfo->red_offset;
-      pg = (g >> (16 - dpyinfo->green_bits)) << dpyinfo->green_offset;
-      pb = (b >> (16 - dpyinfo->blue_bits))  << dpyinfo->blue_offset;
+#define match() \
+     LA1 = xpm_scan (&s, end, &beg, &len)
+
+#define expect(TOKEN)          \
+     if (LA1 != (TOKEN))       \
+       goto failure;           \
+     else                      \
+       match ()
+
+#define expect_ident(IDENT)                                    \
+     if (LA1 == XPM_TK_IDENT \
+         && strlen ((IDENT)) == len && memcmp ((IDENT), beg, len) == 0)        \
+       match ();                                               \
+     else                                                      \
+       goto failure
+
+  if (!(end - s >= 9 && memcmp (s, "/* XPM */", 9) == 0))
+    goto failure;
+  s += 9;
+  match();
+  expect_ident ("static");
+  expect_ident ("char");
+  expect ('*');
+  expect (XPM_TK_IDENT);
+  expect ('[');
+  expect (']');
+  expect ('=');
+  expect ('{');
+  expect (XPM_TK_STRING);
+  if (len >= BUFSIZ)
+    goto failure;
+  memcpy (buffer, beg, len);
+  buffer[len] = '\0';
+  if (sscanf (buffer, "%d %d %d %d", &width, &height,
+             &num_colors, &chars_per_pixel) != 4
+      || width <= 0 || height <= 0
+      || num_colors <= 0 || chars_per_pixel <= 0)
+    goto failure;
+
+  if (!check_image_size (f, width, height))
+    {
+      image_error ("Invalid image size", Qnil, Qnil);
+      goto failure;
+    }
+
+  expect (',');
+
+  XSETFRAME (frame, f);
+  if (!NILP (Fxw_display_color_p (frame)))
+    best_key = XPM_COLOR_KEY_C;
+  else if (!NILP (Fx_display_grayscale_p (frame)))
+    best_key = (XFASTINT (Fx_display_planes (frame)) > 2
+               ? XPM_COLOR_KEY_G : XPM_COLOR_KEY_G4);
+  else
+    best_key = XPM_COLOR_KEY_M;
+
+  color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
+  if (chars_per_pixel == 1)
+    color_table = xpm_make_color_table_v (&put_color_table,
+                                         &get_color_table);
+  else
+    color_table = xpm_make_color_table_h (&put_color_table,
+                                         &get_color_table);
+
+  while (num_colors-- > 0)
+    {
+      unsigned char *color, *max_color;
+      int key, next_key, max_key = 0;
+      Lisp_Object symbol_color = Qnil, color_val;
+      XColor cdef;
+
+      expect (XPM_TK_STRING);
+      if (len <= chars_per_pixel || len >= BUFSIZ + chars_per_pixel)
+       goto failure;
+      memcpy (buffer, beg + chars_per_pixel, len - chars_per_pixel);
+      buffer[len - chars_per_pixel] = '\0';
+
+      str = strtok (buffer, " \t");
+      if (str == NULL)
+       goto failure;
+      key = xpm_str_to_color_key (str);
+      if (key < 0)
+       goto failure;
+      do
+       {
+         color = strtok (NULL, " \t");
+         if (color == NULL)
+           goto failure;
+
+         while (str = strtok (NULL, " \t"))
+           {
+             next_key = xpm_str_to_color_key (str);
+             if (next_key >= 0)
+               break;
+             color[strlen (color)] = ' ';
+           }
+
+         if (key == XPM_COLOR_KEY_S)
+           {
+             if (NILP (symbol_color))
+               symbol_color = build_string (color);
+           }
+         else if (max_key < key && key <= best_key)
+           {
+             max_key = key;
+             max_color = color;
+           }
+         key = next_key;
+       }
+      while (str);
+
+      color_val = Qnil;
+      if (!NILP (color_symbols) && !NILP (symbol_color))
+       {
+         Lisp_Object specified_color = Fassoc (symbol_color, color_symbols);
+
+         if (CONSP (specified_color) && STRINGP (XCDR (specified_color)))
+           if (xstricmp (SDATA (XCDR (specified_color)), "None") == 0)
+             color_val = Qt;
+           else if (x_defined_color (f, SDATA (XCDR (specified_color)),
+                                     &cdef, 0))
+             color_val = make_number (cdef.pixel);
+       }
+      if (NILP (color_val) && max_key > 0)
+       if (xstricmp (max_color, "None") == 0)
+         color_val = Qt;
+       else if (x_defined_color (f, max_color, &cdef, 0))
+         color_val = make_number (cdef.pixel);
+      if (!NILP (color_val))
+       (*put_color_table) (color_table, beg, chars_per_pixel, color_val);
+
+      expect (',');
+    }
+
+  if (!x_create_x_image_and_pixmap (f, width, height, 0,
+                                   &ximg, &img->pixmap)
+      || !x_create_x_image_and_pixmap (f, width, height, 1,
+                                      &mask_img, &img->mask))
+    {
+      image_error ("Out of memory (%s)", img->spec, Qnil);
+      goto error;
+    }
+
+  for (y = 0; y < height; y++)
+    {
+      expect (XPM_TK_STRING);
+      str = beg;
+      if (len < width * chars_per_pixel)
+       goto failure;
+      for (x = 0; x < width; x++, str += chars_per_pixel)
+       {
+         Lisp_Object color_val =
+           (*get_color_table) (color_table, str, chars_per_pixel);
+
+         XPutPixel (ximg, x, y,
+                    (INTEGERP (color_val) ? XINT (color_val)
+                     : FRAME_FOREGROUND_PIXEL (f)));
+         XPutPixel (mask_img, x, y,
+                    (!EQ (color_val, Qt) ? PIX_MASK_DRAW
+                     : (have_mask = 1, PIX_MASK_RETAIN)));
+       }
+      if (y + 1 < height)
+       expect (',');
+    }
+
+  img->width = width;
+  img->height = height;
+
+  x_put_x_image (f, ximg, img->pixmap, width, height);
+  x_destroy_x_image (ximg);
+  if (have_mask)
+    {
+      /* Fill in the background_transparent field while we have the
+        mask handy.  */
+      image_background_transparent (img, f, mask_img);
+
+      x_put_x_image (f, mask_img, img->mask, width, height);
+      x_destroy_x_image (mask_img);
+    }
+  else
+    {
+      x_destroy_x_image (mask_img);
+      Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
+      img->mask = NO_PIXMAP;
+    }
+
+  return 1;
+
+ failure:
+  image_error ("Invalid XPM file (%s)", img->spec, Qnil);
+ error:
+  x_destroy_x_image (ximg);
+  x_destroy_x_image (mask_img);
+  x_clear_image (f, img);
+  return 0;
+
+#undef match
+#undef expect
+#undef expect_ident
+}
+
+static int
+xpm_load (f, img)
+     struct frame *f;
+     struct image *img;
+{
+  int success_p = 0;
+  Lisp_Object file_name;
+
+  /* If IMG->spec specifies a file name, create a non-file spec from it.  */
+  file_name = image_spec_value (img->spec, QCfile, NULL);
+  if (STRINGP (file_name))
+    {
+      Lisp_Object file;
+      unsigned char *contents;
+      int size;
+      struct gcpro gcpro1;
+
+      file = x_find_image_file (file_name);
+      GCPRO1 (file);
+      if (!STRINGP (file))
+       {
+         image_error ("Cannot find image file `%s'", file_name, Qnil);
+         UNGCPRO;
+         return 0;
+       }
+
+      contents = slurp_file (SDATA (file), &size);
+      if (contents == NULL)
+       {
+         image_error ("Error loading XPM image `%s'", img->spec, Qnil);
+         UNGCPRO;
+         return 0;
+       }
+
+      success_p = xpm_load_image (f, img, contents, contents + size);
+      xfree (contents);
+      UNGCPRO;
+    }
+  else
+    {
+      Lisp_Object data;
+
+      data = image_spec_value (img->spec, QCdata, NULL);
+      success_p = xpm_load_image (f, img, SDATA (data),
+                                 SDATA (data) + SBYTES (data));
+    }
+
+  return success_p;
+}
+
+#endif /* MAC_OS */
+
+
+\f
+/***********************************************************************
+                            Color table
+ ***********************************************************************/
+
+#ifdef COLOR_TABLE_SUPPORT
+
+/* An entry in the color table mapping an RGB color to a pixel color.  */
+
+struct ct_color
+{
+  int r, g, b;
+  unsigned long pixel;
+
+  /* Next in color table collision list.  */
+  struct ct_color *next;
+};
+
+/* The bucket vector size to use.  Must be prime.  */
+
+#define CT_SIZE 101
+
+/* Value is a hash of the RGB color given by R, G, and B.  */
+
+#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
+
+/* The color hash table.  */
+
+struct ct_color **ct_table;
+
+/* Number of entries in the color table.  */
+
+int ct_colors_allocated;
+
+/* Initialize the color table.  */
+
+static void
+init_color_table ()
+{
+  int size = CT_SIZE * sizeof (*ct_table);
+  ct_table = (struct ct_color **) xmalloc (size);
+  bzero (ct_table, size);
+  ct_colors_allocated = 0;
+}
+
+
+/* Free memory associated with the color table.  */
+
+static void
+free_color_table ()
+{
+  int i;
+  struct ct_color *p, *next;
+
+  for (i = 0; i < CT_SIZE; ++i)
+    for (p = ct_table[i]; p; p = next)
+      {
+       next = p->next;
+       xfree (p);
+      }
+
+  xfree (ct_table);
+  ct_table = NULL;
+}
+
+
+/* Value is a pixel color for RGB color R, G, B on frame F.  If an
+   entry for that color already is in the color table, return the
+   pixel color of that entry.  Otherwise, allocate a new color for R,
+   G, B, and make an entry in the color table.  */
+
+static unsigned long
+lookup_rgb_color (f, r, g, b)
+     struct frame *f;
+     int r, g, b;
+{
+  unsigned hash = CT_HASH_RGB (r, g, b);
+  int i = hash % CT_SIZE;
+  struct ct_color *p;
+  Display_Info *dpyinfo;
+
+  /* Handle TrueColor visuals specially, which improves performance by
+     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);
+  if (dpyinfo->red_bits > 0)
+    {
+      unsigned long pr, pg, pb;
+
+      /* Apply gamma-correction like normal color allocation does.  */
+      if (f->gamma)
+       {
+         XColor color;
+         color.red = r, color.green = g, color.blue = b;
+         gamma_correct (f, &color);
+         r = color.red, g = color.green, b = color.blue;
+       }
+
+      /* Scale down RGB values to the visual's bits per RGB, and shift
+        them to the right position in the pixel color.  Note that the
+        original RGB values are 16-bit values, as usual in X.  */
+      pr = (r >> (16 - dpyinfo->red_bits))   << dpyinfo->red_offset;
+      pg = (g >> (16 - dpyinfo->green_bits)) << dpyinfo->green_offset;
+      pb = (b >> (16 - dpyinfo->blue_bits))  << dpyinfo->blue_offset;
+
+      /* Assemble the pixel color.  */
+      return pr | pg | pb;
+    }
 
-      /* Assemble the pixel color.  */
-      return pr | pg | pb;
-    }
-  
   for (p = ct_table[i]; p; p = p->next)
     if (p->r == r && p->g == g && p->b == b)
       break;
@@ -4424,7 +5126,7 @@ x_disable_image (f, img)
 
 #ifdef MAC_OS
 #define XCreateGC_pixmap(dpy, pixmap) XCreateGC (dpy, NULL, 0, NULL)
-#define MaskForeground(f)  PIX_MASK_DRAW (f)
+#define MaskForeground(f)  PIX_MASK_DRAW
 #else
 #define XCreateGC_pixmap(dpy, pixmap) XCreateGC (dpy, pixmap, 0, NULL)
 #define MaskForeground(f)  WHITE_PIX_DEFAULT (f)
@@ -4572,7 +5274,7 @@ x_build_heuristic_mask (f, img, how)
   for (y = 0; y < img->height; ++y)
     for (x = 0; x < img->width; ++x)
       XPutPixel (mask_img, x, y, (XGetPixel (ximg, x, y) != bg
-                                 ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f)));
+                                 ? PIX_MASK_DRAW : PIX_MASK_RETAIN));
 
   /* Fill in the background_transparent field while we have the mask handy. */
   image_background_transparent (img, f, mask_img);
@@ -4866,8 +5568,7 @@ pbm_load (f, img)
        max_color_idx = 255;
     }
 
-  if (width < 0
-      || height < 0
+  if (!check_image_size (f, width, height)
       || (type != PBM_MONO && max_color_idx < 0))
     goto error;
 
@@ -4969,14 +5670,15 @@ pbm_load (f, img)
   /* Maybe fill in the background field while we have ximg handy.  */
 
   if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
-    IMAGE_BACKGROUND (img, f, ximg);
+    /* Casting avoids a GCC warning.  */
+    IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
 
   /* Put the image into a pixmap.  */
   x_put_x_image (f, ximg, img->pixmap, width, height);
   x_destroy_x_image (ximg);
 
   /* X and W32 versions did it here, MAC version above.  ++kfs
-     img->width = width;   
+     img->width = width;
      img->height = height; */
 
   UNGCPRO;
@@ -5081,7 +5783,6 @@ DEF_IMGLIB_FN (png_create_read_struct);
 DEF_IMGLIB_FN (png_create_info_struct);
 DEF_IMGLIB_FN (png_destroy_read_struct);
 DEF_IMGLIB_FN (png_set_read_fn);
-DEF_IMGLIB_FN (png_init_io);
 DEF_IMGLIB_FN (png_set_sig_bytes);
 DEF_IMGLIB_FN (png_read_info);
 DEF_IMGLIB_FN (png_get_IHDR);
@@ -5099,21 +5800,12 @@ DEF_IMGLIB_FN (png_read_end);
 DEF_IMGLIB_FN (png_error);
 
 static int
-init_png_functions (void)
+init_png_functions (Lisp_Object libraries)
 {
   HMODULE library;
 
-  /* Ensure zlib is loaded.  Try debug version first.  */
-  if (!LoadLibrary ("zlibd.dll")
-      && !LoadLibrary ("zlib.dll"))
-    return 0;
-
   /* Try loading libpng under probable names.  */
-  if (!(library = LoadLibrary ("libpng13d.dll"))
-      && !(library = LoadLibrary ("libpng13.dll"))
-      && !(library = LoadLibrary ("libpng12d.dll"))
-      && !(library = LoadLibrary ("libpng12.dll"))
-      && !(library = LoadLibrary ("libpng.dll")))
+  if (!(library = w32_delayed_load (libraries, Qpng)))
     return 0;
 
   LOAD_IMGLIB_FN (library, png_get_io_ptr);
@@ -5122,7 +5814,6 @@ init_png_functions (void)
   LOAD_IMGLIB_FN (library, png_create_info_struct);
   LOAD_IMGLIB_FN (library, png_destroy_read_struct);
   LOAD_IMGLIB_FN (library, png_set_read_fn);
-  LOAD_IMGLIB_FN (library, png_init_io);
   LOAD_IMGLIB_FN (library, png_set_sig_bytes);
   LOAD_IMGLIB_FN (library, png_read_info);
   LOAD_IMGLIB_FN (library, png_get_IHDR);
@@ -5148,7 +5839,6 @@ init_png_functions (void)
 #define fn_png_create_info_struct      png_create_info_struct
 #define fn_png_destroy_read_struct     png_destroy_read_struct
 #define fn_png_set_read_fn             png_set_read_fn
-#define fn_png_init_io                 png_init_io
 #define fn_png_set_sig_bytes           png_set_sig_bytes
 #define fn_png_read_info               png_read_info
 #define fn_png_get_IHDR                        png_get_IHDR
@@ -5220,6 +5910,24 @@ png_read_from_memory (png_ptr, data, length)
   tbr->index = tbr->index + length;
 }
 
+
+/* Function set as reader function when reading PNG image from a file.
+   PNG_PTR is a pointer to the PNG control structure.  Copy LENGTH
+   bytes from the input to DATA.  */
+
+static void
+png_read_from_file (png_ptr, data, length)
+     png_structp png_ptr;
+     png_bytep data;
+     png_size_t length;
+{
+  FILE *fp = (FILE *) fn_png_get_io_ptr (png_ptr);
+
+  if (fread (data, 1, length, fp) < length)
+    fn_png_error (png_ptr, "Read error");
+}
+
+
 /* Load PNG image IMG for use on frame F.  Value is non-zero if
    successful.  */
 
@@ -5303,9 +6011,11 @@ png_load (f, img)
       tbr.bytes += sizeof (sig);
     }
 
-  /* Initialize read and info structs for PNG lib.  */
-  png_ptr = fn_png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
-                                      my_png_error, my_png_warning);
+  /* Initialize read and info structs for PNG lib.  Casting return
+     value avoids a GCC warning on W32.  */
+  png_ptr = (png_structp)fn_png_create_read_struct (PNG_LIBPNG_VER_STRING,
+                                                   NULL, my_png_error,
+                                                   my_png_warning);
   if (!png_ptr)
     {
       if (fp) fclose (fp);
@@ -5313,7 +6023,8 @@ png_load (f, img)
       return 0;
     }
 
-  info_ptr = fn_png_create_info_struct (png_ptr);
+  /* Casting return value avoids a GCC warning on W32.  */
+  info_ptr = (png_infop)fn_png_create_info_struct (png_ptr);
   if (!info_ptr)
     {
       fn_png_destroy_read_struct (&png_ptr, NULL, NULL);
@@ -5322,7 +6033,8 @@ png_load (f, img)
       return 0;
     }
 
-  end_info = fn_png_create_info_struct (png_ptr);
+  /* Casting return value avoids a GCC warning on W32.  */
+  end_info = (png_infop)fn_png_create_info_struct (png_ptr);
   if (!end_info)
     {
       fn_png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
@@ -5349,13 +6061,16 @@ png_load (f, img)
   if (!NILP (specified_data))
     fn_png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
   else
-    fn_png_init_io (png_ptr, fp);
+    fn_png_set_read_fn (png_ptr, (void *) fp, png_read_from_file);
 
   fn_png_set_sig_bytes (png_ptr, sizeof sig);
   fn_png_read_info (png_ptr, info_ptr);
   fn_png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
                   &interlace_type, NULL, NULL);
 
+  if (!check_image_size (f, width, height))
+    goto error;
+
   /* If image contains simply transparency data, we prefer to
      construct a clipping mask.  */
   if (fn_png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
@@ -5420,9 +6135,9 @@ png_load (f, img)
              png_color_16 user_bg;
 
              bzero (&user_bg, sizeof user_bg);
-             user_bg.red = color.red >> PNG_BG_COLOR_SHIFT;
-             user_bg.green = color.green >> PNG_BG_COLOR_SHIFT;
-             user_bg.blue = color.blue >> PNG_BG_COLOR_SHIFT;
+             user_bg.red = color.red >> 8;
+             user_bg.green = color.green >> 8;
+             user_bg.blue = color.blue >> 8;
 
              fn_png_set_background (png_ptr, &user_bg,
                                     PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
@@ -5446,9 +6161,9 @@ png_load (f, img)
          x_query_color (f, &color);
 
          bzero (&frame_background, sizeof frame_background);
-         frame_background.red = color.red;
-         frame_background.green = color.green;
-         frame_background.blue = color.blue;
+         frame_background.red = color.red >> 8;
+         frame_background.green = color.green >> 8;
+         frame_background.blue = color.blue >> 8;
 #endif /* HAVE_X_WINDOWS */
 
 #ifdef HAVE_NTGUI
@@ -5459,9 +6174,9 @@ png_load (f, img)
          x_query_color (f, &color);
 #endif
          bzero (&frame_background, sizeof frame_background);
-         frame_background.red = 256 * GetRValue (color);
-         frame_background.green = 256 * GetGValue (color);
-         frame_background.blue = 256 * GetBValue (color);
+         frame_background.red = GetRValue (color);
+         frame_background.green = GetGValue (color);
+         frame_background.blue = GetBValue (color);
 #endif /* HAVE_NTGUI */
 
 #ifdef MAC_OS
@@ -5563,7 +6278,7 @@ png_load (f, img)
          if (channels == 4)
            {
              if (mask_img)
-               XPutPixel (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f));
+               XPutPixel (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : PIX_MASK_RETAIN);
              ++p;
            }
        }
@@ -5595,8 +6310,9 @@ png_load (f, img)
   img->width = width;
   img->height = height;
 
-  /* Maybe fill in the background field while we have ximg handy. */
-  IMAGE_BACKGROUND (img, f, ximg);
+  /* Maybe fill in the background field while we have ximg handy.
+     Casting avoids a GCC warning.  */
+  IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
 
   /* Put the image into the pixmap, then free the X image and its buffer.  */
   x_put_x_image (f, ximg, img->pixmap, width, height);
@@ -5605,9 +6321,9 @@ png_load (f, img)
   /* Same for the mask.  */
   if (mask_img)
     {
-      /* Fill in the background_transparent field while we have the mask
-        handy. */
-      image_background_transparent (img, f, mask_img);
+      /* Fill in the background_transparent field while we have the
+        mask handy.  Casting avoids a GCC warning.  */
+      image_background_transparent (img, f, (XImagePtr_or_DC)mask_img);
 
       x_put_x_image (f, mask_img, img->mask, img->width, img->height);
       x_destroy_x_image (mask_img);
@@ -5724,6 +6440,12 @@ jpeg_image_p (object)
 #undef HAVE_STDLIB_H
 #endif /* HAVE_STLIB_H */
 
+#if defined (HAVE_NTGUI) && !defined (__WIN32__)
+/* In older releases of the jpeg library, jpeglib.h will define boolean
+   differently depending on __WIN32__, so make sure it is defined.  */
+#define __WIN32__ 1
+#endif
+
 #include <jpeglib.h>
 #include <jerror.h>
 #include <setjmp.h>
@@ -5741,25 +6463,21 @@ DEF_IMGLIB_FN (jpeg_finish_decompress);
 DEF_IMGLIB_FN (jpeg_destroy_decompress);
 DEF_IMGLIB_FN (jpeg_read_header);
 DEF_IMGLIB_FN (jpeg_read_scanlines);
-DEF_IMGLIB_FN (jpeg_stdio_src);
 DEF_IMGLIB_FN (jpeg_std_error);
 DEF_IMGLIB_FN (jpeg_resync_to_restart);
 
 static int
-init_jpeg_functions (void)
+init_jpeg_functions (Lisp_Object libraries)
 {
   HMODULE library;
 
-  if (!(library = LoadLibrary ("libjpeg.dll"))
-      && !(library = LoadLibrary ("jpeg-62.dll"))
-      && !(library = LoadLibrary ("jpeg.dll")))
+  if (!(library = w32_delayed_load (libraries, Qjpeg)))
     return 0;
 
   LOAD_IMGLIB_FN (library, jpeg_finish_decompress);
   LOAD_IMGLIB_FN (library, jpeg_read_scanlines);
   LOAD_IMGLIB_FN (library, jpeg_start_decompress);
   LOAD_IMGLIB_FN (library, jpeg_read_header);
-  LOAD_IMGLIB_FN (library, jpeg_stdio_src);
   LOAD_IMGLIB_FN (library, jpeg_CreateDecompress);
   LOAD_IMGLIB_FN (library, jpeg_destroy_decompress);
   LOAD_IMGLIB_FN (library, jpeg_std_error);
@@ -5785,7 +6503,6 @@ jpeg_resync_to_restart_wrapper(cinfo, desired)
 #define fn_jpeg_destroy_decompress     jpeg_destroy_decompress
 #define fn_jpeg_read_header            jpeg_read_header
 #define fn_jpeg_read_scanlines         jpeg_read_scanlines
-#define fn_jpeg_stdio_src              jpeg_stdio_src
 #define fn_jpeg_std_error              jpeg_std_error
 #define jpeg_resync_to_restart_wrapper jpeg_resync_to_restart
 
@@ -5812,7 +6529,17 @@ my_error_exit (cinfo)
    libjpeg.doc from the JPEG lib distribution.  */
 
 static void
-our_init_source (cinfo)
+our_common_init_source (cinfo)
+     j_decompress_ptr cinfo;
+{
+}
+
+
+/* Method to terminate data source.  Called by
+   jpeg_finish_decompress() after all data has been processed.  */
+
+static void
+our_common_term_source (cinfo)
      j_decompress_ptr cinfo;
 {
 }
@@ -5823,7 +6550,7 @@ our_init_source (cinfo)
    so this only adds a fake end of input marker at the end.  */
 
 static boolean
-our_fill_input_buffer (cinfo)
+our_memory_fill_input_buffer (cinfo)
      j_decompress_ptr cinfo;
 {
   /* Insert a fake EOI marker.  */
@@ -5835,7 +6562,7 @@ our_fill_input_buffer (cinfo)
 
   src->next_input_byte = buffer;
   src->bytes_in_buffer = 2;
-  return TRUE;
+  return 1;
 }
 
 
@@ -5843,7 +6570,7 @@ our_fill_input_buffer (cinfo)
    is the JPEG data source manager.  */
 
 static void
-our_skip_input_data (cinfo, num_bytes)
+our_memory_skip_input_data (cinfo, num_bytes)
      j_decompress_ptr cinfo;
      long num_bytes;
 {
@@ -5860,16 +6587,6 @@ our_skip_input_data (cinfo, num_bytes)
 }
 
 
-/* Method to terminate data source.  Called by
-   jpeg_finish_decompress() after all data has been processed.  */
-
-static void
-our_term_source (cinfo)
-     j_decompress_ptr cinfo;
-{
-}
-
-
 /* Set up the JPEG lib for reading an image from DATA which contains
    LEN bytes.  CINFO is the decompression info structure created for
    reading the image.  */
@@ -5893,16 +6610,130 @@ jpeg_memory_src (cinfo, data, len)
     }
 
   src = (struct jpeg_source_mgr *) cinfo->src;
-  src->init_source = our_init_source;
-  src->fill_input_buffer = our_fill_input_buffer;
-  src->skip_input_data = our_skip_input_data;
+  src->init_source = our_common_init_source;
+  src->fill_input_buffer = our_memory_fill_input_buffer;
+  src->skip_input_data = our_memory_skip_input_data;
   src->resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use default method.  */
-  src->term_source = our_term_source;
+  src->term_source = our_common_term_source;
   src->bytes_in_buffer = len;
   src->next_input_byte = data;
 }
 
 
+struct jpeg_stdio_mgr
+{
+  struct jpeg_source_mgr mgr;
+  boolean finished;
+  FILE *file;
+  JOCTET *buffer;
+};
+
+
+/* Size of buffer to read JPEG from file.
+   Not too big, as we want to use alloc_small.  */
+#define JPEG_STDIO_BUFFER_SIZE 8192
+
+
+/* Fill input buffer method for JPEG data source manager.  Called
+   whenever more data is needed.  The data is read from a FILE *.  */
+
+static boolean
+our_stdio_fill_input_buffer (cinfo)
+     j_decompress_ptr cinfo;
+{
+  struct jpeg_stdio_mgr *src;
+
+  src = (struct jpeg_stdio_mgr *) cinfo->src;
+  if (!src->finished)
+    {
+      size_t bytes;
+
+      bytes = fread (src->buffer, 1, JPEG_STDIO_BUFFER_SIZE, src->file);
+      if (bytes > 0)
+        src->mgr.bytes_in_buffer = bytes;
+      else
+        {
+          WARNMS (cinfo, JWRN_JPEG_EOF);
+          src->finished = 1;
+          src->buffer[0] = (JOCTET) 0xFF;
+          src->buffer[1] = (JOCTET) JPEG_EOI;
+          src->mgr.bytes_in_buffer = 2;
+        }
+      src->mgr.next_input_byte = src->buffer;
+    }
+
+  return 1;
+}
+
+
+/* Method to skip over NUM_BYTES bytes in the image data.  CINFO->src
+   is the JPEG data source manager.  */
+
+static void
+our_stdio_skip_input_data (cinfo, num_bytes)
+     j_decompress_ptr cinfo;
+     long num_bytes;
+{
+  struct jpeg_stdio_mgr *src;
+  src = (struct jpeg_stdio_mgr *) cinfo->src;
+
+  while (num_bytes > 0 && !src->finished)
+    {
+      if (num_bytes <= src->mgr.bytes_in_buffer)
+        {
+          src->mgr.bytes_in_buffer -= num_bytes;
+          src->mgr.next_input_byte += num_bytes;
+          break;
+        }
+      else
+        {
+          num_bytes -= src->mgr.bytes_in_buffer;
+          src->mgr.bytes_in_buffer = 0;
+          src->mgr.next_input_byte = NULL;
+
+          our_stdio_fill_input_buffer (cinfo);
+        }
+    }
+}
+
+
+/* Set up the JPEG lib for reading an image from a FILE *.
+   CINFO is the decompression info structure created for
+   reading the image.  */
+
+static void
+jpeg_file_src (cinfo, fp)
+     j_decompress_ptr cinfo;
+     FILE *fp;
+{
+  struct jpeg_stdio_mgr *src;
+
+  if (cinfo->src != NULL)
+      src = (struct jpeg_stdio_mgr *) cinfo->src;
+  else
+    {
+      /* First time for this JPEG object?  */
+      cinfo->src = (struct jpeg_source_mgr *)
+        (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+                                    sizeof (struct jpeg_stdio_mgr));
+      src = (struct jpeg_stdio_mgr *) cinfo->src;
+      src->buffer = (JOCTET *)
+          (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+                                      JPEG_STDIO_BUFFER_SIZE);
+    }
+
+  src->file = fp;
+  src->finished = 0;
+  src->mgr.init_source = our_common_init_source;
+  src->mgr.fill_input_buffer = our_stdio_fill_input_buffer;
+  src->mgr.skip_input_data = our_stdio_skip_input_data;
+  src->mgr.resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use default method.  */
+  src->mgr.term_source = our_common_term_source;
+  src->mgr.bytes_in_buffer = 0;
+  src->mgr.next_input_byte = NULL;
+}
+
+
 /* Load image IMG for use on frame F.  Patterned after example.c
    from the JPEG lib.  */
 
@@ -5950,8 +6781,9 @@ jpeg_load (f, img)
     }
 
   /* 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);
+     error is detected.  This function will perform a longjmp.
+     Casting return value avoids a GCC warning on W32.  */
+  cinfo.err = (struct jpeg_error_mgr *)fn_jpeg_std_error (&mgr.pub);
   mgr.pub.error_exit = my_error_exit;
 
   if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
@@ -5985,20 +6817,26 @@ jpeg_load (f, img)
   fn_jpeg_CreateDecompress (&cinfo, JPEG_LIB_VERSION, sizeof (cinfo));
 
   if (NILP (specified_data))
-    fn_jpeg_stdio_src (&cinfo, (FILE *) fp);
+    jpeg_file_src (&cinfo, (FILE *) fp);
   else
     jpeg_memory_src (&cinfo, SDATA (specified_data),
                     SBYTES (specified_data));
 
-  fn_jpeg_read_header (&cinfo, TRUE);
+  fn_jpeg_read_header (&cinfo, 1);
 
   /* Customize decompression so that color quantization will be used.
         Start decompression.  */
-  cinfo.quantize_colors = TRUE;
+  cinfo.quantize_colors = 1;
   fn_jpeg_start_decompress (&cinfo);
   width = img->width = cinfo.output_width;
   height = img->height = cinfo.output_height;
 
+  if (!check_image_size (f, width, height))
+    {
+      image_error ("Invalid image size", Qnil, Qnil);
+      longjmp (mgr.setjmp_buffer, 2);
+    }
+
   /* Create X image and pixmap.  */
   if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
     longjmp (mgr.setjmp_buffer, 2);
@@ -6062,7 +6900,8 @@ jpeg_load (f, img)
 
   /* Maybe fill in the background field while we have ximg handy. */
   if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
-    IMAGE_BACKGROUND (img, f, ximg);
+    /* Casting avoids a GCC warning.  */
+    IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
 
   /* Put the image into the pixmap.  */
   x_put_x_image (f, ximg, img->pixmap, width, height);
@@ -6183,11 +7022,11 @@ DEF_IMGLIB_FN (TIFFReadRGBAImage);
 DEF_IMGLIB_FN (TIFFClose);
 
 static int
-init_tiff_functions (void)
+init_tiff_functions (Lisp_Object libraries)
 {
   HMODULE library;
 
-  if (!(library = LoadLibrary ("libtiff.dll")))
+  if (!(library = w32_delayed_load (libraries, Qtiff)))
     return 0;
 
   LOAD_IMGLIB_FN (library, TIFFSetErrorHandler);
@@ -6388,8 +7227,9 @@ tiff_load (f, img)
          return 0;
        }
 
-      /* Try to open the image file.  */
-      tiff = fn_TIFFOpen (SDATA (file), "r");
+      /* Try to open the image file.  Casting return value avoids a
+        GCC warning on W32.  */
+      tiff = (TIFF *)fn_TIFFOpen (SDATA (file), "r");
       if (tiff == NULL)
        {
          image_error ("Cannot open `%s'", file, Qnil);
@@ -6404,14 +7244,15 @@ tiff_load (f, img)
       memsrc.len = SBYTES (specified_data);
       memsrc.index = 0;
 
-      tiff = fn_TIFFClientOpen ("memory_source", "r", &memsrc,
-                                (TIFFReadWriteProc) tiff_read_from_memory,
-                                (TIFFReadWriteProc) tiff_write_from_memory,
-                                tiff_seek_in_memory,
-                                tiff_close_memory,
-                                tiff_size_of_memory,
-                                tiff_mmap_memory,
-                                tiff_unmap_memory);
+      /* Casting return value avoids a GCC warning on W32.  */
+      tiff = (TIFF *)fn_TIFFClientOpen ("memory_source", "r", &memsrc,
+                                       (TIFFReadWriteProc) tiff_read_from_memory,
+                                       (TIFFReadWriteProc) tiff_write_from_memory,
+                                       tiff_seek_in_memory,
+                                       tiff_close_memory,
+                                       tiff_size_of_memory,
+                                       tiff_mmap_memory,
+                                       tiff_unmap_memory);
 
       if (!tiff)
        {
@@ -6425,6 +7266,14 @@ tiff_load (f, img)
      of width x height 32-bit values.  */
   fn_TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
   fn_TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
+
+  if (!check_image_size (f, width, height))
+    {
+      image_error ("Invalid image size", Qnil, Qnil);
+      UNGCPRO;
+      return 0;
+    }
+
   buf = (uint32 *) xmalloc (width * height * sizeof *buf);
 
   rc = fn_TIFFReadRGBAImage (tiff, width, height, buf, 0);
@@ -6474,7 +7323,8 @@ tiff_load (f, img)
 
   /* Maybe fill in the background field while we have ximg handy. */
   if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
-    IMAGE_BACKGROUND (img, f, ximg);
+    /* Casting avoids a GCC warning on W32.  */
+    IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
 
   /* Put the image into the pixmap, then free the X image and its buffer.  */
   x_put_x_image (f, ximg, img->pixmap, width, height);
@@ -6582,6 +7432,11 @@ gif_image_p (object)
 #ifdef HAVE_GIF
 
 #if defined (HAVE_NTGUI) || defined (MAC_OS)
+/* winuser.h might define DrawText to DrawTextA or DrawTextW.
+   Undefine before redefining to avoid a preprocessor warning.  */
+#ifdef DrawText
+#undef DrawText
+#endif
 /* avoid conflict with QuickdrawText.h */
 #define DrawText gif_DrawText
 #include <gif_lib.h>
@@ -6603,11 +7458,11 @@ DEF_IMGLIB_FN (DGifOpen);
 DEF_IMGLIB_FN (DGifOpenFileName);
 
 static int
-init_gif_functions (void)
+init_gif_functions (Lisp_Object libraries)
 {
   HMODULE library;
 
-  if (!(library = LoadLibrary ("libungif.dll")))
+  if (!(library = w32_delayed_load (libraries, Qgif)))
     return 0;
 
   LOAD_IMGLIB_FN (library, DGifCloseFile);
@@ -6695,8 +7550,9 @@ gif_load (f, img)
          return 0;
        }
 
-      /* Open the GIF file.  */
-      gif = fn_DGifOpenFileName (SDATA (file));
+      /* Open the GIF file.  Casting return value avoids a GCC warning
+        on W32.  */
+      gif = (GifFileType *)fn_DGifOpenFileName (SDATA (file));
       if (gif == NULL)
        {
          image_error ("Cannot open `%s'", file, Qnil);
@@ -6712,7 +7568,8 @@ gif_load (f, img)
       memsrc.len = SBYTES (specified_data);
       memsrc.index = 0;
 
-      gif = fn_DGifOpen(&memsrc, gif_read_from_memory);
+      /* Casting return value avoids a GCC warning on W32.  */
+      gif = (GifFileType *)fn_DGifOpen(&memsrc, gif_read_from_memory);
       if (!gif)
        {
          image_error ("Cannot open memory source `%s'", img->spec, Qnil);
@@ -6721,6 +7578,15 @@ gif_load (f, img)
        }
     }
 
+  /* Before reading entire contents, check the declared image size. */
+  if (!check_image_size (f, gif->SWidth, gif->SHeight))
+    {
+      image_error ("Invalid image size", Qnil, Qnil);
+      fn_DGifCloseFile (gif);
+      UNGCPRO;
+      return 0;
+    }
+
   /* Read entire contents.  */
   rc = fn_DGifSlurp (gif);
   if (rc == GIF_ERROR)
@@ -6742,8 +7608,25 @@ gif_load (f, img)
       return 0;
     }
 
-  width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width);
-  height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height);
+  image_top = gif->SavedImages[ino].ImageDesc.Top;
+  image_left = gif->SavedImages[ino].ImageDesc.Left;
+  image_width = gif->SavedImages[ino].ImageDesc.Width;
+  image_height = gif->SavedImages[ino].ImageDesc.Height;
+
+  width = img->width = max (gif->SWidth,
+                           max (gif->Image.Left + gif->Image.Width,
+                                image_left + image_width));
+  height = img->height = max (gif->SHeight,
+                             max (gif->Image.Top + gif->Image.Height,
+                                  image_top + image_height));
+
+  if (!check_image_size (f, width, height))
+    {
+      image_error ("Invalid image size", Qnil, Qnil);
+      fn_DGifCloseFile (gif);
+      UNGCPRO;
+      return 0;
+    }
 
   /* Create the X image and pixmap.  */
   if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
@@ -6778,11 +7661,6 @@ gif_load (f, img)
      requires more than can be done here (see the gif89 spec,
      disposal methods).  Let's simply assume that the part
      not covered by a sub-image is in the frame's background color.  */
-  image_top = gif->SavedImages[ino].ImageDesc.Top;
-  image_left = gif->SavedImages[ino].ImageDesc.Left;
-  image_width = gif->SavedImages[ino].ImageDesc.Width;
-  image_height = gif->SavedImages[ino].ImageDesc.Height;
-
   for (y = 0; y < image_top; ++y)
     for (x = 0; x < width; ++x)
       XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
@@ -6846,7 +7724,8 @@ gif_load (f, img)
 
   /* Maybe fill in the background field while we have ximg handy. */
   if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
-    IMAGE_BACKGROUND (img, f, ximg);
+    /* Casting avoids a GCC warning.  */
+    IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
 
   /* Put the image into the pixmap, then free the X image and its buffer.  */
   x_put_x_image (f, ximg, img->pixmap, width, height);
@@ -6856,7 +7735,7 @@ gif_load (f, img)
   return 1;
 }
 
-#else
+#else  /* !HAVE_GIF */
 
 #ifdef MAC_OS
 static int
@@ -6883,6 +7762,8 @@ gif_load (f, img)
   TimeValue time;
   struct gcpro gcpro1;
   int ino;
+  CGrafPtr old_port;
+  GDHandle old_gdh;
 
   specified_file = image_spec_value (img->spec, QCfile, NULL);
   specified_data = image_spec_value (img->spec, QCdata, NULL);
@@ -7000,12 +7881,14 @@ gif_load (f, img)
   if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
     goto error;
 
+  GetGWorld (&old_port, &old_gdh);
   SetGWorld (ximg, NULL);
   bg_color.red = color.red;
   bg_color.green = color.green;
   bg_color.blue = color.blue;
   RGBBackColor (&bg_color);
-  SetMovieActive (movie, TRUE);
+  SetGWorld (old_port, old_gdh);
+  SetMovieActive (movie, 1);
   SetMovieGWorld (movie, ximg, NULL);
   SampleNumToMediaTime (media, ino + 1, &time, NULL);
   SetMovieTimeValue (movie, time);
@@ -7197,6 +8080,12 @@ gs_load (f, img)
   in_height = XFASTINT (pt_height) / 72.0;
   img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
 
+  if (!check_image_size (f, img->width, img->height))
+    {
+      image_error ("Invalid image size", Qnil, Qnil);
+      return 0;
+    }
+
   /* Create the pixmap.  */
   xassert (img->pixmap == NO_PIXMAP);
 
@@ -7376,9 +8265,126 @@ 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,
+       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 `image-library-alist', which see).  */)
+  (type, libraries)
+  Lisp_Object type, libraries;
+{
+  Lisp_Object tested;
+
+  /* Don't try to reload the library.  */
+  tested = Fassq (type, Vimage_type_cache);
+  if (CONSP (tested))
+    return XCDR (tested);
+
+#if defined (HAVE_XPM) || defined (MAC_OS)
+  if (EQ (type, Qxpm))
+    return CHECK_LIB_AVAILABLE (&xpm_type, init_xpm_functions, libraries);
+#endif
+
+#if defined (HAVE_JPEG) || defined (MAC_OS)
+  if (EQ (type, Qjpeg))
+    return CHECK_LIB_AVAILABLE (&jpeg_type, init_jpeg_functions, libraries);
+#endif
+
+#if defined (HAVE_TIFF) || defined (MAC_OS)
+  if (EQ (type, Qtiff))
+    return CHECK_LIB_AVAILABLE (&tiff_type, init_tiff_functions, libraries);
+#endif
+
+#if defined (HAVE_GIF) || defined (MAC_OS)
+  if (EQ (type, Qgif))
+    return CHECK_LIB_AVAILABLE (&gif_type, init_gif_functions, libraries);
+#endif
+
+#if defined (HAVE_PNG) || defined (MAC_OS)
+  if (EQ (type, Qpng))
+    return CHECK_LIB_AVAILABLE (&png_type, init_png_functions, libraries);
+#endif
+
+#ifdef HAVE_GHOSTSCRIPT
+  if (EQ (type, Qpostscript))
+    return CHECK_LIB_AVAILABLE (&gs_type, init_gs_functions, libraries);
+#endif
+
+  /* If the type is not recognized, avoid testing it ever again.  */
+  CACHE_IMAGE_TYPE (type, Qnil);
+  return Qnil;
+}
+
 void
 syms_of_image ()
 {
+  extern Lisp_Object Qrisky_local_variable;   /* Syms_of_xdisp has already run.  */
+
+  /* Initialize this only once, since that's what we do with Vimage_types
+     and they are supposed to be in sync.  Initializing here gives correct
+     operation on GNU/Linux of calling dump-emacs after loading some images.  */
+  image_types = NULL;
+
+  /* Must be defined now becase we're going to update it below, while
+     defining the supported image types.  */
+  DEFVAR_LISP ("image-types", &Vimage_types,
+    doc: /* List of potentially supported image types.
+Each element of the list is a symbol for a image type, like 'jpeg or 'png.
+To check whether it is really supported, use `image-type-available-p'.  */);
+  Vimage_types = Qnil;
+
+  DEFVAR_LISP ("image-library-alist", &Vimage_library_alist,
+    doc: /* Alist of image types vs external libraries needed to display them.
+
+Each element is a list (IMAGE-TYPE LIBRARY...), where the car is a symbol
+representing a supported image type, and the rest are strings giving
+alternate filenames for the corresponding external libraries.
+
+Emacs tries to load the libraries in the order they appear on the
+list; if none is loaded, the running session of Emacs won't
+support the image type.  Types 'pbm and 'xbm don't need to be
+listed; they're always supported.  */);
+  Vimage_library_alist = Qnil;
+  Fput (intern ("image-library-alist"), Qrisky_local_variable, Qt);
+
+  DEFVAR_LISP ("max-image-size", &Vmax_image_size,
+    doc: /* Maximum size of images.
+Emacs will not load an image into memory if its pixel width or
+pixel height exceeds this limit.
+
+If the value is an integer, it directly specifies the maximum
+image height and width, measured in pixels.  If it is a floating
+point number, it specifies the maximum image height and width
+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);
+
+  Vimage_type_cache = Qnil;
+  staticpro (&Vimage_type_cache);
+
+  Qpbm = intern ("pbm");
+  staticpro (&Qpbm);
+  ADD_IMAGE_TYPE(Qpbm);
+
+  Qxbm = intern ("xbm");
+  staticpro (&Qxbm);
+  ADD_IMAGE_TYPE(Qxbm);
+
+  define_image_type (&xbm_type, 1);
+  define_image_type (&pbm_type, 1);
+
   QCascent = intern (":ascent");
   staticpro (&QCascent);
   QCmargin = intern (":margin");
@@ -7408,12 +8414,11 @@ syms_of_image ()
   staticpro (&Qedge_detection);
   Qheuristic = intern ("heuristic");
   staticpro (&Qheuristic);
-  Qcenter = intern ("center");
-  staticpro (&Qcenter);
 
   Qpostscript = intern ("postscript");
   staticpro (&Qpostscript);
 #ifdef HAVE_GHOSTSCRIPT
+  ADD_IMAGE_TYPE(Qpostscript);
   QCloader = intern (":loader");
   staticpro (&QCloader);
   QCbounding_box = intern (":bounding-box");
@@ -7424,37 +8429,37 @@ syms_of_image ()
   staticpro (&QCpt_height);
 #endif /* HAVE_GHOSTSCRIPT */
 
-  Qpbm = intern ("pbm");
-  staticpro (&Qpbm);
-
-  Qxbm = intern ("xbm");
-  staticpro (&Qxbm);
-
-#ifdef HAVE_XPM
+#if defined (HAVE_XPM) || defined (MAC_OS)
   Qxpm = intern ("xpm");
   staticpro (&Qxpm);
+  ADD_IMAGE_TYPE(Qxpm);
 #endif
 
 #if defined (HAVE_JPEG) || defined (MAC_OS)
   Qjpeg = intern ("jpeg");
   staticpro (&Qjpeg);
+  ADD_IMAGE_TYPE(Qjpeg);
 #endif
 
 #if defined (HAVE_TIFF) || defined (MAC_OS)
   Qtiff = intern ("tiff");
   staticpro (&Qtiff);
+  ADD_IMAGE_TYPE(Qtiff);
 #endif
 
 #if defined (HAVE_GIF) || defined (MAC_OS)
   Qgif = intern ("gif");
   staticpro (&Qgif);
+  ADD_IMAGE_TYPE(Qgif);
 #endif
 
 #if defined (HAVE_PNG) || defined (MAC_OS)
   Qpng = intern ("png");
   staticpro (&Qpng);
+  ADD_IMAGE_TYPE(Qpng);
 #endif
 
+  defsubr (&Sinit_image_library);
   defsubr (&Sclear_image_cache);
   defsubr (&Simage_size);
   defsubr (&Simage_mask_p);
@@ -7482,56 +8487,13 @@ meaning don't clear the cache.  */);
   Vimage_cache_eviction_delay = make_number (30 * 60);
 }
 
-
-#ifdef HAVE_NTGUI
-/* Image types that rely on external libraries are loaded dynamically
-   if the library is available.  */
-#define IF_LIB_AVAILABLE(init_lib_fn)  if (init_lib_fn())
-#else
-#define IF_LIB_AVAILABLE(init_func)    /* Load unconditionally */
-#endif /* HAVE_NTGUI */
-
 void
 init_image ()
 {
-  image_types = NULL;
-  Vimage_types = Qnil;
-
-  define_image_type (&xbm_type);
-  define_image_type (&pbm_type);
-
-#ifdef HAVE_XPM
-  IF_LIB_AVAILABLE(init_xpm_functions)
-    define_image_type (&xpm_type);
-#endif
-
-#if defined (HAVE_JPEG) || defined (MAC_OS)
-  IF_LIB_AVAILABLE(init_jpeg_functions)
-    define_image_type (&jpeg_type);
-#endif
-
-#if defined (HAVE_TIFF) || defined (MAC_OS)
-  IF_LIB_AVAILABLE(init_tiff_functions)
-    define_image_type (&tiff_type);
-#endif
-
-#if defined (HAVE_GIF) || defined (MAC_OS)
-  IF_LIB_AVAILABLE(init_gif_functions)
-    define_image_type (&gif_type);
-#endif
-
-#if defined (HAVE_PNG) || defined (MAC_OS)
-  IF_LIB_AVAILABLE(init_png_functions)
-    define_image_type (&png_type);
-#endif
-
-#ifdef HAVE_GHOSTSCRIPT
-  define_image_type (&gs_type);
-#endif
-
 #ifdef MAC_OS
   /* Animated gifs use QuickTime Movie Toolbox.  So initialize it here. */
-  EnterMovies ();
+  if (!inhibit_window_system)
+    EnterMovies ();
 #ifdef MAC_OSX
   init_image_func_pointer ();
 #endif