changeset 31637:c1f4bdbf8465

(ALLOC_XPM_COLORS): Define if we can use Emacs' color allocation functions with the XPM lib. (struct xpm_cached_color) [ALLOC_XPM_COLORS]: New structure. (XPM_COLOR_CACHE_BUCKETS) [ALLOC_XPM_COLORS]: New macro. (xpm_color_cache) [ALLOC_XPM_COLORS]: New variable. (xpm_init_color_cache, xpm_free_color_cache, xpm_lookup_color) (xpm_alloc_color, xpm_free_colors) [ALLOC_XPM_COLORS]: New functions. (xpm_load) [ALLOC_XPM_COLORS]: Use Emacs' own color allocation functions, if possible, because these handle color allocation failure more gracefully. (Fimage_mask_p): New function.
author Gerd Moellmann <gerd@gnu.org>
date Fri, 15 Sep 2000 15:19:03 +0000
parents 3ff1515f7c7a
children 77a8522f11d4
files src/xfns.c
diffstat 1 files changed, 213 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/src/xfns.c	Fri Sep 15 11:49:22 2000 +0000
+++ b/src/xfns.c	Fri Sep 15 15:19:03 2000 +0000
@@ -781,6 +781,13 @@
 static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
 static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
 				  Lisp_Object));
+static void init_color_table P_ ((void));
+static void free_color_table P_ ((void));
+static unsigned long *colors_in_color_table P_ ((int *n));
+static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
+static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
+
+
 
 static struct x_frame_parm_table x_frame_parms[] =
 {
@@ -3833,7 +3840,7 @@
   UNBLOCK_INPUT;
 }
 
-/* Make the GC's needed for this window, setting the
+/* Make the GCs needed for this window, setting the
    background, border and mouse colors; also create the
    mouse cursor and the gray border tile.  */
 
@@ -3853,7 +3860,7 @@
 
   BLOCK_INPUT;
 
-  /* Create the GC's of this frame.
+  /* Create the GCs of this frame.
      Note that many default values are used.  */
 
   /* Normal video */
@@ -5369,6 +5376,31 @@
 }
 
 
+DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
+  "Return t if image SPEC has a mask bitmap.\n\
+FRAME is the frame on which the image will be displayed.  FRAME nil\n\
+or omitted means use the selected frame.")
+  (spec, frame)
+     Lisp_Object spec, frame;
+{
+  Lisp_Object mask;
+
+  mask = 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);
+      if (img->mask)
+	mask = Qt;
+    }
+  else
+    error ("Invalid image specification");
+
+  return mask;
+}
+
+
 
 /***********************************************************************
 		 Image type independent image structures
@@ -5776,7 +5808,7 @@
 			means build a mask heuristically.
 		 `:heuristic-mask (R G B)'
 		 `:mask (heuristic (R G B))'
-			measn build a mask from color (R G B) in the
+			means build a mask from color (R G B) in the
 			image.
 		 `:mask nil'
 			means remove a mask, if any.  */
@@ -6018,7 +6050,7 @@
 
 /* Read FILE into memory.  Value is a pointer to a buffer allocated
    with xmalloc holding FILE's contents.  Value is null if an error
-   occured.  *SIZE is set to the size of the file.  */
+   occurred.  *SIZE is set to the size of the file.  */
 
 static char *
 slurp_file (file, size)
@@ -6329,7 +6361,7 @@
    buffer's end.  Set *WIDTH and *HEIGHT to the width and height of
    the image.  Return in *DATA the bitmap data allocated with xmalloc.
    Value is non-zero if successful.  DATA null means just test if
-   CONTENTS looks like an im-memory XBM file.  */
+   CONTENTS looks like an in-memory XBM file.  */
 
 static int
 xbm_read_bitmap_data (contents, end, width, height, data)
@@ -6747,6 +6779,156 @@
 };
 
 
+/* Define ALLOC_XPM_COLORS if we can use Emacs' own color allocation
+   functions for allocating image colors.  Our own functions handle
+   color allocation failures more gracefully than the ones on the XPM
+   lib.  */
+
+#if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure
+#define ALLOC_XPM_COLORS
+#endif
+
+#ifdef ALLOC_XPM_COLORS
+
+static void xpm_init_color_cache P_ ((void));
+static void xpm_free_color_cache P_ ((void));
+static int xpm_lookup_color P_ ((struct frame *, char *, XColor *));
+
+/* An entry in a hash table used to cache color definitions of named
+   colors.  This cache is necessary to speed up XPM image loading in
+   case we do color allocations ourselves.  Without it, we would need
+   a call to XParseColor per pixel in the image.  */
+
+struct xpm_cached_color
+{
+  /* Next in collision chain.  */
+  struct xpm_cached_color *next;
+
+  /* Color definition (RGB and pixel color).  */
+  XColor color;
+
+  /* Color name.  */
+  char name[1];
+};
+
+/* The hash table used for the color cache, and its bucket vector
+   size.  */
+
+#define XPM_COLOR_CACHE_BUCKETS	1001
+struct xpm_cached_color **xpm_color_cache;
+
+
+/* Initialize the color cache.  */
+
+static void
+xpm_init_color_cache ()
+{
+  size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache;
+  xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes);
+  memset (xpm_color_cache, 0, nbytes);
+  init_color_table ();
+}
+
+
+/* Free the color cache.  */
+
+static void
+xpm_free_color_cache ()
+{
+  struct xpm_cached_color *p, *next;
+  int i;
+
+  for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i)
+    for (p = xpm_color_cache[i]; p; p = next)
+      {
+	next = p->next;
+	xfree (p);
+      }
+
+  xfree (xpm_color_cache);
+  xpm_color_cache = NULL;
+  free_color_table ();
+}
+
+
+/* Look up color COLOR_NAME for frame F in the color cache.  If found,
+   return the cached definition in *COLOR.  Otherwise, make a new
+   entry in the cache and allocate the color.  Value is zero if color
+   allocation failed.  */
+
+static int
+xpm_lookup_color (f, color_name, color)
+     struct frame *f;
+     char *color_name;
+     XColor *color;
+{
+  unsigned h = 0;
+  const char *s;
+  struct xpm_cached_color *p;
+
+  for (s = color_name; *s; ++s)
+    h = (h << 2) ^ *s;
+  h %= XPM_COLOR_CACHE_BUCKETS;
+
+  for (p = xpm_color_cache[h]; p; p = p->next)
+    if (strcmp (p->name, color_name) == 0)
+      break;
+
+  if (p != NULL)
+    *color = p->color;
+  else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
+			color_name, color))
+    {
+      size_t nbytes;
+      color->pixel = lookup_rgb_color (f, color->red, color->green,
+				       color->blue);
+      nbytes = sizeof *p + strlen (color_name);
+      p = (struct xpm_cached_color *) xmalloc (nbytes);
+      strcpy (p->name, color_name);
+      p->color = *color;
+      p->next = xpm_color_cache[h];
+      xpm_color_cache[h] = p;
+    }
+
+  return p != NULL;
+}
+
+
+/* Callback for allocating color COLOR_NAME.  Called from the XPM lib.
+   CLOSURE is a pointer to the frame on which we allocate the
+   color.  Return in *COLOR the allocated color.  Value is non-zero
+   if successful.  */
+
+static int
+xpm_alloc_color (dpy, cmap, color_name, color, closure)
+     Display *dpy;
+     Colormap cmap;
+     char *color_name;
+     XColor *color;
+     void *closure;
+{
+  return xpm_lookup_color ((struct frame *) closure, color_name, color);
+}
+
+
+/* Callback for freeing NPIXELS colors contained in PIXELS.  CLOSURE
+   is a pointer to the frame on which we allocate the color.  Value is
+   non-zero if successful.  */
+
+static int
+xpm_free_colors (dpy, cmap, pixels, npixels, closure)
+     Display *dpy;
+     Colormap cmap;
+     Pixel *pixels;
+     int npixels;
+     void *closure;
+{
+  return 1;
+}
+
+#endif /* ALLOC_XPM_COLORS */
+
+
 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
    for XPM images.  Such a list must consist of conses whose car and
    cdr are strings.  */
@@ -6806,14 +6988,25 @@
   attrs.colormap = FRAME_X_COLORMAP (f);
   attrs.valuemask |= XpmVisual;
   attrs.valuemask |= XpmColormap;
+
+#ifdef ALLOC_XPM_COLORS
+  /* Allocate colors with our own functions which handle
+     failing color allocation more gracefully.  */
+  attrs.color_closure = f;
+  attrs.alloc_color = xpm_alloc_color;
+  attrs.free_colors = xpm_free_colors;
+  attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure;
+#else /* not ALLOC_XPM_COLORS */
+  /* Let the XPM lib allocate colors.  */
   attrs.valuemask |= XpmReturnAllocPixels;
 #ifdef XpmAllocCloseColors
   attrs.alloc_close_colors = 1;
   attrs.valuemask |= XpmAllocCloseColors;
-#else
+#else /* not XpmAllocCloseColors */
   attrs.closeness = 600;
   attrs.valuemask |= XpmCloseness;
-#endif
+#endif /* not XpmAllocCloseColors */
+#endif /* ALLOC_XPM_COLORS */
 
   /* If image specification contains symbolic color definitions, add
      these to `attrs'.  */
@@ -6854,6 +7047,11 @@
   /* Create a pixmap for the image, either from a file, or from a
      string buffer containing data in the same format as an XPM file.  */
   BLOCK_INPUT;
+
+#ifdef ALLOC_XPM_COLORS
+  xpm_init_color_cache ();
+#endif
+  
   specified_file = image_spec_value (img->spec, QCfile, NULL);
   if (STRINGP (specified_file))
     {
@@ -6881,7 +7079,9 @@
 
   if (rc == XpmSuccess)
     {
-      /* Remember allocated colors.  */
+#ifdef ALLOC_XPM_COLORS
+      img->colors = colors_in_color_table (&img->ncolors);
+#else /* not ALLOC_XPM_COLORS */
       img->ncolors = attrs.nalloc_pixels;
       img->colors = (unsigned long *) xmalloc (img->ncolors
 					       * sizeof *img->colors);
@@ -6892,6 +7092,7 @@
 	  register_color (img->colors[i]);
 #endif
 	}
+#endif /* not ALLOC_XPM_COLORS */
 
       img->width = attrs.width;
       img->height = attrs.height;
@@ -6928,6 +7129,9 @@
 	}
     }
 
+#ifdef ALLOC_XPM_COLORS
+  xpm_free_color_cache ();
+#endif
   return rc == XpmSuccess;
 }
 
@@ -6965,15 +7169,6 @@
 
 int ct_colors_allocated;
 
-/* Function prototypes.  */
-
-static void init_color_table P_ ((void));
-static void free_color_table P_ ((void));
-static unsigned long *colors_in_color_table P_ ((int *n));
-static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
-static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
-
-
 /* Initialize the color table.  */
 
 static void
@@ -10855,6 +11050,7 @@
 
   defsubr (&Sclear_image_cache);
   defsubr (&Simage_size);
+  defsubr (&Simage_mask_p);
 
   busy_cursor_atimer = NULL;
   busy_cursor_shown_p = 0;