aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlan Third2019-06-16 20:46:31 +0100
committerAlan Third2019-06-16 20:46:42 +0100
commitbeb572a7ddc07760e077867e286790ddae30a12d (patch)
tree9595b80194dcc0a8ea3bf9c999b8dbe6cca82ba9 /src
parentcf3081d208814ea02fce33aac645abfc24f880a6 (diff)
downloademacs-beb572a7ddc07760e077867e286790ddae30a12d.tar.gz
emacs-beb572a7ddc07760e077867e286790ddae30a12d.zip
Revert "Simplify image transforms"
This reverts commit cf3081d208814ea02fce33aac645abfc24f880a6. ; Pushed in error.
Diffstat (limited to 'src')
-rw-r--r--src/image.c310
1 files changed, 212 insertions, 98 deletions
diff --git a/src/image.c b/src/image.c
index 8b571dd72d6..a3747cfa6b7 100644
--- a/src/image.c
+++ b/src/image.c
@@ -1967,7 +1967,8 @@ compute_image_size (size_t width, size_t height,
1967} 1967}
1968#endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_TRANSFORMS */ 1968#endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_TRANSFORMS */
1969 1969
1970/* image_set_transform uses affine transformation matrices to perform 1970/* image_set_rotation, image_set_crop, image_set_size and
1971 image_set_transform use affine transformation matrices to perform
1971 various transforms on the image. The matrix is a 2D array of 1972 various transforms on the image. The matrix is a 2D array of
1972 doubles. It is laid out like this: 1973 doubles. It is laid out like this:
1973 1974
@@ -2038,6 +2039,10 @@ compute_image_size (size_t width, size_t height,
2038 finally move the origin back to the top left of the image, which 2039 finally move the origin back to the top left of the image, which
2039 may now be a different corner. 2040 may now be a different corner.
2040 2041
2042 Cropping is easier as we just move the origin to the top left of
2043 where we want to crop and set the width and height accordingly.
2044 The matrices don’t know anything about width and height.
2045
2041 It's possible to pre-calculate the matrix multiplications and just 2046 It's possible to pre-calculate the matrix multiplications and just
2042 generate one transform matrix that will do everything we need in a 2047 generate one transform matrix that will do everything we need in a
2043 single step, but the maths for each element is much more complex 2048 single step, but the maths for each element is much more complex
@@ -2065,7 +2070,7 @@ matrix3x3_mult (matrix3x3 a, matrix3x3 b, matrix3x3 result)
2065} 2070}
2066 2071
2067static void 2072static void
2068image_set_transform (struct frame *f, struct image *img) 2073image_set_rotation (struct image *img, matrix3x3 tm)
2069{ 2074{
2070#ifdef HAVE_NATIVE_TRANSFORMS 2075#ifdef HAVE_NATIVE_TRANSFORMS
2071# ifdef HAVE_IMAGEMAGICK 2076# ifdef HAVE_IMAGEMAGICK
@@ -2079,112 +2084,217 @@ image_set_transform (struct frame *f, struct image *img)
2079 return; 2084 return;
2080# endif 2085# endif
2081 2086
2082 /* This is the transformation matrix we will use through all the 2087 int rotation, cos_r, sin_r, width, height;
2083 calculations. */
2084 matrix3x3 tm = { [0][0] = 1, [1][1] = 1, [2][2] = 1 };
2085 2088
2086 /* Calculate image rotation. */
2087 Lisp_Object value = image_spec_value (img->spec, QCrotation, NULL); 2089 Lisp_Object value = image_spec_value (img->spec, QCrotation, NULL);
2088 if (NUMBERP (value)) 2090 if (! NUMBERP (value))
2091 return;
2092
2093 Lisp_Object reduced_angle = Fmod (value, make_fixnum (360));
2094 if (! FLOATP (reduced_angle))
2095 rotation = XFIXNUM (reduced_angle);
2096 else
2089 { 2097 {
2090 int rotation, cos_r, sin_r, width, height; 2098 rotation = XFLOAT_DATA (reduced_angle);
2099 if (rotation != XFLOAT_DATA (reduced_angle))
2100 goto not_a_multiple_of_90;
2101 }
2091 2102
2092 Lisp_Object reduced_angle = Fmod (value, make_fixnum (360)); 2103 if (rotation == 0)
2093 if (! FLOATP (reduced_angle)) 2104 return;
2094 rotation = XFIXNUM (reduced_angle);
2095 else
2096 {
2097 rotation = XFLOAT_DATA (reduced_angle);
2098 if (rotation != XFLOAT_DATA (reduced_angle))
2099 goto not_a_multiple_of_90;
2100 }
2101 2105
2102 if (rotation != 0) 2106 if (rotation == 90)
2103 { 2107 {
2104 if (rotation == 90) 2108 width = img->height;
2105 { 2109 height = img->width;
2106 width = img->height;
2107 height = img->width;
2108 2110
2109 cos_r = 0; 2111 cos_r = 0;
2110 sin_r = 1; 2112 sin_r = 1;
2111 } 2113 }
2112 else if (rotation == 180) 2114 else if (rotation == 180)
2113 { 2115 {
2114 width = img->width; 2116 width = img->width;
2115 height = img->height; 2117 height = img->height;
2116 2118
2117 cos_r = -1; 2119 cos_r = -1;
2118 sin_r = 0; 2120 sin_r = 0;
2119 } 2121 }
2120 else if (rotation == 270) 2122 else if (rotation == 270)
2121 { 2123 {
2122 width = img->height; 2124 width = img->height;
2123 height = img->width; 2125 height = img->width;
2124 2126
2125 cos_r = 0; 2127 cos_r = 0;
2126 sin_r = -1; 2128 sin_r = -1;
2127 } 2129 }
2128 else 2130 else
2129 { 2131 {
2130 not_a_multiple_of_90: 2132 not_a_multiple_of_90:
2131 image_error ("Native image rotation supports " 2133 image_error ("Native image rotation supports "
2132 "only multiples of 90 degrees"); 2134 "only multiples of 90 degrees");
2133 return; 2135 return;
2134 } 2136 }
2135 2137
2136 /* Translate so (0, 0) is in the center of the image. */ 2138 /* Translate so (0, 0) is in the center of the image. */
2137 matrix3x3 t 2139 matrix3x3 t
2138 = { [0][0] = 1, [2][0] = img->width >> 1, 2140 = { [0][0] = 1,
2139 [1][1] = 1, [2][1] = img->height >> 1, 2141 [1][1] = 1,
2140 [2][2] = 1 }; 2142 [2][0] = img->width >> 1, [2][1] = img->height >> 1, [2][2] = 1 };
2141 matrix3x3 tmp; 2143 matrix3x3 tmp;
2142 matrix3x3_mult (t, tm, tmp); 2144 matrix3x3_mult (t, tm, tmp);
2143 2145
2144 /* Rotate. */ 2146 /* Rotate. */
2145 matrix3x3 rot = { [0][0] = cos_r, [1][0] = sin_r, 2147 matrix3x3 rot = { [0][0] = cos_r, [0][1] = -sin_r,
2146 [0][1] = -sin_r, [1][1] = cos_r, 2148 [1][0] = sin_r, [1][1] = cos_r,
2147 [2][2] = 1 }; 2149 [2][2] = 1 };
2148 matrix3x3 tmp2; 2150 matrix3x3 tmp2;
2149 matrix3x3_mult (rot, tmp, tmp2); 2151 matrix3x3_mult (rot, tmp, tmp2);
2150 2152
2151 /* Translate back. */ 2153 /* Translate back. */
2152 t[2][0] = - (width >> 1); 2154 t[2][0] = - (width >> 1);
2153 t[2][1] = - (height >> 1); 2155 t[2][1] = - (height >> 1);
2154 matrix3x3_mult (t, tmp2, tm); 2156 matrix3x3_mult (t, tmp2, tm);
2155 2157
2156 img->width = width; 2158 img->width = width;
2157 img->height = height; 2159 img->height = height;
2158 } 2160#endif
2161}
2162
2163static void
2164image_set_crop (struct image *img, matrix3x3 tm)
2165{
2166#ifdef HAVE_NATIVE_TRANSFORMS
2167# ifdef HAVE_IMAGEMAGICK
2168 /* ImageMagick images are already cropped. */
2169 if (EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick))
2170 return;
2171# endif
2172
2173# if !defined USE_CAIRO && defined HAVE_XRENDER
2174 if (!img->picture)
2175 return;
2176# endif
2177
2178 Lisp_Object crop = image_spec_value (img->spec, QCcrop, NULL);
2179
2180 if (!CONSP (crop))
2181 return;
2182
2183 Lisp_Object w = XCAR (crop), h = Qnil, x = Qnil, y = Qnil;
2184 crop = XCDR (crop);
2185 if (CONSP (crop))
2186 {
2187 h = XCAR (crop);
2188 crop = XCDR (crop);
2189 if (CONSP (crop))
2190 {
2191 x = XCAR (crop);
2192 crop = XCDR (crop);
2193 if (CONSP (crop))
2194 y = XCAR (crop);
2195 }
2159 } 2196 }
2160 2197
2161 /* Calculate final image size. */ 2198 int width = img->width;
2162 { 2199 if (FIXNATP (w) && XFIXNAT (w) < img->width)
2163 int width, height; 2200 width = XFIXNAT (w);
2201 int left;
2202 if (TYPE_RANGED_FIXNUMP (int, x))
2203 {
2204 left = XFIXNUM (x);
2205 if (left < 0)
2206 left = img->width - width + left;
2207 }
2208 else
2209 left = (img->width - width) >> 1;
2164 2210
2165 compute_image_size (img->width, img->height, img->spec, &width, &height); 2211 int height = img->height;
2212 if (FIXNATP (h) && XFIXNAT (h) < img->height)
2213 height = XFIXNAT (h);
2214 int top;
2215 if (TYPE_RANGED_FIXNUMP (int, y))
2216 {
2217 top = XFIXNUM (y);
2218 if (top < 0)
2219 top = img->height - height + top;
2220 }
2221 else
2222 top = (img->height - height) >> 1;
2166 2223
2167 if (img->width != width || img->height != height) 2224 /* Negative values operate from the right and bottom of the image
2168 { 2225 instead of the left and top. */
2169 double xscale = img->width / (double) width; 2226 if (left < 0)
2170 double yscale = img->height / (double) height; 2227 {
2228 width = img->width + left;
2229 left = 0;
2230 }
2171 2231
2172 matrix3x3 tmp, rm = { [0][0] = xscale, [1][1] = yscale, [2][2] = 1 }; 2232 if (width + left > img->width)
2173 matrix3x3_mult (rm, tm, tmp); 2233 width = img->width - left;
2174 matrix3x3_copy (tmp, tm);
2175 2234
2176 img->width = width; 2235 if (top < 0)
2177 img->height = height; 2236 {
2178 } 2237 height = img->height + top;
2179 } 2238 top = 0;
2239 }
2240
2241 if (height + top > img->height)
2242 height = img->height - top;
2243
2244 matrix3x3 tmp, m = { [0][0] = 1,
2245 [1][1] = 1,
2246 [2][0] = left, [2][1] = top, [2][2] = 1 };
2247 matrix3x3_mult (m, tm, tmp);
2248 matrix3x3_copy (tmp, tm);
2249
2250 img->width = width;
2251 img->height = height;
2252#endif
2253}
2180 2254
2255static void
2256image_set_size (struct image *img, matrix3x3 tm)
2257{
2258#ifdef HAVE_NATIVE_TRANSFORMS
2259# ifdef HAVE_IMAGEMAGICK
2260 /* ImageMagick images are already the correct size. */
2261 if (EQ (image_spec_value (img->spec, QCtype, NULL), Qimagemagick))
2262 return;
2263# endif
2264
2265# if !defined USE_CAIRO && defined HAVE_XRENDER
2266 if (!img->picture)
2267 return;
2268# endif
2269
2270 int width, height;
2271
2272 compute_image_size (img->width, img->height, img->spec, &width, &height);
2273
2274 double xscale = img->width / (double) width;
2275 double yscale = img->height / (double) height;
2276
2277 matrix3x3 tmp, rm = { [0][0] = xscale, [1][1] = yscale, [2][2] = 1 };
2278 matrix3x3_mult (rm, tm, tmp);
2279 matrix3x3_copy (tmp, tm);
2280
2281 img->width = width;
2282 img->height = height;
2283#endif
2284}
2285
2286static void
2287image_set_transform (struct frame *f, struct image *img, matrix3x3 matrix)
2288{
2289 /* TODO: Add MS Windows support. */
2290#ifdef HAVE_NATIVE_TRANSFORMS
2181# if defined (HAVE_NS) 2291# if defined (HAVE_NS)
2182 /* Under NS the transform is applied to the drawing surface at 2292 /* Under NS the transform is applied to the drawing surface at
2183 drawing time, so store it for later. */ 2293 drawing time, so store it for later. */
2184 ns_image_set_transform (img->pixmap, tm); 2294 ns_image_set_transform (img->pixmap, matrix);
2185# elif defined USE_CAIRO 2295# elif defined USE_CAIRO
2186 cairo_matrix_t cr_matrix = {tm[0][0], tm[0][1], tm[1][0], 2296 cairo_matrix_t cr_matrix = {matrix[0][0], matrix[0][1], matrix[1][0],
2187 tm[1][1], tm[2][0], tm[2][1]}; 2297 matrix[1][1], matrix[2][0], matrix[2][1]};
2188 cairo_pattern_t *pattern = cairo_pattern_create_rgb (0, 0, 0); 2298 cairo_pattern_t *pattern = cairo_pattern_create_rgb (0, 0, 0);
2189 cairo_pattern_set_matrix (pattern, &cr_matrix); 2299 cairo_pattern_set_matrix (pattern, &cr_matrix);
2190 /* Dummy solid color pattern just to record pattern matrix. */ 2300 /* Dummy solid color pattern just to record pattern matrix. */
@@ -2193,15 +2303,15 @@ image_set_transform (struct frame *f, struct image *img)
2193 if (img->picture) 2303 if (img->picture)
2194 { 2304 {
2195 XTransform tmat 2305 XTransform tmat
2196 = {{{XDoubleToFixed (tm[0][0]), 2306 = {{{XDoubleToFixed (matrix[0][0]),
2197 XDoubleToFixed (tm[1][0]), 2307 XDoubleToFixed (matrix[1][0]),
2198 XDoubleToFixed (tm[2][0])}, 2308 XDoubleToFixed (matrix[2][0])},
2199 {XDoubleToFixed (tm[0][1]), 2309 {XDoubleToFixed (matrix[0][1]),
2200 XDoubleToFixed (tm[1][1]), 2310 XDoubleToFixed (matrix[1][1]),
2201 XDoubleToFixed (tm[2][1])}, 2311 XDoubleToFixed (matrix[2][1])},
2202 {XDoubleToFixed (tm[0][2]), 2312 {XDoubleToFixed (matrix[0][2]),
2203 XDoubleToFixed (tm[1][2]), 2313 XDoubleToFixed (matrix[1][2]),
2204 XDoubleToFixed (tm[2][2])}}}; 2314 XDoubleToFixed (matrix[2][2])}}};
2205 2315
2206 XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest, 2316 XRenderSetPictureFilter (FRAME_X_DISPLAY (f), img->picture, FilterBest,
2207 0, 0); 2317 0, 0);
@@ -2267,7 +2377,11 @@ lookup_image (struct frame *f, Lisp_Object spec)
2267 int relief_bound; 2377 int relief_bound;
2268 2378
2269#ifdef HAVE_NATIVE_TRANSFORMS 2379#ifdef HAVE_NATIVE_TRANSFORMS
2270 image_set_transform (f, img); 2380 matrix3x3 transform_matrix = { [0][0] = 1, [1][1] = 1, [2][2] = 1 };
2381 image_set_size (img, transform_matrix);
2382 image_set_crop (img, transform_matrix);
2383 image_set_rotation (img, transform_matrix);
2384 image_set_transform (f, img, transform_matrix);
2271#endif 2385#endif
2272 2386
2273 ascent = image_spec_value (spec, QCascent, NULL); 2387 ascent = image_spec_value (spec, QCascent, NULL);