Title: [217997] trunk
Revision
217997
Author
[email protected]
Date
2017-06-09 10:52:42 -0700 (Fri, 09 Jun 2017)

Log Message

CSS transitions added while page is not visible do not start when the page becomes visible
https://bugs.webkit.org/show_bug.cgi?id=173166
<rdar://problem/32250351>

Reviewed by Darin Adler.

Source/WebCore:

CSS transitions added while page is not visible would not start when the page becomes
visible. The issue was that when CompositeAnimation::updateTransitions() was called
while the page is hidden (and animations are therefore suspended), it would not
populate m_transations with ImplicitAnimation objects. We would therefore have later
no transitions to resume when the page becomes visible later on. This patch updates
CompositeAnimation::updateTransitions() to properly populate m_transitions and instead
pause the ImplicitAnimation it creates if animations are currently suspended. This
behavior is more consistent with the one of CompositeAnimation::updateKeyframeAnimations().

I also needed to update ImplicitAnimation::animate() to not restart a paused animation
if the animation is currently paused. This is similar to what is done in
KeyframeAnimation::animate(). Without this, the paused ImplicitAnimation we add to
m_transition would incorrectly get unpaused while the page is still hidden and the
animations are still supposed to be suspended. This issue was showing when running the
test I am adding in this patch.

Test: fast/animation/css-animation-resuming-when-visible.html

* page/animation/CompositeAnimation.cpp:
(WebCore::CompositeAnimation::updateTransitions):
* page/animation/ImplicitAnimation.cpp:
(WebCore::ImplicitAnimation::animate):
(WebCore::ImplicitAnimation::reset):
* page/animation/ImplicitAnimation.h:

LayoutTests:

Add layout test coverage.

* fast/animation/css-animation-resuming-when-visible-expected.txt: Added.
* fast/animation/css-animation-resuming-when-visible.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (217996 => 217997)


--- trunk/LayoutTests/ChangeLog	2017-06-09 17:48:05 UTC (rev 217996)
+++ trunk/LayoutTests/ChangeLog	2017-06-09 17:52:42 UTC (rev 217997)
@@ -1,3 +1,16 @@
+2017-06-09  Chris Dumez  <[email protected]>
+
+        CSS transitions added while page is not visible do not start when the page becomes visible
+        https://bugs.webkit.org/show_bug.cgi?id=173166
+        <rdar://problem/32250351>
+
+        Reviewed by Darin Adler.
+
+        Add layout test coverage.
+
+        * fast/animation/css-animation-resuming-when-visible-expected.txt: Added.
+        * fast/animation/css-animation-resuming-when-visible.html: Added.
+
 2017-06-09  Eric Carlson  <[email protected]>
 
         fast/mediastream/MediaStream-page-muted.html times out and asserts

Added: trunk/LayoutTests/fast/animation/css-animation-resuming-when-visible-expected.txt (0 => 217997)


--- trunk/LayoutTests/fast/animation/css-animation-resuming-when-visible-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/animation/css-animation-resuming-when-visible-expected.txt	2017-06-09 17:52:42 UTC (rev 217997)
@@ -0,0 +1,12 @@
+Tests that CSS animations that are created while the page is hidden are properly resumed when the page becomes visible.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS internals.animationsAreSuspended() is true
+PASS internals.numberOfActiveAnimations() is 0
+PASS internals.numberOfActiveAnimations() became 1
+PASS successfullyParsed is true
+
+TEST COMPLETE
+TEST

Added: trunk/LayoutTests/fast/animation/css-animation-resuming-when-visible.html (0 => 217997)


--- trunk/LayoutTests/fast/animation/css-animation-resuming-when-visible.html	                        (rev 0)
+++ trunk/LayoutTests/fast/animation/css-animation-resuming-when-visible.html	2017-06-09 17:52:42 UTC (rev 217997)
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+#testDiv {
+    transition: transform 30s linear, color 2s, left 4s linear, top 4s linear;
+    position: absolute;
+}
+</style>
+</head>
+<body>
+<script src=""
+<div id="testDiv">TEST</div>
+<script>
+description("Tests that CSS animations that are created while the page is hidden are properly resumed when the page becomes visible.");
+jsTestIsAsync = true;
+
+function registerAnimation()
+{
+    testDiv.style.transform = "rotate(170deg) scale(0.2781941414347284)";
+}
+
+_onload_ = function() {
+    internals.suspendAnimations();
+
+    setTimeout(function() {
+        registerAnimation();
+        setTimeout(function() {
+            shouldBeTrue("internals.animationsAreSuspended()");
+            shouldBe("internals.numberOfActiveAnimations()", "0");
+
+            internals.resumeAnimations();
+            shouldBecomeEqual("internals.numberOfActiveAnimations()", "1", finishJSTest);
+        }, 500);
+    }, 0);
+}
+
+</script>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (217996 => 217997)


--- trunk/Source/WebCore/ChangeLog	2017-06-09 17:48:05 UTC (rev 217996)
+++ trunk/Source/WebCore/ChangeLog	2017-06-09 17:52:42 UTC (rev 217997)
@@ -1,3 +1,36 @@
+2017-06-09  Chris Dumez  <[email protected]>
+
+        CSS transitions added while page is not visible do not start when the page becomes visible
+        https://bugs.webkit.org/show_bug.cgi?id=173166
+        <rdar://problem/32250351>
+
+        Reviewed by Darin Adler.
+
+        CSS transitions added while page is not visible would not start when the page becomes
+        visible. The issue was that when CompositeAnimation::updateTransitions() was called
+        while the page is hidden (and animations are therefore suspended), it would not
+        populate m_transations with ImplicitAnimation objects. We would therefore have later
+        no transitions to resume when the page becomes visible later on. This patch updates
+        CompositeAnimation::updateTransitions() to properly populate m_transitions and instead
+        pause the ImplicitAnimation it creates if animations are currently suspended. This
+        behavior is more consistent with the one of CompositeAnimation::updateKeyframeAnimations().
+
+        I also needed to update ImplicitAnimation::animate() to not restart a paused animation
+        if the animation is currently paused. This is similar to what is done in
+        KeyframeAnimation::animate(). Without this, the paused ImplicitAnimation we add to
+        m_transition would incorrectly get unpaused while the page is still hidden and the
+        animations are still supposed to be suspended. This issue was showing when running the
+        test I am adding in this patch.
+
+        Test: fast/animation/css-animation-resuming-when-visible.html
+
+        * page/animation/CompositeAnimation.cpp:
+        (WebCore::CompositeAnimation::updateTransitions):
+        * page/animation/ImplicitAnimation.cpp:
+        (WebCore::ImplicitAnimation::animate):
+        (WebCore::ImplicitAnimation::reset):
+        * page/animation/ImplicitAnimation.h:
+
 2017-06-09  Yusuke Suzuki  <[email protected]>
 
         Unreviewed, Use FALLTHROUGH

Modified: trunk/Source/WebCore/page/animation/AnimationBase.h (217996 => 217997)


--- trunk/Source/WebCore/page/animation/AnimationBase.h	2017-06-09 17:48:05 UTC (rev 217996)
+++ trunk/Source/WebCore/page/animation/AnimationBase.h	2017-06-09 17:52:42 UTC (rev 217997)
@@ -134,7 +134,7 @@
     double progress(double scale = 1, double offset = 0, const TimingFunction* = nullptr) const;
 
     // Returns true if the animation state changed.
-    virtual bool animate(CompositeAnimation*, RenderElement*, const RenderStyle* /*currentStyle*/, const RenderStyle* /*targetStyle*/, std::unique_ptr<RenderStyle>& /*animatedStyle*/, bool& didBlendStyle) = 0;
+    virtual bool animate(CompositeAnimation&, RenderElement*, const RenderStyle* /*currentStyle*/, const RenderStyle& /*targetStyle*/, std::unique_ptr<RenderStyle>& /*animatedStyle*/, bool& didBlendStyle) = 0;
     virtual void getAnimatedStyle(std::unique_ptr<RenderStyle>& /*animatedStyle*/) = 0;
 
     virtual bool computeExtentOfTransformAnimation(LayoutRect&) const = 0;

Modified: trunk/Source/WebCore/page/animation/CompositeAnimation.cpp (217996 => 217997)


--- trunk/Source/WebCore/page/animation/CompositeAnimation.cpp	2017-06-09 17:48:05 UTC (rev 217996)
+++ trunk/Source/WebCore/page/animation/CompositeAnimation.cpp	2017-06-09 17:52:42 UTC (rev 217997)
@@ -94,7 +94,7 @@
     if (targetStyle->transitions()) {
         for (size_t i = 0; i < targetStyle->transitions()->size(); ++i) {
             auto& animation = targetStyle->transitions()->animation(i);
-            bool isActiveTransition = !m_suspended && (animation.duration() || animation.delay() > 0);
+            bool isActiveTransition = animation.duration() || animation.delay() > 0;
 
             Animation::AnimationMode mode = animation.animationMode();
             if (mode == Animation::AnimateNone || mode == Animation::AnimateUnknownProperty)
@@ -169,6 +169,9 @@
                 if (!equal && isActiveTransition) {
                     // Add the new transition
                     auto implicitAnimation = ImplicitAnimation::create(animation, prop, renderer, this, modifiedCurrentStyle ? modifiedCurrentStyle.get() : fromStyle);
+                    if (m_suspended && implicitAnimation->hasStyle())
+                        implicitAnimation->updatePlayState(AnimPlayStatePaused);
+
                     LOG(Animations, "Created ImplicitAnimation %p on renderer %p for property %s duration %.2f delay %.2f", implicitAnimation.ptr(), renderer, getPropertyName(prop), animation.duration(), animation.delay());
                     m_transitions.set(prop, WTFMove(implicitAnimation));
                 }
@@ -300,7 +303,7 @@
         bool checkForStackingContext = false;
         for (auto& transition : m_transitions.values()) {
             bool didBlendStyle = false;
-            if (transition->animate(this, &renderer, currentStyle, &targetStyle, blendedStyle, didBlendStyle))
+            if (transition->animate(*this, &renderer, currentStyle, targetStyle, blendedStyle, didBlendStyle))
                 animationStateChanged = true;
 
             if (didBlendStyle)
@@ -330,7 +333,7 @@
         RefPtr<KeyframeAnimation> keyframeAnim = m_keyframeAnimations.get(name);
         if (keyframeAnim) {
             bool didBlendStyle = false;
-            if (keyframeAnim->animate(this, &renderer, currentStyle, &targetStyle, blendedStyle, didBlendStyle))
+            if (keyframeAnim->animate(*this, &renderer, currentStyle, targetStyle, blendedStyle, didBlendStyle))
                 animationStateChanged = true;
 
             forceStackingContext |= didBlendStyle && keyframeAnim->triggersStackingContext();

Modified: trunk/Source/WebCore/page/animation/ImplicitAnimation.cpp (217996 => 217997)


--- trunk/Source/WebCore/page/animation/ImplicitAnimation.cpp	2017-06-09 17:48:05 UTC (rev 217996)
+++ trunk/Source/WebCore/page/animation/ImplicitAnimation.cpp	2017-06-09 17:52:42 UTC (rev 217997)
@@ -61,7 +61,7 @@
     return m_object->document().hasListenerType(inListenerType);
 }
 
-bool ImplicitAnimation::animate(CompositeAnimation*, RenderElement*, const RenderStyle*, const RenderStyle* targetStyle, std::unique_ptr<RenderStyle>& animatedStyle, bool& didBlendStyle)
+bool ImplicitAnimation::animate(CompositeAnimation& compositeAnimation, RenderElement*, const RenderStyle*, const RenderStyle& targetStyle, std::unique_ptr<RenderStyle>& animatedStyle, bool& didBlendStyle)
 {
     // If we get this far and the animation is done, it means we are cleaning up a just finished animation.
     // So just return. Everything is already all cleaned up.
@@ -72,12 +72,12 @@
 
     // Reset to start the transition if we are new
     if (isNew())
-        reset(targetStyle);
+        reset(targetStyle, compositeAnimation);
 
     // Run a cycle of animation.
     // We know we will need a new render style, so make one if needed
     if (!animatedStyle)
-        animatedStyle = RenderStyle::clonePtr(*targetStyle);
+        animatedStyle = RenderStyle::clonePtr(targetStyle);
 
     CSSPropertyAnimation::blendProperties(this, m_animatingProperty, animatedStyle.get(), m_fromStyle.get(), m_toStyle.get(), progress());
     // FIXME: we also need to detect cases where we have to software animate for other reasons,
@@ -199,12 +199,11 @@
     return false; // Didn't dispatch an event
 }
 
-void ImplicitAnimation::reset(const RenderStyle* to)
+void ImplicitAnimation::reset(const RenderStyle& to, CompositeAnimation& compositeAnimation)
 {
-    ASSERT(to);
     ASSERT(m_fromStyle);
 
-    m_toStyle = RenderStyle::clonePtr(*to);
+    m_toStyle = RenderStyle::clonePtr(to);
 
     if (m_object && m_object->element())
         Style::loadPendingResources(*m_toStyle, m_object->element()->document(), m_object->element());
@@ -211,7 +210,7 @@
 
     // Restart the transition
     if (m_fromStyle && m_toStyle)
-        updateStateMachine(AnimationStateInput::RestartAnimation, -1);
+        updateStateMachine(compositeAnimation.isSuspended() ? AnimationStateInput::PlayStatePaused : AnimationStateInput::RestartAnimation, -1);
         
     // set the transform animation list
     validateTransformFunctionList();

Modified: trunk/Source/WebCore/page/animation/ImplicitAnimation.h (217996 => 217997)


--- trunk/Source/WebCore/page/animation/ImplicitAnimation.h	2017-06-09 17:48:05 UTC (rev 217996)
+++ trunk/Source/WebCore/page/animation/ImplicitAnimation.h	2017-06-09 17:52:42 UTC (rev 217997)
@@ -53,9 +53,9 @@
     void pauseAnimation(double timeOffset) override;
     void endAnimation() override;
 
-    bool animate(CompositeAnimation*, RenderElement*, const RenderStyle* currentStyle, const RenderStyle* targetStyle, std::unique_ptr<RenderStyle>& animatedStyle, bool& didBlendStyle) override;
+    bool animate(CompositeAnimation&, RenderElement*, const RenderStyle* currentStyle, const RenderStyle& targetStyle, std::unique_ptr<RenderStyle>& animatedStyle, bool& didBlendStyle) override;
     void getAnimatedStyle(std::unique_ptr<RenderStyle>& animatedStyle) override;
-    void reset(const RenderStyle* to);
+    void reset(const RenderStyle& to, CompositeAnimation&);
 
     bool computeExtentOfTransformAnimation(LayoutRect&) const override;
 

Modified: trunk/Source/WebCore/page/animation/KeyframeAnimation.cpp (217996 => 217997)


--- trunk/Source/WebCore/page/animation/KeyframeAnimation.cpp	2017-06-09 17:48:05 UTC (rev 217996)
+++ trunk/Source/WebCore/page/animation/KeyframeAnimation.cpp	2017-06-09 17:52:42 UTC (rev 217997)
@@ -154,7 +154,7 @@
     prog = progress(scale, offset, prevKeyframe.timingFunction(name()));
 }
 
-bool KeyframeAnimation::animate(CompositeAnimation* compositeAnimation, RenderElement*, const RenderStyle*, const RenderStyle* targetStyle, std::unique_ptr<RenderStyle>& animatedStyle, bool& didBlendStyle)
+bool KeyframeAnimation::animate(CompositeAnimation& compositeAnimation, RenderElement*, const RenderStyle*, const RenderStyle& targetStyle, std::unique_ptr<RenderStyle>& animatedStyle, bool& didBlendStyle)
 {
     // Fire the start timeout if needed
     fireAnimationEventsIfNeeded();
@@ -161,7 +161,7 @@
     
     // If we have not yet started, we will not have a valid start time, so just start the animation if needed.
     if (isNew()) {
-        if (m_animation->playState() == AnimPlayStatePlaying && !compositeAnimation->isSuspended())
+        if (m_animation->playState() == AnimPlayStatePlaying && !compositeAnimation.isSuspended())
             updateStateMachine(AnimationStateInput::StartAnimation, -1);
         else if (m_animation->playState() == AnimPlayStatePaused)
             updateStateMachine(AnimationStateInput::PlayStatePaused, -1);
@@ -171,7 +171,7 @@
     // If so, we need to send back the targetStyle.
     if (postActive()) {
         if (!animatedStyle)
-            animatedStyle = RenderStyle::clonePtr(*targetStyle);
+            animatedStyle = RenderStyle::clonePtr(targetStyle);
         return false;
     }
 
@@ -195,7 +195,7 @@
     // Run a cycle of animation.
     // We know we will need a new render style, so make one if needed.
     if (!animatedStyle)
-        animatedStyle = RenderStyle::clonePtr(*targetStyle);
+        animatedStyle = RenderStyle::clonePtr(targetStyle);
 
     // FIXME: we need to be more efficient about determining which keyframes we are animating between.
     // We should cache the last pair or something.

Modified: trunk/Source/WebCore/page/animation/KeyframeAnimation.h (217996 => 217997)


--- trunk/Source/WebCore/page/animation/KeyframeAnimation.h	2017-06-09 17:48:05 UTC (rev 217996)
+++ trunk/Source/WebCore/page/animation/KeyframeAnimation.h	2017-06-09 17:52:42 UTC (rev 217997)
@@ -44,7 +44,7 @@
         return adoptRef(*new KeyframeAnimation(animation, renderer, compositeAnimation, unanimatedStyle));
     }
 
-    bool animate(CompositeAnimation*, RenderElement*, const RenderStyle* currentStyle, const RenderStyle* targetStyle, std::unique_ptr<RenderStyle>& animatedStyle, bool& didBlendStyle) override;
+    bool animate(CompositeAnimation&, RenderElement*, const RenderStyle* currentStyle, const RenderStyle& targetStyle, std::unique_ptr<RenderStyle>& animatedStyle, bool& didBlendStyle) override;
     void getAnimatedStyle(std::unique_ptr<RenderStyle>&) override;
 
     bool computeExtentOfTransformAnimation(LayoutRect&) const override;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to