aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2019-06-06 08:09:58 -0700
committerPaul Eggert2019-06-06 08:10:31 -0700
commit7c26e0b18d0cdf656778d6dd332972b538491d95 (patch)
tree48674c6c1658fb5e45d69ca99285480b8655fe82 /src
parente29fb7dfba96e63cb7ba2d2a68f91f8dec336100 (diff)
downloademacs-7c26e0b18d0cdf656778d6dd332972b538491d95.tar.gz
emacs-7c26e0b18d0cdf656778d6dd332972b538491d95.zip
Fix overflow issues in image rotation
Also, do some refactoring to simplify code. * src/dispextern.h (INIT_MATRIX, COPY_MATRIX, MULT_MATRICES): Remove. * src/image.c (matrix3x3): New type, replacing all uses of 3x3 double. (matrix3x3_copy, matrix3x3_mult): New functions, replacing COPY_MATRIX, MULT_MATRICES. Replace INIT_MATRIX by C initializers. (image_set_rotation): Use Fmod to avoid undefined behavior on double-to-int conversion and to reduce bignum rotations correctly. (image_set_crop): Finish up previous correction, by not re-setting width and height if compute_image_size has set them. Prefer shifting right by 1 to dividing by 2 if either will do.
Diffstat (limited to 'src')
-rw-r--r--src/dispextern.h21
-rw-r--r--src/image.c149
2 files changed, 77 insertions, 93 deletions
diff --git a/src/dispextern.h b/src/dispextern.h
index a21edd818f0..cc15950d5df 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -2988,26 +2988,9 @@ struct redisplay_interface
2988 2988
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 \
2992 || defined HAVE_NS || defined HAVE_NTGUI)
2992# define HAVE_NATIVE_TRANSFORMS 2993# 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;}
3011# endif 2994# endif
3012 2995
3013/* Structure describing an image. Specific image formats like XBM are 2996/* Structure describing an image. Specific image formats like XBM are
diff --git a/src/image.c b/src/image.c
index 29cb2fc10b9..2a980135a22 100644
--- a/src/image.c
+++ b/src/image.c
@@ -1942,8 +1942,29 @@ compute_image_size (size_t width, size_t height,
1942} 1942}
1943#endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_TRANSFORMS */ 1943#endif /* HAVE_IMAGEMAGICK || HAVE_NATIVE_TRANSFORMS */
1944 1944
1945typedef double matrix3x3[3][3];
1946
1947static void
1948matrix3x3_copy (matrix3x3 a, matrix3x3 b)
1949{
1950 memcpy (b, a, sizeof (matrix3x3));
1951}
1952
1945static void 1953static void
1946image_set_rotation (struct image *img, double tm[3][3]) 1954matrix3x3_mult (matrix3x3 a, matrix3x3 b, matrix3x3 result)
1955{
1956 for (int i = 0; i < 3; i++)
1957 for (int j = 0; j < 3; j++)
1958 {
1959 double sum = 0;
1960 for (int k = 0; k < 3; k++)
1961 sum += a[i][k] * b[k][j];
1962 result[i][j] = sum;
1963 }
1964}
1965
1966static void
1967image_set_rotation (struct image *img, matrix3x3 tm)
1947{ 1968{
1948#ifdef HAVE_NATIVE_TRANSFORMS 1969#ifdef HAVE_NATIVE_TRANSFORMS
1949# ifdef HAVE_IMAGEMAGICK 1970# ifdef HAVE_IMAGEMAGICK
@@ -1957,19 +1978,21 @@ image_set_rotation (struct image *img, double tm[3][3])
1957 return; 1978 return;
1958# endif 1979# endif
1959 1980
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; 1981 int rotation, cos_r, sin_r, width, height;
1963 1982
1964 value = image_spec_value (img->spec, QCrotation, NULL); 1983 Lisp_Object value = image_spec_value (img->spec, QCrotation, NULL);
1965 if (! NUMBERP (value)) 1984 if (! NUMBERP (value))
1966 return; 1985 return;
1967 1986
1968 rotation = XFLOATINT (value); 1987 Lisp_Object reduced_angle = Fmod (value, make_fixnum (360));
1969 rotation = rotation % 360; 1988 if (! FLOATP (reduced_angle))
1970 1989 rotation = XFIXNUM (reduced_angle);
1971 if (rotation < 0) 1990 else
1972 rotation += 360; 1991 {
1992 rotation = XFLOAT_DATA (reduced_angle);
1993 if (rotation != XFLOAT_DATA (reduced_angle))
1994 goto not_a_multiple_of_90;
1995 }
1973 1996
1974 if (rotation == 0) 1997 if (rotation == 0)
1975 return; 1998 return;
@@ -2000,32 +2023,31 @@ image_set_rotation (struct image *img, double tm[3][3])
2000 } 2023 }
2001 else 2024 else
2002 { 2025 {
2003 image_error ("Native image rotation only supports multiples of 90 degrees"); 2026 not_a_multiple_of_90:
2027 image_error ("Native image rotation supports "
2028 "only multiples of 90 degrees");
2004 return; 2029 return;
2005 } 2030 }
2006 2031
2007 /* Translate so (0, 0) is in the centre of the image. */ 2032 /* Translate so (0, 0) is in the center of the image. */
2008 INIT_MATRIX (t); 2033 matrix3x3 t
2009 t[2][0] = img->width/2; 2034 = { [0][0] = 1,
2010 t[2][1] = img->height/2; 2035 [1][1] = 1,
2011 2036 [2][0] = img->width >> 1, [2][1] = img->height >> 1, [2][2] = 1 };
2012 MULT_MATRICES (tm, t, tmp); 2037 matrix3x3 tmp;
2038 matrix3x3_mult (t, tm, tmp);
2013 2039
2014 /* Rotate. */ 2040 /* Rotate. */
2015 INIT_MATRIX (rot); 2041 matrix3x3 rot = { [0][0] = cos_r, [0][1] = -sin_r,
2016 rot[0][0] = cos_r; 2042 [1][0] = sin_r, [1][1] = cos_r,
2017 rot[1][0] = sin_r; 2043 [2][2] = 1 };
2018 rot[0][1] = - sin_r; 2044 matrix3x3 tmp2;
2019 rot[1][1] = cos_r; 2045 matrix3x3_mult (rot, tmp, tmp2);
2020
2021 MULT_MATRICES (tmp, rot, tmp2);
2022 2046
2023 /* Translate back. */ 2047 /* Translate back. */
2024 INIT_MATRIX (t); 2048 t[2][0] = - (width >> 1);
2025 t[2][0] = - width/2; 2049 t[2][1] = - (height >> 1);
2026 t[2][1] = - height/2; 2050 matrix3x3_mult (t, tmp2, tm);
2027
2028 MULT_MATRICES (tmp2, t, tm);
2029 2051
2030 img->width = width; 2052 img->width = width;
2031 img->height = height; 2053 img->height = height;
@@ -2033,7 +2055,7 @@ image_set_rotation (struct image *img, double tm[3][3])
2033} 2055}
2034 2056
2035static void 2057static void
2036image_set_crop (struct image *img, double tm[3][3]) 2058image_set_crop (struct image *img, matrix3x3 tm)
2037{ 2059{
2038 int width, height; 2060 int width, height;
2039 compute_image_size (img->width, img->height, img->spec, &width, &height); 2061 compute_image_size (img->width, img->height, img->spec, &width, &height);
@@ -2052,39 +2074,29 @@ image_set_crop (struct image *img, double tm[3][3])
2052 return; 2074 return;
2053# endif 2075# endif
2054 2076
2055 double m[3][3], tmp[3][3];
2056 int left, top;
2057 Lisp_Object x = Qnil;
2058 Lisp_Object y = Qnil;
2059 Lisp_Object w = Qnil;
2060 Lisp_Object h = Qnil;
2061 Lisp_Object crop = image_spec_value (img->spec, QCcrop, NULL); 2077 Lisp_Object crop = image_spec_value (img->spec, QCcrop, NULL);
2062 2078
2063 if (!CONSP (crop)) 2079 if (!CONSP (crop))
2064 return; 2080 return;
2065 else 2081
2082 Lisp_Object w = XCAR (crop), h = Qnil, x = Qnil, y = Qnil;
2083 crop = XCDR (crop);
2084 if (CONSP (crop))
2066 { 2085 {
2067 w = XCAR (crop); 2086 h = XCAR (crop);
2068 crop = XCDR (crop); 2087 crop = XCDR (crop);
2069 if (CONSP (crop)) 2088 if (CONSP (crop))
2070 { 2089 {
2071 h = XCAR (crop); 2090 x = XCAR (crop);
2072 crop = XCDR (crop); 2091 crop = XCDR (crop);
2073 if (CONSP (crop)) 2092 if (CONSP (crop))
2074 { 2093 y = XCAR (crop);
2075 x = XCAR (crop);
2076 crop = XCDR (crop);
2077 if (CONSP (crop))
2078 y = XCAR (crop);
2079 }
2080 } 2094 }
2081 } 2095 }
2082 2096
2083 if (FIXNATP (w) && XFIXNAT (w) < img->width) 2097 if (FIXNATP (w) && XFIXNAT (w) < img->width)
2084 width = XFIXNAT (w); 2098 width = XFIXNAT (w);
2085 else 2099 int left;
2086 width = img->width;
2087
2088 if (TYPE_RANGED_FIXNUMP (int, x)) 2100 if (TYPE_RANGED_FIXNUMP (int, x))
2089 { 2101 {
2090 left = XFIXNUM (x); 2102 left = XFIXNUM (x);
@@ -2092,13 +2104,11 @@ image_set_crop (struct image *img, double tm[3][3])
2092 left = img->width - width + left; 2104 left = img->width - width + left;
2093 } 2105 }
2094 else 2106 else
2095 left = (img->width - width)/2; 2107 left = (img->width - width) >> 1;
2096 2108
2097 if (FIXNATP (h) && XFIXNAT (h) < img->height) 2109 if (FIXNATP (h) && XFIXNAT (h) < img->height)
2098 height = XFIXNAT (h); 2110 height = XFIXNAT (h);
2099 else 2111 int top;
2100 height = img->height;
2101
2102 if (TYPE_RANGED_FIXNUMP (int, y)) 2112 if (TYPE_RANGED_FIXNUMP (int, y))
2103 { 2113 {
2104 top = XFIXNUM (y); 2114 top = XFIXNUM (y);
@@ -2106,7 +2116,7 @@ image_set_crop (struct image *img, double tm[3][3])
2106 top = img->height - height + top; 2116 top = img->height - height + top;
2107 } 2117 }
2108 else 2118 else
2109 top = (img->height - height)/2; 2119 top = (img->height - height) >> 1;
2110 2120
2111 /* Negative values operate from the right and bottom of the image 2121 /* Negative values operate from the right and bottom of the image
2112 instead of the left and top. */ 2122 instead of the left and top. */
@@ -2128,12 +2138,11 @@ image_set_crop (struct image *img, double tm[3][3])
2128 if (height + top > img->height) 2138 if (height + top > img->height)
2129 height = img->height - top; 2139 height = img->height - top;
2130 2140
2131 INIT_MATRIX (m); 2141 matrix3x3 tmp, m = { [0][0] = 1,
2132 m[2][0] = left; 2142 [1][1] = 1,
2133 m[2][1] = top; 2143 [2][0] = left, [2][1] = top, [2][2] = 1 };
2134 2144 matrix3x3_mult (m, tm, tmp);
2135 MULT_MATRICES (tm, m, tmp); 2145 matrix3x3_copy (tmp, tm);
2136 COPY_MATRIX (tmp, tm);
2137 2146
2138 img->width = width; 2147 img->width = width;
2139 img->height = height; 2148 img->height = height;
@@ -2141,7 +2150,7 @@ image_set_crop (struct image *img, double tm[3][3])
2141} 2150}
2142 2151
2143static void 2152static void
2144image_set_size (struct image *img, double tm[3][3]) 2153image_set_size (struct image *img, matrix3x3 tm)
2145{ 2154{
2146#ifdef HAVE_NATIVE_TRANSFORMS 2155#ifdef HAVE_NATIVE_TRANSFORMS
2147# ifdef HAVE_IMAGEMAGICK 2156# ifdef HAVE_IMAGEMAGICK
@@ -2160,18 +2169,12 @@ image_set_size (struct image *img, double tm[3][3])
2160 compute_image_size (img->width, img->height, img->spec, &width, &height); 2169 compute_image_size (img->width, img->height, img->spec, &width, &height);
2161 2170
2162# if defined (HAVE_NS) || defined (HAVE_XRENDER) 2171# if defined (HAVE_NS) || defined (HAVE_XRENDER)
2163 double rm[3][3], tmp[3][3]; 2172 double xscale = img->width / (double) width;
2164 double xscale, yscale; 2173 double yscale = img->height / (double) height;
2165
2166 xscale = img->width / (double) width;
2167 yscale = img->height / (double) height;
2168 2174
2169 INIT_MATRIX (rm); 2175 matrix3x3 tmp, rm = { [0][0] = xscale, [1][1] = yscale, [2][2] = 1 };
2170 rm[0][0] = xscale; 2176 matrix3x3_mult (rm, tm, tmp);
2171 rm[1][1] = yscale; 2177 matrix3x3_copy (tmp, tm);
2172
2173 MULT_MATRICES (tm, rm, tmp);
2174 COPY_MATRIX (tmp, tm);
2175 2178
2176 img->width = width; 2179 img->width = width;
2177 img->height = height; 2180 img->height = height;
@@ -2187,7 +2190,7 @@ image_set_size (struct image *img, double tm[3][3])
2187} 2190}
2188 2191
2189static void 2192static void
2190image_set_transform (struct frame *f, struct image *img, double matrix[3][3]) 2193image_set_transform (struct frame *f, struct image *img, matrix3x3 matrix)
2191{ 2194{
2192 /* TODO: Add MS Windows support. */ 2195 /* TODO: Add MS Windows support. */
2193#ifdef HAVE_NATIVE_TRANSFORMS 2196#ifdef HAVE_NATIVE_TRANSFORMS
@@ -2273,9 +2276,7 @@ lookup_image (struct frame *f, Lisp_Object spec)
2273 int relief_bound; 2276 int relief_bound;
2274 2277
2275#ifdef HAVE_NATIVE_TRANSFORMS 2278#ifdef HAVE_NATIVE_TRANSFORMS
2276 double transform_matrix[3][3]; 2279 matrix3x3 transform_matrix = { [0][0] = 1, [1][1] = 1, [2][2] = 1 };
2277
2278 INIT_MATRIX (transform_matrix);
2279 image_set_size (img, transform_matrix); 2280 image_set_size (img, transform_matrix);
2280 image_set_crop (img, transform_matrix); 2281 image_set_crop (img, transform_matrix);
2281 image_set_rotation (img, transform_matrix); 2282 image_set_rotation (img, transform_matrix);