image/src/imgStatusTracker.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  *
     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 #ifndef imgStatusTracker_h__
     8 #define imgStatusTracker_h__
    10 class imgDecoderObserver;
    11 class imgIContainer;
    12 class imgStatusNotifyRunnable;
    13 class imgRequestNotifyRunnable;
    14 class imgStatusTrackerObserver;
    15 class nsIRunnable;
    17 #include "mozilla/RefPtr.h"
    18 #include "mozilla/WeakPtr.h"
    19 #include "nsCOMPtr.h"
    20 #include "nsTObserverArray.h"
    21 #include "nsThreadUtils.h"
    22 #include "nsRect.h"
    23 #include "imgRequestProxy.h"
    25 namespace mozilla {
    26 namespace image {
    28 class Image;
    30 struct ImageStatusDiff
    31 {
    32   ImageStatusDiff()
    33     : invalidRect()
    34     , diffState(0)
    35     , diffImageStatus(0)
    36     , unblockedOnload(false)
    37     , unsetDecodeStarted(false)
    38     , foundError(false)
    39     , foundIsMultipart(false)
    40     , foundLastPart(false)
    41     , gotDecoded(false)
    42   { }
    44   static ImageStatusDiff NoChange() { return ImageStatusDiff(); }
    45   bool IsNoChange() const { return *this == NoChange(); }
    47   bool operator!=(const ImageStatusDiff& aOther) const { return !(*this == aOther); }
    48   bool operator==(const ImageStatusDiff& aOther) const {
    49     return aOther.invalidRect == invalidRect
    50         && aOther.diffState == diffState
    51         && aOther.diffImageStatus == diffImageStatus
    52         && aOther.unblockedOnload == unblockedOnload
    53         && aOther.unsetDecodeStarted == unsetDecodeStarted
    54         && aOther.foundError == foundError
    55         && aOther.foundIsMultipart == foundIsMultipart
    56         && aOther.foundLastPart == foundLastPart
    57         && aOther.gotDecoded == gotDecoded;
    58   }
    60   void Combine(const ImageStatusDiff& aOther) {
    61     invalidRect = invalidRect.Union(aOther.invalidRect);
    62     diffState |= aOther.diffState;
    63     diffImageStatus |= aOther.diffImageStatus;
    64     unblockedOnload = unblockedOnload || aOther.unblockedOnload;
    65     unsetDecodeStarted = unsetDecodeStarted || aOther.unsetDecodeStarted;
    66     foundError = foundError || aOther.foundError;
    67     foundIsMultipart = foundIsMultipart || aOther.foundIsMultipart;
    68     foundLastPart = foundLastPart || aOther.foundLastPart;
    69     gotDecoded = gotDecoded || aOther.gotDecoded;
    70   }
    72   nsIntRect invalidRect;
    73   uint32_t  diffState;
    74   uint32_t  diffImageStatus;
    75   bool      unblockedOnload    : 1;
    76   bool      unsetDecodeStarted : 1;
    77   bool      foundError         : 1;
    78   bool      foundIsMultipart   : 1;
    79   bool      foundLastPart      : 1;
    80   bool      gotDecoded         : 1;
    81 };
    83 enum {
    84   stateRequestStarted    = 1u << 0,
    85   stateHasSize           = 1u << 1,
    86   stateDecodeStarted     = 1u << 2,
    87   stateDecodeStopped     = 1u << 3,
    88   stateFrameStopped      = 1u << 4,
    89   stateRequestStopped    = 1u << 5,
    90   stateBlockingOnload    = 1u << 6,
    91   stateImageIsAnimated   = 1u << 7
    92 };
    94 } // namespace image
    95 } // namespace mozilla
    97 /*
    98  * The image status tracker is a class that encapsulates all the loading and
    99  * decoding status about an Image, and makes it possible to send notifications
   100  * to imgRequestProxys, both synchronously (i.e., the status now) and
   101  * asynchronously (the status later).
   102  *
   103  * When a new proxy needs to be notified of the current state of an image, call
   104  * the Notify() method on this class with the relevant proxy as its argument,
   105  * and the notifications will be replayed to the proxy asynchronously.
   106  */
   109 class imgStatusTracker : public mozilla::SupportsWeakPtr<imgStatusTracker>
   110 {
   111 public:
   112   MOZ_DECLARE_REFCOUNTED_TYPENAME(imgStatusTracker)
   113   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(imgStatusTracker)
   115   // aImage is the image that this status tracker will pass to the
   116   // imgRequestProxys in SyncNotify() and EmulateRequestFinished(), and must be
   117   // alive as long as this instance is, because we hold a weak reference to it.
   118   imgStatusTracker(mozilla::image::Image* aImage);
   119   virtual ~imgStatusTracker();
   121   // Image-setter, for imgStatusTrackers created by imgRequest::Init, which
   122   // are created before their Image is created.  This method should only
   123   // be called once, and only on an imgStatusTracker that was initialized
   124   // without an image.
   125   void SetImage(mozilla::image::Image* aImage);
   127   // Image resetter, for when mImage is about to go out of scope. mImage is a
   128   // weak reference, and thus must be set to null when it's object is deleted.
   129   void ResetImage();
   131   // Inform this status tracker that it is associated with a multipart image.
   132   void SetIsMultipart() { mIsMultipart = true; }
   134   // Schedule an asynchronous "replaying" of all the notifications that would
   135   // have to happen to put us in the current state.
   136   // We will also take note of any notifications that happen between the time
   137   // Notify() is called and when we call SyncNotify on |proxy|, and replay them
   138   // as well.
   139   // Should be called on the main thread only, since imgRequestProxy and GetURI
   140   // are not threadsafe.
   141   void Notify(imgRequestProxy* proxy);
   143   // Schedule an asynchronous "replaying" of all the notifications that would
   144   // have to happen to put us in the state we are in right now.
   145   // Unlike Notify(), does *not* take into account future notifications.
   146   // This is only useful if you do not have an imgRequest, e.g., if you are a
   147   // static request returned from imgIRequest::GetStaticRequest().
   148   // Should be called on the main thread only, since imgRequestProxy and GetURI
   149   // are not threadsafe.
   150   void NotifyCurrentState(imgRequestProxy* proxy);
   152   // "Replay" all of the notifications that would have to happen to put us in
   153   // the state we're currently in.
   154   // Only use this if you're already servicing an asynchronous call (e.g.
   155   // OnStartRequest).
   156   // Should be called on the main thread only, since imgRequestProxy and GetURI
   157   // are not threadsafe.
   158   void SyncNotify(imgRequestProxy* proxy);
   160   // Send some notifications that would be necessary to make |proxy| believe
   161   // the request is finished downloading and decoding.  We only send
   162   // OnStopRequest and UnblockOnload, and only if necessary.
   163   void EmulateRequestFinished(imgRequestProxy* proxy, nsresult aStatus);
   165   // We manage a set of consumers that are using an image and thus concerned
   166   // with its status. Weak pointers.
   167   void AddConsumer(imgRequestProxy* aConsumer);
   168   bool RemoveConsumer(imgRequestProxy* aConsumer, nsresult aStatus);
   169   size_t ConsumerCount() const {
   170     MOZ_ASSERT(NS_IsMainThread(), "Use mConsumers on main thread only");
   171     return mConsumers.Length();
   172   }
   174   // This is intentionally non-general because its sole purpose is to support an
   175   // some obscure network priority logic in imgRequest. That stuff could probably
   176   // be improved, but it's too scary to mess with at the moment.
   177   bool FirstConsumerIs(imgRequestProxy* aConsumer);
   179   void AdoptConsumers(imgStatusTracker* aTracker) {
   180     MOZ_ASSERT(NS_IsMainThread(), "Use mConsumers on main thread only");
   181     MOZ_ASSERT(aTracker);
   182     mConsumers = aTracker->mConsumers;
   183   }
   185   // Returns whether we are in the process of loading; that is, whether we have
   186   // not received OnStopRequest.
   187   bool IsLoading() const;
   189   // Get the current image status (as in imgIRequest).
   190   uint32_t GetImageStatus() const;
   192   // Following are all the notification methods. You must call the Record
   193   // variant on this status tracker, then call the Send variant for each proxy
   194   // you want to notify.
   196   // Call when the request is being cancelled.
   197   void RecordCancel();
   199   // Shorthand for recording all the load notifications: StartRequest,
   200   // StartContainer, StopRequest.
   201   void RecordLoaded();
   203   // Shorthand for recording all the decode notifications: StartDecode,
   204   // StartFrame, DataAvailable, StopFrame, StopDecode.
   205   void RecordDecoded();
   207   /* non-virtual imgDecoderObserver methods */
   208   // Functions with prefix Send- are main thread only, since they contain calls
   209   // to imgRequestProxy functions, which are expected on the main thread.
   210   void RecordStartDecode();
   211   void SendStartDecode(imgRequestProxy* aProxy);
   212   void RecordStartContainer(imgIContainer* aContainer);
   213   void SendStartContainer(imgRequestProxy* aProxy);
   214   void RecordStartFrame();
   215   // No SendStartFrame since it's not observed below us.
   216   void RecordFrameChanged(const nsIntRect* aDirtyRect);
   217   void SendFrameChanged(imgRequestProxy* aProxy, const nsIntRect* aDirtyRect);
   218   void RecordStopFrame();
   219   void SendStopFrame(imgRequestProxy* aProxy);
   220   void RecordStopDecode(nsresult statusg);
   221   void SendStopDecode(imgRequestProxy* aProxy, nsresult aStatus);
   222   void RecordDiscard();
   223   void SendDiscard(imgRequestProxy* aProxy);
   224   void RecordUnlockedDraw();
   225   void SendUnlockedDraw(imgRequestProxy* aProxy);
   226   void RecordImageIsAnimated();
   227   void SendImageIsAnimated(imgRequestProxy *aProxy);
   229   /* non-virtual sort-of-nsIRequestObserver methods */
   230   // Functions with prefix Send- are main thread only, since they contain calls
   231   // to imgRequestProxy functions, which are expected on the main thread.
   232   void RecordStartRequest();
   233   void SendStartRequest(imgRequestProxy* aProxy);
   234   void RecordStopRequest(bool aLastPart, nsresult aStatus);
   235   void SendStopRequest(imgRequestProxy* aProxy, bool aLastPart, nsresult aStatus);
   237   // All main thread only because they call functions (like SendStartRequest)
   238   // which are expected to be called on the main thread.
   239   void OnStartRequest();
   240   // OnDataAvailable will dispatch a call to itself onto the main thread if not
   241   // called there.
   242   void OnDataAvailable();
   243   void OnStopRequest(bool aLastPart, nsresult aStatus);
   244   void OnDiscard();
   245   void FrameChanged(const nsIntRect* aDirtyRect);
   246   void OnUnlockedDraw();
   247   // This is called only by VectorImage, and only to ensure tests work
   248   // properly. Do not use it.
   249   void OnStopFrame();
   251   /* non-virtual imgIOnloadBlocker methods */
   252   // NB: If UnblockOnload is sent, and then we are asked to replay the
   253   // notifications, we will not send a BlockOnload/UnblockOnload pair.  This
   254   // is different from all the other notifications.
   255   void RecordBlockOnload();
   256   void SendBlockOnload(imgRequestProxy* aProxy);
   257   void RecordUnblockOnload();
   258   void SendUnblockOnload(imgRequestProxy* aProxy);
   260   // Main thread only because mConsumers is not threadsafe.
   261   void MaybeUnblockOnload();
   263   void RecordError();
   265   bool IsMultipart() const { return mIsMultipart; }
   267   // Weak pointer getters - no AddRefs.
   268   inline already_AddRefed<mozilla::image::Image> GetImage() const {
   269     nsRefPtr<mozilla::image::Image> image = mImage;
   270     return image.forget();
   271   }
   272   inline bool HasImage() { return mImage; }
   274   inline imgDecoderObserver* GetDecoderObserver() { return mTrackerObserver.get(); }
   276   already_AddRefed<imgStatusTracker> CloneForRecording();
   278   // Compute the difference between this status tracker and aOther.
   279   mozilla::image::ImageStatusDiff Difference(imgStatusTracker* aOther) const;
   281   // Captures all of the decode notifications (i.e., not OnStartRequest /
   282   // OnStopRequest) so far as an ImageStatusDiff.
   283   mozilla::image::ImageStatusDiff DecodeStateAsDifference() const;
   285   // Update our state to incorporate the changes in aDiff.
   286   void ApplyDifference(const mozilla::image::ImageStatusDiff& aDiff);
   288   // Notify for the changes captured in an ImageStatusDiff. Because this may
   289   // result in recursive notifications, no decoding locks may be held.
   290   // Called on the main thread only.
   291   void SyncNotifyDifference(const mozilla::image::ImageStatusDiff& aDiff);
   293   nsIntRect GetInvalidRect() const { return mInvalidRect; }
   295 private:
   296   typedef nsTObserverArray<mozilla::WeakPtr<imgRequestProxy>> ProxyArray;
   297   friend class imgStatusNotifyRunnable;
   298   friend class imgRequestNotifyRunnable;
   299   friend class imgStatusTrackerObserver;
   300   friend class imgStatusTrackerInit;
   301   imgStatusTracker(const imgStatusTracker& aOther);
   303   // Main thread only because it deals with the observer service.
   304   void FireFailureNotification();
   306   // Main thread only, since imgRequestProxy calls are expected on the main
   307   // thread, and mConsumers is not threadsafe.
   308   static void SyncNotifyState(ProxyArray& proxies,
   309                               bool hasImage, uint32_t state,
   310                               nsIntRect& dirtyRect, bool hadLastPart);
   312   nsCOMPtr<nsIRunnable> mRequestRunnable;
   314   // The invalid area of the most recent frame we know about. (All previous
   315   // frames are assumed to be fully valid.)
   316   nsIntRect mInvalidRect;
   318   // This weak ref should be set null when the image goes out of scope.
   319   mozilla::image::Image* mImage;
   321   // List of proxies attached to the image. Each proxy represents a consumer
   322   // using the image. Array and/or individual elements should only be accessed
   323   // on the main thread.
   324   ProxyArray mConsumers;
   326   mozilla::RefPtr<imgDecoderObserver> mTrackerObserver;
   328   uint32_t mState;
   329   uint32_t mImageStatus;
   330   bool mIsMultipart    : 1;
   331   bool mHadLastPart    : 1;
   332   bool mHasBeenDecoded : 1;
   333 };
   335 class imgStatusTrackerInit
   336 {
   337 public:
   338   imgStatusTrackerInit(mozilla::image::Image* aImage,
   339                        imgStatusTracker* aTracker);
   340   ~imgStatusTrackerInit();
   341 private:
   342   imgStatusTracker* mTracker;
   343 };
   345 #endif

mercurial