Bug 867755 - Return already_AddRefed from GetStatusTracker instead of C++ ref r=seth
authorSteve Workman <sworkman@mozilla.com>
Sat, 28 Sep 2013 11:28:44 -0700
changeset 149162 22c38ee36fe9c1f440b3965261a1dde7b1a95ed6
parent 149161 5d8f3119bad7189ab2358fca97466e966a209b55
child 149163 5df5c70b3002a3fc8aaef6171cb7435b89bb9b68
push id25374
push usercbook@mozilla.com
push dateSun, 29 Sep 2013 09:37:16 +0000
treeherdermozilla-central@8f805d3ef377 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersseth
bugs867755
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 867755 - Return already_AddRefed from GetStatusTracker instead of C++ ref r=seth
image/src/ClippedImage.cpp
image/src/Image.h
image/src/ImageWrapper.cpp
image/src/ImageWrapper.h
image/src/RasterImage.cpp
image/src/RasterImage.h
image/src/imgRequest.cpp
image/src/imgRequest.h
image/src/imgRequestProxy.cpp
image/src/imgRequestProxy.h
image/src/imgStatusTracker.cpp
image/src/imgStatusTracker.h
--- a/image/src/ClippedImage.cpp
+++ b/image/src/ClippedImage.cpp
@@ -118,28 +118,31 @@ bool
 ClippedImage::ShouldClip()
 {
   // We need to evaluate the clipping region against the image's width and height
   // once they're available to determine if it's valid and whether we actually
   // need to do any work. We may fail if the image's width and height aren't
   // available yet, in which case we'll try again later.
   if (mShouldClip.empty()) {
     int32_t width, height;
+    nsRefPtr<imgStatusTracker> innerImageStatusTracker =
+      InnerImage()->GetStatusTracker();
     if (InnerImage()->HasError()) {
       // If there's a problem with the inner image we'll let it handle everything.
       mShouldClip.construct(false);
     } else if (NS_SUCCEEDED(InnerImage()->GetWidth(&width)) && width > 0 &&
                NS_SUCCEEDED(InnerImage()->GetHeight(&height)) && height > 0) {
       // Clamp the clipping region to the size of the underlying image.
       mClip = mClip.Intersect(nsIntRect(0, 0, width, height));
 
       // If the clipping region is the same size as the underlying image we
       // don't have to do anything.
       mShouldClip.construct(!mClip.IsEqualInterior(nsIntRect(0, 0, width, height)));
-    } else if (InnerImage()->GetStatusTracker().IsLoading()) {
+    } else if (innerImageStatusTracker &&
+               innerImageStatusTracker->IsLoading()) {
       // The image just hasn't finished loading yet. We don't yet know whether
       // clipping with be needed or not for now. Just return without memoizing
       // anything.
       return false;
     } else {
       // We have a fully loaded image without a clearly defined width and
       // height. This can happen with SVG images.
       mShouldClip.construct(false);
--- a/image/src/Image.h
+++ b/image/src/Image.h
@@ -57,17 +57,17 @@ public:
    * Creates a new image container.
    *
    * @param aMimeType The mimetype of the image.
    * @param aFlags Initialization flags of the INIT_FLAG_* variety.
    */
   virtual nsresult Init(const char* aMimeType,
                         uint32_t aFlags) = 0;
 
-  virtual imgStatusTracker& GetStatusTracker() = 0;
+  virtual already_AddRefed<imgStatusTracker> GetStatusTracker() = 0;
 
   /**
    * The rectangle defining the location and size of the given frame.
    */
   virtual nsIntRect FrameRect(uint32_t aWhichFrame) = 0;
 
   /**
    * The size, in bytes, occupied by the significant data portions of the image.
@@ -132,17 +132,21 @@ public:
   virtual void SetHasError() = 0;
 
   virtual ImageURL* GetURI() = 0;
 };
 
 class ImageResource : public Image
 {
 public:
-  virtual imgStatusTracker& GetStatusTracker() MOZ_OVERRIDE { return *mStatusTracker; }
+  virtual already_AddRefed<imgStatusTracker> GetStatusTracker() MOZ_OVERRIDE {
+    nsRefPtr<imgStatusTracker> statusTracker = mStatusTracker;
+    MOZ_ASSERT(statusTracker);
+    return statusTracker.forget();
+  }
   virtual uint32_t SizeOfData() MOZ_OVERRIDE;
 
   virtual void IncrementAnimationConsumers() MOZ_OVERRIDE;
   virtual void DecrementAnimationConsumers() MOZ_OVERRIDE;
 #ifdef DEBUG
   virtual uint32_t GetAnimationConsumers() MOZ_OVERRIDE { return mAnimationConsumers; }
 #endif
 
--- a/image/src/ImageWrapper.cpp
+++ b/image/src/ImageWrapper.cpp
@@ -17,17 +17,17 @@ namespace image {
 // Inherited methods from Image.
 
 nsresult
 ImageWrapper::Init(const char* aMimeType, uint32_t aFlags)
 {
   return mInnerImage->Init(aMimeType, aFlags);
 }
 
-imgStatusTracker&
+already_AddRefed<imgStatusTracker>
 ImageWrapper::GetStatusTracker()
 {
   return mInnerImage->GetStatusTracker();
 }
 
 nsIntRect
 ImageWrapper::FrameRect(uint32_t aWhichFrame)
 {
--- a/image/src/ImageWrapper.h
+++ b/image/src/ImageWrapper.h
@@ -21,17 +21,17 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_IMGICONTAINER
 
   virtual ~ImageWrapper() { }
 
   // Inherited methods from Image.
   virtual nsresult Init(const char* aMimeType, uint32_t aFlags) MOZ_OVERRIDE;
 
-  virtual imgStatusTracker& GetStatusTracker() MOZ_OVERRIDE;
+  virtual already_AddRefed<imgStatusTracker> GetStatusTracker() MOZ_OVERRIDE;
   virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE;
 
   virtual uint32_t SizeOfData() MOZ_OVERRIDE;
   virtual size_t HeapSizeOfSourceWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
   virtual size_t HeapSizeOfDecodedWithComputedFallback(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
   virtual size_t NonHeapSizeOfDecoded() const MOZ_OVERRIDE;
   virtual size_t OutOfProcessSizeOfDecoded() const MOZ_OVERRIDE;
 
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -1078,17 +1078,18 @@ RasterImage::EnsureAnimExists()
     // data too. However, doing this is actually hard, because we're probably
     // calling ensureAnimExists mid-decode, and thus we're decoding out of
     // the source buffer. Since we're going to fix this anyway later, and
     // since we didn't kill the source data in the old world either, locking
     // is acceptable for the moment.
     LockImage();
 
     // Notify our observers that we are starting animation.
-    CurrentStatusTracker().RecordImageIsAnimated();
+    nsRefPtr<imgStatusTracker> statusTracker = CurrentStatusTracker();
+    statusTracker->RecordImageIsAnimated();
   }
 }
 
 nsresult
 RasterImage::InternalAddFrameHelper(uint32_t framenum, imgFrame *aFrame,
                                     uint8_t **imageData, uint32_t *imageLength,
                                     uint32_t **paletteData, uint32_t *paletteLength,
                                     imgFrame** aRetFrame)
@@ -1720,21 +1721,18 @@ nsresult
 RasterImage::OnImageDataComplete(nsIRequest*, nsISupports*, nsresult aStatus, bool aLastPart)
 {
   nsresult finalStatus = DoImageDataComplete();
 
   // Give precedence to Necko failure codes.
   if (NS_FAILED(aStatus))
     finalStatus = aStatus;
 
-  if (mDecodeRequest) {
-    mDecodeRequest->mStatusTracker->GetDecoderObserver()->OnStopRequest(aLastPart, finalStatus);
-  } else {
-    mStatusTracker->GetDecoderObserver()->OnStopRequest(aLastPart, finalStatus);
-  }
+  nsRefPtr<imgStatusTracker> statusTracker = CurrentStatusTracker();
+  statusTracker->GetDecoderObserver()->OnStopRequest(aLastPart, finalStatus);
 
   // We just recorded OnStopRequest; we need to inform our listeners.
   {
     MutexAutoLock lock(mDecodingMutex);
     FinishedSomeDecoding();
   }
 
   return finalStatus;
@@ -2015,16 +2013,18 @@ RasterImage::InitDecoder(bool aDoSizeDec
     imgFrame *curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1);
     curframe->LockImageData();
   }
 
   // Initialize the decoder
   if (!mDecodeRequest) {
     mDecodeRequest = new DecodeRequest(this);
   }
+  MOZ_ASSERT(mDecodeRequest->mStatusTracker);
+  MOZ_ASSERT(mDecodeRequest->mStatusTracker->GetDecoderObserver());
   mDecoder->SetObserver(mDecodeRequest->mStatusTracker->GetDecoderObserver());
   mDecoder->SetSizeDecode(aDoSizeDecode);
   mDecoder->SetDecodeFlags(mFrameDecodeFlags);
   mDecoder->SetSynchronous(aIsSynchronous);
   if (!aDoSizeDecode) {
     // We already have the size; tell the decoder so it can preallocate a
     // frame.  By default, we create an ARGB frame with no offset. If decoders
     // need a different type, they need to ask for it themselves.
@@ -2841,21 +2841,18 @@ RasterImage::DoError()
   if (mDecoder) {
     MutexAutoLock lock(mDecodingMutex);
     FinishedSomeDecoding(eShutdownIntent_Error);
   }
 
   // Put the container in an error state.
   mError = true;
 
-  if (mDecodeRequest) {
-    mDecodeRequest->mStatusTracker->GetDecoderObserver()->OnError();
-  } else {
-    mStatusTracker->GetDecoderObserver()->OnError();
-  }
+  nsRefPtr<imgStatusTracker> statusTracker = CurrentStatusTracker();
+  statusTracker->GetDecoderObserver()->OnError();
 
   // Log our error
   LOG_CONTAINER_ERROR;
 }
 
 /* static */ void
 RasterImage::HandleErrorWorker::DispatchIfNeeded(RasterImage* aImage)
 {
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -304,23 +304,23 @@ public:
   enum eShutdownIntent {
     eShutdownIntent_Done        = 0,
     eShutdownIntent_NotNeeded   = 1,
     eShutdownIntent_Error       = 2,
     eShutdownIntent_AllCount    = 3
   };
 
 private:
-  imgStatusTracker& CurrentStatusTracker()
+  already_AddRefed<imgStatusTracker> CurrentStatusTracker()
   {
-    if (mDecodeRequest) {
-      return *mDecodeRequest->mStatusTracker;
-    } else {
-      return *mStatusTracker;
-    }
+    nsRefPtr<imgStatusTracker> statusTracker;
+    statusTracker = mDecodeRequest ? mDecodeRequest->mStatusTracker
+                                   : mStatusTracker;
+    MOZ_ASSERT(statusTracker);
+    return statusTracker.forget();
   }
 
   nsresult OnImageDataCompleteCore(nsIRequest* aRequest, nsISupports*, nsresult aStatus);
 
   /**
    * Each RasterImage has a pointer to one or zero heap-allocated
    * DecodeRequests.
    */
@@ -328,16 +328,19 @@ private:
   {
     DecodeRequest(RasterImage* aImage)
       : mImage(aImage)
       , mBytesToDecode(0)
       , mRequestStatus(REQUEST_INACTIVE)
       , mChunkCount(0)
       , mAllocatedNewFrame(false)
     {
+      MOZ_ASSERT(aImage, "aImage cannot be null");
+      MOZ_ASSERT(aImage->mStatusTracker,
+                 "aImage should have an imgStatusTracker");
       mStatusTracker = aImage->mStatusTracker->CloneForRecording();
     }
 
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecodeRequest)
 
     // The status tracker that is associated with a given decode request, to
     // ensure their lifetimes are linked.
     nsRefPtr<imgStatusTracker> mStatusTracker;
--- a/image/src/imgRequest.cpp
+++ b/image/src/imgRequest.cpp
@@ -119,27 +119,29 @@ nsresult imgRequest::Init(nsIURI *aURI,
 
   mCacheEntry = aCacheEntry;
 
   SetLoadId(aLoadId);
 
   return NS_OK;
 }
 
-imgStatusTracker&
+already_AddRefed<imgStatusTracker>
 imgRequest::GetStatusTracker()
 {
   if (mImage && mGotData) {
     NS_ABORT_IF_FALSE(!mStatusTracker,
                       "Should have given mStatusTracker to mImage");
     return mImage->GetStatusTracker();
   } else {
     NS_ABORT_IF_FALSE(mStatusTracker,
                       "Should have mStatusTracker until we create mImage");
-    return *mStatusTracker;
+    nsRefPtr<imgStatusTracker> statusTracker = mStatusTracker;
+    MOZ_ASSERT(statusTracker);
+    return statusTracker.forget();
   }
 }
 
 void imgRequest::SetCacheEntry(imgCacheEntry *entry)
 {
   mCacheEntry = entry;
 }
 
@@ -157,42 +159,43 @@ void imgRequest::ResetCacheEntry()
 
 void imgRequest::AddProxy(imgRequestProxy *proxy)
 {
   NS_PRECONDITION(proxy, "null imgRequestProxy passed in");
   LOG_SCOPE_WITH_PARAM(GetImgLog(), "imgRequest::AddProxy", "proxy", proxy);
 
   // If we're empty before adding, we have to tell the loader we now have
   // proxies.
-  if (GetStatusTracker().ConsumerCount() == 0) {
+  nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
+  if (statusTracker->ConsumerCount() == 0) {
     NS_ABORT_IF_FALSE(mURI, "Trying to SetHasProxies without key uri.");
     mLoader->SetHasProxies(mURI);
   }
 
-  GetStatusTracker().AddConsumer(proxy);
+  statusTracker->AddConsumer(proxy);
 }
 
 nsresult imgRequest::RemoveProxy(imgRequestProxy *proxy, nsresult aStatus)
 {
   LOG_SCOPE_WITH_PARAM(GetImgLog(), "imgRequest::RemoveProxy", "proxy", proxy);
 
   // This will remove our animation consumers, so after removing
   // this proxy, we don't end up without proxies with observers, but still
   // have animation consumers.
   proxy->ClearAnimationConsumers();
 
   // Let the status tracker do its thing before we potentially call Cancel()
   // below, because Cancel() may result in OnStopRequest being called back
   // before Cancel() returns, leaving the image in a different state then the
   // one it was in at this point.
-  imgStatusTracker& statusTracker = GetStatusTracker();
-  if (!statusTracker.RemoveConsumer(proxy, aStatus))
+  nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
+  if (!statusTracker->RemoveConsumer(proxy, aStatus))
     return NS_OK;
 
-  if (statusTracker.ConsumerCount() == 0) {
+  if (statusTracker->ConsumerCount() == 0) {
     // If we have no observers, there's nothing holding us alive. If we haven't
     // been cancelled and thus removed from the cache, tell the image loader so
     // we can be evicted from the cache.
     if (mCacheEntry) {
       NS_ABORT_IF_FALSE(mURI, "Removing last observer without key uri.");
 
       mLoader->SetHasNoProxies(mURI, mCacheEntry);
     }
@@ -204,17 +207,17 @@ nsresult imgRequest::RemoveProxy(imgRequ
     }
 #endif
 
     /* If |aStatus| is a failure code, then cancel the load if it is still in progress.
        Otherwise, let the load continue, keeping 'this' in the cache with no observers.
        This way, if a proxy is destroyed without calling cancel on it, it won't leak
        and won't leave a bad pointer in the observer list.
      */
-    if (statusTracker.IsLoading() && NS_FAILED(aStatus)) {
+    if (statusTracker->IsLoading() && NS_FAILED(aStatus)) {
       LOG_MSG(GetImgLog(), "imgRequest::RemoveProxy", "load in progress.  canceling");
 
       this->Cancel(NS_BINDING_ABORTED);
     }
 
     /* break the cycle from the cache entry. */
     mCacheEntry = nullptr;
   }
@@ -243,30 +246,30 @@ void imgRequest::CancelAndAbort(nsresult
 }
 
 void imgRequest::Cancel(nsresult aStatus)
 {
   /* The Cancel() method here should only be called by this class. */
 
   LOG_SCOPE(GetImgLog(), "imgRequest::Cancel");
 
-  imgStatusTracker& statusTracker = GetStatusTracker();
+  nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
 
-  statusTracker.MaybeUnblockOnload();
+  statusTracker->MaybeUnblockOnload();
 
-  statusTracker.RecordCancel();
+  statusTracker->RecordCancel();
 
   if (NS_IsMainThread()) {
     RemoveFromCache();
   } else {
     NS_DispatchToMainThread(
       NS_NewRunnableMethod(this, &imgRequest::RemoveFromCache));
   }
 
-  if (mRequest && statusTracker.IsLoading())
+  if (mRequest && statusTracker->IsLoading())
     mRequest->Cancel(aStatus);
 }
 
 nsresult imgRequest::GetURI(ImageURL **aURI)
 {
   MOZ_ASSERT(aURI);
 
   LOG_FUNC(GetImgLog(), "imgRequest::GetURI");
@@ -318,17 +321,18 @@ void imgRequest::AdjustPriority(imgReque
 {
   // only the first proxy is allowed to modify the priority of this image load.
   //
   // XXX(darin): this is probably not the most optimal algorithm as we may want
   // to increase the priority of requests that have a lot of proxies.  the key
   // concern though is that image loads remain lower priority than other pieces
   // of content such as link clicks, CSS, and JS.
   //
-  if (!GetStatusTracker().FirstConsumerIs(proxy))
+  nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
+  if (!statusTracker->FirstConsumerIs(proxy))
     return;
 
   nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mChannel);
   if (p)
     p->AdjustPriority(delta);
 }
 
 void imgRequest::SetIsInCache(bool incache)
@@ -512,19 +516,20 @@ imgRequest::StartDecoding()
 
 /* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
 NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt)
 {
   LOG_SCOPE(GetImgLog(), "imgRequest::OnStartRequest");
 
   // Figure out if we're multipart
   nsCOMPtr<nsIMultiPartChannel> mpchan(do_QueryInterface(aRequest));
+  nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
   if (mpchan) {
     mIsMultiPartChannel = true;
-    GetStatusTracker().SetIsMultipart();
+    statusTracker->SetIsMultipart();
   }
 
   // If we're not multipart, we shouldn't have an image yet
   NS_ABORT_IF_FALSE(mIsMultiPartChannel || !mImage,
                     "Already have an image for non-multipart request");
 
   // If we're multipart and about to load another image, signal so we can
   // detect the mime type in OnDataAvailable.
@@ -549,17 +554,19 @@ NS_IMETHODIMP imgRequest::OnStartRequest
   if (!mRequest) {
     NS_ASSERTION(mpchan,
                  "We should have an mRequest here unless we're multipart");
     nsCOMPtr<nsIChannel> chan;
     mpchan->GetBaseChannel(getter_AddRefs(chan));
     mRequest = chan;
   }
 
-  GetStatusTracker().OnStartRequest();
+  // Note: refreshing statusTracker in case OnNewSourceData changed it.
+  statusTracker = GetStatusTracker();
+  statusTracker->OnStartRequest();
 
   nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
   if (channel)
     channel->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
 
   /* Get our principal */
   nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
   if (chan) {
@@ -574,17 +581,17 @@ NS_IMETHODIMP imgRequest::OnStartRequest
     }
   }
 
   SetCacheValidation(mCacheEntry, aRequest);
 
   mApplicationCache = GetApplicationCache(aRequest);
 
   // Shouldn't we be dead already if this gets hit?  Probably multipart/x-mixed-replace...
-  if (GetStatusTracker().ConsumerCount() == 0) {
+  if (statusTracker->ConsumerCount() == 0) {
     this->Cancel(NS_IMAGELIB_ERROR_FAILURE);
   }
 
   // Try to retarget OnDataAvailable to a decode thread.
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
   nsCOMPtr<nsIThreadRetargetableRequest> retargetable =
     do_QueryInterface(aRequest);
   if (httpChannel && retargetable &&
@@ -655,18 +662,18 @@ NS_IMETHODIMP imgRequest::OnStopRequest(
   else {
     // stops animations, removes from cache
     this->Cancel(status);
   }
 
   if (!mImage) {
     // We have to fire imgStatusTracker::OnStopRequest ourselves because there's
     // no image capable of doing so.
-    imgStatusTracker& statusTracker = GetStatusTracker();
-    statusTracker.OnStopRequest(lastPart, status);
+    nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
+    statusTracker->OnStopRequest(lastPart, status);
   }
 
   mTimedChannel = nullptr;
   return NS_OK;
 }
 
 struct mimetype_closure
 {
@@ -752,19 +759,20 @@ imgRequest::OnDataAvailable(nsIRequest *
       mContentType = newType;
 
       // If we've resniffed our MIME type and it changed, we need to create a
       // new status tracker to give to the image, because we don't have one of
       // our own any more.
       if (resniffMimeType) {
         NS_ABORT_IF_FALSE(mIsMultiPartChannel, "Resniffing a non-multipart image");
 
-        imgStatusTracker* freshTracker = new imgStatusTracker(nullptr);
-        freshTracker->AdoptConsumers(&GetStatusTracker());
-        mStatusTracker = freshTracker;
+        nsRefPtr<imgStatusTracker> freshTracker = new imgStatusTracker(nullptr);
+        nsRefPtr<imgStatusTracker> oldStatusTracker = GetStatusTracker();
+        freshTracker->AdoptConsumers(oldStatusTracker);
+        mStatusTracker = freshTracker.forget();
       }
 
       SetProperties(chan);
 
       LOG_MSG_WITH_PARAM(GetImgLog(), "imgRequest::OnDataAvailable", "content type", mContentType.get());
 
       // XXX If server lied about mimetype and it's SVG, we may need to copy
       // the data and dispatch back to the main thread, AND tell the channel to
@@ -776,27 +784,28 @@ imgRequest::OnDataAvailable(nsIRequest *
                                          mURI, mIsMultiPartChannel,
                                          static_cast<uint32_t>(mInnerWindowId));
 
       // Release our copy of the status tracker since the image owns it now.
       mStatusTracker = nullptr;
 
       // Notify listeners that we have an image.
       // XXX(seth): The name of this notification method is pretty misleading.
-      GetStatusTracker().OnDataAvailable();
+      nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
+      statusTracker->OnDataAvailable();
 
       if (mImage->HasError() && !mIsMultiPartChannel) { // Probably bad mimetype
         // We allow multipart images to fail to initialize without cancelling the
         // load because subsequent images might be fine; thus only single part
         // images end up here.
         this->Cancel(NS_ERROR_FAILURE);
         return NS_BINDING_ABORTED;
       }
 
-      NS_ABORT_IF_FALSE(!!GetStatusTracker().GetImage(), "Status tracker should have an image!");
+      NS_ABORT_IF_FALSE(statusTracker->GetImage(), "Status tracker should have an image!");
       NS_ABORT_IF_FALSE(mImage, "imgRequest should have an image!");
 
       if (mDecodeRequested)
         mImage->StartDecoding();
     }
   }
 
   // Notify the image that it has new data.
--- a/image/src/imgRequest.h
+++ b/image/src/imgRequest.h
@@ -110,17 +110,17 @@ public:
   {
     nsCOMPtr<nsIPrincipal> principal = mLoadingPrincipal;
     return principal.forget();
   }
 
   // Return the imgStatusTracker associated with this imgRequest. It may live
   // in |mStatusTracker| or in |mImage.mStatusTracker|, depending on whether
   // mImage has been instantiated yet.
-  imgStatusTracker& GetStatusTracker();
+  already_AddRefed<imgStatusTracker> GetStatusTracker();
 
   // Get the current principal of the image. No AddRefing.
   inline nsIPrincipal* GetPrincipal() const { return mPrincipal.get(); }
 
   // Resize the cache entry to 0 if it exists
   void ResetCacheEntry();
 
   // Update the cache entry size based on the image container
--- a/image/src/imgRequestProxy.cpp
+++ b/image/src/imgRequestProxy.cpp
@@ -22,38 +22,39 @@ using namespace mozilla::image;
 // Since virtual functions can't be used in that way, this class
 // provides a behavioural trait for each class to use instead.
 class ProxyBehaviour
 {
  public:
   virtual ~ProxyBehaviour() {}
 
   virtual mozilla::image::Image* GetImage() const = 0;
-  virtual imgStatusTracker& GetStatusTracker() const = 0;
+  virtual already_AddRefed<imgStatusTracker> GetStatusTracker() const = 0;
   virtual imgRequest* GetOwner() const = 0;
   virtual void SetOwner(imgRequest* aOwner) = 0;
 };
 
 class RequestBehaviour : public ProxyBehaviour
 {
  public:
   RequestBehaviour() : mOwner(nullptr), mOwnerHasImage(false) {}
 
   virtual mozilla::image::Image* GetImage() const MOZ_OVERRIDE;
-  virtual imgStatusTracker& GetStatusTracker() const MOZ_OVERRIDE;
+  virtual already_AddRefed<imgStatusTracker> GetStatusTracker() const MOZ_OVERRIDE;
 
   virtual imgRequest* GetOwner() const MOZ_OVERRIDE {
     return mOwner;
   }
 
   virtual void SetOwner(imgRequest* aOwner) MOZ_OVERRIDE {
     mOwner = aOwner;
 
     if (mOwner) {
-      mOwnerHasImage = !!aOwner->GetStatusTracker().GetImage();
+      nsRefPtr<imgStatusTracker> ownerStatusTracker = GetStatusTracker();
+      mOwnerHasImage = ownerStatusTracker && ownerStatusTracker->GetImage();
     } else {
       mOwnerHasImage = false;
     }
   }
 
  private:
   // We maintain the following invariant:
   // The proxy is registered at most with a single imgRequest as an observer,
@@ -66,20 +67,21 @@ class RequestBehaviour : public ProxyBeh
   bool mOwnerHasImage;
 };
 
 mozilla::image::Image*
 RequestBehaviour::GetImage() const
 {
   if (!mOwnerHasImage)
     return nullptr;
-  return GetStatusTracker().GetImage();
+  nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
+  return statusTracker->GetImage();
 }
 
-imgStatusTracker&
+already_AddRefed<imgStatusTracker>
 RequestBehaviour::GetStatusTracker() const
 {
   // NOTE: It's possible that our mOwner has an Image that it didn't notify
   // us about, if we were Canceled before its Image was constructed.
   // (Canceling removes us as an observer, so mOwner has no way to notify us).
   // That's why this method uses mOwner->GetStatusTracker() instead of just
   // mOwner->mStatusTracker -- we might have a null mImage and yet have an
   // mOwner with a non-null mImage (and a null mStatusTracker pointer).
@@ -192,18 +194,19 @@ nsresult imgRequestProxy::ChangeOwner(im
     UnlockImage();
 
   // If we're holding animation requests, undo them.
   uint32_t oldAnimationConsumers = mAnimationConsumers;
   ClearAnimationConsumers();
 
   // Were we decoded before?
   bool wasDecoded = false;
+  nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
   if (GetImage() &&
-      (GetStatusTracker().GetImageStatus() & imgIRequest::STATUS_FRAME_COMPLETE)) {
+      statusTracker->GetImageStatus() & imgIRequest::STATUS_FRAME_COMPLETE) {
     wasDecoded = true;
   }
 
   GetOwner()->RemoveProxy(this, NS_IMAGELIB_CHANGING_OWNER);
 
   mBehaviour->SetOwner(aNewOwner);
 
   // If we were locked, apply the locks here
@@ -492,17 +495,18 @@ NS_IMETHODIMP imgRequestProxy::GetImage(
   NS_ADDREF(*aImage = imageToReturn);
 
   return NS_OK;
 }
 
 /* readonly attribute unsigned long imageStatus; */
 NS_IMETHODIMP imgRequestProxy::GetImageStatus(uint32_t *aStatus)
 {
-  *aStatus = GetStatusTracker().GetImageStatus();
+  nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
+  *aStatus = statusTracker->GetImageStatus();
 
   return NS_OK;
 }
 
 /* readonly attribute nsIURI URI; */
 NS_IMETHODIMP imgRequestProxy::GetURI(nsIURI **aURI)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread to convert URI");
@@ -935,57 +939,62 @@ imgRequestProxy::GetStaticRequest(imgReq
 
 void imgRequestProxy::NotifyListener()
 {
   // It would be nice to notify the observer directly in the status tracker
   // instead of through the proxy, but there are several places we do extra
   // processing when we receive notifications (like OnStopRequest()), and we
   // need to check mCanceled everywhere too.
 
+  nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
   if (GetOwner()) {
     // Send the notifications to our listener asynchronously.
-    GetStatusTracker().Notify(this);
+    statusTracker->Notify(this);
   } else {
     // We don't have an imgRequest, so we can only notify the clone of our
     // current state, but we still have to do that asynchronously.
     NS_ABORT_IF_FALSE(GetImage(),
                       "if we have no imgRequest, we should have an Image");
-    GetStatusTracker().NotifyCurrentState(this);
+    statusTracker->NotifyCurrentState(this);
   }
 }
 
 void imgRequestProxy::SyncNotifyListener()
 {
   // It would be nice to notify the observer directly in the status tracker
   // instead of through the proxy, but there are several places we do extra
   // processing when we receive notifications (like OnStopRequest()), and we
   // need to check mCanceled everywhere too.
 
-  GetStatusTracker().SyncNotify(this);
+  nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
+  statusTracker->SyncNotify(this);
 }
 
 void
 imgRequestProxy::SetHasImage()
 {
-  Image* image = GetStatusTracker().GetImage();
+  nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
+  MOZ_ASSERT(statusTracker);
+  Image* image = statusTracker->GetImage();
+  MOZ_ASSERT(image);
 
   // Force any private status related to the owner to reflect
   // the presence of an image;
   mBehaviour->SetOwner(mBehaviour->GetOwner());
 
   // Apply any locks we have
   for (uint32_t i = 0; i < mLockCount; ++i)
     image->LockImage();
 
   // Apply any animation consumers we have
   for (uint32_t i = 0; i < mAnimationConsumers; i++)
     image->IncrementAnimationConsumers();
 }
 
-imgStatusTracker&
+already_AddRefed<imgStatusTracker>
 imgRequestProxy::GetStatusTracker() const
 {
   return mBehaviour->GetStatusTracker();
 }
 
 mozilla::image::Image*
 imgRequestProxy::GetImage() const
 {
@@ -1004,17 +1013,17 @@ class StaticBehaviour : public ProxyBeha
 {
 public:
   StaticBehaviour(mozilla::image::Image* aImage) : mImage(aImage) {}
 
   virtual mozilla::image::Image* GetImage() const MOZ_OVERRIDE {
     return mImage;
   }
 
-  virtual imgStatusTracker& GetStatusTracker() const MOZ_OVERRIDE {
+  virtual already_AddRefed<imgStatusTracker> GetStatusTracker() const MOZ_OVERRIDE {
     return mImage->GetStatusTracker();
   }
 
   virtual imgRequest* GetOwner() const MOZ_OVERRIDE {
     return nullptr;
   }
 
   virtual void SetOwner(imgRequest* aOwner) MOZ_OVERRIDE {
--- a/image/src/imgRequestProxy.h
+++ b/image/src/imgRequestProxy.h
@@ -166,17 +166,17 @@ protected:
   void DoRemoveFromLoadGroup() {
     RemoveFromLoadGroup(true);
   }
 
   // Return the imgStatusTracker associated with mOwner and/or mImage. It may
   // live either on mOwner or mImage, depending on whether
   //   (a) we have an mOwner at all
   //   (b) whether mOwner has instantiated its image yet
-  imgStatusTracker& GetStatusTracker() const;
+  already_AddRefed<imgStatusTracker> GetStatusTracker() const;
 
   nsITimedChannel* TimedChannel()
   {
     if (!GetOwner())
       return nullptr;
     return GetOwner()->mTimedChannel;
   }
 
--- a/image/src/imgStatusTracker.cpp
+++ b/image/src/imgStatusTracker.cpp
@@ -18,21 +18,26 @@
 #include "mozilla/Services.h"
 
 using namespace mozilla::image;
 
 class imgStatusTrackerNotifyingObserver : public imgDecoderObserver
 {
 public:
   imgStatusTrackerNotifyingObserver(imgStatusTracker* aTracker)
-  : mTracker(aTracker) {}
+  : mTracker(aTracker)
+  {
+    MOZ_ASSERT(aTracker);
+  }
 
   virtual ~imgStatusTrackerNotifyingObserver() {}
 
-  void SetTracker(imgStatusTracker* aTracker) {
+  void SetTracker(imgStatusTracker* aTracker)
+  {
+    MOZ_ASSERT(aTracker);
     mTracker = aTracker;
   }
 
   /** imgDecoderObserver methods **/
 
   virtual void OnStartDecode()
   {
     MOZ_ASSERT(NS_IsMainThread(),
@@ -200,116 +205,144 @@ public:
   }
 
   virtual void OnError()
   {
     mTracker->RecordError();
   }
 
 private:
-  imgStatusTracker* mTracker;
+  nsRefPtr<imgStatusTracker> mTracker;
 };
 
 class imgStatusTrackerObserver : public imgDecoderObserver
 {
 public:
   imgStatusTrackerObserver(imgStatusTracker* aTracker)
-  : mTracker(aTracker) {}
+  : mTracker(aTracker->asWeakPtr())
+  {
+    MOZ_ASSERT(aTracker);
+  }
 
   virtual ~imgStatusTrackerObserver() {}
 
-  void SetTracker(imgStatusTracker* aTracker) {
-    mTracker = aTracker;
+  void SetTracker(imgStatusTracker* aTracker)
+  {
+    MOZ_ASSERT(aTracker);
+    mTracker = aTracker->asWeakPtr();
   }
 
   /** imgDecoderObserver methods **/
 
   virtual void OnStartDecode() MOZ_OVERRIDE
   {
     LOG_SCOPE(GetImgLog(), "imgStatusTrackerObserver::OnStartDecode");
-    mTracker->RecordStartDecode();
-    if (!mTracker->IsMultipart()) {
-      mTracker->RecordBlockOnload();
+    nsRefPtr<imgStatusTracker> tracker = mTracker.get();
+    if (!tracker) { return; }
+    tracker->RecordStartDecode();
+    if (!tracker->IsMultipart()) {
+      tracker->RecordBlockOnload();
     }
   }
 
   virtual void OnStartRequest() MOZ_OVERRIDE
   {
     NS_NOTREACHED("imgStatusTrackerObserver(imgDecoderObserver)::OnStartRequest");
   }
 
   virtual void OnStartContainer() MOZ_OVERRIDE
   {
     LOG_SCOPE(GetImgLog(), "imgStatusTrackerObserver::OnStartContainer");
-    mTracker->RecordStartContainer(mTracker->GetImage());
+    nsRefPtr<imgStatusTracker> tracker = mTracker.get();
+    if (!tracker) { return; }
+    nsRefPtr<Image> image = tracker->GetImage();;
+    tracker->RecordStartContainer(image);
   }
 
   virtual void OnStartFrame() MOZ_OVERRIDE
   {
     LOG_SCOPE(GetImgLog(), "imgStatusTrackerObserver::OnStartFrame");
-    mTracker->RecordStartFrame();
+    nsRefPtr<imgStatusTracker> tracker = mTracker.get();
+    if (!tracker) { return; }
+    tracker->RecordStartFrame();
   }
 
   virtual void FrameChanged(const nsIntRect* dirtyRect) MOZ_OVERRIDE
   {
     LOG_SCOPE(GetImgLog(), "imgStatusTrackerObserver::FrameChanged");
-    mTracker->RecordFrameChanged(dirtyRect);
+    nsRefPtr<imgStatusTracker> tracker = mTracker.get();
+    if (!tracker) { return; }
+    tracker->RecordFrameChanged(dirtyRect);
   }
 
   virtual void OnStopFrame() MOZ_OVERRIDE
   {
     LOG_SCOPE(GetImgLog(), "imgStatusTrackerObserver::OnStopFrame");
-    mTracker->RecordStopFrame();
-    mTracker->RecordUnblockOnload();
+    nsRefPtr<imgStatusTracker> tracker = mTracker.get();
+    if (!tracker) { return; }
+    tracker->RecordStopFrame();
+    tracker->RecordUnblockOnload();
   }
 
   virtual void OnStopDecode(nsresult aStatus) MOZ_OVERRIDE
   {
     LOG_SCOPE(GetImgLog(), "imgStatusTrackerObserver::OnStopDecode");
-    mTracker->RecordStopDecode(aStatus);
+    nsRefPtr<imgStatusTracker> tracker = mTracker.get();
+    if (!tracker) { return; }
+    tracker->RecordStopDecode(aStatus);
 
     // This is really hacky. We need to handle the case where we start decoding,
     // block onload, but then hit an error before we get to our first frame.
-    mTracker->RecordUnblockOnload();
+    tracker->RecordUnblockOnload();
   }
 
   virtual void OnStopRequest(bool aLastPart, nsresult aStatus) MOZ_OVERRIDE
   {
     LOG_SCOPE(GetImgLog(), "imgStatusTrackerObserver::OnStopRequest");
-    mTracker->RecordStopRequest(aLastPart, aStatus);
+    nsRefPtr<imgStatusTracker> tracker = mTracker.get();
+    if (!tracker) { return; }
+    tracker->RecordStopRequest(aLastPart, aStatus);
   }
 
   virtual void OnDiscard() MOZ_OVERRIDE
   {
     LOG_SCOPE(GetImgLog(), "imgStatusTrackerObserver::OnDiscard");
-    mTracker->RecordDiscard();
+    nsRefPtr<imgStatusTracker> tracker = mTracker.get();
+    if (!tracker) { return; }
+    tracker->RecordDiscard();
   }
 
   virtual void OnUnlockedDraw() MOZ_OVERRIDE
   {
     LOG_SCOPE(GetImgLog(), "imgStatusTrackerObserver::OnUnlockedDraw");
-    NS_ABORT_IF_FALSE(mTracker->GetImage(),
+    nsRefPtr<imgStatusTracker> tracker = mTracker.get();
+    if (!tracker) { return; }
+    NS_ABORT_IF_FALSE(tracker->GetImage(),
                       "OnUnlockedDraw callback before we've created our image");
-    mTracker->RecordUnlockedDraw();
+    tracker->RecordUnlockedDraw();
   }
 
   virtual void OnImageIsAnimated() MOZ_OVERRIDE
   {
     LOG_SCOPE(GetImgLog(), "imgStatusTrackerObserver::OnImageIsAnimated");
-    mTracker->RecordImageIsAnimated();
+    nsRefPtr<imgStatusTracker> tracker = mTracker.get();
+    if (!tracker) { return; }
+    tracker->RecordImageIsAnimated();
   }
 
   virtual void OnError() MOZ_OVERRIDE
   {
     LOG_SCOPE(GetImgLog(), "imgStatusTrackerObserver::OnError");
-    mTracker->RecordError();
+    nsRefPtr<imgStatusTracker> tracker = mTracker.get();
+    if (!tracker) { return; }
+    tracker->RecordError();
   }
 
 private:
-  imgStatusTracker* mTracker;
+  mozilla::WeakPtr<imgStatusTracker> mTracker;
 };
 
 // imgStatusTracker methods
 
 imgStatusTracker::imgStatusTracker(Image* aImage)
   : mImage(aImage),
     mState(0),
     mImageStatus(imgIRequest::STATUS_NONE),
@@ -364,17 +397,18 @@ imgStatusTracker::GetImageStatus() const
 {
   return mImageStatus;
 }
 
 // A helper class to allow us to call SyncNotify asynchronously.
 class imgRequestNotifyRunnable : public nsRunnable
 {
   public:
-    imgRequestNotifyRunnable(imgStatusTracker* aTracker, imgRequestProxy* aRequestProxy)
+    imgRequestNotifyRunnable(imgStatusTracker* aTracker,
+                             imgRequestProxy* aRequestProxy)
       : mTracker(aTracker)
     {
       MOZ_ASSERT(NS_IsMainThread(), "Should be created on the main thread");
       MOZ_ASSERT(aRequestProxy, "aRequestProxy should not be null");
       MOZ_ASSERT(aTracker, "aTracker should not be null");
       mProxies.AppendElement(aRequestProxy);
     }
 
@@ -437,36 +471,37 @@ imgStatusTracker::Notify(imgRequestProxy
   }
 }
 
 // A helper class to allow us to call SyncNotify asynchronously for a given,
 // fixed, state.
 class imgStatusNotifyRunnable : public nsRunnable
 {
   public:
-    imgStatusNotifyRunnable(imgStatusTracker& status,
+    imgStatusNotifyRunnable(imgStatusTracker* statusTracker,
                             imgRequestProxy* requestproxy)
-      : mStatus(status), mImage(status.mImage), mProxy(requestproxy)
+      : mStatusTracker(statusTracker), mProxy(requestproxy)
     {
       MOZ_ASSERT(NS_IsMainThread(), "Should be created on the main thread");
       MOZ_ASSERT(requestproxy, "requestproxy cannot be null");
+      MOZ_ASSERT(statusTracker, "status should not be null");
+      mImage = statusTracker->GetImage();
     }
 
     NS_IMETHOD Run()
     {
       MOZ_ASSERT(NS_IsMainThread(), "Should be running on the main thread");
-      MOZ_ASSERT(mProxy, "mProxy cannot be null");
       mProxy->SetNotificationsDeferred(false);
 
-      mStatus.SyncNotify(mProxy);
+      mStatusTracker->SyncNotify(mProxy);
       return NS_OK;
     }
 
   private:
-    imgStatusTracker mStatus;
+    nsRefPtr<imgStatusTracker> mStatusTracker;
     // We have to hold on to a reference to the tracker's image, just in case
     // it goes away while we're in the event queue.
     nsRefPtr<Image> mImage;
     nsRefPtr<imgRequestProxy> mProxy;
 };
 
 void
 imgStatusTracker::NotifyCurrentState(imgRequestProxy* proxy)
@@ -478,17 +513,17 @@ imgStatusTracker::NotifyCurrentState(img
   nsAutoCString spec;
   uri->GetSpec(spec);
   LOG_FUNC_WITH_PARAM(GetImgLog(), "imgStatusTracker::NotifyCurrentState", "uri", spec.get());
 #endif
 
   proxy->SetNotificationsDeferred(true);
 
   // We don't keep track of
-  nsCOMPtr<nsIRunnable> ev = new imgStatusNotifyRunnable(*this, proxy);
+  nsCOMPtr<nsIRunnable> ev = new imgStatusNotifyRunnable(this, proxy);
   NS_DispatchToCurrentThread(ev);
 }
 
 #define NOTIFY_IMAGE_OBSERVERS(func) \
   do { \
     nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(proxies); \
     while (iter.HasMore()) { \
       nsRefPtr<imgRequestProxy> proxy = iter.GetNext(); \
@@ -544,16 +579,17 @@ imgStatusTracker::SyncNotifyState(nsTObs
   if (state & stateRequestStopped) {
     NOTIFY_IMAGE_OBSERVERS(OnStopRequest(hadLastPart));
   }
 }
 
 ImageStatusDiff
 imgStatusTracker::Difference(imgStatusTracker* aOther) const
 {
+  MOZ_ASSERT(aOther, "aOther cannot be null");
   ImageStatusDiff diff;
   diff.diffState = ~mState & aOther->mState & ~stateRequestStarted;
   diff.diffImageStatus = ~mImageStatus & aOther->mImageStatus;
   diff.unblockedOnload = mState & stateBlockingOnload && !(aOther->mState & stateBlockingOnload);
   diff.unsetDecodeStarted = mImageStatus & imgIRequest::STATUS_DECODE_STARTED
                          && !(aOther->mImageStatus & imgIRequest::STATUS_DECODE_STARTED);
   diff.foundError = (mImageStatus != imgIRequest::STATUS_ERROR)
                  && (aOther->mImageStatus == imgIRequest::STATUS_ERROR);
@@ -647,21 +683,23 @@ imgStatusTracker::SyncNotifyDifference(c
     }
   }
 
   if (diff.foundError) {
     FireFailureNotification();
   }
 }
 
-imgStatusTracker*
+already_AddRefed<imgStatusTracker>
 imgStatusTracker::CloneForRecording()
 {
-  imgStatusTracker* clone = new imgStatusTracker(*this);
-  return clone;
+  // Grab a ref to this to ensure it isn't deleted.
+  nsRefPtr<imgStatusTracker> thisStatusTracker = this;
+  nsRefPtr<imgStatusTracker> clone = new imgStatusTracker(*thisStatusTracker);
+  return clone.forget();
 }
 
 void
 imgStatusTracker::SyncNotify(imgRequestProxy* proxy)
 {
   MOZ_ASSERT(NS_IsMainThread(), "imgRequestProxy is not threadsafe");
 #ifdef PR_LOGGING
   nsRefPtr<ImageURL> uri;
--- a/image/src/imgStatusTracker.h
+++ b/image/src/imgStatusTracker.h
@@ -12,16 +12,17 @@ class imgIContainer;
 class imgRequestProxy;
 class imgStatusNotifyRunnable;
 class imgRequestNotifyRunnable;
 class imgStatusTrackerObserver;
 class imgStatusTrackerNotifyingObserver;
 class nsIRunnable;
 
 #include "mozilla/RefPtr.h"
+#include "mozilla/WeakPtr.h"
 #include "nsCOMPtr.h"
 #include "nsTObserverArray.h"
 #include "nsThreadUtils.h"
 #include "nsRect.h"
 
 namespace mozilla {
 namespace image {
 
@@ -100,26 +101,27 @@ enum {
  * to imgRequestProxys, both synchronously (i.e., the status now) and
  * asynchronously (the status later).
  *
  * When a new proxy needs to be notified of the current state of an image, call
  * the Notify() method on this class with the relevant proxy as its argument,
  * and the notifications will be replayed to the proxy asynchronously.
  */
 
-class imgStatusTracker
+
+class imgStatusTracker : public mozilla::SupportsWeakPtr<imgStatusTracker>
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(imgStatusTracker)
 
   // aImage is the image that this status tracker will pass to the
   // imgRequestProxys in SyncNotify() and EmulateRequestFinished(), and must be
   // alive as long as this instance is, because we hold a weak reference to it.
   imgStatusTracker(mozilla::image::Image* aImage);
-  ~imgStatusTracker();
+  virtual ~imgStatusTracker();
 
   // Image-setter, for imgStatusTrackers created by imgRequest::Init, which
   // are created before their Image is created.  This method should only
   // be called once, and only on an imgStatusTracker that was initialized
   // without an image.
   void SetImage(mozilla::image::Image* aImage);
 
   // Inform this status tracker that it is associated with a multipart image.
@@ -170,16 +172,17 @@ public:
   // be improved, but it's too scary to mess with at the moment.
   bool FirstConsumerIs(imgRequestProxy* aConsumer) {
     MOZ_ASSERT(NS_IsMainThread(), "Use mConsumers on main thread only");
     return mConsumers.SafeElementAt(0, nullptr) == aConsumer;
   }
 
   void AdoptConsumers(imgStatusTracker* aTracker) {
     MOZ_ASSERT(NS_IsMainThread(), "Use mConsumers on main thread only");
+    MOZ_ASSERT(aTracker);
     mConsumers = aTracker->mConsumers;
   }
 
   // Returns whether we are in the process of loading; that is, whether we have
   // not received OnStopRequest.
   bool IsLoading() const;
 
   // Get the current image status (as in imgIRequest).
@@ -260,17 +263,17 @@ public:
 
   bool IsMultipart() const { return mIsMultipart; }
 
   // Weak pointer getters - no AddRefs.
   inline mozilla::image::Image* GetImage() const { return mImage; }
 
   inline imgDecoderObserver* GetDecoderObserver() { return mTrackerObserver.get(); }
 
-  imgStatusTracker* CloneForRecording();
+  already_AddRefed<imgStatusTracker> CloneForRecording();
 
   // Compute the difference between this status tracker and aOther.
   mozilla::image::ImageStatusDiff Difference(imgStatusTracker* aOther) const;
 
   // Captures all of the decode notifications (i.e., not OnStartRequest /
   // OnStopRequest) so far as an ImageStatusDiff.
   mozilla::image::ImageStatusDiff DecodeStateAsDifference() const;