Bug 1294351 - Move restoring the canvas clip stack to its own method and early return form EnsureTarget. r=Bas
authorNicolas Silva <nsilva@mozilla.com>
Fri, 26 Aug 2016 14:31:58 +0200
changeset 311447 ac16b2ccd7a11e81b8d2fcb84146c6460a188256
parent 311446 bc5a4525f6c291dc0482c750a8addeabdb543ca6
child 311448 ba8f999c0a3fdd0ccc61e3676c564c69dbce248b
push id30610
push userkwierso@gmail.com
push dateFri, 26 Aug 2016 23:20:56 +0000
treeherdermozilla-central@f38d60b049f0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas
bugs1294351
milestone51.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 1294351 - Move restoring the canvas clip stack to its own method and early return form EnsureTarget. r=Bas
dom/canvas/CanvasRenderingContext2D.cpp
dom/canvas/CanvasRenderingContext2D.h
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -1500,16 +1500,43 @@ CanvasRenderingContext2D::OnStableState(
     return;
   }
 
   ReturnTarget();
 
   mHasPendingStableStateCallback = false;
 }
 
+void
+CanvasRenderingContext2D::RestoreClipsAndTransformToTarget()
+{
+  // Restore clips and transform.
+  mTarget->SetTransform(Matrix());
+
+  if (mTarget->GetBackendType() == gfx::BackendType::CAIRO) {
+    // Cairo doesn't play well with huge clips. When given a very big clip it
+    // will try to allocate big mask surface without taking the target
+    // size into account which can cause OOM. See bug 1034593.
+    // This limits the clip extents to the size of the canvas.
+    // A fix in Cairo would probably be preferable, but requires somewhat
+    // invasive changes.
+    mTarget->PushClipRect(gfx::Rect(0, 0, mWidth, mHeight));
+  }
+
+  for (const auto& style : mStyleStack) {
+    for (const auto& clipOrTransform : style.clipsAndTransforms) {
+      if (clipOrTransform.IsClip()) {
+        mTarget->PushClip(clipOrTransform.clip);
+      } else {
+        mTarget->SetTransform(clipOrTransform.transform);
+      }
+    }
+  }
+}
+
 CanvasRenderingContext2D::RenderingMode
 CanvasRenderingContext2D::EnsureTarget(const gfx::Rect* aCoveredRect,
                                        RenderingMode aRenderingMode)
 {
   if (AlreadyShutDown()) {
     gfxCriticalError() << "Attempt to render into a Canvas2d after shutdown.";
     EnsureErrorTarget();
     mTarget = sErrorTarget;
@@ -1551,17 +1578,23 @@ CanvasRenderingContext2D::EnsureTarget(c
   // buffer provider.
   RefPtr<PersistentBufferProvider> oldBufferProvider = mBufferProvider;
 
   if (mBufferProvider && mode == mRenderingMode) {
     auto persistedRect = canDiscardContent ? IntRect()
                                            : IntRect(0, 0, mWidth, mHeight);
     mTarget = mBufferProvider->BorrowDrawTarget(persistedRect);
 
-    mode = mRenderingMode;
+    if (mTarget && !mBufferProvider->PreservesDrawingState()) {
+      RestoreClipsAndTransformToTarget();
+    }
+
+    if (mTarget) {
+      return mode;
+    }
   }
 
   mIsSkiaGL = false;
 
    // Check that the dimensions are sane
   IntSize size(mWidth, mHeight);
   if (!mTarget &&
       size.width <= gfxPrefs::MaxCanvasSize() &&
@@ -1644,38 +1677,17 @@ CanvasRenderingContext2D::EnsureTarget(c
       }
       // Calling Redraw() tells our invalidation machinery that the entire
       // canvas is already invalid, which can speed up future drawing.
       Redraw();
     }
 
     if (mBufferProvider != oldBufferProvider || !mBufferProvider ||
         !mBufferProvider->PreservesDrawingState()) {
-      // Restore clips and transform.
-      mTarget->SetTransform(Matrix());
-
-      if (mTarget->GetBackendType() == gfx::BackendType::CAIRO) {
-        // Cairo doesn't play well with huge clips. When given a very big clip it
-        // will try to allocate big mask surface without taking the target
-        // size into account which can cause OOM. See bug 1034593.
-        // This limits the clip extents to the size of the canvas.
-        // A fix in Cairo would probably be preferable, but requires somewhat
-        // invasive changes.
-        mTarget->PushClipRect(canvasRect);
-      }
-
-      for (const auto& style : mStyleStack) {
-        for (const auto& clipOrTransform : style.clipsAndTransforms) {
-          if (clipOrTransform.IsClip()) {
-            mTarget->PushClip(clipOrTransform.clip);
-          } else {
-            mTarget->SetTransform(clipOrTransform.transform);
-          }
-        }
-      }
+      RestoreClipsAndTransformToTarget();
     }
   } else {
     EnsureErrorTarget();
     mTarget = sErrorTarget;
     mBufferProvider = nullptr;
   }
 
   // Drop a note in the debug builds if we ever use accelerated Skia canvas.
@@ -1787,17 +1799,17 @@ CanvasRenderingContext2D::ReturnTarget(b
           if (clipOrTransform.IsClip()) {
             mTarget->PopClip();
           }
         }
       }
 
       if (mTarget->GetBackendType() == gfx::BackendType::CAIRO) {
         // With the cairo backend we pushed an extra clip rect which we have to
-        // balance out here. See the comment in EnsureDrawTarget.
+        // balance out here. See the comment in RestoreClipsAndTransformToTarget.
         mTarget->PopClip();
       }
     }
 
     mBufferProvider->ReturnDrawTarget(mTarget.forget());
   }
 }
 
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -638,16 +638,18 @@ protected:
    * is in turn an error in creating the sErrorTarget then they would both
    * be null so IsTargetValid() would still return null.
    *
    * Returns the actual rendering mode being used by the created target.
    */
   RenderingMode EnsureTarget(const gfx::Rect* aCoveredRect = nullptr,
                              RenderingMode aRenderMode = RenderingMode::DefaultBackendMode);
 
+  void RestoreClipsAndTransformToTarget();
+
   /**
    * This method is run at the end of the event-loop spin where
    * ScheduleStableStateCallback was called.
    *
    * We use it to unlock resources that need to be locked while drawing.
    */
   void OnStableState();