along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
-#include <stdio.h>
+#include "sysstdio.h"
#include <unistd.h>
#ifdef HAVE_PNG
#define GET_PIXEL(ximg, x, y) XGetPixel (ximg, x, y)
#define NO_PIXMAP 0
-#define ZPixmap 0
-
#define PIX_MASK_RETAIN 0
#define PIX_MASK_DRAW 1
static unsigned long *colors_in_color_table (int *n);
#endif
-Lisp_Object QCmax_width, QCmax_height;
+static Lisp_Object QCmax_width, QCmax_height;
/* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
id, which is just an int that this section returns. Bitmaps are
data more than once will not be caught. */
#ifdef HAVE_NS
-XImagePtr
-XGetImage (Display *display, Pixmap pixmap, int x, int y,
- unsigned int width, unsigned int height,
- unsigned long plane_mask, int format)
-{
- /* TODO: not sure what this function is supposed to do.. */
- ns_retain_object (pixmap);
- return pixmap;
-}
-
/* Use with images created by ns_image_for_XPM. */
unsigned long
XGetPixel (XImagePtr ximage, int x, int y)
/* Functions to access the contents of a bitmap, given an id. */
int
-x_bitmap_height (FRAME_PTR f, ptrdiff_t id)
+x_bitmap_height (struct frame *f, ptrdiff_t id)
{
return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height;
}
int
-x_bitmap_width (FRAME_PTR f, ptrdiff_t id)
+x_bitmap_width (struct frame *f, ptrdiff_t id)
{
return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width;
}
#if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI)
ptrdiff_t
-x_bitmap_pixmap (FRAME_PTR f, ptrdiff_t id)
+x_bitmap_pixmap (struct frame *f, ptrdiff_t id)
{
/* HAVE_NTGUI needs the explicit cast here. */
return (ptrdiff_t) FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
#ifdef HAVE_X_WINDOWS
int
-x_bitmap_mask (FRAME_PTR f, ptrdiff_t id)
+x_bitmap_mask (struct frame *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 ptrdiff_t
-x_allocate_bitmap_record (FRAME_PTR f)
+x_allocate_bitmap_record (struct frame *f)
{
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
ptrdiff_t i;
/* Add one reference to the reference count of the bitmap with id ID. */
void
-x_reference_bitmap (FRAME_PTR f, ptrdiff_t id)
+x_reference_bitmap (struct frame *f, ptrdiff_t id)
{
++FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
}
int xhot, yhot, result;
ptrdiff_t id;
Lisp_Object found;
- int fd;
char *filename;
/* Look for an existing bitmap with the same name. */
}
/* Search bitmap-file-path for the file, if appropriate. */
- fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
- if (fd < 0)
+ if (openp (Vx_bitmap_file_path, file, Qnil, &found, make_number (R_OK)) < 0)
return -1;
- emacs_close (fd);
filename = SSDATA (found);
/* Remove reference to bitmap with id number ID. */
void
-x_destroy_bitmap (FRAME_PTR f, ptrdiff_t id)
+x_destroy_bitmap (struct frame *f, ptrdiff_t id)
{
Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
XImagePtr *, Pixmap *);
static void x_destroy_x_image (XImagePtr ximg);
+#ifdef HAVE_NTGUI
+static XImagePtr_or_DC image_get_x_image_or_dc (struct frame *, struct image *,
+ bool, HGDIOBJ *);
+static void image_unget_x_image_or_dc (struct image *, bool, XImagePtr_or_DC,
+ HGDIOBJ);
+#else
+static XImagePtr image_get_x_image (struct frame *, struct image *, bool);
+static void image_unget_x_image (struct image *, bool, XImagePtr);
+#define image_get_x_image_or_dc(f, img, mask_p, dummy) \
+ image_get_x_image (f, img, mask_p)
+#define image_unget_x_image_or_dc(img, mask_p, ximg, dummy) \
+ image_unget_x_image (img, mask_p, ximg)
+#endif
+
#ifdef HAVE_X_WINDOWS
+static void image_sync_to_pixmaps (struct frame *, struct image *);
+
/* Useful functions defined in the section
`Image type independent image structures' below. */
if (img->pixmap == NO_PIXMAP && !img->load_failed_p)
img->load_failed_p = ! img->type->load (f, img);
+#ifdef HAVE_X_WINDOWS
+ if (!img->load_failed_p)
+ {
+ block_input ();
+ image_sync_to_pixmaps (f, img);
+ unblock_input ();
+ }
+#endif
}
#ifdef HAVE_NTGUI
-#define Destroy_Image(img_dc, prev) \
- do { SelectObject (img_dc, prev); DeleteDC (img_dc); } while (0)
-
#define Free_Pixmap(display, pixmap) \
DeleteObject (pixmap)
#elif defined (HAVE_NS)
-#define Destroy_Image(ximg, dummy) \
- ns_release_object (ximg)
-
#define Free_Pixmap(display, pixmap) \
ns_release_object (pixmap)
#else
-#define Destroy_Image(ximg, dummy) \
- XDestroyImage (ximg)
-
#define Free_Pixmap(display, pixmap) \
XFreePixmap (display, pixmap)
#endif /* HAVE_NTGUI */
if (free_ximg)
- {
-#ifndef HAVE_NTGUI
- ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
- 0, 0, img->width, img->height, ~0, ZPixmap);
-#else
- HDC frame_dc = get_frame_dc (f);
- ximg = CreateCompatibleDC (frame_dc);
- release_frame_dc (f, frame_dc);
- prev = SelectObject (ximg, img->pixmap);
-#endif /* !HAVE_NTGUI */
- }
+ ximg = image_get_x_image_or_dc (f, img, 0, &prev);
img->background = four_corners_best (ximg, img->corners, img->width, img->height);
if (free_ximg)
- Destroy_Image (ximg, prev);
+ image_unget_x_image_or_dc (img, 0, ximg, prev);
img->background_valid = 1;
}
#endif /* HAVE_NTGUI */
if (free_mask)
- {
-#ifndef HAVE_NTGUI
- mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
- 0, 0, img->width, img->height, ~0, ZPixmap);
-#else
- HDC frame_dc = get_frame_dc (f);
- mask = CreateCompatibleDC (frame_dc);
- release_frame_dc (f, frame_dc);
- prev = SelectObject (mask, img->mask);
-#endif /* HAVE_NTGUI */
- }
+ mask = image_get_x_image_or_dc (f, img, 1, &prev);
img->background_transparent
= (four_corners_best (mask, img->corners, img->width, img->height) == PIX_MASK_RETAIN);
if (free_mask)
- Destroy_Image (mask, prev);
+ image_unget_x_image_or_dc (img, 1, mask, prev);
}
else
img->background_transparent = 0;
Helper functions for X image types
***********************************************************************/
-/* Clear X resources of image IMG on frame F. PIXMAP_P means free the
- pixmap if any. MASK_P means clear the mask pixmap if any.
- COLORS_P means free colors allocated for the image, if any. */
+/* Clear X resources of image IMG on frame F according to FLAGS.
+ FLAGS is bitwise-or of the following masks:
+ CLEAR_IMAGE_PIXMAP free the pixmap if any.
+ CLEAR_IMAGE_MASK means clear the mask pixmap if any.
+ CLEAR_IMAGE_COLORS means free colors allocated for the image, if
+ any. */
+
+#define CLEAR_IMAGE_PIXMAP (1 << 0)
+#define CLEAR_IMAGE_MASK (1 << 1)
+#define CLEAR_IMAGE_COLORS (1 << 2)
static void
-x_clear_image_1 (struct frame *f, struct image *img, bool pixmap_p,
- bool mask_p, bool colors_p)
+x_clear_image_1 (struct frame *f, struct image *img, int flags)
{
- if (pixmap_p && img->pixmap)
+ if (flags & CLEAR_IMAGE_PIXMAP)
{
- Free_Pixmap (FRAME_X_DISPLAY (f), img->pixmap);
- img->pixmap = NO_PIXMAP;
- /* NOTE (HAVE_NS): background color is NOT an indexed color! */
- img->background_valid = 0;
+ if (img->pixmap)
+ {
+ Free_Pixmap (FRAME_X_DISPLAY (f), img->pixmap);
+ img->pixmap = NO_PIXMAP;
+ /* NOTE (HAVE_NS): background color is NOT an indexed color! */
+ img->background_valid = 0;
+ }
+#ifdef HAVE_X_WINDOWS
+ if (img->ximg)
+ {
+ x_destroy_x_image (img->ximg);
+ img->ximg = NULL;
+ img->background_valid = 0;
+ }
+#endif
}
- if (mask_p && img->mask)
+ if (flags & CLEAR_IMAGE_MASK)
{
- Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
- img->mask = NO_PIXMAP;
- img->background_transparent_valid = 0;
+ if (img->mask)
+ {
+ Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
+ img->mask = NO_PIXMAP;
+ img->background_transparent_valid = 0;
+ }
+#ifdef HAVE_X_WINDOWS
+ if (img->mask_img)
+ {
+ x_destroy_x_image (img->mask_img);
+ img->mask_img = NULL;
+ img->background_transparent_valid = 0;
+ }
+#endif
}
- if (colors_p && img->ncolors)
+ if ((flags & CLEAR_IMAGE_COLORS) && img->ncolors)
{
/* W32_TODO: color table support. */
#ifdef HAVE_X_WINDOWS
x_clear_image (struct frame *f, struct image *img)
{
block_input ();
- x_clear_image_1 (f, img, 1, 1, 1);
+ x_clear_image_1 (f, img,
+ CLEAR_IMAGE_PIXMAP | CLEAR_IMAGE_MASK | CLEAR_IMAGE_COLORS);
unblock_input ();
}
DEFUN ("image-flush", Fimage_flush, Simage_flush,
1, 2, 0,
- doc: /* Fush the image with specification SPEC on frame FRAME.
+ doc: /* Flush 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.
x_build_heuristic_mask (f, img, XCDR (mask));
}
else if (NILP (mask) && found_p && img->mask)
- {
- Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
- img->mask = NO_PIXMAP;
- }
+ x_clear_image_1 (f, img, CLEAR_IMAGE_MASK);
}
#endif
}
+/* Thin wrapper for x_create_x_image_and_pixmap, so that it matches
+ with image_put_x_image. */
+
+static bool
+image_create_x_image_and_pixmap (struct frame *f, struct image *img,
+ int width, int height, int depth,
+ XImagePtr *ximg, bool mask_p)
+{
+ eassert ((!mask_p ? img->pixmap : img->mask) == NO_PIXMAP);
+
+ return x_create_x_image_and_pixmap (f, width, height, depth, ximg,
+ !mask_p ? &img->pixmap : &img->mask);
+}
+
+/* Put X image XIMG into image IMG on frame F, as a mask if and only
+ if MASK_P. On X, this simply records XIMG on a member of IMG, so
+ it can be put into the pixmap afterwards via image_sync_to_pixmaps.
+ On the other platforms, it puts XIMG into the pixmap, then frees
+ the X image and its buffer. */
+
+static void
+image_put_x_image (struct frame *f, struct image *img, XImagePtr ximg,
+ bool mask_p)
+{
+#ifdef HAVE_X_WINDOWS
+ if (!mask_p)
+ {
+ eassert (img->ximg == NULL);
+ img->ximg = ximg;
+ }
+ else
+ {
+ eassert (img->mask_img == NULL);
+ img->mask_img = ximg;
+ }
+#else
+ x_put_x_image (f, ximg, !mask_p ? img->pixmap : img->mask,
+ img->width, img->height);
+ x_destroy_x_image (ximg);
+#endif
+}
+
+#ifdef HAVE_X_WINDOWS
+/* Put the X images recorded in IMG on frame F into pixmaps, then free
+ the X images and their buffers. */
+
+static void
+image_sync_to_pixmaps (struct frame *f, struct image *img)
+{
+ if (img->ximg)
+ {
+ x_put_x_image (f, img->ximg, img->pixmap, img->width, img->height);
+ x_destroy_x_image (img->ximg);
+ img->ximg = NULL;
+ }
+ if (img->mask_img)
+ {
+ x_put_x_image (f, img->mask_img, img->mask, img->width, img->height);
+ x_destroy_x_image (img->mask_img);
+ img->mask_img = NULL;
+ }
+}
+#endif
+
+#ifdef HAVE_NTGUI
+/* Create a memory device context for IMG on frame F. It stores the
+ currently selected GDI object into *PREV for future restoration by
+ image_unget_x_image_or_dc. */
+
+static XImagePtr_or_DC
+image_get_x_image_or_dc (struct frame *f, struct image *img, bool mask_p,
+ HGDIOBJ *prev)
+{
+ HDC frame_dc = get_frame_dc (f);
+ XImagePtr_or_DC ximg = CreateCompatibleDC (frame_dc);
+
+ release_frame_dc (f, frame_dc);
+ *prev = SelectObject (ximg, !mask_p ? img->pixmap : img->mask);
+
+ return ximg;
+}
+
+static void
+image_unget_x_image_or_dc (struct image *img, bool mask_p,
+ XImagePtr_or_DC ximg, HGDIOBJ prev)
+{
+ SelectObject (ximg, prev);
+ DeleteDC (ximg);
+}
+#else /* !HAVE_NTGUI */
+/* Get the X image for IMG on frame F. The resulting X image data
+ should be treated as read-only at least on X. */
+
+static XImagePtr
+image_get_x_image (struct frame *f, struct image *img, bool mask_p)
+{
+#ifdef HAVE_X_WINDOWS
+ XImagePtr ximg_in_img = !mask_p ? img->ximg : img->mask_img;
+
+ if (ximg_in_img)
+ return ximg_in_img;
+ else
+ return XGetImage (FRAME_X_DISPLAY (f), !mask_p ? img->pixmap : img->mask,
+ 0, 0, img->width, img->height, ~0, ZPixmap);
+#elif defined (HAVE_NS)
+ XImagePtr pixmap = !mask_p ? img->pixmap : img->mask;
+
+ ns_retain_object (pixmap);
+ return pixmap;
+#endif
+}
+
+static void
+image_unget_x_image (struct image *img, bool mask_p, XImagePtr ximg)
+{
+#ifdef HAVE_X_WINDOWS
+ XImagePtr ximg_in_img = !mask_p ? img->ximg : img->mask_img;
+
+ if (ximg_in_img)
+ eassert (ximg == ximg_in_img);
+ else
+ XDestroyImage (ximg);
+#elif defined (HAVE_NS)
+ ns_release_object (ximg);
+#endif
+}
+#endif /* !HAVE_NTGUI */
+
\f
/***********************************************************************
File Handling
else
{
file_found = ENCODE_FILE (file_found);
- close (fd);
+ if (fd != -2)
+ emacs_close (fd);
}
return file_found;
static unsigned char *
slurp_file (char *file, ptrdiff_t *size)
{
- FILE *fp = fopen (file, "rb");
+ FILE *fp = emacs_fopen (file, "rb");
unsigned char *buf = NULL;
struct stat st;
- if (fp && fstat (fileno (fp), &st) == 0
- && 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;
- fclose (fp);
- }
- else
+ if (fp)
{
- if (fp)
- fclose (fp);
- if (buf)
+ ptrdiff_t count = SPECPDL_INDEX ();
+ record_unwind_protect_ptr (fclose_unwind, fp);
+
+ if (fstat (fileno (fp), &st) == 0
+ && 0 <= st.st_size && st.st_size < min (PTRDIFF_MAX, SIZE_MAX))
{
- xfree (buf);
- buf = NULL;
+ /* Report an error if we read past the purported EOF.
+ This can happen if the file grows as we read it. */
+ ptrdiff_t buflen = st.st_size;
+ buf = xmalloc (buflen + 1);
+ if (fread (buf, 1, buflen + 1, fp) == buflen)
+ *size = buflen;
+ else
+ {
+ xfree (buf);
+ buf = NULL;
+ }
}
+
+ unbind_to (count, Qnil);
}
return buf;
xpm_alloc_color (Display *dpy, Colormap cmap, char *color_name, XColor *color,
void *closure)
{
- return xpm_lookup_color ((struct frame *) closure, color_name, color);
+ return xpm_lookup_color (closure, color_name, color);
}
&xpm_image, &xpm_mask,
&attrs);
#else
- rc = XpmReadFileToPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- SSDATA (file), &img->pixmap, &img->mask,
- &attrs);
+ rc = XpmReadFileToImage (FRAME_X_DISPLAY (f), SSDATA (file),
+ &img->ximg, &img->mask_img,
+ &attrs);
#endif /* HAVE_NTGUI */
}
else
&xpm_image, &xpm_mask,
&attrs);
#else
- rc = XpmCreatePixmapFromBuffer (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- SSDATA (buffer),
- &img->pixmap, &img->mask,
- &attrs);
+ rc = XpmCreateImageFromBuffer (FRAME_X_DISPLAY (f), SSDATA (buffer),
+ &img->ximg, &img->mask_img,
+ &attrs);
#endif /* HAVE_NTGUI */
}
+#ifdef HAVE_X_WINDOWS
+ if (rc == XpmSuccess)
+ {
+ img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ img->ximg->width, img->ximg->height,
+ img->ximg->depth);
+ if (img->pixmap == NO_PIXMAP)
+ {
+ x_clear_image (f, img);
+ rc = XpmNoMemory;
+ }
+ else if (img->mask_img)
+ {
+ img->mask = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ img->mask_img->width,
+ img->mask_img->height,
+ img->mask_img->depth);
+ if (img->mask == NO_PIXMAP)
+ {
+ x_clear_image (f, img);
+ rc = XpmNoMemory;
+ }
+ }
+ }
+#endif
+
if (rc == XpmSuccess)
{
#if defined (COLOR_TABLE_SUPPORT) && defined (ALLOC_XPM_COLORS)
#else
XpmFreeAttributes (&attrs);
#endif /* HAVE_NTGUI */
+
+#ifdef HAVE_X_WINDOWS
+ /* Maybe fill in the background field while we have ximg handy. */
+ IMAGE_BACKGROUND (img, f, img->ximg);
+ if (img->mask_img)
+ /* Fill in the background_transparent field while we have the
+ mask handy. */
+ image_background_transparent (img, f, img->mask_img);
+#endif
}
else
{
goto failure;
}
- if (!x_create_x_image_and_pixmap (f, width, height, 0,
- &ximg, &img->pixmap)
+ if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0)
#ifndef HAVE_NS
- || !x_create_x_image_and_pixmap (f, width, height, 1,
- &mask_img, &img->mask)
+ || !image_create_x_image_and_pixmap (f, img, width, height, 1,
+ &mask_img, 1)
#endif
)
{
if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
IMAGE_BACKGROUND (img, f, ximg);
- x_put_x_image (f, ximg, img->pixmap, width, height);
- x_destroy_x_image (ximg);
+ image_put_x_image (f, img, ximg, 0);
#ifndef HAVE_NS
if (have_mask)
{
mask handy. */
image_background_transparent (img, f, mask_img);
- x_put_x_image (f, mask_img, img->mask, width, height);
- x_destroy_x_image (mask_img);
+ image_put_x_image (f, img, mask_img, 1);
}
else
{
x_destroy_x_image (mask_img);
- Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
- img->mask = NO_PIXMAP;
+ x_clear_image_1 (f, img, CLEAR_IMAGE_MASK);
}
#endif
return 1;
XColor *colors, *p;
XImagePtr_or_DC ximg;
#ifdef HAVE_NTGUI
- HDC hdc;
HGDIOBJ prev;
#endif /* HAVE_NTGUI */
memory_full (SIZE_MAX);
colors = xmalloc (sizeof *colors * img->width * img->height);
-#ifndef HAVE_NTGUI
- /* Get the X image IMG->pixmap. */
- ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
- 0, 0, img->width, img->height, ~0, ZPixmap);
-#else
- /* Load the image into a memory device context. */
- hdc = get_frame_dc (f);
- ximg = CreateCompatibleDC (hdc);
- release_frame_dc (f, hdc);
- prev = SelectObject (ximg, img->pixmap);
-#endif /* HAVE_NTGUI */
+ /* Get the X image or create a memory device context for IMG. */
+ ximg = image_get_x_image_or_dc (f, img, 0, &prev);
/* Fill the `pixel' members of the XColor array. I wished there
were an easy and portable way to circumvent XGetPixel. */
#endif /* HAVE_X_WINDOWS */
}
- Destroy_Image (ximg, prev);
+ image_unget_x_image_or_dc (img, 0, ximg, prev);
return colors;
}
{
int x, y;
XImagePtr oimg = NULL;
- Pixmap pixmap;
XColor *p;
init_color_table ();
- x_create_x_image_and_pixmap (f, img->width, img->height, 0,
- &oimg, &pixmap);
+ x_clear_image_1 (f, img, CLEAR_IMAGE_PIXMAP | CLEAR_IMAGE_COLORS);
+ image_create_x_image_and_pixmap (f, img, img->width, img->height, 0,
+ &oimg, 0);
p = colors;
for (y = 0; y < img->height; ++y)
for (x = 0; x < img->width; ++x, ++p)
}
xfree (colors);
- x_clear_image_1 (f, img, 1, 0, 1);
- x_put_x_image (f, oimg, pixmap, img->width, img->height);
- x_destroy_x_image (oimg);
- img->pixmap = pixmap;
+ image_put_x_image (f, img, oimg, 0);
#ifdef COLOR_TABLE_SUPPORT
img->colors = colors_in_color_table (&img->ncolors);
free_color_table ();
#define MaskForeground(f) WHITE_PIX_DEFAULT (f)
Display *dpy = FRAME_X_DISPLAY (f);
- GC gc = XCreateGC (dpy, img->pixmap, 0, NULL);
+ GC gc;
+
+ image_sync_to_pixmaps (f, img);
+ 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);
#ifndef HAVE_NTGUI
XImagePtr mask_img;
#else
- HDC frame_dc;
HGDIOBJ prev;
char *mask_img;
int row_width;
unsigned long bg = 0;
if (img->mask)
- {
- Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
- img->mask = NO_PIXMAP;
- img->background_transparent_valid = 0;
- }
+ x_clear_image_1 (f, img, CLEAR_IMAGE_MASK);
#ifndef HAVE_NTGUI
#ifndef HAVE_NS
/* Create an image and pixmap serving as mask. */
- rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
- &mask_img, &img->mask);
+ rc = image_create_x_image_and_pixmap (f, img, img->width, img->height, 1,
+ &mask_img, 1);
if (!rc)
return;
#endif /* !HAVE_NS */
-
- /* Get the X image of IMG->pixmap. */
- ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, 0, 0,
- img->width, img->height,
- ~0, ZPixmap);
#else
/* Create the bit array serving as mask. */
row_width = (img->width + 7) / 8;
mask_img = xzalloc (row_width * img->height);
-
- /* Create a memory device context for IMG->pixmap. */
- frame_dc = get_frame_dc (f);
- ximg = CreateCompatibleDC (frame_dc);
- release_frame_dc (f, frame_dc);
- prev = SelectObject (ximg, img->pixmap);
#endif /* HAVE_NTGUI */
+ /* Get the X image or create a memory device context for IMG. */
+ ximg = image_get_x_image_or_dc (f, img, 0, &prev);
+
/* Determine the background color of ximg. If HOW is `(R G B)'
take that as color. Otherwise, use the image's background color. */
use_img_background = 1;
/* Fill in the background_transparent field while we have the mask handy. */
image_background_transparent (img, f, mask_img);
- /* Put mask_img into img->mask. */
- x_put_x_image (f, mask_img, img->mask, img->width, img->height);
- x_destroy_x_image (mask_img);
+ /* Put mask_img into the image. */
+ image_put_x_image (f, img, mask_img, 1);
#endif /* !HAVE_NS */
#else
for (y = 0; y < img->height; ++y)
xfree (mask_img);
#endif /* HAVE_NTGUI */
- Destroy_Image (ximg, prev);
+ image_unget_x_image_or_dc (img, 0, ximg, prev);
}
\f
goto error;
}
- if (!x_create_x_image_and_pixmap (f, width, height, 0,
- &ximg, &img->pixmap))
+ if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
goto error;
/* Initialize the color hash table. */
/* Casting avoids a GCC warning. */
IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
- /* Put the image into a pixmap. */
- x_put_x_image (f, ximg, img->pixmap, width, height);
- x_destroy_x_image (ximg);
+ /* Put ximg into the image. */
+ image_put_x_image (f, img, ximg, 0);
/* X and W32 versions did it here, MAC version above. ++kfs
img->width = width;
static void
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);
+ struct png_memory_storage *tbr = fn_png_get_io_ptr (png_ptr);
if (length > tbr->len - tbr->index)
fn_png_error (png_ptr, "Read error");
static void
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);
+ FILE *fp = fn_png_get_io_ptr (png_ptr);
if (fread (data, 1, length, fp) < length)
fn_png_error (png_ptr, "Read error");
}
/* Open the image file. */
- fp = fopen (SSDATA (file), "rb");
+ fp = emacs_fopen (SSDATA (file), "rb");
if (!fp)
{
image_error ("Cannot open image file `%s'", file, Qnil);
if (fread (sig, 1, sizeof sig, fp) != sizeof sig
|| fn_png_sig_cmp (sig, 0, sizeof sig))
{
- image_error ("Not a PNG file: `%s'", file, Qnil);
fclose (fp);
+ image_error ("Not a PNG file: `%s'", file, Qnil);
return 0;
}
}
/* Read image info. */
if (!NILP (specified_data))
- fn_png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
+ fn_png_set_read_fn (png_ptr, &tbr, png_read_from_memory);
else
- fn_png_set_read_fn (png_ptr, (void *) fp, png_read_from_file);
+ fn_png_set_read_fn (png_ptr, fp, png_read_from_file);
fn_png_set_sig_bytes (png_ptr, sizeof sig);
fn_png_read_info (png_ptr, info_ptr);
/* 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))
+ if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
goto error;
/* If image contains simply transparency data, we prefer to
contains an alpha channel. */
if (channels == 4
&& !transparent_p
- && !x_create_x_image_and_pixmap (f, width, height, 1,
- &mask_img, &img->mask))
+ && !image_create_x_image_and_pixmap (f, img, width, height, 1,
+ &mask_img, 1))
{
x_destroy_x_image (ximg);
- Free_Pixmap (FRAME_X_DISPLAY (f), img->pixmap);
- img->pixmap = NO_PIXMAP;
+ x_clear_image_1 (f, img, CLEAR_IMAGE_PIXMAP);
goto error;
}
Casting avoids a GCC warning. */
IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
- /* Put the image into the pixmap, then free the X image and its buffer. */
- x_put_x_image (f, ximg, img->pixmap, width, height);
- x_destroy_x_image (ximg);
+ /* Put ximg into the image. */
+ image_put_x_image (f, img, ximg, 0);
/* Same for the mask. */
if (mask_img)
mask handy. Casting avoids a GCC warning. */
image_background_transparent (img, f, (XImagePtr_or_DC)mask_img);
- x_put_x_image (f, mask_img, img->mask, img->width, img->height);
- x_destroy_x_image (mask_img);
+ image_put_x_image (f, img, mask_img, 1);
}
return 1;
static void
our_memory_skip_input_data (j_decompress_ptr cinfo, long int num_bytes)
{
- struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
+ struct jpeg_source_mgr *src = cinfo->src;
if (src)
{
static void
jpeg_memory_src (j_decompress_ptr cinfo, JOCTET *data, ptrdiff_t len)
{
- struct jpeg_source_mgr *src;
+ struct jpeg_source_mgr *src = cinfo->src;
- if (cinfo->src == NULL)
+ if (! src)
{
/* First time for this JPEG object? */
- cinfo->src = (struct jpeg_source_mgr *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- sizeof (struct jpeg_source_mgr));
- src = (struct jpeg_source_mgr *) cinfo->src;
+ src = cinfo->mem->alloc_small ((j_common_ptr) cinfo,
+ JPOOL_PERMANENT, sizeof *src);
+ cinfo->src = src;
src->next_input_byte = data;
}
- src = (struct jpeg_source_mgr *) cinfo->src;
src->init_source = our_common_init_source;
src->fill_input_buffer = our_memory_fill_input_buffer;
src->skip_input_data = our_memory_skip_input_data;
static void
jpeg_file_src (j_decompress_ptr cinfo, FILE *fp)
{
- struct jpeg_stdio_mgr *src;
+ struct jpeg_stdio_mgr *src = (struct jpeg_stdio_mgr *) cinfo->src;
- if (cinfo->src != NULL)
- src = (struct jpeg_stdio_mgr *) cinfo->src;
- else
+ if (! src)
{
/* First time for this JPEG object? */
- cinfo->src = (struct jpeg_source_mgr *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- sizeof (struct jpeg_stdio_mgr));
- src = (struct jpeg_stdio_mgr *) cinfo->src;
- src->buffer = (JOCTET *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- JPEG_STDIO_BUFFER_SIZE);
+ src = cinfo->mem->alloc_small ((j_common_ptr) cinfo,
+ JPOOL_PERMANENT, sizeof *src);
+ cinfo->src = (struct jpeg_source_mgr *) src;
+ src->buffer = cinfo->mem->alloc_small ((j_common_ptr) cinfo,
+ JPOOL_PERMANENT,
+ JPEG_STDIO_BUFFER_SIZE);
}
src->file = fp;
return 0;
}
- fp = fopen (SSDATA (file), "rb");
+ fp = emacs_fopen (SSDATA (file), "rb");
if (fp == NULL)
{
image_error ("Cannot open `%s'", file, Qnil);
}
/* Create X image and pixmap. */
- if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
+ if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
{
mgr->failure_code = MY_JPEG_CANNOT_CREATE_X;
sys_longjmp (mgr->setjmp_buffer, 1);
/* Casting avoids a GCC warning. */
IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
- /* Put the image into the pixmap. */
- x_put_x_image (f, ximg, img->pixmap, width, height);
- x_destroy_x_image (ximg);
+ /* Put ximg into the image. */
+ image_put_x_image (f, img, ximg, 0);
return 1;
}
/* 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)))
+ && image_create_x_image_and_pixmap (f, img, width, height, 0,
+ &ximg, 0)))
{
fn_TIFFClose (tiff);
return 0;
/* Casting avoids a GCC warning on W32. */
IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
- /* Put the image into the pixmap, then free the X image and its buffer. */
- x_put_x_image (f, ximg, img->pixmap, width, height);
- x_destroy_x_image (ximg);
+ /* Put ximg into the image. */
+ image_put_x_image (f, img, ximg, 0);
xfree (buf);
return 1;
}
/* Create the X image and pixmap. */
- if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
+ if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
{
fn_DGifCloseFile (gif);
return 0;
delay |= ext->Bytes[1];
}
}
- img->lisp_data = Fcons (Qextension_data,
- Fcons (img->lisp_data, Qnil));
+ img->lisp_data = list2 (Qextension_data, img->lisp_data);
if (delay)
img->lisp_data
= Fcons (Qdelay,
/* Casting avoids a GCC warning. */
IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
- /* Put the image into the pixmap, then free the X image and its buffer. */
- x_put_x_image (f, ximg, img->pixmap, width, height);
- x_destroy_x_image (ximg);
+ /* Put ximg into the image. */
+ image_put_x_image (f, img, ximg, 0);
return 1;
}
#endif /* HAVE_GIF */
+#ifdef HAVE_IMAGEMAGICK
+
+/***********************************************************************
+ ImageMagick
+***********************************************************************/
+
+/* Scale an image size by returning SIZE / DIVISOR * MULTIPLIER,
+ safely rounded and clipped to int range. */
+
+static int
+scale_image_size (int size, size_t divisor, size_t multiplier)
+{
+ if (divisor != 0)
+ {
+ double s = size;
+ double scaled = s * multiplier / divisor + 0.5;
+ if (scaled < INT_MAX)
+ return scaled;
+ }
+ return INT_MAX;
+}
+
+/* Compute the desired size of an image with native size WIDTH x HEIGHT.
+ Use SPEC to deduce the size. Store the desired size into
+ *D_WIDTH x *D_HEIGHT. Store -1 x -1 if the native size is OK. */
static void
compute_image_size (size_t width, size_t height,
Lisp_Object spec,
unspecified should be calculated from the specified to preserve
aspect ratio. */
value = image_spec_value (spec, QCwidth, NULL);
- desired_width = (INTEGERP (value) ? XFASTINT (value) : -1);
+ desired_width = NATNUMP (value) ? min (XFASTINT (value), INT_MAX) : -1;
value = image_spec_value (spec, QCheight, NULL);
- desired_height = (INTEGERP (value) ? XFASTINT (value) : -1);
+ desired_height = NATNUMP (value) ? min (XFASTINT (value), INT_MAX) : -1;
if (desired_width == -1)
{
value = image_spec_value (spec, QCmax_width, NULL);
- if (INTEGERP (value) &&
- width > XFASTINT (value))
+ if (NATNUMP (value))
{
- /* The image is wider than :max-width. */
- desired_width = XFASTINT (value);
- if (desired_height == -1)
+ int max_width = min (XFASTINT (value), INT_MAX);
+ if (max_width < width)
{
- value = image_spec_value (spec, QCmax_height, NULL);
- if (INTEGERP (value))
+ /* The image is wider than :max-width. */
+ desired_width = max_width;
+ if (desired_height == -1)
{
- /* We have no specified height, but we have a
- :max-height value, so check that we satisfy both
- conditions. */
- desired_height = (double) desired_width / width * height;
- if (desired_height > XFASTINT (value))
+ desired_height = scale_image_size (desired_width,
+ width, height);
+ value = image_spec_value (spec, QCmax_height, NULL);
+ if (NATNUMP (value))
{
- desired_height = XFASTINT (value);
- desired_width = (double) desired_height / height * width;
+ int max_height = min (XFASTINT (value), INT_MAX);
+ if (max_height < desired_height)
+ {
+ desired_height = max_height;
+ desired_width = scale_image_size (desired_height,
+ height, width);
+ }
}
}
- else
- {
- /* We have no specified height and no specified
- max-height, so just compute the height. */
- desired_height = (double) desired_width / width * height;
- }
}
}
}
if (desired_height == -1)
{
value = image_spec_value (spec, QCmax_height, NULL);
- if (INTEGERP (value) &&
- height > XFASTINT (value))
- desired_height = XFASTINT (value);
+ if (NATNUMP (value))
+ {
+ int max_height = min (XFASTINT (value), INT_MAX);
+ if (max_height < height)
+ desired_height = max_height;
+ }
}
if (desired_width != -1 && desired_height == -1)
/* w known, calculate h. */
- desired_height = (double) desired_width / width * height;
+ desired_height = scale_image_size (desired_width, width, height);
if (desired_width == -1 && desired_height != -1)
/* h known, calculate w. */
- desired_width = (double) desired_height / height * width;
+ desired_width = scale_image_size (desired_height, height, width);
*d_width = desired_width;
*d_height = desired_height;
}
-/***********************************************************************
- ImageMagick
-***********************************************************************/
-#if defined (HAVE_IMAGEMAGICK)
-
static Lisp_Object Qimagemagick;
static bool imagemagick_image_p (Lisp_Object);
IMAGEMAGICK_WIDTH,
IMAGEMAGICK_MAX_HEIGHT,
IMAGEMAGICK_MAX_WIDTH,
+ IMAGEMAGICK_FORMAT,
IMAGEMAGICK_ROTATION,
IMAGEMAGICK_CROP,
IMAGEMAGICK_LAST
{":width", IMAGE_INTEGER_VALUE, 0},
{":max-height", IMAGE_INTEGER_VALUE, 0},
{":max-width", IMAGE_INTEGER_VALUE, 0},
+ {":format", IMAGE_SYMBOL_VALUE, 0},
{":rotation", IMAGE_NUMBER_VALUE, 0},
{":crop", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
};
description = (char *) MagickRelinquishMemory (description);
}
+/* Possibly give ImageMagick some extra help to determine the image
+ type by supplying a "dummy" filename based on the Content-Type. */
+
+static char*
+imagemagick_filename_hint (Lisp_Object spec)
+{
+ Lisp_Object format = image_spec_value (spec, intern (":format"), NULL);
+ Lisp_Object symbol = intern ("image-format-suffixes");
+ Lisp_Object val;
+ char *name, *prefix = "/tmp/foo.";
+
+ if (NILP (Fboundp (symbol)))
+ return NULL;
+
+ val = Fassq (format, Fsymbol_value (symbol));
+ if (! CONSP (val))
+ return NULL;
+
+ val = Fcdr (val);
+ if (! CONSP (val))
+ return NULL;
+
+ val = Fcar (val);
+ if (! STRINGP (val))
+ return NULL;
+
+ name = xmalloc (strlen (prefix) + SBYTES (val) + 1);
+ strcpy(name, prefix);
+ strcat(name, SDATA (val));
+ return name;
+}
+
/* 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
int desired_width, desired_height;
double rotation;
int pixelwidth;
+ char *filename_hint = NULL;
/* 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
ping_wand = NewMagickWand ();
/* MagickSetResolution (ping_wand, 2, 2); (Bug#10112) */
+ if (! filename)
+ filename_hint = imagemagick_filename_hint (img->spec);
+
+ if (filename_hint)
+ MagickSetFilename (ping_wand, filename_hint);
+
status = filename
? MagickPingImage (ping_wand, filename)
: MagickPingImageBlob (ping_wand, contents, size);
image_wand = NewMagickWand ();
+ if (filename_hint)
+ MagickSetFilename (image_wand, filename_hint);
+
if ((filename
? MagickReadImage (image_wand, filename)
: MagickReadImageBlob (image_wand, contents, size))
init_color_table ();
-#ifdef HAVE_MAGICKEXPORTIMAGEPIXELS
+#if defined (HAVE_MAGICKEXPORTIMAGEPIXELS) && ! defined (HAVE_NS)
if (imagemagick_render_type != 0)
{
/* Magicexportimage is normally faster than pixelpushing. This
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))
+ if (!image_create_x_image_and_pixmap (f, img, width, height, imagedepth,
+ &ximg, 0))
{
#ifdef COLOR_TABLE_SUPPORT
free_color_table ();
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))
+ if (!image_create_x_image_and_pixmap (f, img, width, height, 0,
+ &ximg, 0))
{
#ifdef COLOR_TABLE_SUPPORT
free_color_table ();
/* Copy pixels from the imagemagick image structure to the x image map. */
iterator = NewPixelIterator (image_wand);
- if (iterator == (PixelIterator *) NULL)
+ if (! iterator)
{
#ifdef COLOR_TABLE_SUPPORT
free_color_table ();
for (y = 0; y < image_height; y++)
{
pixels = PixelGetNextIteratorRow (iterator, &width);
- if (pixels == (PixelWand **) NULL)
+ if (! pixels)
break;
for (x = 0; x < (long) width; x++)
{
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);
+ /* Put ximg into the image. */
+ image_put_x_image (f, img, ximg, 0);
/* Final cleanup. image_wand should be the only resource left. */
DestroyMagickWand (image_wand);
/* `MagickWandTerminus' terminates the imagemagick environment. */
MagickWandTerminus ();
+ if (filename_hint)
+ free (filename_hint);
+
return 1;
imagemagick_error:
DestroyMagickWand (image_wand);
if (bg_wand) DestroyPixelWand (bg_wand);
+ if (filename_hint)
+ free (filename_hint);
MagickWandTerminus ();
/* TODO more cleanup. */
eassert (fn_gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);
/* Try to create a x pixmap to hold the svg pixmap. */
- if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
+ if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, 0))
{
fn_g_object_unref (pixbuf);
return 0;
Casting avoids a GCC warning. */
IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
- /* Put the image into the pixmap, then free the X image and its
- buffer. */
- x_put_x_image (f, ximg, img->pixmap, width, height);
- x_destroy_x_image (ximg);
+ /* Put ximg into the image. */
+ image_put_x_image (f, img, ximg, 0);
return 1;
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);
+ Vx_bitmap_file_path = decode_env_path (0, PATH_BITMAPS);
DEFVAR_LISP ("image-cache-eviction-delay", Vimage_cache_eviction_delay,
doc: /* Maximum time after which images are removed from the cache.