Commit f221e46d authored by dino@apple.com's avatar 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:

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: http://svn.webkit.org/repository/webkit/trunk@149576 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 4302ad6c
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-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
......
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
<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>
......@@ -42,8 +42,10 @@
internals.suspendAnimations(document);
window.setTimeout(function() {
if (window.testRunner)
if (window.testRunner) {
internals.resumeAnimations(document);
testRunner.notifyDone();
}
}, 250);
}
......
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
<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>
......@@ -37,8 +37,10 @@
internals.suspendAnimations(document);
window.setTimeout(function() {
if (window.testRunner)
if (window.testRunner) {
internals.resumeAnimations(document);
testRunner.notifyDone();
}
}, 250);
}
......
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
......
......@@ -602,6 +602,7 @@ __ZN7WebCore18isStartOfParagraphERKNS_15VisiblePositionENS_27EditingBoundaryCros
__ZN7WebCore18makeAllDirectoriesERKN3WTF6StringE
__ZN7WebCore18pluginScriptObjectEPN3JSC9ExecStateEPNS_13JSHTMLElementE
__ZN7WebCore18proxyServersForURLERKNS_4KURLEPKNS_17NetworkingContextE
__ZNK7WebCore19AnimationController11isSuspendedEv
__ZN7WebCore19AnimationController16resumeAnimationsEv
__ZN7WebCore19AnimationController17suspendAnimationsEv
__ZN7WebCore19AnimationController20pauseAnimationAtTimeEPNS_12RenderObjectERKN3WTF12AtomicStringEd
......
......@@ -2396,7 +2396,7 @@ void Document::implicitClose()
Frame* f = frame();
if (f) {
f->loader()->icon()->startLoader();
f->animation()->resumeAnimationsForDocument(this);
f->animation()->startAnimationsIfNotSuspended(this);
}
ImageLoader::dispatchPendingBeforeLoadEvents();
......
......@@ -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::AnimationStatePausedNew: return "PausedNew";
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;
} else {
// We are pausing before we even started.
LOG(Animations, "%p AnimationState %s -> AnimationStatePausedNew", this, nameForState(m_animState));
m_animState = AnimationStatePausedNew;
}
break;
case AnimationStateStartWaitTimer:
......@@ -355,6 +360,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
m_animState = AnimationStateNew;
updateStateMachine(AnimationStateInputStartAnimation, 0);
break;
case AnimationStatePausedNew:
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.
ASSERT(input == AnimationStateInputPlayStateRunning || input == AnimationStateInputStartTimeSet || input == AnimationStateInputStyleAvailable);
ASSERT(input == AnimationStateInputPlayStateRunning || input == AnimationStateInputStartTimeSet || input == AnimationStateInputStyleAvailable || input == AnimationStateInputStartAnimation);
ASSERT(paused());
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;
......@@ -410,7 +425,7 @@ void AnimationBase::updateStateMachine(AnimStateInput input, double param)
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
......@@ -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.
bool pause = playState == AnimPlayStatePaused || m_compAnim->suspended();
bool pause = playState == AnimPlayStatePaused || m_compAnim->isSuspended();
if (pause == paused() && !isNew())
return;
updateStateMachine(pause ? AnimationStateInputPlayStatePaused : AnimationStateInputPlayStateRunning, -1);
}
......
......@@ -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
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
......@@ -115,7 +116,7 @@ public:
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;
......@@ -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 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; }
......
......@@ -59,6 +59,7 @@ AnimationControllerPrivate::AnimationControllerPrivate(Frame* frame)
, 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();
return animation->suspended();
return animation->isSuspended();
}
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();
if (!compAnim->suspended() && compAnim->hasAnimations()) {
if (!compAnim->isSuspended() && compAnim->hasAnimations()) {
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);
if (!compAnim->suspended() && compAnim->hasAnimations())
if (!compAnim->isSuspended() && compAnim->hasAnimations())
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()
{
if (isSuspended())
return;
suspendAnimationsForDocument(m_frame->document());
// Traverse subframes
for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
child->animation()->suspendAnimations();
m_isSuspended = true;
}
void AnimationControllerPrivate::resumeAnimations()
{
if (!isSuspended())
return;
resumeAnimationsForDocument(m_frame->document());
// 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)
{
if (isSuspended())
return;
setBeginAnimationUpdateTime(cBeginAnimationUpdateTimeNotSet);
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();
}
}