Bumping manifests a=b2g-bump
[gecko.git] / image / src / ProgressTracker.h
blob58416a98e9b9e8c575cbc4d882bc1b8de4f3b510
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"
12 #include "nsCOMPtr.h"
13 #include "nsTObserverArray.h"
14 #include "nsThreadUtils.h"
15 #include "nsRect.h"
16 #include "IProgressObserver.h"
18 class imgIContainer;
19 class nsIRunnable;
21 namespace mozilla {
22 namespace image {
24 class AsyncNotifyRunnable;
25 class AsyncNotifyCurrentStateRunnable;
26 class Image;
28 // Image progress bitflags.
29 enum {
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,
48 bool aError,
49 nsresult aStatus)
51 Progress progress = FLAG_LOAD_COMPLETE;
52 if (aLastPart) {
53 progress |= FLAG_LAST_PART_COMPLETE;
55 if (NS_FAILED(aStatus) || aError) {
56 progress |= FLAG_HAS_ERROR;
58 return progress;
61 /**
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
69 * asynchronously.
71 class ProgressTracker : public mozilla::SupportsWeakPtr<ProgressTracker>
73 virtual ~ProgressTracker() { }
75 public:
76 MOZ_DECLARE_REFCOUNTED_TYPENAME(ProgressTracker)
77 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ProgressTracker)
79 ProgressTracker()
80 : mImage(nullptr)
81 , mProgress(NoProgress)
82 { }
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
101 // them as well.
102 // Should be called on the main thread only, since observers and GetURI are
103 // not threadsafe.
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
112 // not threadsafe.
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.
118 // OnStartRequest).
119 // Should be called on the main thread only, since observers and GetURI are
120 // not threadsafe.
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.
129 void OnDiscard();
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);
162 private:
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.
176 void ResetImage();
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.
195 Image* mImage;
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;
202 Progress mProgress;
205 class ProgressTrackerInit
207 public:
208 ProgressTrackerInit(Image* aImage, ProgressTracker* aTracker);
209 ~ProgressTrackerInit();
210 private:
211 ProgressTracker* mTracker;
214 } // namespace image
215 } // namespace mozilla
217 #endif