Bug 1383239 - Don't throttle non-visible changes involved animations on out-of-view elements when they are newly in-effect. r?birtles draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Fri, 20 Oct 2017 18:23:44 +0900
changeset 683828 92bb607004f49d3f0e78fcfbaff8f91961a38be9
parent 683640 cb2a30c6c7f6c738bbf3dfaa7b9d3332ad17e729
child 736732 31357a0ac3c38a46f5fe6a1ec0fe1921243a297b
push id85469
push userhikezoe@mozilla.com
push dateFri, 20 Oct 2017 09:24:22 +0000
reviewersbirtles
bugs1383239
milestone58.0a1
Bug 1383239 - Don't throttle non-visible changes involved animations on out-of-view elements when they are newly in-effect. r?birtles MozReview-Commit-ID: G9OL3pPZarr
dom/animation/KeyframeEffectReadOnly.cpp
layout/reftests/css-animations/animation-initially-out-of-view-with-delay-ref.html
layout/reftests/css-animations/animation-initially-out-of-view-with-delay.html
layout/reftests/css-animations/reftest.list
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -120,33 +120,35 @@ KeyframeEffectReadOnly::NotifyAnimationT
   // the compositor and hence they won't have their compositor status
   // updated. As a result, we need to make sure we clear their compositor
   // status here.
   bool isRelevant = mAnimation && mAnimation->IsRelevant();
   if (!isRelevant) {
     ResetIsRunningOnCompositor();
   }
 
-  // Detect changes to "in effect" status since we need to recalculate the
-  // animation cascade for this element whenever that changes.
-  bool inEffect = IsInEffect();
-  if (inEffect != mInEffectOnLastAnimationTimingUpdate) {
-    MarkCascadeNeedsUpdate();
-    mInEffectOnLastAnimationTimingUpdate = inEffect;
-  }
-
   // Request restyle if necessary.
   if (mAnimation && !mProperties.IsEmpty() && HasComputedTimingChanged()) {
     EffectCompositor::RestyleType restyleType =
       CanThrottle() ?
       EffectCompositor::RestyleType::Throttled :
       EffectCompositor::RestyleType::Standard;
     RequestRestyle(restyleType);
   }
 
+  // Detect changes to "in effect" status since we need to recalculate the
+  // animation cascade for this element whenever that changes.
+  // Note that updating mInEffectOnLastAnimationTimingUpdate has to be done
+  // after above CanThrottle() call since the function uses the flag inside it.
+  bool inEffect = IsInEffect();
+  if (inEffect != mInEffectOnLastAnimationTimingUpdate) {
+    MarkCascadeNeedsUpdate();
+    mInEffectOnLastAnimationTimingUpdate = inEffect;
+  }
+
   // If we're no longer "in effect", our ComposeStyle method will never be
   // called and we will never have a chance to update mProgressOnLastCompose
   // and mCurrentIterationOnLastCompose.
   // We clear them here to ensure that if we later become "in effect" we will
   // request a restyle (above).
   if (!inEffect) {
      mProgressOnLastCompose.SetNull();
      mCurrentIterationOnLastCompose = 0;
@@ -1370,19 +1372,20 @@ KeyframeEffectReadOnly::CanThrottle() co
     // a) No target element
     // b) The target element has no frame, e.g. because it is in a display:none
     //    subtree.
     // In either case we can throttle the animation because there is no
     // need to update on the main thread.
     return true;
   }
 
-  // We can throttle the animation if the animation is paint only and
-  // the target frame is out of view or the document is in background tabs.
-  if (CanIgnoreIfNotVisible()) {
+  // Unless we are newly in-effect, we can throttle the animation if the
+  // animation is paint only and the target frame is out of view or the document
+  // is in background tabs.
+  if (mInEffectOnLastAnimationTimingUpdate && CanIgnoreIfNotVisible()) {
     nsIPresShell* presShell = GetPresShell();
     if ((presShell && !presShell->IsActive()) ||
         frame->IsScrolledOutOfView()) {
       return true;
     }
   }
 
   // First we need to check layer generation and transform overflow
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/animation-initially-out-of-view-with-delay-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<title>Bug 1383239</title>
+<style>
+div {
+ position: absolute;
+ background: orange;
+ width: 20px;
+ height: 20px;
+ left: 0px;
+}
+</style>
+<div></div>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-animations/animation-initially-out-of-view-with-delay.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html class="reftest-wait reftest-no-flush">
+<title>Bug 1383239</title>
+<style>
+div {
+ position: absolute;
+ left: -9999px;
+ background: orange;
+ width: 20px;
+ height: 20px;
+ animation: anim 100s 0.1s infinite;
+}
+
+@keyframes anim {
+ 0% {
+  left: 0px;
+ }
+ 100% {
+  left: 0px;
+ }
+}
+</style>
+<div></div>
+<script>
+document.querySelector('div').addEventListener('animationstart', ()=> {
+  document.documentElement.classList.remove('reftest-wait');
+});
+</script>
+</html>
--- a/layout/reftests/css-animations/reftest.list
+++ b/layout/reftests/css-animations/reftest.list
@@ -1,14 +1,15 @@
 == screen-animations.html screen-animations-ref.html
 != screen-animations.html screen-animations-notref.html
 skip-if(stylo) fails == print-no-animations.html print-no-animations-ref.html # reftest harness doesn't actually make pres context non-dynamic for reftest-paged tests. Bug 1374154 for stylo
 skip-if(stylo) fails != print-no-animations.html print-no-animations-notref.html # reftest harness doesn't actually make pres context non-dynamic for reftest-paged tests. Bug 1374154 for stylo
 == animate-opacity.html animate-opacity-ref.html
 == animate-preserves3d.html animate-preserves3d-ref.html
+== animation-initially-out-of-view-with-delay.html animation-initially-out-of-view-with-delay-ref.html
 == animation-on-empty-height-frame.html about:blank
 == in-visibility-hidden-animation.html in-visibility-hidden-animation-ref.html
 == in-visibility-hidden-animation-pseudo-element.html in-visibility-hidden-animation-pseudo-element-ref.html
 == partially-out-of-view-animation.html partially-out-of-view-animation-ref.html
 == animate-display-table-opacity.html animate-display-table-opacity-ref.html
 # We need to run 100% opacity test case when OMTA is disabled to check that the animation creates a stacking context even if the animation is not running on the compositor
 test-pref(layers.offmainthreadcomposition.async-animations,false) == stacking-context-opacity-1-animation.html stacking-context-animation-ref.html
 # We need to run transform:none test case when OMTA is disabled to check that the animation creates a stacking context even if the animation is not running on the compositor