Bug 1104435 part 2 - Make AnimationPlayer derive from nsISupports; r=smaug
[gecko.git] / layout / base / nsRefreshDriver.h
blob142fc1db20cb4c0f4f4853df96a05c483ec389db
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 * Code to notify things that animate before a refresh, at an appropriate
9 * refresh rate. (Perhaps temporary, until replaced by compositor.)
12 #ifndef nsRefreshDriver_h_
13 #define nsRefreshDriver_h_
15 #include "mozilla/TimeStamp.h"
16 #include "mozFlushType.h"
17 #include "nsTObserverArray.h"
18 #include "nsTArray.h"
19 #include "nsTHashtable.h"
20 #include "nsClassHashtable.h"
21 #include "nsHashKeys.h"
22 #include "mozilla/Attributes.h"
23 #include "mozilla/Maybe.h"
24 #include "GeckoProfiler.h"
25 #include "mozilla/layers/TransactionIdAllocator.h"
27 class nsPresContext;
28 class nsIPresShell;
29 class nsIDocument;
30 class imgIRequest;
31 class nsIRunnable;
33 namespace mozilla {
34 class RefreshDriverTimer;
37 /**
38 * An abstract base class to be implemented by callers wanting to be
39 * notified at refresh times. When nothing needs to be painted, callers
40 * may not be notified.
42 class nsARefreshObserver {
43 public:
44 // AddRef and Release signatures that match nsISupports. Implementors
45 // must implement reference counting, and those that do implement
46 // nsISupports will already have methods with the correct signature.
48 // The refresh driver does NOT hold references to refresh observers
49 // except while it is notifying them.
50 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
51 NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
53 virtual void WillRefresh(mozilla::TimeStamp aTime) = 0;
56 /**
57 * An abstract base class to be implemented by callers wanting to be notified
58 * that a refresh has occurred. Callers must ensure an observer is removed
59 * before it is destroyed.
61 class nsAPostRefreshObserver {
62 public:
63 virtual void DidRefresh() = 0;
66 class nsRefreshDriver MOZ_FINAL : public mozilla::layers::TransactionIdAllocator,
67 public nsARefreshObserver {
68 public:
69 explicit nsRefreshDriver(nsPresContext *aPresContext);
70 ~nsRefreshDriver();
72 static void InitializeStatics();
73 static void Shutdown();
75 /**
76 * Methods for testing, exposed via nsIDOMWindowUtils. See
77 * nsIDOMWindowUtils.advanceTimeAndRefresh for description.
79 void AdvanceTimeAndRefresh(int64_t aMilliseconds);
80 void RestoreNormalRefresh();
81 void DoTick();
82 bool IsTestControllingRefreshesEnabled() const
84 return mTestControllingRefreshes;
87 /**
88 * Return the time of the most recent refresh. This is intended to be
89 * used by callers who want to start an animation now and want to know
90 * what time to consider the start of the animation. (This helps
91 * ensure that multiple animations started during the same event off
92 * the main event loop have the same start time.)
94 mozilla::TimeStamp MostRecentRefresh() const;
95 /**
96 * Same thing, but in microseconds since the epoch.
98 int64_t MostRecentRefreshEpochTime() const;
101 * Add / remove refresh observers. Returns whether the operation
102 * succeeded.
104 * The flush type affects:
105 * + the order in which the observers are notified (lowest flush
106 * type to highest, in order registered)
107 * + (in the future) which observers are suppressed when the display
108 * doesn't require current position data or isn't currently
109 * painting, and, correspondingly, which get notified when there
110 * is a flush during such suppression
111 * and it must be either Flush_Style, Flush_Layout, or Flush_Display.
113 * The refresh driver does NOT own a reference to these observers;
114 * they must remove themselves before they are destroyed.
116 * The observer will be called even if there is no other activity.
118 bool AddRefreshObserver(nsARefreshObserver *aObserver,
119 mozFlushType aFlushType);
120 bool RemoveRefreshObserver(nsARefreshObserver *aObserver,
121 mozFlushType aFlushType);
124 * Add an observer that will be called after each refresh. The caller
125 * must remove the observer before it is deleted. This does not trigger
126 * refresh driver ticks.
128 void AddPostRefreshObserver(nsAPostRefreshObserver *aObserver);
129 void RemovePostRefreshObserver(nsAPostRefreshObserver *aObserver);
132 * Add/Remove imgIRequest versions of observers.
134 * These are used for hooking into the refresh driver for
135 * controlling animated images.
137 * @note The refresh driver owns a reference to these listeners.
139 * @note Technically, imgIRequest objects are not nsARefreshObservers, but
140 * for controlling animated image repaint events, we subscribe the
141 * imgIRequests to the nsRefreshDriver for notification of paint events.
143 * @returns whether the operation succeeded, or void in the case of removal.
145 bool AddImageRequest(imgIRequest* aRequest);
146 void RemoveImageRequest(imgIRequest* aRequest);
149 * Add / remove presshells that we should flush style and layout on
151 bool AddStyleFlushObserver(nsIPresShell* aShell) {
152 NS_ASSERTION(!mStyleFlushObservers.Contains(aShell),
153 "Double-adding style flush observer");
154 // We only get the cause for the first observer each frame because capturing
155 // a stack is expensive. This is still useful if (1) you're trying to remove
156 // all flushes for a particial frame or (2) the costly flush is triggered
157 // near the call site where the first observer is triggered.
158 if (!mStyleCause) {
159 mStyleCause = profiler_get_backtrace();
161 bool appended = mStyleFlushObservers.AppendElement(aShell) != nullptr;
162 EnsureTimerStarted(false);
164 return appended;
166 void RemoveStyleFlushObserver(nsIPresShell* aShell) {
167 mStyleFlushObservers.RemoveElement(aShell);
169 bool AddLayoutFlushObserver(nsIPresShell* aShell) {
170 NS_ASSERTION(!IsLayoutFlushObserver(aShell),
171 "Double-adding layout flush observer");
172 // We only get the cause for the first observer each frame because capturing
173 // a stack is expensive. This is still useful if (1) you're trying to remove
174 // all flushes for a particial frame or (2) the costly flush is triggered
175 // near the call site where the first observer is triggered.
176 if (!mReflowCause) {
177 mReflowCause = profiler_get_backtrace();
179 bool appended = mLayoutFlushObservers.AppendElement(aShell) != nullptr;
180 EnsureTimerStarted(false);
181 return appended;
183 void RemoveLayoutFlushObserver(nsIPresShell* aShell) {
184 mLayoutFlushObservers.RemoveElement(aShell);
186 bool IsLayoutFlushObserver(nsIPresShell* aShell) {
187 return mLayoutFlushObservers.Contains(aShell);
189 bool AddPresShellToInvalidateIfHidden(nsIPresShell* aShell) {
190 NS_ASSERTION(!mPresShellsToInvalidateIfHidden.Contains(aShell),
191 "Double-adding style flush observer");
192 bool appended = mPresShellsToInvalidateIfHidden.AppendElement(aShell) != nullptr;
193 EnsureTimerStarted(false);
194 return appended;
196 void RemovePresShellToInvalidateIfHidden(nsIPresShell* aShell) {
197 mPresShellsToInvalidateIfHidden.RemoveElement(aShell);
201 * Remember whether our presshell's view manager needs a flush
203 void ScheduleViewManagerFlush();
204 void RevokeViewManagerFlush() {
205 mViewManagerFlushIsPending = false;
207 bool ViewManagerFlushIsPending() {
208 return mViewManagerFlushIsPending;
212 * Add a document for which we have nsIFrameRequestCallbacks
214 void ScheduleFrameRequestCallbacks(nsIDocument* aDocument);
217 * Remove a document for which we have nsIFrameRequestCallbacks
219 void RevokeFrameRequestCallbacks(nsIDocument* aDocument);
222 * Tell the refresh driver that it is done driving refreshes and
223 * should stop its timer and forget about its pres context. This may
224 * be called from within a refresh.
226 void Disconnect() {
227 StopTimer();
228 mPresContext = nullptr;
231 bool IsFrozen() { return mFreezeCount > 0; }
234 * Freeze the refresh driver. It should stop delivering future
235 * refreshes until thawed. Note that the number of calls to Freeze() must
236 * match the number of calls to Thaw() in order for the refresh driver to
237 * be un-frozen.
239 void Freeze();
242 * Thaw the refresh driver. If the number of calls to Freeze() matches the
243 * number of calls to this function, the refresh driver should start
244 * delivering refreshes again.
246 void Thaw();
249 * Throttle or unthrottle the refresh driver. This is done if the
250 * corresponding presshell is hidden or shown.
252 void SetThrottled(bool aThrottled);
255 * Return the prescontext we were initialized with
257 nsPresContext* PresContext() const { return mPresContext; }
259 #ifdef DEBUG
261 * Check whether the given observer is an observer for the given flush type
263 bool IsRefreshObserver(nsARefreshObserver *aObserver,
264 mozFlushType aFlushType);
265 #endif
268 * Default interval the refresh driver uses, in ms.
270 static int32_t DefaultInterval();
272 bool IsInRefresh() { return mInRefresh; }
274 // mozilla::layers::TransactionIdAllocator
275 virtual uint64_t GetTransactionId() MOZ_OVERRIDE;
276 void NotifyTransactionCompleted(uint64_t aTransactionId) MOZ_OVERRIDE;
277 void RevokeTransactionId(uint64_t aTransactionId) MOZ_OVERRIDE;
278 mozilla::TimeStamp GetTransactionStart() MOZ_OVERRIDE;
280 bool IsWaitingForPaint(mozilla::TimeStamp aTime);
282 // nsARefreshObserver
283 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) { return TransactionIdAllocator::AddRef(); }
284 NS_IMETHOD_(MozExternalRefCountType) Release(void) { return TransactionIdAllocator::Release(); }
285 virtual void WillRefresh(mozilla::TimeStamp aTime);
286 private:
287 typedef nsTObserverArray<nsARefreshObserver*> ObserverArray;
288 typedef nsTHashtable<nsISupportsHashKey> RequestTable;
289 struct ImageStartData {
290 ImageStartData()
294 mozilla::Maybe<mozilla::TimeStamp> mStartTime;
295 RequestTable mEntries;
297 typedef nsClassHashtable<nsUint32HashKey, ImageStartData> ImageStartTable;
299 void Tick(int64_t aNowEpoch, mozilla::TimeStamp aNowTime);
301 void EnsureTimerStarted(bool aAdjustingTimer);
302 void StopTimer();
304 uint32_t ObserverCount() const;
305 uint32_t ImageRequestCount() const;
306 static PLDHashOperator ImageRequestEnumerator(nsISupportsHashKey* aEntry,
307 void* aUserArg);
308 static PLDHashOperator StartTableRequestCounter(const uint32_t& aKey,
309 ImageStartData* aEntry,
310 void* aUserArg);
311 static PLDHashOperator StartTableRefresh(const uint32_t& aKey,
312 ImageStartData* aEntry,
313 void* aUserArg);
314 static PLDHashOperator BeginRefreshingImages(nsISupportsHashKey* aEntry,
315 void* aUserArg);
316 ObserverArray& ArrayFor(mozFlushType aFlushType);
317 // Trigger a refresh immediately, if haven't been disconnected or frozen.
318 void DoRefresh();
320 double GetRefreshTimerInterval() const;
321 double GetRegularTimerInterval(bool *outIsDefault = nullptr) const;
322 double GetThrottledTimerInterval() const;
324 bool HaveFrameRequestCallbacks() const {
325 return mFrameRequestCallbackDocs.Length() != 0;
328 void FinishedWaitingForTransaction();
330 mozilla::RefreshDriverTimer* ChooseTimer() const;
331 mozilla::RefreshDriverTimer *mActiveTimer;
333 ProfilerBacktrace* mReflowCause;
334 ProfilerBacktrace* mStyleCause;
336 nsPresContext *mPresContext; // weak; pres context passed in constructor
337 // and unset in Disconnect
339 nsRefPtr<nsRefreshDriver> mRootRefresh;
341 // The most recently allocated transaction id.
342 uint64_t mPendingTransaction;
343 // The most recently completed transaction id.
344 uint64_t mCompletedTransaction;
346 uint32_t mFreezeCount;
347 bool mThrottled;
348 bool mTestControllingRefreshes;
349 bool mViewManagerFlushIsPending;
350 bool mRequestedHighPrecision;
351 bool mInRefresh;
353 // True if the refresh driver is suspended waiting for transaction
354 // id's to be returned and shouldn't do any work during Tick().
355 bool mWaitingForTransaction;
356 // True if Tick() was skipped because of mWaitingForTransaction and
357 // we should schedule a new Tick immediately when resumed instead
358 // of waiting until the next interval.
359 bool mSkippedPaints;
361 int64_t mMostRecentRefreshEpochTime;
362 mozilla::TimeStamp mMostRecentRefresh;
363 mozilla::TimeStamp mMostRecentTick;
364 mozilla::TimeStamp mTickStart;
366 // separate arrays for each flush type we support
367 ObserverArray mObservers[3];
368 RequestTable mRequests;
369 ImageStartTable mStartTable;
371 nsAutoTArray<nsIPresShell*, 16> mStyleFlushObservers;
372 nsAutoTArray<nsIPresShell*, 16> mLayoutFlushObservers;
373 nsAutoTArray<nsIPresShell*, 16> mPresShellsToInvalidateIfHidden;
374 // nsTArray on purpose, because we want to be able to swap.
375 nsTArray<nsIDocument*> mFrameRequestCallbackDocs;
376 nsTArray<nsAPostRefreshObserver*> mPostRefreshObservers;
378 // Helper struct for processing image requests
379 struct ImageRequestParameters {
380 mozilla::TimeStamp mCurrent;
381 mozilla::TimeStamp mPrevious;
382 RequestTable* mRequests;
383 mozilla::TimeStamp mDesired;
386 friend class mozilla::RefreshDriverTimer;
388 // turn on or turn off high precision based on various factors
389 void ConfigureHighPrecision();
390 void SetHighPrecisionTimersEnabled(bool aEnable);
393 #endif /* !defined(nsRefreshDriver_h_) */