diff options
Diffstat (limited to 'layout/base/nsRefreshDriver.h')
-rw-r--r-- | layout/base/nsRefreshDriver.h | 735 |
1 files changed, 735 insertions, 0 deletions
diff --git a/layout/base/nsRefreshDriver.h b/layout/base/nsRefreshDriver.h new file mode 100644 index 0000000000..cd050f7431 --- /dev/null +++ b/layout/base/nsRefreshDriver.h @@ -0,0 +1,735 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Code to notify things that animate before a refresh, at an appropriate + * refresh rate. (Perhaps temporary, until replaced by compositor.) + */ + +#ifndef nsRefreshDriver_h_ +#define nsRefreshDriver_h_ + +#include "mozilla/FlushType.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/Vector.h" +#include "mozilla/WeakPtr.h" +#include "nsTObserverArray.h" +#include "nsTArray.h" +#include "nsTHashSet.h" +#include "nsClassHashtable.h" +#include "nsHashKeys.h" +#include "nsRefreshObservers.h" +#include "nsThreadUtils.h" +#include "mozilla/Attributes.h" +#include "mozilla/Maybe.h" +#include "mozilla/dom/VisualViewport.h" +#include "mozilla/layers/TransactionIdAllocator.h" +#include "LayersTypes.h" + +#include "GeckoProfiler.h" // for ProfileChunkedBuffer + +class nsPresContext; + +class imgIRequest; +class nsIRunnable; + +namespace mozilla { +class AnimationEventDispatcher; +class PendingFullscreenEvent; +class PresShell; +class RefreshDriverTimer; +class Runnable; +class Task; +} // namespace mozilla + +class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator, + public nsARefreshObserver { + using Document = mozilla::dom::Document; + using TransactionId = mozilla::layers::TransactionId; + using VVPResizeEvent = + mozilla::dom::VisualViewport::VisualViewportResizeEvent; + using VVPScrollEvent = + mozilla::dom::VisualViewport::VisualViewportScrollEvent; + using LogPresShellObserver = mozilla::LogPresShellObserver; + + public: + explicit nsRefreshDriver(nsPresContext* aPresContext); + ~nsRefreshDriver(); + + /** + * Methods for testing, exposed via nsIDOMWindowUtils. See + * nsIDOMWindowUtils.advanceTimeAndRefresh for description. + */ + void AdvanceTimeAndRefresh(int64_t aMilliseconds); + void RestoreNormalRefresh(); + void DoTick(); + bool IsTestControllingRefreshesEnabled() const { + return mTestControllingRefreshes; + } + + /** + * Return the time of the most recent refresh. This is intended to be + * used by callers who want to start an animation now and want to know + * what time to consider the start of the animation. (This helps + * ensure that multiple animations started during the same event off + * the main event loop have the same start time.) + */ + mozilla::TimeStamp MostRecentRefresh(bool aEnsureTimerStarted = true) const; + + /** + * Add / remove refresh observers. + * RemoveRefreshObserver returns true if aObserver was found. + * + * The flush type affects: + * + the order in which the observers are notified (lowest flush + * type to highest, in order registered) + * + (in the future) which observers are suppressed when the display + * doesn't require current position data or isn't currently + * painting, and, correspondingly, which get notified when there + * is a flush during such suppression + * and it must be FlushType::Style, FlushType::Layout, or FlushType::Display. + * + * The refresh driver does NOT own a reference to these observers; + * they must remove themselves before they are destroyed. + * + * The observer will be called even if there is no other activity. + */ + void AddRefreshObserver(nsARefreshObserver* aObserver, + mozilla::FlushType aFlushType, + 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(); + + void PostScrollEvent(mozilla::Runnable* aScrollEvent, bool aDelayed = false); + void DispatchScrollEvents(); + + void PostVisualViewportScrollEvent(VVPScrollEvent* aScrollEvent); + void DispatchVisualViewportScrollEvents(); + + /** + * Add an observer that will be called after each refresh. The caller + * must remove the observer before it is deleted. This does not trigger + * refresh driver ticks. + */ + void AddPostRefreshObserver(nsAPostRefreshObserver* aObserver); + void AddPostRefreshObserver(mozilla::ManagedPostRefreshObserver*) = delete; + void RemovePostRefreshObserver(nsAPostRefreshObserver* aObserver); + void RemovePostRefreshObserver(mozilla::ManagedPostRefreshObserver*) = delete; + + /** + * Add/Remove imgIRequest versions of observers. + * + * These are used for hooking into the refresh driver for + * controlling animated images. + * + * @note The refresh driver owns a reference to these listeners. + * + * @note Technically, imgIRequest objects are not nsARefreshObservers, but + * for controlling animated image repaint events, we subscribe the + * imgIRequests to the nsRefreshDriver for notification of paint events. + */ + void AddImageRequest(imgIRequest* aRequest); + void RemoveImageRequest(imgIRequest* aRequest); + + /** + * Marks that we're currently in the middle of processing user input. + * Called by EventDispatcher when it's handling an input event. + */ + void EnterUserInputProcessing() { mUserInputProcessingCount++; } + void ExitUserInputProcessing() { + MOZ_ASSERT(mUserInputProcessingCount > 0); + mUserInputProcessingCount--; + } + + /** + * Add / remove presshells which have pending resize event. + */ + void AddResizeEventFlushObserver(mozilla::PresShell* aPresShell, + bool aDelayed = false) { + MOZ_DIAGNOSTIC_ASSERT( + !mResizeEventFlushObservers.Contains(aPresShell) && + !mDelayedResizeEventFlushObservers.Contains(aPresShell), + "Double-adding resize event flush observer"); + if (aDelayed) { + mDelayedResizeEventFlushObservers.AppendElement(aPresShell); + } else { + mResizeEventFlushObservers.AppendElement(aPresShell); + EnsureTimerStarted(); + } + } + + void RemoveResizeEventFlushObserver(mozilla::PresShell* aPresShell) { + mResizeEventFlushObservers.RemoveElement(aPresShell); + mDelayedResizeEventFlushObservers.RemoveElement(aPresShell); + } + + /** + * Add / remove presshells that we should flush style and layout on + */ + void AddStyleFlushObserver(mozilla::PresShell* aPresShell) { + MOZ_DIAGNOSTIC_ASSERT(!mStyleFlushObservers.Contains(aPresShell), + "Double-adding style flush observer"); + LogPresShellObserver::LogDispatch(aPresShell, this); + mStyleFlushObservers.AppendElement(aPresShell); + EnsureTimerStarted(); + } + + void RemoveStyleFlushObserver(mozilla::PresShell* aPresShell) { + mStyleFlushObservers.RemoveElement(aPresShell); + } + void AddLayoutFlushObserver(mozilla::PresShell* aPresShell) { + MOZ_DIAGNOSTIC_ASSERT(!IsLayoutFlushObserver(aPresShell), + "Double-adding layout flush observer"); + LogPresShellObserver::LogDispatch(aPresShell, this); + mLayoutFlushObservers.AppendElement(aPresShell); + EnsureTimerStarted(); + } + void RemoveLayoutFlushObserver(mozilla::PresShell* aPresShell) { + mLayoutFlushObservers.RemoveElement(aPresShell); + } + + bool IsLayoutFlushObserver(mozilla::PresShell* aPresShell) { + return mLayoutFlushObservers.Contains(aPresShell); + } + + /** + * "Early Runner" runnables will be called as the first step when refresh + * driver tick is triggered. Runners shouldn't keep other objects alive, + * since it isn't guaranteed they will ever get called. + */ + void AddEarlyRunner(nsIRunnable* aRunnable) { + mEarlyRunners.AppendElement(aRunnable); + EnsureTimerStarted(); + } + + /** + * Remember whether our presshell's view manager needs a flush + */ + void ScheduleViewManagerFlush(); + void RevokeViewManagerFlush() { mViewManagerFlushIsPending = false; } + bool ViewManagerFlushIsPending() { return mViewManagerFlushIsPending; } + bool HasScheduleFlush() { return mHasScheduleFlush; } + void ClearHasScheduleFlush() { mHasScheduleFlush = false; } + + /** + * Add a document for which we have FrameRequestCallbacks + */ + void ScheduleFrameRequestCallbacks(Document* aDocument); + + /** + * Remove a document for which we have FrameRequestCallbacks + */ + void RevokeFrameRequestCallbacks(Document* aDocument); + + /** + * Queue a new fullscreen event to be dispatched in next tick before + * the style flush + */ + void ScheduleFullscreenEvent( + mozilla::UniquePtr<mozilla::PendingFullscreenEvent> aEvent); + + /** + * Cancel all pending fullscreen events scheduled by ScheduleFullscreenEvent + * which targets any node in aDocument. + */ + void CancelPendingFullscreenEvents(Document* aDocument); + + /** + * Queue new animation events to dispatch in next tick. + */ + void ScheduleAnimationEventDispatch( + mozilla::AnimationEventDispatcher* aDispatcher) { + NS_ASSERTION(!mAnimationEventFlushObservers.Contains(aDispatcher), + "Double-adding animation event flush observer"); + mAnimationEventFlushObservers.AppendElement(aDispatcher); + EnsureTimerStarted(); + } + + /** + * Cancel all pending animation events associated with |aDispatcher|. + */ + void CancelPendingAnimationEvents( + mozilla::AnimationEventDispatcher* aDispatcher); + + /** + * Schedule a frame visibility update "soon", subject to the heuristics and + * throttling we apply to visibility updates. + */ + void ScheduleFrameVisibilityUpdate() { mNeedToRecomputeVisibility = true; } + + /** + * Tell the refresh driver that it is done driving refreshes and + * should stop its timer and forget about its pres context. This may + * be called from within a refresh. + */ + void Disconnect(); + + bool IsFrozen() const { return mFreezeCount > 0; } + + bool IsThrottled() const { return mThrottled; } + + /** + * Freeze the refresh driver. It should stop delivering future + * refreshes until thawed. Note that the number of calls to Freeze() must + * match the number of calls to Thaw() in order for the refresh driver to + * be un-frozen. + */ + void Freeze(); + + /** + * Thaw the refresh driver. If the number of calls to Freeze() matches the + * number of calls to this function, the refresh driver should start + * delivering refreshes again. + */ + void Thaw(); + + /** + * Throttle or unthrottle the refresh driver. This is done if the + * corresponding presshell is hidden or shown. + */ + void SetActivity(bool aIsActive); + + /** + * Return the prescontext we were initialized with + */ + nsPresContext* GetPresContext() const; + + void CreateVsyncRefreshTimer(); + +#ifdef DEBUG + /** + * Check whether the given observer is an observer for the given flush type + */ + bool IsRefreshObserver(nsARefreshObserver* aObserver, + mozilla::FlushType aFlushType); +#endif + + /** + * Default interval the refresh driver uses, in ms. + */ + static int32_t DefaultInterval(); + + /** + * Returns 1.0 if a recent rate wasn't smaller than + * DefaultInterval(). Otherwise return rate / DefaultInterval(); + * So the return value is (0-1]. + * + */ + static double HighRateMultiplier(); + + bool IsInRefresh() { return mInRefresh; } + + void SetIsResizeSuppressed() { mResizeSuppressed = true; } + bool IsResizeSuppressed() const { return mResizeSuppressed; } + + // mozilla::layers::TransactionIdAllocator + TransactionId GetTransactionId(bool aThrottle) override; + TransactionId LastTransactionId() const override; + void NotifyTransactionCompleted(TransactionId aTransactionId) override; + void RevokeTransactionId(TransactionId aTransactionId) override; + void ClearPendingTransactions() override; + void ResetInitialTransactionId(TransactionId aTransactionId) override; + mozilla::TimeStamp GetTransactionStart() override; + mozilla::VsyncId GetVsyncId() override; + mozilla::TimeStamp GetVsyncStart() override; + + bool IsWaitingForPaint(mozilla::TimeStamp aTime); + + void ScheduleAutoFocusFlush(Document* aDocument); + + // nsARefreshObserver + NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override { + return TransactionIdAllocator::AddRef(); + } + NS_IMETHOD_(MozExternalRefCountType) Release(void) override { + return TransactionIdAllocator::Release(); + } + virtual void WillRefresh(mozilla::TimeStamp aTime) override; + + /** + * Compute the time when the currently active refresh driver timer + * will start its next tick. + * + * Expects a non-null default value that is the upper bound of the + * expected deadline. If the next expected deadline is later than + * the default value, the default value is returned. + * + * If we're animating and we have skipped paints a time in the past + * is returned. + * + * If aCheckType is AllVsyncListeners and we're in the parent process, + * which doesn't have a RefreshDriver ticking, but some other process does + * have, the return value is + * (now + refreshrate - layout.idle_period.time_limit) as an approximation + * when something will happen. + * This can be useful check when parent process tries to avoid having too + * long idle periods for example when it is sending input events to an + * active child process. + */ + enum IdleCheck { OnlyThisProcessRefreshDriver, AllVsyncListeners }; + static mozilla::TimeStamp GetIdleDeadlineHint(mozilla::TimeStamp aDefault, + IdleCheck aCheckType); + + /** + * It returns the expected timestamp of the next tick or nothing if the next + * tick is missed. + */ + static mozilla::Maybe<mozilla::TimeStamp> GetNextTickHint(); + + static bool IsRegularRateTimerTicking(); + + static void DispatchIdleTaskAfterTickUnlessExists(mozilla::Task* aTask); + static void CancelIdleTask(mozilla::Task* aTask); + + void NotifyDOMContentLoaded(); + + // Schedule a refresh so that any delayed events will run soon. + void RunDelayedEventsSoon(); + + void InitializeTimer() { + MOZ_ASSERT(!mActiveTimer); + EnsureTimerStarted(); + } + + bool HasPendingTick() const { return mActiveTimer; } + + void EnsureIntersectionObservationsUpdateHappens() { + // This is enough to make sure that UpdateIntersectionObservations runs at + // least once. This is presumably the intent of step 5 in [1]: + // + // Schedule an iteration of the event loop in the root's browsing + // context. + // + // Though the wording of it is not quite clear to me... + // + // [1]: + // https://w3c.github.io/IntersectionObserver/#dom-intersectionobserver-observe + EnsureTimerStarted(); + mNeedToUpdateIntersectionObservations = true; + } + + void EnsureResizeObserverUpdateHappens() { + EnsureTimerStarted(); + mNeedToUpdateResizeObservers = true; + } + + void ScheduleMediaQueryListenerUpdate() { + EnsureTimerStarted(); + mMightNeedMediaQueryListenerUpdate = true; + } + + void EnsureContentRelevancyUpdateHappens() { + EnsureTimerStarted(); + mNeedToUpdateContentRelevancy = true; + } + + // Register a composition payload that will be forwarded to the layer manager + // if the current or upcoming refresh tick does a paint. + // If no paint happens, the payload is discarded. + // Should only be called on root refresh drivers. + void RegisterCompositionPayload( + const mozilla::layers::CompositionPayload& aPayload); + + enum class TickReasons : uint32_t { + eNone = 0, + eHasObservers = 1 << 0, + eHasImageRequests = 1 << 1, + eNeedsToUpdateIntersectionObservations = 1 << 2, + eNeedsToUpdateContentRelevancy = 1 << 3, + eHasVisualViewportResizeEvents = 1 << 4, + eHasScrollEvents = 1 << 5, + eHasVisualViewportScrollEvents = 1 << 6, + eHasPendingMediaQueryListeners = 1 << 7, + eNeedsToNotifyResizeObservers = 1 << 8, + eRootNeedsMoreTicksForUserInput = 1 << 9, + }; + + void AddForceNotifyContentfulPaintPresContext(nsPresContext* aPresContext); + void FlushForceNotifyContentfulPaintPresContext(); + + // Mark that we've just run a tick from vsync, used to throttle 'extra' + // paints to one per vsync (see CanDoExtraTick). + void FinishedVsyncTick() { mAttemptedExtraTickSinceLastVsync = false; } + + void CancelFlushAutoFocus(Document* aDocument); + + private: + typedef nsTArray<RefPtr<VVPResizeEvent>> VisualViewportResizeEventArray; + typedef nsTArray<RefPtr<mozilla::Runnable>> ScrollEventArray; + typedef nsTArray<RefPtr<VVPScrollEvent>> VisualViewportScrollEventArray; + using RequestTable = nsTHashSet<RefPtr<imgIRequest>>; + struct ImageStartData { + ImageStartData() = default; + + mozilla::Maybe<mozilla::TimeStamp> mStartTime; + RequestTable mEntries; + }; + typedef nsClassHashtable<nsUint32HashKey, ImageStartData> ImageStartTable; + + struct ObserverData { + nsARefreshObserver* mObserver; + const char* mDescription; + mozilla::TimeStamp mRegisterTime; + mozilla::MarkerInnerWindowId mInnerWindowId; + mozilla::UniquePtr<mozilla::ProfileChunkedBuffer> mCause; + mozilla::FlushType mFlushType; + + bool operator==(nsARefreshObserver* aObserver) const { + return mObserver == aObserver; + } + operator RefPtr<nsARefreshObserver>() { return mObserver; } + }; + using ObserverArray = nsTObserverArray<ObserverData>; + MOZ_CAN_RUN_SCRIPT + void FlushAutoFocusDocuments(); + void RunFullscreenSteps(); + void DispatchAnimationEvents(); + MOZ_CAN_RUN_SCRIPT + void RunFrameRequestCallbacks(mozilla::TimeStamp aNowTime); + void UpdateIntersectionObservations(mozilla::TimeStamp aNowTime); + void UpdateRelevancyOfContentVisibilityAutoFrames(); + MOZ_CAN_RUN_SCRIPT void + DetermineProximityToViewportAndNotifyResizeObservers(); + void MaybeIncreaseMeasuredTicksSinceLoading(); + void EvaluateMediaQueriesAndReportChanges(); + + enum class IsExtraTick { + No, + Yes, + }; + + // Helper for Tick, to call WillRefresh(aNowTime) on each entry in + // mObservers[aIdx] and then potentially do some additional post-notification + // work that's associated with the FlushType corresponding to aIdx. + // + // Returns true on success, or false if one of our calls has destroyed our + // pres context (in which case our callsite Tick() should immediately bail). + MOZ_CAN_RUN_SCRIPT + bool TickObserverArray(uint32_t aIdx, mozilla::TimeStamp aNowTime); + + MOZ_CAN_RUN_SCRIPT_BOUNDARY + void Tick(mozilla::VsyncId aId, mozilla::TimeStamp aNowTime, + IsExtraTick aIsExtraTick = IsExtraTick::No); + + enum EnsureTimerStartedFlags { + eNone = 0, + eForceAdjustTimer = 1 << 0, + eAllowTimeToGoBackwards = 1 << 1, + eNeverAdjustTimer = 1 << 2, + }; + void EnsureTimerStarted(EnsureTimerStartedFlags aFlags = eNone); + void StopTimer(); + + void UpdateThrottledState(); + + bool HasObservers() const; + void AppendObserverDescriptionsToString(nsACString& aStr) const; + // Note: This should only be called in the dtor of nsRefreshDriver. + uint32_t ObserverCount() const; + bool HasImageRequests() const; + bool ShouldKeepTimerRunningWhileWaitingForFirstContentfulPaint(); + bool ShouldKeepTimerRunningAfterPageLoad(); + ObserverArray& ArrayFor(mozilla::FlushType aFlushType); + // Trigger a refresh immediately, if haven't been disconnected or frozen. + void DoRefresh(); + + // Starts pending image animations, and refreshes ongoing animations. + void UpdateAnimatedImages(mozilla::TimeStamp aPreviousRefresh, + mozilla::TimeStamp aNowTime); + + TickReasons GetReasonsToTick() const; + void AppendTickReasonsToString(TickReasons aReasons, nsACString& aStr) const; + + double GetRegularTimerInterval() const; + static double GetThrottledTimerInterval(); + + static mozilla::TimeDuration GetMinRecomputeVisibilityInterval(); + + bool HaveFrameRequestCallbacks() const { + return mFrameRequestCallbackDocs.Length() != 0; + } + + void FinishedWaitingForTransaction(); + + /** + * Returns true if we didn't tick on the most recent vsync, but we think + * we could run one now instead in order to reduce latency. + */ + bool CanDoCatchUpTick(); + /** + * Returns true if we think it's possible to run an repeat tick (between + * vsyncs) to hopefully replace the original tick's paint on the compositor. + * We allow this sometimes for tick requests coming for user input handling + * to reduce latency. + */ + bool CanDoExtraTick(); + + bool AtPendingTransactionLimit() { + return mPendingTransactions.Length() == 2; + } + bool TooManyPendingTransactions() { + return mPendingTransactions.Length() >= 2; + } + + mozilla::RefreshDriverTimer* ChooseTimer(); + mozilla::RefreshDriverTimer* mActiveTimer; + RefPtr<mozilla::RefreshDriverTimer> mOwnTimer; + mozilla::UniquePtr<mozilla::ProfileChunkedBuffer> mRefreshTimerStartedCause; + + // nsPresContext passed in constructor and unset in Disconnect. + mozilla::WeakPtr<nsPresContext> mPresContext; + + RefPtr<nsRefreshDriver> mRootRefresh; + + // The most recently allocated transaction id. + TransactionId mNextTransactionId; + AutoTArray<TransactionId, 3> mPendingTransactions; + + uint32_t mFreezeCount; + uint32_t mUserInputProcessingCount = 0; + + // How long we wait between ticks for throttled (which generally means + // non-visible) documents registered with a non-throttled refresh driver. + const mozilla::TimeDuration mThrottledFrameRequestInterval; + + // How long we wait, at a minimum, before recomputing approximate frame + // visibility information. This is a minimum because, regardless of this + // interval, we only recompute visibility when we've seen a layout or style + // flush since the last time we did it. + const mozilla::TimeDuration mMinRecomputeVisibilityInterval; + + mozilla::UniquePtr<mozilla::ProfileChunkedBuffer> mViewManagerFlushCause; + + bool mThrottled : 1; + bool mNeedToRecomputeVisibility : 1; + bool mTestControllingRefreshes : 1; + + // These two fields are almost the same, the only difference is that + // mViewManagerFlushIsPending gets cleared right before calling + // ProcessPendingUpdates, and mHasScheduleFlush gets cleared right after + // calling ProcessPendingUpdates. It is important that mHasScheduleFlush + // only gets cleared after, but it's not clear if mViewManagerFlushIsPending + // needs to be cleared before. + bool mViewManagerFlushIsPending : 1; + bool mHasScheduleFlush : 1; + + bool mInRefresh : 1; + + // True if the refresh driver is suspended waiting for transaction + // id's to be returned and shouldn't do any work during Tick(). + bool mWaitingForTransaction : 1; + // True if Tick() was skipped because of mWaitingForTransaction and + // we should schedule a new Tick immediately when resumed instead + // of waiting until the next interval. + bool mSkippedPaints : 1; + + // True if view managers should delay any resize request until the + // next tick by the refresh driver. This flag will be reset at the + // start of every tick. + bool mResizeSuppressed : 1; + + // True if the next tick should notify DOMContentFlushed. + bool mNotifyDOMContentFlushed : 1; + + // True if we need to flush in order to update intersection observations in + // all our documents. + bool mNeedToUpdateIntersectionObservations : 1; + + // True if we need to flush in order to update intersection observations in + // all our documents. + bool mNeedToUpdateResizeObservers : 1; + + // True if we might need to report media query changes in any of our + // documents. + bool mMightNeedMediaQueryListenerUpdate : 1; + + // True if we need to update the relevancy of `content-visibility: auto` + // elements in our documents. + bool mNeedToUpdateContentRelevancy : 1; + + // True if we're currently within the scope of Tick() handling a normal + // (timer-driven) tick. + bool mInNormalTick : 1; + + // True if we attempted an extra tick (see CanDoExtraTick) since the last + // vsync and thus shouldn't allow another. + bool mAttemptedExtraTickSinceLastVsync : 1; + + bool mHasExceededAfterLoadTickPeriod : 1; + + bool mHasStartedTimerAtLeastOnce : 1; + + mozilla::TimeStamp mMostRecentRefresh; + mozilla::TimeStamp mTickStart; + mozilla::VsyncId mTickVsyncId; + mozilla::TimeStamp mTickVsyncTime; + mozilla::TimeStamp mNextThrottledFrameRequestTick; + mozilla::TimeStamp mNextRecomputeVisibilityTick; + mozilla::TimeStamp mBeforeFirstContentfulPaintTimerRunningLimit; + + // separate arrays for each flush type we support + ObserverArray mObservers[4]; + // 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<nsATimerAdjustmentObserver*> mTimerAdjustmentObservers; + nsTArray<mozilla::layers::CompositionPayload> mCompositionPayloads; + RequestTable mRequests; + ImageStartTable mStartTable; + AutoTArray<nsCOMPtr<nsIRunnable>, 16> mEarlyRunners; + VisualViewportResizeEventArray mVisualViewportResizeEvents; + ScrollEventArray mScrollEvents; + VisualViewportScrollEventArray mVisualViewportScrollEvents; + + // Scroll events on documents that might have events suppressed. + ScrollEventArray mDelayedScrollEvents; + + AutoTArray<mozilla::PresShell*, 16> mResizeEventFlushObservers; + AutoTArray<mozilla::PresShell*, 16> mDelayedResizeEventFlushObservers; + AutoTArray<mozilla::PresShell*, 16> mStyleFlushObservers; + AutoTArray<mozilla::PresShell*, 16> mLayoutFlushObservers; + // nsTArray on purpose, because we want to be able to swap. + nsTArray<Document*> mFrameRequestCallbackDocs; + nsTArray<Document*> mThrottledFrameRequestCallbackDocs; + nsTArray<RefPtr<Document>> mAutoFocusFlushDocuments; + nsTObserverArray<nsAPostRefreshObserver*> mPostRefreshObservers; + nsTArray<mozilla::UniquePtr<mozilla::PendingFullscreenEvent>> + mPendingFullscreenEvents; + AutoTArray<mozilla::AnimationEventDispatcher*, 16> + mAnimationEventFlushObservers; + + // nsPresContexts which `NotifyContentfulPaint` have been called, + // however the corresponding paint doesn't come from a regular + // rendering steps(aka tick). + // + // For these nsPresContexts, we invoke + // `FlushForceNotifyContentfulPaintPresContext` in the next tick + // to force notify contentful paint, regardless whether the tick paints + // or not. + nsTArray<mozilla::WeakPtr<nsPresContext>> + mForceNotifyContentfulPaintPresContexts; + + void BeginRefreshingImages(RequestTable& aEntries, + mozilla::TimeStamp aDesired); + + friend class mozilla::RefreshDriverTimer; + + static void Shutdown(); +}; + +#endif /* !defined(nsRefreshDriver_h_) */ |