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)
7d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include <algorithm>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <cmath>
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/logging.h"
1168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "base/strings/stringprintf.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/point.h"
131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ui/gfx/point3_f.h"
141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "ui/gfx/rect.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace gfx {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)SkMScalar Length3(SkMScalar v[3]) {
2168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  double vd[3] = {SkMScalarToDouble(v[0]), SkMScalarToDouble(v[1]),
2268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                  SkMScalarToDouble(v[2])};
2368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return SkDoubleToMScalar(
2468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      std::sqrt(vd[0] * vd[0] + vd[1] * vd[1] + vd[2] * vd[2]));
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void Scale3(SkMScalar v[3], SkMScalar scale) {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < 3; ++i)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    v[i] *= scale;
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template <int n>
3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)SkMScalar Dot(const SkMScalar* a, const SkMScalar* b) {
3468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  double total = 0.0;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < n; ++i)
3668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    total += a[i] * b[i];
3768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return SkDoubleToMScalar(total);
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template <int n>
4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void Combine(SkMScalar* out,
4258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)             const SkMScalar* a,
4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)             const SkMScalar* b,
4468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)             double scale_a,
4568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)             double scale_b) {
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < n; ++i)
4768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    out[i] = SkDoubleToMScalar(a[i] * scale_a + b[i] * scale_b);
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void Cross3(SkMScalar out[3], SkMScalar a[3], SkMScalar b[3]) {
5158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  SkMScalar x = a[1] * b[2] - a[2] * b[1];
5258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  SkMScalar y = a[2] * b[0] - a[0] * b[2];
5358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  SkMScalar z = a[0] * b[1] - a[1] * b[0];
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  out[0] = x;
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  out[1] = y;
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  out[2] = z;
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)SkMScalar Round(SkMScalar n) {
601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return SkDoubleToMScalar(std::floor(SkMScalarToDouble(n) + 0.5));
611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Taken from http://www.w3.org/TR/css3-transforms/.
6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool Slerp(SkMScalar out[4],
6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)           const SkMScalar q1[4],
6658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)           const SkMScalar q2[4],
6768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)           double progress) {
6868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  double product = Dot<4>(q1, q2);
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Clamp product to -1.0 <= product <= 1.0.
7168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  product = std::min(std::max(product, -1.0), 1.0);
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
73b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // Interpolate angles along the shortest path. For example, to interpolate
74b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // between a 175 degree angle and a 185 degree angle, interpolate along the
75b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // 10 degree path from 175 to 185, rather than along the 350 degree path in
76b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // the opposite direction. This matches WebKit's implementation but not
77b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // the current W3C spec. Fixing the spec to match this approach is discussed
78b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // at:
79b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  // http://lists.w3.org/Archives/Public/www-style/2013May/0131.html
8068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  double scale1 = 1.0;
81b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (product < 0) {
82b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    product = -product;
8368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    scale1 = -1.0;
84b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
85b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
8668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const double epsilon = 1e-5;
8768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (std::abs(product - 1.0) < epsilon) {
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < 4; ++i)
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      out[i] = q1[i];
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  double denom = std::sqrt(1.0 - product * product);
9468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  double theta = std::acos(product);
9568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  double w = std::sin(progress * theta) * (1.0 / denom);
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
97b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  scale1 *= std::cos(progress * theta) - product * w;
9868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  double scale2 = w;
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Combine<4>(out, q1, q2, scale1, scale2);
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns false if the matrix cannot be normalized.
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Normalize(SkMatrix44& m) {
10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (m.get(3, 3) == 0.0)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Cannot normalize.
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  SkMScalar scale = 1.0 / m.get(3, 3);
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < 4; i++)
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int j = 0; j < 4; j++)
11358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      m.set(i, j, m.get(i, j) * scale);
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)SkMatrix44 BuildPerspectiveMatrix(const DecomposedTransform& decomp) {
1191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor);
1201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  for (int i = 0; i < 4; i++)
1221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    matrix.setDouble(3, i, decomp.perspective[i]);
1231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return matrix;
1241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)SkMatrix44 BuildTranslationMatrix(const DecomposedTransform& decomp) {
1271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor);
1281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Implicitly calls matrix.setIdentity()
1291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  matrix.setTranslate(SkDoubleToMScalar(decomp.translate[0]),
1301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                      SkDoubleToMScalar(decomp.translate[1]),
1311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                      SkDoubleToMScalar(decomp.translate[2]));
1321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return matrix;
1331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)SkMatrix44 BuildSnappedTranslationMatrix(DecomposedTransform decomp) {
1361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  decomp.translate[0] = Round(decomp.translate[0]);
1371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  decomp.translate[1] = Round(decomp.translate[1]);
1381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  decomp.translate[2] = Round(decomp.translate[2]);
1391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return BuildTranslationMatrix(decomp);
1401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)SkMatrix44 BuildRotationMatrix(const DecomposedTransform& decomp) {
1431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  double x = decomp.quaternion[0];
1441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  double y = decomp.quaternion[1];
1451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  double z = decomp.quaternion[2];
1461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  double w = decomp.quaternion[3];
1471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor);
1491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Implicitly calls matrix.setIdentity()
1511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  matrix.set3x3(1.0 - 2.0 * (y * y + z * z),
1521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                2.0 * (x * y + z * w),
1531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                2.0 * (x * z - y * w),
1541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                2.0 * (x * y - z * w),
1551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                1.0 - 2.0 * (x * x + z * z),
1561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                2.0 * (y * z + x * w),
1571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                2.0 * (x * z + y * w),
1581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                2.0 * (y * z - x * w),
1591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                1.0 - 2.0 * (x * x + y * y));
1601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return matrix;
1611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)SkMatrix44 BuildSnappedRotationMatrix(const DecomposedTransform& decomp) {
1641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Create snapped rotation.
1651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SkMatrix44 rotation_matrix = BuildRotationMatrix(decomp);
1661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  for (int i = 0; i < 3; ++i) {
1671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    for (int j = 0; j < 3; ++j) {
1681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      SkMScalar value = rotation_matrix.get(i, j);
1691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      // Snap values to -1, 0 or 1.
1701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      if (value < -0.5f) {
1711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        value = -1.0f;
1721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      } else if (value > 0.5f) {
1731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        value = 1.0f;
1741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      } else {
1751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        value = 0.0f;
1761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      }
1771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      rotation_matrix.set(i, j, value);
1781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
1791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
1801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return rotation_matrix;
1811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)SkMatrix44 BuildSkewMatrix(const DecomposedTransform& decomp) {
1841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor);
1851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SkMatrix44 temp(SkMatrix44::kIdentity_Constructor);
1871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (decomp.skew[2]) {
1881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    temp.setDouble(1, 2, decomp.skew[2]);
1891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    matrix.preConcat(temp);
1901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
1911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (decomp.skew[1]) {
1931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    temp.setDouble(1, 2, 0);
1941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    temp.setDouble(0, 2, decomp.skew[1]);
1951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    matrix.preConcat(temp);
1961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
1971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (decomp.skew[0]) {
1991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    temp.setDouble(0, 2, 0);
2001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    temp.setDouble(0, 1, decomp.skew[0]);
2011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    matrix.preConcat(temp);
2021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
2031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return matrix;
2041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)SkMatrix44 BuildScaleMatrix(const DecomposedTransform& decomp) {
2071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor);
2081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  matrix.setScale(SkDoubleToMScalar(decomp.scale[0]),
2091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                  SkDoubleToMScalar(decomp.scale[1]),
2101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                  SkDoubleToMScalar(decomp.scale[2]));
2111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return matrix;
2121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)SkMatrix44 BuildSnappedScaleMatrix(DecomposedTransform decomp) {
2151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  decomp.scale[0] = Round(decomp.scale[0]);
2161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  decomp.scale[1] = Round(decomp.scale[1]);
2171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  decomp.scale[2] = Round(decomp.scale[2]);
2181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return BuildScaleMatrix(decomp);
2191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)Transform ComposeTransform(const SkMatrix44& perspective,
2221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                           const SkMatrix44& translation,
2231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                           const SkMatrix44& rotation,
2241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                           const SkMatrix44& skew,
2251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                           const SkMatrix44& scale) {
2261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor);
2271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  matrix.preConcat(perspective);
2291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  matrix.preConcat(translation);
2301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  matrix.preConcat(rotation);
2311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  matrix.preConcat(skew);
2321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  matrix.preConcat(scale);
2331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  Transform to_return;
2351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  to_return.matrix() = matrix;
2361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return to_return;
2371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool CheckViewportPointMapsWithinOnePixel(const Point& point,
2401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                          const Transform& transform) {
2411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  Point3F point_original(point);
2421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  Point3F point_transformed(point);
2431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Can't use TransformRect here since it would give us the axis-aligned
2451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // bounding rect of the 4 points in the initial rectable which is not what we
2461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // want.
2471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  transform.TransformPoint(&point_transformed);
2481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if ((point_transformed - point_original).Length() > 1.f) {
2501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // The changed distance should not be more than 1 pixel.
2511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return false;
2521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
2531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return true;
2541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool CheckTransformsMapsIntViewportWithinOnePixel(const Rect& viewport,
2571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                                  const Transform& original,
2581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                                  const Transform& snapped) {
2591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  Transform original_inv(Transform::kSkipInitialization);
2611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  bool invertible = true;
2621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  invertible &= original.GetInverse(&original_inv);
2631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK(invertible) << "Non-invertible transform, cannot snap.";
2641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  Transform combined = snapped * original_inv;
2661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return CheckViewportPointMapsWithinOnePixel(viewport.origin(), combined) &&
2681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)         CheckViewportPointMapsWithinOnePixel(viewport.top_right(), combined) &&
2691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)         CheckViewportPointMapsWithinOnePixel(viewport.bottom_left(),
2701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                              combined) &&
2711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)         CheckViewportPointMapsWithinOnePixel(viewport.bottom_right(),
2721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                              combined);
2731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
2741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Transform GetScaleTransform(const Point& anchor, float scale) {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Transform transform;
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  transform.Translate(anchor.x() * (1 - scale),
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                      anchor.y() * (1 - scale));
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  transform.Scale(scale, scale);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return transform;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DecomposedTransform::DecomposedTransform() {
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  translate[0] = translate[1] = translate[2] = 0.0;
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scale[0] = scale[1] = scale[2] = 1.0;
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  skew[0] = skew[1] = skew[2] = 0.0;
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  perspective[0] = perspective[1] = perspective[2] = 0.0;
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  quaternion[0] = quaternion[1] = quaternion[2] = 0.0;
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  perspective[3] = quaternion[3] = 1.0;
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BlendDecomposedTransforms(DecomposedTransform* out,
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               const DecomposedTransform& to,
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               const DecomposedTransform& from,
29768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                               double progress) {
29868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  double scalea = progress;
29968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  double scaleb = 1.0 - progress;
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Combine<3>(out->translate, to.translate, from.translate, scalea, scaleb);
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Combine<3>(out->scale, to.scale, from.scale, scalea, scaleb);
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Combine<3>(out->skew, to.skew, from.skew, scalea, scaleb);
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Combine<4>(
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      out->perspective, to.perspective, from.perspective, scalea, scaleb);
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return Slerp(out->quaternion, from.quaternion, to.quaternion, progress);
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Taken from http://www.w3.org/TR/css3-transforms/.
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool DecomposeTransform(DecomposedTransform* decomp,
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        const Transform& transform) {
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!decomp)
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We'll operate on a copy of the matrix.
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SkMatrix44 matrix = transform.matrix();
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If we cannot normalize the matrix, then bail early as we cannot decompose.
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!Normalize(matrix))
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SkMatrix44 perspectiveMatrix = matrix;
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < 3; ++i)
32458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    perspectiveMatrix.set(3, i, 0.0);
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
32658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  perspectiveMatrix.set(3, 3, 1.0);
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If the perspective matrix is not invertible, we are also unable to
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // decompose, so we'll bail early. Constant taken from SkMatrix44::invert.
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (std::abs(perspectiveMatrix.determinant()) < 1e-8)
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
33358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (matrix.get(3, 0) != 0.0 || matrix.get(3, 1) != 0.0 ||
33458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      matrix.get(3, 2) != 0.0) {
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // rhs is the right hand side of the equation.
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SkMScalar rhs[4] = {
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      matrix.get(3, 0),
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      matrix.get(3, 1),
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      matrix.get(3, 2),
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      matrix.get(3, 3)
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    };
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Solve the equation by inverting perspectiveMatrix and multiplying
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // rhs by the inverse.
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SkMatrix44 inversePerspectiveMatrix(SkMatrix44::kUninitialized_Constructor);
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!perspectiveMatrix.invert(&inversePerspectiveMatrix))
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SkMatrix44 transposedInversePerspectiveMatrix =
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        inversePerspectiveMatrix;
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    transposedInversePerspectiveMatrix.transpose();
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    transposedInversePerspectiveMatrix.mapMScalars(rhs);
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < 4; ++i)
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      decomp->perspective[i] = rhs[i];
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // No perspective.
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < 3; ++i)
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      decomp->perspective[i] = 0.0;
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    decomp->perspective[3] = 1.0;
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < 3; i++)
36658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    decomp->translate[i] = matrix.get(i, 3);
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
36858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  SkMScalar row[3][3];
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < 3; i++)
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int j = 0; j < 3; ++j)
37158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      row[i][j] = matrix.get(j, i);
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Compute X scale factor and normalize first row.
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  decomp->scale[0] = Length3(row[0]);
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (decomp->scale[0] != 0.0)
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Scale3(row[0], 1.0 / decomp->scale[0]);
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Compute XY shear factor and make 2nd row orthogonal to 1st.
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  decomp->skew[0] = Dot<3>(row[0], row[1]);
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Combine<3>(row[1], row[1], row[0], 1.0, -decomp->skew[0]);
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Now, compute Y scale and normalize 2nd row.
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  decomp->scale[1] = Length3(row[1]);
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (decomp->scale[1] != 0.0)
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Scale3(row[1], 1.0 / decomp->scale[1]);
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  decomp->skew[0] /= decomp->scale[1];
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Compute XZ and YZ shears, orthogonalize 3rd row
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  decomp->skew[1] = Dot<3>(row[0], row[2]);
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Combine<3>(row[2], row[2], row[0], 1.0, -decomp->skew[1]);
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  decomp->skew[2] = Dot<3>(row[1], row[2]);
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Combine<3>(row[2], row[2], row[1], 1.0, -decomp->skew[2]);
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Next, get Z scale and normalize 3rd row.
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  decomp->scale[2] = Length3(row[2]);
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (decomp->scale[2] != 0.0)
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Scale3(row[2], 1.0 / decomp->scale[2]);
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  decomp->skew[1] /= decomp->scale[2];
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  decomp->skew[2] /= decomp->scale[2];
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // At this point, the matrix (in rows) is orthonormal.
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check for a coordinate system flip.  If the determinant
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // is -1, then negate the matrix and the scaling factors.
40658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  SkMScalar pdum3[3];
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Cross3(pdum3, row[1], row[2]);
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (Dot<3>(row[0], pdum3) < 0) {
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int i = 0; i < 3; i++) {
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      decomp->scale[i] *= -1.0;
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (int j = 0; j < 3; ++j)
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        row[i][j] *= -1.0;
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  decomp->quaternion[0] =
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      0.5 * std::sqrt(std::max(1.0 + row[0][0] - row[1][1] - row[2][2], 0.0));
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  decomp->quaternion[1] =
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      0.5 * std::sqrt(std::max(1.0 - row[0][0] + row[1][1] - row[2][2], 0.0));
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  decomp->quaternion[2] =
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      0.5 * std::sqrt(std::max(1.0 - row[0][0] - row[1][1] + row[2][2], 0.0));
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  decomp->quaternion[3] =
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      0.5 * std::sqrt(std::max(1.0 + row[0][0] + row[1][1] + row[2][2], 0.0));
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (row[2][1] > row[1][2])
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      decomp->quaternion[0] = -decomp->quaternion[0];
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (row[0][2] > row[2][0])
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      decomp->quaternion[1] = -decomp->quaternion[1];
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (row[1][0] > row[0][1])
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      decomp->quaternion[2] = -decomp->quaternion[2];
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Taken from http://www.w3.org/TR/css3-transforms/.
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Transform ComposeTransform(const DecomposedTransform& decomp) {
4371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SkMatrix44 perspective = BuildPerspectiveMatrix(decomp);
4381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SkMatrix44 translation = BuildTranslationMatrix(decomp);
4391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SkMatrix44 rotation = BuildRotationMatrix(decomp);
4401e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SkMatrix44 skew = BuildSkewMatrix(decomp);
4411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SkMatrix44 scale = BuildScaleMatrix(decomp);
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return ComposeTransform(perspective, translation, rotation, skew, scale);
4441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool SnapTransform(Transform* out,
4471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                   const Transform& transform,
4481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                   const Rect& viewport) {
4491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DecomposedTransform decomp;
4501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DecomposeTransform(&decomp, transform);
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SkMatrix44 rotation_matrix = BuildSnappedRotationMatrix(decomp);
4531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SkMatrix44 translation = BuildSnappedTranslationMatrix(decomp);
4541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SkMatrix44 scale = BuildSnappedScaleMatrix(decomp);
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Rebuild matrices for other unchanged components.
4571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SkMatrix44 perspective = BuildPerspectiveMatrix(decomp);
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Completely ignore the skew.
4601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  SkMatrix44 skew(SkMatrix44::kIdentity_Constructor);
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Get full tranform
4631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  Transform snapped =
4641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      ComposeTransform(perspective, translation, rotation_matrix, skew, scale);
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Verify that viewport is not moved unnaturally.
4671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  bool snappable =
4681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    CheckTransformsMapsIntViewportWithinOnePixel(viewport, transform, snapped);
4691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (snappable) {
4701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    *out = snapped;
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return snappable;
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
47568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)std::string DecomposedTransform::ToString() const {
47668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return base::StringPrintf(
47768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "translate: %+0.4f %+0.4f %+0.4f\n"
47868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "scale: %+0.4f %+0.4f %+0.4f\n"
47968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "skew: %+0.4f %+0.4f %+0.4f\n"
48068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "perspective: %+0.4f %+0.4f %+0.4f %+0.4f\n"
48168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      "quaternion: %+0.4f %+0.4f %+0.4f %+0.4f\n",
48268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      translate[0],
48368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      translate[1],
48468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      translate[2],
48568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      scale[0],
48668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      scale[1],
48768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      scale[2],
48868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      skew[0],
48968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      skew[1],
49068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      skew[2],
49168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      perspective[0],
49268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      perspective[1],
49368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      perspective[2],
49468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      perspective[3],
49568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      quaternion[0],
49668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      quaternion[1],
49768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      quaternion[2],
49868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      quaternion[3]);
49968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
50068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace ui
502