Bug 1215438 - Part 3: CairoImage can use in any thread. r=roc
authorMorris Tseng <mtseng@mozilla.com>
Fri, 18 Dec 2015 14:52:16 +0800
changeset 301433 dd4d0619b391d26699851e1f9ec2cc915e26bc29
parent 301432 384e0084e85ff2adc8e31ad471461abeedefaa1e
child 301434 c07ad4a4f4fdb7f94653639a21dd9910e1e871bc
push idunknown
push userunknown
push dateunknown
reviewersroc
bugs1215438
milestone46.0a1
Bug 1215438 - Part 3: CairoImage can use in any thread. r=roc
gfx/layers/ImageContainer.h
--- a/gfx/layers/ImageContainer.h
+++ b/gfx/layers/ImageContainer.h
@@ -78,16 +78,60 @@ public:
   static void AddRef(RawRef aRawRef)
   {
     NS_ASSERTION(NS_IsMainThread(),
                  "Can only add a reference on the main thread");
     aRawRef->AddRef();
   }
 };
 
+class nsOwningThreadSourceSurfaceRef;
+
+template <>
+class nsAutoRefTraits<nsOwningThreadSourceSurfaceRef> {
+public:
+  typedef mozilla::gfx::SourceSurface* RawRef;
+
+  /**
+   * The XPCOM event that will do the actual release on the creation thread.
+   */
+  class SurfaceReleaser : public nsRunnable {
+  public:
+    explicit SurfaceReleaser(RawRef aRef) : mRef(aRef) {}
+    NS_IMETHOD Run() {
+      mRef->Release();
+      return NS_OK;
+    }
+    RawRef mRef;
+  };
+
+  static RawRef Void() { return nullptr; }
+  void Release(RawRef aRawRef)
+  {
+    MOZ_ASSERT(mOwningThread);
+    bool current;
+    mOwningThread->IsOnCurrentThread(&current);
+    if (current) {
+      aRawRef->Release();
+      return;
+    }
+    nsCOMPtr<nsIRunnable> runnable = new SurfaceReleaser(aRawRef);
+    mOwningThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL);
+  }
+  void AddRef(RawRef aRawRef)
+  {
+    MOZ_ASSERT(!mOwningThread);
+    NS_GetCurrentThread(getter_AddRefs(mOwningThread));
+    aRawRef->AddRef();
+  }
+
+private:
+  nsCOMPtr<nsIThread> mOwningThread;
+};
+
 #endif
 
 #ifdef XP_WIN
 struct ID3D10Texture2D;
 struct ID3D10Device;
 struct ID3D10ShaderResourceView;
 #endif
 
@@ -779,17 +823,17 @@ public:
 
   virtual gfx::IntSize GetSize() override { return mSize; }
 
   CairoImage(const gfx::IntSize& aSize, gfx::SourceSurface* aSourceSurface);
   ~CairoImage();
 
 private:
   gfx::IntSize mSize;
-  nsCountedRef<nsMainThreadSourceSurfaceRef> mSourceSurface;
+  nsCountedRef<nsOwningThreadSourceSurfaceRef> mSourceSurface;
   nsDataHashtable<nsUint32HashKey, RefPtr<TextureClient> >  mTextureClients;
 };
 
 #ifdef MOZ_WIDGET_GONK
 class OverlayImage : public Image {
   /**
    * OverlayImage is a special Image type that does not hold any buffer.
    * It only hold an Id as identifier to the real content of the Image.