2010-05-15 00:47:59 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
*
|
2012-05-21 15:12:37 +04:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2010-05-15 00:47:59 +04:00
|
|
|
|
2015-05-15 06:52:05 +03:00
|
|
|
#ifndef mozilla_image_ProgressTracker_h
|
|
|
|
#define mozilla_image_ProgressTracker_h
|
2010-05-15 00:47:59 +04:00
|
|
|
|
2015-08-26 02:26:43 +03:00
|
|
|
#include "CopyOnWrite.h"
|
2015-05-01 04:13:14 +03:00
|
|
|
#include "mozilla/Mutex.h"
|
2015-10-18 08:24:48 +03:00
|
|
|
#include "mozilla/RefPtr.h"
|
2013-09-28 22:28:44 +04:00
|
|
|
#include "mozilla/WeakPtr.h"
|
2015-08-26 02:26:43 +03:00
|
|
|
#include "nsDataHashtable.h"
|
2010-08-12 19:59:28 +04:00
|
|
|
#include "nsCOMPtr.h"
|
2012-10-12 20:11:20 +04:00
|
|
|
#include "nsTObserverArray.h"
|
2013-09-28 22:28:43 +04:00
|
|
|
#include "nsThreadUtils.h"
|
2013-09-07 17:01:08 +04:00
|
|
|
#include "nsRect.h"
|
2015-01-07 12:35:20 +03:00
|
|
|
#include "IProgressObserver.h"
|
2010-05-15 00:47:59 +04:00
|
|
|
|
2014-11-15 07:10:47 +03:00
|
|
|
class nsIRunnable;
|
|
|
|
|
2013-08-29 02:39:04 +04:00
|
|
|
namespace mozilla {
|
|
|
|
namespace image {
|
|
|
|
|
2014-11-15 07:10:47 +03:00
|
|
|
class AsyncNotifyRunnable;
|
|
|
|
class AsyncNotifyCurrentStateRunnable;
|
2013-08-29 02:39:04 +04:00
|
|
|
class Image;
|
|
|
|
|
2015-10-23 09:29:38 +03:00
|
|
|
/**
|
|
|
|
* Image progress bitflags.
|
|
|
|
*
|
|
|
|
* See CheckProgressConsistency() for the invariants we enforce about the
|
|
|
|
* ordering dependencies betweeen these flags.
|
|
|
|
*/
|
2014-11-07 04:33:57 +03:00
|
|
|
enum {
|
2014-11-18 01:29:56 +03:00
|
|
|
FLAG_SIZE_AVAILABLE = 1u << 0, // STATUS_SIZE_AVAILABLE
|
2015-07-07 03:11:14 +03:00
|
|
|
FLAG_DECODE_COMPLETE = 1u << 1, // STATUS_DECODE_COMPLETE
|
|
|
|
FLAG_FRAME_COMPLETE = 1u << 2, // STATUS_FRAME_COMPLETE
|
|
|
|
FLAG_LOAD_COMPLETE = 1u << 3, // STATUS_LOAD_COMPLETE
|
|
|
|
FLAG_ONLOAD_BLOCKED = 1u << 4,
|
|
|
|
FLAG_ONLOAD_UNBLOCKED = 1u << 5,
|
|
|
|
FLAG_IS_ANIMATED = 1u << 6, // STATUS_IS_ANIMATED
|
|
|
|
FLAG_HAS_TRANSPARENCY = 1u << 7, // STATUS_HAS_TRANSPARENCY
|
|
|
|
FLAG_LAST_PART_COMPLETE = 1u << 8,
|
|
|
|
FLAG_HAS_ERROR = 1u << 9 // STATUS_ERROR
|
2014-11-07 04:33:57 +03:00
|
|
|
};
|
|
|
|
|
2014-11-15 07:10:47 +03:00
|
|
|
typedef uint32_t Progress;
|
2013-08-29 02:39:04 +04:00
|
|
|
|
2014-11-15 07:10:47 +03:00
|
|
|
const uint32_t NoProgress = 0;
|
2014-11-15 07:06:19 +03:00
|
|
|
|
2014-11-18 01:29:56 +03:00
|
|
|
inline Progress LoadCompleteProgress(bool aLastPart,
|
|
|
|
bool aError,
|
|
|
|
nsresult aStatus)
|
2014-11-15 07:10:47 +03:00
|
|
|
{
|
2014-11-18 01:29:56 +03:00
|
|
|
Progress progress = FLAG_LOAD_COMPLETE;
|
2014-11-15 07:10:47 +03:00
|
|
|
if (aLastPart) {
|
2014-11-18 01:29:56 +03:00
|
|
|
progress |= FLAG_LAST_PART_COMPLETE;
|
2013-08-29 02:39:04 +04:00
|
|
|
}
|
2014-11-15 07:10:47 +03:00
|
|
|
if (NS_FAILED(aStatus) || aError) {
|
|
|
|
progress |= FLAG_HAS_ERROR;
|
2013-08-29 02:39:04 +04:00
|
|
|
}
|
2014-11-15 07:10:47 +03:00
|
|
|
return progress;
|
|
|
|
}
|
2013-08-29 02:39:04 +04:00
|
|
|
|
2015-08-26 02:26:43 +03:00
|
|
|
/**
|
|
|
|
* ProgressTracker stores its observers in an ObserverTable, which is a hash
|
|
|
|
* table mapping raw pointers to WeakPtr's to the same objects. This sounds like
|
|
|
|
* unnecessary duplication of information, but it's necessary for stable hash
|
|
|
|
* values since WeakPtr's lose the knowledge of which object they used to point
|
|
|
|
* to when that object is destroyed.
|
|
|
|
*
|
|
|
|
* ObserverTable subclasses nsDataHashtable to add reference counting support
|
|
|
|
* and a copy constructor, both of which are needed for use with CopyOnWrite<T>.
|
|
|
|
*/
|
|
|
|
class ObserverTable
|
|
|
|
: public nsDataHashtable<nsPtrHashKey<IProgressObserver>,
|
|
|
|
WeakPtr<IProgressObserver>>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
NS_INLINE_DECL_REFCOUNTING(ObserverTable);
|
|
|
|
|
|
|
|
ObserverTable() = default;
|
|
|
|
|
|
|
|
ObserverTable(const ObserverTable& aOther)
|
|
|
|
{
|
|
|
|
NS_WARNING("Forced to copy ObserverTable due to nested notifications");
|
|
|
|
for (auto iter = aOther.ConstIter(); !iter.Done(); iter.Next()) {
|
|
|
|
this->Put(iter.Key(), iter.Data());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
~ObserverTable() { }
|
|
|
|
};
|
|
|
|
|
2014-11-15 07:10:47 +03:00
|
|
|
/**
|
|
|
|
* ProgressTracker is a class that records an Image's progress through the
|
|
|
|
* loading and decoding process, and makes it possible to send notifications to
|
2015-01-07 12:35:20 +03:00
|
|
|
* IProgressObservers, both synchronously and asynchronously.
|
2010-07-29 01:52:14 +04:00
|
|
|
*
|
2015-01-07 12:35:20 +03:00
|
|
|
* When a new observer needs to be notified of the current progress of an image,
|
|
|
|
* call the Notify() method on this class with the relevant observer as its
|
|
|
|
* argument, and the notifications will be replayed to the observer
|
|
|
|
* asynchronously.
|
2010-05-15 00:47:59 +04:00
|
|
|
*/
|
2014-11-15 07:10:47 +03:00
|
|
|
class ProgressTracker : public mozilla::SupportsWeakPtr<ProgressTracker>
|
2010-05-15 00:47:59 +04:00
|
|
|
{
|
2014-11-15 07:10:47 +03:00
|
|
|
virtual ~ProgressTracker() { }
|
2014-06-19 06:29:00 +04:00
|
|
|
|
2010-05-15 00:47:59 +04:00
|
|
|
public:
|
2015-04-24 19:43:01 +03:00
|
|
|
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(ProgressTracker)
|
2014-11-15 07:10:47 +03:00
|
|
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ProgressTracker)
|
2013-03-02 03:17:24 +04:00
|
|
|
|
2015-01-07 12:37:20 +03:00
|
|
|
ProgressTracker()
|
2015-05-01 04:13:14 +03:00
|
|
|
: mImageMutex("ProgressTracker::mImage")
|
|
|
|
, mImage(nullptr)
|
2015-08-26 02:26:43 +03:00
|
|
|
, mObservers(new ObserverTable)
|
2014-11-15 07:10:47 +03:00
|
|
|
, mProgress(NoProgress)
|
2016-12-04 01:07:10 +03:00
|
|
|
, mIsMultipart(false)
|
2014-11-15 07:06:19 +03:00
|
|
|
{ }
|
2010-05-15 00:47:59 +04:00
|
|
|
|
2015-05-01 04:13:14 +03:00
|
|
|
bool HasImage() const { MutexAutoLock lock(mImageMutex); return mImage; }
|
2014-11-15 07:10:47 +03:00
|
|
|
already_AddRefed<Image> GetImage() const
|
2014-11-15 07:10:47 +03:00
|
|
|
{
|
2015-05-01 04:13:14 +03:00
|
|
|
MutexAutoLock lock(mImageMutex);
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Image> image = mImage;
|
2014-11-15 07:10:47 +03:00
|
|
|
return image.forget();
|
|
|
|
}
|
2013-09-28 22:28:44 +04:00
|
|
|
|
2014-11-15 07:10:47 +03:00
|
|
|
// Get the current image status (as in imgIRequest).
|
|
|
|
uint32_t GetImageStatus() const;
|
|
|
|
|
2014-11-25 10:42:43 +03:00
|
|
|
// Get the current Progress.
|
|
|
|
Progress GetProgress() const { return mProgress; }
|
2014-12-06 02:58:00 +03:00
|
|
|
|
2010-07-29 01:52:14 +04:00
|
|
|
// Schedule an asynchronous "replaying" of all the notifications that would
|
|
|
|
// have to happen to put us in the current state.
|
|
|
|
// We will also take note of any notifications that happen between the time
|
2015-01-07 12:35:20 +03:00
|
|
|
// Notify() is called and when we call SyncNotify on |aObserver|, and replay
|
|
|
|
// them as well.
|
|
|
|
// Should be called on the main thread only, since observers and GetURI are
|
|
|
|
// not threadsafe.
|
|
|
|
void Notify(IProgressObserver* aObserver);
|
2010-07-29 01:52:14 +04:00
|
|
|
|
|
|
|
// Schedule an asynchronous "replaying" of all the notifications that would
|
|
|
|
// have to happen to put us in the state we are in right now.
|
|
|
|
// Unlike Notify(), does *not* take into account future notifications.
|
|
|
|
// This is only useful if you do not have an imgRequest, e.g., if you are a
|
|
|
|
// static request returned from imgIRequest::GetStaticRequest().
|
2015-01-07 12:35:20 +03:00
|
|
|
// Should be called on the main thread only, since observers and GetURI are
|
|
|
|
// not threadsafe.
|
|
|
|
void NotifyCurrentState(IProgressObserver* aObserver);
|
2010-07-29 01:52:14 +04:00
|
|
|
|
2010-05-15 00:47:59 +04:00
|
|
|
// "Replay" all of the notifications that would have to happen to put us in
|
|
|
|
// the state we're currently in.
|
2010-07-29 01:52:14 +04:00
|
|
|
// Only use this if you're already servicing an asynchronous call (e.g.
|
|
|
|
// OnStartRequest).
|
2015-01-07 12:35:20 +03:00
|
|
|
// Should be called on the main thread only, since observers and GetURI are
|
|
|
|
// not threadsafe.
|
|
|
|
void SyncNotify(IProgressObserver* aObserver);
|
2010-05-15 00:47:59 +04:00
|
|
|
|
2014-11-15 07:10:47 +03:00
|
|
|
// Get this ProgressTracker ready for a new request. This resets all the
|
2014-11-15 07:10:47 +03:00
|
|
|
// state that doesn't persist between requests.
|
|
|
|
void ResetForNewRequest();
|
|
|
|
|
|
|
|
// Stateless notifications. These are dispatched and immediately forgotten
|
2015-03-24 05:37:45 +03:00
|
|
|
// about. All of these notifications are main thread only.
|
2014-11-15 07:10:47 +03:00
|
|
|
void OnDiscard();
|
|
|
|
void OnUnlockedDraw();
|
|
|
|
void OnImageAvailable();
|
|
|
|
|
2014-11-15 07:10:47 +03:00
|
|
|
// Compute the difference between this our progress and aProgress. This allows
|
|
|
|
// callers to predict whether SyncNotifyProgress will send any notifications.
|
|
|
|
Progress Difference(Progress aProgress) const
|
|
|
|
{
|
|
|
|
return ~mProgress & aProgress;
|
|
|
|
}
|
2014-11-15 07:10:47 +03:00
|
|
|
|
2014-11-15 07:10:47 +03:00
|
|
|
// Update our state to incorporate the changes in aProgress and synchronously
|
|
|
|
// notify our observers.
|
|
|
|
//
|
|
|
|
// Because this may result in recursive notifications, no decoding locks may
|
|
|
|
// be held. Called on the main thread only.
|
|
|
|
void SyncNotifyProgress(Progress aProgress,
|
|
|
|
const nsIntRect& aInvalidRect = nsIntRect());
|
2010-05-15 00:47:59 +04:00
|
|
|
|
2015-01-07 12:35:20 +03:00
|
|
|
// We manage a set of observers that are using an image and thus concerned
|
2014-11-15 07:10:47 +03:00
|
|
|
// with its loading progress. Weak pointers.
|
2015-01-07 12:35:20 +03:00
|
|
|
void AddObserver(IProgressObserver* aObserver);
|
2015-01-07 12:37:20 +03:00
|
|
|
bool RemoveObserver(IProgressObserver* aObserver);
|
2015-08-26 02:26:43 +03:00
|
|
|
uint32_t ObserverCount() const;
|
2012-10-12 20:11:20 +04:00
|
|
|
|
2015-04-29 02:32:02 +03:00
|
|
|
// Resets our weak reference to our image. Image subclasses should call this
|
|
|
|
// in their destructor.
|
|
|
|
void ResetImage();
|
|
|
|
|
2016-12-04 01:07:10 +03:00
|
|
|
// Tell this progress tracker that it is for a multipart image.
|
|
|
|
void SetIsMultipart() { mIsMultipart = true; }
|
|
|
|
|
2010-05-15 00:47:59 +04:00
|
|
|
private:
|
2014-11-15 07:10:47 +03:00
|
|
|
friend class AsyncNotifyRunnable;
|
|
|
|
friend class AsyncNotifyCurrentStateRunnable;
|
2015-04-29 02:32:02 +03:00
|
|
|
friend class ImageFactory;
|
2014-11-15 07:06:19 +03:00
|
|
|
|
2015-01-07 02:35:02 +03:00
|
|
|
ProgressTracker(const ProgressTracker& aOther) = delete;
|
2010-08-12 19:59:28 +04:00
|
|
|
|
2015-04-29 02:32:02 +03:00
|
|
|
// Sets our weak reference to our image. Only ImageFactory should call this.
|
2014-11-15 07:10:47 +03:00
|
|
|
void SetImage(Image* aImage);
|
2014-11-15 07:10:47 +03:00
|
|
|
|
2015-01-07 12:35:20 +03:00
|
|
|
// Send some notifications that would be necessary to make |aObserver| believe
|
2014-11-15 07:10:47 +03:00
|
|
|
// the request is finished downloading and decoding. We only send
|
2015-01-07 12:35:20 +03:00
|
|
|
// FLAG_LOAD_COMPLETE and FLAG_ONLOAD_UNBLOCKED, and only if necessary.
|
2015-01-07 12:37:20 +03:00
|
|
|
void EmulateRequestFinished(IProgressObserver* aObserver);
|
2014-11-15 07:10:47 +03:00
|
|
|
|
2013-09-28 22:28:43 +04:00
|
|
|
// Main thread only because it deals with the observer service.
|
2012-12-20 01:28:54 +04:00
|
|
|
void FireFailureNotification();
|
|
|
|
|
2015-08-26 02:26:43 +03:00
|
|
|
// The runnable, if any, that we've scheduled to deliver async notifications.
|
2014-11-15 07:10:47 +03:00
|
|
|
nsCOMPtr<nsIRunnable> mRunnable;
|
2010-07-29 01:52:14 +04:00
|
|
|
|
2015-05-01 04:13:14 +03:00
|
|
|
// mImage is a weak ref; it should be set to null when the image goes out of
|
|
|
|
// scope. mImageMutex protects mImage.
|
|
|
|
mutable Mutex mImageMutex;
|
2014-11-15 07:10:47 +03:00
|
|
|
Image* mImage;
|
2012-10-12 20:11:20 +04:00
|
|
|
|
2015-08-26 02:26:43 +03:00
|
|
|
// Hashtable of observers attached to the image. Each observer represents a
|
|
|
|
// consumer using the image. Main thread only.
|
|
|
|
CopyOnWrite<ObserverTable> mObservers;
|
2012-10-12 20:11:21 +04:00
|
|
|
|
2014-11-15 07:10:47 +03:00
|
|
|
Progress mProgress;
|
2016-12-04 01:07:10 +03:00
|
|
|
|
|
|
|
// Whether this is a progress tracker for a multipart image.
|
|
|
|
bool mIsMultipart;
|
2010-05-15 00:47:59 +04:00
|
|
|
};
|
|
|
|
|
2014-11-15 07:10:47 +03:00
|
|
|
} // namespace image
|
|
|
|
} // namespace mozilla
|
|
|
|
|
2015-05-15 06:52:05 +03:00
|
|
|
#endif // mozilla_image_ProgressTracker_h
|