2001-10-20 Miles Bader * dispextern.h (struct image): Add `background', `background_valid', and `background_transparent' fields. (image_background, image_background_transparent): New declarations. (IMAGE_BACKGROUND, IMAGE_BACKGROUND_TRANSPARENT): New macros. * xfns.c (image_background, image_background_transparent) (four_corners_best): New functions. (xpm_format, png_format, jpeg_format, tiff_format, gif_format) (gs_format): Add `:background' entry. (lookup_image): Set IMG's background color if specified. (pbm_load): Set IMG's background-color fields when appropriate. (xbm_load_image): (x_clear_image_1): Reset `background_valid' and `background_transparent_valid' fields. (x_build_heuristic_mask): Use IMAGE_BACKGROUND instead of calculating it here. Set IMG's background_transparent field. (enum xpm_keyword_index): Add XPM_BACKGROUND. (enum png_keyword_index): Add PNG_BACKGROUND. (enum jpeg_keyword_index): Add JPEG_BACKGROUND. (enum tiff_keyword_index): Add TIFF_BACKGROUND. (enum gif_keyword_index): Add GIF_BACKGROUND. (enum gs_keyword_index): Add GS_BACKGROUND. * xterm.c (x_setup_relief_colors): Use `IMAGE_BACKGROUND' and `IMAGE_BACKGROUND_TRANSPARENT' to calculate the correct background color to use for image glyph reliefs. Index: src/dispextern.h =================================================================== RCS file: /cvs/emacs/src/dispextern.h,v retrieving revision 1.113 diff -u -r1.113 dispextern.h --- src/dispextern.h 2001/10/24 09:10:57 1.113 +++ src/dispextern.h 2001/10/24 14:55:04 @@ -1985,6 +1985,20 @@ unsigned long *colors; int ncolors; + /* A single `background color' for this image, for the use of anyone that + cares about such a thing. Only valid if the `background_valid' field + is true. This should generally be accessed by calling the accessor + macro `IMAGE_BACKGROUND', which will heuristically calculate a value + if necessary. */ + unsigned long background; + /* True if this image has a `transparent' background -- that is, is + uses an image mask. The accessor macro for this is + `IMAGE_BACKGROUND_TRANSPARENT'. */ + unsigned background_transparent : 1; + /* True if the `background' and `background_transparent' fields are + valid, respectively. */ + unsigned background_valid : 1, background_transparent_valid : 1; + /* Width and height of the image. */ int width, height; @@ -2268,6 +2282,10 @@ int valid_image_p P_ ((Lisp_Object)); void prepare_image_for_display P_ ((struct frame *, struct image *)); int lookup_image P_ ((struct frame *, Lisp_Object)); +unsigned long image_background P_ ((struct image *, struct frame *, + XImage *ximg)); +int image_background_transparent P_ ((struct image *, struct frame *, + XImage *mask)); extern Lisp_Object tip_frame; extern Window tip_window; EXFUN (Fx_show_tip, 6); @@ -2275,6 +2293,22 @@ extern void start_hourglass P_ ((void)); extern void cancel_hourglass P_ ((void)); extern int display_hourglass_p; + +/* Returns the background color of IMG, calculating one heuristically if + necessary. If non-zero, XIMG is an existing XImage object to use for + the heuristic. */ +#define IMAGE_BACKGROUND(img, f, ximg) \ + ((img)->background_valid \ + ? (img)->background \ + : image_background (img, f, ximg)) + +/* Returns true if IMG has a `transparent' background, using heuristics + to decide if necessary. If non-zero, MASK is an existing XImage + object to use for the heuristic. */ +#define IMAGE_BACKGROUND_TRANSPARENT(img, f, mask) \ + ((img)->background_transparent_valid \ + ? (img)->background_transparent \ + : image_background_transparent (img, f, mask)) #endif /* HAVE_WINDOW_SYSTEM */ Index: src/xfns.c =================================================================== RCS file: /cvs/emacs/src/xfns.c,v retrieving revision 1.512 diff -u -r1.512 xfns.c --- src/xfns.c 2001/10/23 12:00:13 1.512 +++ src/xfns.c 2001/10/24 14:56:23 @@ -5768,6 +5768,99 @@ return ascent; } +static unsigned long +four_corners_best (ximg, width, height) + XImage *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; + XImage *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; + XImage *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); + + if (free_mask) + XDestroyImage (mask); + } + else + img->background_transparent = 0; + + img->background_transparent_valid = 1; + } + + return img->background_transparent; +} /*********************************************************************** @@ -5798,12 +5891,14 @@ { XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap); img->pixmap = None; + img->background_valid = 0; } if (mask_p && img->mask) { XFreePixmap (FRAME_X_DISPLAY (f), img->mask); img->mask = None; + img->background_transparent_valid = 0; } if (colors_p && img->ncolors) @@ -6133,8 +6228,9 @@ else { /* Handle image type independent image attributes - `:ascent ASCENT', `: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)) @@ -6162,6 +6258,18 @@ 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)) @@ -6876,9 +6984,8 @@ 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 (img->background_valid) + background = img->background; img->pixmap = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f), @@ -7081,6 +7188,7 @@ XPM_HEURISTIC_MASK, XPM_MASK, XPM_COLOR_SYMBOLS, + XPM_BACKGROUND, XPM_LAST }; @@ -7098,7 +7206,8 @@ {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":color-symbols", 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. */ @@ -8041,13 +8150,14 @@ { Display *dpy = FRAME_X_DISPLAY (f); XImage *ximg, *mask_img; - int x, y, rc, look_at_corners_p; + int x, y, rc, use_img_background; unsigned long bg = 0; if (img->mask) { XFreePixmap (FRAME_X_DISPLAY (f), img->mask); img->mask = None; + img->background_transparent_valid = 0; } /* Create an image and pixmap serving as mask. */ @@ -8061,9 +8171,8 @@ ~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)) { @@ -8089,35 +8198,13 @@ if (XLookupColor (dpy, cmap, color_name, &exact, &color)) { bg = color.pixel; - look_at_corners_p = 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 = IMAGE_BACKGROUND (img, f, ximg); /* Set all bits in mask_img to 1 whose color in ximg is different from the background color bg. */ @@ -8125,6 +8212,9 @@ for (x = 0; x < img->width; ++x) XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg); + /* 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); @@ -8381,9 +8471,9 @@ 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); + + if (img->background_valid) + bg = img->background; for (y = 0; y < height; ++y) for (x = 0; x < width; ++x) @@ -8491,6 +8581,7 @@ PNG_ALGORITHM, PNG_HEURISTIC_MASK, PNG_MASK, + PNG_BACKGROUND, PNG_LAST }; @@ -8508,6 +8599,7 @@ {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} }; /* Structure describing the image type `png'. */ @@ -8778,12 +8870,31 @@ simple transparency, we prefer a clipping mask. */ if (!transparent_p) { - png_color_16 *image_background; + png_color_16 *image_bg; + Lisp_Object specified_bg + = image_spec_value (img->spec, QCbackground, NULL); + + if (! NILP (specified_bg)) + /* The user specified `:background', use that. */ + { + XColor color; + if (x_defined_color (f, specified_bg, &color, 0)) + { + png_color_16 user_bg; + + bzero (&user_bg, sizeof user_bg); + user_bg.red = color.red; + user_bg.green = color.green; + user_bg.blue = color.blue; - if (png_get_bKGD (png_ptr, info_ptr, &image_background)) + 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 { @@ -8896,6 +9007,18 @@ } } + 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; + } + } + /* Remember colors allocated for this image. */ img->colors = colors_in_color_table (&img->ncolors); free_color_table (); @@ -8915,6 +9038,10 @@ /* 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); } @@ -8968,6 +9095,7 @@ JPEG_ALGORITHM, JPEG_HEURISTIC_MASK, JPEG_MASK, + JPEG_BACKGROUND, JPEG_LAST }; @@ -8984,7 +9112,8 @@ {":relief", IMAGE_INTEGER_VALUE, 0}, {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":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'. */ @@ -9323,6 +9452,7 @@ TIFF_ALGORITHM, TIFF_HEURISTIC_MASK, TIFF_MASK, + TIFF_BACKGROUND, TIFF_LAST }; @@ -9339,7 +9469,8 @@ {":relief", IMAGE_INTEGER_VALUE, 0}, {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":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'. */ @@ -9677,6 +9808,7 @@ GIF_HEURISTIC_MASK, GIF_MASK, GIF_IMAGE, + GIF_BACKGROUND, GIF_LAST }; @@ -9695,6 +9827,7 @@ {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 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'. */ @@ -9987,6 +10120,7 @@ GS_ALGORITHM, GS_HEURISTIC_MASK, GS_MASK, + GS_BACKGROUND, GS_LAST }; @@ -10006,7 +10140,8 @@ {":relief", IMAGE_INTEGER_VALUE, 0}, {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, - {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0} + {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, + {":background", IMAGE_STRING_OR_NIL_VALUE, 0} }; /* Structure describing the image type `ghostscript'. */ Index: src/xterm.c =================================================================== RCS file: /cvs/emacs/src/xterm.c,v retrieving revision 1.665 diff -u -r1.665 xterm.c --- src/xterm.c 2001/10/24 10:28:38 1.665 +++ src/xterm.c 2001/10/24 14:57:24 @@ -3823,6 +3823,9 @@ if (s->face->use_box_color_for_shadows_p) color = s->face->box_color; + else if (s->first_glyph->type == IMAGE_GLYPH + && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0)) + color = IMAGE_BACKGROUND (s->img, s->f, 0); else { XGCValues xgcv;