(print_help_and_exit): Fix space to improve alignment in output messages.
[bpt/emacs.git] / src / image.c
index b8317b1..81a42f9 100644 (file)
@@ -1,12 +1,13 @@
 /* Functions for image support on window system.
    Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
 /* Functions for image support on window system.
    Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-                 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+                 2001, 2002, 2003, 2004, 2005, 2006, 2007
+                 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -531,7 +532,7 @@ x_create_bitmap_from_file (f, file)
 /* Free bitmap B.  */
 
 static void
 /* Free bitmap B.  */
 
 static void
-Free_Bitmap_Record (dpyinfo, bm)
+free_bitmap_record (dpyinfo, bm)
      Display_Info *dpyinfo;
      Bitmap_Record *bm;
 {
      Display_Info *dpyinfo;
      Bitmap_Record *bm;
 {
@@ -573,7 +574,7 @@ x_destroy_bitmap (f, id)
       if (--bm->refcount == 0)
        {
          BLOCK_INPUT;
       if (--bm->refcount == 0)
        {
          BLOCK_INPUT;
-         Free_Bitmap_Record (dpyinfo, bm);
+         free_bitmap_record (dpyinfo, bm);
          UNBLOCK_INPUT;
        }
     }
          UNBLOCK_INPUT;
        }
     }
@@ -590,7 +591,7 @@ x_destroy_all_bitmaps (dpyinfo)
 
   for (i = 0; i < dpyinfo->bitmaps_last; i++, bm++)
     if (bm->refcount > 0)
 
   for (i = 0; i < dpyinfo->bitmaps_last; i++, bm++)
     if (bm->refcount > 0)
-      Free_Bitmap_Record (dpyinfo, bm);
+      free_bitmap_record (dpyinfo, bm);
 
   dpyinfo->bitmaps_last = 0;
 }
 
   dpyinfo->bitmaps_last = 0;
 }
@@ -1317,8 +1318,8 @@ image_ascent (img, face, slice)
        {
 #ifdef HAVE_NTGUI
          /* W32 specific version.  Why?. ++kfs  */
        {
 #ifdef HAVE_NTGUI
          /* W32 specific version.  Why?. ++kfs  */
-         ascent = height / 2 - (FONT_DESCENT(face->font)
-                                - FONT_BASE(face->font)) / 2;
+         ascent = height / 2 - (FONT_DESCENT (face->font)
+                                - FONT_BASE (face->font)) / 2;
 #else
          /* This expression is arranged so that if the image can't be
             exactly centered, it will be moved slightly up.  This is
 #else
          /* This expression is arranged so that if the image can't be
             exactly centered, it will be moved slightly up.  This is
@@ -1609,6 +1610,7 @@ x_alloc_image_color (f, img, color_name, dflt)
                             Image Cache
  ***********************************************************************/
 
                             Image Cache
  ***********************************************************************/
 
+static struct image *search_image_cache P_ ((struct frame *, Lisp_Object, unsigned));
 static void cache_image P_ ((struct frame *f, struct image *img));
 static void postprocess_image P_ ((struct frame *, struct image *));
 
 static void cache_image P_ ((struct frame *f, struct image *img));
 static void postprocess_image P_ ((struct frame *, struct image *));
 
@@ -1631,6 +1633,55 @@ make_image_cache ()
 }
 
 
 }
 
 
+/* Find an image matching SPEC in the cache, and return it.  If no
+   image is found, return NULL.  */
+static struct image *
+search_image_cache (f, spec, hash)
+     struct frame *f;
+     Lisp_Object spec;
+     unsigned hash;
+{
+  struct image *img;
+  struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
+  int i = hash % IMAGE_CACHE_BUCKETS_SIZE;
+
+  if (!c) return NULL;
+
+  /* If the image spec does not specify a background color, the cached
+     image must have the same background color as the current frame.
+     The foreground color must also match, for the sake of monochrome
+     images.
+
+     In fact, we could ignore the foreground color matching condition
+     for color images, or if the image spec specifies :foreground;
+     similarly we could ignore the background color matching condition
+     for formats that don't use transparency (such as jpeg), or if the
+     image spec specifies :background.  However, the extra memory
+     usage is probably negligible in practice, so we don't bother.  */
+
+  for (img = c->buckets[i]; img; img = img->next)
+    if (img->hash == hash
+       && !NILP (Fequal (img->spec, spec))
+       && img->frame_foreground == FRAME_FOREGROUND_PIXEL (f)
+       && img->frame_background == FRAME_BACKGROUND_PIXEL (f))
+      break;
+  return img;
+}
+
+
+/* Search frame F for an image with spec SPEC, and free it.  */
+
+static void
+uncache_image (f, spec)
+     struct frame *f;
+     Lisp_Object spec;
+{
+  struct image *img = search_image_cache (f, spec, sxhash (spec, 0));
+  if (img)
+    free_image (f, img);
+}
+
+
 /* Free image cache of frame F.  Be aware that X frames share images
    caches.  */
 
 /* Free image cache of frame F.  Be aware that X frames share images
    caches.  */
 
@@ -1659,9 +1710,9 @@ free_image_cache (f)
 /* Clear image cache of frame F.  FORCE_P non-zero means free all
    images.  FORCE_P zero means clear only images that haven't been
    displayed for some time.  Should be called from time to time to
 /* Clear image cache of frame F.  FORCE_P non-zero means free all
    images.  FORCE_P zero means clear only images that haven't been
    displayed for some time.  Should be called from time to time to
-   reduce the number of loaded images.  If image-eviction-seconds is
-   non-nil, this frees images in the cache which weren't displayed for
-   at least that many seconds.  */
+   reduce the number of loaded images.  If image-cache-eviction-delay
+   is non-nil, this frees images in the cache which weren't displayed
+   for at least that many seconds.  */
 
 void
 clear_image_cache (f, force_p)
 
 void
 clear_image_cache (f, force_p)
@@ -1741,6 +1792,36 @@ FRAME t means clear the image caches of all frames.  */)
 }
 
 
 }
 
 
+DEFUN ("image-refresh", Fimage_refresh, Simage_refresh,
+       1, 2, 0,
+       doc: /* Refresh the image with specification SPEC on frame FRAME.
+If SPEC specifies an image file, the displayed image is updated with
+the current contents of that file.
+FRAME nil or omitted means use the selected frame.
+FRAME t means refresh the image on all frames.  */)
+     (spec, frame)
+     Lisp_Object spec, frame;
+{
+  if (!valid_image_p (spec))
+    error ("Invalid image specification");
+
+  if (EQ (frame, Qt))
+    {
+      Lisp_Object tail;
+      FOR_EACH_FRAME (tail, frame)
+       {
+         struct frame *f = XFRAME (frame);
+         if (FRAME_WINDOW_P (f))
+           uncache_image (f, spec);
+       }
+    }
+  else
+    uncache_image (check_x_frame (frame), spec);
+
+  return Qnil;
+}
+
+
 /* Compute masks and transform image IMG on frame F, as specified
    by the image's specification,  */
 
 /* Compute masks and transform image IMG on frame F, as specified
    by the image's specification,  */
 
@@ -1824,9 +1905,8 @@ lookup_image (f, spec)
      struct frame *f;
      Lisp_Object spec;
 {
      struct frame *f;
      Lisp_Object spec;
 {
-  struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
+  struct image_cache *c;
   struct image *img;
   struct image *img;
-  int i;
   unsigned hash;
   struct gcpro gcpro1;
   EMACS_TIME now;
   unsigned hash;
   struct gcpro gcpro1;
   EMACS_TIME now;
@@ -1836,16 +1916,13 @@ lookup_image (f, spec)
   xassert (FRAME_WINDOW_P (f));
   xassert (valid_image_p (spec));
 
   xassert (FRAME_WINDOW_P (f));
   xassert (valid_image_p (spec));
 
+  c = FRAME_X_IMAGE_CACHE (f);
+
   GCPRO1 (spec);
 
   /* Look up SPEC in the hash table of the image cache.  */
   hash = sxhash (spec, 0);
   GCPRO1 (spec);
 
   /* Look up SPEC in the hash table of the image cache.  */
   hash = sxhash (spec, 0);
-  i = hash % IMAGE_CACHE_BUCKETS_SIZE;
-
-  for (img = c->buckets[i]; img; img = img->next)
-    if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
-      break;
-
+  img = search_image_cache (f, spec, hash);
   if (img && img->load_failed_p)
     {
       free_image (f, img);
   if (img && img->load_failed_p)
     {
       free_image (f, img);
@@ -1861,6 +1938,8 @@ lookup_image (f, spec)
       img = make_image (spec, hash);
       cache_image (f, img);
       img->load_failed_p = img->type->load (f, img) == 0;
       img = make_image (spec, hash);
       cache_image (f, img);
       img->load_failed_p = img->type->load (f, img) == 0;
+      img->frame_foreground = FRAME_FOREGROUND_PIXEL (f);
+      img->frame_background = FRAME_BACKGROUND_PIXEL (f);
 
       /* If we can't load the image, and we don't have a width and
         height, use some arbitrary width and height so that we can
 
       /* If we can't load the image, and we don't have a width and
         height, use some arbitrary width and height so that we can
@@ -2020,7 +2099,7 @@ forall_images_in_image_cache (f, fn)
 
 /* Load a DLL implementing an image type.
    The `image-library-alist' variable associates a symbol,
 
 /* 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.
+   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.  */
    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.  */
@@ -2176,7 +2255,7 @@ x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
 
   if (*pixmap == NULL)
     {
 
   if (*pixmap == NULL)
     {
-      DWORD err = GetLastError();
+      DWORD err = GetLastError ();
       Lisp_Object errcode;
       /* All system errors are < 10000, so the following is safe.  */
       XSETINT (errcode, (int) err);
       Lisp_Object errcode;
       /* All system errors are < 10000, so the following is safe.  */
       XSETINT (errcode, (int) err);
@@ -2278,7 +2357,7 @@ x_put_x_image (f, ximg, pixmap, width, height)
 static unsigned char *slurp_file P_ ((char *, int *));
 
 
 static unsigned char *slurp_file P_ ((char *, int *));
 
 
-/* Find image file FILE.  Look in data-directory, then
+/* Find image file FILE.  Look in data-directory/images, then
    x-bitmap-file-path.  Value is the encoded 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.  */
 
@@ -2291,10 +2370,14 @@ x_find_image_file (file)
   int fd;
 
   file_found = Qnil;
   int fd;
 
   file_found = Qnil;
-  search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
+  /* TODO I think this should use something like image-load-path
+     instead.  Unfortunately, that can contain non-string elements.  */
+  search_path = Fcons (Fexpand_file_name (build_string ("images"),
+                                         Vdata_directory),
+                      Vx_bitmap_file_path);
   GCPRO2 (file_found, search_path);
 
   GCPRO2 (file_found, search_path);
 
-  /* Try to find FILE in data-directory, then x-bitmap-file-path.  */
+  /* Try to find FILE in data-directory/images, then x-bitmap-file-path.  */
   fd = openp (search_path, file, Qnil, &file_found, Qnil);
 
   if (fd == -1)
   fd = openp (search_path, file, Qnil, &file_found, Qnil);
 
   if (fd == -1)
@@ -2803,7 +2886,7 @@ enum xbm_token
    3. a vector of strings or bool-vectors, one for each line of the
    bitmap.
 
    3. a vector of strings or bool-vectors, one for each line of the
    bitmap.
 
-   4. A string containing an in-memory XBM file.  WIDTH and HEIGHT
+   4. a string containing an in-memory XBM file.  WIDTH and HEIGHT
    may not be specified in this case because they are defined in the
    XBM file.
 
    may not be specified in this case because they are defined in the
    XBM file.
 
@@ -3028,7 +3111,8 @@ w32_create_pixmap_from_bitmap_data (int width, int height, char *data)
   return bmp;
 }
 
   return bmp;
 }
 
-static void convert_mono_to_color_image (f, img, foreground, background)
+static void
+convert_mono_to_color_image (f, img, foreground, background)
      struct frame *f;
      struct image *img;
      COLORREF foreground, background;
      struct frame *f;
      struct image *img;
      COLORREF foreground, background;
@@ -3044,8 +3128,8 @@ static void convert_mono_to_color_image (f, img, foreground, background)
   release_frame_dc (f, hdc);
   old_prev = SelectObject (old_img_dc, img->pixmap);
   new_prev = SelectObject (new_img_dc, new_pixmap);
   release_frame_dc (f, hdc);
   old_prev = SelectObject (old_img_dc, img->pixmap);
   new_prev = SelectObject (new_img_dc, new_pixmap);
-  SetTextColor (new_img_dc, foreground);
-  SetBkColor (new_img_dc, background);
+  SetTextColor (new_img_dc, background);
+  SetBkColor (new_img_dc, foreground);
 
   BitBlt (new_img_dc, 0, 0, img->width, img->height, old_img_dc,
          0, 0, SRCCOPY);
 
   BitBlt (new_img_dc, 0, 0, img->width, img->height, old_img_dc,
          0, 0, SRCCOPY);
@@ -3071,7 +3155,7 @@ static void convert_mono_to_color_image (f, img, foreground, background)
 
 
 static void
 
 
 static void
-Create_Pixmap_From_Bitmap_Data(f, img, data, fg, bg, non_default_colors)
+Create_Pixmap_From_Bitmap_Data (f, img, data, fg, bg, non_default_colors)
      struct frame *f;
      struct image *img;
      char *data;
      struct frame *f;
      struct image *img;
      char *data;
@@ -3910,9 +3994,6 @@ xpm_load (f, img)
   attrs.valuemask |= XpmCloseness;
 #endif /* not XpmAllocCloseColors */
 #endif /* ALLOC_XPM_COLORS */
   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'.  */
 
   /* If image specification contains symbolic color definitions, add
      these to `attrs'.  */
@@ -4202,7 +4283,7 @@ xpm_scan (s, end, beg, len)
   return XPM_TK_EOF;
 }
 
   return XPM_TK_EOF;
 }
 
-/* Functions for color table lookup in XPM data.  A Key is a string
+/* 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
    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
@@ -4980,7 +5061,8 @@ x_to_xcolors (f, img, rgb_p)
    created with CreateDIBSection, with the pointer to the bit values
    stored in ximg->data.  */
 
    created with CreateDIBSection, with the pointer to the bit values
    stored in ximg->data.  */
 
-static void XPutPixel (ximg, x, y, color)
+static void
+XPutPixel (ximg, x, y, color)
      XImagePtr  ximg;
      int x, y;
      COLORREF color;
      XImagePtr  ximg;
      int x, y;
      COLORREF color;
@@ -5730,7 +5812,17 @@ pbm_load (f, img)
            if (raw_p)
              {
                if ((x & 7) == 0)
            if (raw_p)
              {
                if ((x & 7) == 0)
-                 c = *p++;
+                 {
+                   if (p >= end)
+                     {
+                       x_destroy_x_image (ximg);
+                       x_clear_image (f, img);
+                       image_error ("Invalid image size in image `%s'",
+                                    img->spec, Qnil);
+                       goto error;
+                     }
+                   c = *p++;
+                 }
                g = c & 0x80;
                c <<= 1;
              }
                g = c & 0x80;
                c <<= 1;
              }
@@ -5742,9 +5834,13 @@ pbm_load (f, img)
     }
   else
     {
     }
   else
     {
-      if (raw_p && (p + 3 * height * width > end))
+      if (raw_p
+         && ((type == PBM_GRAY)
+             ? (p + height * width > end)
+             : (p + 3 * height * width > end)))
        {
          x_destroy_x_image (ximg);
        {
          x_destroy_x_image (ximg);
+         x_clear_image (f, img);
          image_error ("Invalid image size in image `%s'",
                       img->spec, Qnil);
          goto error;
          image_error ("Invalid image size in image `%s'",
                       img->spec, Qnil);
          goto error;
@@ -6250,7 +6346,7 @@ png_load (f, img)
      simple transparency, we prefer a clipping mask.  */
   if (!transparent_p)
     {
      simple transparency, we prefer a clipping mask.  */
   if (!transparent_p)
     {
-      png_color_16 *image_bg;
+      /* png_color_16 *image_bg; */
       Lisp_Object specified_bg
        = image_spec_value (img->spec, QCbackground, NULL);
 
       Lisp_Object specified_bg
        = image_spec_value (img->spec, QCbackground, NULL);
 
@@ -6272,11 +6368,14 @@ png_load (f, img)
                                     PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
            }
        }
                                     PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
            }
        }
+      /* The commented-out code checked if the png specifies a default
+        background color, and uses that.  Since we use the current
+        frame background, it is OK for us to ignore this.
+
       else if (fn_png_get_bKGD (png_ptr, info_ptr, &image_bg))
       else if (fn_png_get_bKGD (png_ptr, info_ptr, &image_bg))
-       /* Image contains a background color with which to
-          combine the image.  */
        fn_png_set_background (png_ptr, image_bg,
                               PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
        fn_png_set_background (png_ptr, image_bg,
                               PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+       */
       else
        {
          /* Image does not contain a background color with which
       else
        {
          /* Image does not contain a background color with which
@@ -6617,7 +6716,7 @@ init_jpeg_functions (Lisp_Object libraries)
 /* Wrapper since we can't directly assign the function pointer
    to another function pointer that was declared more completely easily.  */
 static boolean
 /* Wrapper since we can't directly assign the function pointer
    to another function pointer that was declared more completely easily.  */
 static boolean
-jpeg_resync_to_restart_wrapper(cinfo, desired)
+jpeg_resync_to_restart_wrapper (cinfo, desired)
      j_decompress_ptr cinfo;
      int desired;
 {
      j_decompress_ptr cinfo;
      int desired;
 {
@@ -6678,18 +6777,19 @@ our_common_term_source (cinfo)
    whenever more data is needed.  We read the whole image in one step,
    so this only adds a fake end of input marker at the end.  */
 
    whenever more data is needed.  We read the whole image in one step,
    so this only adds a fake end of input marker at the end.  */
 
+static JOCTET omfib_buffer[2];
+
 static boolean
 our_memory_fill_input_buffer (cinfo)
      j_decompress_ptr cinfo;
 {
   /* Insert a fake EOI marker.  */
   struct jpeg_source_mgr *src = cinfo->src;
 static boolean
 our_memory_fill_input_buffer (cinfo)
      j_decompress_ptr cinfo;
 {
   /* Insert a fake EOI marker.  */
   struct jpeg_source_mgr *src = cinfo->src;
-  static JOCTET buffer[2];
 
 
-  buffer[0] = (JOCTET) 0xFF;
-  buffer[1] = (JOCTET) JPEG_EOI;
+  omfib_buffer[0] = (JOCTET) 0xFF;
+  omfib_buffer[1] = (JOCTET) JPEG_EOI;
 
 
-  src->next_input_byte = buffer;
+  src->next_input_byte = omfib_buffer;
   src->bytes_in_buffer = 2;
   return 1;
 }
   src->bytes_in_buffer = 2;
   return 1;
 }
@@ -7659,6 +7759,9 @@ gif_read_from_memory (file, buf, len)
 /* Load GIF image IMG for use on frame F.  Value is non-zero if
    successful.  */
 
 /* Load GIF image IMG for use on frame F.  Value is non-zero if
    successful.  */
 
+static int interlace_start[] = {0, 4, 2, 1};
+static int interlace_increment[] = {8, 8, 4, 2};
+
 static int
 gif_load (f, img)
      struct frame *f;
 static int
 gif_load (f, img)
      struct frame *f;
@@ -7711,7 +7814,7 @@ gif_load (f, img)
       memsrc.index = 0;
 
       /* Casting return value avoids a GCC warning on W32.  */
       memsrc.index = 0;
 
       /* Casting return value avoids a GCC warning on W32.  */
-      gif = (GifFileType *)fn_DGifOpen(&memsrc, gif_read_from_memory);
+      gif = (GifFileType *) fn_DGifOpen (&memsrc, gif_read_from_memory);
       if (!gif)
        {
          image_error ("Cannot open memory source `%s'", img->spec, Qnil);
       if (!gif)
        {
          image_error ("Cannot open memory source `%s'", img->spec, Qnil);
@@ -7787,13 +7890,14 @@ gif_load (f, img)
   init_color_table ();
   bzero (pixel_colors, sizeof pixel_colors);
 
   init_color_table ();
   bzero (pixel_colors, sizeof pixel_colors);
 
-  for (i = 0; i < gif_color_map->ColorCount; ++i)
-    {
-      int r = gif_color_map->Colors[i].Red << 8;
-      int g = gif_color_map->Colors[i].Green << 8;
-      int b = gif_color_map->Colors[i].Blue << 8;
-      pixel_colors[i] = lookup_rgb_color (f, r, g, b);
-    }
+  if (gif_color_map)
+    for (i = 0; i < gif_color_map->ColorCount; ++i)
+      {
+        int r = gif_color_map->Colors[i].Red << 8;
+        int g = gif_color_map->Colors[i].Green << 8;
+        int b = gif_color_map->Colors[i].Blue << 8;
+        pixel_colors[i] = lookup_rgb_color (f, r, g, b);
+      }
 
 #ifdef COLOR_TABLE_SUPPORT
   img->colors = colors_in_color_table (&img->ncolors);
 
 #ifdef COLOR_TABLE_SUPPORT
   img->colors = colors_in_color_table (&img->ncolors);
@@ -7828,8 +7932,6 @@ gif_load (f, img)
 
   if (gif->SavedImages[ino].ImageDesc.Interlace)
     {
 
   if (gif->SavedImages[ino].ImageDesc.Interlace)
     {
-      static int interlace_start[] = {0, 4, 2, 1};
-      static int interlace_increment[] = {8, 8, 4, 2};
       int pass;
       int row = interlace_start[0];
 
       int pass;
       int row = interlace_start[0];
 
@@ -8111,6 +8213,418 @@ gif_load (f, img)
 
 
 \f
 
 
 \f
+/***********************************************************************
+                                SVG
+ ***********************************************************************/
+
+#if defined (HAVE_RSVG)
+
+/* Function prototypes.  */
+
+static int svg_image_p P_ ((Lisp_Object object));
+static int svg_load P_ ((struct frame *f, struct image *img));
+
+static int svg_load_image P_ ((struct frame *, struct image *,
+                              unsigned char *, unsigned int));
+
+/* The symbol `svg' identifying images of this type. */
+
+Lisp_Object Qsvg;
+
+/* Indices of image specification fields in svg_format, below.  */
+
+enum svg_keyword_index
+{
+  SVG_TYPE,
+  SVG_DATA,
+  SVG_FILE,
+  SVG_ASCENT,
+  SVG_MARGIN,
+  SVG_RELIEF,
+  SVG_ALGORITHM,
+  SVG_HEURISTIC_MASK,
+  SVG_MASK,
+  SVG_BACKGROUND,
+  SVG_LAST
+};
+
+/* Vector of image_keyword structures describing the format
+   of valid user-defined image specifications.  */
+
+static struct image_keyword svg_format[SVG_LAST] =
+{
+  {":type",            IMAGE_SYMBOL_VALUE,                     1},
+  {":data",            IMAGE_STRING_VALUE,                     0},
+  {":file",            IMAGE_STRING_VALUE,                     0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
+  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,   0},
+  {":relief",          IMAGE_INTEGER_VALUE,                    0},
+  {":conversion",      IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":background",      IMAGE_STRING_OR_NIL_VALUE,              0}
+};
+
+/* Structure describing the image type `svg'.  Its the same type of
+   structure defined for all image formats, handled by emacs image
+   functions.  See struct image_type in dispextern.h.  */
+
+static struct image_type svg_type =
+{
+  /* An identifier showing that this is an image structure for the SVG format.  */
+  &Qsvg,
+  /* Handle to a function that can be used to identify a SVG file.  */
+  svg_image_p,
+  /* Handle to function used to load a SVG file.  */
+  svg_load,
+  /* Handle to function to free sresources for SVG.  */
+  x_clear_image,
+  /* An internal field to link to the next image type in a list of
+     image types, will be filled in when registering the format.  */
+  NULL
+};
+
+
+/* Return non-zero if OBJECT is a valid SVG image specification.  Do
+   this by calling parse_image_spec and supplying the keywords that
+   identify the SVG format.   */
+
+static int
+svg_image_p (object)
+     Lisp_Object object;
+{
+  struct image_keyword fmt[SVG_LAST];
+  bcopy (svg_format, fmt, sizeof fmt);
+
+  if (!parse_image_spec (object, fmt, SVG_LAST, Qsvg))
+    return 0;
+
+  /* Must specify either the :data or :file keyword.  */
+  return fmt[SVG_FILE].count + fmt[SVG_DATA].count == 1;
+}
+
+#include <librsvg/rsvg.h>
+
+#ifdef HAVE_NTGUI
+
+/* SVG library functions.  */
+DEF_IMGLIB_FN (rsvg_handle_new);
+DEF_IMGLIB_FN (rsvg_handle_set_size_callback);
+DEF_IMGLIB_FN (rsvg_handle_write);
+DEF_IMGLIB_FN (rsvg_handle_close);
+DEF_IMGLIB_FN (rsvg_handle_get_pixbuf);
+DEF_IMGLIB_FN (rsvg_handle_free);
+
+DEF_IMGLIB_FN (gdk_pixbuf_get_width);
+DEF_IMGLIB_FN (gdk_pixbuf_get_height);
+DEF_IMGLIB_FN (gdk_pixbuf_get_pixels);
+DEF_IMGLIB_FN (gdk_pixbuf_get_rowstride);
+DEF_IMGLIB_FN (gdk_pixbuf_get_colorspace);
+DEF_IMGLIB_FN (gdk_pixbuf_get_n_channels);
+DEF_IMGLIB_FN (gdk_pixbuf_get_has_alpha);
+DEF_IMGLIB_FN (gdk_pixbuf_get_bits_per_sample);
+
+DEF_IMGLIB_FN (g_type_init);
+DEF_IMGLIB_FN (g_object_unref);
+DEF_IMGLIB_FN (g_error_free);
+
+Lisp_Object Qgdk_pixbuf, Qglib;
+
+static int
+init_svg_functions (Lisp_Object libraries)
+{
+  HMODULE library, gdklib, glib;
+
+  if (!(glib = w32_delayed_load (libraries, Qglib))
+      || !(gdklib = w32_delayed_load (libraries, Qgdk_pixbuf))
+      || !(library = w32_delayed_load (libraries, Qsvg)))
+    return 0;
+
+  LOAD_IMGLIB_FN (library, rsvg_handle_new);
+  LOAD_IMGLIB_FN (library, rsvg_handle_set_size_callback);
+  LOAD_IMGLIB_FN (library, rsvg_handle_write);
+  LOAD_IMGLIB_FN (library, rsvg_handle_close);
+  LOAD_IMGLIB_FN (library, rsvg_handle_get_pixbuf);
+  LOAD_IMGLIB_FN (library, rsvg_handle_free);
+
+  LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_width);
+  LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_height);
+  LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_pixels);
+  LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_rowstride);
+  LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_colorspace);
+  LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_n_channels);
+  LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_has_alpha);
+  LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_bits_per_sample);
+
+  LOAD_IMGLIB_FN (glib, g_type_init);
+  LOAD_IMGLIB_FN (glib, g_object_unref);
+  LOAD_IMGLIB_FN (glib, g_error_free);
+  return 1;
+}
+
+#else
+/* The following aliases for library functions allow dynamic loading
+   to be used on some platforms.  */
+#define fn_rsvg_handle_new             rsvg_handle_new
+#define fn_rsvg_handle_set_size_callback rsvg_handle_set_size_callback
+#define fn_rsvg_handle_write           rsvg_handle_write
+#define fn_rsvg_handle_close           rsvg_handle_close
+#define fn_rsvg_handle_get_pixbuf      rsvg_handle_get_pixbuf
+#define fn_rsvg_handle_free            rsvg_handle_free
+
+#define fn_gdk_pixbuf_get_width                  gdk_pixbuf_get_width
+#define fn_gdk_pixbuf_get_height         gdk_pixbuf_get_height
+#define fn_gdk_pixbuf_get_pixels         gdk_pixbuf_get_pixels
+#define fn_gdk_pixbuf_get_rowstride      gdk_pixbuf_get_rowstride
+#define fn_gdk_pixbuf_get_colorspace     gdk_pixbuf_get_colorspace
+#define fn_gdk_pixbuf_get_n_channels     gdk_pixbuf_get_n_channels
+#define fn_gdk_pixbuf_get_has_alpha      gdk_pixbuf_get_has_alpha
+#define fn_gdk_pixbuf_get_bits_per_sample gdk_pixbuf_get_bits_per_sample
+
+#define fn_g_type_init                    g_type_init
+#define fn_g_object_unref                 g_object_unref
+#define fn_g_error_free                   g_error_free
+#endif /* !HAVE_NTGUI  */
+
+/* Load SVG image IMG for use on frame F.  Value is non-zero if
+   successful. this function will go into the svg_type structure, and
+   the prototype thus needs to be compatible with that structure.  */
+
+static int
+svg_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;
+       }
+
+      /* Read the entire file into memory.  */
+      contents = slurp_file (SDATA (file), &size);
+      if (contents == NULL)
+       {
+         image_error ("Error loading SVG image `%s'", img->spec, Qnil);
+         UNGCPRO;
+         return 0;
+       }
+      /* If the file was slurped into memory properly, parse it.  */
+      success_p = svg_load_image (f, img, contents, size);
+      xfree (contents);
+      UNGCPRO;
+    }
+  /* Else its not a file, its a lisp object.  Load the image from a
+     lisp object rather than a file.  */
+  else
+    {
+      Lisp_Object data;
+
+      data = image_spec_value (img->spec, QCdata, NULL);
+      success_p = svg_load_image (f, img, SDATA (data), SBYTES (data));
+    }
+
+  return success_p;
+}
+
+/* svg_load_image is a helper function for svg_load, which does the
+   actual loading given contents and size, apart from frame and image
+   structures, passed from svg_load.
+
+   Uses librsvg to do most of the image processing.
+
+   Returns non-zero when successful.  */
+static int
+svg_load_image (f, img, contents, size)
+    /* Pointer to emacs frame structure.  */
+     struct frame *f;
+     /* Pointer to emacs image structure.  */
+     struct image *img;
+     /* String containing the SVG XML data to be parsed.  */
+     unsigned char *contents;
+     /* Size of data in bytes.  */
+     unsigned int size;
+{
+  RsvgHandle *rsvg_handle;
+  GError *error = NULL;
+  GdkPixbuf *pixbuf;
+  int width;
+  int height;
+  const guint8 *pixels;
+  int rowstride;
+  XImagePtr ximg;
+  Lisp_Object specified_bg;
+  XColor background;
+  int x;
+  int y;
+
+  /* g_type_init is a glib function that must be called prior to using
+     gnome type library functions.  */
+  fn_g_type_init ();
+  /* Make a handle to a new rsvg object.  */
+  rsvg_handle = fn_rsvg_handle_new ();
+
+  /* Parse the contents argument and fill in the rsvg_handle.  */
+  fn_rsvg_handle_write (rsvg_handle, contents, size, &error);
+  if (error)
+    goto rsvg_error;
+
+  /* The parsing is complete, rsvg_handle is ready to used, close it
+     for further writes.  */
+  fn_rsvg_handle_close (rsvg_handle, &error);
+  if (error)
+    goto rsvg_error;
+  /* We can now get a valid pixel buffer from the svg file, if all
+     went ok.  */
+  pixbuf = fn_rsvg_handle_get_pixbuf (rsvg_handle);
+  eassert (pixbuf);
+
+  /* Extract some meta data from the svg handle.  */
+  width     = fn_gdk_pixbuf_get_width (pixbuf);
+  height    = fn_gdk_pixbuf_get_height (pixbuf);
+  pixels    = fn_gdk_pixbuf_get_pixels (pixbuf);
+  rowstride = fn_gdk_pixbuf_get_rowstride (pixbuf);
+
+  /* Validate the svg meta data.  */
+  eassert (fn_gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB);
+  eassert (fn_gdk_pixbuf_get_n_channels (pixbuf) == 4);
+  eassert (fn_gdk_pixbuf_get_has_alpha (pixbuf));
+  eassert (fn_gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);
+
+  /* Try to create a x pixmap to hold the svg pixmap.  */
+  if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
+    {
+      fn_g_object_unref (pixbuf);
+      return 0;
+    }
+
+  init_color_table ();
+
+  /* Handle alpha channel by combining the image with a background
+     color.  */
+  specified_bg = image_spec_value (img->spec, QCbackground, NULL);
+  if (STRINGP (specified_bg)
+      && x_defined_color (f, SDATA (specified_bg), &background, 0))
+    {
+      background.red   >>= 8;
+      background.green >>= 8;
+      background.blue  >>= 8;
+    }
+  else
+    {
+#ifdef HAVE_X_WINDOWS
+      background.pixel = FRAME_BACKGROUND_PIXEL (f);
+      x_query_color (f, &background);
+
+      /* SVG pixmaps specify transparency in the last byte, so right
+        shift 8 bits to get rid of it, since emacs doesn't support
+        transparency.  */
+      background.red   >>= 8;
+      background.green >>= 8;
+      background.blue  >>= 8;
+#elif defined (MAC_OS)
+      background.pixel = FRAME_BACKGROUND_PIXEL (f);
+      background.red   = RED_FROM_ULONG (background.pixel);
+      background.green = GREEN_FROM_ULONG (background.pixel);
+      background.blue  = BLUE_FROM_ULONG (background.pixel);
+#elif defined (HAVE_NTGUI)
+      background.pixel = FRAME_BACKGROUND_PIXEL (f);
+#if 0 /* W32 TODO : Colormap support.  */
+      x_query_color (f, &background);
+#endif
+
+      /* SVG pixmaps specify transparency in the last byte, so right
+        shift 8 bits to get rid of it, since emacs doesn't support
+        transparency.  */
+      background.red   >>= 8;
+      background.green >>= 8;
+      background.blue  >>= 8;
+#else /* not HAVE_X_WINDOWS && not MAC_OS*/
+#error FIXME
+#endif
+    }
+
+  /* This loop handles opacity values, since Emacs assumes
+     non-transparent images.  Each pixel must be "flattened" by
+     calculating the resulting color, given the transparency of the
+     pixel, and the image background color.  */
+  for (y = 0; y < height; ++y)
+    {
+      for (x = 0; x < width; ++x)
+       {
+         unsigned red;
+         unsigned green;
+         unsigned blue;
+         unsigned opacity;
+
+         red     = *pixels++;
+         green   = *pixels++;
+         blue    = *pixels++;
+         opacity = *pixels++;
+
+         red   = ((red * opacity)
+                  + (background.red * ((1 << 8) - opacity)));
+         green = ((green * opacity)
+                  + (background.green * ((1 << 8) - opacity)));
+         blue  = ((blue * opacity)
+                  + (background.blue * ((1 << 8) - opacity)));
+
+         XPutPixel (ximg, x, y, lookup_rgb_color (f, red, green, blue));
+       }
+
+      pixels += rowstride - 4 * width;
+    }
+
+#ifdef COLOR_TABLE_SUPPORT
+  /* Remember colors allocated for this image.  */
+  img->colors = colors_in_color_table (&img->ncolors);
+  free_color_table ();
+#endif /* COLOR_TABLE_SUPPORT */
+
+  fn_g_object_unref (pixbuf);
+
+  img->width  = width;
+  img->height = height;
+
+  /* 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);
+  x_destroy_x_image (ximg);
+
+  return 1;
+
+ rsvg_error:
+  /* FIXME: Use error->message so the user knows what is the actual
+     problem with the image.  */
+  image_error ("Error parsing SVG image `%s'", img->spec, Qnil);
+  fn_g_error_free (error);
+  return 0;
+}
+
+#endif /* defined (HAVE_RSVG) */
+
+
+
+\f
 /***********************************************************************
                                Ghostscript
  ***********************************************************************/
 /***********************************************************************
                                Ghostscript
  ***********************************************************************/
@@ -8502,6 +9016,11 @@ of `image-library-alist', which see).  */)
     return CHECK_LIB_AVAILABLE (&png_type, init_png_functions, libraries);
 #endif
 
     return CHECK_LIB_AVAILABLE (&png_type, init_png_functions, libraries);
 #endif
 
+#if defined (HAVE_RSVG)
+  if (EQ (type, Qsvg))
+    return CHECK_LIB_AVAILABLE (&svg_type, init_svg_functions, libraries);
+#endif
+
 #ifdef HAVE_GHOSTSCRIPT
   if (EQ (type, Qpostscript))
     return CHECK_LIB_AVAILABLE (&gs_type, init_gs_functions, libraries);
 #ifdef HAVE_GHOSTSCRIPT
   if (EQ (type, Qpostscript))
     return CHECK_LIB_AVAILABLE (&gs_type, init_gs_functions, libraries);
@@ -8526,7 +9045,7 @@ syms_of_image ()
      defining the supported image types.  */
   DEFVAR_LISP ("image-types", &Vimage_types,
     doc: /* List of potentially supported image types.
      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.
+Each element of the list is a symbol for an image type, like 'jpeg or 'png.
 To check whether it is really supported, use `image-type-available-p'.  */);
   Vimage_types = Qnil;
 
 To check whether it is really supported, use `image-type-available-p'.  */);
   Vimage_types = Qnil;
 
@@ -8540,7 +9059,7 @@ 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
 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.  */);
+listed; they are always supported.  */);
   Vimage_library_alist = Qnil;
   Fput (intern ("image-library-alist"), Qrisky_local_variable, Qt);
 
   Vimage_library_alist = Qnil;
   Fput (intern ("image-library-alist"), Qrisky_local_variable, Qt);
 
@@ -8561,11 +9080,11 @@ non-numeric, there is no explicit limit on the size of images.  */);
 
   Qpbm = intern ("pbm");
   staticpro (&Qpbm);
 
   Qpbm = intern ("pbm");
   staticpro (&Qpbm);
-  ADD_IMAGE_TYPE(Qpbm);
+  ADD_IMAGE_TYPE (Qpbm);
 
   Qxbm = intern ("xbm");
   staticpro (&Qxbm);
 
   Qxbm = intern ("xbm");
   staticpro (&Qxbm);
-  ADD_IMAGE_TYPE(Qxbm);
+  ADD_IMAGE_TYPE (Qxbm);
 
   define_image_type (&xbm_type, 1);
   define_image_type (&pbm_type, 1);
 
   define_image_type (&xbm_type, 1);
   define_image_type (&pbm_type, 1);
@@ -8603,7 +9122,7 @@ non-numeric, there is no explicit limit on the size of images.  */);
   Qpostscript = intern ("postscript");
   staticpro (&Qpostscript);
 #ifdef HAVE_GHOSTSCRIPT
   Qpostscript = intern ("postscript");
   staticpro (&Qpostscript);
 #ifdef HAVE_GHOSTSCRIPT
-  ADD_IMAGE_TYPE(Qpostscript);
+  ADD_IMAGE_TYPE (Qpostscript);
   QCloader = intern (":loader");
   staticpro (&QCloader);
   QCbounding_box = intern (":bounding-box");
   QCloader = intern (":loader");
   staticpro (&QCloader);
   QCbounding_box = intern (":bounding-box");
@@ -8617,35 +9136,48 @@ non-numeric, there is no explicit limit on the size of images.  */);
 #if defined (HAVE_XPM) || defined (MAC_OS)
   Qxpm = intern ("xpm");
   staticpro (&Qxpm);
 #if defined (HAVE_XPM) || defined (MAC_OS)
   Qxpm = intern ("xpm");
   staticpro (&Qxpm);
-  ADD_IMAGE_TYPE(Qxpm);
+  ADD_IMAGE_TYPE (Qxpm);
 #endif
 
 #if defined (HAVE_JPEG) || defined (MAC_OS)
   Qjpeg = intern ("jpeg");
   staticpro (&Qjpeg);
 #endif
 
 #if defined (HAVE_JPEG) || defined (MAC_OS)
   Qjpeg = intern ("jpeg");
   staticpro (&Qjpeg);
-  ADD_IMAGE_TYPE(Qjpeg);
+  ADD_IMAGE_TYPE (Qjpeg);
 #endif
 
 #if defined (HAVE_TIFF) || defined (MAC_OS)
   Qtiff = intern ("tiff");
   staticpro (&Qtiff);
 #endif
 
 #if defined (HAVE_TIFF) || defined (MAC_OS)
   Qtiff = intern ("tiff");
   staticpro (&Qtiff);
-  ADD_IMAGE_TYPE(Qtiff);
+  ADD_IMAGE_TYPE (Qtiff);
 #endif
 
 #if defined (HAVE_GIF) || defined (MAC_OS)
   Qgif = intern ("gif");
   staticpro (&Qgif);
 #endif
 
 #if defined (HAVE_GIF) || defined (MAC_OS)
   Qgif = intern ("gif");
   staticpro (&Qgif);
-  ADD_IMAGE_TYPE(Qgif);
+  ADD_IMAGE_TYPE (Qgif);
 #endif
 
 #if defined (HAVE_PNG) || defined (MAC_OS)
   Qpng = intern ("png");
   staticpro (&Qpng);
 #endif
 
 #if defined (HAVE_PNG) || defined (MAC_OS)
   Qpng = intern ("png");
   staticpro (&Qpng);
-  ADD_IMAGE_TYPE(Qpng);
+  ADD_IMAGE_TYPE (Qpng);
 #endif
 
 #endif
 
+#if defined (HAVE_RSVG)
+  Qsvg = intern ("svg");
+  staticpro (&Qsvg);
+  ADD_IMAGE_TYPE (Qsvg);
+#ifdef HAVE_NTGUI
+  Qgdk_pixbuf = intern ("gdk-pixbuf");
+  staticpro (&Qgdk_pixbuf);
+  Qglib = intern ("glib");
+  staticpro (&Qglib);
+#endif /* HAVE_NTGUI  */
+#endif /* HAVE_RSVG  */
+
   defsubr (&Sinit_image_library);
   defsubr (&Sclear_image_cache);
   defsubr (&Sinit_image_library);
   defsubr (&Sclear_image_cache);
+  defsubr (&Simage_refresh);
   defsubr (&Simage_size);
   defsubr (&Simage_mask_p);
   defsubr (&Simage_extension_data);
   defsubr (&Simage_size);
   defsubr (&Simage_mask_p);
   defsubr (&Simage_extension_data);
@@ -8657,7 +9189,7 @@ non-numeric, there is no explicit limit on the size of images.  */);
 
   DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
     doc: /* Non-nil means always draw a cross over disabled images.
 
   DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
     doc: /* Non-nil means always draw a cross over disabled images.
-Disabled images are those having an `:conversion disabled' property.
+Disabled images are those having a `:conversion disabled' property.
 A cross is always drawn on black & white displays.  */);
   cross_disabled_images = 0;
 
 A cross is always drawn on black & white displays.  */);
   cross_disabled_images = 0;