OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/transform_util.h" | 5 #include "ui/gfx/transform_util.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 | 8 |
9 #include "ui/gfx/point.h" | 9 #include "ui/gfx/point.h" |
10 | 10 |
11 namespace gfx { | 11 namespace gfx { |
12 | 12 |
13 namespace { | 13 namespace { |
14 | 14 |
15 double Length3(double v[3]) { | 15 SkMScalar Length3(SkMScalar v[3]) { |
16 return std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); | 16 return std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); |
17 } | 17 } |
18 | 18 |
19 void Scale3(double v[3], double scale) { | 19 void Scale3(SkMScalar v[3], SkMScalar scale) { |
20 for (int i = 0; i < 3; ++i) | 20 for (int i = 0; i < 3; ++i) |
21 v[i] *= scale; | 21 v[i] *= scale; |
22 } | 22 } |
23 | 23 |
24 template <int n> | 24 template <int n> |
25 double Dot(const double* a, const double* b) { | 25 SkMScalar Dot(const SkMScalar* a, const SkMScalar* b) { |
26 double toReturn = 0; | 26 SkMScalar toReturn = 0; |
27 for (int i = 0; i < n; ++i) | 27 for (int i = 0; i < n; ++i) |
28 toReturn += a[i] * b[i]; | 28 toReturn += a[i] * b[i]; |
29 return toReturn; | 29 return toReturn; |
30 } | 30 } |
31 | 31 |
32 template <int n> | 32 template <int n> |
33 void Combine(double* out, | 33 void Combine(SkMScalar* out, |
34 const double* a, | 34 const SkMScalar* a, |
35 const double* b, | 35 const SkMScalar* b, |
36 double scale_a, | 36 SkMScalar scale_a, |
37 double scale_b) { | 37 SkMScalar scale_b) { |
38 for (int i = 0; i < n; ++i) | 38 for (int i = 0; i < n; ++i) |
39 out[i] = a[i] * scale_a + b[i] * scale_b; | 39 out[i] = a[i] * scale_a + b[i] * scale_b; |
40 } | 40 } |
41 | 41 |
42 void Cross3(double out[3], double a[3], double b[3]) { | 42 void Cross3(SkMScalar out[3], SkMScalar a[3], SkMScalar b[3]) { |
43 double x = a[1] * b[2] - a[2] * b[1]; | 43 SkMScalar x = a[1] * b[2] - a[2] * b[1]; |
44 double y = a[2] * b[0] - a[0] * b[2]; | 44 SkMScalar y = a[2] * b[0] - a[0] * b[2]; |
45 double z = a[0] * b[1] - a[1] * b[0]; | 45 SkMScalar z = a[0] * b[1] - a[1] * b[0]; |
46 out[0] = x; | 46 out[0] = x; |
47 out[1] = y; | 47 out[1] = y; |
48 out[2] = z; | 48 out[2] = z; |
49 } | 49 } |
50 | 50 |
51 // Taken from http://www.w3.org/TR/css3-transforms/. | 51 // Taken from http://www.w3.org/TR/css3-transforms/. |
52 bool Slerp(double out[4], | 52 bool Slerp(SkMScalar out[4], |
53 const double q1[4], | 53 const SkMScalar q1[4], |
54 const double q2[4], | 54 const SkMScalar q2[4], |
55 double progress) { | 55 double progress) { |
56 double product = Dot<4>(q1, q2); | 56 SkMScalar product = Dot<4>(q1, q2); |
57 | 57 |
58 // Clamp product to -1.0 <= product <= 1.0. | 58 // Clamp product to -1.0 <= product <= 1.0. |
59 product = std::min(std::max(product, -1.0), 1.0); | 59 SkMScalar one(1); |
60 product = std::min(std::max(product, -one), one); | |
danakj
2013/09/09 17:57:45
SK_MScalar1?
enne (OOO)
2013/09/10 22:32:32
Done.
| |
60 | 61 |
61 // Interpolate angles along the shortest path. For example, to interpolate | 62 // Interpolate angles along the shortest path. For example, to interpolate |
62 // between a 175 degree angle and a 185 degree angle, interpolate along the | 63 // between a 175 degree angle and a 185 degree angle, interpolate along the |
63 // 10 degree path from 175 to 185, rather than along the 350 degree path in | 64 // 10 degree path from 175 to 185, rather than along the 350 degree path in |
64 // the opposite direction. This matches WebKit's implementation but not | 65 // the opposite direction. This matches WebKit's implementation but not |
65 // the current W3C spec. Fixing the spec to match this approach is discussed | 66 // the current W3C spec. Fixing the spec to match this approach is discussed |
66 // at: | 67 // at: |
67 // http://lists.w3.org/Archives/Public/www-style/2013May/0131.html | 68 // http://lists.w3.org/Archives/Public/www-style/2013May/0131.html |
68 double scale1 = 1.0; | 69 SkMScalar scale1 = 1.0; |
69 if (product < 0) { | 70 if (product < 0) { |
70 product = -product; | 71 product = -product; |
71 scale1 = -1.0; | 72 scale1 = -1.0; |
72 } | 73 } |
73 | 74 |
74 const double epsilon = 1e-5; | 75 const SkMScalar epsilon = 1e-5; |
75 if (std::abs(product - 1.0) < epsilon) { | 76 if (std::abs(product - 1.0) < epsilon) { |
danakj
2013/09/09 17:57:45
should this be SK_MScalar1? or integer literal? or
enne (OOO)
2013/09/10 22:32:32
Done.
| |
76 for (int i = 0; i < 4; ++i) | 77 for (int i = 0; i < 4; ++i) |
77 out[i] = q1[i]; | 78 out[i] = q1[i]; |
78 return true; | 79 return true; |
79 } | 80 } |
80 | 81 |
81 double denom = std::sqrt(1 - product * product); | 82 SkMScalar denom = std::sqrt(1 - product * product); |
82 double theta = std::acos(product); | 83 SkMScalar theta = std::acos(product); |
danakj
2013/09/09 17:57:45
Should |product| and |w| and all these variables a
enne (OOO)
2013/09/10 22:32:32
I think it's less important here. The doubles for
| |
83 double w = std::sin(progress * theta) * (1 / denom); | 84 SkMScalar w = std::sin(progress * theta) * (1 / denom); |
84 | 85 |
85 scale1 *= std::cos(progress * theta) - product * w; | 86 scale1 *= std::cos(progress * theta) - product * w; |
86 double scale2 = w; | 87 SkMScalar scale2 = w; |
87 Combine<4>(out, q1, q2, scale1, scale2); | 88 Combine<4>(out, q1, q2, scale1, scale2); |
88 | 89 |
89 return true; | 90 return true; |
90 } | 91 } |
91 | 92 |
92 // Returns false if the matrix cannot be normalized. | 93 // Returns false if the matrix cannot be normalized. |
93 bool Normalize(SkMatrix44& m) { | 94 bool Normalize(SkMatrix44& m) { |
94 if (m.getDouble(3, 3) == 0.0) | 95 if (m.get(3, 3) == 0.0) |
95 // Cannot normalize. | 96 // Cannot normalize. |
96 return false; | 97 return false; |
97 | 98 |
98 double scale = 1.0 / m.getDouble(3, 3); | 99 SkMScalar scale = 1.0 / m.get(3, 3); |
99 for (int i = 0; i < 4; i++) | 100 for (int i = 0; i < 4; i++) |
100 for (int j = 0; j < 4; j++) | 101 for (int j = 0; j < 4; j++) |
101 m.setDouble(i, j, m.getDouble(i, j) * scale); | 102 m.set(i, j, m.get(i, j) * scale); |
102 | 103 |
103 return true; | 104 return true; |
104 } | 105 } |
105 | 106 |
106 } // namespace | 107 } // namespace |
107 | 108 |
108 Transform GetScaleTransform(const Point& anchor, float scale) { | 109 Transform GetScaleTransform(const Point& anchor, float scale) { |
109 Transform transform; | 110 Transform transform; |
110 transform.Translate(anchor.x() * (1 - scale), | 111 transform.Translate(anchor.x() * (1 - scale), |
111 anchor.y() * (1 - scale)); | 112 anchor.y() * (1 - scale)); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
145 // We'll operate on a copy of the matrix. | 146 // We'll operate on a copy of the matrix. |
146 SkMatrix44 matrix = transform.matrix(); | 147 SkMatrix44 matrix = transform.matrix(); |
147 | 148 |
148 // If we cannot normalize the matrix, then bail early as we cannot decompose. | 149 // If we cannot normalize the matrix, then bail early as we cannot decompose. |
149 if (!Normalize(matrix)) | 150 if (!Normalize(matrix)) |
150 return false; | 151 return false; |
151 | 152 |
152 SkMatrix44 perspectiveMatrix = matrix; | 153 SkMatrix44 perspectiveMatrix = matrix; |
153 | 154 |
154 for (int i = 0; i < 3; ++i) | 155 for (int i = 0; i < 3; ++i) |
155 perspectiveMatrix.setDouble(3, i, 0.0); | 156 perspectiveMatrix.set(3, i, 0.0); |
156 | 157 |
157 perspectiveMatrix.setDouble(3, 3, 1.0); | 158 perspectiveMatrix.set(3, 3, 1.0); |
158 | 159 |
159 // If the perspective matrix is not invertible, we are also unable to | 160 // If the perspective matrix is not invertible, we are also unable to |
160 // decompose, so we'll bail early. Constant taken from SkMatrix44::invert. | 161 // decompose, so we'll bail early. Constant taken from SkMatrix44::invert. |
161 if (std::abs(perspectiveMatrix.determinant()) < 1e-8) | 162 if (std::abs(perspectiveMatrix.determinant()) < 1e-8) |
162 return false; | 163 return false; |
163 | 164 |
164 if (matrix.getDouble(3, 0) != 0.0 || | 165 if (matrix.get(3, 0) != 0.0 || matrix.get(3, 1) != 0.0 || |
165 matrix.getDouble(3, 1) != 0.0 || | 166 matrix.get(3, 2) != 0.0) { |
166 matrix.getDouble(3, 2) != 0.0) { | |
167 // rhs is the right hand side of the equation. | 167 // rhs is the right hand side of the equation. |
168 SkMScalar rhs[4] = { | 168 SkMScalar rhs[4] = { |
169 matrix.get(3, 0), | 169 matrix.get(3, 0), |
170 matrix.get(3, 1), | 170 matrix.get(3, 1), |
171 matrix.get(3, 2), | 171 matrix.get(3, 2), |
172 matrix.get(3, 3) | 172 matrix.get(3, 3) |
173 }; | 173 }; |
174 | 174 |
175 // Solve the equation by inverting perspectiveMatrix and multiplying | 175 // Solve the equation by inverting perspectiveMatrix and multiplying |
176 // rhs by the inverse. | 176 // rhs by the inverse. |
(...skipping 11 matching lines...) Expand all Loading... | |
188 decomp->perspective[i] = rhs[i]; | 188 decomp->perspective[i] = rhs[i]; |
189 | 189 |
190 } else { | 190 } else { |
191 // No perspective. | 191 // No perspective. |
192 for (int i = 0; i < 3; ++i) | 192 for (int i = 0; i < 3; ++i) |
193 decomp->perspective[i] = 0.0; | 193 decomp->perspective[i] = 0.0; |
194 decomp->perspective[3] = 1.0; | 194 decomp->perspective[3] = 1.0; |
195 } | 195 } |
196 | 196 |
197 for (int i = 0; i < 3; i++) | 197 for (int i = 0; i < 3; i++) |
198 decomp->translate[i] = matrix.getDouble(i, 3); | 198 decomp->translate[i] = matrix.get(i, 3); |
199 | 199 |
200 double row[3][3]; | 200 SkMScalar row[3][3]; |
201 for (int i = 0; i < 3; i++) | 201 for (int i = 0; i < 3; i++) |
202 for (int j = 0; j < 3; ++j) | 202 for (int j = 0; j < 3; ++j) |
203 row[i][j] = matrix.getDouble(j, i); | 203 row[i][j] = matrix.get(j, i); |
204 | 204 |
205 // Compute X scale factor and normalize first row. | 205 // Compute X scale factor and normalize first row. |
206 decomp->scale[0] = Length3(row[0]); | 206 decomp->scale[0] = Length3(row[0]); |
207 if (decomp->scale[0] != 0.0) | 207 if (decomp->scale[0] != 0.0) |
208 Scale3(row[0], 1.0 / decomp->scale[0]); | 208 Scale3(row[0], 1.0 / decomp->scale[0]); |
209 | 209 |
210 // Compute XY shear factor and make 2nd row orthogonal to 1st. | 210 // Compute XY shear factor and make 2nd row orthogonal to 1st. |
211 decomp->skew[0] = Dot<3>(row[0], row[1]); | 211 decomp->skew[0] = Dot<3>(row[0], row[1]); |
212 Combine<3>(row[1], row[1], row[0], 1.0, -decomp->skew[0]); | 212 Combine<3>(row[1], row[1], row[0], 1.0, -decomp->skew[0]); |
213 | 213 |
(...skipping 14 matching lines...) Expand all Loading... | |
228 decomp->scale[2] = Length3(row[2]); | 228 decomp->scale[2] = Length3(row[2]); |
229 if (decomp->scale[2] != 0.0) | 229 if (decomp->scale[2] != 0.0) |
230 Scale3(row[2], 1.0 / decomp->scale[2]); | 230 Scale3(row[2], 1.0 / decomp->scale[2]); |
231 | 231 |
232 decomp->skew[1] /= decomp->scale[2]; | 232 decomp->skew[1] /= decomp->scale[2]; |
233 decomp->skew[2] /= decomp->scale[2]; | 233 decomp->skew[2] /= decomp->scale[2]; |
234 | 234 |
235 // At this point, the matrix (in rows) is orthonormal. | 235 // At this point, the matrix (in rows) is orthonormal. |
236 // Check for a coordinate system flip. If the determinant | 236 // Check for a coordinate system flip. If the determinant |
237 // is -1, then negate the matrix and the scaling factors. | 237 // is -1, then negate the matrix and the scaling factors. |
238 double pdum3[3]; | 238 SkMScalar pdum3[3]; |
239 Cross3(pdum3, row[1], row[2]); | 239 Cross3(pdum3, row[1], row[2]); |
240 if (Dot<3>(row[0], pdum3) < 0) { | 240 if (Dot<3>(row[0], pdum3) < 0) { |
241 for (int i = 0; i < 3; i++) { | 241 for (int i = 0; i < 3; i++) { |
242 decomp->scale[i] *= -1.0; | 242 decomp->scale[i] *= -1.0; |
243 for (int j = 0; j < 3; ++j) | 243 for (int j = 0; j < 3; ++j) |
244 row[i][j] *= -1.0; | 244 row[i][j] *= -1.0; |
245 } | 245 } |
246 } | 246 } |
247 | 247 |
248 decomp->quaternion[0] = | 248 decomp->quaternion[0] = |
(...skipping 12 matching lines...) Expand all Loading... | |
261 if (row[1][0] > row[0][1]) | 261 if (row[1][0] > row[0][1]) |
262 decomp->quaternion[2] = -decomp->quaternion[2]; | 262 decomp->quaternion[2] = -decomp->quaternion[2]; |
263 | 263 |
264 return true; | 264 return true; |
265 } | 265 } |
266 | 266 |
267 // Taken from http://www.w3.org/TR/css3-transforms/. | 267 // Taken from http://www.w3.org/TR/css3-transforms/. |
268 Transform ComposeTransform(const DecomposedTransform& decomp) { | 268 Transform ComposeTransform(const DecomposedTransform& decomp) { |
269 SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor); | 269 SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor); |
270 for (int i = 0; i < 4; i++) | 270 for (int i = 0; i < 4; i++) |
271 matrix.setDouble(3, i, decomp.perspective[i]); | 271 matrix.set(3, i, decomp.perspective[i]); |
272 | 272 |
273 matrix.preTranslate(SkDoubleToMScalar(decomp.translate[0]), | 273 matrix.preTranslate( |
274 SkDoubleToMScalar(decomp.translate[1]), | 274 decomp.translate[0], decomp.translate[1], decomp.translate[2]); |
275 SkDoubleToMScalar(decomp.translate[2])); | |
276 | 275 |
277 double x = decomp.quaternion[0]; | 276 SkMScalar x = decomp.quaternion[0]; |
278 double y = decomp.quaternion[1]; | 277 SkMScalar y = decomp.quaternion[1]; |
279 double z = decomp.quaternion[2]; | 278 SkMScalar z = decomp.quaternion[2]; |
280 double w = decomp.quaternion[3]; | 279 SkMScalar w = decomp.quaternion[3]; |
281 | 280 |
282 SkMatrix44 rotation_matrix(SkMatrix44::kUninitialized_Constructor); | 281 SkMatrix44 rotation_matrix(SkMatrix44::kUninitialized_Constructor); |
283 rotation_matrix.set3x3(1.0 - 2.0 * (y * y + z * z), | 282 rotation_matrix.set3x3(1.0 - 2.0 * (y * y + z * z), |
284 2.0 * (x * y + z * w), | 283 2.0 * (x * y + z * w), |
285 2.0 * (x * z - y * w), | 284 2.0 * (x * z - y * w), |
286 2.0 * (x * y - z * w), | 285 2.0 * (x * y - z * w), |
287 1.0 - 2.0 * (x * x + z * z), | 286 1.0 - 2.0 * (x * x + z * z), |
288 2.0 * (y * z + x * w), | 287 2.0 * (y * z + x * w), |
289 2.0 * (x * z + y * w), | 288 2.0 * (x * z + y * w), |
290 2.0 * (y * z - x * w), | 289 2.0 * (y * z - x * w), |
291 1.0 - 2.0 * (x * x + y * y)); | 290 1.0 - 2.0 * (x * x + y * y)); |
292 | 291 |
293 matrix.preConcat(rotation_matrix); | 292 matrix.preConcat(rotation_matrix); |
294 | 293 |
295 SkMatrix44 temp(SkMatrix44::kIdentity_Constructor); | 294 SkMatrix44 temp(SkMatrix44::kIdentity_Constructor); |
296 if (decomp.skew[2]) { | 295 if (decomp.skew[2]) { |
297 temp.setDouble(1, 2, decomp.skew[2]); | 296 temp.set(1, 2, decomp.skew[2]); |
298 matrix.preConcat(temp); | 297 matrix.preConcat(temp); |
299 } | 298 } |
300 | 299 |
301 if (decomp.skew[1]) { | 300 if (decomp.skew[1]) { |
302 temp.setDouble(1, 2, 0); | 301 temp.set(1, 2, 0); |
303 temp.setDouble(0, 2, decomp.skew[1]); | 302 temp.set(0, 2, decomp.skew[1]); |
304 matrix.preConcat(temp); | 303 matrix.preConcat(temp); |
305 } | 304 } |
306 | 305 |
307 if (decomp.skew[0]) { | 306 if (decomp.skew[0]) { |
308 temp.setDouble(0, 2, 0); | 307 temp.set(0, 2, 0); |
309 temp.setDouble(0, 1, decomp.skew[0]); | 308 temp.set(0, 1, decomp.skew[0]); |
310 matrix.preConcat(temp); | 309 matrix.preConcat(temp); |
311 } | 310 } |
312 | 311 |
313 matrix.preScale(SkDoubleToMScalar(decomp.scale[0]), | 312 matrix.preScale(decomp.scale[0], decomp.scale[1], decomp.scale[2]); |
314 SkDoubleToMScalar(decomp.scale[1]), | |
315 SkDoubleToMScalar(decomp.scale[2])); | |
316 | 313 |
317 Transform to_return; | 314 Transform to_return; |
318 to_return.matrix() = matrix; | 315 to_return.matrix() = matrix; |
319 return to_return; | 316 return to_return; |
320 } | 317 } |
321 | 318 |
322 } // namespace ui | 319 } // namespace ui |
OLD | NEW |