image/src/imgStatusTracker.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2 *
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef imgStatusTracker_h__
michael@0 8 #define imgStatusTracker_h__
michael@0 9
michael@0 10 class imgDecoderObserver;
michael@0 11 class imgIContainer;
michael@0 12 class imgStatusNotifyRunnable;
michael@0 13 class imgRequestNotifyRunnable;
michael@0 14 class imgStatusTrackerObserver;
michael@0 15 class nsIRunnable;
michael@0 16
michael@0 17 #include "mozilla/RefPtr.h"
michael@0 18 #include "mozilla/WeakPtr.h"
michael@0 19 #include "nsCOMPtr.h"
michael@0 20 #include "nsTObserverArray.h"
michael@0 21 #include "nsThreadUtils.h"
michael@0 22 #include "nsRect.h"
michael@0 23 #include "imgRequestProxy.h"
michael@0 24
michael@0 25 namespace mozilla {
michael@0 26 namespace image {
michael@0 27
michael@0 28 class Image;
michael@0 29
michael@0 30 struct ImageStatusDiff
michael@0 31 {
michael@0 32 ImageStatusDiff()
michael@0 33 : invalidRect()
michael@0 34 , diffState(0)
michael@0 35 , diffImageStatus(0)
michael@0 36 , unblockedOnload(false)
michael@0 37 , unsetDecodeStarted(false)
michael@0 38 , foundError(false)
michael@0 39 , foundIsMultipart(false)
michael@0 40 , foundLastPart(false)
michael@0 41 , gotDecoded(false)
michael@0 42 { }
michael@0 43
michael@0 44 static ImageStatusDiff NoChange() { return ImageStatusDiff(); }
michael@0 45 bool IsNoChange() const { return *this == NoChange(); }
michael@0 46
michael@0 47 bool operator!=(const ImageStatusDiff& aOther) const { return !(*this == aOther); }
michael@0 48 bool operator==(const ImageStatusDiff& aOther) const {
michael@0 49 return aOther.invalidRect == invalidRect
michael@0 50 && aOther.diffState == diffState
michael@0 51 && aOther.diffImageStatus == diffImageStatus
michael@0 52 && aOther.unblockedOnload == unblockedOnload
michael@0 53 && aOther.unsetDecodeStarted == unsetDecodeStarted
michael@0 54 && aOther.foundError == foundError
michael@0 55 && aOther.foundIsMultipart == foundIsMultipart
michael@0 56 && aOther.foundLastPart == foundLastPart
michael@0 57 && aOther.gotDecoded == gotDecoded;
michael@0 58 }
michael@0 59
michael@0 60 void Combine(const ImageStatusDiff& aOther) {
michael@0 61 invalidRect = invalidRect.Union(aOther.invalidRect);
michael@0 62 diffState |= aOther.diffState;
michael@0 63 diffImageStatus |= aOther.diffImageStatus;
michael@0 64 unblockedOnload = unblockedOnload || aOther.unblockedOnload;
michael@0 65 unsetDecodeStarted = unsetDecodeStarted || aOther.unsetDecodeStarted;
michael@0 66 foundError = foundError || aOther.foundError;
michael@0 67 foundIsMultipart = foundIsMultipart || aOther.foundIsMultipart;
michael@0 68 foundLastPart = foundLastPart || aOther.foundLastPart;
michael@0 69 gotDecoded = gotDecoded || aOther.gotDecoded;
michael@0 70 }
michael@0 71
michael@0 72 nsIntRect invalidRect;
michael@0 73 uint32_t diffState;
michael@0 74 uint32_t diffImageStatus;
michael@0 75 bool unblockedOnload : 1;
michael@0 76 bool unsetDecodeStarted : 1;
michael@0 77 bool foundError : 1;
michael@0 78 bool foundIsMultipart : 1;
michael@0 79 bool foundLastPart : 1;
michael@0 80 bool gotDecoded : 1;
michael@0 81 };
michael@0 82
michael@0 83 enum {
michael@0 84 stateRequestStarted = 1u << 0,
michael@0 85 stateHasSize = 1u << 1,
michael@0 86 stateDecodeStarted = 1u << 2,
michael@0 87 stateDecodeStopped = 1u << 3,
michael@0 88 stateFrameStopped = 1u << 4,
michael@0 89 stateRequestStopped = 1u << 5,
michael@0 90 stateBlockingOnload = 1u << 6,
michael@0 91 stateImageIsAnimated = 1u << 7
michael@0 92 };
michael@0 93
michael@0 94 } // namespace image
michael@0 95 } // namespace mozilla
michael@0 96
michael@0 97 /*
michael@0 98 * The image status tracker is a class that encapsulates all the loading and
michael@0 99 * decoding status about an Image, and makes it possible to send notifications
michael@0 100 * to imgRequestProxys, both synchronously (i.e., the status now) and
michael@0 101 * asynchronously (the status later).
michael@0 102 *
michael@0 103 * When a new proxy needs to be notified of the current state of an image, call
michael@0 104 * the Notify() method on this class with the relevant proxy as its argument,
michael@0 105 * and the notifications will be replayed to the proxy asynchronously.
michael@0 106 */
michael@0 107
michael@0 108
michael@0 109 class imgStatusTracker : public mozilla::SupportsWeakPtr<imgStatusTracker>
michael@0 110 {
michael@0 111 public:
michael@0 112 MOZ_DECLARE_REFCOUNTED_TYPENAME(imgStatusTracker)
michael@0 113 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(imgStatusTracker)
michael@0 114
michael@0 115 // aImage is the image that this status tracker will pass to the
michael@0 116 // imgRequestProxys in SyncNotify() and EmulateRequestFinished(), and must be
michael@0 117 // alive as long as this instance is, because we hold a weak reference to it.
michael@0 118 imgStatusTracker(mozilla::image::Image* aImage);
michael@0 119 virtual ~imgStatusTracker();
michael@0 120
michael@0 121 // Image-setter, for imgStatusTrackers created by imgRequest::Init, which
michael@0 122 // are created before their Image is created. This method should only
michael@0 123 // be called once, and only on an imgStatusTracker that was initialized
michael@0 124 // without an image.
michael@0 125 void SetImage(mozilla::image::Image* aImage);
michael@0 126
michael@0 127 // Image resetter, for when mImage is about to go out of scope. mImage is a
michael@0 128 // weak reference, and thus must be set to null when it's object is deleted.
michael@0 129 void ResetImage();
michael@0 130
michael@0 131 // Inform this status tracker that it is associated with a multipart image.
michael@0 132 void SetIsMultipart() { mIsMultipart = true; }
michael@0 133
michael@0 134 // Schedule an asynchronous "replaying" of all the notifications that would
michael@0 135 // have to happen to put us in the current state.
michael@0 136 // We will also take note of any notifications that happen between the time
michael@0 137 // Notify() is called and when we call SyncNotify on |proxy|, and replay them
michael@0 138 // as well.
michael@0 139 // Should be called on the main thread only, since imgRequestProxy and GetURI
michael@0 140 // are not threadsafe.
michael@0 141 void Notify(imgRequestProxy* proxy);
michael@0 142
michael@0 143 // Schedule an asynchronous "replaying" of all the notifications that would
michael@0 144 // have to happen to put us in the state we are in right now.
michael@0 145 // Unlike Notify(), does *not* take into account future notifications.
michael@0 146 // This is only useful if you do not have an imgRequest, e.g., if you are a
michael@0 147 // static request returned from imgIRequest::GetStaticRequest().
michael@0 148 // Should be called on the main thread only, since imgRequestProxy and GetURI
michael@0 149 // are not threadsafe.
michael@0 150 void NotifyCurrentState(imgRequestProxy* proxy);
michael@0 151
michael@0 152 // "Replay" all of the notifications that would have to happen to put us in
michael@0 153 // the state we're currently in.
michael@0 154 // Only use this if you're already servicing an asynchronous call (e.g.
michael@0 155 // OnStartRequest).
michael@0 156 // Should be called on the main thread only, since imgRequestProxy and GetURI
michael@0 157 // are not threadsafe.
michael@0 158 void SyncNotify(imgRequestProxy* proxy);
michael@0 159
michael@0 160 // Send some notifications that would be necessary to make |proxy| believe
michael@0 161 // the request is finished downloading and decoding. We only send
michael@0 162 // OnStopRequest and UnblockOnload, and only if necessary.
michael@0 163 void EmulateRequestFinished(imgRequestProxy* proxy, nsresult aStatus);
michael@0 164
michael@0 165 // We manage a set of consumers that are using an image and thus concerned
michael@0 166 // with its status. Weak pointers.
michael@0 167 void AddConsumer(imgRequestProxy* aConsumer);
michael@0 168 bool RemoveConsumer(imgRequestProxy* aConsumer, nsresult aStatus);
michael@0 169 size_t ConsumerCount() const {
michael@0 170 MOZ_ASSERT(NS_IsMainThread(), "Use mConsumers on main thread only");
michael@0 171 return mConsumers.Length();
michael@0 172 }
michael@0 173
michael@0 174 // This is intentionally non-general because its sole purpose is to support an
michael@0 175 // some obscure network priority logic in imgRequest. That stuff could probably
michael@0 176 // be improved, but it's too scary to mess with at the moment.
michael@0 177 bool FirstConsumerIs(imgRequestProxy* aConsumer);
michael@0 178
michael@0 179 void AdoptConsumers(imgStatusTracker* aTracker) {
michael@0 180 MOZ_ASSERT(NS_IsMainThread(), "Use mConsumers on main thread only");
michael@0 181 MOZ_ASSERT(aTracker);
michael@0 182 mConsumers = aTracker->mConsumers;
michael@0 183 }
michael@0 184
michael@0 185 // Returns whether we are in the process of loading; that is, whether we have
michael@0 186 // not received OnStopRequest.
michael@0 187 bool IsLoading() const;
michael@0 188
michael@0 189 // Get the current image status (as in imgIRequest).
michael@0 190 uint32_t GetImageStatus() const;
michael@0 191
michael@0 192 // Following are all the notification methods. You must call the Record
michael@0 193 // variant on this status tracker, then call the Send variant for each proxy
michael@0 194 // you want to notify.
michael@0 195
michael@0 196 // Call when the request is being cancelled.
michael@0 197 void RecordCancel();
michael@0 198
michael@0 199 // Shorthand for recording all the load notifications: StartRequest,
michael@0 200 // StartContainer, StopRequest.
michael@0 201 void RecordLoaded();
michael@0 202
michael@0 203 // Shorthand for recording all the decode notifications: StartDecode,
michael@0 204 // StartFrame, DataAvailable, StopFrame, StopDecode.
michael@0 205 void RecordDecoded();
michael@0 206
michael@0 207 /* non-virtual imgDecoderObserver methods */
michael@0 208 // Functions with prefix Send- are main thread only, since they contain calls
michael@0 209 // to imgRequestProxy functions, which are expected on the main thread.
michael@0 210 void RecordStartDecode();
michael@0 211 void SendStartDecode(imgRequestProxy* aProxy);
michael@0 212 void RecordStartContainer(imgIContainer* aContainer);
michael@0 213 void SendStartContainer(imgRequestProxy* aProxy);
michael@0 214 void RecordStartFrame();
michael@0 215 // No SendStartFrame since it's not observed below us.
michael@0 216 void RecordFrameChanged(const nsIntRect* aDirtyRect);
michael@0 217 void SendFrameChanged(imgRequestProxy* aProxy, const nsIntRect* aDirtyRect);
michael@0 218 void RecordStopFrame();
michael@0 219 void SendStopFrame(imgRequestProxy* aProxy);
michael@0 220 void RecordStopDecode(nsresult statusg);
michael@0 221 void SendStopDecode(imgRequestProxy* aProxy, nsresult aStatus);
michael@0 222 void RecordDiscard();
michael@0 223 void SendDiscard(imgRequestProxy* aProxy);
michael@0 224 void RecordUnlockedDraw();
michael@0 225 void SendUnlockedDraw(imgRequestProxy* aProxy);
michael@0 226 void RecordImageIsAnimated();
michael@0 227 void SendImageIsAnimated(imgRequestProxy *aProxy);
michael@0 228
michael@0 229 /* non-virtual sort-of-nsIRequestObserver methods */
michael@0 230 // Functions with prefix Send- are main thread only, since they contain calls
michael@0 231 // to imgRequestProxy functions, which are expected on the main thread.
michael@0 232 void RecordStartRequest();
michael@0 233 void SendStartRequest(imgRequestProxy* aProxy);
michael@0 234 void RecordStopRequest(bool aLastPart, nsresult aStatus);
michael@0 235 void SendStopRequest(imgRequestProxy* aProxy, bool aLastPart, nsresult aStatus);
michael@0 236
michael@0 237 // All main thread only because they call functions (like SendStartRequest)
michael@0 238 // which are expected to be called on the main thread.
michael@0 239 void OnStartRequest();
michael@0 240 // OnDataAvailable will dispatch a call to itself onto the main thread if not
michael@0 241 // called there.
michael@0 242 void OnDataAvailable();
michael@0 243 void OnStopRequest(bool aLastPart, nsresult aStatus);
michael@0 244 void OnDiscard();
michael@0 245 void FrameChanged(const nsIntRect* aDirtyRect);
michael@0 246 void OnUnlockedDraw();
michael@0 247 // This is called only by VectorImage, and only to ensure tests work
michael@0 248 // properly. Do not use it.
michael@0 249 void OnStopFrame();
michael@0 250
michael@0 251 /* non-virtual imgIOnloadBlocker methods */
michael@0 252 // NB: If UnblockOnload is sent, and then we are asked to replay the
michael@0 253 // notifications, we will not send a BlockOnload/UnblockOnload pair. This
michael@0 254 // is different from all the other notifications.
michael@0 255 void RecordBlockOnload();
michael@0 256 void SendBlockOnload(imgRequestProxy* aProxy);
michael@0 257 void RecordUnblockOnload();
michael@0 258 void SendUnblockOnload(imgRequestProxy* aProxy);
michael@0 259
michael@0 260 // Main thread only because mConsumers is not threadsafe.
michael@0 261 void MaybeUnblockOnload();
michael@0 262
michael@0 263 void RecordError();
michael@0 264
michael@0 265 bool IsMultipart() const { return mIsMultipart; }
michael@0 266
michael@0 267 // Weak pointer getters - no AddRefs.
michael@0 268 inline already_AddRefed<mozilla::image::Image> GetImage() const {
michael@0 269 nsRefPtr<mozilla::image::Image> image = mImage;
michael@0 270 return image.forget();
michael@0 271 }
michael@0 272 inline bool HasImage() { return mImage; }
michael@0 273
michael@0 274 inline imgDecoderObserver* GetDecoderObserver() { return mTrackerObserver.get(); }
michael@0 275
michael@0 276 already_AddRefed<imgStatusTracker> CloneForRecording();
michael@0 277
michael@0 278 // Compute the difference between this status tracker and aOther.
michael@0 279 mozilla::image::ImageStatusDiff Difference(imgStatusTracker* aOther) const;
michael@0 280
michael@0 281 // Captures all of the decode notifications (i.e., not OnStartRequest /
michael@0 282 // OnStopRequest) so far as an ImageStatusDiff.
michael@0 283 mozilla::image::ImageStatusDiff DecodeStateAsDifference() const;
michael@0 284
michael@0 285 // Update our state to incorporate the changes in aDiff.
michael@0 286 void ApplyDifference(const mozilla::image::ImageStatusDiff& aDiff);
michael@0 287
michael@0 288 // Notify for the changes captured in an ImageStatusDiff. Because this may
michael@0 289 // result in recursive notifications, no decoding locks may be held.
michael@0 290 // Called on the main thread only.
michael@0 291 void SyncNotifyDifference(const mozilla::image::ImageStatusDiff& aDiff);
michael@0 292
michael@0 293 nsIntRect GetInvalidRect() const { return mInvalidRect; }
michael@0 294
michael@0 295 private:
michael@0 296 typedef nsTObserverArray<mozilla::WeakPtr<imgRequestProxy>> ProxyArray;
michael@0 297 friend class imgStatusNotifyRunnable;
michael@0 298 friend class imgRequestNotifyRunnable;
michael@0 299 friend class imgStatusTrackerObserver;
michael@0 300 friend class imgStatusTrackerInit;
michael@0 301 imgStatusTracker(const imgStatusTracker& aOther);
michael@0 302
michael@0 303 // Main thread only because it deals with the observer service.
michael@0 304 void FireFailureNotification();
michael@0 305
michael@0 306 // Main thread only, since imgRequestProxy calls are expected on the main
michael@0 307 // thread, and mConsumers is not threadsafe.
michael@0 308 static void SyncNotifyState(ProxyArray& proxies,
michael@0 309 bool hasImage, uint32_t state,
michael@0 310 nsIntRect& dirtyRect, bool hadLastPart);
michael@0 311
michael@0 312 nsCOMPtr<nsIRunnable> mRequestRunnable;
michael@0 313
michael@0 314 // The invalid area of the most recent frame we know about. (All previous
michael@0 315 // frames are assumed to be fully valid.)
michael@0 316 nsIntRect mInvalidRect;
michael@0 317
michael@0 318 // This weak ref should be set null when the image goes out of scope.
michael@0 319 mozilla::image::Image* mImage;
michael@0 320
michael@0 321 // List of proxies attached to the image. Each proxy represents a consumer
michael@0 322 // using the image. Array and/or individual elements should only be accessed
michael@0 323 // on the main thread.
michael@0 324 ProxyArray mConsumers;
michael@0 325
michael@0 326 mozilla::RefPtr<imgDecoderObserver> mTrackerObserver;
michael@0 327
michael@0 328 uint32_t mState;
michael@0 329 uint32_t mImageStatus;
michael@0 330 bool mIsMultipart : 1;
michael@0 331 bool mHadLastPart : 1;
michael@0 332 bool mHasBeenDecoded : 1;
michael@0 333 };
michael@0 334
michael@0 335 class imgStatusTrackerInit
michael@0 336 {
michael@0 337 public:
michael@0 338 imgStatusTrackerInit(mozilla::image::Image* aImage,
michael@0 339 imgStatusTracker* aTracker);
michael@0 340 ~imgStatusTrackerInit();
michael@0 341 private:
michael@0 342 imgStatusTracker* mTracker;
michael@0 343 };
michael@0 344
michael@0 345 #endif

mercurial