/* 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, 2008, 2009, 2010, 2011, 2012
- Free Software Foundation, Inc.
+
+Copyright (C) 1989, 1992-2012 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include <config.h>
#include <stdio.h>
-#include <math.h>
-#include <ctype.h>
-
-#ifdef HAVE_UNISTD_H
#include <unistd.h>
-#endif
#ifdef HAVE_PNG
#if defined HAVE_LIBPNG_PNG_H
#include <setjmp.h>
+#include <c-ctype.h>
+
/* This makes the fields of a Display accessible, in Xlib header files. */
#define XLIB_ILLEGAL_ACCESS
#include "termhooks.h"
#include "font.h"
-#ifdef HAVE_X_WINDOWS
-#include "xterm.h"
-#include <sys/types.h>
+#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
+#endif /* HAVE_SYS_STAT_H */
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+#ifdef HAVE_WINDOW_SYSTEM
+#include TERM_HEADER
+#endif /* HAVE_WINDOW_SYSTEM */
+
+#ifdef HAVE_X_WINDOWS
#define COLOR_TABLE_SUPPORT 1
typedef struct x_bitmap_record Bitmap_Record;
-#define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y)
+#define GET_PIXEL(ximg, x, y) XGetPixel (ximg, x, y)
#define NO_PIXMAP None
#define RGB_PIXEL_COLOR unsigned long
#define PIX_MASK_DRAW 1
#endif /* HAVE_X_WINDOWS */
-
#ifdef HAVE_NTGUI
-#include "w32term.h"
-
+#include "w32.h"
/* W32_TODO : Color tables on W32. */
#undef COLOR_TABLE_SUPPORT
typedef struct w32_bitmap_record Bitmap_Record;
-#define GET_PIXEL(ximg, x, y) GetPixel(ximg, x, y)
+#define GET_PIXEL(ximg, x, y) GetPixel (ximg, x, y)
#define NO_PIXMAP 0
#define RGB_PIXEL_COLOR COLORREF
#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
#define DefaultDepthOfScreen(screen) (one_w32_display_info.n_cbits)
-/* Functions from w32term.c that depend on XColor (so can't go in w32term.h
- without modifying lots of files). */
-extern void x_query_colors (struct frame *f, XColor *colors, int ncolors);
-extern void x_query_color (struct frame *f, XColor *color);
-
/* Version of libpng that we were compiled with, or -1 if no PNG
support was compiled in. This is tested by w32-win.el to correctly
set up the alist used to search for PNG libraries. */
#endif /* HAVE_NTGUI */
#ifdef HAVE_NS
-#include "nsterm.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-
#undef COLOR_TABLE_SUPPORT
typedef struct ns_bitmap_record Bitmap_Record;
-#define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y)
+#define GET_PIXEL(ximg, x, y) XGetPixel (ximg, x, y)
#define NO_PIXMAP 0
#define RGB_PIXEL_COLOR unsigned long
#define PIX_MASK_RETAIN 0
#define PIX_MASK_DRAW 1
-#define FRAME_X_VISUAL FRAME_NS_DISPLAY_INFO(f)->visual
#define x_defined_color(f, name, color_def, alloc) \
ns_defined_color (f, name, color_def, alloc, 0)
-#define FRAME_X_SCREEN(f) 0
#define DefaultDepthOfScreen(screen) x_display_list->n_planes
#endif /* HAVE_NS */
-/* Search path for bitmap files. */
-
-Lisp_Object Vx_bitmap_file_path;
+/* The symbol `postscript' identifying images of this type. */
+static Lisp_Object Qpostscript;
-static void x_disable_image P_ ((struct frame *, struct image *));
-static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
- Lisp_Object));
+static void x_disable_image (struct frame *, struct image *);
+static void x_edge_detection (struct frame *, struct image *, Lisp_Object,
+ Lisp_Object);
-static void init_color_table P_ ((void));
-static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
+static void init_color_table (void);
+static unsigned long lookup_rgb_color (struct frame *f, int r, int g, int b);
#ifdef COLOR_TABLE_SUPPORT
-static void free_color_table P_ ((void));
-static unsigned long *colors_in_color_table P_ ((int *n));
-static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
+static void free_color_table (void);
+static unsigned long *colors_in_color_table (int *n);
#endif
/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
unsigned long plane_mask, int format)
{
/* TODO: not sure what this function is supposed to do.. */
- ns_retain_object(pixmap);
+ ns_retain_object (pixmap);
return pixmap;
}
unsigned long
XGetPixel (XImagePtr ximage, int x, int y)
{
- return ns_get_pixel(ximage, x, y);
+ return ns_get_pixel (ximage, x, y);
}
/* use with imgs created by ns_image_for_XPM; alpha set to 1;
void
XPutPixel (XImagePtr ximage, int x, int y, unsigned long pixel)
{
- ns_put_pixel(ximage, x, y, pixel);
+ ns_put_pixel (ximage, x, y, pixel);
}
#endif /* HAVE_NS */
/* Functions to access the contents of a bitmap, given an id. */
int
-x_bitmap_height (f, id)
- FRAME_PTR f;
- int id;
+x_bitmap_height (FRAME_PTR f, ptrdiff_t id)
{
return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height;
}
int
-x_bitmap_width (f, id)
- FRAME_PTR f;
- int id;
+x_bitmap_width (FRAME_PTR f, ptrdiff_t id)
{
return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width;
}
#if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
int
-x_bitmap_pixmap (f, id)
- FRAME_PTR f;
- int id;
+x_bitmap_pixmap (FRAME_PTR f, ptrdiff_t id)
{
+ /* HAVE_NTGUI needs the explicit cast here. */
return (int) FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
}
#endif
#ifdef HAVE_X_WINDOWS
int
-x_bitmap_mask (f, id)
- FRAME_PTR f;
- int id;
+x_bitmap_mask (FRAME_PTR f, ptrdiff_t id)
{
return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].mask;
}
/* Allocate a new bitmap record. Returns index of new record. */
-static int
-x_allocate_bitmap_record (f)
- FRAME_PTR f;
+static ptrdiff_t
+x_allocate_bitmap_record (FRAME_PTR f)
{
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
- int i;
-
- if (dpyinfo->bitmaps == NULL)
- {
- dpyinfo->bitmaps_size = 10;
- dpyinfo->bitmaps
- = (Bitmap_Record *) xmalloc (dpyinfo->bitmaps_size * sizeof (Bitmap_Record));
- dpyinfo->bitmaps_last = 1;
- return 1;
- }
+ ptrdiff_t i;
if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
return ++dpyinfo->bitmaps_last;
if (dpyinfo->bitmaps[i].refcount == 0)
return i + 1;
- dpyinfo->bitmaps_size *= 2;
- dpyinfo->bitmaps
- = (Bitmap_Record *) xrealloc (dpyinfo->bitmaps,
- dpyinfo->bitmaps_size * sizeof (Bitmap_Record));
+ dpyinfo->bitmaps =
+ xpalloc (dpyinfo->bitmaps, &dpyinfo->bitmaps_size,
+ 10, -1, sizeof *dpyinfo->bitmaps);
return ++dpyinfo->bitmaps_last;
}
/* Add one reference to the reference count of the bitmap with id ID. */
void
-x_reference_bitmap (f, id)
- FRAME_PTR f;
- int id;
+x_reference_bitmap (FRAME_PTR f, ptrdiff_t id)
{
++FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
}
/* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
-int
-x_create_bitmap_from_data (f, bits, width, height)
- struct frame *f;
- char *bits;
- unsigned int width, height;
+ptrdiff_t
+x_create_bitmap_from_data (struct frame *f, char *bits, unsigned int width, unsigned int height)
{
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
- int id;
+ ptrdiff_t id;
#ifdef HAVE_X_WINDOWS
Pixmap bitmap;
#endif /* HAVE_NTGUI */
#ifdef HAVE_NS
- void *bitmap = ns_image_from_XBM(bits, width, height);
+ void *bitmap = ns_image_from_XBM (bits, width, height);
if (!bitmap)
return -1;
#endif
/* Create bitmap from file FILE for frame F. */
-int
-x_create_bitmap_from_file (f, file)
- struct frame *f;
- Lisp_Object file;
+ptrdiff_t
+x_create_bitmap_from_file (struct frame *f, Lisp_Object file)
{
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
#endif /* HAVE_NTGUI */
#ifdef HAVE_NS
- int id;
- void *bitmap = ns_image_from_file(file);
+ ptrdiff_t id;
+ void *bitmap = ns_image_from_file (file);
if (!bitmap)
return -1;
id = x_allocate_bitmap_record (f);
dpyinfo->bitmaps[id - 1].img = bitmap;
dpyinfo->bitmaps[id - 1].refcount = 1;
- dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (SBYTES (file) + 1);
+ dpyinfo->bitmaps[id - 1].file = xmalloc (SBYTES (file) + 1);
dpyinfo->bitmaps[id - 1].depth = 1;
- dpyinfo->bitmaps[id - 1].height = ns_image_width(bitmap);
- dpyinfo->bitmaps[id - 1].width = ns_image_height(bitmap);
- strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file));
+ dpyinfo->bitmaps[id - 1].height = ns_image_width (bitmap);
+ dpyinfo->bitmaps[id - 1].width = ns_image_height (bitmap);
+ strcpy (dpyinfo->bitmaps[id - 1].file, SSDATA (file));
return id;
#endif
#ifdef HAVE_X_WINDOWS
unsigned int width, height;
Pixmap bitmap;
- int xhot, yhot, result, id;
+ int xhot, yhot, result;
+ ptrdiff_t id;
Lisp_Object found;
int fd;
char *filename;
{
if (dpyinfo->bitmaps[id].refcount
&& dpyinfo->bitmaps[id].file
- && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file)))
+ && !strcmp (dpyinfo->bitmaps[id].file, SSDATA (file)))
{
++dpyinfo->bitmaps[id].refcount;
return id + 1;
return -1;
emacs_close (fd);
- filename = (char *) SDATA (found);
+ filename = SSDATA (found);
result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
filename, &width, &height, &bitmap, &xhot, &yhot);
dpyinfo->bitmaps[id - 1].pixmap = bitmap;
dpyinfo->bitmaps[id - 1].have_mask = 0;
dpyinfo->bitmaps[id - 1].refcount = 1;
- dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (SBYTES (file) + 1);
+ dpyinfo->bitmaps[id - 1].file = xmalloc (SBYTES (file) + 1);
dpyinfo->bitmaps[id - 1].depth = 1;
dpyinfo->bitmaps[id - 1].height = height;
dpyinfo->bitmaps[id - 1].width = width;
- strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file));
+ strcpy (dpyinfo->bitmaps[id - 1].file, SSDATA (file));
return id;
#endif /* HAVE_X_WINDOWS */
/* Free bitmap B. */
static void
-free_bitmap_record (dpyinfo, bm)
- Display_Info *dpyinfo;
- Bitmap_Record *bm;
+free_bitmap_record (Display_Info *dpyinfo, Bitmap_Record *bm)
{
#ifdef HAVE_X_WINDOWS
XFreePixmap (dpyinfo->display, bm->pixmap);
#endif /* HAVE_NTGUI */
#ifdef HAVE_NS
- ns_release_object(bm->img);
+ ns_release_object (bm->img);
#endif
if (bm->file)
/* Remove reference to bitmap with id number ID. */
void
-x_destroy_bitmap (f, id)
- FRAME_PTR f;
- int id;
+x_destroy_bitmap (FRAME_PTR f, ptrdiff_t id)
{
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
if (--bm->refcount == 0)
{
- BLOCK_INPUT;
+ block_input ();
free_bitmap_record (dpyinfo, bm);
- UNBLOCK_INPUT;
+ unblock_input ();
}
}
}
/* Free all the bitmaps for the display specified by DPYINFO. */
void
-x_destroy_all_bitmaps (dpyinfo)
- Display_Info *dpyinfo;
+x_destroy_all_bitmaps (Display_Info *dpyinfo)
{
- int i;
+ ptrdiff_t i;
Bitmap_Record *bm = dpyinfo->bitmaps;
for (i = 0; i < dpyinfo->bitmaps_last; i++, bm++)
/* Useful functions defined in the section
`Image type independent image structures' below. */
-static unsigned long four_corners_best P_ ((XImagePtr ximg,
- int *corners,
- unsigned long width,
- unsigned long height));
+static unsigned long four_corners_best (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,
- int depth, XImagePtr *ximg,
- Pixmap *pixmap));
+static int x_create_x_image_and_pixmap (struct frame *f, int width, int height,
+ int depth, XImagePtr *ximg,
+ Pixmap *pixmap);
-static void x_destroy_x_image P_ ((XImagePtr ximg));
+static void x_destroy_x_image (XImagePtr ximg);
/* Create a mask of a bitmap. Note is this not a perfect mask.
It's nicer with some borders in this context */
int
-x_create_bitmap_mask (f, id)
- struct frame *f;
- int id;
+x_create_bitmap_mask (struct frame *f, ptrdiff_t id)
{
Pixmap pixmap, mask;
XImagePtr ximg, mask_img;
width = x_bitmap_width (f, id);
height = x_bitmap_height (f, id);
- BLOCK_INPUT;
+ block_input ();
ximg = XGetImage (FRAME_X_DISPLAY (f), pixmap, 0, 0, width, height,
~0, ZPixmap);
if (!ximg)
{
- UNBLOCK_INPUT;
+ unblock_input ();
return -1;
}
result = x_create_x_image_and_pixmap (f, width, height, 1, &mask_img, &mask);
- UNBLOCK_INPUT;
+ unblock_input ();
if (!result)
{
XDestroyImage (ximg);
}
}
- xassert (interrupt_input_blocked);
+ eassert (input_blocked_p ());
gc = XCreateGC (FRAME_X_DISPLAY (f), mask, 0, NULL);
XPutImage (FRAME_X_DISPLAY (f), mask, gc, mask_img, 0, 0, 0, 0,
width, height);
Image types
***********************************************************************/
-/* Value is the number of elements of vector VECTOR. */
-
-#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
-
/* List of supported image types. Use define_image_type to add new
types. Use lookup_image_type to find a type for a given symbol. */
static struct image_type *image_types;
-/* A list of symbols, one for each supported image type. */
-
-Lisp_Object Vimage_types;
-
-/* An alist of image types and libraries that implement the type. */
-
-Lisp_Object Vimage_library_alist;
-
-/* Cache for delayed-loading image types. */
-
-static Lisp_Object Vimage_type_cache;
-
/* The symbol `xbm' which is used as the type symbol for XBM images. */
-Lisp_Object Qxbm;
+static Lisp_Object Qxbm;
/* Keywords. */
-extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
-extern Lisp_Object QCdata, QCtype;
-extern Lisp_Object Qcenter;
-Lisp_Object QCascent, QCmargin, QCrelief, Qcount;
-Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
-Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
+Lisp_Object QCascent, QCmargin, QCrelief;
+Lisp_Object QCconversion;
+static Lisp_Object QCheuristic_mask;
+static Lisp_Object QCcolor_symbols;
+static Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask, QCgeometry;
+static Lisp_Object QCcrop, QCrotation;
/* Other symbols. */
-Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
-
-/* Time in seconds after which images should be removed from the cache
- if not displayed. */
-
-Lisp_Object Vimage_cache_eviction_delay;
+static Lisp_Object Qcount, Qextension_data, Qdelay;
+static Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
/* Function prototypes. */
-static Lisp_Object define_image_type P_ ((struct image_type *type, int loaded));
-static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
-static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
-static void x_laplace P_ ((struct frame *, struct image *));
-static void x_emboss P_ ((struct frame *, struct image *));
-static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
- Lisp_Object));
-
+static struct image_type *define_image_type (struct image_type *);
+static struct image_type *lookup_image_type (Lisp_Object);
+static void image_error (const char *format, Lisp_Object, Lisp_Object);
+static void x_laplace (struct frame *, struct image *);
+static void x_emboss (struct frame *, struct image *);
+static int x_build_heuristic_mask (struct frame *, struct image *,
+ Lisp_Object);
+#ifdef HAVE_NTGUI
#define CACHE_IMAGE_TYPE(type, status) \
- do { Vimage_type_cache = Fcons (Fcons (type, status), Vimage_type_cache); } while (0)
+ do { Vlibrary_cache = Fcons (Fcons (type, status), Vlibrary_cache); } while (0)
+#else
+#define CACHE_IMAGE_TYPE(type, status)
+#endif
#define ADD_IMAGE_TYPE(type) \
do { Vimage_types = Fcons (type, Vimage_types); } while (0)
/* Define a new image type from TYPE. This adds a copy of TYPE to
image_types and caches the loading status of TYPE. */
-static Lisp_Object
-define_image_type (type, loaded)
- struct image_type *type;
- int loaded;
+static struct image_type *
+define_image_type (struct image_type *type)
{
- Lisp_Object success;
+ struct image_type *p = NULL;
+ Lisp_Object target_type = *type->type;
+ int type_valid = 1;
- if (!loaded)
- success = Qnil;
- else
+ block_input ();
+
+ for (p = image_types; p; p = p->next)
+ if (EQ (*p->type, target_type))
+ goto done;
+
+ if (type->init)
+ {
+#ifdef HAVE_NTGUI
+ /* If we failed to load the library before, don't try again. */
+ Lisp_Object tested = Fassq (target_type, Vlibrary_cache);
+ if (CONSP (tested) && NILP (XCDR (tested)))
+ type_valid = 0;
+ else
+#endif
+ {
+ type_valid = type->init ();
+ CACHE_IMAGE_TYPE (target_type, type_valid ? Qt : Qnil);
+ }
+ }
+
+ if (type_valid)
{
/* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
The initialized data segment is read-only. */
- struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
- bcopy (type, p, sizeof *p);
+ p = xmalloc (sizeof *p);
+ *p = *type;
p->next = image_types;
image_types = p;
- success = Qt;
}
- CACHE_IMAGE_TYPE (*type->type, success);
- return success;
-}
-
-
-/* Look up image type SYMBOL, and return a pointer to its image_type
- structure. Value is null if SYMBOL is not a known image type. */
-
-static INLINE struct image_type *
-lookup_image_type (symbol)
- Lisp_Object symbol;
-{
- struct image_type *type;
-
- /* We must initialize the image-type if it hasn't been already. */
- if (NILP (Finit_image_library (symbol, Vimage_library_alist)))
- return 0; /* unimplemented */
-
- for (type = image_types; type; type = type->next)
- if (EQ (symbol, *type->type))
- break;
-
- return type;
+ done:
+ unblock_input ();
+ return p;
}
image type. */
int
-valid_image_p (object)
- Lisp_Object object;
+valid_image_p (Lisp_Object object)
{
int valid_p = 0;
therefore simply displays a message. */
static void
-image_error (format, arg1, arg2)
- char *format;
- Lisp_Object arg1, arg2;
+image_error (const char *format, Lisp_Object arg1, Lisp_Object arg2)
{
add_to_log (format, arg1, arg2);
}
IMAGE_STRING_OR_NIL_VALUE,
IMAGE_SYMBOL_VALUE,
IMAGE_POSITIVE_INTEGER_VALUE,
- IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
+ IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR,
IMAGE_NON_NEGATIVE_INTEGER_VALUE,
IMAGE_ASCENT_VALUE,
IMAGE_INTEGER_VALUE,
struct image_keyword
{
/* Name of keyword. */
- char *name;
+ const char *name;
/* The type of value allowed. */
enum image_value_type type;
};
-static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
- int, Lisp_Object));
-static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
+static int parse_image_spec (Lisp_Object, struct image_keyword *,
+ int, Lisp_Object);
+static Lisp_Object image_spec_value (Lisp_Object, Lisp_Object, int *);
/* Parse image spec SPEC according to KEYWORDS. A valid image spec
allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
static int
-parse_image_spec (spec, keywords, nkeywords, type)
- Lisp_Object spec;
- struct image_keyword *keywords;
- int nkeywords;
- Lisp_Object type;
+parse_image_spec (Lisp_Object spec, struct image_keyword *keywords,
+ int nkeywords, Lisp_Object type)
{
int i;
Lisp_Object plist;
/* Find key in KEYWORDS. Error if not found. */
for (i = 0; i < nkeywords; ++i)
- if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0)
+ if (strcmp (keywords[i].name, SSDATA (SYMBOL_NAME (key))) == 0)
break;
if (i == nkeywords)
/* Record that we recognized the keyword. If a keywords
was found more than once, it's an error. */
keywords[i].value = value;
- ++keywords[i].count;
-
if (keywords[i].count > 1)
return 0;
+ ++keywords[i].count;
/* Check type of value against allowed type. */
switch (keywords[i].type)
break;
case IMAGE_POSITIVE_INTEGER_VALUE:
- if (!INTEGERP (value) || XINT (value) <= 0)
+ if (! RANGED_INTEGERP (1, value, INT_MAX))
return 0;
break;
- case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
- if (INTEGERP (value) && XINT (value) >= 0)
+ case IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR:
+ if (RANGED_INTEGERP (0, value, INT_MAX))
break;
if (CONSP (value)
- && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
- && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
+ && RANGED_INTEGERP (0, XCAR (value), INT_MAX)
+ && RANGED_INTEGERP (0, XCDR (value), INT_MAX))
break;
return 0;
case IMAGE_ASCENT_VALUE:
if (SYMBOLP (value) && EQ (value, Qcenter))
break;
- else if (INTEGERP (value)
- && XINT (value) >= 0
- && XINT (value) <= 100)
+ else if (RANGED_INTEGERP (0, value, 100))
break;
return 0;
case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
+ /* Unlike the other integer-related cases, this one does not
+ verify that VALUE fits in 'int'. This is because callers
+ want EMACS_INT. */
if (!INTEGERP (value) || XINT (value) < 0)
return 0;
break;
case IMAGE_FUNCTION_VALUE:
value = indirect_function (value);
- if (SUBRP (value)
- || COMPILEDP (value)
- || (CONSP (value) && EQ (XCAR (value), Qlambda)))
+ if (!NILP (Ffunctionp (value)))
break;
return 0;
break;
case IMAGE_INTEGER_VALUE:
- if (!INTEGERP (value))
+ if (! TYPE_RANGED_INTEGERP (int, value))
return 0;
break;
break;
default:
- abort ();
+ emacs_abort ();
break;
}
to 1 if KEY was found in SPEC, set it to 0 otherwise. */
static Lisp_Object
-image_spec_value (spec, key, found)
- Lisp_Object spec, key;
- int *found;
+image_spec_value (Lisp_Object spec, Lisp_Object key, int *found)
{
Lisp_Object tail;
- xassert (valid_image_p (spec));
+ eassert (valid_image_p (spec));
for (tail = XCDR (spec);
CONSP (tail) && CONSP (XCDR (tail));
size in canonical character units.
FRAME is the frame on which the image will be displayed. FRAME nil
or omitted means use the selected frame. */)
- (spec, pixels, frame)
- Lisp_Object spec, pixels, frame;
+ (Lisp_Object spec, Lisp_Object pixels, Lisp_Object frame)
{
Lisp_Object size;
if (valid_image_p (spec))
{
struct frame *f = check_x_frame (frame);
- int id = lookup_image (f, spec);
+ ptrdiff_t id = lookup_image (f, spec);
struct image *img = IMAGE_FROM_ID (f, id);
int width = img->width + 2 * img->hmargin;
int height = img->height + 2 * img->vmargin;
doc: /* Return t if image SPEC has a mask bitmap.
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 spec, Lisp_Object frame)
{
Lisp_Object mask;
if (valid_image_p (spec))
{
struct frame *f = check_x_frame (frame);
- int id = lookup_image (f, spec);
+ ptrdiff_t id = lookup_image (f, spec);
struct image *img = IMAGE_FROM_ID (f, id);
if (img->mask)
mask = Qt;
return mask;
}
-DEFUN ("image-extension-data", Fimage_extension_data, Simage_extension_data, 1, 2, 0,
- doc: /* Return extension data for image SPEC.
+DEFUN ("image-metadata", Fimage_metadata, Simage_metadata, 1, 2, 0,
+ doc: /* Return metadata 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 spec, Lisp_Object frame)
{
Lisp_Object ext;
if (valid_image_p (spec))
{
struct frame *f = check_x_frame (frame);
- int id = lookup_image (f, spec);
+ ptrdiff_t id = lookup_image (f, spec);
struct image *img = IMAGE_FROM_ID (f, id);
- ext = img->data.lisp_val;
+ ext = img->lisp_data;
}
return ext;
Image type independent image structures
***********************************************************************/
-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;
+static void free_image (struct frame *f, struct image *img);
+#define MAX_IMAGE_SIZE 10.0
/* Allocate and return a new image structure for image specification
SPEC. SPEC has a hash value of HASH. */
static struct image *
-make_image (spec, hash)
- Lisp_Object spec;
- unsigned hash;
+make_image (Lisp_Object spec, EMACS_UINT hash)
{
- struct image *img = (struct image *) xmalloc (sizeof *img);
+ struct image *img = xzalloc (sizeof *img);
Lisp_Object file = image_spec_value (spec, QCfile, NULL);
- xassert (valid_image_p (spec));
- bzero (img, sizeof *img);
+ eassert (valid_image_p (spec));
img->dependencies = NILP (file) ? Qnil : list1 (file);
img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
- xassert (img->type != NULL);
+ eassert (img->type != NULL);
img->spec = spec;
- img->data.lisp_val = Qnil;
+ img->lisp_data = Qnil;
img->ascent = DEFAULT_IMAGE_ASCENT;
img->hash = hash;
img->corners[BOT_CORNER] = -1; /* Full image */
/* Free image IMG which was used on frame F, including its resources. */
static void
-free_image (f, img)
- struct frame *f;
- struct image *img;
+free_image (struct frame *f, struct image *img)
{
if (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;
+static int
+check_image_size (struct frame *f, int width, int height)
{
int w, h;
return 0;
if (INTEGERP (Vmax_image_size))
- w = h = XINT (Vmax_image_size);
+ return (width <= XINT (Vmax_image_size)
+ && height <= XINT (Vmax_image_size));
else if (FLOATP (Vmax_image_size))
{
if (f != NULL)
}
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);
+ return (width <= XFLOAT_DATA (Vmax_image_size) * w
+ && height <= 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. */
void
-prepare_image_for_display (f, img)
- struct frame *f;
- struct image *img;
+prepare_image_for_display (struct frame *f, struct image *img)
{
- EMACS_TIME t;
-
/* We're about to display IMG, so set its timestamp to `now'. */
- EMACS_GET_TIME (t);
- img->timestamp = EMACS_SECS (t);
+ img->timestamp = current_emacs_time ();
/* If IMG doesn't have a pixmap yet, load it now, using the image
type dependent loader function. */
drawn in face FACE. */
int
-image_ascent (img, face, slice)
- struct image *img;
- struct face *face;
- struct glyph_slice *slice;
+image_ascent (struct image *img, struct face *face, struct glyph_slice *slice)
{
int height;
int ascent;
because a typical font is `top-heavy' (due to the presence
uppercase letters), so the image placement should err towards
being top-heavy too. It also just generally looks better. */
- ascent = (height + FONT_BASE(face->font)
- - FONT_DESCENT(face->font) + 1) / 2;
+ ascent = (height + FONT_BASE (face->font)
+ - FONT_DESCENT (face->font) + 1) / 2;
#endif /* HAVE_NTGUI */
}
else
ascent = height / 2;
}
else
- ascent = (int) (height * img->ascent / 100.0);
+ ascent = height * (img->ascent / 100.0);
return ascent;
}
On W32, XIMG is assumed to a device context with the bitmap selected. */
static RGB_PIXEL_COLOR
-four_corners_best (ximg, corners, width, height)
- XImagePtr_or_DC ximg;
- int *corners;
- unsigned long width, height;
+four_corners_best (XImagePtr_or_DC ximg, int *corners,
+ unsigned long width, unsigned long height)
{
- RGB_PIXEL_COLOR corner_pixels[4], best;
+ RGB_PIXEL_COLOR corner_pixels[4], best IF_LINT (= 0);
int i, best_count;
if (corners && corners[BOT_CORNER] >= 0)
#elif defined (HAVE_NS)
#define Destroy_Image(ximg, dummy) \
- ns_release_object(ximg)
+ ns_release_object (ximg)
#define Free_Pixmap(display, pixmap) \
- ns_release_object(pixmap)
+ ns_release_object (pixmap)
#else
use for the heuristic. */
RGB_PIXEL_COLOR
-image_background (img, f, ximg)
- struct image *img;
- struct frame *f;
- XImagePtr_or_DC ximg;
+image_background (struct image *img, struct frame *f, XImagePtr_or_DC ximg)
{
if (! img->background_valid)
/* IMG doesn't have a background yet, try to guess a reasonable value. */
existing XImage object to use for the heuristic. */
int
-image_background_transparent (img, f, mask)
- struct image *img;
- struct frame *f;
- XImagePtr_or_DC mask;
+image_background_transparent (struct image *img, struct frame *f, XImagePtr_or_DC mask)
{
if (! img->background_transparent_valid)
/* IMG doesn't have a background yet, try to guess a reasonable value. */
Helper functions for X image types
***********************************************************************/
-static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
- int, int));
-static void x_clear_image P_ ((struct frame *f, struct image *img));
-static unsigned long x_alloc_image_color P_ ((struct frame *f,
- struct image *img,
- Lisp_Object color_name,
- unsigned long dflt));
+static void x_clear_image_1 (struct frame *, struct image *, int,
+ int, int);
+static void x_clear_image (struct frame *f, struct image *img);
+static unsigned long x_alloc_image_color (struct frame *f,
+ struct image *img,
+ Lisp_Object color_name,
+ unsigned long dflt);
/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
the image, if any. */
static void
-x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
- struct frame *f;
- struct image *img;
- int pixmap_p, mask_p, colors_p;
+x_clear_image_1 (struct frame *f, struct image *img, int pixmap_p, int mask_p,
+ int colors_p)
{
if (pixmap_p && img->pixmap)
{
/* Free X resources of image IMG which is used on frame F. */
static void
-x_clear_image (f, img)
- struct frame *f;
- struct image *img;
+x_clear_image (struct frame *f, struct image *img)
{
- BLOCK_INPUT;
+ block_input ();
x_clear_image_1 (f, img, 1, 1, 1);
- UNBLOCK_INPUT;
+ unblock_input ();
}
color. */
static unsigned long
-x_alloc_image_color (f, img, color_name, dflt)
- struct frame *f;
- struct image *img;
- Lisp_Object color_name;
- unsigned long dflt;
+x_alloc_image_color (struct frame *f, struct image *img, Lisp_Object color_name,
+ unsigned long dflt)
{
XColor color;
unsigned long result;
- xassert (STRINGP (color_name));
+ eassert (STRINGP (color_name));
- if (x_defined_color (f, SDATA (color_name), &color, 1))
+ if (x_defined_color (f, SSDATA (color_name), &color, 1)
+ && img->ncolors < min (min (PTRDIFF_MAX, SIZE_MAX) / sizeof *img->colors,
+ INT_MAX))
{
/* This isn't called frequently so we get away with simply
reallocating the color vector to the needed size, here. */
- ++img->ncolors;
- img->colors =
- (unsigned long *) xrealloc (img->colors,
- img->ncolors * sizeof *img->colors);
- img->colors[img->ncolors - 1] = color.pixel;
+ ptrdiff_t ncolors = img->ncolors + 1;
+ img->colors = xrealloc (img->colors, ncolors * sizeof *img->colors);
+ img->colors[ncolors - 1] = color.pixel;
+ img->ncolors = ncolors;
result = color.pixel;
}
else
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 (struct frame *f, struct image *img);
+static void postprocess_image (struct frame *, struct image *);
/* Return a new, initialized image cache that is allocated from the
heap. Call free_image_cache to free an image cache. */
struct image_cache *
-make_image_cache ()
+make_image_cache (void)
{
- struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
+ struct image_cache *c = xzalloc (sizeof *c);
int size;
- bzero (c, sizeof *c);
- c->size = 50;
- c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
+ size = 50;
+ c->images = xmalloc (size * sizeof *c->images);
+ c->size = size;
size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
- c->buckets = (struct image **) xmalloc (size);
- bzero (c->buckets, size);
+ c->buckets = xzalloc (size);
return c;
}
/* 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;
+search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash)
{
struct image *img;
struct image_cache *c = FRAME_IMAGE_CACHE (f);
/* Search frame F for an image with spec SPEC, and free it. */
static void
-uncache_image (f, spec)
- struct frame *f;
- Lisp_Object spec;
+uncache_image (struct frame *f, Lisp_Object spec)
{
struct image *img = search_image_cache (f, spec, sxhash (spec, 0));
if (img)
caches. */
void
-free_image_cache (f)
- struct frame *f;
+free_image_cache (struct frame *f)
{
struct image_cache *c = FRAME_IMAGE_CACHE (f);
if (c)
{
- int i;
+ ptrdiff_t i;
/* Cache should not be referenced by any frame when freed. */
- xassert (c->refcount == 0);
+ eassert (c->refcount == 0);
for (i = 0; i < c->used; ++i)
free_image (f, c->images[i]);
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
+static void
clear_image_cache (struct frame *f, Lisp_Object filter)
{
struct image_cache *c = FRAME_IMAGE_CACHE (f);
- if (c && (!NILP (filter) || INTEGERP (Vimage_cache_eviction_delay)))
+ if (c)
{
- EMACS_TIME t;
- unsigned long old;
- int i, nfreed;
-
- EMACS_GET_TIME (t);
- old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
+ ptrdiff_t i, nfreed = 0;
/* Block input so that we won't be interrupted by a SIGIO
while being in an inconsistent state. */
- BLOCK_INPUT;
+ block_input ();
- for (i = nfreed = 0; i < c->used; ++i)
+ if (!NILP (filter))
+ {
+ /* Filter image cache. */
+ for (i = 0; i < c->used; ++i)
+ {
+ struct image *img = c->images[i];
+ if (img && (EQ (Qt, filter)
+ || !NILP (Fmember (filter, img->dependencies))))
+ {
+ free_image (f, img);
+ ++nfreed;
+ }
+ }
+ }
+ else if (INTEGERP (Vimage_cache_eviction_delay))
{
- struct image *img = c->images[i];
- if (img != NULL
- && (NILP (filter) ? img->timestamp < old
- : (EQ (Qt, filter)
- || !NILP (Fmember (filter, img->dependencies)))))
+ /* Free cache based on timestamp. */
+ EMACS_TIME old, t;
+ double delay;
+ ptrdiff_t nimages = 0;
+
+ for (i = 0; i < c->used; ++i)
+ if (c->images[i])
+ nimages++;
+
+ /* If the number of cached images has grown unusually large,
+ decrease the cache eviction delay (Bug#6230). */
+ delay = XINT (Vimage_cache_eviction_delay);
+ if (nimages > 40)
+ delay = 1600 * delay / nimages / nimages;
+ delay = max (delay, 1);
+
+ t = current_emacs_time ();
+ old = sub_emacs_time (t, EMACS_TIME_FROM_DOUBLE (delay));
+
+ for (i = 0; i < c->used; ++i)
{
- free_image (f, img);
- ++nfreed;
+ struct image *img = c->images[i];
+ if (img && EMACS_TIME_LT (img->timestamp, old))
+ {
+ free_image (f, img);
+ ++nfreed;
+ }
}
}
FOR_EACH_FRAME (tail, frame)
{
- struct frame *f = XFRAME (frame);
- if (FRAME_IMAGE_CACHE (f) == c)
- clear_current_matrices (f);
+ struct frame *fr = XFRAME (frame);
+ if (FRAME_IMAGE_CACHE (fr) == c)
+ clear_current_matrices (fr);
}
++windows_or_buffers_changed;
}
- UNBLOCK_INPUT;
+ unblock_input ();
}
}
FILTER t means clear the image caches of all frames.
Anything else, means only clear those images which refer to FILTER,
which is then usually a filename. */)
- (filter)
- Lisp_Object filter;
+ (Lisp_Object filter)
{
if (!(EQ (filter, Qnil) || FRAMEP (filter)))
clear_image_caches (filter);
}
-DEFUN ("image-refresh", Fimage_refresh, Simage_refresh,
+DEFUN ("image-flush", Fimage_flush, Simage_flush,
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.
+ doc: /* Fush the image with specification SPEC on frame FRAME.
+This removes the image from the Emacs image cache. If SPEC specifies
+an image file, the next redisplay of this image will read from 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;
+ (Lisp_Object spec, Lisp_Object frame)
{
if (!valid_image_p (spec))
error ("Invalid image specification");
by the image's specification, */
static void
-postprocess_image (f, img)
- struct frame *f;
- struct image *img;
+postprocess_image (struct frame *f, struct image *img)
{
/* Manipulation of the image's mask. */
if (img->pixmap)
/* Return the id of image with Lisp specification SPEC on frame F.
SPEC must be a valid Lisp image specification (see valid_image_p). */
-int
-lookup_image (f, spec)
- struct frame *f;
- Lisp_Object spec;
+ptrdiff_t
+lookup_image (struct frame *f, Lisp_Object spec)
{
- struct image_cache *c;
struct image *img;
- unsigned hash;
- struct gcpro gcpro1;
- EMACS_TIME now;
+ EMACS_UINT hash;
/* F must be a window-system frame, and SPEC must be a valid image
specification. */
- xassert (FRAME_WINDOW_P (f));
- xassert (valid_image_p (spec));
-
- c = FRAME_IMAGE_CACHE (f);
-
- GCPRO1 (spec);
+ eassert (FRAME_WINDOW_P (f));
+ eassert (valid_image_p (spec));
/* Look up SPEC in the hash table of the image cache. */
hash = sxhash (spec, 0);
/* If not found, create a new image and cache it. */
if (img == NULL)
{
- extern Lisp_Object Qpostscript;
-
- BLOCK_INPUT;
+ block_input ();
img = make_image (spec, hash);
cache_image (f, img);
img->load_failed_p = img->type->load (f, img) == 0;
`:ascent ASCENT', `:margin MARGIN', `:relief RELIEF',
`:background COLOR'. */
Lisp_Object ascent, margin, relief, bg;
+ int relief_bound;
ascent = image_spec_value (spec, QCascent, NULL);
if (INTEGERP (ascent))
img->ascent = CENTERED_IMAGE_ASCENT;
margin = image_spec_value (spec, QCmargin, NULL);
- if (INTEGERP (margin) && XINT (margin) >= 0)
+ if (INTEGERP (margin))
img->vmargin = img->hmargin = XFASTINT (margin);
- else if (CONSP (margin) && INTEGERP (XCAR (margin))
- && INTEGERP (XCDR (margin)))
+ else if (CONSP (margin))
{
- if (XINT (XCAR (margin)) > 0)
- img->hmargin = XFASTINT (XCAR (margin));
- if (XINT (XCDR (margin)) > 0)
- img->vmargin = XFASTINT (XCDR (margin));
+ img->hmargin = XFASTINT (XCAR (margin));
+ img->vmargin = XFASTINT (XCDR (margin));
}
relief = image_spec_value (spec, QCrelief, NULL);
- if (INTEGERP (relief))
+ relief_bound = INT_MAX - max (img->hmargin, img->vmargin);
+ if (RANGED_INTEGERP (- relief_bound, relief, relief_bound))
{
img->relief = XINT (relief);
img->hmargin += eabs (img->relief);
postprocess_image (f, img);
}
- UNBLOCK_INPUT;
+ unblock_input ();
}
/* We're using IMG, so set its timestamp to `now'. */
- EMACS_GET_TIME (now);
- img->timestamp = EMACS_SECS (now);
-
- UNGCPRO;
+ img->timestamp = current_emacs_time ();
/* Value is the image id. */
return img->id;
/* Cache image IMG in the image cache of frame F. */
static void
-cache_image (f, img)
- struct frame *f;
- struct image *img;
+cache_image (struct frame *f, struct image *img)
{
struct image_cache *c = FRAME_IMAGE_CACHE (f);
- int i;
+ ptrdiff_t i;
/* Find a free slot in c->images. */
for (i = 0; i < c->used; ++i)
/* If no free slot found, maybe enlarge c->images. */
if (i == c->used && c->used == c->size)
- {
- c->size *= 2;
- c->images = (struct image **) xrealloc (c->images,
- c->size * sizeof *c->images);
- }
+ c->images = xpalloc (c->images, &c->size, 1, -1, sizeof *c->images);
/* Add IMG to c->images, and assign IMG an id. */
c->images[i] = img;
/* Mark Lisp objects in image IMG. */
static void
-mark_image (img)
- struct image *img;
+mark_image (struct image *img)
{
mark_object (img->spec);
mark_object (img->dependencies);
- if (!NILP (img->data.lisp_val))
- mark_object (img->data.lisp_val);
+ if (!NILP (img->lisp_data))
+ mark_object (img->lisp_data);
}
{
if (c)
{
- int i;
+ ptrdiff_t i;
for (i = 0; i < c->used; ++i)
if (c->images[i])
mark_image (c->images[i]);
#ifdef HAVE_NTGUI
/* Macro for defining functions that will be loaded from image DLLs. */
-#define DEF_IMGLIB_FN(rettype, func) rettype (FAR CDECL *fn_##func)()
+#define DEF_IMGLIB_FN(rettype,func,args) static rettype (FAR CDECL *fn_##func)args
/* Macro for loading those image functions from the library. */
#define LOAD_IMGLIB_FN(lib,func) { \
if (!fn_##func) return 0; \
}
-/* Load a DLL implementing an image type.
- The `image-library-alist' variable associates a symbol,
- identifying an image type, to a list of possible filenames.
- The function returns NULL if no library could be loaded for
- the given image type, or if the library was previously loaded;
- else the handle of the DLL. */
-static HMODULE
-w32_delayed_load (Lisp_Object libraries, Lisp_Object type)
+#endif /* HAVE_NTGUI */
+
+static int x_create_x_image_and_pixmap (struct frame *, int, int, int,
+ XImagePtr *, Pixmap *);
+static void x_destroy_x_image (XImagePtr);
+static void x_put_x_image (struct frame *, XImagePtr, Pixmap, int, int);
+
+/* Return nonzero if XIMG's size WIDTH x HEIGHT doesn't break the
+ windowing system.
+ WIDTH and HEIGHT must both be positive.
+ If XIMG is null, assume it is a bitmap. */
+static int
+x_check_image_size (XImagePtr ximg, int width, int height)
{
- HMODULE library = NULL;
+#ifdef HAVE_X_WINDOWS
+ /* Respect Xlib's limits: it cannot deal with images that have more
+ than INT_MAX (and/or UINT_MAX) bytes. And respect Emacs's limits
+ of PTRDIFF_MAX (and/or SIZE_MAX) bytes for any object. */
+ enum
+ {
+ XLIB_BYTES_MAX = min (INT_MAX, UINT_MAX),
+ X_IMAGE_BYTES_MAX = min (XLIB_BYTES_MAX, min (PTRDIFF_MAX, SIZE_MAX))
+ };
- if (CONSP (libraries) && NILP (Fassq (type, Vimage_type_cache)))
+ int bitmap_pad, depth, bytes_per_line;
+ if (ximg)
{
- Lisp_Object dlls = Fassq (type, libraries);
-
- if (CONSP (dlls))
- for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
- {
- CHECK_STRING_CAR (dlls);
- if (library = LoadLibrary (SDATA (XCAR (dlls))))
- break;
- }
+ bitmap_pad = ximg->bitmap_pad;
+ depth = ximg->depth;
+ bytes_per_line = ximg->bytes_per_line;
}
-
- return library;
+ else
+ {
+ bitmap_pad = 8;
+ depth = 1;
+ bytes_per_line = (width >> 3) + ((width & 7) != 0);
+ }
+ return (width <= (INT_MAX - (bitmap_pad - 1)) / depth
+ && height <= X_IMAGE_BYTES_MAX / bytes_per_line);
+#else
+ /* FIXME: Implement this check for the HAVE_NS and HAVE_NTGUI cases.
+ For now, assume that every image size is allowed on these systems. */
+ return 1;
+#endif
}
-#endif /* HAVE_NTGUI */
-
-static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
- XImagePtr *, Pixmap *));
-static void x_destroy_x_image P_ ((XImagePtr));
-static void x_put_x_image P_ ((struct frame *, XImagePtr, Pixmap, int, int));
-
-
/* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
should indicate the bit depth of the image. */
static int
-x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
- struct frame *f;
- int width, height, depth;
- XImagePtr *ximg;
- Pixmap *pixmap;
+x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth,
+ XImagePtr *ximg, Pixmap *pixmap)
{
#ifdef HAVE_X_WINDOWS
Display *display = FRAME_X_DISPLAY (f);
Window window = FRAME_X_WINDOW (f);
Screen *screen = FRAME_X_SCREEN (f);
- xassert (interrupt_input_blocked);
+ eassert (input_blocked_p ());
if (depth <= 0)
depth = DefaultDepthOfScreen (screen);
return 0;
}
+ if (! x_check_image_size (*ximg, width, height))
+ {
+ x_destroy_x_image (*ximg);
+ *ximg = NULL;
+ image_error ("Image too large (%dx%d)",
+ make_number (width), make_number (height));
+ return 0;
+ }
+
/* Allocate image raster. */
- (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
+ (*ximg)->data = xmalloc ((*ximg)->bytes_per_line * height);
/* Allocate a pixmap of the same size. */
*pixmap = XCreatePixmap (display, window, width, height, depth);
/* Bitmaps with a depth less than 16 need a palette. */
/* BITMAPINFO structure already contains the first RGBQUAD. */
if (depth < 16)
- palette_colors = 1 << depth - 1;
+ palette_colors = 1 << (depth - 1);
*ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
- if (*ximg == NULL)
- {
- image_error ("Unable to allocate memory for XImage", Qnil, Qnil);
- return 0;
- }
- header = &((*ximg)->info.bmiHeader);
- bzero (&((*ximg)->info), sizeof (BITMAPINFO));
+ header = &(*ximg)->info.bmiHeader;
+ memset (&(*ximg)->info, 0, sizeof (BITMAPINFO));
header->biSize = sizeof (*header);
header->biWidth = width;
header->biHeight = -height; /* negative indicates a top-down bitmap. */
DWORD err = GetLastError ();
Lisp_Object errcode;
/* All system errors are < 10000, so the following is safe. */
- XSETINT (errcode, (int) err);
+ XSETINT (errcode, err);
image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
x_destroy_x_image (*ximg);
return 0;
#endif /* HAVE_NTGUI */
#ifdef HAVE_NS
- *pixmap = ns_image_for_XPM(width, height, depth);
+ *pixmap = ns_image_for_XPM (width, height, depth);
if (*pixmap == 0)
{
*ximg = NULL;
/* Destroy XImage XIMG. Free XIMG->data. */
static void
-x_destroy_x_image (ximg)
- XImagePtr ximg;
+x_destroy_x_image (XImagePtr ximg)
{
- xassert (interrupt_input_blocked);
+ eassert (input_blocked_p ());
if (ximg)
{
#ifdef HAVE_X_WINDOWS
xfree (ximg);
#endif /* HAVE_NTGUI */
#ifdef HAVE_NS
- ns_release_object(ximg);
+ ns_release_object (ximg);
#endif /* HAVE_NS */
}
}
are width and height of both the image and pixmap. */
static void
-x_put_x_image (f, ximg, pixmap, width, height)
- struct frame *f;
- XImagePtr ximg;
- Pixmap pixmap;
- int width, height;
+x_put_x_image (struct frame *f, XImagePtr ximg, Pixmap pixmap, int width, int height)
{
#ifdef HAVE_X_WINDOWS
GC gc;
- xassert (interrupt_input_blocked);
+ eassert (input_blocked_p ());
gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height);
XFreeGC (FRAME_X_DISPLAY (f), gc);
#endif /* HAVE_NTGUI */
#ifdef HAVE_NS
- xassert (ximg == pixmap);
- ns_retain_object(ximg);
+ eassert (ximg == pixmap);
+ ns_retain_object (ximg);
#endif
}
File Handling
***********************************************************************/
-static unsigned char *slurp_file P_ ((char *, int *));
-
-
/* 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. */
Lisp_Object
-x_find_image_file (file)
- Lisp_Object file;
+x_find_image_file (Lisp_Object file)
{
Lisp_Object file_found, search_path;
- struct gcpro gcpro1, gcpro2;
int fd;
- file_found = Qnil;
/* 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);
/* Try to find FILE in data-directory/images, then x-bitmap-file-path. */
fd = openp (search_path, file, Qnil, &file_found, Qnil);
close (fd);
}
- UNGCPRO;
return file_found;
}
occurred. *SIZE is set to the size of the file. */
static unsigned char *
-slurp_file (file, size)
- char *file;
- int *size;
+slurp_file (char *file, ptrdiff_t *size)
{
FILE *fp = NULL;
unsigned char *buf = NULL;
if (stat (file, &st) == 0
&& (fp = fopen (file, "rb")) != NULL
- && (buf = (unsigned char *) xmalloc (st.st_size),
+ && 0 <= st.st_size && st.st_size <= min (PTRDIFF_MAX, SIZE_MAX)
+ && (buf = xmalloc (st.st_size),
fread (buf, 1, st.st_size, fp) == st.st_size))
{
*size = st.st_size;
XBM images
***********************************************************************/
-static int xbm_scan P_ ((unsigned char **, unsigned char *, char *, int *));
-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_ ((struct frame *f,
- unsigned char *, unsigned char *,
- int *, int *, unsigned char **, int));
-static int xbm_file_p P_ ((Lisp_Object));
+static int xbm_scan (unsigned char **, unsigned char *, char *, int *);
+static int xbm_load (struct frame *f, struct image *img);
+static int xbm_load_image (struct frame *f, struct image *img,
+ unsigned char *, unsigned char *);
+static int xbm_image_p (Lisp_Object object);
+static int xbm_read_bitmap_data (struct frame *f,
+ unsigned char *, unsigned char *,
+ int *, int *, char **, int);
+static int xbm_file_p (Lisp_Object);
/* Indices of image specification fields in xbm_format, below. */
{":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
{":background", IMAGE_STRING_OR_NIL_VALUE, 0},
{":ascent", IMAGE_ASCENT_VALUE, 0},
- {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
+ {":margin", IMAGE_NON_NEGATIVE_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},
xbm_image_p,
xbm_load,
x_clear_image,
+ NULL,
NULL
};
displayed is used. */
static int
-xbm_image_p (object)
- Lisp_Object object;
+xbm_image_p (Lisp_Object object)
{
struct image_keyword kw[XBM_LAST];
- bcopy (xbm_format, kw, sizeof kw);
+ memcpy (kw, xbm_format, sizeof kw);
if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
return 0;
- xassert (EQ (kw[XBM_TYPE].value, Qxbm));
+ eassert (EQ (kw[XBM_TYPE].value, Qxbm));
if (kw[XBM_FILE].count)
{
data. */
if (VECTORP (data))
{
- int i;
+ EMACS_INT i;
/* Number of elements of the vector must be >= height. */
- if (XVECTOR_SIZE (data) < height)
+ if (ASIZE (data) < height)
return 0;
/* Each string or bool-vector in data must be large enough
for one line of the image. */
for (i = 0; i < height; ++i)
{
- Lisp_Object elt = XVECTOR (data)->contents[i];
+ Lisp_Object elt = AREF (data, i);
if (STRINGP (elt))
{
}
else if (BOOL_VECTOR_P (data))
{
- if (XBOOL_VECTOR (data)->size < width * height)
+ if (XBOOL_VECTOR (data)->size / height < width)
return 0;
}
else
scanning a number, store its value in *IVAL. */
static int
-xbm_scan (s, end, sval, ival)
- unsigned char **s, *end;
- char *sval;
- int *ival;
+xbm_scan (unsigned char **s, unsigned char *end, char *sval, int *ival)
{
unsigned int c;
loop:
/* Skip white space. */
- while (*s < end && (c = *(*s)++, isspace (c)))
+ while (*s < end && (c = *(*s)++, c_isspace (c)))
;
if (*s >= end)
c = 0;
- else if (isdigit (c))
+ else if (c_isdigit (c))
{
int value = 0, digit;
while (*s < end)
{
c = *(*s)++;
- if (isdigit (c))
+ if (c_isdigit (c))
digit = c - '0';
else if (c >= 'a' && c <= 'f')
digit = c - 'a' + 10;
value = 16 * value + digit;
}
}
- else if (isdigit (c))
+ else if (c_isdigit (c))
{
value = c - '0';
while (*s < end
- && (c = *(*s)++, isdigit (c)))
+ && (c = *(*s)++, c_isdigit (c)))
value = 8 * value + c - '0';
}
}
{
value = c - '0';
while (*s < end
- && (c = *(*s)++, isdigit (c)))
+ && (c = *(*s)++, c_isdigit (c)))
value = 10 * value + c - '0';
}
*ival = value;
c = XBM_TK_NUMBER;
}
- else if (isalpha (c) || c == '_')
+ else if (c_isalpha (c) || c == '_')
{
*sval++ = c;
while (*s < end
- && (c = *(*s)++, (isalnum (c) || c == '_')))
+ && (c = *(*s)++, (c_isalnum (c) || c == '_')))
*sval++ = c;
*sval = 0;
if (*s < end)
w1 = (width + 7) / 8; /* nb of 8bits elt in X bitmap */
w2 = ((width + 15) / 16) * 2; /* nb of 16bits elt in W32 bitmap */
- bits = (unsigned char *) alloca (height * w2);
- bzero (bits, height * w2);
+ bits = alloca (height * w2);
+ memset (bits, 0, height * w2);
for (i = 0; i < height; i++)
{
p = bits + i*w2;
}
static void
-convert_mono_to_color_image (f, img, foreground, background)
- struct frame *f;
- struct image *img;
- COLORREF foreground, background;
+convert_mono_to_color_image (struct frame *f, struct image *img,
+ COLORREF foreground, COLORREF background)
{
HDC hdc, old_img_dc, new_img_dc;
HGDIOBJ old_prev, new_prev;
static void
-Create_Pixmap_From_Bitmap_Data (f, img, data, fg, bg, non_default_colors)
- struct frame *f;
- struct image *img;
- char *data;
- RGB_PIXEL_COLOR fg, bg;
- int non_default_colors;
+Create_Pixmap_From_Bitmap_Data (struct frame *f, struct image *img, char *data,
+ RGB_PIXEL_COLOR fg, RGB_PIXEL_COLOR bg,
+ int non_default_colors)
{
#ifdef HAVE_NTGUI
img->pixmap
convert_mono_to_color_image (f, img, fg, bg);
#elif defined (HAVE_NS)
- img->pixmap = ns_image_from_XBM(data, img->width, img->height);
+ img->pixmap = ns_image_from_XBM (data, img->width, img->height);
#else
- img->pixmap
- = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
+ img->pixmap =
+ (x_check_image_size (0, img->width, img->height)
+ ? XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
FRAME_X_WINDOW (f),
data,
img->width, img->height,
fg, bg,
- DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
+ DefaultDepthOfScreen (FRAME_X_SCREEN (f)))
+ : NO_PIXMAP);
#endif /* !HAVE_NTGUI && !HAVE_NS */
}
invalid (the bitmap remains unread). */
static int
-xbm_read_bitmap_data (f, contents, end, width, height, data, inhibit_image_error)
- struct frame *f;
- unsigned char *contents, *end;
- int *width, *height;
- unsigned char **data;
- int inhibit_image_error;
+xbm_read_bitmap_data (struct frame *f, unsigned char *contents, unsigned char *end,
+ int *width, int *height, char **data,
+ int inhibit_image_error)
{
unsigned char *s = contents;
char buffer[BUFSIZ];
int padding_p = 0;
int v10 = 0;
int bytes_per_line, i, nbytes;
- unsigned char *p;
+ char *p;
int value;
int LA1;
if (LA1 == XBM_TK_NUMBER)
{
- char *p = strrchr (buffer, '_');
- p = p ? p + 1 : buffer;
- if (strcmp (p, "width") == 0)
+ char *q = strrchr (buffer, '_');
+ q = q ? q + 1 : buffer;
+ if (strcmp (q, "width") == 0)
*width = value;
- else if (strcmp (p, "height") == 0)
+ else if (strcmp (q, "height") == 0)
*height = value;
}
expect (XBM_TK_NUMBER);
expect ('=');
expect ('{');
+ if (! x_check_image_size (0, *width, *height))
+ {
+ if (!inhibit_image_error)
+ image_error ("Image too large (%dx%d)",
+ make_number (*width), make_number (*height));
+ goto failure;
+ }
bytes_per_line = (*width + 7) / 8 + padding_p;
nbytes = bytes_per_line * *height;
- p = *data = (unsigned char *) xmalloc (nbytes);
+ p = *data = xmalloc (nbytes);
if (v10)
{
successful. */
static int
-xbm_load_image (f, img, contents, end)
- struct frame *f;
- struct image *img;
- unsigned char *contents, *end;
+xbm_load_image (struct frame *f, struct image *img, unsigned char *contents,
+ unsigned char *end)
{
int rc;
- unsigned char *data;
+ char *data;
int success_p = 0;
rc = xbm_read_bitmap_data (f, contents, end, &img->width, &img->height,
int non_default_colors = 0;
Lisp_Object value;
- xassert (img->width > 0 && img->height > 0);
+ eassert (img->width > 0 && img->height > 0);
/* Get foreground and background colors, maybe allocate colors. */
value = image_spec_value (img->spec, QCforeground, NULL);
/* Value is non-zero if DATA looks like an in-memory XBM file. */
static int
-xbm_file_p (data)
- Lisp_Object data;
+xbm_file_p (Lisp_Object data)
{
int w, h;
return (STRINGP (data)
non-zero if successful. */
static int
-xbm_load (f, img)
- struct frame *f;
- struct image *img;
+xbm_load (struct frame *f, struct image *img)
{
int success_p = 0;
Lisp_Object file_name;
- xassert (xbm_image_p (img->spec));
+ eassert (xbm_image_p (img->spec));
/* If IMG->spec specifies a file name, create a non-file spec from it. */
file_name = image_spec_value (img->spec, QCfile, NULL);
{
Lisp_Object file;
unsigned char *contents;
- int size;
- struct gcpro gcpro1;
+ ptrdiff_t size;
file = x_find_image_file (file_name);
- GCPRO1 (file);
if (!STRINGP (file))
{
image_error ("Cannot find image file `%s'", file_name, Qnil);
- UNGCPRO;
return 0;
}
- contents = slurp_file (SDATA (file), &size);
+ contents = slurp_file (SSDATA (file), &size);
if (contents == NULL)
{
image_error ("Error loading XBM image `%s'", img->spec, Qnil);
- UNGCPRO;
return 0;
}
success_p = xbm_load_image (f, img, contents, contents + size);
- UNGCPRO;
+ xfree (contents);
}
else
{
in_memory_file_p = xbm_file_p (data);
/* Parse the image specification. */
- bcopy (xbm_format, fmt, sizeof fmt);
+ memcpy (fmt, xbm_format, sizeof fmt);
parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
- xassert (parsed_p);
+ (void) parsed_p;
+ eassert (parsed_p);
/* Get specified width, and height. */
if (!in_memory_file_p)
{
img->width = XFASTINT (fmt[XBM_WIDTH].value);
img->height = XFASTINT (fmt[XBM_HEIGHT].value);
- xassert (img->width > 0 && img->height > 0);
+ eassert (img->width > 0 && img->height > 0);
+ if (!check_image_size (f, img->width, img->height))
+ {
+ image_error ("Invalid image size (see `max-image-size')",
+ Qnil, Qnil);
+ return 0;
+ }
}
/* Get foreground and background colors, maybe allocate colors. */
char *p;
int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
- p = bits = (char *) alloca (nbytes * img->height);
+ p = bits = alloca (nbytes * img->height);
for (i = 0; i < img->height; ++i, p += nbytes)
{
- Lisp_Object line = XVECTOR (data)->contents[i];
+ Lisp_Object line = AREF (data, i);
if (STRINGP (line))
- bcopy (SDATA (line), p, nbytes);
+ memcpy (p, SDATA (line), nbytes);
else
- bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
+ memcpy (p, XBOOL_VECTOR (line)->data, nbytes);
}
}
else if (STRINGP (data))
- bits = SDATA (data);
+ bits = SSDATA (data);
else
- bits = XBOOL_VECTOR (data)->data;
+ bits = (char *) XBOOL_VECTOR (data)->data;
#ifdef WINDOWSNT
{
invertedBits = bits;
nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR
* img->height;
- bits = (char *) alloca(nbytes);
+ bits = alloca (nbytes);
for (i = 0; i < nbytes; i++)
bits[i] = XBM_BIT_SHUFFLE (invertedBits[i]);
}
#endif
/* Create the pixmap. */
- Create_Pixmap_From_Bitmap_Data (f, img, bits,
- foreground, background,
- non_default_colors);
+ if (x_check_image_size (0, img->width, img->height))
+ Create_Pixmap_From_Bitmap_Data (f, img, bits,
+ foreground, background,
+ non_default_colors);
+ else
+ img->pixmap = NO_PIXMAP;
+
if (img->pixmap)
success_p = 1;
else
#if defined (HAVE_XPM) || defined (HAVE_NS)
-static int xpm_image_p P_ ((Lisp_Object object));
-static int xpm_load P_ ((struct frame *f, struct image *img));
-static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
+static int xpm_image_p (Lisp_Object object);
+static int xpm_load (struct frame *f, struct image *img);
+static int xpm_valid_color_symbols_p (Lisp_Object);
#endif /* HAVE_XPM || HAVE_NS */
#if defined (HAVE_XPM) || defined (HAVE_NS)
/* The symbol `xpm' identifying XPM-format images. */
-Lisp_Object Qxpm;
+static Lisp_Object Qxpm;
/* Indices of image specification fields in xpm_format, below. */
{":file", IMAGE_STRING_VALUE, 0},
{":data", IMAGE_STRING_VALUE, 0},
{":ascent", IMAGE_ASCENT_VALUE, 0},
- {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
+ {":margin", IMAGE_NON_NEGATIVE_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},
{":background", IMAGE_STRING_OR_NIL_VALUE, 0}
};
+#ifdef HAVE_NTGUI
+static int init_xpm_functions (void);
+#else
+#define init_xpm_functions NULL
+#endif
+
/* Structure describing the image type XPM. */
static struct image_type xpm_type =
xpm_image_p,
xpm_load,
x_clear_image,
+ init_xpm_functions,
NULL
};
#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));
+static void xpm_init_color_cache (struct frame *, XpmAttributes *);
+static void xpm_free_color_cache (void);
+static int xpm_lookup_color (struct frame *, char *, XColor *);
+static int xpm_color_bucket (char *);
+static struct xpm_cached_color *xpm_cache_color (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
size. */
#define XPM_COLOR_CACHE_BUCKETS 1001
-struct xpm_cached_color **xpm_color_cache;
+static struct xpm_cached_color **xpm_color_cache;
/* Initialize the color cache. */
static void
-xpm_init_color_cache (f, attrs)
- struct frame *f;
- XpmAttributes *attrs;
+xpm_init_color_cache (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);
+ xpm_color_cache = xzalloc (nbytes);
init_color_table ();
if (attrs->valuemask & XpmColorSymbols)
/* Free the color cache. */
static void
-xpm_free_color_cache ()
+xpm_free_color_cache (void)
{
struct xpm_cached_color *p, *next;
int i;
cache. */
static int
-xpm_color_bucket (color_name)
- char *color_name;
+xpm_color_bucket (char *color_name)
{
- unsigned h = 0;
- char *s;
-
- for (s = color_name; *s; ++s)
- h = (h << 2) ^ *s;
- return h %= XPM_COLOR_CACHE_BUCKETS;
+ EMACS_UINT hash = hash_string (color_name, strlen (color_name));
+ return hash % XPM_COLOR_CACHE_BUCKETS;
}
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;
+xpm_cache_color (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);
+ nbytes = offsetof (struct xpm_cached_color, name) + strlen (color_name) + 1;
+ p = xmalloc (nbytes);
strcpy (p->name, color_name);
p->color = *color;
p->next = xpm_color_cache[bucket];
allocation failed. */
static int
-xpm_lookup_color (f, color_name, color)
- struct frame *f;
- char *color_name;
- XColor *color;
+xpm_lookup_color (struct frame *f, char *color_name, XColor *color)
{
struct xpm_cached_color *p;
int h = xpm_color_bucket (color_name);
with transparency, and it's useful. */
else if (strcmp ("opaque", color_name) == 0)
{
- bzero (color, sizeof (XColor)); /* Is this necessary/correct? */
+ memset (color, 0, sizeof (XColor)); /* Is this necessary/correct? */
color->pixel = FRAME_FOREGROUND_PIXEL (f);
p = xpm_cache_color (f, color_name, color, h);
}
if successful. */
static int
-xpm_alloc_color (dpy, cmap, color_name, color, closure)
- Display *dpy;
- Colormap cmap;
- char *color_name;
- XColor *color;
- void *closure;
+xpm_alloc_color (Display *dpy, Colormap cmap, char *color_name, XColor *color,
+ void *closure)
{
return xpm_lookup_color ((struct frame *) closure, color_name, color);
}
non-zero if successful. */
static int
-xpm_free_colors (dpy, cmap, pixels, npixels, closure)
- Display *dpy;
- Colormap cmap;
- Pixel *pixels;
- int npixels;
- void *closure;
+xpm_free_colors (Display *dpy, Colormap cmap, Pixel *pixels, int npixels, void *closure)
{
return 1;
}
/* XPM library details. */
-DEF_IMGLIB_FN (void, XpmFreeAttributes);
-DEF_IMGLIB_FN (int, XpmCreateImageFromBuffer);
-DEF_IMGLIB_FN (int, XpmReadFileToImage);
-DEF_IMGLIB_FN (void, XImageFree);
+DEF_IMGLIB_FN (void, XpmFreeAttributes, (XpmAttributes *));
+DEF_IMGLIB_FN (int, XpmCreateImageFromBuffer, (Display *, char *, xpm_XImage **,
+ xpm_XImage **, XpmAttributes *));
+DEF_IMGLIB_FN (int, XpmReadFileToImage, (Display *, char *, xpm_XImage **,
+ xpm_XImage **, XpmAttributes *));
+DEF_IMGLIB_FN (void, XImageFree, (xpm_XImage *));
static int
-init_xpm_functions (Lisp_Object libraries)
+init_xpm_functions (void)
{
HMODULE library;
- if (!(library = w32_delayed_load (libraries, Qxpm)))
+ if (!(library = w32_delayed_load (Qxpm)))
return 0;
LOAD_IMGLIB_FN (library, XpmFreeAttributes);
cdr are strings. */
static int
-xpm_valid_color_symbols_p (color_symbols)
- Lisp_Object color_symbols;
+xpm_valid_color_symbols_p (Lisp_Object color_symbols)
{
while (CONSP (color_symbols))
{
/* Value is non-zero if OBJECT is a valid XPM image specification. */
static int
-xpm_image_p (object)
- Lisp_Object object;
+xpm_image_p (Lisp_Object object)
{
struct image_keyword fmt[XPM_LAST];
- bcopy (xpm_format, fmt, sizeof fmt);
+ memcpy (fmt, xpm_format, sizeof fmt);
return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
/* Either `:file' or `:data' must be present. */
&& fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
#endif /* HAVE_XPM || HAVE_NS */
-#if defined (HAVE_XPM) && defined (HAVE_X_WINDOWS)
-int
-x_create_bitmap_from_xpm_data (f, bits)
- struct frame *f;
- char **bits;
+#if defined HAVE_XPM && defined HAVE_X_WINDOWS && !defined USE_GTK
+ptrdiff_t
+x_create_bitmap_from_xpm_data (struct frame *f, const char **bits)
{
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
- int id, rc;
+ ptrdiff_t id;
+ int rc;
XpmAttributes attrs;
Pixmap bitmap, mask;
- bzero (&attrs, sizeof attrs);
+ memset (&attrs, 0, sizeof attrs);
attrs.visual = FRAME_X_VISUAL (f);
attrs.colormap = FRAME_X_COLORMAP (f);
attrs.valuemask |= XpmColormap;
rc = XpmCreatePixmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- bits, &bitmap, &mask, &attrs);
+ (char **) bits, &bitmap, &mask, &attrs);
if (rc != XpmSuccess)
{
XpmFreeAttributes (&attrs);
#ifdef HAVE_XPM
static int
-xpm_load (f, img)
- struct frame *f;
- struct image *img;
+xpm_load (struct frame *f, struct image *img)
{
int rc;
XpmAttributes attrs;
/* Configure the XPM lib. Use the visual of frame F. Allocate
close colors. Return colors allocated. */
- bzero (&attrs, sizeof attrs);
+ memset (&attrs, 0, sizeof attrs);
#ifndef HAVE_NTGUI
attrs.visual = FRAME_X_VISUAL (f);
/* Allocate an XpmColorSymbol array. */
size = attrs.numsymbols * sizeof *xpm_syms;
- xpm_syms = (XpmColorSymbol *) alloca (size);
- bzero (xpm_syms, size);
+ xpm_syms = alloca (size);
+ memset (xpm_syms, 0, size);
attrs.colorsymbols = xpm_syms;
/* Fill the color symbol array. */
CONSP (tail);
++i, tail = XCDR (tail))
{
- Lisp_Object name = XCAR (XCAR (tail));
- Lisp_Object color = XCDR (XCAR (tail));
- xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1);
- strcpy (xpm_syms[i].name, SDATA (name));
- xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1);
- strcpy (xpm_syms[i].value, SDATA (color));
+ Lisp_Object name;
+ Lisp_Object color;
+ char *empty_string = (char *) "";
+
+ if (!CONSP (XCAR (tail)))
+ {
+ xpm_syms[i].name = empty_string;
+ xpm_syms[i].value = empty_string;
+ continue;
+ }
+ name = XCAR (XCAR (tail));
+ color = XCDR (XCAR (tail));
+ if (STRINGP (name))
+ {
+ xpm_syms[i].name = alloca (SCHARS (name) + 1);
+ strcpy (xpm_syms[i].name, SSDATA (name));
+ }
+ else
+ xpm_syms[i].name = empty_string;
+ if (STRINGP (color))
+ {
+ xpm_syms[i].value = alloca (SCHARS (color) + 1);
+ strcpy (xpm_syms[i].value, SSDATA (color));
+ }
+ else
+ xpm_syms[i].value = empty_string;
}
}
if (!STRINGP (file))
{
image_error ("Cannot find image file `%s'", specified_file, Qnil);
+#ifdef ALLOC_XPM_COLORS
+ xpm_free_color_cache ();
+#endif
return 0;
}
&attrs);
#else
rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- SDATA (file), &img->pixmap, &img->mask,
+ SSDATA (file), &img->pixmap, &img->mask,
&attrs);
#endif /* HAVE_NTGUI */
}
else
{
Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
+ if (!STRINGP (buffer))
+ {
+ image_error ("Invalid image data `%s'", buffer, Qnil);
+#ifdef ALLOC_XPM_COLORS
+ xpm_free_color_cache ();
+#endif
+ return 0;
+ }
#ifdef HAVE_NTGUI
/* XpmCreatePixmapFromBuffer is not available in the Windows port
of libxpm. But XpmCreateImageFromBuffer almost does what we want. */
&attrs);
#else
rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- SDATA (buffer),
+ SSDATA (buffer),
&img->pixmap, &img->mask,
&attrs);
#endif /* HAVE_NTGUI */
#endif /* HAVE_NTGUI */
/* Remember allocated colors. */
+ img->colors = xnmalloc (attrs.nalloc_pixels, sizeof *img->colors);
img->ncolors = attrs.nalloc_pixels;
- img->colors = (unsigned long *) xmalloc (img->ncolors
- * sizeof *img->colors);
for (i = 0; i < attrs.nalloc_pixels; ++i)
{
img->colors[i] = attrs.alloc_pixels[i];
img->width = attrs.width;
img->height = attrs.height;
- xassert (img->width > 0 && img->height > 0);
+ eassert (img->width > 0 && img->height > 0);
/* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
#ifdef HAVE_NTGUI
/* XPM support functions for NS where libxpm is not available.
Only XPM version 3 (without any extensions) is supported. */
-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, 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,
- const unsigned char *, int));
-static Lisp_Object xpm_make_color_table_h
- 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,
- const unsigned char *, int));
-static int xpm_str_to_color_key P_ ((const char *));
-static int xpm_load_image P_ ((struct frame *, struct image *,
- const unsigned char *, const unsigned char *));
+static void xpm_put_color_table_v (Lisp_Object, const unsigned char *,
+ int, Lisp_Object);
+static Lisp_Object xpm_get_color_table_v (Lisp_Object,
+ const unsigned char *, int);
+static void xpm_put_color_table_h (Lisp_Object, const unsigned char *,
+ int, Lisp_Object);
+static Lisp_Object xpm_get_color_table_h (Lisp_Object,
+ const unsigned char *, int);
/* Tokens returned from xpm_scan. */
length of the corresponding token, respectively. */
static int
-xpm_scan (s, end, beg, len)
- const unsigned char **s, *end, **beg;
- int *len;
+xpm_scan (const unsigned char **s,
+ const unsigned char *end,
+ const unsigned char **beg,
+ ptrdiff_t *len)
{
int c;
while (*s < end)
{
/* Skip white-space. */
- while (*s < end && (c = *(*s)++, isspace (c)))
+ while (*s < end && (c = *(*s)++, c_isspace (c)))
;
/* gnus-pointer.xpm uses '-' in its identifier.
sb-dir-plus.xpm uses '+' in its identifier. */
- if (isalpha (c) || c == '_' || c == '-' || c == '+')
+ if (c_isalpha (c) || c == '_' || c == '-' || c == '+')
{
*beg = *s - 1;
while (*s < end
- && (c = **s, isalnum (c) || c == '_' || c == '-' || c == '+'))
+ && (c = **s, c_isalnum (c)
+ || c == '_' || c == '-' || c == '+'))
++*s;
*len = *s - *beg;
return XPM_TK_IDENT;
hash table is used. */
static Lisp_Object
-xpm_make_color_table_v (put_func, get_func)
- void (**put_func) (Lisp_Object, const unsigned char *, int, Lisp_Object);
- Lisp_Object (**get_func) (Lisp_Object, const unsigned char *, int);
+xpm_make_color_table_v (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;
}
static void
-xpm_put_color_table_v (color_table, chars_start, chars_len, color)
- Lisp_Object color_table;
- const unsigned char *chars_start;
- int chars_len;
- Lisp_Object color;
+xpm_put_color_table_v (Lisp_Object color_table,
+ const unsigned char *chars_start,
+ int chars_len,
+ Lisp_Object color)
{
- XVECTOR (color_table)->contents[*chars_start] = color;
+ ASET (color_table, *chars_start, color);
}
static Lisp_Object
-xpm_get_color_table_v (color_table, chars_start, chars_len)
- Lisp_Object color_table;
- const unsigned char *chars_start;
- int chars_len;
+xpm_get_color_table_v (Lisp_Object color_table,
+ const unsigned char *chars_start,
+ int chars_len)
{
- return XVECTOR (color_table)->contents[*chars_start];
+ return AREF (color_table, *chars_start);
}
static Lisp_Object
-xpm_make_color_table_h (put_func, get_func)
- void (**put_func) (Lisp_Object, const unsigned char *, int, Lisp_Object);
- Lisp_Object (**get_func) (Lisp_Object, const unsigned char *, int);
+xpm_make_color_table_h (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;
}
static void
-xpm_put_color_table_h (color_table, chars_start, chars_len, color)
- Lisp_Object color_table;
- const unsigned char *chars_start;
- int chars_len;
- Lisp_Object color;
+xpm_put_color_table_h (Lisp_Object color_table,
+ const unsigned char *chars_start,
+ int chars_len,
+ Lisp_Object color)
{
struct Lisp_Hash_Table *table = XHASH_TABLE (color_table);
- unsigned hash_code;
+ EMACS_UINT hash_code;
Lisp_Object chars = make_unibyte_string (chars_start, chars_len);
hash_lookup (table, chars, &hash_code);
}
static Lisp_Object
-xpm_get_color_table_h (color_table, chars_start, chars_len)
- Lisp_Object color_table;
- const unsigned char *chars_start;
- int chars_len;
+xpm_get_color_table_h (Lisp_Object color_table,
+ 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);
+ ptrdiff_t i =
+ hash_lookup (table, make_unibyte_string (chars_start, chars_len), NULL);
return i >= 0 ? HASH_VALUE (table, i) : Qnil;
}
static const char xpm_color_key_strings[][4] = {"s", "m", "g4", "g", "c"};
static int
-xpm_str_to_color_key (s)
- const char *s;
+xpm_str_to_color_key (const char *s)
{
int i;
}
static int
-xpm_load_image (f, img, contents, end)
- struct frame *f;
- struct image *img;
- const unsigned char *contents, *end;
+xpm_load_image (struct frame *f,
+ struct image *img,
+ const unsigned char *contents,
+ const unsigned char *end)
{
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;
+ ptrdiff_t len;
+ int LA1;
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;
if (!(end - s >= 9 && memcmp (s, "/* XPM */", 9) == 0))
goto failure;
s += 9;
- match();
+ match ();
expect_ident ("static");
expect_ident ("char");
expect ('*');
goto failure;
}
+ if (!x_create_x_image_and_pixmap (f, width, height, 0,
+ &ximg, &img->pixmap)
+#ifndef HAVE_NS
+ || !x_create_x_image_and_pixmap (f, width, height, 1,
+ &mask_img, &img->mask)
+#endif
+ )
+ {
+ image_error ("Image too large", Qnil, Qnil);
+ goto failure;
+ }
+
expect (',');
XSETFRAME (frame, f);
while (num_colors-- > 0)
{
- unsigned char *color, *max_color;
+ char *color, *max_color;
int key, next_key, max_key = 0;
Lisp_Object symbol_color = Qnil, color_val;
XColor cdef;
if (CONSP (specified_color) && STRINGP (XCDR (specified_color)))
{
- if (xstrcasecmp (SDATA (XCDR (specified_color)), "None") == 0)
+ if (xstrcasecmp (SSDATA (XCDR (specified_color)), "None") == 0)
color_val = Qt;
- else if (x_defined_color (f, SDATA (XCDR (specified_color)),
+ else if (x_defined_color (f, SSDATA (XCDR (specified_color)),
&cdef, 0))
color_val = make_number (cdef.pixel);
}
expect (',');
}
- if (!x_create_x_image_and_pixmap (f, width, height, 0,
- &ximg, &img->pixmap)
-#ifndef HAVE_NS
- || !x_create_x_image_and_pixmap (f, width, height, 1,
- &mask_img, &img->mask)
-#endif
- )
- {
- image_error ("Out of memory (%s)", img->spec, Qnil);
- goto error;
- }
-
for (y = 0; y < height; y++)
{
expect (XPM_TK_STRING);
(!EQ (color_val, Qt) ? PIX_MASK_DRAW
: (have_mask = 1, PIX_MASK_RETAIN)));
#else
- if (EQ(color_val, Qt))
- ns_set_alpha(ximg, x, y, 0);
+ if (EQ (color_val, Qt))
+ ns_set_alpha (ximg, x, y, 0);
#endif
}
if (y + 1 < height)
failure:
image_error ("Invalid XPM file (%s)", img->spec, Qnil);
- error:
x_destroy_x_image (ximg);
x_destroy_x_image (mask_img);
x_clear_image (f, img);
}
static int
-xpm_load (f, img)
- struct frame *f;
- struct image *img;
+xpm_load (struct frame *f,
+ struct image *img)
{
int success_p = 0;
Lisp_Object file_name;
{
Lisp_Object file;
unsigned char *contents;
- int size;
- struct gcpro gcpro1;
+ ptrdiff_t size;
file = x_find_image_file (file_name);
- GCPRO1 (file);
if (!STRINGP (file))
{
image_error ("Cannot find image file `%s'", file_name, Qnil);
- UNGCPRO;
return 0;
}
- contents = slurp_file (SDATA (file), &size);
+ contents = slurp_file (SSDATA (file), &size);
if (contents == NULL)
{
image_error ("Error loading XPM image `%s'", img->spec, Qnil);
- UNGCPRO;
return 0;
}
success_p = xpm_load_image (f, img, contents, contents + size);
xfree (contents);
- UNGCPRO;
}
else
{
Lisp_Object data;
data = image_spec_value (img->spec, QCdata, NULL);
+ if (!STRINGP (data))
+ {
+ image_error ("Invalid image data `%s'", data, Qnil);
+ return 0;
+ }
success_p = xpm_load_image (f, img, SDATA (data),
SDATA (data) + SBYTES (data));
}
/* The color hash table. */
-struct ct_color **ct_table;
+static struct ct_color **ct_table;
/* Number of entries in the color table. */
-int ct_colors_allocated;
+static int ct_colors_allocated;
+enum
+{
+ ct_colors_allocated_max =
+ min (INT_MAX,
+ min (PTRDIFF_MAX, SIZE_MAX) / sizeof (unsigned long))
+};
/* Initialize the color table. */
static void
-init_color_table ()
+init_color_table (void)
{
int size = CT_SIZE * sizeof (*ct_table);
- ct_table = (struct ct_color **) xmalloc (size);
- bzero (ct_table, size);
+ ct_table = xzalloc (size);
ct_colors_allocated = 0;
}
/* Free memory associated with the color table. */
static void
-free_color_table ()
+free_color_table (void)
{
int i;
struct ct_color *p, *next;
G, B, and make an entry in the color table. */
static unsigned long
-lookup_rgb_color (f, r, g, b)
- struct frame *f;
- int r, g, b;
+lookup_rgb_color (struct frame *f, int r, int g, int b)
{
unsigned hash = CT_HASH_RGB (r, g, b);
int i = hash % CT_SIZE;
XColor color;
Colormap cmap;
int rc;
+#else
+ COLORREF color;
+#endif
+
+ if (ct_colors_allocated_max <= ct_colors_allocated)
+ return FRAME_FOREGROUND_PIXEL (f);
+#ifdef HAVE_X_WINDOWS
color.red = r;
color.green = g;
color.blue = b;
if (rc)
{
++ct_colors_allocated;
- p = (struct ct_color *) xmalloc (sizeof *p);
+ p = xmalloc (sizeof *p);
p->r = r;
p->g = g;
p->b = b;
return FRAME_FOREGROUND_PIXEL (f);
#else
- COLORREF color;
#ifdef HAVE_NTGUI
color = PALETTERGB (r, g, b);
#else
color = RGB_TO_ULONG (r, g, b);
#endif /* HAVE_NTGUI */
++ct_colors_allocated;
- p = (struct ct_color *) xmalloc (sizeof *p);
+ p = xmalloc (sizeof *p);
p->r = r;
p->g = g;
p->b = b;
table. If not already present, allocate it. Value is PIXEL. */
static unsigned long
-lookup_pixel_color (f, pixel)
- struct frame *f;
- unsigned long pixel;
+lookup_pixel_color (struct frame *f, unsigned long pixel)
{
int i = pixel % CT_SIZE;
struct ct_color *p;
Colormap cmap;
int rc;
+ if (ct_colors_allocated_max <= ct_colors_allocated)
+ return FRAME_FOREGROUND_PIXEL (f);
+
#ifdef HAVE_X_WINDOWS
cmap = FRAME_X_COLORMAP (f);
color.pixel = pixel;
x_query_color (f, &color);
rc = x_alloc_nearest_color (f, cmap, &color);
#else
- BLOCK_INPUT;
+ block_input ();
cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
color.pixel = pixel;
XQueryColor (NULL, cmap, &color);
rc = x_alloc_nearest_color (f, cmap, &color);
- UNBLOCK_INPUT;
+ unblock_input ();
#endif /* HAVE_X_WINDOWS */
if (rc)
{
++ct_colors_allocated;
- p = (struct ct_color *) xmalloc (sizeof *p);
+ p = xmalloc (sizeof *p);
p->r = color.red;
p->g = color.green;
p->b = color.blue;
allocated via xmalloc. Set *N to the number of colors. */
static unsigned long *
-colors_in_color_table (n)
- int *n;
+colors_in_color_table (int *n)
{
int i, j;
struct ct_color *p;
}
else
{
- colors = (unsigned long *) xmalloc (ct_colors_allocated
- * sizeof *colors);
+ colors = xmalloc (ct_colors_allocated * sizeof *colors);
*n = ct_colors_allocated;
for (i = j = 0; i < CT_SIZE; ++i)
#else /* COLOR_TABLE_SUPPORT */
static unsigned long
-lookup_rgb_color (f, r, g, b)
- struct frame *f;
- int r, g, b;
+lookup_rgb_color (struct frame *f, int r, int g, int b)
{
unsigned long pixel;
}
static void
-init_color_table ()
+init_color_table (void)
{
}
#endif /* COLOR_TABLE_SUPPORT */
Algorithms
***********************************************************************/
-static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
-static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
-static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
+static XColor *x_to_xcolors (struct frame *, struct image *, int);
+static void x_from_xcolors (struct frame *, struct image *, XColor *);
+static void x_detect_edges (struct frame *, struct image *, int[9], int);
#ifdef HAVE_NTGUI
static void XPutPixel (XImagePtr , int, int, COLORREF);
#endif /* HAVE_NTGUI */
-/* Non-zero means draw a cross on images having `:conversion
- disabled'. */
-
-int cross_disabled_images;
-
/* Edge detection matrices for different edge-detection
strategies. */
allocated with xmalloc; it must be freed by the caller. */
static XColor *
-x_to_xcolors (f, img, rgb_p)
- struct frame *f;
- struct image *img;
- int rgb_p;
+x_to_xcolors (struct frame *f, struct image *img, int rgb_p)
{
int x, y;
XColor *colors, *p;
HGDIOBJ prev;
#endif /* HAVE_NTGUI */
- colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
+ if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof *colors / img->width < img->height)
+ memory_full (SIZE_MAX);
+ colors = xmalloc (sizeof *colors * img->width * img->height);
#ifndef HAVE_NTGUI
/* Get the X image IMG->pixmap. */
p = colors;
for (y = 0; y < img->height; ++y)
{
- XColor *row = p;
-
#if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
+ XColor *row = p;
for (x = 0; x < img->width; ++x, ++p)
p->pixel = GET_PIXEL (ximg, x, y);
if (rgb_p)
stored in ximg->data. */
static void
-XPutPixel (ximg, x, y, color)
- XImagePtr ximg;
- int x, y;
- COLORREF color;
+XPutPixel (XImagePtr ximg, int x, int y, COLORREF color)
{
int width = ximg->info.bmiHeader.biWidth;
- int height = ximg->info.bmiHeader.biHeight;
unsigned char * pixel;
/* True color images. */
COLORS will be freed; an existing IMG->pixmap will be freed, too. */
static void
-x_from_xcolors (f, img, colors)
- struct frame *f;
- struct image *img;
- XColor *colors;
+x_from_xcolors (struct frame *f, struct image *img, XColor *colors)
{
int x, y;
XImagePtr oimg = NULL;
outgoing image. */
static void
-x_detect_edges (f, img, matrix, color_adjust)
- struct frame *f;
- struct image *img;
- int matrix[9], color_adjust;
+x_detect_edges (struct frame *f, struct image *img, int *matrix, int color_adjust)
{
XColor *colors = x_to_xcolors (f, img, 1);
XColor *new, *p;
#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
- new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
+ if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof *new / img->width < img->height)
+ memory_full (SIZE_MAX);
+ new = xmalloc (sizeof *new * img->width * img->height);
for (y = 0; y < img->height; ++y)
{
for (x = 1; x < img->width - 1; ++x, ++p)
{
- int r, g, b, y1, x1;
+ int r, g, b, yy, xx;
r = g = b = i = 0;
- for (y1 = y - 1; y1 < y + 2; ++y1)
- for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
+ for (yy = y - 1; yy < y + 2; ++yy)
+ for (xx = x - 1; xx < x + 2; ++xx, ++i)
if (matrix[i])
{
- XColor *t = COLOR (colors, x1, y1);
+ XColor *t = COLOR (colors, xx, yy);
r += matrix[i] * t->red;
g += matrix[i] * t->green;
b += matrix[i] * t->blue;
on frame F. */
static void
-x_emboss (f, img)
- struct frame *f;
- struct image *img;
+x_emboss (struct frame *f, struct image *img)
{
x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
}
to draw disabled buttons, for example. */
static void
-x_laplace (f, img)
- struct frame *f;
- struct image *img;
+x_laplace (struct frame *f, struct image *img)
{
x_detect_edges (f, img, laplace_matrix, 45000);
}
number. */
static void
-x_edge_detection (f, img, matrix, color_adjust)
- struct frame *f;
- struct image *img;
- Lisp_Object matrix, color_adjust;
+x_edge_detection (struct frame *f, struct image *img, Lisp_Object matrix,
+ Lisp_Object color_adjust)
{
int i = 0;
int trans[9];
color_adjust = make_number (0xffff / 2);
if (i == 9 && NUMBERP (color_adjust))
- x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
+ x_detect_edges (f, img, trans, XFLOATINT (color_adjust));
}
/* Transform image IMG on frame F so that it looks disabled. */
static void
-x_disable_image (f, img)
- struct frame *f;
- struct image *img;
+x_disable_image (struct frame *f, struct image *img)
{
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
#ifdef HAVE_NTGUI
if (n_planes < 2 || cross_disabled_images)
{
#ifndef HAVE_NTGUI
- Display *dpy = FRAME_X_DISPLAY (f);
- GC gc;
-
#ifndef HAVE_NS /* TODO: NS support, however this not needed for toolbars */
#define MaskForeground(f) WHITE_PIX_DEFAULT (f)
- gc = XCreateGC (dpy, img->pixmap, 0, NULL);
+ Display *dpy = FRAME_X_DISPLAY (f);
+ GC gc = XCreateGC (dpy, img->pixmap, 0, NULL);
XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
XDrawLine (dpy, img->pixmap, gc, 0, 0,
img->width - 1, img->height - 1);
heuristically. Value is non-zero if successful. */
static int
-x_build_heuristic_mask (f, img, how)
- struct frame *f;
- struct image *img;
- Lisp_Object how;
+x_build_heuristic_mask (struct frame *f, struct image *img, Lisp_Object how)
{
XImagePtr_or_DC ximg;
#ifndef HAVE_NTGUI
#else
/* Create the bit array serving as mask. */
row_width = (img->width + 7) / 8;
- mask_img = xmalloc (row_width * img->height);
- bzero (mask_img, row_width * img->height);
+ mask_img = xzalloc (row_width * img->height);
/* Create a memory device context for IMG->pixmap. */
frame_dc = get_frame_dc (f);
? PIX_MASK_DRAW : PIX_MASK_RETAIN));
#else
if (XGetPixel (ximg, x, y) == bg)
- ns_set_alpha(ximg, x, y, 0);
+ ns_set_alpha (ximg, x, y, 0);
#endif /* HAVE_NS */
#ifndef HAVE_NS
/* Fill in the background_transparent field while we have the mask handy. */
PBM (mono, gray, color)
***********************************************************************/
-static int pbm_image_p P_ ((Lisp_Object object));
-static int pbm_load P_ ((struct frame *f, struct image *img));
-static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
+static int pbm_image_p (Lisp_Object object);
+static int pbm_load (struct frame *f, struct image *img);
+static int pbm_scan_number (unsigned char **, unsigned char *);
/* The symbol `pbm' identifying images of this type. */
-Lisp_Object Qpbm;
+static Lisp_Object Qpbm;
/* Indices of image specification fields in gs_format, below. */
{":file", IMAGE_STRING_VALUE, 0},
{":data", IMAGE_STRING_VALUE, 0},
{":ascent", IMAGE_ASCENT_VALUE, 0},
- {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
+ {":margin", IMAGE_NON_NEGATIVE_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},
pbm_image_p,
pbm_load,
x_clear_image,
+ NULL,
NULL
};
/* Return non-zero if OBJECT is a valid PBM image specification. */
static int
-pbm_image_p (object)
- Lisp_Object object;
+pbm_image_p (Lisp_Object object)
{
struct image_keyword fmt[PBM_LAST];
- bcopy (pbm_format, fmt, sizeof fmt);
+ memcpy (fmt, pbm_format, sizeof fmt);
if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
return 0;
end of input. */
static int
-pbm_scan_number (s, end)
- unsigned char **s, *end;
+pbm_scan_number (unsigned char **s, unsigned char *end)
{
int c = 0, val = -1;
while (*s < end)
{
/* Skip white-space. */
- while (*s < end && (c = *(*s)++, isspace (c)))
+ while (*s < end && (c = *(*s)++, c_isspace (c)))
;
if (c == '#')
while (*s < end && (c = *(*s)++, c != '\n'))
;
}
- else if (isdigit (c))
+ else if (c_isdigit (c))
{
/* Read decimal number. */
val = c - '0';
- while (*s < end && (c = *(*s)++, isdigit (c)))
+ while (*s < end && (c = *(*s)++, c_isdigit (c)))
val = 10 * val + c - '0';
break;
}
occurred. *SIZE is set to the size of the file. */
static char *
-pbm_read_file (file, size)
- Lisp_Object file;
- int *size;
+pbm_read_file (Lisp_Object file, int *size)
{
FILE *fp = NULL;
char *buf = NULL;
if (stat (SDATA (file), &st) == 0
&& (fp = fopen (SDATA (file), "rb")) != NULL
- && (buf = (char *) xmalloc (st.st_size),
+ && 0 <= st.st_size && st.st_size <= min (PTRDIFF_MAX, SIZE_MAX)
+ && (buf = xmalloc (st.st_size),
fread (buf, 1, st.st_size, fp) == st.st_size))
{
*size = st.st_size;
/* Load PBM image IMG for use on frame F. */
static int
-pbm_load (f, img)
- struct frame *f;
- struct image *img;
+pbm_load (struct frame *f, struct image *img)
{
int raw_p, x, y;
int width, height, max_color_idx = 0;
XImagePtr ximg;
Lisp_Object file, specified_file;
enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
- struct gcpro gcpro1;
unsigned char *contents = NULL;
unsigned char *end, *p;
- int size;
+ ptrdiff_t size;
specified_file = image_spec_value (img->spec, QCfile, NULL);
- file = Qnil;
- GCPRO1 (file);
if (STRINGP (specified_file))
{
if (!STRINGP (file))
{
image_error ("Cannot find image file `%s'", specified_file, Qnil);
- UNGCPRO;
return 0;
}
- contents = slurp_file (SDATA (file), &size);
+ contents = slurp_file (SSDATA (file), &size);
if (contents == NULL)
{
image_error ("Error reading `%s'", file, Qnil);
- UNGCPRO;
return 0;
}
{
Lisp_Object data;
data = image_spec_value (img->spec, QCdata, NULL);
+ if (!STRINGP (data))
+ {
+ image_error ("Invalid image data `%s'", data, Qnil);
+ return 0;
+ }
p = SDATA (data);
end = p + SBYTES (data);
}
image_error ("Not a PBM image: `%s'", img->spec, Qnil);
error:
xfree (contents);
- UNGCPRO;
return 0;
}
unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
/* Parse the image specification. */
- bcopy (pbm_format, fmt, sizeof fmt);
+ memcpy (fmt, pbm_format, sizeof fmt);
parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
/* Get foreground and background colors, maybe allocate colors. */
img->width = width;
img->height = height; */
- UNGCPRO;
xfree (contents);
return 1;
}
/* Function prototypes. */
-static int png_image_p P_ ((Lisp_Object object));
-static int png_load P_ ((struct frame *f, struct image *img));
+static int png_image_p (Lisp_Object object);
+static int png_load (struct frame *f, struct image *img);
/* The symbol `png' identifying images of this type. */
-Lisp_Object Qpng;
+static Lisp_Object Qpng;
/* Indices of image specification fields in png_format, below. */
{":data", IMAGE_STRING_VALUE, 0},
{":file", IMAGE_STRING_VALUE, 0},
{":ascent", IMAGE_ASCENT_VALUE, 0},
- {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
+ {":margin", IMAGE_NON_NEGATIVE_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},
{":background", IMAGE_STRING_OR_NIL_VALUE, 0}
};
+#ifdef HAVE_NTGUI
+static int init_png_functions (void);
+#else
+#define init_png_functions NULL
+#endif
+
/* Structure describing the image type `png'. */
static struct image_type png_type =
png_image_p,
png_load,
x_clear_image,
+ init_png_functions,
NULL
};
/* Return non-zero if OBJECT is a valid PNG image specification. */
static int
-png_image_p (object)
- Lisp_Object object;
+png_image_p (Lisp_Object object)
{
struct image_keyword fmt[PNG_LAST];
- bcopy (png_format, fmt, sizeof fmt);
+ memcpy (fmt, png_format, sizeof fmt);
if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
return 0;
#ifdef HAVE_NTGUI
/* PNG library details. */
-DEF_IMGLIB_FN (png_voidp, png_get_io_ptr);
-DEF_IMGLIB_FN (int, png_sig_cmp);
-DEF_IMGLIB_FN (png_structp, png_create_read_struct);
-DEF_IMGLIB_FN (png_infop, png_create_info_struct);
-DEF_IMGLIB_FN (void, png_destroy_read_struct);
-DEF_IMGLIB_FN (void, png_set_read_fn);
-DEF_IMGLIB_FN (void, png_set_sig_bytes);
-DEF_IMGLIB_FN (void, png_read_info);
-DEF_IMGLIB_FN (png_uint_32, png_get_IHDR);
-DEF_IMGLIB_FN (png_uint_32, png_get_valid);
-DEF_IMGLIB_FN (void, png_set_strip_16);
-DEF_IMGLIB_FN (void, png_set_expand);
-DEF_IMGLIB_FN (void, png_set_gray_to_rgb);
-DEF_IMGLIB_FN (void, png_set_background);
-DEF_IMGLIB_FN (png_uint_32, png_get_bKGD);
-DEF_IMGLIB_FN (void, png_read_update_info);
-DEF_IMGLIB_FN (png_byte, png_get_channels);
-DEF_IMGLIB_FN (png_size_t, png_get_rowbytes);
-DEF_IMGLIB_FN (void, png_read_image);
-DEF_IMGLIB_FN (void, png_read_end);
-DEF_IMGLIB_FN (void, png_error);
+DEF_IMGLIB_FN (png_voidp, png_get_io_ptr, (png_structp));
+DEF_IMGLIB_FN (int, png_sig_cmp, (png_bytep, png_size_t, png_size_t));
+DEF_IMGLIB_FN (png_structp, png_create_read_struct, (png_const_charp, png_voidp,
+ png_error_ptr, png_error_ptr));
+DEF_IMGLIB_FN (png_infop, png_create_info_struct, (png_structp));
+DEF_IMGLIB_FN (void, png_destroy_read_struct, (png_structpp, png_infopp, png_infopp));
+DEF_IMGLIB_FN (void, png_set_read_fn, (png_structp, png_voidp, png_rw_ptr));
+DEF_IMGLIB_FN (void, png_set_sig_bytes, (png_structp, int));
+DEF_IMGLIB_FN (void, png_read_info, (png_structp, png_infop));
+DEF_IMGLIB_FN (png_uint_32, png_get_IHDR, (png_structp, png_infop,
+ png_uint_32 *, png_uint_32 *,
+ int *, int *, int *, int *, int *));
+DEF_IMGLIB_FN (png_uint_32, png_get_valid, (png_structp, png_infop, png_uint_32));
+DEF_IMGLIB_FN (void, png_set_strip_16, (png_structp));
+DEF_IMGLIB_FN (void, png_set_expand, (png_structp));
+DEF_IMGLIB_FN (void, png_set_gray_to_rgb, (png_structp));
+DEF_IMGLIB_FN (void, png_set_background, (png_structp, png_color_16p,
+ int, int, double));
+DEF_IMGLIB_FN (png_uint_32, png_get_bKGD, (png_structp, png_infop, png_color_16p *));
+DEF_IMGLIB_FN (void, png_read_update_info, (png_structp, png_infop));
+DEF_IMGLIB_FN (png_byte, png_get_channels, (png_structp, png_infop));
+DEF_IMGLIB_FN (png_size_t, png_get_rowbytes, (png_structp, png_infop));
+DEF_IMGLIB_FN (void, png_read_image, (png_structp, png_bytepp));
+DEF_IMGLIB_FN (void, png_read_end, (png_structp, png_infop));
+DEF_IMGLIB_FN (void, png_error, (png_structp, png_const_charp));
#if (PNG_LIBPNG_VER >= 10500)
-DEF_IMGLIB_FN (void, png_longjmp);
-DEF_IMGLIB_FN (jmp_buf *, png_set_longjmp_fn);
+DEF_IMGLIB_FN (void, png_longjmp, (png_structp, int));
+DEF_IMGLIB_FN (jmp_buf *, png_set_longjmp_fn, (png_structp, png_longjmp_ptr, size_t));
#endif /* libpng version >= 1.5 */
static int
-init_png_functions (Lisp_Object libraries)
+init_png_functions (void)
{
HMODULE library;
- /* Try loading libpng under probable names. */
- if (!(library = w32_delayed_load (libraries, Qpng)))
+ if (!(library = w32_delayed_load (Qpng)))
return 0;
LOAD_IMGLIB_FN (library, png_get_io_ptr);
#endif /* HAVE_NTGUI */
+/* Possibly inefficient/inexact substitutes for _setjmp and _longjmp.
+ Do not use sys_setjmp, as PNG supports only jmp_buf. The _longjmp
+ substitute may munge the signal mask, but that should be OK here.
+ MinGW (MS-Windows) uses _setjmp and defines setjmp to _setjmp in
+ the system header setjmp.h; don't mess up that. */
+#ifndef HAVE__SETJMP
+# define _setjmp(j) setjmp (j)
+# define _longjmp longjmp
+#endif
#if (PNG_LIBPNG_VER < 10500)
-#define PNG_LONGJMP(ptr) (longjmp ((ptr)->jmpbuf, 1))
+#define PNG_LONGJMP(ptr) (_longjmp ((ptr)->jmpbuf, 1))
#define PNG_JMPBUF(ptr) ((ptr)->jmpbuf)
#else
/* In libpng version 1.5, the jmpbuf member is hidden. (Bug#7908) */
#define PNG_LONGJMP(ptr) (fn_png_longjmp ((ptr), 1))
#define PNG_JMPBUF(ptr) \
- (*fn_png_set_longjmp_fn((ptr), longjmp, sizeof (jmp_buf)))
+ (*fn_png_set_longjmp_fn ((ptr), _longjmp, sizeof (jmp_buf)))
#endif
/* Error and warning handlers installed when the PNG library
is initialized. */
-static void
-my_png_error (png_ptr, msg)
- png_struct *png_ptr;
- char *msg;
+static _Noreturn void
+my_png_error (png_struct *png_ptr, const char *msg)
{
- xassert (png_ptr != NULL);
+ eassert (png_ptr != NULL);
/* Avoid compiler warning about deprecated direct access to
png_ptr's fields in libpng versions 1.4.x. */
image_error ("PNG error: %s", build_string (msg), Qnil);
static void
-my_png_warning (png_ptr, msg)
- png_struct *png_ptr;
- char *msg;
+my_png_warning (png_struct *png_ptr, const char *msg)
{
- xassert (png_ptr != NULL);
+ eassert (png_ptr != NULL);
image_error ("PNG warning: %s", build_string (msg), Qnil);
}
struct png_memory_storage
{
unsigned char *bytes; /* The data */
- size_t len; /* How big is it? */
- int index; /* Where are we? */
+ ptrdiff_t len; /* How big is it? */
+ ptrdiff_t index; /* Where are we? */
};
bytes from the input to DATA. */
static void
-png_read_from_memory (png_ptr, data, length)
- png_structp png_ptr;
- png_bytep data;
- png_size_t length;
+png_read_from_memory (png_structp png_ptr, png_bytep data, png_size_t length)
{
struct png_memory_storage *tbr
= (struct png_memory_storage *) fn_png_get_io_ptr (png_ptr);
if (length > tbr->len - tbr->index)
fn_png_error (png_ptr, "Read error");
- bcopy (tbr->bytes + tbr->index, data, length);
+ memcpy (data, tbr->bytes + tbr->index, length);
tbr->index = tbr->index + length;
}
bytes from the input to DATA. */
static void
-png_read_from_file (png_ptr, data, length)
- png_structp png_ptr;
- png_bytep data;
- png_size_t length;
+png_read_from_file (png_structp png_ptr, png_bytep data, png_size_t length)
{
FILE *fp = (FILE *) fn_png_get_io_ptr (png_ptr);
/* Load PNG image IMG for use on frame F. Value is non-zero if
successful. */
+struct png_load_context
+{
+ /* These are members so that longjmp doesn't munge local variables. */
+ png_struct *png_ptr;
+ png_info *info_ptr;
+ png_info *end_info;
+ FILE *fp;
+ png_byte *pixels;
+ png_byte **rows;
+};
+
static int
-png_load (f, img)
- struct frame *f;
- struct image *img;
+png_load_body (struct frame *f, struct image *img, struct png_load_context *c)
{
Lisp_Object file, specified_file;
Lisp_Object specified_data;
- int x, y, i;
+ int x, y;
+ ptrdiff_t i;
XImagePtr ximg, mask_img = NULL;
- struct gcpro gcpro1;
- png_struct *png_ptr = NULL;
+ png_struct *png_ptr;
png_info *info_ptr = NULL, *end_info = NULL;
- FILE *volatile fp = NULL;
+ FILE *fp = NULL;
png_byte sig[8];
- png_byte * volatile pixels = NULL;
- png_byte ** volatile rows = NULL;
+ png_byte *pixels = NULL;
+ png_byte **rows = NULL;
png_uint_32 width, height;
int bit_depth, color_type, interlace_type;
png_byte channels;
/* Find out what file to load. */
specified_file = image_spec_value (img->spec, QCfile, NULL);
specified_data = image_spec_value (img->spec, QCdata, NULL);
- file = Qnil;
- GCPRO1 (file);
if (NILP (specified_data))
{
if (!STRINGP (file))
{
image_error ("Cannot find image file `%s'", specified_file, Qnil);
- UNGCPRO;
return 0;
}
/* Open the image file. */
- fp = fopen (SDATA (file), "rb");
+ fp = fopen (SSDATA (file), "rb");
if (!fp)
{
image_error ("Cannot open image file `%s'", file, Qnil);
- UNGCPRO;
return 0;
}
|| fn_png_sig_cmp (sig, 0, sizeof sig))
{
image_error ("Not a PNG file: `%s'", file, Qnil);
- UNGCPRO;
fclose (fp);
return 0;
}
}
else
{
+ if (!STRINGP (specified_data))
+ {
+ image_error ("Invalid image data `%s'", specified_data, Qnil);
+ return 0;
+ }
+
/* Read from memory. */
tbr.bytes = SDATA (specified_data);
tbr.len = SBYTES (specified_data);
|| fn_png_sig_cmp (tbr.bytes, 0, sizeof sig))
{
image_error ("Not a PNG image: `%s'", img->spec, Qnil);
- UNGCPRO;
return 0;
}
png_ptr = fn_png_create_read_struct (PNG_LIBPNG_VER_STRING,
NULL, my_png_error,
my_png_warning);
- if (!png_ptr)
+ if (png_ptr)
{
- if (fp) fclose (fp);
- UNGCPRO;
- return 0;
+ info_ptr = fn_png_create_info_struct (png_ptr);
+ end_info = fn_png_create_info_struct (png_ptr);
}
- info_ptr = fn_png_create_info_struct (png_ptr);
- if (!info_ptr)
+ c->png_ptr = png_ptr;
+ c->info_ptr = info_ptr;
+ c->end_info = end_info;
+ c->fp = fp;
+ c->pixels = pixels;
+ c->rows = rows;
+
+ if (! (info_ptr && end_info))
{
- fn_png_destroy_read_struct (&png_ptr, NULL, NULL);
- if (fp) fclose (fp);
- UNGCPRO;
- return 0;
+ fn_png_destroy_read_struct (&c->png_ptr, &c->info_ptr, &c->end_info);
+ png_ptr = 0;
}
-
- end_info = fn_png_create_info_struct (png_ptr);
- if (!end_info)
+ if (! png_ptr)
{
- fn_png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
if (fp) fclose (fp);
- UNGCPRO;
return 0;
}
/* Set error jump-back. We come back here when the PNG library
detects an error. */
- if (setjmp (PNG_JMPBUF (png_ptr)))
+ if (_setjmp (PNG_JMPBUF (png_ptr)))
{
error:
- if (png_ptr)
- fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
- xfree (pixels);
- xfree (rows);
- if (fp) fclose (fp);
- UNGCPRO;
+ if (c->png_ptr)
+ fn_png_destroy_read_struct (&c->png_ptr, &c->info_ptr, &c->end_info);
+ xfree (c->pixels);
+ xfree (c->rows);
+ if (c->fp)
+ fclose (c->fp);
return 0;
}
+ /* Silence a bogus diagnostic; see GCC bug 54561. */
+ IF_LINT (fp = c->fp);
+
/* Read image info. */
if (!NILP (specified_data))
fn_png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
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))
+ if (! (width <= INT_MAX && height <= INT_MAX
+ && check_image_size (f, width, height)))
{
image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
goto error;
}
+
+ /* Create the X image and pixmap now, so that the work below can be
+ omitted if the image is too large for X. */
+ if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
+ &img->pixmap))
+ 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))
/* The user specified `:background', use that. */
{
XColor color;
- if (x_defined_color (f, SDATA (specified_bg), &color, 0))
+ if (x_defined_color (f, SSDATA (specified_bg), &color, 0))
{
png_color_16 user_bg;
- bzero (&user_bg, sizeof user_bg);
+ memset (&user_bg, 0, sizeof user_bg);
user_bg.red = color.red >> shift;
user_bg.green = color.green >> shift;
user_bg.blue = color.blue >> shift;
color.pixel = FRAME_BACKGROUND_PIXEL (f);
x_query_color (f, &color);
- bzero (&frame_background, sizeof frame_background);
+ memset (&frame_background, 0, sizeof frame_background);
frame_background.red = color.red >> shift;
frame_background.green = color.green >> shift;
frame_background.blue = color.blue >> shift;
images with alpha channel, i.e. RGBA. If conversions above were
sufficient we should only have 3 or 4 channels here. */
channels = fn_png_get_channels (png_ptr, info_ptr);
- xassert (channels == 3 || channels == 4);
+ eassert (channels == 3 || channels == 4);
/* Number of bytes needed for one row of the image. */
row_bytes = fn_png_get_rowbytes (png_ptr, info_ptr);
/* Allocate memory for the image. */
- pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
- rows = (png_byte **) xmalloc (height * sizeof *rows);
+ if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof *rows < height
+ || min (PTRDIFF_MAX, SIZE_MAX) / sizeof *pixels / height < row_bytes)
+ memory_full (SIZE_MAX);
+ c->pixels = pixels = xmalloc (sizeof *pixels * row_bytes * height);
+ c->rows = rows = xmalloc (height * sizeof *rows);
for (i = 0; i < height; ++i)
rows[i] = pixels + i * row_bytes;
if (fp)
{
fclose (fp);
- fp = NULL;
+ c->fp = NULL;
}
- /* Create the X image and pixmap. */
- if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
- &img->pixmap))
- goto error;
-
/* Create an image and pixmap serving as mask if the PNG image
contains an alpha channel. */
if (channels == 4
for (x = 0; x < width; ++x)
{
- unsigned r, g, b;
+ int r, g, b;
r = *p++ << 8;
g = *p++ << 8;
#endif /* COLOR_TABLE_SUPPORT */
/* Clean up. */
- fn_png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
+ fn_png_destroy_read_struct (&c->png_ptr, &c->info_ptr, &c->end_info);
xfree (rows);
xfree (pixels);
x_destroy_x_image (mask_img);
}
- UNGCPRO;
return 1;
}
+static int
+png_load (struct frame *f, struct image *img)
+{
+ struct png_load_context c;
+ return png_load_body (f, img, &c);
+}
+
#else /* HAVE_PNG */
#ifdef HAVE_NS
static int
png_load (struct frame *f, struct image *img)
{
- return ns_load_image(f, img,
- image_spec_value (img->spec, QCfile, NULL),
- image_spec_value (img->spec, QCdata, NULL));
+ return ns_load_image (f, img,
+ image_spec_value (img->spec, QCfile, NULL),
+ image_spec_value (img->spec, QCdata, NULL));
}
#endif /* HAVE_NS */
#if defined (HAVE_JPEG) || defined (HAVE_NS)
-static int jpeg_image_p P_ ((Lisp_Object object));
-static int jpeg_load P_ ((struct frame *f, struct image *img));
+static int jpeg_image_p (Lisp_Object object);
+static int jpeg_load (struct frame *f, struct image *img);
/* The symbol `jpeg' identifying images of this type. */
-Lisp_Object Qjpeg;
+static Lisp_Object Qjpeg;
/* Indices of image specification fields in gs_format, below. */
{":data", IMAGE_STRING_VALUE, 0},
{":file", IMAGE_STRING_VALUE, 0},
{":ascent", IMAGE_ASCENT_VALUE, 0},
- {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
+ {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
{":relief", IMAGE_INTEGER_VALUE, 0},
{":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
{":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
{":background", IMAGE_STRING_OR_NIL_VALUE, 0}
};
+#ifdef HAVE_NTGUI
+static int init_jpeg_functions (void);
+#else
+#define init_jpeg_functions NULL
+#endif
+
/* Structure describing the image type `jpeg'. */
static struct image_type jpeg_type =
jpeg_image_p,
jpeg_load,
x_clear_image,
+ init_jpeg_functions,
NULL
};
/* Return non-zero if OBJECT is a valid JPEG image specification. */
static int
-jpeg_image_p (object)
- Lisp_Object object;
+jpeg_image_p (Lisp_Object object)
{
struct image_keyword fmt[JPEG_LAST];
- bcopy (jpeg_format, fmt, sizeof fmt);
+ memcpy (fmt, jpeg_format, sizeof fmt);
if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
return 0;
/* Work around a warning about HAVE_STDLIB_H being redefined in
jconfig.h. */
#ifdef HAVE_STDLIB_H
-#define HAVE_STDLIB_H_1
#undef HAVE_STDLIB_H
#endif /* HAVE_STLIB_H */
#ifdef HAVE_NTGUI
/* JPEG library details. */
-DEF_IMGLIB_FN (void, jpeg_CreateDecompress);
-DEF_IMGLIB_FN (boolean, jpeg_start_decompress);
-DEF_IMGLIB_FN (boolean, jpeg_finish_decompress);
-DEF_IMGLIB_FN (void, jpeg_destroy_decompress);
-DEF_IMGLIB_FN (int, jpeg_read_header);
-DEF_IMGLIB_FN (JDIMENSION, jpeg_read_scanlines);
-DEF_IMGLIB_FN (struct jpeg_error_mgr *, jpeg_std_error);
-DEF_IMGLIB_FN (boolean, jpeg_resync_to_restart);
+DEF_IMGLIB_FN (void, jpeg_CreateDecompress, (j_decompress_ptr, int, size_t));
+DEF_IMGLIB_FN (boolean, jpeg_start_decompress, (j_decompress_ptr));
+DEF_IMGLIB_FN (boolean, jpeg_finish_decompress, (j_decompress_ptr));
+DEF_IMGLIB_FN (void, jpeg_destroy_decompress, (j_decompress_ptr));
+DEF_IMGLIB_FN (int, jpeg_read_header, (j_decompress_ptr, boolean));
+DEF_IMGLIB_FN (JDIMENSION, jpeg_read_scanlines, (j_decompress_ptr, JSAMPARRAY, JDIMENSION));
+DEF_IMGLIB_FN (struct jpeg_error_mgr *, jpeg_std_error, (struct jpeg_error_mgr *));
+DEF_IMGLIB_FN (boolean, jpeg_resync_to_restart, (j_decompress_ptr, int));
static int
-init_jpeg_functions (Lisp_Object libraries)
+init_jpeg_functions (void)
{
HMODULE library;
- if (!(library = w32_delayed_load (libraries, Qjpeg)))
+ if (!(library = w32_delayed_load (Qjpeg)))
return 0;
LOAD_IMGLIB_FN (library, jpeg_finish_decompress);
/* 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)
- j_decompress_ptr cinfo;
- int desired;
+jpeg_resync_to_restart_wrapper (j_decompress_ptr cinfo, int desired)
{
return fn_jpeg_resync_to_restart (cinfo, desired);
}
#else
-#define fn_jpeg_CreateDecompress(a,b,c) jpeg_create_decompress(a)
+#define fn_jpeg_CreateDecompress(a,b,c) jpeg_create_decompress (a)
#define fn_jpeg_start_decompress jpeg_start_decompress
#define fn_jpeg_finish_decompress jpeg_finish_decompress
#define fn_jpeg_destroy_decompress jpeg_destroy_decompress
struct my_jpeg_error_mgr
{
struct jpeg_error_mgr pub;
- jmp_buf setjmp_buffer;
+ sys_jmp_buf setjmp_buffer;
+
+ /* The remaining members are so that longjmp doesn't munge local
+ variables. */
+ struct jpeg_decompress_struct cinfo;
+ enum
+ {
+ MY_JPEG_ERROR_EXIT,
+ MY_JPEG_INVALID_IMAGE_SIZE,
+ MY_JPEG_CANNOT_CREATE_X
+ } failure_code;
+#ifdef lint
+ FILE *fp;
+#endif
};
-static void
-my_error_exit (cinfo)
- j_common_ptr cinfo;
+static _Noreturn void
+my_error_exit (j_common_ptr cinfo)
{
struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
- longjmp (mgr->setjmp_buffer, 1);
+ mgr->failure_code = MY_JPEG_ERROR_EXIT;
+ sys_longjmp (mgr->setjmp_buffer, 1);
}
libjpeg.doc from the JPEG lib distribution. */
static void
-our_common_init_source (cinfo)
- j_decompress_ptr cinfo;
+our_common_init_source (j_decompress_ptr cinfo)
{
}
jpeg_finish_decompress() after all data has been processed. */
static void
-our_common_term_source (cinfo)
- j_decompress_ptr cinfo;
+our_common_term_source (j_decompress_ptr cinfo)
{
}
static JOCTET our_memory_buffer[2];
static boolean
-our_memory_fill_input_buffer (cinfo)
- j_decompress_ptr cinfo;
+our_memory_fill_input_buffer (j_decompress_ptr cinfo)
{
/* Insert a fake EOI marker. */
struct jpeg_source_mgr *src = cinfo->src;
is the JPEG data source manager. */
static void
-our_memory_skip_input_data (cinfo, num_bytes)
- j_decompress_ptr cinfo;
- long num_bytes;
+our_memory_skip_input_data (j_decompress_ptr cinfo, long int num_bytes)
{
struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
reading the image. */
static void
-jpeg_memory_src (cinfo, data, len)
- j_decompress_ptr cinfo;
- JOCTET *data;
- unsigned int len;
+jpeg_memory_src (j_decompress_ptr cinfo, JOCTET *data, ptrdiff_t len)
{
struct jpeg_source_mgr *src;
whenever more data is needed. The data is read from a FILE *. */
static boolean
-our_stdio_fill_input_buffer (cinfo)
- j_decompress_ptr cinfo;
+our_stdio_fill_input_buffer (j_decompress_ptr cinfo)
{
struct jpeg_stdio_mgr *src;
src = (struct jpeg_stdio_mgr *) cinfo->src;
if (!src->finished)
{
- size_t bytes;
+ ptrdiff_t bytes;
bytes = fread (src->buffer, 1, JPEG_STDIO_BUFFER_SIZE, src->file);
if (bytes > 0)
is the JPEG data source manager. */
static void
-our_stdio_skip_input_data (cinfo, num_bytes)
- j_decompress_ptr cinfo;
- long num_bytes;
+our_stdio_skip_input_data (j_decompress_ptr cinfo, long int num_bytes)
{
struct jpeg_stdio_mgr *src;
src = (struct jpeg_stdio_mgr *) cinfo->src;
reading the image. */
static void
-jpeg_file_src (cinfo, fp)
- j_decompress_ptr cinfo;
- FILE *fp;
+jpeg_file_src (j_decompress_ptr cinfo, FILE *fp)
{
struct jpeg_stdio_mgr *src;
from the JPEG lib. */
static int
-jpeg_load (f, img)
- struct frame *f;
- struct image *img;
+jpeg_load_body (struct frame *f, struct image *img,
+ struct my_jpeg_error_mgr *mgr)
{
- struct jpeg_decompress_struct cinfo;
- struct my_jpeg_error_mgr mgr;
Lisp_Object file, specified_file;
Lisp_Object specified_data;
- FILE * volatile fp = NULL;
+ FILE *fp = NULL;
JSAMPARRAY buffer;
int row_stride, x, y;
XImagePtr ximg = NULL;
- int rc;
unsigned long *colors;
int width, height;
- struct gcpro gcpro1;
/* Open the JPEG file. */
specified_file = image_spec_value (img->spec, QCfile, NULL);
specified_data = image_spec_value (img->spec, QCdata, NULL);
- file = Qnil;
- GCPRO1 (file);
if (NILP (specified_data))
{
if (!STRINGP (file))
{
image_error ("Cannot find image file `%s'", specified_file, Qnil);
- UNGCPRO;
return 0;
}
- fp = fopen (SDATA (file), "rb");
+ fp = fopen (SSDATA (file), "rb");
if (fp == NULL)
{
image_error ("Cannot open `%s'", file, Qnil);
- UNGCPRO;
return 0;
}
}
+ else if (!STRINGP (specified_data))
+ {
+ image_error ("Invalid image data `%s'", specified_data, Qnil);
+ return 0;
+ }
+
+ IF_LINT (mgr->fp = fp);
/* Customize libjpeg's error handling to call my_error_exit when an
error is detected. This function will perform a longjmp. */
- cinfo.err = fn_jpeg_std_error (&mgr.pub);
- mgr.pub.error_exit = my_error_exit;
-
- if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
+ mgr->cinfo.err = fn_jpeg_std_error (&mgr->pub);
+ mgr->pub.error_exit = my_error_exit;
+ if (sys_setjmp (mgr->setjmp_buffer))
{
- if (rc == 1)
+ switch (mgr->failure_code)
{
- /* Called from my_error_exit. Display a JPEG error. */
- char buffer[JMSG_LENGTH_MAX];
- cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
- image_error ("Error reading JPEG image `%s': %s", img->spec,
- build_string (buffer));
+ case MY_JPEG_ERROR_EXIT:
+ {
+ char buf[JMSG_LENGTH_MAX];
+ mgr->cinfo.err->format_message ((j_common_ptr) &mgr->cinfo, buf);
+ image_error ("Error reading JPEG image `%s': %s", img->spec,
+ build_string (buf));
+ break;
+ }
+
+ case MY_JPEG_INVALID_IMAGE_SIZE:
+ image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
+ break;
+
+ case MY_JPEG_CANNOT_CREATE_X:
+ break;
}
/* Close the input file and destroy the JPEG object. */
if (fp)
- fclose ((FILE *) fp);
- fn_jpeg_destroy_decompress (&cinfo);
+ fclose (fp);
+ fn_jpeg_destroy_decompress (&mgr->cinfo);
/* If we already have an XImage, free that. */
x_destroy_x_image (ximg);
/* Free pixmap and colors. */
x_clear_image (f, img);
-
- UNGCPRO;
return 0;
}
+ /* Silence a bogus diagnostic; see GCC bug 54561. */
+ IF_LINT (fp = mgr->fp);
+
/* Create the JPEG decompression object. Let it read from fp.
Read the JPEG image header. */
- fn_jpeg_CreateDecompress (&cinfo, JPEG_LIB_VERSION, sizeof (cinfo));
+ fn_jpeg_CreateDecompress (&mgr->cinfo, JPEG_LIB_VERSION, sizeof *&mgr->cinfo);
if (NILP (specified_data))
- jpeg_file_src (&cinfo, (FILE *) fp);
+ jpeg_file_src (&mgr->cinfo, fp);
else
- jpeg_memory_src (&cinfo, SDATA (specified_data),
+ jpeg_memory_src (&mgr->cinfo, SDATA (specified_data),
SBYTES (specified_data));
- fn_jpeg_read_header (&cinfo, 1);
+ fn_jpeg_read_header (&mgr->cinfo, 1);
/* Customize decompression so that color quantization will be used.
Start decompression. */
- cinfo.quantize_colors = 1;
- fn_jpeg_start_decompress (&cinfo);
- width = img->width = cinfo.output_width;
- height = img->height = cinfo.output_height;
+ mgr->cinfo.quantize_colors = 1;
+ fn_jpeg_start_decompress (&mgr->cinfo);
+ width = img->width = mgr->cinfo.output_width;
+ height = img->height = mgr->cinfo.output_height;
if (!check_image_size (f, width, height))
{
- image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
- longjmp (mgr.setjmp_buffer, 2);
+ mgr->failure_code = MY_JPEG_INVALID_IMAGE_SIZE;
+ sys_longjmp (mgr->setjmp_buffer, 1);
}
/* Create X image and pixmap. */
if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
- longjmp (mgr.setjmp_buffer, 2);
+ {
+ mgr->failure_code = MY_JPEG_CANNOT_CREATE_X;
+ sys_longjmp (mgr->setjmp_buffer, 1);
+ }
/* Allocate colors. When color quantization is used,
- cinfo.actual_number_of_colors has been set with the number of
- colors generated, and cinfo.colormap is a two-dimensional array
- of color indices in the range 0..cinfo.actual_number_of_colors.
+ mgr->cinfo.actual_number_of_colors has been set with the number of
+ colors generated, and mgr->cinfo.colormap is a two-dimensional array
+ of color indices in the range 0..mgr->cinfo.actual_number_of_colors.
No more than 255 colors will be generated. */
{
int i, ir, ig, ib;
- if (cinfo.out_color_components > 2)
+ if (mgr->cinfo.out_color_components > 2)
ir = 0, ig = 1, ib = 2;
- else if (cinfo.out_color_components > 1)
+ else if (mgr->cinfo.out_color_components > 1)
ir = 0, ig = 1, ib = 0;
else
ir = 0, ig = 0, ib = 0;
a default color, and we don't have to care about which colors
can be freed safely, and which can't. */
init_color_table ();
- colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
- * sizeof *colors);
+ colors = alloca (mgr->cinfo.actual_number_of_colors * sizeof *colors);
- for (i = 0; i < cinfo.actual_number_of_colors; ++i)
+ for (i = 0; i < mgr->cinfo.actual_number_of_colors; ++i)
{
/* Multiply RGB values with 255 because X expects RGB values
in the range 0..0xffff. */
- int r = cinfo.colormap[ir][i] << 8;
- int g = cinfo.colormap[ig][i] << 8;
- int b = cinfo.colormap[ib][i] << 8;
+ int r = mgr->cinfo.colormap[ir][i] << 8;
+ int g = mgr->cinfo.colormap[ig][i] << 8;
+ int b = mgr->cinfo.colormap[ib][i] << 8;
colors[i] = lookup_rgb_color (f, r, g, b);
}
}
/* Read pixels. */
- row_stride = width * cinfo.output_components;
- buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
- row_stride, 1);
+ row_stride = width * mgr->cinfo.output_components;
+ buffer = mgr->cinfo.mem->alloc_sarray ((j_common_ptr) &mgr->cinfo,
+ JPOOL_IMAGE, row_stride, 1);
for (y = 0; y < height; ++y)
{
- fn_jpeg_read_scanlines (&cinfo, buffer, 1);
- for (x = 0; x < cinfo.output_width; ++x)
+ fn_jpeg_read_scanlines (&mgr->cinfo, buffer, 1);
+ for (x = 0; x < mgr->cinfo.output_width; ++x)
XPutPixel (ximg, x, y, colors[buffer[0][x]]);
}
/* Clean up. */
- fn_jpeg_finish_decompress (&cinfo);
- fn_jpeg_destroy_decompress (&cinfo);
+ fn_jpeg_finish_decompress (&mgr->cinfo);
+ fn_jpeg_destroy_decompress (&mgr->cinfo);
if (fp)
- fclose ((FILE *) fp);
+ fclose (fp);
/* Maybe fill in the background field while we have ximg handy. */
if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
/* Put the image into the pixmap. */
x_put_x_image (f, ximg, img->pixmap, width, height);
x_destroy_x_image (ximg);
- UNGCPRO;
return 1;
}
+static int
+jpeg_load (struct frame *f, struct image *img)
+{
+ struct my_jpeg_error_mgr mgr;
+ return jpeg_load_body (f, img, &mgr);
+}
+
#else /* HAVE_JPEG */
#ifdef HAVE_NS
static int
jpeg_load (struct frame *f, struct image *img)
{
- return ns_load_image(f, img,
- image_spec_value (img->spec, QCfile, NULL),
- image_spec_value (img->spec, QCdata, NULL));
+ return ns_load_image (f, img,
+ image_spec_value (img->spec, QCfile, NULL),
+ image_spec_value (img->spec, QCdata, NULL));
}
#endif /* HAVE_NS */
#if defined (HAVE_TIFF) || defined (HAVE_NS)
-static int tiff_image_p P_ ((Lisp_Object object));
-static int tiff_load P_ ((struct frame *f, struct image *img));
+static int tiff_image_p (Lisp_Object object);
+static int tiff_load (struct frame *f, struct image *img);
/* The symbol `tiff' identifying images of this type. */
-Lisp_Object Qtiff;
+static Lisp_Object Qtiff;
/* Indices of image specification fields in tiff_format, below. */
{":data", IMAGE_STRING_VALUE, 0},
{":file", IMAGE_STRING_VALUE, 0},
{":ascent", IMAGE_ASCENT_VALUE, 0},
- {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
+ {":margin", IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR, 0},
{":relief", IMAGE_INTEGER_VALUE, 0},
{":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
{":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
{":index", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
};
+#ifdef HAVE_NTGUI
+static int init_tiff_functions (void);
+#else
+#define init_tiff_functions NULL
+#endif
+
/* Structure describing the image type `tiff'. */
static struct image_type tiff_type =
tiff_image_p,
tiff_load,
x_clear_image,
+ init_tiff_functions,
NULL
};
/* Return non-zero if OBJECT is a valid TIFF image specification. */
static int
-tiff_image_p (object)
- Lisp_Object object;
+tiff_image_p (Lisp_Object object)
{
struct image_keyword fmt[TIFF_LAST];
- bcopy (tiff_format, fmt, sizeof fmt);
+ memcpy (fmt, tiff_format, sizeof fmt);
if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
return 0;
#ifdef HAVE_NTGUI
/* TIFF library details. */
-DEF_IMGLIB_FN (TIFFErrorHandler, TIFFSetErrorHandler);
-DEF_IMGLIB_FN (TIFFErrorHandler, TIFFSetWarningHandler);
-DEF_IMGLIB_FN (TIFF *, TIFFOpen);
-DEF_IMGLIB_FN (TIFF *, TIFFClientOpen);
-DEF_IMGLIB_FN (int, TIFFGetField);
-DEF_IMGLIB_FN (int, TIFFReadRGBAImage);
-DEF_IMGLIB_FN (void, TIFFClose);
-DEF_IMGLIB_FN (int, TIFFSetDirectory);
+DEF_IMGLIB_FN (TIFFErrorHandler, TIFFSetErrorHandler, (TIFFErrorHandler));
+DEF_IMGLIB_FN (TIFFErrorHandler, TIFFSetWarningHandler, (TIFFErrorHandler));
+DEF_IMGLIB_FN (TIFF *, TIFFOpen, (const char *, const char *));
+DEF_IMGLIB_FN (TIFF *, TIFFClientOpen, (const char *, const char *, thandle_t,
+ TIFFReadWriteProc, TIFFReadWriteProc,
+ TIFFSeekProc, TIFFCloseProc, TIFFSizeProc,
+ TIFFMapFileProc, TIFFUnmapFileProc));
+DEF_IMGLIB_FN (int, TIFFGetField, (TIFF *, ttag_t, ...));
+DEF_IMGLIB_FN (int, TIFFReadRGBAImage, (TIFF *, uint32, uint32, uint32 *, int));
+DEF_IMGLIB_FN (void, TIFFClose, (TIFF *));
+DEF_IMGLIB_FN (int, TIFFSetDirectory, (TIFF *, tdir_t));
static int
-init_tiff_functions (Lisp_Object libraries)
+init_tiff_functions (void)
{
HMODULE library;
- if (!(library = w32_delayed_load (libraries, Qtiff)))
+ if (!(library = w32_delayed_load (Qtiff)))
return 0;
LOAD_IMGLIB_FN (library, TIFFSetErrorHandler);
typedef struct
{
unsigned char *bytes;
- size_t len;
- int index;
+ ptrdiff_t len;
+ ptrdiff_t index;
}
tiff_memory_source;
-static size_t
-tiff_read_from_memory (data, buf, size)
- thandle_t data;
- tdata_t buf;
- tsize_t size;
+static tsize_t
+tiff_read_from_memory (thandle_t data, tdata_t buf, tsize_t size)
{
tiff_memory_source *src = (tiff_memory_source *) data;
- if (size > src->len - src->index)
- return (size_t) -1;
- bcopy (src->bytes + src->index, buf, size);
+ size = min (size, src->len - src->index);
+ memcpy (buf, src->bytes + src->index, size);
src->index += size;
return size;
}
-static size_t
-tiff_write_from_memory (data, buf, size)
- thandle_t data;
- tdata_t buf;
- tsize_t size;
+static tsize_t
+tiff_write_from_memory (thandle_t data, tdata_t buf, tsize_t size)
{
- return (size_t) -1;
+ return -1;
}
static toff_t
-tiff_seek_in_memory (data, off, whence)
- thandle_t data;
- toff_t off;
- int whence;
+tiff_seek_in_memory (thandle_t data, toff_t off, int whence)
{
tiff_memory_source *src = (tiff_memory_source *) data;
- int idx;
+ ptrdiff_t idx;
switch (whence)
{
}
static int
-tiff_close_memory (data)
- thandle_t data;
+tiff_close_memory (thandle_t data)
{
/* NOOP */
return 0;
}
static int
-tiff_mmap_memory (data, pbase, psize)
- thandle_t data;
- tdata_t *pbase;
- toff_t *psize;
+tiff_mmap_memory (thandle_t data, tdata_t *pbase, toff_t *psize)
{
/* It is already _IN_ memory. */
return 0;
}
static void
-tiff_unmap_memory (data, base, size)
- thandle_t data;
- tdata_t base;
- toff_t size;
+tiff_unmap_memory (thandle_t data, tdata_t base, toff_t size)
{
/* We don't need to do this. */
}
static toff_t
-tiff_size_of_memory (data)
- thandle_t data;
+tiff_size_of_memory (thandle_t data)
{
return ((tiff_memory_source *) data)->len;
}
+/* GCC 3.x on x86 Windows targets has a bug that triggers an internal
+ compiler error compiling tiff_handler, see Bugzilla bug #17406
+ (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=17406). Declaring
+ this function as external works around that problem. */
+#if defined (__MINGW32__) && __GNUC__ == 3
+# define MINGW_STATIC
+#else
+# define MINGW_STATIC static
+#endif
+MINGW_STATIC void
+tiff_handler (const char *, const char *, const char *, va_list)
+ ATTRIBUTE_FORMAT_PRINTF (3, 0);
+MINGW_STATIC void
+tiff_handler (const char *log_format, const char *title,
+ const char *format, va_list ap)
+{
+ /* doprnt is not suitable here, as TIFF handlers are called from
+ libtiff and are passed arbitrary printf directives. Instead, use
+ vsnprintf, taking care to be portable to nonstandard environments
+ where vsnprintf returns -1 on buffer overflow. Since it's just a
+ log entry, it's OK to truncate it. */
+ char buf[4000];
+ int len = vsnprintf (buf, sizeof buf, format, ap);
+ add_to_log (log_format, build_string (title),
+ make_string (buf, max (0, min (len, sizeof buf - 1))));
+}
+#undef MINGW_STATIC
+
+static void tiff_error_handler (const char *, const char *, va_list)
+ ATTRIBUTE_FORMAT_PRINTF (2, 0);
static void
-tiff_error_handler (title, format, ap)
- const char *title, *format;
- va_list ap;
+tiff_error_handler (const char *title, const char *format, va_list ap)
{
- char buf[512];
- int len;
-
- len = sprintf (buf, "TIFF error: %s ", title);
- vsprintf (buf + len, format, ap);
- add_to_log (buf, Qnil, Qnil);
+ tiff_handler ("TIFF error: %s %s", title, format, ap);
}
+static void tiff_warning_handler (const char *, const char *, va_list)
+ ATTRIBUTE_FORMAT_PRINTF (2, 0);
static void
-tiff_warning_handler (title, format, ap)
- const char *title, *format;
- va_list ap;
+tiff_warning_handler (const char *title, const char *format, va_list ap)
{
- char buf[512];
- int len;
-
- len = sprintf (buf, "TIFF warning: %s ", title);
- vsprintf (buf + len, format, ap);
- add_to_log (buf, Qnil, Qnil);
+ tiff_handler ("TIFF warning: %s %s", title, format, ap);
}
successful. */
static int
-tiff_load (f, img)
- struct frame *f;
- struct image *img;
+tiff_load (struct frame *f, struct image *img)
{
Lisp_Object file, specified_file;
Lisp_Object specified_data;
TIFF *tiff;
int width, height, x, y, count;
uint32 *buf;
- int rc, rc2;
+ int rc;
XImagePtr ximg;
- struct gcpro gcpro1;
tiff_memory_source memsrc;
Lisp_Object image;
specified_file = image_spec_value (img->spec, QCfile, NULL);
specified_data = image_spec_value (img->spec, QCdata, NULL);
- file = Qnil;
- GCPRO1 (file);
- fn_TIFFSetErrorHandler (tiff_error_handler);
- fn_TIFFSetWarningHandler (tiff_warning_handler);
+ fn_TIFFSetErrorHandler ((TIFFErrorHandler) tiff_error_handler);
+ fn_TIFFSetWarningHandler ((TIFFErrorHandler) tiff_warning_handler);
if (NILP (specified_data))
{
if (!STRINGP (file))
{
image_error ("Cannot find image file `%s'", specified_file, Qnil);
- UNGCPRO;
return 0;
}
/* Try to open the image file. */
- tiff = fn_TIFFOpen (SDATA (file), "r");
+ tiff = fn_TIFFOpen (SSDATA (file), "r");
if (tiff == NULL)
{
image_error ("Cannot open `%s'", file, Qnil);
- UNGCPRO;
return 0;
}
}
else
{
+ if (!STRINGP (specified_data))
+ {
+ image_error ("Invalid image data `%s'", specified_data, Qnil);
+ return 0;
+ }
+
/* Memory source! */
memsrc.bytes = SDATA (specified_data);
memsrc.len = SBYTES (specified_data);
memsrc.index = 0;
- tiff = fn_TIFFClientOpen ("memory_source", "r", &memsrc,
- (TIFFReadWriteProc) tiff_read_from_memory,
- (TIFFReadWriteProc) tiff_write_from_memory,
+ tiff = fn_TIFFClientOpen ("memory_source", "r", (thandle_t)&memsrc,
+ tiff_read_from_memory,
+ tiff_write_from_memory,
tiff_seek_in_memory,
tiff_close_memory,
tiff_size_of_memory,
if (!tiff)
{
image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
- UNGCPRO;
return 0;
}
}
image = image_spec_value (img->spec, QCindex, NULL);
if (INTEGERP (image))
{
- int ino = XFASTINT (image);
- if (!fn_TIFFSetDirectory (tiff, ino))
+ EMACS_INT ino = XFASTINT (image);
+ if (! (TYPE_MINIMUM (tdir_t) <= ino && ino <= TYPE_MAXIMUM (tdir_t)
+ && fn_TIFFSetDirectory (tiff, ino)))
{
image_error ("Invalid image number `%s' in image `%s'",
image, img->spec);
fn_TIFFClose (tiff);
- UNGCPRO;
return 0;
}
}
{
image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
fn_TIFFClose (tiff);
- UNGCPRO;
return 0;
}
- buf = (uint32 *) xmalloc (width * height * sizeof *buf);
+ /* Create the X image and pixmap. */
+ if (! (height <= min (PTRDIFF_MAX, SIZE_MAX) / sizeof *buf / width
+ && x_create_x_image_and_pixmap (f, width, height, 0,
+ &ximg, &img->pixmap)))
+ {
+ fn_TIFFClose (tiff);
+ return 0;
+ }
+
+ buf = xmalloc (sizeof *buf * width * height);
rc = fn_TIFFReadRGBAImage (tiff, width, height, buf, 0);
/* Count the number of images in the file. */
- for (count = 1, rc2 = 1; rc2; count++)
- rc2 = fn_TIFFSetDirectory (tiff, count);
+ for (count = 1; fn_TIFFSetDirectory (tiff, count); count++)
+ continue;
if (count > 1)
- img->data.lisp_val = Fcons (Qcount,
- Fcons (make_number (count),
- img->data.lisp_val));
+ img->lisp_data = Fcons (Qcount,
+ Fcons (make_number (count),
+ img->lisp_data));
fn_TIFFClose (tiff);
if (!rc)
{
image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
xfree (buf);
- UNGCPRO;
- return 0;
- }
-
- /* Create the X image and pixmap. */
- if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
- {
- xfree (buf);
- UNGCPRO;
return 0;
}
x_destroy_x_image (ximg);
xfree (buf);
- UNGCPRO;
return 1;
}
static int
tiff_load (struct frame *f, struct image *img)
{
- return ns_load_image(f, img,
- image_spec_value (img->spec, QCfile, NULL),
- image_spec_value (img->spec, QCdata, NULL));
+ return ns_load_image (f, img,
+ image_spec_value (img->spec, QCfile, NULL),
+ image_spec_value (img->spec, QCdata, NULL));
}
#endif /* HAVE_NS */
#if defined (HAVE_GIF) || defined (HAVE_NS)
-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));
+static int gif_image_p (Lisp_Object object);
+static int gif_load (struct frame *f, struct image *img);
+static void gif_clear_image (struct frame *f, struct image *img);
/* The symbol `gif' identifying images of this type. */
-Lisp_Object Qgif;
+static Lisp_Object Qgif;
/* Indices of image specification fields in gif_format, below. */
{":data", IMAGE_STRING_VALUE, 0},
{":file", IMAGE_STRING_VALUE, 0},
{":ascent", IMAGE_ASCENT_VALUE, 0},
- {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
+ {":margin", IMAGE_NON_NEGATIVE_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},
{":background", IMAGE_STRING_OR_NIL_VALUE, 0}
};
+#ifdef HAVE_NTGUI
+static int init_gif_functions (void);
+#else
+#define init_gif_functions NULL
+#endif
+
/* Structure describing the image type `gif'. */
static struct image_type gif_type =
gif_image_p,
gif_load,
gif_clear_image,
+ init_gif_functions,
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;
+gif_clear_image (struct frame *f, struct image *img)
{
- /* IMG->data.ptr_val may contain extension data. */
- img->data.lisp_val = Qnil;
+ img->lisp_data = Qnil;
x_clear_image (f, img);
}
/* Return non-zero if OBJECT is a valid GIF image specification. */
static int
-gif_image_p (object)
- Lisp_Object object;
+gif_image_p (Lisp_Object object)
{
struct image_keyword fmt[GIF_LAST];
- bcopy (gif_format, fmt, sizeof fmt);
+ memcpy (fmt, gif_format, sizeof fmt);
if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
return 0;
#ifdef HAVE_NTGUI
/* GIF library details. */
-DEF_IMGLIB_FN (int, DGifCloseFile);
-DEF_IMGLIB_FN (int, DGifSlurp);
-DEF_IMGLIB_FN (GifFileType *, DGifOpen);
-DEF_IMGLIB_FN (GifFileType *, DGifOpenFileName);
+DEF_IMGLIB_FN (int, DGifCloseFile, (GifFileType *));
+DEF_IMGLIB_FN (int, DGifSlurp, (GifFileType *));
+DEF_IMGLIB_FN (GifFileType *, DGifOpen, (void *, InputFunc));
+DEF_IMGLIB_FN (GifFileType *, DGifOpenFileName, (const char *));
static int
-init_gif_functions (Lisp_Object libraries)
+init_gif_functions (void)
{
HMODULE library;
- if (!(library = w32_delayed_load (libraries, Qgif)))
+ if (!(library = w32_delayed_load (Qgif)))
return 0;
LOAD_IMGLIB_FN (library, DGifCloseFile);
typedef struct
{
unsigned char *bytes;
- size_t len;
- int index;
+ ptrdiff_t len;
+ ptrdiff_t index;
}
gif_memory_source;
static gif_memory_source *current_gif_memory_src;
static int
-gif_read_from_memory (file, buf, len)
- GifFileType *file;
- GifByteType *buf;
- int len;
+gif_read_from_memory (GifFileType *file, GifByteType *buf, int len)
{
gif_memory_source *src = current_gif_memory_src;
if (len > src->len - src->index)
return -1;
- bcopy (src->bytes + src->index, buf, len);
+ memcpy (buf, src->bytes + src->index, len);
src->index += len;
return len;
}
static const int interlace_start[] = {0, 4, 2, 1};
static const int interlace_increment[] = {8, 8, 4, 2};
+#define GIF_LOCAL_DESCRIPTOR_EXTENSION 249
+
static int
-gif_load (f, img)
- struct frame *f;
- struct image *img;
+gif_load (struct frame *f, struct image *img)
{
- Lisp_Object file, specified_file;
- Lisp_Object specified_data;
- int rc, width, height, x, y, i;
+ Lisp_Object file;
+ int rc, width, height, x, y, i, j;
XImagePtr ximg;
ColorMapObject *gif_color_map;
unsigned long pixel_colors[256];
GifFileType *gif;
- struct gcpro gcpro1;
- Lisp_Object image;
- int ino, image_height, image_width;
gif_memory_source memsrc;
- unsigned char *raster;
-
- specified_file = image_spec_value (img->spec, QCfile, NULL);
- specified_data = image_spec_value (img->spec, QCdata, NULL);
- file = Qnil;
- GCPRO1 (file);
+ Lisp_Object specified_bg = image_spec_value (img->spec, QCbackground, NULL);
+ Lisp_Object specified_file = image_spec_value (img->spec, QCfile, NULL);
+ Lisp_Object specified_data = image_spec_value (img->spec, QCdata, NULL);
+ unsigned long bgcolor = 0;
+ EMACS_INT idx;
if (NILP (specified_data))
{
if (!STRINGP (file))
{
image_error ("Cannot find image file `%s'", specified_file, Qnil);
- UNGCPRO;
return 0;
}
/* Open the GIF file. */
- gif = fn_DGifOpenFileName (SDATA (file));
+ gif = fn_DGifOpenFileName (SSDATA (file));
if (gif == NULL)
{
image_error ("Cannot open `%s'", file, Qnil);
- UNGCPRO;
return 0;
}
}
else
{
+ if (!STRINGP (specified_data))
+ {
+ image_error ("Invalid image data `%s'", specified_data, Qnil);
+ return 0;
+ }
+
/* Read from memory! */
current_gif_memory_src = &memsrc;
memsrc.bytes = SDATA (specified_data);
if (!gif)
{
image_error ("Cannot open memory source `%s'", img->spec, Qnil);
- UNGCPRO;
return 0;
}
}
{
image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
fn_DGifCloseFile (gif);
- UNGCPRO;
return 0;
}
/* Read entire contents. */
rc = fn_DGifSlurp (gif);
- if (rc == GIF_ERROR)
+ if (rc == GIF_ERROR || gif->ImageCount <= 0)
{
image_error ("Error reading `%s'", img->spec, Qnil);
fn_DGifCloseFile (gif);
- UNGCPRO;
return 0;
}
- image = image_spec_value (img->spec, QCindex, NULL);
- ino = INTEGERP (image) ? XFASTINT (image) : 0;
- if (ino >= gif->ImageCount)
- {
- image_error ("Invalid image number `%s' in image `%s'",
- image, img->spec);
- fn_DGifCloseFile (gif);
- UNGCPRO;
- return 0;
- }
+ /* Which sub-image are we to display? */
+ {
+ Lisp_Object image_number = image_spec_value (img->spec, QCindex, NULL);
+ idx = INTEGERP (image_number) ? XFASTINT (image_number) : 0;
+ if (idx < 0 || idx >= gif->ImageCount)
+ {
+ image_error ("Invalid image number `%s' in image `%s'",
+ image_number, img->spec);
+ fn_DGifCloseFile (gif);
+ return 0;
+ }
+ }
- 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 = gif->SWidth;
+ height = img->height = gif->SHeight;
- 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]));
+ img->corners[TOP_CORNER] = gif->SavedImages[0].ImageDesc.Top;
+ img->corners[LEFT_CORNER] = gif->SavedImages[0].ImageDesc.Left;
+ img->corners[BOT_CORNER]
+ = img->corners[TOP_CORNER] + gif->SavedImages[0].ImageDesc.Height;
+ img->corners[RIGHT_CORNER]
+ = img->corners[LEFT_CORNER] + gif->SavedImages[0].ImageDesc.Width;
if (!check_image_size (f, width, height))
{
image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
fn_DGifCloseFile (gif);
- UNGCPRO;
return 0;
}
if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
{
fn_DGifCloseFile (gif);
- UNGCPRO;
return 0;
}
- /* Allocate colors. */
- gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
- if (!gif_color_map)
- gif_color_map = gif->SColorMap;
- init_color_table ();
- bzero (pixel_colors, sizeof pixel_colors);
-
- 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);
- free_color_table ();
-#endif /* COLOR_TABLE_SUPPORT */
-
- /* Clear the part of the screen image that are not covered by
- the image from the GIF file. Full animated GIF support
- 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. */
+ /* Clear the part of the screen image not covered by the image.
+ Full animated GIF support requires more 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. */
for (y = 0; y < img->corners[TOP_CORNER]; ++y)
for (x = 0; x < width; ++x)
XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
}
- /* Read the GIF image into the X image. We use a local variable
- `raster' here because RasterBits below is a char *, and invites
- problems with bytes >= 0x80. */
- raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
-
- if (gif->SavedImages[ino].ImageDesc.Interlace)
- {
- int pass;
- int row = interlace_start[0];
+ /* Read the GIF image into the X image. */
- pass = 0;
+ /* FIXME: With the current implementation, loading an animated gif
+ is quadratic in the number of animation frames, since each frame
+ is a separate struct image. We must provide a way for a single
+ gif_load call to construct and save all animation frames. */
- for (y = 0; y < image_height; y++)
+ init_color_table ();
+ if (STRINGP (specified_bg))
+ bgcolor = x_alloc_image_color (f, img, specified_bg,
+ FRAME_BACKGROUND_PIXEL (f));
+ for (j = 0; j <= idx; ++j)
+ {
+ /* We use a local variable `raster' here because RasterBits is a
+ char *, which invites problems with bytes >= 0x80. */
+ struct SavedImage *subimage = gif->SavedImages + j;
+ unsigned char *raster = (unsigned char *) subimage->RasterBits;
+ int transparency_color_index = -1;
+ int disposal = 0;
+ int subimg_width = subimage->ImageDesc.Width;
+ int subimg_height = subimage->ImageDesc.Height;
+ int subimg_top = subimage->ImageDesc.Top;
+ int subimg_left = subimage->ImageDesc.Left;
+
+ /* Find the Graphic Control Extension block for this sub-image.
+ Extract the disposal method and transparency color. */
+ for (i = 0; i < subimage->ExtensionBlockCount; i++)
{
- if (row >= image_height)
- {
- row = interlace_start[++pass];
- while (row >= image_height)
- row = interlace_start[++pass];
- }
+ ExtensionBlock *extblock = subimage->ExtensionBlocks + i;
- for (x = 0; x < image_width; x++)
+ if ((extblock->Function == GIF_LOCAL_DESCRIPTOR_EXTENSION)
+ && extblock->ByteCount == 4
+ && extblock->Bytes[0] & 1)
{
- int i = raster[(y * image_width) + x];
- XPutPixel (ximg, x + img->corners[LEFT_CORNER],
- row + img->corners[TOP_CORNER], pixel_colors[i]);
+ /* From gif89a spec: 1 = "keep in place", 2 = "restore
+ to background". Treat any other value like 2. */
+ disposal = (extblock->Bytes[0] >> 2) & 7;
+ transparency_color_index = (unsigned char) extblock->Bytes[3];
+ break;
}
-
- row += interlace_increment[pass];
}
- }
- else
- {
- for (y = 0; y < image_height; ++y)
- for (x = 0; x < image_width; ++x)
+
+ /* We can't "keep in place" the first subimage. */
+ if (j == 0)
+ disposal = 2;
+
+ /* For disposal == 0, the spec says "No disposal specified. The
+ decoder is not required to take any action." In practice, it
+ seems we need to treat this like "keep in place", see e.g.
+ http://upload.wikimedia.org/wikipedia/commons/3/37/Clock.gif */
+ if (disposal == 0)
+ disposal = 1;
+
+ /* Allocate subimage colors. */
+ memset (pixel_colors, 0, sizeof pixel_colors);
+ gif_color_map = subimage->ImageDesc.ColorMap;
+ if (!gif_color_map)
+ gif_color_map = gif->SColorMap;
+
+ if (gif_color_map)
+ for (i = 0; i < gif_color_map->ColorCount; ++i)
{
- int i = raster[y * image_width + x];
- XPutPixel (ximg, x + img->corners[LEFT_CORNER],
- y + img->corners[TOP_CORNER], pixel_colors[i]);
+ if (transparency_color_index == i)
+ pixel_colors[i] = STRINGP (specified_bg)
+ ? bgcolor : FRAME_BACKGROUND_PIXEL (f);
+ else
+ {
+ 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);
+ }
}
+
+ /* Apply the pixel values. */
+ if (gif->SavedImages[j].ImageDesc.Interlace)
+ {
+ int row, pass;
+
+ for (y = 0, row = interlace_start[0], pass = 0;
+ y < subimg_height;
+ y++, row += interlace_increment[pass])
+ {
+ if (row >= subimg_height)
+ {
+ row = interlace_start[++pass];
+ while (row >= subimg_height)
+ row = interlace_start[++pass];
+ }
+
+ for (x = 0; x < subimg_width; x++)
+ {
+ int c = raster[y * subimg_width + x];
+ if (transparency_color_index != c || disposal != 1)
+ XPutPixel (ximg, x + subimg_left, row + subimg_top,
+ pixel_colors[c]);
+ }
+ }
+ }
+ else
+ {
+ for (y = 0; y < subimg_height; ++y)
+ for (x = 0; x < subimg_width; ++x)
+ {
+ int c = raster[y * subimg_width + x];
+ if (transparency_color_index != c || disposal != 1)
+ XPutPixel (ximg, x + subimg_left, y + subimg_top,
+ pixel_colors[c]);
+ }
+ }
}
- /* 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)
+#ifdef COLOR_TABLE_SUPPORT
+ img->colors = colors_in_color_table (&img->ncolors);
+ free_color_table ();
+#endif /* COLOR_TABLE_SUPPORT */
+
+ /* Save GIF image extension data for `image-metadata'.
+ Format is (count IMAGES extension-data (FUNCTION "BYTES" ...)). */
+ img->lisp_data = Qnil;
+ if (gif->SavedImages[idx].ExtensionBlockCount > 0)
{
- ExtensionBlock *ext = gif->SavedImages[ino].ExtensionBlocks;
- for (i = 0; i < gif->SavedImages[ino].ExtensionBlockCount; i++, ext++)
+ int delay = 0;
+ ExtensionBlock *ext = gif->SavedImages[idx].ExtensionBlocks;
+ for (i = 0; i < gif->SavedImages[idx].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);
+ {
+ img->lisp_data
+ = Fcons (make_number (ext->Function),
+ Fcons (make_unibyte_string (ext->Bytes, ext->ByteCount),
+ img->lisp_data));
+ if (ext->Function == GIF_LOCAL_DESCRIPTOR_EXTENSION
+ && ext->ByteCount == 4)
+ {
+ delay = ext->Bytes[2] << CHAR_BIT;
+ delay |= ext->Bytes[1];
+ }
+ }
+ img->lisp_data = Fcons (Qextension_data,
+ Fcons (img->lisp_data, Qnil));
+ if (delay)
+ img->lisp_data
+ = Fcons (Qdelay,
+ Fcons (make_float (delay / 100.0),
+ img->lisp_data));
}
+
if (gif->ImageCount > 1)
- img->data.lisp_val = Fcons (Qcount,
- Fcons (make_number (gif->ImageCount),
- img->data.lisp_val));
+ img->lisp_data = Fcons (Qcount,
+ Fcons (make_number (gif->ImageCount),
+ img->lisp_data));
fn_DGifCloseFile (gif);
x_put_x_image (f, ximg, img->pixmap, width, height);
x_destroy_x_image (ximg);
- UNGCPRO;
return 1;
}
static int
gif_load (struct frame *f, struct image *img)
{
- return ns_load_image(f, img,
- image_spec_value (img->spec, QCfile, NULL),
- image_spec_value (img->spec, QCdata, NULL));
+ return ns_load_image (f, img,
+ image_spec_value (img->spec, QCfile, NULL),
+ image_spec_value (img->spec, QCdata, NULL));
}
#endif /* HAVE_NS */
#endif /* HAVE_GIF */
+/***********************************************************************
+ ImageMagick
+***********************************************************************/
+#if defined (HAVE_IMAGEMAGICK)
+
+static Lisp_Object Qimagemagick;
+
+static int imagemagick_image_p (Lisp_Object);
+static int imagemagick_load (struct frame *, struct image *);
+static void imagemagick_clear_image (struct frame *, struct image *);
+
+/* Indices of image specification fields in imagemagick_format. */
+
+enum imagemagick_keyword_index
+ {
+ IMAGEMAGICK_TYPE,
+ IMAGEMAGICK_DATA,
+ IMAGEMAGICK_FILE,
+ IMAGEMAGICK_ASCENT,
+ IMAGEMAGICK_MARGIN,
+ IMAGEMAGICK_RELIEF,
+ IMAGEMAGICK_ALGORITHM,
+ IMAGEMAGICK_HEURISTIC_MASK,
+ IMAGEMAGICK_MASK,
+ IMAGEMAGICK_BACKGROUND,
+ IMAGEMAGICK_HEIGHT,
+ IMAGEMAGICK_WIDTH,
+ IMAGEMAGICK_ROTATION,
+ IMAGEMAGICK_CROP,
+ IMAGEMAGICK_LAST
+ };
+
+/* Vector of image_keyword structures describing the format
+ of valid user-defined image specifications. */
+
+static struct image_keyword imagemagick_format[IMAGEMAGICK_LAST] =
+ {
+ {":type", IMAGE_SYMBOL_VALUE, 1},
+ {":data", IMAGE_STRING_VALUE, 0},
+ {":file", IMAGE_STRING_VALUE, 0},
+ {":ascent", IMAGE_ASCENT_VALUE, 0},
+ {":margin", IMAGE_NON_NEGATIVE_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},
+ {":height", IMAGE_INTEGER_VALUE, 0},
+ {":width", IMAGE_INTEGER_VALUE, 0},
+ {":rotation", IMAGE_NUMBER_VALUE, 0},
+ {":crop", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
+ };
+
+#ifdef HAVE_NTGUI
+static int init_imagemagick_functions (void);
+#else
+#define init_imagemagick_functions NULL
+#endif
+
+/* Structure describing the image type for any image handled via
+ ImageMagick. */
+
+static struct image_type imagemagick_type =
+ {
+ &Qimagemagick,
+ imagemagick_image_p,
+ imagemagick_load,
+ imagemagick_clear_image,
+ init_imagemagick_functions,
+ NULL
+ };
+
+/* Free X resources of imagemagick image IMG which is used on frame F. */
+
+static void
+imagemagick_clear_image (struct frame *f,
+ struct image *img)
+{
+ x_clear_image (f, img);
+}
+
+/* Return non-zero if OBJECT is a valid IMAGEMAGICK image specification. Do
+ this by calling parse_image_spec and supplying the keywords that
+ identify the IMAGEMAGICK format. */
+
+static int
+imagemagick_image_p (Lisp_Object object)
+{
+ struct image_keyword fmt[IMAGEMAGICK_LAST];
+ memcpy (fmt, imagemagick_format, sizeof fmt);
+
+ if (!parse_image_spec (object, fmt, IMAGEMAGICK_LAST, Qimagemagick))
+ return 0;
+
+ /* Must specify either the :data or :file keyword. */
+ return fmt[IMAGEMAGICK_FILE].count + fmt[IMAGEMAGICK_DATA].count == 1;
+}
+
+/* The GIF library also defines DrawRectangle, but its never used in Emacs.
+ Therefore rename the function so it doesn't collide with ImageMagick. */
+#define DrawRectangle DrawRectangleGif
+#include <wand/MagickWand.h>
+
+/* ImageMagick 6.5.3 through 6.6.5 hid PixelGetMagickColor for some reason.
+ Emacs seems to work fine with the hidden version, so unhide it. */
+#include <magick/version.h>
+#if 0x653 <= MagickLibVersion && MagickLibVersion <= 0x665
+extern WandExport void PixelGetMagickColor (const PixelWand *,
+ MagickPixelPacket *);
+#endif
+
+/* Log ImageMagick error message.
+ Useful when a ImageMagick function returns the status `MagickFalse'. */
+
+static void
+imagemagick_error (MagickWand *wand)
+{
+ char *description;
+ ExceptionType severity;
+
+ description = MagickGetException (wand, &severity);
+ image_error ("ImageMagick error: %s",
+ build_string (description),
+ Qnil);
+ description = (char *) MagickRelinquishMemory (description);
+}
+
+/* Helper function for imagemagick_load, which does the actual loading
+ given contents and size, apart from frame and image structures,
+ passed from imagemagick_load. Uses librimagemagick to do most of
+ the image processing.
+
+ F is a pointer to the Emacs frame; IMG to the image structure to
+ prepare; CONTENTS is the string containing the IMAGEMAGICK data to
+ be parsed; SIZE is the number of bytes of data; and FILENAME is
+ either the file name or the image data.
+
+ Return non-zero if successful. */
+
+static int
+imagemagick_load_image (struct frame *f, struct image *img,
+ unsigned char *contents, unsigned int size,
+ char *filename)
+{
+ size_t width, height;
+ MagickBooleanType status;
+ XImagePtr ximg;
+ int x, y;
+ MagickWand *image_wand;
+ MagickWand *ping_wand;
+ PixelIterator *iterator;
+ PixelWand **pixels, *bg_wand = NULL;
+ MagickPixelPacket pixel;
+ Lisp_Object image;
+ Lisp_Object value;
+ Lisp_Object crop;
+ EMACS_INT ino;
+ int desired_width, desired_height;
+ double rotation;
+ int pixelwidth;
+
+ /* Handle image index for image types who can contain more than one image.
+ Interface :index is same as for GIF. First we "ping" the image to see how
+ many sub-images it contains. Pinging is faster than loading the image to
+ find out things about it. */
+
+ /* Initialize the imagemagick environment. */
+ MagickWandGenesis ();
+ image = image_spec_value (img->spec, QCindex, NULL);
+ ino = INTEGERP (image) ? XFASTINT (image) : 0;
+ ping_wand = NewMagickWand ();
+ /* MagickSetResolution (ping_wand, 2, 2); (Bug#10112) */
+
+ status = filename
+ ? MagickPingImage (ping_wand, filename)
+ : MagickPingImageBlob (ping_wand, contents, size);
+
+ if (status == MagickFalse)
+ {
+ imagemagick_error (ping_wand);
+ DestroyMagickWand (ping_wand);
+ return 0;
+ }
+
+ if (ino < 0 || ino >= MagickGetNumberImages (ping_wand))
+ {
+ image_error ("Invalid image number `%s' in image `%s'",
+ image, img->spec);
+ DestroyMagickWand (ping_wand);
+ return 0;
+ }
+
+ if (MagickGetNumberImages (ping_wand) > 1)
+ img->lisp_data =
+ Fcons (Qcount,
+ Fcons (make_number (MagickGetNumberImages (ping_wand)),
+ img->lisp_data));
+
+ DestroyMagickWand (ping_wand);
+
+ /* Now we know how many images are inside the file. If it's not a
+ bundle, the number is one. Load the image data. */
+
+ image_wand = NewMagickWand ();
+
+ if ((filename
+ ? MagickReadImage (image_wand, filename)
+ : MagickReadImageBlob (image_wand, contents, size))
+ == MagickFalse)
+ {
+ imagemagick_error (image_wand);
+ goto imagemagick_error;
+ }
+
+ /* Retrieve the frame's background color, for use later. */
+ {
+ XColor bgcolor;
+ Lisp_Object specified_bg;
+
+ specified_bg = image_spec_value (img->spec, QCbackground, NULL);
+ if (!STRINGP (specified_bg)
+ || !x_defined_color (f, SSDATA (specified_bg), &bgcolor, 0))
+ {
+#ifndef HAVE_NS
+ bgcolor.pixel = FRAME_BACKGROUND_PIXEL (f);
+ x_query_color (f, &bgcolor);
+#else
+ ns_query_color (FRAME_BACKGROUND_COLOR (f), &bgcolor, 1);
+#endif
+ }
+
+ bg_wand = NewPixelWand ();
+ PixelSetRed (bg_wand, (double) bgcolor.red / 65535);
+ PixelSetGreen (bg_wand, (double) bgcolor.green / 65535);
+ PixelSetBlue (bg_wand, (double) bgcolor.blue / 65535);
+ }
+
+ /* If width and/or height is set in the display spec assume we want
+ to scale to those values. If either h or w is unspecified, the
+ unspecified should be calculated from the specified to preserve
+ aspect ratio. */
+ value = image_spec_value (img->spec, QCwidth, NULL);
+ desired_width = (INTEGERP (value) ? XFASTINT (value) : -1);
+ value = image_spec_value (img->spec, QCheight, NULL);
+ desired_height = (INTEGERP (value) ? XFASTINT (value) : -1);
+
+ height = MagickGetImageHeight (image_wand);
+ width = MagickGetImageWidth (image_wand);
+
+ if (desired_width != -1 && desired_height == -1)
+ /* w known, calculate h. */
+ desired_height = (double) desired_width / width * height;
+ if (desired_width == -1 && desired_height != -1)
+ /* h known, calculate w. */
+ desired_width = (double) desired_height / height * width;
+ if (desired_width != -1 && desired_height != -1)
+ {
+ status = MagickScaleImage (image_wand, desired_width, desired_height);
+ if (status == MagickFalse)
+ {
+ image_error ("Imagemagick scale failed", Qnil, Qnil);
+ imagemagick_error (image_wand);
+ goto imagemagick_error;
+ }
+ }
+
+ /* crop behaves similar to image slicing in Emacs but is more memory
+ efficient. */
+ crop = image_spec_value (img->spec, QCcrop, NULL);
+
+ if (CONSP (crop) && TYPE_RANGED_INTEGERP (size_t, XCAR (crop)))
+ {
+ /* After some testing, it seems MagickCropImage is the fastest crop
+ function in ImageMagick. This crop function seems to do less copying
+ than the alternatives, but it still reads the entire image into memory
+ before cropping, which is apparently difficult to avoid when using
+ imagemagick. */
+ size_t crop_width = XINT (XCAR (crop));
+ crop = XCDR (crop);
+ if (CONSP (crop) && TYPE_RANGED_INTEGERP (size_t, XCAR (crop)))
+ {
+ size_t crop_height = XINT (XCAR (crop));
+ crop = XCDR (crop);
+ if (CONSP (crop) && TYPE_RANGED_INTEGERP (ssize_t, XCAR (crop)))
+ {
+ ssize_t crop_x = XINT (XCAR (crop));
+ crop = XCDR (crop);
+ if (CONSP (crop) && TYPE_RANGED_INTEGERP (ssize_t, XCAR (crop)))
+ {
+ ssize_t crop_y = XINT (XCAR (crop));
+ MagickCropImage (image_wand, crop_width, crop_height,
+ crop_x, crop_y);
+ }
+ }
+ }
+ }
+
+ /* Furthermore :rotation. we need background color and angle for
+ rotation. */
+ /*
+ TODO background handling for rotation specified_bg =
+ image_spec_value (img->spec, QCbackground, NULL); if (!STRINGP
+ (specified_bg). */
+ value = image_spec_value (img->spec, QCrotation, NULL);
+ if (FLOATP (value))
+ {
+ rotation = extract_float (value);
+ status = MagickRotateImage (image_wand, bg_wand, rotation);
+ if (status == MagickFalse)
+ {
+ image_error ("Imagemagick image rotate failed", Qnil, Qnil);
+ imagemagick_error (image_wand);
+ goto imagemagick_error;
+ }
+ }
+
+ /* Finally we are done manipulating the image. Figure out the
+ resulting width/height and transfer ownership to Emacs. */
+ height = MagickGetImageHeight (image_wand);
+ width = MagickGetImageWidth (image_wand);
+
+ /* Set the canvas background color to the frame or specified
+ background, and flatten the image. Note: as of ImageMagick
+ 6.6.0, SVG image transparency is not handled properly
+ (e.g. etc/images/splash.svg shows a white background always). */
+ {
+ MagickWand *new_wand;
+ MagickSetImageBackgroundColor (image_wand, bg_wand);
+#ifdef HAVE_MAGICKMERGEIMAGELAYERS
+ new_wand = MagickMergeImageLayers (image_wand, MergeLayer);
+#else
+ new_wand = MagickFlattenImages (image_wand);
+#endif
+ DestroyMagickWand (image_wand);
+ image_wand = new_wand;
+ }
+
+ if (! (width <= INT_MAX && height <= INT_MAX
+ && check_image_size (f, width, height)))
+ {
+ image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
+ goto imagemagick_error;
+ }
+
+ /* We can now get a valid pixel buffer from the imagemagick file, if all
+ went ok. */
+
+ init_color_table ();
+
+#ifdef HAVE_MAGICKEXPORTIMAGEPIXELS
+ if (imagemagick_render_type != 0)
+ {
+ /* Magicexportimage is normally faster than pixelpushing. This
+ method is also well tested. Some aspects of this method are
+ ad-hoc and needs to be more researched. */
+ int imagedepth = 24; /*MagickGetImageDepth(image_wand);*/
+ const char *exportdepth = imagedepth <= 8 ? "I" : "BGRP"; /*"RGBP";*/
+ /* Try to create a x pixmap to hold the imagemagick pixmap. */
+ if (!x_create_x_image_and_pixmap (f, width, height, imagedepth,
+ &ximg, &img->pixmap))
+ {
+#ifdef COLOR_TABLE_SUPPORT
+ free_color_table ();
+#endif
+ image_error ("Imagemagick X bitmap allocation failure", Qnil, Qnil);
+ goto imagemagick_error;
+ }
+
+ /* Oddly, the below code doesn't seem to work:*/
+ /* switch(ximg->bitmap_unit){ */
+ /* case 8: */
+ /* pixelwidth=CharPixel; */
+ /* break; */
+ /* case 16: */
+ /* pixelwidth=ShortPixel; */
+ /* break; */
+ /* case 32: */
+ /* pixelwidth=LongPixel; */
+ /* break; */
+ /* } */
+ /*
+ Here im just guessing the format of the bitmap.
+ happens to work fine for:
+ - bw djvu images
+ on rgb display.
+ seems about 3 times as fast as pixel pushing(not carefully measured)
+ */
+ pixelwidth = CharPixel; /*??? TODO figure out*/
+ MagickExportImagePixels (image_wand, 0, 0, width, height,
+ exportdepth, pixelwidth, ximg->data);
+ }
+ else
+#endif /* HAVE_MAGICKEXPORTIMAGEPIXELS */
+ {
+ size_t image_height;
+
+ /* Try to create a x pixmap to hold the imagemagick pixmap. */
+ if (!x_create_x_image_and_pixmap (f, width, height, 0,
+ &ximg, &img->pixmap))
+ {
+#ifdef COLOR_TABLE_SUPPORT
+ free_color_table ();
+#endif
+ image_error ("Imagemagick X bitmap allocation failure", Qnil, Qnil);
+ goto imagemagick_error;
+ }
+
+ /* Copy imagemagick image to x with primitive yet robust pixel
+ pusher loop. This has been tested a lot with many different
+ images. */
+
+ /* Copy pixels from the imagemagick image structure to the x image map. */
+ iterator = NewPixelIterator (image_wand);
+ if (iterator == (PixelIterator *) NULL)
+ {
+#ifdef COLOR_TABLE_SUPPORT
+ free_color_table ();
+#endif
+ x_destroy_x_image (ximg);
+ image_error ("Imagemagick pixel iterator creation failed",
+ Qnil, Qnil);
+ goto imagemagick_error;
+ }
+
+ image_height = MagickGetImageHeight (image_wand);
+ for (y = 0; y < image_height; y++)
+ {
+ pixels = PixelGetNextIteratorRow (iterator, &width);
+ if (pixels == (PixelWand **) NULL)
+ break;
+ for (x = 0; x < (long) width; x++)
+ {
+ PixelGetMagickColor (pixels[x], &pixel);
+ XPutPixel (ximg, x, y,
+ lookup_rgb_color (f,
+ pixel.red,
+ pixel.green,
+ pixel.blue));
+ }
+ }
+ DestroyPixelIterator (iterator);
+ }
+
+#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 */
+
+ img->width = width;
+ img->height = height;
+
+ /* 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);
+
+ /* Final cleanup. image_wand should be the only resource left. */
+ DestroyMagickWand (image_wand);
+ if (bg_wand) DestroyPixelWand (bg_wand);
+
+ /* `MagickWandTerminus' terminates the imagemagick environment. */
+ MagickWandTerminus ();
+
+ return 1;
+
+ imagemagick_error:
+ DestroyMagickWand (image_wand);
+ if (bg_wand) DestroyPixelWand (bg_wand);
+
+ MagickWandTerminus ();
+ /* TODO more cleanup. */
+ image_error ("Error parsing IMAGEMAGICK image `%s'", img->spec, Qnil);
+ return 0;
+}
+
+
+/* Load IMAGEMAGICK image IMG for use on frame F. Value is non-zero if
+ successful. this function will go into the imagemagick_type structure, and
+ the prototype thus needs to be compatible with that structure. */
+
+static int
+imagemagick_load (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;
+
+ file = x_find_image_file (file_name);
+ if (!STRINGP (file))
+ {
+ image_error ("Cannot find image file `%s'", file_name, Qnil);
+ return 0;
+ }
+ success_p = imagemagick_load_image (f, img, 0, 0, SSDATA (file));
+ }
+ /* 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);
+ if (!STRINGP (data))
+ {
+ image_error ("Invalid image data `%s'", data, Qnil);
+ return 0;
+ }
+ success_p = imagemagick_load_image (f, img, SDATA (data),
+ SBYTES (data), NULL);
+ }
+
+ return success_p;
+}
+
+DEFUN ("imagemagick-types", Fimagemagick_types, Simagemagick_types, 0, 0, 0,
+ doc: /* Return a list of image types supported by ImageMagick.
+Each entry in this list is a symbol named after an ImageMagick format
+tag. See the ImageMagick manual for a list of ImageMagick formats and
+their descriptions (http://www.imagemagick.org/script/formats.php).
+You can also try the shell command: `identify -list format'.
+
+Note that ImageMagick recognizes many file-types that Emacs does not
+recognize as images, such as C. See `imagemagick-types-enable'
+and `imagemagick-types-inhibit'. */)
+ (void)
+{
+ Lisp_Object typelist = Qnil;
+ size_t numf = 0;
+ ExceptionInfo ex;
+ char **imtypes;
+ size_t i;
+ Lisp_Object Qimagemagicktype;
+
+ GetExceptionInfo(&ex);
+ imtypes = GetMagickList ("*", &numf, &ex);
+ DestroyExceptionInfo(&ex);
+
+ for (i = 0; i < numf; i++)
+ {
+ Qimagemagicktype = intern (imtypes[i]);
+ typelist = Fcons (Qimagemagicktype, typelist);
+ }
+ return Fnreverse (typelist);
+}
+
+#endif /* defined (HAVE_IMAGEMAGICK) */
+
+
\f
/***********************************************************************
SVG
/* 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_image_p (Lisp_Object object);
+static int svg_load (struct frame *f, struct image *img);
-static int svg_load_image P_ ((struct frame *, struct image *,
- unsigned char *, unsigned int));
+static int svg_load_image (struct frame *, struct image *,
+ unsigned char *, ptrdiff_t);
/* The symbol `svg' identifying images of this type. */
-Lisp_Object Qsvg;
+static Lisp_Object Qsvg;
/* Indices of image specification fields in svg_format, below. */
{":data", IMAGE_STRING_VALUE, 0},
{":file", IMAGE_STRING_VALUE, 0},
{":ascent", IMAGE_ASCENT_VALUE, 0},
- {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
+ {":margin", IMAGE_NON_NEGATIVE_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},
{":background", IMAGE_STRING_OR_NIL_VALUE, 0}
};
+#ifdef HAVE_NTGUI
+static int init_svg_functions (void);
+#else
+#define init_svg_functions NULL
+#endif
+
/* 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. */
+ init_svg_functions,
NULL
};
identify the SVG format. */
static int
-svg_image_p (object)
- Lisp_Object object;
+svg_image_p (Lisp_Object object)
{
struct image_keyword fmt[SVG_LAST];
- bcopy (svg_format, fmt, sizeof fmt);
+ memcpy (fmt, svg_format, sizeof fmt);
if (!parse_image_spec (object, fmt, SVG_LAST, Qsvg))
return 0;
DEF_IMGLIB_FN (gboolean, rsvg_handle_write);
DEF_IMGLIB_FN (gboolean, rsvg_handle_close);
DEF_IMGLIB_FN (GdkPixbuf *, rsvg_handle_get_pixbuf);
-DEF_IMGLIB_FN (void, rsvg_handle_free);
DEF_IMGLIB_FN (int, gdk_pixbuf_get_width);
DEF_IMGLIB_FN (int, gdk_pixbuf_get_height);
Lisp_Object Qgdk_pixbuf, Qglib, Qgobject;
static int
-init_svg_functions (Lisp_Object libraries)
+init_svg_functions (void)
{
HMODULE library, gdklib, glib, gobject;
- if (!(glib = w32_delayed_load (libraries, Qglib))
- || !(gobject = w32_delayed_load (libraries, Qgobject))
- || !(gdklib = w32_delayed_load (libraries, Qgdk_pixbuf))
- || !(library = w32_delayed_load (libraries, Qsvg)))
+ if (!(glib = w32_delayed_load (Qglib))
+ || !(gobject = w32_delayed_load (Qgobject))
+ || !(gdklib = w32_delayed_load (Qgdk_pixbuf))
+ || !(library = w32_delayed_load (Qsvg)))
return 0;
LOAD_IMGLIB_FN (library, rsvg_handle_new);
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);
#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
the prototype thus needs to be compatible with that structure. */
static int
-svg_load (f, img)
- struct frame *f;
- struct image *img;
+svg_load (struct frame *f, struct image *img)
{
int success_p = 0;
Lisp_Object file_name;
{
Lisp_Object file;
unsigned char *contents;
- int size;
- struct gcpro gcpro1;
+ ptrdiff_t size;
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);
+ contents = slurp_file (SSDATA (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. */
Lisp_Object data;
data = image_spec_value (img->spec, QCdata, NULL);
+ if (!STRINGP (data))
+ {
+ image_error ("Invalid image data `%s'", data, Qnil);
+ return 0;
+ }
success_p = svg_load_image (f, img, SDATA (data), SBYTES (data));
}
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;
+svg_load_image (struct frame *f, /* Pointer to emacs frame structure. */
+ struct image *img, /* Pointer to emacs image structure. */
+ unsigned char *contents, /* String containing the SVG XML data to be parsed. */
+ ptrdiff_t size) /* Size of data in bytes. */
{
RsvgHandle *rsvg_handle;
RsvgDimensionData dimension_data;
- GError *error = NULL;
+ GError *err = NULL;
GdkPixbuf *pixbuf;
int width;
int height;
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;
+ fn_rsvg_handle_write (rsvg_handle, contents, size, &err);
+ if (err) 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;
+ fn_rsvg_handle_close (rsvg_handle, &err);
+ if (err) goto rsvg_error;
fn_rsvg_handle_get_dimensions (rsvg_handle, &dimension_data);
if (! check_image_size (f, dimension_data.width, dimension_data.height))
color. */
specified_bg = image_spec_value (img->spec, QCbackground, NULL);
if (!STRINGP (specified_bg)
- || !x_defined_color (f, SDATA (specified_bg), &background, 0))
+ || !x_defined_color (f, SSDATA (specified_bg), &background, 0))
{
#ifndef HAVE_NS
background.pixel = FRAME_BACKGROUND_PIXEL (f);
x_query_color (f, &background);
#else
- ns_query_color(FRAME_BACKGROUND_COLOR (f), &background, 1);
+ ns_query_color (FRAME_BACKGROUND_COLOR (f), &background, 1);
#endif
}
{
for (x = 0; x < width; ++x)
{
- unsigned red;
- unsigned green;
- unsigned blue;
- unsigned opacity;
+ int red;
+ int green;
+ int blue;
+ int opacity;
red = *pixels++;
green = *pixels++;
/* 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);
+ fn_g_error_free (err);
return 0;
}
#define HAVE_GHOSTSCRIPT 1
#endif /* HAVE_X_WINDOWS */
-/* The symbol `postscript' identifying images of this type. */
-
-Lisp_Object Qpostscript;
-
#ifdef HAVE_GHOSTSCRIPT
-static int gs_image_p P_ ((Lisp_Object object));
-static int gs_load P_ ((struct frame *f, struct image *img));
-static void gs_clear_image P_ ((struct frame *f, struct image *img));
+static int gs_image_p (Lisp_Object object);
+static int gs_load (struct frame *f, struct image *img);
+static void gs_clear_image (struct frame *f, struct image *img);
/* Keyword symbols. */
-Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
+static Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
/* Indices of image specification fields in gs_format, below. */
{":loader", IMAGE_FUNCTION_VALUE, 0},
{":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
{":ascent", IMAGE_ASCENT_VALUE, 0},
- {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
+ {":margin", IMAGE_NON_NEGATIVE_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},
gs_image_p,
gs_load,
gs_clear_image,
+ NULL,
NULL
};
/* Free X resources of Ghostscript image IMG which is used on frame F. */
static void
-gs_clear_image (f, img)
- struct frame *f;
- struct image *img;
+gs_clear_image (struct frame *f, struct image *img)
{
- /* IMG->data.ptr_val may contain a recorded colormap. */
- xfree (img->data.ptr_val);
x_clear_image (f, img);
}
specification. */
static int
-gs_image_p (object)
- Lisp_Object object;
+gs_image_p (Lisp_Object object)
{
struct image_keyword fmt[GS_LAST];
Lisp_Object tem;
int i;
- bcopy (gs_format, fmt, sizeof fmt);
+ memcpy (fmt, gs_format, sizeof fmt);
if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
return 0;
}
else if (VECTORP (tem))
{
- if (XVECTOR_SIZE (tem) != 4)
+ if (ASIZE (tem) != 4)
return 0;
for (i = 0; i < 4; ++i)
- if (!INTEGERP (XVECTOR (tem)->contents[i]))
+ if (!INTEGERP (AREF (tem, i)))
return 0;
}
else
if successful. */
static int
-gs_load (f, img)
- struct frame *f;
- struct image *img;
+gs_load (struct frame *f, struct image *img)
{
- char buffer[100];
+ uprintmax_t printnum1, printnum2;
+ char buffer[sizeof " " + INT_STRLEN_BOUND (printmax_t)];
Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
- struct gcpro gcpro1, gcpro2;
Lisp_Object frame;
double in_width, in_height;
Lisp_Object pixel_colors = Qnil;
= 1/72 in, xdpi and ydpi are stored in the frame's X display
info. */
pt_width = image_spec_value (img->spec, QCpt_width, NULL);
- in_width = XFASTINT (pt_width) / 72.0;
- img->width = in_width * FRAME_X_DISPLAY_INFO (f)->resx;
+ in_width = INTEGERP (pt_width) ? XFASTINT (pt_width) / 72.0 : 0;
+ in_width *= FRAME_X_DISPLAY_INFO (f)->resx;
pt_height = image_spec_value (img->spec, QCpt_height, NULL);
- in_height = XFASTINT (pt_height) / 72.0;
- img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
+ in_height = INTEGERP (pt_height) ? XFASTINT (pt_height) / 72.0 : 0;
+ in_height *= FRAME_X_DISPLAY_INFO (f)->resy;
- if (!check_image_size (f, img->width, img->height))
+ if (! (in_width <= INT_MAX && in_height <= INT_MAX
+ && check_image_size (f, in_width, in_height)))
{
image_error ("Invalid image size (see `max-image-size')", Qnil, Qnil);
return 0;
}
+ img->width = in_width;
+ img->height = in_height;
/* Create the pixmap. */
- xassert (img->pixmap == NO_PIXMAP);
+ eassert (img->pixmap == NO_PIXMAP);
- /* Only W32 version did BLOCK_INPUT here. ++kfs */
- BLOCK_INPUT;
- img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- img->width, img->height,
- DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
- UNBLOCK_INPUT;
+ if (x_check_image_size (0, img->width, img->height))
+ {
+ /* Only W32 version did BLOCK_INPUT here. ++kfs */
+ block_input ();
+ img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ img->width, img->height,
+ DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
+ unblock_input ();
+ }
if (!img->pixmap)
{
if successful. We do not record_unwind_protect here because
other places in redisplay like calling window scroll functions
don't either. Let the Lisp loader use `unwind-protect' instead. */
- GCPRO2 (window_and_pixmap_id, pixel_colors);
+ printnum1 = FRAME_X_WINDOW (f);
+ printnum2 = img->pixmap;
+ window_and_pixmap_id
+ = make_formatted_string (buffer, "%"pMu" %"pMu, printnum1, printnum2);
- sprintf (buffer, "%lu %lu",
- (unsigned long) FRAME_X_WINDOW (f),
- (unsigned long) img->pixmap);
- window_and_pixmap_id = build_string (buffer);
-
- sprintf (buffer, "%lu %lu",
- FRAME_FOREGROUND_PIXEL (f),
- FRAME_BACKGROUND_PIXEL (f));
- pixel_colors = build_string (buffer);
+ printnum1 = FRAME_FOREGROUND_PIXEL (f);
+ printnum2 = FRAME_BACKGROUND_PIXEL (f);
+ pixel_colors
+ = make_formatted_string (buffer, "%"pMu" %"pMu, printnum1, printnum2);
XSETFRAME (frame, f);
loader = image_spec_value (img->spec, QCloader, NULL);
if (NILP (loader))
loader = intern ("gs-load-image");
- img->data.lisp_val = call6 (loader, frame, img->spec,
- make_number (img->width),
- make_number (img->height),
- window_and_pixmap_id,
- pixel_colors);
- UNGCPRO;
- return PROCESSP (img->data.lisp_val);
+ img->lisp_data = call6 (loader, frame, img->spec,
+ make_number (img->width),
+ make_number (img->height),
+ window_and_pixmap_id,
+ pixel_colors);
+ return PROCESSP (img->lisp_data);
}
telling Emacs that Ghostscript has finished drawing. */
void
-x_kill_gs_process (pixmap, f)
- Pixmap pixmap;
- struct frame *f;
+x_kill_gs_process (Pixmap pixmap, struct frame *f)
{
struct image_cache *c = FRAME_IMAGE_CACHE (f);
- int class, i;
+ int class;
+ ptrdiff_t i;
struct image *img;
/* Find the image containing PIXMAP. */
/* Kill the GS process. We should have found PIXMAP in the image
cache and its image should contain a process object. */
img = c->images[i];
- xassert (PROCESSP (img->data.lisp_val));
- Fkill_process (img->data.lisp_val, Qnil);
- img->data.lisp_val = Qnil;
+ eassert (PROCESSP (img->lisp_data));
+ Fkill_process (img->lisp_data, Qnil);
+ img->lisp_data = Qnil;
#if defined (HAVE_X_WINDOWS)
{
XImagePtr ximg;
- BLOCK_INPUT;
+ block_input ();
/* Try to get an XImage for img->pixmep. */
ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
image_error ("Cannot get X image of `%s'; colors will not be freed",
img->spec, Qnil);
- UNBLOCK_INPUT;
+ unblock_input ();
}
#endif /* HAVE_X_WINDOWS */
/* Now that we have the pixmap, compute mask and transform the
image if requested. */
- BLOCK_INPUT;
+ block_input ();
postprocess_image (f, img);
- UNBLOCK_INPUT;
+ unblock_input ();
}
#endif /* HAVE_GHOSTSCRIPT */
Tests
***********************************************************************/
-#if GLYPH_DEBUG
+#ifdef GLYPH_DEBUG
DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
doc: /* Value is non-nil if SPEC is a valid image specification. */)
- (spec)
- Lisp_Object spec;
+ (Lisp_Object spec)
{
return valid_image_p (spec) ? Qt : Qnil;
}
DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
- (spec)
- Lisp_Object spec;
+ (Lisp_Object spec)
{
- int id = -1;
+ ptrdiff_t id = -1;
if (valid_image_p (spec))
id = lookup_image (SELECTED_FRAME (), spec);
return make_number (id);
}
-#endif /* GLYPH_DEBUG != 0 */
+#endif /* GLYPH_DEBUG */
/***********************************************************************
Initialization
***********************************************************************/
-#ifdef HAVE_NTGUI
-/* Image types that rely on external libraries are loaded dynamically
- if the library is available. */
-#define CHECK_LIB_AVAILABLE(image_type, init_lib_fn, libraries) \
- define_image_type (image_type, init_lib_fn (libraries))
-#else
-#define CHECK_LIB_AVAILABLE(image_type, init_lib_fn, libraries) \
- define_image_type (image_type, 1)
-#endif /* HAVE_NTGUI */
-
-DEFUN ("init-image-library", Finit_image_library, Sinit_image_library, 2, 2, 0,
+DEFUN ("init-image-library", Finit_image_library, Sinit_image_library, 1, 1, 0,
doc: /* Initialize image library implementing image type TYPE.
Return non-nil if TYPE is a supported image type.
-Image types pbm and xbm are prebuilt; other types are loaded here.
-Libraries to load are specified in alist LIBRARIES (usually, the value
-of `image-library-alist', which see). */)
- (type, libraries)
- Lisp_Object type, libraries;
+If image libraries are loaded dynamically (currently only the case on
+MS-Windows), load the library for TYPE if it is not yet loaded, using
+the library file(s) specified by `dynamic-library-alist'. */)
+ (Lisp_Object type)
+{
+ return lookup_image_type (type) ? Qt : Qnil;
+}
+
+/* Look up image type TYPE, and return a pointer to its image_type
+ structure. Return 0 if TYPE is not a known image type. */
+
+static struct image_type *
+lookup_image_type (Lisp_Object type)
{
- Lisp_Object tested;
+ /* Types pbm and xbm are built-in and always available. */
+ if (EQ (type, Qpbm))
+ return define_image_type (&pbm_type);
- /* Don't try to reload the library. */
- tested = Fassq (type, Vimage_type_cache);
- if (CONSP (tested))
- return XCDR (tested);
+ if (EQ (type, Qxbm))
+ return define_image_type (&xbm_type);
#if defined (HAVE_XPM) || defined (HAVE_NS)
if (EQ (type, Qxpm))
- return CHECK_LIB_AVAILABLE (&xpm_type, init_xpm_functions, libraries);
+ return define_image_type (&xpm_type);
#endif
#if defined (HAVE_JPEG) || defined (HAVE_NS)
if (EQ (type, Qjpeg))
- return CHECK_LIB_AVAILABLE (&jpeg_type, init_jpeg_functions, libraries);
+ return define_image_type (&jpeg_type);
#endif
#if defined (HAVE_TIFF) || defined (HAVE_NS)
if (EQ (type, Qtiff))
- return CHECK_LIB_AVAILABLE (&tiff_type, init_tiff_functions, libraries);
+ return define_image_type (&tiff_type);
#endif
#if defined (HAVE_GIF) || defined (HAVE_NS)
if (EQ (type, Qgif))
- return CHECK_LIB_AVAILABLE (&gif_type, init_gif_functions, libraries);
+ return define_image_type (&gif_type);
#endif
#if defined (HAVE_PNG) || defined (HAVE_NS)
if (EQ (type, Qpng))
- return CHECK_LIB_AVAILABLE (&png_type, init_png_functions, libraries);
+ return define_image_type (&png_type);
#endif
#if defined (HAVE_RSVG)
if (EQ (type, Qsvg))
- return CHECK_LIB_AVAILABLE (&svg_type, init_svg_functions, libraries);
+ return define_image_type (&svg_type);
+#endif
+
+#if defined (HAVE_IMAGEMAGICK)
+ if (EQ (type, Qimagemagick))
+ return define_image_type (&imagemagick_type);
#endif
#ifdef HAVE_GHOSTSCRIPT
if (EQ (type, Qpostscript))
- return CHECK_LIB_AVAILABLE (&gs_type, init_gs_functions, libraries);
+ return define_image_type (&gs_type);
#endif
- /* If the type is not recognized, avoid testing it ever again. */
- CACHE_IMAGE_TYPE (type, Qnil);
- return Qnil;
+ return NULL;
}
void
-syms_of_image ()
+syms_of_image (void)
{
- extern Lisp_Object Qrisky_local_variable; /* Syms_of_xdisp has already run. */
-
/* Initialize this only once, since that's what we do with Vimage_types
and they are supposed to be in sync. Initializing here gives correct
operation on GNU/Linux of calling dump-emacs after loading some images. */
image_types = NULL;
- /* Must be defined now becase we're going to update it below, while
+ /* Must be defined now because we're going to update it below, while
defining the supported image types. */
- DEFVAR_LISP ("image-types", &Vimage_types,
+ DEFVAR_LISP ("image-types", Vimage_types,
doc: /* List of potentially supported image types.
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;
- DEFVAR_LISP ("image-library-alist", &Vimage_library_alist,
- doc: /* Alist of image types vs external libraries needed to display them.
-
-Each element is a list (IMAGE-TYPE LIBRARY...), where the car is a symbol
-representing a supported image type, and the rest are strings giving
-alternate filenames for the corresponding external libraries.
-
-Emacs tries to load the libraries in the order they appear on the
-list; if none is loaded, the running session of Emacs won't
-support the image type. Types 'pbm and 'xbm don't need to be
-listed; they are always supported. */);
- Vimage_library_alist = Qnil;
- Fput (intern_c_string ("image-library-alist"), Qrisky_local_variable, Qt);
-
- DEFVAR_LISP ("max-image-size", &Vmax_image_size,
+ 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.
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_c_string ("pbm");
- staticpro (&Qpbm);
- ADD_IMAGE_TYPE (Qpbm);
-
- Qxbm = intern_c_string ("xbm");
- staticpro (&Qxbm);
- ADD_IMAGE_TYPE (Qxbm);
-
- define_image_type (&xbm_type, 1);
- define_image_type (&pbm_type, 1);
-
- Qcount = intern_c_string ("count");
- staticpro (&Qcount);
-
- QCascent = intern_c_string (":ascent");
- staticpro (&QCascent);
- QCmargin = intern_c_string (":margin");
- staticpro (&QCmargin);
- QCrelief = intern_c_string (":relief");
- staticpro (&QCrelief);
- QCconversion = intern_c_string (":conversion");
- staticpro (&QCconversion);
- QCcolor_symbols = intern_c_string (":color-symbols");
- staticpro (&QCcolor_symbols);
- QCheuristic_mask = intern_c_string (":heuristic-mask");
- staticpro (&QCheuristic_mask);
- QCindex = intern_c_string (":index");
- staticpro (&QCindex);
- QCmatrix = intern_c_string (":matrix");
- staticpro (&QCmatrix);
- QCcolor_adjustment = intern_c_string (":color-adjustment");
- staticpro (&QCcolor_adjustment);
- QCmask = intern_c_string (":mask");
- staticpro (&QCmask);
-
- Qlaplace = intern_c_string ("laplace");
- staticpro (&Qlaplace);
- Qemboss = intern_c_string ("emboss");
- staticpro (&Qemboss);
- Qedge_detection = intern_c_string ("edge-detection");
- staticpro (&Qedge_detection);
- Qheuristic = intern_c_string ("heuristic");
- staticpro (&Qheuristic);
-
- Qpostscript = intern_c_string ("postscript");
- staticpro (&Qpostscript);
+ DEFSYM (Qcount, "count");
+ DEFSYM (Qextension_data, "extension-data");
+ DEFSYM (Qdelay, "delay");
+
+ DEFSYM (QCascent, ":ascent");
+ DEFSYM (QCmargin, ":margin");
+ DEFSYM (QCrelief, ":relief");
+ DEFSYM (QCconversion, ":conversion");
+ DEFSYM (QCcolor_symbols, ":color-symbols");
+ DEFSYM (QCheuristic_mask, ":heuristic-mask");
+ DEFSYM (QCindex, ":index");
+ DEFSYM (QCgeometry, ":geometry");
+ DEFSYM (QCcrop, ":crop");
+ DEFSYM (QCrotation, ":rotation");
+ DEFSYM (QCmatrix, ":matrix");
+ DEFSYM (QCcolor_adjustment, ":color-adjustment");
+ DEFSYM (QCmask, ":mask");
+
+ DEFSYM (Qlaplace, "laplace");
+ DEFSYM (Qemboss, "emboss");
+ DEFSYM (Qedge_detection, "edge-detection");
+ DEFSYM (Qheuristic, "heuristic");
+
+ DEFSYM (Qpostscript, "postscript");
#ifdef HAVE_GHOSTSCRIPT
ADD_IMAGE_TYPE (Qpostscript);
- QCloader = intern_c_string (":loader");
- staticpro (&QCloader);
- QCbounding_box = intern_c_string (":bounding-box");
- staticpro (&QCbounding_box);
- QCpt_width = intern_c_string (":pt-width");
- staticpro (&QCpt_width);
- QCpt_height = intern_c_string (":pt-height");
- staticpro (&QCpt_height);
+ DEFSYM (QCloader, ":loader");
+ DEFSYM (QCbounding_box, ":bounding-box");
+ DEFSYM (QCpt_width, ":pt-width");
+ DEFSYM (QCpt_height, ":pt-height");
#endif /* HAVE_GHOSTSCRIPT */
#ifdef HAVE_NTGUI
- Qlibpng_version = intern_c_string ("libpng-version");
- staticpro (&Qlibpng_version);
+ DEFSYM (Qlibpng_version, "libpng-version");
Fset (Qlibpng_version,
#if HAVE_PNG
make_number (PNG_LIBPNG_VER)
);
#endif
+ DEFSYM (Qpbm, "pbm");
+ ADD_IMAGE_TYPE (Qpbm);
+
+ DEFSYM (Qxbm, "xbm");
+ ADD_IMAGE_TYPE (Qxbm);
+
#if defined (HAVE_XPM) || defined (HAVE_NS)
- Qxpm = intern_c_string ("xpm");
- staticpro (&Qxpm);
+ DEFSYM (Qxpm, "xpm");
ADD_IMAGE_TYPE (Qxpm);
#endif
#if defined (HAVE_JPEG) || defined (HAVE_NS)
- Qjpeg = intern_c_string ("jpeg");
- staticpro (&Qjpeg);
+ DEFSYM (Qjpeg, "jpeg");
ADD_IMAGE_TYPE (Qjpeg);
#endif
#if defined (HAVE_TIFF) || defined (HAVE_NS)
- Qtiff = intern_c_string ("tiff");
- staticpro (&Qtiff);
+ DEFSYM (Qtiff, "tiff");
ADD_IMAGE_TYPE (Qtiff);
#endif
#if defined (HAVE_GIF) || defined (HAVE_NS)
- Qgif = intern_c_string ("gif");
- staticpro (&Qgif);
+ DEFSYM (Qgif, "gif");
ADD_IMAGE_TYPE (Qgif);
#endif
#if defined (HAVE_PNG) || defined (HAVE_NS)
- Qpng = intern_c_string ("png");
- staticpro (&Qpng);
+ DEFSYM (Qpng, "png");
ADD_IMAGE_TYPE (Qpng);
#endif
+#if defined (HAVE_IMAGEMAGICK)
+ DEFSYM (Qimagemagick, "imagemagick");
+ ADD_IMAGE_TYPE (Qimagemagick);
+#endif
+
#if defined (HAVE_RSVG)
- Qsvg = intern_c_string ("svg");
- staticpro (&Qsvg);
+ DEFSYM (Qsvg, "svg");
ADD_IMAGE_TYPE (Qsvg);
#ifdef HAVE_NTGUI
/* Other libraries used directly by svg code. */
- Qgdk_pixbuf = intern_c_string ("gdk-pixbuf");
- staticpro (&Qgdk_pixbuf);
- Qglib = intern_c_string ("glib");
- staticpro (&Qglib);
- Qgobject = intern_c_string ("gobject");
- staticpro (&Qgobject);
+ DEFSYM (Qgdk_pixbuf, "gdk-pixbuf");
+ DEFSYM (Qglib, "glib");
+ DEFSYM (Qgobject, "gobject");
#endif /* HAVE_NTGUI */
#endif /* HAVE_RSVG */
defsubr (&Sinit_image_library);
+#ifdef HAVE_IMAGEMAGICK
+ defsubr (&Simagemagick_types);
+#endif
defsubr (&Sclear_image_cache);
- defsubr (&Simage_refresh);
+ defsubr (&Simage_flush);
defsubr (&Simage_size);
defsubr (&Simage_mask_p);
- defsubr (&Simage_extension_data);
+ defsubr (&Simage_metadata);
-#if GLYPH_DEBUG
+#ifdef GLYPH_DEBUG
defsubr (&Simagep);
defsubr (&Slookup_image);
#endif
- DEFVAR_BOOL ("cross-disabled-images", &cross_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 a `:conversion disabled' property.
A cross is always drawn on black & white displays. */);
cross_disabled_images = 0;
- DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
+ DEFVAR_LISP ("x-bitmap-file-path", Vx_bitmap_file_path,
doc: /* List of directories to search for window system bitmap files. */);
Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
- DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
- doc: /* Time after which cached images are removed from the cache.
-When an image has not been displayed this many seconds, remove it
-from the image cache. Value must be an integer or nil with nil
-meaning don't clear the cache. */);
- Vimage_cache_eviction_delay = make_number (30 * 60);
-}
+ DEFVAR_LISP ("image-cache-eviction-delay", Vimage_cache_eviction_delay,
+ doc: /* Maximum time after which images are removed from the cache.
+When an image has not been displayed this many seconds, Emacs
+automatically removes it from the image cache. If the cache contains
+a large number of images, the actual eviction time may be shorter.
+The value can also be nil, meaning the cache is never cleared.
+
+The function `clear-image-cache' disregards this variable. */);
+ Vimage_cache_eviction_delay = make_number (300);
+#ifdef HAVE_IMAGEMAGICK
+ DEFVAR_INT ("imagemagick-render-type", imagemagick_render_type,
+ doc: /* Integer indicating which ImageMagick rendering method to use.
+The options are:
+ 0 -- the default method (pixel pushing)
+ 1 -- a newer method ("MagickExportImagePixels") that may perform
+ better (speed etc) in some cases, but has not been as thoroughly
+ tested with Emacs as the default method. This method requires
+ ImageMagick version 6.4.6 (approximately) or later.
+*/);
+ /* MagickExportImagePixels is in 6.4.6-9, but not 6.4.4-10. */
+ imagemagick_render_type = 0;
+#endif
-void
-init_image ()
-{
}
-
-/* arch-tag: 123c2a5e-14a8-4c53-ab95-af47d7db49b9
- (do not change this comment) */