Modified: trunk/Source/WebCore/platform/chromium/support/WebTransformOperations.cpp (126837 => 126838)
--- trunk/Source/WebCore/platform/chromium/support/WebTransformOperations.cpp 2012-08-28 02:39:27 UTC (rev 126837)
+++ trunk/Source/WebCore/platform/chromium/support/WebTransformOperations.cpp 2012-08-28 03:39:01 UTC (rev 126838)
@@ -26,8 +26,15 @@
#include <public/WebTransformOperations.h>
+#include <algorithm>
#include <wtf/Vector.h>
+using namespace std;
+
+namespace {
+const double EPSILON = 1e-4;
+}
+
namespace WebKit {
struct WebTransformOperation {
@@ -37,11 +44,43 @@
WebTransformOperationScale,
WebTransformOperationSkew,
WebTransformOperationPerspective,
- WebTransformOperationMatrix
+ WebTransformOperationMatrix,
+ WebTransformOperationIdentity
};
+ WebTransformOperation()
+ : type(WebTransformOperationIdentity)
+ {
+ }
+
Type type;
WebTransformationMatrix matrix;
+
+ union {
+ double perspectiveDepth;
+
+ struct {
+ double x, y;
+ } skew;
+
+ struct {
+ double x, y, z;
+ } scale;
+
+ struct {
+ double x, y, z;
+ } translate;
+
+ struct {
+ struct {
+ double x, y, z;
+ } axis;
+
+ double angle;
+ } rotate;
+ };
+
+ bool isIdentity() const { return matrix.isIdentity(); }
};
class WebTransformOperationsPrivate {
@@ -57,13 +96,165 @@
return toReturn;
}
+static bool isIdentity(const WebTransformOperation* operation)
+{
+ return !operation || operation->isIdentity();
+}
+
+static bool shareSameAxis(const WebTransformOperation* from, const WebTransformOperation* to, double& axisX, double& axisY, double& axisZ, double& angleFrom)
+{
+ if (isIdentity(from) && isIdentity(to))
+ return false;
+
+ if (isIdentity(from) && !isIdentity(to)) {
+ axisX = to->rotate.axis.x;
+ axisY = to->rotate.axis.y;
+ axisZ = to->rotate.axis.z;
+ angleFrom = 0;
+ return true;
+ }
+
+ if (!isIdentity(from) && isIdentity(to)) {
+ axisX = from->rotate.axis.x;
+ axisY = from->rotate.axis.y;
+ axisZ = from->rotate.axis.z;
+ angleFrom = from->rotate.angle;
+ return true;
+ }
+
+ double length2 = from->rotate.axis.x * from->rotate.axis.x + from->rotate.axis.y * from->rotate.axis.y + from->rotate.axis.z * from->rotate.axis.z;
+ double otherLength2 = to->rotate.axis.x * to->rotate.axis.x + to->rotate.axis.y * to->rotate.axis.y + to->rotate.axis.z * to->rotate.axis.z;
+
+ if (length2 <= EPSILON || otherLength2 <= EPSILON)
+ return false;
+
+ double dot = to->rotate.axis.x * from->rotate.axis.x + to->rotate.axis.y * from->rotate.axis.y + to->rotate.axis.z * from->rotate.axis.z;
+ double error = fabs(1.0 - (dot * dot) / (length2 * otherLength2));
+ bool result = error < EPSILON;
+ if (result) {
+ axisX = to->rotate.axis.x;
+ axisY = to->rotate.axis.y;
+ axisZ = to->rotate.axis.z;
+ // If the axes are pointing in opposite directions, we need to reverse
+ // the angle.
+ angleFrom = dot > 0 ? from->rotate.angle : -from->rotate.angle;
+ }
+ return result;
+}
+
+static double blendDoubles(double from, double to, double progress)
+{
+ return from * (1 - progress) + to * progress;
+}
+
+static WebTransformationMatrix blendTransformOperations(const WebTransformOperation* from, const WebTransformOperation* to, double progress)
+{
+ WebTransformationMatrix toReturn;
+
+ if (isIdentity(from) && isIdentity(to))
+ return toReturn;
+
+ WebTransformOperation::Type interpolationType = WebTransformOperation::WebTransformOperationIdentity;
+ if (isIdentity(to))
+ interpolationType = from->type;
+ else
+ interpolationType = to->type;
+
+ switch (interpolationType) {
+ case WebTransformOperation::WebTransformOperationTranslate: {
+ double fromX = isIdentity(from) ? 0 : from->translate.x;
+ double fromY = isIdentity(from) ? 0 : from->translate.y;
+ double fromZ = isIdentity(from) ? 0 : from->translate.z;
+ double toX = isIdentity(to) ? 0 : to->translate.x;
+ double toY = isIdentity(to) ? 0 : to->translate.y;
+ double toZ = isIdentity(to) ? 0 : to->translate.z;
+ toReturn.translate3d(blendDoubles(fromX, toX, progress),
+ blendDoubles(fromY, toY, progress),
+ blendDoubles(fromZ, toZ, progress));
+ break;
+ }
+ case WebTransformOperation::WebTransformOperationRotate: {
+ double axisX = 0;
+ double axisY = 0;
+ double axisZ = 1;
+ double fromAngle = 0;
+ double toAngle = isIdentity(to) ? 0 : to->rotate.angle;
+ if (shareSameAxis(from, to, axisX, axisY, axisZ, fromAngle))
+ toReturn.rotate3d(axisX, axisY, axisZ, blendDoubles(fromAngle, toAngle, progress));
+ else {
+ WebTransformationMatrix toMatrix;
+ if (!isIdentity(to))
+ toMatrix = to->matrix;
+ WebTransformationMatrix fromMatrix;
+ if (!isIdentity(from))
+ fromMatrix = from->matrix;
+ toReturn = toMatrix;
+ toReturn.blend(fromMatrix, progress);
+ }
+ break;
+ }
+ case WebTransformOperation::WebTransformOperationScale: {
+ double fromX = isIdentity(from) ? 1 : from->scale.x;
+ double fromY = isIdentity(from) ? 1 : from->scale.y;
+ double fromZ = isIdentity(from) ? 1 : from->scale.z;
+ double toX = isIdentity(to) ? 1 : to->scale.x;
+ double toY = isIdentity(to) ? 1 : to->scale.y;
+ double toZ = isIdentity(to) ? 1 : to->scale.z;
+ toReturn.scale3d(blendDoubles(fromX, toX, progress),
+ blendDoubles(fromY, toY, progress),
+ blendDoubles(fromZ, toZ, progress));
+ break;
+ }
+ case WebTransformOperation::WebTransformOperationSkew: {
+ double fromX = isIdentity(from) ? 0 : from->skew.x;
+ double fromY = isIdentity(from) ? 0 : from->skew.y;
+ double toX = isIdentity(to) ? 0 : to->skew.x;
+ double toY = isIdentity(to) ? 0 : to->skew.y;
+ toReturn.skewX(blendDoubles(fromX, toX, progress));
+ toReturn.skewY(blendDoubles(fromY, toY, progress));
+ break;
+ }
+ case WebTransformOperation::WebTransformOperationPerspective: {
+ double fromPerspectiveDepth = isIdentity(from) ? numeric_limits<double>::max() : from->perspectiveDepth;
+ double toPerspectiveDepth = isIdentity(to) ? numeric_limits<double>::max() : to->perspectiveDepth;
+ toReturn.applyPerspective(blendDoubles(fromPerspectiveDepth, toPerspectiveDepth, progress));
+ break;
+ }
+ case WebTransformOperation::WebTransformOperationMatrix: {
+ WebTransformationMatrix toMatrix;
+ if (!isIdentity(to))
+ toMatrix = to->matrix;
+ WebTransformationMatrix fromMatrix;
+ if (!isIdentity(from))
+ fromMatrix = from->matrix;
+ toReturn = toMatrix;
+ toReturn.blend(fromMatrix, progress);
+ break;
+ }
+ case WebTransformOperation::WebTransformOperationIdentity:
+ // Do nothing.
+ break;
+ }
+
+ return toReturn;
+}
+
WebTransformationMatrix WebTransformOperations::blend(const WebTransformOperations& from, double progress) const
{
WebTransformationMatrix toReturn;
+ bool fromIdentity = from.isIdentity();
+ bool toIdentity = isIdentity();
+ if (fromIdentity && toIdentity)
+ return toReturn;
+
if (matchesTypes(from)) {
- for (size_t i = 0; i < m_private->operations.size(); ++i) {
- WebTransformationMatrix blended = m_private->operations[i].matrix;
- blended.blend(from.m_private->operations[i].matrix, progress);
+ size_t numOperations = max(fromIdentity ? 0 : from.m_private->operations.size(),
+ toIdentity ? 0 : m_private->operations.size());
+ for (size_t i = 0; i < numOperations; ++i) {
+ WebTransformationMatrix blended = blendTransformOperations(
+ fromIdentity ? 0 : &from.m_private->operations[i],
+ toIdentity ? 0 : &m_private->operations[i],
+ progress);
toReturn.multiply(blended);
}
} else {
@@ -76,11 +267,16 @@
bool WebTransformOperations::matchesTypes(const WebTransformOperations& other) const
{
+ if (isIdentity() || other.isIdentity())
+ return true;
+
if (m_private->operations.size() != other.m_private->operations.size())
return false;
for (size_t i = 0; i < m_private->operations.size(); ++i) {
- if (m_private->operations[i].type != other.m_private->operations[i].type)
+ if (m_private->operations[i].type != other.m_private->operations[i].type
+ && !m_private->operations[i].isIdentity()
+ && !other.m_private->operations[i].isIdentity())
return false;
}
@@ -92,6 +288,9 @@
WebTransformOperation toAdd;
toAdd.matrix.translate3d(x, y, z);
toAdd.type = WebTransformOperation::WebTransformOperationTranslate;
+ toAdd.translate.x = x;
+ toAdd.translate.y = y;
+ toAdd.translate.z = z;
m_private->operations.append(toAdd);
}
@@ -100,6 +299,10 @@
WebTransformOperation toAdd;
toAdd.matrix.rotate3d(x, y, z, degrees);
toAdd.type = WebTransformOperation::WebTransformOperationRotate;
+ toAdd.rotate.axis.x = x;
+ toAdd.rotate.axis.y = y;
+ toAdd.rotate.axis.z = z;
+ toAdd.rotate.angle = degrees;
m_private->operations.append(toAdd);
}
@@ -108,6 +311,9 @@
WebTransformOperation toAdd;
toAdd.matrix.scale3d(x, y, z);
toAdd.type = WebTransformOperation::WebTransformOperationScale;
+ toAdd.scale.x = x;
+ toAdd.scale.y = y;
+ toAdd.scale.z = z;
m_private->operations.append(toAdd);
}
@@ -117,6 +323,8 @@
toAdd.matrix.skewX(x);
toAdd.matrix.skewY(y);
toAdd.type = WebTransformOperation::WebTransformOperationSkew;
+ toAdd.skew.x = x;
+ toAdd.skew.y = y;
m_private->operations.append(toAdd);
}
@@ -125,6 +333,7 @@
WebTransformOperation toAdd;
toAdd.matrix.applyPerspective(depth);
toAdd.type = WebTransformOperation::WebTransformOperationPerspective;
+ toAdd.perspectiveDepth = depth;
m_private->operations.append(toAdd);
}
@@ -136,6 +345,20 @@
m_private->operations.append(toAdd);
}
+void WebTransformOperations::appendIdentity()
+{
+ m_private->operations.append(WebTransformOperation());
+}
+
+bool WebTransformOperations::isIdentity() const
+{
+ for (size_t i = 0; i < m_private->operations.size(); ++i) {
+ if (!m_private->operations[i].isIdentity())
+ return false;
+ }
+ return true;
+}
+
void WebTransformOperations::reset()
{
m_private.reset(0);
Modified: trunk/Source/WebCore/platform/graphics/chromium/AnimationTranslationUtil.cpp (126837 => 126838)
--- trunk/Source/WebCore/platform/graphics/chromium/AnimationTranslationUtil.cpp 2012-08-28 02:39:27 UTC (rev 126837)
+++ trunk/Source/WebCore/platform/graphics/chromium/AnimationTranslationUtil.cpp 2012-08-28 03:39:01 UTC (rev 126838)
@@ -113,6 +113,8 @@
break;
}
case TransformOperation::IDENTITY:
+ webTransformOperations.appendIdentity();
+ break;
case TransformOperation::NONE:
// Do nothing.
break;
@@ -145,51 +147,9 @@
|| transformType == TransformOperation::ROTATE_3D;
}
-bool causesRotationOfAtLeast180Degrees(const TransformAnimationValue* value, const TransformAnimationValue* lastValue)
-{
- if (!lastValue)
- return false;
-
- const TransformOperations& operations = *value->value();
- const TransformOperations& lastOperations = *lastValue->value();
-
- // We'll be doing matrix interpolation in this case. No risk of incorrect rotations here.
- if (operations.size() && lastOperations.size() && !operations.operationsMatch(lastOperations))
- return false;
-
- size_t numOperations = max(operations.size(), lastOperations.size());
- for (size_t i = 0; i < numOperations; ++i) {
- float angle = 0;
- if (i < operations.size()) {
- if (!isRotationType(operations.operations()[i]->getOperationType()))
- continue;
-
- RotateTransformOperation* rotation = static_cast<RotateTransformOperation*>(operations.operations()[i].get());
- angle = rotation->angle();
- }
-
- float lastAngle = 0;
- if (i < lastOperations.size()) {
- if (!isRotationType(lastOperations.operations()[i]->getOperationType()))
- continue;
-
- RotateTransformOperation* lastRotation = static_cast<RotateTransformOperation*>(lastOperations.operations()[i].get());
- lastAngle = lastRotation->angle();
- }
-
- if (fabs(angle - lastAngle) >= 180)
- return true;
- }
-
- return false;
-}
-
template <>
bool appendKeyframeWithStandardTimingFunction<TransformAnimationValue, WebTransformKeyframe, WebTransformAnimationCurve>(WebTransformAnimationCurve* curve, double keyTime, const TransformAnimationValue* value, const TransformAnimationValue* lastValue, WebKit::WebAnimationCurve::TimingFunctionType timingFunctionType, const FloatSize& boxSize)
{
- if (causesRotationOfAtLeast180Degrees(value, lastValue))
- return false;
-
WebTransformOperations operations = toWebTransformOperations(*value->value(), boxSize);
if (operations.apply().isInvertible()) {
curve->add(WebTransformKeyframe(keyTime, operations), timingFunctionType);
@@ -201,9 +161,6 @@
template <>
bool appendKeyframeWithCustomBezierTimingFunction<TransformAnimationValue, WebTransformKeyframe, WebTransformAnimationCurve>(WebTransformAnimationCurve* curve, double keyTime, const TransformAnimationValue* value, const TransformAnimationValue* lastValue, double x1, double y1, double x2, double y2, const FloatSize& boxSize)
{
- if (causesRotationOfAtLeast180Degrees(value, lastValue))
- return false;
-
WebTransformOperations operations = toWebTransformOperations(*value->value(), boxSize);
if (operations.apply().isInvertible()) {
curve->add(WebTransformKeyframe(keyTime, operations), x1, y1, x2, y2);
Modified: trunk/Source/WebKit/chromium/tests/WebTransformOperationsTest.cpp (126837 => 126838)
--- trunk/Source/WebKit/chromium/tests/WebTransformOperationsTest.cpp 2012-08-28 02:39:27 UTC (rev 126837)
+++ trunk/Source/WebKit/chromium/tests/WebTransformOperationsTest.cpp 2012-08-28 03:39:01 UTC (rev 126838)
@@ -35,6 +35,7 @@
#include <wtf/PassOwnPtr.h>
#include <wtf/Vector.h>
+using namespace std;
using namespace WebKit;
TEST(WebTransformOperationTest, transformTypesAreUnique)
@@ -42,19 +43,19 @@
Vector<OwnPtr<WebTransformOperations> > transforms;
WebTransformOperations* toAdd = new WebTransformOperations();
- toAdd->appendTranslate(0, 0, 0);
+ toAdd->appendTranslate(1, 0, 0);
transforms.append(adoptPtr(toAdd));
toAdd = new WebTransformOperations();
- toAdd->appendRotate(0, 0, 1, 0);
+ toAdd->appendRotate(0, 0, 1, 2);
transforms.append(adoptPtr(toAdd));
toAdd = new WebTransformOperations();
- toAdd->appendScale(1, 1, 1);
+ toAdd->appendScale(2, 2, 2);
transforms.append(adoptPtr(toAdd));
toAdd = new WebTransformOperations();
- toAdd->appendSkew(0, 0);
+ toAdd->appendSkew(1, 0);
transforms.append(adoptPtr(toAdd));
toAdd = new WebTransformOperations();
@@ -72,19 +73,19 @@
TEST(WebTransformOperationTest, matchTypesSameLength)
{
WebTransformOperations translates;
- translates.appendTranslate(0, 0, 0);
- translates.appendTranslate(0, 0, 0);
- translates.appendTranslate(0, 0, 0);
+ translates.appendTranslate(1, 0, 0);
+ translates.appendTranslate(1, 0, 0);
+ translates.appendTranslate(1, 0, 0);
WebTransformOperations skews;
- skews.appendSkew(0, 0);
- skews.appendSkew(0, 0);
- skews.appendSkew(0, 0);
+ skews.appendSkew(0, 2);
+ skews.appendSkew(0, 2);
+ skews.appendSkew(0, 2);
WebTransformOperations translates2;
- translates2.appendTranslate(0, 0, 0);
- translates2.appendTranslate(0, 0, 0);
- translates2.appendTranslate(0, 0, 0);
+ translates2.appendTranslate(0, 2, 0);
+ translates2.appendTranslate(0, 2, 0);
+ translates2.appendTranslate(0, 2, 0);
WebTransformOperations translates3 = translates2;
@@ -96,22 +97,84 @@
TEST(WebTransformOperationTest, matchTypesDifferentLength)
{
WebTransformOperations translates;
- translates.appendTranslate(0, 0, 0);
- translates.appendTranslate(0, 0, 0);
- translates.appendTranslate(0, 0, 0);
+ translates.appendTranslate(1, 0, 0);
+ translates.appendTranslate(1, 0, 0);
+ translates.appendTranslate(1, 0, 0);
WebTransformOperations skews;
- skews.appendSkew(0, 0);
- skews.appendSkew(0, 0);
+ skews.appendSkew(2, 0);
+ skews.appendSkew(2, 0);
WebTransformOperations translates2;
- translates2.appendTranslate(0, 0, 0);
- translates2.appendTranslate(0, 0, 0);
+ translates2.appendTranslate(0, 2, 0);
+ translates2.appendTranslate(0, 2, 0);
EXPECT_FALSE(translates.matchesTypes(skews));
EXPECT_FALSE(translates.matchesTypes(translates2));
}
+void getIdentityOperations(Vector<OwnPtr<WebTransformOperations> >* operations)
+{
+ WebTransformOperations* toAdd = new WebTransformOperations();
+ operations->append(adoptPtr(toAdd));
+
+ toAdd = new WebTransformOperations();
+ toAdd->appendTranslate(0, 0, 0);
+ operations->append(adoptPtr(toAdd));
+
+ toAdd = new WebTransformOperations();
+ toAdd->appendTranslate(0, 0, 0);
+ toAdd->appendTranslate(0, 0, 0);
+ operations->append(adoptPtr(toAdd));
+
+ toAdd = new WebTransformOperations();
+ toAdd->appendScale(1, 1, 1);
+ operations->append(adoptPtr(toAdd));
+
+ toAdd = new WebTransformOperations();
+ toAdd->appendScale(1, 1, 1);
+ toAdd->appendScale(1, 1, 1);
+ operations->append(adoptPtr(toAdd));
+
+ toAdd = new WebTransformOperations();
+ toAdd->appendSkew(0, 0);
+ operations->append(adoptPtr(toAdd));
+
+ toAdd = new WebTransformOperations();
+ toAdd->appendSkew(0, 0);
+ toAdd->appendSkew(0, 0);
+ operations->append(adoptPtr(toAdd));
+
+ toAdd = new WebTransformOperations();
+ toAdd->appendRotate(0, 0, 1, 0);
+ operations->append(adoptPtr(toAdd));
+
+ toAdd = new WebTransformOperations();
+ toAdd->appendRotate(0, 0, 1, 0);
+ toAdd->appendRotate(0, 0, 1, 0);
+ operations->append(adoptPtr(toAdd));
+
+ toAdd = new WebTransformOperations();
+ toAdd->appendMatrix(WebTransformationMatrix());
+ operations->append(adoptPtr(toAdd));
+
+ toAdd = new WebTransformOperations();
+ toAdd->appendMatrix(WebTransformationMatrix());
+ toAdd->appendMatrix(WebTransformationMatrix());
+ operations->append(adoptPtr(toAdd));
+}
+
+TEST(WebTransformOperationTest, identityAlwaysMatches)
+{
+ Vector<OwnPtr<WebTransformOperations> > operations;
+ getIdentityOperations(&operations);
+
+ for (size_t i = 0; i < operations.size(); ++i) {
+ for (size_t j = 0; j < operations.size(); ++j)
+ EXPECT_TRUE(operations[i]->matchesTypes(*operations[j]));
+ }
+}
+
TEST(WebTransformOperationTest, applyTranslate)
{
double x = 1;
@@ -339,3 +402,238 @@
EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operationsTo.blend(operationsFrom, progress));
}
+
+TEST(WebTransformOperationTest, largeRotationsWithSameAxis)
+{
+ WebTransformOperations operationsFrom;
+ operationsFrom.appendRotate(0, 0, 1, 0);
+
+ WebTransformOperations operationsTo;
+ operationsTo.appendRotate(0, 0, 2, 360);
+
+ double progress = 0.5;
+
+ WebTransformationMatrix expected;
+ expected.rotate3d(0, 0, 1, 180);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operationsTo.blend(operationsFrom, progress));
+}
+
+TEST(WebTransformOperationTest, largeRotationsWithSameAxisInDifferentDirection)
+{
+ WebTransformOperations operationsFrom;
+ operationsFrom.appendRotate(0, 0, 1, 180);
+
+ WebTransformOperations operationsTo;
+ operationsTo.appendRotate(0, 0, -1, 180);
+
+ double progress = 0.5;
+
+ WebTransformationMatrix expected;
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operationsTo.blend(operationsFrom, progress));
+}
+
+TEST(WebTransformOperationTest, largeRotationsWithDifferentAxes)
+{
+ WebTransformOperations operationsFrom;
+ operationsFrom.appendRotate(0, 0, 1, 180);
+
+ WebTransformOperations operationsTo;
+ operationsTo.appendRotate(0, 1, 0, 180);
+
+ double progress = 0.5;
+ WebTransformationMatrix matrixFrom;
+ matrixFrom.rotate3d(0, 0, 1, 180);
+
+ WebTransformationMatrix matrixTo;
+ matrixTo.rotate3d(0, 1, 0, 180);
+
+ WebTransformationMatrix expected = matrixTo;
+ expected.blend(matrixFrom, progress);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operationsTo.blend(operationsFrom, progress));
+}
+
+TEST(WebTransformOperationTest, blendRotationFromIdentity)
+{
+ Vector<OwnPtr<WebTransformOperations> > identityOperations;
+ getIdentityOperations(&identityOperations);
+
+ for (size_t i = 0; i < identityOperations.size(); ++i) {
+ WebTransformOperations operations;
+ operations.appendRotate(0, 0, 1, 360);
+
+ double progress = 0.5;
+
+ WebTransformationMatrix expected;
+ expected.rotate3d(0, 0, 1, 180);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.blend(*identityOperations[i], progress));
+ }
+}
+
+TEST(WebTransformOperationTest, blendTranslationFromIdentity)
+{
+ Vector<OwnPtr<WebTransformOperations> > identityOperations;
+ getIdentityOperations(&identityOperations);
+
+ for (size_t i = 0; i < identityOperations.size(); ++i) {
+ WebTransformOperations operations;
+ operations.appendTranslate(2, 2, 2);
+
+ double progress = 0.5;
+
+ WebTransformationMatrix expected;
+ expected.translate3d(1, 1, 1);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.blend(*identityOperations[i], progress));
+ }
+}
+
+TEST(WebTransformOperationTest, blendScaleFromIdentity)
+{
+ Vector<OwnPtr<WebTransformOperations> > identityOperations;
+ getIdentityOperations(&identityOperations);
+
+ for (size_t i = 0; i < identityOperations.size(); ++i) {
+ WebTransformOperations operations;
+ operations.appendScale(3, 3, 3);
+
+ double progress = 0.5;
+
+ WebTransformationMatrix expected;
+ expected.scale3d(2, 2, 2);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.blend(*identityOperations[i], progress));
+ }
+}
+
+TEST(WebTransformOperationTest, blendSkewFromIdentity)
+{
+ Vector<OwnPtr<WebTransformOperations> > identityOperations;
+ getIdentityOperations(&identityOperations);
+
+ for (size_t i = 0; i < identityOperations.size(); ++i) {
+ WebTransformOperations operations;
+ operations.appendSkew(2, 2);
+
+ double progress = 0.5;
+
+ WebTransformationMatrix expected;
+ expected.skewX(1);
+ expected.skewY(1);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.blend(*identityOperations[i], progress));
+ }
+}
+
+TEST(WebTransformOperationTest, blendPerspectiveFromIdentity)
+{
+ Vector<OwnPtr<WebTransformOperations> > identityOperations;
+ getIdentityOperations(&identityOperations);
+
+ for (size_t i = 0; i < identityOperations.size(); ++i) {
+ WebTransformOperations operations;
+ operations.appendPerspective(1000);
+
+ double progress = 0.5;
+
+ WebTransformationMatrix expected;
+ expected.applyPerspective(500 + 0.5 * numeric_limits<double>::max());
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.blend(*identityOperations[i], progress));
+ }
+}
+
+TEST(WebTransformOperationTest, blendRotationToIdentity)
+{
+ Vector<OwnPtr<WebTransformOperations> > identityOperations;
+ getIdentityOperations(&identityOperations);
+
+ for (size_t i = 0; i < identityOperations.size(); ++i) {
+ WebTransformOperations operations;
+ operations.appendRotate(0, 0, 1, 360);
+
+ double progress = 0.5;
+
+ WebTransformationMatrix expected;
+ expected.rotate3d(0, 0, 1, 180);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, identityOperations[i]->blend(operations, progress));
+ }
+}
+
+TEST(WebTransformOperationTest, blendTranslationToIdentity)
+{
+ Vector<OwnPtr<WebTransformOperations> > identityOperations;
+ getIdentityOperations(&identityOperations);
+
+ for (size_t i = 0; i < identityOperations.size(); ++i) {
+ WebTransformOperations operations;
+ operations.appendTranslate(2, 2, 2);
+
+ double progress = 0.5;
+
+ WebTransformationMatrix expected;
+ expected.translate3d(1, 1, 1);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, identityOperations[i]->blend(operations, progress));
+ }
+}
+
+TEST(WebTransformOperationTest, blendScaleToIdentity)
+{
+ Vector<OwnPtr<WebTransformOperations> > identityOperations;
+ getIdentityOperations(&identityOperations);
+
+ for (size_t i = 0; i < identityOperations.size(); ++i) {
+ WebTransformOperations operations;
+ operations.appendScale(3, 3, 3);
+
+ double progress = 0.5;
+
+ WebTransformationMatrix expected;
+ expected.scale3d(2, 2, 2);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, identityOperations[i]->blend(operations, progress));
+ }
+}
+
+TEST(WebTransformOperationTest, blendSkewToIdentity)
+{
+ Vector<OwnPtr<WebTransformOperations> > identityOperations;
+ getIdentityOperations(&identityOperations);
+
+ for (size_t i = 0; i < identityOperations.size(); ++i) {
+ WebTransformOperations operations;
+ operations.appendSkew(2, 2);
+
+ double progress = 0.5;
+
+ WebTransformationMatrix expected;
+ expected.skewX(1);
+ expected.skewY(1);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, identityOperations[i]->blend(operations, progress));
+ }
+}
+
+TEST(WebTransformOperationTest, blendPerspectiveToIdentity)
+{
+ Vector<OwnPtr<WebTransformOperations> > identityOperations;
+ getIdentityOperations(&identityOperations);
+
+ for (size_t i = 0; i < identityOperations.size(); ++i) {
+ WebTransformOperations operations;
+ operations.appendPerspective(1000);
+
+ double progress = 0.5;
+
+ WebTransformationMatrix expected;
+ expected.applyPerspective(500 + 0.5 * numeric_limits<double>::max());
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, identityOperations[i]->blend(operations, progress));
+ }
+}
+