diff options
| author | Alan Third | 2019-01-02 21:00:09 +0000 |
|---|---|---|
| committer | Alan Third | 2019-01-10 19:24:20 +0000 |
| commit | a1b7a3f2a3957a399d6c3c7bcffa07ac67da82fc (patch) | |
| tree | 478594bd679f2db099fcb6320750f24fcedf5fc6 | |
| parent | c342b26371480316024e1e5d63cd8b3f035dda69 (diff) | |
| download | emacs-a1b7a3f2a3957a399d6c3c7bcffa07ac67da82fc.tar.gz emacs-a1b7a3f2a3957a399d6c3c7bcffa07ac67da82fc.zip | |
Add native image scaling (bug#33587)
* 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.
* doc/lispref/display.texi (Image Descriptors): Document
image-scaling-p and add resizing descriptors.
(ImageMagick Images): Remove resizing descriptors.
| -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 | |||
| 3241 | CFLAGS=$late_CFLAGS | 3241 | CFLAGS=$late_CFLAGS |
| 3242 | fi | 3242 | fi |
| 3243 | 3243 | ||
| 3244 | # Check for XRender | ||
| 3245 | HAVE_XRENDER=no | ||
| 3246 | if test "${HAVE_X11}" = "yes"; then | ||
| 3247 | AC_CHECK_LIB(Xrender, XRenderQueryExtension, HAVE_XRENDER=yes) | ||
| 3248 | if test $HAVE_XRENDER = yes; then | ||
| 3249 | XRENDER_LIBS="-lXrender" | ||
| 3250 | AC_SUBST(XRENDER_LIBS) | ||
| 3251 | AC_DEFINE([HAVE_XRENDER], 1, [Define to 1 if XRender is available.]) | ||
| 3252 | fi | ||
| 3253 | fi | ||
| 3254 | |||
| 3244 | ### Start of font-backend (under any platform) section. | 3255 | ### Start of font-backend (under any platform) section. |
| 3245 | # (nothing here yet -- this is a placeholder) | 3256 | # (nothing here yet -- this is a placeholder) |
| 3246 | ### End of font-backend (under any platform) section. | 3257 | ### End of font-backend (under any platform) section. |
| @@ -3263,15 +3274,12 @@ if test "${HAVE_X11}" = "yes"; then | |||
| 3263 | EMACS_CHECK_MODULES([XFT], [xft >= 0.13.0], [], [HAVE_XFT=no]) | 3274 | EMACS_CHECK_MODULES([XFT], [xft >= 0.13.0], [], [HAVE_XFT=no]) |
| 3264 | ## Because xterm.c uses XRenderQueryExtension when XFT is | 3275 | ## Because xterm.c uses XRenderQueryExtension when XFT is |
| 3265 | ## enabled, we also need to link to -lXrender. | 3276 | ## enabled, we also need to link to -lXrender. |
| 3266 | HAVE_XRENDER=no | ||
| 3267 | AC_CHECK_LIB(Xrender, XRenderQueryExtension, HAVE_XRENDER=yes) | ||
| 3268 | if test "$HAVE_XFT" != no && test "$HAVE_XRENDER" != no; then | 3277 | if test "$HAVE_XFT" != no && test "$HAVE_XRENDER" != no; then |
| 3269 | OLD_CPPFLAGS="$CPPFLAGS" | 3278 | OLD_CPPFLAGS="$CPPFLAGS" |
| 3270 | OLD_CFLAGS="$CFLAGS" | 3279 | OLD_CFLAGS="$CFLAGS" |
| 3271 | OLD_LIBS="$LIBS" | 3280 | OLD_LIBS="$LIBS" |
| 3272 | CPPFLAGS="$CPPFLAGS $XFT_CFLAGS" | 3281 | CPPFLAGS="$CPPFLAGS $XFT_CFLAGS" |
| 3273 | CFLAGS="$CFLAGS $XFT_CFLAGS" | 3282 | CFLAGS="$CFLAGS $XFT_CFLAGS" |
| 3274 | XFT_LIBS="-lXrender $XFT_LIBS" | ||
| 3275 | LIBS="$XFT_LIBS $LIBS" | 3283 | LIBS="$XFT_LIBS $LIBS" |
| 3276 | AC_CHECK_HEADER(X11/Xft/Xft.h, | 3284 | AC_CHECK_HEADER(X11/Xft/Xft.h, |
| 3277 | AC_CHECK_LIB(Xft, XftFontOpen, HAVE_XFT=yes, , $XFT_LIBS) , , | 3285 | 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, | |||
| 5112 | @var{relief} is negative, shadows are drawn so that the image appears | 5112 | @var{relief} is negative, shadows are drawn so that the image appears |
| 5113 | as a pressed button; otherwise, it appears as an unpressed button. | 5113 | as a pressed button; otherwise, it appears as an unpressed button. |
| 5114 | 5114 | ||
| 5115 | @item :width @var{width}, :height @var{height} | ||
| 5116 | The @code{:width} and @code{:height} keywords are used for scaling the | ||
| 5117 | image. If only one of them is specified, the other one will be | ||
| 5118 | calculated so as to preserve the aspect ratio. If both are specified, | ||
| 5119 | aspect ratio may not be preserved. | ||
| 5120 | |||
| 5121 | @item :max-width @var{max-width}, :max-height @var{max-height} | ||
| 5122 | The @code{:max-width} and @code{:max-height} keywords are used for | ||
| 5123 | scaling if the size of the image exceeds these values. If | ||
| 5124 | @code{:width} is set, it will have precedence over @code{max-width}, | ||
| 5125 | and if @code{:height} is set, it will have precedence over | ||
| 5126 | @code{max-height}, but you can otherwise mix these keywords as you | ||
| 5127 | wish. | ||
| 5128 | |||
| 5129 | If both @code{:max-width} and @code{:height} are specified, but | ||
| 5130 | @code{:width} is not, preserving the aspect ratio might require that | ||
| 5131 | width exceeds @code{:max-width}. If this happens, scaling will use a | ||
| 5132 | smaller value for the height so as to preserve the aspect ratio while | ||
| 5133 | not exceeding @code{:max-width}. Similarly when both | ||
| 5134 | @code{:max-height} and @code{:width} are specified, but @code{:height} | ||
| 5135 | is not. For example, if you have a 200x100 image and specify that | ||
| 5136 | @code{:width} should be 400 and @code{:max-height} should be 150, | ||
| 5137 | you'll end up with an image that is 300x150: Preserving the aspect | ||
| 5138 | ratio and not exceeding the ``max'' setting. This combination of | ||
| 5139 | parameters is a useful way of saying ``display this image as large as | ||
| 5140 | possible, but no larger than the available display area''. | ||
| 5141 | |||
| 5142 | @item :scale @var{scale} | ||
| 5143 | This should be a number, where values higher than 1 means to increase | ||
| 5144 | the size, and lower means to decrease the size, by multiplying both | ||
| 5145 | the width and height. For instance, a value of 0.25 will make the | ||
| 5146 | image a quarter size of what it originally was. If the scaling makes | ||
| 5147 | the image larger than specified by @code{:max-width} or | ||
| 5148 | @code{:max-height}, the resulting size will not exceed those two | ||
| 5149 | values. If both @code{:scale} and @code{:height}/@code{:width} are | ||
| 5150 | specified, the height/width will be adjusted by the specified scaling | ||
| 5151 | factor. | ||
| 5152 | |||
| 5153 | @item :index @var{frame} | ||
| 5154 | @xref{Multi-Frame Images}. | ||
| 5155 | |||
| 5115 | @item :conversion @var{algorithm} | 5156 | @item :conversion @var{algorithm} |
| 5116 | This specifies a conversion algorithm that should be applied to the | 5157 | This specifies a conversion algorithm that should be applied to the |
| 5117 | image before it is displayed; the value, @var{algorithm}, specifies | 5158 | 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. | |||
| 5251 | (@pxref{Input Focus}). | 5292 | (@pxref{Input Focus}). |
| 5252 | @end defun | 5293 | @end defun |
| 5253 | 5294 | ||
| 5295 | @defun image-scaling-p &optional frame | ||
| 5296 | This function returns @code{t} if @var{frame} supports image scaling. | ||
| 5297 | @var{frame} @code{nil} or omitted means to use the selected frame | ||
| 5298 | (@pxref{Input Focus}). | ||
| 5299 | |||
| 5300 | If image scaling is not supported, @code{:width}, @code{:height}, | ||
| 5301 | @code{:scale}, @code{:max-width} and @code{:max-height} will only be | ||
| 5302 | usable through ImageMagick, if available (@pxref{ImageMagick Images}). | ||
| 5303 | @end defun | ||
| 5304 | |||
| 5254 | @node XBM Images | 5305 | @node XBM Images |
| 5255 | @subsection XBM Images | 5306 | @subsection XBM Images |
| 5256 | @cindex XBM | 5307 | @cindex XBM |
| @@ -5387,42 +5438,6 @@ color, which is used as the image's background color if the image | |||
| 5387 | supports transparency. If the value is @code{nil}, it defaults to the | 5438 | supports transparency. If the value is @code{nil}, it defaults to the |
| 5388 | frame's background color. | 5439 | frame's background color. |
| 5389 | 5440 | ||
| 5390 | @item :width @var{width}, :height @var{height} | ||
| 5391 | The @code{:width} and @code{:height} keywords are used for scaling the | ||
| 5392 | image. If only one of them is specified, the other one will be | ||
| 5393 | calculated so as to preserve the aspect ratio. If both are specified, | ||
| 5394 | aspect ratio may not be preserved. | ||
| 5395 | |||
| 5396 | @item :max-width @var{max-width}, :max-height @var{max-height} | ||
| 5397 | The @code{:max-width} and @code{:max-height} keywords are used for | ||
| 5398 | scaling if the size of the image of the image exceeds these values. | ||
| 5399 | If @code{:width} is set it will have precedence over @code{max-width}, | ||
| 5400 | and if @code{:height} is set it will have precedence over | ||
| 5401 | @code{max-height}, but you can otherwise mix these keywords as you | ||
| 5402 | wish. @code{:max-width} and @code{:max-height} will always preserve | ||
| 5403 | the aspect ratio. | ||
| 5404 | |||
| 5405 | If both @code{:width} and @code{:max-height} has been set (but | ||
| 5406 | @code{:height} has not been set), then @code{:max-height} will have | ||
| 5407 | precedence. The same is the case for the opposite combination: The | ||
| 5408 | ``max'' keyword has precedence. That is, if you have a 200x100 image | ||
| 5409 | and specify that @code{:width} should be 400 and @code{:max-height} | ||
| 5410 | should be 150, you'll end up with an image that is 300x150: Preserving | ||
| 5411 | the aspect ratio and not exceeding the ``max'' setting. This | ||
| 5412 | combination of parameters is a useful way of saying ``display this | ||
| 5413 | image as large as possible, but no larger than the available display | ||
| 5414 | area''. | ||
| 5415 | |||
| 5416 | @item :scale @var{scale} | ||
| 5417 | This should be a number, where values higher than 1 means to increase | ||
| 5418 | the size, and lower means to decrease the size. For instance, a value | ||
| 5419 | of 0.25 will make the image a quarter size of what it originally was. | ||
| 5420 | If the scaling makes the image larger than specified by | ||
| 5421 | @code{:max-width} or @code{:max-height}, the resulting size will not | ||
| 5422 | exceed those two values. If both @code{:scale} and | ||
| 5423 | @code{:height}/@code{:width} are specified, the height/width will be | ||
| 5424 | adjusted by the specified scaling factor. | ||
| 5425 | |||
| 5426 | @item :format @var{type} | 5441 | @item :format @var{type} |
| 5427 | The value, @var{type}, should be a symbol specifying the type of the | 5442 | The value, @var{type}, should be a symbol specifying the type of the |
| 5428 | image data, as found in @code{image-format-suffixes}. This is used | 5443 | 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. | |||
| 5431 | 5446 | ||
| 5432 | @item :rotation @var{angle} | 5447 | @item :rotation @var{angle} |
| 5433 | Specifies a rotation angle in degrees. | 5448 | Specifies a rotation angle in degrees. |
| 5434 | |||
| 5435 | @item :index @var{frame} | ||
| 5436 | @xref{Multi-Frame Images}. | ||
| 5437 | @end table | 5449 | @end table |
| 5438 | 5450 | ||
| 5439 | @node SVG Images | 5451 | @node SVG Images |
| @@ -1461,6 +1461,12 @@ that is non-nil, it will look for a file name handler for the current | |||
| 1461 | buffer's 'default-directory' and invoke that file name handler to make | 1461 | buffer's 'default-directory' and invoke that file name handler to make |
| 1462 | the process. That way 'make-process' can start remote processes. | 1462 | the process. That way 'make-process' can start remote processes. |
| 1463 | 1463 | ||
| 1464 | +++ | ||
| 1465 | ** Emacs now supports resizing images without ImageMagick on X window | ||
| 1466 | systems where the XRender extension is available, and on the NS port. | ||
| 1467 | The new function 'image-scaling-p' can be used to test whether any | ||
| 1468 | given frame supports resizing. | ||
| 1469 | |||
| 1464 | 1470 | ||
| 1465 | * Changes in Emacs 27.1 on Non-Free Operating Systems | 1471 | * Changes in Emacs 27.1 on Non-Free Operating Systems |
| 1466 | 1472 | ||
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%." | |||
| 982 | image)) | 982 | image)) |
| 983 | 983 | ||
| 984 | (defun image--get-imagemagick-and-warn () | 984 | (defun image--get-imagemagick-and-warn () |
| 985 | (unless (or (fboundp 'imagemagick-types) (featurep 'ns)) | 985 | (unless (or (fboundp 'imagemagick-types) (image-scaling-p)) |
| 986 | (error "Cannot rescale images without ImageMagick support")) | 986 | (error "Cannot rescale images on this terminal")) |
| 987 | (let ((image (image--get-image))) | 987 | (let ((image (image--get-image))) |
| 988 | (image-flush image) | 988 | (image-flush image) |
| 989 | (when (fboundp 'imagemagick-types) | 989 | (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@ | |||
| 127 | 127 | ||
| 128 | XCB_LIBS=@XCB_LIBS@ | 128 | XCB_LIBS=@XCB_LIBS@ |
| 129 | XFT_LIBS=@XFT_LIBS@ | 129 | XFT_LIBS=@XFT_LIBS@ |
| 130 | LIBX_EXTRA=-lX11 $(XCB_LIBS) $(XFT_LIBS) | 130 | XRENDER_LIBS=@XRENDER_LIBS@ |
| 131 | LIBX_EXTRA=-lX11 $(XCB_LIBS) $(XFT_LIBS) $(XRENDER_LIBS) | ||
| 131 | 132 | ||
| 132 | FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@ | 133 | FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@ |
| 133 | FONTCONFIG_LIBS = @FONTCONFIG_LIBS@ | 134 | 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/>. */ | |||
| 31 | #include <X11/Intrinsic.h> | 31 | #include <X11/Intrinsic.h> |
| 32 | #endif /* USE_X_TOOLKIT */ | 32 | #endif /* USE_X_TOOLKIT */ |
| 33 | 33 | ||
| 34 | #ifdef HAVE_XRENDER | ||
| 35 | #include <X11/extensions/Xrender.h> | ||
| 36 | #endif | ||
| 34 | #else /* !HAVE_X_WINDOWS */ | 37 | #else /* !HAVE_X_WINDOWS */ |
| 35 | 38 | ||
| 36 | /* X-related stuff used by non-X gui code. */ | 39 | /* X-related stuff used by non-X gui code. */ |
| @@ -2935,6 +2938,11 @@ struct redisplay_interface | |||
| 2935 | 2938 | ||
| 2936 | #ifdef HAVE_WINDOW_SYSTEM | 2939 | #ifdef HAVE_WINDOW_SYSTEM |
| 2937 | 2940 | ||
| 2941 | #if defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER) \ | ||
| 2942 | || defined (HAVE_NS) | ||
| 2943 | #define HAVE_NATIVE_SCALING | ||
| 2944 | #endif | ||
| 2945 | |||
| 2938 | /* Structure describing an image. Specific image formats like XBM are | 2946 | /* Structure describing an image. Specific image formats like XBM are |
| 2939 | converted into this form, so that display only has to deal with | 2947 | converted into this form, so that display only has to deal with |
| 2940 | this type of image. */ | 2948 | this type of image. */ |
| @@ -2958,6 +2966,11 @@ struct image | |||
| 2958 | and the latter is outdated. NULL means the X image has been | 2966 | and the latter is outdated. NULL means the X image has been |
| 2959 | synchronized to Pixmap. */ | 2967 | synchronized to Pixmap. */ |
| 2960 | XImagePtr ximg, mask_img; | 2968 | XImagePtr ximg, mask_img; |
| 2969 | |||
| 2970 | #ifdef HAVE_NATIVE_SCALING | ||
| 2971 | /* Picture versions of pixmap and mask for compositing. */ | ||
| 2972 | Picture picture, mask_picture; | ||
| 2973 | #endif | ||
| 2961 | #endif | 2974 | #endif |
| 2962 | 2975 | ||
| 2963 | /* Colors allocated for this image, if any. Allocated via xmalloc. */ | 2976 | /* 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) | |||
| 408 | dpyinfo->bitmaps_last = 0; | 408 | dpyinfo->bitmaps_last = 0; |
| 409 | } | 409 | } |
| 410 | 410 | ||
| 411 | #ifndef HAVE_XRENDER | ||
| 412 | /* Required for the definition of x_create_x_image_and_pixmap below. */ | ||
| 413 | typedef void Picture; | ||
| 414 | #endif | ||
| 415 | |||
| 411 | static bool x_create_x_image_and_pixmap (struct frame *, int, int, int, | 416 | static bool x_create_x_image_and_pixmap (struct frame *, int, int, int, |
| 412 | XImagePtr *, Pixmap *); | 417 | XImagePtr *, Pixmap *, Picture *); |
| 413 | static void x_destroy_x_image (XImagePtr ximg); | 418 | static void x_destroy_x_image (XImagePtr ximg); |
| 414 | 419 | ||
| 415 | #ifdef HAVE_NTGUI | 420 | #ifdef HAVE_NTGUI |
| @@ -472,7 +477,8 @@ x_create_bitmap_mask (struct frame *f, ptrdiff_t id) | |||
| 472 | return; | 477 | return; |
| 473 | } | 478 | } |
| 474 | 479 | ||
| 475 | result = x_create_x_image_and_pixmap (f, width, height, 1, &mask_img, &mask); | 480 | result = x_create_x_image_and_pixmap (f, width, height, 1, |
| 481 | &mask_img, &mask, NULL); | ||
| 476 | 482 | ||
| 477 | unblock_input (); | 483 | unblock_input (); |
| 478 | if (!result) | 484 | if (!result) |
| @@ -1011,6 +1017,13 @@ free_image (struct frame *f, struct image *img) | |||
| 1011 | 1017 | ||
| 1012 | c->images[img->id] = NULL; | 1018 | c->images[img->id] = NULL; |
| 1013 | 1019 | ||
| 1020 | #ifdef HAVE_XRENDER | ||
| 1021 | if (img->picture) | ||
| 1022 | XRenderFreePicture (FRAME_X_DISPLAY (f), img->picture); | ||
| 1023 | if (img->mask_picture) | ||
| 1024 | XRenderFreePicture (FRAME_X_DISPLAY (f), img->mask_picture); | ||
| 1025 | #endif | ||
| 1026 | |||
| 1014 | /* Windows NT redefines 'free', but in this file, we need to | 1027 | /* Windows NT redefines 'free', but in this file, we need to |
| 1015 | avoid the redefinition. */ | 1028 | avoid the redefinition. */ |
| 1016 | #ifdef WINDOWSNT | 1029 | #ifdef WINDOWSNT |
| @@ -1747,6 +1760,147 @@ postprocess_image (struct frame *f, struct image *img) | |||
| 1747 | } | 1760 | } |
| 1748 | } | 1761 | } |
| 1749 | 1762 | ||
| 1763 | #if defined (HAVE_IMAGEMAGICK) || defined (HAVE_NATIVE_SCALING) | ||
| 1764 | /* Scale an image size by returning SIZE / DIVISOR * MULTIPLIER, | ||
| 1765 | safely rounded and clipped to int range. */ | ||
| 1766 | |||
| 1767 | static int | ||
| 1768 | scale_image_size (int size, size_t divisor, size_t multiplier) | ||
| 1769 | { | ||
| 1770 | if (divisor != 0) | ||
| 1771 | { | ||
| 1772 | double s = size; | ||
| 1773 | double scaled = s * multiplier / divisor + 0.5; | ||
| 1774 | if (scaled < INT_MAX) | ||
| 1775 | return scaled; | ||
| 1776 | } | ||
| 1777 | return INT_MAX; | ||
| 1778 | } | ||
| 1779 | |||
| 1780 | /* Compute the desired size of an image with native size WIDTH x HEIGHT. | ||
| 1781 | Use SPEC to deduce the size. Store the desired size into | ||
| 1782 | *D_WIDTH x *D_HEIGHT. Store -1 x -1 if the native size is OK. */ | ||
| 1783 | static void | ||
| 1784 | compute_image_size (size_t width, size_t height, | ||
| 1785 | Lisp_Object spec, | ||
| 1786 | int *d_width, int *d_height) | ||
| 1787 | { | ||
| 1788 | Lisp_Object value; | ||
| 1789 | int desired_width = -1, desired_height = -1, max_width = -1, max_height = -1; | ||
| 1790 | double scale = 1; | ||
| 1791 | |||
| 1792 | value = image_spec_value (spec, QCscale, NULL); | ||
| 1793 | if (NUMBERP (value)) | ||
| 1794 | scale = XFLOATINT (value); | ||
| 1795 | |||
| 1796 | value = image_spec_value (spec, QCmax_width, NULL); | ||
| 1797 | if (FIXNATP (value)) | ||
| 1798 | max_width = min (XFIXNAT (value), INT_MAX); | ||
| 1799 | |||
| 1800 | value = image_spec_value (spec, QCmax_height, NULL); | ||
| 1801 | if (FIXNATP (value)) | ||
| 1802 | max_height = min (XFIXNAT (value), INT_MAX); | ||
| 1803 | |||
| 1804 | /* If width and/or height is set in the display spec assume we want | ||
| 1805 | to scale to those values. If either h or w is unspecified, the | ||
| 1806 | unspecified should be calculated from the specified to preserve | ||
| 1807 | aspect ratio. */ | ||
| 1808 | value = image_spec_value (spec, QCwidth, NULL); | ||
| 1809 | if (FIXNATP (value)) | ||
| 1810 | { | ||
| 1811 | desired_width = min (XFIXNAT (value) * scale, INT_MAX); | ||
| 1812 | /* :width overrides :max-width. */ | ||
| 1813 | max_width = -1; | ||
| 1814 | } | ||
| 1815 | |||
| 1816 | value = image_spec_value (spec, QCheight, NULL); | ||
| 1817 | if (FIXNATP (value)) | ||
| 1818 | { | ||
| 1819 | desired_height = min (XFIXNAT (value) * scale, INT_MAX); | ||
| 1820 | /* :height overrides :max-height. */ | ||
| 1821 | max_height = -1; | ||
| 1822 | } | ||
| 1823 | |||
| 1824 | /* If we have both width/height set explicitly, we skip past all the | ||
| 1825 | aspect ratio-preserving computations below. */ | ||
| 1826 | if (desired_width != -1 && desired_height != -1) | ||
| 1827 | goto out; | ||
| 1828 | |||
| 1829 | width = width * scale; | ||
| 1830 | height = height * scale; | ||
| 1831 | |||
| 1832 | if (desired_width != -1) | ||
| 1833 | /* Width known, calculate height. */ | ||
| 1834 | desired_height = scale_image_size (desired_width, width, height); | ||
| 1835 | else if (desired_height != -1) | ||
| 1836 | /* Height known, calculate width. */ | ||
| 1837 | desired_width = scale_image_size (desired_height, height, width); | ||
| 1838 | else | ||
| 1839 | { | ||
| 1840 | desired_width = width; | ||
| 1841 | desired_height = height; | ||
| 1842 | } | ||
| 1843 | |||
| 1844 | if (max_width != -1 && desired_width > max_width) | ||
| 1845 | { | ||
| 1846 | /* The image is wider than :max-width. */ | ||
| 1847 | desired_width = max_width; | ||
| 1848 | desired_height = scale_image_size (desired_width, width, height); | ||
| 1849 | } | ||
| 1850 | |||
| 1851 | if (max_height != -1 && desired_height > max_height) | ||
| 1852 | { | ||
| 1853 | /* The image is higher than :max-height. */ | ||
| 1854 | desired_height = max_height; | ||
| 1855 | desired_width = scale_image_size (desired_height, height, width); | ||
| 1856 | } | ||
| 1857 | |||
| 1858 | out: | ||
| 1859 | *d_width = desired_width; | ||
| 1860 | *d_height = desired_height; | ||
| 1861 | } | ||
| 1862 | |||
| 1863 | #ifdef HAVE_NATIVE_SCALING | ||
| 1864 | static void | ||
| 1865 | x_set_image_size (struct frame *f, struct image *img) | ||
| 1866 | { | ||
| 1867 | #ifdef HAVE_IMAGEMAGICK | ||
| 1868 | /* ImageMagick images are already the correct size. */ | ||
| 1869 | if (!EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick)) | ||
| 1870 | #endif | ||
| 1871 | { | ||
| 1872 | int width, height; | ||
| 1873 | |||
| 1874 | compute_image_size (img->width, img->height, img->spec, &width, &height); | ||
| 1875 | |||
| 1876 | #ifdef HAVE_NS | ||
| 1877 | ns_image_set_size (img->pixmap, width, height); | ||
| 1878 | img->width = width; | ||
| 1879 | img->height = height; | ||
| 1880 | #endif | ||
| 1881 | |||
| 1882 | #ifdef HAVE_XRENDER | ||
| 1883 | if (img->picture) | ||
| 1884 | { | ||
| 1885 | double xscale = (double) img->width/width; | ||
| 1886 | double yscale = (double) img->height/height; | ||
| 1887 | |||
| 1888 | XTransform tmat = {{{XDoubleToFixed (xscale), XDoubleToFixed (0), XDoubleToFixed (0)}, | ||
| 1889 | {XDoubleToFixed (0), XDoubleToFixed (yscale), XDoubleToFixed (0)}, | ||
| 1890 | {XDoubleToFixed (0), XDoubleToFixed (0), XDoubleToFixed (1)}}}; | ||
| 1891 | |||
| 1892 | XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest, 0, 0); | ||
| 1893 | XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->picture, &tmat); | ||
| 1894 | |||
| 1895 | img->width = width; | ||
| 1896 | img->height = height; | ||
| 1897 | } | ||
| 1898 | #endif | ||
| 1899 | } | ||
| 1900 | } | ||
| 1901 | #endif | ||
| 1902 | #endif /* HAVE_IMAGEMAGICK || HAVE_XRENDER || HAVE_NS */ | ||
| 1903 | |||
| 1750 | 1904 | ||
| 1751 | /* Return the id of image with Lisp specification SPEC on frame F. | 1905 | /* Return the id of image with Lisp specification SPEC on frame F. |
| 1752 | SPEC must be a valid Lisp image specification (see valid_image_p). */ | 1906 | SPEC must be a valid Lisp image specification (see valid_image_p). */ |
| @@ -1802,6 +1956,9 @@ lookup_image (struct frame *f, Lisp_Object spec) | |||
| 1802 | `:background COLOR'. */ | 1956 | `:background COLOR'. */ |
| 1803 | Lisp_Object ascent, margin, relief, bg; | 1957 | Lisp_Object ascent, margin, relief, bg; |
| 1804 | int relief_bound; | 1958 | int relief_bound; |
| 1959 | #ifdef HAVE_NATIVE_SCALING | ||
| 1960 | x_set_image_size (f, img); | ||
| 1961 | #endif | ||
| 1805 | 1962 | ||
| 1806 | ascent = image_spec_value (spec, QCascent, NULL); | 1963 | ascent = image_spec_value (spec, QCascent, NULL); |
| 1807 | if (FIXNUMP (ascent)) | 1964 | if (FIXNUMP (ascent)) |
| @@ -1976,12 +2133,15 @@ x_check_image_size (XImagePtr ximg, int width, int height) | |||
| 1976 | 2133 | ||
| 1977 | static bool | 2134 | static bool |
| 1978 | x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth, | 2135 | x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth, |
| 1979 | XImagePtr *ximg, Pixmap *pixmap) | 2136 | XImagePtr *ximg, Pixmap *pixmap, Picture *picture) |
| 1980 | { | 2137 | { |
| 1981 | #ifdef HAVE_X_WINDOWS | 2138 | #ifdef HAVE_X_WINDOWS |
| 1982 | Display *display = FRAME_X_DISPLAY (f); | 2139 | Display *display = FRAME_X_DISPLAY (f); |
| 1983 | Drawable drawable = FRAME_X_DRAWABLE (f); | 2140 | Drawable drawable = FRAME_X_DRAWABLE (f); |
| 1984 | Screen *screen = FRAME_X_SCREEN (f); | 2141 | Screen *screen = FRAME_X_SCREEN (f); |
| 2142 | #ifdef HAVE_XRENDER | ||
| 2143 | int event_basep, error_basep; | ||
| 2144 | #endif | ||
| 1985 | 2145 | ||
| 1986 | eassert (input_blocked_p ()); | 2146 | eassert (input_blocked_p ()); |
| 1987 | 2147 | ||
| @@ -2018,6 +2178,21 @@ x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth, | |||
| 2018 | return 0; | 2178 | return 0; |
| 2019 | } | 2179 | } |
| 2020 | 2180 | ||
| 2181 | #ifdef HAVE_XRENDER | ||
| 2182 | if (picture && XRenderQueryExtension (display, &event_basep, &error_basep)) | ||
| 2183 | { | ||
| 2184 | XRenderPictFormat *format; | ||
| 2185 | XRenderPictureAttributes attr; | ||
| 2186 | |||
| 2187 | /* FIXME: Do we need to handle all possible bit depths? */ | ||
| 2188 | format = XRenderFindStandardFormat (display, | ||
| 2189 | depth > 24 ? PictStandardARGB32 | ||
| 2190 | : depth > 8 ? PictStandardRGB24 | ||
| 2191 | : PictStandardA8); | ||
| 2192 | *picture = XRenderCreatePicture (display, *pixmap, format, 0, &attr); | ||
| 2193 | } | ||
| 2194 | #endif | ||
| 2195 | |||
| 2021 | return 1; | 2196 | return 1; |
| 2022 | #endif /* HAVE_X_WINDOWS */ | 2197 | #endif /* HAVE_X_WINDOWS */ |
| 2023 | 2198 | ||
| @@ -2163,7 +2338,8 @@ x_put_x_image (struct frame *f, XImagePtr ximg, Pixmap pixmap, int width, int he | |||
| 2163 | 2338 | ||
| 2164 | eassert (input_blocked_p ()); | 2339 | eassert (input_blocked_p ()); |
| 2165 | gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL); | 2340 | gc = XCreateGC (FRAME_X_DISPLAY (f), pixmap, 0, NULL); |
| 2166 | XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, width, height); | 2341 | XPutImage (FRAME_X_DISPLAY (f), pixmap, gc, ximg, 0, 0, 0, 0, |
| 2342 | ximg->width, ximg->height); | ||
| 2167 | XFreeGC (FRAME_X_DISPLAY (f), gc); | 2343 | XFreeGC (FRAME_X_DISPLAY (f), gc); |
| 2168 | #endif /* HAVE_X_WINDOWS */ | 2344 | #endif /* HAVE_X_WINDOWS */ |
| 2169 | 2345 | ||
| @@ -2192,7 +2368,13 @@ image_create_x_image_and_pixmap (struct frame *f, struct image *img, | |||
| 2192 | eassert ((!mask_p ? img->pixmap : img->mask) == NO_PIXMAP); | 2368 | eassert ((!mask_p ? img->pixmap : img->mask) == NO_PIXMAP); |
| 2193 | 2369 | ||
| 2194 | return x_create_x_image_and_pixmap (f, width, height, depth, ximg, | 2370 | return x_create_x_image_and_pixmap (f, width, height, depth, ximg, |
| 2195 | !mask_p ? &img->pixmap : &img->mask); | 2371 | !mask_p ? &img->pixmap : &img->mask, |
| 2372 | #ifdef HAVE_XRENDER | ||
| 2373 | !mask_p ? &img->picture : &img->mask_picture | ||
| 2374 | #else | ||
| 2375 | NULL | ||
| 2376 | #endif | ||
| 2377 | ); | ||
| 2196 | } | 2378 | } |
| 2197 | 2379 | ||
| 2198 | /* Put X image XIMG into image IMG on frame F, as a mask if and only | 2380 | /* 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) | |||
| 8101 | ImageMagick | 8283 | ImageMagick |
| 8102 | ***********************************************************************/ | 8284 | ***********************************************************************/ |
| 8103 | 8285 | ||
| 8104 | /* Scale an image size by returning SIZE / DIVISOR * MULTIPLIER, | ||
| 8105 | safely rounded and clipped to int range. */ | ||
| 8106 | |||
| 8107 | static int | ||
| 8108 | scale_image_size (int size, size_t divisor, size_t multiplier) | ||
| 8109 | { | ||
| 8110 | if (divisor != 0) | ||
| 8111 | { | ||
| 8112 | double s = size; | ||
| 8113 | double scaled = s * multiplier / divisor + 0.5; | ||
| 8114 | if (scaled < INT_MAX) | ||
| 8115 | return scaled; | ||
| 8116 | } | ||
| 8117 | return INT_MAX; | ||
| 8118 | } | ||
| 8119 | |||
| 8120 | /* Compute the desired size of an image with native size WIDTH x HEIGHT. | ||
| 8121 | Use SPEC to deduce the size. Store the desired size into | ||
| 8122 | *D_WIDTH x *D_HEIGHT. Store -1 x -1 if the native size is OK. */ | ||
| 8123 | static void | ||
| 8124 | compute_image_size (size_t width, size_t height, | ||
| 8125 | Lisp_Object spec, | ||
| 8126 | int *d_width, int *d_height) | ||
| 8127 | { | ||
| 8128 | Lisp_Object value; | ||
| 8129 | int desired_width = -1, desired_height = -1, max_width = -1, max_height = -1; | ||
| 8130 | double scale = 1; | ||
| 8131 | |||
| 8132 | value = image_spec_value (spec, QCscale, NULL); | ||
| 8133 | if (NUMBERP (value)) | ||
| 8134 | scale = XFLOATINT (value); | ||
| 8135 | |||
| 8136 | value = image_spec_value (spec, QCmax_width, NULL); | ||
| 8137 | if (FIXNATP (value)) | ||
| 8138 | max_width = min (XFIXNAT (value), INT_MAX); | ||
| 8139 | |||
| 8140 | value = image_spec_value (spec, QCmax_height, NULL); | ||
| 8141 | if (FIXNATP (value)) | ||
| 8142 | max_height = min (XFIXNAT (value), INT_MAX); | ||
| 8143 | |||
| 8144 | /* If width and/or height is set in the display spec assume we want | ||
| 8145 | to scale to those values. If either h or w is unspecified, the | ||
| 8146 | unspecified should be calculated from the specified to preserve | ||
| 8147 | aspect ratio. */ | ||
| 8148 | value = image_spec_value (spec, QCwidth, NULL); | ||
| 8149 | if (FIXNATP (value)) | ||
| 8150 | { | ||
| 8151 | desired_width = min (XFIXNAT (value) * scale, INT_MAX); | ||
| 8152 | /* :width overrides :max-width. */ | ||
| 8153 | max_width = -1; | ||
| 8154 | } | ||
| 8155 | |||
| 8156 | value = image_spec_value (spec, QCheight, NULL); | ||
| 8157 | if (FIXNATP (value)) | ||
| 8158 | { | ||
| 8159 | desired_height = min (XFIXNAT (value) * scale, INT_MAX); | ||
| 8160 | /* :height overrides :max-height. */ | ||
| 8161 | max_height = -1; | ||
| 8162 | } | ||
| 8163 | |||
| 8164 | /* If we have both width/height set explicitly, we skip past all the | ||
| 8165 | aspect ratio-preserving computations below. */ | ||
| 8166 | if (desired_width != -1 && desired_height != -1) | ||
| 8167 | goto out; | ||
| 8168 | |||
| 8169 | width = width * scale; | ||
| 8170 | height = height * scale; | ||
| 8171 | |||
| 8172 | if (desired_width != -1) | ||
| 8173 | /* Width known, calculate height. */ | ||
| 8174 | desired_height = scale_image_size (desired_width, width, height); | ||
| 8175 | else if (desired_height != -1) | ||
| 8176 | /* Height known, calculate width. */ | ||
| 8177 | desired_width = scale_image_size (desired_height, height, width); | ||
| 8178 | else | ||
| 8179 | { | ||
| 8180 | desired_width = width; | ||
| 8181 | desired_height = height; | ||
| 8182 | } | ||
| 8183 | |||
| 8184 | if (max_width != -1 && desired_width > max_width) | ||
| 8185 | { | ||
| 8186 | /* The image is wider than :max-width. */ | ||
| 8187 | desired_width = max_width; | ||
| 8188 | desired_height = scale_image_size (desired_width, width, height); | ||
| 8189 | } | ||
| 8190 | |||
| 8191 | if (max_height != -1 && desired_height > max_height) | ||
| 8192 | { | ||
| 8193 | /* The image is higher than :max-height. */ | ||
| 8194 | desired_height = max_height; | ||
| 8195 | desired_width = scale_image_size (desired_height, height, width); | ||
| 8196 | } | ||
| 8197 | |||
| 8198 | out: | ||
| 8199 | *d_width = desired_width; | ||
| 8200 | *d_height = desired_height; | ||
| 8201 | } | ||
| 8202 | |||
| 8203 | static bool imagemagick_image_p (Lisp_Object); | 8286 | static bool imagemagick_image_p (Lisp_Object); |
| 8204 | static bool imagemagick_load (struct frame *, struct image *); | 8287 | static bool imagemagick_load (struct frame *, struct image *); |
| 8205 | static void imagemagick_clear_image (struct frame *, struct image *); | 8288 | static void imagemagick_clear_image (struct frame *, struct image *); |
| @@ -9816,6 +9899,25 @@ DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, | |||
| 9816 | Initialization | 9899 | Initialization |
| 9817 | ***********************************************************************/ | 9900 | ***********************************************************************/ |
| 9818 | 9901 | ||
| 9902 | DEFUN ("image-scaling-p", Fimage_scaling_p, Simage_scaling_p, 0, 1, 0, | ||
| 9903 | doc: /* Test whether FRAME supports resizing images. | ||
| 9904 | Return t if FRAME supports native scaling, nil otherwise. */) | ||
| 9905 | (Lisp_Object frame) | ||
| 9906 | { | ||
| 9907 | #ifdef HAVE_NS | ||
| 9908 | return Qt; | ||
| 9909 | #elif defined (HAVE_X_WINDOWS) && defined (HAVE_XRENDER) | ||
| 9910 | int event_basep, error_basep; | ||
| 9911 | |||
| 9912 | if (XRenderQueryExtension | ||
| 9913 | (FRAME_X_DISPLAY (decode_window_system_frame (frame)), | ||
| 9914 | &event_basep, &error_basep)) | ||
| 9915 | return Qt; | ||
| 9916 | #endif | ||
| 9917 | |||
| 9918 | return Qnil; | ||
| 9919 | } | ||
| 9920 | |||
| 9819 | DEFUN ("init-image-library", Finit_image_library, Sinit_image_library, 1, 1, 0, | 9921 | DEFUN ("init-image-library", Finit_image_library, Sinit_image_library, 1, 1, 0, |
| 9820 | doc: /* Initialize image library implementing image type TYPE. | 9922 | doc: /* Initialize image library implementing image type TYPE. |
| 9821 | Return non-nil if TYPE is a supported image type. | 9923 | 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. */); | |||
| 10058 | defsubr (&Slookup_image); | 10160 | defsubr (&Slookup_image); |
| 10059 | #endif | 10161 | #endif |
| 10060 | 10162 | ||
| 10163 | defsubr (&Simage_scaling_p); | ||
| 10164 | |||
| 10061 | DEFVAR_BOOL ("cross-disabled-images", cross_disabled_images, | 10165 | DEFVAR_BOOL ("cross-disabled-images", cross_disabled_images, |
| 10062 | doc: /* Non-nil means always draw a cross over disabled images. | 10166 | doc: /* Non-nil means always draw a cross over disabled images. |
| 10063 | Disabled images are those having a `:conversion disabled' property. | 10167 | 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, | |||
| 126 | eImg = temp; | 126 | eImg = temp; |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | [eImg setSizeFromSpec:XCDR (img->spec)]; | ||
| 130 | |||
| 131 | size = [eImg size]; | 129 | size = [eImg size]; |
| 132 | img->width = size.width; | 130 | img->width = size.width; |
| 133 | img->height = size.height; | 131 | img->height = size.height; |
| @@ -151,6 +149,12 @@ ns_image_height (void *img) | |||
| 151 | return [(id)img size].height; | 149 | return [(id)img size].height; |
| 152 | } | 150 | } |
| 153 | 151 | ||
| 152 | void | ||
| 153 | ns_image_set_size (void *img, int width, int height) | ||
| 154 | { | ||
| 155 | [(EmacsImage *)img setSize:NSMakeSize (width, height)]; | ||
| 156 | } | ||
| 157 | |||
| 154 | unsigned long | 158 | unsigned long |
| 155 | ns_get_pixel (void *img, int x, int y) | 159 | ns_get_pixel (void *img, int x, int y) |
| 156 | { | 160 | { |
| @@ -524,66 +528,6 @@ ns_set_alpha (void *img, int x, int y, unsigned char a) | |||
| 524 | return YES; | 528 | return YES; |
| 525 | } | 529 | } |
| 526 | 530 | ||
| 527 | - (void)setSizeFromSpec: (Lisp_Object) spec | ||
| 528 | { | ||
| 529 | NSSize size = [self size]; | ||
| 530 | Lisp_Object value; | ||
| 531 | double scale = 1, aspect = size.width / size.height; | ||
| 532 | double width = -1, height = -1, max_width = -1, max_height = -1; | ||
| 533 | |||
| 534 | value = Fplist_get (spec, QCscale); | ||
| 535 | if (NUMBERP (value)) | ||
| 536 | scale = XFLOATINT (value) ; | ||
| 537 | |||
| 538 | value = Fplist_get (spec, QCmax_width); | ||
| 539 | if (NUMBERP (value)) | ||
| 540 | max_width = XFLOATINT (value); | ||
| 541 | |||
| 542 | value = Fplist_get (spec, QCmax_height); | ||
| 543 | if (NUMBERP (value)) | ||
| 544 | max_height = XFLOATINT (value); | ||
| 545 | |||
| 546 | value = Fplist_get (spec, QCwidth); | ||
| 547 | if (NUMBERP (value)) | ||
| 548 | { | ||
| 549 | width = XFLOATINT (value) * scale; | ||
| 550 | /* :width overrides :max-width. */ | ||
| 551 | max_width = -1; | ||
| 552 | } | ||
| 553 | |||
| 554 | value = Fplist_get (spec, QCheight); | ||
| 555 | if (NUMBERP (value)) | ||
| 556 | { | ||
| 557 | height = XFLOATINT (value) * scale; | ||
| 558 | /* :height overrides :max-height. */ | ||
| 559 | max_height = -1; | ||
| 560 | } | ||
| 561 | |||
| 562 | if (width <= 0 && height <= 0) | ||
| 563 | { | ||
| 564 | width = size.width * scale; | ||
| 565 | height = size.height * scale; | ||
| 566 | } | ||
| 567 | else if (width > 0 && height <= 0) | ||
| 568 | height = width / aspect; | ||
| 569 | else if (height > 0 && width <= 0) | ||
| 570 | width = height * aspect; | ||
| 571 | |||
| 572 | if (max_width > 0 && width > max_width) | ||
| 573 | { | ||
| 574 | width = max_width; | ||
| 575 | height = max_width / aspect; | ||
| 576 | } | ||
| 577 | |||
| 578 | if (max_height > 0 && height > max_height) | ||
| 579 | { | ||
| 580 | height = max_height; | ||
| 581 | width = max_height * aspect; | ||
| 582 | } | ||
| 583 | |||
| 584 | [self setSize:NSMakeSize(width, height)]; | ||
| 585 | } | ||
| 586 | |||
| 587 | - (instancetype)rotate: (double)rotation | 531 | - (instancetype)rotate: (double)rotation |
| 588 | { | 532 | { |
| 589 | EmacsImage *new_image; | 533 | 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; | |||
| 648 | - (NSColor *)stippleMask; | 648 | - (NSColor *)stippleMask; |
| 649 | - (Lisp_Object)getMetadata; | 649 | - (Lisp_Object)getMetadata; |
| 650 | - (BOOL)setFrame: (unsigned int) index; | 650 | - (BOOL)setFrame: (unsigned int) index; |
| 651 | - (void)setSizeFromSpec: (Lisp_Object) spec; | ||
| 652 | - (instancetype)rotate: (double)rotation; | 651 | - (instancetype)rotate: (double)rotation; |
| 653 | @end | 652 | @end |
| 654 | 653 | ||
| @@ -1197,6 +1196,7 @@ extern bool ns_load_image (struct frame *f, struct image *img, | |||
| 1197 | Lisp_Object spec_file, Lisp_Object spec_data); | 1196 | Lisp_Object spec_file, Lisp_Object spec_data); |
| 1198 | extern int ns_image_width (void *img); | 1197 | extern int ns_image_width (void *img); |
| 1199 | extern int ns_image_height (void *img); | 1198 | extern int ns_image_height (void *img); |
| 1199 | extern void ns_image_set_size (void *img, int width, int height); | ||
| 1200 | extern unsigned long ns_get_pixel (void *img, int x, int y); | 1200 | extern unsigned long ns_get_pixel (void *img, int x, int y); |
| 1201 | extern void ns_put_pixel (void *img, int x, int y, unsigned long argb); | 1201 | extern void ns_put_pixel (void *img, int x, int y, unsigned long argb); |
| 1202 | extern void ns_set_alpha (void *img, int x, int y, unsigned char a); | 1202 | 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, | |||
| 3121 | [img setXBMColor: bm_color]; | 3121 | [img setXBMColor: bm_color]; |
| 3122 | } | 3122 | } |
| 3123 | 3123 | ||
| 3124 | #ifdef NS_IMPL_COCOA | ||
| 3125 | // Note: For periodic images, the full image height is "h + hd". | 3124 | // Note: For periodic images, the full image height is "h + hd". |
| 3126 | // By using the height h, a suitable part of the image is used. | 3125 | // By using the height h, a suitable part of the image is used. |
| 3127 | NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h); | 3126 | NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h); |
| @@ -3134,13 +3133,6 @@ ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row, | |||
| 3134 | fraction: 1.0 | 3133 | fraction: 1.0 |
| 3135 | respectFlipped: YES | 3134 | respectFlipped: YES |
| 3136 | hints: nil]; | 3135 | hints: nil]; |
| 3137 | #else | ||
| 3138 | { | ||
| 3139 | NSPoint pt = imageRect.origin; | ||
| 3140 | pt.y += p->h; | ||
| 3141 | [img compositeToPoint: pt operation: NSCompositingOperationSourceOver]; | ||
| 3142 | } | ||
| 3143 | #endif | ||
| 3144 | } | 3136 | } |
| 3145 | ns_reset_clipping (f); | 3137 | ns_reset_clipping (f); |
| 3146 | } | 3138 | } |
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/>. */ | |||
| 38 | #include <X11/extensions/Xfixes.h> | 38 | #include <X11/extensions/Xfixes.h> |
| 39 | #endif | 39 | #endif |
| 40 | 40 | ||
| 41 | /* Using Xft implies that XRender is available. */ | ||
| 42 | #ifdef HAVE_XFT | ||
| 43 | #include <X11/extensions/Xrender.h> | ||
| 44 | #endif | ||
| 45 | |||
| 46 | #ifdef HAVE_XDBE | 41 | #ifdef HAVE_XDBE |
| 47 | #include <X11/extensions/Xdbe.h> | 42 | #include <X11/extensions/Xdbe.h> |
| 48 | #endif | 43 | #endif |
| @@ -2976,6 +2971,46 @@ x_draw_glyph_string_box (struct glyph_string *s) | |||
| 2976 | } | 2971 | } |
| 2977 | 2972 | ||
| 2978 | 2973 | ||
| 2974 | static void | ||
| 2975 | x_composite_image (struct glyph_string *s, Pixmap dest, | ||
| 2976 | int srcX, int srcY, int dstX, int dstY, | ||
| 2977 | int width, int height) | ||
| 2978 | { | ||
| 2979 | #ifdef HAVE_XRENDER | ||
| 2980 | if (s->img->picture) | ||
| 2981 | { | ||
| 2982 | Picture destination; | ||
| 2983 | XRenderPictFormat *default_format; | ||
| 2984 | XRenderPictureAttributes attr; | ||
| 2985 | |||
| 2986 | /* FIXME: Should we do this each time or would it make sense to | ||
| 2987 | store destination in the frame struct? */ | ||
| 2988 | default_format = XRenderFindVisualFormat (s->display, | ||
| 2989 | DefaultVisual (s->display, 0)); | ||
| 2990 | destination = XRenderCreatePicture (s->display, dest, | ||
| 2991 | default_format, 0, &attr); | ||
| 2992 | |||
| 2993 | /* FIXME: It may make sense to use PictOpSrc instead of | ||
| 2994 | PictOpOver, as I don't know if we care about alpha values too | ||
| 2995 | much here. */ | ||
| 2996 | XRenderComposite (s->display, PictOpOver, | ||
| 2997 | s->img->picture, s->img->mask_picture, destination, | ||
| 2998 | srcX, srcY, | ||
| 2999 | srcX, srcY, | ||
| 3000 | dstX, dstY, | ||
| 3001 | width, height); | ||
| 3002 | |||
| 3003 | XRenderFreePicture (s->display, destination); | ||
| 3004 | } | ||
| 3005 | else | ||
| 3006 | #endif | ||
| 3007 | XCopyArea (s->display, s->img->pixmap, | ||
| 3008 | dest, s->gc, | ||
| 3009 | srcX, srcY, | ||
| 3010 | width, height, dstX, dstY); | ||
| 3011 | } | ||
| 3012 | |||
| 3013 | |||
| 2979 | /* Draw foreground of image glyph string S. */ | 3014 | /* Draw foreground of image glyph string S. */ |
| 2980 | 3015 | ||
| 2981 | static void | 3016 | static void |
| @@ -3007,6 +3042,7 @@ x_draw_image_foreground (struct glyph_string *s) | |||
| 3007 | trust on the shape extension to be available | 3042 | trust on the shape extension to be available |
| 3008 | (XShapeCombineRegion). So, compute the rectangle to draw | 3043 | (XShapeCombineRegion). So, compute the rectangle to draw |
| 3009 | manually. */ | 3044 | manually. */ |
| 3045 | /* FIXME: Do we need to do this when using XRender compositing? */ | ||
| 3010 | unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin | 3046 | unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin |
| 3011 | | GCFunction); | 3047 | | GCFunction); |
| 3012 | XGCValues xgcv; | 3048 | XGCValues xgcv; |
| @@ -3024,10 +3060,8 @@ x_draw_image_foreground (struct glyph_string *s) | |||
| 3024 | image_rect.width = s->slice.width; | 3060 | image_rect.width = s->slice.width; |
| 3025 | image_rect.height = s->slice.height; | 3061 | image_rect.height = s->slice.height; |
| 3026 | if (x_intersect_rectangles (&clip_rect, &image_rect, &r)) | 3062 | if (x_intersect_rectangles (&clip_rect, &image_rect, &r)) |
| 3027 | XCopyArea (s->display, s->img->pixmap, | 3063 | x_composite_image (s, FRAME_X_DRAWABLE (s->f), s->slice.x + r.x - x, s->slice.y + r.y - y, |
| 3028 | FRAME_X_DRAWABLE (s->f), s->gc, | 3064 | r.x, r.y, r.width, r.height); |
| 3029 | s->slice.x + r.x - x, s->slice.y + r.y - y, | ||
| 3030 | r.width, r.height, r.x, r.y); | ||
| 3031 | } | 3065 | } |
| 3032 | else | 3066 | else |
| 3033 | { | 3067 | { |
| @@ -3039,10 +3073,8 @@ x_draw_image_foreground (struct glyph_string *s) | |||
| 3039 | image_rect.width = s->slice.width; | 3073 | image_rect.width = s->slice.width; |
| 3040 | image_rect.height = s->slice.height; | 3074 | image_rect.height = s->slice.height; |
| 3041 | if (x_intersect_rectangles (&clip_rect, &image_rect, &r)) | 3075 | if (x_intersect_rectangles (&clip_rect, &image_rect, &r)) |
| 3042 | XCopyArea (s->display, s->img->pixmap, | 3076 | x_composite_image (s, FRAME_X_DRAWABLE (s->f), s->slice.x + r.x - x, s->slice.y + r.y - y, |
| 3043 | FRAME_X_DRAWABLE (s->f), s->gc, | 3077 | r.x, r.y, r.width, r.height); |
| 3044 | s->slice.x + r.x - x, s->slice.y + r.y - y, | ||
| 3045 | r.width, r.height, r.x, r.y); | ||
| 3046 | 3078 | ||
| 3047 | /* When the image has a mask, we can expect that at | 3079 | /* When the image has a mask, we can expect that at |
| 3048 | least part of a mouse highlight or a block cursor will | 3080 | least part of a mouse highlight or a block cursor will |