Bug 924967 - Dispatch nsIRequest::Cancel to main thread in imgRequest::Cancel r=seth
authorSteve Workman <sworkman@mozilla.com>
Tue, 15 Oct 2013 16:33:11 -0700
changeset 150841 dd2957ba1805c037737742e8832233ceba02bb0e
parent 150840 15e91a96d77d105afd200b0d9dc88752b72c8148
child 150842 6d9022faecd0d3f3724605189aed828a6c65443d
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersseth
bugs924967
milestone27.0a1
Bug 924967 - Dispatch nsIRequest::Cancel to main thread in imgRequest::Cancel r=seth
image/src/imgRequest.cpp
image/src/imgRequest.h
--- a/image/src/imgRequest.cpp
+++ b/image/src/imgRequest.cpp
@@ -240,37 +240,67 @@ void imgRequest::CancelAndAbort(nsresult
   // notification callbacks. In that case, make sure to break the cycle between
   // the channel and us, because it won't.
   if (mChannel) {
     mChannel->SetNotificationCallbacks(mPrevChannelSink);
     mPrevChannelSink = nullptr;
   }
 }
 
+class imgRequestMainThreadCancel : public nsRunnable
+{
+public:
+  imgRequestMainThreadCancel(imgRequest *aImgRequest, nsresult aStatus)
+    : mImgRequest(aImgRequest)
+    , mStatus(aStatus)
+  {
+    MOZ_ASSERT(!NS_IsMainThread(), "Create me off main thread only!");
+    MOZ_ASSERT(aImgRequest);
+  }
+
+  NS_IMETHOD Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread(), "I should be running on the main thread!");
+    mImgRequest->ContinueCancel(mStatus);
+    return NS_OK;
+  } 
+private:
+  nsRefPtr<imgRequest> mImgRequest;
+  nsresult mStatus;
+};
+
 void imgRequest::Cancel(nsresult aStatus)
 {
   /* The Cancel() method here should only be called by this class. */
 
   LOG_SCOPE(GetImgLog(), "imgRequest::Cancel");
 
   nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
 
   statusTracker->MaybeUnblockOnload();
 
   statusTracker->RecordCancel();
 
   if (NS_IsMainThread()) {
-    RemoveFromCache();
+    ContinueCancel(aStatus);
   } else {
-    NS_DispatchToMainThread(
-      NS_NewRunnableMethod(this, &imgRequest::RemoveFromCache));
+    NS_DispatchToMainThread(new imgRequestMainThreadCancel(this, aStatus));
   }
+}
 
-  if (mRequest && statusTracker->IsLoading())
-    mRequest->Cancel(aStatus);
+void imgRequest::ContinueCancel(nsresult aStatus)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  RemoveFromCache();
+
+  nsRefPtr<imgStatusTracker> statusTracker = GetStatusTracker();
+  if (mRequest && statusTracker->IsLoading()) {
+     mRequest->Cancel(aStatus);
+  }
 }
 
 nsresult imgRequest::GetURI(ImageURL **aURI)
 {
   MOZ_ASSERT(aURI);
 
   LOG_FUNC(GetImgLog(), "imgRequest::GetURI");
 
--- a/image/src/imgRequest.h
+++ b/image/src/imgRequest.h
@@ -67,16 +67,19 @@ public:
 
   nsresult RemoveProxy(imgRequestProxy *proxy, nsresult aStatus);
 
   // Cancel, but also ensure that all work done in Init() is undone. Call this
   // only when the channel has failed to open, and so calling Cancel() on it
   // won't be sufficient.
   void CancelAndAbort(nsresult aStatus);
 
+  // Called or dispatched by cancel for main thread only execution.
+  void ContinueCancel(nsresult aStatus);
+
   // Methods that get forwarded to the Image, or deferred until it's
   // instantiated.
   nsresult LockImage();
   nsresult UnlockImage();
   nsresult StartDecoding();
   nsresult RequestDecode();
 
   inline void SetInnerWindowID(uint64_t aInnerWindowId) {