+/* 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_ ((struct frame *, XpmAttributes *));
+static void xpm_free_color_cache P_ ((void));
+static int xpm_lookup_color P_ ((struct frame *, char *, XColor *));
+static int xpm_color_bucket P_ ((char *));
+static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *,
+ XColor *, int));
+
+/* 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 (f, attrs)
+ struct frame *f;
+ XpmAttributes *attrs;
+{
+ 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 ();
+
+ if (attrs->valuemask & XpmColorSymbols)
+ {
+ int i;
+ XColor color;
+
+ for (i = 0; i < attrs->numsymbols; ++i)
+ if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
+ attrs->colorsymbols[i].value, &color))
+ {
+ color.pixel = lookup_rgb_color (f, color.red, color.green,
+ color.blue);
+ xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1);
+ }
+ }
+}
+
+
+/* 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 ();
+}
+
+
+/* Return the bucket index for color named COLOR_NAME in the color
+ cache. */
+
+static int
+xpm_color_bucket (color_name)
+ char *color_name;
+{
+ unsigned h = 0;
+ char *s;
+
+ for (s = color_name; *s; ++s)
+ h = (h << 2) ^ *s;
+ return h %= XPM_COLOR_CACHE_BUCKETS;
+}
+
+
+/* On frame F, cache values COLOR for color with name COLOR_NAME.
+ BUCKET, if >= 0, is a precomputed bucket index. Value is the cache
+ entry added. */
+
+static struct xpm_cached_color *
+xpm_cache_color (f, color_name, color, bucket)
+ struct frame *f;
+ char *color_name;
+ XColor *color;
+ int bucket;
+{
+ size_t nbytes;
+ struct xpm_cached_color *p;
+
+ if (bucket < 0)
+ bucket = xpm_color_bucket (color_name);
+
+ 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[bucket];
+ xpm_color_cache[bucket] = p;
+ return p;
+}
+
+
+/* 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;
+{
+ struct xpm_cached_color *p;
+ int h = xpm_color_bucket (color_name);
+
+ 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))
+ {
+ color->pixel = lookup_rgb_color (f, color->red, color->green,
+ color->blue);
+ p = xpm_cache_color (f, color_name, color, h);
+ }
+
+ 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 */
+
+