Back out 4f682f01262e (bug 857895) for widespread destruction
authorPhil Ringnalda <philringnalda@gmail.com>
Mon, 11 May 2015 19:53:28 -0700
changeset 243451 cef5cc5e60803c2cd7975b2b70ad75fe6cac2b2a
parent 243450 b0ea7f4820e04cdee5221c1c8571550f3ab6b8ca
child 243452 a0a7ad859a667d4bc1a76cf79c9dd064b715a8c8
push id28738
push usercbook@mozilla.com
push dateTue, 12 May 2015 14:11:31 +0000
treeherderautoland@bedce1b405a3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs857895
milestone40.0a1
backs out4f682f01262e830c7d3ec93664c53f92cd6456d2
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
Back out 4f682f01262e (bug 857895) for widespread destruction CLOSED TREE
dom/canvas/CanvasRenderingContext2D.cpp
dom/canvas/CanvasRenderingContext2D.h
dom/media/MediaTaskQueue.cpp
gfx/2d/2D.h
gfx/2d/DrawCommand.h
gfx/2d/DrawTargetCapture.cpp
gfx/2d/DrawTargetCapture.h
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -14,18 +14,16 @@
 
 #include "nsContentUtils.h"
 
 #include "nsIDocument.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "nsSVGEffects.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
-#include "nsWidgetsCID.h"
-#include "nsIAppShell.h"
 
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIFrame.h"
 #include "nsError.h"
 
 #include "nsCSSParser.h"
 #include "mozilla/css/StyleRule.h"
 #include "mozilla/css/Declaration.h"
@@ -111,17 +109,16 @@
 #include "SVGContentUtils.h"
 #include "SVGImageContext.h"
 #include "nsIScreenManager.h"
 #include "nsFilterInstance.h"
 #include "nsSVGLength2.h"
 #include "nsDeviceContext.h"
 #include "nsFontMetrics.h"
 #include "Units.h"
-#include "mozilla/Services.h"
 
 #undef free // apparently defined by some windows header, clashing with a free()
             // method in SkTypes.h
 #include "SkiaGLGlue.h"
 #ifdef USE_SKIA
 #include "SurfaceTypes.h"
 #include "GLBlitHelper.h"
 #endif
@@ -177,74 +174,16 @@ public:
       gCanvasAzureMemoryUsed,
       "Memory used by 2D canvases. Each canvas requires "
       "(width * height * 4) bytes.");
   }
 };
 
 NS_IMPL_ISUPPORTS(Canvas2dPixelsReporter, nsIMemoryReporter)
 
-class CanvasShutdownObserver : public nsIObserver
-{
-  virtual ~CanvasShutdownObserver() {}
-
-public:
-  NS_DECL_ISUPPORTS
-
-  explicit CanvasShutdownObserver(CanvasRenderingContext2D* aCanvas)
-    : mCanvas(aCanvas)
-  {
-    nsCOMPtr<nsIObserverService> observerService =
-      mozilla::services::GetObserverService();
-    observerService->AddObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, false);
-  }
-
-  void Shutdown() {
-    nsCOMPtr<nsIObserverService> observerService =
-      mozilla::services::GetObserverService();
-    observerService->RemoveObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID);
-  }
-
-  NS_IMETHOD Observe(nsISupports* aSubject,
-                     const char* aTopic,
-                     const char16_t* aData) override
-  {
-    mCanvas->ShutdownTaskQueue();
-    return NS_OK;
-  }
-
-private:
-  CanvasRenderingContext2D* mCanvas;
-};
-
-NS_IMPL_ISUPPORTS(CanvasShutdownObserver, nsIObserver);
-
-
-static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
-
-void
-CanvasRenderingContext2D::RecordCommand()
-{
-  static uint32_t kBatchSize = 5;
-  if (++mPendingCommands > kBatchSize) {
-    mPendingCommands = 0;
-    FlushDelayedTarget();
-    return;
-  }
-
-  if (mScheduledFlush) {
-    return;
-  }
-
-  mScheduledFlush = true;
-  nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
-  nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(this, &CanvasRenderingContext2D::StableStateReached);
-  appShell->RunInStableState(r);
-}
-
 class CanvasRadialGradient : public CanvasGradient
 {
 public:
   CanvasRadialGradient(CanvasRenderingContext2D* aContext,
                        const Point &aBeginOrigin, Float aBeginRadius,
                        const Point &aEndOrigin, Float aEndRadius)
     : CanvasGradient(aContext, Type::RADIAL)
     , mCenter1(aBeginOrigin)
@@ -449,21 +388,16 @@ public:
       mFinalTarget, mCtx->CurrentState().filter,
       mgfx::Rect(mPostFilterBounds),
       snapshot, mSourceGraphicRect,
       fillPaint, mFillPaintRect,
       strokePaint, mStrokePaintRect,
       mCtx->CurrentState().filterAdditionalImages,
       mPostFilterBounds.TopLeft() - mOffset,
       DrawOptions(1.0f, mCompositionOp));
-
-    // DrawTargetCapture doesn't properly support filter nodes because they are
-    // mutable. Block until drawing is done to avoid races.
-    mCtx->FlushDelayedTarget();
-    mCtx->FinishDelayedRendering();
   }
 
   DrawTarget* DT()
   {
     return mTarget;
   }
 
 private:
@@ -878,19 +812,16 @@ public:
   static void PreTransactionCallback(void* aData)
   {
     CanvasRenderingContext2DUserData* self =
       static_cast<CanvasRenderingContext2DUserData*>(aData);
     CanvasRenderingContext2D* context = self->mContext;
     if (!context || !context->mTarget)
       return;
 
-    context->FlushDelayedTarget();
-    context->FinishDelayedRendering();
-
     // Since SkiaGL default to store drawing command until flush
     // We will have to flush it before present.
     context->mTarget->Flush();
   }
 
   static void DidTransactionCallback(void* aData)
   {
     CanvasRenderingContext2DUserData* self =
@@ -1002,48 +933,35 @@ CanvasRenderingContext2D::CanvasRenderin
 #ifdef USE_SKIA_GPU
   , mVideoTexture(0)
 #endif
   // these are the default values from the Canvas spec
   , mWidth(0), mHeight(0)
   , mZero(false), mOpaque(false)
   , mResetLayer(true)
   , mIPC(false)
-  , mPendingCommands(0)
-  , mScheduledFlush(false)
   , mDrawObserver(nullptr)
   , mIsEntireFrameInvalid(false)
   , mPredictManyRedrawCalls(false), mPathTransformWillUpdate(false)
   , mInvalidateCount(0)
 {
   sNumLivingContexts++;
 
-#ifdef XP_MACOSX
-  // Restrict async rendering to OSX for now until the failures on other
-  // platforms get resolved.
-  mTaskQueue = new MediaTaskQueue(SharedThreadPool::Get(NS_LITERAL_CSTRING("Canvas Rendering"),
-                                                        4));
-  mShutdownObserver = new CanvasShutdownObserver(this);
-#endif
-
   // The default is to use OpenGL mode
   if (!gfxPlatform::GetPlatform()->UseAcceleratedSkiaCanvas()) {
     mRenderingMode = RenderingMode::SoftwareBackendMode;
   }
 
   if (gfxPlatform::GetPlatform()->HaveChoiceOfHWAndSWCanvas()) {
     mDrawObserver = new CanvasDrawObserver(this);
   }
 }
 
 CanvasRenderingContext2D::~CanvasRenderingContext2D()
 {
-  if (mTaskQueue) {
-    ShutdownTaskQueue();
-  }
   RemoveDrawObserver();
   RemovePostRefreshObserver();
   Reset();
   // Drop references from all CanvasRenderingContext2DUserData to this context
   for (uint32_t i = 0; i < mUserDatas.Length(); ++i) {
     mUserDatas[i]->Forget();
   }
   sNumLivingContexts--;
@@ -1056,29 +974,16 @@ CanvasRenderingContext2D::~CanvasRenderi
     gfxPlatform::GetPlatform()->GetSkiaGLGlue()->GetGLContext()->MakeCurrent();
     gfxPlatform::GetPlatform()->GetSkiaGLGlue()->GetGLContext()->fDeleteTextures(1, &mVideoTexture);
   }
 #endif
 
   RemoveDemotableContext(this);
 }
 
-void
-CanvasRenderingContext2D::ShutdownTaskQueue()
-{
-  mShutdownObserver->Shutdown();
-  mShutdownObserver = nullptr;
-  FlushDelayedTarget();
-  FinishDelayedRendering();
-  mTaskQueue->BeginShutdown();
-  mTaskQueue = nullptr;
-  mDelayedTarget = nullptr;
-}
-
-
 JSObject*
 CanvasRenderingContext2D::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
 {
   return CanvasRenderingContext2DBinding::Wrap(cx, this, aGivenProto);
 }
 
 bool
 CanvasRenderingContext2D::ParseColor(const nsAString& aString,
@@ -1124,20 +1029,17 @@ CanvasRenderingContext2D::Reset()
   }
 
   // only do this for non-docshell created contexts,
   // since those are the ones that we created a surface for
   if (mTarget && IsTargetValid() && !mDocShell) {
     gCanvasAzureMemoryUsed -= mWidth * mHeight * 4;
   }
 
-  FinishDelayedRendering();
   mTarget = nullptr;
-  mDelayedTarget = nullptr;
-  mFinalTarget = nullptr;
 
   // reset hit regions
   mHitRegionsOptions.ClearAndRetainStorage();
 
   // Since the target changes the backing texture will change, and this will
   // no longer be valid.
   mIsEntireFrameInvalid = false;
   mPredictManyRedrawCalls = false;
@@ -1194,18 +1096,16 @@ CanvasRenderingContext2D::StyleColorToSt
     aStr.AppendFloat(nsStyleUtil::ColorComponentToFloat(NS_GET_A(aColor)));
     aStr.Append(')');
   }
 }
 
 nsresult
 CanvasRenderingContext2D::Redraw()
 {
-  RecordCommand();
-
   if (mIsEntireFrameInvalid) {
     return NS_OK;
   }
 
   mIsEntireFrameInvalid = true;
 
   if (!mCanvasElement) {
     NS_ASSERTION(mDocShell, "Redraw with no canvas element or docshell!");
@@ -1217,17 +1117,16 @@ CanvasRenderingContext2D::Redraw()
   mCanvasElement->InvalidateCanvasContent(nullptr);
 
   return NS_OK;
 }
 
 void
 CanvasRenderingContext2D::Redraw(const mgfx::Rect &r)
 {
-  RecordCommand();
   ++mInvalidateCount;
 
   if (mIsEntireFrameInvalid) {
     return;
   }
 
   if (mPredictManyRedrawCalls ||
     mInvalidateCount > kCanvasMaxInvalidateCount) {
@@ -1240,28 +1139,16 @@ CanvasRenderingContext2D::Redraw(const m
     return;
   }
 
   nsSVGEffects::InvalidateDirectRenderingObservers(mCanvasElement);
 
   mCanvasElement->InvalidateCanvasContent(&r);
 }
 
-TemporaryRef<SourceSurface>
-CanvasRenderingContext2D::GetSurfaceSnapshot(bool* aPremultAlpha /* = nullptr */)
-{
-  EnsureTarget();
-  if (aPremultAlpha) {
-    *aPremultAlpha = true;
-  }
-  FlushDelayedTarget();
-  FinishDelayedRendering();
-  return mFinalTarget->Snapshot();
-}
-
 void
 CanvasRenderingContext2D::DidRefresh()
 {
   if (IsTargetValid() && SkiaGLTex()) {
     SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
     MOZ_ASSERT(glue);
 
     auto gl = glue->GetGLContext();
@@ -1269,17 +1156,16 @@ CanvasRenderingContext2D::DidRefresh()
   }
 }
 
 void
 CanvasRenderingContext2D::RedrawUser(const gfxRect& r)
 {
   if (mIsEntireFrameInvalid) {
     ++mInvalidateCount;
-    RecordCommand();
     return;
   }
 
   mgfx::Rect newr =
     mTarget->GetTransform().TransformBounds(ToRect(r));
   Redraw(newr);
 }
 
@@ -1295,17 +1181,17 @@ bool CanvasRenderingContext2D::SwitchRen
       gfxPlatform::GetPlatform()->GetSkiaGLGlue()->GetGLContext()->MakeCurrent();
       gfxPlatform::GetPlatform()->GetSkiaGLGlue()->GetGLContext()->fDeleteTextures(1, &mVideoTexture);
     }
 	  mCurrentVideoSize.width = 0;
 	  mCurrentVideoSize.height = 0;
   }
 #endif
 
-  RefPtr<SourceSurface> snapshot = GetSurfaceSnapshot();
+  RefPtr<SourceSurface> snapshot = mTarget->Snapshot();
   RefPtr<DrawTarget> oldTarget = mTarget;
   mTarget = nullptr;
   mResetLayer = true;
 
   // Recreate target using the new rendering mode
   RenderingMode attemptedMode = EnsureTarget(aRenderingMode);
   if (!IsTargetValid())
     return false;
@@ -1469,54 +1355,38 @@ CanvasRenderingContext2D::EnsureTarget(R
           gfxPlatform::GetPlatform()->UseAcceleratedSkiaCanvas() &&
           CheckSizeForSkiaGL(size)) {
         DemoteOldestContextIfNecessary();
 
 #if USE_SKIA_GPU
         SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
 
         if (glue && glue->GetGrContext() && glue->GetGLContext()) {
-          // Don't use mFinalTarget (async canvas drawing) with SkiaGL, because we currently
-          // use a single GLContext and need them all to be on the same thread.
           mTarget = Factory::CreateDrawTargetSkiaWithGrContext(glue->GetGrContext(), size, format);
           if (mTarget) {
             AddDemotableContext(this);
           } else {
             printf_stderr("Failed to create a SkiaGL DrawTarget, falling back to software\n");
             mode = RenderingMode::SoftwareBackendMode;
           }
         }
 #endif
         if (!mTarget) {
-          mFinalTarget = layerManager->CreateDrawTarget(size, format);
+          mTarget = layerManager->CreateDrawTarget(size, format);
         }
       } else {
-        mFinalTarget = layerManager->CreateDrawTarget(size, format);
+        mTarget = layerManager->CreateDrawTarget(size, format);
         mode = RenderingMode::SoftwareBackendMode;
       }
      } else {
-        mFinalTarget = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(size, format);
+        mTarget = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(size, format);
         mode = RenderingMode::SoftwareBackendMode;
      }
   }
 
-  // Restrict async canvas drawing to OSX for now since we get test failures
-  // on other platforms.
-#ifdef XP_MACOSX
-  if (mFinalTarget) {
-    mTarget = mDelayedTarget = mFinalTarget->CreateCaptureDT(size);
-  } else {
-    mFinalTarget = mTarget;
-  }
-#else
-  mFinalTarget = mTarget;
-#endif
-
-  mPendingCommands = 0;
-
   if (mTarget) {
     static bool registered = false;
     if (!registered) {
       registered = true;
       RegisterStrongMemoryReporter(new Canvas2dPixelsReporter());
     }
 
     gCanvasAzureMemoryUsed += mWidth * mHeight * 4;
@@ -1540,17 +1410,17 @@ CanvasRenderingContext2D::EnsureTarget(R
     if (mCanvasElement) {
       mCanvasElement->InvalidateCanvas();
     }
     // Calling Redraw() tells our invalidation machinery that the entire
     // canvas is already invalid, which can speed up future drawing.
     Redraw();
   } else {
     EnsureErrorTarget();
-    mTarget = mFinalTarget = sErrorTarget;
+    mTarget = sErrorTarget;
   }
 
   return mode;
 }
 
 #ifdef DEBUG
 int32_t
 CanvasRenderingContext2D::GetWidth() const
@@ -1560,61 +1430,16 @@ CanvasRenderingContext2D::GetWidth() con
 
 int32_t
 CanvasRenderingContext2D::GetHeight() const
 {
   return mHeight;
 }
 #endif
 
-class DrawCaptureTask : public nsRunnable
-{
-public:
-  DrawCaptureTask(DrawTargetCapture *aReplay, DrawTarget* aDest)
-    : mReplay(aReplay)
-    , mDest(aDest)
-  {
-  }
-
-  NS_IMETHOD Run()
-  {
-    mDest->DrawCapturedDT(mReplay, Matrix());
-    return NS_OK;
-  }
-
-private:
-  RefPtr<DrawTargetCapture> mReplay;
-  RefPtr<DrawTarget> mDest;
-};
-
-void
-CanvasRenderingContext2D::FlushDelayedTarget()
-{
-  if (!mDelayedTarget) {
-    return;
-  }
-  mPendingCommands = 0;
-
-  nsCOMPtr<nsIRunnable> task = new DrawCaptureTask(mDelayedTarget, mFinalTarget);
-  mTaskQueue->Dispatch(task.forget());
-
-  mDelayedTarget = mFinalTarget->CreateCaptureDT(IntSize(mWidth, mHeight));
-
-  mDelayedTarget->SetTransform(mTarget->GetTransform());
-  mTarget = mDelayedTarget;
-}
-
-void
-CanvasRenderingContext2D::FinishDelayedRendering()
-{
-  if (mTaskQueue) {
-    mTaskQueue->AwaitIdle();
-  }
-}
-
 NS_IMETHODIMP
 CanvasRenderingContext2D::SetDimensions(int32_t width, int32_t height)
 {
   ClearTarget();
 
   // Zero sized surfaces can cause problems.
   mZero = false;
   if (height == 0) {
@@ -1754,17 +1579,17 @@ CanvasRenderingContext2D::SetContextOpti
 void
 CanvasRenderingContext2D::GetImageBuffer(uint8_t** aImageBuffer,
                                          int32_t* aFormat)
 {
   *aImageBuffer = nullptr;
   *aFormat = 0;
 
   EnsureTarget();
-  RefPtr<SourceSurface> snapshot = GetSurfaceSnapshot();
+  RefPtr<SourceSurface> snapshot = mTarget->Snapshot();
   if (!snapshot) {
     return;
   }
 
   RefPtr<DataSourceSurface> data = snapshot->GetDataSurface();
   if (!data || data->GetSize() != IntSize(mWidth, mHeight)) {
     return;
   }
@@ -2173,17 +1998,17 @@ CanvasRenderingContext2D::CreatePattern(
   }
 
   EnsureTarget();
 
   // The canvas spec says that createPattern should use the first frame
   // of animated images
   nsLayoutUtils::SurfaceFromElementResult res =
     nsLayoutUtils::SurfaceFromElement(htmlElement,
-      nsLayoutUtils::SFE_WANT_FIRST_FRAME, mFinalTarget);
+      nsLayoutUtils::SFE_WANT_FIRST_FRAME, mTarget);
 
   if (!res.mSourceSurface) {
     error.Throw(NS_ERROR_NOT_AVAILABLE);
     return nullptr;
   }
 
   nsRefPtr<CanvasPattern> pat =
     new CanvasPattern(this, res.mSourceSurface, repeatMode, res.mPrincipal,
@@ -4484,17 +4309,17 @@ CanvasRenderingContext2D::DrawImage(cons
     // The cache lookup can miss even if the image is already in the cache
     // if the image is coming from a different element or cached for a
     // different canvas. This covers the case when we miss due to caching
     // for a different canvas, but CanvasImageCache should be fixed if we
     // see misses due to different elements drawing the same image.
     nsLayoutUtils::SurfaceFromElementResult res =
       CachedSurfaceFromElement(element);
     if (!res.mSourceSurface)
-      res = nsLayoutUtils::SurfaceFromElement(element, sfeFlags, mFinalTarget);
+      res = nsLayoutUtils::SurfaceFromElement(element, sfeFlags, mTarget);
 
     if (!res.mSourceSurface && !res.mDrawInfo.mImgContainer) {
       // The spec says to silently do nothing in the following cases:
       //   - The element is still loading.
       //   - The image is bad, but it's not in the broken state (i.e., we could
       //     decode the headers and get the size).
       if (!res.mIsStillLoading && !res.mHasSize) {
         error.Throw(NS_ERROR_NOT_AVAILABLE);
@@ -4828,22 +4653,17 @@ CanvasRenderingContext2D::DrawWindow(nsG
   }
   nsRefPtr<gfxContext> thebes;
   RefPtr<DrawTarget> drawDT;
   // Rendering directly is faster and can be done if mTarget supports Azure
   // and does not need alpha blending.
   if (gfxPlatform::GetPlatform()->SupportsAzureContentForDrawTarget(mTarget) &&
       GlobalAlpha() == 1.0f)
   {
-    // Complete any async rendering and use synchronous rendering for DrawWindow
-    // until we're confident it works for all content.
-    FlushDelayedTarget();
-    FinishDelayedRendering();
-
-    thebes = new gfxContext(mFinalTarget);
+    thebes = new gfxContext(mTarget);
     thebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21,
                                 matrix._22, matrix._31, matrix._32));
   } else {
     drawDT =
       gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(ceil(sw), ceil(sh)),
                                                                    SurfaceFormat::B8G8R8A8);
     if (!drawDT) {
       error.Throw(NS_ERROR_FAILURE);
@@ -5090,17 +4910,17 @@ CanvasRenderingContext2D::GetImageDataAr
     return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
   IntRect srcRect(0, 0, mWidth, mHeight);
   IntRect destRect(aX, aY, aWidth, aHeight);
   IntRect srcReadRect = srcRect.Intersect(destRect);
   RefPtr<DataSourceSurface> readback;
   if (!srcReadRect.IsEmpty() && !mZero) {
-    RefPtr<SourceSurface> snapshot = GetSurfaceSnapshot();
+    RefPtr<SourceSurface> snapshot = mTarget->Snapshot();
     if (snapshot) {
       readback = snapshot->GetDataSurface();
     }
     if (!readback || !readback->GetData()) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
@@ -5464,17 +5284,17 @@ CanvasRenderingContext2D::GetCanvasLayer
   // layer manager which must NOT happen during a paint.
   if (!mTarget || !IsTargetValid()) {
     // No DidTransactionCallback will be received, so mark the context clean
     // now so future invalidations will be dispatched.
     MarkContextClean();
     return nullptr;
   }
 
-  FlushDelayedTarget();
+  mTarget->Flush();
 
   if (!mResetLayer && aOldLayer) {
     CanvasRenderingContext2DUserData* userData =
       static_cast<CanvasRenderingContext2DUserData*>(
         aOldLayer->GetUserData(&g2DContextLayerUserData));
 
     CanvasLayer::Data data;
 
@@ -5513,33 +5333,34 @@ CanvasRenderingContext2D::GetCanvasLayer
   // The layer will be destroyed when we tear down the presentation
   // (at the latest), at which time this userData will be destroyed,
   // releasing the reference to the element.
   // The userData will receive DidTransactionCallbacks, which flush the
   // the invalidation state to indicate that the canvas is up to date.
   userData = new CanvasRenderingContext2DUserData(this);
   canvasLayer->SetDidTransactionCallback(
           CanvasRenderingContext2DUserData::DidTransactionCallback, userData);
-  canvasLayer->SetPreTransactionCallback(
-          CanvasRenderingContext2DUserData::PreTransactionCallback, userData);
   canvasLayer->SetUserData(&g2DContextLayerUserData, userData);
 
   CanvasLayer::Data data;
   data.mSize = nsIntSize(mWidth, mHeight);
   data.mHasAlpha = !mOpaque;
 
   GLuint skiaGLTex = SkiaGLTex();
   if (skiaGLTex) {
+    canvasLayer->SetPreTransactionCallback(
+            CanvasRenderingContext2DUserData::PreTransactionCallback, userData);
+
     SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
     MOZ_ASSERT(glue);
 
     data.mGLContext = glue->GetGLContext();
     data.mFrontbufferGLTex = skiaGLTex;
   } else {
-    data.mDrawTarget = mFinalTarget;
+    data.mDrawTarget = mTarget;
   }
 
   canvasLayer->Initialize(data);
   uint32_t flags = mOpaque ? Layer::CONTENT_OPAQUE : 0;
   canvasLayer->SetContentFlags(flags);
   canvasLayer->Updated();
 
   mResetLayer = false;
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -5,17 +5,16 @@
 #ifndef CanvasRenderingContext2D_h
 #define CanvasRenderingContext2D_h
 
 #include "mozilla/Attributes.h"
 #include <vector>
 #include "nsIDOMCanvasRenderingContext2D.h"
 #include "nsICanvasRenderingContextInternal.h"
 #include "mozilla/RefPtr.h"
-#include "mozilla/Monitor.h"
 #include "nsColor.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "CanvasUtils.h"
 #include "gfxTextRun.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/CanvasGradient.h"
 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
@@ -23,17 +22,16 @@
 #include "mozilla/gfx/Rect.h"
 #include "mozilla/gfx/2D.h"
 #include "gfx2DGlue.h"
 #include "imgIEncoder.h"
 #include "nsLayoutUtils.h"
 #include "mozilla/EnumeratedArray.h"
 #include "FilterSupport.h"
 #include "nsSVGEffects.h"
-#include "MediaTaskQueue.h"
 
 class nsGlobalWindow;
 class nsXULElement;
 
 namespace mozilla {
 namespace gl {
 class SourceSurface;
 }
@@ -49,17 +47,16 @@ class CanvasPath;
 
 extern const mozilla::gfx::Float SIGMA_MAX;
 
 template<typename T> class Optional;
 
 struct CanvasBidiProcessor;
 class CanvasRenderingContext2DUserData;
 class CanvasDrawObserver;
-class CanvasShutdownObserver;
 
 /**
  ** CanvasRenderingContext2D
  **/
 class CanvasRenderingContext2D final :
   public nsICanvasRenderingContextInternal,
   public nsWrapperCache
 {
@@ -440,17 +437,24 @@ public:
   }
   NS_IMETHOD SetDimensions(int32_t width, int32_t height) override;
   NS_IMETHOD InitializeWithSurface(nsIDocShell *shell, gfxASurface *surface, int32_t width, int32_t height) override;
 
   NS_IMETHOD GetInputStream(const char* aMimeType,
                             const char16_t* aEncoderOptions,
                             nsIInputStream **aStream) override;
 
-  mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr) override;
+  mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr) override
+  {
+    EnsureTarget();
+    if (aPremultAlpha) {
+      *aPremultAlpha = true;
+    }
+    return mTarget->Snapshot();
+  }
 
   NS_IMETHOD SetIsOpaque(bool isOpaque) override;
   bool GetIsOpaque() override { return mOpaque; }
   NS_IMETHOD Reset() override;
   already_AddRefed<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                                CanvasLayer *aOldLayer,
                                                LayerManager *aManager) override;
   virtual bool ShouldForceInactiveLayer(LayerManager *aManager) override;
@@ -512,43 +516,27 @@ public:
       mozilla::gfx::Matrix transform = mTarget->GetTransform();
       mDSPathBuilder->BezierTo(transform * aCP1,
                                 transform * aCP2,
                                 transform * aCP3);
     }
   }
 
   friend class CanvasRenderingContext2DUserData;
-  friend class CanvasShutdownObserver;
 
   virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat) override;
 
 
   // Given a point, return hit region ID if it exists
   nsString GetHitRegion(const mozilla::gfx::Point& aPoint) override;
 
 
   // return true and fills in the bound rect if element has a hit region.
   bool GetHitRegionRect(Element* aElement, nsRect& aRect) override;
 
-  /**
-   * Deferred rendering functions
-   */
-
-  /**
-   * Called when the event loop reaches a stable
-   * state, and trigger us to flush any outstanding
-   * commands to the rendering thread.
-   */
-  void StableStateReached()
-  {
-    mScheduledFlush = false;
-    FlushDelayedTarget();
-  }
-
 protected:
   nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
                              uint32_t aWidth, uint32_t aHeight,
                              JSObject** aRetval);
 
   nsresult PutImageData_explicit(int32_t x, int32_t y, uint32_t w, uint32_t h,
                                  dom::Uint8ClampedArray* aArray,
                                  bool hasDirtyRect, int32_t dirtyX, int32_t dirtyY,
@@ -557,18 +545,16 @@ protected:
   /**
    * Internal method to complete initialisation, expects mTarget to have been set
    */
   nsresult Initialize(int32_t width, int32_t height);
 
   nsresult InitializeWithTarget(mozilla::gfx::DrawTarget *surface,
                                 int32_t width, int32_t height);
 
-  void ShutdownTaskQueue();
-
   /**
     * The number of living nsCanvasRenderingContexts.  When this goes down to
     * 0, we free the premultiply and unpremultiply tables, if they exist.
     */
   static uint32_t sNumLivingContexts;
 
   /**
     * Lookup table used to speed up GetImageData().
@@ -722,64 +708,16 @@ protected:
   // If mCanvasElement is not provided, then a docshell is
   nsCOMPtr<nsIDocShell> mDocShell;
 
   // This is created lazily so it is necessary to call EnsureTarget before
   // accessing it. In the event of an error it will be equal to
   // sErrorTarget.
   mozilla::RefPtr<mozilla::gfx::DrawTarget> mTarget;
 
-  /**
-   * Deferred rendering implementation
-   */
-
-  // If we are using deferred rendering, then this is the current
-  // deferred rendering target. It is the same pointer as mTarget.
-  mozilla::RefPtr<mozilla::gfx::DrawTargetCapture> mDelayedTarget;
-
-  // If we are using deferred rendering, then this is the actual destination
-  // buffer.
-  mozilla::RefPtr<mozilla::gfx::DrawTarget> mFinalTarget;
-
-  /**
-   * Add the current DelayedDrawTarget to the rendering queue,
-   * schedule a rendering job if required, and create a new
-   * DelayedDrawTarget.
-   */
-  void FlushDelayedTarget();
-
-  /**
-   * Make sure all commands have been flushed to
-   * the rendering thread, and block until they
-   * are completed.
-   */
-  void FinishDelayedRendering();
-
-  /**
-   * Called when a command is added to the current
-   * delayed draw target.
-   *
-   * Either flushes the current batch of commands to
-   * the rendering thread, or ensures that this happens
-   * the next time the event loop reaches a stable state.
-   */
-  void RecordCommand();
-
-  // The number of commands currently waiting to be sent
-  // to the rendering thread.
-  uint32_t mPendingCommands;
-
-  // True if we have scheduled FlushDelayedTarget to be
-  // called in the next browser stable state.
-  bool mScheduledFlush;
-
-  nsRefPtr<MediaTaskQueue> mTaskQueue;
-
-  nsRefPtr<CanvasShutdownObserver> mShutdownObserver;
-
   uint32_t SkiaGLTex() const;
 
   // This observes our draw calls at the beginning of the canvas
   // lifetime and switches to software or GPU mode depending on
   // what it thinks is best
   CanvasDrawObserver* mDrawObserver;
   void RemoveDrawObserver();
 
--- a/dom/media/MediaTaskQueue.cpp
+++ b/dom/media/MediaTaskQueue.cpp
@@ -22,17 +22,16 @@ MediaTaskQueue::MediaTaskQueue(Temporary
 {
   MOZ_COUNT_CTOR(MediaTaskQueue);
 }
 
 MediaTaskQueue::~MediaTaskQueue()
 {
   MonitorAutoLock mon(mQueueMonitor);
   MOZ_ASSERT(mIsShutdown);
-  MOZ_DIAGNOSTIC_ASSERT(mTasks.empty());
   MOZ_COUNT_DTOR(MediaTaskQueue);
 }
 
 TaskDispatcher&
 MediaTaskQueue::TailDispatcher()
 {
   MOZ_ASSERT(IsCurrentThreadIn());
   MOZ_ASSERT(mTailDispatcher);
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -150,17 +150,17 @@ struct DrawSurfaceOptions {
 
 };
 
 /**
  * This class is used to store gradient stops, it can only be used with a
  * matching DrawTarget. Not adhering to this condition will make a draw call
  * fail.
  */
-class GradientStops : public external::AtomicRefCounted<GradientStops>
+class GradientStops : public RefCounted<GradientStops>
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GradientStops)
   virtual ~GradientStops() {}
 
   virtual BackendType GetBackendType() const = 0;
   virtual bool IsValid() const { return true; }
 
@@ -313,17 +313,17 @@ public:
 class StoredPattern;
 class DrawTargetCaptureImpl;
 
 /**
  * This is the base class for source surfaces. These objects are surfaces
  * which may be used as a source in a SurfacePattern or a DrawSurface call.
  * They cannot be drawn to directly.
  */
-class SourceSurface : public external::AtomicRefCounted<SourceSurface>
+class SourceSurface : public RefCounted<SourceSurface>
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurface)
   virtual ~SourceSurface() {}
 
   virtual SurfaceType GetType() const = 0;
   virtual IntSize GetSize() const = 0;
   virtual SurfaceFormat GetFormat() const = 0;
@@ -471,17 +471,17 @@ public:
 };
 
 class PathBuilder;
 class FlattenedPath;
 
 /** The path class is used to create (sets of) figures of any shape that can be
  * filled or stroked to a DrawTarget
  */
-class Path : public external::AtomicRefCounted<Path>
+class Path : public RefCounted<Path>
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(Path)
   virtual ~Path();
   
   virtual BackendType GetBackendType() const = 0;
 
   /** This returns a PathBuilder object that contains a copy of the contents of
@@ -572,17 +572,17 @@ struct GlyphBuffer
   const Glyph *mGlyphs; //!< A pointer to a buffer of glyphs. Managed by the caller.
   uint32_t mNumGlyphs;  //!< Number of glyphs mGlyphs points to.
 };
 
 /** This class is an abstraction of a backend/platform specific font object
  * at a particular size. It is passed into text drawing calls to describe
  * the font used for the drawing call.
  */
-class ScaledFont : public external::AtomicRefCounted<ScaledFont>
+class ScaledFont : public RefCounted<ScaledFont>
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFont)
   virtual ~ScaledFont() {}
 
   typedef void (*FontFileDataOutput)(const uint8_t *aData, uint32_t aLength, uint32_t aIndex, Float aGlyphSize, void *aBaton);
 
   virtual FontType GetType() const = 0;
@@ -617,17 +617,17 @@ protected:
 };
 
 /** This class is designed to allow passing additional glyph rendering
  * parameters to the glyph drawing functions. This is an empty wrapper class
  * merely used to allow holding on to and passing around platform specific
  * parameters. This is because different platforms have unique rendering
  * parameters.
  */
-class GlyphRenderingOptions : public external::AtomicRefCounted<GlyphRenderingOptions>
+class GlyphRenderingOptions : public RefCounted<GlyphRenderingOptions>
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GlyphRenderingOptions)
   virtual ~GlyphRenderingOptions() {}
 
   virtual FontType GetType() const = 0;
 
 protected:
@@ -636,17 +636,17 @@ protected:
 
 class DrawTargetCapture;
 
 /** This is the main class used for all the drawing. It is created through the
  * factory and accepts drawing commands. The results of drawing to a target
  * may be used either through a Snapshot or by flushing the target and directly
  * accessing the backing store a DrawTarget was created with.
  */
-class DrawTarget : public external::AtomicRefCounted<DrawTarget>
+class DrawTarget : public RefCounted<DrawTarget>
 {
 public:
   MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTarget)
   DrawTarget() : mTransformDirty(false), mPermitSubpixelAA(false) {}
   virtual ~DrawTarget() {}
 
   virtual DrawTargetType GetType() const = 0;
 
--- a/gfx/2d/DrawCommand.h
+++ b/gfx/2d/DrawCommand.h
@@ -143,17 +143,17 @@ private:
   DrawOptions mOptions;
 };
 
 class DrawFilterCommand : public DrawingCommand
 {
 public:
   DrawFilterCommand(FilterNode* aFilter, const Rect& aSourceRect,
                     const Point& aDestPoint, const DrawOptions& aOptions)
-    : DrawingCommand(CommandType::DRAWFILTER)
+    : DrawingCommand(CommandType::DRAWSURFACE)
     , mFilter(aFilter), mSourceRect(aSourceRect)
     , mDestPoint(aDestPoint), mOptions(aOptions)
   {
   }
 
   virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&)
   {
     aDT->DrawFilter(mFilter, mSourceRect, mDestPoint, mOptions);
@@ -161,46 +161,16 @@ public:
 
 private:
   RefPtr<FilterNode> mFilter;
   Rect mSourceRect;
   Point mDestPoint;
   DrawOptions mOptions;
 };
 
-class DrawSurfaceWithShadowCommand : public DrawingCommand
-{
-public:
-  DrawSurfaceWithShadowCommand(SourceSurface* aSurface, const Point& aDest,
-                               const Color& aColor, const Point& aOffset,
-                               Float aSigma, CompositionOp aOperator)
-    : DrawingCommand(CommandType::DRAWSURFACEWITHSHADOW)
-    , mSurface(aSurface)
-    , mDest(aDest)
-    , mColor(aColor)
-    , mOffset(aOffset)
-    , mSigma(aSigma)
-    , mOperator(aOperator)
-  {
-  }
-
-  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix&)
-  {
-    aDT->DrawSurfaceWithShadow(mSurface, mDest, mColor, mOffset, mSigma, mOperator);
-  }
-
-private:
-  RefPtr<SourceSurface> mSurface;
-  Point mDest;
-  Color mColor;
-  Point mOffset;
-  Float mSigma;
-  CompositionOp mOperator;
-};
-
 class ClearRectCommand : public DrawingCommand
 {
 public:
   explicit ClearRectCommand(const Rect& aRect)
     : DrawingCommand(CommandType::CLEARRECT)
     , mRect(aRect)
   {
   }
--- a/gfx/2d/DrawTargetCapture.cpp
+++ b/gfx/2d/DrawTargetCapture.cpp
@@ -25,17 +25,16 @@ DrawTargetCaptureImpl::~DrawTargetCaptur
 bool
 DrawTargetCaptureImpl::Init(const IntSize& aSize, DrawTarget* aRefDT)
 {
   if (!aRefDT) {
     return false;
   }
 
   mRefDT = aRefDT;
-  mFormat = mRefDT->GetFormat();
 
   mSize = aSize;
   return true;
 }
 
 TemporaryRef<SourceSurface>
 DrawTargetCaptureImpl::Snapshot()
 {
@@ -66,28 +65,16 @@ DrawTargetCaptureImpl::DrawFilter(Filter
                                   const DrawOptions &aOptions)
 {
   // @todo XXX - this won't work properly long term yet due to filternodes not
   // being immutable.
   AppendCommand(DrawFilterCommand)(aNode, aSourceRect, aDestPoint, aOptions);
 }
 
 void
-DrawTargetCaptureImpl::DrawSurfaceWithShadow(SourceSurface *aSurface,
-                                             const Point &aDest,
-                                             const Color &aColor,
-                                             const Point &aOffset,
-                                             Float aSigma,
-                                             CompositionOp aOperator)
-{
-  aSurface->GuaranteePersistance();
-  AppendCommand(DrawSurfaceWithShadowCommand)(aSurface, aDest, aColor, aOffset, aSigma, aOperator);
-}
-
-void
 DrawTargetCaptureImpl::ClearRect(const Rect &aRect)
 {
   AppendCommand(ClearRectCommand)(aRect);
 }
 
 void
 DrawTargetCaptureImpl::MaskSurface(const Pattern &aSource,
                                    SourceSurface *aMask,
@@ -186,17 +173,16 @@ DrawTargetCaptureImpl::PopClip()
 {
   AppendCommand(PopClipCommand)();
 }
 
 void
 DrawTargetCaptureImpl::SetTransform(const Matrix& aTransform)
 {
   AppendCommand(SetTransformCommand)(aTransform);
-  mTransform = aTransform;
 }
 
 void
 DrawTargetCaptureImpl::ReplayToDrawTarget(DrawTarget* aDT, const Matrix& aTransform)
 {
   uint8_t* start = &mDrawCommandStorage.front();
 
   uint8_t* current = start;
--- a/gfx/2d/DrawTargetCapture.h
+++ b/gfx/2d/DrawTargetCapture.h
@@ -40,17 +40,17 @@ public:
                           const Rect &aSourceRect,
                           const Point &aDestPoint,
                           const DrawOptions &aOptions = DrawOptions());
   virtual void DrawSurfaceWithShadow(SourceSurface *aSurface,
                                      const Point &aDest,
                                      const Color &aColor,
                                      const Point &aOffset,
                                      Float aSigma,
-                                     CompositionOp aOperator);
+                                     CompositionOp aOperator) { /* Not implemented */ }
 
   virtual void ClearRect(const Rect &aRect);
   virtual void MaskSurface(const Pattern &aSource,
                            SourceSurface *aMask,
                            Point aOffset,
                            const DrawOptions &aOptions = DrawOptions());
 
   virtual void CopySurface(SourceSurface *aSurface,