15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/transform_util.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <cmath> 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/point.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace gfx { 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)double Length3(double v[3]) { 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Scale3(double v[3], double scale) { 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < 3; ++i) 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) v[i] *= scale; 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template <int n> 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)double Dot(const double* a, const double* b) { 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double toReturn = 0; 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < n; ++i) 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) toReturn += a[i] * b[i]; 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return toReturn; 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template <int n> 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Combine(double* out, 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const double* a, 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const double* b, 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double scale_a, 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double scale_b) { 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < n; ++i) 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) out[i] = a[i] * scale_a + b[i] * scale_b; 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void Cross3(double out[3], double a[3], double b[3]) { 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double x = a[1] * b[2] - a[2] * b[1]; 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double y = a[2] * b[0] - a[0] * b[2]; 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double z = a[0] * b[1] - a[1] * b[0]; 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) out[0] = x; 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) out[1] = y; 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) out[2] = z; 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Taken from http://www.w3.org/TR/css3-transforms/. 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Slerp(double out[4], 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const double q1[4], 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const double q2[4], 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double progress) { 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double product = Dot<4>(q1, q2); 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Clamp product to -1.0 <= product <= 1.0. 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) product = std::min(std::max(product, -1.0), 1.0); 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 61b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Interpolate angles along the shortest path. For example, to interpolate 62b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // between a 175 degree angle and a 185 degree angle, interpolate along the 63b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // 10 degree path from 175 to 185, rather than along the 350 degree path in 64b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // the opposite direction. This matches WebKit's implementation but not 65b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // the current W3C spec. Fixing the spec to match this approach is discussed 66b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // at: 67b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // http://lists.w3.org/Archives/Public/www-style/2013May/0131.html 68b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) double scale1 = 1.0; 69b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (product < 0) { 70b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) product = -product; 71b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) scale1 = -1.0; 72b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 73b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const double epsilon = 1e-5; 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (std::abs(product - 1.0) < epsilon) { 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < 4; ++i) 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) out[i] = q1[i]; 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double denom = std::sqrt(1 - product * product); 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double theta = std::acos(product); 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double w = std::sin(progress * theta) * (1 / denom); 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 85b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) scale1 *= std::cos(progress * theta) - product * w; 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double scale2 = w; 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Combine<4>(out, q1, q2, scale1, scale2); 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns false if the matrix cannot be normalized. 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Normalize(SkMatrix44& m) { 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (m.getDouble(3, 3) == 0.0) 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Cannot normalize. 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double scale = 1.0 / m.getDouble(3, 3); 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < 4; i++) 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int j = 0; j < 4; j++) 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) m.setDouble(i, j, m.getDouble(i, j) * scale); 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Transform GetScaleTransform(const Point& anchor, float scale) { 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Transform transform; 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) transform.Translate(anchor.x() * (1 - scale), 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) anchor.y() * (1 - scale)); 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) transform.Scale(scale, scale); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return transform; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DecomposedTransform::DecomposedTransform() { 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) translate[0] = translate[1] = translate[2] = 0.0; 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scale[0] = scale[1] = scale[2] = 1.0; 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) skew[0] = skew[1] = skew[2] = 0.0; 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) perspective[0] = perspective[1] = perspective[2] = 0.0; 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) quaternion[0] = quaternion[1] = quaternion[2] = 0.0; 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) perspective[3] = quaternion[3] = 1.0; 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BlendDecomposedTransforms(DecomposedTransform* out, 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const DecomposedTransform& to, 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const DecomposedTransform& from, 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double progress) { 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double scalea = progress; 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double scaleb = 1.0 - progress; 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Combine<3>(out->translate, to.translate, from.translate, scalea, scaleb); 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Combine<3>(out->scale, to.scale, from.scale, scalea, scaleb); 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Combine<3>(out->skew, to.skew, from.skew, scalea, scaleb); 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Combine<4>( 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) out->perspective, to.perspective, from.perspective, scalea, scaleb); 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return Slerp(out->quaternion, from.quaternion, to.quaternion, progress); 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Taken from http://www.w3.org/TR/css3-transforms/. 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DecomposeTransform(DecomposedTransform* decomp, 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const Transform& transform) { 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!decomp) 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We'll operate on a copy of the matrix. 1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkMatrix44 matrix = transform.matrix(); 1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If we cannot normalize the matrix, then bail early as we cannot decompose. 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!Normalize(matrix)) 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkMatrix44 perspectiveMatrix = matrix; 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < 3; ++i) 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) perspectiveMatrix.setDouble(3, i, 0.0); 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) perspectiveMatrix.setDouble(3, 3, 1.0); 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If the perspective matrix is not invertible, we are also unable to 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // decompose, so we'll bail early. Constant taken from SkMatrix44::invert. 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (std::abs(perspectiveMatrix.determinant()) < 1e-8) 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (matrix.getDouble(3, 0) != 0.0 || 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) matrix.getDouble(3, 1) != 0.0 || 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) matrix.getDouble(3, 2) != 0.0) { 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // rhs is the right hand side of the equation. 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkMScalar rhs[4] = { 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) matrix.get(3, 0), 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) matrix.get(3, 1), 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) matrix.get(3, 2), 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) matrix.get(3, 3) 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) }; 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Solve the equation by inverting perspectiveMatrix and multiplying 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // rhs by the inverse. 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkMatrix44 inversePerspectiveMatrix(SkMatrix44::kUninitialized_Constructor); 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!perspectiveMatrix.invert(&inversePerspectiveMatrix)) 1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkMatrix44 transposedInversePerspectiveMatrix = 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) inversePerspectiveMatrix; 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) transposedInversePerspectiveMatrix.transpose(); 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) transposedInversePerspectiveMatrix.mapMScalars(rhs); 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < 4; ++i) 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->perspective[i] = rhs[i]; 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // No perspective. 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < 3; ++i) 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->perspective[i] = 0.0; 1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->perspective[3] = 1.0; 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < 3; i++) 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->translate[i] = matrix.getDouble(i, 3); 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double row[3][3]; 2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < 3; i++) 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int j = 0; j < 3; ++j) 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) row[i][j] = matrix.getDouble(j, i); 2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Compute X scale factor and normalize first row. 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->scale[0] = Length3(row[0]); 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (decomp->scale[0] != 0.0) 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Scale3(row[0], 1.0 / decomp->scale[0]); 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Compute XY shear factor and make 2nd row orthogonal to 1st. 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->skew[0] = Dot<3>(row[0], row[1]); 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Combine<3>(row[1], row[1], row[0], 1.0, -decomp->skew[0]); 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Now, compute Y scale and normalize 2nd row. 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->scale[1] = Length3(row[1]); 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (decomp->scale[1] != 0.0) 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Scale3(row[1], 1.0 / decomp->scale[1]); 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->skew[0] /= decomp->scale[1]; 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Compute XZ and YZ shears, orthogonalize 3rd row 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->skew[1] = Dot<3>(row[0], row[2]); 2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Combine<3>(row[2], row[2], row[0], 1.0, -decomp->skew[1]); 2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->skew[2] = Dot<3>(row[1], row[2]); 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Combine<3>(row[2], row[2], row[1], 1.0, -decomp->skew[2]); 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Next, get Z scale and normalize 3rd row. 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->scale[2] = Length3(row[2]); 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (decomp->scale[2] != 0.0) 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Scale3(row[2], 1.0 / decomp->scale[2]); 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->skew[1] /= decomp->scale[2]; 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->skew[2] /= decomp->scale[2]; 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // At this point, the matrix (in rows) is orthonormal. 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Check for a coordinate system flip. If the determinant 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // is -1, then negate the matrix and the scaling factors. 2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double pdum3[3]; 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Cross3(pdum3, row[1], row[2]); 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (Dot<3>(row[0], pdum3) < 0) { 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < 3; i++) { 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->scale[i] *= -1.0; 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int j = 0; j < 3; ++j) 2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) row[i][j] *= -1.0; 2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->quaternion[0] = 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 0.5 * std::sqrt(std::max(1.0 + row[0][0] - row[1][1] - row[2][2], 0.0)); 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->quaternion[1] = 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 0.5 * std::sqrt(std::max(1.0 - row[0][0] + row[1][1] - row[2][2], 0.0)); 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->quaternion[2] = 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 0.5 * std::sqrt(std::max(1.0 - row[0][0] - row[1][1] + row[2][2], 0.0)); 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->quaternion[3] = 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 0.5 * std::sqrt(std::max(1.0 + row[0][0] + row[1][1] + row[2][2], 0.0)); 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (row[2][1] > row[1][2]) 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->quaternion[0] = -decomp->quaternion[0]; 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (row[0][2] > row[2][0]) 2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->quaternion[1] = -decomp->quaternion[1]; 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (row[1][0] > row[0][1]) 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) decomp->quaternion[2] = -decomp->quaternion[2]; 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Taken from http://www.w3.org/TR/css3-transforms/. 2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Transform ComposeTransform(const DecomposedTransform& decomp) { 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor); 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < 4; i++) 2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) matrix.setDouble(3, i, decomp.perspective[i]); 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) matrix.preTranslate(SkDoubleToMScalar(decomp.translate[0]), 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkDoubleToMScalar(decomp.translate[1]), 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkDoubleToMScalar(decomp.translate[2])); 2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double x = decomp.quaternion[0]; 2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double y = decomp.quaternion[1]; 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double z = decomp.quaternion[2]; 2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double w = decomp.quaternion[3]; 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkMatrix44 rotation_matrix(SkMatrix44::kUninitialized_Constructor); 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rotation_matrix.set3x3(1.0 - 2.0 * (y * y + z * z), 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2.0 * (x * y + z * w), 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2.0 * (x * z - y * w), 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2.0 * (x * y - z * w), 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1.0 - 2.0 * (x * x + z * z), 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2.0 * (y * z + x * w), 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2.0 * (x * z + y * w), 2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2.0 * (y * z - x * w), 2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1.0 - 2.0 * (x * x + y * y)); 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) matrix.preConcat(rotation_matrix); 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkMatrix44 temp(SkMatrix44::kIdentity_Constructor); 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (decomp.skew[2]) { 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) temp.setDouble(1, 2, decomp.skew[2]); 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) matrix.preConcat(temp); 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (decomp.skew[1]) { 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) temp.setDouble(1, 2, 0); 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) temp.setDouble(0, 2, decomp.skew[1]); 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) matrix.preConcat(temp); 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (decomp.skew[0]) { 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) temp.setDouble(0, 2, 0); 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) temp.setDouble(0, 1, decomp.skew[0]); 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) matrix.preConcat(temp); 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) matrix.preScale(SkDoubleToMScalar(decomp.scale[0]), 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkDoubleToMScalar(decomp.scale[1]), 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkDoubleToMScalar(decomp.scale[2])); 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Transform to_return; 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) to_return.matrix() = matrix; 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return to_return; 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace ui 323