[chromium] Add pause and resume support for accelerated css animations.
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 28 Apr 2012 00:07:49 +0000 (00:07 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 28 Apr 2012 00:07:49 +0000 (00:07 +0000)
https://bugs.webkit.org/show_bug.cgi?id=84601

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

Source/WebCore:

Tested in:
CCLayerAnimationControllerTest.syncPauseResume
CCActiveAnimationTest.TrimTimeTimeOffset
CCActiveAnimationTest.TrimTimeSuspendResume
CCActiveAnimationTest.IsFinishedNeedsSynchronizedStartTime
CCActiveAnimationTest.RunStateChangesIgnoredWhileSuspended

* platform/graphics/chromium/GraphicsLayerChromium.cpp:
(WebCore::GraphicsLayerChromium::suspendAnimations):
(WebCore::GraphicsLayerChromium::resumeAnimations):
* platform/graphics/chromium/GraphicsLayerChromium.h:
(GraphicsLayerChromium):
* platform/graphics/chromium/LayerChromium.cpp:
(WebCore::LayerChromium::suspendAnimations):
(WebCore::LayerChromium::resumeAnimations):
* platform/graphics/chromium/LayerChromium.h:
(LayerChromium):
* platform/graphics/chromium/cc/CCActiveAnimation.cpp:
(WebCore::CCActiveAnimation::CCActiveAnimation):
(WebCore::CCActiveAnimation::setRunState):
(WebCore::CCActiveAnimation::suspend):
(WebCore::CCActiveAnimation::resume):
(WebCore::CCActiveAnimation::isFinishedAt):
(WebCore::CCActiveAnimation::trimTimeToCurrentIteration):
(WebCore::CCActiveAnimation::cloneForImplThread):
(WebCore::CCActiveAnimation::pushPropertiesTo):
* platform/graphics/chromium/cc/CCActiveAnimation.h:
(CCActiveAnimation):
(WebCore::CCActiveAnimation::setStartTime):
(WebCore::CCActiveAnimation::timeOffset):
(WebCore::CCActiveAnimation::setTimeOffset):
(WebCore::CCActiveAnimation::isFinished):
* platform/graphics/chromium/cc/CCLayerAnimationController.cpp:
(WebCore::CCLayerAnimationController::addAnimation):
(WebCore::CCLayerAnimationController::pauseAnimation):
(WebCore::CCLayerAnimationController::suspendAnimations):
(WebCore::CCLayerAnimationController::resumeAnimations):
(WebCore::CCLayerAnimationController::pushAnimationUpdatesTo):
(WebCore::CCLayerAnimationController::getActiveAnimation):
(WebCore::CCLayerAnimationController::pushNewAnimationsToImplThread):
(WebCore::CCLayerAnimationController::removeAnimationsCompletedOnMainThread):
(WebCore::CCLayerAnimationController::pushPropertiesToImplThread):
(WebCore):
(WebCore::CCLayerAnimationController::tickAnimations):
* platform/graphics/chromium/cc/CCLayerAnimationController.h:
(CCLayerAnimationController):

Source/WebKit/chromium:

* tests/CCActiveAnimationTest.cpp:
(WebCore::TEST):
(WebCore):
* tests/CCLayerAnimationControllerTest.cpp:
(WebKitTests::TEST):
(WebKitTests):

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

12 files changed:
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp
Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h
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/CCLayerAnimationController.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerAnimationController.h
Source/WebKit/chromium/ChangeLog
Source/WebKit/chromium/tests/CCActiveAnimationTest.cpp
Source/WebKit/chromium/tests/CCLayerAnimationControllerTest.cpp

index 7e38e4b..702c6d7 100644 (file)
@@ -1,3 +1,57 @@
+2012-04-27  Ian Vollick  <vollick@chromium.org>
+
+        [chromium] Add pause and resume support for accelerated css animations.
+        https://bugs.webkit.org/show_bug.cgi?id=84601
+
+        Reviewed by James Robinson.
+
+        Tested in:
+        CCLayerAnimationControllerTest.syncPauseResume
+        CCActiveAnimationTest.TrimTimeTimeOffset
+        CCActiveAnimationTest.TrimTimeSuspendResume
+        CCActiveAnimationTest.IsFinishedNeedsSynchronizedStartTime
+        CCActiveAnimationTest.RunStateChangesIgnoredWhileSuspended
+
+        * platform/graphics/chromium/GraphicsLayerChromium.cpp:
+        (WebCore::GraphicsLayerChromium::suspendAnimations):
+        (WebCore::GraphicsLayerChromium::resumeAnimations):
+        * platform/graphics/chromium/GraphicsLayerChromium.h:
+        (GraphicsLayerChromium):
+        * platform/graphics/chromium/LayerChromium.cpp:
+        (WebCore::LayerChromium::suspendAnimations):
+        (WebCore::LayerChromium::resumeAnimations):
+        * platform/graphics/chromium/LayerChromium.h:
+        (LayerChromium):
+        * platform/graphics/chromium/cc/CCActiveAnimation.cpp:
+        (WebCore::CCActiveAnimation::CCActiveAnimation):
+        (WebCore::CCActiveAnimation::setRunState):
+        (WebCore::CCActiveAnimation::suspend):
+        (WebCore::CCActiveAnimation::resume):
+        (WebCore::CCActiveAnimation::isFinishedAt):
+        (WebCore::CCActiveAnimation::trimTimeToCurrentIteration):
+        (WebCore::CCActiveAnimation::cloneForImplThread):
+        (WebCore::CCActiveAnimation::pushPropertiesTo):
+        * platform/graphics/chromium/cc/CCActiveAnimation.h:
+        (CCActiveAnimation):
+        (WebCore::CCActiveAnimation::setStartTime):
+        (WebCore::CCActiveAnimation::timeOffset):
+        (WebCore::CCActiveAnimation::setTimeOffset):
+        (WebCore::CCActiveAnimation::isFinished):
+        * platform/graphics/chromium/cc/CCLayerAnimationController.cpp:
+        (WebCore::CCLayerAnimationController::addAnimation):
+        (WebCore::CCLayerAnimationController::pauseAnimation):
+        (WebCore::CCLayerAnimationController::suspendAnimations):
+        (WebCore::CCLayerAnimationController::resumeAnimations):
+        (WebCore::CCLayerAnimationController::pushAnimationUpdatesTo):
+        (WebCore::CCLayerAnimationController::getActiveAnimation):
+        (WebCore::CCLayerAnimationController::pushNewAnimationsToImplThread):
+        (WebCore::CCLayerAnimationController::removeAnimationsCompletedOnMainThread):
+        (WebCore::CCLayerAnimationController::pushPropertiesToImplThread):
+        (WebCore):
+        (WebCore::CCLayerAnimationController::tickAnimations):
+        * platform/graphics/chromium/cc/CCLayerAnimationController.h:
+        (CCLayerAnimationController):
+
 2012-04-27  Tim Horton  <timothy_horton@apple.com>
 
         SMIL animation causes leak of the related Document (and many elements)
index 7dde42e..3c6d924 100644 (file)
@@ -420,14 +420,17 @@ void GraphicsLayerChromium::removeAnimation(const String& animationName)
     primaryLayer()->removeAnimation(mapAnimationNameToId(animationName));
 }
 
-void GraphicsLayerChromium::suspendAnimations(double time)
+void GraphicsLayerChromium::suspendAnimations(double wallClockTime)
 {
-    primaryLayer()->suspendAnimations(time);
+    // |wallClockTime| is in the wrong time base. Need to convert here.
+    // FIXME: find a more reliable way to do this.
+    double monotonicTime = wallClockTime + monotonicallyIncreasingTime() - currentTime();
+    primaryLayer()->suspendAnimations(monotonicTime);
 }
 
 void GraphicsLayerChromium::resumeAnimations()
 {
-    primaryLayer()->resumeAnimations();
+    primaryLayer()->resumeAnimations(monotonicallyIncreasingTime());
 }
 
 void GraphicsLayerChromium::setContentsToMedia(PlatformLayer* layer)
index 883355f..e3a8209 100644 (file)
@@ -102,7 +102,7 @@ public:
     virtual bool addAnimation(const KeyframeValueList&, const IntSize& boxSize, const Animation*, const String&, double timeOffset);
     virtual void pauseAnimation(const String& animationName, double timeOffset);
     virtual void removeAnimation(const String& animationName);
-    virtual void suspendAnimations(double time);
+    virtual void suspendAnimations(double wallClockTime);
     virtual void resumeAnimations();
 
     virtual PlatformLayer* platformLayer() const;
index 180404f..48c5754 100644 (file)
@@ -621,15 +621,15 @@ void LayerChromium::removeAnimation(int animationId)
     setNeedsCommit();
 }
 
-void LayerChromium::suspendAnimations(double time)
+void LayerChromium::suspendAnimations(double monotonicTime)
 {
-    m_layerAnimationController->suspendAnimations(time);
+    m_layerAnimationController->suspendAnimations(monotonicTime);
     setNeedsCommit();
 }
 
-void LayerChromium::resumeAnimations()
+void LayerChromium::resumeAnimations(double monotonicTime)
 {
-    m_layerAnimationController->resumeAnimations();
+    m_layerAnimationController->resumeAnimations(monotonicTime);
     setNeedsCommit();
 }
 
index b58f008..d594840 100644 (file)
@@ -240,8 +240,8 @@ public:
     void pauseAnimation(int animationId, double timeOffset);
     void removeAnimation(int animationId);
 
-    void suspendAnimations(double time);
-    void resumeAnimations();
+    void suspendAnimations(double monotonicTime);
+    void resumeAnimations(double monotonicTime);
 
     CCLayerAnimationController* layerAnimationController() { return m_layerAnimationController.get(); }
     void setLayerAnimationController(PassOwnPtr<CCLayerAnimationController>);
index 260d7d4..ccffdbc 100644 (file)
@@ -45,7 +45,9 @@ CCActiveAnimation::CCActiveAnimation(PassOwnPtr<CCAnimationCurve> curve, int ani
     , m_runState(WaitingForTargetAvailability)
     , m_iterations(1)
     , m_startTime(0)
+    , m_timeOffset(0)
     , m_needsSynchronizedStartTime(false)
+    , m_suspended(false)
     , m_pauseTime(0)
     , m_totalPausedTime(0)
 {
@@ -55,46 +57,49 @@ CCActiveAnimation::~CCActiveAnimation()
 {
 }
 
-void CCActiveAnimation::setRunState(RunState runState, double now)
+void CCActiveAnimation::setRunState(RunState runState, double monotonicTime)
 {
+    if (m_suspended)
+        return;
+
     if (runState == Running && m_runState == Paused)
-        m_totalPausedTime += now - m_pauseTime;
+        m_totalPausedTime += monotonicTime - m_pauseTime;
     else if (runState == Paused)
-        m_pauseTime = now;
+        m_pauseTime = monotonicTime;
     m_runState = runState;
 }
 
-bool CCActiveAnimation::isFinishedAt(double time) const
+void CCActiveAnimation::suspend(double monotonicTime)
 {
-    if (m_runState == Finished || m_runState == Aborted)
-        return true;
-
-    return m_runState == Running
-        && m_iterations >= 0
-        && m_iterations * m_curve->duration() <= time - startTime() - m_totalPausedTime;
+    setRunState(Paused, monotonicTime);
+    m_suspended = true;
 }
 
-bool CCActiveAnimation::isWaiting() const
+void CCActiveAnimation::resume(double monotonicTime)
 {
-    return m_runState == WaitingForNextTick
-        || m_runState == WaitingForTargetAvailability
-        || m_runState == WaitingForStartTime;
+    m_suspended = false;
+    setRunState(Running, monotonicTime);
 }
 
-bool CCActiveAnimation::isRunningOrHasRun() const
+bool CCActiveAnimation::isFinishedAt(double monotonicTime) const
 {
+    if (m_runState == Finished || m_runState == Aborted)
+        return true;
+
+    if (m_needsSynchronizedStartTime)
+        return false;
+
     return m_runState == Running
-        || m_runState == Finished
-        || m_runState == Aborted
-        || m_runState == Paused;
+        && m_iterations >= 0
+        && m_iterations * m_curve->duration() <= monotonicTime - startTime() - m_totalPausedTime;
 }
 
-double CCActiveAnimation::trimTimeToCurrentIteration(double now) const
+double CCActiveAnimation::trimTimeToCurrentIteration(double monotonicTime) const
 {
-    double trimmed = now;
+    double trimmed = monotonicTime + m_timeOffset;
 
     // If we're paused, time is 'stuck' at the pause time.
-    if (m_runState == Paused && trimmed > m_pauseTime)
+    if (m_runState == Paused)
         trimmed = m_pauseTime;
 
     // Returned time should always be relative to the start time and should subtract
@@ -129,28 +134,18 @@ PassOwnPtr<CCActiveAnimation> CCActiveAnimation::cloneForImplThread() const
     toReturn->m_startTime = m_startTime;
     toReturn->m_pauseTime = m_pauseTime;
     toReturn->m_totalPausedTime = m_totalPausedTime;
+    toReturn->m_timeOffset = m_timeOffset;
     return toReturn.release();
 }
 
-void CCActiveAnimation::synchronizeProperties(CCActiveAnimation* other)
+void CCActiveAnimation::pushPropertiesTo(CCActiveAnimation* other) const
 {
-    // It is possible for the impl thread to initiate a run state change.
-    // This happens when the animation was waiting for a future event to take
-    // place, and the event has happened. In that case, we want 'this' to
-    // assume the impl thread's run state and start time.
-    if (isWaiting() && other->isRunningOrHasRun()) {
-        m_runState = other->m_runState;
-        m_startTime = other->m_startTime;
-    } else {
+    // Currently, we only push changes due to pausing and resuming animations on the main thread.
+    if (m_runState == CCActiveAnimation::Paused || other->m_runState == CCActiveAnimation::Paused) {
         other->m_runState = m_runState;
-        other->m_startTime = m_startTime;
+        other->m_pauseTime = m_pauseTime;
+        other->m_totalPausedTime = m_totalPausedTime;
     }
-
-    // Change in state related to iterations and pause is always initiated from
-    // the main thread, so it is safe to push properties in that direction.
-    other->m_iterations = m_iterations;
-    other->m_pauseTime = m_pauseTime;
-    other->m_totalPausedTime = m_totalPausedTime;
 }
 
 } // namespace WebCore
index a223b66..531eb46 100644 (file)
@@ -72,7 +72,7 @@ public:
     TargetProperty targetProperty() const { return m_targetProperty; }
 
     RunState runState() const { return m_runState; }
-    void setRunState(RunState, double now);
+    void setRunState(RunState, double monotonicTime);
 
     // This is the number of times that the animation will play. If this
     // value is zero the animation will not play. If it is negative, then
@@ -81,14 +81,17 @@ public:
     void setIterations(int n) { m_iterations = n; }
 
     double startTime() const { return m_startTime; }
-    void setStartTime(double startTime) { m_startTime = startTime; }
+    void setStartTime(double monotonicTime) { m_startTime = monotonicTime; }
     bool hasSetStartTime() const { return m_startTime; }
 
-    bool isFinishedAt(double time) const;
-    bool isFinished() const { return m_runState == Finished || m_runState == Aborted; }
+    double timeOffset() const { return m_timeOffset; }
+    void setTimeOffset(double monotonicTime) { m_timeOffset = monotonicTime; }
+
+    void suspend(double monotonicTime);
+    void resume(double monotonicTime);
 
-    bool isWaiting() const;
-    bool isRunningOrHasRun() const;
+    bool isFinishedAt(double monotonicTime) const;
+    bool isFinished() const { return m_runState == Finished || m_runState == Aborted; }
 
     CCAnimationCurve* curve() { return m_curve.get(); }
     const CCAnimationCurve* curve() const { return m_curve.get(); }
@@ -100,11 +103,11 @@ public:
 
     // Takes the given absolute time, and using the start time and the number
     // of iterations, returns the relative time in the current iteration.
-    double trimTimeToCurrentIteration(double now) const;
+    double trimTimeToCurrentIteration(double monotonicTime) const;
 
     PassOwnPtr<CCActiveAnimation> cloneForImplThread() const;
 
-    void synchronizeProperties(CCActiveAnimation*);
+    void pushPropertiesTo(CCActiveAnimation*) const;
 
 private:
     CCActiveAnimation(PassOwnPtr<CCAnimationCurve>, int animationId, int groupId, TargetProperty);
@@ -126,8 +129,17 @@ private:
     int m_iterations;
     double m_startTime;
 
+    // The time offset effectively pushes the start of the animation back in time. This is
+    // used for resuming paused animations -- an animation is added with a non-zero time
+    // offset, causing the animation to skip ahead to the desired point in time.
+    double m_timeOffset;
+
     bool m_needsSynchronizedStartTime;
 
+    // When an animation is suspended, it behaves as if it is paused and it also ignores
+    // all run state changes until it is resumed. This is used for testing purposes.
+    bool m_suspended;
+
     // These are used in trimTimeToCurrentIteration to account for time
     // spent while paused. This is not included in AnimationState since it
     // there is absolutely no need for clients of this controller to know
index 43fda09..199192d 100644 (file)
@@ -107,6 +107,9 @@ PassOwnPtr<CCActiveAnimation> createActiveAnimation(const KeyframeValueList& val
     // the corresponding impl thread animation.
     anim->setNeedsSynchronizedStartTime(true);
 
+    // If timeOffset > 0, then the animation has started in the past.
+    anim->setTimeOffset(timeOffset);
+
     return anim.release();
 }
 
@@ -138,6 +141,13 @@ bool CCLayerAnimationController::addAnimation(const KeyframeValueList& valueList
         toAdd = createActiveAnimation<FloatAnimationValue, CCFloatKeyframe, CCKeyframedFloatAnimationCurve>(valueList, animation, animationId, groupId, timeOffset, CCActiveAnimation::Opacity);
 
     if (toAdd.get()) {
+        // Remove any existing animations with the same animation id and target property.
+        for (size_t i = 0; i < m_activeAnimations.size();) {
+            if (m_activeAnimations[i]->id() == animationId && m_activeAnimations[i]->targetProperty() == toAdd->targetProperty())
+                m_activeAnimations.remove(i);
+            else
+                i++;
+        }
         m_activeAnimations.append(toAdd.release());
         return true;
     }
@@ -149,7 +159,7 @@ void CCLayerAnimationController::pauseAnimation(int animationId, double timeOffs
 {
     for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
         if (m_activeAnimations[i]->id() == animationId)
-            m_activeAnimations[i]->setRunState(CCActiveAnimation::Paused, timeOffset);
+            m_activeAnimations[i]->setRunState(CCActiveAnimation::Paused, timeOffset + m_activeAnimations[i]->startTime());
     }
 }
 
@@ -164,13 +174,21 @@ void CCLayerAnimationController::removeAnimation(int animationId)
 }
 
 // According to render layer backing, these are for testing only.
-void CCLayerAnimationController::suspendAnimations(double time)
+void CCLayerAnimationController::suspendAnimations(double monotonicTime)
 {
+    for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
+        if (m_activeAnimations[i]->runState() != CCActiveAnimation::Finished && m_activeAnimations[i]->runState() != CCActiveAnimation::Aborted)
+            m_activeAnimations[i]->setRunState(CCActiveAnimation::Paused, monotonicTime);
+    }
 }
 
 // Looking at GraphicsLayerCA, this appears to be the analog to suspendAnimations, which is for testing.
-void CCLayerAnimationController::resumeAnimations()
+void CCLayerAnimationController::resumeAnimations(double monotonicTime)
 {
+    for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
+        if (m_activeAnimations[i]->runState() == CCActiveAnimation::Paused)
+            m_activeAnimations[i]->setRunState(CCActiveAnimation::Running, monotonicTime);
+    }
 }
 
 // Ensures that the list of active animations on the main thread and the impl thread
@@ -179,6 +197,7 @@ void CCLayerAnimationController::pushAnimationUpdatesTo(CCLayerAnimationControll
 {
     pushNewAnimationsToImplThread(controllerImpl);
     removeAnimationsCompletedOnMainThread(controllerImpl);
+    pushPropertiesToImplThread(controllerImpl);
 }
 
 void CCLayerAnimationController::animate(double monotonicTime, CCAnimationEventsVector* events)
@@ -197,7 +216,7 @@ void CCLayerAnimationController::add(PassOwnPtr<CCActiveAnimation> animation)
     m_activeAnimations.append(animation);
 }
 
-CCActiveAnimation* CCLayerAnimationController::getActiveAnimation(int groupId, CCActiveAnimation::TargetProperty targetProperty)
+CCActiveAnimation* CCLayerAnimationController::getActiveAnimation(int groupId, CCActiveAnimation::TargetProperty targetProperty) const
 {
     for (size_t i = 0; i < m_activeAnimations.size(); ++i)
         if (m_activeAnimations[i]->group() == groupId && m_activeAnimations[i]->targetProperty() == targetProperty)
@@ -235,7 +254,7 @@ void CCLayerAnimationController::notifyAnimationStarted(const CCAnimationEvent&
     }
 }
 
-void CCLayerAnimationController::pushNewAnimationsToImplThread(CCLayerAnimationController* controllerImpl)
+void CCLayerAnimationController::pushNewAnimationsToImplThread(CCLayerAnimationController* controllerImpl) const
 {
     // Any new animations owned by the main thread's controller are cloned and adde to the impl thread's controller.
     for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
@@ -258,7 +277,7 @@ void CCLayerAnimationController::pushNewAnimationsToImplThread(CCLayerAnimationC
     }
 }
 
-void CCLayerAnimationController::removeAnimationsCompletedOnMainThread(CCLayerAnimationController* controllerImpl)
+void CCLayerAnimationController::removeAnimationsCompletedOnMainThread(CCLayerAnimationController* controllerImpl) const
 {
     // Delete all impl thread animations for which there is no corresponding main thread animation.
     // Each iteration, controller->m_activeAnimations.size() is decremented or i is incremented
@@ -272,6 +291,15 @@ void CCLayerAnimationController::removeAnimationsCompletedOnMainThread(CCLayerAn
     }
 }
 
+void CCLayerAnimationController::pushPropertiesToImplThread(CCLayerAnimationController* controllerImpl) const
+{
+    for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
+        CCActiveAnimation* currentImpl = controllerImpl->getActiveAnimation(m_activeAnimations[i]->group(), m_activeAnimations[i]->targetProperty());
+        if (currentImpl)
+            m_activeAnimations[i]->pushPropertiesTo(currentImpl);
+    }
+}
+
 void CCLayerAnimationController::startAnimationsWaitingForNextTick(double monotonicTime, CCAnimationEventsVector* events)
 {
     for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
@@ -404,7 +432,7 @@ void CCLayerAnimationController::purgeFinishedAnimations(double monotonicTime, C
 void CCLayerAnimationController::tickAnimations(double monotonicTime)
 {
     for (size_t i = 0; i < m_activeAnimations.size(); ++i) {
-        if (m_activeAnimations[i]->runState() == CCActiveAnimation::Running) {
+        if (m_activeAnimations[i]->runState() == CCActiveAnimation::Running || m_activeAnimations[i]->runState() == CCActiveAnimation::Paused) {
             double trimmed = m_activeAnimations[i]->trimTimeToCurrentIteration(monotonicTime);
 
             // Animation assumes its initial value until it gets the synchronized start time
@@ -417,7 +445,7 @@ void CCLayerAnimationController::tickAnimations(double monotonicTime)
             case CCActiveAnimation::Transform: {
                 const CCTransformAnimationCurve* transformAnimationCurve = m_activeAnimations[i]->curve()->toTransformAnimationCurve();
                 const TransformationMatrix matrix = transformAnimationCurve->getValue(trimmed, m_client->bounds());
-                if (m_activeAnimations[i]->isFinishedAt(monotonicTime) && !m_activeAnimations[i]->needsSynchronizedStartTime())
+                if (m_activeAnimations[i]->isFinishedAt(monotonicTime))
                     m_activeAnimations[i]->setRunState(CCActiveAnimation::Finished, monotonicTime);
 
                 m_client->setTransformFromAnimation(matrix);
@@ -427,7 +455,7 @@ void CCLayerAnimationController::tickAnimations(double monotonicTime)
             case CCActiveAnimation::Opacity: {
                 const CCFloatAnimationCurve* floatAnimationCurve = m_activeAnimations[i]->curve()->toFloatAnimationCurve();
                 const float opacity = floatAnimationCurve->getValue(trimmed);
-                if (m_activeAnimations[i]->isFinishedAt(monotonicTime) && !m_activeAnimations[i]->needsSynchronizedStartTime())
+                if (m_activeAnimations[i]->isFinishedAt(monotonicTime))
                     m_activeAnimations[i]->setRunState(CCActiveAnimation::Finished, monotonicTime);
 
                 m_client->setOpacityFromAnimation(opacity);
index 8350741..e22f805 100644 (file)
@@ -64,8 +64,8 @@ public:
     virtual bool addAnimation(const KeyframeValueList&, const IntSize& boxSize, const Animation*, int animationId, int groupId, double timeOffset);
     virtual void pauseAnimation(int animationId, double timeOffset);
     virtual void removeAnimation(int animationId);
-    virtual void suspendAnimations(double time);
-    virtual void resumeAnimations();
+    virtual void suspendAnimations(double monotonicTime);
+    virtual void resumeAnimations(double monotonicTime);
 
     // Ensures that the list of active animations on the main thread and the impl thread
     // are kept in sync. This function does not take ownership of the impl thread controller.
@@ -77,7 +77,7 @@ public:
 
     // Returns the active animation in the given group, animating the given property if such an
     // animation exists.
-    CCActiveAnimation* getActiveAnimation(int groupId, CCActiveAnimation::TargetProperty);
+    CCActiveAnimation* getActiveAnimation(int groupId, CCActiveAnimation::TargetProperty) const;
 
     // Returns true if there are any animations that have neither finished nor aborted.
     bool hasActiveAnimation() const;
@@ -96,8 +96,9 @@ protected:
 private:
     typedef HashSet<int> TargetProperties;
 
-    void pushNewAnimationsToImplThread(CCLayerAnimationController*);
-    void removeAnimationsCompletedOnMainThread(CCLayerAnimationController*);
+    void pushNewAnimationsToImplThread(CCLayerAnimationController*) const;
+    void removeAnimationsCompletedOnMainThread(CCLayerAnimationController*) const;
+    void pushPropertiesToImplThread(CCLayerAnimationController*) const;
 
     void startAnimationsWaitingForNextTick(double monotonicTime, CCAnimationEventsVector*);
     void startAnimationsWaitingForStartTime(double monotonicTime, CCAnimationEventsVector*);
index d7ddd54..989e5e8 100644 (file)
@@ -1,3 +1,17 @@
+2012-04-27  Ian Vollick  <vollick@chromium.org>
+
+        [chromium] Add pause and resume support for accelerated css animations.
+        https://bugs.webkit.org/show_bug.cgi?id=84601
+
+        Reviewed by James Robinson.
+
+        * tests/CCActiveAnimationTest.cpp:
+        (WebCore::TEST):
+        (WebCore):
+        * tests/CCLayerAnimationControllerTest.cpp:
+        (WebKitTests::TEST):
+        (WebKitTests):
+
 2012-04-26  James Robinson  <jamesr@chromium.org>
 
         [chromium] Separate IOSurface layer type from texture layers
index e14ef9b..a1ab770 100644 (file)
@@ -80,6 +80,17 @@ TEST(CCActiveAnimationTest, TrimTimeStartTime)
     EXPECT_EQ(1, anim->trimTimeToCurrentIteration(6));
 }
 
+TEST(CCActiveAnimationTest, TrimTimeTimeOffset)
+{
+    OwnPtr<CCActiveAnimation> anim(createActiveAnimation(1));
+    anim->setTimeOffset(4);
+    anim->setStartTime(4);
+    EXPECT_EQ(0, anim->trimTimeToCurrentIteration(0));
+    EXPECT_EQ(0.5, anim->trimTimeToCurrentIteration(0.5));
+    EXPECT_EQ(1, anim->trimTimeToCurrentIteration(1));
+    EXPECT_EQ(1, anim->trimTimeToCurrentIteration(1));
+}
+
 TEST(CCActiveAnimationTest, TrimTimePauseResume)
 {
     OwnPtr<CCActiveAnimation> anim(createActiveAnimation(1));
@@ -93,6 +104,19 @@ TEST(CCActiveAnimationTest, TrimTimePauseResume)
     EXPECT_EQ(1, anim->trimTimeToCurrentIteration(1024.5));
 }
 
+TEST(CCActiveAnimationTest, TrimTimeSuspendResume)
+{
+    OwnPtr<CCActiveAnimation> anim(createActiveAnimation(1));
+    anim->setRunState(CCActiveAnimation::Running, 0);
+    EXPECT_EQ(0, anim->trimTimeToCurrentIteration(0));
+    EXPECT_EQ(0.5, anim->trimTimeToCurrentIteration(0.5));
+    anim->suspend(0.5);
+    EXPECT_EQ(0.5, anim->trimTimeToCurrentIteration(1024));
+    anim->resume(1024);
+    EXPECT_EQ(0.5, anim->trimTimeToCurrentIteration(1024));
+    EXPECT_EQ(1, anim->trimTimeToCurrentIteration(1024.5));
+}
+
 TEST(CCActiveAnimationTest, IsFinishedAtZeroIterations)
 {
     OwnPtr<CCActiveAnimation> anim(createActiveAnimation(0));
@@ -160,4 +184,35 @@ TEST(CCActiveAnimationTest, IsFinished)
     EXPECT_TRUE(anim->isFinished());
 }
 
+TEST(CCActiveAnimationTest, IsFinishedNeedsSynchronizedStartTime)
+{
+    OwnPtr<CCActiveAnimation> anim(createActiveAnimation(1));
+    anim->setRunState(CCActiveAnimation::Running, 2);
+    EXPECT_FALSE(anim->isFinished());
+    anim->setRunState(CCActiveAnimation::Paused, 2);
+    EXPECT_FALSE(anim->isFinished());
+    anim->setRunState(CCActiveAnimation::WaitingForNextTick, 2);
+    EXPECT_FALSE(anim->isFinished());
+    anim->setRunState(CCActiveAnimation::WaitingForTargetAvailability, 2);
+    EXPECT_FALSE(anim->isFinished());
+    anim->setRunState(CCActiveAnimation::WaitingForStartTime, 2);
+    EXPECT_FALSE(anim->isFinished());
+    anim->setRunState(CCActiveAnimation::Finished, 0);
+    EXPECT_TRUE(anim->isFinished());
+    anim->setRunState(CCActiveAnimation::Aborted, 0);
+    EXPECT_TRUE(anim->isFinished());
+}
+
+TEST(CCActiveAnimationTest, RunStateChangesIgnoredWhileSuspended)
+{
+    OwnPtr<CCActiveAnimation> anim(createActiveAnimation(1));
+    anim->suspend(0);
+    EXPECT_EQ(CCActiveAnimation::Paused, anim->runState());
+    anim->setRunState(CCActiveAnimation::Running, 0);
+    EXPECT_EQ(CCActiveAnimation::Paused, anim->runState());
+    anim->resume(0);
+    anim->setRunState(CCActiveAnimation::Running, 0);
+    EXPECT_EQ(CCActiveAnimation::Running, anim->runState());
+}
+
 } // namespace
index 7cb3953..fa95a2a 100644 (file)
@@ -199,6 +199,47 @@ TEST(CCLayerAnimationControllerTest, doNotClobberStartTimes)
     EXPECT_EQ(controller->getActiveAnimation(0, CCActiveAnimation::Opacity)->startTime(), controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)->startTime());
 }
 
+TEST(CCLayerAnimationControllerTest, syncPauseAndResume)
+{
+    FakeLayerAnimationControllerClient dummyImpl;
+    OwnPtr<CCLayerAnimationController> controllerImpl(CCLayerAnimationController::create(&dummyImpl));
+    FakeLayerAnimationControllerClient dummy;
+    OwnPtr<CCLayerAnimationController> controller(CCLayerAnimationController::create(&dummy));
+
+    EXPECT_FALSE(controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity));
+
+    addOpacityTransitionToController(*controller, 1, 0, 1, false);
+
+    controller->pushAnimationUpdatesTo(controllerImpl.get());
+
+    EXPECT_TRUE(controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity));
+    EXPECT_EQ(CCActiveAnimation::WaitingForTargetAvailability, controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)->runState());
+
+    // Start the animations on each controller.
+    CCAnimationEventsVector events;
+    controllerImpl->animate(0, &events);
+    controller->animate(0, 0);
+    EXPECT_EQ(CCActiveAnimation::Running, controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)->runState());
+    EXPECT_EQ(CCActiveAnimation::Running, controller->getActiveAnimation(0, CCActiveAnimation::Opacity)->runState());
+
+    // Pause the main-thread animation.
+    controller->suspendAnimations(1);
+    EXPECT_EQ(CCActiveAnimation::Paused, controller->getActiveAnimation(0, CCActiveAnimation::Opacity)->runState());
+
+    // The pause run state change should make it to the impl thread controller.
+    controller->pushAnimationUpdatesTo(controllerImpl.get());
+    EXPECT_EQ(CCActiveAnimation::Paused, controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)->runState());
+
+    // Resume the main-thread animation.
+    controller->resumeAnimations(2);
+    EXPECT_EQ(CCActiveAnimation::Running, controller->getActiveAnimation(0, CCActiveAnimation::Opacity)->runState());
+
+    // The pause run state change should make it to the impl thread controller.
+    controller->pushAnimationUpdatesTo(controllerImpl.get());
+    EXPECT_EQ(CCActiveAnimation::Running, controllerImpl->getActiveAnimation(0, CCActiveAnimation::Opacity)->runState());
+}
+
+
 TEST(CCLayerAnimationControllerTest, doNotSyncFinishedAnimation)
 {
     FakeLayerAnimationControllerClient dummyImpl;