/* -*- 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.)
*/
#include"GeckoProfiler.h"// for ProfileChunkedBuffer
class nsPresContext;
class imgIRequest; class nsIRunnable;
struct DocumentFrameCallbacks;
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;
/** * 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, 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, constchar* aObserverDescription); bool RemoveRefreshObserver(nsARefreshObserver* aObserver,
mozilla::FlushType aFlushType);
/** * 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--;
}
/** * "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();
}
/** * 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();
/** * 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]. *
*/ staticdouble HighRateMultiplier();
/** * 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();
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;
}
// 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);
// 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; }
// 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);
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();
/** * 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();
// 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;
// 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 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 resize observations in all // our documents. bool mNeedToUpdateResizeObservers : 1;
// True if we may need to perform pending view transition operations. bool mNeedToUpdateViewTransitions : 1;
// True if we may need to run any frame callback. bool mNeedToRunFrameRequestCallbacks : 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;
// 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;
// separate arrays for each flush type we support
ObserverArray mObservers[3];
nsTArray<mozilla::layers::CompositionPayload> mCompositionPayloads;
RequestTable mRequests;
ImageStartTable mStartTable;
AutoTArray<nsCOMPtr<nsIRunnable>, 16> mEarlyRunners;
VisualViewportResizeEventArray mVisualViewportResizeEvents;
ScrollEventArray mScrollEvents;
ScrollEventArray mScrollEndEvents;
VisualViewportScrollEventArray mVisualViewportScrollEvents;
// Scroll events on documents that might have events suppressed.
ScrollEventArray mDelayedScrollEvents;
ScrollEventArray mDelayedScrollEndEvents;
// 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;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.