diff --git a/dom/animation/DocumentTimeline.cpp b/dom/animation/DocumentTimeline.cpp index 804ae661600f..81fc2bcb4c4c 100644 --- a/dom/animation/DocumentTimeline.cpp +++ b/dom/animation/DocumentTimeline.cpp @@ -19,7 +19,6 @@ namespace mozilla::dom { NS_IMPL_CYCLE_COLLECTION_CLASS(DocumentTimeline) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DocumentTimeline, AnimationTimeline) - tmp->UnregisterFromRefreshDriver(); if (tmp->isInList()) { tmp->remove(); } @@ -45,7 +44,6 @@ DocumentTimeline::DocumentTimeline(Document* aDocument, : AnimationTimeline(aDocument->GetParentObject(), aDocument->GetScopeObject()->GetRTPCallerType()), mDocument(aDocument), - mIsObservingRefreshDriver(false), mOriginTime(aOriginTime) { if (mDocument) { mDocument->Timelines().insertBack(this); @@ -55,9 +53,6 @@ DocumentTimeline::DocumentTimeline(Document* aDocument, } DocumentTimeline::~DocumentTimeline() { - MOZ_RELEASE_ASSERT(!mIsObservingRefreshDriver, - "Timeline should have disassociated" - " from the refresh driver before being destroyed"); if (isInList()) { remove(); } @@ -105,11 +100,8 @@ TimeStamp DocumentTimeline::GetCurrentTimeStamp() const { : mLastRefreshDriverTime; } -void DocumentTimeline::UpdateLastRefreshDriverTime(TimeStamp aKnownTime) { +void DocumentTimeline::UpdateLastRefreshDriverTime() { TimeStamp result = [&] { - if (!aKnownTime.IsNull()) { - return aKnownTime; - } if (auto* rd = GetRefreshDriver()) { return rd->MostRecentRefresh(); }; @@ -157,110 +149,53 @@ Nullable DocumentTimeline::ToTimelineTime( void DocumentTimeline::NotifyAnimationUpdated(Animation& aAnimation) { AnimationTimeline::NotifyAnimationUpdated(aAnimation); - if (!mIsObservingRefreshDriver && !mAnimationOrder.isEmpty()) { - nsRefreshDriver* refreshDriver = GetRefreshDriver(); - if (refreshDriver) { + if (!mAnimationOrder.isEmpty()) { + if (nsRefreshDriver* refreshDriver = GetRefreshDriver()) { MOZ_ASSERT(isInList(), "We should not register with the refresh driver if we are not" " in the document's list of timelines"); - - ObserveRefreshDriver(refreshDriver); + refreshDriver->EnsureAnimationUpdate(); } } } -void DocumentTimeline::MostRecentRefreshTimeUpdated() { - MOZ_ASSERT(mIsObservingRefreshDriver); - MOZ_ASSERT(GetRefreshDriver(), - "Should be able to reach refresh driver from within WillRefresh"); - - nsAutoAnimationMutationBatch mb(mDocument); - - TickState state; - bool ticked = Tick(state); - if (!ticked) { - // We already assert that GetRefreshDriver() is non-null at the beginning - // of this function but we check it again here to be sure that ticking - // animations does not have any side effects that cause us to lose the - // connection with the refresh driver, such as triggering the destruction - // of mDocument's PresShell. - MOZ_ASSERT(GetRefreshDriver(), - "Refresh driver should still be valid at end of WillRefresh"); - UnregisterFromRefreshDriver(); - } -} - void DocumentTimeline::TriggerAllPendingAnimationsNow() { for (Animation* animation : mAnimationOrder) { animation->TryTriggerNow(); } } -void DocumentTimeline::WillRefresh(TimeStamp aTime) { - UpdateLastRefreshDriverTime(); - MostRecentRefreshTimeUpdated(); -} - -void DocumentTimeline::NotifyTimerAdjusted(TimeStamp aTime) { - MostRecentRefreshTimeUpdated(); -} - -void DocumentTimeline::ObserveRefreshDriver(nsRefreshDriver* aDriver) { - MOZ_RELEASE_ASSERT(!mIsObservingRefreshDriver, - "shouldn't register as an observer more than once"); - // Set the mIsObservingRefreshDriver flag before calling AddRefreshObserver - // since it might end up calling NotifyTimerAdjusted which calls - // MostRecentRefreshTimeUpdated which has an assertion for - // mIsObserveingRefreshDriver check. - mIsObservingRefreshDriver = true; - aDriver->AddRefreshObserver(this, FlushType::Style, - "DocumentTimeline animations"); - aDriver->AddTimerAdjustmentObserver(this); -} - -void DocumentTimeline::NotifyRefreshDriverCreated(nsRefreshDriver* aDriver) { - MOZ_RELEASE_ASSERT( - !mIsObservingRefreshDriver, - "Timeline should not be observing the refresh driver before" - " it is created"); - - if (!mAnimationOrder.isEmpty()) { - MOZ_ASSERT(isInList(), - "We should not register with the refresh driver if we are not" - " in the document's list of timelines"); - ObserveRefreshDriver(aDriver); - // Although we have started observing the refresh driver, it's possible we - // could perform a paint before the first refresh driver tick happens. To - // ensure we're in a consistent state in that case we run the first tick - // manually. - MostRecentRefreshTimeUpdated(); - } -} - -void DocumentTimeline::DisconnectRefreshDriver(nsRefreshDriver* aDriver) { - MOZ_ASSERT(mIsObservingRefreshDriver); - - aDriver->RemoveRefreshObserver(this, FlushType::Style); - aDriver->RemoveTimerAdjustmentObserver(this); - mIsObservingRefreshDriver = false; -} - -void DocumentTimeline::NotifyRefreshDriverDestroying(nsRefreshDriver* aDriver) { - if (!mIsObservingRefreshDriver) { +void DocumentTimeline::WillRefresh() { + if (!mDocument->GetPresShell()) { + // If we're not displayed, don't tick animations. return; } + UpdateLastRefreshDriverTime(); + if (mAnimationOrder.isEmpty()) { + return; + } + nsAutoAnimationMutationBatch mb(mDocument); - DisconnectRefreshDriver(aDriver); + TickState state; + bool ticked = Tick(state); + if (!ticked) { + return; + } + // We already assert that GetRefreshDriver() is non-null at the beginning + // of this function but we check it again here to be sure that ticking + // animations does not have any side effects that cause us to lose the + // connection with the refresh driver, such as triggering the destruction + // of mDocument's PresShell. + if (nsRefreshDriver* refreshDriver = GetRefreshDriver()) { + refreshDriver->EnsureAnimationUpdate(); + } else { + MOZ_ASSERT_UNREACHABLE( + "Refresh driver should still be valid at end of WillRefresh"); + } } void DocumentTimeline::RemoveAnimation(Animation* aAnimation) { AnimationTimeline::RemoveAnimation(aAnimation); - - if (!mIsObservingRefreshDriver || !mAnimationOrder.isEmpty()) { - return; - } - - UnregisterFromRefreshDriver(); } void DocumentTimeline::NotifyAnimationContentVisibilityChanged( @@ -268,19 +203,11 @@ void DocumentTimeline::NotifyAnimationContentVisibilityChanged( AnimationTimeline::NotifyAnimationContentVisibilityChanged(aAnimation, aIsVisible); - if (mIsObservingRefreshDriver && mAnimationOrder.isEmpty()) { - UnregisterFromRefreshDriver(); - } - - if (!mIsObservingRefreshDriver && !mAnimationOrder.isEmpty()) { - nsRefreshDriver* refreshDriver = GetRefreshDriver(); - if (refreshDriver) { - MOZ_ASSERT(isInList(), - "We should not register with the refresh driver if we are not" - " in the document's list of timelines"); - - ObserveRefreshDriver(refreshDriver); - } + if (nsRefreshDriver* refreshDriver = GetRefreshDriver()) { + MOZ_ASSERT(isInList(), + "We should not register with the refresh driver if we are not" + " in the document's list of timelines"); + refreshDriver->EnsureAnimationUpdate(); } } @@ -302,20 +229,7 @@ nsRefreshDriver* DocumentTimeline::GetRefreshDriver() const { if (MOZ_UNLIKELY(!presContext)) { return nullptr; } - return presContext->RefreshDriver(); } -void DocumentTimeline::UnregisterFromRefreshDriver() { - if (!mIsObservingRefreshDriver) { - return; - } - - nsRefreshDriver* refreshDriver = GetRefreshDriver(); - if (!refreshDriver) { - return; - } - DisconnectRefreshDriver(refreshDriver); -} - } // namespace mozilla::dom diff --git a/dom/animation/DocumentTimeline.h b/dom/animation/DocumentTimeline.h index d4e763ea90f8..c702d0f40821 100644 --- a/dom/animation/DocumentTimeline.h +++ b/dom/animation/DocumentTimeline.h @@ -14,15 +14,12 @@ #include "AnimationTimeline.h" #include "nsDOMNavigationTiming.h" // for DOMHighResTimeStamp #include "nsRefreshDriver.h" -#include "nsRefreshObservers.h" struct JSContext; namespace mozilla::dom { class DocumentTimeline final : public AnimationTimeline, - public nsARefreshObserver, - public nsATimerAdjustmentObserver, public LinkedListElement { public: DocumentTimeline(Document* aDocument, const TimeDuration& aOriginTime); @@ -35,8 +32,7 @@ class DocumentTimeline final : public AnimationTimeline, NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(DocumentTimeline, AnimationTimeline) - virtual JSObject* WrapObject(JSContext* aCx, - JS::Handle aGivenProto) override; + JSObject* WrapObject(JSContext*, JS::Handle aGivenProto) override; static already_AddRefed Constructor( const GlobalObject& aGlobal, const DocumentTimelineOptions& aOptions, @@ -46,7 +42,7 @@ class DocumentTimeline final : public AnimationTimeline, // This is deliberately _not_ called GetCurrentTime since that would clash // with a macro defined in winbase.h - virtual Nullable GetCurrentTimeAsDuration() const override; + Nullable GetCurrentTimeAsDuration() const override; bool TracksWallclockTime() const override; Nullable ToTimelineTime( @@ -61,27 +57,17 @@ class DocumentTimeline final : public AnimationTimeline, void TriggerAllPendingAnimationsNow(); - // nsARefreshObserver methods - void WillRefresh(TimeStamp aTime) override; - // nsATimerAdjustmentObserver methods - void NotifyTimerAdjusted(TimeStamp aTime) override; - - void NotifyRefreshDriverCreated(nsRefreshDriver* aDriver); - void NotifyRefreshDriverDestroying(nsRefreshDriver* aDriver); + void WillRefresh(); Document* GetDocument() const override { return mDocument; } - void UpdateLastRefreshDriverTime(TimeStamp aKnownTime = {}); + void UpdateLastRefreshDriverTime(); bool IsMonotonicallyIncreasing() const override { return true; } protected: TimeStamp GetCurrentTimeStamp() const; nsRefreshDriver* GetRefreshDriver() const; - void UnregisterFromRefreshDriver(); - void MostRecentRefreshTimeUpdated(); - void ObserveRefreshDriver(nsRefreshDriver* aDriver); - void DisconnectRefreshDriver(nsRefreshDriver* aDriver); RefPtr mDocument; @@ -89,8 +75,6 @@ class DocumentTimeline final : public AnimationTimeline, // we don't have a refresh driver (e.g. because we are in a display:none // iframe). TimeStamp mLastRefreshDriverTime; - bool mIsObservingRefreshDriver; - TimeDuration mOriginTime; }; diff --git a/dom/animation/test/chrome/test_running_on_compositor.html b/dom/animation/test/chrome/test_running_on_compositor.html index d8c1d0573e40..cceb4eab066f 100644 --- a/dom/animation/test/chrome/test_running_on_compositor.html +++ b/dom/animation/test/chrome/test_running_on_compositor.html @@ -88,11 +88,12 @@ promise_test(async t => { div.style.animationPlayState = 'paused'; await animation.ready; + await waitForPaints(); assert_animation_is_not_running_on_compositor(animation, 'Animation reports that it is NOT running on the compositor' + ' when paused'); -}, ''); +}, 'Basic test'); promise_test(async t => { var div = addDiv(t, { style: 'animation: z-index 100s' }); @@ -127,6 +128,8 @@ promise_test(async t => { animation.pause(); await animation.ready; + await waitForPaints(); + assert_animation_is_not_running_on_compositor(animation, 'Animation reports that it is NOT running on the compositor' + ' when animation.pause() is called'); diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp index 7f3349988360..739dfd4bba2c 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -994,8 +994,8 @@ void PresShell::Init(nsPresContext* aPresContext, nsViewManager* aViewManager) { animCtrl->NotifyRefreshDriverCreated(GetPresContext()->RefreshDriver()); } - for (DocumentTimeline* timeline : mDocument->Timelines()) { - timeline->NotifyRefreshDriverCreated(GetPresContext()->RefreshDriver()); + for (DocumentTimeline* timelines : mDocument->Timelines()) { + timelines->UpdateLastRefreshDriverTime(); } // Get our activeness from the docShell. @@ -1338,9 +1338,6 @@ void PresShell::Destroy() { if (mDocument->HasAnimationController()) { mDocument->GetAnimationController()->NotifyRefreshDriverDestroying(rd); } - for (DocumentTimeline* timeline : mDocument->Timelines()) { - timeline->NotifyRefreshDriverDestroying(rd); - } } if (mPresContext) { diff --git a/layout/base/nsRefreshDriver.cpp b/layout/base/nsRefreshDriver.cpp index 4ded041f53a4..75d05ae7e446 100644 --- a/layout/base/nsRefreshDriver.cpp +++ b/layout/base/nsRefreshDriver.cpp @@ -50,6 +50,7 @@ #include "nsComponentManagerUtils.h" #include "mozilla/Logging.h" #include "mozilla/dom/Document.h" +#include "mozilla/dom/DocumentTimeline.h" #include "mozilla/dom/DocumentInlines.h" #include "nsIXULRuntime.h" #include "jsapi.h" @@ -1364,6 +1365,7 @@ nsRefreshDriver::nsRefreshDriver(nsPresContext* aPresContext) mNotifyDOMContentFlushed(false), mNeedToUpdateIntersectionObservations(false), mNeedToUpdateResizeObservers(false), + mNeedToUpdateAnimations(false), mMightNeedMediaQueryListenerUpdate(false), mNeedToUpdateContentRelevancy(false), mInNormalTick(false), @@ -1489,18 +1491,6 @@ bool nsRefreshDriver::RemoveRefreshObserver(nsARefreshObserver* aObserver, return true; } -void nsRefreshDriver::AddTimerAdjustmentObserver( - nsATimerAdjustmentObserver* aObserver) { - MOZ_ASSERT(!mTimerAdjustmentObservers.Contains(aObserver)); - mTimerAdjustmentObservers.AppendElement(aObserver); -} - -void nsRefreshDriver::RemoveTimerAdjustmentObserver( - nsATimerAdjustmentObserver* aObserver) { - MOZ_ASSERT(mTimerAdjustmentObservers.Contains(aObserver)); - mTimerAdjustmentObservers.RemoveElement(aObserver); -} - void nsRefreshDriver::PostVisualViewportResizeEvent( VVPResizeEvent* aResizeEvent) { mVisualViewportResizeEvents.AppendElement(aResizeEvent); @@ -1885,11 +1875,6 @@ void nsRefreshDriver::EnsureTimerStarted(EnsureTimerStartedFlags aFlags) { if (mMostRecentRefresh != mActiveTimer->MostRecentRefresh()) { mMostRecentRefresh = mActiveTimer->MostRecentRefresh(); - - for (nsATimerAdjustmentObserver* obs : - mTimerAdjustmentObservers.EndLimitedRange()) { - obs->NotifyTimerAdjusted(mMostRecentRefresh); - } } } @@ -1919,7 +1904,6 @@ uint32_t nsRefreshDriver::ObserverCount() const { sum += mThrottledFrameRequestCallbackDocs.Length(); sum += mViewManagerFlushIsPending; sum += mEarlyRunners.Length(); - sum += mTimerAdjustmentObservers.Length(); sum += mAutoFocusFlushDocuments.Length(); return sum; } @@ -2011,6 +1995,9 @@ auto nsRefreshDriver::GetReasonsToTick() const -> TickReasons { if (mNeedToUpdateResizeObservers) { reasons |= TickReasons::eNeedsToNotifyResizeObservers; } + if (mNeedToUpdateAnimations) { + reasons |= TickReasons::eNeedsToUpdateAnimations; + } if (mNeedToUpdateIntersectionObservations) { reasons |= TickReasons::eNeedsToUpdateIntersectionObservations; } @@ -2054,6 +2041,9 @@ void nsRefreshDriver::AppendTickReasonsToString(TickReasons aReasons, if (aReasons & TickReasons::eNeedsToNotifyResizeObservers) { aStr.AppendLiteral(" NeedsToNotifyResizeObservers"); } + if (aReasons & TickReasons::eNeedsToUpdateAnimations) { + aStr.AppendLiteral(" NeedsToUpdateAnimations"); + } if (aReasons & TickReasons::eNeedsToUpdateIntersectionObservations) { aStr.AppendLiteral(" NeedsToUpdateIntersectionObservations"); } @@ -2344,11 +2334,41 @@ void nsRefreshDriver::DetermineProximityToViewportAndNotifyResizeObservers() { } } -void nsRefreshDriver::DispatchAnimationEvents() { +static CallState UpdateAndReduceAnimations(Document& aDocument) { + for (DocumentTimeline* timeline : aDocument.Timelines()) { + timeline->WillRefresh(); + } + + if (nsPresContext* pc = aDocument.GetPresContext()) { + if (pc->EffectCompositor()->NeedsReducing()) { + pc->EffectCompositor()->ReduceAnimations(); + } + } + aDocument.EnumerateSubDocuments(UpdateAndReduceAnimations); + return CallState::Continue; +} + +void nsRefreshDriver::UpdateAnimationsAndSendEvents() { + // TODO(emilio): Can we early-return here if mNeedToUpdateAnimations is + // already false? + mNeedToUpdateAnimations = false; if (!mPresContext) { return; } + { + // Animation updates may queue Promise resolution microtasks. We shouldn't + // run these, however, until we have fully updated the animation state. As + // per the "update animations and send events" procedure[1], we should + // remove replaced animations and then run these microtasks before + // dispatching the corresponding animation events. + // + // [1]: + // https://drafts.csswg.org/web-animations-1/#update-animations-and-send-events + nsAutoMicroTask mt; + UpdateAndReduceAnimations(*mPresContext->Document()); + } + // Hold all AnimationEventDispatcher in mAnimationEventFlushObservers as // a RefPtr<> array since each AnimationEventDispatcher might be destroyed // during processing the previous dispatcher. @@ -2495,16 +2515,6 @@ void nsRefreshDriver::CancelIdleTask(Task* aTask) { } } -static CallState ReduceAnimations(Document& aDocument) { - if (nsPresContext* pc = aDocument.GetPresContext()) { - if (pc->EffectCompositor()->NeedsReducing()) { - pc->EffectCompositor()->ReduceAnimations(); - } - } - aDocument.EnumerateSubDocuments(ReduceAnimations); - return CallState::Continue; -} - bool nsRefreshDriver::TickObserverArray(uint32_t aIdx, TimeStamp aNowTime) { MOZ_ASSERT(aIdx < ArrayLength(mObservers)); for (RefPtr obs : mObservers[aIdx].EndLimitedRange()) { @@ -2667,28 +2677,6 @@ void nsRefreshDriver::Tick(VsyncId aId, TimeStamp aNowTime, return StopTimer(); } - // Any animation timelines updated above (animation timelines are style flush - // observers) may cause animations to queue Promise resolution microtasks. We - // shouldn't run these, however, until we have fully updated the animation - // state. - // - // As per the "update animations and send events" procedure[1], we should - // remove replaced animations and then run these microtasks before - // dispatching the corresponding animation events. - // - // FIXME(emilio, bug 1896762): This comment doesn't make much sense to me. - // We're running micro-tasks in the block below, but we don't "Update - // animations and send events" until we hit DispatchAnimationEvents() below. - // We should probably refactor the setup so that animation timelines are - // ticked as part of step 11 below or so, and do this only then. - // - // [1]: - // https://drafts.csswg.org/web-animations-1/#update-animations-and-send-events - { - nsAutoMicroTask mt; - ReduceAnimations(*mPresContext->Document()); - } - // Check if running the microtask checkpoint above caused the pres context to // be destroyed. if (!mPresContext || !mPresContext->GetPresShell()) { @@ -2713,7 +2701,7 @@ void nsRefreshDriver::Tick(VsyncId aId, TimeStamp aNowTime, EvaluateMediaQueriesAndReportChanges(); // Step 11. For each doc of docs, update animations and send events for doc. - DispatchAnimationEvents(); + UpdateAnimationsAndSendEvents(); // Step 12. For each doc of docs, run the fullscreen steps for doc. RunFullscreenSteps(); diff --git a/layout/base/nsRefreshDriver.h b/layout/base/nsRefreshDriver.h index 72f4d3912c14..e10d525f343c 100644 --- a/layout/base/nsRefreshDriver.h +++ b/layout/base/nsRefreshDriver.h @@ -103,12 +103,6 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator, const char* aObserverDescription); bool RemoveRefreshObserver(nsARefreshObserver* aObserver, mozilla::FlushType aFlushType); - /** - * Add / remove an observer wants to know the time when the refresh driver - * updated the most recent refresh time due to its active timer changes. - */ - void AddTimerAdjustmentObserver(nsATimerAdjustmentObserver* aObserver); - void RemoveTimerAdjustmentObserver(nsATimerAdjustmentObserver* aObserver); void PostVisualViewportResizeEvent(VVPResizeEvent* aResizeEvent); void DispatchVisualViewportResizeEvents(); @@ -417,6 +411,11 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator, mNeedToUpdateResizeObservers = true; } + void EnsureAnimationUpdate() { + EnsureTimerStarted(); + mNeedToUpdateAnimations = true; + } + void ScheduleMediaQueryListenerUpdate() { EnsureTimerStarted(); mMightNeedMediaQueryListenerUpdate = true; @@ -446,6 +445,7 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator, eHasPendingMediaQueryListeners = 1 << 7, eNeedsToNotifyResizeObservers = 1 << 8, eRootNeedsMoreTicksForUserInput = 1 << 9, + eNeedsToUpdateAnimations = 1 << 10, }; void AddForceNotifyContentfulPaintPresContext(nsPresContext* aPresContext); @@ -487,7 +487,7 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator, MOZ_CAN_RUN_SCRIPT void FlushAutoFocusDocuments(); void RunFullscreenSteps(); - void DispatchAnimationEvents(); + void UpdateAnimationsAndSendEvents(); MOZ_CAN_RUN_SCRIPT void RunFrameRequestCallbacks(mozilla::TimeStamp aNowTime); void UpdateIntersectionObservations(mozilla::TimeStamp aNowTime); @@ -643,6 +643,9 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator, // all our documents. bool mNeedToUpdateResizeObservers : 1; + // True if we need to update animations. + bool mNeedToUpdateAnimations : 1; + // True if we might need to report media query changes in any of our // documents. bool mMightNeedMediaQueryListenerUpdate : 1; @@ -673,12 +676,6 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator, // separate arrays for each flush type we support ObserverArray mObservers[3]; - // These observers should NOT be included in HasObservers() since that method - // is used to determine whether or not to stop the timer, or restore it when - // thawing the refresh driver. On the other hand these observers are intended - // to be called when the timer is re-started and should not influence its - // starting or stopping. - nsTObserverArray mTimerAdjustmentObservers; nsTArray mCompositionPayloads; RequestTable mRequests; ImageStartTable mStartTable; diff --git a/layout/base/nsRefreshObservers.h b/layout/base/nsRefreshObservers.h index f1516cc4c1a0..707ddd1bcaaa 100644 --- a/layout/base/nsRefreshObservers.h +++ b/layout/base/nsRefreshObservers.h @@ -60,17 +60,6 @@ class nsARefreshObserver { #endif // DEBUG }; -/** - * An abstract base class to be implemented by callers wanting to be notified - * when the observing refresh driver updated mMostRecentRefresh due to active - * timer changes. Callers must ensure an observer is removed before it is - * destroyed. - */ -class nsATimerAdjustmentObserver { - public: - virtual void NotifyTimerAdjusted(mozilla::TimeStamp aTime) = 0; -}; - /** * An abstract base class to be implemented by callers wanting to be notified * that a refresh has occurred. Callers must ensure an observer is removed diff --git a/layout/printing/nsPrintJob.cpp b/layout/printing/nsPrintJob.cpp index 08bd54bc01cb..9ac5be9570a6 100644 --- a/layout/printing/nsPrintJob.cpp +++ b/layout/printing/nsPrintJob.cpp @@ -20,6 +20,7 @@ #include "mozilla/dom/ShadowRoot.h" #include "mozilla/dom/CustomEvent.h" #include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/DocumentTimeline.h" #include "mozilla/dom/HTMLCanvasElement.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/IntegerRange.h" @@ -1414,6 +1415,10 @@ nsresult nsPrintJob::ReflowPrintObject(const UniquePtr& aPO) { aPO->mPresContext->SetPageSize(pageSize); } } + // Make sure animations are active. + for (DocumentTimeline* tl : aPO->mDocument->Timelines()) { + tl->TriggerAllPendingAnimationsNow(); + } // Process the reflow event Initialize posted presShell->FlushPendingNotifications(FlushType::Layout); diff --git a/testing/web-platform/meta/dom/nodes/moveBefore/tentative/css-transition-cross-document.html.ini b/testing/web-platform/meta/dom/nodes/moveBefore/tentative/css-transition-cross-document.html.ini index 11bd069d369a..37f30e58da01 100644 --- a/testing/web-platform/meta/dom/nodes/moveBefore/tentative/css-transition-cross-document.html.ini +++ b/testing/web-platform/meta/dom/nodes/moveBefore/tentative/css-transition-cross-document.html.ini @@ -1,16 +1,4 @@ [css-transition-cross-document.html] - expected: - if (os == "linux") and debug and fission: [OK, TIMEOUT] - if (os == "linux") and debug and not fission: [OK, TIMEOUT] - if (os == "win") and not debug: TIMEOUT - if (os == "linux") and not debug: TIMEOUT - if os == "android": OK - [TIMEOUT, OK] + expected: [TIMEOUT, OK] [Moving a transition across documents should reset its state] - expected: - if (os == "linux") and debug and fission: [FAIL, TIMEOUT] - if (os == "linux") and debug and not fission: [FAIL, TIMEOUT] - if (os == "win") and not debug: TIMEOUT - if (os == "linux") and not debug: TIMEOUT - if os == "android": FAIL - [TIMEOUT, FAIL] + expected: [TIMEOUT, FAIL]