aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlan Third2019-06-05 21:51:33 +0100
committerAlan Third2019-06-05 22:28:46 +0100
commit610fb73ab6d7a22b722f523d6ebc4aa8fa1db7c9 (patch)
tree8a3ee992ccc310071ac5a97ced8907652974c88e /src
parent9201cf62ce9f17793bb6103050c9ba27eb942e57 (diff)
downloademacs-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.h22
-rw-r--r--src/image.c283
-rw-r--r--src/nsimage.m64
-rw-r--r--src/nsterm.h5
-rw-r--r--src/nsterm.m41
-rw-r--r--src/xterm.c5
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
1945static void 1945static void
1946image_set_image_size (struct frame *f, struct image *img) 1946image_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
2035static void
2036image_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
2141static void
2142image_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
2187static void
2188image_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
9676DEFUN ("image-scaling-p", Fimage_scaling_p, Simage_scaling_p, 0, 1, 0, 9907DEFUN ("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.
9678Return t if FRAME supports native scaling, nil otherwise. */) 9909Return 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
147void
148ns_image_set_transform (void *img, double m[3][3])
149{
150 [(EmacsImage *)img setTransform:m];
151}
152
158unsigned long 153unsigned long
159ns_get_pixel (void *img, int x, int y) 154ns_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,
1201extern int ns_image_width (void *img); 1203extern int ns_image_width (void *img);
1202extern int ns_image_height (void *img); 1204extern int ns_image_height (void *img);
1203extern void ns_image_set_size (void *img, int width, int height); 1205extern void ns_image_set_size (void *img, int width, int height);
1206extern void ns_image_set_transform (void *img, double m[3][3]);
1204extern unsigned long ns_get_pixel (void *img, int x, int y); 1207extern unsigned long ns_get_pixel (void *img, int x, int y);
1205extern void ns_put_pixel (void *img, int x, int y, unsigned long argb); 1208extern void ns_put_pixel (void *img, int x, int y, unsigned long argb);
1206extern void ns_set_alpha (void *img, int x, int y, unsigned char a); 1209extern 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,