[chromium] Implement keyframed animations for the cc thread.
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Feb 2012 05:31:12 +0000 (05:31 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Feb 2012 05:31:12 +0000 (05:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=77229

Patch by Ian Vollick <vollick@chromium.org> on 2012-02-23
Reviewed by James Robinson.

Source/WebCore:

* WebCore.gypi:
* platform/graphics/chromium/LayerChromium.cpp:
(WebCore::LayerChromium::hasActiveAnimation):
(WebCore):
* platform/graphics/chromium/LayerChromium.h:
(LayerChromium):
* platform/graphics/chromium/cc/CCActiveAnimation.cpp:
(WebCore::CCActiveAnimation::CCActiveAnimation):
(WebCore::CCActiveAnimation::isFinishedAt):
(WebCore::CCActiveAnimation::trimTimeToCurrentIteration):
(WebCore::CCActiveAnimation::cloneForImplThread):
* platform/graphics/chromium/cc/CCActiveAnimation.h:
(WebCore::CCActiveAnimation::curve):
(CCActiveAnimation):
* platform/graphics/chromium/cc/CCKeyframedAnimationCurve.cpp: Added.
(WebCore::CCKeyframedFloatAnimationCurve::create):
(WebCore):
(WebCore::CCKeyframedFloatAnimationCurve::CCKeyframedFloatAnimationCurve):
(WebCore::CCKeyframedFloatAnimationCurve::~CCKeyframedFloatAnimationCurve):
(WebCore::CCKeyframedFloatAnimationCurve::duration):
(WebCore::CCKeyframedFloatAnimationCurve::clone):
(WebCore::CCKeyframedFloatAnimationCurve::getValue):
(WebCore::CCKeyframedTransformAnimationCurve::create):
(WebCore::CCKeyframedTransformAnimationCurve::CCKeyframedTransformAnimationCurve):
(WebCore::CCKeyframedTransformAnimationCurve::~CCKeyframedTransformAnimationCurve):
(WebCore::CCKeyframedTransformAnimationCurve::duration):
(WebCore::CCKeyframedTransformAnimationCurve::clone):
(WebCore::CCKeyframedTransformAnimationCurve::getValue):
* platform/graphics/chromium/cc/CCKeyframedAnimationCurve.h: Added.
(WebCore):
(WebCore::CCFloatKeyframe::CCFloatKeyframe):
(CCFloatKeyframe):
(WebCore::CCTransformKeyframe::CCTransformKeyframe):
(CCTransformKeyframe):
(CCKeyframedFloatAnimationCurve):
(CCKeyframedTransformAnimationCurve):
* platform/graphics/chromium/cc/CCLayerAnimationController.cpp:
(WebCore::CCLayerAnimationController::addAnimation):
* platform/graphics/chromium/cc/CCLayerAnimationController.h:
(WebCore::CCLayerAnimationController::hasActiveAnimation):
(CCLayerAnimationController):
* platform/graphics/chromium/cc/CCLayerAnimationControllerImpl.cpp:
(WebCore::CCLayerAnimationControllerImpl::tickAnimations):

Source/WebKit/chromium:

* WebKit.gypi:
* tests/CCAnimationTestCommon.cpp:
(WebCore):
(WebCore::addOpacityTransition):
(WebKitTests::addOpacityTransitionToController):
(WebKitTests::addOpacityTransitionToLayer):
* tests/CCAnimationTestCommon.h:
(WebCore):
(WebKitTests):
* tests/CCKeyframedAnimationCurveTest.cpp: Added.
(WebCore):
(WebCore::expectTranslateX):
(WebCore::TEST):
* tests/CCLayerAnimationControllerTest.cpp:
(WebKitTests::expectTranslateX):
(WebKitTests):
(WebKitTests::TEST):
* tests/CCLayerTreeHostTest.cpp:
(WTF::CCLayerTreeHostTest::dispatchAddAnimation):
(WTF::CCLayerTreeHostTest::doBeginTest):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@108727 268f45cc-cd09-0410-ab3c-d52691b4dbfc

18 files changed:
Source/WebCore/ChangeLog
Source/WebCore/WebCore.gypi
Source/WebCore/platform/graphics/chromium/LayerChromium.cpp
Source/WebCore/platform/graphics/chromium/LayerChromium.h
Source/WebCore/platform/graphics/chromium/cc/CCActiveAnimation.cpp
Source/WebCore/platform/graphics/chromium/cc/CCActiveAnimation.h
Source/WebCore/platform/graphics/chromium/cc/CCKeyframedAnimationCurve.cpp [new file with mode: 0644]
Source/WebCore/platform/graphics/chromium/cc/CCKeyframedAnimationCurve.h [new file with mode: 0644]
Source/WebCore/platform/graphics/chromium/cc/CCLayerAnimationController.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerAnimationController.h
Source/WebCore/platform/graphics/chromium/cc/CCLayerAnimationControllerImpl.cpp
Source/WebKit/chromium/ChangeLog
Source/WebKit/chromium/WebKit.gypi
Source/WebKit/chromium/tests/CCAnimationTestCommon.cpp
Source/WebKit/chromium/tests/CCAnimationTestCommon.h
Source/WebKit/chromium/tests/CCKeyframedAnimationCurveTest.cpp [new file with mode: 0644]
Source/WebKit/chromium/tests/CCLayerAnimationControllerTest.cpp
Source/WebKit/chromium/tests/CCLayerTreeHostTest.cpp

index a927f62..879df0e 100644 (file)
@@ -1,3 +1,54 @@
+2012-02-23  Ian Vollick  <vollick@chromium.org>
+
+        [chromium] Implement keyframed animations for the cc thread.
+        https://bugs.webkit.org/show_bug.cgi?id=77229
+
+        Reviewed by James Robinson.
+
+        * WebCore.gypi:
+        * platform/graphics/chromium/LayerChromium.cpp:
+        (WebCore::LayerChromium::hasActiveAnimation):
+        (WebCore):
+        * platform/graphics/chromium/LayerChromium.h:
+        (LayerChromium):
+        * platform/graphics/chromium/cc/CCActiveAnimation.cpp:
+        (WebCore::CCActiveAnimation::CCActiveAnimation):
+        (WebCore::CCActiveAnimation::isFinishedAt):
+        (WebCore::CCActiveAnimation::trimTimeToCurrentIteration):
+        (WebCore::CCActiveAnimation::cloneForImplThread):
+        * platform/graphics/chromium/cc/CCActiveAnimation.h:
+        (WebCore::CCActiveAnimation::curve):
+        (CCActiveAnimation):
+        * platform/graphics/chromium/cc/CCKeyframedAnimationCurve.cpp: Added.
+        (WebCore::CCKeyframedFloatAnimationCurve::create):
+        (WebCore):
+        (WebCore::CCKeyframedFloatAnimationCurve::CCKeyframedFloatAnimationCurve):
+        (WebCore::CCKeyframedFloatAnimationCurve::~CCKeyframedFloatAnimationCurve):
+        (WebCore::CCKeyframedFloatAnimationCurve::duration):
+        (WebCore::CCKeyframedFloatAnimationCurve::clone):
+        (WebCore::CCKeyframedFloatAnimationCurve::getValue):
+        (WebCore::CCKeyframedTransformAnimationCurve::create):
+        (WebCore::CCKeyframedTransformAnimationCurve::CCKeyframedTransformAnimationCurve):
+        (WebCore::CCKeyframedTransformAnimationCurve::~CCKeyframedTransformAnimationCurve):
+        (WebCore::CCKeyframedTransformAnimationCurve::duration):
+        (WebCore::CCKeyframedTransformAnimationCurve::clone):
+        (WebCore::CCKeyframedTransformAnimationCurve::getValue):
+        * platform/graphics/chromium/cc/CCKeyframedAnimationCurve.h: Added.
+        (WebCore):
+        (WebCore::CCFloatKeyframe::CCFloatKeyframe):
+        (CCFloatKeyframe):
+        (WebCore::CCTransformKeyframe::CCTransformKeyframe):
+        (CCTransformKeyframe):
+        (CCKeyframedFloatAnimationCurve):
+        (CCKeyframedTransformAnimationCurve):
+        * platform/graphics/chromium/cc/CCLayerAnimationController.cpp:
+        (WebCore::CCLayerAnimationController::addAnimation):
+        * platform/graphics/chromium/cc/CCLayerAnimationController.h:
+        (WebCore::CCLayerAnimationController::hasActiveAnimation):
+        (CCLayerAnimationController):
+        * platform/graphics/chromium/cc/CCLayerAnimationControllerImpl.cpp:
+        (WebCore::CCLayerAnimationControllerImpl::tickAnimations):
+
 2012-02-23  Raymond Toy  <rtoy@google.com>
 
         Use MathExtras round() in timeToSampleFrame
index e0ecca3..bb2b54e 100644 (file)
             'platform/graphics/chromium/cc/CCHeadsUpDisplay.cpp',
             'platform/graphics/chromium/cc/CCHeadsUpDisplay.h',
             'platform/graphics/chromium/cc/CCInputHandler.h',
+            'platform/graphics/chromium/cc/CCKeyframedAnimationCurve.cpp',
+            'platform/graphics/chromium/cc/CCKeyframedAnimationCurve.h',
             'platform/graphics/chromium/cc/CCLayerAnimationController.h',
             'platform/graphics/chromium/cc/CCLayerAnimationController.cpp',
             'platform/graphics/chromium/cc/CCLayerAnimationControllerImpl.h',
index b59a6a1..8eeda68 100644 (file)
@@ -136,6 +136,11 @@ void LayerChromium::setLayerAnimationController(PassOwnPtr<CCLayerAnimationContr
     setNeedsCommit();
 }
 
+bool LayerChromium::hasActiveAnimation() const
+{
+    return m_layerAnimationController->hasActiveAnimation();
+}
+
 void LayerChromium::setIsNonCompositedContent(bool isNonCompositedContent)
 {
     m_isNonCompositedContent = isNonCompositedContent;
index 2f7cf68..897647d 100644 (file)
@@ -224,6 +224,7 @@ public:
 
     CCLayerAnimationController* layerAnimationController() { return m_layerAnimationController.get(); }
     void setLayerAnimationController(PassOwnPtr<CCLayerAnimationController>);
+    bool hasActiveAnimation() const;
 
 protected:
     friend class CCLayerImpl;
index 9ef5fe2..8c0303e 100644 (file)
@@ -38,7 +38,7 @@ PassOwnPtr<CCActiveAnimation> CCActiveAnimation::create(PassOwnPtr<CCAnimationCu
 }
 
 CCActiveAnimation::CCActiveAnimation(PassOwnPtr<CCAnimationCurve> curve, int animationId, int groupId, TargetProperty targetProperty)
-    : m_animationCurve(curve)
+    : m_curve(curve)
     , m_id(animationId)
     , m_group(groupId)
     , m_targetProperty(targetProperty)
@@ -70,7 +70,7 @@ bool CCActiveAnimation::isFinishedAt(double time) const
 
     return m_runState == Running
         && m_iterations >= 0
-        && m_iterations * m_animationCurve->duration() <= time - startTime() - m_totalPausedTime;
+        && m_iterations * m_curve->duration() <= time - startTime() - m_totalPausedTime;
 }
 
 bool CCActiveAnimation::isWaiting() const
@@ -109,20 +109,20 @@ double CCActiveAnimation::trimTimeToCurrentIteration(double now) const
         return 0;
 
     // If less than an iteration duration, just return trimmed.
-    if (trimmed < m_animationCurve->duration())
+    if (trimmed < m_curve->duration())
         return trimmed;
 
     // If greater than or equal to the total duration, return iteration duration.
-    if (m_iterations >= 0 && trimmed >= m_animationCurve->duration() * m_iterations)
-        return m_animationCurve->duration();
+    if (m_iterations >= 0 && trimmed >= m_curve->duration() * m_iterations)
+        return m_curve->duration();
 
     // Finally, return x where trimmed = x + n * m_animation->duration() for some positive integer n.
-    return fmod(trimmed, m_animationCurve->duration());
+    return fmod(trimmed, m_curve->duration());
 }
 
 PassOwnPtr<CCActiveAnimation> CCActiveAnimation::cloneForImplThread() const
 {
-    OwnPtr<CCActiveAnimation> toReturn(adoptPtr(new CCActiveAnimation(m_animationCurve->clone(), m_id, m_group, m_targetProperty)));
+    OwnPtr<CCActiveAnimation> toReturn(adoptPtr(new CCActiveAnimation(m_curve->clone(), m_id, m_group, m_targetProperty)));
     toReturn->m_runState = m_runState;
     toReturn->m_iterations = m_iterations;
     toReturn->m_startTime = m_startTime;
index ad9e84e..2093421 100644 (file)
@@ -97,8 +97,8 @@ public:
     bool isWaiting() const;
     bool isRunningOrHasRun() const;
 
-    CCAnimationCurve* animationCurve() { return m_animationCurve.get(); }
-    const CCAnimationCurve* animationCurve() const { return m_animationCurve.get(); }
+    CCAnimationCurve* curve() { return m_curve.get(); }
+    const CCAnimationCurve* curve() const { return m_curve.get(); }
 
     // Takes the given absolute time, and using the start time and the number
     // of iterations, returns the relative time in the current iteration.
@@ -113,7 +113,7 @@ public:
 private:
     CCActiveAnimation(PassOwnPtr<CCAnimationCurve>, int animationId, int groupId, TargetProperty);
 
-    OwnPtr<CCAnimationCurve> m_animationCurve;
+    OwnPtr<CCAnimationCurve> m_curve;
 
     // IDs are not necessarily unique.
     int m_id;
diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCKeyframedAnimationCurve.cpp b/Source/WebCore/platform/graphics/chromium/cc/CCKeyframedAnimationCurve.cpp
new file mode 100644 (file)
index 0000000..b615c73
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "cc/CCKeyframedAnimationCurve.h"
+
+#include "IdentityTransformOperation.h"
+#include "Matrix3DTransformOperation.h"
+#include "MatrixTransformOperation.h"
+#include "PerspectiveTransformOperation.h"
+#include "RotateTransformOperation.h"
+#include "ScaleTransformOperation.h"
+#include "SkewTransformOperation.h"
+#include "TranslateTransformOperation.h"
+
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+namespace {
+
+template <class Keyframe>
+bool keyframesAreSorted(const Vector<Keyframe>& keyframes)
+{
+    if (!keyframes.size())
+        return true;
+
+    for (size_t i = 0; i < keyframes.size() - 1; ++i) {
+        if (keyframes[i].time > keyframes[i+1].time)
+            return false;
+    }
+
+    return true;
+}
+
+} // namespace
+
+PassOwnPtr<CCKeyframedFloatAnimationCurve> CCKeyframedFloatAnimationCurve::create(const Vector<CCFloatKeyframe>& keyframes)
+{
+    if (!keyframes.size() || !keyframesAreSorted(keyframes))
+        return nullptr;
+
+    return adoptPtr(new CCKeyframedFloatAnimationCurve(keyframes));
+}
+
+CCKeyframedFloatAnimationCurve::CCKeyframedFloatAnimationCurve(const Vector<CCFloatKeyframe>& keyframes)
+    : m_keyframes(keyframes)
+{
+}
+
+CCKeyframedFloatAnimationCurve::~CCKeyframedFloatAnimationCurve()
+{
+}
+
+double CCKeyframedFloatAnimationCurve::duration() const
+{
+    return m_keyframes.last().time - m_keyframes.first().time;
+}
+
+PassOwnPtr<CCAnimationCurve> CCKeyframedFloatAnimationCurve::clone() const
+{
+    return adoptPtr(new CCKeyframedFloatAnimationCurve(*this));
+}
+
+float CCKeyframedFloatAnimationCurve::getValue(double t) const
+{
+    if (t <= m_keyframes.first().time)
+        return m_keyframes.first().value;
+
+    if (t >= m_keyframes.last().time)
+        return m_keyframes.last().value;
+
+    size_t i = 0;
+    for (; i < m_keyframes.size() - 1; ++i) {
+        if (t < m_keyframes[i+1].time)
+            break;
+    }
+
+    float progress = static_cast<float>((t - m_keyframes[i].time) / (m_keyframes[i+1].time - m_keyframes[i].time));
+    // FIXME: apply timing function here.
+    return m_keyframes[i].value + (m_keyframes[i+1].value - m_keyframes[i].value) * progress;
+}
+
+PassOwnPtr<CCKeyframedTransformAnimationCurve> CCKeyframedTransformAnimationCurve::create(const Vector<CCTransformKeyframe>& keyframes)
+{
+    if (!keyframes.size() || !keyframesAreSorted(keyframes))
+        return nullptr;
+
+    return adoptPtr(new CCKeyframedTransformAnimationCurve(keyframes));
+}
+
+CCKeyframedTransformAnimationCurve::CCKeyframedTransformAnimationCurve(const Vector<CCTransformKeyframe>& keyframes)
+    : m_keyframes(keyframes)
+{
+}
+
+CCKeyframedTransformAnimationCurve::~CCKeyframedTransformAnimationCurve() { }
+
+double CCKeyframedTransformAnimationCurve::duration() const
+{
+    return m_keyframes.last().time - m_keyframes.first().time;
+}
+
+PassOwnPtr<CCAnimationCurve> CCKeyframedTransformAnimationCurve::clone() const
+{
+    Vector<CCTransformKeyframe> keyframes;
+    // We need to do a deep copy of all of the keyframes since they contain ref
+    // pointers to TransformOperation objects.
+    for (size_t i = 0; i < m_keyframes.size(); ++i) {
+        CCTransformKeyframe keyframe(m_keyframes[i].time);
+        for (size_t j = 0; j < m_keyframes[i].value.size(); ++j) {
+            TransformOperation::OperationType operationType = m_keyframes[i].value.operations()[j]->getOperationType();
+            switch (operationType) {
+            case TransformOperation::SCALE_X:
+            case TransformOperation::SCALE_Y:
+            case TransformOperation::SCALE_Z:
+            case TransformOperation::SCALE_3D:
+            case TransformOperation::SCALE: {
+                ScaleTransformOperation* transform = static_cast<ScaleTransformOperation*>(m_keyframes[i].value.operations()[j].get());
+                keyframe.value.operations().append(ScaleTransformOperation::create(transform->x(), transform->y(), transform->z(), operationType));
+                break;
+            }
+            case TransformOperation::TRANSLATE_X:
+            case TransformOperation::TRANSLATE_Y:
+            case TransformOperation::TRANSLATE_Z:
+            case TransformOperation::TRANSLATE_3D:
+            case TransformOperation::TRANSLATE: {
+                TranslateTransformOperation* transform = static_cast<TranslateTransformOperation*>(m_keyframes[i].value.operations()[j].get());
+                keyframe.value.operations().append(TranslateTransformOperation::create(transform->x(), transform->y(), transform->z(), operationType));
+                break;
+            }
+            case TransformOperation::ROTATE_X:
+            case TransformOperation::ROTATE_Y:
+            case TransformOperation::ROTATE_3D:
+            case TransformOperation::ROTATE: {
+                RotateTransformOperation* transform = static_cast<RotateTransformOperation*>(m_keyframes[i].value.operations()[j].get());
+                keyframe.value.operations().append(RotateTransformOperation::create(transform->x(), transform->y(), transform->z(), transform->angle(), operationType));
+                break;
+            }
+            case TransformOperation::SKEW_X:
+            case TransformOperation::SKEW_Y:
+            case TransformOperation::SKEW: {
+                SkewTransformOperation* transform = static_cast<SkewTransformOperation*>(m_keyframes[i].value.operations()[j].get());
+                keyframe.value.operations().append(SkewTransformOperation::create(transform->angleX(), transform->angleY(), operationType));
+                break;
+            }
+            case TransformOperation::MATRIX: {
+                MatrixTransformOperation* transform = static_cast<MatrixTransformOperation*>(m_keyframes[i].value.operations()[j].get());
+                TransformationMatrix m = transform->matrix();
+                keyframe.value.operations().append(MatrixTransformOperation::create(m.a(), m.b(), m.c(), m.d(), m.e(), m.f()));
+                break;
+            }
+            case TransformOperation::MATRIX_3D: {
+                Matrix3DTransformOperation* transform = static_cast<Matrix3DTransformOperation*>(m_keyframes[i].value.operations()[j].get());
+                keyframe.value.operations().append(Matrix3DTransformOperation::create(transform->matrix()));
+                break;
+            }
+            case TransformOperation::PERSPECTIVE: {
+                PerspectiveTransformOperation* transform = static_cast<PerspectiveTransformOperation*>(m_keyframes[i].value.operations()[j].get());
+                keyframe.value.operations().append(PerspectiveTransformOperation::create(transform->perspective()));
+                break;
+            }
+            case TransformOperation::IDENTITY: {
+                keyframe.value.operations().append(IdentityTransformOperation::create());
+                break;
+            }
+            case TransformOperation::NONE:
+                // Do nothing.
+                break;
+            } // switch
+        } // for each operation
+        keyframes.append(keyframe);
+    }
+    return CCKeyframedTransformAnimationCurve::create(keyframes);
+}
+
+TransformationMatrix CCKeyframedTransformAnimationCurve::getValue(double t, const IntSize& layerSize) const
+{
+    TransformationMatrix transformMatrix;
+
+    if (t <= m_keyframes.first().time) {
+        m_keyframes.first().value.apply(layerSize, transformMatrix);
+        return transformMatrix;
+    }
+
+    if (t >= m_keyframes.last().time) {
+        m_keyframes.last().value.apply(layerSize, transformMatrix);
+        return transformMatrix;
+    }
+
+    size_t i = 0;
+    for (; i < m_keyframes.size() - 1; ++i) {
+        if (t < m_keyframes[i+1].time)
+            break;
+    }
+
+    // FIXME: apply timing function here.
+    double progress = (t - m_keyframes[i].time) / (m_keyframes[i+1].time - m_keyframes[i].time);
+
+    if (m_keyframes[i].value.operationsMatch(m_keyframes[i+1].value)) {
+        for (size_t j = 0; j < m_keyframes[i+1].value.size(); ++j)
+            m_keyframes[i+1].value.operations()[j]->blend(m_keyframes[i].value.at(j), progress)->apply(transformMatrix, layerSize);
+    } else {
+        TransformationMatrix source;
+
+        m_keyframes[i].value.apply(layerSize, source);
+        m_keyframes[i+1].value.apply(layerSize, transformMatrix);
+
+        transformMatrix.blend(source, progress);
+    }
+
+    return transformMatrix;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/chromium/cc/CCKeyframedAnimationCurve.h b/Source/WebCore/platform/graphics/chromium/cc/CCKeyframedAnimationCurve.h
new file mode 100644 (file)
index 0000000..1c4d64a
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CCKeyframedAnimationCurve_h
+#define CCKeyframedAnimationCurve_h
+
+#include "TransformOperations.h"
+#include "cc/CCAnimationCurve.h"
+
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+struct CCFloatKeyframe {
+    CCFloatKeyframe(double time, float value)
+        : time(time)
+        , value(value)
+    {
+    }
+
+    double time;
+    float value;
+};
+
+struct CCTransformKeyframe {
+    explicit CCTransformKeyframe(double time)
+        : time(time)
+    {
+    }
+
+    CCTransformKeyframe(double time, const TransformOperations& value)
+        : time(time)
+        , value(value)
+    {
+    }
+
+    double time;
+    TransformOperations value;
+};
+
+class CCKeyframedFloatAnimationCurve : public CCFloatAnimationCurve {
+public:
+    // It is required that the keyframes be sorted by time.
+    static PassOwnPtr<CCKeyframedFloatAnimationCurve> create(const Vector<CCFloatKeyframe>& keyframes);
+
+    virtual ~CCKeyframedFloatAnimationCurve();
+
+    // CCAnimationCurve implementation
+    virtual double duration() const;
+    virtual PassOwnPtr<CCAnimationCurve> clone() const;
+
+    // CCFloatAnimationCurve implementation
+    virtual float getValue(double t) const;
+
+private:
+    explicit CCKeyframedFloatAnimationCurve(const Vector<CCFloatKeyframe>&);
+
+    // Always sorted in order of increasing time. No two keyframes have the
+    // same time.
+    Vector<CCFloatKeyframe> m_keyframes;
+};
+
+class CCKeyframedTransformAnimationCurve : public CCTransformAnimationCurve {
+public:
+    // It is required that the keyframes be sorted by time.
+    static PassOwnPtr<CCKeyframedTransformAnimationCurve> create(const Vector<CCTransformKeyframe>& keyframes);
+
+    virtual ~CCKeyframedTransformAnimationCurve();
+
+    // CCAnimationCurve implementation
+    virtual double duration() const;
+    virtual PassOwnPtr<CCAnimationCurve> clone() const;
+
+    // CCTransformAnimationCurve implementation
+    virtual TransformationMatrix getValue(double t, const IntSize&) const;
+
+private:
+    explicit CCKeyframedTransformAnimationCurve(const Vector<CCTransformKeyframe>&);
+
+    // Always sorted in order of increasing time. No two keyframes have the
+    // same time.
+    Vector<CCTransformKeyframe> m_keyframes;
+};
+
+} // namespace WebCore
+
+#endif // CCKeyframedAnimationCurve_h
index 94551d9..d9e72ef 100644 (file)
 
 #include "GraphicsLayer.h" // for KeyframeValueList
 #include "cc/CCActiveAnimation.h"
+#include "cc/CCKeyframedAnimationCurve.h"
 #include "cc/CCLayerAnimationControllerImpl.h"
+#include <wtf/CurrentTime.h>
 #include <wtf/HashMap.h>
 
 namespace WebCore {
 
+namespace {
+
+template <typename Keyframe, typename Value>
+void appendKeyframe(Vector<Keyframe>& keyframes, double keyTime, const Value* value)
+{
+    keyframes.append(Keyframe(keyTime, value->value()));
+}
+
+template <>
+void appendKeyframe<CCTransformKeyframe, TransformAnimationValue>(Vector<CCTransformKeyframe>& keyframes, double keyTime, const TransformAnimationValue* value)
+{
+    keyframes.append(CCTransformKeyframe(keyTime, *value->value()));
+}
+
+template <class Value, class Keyframe, class Curve>
+PassOwnPtr<CCActiveAnimation> createActiveAnimation(const KeyframeValueList& valueList, const Animation* animation, size_t animationId, size_t groupId, double timeOffset, CCActiveAnimation::TargetProperty targetProperty)
+{
+    // FIXME: add support for different directions.
+    if (animation && animation->isDirectionSet() && animation->direction() == Animation::AnimationDirectionAlternate)
+        return nullptr;
+
+    // FIXME: add support for delay
+    if (animation && animation->isDelaySet() && animation->delay() > 0)
+        return nullptr;
+
+    // FIXME: add support for fills forwards and fills backwards
+    if (animation && animation->isFillModeSet() && (animation->fillsForwards() || animation->fillsBackwards()))
+        return nullptr;
+
+    Vector<Keyframe> keyframes;
+
+    for (size_t i = 0; i < valueList.size(); i++) {
+        const Value* originalValue = static_cast<const Value*>(valueList.at(i));
+
+        // FIXME: add support for timing functions.
+        if (originalValue->timingFunction() && originalValue->timingFunction()->type() != TimingFunction::LinearFunction)
+            return nullptr;
+
+        double duration = (animation && animation->isDurationSet()) ? animation->duration() : 1;
+        appendKeyframe(keyframes, originalValue->keyTime() * duration, originalValue);
+    }
+
+    OwnPtr<Curve> curve = Curve::create(keyframes);
+
+    OwnPtr<CCActiveAnimation> anim = CCActiveAnimation::create(curve.release(), animationId, groupId, targetProperty);
+
+    ASSERT(anim.get());
+
+    if (anim.get()) {
+        int iterations = (animation && animation->isIterationCountSet()) ? animation->iterationCount() : 1;
+        anim->setIterations(iterations);
+    }
+
+    return anim.release();
+}
+
+} // namepace
+
 CCLayerAnimationController::CCLayerAnimationController()
 {
 }
@@ -46,13 +106,22 @@ PassOwnPtr<CCLayerAnimationController> CCLayerAnimationController::create()
     return adoptPtr(new CCLayerAnimationController);
 }
 
-bool CCLayerAnimationController::addAnimation(const KeyframeValueList& valueList,
-                                              const IntSize&,
-                                              const Animation* animation,
-                                              int animationId,
-                                              int groupId,
-                                              double timeOffset)
+bool CCLayerAnimationController::addAnimation(const KeyframeValueList& valueList, const IntSize&, const Animation* animation, int animationId, int groupId, double timeOffset)
 {
+    if (!animation)
+        return false;
+
+    OwnPtr<CCActiveAnimation> toAdd;
+    if (valueList.property() == AnimatedPropertyWebkitTransform)
+        toAdd = createActiveAnimation<TransformAnimationValue, CCTransformKeyframe, CCKeyframedTransformAnimationCurve>(valueList, animation, animationId, groupId, timeOffset, CCActiveAnimation::Transform);
+    else if (valueList.property() == AnimatedPropertyOpacity)
+        toAdd = createActiveAnimation<FloatAnimationValue, CCFloatKeyframe, CCKeyframedFloatAnimationCurve>(valueList, animation, animationId, groupId, timeOffset, CCActiveAnimation::Opacity);
+
+    if (toAdd.get()) {
+        m_activeAnimations.append(toAdd.release());
+        return true;
+    }
+
     return false;
 }
 
index ef8f1bd..0682130 100644 (file)
@@ -56,8 +56,8 @@ public:
     // are kept in sync. This function does not take ownership of the impl thread controller.
     virtual void synchronizeAnimations(CCLayerAnimationControllerImpl*);
 
-    // This is for testing purposes only.
-    Vector<OwnPtr<CCActiveAnimation> >& activeAnimations() { return m_activeAnimations; }
+    bool hasActiveAnimation() const { return m_activeAnimations.size(); }
+    CCActiveAnimation* getActiveAnimation(int groupId, CCActiveAnimation::TargetProperty);
 
 protected:
     CCLayerAnimationController();
@@ -68,7 +68,6 @@ private:
     void removeAnimationsCompletedOnMainThread(CCLayerAnimationControllerImpl*);
     void pushAnimationProperties(CCLayerAnimationControllerImpl*);
 
-    CCActiveAnimation* getActiveAnimation(int groupId, CCActiveAnimation::TargetProperty);
     void remove(int groupId, CCActiveAnimation::TargetProperty);
 
     Vector<OwnPtr<CCActiveAnimation> > m_activeAnimations;
index 4f72798..2096ce3 100644 (file)
@@ -201,7 +201,7 @@ void CCLayerAnimationControllerImpl::tickAnimations(double now)
             switch (m_activeAnimations[i]->targetProperty()) {
 
             case CCActiveAnimation::Transform: {
-                const CCTransformAnimationCurve* transformAnimationCurve = m_activeAnimations[i]->animationCurve()->toTransformAnimationCurve();
+                const CCTransformAnimationCurve* transformAnimationCurve = m_activeAnimations[i]->curve()->toTransformAnimationCurve();
                 const TransformationMatrix matrix = transformAnimationCurve->getValue(trimmed, m_client->bounds());
                 if (m_activeAnimations[i]->isFinishedAt(now))
                     m_activeAnimations[i]->setRunState(CCActiveAnimation::Finished, now);
@@ -211,7 +211,7 @@ void CCLayerAnimationControllerImpl::tickAnimations(double now)
             }
 
             case CCActiveAnimation::Opacity: {
-                const CCFloatAnimationCurve* floatAnimationCurve = m_activeAnimations[i]->animationCurve()->toFloatAnimationCurve();
+                const CCFloatAnimationCurve* floatAnimationCurve = m_activeAnimations[i]->curve()->toFloatAnimationCurve();
                 const float opacity = floatAnimationCurve->getValue(trimmed);
                 if (m_activeAnimations[i]->isFinishedAt(now))
                     m_activeAnimations[i]->setRunState(CCActiveAnimation::Finished, now);
index d48f25b..f0fc596 100644 (file)
@@ -1,3 +1,31 @@
+2012-02-23  Ian Vollick  <vollick@chromium.org>
+
+        [chromium] Implement keyframed animations for the cc thread.
+        https://bugs.webkit.org/show_bug.cgi?id=77229
+
+        Reviewed by James Robinson.
+
+        * WebKit.gypi:
+        * tests/CCAnimationTestCommon.cpp:
+        (WebCore):
+        (WebCore::addOpacityTransition):
+        (WebKitTests::addOpacityTransitionToController):
+        (WebKitTests::addOpacityTransitionToLayer):
+        * tests/CCAnimationTestCommon.h:
+        (WebCore):
+        (WebKitTests):
+        * tests/CCKeyframedAnimationCurveTest.cpp: Added.
+        (WebCore):
+        (WebCore::expectTranslateX):
+        (WebCore::TEST):
+        * tests/CCLayerAnimationControllerTest.cpp:
+        (WebKitTests::expectTranslateX):
+        (WebKitTests):
+        (WebKitTests::TEST):
+        * tests/CCLayerTreeHostTest.cpp:
+        (WTF::CCLayerTreeHostTest::dispatchAddAnimation):
+        (WTF::CCLayerTreeHostTest::doBeginTest):
+
 2012-02-23  James Robinson  <jamesr@chromium.org>
 
         [chromium] Clean up GraphicsContext3D initialization paths
index a422401..e91e336 100644 (file)
@@ -66,6 +66,7 @@
             'tests/CCDamageTrackerTest.cpp',
             'tests/CCDelayBasedTimeSourceTest.cpp',
             'tests/CCFrameRateControllerTest.cpp',
+            'tests/CCKeyframedAnimationCurveTest.cpp',
             'tests/CCLayerAnimationControllerImplTest.cpp',
             'tests/CCLayerAnimationControllerTest.cpp',
             'tests/CCLayerImplTest.cpp',
index 0e06157..c9240e3 100644 (file)
 
 #include "GraphicsLayer.h"
 #include "LayerChromium.h"
+#include "cc/CCLayerAnimationController.h"
 
 using namespace WebCore;
 
+namespace {
+
+template <class Target>
+void addOpacityTransition(Target& target, double duration, float startOpacity, float endOpacity)
+{
+    WebCore::KeyframeValueList values(AnimatedPropertyOpacity);
+    if (duration > 0)
+        values.insert(new FloatAnimationValue(0, startOpacity));
+    values.insert(new FloatAnimationValue(duration, endOpacity));
+
+    RefPtr<Animation> animation = Animation::create();
+    animation->setDuration(duration);
+
+    IntSize boxSize;
+
+    target.addAnimation(values, boxSize, animation.get(), 0, 0, 0);
+}
+
+} // namespace
+
 namespace WebKitTests {
 
 FakeFloatAnimationCurve::FakeFloatAnimationCurve()
@@ -99,19 +120,14 @@ PassOwnPtr<WebCore::CCAnimationCurve> FakeFloatTransition::clone() const
     return adoptPtr(new FakeFloatTransition(*this));
 }
 
-void addOpacityTransition(WebCore::LayerChromium& layer, double duration, float startOpacity, float endOpacity)
+void addOpacityTransitionToController(WebCore::CCLayerAnimationController& controller, double duration, float startOpacity, float endOpacity)
 {
-    WebCore::KeyframeValueList values(AnimatedPropertyOpacity);
-    if (duration > 0)
-        values.insert(new FloatAnimationValue(0, startOpacity));
-    values.insert(new FloatAnimationValue(duration, endOpacity));
-
-    RefPtr<Animation> animation = Animation::create();
-    animation->setDuration(1);
-
-    IntSize boxSize;
+    addOpacityTransition(controller, duration, startOpacity, endOpacity);
+}
 
-    layer.addAnimation(values, boxSize, animation.get(), 0, 0, 0);
+void addOpacityTransitionToLayer(WebCore::LayerChromium& layer, double duration, float startOpacity, float endOpacity)
+{
+    addOpacityTransition(layer, duration, startOpacity, endOpacity);
 }
 
 } // namespace WebKitTests
index 9f964e4..d13e74c 100644 (file)
@@ -31,6 +31,7 @@
 #include <wtf/OwnPtr.h>
 
 namespace WebCore {
+class CCLayerAnimationController;
 class LayerChromium;
 }
 
@@ -94,7 +95,9 @@ private:
     WebCore::IntSize m_bounds;
 };
 
-void addOpacityTransition(WebCore::LayerChromium&, double duration, float startOpacity, float endOpacity);
+void addOpacityTransitionToController(WebCore::CCLayerAnimationController&, double duration, float startOpacity, float endOpacity);
+
+void addOpacityTransitionToLayer(WebCore::LayerChromium&, double duration, float startOpacity, float endOpacity);
 
 } // namespace WebKitTests
 
diff --git a/Source/WebKit/chromium/tests/CCKeyframedAnimationCurveTest.cpp b/Source/WebKit/chromium/tests/CCKeyframedAnimationCurveTest.cpp
new file mode 100644 (file)
index 0000000..b7732ae
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "cc/CCKeyframedAnimationCurve.h"
+
+#include "Length.h"
+#include "TranslateTransformOperation.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/Vector.h>
+
+using namespace WebCore;
+
+namespace {
+
+void expectTranslateX(double translateX, const TransformationMatrix& matrix)
+{
+    TransformationMatrix::DecomposedType decomposedType;
+    matrix.decompose(decomposedType);
+    EXPECT_FLOAT_EQ(translateX, decomposedType.translateX);
+}
+
+// Tests that a float animation with one keyframe works as expected.
+TEST(CCKeyframedAnimationCurveTest, OneFloatKeyframe)
+{
+    Vector<CCFloatKeyframe> keyframes;
+    keyframes.append(CCFloatKeyframe(0, 2));
+    OwnPtr<CCKeyframedFloatAnimationCurve> curve(CCKeyframedFloatAnimationCurve::create(keyframes));
+    EXPECT_FLOAT_EQ(2, curve->getValue(-1));
+    EXPECT_FLOAT_EQ(2, curve->getValue(0));
+    EXPECT_FLOAT_EQ(2, curve->getValue(0.5));
+    EXPECT_FLOAT_EQ(2, curve->getValue(1));
+    EXPECT_FLOAT_EQ(2, curve->getValue(2));
+}
+
+// Tests that a float animation with two keyframes works as expected.
+TEST(CCKeyframedAnimationCurveTest, TwoFloatKeyframe)
+{
+    Vector<CCFloatKeyframe> keyframes;
+    keyframes.append(CCFloatKeyframe(0, 2));
+    keyframes.append(CCFloatKeyframe(1, 4));
+    OwnPtr<CCKeyframedFloatAnimationCurve> curve(CCKeyframedFloatAnimationCurve::create(keyframes));
+    EXPECT_FLOAT_EQ(2, curve->getValue(-1));
+    EXPECT_FLOAT_EQ(2, curve->getValue(0));
+    EXPECT_FLOAT_EQ(3, curve->getValue(0.5));
+    EXPECT_FLOAT_EQ(4, curve->getValue(1));
+    EXPECT_FLOAT_EQ(4, curve->getValue(2));
+}
+
+// Tests that a float animation with three keyframes works as expected.
+TEST(CCKeyframedAnimationCurveTest, ThreeFloatKeyframe)
+{
+    Vector<CCFloatKeyframe> keyframes;
+    keyframes.append(CCFloatKeyframe(0, 2));
+    keyframes.append(CCFloatKeyframe(1, 4));
+    keyframes.append(CCFloatKeyframe(2, 8));
+    OwnPtr<CCKeyframedFloatAnimationCurve> curve(CCKeyframedFloatAnimationCurve::create(keyframes));
+    EXPECT_FLOAT_EQ(2, curve->getValue(-1));
+    EXPECT_FLOAT_EQ(2, curve->getValue(0));
+    EXPECT_FLOAT_EQ(3, curve->getValue(0.5));
+    EXPECT_FLOAT_EQ(4, curve->getValue(1));
+    EXPECT_FLOAT_EQ(6, curve->getValue(1.5));
+    EXPECT_FLOAT_EQ(8, curve->getValue(2));
+    EXPECT_FLOAT_EQ(8, curve->getValue(3));
+}
+
+// Tests that a float animation with multiple keys at a given time works sanely.
+TEST(CCKeyframedAnimationCurveTest, RepeatedFloatKeyTimes)
+{
+    Vector<CCFloatKeyframe> keyframes;
+    // A step function.
+    keyframes.append(CCFloatKeyframe(0, 4));
+    keyframes.append(CCFloatKeyframe(1, 4));
+    keyframes.append(CCFloatKeyframe(1, 6));
+    keyframes.append(CCFloatKeyframe(2, 6));
+    OwnPtr<CCKeyframedFloatAnimationCurve> curve(CCKeyframedFloatAnimationCurve::create(keyframes));
+
+    EXPECT_FLOAT_EQ(4, curve->getValue(-1));
+    EXPECT_FLOAT_EQ(4, curve->getValue(0));
+    EXPECT_FLOAT_EQ(4, curve->getValue(0.5));
+
+    // There is a discontinuity at 1. Any value between 4 and 6 is valid.
+    float value = curve->getValue(1);
+    EXPECT_TRUE(value >= 4 && value <= 6);
+
+    EXPECT_FLOAT_EQ(6, curve->getValue(1.5));
+    EXPECT_FLOAT_EQ(6, curve->getValue(2));
+    EXPECT_FLOAT_EQ(6, curve->getValue(3));
+}
+
+
+// Tests that a transform animation with one keyframe works as expected.
+TEST(CCKeyframedAnimationCurveTest, OneTransformKeyframe)
+{
+    Vector<CCTransformKeyframe> keyframes;
+    TransformOperations operations;
+    operations.operations().append(TranslateTransformOperation::create(Length(2, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X));
+    keyframes.append(CCTransformKeyframe(0, operations));
+    OwnPtr<CCKeyframedTransformAnimationCurve> curve(CCKeyframedTransformAnimationCurve::create(keyframes));
+    IntSize layerSize; // ignored
+    expectTranslateX(2, curve->getValue(-1, layerSize));
+    expectTranslateX(2, curve->getValue(0, layerSize));
+    expectTranslateX(2, curve->getValue(0.5, layerSize));
+    expectTranslateX(2, curve->getValue(1, layerSize));
+    expectTranslateX(2, curve->getValue(2, layerSize));
+}
+
+// Tests that a transform animation with two keyframes works as expected.
+TEST(CCKeyframedAnimationCurveTest, TwoTransformKeyframe)
+{
+    Vector<CCTransformKeyframe> keyframes;
+    TransformOperations operations1;
+    operations1.operations().append(TranslateTransformOperation::create(Length(2, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X));
+    TransformOperations operations2;
+    operations2.operations().append(TranslateTransformOperation::create(Length(4, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X));
+    keyframes.append(CCTransformKeyframe(0, operations1));
+    keyframes.append(CCTransformKeyframe(1, operations2));
+    OwnPtr<CCKeyframedTransformAnimationCurve> curve(CCKeyframedTransformAnimationCurve::create(keyframes));
+    IntSize layerSize; // ignored
+    expectTranslateX(2, curve->getValue(-1, layerSize));
+    expectTranslateX(2, curve->getValue(0, layerSize));
+    expectTranslateX(3, curve->getValue(0.5, layerSize));
+    expectTranslateX(4, curve->getValue(1, layerSize));
+    expectTranslateX(4, curve->getValue(2, layerSize));
+}
+
+// Tests that a transform animation with three keyframes works as expected.
+TEST(CCKeyframedAnimationCurveTest, ThreeTransformKeyframe)
+{
+    Vector<CCTransformKeyframe> keyframes;
+    TransformOperations operations1;
+    operations1.operations().append(TranslateTransformOperation::create(Length(2, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X));
+    TransformOperations operations2;
+    operations2.operations().append(TranslateTransformOperation::create(Length(4, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X));
+    TransformOperations operations3;
+    operations3.operations().append(TranslateTransformOperation::create(Length(8, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X));
+    keyframes.append(CCTransformKeyframe(0, operations1));
+    keyframes.append(CCTransformKeyframe(1, operations2));
+    keyframes.append(CCTransformKeyframe(2, operations3));
+    OwnPtr<CCKeyframedTransformAnimationCurve> curve(CCKeyframedTransformAnimationCurve::create(keyframes));
+    IntSize layerSize; // ignored
+    expectTranslateX(2, curve->getValue(-1, layerSize));
+    expectTranslateX(2, curve->getValue(0, layerSize));
+    expectTranslateX(3, curve->getValue(0.5, layerSize));
+    expectTranslateX(4, curve->getValue(1, layerSize));
+    expectTranslateX(6, curve->getValue(1.5, layerSize));
+    expectTranslateX(8, curve->getValue(2, layerSize));
+    expectTranslateX(8, curve->getValue(3, layerSize));
+}
+
+// Tests that a transform animation with multiple keys at a given time works sanely.
+TEST(CCKeyframedAnimationCurveTest, RepeatedTransformKeyTimes)
+{
+    Vector<CCTransformKeyframe> keyframes;
+    // A step function.
+    TransformOperations operations1;
+    operations1.operations().append(TranslateTransformOperation::create(Length(4, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X));
+    TransformOperations operations2;
+    operations2.operations().append(TranslateTransformOperation::create(Length(4, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X));
+    TransformOperations operations3;
+    operations3.operations().append(TranslateTransformOperation::create(Length(6, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X));
+    TransformOperations operations4;
+    operations4.operations().append(TranslateTransformOperation::create(Length(6, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X));
+    keyframes.append(CCTransformKeyframe(0, operations1));
+    keyframes.append(CCTransformKeyframe(1, operations2));
+    keyframes.append(CCTransformKeyframe(1, operations3));
+    keyframes.append(CCTransformKeyframe(2, operations4));
+    OwnPtr<CCKeyframedTransformAnimationCurve> curve(CCKeyframedTransformAnimationCurve::create(keyframes));
+
+    IntSize layerSize; // ignored
+
+    expectTranslateX(4, curve->getValue(-1, layerSize));
+    expectTranslateX(4, curve->getValue(0, layerSize));
+    expectTranslateX(4, curve->getValue(0.5, layerSize));
+
+    // There is a discontinuity at 1. Any value between 4 and 6 is valid.
+    TransformationMatrix value = curve->getValue(1, layerSize);
+    TransformationMatrix::DecomposedType decomposedType;
+    value.decompose(decomposedType);
+    EXPECT_TRUE(decomposedType.translateX >= 4 && decomposedType.translateX <= 6);
+
+    expectTranslateX(6, curve->getValue(1.5, layerSize));
+    expectTranslateX(6, curve->getValue(2, layerSize));
+    expectTranslateX(6, curve->getValue(3, layerSize));
+}
+
+// Tests that invalid lists of keyframes result in nothing being returned from ::create.
+TEST(CCKeyframedAnimationCurveTest, InvalidKeyframes)
+{
+    // It is invalid to pass an empty vector of keyframes to create.
+    Vector<CCTransformKeyframe> transformKeyframes;
+    OwnPtr<CCKeyframedTransformAnimationCurve> transformCurve = CCKeyframedTransformAnimationCurve::create(transformKeyframes);
+    EXPECT_FALSE(transformCurve.get());
+
+    Vector<CCFloatKeyframe> floatKeyframes;
+    OwnPtr<CCKeyframedFloatAnimationCurve> floatCurve = CCKeyframedFloatAnimationCurve::create(floatKeyframes);
+    EXPECT_FALSE(floatCurve.get());
+
+    // It is invalid to pass a vector of unsorted keyframes to create;
+    TransformOperations operations1;
+    operations1.operations().append(TranslateTransformOperation::create(Length(2, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X));
+    TransformOperations operations2;
+    operations2.operations().append(TranslateTransformOperation::create(Length(4, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X));
+    transformKeyframes.append(CCTransformKeyframe(1, operations1));
+    transformKeyframes.append(CCTransformKeyframe(0, operations2));
+    transformCurve = CCKeyframedTransformAnimationCurve::create(transformKeyframes);
+    EXPECT_FALSE(transformCurve.get());
+
+    floatKeyframes.append(CCFloatKeyframe(1, 2));
+    floatKeyframes.append(CCFloatKeyframe(0, 4));
+    floatCurve = CCKeyframedFloatAnimationCurve::create(floatKeyframes);
+    EXPECT_FALSE(floatCurve.get());
+}
+
+
+} // namespace
index 6ecc1ff..c4f103a 100644 (file)
 #include "cc/CCLayerAnimationController.h"
 
 #include "CCAnimationTestCommon.h"
+#include "GraphicsLayer.h"
+#include "Length.h"
+#include "TranslateTransformOperation.h"
+#include "cc/CCActiveAnimation.h"
+#include "cc/CCAnimationCurve.h"
+
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <wtf/Vector.h>
@@ -36,22 +42,95 @@ using namespace WebKitTests;
 
 namespace {
 
+void expectTranslateX(double translateX, const TransformationMatrix& matrix)
+{
+    TransformationMatrix::DecomposedType decomposedType;
+    matrix.decompose(decomposedType);
+    EXPECT_FLOAT_EQ(translateX, decomposedType.translateX);
+}
+
 PassOwnPtr<CCActiveAnimation> createActiveAnimation(PassOwnPtr<CCAnimationCurve> curve, int id, CCActiveAnimation::TargetProperty property)
 {
     return CCActiveAnimation::create(curve, 0, id, property);
 }
 
+TEST(CCLayerAnimationControllerTest, createOpacityAnimation)
+{
+    OwnPtr<CCLayerAnimationController> controller(CCLayerAnimationController::create());
+    const double duration = 1;
+    WebCore::KeyframeValueList values(AnimatedPropertyOpacity);
+    values.insert(new FloatAnimationValue(0, 0));
+    values.insert(new FloatAnimationValue(duration, 1));
+
+    RefPtr<Animation> animation = Animation::create();
+    animation->setDuration(duration);
+
+    IntSize boxSize;
+    controller->addAnimation(values, boxSize, animation.get(), 0, 0, 0);
+
+    EXPECT_TRUE(controller->hasActiveAnimation());
+
+    CCActiveAnimation* activeAnimation = controller->getActiveAnimation(0, CCActiveAnimation::Opacity);
+    EXPECT_TRUE(activeAnimation);
+
+    EXPECT_EQ(1, activeAnimation->iterations());
+    EXPECT_EQ(CCActiveAnimation::Opacity, activeAnimation->targetProperty());
+
+    EXPECT_EQ(CCAnimationCurve::Float, activeAnimation->curve()->type());
+
+    const CCFloatAnimationCurve* curve = activeAnimation->curve()->toFloatAnimationCurve();
+    EXPECT_TRUE(curve);
+
+    EXPECT_EQ(0, curve->getValue(0));
+    EXPECT_EQ(1, curve->getValue(duration));
+}
+
+TEST(CCLayerAnimationControllerTest, createTransformAnimation)
+{
+    OwnPtr<CCLayerAnimationController> controller(CCLayerAnimationController::create());
+    const double duration = 1;
+    WebCore::KeyframeValueList values(AnimatedPropertyWebkitTransform);
+
+    TransformOperations operations1;
+    operations1.operations().append(TranslateTransformOperation::create(Length(2, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X));
+    values.insert(new TransformAnimationValue(0, &operations1));
+
+    TransformOperations operations2;
+    operations2.operations().append(TranslateTransformOperation::create(Length(4, Fixed), Length(0, Fixed), TransformOperation::TRANSLATE_X));
+    values.insert(new TransformAnimationValue(duration, &operations2));
+
+    RefPtr<Animation> animation = Animation::create();
+    animation->setDuration(duration);
+
+    IntSize boxSize;
+    controller->addAnimation(values, boxSize, animation.get(), 0, 0, 0);
+
+    EXPECT_TRUE(controller->hasActiveAnimation());
+
+    CCActiveAnimation* activeAnimation = controller->getActiveAnimation(0, CCActiveAnimation::Transform);
+    EXPECT_TRUE(activeAnimation);
+
+    EXPECT_EQ(1, activeAnimation->iterations());
+    EXPECT_EQ(CCActiveAnimation::Transform, activeAnimation->targetProperty());
+
+    EXPECT_EQ(CCAnimationCurve::Transform, activeAnimation->curve()->type());
+
+    const CCTransformAnimationCurve* curve = activeAnimation->curve()->toTransformAnimationCurve();
+    EXPECT_TRUE(curve);
+
+    expectTranslateX(2, curve->getValue(0, boxSize));
+    expectTranslateX(4, curve->getValue(duration, boxSize));
+}
+
 TEST(CCLayerAnimationControllerTest, syncNewAnimation)
 {
     FakeLayerAnimationControllerImplClient dummy;
-    OwnPtr<CCLayerAnimationControllerImpl> controllerImpl(
-        CCLayerAnimationControllerImpl::create(&dummy));
-    OwnPtr<CCLayerAnimationController> controller(
-        CCLayerAnimationController::create());
+    OwnPtr<CCLayerAnimationControllerImpl> controllerImpl(CCLayerAnimationControllerImpl::create(&dummy));
+    OwnPtr<CCLayerAnimationController> controller(CCLayerAnimationController::create());
 
     EXPECT_FALSE(controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity));
 
-    controller->activeAnimations().append(CCActiveAnimation::create(adoptPtr(new FakeFloatAnimationCurve()), 0, 0, CCActiveAnimation::Opacity));
+    addOpacityTransitionToController(*controller, 1, 0, 1);
 
     controller->synchronizeAnimations(controllerImpl.get());
 
@@ -62,14 +141,12 @@ TEST(CCLayerAnimationControllerTest, syncNewAnimation)
 TEST(CCLayerAnimationControllerTest, syncAnimationProperties)
 {
     FakeLayerAnimationControllerImplClient dummy;
-    OwnPtr<CCLayerAnimationControllerImpl> controllerImpl(
-        CCLayerAnimationControllerImpl::create(&dummy));
-    OwnPtr<CCLayerAnimationController> controller(
-        CCLayerAnimationController::create());
+    OwnPtr<CCLayerAnimationControllerImpl> controllerImpl(CCLayerAnimationControllerImpl::create(&dummy));
+    OwnPtr<CCLayerAnimationController> controller(CCLayerAnimationController::create());
 
     EXPECT_FALSE(controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity));
 
-    controller->activeAnimations().append(CCActiveAnimation::create(adoptPtr(new FakeFloatAnimationCurve()), 0, 0, CCActiveAnimation::Opacity));
+    addOpacityTransitionToController(*controller, 1, 0, 1);
 
     controller->synchronizeAnimations(controllerImpl.get());
 
@@ -87,14 +164,12 @@ TEST(CCLayerAnimationControllerTest, syncAnimationProperties)
 TEST(CCLayerAnimationControllerTest, syncAbortedAnimation)
 {
     FakeLayerAnimationControllerImplClient dummy;
-    OwnPtr<CCLayerAnimationControllerImpl> controllerImpl(
-        CCLayerAnimationControllerImpl::create(&dummy));
-    OwnPtr<CCLayerAnimationController> controller(
-        CCLayerAnimationController::create());
+    OwnPtr<CCLayerAnimationControllerImpl> controllerImpl(CCLayerAnimationControllerImpl::create(&dummy));
+    OwnPtr<CCLayerAnimationController> controller(CCLayerAnimationController::create());
 
     EXPECT_FALSE(controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity));
 
-    controller->activeAnimations().append(CCActiveAnimation::create(adoptPtr(new FakeFloatAnimationCurve()), 0, 0, CCActiveAnimation::Opacity));
+    addOpacityTransitionToController(*controller, 1, 0, 1);
 
     controller->synchronizeAnimations(controllerImpl.get());
 
@@ -112,14 +187,12 @@ TEST(CCLayerAnimationControllerTest, syncAbortedAnimation)
 TEST(CCLayerAnimationControllerTest, syncCompletedAnimation)
 {
     FakeLayerAnimationControllerImplClient dummy;
-    OwnPtr<CCLayerAnimationControllerImpl> controllerImpl(
-        CCLayerAnimationControllerImpl::create(&dummy));
-    OwnPtr<CCLayerAnimationController> controller(
-        CCLayerAnimationController::create());
+    OwnPtr<CCLayerAnimationControllerImpl> controllerImpl(CCLayerAnimationControllerImpl::create(&dummy));
+    OwnPtr<CCLayerAnimationController> controller(CCLayerAnimationController::create());
 
     EXPECT_FALSE(controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity));
 
-    controller->activeAnimations().append(CCActiveAnimation::create(adoptPtr(new FakeFloatAnimationCurve()), 0, 0, CCActiveAnimation::Opacity));
+    addOpacityTransitionToController(*controller, 1, 0, 1);
 
     controller->synchronizeAnimations(controllerImpl.get());
 
@@ -132,11 +205,11 @@ TEST(CCLayerAnimationControllerTest, syncCompletedAnimation)
     controllerImpl->animate(2, *events);
 
     EXPECT_FALSE(controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity));
-    EXPECT_EQ(size_t(1), controller->activeAnimations().size());
+    EXPECT_TRUE(controller->hasActiveAnimation());
 
     controller->synchronizeAnimations(controllerImpl.get());
 
-    EXPECT_EQ(size_t(0), controller->activeAnimations().size());
+    EXPECT_FALSE(controller->hasActiveAnimation());
 }
 
 } // namespace
index 12d7141..10cfa69 100644 (file)
@@ -151,25 +151,6 @@ private:
     TestHooks* m_testHooks;
 };
 
-// Adapts CCLayerAnimationController for test. Adds a dummy implementation of addAnimation that inserts a float animation.
-// FIXME: once CCLayerAnimationController::addAnimation is implemented, that function should be called directly and this
-// class can be removed.
-class MockLayerAnimationController : public CCLayerAnimationController {
-public:
-    static PassOwnPtr<MockLayerAnimationController> create()
-    {
-        return adoptPtr(new MockLayerAnimationController);
-    }
-
-private:
-    virtual bool addAnimation(const KeyframeValueList&, const IntSize& boxSize, const Animation*, int animationId, int groupId, double timeOffset)
-    {
-        double duration = 0;
-        activeAnimations().append(CCActiveAnimation::create(adoptPtr(new FakeFloatTransition(duration, 1, 0)), animationId, groupId, CCActiveAnimation::Opacity));
-        return true;
-    }
-};
-
 class CompositorFakeWebGraphicsContext3DWithTextureTracking : public CompositorFakeWebGraphicsContext3D {
 public:
     static PassOwnPtr<CompositorFakeWebGraphicsContext3DWithTextureTracking> create(Attributes attrs)
@@ -361,7 +342,7 @@ protected:
       CCLayerTreeHostTest* test = static_cast<CCLayerTreeHostTest*>(self);
       ASSERT(test);
       if (test->m_layerTreeHost && test->m_layerTreeHost->rootLayer())
-          test->m_layerTreeHost->rootLayer()->addAnimation(KeyframeValueList(AnimatedPropertyOpacity), IntSize(), 0, 0, 0, 0.0);
+          addOpacityTransitionToLayer(*test->m_layerTreeHost->rootLayer(), 0, 0, 1);
     }
 
     static void dispatchSetNeedsAnimateAndCommit(void* self)
@@ -514,7 +495,6 @@ void CCLayerTreeHostTest::doBeginTest()
     m_layerTreeHost = MockLayerTreeHost::create(this, m_client.get(), rootLayer, m_settings);
     ASSERT_TRUE(m_layerTreeHost);
     rootLayer->setLayerTreeHost(m_layerTreeHost.get());
-    rootLayer->setLayerAnimationController(MockLayerAnimationController::create());
 
     m_beginning = true;
     beginTest();