layout/base/nsRefreshDriver.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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.)
    10  */
    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"
    25 class nsPresContext;
    26 class nsIPresShell;
    27 class nsIDocument;
    28 class imgIRequest;
    29 class nsIRunnable;
    31 namespace mozilla {
    32 class RefreshDriverTimer;
    33 }
    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;
    51   virtual void WillRefresh(mozilla::TimeStamp aTime) = 0;
    52 };
    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 };
    64 class nsRefreshDriver MOZ_FINAL : public nsISupports {
    65 public:
    66   nsRefreshDriver(nsPresContext *aPresContext);
    67   ~nsRefreshDriver();
    69   static void InitializeStatics();
    70   static void Shutdown();
    72   // nsISupports implementation
    73   NS_DECL_ISUPPORTS
    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   }
    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;
   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);
   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);
   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);
   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   }
   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   }
   196   /**
   197    * Add a document for which we have nsIFrameRequestCallbacks
   198    */
   199   void ScheduleFrameRequestCallbacks(nsIDocument* aDocument);
   201   /**
   202    * Remove a document for which we have nsIFrameRequestCallbacks
   203    */
   204   void RevokeFrameRequestCallbacks(nsIDocument* aDocument);
   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   }
   216   bool IsFrozen() { return mFreezeCount > 0; }
   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();
   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();
   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);
   239   /**
   240    * Return the prescontext we were initialized with
   241    */
   242   nsPresContext* PresContext() const { return mPresContext; }
   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
   252   /**
   253    * Default interval the refresh driver uses, in ms.
   254    */
   255   static int32_t DefaultInterval();
   257   bool IsInRefresh() { return mInRefresh; }
   259 private:
   260   typedef nsTObserverArray<nsARefreshObserver*> ObserverArray;
   261   typedef nsTHashtable<nsISupportsHashKey> RequestTable;
   262   struct ImageStartData {
   263     ImageStartData()
   264     {
   265     }
   267     mozilla::Maybe<mozilla::TimeStamp> mStartTime;
   268     RequestTable mEntries;
   269   };
   270   typedef nsClassHashtable<nsUint32HashKey, ImageStartData> ImageStartTable;
   272   void Tick(int64_t aNowEpoch, mozilla::TimeStamp aNowTime);
   274   void EnsureTimerStarted(bool aAdjustingTimer);
   275   void StopTimer();
   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();
   293   double GetRefreshTimerInterval() const;
   294   double GetRegularTimerInterval(bool *outIsDefault = nullptr) const;
   295   double GetThrottledTimerInterval() const;
   297   bool HaveFrameRequestCallbacks() const {
   298     return mFrameRequestCallbackDocs.Length() != 0;
   299   }
   301   mozilla::RefreshDriverTimer* ChooseTimer() const;
   302   mozilla::RefreshDriverTimer *mActiveTimer;
   304   nsPresContext *mPresContext; // weak; pres context passed in constructor
   305                                // and unset in Disconnect
   307   uint32_t mFreezeCount;
   308   bool mThrottled;
   309   bool mTestControllingRefreshes;
   310   bool mViewManagerFlushIsPending;
   311   bool mRequestedHighPrecision;
   312   bool mInRefresh;
   314   int64_t mMostRecentRefreshEpochTime;
   315   mozilla::TimeStamp mMostRecentRefresh;
   317   // separate arrays for each flush type we support
   318   ObserverArray mObservers[3];
   319   RequestTable mRequests;
   320   ImageStartTable mStartTable;
   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;
   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   };
   337   friend class mozilla::RefreshDriverTimer;
   339   // turn on or turn off high precision based on various factors
   340   void ConfigureHighPrecision();
   341   void SetHighPrecisionTimersEnabled(bool aEnable);
   342 };
   344 #endif /* !defined(nsRefreshDriver_h_) */

mercurial