summaryrefslogtreecommitdiffstats
path: root/layout/base/nsRefreshDriver.h
diff options
context:
space:
mode:
Diffstat (limited to 'layout/base/nsRefreshDriver.h')
-rw-r--r--layout/base/nsRefreshDriver.h720
1 files changed, 720 insertions, 0 deletions
diff --git a/layout/base/nsRefreshDriver.h b/layout/base/nsRefreshDriver.h
new file mode 100644
index 0000000000..3733abe162
--- /dev/null
+++ b/layout/base/nsRefreshDriver.h
@@ -0,0 +1,720 @@
+/* -*- 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, bool aIsInActiveTab);
+
+ /**
+ * 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 true if a recent vsync interval has been less than a half of
+ * DefaultInterval.
+ */
+ static bool IsInHighRateMode();
+
+ 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 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,
+ 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; }
+ };
+ typedef nsTObserverArray<ObserverData> ObserverArray;
+ 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();
+ void MaybeIncreaseMeasuredTicksSinceLoading();
+
+ 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();
+
+ bool ComputeShouldBeThrottled() const;
+ bool ShouldStopActivityGracePeriod() const;
+ 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 mIsActive : 1;
+ bool mIsInActiveTab : 1;
+ // We grant a period of activity to out-of-process iframes that are in the
+ // foreground tab but inactive (hidden), in case they can set themselves up
+ // and get shown soon enough (see bug 1745869).
+ bool mIsGrantingActivityGracePeriod : 1;
+ bool mHasGrantedActivityGracePeriod : 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 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;
+ mozilla::TimeStamp mActivityGracePeriodStart;
+
+ // 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_) */