Bug 1323121 - Destroy animations on hidden elements even if the animation has been already finished. r=birtles a=gchang
authorHiroyuki Ikezoe <hiikezoe@mozilla-japan.org>
Mon, 19 Dec 2016 14:00:43 +0900
changeset 353087 18ca74ed9f75b19ff614801c27e2ab50b10bd704
parent 353086 70c74e162506f62cbb5023659a7237604c037bd7
child 353088 1e46434c7b43128830f1cd34b4372c06366912ee
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbirtles, gchang
bugs1323121, 1197620
milestone52.0a2
Bug 1323121 - Destroy animations on hidden elements even if the animation has been already finished. r=birtles a=gchang We have added a test case in bug 1197620 that finished animation with fill:forwards on hidden elements restarts when the element gets visible, but it did not catch this bug. We should have added a case without fill:forwards. MozReview-Commit-ID: 5lfJkO3i9ME
dom/animation/test/mozilla/file_hide_and_show.html
layout/generic/nsFrame.cpp
--- a/dom/animation/test/mozilla/file_hide_and_show.html
+++ b/dom/animation/test/mozilla/file_hide_and_show.html
@@ -120,14 +120,43 @@ test(function(t) {
   parentElement.style.display = '';
   assert_equals(div.getAnimations().length, 1,
                 'Element which is no longer in display:none subtree has ' +
                 'animations again');
 
   assert_not_equals(div.getAnimations()[0], animation,
                     'Restarted animation is a newly-generated animation');
 
-}, 'Animation which has already finished starts playing when its parent ' +
+}, 'Animation with fill:forwards which has already finished starts playing ' +
+   'when its parent element is shown from "display:none" state');
+
+test(function(t) {
+  var parentElement = addDiv(t);
+  var div = addDiv(t, { style: 'animation: move 100s' });
+  parentElement.appendChild(div);
+  assert_equals(div.getAnimations().length, 1,
+                'display:initial element has animations');
+
+  var animation = div.getAnimations()[0];
+  animation.finish();
+  assert_equals(div.getAnimations().length, 0,
+                'Element does not have finished animations');
+
+  parentElement.style.display = 'none';
+  assert_equals(animation.playState, 'idle',
+                'The animation.playState should be idle');
+  assert_equals(div.getAnimations().length, 0,
+                'Element in display:none subtree has no animations');
+
+  parentElement.style.display = '';
+  assert_equals(div.getAnimations().length, 1,
+                'Element which is no longer in display:none subtree has ' +
+                'animations again');
+
+  assert_not_equals(div.getAnimations()[0], animation,
+                    'Restarted animation is a newly-generated animation');
+
+}, 'CSS Animation which has already finished starts playing when its parent ' +
    'element is shown from "display:none" state');
 
 done();
 </script>
 </body>
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -691,17 +691,18 @@ nsFrame::DestroyFrom(nsIFrame* aDestruct
       RestyleManager::ReframingStyleContexts* rsc =
         presContext->RestyleManager()->AsGecko()->GetReframingStyleContexts();
       if (rsc) {
         rsc->Put(mContent, mStyleContext);
       }
     }
   }
 
-  if (EffectSet::GetEffectSet(this)) {
+  if (HasCSSAnimations() || HasCSSTransitions() ||
+      EffectSet::GetEffectSet(this)) {
     // If no new frame for this element is created by the end of the
     // restyling process, stop animations and transitions for this frame
     if (presContext->RestyleManager()->IsGecko()) {
       RestyleManager::AnimationsWithDestroyedFrame* adf =
         presContext->RestyleManager()->AsGecko()->GetAnimationsWithDestroyedFrame();
       // AnimationsWithDestroyedFrame only lives during the restyling process.
       if (adf) {
         adf->Put(mContent, mStyleContext);