Mercurial > emacs
changeset 54150:6c8849d06ab3
Inserting Yamomotosan's changes for MacOSX image support, better support
of Asian fonts, and some long awaited header cleanup and centralization.
author | Steven Tamm <steventamm@mac.com> |
---|---|
date | Thu, 26 Feb 2004 17:46:48 +0000 |
parents | 6065441e9610 |
children | 9a5c3b661a40 887bb2eb4a89 |
files | src/ChangeLog src/dispextern.h src/emacs.c src/macfns.c src/macgui.h src/macmenu.c src/macterm.c src/macterm.h src/s/darwin.h |
diffstat | 9 files changed, 3218 insertions(+), 1270 deletions(-) [+] |
line wrap: on
line diff
--- a/src/ChangeLog Thu Feb 26 11:14:34 2004 +0000 +++ b/src/ChangeLog Thu Feb 26 17:46:48 2004 +0000 @@ -1,3 +1,215 @@ +2004-02-26 YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> + + * s/darwin.h (LD_SWITCH_SYSTEM_TEMACS): Add `-framework + QuickTime'. + + * dispextern.h [MAC_OSX]: Do not include Carbon/Carbon.h (now in + macgui.h). + + * emacs.c (main) [HAVE_CARBON]: Call init_xfns. + + * macgui.h [MAC_OSX]: Include Carbon/Carbon.h. + (mktime, DEBUG, Z, free, malloc, realloc, max, min) + (init_process) [MAC_OSX] : Avoid conflicts with Carbon/Carbon.h. + [!MAC_OSX]: Include QDOffscreen.h and Controls.h. + (INFINITY) [MAC_OSX]: Avoid conflict with definition in math.h. + (Bitmap): Remove typedef. + (Pixmap): Change int to GWorldPtr. + + * macmenu.c [MAC_OSX]: Do not include Carbon/Carbon.h (now in + macgui.h). + + * macterm.h [MAC_OSX]: Do not include Carbon/Carbon.h (now in + macgui.h). + (RED16_FROM_ULONG, GREEN16_FROM_ULONG, BLUE16_FROM_ULONG): New + #define to extract 16-bit depth color components from unsigned + long representation. + (PIX_MASK_DRAW, PIX_MASK_RETAIN): New #define to represent pixel + colors used for masks. + (struct mac_display_info): Add color_p. Remove n_cbits. + + * macfns.c: Include sys/types.h and sys/stat.h. + [MAC_OSX]: Do not include Carbon/Carbon.h (now in macgui.h). + Include QuickTime/QuickTime.h. + (XCreatePixmap, XCreatePixmapFromBitmapData, XFreePixmap) + (XSetForeground, mac_draw_line_to_pixmap): Add externs for + functions defined in macterm.c. + (XImagePtr): New typedef. Corresponds to XImage * in xfns.c. + (ZPixmap): New #define for compatibility with xfns.c. + (XGetImage, XPutPixel, XGetPixel, XDestroyImage) + (x_create_x_image_and_pixmap, x_destroy_x_image, x_put_x_image) + (find_image_fsspec, image_load_qt_1, image_load_quicktime): New + functions. + (four_corners_best, x_create_x_image_and_pixmap) + (x_destroy_x_image, unwind_create_frame, x_disable_image, + (x_edge_detection, init_color_table, colors_in_color_table, + (lookup_rgb_color, lookup_pixel_color, postprocess_image) + (x_put_x_image, slurp_file, xbm_scan, xbm_load, xbm_load_image) + (xbm_image_p, xbm_read_bitmap_data, xbm_file_p, x_to_xcolors) + (x_from_xcolors, x_detect_edges): New declarations (from xfns.c). + (mac_color_map_lookup, x_to_mac_color): Fix Lisp_Object/unsigned + long mixup. + (mac_defined_color, x_to_x_colors): Use RED16_FROM_ULONG etc. + (x_decode_color): Don't use n_cbits (in struct mac_display_info). + (x_set_foreground_color, x_set_cursor_color): Sync with w32fns.c. + (x_set_cursor_type, Fxw_color_values, valid_image_p) + (image_value_type, parse_image_spec, image_ascent, x_clear_image) + (x_alloc_image_color, clear_image_cache, lookup_image) + (x_find_image_file, xbm_read_bitmap_file_data) + (enum xbm_keyword_index, xbm_format, xbm_image_p, xbm_scan) + (xbm_read_bitmap_data, xbm_load, pbm_image_p, pbm_scan_number) + (enum pbm_keyword_index, pbm_format, enum png_keyword_index) + (png_format, png_image_p, enum jpeg_keyword_index, jpeg_format) + (jpeg_image_p, enum tiff_keyword_index, tiff_format, tiff_image_p) + (enum gif_keyword_index, gif_format, gif_image_p): Sync with + xfns.c. + (x_make_gc): Sync with xfns.c. Enclose unused `border_tile' with + #if 0. + (x_free_gcs): Sync with xfns.c. Enclose unused `border_tile' with + #if 0. Free white_relief.gc and black_relief.gc. + (unwind_create_frame, x_emboss, x_laplace, x_edge_detection): New + functions (from xfns.c). + (Fx_create_frame): Record unwind_create_frame. + (Fxw_display_color_p): Use dpyinfo->color_p. + (Fx_display_grayscale_p, Fx_display_planes): Don't use + dpyinfo->n_cbits. + (Fx_display_color_cells): Use dpyinfo->n_planes; + (QCmatrix, QCcolor_adjustment, QCmask, Qemboss, Qedge_detection) + (Qheuristic, cross_disabled_images, emboss_matrix) + (laplace_matrix): New variables (from xfns.c). + (Fimage_size, Fimage_mask_p, four_corners_best, image_background) + (x_clear_image_1, postprocess_image, slurp_file, xbm_load_image) + (xbm_file_p, x_to_xcolors, x_from_xcolors, x_detect_edges) + (image_background_transparent): New function (from xfns.c). Use + PIX_MASK_DRAW/PIX_MASK_RETAIN. + (image_load_quicktime): Add declaration. + [MAC_OSX] (image_load_quartz2d): Likewise. + [MAC_OSX] (CGImageCreateWithPNGDataProviderProcType): New typedef. + [MAC_OSX] (MyCGImageCreateWithPNGDataProvider): New variable. + [MAC_OSX] (init_image_func_pointer, image_load_quartz2d): New + functions. + (xbm_load_image_from_file, x_laplace_read_row) + (x_laplace_write_row, pbm_read_file): Remove functions. + [HAVE_XPM] (enum xpm_keyword_index, xpm_format, xpm_image_p) + (xpm_load): Sync with xfns.c (although XPM is not supported yet). + (colors_in_color_table): Sync with xfns.c (although not used). + (lookup_rgb_color): Don't lookup color table. Just do gamma + correction. + (COLOR_INTENSITY): New #define (from xfns.c). + (x_disable_image): New function (from xfns.c). Use + PIX_MASK_DRAW/PIX_MASK_RETAIN. + (x_build_heuristic_mask): Sync with xfns.c. Use + PIX_MASK_DRAW/PIX_MASK_RETAIN. + (HAVE_PBM): Remove #ifdef. + (pbm_load): Sync with xfns.c. Set img->width and img->height + before IMAGE_BACKGROUND. + (png_image_p, png_load): Don't enclose declarations with #if + HAVE_PNG. + (Qpng, enum png_keyword_index, png_format, png_type, png_image_p): + Don't enclose with #if HAVE_PNG. + [!HAVE_PNG] (png_load) [MAC_OSX]: Use image_load_quartz2d if a + symbol _CGImageCreateWithPNGDataProvider is defined. Otherwise + use image_load_quicktime. + [!HAVE_PNG] (png_load) [!MAC_OSX]: Use image_load_quicktime. + [HAVE_PNG] (png_load): Sync with xfns.c. Use + PIX_MASK_DRAW/PIX_MASK_RETAIN. + (jpeg_image_p, jpeg_load): Don't enclose declarations with #if + HAVE_JPEG. + (Qjpeg, enum jpeg_keyword_index, jpeg_format, jpeg_type) + (jpeg_image_p): Don't enclose with #if HAVE_JPEG. + [!HAVE_JPEG] (jpeg_load) [MAC_OSX]: Use image_load_quartz2d. + [!HAVE_JPEG] (jpeg_load) [!MAC_OSX]: Use image_load_quicktime. + [HAVE_JPEG] (jpeg_load): Sync with xfns.c. + (tiff_image_p, tiff_load): Don't enclose declarations with #if + HAVE_TIFF. + (Qtiff, enum tiff_keyword_index, tiff_format, tiff_type) + (tiff_image_p): Don't enclose with #if HAVE_TIFF. + [!HAVE_TIFF] (tiff_load): Use image_load_quicktime. + [HAVE_TIFF] (tiff_error_handler, tiff_warning_handler): New + functions (from xfns.c). + [HAVE_TIFF] (tiff_load): Sync with xfns.c. + (gif_image_p, gif_load): Don't enclose declarations with #if + HAVE_GIF. + (Qgif, enum gif_keyword_index, gif_format, gif_type, gif_image_p): + Don't enclose with #if HAVE_GIF. + [!HAVE_GIF] (gif_load): Use Quicktime Movie Toolbox if it is + animated gif. Otherwise use image_load_quicktime. + [HAVE_GIF] (gif_lib.h): Temporarily define DrawText as + gif_DrawText to avoid conflict with QuickdrawText.h. + [HAVE_GIF] (gif_load): Sync with xfns.c. + (enum gs_keyword_index, gs_format, gs_image_p, gs_load) + [HAVE_GHOSTSCRIPT] (x_kill_gs_process): Sync with xfns.c (although + Ghostscript is not supported yet). + (syms_of_macfns): Initialize Qemboss, Qedge_detection, Qheuristic, + QCmatrix, QCcolor_adjustment, and QCmask. Add DEFVAR_BOOL + cross_disabled_images (from xfns.c). Remove #if 0 for supported + image types. Remove #if HAVE_JPEG, HAVE_TIFF, HAVE_GIF, and + HAVE_PNG. Add defsubr for Simage_size and Simage_mask_p. + (init_xfns): Remove #if HAVE_JPEG, HAVE_TIFF, HAVE_GIF, and + HAVE_PNG. Call EnterMovies to support animated gifs. Call + init_image_func_pointer to bind a symbol + _CGImageCreateWithPNGDataProvider if it is defined. + + * macterm.c [MAC_OSX]: Do not include Carbon/Carbon.h (now in + macgui.h). + (x_draw_bar_cursor): Sync declaration with xterm.c. + (XFreePixmap, mac_draw_rectangle_to_pixmap, mac_copy_area) + (mac_copy_area_to_pixmap): Implementation with GWorld (offscreen + graphics). + (mac_set_forecolor, mac_set_backcolor): Use RED16_FROM_ULONG etc. + (mac_draw_line_to_pixmap, XCreatePixmap) + (XCreatePixmapFromBitmapData, mac_fill_rectangle_to_pixmap) + (mac_copy_area_with_mask, mac_copy_area_with_mask_to_pixmap): New + functions. + (mac_draw_bitmap) [TARGET_API_MAC_CARBON]: Use + GetPortBitMapForCopyBits instead of the cast to Bitmap *. Cast + bits to char *. + (reflect_byte): New function (from w32fns.c). + (mac_create_bitmap_from_bitmap_data): Use it and don't stuff bits + due to byte alignment. + (mac_scroll_area) [TARGET_API_MAC_CARBON]: Use + GetPortBitMapForCopyBits instead of the cast to Bitmap *. + (XSetForeground): Remove static (now used in macfns.c). + (HIGHLIGHT_COLOR_DARK_BOOST_LIMIT): New #define (from w32term.c). + (mac_alloc_lighter_color, x_destroy_window): Sync with w32term.c. + (x_setup_relief_color, x_setup_relief_colors, x_draw_box_rect) + (x_draw_glyph_string_box, x_draw_image_foreground) + (x_draw_image_foreground_1, x_draw_image_glyph_string) + (x_draw_stretch_glyph_string, x_draw_glyph_string) + (x_draw_hollow_cursor, x_draw_bar_cursor, mac_draw_window_cursor): + Sync with xterm.c. + (x_draw_relief_rect): Sync with xterm.c. Make 1 pixel shorter + than the xterm.c version when a strictly horizontal or vertical + line is drawn. + (XTset_terminal_window): Add static. + (x_make_frame_visible): Add UNBLOCK_INPUT. + (x_free_frame_resources): New funcion (from xterm.c). + (XTread_socket): Call handle_tool_bar_click if mouse up/down event + occurs in tool bar area. + (mac_initialize_display_info): Remove dpyinfo->n_cbits. Set + dpyinfo->color_p. Determine dpyinfo->n_planes using HasDepth. + Initialize image cache. + (stricmp, wildstrieq, mac_font_pattern_match, mac_font_match): + Enclose unused functions with #if 0. + (Qbig5, Qcn_gb, Qsjis, Qeuc_kr): New variables. + (decode_mac_font_name): New function to apply code conversions + from a mac font name to an XLFD font name according to its script + code. + (x_font_name_to_mac_font_name): Apply code conversion from an XLFD + font name to a mac font name according to REGISTRY and ENCODING + fields. + (init_font_name_table) [TARGET_API_MAC_CARBON]: Don't use a font + whose name starts with `.'. + (init_font_name_table): Use decode_mac_font_name. Add both + jisx0208.1983-sjis and jisx0201.1976-0 entries if the script code + of a font is smJapanese. + (mac_do_list_fonts): New function to list fonts that match a given + pattern. + (x_list_fonts, XLoadQueryFont): Use it. + (XLoadQueryFont): Set rbearing field for each variable width + character to avoid needless redraw. + (syms_of_macterm): Initialize Qbig5, Qcn_gb, Qsjis, and Qeuc_kr. + 2004-02-26 Kim F. Storm <storm@cua.dk> * keyboard.c (NREAD_INPUT_EVENTS): Temporarily increase to 512
--- a/src/dispextern.h Thu Feb 26 11:14:34 2004 +0000 +++ b/src/dispextern.h Thu Feb 26 17:46:48 2004 +0000 @@ -61,38 +61,8 @@ #ifdef HAVE_CARBON #include "macgui.h" typedef struct mac_display_info Display_Info; - -/* Include Carbon.h to define Cursor and Rect. */ -#undef mktime -#undef DEBUG -#undef Z -#undef free -#undef malloc -#undef realloc -/* Macros max and min defined in lisp.h conflict with those in - precompiled header Carbon.h. */ -#undef max -#undef min -#undef init_process -#include <Carbon/Carbon.h> -#undef Z -#define Z (current_buffer->text->z) -#undef free -#define free unexec_free -#undef malloc -#define malloc unexec_malloc -#undef realloc -#define realloc unexec_realloc -#undef min -#define min(a, b) ((a) < (b) ? (a) : (b)) -#undef max -#define max(a, b) ((a) > (b) ? (a) : (b)) -#undef init_process -#define init_process emacs_init_process - #endif - #ifndef NativeRectangle #define NativeRectangle int #endif
--- a/src/emacs.c Thu Feb 26 11:14:34 2004 +0000 +++ b/src/emacs.c Thu Feb 26 17:46:48 2004 +0000 @@ -1589,7 +1589,7 @@ init_vmsproc (); /* And this too. */ #endif /* VMS */ init_sys_modes (); /* Init system terminal modes (RAW or CBREAK, etc.). */ -#if defined (HAVE_X_WINDOWS) || defined (WINDOWSNT) +#if defined (HAVE_X_WINDOWS) || defined (WINDOWSNT) || defined (HAVE_CARBON) init_xfns (); #endif /* HAVE_X_WINDOWS */ init_fns ();
--- a/src/macfns.c Thu Feb 26 11:14:34 2004 +0000 +++ b/src/macfns.c Thu Feb 26 17:46:48 2004 +0000 @@ -54,6 +54,8 @@ /*#include <commdlg.h> #include <shellapi.h>*/ #include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> #include <stdlib.h> #include <string.h> @@ -62,32 +64,7 @@ #endif #ifdef MAC_OSX -#undef mktime -#undef DEBUG -#undef Z -#undef free -#undef malloc -#undef realloc -/* Macros max and min defined in lisp.h conflict with those in - precompiled header Carbon.h. */ -#undef max -#undef min -#undef init_process -#include <Carbon/Carbon.h> -#undef Z -#define Z (current_buffer->text->z) -#undef free -#define free unexec_free -#undef malloc -#define malloc unexec_malloc -#undef realloc -#define realloc unexec_realloc -#undef min -#define min(a, b) ((a) < (b) ? (a) : (b)) -#undef max -#define max(a, b) ((a) > (b) ? (a) : (b)) -#undef init_process -#define init_process emacs_init_process +#include <QuickTime/QuickTime.h> #else /* not MAC_OSX */ #include <Windows.h> #include <Gestalt.h> @@ -209,6 +186,12 @@ extern void x_find_ccl_program (struct font_info *); extern struct font_info *x_query_font (struct frame *, char *); extern void mac_initialize (); +extern Pixmap XCreatePixmap (Display *, WindowPtr, unsigned int, unsigned int, unsigned int); +extern Pixmap XCreatePixmapFromBitmapData (Display *, WindowPtr, char *, unsigned int, unsigned int, unsigned long, unsigned long, unsigned int); +extern void XFreePixmap (Display *, Pixmap); +extern void XSetForeground (Display *, GC, unsigned long); +extern void mac_draw_line_to_pixmap (Display *, Pixmap, GC, int, int, int, int); + /* compare two strings ignoring case */ @@ -552,13 +535,89 @@ xfree (dpyinfo->bitmaps[i].bitmap_data); dpyinfo->bitmaps_last = 0; } + + -/* Connect the frame-parameter names for W32 frames - to the ways of passing the parameter values to the window system. - - The name of a parameter, as a Lisp symbol, - has an `x-frame-parameter' property which is an integer in Lisp - but can be interpreted as an `enum x_frame_parm' in C. */ +/* Mac equivalent of XImage. */ +typedef Pixmap XImagePtr; +#define ZPixmap 0 /* arbitrary */ + +static XImagePtr +XGetImage (display, pixmap, x, y, width, height, plane_mask, format) + Display *display; /* not used */ + Pixmap pixmap; + int x, y; /* not used */ + unsigned int width, height; /* not used */ + unsigned long plane_mask; /* not used */ + int format; /* not used */ +{ +#if GLYPH_DEBUG + xassert (x == 0 && y == 0); + { + Rect ri, rp; + SetRect (&ri, 0, 0, width, height); + xassert (EqualRect (&ri, GetPixBounds (GetGWorldPixMap (pixmap), &rp))); + } + xassert (! (pixelsLocked & GetPixelsState (GetGWorldPixMap (pixmap)))); +#endif + + LockPixels (GetGWorldPixMap (pixmap)); + + return pixmap; +} + +static void +XPutPixel (ximage, x, y, pixel) + XImagePtr ximage; + int x, y; + unsigned long pixel; +{ + RGBColor color; + + 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); +} + +static unsigned long +XGetPixel (ximage, x, y) + XImagePtr ximage; + int x, y; +{ + RGBColor color; + + SetGWorld (ximage, NULL); + + GetCPixel (x, y, &color); + return RGB_TO_ULONG (color.red >> 8, color.green >> 8, color.blue >> 8); +} + +static void +XDestroyImage (ximg) + XImagePtr ximg; +{ + UnlockPixels (GetGWorldPixMap (ximg)); +} + + + +/* Useful functions defined in the section + `Image type independent image structures' below. */ + +static unsigned long four_corners_best P_ ((XImagePtr ximg, 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 void x_destroy_x_image P_ ((XImagePtr ximg)); + +static Lisp_Object unwind_create_frame P_ ((Lisp_Object)); +static void x_disable_image P_ ((struct frame *, struct image *)); void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object)); void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object)); @@ -581,6 +640,13 @@ Lisp_Object, char *, char *, int)); +static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object, + Lisp_Object)); +static void init_color_table P_ ((void)); +static void free_color_table P_ ((void)); +static unsigned long *colors_in_color_table P_ ((int *n)); +static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b)); +static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p)); /* Store the screen positions of frame F into XPTR and YPTR. These are the positions of the containing window manager window, @@ -1382,7 +1448,7 @@ { RGB_TO_ULONG(144, 238, 144), "LightGreen" } }; -unsigned long +Lisp_Object mac_color_map_lookup (colorname) char *colorname; { @@ -1394,7 +1460,7 @@ for (i = 0; i < sizeof (mac_color_map) / sizeof (mac_color_map[0]); i++) if (stricmp (colorname, mac_color_map[i].name) == 0) { - ret = mac_color_map[i].color; + ret = make_number (mac_color_map[i].color); break; } @@ -1463,7 +1529,7 @@ if (i == 2) { UNBLOCK_INPUT; - return (colorval); + return make_number (colorval); } color = end; } @@ -1516,7 +1582,7 @@ if (*end != '\0') break; UNBLOCK_INPUT; - return (colorval); + return make_number (colorval); } if (*end != '/') break; @@ -1557,7 +1623,7 @@ if (*end != '\0') break; UNBLOCK_INPUT; - return (colorval); + return make_number (colorval); } if (*end != '/') break; @@ -1616,9 +1682,9 @@ } color_def->pixel = mac_color_ref; - color_def->red = RED_FROM_ULONG (mac_color_ref); - color_def->green = GREEN_FROM_ULONG (mac_color_ref); - color_def->blue = BLUE_FROM_ULONG (mac_color_ref); + color_def->red = RED16_FROM_ULONG (mac_color_ref); + color_def->green = GREEN16_FROM_ULONG (mac_color_ref); + color_def->blue = BLUE16_FROM_ULONG (mac_color_ref); return 1; } @@ -1649,8 +1715,7 @@ return WHITE_PIX_DEFAULT (f); #if 0 - if ((FRAME_MAC_DISPLAY_INFO (f)->n_planes - * FRAME_MAC_DISPLAY_INFO (f)->n_cbits) == 1) + if (FRAME_MAC_DISPLAY_INFO (f)->n_planes) == 1) return def; #endif @@ -1674,8 +1739,11 @@ struct frame *f; Lisp_Object arg, oldval; { - FRAME_FOREGROUND_PIXEL (f) - = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); + unsigned long fg, old_fg; + + fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); + old_fg = FRAME_FOREGROUND_PIXEL (f); + FRAME_FOREGROUND_PIXEL (f) = fg; if (FRAME_MAC_WINDOW (f) != 0) { @@ -1856,36 +1924,42 @@ struct frame *f; Lisp_Object arg, oldval; { - unsigned long fore_pixel; + unsigned long fore_pixel, pixel; if (!NILP (Vx_cursor_fore_pixel)) fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel, WHITE_PIX_DEFAULT (f)); else fore_pixel = FRAME_BACKGROUND_PIXEL (f); - f->output_data.mac->cursor_pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); + + pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f)); /* Make sure that the cursor color differs from the background color. */ - if (f->output_data.mac->cursor_pixel == FRAME_BACKGROUND_PIXEL (f)) - { - f->output_data.mac->cursor_pixel = f->output_data.mac->mouse_pixel; - if (f->output_data.mac->cursor_pixel == fore_pixel) + if (pixel == FRAME_BACKGROUND_PIXEL (f)) + { + pixel = f->output_data.mac->mouse_pixel; + if (pixel == fore_pixel) fore_pixel = FRAME_BACKGROUND_PIXEL (f); } - FRAME_FOREGROUND_PIXEL (f) = fore_pixel; - -#if 0 /* MAC_TODO: cannot figure out what to do (wrong number of params) */ + + f->output_data.mac->cursor_foreground_pixel = fore_pixel; + f->output_data.mac->cursor_pixel = pixel; + if (FRAME_MAC_WINDOW (f) != 0) { + BLOCK_INPUT; + /* Update frame's cursor_gc. */ + f->output_data.mac->cursor_gc->foreground = fore_pixel; + f->output_data.mac->cursor_gc->background = pixel; + + UNBLOCK_INPUT; + if (FRAME_VISIBLE_P (f)) { - BLOCK_INPUT; - display_and_set_cursor (f, 0); - display_and_set_cursor (f, 1); - UNBLOCK_INPUT; + x_update_cursor (f, 0); + x_update_cursor (f, 1); } } -#endif update_face_from_frame_parameter (f, Qcursor_color, arg); } @@ -1893,11 +1967,13 @@ /* Set the border-color of frame F to pixel value PIX. Note that this does not fully take effect if done before F has a window. */ + void x_set_border_pixel (f, pix) struct frame *f; int pix; { + f->output_data.mac->border_pixel = pix; if (FRAME_MAC_WINDOW (f) != 0 && f->border_width > 0) @@ -1926,6 +2002,7 @@ update_face_from_frame_parameter (f, Qborder_color, arg); } + void x_set_cursor_type (f, arg, oldval) FRAME_PTR f; @@ -1933,9 +2010,8 @@ { set_frame_cursor_types (f, arg); - /* Make sure the cursor gets redrawn. This is overkill, but how - often do people change cursor types? */ - update_mode_lines++; + /* Make sure the cursor gets redrawn. */ + cursor_type_changed = 1; } #if 0 /* MAC_TODO: really no icon for Mac */ @@ -2597,7 +2673,7 @@ BLOCK_INPUT; - /* Create the GC's of this frame. + /* Create the GCs of this frame. Note that many default values are used. */ /* Normal video */ @@ -2629,10 +2705,104 @@ f->output_data.mac->white_relief.gc = 0; f->output_data.mac->black_relief.gc = 0; +#if 0 + /* Create the gray border tile used when the pointer is not in + the frame. Since this depends on the frame's pixel values, + this must be done on a per-frame basis. */ + f->output_data.x->border_tile + = (XCreatePixmapFromBitmapData + (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window, + gray_bits, gray_width, gray_height, + f->output_data.x->foreground_pixel, + f->output_data.x->background_pixel, + DefaultDepth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f)))); +#endif + UNBLOCK_INPUT; } +/* Free what was was allocated in x_make_gc. */ + +void +x_free_gcs (f) + struct frame *f; +{ + Display *dpy = FRAME_MAC_DISPLAY (f); + + BLOCK_INPUT; + + if (f->output_data.mac->normal_gc) + { + XFreeGC (dpy, f->output_data.mac->normal_gc); + f->output_data.mac->normal_gc = 0; + } + + if (f->output_data.mac->reverse_gc) + { + XFreeGC (dpy, f->output_data.mac->reverse_gc); + f->output_data.mac->reverse_gc = 0; + } + + if (f->output_data.mac->cursor_gc) + { + XFreeGC (dpy, f->output_data.mac->cursor_gc); + f->output_data.mac->cursor_gc = 0; + } + +#if 0 + if (f->output_data.mac->border_tile) + { + XFreePixmap (dpy, f->output_data.mac->border_tile); + f->output_data.mac->border_tile = 0; + } +#endif + + if (f->output_data.mac->white_relief.gc) + { + XFreeGC (dpy, f->output_data.mac->white_relief.gc); + f->output_data.mac->white_relief.gc = 0; + } + + if (f->output_data.mac->black_relief.gc) + { + XFreeGC (dpy, f->output_data.mac->black_relief.gc); + f->output_data.mac->black_relief.gc = 0; + } + + UNBLOCK_INPUT; +} + + +/* Handler for signals raised during x_create_frame and + x_create_top_frame. FRAME is the frame which is partially + constructed. */ + +static Lisp_Object +unwind_create_frame (frame) + Lisp_Object frame; +{ + struct frame *f = XFRAME (frame); + + /* If frame is ``official'', nothing to do. */ + if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame)) + { +#if GLYPH_DEBUG + struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); +#endif + + x_free_frame_resources (f); + + /* Check that reference counts are indeed correct. */ + xassert (dpyinfo->reference_count == dpyinfo_refcount); + xassert (dpyinfo->image_cache->refcount == image_cache_refcount); + return Qt; + } + + return Qnil; +} + + DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame, 1, 1, 0, doc: /* Make a new window, which is called a \"frame\" in Emacs terms. @@ -2736,10 +2906,7 @@ FRAME_FONTSET (f) = -1; f->output_data.mac->scroll_bar_foreground_pixel = -1; f->output_data.mac->scroll_bar_background_pixel = -1; - -#if 0 - FRAME_FONTSET (f) = -1; -#endif + record_unwind_protect (unwind_create_frame, frame); f->icon_name = mac_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING); @@ -2790,17 +2957,18 @@ /* First, try whatever font the caller has specified. */ if (STRINGP (font)) { - tem = Fquery_fontset (font, Qnil); - if (STRINGP (tem)) - font = x_new_fontset (f, SDATA (tem)); - else - font = x_new_font (f, SDATA (font)); + tem = Fquery_fontset (font, Qnil); + if (STRINGP (tem)) + font = x_new_fontset (f, SDATA (tem)); + else + font = x_new_font (f, SDATA (font)); } + /* Try out a font which we hope has bold and italic variations. */ if (! STRINGP (font)) font = x_new_font (f, "-ETL-fixed-medium-r-*--*-160-*-*-*-*-iso8859-1"); /* If those didn't work, look for something which will at least work. */ - if (!STRINGP (font)) + if (! STRINGP (font)) font = x_new_font (f, "-*-monaco-*-12-*-mac-roman"); if (! STRINGP (font)) font = x_new_font (f, "-*-courier-*-10-*-mac-roman"); @@ -3011,12 +3179,9 @@ { Lisp_Object rgb[3]; - rgb[0] = make_number ((RED_FROM_ULONG (foo.pixel) << 8) - | RED_FROM_ULONG (foo.pixel)); - rgb[1] = make_number ((GREEN_FROM_ULONG (foo.pixel) << 8) - | GREEN_FROM_ULONG (foo.pixel)); - rgb[2] = make_number ((BLUE_FROM_ULONG (foo.pixel) << 8) - | BLUE_FROM_ULONG (foo.pixel)); + rgb[0] = make_number (foo.red); + rgb[1] = make_number (foo.green); + rgb[2] = make_number (foo.blue); return Flist (3, rgb); } else @@ -3030,7 +3195,7 @@ { struct mac_display_info *dpyinfo = check_x_display_info (display); - if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2) + if (!dpyinfo->color_p) return Qnil; return Qt; @@ -3048,7 +3213,7 @@ { struct mac_display_info *dpyinfo = check_x_display_info (display); - if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1) + if (dpyinfo->n_planes <= 1) return Qnil; return Qt; @@ -3093,7 +3258,7 @@ { struct mac_display_info *dpyinfo = check_x_display_info (display); - return make_number (dpyinfo->n_planes * dpyinfo->n_cbits); + return make_number (dpyinfo->n_planes); } DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells, @@ -3108,7 +3273,7 @@ struct mac_display_info *dpyinfo = check_x_display_info (display); /* MAC_TODO: check whether this is right */ - return make_number ((unsigned long) (pow (2, dpyinfo->n_cbits))); + return make_number (dpyinfo->n_planes >= 8 ? 256 : 1 << dpyinfo->n_planes - 1); } DEFUN ("x-server-max-request-size", Fx_server_max_request_size, @@ -3446,6 +3611,7 @@ return Qnil; } + /*********************************************************************** Image types @@ -3470,11 +3636,11 @@ extern Lisp_Object QCdata, QCtype; Lisp_Object QCascent, QCmargin, QCrelief; Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask; -Lisp_Object QCindex; +Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask; /* Other symbols. */ -Lisp_Object Qlaplace; +Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic; /* Time in seconds after which images should be removed from the cache if not displayed. */ @@ -3487,6 +3653,7 @@ 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)); @@ -3540,11 +3707,22 @@ if (IMAGEP (object)) { - Lisp_Object symbol = Fplist_get (XCDR (object), QCtype); - struct image_type *type = lookup_image_type (symbol); - - if (type) - valid_p = type->valid_p (object); + Lisp_Object tem; + + for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem)) + if (EQ (XCAR (tem), QCtype)) + { + tem = XCDR (tem); + if (CONSP (tem) && SYMBOLP (XCAR (tem))) + { + struct image_type *type; + type = lookup_image_type (XCAR (tem)); + if (type) + valid_p = type->valid_p (object); + } + + break; + } } return valid_p; @@ -3554,8 +3732,8 @@ /* Log error message with format string FORMAT and argument ARG. Signaling an error, e.g. when an image cannot be loaded, is not a good idea because this would interrupt redisplay, and the error - message display would lead to another redisplay. This function - therefore simply displays a message. */ + message display would lead to another redisplay. This function + therefore simply displays a message. */ static void image_error (format, arg1, arg2) @@ -3575,6 +3753,7 @@ { IMAGE_DONT_CHECK_VALUE_TYPE, IMAGE_STRING_VALUE, + IMAGE_STRING_OR_NIL_VALUE, IMAGE_SYMBOL_VALUE, IMAGE_POSITIVE_INTEGER_VALUE, IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, @@ -3654,7 +3833,7 @@ break; if (i == nkeywords) - continue; + continue; /* Record that we recognized the keyword. If a keywords was found more than once, it's an error. */ @@ -3672,6 +3851,11 @@ return 0; break; + case IMAGE_STRING_OR_NIL_VALUE: + if (!STRINGP (value) && !NILP (value)) + return 0; + break; + case IMAGE_SYMBOL_VALUE: if (!SYMBOLP (value)) return 0; @@ -3691,7 +3875,7 @@ break; return 0; - case IMAGE_ASCENT_VALUE: + case IMAGE_ASCENT_VALUE: if (SYMBOLP (value) && EQ (value, Qcenter)) break; else if (INTEGERP (value) @@ -3780,6 +3964,63 @@ } +DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0, + doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT). +PIXELS non-nil means return the size in pixels, otherwise return the +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 size; + + size = 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); + int width = img->width + 2 * img->hmargin; + int height = img->height + 2 * img->vmargin; + + if (NILP (pixels)) + size = Fcons (make_float ((double) width / FRAME_COLUMN_WIDTH (f)), + make_float ((double) height / FRAME_LINE_HEIGHT (f))); + else + size = Fcons (make_number (width), make_number (height)); + } + else + error ("Invalid image specification"); + + return size; +} + + +DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0, + 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 mask; + + mask = Qnil; + if (valid_image_p (spec)) + { + struct frame *f = check_x_frame (frame); + int id = lookup_image (f, spec); + struct image *img = IMAGE_FROM_ID (f, id); + if (img->mask) + mask = Qt; + } + else + error ("Invalid image specification"); + + return mask; +} + /*********************************************************************** @@ -3876,8 +4117,12 @@ if (img->ascent == CENTERED_IMAGE_ASCENT) { if (face->font) - ascent = height / 2 - (FONT_DESCENT(face->font) - - FONT_BASE(face->font)) / 2; + /* This expression is arranged so that if the image can't be + exactly centered, it will be moved slightly up. This is + 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 + face->font->ascent - face->font->descent + 1) / 2; else ascent = height / 2; } @@ -3887,18 +4132,155 @@ return ascent; } + +/* Image background colors. */ + +static unsigned long +four_corners_best (ximg, width, height) + XImagePtr ximg; + unsigned long width, height; +{ + unsigned long corners[4], best; + int i, best_count; + + /* Get the colors at the corners of ximg. */ + corners[0] = XGetPixel (ximg, 0, 0); + corners[1] = XGetPixel (ximg, width - 1, 0); + corners[2] = XGetPixel (ximg, width - 1, height - 1); + corners[3] = XGetPixel (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]) + ++n; + + if (n > best_count) + best = corners[i], best_count = n; + } + + return best; +} + +/* Return the `background' field of IMG. If IMG doesn't have one yet, + it is guessed heuristically. If non-zero, XIMG is an existing XImage + object to use for the heuristic. */ + +unsigned long +image_background (img, f, ximg) + struct image *img; + struct frame *f; + XImagePtr ximg; +{ + if (! img->background_valid) + /* IMG doesn't have a background yet, try to guess a reasonable value. */ + { + int free_ximg = !ximg; + + if (! ximg) + ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, + 0, 0, img->width, img->height, ~0, ZPixmap); + + img->background = four_corners_best (ximg, img->width, img->height); + + if (free_ximg) + XDestroyImage (ximg); + + img->background_valid = 1; + } + + return img->background; +} + +/* Return the `background_transparent' field of IMG. If IMG doesn't + have one yet, it is guessed heuristically. If non-zero, MASK is an + existing XImage object to use for the heuristic. */ + +int +image_background_transparent (img, f, mask) + struct image *img; + struct frame *f; + XImagePtr mask; +{ + if (! img->background_transparent_valid) + /* IMG doesn't have a background yet, try to guess a reasonable value. */ + { + if (img->mask) + { + int free_mask = !mask; + + if (! mask) + mask = XGetImage (FRAME_X_DISPLAY (f), img->mask, + 0, 0, img->width, img->height, ~0, ZPixmap); + + img->background_transparent + = four_corners_best (mask, img->width, img->height) == PIX_MASK_RETAIN (f); + + if (free_mask) + XDestroyImage (mask); + } + else + img->background_transparent = 0; + + img->background_transparent_valid = 1; + } + + return img->background_transparent; +} /*********************************************************************** 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)); + +/* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means + free the pixmap if any. MASK_P non-zero means clear the mask + pixmap if any. COLORS_P non-zero means free colors allocated for + 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; +{ + if (pixmap_p && img->pixmap) + { + XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap); + img->pixmap = NULL; + img->background_valid = 0; + } + + if (mask_p && img->mask) + { + XFreePixmap (FRAME_X_DISPLAY (f), img->mask); + img->mask = NULL; + img->background_transparent_valid = 0; + } + + if (colors_p && img->ncolors) + { +#if 0 /* TODO: color table support. */ + x_free_colors (f, img->colors, img->ncolors); +#endif + xfree (img->colors); + img->colors = NULL; + img->ncolors = 0; + } +} + /* Free X resources of image IMG which is used on frame F. */ static void @@ -3906,39 +4288,9 @@ struct frame *f; struct image *img; { -#if 0 /* MAC_TODO: W32 image support */ - - if (img->pixmap) - { - BLOCK_INPUT; - XFreePixmap (NULL, img->pixmap); - img->pixmap = 0; - UNBLOCK_INPUT; - } - - if (img->ncolors) - { - int class = FRAME_W32_DISPLAY_INFO (f)->visual->class; - - /* If display has an immutable color map, freeing colors is not - necessary and some servers don't allow it. So don't do it. */ - if (class != StaticColor - && class != StaticGray - && class != TrueColor) - { - Colormap cmap; - BLOCK_INPUT; - cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen); - XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors, - img->ncolors, 0); - UNBLOCK_INPUT; - } - - xfree (img->colors); - img->colors = NULL; - img->ncolors = 0; - } -#endif /* MAC_TODO */ + BLOCK_INPUT; + x_clear_image_1 (f, img, 1, 1, 1); + UNBLOCK_INPUT; } @@ -3954,13 +4306,12 @@ Lisp_Object color_name; unsigned long dflt; { -#if 0 /* MAC_TODO: allocing colors. */ XColor color; unsigned long result; xassert (STRINGP (color_name)); - if (w32_defined_color (f, SDATA (color_name), &color, 1)) + if (mac_defined_color (f, SDATA (color_name), &color, 1)) { /* This isn't called frequently so we get away with simply reallocating the color vector to the needed size, here. */ @@ -3973,9 +4324,8 @@ } else result = dflt; + return result; -#endif /* MAC_TODO */ - return 0; } @@ -3985,6 +4335,7 @@ ***********************************************************************/ static void cache_image P_ ((struct frame *f, struct image *img)); +static void postprocess_image P_ ((struct frame *, struct image *)); /* Return a new, initialized image cache that is allocated from the @@ -4049,20 +4400,23 @@ { EMACS_TIME t; unsigned long old; - int i, any_freed_p = 0; + int i, nfreed; EMACS_GET_TIME (t); old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay); - for (i = 0; i < c->used; ++i) + /* Block input so that we won't be interrupted by a SIGIO + while being in an inconsistent state. */ + BLOCK_INPUT; + + for (i = nfreed = 0; i < c->used; ++i) { struct image *img = c->images[i]; if (img != NULL - && (force_p - || (img->timestamp > old))) + && (force_p || img->timestamp < old)) { free_image (f, img); - any_freed_p = 1; + ++nfreed; } } @@ -4070,11 +4424,22 @@ Emacs was iconified for a longer period of time. In that case, current matrices may still contain references to images freed above. So, clear these matrices. */ - if (any_freed_p) + if (nfreed) { - clear_current_matrices (f); + Lisp_Object tail, frame; + + FOR_EACH_FRAME (tail, frame) + { + struct frame *f = XFRAME (frame); + if (FRAME_MAC_P (f) + && FRAME_X_IMAGE_CACHE (f) == c) + clear_current_matrices (f); + } + ++windows_or_buffers_changed; } + + UNBLOCK_INPUT; } } @@ -4084,7 +4449,7 @@ doc: /* Clear the image cache of FRAME. FRAME nil or omitted means use the selected frame. FRAME t means clear the image caches of all frames. */) - (frame) + (frame) Lisp_Object frame; { if (EQ (frame, Qt)) @@ -4102,6 +4467,81 @@ } +/* Compute masks and transform image IMG on frame F, as specified + by the image's specification, */ + +static void +postprocess_image (f, img) + struct frame *f; + struct image *img; +{ + /* Manipulation of the image's mask. */ + if (img->pixmap) + { + Lisp_Object conversion, spec; + Lisp_Object mask; + + spec = img->spec; + + /* `:heuristic-mask t' + `:mask heuristic' + means build a mask heuristically. + `:heuristic-mask (R G B)' + `:mask (heuristic (R G B))' + means build a mask from color (R G B) in the + image. + `:mask nil' + means remove a mask, if any. */ + + mask = image_spec_value (spec, QCheuristic_mask, NULL); + if (!NILP (mask)) + x_build_heuristic_mask (f, img, mask); + else + { + int found_p; + + mask = image_spec_value (spec, QCmask, &found_p); + + if (EQ (mask, Qheuristic)) + x_build_heuristic_mask (f, img, Qt); + else if (CONSP (mask) + && EQ (XCAR (mask), Qheuristic)) + { + if (CONSP (XCDR (mask))) + x_build_heuristic_mask (f, img, XCAR (XCDR (mask))); + else + x_build_heuristic_mask (f, img, XCDR (mask)); + } + else if (NILP (mask) && found_p && img->mask) + { + XFreePixmap (FRAME_X_DISPLAY (f), img->mask); + img->mask = NULL; + } + } + + + /* Should we apply an image transformation algorithm? */ + conversion = image_spec_value (spec, QCconversion, NULL); + if (EQ (conversion, Qdisabled)) + x_disable_image (f, img); + else if (EQ (conversion, Qlaplace)) + x_laplace (f, img); + else if (EQ (conversion, Qemboss)) + x_emboss (f, img); + else if (CONSP (conversion) + && EQ (XCAR (conversion), Qedge_detection)) + { + Lisp_Object tem; + tem = XCDR (conversion); + if (CONSP (tem)) + x_edge_detection (f, img, + Fplist_get (tem, QCmatrix), + Fplist_get (tem, QCcolor_adjustment)); + } + } +} + + /* Return the id of image with Lisp specification SPEC on frame F. SPEC must be a valid Lisp image specification (see valid_image_p). */ @@ -4135,11 +4575,12 @@ /* If not found, create a new image and cache it. */ if (img == NULL) { + extern Lisp_Object Qpostscript; + BLOCK_INPUT; img = make_image (spec, hash); cache_image (f, img); img->load_failed_p = img->type->load (f, img) == 0; - xassert (!interrupt_input_blocked); /* If we can't load the image, and we don't have a width and height, use some arbitrary width and height so that we can @@ -4158,14 +4599,15 @@ else { /* Handle image type independent image attributes - `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */ - Lisp_Object ascent, margin, relief; + `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF', + `:background COLOR'. */ + Lisp_Object ascent, margin, relief, bg; ascent = image_spec_value (spec, QCascent, NULL); if (INTEGERP (ascent)) img->ascent = XFASTINT (ascent); else if (EQ (ascent, Qcenter)) - img->ascent = CENTERED_IMAGE_ASCENT; + img->ascent = CENTERED_IMAGE_ASCENT; margin = image_spec_value (spec, QCmargin, NULL); if (INTEGERP (margin) && XINT (margin) >= 0) @@ -4186,7 +4628,26 @@ img->hmargin += abs (img->relief); img->vmargin += abs (img->relief); } + + if (! img->background_valid) + { + bg = image_spec_value (img->spec, QCbackground, NULL); + if (!NILP (bg)) + { + img->background + = x_alloc_image_color (f, img, bg, + FRAME_BACKGROUND_PIXEL (f)); + img->background_valid = 1; + } + } + + /* Do image transformations and compute masks, unless we + don't have the image yet. */ + if (!EQ (*img->type->type, Qpostscript)) + postprocess_image (f, img); } + + UNBLOCK_INPUT; } /* We're using IMG, so set its timestamp to `now'. */ @@ -4266,48 +4727,23 @@ Mac support code ***********************************************************************/ -#if 0 /* MAC_TODO: Mac specific image code. */ - static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int, - XImage **, Pixmap *)); -static void x_destroy_x_image P_ ((XImage *)); -static void x_put_x_image P_ ((struct frame *, XImage *, 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 - via xmalloc. Print error messages via image_error if an error - occurs. Value is non-zero if successful. */ - -static int + XImagePtr *, Pixmap *)); +static void x_destroy_x_image P_ ((XImagePtr)); +static void x_put_x_image P_ ((struct frame *, XImagePtr, Pixmap, int, int)); + + x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap) struct frame *f; int width, height, depth; - XImage **ximg; + XImagePtr *ximg; Pixmap *pixmap; { -#if 0 /* MAC_TODO: Image support for Mac */ - Display *display = FRAME_W32_DISPLAY (f); - Screen *screen = FRAME_X_SCREEN (f); - Window window = FRAME_W32_WINDOW (f); + Display *display = FRAME_MAC_DISPLAY (f); + Window window = FRAME_MAC_WINDOW (f); xassert (interrupt_input_blocked); - if (depth <= 0) - depth = DefaultDepthOfScreen (screen); - *ximg = XCreateImage (display, DefaultVisualOfScreen (screen), - depth, ZPixmap, 0, NULL, width, height, - depth > 16 ? 32 : depth > 8 ? 16 : 8, 0); - if (*ximg == NULL) - { - image_error ("Unable to allocate X image", Qnil, Qnil); - return 0; - } - - /* Allocate image raster. */ - (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height); - /* Allocate a pixmap of the same size. */ *pixmap = XCreatePixmap (display, window, width, height, depth); if (*pixmap == 0) @@ -4317,52 +4753,39 @@ image_error ("Unable to create X pixmap", Qnil, Qnil); return 0; } -#endif /* MAC_TODO */ + + LockPixels (GetGWorldPixMap (*pixmap)); + *ximg = *pixmap; return 1; } - -/* Destroy XImage XIMG. Free XIMG->data. */ - static void x_destroy_x_image (ximg) - XImage *ximg; + XImagePtr ximg; { xassert (interrupt_input_blocked); if (ximg) - { - xfree (ximg->data); - ximg->data = NULL; - XDestroyImage (ximg); - } -} - - -/* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT - are width and height of both the image and pixmap. */ + XDestroyImage (ximg); +} static void x_put_x_image (f, ximg, pixmap, width, height) struct frame *f; - XImage *ximg; + XImagePtr ximg; Pixmap pixmap; { - GC gc; - - xassert (interrupt_input_blocked); - gc = XCreateGC (NULL, pixmap, 0, NULL); - XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height); - XFreeGC (NULL, gc); -} - -#endif /* MAC_TODO */ + xassert (ximg == pixmap); +} + /*********************************************************************** - Searching files + File Handling ***********************************************************************/ static Lisp_Object x_find_image_file P_ ((Lisp_Object)); +static 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 @@ -4383,7 +4806,7 @@ /* Try to find FILE in data-directory, then x-bitmap-file-path. */ fd = openp (search_path, file, Qnil, &file_found, Qnil); - if (fd < 0) + if (fd == -1) file_found = Qnil; else close (fd); @@ -4392,17 +4815,398 @@ return file_found; } + +/* Read FILE into memory. Value is a pointer to a buffer allocated + with xmalloc holding FILE's contents. Value is null if an error + occurred. *SIZE is set to the size of the file. */ + +static char * +slurp_file (file, size) + char *file; + int *size; +{ + FILE *fp = NULL; + char *buf = NULL; + struct stat st; + + if (stat (file, &st) == 0 + && (fp = fopen (file, "r")) != NULL + && (buf = (char *) xmalloc (st.st_size), + fread (buf, 1, st.st_size, fp) == st.st_size)) + { + *size = st.st_size; + fclose (fp); + } + else + { + if (fp) + fclose (fp); + if (buf) + { + xfree (buf); + buf = NULL; + } + } + + return buf; +} + + + +/*********************************************************************** + Image Load Functions + ***********************************************************************/ + +static int image_load_quicktime P_ ((struct frame *, struct image *img, + OSType)); +#ifdef MAC_OSX +static int image_load_quartz2d P_ ((struct frame *, struct image *img, int)); +#endif + + +static OSErr +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; + + *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); + if (err == noErr) + err = FSGetCatalogInfo (&fsr, kFSCatInfoNone, NULL, NULL, fss, NULL); +#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); +#endif + return err; +} + + +static int +image_load_qt_1 (f, img, type, fss, dh) + struct frame *f; + struct image *img; + OSType type; + FSSpec *fss; + Handle dh; +{ + OSErr err; + GraphicsImportComponent gi; + Rect rect; + int width, height; + short draw_all_pixels; + Lisp_Object specified_bg; + XColor color; + XImagePtr ximg; + RGBColor bg_color; + + err = OpenADefaultComponent (GraphicsImporterComponentType, + type, &gi); + if (err != noErr) + { + image_error ("Cannot get importer component for `%s'", img->spec, Qnil); + return 0; + } + if (dh == NULL) + { + /* read from file system spec */ + err = GraphicsImportSetDataFile (gi, fss); + if (err != noErr) + { + image_error ("Cannot set fsspec to graphics importer for '%s'", + img->spec, Qnil); + goto error; + } + } + else + { + /* read from data handle */ + err = GraphicsImportSetDataHandle (gi, dh); + if (err != noErr) + { + image_error ("Cannot set data handle to graphics importer for `%s'", + img->spec, Qnil); + goto error; + } + } + err = GraphicsImportGetNaturalBounds (gi, &rect); + if (err != noErr) + { + image_error ("Error reading `%s'", img->spec, Qnil); + goto error; + } + width = img->width = rect.right - rect.left; + height = img->height = rect.bottom - rect.top; + err = GraphicsImportDoesDrawAllPixels (gi, &draw_all_pixels); +#if 0 + /* Don't check the error code here. It may have an undocumented + value -32766. */ + if (err != noErr) + { + image_error ("Error reading `%s'", img->spec, Qnil); + goto error; + } +#endif + if (draw_all_pixels != graphicsImporterDrawsAllPixels) + { + specified_bg = image_spec_value (img->spec, QCbackground, NULL); + if (!STRINGP (specified_bg) || + !mac_defined_color (f, SDATA (specified_bg), &color, 0)) + { + color.pixel = FRAME_BACKGROUND_PIXEL (f); + color.red = RED16_FROM_ULONG (color.pixel); + color.green = GREEN16_FROM_ULONG (color.pixel); + color.blue = BLUE16_FROM_ULONG (color.pixel); + } + } + + if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) + goto error; + if (draw_all_pixels != graphicsImporterDrawsAllPixels) + { + SetGWorld (ximg, NULL); + bg_color.red = color.red; + bg_color.green = color.green; + bg_color.blue = color.blue; + RGBBackColor (&bg_color); +#if TARGET_API_MAC_CARBON + GetPortBounds (ximg, &rect); + EraseRect (&rect); +#else + EraseRect (&(ximg->portRect)); +#endif + } + GraphicsImportSetGWorld (gi, ximg, NULL); + GraphicsImportDraw (gi); + CloseComponent (gi); + + /* 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); + + /* Put the image into the pixmap. */ + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + return 1; + + error: + CloseComponent (gi); + return 0; +} + + +/* Load an image using the QuickTime Graphics Importer. + Note: The alpha channel does not work for PNG images. */ +static int +image_load_quicktime (f, img, type) + struct frame *f; + struct image *img; + OSType type; +{ + Lisp_Object specified_file; + Lisp_Object specified_data; + OSErr err; + + specified_file = image_spec_value (img->spec, QCfile, NULL); + specified_data = image_spec_value (img->spec, QCdata, NULL); + + if (NILP (specified_data)) + { + /* Read from a file */ + Lisp_Object file; + FSSpec fss; + + err = find_image_fsspec (specified_file, &file, &fss); + if (err != noErr) + { + if (err == fnfErr) + image_error ("Cannot find image file `%s'", specified_file, Qnil); + else + image_error ("Cannot open `%s'", file, Qnil); + return 0; + } + return image_load_qt_1 (f, img, type, &fss, NULL); + } + else + { + /* Memory source! */ + int success_p; + Handle dh; + + err = PtrToHand (SDATA (specified_data), &dh, SBYTES (specified_data)); + if (err != noErr) + { + image_error ("Cannot allocate data handle for `%s'", + img->spec, Qnil); + return 0; + } + success_p = image_load_qt_1 (f, img, type, NULL, dh); + DisposeHandle (dh); + return success_p; + } +} + + +#ifdef MAC_OSX +/* Load a PNG/JPEG image using Quartz 2D decoding routines. + CGImageCreateWithPNGDataProvider is provided after Mac OS X 10.2. + So don't use this function directly but determine at runtime + whether it exists. */ +typedef CGImageRef (*CGImageCreateWithPNGDataProviderProcType) + (CGDataProviderRef, const float [], bool, CGColorRenderingIntent); +static CGImageCreateWithPNGDataProviderProcType MyCGImageCreateWithPNGDataProvider; + + +static void +init_image_func_pointer () +{ + if (NSIsSymbolNameDefined ("_CGImageCreateWithPNGDataProvider")) + { + MyCGImageCreateWithPNGDataProvider + = (CGImageCreateWithPNGDataProviderProcType) + NSAddressOfSymbol (NSLookupAndBindSymbol + ("_CGImageCreateWithPNGDataProvider")); + } + else + MyCGImageCreateWithPNGDataProvider = NULL; +} + + +static int +image_load_quartz2d (f, img, png_p) + struct frame *f; + struct image *img; + int png_p; +{ + Lisp_Object file, specified_file; + Lisp_Object specified_data, specified_bg; + struct gcpro gcpro1; + CGDataProviderRef source; + CGImageRef image; + int width, height; + XColor color; + XImagePtr ximg = NULL; + CGContextRef context; + CGRect rectangle; + + /* Open the 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)) + { + CFStringRef path; + CFURLRef url; + + file = x_find_image_file (specified_file); + if (!STRINGP (file)) + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + UNGCPRO; + return 0; + } + path = CFStringCreateWithCString (NULL, SDATA (file), + kCFStringEncodingUTF8); + url = CFURLCreateWithFileSystemPath (NULL, path, + kCFURLPOSIXPathStyle, 0); + CFRelease (path); + source = CGDataProviderCreateWithURL (url); + CFRelease (url); + } + else + source = CGDataProviderCreateWithData (NULL, SDATA (specified_data), + SBYTES (specified_data), NULL); + + if (png_p) + image = (*MyCGImageCreateWithPNGDataProvider) (source, NULL, FALSE, + kCGRenderingIntentDefault); + else + image = CGImageCreateWithJPEGDataProvider (source, NULL, FALSE, + kCGRenderingIntentDefault); + + CGDataProviderRelease (source); + if (image == NULL) + { + UNGCPRO; + image_error ("Error reading image `%s'", img->spec, Qnil); + return 0; + } + + if (png_p) + { + specified_bg = image_spec_value (img->spec, QCbackground, NULL); + if (!STRINGP (specified_bg) || + !mac_defined_color (f, SDATA (specified_bg), &color, 0)) + { + color.pixel = FRAME_BACKGROUND_PIXEL (f); + color.red = RED16_FROM_ULONG (color.pixel); + color.green = GREEN16_FROM_ULONG (color.pixel); + 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); + UNGCPRO; + return 0; + } + rectangle = CGRectMake (0, 0, width, height); + QDBeginCGContext (ximg, &context); + if (png_p) + { + CGContextSetRGBFillColor (context, color.red / 65535.0, + color.green / 65535.0, + color.blue / 65535.0, 1.0); + CGContextFillRect (context, rectangle); + } + CGContextDrawImage (context, rectangle, image); + QDEndCGContext (ximg, &context); + CGImageRelease (image); + + /* 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); + + /* Put the image into the pixmap. */ + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + UNGCPRO; + return 1; +} +#endif + + /*********************************************************************** XBM images ***********************************************************************/ +static int xbm_scan P_ ((char **, char *, char *, int *)); static int xbm_load P_ ((struct frame *f, struct image *img)); -static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img, - Lisp_Object file)); +static int xbm_load_image P_ ((struct frame *f, struct image *img, + char *, char *)); static int xbm_image_p P_ ((Lisp_Object object)); -static int xbm_read_bitmap_file_data P_ ((char *, int *, int *, - unsigned char **)); +static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *, + unsigned char **)); +static int xbm_file_p P_ ((Lisp_Object)); /* Indices of image specification fields in xbm_format, below. */ @@ -4421,6 +5225,7 @@ XBM_RELIEF, XBM_ALGORITHM, XBM_HEURISTIC_MASK, + XBM_MASK, XBM_LAST }; @@ -4434,13 +5239,14 @@ {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0}, {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0}, {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":foreground", IMAGE_STRING_VALUE, 0}, - {":background", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, + {":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}, {":relief", IMAGE_INTEGER_VALUE, 0}, {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} }; /* Structure describing the image type XBM. */ @@ -4483,10 +5289,14 @@ 3. a vector of strings or bool-vectors, one for each line of the bitmap. + 4. A string containing an in-memory XBM file. WIDTH and HEIGHT + may not be specified in this case because they are defined in the + XBM file. + Both the file and data forms may contain the additional entries `:background COLOR' and `:foreground COLOR'. If not present, foreground and background of the frame on which the image is - displayed, is used. */ + displayed is used. */ static int xbm_image_p (object) @@ -4505,6 +5315,12 @@ if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count) return 0; } + else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value)) + { + /* In-memory XBM file. */ + if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count) + return 0; + } else { Lisp_Object data; @@ -4566,11 +5382,6 @@ return 0; } - /* Baseline must be a value between 0 and 100 (a percentage). */ - if (kw[XBM_ASCENT].count - && XFASTINT (kw[XBM_ASCENT].value) > 100) - return 0; - return 1; } @@ -4582,30 +5393,33 @@ scanning a number, store its value in *IVAL. */ static int -xbm_scan (fp, sval, ival) - FILE *fp; +xbm_scan (s, end, sval, ival) + char **s, *end; char *sval; int *ival; { int c; + loop: + /* Skip white space. */ - while ((c = fgetc (fp)) != EOF && isspace (c)) + while (*s < end && (c = *(*s)++, isspace (c))) ; - if (c == EOF) + if (*s >= end) c = 0; else if (isdigit (c)) { int value = 0, digit; - if (c == '0') + if (c == '0' && *s < end) { - c = fgetc (fp); + c = *(*s)++; if (c == 'x' || c == 'X') { - while ((c = fgetc (fp)) != EOF) + while (*s < end) { + c = *(*s)++; if (isdigit (c)) digit = c - '0'; else if (c >= 'a' && c <= 'f') @@ -4620,53 +5434,66 @@ else if (isdigit (c)) { value = c - '0'; - while ((c = fgetc (fp)) != EOF - && isdigit (c)) + while (*s < end + && (c = *(*s)++, isdigit (c))) value = 8 * value + c - '0'; } } else { value = c - '0'; - while ((c = fgetc (fp)) != EOF - && isdigit (c)) + while (*s < end + && (c = *(*s)++, isdigit (c))) value = 10 * value + c - '0'; } - if (c != EOF) - ungetc (c, fp); + if (*s < end) + *s = *s - 1; *ival = value; c = XBM_TK_NUMBER; } else if (isalpha (c) || c == '_') { *sval++ = c; - while ((c = fgetc (fp)) != EOF - && (isalnum (c) || c == '_')) + while (*s < end + && (c = *(*s)++, (isalnum (c) || c == '_'))) *sval++ = c; *sval = 0; - if (c != EOF) - ungetc (c, fp); + if (*s < end) + *s = *s - 1; c = XBM_TK_IDENT; } + else if (c == '/' && **s == '*') + { + /* C-style comment. */ + ++*s; + while (**s && (**s != '*' || *(*s + 1) != '/')) + ++*s; + if (**s) + { + *s += 2; + goto loop; + } + } return c; } /* Replacement for XReadBitmapFileData which isn't available under old - X versions. FILE is the name of the bitmap file to read. Set - *WIDTH and *HEIGHT to the width and height of the image. Return in - *DATA the bitmap data allocated with xmalloc. Value is non-zero if - successful. */ + X versions. CONTENTS is a pointer to a buffer to parse; END is the + buffer's end. Set *WIDTH and *HEIGHT to the width and height of + the image. Return in *DATA the bitmap data allocated with xmalloc. + Value is non-zero if successful. DATA null means just test if + CONTENTS looks like an in-memory XBM file. */ static int -xbm_read_bitmap_file_data (file, width, height, data) - char *file; +xbm_read_bitmap_data (contents, end, width, height, data) + char *contents, *end; int *width, *height; unsigned char **data; { - FILE *fp; + char *s = contents; char buffer[BUFSIZ]; int padding_p = 0; int v10 = 0; @@ -4676,7 +5503,7 @@ int LA1; #define match() \ - LA1 = xbm_scan (fp, buffer, &value) + LA1 = xbm_scan (&s, end, buffer, &value) #define expect(TOKEN) \ if (LA1 != (TOKEN)) \ @@ -4690,13 +5517,10 @@ else \ goto failure - fp = fopen (file, "r"); - if (fp == NULL) - return 0; - *width = *height = -1; - *data = NULL; - LA1 = xbm_scan (fp, buffer, &value); + if (data) + *data = NULL; + LA1 = xbm_scan (&s, end, buffer, &value); /* Parse defines for width, height and hot-spots. */ while (LA1 == '#') @@ -4719,6 +5543,8 @@ if (*width < 0 || *height < 0) goto failure; + else if (data == NULL) + goto success; /* Parse bits. Must start with `static'. */ expect_ident ("static"); @@ -4756,7 +5582,6 @@ if (v10) { - for (i = 0; i < nbytes; i += 2) { int val = value; @@ -4788,13 +5613,12 @@ } } - fclose (fp); + success: return 1; failure: - fclose (fp); - if (*data) + if (data && *data) { xfree (*data); *data = NULL; @@ -4807,38 +5631,24 @@ } -/* Load XBM image IMG which will be displayed on frame F from file - SPECIFIED_FILE. Value is non-zero if successful. */ +/* Load XBM image IMG which will be displayed on frame F from buffer + CONTENTS. END is the end of the buffer. Value is non-zero if + successful. */ static int -xbm_load_image_from_file (f, img, specified_file) +xbm_load_image (f, img, contents, end) struct frame *f; struct image *img; - Lisp_Object specified_file; + char *contents, *end; { int rc; unsigned char *data; int success_p = 0; - Lisp_Object file; - struct gcpro gcpro1; - - xassert (STRINGP (specified_file)); - file = Qnil; - GCPRO1 (file); - - file = x_find_image_file (specified_file); - if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNGCPRO; - return 0; - } - - rc = xbm_read_bitmap_file_data (SDATA (file), &img->width, - &img->height, &data); + + rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data); if (rc) { - int depth = one_mac_display_info.n_cbits; + int depth = one_mac_display_info.n_planes; unsigned long foreground = FRAME_FOREGROUND_PIXEL (f); unsigned long background = FRAME_BACKGROUND_PIXEL (f); Lisp_Object value; @@ -4849,16 +5659,17 @@ value = image_spec_value (img->spec, QCforeground, NULL); if (!NILP (value)) foreground = x_alloc_image_color (f, img, value, foreground); - value = image_spec_value (img->spec, QCbackground, NULL); if (!NILP (value)) - background = x_alloc_image_color (f, img, value, background); - -#if 0 /* MAC_TODO : Port image display to Mac */ - BLOCK_INPUT; + { + background = x_alloc_image_color (f, img, value, background); + img->background = background; + img->background_valid = 1; + } + img->pixmap - = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f), - FRAME_W32_WINDOW (f), + = XCreatePixmapFromBitmapData (FRAME_MAC_DISPLAY (f), + FRAME_MAC_WINDOW (f), data, img->width, img->height, foreground, background, @@ -4868,22 +5679,33 @@ if (img->pixmap == 0) { x_clear_image (f, img); - image_error ("Unable to create X pixmap for `%s'", file, Qnil); + image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil); } else success_p = 1; - - UNBLOCK_INPUT; -#endif /* MAC_TODO */ } else image_error ("Error loading XBM image `%s'", img->spec, Qnil); - UNGCPRO; return success_p; } +/* Value is non-zero if DATA looks like an in-memory XBM file. */ + +static int +xbm_file_p (data) + Lisp_Object data; +{ + int w, h; + return (STRINGP (data) + && xbm_read_bitmap_data (SDATA (data), + (SDATA (data) + + SBYTES (data)), + &w, &h, NULL)); +} + + /* Fill image IMG which is used on frame F with pixmap data. Value is non-zero if successful. */ @@ -4900,7 +5722,32 @@ /* 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)) - success_p = xbm_load_image_from_file (f, img, file_name); + { + Lisp_Object file; + char *contents; + int size; + struct gcpro gcpro1; + + 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); + 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; + } else { struct image_keyword fmt[XBM_LAST]; @@ -4910,75 +5757,80 @@ unsigned long background = FRAME_BACKGROUND_PIXEL (f); char *bits; int parsed_p; - - /* Parse the list specification. */ + int in_memory_file_p = 0; + + /* See if data looks like an in-memory XBM file. */ + data = image_spec_value (img->spec, QCdata, NULL); + in_memory_file_p = xbm_file_p (data); + + /* Parse the image specification. */ bcopy (xbm_format, fmt, sizeof fmt); parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm); xassert (parsed_p); /* Get specified width, and height. */ - img->width = XFASTINT (fmt[XBM_WIDTH].value); - img->height = XFASTINT (fmt[XBM_HEIGHT].value); - xassert (img->width > 0 && img->height > 0); - - BLOCK_INPUT; - - if (fmt[XBM_ASCENT].count) - img->ascent = XFASTINT (fmt[XBM_ASCENT].value); + 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); + } /* Get foreground and background colors, maybe allocate colors. */ - if (fmt[XBM_FOREGROUND].count) + if (fmt[XBM_FOREGROUND].count + && STRINGP (fmt[XBM_FOREGROUND].value)) foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value, foreground); - if (fmt[XBM_BACKGROUND].count) + if (fmt[XBM_BACKGROUND].count + && STRINGP (fmt[XBM_BACKGROUND].value)) background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value, background); - /* Set bits to the bitmap image data. */ - data = fmt[XBM_DATA].value; - if (VECTORP (data)) + if (in_memory_file_p) + success_p = xbm_load_image (f, img, SDATA (data), + (SDATA (data) + + SBYTES (data))); + else { - int i; - char *p; - int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR; - - p = bits = (char *) alloca (nbytes * img->height); - for (i = 0; i < img->height; ++i, p += nbytes) + if (VECTORP (data)) { - Lisp_Object line = XVECTOR (data)->contents[i]; - if (STRINGP (line)) - bcopy (SDATA (line), p, nbytes); - else - bcopy (XBOOL_VECTOR (line)->data, p, nbytes); + int i; + char *p; + int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR; + + p = bits = (char *) alloca (nbytes * img->height); + for (i = 0; i < img->height; ++i, p += nbytes) + { + Lisp_Object line = XVECTOR (data)->contents[i]; + if (STRINGP (line)) + bcopy (SDATA (line), p, nbytes); + else + bcopy (XBOOL_VECTOR (line)->data, p, nbytes); + } + } + else if (STRINGP (data)) + bits = SDATA (data); + else + bits = XBOOL_VECTOR (data)->data; + + /* Create the pixmap. */ + depth = one_mac_display_info.n_planes; + img->pixmap + = XCreatePixmapFromBitmapData (FRAME_MAC_DISPLAY (f), + FRAME_MAC_WINDOW (f), + bits, + img->width, img->height, + foreground, background, + depth); + if (img->pixmap) + success_p = 1; + else + { + image_error ("Unable to create pixmap for XBM image `%s'", + img->spec, Qnil); + x_clear_image (f, img); } } - else if (STRINGP (data)) - bits = SDATA (data); - else - bits = XBOOL_VECTOR (data)->data; - -#if 0 /* MAC_TODO : port Mac display code */ - /* Create the pixmap. */ - depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f)); - img->pixmap - = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f), - FRAME_W32_WINDOW (f), - bits, - img->width, img->height, - foreground, background, - depth); -#endif /* MAC_TODO */ - - if (img->pixmap) - success_p = 1; - else - { - image_error ("Unable to create pixmap for XBM image `%s'", - img->spec, Qnil); - x_clear_image (f, img); - } - - UNBLOCK_INPUT; } return success_p; @@ -5014,7 +5866,9 @@ XPM_RELIEF, XPM_ALGORITHM, XPM_HEURISTIC_MASK, + XPM_MASK, XPM_COLOR_SYMBOLS, + XPM_BACKGROUND, XPM_LAST }; @@ -5026,12 +5880,14 @@ {":type", IMAGE_SYMBOL_VALUE, 1}, {":file", IMAGE_STRING_VALUE, 0}, {":data", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, + {":ascent", IMAGE_ASCENT_VALUE, 0}, {":margin", IMAGE_POSITIVE_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}, - {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0} + {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} }; /* Structure describing the image type XBM. */ @@ -5082,9 +5938,7 @@ /* Either no `:color-symbols' or it's a list of conses whose car and cdr are strings. */ && (fmt[XPM_COLOR_SYMBOLS].count == 0 - || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)) - && (fmt[XPM_ASCENT].count == 0 - || XFASTINT (fmt[XPM_ASCENT].value) < 100)); + || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))); } @@ -5096,7 +5950,7 @@ struct frame *f; struct image *img; { - int rc, i; + int rc; XpmAttributes attrs; Lisp_Object specified_file, color_symbols; @@ -5111,10 +5965,10 @@ #ifdef XpmAllocCloseColors attrs.alloc_close_colors = 1; attrs.valuemask |= XpmAllocCloseColors; -#else +#else /* not XpmAllocCloseColors */ attrs.closeness = 600; attrs.valuemask |= XpmCloseness; -#endif +#endif /* not XpmAllocCloseColors */ /* If image specification contains symbolic color definitions, add these to `attrs'. */ @@ -5154,7 +6008,7 @@ /* Create a pixmap for the image, either from a file, or from a string buffer containing data in the same format as an XPM file. */ - BLOCK_INPUT; + specified_file = image_spec_value (img->spec, QCfile, NULL); if (STRINGP (specified_file)) { @@ -5162,27 +6016,26 @@ if (!STRINGP (file)) { image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNBLOCK_INPUT; return 0; } - rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f), + rc = XpmReadFileToPixmap (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), SDATA (file), &img->pixmap, &img->mask, &attrs); } else { Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL); - rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f), + rc = XpmCreatePixmapFromBuffer (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), SDATA (buffer), &img->pixmap, &img->mask, &attrs); } - UNBLOCK_INPUT; if (rc == XpmSuccess) { - /* Remember allocated colors. */ + int i; + img->ncolors = attrs.nalloc_pixels; img->colors = (unsigned long *) xmalloc (img->ncolors * sizeof *img->colors); @@ -5194,9 +6047,7 @@ xassert (img->width > 0 && img->height > 0); /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */ - BLOCK_INPUT; XpmFreeAttributes (&attrs); - UNBLOCK_INPUT; } else { @@ -5262,15 +6113,6 @@ int ct_colors_allocated; -/* Function prototypes. */ - -static void init_color_table P_ ((void)); -static void free_color_table P_ ((void)); -static unsigned long *colors_in_color_table P_ ((int *n)); -static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b)); -static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p)); - - /* Initialize the color table. */ static void @@ -5422,6 +6264,17 @@ return colors; } +#else +static unsigned long +lookup_rgb_color (f, r, g, b) + struct frame *f; + int r, g, b; +{ + unsigned long pixel = RGB_TO_ULONG (r >> 8, g >> 8, b >> 8); + + gamma_correct (f, &pixel); + return pixel; +} #endif /* MAC_TODO */ @@ -5429,151 +6282,333 @@ Algorithms ***********************************************************************/ -#if 0 /* MAC_TODO : Mac versions of low level algorithms */ -static void x_laplace_write_row P_ ((struct frame *, long *, - int, XImage *, int)); -static void x_laplace_read_row P_ ((struct frame *, Colormap, - XColor *, int, XImage *, int)); - - -/* Fill COLORS with RGB colors from row Y of image XIMG. F is the - frame we operate on, CMAP is the color-map in effect, and WIDTH is - the width of one row in the image. */ +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)); + +/* Non-zero means draw a cross on images having `:conversion + disabled'. */ + +int cross_disabled_images; + +/* Edge detection matrices for different edge-detection + strategies. */ + +static int emboss_matrix[9] = { + /* x - 1 x x + 1 */ + 2, -1, 0, /* y - 1 */ + -1, 0, 1, /* y */ + 0, 1, -2 /* y + 1 */ +}; + +static int laplace_matrix[9] = { + /* x - 1 x x + 1 */ + 1, 0, 0, /* y - 1 */ + 0, 0, 0, /* y */ + 0, 0, -1 /* y + 1 */ +}; + +/* Value is the intensity of the color whose red/green/blue values + are R, G, and B. */ + +#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6) + + +/* On frame F, return an array of XColor structures describing image + IMG->pixmap. Each XColor structure has its pixel color set. RGB_P + non-zero means also fill the red/green/blue members of the XColor + structures. Value is a pointer to the array of XColors structures, + 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; +{ + int x, y; + XColor *colors, *p; + XImagePtr ximg; + + colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors); + + /* Get the X image IMG->pixmap. */ + ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap, + 0, 0, img->width, img->height, ~0, ZPixmap); + + /* Fill the `pixel' members of the XColor array. I wished there + were an easy and portable way to circumvent XGetPixel. */ + p = colors; + for (y = 0; y < img->height; ++y) + { + XColor *row = p; + + for (x = 0; x < img->width; ++x, ++p) + { + p->pixel = XGetPixel (ximg, x, y); + + if (rgb_p) + { + p->red = RED16_FROM_ULONG (p->pixel); + p->green = GREEN16_FROM_ULONG (p->pixel); + p->blue = BLUE16_FROM_ULONG (p->pixel); + } + } + } + + XDestroyImage (ximg); + return colors; +} + + +/* Create IMG->pixmap from an array COLORS of XColor structures, whose + RGB members are set. F is the frame on which this all happens. + COLORS will be freed; an existing IMG->pixmap will be freed, too. */ static void -x_laplace_read_row (f, cmap, colors, width, ximg, y) +x_from_xcolors (f, img, colors) struct frame *f; - Colormap cmap; + struct image *img; XColor *colors; - int width; - XImage *ximg; - int y; -{ - int x; - - for (x = 0; x < width; ++x) - colors[x].pixel = XGetPixel (ximg, x, y); - - XQueryColors (NULL, cmap, colors, width); -} - - -/* Write row Y of image XIMG. PIXELS is an array of WIDTH longs - containing the pixel colors to write. F is the frame we are - working on. */ +{ + int x, y; + XImagePtr oimg; + Pixmap pixmap; + XColor *p; + +#if 0 /* TODO: color tables. */ + init_color_table (); +#endif + + x_create_x_image_and_pixmap (f, img->width, img->height, 0, + &oimg, &pixmap); + p = colors; + for (y = 0; y < img->height; ++y) + for (x = 0; x < img->width; ++x, ++p) + { + unsigned long pixel; + pixel = lookup_rgb_color (f, p->red, p->green, p->blue); + XPutPixel (oimg, x, y, pixel); + } + + 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; +#if 0 /* TODO: color tables. */ + img->colors = colors_in_color_table (&img->ncolors); + free_color_table (); +#endif +} + + +/* On frame F, perform edge-detection on image IMG. + + MATRIX is a nine-element array specifying the transformation + matrix. See emboss_matrix for an example. + + COLOR_ADJUST is a color adjustment added to each pixel of the + outgoing image. */ static void -x_laplace_write_row (f, pixels, width, ximg, y) +x_detect_edges (f, img, matrix, color_adjust) struct frame *f; - long *pixels; - int width; - XImage *ximg; - int y; -{ - int x; - - for (x = 0; x < width; ++x) - XPutPixel (ximg, x, y, pixels[x]); -} -#endif /* MAC_TODO */ - -/* Transform image IMG which is used on frame F with a Laplace - edge-detection algorithm. The result is an image that can be used - to draw disabled buttons, for example. */ + struct image *img; + int matrix[9], color_adjust; +{ + XColor *colors = x_to_xcolors (f, img, 1); + XColor *new, *p; + int x, y, i, sum; + + for (i = sum = 0; i < 9; ++i) + sum += abs (matrix[i]); + +#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X)) + + new = (XColor *) xmalloc (img->width * img->height * sizeof *new); + + for (y = 0; y < img->height; ++y) + { + p = COLOR (new, 0, y); + p->red = p->green = p->blue = 0xffff/2; + p = COLOR (new, img->width - 1, y); + p->red = p->green = p->blue = 0xffff/2; + } + + for (x = 1; x < img->width - 1; ++x) + { + p = COLOR (new, x, 0); + p->red = p->green = p->blue = 0xffff/2; + p = COLOR (new, x, img->height - 1); + p->red = p->green = p->blue = 0xffff/2; + } + + for (y = 1; y < img->height - 1; ++y) + { + p = COLOR (new, 1, y); + + for (x = 1; x < img->width - 1; ++x, ++p) + { + int r, g, b, y1, x1; + + r = g = b = i = 0; + for (y1 = y - 1; y1 < y + 2; ++y1) + for (x1 = x - 1; x1 < x + 2; ++x1, ++i) + if (matrix[i]) + { + XColor *t = COLOR (colors, x1, y1); + r += matrix[i] * t->red; + g += matrix[i] * t->green; + b += matrix[i] * t->blue; + } + + r = (r / sum + color_adjust) & 0xffff; + g = (g / sum + color_adjust) & 0xffff; + b = (b / sum + color_adjust) & 0xffff; + p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b); + } + } + + xfree (colors); + x_from_xcolors (f, img, new); + +#undef COLOR +} + + +/* Perform the pre-defined `emboss' edge-detection on image IMG + on frame F. */ + +static void +x_emboss (f, img) + struct frame *f; + struct image *img; +{ + x_detect_edges (f, img, emboss_matrix, 0xffff / 2); +} + + +/* Perform the pre-defined `laplace' edge-detection on image IMG + on frame F. */ static void x_laplace (f, img) struct frame *f; struct image *img; { -#if 0 /* MAC_TODO : Mac version */ - Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); - XImage *ximg, *oimg; - XColor *in[3]; - long *out; - Pixmap pixmap; - int x, y, i; - long pixel; - int in_y, out_y, rc; - int mv2 = 45000; - - BLOCK_INPUT; - - /* Get the X image IMG->pixmap. */ - ximg = XGetImage (NULL, img->pixmap, - 0, 0, img->width, img->height, ~0, ZPixmap); - - /* Allocate 3 input rows, and one output row of colors. */ - for (i = 0; i < 3; ++i) - in[i] = (XColor *) alloca (img->width * sizeof (XColor)); - out = (long *) alloca (img->width * sizeof (long)); - - /* Create an X image for output. */ - rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0, - &oimg, &pixmap); - - /* Fill first two rows. */ - x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0); - x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1); - in_y = 2; - - /* Write first row, all zeros. */ - init_color_table (); - pixel = lookup_rgb_color (f, 0, 0, 0); - for (x = 0; x < img->width; ++x) - out[x] = pixel; - x_laplace_write_row (f, out, img->width, oimg, 0); - out_y = 1; - - for (y = 2; y < img->height; ++y) - { - int rowa = y % 3; - int rowb = (y + 2) % 3; - - x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++); - - for (x = 0; x < img->width - 2; ++x) + x_detect_edges (f, img, laplace_matrix, 45000); +} + + +/* Perform edge-detection on image IMG on frame F, with specified + transformation matrix MATRIX and color-adjustment COLOR_ADJUST. + + MATRIX must be either + + - a list of at least 9 numbers in row-major form + - a vector of at least 9 numbers + + COLOR_ADJUST nil means use a default; otherwise it must be a + number. */ + +static void +x_edge_detection (f, img, matrix, color_adjust) + struct frame *f; + struct image *img; + Lisp_Object matrix, color_adjust; +{ + int i = 0; + int trans[9]; + + if (CONSP (matrix)) + { + for (i = 0; + i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix)); + ++i, matrix = XCDR (matrix)) + trans[i] = XFLOATINT (XCAR (matrix)); + } + else if (VECTORP (matrix) && ASIZE (matrix) >= 9) + { + for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i) + trans[i] = XFLOATINT (AREF (matrix, i)); + } + + if (NILP (color_adjust)) + color_adjust = make_number (0xffff / 2); + + if (i == 9 && NUMBERP (color_adjust)) + x_detect_edges (f, img, trans, (int) 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; +{ + struct x_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + + if (dpyinfo->n_planes >= 2) + { + /* Color (or grayscale). Convert to gray, and equalize. Just + drawing such images with a stipple can look very odd, so + we're using this method instead. */ + XColor *colors = x_to_xcolors (f, img, 1); + XColor *p, *end; + const int h = 15000; + const int l = 30000; + + for (p = colors, end = colors + img->width * img->height; + p < end; + ++p) { - int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red; - int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green; - int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue; - - out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff, - b & 0xffff); + int i = COLOR_INTENSITY (p->red, p->green, p->blue); + int i2 = (0xffff - h - l) * i / 0xffff + l; + p->red = p->green = p->blue = i2; } - x_laplace_write_row (f, out, img->width, oimg, out_y++); - } - - /* Write last line, all zeros. */ - for (x = 0; x < img->width; ++x) - out[x] = pixel; - x_laplace_write_row (f, out, img->width, oimg, out_y); - - /* Free the input image, and free resources of IMG. */ - XDestroyImage (ximg); - x_clear_image (f, img); - - /* Put the output image into pixmap, and destroy it. */ - x_put_x_image (f, oimg, pixmap, img->width, img->height); - x_destroy_x_image (oimg); - - /* Remember new pixmap and colors in IMG. */ - img->pixmap = pixmap; - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); - - UNBLOCK_INPUT; -#endif /* MAC_TODO */ -} - - -/* Build a mask for image IMG which is used on frame F. FILE is the - name of an image file, for error messages. HOW determines how to - determine the background color of IMG. If it is a list '(R G B)', + x_from_xcolors (f, img, colors); + } + + /* Draw a cross over the disabled image, if we must or if we + should. */ + if (dpyinfo->n_planes < 2 || cross_disabled_images) + { + Display *dpy = FRAME_MAC_DISPLAY (f); + GC gc; + + gc = XCreateGC (dpy, NULL /*img->pixmap*/, 0, NULL); + XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f)); + mac_draw_line_to_pixmap (dpy, img->pixmap, gc, 0, 0, + img->width - 1, img->height - 1); + mac_draw_line_to_pixmap (dpy, img->pixmap, gc, 0, img->height - 1, + img->width - 1, 0); + XFreeGC (dpy, gc); + + if (img->mask) + { + gc = XCreateGC (dpy, NULL /*img->mask*/, 0, NULL); + XSetForeground (dpy, gc, PIX_MASK_DRAW (f)); + mac_draw_line_to_pixmap (dpy, img->mask, gc, 0, 0, + img->width - 1, img->height - 1); + mac_draw_line_to_pixmap (dpy, img->mask, gc, 0, img->height - 1, + img->width - 1, 0); + XFreeGC (dpy, gc); + } + } +} + + +/* Build a mask for image IMG which is used on frame F. FILE is the + name of an image file, for error messages. HOW determines how to + determine the background color of IMG. If it is a list '(R G B)', with R, G, and B being integers >= 0, take that as the color of the - background. Otherwise, determine the background color of IMG - heuristically. Value is non-zero if successful. */ + background. Otherwise, determine the background color of IMG + heuristically. Value is non-zero if successful. */ static int x_build_heuristic_mask (f, img, how) @@ -5581,39 +6616,37 @@ struct image *img; Lisp_Object how; { -#if 0 /* MAC_TODO : Mac version */ - Display *dpy = FRAME_W32_DISPLAY (f); - XImage *ximg, *mask_img; - int x, y, rc, look_at_corners_p; - unsigned long bg; - - BLOCK_INPUT; + Display *dpy = FRAME_X_DISPLAY (f); + XImagePtr ximg, mask_img; + int x, y, rc, use_img_background; + unsigned long bg = 0; + + if (img->mask) + { + XFreePixmap (FRAME_X_DISPLAY (f), img->mask); + img->mask = 0; + img->background_transparent_valid = 0; + } /* 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); if (!rc) - { - UNBLOCK_INPUT; - return 0; - } + return 0; /* Get the X image of IMG->pixmap. */ ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height, ~0, ZPixmap); /* Determine the background color of ximg. If HOW is `(R G B)' - take that as color. Otherwise, try to determine the color - heuristically. */ - look_at_corners_p = 1; + take that as color. Otherwise, use the image's background color. */ + use_img_background = 1; if (CONSP (how)) { - int rgb[3], i = 0; - - while (i < 3 - && CONSP (how) - && NATNUMP (XCAR (how))) + int rgb[3], i; + + for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i) { rgb[i] = XFASTINT (XCAR (how)) & 0xffff; how = XCDR (how); @@ -5622,59 +6655,29 @@ if (i == 3 && NILP (how)) { char color_name[30]; - XColor exact, color; - Colormap cmap; - sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]); - - cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); - if (XLookupColor (dpy, cmap, color_name, &exact, &color)) - { - bg = color.pixel; - look_at_corners_p = 0; - } + bg = x_alloc_image_color (f, img, build_string (color_name), 0); + use_img_background = 0; } } - if (look_at_corners_p) - { - unsigned long corners[4]; - int i, best_count; - - /* Get the colors at the corners of ximg. */ - corners[0] = XGetPixel (ximg, 0, 0); - corners[1] = XGetPixel (ximg, img->width - 1, 0); - corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1); - corners[3] = XGetPixel (ximg, 0, img->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]) - ++n; - - if (n > best_count) - bg = corners[i], best_count = n; - } - } + if (use_img_background) + bg = four_corners_best (ximg, img->width, img->height); /* Set all bits in mask_img to 1 whose color in ximg is different from the background color bg. */ for (y = 0; y < img->height; ++y) for (x = 0; x < img->width; ++x) - XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg); + XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f)); + + /* 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); XDestroyImage (ximg); - UNBLOCK_INPUT; -#endif /* MAC_TODO */ - return 1; } @@ -5683,7 +6686,6 @@ /*********************************************************************** PBM (mono, gray, color) ***********************************************************************/ -#ifdef HAVE_PBM static int pbm_image_p P_ ((Lisp_Object object)); static int pbm_load P_ ((struct frame *f, struct image *img)); @@ -5705,6 +6707,9 @@ PBM_RELIEF, PBM_ALGORITHM, PBM_HEURISTIC_MASK, + PBM_MASK, + PBM_FOREGROUND, + PBM_BACKGROUND, PBM_LAST }; @@ -5716,11 +6721,14 @@ {":type", IMAGE_SYMBOL_VALUE, 1}, {":file", IMAGE_STRING_VALUE, 0}, {":data", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, + {":ascent", IMAGE_ASCENT_VALUE, 0}, {":margin", IMAGE_POSITIVE_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} + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} }; /* Structure describing the image type `pbm'. */ @@ -5745,9 +6753,7 @@ bcopy (pbm_format, fmt, sizeof fmt); - if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm) - || (fmt[PBM_ASCENT].count - && XFASTINT (fmt[PBM_ASCENT].value) > 100)) + if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)) return 0; /* Must specify either :data or :file. */ @@ -5763,7 +6769,7 @@ pbm_scan_number (s, end) unsigned char **s, *end; { - int c, val = -1; + int c = 0, val = -1; while (*s < end) { @@ -5793,42 +6799,6 @@ } -/* Read FILE into memory. Value is a pointer to a buffer allocated - with xmalloc holding FILE's contents. Value is null if an error - occurred. *SIZE is set to the size of the file. */ - -static char * -pbm_read_file (file, size) - Lisp_Object file; - int *size; -{ - FILE *fp = NULL; - char *buf = NULL; - struct stat st; - - if (stat (SDATA (file), &st) == 0 - && (fp = fopen (SDATA (file), "r")) != NULL - && (buf = (char *) xmalloc (st.st_size), - fread (buf, 1, st.st_size, fp) == st.st_size)) - { - *size = st.st_size; - fclose (fp); - } - else - { - if (fp) - fclose (fp); - if (buf) - { - xfree (buf); - buf = NULL; - } - } - - return buf; -} - - /* Load PBM image IMG for use on frame F. */ static int @@ -5838,7 +6808,7 @@ { int raw_p, x, y; int width, height, max_color_idx = 0; - XImage *ximg; + XImagePtr ximg; Lisp_Object file, specified_file; enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type; struct gcpro gcpro1; @@ -5854,13 +6824,13 @@ { file = x_find_image_file (specified_file); if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNGCPRO; - return 0; - } - - contents = pbm_read_file (file, &size); + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + UNGCPRO; + return 0; + } + + contents = slurp_file (SDATA (file), &size); if (contents == NULL) { image_error ("Error reading `%s'", file, Qnil); @@ -5937,20 +6907,37 @@ || (type != PBM_MONO && max_color_idx < 0)) goto error; - BLOCK_INPUT; if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) - { - UNBLOCK_INPUT; - goto error; - } - + goto error; + +#if 0 /* TODO: color tables. */ /* Initialize the color hash table. */ init_color_table (); +#endif if (type == PBM_MONO) { int c = 0, g; + struct image_keyword fmt[PBM_LAST]; + unsigned long fg = FRAME_FOREGROUND_PIXEL (f); + unsigned long bg = FRAME_BACKGROUND_PIXEL (f); + + /* Parse the image specification. */ + bcopy (pbm_format, fmt, sizeof fmt); + parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm); + + /* Get foreground and background colors, maybe allocate colors. */ + if (fmt[PBM_FOREGROUND].count + && STRINGP (fmt[PBM_FOREGROUND].value)) + fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg); + if (fmt[PBM_BACKGROUND].count + && STRINGP (fmt[PBM_BACKGROUND].value)) + { + bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg); + img->background = bg; + img->background_valid = 1; + } for (y = 0; y < height; ++y) for (x = 0; x < width; ++x) @@ -5965,9 +6952,7 @@ else g = pbm_scan_number (&p, end); - XPutPixel (ximg, x, y, (g - ? FRAME_FOREGROUND_PIXEL (f) - : FRAME_BACKGROUND_PIXEL (f))); + XPutPixel (ximg, x, y, g ? fg : bg); } } else @@ -5994,13 +6979,10 @@ if (r < 0 || g < 0 || b < 0) { - xfree (ximg->data); - ximg->data = NULL; - XDestroyImage (ximg); - UNBLOCK_INPUT; + x_destroy_x_image (ximg); image_error ("Invalid pixel value in image `%s'", img->spec, Qnil); - goto error; + goto error; } /* RGB values are now in the range 0..max_color_idx. @@ -6012,33 +6994,35 @@ } } +#if 0 /* TODO: color tables. */ /* Store in IMG->colors the colors allocated for the image, and free the color table. */ img->colors = colors_in_color_table (&img->ncolors); free_color_table (); +#endif + + 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); /* Put the image into a pixmap. */ x_put_x_image (f, ximg, img->pixmap, width, height); x_destroy_x_image (ximg); - UNBLOCK_INPUT; - - img->width = width; - img->height = height; UNGCPRO; xfree (contents); return 1; } -#endif /* HAVE_PBM */ + /*********************************************************************** PNG ***********************************************************************/ -#if HAVE_PNG - -#include <png.h> /* Function prototypes. */ @@ -6061,6 +7045,8 @@ PNG_RELIEF, PNG_ALGORITHM, PNG_HEURISTIC_MASK, + PNG_MASK, + PNG_BACKGROUND, PNG_LAST }; @@ -6072,11 +7058,13 @@ {":type", IMAGE_SYMBOL_VALUE, 1}, {":data", IMAGE_STRING_VALUE, 0}, {":file", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, + {":ascent", IMAGE_ASCENT_VALUE, 0}, {":margin", IMAGE_POSITIVE_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} + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} }; /* Structure describing the image type `png'. */ @@ -6100,9 +7088,7 @@ struct image_keyword fmt[PNG_LAST]; bcopy (png_format, fmt, sizeof fmt); - if (!parse_image_spec (object, fmt, PNG_LAST, Qpng) - || (fmt[PNG_ASCENT].count - && XFASTINT (fmt[PNG_ASCENT].value) > 100)) + if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)) return 0; /* Must specify either the :data or :file keyword. */ @@ -6110,6 +7096,27 @@ } +#ifndef HAVE_PNG +static int +png_load (f, img) + struct frame *f; + struct image *img; +{ +#ifdef MAC_OSX + if (MyCGImageCreateWithPNGDataProvider) + return image_load_quartz2d (f, img, 1); + else +#endif + return image_load_quicktime (f, img, kQTFileTypePNG); +} +#else + +#if defined HAVE_LIBPNG_PNG_H +# include <libpng/png.h> +#else +# include <png.h> +#endif + /* Error and warning handlers installed when the PNG library is initialized. */ @@ -6174,22 +7181,20 @@ Lisp_Object file, specified_file; Lisp_Object specified_data; int x, y, i; - XImage *ximg, *mask_img = NULL; + XImagePtr ximg, mask_img = NULL; struct gcpro gcpro1; png_struct *png_ptr = NULL; png_info *info_ptr = NULL, *end_info = NULL; - FILE *fp = NULL; + FILE *volatile fp = NULL; png_byte sig[8]; - png_byte *pixels = NULL; - png_byte **rows = NULL; + png_byte * volatile pixels = NULL; + png_byte ** volatile rows = NULL; png_uint_32 width, height; int bit_depth, color_type, interlace_type; png_byte channels; png_uint_32 row_bytes; int transparent_p; - char *gamma_str; - double screen_gamma, image_gamma; - int intent; + double screen_gamma; struct png_memory_storage tbr; /* Data to be read */ /* Find out what file to load. */ @@ -6202,31 +7207,31 @@ { file = x_find_image_file (specified_file); if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNGCPRO; - return 0; - } + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + UNGCPRO; + return 0; + } /* Open the image file. */ fp = fopen (SDATA (file), "rb"); if (!fp) - { - image_error ("Cannot open image file `%s'", file, Qnil); - UNGCPRO; - fclose (fp); - return 0; - } + { + image_error ("Cannot open image file `%s'", file, Qnil); + UNGCPRO; + fclose (fp); + return 0; + } /* Check PNG signature. */ if (fread (sig, 1, sizeof sig, fp) != sizeof sig - || !png_check_sig (sig, sizeof sig)) - { - image_error ("Not a PNG file:` %s'", file, Qnil); - UNGCPRO; - fclose (fp); - return 0; - } + || !png_check_sig (sig, sizeof sig)) + { + image_error ("Not a PNG file: `%s'", file, Qnil); + UNGCPRO; + fclose (fp); + return 0; + } } else { @@ -6325,56 +7330,76 @@ || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb (png_ptr); - /* The value 2.2 is a guess for PC monitors from PNG example.c. */ - gamma_str = getenv ("SCREEN_GAMMA"); - screen_gamma = gamma_str ? atof (gamma_str) : 2.2; - - /* Tell the PNG lib to handle gamma correction for us. */ - + screen_gamma = (f->gamma ? 1 / f->gamma / 0.45455 : 2.2); + +#if 0 /* Avoid double gamma correction for PNG images. */ + { /* Tell the PNG lib to handle gamma correction for us. */ + int intent; + double image_gamma; #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED) - if (png_get_sRGB (png_ptr, info_ptr, &intent)) - /* There is a special chunk in the image specifying the gamma. */ - png_set_sRGB (png_ptr, info_ptr, intent); - else + if (png_get_sRGB (png_ptr, info_ptr, &intent)) + /* The libpng documentation says this is right in this case. */ + png_set_gamma (png_ptr, screen_gamma, 0.45455); + else #endif - if (png_get_gAMA (png_ptr, info_ptr, &image_gamma)) - /* Image contains gamma information. */ - png_set_gamma (png_ptr, screen_gamma, image_gamma); - else - /* Use a default of 0.5 for the image gamma. */ - png_set_gamma (png_ptr, screen_gamma, 0.5); + if (png_get_gAMA (png_ptr, info_ptr, &image_gamma)) + /* Image contains gamma information. */ + png_set_gamma (png_ptr, screen_gamma, image_gamma); + else + /* Use the standard default for the image gamma. */ + png_set_gamma (png_ptr, screen_gamma, 0.45455); + } +#endif /* if 0 */ /* Handle alpha channel by combining the image with a background color. Do this only if a real alpha channel is supplied. For simple transparency, we prefer a clipping mask. */ if (!transparent_p) { - png_color_16 *image_background; - - if (png_get_bKGD (png_ptr, info_ptr, &image_background)) + png_color_16 *image_bg; + Lisp_Object specified_bg + = image_spec_value (img->spec, QCbackground, NULL); + + if (STRINGP (specified_bg)) + /* The user specified `:background', use that. */ + { + XColor color; + if (mac_defined_color (f, SDATA (specified_bg), &color, 0)) + { + png_color_16 user_bg; + + bzero (&user_bg, sizeof user_bg); + user_bg.red = color.red >> 8; + user_bg.green = color.green >> 8; + user_bg.blue = color.blue >> 8; + + png_set_background (png_ptr, &user_bg, + PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); + } + } + else if (png_get_bKGD (png_ptr, info_ptr, &image_bg)) /* Image contains a background color with which to combine the image. */ - png_set_background (png_ptr, image_background, + png_set_background (png_ptr, image_bg, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); else { /* Image does not contain a background color with which to combine the image data via an alpha channel. Use the frame's background instead. */ - XColor color; - Colormap cmap; + unsigned long color; png_color_16 frame_background; - - BLOCK_INPUT; - cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); - color.pixel = FRAME_BACKGROUND_PIXEL (f); - XQueryColor (FRAME_W32_DISPLAY (f), cmap, &color); - UNBLOCK_INPUT; - + color = FRAME_BACKGROUND_PIXEL (f); +#if 0 /* TODO : Colormap support. */ + Colormap cmap; + + cmap = FRAME_X_COLORMAP (f); + x_query_color (f, &color); +#endif bzero (&frame_background, sizeof frame_background); - frame_background.red = color.red; - frame_background.green = color.green; - frame_background.blue = color.blue; + frame_background.red = RED_FROM_ULONG (color); + frame_background.green = GREEN_FROM_ULONG (color); + frame_background.blue = BLUE_FROM_ULONG (color); png_set_background (png_ptr, &frame_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); @@ -6410,15 +7435,10 @@ fp = NULL; } - BLOCK_INPUT; - /* Create the X image and pixmap. */ if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) - { - UNBLOCK_INPUT; - goto error; - } + goto error; /* Create an image and pixmap serving as mask if the PNG image contains an alpha channel. */ @@ -6428,14 +7448,15 @@ &mask_img, &img->mask)) { x_destroy_x_image (ximg); - XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap); - img->pixmap = 0; - UNBLOCK_INPUT; + XFreePixmap (FRAME_MAC_DISPLAY (f), img->pixmap); + img->pixmap = NULL; goto error; } /* Fill the X image and mask from PNG data. */ +#if 0 /* TODO: Color tables. */ init_color_table (); +#endif for (y = 0; y < height; ++y) { @@ -6469,15 +7490,29 @@ if (channels == 4) { if (mask_img) - XPutPixel (mask_img, x, y, *p > 0); + XPutPixel (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f)); ++p; } } } + if (NILP (image_spec_value (img->spec, QCbackground, NULL))) + /* Set IMG's background color from the PNG image, unless the user + overrode it. */ + { + png_color_16 *bg; + if (png_get_bKGD (png_ptr, info_ptr, &bg)) + { + img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue); + img->background_valid = 1; + } + } + +#if 0 /* TODO: Color tables. */ /* Remember colors allocated for this image. */ img->colors = colors_in_color_table (&img->ncolors); free_color_table (); +#endif /* Clean up. */ png_destroy_read_struct (&png_ptr, &info_ptr, &end_info); @@ -6487,6 +7522,9 @@ img->width = width; img->height = height; + /* Maybe fill in the background field while we have ximg handy. */ + IMAGE_BACKGROUND (img, f, 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); @@ -6494,16 +7532,19 @@ /* Same for the mask. */ if (mask_img) { + /* 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, img->width, img->height); x_destroy_x_image (mask_img); } - UNBLOCK_INPUT; UNGCPRO; return 1; } -#endif /* HAVE_PNG != 0 */ +#endif /* HAVE_PNG */ @@ -6511,23 +7552,6 @@ JPEG ***********************************************************************/ -#if HAVE_JPEG - -/* 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 */ - -#include <jpeglib.h> -#include <jerror.h> -#include <setjmp.h> - -#ifdef HAVE_STLIB_H_1 -#define HAVE_STDLIB_H 1 -#endif - static int jpeg_image_p P_ ((Lisp_Object object)); static int jpeg_load P_ ((struct frame *f, struct image *img)); @@ -6547,6 +7571,8 @@ JPEG_RELIEF, JPEG_ALGORITHM, JPEG_HEURISTIC_MASK, + JPEG_MASK, + JPEG_BACKGROUND, JPEG_LAST }; @@ -6558,11 +7584,13 @@ {":type", IMAGE_SYMBOL_VALUE, 1}, {":data", IMAGE_STRING_VALUE, 0}, {":file", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, + {":ascent", IMAGE_ASCENT_VALUE, 0}, {":margin", IMAGE_POSITIVE_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} + {":conversions", 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} }; /* Structure describing the image type `jpeg'. */ @@ -6587,9 +7615,7 @@ bcopy (jpeg_format, fmt, sizeof fmt); - if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg) - || (fmt[JPEG_ASCENT].count - && XFASTINT (fmt[JPEG_ASCENT].value) > 100)) + if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)) return 0; /* Must specify either the :data or :file keyword. */ @@ -6597,12 +7623,42 @@ } +#ifndef HAVE_JPEG +static int +jpeg_load (f, img) + struct frame *f; + struct image *img; +{ +#ifdef MAC_OSX + return image_load_quartz2d (f, img, 0); +#else + return image_load_quicktime (f, img, kQTFileTypeJPEG); +#endif +} +#else + +/* 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 */ + +#include <jpeglib.h> +#include <jerror.h> +#include <setjmp.h> + +#ifdef HAVE_STLIB_H_1 +#define HAVE_STDLIB_H 1 +#endif + struct my_jpeg_error_mgr { struct jpeg_error_mgr pub; jmp_buf setjmp_buffer; }; + static void my_error_exit (cinfo) j_common_ptr cinfo; @@ -6611,6 +7667,7 @@ longjmp (mgr->setjmp_buffer, 1); } + /* Init source method for JPEG data source manager. Called by jpeg_read_header() before any data is actually read. See libjpeg.doc from the JPEG lib distribution. */ @@ -6719,10 +7776,10 @@ struct my_jpeg_error_mgr mgr; Lisp_Object file, specified_file; Lisp_Object specified_data; - FILE *fp = NULL; + FILE * volatile fp = NULL; JSAMPARRAY buffer; int row_stride, x, y; - XImage *ximg = NULL; + XImagePtr ximg = NULL; int rc; unsigned long *colors; int width, height; @@ -6738,25 +7795,25 @@ { file = x_find_image_file (specified_file); if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNGCPRO; - return 0; - } + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + UNGCPRO; + return 0; + } fp = fopen (SDATA (file), "r"); if (fp == NULL) - { - image_error ("Cannot open `%s'", file, Qnil); - UNGCPRO; - return 0; - } + { + image_error ("Cannot open `%s'", file, Qnil); + UNGCPRO; + return 0; + } } /* Customize libjpeg's error handling to call my_error_exit when an - error is detected. This function will perform a longjmp. */ + error is detected. This function will perform a longjmp. */ + cinfo.err = jpeg_std_error (&mgr.pub); mgr.pub.error_exit = my_error_exit; - cinfo.err = jpeg_std_error (&mgr.pub); if ((rc = setjmp (mgr.setjmp_buffer)) != 0) { @@ -6771,28 +7828,25 @@ /* Close the input file and destroy the JPEG object. */ if (fp) - fclose (fp); + fclose ((FILE *) fp); jpeg_destroy_decompress (&cinfo); - BLOCK_INPUT; - /* If we already have an XImage, free that. */ x_destroy_x_image (ximg); /* Free pixmap and colors. */ x_clear_image (f, img); - UNBLOCK_INPUT; UNGCPRO; return 0; } /* Create the JPEG decompression object. Let it read from fp. - Read the JPEG image header. */ + Read the JPEG image header. */ jpeg_create_decompress (&cinfo); if (NILP (specified_data)) - jpeg_stdio_src (&cinfo, fp); + jpeg_stdio_src (&cinfo, (FILE *) fp); else jpeg_memory_src (&cinfo, SDATA (specified_data), SBYTES (specified_data)); @@ -6800,21 +7854,15 @@ jpeg_read_header (&cinfo, TRUE); /* Customize decompression so that color quantization will be used. - Start decompression. */ + Start decompression. */ cinfo.quantize_colors = TRUE; jpeg_start_decompress (&cinfo); width = img->width = cinfo.output_width; height = img->height = cinfo.output_height; - BLOCK_INPUT; - /* Create X image and pixmap. */ - if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, - &img->pixmap)) - { - UNBLOCK_INPUT; - longjmp (mgr.setjmp_buffer, 2); - } + if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) + longjmp (mgr.setjmp_buffer, 2); /* Allocate colors. When color quantization is used, cinfo.actual_number_of_colors has been set with the number of @@ -6831,11 +7879,13 @@ else ir = 0, ig = 0, ib = 0; +#if 0 /* TODO: Color tables. */ /* Use the color table mechanism because it handles colors that cannot be allocated nicely. Such colors will be replaced with a default color, and we don't have to care about which colors can be freed safely, and which can't. */ init_color_table (); +#endif colors = (unsigned long *) alloca (cinfo.actual_number_of_colors * sizeof *colors); @@ -6849,9 +7899,11 @@ colors[i] = lookup_rgb_color (f, r, g, b); } +#if 0 /* TODO: Color tables. */ /* Remember those colors actually allocated. */ img->colors = colors_in_color_table (&img->ncolors); free_color_table (); +#endif } /* Read pixels. */ @@ -6869,12 +7921,15 @@ jpeg_finish_decompress (&cinfo); jpeg_destroy_decompress (&cinfo); if (fp) - fclose (fp); + fclose ((FILE *) fp); + + /* 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); /* Put the image into the pixmap. */ x_put_x_image (f, ximg, img->pixmap, width, height); x_destroy_x_image (ximg); - UNBLOCK_INPUT; UNGCPRO; return 1; } @@ -6887,10 +7942,6 @@ TIFF ***********************************************************************/ -#if HAVE_TIFF - -#include <tiffio.h> - static int tiff_image_p P_ ((Lisp_Object object)); static int tiff_load P_ ((struct frame *f, struct image *img)); @@ -6910,6 +7961,8 @@ TIFF_RELIEF, TIFF_ALGORITHM, TIFF_HEURISTIC_MASK, + TIFF_MASK, + TIFF_BACKGROUND, TIFF_LAST }; @@ -6921,11 +7974,13 @@ {":type", IMAGE_SYMBOL_VALUE, 1}, {":data", IMAGE_STRING_VALUE, 0}, {":file", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, + {":ascent", IMAGE_ASCENT_VALUE, 0}, {":margin", IMAGE_POSITIVE_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} + {":conversions", 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} }; /* Structure describing the image type `tiff'. */ @@ -6949,15 +8004,26 @@ struct image_keyword fmt[TIFF_LAST]; bcopy (tiff_format, fmt, sizeof fmt); - if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff) - || (fmt[TIFF_ASCENT].count - && XFASTINT (fmt[TIFF_ASCENT].value) > 100)) + if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)) return 0; /* Must specify either the :data or :file keyword. */ return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1; } +#ifndef HAVE_TIFF + +static int +tiff_load (f, img) + struct frame *f; + struct image *img; +{ + return image_load_quicktime (f, img, kQTFileTypeTIFF); +} + +#else + +#include <tiffio.h> /* Reading from a memory buffer for TIFF images Based on the PNG memory source, but we have to provide a lot of extra functions. @@ -6976,6 +8042,7 @@ } tiff_memory_source; + static size_t tiff_read_from_memory (data, buf, size) thandle_t data; @@ -6991,6 +8058,7 @@ return size; } + static size_t tiff_write_from_memory (data, buf, size) thandle_t data; @@ -7000,6 +8068,7 @@ return (size_t) -1; } + static toff_t tiff_seek_in_memory (data, off, whence) thandle_t data; @@ -7023,7 +8092,7 @@ idx = src->index + off; break; - default: /* Invalid `whence'. */ + default: /* Invalid `whence'. */ return -1; } @@ -7034,6 +8103,7 @@ return src->index; } + static int tiff_close_memory (data) thandle_t data; @@ -7042,6 +8112,7 @@ return 0; } + static int tiff_mmap_memory (data, pbase, psize) thandle_t data; @@ -7052,6 +8123,7 @@ return 0; } + static void tiff_unmap_memory (data, base, size) thandle_t data; @@ -7061,6 +8133,7 @@ /* We don't need to do this. */ } + static toff_t tiff_size_of_memory (data) thandle_t data; @@ -7068,6 +8141,35 @@ return ((tiff_memory_source *) data)->len; } + +static void +tiff_error_handler (title, format, ap) + const char *title, *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); +} + + +static void +tiff_warning_handler (title, format, ap) + const char *title, *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); +} + + /* Load TIFF image IMG for use on frame F. Value is non-zero if successful. */ @@ -7082,7 +8184,7 @@ int width, height, x, y; uint32 *buf; int rc; - XImage *ximg; + XImagePtr ximg; struct gcpro gcpro1; tiff_memory_source memsrc; @@ -7091,25 +8193,28 @@ file = Qnil; GCPRO1 (file); + TIFFSetErrorHandler (tiff_error_handler); + TIFFSetWarningHandler (tiff_warning_handler); + if (NILP (specified_data)) { /* Read from a file */ file = x_find_image_file (specified_file); if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", file, Qnil); - UNGCPRO; - return 0; - } + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + UNGCPRO; + return 0; + } /* Try to open the image file. */ tiff = TIFFOpen (SDATA (file), "r"); if (tiff == NULL) - { - image_error ("Cannot open `%s'", file, Qnil); - UNGCPRO; - return 0; - } + { + image_error ("Cannot open `%s'", file, Qnil); + UNGCPRO; + return 0; + } } else { @@ -7151,19 +8256,18 @@ return 0; } - BLOCK_INPUT; - /* Create the X image and pixmap. */ if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) { - UNBLOCK_INPUT; xfree (buf); UNGCPRO; return 0; } +#if 0 /* TODO: Color tables. */ /* Initialize the color table. */ init_color_table (); +#endif /* Process the pixel raster. Origin is in the lower-left corner. */ for (y = 0; y < height; ++y) @@ -7180,24 +8284,29 @@ } } +#if 0 /* TODO: Color tables. */ /* Remember the colors allocated for the image. Free the color table. */ img->colors = colors_in_color_table (&img->ncolors); free_color_table (); +#endif + + 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); /* 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); xfree (buf); - UNBLOCK_INPUT; - - img->width = width; - img->height = height; UNGCPRO; return 1; } -#endif /* HAVE_TIFF != 0 */ +#endif /* HAVE_TIFF */ @@ -7205,10 +8314,6 @@ GIF ***********************************************************************/ -#if HAVE_GIF - -#include <gif_lib.h> - static int gif_image_p P_ ((Lisp_Object object)); static int gif_load P_ ((struct frame *f, struct image *img)); @@ -7228,7 +8333,9 @@ GIF_RELIEF, GIF_ALGORITHM, GIF_HEURISTIC_MASK, + GIF_MASK, GIF_IMAGE, + GIF_BACKGROUND, GIF_LAST }; @@ -7240,12 +8347,14 @@ {":type", IMAGE_SYMBOL_VALUE, 1}, {":data", IMAGE_STRING_VALUE, 0}, {":file", IMAGE_STRING_VALUE, 0}, - {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, + {":ascent", IMAGE_ASCENT_VALUE, 0}, {":margin", IMAGE_POSITIVE_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}, - {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0} + {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} }; /* Structure describing the image type `gif'. */ @@ -7259,6 +8368,7 @@ NULL }; + /* Return non-zero if OBJECT is a valid GIF image specification. */ static int @@ -7268,15 +8378,200 @@ struct image_keyword fmt[GIF_LAST]; bcopy (gif_format, fmt, sizeof fmt); - if (!parse_image_spec (object, fmt, GIF_LAST, Qgif) - || (fmt[GIF_ASCENT].count - && XFASTINT (fmt[GIF_ASCENT].value) > 100)) + if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)) return 0; /* Must specify either the :data or :file keyword. */ return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1; } +#ifndef HAVE_GIF + +static int +gif_load (f, img) + struct frame *f; + struct image *img; +{ + Lisp_Object specified_file, file; + Lisp_Object specified_data; + OSErr err; + Boolean graphic_p, movie_p, prefer_graphic_p; + Handle dh = NULL; + Movie movie = NULL; + Lisp_Object image; + Track track = NULL; + Media media = NULL; + long nsamples; + Rect rect; + Lisp_Object specified_bg; + XColor color; + RGBColor bg_color; + int width, height; + XImagePtr ximg; + TimeValue time; + struct gcpro gcpro1; + int ino; + + specified_file = image_spec_value (img->spec, QCfile, NULL); + specified_data = image_spec_value (img->spec, QCdata, NULL); + + if (NILP (specified_data)) + { + /* Read from a file */ + FSSpec fss; + short refnum; + + err = find_image_fsspec (specified_file, &file, &fss); + if (err != noErr) + { + if (err == fnfErr) + image_error ("Cannot find image file `%s'", specified_file, Qnil); + else + goto open_error; + } + + err = CanQuickTimeOpenFile (&fss, kQTFileTypeGIF, 0, + &graphic_p, &movie_p, &prefer_graphic_p, 0); + if (err != noErr) + goto open_error; + + if (!graphic_p && !movie_p) + goto open_error; + if (prefer_graphic_p) + return image_load_qt_1 (f, img, kQTFileTypeGIF, &fss, NULL); + err = OpenMovieFile (&fss, &refnum, fsRdPerm); + if (err != noErr) + goto open_error; + err = NewMovieFromFile (&movie, refnum, NULL, NULL, 0, NULL); + CloseMovieFile (refnum); + if (err != noErr) + { + image_error ("Error reading `%s'", file, Qnil); + return 0; + } + } + else + { + /* Memory source! */ + Handle dref = NULL; + long file_type_atom[3]; + + err = PtrToHand (SDATA (specified_data), &dh, SBYTES (specified_data)); + if (err != noErr) + { + image_error ("Cannot allocate data handle for `%s'", + img->spec, Qnil); + goto error; + } + + file_type_atom[0] = EndianU32_NtoB (sizeof (long) * 3); + file_type_atom[1] = EndianU32_NtoB (kDataRefExtensionMacOSFileType); + file_type_atom[2] = EndianU32_NtoB (kQTFileTypeGIF); + err = PtrToHand (&dh, &dref, sizeof (Handle)); + if (err == noErr) + /* no file name */ + err = PtrAndHand ("\p", dref, 1); + if (err == noErr) + err = PtrAndHand (file_type_atom, dref, sizeof (long) * 3); + if (err != noErr) + { + image_error ("Cannot allocate handle data ref for `%s'", img->spec, Qnil); + goto error; + } + err = CanQuickTimeOpenDataRef (dref, HandleDataHandlerSubType, &graphic_p, + &movie_p, &prefer_graphic_p, 0); + if (err != noErr) + goto open_error; + + if (!graphic_p && !movie_p) + goto open_error; + if (prefer_graphic_p) + { + int success_p; + + DisposeHandle (dref); + success_p = image_load_qt_1 (f, img, kQTFileTypeGIF, NULL, dh); + DisposeHandle (dh); + return success_p; + } + err = NewMovieFromDataRef (&movie, 0, NULL, dref, + HandleDataHandlerSubType); + DisposeHandle (dref); + if (err != noErr) + goto open_error; + } + + image = image_spec_value (img->spec, QCindex, NULL); + ino = INTEGERP (image) ? XFASTINT (image) : 0; + track = GetMovieIndTrack (movie, 1); + media = GetTrackMedia (track); + nsamples = GetMediaSampleCount (media); + if (ino >= nsamples) + { + image_error ("Invalid image number `%s' in image `%s'", + image, img->spec); + goto error; + } + + specified_bg = image_spec_value (img->spec, QCbackground, NULL); + if (!STRINGP (specified_bg) || + !mac_defined_color (f, SDATA (specified_bg), &color, 0)) + { + color.pixel = FRAME_BACKGROUND_PIXEL (f); + color.red = RED16_FROM_ULONG (color.pixel); + color.green = GREEN16_FROM_ULONG (color.pixel); + color.blue = BLUE16_FROM_ULONG (color.pixel); + } + GetMovieBox (movie, &rect); + width = img->width = rect.right - rect.left; + height = img->height = rect.bottom - rect.top; + if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) + goto error; + + SetGWorld (ximg, NULL); + bg_color.red = color.red; + bg_color.green = color.green; + bg_color.blue = color.blue; + RGBBackColor (&bg_color); + SetMovieActive (movie, TRUE); + SetMovieGWorld (movie, ximg, NULL); + SampleNumToMediaTime (media, ino + 1, &time, NULL); + SetMovieTimeValue (movie, time); + MoviesTask (movie, 0L); + DisposeTrackMedia (media); + DisposeMovieTrack (track); + DisposeMovie (movie); + if (dh) + DisposeHandle (dh); + /* 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); + + /* Put the image into the pixmap. */ + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + return 1; + + open_error: + image_error ("Cannot open `%s'", file, Qnil); + error: + if (media) + DisposeTrackMedia (media); + if (track) + DisposeMovieTrack (track); + if (movie) + DisposeMovie (movie); + if (dh) + DisposeHandle (dh); + return 0; +} + +#else + +#define DrawText gif_DrawText /* avoid conflict with QuickdrawText.h */ +#include <gif_lib.h> +#undef DrawText + /* Reading a GIF image from memory Based on the PNG memory stuff to a certain extent. */ @@ -7288,6 +8583,7 @@ } gif_memory_source; + /* Make the current memory source available to gif_read_from_memory. It's done this way because not all versions of libungif support a UserData field in the GifFileType structure. */ @@ -7321,7 +8617,7 @@ Lisp_Object file, specified_file; Lisp_Object specified_data; int rc, width, height, x, y, i; - XImage *ximg; + XImagePtr ximg; ColorMapObject *gif_color_map; unsigned long pixel_colors[256]; GifFileType *gif; @@ -7340,20 +8636,20 @@ { file = x_find_image_file (specified_file); if (!STRINGP (file)) - { - image_error ("Cannot find image file `%s'", specified_file, Qnil); - UNGCPRO; - return 0; - } + { + image_error ("Cannot find image file `%s'", specified_file, Qnil); + UNGCPRO; + return 0; + } /* Open the GIF file. */ gif = DGifOpenFileName (SDATA (file)); if (gif == NULL) - { - image_error ("Cannot open `%s'", file, Qnil); - UNGCPRO; - return 0; - } + { + image_error ("Cannot open `%s'", file, Qnil); + UNGCPRO; + return 0; + } } else { @@ -7363,7 +8659,7 @@ memsrc.len = SBYTES (specified_data); memsrc.index = 0; - gif = DGifOpen(&memsrc, gif_read_from_memory); + gif = DGifOpen (&memsrc, gif_read_from_memory); if (!gif) { image_error ("Cannot open memory source `%s'", img->spec, Qnil); @@ -7387,21 +8683,18 @@ if (ino >= gif->ImageCount) { image_error ("Invalid image number `%s' in image `%s'", - image, img->spec); + image, img->spec); DGifCloseFile (gif); UNGCPRO; return 0; } - width = img->width = gif->SWidth; - height = img->height = gif->SHeight; - - BLOCK_INPUT; + width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width); + height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height); /* Create the X image and pixmap. */ if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) { - UNBLOCK_INPUT; DGifCloseFile (gif); UNGCPRO; return 0; @@ -7411,7 +8704,9 @@ gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap; if (!gif_color_map) gif_color_map = gif->SColorMap; +#if 0 /* TODO: Color tables */ init_color_table (); +#endif bzero (pixel_colors, sizeof pixel_colors); for (i = 0; i < gif_color_map->ColorCount; ++i) @@ -7422,8 +8717,10 @@ pixel_colors[i] = lookup_rgb_color (f, r, g, b); } +#if 0 /* TODO: Color tables */ img->colors = colors_in_color_table (&img->ncolors); free_color_table (); +#endif /* Clear the part of the screen image that are not covered by the image from the GIF file. Full animated GIF support @@ -7460,7 +8757,7 @@ { static int interlace_start[] = {0, 4, 2, 1}; static int interlace_increment[] = {8, 8, 4, 2}; - int pass, inc; + int pass; int row = interlace_start[0]; pass = 0; @@ -7489,23 +8786,25 @@ for (y = 0; y < image_height; ++y) for (x = 0; x < image_width; ++x) { - int i = raster[y* image_width + x]; + int i = raster[y * image_width + x]; XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]); } } DGifCloseFile (gif); + /* 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); + /* 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); - UNBLOCK_INPUT; UNGCPRO; return 1; } - -#endif /* HAVE_GIF != 0 */ +#endif /* HAVE_GIF */ @@ -7513,11 +8812,6 @@ Ghostscript ***********************************************************************/ -#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)); - /* The symbol `postscript' identifying images of this type. */ Lisp_Object Qpostscript; @@ -7526,6 +8820,11 @@ Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height; +#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)); + /* Indices of image specification fields in gs_format, below. */ enum gs_keyword_index @@ -7541,6 +8840,8 @@ GS_RELIEF, GS_ALGORITHM, GS_HEURISTIC_MASK, + GS_MASK, + GS_BACKGROUND, GS_LAST }; @@ -7555,11 +8856,13 @@ {":file", IMAGE_STRING_VALUE, 1}, {":loader", IMAGE_FUNCTION_VALUE, 0}, {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1}, - {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}, + {":ascent", IMAGE_ASCENT_VALUE, 0}, {":margin", IMAGE_POSITIVE_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} + {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} }; /* Structure describing the image type `ghostscript'. */ @@ -7600,9 +8903,7 @@ bcopy (gs_format, fmt, sizeof fmt); - if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript) - || (fmt[GS_ASCENT].count - && XFASTINT (fmt[GS_ASCENT].value) > 100)) + if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)) return 0; /* Bounding box must be a list or vector containing 4 integers. */ @@ -7651,18 +8952,16 @@ info. */ pt_width = image_spec_value (img->spec, QCpt_width, NULL); in_width = XFASTINT (pt_width) / 72.0; - img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx; + img->width = in_width * FRAME_MAC_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_W32_DISPLAY_INFO (f)->resy; + img->height = in_height * FRAME_MAC_DISPLAY_INFO (f)->resy; /* Create the pixmap. */ - BLOCK_INPUT; - xassert (img->pixmap == 0); - img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), + xassert (img->pixmap == NULL); + img->pixmap = XCreatePixmap (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), img->width, img->height, - DefaultDepthOfScreen (FRAME_X_SCREEN (f))); - UNBLOCK_INPUT; + one_mac_display_info.n_planes); if (!img->pixmap) { @@ -7677,7 +8976,7 @@ GCPRO2 (window_and_pixmap_id, pixel_colors); sprintf (buffer, "%lu %lu", - (unsigned long) FRAME_W32_WINDOW (f), + (unsigned long) FRAME_MAC_WINDOW (f), (unsigned long) img->pixmap); window_and_pixmap_id = build_string (buffer); @@ -7719,26 +9018,31 @@ if (c->images[i]->pixmap == pixmap) break; + /* Should someone in between have cleared the image cache, for + instance, give up. */ + if (i == c->used) + return; + /* Kill the GS process. We should have found PIXMAP in the image cache and its image should contain a process object. */ - xassert (i < c->used); img = c->images[i]; xassert (PROCESSP (img->data.lisp_val)); Fkill_process (img->data.lisp_val, Qnil); img->data.lisp_val = Qnil; +#if 0 /* On displays with a mutable colormap, figure out the colors allocated for the image by looking at the pixels of an XImage for img->pixmap. */ - class = FRAME_W32_DISPLAY_INFO (f)->visual->class; + class = FRAME_MAC_DISPLAY_INFO (f)->visual->class; if (class != StaticColor && class != StaticGray && class != TrueColor) { - XImage *ximg; + XImagePtr ximg; BLOCK_INPUT; /* Try to get an XImage for img->pixmep. */ - ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap, + ximg = XGetImage (FRAME_MAC_DISPLAY (f), img->pixmap, 0, 0, img->width, img->height, ~0, ZPixmap); if (ximg) { @@ -7769,11 +9073,7 @@ allocated colors on behalf of us. So, to get the reference counts right, free them once. */ if (img->ncolors) - { - Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f)); - XFreeColors (FRAME_W32_DISPLAY (f), cmap, - img->colors, img->ncolors, 0); - } + x_free_colors (f, img->colors, img->ncolors); #endif } else @@ -7782,6 +9082,13 @@ UNBLOCK_INPUT; } +#endif + + /* Now that we have the pixmap, compute mask and transform the + image if requested. */ + BLOCK_INPUT; + postprocess_image (f, img); + UNBLOCK_INPUT; } #endif /* HAVE_GHOSTSCRIPT */ @@ -8806,6 +10113,18 @@ Qlaplace = intern ("laplace"); staticpro (&Qlaplace); + Qemboss = intern ("emboss"); + staticpro (&Qemboss); + Qedge_detection = intern ("edge-detection"); + staticpro (&Qedge_detection); + Qheuristic = intern ("heuristic"); + staticpro (&Qheuristic); + QCmatrix = intern (":matrix"); + staticpro (&QCmatrix); + QCcolor_adjustment = intern (":color-adjustment"); + staticpro (&QCcolor_adjustment); + QCmask = intern (":mask"); + staticpro (&QCmask); Qface_set_after_frame_default = intern ("face-set-after-frame-default"); staticpro (&Qface_set_after_frame_default); @@ -8815,6 +10134,12 @@ Fput (Qundefined_color, Qerror_message, build_string ("Undefined color")); + DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images, + doc: /* Non-nil means always draw a cross over disabled images. +Disabled images are those having an `: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, doc: /* List of directories to search for window system bitmap files. */); Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH"); @@ -8880,9 +10205,11 @@ meaning don't clear the cache. */); Vimage_cache_eviction_delay = make_number (30 * 60); + /* X window properties. */ defsubr (&Sx_change_window_property); defsubr (&Sx_delete_window_property); defsubr (&Sx_window_property); + defsubr (&Sxw_display_color_p); defsubr (&Sx_display_grayscale_p); defsubr (&Sxw_color_defined_p); @@ -8919,15 +10246,12 @@ load_font_func = x_load_font; find_ccl_program_func = x_find_ccl_program; query_font_func = x_query_font; - set_frame_fontset_func = x_set_font; check_window_system_func = check_mac; -#if 0 /* MAC_TODO: Image support for Mac Images. */ + /* Images. */ Qxbm = intern ("xbm"); staticpro (&Qxbm); - QCtype = intern (":type"); - staticpro (&QCtype); QCconversion = intern (":conversion"); staticpro (&QCconversion); QCheuristic_mask = intern (":heuristic-mask"); @@ -8960,41 +10284,36 @@ staticpro (&Qxpm); #endif -#if HAVE_JPEG Qjpeg = intern ("jpeg"); staticpro (&Qjpeg); -#endif - -#if HAVE_TIFF + Qtiff = intern ("tiff"); staticpro (&Qtiff); -#endif - -#if HAVE_GIF + Qgif = intern ("gif"); staticpro (&Qgif); -#endif - -#if HAVE_PNG + Qpng = intern ("png"); staticpro (&Qpng); -#endif defsubr (&Sclear_image_cache); + defsubr (&Simage_size); + defsubr (&Simage_mask_p); #if GLYPH_DEBUG defsubr (&Simagep); defsubr (&Slookup_image); #endif -#endif /* MAC_TODO */ hourglass_atimer = NULL; hourglass_shown_p = 0; defsubr (&Sx_show_tip); defsubr (&Sx_hide_tip); + tip_timer = Qnil; staticpro (&tip_timer); - tip_timer = Qnil; + tip_frame = Qnil; + staticpro (&tip_frame); #if 0 /* MAC_TODO */ defsubr (&Sx_file_dialog); @@ -9009,30 +10328,26 @@ Vimage_types = Qnil; define_image_type (&xbm_type); -#if 0 /* NTEMACS_TODO : Image support for W32 */ +#if HAVE_GHOSTSCRIPT define_image_type (&gs_type); +#endif define_image_type (&pbm_type); #if HAVE_XPM define_image_type (&xpm_type); #endif -#if HAVE_JPEG define_image_type (&jpeg_type); -#endif - -#if HAVE_TIFF define_image_type (&tiff_type); + define_image_type (&gif_type); + define_image_type (&png_type); + + /* Animated gifs use QuickTime Movie Toolbox. So initialize it + here. */ + EnterMovies (); +#ifdef MAC_OSX + init_image_func_pointer (); #endif - -#if HAVE_GIF - define_image_type (&gif_type); -#endif - -#if HAVE_PNG - define_image_type (&png_type); -#endif -#endif /* NTEMACS_TODO */ } /* arch-tag: d7591289-f374-4377-b245-12f5dbbb8edc
--- a/src/macgui.h Thu Feb 26 11:14:34 2004 +0000 +++ b/src/macgui.h Thu Feb 26 17:46:48 2004 +0000 @@ -23,9 +23,6 @@ #ifndef EMACS_MACGUI_H #define EMACS_MACGUI_H -typedef int Pixmap; -typedef int Bitmap; - typedef int Display; /* fix later */ typedef char * XrmDatabase; /* fix later */ @@ -33,12 +30,43 @@ typedef unsigned long Time; #if MAC_OSX +#undef mktime +#undef DEBUG +#undef Z +#undef free +#undef malloc +#undef realloc +/* Macros max and min defined in lisp.h conflict with those in + precompiled header Carbon.h. */ +#undef max +#undef min +#undef init_process +#include <Carbon/Carbon.h> +#undef Z +#define Z (current_buffer->text->z) +#undef free +#define free unexec_free +#undef malloc +#define malloc unexec_malloc +#undef realloc +#define realloc unexec_realloc +#undef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#undef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#undef init_process +#define init_process emacs_init_process +#undef INFINITY typedef struct OpaqueWindowPtr* Window; #else -#include <QuickDraw.h> +#include <QuickDraw.h> /* for WindowPtr */ +#include <QDOffscreen.h> /* for GWorldPtr */ +#include <Controls.h> /* for ControlHandle in xdisp.c */ typedef WindowPtr Window; #endif +typedef GWorldPtr Pixmap; + #define FACE_DEFAULT (~0)
--- a/src/macmenu.c Thu Feb 26 11:14:34 2004 +0000 +++ b/src/macmenu.c Thu Feb 26 17:46:48 2004 +0000 @@ -35,34 +35,7 @@ #include "charset.h" #include "coding.h" -#ifdef MAC_OSX -#undef mktime -#undef DEBUG -#undef Z -#undef free -#undef malloc -#undef realloc -/* Macros max and min defined in lisp.h conflict with those in - precompiled header Carbon.h. */ -#undef max -#undef min -#undef init_process -#include <Carbon/Carbon.h> -#undef Z -#define Z (current_buffer->text->z) -#undef free -#define free unexec_free -#undef malloc -#define malloc unexec_malloc -#undef realloc -#define realloc unexec_realloc -#undef min -#define min(a, b) ((a) < (b) ? (a) : (b)) -#undef max -#define max(a, b) ((a) > (b) ? (a) : (b)) -#undef init_process -#define init_process emacs_init_process -#else /* not MAC_OSX */ +#ifndef MAC_OSX #include <MacTypes.h> #include <Menus.h> #include <QuickDraw.h>
--- a/src/macterm.c Thu Feb 26 11:14:34 2004 +0000 +++ b/src/macterm.c Thu Feb 26 17:46:48 2004 +0000 @@ -35,29 +35,6 @@ #endif #ifdef MAC_OSX -#undef mktime -#undef DEBUG -#undef free -#undef malloc -#undef realloc -/* Macros max and min defined in lisp.h conflict with those in - precompiled header Carbon.h. */ -#undef max -#undef min -#undef init_process -#include <Carbon/Carbon.h> -#undef free -#define free unexec_free -#undef malloc -#define malloc unexec_malloc -#undef realloc -#define realloc unexec_realloc -#undef min -#define min(a, b) ((a) < (b) ? (a) : (b)) -#undef max -#define max(a, b) ((a) > (b) ? (a) : (b)) -#undef init_process -#define init_process emacs_init_process /* USE_CARBON_EVENTS determines if the Carbon Event Manager is used to obtain events from the event queue. If set to 0, WaitNextEvent is used instead. */ @@ -303,7 +280,9 @@ static void XTframe_rehighlight P_ ((struct frame *)); static void x_frame_rehighlight P_ ((struct x_display_info *)); static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *)); -static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int)); +static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int, + enum text_cursor_kinds)); + static void x_clip_to_row P_ ((struct window *, struct glyph_row *, GC)); static void x_flush P_ ((struct frame *f)); static void x_update_begin P_ ((struct frame *)); @@ -327,15 +306,12 @@ /* X display function emulation */ -static void +void XFreePixmap (display, pixmap) - Display *display; + Display *display; /* not used */ Pixmap pixmap; { - PixMap *p = (PixMap *) pixmap; - - xfree (p->baseAddr); - xfree (p); + DisposeGWorld (pixmap); } @@ -347,9 +323,9 @@ { RGBColor fg_color; - fg_color.red = RED_FROM_ULONG (color) * 256; - fg_color.green = GREEN_FROM_ULONG (color) * 256; - fg_color.blue = BLUE_FROM_ULONG (color) * 256; + fg_color.red = RED16_FROM_ULONG (color); + fg_color.green = GREEN16_FROM_ULONG (color); + fg_color.blue = BLUE16_FROM_ULONG (color); RGBForeColor (&fg_color); } @@ -363,9 +339,9 @@ { RGBColor bg_color; - bg_color.red = RED_FROM_ULONG (color) * 256; - bg_color.green = GREEN_FROM_ULONG (color) * 256; - bg_color.blue = BLUE_FROM_ULONG (color) * 256; + bg_color.red = RED16_FROM_ULONG (color); + bg_color.green = GREEN16_FROM_ULONG (color); + bg_color.blue = BLUE16_FROM_ULONG (color); RGBBackColor (&bg_color); } @@ -401,6 +377,23 @@ LineTo (x2, y2); } +void +mac_draw_line_to_pixmap (display, p, gc, x1, y1, x2, y2) + Display *display; + Pixmap p; + GC gc; + int x1, y1, x2, y2; +{ + SetGWorld (p, NULL); + + mac_set_colors (gc); + + LockPixels (GetGWorldPixMap (p)); + MoveTo (x1, y1); + LineTo (x2, y2); + UnlockPixels (GetGWorldPixMap (p)); +} + /* Mac version of XClearArea. */ void @@ -479,7 +472,7 @@ Rect r; bitmap.rowBytes = sizeof(unsigned short); - bitmap.baseAddr = bits; + bitmap.baseAddr = (char *)bits; SetRect (&(bitmap.bounds), 0, 0, width, height); #if TARGET_API_MAC_CARBON @@ -489,18 +482,13 @@ #endif mac_set_colors (gc); - SetRect (&r, x, y, x + bitmap.bounds.right, y + bitmap.bounds.bottom); + SetRect (&r, x, y, x + width, y + height); #if TARGET_API_MAC_CARBON - { - PixMapHandle pmh; - - LockPortBits (GetWindowPort (w)); - pmh = GetPortPixMap (GetWindowPort (w)); - CopyBits (&bitmap, (BitMap *) *pmh, &(bitmap.bounds), &r, - overlay_p ? srcOr : srcCopy, 0); - UnlockPortBits (GetWindowPort (w)); - } + LockPortBits (GetWindowPort (w)); + CopyBits (&bitmap, GetPortBitMapForCopyBits (GetWindowPort (w)), + &(bitmap.bounds), &r, overlay_p ? srcOr : srcCopy, 0); + UnlockPortBits (GetWindowPort (w)); #else /* not TARGET_API_MAC_CARBON */ CopyBits (&bitmap, &(w->portBits), &(bitmap.bounds), &r, overlay_p ? srcOr : srcCopy, 0); @@ -546,6 +534,23 @@ } +/* XBM bits seem to be backward within bytes compared with how + Mac does things. */ +static unsigned char +reflect_byte (orig) + unsigned char orig; +{ + int i; + unsigned char reflected = 0x00; + for (i = 0; i < 8; i++) + { + if (orig & (0x01 << i)) + reflected |= 0x80 >> i; + } + return reflected; +} + + /* Mac replacement for XCreateBitmapFromBitmapData. */ static void @@ -554,18 +559,19 @@ char *bits; int w, h; { - int bytes_per_row, i, j; - - bitmap->rowBytes = (w + 15) / 16 * 2; /* must be on word boundary */ + int i, j, w1; + char *p; + + w1 = (w + 7) / 8; /* nb of 8bits elt in X bitmap */ + bitmap->rowBytes = ((w + 15) / 16) * 2; /* nb of 16bits elt in Mac bitmap */ bitmap->baseAddr = xmalloc (bitmap->rowBytes * h); - if (!bitmap->baseAddr) - abort (); - bzero (bitmap->baseAddr, bitmap->rowBytes * h); for (i = 0; i < h; i++) - for (j = 0; j < w; j++) - if (BitTst (bits, i * w + j)) - BitSet (bitmap->baseAddr, i * bitmap->rowBytes * 8 + j); + { + p = bitmap->baseAddr + i * bitmap->rowBytes; + for (j = 0; j < w1; j++) + *p++ = reflect_byte (*bits++); + } SetRect (&(bitmap->bounds), 0, 0, w, h); } @@ -578,6 +584,67 @@ xfree (bitmap->baseAddr); } + +Pixmap +XCreatePixmap (display, w, width, height, depth) + Display *display; /* not used */ + WindowPtr w; + unsigned int width, height; + unsigned int depth; /* not used */ +{ + Pixmap pixmap; + Rect r; + QDErr err; + +#if TARGET_API_MAC_CARBON + SetPort (GetWindowPort (w)); +#else + SetPort (w); +#endif + + SetRect (&r, 0, 0, width, height); + err = NewGWorld (&pixmap, depth, &r, NULL, NULL, 0); + if (err != noErr) + return NULL; + return pixmap; +} + + +Pixmap +XCreatePixmapFromBitmapData (display, w, data, width, height, fg, bg, depth) + Display *display; /* not used */ + WindowPtr w; + char *data; + unsigned int width, height; + unsigned long fg, bg; + unsigned int depth; /* not used */ +{ + Pixmap pixmap; + BitMap bitmap; + + pixmap = XCreatePixmap (display, w, width, height, depth); + if (pixmap == NULL) + return NULL; + + SetGWorld (pixmap, NULL); + mac_create_bitmap_from_bitmap_data (&bitmap, data, width, height); + mac_set_forecolor (fg); + mac_set_backcolor (bg); + LockPixels (GetGWorldPixMap (pixmap)); +#if TARGET_API_MAC_CARBON + CopyBits (&bitmap, GetPortBitMapForCopyBits (pixmap), + &bitmap.bounds, &bitmap.bounds, srcCopy, 0); +#else /* not TARGET_API_MAC_CARBON */ + CopyBits (&bitmap, &(((GrafPtr)pixmap)->portBits), + &bitmap.bounds, &bitmap.bounds, srcCopy, 0); +#endif /* not TARGET_API_MAC_CARBON */ + UnlockPixels (GetGWorldPixMap (pixmap)); + mac_free_bitmap (&bitmap); + + return pixmap; +} + + /* Mac replacement for XFillRectangle. */ static void @@ -603,6 +670,26 @@ } +static void +mac_fill_rectangle_to_pixmap (display, p, gc, x, y, width, height) + Display *display; + Pixmap p; + GC gc; + int x, y; + unsigned int width, height; +{ + Rect r; + + SetGWorld (p, NULL); + mac_set_colors (gc); + SetRect (&r, x, y, x + width, y + height); + + LockPixels (GetGWorldPixMap (p)); + PaintRect (&r); /* using foreground color of gc */ + UnlockPixels (GetGWorldPixMap (p)); +} + + /* Mac replacement for XDrawRectangle: dest is a window. */ static void @@ -638,20 +725,15 @@ int x, y; unsigned int width, height; { -#if 0 /* MAC_TODO: draw a rectangle in a PixMap */ Rect r; -#if TARGET_API_MAC_CARBON - SetPort (GetWindowPort (w)); -#else - SetPort (w); -#endif - + SetGWorld (p, NULL); mac_set_colors (gc); - SetRect (&r, x, y, x + width, y + height); - + SetRect (&r, x, y, x + width + 1, y + height + 1); + + LockPixels (GetGWorldPixMap (p)); FrameRect (&r); /* using foreground color of gc */ -#endif /* 0 */ + UnlockPixels (GetGWorldPixMap (p)); } @@ -766,23 +848,66 @@ SetPort (dest); #endif - mac_set_colors (gc); + SetRect (&src_r, src_x, src_y, src_x + width, src_y + height); + SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height); + + ForeColor (blackColor); + BackColor (whiteColor); + + LockPixels (GetGWorldPixMap (src)); +#if TARGET_API_MAC_CARBON + LockPortBits (GetWindowPort (dest)); + CopyBits (GetPortBitMapForCopyBits (src), + GetPortBitMapForCopyBits (GetWindowPort (dest)), + &src_r, &dest_r, srcCopy, 0); + UnlockPortBits (GetWindowPort (dest)); +#else /* not TARGET_API_MAC_CARBON */ + CopyBits (&(((GrafPtr)src)->portBits), &(dest->portBits), + &src_r, &dest_r, srcCopy, 0); +#endif /* not TARGET_API_MAC_CARBON */ + UnlockPixels (GetGWorldPixMap (src)); +} + + +static void +mac_copy_area_with_mask (display, src, mask, dest, gc, src_x, src_y, + width, height, dest_x, dest_y) + Display *display; + Pixmap src, mask; + WindowPtr dest; + GC gc; + int src_x, src_y; + unsigned int width, height; + int dest_x, dest_y; +{ + Rect src_r, dest_r; + +#if TARGET_API_MAC_CARBON + SetPort (GetWindowPort (dest)); +#else + SetPort (dest); +#endif SetRect (&src_r, src_x, src_y, src_x + width, src_y + height); SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height); + ForeColor (blackColor); + BackColor (whiteColor); + + LockPixels (GetGWorldPixMap (src)); + LockPixels (GetGWorldPixMap (mask)); #if TARGET_API_MAC_CARBON - { - PixMapHandle pmh; - - LockPortBits (GetWindowPort (dest)); - pmh = GetPortPixMap (GetWindowPort (dest)); - CopyBits ((BitMap *) &src, (BitMap *) *pmh, &src_r, &dest_r, srcCopy, 0); - UnlockPortBits (GetWindowPort (dest)); - } + LockPortBits (GetWindowPort (dest)); + CopyMask (GetPortBitMapForCopyBits (src), GetPortBitMapForCopyBits (mask), + GetPortBitMapForCopyBits (GetWindowPort (dest)), + &src_r, &src_r, &dest_r); + UnlockPortBits (GetWindowPort (dest)); #else /* not TARGET_API_MAC_CARBON */ - CopyBits ((BitMap *) &src, &(dest->portBits), &src_r, &dest_r, srcCopy, 0); + CopyMask (&(((GrafPtr)src)->portBits), &(((GrafPtr)mask)->portBits), + &(dest->portBits), &src_r, &src_r, &dest_r); #endif /* not TARGET_API_MAC_CARBON */ + UnlockPixels (GetGWorldPixMap (mask)); + UnlockPixels (GetGWorldPixMap (src)); } @@ -817,7 +942,6 @@ { #if TARGET_API_MAC_CARBON Rect gw_r, src_r, dest_r; - PixMapHandle pmh; SetRect (&src_r, src_x, src_y, src_x + width, src_y + height); SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height); @@ -828,8 +952,10 @@ BackColor (whiteColor); LockPortBits (GetWindowPort (w)); - pmh = GetPortPixMap (GetWindowPort (w)); - CopyBits ((BitMap *) *pmh, (BitMap *) *pmh, &src_r, &dest_r, srcCopy, 0); + { + const BitMap *bitmap = GetPortBitMapForCopyBits (GetWindowPort (w)); + CopyBits (bitmap, bitmap, &src_r, &dest_r, srcCopy, 0); + } UnlockPortBits (GetWindowPort (w)); mac_set_colors (gc); @@ -872,25 +998,67 @@ mac_copy_area_to_pixmap (display, src, dest, gc, src_x, src_y, width, height, dest_x, dest_y) Display *display; - Pixmap src; - Pixmap dest; + Pixmap src, dest; GC gc; int src_x, src_y; unsigned int width, height; int dest_x, dest_y; { Rect src_r, dest_r; - int src_right = ((PixMap *) src)->bounds.right; - int src_bottom = ((PixMap *) src)->bounds.bottom; - int w = src_right - src_x; - int h = src_bottom - src_y; - - mac_set_colors (gc); - - SetRect (&src_r, src_x, src_y, src_right, src_bottom); - SetRect (&dest_r, dest_x, dest_y, dest_x + w, dest_y + h); - - CopyBits ((BitMap *) &src, (BitMap *) &dest, &src_r, &dest_r, srcCopy, 0); + + SetGWorld (dest, NULL); + ForeColor (blackColor); + BackColor (whiteColor); + + SetRect (&src_r, src_x, src_y, src_x + width, src_y + height); + SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height); + + LockPixels (GetGWorldPixMap (src)); + LockPixels (GetGWorldPixMap (dest)); +#if TARGET_API_MAC_CARBON + CopyBits (GetPortBitMapForCopyBits (src), GetPortBitMapForCopyBits (dest), + &src_r, &dest_r, srcCopy, 0); +#else /* not TARGET_API_MAC_CARBON */ + CopyBits (&(((GrafPtr)src)->portBits), &(((GrafPtr)dest)->portBits), + &src_r, &dest_r, srcCopy, 0); +#endif /* not TARGET_API_MAC_CARBON */ + UnlockPixels (GetGWorldPixMap (dest)); + UnlockPixels (GetGWorldPixMap (src)); +} + + +static void +mac_copy_area_with_mask_to_pixmap (display, src, mask, dest, gc, src_x, src_y, + width, height, dest_x, dest_y) + Display *display; + Pixmap src, mask, dest; + GC gc; + int src_x, src_y; + unsigned int width, height; + int dest_x, dest_y; +{ + Rect src_r, dest_r; + + SetGWorld (dest, NULL); + ForeColor (blackColor); + BackColor (whiteColor); + + SetRect (&src_r, src_x, src_y, src_x + width, src_y + height); + SetRect (&dest_r, dest_x, dest_y, dest_x + width, dest_y + height); + + LockPixels (GetGWorldPixMap (src)); + LockPixels (GetGWorldPixMap (mask)); + LockPixels (GetGWorldPixMap (dest)); +#if TARGET_API_MAC_CARBON + CopyMask (GetPortBitMapForCopyBits (src), GetPortBitMapForCopyBits (mask), + GetPortBitMapForCopyBits (dest), &src_r, &src_r, &dest_r); +#else /* not TARGET_API_MAC_CARBON */ + CopyMask (&(((GrafPtr)src)->portBits), &(((GrafPtr)mask)->portBits), + &(((GrafPtr)dest)->portBits), &src_r, &src_r, &dest_r); +#endif /* not TARGET_API_MAC_CARBON */ + UnlockPixels (GetGWorldPixMap (dest)); + UnlockPixels (GetGWorldPixMap (mask)); + UnlockPixels (GetGWorldPixMap (src)); } @@ -947,7 +1115,7 @@ /* Mac replacement for XSetForeground. */ -static void +void XSetForeground (display, gc, color) Display *display; GC gc; @@ -2139,6 +2307,21 @@ #endif /* MAC_TODO */ + +/* Brightness beyond which a color won't have its highlight brightness + boosted. + + Nominally, highlight colors for `3d' faces are calculated by + brightening an object's color by a constant scale factor, but this + doesn't yield good results for dark colors, so for colors who's + brightness is less than this value (on a scale of 0-255) have to + use an additional additive factor. + + The value here is set so that the default menu-bar/mode-line color + (grey75) will not have its highlights changed at all. */ +#define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 187 + + /* Allocate a color which is lighter or darker than *COLOR by FACTOR or DELTA. Try a color with RGB values multiplied by FACTOR first. If this produces the same color as COLOR, try a color where all RGB @@ -2154,12 +2337,42 @@ int delta; { unsigned long new; + long bright; + + /* On Mac, RGB values are 0-255, not 0-65535, so scale delta. */ + delta /= 256; /* Change RGB values by specified FACTOR. Avoid overflow! */ xassert (factor >= 0); new = RGB_TO_ULONG (min (0xff, (int) (factor * RED_FROM_ULONG (*color))), min (0xff, (int) (factor * GREEN_FROM_ULONG (*color))), min (0xff, (int) (factor * BLUE_FROM_ULONG (*color)))); + + /* Calculate brightness of COLOR. */ + bright = (2 * RED_FROM_ULONG (*color) + 3 * GREEN_FROM_ULONG (*color) + + BLUE_FROM_ULONG (*color)) / 6; + + /* We only boost colors that are darker than + HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */ + if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT) + /* Make an additive adjustment to NEW, because it's dark enough so + that scaling by FACTOR alone isn't enough. */ + { + /* How far below the limit this color is (0 - 1, 1 being darker). */ + double dimness = 1 - (double)bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT; + /* The additive adjustment. */ + int min_delta = delta * dimness * factor / 2; + + if (factor < 1) + new = RGB_TO_ULONG (max (0, min (0xff, (int) (RED_FROM_ULONG (*color)) - min_delta)), + max (0, min (0xff, (int) (GREEN_FROM_ULONG (*color)) - min_delta)), + max (0, min (0xff, (int) (BLUE_FROM_ULONG (*color)) - min_delta))); + else + new = RGB_TO_ULONG (max (0, min (0xff, (int) (min_delta + RED_FROM_ULONG (*color)))), + max (0, min (0xff, (int) (min_delta + GREEN_FROM_ULONG (*color)))), + max (0, min (0xff, (int) (min_delta + BLUE_FROM_ULONG (*color))))); + } + if (new == *color) new = RGB_TO_ULONG (max (0, min (0xff, (int) (delta + RED_FROM_ULONG (*color)))), max (0, min (0xff, (int) (delta + GREEN_FROM_ULONG (*color)))), @@ -2204,7 +2417,8 @@ /* Allocate new color. */ xgcv.foreground = default_pixel; pixel = background; - if (mac_alloc_lighter_color (f, &pixel, factor, delta)) + if (dpyinfo->n_planes != 1 + && mac_alloc_lighter_color (f, &pixel, factor, delta)) { relief->allocated_p = 1; xgcv.foreground = relief->pixel = pixel; @@ -2234,6 +2448,10 @@ if (s->face->use_box_color_for_shadows_p) color = s->face->box_color; + else if (s->first_glyph->type == IMAGE_GLYPH + && s->img->pixmap + && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0)) + color = IMAGE_BACKGROUND (s->img, s->f, 0); else { XGCValues xgcv; @@ -2267,9 +2485,11 @@ x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width, raised_p, left_p, right_p, clip_rect) struct frame *f; - int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p; + int left_x, top_y, right_x, bottom_y, width, left_p, right_p, raised_p; Rect *clip_rect; { + Display *dpy = FRAME_MAC_DISPLAY (f); + Window window = FRAME_MAC_WINDOW (f); int i; GC gc; @@ -2277,41 +2497,41 @@ gc = f->output_data.mac->white_relief.gc; else gc = f->output_data.mac->black_relief.gc; - mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), clip_rect); + mac_set_clip_rectangle (dpy, window, clip_rect); /* Top. */ for (i = 0; i < width; ++i) - XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc, + XDrawLine (dpy, window, gc, left_x + i * left_p, top_y + i, - right_x + 1 - i * right_p, top_y + i); + right_x - i * right_p, top_y + i); /* Left. */ if (left_p) for (i = 0; i < width; ++i) - XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc, + XDrawLine (dpy, window, gc, left_x + i, top_y + i, left_x + i, bottom_y - i); - mac_reset_clipping (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f)); + mac_reset_clipping (dpy, window); if (raised_p) gc = f->output_data.mac->black_relief.gc; else gc = f->output_data.mac->white_relief.gc; - mac_set_clip_rectangle (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), + mac_set_clip_rectangle (dpy, window, clip_rect); /* Bottom. */ for (i = 0; i < width; ++i) - XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc, + XDrawLine (dpy, window, gc, left_x + i * left_p, bottom_y - i, - right_x + 1 - i * right_p, bottom_y - i); + right_x - i * right_p, bottom_y - i); /* Right. */ if (right_p) for (i = 0; i < width; ++i) - XDrawLine (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), gc, - right_x - i, top_y + i + 1, right_x - i, bottom_y - i); - - mac_reset_clipping (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f)); + XDrawLine (dpy, window, gc, + right_x - i, top_y + i + 1, right_x - i, bottom_y - i - 1); + + mac_reset_clipping (dpy, window); } @@ -2326,7 +2546,7 @@ x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width, left_p, right_p, clip_rect) struct glyph_string *s; - int left_x, top_y, right_x, bottom_y, left_p, right_p; + int left_x, top_y, right_x, bottom_y, width, left_p, right_p; Rect *clip_rect; { XGCValues xgcv; @@ -2336,21 +2556,21 @@ /* Top. */ XFillRectangle (s->display, s->window, &xgcv, - left_x, top_y, right_x - left_x, width); + left_x, top_y, right_x - left_x + 1, width); /* Left. */ if (left_p) XFillRectangle (s->display, s->window, &xgcv, - left_x, top_y, width, bottom_y - top_y); + left_x, top_y, width, bottom_y - top_y + 1); /* Bottom. */ XFillRectangle (s->display, s->window, &xgcv, - left_x, bottom_y - width, right_x - left_x, width); + left_x, bottom_y - width + 1, right_x - left_x + 1, width); /* Right. */ if (right_p) XFillRectangle (s->display, s->window, &xgcv, - right_x - width, top_y, width, bottom_y - top_y); + right_x - width + 1, top_y, width, bottom_y - top_y + 1); mac_reset_clipping (s->display, s->window); } @@ -2385,9 +2605,9 @@ width = abs (s->face->box_line_width); raised_p = s->face->box == FACE_RAISED_BOX; left_x = s->x; - right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p - ? last_x - 1 - : min (last_x, s->x + s->background_width) - 1)); + right_x = (s->row->full_width_p && s->extends_to_end_of_line_p + ? last_x - 1 + : min (last_x, s->x + s->background_width) - 1); top_y = s->y; bottom_y = top_y + s->height - 1; @@ -2438,39 +2658,36 @@ if (s->img->pixmap) { -#if 0 /* MAC_TODO: image mask */ if (s->img->mask) { - /* We can't set both a clip mask and use XSetClipRectangles - because the latter also sets a clip mask. We also can't - trust on the shape extension to be available - (XShapeCombineRegion). So, compute the rectangle to draw - manually. */ - unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin - | GCFunction); - XGCValues xgcv; + Rect nr; XRectangle clip_rect, image_rect, r; - xgcv.clip_mask = s->img->mask; - xgcv.clip_x_origin = x; - xgcv.clip_y_origin = y; - xgcv.function = GXcopy; - XChangeGC (s->display, s->gc, mask, &xgcv); - - get_glyph_string_clip_rect (s, &clip_rect); + get_glyph_string_clip_rect (s, &nr); + CONVERT_TO_XRECT (clip_rect, nr); image_rect.x = x; image_rect.y = y; image_rect.width = s->img->width; image_rect.height = s->img->height; if (x_intersect_rectangles (&clip_rect, &image_rect, &r)) - XCopyArea (s->display, s->img->pixmap, s->window, s->gc, - r.x - x, r.y - y, r.width, r.height, r.x, r.y); + mac_copy_area_with_mask (s->display, s->img->pixmap, s->img->mask, + s->window, s->gc, r.x - x, r.y - y, + r.width, r.height, r.x, r.y); } else -#endif /* MAC_TODO */ { - mac_copy_area (s->display, s->img->pixmap, s->window, s->gc, - 0, 0, s->img->width, s->img->height, x, y); + Rect nr; + XRectangle clip_rect, image_rect, r; + + get_glyph_string_clip_rect (s, &nr); + CONVERT_TO_XRECT (clip_rect, nr); + image_rect.x = x; + image_rect.y = y; + image_rect.width = s->img->width; + image_rect.height = s->img->height; + if (x_intersect_rectangles (&clip_rect, &image_rect, &r)) + mac_copy_area (s->display, s->img->pixmap, s->window, s->gc, + r.x - x, r.y - y, r.width, r.height, r.x, r.y); /* When the image has a mask, we can expect that at least part of a mouse highlight or a block cursor will @@ -2494,7 +2711,6 @@ } - /* Draw a relief around the image glyph string S. */ static void @@ -2567,30 +2783,12 @@ if (s->img->pixmap) { -#if 0 /* MAC_TODO: image mask */ if (s->img->mask) - { - /* We can't set both a clip mask and use XSetClipRectangles - because the latter also sets a clip mask. We also can't - trust on the shape extension to be available - (XShapeCombineRegion). So, compute the rectangle to draw - manually. */ - unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin - | GCFunction); - XGCValues xgcv; - - xgcv.clip_mask = s->img->mask; - xgcv.clip_x_origin = x; - xgcv.clip_y_origin = y; - xgcv.function = GXcopy; - XChangeGC (s->display, s->gc, mask, &xgcv); - - XCopyArea (s->display, s->img->pixmap, pixmap, s->gc, - 0, 0, s->img->width, s->img->height, x, y); - XSetClipMask (s->display, s->gc, None); - } + mac_copy_area_with_mask_to_pixmap (s->display, s->img->pixmap, + s->img->mask, pixmap, s->gc, + 0, 0, s->img->width, s->img->height, + x, y); else -#endif /* MAC_TODO */ { mac_copy_area_to_pixmap (s->display, s->img->pixmap, pixmap, s->gc, 0, 0, s->img->width, s->img->height, x, y); @@ -2605,15 +2803,16 @@ { int r = s->img->relief; if (r < 0) r = -r; - mac_draw_rectangle_to_pixmap (s->display, pixmap, s->gc, x - r, y - r, - s->img->width + r*2 - 1, s->img->height + r*2 - 1); + mac_draw_rectangle (s->display, s->window, s->gc, x - r, y - r, + s->img->width + r*2 - 1, + s->img->height + r*2 - 1); } } } else /* Draw a rectangle if image could not be loaded. */ mac_draw_rectangle_to_pixmap (s->display, pixmap, s->gc, x, y, - s->img->width - 1, s->img->height - 1); + s->img->width - 1, s->img->height - 1); } @@ -2646,7 +2845,7 @@ | s->face->box | | +------------------------- - | | s->img->vmargin + | | s->img->margin | | | | +------------------- | | | the image @@ -2665,6 +2864,7 @@ height = s->height - 2 * box_line_vwidth; + /* Fill background with face under the image. Do it only if row is taller than image or if image has a clip mask to reduce flickering. */ @@ -2672,9 +2872,7 @@ if (height > s->img->height || s->img->hmargin || s->img->vmargin -#if 0 /* TODO: image mask */ || s->img->mask -#endif || s->img->pixmap == 0 || s->width != s->background_width) { @@ -2684,25 +2882,21 @@ x = s->x; y = s->y + box_line_vwidth; -#if 0 /* TODO: image mask */ + if (s->img->mask) { /* Create a pixmap as large as the glyph string. Fill it with the background color. Copy the image to it, using its mask. Copy the temporary pixmap to the display. */ - Screen *screen = FRAME_X_SCREEN (s->f); - int depth = DefaultDepthOfScreen (screen); + int depth = one_mac_display_info.n_planes; /* Create a pixmap as large as the glyph string. */ pixmap = XCreatePixmap (s->display, s->window, s->background_width, s->height, depth); - /* Don't clip in the following because we're working on the - pixmap. */ - XSetClipMask (s->display, s->gc, None); - /* Fill the pixmap with the background color/stipple. */ +#if 0 /* TODO: stipple */ if (s->stippled_p) { /* Fill background with a stipple pattern. */ @@ -2712,18 +2906,19 @@ XSetFillStyle (s->display, s->gc, FillSolid); } else +#endif { XGCValues xgcv; XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv); XSetForeground (s->display, s->gc, xgcv.background); - XFillRectangle (s->display, pixmap, s->gc, - 0, 0, s->background_width, s->height); + mac_fill_rectangle_to_pixmap (s->display, pixmap, s->gc, + 0, 0, s->background_width, + s->height); XSetForeground (s->display, s->gc, xgcv.foreground); } } else -#endif x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height); s->background_filled_p = 1; @@ -2735,7 +2930,7 @@ x_draw_image_foreground_1 (s, pixmap); x_set_glyph_string_clipping (s); mac_copy_area (s->display, pixmap, s->window, s->gc, - 0, 0, s->background_width, s->height, s->x, s->y); + 0, 0, s->background_width, s->height, s->x, s->y); mac_reset_clipping (s->display, s->window); XFreePixmap (s->display, pixmap); } @@ -2772,10 +2967,10 @@ /* Clear rest using the GC of the original non-cursor face. */ if (width < s->background_width) { - GC gc = s->face->gc; int x = s->x + width, y = s->y; int w = s->background_width - width, h = s->height; Rect r; + GC gc; if (s->row->mouse_face_p && cursor_in_mouse_face_p (s->w)) @@ -2835,7 +3030,6 @@ x_set_glyph_string_gc (s->next); x_set_glyph_string_clipping (s->next); x_draw_glyph_string_background (s->next, 1); - } /* Set up S->gc, set clipping and draw S. */ @@ -2872,7 +3066,7 @@ if (s->for_overlaps_p) s->background_filled_p = 1; else - x_draw_glyph_string_background (s, 0); + x_draw_glyph_string_background (s, 0); x_draw_glyph_string_foreground (s); break; @@ -2949,9 +3143,9 @@ } } - /* Draw relief. */ + /* Draw relief if not yet drawn. */ if (!relief_drawn_p && s->face->box != FACE_NO_BOX) - x_draw_glyph_string_box (s); + x_draw_glyph_string_box (s); } /* Reset clipping. */ @@ -2971,7 +3165,6 @@ x + shift_by, y); } - /* Delete N glyphs at the nominal cursor position. Not implemented for X frames. */ @@ -3026,6 +3219,7 @@ #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) + /* Subtract the `struct timeval' values X and Y, storing the result in *RESULT. Return 1 if the difference is negative, otherwise 0. */ @@ -3129,7 +3323,7 @@ This, and those operations, are used only within an update that is bounded by calls to x_update_begin and x_update_end. */ -void +static void XTset_terminal_window (n) register int n; { @@ -3165,7 +3359,7 @@ /* Get frame-relative bounding box of the text display area of W, without mode lines. Include in this box the left and right - fringes of W. */ + fringe of W. */ window_box (w, -1, &x, &y, &width, &height); from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y); @@ -3287,8 +3481,6 @@ XTframe_rehighlight (frame) struct frame *frame; { - - x_frame_rehighlight (FRAME_X_DISPLAY_INFO (frame)); } @@ -4429,13 +4621,6 @@ struct glyph *cursor_glyph; GC gc; - /* Compute frame-relative coordinates from window-relative - coordinates. */ - x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); - y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y) - + row->ascent - w->phys_cursor_ascent); - h = row->height - 1; - /* Get the glyph the cursor is on. If we can't tell because the current matrix is invalid or such, give up. */ cursor_glyph = get_phys_cursor_glyph (w); @@ -4450,6 +4635,20 @@ if (cursor_glyph->type == STRETCH_GLYPH && !x_stretch_cursor_p) wd = min (FRAME_COLUMN_WIDTH (f), wd); + w->phys_cursor_width = wd; + + /* Compute frame-relative coordinates from window-relative + coordinates. */ + x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); + y = WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y); + + /* Compute the proper height and ascent of the rectangle, based + on the actual glyph. Using the full height of the row looks + bad when there are tall images on that row. */ + h = max (FRAME_LINE_HEIGHT (f), cursor_glyph->ascent + cursor_glyph->descent); + if (h < row->height) + y += row->ascent /* - w->phys_cursor_ascent */ + cursor_glyph->descent - h; + h--; /* The foreground of cursor_gc is typically the same as the normal background color, which can cause the cursor box to be invisible. */ @@ -4476,35 +4675,49 @@ --gerd. */ static void -x_draw_bar_cursor (w, row, width) +x_draw_bar_cursor (w, row, width, kind) struct window *w; struct glyph_row *row; int width; -{ - /* If cursor hpos is out of bounds, don't draw garbage. This can - happen in mini-buffer windows when switching between echo area - glyphs and mini-buffer. */ - if (w->phys_cursor.hpos < row->used[TEXT_AREA]) - { - struct frame *f = XFRAME (w->frame); - struct glyph *cursor_glyph; - GC gc; - int x; - unsigned long mask; + enum text_cursor_kinds kind; +{ + struct frame *f = XFRAME (w->frame); + struct glyph *cursor_glyph; + + /* If cursor is out of bounds, don't draw garbage. This can happen + in mini-buffer windows when switching between echo area glyphs + and mini-buffer. */ + cursor_glyph = get_phys_cursor_glyph (w); + if (cursor_glyph == NULL) + return; + + /* If on an image, draw like a normal cursor. That's usually better + visible than drawing a bar, esp. if the image is large so that + the bar might not be in the window. */ + if (cursor_glyph->type == IMAGE_GLYPH) + { + struct glyph_row *row; + row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos); + draw_phys_cursor_glyph (w, row, DRAW_CURSOR); + } + else + { + Display *dpy = FRAME_MAC_DISPLAY (f); + Window window = FRAME_MAC_WINDOW (f); + GC gc = FRAME_MAC_DISPLAY_INFO (f)->scratch_cursor_gc; + unsigned long mask = GCForeground | GCBackground; + struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id); XGCValues xgcv; - Display *dpy; - Window window; - - cursor_glyph = get_phys_cursor_glyph (w); - if (cursor_glyph == NULL) - return; - - xgcv.background = f->output_data.mac->cursor_pixel; - xgcv.foreground = f->output_data.mac->cursor_pixel; - mask = GCForeground | GCBackground; - dpy = FRAME_MAC_DISPLAY (f); - window = FRAME_MAC_WINDOW (f); - gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc; + + /* If the glyph's background equals the color we normally draw + the bar cursor in, the bar cursor in its normal color is + invisible. Use the glyph's foreground color instead in this + case, on the assumption that the glyph's colors are chosen so + that the glyph is legible. */ + if (face->background == f->output_data.mac->cursor_pixel) + xgcv.background = xgcv.foreground = face->foreground; + else + xgcv.background = xgcv.foreground = f->output_data.mac->cursor_pixel; if (gc) XChangeGC (dpy, gc, mask, &xgcv); @@ -4516,14 +4729,24 @@ if (width < 0) width = FRAME_CURSOR_WIDTH (f); - - x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); + width = min (cursor_glyph->pixel_width, width); + + w->phys_cursor_width = width; x_clip_to_row (w, row, gc); - XFillRectangle (dpy, window, gc, - x, - WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y), - min (cursor_glyph->pixel_width, width), - row->height); + + if (kind == BAR_CURSOR) + XFillRectangle (dpy, window, gc, + WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x), + WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y), + width, row->height); + else + XFillRectangle (dpy, window, gc, + WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x), + WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y + + row->height - width), + cursor_glyph->pixel_width, + width); + mac_reset_clipping (dpy, FRAME_MAC_WINDOW (f)); } } @@ -4565,7 +4788,6 @@ if (on_p) { w->phys_cursor_type = cursor_type; - w->phys_cursor_width = cursor_width; w->phys_cursor_on_p = 1; if (glyph_row->exact_window_width_line_p @@ -4573,9 +4795,8 @@ { glyph_row->cursor_in_fringe_p = 1; draw_fringe_bitmap (w, glyph_row, 0); - return; } - + else switch (cursor_type) { case HOLLOW_BOX_CURSOR: @@ -4586,13 +4807,16 @@ draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); break; + case BAR_CURSOR: + x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR); + break; + case HBAR_CURSOR: - /* TODO. For now, just draw bar cursor. */ - case BAR_CURSOR: - x_draw_bar_cursor (w, glyph_row, cursor_width); + x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR); break; case NO_CURSOR: + w->phys_cursor_width = 0; break; default: @@ -5117,6 +5341,8 @@ FRAME_SAMPLE_VISIBILITY (f); } } +#else + UNBLOCK_INPUT; #endif /* MAC_TODO */ } @@ -5173,10 +5399,10 @@ } -/* Destroy the X window of frame F. */ +/* Free X resources of frame F. */ void -x_destroy_window (f) +x_free_frame_resources (f) struct frame *f; { struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); @@ -5186,10 +5412,15 @@ DisposeWindow (FRAME_MAC_WINDOW (f)); free_frame_menubar (f); - free_frame_faces (f); + + if (FRAME_FACE_CACHE (f)) + free_frame_faces (f); + + x_free_gcs (f); xfree (f->output_data.mac); - f->output_data.mac = 0; + f->output_data.mac = NULL; + if (f == dpyinfo->x_focus_frame) dpyinfo->x_focus_frame = 0; if (f == dpyinfo->x_focus_event_frame) @@ -5197,8 +5428,6 @@ if (f == dpyinfo->x_highlight_frame) dpyinfo->x_highlight_frame = 0; - dpyinfo->reference_count--; - if (f == dpyinfo->mouse_face_mouse_frame) { dpyinfo->mouse_face_beg_row @@ -5212,6 +5441,21 @@ UNBLOCK_INPUT; } + + +/* Destroy the X window of frame F. */ + +void +x_destroy_window (f) + struct frame *f; +{ + struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f); + + x_free_frame_resources (f); + + dpyinfo->reference_count--; +} + /* Setting window manager hints. */ @@ -5478,6 +5722,7 @@ int font_name_table_size = 0; int font_name_count = 0; +#if 0 /* compare two strings ignoring case */ static int stricmp (const char *s, const char *t) @@ -5557,13 +5802,53 @@ && wildstrieq (m_charset, x_charset)) || mac_font_pattern_match (mf, xf); } +#endif + +static Lisp_Object Qbig5, Qcn_gb, Qsjis, Qeuc_kr; + +static void +decode_mac_font_name (char *name, int size, short scriptcode) +{ + Lisp_Object coding_system; + struct coding_system coding; + char *buf; + + switch (scriptcode) + { + case smTradChinese: + coding_system = Qbig5; + break; + case smSimpChinese: + coding_system = Qcn_gb; + break; + case smJapanese: + coding_system = Qsjis; + break; + case smKorean: + coding_system = Qeuc_kr; + break; + default: + return; + } + + setup_coding_system (coding_system, &coding); + coding.src_multibyte = 0; + coding.dst_multibyte = 1; + coding.mode |= CODING_MODE_LAST_BLOCK; + coding.composing = COMPOSITION_DISABLED; + buf = (char *) alloca (size); + + decode_coding (&coding, name, buf, strlen (name), size - 1); + bcopy (buf, name, coding.produced); + name[coding.produced] = '\0'; +} static char * mac_to_x_fontname (char *name, int size, Style style, short scriptcode) { char foundry[32], family[32], cs[32]; - char xf[255], *result, *p; + char xf[256], *result, *p; if (sscanf (name, "%31[^-]-%31[^-]-%31s", foundry, family, cs) != 3) { @@ -5622,6 +5907,8 @@ x_font_name_to_mac_font_name (char *xf, char *mf) { char foundry[32], family[32], weight[20], slant[2], cs[32]; + Lisp_Object coding_system = Qnil; + struct coding_system coding; strcpy (mf, ""); @@ -5631,13 +5918,29 @@ foundry, family, weight, slant, cs) != 5) return; - if (strcmp (cs, "big5-0") == 0 || strcmp (cs, "gb2312.1980-0") == 0 - || strcmp (cs, "jisx0208.1983-sjis") == 0 - || strcmp (cs, "jisx0201.1976-0") == 0 - || strcmp (cs, "ksc5601.1989-0") == 0 || strcmp (cs, "mac-roman") == 0) - strcpy(mf, family); + if (strcmp (cs, "big5-0") == 0) + coding_system = Qbig5; + else if (strcmp (cs, "gb2312.1980-0") == 0) + coding_system = Qcn_gb; + else if (strcmp (cs, "jisx0208.1983-sjis") == 0 + || strcmp (cs, "jisx0201.1976-0") == 0) + coding_system = Qsjis; + else if (strcmp (cs, "ksc5601.1989-0") == 0) + coding_system = Qeuc_kr; + else if (strcmp (cs, "mac-roman") == 0) + strcpy (mf, family); else - sprintf(mf, "%s-%s-%s", foundry, family, cs); + sprintf (mf, "%s-%s-%s", foundry, family, cs); + + if (!NILP (coding_system)) + { + setup_coding_system (coding_system, &coding); + coding.src_multibyte = 1; + coding.dst_multibyte = 1; + coding.mode |= CODING_MODE_LAST_BLOCK; + encode_coding (&coding, family, mf, strlen (family), sizeof (Str32) - 1); + mf[coding.produced] = '\0'; + } } @@ -5701,36 +6004,45 @@ if (FMGetFontFamilyName (ff, name) != noErr) break; p2cstr (name); + if (*name == '.') + continue; sc = FontToScript (ff); + decode_mac_font_name (name, sizeof (name), sc); /* Point the instance iterator at the current font family. */ - if (FMResetFontFamilyInstanceIterator(ff, &ffii) != noErr) + if (FMResetFontFamilyInstanceIterator (ff, &ffii) != noErr) break; while (FMGetNextFontFamilyInstance (&ffii, &font, &style, &size) == noErr) - if (size == 0) - { + { + /* Both jisx0208.1983-sjis and jisx0201.1976-0 parts are + contained in Apple Japanese (SJIS) font. */ + again: + if (size == 0) + { + add_font_name_table_entry (mac_to_x_fontname (name, size, + style, sc)); + add_font_name_table_entry (mac_to_x_fontname (name, size, + italic, sc)); + add_font_name_table_entry (mac_to_x_fontname (name, size, + bold, sc)); + add_font_name_table_entry (mac_to_x_fontname (name, size, + italic | bold, + sc)); + } + else add_font_name_table_entry (mac_to_x_fontname (name, size, style, sc)); - add_font_name_table_entry (mac_to_x_fontname (name, size, - italic, sc)); - add_font_name_table_entry (mac_to_x_fontname (name, size, - bold, sc)); - add_font_name_table_entry (mac_to_x_fontname (name, size, - italic | bold, - sc)); - } - else - { - add_font_name_table_entry (mac_to_x_fontname (name, size, - style, sc)); - if (smJapanese == sc) - add_font_name_table_entry (mac_to_x_fontname (name, size, - style, - -smJapanese)); - } + if (sc == smJapanese) + { + sc = -smJapanese; + goto again; + } + else if (sc == -smJapanese) + sc = smJapanese; + } } /* Dispose of the iterators. */ @@ -5772,6 +6084,7 @@ TextFont (fontnum); scriptcode = FontToScript (fontnum); + decode_mac_font_name (name, sizeof (name), scriptcode); do { HLock (font_handle); @@ -5806,9 +6119,9 @@ assc_entry->fontSize, assc_entry->fontStyle, scriptcode); - /* Both jisx0208.1983-sjis and - jisx0201.1976-sjis parts are contained in - Apple Japanese (SJIS) font. */ + /* Both jisx0208.1983-sjis and jisx0201.1976-0 + parts are contained in Apple Japanese (SJIS) + font. */ if (smJapanese == scriptcode) { font_name_table[font_name_count++] @@ -5835,6 +6148,145 @@ } +enum xlfd_scalable_field_index + { + XLFD_SCL_PIXEL_SIZE, + XLFD_SCL_POINT_SIZE, + XLFD_SCL_AVGWIDTH, + XLFD_SCL_LAST + }; + +static int xlfd_scalable_fields[] = + { + 6, /* PIXEL_SIZE */ + 7, /* POINT_SIZE */ + 11, /* AVGWIDTH */ + -1 + }; + +static Lisp_Object +mac_do_list_fonts (pattern, maxnames) + char *pattern; + int maxnames; +{ + int i, n_fonts = 0; + Lisp_Object font_list = Qnil, pattern_regex, fontname; + char *regex = (char *) alloca (strlen (pattern) * 2 + 3); + char scaled[256]; + char *ptr; + int scl_val[XLFD_SCL_LAST], *field, *val; + + for (i = 0; i < XLFD_SCL_LAST; i++) + scl_val[i] = -1; + + /* If the pattern contains 14 dashes and one of PIXEL_SIZE, + POINT_SIZE, and AVGWIDTH fields is explicitly specified, scalable + fonts are scaled according to the specified size. */ + ptr = pattern; + i = 0; + field = xlfd_scalable_fields; + val = scl_val; + if (*ptr == '-') + do + { + ptr++; + if (i == *field) + { + if ('1' <= *ptr && *ptr <= '9') + { + *val = *ptr++ - '0'; + while ('0' <= *ptr && *ptr <= '9' && *val < 10000) + *val = *val * 10 + *ptr++ - '0'; + if (*ptr != '-') + *val = -1; + } + field++; + val++; + } + ptr = strchr (ptr, '-'); + i++; + } + while (ptr && i < 14); + + if (i == 14 && ptr == NULL) + { + if (scl_val[XLFD_SCL_POINT_SIZE] > 0) + { + scl_val[XLFD_SCL_PIXEL_SIZE] = scl_val[XLFD_SCL_POINT_SIZE] / 10; + scl_val[XLFD_SCL_AVGWIDTH] = scl_val[XLFD_SCL_POINT_SIZE]; + } + else if (scl_val[XLFD_SCL_PIXEL_SIZE] > 0) + { + scl_val[XLFD_SCL_POINT_SIZE] = + scl_val[XLFD_SCL_AVGWIDTH] = scl_val[XLFD_SCL_PIXEL_SIZE] * 10; + } + else if (scl_val[XLFD_SCL_AVGWIDTH] > 0) + { + scl_val[XLFD_SCL_PIXEL_SIZE] = scl_val[XLFD_SCL_AVGWIDTH] / 10; + scl_val[XLFD_SCL_POINT_SIZE] = scl_val[XLFD_SCL_AVGWIDTH]; + } + } + else + scl_val[XLFD_SCL_PIXEL_SIZE] = -1; + + ptr = regex; + *ptr++ = '^'; + + /* Turn pattern into a regexp and do a regexp match. */ + for (; *pattern; pattern++) + { + if (*pattern == '?') + *ptr++ = '.'; + else if (*pattern == '*') + { + *ptr++ = '.'; + *ptr++ = '*'; + } + else + *ptr++ = tolower (*pattern); + } + *ptr = '$'; + *(ptr + 1) = '\0'; + + pattern_regex = build_string (regex); + + for (i = 0; i < font_name_count; i++) + { + fontname = build_string (font_name_table[i]); + if (fast_string_match (pattern_regex, fontname) >= 0) + { + font_list = Fcons (fontname, font_list); + + n_fonts++; + if (maxnames > 0 && n_fonts >= maxnames) + break; + } + else if (scl_val[XLFD_SCL_PIXEL_SIZE] > 0 + && (ptr = strstr (font_name_table[i], "-0-0-75-75-m-0-"))) + { + int former_len = ptr - font_name_table[i]; + + memcpy (scaled, font_name_table[i], former_len); + sprintf (scaled + former_len, + "-%d-%d-75-75-m-%d-%s", + scl_val[XLFD_SCL_PIXEL_SIZE], + scl_val[XLFD_SCL_POINT_SIZE], + scl_val[XLFD_SCL_AVGWIDTH], + ptr + sizeof ("-0-0-75-75-m-0-") - 1); + fontname = build_string (scaled); + if (fast_string_match (pattern_regex, fontname) >= 0) + { + font_list = Fcons (fontname, font_list); + + n_fonts++; + if (maxnames > 0 && n_fonts >= maxnames) + break; + } + } + } + return font_list; +} + /* Return a list of at most MAXNAMES font specs matching the one in PATTERN. Cache matching fonts for patterns in dpyinfo->name_list_element to avoid looking them up again by @@ -5847,11 +6299,7 @@ int size, int maxnames) { - char *ptnstr; Lisp_Object newlist = Qnil, tem, key; - int n_fonts = 0; - int i; - struct gcpro gcpro1, gcpro2; struct mac_display_info *dpyinfo = f ? FRAME_MAC_DISPLAY_INFO (f) : NULL; if (font_name_table == NULL) /* Initialize when first used. */ @@ -5870,27 +6318,10 @@ } } - ptnstr = SDATA (pattern); - - GCPRO2 (pattern, newlist); - - /* Scan and matching bitmap fonts. */ - for (i = 0; i < font_name_count; i++) - { - if (mac_font_pattern_match (font_name_table[i], ptnstr)) - { - newlist = Fcons (build_string (font_name_table[i]), newlist); - - n_fonts++; - if (maxnames > 0 && n_fonts >= maxnames) - break; - } - } + newlist = mac_do_list_fonts (SDATA (pattern), maxnames); /* MAC_TODO: add code for matching outline fonts here */ - UNGCPRO; - if (dpyinfo) { XSETCDR (dpyinfo->name_list_element, @@ -6050,14 +6481,12 @@ name = fontname; else { - for (i = 0; i < font_name_count; i++) - if (mac_font_pattern_match (font_name_table[i], fontname)) - break; - - if (i >= font_name_count) - return NULL; - - name = font_name_table[i]; + Lisp_Object matched_fonts; + + matched_fonts = mac_do_list_fonts (fontname, 1); + if (NILP (matched_fonts)) + return NULL; + name = SDATA (XCAR (matched_fonts)); } GetPort (&port); /* save the current font number used */ @@ -6179,7 +6608,8 @@ for (c = 0x20; c <= 0xff; c++) { font->per_char[c - 0x20] = font->max_bounds; - font->per_char[c - 0x20].width = CharWidth (c); + font->per_char[c - 0x20].width = + font->per_char[c - 0x20].rbearing = CharWidth (c); } } } @@ -7833,14 +8263,32 @@ } else { - bufp->kind = MOUSE_CLICK_EVENT; + Lisp_Object window; + + bufp->kind = MOUSE_CLICK_EVENT; XSETFRAME (bufp->frame_or_window, mwp->mFP); if (er.what == mouseDown) - mouse_tracking_in_progress + mouse_tracking_in_progress = mouse_tracking_mouse_movement; else - mouse_tracking_in_progress = mouse_tracking_none; - } + mouse_tracking_in_progress = mouse_tracking_none; + window = window_from_coordinates (mwp->mFP, bufp->x, bufp->y, 0, 0, 0, 1); + + if (EQ (window, mwp->mFP->tool_bar_window)) + { + if (er.what == mouseDown) + handle_tool_bar_click (mwp->mFP, bufp->x, bufp->y, 1, 0); + else + handle_tool_bar_click (mwp->mFP, bufp->x, bufp->y, 0, +#if USE_CARBON_EVENTS + mac_event_to_emacs_modifiers (eventRef) +#else + er.modifiers +#endif + ); + break; + } + } #if USE_CARBON_EVENTS bufp->modifiers = mac_event_to_emacs_modifiers (eventRef); @@ -8352,12 +8800,16 @@ dpyinfo->reference_count = 0; dpyinfo->resx = 75.0; dpyinfo->resy = 75.0; - dpyinfo->n_planes = 1; - dpyinfo->n_cbits = 16; + dpyinfo->color_p = TestDeviceAttribute (main_device_handle, gdDevType); + for (dpyinfo->n_planes = 32; dpyinfo->n_planes > 0; dpyinfo->n_planes >>= 1) + if (HasDepth (main_device_handle, dpyinfo->n_planes, + gdDevType, dpyinfo->color_p)) + break; dpyinfo->height = (**main_device_handle).gdRect.bottom; dpyinfo->width = (**main_device_handle).gdRect.right; dpyinfo->grabbed = 0; dpyinfo->root_window = NULL; + dpyinfo->image_cache = make_image_cache (); dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1; dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1; @@ -8696,6 +9148,18 @@ Qmac_ready_for_drag_n_drop = intern ("mac-ready-for-drag-n-drop"); staticpro (&Qmac_ready_for_drag_n_drop); + Qbig5 = intern ("big5"); + staticpro (&Qbig5); + + Qcn_gb = intern ("cn-gb"); + staticpro (&Qcn_gb); + + Qsjis = intern ("sjis"); + staticpro (&Qsjis); + + Qeuc_kr = intern ("euc-kr"); + staticpro (&Qeuc_kr); + DEFVAR_BOOL ("x-autoselect-window", &x_autoselect_window_p, doc: /* *Non-nil means autoselect window with mouse pointer. */); x_autoselect_window_p = 0;
--- a/src/macterm.h Thu Feb 26 11:14:34 2004 +0000 +++ b/src/macterm.h Thu Feb 26 17:46:48 2004 +0000 @@ -23,45 +23,26 @@ #include "macgui.h" #include "frame.h" -/* Include Carbon.h to define Cursor and Rect. */ -#ifdef HAVE_CARBON -#undef mktime -#undef DEBUG -#undef Z -#undef free -#undef malloc -#undef realloc -/* Macros max and min defined in lisp.h conflict with those in - precompiled header Carbon.h. */ -#undef max -#undef min -#undef init_process -#include <Carbon/Carbon.h> -#undef Z -#define Z (current_buffer->text->z) -#undef free -#define free unexec_free -#undef malloc -#define malloc unexec_malloc -#undef realloc -#define realloc unexec_realloc -#undef min -#define min(a, b) ((a) < (b) ? (a) : (b)) -#undef max -#define max(a, b) ((a) > (b) ? (a) : (b)) -#undef init_process -#define init_process emacs_init_process -#endif /* MAC_OSX */ - #define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b)) #define RED_FROM_ULONG(color) ((color) >> 16) #define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff) #define BLUE_FROM_ULONG(color) ((color) & 0xff) +/* Do not change `* 0x101' in the following lines to `<< 8'. If + changed, image masks in 1-bit depth will not work. */ +#define RED16_FROM_ULONG(color) (RED_FROM_ULONG(color) * 0x101) +#define GREEN16_FROM_ULONG(color) (GREEN_FROM_ULONG(color) * 0x101) +#define BLUE16_FROM_ULONG(color) (BLUE_FROM_ULONG(color) * 0x101) + #define BLACK_PIX_DEFAULT(f) RGB_TO_ULONG(0,0,0) #define WHITE_PIX_DEFAULT(f) RGB_TO_ULONG(255,255,255) +/* 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(f) BLACK_PIX_DEFAULT(f) +#define PIX_MASK_RETAIN(f) WHITE_PIX_DEFAULT(f) + #define FONT_WIDTH(f) ((f)->max_bounds.width) #define FONT_HEIGHT(f) ((f)->ascent + (f)->descent) #define FONT_BASE(f) ((f)->ascent) @@ -101,8 +82,13 @@ /* Number of planes on this screen. */ int n_planes; + /* Whether the screen supports color */ + int color_p; + +#if 0 /* Number of bits per pixel on this screen. */ int n_cbits; +#endif /* Dimensions of this screen. */ int height, width;
--- a/src/s/darwin.h Thu Feb 26 11:14:34 2004 +0000 +++ b/src/s/darwin.h Thu Feb 26 17:46:48 2004 +0000 @@ -247,7 +247,7 @@ page) to leave room at the end of the header for adding load commands. Needed for dumping. 0x690 is the total size of 30 segment load commands (at 56 each). */ -#define LD_SWITCH_SYSTEM_TEMACS -prebind -framework Carbon -lstdc++ -Xlinker -headerpad -Xlinker 690 +#define LD_SWITCH_SYSTEM_TEMACS -prebind -framework Carbon -framework QuickTime -lstdc++ -Xlinker -headerpad -Xlinker 690 #define C_SWITCH_SYSTEM_TEMACS -Dtemacs