From e88b28e248be21e4dbe689f754de732912c080e7 Mon Sep 17 00:00:00 2001 From: Cathie Chen Date: Wed, 6 Dec 2023 13:36:59 +0000 Subject: [PATCH] Bug 1866566 - If there is change in over-all relevancy, update HiddenByContentVisibility for animations, r=emilio,hiro Differential Revision: https://phabricator.services.mozilla.com/D195009 --- dom/animation/Animation.cpp | 16 ++++ dom/animation/Animation.h | 1 + dom/animation/AnimationTimeline.cpp | 6 ++ dom/animation/AnimationTimeline.h | 1 + dom/animation/ScrollTimeline.cpp | 11 +++ dom/animation/ScrollTimeline.h | 3 + dom/base/Document.cpp | 5 ++ dom/base/Document.h | 1 + layout/base/PresShell.cpp | 18 +++- layout/base/nsPresContext.cpp | 5 ++ layout/base/nsPresContext.h | 2 + layout/generic/nsIFrame.cpp | 5 +- layout/generic/nsIFrame.h | 4 +- layout/style/TimelineCollection.h | 1 + layout/style/TimelineManager.cpp | 16 ++++ layout/style/TimelineManager.h | 2 + ...t-visibility-animation-and-scroll.html.ini | 2 - ...ibility-animation-in-auto-subtree.html.ini | 11 +-- ...h-scroll-timeline-in-auto-subtree.html.ini | 2 + ...scroll-timeline-in-hidden-subtree.html.ini | 2 + ...-visibility-animation-in-auto-subtree.html | 2 +- ...-with-scroll-timeline-in-auto-subtree.html | 82 +++++++++++++++++++ ...ith-scroll-timeline-in-hidden-subtree.html | 81 ++++++++++++++++++ ...ibility-web-animation-in-auto-subtree.html | 74 +++++++++++++++++ 24 files changed, 335 insertions(+), 18 deletions(-) delete mode 100644 testing/web-platform/meta/css/css-contain/content-visibility/content-visibility-animation-and-scroll.html.ini create mode 100644 testing/web-platform/meta/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-auto-subtree.html.ini create mode 100644 testing/web-platform/meta/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-hidden-subtree.html.ini create mode 100644 testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-auto-subtree.html create mode 100644 testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-hidden-subtree.html create mode 100644 testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-web-animation-in-auto-subtree.html diff --git a/dom/animation/Animation.cpp b/dom/animation/Animation.cpp index cd34d8765400..c0427bd2f458 100644 --- a/dom/animation/Animation.cpp +++ b/dom/animation/Animation.cpp @@ -1953,6 +1953,22 @@ void Animation::SetHiddenByContentVisibility(bool hidden) { GetTimeline()->NotifyAnimationContentVisibilityChanged(this, !hidden); } +void Animation::UpdateHiddenByContentVisibility() { + // To be consistent with nsIFrame::UpdateAnimationVisibility, here we only + // deal with CSSAnimation and CSSTransition. + if (!AsCSSAnimation() && !AsCSSTransition()) { + return; + } + NonOwningAnimationTarget target = GetTargetForAnimation(); + if (!target) { + return; + } + if (auto* frame = target.mElement->GetPrimaryFrame()) { + SetHiddenByContentVisibility( + frame->IsHiddenByContentVisibilityOnAnyAncestor()); + } +} + StickyTimeDuration Animation::IntervalStartTime( const StickyTimeDuration& aActiveDuration) const { MOZ_ASSERT(AsCSSTransition() || AsCSSAnimation(), diff --git a/dom/animation/Animation.h b/dom/animation/Animation.h index a9e082e80ae0..56c0f86d5087 100644 --- a/dom/animation/Animation.h +++ b/dom/animation/Animation.h @@ -399,6 +399,7 @@ class Animation : public DOMEventTargetHelper, bool IsHiddenByContentVisibility() const { return mHiddenByContentVisibility; } + void UpdateHiddenByContentVisibility(); DocGroup* GetDocGroup(); void SetSyncWithGeometricAnimations() { mSyncWithGeometricAnimations = true; } diff --git a/dom/animation/AnimationTimeline.cpp b/dom/animation/AnimationTimeline.cpp index e8ff3025a454..a684cd60cfee 100644 --- a/dom/animation/AnimationTimeline.cpp +++ b/dom/animation/AnimationTimeline.cpp @@ -112,4 +112,10 @@ void AnimationTimeline::NotifyAnimationContentVisibilityChanged( } } +void AnimationTimeline::UpdateHiddenByContentVisibility() { + for (Animation* animation : mAnimations) { + animation->UpdateHiddenByContentVisibility(); + } +} + } // namespace mozilla::dom diff --git a/dom/animation/AnimationTimeline.h b/dom/animation/AnimationTimeline.h index 5b33481ac7ff..6226bbb17908 100644 --- a/dom/animation/AnimationTimeline.h +++ b/dom/animation/AnimationTimeline.h @@ -113,6 +113,7 @@ class AnimationTimeline : public nsISupports, public nsWrapperCache { virtual void RemoveAnimation(Animation* aAnimation); virtual void NotifyAnimationContentVisibilityChanged(Animation* aAnimation, bool aIsVisible); + void UpdateHiddenByContentVisibility(); virtual Document* GetDocument() const = 0; diff --git a/dom/animation/ScrollTimeline.cpp b/dom/animation/ScrollTimeline.cpp index eeb9571494a7..27ea7de09abc 100644 --- a/dom/animation/ScrollTimeline.cpp +++ b/dom/animation/ScrollTimeline.cpp @@ -263,6 +263,17 @@ const nsIScrollableFrame* ScrollTimeline::GetScrollFrame() const { return nullptr; } +void ScrollTimeline::NotifyAnimationContentVisibilityChanged( + Animation* aAnimation, bool aIsVisible) { + AnimationTimeline::NotifyAnimationContentVisibilityChanged(aAnimation, + aIsVisible); + if (mAnimationOrder.isEmpty()) { + UnregisterFromScrollSource(); + } else { + RegisterWithScrollSource(); + } +} + // ------------------------------------ // Methods of ProgressTimelineScheduler // ------------------------------------ diff --git a/dom/animation/ScrollTimeline.h b/dom/animation/ScrollTimeline.h index 0984845dc8f2..58ab9586d946 100644 --- a/dom/animation/ScrollTimeline.h +++ b/dom/animation/ScrollTimeline.h @@ -197,6 +197,9 @@ class ScrollTimeline : public AnimationTimeline { PseudoStyleType aPseudoType, const StyleScrollTimeline& aNew); + void NotifyAnimationContentVisibilityChanged(Animation* aAnimation, + bool aIsVisible) override; + protected: virtual ~ScrollTimeline() { Teardown(); } ScrollTimeline() = delete; diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp index 84b0ad864da3..c43f308dc918 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -18983,4 +18983,9 @@ RadioGroupContainer& Document::OwnedRadioGroupContainer() { return *mRadioGroupContainer; } +void Document::UpdateHiddenByContentVisibilityForAnimations() { + for (AnimationTimeline* timeline : Timelines()) { + timeline->UpdateHiddenByContentVisibility(); + } +} } // namespace mozilla::dom diff --git a/dom/base/Document.h b/dom/base/Document.h index 7d9e65cf1e79..7e8fdfa23352 100644 --- a/dom/base/Document.h +++ b/dom/base/Document.h @@ -3034,6 +3034,7 @@ class Document : public nsINode, DocumentTimeline* Timeline(); LinkedList& Timelines() { return mTimelines; } + void UpdateHiddenByContentVisibilityForAnimations(); SVGSVGElement* GetSVGRootElement() const; diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp index 0fc7c310b3c7..0b23fd5e3d61 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -11950,8 +11950,15 @@ void PresShell::UpdateRelevancyOfContentVisibilityAutoFrames() { return; } + bool isRelevantContentChanged = false; for (nsIFrame* frame : mContentVisibilityAutoFrames) { - frame->UpdateIsRelevantContent(mContentVisibilityRelevancyToUpdate); + isRelevantContentChanged |= + frame->UpdateIsRelevantContent(mContentVisibilityRelevancyToUpdate); + } + if (isRelevantContentChanged) { + if (nsPresContext* presContext = GetPresContext()) { + presContext->UpdateHiddenByContentVisibilityForAnimations(); + } } mContentVisibilityRelevancyToUpdate.clear(); @@ -11985,6 +11992,7 @@ PresShell::ProximityToViewportResult PresShell::DetermineProximityToViewport() { auto input = DOMIntersectionObserver::ComputeInput( *mDocument, /* aRoot = */ nullptr, &rootMargin); + bool isRelevantContentChanged = false; for (nsIFrame* frame : mContentVisibilityAutoFrames) { auto* element = frame->GetContent()->AsElement(); result.mAnyScrollIntoViewFlag |= @@ -12005,7 +12013,8 @@ PresShell::ProximityToViewportResult PresShell::DetermineProximityToViewport() { .Intersects(); element->SetVisibleForContentVisibility(intersects); if (oldVisibility.isNothing() || *oldVisibility != intersects) { - frame->UpdateIsRelevantContent(ContentRelevancyReason::Visible); + isRelevantContentChanged |= + frame->UpdateIsRelevantContent(ContentRelevancyReason::Visible); } // 14.2.3.3 @@ -12013,6 +12022,11 @@ PresShell::ProximityToViewportResult PresShell::DetermineProximityToViewport() { result.mHadInitialDetermination = true; } } + if (isRelevantContentChanged) { + if (nsPresContext* presContext = GetPresContext()) { + presContext->UpdateHiddenByContentVisibilityForAnimations(); + } + } return result; } diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 99c435e281e1..0ed162c3a34d 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -3077,6 +3077,11 @@ PerformanceMainThread* nsPresContext::GetPerformanceMainThread() const { return nullptr; } +void nsPresContext::UpdateHiddenByContentVisibilityForAnimations() { + mDocument->UpdateHiddenByContentVisibilityForAnimations(); + TimelineManager()->UpdateHiddenByContentVisibilityForAnimations(); +} + #ifdef DEBUG void nsPresContext::ValidatePresShellAndDocumentReleation() const { diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index ed99f9a72026..550ef009a72d 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -1079,6 +1079,8 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr { return mFontPaletteValueSet; } + void UpdateHiddenByContentVisibilityForAnimations(); + protected: friend class nsRunnableMethod; void ThemeChangedInternal(); diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp index 2181365f9dbc..593536c85e1e 100644 --- a/layout/generic/nsIFrame.cpp +++ b/layout/generic/nsIFrame.cpp @@ -7003,7 +7003,7 @@ bool nsIFrame::IsDescendantOfTopLayerElement() const { return false; } -void nsIFrame::UpdateIsRelevantContent( +bool nsIFrame::UpdateIsRelevantContent( const ContentRelevancy& aRelevancyToUpdate) { MOZ_ASSERT(StyleDisplay()->ContentVisibility(*this) == StyleContentVisibility::Auto); @@ -7053,7 +7053,7 @@ void nsIFrame::UpdateIsRelevantContent( } if (!overallRelevancyChanged) { - return; + return false; } HandleLastRememberedSize(); @@ -7075,6 +7075,7 @@ void nsIFrame::UpdateIsRelevantContent( new AsyncEventDispatcher(element, event.forget()); DebugOnly rv = asyncDispatcher->PostDOMEvent(); NS_ASSERTION(NS_SUCCEEDED(rv), "AsyncEventDispatcher failed to dispatch"); + return true; } nsresult nsIFrame::CharacterDataChanged(const CharacterDataChangeInfo&) { diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 791d1ee905a1..97d00fd8d661 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -3303,8 +3303,10 @@ class nsIFrame : public nsQueryFrame { * Update the whether or not this frame is considered relevant content for the * purposes of `content-visibility: auto` according to the rules specified in * https://drafts.csswg.org/css-contain-2/#relevant-to-the-user. + * Returns true if the over-all relevancy changed. */ - void UpdateIsRelevantContent(const ContentRelevancy& aRelevancyToUpdate); + [[nodiscard]] bool UpdateIsRelevantContent( + const ContentRelevancy& aRelevancyToUpdate); /** * Get the "type" of the frame. diff --git a/layout/style/TimelineCollection.h b/layout/style/TimelineCollection.h index 1f61845e2e26..21e0b2b6bc39 100644 --- a/layout/style/TimelineCollection.h +++ b/layout/style/TimelineCollection.h @@ -55,6 +55,7 @@ class TimelineCollection final // if it does not already exist. static TimelineCollection* Get(const dom::Element* aElement, PseudoStyleType aPseudoType); + const TimelineMap& Timelines() const { return mTimelines; } private: // The element. Weak reference is fine since it owns us. diff --git a/layout/style/TimelineManager.cpp b/layout/style/TimelineManager.cpp index 78db0765e6fd..4adc03df173f 100644 --- a/layout/style/TimelineManager.cpp +++ b/layout/style/TimelineManager.cpp @@ -168,4 +168,20 @@ void TimelineManager::DoUpdateTimelines( // siblings when mutating {scroll|view}-timeline-name. } +void TimelineManager::UpdateHiddenByContentVisibilityForAnimations() { + for (auto* scrollTimelineCollection : mScrollTimelineCollections) { + for (ScrollTimeline* timeline : + scrollTimelineCollection->Timelines().Values()) { + timeline->UpdateHiddenByContentVisibility(); + } + } + + for (auto* viewTimelineCollection : mViewTimelineCollections) { + for (ViewTimeline* timeline : + viewTimelineCollection->Timelines().Values()) { + timeline->UpdateHiddenByContentVisibility(); + } + } +} + } // namespace mozilla diff --git a/layout/style/TimelineManager.h b/layout/style/TimelineManager.h index f52302a66162..3fc31a719c23 100644 --- a/layout/style/TimelineManager.h +++ b/layout/style/TimelineManager.h @@ -51,6 +51,8 @@ class TimelineManager { const ComputedStyle* aComputedStyle, ProgressTimelineType aType); + void UpdateHiddenByContentVisibilityForAnimations(); + private: template void DoUpdateTimelines(nsPresContext* aPresContext, dom::Element* aElement, diff --git a/testing/web-platform/meta/css/css-contain/content-visibility/content-visibility-animation-and-scroll.html.ini b/testing/web-platform/meta/css/css-contain/content-visibility/content-visibility-animation-and-scroll.html.ini deleted file mode 100644 index fa738b11fa8d..000000000000 --- a/testing/web-platform/meta/css/css-contain/content-visibility/content-visibility-animation-and-scroll.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[content-visibility-animation-and-scroll.html] - expected: TIMEOUT diff --git a/testing/web-platform/meta/css/css-contain/content-visibility/content-visibility-animation-in-auto-subtree.html.ini b/testing/web-platform/meta/css/css-contain/content-visibility/content-visibility-animation-in-auto-subtree.html.ini index d960484b9205..a4168d942a96 100644 --- a/testing/web-platform/meta/css/css-contain/content-visibility/content-visibility-animation-in-auto-subtree.html.ini +++ b/testing/web-platform/meta/css/css-contain/content-visibility/content-visibility-animation-in-auto-subtree.html.ini @@ -1,13 +1,4 @@ [content-visibility-animation-in-auto-subtree.html] expected: TIMEOUT - [Animation events do not fire for a CSS animation running in a content visibility subtree] - expected: TIMEOUT - - [The finished promise does not resolve due to the normal passage of time for a CSS animation in a content visibility subtree] - expected: NOTRUN - - [The finished promise does not resolve due to the normal passage of time for a CSS transition in a content visibility subtree] - expected: NOTRUN - [Events and promises are handled normally for animations without an owning element] - expected: NOTRUN + expected: TIMEOUT diff --git a/testing/web-platform/meta/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-auto-subtree.html.ini b/testing/web-platform/meta/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-auto-subtree.html.ini new file mode 100644 index 000000000000..44714a2940a4 --- /dev/null +++ b/testing/web-platform/meta/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-auto-subtree.html.ini @@ -0,0 +1,2 @@ +[content-visibility-animation-with-scroll-timeline-in-auto-subtree.html] + prefs: [layout.css.scroll-driven-animations.enabled:true] diff --git a/testing/web-platform/meta/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-hidden-subtree.html.ini b/testing/web-platform/meta/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-hidden-subtree.html.ini new file mode 100644 index 000000000000..82d675a7bbcf --- /dev/null +++ b/testing/web-platform/meta/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-hidden-subtree.html.ini @@ -0,0 +1,2 @@ +[content-visibility-animation-with-scroll-timeline-in-hidden-subtree.html] + prefs: [layout.css.scroll-driven-animations.enabled:true] diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-in-auto-subtree.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-in-auto-subtree.html index 50f04f94f3f7..493d591b4b3c 100644 --- a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-in-auto-subtree.html +++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-in-auto-subtree.html @@ -14,7 +14,7 @@ to { opacity: 0; } } #target { - background: 'green'; + background: green; height: 100px; width: 100px; } diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-auto-subtree.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-auto-subtree.html new file mode 100644 index 000000000000..0d9bde7d751b --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-auto-subtree.html @@ -0,0 +1,82 @@ + + +Test getComputedStyle on a CSS animation with scroll timeline in a content visibility subtree using content-visibility: auto + + + + + + +
+
+
+
+
+
+ + + diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-hidden-subtree.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-hidden-subtree.html new file mode 100644 index 000000000000..af29a200f159 --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-animation-with-scroll-timeline-in-hidden-subtree.html @@ -0,0 +1,81 @@ + + +Test getComputedStyle on a CSS animation with scroll-timeline in a content-visibility subtree + + + + + + +
+
+
+
+
+ + + diff --git a/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-web-animation-in-auto-subtree.html b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-web-animation-in-auto-subtree.html new file mode 100644 index 000000000000..a663e58fe03e --- /dev/null +++ b/testing/web-platform/tests/css/css-contain/content-visibility/content-visibility-web-animation-in-auto-subtree.html @@ -0,0 +1,74 @@ + + +Web Animation does not stop even if target is hidden by c-v + + + + + + +
+
+ +