*** empty log message ***
[bpt/emacs.git] / src / image.c
index dfe592f..f4616b6 100644 (file)
@@ -1,6 +1,6 @@
 /* Functions for image support on window system.
    Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-                 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+                 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -39,6 +39,8 @@ Boston, MA 02110-1301, USA.  */
 #include "blockinput.h"
 #include "systime.h"
 #include <epaths.h>
+#include "charset.h"
+#include "coding.h"
 
 
 #ifdef HAVE_X_WINDOWS
@@ -54,8 +56,8 @@ typedef struct x_bitmap_record Bitmap_Record;
 
 #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 */
 
 
@@ -71,8 +73,8 @@ typedef struct w32_bitmap_record Bitmap_Record;
 
 #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
@@ -112,6 +114,11 @@ typedef struct mac_bitmap_record Bitmap_Record;
 
 #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)
@@ -181,19 +188,46 @@ XPutPixel (ximage, x, y, pixel)
      int x, y;
      unsigned long pixel;
 {
-  CGrafPtr old_port;
-  GDHandle old_gdh;
-  RGBColor color;
+  PixMapHandle pixmap = GetGWorldPixMap (ximage);
+  short depth = GetPixDepth (pixmap);
 
-  GetGWorld (&old_port, &old_gdh);
-  SetGWorld (ximage, NULL);
+#if defined (WORDS_BIG_ENDIAN) || !USE_CG_DRAWING
+  if (depth == 32)
+    {
+      char *base_addr = GetPixBaseAddr (pixmap);
+      short row_bytes = GetPixRowBytes (pixmap);
 
-  color.red = RED16_FROM_ULONG (pixel);
-  color.green = GREEN16_FROM_ULONG (pixel);
-  color.blue = BLUE16_FROM_ULONG (pixel);
-  SetCPixel (x, y, &color);
+      ((unsigned long *) (base_addr + y * row_bytes))[x] = 0xff000000 | pixel;
+    }
+  else
+#endif
+  if (depth == 1)
+    {
+      char *base_addr = GetPixBaseAddr (pixmap);
+      short row_bytes = GetPixRowBytes (pixmap);
 
-  SetGWorld (old_port, old_gdh);
+      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);
+
+      SetCPixel (x, y, &color);
+
+      SetGWorld (old_port, old_gdh);
+    }
 }
 
 static unsigned long
@@ -201,17 +235,43 @@ XGetPixel (ximage, x, y)
      XImagePtr ximage;
      int x, y;
 {
-  CGrafPtr old_port;
-  GDHandle old_gdh;
-  RGBColor color;
+  PixMapHandle pixmap = GetGWorldPixMap (ximage);
+  short depth = GetPixDepth (pixmap);
 
-  GetGWorld (&old_port, &old_gdh);
-  SetGWorld (ximage, NULL);
+#if defined (WORDS_BIG_ENDIAN) || !USE_CG_DRAWING
+  if (depth == 32)
+    {
+      char *base_addr = GetPixBaseAddr (pixmap);
+      short row_bytes = GetPixRowBytes (pixmap);
 
-  GetCPixel (x, y, &color);
+      return ((unsigned long *) (base_addr + y * row_bytes))[x] & 0x00ffffff;
+    }
+  else
+#endif
+  if (depth == 1)
+    {
+      char *base_addr = GetPixBaseAddr (pixmap);
+      short row_bytes = GetPixRowBytes (pixmap);
 
-  SetGWorld (old_port, old_gdh);
-  return RGB_TO_ULONG (color.red >> 8, color.green >> 8, color.blue >> 8);
+      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);
+
+      GetCPixel (x, y, &color);
+
+      SetGWorld (old_port, old_gdh);
+      return RGB_TO_ULONG (color.red >> 8, color.green >> 8, color.blue >> 8);
+    }
 }
 
 static void
@@ -220,6 +280,49 @@ XDestroyImage (ximg)
 {
   UnlockPixels (GetGWorldPixMap (ximg));
 }
+
+#if USE_CG_DRAWING
+static CGImageRef
+mac_create_cg_image_from_image (f, img)
+     struct frame *f;
+     struct image *img;
+{
+  Pixmap mask;
+  CGImageRef result = NULL;
+
+  BLOCK_INPUT;
+  if (img->mask)
+    mask = img->mask;
+  else
+    {
+      mask = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                           img->width, img->height, 1);
+      if (mask)
+       {
+         CGrafPtr old_port;
+         GDHandle old_gdh;
+         Rect r;
+
+         GetGWorld (&old_port, &old_gdh);
+         SetGWorld (mask, NULL);
+         BackColor (blackColor); /* Don't mask.  */
+         SetRect (&r, 0, 0, img->width, img->height);
+         EraseRect (&r);
+         SetGWorld (old_port, old_gdh);
+       }
+    }
+  if (mask)
+    {
+      CreateCGImageFromPixMaps (GetGWorldPixMap (img->pixmap),
+                               GetGWorldPixMap (mask), &result);
+      if (mask != img->mask)
+       XFreePixmap (FRAME_X_DISPLAY (f), mask);
+    }
+  UNBLOCK_INPUT;
+
+  return result;
+}
+#endif /* USE_CG_DRAWING */
 #endif /* MAC_OS */
 
 
@@ -341,8 +444,6 @@ x_create_bitmap_from_data (f, bits, width, height)
   id = x_allocate_bitmap_record (f);
 #ifdef MAC_OS
   dpyinfo->bitmaps[id - 1].bitmap_data = (char *) xmalloc (height * width);
-  if (! dpyinfo->bitmaps[id - 1].bitmap_data)
-    return -1;
   bcopy (bits, dpyinfo->bitmaps[id - 1].bitmap_data, height * width);
 #endif  /* MAC_OS */
 
@@ -502,7 +603,9 @@ x_destroy_all_bitmaps (dpyinfo)
 /* Useful functions defined in the section
    `Image type independent image structures' below. */
 
-static unsigned long four_corners_best P_ ((XImagePtr ximg, unsigned long width,
+static unsigned long four_corners_best P_ ((XImagePtr ximg,
+                                           int *corners,
+                                           unsigned long width,
                                            unsigned long height));
 
 static int x_create_x_image_and_pixmap P_ ((struct frame *f, int width, int height,
@@ -556,7 +659,7 @@ x_create_bitmap_mask (f, id)
       return -1;
     }
 
-  bg = four_corners_best (ximg, width, height);
+  bg = four_corners_best (ximg, NULL, width, height);
 
   for (y = 0; y < ximg->height; ++y)
     {
@@ -631,7 +734,7 @@ Lisp_Object Qxbm;
 /* Keywords.  */
 
 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
-extern Lisp_Object QCdata, QCtype;
+extern Lisp_Object QCdata, QCtype, Qcount;
 extern Lisp_Object Qcenter;
 Lisp_Object QCascent, QCmargin, QCrelief;
 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
@@ -1040,6 +1143,27 @@ or omitted means use the selected frame.  */)
   return mask;
 }
 
+DEFUN ("image-extension-data", Fimage_extension_data, Simage_extension_data, 1, 2, 0,
+       doc: /* Return extension data for image SPEC.
+FRAME is the frame on which the image will be displayed.  FRAME nil
+or omitted means use the selected frame.  */)
+     (spec, frame)
+     Lisp_Object spec, frame;
+{
+  Lisp_Object ext;
+
+  ext = Qnil;
+  if (valid_image_p (spec))
+    {
+      struct frame *f = check_x_frame (frame);
+      int id = lookup_image (f, spec);
+      struct image *img = IMAGE_FROM_ID (f, id);
+      ext = img->data.lisp_val;
+    }
+
+  return ext;
+}
+
 \f
 /***********************************************************************
                 Image type independent image structures
@@ -1047,7 +1171,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.  */
@@ -1067,6 +1194,7 @@ make_image (spec, hash)
   img->data.lisp_val = Qnil;
   img->ascent = DEFAULT_IMAGE_ASCENT;
   img->hash = hash;
+  img->corners[BOT_CORNER] = -1;  /* Full image */
   return img;
 }
 
@@ -1099,6 +1227,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.  */
@@ -1118,6 +1279,18 @@ prepare_image_for_display (f, img)
      type dependent loader function.  */
   if (img->pixmap == NO_PIXMAP && !img->load_failed_p)
     img->load_failed_p = img->type->load (f, img) == 0;
+
+#if defined (MAC_OS) && USE_CG_DRAWING
+  if (!img->load_failed_p && img->data.ptr_val == NULL)
+    {
+      img->data.ptr_val = mac_create_cg_image_from_image (f, img);
+      if (img->data.ptr_val == NULL)
+       {
+         img->load_failed_p = 1;
+         img->type->free (f, img);
+       }
+    }
+#endif
 }
 
 
@@ -1173,30 +1346,41 @@ image_ascent (img, face, slice)
    On W32, XIMG is assumed to a device context with the bitmap selected.  */
 
 static RGB_PIXEL_COLOR
-four_corners_best (ximg, width, height)
+four_corners_best (ximg, corners, width, height)
      XImagePtr_or_DC ximg;
+     int *corners;
      unsigned long width, height;
 {
-  RGB_PIXEL_COLOR corners[4], best;
+  RGB_PIXEL_COLOR corner_pixels[4], best;
   int i, best_count;
 
-  /* Get the colors at the corners of ximg.  */
-  corners[0] = GET_PIXEL (ximg, 0, 0);
-  corners[1] = GET_PIXEL (ximg, width - 1, 0);
-  corners[2] = GET_PIXEL (ximg, width - 1, height - 1);
-  corners[3] = GET_PIXEL (ximg, 0, height - 1);
-
+  if (corners && corners[BOT_CORNER] >= 0)
+    {
+      /* Get the colors at the corner_pixels of ximg.  */
+      corner_pixels[0] = GET_PIXEL (ximg, corners[LEFT_CORNER], corners[TOP_CORNER]);
+      corner_pixels[1] = GET_PIXEL (ximg, corners[RIGHT_CORNER] - 1, corners[TOP_CORNER]);
+      corner_pixels[2] = GET_PIXEL (ximg, corners[RIGHT_CORNER] - 1, corners[BOT_CORNER] - 1);
+      corner_pixels[3] = GET_PIXEL (ximg, corners[LEFT_CORNER], corners[BOT_CORNER] - 1);
+    }
+  else
+    {
+      /* Get the colors at the corner_pixels of ximg.  */
+      corner_pixels[0] = GET_PIXEL (ximg, 0, 0);
+      corner_pixels[1] = GET_PIXEL (ximg, width - 1, 0);
+      corner_pixels[2] = GET_PIXEL (ximg, width - 1, height - 1);
+      corner_pixels[3] = GET_PIXEL (ximg, 0, height - 1);
+    }
   /* Choose the most frequently found color as background.  */
   for (i = best_count = 0; i < 4; ++i)
     {
       int j, n;
 
       for (j = n = 0; j < 4; ++j)
-       if (corners[i] == corners[j])
+       if (corner_pixels[i] == corner_pixels[j])
          ++n;
 
       if (n > best_count)
-       best = corners[i], best_count = n;
+       best = corner_pixels[i], best_count = n;
     }
 
   return best;
@@ -1255,7 +1439,7 @@ image_background (img, f, ximg)
 #endif /* !HAVE_NTGUI */
        }
 
-      img->background = four_corners_best (ximg, img->width, img->height);
+      img->background = four_corners_best (ximg, img->corners, img->width, img->height);
 
       if (free_ximg)
        Destroy_Image (ximg, prev);
@@ -1300,7 +1484,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->corners, img->width, img->height) == PIX_MASK_RETAIN);
 
          if (free_mask)
            Destroy_Image (mask, prev);
@@ -1364,6 +1548,14 @@ x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
       img->colors = NULL;
       img->ncolors = 0;
     }
+
+#if defined (MAC_OS) && USE_CG_DRAWING
+  if (img->data.ptr_val)
+    {
+      CGImageRelease (img->data.ptr_val);
+      img->data.ptr_val = NULL;
+    }
+#endif
 }
 
 /* Free X resources of image IMG which is used on frame F.  */
@@ -1656,6 +1848,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)
     {
@@ -2003,7 +2201,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;
@@ -2084,8 +2281,8 @@ static unsigned char *slurp_file P_ ((char *, int *));
 
 
 /* Find image file FILE.  Look in data-directory, then
-   x-bitmap-file-path.  Value is the full name of the file found, or
-   nil if not found.  */
+   x-bitmap-file-path.  Value is the encoded full name of the file
+   found, or nil if not found.  */
 
 Lisp_Object
 x_find_image_file (file)
@@ -2105,7 +2302,10 @@ x_find_image_file (file)
   if (fd == -1)
     file_found = Qnil;
   else
-    close (fd);
+    {
+      file_found = ENCODE_FILE (file_found);
+      close (fd);
+    }
 
   UNGCPRO;
   return file_found;
@@ -2127,7 +2327,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;
@@ -2166,28 +2366,25 @@ find_image_fsspec (specified_file, file, fss)
      Lisp_Object specified_file, *file;
      FSSpec *fss;
 {
-#if TARGET_API_MAC_CARBON
-  FSRef fsr;
-#else
-  Str255 mac_pathname;
-#endif
   OSErr err;
+  AEDesc desc;
 
   *file = x_find_image_file (specified_file);
   if (!STRINGP (*file))
     return fnfErr;             /* file or directory not found;
                                   incomplete pathname */
   /* Try to open the image file.  */
-#if TARGET_API_MAC_CARBON
-  err = FSPathMakeRef (SDATA (*file), &fsr, NULL);
+  err = AECoercePtr (TYPE_FILE_NAME, SDATA (*file),
+                    SBYTES (*file), typeFSS, &desc);
   if (err == noErr)
-    err = FSGetCatalogInfo (&fsr, kFSCatInfoNone, NULL, NULL, fss, NULL);
+    {
+#if TARGET_API_MAC_CARBON
+      err = AEGetDescData (&desc, fss, sizeof (FSSpec));
 #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);
+      *fss = *(FSSpec *)(*(desc.dataHandle));
 #endif
+      AEDisposeDesc (&desc);
+    }
   return err;
 }
 
@@ -2196,21 +2393,21 @@ image_load_qt_1 (f, img, type, fss, dh)
      struct frame *f;
      struct image *img;
      OSType type;
-     FSSpec *fss;
+     const FSSpec *fss;
      Handle dh;
 {
-  OSErr err;
+  ComponentResult err;
   GraphicsImportComponent gi;
   Rect rect;
   int width, height;
+  ImageDescriptionHandle desc_handle;
   short draw_all_pixels;
   Lisp_Object specified_bg;
   XColor color;
   XImagePtr ximg;
   RGBColor bg_color;
 
-  err = OpenADefaultComponent (GraphicsImporterComponentType,
-                              type, &gi);
+  err = OpenADefaultComponent (GraphicsImporterComponentType, type, &gi);
   if (err != noErr)
     {
       image_error ("Cannot get importer component for `%s'", img->spec, Qnil);
@@ -2238,14 +2435,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
@@ -2422,7 +2627,7 @@ image_load_quartz2d (f, img, png_p)
          UNGCPRO;
          return 0;
        }
-      path = cfstring_create_with_string (file);
+      path = cfstring_create_with_utf8_cstring (SDATA (file));
       url = CFURLCreateWithFileSystemPath (NULL, path,
                                           kCFURLPOSIXPathStyle, 0);
       CFRelease (path);
@@ -2447,6 +2652,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)
     {
@@ -2460,8 +2675,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);
@@ -2505,7 +2719,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));
 
@@ -2893,7 +3108,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;
@@ -2934,7 +3150,7 @@ xbm_read_bitmap_data (contents, end, width, height, data)
       expect_ident ("define");
       expect (XBM_TK_IDENT);
 
-      if (LA1 == XBM_TK_NUMBER);
+      if (LA1 == XBM_TK_NUMBER)
        {
           char *p = strrchr (buffer, '_');
          p = p ? p + 1 : buffer;
@@ -2946,7 +3162,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;
@@ -2983,7 +3199,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)
     {
@@ -3050,7 +3266,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);
@@ -3104,7 +3320,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));
@@ -3608,6 +3824,47 @@ xpm_image_p (object)
 
 #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);
+
+  attrs.visual = FRAME_X_VISUAL (f);
+  attrs.colormap = FRAME_X_COLORMAP (f);
+  attrs.valuemask |= XpmVisual;
+  attrs.valuemask |= XpmColormap;
+
+  rc = XpmCreatePixmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                               bits, &bitmap, &mask, &attrs);
+  if (rc != XpmSuccess)
+    {
+      XpmFreeAttributes (&attrs);
+      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 /* defined (HAVE_XPM) && defined (HAVE_X_WINDOWS) */
+
 /* Load image IMG which will be displayed on frame F.  Value is
    non-zero if successful.  */
 
@@ -3655,6 +3912,9 @@ xpm_load (f, img)
   attrs.valuemask |= XpmCloseness;
 #endif /* not XpmAllocCloseColors */
 #endif /* ALLOC_XPM_COLORS */
+#ifdef ALLOC_XPM_COLORS
+  xpm_init_color_cache (f, &attrs);
+#endif
 
   /* If image specification contains symbolic color definitions, add
      these to `attrs'.  */
@@ -3849,25 +4109,25 @@ xpm_load (f, img)
 /* 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 int xpm_scan P_ ((const unsigned char **, const unsigned char *,
+                        const 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));
+  P_ ((void (**) (Lisp_Object, const unsigned char *, int, Lisp_Object),
+       Lisp_Object (**) (Lisp_Object, const unsigned char *, int)));
+static void xpm_put_color_table_v P_ ((Lisp_Object, const unsigned char *,
+                                      int, Lisp_Object));
 static Lisp_Object xpm_get_color_table_v P_ ((Lisp_Object,
-                                            unsigned char *, int));
+                                             const 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));
+  P_ ((void (**) (Lisp_Object, const unsigned char *, int, Lisp_Object),
+       Lisp_Object (**) (Lisp_Object, const unsigned char *, int)));
+static void xpm_put_color_table_h P_ ((Lisp_Object, const 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 *));
+                                             const unsigned char *, int));
+static int xpm_str_to_color_key P_ ((const char *));
 static int xpm_load_image P_ ((struct frame *, struct image *,
-                             unsigned char *, unsigned char *));
+                              const unsigned char *, const unsigned char *));
 
 /* Tokens returned from xpm_scan.  */
 
@@ -3887,7 +4147,7 @@ enum xpm_token
 
 static int
 xpm_scan (s, end, beg, len)
-     unsigned char **s, *end, **beg;
+     const unsigned char **s, *end, **beg;
      int *len;
 {
   int c;
@@ -3896,49 +4156,49 @@ xpm_scan (s, end, beg, len)
     {
       /* Skip white-space.  */
       while (*s < end && (c = *(*s)++, isspace (c)))
-      ;
+       ;
 
       /* gnus-pointer.xpm uses '-' in its identifier.
-       sb-dir-plus.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;
-      }
+       {
+         *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;
-      }
+       {
+         *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;
-      }
+       {
+         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;
+       return c;
     }
 
   return XPM_TK_EOF;
@@ -3953,8 +4213,8 @@ xpm_scan (s, end, beg, len)
 
 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);
+     void (**put_func) (Lisp_Object, const unsigned char *, int, Lisp_Object);
+     Lisp_Object (**get_func) (Lisp_Object, const unsigned char *, int);
 {
   *put_func = xpm_put_color_table_v;
   *get_func = xpm_get_color_table_v;
@@ -3964,7 +4224,7 @@ xpm_make_color_table_v (put_func, get_func)
 static void
 xpm_put_color_table_v (color_table, chars_start, chars_len, color)
      Lisp_Object color_table;
-     unsigned char *chars_start;
+     const unsigned char *chars_start;
      int chars_len;
      Lisp_Object color;
 {
@@ -3974,7 +4234,7 @@ xpm_put_color_table_v (color_table, chars_start, chars_len, color)
 static Lisp_Object
 xpm_get_color_table_v (color_table, chars_start, chars_len)
      Lisp_Object color_table;
-     unsigned char *chars_start;
+     const unsigned char *chars_start;
      int chars_len;
 {
   return XVECTOR (color_table)->contents[*chars_start];
@@ -3982,21 +4242,21 @@ xpm_get_color_table_v (color_table, chars_start, chars_len)
 
 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);
+     void (**put_func) (Lisp_Object, const unsigned char *, int, Lisp_Object);
+     Lisp_Object (**get_func) (Lisp_Object, const 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);
+                         make_float (DEFAULT_REHASH_SIZE),
+                         make_float (DEFAULT_REHASH_THRESHOLD),
+                         Qnil, Qnil, Qnil);
 }
 
 static void
 xpm_put_color_table_h (color_table, chars_start, chars_len, color)
      Lisp_Object color_table;
-     unsigned char *chars_start;
+     const unsigned char *chars_start;
      int chars_len;
      Lisp_Object color;
 {
@@ -4011,12 +4271,12 @@ xpm_put_color_table_h (color_table, chars_start, chars_len, color)
 static Lisp_Object
 xpm_get_color_table_h (color_table, chars_start, chars_len)
      Lisp_Object color_table;
-     unsigned char *chars_start;
+     const 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);
+                      NULL);
 
   return i >= 0 ? HASH_VALUE (table, i) : Qnil;
 }
@@ -4029,11 +4289,11 @@ enum xpm_color_key {
   XPM_COLOR_KEY_C
 };
 
-static char xpm_color_key_strings[][4] = {"s", "m", "g4", "g", "c"};
+static const char xpm_color_key_strings[][4] = {"s", "m", "g4", "g", "c"};
 
 static int
 xpm_str_to_color_key (s)
-     char *s;
+     const char *s;
 {
   int i;
 
@@ -4049,15 +4309,15 @@ static int
 xpm_load_image (f, img, contents, end)
      struct frame *f;
      struct image *img;
-     unsigned char *contents, *end;
+     const unsigned char *contents, *end;
 {
-  unsigned char *s = contents, *beg, *str;
+  const 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);
+  void (*put_color_table) (Lisp_Object, const unsigned char *, int, Lisp_Object);
+  Lisp_Object (*get_color_table) (Lisp_Object, const unsigned char *, int);
   Lisp_Object frame, color_symbols, color_table;
   int best_key, have_mask = 0;
   XImagePtr ximg = NULL, mask_img = NULL;
@@ -4065,17 +4325,17 @@ xpm_load_image (f, img, contents, end)
 #define match() \
      LA1 = xpm_scan (&s, end, &beg, &len)
 
-#define expect(TOKEN)         \
-     if (LA1 != (TOKEN))      \
-       goto failure;          \
-     else                     \
+#define expect(TOKEN)          \
+     if (LA1 != (TOKEN))       \
+       goto failure;           \
+     else                      \
        match ()
 
-#define expect_ident(IDENT)                                   \
+#define expect_ident(IDENT)                                    \
      if (LA1 == XPM_TK_IDENT \
-         && strlen ((IDENT)) == len && memcmp ((IDENT), beg, len) == 0)  \
-        match ();                                              \
-     else                                                     \
+         && strlen ((IDENT)) == len && memcmp ((IDENT), beg, len) == 0)        \
+       match ();                                               \
+     else                                                      \
        goto failure
 
   if (!(end - s >= 9 && memcmp (s, "/* XPM */", 9) == 0))
@@ -4096,10 +4356,17 @@ xpm_load_image (f, img, contents, end)
   memcpy (buffer, beg, len);
   buffer[len] = '\0';
   if (sscanf (buffer, "%d %d %d %d", &width, &height,
-            &num_colors, &chars_per_pixel) != 4
+             &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);
@@ -4107,17 +4374,17 @@ xpm_load_image (f, img, contents, end)
     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);
+               ? 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);
+                                         &get_color_table);
   else
     color_table = xpm_make_color_table_h (&put_color_table,
-                                        &get_color_table);
+                                         &get_color_table);
 
   while (num_colors-- > 0)
     {
@@ -4128,71 +4395,75 @@ xpm_load_image (f, img, contents, end)
 
       expect (XPM_TK_STRING);
       if (len <= chars_per_pixel || len >= BUFSIZ + chars_per_pixel)
-      goto failure;
+       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;
+       goto failure;
       key = xpm_str_to_color_key (str);
       if (key < 0)
-      goto failure;
+       goto failure;
       do
-      {
-        color = strtok (NULL, " \t");
-        if (color == NULL)
-          goto failure;
+       {
+         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)] = ' ';
-          }
+         while ((str = strtok (NULL, " \t")) != NULL)
+           {
+             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;
-      }
+         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);
-      }
+       {
+         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 (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);
+       (*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)
+                                   &ximg, &img->pixmap)
       || !x_create_x_image_and_pixmap (f, width, height, 1,
-                                     &mask_img, &img->mask))
+                                      &mask_img, &img->mask))
     {
       image_error ("Out of memory (%s)", img->spec, Qnil);
       goto error;
@@ -4203,30 +4474,38 @@ xpm_load_image (f, img, contents, end)
       expect (XPM_TK_STRING);
       str = beg;
       if (len < width * chars_per_pixel)
-      goto failure;
+       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 (f)
-                    : (have_mask = 1, PIX_MASK_RETAIN (f))));
-      }
+       {
+         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 (',');
+       expect (',');
     }
 
   img->width = width;
   img->height = height;
 
+  /* 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);
+
   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);
     }
@@ -4272,19 +4551,19 @@ xpm_load (f, img)
       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;
-      }
+       {
+         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;
-      }
+       {
+         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);
@@ -4296,7 +4575,7 @@ xpm_load (f, img)
 
       data = image_spec_value (img->spec, QCdata, NULL);
       success_p = xpm_load_image (f, img, SDATA (data),
-                                SDATA (data) + SBYTES (data));
+                                 SDATA (data) + SBYTES (data));
     }
 
   return success_p;
@@ -4973,7 +5252,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)
@@ -5113,7 +5392,7 @@ x_build_heuristic_mask (f, img, how)
     }
 
   if (use_img_background)
-    bg = four_corners_best (ximg, img->width, img->height);
+    bg = four_corners_best (ximg, img->corners, img->width, img->height);
 
   /* Set all bits in mask_img to 1 whose color in ximg is different
      from the background color bg.  */
@@ -5121,7 +5400,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);
@@ -5415,8 +5694,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;
 
@@ -5825,7 +6103,6 @@ png_load (f, img)
        {
          image_error ("Cannot open image file `%s'", file, Qnil);
          UNGCPRO;
-         fclose (fp);
          return 0;
        }
 
@@ -5916,6 +6193,9 @@ png_load (f, img)
   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))
@@ -6123,7 +6403,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;
            }
        }
@@ -6308,7 +6588,6 @@ 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);
 
@@ -6324,7 +6603,6 @@ init_jpeg_functions (Lisp_Object libraries)
   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);
@@ -6350,7 +6628,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
 
@@ -6377,7 +6654,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;
 {
 }
@@ -6388,7 +6675,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.  */
@@ -6408,7 +6695,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;
 {
@@ -6425,16 +6712,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.  */
@@ -6458,16 +6735,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.  */
 
@@ -6551,7 +6942,7 @@ 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));
@@ -6565,6 +6956,12 @@ jpeg_load (f, img)
   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);
@@ -6994,6 +7391,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);
@@ -7079,6 +7484,7 @@ tiff_load (f, img)
 
 static int gif_image_p P_ ((Lisp_Object object));
 static int gif_load P_ ((struct frame *f, struct image *img));
+static void gif_clear_image P_ ((struct frame *f, struct image *img));
 
 /* The symbol `gif' identifying images of this type.  */
 
@@ -7127,10 +7533,22 @@ static struct image_type gif_type =
   &Qgif,
   gif_image_p,
   gif_load,
-  x_clear_image,
+  gif_clear_image,
   NULL
 };
 
+/* Free X resources of GIF image IMG which is used on frame F.  */
+
+static void
+gif_clear_image (f, img)
+     struct frame *f;
+     struct image *img;
+{
+  /* IMG->data.ptr_val may contain extension data.  */
+  img->data.lisp_val = Qnil;
+  x_clear_image (f, img);
+}
+
 /* Return non-zero if OBJECT is a valid GIF image specification.  */
 
 static int
@@ -7251,7 +7669,7 @@ gif_load (f, img)
   GifFileType *gif;
   struct gcpro gcpro1;
   Lisp_Object image;
-  int ino, image_left, image_top, image_width, image_height;
+  int ino, image_height, image_width;
   gif_memory_source memsrc;
   unsigned char *raster;
 
@@ -7298,6 +7716,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)
@@ -7319,8 +7746,27 @@ 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);
+  img->corners[TOP_CORNER] = gif->SavedImages[ino].ImageDesc.Top;
+  img->corners[LEFT_CORNER] = gif->SavedImages[ino].ImageDesc.Left;
+  image_height = gif->SavedImages[ino].ImageDesc.Height;
+  img->corners[BOT_CORNER] = img->corners[TOP_CORNER] + image_height;
+  image_width = gif->SavedImages[ino].ImageDesc.Width;
+  img->corners[RIGHT_CORNER] = img->corners[LEFT_CORNER] + image_width;
+
+  width = img->width = max (gif->SWidth,
+                           max (gif->Image.Left + gif->Image.Width,
+                                img->corners[RIGHT_CORNER]));
+  height = img->height = max (gif->SHeight,
+                             max (gif->Image.Top + gif->Image.Height,
+                                  img->corners[BOT_CORNER]));
+
+  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))
@@ -7355,24 +7801,19 @@ 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 (y = 0; y < img->corners[TOP_CORNER]; ++y)
     for (x = 0; x < width; ++x)
       XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
 
-  for (y = image_top + image_height; y < height; ++y)
+  for (y = img->corners[BOT_CORNER]; y < height; ++y)
     for (x = 0; x < width; ++x)
       XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
 
-  for (y = image_top; y < image_top + image_height; ++y)
+  for (y = img->corners[TOP_CORNER]; y < img->corners[BOT_CORNER]; ++y)
     {
-      for (x = 0; x < image_left; ++x)
+      for (x = 0; x < img->corners[LEFT_CORNER]; ++x)
        XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
-      for (x = image_left + image_width; x < width; ++x)
+      for (x = img->corners[RIGHT_CORNER]; x < width; ++x)
        XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
     }
 
@@ -7402,8 +7843,8 @@ gif_load (f, img)
          for (x = 0; x < image_width; x++)
            {
              int i = raster[(y * image_width) + x];
-             XPutPixel (ximg, x + image_left, row + image_top,
-                        pixel_colors[i]);
+             XPutPixel (ximg, x + img->corners[LEFT_CORNER],
+                        row + img->corners[TOP_CORNER], pixel_colors[i]);
            }
 
          row += interlace_increment[pass];
@@ -7415,10 +7856,29 @@ gif_load (f, img)
        for (x = 0; x < image_width; ++x)
          {
            int i = raster[y * image_width + x];
-           XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
+           XPutPixel (ximg, x + img->corners[LEFT_CORNER],
+                      y + img->corners[TOP_CORNER], pixel_colors[i]);
          }
     }
 
+  /* Save GIF image extension data for `image-extension-data'.
+     Format is (count IMAGES FUNCTION "BYTES" ...).  */
+  img->data.lisp_val = Qnil;
+  if (gif->SavedImages[ino].ExtensionBlockCount > 0)
+    {
+      ExtensionBlock *ext = gif->SavedImages[ino].ExtensionBlocks;
+      for (i = 0; i < gif->SavedImages[ino].ExtensionBlockCount; i++, ext++)
+       /* Append (... FUNCTION "BYTES") */
+       img->data.lisp_val = Fcons (make_unibyte_string (ext->Bytes, ext->ByteCount),
+                                   Fcons (make_number (ext->Function),
+                                          img->data.lisp_val));
+      img->data.lisp_val = Fnreverse (img->data.lisp_val);
+    }
+  if (gif->ImageCount > 1)
+    img->data.lisp_val = Fcons (Qcount,
+                               Fcons (make_number (gif->ImageCount),
+                                      img->data.lisp_val));
+
   fn_DGifCloseFile (gif);
 
   /* Maybe fill in the background field while we have ximg handy. */
@@ -7458,8 +7918,8 @@ gif_load (f, img)
   RGBColor bg_color;
   int width, height;
   XImagePtr ximg;
-  TimeValue time;
-  struct gcpro gcpro1;
+  TimeScale time_scale;
+  TimeValue time, duration;
   int ino;
   CGrafPtr old_port;
   GDHandle old_gdh;
@@ -7467,6 +7927,9 @@ gif_load (f, img)
   specified_file = image_spec_value (img->spec, QCfile, NULL);
   specified_data = image_spec_value (img->spec, QCdata, NULL);
 
+  /* Animated gifs use QuickTime Movie Toolbox.  So initialize it here. */
+  EnterMovies ();
+
   if (NILP (specified_data))
     {
       /* Read from a file */
@@ -7564,6 +8027,7 @@ gif_load (f, img)
                   image, img->spec);
       goto error;
     }
+  time_scale = GetMediaTimeScale (media);
 
   specified_bg = image_spec_value (img->spec, QCbackground, NULL);
   if (!STRINGP (specified_bg) ||
@@ -7589,7 +8053,7 @@ gif_load (f, img)
   SetGWorld (old_port, old_gdh);
   SetMovieActive (movie, 1);
   SetMovieGWorld (movie, ximg, NULL);
-  SampleNumToMediaTime (media, ino + 1, &time, NULL);
+  SampleNumToMediaTime (media, ino + 1, &time, &duration);
   SetMovieTimeValue (movie, time);
   MoviesTask (movie, 0L);
   DisposeTrackMedia (media);
@@ -7597,6 +8061,24 @@ gif_load (f, img)
   DisposeMovie (movie);
   if (dh)
     DisposeHandle (dh);
+
+  /* Save GIF image extension data for `image-extension-data'.
+     Format is (count IMAGES 0xf9 GRAPHIC_CONTROL_EXTENSION_BLOCK).  */
+  {
+    Lisp_Object gce = make_uninit_string (4);
+    int centisec = ((float)duration / time_scale) * 100.0f + 0.5f;
+
+    /* Fill the delay time field.  */
+    SSET (gce, 1, centisec & 0xff);
+    SSET (gce, 2, (centisec >> 8) & 0xff);
+    /* We don't know about other fields.  */
+    SSET (gce, 0, 0);
+    SSET (gce, 3, 0);
+
+    img->data.lisp_val = list4 (Qcount, make_number (nsamples),
+                               make_number (0xf9), gce);
+  }
+
   /* 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);
@@ -7779,6 +8261,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);
 
@@ -8038,9 +8526,6 @@ 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;
 
-  define_image_type (&xbm_type, 1);
-  define_image_type (&pbm_type, 1);
-
   DEFVAR_LISP ("image-library-alist", &Vimage_library_alist,
     doc: /* Alist of image types vs external libraries needed to display them.
 
@@ -8055,9 +8540,32 @@ 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");
@@ -8102,14 +8610,6 @@ listed; they're always supported.  */);
   staticpro (&QCpt_height);
 #endif /* HAVE_GHOSTSCRIPT */
 
-  Qpbm = intern ("pbm");
-  staticpro (&Qpbm);
-  ADD_IMAGE_TYPE(Qpbm);
-
-  Qxbm = intern ("xbm");
-  staticpro (&Qxbm);
-  ADD_IMAGE_TYPE(Qxbm);
-
 #if defined (HAVE_XPM) || defined (MAC_OS)
   Qxpm = intern ("xpm");
   staticpro (&Qxpm);
@@ -8144,6 +8644,7 @@ listed; they're always supported.  */);
   defsubr (&Sclear_image_cache);
   defsubr (&Simage_size);
   defsubr (&Simage_mask_p);
+  defsubr (&Simage_extension_data);
 
 #if GLYPH_DEBUG
   defsubr (&Simagep);
@@ -8171,13 +8672,9 @@ meaning don't clear the cache.  */);
 void
 init_image ()
 {
-#ifdef MAC_OS
-  /* Animated gifs use QuickTime Movie Toolbox.  So initialize it here. */
-  EnterMovies ();
-#ifdef MAC_OSX
+#if defined (MAC_OSX) && TARGET_API_MAC_CARBON
   init_image_func_pointer ();
 #endif
-#endif
 }
 
 /* arch-tag: 123c2a5e-14a8-4c53-ab95-af47d7db49b9