From: Alan Third <alan@idiocy.org>
To: Eli Zaretskii <eliz@gnu.org>
Cc: emacs-devel@gnu.org
Subject: Re: Linking to ImageMagick by default
Date: Thu, 27 Dec 2018 13:11:05 +0000 [thread overview]
Message-ID: <20181227131105.GA18792@breton.holly.idiocy.org> (raw)
In-Reply-To: <83efadcw3j.fsf@gnu.org>
[-- Attachment #1: Type: text/plain, Size: 824 bytes --]
On Wed, Dec 19, 2018 at 06:36:16PM +0200, Eli Zaretskii wrote:
> I think you should use Fcons instead of list3 or list2.
Thanks Eli! I got there eventually using Fcons.
I’ve now run into another issue. Now that I’m stripping the image spec
down to the basics when I load an image in image mode and then use +
or - to resize, it doesn’t redraw.
It redraws correctly if you cause a redraw, by scrolling the window,
or making an animated gif animate, or similar.
I think that during redisplay something must be looking at the image
and deciding it hasn’t changed, but I can’t find anything like that.
Patch attached. It probably won’t build on Windows, unfortunately.
I’ve yet to look at that code properly, and I don’t have a Windows
build environment, but I expect it to work on X and NS.
--
Alan Third
[-- Attachment #2: 0001-Add-native-image-scaling.patch --]
[-- Type: text/plain, Size: 52631 bytes --]
From 8644aace35436d4e92f5c998003072b4b345f8ab Mon Sep 17 00:00:00 2001
From: Alan Third <alan@idiocy.org>
Date: Mon, 10 Dec 2018 19:43:08 +0000
Subject: [PATCH] Add native image scaling
* configure.ac: Test for XRender outside of xft checks.
* src/Makefile.in (XRENDER_LIBS): List XRender libs separately from
xft libs.
* lisp/image.el (image--get-imagemagick-and-warn): Remove ImageMagick
checks and on't flush the image cache as often.
* src/image.c (get_cache_spec):
(calc_image_spec): New function.
(Fimage_flush): Use the modified image spec.
(image_ascent):
(Fimage_size): Replace struct image with struct image_spec.
(make_image): Remove members that are image independent.
(scale_image_size):
(compute_image_size): Make available when image resizing of any sort
is available.
(lookup_image): Use new cache_spec for lookups and remove image
independent code.
* src/dispextern.h (struct image_spec): New struct.
(struct it):
(struct glyph): Replace an image_id with struct image_spec.
(struct glyph_string): Add struct image_spec.
(struct image): Remove members that are image independent.
(calc_image_spec): New function.
(image_ascent): Replace struct image with struct image_spec.
* src/dispnew.c (buffer_posn_from_coords):
(mode_line_string):
(marginal_area_string): Replace struct image.
* src/nsimage.m (ns_load_image):
([EmacsImage setSizeFromSpec:]): Remove NS specific image resizing.
* src/nsterm.m (ns_draw_fringe_bitmap): Remove GNUstep specific code.
(ns_dumpglyphs_image): Composite image according to sizes in new
image_prop struct.
* src/w32term.c (x_draw_image_foreground):
(x_draw_image_relief):
(w32_draw_image_foreground_1): Replace struct image with struct image_spec.
* src/xdisp.c (handle_single_display_spec):
(push_it):
(pop_it):
(dump_glyph):
(push_prefix_prop):
(calc_pixel_width_or_height):
(fill_image_glyph_string):
(produce_image_glyph):
(get_window_cursor_type): Replace struct image with struct image_spec.
(note_mouse_highlight): Use the image spec stored in the glyph struct
rather than the one attached to the image struct.
* src/xterm.c (x_composite_image): New function.
(x_draw_image_foreground): Replace struct image with struct image_spec
and use new x_composite_image function.
(x_draw_image_relief):
(x_draw_image_foreground_1):
(x_draw_image_glyph_string): Replace struct image with struct image_spec.
---
configure.ac | 14 +-
lisp/image.el | 3 -
src/Makefile.in | 3 +-
src/dispextern.h | 48 +++---
src/dispnew.c | 32 +---
src/image.c | 374 +++++++++++++++++++++++++++++------------------
src/nsimage.m | 62 --------
src/nsterm.h | 1 -
src/nsterm.m | 36 ++---
src/w32term.c | 6 +-
src/xdisp.c | 86 ++++++-----
src/xterm.c | 108 +++++++++-----
12 files changed, 417 insertions(+), 356 deletions(-)
diff --git a/configure.ac b/configure.ac
index 8b34c3b658..2b22e2cbc2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3241,6 +3241,17 @@ AC_DEFUN
CFLAGS=$late_CFLAGS
fi
+# Check for XRender
+HAVE_XRENDER=no
+if test "${HAVE_X11}" = "yes"; then
+ AC_CHECK_LIB(Xrender, XRenderQueryExtension, HAVE_XRENDER=yes)
+ if test $HAVE_XRENDER = yes; then
+ XRENDER_LIBS="-lXrender"
+ AC_SUBST(XRENDER_LIBS)
+ AC_DEFINE([HAVE_XRENDER], 1, [Define to 1 if XRender is available.])
+ fi
+fi
+
### Start of font-backend (under any platform) section.
# (nothing here yet -- this is a placeholder)
### End of font-backend (under any platform) section.
@@ -3263,15 +3274,12 @@ AC_DEFUN
EMACS_CHECK_MODULES([XFT], [xft >= 0.13.0], [], [HAVE_XFT=no])
## Because xterm.c uses XRenderQueryExtension when XFT is
## enabled, we also need to link to -lXrender.
- HAVE_XRENDER=no
- AC_CHECK_LIB(Xrender, XRenderQueryExtension, HAVE_XRENDER=yes)
if test "$HAVE_XFT" != no && test "$HAVE_XRENDER" != no; then
OLD_CPPFLAGS="$CPPFLAGS"
OLD_CFLAGS="$CFLAGS"
OLD_LIBS="$LIBS"
CPPFLAGS="$CPPFLAGS $XFT_CFLAGS"
CFLAGS="$CFLAGS $XFT_CFLAGS"
- XFT_LIBS="-lXrender $XFT_LIBS"
LIBS="$XFT_LIBS $LIBS"
AC_CHECK_HEADER(X11/Xft/Xft.h,
AC_CHECK_LIB(Xft, XftFontOpen, HAVE_XFT=yes, , $XFT_LIBS) , ,
diff --git a/lisp/image.el b/lisp/image.el
index 74a23046e9..4843c2de1f 100644
--- a/lisp/image.el
+++ b/lisp/image.el
@@ -982,10 +982,7 @@ image--get-image
image))
(defun image--get-imagemagick-and-warn ()
- (unless (or (fboundp 'imagemagick-types) (featurep 'ns))
- (error "Cannot rescale images without ImageMagick support"))
(let ((image (image--get-image)))
- (image-flush image)
(when (fboundp 'imagemagick-types)
(plist-put (cdr image) :type 'imagemagick))
image))
diff --git a/src/Makefile.in b/src/Makefile.in
index 6b2e54a160..809a484413 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -127,7 +127,8 @@ LIBIMAGE=
XCB_LIBS=@XCB_LIBS@
XFT_LIBS=@XFT_LIBS@
-LIBX_EXTRA=-lX11 $(XCB_LIBS) $(XFT_LIBS)
+XRENDER_LIBS=@XRENDER_LIBS@
+LIBX_EXTRA=-lX11 $(XCB_LIBS) $(XFT_LIBS) $(XRENDER_LIBS)
FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
diff --git a/src/dispextern.h b/src/dispextern.h
index 4cd017603d..877948ee97 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -172,6 +172,30 @@ extern bool trace_redisplay_p EXTERNALLY_VISIBLE;
\f
+/* Struct for use by display functions. Contains the desired size of
+ the image, derived from the display properties. */
+
+struct image_spec
+{
+ ptrdiff_t image_id;
+ int width;
+ int height;
+
+ /* Relief to draw around the image. */
+ int relief;
+
+ /* Optional margins around the image. This includes the relief. */
+ int hmargin, vmargin;
+
+ /* Percent of image height used as ascent. A value of
+ CENTERED_IMAGE_ASCENT means draw the image centered on the
+ line. */
+ int ascent;
+#define DEFAULT_IMAGE_ASCENT 50
+#define CENTERED_IMAGE_ASCENT -1
+};
+
+\f
/***********************************************************************
Text positions
***********************************************************************/
@@ -505,7 +529,7 @@ struct glyph
} cmp;
/* Image ID for image glyphs (type == IMAGE_GLYPH). */
- int img_id;
+ struct image_spec image;
#ifdef HAVE_XWIDGETS
/* Xwidget reference (type == XWIDGET_GLYPH). */
@@ -1361,6 +1385,7 @@ struct glyph_string
/* Image, if any. */
struct image *img;
+ struct image_spec image;
/* Xwidget. */
struct xwidget *xwidget;
@@ -2373,7 +2398,7 @@ struct it
struct {
Lisp_Object object;
struct it_slice slice;
- ptrdiff_t image_id;
+ struct image_spec image;
} image;
/* method == GET_FROM_STRETCH */
struct {
@@ -2509,7 +2534,7 @@ struct it
enum glyphless_display_method glyphless_method;
/* If what == IT_IMAGE, the id of the image to display. */
- ptrdiff_t image_id;
+ struct image_spec image;
/* If what == IT_XWIDGET. */
struct xwidget *xwidget;
@@ -3001,13 +3026,6 @@ struct image
#define BOT_CORNER 2
#define RIGHT_CORNER 3
- /* Percent of image height used as ascent. A value of
- CENTERED_IMAGE_ASCENT means draw the image centered on the
- line. */
- int ascent;
-#define DEFAULT_IMAGE_ASCENT 50
-#define CENTERED_IMAGE_ASCENT -1
-
/* Lisp specification of this image. */
Lisp_Object spec;
@@ -3016,12 +3034,6 @@ struct image
Used to allow fine-grained cache flushing. */
Lisp_Object dependencies;
- /* Relief to draw around the image. */
- int relief;
-
- /* Optional margins around the image. This includes the relief. */
- int hmargin, vmargin;
-
/* Reference to the type of the image. */
struct image_type *type;
@@ -3042,7 +3054,6 @@ struct image
struct image *next, *prev;
};
-
/* Cache of images. Each frame has a cache. X frames with the same
x_display_info share their caches. */
@@ -3358,6 +3369,7 @@ void clear_image_caches (Lisp_Object);
void mark_image_cache (struct image_cache *);
bool valid_image_p (Lisp_Object);
void prepare_image_for_display (struct frame *, struct image *);
+struct image_spec calc_image_spec (struct frame *f, Lisp_Object spec);
ptrdiff_t lookup_image (struct frame *, Lisp_Object);
#if defined (HAVE_X_WINDOWS) || defined (HAVE_NS)
@@ -3373,7 +3385,7 @@ RGB_PIXEL_COLOR image_background (struct image *, struct frame *,
int image_background_transparent (struct image *, struct frame *,
XImagePtr_or_DC mask);
-int image_ascent (struct image *, struct face *, struct glyph_slice *);
+int image_ascent (struct image_spec, struct face *, struct glyph_slice *);
#endif
diff --git a/src/dispnew.c b/src/dispnew.c
index b628c694e8..4f374928eb 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -5117,9 +5117,6 @@ buffer_posn_from_coords (struct window *w, int *x, int *y, struct display_pos *p
struct text_pos startp;
Lisp_Object string;
struct glyph_row *row;
-#ifdef HAVE_WINDOW_SYSTEM
- struct image *img = 0;
-#endif
int x0, x1, to_x, it_vpos;
void *itdata = NULL;
@@ -5213,17 +5210,8 @@ buffer_posn_from_coords (struct window *w, int *x, int *y, struct display_pos *p
}
#ifdef HAVE_WINDOW_SYSTEM
- if (it.what == IT_IMAGE)
- {
- /* Note that this ignores images that are fringe bitmaps,
- because their image ID is zero, and so IMAGE_OPT_FROM_ID will
- return NULL. This is okay, since fringe bitmaps are not
- displayed in the text area, and so are never the object we
- are interested in. */
- img = IMAGE_OPT_FROM_ID (it.f, it.image_id);
- if (img && !NILP (img->spec))
- *object = img->spec;
- }
+ if (it.what == IT_IMAGE && !NILP (it.object))
+ *object = it.object;
#endif
/* IT's vpos counts from the glyph row that includes the window's
@@ -5239,14 +5227,14 @@ buffer_posn_from_coords (struct window *w, int *x, int *y, struct display_pos *p
{
struct glyph *glyph = row->glyphs[TEXT_AREA] + it.hpos;
#ifdef HAVE_WINDOW_SYSTEM
- if (img)
+ if (it.what == IT_IMAGE)
{
*dy -= row->ascent - glyph->ascent;
*dx += glyph->slice.img.x;
*dy += glyph->slice.img.y;
/* Image slices positions are still relative to the entire image */
- *width = img->width;
- *height = img->height;
+ *width = it.image.width;
+ *height = it.image.height;
}
else
#endif
@@ -5317,10 +5305,7 @@ mode_line_string (struct window *w, enum window_part part,
#ifdef HAVE_WINDOW_SYSTEM
if (glyph->type == IMAGE_GLYPH)
{
- struct image *img;
- img = IMAGE_OPT_FROM_ID (WINDOW_XFRAME (w), glyph->u.img_id);
- if (img != NULL)
- *object = img->spec;
+ *object = glyph->object;
y0 -= row->ascent - glyph->ascent;
}
#endif
@@ -5404,10 +5389,7 @@ marginal_area_string (struct window *w, enum window_part part,
#ifdef HAVE_WINDOW_SYSTEM
if (glyph->type == IMAGE_GLYPH)
{
- struct image *img;
- img = IMAGE_OPT_FROM_ID (WINDOW_XFRAME (w), glyph->u.img_id);
- if (img != NULL)
- *object = img->spec;
+ *object = glyph->object;
y0 -= row->ascent - glyph->ascent;
x0 += glyph->slice.img.x;
y0 += glyph->slice.img.y;
diff --git a/src/image.c b/src/image.c
index 218626f771..7900d3a2bc 100644
--- a/src/image.c
+++ b/src/image.c
@@ -901,11 +901,14 @@ or omitted means use the selected frame. */)
size = Qnil;
if (valid_image_p (spec))
{
+ struct image_spec image;
+ int width, height;
struct frame *f = decode_window_system_frame (frame);
- ptrdiff_t 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;
+
+ image = calc_image_spec (f, spec);
+
+ width = image.width + 2 * image.hmargin;
+ height = image.height + 2 * image.vmargin;
if (NILP (pixels))
size = Fcons (make_float ((double) width / FRAME_COLUMN_WIDTH (f)),
@@ -984,7 +987,6 @@ make_image (Lisp_Object spec, EMACS_UINT hash)
eassert (img->type != NULL);
img->spec = spec;
img->lisp_data = Qnil;
- img->ascent = DEFAULT_IMAGE_ASCENT;
img->hash = hash;
img->corners[BOT_CORNER] = -1; /* Full image */
return img;
@@ -1082,19 +1084,19 @@ prepare_image_for_display (struct frame *f, struct image *img)
drawn in face FACE. */
int
-image_ascent (struct image *img, struct face *face, struct glyph_slice *slice)
+image_ascent (struct image_spec img, struct face *face, struct glyph_slice *slice)
{
int height;
int ascent;
- if (slice->height == img->height)
- height = img->height + img->vmargin;
+ if (slice->height == img.height)
+ height = img.height + img.vmargin;
else if (slice->y == 0)
- height = slice->height + img->vmargin;
+ height = slice->height + img.vmargin;
else
height = slice->height;
- if (img->ascent == CENTERED_IMAGE_ASCENT)
+ if (img.ascent == CENTERED_IMAGE_ASCENT)
{
if (face->font)
{
@@ -1116,7 +1118,7 @@ image_ascent (struct image *img, struct face *face, struct glyph_slice *slice)
ascent = height / 2;
}
else
- ascent = height * (img->ascent / 100.0);
+ ascent = height * (img.ascent / 100.0);
return ascent;
}
@@ -1453,6 +1455,46 @@ make_image_cache (void)
return c;
}
+/* Filter the SPEC so it can be used to look up images in the cache
+ without worrying about whether they are the same size, etc. */
+
+static Lisp_Object
+get_cache_spec (Lisp_Object spec)
+{
+ Lisp_Object cache_spec, tail;
+
+ /* If type is imagemagick then the image will already be resized and
+ rotated, etc., so just return the full spec.
+
+ FIXME: I think we still want to strip out the likes of margin, as
+ that is not part of the image. */
+ if (EQ (image_spec_value (spec, QCtype, NULL), Qimagemagick))
+ return spec;
+
+ cache_spec = Qnil;
+
+ for (tail = XCDR (spec);
+ CONSP (tail) && CONSP (XCDR (tail));
+ tail = XCDR (XCDR (tail)))
+ {
+ Lisp_Object property = XCAR (tail);
+ Lisp_Object value = XCAR (XCDR (tail));
+
+ /* FIXME: Surely there's a better way to do this? */
+ if (!EQ (property, QCwidth)
+ && !EQ (property, QCheight)
+ && !EQ (property, QCmax_width)
+ && !EQ (property, QCmax_height)
+ && !EQ (property, QCscale)
+ && !EQ (property, QCmargin)
+ && !EQ (property, QCascent)
+ && !EQ (property, QCrelief))
+ cache_spec = Fcons (property, Fcons (value, cache_spec));
+ }
+ cache_spec = Fcons (XCAR (spec), cache_spec);
+
+ return cache_spec;
+}
/* Find an image matching SPEC in the cache, and return it. If no
image is found, return NULL. */
@@ -1661,6 +1703,8 @@ FRAME t means refresh the image on all frames. */)
if (!valid_image_p (spec))
error ("Invalid image specification");
+ spec = get_cache_spec (spec);
+
if (EQ (frame, Qt))
{
Lisp_Object tail;
@@ -1747,6 +1791,176 @@ postprocess_image (struct frame *f, struct image *img)
}
}
+#if defined (HAVE_IMAGEMAGICK) || defined (HAVE_XRENDER) || defined (HAVE_NS)
+/* Scale an image size by returning SIZE / DIVISOR * MULTIPLIER,
+ safely rounded and clipped to int range. */
+
+static int
+scale_image_size (int size, size_t divisor, size_t multiplier)
+{
+ if (divisor != 0)
+ {
+ double s = size;
+ double scaled = s * multiplier / divisor + 0.5;
+ if (scaled < INT_MAX)
+ return scaled;
+ }
+ return INT_MAX;
+}
+
+/* Compute the desired size of an image with native size WIDTH x HEIGHT.
+ Use SPEC to deduce the size. Store the desired size into
+ *D_WIDTH x *D_HEIGHT. Store -1 x -1 if the native size is OK. */
+static void
+compute_image_size (size_t width, size_t height,
+ Lisp_Object spec,
+ int *d_width, int *d_height)
+{
+ Lisp_Object value;
+ int desired_width = -1, desired_height = -1, max_width = -1, max_height = -1;
+ double scale = 1;
+
+ value = image_spec_value (spec, QCscale, NULL);
+ if (NUMBERP (value))
+ scale = XFLOATINT (value);
+
+ value = image_spec_value (spec, QCmax_width, NULL);
+ if (FIXNATP (value))
+ max_width = min (XFIXNAT (value), INT_MAX);
+
+ value = image_spec_value (spec, QCmax_height, NULL);
+ if (FIXNATP (value))
+ max_height = min (XFIXNAT (value), INT_MAX);
+
+ /* If width and/or height is set in the display spec assume we want
+ to scale to those values. If either h or w is unspecified, the
+ unspecified should be calculated from the specified to preserve
+ aspect ratio. */
+ value = image_spec_value (spec, QCwidth, NULL);
+ if (FIXNATP (value))
+ {
+ desired_width = min (XFIXNAT (value) * scale, INT_MAX);
+ /* :width overrides :max-width. */
+ max_width = -1;
+ }
+
+ value = image_spec_value (spec, QCheight, NULL);
+ if (FIXNATP (value))
+ {
+ desired_height = min (XFIXNAT (value) * scale, INT_MAX);
+ /* :height overrides :max-height. */
+ max_height = -1;
+ }
+
+ /* If we have both width/height set explicitly, we skip past all the
+ aspect ratio-preserving computations below. */
+ if (desired_width != -1 && desired_height != -1)
+ goto out;
+
+ width = width * scale;
+ height = height * scale;
+
+ if (desired_width != -1)
+ /* Width known, calculate height. */
+ desired_height = scale_image_size (desired_width, width, height);
+ else if (desired_height != -1)
+ /* Height known, calculate width. */
+ desired_width = scale_image_size (desired_height, height, width);
+ else
+ {
+ desired_width = width;
+ desired_height = height;
+ }
+
+ if (max_width != -1 && desired_width > max_width)
+ {
+ /* The image is wider than :max-width. */
+ desired_width = max_width;
+ desired_height = scale_image_size (desired_width, width, height);
+ }
+
+ if (max_height != -1 && desired_height > max_height)
+ {
+ /* The image is higher than :max-height. */
+ desired_height = max_height;
+ desired_width = scale_image_size (desired_height, height, width);
+ }
+
+ out:
+ *d_width = desired_width;
+ *d_height = desired_height;
+}
+#endif /* HAVE_IMAGEMAGICK || HAVE_XRENDER || HAVE_NS */
+
+struct image_spec
+calc_image_spec (struct frame *f, Lisp_Object spec)
+{
+ struct image_spec img_spec;
+ struct image *img;
+
+ Lisp_Object ascent, margin, relief;
+ int relief_bound;
+
+ img_spec.image_id = lookup_image (f, spec);
+ img = IMAGE_OPT_FROM_ID (f, img_spec.image_id);
+
+#if defined (HAVE_XRENDER) || defined (HAVE_NS)
+ if (!EQ (image_spec_value (spec, QCtype, NULL), Qimagemagick))
+ {
+ int width, height;
+
+ compute_image_size (img->width, img->height, spec, &width, &height);
+
+ /* Set the final sizes. We always maintain the aspect ratio. */
+ img_spec.width = width;
+ img_spec.height = height;
+ }
+ else
+#endif
+ {
+ /* We don't have built-in image resizing or we're using
+ ImageMagick which does its own transforms. */
+ img_spec.width = img->width;
+ img_spec.height = img->height;
+ }
+
+ /* Handle type independent image attributes
+ `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF'. */
+ ascent = image_spec_value (spec, QCascent, NULL);
+ if (FIXNUMP (ascent))
+ img_spec.ascent = XFIXNAT (ascent);
+ else if (EQ (ascent, Qcenter))
+ img_spec.ascent = CENTERED_IMAGE_ASCENT;
+ else
+ img_spec.ascent = DEFAULT_IMAGE_ASCENT;
+
+ margin = image_spec_value (spec, QCmargin, NULL);
+ if (FIXNUMP (margin))
+ img_spec.vmargin = img_spec.hmargin = XFIXNAT (margin);
+ else if (CONSP (margin))
+ {
+ img_spec.hmargin = XFIXNAT (XCAR (margin));
+ img_spec.vmargin = XFIXNAT (XCDR (margin));
+ }
+ else
+ {
+ img_spec.hmargin = 0;
+ img_spec.vmargin = 0;
+ }
+
+ relief = image_spec_value (spec, QCrelief, NULL);
+ relief_bound = INT_MAX - max (img_spec.hmargin, img_spec.vmargin);
+ if (RANGED_FIXNUMP (- relief_bound, relief, relief_bound))
+ {
+ img_spec.relief = XFIXNUM (relief);
+ img_spec.hmargin += eabs (img_spec.relief);
+ img_spec.vmargin += eabs (img_spec.relief);
+ }
+ else
+ img_spec.relief = 0;
+
+ return img_spec;
+}
/* Return the id of image with Lisp specification SPEC on frame F.
SPEC must be a valid Lisp image specification (see valid_image_p). */
@@ -1756,15 +1970,18 @@ lookup_image (struct frame *f, Lisp_Object spec)
{
struct image *img;
EMACS_UINT hash;
+ Lisp_Object cache_spec;
/* F must be a window-system frame, and SPEC must be a valid image
specification. */
eassert (FRAME_WINDOW_P (f));
eassert (valid_image_p (spec));
+ cache_spec = get_cache_spec (spec);
+
/* Look up SPEC in the hash table of the image cache. */
- hash = sxhash (spec, 0);
- img = search_image_cache (f, spec, hash);
+ hash = sxhash (cache_spec, 0);
+ img = search_image_cache (f, cache_spec, hash);
if (img && img->load_failed_p)
{
free_image (f, img);
@@ -1775,7 +1992,7 @@ lookup_image (struct frame *f, Lisp_Object spec)
if (img == NULL)
{
block_input ();
- img = make_image (spec, hash);
+ img = make_image (cache_spec, hash);
cache_image (f, img);
img->load_failed_p = ! img->type->load (f, img);
img->frame_foreground = FRAME_FOREGROUND_PIXEL (f);
@@ -1797,35 +2014,9 @@ lookup_image (struct frame *f, Lisp_Object spec)
}
else
{
- /* Handle image type independent image attributes
- `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF',
+ /* Handle image type independent image attribute
`:background COLOR'. */
- Lisp_Object ascent, margin, relief, bg;
- int relief_bound;
-
- ascent = image_spec_value (spec, QCascent, NULL);
- if (FIXNUMP (ascent))
- img->ascent = XFIXNAT (ascent);
- else if (EQ (ascent, Qcenter))
- img->ascent = CENTERED_IMAGE_ASCENT;
-
- margin = image_spec_value (spec, QCmargin, NULL);
- if (FIXNUMP (margin))
- img->vmargin = img->hmargin = XFIXNAT (margin);
- else if (CONSP (margin))
- {
- img->hmargin = XFIXNAT (XCAR (margin));
- img->vmargin = XFIXNAT (XCDR (margin));
- }
-
- relief = image_spec_value (spec, QCrelief, NULL);
- relief_bound = INT_MAX - max (img->hmargin, img->vmargin);
- if (RANGED_FIXNUMP (- relief_bound, relief, relief_bound))
- {
- img->relief = XFIXNUM (relief);
- img->hmargin += eabs (img->relief);
- img->vmargin += eabs (img->relief);
- }
+ Lisp_Object bg;
if (! img->background_valid)
{
@@ -8101,105 +8292,6 @@ gif_load (struct frame *f, struct image *img)
ImageMagick
***********************************************************************/
-/* Scale an image size by returning SIZE / DIVISOR * MULTIPLIER,
- safely rounded and clipped to int range. */
-
-static int
-scale_image_size (int size, size_t divisor, size_t multiplier)
-{
- if (divisor != 0)
- {
- double s = size;
- double scaled = s * multiplier / divisor + 0.5;
- if (scaled < INT_MAX)
- return scaled;
- }
- return INT_MAX;
-}
-
-/* Compute the desired size of an image with native size WIDTH x HEIGHT.
- Use SPEC to deduce the size. Store the desired size into
- *D_WIDTH x *D_HEIGHT. Store -1 x -1 if the native size is OK. */
-static void
-compute_image_size (size_t width, size_t height,
- Lisp_Object spec,
- int *d_width, int *d_height)
-{
- Lisp_Object value;
- int desired_width = -1, desired_height = -1, max_width = -1, max_height = -1;
- double scale = 1;
-
- value = image_spec_value (spec, QCscale, NULL);
- if (NUMBERP (value))
- scale = XFLOATINT (value);
-
- value = image_spec_value (spec, QCmax_width, NULL);
- if (FIXNATP (value))
- max_width = min (XFIXNAT (value), INT_MAX);
-
- value = image_spec_value (spec, QCmax_height, NULL);
- if (FIXNATP (value))
- max_height = min (XFIXNAT (value), INT_MAX);
-
- /* If width and/or height is set in the display spec assume we want
- to scale to those values. If either h or w is unspecified, the
- unspecified should be calculated from the specified to preserve
- aspect ratio. */
- value = image_spec_value (spec, QCwidth, NULL);
- if (FIXNATP (value))
- {
- desired_width = min (XFIXNAT (value) * scale, INT_MAX);
- /* :width overrides :max-width. */
- max_width = -1;
- }
-
- value = image_spec_value (spec, QCheight, NULL);
- if (FIXNATP (value))
- {
- desired_height = min (XFIXNAT (value) * scale, INT_MAX);
- /* :height overrides :max-height. */
- max_height = -1;
- }
-
- /* If we have both width/height set explicitly, we skip past all the
- aspect ratio-preserving computations below. */
- if (desired_width != -1 && desired_height != -1)
- goto out;
-
- width = width * scale;
- height = height * scale;
-
- if (desired_width != -1)
- /* Width known, calculate height. */
- desired_height = scale_image_size (desired_width, width, height);
- else if (desired_height != -1)
- /* Height known, calculate width. */
- desired_width = scale_image_size (desired_height, height, width);
- else
- {
- desired_width = width;
- desired_height = height;
- }
-
- if (max_width != -1 && desired_width > max_width)
- {
- /* The image is wider than :max-width. */
- desired_width = max_width;
- desired_height = scale_image_size (desired_width, width, height);
- }
-
- if (max_height != -1 && desired_height > max_height)
- {
- /* The image is higher than :max-height. */
- desired_height = max_height;
- desired_width = scale_image_size (desired_height, height, width);
- }
-
- out:
- *d_width = desired_width;
- *d_height = desired_height;
-}
-
static bool imagemagick_image_p (Lisp_Object);
static bool imagemagick_load (struct frame *, struct image *);
static void imagemagick_clear_image (struct frame *, struct image *);
diff --git a/src/nsimage.m b/src/nsimage.m
index 0ae1b88edd..71da0201d1 100644
--- a/src/nsimage.m
+++ b/src/nsimage.m
@@ -126,8 +126,6 @@ Updated by Christian Limpach (chris@nice.ch)
eImg = temp;
}
- [eImg setSizeFromSpec:XCDR (img->spec)];
-
size = [eImg size];
img->width = size.width;
img->height = size.height;
@@ -524,66 +522,6 @@ - (BOOL)setFrame: (unsigned int) index
return YES;
}
-- (void)setSizeFromSpec: (Lisp_Object) spec
-{
- NSSize size = [self size];
- Lisp_Object value;
- double scale = 1, aspect = size.width / size.height;
- double width = -1, height = -1, max_width = -1, max_height = -1;
-
- value = Fplist_get (spec, QCscale);
- if (NUMBERP (value))
- scale = XFLOATINT (value) ;
-
- value = Fplist_get (spec, QCmax_width);
- if (NUMBERP (value))
- max_width = XFLOATINT (value);
-
- value = Fplist_get (spec, QCmax_height);
- if (NUMBERP (value))
- max_height = XFLOATINT (value);
-
- value = Fplist_get (spec, QCwidth);
- if (NUMBERP (value))
- {
- width = XFLOATINT (value) * scale;
- /* :width overrides :max-width. */
- max_width = -1;
- }
-
- value = Fplist_get (spec, QCheight);
- if (NUMBERP (value))
- {
- height = XFLOATINT (value) * scale;
- /* :height overrides :max-height. */
- max_height = -1;
- }
-
- if (width <= 0 && height <= 0)
- {
- width = size.width * scale;
- height = size.height * scale;
- }
- else if (width > 0 && height <= 0)
- height = width / aspect;
- else if (height > 0 && width <= 0)
- width = height * aspect;
-
- if (max_width > 0 && width > max_width)
- {
- width = max_width;
- height = max_width / aspect;
- }
-
- if (max_height > 0 && height > max_height)
- {
- height = max_height;
- width = max_height * aspect;
- }
-
- [self setSize:NSMakeSize(width, height)];
-}
-
- (instancetype)rotate: (double)rotation
{
EmacsImage *new_image;
diff --git a/src/nsterm.h b/src/nsterm.h
index 23460abc65..f64d78bd2b 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -648,7 +648,6 @@ typedef id instancetype;
- (NSColor *)stippleMask;
- (Lisp_Object)getMetadata;
- (BOOL)setFrame: (unsigned int) index;
-- (void)setSizeFromSpec: (Lisp_Object) spec;
- (instancetype)rotate: (double)rotation;
@end
diff --git a/src/nsterm.m b/src/nsterm.m
index 6c285f0abb..0a2a184830 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -3121,7 +3121,6 @@ so some key presses (TAB) are swallowed by the system. */
[img setXBMColor: bm_color];
}
-#ifdef NS_IMPL_COCOA
// Note: For periodic images, the full image height is "h + hd".
// By using the height h, a suitable part of the image is used.
NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
@@ -3134,13 +3133,6 @@ so some key presses (TAB) are swallowed by the system. */
fraction: 1.0
respectFlipped: YES
hints: nil];
-#else
- {
- NSPoint pt = imageRect.origin;
- pt.y += p->h;
- [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
- }
-#endif
}
ns_reset_clipping (f);
}
@@ -3821,13 +3813,15 @@ Function modeled after x_draw_glyph_string_box ().
{
EmacsImage *img = s->img->pixmap;
int box_line_vwidth = max (s->face->box_line_width, 0);
- int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
+ int x = s->x, y = s->ybase - image_ascent (s->image, s->face, &s->slice);
int bg_x, bg_y, bg_height;
int th;
char raised_p;
NSRect br;
struct face *face;
NSColor *tdCol;
+ double xscale = (double)s->img->width/s->image.width;
+ double yscale = (double)s->img->height/s->image.height;
NSTRACE ("ns_dumpglyphs_image");
@@ -3841,8 +3835,8 @@ Function modeled after x_draw_glyph_string_box ().
/* other terms have this, but was causing problems w/tabbar mode */
/* - 2 * box_line_vwidth; */
- if (s->slice.x == 0) x += s->img->hmargin;
- if (s->slice.y == 0) y += s->img->vmargin;
+ if (s->slice.x == 0) x += s->image.hmargin;
+ if (s->slice.y == 0) y += s->image.vmargin;
/* Draw BG: if we need larger area than image itself cleared, do that,
otherwise, since we composite the image under NS (instead of mucking
@@ -3859,7 +3853,7 @@ Function modeled after x_draw_glyph_string_box ().
[ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
- if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
+ if (bg_height > s->slice.height || s->image.hmargin || s->image.vmargin
|| s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
{
br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
@@ -3877,9 +3871,9 @@ Function modeled after x_draw_glyph_string_box ().
{
#ifdef NS_IMPL_COCOA
NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
- NSRect ir = NSMakeRect (s->slice.x,
- s->img->height - s->slice.y - s->slice.height,
- s->slice.width, s->slice.height);
+ NSRect ir = NSMakeRect (s->slice.x * xscale,
+ (s->image.height - s->slice.y - s->slice.height) * yscale,
+ s->slice.width * xscale , s->slice.height * yscale);
[img drawInRect: dr
fromRect: ir
operation: NSCompositingOperationSourceOver
@@ -3914,7 +3908,7 @@ Function modeled after x_draw_glyph_string_box ().
ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
/* Draw relief, if requested */
- if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
+ if (s->image.relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
{
if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
{
@@ -3924,8 +3918,8 @@ Function modeled after x_draw_glyph_string_box ().
}
else
{
- th = abs (s->img->relief);
- raised_p = (s->img->relief > 0);
+ th = abs (s->image.relief);
+ raised_p = (s->image.relief > 0);
}
r.origin.x = x - th;
@@ -3934,9 +3928,9 @@ Function modeled after x_draw_glyph_string_box ().
r.size.height = s->slice.height + 2*th-1;
ns_draw_relief (r, th, raised_p,
s->slice.y == 0,
- s->slice.y + s->slice.height == s->img->height,
+ s->slice.y + s->slice.height == s->image.height,
s->slice.x == 0,
- s->slice.x + s->slice.width == s->img->width, s);
+ s->slice.x + s->slice.width == s->image.width, s);
}
/* If there is no mask, the background won't be seen,
@@ -3944,7 +3938,7 @@ Function modeled after x_draw_glyph_string_box ().
Do this for all images, getting transparency right is not reliable. */
if (s->hl == DRAW_CURSOR)
{
- int thickness = abs (s->img->relief);
+ int thickness = abs (s->image.relief);
if (thickness == 0) thickness = 1;
ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
}
diff --git a/src/w32term.c b/src/w32term.c
index 8d189ae32c..eb231b57f7 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -1850,7 +1850,7 @@ static void
x_draw_image_foreground (struct glyph_string *s)
{
int x = s->x;
- int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
+ int y = s->ybase - image_ascent (s->image, s->face, &s->slice);
/* If first glyph of S has a left box line, start drawing it to the
right of that line. */
@@ -1943,7 +1943,7 @@ x_draw_image_relief (struct glyph_string *s)
int extra_x, extra_y;
RECT r;
int x = s->x;
- int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
+ int y = s->ybase - image_ascent (s->image, s->face, &s->slice);
/* If first glyph of S has a left box line, start drawing it to the
right of that line. */
@@ -2015,7 +2015,7 @@ w32_draw_image_foreground_1 (struct glyph_string *s, HBITMAP pixmap)
HDC hdc = CreateCompatibleDC (s->hdc);
HGDIOBJ orig_hdc_obj = SelectObject (hdc, pixmap);
int x = 0;
- int y = s->ybase - s->y - image_ascent (s->img, s->face, &s->slice);
+ int y = s->ybase - s->y - image_ascent (s->image, s->face, &s->slice);
/* If first glyph of S has a left box line, start drawing it to the
right of that line. */
diff --git a/src/xdisp.c b/src/xdisp.c
index 4201bdc4a7..6d17f64b7d 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -5197,7 +5197,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
it->area = TEXT_AREA;
it->what = IT_IMAGE;
- it->image_id = -1; /* no image */
+ it->image.image_id = -1; /* no image */
it->position = start_pos;
it->object = NILP (object) ? it->w->contents : object;
it->method = GET_FROM_IMAGE;
@@ -5356,7 +5356,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
else
{
it->what = IT_IMAGE;
- it->image_id = lookup_image (it->f, value);
+ it->image = calc_image_spec (it->f, value);
it->position = start_pos;
it->object = NILP (object) ? it->w->contents : object;
it->method = GET_FROM_IMAGE;
@@ -6103,7 +6103,7 @@ push_it (struct it *it, struct text_pos *position)
{
case GET_FROM_IMAGE:
p->u.image.object = it->object;
- p->u.image.image_id = it->image_id;
+ p->u.image.image = it->image;
p->u.image.slice = it->slice;
break;
case GET_FROM_STRETCH:
@@ -6209,7 +6209,7 @@ pop_it (struct it *it)
switch (it->method)
{
case GET_FROM_IMAGE:
- it->image_id = p->u.image.image_id;
+ it->image = p->u.image.image;
it->object = p->u.image.object;
it->slice = p->u.image.slice;
break;
@@ -19446,7 +19446,7 @@ dump_glyph (struct glyph_row *row, struct glyph *glyph, int area)
? '0'
: '-'))),
glyph->pixel_width,
- (unsigned int) glyph->u.img_id,
+ (unsigned int) glyph->u.image.image_id,
'.',
glyph->face_id,
glyph->left_box_line_p,
@@ -20775,7 +20775,7 @@ push_prefix_prop (struct it *it, Lisp_Object prop)
else if (IMAGEP (prop))
{
it->what = IT_IMAGE;
- it->image_id = lookup_image (it->f, prop);
+ it->image = calc_image_spec (it->f, prop);
it->method = GET_FROM_IMAGE;
}
#endif /* HAVE_WINDOW_SYSTEM */
@@ -25596,12 +25596,8 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
/* '(image PROPS...)': width or height of the specified image. */
if (FRAME_WINDOW_P (it->f)
&& valid_image_p (prop))
- {
- ptrdiff_t id = lookup_image (it->f, prop);
- struct image *img = IMAGE_FROM_ID (it->f, id);
+ return OK_PIXELS (width_p ? it->image.width : it->image.height);
- return OK_PIXELS (width_p ? img->width : img->height);
- }
/* '(xwidget PROPS...)': dimensions of the specified xwidget. */
if (FRAME_WINDOW_P (it->f) && valid_xwidget_spec_p (prop))
{
@@ -26104,7 +26100,8 @@ static void
fill_image_glyph_string (struct glyph_string *s)
{
eassert (s->first_glyph->type == IMAGE_GLYPH);
- s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
+ s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.image.image_id);
+ s->image = s->first_glyph->u.image;
eassert (s->img);
s->slice = s->first_glyph->slice.img;
s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
@@ -27247,7 +27244,7 @@ produce_image_glyph (struct it *it)
/* Make sure X resources of the face is loaded. */
prepare_face_for_display (it->f, face);
- if (it->image_id < 0)
+ if (it->image.image_id < 0)
{
/* Fringe bitmap. */
it->ascent = it->phys_ascent = 0;
@@ -27257,60 +27254,60 @@ produce_image_glyph (struct it *it)
return;
}
- img = IMAGE_FROM_ID (it->f, it->image_id);
+ img = IMAGE_FROM_ID (it->f, it->image.image_id);
/* Make sure X resources of the image is loaded. */
prepare_image_for_display (it->f, img);
slice.x = slice.y = 0;
- slice.width = img->width;
- slice.height = img->height;
+ slice.width = it->image.width;
+ slice.height = it->image.height;
if (FIXNUMP (it->slice.x))
slice.x = XFIXNUM (it->slice.x);
else if (FLOATP (it->slice.x))
- slice.x = XFLOAT_DATA (it->slice.x) * img->width;
+ slice.x = XFLOAT_DATA (it->slice.x) * it->image.width;
if (FIXNUMP (it->slice.y))
slice.y = XFIXNUM (it->slice.y);
else if (FLOATP (it->slice.y))
- slice.y = XFLOAT_DATA (it->slice.y) * img->height;
+ slice.y = XFLOAT_DATA (it->slice.y) * it->image.height;
if (FIXNUMP (it->slice.width))
slice.width = XFIXNUM (it->slice.width);
else if (FLOATP (it->slice.width))
- slice.width = XFLOAT_DATA (it->slice.width) * img->width;
+ slice.width = XFLOAT_DATA (it->slice.width) * it->image.width;
if (FIXNUMP (it->slice.height))
slice.height = XFIXNUM (it->slice.height);
else if (FLOATP (it->slice.height))
- slice.height = XFLOAT_DATA (it->slice.height) * img->height;
+ slice.height = XFLOAT_DATA (it->slice.height) * it->image.height;
- if (slice.x >= img->width)
- slice.x = img->width;
- if (slice.y >= img->height)
- slice.y = img->height;
- if (slice.x + slice.width >= img->width)
- slice.width = img->width - slice.x;
- if (slice.y + slice.height > img->height)
- slice.height = img->height - slice.y;
+ if (slice.x >= it->image.width)
+ slice.x = it->image.width;
+ if (slice.y >= it->image.height)
+ slice.y = it->image.height;
+ if (slice.x + slice.width >= it->image.width)
+ slice.width = it->image.width - slice.x;
+ if (slice.y + slice.height > it->image.height)
+ slice.height = it->image.height - slice.y;
if (slice.width == 0 || slice.height == 0)
return;
- it->ascent = it->phys_ascent = glyph_ascent = image_ascent (img, face, &slice);
+ it->ascent = it->phys_ascent = glyph_ascent = image_ascent (it->image, face, &slice);
it->descent = slice.height - glyph_ascent;
if (slice.y == 0)
- it->descent += img->vmargin;
- if (slice.y + slice.height == img->height)
- it->descent += img->vmargin;
+ it->descent += it->image.vmargin;
+ if (slice.y + slice.height == it->image.height)
+ it->descent += it->image.vmargin;
it->phys_descent = it->descent;
it->pixel_width = slice.width;
if (slice.x == 0)
- it->pixel_width += img->hmargin;
- if (slice.x + slice.width == img->width)
- it->pixel_width += img->hmargin;
+ it->pixel_width += it->image.hmargin;
+ if (slice.x + slice.width == it->image.width)
+ it->pixel_width += it->image.hmargin;
/* It's quite possible for images to have an ascent greater than
their height, so don't get confused in that case. */
@@ -27325,13 +27322,13 @@ produce_image_glyph (struct it *it)
{
if (slice.y == 0)
it->ascent += face->box_line_width;
- if (slice.y + slice.height == img->height)
+ if (slice.y + slice.height == it->image.height)
it->descent += face->box_line_width;
}
if (it->start_of_box_run_p && slice.x == 0)
it->pixel_width += eabs (face->box_line_width);
- if (it->end_of_box_run_p && slice.x + slice.width == img->width)
+ if (it->end_of_box_run_p && slice.x + slice.width == it->image.width)
it->pixel_width += eabs (face->box_line_width);
}
@@ -27388,7 +27385,7 @@ produce_image_glyph (struct it *it)
glyph->padding_p = false;
glyph->glyph_not_available_p = false;
glyph->face_id = it->face_id;
- glyph->u.img_id = img->id;
+ glyph->u.image = it->image;
glyph->slice.img = slice;
glyph->font_type = FONT_TYPE_UNKNOWN;
if (it->bidi_p)
@@ -29326,15 +29323,15 @@ get_window_cursor_type (struct window *w, struct glyph *glyph, int *width,
/* Using a block cursor on large images can be very annoying.
So use a hollow cursor for "large" images.
If image is not transparent (no mask), also use hollow cursor. */
- struct image *img = IMAGE_OPT_FROM_ID (f, glyph->u.img_id);
+ struct image *img = IMAGE_OPT_FROM_ID (f, glyph->u.image.image_id);
if (img != NULL && IMAGEP (img->spec))
{
/* Arbitrarily, interpret "Large" as >32x32 and >NxN
where N = size of default frame font size.
This should cover most of the "tiny" icons people may use. */
if (!img->mask
- || img->width > max (32, WINDOW_FRAME_COLUMN_WIDTH (w))
- || img->height > max (32, WINDOW_FRAME_LINE_HEIGHT (w)))
+ || glyph->u.image.width > max (32, WINDOW_FRAME_COLUMN_WIDTH (w))
+ || glyph->u.image.height > max (32, WINDOW_FRAME_LINE_HEIGHT (w)))
cursor_type = HOLLOW_BOX_CURSOR;
}
}
@@ -31482,11 +31479,10 @@ note_mouse_highlight (struct frame *f, int x, int y)
/* Look for :pointer property on image. */
if (glyph != NULL && glyph->type == IMAGE_GLYPH)
{
- struct image *img = IMAGE_OPT_FROM_ID (f, glyph->u.img_id);
- if (img != NULL && IMAGEP (img->spec))
+ if (IMAGEP (glyph->object))
{
Lisp_Object image_map, hotspot;
- if ((image_map = Fplist_get (XCDR (img->spec), QCmap),
+ if ((image_map = Fplist_get (XCDR (glyph->object), QCmap),
!NILP (image_map))
&& (hotspot = find_hot_spot (image_map,
glyph->slice.img.x + dx,
@@ -31517,7 +31513,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
}
}
if (NILP (pointer))
- pointer = Fplist_get (XCDR (img->spec), QCpointer);
+ pointer = Fplist_get (XCDR (glyph->object), QCpointer);
}
}
#endif /* HAVE_WINDOW_SYSTEM */
diff --git a/src/xterm.c b/src/xterm.c
index 943f4c3b3d..6a94916d4e 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -38,11 +38,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <X11/extensions/Xfixes.h>
#endif
-/* Using Xft implies that XRender is available. */
-#ifdef HAVE_XFT
-#include <X11/extensions/Xrender.h>
-#endif
-
#ifdef HAVE_XDBE
#include <X11/extensions/Xdbe.h>
#endif
@@ -136,6 +131,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <X11/XKBlib.h>
#endif
+#ifdef HAVE_XRENDER
+#include <X11/extensions/Xrender.h>
+#endif
+
/* Default to using XIM if available. */
#ifdef USE_XIM
bool use_xim = true;
@@ -2976,13 +2975,60 @@ x_draw_glyph_string_box (struct glyph_string *s)
}
+static void
+x_composite_image (struct glyph_string *s, Pixmap dest,
+ int srcX, int srcY, int dstX, int dstY,
+ int width, int height)
+{
+#ifdef HAVE_XRENDER
+ Picture source, destination;
+ XRenderPictFormat *default_format, *source_format;
+ XRenderPictureAttributes source_attr, dest_attr;
+ double xscale = (double) s->img->width/s->image.width;
+ double yscale = (double) s->img->height/s->image.height;
+
+ XTransform tmat = {{{XDoubleToFixed (xscale), XDoubleToFixed (0), XDoubleToFixed (0)},
+ {XDoubleToFixed (0), XDoubleToFixed (yscale), XDoubleToFixed (0)},
+ {XDoubleToFixed (0), XDoubleToFixed (0), XDoubleToFixed (1)}}};
+
+ default_format = XRenderFindVisualFormat (s->display, DefaultVisual (s->display, 0));
+ /* FIXME: I doubt this is always correct. There must be a way of
+ working out the format of the pixmap. */
+ source_format = XRenderFindStandardFormat (s->display, PictStandardRGB24);
+
+ source = XRenderCreatePicture (s->display, s->img->pixmap, source_format,
+ 0, &source_attr);
+ destination = XRenderCreatePicture (s->display, dest, default_format, 0, &dest_attr);
+
+ XRenderSetPictureFilter (s->display, source, FilterBest, 0, 0);
+ XRenderSetPictureTransform (s->display, source, &tmat);
+
+ /* FIXME: XRenderComposite supports masks, so can we just use the
+ mask in s->img->mask here? */
+ XRenderComposite (s->display, PictOpOver, source, None, destination,
+ srcX*xscale, srcY*yscale,
+ 0, 0,
+ dstX, dstY,
+ width, height);
+
+ XRenderFreePicture (s->display, source);
+ XRenderFreePicture (s->display, destination);
+#else
+ XCopyArea (s->display, s->img->pixmap,
+ dest, s->gc,
+ srcX, srcY
+ width, height, dstX, dstY);
+#endif
+}
+
+
/* Draw foreground of image glyph string S. */
static void
x_draw_image_foreground (struct glyph_string *s)
{
int x = s->x;
- int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
+ int y = s->ybase - image_ascent (s->image, s->face, &s->slice);
/* If first glyph of S has a left box line, start drawing it to the
right of that line. */
@@ -2994,9 +3040,9 @@ x_draw_image_foreground (struct glyph_string *s)
/* If there is a margin around the image, adjust x- and y-position
by that margin. */
if (s->slice.x == 0)
- x += s->img->hmargin;
+ x += s->image.hmargin;
if (s->slice.y == 0)
- y += s->img->vmargin;
+ y += s->image.vmargin;
if (s->img->pixmap)
{
@@ -3024,10 +3070,8 @@ x_draw_image_foreground (struct glyph_string *s)
image_rect.width = s->slice.width;
image_rect.height = s->slice.height;
if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
- XCopyArea (s->display, s->img->pixmap,
- FRAME_X_DRAWABLE (s->f), s->gc,
- s->slice.x + r.x - x, s->slice.y + r.y - y,
- r.width, r.height, r.x, r.y);
+ x_composite_image (s, FRAME_X_DRAWABLE (s->f), s->slice.x + r.x - x, s->slice.y + r.y - y,
+ r.x, r.y, r.width, r.height);
}
else
{
@@ -3039,10 +3083,8 @@ x_draw_image_foreground (struct glyph_string *s)
image_rect.width = s->slice.width;
image_rect.height = s->slice.height;
if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
- XCopyArea (s->display, s->img->pixmap,
- FRAME_X_DRAWABLE (s->f), s->gc,
- s->slice.x + r.x - x, s->slice.y + r.y - y,
- r.width, r.height, r.x, r.y);
+ x_composite_image (s, FRAME_X_DRAWABLE (s->f), s->slice.x + r.x - x, s->slice.y + r.y - y,
+ r.x, r.y, r.width, r.height);
/* When the image has a mask, we can expect that at
least part of a mouse highlight or a block cursor will
@@ -3052,7 +3094,7 @@ x_draw_image_foreground (struct glyph_string *s)
nothing here for mouse-face. */
if (s->hl == DRAW_CURSOR)
{
- int relief = eabs (s->img->relief);
+ int relief = eabs (s->image.relief);
x_draw_rectangle (s->f, s->gc,
x - relief, y - relief,
s->slice.width + relief*2 - 1,
@@ -3077,7 +3119,7 @@ x_draw_image_relief (struct glyph_string *s)
int extra_x, extra_y;
XRectangle r;
int x = s->x;
- int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
+ int y = s->ybase - image_ascent (s->image, s->face, &s->slice);
/* If first glyph of S has a left box line, start drawing it to the
right of that line. */
@@ -3089,9 +3131,9 @@ x_draw_image_relief (struct glyph_string *s)
/* If there is a margin around the image, adjust x- and y-position
by that margin. */
if (s->slice.x == 0)
- x += s->img->hmargin;
+ x += s->image.hmargin;
if (s->slice.y == 0)
- y += s->img->vmargin;
+ y += s->image.vmargin;
if (s->hl == DRAW_IMAGE_SUNKEN
|| s->hl == DRAW_IMAGE_RAISED)
@@ -3101,8 +3143,8 @@ x_draw_image_relief (struct glyph_string *s)
}
else
{
- thick = eabs (s->img->relief);
- raised_p = s->img->relief > 0;
+ thick = eabs (s->image.relief);
+ raised_p = s->image.relief > 0;
}
x1 = x + s->slice.width - 1;
@@ -3128,9 +3170,9 @@ x_draw_image_relief (struct glyph_string *s)
x -= thick + extra_x, left_p = true;
if (s->slice.y == 0)
y -= thick + extra_y, top_p = true;
- if (s->slice.x + s->slice.width == s->img->width)
+ if (s->slice.x + s->slice.width == s->image.width)
x1 += thick + extra_x, right_p = true;
- if (s->slice.y + s->slice.height == s->img->height)
+ if (s->slice.y + s->slice.height == s->image.height)
y1 += thick + extra_y, bot_p = true;
x_setup_relief_colors (s);
@@ -3146,7 +3188,7 @@ static void
x_draw_image_foreground_1 (struct glyph_string *s, Pixmap pixmap)
{
int x = 0;
- int y = s->ybase - s->y - image_ascent (s->img, s->face, &s->slice);
+ int y = s->ybase - s->y - image_ascent (s->image, s->face, &s->slice);
/* If first glyph of S has a left box line, start drawing it to the
right of that line. */
@@ -3158,9 +3200,9 @@ x_draw_image_foreground_1 (struct glyph_string *s, Pixmap pixmap)
/* If there is a margin around the image, adjust x- and y-position
by that margin. */
if (s->slice.x == 0)
- x += s->img->hmargin;
+ x += s->image.hmargin;
if (s->slice.y == 0)
- y += s->img->vmargin;
+ y += s->image.vmargin;
if (s->img->pixmap)
{
@@ -3200,7 +3242,7 @@ x_draw_image_foreground_1 (struct glyph_string *s, Pixmap pixmap)
nothing here for mouse-face. */
if (s->hl == DRAW_CURSOR)
{
- int r = eabs (s->img->relief);
+ int r = eabs (s->image.relief);
x_draw_rectangle (s->f, s->gc, x - r, y - r,
s->slice.width + r*2 - 1,
s->slice.height + r*2 - 1);
@@ -3265,8 +3307,8 @@ x_draw_image_glyph_string (struct glyph_string *s)
flickering. */
s->stippled_p = s->face->stipple != 0;
if (height > s->slice.height
- || s->img->hmargin
- || s->img->vmargin
+ || s->image.hmargin
+ || s->image.vmargin
|| s->img->mask
|| s->img->pixmap == 0
|| s->width != s->background_width)
@@ -3338,8 +3380,8 @@ x_draw_image_glyph_string (struct glyph_string *s)
{
cairo_t *cr = x_begin_cr_clip (s->f, s->gc);
- int x = s->x + s->img->hmargin;
- int y = s->y + s->img->vmargin;
+ int x = s->x + s->image.hmargin;
+ int y = s->y + s->image.vmargin;
int width = s->background_width;
cairo_set_source_surface (cr, s->img->cr_data,
@@ -3363,7 +3405,7 @@ x_draw_image_glyph_string (struct glyph_string *s)
x_draw_image_foreground (s);
/* If we must draw a relief around the image, do it. */
- if (s->img->relief
+ if (s->image.relief
|| s->hl == DRAW_IMAGE_RAISED
|| s->hl == DRAW_IMAGE_SUNKEN)
x_draw_image_relief (s);
--
2.19.1
next prev parent reply other threads:[~2018-12-27 13:11 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-12-02 1:33 Linking to ImageMagick by default Glenn Morris
2018-12-02 18:15 ` Paul Eggert
2018-12-05 13:30 ` Lars Ingebrigtsen
2018-12-05 15:28 ` Stefan Monnier
2018-12-06 11:06 ` Lars Ingebrigtsen
2018-12-05 17:24 ` Glenn Morris
2018-12-05 17:27 ` Lars Ingebrigtsen
2018-12-05 18:27 ` Daniel Pittman
2018-12-05 18:38 ` Lars Ingebrigtsen
2018-12-05 19:31 ` joakim
2018-12-05 22:39 ` Alan Third
2018-12-08 18:38 ` Alan Third
2018-12-08 21:24 ` Paul Eggert
2018-12-10 22:09 ` Alan Third
2018-12-19 16:03 ` Alan Third
2018-12-19 16:36 ` Eli Zaretskii
2018-12-19 16:45 ` Joseph Garvin
2018-12-27 15:06 ` Alan Third
2018-12-27 13:11 ` Alan Third [this message]
2018-12-27 16:05 ` Eli Zaretskii
2018-12-27 20:37 ` Juri Linkov
2018-12-28 8:12 ` Eli Zaretskii
2018-12-28 21:21 ` Alan Third
2018-12-29 6:56 ` Eli Zaretskii
2018-12-29 21:31 ` Juri Linkov
2018-12-30 12:47 ` Alan Third
2019-01-01 21:47 ` [PATCH] Add native image scaling Alan Third
2019-01-02 16:11 ` Eli Zaretskii
2019-01-02 21:12 ` [PATCH v2] Add native image scaling (bug#33587) Alan Third
2019-01-04 14:31 ` Eli Zaretskii
2019-01-04 19:09 ` Alan Third
2019-01-04 20:21 ` Eli Zaretskii
2019-01-04 22:45 ` Alan Third
2019-01-10 19:42 ` Alan Third
2019-01-10 19:50 ` Eli Zaretskii
2019-01-10 23:40 ` Paul Eggert
2019-01-06 16:26 ` Eli Zaretskii
2019-01-05 21:30 ` Track mouse drags over an image (was: Add native image scaling) Roland Winkler
2019-01-08 18:20 ` Track mouse drags over an image Stefan Monnier
2019-01-11 4:55 ` Roland Winkler
2019-01-11 16:23 ` Stefan Monnier
2018-12-09 11:34 ` Linking to ImageMagick by default Elias Mårtenson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20181227131105.GA18792@breton.holly.idiocy.org \
--to=alan@idiocy.org \
--cc=eliz@gnu.org \
--cc=emacs-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).