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 SkMScalar 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 product = std::min(std::max(product, -SK_MScalar1), SK_MScalar1); |
60 | 60 |
61 // Interpolate angles along the shortest path. For example, to interpolate | 61 // Interpolate angles along the shortest path. For example, to interpolate |
62 // between a 175 degree angle and a 185 degree angle, interpolate along the | 62 // 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 | 63 // 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 | 64 // the opposite direction. This matches WebKit's implementation but not |
65 // the current W3C spec. Fixing the spec to match this approach is discussed | 65 // the current W3C spec. Fixing the spec to match this approach is discussed |
66 // at: | 66 // at: |
67 // http://lists.w3.org/Archives/Public/www-style/2013May/0131.html | 67 // http://lists.w3.org/Archives/Public/www-style/2013May/0131.html |
68 double scale1 = 1.0; | 68 SkMScalar scale1 = SK_MScalar1; |
69 if (product < 0) { | 69 if (product < 0) { |
70 product = -product; | 70 product = -product; |
71 scale1 = -1.0; | 71 scale1 = -SK_MScalar1; |
72 } | 72 } |
73 | 73 |
74 const double epsilon = 1e-5; | 74 const SkMScalar epsilon = 1e-5; |
75 if (std::abs(product - 1.0) < epsilon) { | 75 if (std::abs(product - SK_MScalar1) < epsilon) { |
76 for (int i = 0; i < 4; ++i) | 76 for (int i = 0; i < 4; ++i) |
77 out[i] = q1[i]; | 77 out[i] = q1[i]; |
78 return true; | 78 return true; |
79 } | 79 } |
80 | 80 |
81 double denom = std::sqrt(1 - product * product); | 81 SkMScalar denom = std::sqrt(1 - product * product); |
82 double theta = std::acos(product); | 82 SkMScalar theta = std::acos(product); |
83 double w = std::sin(progress * theta) * (1 / denom); | 83 SkMScalar w = std::sin(progress * theta) * (1 / denom); |
84 | 84 |
85 scale1 *= std::cos(progress * theta) - product * w; | 85 scale1 *= std::cos(progress * theta) - product * w; |
86 double scale2 = w; | 86 SkMScalar scale2 = w; |
87 Combine<4>(out, q1, q2, scale1, scale2); | 87 Combine<4>(out, q1, q2, scale1, scale2); |
88 | 88 |
89 return true; | 89 return true; |
90 } | 90 } |
91 | 91 |
92 // Returns false if the matrix cannot be normalized. | 92 // Returns false if the matrix cannot be normalized. |
93 bool Normalize(SkMatrix44& m) { | 93 bool Normalize(SkMatrix44& m) { |
94 if (m.getDouble(3, 3) == 0.0) | 94 if (m.get(3, 3) == 0.0) |
95 // Cannot normalize. | 95 // Cannot normalize. |
96 return false; | 96 return false; |
97 | 97 |
98 double scale = 1.0 / m.getDouble(3, 3); | 98 SkMScalar scale = 1.0 / m.get(3, 3); |
99 for (int i = 0; i < 4; i++) | 99 for (int i = 0; i < 4; i++) |
100 for (int j = 0; j < 4; j++) | 100 for (int j = 0; j < 4; j++) |
101 m.setDouble(i, j, m.getDouble(i, j) * scale); | 101 m.set(i, j, m.get(i, j) * scale); |
102 | 102 |
103 return true; | 103 return true; |
104 } | 104 } |
105 | 105 |
106 } // namespace | 106 } // namespace |
107 | 107 |
108 Transform GetScaleTransform(const Point& anchor, float scale) { | 108 Transform GetScaleTransform(const Point& anchor, float scale) { |
109 Transform transform; | 109 Transform transform; |
110 transform.Translate(anchor.x() * (1 - scale), | 110 transform.Translate(anchor.x() * (1 - scale), |
111 anchor.y() * (1 - scale)); | 111 anchor.y() * (1 - scale)); |
112 transform.Scale(scale, scale); | 112 transform.Scale(scale, scale); |
113 return transform; | 113 return transform; |
114 } | 114 } |
115 | 115 |
116 DecomposedTransform::DecomposedTransform() { | 116 DecomposedTransform::DecomposedTransform() { |
117 translate[0] = translate[1] = translate[2] = 0.0; | 117 translate[0] = translate[1] = translate[2] = 0.0; |
118 scale[0] = scale[1] = scale[2] = 1.0; | 118 scale[0] = scale[1] = scale[2] = 1.0; |
119 skew[0] = skew[1] = skew[2] = 0.0; | 119 skew[0] = skew[1] = skew[2] = 0.0; |
120 perspective[0] = perspective[1] = perspective[2] = 0.0; | 120 perspective[0] = perspective[1] = perspective[2] = 0.0; |
121 quaternion[0] = quaternion[1] = quaternion[2] = 0.0; | 121 quaternion[0] = quaternion[1] = quaternion[2] = 0.0; |
122 perspective[3] = quaternion[3] = 1.0; | 122 perspective[3] = quaternion[3] = 1.0; |
123 } | 123 } |
124 | 124 |
125 bool BlendDecomposedTransforms(DecomposedTransform* out, | 125 bool BlendDecomposedTransforms(DecomposedTransform* out, |
126 const DecomposedTransform& to, | 126 const DecomposedTransform& to, |
127 const DecomposedTransform& from, | 127 const DecomposedTransform& from, |
128 double progress) { | 128 SkMScalar progress) { |
129 double scalea = progress; | 129 SkMScalar scalea = progress; |
130 double scaleb = 1.0 - progress; | 130 SkMScalar scaleb = SK_MScalar1 - progress; |
131 Combine<3>(out->translate, to.translate, from.translate, scalea, scaleb); | 131 Combine<3>(out->translate, to.translate, from.translate, scalea, scaleb); |
132 Combine<3>(out->scale, to.scale, from.scale, scalea, scaleb); | 132 Combine<3>(out->scale, to.scale, from.scale, scalea, scaleb); |
133 Combine<3>(out->skew, to.skew, from.skew, scalea, scaleb); | 133 Combine<3>(out->skew, to.skew, from.skew, scalea, scaleb); |
134 Combine<4>( | 134 Combine<4>( |
135 out->perspective, to.perspective, from.perspective, scalea, scaleb); | 135 out->perspective, to.perspective, from.perspective, scalea, scaleb); |
136 return Slerp(out->quaternion, from.quaternion, to.quaternion, progress); | 136 return Slerp(out->quaternion, from.quaternion, to.quaternion, progress); |
137 } | 137 } |
138 | 138 |
139 // Taken from http://www.w3.org/TR/css3-transforms/. | 139 // Taken from http://www.w3.org/TR/css3-transforms/. |
140 bool DecomposeTransform(DecomposedTransform* decomp, | 140 bool DecomposeTransform(DecomposedTransform* decomp, |
141 const Transform& transform) { | 141 const Transform& transform) { |
142 if (!decomp) | 142 if (!decomp) |
143 return false; | 143 return false; |
144 | 144 |
145 // We'll operate on a copy of the matrix. | 145 // We'll operate on a copy of the matrix. |
146 SkMatrix44 matrix = transform.matrix(); | 146 SkMatrix44 matrix = transform.matrix(); |
147 | 147 |
148 // If we cannot normalize the matrix, then bail early as we cannot decompose. | 148 // If we cannot normalize the matrix, then bail early as we cannot decompose. |
149 if (!Normalize(matrix)) | 149 if (!Normalize(matrix)) |
150 return false; | 150 return false; |
151 | 151 |
152 SkMatrix44 perspectiveMatrix = matrix; | 152 SkMatrix44 perspectiveMatrix = matrix; |
153 | 153 |
154 for (int i = 0; i < 3; ++i) | 154 for (int i = 0; i < 3; ++i) |
155 perspectiveMatrix.setDouble(3, i, 0.0); | 155 perspectiveMatrix.set(3, i, 0.0); |
156 | 156 |
157 perspectiveMatrix.setDouble(3, 3, 1.0); | 157 perspectiveMatrix.set(3, 3, 1.0); |
158 | 158 |
159 // If the perspective matrix is not invertible, we are also unable to | 159 // If the perspective matrix is not invertible, we are also unable to |
160 // decompose, so we'll bail early. Constant taken from SkMatrix44::invert. | 160 // decompose, so we'll bail early. Constant taken from SkMatrix44::invert. |
161 if (std::abs(perspectiveMatrix.determinant()) < 1e-8) | 161 if (std::abs(perspectiveMatrix.determinant()) < 1e-8) |
162 return false; | 162 return false; |
163 | 163 |
164 if (matrix.getDouble(3, 0) != 0.0 || | 164 if (matrix.get(3, 0) != 0.0 || matrix.get(3, 1) != 0.0 || |
165 matrix.getDouble(3, 1) != 0.0 || | 165 matrix.get(3, 2) != 0.0) { |
166 matrix.getDouble(3, 2) != 0.0) { | |
167 // rhs is the right hand side of the equation. | 166 // rhs is the right hand side of the equation. |
168 SkMScalar rhs[4] = { | 167 SkMScalar rhs[4] = { |
169 matrix.get(3, 0), | 168 matrix.get(3, 0), |
170 matrix.get(3, 1), | 169 matrix.get(3, 1), |
171 matrix.get(3, 2), | 170 matrix.get(3, 2), |
172 matrix.get(3, 3) | 171 matrix.get(3, 3) |
173 }; | 172 }; |
174 | 173 |
175 // Solve the equation by inverting perspectiveMatrix and multiplying | 174 // Solve the equation by inverting perspectiveMatrix and multiplying |
176 // rhs by the inverse. | 175 // rhs by the inverse. |
(...skipping 11 matching lines...) Expand all Loading... |
188 decomp->perspective[i] = rhs[i]; | 187 decomp->perspective[i] = rhs[i]; |
189 | 188 |
190 } else { | 189 } else { |
191 // No perspective. | 190 // No perspective. |
192 for (int i = 0; i < 3; ++i) | 191 for (int i = 0; i < 3; ++i) |
193 decomp->perspective[i] = 0.0; | 192 decomp->perspective[i] = 0.0; |
194 decomp->perspective[3] = 1.0; | 193 decomp->perspective[3] = 1.0; |
195 } | 194 } |
196 | 195 |
197 for (int i = 0; i < 3; i++) | 196 for (int i = 0; i < 3; i++) |
198 decomp->translate[i] = matrix.getDouble(i, 3); | 197 decomp->translate[i] = matrix.get(i, 3); |
199 | 198 |
200 double row[3][3]; | 199 SkMScalar row[3][3]; |
201 for (int i = 0; i < 3; i++) | 200 for (int i = 0; i < 3; i++) |
202 for (int j = 0; j < 3; ++j) | 201 for (int j = 0; j < 3; ++j) |
203 row[i][j] = matrix.getDouble(j, i); | 202 row[i][j] = matrix.get(j, i); |
204 | 203 |
205 // Compute X scale factor and normalize first row. | 204 // Compute X scale factor and normalize first row. |
206 decomp->scale[0] = Length3(row[0]); | 205 decomp->scale[0] = Length3(row[0]); |
207 if (decomp->scale[0] != 0.0) | 206 if (decomp->scale[0] != 0.0) |
208 Scale3(row[0], 1.0 / decomp->scale[0]); | 207 Scale3(row[0], 1.0 / decomp->scale[0]); |
209 | 208 |
210 // Compute XY shear factor and make 2nd row orthogonal to 1st. | 209 // Compute XY shear factor and make 2nd row orthogonal to 1st. |
211 decomp->skew[0] = Dot<3>(row[0], row[1]); | 210 decomp->skew[0] = Dot<3>(row[0], row[1]); |
212 Combine<3>(row[1], row[1], row[0], 1.0, -decomp->skew[0]); | 211 Combine<3>(row[1], row[1], row[0], 1.0, -decomp->skew[0]); |
213 | 212 |
(...skipping 14 matching lines...) Expand all Loading... |
228 decomp->scale[2] = Length3(row[2]); | 227 decomp->scale[2] = Length3(row[2]); |
229 if (decomp->scale[2] != 0.0) | 228 if (decomp->scale[2] != 0.0) |
230 Scale3(row[2], 1.0 / decomp->scale[2]); | 229 Scale3(row[2], 1.0 / decomp->scale[2]); |
231 | 230 |
232 decomp->skew[1] /= decomp->scale[2]; | 231 decomp->skew[1] /= decomp->scale[2]; |
233 decomp->skew[2] /= decomp->scale[2]; | 232 decomp->skew[2] /= decomp->scale[2]; |
234 | 233 |
235 // At this point, the matrix (in rows) is orthonormal. | 234 // At this point, the matrix (in rows) is orthonormal. |
236 // Check for a coordinate system flip. If the determinant | 235 // Check for a coordinate system flip. If the determinant |
237 // is -1, then negate the matrix and the scaling factors. | 236 // is -1, then negate the matrix and the scaling factors. |
238 double pdum3[3]; | 237 SkMScalar pdum3[3]; |
239 Cross3(pdum3, row[1], row[2]); | 238 Cross3(pdum3, row[1], row[2]); |
240 if (Dot<3>(row[0], pdum3) < 0) { | 239 if (Dot<3>(row[0], pdum3) < 0) { |
241 for (int i = 0; i < 3; i++) { | 240 for (int i = 0; i < 3; i++) { |
242 decomp->scale[i] *= -1.0; | 241 decomp->scale[i] *= -1.0; |
243 for (int j = 0; j < 3; ++j) | 242 for (int j = 0; j < 3; ++j) |
244 row[i][j] *= -1.0; | 243 row[i][j] *= -1.0; |
245 } | 244 } |
246 } | 245 } |
247 | 246 |
248 decomp->quaternion[0] = | 247 decomp->quaternion[0] = |
(...skipping 12 matching lines...) Expand all Loading... |
261 if (row[1][0] > row[0][1]) | 260 if (row[1][0] > row[0][1]) |
262 decomp->quaternion[2] = -decomp->quaternion[2]; | 261 decomp->quaternion[2] = -decomp->quaternion[2]; |
263 | 262 |
264 return true; | 263 return true; |
265 } | 264 } |
266 | 265 |
267 // Taken from http://www.w3.org/TR/css3-transforms/. | 266 // Taken from http://www.w3.org/TR/css3-transforms/. |
268 Transform ComposeTransform(const DecomposedTransform& decomp) { | 267 Transform ComposeTransform(const DecomposedTransform& decomp) { |
269 SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor); | 268 SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor); |
270 for (int i = 0; i < 4; i++) | 269 for (int i = 0; i < 4; i++) |
271 matrix.setDouble(3, i, decomp.perspective[i]); | 270 matrix.set(3, i, decomp.perspective[i]); |
272 | 271 |
273 matrix.preTranslate(SkDoubleToMScalar(decomp.translate[0]), | 272 matrix.preTranslate( |
274 SkDoubleToMScalar(decomp.translate[1]), | 273 decomp.translate[0], decomp.translate[1], decomp.translate[2]); |
275 SkDoubleToMScalar(decomp.translate[2])); | |
276 | 274 |
277 double x = decomp.quaternion[0]; | 275 SkMScalar x = decomp.quaternion[0]; |
278 double y = decomp.quaternion[1]; | 276 SkMScalar y = decomp.quaternion[1]; |
279 double z = decomp.quaternion[2]; | 277 SkMScalar z = decomp.quaternion[2]; |
280 double w = decomp.quaternion[3]; | 278 SkMScalar w = decomp.quaternion[3]; |
281 | 279 |
282 SkMatrix44 rotation_matrix(SkMatrix44::kUninitialized_Constructor); | 280 SkMatrix44 rotation_matrix(SkMatrix44::kUninitialized_Constructor); |
283 rotation_matrix.set3x3(1.0 - 2.0 * (y * y + z * z), | 281 rotation_matrix.set3x3(1.0 - 2.0 * (y * y + z * z), |
284 2.0 * (x * y + z * w), | 282 2.0 * (x * y + z * w), |
285 2.0 * (x * z - y * w), | 283 2.0 * (x * z - y * w), |
286 2.0 * (x * y - z * w), | 284 2.0 * (x * y - z * w), |
287 1.0 - 2.0 * (x * x + z * z), | 285 1.0 - 2.0 * (x * x + z * z), |
288 2.0 * (y * z + x * w), | 286 2.0 * (y * z + x * w), |
289 2.0 * (x * z + y * w), | 287 2.0 * (x * z + y * w), |
290 2.0 * (y * z - x * w), | 288 2.0 * (y * z - x * w), |
291 1.0 - 2.0 * (x * x + y * y)); | 289 1.0 - 2.0 * (x * x + y * y)); |
292 | 290 |
293 matrix.preConcat(rotation_matrix); | 291 matrix.preConcat(rotation_matrix); |
294 | 292 |
295 SkMatrix44 temp(SkMatrix44::kIdentity_Constructor); | 293 SkMatrix44 temp(SkMatrix44::kIdentity_Constructor); |
296 if (decomp.skew[2]) { | 294 if (decomp.skew[2]) { |
297 temp.setDouble(1, 2, decomp.skew[2]); | 295 temp.set(1, 2, decomp.skew[2]); |
298 matrix.preConcat(temp); | 296 matrix.preConcat(temp); |
299 } | 297 } |
300 | 298 |
301 if (decomp.skew[1]) { | 299 if (decomp.skew[1]) { |
302 temp.setDouble(1, 2, 0); | 300 temp.set(1, 2, 0); |
303 temp.setDouble(0, 2, decomp.skew[1]); | 301 temp.set(0, 2, decomp.skew[1]); |
304 matrix.preConcat(temp); | 302 matrix.preConcat(temp); |
305 } | 303 } |
306 | 304 |
307 if (decomp.skew[0]) { | 305 if (decomp.skew[0]) { |
308 temp.setDouble(0, 2, 0); | 306 temp.set(0, 2, 0); |
309 temp.setDouble(0, 1, decomp.skew[0]); | 307 temp.set(0, 1, decomp.skew[0]); |
310 matrix.preConcat(temp); | 308 matrix.preConcat(temp); |
311 } | 309 } |
312 | 310 |
313 matrix.preScale(SkDoubleToMScalar(decomp.scale[0]), | 311 matrix.preScale(decomp.scale[0], decomp.scale[1], decomp.scale[2]); |
314 SkDoubleToMScalar(decomp.scale[1]), | |
315 SkDoubleToMScalar(decomp.scale[2])); | |
316 | 312 |
317 Transform to_return; | 313 Transform to_return; |
318 to_return.matrix() = matrix; | 314 to_return.matrix() = matrix; |
319 return to_return; | 315 return to_return; |
320 } | 316 } |
321 | 317 |
322 } // namespace ui | 318 } // namespace ui |
OLD | NEW |