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