Animations and Transitions should not start when globally suspended
authordino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 5 May 2013 04:43:05 +0000 (04:43 +0000)
committerdino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 5 May 2013 04:43:05 +0000 (04:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=114915

Reviewed by Sam Weinig.

.:

Export AnimationController::isSuspended().

* Source/autotools/symbols.filter:

Source/WebCore:

When the Document's AnimationController was suspended, we still
started new transitions and animations. Change this so that
animations enter a paused-but-new state, where they are frozen
until the AnimationController resumes. At that time, it is as
if they had just appeared: any delay counts down before
the animation starts.

For transitions, the change in value must still happen, but
it does so immediately. No transitionend event should be fired.
This produces a slightly confusing behaviour, because any
in-progress transitions are suspended, but any new style changes
happen instantly. This might sound contradictory, but in general
suspending the document is a rare (and dangerous) thing to do.

Previously, the Document would call resumeAnimations as it loaded,
effectively starting all the animations. This meant if you suspended
animations before loading a document, it was ignored as soon as the
load finished. Now there is a separate method startAnimationsIfNotSuspended
which checks to see if the document is suspended as it loads.

In order to handle this case, I added a new state to the Animation
machinery: AnimationStatePausedNew. This is an animation that was created
in the suspended state.

Tests: animations/added-while-suspended.html
       transitions/started-while-suspended.html

* WebCore.exp.in: Export AnimationController::isSuspended().

* dom/Document.cpp:
(WebCore::Document::implicitClose):
    resumeAnimationsForDocument() -> startAnimationsIfNotSuspended()

* page/animation/AnimationBase.cpp:
(WebCore::nameForState): New name for AnimationStatePausedNew.
(WebCore::AnimationBase::updateStateMachine): Handle new state AnimationStatePausedNew. The
    most important change is that when go from PausedNew to Running, we jump back into
    the New state and continue from there.
(WebCore::AnimationBase::updatePlayState): suspended -> isSuspended
* page/animation/AnimationBase.h: New state: AnimationStatePausedNew
(WebCore::AnimationBase::waitingToStart): Add AnimationStatePausedNew.
(WebCore::AnimationBase::paused): Add AnimationStatePausedNew.
(WebCore::AnimationBase::isNew): Add AnimationStatePausedNew.

* page/animation/AnimationController.cpp:
(WebCore::AnimationControllerPrivate::AnimationControllerPrivate): Initialise m_suspended.
(WebCore::AnimationControllerPrivate::clear): suspended -> isSuspended
(WebCore::AnimationControllerPrivate::updateAnimations): Ditto.
(WebCore::AnimationControllerPrivate::updateAnimationTimerForRenderer): Ditto.
(WebCore::AnimationControllerPrivate::suspendAnimations): Update m_suspended.
(WebCore::AnimationControllerPrivate::resumeAnimations): Ditto.
(WebCore::AnimationControllerPrivate::suspendAnimationsForDocument):
(WebCore::AnimationControllerPrivate::resumeAnimationsForDocument):
(WebCore::AnimationControllerPrivate::startAnimationsIfNotSuspended): New method that will
    only resume animations if we were not globally suspended.
(WebCore::AnimationController::isSuspended): New method.
(WebCore::AnimationController::suspendAnimations): Add logging.
(WebCore::AnimationController::resumeAnimations): Add logging.
(WebCore::AnimationController::suspendAnimationsForDocument): Add logging.
(WebCore::AnimationController::resumeAnimationsForDocument): Add logging.
(WebCore::AnimationController::startAnimationsIfNotSuspended): Calls private method.
* page/animation/AnimationController.h:
(AnimationController): Add isSuspended() and animationsForDocumentMayStart().
* page/animation/AnimationControllerPrivate.h:
(WebCore::AnimationControllerPrivate::isSuspended): New method.
(AnimationControllerPrivate): Add m_isSuspended member.

* page/animation/CompositeAnimation.cpp:
(WebCore::CompositeAnimation::CompositeAnimation): Moved from header - initialise m_isSuspended.
(WebCore::CompositeAnimation::updateTransitions): Do not create ImplicitAnimation if suspended.
(WebCore::CompositeAnimation::updateKeyframeAnimations): Move to AnimationStatePausedNew if suspended.
(WebCore::CompositeAnimation::suspendAnimations): m_suspended -> m_isSuspended
(WebCore::CompositeAnimation::resumeAnimations): Ditto.
* page/animation/CompositeAnimation.h:
(WebCore::CompositeAnimation::isSuspended): Renamed from suspended()

* page/animation/KeyframeAnimation.cpp:
(WebCore::KeyframeAnimation::animate): If we're in the AnimationStatePausedNew state, then
    we need to go to the first frame (to handle fill mode).

* testing/Internals.cpp:
(WebCore::Internals::animationsAreSuspended): New exposed method to reflect AnimationController.
* testing/Internals.h: Add animationsAreSuspended.
* testing/Internals.idl: Ditto.

Source/WebKit:

Export AnimationController::isSuspended

* WebKit.vcxproj/WebKitExportGenerator/WebKitExports.def.in:

Source/WebKit/mac:

The WebView private API cssAnimationsSuspended did not necessarily
reflect the reality of the Frame's AnimationController value because it
was caching rather than asking directly. While the WebCore part of this
patch ensured loading the Document wouldn't resume all animations, it
is still better to ask directly.

* WebView/WebView.mm:
(-[WebView cssAnimationsSuspended]): Call into AnimationController.
(-[WebView setCSSAnimationsSuspended:]): Ditto.
* WebView/WebViewData.h: Remove cssAnimationsSuspended boolean.
* WebView/WebViewData.mm: Ditto.
(-[WebViewPrivate init]):

Source/WebKit/win:

Export AnimationController::isSuspended

* WebKit.vcproj/WebKitExports.def.in:

LayoutTests:

Two new tests. Add an animation or transition to
the document when the global animation controller is suspended.
In the animation case, nothing should happen until the
animations are resumed. In the transition case, the style
change should happen immediately and not fire any events.

* animations/added-while-suspended-expected.txt: Added.
* animations/added-while-suspended.html: Added.
* animations/suspend-transform-animation.html: Make sure to resume suspended animations
    before quitting the test.
* transitions/started-while-suspended-expected.txt: Added.
* transitions/started-while-suspended.html: Added.
* transitions/suspend-transform-transition.html: Make sure to resume suspended animations
    before quitting the test.

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

30 files changed:
ChangeLog
LayoutTests/ChangeLog
LayoutTests/animations/added-while-suspended-expected.txt [new file with mode: 0644]
LayoutTests/animations/added-while-suspended.html [new file with mode: 0644]
LayoutTests/animations/suspend-transform-animation.html
LayoutTests/transitions/started-while-suspended-expected.txt [new file with mode: 0644]
LayoutTests/transitions/started-while-suspended.html [new file with mode: 0644]
LayoutTests/transitions/suspend-transform-transition.html
Source/WebCore/ChangeLog
Source/WebCore/WebCore.exp.in
Source/WebCore/dom/Document.cpp
Source/WebCore/page/animation/AnimationBase.cpp
Source/WebCore/page/animation/AnimationBase.h
Source/WebCore/page/animation/AnimationController.cpp
Source/WebCore/page/animation/AnimationController.h
Source/WebCore/page/animation/AnimationControllerPrivate.h
Source/WebCore/page/animation/CompositeAnimation.cpp
Source/WebCore/page/animation/CompositeAnimation.h
Source/WebCore/page/animation/KeyframeAnimation.cpp
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h
Source/WebCore/testing/Internals.idl
Source/WebKit/ChangeLog
Source/WebKit/mac/ChangeLog
Source/WebKit/mac/WebView/WebView.mm
Source/WebKit/mac/WebView/WebViewData.h
Source/WebKit/mac/WebView/WebViewData.mm
Source/WebKit/win/ChangeLog
Source/WebKit/win/WebKit.vcproj/WebKitExports.def.in
Source/autotools/symbols.filter

index 999d90f..93e20ab 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2013-04-30  Dean Jackson  <dino@apple.com>
+
+        Animations and Transitions should not start when globally suspended
+        https://bugs.webkit.org/show_bug.cgi?id=114915
+
+        Reviewed by Sam Weinig.
+
+        Export AnimationController::isSuspended().
+
+        * Source/autotools/symbols.filter:
+
 2013-05-01  Benjamin Poulain  <benjamin@webkit.org>
 
         Remove the remaining wscript
 2013-05-01  Benjamin Poulain  <benjamin@webkit.org>
 
         Remove the remaining wscript
index f1af78f..759d0dc 100644 (file)
@@ -1,3 +1,25 @@
+2013-04-30  Dean Jackson  <dino@apple.com>
+
+        Animations and Transitions should not start when globally suspended
+        https://bugs.webkit.org/show_bug.cgi?id=114915
+
+        Reviewed by Sam Weinig.
+
+        Two new tests. Add an animation or transition to
+        the document when the global animation controller is suspended.
+        In the animation case, nothing should happen until the
+        animations are resumed. In the transition case, the style
+        change should happen immediately and not fire any events.
+
+        * animations/added-while-suspended-expected.txt: Added.
+        * animations/added-while-suspended.html: Added.
+        * animations/suspend-transform-animation.html: Make sure to resume suspended animations
+            before quitting the test.
+        * transitions/started-while-suspended-expected.txt: Added.
+        * transitions/started-while-suspended.html: Added.
+        * transitions/suspend-transform-transition.html: Make sure to resume suspended animations
+            before quitting the test.
+
 2013-04-30  Robert Hogan  <robert@webkit.org>
 
         REGRESSION(r140907): Incorrect baseline on cells after updating vertical-align
 2013-04-30  Robert Hogan  <robert@webkit.org>
 
         REGRESSION(r140907): Incorrect baseline on cells after updating vertical-align
diff --git a/LayoutTests/animations/added-while-suspended-expected.txt b/LayoutTests/animations/added-while-suspended-expected.txt
new file mode 100644 (file)
index 0000000..6b01baa
--- /dev/null
@@ -0,0 +1,15 @@
+This test adds some elements to the document when animations should be paused. It will only have reproducible output when run in the test system
+
+Animations should not be suspended: PASS
+*** Suspending Animations
+Animations should be suspended: PASS
+*** Adding first box with animation
+*** Adding second box with animation and delay
+*** Resuming Animations
+Animation started on element with id: box
+Animation ended on element with id: box
+Animation started on element with id: box-with-delay
+Animation ended on element with id: box-with-delay
+Animations should not be suspended: PASS
+*** Animations finished
+
diff --git a/LayoutTests/animations/added-while-suspended.html b/LayoutTests/animations/added-while-suspended.html
new file mode 100644 (file)
index 0000000..de1c189
--- /dev/null
@@ -0,0 +1,127 @@
+<title>Test that new animations do not run while we are suspended</title>
+<style>
+#box {
+    position: relative;
+    height: 100px;
+    width: 100px;
+    background-color: blue;
+    -webkit-animation-name: move;
+    -webkit-animation-duration: 0.1s;
+}
+
+#box-with-delay {
+    position: relative;
+    height: 100px;
+    width: 100px;
+    background-color: blue;
+    -webkit-animation-name: move;
+    -webkit-animation-duration: 0.1s;
+    -webkit-animation-delay: 0.3s;
+}
+
+@-webkit-keyframes move {
+    from { left: 0; }
+    to { left: 500px; }
+}
+</style>
+<script>
+
+var animationsYetToEnd = 2;
+
+function suspend()
+{
+    if (window.internals)
+        internals.suspendAnimations(document);
+}
+
+function resume()
+{
+    if (window.internals)
+        internals.resumeAnimations(document);
+}
+
+function animationStarted(event)
+{
+    log("Animation started on element with id: " + event.target.id);
+}
+
+function animationEnded(event)
+{
+    log("Animation ended on element with id: " + event.target.id);
+    animationsYetToEnd--;
+    if (!animationsYetToEnd)
+        endTest();
+}
+
+function addDivWithId(id)
+{
+    var div = document.createElement("div");
+    div.id = id;
+    document.body.appendChild(div);
+}
+
+function addFirstBox()
+{
+    if (window.internals)
+        log("Animations should be suspended: " + (window.internals.animationsAreSuspended(document) ? "PASS" : "FAIL"));
+
+    log("*** Adding first box with animation");
+    addDivWithId("box");
+    setTimeout(addSecondBox, 100);
+}
+
+function addSecondBox()
+{
+    log("*** Adding second box with animation and delay");
+    addDivWithId("box-with-delay");
+    setTimeout(resumeAndContinue, 50);
+}
+
+function resumeAndContinue()
+{
+    log("*** Resuming Animations");
+    resume();
+}
+
+function endTest()
+{
+    if (window.internals)
+        log("Animations should not be suspended: " + (window.internals.animationsAreSuspended(document) ? "FAIL" : "PASS"));
+    log("*** Animations finished");
+    resume(); // Just in case.
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+function startTest()
+{
+    document.addEventListener("webkitAnimationStart", animationStarted, false);
+    document.addEventListener("webkitAnimationEnd", animationEnded, false);
+
+    if (window.internals)
+        log("Animations should not be suspended: " + (window.internals.animationsAreSuspended(document) ? "FAIL" : "PASS"));
+
+    setTimeout(function() {
+        log("*** Suspending Animations");
+        suspend();
+        setTimeout(addFirstBox, 50);
+    }, 50);
+}
+
+function log(message)
+{
+    var results = document.getElementById("results");
+    results.innerHTML = results.innerHTML + message + "<br>";
+}
+
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+    testRunner.dumpAsText();
+}
+
+window.addEventListener("load", startTest, false);
+
+</script>
+<p>This test adds some elements to the document when animations should be paused. It will only have reproducible output when run in the test system</p>
+<div id="results">
+</div>
index c5b3f72..46c6f71 100644 (file)
             internals.suspendAnimations(document);
 
         window.setTimeout(function() {
             internals.suspendAnimations(document);
 
         window.setTimeout(function() {
-            if (window.testRunner)
+            if (window.testRunner) {
+                internals.resumeAnimations(document);
                 testRunner.notifyDone();
                 testRunner.notifyDone();
+            }
         }, 250);
     }
     
         }, 250);
     }
     
diff --git a/LayoutTests/transitions/started-while-suspended-expected.txt b/LayoutTests/transitions/started-while-suspended-expected.txt
new file mode 100644 (file)
index 0000000..bd8a6bf
--- /dev/null
@@ -0,0 +1,13 @@
+This test sets the left property on the box below. It will only have reproducible output when run in the test system
+
+*** Starting test.
+Transitions should not be suspended: PASS
+*** Setting left property to 100px. We should see transition events.
+Transition ended on element with id: box
+*** Suspending Animations/Transitions
+Transitions should be suspended: PASS
+*** Setting left property to 200px. We should NOT see transition events.
+*** Resuming Animations/Transitions
+Transitions should not be suspended: PASS
+*** Test finished
+
diff --git a/LayoutTests/transitions/started-while-suspended.html b/LayoutTests/transitions/started-while-suspended.html
new file mode 100644 (file)
index 0000000..6145315
--- /dev/null
@@ -0,0 +1,100 @@
+<title>Test that new transitions do not run while we are suspended</title>
+<style>
+#box {
+    position: relative;
+    left: 0px;
+    height: 100px;
+    width: 100px;
+    background-color: blue;
+    -webkit-transition: left 0.1s;
+}
+</style>
+<script>
+var box;
+
+function suspend()
+{
+    if (window.internals)
+        internals.suspendAnimations(document);
+}
+
+function resume()
+{
+    if (window.internals)
+        internals.resumeAnimations(document);
+}
+
+function transitionEnded(event)
+{
+    log("Transition ended on element with id: " + event.target.id);
+}
+
+function suspendAndContinue()
+{
+    log("*** Suspending Animations/Transitions");
+    suspend();
+    setTimeout(function() {
+        if (window.internals)
+            log("Transitions should be suspended: " + (window.internals.animationsAreSuspended(document) ? "PASS" : "FAIL"));
+        log("*** Setting left property to 200px. We should NOT see transition events.")
+        box.style.left = "200px";
+        setTimeout(function() {
+            endTest();
+        }, 200);
+    }, 100);
+}
+
+function resumeAndContinue()
+{
+}
+
+function endTest()
+{
+    log("*** Resuming Animations/Transitions");
+    resume();
+    if (window.internals)
+        log("Transitions should not be suspended: " + (window.internals.animationsAreSuspended(document) ? "FAIL" : "PASS"));
+
+    resume(); // Just in case.
+    log("*** Test finished");
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+function startTest()
+{
+    log("*** Starting test.")
+
+    box = document.getElementById("box");
+    document.addEventListener("webkitTransitionEnd", transitionEnded, false);
+
+    if (window.internals)
+        log("Transitions should not be suspended: " + (window.internals.animationsAreSuspended(document) ? "FAIL" : "PASS"));
+
+    setTimeout(function() {
+        log("*** Setting left property to 100px. We should see transition events.")
+        box.style.left = "100px";
+        setTimeout(function() {
+            suspendAndContinue();
+        }, 200);
+    }, 50);
+}
+
+function log(message)
+{
+    var results = document.getElementById("results");
+    results.innerHTML = results.innerHTML + message + "<br>";
+}
+
+if (window.testRunner) {
+    testRunner.waitUntilDone();
+    testRunner.dumpAsText();
+}
+
+window.addEventListener("load", startTest, false);
+
+</script>
+<p>This test sets the left property on the box below. It will only have reproducible output when run in the test system</p>
+<div id="box"></div>
+<div id="results">
+</div>
index 208a95c..9d75a2c 100644 (file)
             internals.suspendAnimations(document);
 
         window.setTimeout(function() {
             internals.suspendAnimations(document);
 
         window.setTimeout(function() {
-            if (window.testRunner)
+            if (window.testRunner) {
+                internals.resumeAnimations(document);
                 testRunner.notifyDone();
                 testRunner.notifyDone();
+            }
         }, 250);
     }
     
         }, 250);
     }
     
index b63a2d1..e1c5e2a 100644 (file)
@@ -1,3 +1,95 @@
+2013-04-30  Dean Jackson  <dino@apple.com>
+
+        Animations and Transitions should not start when globally suspended
+        https://bugs.webkit.org/show_bug.cgi?id=114915
+
+        Reviewed by Sam Weinig.
+
+        When the Document's AnimationController was suspended, we still
+        started new transitions and animations. Change this so that
+        animations enter a paused-but-new state, where they are frozen
+        until the AnimationController resumes. At that time, it is as
+        if they had just appeared: any delay counts down before
+        the animation starts.
+
+        For transitions, the change in value must still happen, but
+        it does so immediately. No transitionend event should be fired.
+        This produces a slightly confusing behaviour, because any
+        in-progress transitions are suspended, but any new style changes
+        happen instantly. This might sound contradictory, but in general
+        suspending the document is a rare (and dangerous) thing to do.
+
+        Previously, the Document would call resumeAnimations as it loaded,
+        effectively starting all the animations. This meant if you suspended
+        animations before loading a document, it was ignored as soon as the
+        load finished. Now there is a separate method startAnimationsIfNotSuspended
+        which checks to see if the document is suspended as it loads.
+
+        In order to handle this case, I added a new state to the Animation
+        machinery: AnimationStatePausedNew. This is an animation that was created
+        in the suspended state.
+
+        Tests: animations/added-while-suspended.html
+               transitions/started-while-suspended.html
+
+        * WebCore.exp.in: Export AnimationController::isSuspended().
+
+        * dom/Document.cpp:
+        (WebCore::Document::implicitClose):
+            resumeAnimationsForDocument() -> startAnimationsIfNotSuspended()
+
+        * page/animation/AnimationBase.cpp:
+        (WebCore::nameForState): New name for AnimationStatePausedNew.
+        (WebCore::AnimationBase::updateStateMachine): Handle new state AnimationStatePausedNew. The
+            most important change is that when go from PausedNew to Running, we jump back into
+            the New state and continue from there.
+        (WebCore::AnimationBase::updatePlayState): suspended -> isSuspended
+        * page/animation/AnimationBase.h: New state: AnimationStatePausedNew
+        (WebCore::AnimationBase::waitingToStart): Add AnimationStatePausedNew.
+        (WebCore::AnimationBase::paused): Add AnimationStatePausedNew.
+        (WebCore::AnimationBase::isNew): Add AnimationStatePausedNew.
+
+        * page/animation/AnimationController.cpp:
+        (WebCore::AnimationControllerPrivate::AnimationControllerPrivate): Initialise m_suspended.
+        (WebCore::AnimationControllerPrivate::clear): suspended -> isSuspended
+        (WebCore::AnimationControllerPrivate::updateAnimations): Ditto.
+        (WebCore::AnimationControllerPrivate::updateAnimationTimerForRenderer): Ditto.
+        (WebCore::AnimationControllerPrivate::suspendAnimations): Update m_suspended.
+        (WebCore::AnimationControllerPrivate::resumeAnimations): Ditto.
+        (WebCore::AnimationControllerPrivate::suspendAnimationsForDocument):
+        (WebCore::AnimationControllerPrivate::resumeAnimationsForDocument):
+        (WebCore::AnimationControllerPrivate::startAnimationsIfNotSuspended): New method that will
+            only resume animations if we were not globally suspended.
+        (WebCore::AnimationController::isSuspended): New method.
+        (WebCore::AnimationController::suspendAnimations): Add logging.
+        (WebCore::AnimationController::resumeAnimations): Add logging.
+        (WebCore::AnimationController::suspendAnimationsForDocument): Add logging.
+        (WebCore::AnimationController::resumeAnimationsForDocument): Add logging.
+        (WebCore::AnimationController::startAnimationsIfNotSuspended): Calls private method.
+        * page/animation/AnimationController.h:
+        (AnimationController): Add isSuspended() and animationsForDocumentMayStart().
+        * page/animation/AnimationControllerPrivate.h:
+        (WebCore::AnimationControllerPrivate::isSuspended): New method.
+        (AnimationControllerPrivate): Add m_isSuspended member.
+
+        * page/animation/CompositeAnimation.cpp:
+        (WebCore::CompositeAnimation::CompositeAnimation): Moved from header - initialise m_isSuspended.
+        (WebCore::CompositeAnimation::updateTransitions): Do not create ImplicitAnimation if suspended.
+        (WebCore::CompositeAnimation::updateKeyframeAnimations): Move to AnimationStatePausedNew if suspended.
+        (WebCore::CompositeAnimation::suspendAnimations): m_suspended -> m_isSuspended
+        (WebCore::CompositeAnimation::resumeAnimations): Ditto.
+        * page/animation/CompositeAnimation.h:
+        (WebCore::CompositeAnimation::isSuspended): Renamed from suspended()
+
+        * page/animation/KeyframeAnimation.cpp:
+        (WebCore::KeyframeAnimation::animate): If we're in the AnimationStatePausedNew state, then
+            we need to go to the first frame (to handle fill mode).
+
+        * testing/Internals.cpp:
+        (WebCore::Internals::animationsAreSuspended): New exposed method to reflect AnimationController.
+        * testing/Internals.h: Add animationsAreSuspended.
+        * testing/Internals.idl: Ditto.
+
 2013-05-04  Sam Weinig  <sam@webkit.org>
 
         Move PopupMenuMac and SearchPopupMenuMac to Source/WebKit/mac
 2013-05-04  Sam Weinig  <sam@webkit.org>
 
         Move PopupMenuMac and SearchPopupMenuMac to Source/WebKit/mac
index b7f63fd..d401501 100644 (file)
@@ -602,6 +602,7 @@ __ZN7WebCore18isStartOfParagraphERKNS_15VisiblePositionENS_27EditingBoundaryCros
 __ZN7WebCore18makeAllDirectoriesERKN3WTF6StringE
 __ZN7WebCore18pluginScriptObjectEPN3JSC9ExecStateEPNS_13JSHTMLElementE
 __ZN7WebCore18proxyServersForURLERKNS_4KURLEPKNS_17NetworkingContextE
 __ZN7WebCore18makeAllDirectoriesERKN3WTF6StringE
 __ZN7WebCore18pluginScriptObjectEPN3JSC9ExecStateEPNS_13JSHTMLElementE
 __ZN7WebCore18proxyServersForURLERKNS_4KURLEPKNS_17NetworkingContextE
+__ZNK7WebCore19AnimationController11isSuspendedEv
 __ZN7WebCore19AnimationController16resumeAnimationsEv
 __ZN7WebCore19AnimationController17suspendAnimationsEv
 __ZN7WebCore19AnimationController20pauseAnimationAtTimeEPNS_12RenderObjectERKN3WTF12AtomicStringEd
 __ZN7WebCore19AnimationController16resumeAnimationsEv
 __ZN7WebCore19AnimationController17suspendAnimationsEv
 __ZN7WebCore19AnimationController20pauseAnimationAtTimeEPNS_12RenderObjectERKN3WTF12AtomicStringEd
index 1d6df85..c23d3e8 100644 (file)
@@ -2396,7 +2396,7 @@ void Document::implicitClose()
     Frame* f = frame();
     if (f) {
         f->loader()->icon()->startLoader();
     Frame* f = frame();
     if (f) {
         f->loader()->icon()->startLoader();
-        f->animation()->resumeAnimationsForDocument(this);
+        f->animation()->startAnimationsIfNotSuspended(this);
     }
 
     ImageLoader::dispatchPendingBeforeLoadEvents();
     }
 
     ImageLoader::dispatchPendingBeforeLoadEvents();
index 796e7c7..8da678b 100644 (file)
@@ -122,6 +122,7 @@ static const char* nameForState(AnimationBase::AnimState state)
     case AnimationBase::AnimationStateStartWaitResponse: return "StartWaitResponse";
     case AnimationBase::AnimationStateLooping: return "Looping";
     case AnimationBase::AnimationStateEnding: return "Ending";
     case AnimationBase::AnimationStateStartWaitResponse: return "StartWaitResponse";
     case AnimationBase::AnimationStateLooping: return "Looping";
     case AnimationBase::AnimationStateEnding: return "Ending";
+    case AnimationBase::AnimationStatePausedNew: return "PausedNew";
     case AnimationBase::AnimationStatePausedWaitTimer: return "PausedWaitTimer";
     case AnimationBase::AnimationStatePausedWaitStyleAvailable: return "PausedWaitStyleAvailable";
     case AnimationBase::AnimationStatePausedWaitResponse: return "PausedWaitResponse";
     case AnimationBase::AnimationStatePausedWaitTimer: return "PausedWaitTimer";
     case AnimationBase::AnimationStatePausedWaitStyleAvailable: return "PausedWaitStyleAvailable";
     case AnimationBase::AnimationStatePausedWaitResponse: return "PausedWaitResponse";
@@ -203,6 +204,10 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
                 m_requestedStartTime = beginAnimationUpdateTime();
                 LOG(Animations, "%p AnimationState %s -> StartWaitTimer", this, nameForState(m_animState));
                 m_animState = AnimationStateStartWaitTimer;
                 m_requestedStartTime = beginAnimationUpdateTime();
                 LOG(Animations, "%p AnimationState %s -> StartWaitTimer", this, nameForState(m_animState));
                 m_animState = AnimationStateStartWaitTimer;
+            } else {
+                // We are pausing before we even started.
+                LOG(Animations, "%p AnimationState %s -> AnimationStatePausedNew", this, nameForState(m_animState));
+                m_animState = AnimationStatePausedNew;
             }
             break;
         case AnimationStateStartWaitTimer:
             }
             break;
         case AnimationStateStartWaitTimer:
@@ -355,6 +360,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
             m_animState = AnimationStateNew;
             updateStateMachine(AnimationStateInputStartAnimation, 0);
             break;
             m_animState = AnimationStateNew;
             updateStateMachine(AnimationStateInputStartAnimation, 0);
             break;
+        case AnimationStatePausedNew:
         case AnimationStatePausedWaitResponse:
         case AnimationStatePausedWaitStyleAvailable:
         case AnimationStatePausedRun:
         case AnimationStatePausedWaitResponse:
         case AnimationStatePausedWaitStyleAvailable:
         case AnimationStatePausedRun:
@@ -362,10 +368,19 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
             // AnimationStatePausedWaitResponse, we don't yet have a valid startTime, so we send 0 to startAnimation.
             // When the AnimationStateInputStartTimeSet comes in and we were in AnimationStatePausedRun, we will notice
             // that we have already set the startTime and will ignore it.
             // AnimationStatePausedWaitResponse, we don't yet have a valid startTime, so we send 0 to startAnimation.
             // When the AnimationStateInputStartTimeSet comes in and we were in AnimationStatePausedRun, we will notice
             // that we have already set the startTime and will ignore it.
-            ASSERT(input == AnimationStateInputPlayStateRunning || input == AnimationStateInputStartTimeSet || input == AnimationStateInputStyleAvailable);
+            ASSERT(input == AnimationStateInputPlayStateRunning || input == AnimationStateInputStartTimeSet || input == AnimationStateInputStyleAvailable || input == AnimationStateInputStartAnimation);
             ASSERT(paused());
             ASSERT(paused());
-            
+
             if (input == AnimationStateInputPlayStateRunning) {
             if (input == AnimationStateInputPlayStateRunning) {
+                if (m_animState == AnimationStatePausedNew) {
+                    // We were paused before we even started, and now we're supposed
+                    // to start, so jump back to the New state and reset.
+                    LOG(Animations, "%p AnimationState %s -> AnimationStateNew", this, nameForState(m_animState));
+                    m_animState = AnimationStateNew;
+                    updateStateMachine(input, param);
+                    break;
+                }
+
                 // Update the times
                 if (m_animState == AnimationStatePausedRun)
                     m_startTime += beginAnimationUpdateTime() - m_pauseTime;
                 // Update the times
                 if (m_animState == AnimationStatePausedRun)
                     m_startTime += beginAnimationUpdateTime() - m_pauseTime;
@@ -410,7 +425,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
                 m_pauseTime += m_startTime;
                 break;
             }
                 m_pauseTime += m_startTime;
                 break;
             }
-            
+
             ASSERT(m_animState == AnimationStatePausedWaitStyleAvailable);
             // We are paused but we got the callback that notifies us that style has been updated.
             // We move to the AnimationStatePausedWaitResponse state
             ASSERT(m_animState == AnimationStatePausedWaitStyleAvailable);
             // We are paused but we got the callback that notifies us that style has been updated.
             // We move to the AnimationStatePausedWaitResponse state
@@ -491,11 +506,11 @@ void AnimationBase::updatePlayState(EAnimPlayState playState)
     // When we get here, we can have one of 4 desired states: running, paused, suspended, paused & suspended.
     // The state machine can be in one of two states: running, paused.
     // Set the state machine to the desired state.
     // When we get here, we can have one of 4 desired states: running, paused, suspended, paused & suspended.
     // The state machine can be in one of two states: running, paused.
     // Set the state machine to the desired state.
-    bool pause = playState == AnimPlayStatePaused || m_compAnim->suspended();
-    
+    bool pause = playState == AnimPlayStatePaused || m_compAnim->isSuspended();
+
     if (pause == paused() && !isNew())
         return;
     if (pause == paused() && !isNew())
         return;
-    
+
     updateStateMachine(pause ?  AnimationStateInputPlayStatePaused : AnimationStateInputPlayStateRunning, -1);
 }
 
     updateStateMachine(pause ?  AnimationStateInputPlayStatePaused : AnimationStateInputPlayStateRunning, -1);
 }
 
index 4a6b17d..dee0836 100644 (file)
@@ -78,6 +78,7 @@ public:
         AnimationStateStartWaitResponse,    // animation started, waiting for response
         AnimationStateLooping,              // response received, animation running, loop timer running, waiting for fire
         AnimationStateEnding,               // received, animation running, end timer running, waiting for fire
         AnimationStateStartWaitResponse,    // animation started, waiting for response
         AnimationStateLooping,              // response received, animation running, loop timer running, waiting for fire
         AnimationStateEnding,               // received, animation running, end timer running, waiting for fire
+        AnimationStatePausedNew,            // in pause mode when animation was created
         AnimationStatePausedWaitTimer,      // in pause mode when animation started
         AnimationStatePausedWaitStyleAvailable, // in pause mode when waiting for style setup
         AnimationStatePausedWaitResponse,   // animation paused when in STARTING state
         AnimationStatePausedWaitTimer,      // in pause mode when animation started
         AnimationStatePausedWaitStyleAvailable, // in pause mode when waiting for style setup
         AnimationStatePausedWaitResponse,   // animation paused when in STARTING state
@@ -115,7 +116,7 @@ public:
     void updatePlayState(EAnimPlayState);
     bool playStatePlaying() const;
 
     void updatePlayState(EAnimPlayState);
     bool playStatePlaying() const;
 
-    bool waitingToStart() const { return m_animState == AnimationStateNew || m_animState == AnimationStateStartWaitTimer; }
+    bool waitingToStart() const { return m_animState == AnimationStateNew || m_animState == AnimationStateStartWaitTimer || m_animState == AnimationStatePausedNew; }
     bool preActive() const
     {
         return m_animState == AnimationStateNew || m_animState == AnimationStateStartWaitTimer || m_animState == AnimationStateStartWaitStyleAvailable || m_animState == AnimationStateStartWaitResponse;
     bool preActive() const
     {
         return m_animState == AnimationStateNew || m_animState == AnimationStateStartWaitTimer || m_animState == AnimationStateStartWaitStyleAvailable || m_animState == AnimationStateStartWaitResponse;
@@ -124,8 +125,8 @@ public:
     bool postActive() const { return m_animState == AnimationStateDone; }
     bool active() const { return !postActive() && !preActive(); }
     bool running() const { return !isNew() && !postActive(); }
     bool postActive() const { return m_animState == AnimationStateDone; }
     bool active() const { return !postActive() && !preActive(); }
     bool running() const { return !isNew() && !postActive(); }
-    bool paused() const { return m_pauseTime >= 0; }
-    bool isNew() const { return m_animState == AnimationStateNew; }
+    bool paused() const { return m_pauseTime >= 0 || m_animState == AnimationStatePausedNew; }
+    bool isNew() const { return m_animState == AnimationStateNew || m_animState == AnimationStatePausedNew; }
     bool waitingForStartTime() const { return m_animState == AnimationStateStartWaitResponse; }
     bool waitingForStyleAvailable() const { return m_animState == AnimationStateStartWaitStyleAvailable; }
 
     bool waitingForStartTime() const { return m_animState == AnimationStateStartWaitResponse; }
     bool waitingForStyleAvailable() const { return m_animState == AnimationStateStartWaitStyleAvailable; }
 
index 1c15870..a484382 100644 (file)
@@ -59,6 +59,7 @@ AnimationControllerPrivate::AnimationControllerPrivate(Frame* frame)
     , m_animationsWaitingForStyle()
     , m_animationsWaitingForStartTimeResponse()
     , m_waitingForAsyncStartNotification(false)
     , m_animationsWaitingForStyle()
     , m_animationsWaitingForStartTimeResponse()
     , m_waitingForAsyncStartNotification(false)
+    , m_isSuspended(false)
 {
 }
 
 {
 }
 
@@ -84,7 +85,7 @@ bool AnimationControllerPrivate::clear(RenderObject* renderer)
     if (!animation)
         return false;
     animation->clearRenderer();
     if (!animation)
         return false;
     animation->clearRenderer();
-    return animation->suspended();
+    return animation->isSuspended();
 }
 
 double AnimationControllerPrivate::updateAnimations(SetChanged callSetChanged/* = DoNotCallSetChanged*/)
 }
 
 double AnimationControllerPrivate::updateAnimations(SetChanged callSetChanged/* = DoNotCallSetChanged*/)
@@ -95,7 +96,7 @@ double AnimationControllerPrivate::updateAnimations(SetChanged callSetChanged/*
     RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
     for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
         CompositeAnimation* compAnim = it->value.get();
     RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
     for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
         CompositeAnimation* compAnim = it->value.get();
-        if (!compAnim->suspended() && compAnim->hasAnimations()) {
+        if (!compAnim->isSuspended() && compAnim->hasAnimations()) {
             double t = compAnim->timeToNextService();
             if (t != -1 && (t < timeToNextService || timeToNextService == -1))
                 timeToNextService = t;
             double t = compAnim->timeToNextService();
             if (t != -1 && (t < timeToNextService || timeToNextService == -1))
                 timeToNextService = t;
@@ -123,7 +124,7 @@ void AnimationControllerPrivate::updateAnimationTimerForRenderer(RenderObject* r
     double timeToNextService = 0;
 
     RefPtr<CompositeAnimation> compAnim = m_compositeAnimations.get(renderer);
     double timeToNextService = 0;
 
     RefPtr<CompositeAnimation> compAnim = m_compositeAnimations.get(renderer);
-    if (!compAnim->suspended() && compAnim->hasAnimations())
+    if (!compAnim->isSuspended() && compAnim->hasAnimations())
         timeToNextService = compAnim->timeToNextService();
 
     if (m_animationTimer.isActive() && (m_animationTimer.repeatInterval() || m_animationTimer.nextFireInterval() <= timeToNextService))
         timeToNextService = compAnim->timeToNextService();
 
     if (m_animationTimer.isActive() && (m_animationTimer.repeatInterval() || m_animationTimer.nextFireInterval() <= timeToNextService))
@@ -264,26 +265,39 @@ bool AnimationControllerPrivate::isRunningAcceleratedAnimationOnRenderer(RenderO
 
 void AnimationControllerPrivate::suspendAnimations()
 {
 
 void AnimationControllerPrivate::suspendAnimations()
 {
+    if (isSuspended())
+        return;
+
     suspendAnimationsForDocument(m_frame->document());
     suspendAnimationsForDocument(m_frame->document());
-    
+
     // Traverse subframes
     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
         child->animation()->suspendAnimations();
     // Traverse subframes
     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
         child->animation()->suspendAnimations();
+
+    m_isSuspended = true;
 }
 
 void AnimationControllerPrivate::resumeAnimations()
 {
 }
 
 void AnimationControllerPrivate::resumeAnimations()
 {
+    if (!isSuspended())
+        return;
+
     resumeAnimationsForDocument(m_frame->document());
     resumeAnimationsForDocument(m_frame->document());
-    
+
     // Traverse subframes
     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
         child->animation()->resumeAnimations();
     // Traverse subframes
     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
         child->animation()->resumeAnimations();
+
+    m_isSuspended = false;
 }
 
 void AnimationControllerPrivate::suspendAnimationsForDocument(Document* document)
 {
 }
 
 void AnimationControllerPrivate::suspendAnimationsForDocument(Document* document)
 {
+    if (isSuspended())
+        return;
+
     setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
     setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
-    
+
     RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
     for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
         RenderObject* renderer = it->key;
     RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
     for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
         RenderObject* renderer = it->key;
@@ -292,14 +306,17 @@ void AnimationControllerPrivate::suspendAnimationsForDocument(Document* document
             compAnim->suspendAnimations();
         }
     }
             compAnim->suspendAnimations();
         }
     }
-    
+
     updateAnimationTimer();
 }
 
 void AnimationControllerPrivate::resumeAnimationsForDocument(Document* document)
 {
     updateAnimationTimer();
 }
 
 void AnimationControllerPrivate::resumeAnimationsForDocument(Document* document)
 {
+    if (!isSuspended())
+        return;
+
     setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
     setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
-    
+
     RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
     for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
         RenderObject* renderer = it->key;
     RenderObjectAnimationMap::const_iterator animationsEnd = m_compositeAnimations.end();
     for (RenderObjectAnimationMap::const_iterator it = m_compositeAnimations.begin(); it != animationsEnd; ++it) {
         RenderObject* renderer = it->key;
@@ -308,10 +325,16 @@ void AnimationControllerPrivate::resumeAnimationsForDocument(Document* document)
             compAnim->resumeAnimations();
         }
     }
             compAnim->resumeAnimations();
         }
     }
-    
+
     updateAnimationTimer();
 }
 
     updateAnimationTimer();
 }
 
+void AnimationControllerPrivate::startAnimationsIfNotSuspended(Document* document)
+{
+    if (!isSuspended())
+        resumeAnimationsForDocument(document);
+}
+
 bool AnimationControllerPrivate::pauseAnimationAtTime(RenderObject* renderer, const AtomicString& name, double t)
 {
     if (!renderer)
 bool AnimationControllerPrivate::pauseAnimationAtTime(RenderObject* renderer, const AtomicString& name, double t)
 {
     if (!renderer)
@@ -578,13 +601,20 @@ bool AnimationController::isRunningAcceleratedAnimationOnRenderer(RenderObject*
     return m_data->isRunningAcceleratedAnimationOnRenderer(renderer, property, isRunningNow);
 }
 
     return m_data->isRunningAcceleratedAnimationOnRenderer(renderer, property, isRunningNow);
 }
 
+bool AnimationController::isSuspended() const
+{
+    return m_data->isSuspended();
+}
+
 void AnimationController::suspendAnimations()
 {
 void AnimationController::suspendAnimations()
 {
+    LOG(Animations, "controller is suspending animations");
     m_data->suspendAnimations();
 }
 
 void AnimationController::resumeAnimations()
 {
     m_data->suspendAnimations();
 }
 
 void AnimationController::resumeAnimations()
 {
+    LOG(Animations, "controller is resuming animations");
     m_data->resumeAnimations();
 }
 
     m_data->resumeAnimations();
 }
 
@@ -597,14 +627,22 @@ void AnimationController::serviceAnimations()
 
 void AnimationController::suspendAnimationsForDocument(Document* document)
 {
 
 void AnimationController::suspendAnimationsForDocument(Document* document)
 {
+    LOG(Animations, "suspending animations for document %p", document);
     m_data->suspendAnimationsForDocument(document);
 }
 
 void AnimationController::resumeAnimationsForDocument(Document* document)
 {
     m_data->suspendAnimationsForDocument(document);
 }
 
 void AnimationController::resumeAnimationsForDocument(Document* document)
 {
+    LOG(Animations, "resuming animations for document %p", document);
     m_data->resumeAnimationsForDocument(document);
 }
 
     m_data->resumeAnimationsForDocument(document);
 }
 
+void AnimationController::startAnimationsIfNotSuspended(Document* document)
+{
+    LOG(Animations, "animations may start for document %p", document);
+    m_data->startAnimationsIfNotSuspended(document);
+}
+
 void AnimationController::beginAnimationUpdate()
 {
     if (!m_beginAnimationUpdateCount)
 void AnimationController::beginAnimationUpdate()
 {
     if (!m_beginAnimationUpdateCount)
index 49d0854..9a267d4 100644 (file)
@@ -63,6 +63,7 @@ public:
     bool isRunningAnimationOnRenderer(RenderObject*, CSSPropertyID, bool isRunningNow = true) const;
     bool isRunningAcceleratedAnimationOnRenderer(RenderObject*, CSSPropertyID, bool isRunningNow = true) const;
 
     bool isRunningAnimationOnRenderer(RenderObject*, CSSPropertyID, bool isRunningNow = true) const;
     bool isRunningAcceleratedAnimationOnRenderer(RenderObject*, CSSPropertyID, bool isRunningNow = true) const;
 
+    bool isSuspended() const;
     void suspendAnimations();
     void resumeAnimations();
 #if ENABLE(REQUEST_ANIMATION_FRAME)
     void suspendAnimations();
     void resumeAnimations();
 #if ENABLE(REQUEST_ANIMATION_FRAME)
@@ -71,6 +72,7 @@ public:
 
     void suspendAnimationsForDocument(Document*);
     void resumeAnimationsForDocument(Document*);
 
     void suspendAnimationsForDocument(Document*);
     void resumeAnimationsForDocument(Document*);
+    void startAnimationsIfNotSuspended(Document*);
 
     void beginAnimationUpdate();
     void endAnimationUpdate();
 
     void beginAnimationUpdate();
     void endAnimationUpdate();
index 8a292f3..f0bea34 100644 (file)
@@ -75,6 +75,7 @@ public:
 
     bool hasAnimations() const { return !m_compositeAnimations.isEmpty(); }
 
 
     bool hasAnimations() const { return !m_compositeAnimations.isEmpty(); }
 
+    bool isSuspended() const { return m_isSuspended; }
     void suspendAnimations();
     void resumeAnimations();
 #if ENABLE(REQUEST_ANIMATION_FRAME)
     void suspendAnimations();
     void resumeAnimations();
 #if ENABLE(REQUEST_ANIMATION_FRAME)
@@ -83,6 +84,7 @@ public:
 
     void suspendAnimationsForDocument(Document*);
     void resumeAnimationsForDocument(Document*);
 
     void suspendAnimationsForDocument(Document*);
     void resumeAnimationsForDocument(Document*);
+    void startAnimationsIfNotSuspended(Document*);
 
     bool isRunningAnimationOnRenderer(RenderObject*, CSSPropertyID, bool isRunningNow) const;
     bool isRunningAcceleratedAnimationOnRenderer(RenderObject*, CSSPropertyID, bool isRunningNow) const;
 
     bool isRunningAnimationOnRenderer(RenderObject*, CSSPropertyID, bool isRunningNow) const;
     bool isRunningAcceleratedAnimationOnRenderer(RenderObject*, CSSPropertyID, bool isRunningNow) const;
@@ -139,6 +141,7 @@ private:
     WaitingAnimationsSet m_animationsWaitingForStyle;
     WaitingAnimationsSet m_animationsWaitingForStartTimeResponse;
     bool m_waitingForAsyncStartNotification;
     WaitingAnimationsSet m_animationsWaitingForStyle;
     WaitingAnimationsSet m_animationsWaitingForStartTimeResponse;
     bool m_waitingForAsyncStartNotification;
+    bool m_isSuspended;
 };
 
 } // namespace WebCore
 };
 
 } // namespace WebCore
index 071dbcf..aeff0f0 100644 (file)
 
 namespace WebCore {
 
 
 namespace WebCore {
 
+CompositeAnimation::CompositeAnimation(AnimationControllerPrivate* animationController)
+    : m_animationController(animationController)
+{
+    m_suspended = animationController->isSuspended();
+}
+
 CompositeAnimation::~CompositeAnimation()
 {
     // Toss the refs to all animations, but make sure we remove them from
 CompositeAnimation::~CompositeAnimation()
 {
     // Toss the refs to all animations, but make sure we remove them from
@@ -92,7 +98,7 @@ void CompositeAnimation::updateTransitions(RenderObject* renderer, RenderStyle*
     if (targetStyle->transitions()) {
         for (size_t i = 0; i < targetStyle->transitions()->size(); ++i) {
             const Animation* anim = targetStyle->transitions()->animation(i);
     if (targetStyle->transitions()) {
         for (size_t i = 0; i < targetStyle->transitions()->size(); ++i) {
             const Animation* anim = targetStyle->transitions()->animation(i);
-            bool isActiveTransition = anim->duration() || anim->delay() > 0;
+            bool isActiveTransition = !m_suspended && (anim->duration() || anim->delay() > 0);
 
             Animation::AnimationMode mode = anim->animationMode();
             if (mode == Animation::AnimateNone)
 
             Animation::AnimationMode mode = anim->animationMode();
             if (mode == Animation::AnimateNone)
@@ -252,7 +258,11 @@ void CompositeAnimation::updateKeyframeAnimations(RenderObject* renderer, Render
                     keyframeAnim->setIndex(i);
                 } else if ((anim->duration() || anim->delay()) && anim->iterationCount() && animationName != none) {
                     keyframeAnim = KeyframeAnimation::create(const_cast<Animation*>(anim), renderer, i, this, targetStyle);
                     keyframeAnim->setIndex(i);
                 } else if ((anim->duration() || anim->delay()) && anim->iterationCount() && animationName != none) {
                     keyframeAnim = KeyframeAnimation::create(const_cast<Animation*>(anim), renderer, i, this, targetStyle);
-                    LOG(Animations, "Creating KeyframeAnimation %p with keyframes %s duration %.2f delay %.2f, iterations %.2f", keyframeAnim.get(), anim->name().utf8().data(), anim->duration(), anim->delay(), anim->iterationCount());
+                    LOG(Animations, "Creating KeyframeAnimation %p with keyframes %s, duration %.2f, delay %.2f, iterations %.2f", keyframeAnim.get(), anim->name().utf8().data(), anim->duration(), anim->delay(), anim->iterationCount());
+                    if (m_suspended) {
+                        keyframeAnim->updatePlayState(AnimPlayStatePaused);
+                        LOG(Animations, "  (created in suspended/paused state)");
+                    }
 #if !LOG_DISABLED
                     HashSet<CSSPropertyID>::const_iterator endProperties = keyframeAnim->keyframes().endProperties();
                     for (HashSet<CSSPropertyID>::const_iterator it = keyframeAnim->keyframes().beginProperties(); it != endProperties; ++it)
 #if !LOG_DISABLED
                     HashSet<CSSPropertyID>::const_iterator endProperties = keyframeAnim->keyframes().endProperties();
                     for (HashSet<CSSPropertyID>::const_iterator it = keyframeAnim->keyframes().beginProperties(); it != endProperties; ++it)
index c95048e..4f49190 100644 (file)
@@ -64,7 +64,7 @@ public:
 
     void suspendAnimations();
     void resumeAnimations();
 
     void suspendAnimations();
     void resumeAnimations();
-    bool suspended() const { return m_suspended; }
+    bool isSuspended() const { return m_suspended; }
     
     bool hasAnimations() const  { return !m_transitions.isEmpty() || !m_keyframeAnimations.isEmpty(); }
 
     
     bool hasAnimations() const  { return !m_transitions.isEmpty() || !m_keyframeAnimations.isEmpty(); }
 
@@ -80,11 +80,7 @@ public:
     unsigned numberOfActiveAnimations() const;
 
 private:
     unsigned numberOfActiveAnimations() const;
 
 private:
-    CompositeAnimation(AnimationControllerPrivate* animationController)
-        : m_animationController(animationController)
-        , m_suspended(false)
-    {
-    }
+    CompositeAnimation(AnimationControllerPrivate*);
 
     void updateTransitions(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle);
     void updateKeyframeAnimations(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle);
 
     void updateTransitions(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle);
     void updateKeyframeAnimations(RenderObject*, RenderStyle* currentStyle, RenderStyle* targetStyle);
index 6cb827e..f888c8a 100644 (file)
@@ -140,13 +140,13 @@ void KeyframeAnimation::fetchIntervalEndpointsForProperty(CSSPropertyID property
     prog = progress(scale, offset, timingFunction);
 }
 
     prog = progress(scale, offset, timingFunction);
 }
 
-void KeyframeAnimation::animate(CompositeAnimation*, RenderObject*, const RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle)
+void KeyframeAnimation::animate(CompositeAnimation* compositeAnimation, RenderObject*, const RenderStyle*, RenderStyle* targetStyle, RefPtr<RenderStyle>& animatedStyle)
 {
     // Fire the start timeout if needed
     fireAnimationEventsIfNeeded();
     
     // If we have not yet started, we will not have a valid start time, so just start the animation if needed.
 {
     // Fire the start timeout if needed
     fireAnimationEventsIfNeeded();
     
     // If we have not yet started, we will not have a valid start time, so just start the animation if needed.
-    if (isNew() && m_animation->playState() == AnimPlayStatePlaying)
+    if (isNew() && m_animation->playState() == AnimPlayStatePlaying && !compositeAnimation->isSuspended())
         updateStateMachine(AnimationStateInputStartAnimation, -1);
 
     // If we get this far and the animation is done, it means we are cleaning up a just finished animation.
         updateStateMachine(AnimationStateInputStartAnimation, -1);
 
     // If we get this far and the animation is done, it means we are cleaning up a just finished animation.
index 85e95ef..330714a 100644 (file)
@@ -467,6 +467,20 @@ unsigned Internals::numberOfActiveAnimations() const
     return 0;
 }
 
     return 0;
 }
 
+bool Internals::animationsAreSuspended(Document* document, ExceptionCode& ec) const
+{
+    if (!document || !document->frame()) {
+        ec = INVALID_ACCESS_ERR;
+        return false;
+    }
+
+    AnimationController* controller = document->frame()->animation();
+    if (!controller)
+        return false;
+
+    return controller->isSuspended();
+}
+
 void Internals::suspendAnimations(Document* document, ExceptionCode& ec) const
 {
     if (!document || !document->frame()) {
 void Internals::suspendAnimations(Document* document, ExceptionCode& ec) const
 {
     if (!document || !document->frame()) {
index b416e32..8476a5f 100644 (file)
@@ -99,6 +99,7 @@ public:
 
     // CSS Animation testing.
     unsigned numberOfActiveAnimations() const;
 
     // CSS Animation testing.
     unsigned numberOfActiveAnimations() const;
+    bool animationsAreSuspended(Document*, ExceptionCode&) const;
     void suspendAnimations(Document*, ExceptionCode&) const;
     void resumeAnimations(Document*, ExceptionCode&) const;
     bool pauseAnimationAtTimeOnElement(const String& animationName, double pauseTime, Element*, ExceptionCode&);
     void suspendAnimations(Document*, ExceptionCode&) const;
     void resumeAnimations(Document*, ExceptionCode&) const;
     bool pauseAnimationAtTimeOnElement(const String& animationName, double pauseTime, Element*, ExceptionCode&);
index 0d4e536..e398241 100644 (file)
@@ -65,6 +65,7 @@
     unsigned long numberOfActiveAnimations();
     void suspendAnimations(Document document) raises (DOMException);
     void resumeAnimations(Document document) raises (DOMException);
     unsigned long numberOfActiveAnimations();
     void suspendAnimations(Document document) raises (DOMException);
     void resumeAnimations(Document document) raises (DOMException);
+    boolean animationsAreSuspended(in Document document) raises (DOMException);
     boolean pauseAnimationAtTimeOnElement(DOMString animationName, double pauseTime, Element element) raises (DOMException);
     boolean pauseAnimationAtTimeOnPseudoElement(DOMString animationName, double pauseTime, Element element, DOMString pseudoId) raises (DOMException);
 
     boolean pauseAnimationAtTimeOnElement(DOMString animationName, double pauseTime, Element element) raises (DOMException);
     boolean pauseAnimationAtTimeOnPseudoElement(DOMString animationName, double pauseTime, Element element, DOMString pseudoId) raises (DOMException);
 
index 3fcb3b3..0e05833 100644 (file)
@@ -1,3 +1,14 @@
+2013-05-04  Dean Jackson  <dino@apple.com>
+
+        Animations and Transitions should not start when globally suspended
+        https://bugs.webkit.org/show_bug.cgi?id=114915
+
+        Reviewed by Sam Weinig.
+
+        Export AnimationController::isSuspended
+
+        * WebKit.vcxproj/WebKitExportGenerator/WebKitExports.def.in:
+
 2013-05-04  Sam Weinig  <sam@webkit.org>
 
         Move PopupMenuMac and SearchPopupMenuMac to Source/WebKit/mac
 2013-05-04  Sam Weinig  <sam@webkit.org>
 
         Move PopupMenuMac and SearchPopupMenuMac to Source/WebKit/mac
index 2876b01..e90ac48 100644 (file)
@@ -1,3 +1,23 @@
+2013-05-04  Dean Jackson  <dino@apple.com>
+
+        Animations and Transitions should not start when globally suspended
+        https://bugs.webkit.org/show_bug.cgi?id=114915
+
+        Reviewed by Sam Weinig.
+
+        The WebView private API cssAnimationsSuspended did not necessarily
+        reflect the reality of the Frame's AnimationController value because it
+        was caching rather than asking directly. While the WebCore part of this
+        patch ensured loading the Document wouldn't resume all animations, it
+        is still better to ask directly.
+
+        * WebView/WebView.mm:
+        (-[WebView cssAnimationsSuspended]): Call into AnimationController.
+        (-[WebView setCSSAnimationsSuspended:]): Ditto.
+        * WebView/WebViewData.h: Remove cssAnimationsSuspended boolean.
+        * WebView/WebViewData.mm: Ditto.
+        (-[WebViewPrivate init]):
+
 2013-05-04  Sam Weinig  <sam@webkit.org>
 
         Move PopupMenuMac and SearchPopupMenuMac to Source/WebKit/mac
 2013-05-04  Sam Weinig  <sam@webkit.org>
 
         Move PopupMenuMac and SearchPopupMenuMac to Source/WebKit/mac
index 57f9976..ccbb4b0 100644 (file)
@@ -2769,17 +2769,20 @@ static Vector<String> toStringVector(NSArray* patterns)
 
 - (BOOL)cssAnimationsSuspended
 {
 
 - (BOOL)cssAnimationsSuspended
 {
-    return _private->cssAnimationsSuspended;
+    // should ask the page!
+    Frame* frame = core([self mainFrame]);
+    if (frame)
+        return frame->animation()->isSuspended();
+
+    return false;
 }
 
 - (void)setCSSAnimationsSuspended:(BOOL)suspended
 {
 }
 
 - (void)setCSSAnimationsSuspended:(BOOL)suspended
 {
-    if (suspended == _private->cssAnimationsSuspended)
+    Frame* frame = core([self mainFrame]);
+    if (suspended == frame->animation()->isSuspended())
         return;
         
         return;
         
-    _private->cssAnimationsSuspended = suspended;
-    
-    Frame* frame = core([self mainFrame]);
     if (suspended)
         frame->animation()->suspendAnimations();
     else
     if (suspended)
         frame->animation()->suspendAnimations();
     else
index 347aba4..89f7321 100644 (file)
@@ -137,7 +137,6 @@ private:
     BOOL becomingFirstResponder;
     BOOL becomingFirstResponderFromOutside;
     BOOL usesPageCache;
     BOOL becomingFirstResponder;
     BOOL becomingFirstResponderFromOutside;
     BOOL usesPageCache;
-    BOOL cssAnimationsSuspended;
 
     NSColor *backgroundColor;
 
 
     NSColor *backgroundColor;
 
index c681f09..4d108f0 100644 (file)
@@ -80,7 +80,6 @@ LayerFlushController::LayerFlushController(WebView* webView)
     allowsUndo = YES;
     usesPageCache = YES;
     shouldUpdateWhileOffscreen = YES;
     allowsUndo = YES;
     usesPageCache = YES;
     shouldUpdateWhileOffscreen = YES;
-    cssAnimationsSuspended = NO;
 
     zoomMultiplier = 1;
     zoomsTextOnly = NO;
 
     zoomMultiplier = 1;
     zoomsTextOnly = NO;
index fed3ef2..81508de 100644 (file)
@@ -1,3 +1,14 @@
+2013-05-04  Dean Jackson  <dino@apple.com>
+
+        Animations and Transitions should not start when globally suspended
+        https://bugs.webkit.org/show_bug.cgi?id=114915
+
+        Reviewed by Sam Weinig.
+
+        Export AnimationController::isSuspended
+
+        * WebKit.vcproj/WebKitExports.def.in:
+
 2013-05-01  Sergio Villar Senin  <svillar@igalia.com>
 
         Show a block cursor in overtype mode
 2013-05-01  Sergio Villar Senin  <svillar@igalia.com>
 
         Show a block cursor in overtype mode
index 3f82128..15ef021 100644 (file)
@@ -333,6 +333,7 @@ EXPORTS
         ?viewportArguments@Page@WebCore@@QBE?AUViewportArguments@2@XZ
         ?isPageBoxVisible@Document@WebCore@@QAE_NH@Z
         ?isActive@InsertionPoint@WebCore@@QBE_NXZ
         ?viewportArguments@Page@WebCore@@QBE?AUViewportArguments@2@XZ
         ?isPageBoxVisible@Document@WebCore@@QAE_NH@Z
         ?isActive@InsertionPoint@WebCore@@QBE_NXZ
+        ?isSuspended@AnimationController@WebCore@@QBE_NXZ
         ?suspendAnimations@AnimationController@WebCore@@QAEXXZ
         ?resumeAnimations@AnimationController@WebCore@@QAEXXZ
         ?setAllowsRoundingHacks@TextRun@WebCore@@SAX_N@Z
         ?suspendAnimations@AnimationController@WebCore@@QAEXXZ
         ?resumeAnimations@AnimationController@WebCore@@QAEXXZ
         ?setAllowsRoundingHacks@TextRun@WebCore@@SAX_N@Z
index 868bde4..9069cdd 100644 (file)
@@ -184,6 +184,7 @@ _ZN7WebCore22counterValueForElementEPNS_7ElementE;
 _ZNK7WebCore14DocumentMarker11descriptionEv;
 _ZN7WebCore8Document16isPageBoxVisibleEi;
 _ZN7WebCore18ContentDistributor22ensureSelectFeatureSetEPNS_13ElementShadowE;
 _ZNK7WebCore14DocumentMarker11descriptionEv;
 _ZN7WebCore8Document16isPageBoxVisibleEi;
 _ZN7WebCore18ContentDistributor22ensureSelectFeatureSetEPNS_13ElementShadowE;
+_ZNK7WebCore19AnimationController11isSuspendedEv;
 _ZN7WebCore19AnimationController17suspendAnimationsEv;
 _ZN7WebCore19AnimationController16resumeAnimationsEv;
 _ZN7WebCore19AnimationController20pauseAnimationAtTimeEPNS_12RenderObjectERKN3WTF12AtomicStringEd;
 _ZN7WebCore19AnimationController17suspendAnimationsEv;
 _ZN7WebCore19AnimationController16resumeAnimationsEv;
 _ZN7WebCore19AnimationController20pauseAnimationAtTimeEPNS_12RenderObjectERKN3WTF12AtomicStringEd;