Ensure that Slerp returns a non-inf for opposing vectors.

In the case where the given vectors are opposite of each other, we
get a 0 denominator which causes inf/nan values which later down
the pipeline can result in CHECKs since the layer transform would have
nans as well.

R=vollick
BUG=506543

Review URL: https://codereview.chromium.org/1217773011

Cr-Commit-Position: refs/heads/master@{#337881}
diff --git a/ui/gfx/transform_util.cc b/ui/gfx/transform_util.cc
index 3eab6e2..33c5508 100644
--- a/ui/gfx/transform_util.cc
+++ b/ui/gfx/transform_util.cc
@@ -73,6 +73,18 @@
     return true;
   }
 
+  // TODO(vmpstr): In case the product is -1, the vectors are exactly opposite
+  // of each other. In this case, it's technically not correct to just pick one
+  // of the vectors, we instead need to pick how to interpolate. However, the
+  // spec isn't clear on this. If we don't handle the -1 case explicitly, it
+  // results in inf and nans however, which is worse. See crbug.com/506543 for
+  // more discussion.
+  if (std::abs(product + 1.0) < epsilon) {
+    for (int i = 0; i < 4; ++i)
+      out[i] = q1[i];
+    return true;
+  }
+
   double denom = std::sqrt(1.0 - product * product);
   double theta = std::acos(product);
   double w = std::sin(progress * theta) * (1.0 / denom);
diff --git a/ui/gfx/transform_util_unittest.cc b/ui/gfx/transform_util_unittest.cc
index 404833c..02bf46a4 100644
--- a/ui/gfx/transform_util_unittest.cc
+++ b/ui/gfx/transform_util_unittest.cc
@@ -192,5 +192,18 @@
   EXPECT_EQ(Point(-11, -20).ToString(), point.ToString());
 }
 
+TEST(TransformUtilTest, BlendOppositeQuaternions) {
+  DecomposedTransform first;
+  DecomposedTransform second;
+  second.quaternion[3] = -second.quaternion[3];
+
+  DecomposedTransform result;
+  BlendDecomposedTransforms(&result, first, second, 0.25);
+  for (size_t i = 0; i < 4; ++i) {
+    EXPECT_TRUE(std::isfinite(result.quaternion[i]));
+    EXPECT_FALSE(std::isnan(result.quaternion[i]));
+  }
+}
+
 }  // namespace
 }  // namespace gfx