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 /src | |
| 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.
Diffstat (limited to 'src')
| -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 |
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 | ||
| 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 |