Bug 905002: backout bug 879717 until we can fix the mac-only regression rs=roc
[gecko.git] / image / src / imgStatusTracker.h
blob6bcc36fee7fb620671bdbfd01cec17fb9f39b231
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 imgStatusTracker_h__
8 #define imgStatusTracker_h__
10 class imgIContainer;
11 class imgRequestProxy;
12 class imgStatusNotifyRunnable;
13 class imgRequestNotifyRunnable;
14 class imgStatusTrackerObserver;
15 class imgStatusTrackerNotifyingObserver;
16 struct nsIntRect;
17 namespace mozilla {
18 namespace image {
19 class Image;
20 } // namespace image
21 } // namespace mozilla
24 #include "mozilla/RefPtr.h"
25 #include "nsCOMPtr.h"
26 #include "nsTObserverArray.h"
27 #include "nsIRunnable.h"
28 #include "nscore.h"
29 #include "imgDecoderObserver.h"
30 #include "nsISupportsImpl.h"
32 enum {
33 stateRequestStarted = 1u << 0,
34 stateHasSize = 1u << 1,
35 stateDecodeStarted = 1u << 2,
36 stateDecodeStopped = 1u << 3,
37 stateFrameStopped = 1u << 4,
38 stateRequestStopped = 1u << 5,
39 stateBlockingOnload = 1u << 6,
40 stateImageIsAnimated = 1u << 7
44 * The image status tracker is a class that encapsulates all the loading and
45 * decoding status about an Image, and makes it possible to send notifications
46 * to imgRequestProxys, both synchronously (i.e., the status now) and
47 * asynchronously (the status later).
49 * When a new proxy needs to be notified of the current state of an image, call
50 * the Notify() method on this class with the relevant proxy as its argument,
51 * and the notifications will be replayed to the proxy asynchronously.
54 class imgStatusTracker
56 public:
57 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(imgStatusTracker)
59 // aImage is the image that this status tracker will pass to the
60 // imgRequestProxys in SyncNotify() and EmulateRequestFinished(), and must be
61 // alive as long as this instance is, because we hold a weak reference to it.
62 imgStatusTracker(mozilla::image::Image* aImage);
63 ~imgStatusTracker();
65 // Image-setter, for imgStatusTrackers created by imgRequest::Init, which
66 // are created before their Image is created. This method should only
67 // be called once, and only on an imgStatusTracker that was initialized
68 // without an image.
69 void SetImage(mozilla::image::Image* aImage);
71 // Inform this status tracker that it is associated with a multipart image.
72 void SetIsMultipart() { mIsMultipart = true; }
74 // Schedule an asynchronous "replaying" of all the notifications that would
75 // have to happen to put us in the current state.
76 // We will also take note of any notifications that happen between the time
77 // Notify() is called and when we call SyncNotify on |proxy|, and replay them
78 // as well.
79 void Notify(imgRequestProxy* proxy);
81 // Schedule an asynchronous "replaying" of all the notifications that would
82 // have to happen to put us in the state we are in right now.
83 // Unlike Notify(), does *not* take into account future notifications.
84 // This is only useful if you do not have an imgRequest, e.g., if you are a
85 // static request returned from imgIRequest::GetStaticRequest().
86 void NotifyCurrentState(imgRequestProxy* proxy);
88 // "Replay" all of the notifications that would have to happen to put us in
89 // the state we're currently in.
90 // Only use this if you're already servicing an asynchronous call (e.g.
91 // OnStartRequest).
92 void SyncNotify(imgRequestProxy* proxy);
94 // "Replays" all of the decode notifications (i.e., not
95 // OnStartRequest/OnStopRequest) that have happened to us to all of our
96 // non-deferred proxies.
97 void SyncNotifyDecodeState();
99 // Send some notifications that would be necessary to make |proxy| believe
100 // the request is finished downloading and decoding. We only send
101 // OnStopRequest and UnblockOnload, and only if necessary.
102 void EmulateRequestFinished(imgRequestProxy* proxy, nsresult aStatus);
104 // We manage a set of consumers that are using an image and thus concerned
105 // with its status. Weak pointers.
106 void AddConsumer(imgRequestProxy* aConsumer);
107 bool RemoveConsumer(imgRequestProxy* aConsumer, nsresult aStatus);
108 size_t ConsumerCount() const { return mConsumers.Length(); }
110 // This is intentionally non-general because its sole purpose is to support an
111 // some obscure network priority logic in imgRequest. That stuff could probably
112 // be improved, but it's too scary to mess with at the moment.
113 bool FirstConsumerIs(imgRequestProxy* aConsumer) {
114 return mConsumers.SafeElementAt(0, nullptr) == aConsumer;
117 void AdoptConsumers(imgStatusTracker* aTracker) { mConsumers = aTracker->mConsumers; }
119 // Returns whether we are in the process of loading; that is, whether we have
120 // not received OnStopRequest.
121 bool IsLoading() const;
123 // Get the current image status (as in imgIRequest).
124 uint32_t GetImageStatus() const;
126 // Following are all the notification methods. You must call the Record
127 // variant on this status tracker, then call the Send variant for each proxy
128 // you want to notify.
130 // Call when the request is being cancelled.
131 void RecordCancel();
133 // Shorthand for recording all the load notifications: StartRequest,
134 // StartContainer, StopRequest.
135 void RecordLoaded();
137 // Shorthand for recording all the decode notifications: StartDecode,
138 // StartFrame, DataAvailable, StopFrame, StopDecode.
139 void RecordDecoded();
141 /* non-virtual imgDecoderObserver methods */
142 void RecordStartDecode();
143 void SendStartDecode(imgRequestProxy* aProxy);
144 void RecordStartContainer(imgIContainer* aContainer);
145 void SendStartContainer(imgRequestProxy* aProxy);
146 void RecordStartFrame();
147 // No SendStartFrame since it's not observed below us.
148 void RecordFrameChanged(const nsIntRect* aDirtyRect);
149 void SendFrameChanged(imgRequestProxy* aProxy, const nsIntRect* aDirtyRect);
150 void RecordStopFrame();
151 void SendStopFrame(imgRequestProxy* aProxy);
152 void RecordStopDecode(nsresult statusg);
153 void SendStopDecode(imgRequestProxy* aProxy, nsresult aStatus);
154 void RecordDiscard();
155 void SendDiscard(imgRequestProxy* aProxy);
156 void RecordUnlockedDraw();
157 void SendUnlockedDraw(imgRequestProxy* aProxy);
158 void RecordImageIsAnimated();
159 void SendImageIsAnimated(imgRequestProxy *aProxy);
161 /* non-virtual sort-of-nsIRequestObserver methods */
162 void RecordStartRequest();
163 void SendStartRequest(imgRequestProxy* aProxy);
164 void RecordStopRequest(bool aLastPart, nsresult aStatus);
165 void SendStopRequest(imgRequestProxy* aProxy, bool aLastPart, nsresult aStatus);
167 void OnStartRequest();
168 void OnDataAvailable();
169 void OnStopRequest(bool aLastPart, nsresult aStatus);
170 void OnDiscard();
171 void FrameChanged(const nsIntRect* aDirtyRect);
172 void OnUnlockedDraw();
173 // This is called only by VectorImage, and only to ensure tests work
174 // properly. Do not use it.
175 void OnStopFrame();
177 /* non-virtual imgIOnloadBlocker methods */
178 // NB: If UnblockOnload is sent, and then we are asked to replay the
179 // notifications, we will not send a BlockOnload/UnblockOnload pair. This
180 // is different from all the other notifications.
181 void RecordBlockOnload();
182 void SendBlockOnload(imgRequestProxy* aProxy);
183 void RecordUnblockOnload();
184 void SendUnblockOnload(imgRequestProxy* aProxy);
186 void MaybeUnblockOnload();
188 void RecordError();
190 bool IsMultipart() const { return mIsMultipart; }
192 // Weak pointer getters - no AddRefs.
193 inline mozilla::image::Image* GetImage() const { return mImage; }
195 inline imgDecoderObserver* GetDecoderObserver() { return mTrackerObserver.get(); }
197 imgStatusTracker* CloneForRecording();
199 struct StatusDiff
201 uint32_t mDiffState;
202 bool mUnblockedOnload;
203 bool mFoundError;
204 nsIntRect mInvalidRect;
207 // Calculate the difference between this and other, apply that difference to
208 // ourselves, and return it for passing to SyncNotifyDifference.
209 StatusDiff CalculateAndApplyDifference(imgStatusTracker* other);
211 // Notify for the difference found in CalculateAndApplyDifference. No
212 // decoding locks may be held.
213 void SyncNotifyDifference(StatusDiff diff);
215 nsIntRect GetInvalidRect() const { return mInvalidRect; }
217 private:
218 friend class imgStatusNotifyRunnable;
219 friend class imgRequestNotifyRunnable;
220 friend class imgStatusTrackerObserver;
221 friend class imgStatusTrackerNotifyingObserver;
222 imgStatusTracker(const imgStatusTracker& aOther);
224 void FireFailureNotification();
226 static void SyncNotifyState(nsTObserverArray<imgRequestProxy*>& proxies,
227 bool hasImage, uint32_t state,
228 nsIntRect& dirtyRect, bool hadLastPart);
230 nsCOMPtr<nsIRunnable> mRequestRunnable;
232 // The invalid area of the most recent frame we know about. (All previous
233 // frames are assumed to be fully valid.)
234 nsIntRect mInvalidRect;
236 // Weak pointer to the image. The image owns the status tracker.
237 mozilla::image::Image* mImage;
239 // List of proxies attached to the image. Each proxy represents a consumer
240 // using the image.
241 nsTObserverArray<imgRequestProxy*> mConsumers;
243 mozilla::RefPtr<imgDecoderObserver> mTrackerObserver;
245 uint32_t mState;
246 uint32_t mImageStatus;
247 bool mIsMultipart : 1;
248 bool mHadLastPart : 1;
249 bool mHasBeenDecoded : 1;
252 #endif