Bug 1323121 - Destroy animations on hidden elements even if the animation has been already finished. r?birtles draft
authorHiroyuki Ikezoe <hiikezoe@mozilla-japan.org>
Mon, 19 Dec 2016 14:00:43 +0900
changeset 450883 63170bb83e41469f8b594c06bb9cf33ca2cf6457
parent 450805 2824deb82146bba070995a762cfc98ddb2d1decb
child 539861 c2da8a2832adfa482d79cd220e6c06d375e1a382
push id38983
push userhiikezoe@mozilla-japan.org
push dateMon, 19 Dec 2016 07:08:13 +0000
reviewersbirtles
bugs1323121, 1197620
milestone53.0a1
Bug 1323121 - Destroy animations on hidden elements even if the animation has been already finished. r?birtles 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);