Bug 1474247 - Remove the animation from the pending tracker if the new target element is in a different document. r?birtles
MozReview-Commit-ID: 1usQWhujUMC
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -391,16 +391,23 @@ public:
/**
* Performs the same steps as CancelPendingTasks and also rejects and
* recreates the ready promise if the animation was pending.
*/
void ResetPendingTasks();
/**
+ * Remove this animation from the pending animation tracker and reset
+ * mPendingReadyTime.
+ * Unlike CancelPendingTasks() this function preserves mPendingState.
+ */
+ void RemovePendingTasksFromTracker();
+
+ /**
* Used by subclasses to synchronously queue a cancel event in situations
* where the Animation may have been cancelled.
*
* We need to do this synchronously because after a CSS animation/transition
* is canceled, it will be released by its owning element and may not still
* exist when we would normally go to queue events on the next tick.
*/
virtual void MaybeQueueCancelEvent(const StickyTimeDuration& aActiveTime) {};
@@ -465,24 +472,16 @@ protected:
/**
* Remove this animation from the pending animation tracker and reset
* mPendingState as necessary. The caller is responsible for resolving or
* aborting the mReady promise as necessary.
*/
void CancelPendingTasks();
/**
- * Remove this animation from the pending animation tracker and reset
- * mPendingReadyTime.
- * Unlike the above CancelPendingTasks() this function preserves
- * mPendingState.
- */
- void RemovePendingTasksFromTracker();
-
- /**
* Returns true if this animation is not only play-pending, but has
* yet to be given a pending ready time. This roughly corresponds to
* animations that are waiting to be painted (since we set the pending
* ready time at the end of painting). Identifying such animations is
* useful because in some cases animations that are painted together
* may need to be synchronized.
*
* We don't, however, want to include animations with a fixed start time such
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -946,16 +946,26 @@ KeyframeEffect::SetTarget(const Nullable
ResetIsRunningOnCompositor();
RequestRestyle(EffectCompositor::RestyleType::Layer);
nsAutoAnimationMutationBatch mb(mTarget->mElement->OwnerDoc());
if (mAnimation) {
if (!newTarget) {
mAnimation->ResetPendingTasks();
+ } else if (mAnimation->Pending()) {
+ nsIDocument* newRenderedDocument =
+ newTarget->mElement->GetComposedDoc();
+ if (newRenderedDocument &&
+ newRenderedDocument != GetRenderedDocument()) {
+ // If the new target is in a different document, we need to remove
+ // the animation from the PendingAnimationTracker of the old document
+ // without changing pending state.
+ mAnimation->RemovePendingTasksFromTracker();
+ }
}
nsNodeUtils::AnimationRemoved(mAnimation);
}
}
mTarget = newTarget;
if (mTarget) {
--- a/dom/animation/test/mozilla/test_pending_animation_tracker.html
+++ b/dom/animation/test/mozilla/test_pending_animation_tracker.html
@@ -173,10 +173,34 @@ test(t => {
anim.effect.target = target;
assert_true(anim.pending, 'The animation should be still pending');
assert_true(SpecialPowers.DOMWindowUtils.isAnimationPending(anim),
'The animation should be now tracked by tracker');
}, 'Setting target element to the orphaned animation starts being tracked ' +
'by the tracker');
+test(t => {
+ const target = addDiv(t);
+ const anim = target.animate(null, 100 * MS_PER_SEC);
+ assert_true(anim.pending, 'The animation should be pending');
+ assert_true(SpecialPowers.DOMWindowUtils.isAnimationPending(anim),
+ 'The animation should be tracked by tracker');
+
+ const targetInIframe = iframe.contentDocument.createElement('div');
+ iframe.contentDocument.body.appendChild(targetInIframe);
+ t.add_cleanup(() => targetInIframe.remove());
+
+ anim.effect.target = targetInIframe;
+
+ assert_true(anim.pending, 'The animation should be still pending');
+ assert_false(SpecialPowers.DOMWindowUtils.isAnimationPending(anim),
+ 'The animation should no more be tracked by the tracker of ' +
+ 'the parent document');
+ assert_true(SpecialPowers.getDOMWindowUtils(iframe.contentWindow)
+ .isAnimationPending(anim),
+ 'The animation should be now tracked by the tracker of ' +
+ 'the iframe document');
+}, 'Moving target element to other document changes the pending animation ' +
+ 'tracker');
+
</script>
</body>