LCOV - code coverage report
Current view: top level - image - ProgressTracker.h (source / functions) Hit Total Coverage
Test: output.info Lines: 26 33 78.8 %
Date: 2017-07-14 16:53:18 Functions: 15 17 88.2 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : #ifndef mozilla_image_ProgressTracker_h
       8             : #define mozilla_image_ProgressTracker_h
       9             : 
      10             : #include "CopyOnWrite.h"
      11             : #include "mozilla/Mutex.h"
      12             : #include "mozilla/RefPtr.h"
      13             : #include "mozilla/WeakPtr.h"
      14             : #include "nsDataHashtable.h"
      15             : #include "nsCOMPtr.h"
      16             : #include "nsTObserverArray.h"
      17             : #include "nsThreadUtils.h"
      18             : #include "nsRect.h"
      19             : #include "IProgressObserver.h"
      20             : 
      21             : class nsIRunnable;
      22             : 
      23             : namespace mozilla {
      24             : namespace image {
      25             : 
      26             : class AsyncNotifyRunnable;
      27             : class AsyncNotifyCurrentStateRunnable;
      28             : class Image;
      29             : 
      30             : /**
      31             :  * Image progress bitflags.
      32             :  *
      33             :  * See CheckProgressConsistency() for the invariants we enforce about the
      34             :  * ordering dependencies betweeen these flags.
      35             :  */
      36             : enum {
      37             :   FLAG_SIZE_AVAILABLE     = 1u << 0,  // STATUS_SIZE_AVAILABLE
      38             :   FLAG_DECODE_COMPLETE    = 1u << 1,  // STATUS_DECODE_COMPLETE
      39             :   FLAG_FRAME_COMPLETE     = 1u << 2,  // STATUS_FRAME_COMPLETE
      40             :   FLAG_LOAD_COMPLETE      = 1u << 3,  // STATUS_LOAD_COMPLETE
      41             :   FLAG_ONLOAD_BLOCKED     = 1u << 4,
      42             :   FLAG_ONLOAD_UNBLOCKED   = 1u << 5,
      43             :   FLAG_IS_ANIMATED        = 1u << 6,  // STATUS_IS_ANIMATED
      44             :   FLAG_HAS_TRANSPARENCY   = 1u << 7,  // STATUS_HAS_TRANSPARENCY
      45             :   FLAG_LAST_PART_COMPLETE = 1u << 8,
      46             :   FLAG_HAS_ERROR          = 1u << 9   // STATUS_ERROR
      47             : };
      48             : 
      49             : typedef uint32_t Progress;
      50             : 
      51             : const uint32_t NoProgress = 0;
      52             : 
      53          41 : inline Progress LoadCompleteProgress(bool aLastPart,
      54             :                                      bool aError,
      55             :                                      nsresult aStatus)
      56             : {
      57          41 :   Progress progress = FLAG_LOAD_COMPLETE;
      58          41 :   if (aLastPart) {
      59          41 :     progress |= FLAG_LAST_PART_COMPLETE;
      60             :   }
      61          41 :   if (NS_FAILED(aStatus) || aError) {
      62           1 :     progress |= FLAG_HAS_ERROR;
      63             :   }
      64          41 :   return progress;
      65             : }
      66             : 
      67             : /**
      68             :  * ProgressTracker stores its observers in an ObserverTable, which is a hash
      69             :  * table mapping raw pointers to WeakPtr's to the same objects. This sounds like
      70             :  * unnecessary duplication of information, but it's necessary for stable hash
      71             :  * values since WeakPtr's lose the knowledge of which object they used to point
      72             :  * to when that object is destroyed.
      73             :  *
      74             :  * ObserverTable subclasses nsDataHashtable to add reference counting support
      75             :  * and a copy constructor, both of which are needed for use with CopyOnWrite<T>.
      76             :  */
      77             : class ObserverTable
      78             :   : public nsDataHashtable<nsPtrHashKey<IProgressObserver>,
      79             :                            WeakPtr<IProgressObserver>>
      80             : {
      81             : public:
      82          43 :   NS_INLINE_DECL_REFCOUNTING(ObserverTable);
      83             : 
      84          41 :   ObserverTable() = default;
      85             : 
      86           0 :   ObserverTable(const ObserverTable& aOther)
      87           0 :   {
      88           0 :     NS_WARNING("Forced to copy ObserverTable due to nested notifications");
      89           0 :     for (auto iter = aOther.ConstIter(); !iter.Done(); iter.Next()) {
      90           0 :       this->Put(iter.Key(), iter.Data());
      91             :     }
      92           0 :   }
      93             : 
      94             : private:
      95           1 :   ~ObserverTable() { }
      96             : };
      97             : 
      98             : /**
      99             :  * ProgressTracker is a class that records an Image's progress through the
     100             :  * loading and decoding process, and makes it possible to send notifications to
     101             :  * IProgressObservers, both synchronously and asynchronously.
     102             :  *
     103             :  * When a new observer needs to be notified of the current progress of an image,
     104             :  * call the Notify() method on this class with the relevant observer as its
     105             :  * argument, and the notifications will be replayed to the observer
     106             :  * asynchronously.
     107             :  */
     108             : class ProgressTracker : public mozilla::SupportsWeakPtr<ProgressTracker>
     109             : {
     110           3 :   virtual ~ProgressTracker() { }
     111             : 
     112             : public:
     113          42 :   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(ProgressTracker)
     114        5578 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ProgressTracker)
     115             : 
     116          41 :   ProgressTracker()
     117          41 :     : mImageMutex("ProgressTracker::mImage")
     118             :     , mImage(nullptr)
     119          41 :     , mObservers(new ObserverTable)
     120             :     , mProgress(NoProgress)
     121          82 :     , mIsMultipart(false)
     122          41 :   { }
     123             : 
     124         489 :   bool HasImage() const { MutexAutoLock lock(mImageMutex); return mImage; }
     125        1420 :   already_AddRefed<Image> GetImage() const
     126             :   {
     127        2840 :     MutexAutoLock lock(mImageMutex);
     128        2840 :     RefPtr<Image> image = mImage;
     129        2840 :     return image.forget();
     130             :   }
     131             : 
     132             :   // Get the current image status (as in imgIRequest).
     133             :   uint32_t GetImageStatus() const;
     134             : 
     135             :   // Get the current Progress.
     136         178 :   Progress GetProgress() const { return mProgress; }
     137             : 
     138             :   // Schedule an asynchronous "replaying" of all the notifications that would
     139             :   // have to happen to put us in the current state.
     140             :   // We will also take note of any notifications that happen between the time
     141             :   // Notify() is called and when we call SyncNotify on |aObserver|, and replay
     142             :   // them as well.
     143             :   // Should be called on the main thread only, since observers and GetURI are
     144             :   // not threadsafe.
     145             :   void Notify(IProgressObserver* aObserver);
     146             : 
     147             :   // Schedule an asynchronous "replaying" of all the notifications that would
     148             :   // have to happen to put us in the state we are in right now.
     149             :   // Unlike Notify(), does *not* take into account future notifications.
     150             :   // This is only useful if you do not have an imgRequest, e.g., if you are a
     151             :   // static request returned from imgIRequest::GetStaticRequest().
     152             :   // Should be called on the main thread only, since observers and GetURI are
     153             :   // not threadsafe.
     154             :   void NotifyCurrentState(IProgressObserver* aObserver);
     155             : 
     156             :   // "Replay" all of the notifications that would have to happen to put us in
     157             :   // the state we're currently in.
     158             :   // Only use this if you're already servicing an asynchronous call (e.g.
     159             :   // OnStartRequest).
     160             :   // Should be called on the main thread only, since observers and GetURI are
     161             :   // not threadsafe.
     162             :   void SyncNotify(IProgressObserver* aObserver);
     163             : 
     164             :   // Get this ProgressTracker ready for a new request. This resets all the
     165             :   // state that doesn't persist between requests.
     166             :   void ResetForNewRequest();
     167             : 
     168             :   // Stateless notifications. These are dispatched and immediately forgotten
     169             :   // about. All of these notifications are main thread only.
     170             :   void OnDiscard();
     171             :   void OnUnlockedDraw();
     172             :   void OnImageAvailable();
     173             : 
     174             :   // Compute the difference between this our progress and aProgress. This allows
     175             :   // callers to predict whether SyncNotifyProgress will send any notifications.
     176         195 :   Progress Difference(Progress aProgress) const
     177             :   {
     178         195 :     return ~mProgress & aProgress;
     179             :   }
     180             : 
     181             :   // Update our state to incorporate the changes in aProgress and synchronously
     182             :   // notify our observers.
     183             :   //
     184             :   // Because this may result in recursive notifications, no decoding locks may
     185             :   // be held.  Called on the main thread only.
     186             :   void SyncNotifyProgress(Progress aProgress,
     187             :                           const nsIntRect& aInvalidRect = nsIntRect());
     188             : 
     189             :   // We manage a set of observers that are using an image and thus concerned
     190             :   // with its loading progress. Weak pointers.
     191             :   void AddObserver(IProgressObserver* aObserver);
     192             :   bool RemoveObserver(IProgressObserver* aObserver);
     193             :   uint32_t ObserverCount() const;
     194             : 
     195             :   // Resets our weak reference to our image. Image subclasses should call this
     196             :   // in their destructor.
     197             :   void ResetImage();
     198             : 
     199             :   // Tell this progress tracker that it is for a multipart image.
     200           0 :   void SetIsMultipart() { mIsMultipart = true; }
     201             : 
     202             : private:
     203             :   friend class AsyncNotifyRunnable;
     204             :   friend class AsyncNotifyCurrentStateRunnable;
     205             :   friend class ImageFactory;
     206             : 
     207             :   ProgressTracker(const ProgressTracker& aOther) = delete;
     208             : 
     209             :   // Sets our weak reference to our image. Only ImageFactory should call this.
     210             :   void SetImage(Image* aImage);
     211             : 
     212             :   // Send some notifications that would be necessary to make |aObserver| believe
     213             :   // the request is finished downloading and decoding.  We only send
     214             :   // FLAG_LOAD_COMPLETE and FLAG_ONLOAD_UNBLOCKED, and only if necessary.
     215             :   void EmulateRequestFinished(IProgressObserver* aObserver);
     216             : 
     217             :   // Main thread only because it deals with the observer service.
     218             :   void FireFailureNotification();
     219             : 
     220             :   // The runnable, if any, that we've scheduled to deliver async notifications.
     221             :   nsCOMPtr<nsIRunnable> mRunnable;
     222             : 
     223             :   // mImage is a weak ref; it should be set to null when the image goes out of
     224             :   // scope. mImageMutex protects mImage.
     225             :   mutable Mutex mImageMutex;
     226             :   Image* mImage;
     227             : 
     228             :   // Hashtable of observers attached to the image. Each observer represents a
     229             :   // consumer using the image. Main thread only.
     230             :   CopyOnWrite<ObserverTable> mObservers;
     231             : 
     232             :   Progress mProgress;
     233             : 
     234             :   // Whether this is a progress tracker for a multipart image.
     235             :   bool mIsMultipart;
     236             : };
     237             : 
     238             : } // namespace image
     239             : } // namespace mozilla
     240             : 
     241             : #endif // mozilla_image_ProgressTracker_h

Generated by: LCOV version 1.13