aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlan Third2019-01-02 21:00:09 +0000
committerAlan Third2019-01-10 19:24:20 +0000
commita1b7a3f2a3957a399d6c3c7bcffa07ac67da82fc (patch)
tree478594bd679f2db099fcb6320750f24fcedf5fc6 /src
parentc342b26371480316024e1e5d63cd8b3f035dda69 (diff)
downloademacs-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.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in3
-rw-r--r--src/dispextern.h13
-rw-r--r--src/image.c312
-rw-r--r--src/nsimage.m68
-rw-r--r--src/nsterm.h2
-rw-r--r--src/nsterm.m8
-rw-r--r--src/xterm.c58
7 files changed, 275 insertions, 189 deletions
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
128XCB_LIBS=@XCB_LIBS@ 128XCB_LIBS=@XCB_LIBS@
129XFT_LIBS=@XFT_LIBS@ 129XFT_LIBS=@XFT_LIBS@
130LIBX_EXTRA=-lX11 $(XCB_LIBS) $(XFT_LIBS) 130XRENDER_LIBS=@XRENDER_LIBS@
131LIBX_EXTRA=-lX11 $(XCB_LIBS) $(XFT_LIBS) $(XRENDER_LIBS)
131 132
132FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@ 133FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
133FONTCONFIG_LIBS = @FONTCONFIG_LIBS@ 134FONTCONFIG_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. */
413typedef void Picture;
414#endif
415
411static bool x_create_x_image_and_pixmap (struct frame *, int, int, int, 416static bool x_create_x_image_and_pixmap (struct frame *, int, int, int,
412 XImagePtr *, Pixmap *); 417 XImagePtr *, Pixmap *, Picture *);
413static void x_destroy_x_image (XImagePtr ximg); 418static 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
1767static int
1768scale_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. */
1783static void
1784compute_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
1864static void
1865x_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
1977static bool 2134static bool
1978x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth, 2135x_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
8107static int
8108scale_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. */
8123static void
8124compute_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
8203static bool imagemagick_image_p (Lisp_Object); 8286static bool imagemagick_image_p (Lisp_Object);
8204static bool imagemagick_load (struct frame *, struct image *); 8287static bool imagemagick_load (struct frame *, struct image *);
8205static void imagemagick_clear_image (struct frame *, struct image *); 8288static 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
9902DEFUN ("image-scaling-p", Fimage_scaling_p, Simage_scaling_p, 0, 1, 0,
9903 doc: /* Test whether FRAME supports resizing images.
9904Return 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
9819DEFUN ("init-image-library", Finit_image_library, Sinit_image_library, 1, 1, 0, 9921DEFUN ("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.
9821Return non-nil if TYPE is a supported image type. 9923Return 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.
10063Disabled images are those having a `:conversion disabled' property. 10167Disabled 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
152void
153ns_image_set_size (void *img, int width, int height)
154{
155 [(EmacsImage *)img setSize:NSMakeSize (width, height)];
156}
157
154unsigned long 158unsigned long
155ns_get_pixel (void *img, int x, int y) 159ns_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);
1198extern int ns_image_width (void *img); 1197extern int ns_image_width (void *img);
1199extern int ns_image_height (void *img); 1198extern int ns_image_height (void *img);
1199extern void ns_image_set_size (void *img, int width, int height);
1200extern unsigned long ns_get_pixel (void *img, int x, int y); 1200extern unsigned long ns_get_pixel (void *img, int x, int y);
1201extern void ns_put_pixel (void *img, int x, int y, unsigned long argb); 1201extern void ns_put_pixel (void *img, int x, int y, unsigned long argb);
1202extern void ns_set_alpha (void *img, int x, int y, unsigned char a); 1202extern 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
2974static void
2975x_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
2981static void 3016static 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