layout/base/nsRefreshDriver.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/base/nsRefreshDriver.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,344 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +/*
    1.11 + * Code to notify things that animate before a refresh, at an appropriate
    1.12 + * refresh rate.  (Perhaps temporary, until replaced by compositor.)
    1.13 + */
    1.14 +
    1.15 +#ifndef nsRefreshDriver_h_
    1.16 +#define nsRefreshDriver_h_
    1.17 +
    1.18 +#include "mozilla/TimeStamp.h"
    1.19 +#include "mozFlushType.h"
    1.20 +#include "nsTObserverArray.h"
    1.21 +#include "nsTArray.h"
    1.22 +#include "nsTHashtable.h"
    1.23 +#include "nsClassHashtable.h"
    1.24 +#include "nsHashKeys.h"
    1.25 +#include "mozilla/Attributes.h"
    1.26 +#include "mozilla/Maybe.h"
    1.27 +
    1.28 +class nsPresContext;
    1.29 +class nsIPresShell;
    1.30 +class nsIDocument;
    1.31 +class imgIRequest;
    1.32 +class nsIRunnable;
    1.33 +
    1.34 +namespace mozilla {
    1.35 +class RefreshDriverTimer;
    1.36 +}
    1.37 +
    1.38 +/**
    1.39 + * An abstract base class to be implemented by callers wanting to be
    1.40 + * notified at refresh times.  When nothing needs to be painted, callers
    1.41 + * may not be notified.
    1.42 + */
    1.43 +class nsARefreshObserver {
    1.44 +public:
    1.45 +  // AddRef and Release signatures that match nsISupports.  Implementors
    1.46 +  // must implement reference counting, and those that do implement
    1.47 +  // nsISupports will already have methods with the correct signature.
    1.48 +  //
    1.49 +  // The refresh driver does NOT hold references to refresh observers
    1.50 +  // except while it is notifying them.
    1.51 +  NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
    1.52 +  NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
    1.53 +
    1.54 +  virtual void WillRefresh(mozilla::TimeStamp aTime) = 0;
    1.55 +};
    1.56 +
    1.57 +/**
    1.58 + * An abstract base class to be implemented by callers wanting to be notified
    1.59 + * that a refresh has occurred. Callers must ensure an observer is removed
    1.60 + * before it is destroyed.
    1.61 + */
    1.62 +class nsAPostRefreshObserver {
    1.63 +public:
    1.64 +  virtual void DidRefresh() = 0;
    1.65 +};
    1.66 +
    1.67 +class nsRefreshDriver MOZ_FINAL : public nsISupports {
    1.68 +public:
    1.69 +  nsRefreshDriver(nsPresContext *aPresContext);
    1.70 +  ~nsRefreshDriver();
    1.71 +
    1.72 +  static void InitializeStatics();
    1.73 +  static void Shutdown();
    1.74 +
    1.75 +  // nsISupports implementation
    1.76 +  NS_DECL_ISUPPORTS
    1.77 +
    1.78 +  /**
    1.79 +   * Methods for testing, exposed via nsIDOMWindowUtils.  See
    1.80 +   * nsIDOMWindowUtils.advanceTimeAndRefresh for description.
    1.81 +   */
    1.82 +  void AdvanceTimeAndRefresh(int64_t aMilliseconds);
    1.83 +  void RestoreNormalRefresh();
    1.84 +  void DoTick();
    1.85 +  bool IsTestControllingRefreshesEnabled() const
    1.86 +  {
    1.87 +    return mTestControllingRefreshes;
    1.88 +  }
    1.89 +
    1.90 +  /**
    1.91 +   * Return the time of the most recent refresh.  This is intended to be
    1.92 +   * used by callers who want to start an animation now and want to know
    1.93 +   * what time to consider the start of the animation.  (This helps
    1.94 +   * ensure that multiple animations started during the same event off
    1.95 +   * the main event loop have the same start time.)
    1.96 +   */
    1.97 +  mozilla::TimeStamp MostRecentRefresh() const;
    1.98 +  /**
    1.99 +   * Same thing, but in microseconds since the epoch.
   1.100 +   */
   1.101 +  int64_t MostRecentRefreshEpochTime() const;
   1.102 +
   1.103 +  /**
   1.104 +   * Add / remove refresh observers.  Returns whether the operation
   1.105 +   * succeeded.
   1.106 +   *
   1.107 +   * The flush type affects:
   1.108 +   *   + the order in which the observers are notified (lowest flush
   1.109 +   *     type to highest, in order registered)
   1.110 +   *   + (in the future) which observers are suppressed when the display
   1.111 +   *     doesn't require current position data or isn't currently
   1.112 +   *     painting, and, correspondingly, which get notified when there
   1.113 +   *     is a flush during such suppression
   1.114 +   * and it must be either Flush_Style, Flush_Layout, or Flush_Display.
   1.115 +   *
   1.116 +   * The refresh driver does NOT own a reference to these observers;
   1.117 +   * they must remove themselves before they are destroyed.
   1.118 +   *
   1.119 +   * The observer will be called even if there is no other activity.
   1.120 +   */
   1.121 +  bool AddRefreshObserver(nsARefreshObserver *aObserver,
   1.122 +                          mozFlushType aFlushType);
   1.123 +  bool RemoveRefreshObserver(nsARefreshObserver *aObserver,
   1.124 +                             mozFlushType aFlushType);
   1.125 +
   1.126 +  /**
   1.127 +   * Add an observer that will be called after each refresh. The caller
   1.128 +   * must remove the observer before it is deleted. This does not trigger
   1.129 +   * refresh driver ticks.
   1.130 +   */
   1.131 +  void AddPostRefreshObserver(nsAPostRefreshObserver *aObserver);
   1.132 +  void RemovePostRefreshObserver(nsAPostRefreshObserver *aObserver);
   1.133 +
   1.134 +  /**
   1.135 +   * Add/Remove imgIRequest versions of observers.
   1.136 +   *
   1.137 +   * These are used for hooking into the refresh driver for
   1.138 +   * controlling animated images.
   1.139 +   *
   1.140 +   * @note The refresh driver owns a reference to these listeners.
   1.141 +   *
   1.142 +   * @note Technically, imgIRequest objects are not nsARefreshObservers, but
   1.143 +   * for controlling animated image repaint events, we subscribe the
   1.144 +   * imgIRequests to the nsRefreshDriver for notification of paint events.
   1.145 +   *
   1.146 +   * @returns whether the operation succeeded, or void in the case of removal.
   1.147 +   */
   1.148 +  bool AddImageRequest(imgIRequest* aRequest);
   1.149 +  void RemoveImageRequest(imgIRequest* aRequest);
   1.150 +
   1.151 +  /**
   1.152 +   * Add / remove presshells that we should flush style and layout on
   1.153 +   */
   1.154 +  bool AddStyleFlushObserver(nsIPresShell* aShell) {
   1.155 +    NS_ASSERTION(!mStyleFlushObservers.Contains(aShell),
   1.156 +		 "Double-adding style flush observer");
   1.157 +    bool appended = mStyleFlushObservers.AppendElement(aShell) != nullptr;
   1.158 +    EnsureTimerStarted(false);
   1.159 +    return appended;
   1.160 +  }
   1.161 +  void RemoveStyleFlushObserver(nsIPresShell* aShell) {
   1.162 +    mStyleFlushObservers.RemoveElement(aShell);
   1.163 +  }
   1.164 +  bool AddLayoutFlushObserver(nsIPresShell* aShell) {
   1.165 +    NS_ASSERTION(!IsLayoutFlushObserver(aShell),
   1.166 +		 "Double-adding layout flush observer");
   1.167 +    bool appended = mLayoutFlushObservers.AppendElement(aShell) != nullptr;
   1.168 +    EnsureTimerStarted(false);
   1.169 +    return appended;
   1.170 +  }
   1.171 +  void RemoveLayoutFlushObserver(nsIPresShell* aShell) {
   1.172 +    mLayoutFlushObservers.RemoveElement(aShell);
   1.173 +  }
   1.174 +  bool IsLayoutFlushObserver(nsIPresShell* aShell) {
   1.175 +    return mLayoutFlushObservers.Contains(aShell);
   1.176 +  }
   1.177 +  bool AddPresShellToInvalidateIfHidden(nsIPresShell* aShell) {
   1.178 +    NS_ASSERTION(!mPresShellsToInvalidateIfHidden.Contains(aShell),
   1.179 +		 "Double-adding style flush observer");
   1.180 +    bool appended = mPresShellsToInvalidateIfHidden.AppendElement(aShell) != nullptr;
   1.181 +    EnsureTimerStarted(false);
   1.182 +    return appended;
   1.183 +  }
   1.184 +  void RemovePresShellToInvalidateIfHidden(nsIPresShell* aShell) {
   1.185 +    mPresShellsToInvalidateIfHidden.RemoveElement(aShell);
   1.186 +  }
   1.187 +
   1.188 +  /**
   1.189 +   * Remember whether our presshell's view manager needs a flush
   1.190 +   */
   1.191 +  void ScheduleViewManagerFlush();
   1.192 +  void RevokeViewManagerFlush() {
   1.193 +    mViewManagerFlushIsPending = false;
   1.194 +  }
   1.195 +  bool ViewManagerFlushIsPending() {
   1.196 +    return mViewManagerFlushIsPending;
   1.197 +  }
   1.198 +
   1.199 +  /**
   1.200 +   * Add a document for which we have nsIFrameRequestCallbacks
   1.201 +   */
   1.202 +  void ScheduleFrameRequestCallbacks(nsIDocument* aDocument);
   1.203 +
   1.204 +  /**
   1.205 +   * Remove a document for which we have nsIFrameRequestCallbacks
   1.206 +   */
   1.207 +  void RevokeFrameRequestCallbacks(nsIDocument* aDocument);
   1.208 +
   1.209 +  /**
   1.210 +   * Tell the refresh driver that it is done driving refreshes and
   1.211 +   * should stop its timer and forget about its pres context.  This may
   1.212 +   * be called from within a refresh.
   1.213 +   */
   1.214 +  void Disconnect() {
   1.215 +    StopTimer();
   1.216 +    mPresContext = nullptr;
   1.217 +  }
   1.218 +
   1.219 +  bool IsFrozen() { return mFreezeCount > 0; }
   1.220 +
   1.221 +  /**
   1.222 +   * Freeze the refresh driver.  It should stop delivering future
   1.223 +   * refreshes until thawed. Note that the number of calls to Freeze() must
   1.224 +   * match the number of calls to Thaw() in order for the refresh driver to
   1.225 +   * be un-frozen.
   1.226 +   */
   1.227 +  void Freeze();
   1.228 +
   1.229 +  /**
   1.230 +   * Thaw the refresh driver.  If the number of calls to Freeze() matches the
   1.231 +   * number of calls to this function, the refresh driver should start
   1.232 +   * delivering refreshes again.
   1.233 +   */
   1.234 +  void Thaw();
   1.235 +
   1.236 +  /**
   1.237 +   * Throttle or unthrottle the refresh driver.  This is done if the
   1.238 +   * corresponding presshell is hidden or shown.
   1.239 +   */
   1.240 +  void SetThrottled(bool aThrottled);
   1.241 +
   1.242 +  /**
   1.243 +   * Return the prescontext we were initialized with
   1.244 +   */
   1.245 +  nsPresContext* PresContext() const { return mPresContext; }
   1.246 +
   1.247 +#ifdef DEBUG
   1.248 +  /**
   1.249 +   * Check whether the given observer is an observer for the given flush type
   1.250 +   */
   1.251 +  bool IsRefreshObserver(nsARefreshObserver *aObserver,
   1.252 +			   mozFlushType aFlushType);
   1.253 +#endif
   1.254 +
   1.255 +  /**
   1.256 +   * Default interval the refresh driver uses, in ms.
   1.257 +   */
   1.258 +  static int32_t DefaultInterval();
   1.259 +
   1.260 +  bool IsInRefresh() { return mInRefresh; }
   1.261 +
   1.262 +private:
   1.263 +  typedef nsTObserverArray<nsARefreshObserver*> ObserverArray;
   1.264 +  typedef nsTHashtable<nsISupportsHashKey> RequestTable;
   1.265 +  struct ImageStartData {
   1.266 +    ImageStartData()
   1.267 +    {
   1.268 +    }
   1.269 +
   1.270 +    mozilla::Maybe<mozilla::TimeStamp> mStartTime;
   1.271 +    RequestTable mEntries;
   1.272 +  };
   1.273 +  typedef nsClassHashtable<nsUint32HashKey, ImageStartData> ImageStartTable;
   1.274 +
   1.275 +  void Tick(int64_t aNowEpoch, mozilla::TimeStamp aNowTime);
   1.276 +
   1.277 +  void EnsureTimerStarted(bool aAdjustingTimer);
   1.278 +  void StopTimer();
   1.279 +
   1.280 +  uint32_t ObserverCount() const;
   1.281 +  uint32_t ImageRequestCount() const;
   1.282 +  static PLDHashOperator ImageRequestEnumerator(nsISupportsHashKey* aEntry,
   1.283 +                                                void* aUserArg);
   1.284 +  static PLDHashOperator StartTableRequestCounter(const uint32_t& aKey,
   1.285 +                                                  ImageStartData* aEntry,
   1.286 +                                                  void* aUserArg);
   1.287 +  static PLDHashOperator StartTableRefresh(const uint32_t& aKey,
   1.288 +                                           ImageStartData* aEntry,
   1.289 +                                           void* aUserArg);
   1.290 +  static PLDHashOperator BeginRefreshingImages(nsISupportsHashKey* aEntry,
   1.291 +                                               void* aUserArg);
   1.292 +  ObserverArray& ArrayFor(mozFlushType aFlushType);
   1.293 +  // Trigger a refresh immediately, if haven't been disconnected or frozen.
   1.294 +  void DoRefresh();
   1.295 +
   1.296 +  double GetRefreshTimerInterval() const;
   1.297 +  double GetRegularTimerInterval(bool *outIsDefault = nullptr) const;
   1.298 +  double GetThrottledTimerInterval() const;
   1.299 +
   1.300 +  bool HaveFrameRequestCallbacks() const {
   1.301 +    return mFrameRequestCallbackDocs.Length() != 0;
   1.302 +  }
   1.303 +
   1.304 +  mozilla::RefreshDriverTimer* ChooseTimer() const;
   1.305 +  mozilla::RefreshDriverTimer *mActiveTimer;
   1.306 +
   1.307 +  nsPresContext *mPresContext; // weak; pres context passed in constructor
   1.308 +                               // and unset in Disconnect
   1.309 +
   1.310 +  uint32_t mFreezeCount;
   1.311 +  bool mThrottled;
   1.312 +  bool mTestControllingRefreshes;
   1.313 +  bool mViewManagerFlushIsPending;
   1.314 +  bool mRequestedHighPrecision;
   1.315 +  bool mInRefresh;
   1.316 +
   1.317 +  int64_t mMostRecentRefreshEpochTime;
   1.318 +  mozilla::TimeStamp mMostRecentRefresh;
   1.319 +
   1.320 +  // separate arrays for each flush type we support
   1.321 +  ObserverArray mObservers[3];
   1.322 +  RequestTable mRequests;
   1.323 +  ImageStartTable mStartTable;
   1.324 +
   1.325 +  nsAutoTArray<nsIPresShell*, 16> mStyleFlushObservers;
   1.326 +  nsAutoTArray<nsIPresShell*, 16> mLayoutFlushObservers;
   1.327 +  nsAutoTArray<nsIPresShell*, 16> mPresShellsToInvalidateIfHidden;
   1.328 +  // nsTArray on purpose, because we want to be able to swap.
   1.329 +  nsTArray<nsIDocument*> mFrameRequestCallbackDocs;
   1.330 +  nsTArray<nsAPostRefreshObserver*> mPostRefreshObservers;
   1.331 +
   1.332 +  // Helper struct for processing image requests
   1.333 +  struct ImageRequestParameters {
   1.334 +    mozilla::TimeStamp mCurrent;
   1.335 +    mozilla::TimeStamp mPrevious;
   1.336 +    RequestTable* mRequests;
   1.337 +    mozilla::TimeStamp mDesired;
   1.338 +  };
   1.339 +
   1.340 +  friend class mozilla::RefreshDriverTimer;
   1.341 +
   1.342 +  // turn on or turn off high precision based on various factors
   1.343 +  void ConfigureHighPrecision();
   1.344 +  void SetHighPrecisionTimersEnabled(bool aEnable);
   1.345 +};
   1.346 +
   1.347 +#endif /* !defined(nsRefreshDriver_h_) */

mercurial