X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/6e6fc3fd4b8195264bb64a70834d354cbbed98a0..5c35ec32a51beaeae9e4233436816e1aeba053d0:/src/image.c diff --git a/src/image.c b/src/image.c index dfe592f3c1..f4616b626a 100644 --- a/src/image.c +++ b/src/image.c @@ -1,6 +1,6 @@ /* Functions for image support on window system. Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -39,6 +39,8 @@ Boston, MA 02110-1301, USA. */ #include "blockinput.h" #include "systime.h" #include +#include "charset.h" +#include "coding.h" #ifdef HAVE_X_WINDOWS @@ -54,8 +56,8 @@ typedef struct x_bitmap_record Bitmap_Record; #define RGB_PIXEL_COLOR unsigned long -#define PIX_MASK_RETAIN(f) 0 -#define PIX_MASK_DRAW(f) 1 +#define PIX_MASK_RETAIN 0 +#define PIX_MASK_DRAW 1 #endif /* HAVE_X_WINDOWS */ @@ -71,8 +73,8 @@ typedef struct w32_bitmap_record Bitmap_Record; #define RGB_PIXEL_COLOR COLORREF -#define PIX_MASK_RETAIN(f) 0 -#define PIX_MASK_DRAW(f) 1 +#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 @@ -112,6 +114,11 @@ typedef struct mac_bitmap_record Bitmap_Record; #define RGB_PIXEL_COLOR unsigned long +/* A black pixel in a mask bitmap/pixmap means ``draw a source + pixel''. A white pixel means ``retain the current pixel''. */ +#define PIX_MASK_DRAW RGB_TO_ULONG(0,0,0) +#define PIX_MASK_RETAIN RGB_TO_ULONG(255,255,255) + #define FRAME_X_VISUAL(f) FRAME_X_DISPLAY_INFO (f)->visual #define x_defined_color mac_defined_color #define DefaultDepthOfScreen(screen) (one_mac_display_info.n_planes) @@ -181,19 +188,46 @@ XPutPixel (ximage, x, y, pixel) int x, y; unsigned long pixel; { - CGrafPtr old_port; - GDHandle old_gdh; - RGBColor color; + PixMapHandle pixmap = GetGWorldPixMap (ximage); + short depth = GetPixDepth (pixmap); - GetGWorld (&old_port, &old_gdh); - SetGWorld (ximage, NULL); +#if defined (WORDS_BIG_ENDIAN) || !USE_CG_DRAWING + if (depth == 32) + { + char *base_addr = GetPixBaseAddr (pixmap); + short row_bytes = GetPixRowBytes (pixmap); - color.red = RED16_FROM_ULONG (pixel); - color.green = GREEN16_FROM_ULONG (pixel); - color.blue = BLUE16_FROM_ULONG (pixel); - SetCPixel (x, y, &color); + ((unsigned long *) (base_addr + y * row_bytes))[x] = 0xff000000 | pixel; + } + else +#endif + if (depth == 1) + { + char *base_addr = GetPixBaseAddr (pixmap); + short row_bytes = GetPixRowBytes (pixmap); - SetGWorld (old_port, old_gdh); + if (pixel == PIX_MASK_DRAW) + base_addr[y * row_bytes + x / 8] |= (1 << 7) >> (x & 7); + else + base_addr[y * row_bytes + x / 8] &= ~((1 << 7) >> (x & 7)); + } + else + { + CGrafPtr old_port; + GDHandle old_gdh; + RGBColor color; + + GetGWorld (&old_port, &old_gdh); + SetGWorld (ximage, NULL); + + color.red = RED16_FROM_ULONG (pixel); + color.green = GREEN16_FROM_ULONG (pixel); + color.blue = BLUE16_FROM_ULONG (pixel); + + SetCPixel (x, y, &color); + + SetGWorld (old_port, old_gdh); + } } static unsigned long @@ -201,17 +235,43 @@ XGetPixel (ximage, x, y) XImagePtr ximage; int x, y; { - CGrafPtr old_port; - GDHandle old_gdh; - RGBColor color; + PixMapHandle pixmap = GetGWorldPixMap (ximage); + short depth = GetPixDepth (pixmap); - GetGWorld (&old_port, &old_gdh); - SetGWorld (ximage, NULL); +#if defined (WORDS_BIG_ENDIAN) || !USE_CG_DRAWING + if (depth == 32) + { + char *base_addr = GetPixBaseAddr (pixmap); + short row_bytes = GetPixRowBytes (pixmap); - GetCPixel (x, y, &color); + return ((unsigned long *) (base_addr + y * row_bytes))[x] & 0x00ffffff; + } + else +#endif + if (depth == 1) + { + char *base_addr = GetPixBaseAddr (pixmap); + short row_bytes = GetPixRowBytes (pixmap); - SetGWorld (old_port, old_gdh); - return RGB_TO_ULONG (color.red >> 8, color.green >> 8, color.blue >> 8); + if (base_addr[y * row_bytes + x / 8] & (1 << (~x & 7))) + return PIX_MASK_DRAW; + else + return PIX_MASK_RETAIN; + } + else + { + CGrafPtr old_port; + GDHandle old_gdh; + RGBColor color; + + GetGWorld (&old_port, &old_gdh); + SetGWorld (ximage, NULL); + + GetCPixel (x, y, &color); + + SetGWorld (old_port, old_gdh); + return RGB_TO_ULONG (color.red >> 8, color.green >> 8, color.blue >> 8); + } } static void @@ -220,6 +280,49 @@ XDestroyImage (ximg) { UnlockPixels (GetGWorldPixMap (ximg)); } + +#if USE_CG_DRAWING +static CGImageRef +mac_create_cg_image_from_image (f, img) + struct frame *f; + struct image *img; +{ + Pixmap mask; + CGImageRef result = NULL; + + BLOCK_INPUT; + if (img->mask) + mask = img->mask; + else + { + mask = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + img->width, img->height, 1); + if (mask) + { + CGrafPtr old_port; + GDHandle old_gdh; + Rect r; + + GetGWorld (&old_port, &old_gdh); + SetGWorld (mask, NULL); + BackColor (blackColor); /* Don't mask. */ + SetRect (&r, 0, 0, img->width, img->height); + EraseRect (&r); + SetGWorld (old_port, old_gdh); + } + } + if (mask) + { + CreateCGImageFromPixMaps (GetGWorldPixMap (img->pixmap), + GetGWorldPixMap (mask), &result); + if (mask != img->mask) + XFreePixmap (FRAME_X_DISPLAY (f), mask); + } + UNBLOCK_INPUT; + + return result; +} +#endif /* USE_CG_DRAWING */ #endif /* MAC_OS */ @@ -341,8 +444,6 @@ x_create_bitmap_from_data (f, bits, width, height) id = x_allocate_bitmap_record (f); #ifdef MAC_OS dpyinfo->bitmaps[id - 1].bitmap_data = (char *) xmalloc (height * width); - if (! dpyinfo->bitmaps[id - 1].bitmap_data) - return -1; bcopy (bits, dpyinfo->bitmaps[id - 1].bitmap_data, height * width); #endif /* MAC_OS */ @@ -502,7 +603,9 @@ x_destroy_all_bitmaps (dpyinfo) /* Useful functions defined in the section `Image type independent image structures' below. */ -static unsigned long four_corners_best P_ ((XImagePtr ximg, unsigned long width, +static unsigned long four_corners_best P_ ((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, @@ -556,7 +659,7 @@ x_create_bitmap_mask (f, id) return -1; } - bg = four_corners_best (ximg, width, height); + bg = four_corners_best (ximg, NULL, width, height); for (y = 0; y < ximg->height; ++y) { @@ -631,7 +734,7 @@ Lisp_Object Qxbm; /* Keywords. */ extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile; -extern Lisp_Object QCdata, QCtype; +extern Lisp_Object QCdata, QCtype, Qcount; extern Lisp_Object Qcenter; Lisp_Object QCascent, QCmargin, QCrelief; Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask; @@ -1040,6 +1143,27 @@ or omitted means use the selected frame. */) return mask; } +DEFUN ("image-extension-data", Fimage_extension_data, Simage_extension_data, 1, 2, 0, + doc: /* Return extension data 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 ext; + + ext = Qnil; + if (valid_image_p (spec)) + { + struct frame *f = check_x_frame (frame); + int id = lookup_image (f, spec); + struct image *img = IMAGE_FROM_ID (f, id); + ext = img->data.lisp_val; + } + + return ext; +} + /*********************************************************************** Image type independent image structures @@ -1047,7 +1171,10 @@ or omitted means use the selected frame. */) 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; /* Allocate and return a new image structure for image specification SPEC. SPEC has a hash value of HASH. */ @@ -1067,6 +1194,7 @@ make_image (spec, hash) img->data.lisp_val = Qnil; img->ascent = DEFAULT_IMAGE_ASCENT; img->hash = hash; + img->corners[BOT_CORNER] = -1; /* Full image */ return img; } @@ -1099,6 +1227,39 @@ free_image (f, 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; +{ + int w, h; + + if (width <= 0 || height <= 0) + return 0; + + if (INTEGERP (Vmax_image_size)) + w = h = XINT (Vmax_image_size); + else if (FLOATP (Vmax_image_size)) + { + if (f != NULL) + { + w = FRAME_PIXEL_WIDTH (f); + h = FRAME_PIXEL_HEIGHT (f); + } + 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); + } + else + return 1; + + return (width <= w && height <= h); +} /* Prepare image IMG for display on frame F. Must be called before drawing an image. */ @@ -1118,6 +1279,18 @@ prepare_image_for_display (f, img) type dependent loader function. */ if (img->pixmap == NO_PIXMAP && !img->load_failed_p) img->load_failed_p = img->type->load (f, img) == 0; + +#if defined (MAC_OS) && USE_CG_DRAWING + if (!img->load_failed_p && img->data.ptr_val == NULL) + { + img->data.ptr_val = mac_create_cg_image_from_image (f, img); + if (img->data.ptr_val == NULL) + { + img->load_failed_p = 1; + img->type->free (f, img); + } + } +#endif } @@ -1173,30 +1346,41 @@ image_ascent (img, face, slice) On W32, XIMG is assumed to a device context with the bitmap selected. */ static RGB_PIXEL_COLOR -four_corners_best (ximg, width, height) +four_corners_best (ximg, corners, width, height) XImagePtr_or_DC ximg; + int *corners; unsigned long width, height; { - RGB_PIXEL_COLOR corners[4], best; + RGB_PIXEL_COLOR corner_pixels[4], best; int i, best_count; - /* Get the colors at the corners of ximg. */ - corners[0] = GET_PIXEL (ximg, 0, 0); - corners[1] = GET_PIXEL (ximg, width - 1, 0); - corners[2] = GET_PIXEL (ximg, width - 1, height - 1); - corners[3] = GET_PIXEL (ximg, 0, height - 1); - + if (corners && corners[BOT_CORNER] >= 0) + { + /* Get the colors at the corner_pixels of ximg. */ + corner_pixels[0] = GET_PIXEL (ximg, corners[LEFT_CORNER], corners[TOP_CORNER]); + corner_pixels[1] = GET_PIXEL (ximg, corners[RIGHT_CORNER] - 1, corners[TOP_CORNER]); + corner_pixels[2] = GET_PIXEL (ximg, corners[RIGHT_CORNER] - 1, corners[BOT_CORNER] - 1); + corner_pixels[3] = GET_PIXEL (ximg, corners[LEFT_CORNER], corners[BOT_CORNER] - 1); + } + else + { + /* Get the colors at the corner_pixels of ximg. */ + corner_pixels[0] = GET_PIXEL (ximg, 0, 0); + corner_pixels[1] = GET_PIXEL (ximg, width - 1, 0); + corner_pixels[2] = GET_PIXEL (ximg, width - 1, height - 1); + corner_pixels[3] = GET_PIXEL (ximg, 0, height - 1); + } /* Choose the most frequently found color as background. */ for (i = best_count = 0; i < 4; ++i) { int j, n; for (j = n = 0; j < 4; ++j) - if (corners[i] == corners[j]) + if (corner_pixels[i] == corner_pixels[j]) ++n; if (n > best_count) - best = corners[i], best_count = n; + best = corner_pixels[i], best_count = n; } return best; @@ -1255,7 +1439,7 @@ image_background (img, f, ximg) #endif /* !HAVE_NTGUI */ } - img->background = four_corners_best (ximg, img->width, img->height); + img->background = four_corners_best (ximg, img->corners, img->width, img->height); if (free_ximg) Destroy_Image (ximg, prev); @@ -1300,7 +1484,7 @@ image_background_transparent (img, f, mask) } img->background_transparent - = (four_corners_best (mask, img->width, img->height) == PIX_MASK_RETAIN (f)); + = (four_corners_best (mask, img->corners, img->width, img->height) == PIX_MASK_RETAIN); if (free_mask) Destroy_Image (mask, prev); @@ -1364,6 +1548,14 @@ x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p) img->colors = NULL; img->ncolors = 0; } + +#if defined (MAC_OS) && USE_CG_DRAWING + if (img->data.ptr_val) + { + CGImageRelease (img->data.ptr_val); + img->data.ptr_val = NULL; + } +#endif } /* Free X resources of image IMG which is used on frame F. */ @@ -1656,6 +1848,12 @@ lookup_image (f, spec) if (img->hash == hash && !NILP (Fequal (img->spec, spec))) break; + if (img && img->load_failed_p) + { + free_image (f, img); + img = NULL; + } + /* If not found, create a new image and cache it. */ if (img == NULL) { @@ -2003,7 +2201,6 @@ x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap) *pixmap = XCreatePixmap (display, window, width, height, depth); if (*pixmap == NO_PIXMAP) { - x_destroy_x_image (*ximg); *ximg = NULL; image_error ("Unable to create X pixmap", Qnil, Qnil); return 0; @@ -2084,8 +2281,8 @@ static unsigned char *slurp_file P_ ((char *, int *)); /* Find image file FILE. Look in data-directory, then - x-bitmap-file-path. Value is the full name of the file found, or - nil if not found. */ + x-bitmap-file-path. Value is the encoded full name of the file + found, or nil if not found. */ Lisp_Object x_find_image_file (file) @@ -2105,7 +2302,10 @@ x_find_image_file (file) if (fd == -1) file_found = Qnil; else - close (fd); + { + file_found = ENCODE_FILE (file_found); + close (fd); + } UNGCPRO; return file_found; @@ -2127,7 +2327,7 @@ slurp_file (file, size) if (stat (file, &st) == 0 && (fp = fopen (file, "rb")) != NULL - && (buf = (char *) xmalloc (st.st_size), + && (buf = (unsigned char *) xmalloc (st.st_size), fread (buf, 1, st.st_size, fp) == st.st_size)) { *size = st.st_size; @@ -2166,28 +2366,25 @@ find_image_fsspec (specified_file, file, fss) Lisp_Object specified_file, *file; FSSpec *fss; { -#if TARGET_API_MAC_CARBON - FSRef fsr; -#else - Str255 mac_pathname; -#endif OSErr err; + AEDesc desc; *file = x_find_image_file (specified_file); if (!STRINGP (*file)) return fnfErr; /* file or directory not found; incomplete pathname */ /* Try to open the image file. */ -#if TARGET_API_MAC_CARBON - err = FSPathMakeRef (SDATA (*file), &fsr, NULL); + err = AECoercePtr (TYPE_FILE_NAME, SDATA (*file), + SBYTES (*file), typeFSS, &desc); if (err == noErr) - err = FSGetCatalogInfo (&fsr, kFSCatInfoNone, NULL, NULL, fss, NULL); + { +#if TARGET_API_MAC_CARBON + err = AEGetDescData (&desc, fss, sizeof (FSSpec)); #else - if (posix_to_mac_pathname (SDATA (*file), mac_pathname, MAXPATHLEN+1) == 0) - return fnfErr; - c2pstr (mac_pathname); - err = FSMakeFSSpec (0, 0, mac_pathname, fss); + *fss = *(FSSpec *)(*(desc.dataHandle)); #endif + AEDisposeDesc (&desc); + } return err; } @@ -2196,21 +2393,21 @@ image_load_qt_1 (f, img, type, fss, dh) struct frame *f; struct image *img; OSType type; - FSSpec *fss; + const FSSpec *fss; Handle dh; { - OSErr err; + ComponentResult err; GraphicsImportComponent gi; Rect rect; int width, height; + ImageDescriptionHandle desc_handle; short draw_all_pixels; Lisp_Object specified_bg; XColor color; XImagePtr ximg; RGBColor bg_color; - err = OpenADefaultComponent (GraphicsImporterComponentType, - type, &gi); + err = OpenADefaultComponent (GraphicsImporterComponentType, type, &gi); if (err != noErr) { image_error ("Cannot get importer component for `%s'", img->spec, Qnil); @@ -2238,14 +2435,22 @@ image_load_qt_1 (f, img, type, fss, dh) goto error; } } - err = GraphicsImportGetNaturalBounds (gi, &rect); - if (err != noErr) + err = GraphicsImportGetImageDescription (gi, &desc_handle); + if (err != noErr || desc_handle == NULL) { image_error ("Error reading `%s'", img->spec, Qnil); goto error; } - width = img->width = rect.right - rect.left; - height = img->height = rect.bottom - rect.top; + width = img->width = (*desc_handle)->width; + height = img->height = (*desc_handle)->height; + DisposeHandle ((Handle)desc_handle); + + if (!check_image_size (f, width, height)) + { + image_error ("Invalid image size", Qnil, Qnil); + goto error; + } + err = GraphicsImportDoesDrawAllPixels (gi, &draw_all_pixels); #if 0 /* Don't check the error code here. It may have an undocumented @@ -2422,7 +2627,7 @@ image_load_quartz2d (f, img, png_p) UNGCPRO; return 0; } - path = cfstring_create_with_string (file); + path = cfstring_create_with_utf8_cstring (SDATA (file)); url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, 0); CFRelease (path); @@ -2447,6 +2652,16 @@ image_load_quartz2d (f, img, png_p) image_error ("Error reading image `%s'", img->spec, Qnil); return 0; } + width = img->width = CGImageGetWidth (image); + height = img->height = CGImageGetHeight (image); + + if (!check_image_size (f, width, height)) + { + CGImageRelease (image); + UNGCPRO; + image_error ("Invalid image size", Qnil, Qnil); + return 0; + } if (png_p) { @@ -2460,8 +2675,7 @@ image_load_quartz2d (f, img, png_p) color.blue = BLUE16_FROM_ULONG (color.pixel); } } - width = img->width = CGImageGetWidth (image); - height = img->height = CGImageGetHeight (image); + if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) { CGImageRelease (image); @@ -2505,7 +2719,8 @@ 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_ ((unsigned char *, unsigned char *, +static int xbm_read_bitmap_data P_ ((struct frame *f, + unsigned char *, unsigned char *, int *, int *, unsigned char **)); static int xbm_file_p P_ ((Lisp_Object)); @@ -2893,7 +3108,8 @@ Create_Pixmap_From_Bitmap_Data(f, img, data, fg, bg, non_default_colors) CONTENTS looks like an in-memory XBM file. */ static int -xbm_read_bitmap_data (contents, end, width, height, data) +xbm_read_bitmap_data (f, contents, end, width, height, data) + struct frame *f; unsigned char *contents, *end; int *width, *height; unsigned char **data; @@ -2934,7 +3150,7 @@ xbm_read_bitmap_data (contents, end, width, height, data) expect_ident ("define"); expect (XBM_TK_IDENT); - if (LA1 == XBM_TK_NUMBER); + if (LA1 == XBM_TK_NUMBER) { char *p = strrchr (buffer, '_'); p = p ? p + 1 : buffer; @@ -2946,7 +3162,7 @@ xbm_read_bitmap_data (contents, end, width, height, data) expect (XBM_TK_NUMBER); } - if (*width < 0 || *height < 0) + if (!check_image_size (f, *width, *height)) goto failure; else if (data == NULL) goto success; @@ -2983,7 +3199,7 @@ xbm_read_bitmap_data (contents, end, width, height, data) bytes_per_line = (*width + 7) / 8 + padding_p; nbytes = bytes_per_line * *height; - p = *data = (char *) xmalloc (nbytes); + p = *data = (unsigned char *) xmalloc (nbytes); if (v10) { @@ -3050,7 +3266,7 @@ xbm_load_image (f, img, contents, end) unsigned char *data; int success_p = 0; - rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data); + rc = xbm_read_bitmap_data (f, contents, end, &img->width, &img->height, &data); if (rc) { unsigned long foreground = FRAME_FOREGROUND_PIXEL (f); @@ -3104,7 +3320,7 @@ xbm_file_p (data) { int w, h; return (STRINGP (data) - && xbm_read_bitmap_data (SDATA (data), + && xbm_read_bitmap_data (NULL, SDATA (data), (SDATA (data) + SBYTES (data)), &w, &h, NULL)); @@ -3608,6 +3824,47 @@ xpm_image_p (object) #endif /* HAVE_XPM || MAC_OS */ +#if defined (HAVE_XPM) && defined (HAVE_X_WINDOWS) +int +x_create_bitmap_from_xpm_data (f, bits) + struct frame *f; + char **bits; +{ + Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); + int id, rc; + XpmAttributes attrs; + Pixmap bitmap, mask; + + bzero (&attrs, sizeof attrs); + + attrs.visual = FRAME_X_VISUAL (f); + attrs.colormap = FRAME_X_COLORMAP (f); + attrs.valuemask |= XpmVisual; + attrs.valuemask |= XpmColormap; + + rc = XpmCreatePixmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + bits, &bitmap, &mask, &attrs); + if (rc != XpmSuccess) + { + XpmFreeAttributes (&attrs); + return -1; + } + + id = x_allocate_bitmap_record (f); + dpyinfo->bitmaps[id - 1].pixmap = bitmap; + dpyinfo->bitmaps[id - 1].have_mask = 1; + dpyinfo->bitmaps[id - 1].mask = mask; + dpyinfo->bitmaps[id - 1].file = NULL; + dpyinfo->bitmaps[id - 1].height = attrs.height; + dpyinfo->bitmaps[id - 1].width = attrs.width; + dpyinfo->bitmaps[id - 1].depth = attrs.depth; + dpyinfo->bitmaps[id - 1].refcount = 1; + + XpmFreeAttributes (&attrs); + return id; +} +#endif /* defined (HAVE_XPM) && defined (HAVE_X_WINDOWS) */ + /* Load image IMG which will be displayed on frame F. Value is non-zero if successful. */ @@ -3655,6 +3912,9 @@ xpm_load (f, img) attrs.valuemask |= XpmCloseness; #endif /* not XpmAllocCloseColors */ #endif /* ALLOC_XPM_COLORS */ +#ifdef ALLOC_XPM_COLORS + xpm_init_color_cache (f, &attrs); +#endif /* If image specification contains symbolic color definitions, add these to `attrs'. */ @@ -3849,25 +4109,25 @@ xpm_load (f, img) /* XPM support functions for Mac OS where libxpm is not available. Only XPM version 3 (without any extensions) is supported. */ -static int xpm_scan P_ ((unsigned char **, unsigned char *, - unsigned char **, int *)); +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, unsigned char *, int, Lisp_Object), - Lisp_Object (**) (Lisp_Object, unsigned char *, int))); -static void xpm_put_color_table_v P_ ((Lisp_Object, unsigned char *, - int, Lisp_Object)); + 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, - unsigned char *, int)); + const unsigned char *, int)); static Lisp_Object xpm_make_color_table_h - P_ ((void (**) (Lisp_Object, unsigned char *, int, Lisp_Object), - Lisp_Object (**) (Lisp_Object, unsigned char *, int))); -static void xpm_put_color_table_h P_ ((Lisp_Object, unsigned char *, - int, Lisp_Object)); + 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, - unsigned char *, int)); -static int xpm_str_to_color_key P_ ((char *)); + const unsigned char *, int)); +static int xpm_str_to_color_key P_ ((const char *)); static int xpm_load_image P_ ((struct frame *, struct image *, - unsigned char *, unsigned char *)); + const unsigned char *, const unsigned char *)); /* Tokens returned from xpm_scan. */ @@ -3887,7 +4147,7 @@ enum xpm_token static int xpm_scan (s, end, beg, len) - unsigned char **s, *end, **beg; + const unsigned char **s, *end, **beg; int *len; { int c; @@ -3896,49 +4156,49 @@ xpm_scan (s, end, beg, len) { /* Skip white-space. */ while (*s < end && (c = *(*s)++, isspace (c))) - ; + ; /* gnus-pointer.xpm uses '-' in its identifier. - sb-dir-plus.xpm uses '+' in its identifier. */ + sb-dir-plus.xpm uses '+' in its identifier. */ if (isalpha (c) || c == '_' || c == '-' || c == '+') - { - *beg = *s - 1; - while (*s < end && - (c = **s, isalnum (c) || c == '_' || c == '-' || c == '+')) - ++*s; - *len = *s - *beg; - return XPM_TK_IDENT; - } + { + *beg = *s - 1; + while (*s < end && + (c = **s, isalnum (c) || c == '_' || c == '-' || c == '+')) + ++*s; + *len = *s - *beg; + return XPM_TK_IDENT; + } else if (c == '"') - { - *beg = *s; - while (*s < end && **s != '"') - ++*s; - *len = *s - *beg; - if (*s < end) - ++*s; - return XPM_TK_STRING; - } + { + *beg = *s; + while (*s < end && **s != '"') + ++*s; + *len = *s - *beg; + if (*s < end) + ++*s; + return XPM_TK_STRING; + } else if (c == '/') - { - if (*s < end && **s == '*') - { - /* C-style comment. */ - ++*s; - do - { - while (*s < end && *(*s)++ != '*') - ; - } - while (*s < end && **s != '/'); - if (*s < end) - ++*s; - } - else - return c; - } + { + if (*s < end && **s == '*') + { + /* C-style comment. */ + ++*s; + do + { + while (*s < end && *(*s)++ != '*') + ; + } + while (*s < end && **s != '/'); + if (*s < end) + ++*s; + } + else + return c; + } else - return c; + return c; } return XPM_TK_EOF; @@ -3953,8 +4213,8 @@ xpm_scan (s, end, beg, len) static Lisp_Object xpm_make_color_table_v (put_func, get_func) - void (**put_func) (Lisp_Object, unsigned char *, int, Lisp_Object); - Lisp_Object (**get_func) (Lisp_Object, unsigned char *, int); + 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; @@ -3964,7 +4224,7 @@ xpm_make_color_table_v (put_func, get_func) static void xpm_put_color_table_v (color_table, chars_start, chars_len, color) Lisp_Object color_table; - unsigned char *chars_start; + const unsigned char *chars_start; int chars_len; Lisp_Object color; { @@ -3974,7 +4234,7 @@ xpm_put_color_table_v (color_table, chars_start, chars_len, color) static Lisp_Object xpm_get_color_table_v (color_table, chars_start, chars_len) Lisp_Object color_table; - unsigned char *chars_start; + const unsigned char *chars_start; int chars_len; { return XVECTOR (color_table)->contents[*chars_start]; @@ -3982,21 +4242,21 @@ xpm_get_color_table_v (color_table, chars_start, chars_len) static Lisp_Object xpm_make_color_table_h (put_func, get_func) - void (**put_func) (Lisp_Object, unsigned char *, int, Lisp_Object); - Lisp_Object (**get_func) (Lisp_Object, unsigned char *, int); + 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; return make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE), - make_float (DEFAULT_REHASH_SIZE), - make_float (DEFAULT_REHASH_THRESHOLD), - Qnil, Qnil, Qnil); + make_float (DEFAULT_REHASH_SIZE), + make_float (DEFAULT_REHASH_THRESHOLD), + Qnil, Qnil, Qnil); } static void xpm_put_color_table_h (color_table, chars_start, chars_len, color) Lisp_Object color_table; - unsigned char *chars_start; + const unsigned char *chars_start; int chars_len; Lisp_Object color; { @@ -4011,12 +4271,12 @@ xpm_put_color_table_h (color_table, chars_start, chars_len, color) static Lisp_Object xpm_get_color_table_h (color_table, chars_start, chars_len) Lisp_Object color_table; - unsigned char *chars_start; + 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); + NULL); return i >= 0 ? HASH_VALUE (table, i) : Qnil; } @@ -4029,11 +4289,11 @@ enum xpm_color_key { XPM_COLOR_KEY_C }; -static char xpm_color_key_strings[][4] = {"s", "m", "g4", "g", "c"}; +static const char xpm_color_key_strings[][4] = {"s", "m", "g4", "g", "c"}; static int xpm_str_to_color_key (s) - char *s; + const char *s; { int i; @@ -4049,15 +4309,15 @@ static int xpm_load_image (f, img, contents, end) struct frame *f; struct image *img; - unsigned char *contents, *end; + const unsigned char *contents, *end; { - unsigned char *s = contents, *beg, *str; + 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; - void (*put_color_table) (Lisp_Object, unsigned char *, int, Lisp_Object); - Lisp_Object (*get_color_table) (Lisp_Object, unsigned char *, int); + 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; int best_key, have_mask = 0; XImagePtr ximg = NULL, mask_img = NULL; @@ -4065,17 +4325,17 @@ xpm_load_image (f, img, contents, end) #define match() \ LA1 = xpm_scan (&s, end, &beg, &len) -#define expect(TOKEN) \ - if (LA1 != (TOKEN)) \ - goto failure; \ - else \ +#define expect(TOKEN) \ + if (LA1 != (TOKEN)) \ + goto failure; \ + else \ match () -#define expect_ident(IDENT) \ +#define expect_ident(IDENT) \ if (LA1 == XPM_TK_IDENT \ - && strlen ((IDENT)) == len && memcmp ((IDENT), beg, len) == 0) \ - match (); \ - else \ + && strlen ((IDENT)) == len && memcmp ((IDENT), beg, len) == 0) \ + match (); \ + else \ goto failure if (!(end - s >= 9 && memcmp (s, "/* XPM */", 9) == 0)) @@ -4096,10 +4356,17 @@ xpm_load_image (f, img, contents, end) memcpy (buffer, beg, len); buffer[len] = '\0'; if (sscanf (buffer, "%d %d %d %d", &width, &height, - &num_colors, &chars_per_pixel) != 4 + &num_colors, &chars_per_pixel) != 4 || width <= 0 || height <= 0 || num_colors <= 0 || chars_per_pixel <= 0) goto failure; + + if (!check_image_size (f, width, height)) + { + image_error ("Invalid image size", Qnil, Qnil); + goto failure; + } + expect (','); XSETFRAME (frame, f); @@ -4107,17 +4374,17 @@ xpm_load_image (f, img, contents, end) best_key = XPM_COLOR_KEY_C; else if (!NILP (Fx_display_grayscale_p (frame))) best_key = (XFASTINT (Fx_display_planes (frame)) > 2 - ? XPM_COLOR_KEY_G : XPM_COLOR_KEY_G4); + ? XPM_COLOR_KEY_G : XPM_COLOR_KEY_G4); else best_key = XPM_COLOR_KEY_M; color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL); if (chars_per_pixel == 1) color_table = xpm_make_color_table_v (&put_color_table, - &get_color_table); + &get_color_table); else color_table = xpm_make_color_table_h (&put_color_table, - &get_color_table); + &get_color_table); while (num_colors-- > 0) { @@ -4128,71 +4395,75 @@ xpm_load_image (f, img, contents, end) expect (XPM_TK_STRING); if (len <= chars_per_pixel || len >= BUFSIZ + chars_per_pixel) - goto failure; + goto failure; memcpy (buffer, beg + chars_per_pixel, len - chars_per_pixel); buffer[len - chars_per_pixel] = '\0'; str = strtok (buffer, " \t"); if (str == NULL) - goto failure; + goto failure; key = xpm_str_to_color_key (str); if (key < 0) - goto failure; + goto failure; do - { - color = strtok (NULL, " \t"); - if (color == NULL) - goto failure; + { + color = strtok (NULL, " \t"); + if (color == NULL) + goto failure; - while (str = strtok (NULL, " \t")) - { - next_key = xpm_str_to_color_key (str); - if (next_key >= 0) - break; - color[strlen (color)] = ' '; - } + while ((str = strtok (NULL, " \t")) != NULL) + { + next_key = xpm_str_to_color_key (str); + if (next_key >= 0) + break; + color[strlen (color)] = ' '; + } - if (key == XPM_COLOR_KEY_S) - { - if (NILP (symbol_color)) - symbol_color = build_string (color); - } - else if (max_key < key && key <= best_key) - { - max_key = key; - max_color = color; - } - key = next_key; - } + if (key == XPM_COLOR_KEY_S) + { + if (NILP (symbol_color)) + symbol_color = build_string (color); + } + else if (max_key < key && key <= best_key) + { + max_key = key; + max_color = color; + } + key = next_key; + } while (str); color_val = Qnil; if (!NILP (color_symbols) && !NILP (symbol_color)) - { - Lisp_Object specified_color = Fassoc (symbol_color, color_symbols); - - if (CONSP (specified_color) && STRINGP (XCDR (specified_color))) - if (xstricmp (SDATA (XCDR (specified_color)), "None") == 0) - color_val = Qt; - else if (x_defined_color (f, SDATA (XCDR (specified_color)), - &cdef, 0)) - color_val = make_number (cdef.pixel); - } + { + Lisp_Object specified_color = Fassoc (symbol_color, color_symbols); + + if (CONSP (specified_color) && STRINGP (XCDR (specified_color))) + { + if (xstricmp (SDATA (XCDR (specified_color)), "None") == 0) + color_val = Qt; + else if (x_defined_color (f, SDATA (XCDR (specified_color)), + &cdef, 0)) + color_val = make_number (cdef.pixel); + } + } if (NILP (color_val) && max_key > 0) - if (xstricmp (max_color, "None") == 0) - color_val = Qt; - else if (x_defined_color (f, max_color, &cdef, 0)) - color_val = make_number (cdef.pixel); + { + if (xstricmp (max_color, "None") == 0) + color_val = Qt; + else if (x_defined_color (f, max_color, &cdef, 0)) + color_val = make_number (cdef.pixel); + } if (!NILP (color_val)) - (*put_color_table) (color_table, beg, chars_per_pixel, color_val); + (*put_color_table) (color_table, beg, chars_per_pixel, color_val); expect (','); } if (!x_create_x_image_and_pixmap (f, width, height, 0, - &ximg, &img->pixmap) + &ximg, &img->pixmap) || !x_create_x_image_and_pixmap (f, width, height, 1, - &mask_img, &img->mask)) + &mask_img, &img->mask)) { image_error ("Out of memory (%s)", img->spec, Qnil); goto error; @@ -4203,30 +4474,38 @@ xpm_load_image (f, img, contents, end) expect (XPM_TK_STRING); str = beg; if (len < width * chars_per_pixel) - goto failure; + goto failure; for (x = 0; x < width; x++, str += chars_per_pixel) - { - Lisp_Object color_val = - (*get_color_table) (color_table, str, chars_per_pixel); - - XPutPixel (ximg, x, y, - (INTEGERP (color_val) ? XINT (color_val) - : FRAME_FOREGROUND_PIXEL (f))); - XPutPixel (mask_img, x, y, - (!EQ (color_val, Qt) ? PIX_MASK_DRAW (f) - : (have_mask = 1, PIX_MASK_RETAIN (f)))); - } + { + Lisp_Object color_val = + (*get_color_table) (color_table, str, chars_per_pixel); + + XPutPixel (ximg, x, y, + (INTEGERP (color_val) ? XINT (color_val) + : FRAME_FOREGROUND_PIXEL (f))); + XPutPixel (mask_img, x, y, + (!EQ (color_val, Qt) ? PIX_MASK_DRAW + : (have_mask = 1, PIX_MASK_RETAIN))); + } if (y + 1 < height) - expect (','); + expect (','); } img->width = width; img->height = height; + /* Maybe fill in the background field while we have ximg handy. */ + 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); if (have_mask) { + /* Fill in the background_transparent field while we have the + 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); } @@ -4272,19 +4551,19 @@ xpm_load (f, img) 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; - } + { + image_error ("Cannot find image file `%s'", file_name, Qnil); + UNGCPRO; + return 0; + } contents = slurp_file (SDATA (file), &size); if (contents == NULL) - { - image_error ("Error loading XPM image `%s'", img->spec, Qnil); - UNGCPRO; - return 0; - } + { + 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); @@ -4296,7 +4575,7 @@ xpm_load (f, img) data = image_spec_value (img->spec, QCdata, NULL); success_p = xpm_load_image (f, img, SDATA (data), - SDATA (data) + SBYTES (data)); + SDATA (data) + SBYTES (data)); } return success_p; @@ -4973,7 +5252,7 @@ x_disable_image (f, img) #ifdef MAC_OS #define XCreateGC_pixmap(dpy, pixmap) XCreateGC (dpy, NULL, 0, NULL) -#define MaskForeground(f) PIX_MASK_DRAW (f) +#define MaskForeground(f) PIX_MASK_DRAW #else #define XCreateGC_pixmap(dpy, pixmap) XCreateGC (dpy, pixmap, 0, NULL) #define MaskForeground(f) WHITE_PIX_DEFAULT (f) @@ -5113,7 +5392,7 @@ x_build_heuristic_mask (f, img, how) } if (use_img_background) - bg = four_corners_best (ximg, img->width, img->height); + bg = four_corners_best (ximg, img->corners, img->width, img->height); /* Set all bits in mask_img to 1 whose color in ximg is different from the background color bg. */ @@ -5121,7 +5400,7 @@ x_build_heuristic_mask (f, img, how) for (y = 0; y < img->height; ++y) for (x = 0; x < img->width; ++x) XPutPixel (mask_img, x, y, (XGetPixel (ximg, x, y) != bg - ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f))); + ? PIX_MASK_DRAW : PIX_MASK_RETAIN)); /* Fill in the background_transparent field while we have the mask handy. */ image_background_transparent (img, f, mask_img); @@ -5415,8 +5694,7 @@ pbm_load (f, img) max_color_idx = 255; } - if (width < 0 - || height < 0 + if (!check_image_size (f, width, height) || (type != PBM_MONO && max_color_idx < 0)) goto error; @@ -5825,7 +6103,6 @@ png_load (f, img) { image_error ("Cannot open image file `%s'", file, Qnil); UNGCPRO; - fclose (fp); return 0; } @@ -5916,6 +6193,9 @@ png_load (f, img) 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)) + 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)) @@ -6123,7 +6403,7 @@ png_load (f, img) if (channels == 4) { if (mask_img) - XPutPixel (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f)); + XPutPixel (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : PIX_MASK_RETAIN); ++p; } } @@ -6308,7 +6588,6 @@ DEF_IMGLIB_FN (jpeg_finish_decompress); DEF_IMGLIB_FN (jpeg_destroy_decompress); DEF_IMGLIB_FN (jpeg_read_header); DEF_IMGLIB_FN (jpeg_read_scanlines); -DEF_IMGLIB_FN (jpeg_stdio_src); DEF_IMGLIB_FN (jpeg_std_error); DEF_IMGLIB_FN (jpeg_resync_to_restart); @@ -6324,7 +6603,6 @@ init_jpeg_functions (Lisp_Object libraries) LOAD_IMGLIB_FN (library, jpeg_read_scanlines); LOAD_IMGLIB_FN (library, jpeg_start_decompress); LOAD_IMGLIB_FN (library, jpeg_read_header); - LOAD_IMGLIB_FN (library, jpeg_stdio_src); LOAD_IMGLIB_FN (library, jpeg_CreateDecompress); LOAD_IMGLIB_FN (library, jpeg_destroy_decompress); LOAD_IMGLIB_FN (library, jpeg_std_error); @@ -6350,7 +6628,6 @@ jpeg_resync_to_restart_wrapper(cinfo, desired) #define fn_jpeg_destroy_decompress jpeg_destroy_decompress #define fn_jpeg_read_header jpeg_read_header #define fn_jpeg_read_scanlines jpeg_read_scanlines -#define fn_jpeg_stdio_src jpeg_stdio_src #define fn_jpeg_std_error jpeg_std_error #define jpeg_resync_to_restart_wrapper jpeg_resync_to_restart @@ -6377,7 +6654,17 @@ my_error_exit (cinfo) libjpeg.doc from the JPEG lib distribution. */ static void -our_init_source (cinfo) +our_common_init_source (cinfo) + j_decompress_ptr cinfo; +{ +} + + +/* Method to terminate data source. Called by + jpeg_finish_decompress() after all data has been processed. */ + +static void +our_common_term_source (cinfo) j_decompress_ptr cinfo; { } @@ -6388,7 +6675,7 @@ our_init_source (cinfo) so this only adds a fake end of input marker at the end. */ static boolean -our_fill_input_buffer (cinfo) +our_memory_fill_input_buffer (cinfo) j_decompress_ptr cinfo; { /* Insert a fake EOI marker. */ @@ -6408,7 +6695,7 @@ our_fill_input_buffer (cinfo) is the JPEG data source manager. */ static void -our_skip_input_data (cinfo, num_bytes) +our_memory_skip_input_data (cinfo, num_bytes) j_decompress_ptr cinfo; long num_bytes; { @@ -6425,16 +6712,6 @@ our_skip_input_data (cinfo, num_bytes) } -/* Method to terminate data source. Called by - jpeg_finish_decompress() after all data has been processed. */ - -static void -our_term_source (cinfo) - j_decompress_ptr cinfo; -{ -} - - /* Set up the JPEG lib for reading an image from DATA which contains LEN bytes. CINFO is the decompression info structure created for reading the image. */ @@ -6458,16 +6735,130 @@ jpeg_memory_src (cinfo, data, len) } src = (struct jpeg_source_mgr *) cinfo->src; - src->init_source = our_init_source; - src->fill_input_buffer = our_fill_input_buffer; - src->skip_input_data = our_skip_input_data; + 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; src->resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use default method. */ - src->term_source = our_term_source; + src->term_source = our_common_term_source; src->bytes_in_buffer = len; src->next_input_byte = data; } +struct jpeg_stdio_mgr +{ + struct jpeg_source_mgr mgr; + boolean finished; + FILE *file; + JOCTET *buffer; +}; + + +/* Size of buffer to read JPEG from file. + Not too big, as we want to use alloc_small. */ +#define JPEG_STDIO_BUFFER_SIZE 8192 + + +/* Fill input buffer method for JPEG data source manager. Called + whenever more data is needed. The data is read from a FILE *. */ + +static boolean +our_stdio_fill_input_buffer (cinfo) + j_decompress_ptr cinfo; +{ + struct jpeg_stdio_mgr *src; + + src = (struct jpeg_stdio_mgr *) cinfo->src; + if (!src->finished) + { + size_t bytes; + + bytes = fread (src->buffer, 1, JPEG_STDIO_BUFFER_SIZE, src->file); + if (bytes > 0) + src->mgr.bytes_in_buffer = bytes; + else + { + WARNMS (cinfo, JWRN_JPEG_EOF); + src->finished = 1; + src->buffer[0] = (JOCTET) 0xFF; + src->buffer[1] = (JOCTET) JPEG_EOI; + src->mgr.bytes_in_buffer = 2; + } + src->mgr.next_input_byte = src->buffer; + } + + return 1; +} + + +/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src + is the JPEG data source manager. */ + +static void +our_stdio_skip_input_data (cinfo, num_bytes) + j_decompress_ptr cinfo; + long num_bytes; +{ + struct jpeg_stdio_mgr *src; + src = (struct jpeg_stdio_mgr *) cinfo->src; + + while (num_bytes > 0 && !src->finished) + { + if (num_bytes <= src->mgr.bytes_in_buffer) + { + src->mgr.bytes_in_buffer -= num_bytes; + src->mgr.next_input_byte += num_bytes; + break; + } + else + { + num_bytes -= src->mgr.bytes_in_buffer; + src->mgr.bytes_in_buffer = 0; + src->mgr.next_input_byte = NULL; + + our_stdio_fill_input_buffer (cinfo); + } + } +} + + +/* Set up the JPEG lib for reading an image from a FILE *. + CINFO is the decompression info structure created for + reading the image. */ + +static void +jpeg_file_src (cinfo, fp) + j_decompress_ptr cinfo; + FILE *fp; +{ + struct jpeg_stdio_mgr *src; + + if (cinfo->src != NULL) + src = (struct jpeg_stdio_mgr *) cinfo->src; + else + { + /* 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->file = fp; + src->finished = 0; + src->mgr.init_source = our_common_init_source; + src->mgr.fill_input_buffer = our_stdio_fill_input_buffer; + src->mgr.skip_input_data = our_stdio_skip_input_data; + src->mgr.resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use default method. */ + src->mgr.term_source = our_common_term_source; + src->mgr.bytes_in_buffer = 0; + src->mgr.next_input_byte = NULL; +} + + /* Load image IMG for use on frame F. Patterned after example.c from the JPEG lib. */ @@ -6551,7 +6942,7 @@ jpeg_load (f, img) fn_jpeg_CreateDecompress (&cinfo, JPEG_LIB_VERSION, sizeof (cinfo)); if (NILP (specified_data)) - fn_jpeg_stdio_src (&cinfo, (FILE *) fp); + jpeg_file_src (&cinfo, (FILE *) fp); else jpeg_memory_src (&cinfo, SDATA (specified_data), SBYTES (specified_data)); @@ -6565,6 +6956,12 @@ jpeg_load (f, img) width = img->width = cinfo.output_width; height = img->height = cinfo.output_height; + if (!check_image_size (f, width, height)) + { + image_error ("Invalid image size", Qnil, Qnil); + longjmp (mgr.setjmp_buffer, 2); + } + /* Create X image and pixmap. */ if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) longjmp (mgr.setjmp_buffer, 2); @@ -6994,6 +7391,14 @@ tiff_load (f, img) of width x height 32-bit values. */ fn_TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width); fn_TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height); + + if (!check_image_size (f, width, height)) + { + image_error ("Invalid image size", Qnil, Qnil); + UNGCPRO; + return 0; + } + buf = (uint32 *) xmalloc (width * height * sizeof *buf); rc = fn_TIFFReadRGBAImage (tiff, width, height, buf, 0); @@ -7079,6 +7484,7 @@ tiff_load (f, img) 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)); /* The symbol `gif' identifying images of this type. */ @@ -7127,10 +7533,22 @@ static struct image_type gif_type = &Qgif, gif_image_p, gif_load, - x_clear_image, + gif_clear_image, 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; +{ + /* IMG->data.ptr_val may contain extension data. */ + img->data.lisp_val = Qnil; + x_clear_image (f, img); +} + /* Return non-zero if OBJECT is a valid GIF image specification. */ static int @@ -7251,7 +7669,7 @@ gif_load (f, img) GifFileType *gif; struct gcpro gcpro1; Lisp_Object image; - int ino, image_left, image_top, image_width, image_height; + int ino, image_height, image_width; gif_memory_source memsrc; unsigned char *raster; @@ -7298,6 +7716,15 @@ gif_load (f, img) } } + /* Before reading entire contents, check the declared image size. */ + if (!check_image_size (f, gif->SWidth, gif->SHeight)) + { + image_error ("Invalid image size", Qnil, Qnil); + fn_DGifCloseFile (gif); + UNGCPRO; + return 0; + } + /* Read entire contents. */ rc = fn_DGifSlurp (gif); if (rc == GIF_ERROR) @@ -7319,8 +7746,27 @@ gif_load (f, img) return 0; } - width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width); - height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height); + 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 = 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])); + + if (!check_image_size (f, width, height)) + { + image_error ("Invalid image size", Qnil, Qnil); + fn_DGifCloseFile (gif); + UNGCPRO; + return 0; + } /* Create the X image and pixmap. */ if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) @@ -7355,24 +7801,19 @@ gif_load (f, img) 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. */ - image_top = gif->SavedImages[ino].ImageDesc.Top; - image_left = gif->SavedImages[ino].ImageDesc.Left; - image_width = gif->SavedImages[ino].ImageDesc.Width; - image_height = gif->SavedImages[ino].ImageDesc.Height; - - for (y = 0; y < image_top; ++y) + for (y = 0; y < img->corners[TOP_CORNER]; ++y) for (x = 0; x < width; ++x) XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); - for (y = image_top + image_height; y < height; ++y) + for (y = img->corners[BOT_CORNER]; y < height; ++y) for (x = 0; x < width; ++x) XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); - for (y = image_top; y < image_top + image_height; ++y) + for (y = img->corners[TOP_CORNER]; y < img->corners[BOT_CORNER]; ++y) { - for (x = 0; x < image_left; ++x) + for (x = 0; x < img->corners[LEFT_CORNER]; ++x) XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); - for (x = image_left + image_width; x < width; ++x) + for (x = img->corners[RIGHT_CORNER]; x < width; ++x) XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); } @@ -7402,8 +7843,8 @@ gif_load (f, img) for (x = 0; x < image_width; x++) { int i = raster[(y * image_width) + x]; - XPutPixel (ximg, x + image_left, row + image_top, - pixel_colors[i]); + XPutPixel (ximg, x + img->corners[LEFT_CORNER], + row + img->corners[TOP_CORNER], pixel_colors[i]); } row += interlace_increment[pass]; @@ -7415,10 +7856,29 @@ gif_load (f, img) for (x = 0; x < image_width; ++x) { int i = raster[y * image_width + x]; - XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]); + XPutPixel (ximg, x + img->corners[LEFT_CORNER], + y + img->corners[TOP_CORNER], pixel_colors[i]); } } + /* 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) + { + ExtensionBlock *ext = gif->SavedImages[ino].ExtensionBlocks; + for (i = 0; i < gif->SavedImages[ino].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); + } + if (gif->ImageCount > 1) + img->data.lisp_val = Fcons (Qcount, + Fcons (make_number (gif->ImageCount), + img->data.lisp_val)); + fn_DGifCloseFile (gif); /* Maybe fill in the background field while we have ximg handy. */ @@ -7458,8 +7918,8 @@ gif_load (f, img) RGBColor bg_color; int width, height; XImagePtr ximg; - TimeValue time; - struct gcpro gcpro1; + TimeScale time_scale; + TimeValue time, duration; int ino; CGrafPtr old_port; GDHandle old_gdh; @@ -7467,6 +7927,9 @@ gif_load (f, img) specified_file = image_spec_value (img->spec, QCfile, NULL); specified_data = image_spec_value (img->spec, QCdata, NULL); + /* Animated gifs use QuickTime Movie Toolbox. So initialize it here. */ + EnterMovies (); + if (NILP (specified_data)) { /* Read from a file */ @@ -7564,6 +8027,7 @@ gif_load (f, img) image, img->spec); goto error; } + time_scale = GetMediaTimeScale (media); specified_bg = image_spec_value (img->spec, QCbackground, NULL); if (!STRINGP (specified_bg) || @@ -7589,7 +8053,7 @@ gif_load (f, img) SetGWorld (old_port, old_gdh); SetMovieActive (movie, 1); SetMovieGWorld (movie, ximg, NULL); - SampleNumToMediaTime (media, ino + 1, &time, NULL); + SampleNumToMediaTime (media, ino + 1, &time, &duration); SetMovieTimeValue (movie, time); MoviesTask (movie, 0L); DisposeTrackMedia (media); @@ -7597,6 +8061,24 @@ gif_load (f, img) DisposeMovie (movie); if (dh) DisposeHandle (dh); + + /* Save GIF image extension data for `image-extension-data'. + Format is (count IMAGES 0xf9 GRAPHIC_CONTROL_EXTENSION_BLOCK). */ + { + Lisp_Object gce = make_uninit_string (4); + int centisec = ((float)duration / time_scale) * 100.0f + 0.5f; + + /* Fill the delay time field. */ + SSET (gce, 1, centisec & 0xff); + SSET (gce, 2, (centisec >> 8) & 0xff); + /* We don't know about other fields. */ + SSET (gce, 0, 0); + SSET (gce, 3, 0); + + img->data.lisp_val = list4 (Qcount, make_number (nsamples), + make_number (0xf9), gce); + } + /* Maybe fill in the background field while we have ximg handy. */ if (NILP (image_spec_value (img->spec, QCbackground, NULL))) IMAGE_BACKGROUND (img, f, ximg); @@ -7779,6 +8261,12 @@ gs_load (f, img) in_height = XFASTINT (pt_height) / 72.0; img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy; + if (!check_image_size (f, img->width, img->height)) + { + image_error ("Invalid image size", Qnil, Qnil); + return 0; + } + /* Create the pixmap. */ xassert (img->pixmap == NO_PIXMAP); @@ -8038,9 +8526,6 @@ Each element of the list is a symbol for a image type, like 'jpeg or 'png. To check whether it is really supported, use `image-type-available-p'. */); Vimage_types = Qnil; - define_image_type (&xbm_type, 1); - define_image_type (&pbm_type, 1); - DEFVAR_LISP ("image-library-alist", &Vimage_library_alist, doc: /* Alist of image types vs external libraries needed to display them. @@ -8055,9 +8540,32 @@ listed; they're always supported. */); Vimage_library_alist = Qnil; Fput (intern ("image-library-alist"), Qrisky_local_variable, Qt); + 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. + +If the value is an integer, it directly specifies the maximum +image height and width, measured in pixels. If it is a floating +point number, it specifies the maximum image height and width +as a ratio to the frame height and width. If the value is +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 ("pbm"); + staticpro (&Qpbm); + ADD_IMAGE_TYPE(Qpbm); + + Qxbm = intern ("xbm"); + staticpro (&Qxbm); + ADD_IMAGE_TYPE(Qxbm); + + define_image_type (&xbm_type, 1); + define_image_type (&pbm_type, 1); + QCascent = intern (":ascent"); staticpro (&QCascent); QCmargin = intern (":margin"); @@ -8102,14 +8610,6 @@ listed; they're always supported. */); staticpro (&QCpt_height); #endif /* HAVE_GHOSTSCRIPT */ - Qpbm = intern ("pbm"); - staticpro (&Qpbm); - ADD_IMAGE_TYPE(Qpbm); - - Qxbm = intern ("xbm"); - staticpro (&Qxbm); - ADD_IMAGE_TYPE(Qxbm); - #if defined (HAVE_XPM) || defined (MAC_OS) Qxpm = intern ("xpm"); staticpro (&Qxpm); @@ -8144,6 +8644,7 @@ listed; they're always supported. */); defsubr (&Sclear_image_cache); defsubr (&Simage_size); defsubr (&Simage_mask_p); + defsubr (&Simage_extension_data); #if GLYPH_DEBUG defsubr (&Simagep); @@ -8171,13 +8672,9 @@ meaning don't clear the cache. */); void init_image () { -#ifdef MAC_OS - /* Animated gifs use QuickTime Movie Toolbox. So initialize it here. */ - EnterMovies (); -#ifdef MAC_OSX +#if defined (MAC_OSX) && TARGET_API_MAC_CARBON init_image_func_pointer (); #endif -#endif } /* arch-tag: 123c2a5e-14a8-4c53-ab95-af47d7db49b9