Bug 1383239 - Don't throttle non-visible changes involved animations on out-of-view elements when they are newly in-effect. r=birtles
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Fri, 20 Oct 2017 18:23:44 +0900
changeset 387344 7a477904ed4fa7331db873061e28938d868e93f4
parent 387343 3b598784dfd30d89c447cabe5ab4160597bf0bc3
child 387345 484a2644318f5af33d225ae015e2b7a5c2ff7ad9
push id32717
push userarchaeopteryx@coole-files.de
push dateFri, 20 Oct 2017 22:01:38 +0000
treeherdermozilla-central@69998f1363be [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbirtles
bugs1383239
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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