all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Alan Third <alan@idiocy.org>
To: Eli Zaretskii <eliz@gnu.org>
Cc: emacs-devel@gnu.org
Subject: [PATCH] Add native image scaling
Date: Tue, 1 Jan 2019 21:47:19 +0000	[thread overview]
Message-ID: <20190101214719.GA18292@breton.holly.idiocy.org> (raw)
In-Reply-To: <20181230124759.GA77761@breton.holly.idiocy.org>

* 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): Allow resizing if
native scaling is available.
* src/dispextern.h: Add XRender and image scaling stuff.
(struct image): Add XRender Pictures.
* src/image.c (x_create_bitmap_mask):
(image_create_x_image_and_pixmap): Handle XRender Picture.
(scale_image_size):
(compute_image_size): Make available when any form of scaling is
enabled.
(x_set_image_size): New function.
(lookup_image): Set image size.
(x_create_x_image_and_pixmap): Create XRender Picture when necessary.
(x_put_x_image): Handle the case where desired size != actual size.
(free_image): Free XRender Pictures.
(Fimage_scaling_p): New function.
(syms_of_image): Add image-scaling-p.
* src/nsimage.m (ns_load_image): Remove NS specific resizing.
([EmacsImage setSizeFromSpec:]): Remove method.
(ns_image_set_size): New function.
* src/nsterm.m (ns_draw_fringe_bitmap): Cocoa and GNUstep both have
the same compositing functions, so remove unnecessary difference.
* src/xterm.c (x_composite_image): New function.
(x_draw_image_foreground): Use new x_composite_image function.
---

This is a completely rewritten version that doesn't do anything
different with the image cache. I think this is pretty complete as it
is, excepting Windows support. I don't know how to add Windows support
to match the way it's done in NS and X, however if we can't resize the
images up-front, it should be possible to add some size info to the
image struct and do the resize on display.

I'm still unsure about image.el calling image-flush on every image
resize, but I have to assume it's in there for a reason.

 configure.ac     |  14 ++-
 etc/NEWS         |   6 +
 lisp/image.el    |   4 +-
 src/Makefile.in  |   3 +-
 src/dispextern.h |  13 ++
 src/image.c      | 314 ++++++++++++++++++++++++++++++++---------------
 src/nsimage.m    |  68 +---------
 src/nsterm.h     |   2 +-
 src/nsterm.m     |   8 --
 src/xterm.c      |  58 +++++++--
 10 files changed, 298 insertions(+), 192 deletions(-)

diff --git a/configure.ac b/configure.ac
index 91fa417308..0c59fe0619 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/etc/NEWS b/etc/NEWS
index 75e2c1bf98..69e14773a7 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1442,6 +1442,12 @@ that is non-nil, it will look for a file name handler for the current
 buffer's 'default-directory' and invoke that file name handler to make
 the process.  That way 'make-process' can start remote processes.
 
++++
+** Emacs now supports resizing images without ImageMagick on X window
+systems where the XRender extension is available, and on the NS port.
+The new function 'image-scaling-p' can be used to test whether any
+given frame supports resizing.
+
 \f
 * Changes in Emacs 27.1 on Non-Free Operating Systems
 
diff --git a/lisp/image.el b/lisp/image.el
index 5727d8fbce..2e84e47b5c 100644
--- a/lisp/image.el
+++ b/lisp/image.el
@@ -982,8 +982,8 @@ image--get-image
     image))
 
 (defun image--get-imagemagick-and-warn ()
-  (unless (or (fboundp 'imagemagick-types) (featurep 'ns))
-    (error "Cannot rescale images without ImageMagick support"))
+  (unless (or (fboundp 'imagemagick-types) (image-scaling-p))
+    (error "Cannot rescale images on this terminal"))
   (let ((image (image--get-image)))
     (image-flush image)
     (when (fboundp 'imagemagick-types)
diff --git a/src/Makefile.in b/src/Makefile.in
index e9831e9299..f409ed4db2 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 5774e3e951..b064875ac4 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -31,6 +31,9 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #include <X11/Intrinsic.h>
 #endif /* USE_X_TOOLKIT */
 
+#ifdef HAVE_XRENDER
+#include <X11/extensions/Xrender.h>
+#endif
 #else /* !HAVE_X_WINDOWS */
 
 /* X-related stuff used by non-X gui code.  */
@@ -2935,6 +2938,11 @@ struct redisplay_interface
 
 #ifdef HAVE_WINDOW_SYSTEM
 
+#if defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER) \
+  || defined (HAVE_NS)
+#define HAVE_NATIVE_SCALING
+#endif
+
 /* Structure describing an image.  Specific image formats like XBM are
    converted into this form, so that display only has to deal with
    this type of image.  */
@@ -2958,6 +2966,11 @@ struct image
      and the latter is outdated.  NULL means the X image has been
      synchronized to Pixmap.  */
   XImagePtr ximg, mask_img;
+
+#ifdef HAVE_NATIVE_SCALING
+  /* Picture versions of pixmap and mask for compositing.  */
+  Picture picture, mask_picture;
+#endif
 #endif
 
   /* Colors allocated for this image, if any.  Allocated via xmalloc.  */
diff --git a/src/image.c b/src/image.c
index 87e0c071ee..9c78755bbc 100644
--- a/src/image.c
+++ b/src/image.c
@@ -408,8 +408,13 @@ x_destroy_all_bitmaps (Display_Info *dpyinfo)
   dpyinfo->bitmaps_last = 0;
 }
 
+#ifdef HAVE_XRENDER
+static bool x_create_x_image_and_pixmap (struct frame *, int, int, int,
+					 XImagePtr *, Pixmap *, Picture *);
+#else
 static bool x_create_x_image_and_pixmap (struct frame *, int, int, int,
 					 XImagePtr *, Pixmap *);
+#endif
 static void x_destroy_x_image (XImagePtr ximg);
 
 #ifdef HAVE_NTGUI
@@ -472,7 +477,11 @@ x_create_bitmap_mask (struct frame *f, ptrdiff_t id)
       return;
     }
 
-  result = x_create_x_image_and_pixmap (f, width, height, 1, &mask_img, &mask);
+  result = x_create_x_image_and_pixmap (f, width, height, 1, &mask_img, &mask
+#ifdef HAVE_XRENDER
+                                        , NULL
+#endif
+                                        );
 
   unblock_input ();
   if (!result)
@@ -1011,6 +1020,13 @@ free_image (struct frame *f, struct image *img)
 
       c->images[img->id] = NULL;
 
+#ifdef HAVE_XRENDER
+      if (img->picture)
+        XRenderFreePicture (FRAME_X_DISPLAY (f), img->picture);
+      if (img->mask_picture)
+        XRenderFreePicture (FRAME_X_DISPLAY (f), img->mask_picture);
+#endif
+
       /* Windows NT redefines 'free', but in this file, we need to
          avoid the redefinition.  */
 #ifdef WINDOWSNT
@@ -1747,6 +1763,147 @@ postprocess_image (struct frame *f, struct image *img)
     }
 }
 
+#if defined (HAVE_IMAGEMAGICK) || defined (HAVE_NATIVE_SCALING)
+/* 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;
+}
+
+#ifdef HAVE_NATIVE_SCALING
+static void
+x_set_image_size (struct frame *f, struct image *img)
+{
+#ifdef HAVE_IMAGEMAGICK
+  /* ImageMagick images are already the correct size.  */
+  if (!imagemagick_image_p (img->spec))
+#endif
+    {
+      int width, height;
+
+      compute_image_size (img->width, img->height, img->spec, &width, &height);
+
+#ifdef HAVE_NS
+      ns_image_set_size (img->pixmap, width, height);
+      img->width = width;
+      img->height = height;
+#endif
+
+#ifdef HAVE_XRENDER
+      if (img->picture)
+      {
+        double xscale = (double) img->width/width;
+        double yscale = (double) img->height/height;
+
+        XTransform tmat = {{{XDoubleToFixed (xscale), XDoubleToFixed (0), XDoubleToFixed (0)},
+                            {XDoubleToFixed (0), XDoubleToFixed (yscale), XDoubleToFixed (0)},
+                            {XDoubleToFixed (0), XDoubleToFixed (0), XDoubleToFixed (1)}}};
+
+        XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest, 0, 0);
+        XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->picture, &tmat);
+
+        img->width = width;
+        img->height = height;
+      }
+#endif
+    }
+}
+#endif
+#endif /* HAVE_IMAGEMAGICK || HAVE_XRENDER || HAVE_NS  */
+
 
 /* Return the id of image with Lisp specification SPEC on frame F.
    SPEC must be a valid Lisp image specification (see valid_image_p).  */
@@ -1802,6 +1959,9 @@ lookup_image (struct frame *f, Lisp_Object spec)
 	     `:background COLOR'.  */
 	  Lisp_Object ascent, margin, relief, bg;
 	  int relief_bound;
+#ifdef HAVE_NATIVE_SCALING
+          x_set_image_size (f, img);
+#endif
 
 	  ascent = image_spec_value (spec, QCascent, NULL);
 	  if (FIXNUMP (ascent))
@@ -1975,13 +2135,21 @@ x_check_image_size (XImagePtr ximg, int width, int height)
    should indicate the bit depth of the image.  */
 
 static bool
+#ifdef HAVE_XRENDER
+x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth,
+			     XImagePtr *ximg, Pixmap *pixmap, Picture *picture)
+#else
 x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth,
 			     XImagePtr *ximg, Pixmap *pixmap)
+#endif
 {
 #ifdef HAVE_X_WINDOWS
   Display *display = FRAME_X_DISPLAY (f);
   Drawable drawable = FRAME_X_DRAWABLE (f);
   Screen *screen = FRAME_X_SCREEN (f);
+#ifdef HAVE_XRENDER
+  int event_basep, error_basep;
+#endif
 
   eassert (input_blocked_p ());
 
@@ -2018,6 +2186,21 @@ x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth,
       return 0;
     }
 
+#ifdef HAVE_XRENDER
+  if (picture && XRenderQueryExtension (display, &event_basep, &error_basep))
+    {
+      XRenderPictFormat *format;
+      XRenderPictureAttributes attr;
+
+      /* FIXME: Do we need to handle all possible bit depths?  */
+      format = XRenderFindStandardFormat (display,
+                                          depth > 24 ? PictStandardARGB32
+                                          : depth > 8 ? PictStandardRGB24
+                                          : PictStandardA8);
+      *picture = XRenderCreatePicture (display, *pixmap, format, 0, &attr);
+    }
+#endif
+
   return 1;
 #endif /* HAVE_X_WINDOWS */
 
@@ -2163,7 +2346,8 @@ x_put_x_image (struct frame *f, XImagePtr ximg, Pixmap pixmap, int width, int he
 
   eassert (input_blocked_p ());
   gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL);
-  XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height);
+  XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0,
+             ximg->width, ximg->height);
   XFreeGC (FRAME_X_DISPLAY (f), gc);
 #endif /* HAVE_X_WINDOWS */
 
@@ -2192,7 +2376,11 @@ image_create_x_image_and_pixmap (struct frame *f, struct image *img,
   eassert ((!mask_p ? img->pixmap : img->mask) == NO_PIXMAP);
 
   return x_create_x_image_and_pixmap (f, width, height, depth, ximg,
-				      !mask_p ? &img->pixmap : &img->mask);
+				      !mask_p ? &img->pixmap : &img->mask
+#ifdef HAVE_XRENDER
+                                      , !mask_p ? &img->picture : &img->mask_picture
+#endif
+                                      );
 }
 
 /* Put X image XIMG into image IMG on frame F, as a mask if and only
@@ -8101,105 +8289,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 *);
@@ -9816,6 +9905,25 @@ DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0,
 			    Initialization
  ***********************************************************************/
 
+DEFUN ("image-scaling-p", Fimage_scaling_p, Simage_scaling_p, 0, 1, 0,
+       doc: /* Test whether FRAME supports resizing images.
+Return t if FRAME supports native scaling, nil otherwise.  */)
+     (Lisp_Object frame)
+{
+#ifdef HAVE_NS
+  return Qt;
+#elif defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER)
+  int event_basep, error_basep;
+
+  if (XRenderQueryExtension
+      (FRAME_X_DISPLAY (decode_window_system_frame (frame)),
+       &event_basep, &error_basep))
+    return Qt;
+#endif
+
+  return Qnil;
+}
+
 DEFUN ("init-image-library", Finit_image_library, Sinit_image_library, 1, 1, 0,
        doc: /* Initialize image library implementing image type TYPE.
 Return non-nil if TYPE is a supported image type.
@@ -10058,6 +10166,8 @@ non-numeric, there is no explicit limit on the size of images.  */);
   defsubr (&Slookup_image);
 #endif
 
+  defsubr (&Simage_scaling_p);
+
   DEFVAR_BOOL ("cross-disabled-images", cross_disabled_images,
     doc: /* Non-nil means always draw a cross over disabled images.
 Disabled images are those having a `:conversion disabled' property.
diff --git a/src/nsimage.m b/src/nsimage.m
index 7879c5891d..f16910de08 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;
@@ -151,6 +149,12 @@ Updated by Christian Limpach (chris@nice.ch)
   return [(id)img size].height;
 }
 
+void
+ns_image_set_size (void *img, int width, int height)
+{
+  [(EmacsImage *)img setSize:NSMakeSize (width, height)];
+}
+
 unsigned long
 ns_get_pixel (void *img, int x, int y)
 {
@@ -524,66 +528,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 089cbccbf0..78ce608554 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
 
@@ -1197,6 +1196,7 @@ extern bool ns_load_image (struct frame *f, struct image *img,
 			   Lisp_Object spec_file, Lisp_Object spec_data);
 extern int ns_image_width (void *img);
 extern int ns_image_height (void *img);
+extern void ns_image_set_size (void *img, int width, int height);
 extern unsigned long ns_get_pixel (void *img, int x, int y);
 extern void ns_put_pixel (void *img, int x, int y, unsigned long argb);
 extern void ns_set_alpha (void *img, int x, int y, unsigned char a);
diff --git a/src/nsterm.m b/src/nsterm.m
index 016c044760..cbb2d2a5ce 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);
     }
diff --git a/src/xterm.c b/src/xterm.c
index e9cebcebba..fbbf61d320 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
@@ -2976,6 +2971,46 @@ 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
+  if (s->img->picture)
+    {
+      Picture destination;
+      XRenderPictFormat *default_format;
+      XRenderPictureAttributes attr;
+
+      /* FIXME: Should we do this each time or would it make sense to
+         store destination in the frame struct?  */
+      default_format = XRenderFindVisualFormat (s->display,
+                                                DefaultVisual (s->display, 0));
+      destination = XRenderCreatePicture (s->display, dest,
+                                          default_format, 0, &attr);
+
+      /* FIXME: It may make sense to use PictOpSrc instead of
+         PictOpOver, as I don't know if we care about alpha values too
+         much here.  */
+      XRenderComposite (s->display, PictOpOver,
+                        s->img->picture, s->img->mask_picture, destination,
+                        srcX, srcY,
+                        srcX, srcY,
+                        dstX, dstY,
+                        width, height);
+
+      XRenderFreePicture (s->display, destination);
+    }
+  else
+#endif
+    XCopyArea (s->display, s->img->pixmap,
+               dest, s->gc,
+               srcX, srcY,
+               width, height, dstX, dstY);
+}
+
+
 /* Draw foreground of image glyph string S.  */
 
 static void
@@ -3007,6 +3042,7 @@ x_draw_image_foreground (struct glyph_string *s)
 	     trust on the shape extension to be available
 	     (XShapeCombineRegion).  So, compute the rectangle to draw
 	     manually.  */
+          /* FIXME: Do we need to do this when using XRender compositing?  */
 	  unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
 				| GCFunction);
 	  XGCValues xgcv;
@@ -3024,10 +3060,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 +3073,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
-- 
2.19.1


-- 
Alan Third



  reply	other threads:[~2019-01-01 21:47 UTC|newest]

Thread overview: 44+ 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
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                         ` Alan Third [this message]
2019-01-02 16:11                           ` [PATCH] Add native image scaling 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-05-14  6:15                                           ` bug#33587: [PROPOSED] Default to disabling ImageMagick Paul Eggert
2019-01-10 23:40                                         ` bug#33587: [PATCH v2] Add native image scaling (bug#33587) 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

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190101214719.GA18292@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 external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.