aboutsummaryrefslogtreecommitdiffstats
path: root/src/image.c
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/image.c
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/image.c')
-rw-r--r--src/image.c312
1 files changed, 208 insertions, 104 deletions
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.