diff options
| author | Alan Third | 2019-06-05 21:51:33 +0100 |
|---|---|---|
| committer | Alan Third | 2019-06-05 22:28:46 +0100 |
| commit | 610fb73ab6d7a22b722f523d6ebc4aa8fa1db7c9 (patch) | |
| tree | 8a3ee992ccc310071ac5a97ced8907652974c88e /src | |
| parent | 9201cf62ce9f17793bb6103050c9ba27eb942e57 (diff) | |
| download | emacs-610fb73ab6d7a22b722f523d6ebc4aa8fa1db7c9.tar.gz emacs-610fb73ab6d7a22b722f523d6ebc4aa8fa1db7c9.zip | |
Add native image rotation and cropping
* lisp/image.el (image--get-imagemagick-and-warn): Only fallback to
ImageMagick if native transforms aren't available.
* src/dispextern.h (INIT_MATRIX, COPY_MATRIX, MULT_MATRICES): New
macros for matrix manipulation.
(HAVE_NATIVE_SCALING, HAVE_NATIVE_TRANSFORMS): Rename and change all
relevant locations.
* src/image.c (x_set_image_rotation):
(x_set_transform): New functions.
(x_set_image_size): Use transform matrix for resizing under X and NS.
(x_set_image_crop): New function.
(lookup_image): Use the new transform functions.
(Fimage_scaling_p, Fimage_transforms_p): Rename and update all
callers.
* src/nsimage.m (ns_load_image): Remove rotation code.
(ns_image_set_transform): New function.
([EmacsImage dealloc]): Release the saved transform.
([EmacsImage rotate:]): Remove unneeded method.
([EmacsImage setTransform:]): New method.
* src/nsterm.h (EmacsImage): Add transform property and update method
definitions.
* src/nsterm.m (ns_dumpglyphs_image): Use the transform to draw the
image correctly.
* src/xterm.c (x_composite_image): Use PictOpSrc as we don't care
about alpha values here.
* doc/lispref/display.texi (Image Descriptors): Add :rotation.
(ImageMagick Images): Remove :rotation.
Diffstat (limited to 'src')
| -rw-r--r-- | src/dispextern.h | 22 | ||||
| -rw-r--r-- | src/image.c | 283 | ||||
| -rw-r--r-- | src/nsimage.m | 64 | ||||
| -rw-r--r-- | src/nsterm.h | 5 | ||||
| -rw-r--r-- | src/nsterm.m | 41 | ||||
| -rw-r--r-- | src/xterm.c | 5 |
6 files changed, 326 insertions, 94 deletions
diff --git a/src/dispextern.h b/src/dispextern.h index 70ae96b8243..a21edd818f0 100644 --- a/src/dispextern.h +++ b/src/dispextern.h | |||
| @@ -2989,7 +2989,25 @@ struct redisplay_interface | |||
| 2989 | #ifdef HAVE_WINDOW_SYSTEM | 2989 | #ifdef HAVE_WINDOW_SYSTEM |
| 2990 | 2990 | ||
| 2991 | # if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS || defined HAVE_NTGUI | 2991 | # if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS || defined HAVE_NTGUI |
| 2992 | # define HAVE_NATIVE_SCALING | 2992 | # define HAVE_NATIVE_TRANSFORMS |
| 2993 | |||
| 2994 | # define INIT_MATRIX(m) \ | ||
| 2995 | for (int i = 0 ; i < 3 ; i++) \ | ||
| 2996 | for (int j = 0 ; j < 3 ; j++) \ | ||
| 2997 | m[i][j] = (i == j) ? 1 : 0; | ||
| 2998 | |||
| 2999 | # define COPY_MATRIX(a, b) \ | ||
| 3000 | for (int i = 0 ; i < 3 ; i++) \ | ||
| 3001 | for (int j = 0 ; j < 3 ; j++) \ | ||
| 3002 | b[i][j] = a[i][j]; | ||
| 3003 | |||
| 3004 | # define MULT_MATRICES(a, b, result) \ | ||
| 3005 | for (int i = 0 ; i < 3 ; i++) \ | ||
| 3006 | for (int j = 0 ; j < 3 ; j++) { \ | ||
| 3007 | double sum = 0; \ | ||
| 3008 | for (int k = 0 ; k < 3 ; k++) \ | ||
| 3009 | sum += a[k][j] * b[i][k]; \ | ||
| 3010 | result[i][j] = sum;} | ||
| 2993 | # endif | 3011 | # endif |
| 2994 | 3012 | ||
| 2995 | /* Structure describing an image. Specific image formats like XBM are | 3013 | /* Structure describing an image. Specific image formats like XBM are |
| @@ -3015,7 +3033,7 @@ struct image | |||
| 3015 | synchronized to Pixmap. */ | 3033 | synchronized to Pixmap. */ |
| 3016 | XImage *ximg, *mask_img; | 3034 | XImage *ximg, *mask_img; |
| 3017 | 3035 | ||
| 3018 | # ifdef HAVE_NATIVE_SCALING | 3036 | # ifdef HAVE_NATIVE_TRANSFORMS |
| 3019 | /* Picture versions of pixmap and mask for compositing. */ | 3037 | /* Picture versions of pixmap and mask for compositing. */ |
| 3020 | Picture picture, mask_picture; | 3038 | Picture picture, mask_picture; |
| 3021 | # endif | 3039 | # endif |
diff --git a/src/image.c b/src/image.c index 9b0080130bc..a95a7bf27f9 100644 --- a/src/image.c +++ b/src/image.c | |||
| @@ -1841,7 +1841,7 @@ postprocess_image (struct frame *f, struct image *img) | |||
| 1841 | } | 1841 | } |
| 1842 | } | 1842 | } |
| 1843 | 1843 | ||
| 1844 | #if defined (HAVE_IMAGEMAGICK) || defined (HAVE_NATIVE_SCALING) | 1844 | #if defined (HAVE_IMAGEMAGICK) || defined (HAVE_NATIVE_TRANSFORMS) |
| 1845 | /* Scale an image size by returning SIZE / DIVISOR * MULTIPLIER, | 1845 | /* Scale an image size by returning SIZE / DIVISOR * MULTIPLIER, |
| 1846 | safely rounded and clipped to int range. */ | 1846 | safely rounded and clipped to int range. */ |
| 1847 | 1847 | ||
| @@ -1940,49 +1940,241 @@ compute_image_size (size_t width, size_t height, | |||
| 1940 | *d_width = desired_width; | 1940 | *d_width = desired_width; |
| 1941 | *d_height = desired_height; | 1941 | *d_height = desired_height; |
| 1942 | } | 1942 | } |
| 1943 | #endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_SCALING */ | 1943 | #endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_TRANSFORMS */ |
| 1944 | 1944 | ||
| 1945 | static void | 1945 | static void |
| 1946 | image_set_image_size (struct frame *f, struct image *img) | 1946 | image_set_rotation (struct image *img, double tm[3][3]) |
| 1947 | { | 1947 | { |
| 1948 | #ifdef HAVE_NATIVE_SCALING | 1948 | #ifdef HAVE_NATIVE_TRANSFORMS |
| 1949 | # ifdef HAVE_IMAGEMAGICK | 1949 | # ifdef HAVE_IMAGEMAGICK |
| 1950 | /* ImageMagick images are already the correct size. */ | 1950 | /* ImageMagick images are already rotated. */ |
| 1951 | if (EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick)) | 1951 | if (EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick)) |
| 1952 | return; | 1952 | return; |
| 1953 | # endif | 1953 | # endif |
| 1954 | 1954 | ||
| 1955 | int width, height; | 1955 | # ifdef HAVE_XRENDER |
| 1956 | compute_image_size (img->width, img->height, img->spec, &width, &height); | 1956 | if (!img->picture) |
| 1957 | return; | ||
| 1958 | # endif | ||
| 1959 | |||
| 1960 | Lisp_Object value; | ||
| 1961 | double t[3][3], rot[3][3], tmp[3][3], tmp2[3][3]; | ||
| 1962 | int rotation, cos_r, sin_r, width, height; | ||
| 1963 | |||
| 1964 | value = image_spec_value (img->spec, QCrotation, NULL); | ||
| 1965 | if (! NUMBERP (value)) | ||
| 1966 | return; | ||
| 1967 | |||
| 1968 | rotation = XFLOATINT (value); | ||
| 1969 | rotation = rotation % 360; | ||
| 1970 | |||
| 1971 | if (rotation < 0) | ||
| 1972 | rotation += 360; | ||
| 1973 | |||
| 1974 | if (rotation == 0) | ||
| 1975 | return; | ||
| 1976 | |||
| 1977 | if (rotation == 90) | ||
| 1978 | { | ||
| 1979 | width = img->height; | ||
| 1980 | height = img->width; | ||
| 1981 | |||
| 1982 | cos_r = 0; | ||
| 1983 | sin_r = 1; | ||
| 1984 | } | ||
| 1985 | else if (rotation == 180) | ||
| 1986 | { | ||
| 1987 | width = img->width; | ||
| 1988 | height = img->height; | ||
| 1989 | |||
| 1990 | cos_r = -1; | ||
| 1991 | sin_r = 0; | ||
| 1992 | } | ||
| 1993 | else if (rotation == 270) | ||
| 1994 | { | ||
| 1995 | width = img->height; | ||
| 1996 | height = img->width; | ||
| 1997 | |||
| 1998 | cos_r = 0; | ||
| 1999 | sin_r = -1; | ||
| 2000 | } | ||
| 2001 | else | ||
| 2002 | { | ||
| 2003 | image_error ("Native image rotation only supports multiples of 90 degrees"); | ||
| 2004 | return; | ||
| 2005 | } | ||
| 2006 | |||
| 2007 | /* Translate so (0, 0) is in the centre of the image. */ | ||
| 2008 | INIT_MATRIX (t); | ||
| 2009 | t[2][0] = img->width/2; | ||
| 2010 | t[2][1] = img->height/2; | ||
| 2011 | |||
| 2012 | MULT_MATRICES (tm, t, tmp); | ||
| 2013 | |||
| 2014 | /* Rotate. */ | ||
| 2015 | INIT_MATRIX (rot); | ||
| 2016 | rot[0][0] = cos_r; | ||
| 2017 | rot[1][0] = sin_r; | ||
| 2018 | rot[0][1] = - sin_r; | ||
| 2019 | rot[1][1] = cos_r; | ||
| 2020 | |||
| 2021 | MULT_MATRICES (tmp, rot, tmp2); | ||
| 2022 | |||
| 2023 | /* Translate back. */ | ||
| 2024 | INIT_MATRIX (t); | ||
| 2025 | t[2][0] = - width/2; | ||
| 2026 | t[2][1] = - height/2; | ||
| 2027 | |||
| 2028 | MULT_MATRICES (tmp2, t, tm); | ||
| 1957 | 2029 | ||
| 1958 | # ifdef HAVE_NS | ||
| 1959 | ns_image_set_size (img->pixmap, width, height); | ||
| 1960 | img->width = width; | 2030 | img->width = width; |
| 1961 | img->height = height; | 2031 | img->height = height; |
| 2032 | #endif | ||
| 2033 | } | ||
| 2034 | |||
| 2035 | static void | ||
| 2036 | image_set_crop (struct image *img, double tm[3][3]) | ||
| 2037 | { | ||
| 2038 | #ifdef HAVE_NATIVE_TRANSFORMS | ||
| 2039 | # ifdef HAVE_IMAGEMAGICK | ||
| 2040 | /* ImageMagick images are already cropped. */ | ||
| 2041 | if (EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick)) | ||
| 2042 | return; | ||
| 1962 | # endif | 2043 | # endif |
| 1963 | 2044 | ||
| 1964 | # ifdef USE_CAIRO | 2045 | # ifdef USE_CAIRO |
| 1965 | img->width = width; | 2046 | img->width = width; |
| 1966 | img->height = height; | 2047 | img->height = height; |
| 1967 | # elif defined HAVE_XRENDER | 2048 | # elif defined HAVE_XRENDER |
| 1968 | if (img->picture) | 2049 | if (!img->picture) |
| 2050 | return; | ||
| 2051 | # endif | ||
| 2052 | |||
| 2053 | double m[3][3], tmp[3][3]; | ||
| 2054 | int left, top, width, height; | ||
| 2055 | Lisp_Object x = Qnil; | ||
| 2056 | Lisp_Object y = Qnil; | ||
| 2057 | Lisp_Object w = Qnil; | ||
| 2058 | Lisp_Object h = Qnil; | ||
| 2059 | Lisp_Object crop = image_spec_value (img->spec, QCcrop, NULL); | ||
| 2060 | |||
| 2061 | if (!CONSP (crop)) | ||
| 2062 | return; | ||
| 2063 | else | ||
| 1969 | { | 2064 | { |
| 1970 | double xscale = img->width / (double) width; | 2065 | w = XCAR (crop); |
| 1971 | double yscale = img->height / (double) height; | 2066 | crop = XCDR (crop); |
| 2067 | if (CONSP (crop)) | ||
| 2068 | { | ||
| 2069 | h = XCAR (crop); | ||
| 2070 | crop = XCDR (crop); | ||
| 2071 | if (CONSP (crop)) | ||
| 2072 | { | ||
| 2073 | x = XCAR (crop); | ||
| 2074 | crop = XCDR (crop); | ||
| 2075 | if (CONSP (crop)) | ||
| 2076 | y = XCAR (crop); | ||
| 2077 | } | ||
| 2078 | } | ||
| 2079 | } | ||
| 1972 | 2080 | ||
| 1973 | XTransform tmat | 2081 | if (FIXNATP (w) && XFIXNAT (w) < img->width) |
| 1974 | = {{{XDoubleToFixed (xscale), XDoubleToFixed (0), XDoubleToFixed (0)}, | 2082 | width = XFIXNAT (w); |
| 1975 | {XDoubleToFixed (0), XDoubleToFixed (yscale), XDoubleToFixed (0)}, | 2083 | else |
| 1976 | {XDoubleToFixed (0), XDoubleToFixed (0), XDoubleToFixed (1)}}}; | 2084 | width = img->width; |
| 1977 | 2085 | ||
| 1978 | XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest, | 2086 | if (TYPE_RANGED_FIXNUMP (int, x)) |
| 1979 | 0, 0); | 2087 | { |
| 1980 | XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->picture, &tmat); | 2088 | left = XFIXNUM (x); |
| 2089 | if (left < 0) | ||
| 2090 | left = img->width - width + left; | ||
| 2091 | } | ||
| 2092 | else | ||
| 2093 | left = (img->width - width)/2; | ||
| 2094 | |||
| 2095 | if (FIXNATP (h) && XFIXNAT (h) < img->height) | ||
| 2096 | height = XFIXNAT (h); | ||
| 2097 | else | ||
| 2098 | height = img->height; | ||
| 2099 | |||
| 2100 | if (TYPE_RANGED_FIXNUMP (int, y)) | ||
| 2101 | { | ||
| 2102 | top = XFIXNUM (y); | ||
| 2103 | if (top < 0) | ||
| 2104 | top = img->height - height + top; | ||
| 2105 | } | ||
| 2106 | else | ||
| 2107 | top = (img->height - height)/2; | ||
| 2108 | |||
| 2109 | /* Negative values operate from the right and bottom of the image | ||
| 2110 | instead of the left and top. */ | ||
| 2111 | if (left < 0) | ||
| 2112 | { | ||
| 2113 | width = img->width + left; | ||
| 2114 | left = 0; | ||
| 2115 | } | ||
| 2116 | |||
| 2117 | if (width + left > img->width) | ||
| 2118 | width = img->width - left; | ||
| 1981 | 2119 | ||
| 1982 | img->width = width; | 2120 | if (top < 0) |
| 1983 | img->height = height; | 2121 | { |
| 2122 | height = img->height + top; | ||
| 2123 | top = 0; | ||
| 1984 | } | 2124 | } |
| 2125 | |||
| 2126 | if (height + top > img->height) | ||
| 2127 | height = img->height - top; | ||
| 2128 | |||
| 2129 | INIT_MATRIX (m); | ||
| 2130 | m[2][0] = left; | ||
| 2131 | m[2][1] = top; | ||
| 2132 | |||
| 2133 | MULT_MATRICES (tm, m, tmp); | ||
| 2134 | COPY_MATRIX (tmp, tm); | ||
| 2135 | |||
| 2136 | img->width = width; | ||
| 2137 | img->height = height; | ||
| 2138 | #endif | ||
| 2139 | } | ||
| 2140 | |||
| 2141 | static void | ||
| 2142 | image_set_size (struct image *img, double tm[3][3]) | ||
| 2143 | { | ||
| 2144 | #ifdef HAVE_NATIVE_TRANSFORMS | ||
| 2145 | # ifdef HAVE_IMAGEMAGICK | ||
| 2146 | /* ImageMagick images are already the correct size. */ | ||
| 2147 | if (EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick)) | ||
| 2148 | return; | ||
| 2149 | # endif | ||
| 2150 | |||
| 2151 | # ifdef HAVE_XRENDER | ||
| 2152 | if (!img->picture) | ||
| 2153 | return; | ||
| 2154 | # endif | ||
| 2155 | |||
| 2156 | int width, height; | ||
| 2157 | |||
| 2158 | compute_image_size (img->width, img->height, img->spec, &width, &height); | ||
| 2159 | |||
| 2160 | # if defined (HAVE_NS) || defined (HAVE_XRENDER) | ||
| 2161 | double rm[3][3], tmp[3][3]; | ||
| 2162 | double xscale, yscale; | ||
| 2163 | |||
| 2164 | xscale = img->width / (double) width; | ||
| 2165 | yscale = img->height / (double) height; | ||
| 2166 | |||
| 2167 | INIT_MATRIX (rm); | ||
| 2168 | rm[0][0] = xscale; | ||
| 2169 | rm[1][1] = yscale; | ||
| 2170 | |||
| 2171 | MULT_MATRICES (tm, rm, tmp); | ||
| 2172 | COPY_MATRIX (tmp, tm); | ||
| 2173 | |||
| 2174 | img->width = width; | ||
| 2175 | img->height = height; | ||
| 1985 | # endif | 2176 | # endif |
| 2177 | |||
| 1986 | # ifdef HAVE_NTGUI | 2178 | # ifdef HAVE_NTGUI |
| 1987 | /* Under HAVE_NTGUI, we will scale the image on the fly, when we | 2179 | /* Under HAVE_NTGUI, we will scale the image on the fly, when we |
| 1988 | draw it. See w32term.c:x_draw_image_foreground. */ | 2180 | draw it. See w32term.c:x_draw_image_foreground. */ |
| @@ -1992,6 +2184,36 @@ image_set_image_size (struct frame *f, struct image *img) | |||
| 1992 | #endif | 2184 | #endif |
| 1993 | } | 2185 | } |
| 1994 | 2186 | ||
| 2187 | static void | ||
| 2188 | image_set_transform (struct frame *f, struct image *img, double matrix[3][3]) | ||
| 2189 | { | ||
| 2190 | /* TODO: Add MS Windows support. */ | ||
| 2191 | #ifdef HAVE_NATIVE_TRANSFORMS | ||
| 2192 | # if defined (HAVE_NS) | ||
| 2193 | /* Under NS the transform is applied to the drawing surface at | ||
| 2194 | drawing time, so store it for later. */ | ||
| 2195 | ns_image_set_transform (img->pixmap, matrix); | ||
| 2196 | # elif defined (HAVE_XRENDER) | ||
| 2197 | if (img->picture) | ||
| 2198 | { | ||
| 2199 | XTransform tmat | ||
| 2200 | = {{{XDoubleToFixed (matrix[0][0]), | ||
| 2201 | XDoubleToFixed (matrix[1][0]), | ||
| 2202 | XDoubleToFixed (matrix[2][0])}, | ||
| 2203 | {XDoubleToFixed (matrix[0][1]), | ||
| 2204 | XDoubleToFixed (matrix[1][1]), | ||
| 2205 | XDoubleToFixed (matrix[2][1])}, | ||
| 2206 | {XDoubleToFixed (matrix[0][2]), | ||
| 2207 | XDoubleToFixed (matrix[1][2]), | ||
| 2208 | XDoubleToFixed (matrix[2][2])}}}; | ||
| 2209 | |||
| 2210 | XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest, | ||
| 2211 | 0, 0); | ||
| 2212 | XRenderSetPictureTransform (FRAME_X_DISPLAY (f), img->picture, &tmat); | ||
| 2213 | } | ||
| 2214 | # endif | ||
| 2215 | #endif | ||
| 2216 | } | ||
| 1995 | 2217 | ||
| 1996 | /* Return the id of image with Lisp specification SPEC on frame F. | 2218 | /* Return the id of image with Lisp specification SPEC on frame F. |
| 1997 | SPEC must be a valid Lisp image specification (see valid_image_p). */ | 2219 | SPEC must be a valid Lisp image specification (see valid_image_p). */ |
| @@ -2047,7 +2269,16 @@ lookup_image (struct frame *f, Lisp_Object spec) | |||
| 2047 | `:background COLOR'. */ | 2269 | `:background COLOR'. */ |
| 2048 | Lisp_Object ascent, margin, relief, bg; | 2270 | Lisp_Object ascent, margin, relief, bg; |
| 2049 | int relief_bound; | 2271 | int relief_bound; |
| 2050 | image_set_image_size (f, img); | 2272 | |
| 2273 | #ifdef HAVE_NATIVE_TRANSFORMS | ||
| 2274 | double transform_matrix[3][3]; | ||
| 2275 | |||
| 2276 | INIT_MATRIX (transform_matrix); | ||
| 2277 | image_set_size (img, transform_matrix); | ||
| 2278 | image_set_crop (img, transform_matrix); | ||
| 2279 | image_set_rotation (img, transform_matrix); | ||
| 2280 | image_set_transform (f, img, transform_matrix); | ||
| 2281 | #endif | ||
| 2051 | 2282 | ||
| 2052 | ascent = image_spec_value (spec, QCascent, NULL); | 2283 | ascent = image_spec_value (spec, QCascent, NULL); |
| 2053 | if (FIXNUMP (ascent)) | 2284 | if (FIXNUMP (ascent)) |
| @@ -9673,9 +9904,9 @@ DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, | |||
| 9673 | Initialization | 9904 | Initialization |
| 9674 | ***********************************************************************/ | 9905 | ***********************************************************************/ |
| 9675 | 9906 | ||
| 9676 | DEFUN ("image-scaling-p", Fimage_scaling_p, Simage_scaling_p, 0, 1, 0, | 9907 | DEFUN ("image-transforms-p", Fimage_transforms_p, Simage_transforms_p, 0, 1, 0, |
| 9677 | doc: /* Test whether FRAME supports resizing images. | 9908 | doc: /* Test whether FRAME supports image transformation. |
| 9678 | Return t if FRAME supports native scaling, nil otherwise. */) | 9909 | Return t if FRAME supports native transforms, nil otherwise. */) |
| 9679 | (Lisp_Object frame) | 9910 | (Lisp_Object frame) |
| 9680 | { | 9911 | { |
| 9681 | #if defined (USE_CAIRO) || defined (HAVE_NS) || defined (HAVE_NTGUI) | 9912 | #if defined (USE_CAIRO) || defined (HAVE_NS) || defined (HAVE_NTGUI) |
| @@ -9935,7 +10166,7 @@ non-numeric, there is no explicit limit on the size of images. */); | |||
| 9935 | defsubr (&Slookup_image); | 10166 | defsubr (&Slookup_image); |
| 9936 | #endif | 10167 | #endif |
| 9937 | 10168 | ||
| 9938 | defsubr (&Simage_scaling_p); | 10169 | defsubr (&Simage_transforms_p); |
| 9939 | 10170 | ||
| 9940 | DEFVAR_BOOL ("cross-disabled-images", cross_disabled_images, | 10171 | DEFVAR_BOOL ("cross-disabled-images", cross_disabled_images, |
| 9941 | doc: /* Non-nil means always draw a cross over disabled images. | 10172 | doc: /* Non-nil means always draw a cross over disabled images. |
diff --git a/src/nsimage.m b/src/nsimage.m index 0249d22acae..7268e662638 100644 --- a/src/nsimage.m +++ b/src/nsimage.m | |||
| @@ -76,9 +76,8 @@ ns_load_image (struct frame *f, struct image *img, | |||
| 76 | { | 76 | { |
| 77 | EmacsImage *eImg = nil; | 77 | EmacsImage *eImg = nil; |
| 78 | NSSize size; | 78 | NSSize size; |
| 79 | Lisp_Object lisp_index, lisp_rotation; | 79 | Lisp_Object lisp_index; |
| 80 | unsigned int index; | 80 | unsigned int index; |
| 81 | double rotation; | ||
| 82 | 81 | ||
| 83 | NSTRACE ("ns_load_image"); | 82 | NSTRACE ("ns_load_image"); |
| 84 | 83 | ||
| @@ -87,9 +86,6 @@ ns_load_image (struct frame *f, struct image *img, | |||
| 87 | lisp_index = Fplist_get (XCDR (img->spec), QCindex); | 86 | lisp_index = Fplist_get (XCDR (img->spec), QCindex); |
| 88 | index = FIXNUMP (lisp_index) ? XFIXNAT (lisp_index) : 0; | 87 | index = FIXNUMP (lisp_index) ? XFIXNAT (lisp_index) : 0; |
| 89 | 88 | ||
| 90 | lisp_rotation = Fplist_get (XCDR (img->spec), QCrotation); | ||
| 91 | rotation = NUMBERP (lisp_rotation) ? XFLOATINT (lisp_rotation) : 0; | ||
| 92 | |||
| 93 | if (STRINGP (spec_file)) | 89 | if (STRINGP (spec_file)) |
| 94 | { | 90 | { |
| 95 | eImg = [EmacsImage allocInitFromFile: spec_file]; | 91 | eImg = [EmacsImage allocInitFromFile: spec_file]; |
| @@ -119,13 +115,6 @@ ns_load_image (struct frame *f, struct image *img, | |||
| 119 | 115 | ||
| 120 | img->lisp_data = [eImg getMetadata]; | 116 | img->lisp_data = [eImg getMetadata]; |
| 121 | 117 | ||
| 122 | if (rotation != 0) | ||
| 123 | { | ||
| 124 | EmacsImage *temp = [eImg rotate:rotation]; | ||
| 125 | [eImg release]; | ||
| 126 | eImg = temp; | ||
| 127 | } | ||
| 128 | |||
| 129 | size = [eImg size]; | 118 | size = [eImg size]; |
| 130 | img->width = size.width; | 119 | img->width = size.width; |
| 131 | img->height = size.height; | 120 | img->height = size.height; |
| @@ -155,6 +144,12 @@ ns_image_set_size (void *img, int width, int height) | |||
| 155 | [(EmacsImage *)img setSize:NSMakeSize (width, height)]; | 144 | [(EmacsImage *)img setSize:NSMakeSize (width, height)]; |
| 156 | } | 145 | } |
| 157 | 146 | ||
| 147 | void | ||
| 148 | ns_image_set_transform (void *img, double m[3][3]) | ||
| 149 | { | ||
| 150 | [(EmacsImage *)img setTransform:m]; | ||
| 151 | } | ||
| 152 | |||
| 158 | unsigned long | 153 | unsigned long |
| 159 | ns_get_pixel (void *img, int x, int y) | 154 | ns_get_pixel (void *img, int x, int y) |
| 160 | { | 155 | { |
| @@ -225,6 +220,7 @@ ns_set_alpha (void *img, int x, int y, unsigned char a) | |||
| 225 | { | 220 | { |
| 226 | [stippleMask release]; | 221 | [stippleMask release]; |
| 227 | [bmRep release]; | 222 | [bmRep release]; |
| 223 | [transform release]; | ||
| 228 | [super dealloc]; | 224 | [super dealloc]; |
| 229 | } | 225 | } |
| 230 | 226 | ||
| @@ -528,42 +524,16 @@ ns_set_alpha (void *img, int x, int y, unsigned char a) | |||
| 528 | return YES; | 524 | return YES; |
| 529 | } | 525 | } |
| 530 | 526 | ||
| 531 | - (instancetype)rotate: (double)rotation | 527 | - (void)setTransform: (double[3][3]) m |
| 532 | { | 528 | { |
| 533 | EmacsImage *new_image; | 529 | transform = [[NSAffineTransform transform] retain]; |
| 534 | NSPoint new_origin; | 530 | NSAffineTransformStruct tm |
| 535 | NSSize new_size, size = [self size]; | 531 | = { m[0][0], m[0][1], m[1][0], m[1][1], m[2][0], m[2][1]}; |
| 536 | NSRect rect = { NSZeroPoint, [self size] }; | 532 | [transform setTransformStruct:tm]; |
| 537 | 533 | ||
| 538 | /* Create a bezier path of the outline of the image and do the | 534 | /* Because the transform is applied to the drawing surface, and not |
| 539 | * rotation on it. */ | 535 | the image itself, we need to invert it. */ |
| 540 | NSBezierPath *bounds_path = [NSBezierPath bezierPathWithRect:rect]; | 536 | [transform invert]; |
| 541 | NSAffineTransform *transform = [NSAffineTransform transform]; | ||
| 542 | [transform rotateByDegrees: rotation * -1]; | ||
| 543 | [bounds_path transformUsingAffineTransform:transform]; | ||
| 544 | |||
| 545 | /* Now we can find out how large the rotated image needs to be. */ | ||
| 546 | new_size = [bounds_path bounds].size; | ||
| 547 | new_image = [[EmacsImage alloc] initWithSize:new_size]; | ||
| 548 | |||
| 549 | new_origin = NSMakePoint((new_size.width - size.width)/2, | ||
| 550 | (new_size.height - size.height)/2); | ||
| 551 | |||
| 552 | [new_image lockFocus]; | ||
| 553 | |||
| 554 | /* Create the final transform. */ | ||
| 555 | transform = [NSAffineTransform transform]; | ||
| 556 | [transform translateXBy:new_size.width/2 yBy:new_size.height/2]; | ||
| 557 | [transform rotateByDegrees: rotation * -1]; | ||
| 558 | [transform translateXBy:-new_size.width/2 yBy:-new_size.height/2]; | ||
| 559 | |||
| 560 | [transform concat]; | ||
| 561 | [self drawAtPoint:new_origin fromRect:NSZeroRect | ||
| 562 | operation:NSCompositingOperationCopy fraction:1]; | ||
| 563 | |||
| 564 | [new_image unlockFocus]; | ||
| 565 | |||
| 566 | return new_image; | ||
| 567 | } | 537 | } |
| 568 | 538 | ||
| 569 | @end | 539 | @end |
diff --git a/src/nsterm.h b/src/nsterm.h index 1e56276ca3c..567f462ec69 100644 --- a/src/nsterm.h +++ b/src/nsterm.h | |||
| @@ -632,6 +632,8 @@ typedef id instancetype; | |||
| 632 | unsigned char *pixmapData[5]; /* shortcut to access pixel data */ | 632 | unsigned char *pixmapData[5]; /* shortcut to access pixel data */ |
| 633 | NSColor *stippleMask; | 633 | NSColor *stippleMask; |
| 634 | unsigned long xbm_fg; | 634 | unsigned long xbm_fg; |
| 635 | @public | ||
| 636 | NSAffineTransform *transform; | ||
| 635 | } | 637 | } |
| 636 | + (instancetype)allocInitFromFile: (Lisp_Object)file; | 638 | + (instancetype)allocInitFromFile: (Lisp_Object)file; |
| 637 | - (void)dealloc; | 639 | - (void)dealloc; |
| @@ -648,7 +650,7 @@ typedef id instancetype; | |||
| 648 | - (NSColor *)stippleMask; | 650 | - (NSColor *)stippleMask; |
| 649 | - (Lisp_Object)getMetadata; | 651 | - (Lisp_Object)getMetadata; |
| 650 | - (BOOL)setFrame: (unsigned int) index; | 652 | - (BOOL)setFrame: (unsigned int) index; |
| 651 | - (instancetype)rotate: (double)rotation; | 653 | - (void)setTransform: (double[3][3]) m; |
| 652 | @end | 654 | @end |
| 653 | 655 | ||
| 654 | 656 | ||
| @@ -1201,6 +1203,7 @@ extern bool ns_load_image (struct frame *f, struct image *img, | |||
| 1201 | extern int ns_image_width (void *img); | 1203 | extern int ns_image_width (void *img); |
| 1202 | extern int ns_image_height (void *img); | 1204 | extern int ns_image_height (void *img); |
| 1203 | extern void ns_image_set_size (void *img, int width, int height); | 1205 | extern void ns_image_set_size (void *img, int width, int height); |
| 1206 | extern void ns_image_set_transform (void *img, double m[3][3]); | ||
| 1204 | extern unsigned long ns_get_pixel (void *img, int x, int y); | 1207 | extern unsigned long ns_get_pixel (void *img, int x, int y); |
| 1205 | extern void ns_put_pixel (void *img, int x, int y, unsigned long argb); | 1208 | extern void ns_put_pixel (void *img, int x, int y, unsigned long argb); |
| 1206 | extern void ns_set_alpha (void *img, int x, int y, unsigned char a); | 1209 | 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 0cae5e9d448..f12e98ebfde 100644 --- a/src/nsterm.m +++ b/src/nsterm.m | |||
| @@ -3813,21 +3813,34 @@ ns_dumpglyphs_image (struct glyph_string *s, NSRect r) | |||
| 3813 | /* Draw the image... do we need to draw placeholder if img == nil? */ | 3813 | /* Draw the image... do we need to draw placeholder if img == nil? */ |
| 3814 | if (img != nil) | 3814 | if (img != nil) |
| 3815 | { | 3815 | { |
| 3816 | #ifdef NS_IMPL_COCOA | 3816 | /* The idea here is that the clipped area is set in the normal |
| 3817 | view coordinate system, then we transform the coordinate | ||
| 3818 | system so that when we draw the image it is rotated, resized | ||
| 3819 | or whatever as required. This is kind of backwards, but | ||
| 3820 | there's no way to apply the transform to the image without | ||
| 3821 | creating a whole new bitmap. */ | ||
| 3817 | NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height); | 3822 | NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height); |
| 3818 | NSRect ir = NSMakeRect (s->slice.x, | 3823 | NSRect ir = NSMakeRect (0, 0, [img size].width, [img size].height); |
| 3819 | s->img->height - s->slice.y - s->slice.height, | 3824 | |
| 3820 | s->slice.width, s->slice.height); | 3825 | NSAffineTransform *setOrigin = [NSAffineTransform transform]; |
| 3821 | [img drawInRect: dr | 3826 | |
| 3822 | fromRect: ir | 3827 | [[NSGraphicsContext currentContext] saveGraphicsState]; |
| 3823 | operation: NSCompositingOperationSourceOver | 3828 | |
| 3824 | fraction: 1.0 | 3829 | /* Because of the transforms it's far too difficult to work out |
| 3825 | respectFlipped: YES | 3830 | what portion of the original, untransformed, image will be |
| 3826 | hints: nil]; | 3831 | drawn, so the clipping area will ensure we draw only the |
| 3827 | #else | 3832 | correct bit. */ |
| 3828 | [img compositeToPoint: NSMakePoint (x, y + s->slice.height) | 3833 | NSRectClip (dr); |
| 3829 | operation: NSCompositingOperationSourceOver]; | 3834 | |
| 3830 | #endif | 3835 | [setOrigin translateXBy:x - s->slice.x yBy:y - s->slice.y]; |
| 3836 | [setOrigin concat]; | ||
| 3837 | [img->transform concat]; | ||
| 3838 | |||
| 3839 | [img drawInRect:ir fromRect:ir | ||
| 3840 | operation:NSCompositingOperationSourceOver | ||
| 3841 | fraction:1.0 respectFlipped:YES hints:nil]; | ||
| 3842 | |||
| 3843 | [[NSGraphicsContext currentContext] restoreGraphicsState]; | ||
| 3831 | } | 3844 | } |
| 3832 | 3845 | ||
| 3833 | if (s->hl == DRAW_CURSOR) | 3846 | if (s->hl == DRAW_CURSOR) |
diff --git a/src/xterm.c b/src/xterm.c index ccc84dcc716..c064647da0c 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -2883,10 +2883,7 @@ x_composite_image (struct glyph_string *s, Pixmap dest, | |||
| 2883 | destination = XRenderCreatePicture (display, dest, | 2883 | destination = XRenderCreatePicture (display, dest, |
| 2884 | default_format, 0, &attr); | 2884 | default_format, 0, &attr); |
| 2885 | 2885 | ||
| 2886 | /* FIXME: It may make sense to use PictOpSrc instead of | 2886 | XRenderComposite (display, PictOpSrc, |
| 2887 | PictOpOver, as I don't know if we care about alpha values too | ||
| 2888 | much here. */ | ||
| 2889 | XRenderComposite (display, PictOpOver, | ||
| 2890 | s->img->picture, s->img->mask_picture, destination, | 2887 | s->img->picture, s->img->mask_picture, destination, |
| 2891 | srcX, srcY, | 2888 | srcX, srcY, |
| 2892 | srcX, srcY, | 2889 | srcX, srcY, |