layout/base/nsRefreshDriver.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:dc0411e56a06
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/. */
6
7 /*
8 * Code to notify things that animate before a refresh, at an appropriate
9 * refresh rate. (Perhaps temporary, until replaced by compositor.)
10 */
11
12 #ifndef nsRefreshDriver_h_
13 #define nsRefreshDriver_h_
14
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
25 class nsPresContext;
26 class nsIPresShell;
27 class nsIDocument;
28 class imgIRequest;
29 class nsIRunnable;
30
31 namespace mozilla {
32 class RefreshDriverTimer;
33 }
34
35 /**
36 * An abstract base class to be implemented by callers wanting to be
37 * notified at refresh times. When nothing needs to be painted, callers
38 * may not be notified.
39 */
40 class nsARefreshObserver {
41 public:
42 // AddRef and Release signatures that match nsISupports. Implementors
43 // must implement reference counting, and those that do implement
44 // nsISupports will already have methods with the correct signature.
45 //
46 // The refresh driver does NOT hold references to refresh observers
47 // except while it is notifying them.
48 NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
49 NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
50
51 virtual void WillRefresh(mozilla::TimeStamp aTime) = 0;
52 };
53
54 /**
55 * An abstract base class to be implemented by callers wanting to be notified
56 * that a refresh has occurred. Callers must ensure an observer is removed
57 * before it is destroyed.
58 */
59 class nsAPostRefreshObserver {
60 public:
61 virtual void DidRefresh() = 0;
62 };
63
64 class nsRefreshDriver MOZ_FINAL : public nsISupports {
65 public:
66 nsRefreshDriver(nsPresContext *aPresContext);
67 ~nsRefreshDriver();
68
69 static void InitializeStatics();
70 static void Shutdown();
71
72 // nsISupports implementation
73 NS_DECL_ISUPPORTS
74
75 /**
76 * Methods for testing, exposed via nsIDOMWindowUtils. See
77 * nsIDOMWindowUtils.advanceTimeAndRefresh for description.
78 */
79 void AdvanceTimeAndRefresh(int64_t aMilliseconds);
80 void RestoreNormalRefresh();
81 void DoTick();
82 bool IsTestControllingRefreshesEnabled() const
83 {
84 return mTestControllingRefreshes;
85 }
86
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.)
93 */
94 mozilla::TimeStamp MostRecentRefresh() const;
95 /**
96 * Same thing, but in microseconds since the epoch.
97 */
98 int64_t MostRecentRefreshEpochTime() const;
99
100 /**
101 * Add / remove refresh observers. Returns whether the operation
102 * succeeded.
103 *
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.
112 *
113 * The refresh driver does NOT own a reference to these observers;
114 * they must remove themselves before they are destroyed.
115 *
116 * The observer will be called even if there is no other activity.
117 */
118 bool AddRefreshObserver(nsARefreshObserver *aObserver,
119 mozFlushType aFlushType);
120 bool RemoveRefreshObserver(nsARefreshObserver *aObserver,
121 mozFlushType aFlushType);
122
123 /**
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.
127 */
128 void AddPostRefreshObserver(nsAPostRefreshObserver *aObserver);
129 void RemovePostRefreshObserver(nsAPostRefreshObserver *aObserver);
130
131 /**
132 * Add/Remove imgIRequest versions of observers.
133 *
134 * These are used for hooking into the refresh driver for
135 * controlling animated images.
136 *
137 * @note The refresh driver owns a reference to these listeners.
138 *
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.
142 *
143 * @returns whether the operation succeeded, or void in the case of removal.
144 */
145 bool AddImageRequest(imgIRequest* aRequest);
146 void RemoveImageRequest(imgIRequest* aRequest);
147
148 /**
149 * Add / remove presshells that we should flush style and layout on
150 */
151 bool AddStyleFlushObserver(nsIPresShell* aShell) {
152 NS_ASSERTION(!mStyleFlushObservers.Contains(aShell),
153 "Double-adding style flush observer");
154 bool appended = mStyleFlushObservers.AppendElement(aShell) != nullptr;
155 EnsureTimerStarted(false);
156 return appended;
157 }
158 void RemoveStyleFlushObserver(nsIPresShell* aShell) {
159 mStyleFlushObservers.RemoveElement(aShell);
160 }
161 bool AddLayoutFlushObserver(nsIPresShell* aShell) {
162 NS_ASSERTION(!IsLayoutFlushObserver(aShell),
163 "Double-adding layout flush observer");
164 bool appended = mLayoutFlushObservers.AppendElement(aShell) != nullptr;
165 EnsureTimerStarted(false);
166 return appended;
167 }
168 void RemoveLayoutFlushObserver(nsIPresShell* aShell) {
169 mLayoutFlushObservers.RemoveElement(aShell);
170 }
171 bool IsLayoutFlushObserver(nsIPresShell* aShell) {
172 return mLayoutFlushObservers.Contains(aShell);
173 }
174 bool AddPresShellToInvalidateIfHidden(nsIPresShell* aShell) {
175 NS_ASSERTION(!mPresShellsToInvalidateIfHidden.Contains(aShell),
176 "Double-adding style flush observer");
177 bool appended = mPresShellsToInvalidateIfHidden.AppendElement(aShell) != nullptr;
178 EnsureTimerStarted(false);
179 return appended;
180 }
181 void RemovePresShellToInvalidateIfHidden(nsIPresShell* aShell) {
182 mPresShellsToInvalidateIfHidden.RemoveElement(aShell);
183 }
184
185 /**
186 * Remember whether our presshell's view manager needs a flush
187 */
188 void ScheduleViewManagerFlush();
189 void RevokeViewManagerFlush() {
190 mViewManagerFlushIsPending = false;
191 }
192 bool ViewManagerFlushIsPending() {
193 return mViewManagerFlushIsPending;
194 }
195
196 /**
197 * Add a document for which we have nsIFrameRequestCallbacks
198 */
199 void ScheduleFrameRequestCallbacks(nsIDocument* aDocument);
200
201 /**
202 * Remove a document for which we have nsIFrameRequestCallbacks
203 */
204 void RevokeFrameRequestCallbacks(nsIDocument* aDocument);
205
206 /**
207 * Tell the refresh driver that it is done driving refreshes and
208 * should stop its timer and forget about its pres context. This may
209 * be called from within a refresh.
210 */
211 void Disconnect() {
212 StopTimer();
213 mPresContext = nullptr;
214 }
215
216 bool IsFrozen() { return mFreezeCount > 0; }
217
218 /**
219 * Freeze the refresh driver. It should stop delivering future
220 * refreshes until thawed. Note that the number of calls to Freeze() must
221 * match the number of calls to Thaw() in order for the refresh driver to
222 * be un-frozen.
223 */
224 void Freeze();
225
226 /**
227 * Thaw the refresh driver. If the number of calls to Freeze() matches the
228 * number of calls to this function, the refresh driver should start
229 * delivering refreshes again.
230 */
231 void Thaw();
232
233 /**
234 * Throttle or unthrottle the refresh driver. This is done if the
235 * corresponding presshell is hidden or shown.
236 */
237 void SetThrottled(bool aThrottled);
238
239 /**
240 * Return the prescontext we were initialized with
241 */
242 nsPresContext* PresContext() const { return mPresContext; }
243
244 #ifdef DEBUG
245 /**
246 * Check whether the given observer is an observer for the given flush type
247 */
248 bool IsRefreshObserver(nsARefreshObserver *aObserver,
249 mozFlushType aFlushType);
250 #endif
251
252 /**
253 * Default interval the refresh driver uses, in ms.
254 */
255 static int32_t DefaultInterval();
256
257 bool IsInRefresh() { return mInRefresh; }
258
259 private:
260 typedef nsTObserverArray<nsARefreshObserver*> ObserverArray;
261 typedef nsTHashtable<nsISupportsHashKey> RequestTable;
262 struct ImageStartData {
263 ImageStartData()
264 {
265 }
266
267 mozilla::Maybe<mozilla::TimeStamp> mStartTime;
268 RequestTable mEntries;
269 };
270 typedef nsClassHashtable<nsUint32HashKey, ImageStartData> ImageStartTable;
271
272 void Tick(int64_t aNowEpoch, mozilla::TimeStamp aNowTime);
273
274 void EnsureTimerStarted(bool aAdjustingTimer);
275 void StopTimer();
276
277 uint32_t ObserverCount() const;
278 uint32_t ImageRequestCount() const;
279 static PLDHashOperator ImageRequestEnumerator(nsISupportsHashKey* aEntry,
280 void* aUserArg);
281 static PLDHashOperator StartTableRequestCounter(const uint32_t& aKey,
282 ImageStartData* aEntry,
283 void* aUserArg);
284 static PLDHashOperator StartTableRefresh(const uint32_t& aKey,
285 ImageStartData* aEntry,
286 void* aUserArg);
287 static PLDHashOperator BeginRefreshingImages(nsISupportsHashKey* aEntry,
288 void* aUserArg);
289 ObserverArray& ArrayFor(mozFlushType aFlushType);
290 // Trigger a refresh immediately, if haven't been disconnected or frozen.
291 void DoRefresh();
292
293 double GetRefreshTimerInterval() const;
294 double GetRegularTimerInterval(bool *outIsDefault = nullptr) const;
295 double GetThrottledTimerInterval() const;
296
297 bool HaveFrameRequestCallbacks() const {
298 return mFrameRequestCallbackDocs.Length() != 0;
299 }
300
301 mozilla::RefreshDriverTimer* ChooseTimer() const;
302 mozilla::RefreshDriverTimer *mActiveTimer;
303
304 nsPresContext *mPresContext; // weak; pres context passed in constructor
305 // and unset in Disconnect
306
307 uint32_t mFreezeCount;
308 bool mThrottled;
309 bool mTestControllingRefreshes;
310 bool mViewManagerFlushIsPending;
311 bool mRequestedHighPrecision;
312 bool mInRefresh;
313
314 int64_t mMostRecentRefreshEpochTime;
315 mozilla::TimeStamp mMostRecentRefresh;
316
317 // separate arrays for each flush type we support
318 ObserverArray mObservers[3];
319 RequestTable mRequests;
320 ImageStartTable mStartTable;
321
322 nsAutoTArray<nsIPresShell*, 16> mStyleFlushObservers;
323 nsAutoTArray<nsIPresShell*, 16> mLayoutFlushObservers;
324 nsAutoTArray<nsIPresShell*, 16> mPresShellsToInvalidateIfHidden;
325 // nsTArray on purpose, because we want to be able to swap.
326 nsTArray<nsIDocument*> mFrameRequestCallbackDocs;
327 nsTArray<nsAPostRefreshObserver*> mPostRefreshObservers;
328
329 // Helper struct for processing image requests
330 struct ImageRequestParameters {
331 mozilla::TimeStamp mCurrent;
332 mozilla::TimeStamp mPrevious;
333 RequestTable* mRequests;
334 mozilla::TimeStamp mDesired;
335 };
336
337 friend class mozilla::RefreshDriverTimer;
338
339 // turn on or turn off high precision based on various factors
340 void ConfigureHighPrecision();
341 void SetHighPrecisionTimersEnabled(bool aEnable);
342 };
343
344 #endif /* !defined(nsRefreshDriver_h_) */

mercurial