Mercurial > emacs
changeset 55540:30c03f9042b8
Support XPM on Carbon Emacs. Does not
depend on libXpm, but only supports XPM version 3 without
extensions.
author | Steven Tamm <steventamm@mac.com> |
---|---|
date | Wed, 12 May 2004 02:23:37 +0000 |
parents | db942c4b4345 |
children | 1cd6f125aac9 |
files | src/ChangeLog src/image.c |
diffstat | 2 files changed, 483 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/src/ChangeLog Wed May 12 01:40:05 2004 +0000 +++ b/src/ChangeLog Wed May 12 02:23:37 2004 +0000 @@ -1,3 +1,13 @@ +2004-05-11 Steven Tamm <tamm@Steven-Tamms-Computer.local> + + * image.c (xpm_scan, xpm_make_color_table_v, xpm_put_color_table_v) + (xpm_get_color_table_v, xpm_make_color_table_h) + (xpm_put_color_table_h, xpm_get_color_table_h) + (xpm_str_to_color_key, xpm_load_image, xpm_load) + (syms_of_image): Support XPM on Carbon Emacs. Does not + depend on libXpm, but only supports XPM version 3 without + extensions. + 2004-05-11 YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> * macterm.c (x_flush, XTframe_up_to_date): use FRAME_MAC_P
--- a/src/image.c Wed May 12 01:40:05 2004 +0000 +++ b/src/image.c Wed May 12 02:23:37 2004 +0000 @@ -3184,12 +3184,15 @@ XPM images ***********************************************************************/ -#ifdef HAVE_XPM +#if defined (HAVE_XPM) || defined (MAC_OS) static int xpm_image_p P_ ((Lisp_Object object)); static int xpm_load P_ ((struct frame *f, struct image *img)); static int xpm_valid_color_symbols_p P_ ((Lisp_Object)); +#endif /* HAVE_XPM || MAC_OS */ + +#ifdef HAVE_XPM #ifdef HAVE_NTGUI /* Indicate to xpm.h that we don't have Xlib. */ #define FOR_MSW @@ -3208,7 +3211,9 @@ #else #include "X11/xpm.h" #endif /* HAVE_NTGUI */ - +#endif /* HAVE_XPM */ + +#if defined (HAVE_XPM) || defined (MAC_OS) /* The symbol `xpm' identifying XPM-format images. */ Lisp_Object Qxpm; @@ -3536,10 +3541,13 @@ || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))); } +#endif /* HAVE_XPM || MAC_OS */ /* Load image IMG which will be displayed on frame F. Value is non-zero if successful. */ +#ifdef HAVE_XPM + static int xpm_load (f, img) struct frame *f; @@ -3771,6 +3779,467 @@ #endif /* HAVE_XPM */ +#ifdef MAC_OS + +/* XPM support functions for Mac OS where libxpm is not available. + Only XPM version 3 (without any extensions) is supported. */ + +static int xpm_scan P_ ((unsigned char **, unsigned char *, + unsigned char **, int *)); +static Lisp_Object xpm_make_color_table_v + P_ ((void (**) (Lisp_Object, unsigned char *, int, Lisp_Object), + Lisp_Object (**) (Lisp_Object, unsigned char *, int))); +static void xpm_put_color_table_v P_ ((Lisp_Object, unsigned char *, + int, Lisp_Object)); +static Lisp_Object xpm_get_color_table_v P_ ((Lisp_Object, + unsigned char *, int)); +static Lisp_Object xpm_make_color_table_h + P_ ((void (**) (Lisp_Object, unsigned char *, int, Lisp_Object), + Lisp_Object (**) (Lisp_Object, unsigned char *, int))); +static void xpm_put_color_table_h P_ ((Lisp_Object, unsigned char *, + int, Lisp_Object)); +static Lisp_Object xpm_get_color_table_h P_ ((Lisp_Object, + unsigned char *, int)); +static int xpm_str_to_color_key P_ ((char *)); +static int xpm_load_image P_ ((struct frame *, struct image *, + unsigned char *, unsigned char *)); + +/* Tokens returned from xpm_scan. */ + +enum xpm_token +{ + XPM_TK_IDENT = 256, + XPM_TK_STRING, + XPM_TK_EOF +}; + +/* Scan an XPM data and return a character (< 256) or a token defined + by enum xpm_token above. *S and END are the start (inclusive) and + the end (exclusive) addresses of the data, respectively. Advance + *S while scanning. If token is either XPM_TK_IDENT or + XPM_TK_STRING, *BEG and *LEN are set to the start address and the + length of the corresponding token, respectively. */ + +static int +xpm_scan (s, end, beg, len) + unsigned char **s, *end, **beg; + int *len; +{ + int c; + + while (*s < end) + { + /* Skip white-space. */ + while (*s < end && (c = *(*s)++, isspace (c))) + ; + + /* gnus-pointer.xpm uses '-' in its identifier. + sb-dir-plus.xpm uses '+' in its identifier. */ + if (isalpha (c) || c == '_' || c == '-' || c == '+') + { + *beg = *s - 1; + while (*s < end && + (c = **s, isalnum (c) || c == '_' || c == '-' || c == '+')) + ++*s; + *len = *s - *beg; + return XPM_TK_IDENT; + } + else if (c == '"') + { + *beg = *s; + while (*s < end && **s != '"') + ++*s; + *len = *s - *beg; + if (*s < end) + ++*s; + return XPM_TK_STRING; + } + else if (c == '/') + { + if (*s < end && **s == '*') + { + /* C-style comment. */ + ++*s; + do + { + while (*s < end && *(*s)++ != '*') + ; + } + while (*s < end && **s != '/'); + if (*s < end) + ++*s; + } + else + return c; + } + else + return c; + } + + return XPM_TK_EOF; +} + +/* Functions for color table lookup in XPM data. A Key is a string + specifying the color of each pixel in XPM data. A value is either + an integer that specifies a pixel color, Qt that specifies + transparency, or Qnil for the unspecified color. If the length of + the key string is one, a vector is used as a table. Otherwise, a + hash table is used. */ + +static Lisp_Object +xpm_make_color_table_v (put_func, get_func) + void (**put_func) (Lisp_Object, unsigned char *, int, Lisp_Object); + Lisp_Object (**get_func) (Lisp_Object, unsigned char *, int); +{ + *put_func = xpm_put_color_table_v; + *get_func = xpm_get_color_table_v; + return Fmake_vector (make_number (256), Qnil); +} + +static void +xpm_put_color_table_v (color_table, chars_start, chars_len, color) + Lisp_Object color_table; + unsigned char *chars_start; + int chars_len; + Lisp_Object color; +{ + XVECTOR (color_table)->contents[*chars_start] = color; +} + +static Lisp_Object +xpm_get_color_table_v (color_table, chars_start, chars_len) + Lisp_Object color_table; + unsigned char *chars_start; + int chars_len; +{ + return XVECTOR (color_table)->contents[*chars_start]; +} + +static Lisp_Object +xpm_make_color_table_h (put_func, get_func) + void (**put_func) (Lisp_Object, unsigned char *, int, Lisp_Object); + Lisp_Object (**get_func) (Lisp_Object, unsigned char *, int); +{ + *put_func = xpm_put_color_table_h; + *get_func = xpm_get_color_table_h; + return make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE), + make_float (DEFAULT_REHASH_SIZE), + make_float (DEFAULT_REHASH_THRESHOLD), + Qnil, Qnil, Qnil); +} + +static void +xpm_put_color_table_h (color_table, chars_start, chars_len, color) + Lisp_Object color_table; + unsigned char *chars_start; + int chars_len; + Lisp_Object color; +{ + struct Lisp_Hash_Table *table = XHASH_TABLE (color_table); + unsigned hash_code; + Lisp_Object chars = make_unibyte_string (chars_start, chars_len); + + hash_lookup (table, chars, &hash_code); + hash_put (table, chars, color, hash_code); +} + +static Lisp_Object +xpm_get_color_table_h (color_table, chars_start, chars_len) + Lisp_Object color_table; + unsigned char *chars_start; + int chars_len; +{ + struct Lisp_Hash_Table *table = XHASH_TABLE (color_table); + int i = hash_lookup (table, make_unibyte_string (chars_start, chars_len), + NULL); + + return i >= 0 ? HASH_VALUE (table, i) : Qnil; +} + +enum xpm_color_key { + XPM_COLOR_KEY_S, + XPM_COLOR_KEY_M, + XPM_COLOR_KEY_G4, + XPM_COLOR_KEY_G, + XPM_COLOR_KEY_C +}; + +static char xpm_color_key_strings[][4] = {"s", "m", "g4", "g", "c"}; + +static int +xpm_str_to_color_key (s) + char *s; +{ + int i; + + for (i = 0; + i < sizeof xpm_color_key_strings / sizeof xpm_color_key_strings[0]; + i++) + if (strcmp (xpm_color_key_strings[i], s) == 0) + return i; + return -1; +} + +static int +xpm_load_image (f, img, contents, end) + struct frame *f; + struct image *img; + unsigned char *contents, *end; +{ + unsigned char *s = contents, *beg, *str; + unsigned char buffer[BUFSIZ]; + int width, height, x, y; + int num_colors, chars_per_pixel; + int len, LA1; + void (*put_color_table) (Lisp_Object, unsigned char *, int, Lisp_Object); + Lisp_Object (*get_color_table) (Lisp_Object, unsigned char *, int); + Lisp_Object frame, color_symbols, color_table; + int best_key, have_mask = 0; + XImagePtr ximg = NULL, mask_img = NULL; + +#define match() \ + LA1 = xpm_scan (&s, end, &beg, &len) + +#define expect(TOKEN) \ + if (LA1 != (TOKEN)) \ + goto failure; \ + else \ + match () + +#define expect_ident(IDENT) \ + if (LA1 == XPM_TK_IDENT \ + && strlen ((IDENT)) == len && memcmp ((IDENT), beg, len) == 0) \ + match (); \ + else \ + goto failure + + if (!(end - s >= 9 && memcmp (s, "/* XPM */", 9) == 0)) + goto failure; + s += 9; + match(); + expect_ident ("static"); + expect_ident ("char"); + expect ('*'); + expect (XPM_TK_IDENT); + expect ('['); + expect (']'); + expect ('='); + expect ('{'); + expect (XPM_TK_STRING); + if (len >= BUFSIZ) + goto failure; + memcpy (buffer, beg, len); + buffer[len] = '\0'; + if (sscanf (buffer, "%d %d %d %d", &width, &height, + &num_colors, &chars_per_pixel) != 4 + || width <= 0 || height <= 0 + || num_colors <= 0 || chars_per_pixel <= 0) + goto failure; + expect (','); + + XSETFRAME (frame, f); + if (!NILP (Fxw_display_color_p (frame))) + best_key = XPM_COLOR_KEY_C; + else if (!NILP (Fx_display_grayscale_p (frame))) + best_key = (XFASTINT (Fx_display_planes (frame)) > 2 + ? XPM_COLOR_KEY_G : XPM_COLOR_KEY_G4); + else + best_key = XPM_COLOR_KEY_M; + + color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL); + if (chars_per_pixel == 1) + color_table = xpm_make_color_table_v (&put_color_table, + &get_color_table); + else + color_table = xpm_make_color_table_h (&put_color_table, + &get_color_table); + + while (num_colors-- > 0) + { + unsigned char *color, *max_color; + int key, next_key, max_key = 0; + Lisp_Object symbol_color = Qnil, color_val; + XColor cdef; + + expect (XPM_TK_STRING); + if (len <= chars_per_pixel || len >= BUFSIZ + chars_per_pixel) + goto failure; + memcpy (buffer, beg + chars_per_pixel, len - chars_per_pixel); + buffer[len - chars_per_pixel] = '\0'; + + str = strtok (buffer, " \t"); + if (str == NULL) + goto failure; + key = xpm_str_to_color_key (str); + if (key < 0) + goto failure; + do + { + color = strtok (NULL, " \t"); + if (color == NULL) + goto failure; + + while (str = strtok (NULL, " \t")) + { + next_key = xpm_str_to_color_key (str); + if (next_key >= 0) + break; + color[strlen (color)] = ' '; + } + + if (key == XPM_COLOR_KEY_S) + { + if (NILP (symbol_color)) + symbol_color = build_string (color); + } + else if (max_key < key && key <= best_key) + { + max_key = key; + max_color = color; + } + key = next_key; + } + while (str); + + color_val = Qnil; + if (!NILP (color_symbols) && !NILP (symbol_color)) + { + Lisp_Object specified_color = Fassoc (symbol_color, color_symbols); + + if (CONSP (specified_color) && STRINGP (XCDR (specified_color))) + if (xstricmp (SDATA (XCDR (specified_color)), "None") == 0) + color_val = Qt; + else if (x_defined_color (f, SDATA (XCDR (specified_color)), + &cdef, 0)) + color_val = make_number (cdef.pixel); + } + if (NILP (color_val) && max_key > 0) + if (xstricmp (max_color, "None") == 0) + color_val = Qt; + else if (x_defined_color (f, max_color, &cdef, 0)) + color_val = make_number (cdef.pixel); + if (!NILP (color_val)) + (*put_color_table) (color_table, beg, chars_per_pixel, color_val); + + expect (','); + } + + if (!x_create_x_image_and_pixmap (f, width, height, 0, + &ximg, &img->pixmap) + || !x_create_x_image_and_pixmap (f, width, height, 1, + &mask_img, &img->mask)) + { + image_error ("Out of memory (%s)", img->spec, Qnil); + goto error; + } + + for (y = 0; y < height; y++) + { + expect (XPM_TK_STRING); + str = beg; + if (len < width * chars_per_pixel) + goto failure; + for (x = 0; x < width; x++, str += chars_per_pixel) + { + Lisp_Object color_val = + (*get_color_table) (color_table, str, chars_per_pixel); + + XPutPixel (ximg, x, y, + (INTEGERP (color_val) ? XINT (color_val) + : FRAME_FOREGROUND_PIXEL (f))); + XPutPixel (mask_img, x, y, + (!EQ (color_val, Qt) ? PIX_MASK_DRAW (f) + : (have_mask = 1, PIX_MASK_RETAIN (f)))); + } + if (y + 1 < height) + expect (','); + } + + img->width = width; + img->height = height; + + x_put_x_image (f, ximg, img->pixmap, width, height); + x_destroy_x_image (ximg); + if (have_mask) + { + x_put_x_image (f, mask_img, img->mask, width, height); + x_destroy_x_image (mask_img); + } + else + { + x_destroy_x_image (mask_img); + Free_Pixmap (FRAME_X_DISPLAY (f), img->mask); + img->mask = NO_PIXMAP; + } + + return 1; + + failure: + image_error ("Invalid XPM file (%s)", img->spec, Qnil); + error: + x_destroy_x_image (ximg); + x_destroy_x_image (mask_img); + x_clear_image (f, img); + return 0; + +#undef match +#undef expect +#undef expect_ident +} + +static int +xpm_load (f, img) + struct frame *f; + struct image *img; +{ + int success_p = 0; + Lisp_Object file_name; + + /* If IMG->spec specifies a file name, create a non-file spec from it. */ + file_name = image_spec_value (img->spec, QCfile, NULL); + if (STRINGP (file_name)) + { + Lisp_Object file; + unsigned 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 XPM image `%s'", img->spec, Qnil); + UNGCPRO; + return 0; + } + + success_p = xpm_load_image (f, img, contents, contents + size); + xfree (contents); + UNGCPRO; + } + else + { + Lisp_Object data; + + data = image_spec_value (img->spec, QCdata, NULL); + success_p = xpm_load_image (f, img, SDATA (data), + SDATA (data) + SBYTES (data)); + } + + return success_p; +} + +#endif /* MAC_OS */ + + /*********************************************************************** Color table @@ -7447,7 +7916,7 @@ Qxbm = intern ("xbm"); staticpro (&Qxbm); -#ifdef HAVE_XPM +#if defined (HAVE_XPM) || defined (MAC_OS) Qxpm = intern ("xpm"); staticpro (&Qxpm); #endif @@ -7517,7 +7986,7 @@ define_image_type (&xbm_type); define_image_type (&pbm_type); -#ifdef HAVE_XPM +#if defined (HAVE_XPM) || defined (MAC_OS) IF_LIB_AVAILABLE(init_xpm_functions) define_image_type (&xpm_type); #endif