diff options
-rw-r--r-- | configure.ac | 14 | ||||
-rw-r--r-- | doc/lispref/display.texi | 90 | ||||
-rw-r--r-- | etc/NEWS | 6 | ||||
-rw-r--r-- | lisp/image.el | 4 | ||||
-rw-r--r-- | src/Makefile.in | 3 | ||||
-rw-r--r-- | src/dispextern.h | 13 | ||||
-rw-r--r-- | src/image.c | 312 | ||||
-rw-r--r-- | src/nsimage.m | 68 | ||||
-rw-r--r-- | src/nsterm.h | 2 | ||||
-rw-r--r-- | src/nsterm.m | 8 | ||||
-rw-r--r-- | src/xterm.c | 58 |
11 files changed, 345 insertions, 233 deletions
diff --git a/configure.ac b/configure.ac index e5bd6943caf..16a2ce059df 100644 --- a/configure.ac +++ b/configure.ac @@ -3241,6 +3241,17 @@ either XPointer or XPointer*.])dnl 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 @@ if test "${HAVE_X11}" = "yes"; then 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/doc/lispref/display.texi b/doc/lispref/display.texi index 19424ecc7e6..350b3108715 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -5112,6 +5112,47 @@ This adds a shadow rectangle around the image. The value, @var{relief} is negative, shadows are drawn so that the image appears as a pressed button; otherwise, it appears as an unpressed button. +@item :width @var{width}, :height @var{height} +The @code{:width} and @code{:height} keywords are used for scaling the +image. If only one of them is specified, the other one will be +calculated so as to preserve the aspect ratio. If both are specified, +aspect ratio may not be preserved. + +@item :max-width @var{max-width}, :max-height @var{max-height} +The @code{:max-width} and @code{:max-height} keywords are used for +scaling if the size of the image exceeds these values. If +@code{:width} is set, it will have precedence over @code{max-width}, +and if @code{:height} is set, it will have precedence over +@code{max-height}, but you can otherwise mix these keywords as you +wish. + +If both @code{:max-width} and @code{:height} are specified, but +@code{:width} is not, preserving the aspect ratio might require that +width exceeds @code{:max-width}. If this happens, scaling will use a +smaller value for the height so as to preserve the aspect ratio while +not exceeding @code{:max-width}. Similarly when both +@code{:max-height} and @code{:width} are specified, but @code{:height} +is not. For example, if you have a 200x100 image and specify that +@code{:width} should be 400 and @code{:max-height} should be 150, +you'll end up with an image that is 300x150: Preserving the aspect +ratio and not exceeding the ``max'' setting. This combination of +parameters is a useful way of saying ``display this image as large as +possible, but no larger than the available display area''. + +@item :scale @var{scale} +This should be a number, where values higher than 1 means to increase +the size, and lower means to decrease the size, by multiplying both +the width and height. For instance, a value of 0.25 will make the +image a quarter size of what it originally was. If the scaling makes +the image larger than specified by @code{:max-width} or +@code{:max-height}, the resulting size will not exceed those two +values. If both @code{:scale} and @code{:height}/@code{:width} are +specified, the height/width will be adjusted by the specified scaling +factor. + +@item :index @var{frame} +@xref{Multi-Frame Images}. + @item :conversion @var{algorithm} This specifies a conversion algorithm that should be applied to the image before it is displayed; the value, @var{algorithm}, specifies @@ -5251,6 +5292,16 @@ This function returns @code{t} if image @var{spec} has a mask bitmap. (@pxref{Input Focus}). @end defun +@defun image-scaling-p &optional frame +This function returns @code{t} if @var{frame} supports image scaling. +@var{frame} @code{nil} or omitted means to use the selected frame +(@pxref{Input Focus}). + +If image scaling is not supported, @code{:width}, @code{:height}, +@code{:scale}, @code{:max-width} and @code{:max-height} will only be +usable through ImageMagick, if available (@pxref{ImageMagick Images}). +@end defun + @node XBM Images @subsection XBM Images @cindex XBM @@ -5387,42 +5438,6 @@ color, which is used as the image's background color if the image supports transparency. If the value is @code{nil}, it defaults to the frame's background color. -@item :width @var{width}, :height @var{height} -The @code{:width} and @code{:height} keywords are used for scaling the -image. If only one of them is specified, the other one will be -calculated so as to preserve the aspect ratio. If both are specified, -aspect ratio may not be preserved. - -@item :max-width @var{max-width}, :max-height @var{max-height} -The @code{:max-width} and @code{:max-height} keywords are used for -scaling if the size of the image of the image exceeds these values. -If @code{:width} is set it will have precedence over @code{max-width}, -and if @code{:height} is set it will have precedence over -@code{max-height}, but you can otherwise mix these keywords as you -wish. @code{:max-width} and @code{:max-height} will always preserve -the aspect ratio. - -If both @code{:width} and @code{:max-height} has been set (but -@code{:height} has not been set), then @code{:max-height} will have -precedence. The same is the case for the opposite combination: The -``max'' keyword has precedence. That is, if you have a 200x100 image -and specify that @code{:width} should be 400 and @code{:max-height} -should be 150, you'll end up with an image that is 300x150: Preserving -the aspect ratio and not exceeding the ``max'' setting. This -combination of parameters is a useful way of saying ``display this -image as large as possible, but no larger than the available display -area''. - -@item :scale @var{scale} -This should be a number, where values higher than 1 means to increase -the size, and lower means to decrease the size. For instance, a value -of 0.25 will make the image a quarter size of what it originally was. -If the scaling makes the image larger than specified by -@code{:max-width} or @code{:max-height}, the resulting size will not -exceed those two values. If both @code{:scale} and -@code{:height}/@code{:width} are specified, the height/width will be -adjusted by the specified scaling factor. - @item :format @var{type} The value, @var{type}, should be a symbol specifying the type of the image data, as found in @code{image-format-suffixes}. This is used @@ -5431,9 +5446,6 @@ hint to ImageMagick to help it detect the image type. @item :rotation @var{angle} Specifies a rotation angle in degrees. - -@item :index @var{frame} -@xref{Multi-Frame Images}. @end table @node SVG Images @@ -1461,6 +1461,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. + * Changes in Emacs 27.1 on Non-Free Operating Systems diff --git a/lisp/image.el b/lisp/image.el index 5727d8fbce5..2e84e47b5c0 100644 --- a/lisp/image.el +++ b/lisp/image.el @@ -982,8 +982,8 @@ default is 20%." 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 e9831e92995..f409ed4db28 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -127,7 +127,8 @@ LIBIMAGE=@LIBTIFF@ @LIBJPEG@ @LIBPNG@ @LIBGIF@ @LIBXPM@ 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 5774e3e9514..b064875ac46 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 87e0c071eef..84c31dcfc3c 100644 --- a/src/image.c +++ b/src/image.c @@ -408,8 +408,13 @@ x_destroy_all_bitmaps (Display_Info *dpyinfo) dpyinfo->bitmaps_last = 0; } +#ifndef HAVE_XRENDER +/* Required for the definition of x_create_x_image_and_pixmap below. */ +typedef void Picture; +#endif + static bool x_create_x_image_and_pixmap (struct frame *, int, int, int, - XImagePtr *, Pixmap *); + XImagePtr *, Pixmap *, Picture *); static void x_destroy_x_image (XImagePtr ximg); #ifdef HAVE_NTGUI @@ -472,7 +477,8 @@ 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, NULL); unblock_input (); if (!result) @@ -1011,6 +1017,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 +1760,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 (!EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick)) +#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 +1956,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)) @@ -1976,12 +2133,15 @@ x_check_image_size (XImagePtr ximg, int width, int height) static bool x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth, - XImagePtr *ximg, Pixmap *pixmap) + XImagePtr *ximg, Pixmap *pixmap, Picture *picture) { #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 +2178,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 +2338,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 +2368,13 @@ 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 +#else + NULL +#endif + ); } /* Put X image XIMG into image IMG on frame F, as a mask if and only @@ -8101,105 +8283,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 +9899,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 +10160,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 7879c5891d6..f16910de088 100644 --- a/src/nsimage.m +++ b/src/nsimage.m @@ -126,8 +126,6 @@ ns_load_image (struct frame *f, struct image *img, eImg = temp; } - [eImg setSizeFromSpec:XCDR (img->spec)]; - size = [eImg size]; img->width = size.width; img->height = size.height; @@ -151,6 +149,12 @@ ns_image_height (void *img) 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 @@ ns_set_alpha (void *img, int x, int y, unsigned char a) 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 089cbccbf0c..78ce6085545 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 2bce4a89aea..6383e4b7ab5 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -3121,7 +3121,6 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row, [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 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row, 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 e9cebcebba4..fbbf61d320d 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 |