mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 07:13:20 +00:00
Bug 1822907 part 2: When handling a content-visibility change, don't insert already-completed animations into the timeline's sampling-order list. r=hiro
We have an invariant that the mAnimationOrder LinkedList is a subset of the mAnimations hashset (omitting any animations that are hidden due to content-visibility). This patch corrects one case where we were incorrectly inserting an animation into the linked list when it wasn't present in the hashset (because the animation had completed). This patch also adds some documentation to mention this invariant, and some assertions to enforce it in several places. Differential Revision: https://phabricator.services.mozilla.com/D173333
This commit is contained in:
parent
42d84e917d
commit
86fdc8655d
@ -46,6 +46,8 @@ bool AnimationTimeline::Tick() {
|
||||
for (Animation* animation = mAnimationOrder.getFirst(); animation;
|
||||
animation =
|
||||
static_cast<LinkedListElement<Animation>*>(animation)->getNext()) {
|
||||
MOZ_ASSERT(mAnimations.Contains(animation),
|
||||
"The sampling order list should be a subset of the hashset");
|
||||
MOZ_ASSERT(!animation->IsHiddenByContentVisibility(),
|
||||
"The sampling order list should not contain any animations "
|
||||
"that are hidden by content-visibility");
|
||||
@ -91,6 +93,8 @@ void AnimationTimeline::NotifyAnimationUpdated(Animation& aAnimation) {
|
||||
void AnimationTimeline::RemoveAnimation(Animation* aAnimation) {
|
||||
MOZ_ASSERT(!aAnimation->GetTimeline() || aAnimation->GetTimeline() == this);
|
||||
if (static_cast<LinkedListElement<Animation>*>(aAnimation)->isInList()) {
|
||||
MOZ_ASSERT(mAnimations.Contains(aAnimation),
|
||||
"The sampling order list should be a subset of the hashset");
|
||||
static_cast<LinkedListElement<Animation>*>(aAnimation)->remove();
|
||||
}
|
||||
mAnimations.Remove(aAnimation);
|
||||
@ -100,7 +104,9 @@ void AnimationTimeline::NotifyAnimationContentVisibilityChanged(
|
||||
Animation* aAnimation, bool aIsVisible) {
|
||||
bool inList =
|
||||
static_cast<LinkedListElement<Animation>*>(aAnimation)->isInList();
|
||||
if (aIsVisible && !inList) {
|
||||
MOZ_ASSERT(!inList || mAnimations.Contains(aAnimation),
|
||||
"The sampling order list should be a subset of the hashset");
|
||||
if (aIsVisible && !inList && mAnimations.Contains(aAnimation)) {
|
||||
mAnimationOrder.insertBack(aAnimation);
|
||||
} else if (!aIsVisible && inList) {
|
||||
static_cast<LinkedListElement<Animation>*>(aAnimation)->remove();
|
||||
|
@ -125,6 +125,7 @@ class AnimationTimeline : public nsISupports, public nsWrapperCache {
|
||||
// We store them in (a) a hashset for quick lookup, and (b) a LinkedList
|
||||
// to maintain a fixed sampling order. Animations that are hidden by
|
||||
// `content-visibility` are not sampled and will only be in the hashset.
|
||||
// The LinkedList should always be a subset of the hashset.
|
||||
//
|
||||
// The hashset keeps a strong reference to each animation since
|
||||
// dealing with addref/release with LinkedList is difficult.
|
||||
|
@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="test-wait">
|
||||
<meta charset="utf-8">
|
||||
<link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
|
||||
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1822907">
|
||||
<style>
|
||||
#inner {
|
||||
/* Extremely short so that we can just do a double-rAF and
|
||||
* expect that this transition will have completed: */
|
||||
transition: opacity 0.01s;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function setup() {
|
||||
// Flush style, in case the document hasn't been styled yet:
|
||||
let origOpacity = getComputedStyle(inner).opacity;
|
||||
|
||||
// Trigger the (extremely short) transition, and proceed to next step
|
||||
// when it finishes.
|
||||
inner.addEventListener("transitionend", handleTransitionEnd);
|
||||
inner.style.opacity = "0.8";
|
||||
}
|
||||
function handleTransitionEnd(e) {
|
||||
// Hide & unhide the subtree that contained the transition:
|
||||
foo.style.contentVisibility = "hidden";
|
||||
document.documentElement.offsetHeight; // flush layout
|
||||
foo.style.contentVisibility = "";
|
||||
|
||||
// Double-rAF to see if we crash when animations are resampled.
|
||||
requestAnimationFrame(() => { requestAnimationFrame(finish) });
|
||||
}
|
||||
function finish() {
|
||||
// If we get here, we've succeeded; hooray!
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
</script>
|
||||
<body onload="setup()">
|
||||
<div id="foo">
|
||||
Hello
|
||||
<div id="inner">Inner</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user