Bug 1060953: Fix reference cycle between DrawTargetD2D1 and SourceSurfaceD2D1. r=jrmuizel
authorBas Schouten <bschouten@mozilla.com>
Sun, 14 Sep 2014 23:51:28 +0200
changeset 205251 e195dda5f23aeb51efd6272b8f73253899850c99
parent 205250 7b9201731195c5391405de8d9f52b370a34a4ba0
child 205252 3b03f3ab20bb7248e01d9ad14a7ec134c5733d51
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersjrmuizel
bugs1060953
milestone35.0a1
Bug 1060953: Fix reference cycle between DrawTargetD2D1 and SourceSurfaceD2D1. r=jrmuizel
gfx/2d/DrawTargetD2D1.cpp
gfx/2d/SourceSurfaceD2D1.h
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -34,17 +34,40 @@ DrawTargetD2D1::DrawTargetD2D1()
   : mClipsArePushed(false)
 {
 }
 
 DrawTargetD2D1::~DrawTargetD2D1()
 {
   PopAllClips();
 
+  if (mSnapshot) {
+    // We may hold the only reference. MarkIndependent will clear mSnapshot;
+    // keep the snapshot object alive so it doesn't get destroyed while
+    // MarkIndependent is running.
+    RefPtr<SourceSurfaceD2D1> deathGrip = mSnapshot;
+    // mSnapshot can be treated as independent of this DrawTarget since we know
+    // this DrawTarget won't change again.
+    deathGrip->MarkIndependent();
+    // mSnapshot will be cleared now.
+  }
+
   mDC->EndDraw();
+
+  // Targets depending on us can break that dependency, since we're obviously not going to
+  // be modified in the future.
+  for (auto iter = mDependentTargets.begin();
+       iter != mDependentTargets.end(); iter++) {
+    (*iter)->mDependingOnTargets.erase(this);
+  }
+  // Our dependencies on other targets no longer matter.
+  for (TargetSet::iterator iter = mDependingOnTargets.begin();
+       iter != mDependingOnTargets.end(); iter++) {
+    (*iter)->mDependentTargets.erase(this);
+  }
 }
 
 TemporaryRef<SourceSurface>
 DrawTargetD2D1::Snapshot()
 {
   if (mSnapshot) {
     return mSnapshot;
   }
@@ -56,16 +79,23 @@ DrawTargetD2D1::Snapshot()
 
   return mSnapshot;
 }
 
 void
 DrawTargetD2D1::Flush()
 {
   mDC->Flush();
+
+  // We no longer depend on any target.
+  for (TargetSet::iterator iter = mDependingOnTargets.begin();
+       iter != mDependingOnTargets.end(); iter++) {
+    (*iter)->mDependentTargets.erase(this);
+  }
+  mDependingOnTargets.clear();
 }
 
 void
 DrawTargetD2D1::DrawSurface(SourceSurface *aSurface,
                             const Rect &aDest,
                             const Rect &aSource,
                             const DrawSurfaceOptions &aSurfOptions,
                             const DrawOptions &aOptions)
--- a/gfx/2d/SourceSurfaceD2D1.h
+++ b/gfx/2d/SourceSurfaceD2D1.h
@@ -52,17 +52,17 @@ private:
   RefPtr<ID2D1Image> mImage;
   // This may be null if we were created for a non-bitmap image and have not
   // had a reason yet to realize ourselves.
   RefPtr<ID2D1Bitmap1> mRealizedBitmap;
   RefPtr<ID2D1DeviceContext> mDC;
 
   SurfaceFormat mFormat;
   IntSize mSize;
-  RefPtr<DrawTargetD2D1> mDrawTarget;
+  DrawTargetD2D1* mDrawTarget;
 };
 
 class DataSourceSurfaceD2D1 : public DataSourceSurface
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceD2D1)
   DataSourceSurfaceD2D1(ID2D1Bitmap1 *aMappableBitmap, SurfaceFormat aFormat);
   ~DataSourceSurfaceD2D1();