1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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 ProgressTracker_h__
8 #define ProgressTracker_h__
10 #include "mozilla/RefPtr.h"
11 #include "mozilla/WeakPtr.h"
13 #include "nsTObserverArray.h"
14 #include "nsThreadUtils.h"
16 #include "IProgressObserver.h"
24 class AsyncNotifyRunnable
;
25 class AsyncNotifyCurrentStateRunnable
;
28 // Image progress bitflags.
30 FLAG_SIZE_AVAILABLE
= 1u << 0, // STATUS_SIZE_AVAILABLE
31 FLAG_DECODE_STARTED
= 1u << 1, // STATUS_DECODE_STARTED
32 FLAG_DECODE_COMPLETE
= 1u << 2, // STATUS_DECODE_COMPLETE
33 FLAG_FRAME_COMPLETE
= 1u << 3, // STATUS_FRAME_COMPLETE
34 FLAG_LOAD_COMPLETE
= 1u << 4, // STATUS_LOAD_COMPLETE
35 FLAG_ONLOAD_BLOCKED
= 1u << 5,
36 FLAG_ONLOAD_UNBLOCKED
= 1u << 6,
37 FLAG_IS_ANIMATED
= 1u << 7, // STATUS_IS_ANIMATED
38 FLAG_HAS_TRANSPARENCY
= 1u << 8, // STATUS_HAS_TRANSPARENCY
39 FLAG_LAST_PART_COMPLETE
= 1u << 9,
40 FLAG_HAS_ERROR
= 1u << 10 // STATUS_ERROR
43 typedef uint32_t Progress
;
45 const uint32_t NoProgress
= 0;
47 inline Progress
LoadCompleteProgress(bool aLastPart
,
51 Progress progress
= FLAG_LOAD_COMPLETE
;
53 progress
|= FLAG_LAST_PART_COMPLETE
;
55 if (NS_FAILED(aStatus
) || aError
) {
56 progress
|= FLAG_HAS_ERROR
;
62 * ProgressTracker is a class that records an Image's progress through the
63 * loading and decoding process, and makes it possible to send notifications to
64 * IProgressObservers, both synchronously and asynchronously.
66 * When a new observer needs to be notified of the current progress of an image,
67 * call the Notify() method on this class with the relevant observer as its
68 * argument, and the notifications will be replayed to the observer
71 class ProgressTracker
: public mozilla::SupportsWeakPtr
<ProgressTracker
>
73 virtual ~ProgressTracker() { }
76 MOZ_DECLARE_REFCOUNTED_TYPENAME(ProgressTracker
)
77 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ProgressTracker
)
81 , mProgress(NoProgress
)
84 bool HasImage() const { return mImage
; }
85 already_AddRefed
<Image
> GetImage() const
87 nsRefPtr
<Image
> image
= mImage
;
88 return image
.forget();
91 // Get the current image status (as in imgIRequest).
92 uint32_t GetImageStatus() const;
94 // Get the current Progress.
95 Progress
GetProgress() const { return mProgress
; }
97 // Schedule an asynchronous "replaying" of all the notifications that would
98 // have to happen to put us in the current state.
99 // We will also take note of any notifications that happen between the time
100 // Notify() is called and when we call SyncNotify on |aObserver|, and replay
102 // Should be called on the main thread only, since observers and GetURI are
104 void Notify(IProgressObserver
* aObserver
);
106 // Schedule an asynchronous "replaying" of all the notifications that would
107 // have to happen to put us in the state we are in right now.
108 // Unlike Notify(), does *not* take into account future notifications.
109 // This is only useful if you do not have an imgRequest, e.g., if you are a
110 // static request returned from imgIRequest::GetStaticRequest().
111 // Should be called on the main thread only, since observers and GetURI are
113 void NotifyCurrentState(IProgressObserver
* aObserver
);
115 // "Replay" all of the notifications that would have to happen to put us in
116 // the state we're currently in.
117 // Only use this if you're already servicing an asynchronous call (e.g.
119 // Should be called on the main thread only, since observers and GetURI are
121 void SyncNotify(IProgressObserver
* aObserver
);
123 // Get this ProgressTracker ready for a new request. This resets all the
124 // state that doesn't persist between requests.
125 void ResetForNewRequest();
127 // Stateless notifications. These are dispatched and immediately forgotten
128 // about. All except OnImageAvailable are main thread only.
130 void OnUnlockedDraw();
131 void OnImageAvailable();
133 // Compute the difference between this our progress and aProgress. This allows
134 // callers to predict whether SyncNotifyProgress will send any notifications.
135 Progress
Difference(Progress aProgress
) const
137 return ~mProgress
& aProgress
;
140 // Update our state to incorporate the changes in aProgress and synchronously
141 // notify our observers.
143 // Because this may result in recursive notifications, no decoding locks may
144 // be held. Called on the main thread only.
145 void SyncNotifyProgress(Progress aProgress
,
146 const nsIntRect
& aInvalidRect
= nsIntRect());
148 // We manage a set of observers that are using an image and thus concerned
149 // with its loading progress. Weak pointers.
150 void AddObserver(IProgressObserver
* aObserver
);
151 bool RemoveObserver(IProgressObserver
* aObserver
);
152 size_t ObserverCount() const {
153 MOZ_ASSERT(NS_IsMainThread(), "Use mObservers on main thread only");
154 return mObservers
.Length();
157 // This is intentionally non-general because its sole purpose is to support
158 // some obscure network priority logic in imgRequest. That stuff could
159 // probably be improved, but it's too scary to mess with at the moment.
160 bool FirstObserverIs(IProgressObserver
* aObserver
);
163 typedef nsTObserverArray
<mozilla::WeakPtr
<IProgressObserver
>> ObserverArray
;
164 friend class AsyncNotifyRunnable
;
165 friend class AsyncNotifyCurrentStateRunnable
;
166 friend class ProgressTrackerInit
;
168 ProgressTracker(const ProgressTracker
& aOther
) = delete;
170 // This method should only be called once, and only on an ProgressTracker
171 // that was initialized without an image. ProgressTrackerInit automates this.
172 void SetImage(Image
* aImage
);
174 // Resets our weak reference to our image, for when mImage is about to go out
175 // of scope. ProgressTrackerInit automates this.
178 // Send some notifications that would be necessary to make |aObserver| believe
179 // the request is finished downloading and decoding. We only send
180 // FLAG_LOAD_COMPLETE and FLAG_ONLOAD_UNBLOCKED, and only if necessary.
181 void EmulateRequestFinished(IProgressObserver
* aObserver
);
183 // Main thread only because it deals with the observer service.
184 void FireFailureNotification();
186 // Main thread only, since notifications are expected on the main thread, and
187 // mObservers is not threadsafe.
188 static void SyncNotifyInternal(ObserverArray
& aObservers
,
189 bool aHasImage
, Progress aProgress
,
190 const nsIntRect
& aInvalidRect
);
192 nsCOMPtr
<nsIRunnable
> mRunnable
;
194 // This weak ref should be set null when the image goes out of scope.
197 // List of observers attached to the image. Each observer represents a
198 // consumer using the image. Array and/or individual elements should only be
199 // accessed on the main thread.
200 ObserverArray mObservers
;
205 class ProgressTrackerInit
208 ProgressTrackerInit(Image
* aImage
, ProgressTracker
* aTracker
);
209 ~ProgressTrackerInit();
211 ProgressTracker
* mTracker
;
215 } // namespace mozilla