Bug 1379920 - Introduce CanvasRenderer and its derived classes. r=nical,jrmuizel draft
authorMorris Tseng <mtseng@mozilla.com>
Tue, 18 Jul 2017 16:55:47 +0800
changeset 612086 ac2020aa6f595f38965dc25a13e0a9e99b677d58
parent 612085 ab9ea9c68c7684ca5e508519c38f1a65c6708122
child 612087 0fd99692c8b454df0898620318bb889410f67872
push id69379
push userbmo:mtseng@mozilla.com
push dateThu, 20 Jul 2017 09:19:49 +0000
reviewersnical, jrmuizel
bugs1379920
milestone56.0a1
Bug 1379920 - Introduce CanvasRenderer and its derived classes. r=nical,jrmuizel This patch move common canvas interfaces out of layer. So I create a base class CanvasRenderer which move interfaces from CanvasLayer. CopyableCanvasRenderer from CopyableCanvasLayer, ClientCanvasRenderer from ClientCanvasLayer and WebRenderCanvasRenderer from WebRenderCanvasLayer. And finally, WebRenderCanvasRendererSync for the non layers free mode and WebRenderCanvasRendererAsync for the layers free mode. Summary all changes in this patch. * Move class CanvasLayer::Data to CanvasRenderer.h and rename it to CanvasInitializeData. Because this class not only use by layer but also * Move BasicCanvasLayer::UpdateSurface to CopyableCanvasRenderer::ReadbackSurface. * CanvasClient::Update now accepts ShareableCanvasRenderer as parameter. not CanvasLayer. use by layers-free mode. Move it out of layer's class makes more sense. * Add InitializeCanvasRenderer in the canvas related classes to initialize CanvasRenderer without involved layer. * All canvas layer has function "CreateCanvasRendererInternal" that initialize corresponding CanvasRenderer. * Description of all CanvasRenderer classes: ** CanvasRenderer: Based classes. ** CopyableCanvasRenderer: Can readback canvas content to a SourceSurface. Use by BasicCanvasLayer. ** ShareableCanvasRenderer: Provide IPC capabilities that allow sending canvas content over IPC. This is pure virtual class because the IPC handling is different in different LayerManager. ** ClientCanvasRenderer: Implement IPC handling for ClientLayerManager. Use by ClientCanvasLayer. ** WebRenderCanvasRenderer: Implement IPC handling for WebRenderLayerManager. ** WebRenderCanvasRendererSync: Use by WebRenderCanvasLayer. ** WebRenderCanvasRendererAsync: Use by layers-free mode in WebRender. class diagram shows below: +--------------+ |CanvasRenderer| +-------+------+ ^ | +----------------------+ |CopyableCanvasRenderer| +----------------------+ ^ | +-----------+-----------+ |ShareableCanvasRenderer| +-----+-----------------+ ^ ^ +-------------+ +-------+ | | +--------------------+ +---------+-------------+ |ClientCanvasRenderer| |WebRenderCanvasRenderer| +--------------------+ +--------+--+-----------+ ^ ^ +-----------------------+ +----+ | | +-------------+-------------+ +-------------+--------------+ |WebRenderCanvasRendererSync| |WebRenderCanvasRendererAsync| +---------------------------+ +----------------------------+ MozReview-Commit-ID: 5hqQ19W169r
dom/canvas/CanvasRenderingContext2D.cpp
dom/canvas/CanvasRenderingContext2D.h
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
dom/canvas/nsICanvasRenderingContextInternal.h
dom/html/HTMLCanvasElement.cpp
dom/html/HTMLCanvasElement.h
gfx/layers/CanvasRenderer.cpp
gfx/layers/CanvasRenderer.h
gfx/layers/CopyableCanvasRenderer.cpp
gfx/layers/CopyableCanvasRenderer.h
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/ShareableCanvasRenderer.cpp
gfx/layers/ShareableCanvasRenderer.h
gfx/layers/basic/BasicCanvasLayer.cpp
gfx/layers/basic/BasicCanvasLayer.h
gfx/layers/client/CanvasClient.cpp
gfx/layers/client/CanvasClient.h
gfx/layers/client/ClientCanvasLayer.cpp
gfx/layers/client/ClientCanvasLayer.h
gfx/layers/client/ClientCanvasRenderer.cpp
gfx/layers/client/ClientCanvasRenderer.h
gfx/layers/composite/CanvasLayerComposite.h
gfx/layers/mlgpu/CanvasLayerMLGPU.h
gfx/layers/moz.build
gfx/layers/wr/WebRenderCanvasLayer.cpp
gfx/layers/wr/WebRenderCanvasLayer.h
gfx/layers/wr/WebRenderCanvasRenderer.cpp
gfx/layers/wr/WebRenderCanvasRenderer.h
layout/generic/nsHTMLCanvasFrame.cpp
layout/generic/nsHTMLCanvasFrame.h
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -931,33 +931,32 @@ public:
   {
     if (mContext) {
       mContext->mUserDatas.RemoveElement(this);
     }
   }
 
   static void PreTransactionCallback(void* aData)
   {
-    auto self = static_cast<CanvasRenderingContext2DUserData*>(aData);
-    CanvasRenderingContext2D* context = self->mContext;
+    CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(aData);
     if (!context || !context->mTarget)
       return;
 
     context->OnStableState();
   }
 
   static void DidTransactionCallback(void* aData)
   {
-    auto self = static_cast<CanvasRenderingContext2DUserData*>(aData);
-    if (self->mContext) {
-      self->mContext->MarkContextClean();
-      if (self->mContext->mDrawObserver) {
-        if (self->mContext->mDrawObserver->FrameEnd()) {
+    CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(aData);
+    if (context) {
+      context->MarkContextClean();
+      if (context->mDrawObserver) {
+        if (context->mDrawObserver->FrameEnd()) {
           // Note that this call deletes and nulls out mDrawObserver:
-          self->mContext->RemoveDrawObserver();
+          context->RemoveDrawObserver();
         }
       }
     }
   }
   bool IsForContext(CanvasRenderingContext2D* aContext)
   {
     return mContext == aContext;
   }
@@ -6243,33 +6242,33 @@ CanvasRenderingContext2D::GetCanvasLayer
     return nullptr;
   }
 
   if (!mResetLayer && aOldLayer) {
     auto userData =
       static_cast<CanvasRenderingContext2DUserData*>(
         aOldLayer->GetUserData(&g2DContextLayerUserData));
 
-    CanvasLayer::Data data;
+    CanvasInitializeData data;
 
     if (mIsSkiaGL) {
       GLuint skiaGLTex = SkiaGLTex();
       if (skiaGLTex) {
         SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
         MOZ_ASSERT(glue);
         data.mGLContext = glue->GetGLContext();
         data.mFrontbufferGLTex = skiaGLTex;
       }
     }
 
     data.mBufferProvider = mBufferProvider;
 
     if (userData &&
         userData->IsForContext(this) &&
-        static_cast<CanvasLayer*>(aOldLayer)->IsDataValid(data)) {
+        static_cast<CanvasLayer*>(aOldLayer)->CreateOrGetCanvasRenderer()->IsDataValid(data)) {
       RefPtr<Layer> ret = aOldLayer;
       return ret.forget();
     }
   }
 
   RefPtr<CanvasLayer> canvasLayer = aManager->CreateCanvasLayer();
   if (!canvasLayer) {
     NS_WARNING("CreateCanvasLayer returned null!");
@@ -6286,48 +6285,55 @@ CanvasRenderingContext2D::GetCanvasLayer
   // notifications after this paint.
 
   // 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->SetUserData(&g2DContextLayerUserData, userData);
 
-  CanvasLayer::Data data;
+  CanvasRenderer* canvasRenderer = canvasLayer->CreateOrGetCanvasRenderer();
+  InitializeCanvasRenderer(aBuilder, canvasRenderer, aMirror);
+  uint32_t flags = mOpaque ? Layer::CONTENT_OPAQUE : 0;
+  canvasLayer->SetContentFlags(flags);
+
+  mResetLayer = false;
+
+  return canvasLayer.forget();
+}
+
+void
+CanvasRenderingContext2D::InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+                                                   CanvasRenderer* aRenderer,
+                                                   bool aMirror)
+{
+  CanvasInitializeData data;
   data.mSize = GetSize();
   data.mHasAlpha = !mOpaque;
-
-  canvasLayer->SetPreTransactionCallback(
-          CanvasRenderingContext2DUserData::PreTransactionCallback, userData);
-
+  data.mPreTransCallback = CanvasRenderingContext2DUserData::PreTransactionCallback;
+  data.mPreTransCallbackData = this;
+  data.mDidTransCallback = CanvasRenderingContext2DUserData::DidTransactionCallback;
+  data.mDidTransCallbackData = this;
 
   if (mIsSkiaGL) {
       GLuint skiaGLTex = SkiaGLTex();
       if (skiaGLTex) {
         SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
         MOZ_ASSERT(glue);
         data.mGLContext = glue->GetGLContext();
         data.mFrontbufferGLTex = skiaGLTex;
       }
   }
 
   data.mBufferProvider = mBufferProvider;
 
-  canvasLayer->Initialize(data);
-  uint32_t flags = mOpaque ? Layer::CONTENT_OPAQUE : 0;
-  canvasLayer->SetContentFlags(flags);
-  canvasLayer->Updated();
-
-  mResetLayer = false;
-
-  return canvasLayer.forget();
+  aRenderer->Initialize(data);
+  aRenderer->SetDirty();
 }
 
 void
 CanvasRenderingContext2D::MarkContextClean()
 {
   if (mInvalidateCount > 0) {
     mPredictManyRedrawCalls = mInvalidateCount > kCanvasMaxInvalidateCount;
   }
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -463,16 +463,19 @@ public:
 
   virtual void SetIsOpaque(bool aIsOpaque) override;
   bool GetIsOpaque() override { return mOpaque; }
   NS_IMETHOD Reset() override;
   already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                          Layer* aOldLayer,
                                          LayerManager* aManager,
                                          bool aMirror = false) override;
+  void InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+                                CanvasRenderer* aRenderer,
+                                bool aMirror = false) override;
   virtual bool ShouldForceInactiveLayer(LayerManager* aManager) override;
   void MarkContextClean() override;
   void MarkContextCleanForFrameCapture() override;
   bool IsContextCleanForFrameCapture() override;
   NS_IMETHOD SetIsIPC(bool aIsIPC) override;
   // this rect is in canvas device space
   void Redraw(const mozilla::gfx::Rect& aR);
   NS_IMETHOD Redraw(const gfxRect& aR) override { Redraw(ToRect(aR)); return NS_OK; }
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -1311,31 +1311,27 @@ public:
     explicit WebGLContextUserData(HTMLCanvasElement* canvas)
         : mCanvas(canvas)
     {}
 
     /* PreTransactionCallback gets called by the Layers code every time the
      * WebGL canvas is going to be composited.
      */
     static void PreTransactionCallback(void* data) {
-        WebGLContextUserData* userdata = static_cast<WebGLContextUserData*>(data);
-        HTMLCanvasElement* canvas = userdata->mCanvas;
-        WebGLContext* webgl = static_cast<WebGLContext*>(canvas->GetContextAtIndex(0));
+        WebGLContext* webgl = static_cast<WebGLContext*>(data);
 
         // Prepare the context for composition
         webgl->BeginComposition();
     }
 
     /** DidTransactionCallback gets called by the Layers code everytime the WebGL canvas gets composite,
       * so it really is the right place to put actions that have to be performed upon compositing
       */
     static void DidTransactionCallback(void* data) {
-        WebGLContextUserData* userdata = static_cast<WebGLContextUserData*>(data);
-        HTMLCanvasElement* canvas = userdata->mCanvas;
-        WebGLContext* webgl = static_cast<WebGLContext*>(canvas->GetContextAtIndex(0));
+        WebGLContext* webgl = static_cast<WebGLContext*>(data);
 
         // Clean up the context after composition
         webgl->EndComposition();
     }
 
 private:
     RefPtr<HTMLCanvasElement> mCanvas;
 };
@@ -1358,56 +1354,68 @@ WebGLContext::GetCanvasLayer(nsDisplayLi
     RefPtr<CanvasLayer> canvasLayer = manager->CreateCanvasLayer();
     if (!canvasLayer) {
         NS_WARNING("CreateCanvasLayer returned null!");
         return nullptr;
     }
 
     WebGLContextUserData* userData = nullptr;
     if (builder->IsPaintingToWindow() && mCanvasElement && !aMirror) {
+        userData = new WebGLContextUserData(mCanvasElement);
+    }
+
+    canvasLayer->SetUserData(aMirror ? &gWebGLMirrorLayerUserData : &gWebGLLayerUserData, userData);
+
+    CanvasRenderer* canvasRenderer = canvasLayer->CreateOrGetCanvasRenderer();
+    InitializeCanvasRenderer(builder, canvasRenderer, aMirror);
+    uint32_t flags = gl->Caps().alpha ? 0 : Layer::CONTENT_OPAQUE;
+    canvasLayer->SetContentFlags(flags);
+
+    mResetLayer = false;
+    // We only wish to update mLayerIsMirror when a new layer is returned.
+    // If a cached layer is returned above, aMirror is not changing since
+    // the last cached layer was created and mLayerIsMirror is still valid.
+    mLayerIsMirror = aMirror;
+
+    return canvasLayer.forget();
+}
+
+void
+WebGLContext::InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+                                       CanvasRenderer* aRenderer,
+                                       bool aMirror)
+{
+    CanvasInitializeData data;
+    if (aBuilder->IsPaintingToWindow() && mCanvasElement && !aMirror) {
         // Make the layer tell us whenever a transaction finishes (including
         // the current transaction), so we can clear our invalidation state and
         // start invalidating again. We need to do this for the layer that is
         // being painted to a window (there shouldn't be more than one at a time,
         // and if there is, flushing the invalidation state more often than
         // necessary is harmless).
 
         // 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 WebGLContextUserData(mCanvasElement);
-        canvasLayer->SetDidTransactionCallback(
-            WebGLContextUserData::DidTransactionCallback, userData);
-        canvasLayer->SetPreTransactionCallback(
-            WebGLContextUserData::PreTransactionCallback, userData);
+        data.mPreTransCallback = WebGLContextUserData::PreTransactionCallback;
+        data.mPreTransCallbackData = this;
+        data.mDidTransCallback = WebGLContextUserData::DidTransactionCallback;
+        data.mDidTransCallbackData = this;
     }
 
-    canvasLayer->SetUserData(aMirror ? &gWebGLMirrorLayerUserData : &gWebGLLayerUserData, userData);
-
-    CanvasLayer::Data data;
     data.mGLContext = gl;
     data.mSize = nsIntSize(mWidth, mHeight);
     data.mHasAlpha = gl->Caps().alpha;
     data.mIsGLAlphaPremult = IsPremultAlpha() || !data.mHasAlpha;
     data.mIsMirror = aMirror;
 
-    canvasLayer->Initialize(data);
-    uint32_t flags = gl->Caps().alpha ? 0 : Layer::CONTENT_OPAQUE;
-    canvasLayer->SetContentFlags(flags);
-    canvasLayer->Updated();
-
-    mResetLayer = false;
-    // We only wish to update mLayerIsMirror when a new layer is returned.
-    // If a cached layer is returned above, aMirror is not changing since
-    // the last cached layer was created and mLayerIsMirror is still valid.
-    mLayerIsMirror = aMirror;
-
-    return canvasLayer.forget();
+    aRenderer->Initialize(data);
+    aRenderer->SetDirty();
 }
 
 layers::LayersBackend
 WebGLContext::GetCompositorBackendType() const
 {
     if (mCanvasElement) {
         return mCanvasElement->GetCompositorBackendType();
     } else if (mOffscreenCanvas) {
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -457,16 +457,20 @@ public:
     }
 
     void InvalidateResolveCacheForTextureWithTexUnit(const GLuint);
 
     already_AddRefed<Layer>
     GetCanvasLayer(nsDisplayListBuilder* builder, Layer* oldLayer,
                    LayerManager* manager,
                    bool aMirror = false) override;
+    void
+    InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+                             CanvasRenderer* aRenderer,
+                             bool aMirror = false) override;
 
     // Note that 'clean' here refers to its invalidation state, not the
     // contents of the buffer.
     void MarkContextClean() override { mInvalidated = false; }
 
     void MarkContextCleanForFrameCapture() override { mCapturedFrameInvalidated = false; }
 
     bool IsContextCleanForFrameCapture() override { return !mCapturedFrameInvalidated; }
--- a/dom/canvas/nsICanvasRenderingContextInternal.h
+++ b/dom/canvas/nsICanvasRenderingContextInternal.h
@@ -21,30 +21,32 @@
 { 0xb84f2fed, 0x9d4b, 0x430b, \
   { 0xbd, 0xfb, 0x85, 0x57, 0x8a, 0xc2, 0xb4, 0x4b } }
 
 class nsDisplayListBuilder;
 
 namespace mozilla {
 namespace layers {
 class CanvasLayer;
+class CanvasRenderer;
 class Layer;
 class LayerManager;
 } // namespace layers
 namespace gfx {
 class SourceSurface;
 } // namespace gfx
 } // namespace mozilla
 
 class nsICanvasRenderingContextInternal :
   public nsISupports,
   public nsAPostRefreshObserver
 {
 public:
   typedef mozilla::layers::CanvasLayer CanvasLayer;
+  typedef mozilla::layers::CanvasRenderer CanvasRenderer;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICANVASRENDERINGCONTEXTINTERNAL_IID)
 
   void SetCanvasElement(mozilla::dom::HTMLCanvasElement* parentCanvas)
   {
     RemovePostRefreshObserver();
@@ -134,16 +136,19 @@ public:
   NS_IMETHOD Reset() = 0;
 
   // Return the CanvasLayer for this context, creating
   // one for the given layer manager if not available.
   virtual already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* builder,
                                                  Layer *oldLayer,
                                                  LayerManager *manager,
                                                  bool aMirror = false) = 0;
+  virtual void InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+                                        CanvasRenderer* aRenderer,
+                                        bool aMirror = false) { };
 
   // Return true if the canvas should be forced to be "inactive" to ensure
   // it can be drawn to the screen even if it's too large to be blitted by
   // an accelerated CanvasLayer.
   virtual bool ShouldForceInactiveLayer(LayerManager *manager) { return false; }
 
   virtual void MarkContextClean() = 0;
 
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -1163,28 +1163,42 @@ HTMLCanvasElement::GetCanvasLayer(nsDisp
     if (!layer) {
       NS_WARNING("CreateCanvasLayer failed!");
       return nullptr;
     }
 
     LayerUserData* userData = nullptr;
     layer->SetUserData(&sOffscreenCanvasLayerUserDataDummy, userData);
 
-    CanvasLayer::Data data;
-    data.mRenderer = GetAsyncCanvasRenderer();
-    data.mSize = GetWidthHeight();
-    layer->Initialize(data);
+    CanvasRenderer* canvasRenderer = layer->CreateOrGetCanvasRenderer();
+    InitializeCanvasRenderer(aBuilder, canvasRenderer);
 
     layer->Updated();
     return layer.forget();
   }
 
   return nullptr;
 }
 
+void
+HTMLCanvasElement::InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+                                            CanvasRenderer* aRenderer)
+{
+  if (mCurrentContext) {
+    mCurrentContext->InitializeCanvasRenderer(aBuilder, aRenderer);
+  }
+
+  if (mOffscreenCanvas) {
+    CanvasInitializeData data;
+    data.mRenderer = GetAsyncCanvasRenderer();
+    data.mSize = GetWidthHeight();
+    aRenderer->Initialize(data);
+  }
+}
+
 bool
 HTMLCanvasElement::ShouldForceInactiveLayer(LayerManager* aManager)
 {
   if (mCurrentContext) {
     return mCurrentContext->ShouldForceInactiveLayer(aManager);
   }
 
   if (mOffscreenCanvas) {
--- a/dom/html/HTMLCanvasElement.h
+++ b/dom/html/HTMLCanvasElement.h
@@ -25,16 +25,17 @@ class nsICanvasRenderingContextInternal;
 class nsITimerCallback;
 
 namespace mozilla {
 
 class WebGLContext;
 
 namespace layers {
 class AsyncCanvasRenderer;
+class CanvasRenderer;
 class CanvasLayer;
 class Image;
 class Layer;
 class LayerManager;
 class SharedSurfaceTextureClient;
 } // namespace layers
 namespace gfx {
 class SourceSurface;
@@ -119,16 +120,17 @@ class HTMLCanvasElement final : public n
                                 public CanvasRenderingContextHelper
 {
   enum {
     DEFAULT_CANVAS_WIDTH = 300,
     DEFAULT_CANVAS_HEIGHT = 150
   };
 
   typedef layers::AsyncCanvasRenderer AsyncCanvasRenderer;
+  typedef layers::CanvasRenderer CanvasRenderer;
   typedef layers::CanvasLayer CanvasLayer;
   typedef layers::Layer Layer;
   typedef layers::LayerManager LayerManager;
 
 public:
   explicit HTMLCanvasElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
 
   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLCanvasElement, canvas)
@@ -303,16 +305,18 @@ public:
 
   /*
    * Helpers called by various users of Canvas
    */
 
   already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                          Layer *aOldLayer,
                                          LayerManager *aManager);
+  void InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+                                CanvasRenderer* aRenderer);
   // Should return true if the canvas layer should always be marked inactive.
   // We should return true here if we can't do accelerated compositing with
   // a non-BasicCanvasLayer.
   bool ShouldForceInactiveLayer(LayerManager *aManager);
 
   // Call this whenever we need future changes to the canvas
   // to trigger fresh invalidation requests. This needs to be called
   // whenever we render the canvas contents to the screen, or whenever we
new file mode 100644
--- /dev/null
+++ b/gfx/layers/CanvasRenderer.cpp
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "CanvasRenderer.h"
+
+namespace mozilla {
+namespace layers {
+
+CanvasRenderer::CanvasRenderer()
+  : mPreTransCallback(nullptr)
+  , mPreTransCallbackData(nullptr)
+  , mDidTransCallback(nullptr)
+  , mDidTransCallbackData(nullptr)
+  , mDirty(false)
+{
+  MOZ_COUNT_CTOR(CanvasRenderer);
+}
+
+CanvasRenderer::~CanvasRenderer()
+{
+  Destroy();
+  MOZ_COUNT_DTOR(CanvasRenderer);
+}
+
+void
+CanvasRenderer::Initialize(const CanvasInitializeData& aData)
+{
+  mPreTransCallback = aData.mPreTransCallback;
+  mPreTransCallbackData = aData.mPreTransCallbackData;
+  mDidTransCallback = aData.mDidTransCallback;
+  mDidTransCallbackData = aData.mDidTransCallbackData;
+
+  mSize = aData.mSize;
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/CanvasRenderer.h
@@ -0,0 +1,178 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_CANVASRENDERER_H
+#define GFX_CANVASRENDERER_H
+
+#include <stdint.h>                     // for uint32_t
+#include "GLContextTypes.h"             // for GLContext
+#include "gfxContext.h"                 // for gfxContext, etc
+#include "gfxTypes.h"
+#include "gfxPlatform.h"                // for gfxImageFormat
+#include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
+#include "mozilla/Preferences.h"        // for Preferences
+#include "mozilla/RefPtr.h"             // for RefPtr
+#include "mozilla/gfx/2D.h"             // for DrawTarget
+#include "mozilla/mozalloc.h"           // for operator delete, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
+
+namespace mozilla {
+namespace layers {
+
+class AsyncCanvasRenderer;
+class ClientCanvasRenderer;
+class CopyableCanvasRenderer;
+class PersistentBufferProvider;
+class WebRenderCanvasRendererSync;
+class WebRenderCanvasRendererAsync;
+
+struct CanvasInitializeData {
+  CanvasInitializeData()
+    : mBufferProvider(nullptr)
+    , mGLContext(nullptr)
+    , mRenderer(nullptr)
+    , mPreTransCallback(nullptr)
+    , mPreTransCallbackData(nullptr)
+    , mDidTransCallback(nullptr)
+    , mDidTransCallbackData(nullptr)
+    , mFrontbufferGLTex(0)
+    , mSize(0,0)
+    , mHasAlpha(false)
+    , mIsGLAlphaPremult(true)
+    , mIsMirror(false)
+  { }
+
+  // One of these three must be specified for Canvas2D, but never more than one
+  PersistentBufferProvider* mBufferProvider; // A BufferProvider for the Canvas contents
+  mozilla::gl::GLContext* mGLContext; // or this, for GL.
+  AsyncCanvasRenderer* mRenderer; // or this, for OffscreenCanvas
+
+  typedef void (* TransactionCallback)(void* closureData);
+  TransactionCallback mPreTransCallback;
+  void* mPreTransCallbackData;
+  TransactionCallback mDidTransCallback;
+  void* mDidTransCallbackData;
+
+  // Frontbuffer override
+  uint32_t mFrontbufferGLTex;
+
+  // The size of the canvas content
+  gfx::IntSize mSize;
+
+  // Whether the canvas drawingbuffer has an alpha channel.
+  bool mHasAlpha;
+
+  // Whether mGLContext contains data that is alpha-premultiplied.
+  bool mIsGLAlphaPremult;
+
+  // Whether the canvas front buffer is already being rendered somewhere else.
+  // When true, do not swap buffers or Morph() to another factory on mGLContext
+  bool mIsMirror;
+};
+
+// Based class which used for canvas rendering. There are many derived classes for
+// different purposes. such as:
+//
+// CopyableCanvasRenderer provides a utility which readback canvas content to a
+// SourceSurface. BasicCanvasLayer uses CopyableCanvasRenderer.
+//
+// ShareableCanvasRenderer provides IPC capabilities that allow sending canvas
+// content over IPC. This is pure virtual class because the IPC handling is
+// different in different LayerManager. So that we have following classes inherite
+// ShareableCanvasRenderer.
+//
+// ClientCanvasRenderer inherites ShareableCanvasRenderer and be used in
+// ClientCanvasLayer.
+// WebRenderCanvasRenderer inherites ShareableCanvasRenderer and provides all
+// functionality that WebRender uses.
+// WebRenderCanvasRendererSync inherites WebRenderCanvasRenderer and be used in
+// WebRenderCanvasLayer.
+// WebRenderCanvasRendererAsync inherites WebRenderCanvasRenderer and be used in
+// layers-free mode of WebRender.
+//
+// class diagram shows below:
+//
+//                       +--------------+
+//                       |CanvasRenderer|
+//                       +-------+------+
+//                               ^
+//                               |
+//                   +----------------------+
+//                   |CopyableCanvasRenderer|
+//                   +----------------------+
+//                               ^
+//                               |
+//                   +-----------+-----------+
+//                   |ShareableCanvasRenderer|
+//                   +-----+-----------------+
+//                         ^      ^
+//           +-------------+      +-------+
+//           |                            |
+// +--------------------+       +---------+-------------+
+// |ClientCanvasRenderer|       |WebRenderCanvasRenderer|
+// +--------------------+       +--------+--+-----------+
+//                                       ^  ^
+//               +-----------------------+  +----+
+//               |                               |
+// +-------------+-------------+   +-------------+--------------+
+// |WebRenderCanvasRendererSync|   |WebRenderCanvasRendererAsync|
+// +---------------------------+   +----------------------------+
+class CanvasRenderer
+{
+public:
+  CanvasRenderer();
+  virtual ~CanvasRenderer();
+
+public:
+  virtual void Initialize(const CanvasInitializeData& aData);
+  virtual bool IsDataValid(const CanvasInitializeData& aData) { return true; }
+
+  virtual void ClearCachedResources() { }
+  virtual void Destroy() { }
+
+  const gfx::IntSize& GetSize() const { return mSize; }
+
+  void SetDirty() { mDirty = true; }
+  void ResetDirty() { mDirty = false; }
+  bool IsDirty() const { return mDirty; }
+
+  virtual CopyableCanvasRenderer* AsCopyableCanvasRenderer() { return nullptr; }
+  virtual ClientCanvasRenderer* AsClientCanvasRenderer() { return nullptr; }
+  virtual WebRenderCanvasRendererSync* AsWebRenderCanvasRendererSync() { return nullptr; }
+  virtual WebRenderCanvasRendererAsync* AsWebRenderCanvasRendererAsync() { return nullptr; }
+
+protected:
+  void FirePreTransactionCallback()
+  {
+    if (mPreTransCallback) {
+      mPreTransCallback(mPreTransCallbackData);
+    }
+  }
+
+  void FireDidTransactionCallback()
+  {
+    if (mDidTransCallback) {
+      mDidTransCallback(mDidTransCallbackData);
+    }
+  }
+
+  typedef void (* TransactionCallback)(void* closureData);
+  TransactionCallback mPreTransCallback;
+  void* mPreTransCallbackData;
+  TransactionCallback mDidTransCallback;
+  void* mDidTransCallbackData;
+  gfx::IntSize mSize;
+
+private:
+  /**
+   * Set to true in Updated(), cleared during a transaction.
+   */
+  bool mDirty;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
--- a/gfx/layers/CopyableCanvasRenderer.cpp
+++ b/gfx/layers/CopyableCanvasRenderer.cpp
@@ -1,14 +1,14 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "CopyableCanvasLayer.h"
+#include "CopyableCanvasRenderer.h"
 
 #include "BasicLayersImpl.h"            // for FillWithMask, etc
 #include "GLContext.h"                  // for GLContext
 #include "GLScreenBuffer.h"             // for GLScreenBuffer
 #include "SharedSurface.h"              // for SharedSurface
 #include "SharedSurfaceGL.h"              // for SharedSurface
 #include "gfxPattern.h"                 // for gfxPattern, etc
 #include "gfxPlatform.h"                // for gfxPlatform, gfxImageFormat
@@ -27,34 +27,41 @@
 #include "client/TextureClientSharedSurface.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
 
-CopyableCanvasLayer::CopyableCanvasLayer(LayerManager* aLayerManager, void *aImplData) :
-  CanvasLayer(aLayerManager, aImplData)
+CopyableCanvasRenderer::CopyableCanvasRenderer()
+  : mGLContext(nullptr)
+  , mBufferProvider(nullptr)
   , mGLFrontbuffer(nullptr)
+  , mAsyncRenderer(nullptr)
   , mIsAlphaPremultiplied(true)
   , mOriginPos(gl::OriginPos::TopLeft)
   , mIsMirror(false)
+  , mOpaque(true)
+  , mCachedTempSurface(nullptr)
 {
-  MOZ_COUNT_CTOR(CopyableCanvasLayer);
+  MOZ_COUNT_CTOR(CopyableCanvasRenderer);
 }
 
-CopyableCanvasLayer::~CopyableCanvasLayer()
+CopyableCanvasRenderer::~CopyableCanvasRenderer()
 {
-  MOZ_COUNT_DTOR(CopyableCanvasLayer);
+  Destroy();
+  MOZ_COUNT_DTOR(CopyableCanvasRenderer);
 }
 
 void
-CopyableCanvasLayer::Initialize(const Data& aData)
+CopyableCanvasRenderer::Initialize(const CanvasInitializeData& aData)
 {
+  CanvasRenderer::Initialize(aData);
+
   if (aData.mGLContext) {
     mGLContext = aData.mGLContext;
     mIsAlphaPremultiplied = aData.mIsGLAlphaPremult;
     mOriginPos = gl::OriginPos::BottomLeft;
     mIsMirror = aData.mIsMirror;
 
     MOZ_ASSERT(mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
 
@@ -65,30 +72,104 @@ CopyableCanvasLayer::Initialize(const Da
       mBufferProvider = aData.mBufferProvider;
     }
   } else if (aData.mBufferProvider) {
     mBufferProvider = aData.mBufferProvider;
   } else if (aData.mRenderer) {
     mAsyncRenderer = aData.mRenderer;
     mOriginPos = gl::OriginPos::BottomLeft;
   } else {
-    MOZ_CRASH("GFX: CanvasLayer created without BufferProvider, DrawTarget or GLContext?");
+    MOZ_CRASH("GFX: CanvasRenderer created without BufferProvider, DrawTarget or GLContext?");
   }
 
-  mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
+  mOpaque = !aData.mHasAlpha;
 }
 
 bool
-CopyableCanvasLayer::IsDataValid(const Data& aData)
+CopyableCanvasRenderer::IsDataValid(const CanvasInitializeData& aData)
 {
   return mGLContext == aData.mGLContext;
 }
 
+void
+CopyableCanvasRenderer::ClearCachedResources()
+{
+  if (mBufferProvider) {
+    mBufferProvider->ClearCachedResources();
+  }
+
+  mCachedTempSurface = nullptr;
+}
+
+void
+CopyableCanvasRenderer::Destroy()
+{
+  if (mBufferProvider) {
+    mBufferProvider->ClearCachedResources();
+  }
+
+  mCachedTempSurface = nullptr;
+}
+
+already_AddRefed<SourceSurface>
+CopyableCanvasRenderer::ReadbackSurface()
+{
+  FirePreTransactionCallback();
+  if (mAsyncRenderer) {
+    MOZ_ASSERT(!mBufferProvider);
+    MOZ_ASSERT(!mGLContext);
+    return mAsyncRenderer->GetSurface();
+  }
+
+  if (!mGLContext) {
+    return nullptr;
+  }
+
+  SharedSurface* frontbuffer = nullptr;
+  if (mGLFrontbuffer) {
+    frontbuffer = mGLFrontbuffer.get();
+  } else {
+    GLScreenBuffer* screen = mGLContext->Screen();
+    const auto& front = screen->Front();
+    if (front) {
+      frontbuffer = front->Surf();
+    }
+  }
+
+  if (!frontbuffer) {
+    NS_WARNING("Null frame received.");
+    return nullptr;
+  }
+
+  IntSize readSize(frontbuffer->mSize);
+  SurfaceFormat format =
+    mOpaque ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8;
+  bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied;
+
+  RefPtr<DataSourceSurface> resultSurf = GetTempSurface(readSize, format);
+  // There will already be a warning from inside of GetTempSurface, but
+  // it doesn't hurt to complain:
+  if (NS_WARN_IF(!resultSurf)) {
+    return nullptr;
+  }
+
+  // Readback handles Flush/MarkDirty.
+  mGLContext->Readback(frontbuffer, resultSurf);
+  if (needsPremult) {
+    gfxUtils::PremultiplyDataSurface(resultSurf, resultSurf);
+  }
+  MOZ_ASSERT(resultSurf);
+
+  FireDidTransactionCallback();
+
+  return resultSurf.forget();
+}
+
 DataSourceSurface*
-CopyableCanvasLayer::GetTempSurface(const IntSize& aSize,
+CopyableCanvasRenderer::GetTempSurface(const IntSize& aSize,
                                     const SurfaceFormat aFormat)
 {
   if (!mCachedTempSurface ||
       aSize != mCachedTempSurface->GetSize() ||
       aFormat != mCachedTempSurface->GetFormat())
   {
     // Create a surface aligned to 8 bytes since that's the highest alignment WebGL can handle.
     uint32_t stride = GetAlignedStride<8>(aSize.width, BytesPerPixel(aFormat));
--- a/gfx/layers/CopyableCanvasRenderer.h
+++ b/gfx/layers/CopyableCanvasRenderer.h
@@ -1,19 +1,19 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef GFX_COPYABLECANVASLAYER_H
-#define GFX_COPYABLECANVASLAYER_H
+#ifndef GFX_COPYABLECANVASRENDERER_H
+#define GFX_COPYABLECANVASRENDERER_H
 
 #include <stdint.h>                     // for uint32_t
+#include "CanvasRenderer.h"
 #include "GLContextTypes.h"             // for GLContext
-#include "Layers.h"                     // for CanvasLayer, etc
 #include "gfxContext.h"                 // for gfxContext, etc
 #include "gfxTypes.h"
 #include "gfxPlatform.h"                // for gfxImageFormat
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/Preferences.h"        // for Preferences
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/gfx/2D.h"             // for DrawTarget
 #include "mozilla/mozalloc.h"           // for operator delete, etc
@@ -23,43 +23,54 @@ namespace mozilla {
 
 namespace gl {
 class SharedSurface;
 } // namespace gl
 
 namespace layers {
 
 /**
- * A shared CanvasLayer implementation that supports copying
- * its contents into a gfxASurface using UpdateSurface.
+ * A shared CanvasRenderer implementation that supports copying
+ * its contents into a gfxASurface using RebackSurface.
  */
-class CopyableCanvasLayer : public CanvasLayer
+class CopyableCanvasRenderer : public CanvasRenderer
 {
 public:
-  CopyableCanvasLayer(LayerManager* aLayerManager, void *aImplData);
-
-protected:
-  virtual ~CopyableCanvasLayer();
+  CopyableCanvasRenderer();
+  virtual ~CopyableCanvasRenderer();
 
 public:
-  virtual void Initialize(const Data& aData) override;
+  void Initialize(const CanvasInitializeData& aData) override;
+  bool IsDataValid(const CanvasInitializeData& aData) override;
+
+  void ClearCachedResources() override;
+  void Destroy() override;
+
+  CopyableCanvasRenderer* AsCopyableCanvasRenderer() override { return this; }
 
-  virtual bool IsDataValid(const Data& aData) override;
+  bool NeedsYFlip() const { return mOriginPos == gl::OriginPos::BottomLeft; }
+  bool HasGLContext() const { return !!mGLContext; }
+  bool IsOpaque() const { return mOpaque; }
 
-  bool IsGLLayer() { return !!mGLContext; }
+  PersistentBufferProvider* GetBufferProvider() { return mBufferProvider; }
+
+  already_AddRefed<gfx::SourceSurface> ReadbackSurface();
 
 protected:
   RefPtr<gl::GLContext> mGLContext;
   RefPtr<PersistentBufferProvider> mBufferProvider;
   UniquePtr<gl::SharedSurface> mGLFrontbuffer;
+  RefPtr<AsyncCanvasRenderer> mAsyncRenderer;
 
   bool mIsAlphaPremultiplied;
   gl::OriginPos mOriginPos;
   bool mIsMirror;
 
+  bool mOpaque;
+
   RefPtr<gfx::DataSourceSurface> mCachedTempSurface;
 
   gfx::DataSourceSurface* GetTempSurface(const gfx::IntSize& aSize,
                                          const gfx::SurfaceFormat aFormat);
 };
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -2238,23 +2238,18 @@ BorderLayer::PrintInfo(std::stringstream
 void
 BorderLayer::DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent)
 {
   Layer::DumpPacket(aPacket, aParent);
 }
 
 CanvasLayer::CanvasLayer(LayerManager* aManager, void* aImplData)
   : Layer(aManager, aImplData)
-  , mPreTransCallback(nullptr)
-  , mPreTransCallbackData(nullptr)
-  , mPostTransCallback(nullptr)
-  , mPostTransCallbackData(nullptr)
-  , mSamplingFilter(gfx::SamplingFilter::GOOD)
-  , mDirty(false)
-{}
+{
+}
 
 CanvasLayer::~CanvasLayer() = default;
 
 void
 CanvasLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
 {
   Layer::PrintInfo(aStream, aPrefix);
   if (mSamplingFilter != SamplingFilter::GOOD) {
@@ -2291,16 +2286,26 @@ CanvasLayer::DumpPacket(layerscope::Laye
   Layer::DumpPacket(aPacket, aParent);
   // Get this layer data
   using namespace layerscope;
   LayersPacket::Layer* layer = aPacket->mutable_layer(aPacket->layer_size()-1);
   layer->set_type(LayersPacket::Layer::CanvasLayer);
   DumpFilter(layer, mSamplingFilter);
 }
 
+CanvasRenderer*
+CanvasLayer::CreateOrGetCanvasRenderer()
+{
+  if (!mCanvasRenderer) {
+    mCanvasRenderer.reset(CreateCanvasRendererInternal());
+  }
+
+  return mCanvasRenderer.get();
+}
+
 void
 ImageLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
 {
   Layer::PrintInfo(aStream, aPrefix);
   if (mSamplingFilter != SamplingFilter::GOOD) {
     AppendToString(aStream, mSamplingFilter, " [filter=", "]");
   }
 }
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -29,16 +29,17 @@
 #include "mozilla/UniquePtr.h"          // for UniquePtr
 #include "mozilla/gfx/BaseMargin.h"     // for BaseMargin
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/TiledRegion.h"    // for TiledIntRegion
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
 #include "mozilla/gfx/UserData.h"       // for UserData, etc
 #include "mozilla/layers/BSPTree.h"     // for LayerPolygon
+#include "mozilla/layers/CanvasRenderer.h"
 #include "mozilla/layers/LayerAttributes.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsAutoPtr.h"                  // for nsAutoPtr, nsRefPtr, etc
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsCSSPropertyID.h"              // for nsCSSPropertyID
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for Layer::Release, etc
@@ -2704,125 +2705,51 @@ protected:
  * if hardware compositing is not available, for reading from the GL
  * buffer into an image surface that we can layer composite.)
  *
  * After Initialize is called, the underlying canvas Surface/GLContext
  * must not be modified during a layer transaction.
  */
 class CanvasLayer : public Layer {
 public:
-  struct Data {
-    Data()
-      : mBufferProvider(nullptr)
-      , mGLContext(nullptr)
-      , mRenderer(nullptr)
-      , mFrontbufferGLTex(0)
-      , mSize(0,0)
-      , mHasAlpha(false)
-      , mIsGLAlphaPremult(true)
-      , mIsMirror(false)
-    { }
-
-    // One of these three must be specified for Canvas2D, but never more than one
-    PersistentBufferProvider* mBufferProvider; // A BufferProvider for the Canvas contents
-    mozilla::gl::GLContext* mGLContext; // or this, for GL.
-    AsyncCanvasRenderer* mRenderer; // or this, for OffscreenCanvas
-
-    // Frontbuffer override
-    uint32_t mFrontbufferGLTex;
-
-    // The size of the canvas content
-    gfx::IntSize mSize;
-
-    // Whether the canvas drawingbuffer has an alpha channel.
-    bool mHasAlpha;
-
-    // Whether mGLContext contains data that is alpha-premultiplied.
-    bool mIsGLAlphaPremult;
-
-    // Whether the canvas front buffer is already being rendered somewhere else.
-    // When true, do not swap buffers or Morph() to another factory on mGLContext
-    bool mIsMirror;
-  };
-
-  /**
-   * CONSTRUCTION PHASE ONLY
-   * Initialize this CanvasLayer with the given data.  The data must
-   * have either mSurface or mGLContext initialized (but not both), as
-   * well as mSize.
-   *
-   * This must only be called once.
-   */
-  virtual void Initialize(const Data& aData) = 0;
-
   void SetBounds(gfx::IntRect aBounds) { mBounds = aBounds; }
 
-  /**
-   * Check the data is owned by this layer is still valid for rendering
-   */
-  virtual bool IsDataValid(const Data& aData) { return true; }
-
   virtual CanvasLayer* AsCanvasLayer() override { return this; }
 
   /**
    * Notify this CanvasLayer that the canvas surface contents have
    * changed (or will change) before the next transaction.
    */
-  void Updated() { mDirty = true; SetInvalidRectToVisibleRegion(); }
+  void Updated() { mCanvasRenderer->SetDirty(); SetInvalidRectToVisibleRegion(); }
 
   /**
    * Notify this CanvasLayer that the canvas surface contents have
    * been painted since the last change.
    */
-  void Painted() { mDirty = false; }
+  void Painted() { mCanvasRenderer->ResetDirty(); }
 
   /**
    * Returns true if the canvas surface contents have changed since the
    * last paint.
    */
   bool IsDirty()
   {
     // We can only tell if we are dirty if we're part of the
     // widget's retained layer tree.
     if (!mManager || !mManager->IsWidgetLayerManager()) {
       return true;
     }
-    return mDirty;
-  }
-
-  /**
-   * Register a callback to be called at the start of each transaction.
-   */
-  typedef void PreTransactionCallback(void* closureData);
-  void SetPreTransactionCallback(PreTransactionCallback* callback, void* closureData)
-  {
-    mPreTransCallback = callback;
-    mPreTransCallbackData = closureData;
+    return mCanvasRenderer->IsDirty();
   }
 
   const nsIntRect& GetBounds() const { return mBounds; }
 
-protected:
-  void FirePreTransactionCallback()
-  {
-    if (mPreTransCallback) {
-      mPreTransCallback(mPreTransCallbackData);
-    }
-  }
+  CanvasRenderer* CreateOrGetCanvasRenderer();
 
 public:
-  /**
-   * Register a callback to be called at the end of each transaction.
-   */
-  typedef void (* DidTransactionCallback)(void* aClosureData);
-  void SetDidTransactionCallback(DidTransactionCallback aCallback, void* aClosureData)
-  {
-    mPostTransCallback = aCallback;
-    mPostTransCallbackData = aClosureData;
-  }
 
   /**
    * CONSTRUCTION PHASE ONLY
    * Set the filter used to resample this image (if necessary).
    */
   void SetSamplingFilter(gfx::SamplingFilter aSamplingFilter)
   {
     if (mSamplingFilter != aSamplingFilter) {
@@ -2843,52 +2770,33 @@ public:
     // transform, then we'd snap again when compositing the PaintedLayer).
     mEffectiveTransform =
         SnapTransform(GetLocalTransform(), gfxRect(0, 0, mBounds.width, mBounds.height),
                       nullptr)*
         SnapTransformTranslation(aTransformToSurface, nullptr);
     ComputeEffectiveTransformForMaskLayers(aTransformToSurface);
   }
 
-  bool GetIsAsyncRenderer() const
-  {
-    return !!mAsyncRenderer;
-  }
-
 protected:
   CanvasLayer(LayerManager* aManager, void* aImplData);
   virtual ~CanvasLayer();
 
   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
 
   virtual void DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent) override;
 
-  void FireDidTransactionCallback()
-  {
-    if (mPostTransCallback) {
-      mPostTransCallback(mPostTransCallbackData);
-    }
-  }
+  virtual CanvasRenderer* CreateCanvasRendererInternal() = 0;
+
+  UniquePtr<CanvasRenderer> mCanvasRenderer;
+  gfx::SamplingFilter mSamplingFilter;
 
   /**
    * 0, 0, canvaswidth, canvasheight
    */
   gfx::IntRect mBounds;
-  PreTransactionCallback* mPreTransCallback;
-  void* mPreTransCallbackData;
-  DidTransactionCallback mPostTransCallback;
-  void* mPostTransCallbackData;
-  gfx::SamplingFilter mSamplingFilter;
-  RefPtr<AsyncCanvasRenderer> mAsyncRenderer;
-
-private:
-  /**
-   * Set to true in Updated(), cleared during a transaction.
-   */
-  bool mDirty;
 };
 
 /**
  * ContainerLayer that refers to a "foreign" layer tree, through an
  * ID.  Usage of RefLayer looks like
  *
  * Construction phase:
  *   allocate ID for layer subtree
--- a/gfx/layers/ShareableCanvasRenderer.cpp
+++ b/gfx/layers/ShareableCanvasRenderer.cpp
@@ -1,47 +1,43 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "ShareableCanvasLayer.h"
+#include "ShareableCanvasRenderer.h"
 
 #include "GLContext.h"                  // for GLContext
 #include "GLScreenBuffer.h"             // for GLScreenBuffer
 #include "SharedSurfaceGL.h"            // for SurfaceFactory_GLTexture, etc
 #include "mozilla/layers/AsyncCanvasRenderer.h"
 #include "mozilla/layers/TextureClientSharedSurface.h"
 
 namespace mozilla {
 namespace layers {
 
-ShareableCanvasLayer::ShareableCanvasLayer(LayerManager* aLayerManager, void *aImplData)
-  : CopyableCanvasLayer(aLayerManager, aImplData)
+ShareableCanvasRenderer::ShareableCanvasRenderer()
+  : mCanvasClient(nullptr)
+  , mFactory(nullptr)
   , mFlags(TextureFlags::NO_FLAGS)
 {
-  MOZ_COUNT_CTOR(ShareableCanvasLayer);
+  MOZ_COUNT_CTOR(ShareableCanvasRenderer);
 }
 
-ShareableCanvasLayer::~ShareableCanvasLayer()
+ShareableCanvasRenderer::~ShareableCanvasRenderer()
 {
-  MOZ_COUNT_DTOR(ShareableCanvasLayer);
-  if (mBufferProvider) {
-    mBufferProvider->ClearCachedResources();
-  }
-  if (mCanvasClient) {
-    mCanvasClient->OnDetach();
-    mCanvasClient = nullptr;
-  }
+  MOZ_COUNT_DTOR(ShareableCanvasRenderer);
+
+  Destroy();
 }
 
 void
-ShareableCanvasLayer::Initialize(const Data& aData)
+ShareableCanvasRenderer::Initialize(const CanvasInitializeData& aData)
 {
-  CopyableCanvasLayer::Initialize(aData);
+  CopyableCanvasRenderer::Initialize(aData);
 
   mCanvasClient = nullptr;
 
   if (!mGLContext)
     return;
 
   gl::GLScreenBuffer* screen = mGLContext->Screen();
 
@@ -75,18 +71,39 @@ ShareableCanvasLayer::Initialize(const D
       mFactory = MakeUnique<gl::SurfaceFactory_Basic>(mGLContext, caps, mFlags);
     }
   } else {
     if (factory)
       screen->Morph(Move(factory));
   }
 }
 
+void
+ShareableCanvasRenderer::ClearCachedResources()
+{
+  CopyableCanvasRenderer::ClearCachedResources();
+
+  if (mCanvasClient) {
+    mCanvasClient->Clear();
+  }
+}
+
+void
+ShareableCanvasRenderer::Destroy()
+{
+  CopyableCanvasRenderer::Destroy();
+
+  if (mCanvasClient) {
+    mCanvasClient->OnDetach();
+    mCanvasClient = nullptr;
+  }
+}
+
 bool
-ShareableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
+ShareableCanvasRenderer::UpdateTarget(DrawTarget* aDestTarget)
 {
   MOZ_ASSERT(aDestTarget);
   if (!aDestTarget) {
     return false;
   }
 
   RefPtr<SourceSurface> surface;
 
@@ -102,17 +119,17 @@ ShareableCanvasLayer::UpdateTarget(DrawT
     }
 
     MOZ_ASSERT(surface);
     if (!surface) {
       return false;
     }
 
     aDestTarget->CopySurface(surface,
-                             IntRect(0, 0, mBounds.width, mBounds.height),
+                             IntRect(0, 0, mSize.width, mSize.height),
                              IntPoint(0, 0));
     return true;
   }
 
   gl::SharedSurface* frontbuffer = nullptr;
   if (mGLFrontbuffer) {
     frontbuffer = mGLFrontbuffer.get();
   } else {
@@ -124,19 +141,18 @@ ShareableCanvasLayer::UpdateTarget(DrawT
   }
 
   if (!frontbuffer) {
     NS_WARNING("Null frame received.");
     return false;
   }
 
   IntSize readSize(frontbuffer->mSize);
-  SurfaceFormat format = (GetContentFlags() & CONTENT_OPAQUE)
-                          ? SurfaceFormat::B8G8R8X8
-                          : SurfaceFormat::B8G8R8A8;
+  SurfaceFormat format =
+    mOpaque ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8;
   bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied;
 
   // Try to read back directly into aDestTarget's output buffer
   uint8_t* destData;
   IntSize destSize;
   int32_t destStride;
   SurfaceFormat destFormat;
   if (aDestTarget->LockBits(&destData, &destSize, &destStride, &destFormat)) {
@@ -169,69 +185,53 @@ ShareableCanvasLayer::UpdateTarget(DrawT
   aDestTarget->CopySurface(resultSurf,
                            IntRect(0, 0, readSize.width, readSize.height),
                            IntPoint(0, 0));
 
   return true;
 }
 
 CanvasClient::CanvasClientType
-ShareableCanvasLayer::GetCanvasClientType()
+ShareableCanvasRenderer::GetCanvasClientType()
 {
   if (mAsyncRenderer) {
     return CanvasClient::CanvasClientAsync;
   }
 
   if (mGLContext) {
     return CanvasClient::CanvasClientTypeShSurf;
   }
   return CanvasClient::CanvasClientSurface;
 }
 
 void
-ShareableCanvasLayer::UpdateCompositableClient()
+ShareableCanvasRenderer::UpdateCompositableClient()
 {
-  if (!mCanvasClient) {
-    TextureFlags flags = TextureFlags::DEFAULT;
-    if (mOriginPos == gl::OriginPos::BottomLeft) {
-      flags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
-    }
-
-    if (!mIsAlphaPremultiplied) {
-      flags |= TextureFlags::NON_PREMULTIPLIED;
-    }
-
-    mCanvasClient = CanvasClient::CreateCanvasClient(GetCanvasClientType(),
-                                                     GetForwarder(),
-                                                     flags);
-    if (!mCanvasClient) {
-      return;
-    }
-
-    AttachCompositable();
+  if (!CreateCompositable()) {
+    return;
   }
 
   if (mCanvasClient && mAsyncRenderer) {
     mCanvasClient->UpdateAsync(mAsyncRenderer);
   }
 
   if (!IsDirty()) {
     return;
   }
-  Painted();
+  ResetDirty();
 
   FirePreTransactionCallback();
   if (mBufferProvider && mBufferProvider->GetTextureClient()) {
-    if (!mBufferProvider->SetForwarder(mManager->AsShadowForwarder())) {
+    if (!mBufferProvider->SetForwarder(GetForwarder()->AsLayerForwarder())) {
       gfxCriticalNote << "BufferProvider::SetForwarder failed";
       return;
     }
     mCanvasClient->UpdateFromTexture(mBufferProvider->GetTextureClient());
   } else {
-    mCanvasClient->Update(gfx::IntSize(mBounds.width, mBounds.height), this);
+    mCanvasClient->Update(gfx::IntSize(mSize.width, mSize.height), this);
   }
 
   FireDidTransactionCallback();
 
   mCanvasClient->Updated();
 }
 
 } // namespace layers
--- a/gfx/layers/ShareableCanvasRenderer.h
+++ b/gfx/layers/ShareableCanvasRenderer.h
@@ -1,50 +1,52 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef GFX_SHAREABLECANVASLAYER_H
-#define GFX_SHAREABLECANVASLAYER_H
+#ifndef GFX_SHAREABLECANVASRENDERER_H
+#define GFX_SHAREABLECANVASRENDERER_H
 
 #include "CompositorTypes.h"
-#include "CopyableCanvasLayer.h"
+#include "CopyableCanvasRenderer.h"
 #include "mozilla/layers/CanvasClient.h"
 
 namespace mozilla {
 namespace gl {
 class SurfaceFactory;
 } // namespace gl
 
 namespace layers {
 
-class ShareableCanvasLayer : public CopyableCanvasLayer
+class ShareableCanvasRenderer : public CopyableCanvasRenderer
 {
   typedef CanvasClient::CanvasClientType CanvasClientType;
 public:
-  ShareableCanvasLayer(LayerManager* aLayerManager, void *aImplData);
-
-protected:
-  virtual ~ShareableCanvasLayer();
+  ShareableCanvasRenderer();
+  virtual ~ShareableCanvasRenderer();
 
 public:
-  virtual void Initialize(const Data& aData) override;
+  void Initialize(const CanvasInitializeData& aData) override;
 
   virtual CompositableForwarder* GetForwarder() = 0;
 
-  virtual void AttachCompositable() = 0;
+  virtual bool CreateCompositable() = 0;
+
+  void ClearCachedResources() override;
+  void Destroy() override;
 
   void UpdateCompositableClient();
 
   const TextureFlags& Flags() const { return mFlags; }
 
-protected:
+  CanvasClient* GetCanvasClient() { return mCanvasClient; }
 
-  bool UpdateTarget(gfx::DrawTarget* aDestTarget = nullptr);
+protected:
+  bool UpdateTarget(gfx::DrawTarget* aDestTarget);
 
   CanvasClientType GetCanvasClientType();
 
   RefPtr<CanvasClient> mCanvasClient;
 
   UniquePtr<gl::SurfaceFactory> mFactory;
 
   TextureFlags mFlags;
--- a/gfx/layers/basic/BasicCanvasLayer.cpp
+++ b/gfx/layers/basic/BasicCanvasLayer.cpp
@@ -2,16 +2,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BasicCanvasLayer.h"
 #include "AsyncCanvasRenderer.h"
 #include "basic/BasicLayers.h"          // for BasicLayerManager
 #include "basic/BasicLayersImpl.h"      // for GetEffectiveOperator
+#include "CopyableCanvasRenderer.h"
 #include "mozilla/mozalloc.h"           // for operator new
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "gfx2DGlue.h"
 #include "GLScreenBuffer.h"
 #include "GLContext.h"
 #include "gfxUtils.h"
 #include "mozilla/layers/PersistentBufferProvider.h"
@@ -20,120 +21,73 @@
 class gfxContext;
 
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
 
 namespace mozilla {
 namespace layers {
 
-already_AddRefed<SourceSurface>
-BasicCanvasLayer::UpdateSurface()
-{
-  if (mAsyncRenderer) {
-    MOZ_ASSERT(!mBufferProvider);
-    MOZ_ASSERT(!mGLContext);
-    return mAsyncRenderer->GetSurface();
-  }
-
-  if (!mGLContext) {
-    return nullptr;
-  }
-
-  SharedSurface* frontbuffer = nullptr;
-  if (mGLFrontbuffer) {
-    frontbuffer = mGLFrontbuffer.get();
-  } else {
-    GLScreenBuffer* screen = mGLContext->Screen();
-    const auto& front = screen->Front();
-    if (front) {
-      frontbuffer = front->Surf();
-    }
-  }
-
-  if (!frontbuffer) {
-    NS_WARNING("Null frame received.");
-    return nullptr;
-  }
-
-  IntSize readSize(frontbuffer->mSize);
-  SurfaceFormat format = (GetContentFlags() & CONTENT_OPAQUE)
-                          ? SurfaceFormat::B8G8R8X8
-                          : SurfaceFormat::B8G8R8A8;
-  bool needsPremult = frontbuffer->mHasAlpha && !mIsAlphaPremultiplied;
-
-  RefPtr<DataSourceSurface> resultSurf = GetTempSurface(readSize, format);
-  // There will already be a warning from inside of GetTempSurface, but
-  // it doesn't hurt to complain:
-  if (NS_WARN_IF(!resultSurf)) {
-    return nullptr;
-  }
-
-  // Readback handles Flush/MarkDirty.
-  mGLContext->Readback(frontbuffer, resultSurf);
-  if (needsPremult) {
-    gfxUtils::PremultiplyDataSurface(resultSurf, resultSurf);
-  }
-  MOZ_ASSERT(resultSurf);
-
-  return resultSurf.forget();
-}
-
 void
 BasicCanvasLayer::Paint(DrawTarget* aDT,
                         const Point& aDeviceOffset,
                         Layer* aMaskLayer)
 {
   if (IsHidden())
     return;
 
   RefPtr<SourceSurface> surface;
+  CopyableCanvasRenderer* canvasRenderer = mCanvasRenderer->AsCopyableCanvasRenderer();
+  MOZ_ASSERT(canvasRenderer);
   if (IsDirty()) {
     Painted();
 
-    FirePreTransactionCallback();
-    surface = UpdateSurface();
-    FireDidTransactionCallback();
+    surface = canvasRenderer->ReadbackSurface();
   }
 
   bool bufferPoviderSnapshot = false;
-  if (!surface && mBufferProvider) {
-    surface = mBufferProvider->BorrowSnapshot();
+  PersistentBufferProvider* bufferProvider = canvasRenderer->GetBufferProvider();
+  if (!surface && bufferProvider) {
+    surface = bufferProvider->BorrowSnapshot();
     bufferPoviderSnapshot = !!surface;
   }
 
   if (!surface) {
     return;
   }
 
-  const bool needsYFlip = (mOriginPos == gl::OriginPos::BottomLeft);
-
   Matrix oldTM;
-  if (needsYFlip) {
+  if (canvasRenderer->NeedsYFlip()) {
     oldTM = aDT->GetTransform();
     aDT->SetTransform(Matrix(oldTM).
                         PreTranslate(0.0f, mBounds.height).
                         PreScale(1.0f, -1.0f));
   }
 
   FillRectWithMask(aDT, aDeviceOffset,
                    Rect(0, 0, mBounds.width, mBounds.height),
                    surface, mSamplingFilter,
                    DrawOptions(GetEffectiveOpacity(), GetEffectiveOperator(this)),
                    aMaskLayer);
 
-  if (needsYFlip) {
+  if (canvasRenderer->NeedsYFlip()) {
     aDT->SetTransform(oldTM);
   }
 
   if (bufferPoviderSnapshot) {
-    mBufferProvider->ReturnSnapshot(surface.forget());
+    bufferProvider->ReturnSnapshot(surface.forget());
   }
 }
 
+CanvasRenderer*
+BasicCanvasLayer::CreateCanvasRendererInternal()
+{
+  return new CopyableCanvasRenderer();
+}
+
 already_AddRefed<CanvasLayer>
 BasicLayerManager::CreateCanvasLayer()
 {
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   RefPtr<CanvasLayer> layer = new BasicCanvasLayer(this);
   return layer.forget();
 }
 
--- a/gfx/layers/basic/BasicCanvasLayer.h
+++ b/gfx/layers/basic/BasicCanvasLayer.h
@@ -3,49 +3,47 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_BASICCANVASLAYER_H
 #define GFX_BASICCANVASLAYER_H
 
 #include "BasicImplData.h"              // for BasicImplData
 #include "BasicLayers.h"                // for BasicLayerManager
-#include "CopyableCanvasLayer.h"        // for CopyableCanvasLayer
 #include "Layers.h"                     // for CanvasLayer, etc
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsRegion.h"                   // for nsIntRegion
 
 namespace mozilla {
 namespace layers {
 
-class BasicCanvasLayer : public CopyableCanvasLayer,
+class BasicCanvasLayer : public CanvasLayer,
                          public BasicImplData
 {
 public:
   explicit BasicCanvasLayer(BasicLayerManager* aLayerManager) :
-    CopyableCanvasLayer(aLayerManager, static_cast<BasicImplData*>(this))
+    CanvasLayer(aLayerManager, static_cast<BasicImplData*>(this))
   { }
 
   virtual void SetVisibleRegion(const LayerIntRegion& aRegion) override
   {
     NS_ASSERTION(BasicManager()->InConstruction(),
                  "Can only set properties in construction phase");
     CanvasLayer::SetVisibleRegion(aRegion);
   }
 
   virtual void Paint(gfx::DrawTarget* aDT,
                      const gfx::Point& aDeviceOffset,
                      Layer* aMaskLayer) override;
 
 protected:
-
-  already_AddRefed<gfx::SourceSurface> UpdateSurface();
-
   BasicLayerManager* BasicManager()
   {
     return static_cast<BasicLayerManager*>(mManager);
   }
+
+  CanvasRenderer* CreateCanvasRendererInternal() override;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -17,17 +17,16 @@
 #include "mozilla/layers/AsyncCanvasRenderer.h"
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/CompositorBridgeChild.h" // for CompositorBridgeChild
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/layers/TextureClient.h"  // for TextureClient, etc
 #include "mozilla/layers/TextureClientOGL.h"
 #include "nsDebug.h"                    // for printf_stderr, NS_ASSERTION
 #include "nsXULAppAPI.h"                // for XRE_GetProcessType, etc
-#include "ShareableCanvasLayer.h"
 #include "TextureClientSharedSurface.h"
 
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
 
 namespace mozilla {
 namespace layers {
 
@@ -86,40 +85,38 @@ CanvasClient2D::UpdateFromTexture(Textur
   t->mPictureRect = nsIntRect(nsIntPoint(0, 0), aTexture->GetSize());
   t->mFrameID = mFrameID;
 
   GetForwarder()->UseTextures(this, textures);
   aTexture->SyncWithObject(GetForwarder()->GetSyncObject());
 }
 
 void
-CanvasClient2D::Update(gfx::IntSize aSize, ShareableCanvasLayer* aLayer)
+CanvasClient2D::Update(gfx::IntSize aSize, ShareableCanvasRenderer* aCanvasRenderer)
 {
   mBufferProviderTexture = nullptr;
 
   AutoRemoveTexture autoRemove(this);
   if (mBackBuffer && (mBackBuffer->IsReadLocked() || mBackBuffer->GetSize() != aSize)) {
     autoRemove.mTexture = mBackBuffer;
     mBackBuffer = nullptr;
   }
 
   bool bufferCreated = false;
   if (!mBackBuffer) {
-    bool isOpaque = (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE);
-    gfxContentType contentType = isOpaque
-                                                ? gfxContentType::COLOR
-                                                : gfxContentType::COLOR_ALPHA;
+    gfxContentType contentType =
+      aCanvasRenderer->IsOpaque() ? gfxContentType::COLOR : gfxContentType::COLOR_ALPHA;
     gfx::SurfaceFormat surfaceFormat
       = gfxPlatform::GetPlatform()->Optimal2DFormatForContent(contentType);
     TextureFlags flags = TextureFlags::DEFAULT;
     if (mTextureFlags & TextureFlags::ORIGIN_BOTTOM_LEFT) {
       flags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
     }
 
-    mBackBuffer = CreateTextureClientForCanvas(surfaceFormat, aSize, flags, aLayer);
+    mBackBuffer = CreateTextureClientForCanvas(surfaceFormat, aSize, flags, aCanvasRenderer);
     if (!mBackBuffer) {
       NS_WARNING("Failed to allocate the TextureClient");
       return;
     }
     mBackBuffer->EnableReadLock();
     MOZ_ASSERT(mBackBuffer->CanExposeDrawTarget());
 
     bufferCreated = true;
@@ -130,17 +127,17 @@ CanvasClient2D::Update(gfx::IntSize aSiz
     TextureClientAutoLock autoLock(mBackBuffer, OpenMode::OPEN_WRITE_ONLY);
     if (!autoLock.Succeeded()) {
       mBackBuffer = nullptr;
       return;
     }
 
     RefPtr<DrawTarget> target = mBackBuffer->BorrowDrawTarget();
     if (target) {
-      if (!aLayer->UpdateTarget(target)) {
+      if (!aCanvasRenderer->UpdateTarget(target)) {
         NS_WARNING("Failed to copy the canvas into a TextureClient.");
         return;
       }
       updated = true;
     }
   }
 
   if (bufferCreated && !AddTextureClient(mBackBuffer)) {
@@ -160,19 +157,19 @@ CanvasClient2D::Update(gfx::IntSize aSiz
 
   mBackBuffer.swap(mFrontBuffer);
 }
 
 already_AddRefed<TextureClient>
 CanvasClient2D::CreateTextureClientForCanvas(gfx::SurfaceFormat aFormat,
                                              gfx::IntSize aSize,
                                              TextureFlags aFlags,
-                                             ShareableCanvasLayer* aLayer)
+                                             ShareableCanvasRenderer* aCanvasRenderer)
 {
-  if (aLayer->IsGLLayer()) {
+  if (aCanvasRenderer->HasGLContext()) {
     // We want a cairo backend here as we don't want to be copying into
     // an accelerated backend and we like LockBits to work. This is currently
     // the most effective way to make this work.
     return TextureClient::CreateForRawBufferAccess(GetForwarder(),
                                                    aFormat, aSize, BackendType::CAIRO,
                                                    mTextureFlags | aFlags);
   }
 
@@ -370,56 +367,56 @@ CloneSurface(gl::SharedSurface* src, gl:
     destSurf->ProducerAcquire();
     SharedSurface::ProdCopy(src, dest->Surf(), factory);
     destSurf->ProducerRelease();
 
     return dest.forget();
 }
 
 void
-CanvasClientSharedSurface::Update(gfx::IntSize aSize, ShareableCanvasLayer* aLayer)
+CanvasClientSharedSurface::Update(gfx::IntSize aSize, ShareableCanvasRenderer* aCanvasRenderer)
 {
   Renderer renderer;
-  renderer.construct<ShareableCanvasLayer*>(aLayer);
+  renderer.construct<ShareableCanvasRenderer*>(aCanvasRenderer);
   UpdateRenderer(aSize, renderer);
 }
 
 void
 CanvasClientSharedSurface::UpdateAsync(AsyncCanvasRenderer* aRenderer)
 {
   Renderer renderer;
   renderer.construct<AsyncCanvasRenderer*>(aRenderer);
   UpdateRenderer(aRenderer->GetSize(), renderer);
 }
 
 void
 CanvasClientSharedSurface::UpdateRenderer(gfx::IntSize aSize, Renderer& aRenderer)
 {
   GLContext* gl = nullptr;
-  ShareableCanvasLayer* layer = nullptr;
+  ShareableCanvasRenderer* canvasRenderer = nullptr;
   AsyncCanvasRenderer* asyncRenderer = nullptr;
-  if (aRenderer.constructed<ShareableCanvasLayer*>()) {
-    layer = aRenderer.ref<ShareableCanvasLayer*>();
-    gl = layer->mGLContext;
+  if (aRenderer.constructed<ShareableCanvasRenderer*>()) {
+    canvasRenderer = aRenderer.ref<ShareableCanvasRenderer*>();
+    gl = canvasRenderer->mGLContext;
   } else {
     asyncRenderer = aRenderer.ref<AsyncCanvasRenderer*>();
     gl = asyncRenderer->mGLContext;
   }
   gl->MakeCurrent();
 
   RefPtr<TextureClient> newFront;
 
-  if (layer && layer->mGLFrontbuffer) {
-    mShSurfClient = CloneSurface(layer->mGLFrontbuffer.get(), layer->mFactory.get());
+  if (canvasRenderer && canvasRenderer->mGLFrontbuffer) {
+    mShSurfClient = CloneSurface(canvasRenderer->mGLFrontbuffer.get(), canvasRenderer->mFactory.get());
     if (!mShSurfClient) {
       gfxCriticalError() << "Invalid canvas front buffer";
       return;
     }
-  } else if (layer && layer->mIsMirror) {
-    mShSurfClient = CloneSurface(gl->Screen()->Front()->Surf(), layer->mFactory.get());
+  } else if (canvasRenderer && canvasRenderer->mIsMirror) {
+    mShSurfClient = CloneSurface(gl->Screen()->Front()->Surf(), canvasRenderer->mFactory.get());
     if (!mShSurfClient) {
       return;
     }
   } else {
     mShSurfClient = gl->Screen()->Front();
     if (mShSurfClient && mShSurfClient->GetAllocator() &&
         mShSurfClient->GetAllocator() != GetForwarder()->GetTextureForwarder()) {
       mShSurfClient = CloneSurface(mShSurfClient->Surf(), gl->Screen()->Factory());
@@ -439,19 +436,19 @@ CanvasClientSharedSurface::UpdateRendere
 
   auto forwarder = GetForwarder();
 
   bool needsReadback = (surf->mType == SharedSurfaceType::Basic);
   if (needsReadback) {
     TextureFlags flags = TextureFlags::IMMUTABLE;
 
     CompositableForwarder* shadowForwarder = nullptr;
-    if (layer) {
-      flags |= layer->Flags();
-      shadowForwarder = layer->GetForwarder();
+    if (canvasRenderer) {
+      flags |= canvasRenderer->Flags();
+      shadowForwarder = canvasRenderer->GetForwarder();
     } else {
       MOZ_ASSERT(asyncRenderer);
       flags |= mTextureFlags;
       shadowForwarder = GetForwarder();
     }
 
     auto layersBackend = shadowForwarder->GetCompositorBackendType();
     mReadbackClient = TexClientFromReadback(surf, forwarder, flags, layersBackend);
--- a/gfx/layers/client/CanvasClient.h
+++ b/gfx/layers/client/CanvasClient.h
@@ -23,28 +23,28 @@
 
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
 
 namespace mozilla {
 namespace layers {
 
 class AsyncCanvasRenderer;
-class ShareableCanvasLayer;
+class ShareableCanvasRenderer;
 class CompositableForwarder;
 class ShadowableLayer;
 class SharedSurfaceTextureClient;
 
 /**
  * Compositable client for 2d and webgl canvas.
  */
 class CanvasClient : public CompositableClient
 {
 public:
-  typedef MaybeOneOf<ShareableCanvasLayer*, AsyncCanvasRenderer*> Renderer;
+  typedef MaybeOneOf<ShareableCanvasRenderer*, AsyncCanvasRenderer*> Renderer;
 
   /**
    * Creates, configures, and returns a new canvas client. If necessary, a
    * message will be sent to the compositor to create a corresponding image
    * host.
    */
   enum CanvasClientType {
     CanvasClientSurface,
@@ -62,17 +62,17 @@ public:
   {
     mTextureFlags = aFlags;
   }
 
   virtual ~CanvasClient() {}
 
   virtual void Clear() {};
 
-  virtual void Update(gfx::IntSize aSize, ShareableCanvasLayer* aLayer) = 0;
+  virtual void Update(gfx::IntSize aSize, ShareableCanvasRenderer* aCanvasRenderer) = 0;
 
   virtual bool AddTextureClient(TextureClient* aTexture) override
   {
     ++mFrameID;
     return CompositableClient::AddTextureClient(aTexture);
   }
 
   virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) {}
@@ -100,17 +100,17 @@ public:
     return TextureInfo(CompositableType::IMAGE, mTextureFlags);
   }
 
   virtual void Clear() override
   {
     mBackBuffer = mFrontBuffer = mBufferProviderTexture = nullptr;
   }
 
-  virtual void Update(gfx::IntSize aSize, ShareableCanvasLayer* aLayer) override;
+  virtual void Update(gfx::IntSize aSize, ShareableCanvasRenderer* aCanvasRenderer) override;
 
   virtual void UpdateFromTexture(TextureClient* aBuffer) override;
 
   virtual bool AddTextureClient(TextureClient* aTexture) override
   {
     return CanvasClient::AddTextureClient(aTexture);
   }
 
@@ -119,17 +119,17 @@ public:
     mBackBuffer = mFrontBuffer = nullptr;
   }
 
 private:
   already_AddRefed<TextureClient>
     CreateTextureClientForCanvas(gfx::SurfaceFormat aFormat,
                                  gfx::IntSize aSize,
                                  TextureFlags aFlags,
-                                 ShareableCanvasLayer* aLayer);
+                                 ShareableCanvasRenderer* aCanvasRenderer);
 
   RefPtr<TextureClient> mBackBuffer;
   RefPtr<TextureClient> mFrontBuffer;
   // We store this texture separately to make sure it is not written into
   // in Update() if for some silly reason we end up alternating between
   // UpdateFromTexture and Update.
   // This code is begging for a cleanup. The situation described above should
   // not be made possible.
@@ -158,17 +158,17 @@ public:
     return TextureInfo(CompositableType::IMAGE);
   }
 
   virtual void Clear() override {
     ClearSurfaces();
   }
 
   virtual void Update(gfx::IntSize aSize,
-                      ShareableCanvasLayer* aLayer) override;
+                      ShareableCanvasRenderer* aCanvasRenderer) override;
   void UpdateRenderer(gfx::IntSize aSize, Renderer& aRenderer);
 
   virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) override;
 
   virtual void Updated() override;
 
   virtual void OnDetach() override;
 };
@@ -188,17 +188,17 @@ public:
   {
   }
 
   TextureInfo GetTextureInfo() const override
   {
     return TextureInfo(CompositableType::IMAGE);
   }
 
-  virtual void Update(gfx::IntSize aSize, ShareableCanvasLayer* aLayer) override
+  virtual void Update(gfx::IntSize aSize, ShareableCanvasRenderer* aCanvasRenderer) override
   {
   }
 
   virtual void UpdateAsync(AsyncCanvasRenderer* aRenderer) override;
 
   void SetLayer(ShadowableLayer* aLayer)
   {
     mLayer = aLayer;
--- a/gfx/layers/client/ClientCanvasLayer.cpp
+++ b/gfx/layers/client/ClientCanvasLayer.cpp
@@ -18,20 +18,28 @@ ClientCanvasLayer::~ClientCanvasLayer()
 
 void
 ClientCanvasLayer::RenderLayer()
 {
   AUTO_PROFILER_LABEL("ClientCanvasLayer::RenderLayer", GRAPHICS);
 
   RenderMaskLayers(this);
 
-  UpdateCompositableClient();
+  ClientCanvasRenderer* canvasRenderer = mCanvasRenderer->AsClientCanvasRenderer();
+  MOZ_ASSERT(canvasRenderer);
+  canvasRenderer->UpdateCompositableClient();
   ClientManager()->Hold(this);
 }
 
+CanvasRenderer*
+ClientCanvasLayer::CreateCanvasRendererInternal()
+{
+  return new ClientCanvasRenderer(this);
+}
+
 already_AddRefed<CanvasLayer>
 ClientLayerManager::CreateCanvasLayer()
 {
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   RefPtr<ClientCanvasLayer> layer =
     new ClientCanvasLayer(this);
   CREATE_SHADOW(Canvas);
   return layer.forget();
--- a/gfx/layers/client/ClientCanvasLayer.h
+++ b/gfx/layers/client/ClientCanvasLayer.h
@@ -1,111 +1,85 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_CLIENTCANVASLAYER_H
 #define GFX_CLIENTCANVASLAYER_H
 
-#include "CanvasClient.h"               // for CanvasClient, etc
+#include "ClientCanvasRenderer.h"
 #include "ClientLayerManager.h"         // for ClientLayerManager, etc
 #include "Layers.h"                     // for CanvasLayer, etc
 #include "mozilla/Attributes.h"         // for override
+#include "mozilla/layers/CanvasClient.h"// for CanvasClient, etc
 #include "mozilla/layers/LayersMessages.h"  // for CanvasLayerAttributes, etc
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
-#include "ShareableCanvasLayer.h"
 
 namespace mozilla {
 namespace layers {
 
 class CompositableClient;
 class ShadowableLayer;
 
-class ClientCanvasLayer : public ShareableCanvasLayer,
+class ClientCanvasLayer : public CanvasLayer,
                           public ClientLayer
 {
 public:
   explicit ClientCanvasLayer(ClientLayerManager* aLayerManager) :
-    ShareableCanvasLayer(aLayerManager, static_cast<ClientLayer*>(this))
+    CanvasLayer(aLayerManager, static_cast<ClientLayer*>(this))
   {
     MOZ_COUNT_CTOR(ClientCanvasLayer);
   }
 
+  CanvasRenderer* CreateCanvasRendererInternal() override;
+
 protected:
   virtual ~ClientCanvasLayer();
 
 public:
   virtual void SetVisibleRegion(const LayerIntRegion& aRegion) override
   {
     NS_ASSERTION(ClientManager()->InConstruction(),
                  "Can only set properties in construction phase");
     CanvasLayer::SetVisibleRegion(aRegion);
   }
 
   virtual void RenderLayer() override;
 
   virtual void ClearCachedResources() override
   {
-    if (mBufferProvider) {
-      mBufferProvider->ClearCachedResources();
-    }
-    if (mCanvasClient) {
-      mCanvasClient->Clear();
-    }
+    mCanvasRenderer->ClearCachedResources();
   }
 
   virtual void HandleMemoryPressure() override
   {
-    if (mBufferProvider) {
-      mBufferProvider->ClearCachedResources();
-    }
-    if (mCanvasClient) {
-      mCanvasClient->HandleMemoryPressure();
-    }
+    mCanvasRenderer->ClearCachedResources();
   }
 
   virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) override
   {
     aAttrs = CanvasLayerAttributes(mSamplingFilter, mBounds);
   }
 
   virtual Layer* AsLayer()  override { return this; }
   virtual ShadowableLayer* AsShadowableLayer()  override { return this; }
 
   virtual void Disconnect() override
   {
-    if (mBufferProvider) {
-      mBufferProvider->ClearCachedResources();
-    }
-    mCanvasClient = nullptr;
-  }
-
-  virtual CompositableForwarder* GetForwarder() override
-  {
-    return mManager->AsShadowForwarder();
+    mCanvasRenderer->Destroy();
   }
 
   virtual CompositableClient* GetCompositableClient() override
   {
-    return mCanvasClient;
-  }
-
-  virtual void AttachCompositable() override
-  {
-    if (HasShadow()) {
-      if (mAsyncRenderer) {
-        static_cast<CanvasClientBridge*>(mCanvasClient.get())->SetLayer(this);
-      } else {
-        mCanvasClient->Connect();
-        ClientManager()->AsShadowForwarder()->Attach(mCanvasClient, this);
-      }
-    }
+    ClientCanvasRenderer* canvasRenderer = mCanvasRenderer->AsClientCanvasRenderer();
+    MOZ_ASSERT(canvasRenderer);
+    return canvasRenderer->GetCanvasClient();
   }
 
 protected:
   ClientLayerManager* ClientManager()
   {
     return static_cast<ClientLayerManager*>(mManager);
   }
 };
new file mode 100644
--- /dev/null
+++ b/gfx/layers/client/ClientCanvasRenderer.cpp
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ClientCanvasRenderer.h"
+
+#include "ClientCanvasLayer.h"
+
+namespace mozilla {
+namespace layers {
+
+CompositableForwarder*
+ClientCanvasRenderer::GetForwarder()
+{
+  return mLayer->Manager()->AsShadowForwarder();
+}
+
+bool
+ClientCanvasRenderer::CreateCompositable()
+{
+  if (!mCanvasClient) {
+    TextureFlags flags = TextureFlags::DEFAULT;
+    if (mOriginPos == gl::OriginPos::BottomLeft) {
+      flags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
+    }
+
+    if (!mIsAlphaPremultiplied) {
+      flags |= TextureFlags::NON_PREMULTIPLIED;
+    }
+
+    mCanvasClient = CanvasClient::CreateCanvasClient(GetCanvasClientType(),
+                                                     GetForwarder(),
+                                                     flags);
+    if (!mCanvasClient) {
+      return false;
+    }
+
+    if (mLayer->HasShadow()) {
+      if (mAsyncRenderer) {
+        static_cast<CanvasClientBridge*>(mCanvasClient.get())->SetLayer(mLayer);
+      } else {
+        mCanvasClient->Connect();
+        GetForwarder()->AsLayerForwarder()->Attach(mCanvasClient, mLayer);
+      }
+    }
+  }
+
+  return true;
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/client/ClientCanvasRenderer.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_CLIENTCANVASRENDERER_H
+#define GFX_CLIENTCANVASRENDERER_H
+
+#include "ShareableCanvasRenderer.h"
+
+namespace mozilla {
+namespace layers {
+
+class ClientCanvasLayer;
+class ClientCanvasRenderer : public ShareableCanvasRenderer
+{
+public:
+  explicit ClientCanvasRenderer(ClientCanvasLayer* aLayer)
+    : mLayer(aLayer)
+  { }
+
+  ClientCanvasRenderer* AsClientCanvasRenderer() override { return this; }
+
+  CompositableForwarder* GetForwarder() override;
+
+  bool CreateCompositable() override;
+
+protected:
+  ClientCanvasLayer* mLayer;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
--- a/gfx/layers/composite/CanvasLayerComposite.h
+++ b/gfx/layers/composite/CanvasLayerComposite.h
@@ -28,22 +28,16 @@ class CanvasLayerComposite : public Canv
 {
 public:
   explicit CanvasLayerComposite(LayerManagerComposite* aManager);
 
 protected:
   virtual ~CanvasLayerComposite();
 
 public:
-  // CanvasLayer impl
-  virtual void Initialize(const Data& aData) override
-  {
-    MOZ_CRASH("Incompatibe surface type");
-  }
-
   virtual bool SetCompositableHost(CompositableHost* aHost) override;
 
   virtual void Disconnect() override
   {
     Destroy();
   }
 
   virtual void SetLayerManager(HostLayerManager* aManager) override;
@@ -58,16 +52,21 @@ public:
 
   CompositableHost* GetCompositableHost() override;
 
   virtual HostLayer* AsHostLayer() override { return this; }
 
   virtual const char* Name() const override { return "CanvasLayerComposite"; }
 
 protected:
+  CanvasRenderer* CreateCanvasRendererInternal() override {
+    MOZ_CRASH("Incompatible surface type");
+    return nullptr;
+  }
+
   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
 
 private:
   gfx::SamplingFilter GetSamplingFilter();
 
 private:
   RefPtr<CompositableHost> mCompositableHost;
 };
--- a/gfx/layers/mlgpu/CanvasLayerMLGPU.h
+++ b/gfx/layers/mlgpu/CanvasLayerMLGPU.h
@@ -27,32 +27,33 @@ class CanvasLayerMLGPU final : public Ca
 {
 public:
   explicit CanvasLayerMLGPU(LayerManagerMLGPU* aManager);
 
 protected:
   ~CanvasLayerMLGPU() override;
 
 public:
-  void Initialize(const Data& aData) override {
-    MOZ_CRASH("Incompatibe surface type");
-  }
-
   Layer* GetLayer() override;
   void Disconnect() override;
 
   HostLayer* AsHostLayer() override { return this; }
   CanvasLayerMLGPU* AsCanvasLayerMLGPU() override { return this; }
   gfx::SamplingFilter GetSamplingFilter() override;
   void ClearCachedResources() override;
   void SetRegionToRender(LayerIntRegion&& aRegion) override;
 
   MOZ_LAYER_DECL_NAME("CanvasLayerMLGPU", TYPE_CANVAS)
 
 protected:
+  CanvasRenderer* CreateCanvasRendererInternal() override {
+    MOZ_CRASH("Incompatible surface type");
+    return nullptr;
+  }
+
   void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
   void CleanupResources();
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif /* GFX_CanvasLayerMLGPU_H */
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -123,16 +123,17 @@ EXPORTS.mozilla.layers += [
     'AtomicRefCountedWithFinalize.h',
     'AxisPhysicsModel.h',
     'AxisPhysicsMSDModel.h',
     'basic/BasicCompositor.h',
     'basic/MacIOSurfaceTextureHostBasic.h',
     'basic/TextureHostBasic.h',
     'BSPTree.h',
     'BufferTexture.h',
+    'CanvasRenderer.h',
     'client/CanvasClient.h',
     'client/CompositableClient.h',
     'client/ContentClient.h',
     'client/GPUVideoTextureClient.h',
     'client/ImageClient.h',
     'client/SingleTiledContentClient.h',
     'client/TextureClient.h',
     'client/TextureClientPool.h',
@@ -154,16 +155,17 @@ EXPORTS.mozilla.layers += [
     'composite/ImageLayerComposite.h',
     'composite/LayerManagerComposite.h',
     'composite/PaintedLayerComposite.h',
     'composite/TextRenderer.h',
     'composite/TextureHost.h',
     'composite/TiledContentHost.h',
     'Compositor.h',
     'CompositorTypes.h',
+    'CopyableCanvasRenderer.h',
     'D3D11ShareHandleImage.h',
     'D3D11YCbCrImage.h',
     'D3D9SurfaceImage.h',
     'DirectionUtils.h',
     'Effects.h',
     'ImageDataSerializer.h',
     'ipc/APZChild.h',
     'ipc/APZCTreeManagerChild.h',
@@ -213,26 +215,28 @@ EXPORTS.mozilla.layers += [
     'opengl/CompositorOGL.h',
     'opengl/MacIOSurfaceTextureClientOGL.h',
     'opengl/MacIOSurfaceTextureHostOGL.h',
     'opengl/TextureClientOGL.h',
     'opengl/TextureHostOGL.h',
     'PaintThread.h',
     'PersistentBufferProvider.h',
     'RenderTrace.h',
+    'ShareableCanvasRenderer.h',
     'SourceSurfaceSharedData.h',
     'SourceSurfaceVolatileData.h',
     'TextureSourceProvider.h',
     'TextureWrapperImage.h',
     'TransactionIdAllocator.h',
     'UpdateImageHelper.h',
     'wr/ScrollingLayersHelper.h',
     'wr/StackingContextHelper.h',
     'wr/WebRenderBridgeChild.h',
     'wr/WebRenderBridgeParent.h',
+    'wr/WebRenderCanvasRenderer.h',
     'wr/WebRenderCompositableHolder.h',
     'wr/WebRenderDisplayItemLayer.h',
     'wr/WebRenderImageHost.h',
     'wr/WebRenderLayer.h',
     'wr/WebRenderLayerManager.h',
     'wr/WebRenderLayersLogging.h',
     'wr/WebRenderMessageUtils.h',
     'wr/WebRenderScrollData.h',
@@ -332,19 +336,21 @@ UNIFIED_SOURCES += [
     'basic/BasicLayerManager.cpp',
     'basic/BasicLayersImpl.cpp',
     'basic/BasicPaintedLayer.cpp',
     'basic/BasicTextLayer.cpp',
     'basic/TextureHostBasic.cpp',
     'BSPTree.cpp',
     'BufferTexture.cpp',
     'BufferUnrotate.cpp',
+    'CanvasRenderer.cpp',
     'client/CanvasClient.cpp',
     'client/ClientBorderLayer.cpp',
     'client/ClientCanvasLayer.cpp',
+    'client/ClientCanvasRenderer.cpp',
     'client/ClientColorLayer.cpp',
     'client/ClientContainerLayer.cpp',
     'client/ClientImageLayer.cpp',
     'client/ClientLayerManager.cpp',
     'client/ClientPaintedLayer.cpp',
     'client/ClientTextLayer.cpp',
     'client/ClientTiledPaintedLayer.cpp',
     'client/CompositableClient.cpp',
@@ -372,17 +378,17 @@ UNIFIED_SOURCES += [
     'composite/ImageHost.cpp',
     'composite/ImageLayerComposite.cpp',
     'composite/LayerManagerComposite.cpp',
     'composite/PaintedLayerComposite.cpp',
     'composite/TextRenderer.cpp',
     'composite/TextureHost.cpp',
     'composite/TiledContentHost.cpp',
     'Compositor.cpp',
-    'CopyableCanvasLayer.cpp',
+    'CopyableCanvasRenderer.cpp',
     'Effects.cpp',
     'FrameMetrics.cpp',
     'GLImages.cpp',
     'ImageDataSerializer.cpp',
     'ImageLayers.cpp',
     'ipc/APZChild.cpp',
     'ipc/APZCTreeManagerChild.cpp',
     'ipc/APZCTreeManagerParent.cpp',
@@ -439,26 +445,27 @@ UNIFIED_SOURCES += [
     'opengl/TextureClientOGL.cpp',
     'opengl/TextureHostOGL.cpp',
     'opengl/TexturePoolOGL.cpp',
     'PaintThread.cpp',
     'protobuf/LayerScopePacket.pb.cc',
     'ReadbackProcessor.cpp',
     'RenderTrace.cpp',
     'RotatedBuffer.cpp',
-    'ShareableCanvasLayer.cpp',
+    'ShareableCanvasRenderer.cpp',
     'SourceSurfaceSharedData.cpp',
     'SourceSurfaceVolatileData.cpp',
     'TextureSourceProvider.cpp',
     'TextureWrapperImage.cpp',
     'wr/ScrollingLayersHelper.cpp',
     'wr/StackingContextHelper.cpp',
     'wr/WebRenderBridgeChild.cpp',
     'wr/WebRenderBridgeParent.cpp',
     'wr/WebRenderCanvasLayer.cpp',
+    'wr/WebRenderCanvasRenderer.cpp',
     'wr/WebRenderColorLayer.cpp',
     'wr/WebRenderCompositableHolder.cpp',
     'wr/WebRenderContainerLayer.cpp',
     'wr/WebRenderDisplayItemLayer.cpp',
     'wr/WebRenderImageHost.cpp',
     'wr/WebRenderImageLayer.cpp',
     'wr/WebRenderLayer.cpp',
     'wr/WebRenderLayerManager.cpp',
--- a/gfx/layers/wr/WebRenderCanvasLayer.cpp
+++ b/gfx/layers/wr/WebRenderCanvasLayer.cpp
@@ -15,62 +15,42 @@
 #include "mozilla/layers/ScrollingLayersHelper.h"
 #include "mozilla/layers/StackingContextHelper.h"
 #include "mozilla/layers/TextureClientSharedSurface.h"
 #include "mozilla/layers/WebRenderBridgeChild.h"
 #include "PersistentBufferProvider.h"
 #include "SharedSurface.h"
 #include "SharedSurfaceGL.h"
 #include "mozilla/webrender/WebRenderTypes.h"
+#include "WebRenderCanvasRenderer.h"
 
 namespace mozilla {
 namespace layers {
 
 WebRenderCanvasLayer::~WebRenderCanvasLayer()
 {
   MOZ_COUNT_DTOR(WebRenderCanvasLayer);
-  ClearWrResources();
-}
-
-void
-WebRenderCanvasLayer::ClearWrResources()
-{
-  if (mExternalImageId.isSome()) {
-    WrBridge()->DeallocExternalImageId(mExternalImageId.ref());
-    mExternalImageId = Nothing();
-  }
 }
 
-void
-WebRenderCanvasLayer::Initialize(const Data& aData)
+CanvasRenderer*
+WebRenderCanvasLayer::CreateCanvasRendererInternal()
 {
-  ShareableCanvasLayer::Initialize(aData);
-
-  // XXX: Use basic surface factory until we support shared surface.
-  if (!mGLContext || mGLFrontbuffer)
-    return;
-
-  gl::GLScreenBuffer* screen = mGLContext->Screen();
-  auto factory = MakeUnique<gl::SurfaceFactory_Basic>(mGLContext, screen->mCaps, mFlags);
-  screen->Morph(Move(factory));
+  return new WebRenderCanvasRendererSync(mManager->AsWebRenderLayerManager());
 }
 
 void
 WebRenderCanvasLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
                                   const StackingContextHelper& aSc)
 {
-  UpdateCompositableClient();
-
-  if (mExternalImageId.isNothing()) {
-    mExternalImageId = Some(WrBridge()->AllocExternalImageIdForCompositable(mCanvasClient));
-  }
+  WebRenderCanvasRendererSync* canvasRenderer = mCanvasRenderer->AsWebRenderCanvasRendererSync();
+  MOZ_ASSERT(canvasRenderer);
+  canvasRenderer->UpdateCompositableClient();
 
   Maybe<gfx::Matrix4x4> transform;
-  const bool needsYFlip = (mOriginPos == gl::OriginPos::BottomLeft);
-  if (needsYFlip) {
+  if (canvasRenderer->NeedsYFlip()) {
     transform = Some(GetTransform().PreTranslate(0, mBounds.height, 0).PreScale(1, -1, 1));
   }
 
   ScrollingLayersHelper scroller(this, aBuilder, aSc);
   StackingContextHelper sc(aSc, aBuilder, this, transform);
 
   LayerRect rect(0, 0, mBounds.width, mBounds.height);
   DumpLayerInfo("CanvasLayer", rect);
@@ -79,41 +59,23 @@ WebRenderCanvasLayer::RenderLayer(wr::Di
 
   if (gfxPrefs::LayersDump()) {
     printf_stderr("CanvasLayer %p texture-filter=%s\n",
                   this->GetLayer(),
                   Stringify(filter).c_str());
   }
 
   wr::WrImageKey key = GetImageKey();
-  WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(mExternalImageId.value(), key));
+  WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(canvasRenderer->GetExternalImageId().value(), key));
   WrManager()->AddImageKeyForDiscard(key);
 
   wr::LayoutRect r = sc.ToRelativeLayoutRect(rect);
   aBuilder.PushImage(r, r, filter, key);
 }
 
 void
-WebRenderCanvasLayer::AttachCompositable()
-{
-  mCanvasClient->Connect();
-}
-
-CompositableForwarder*
-WebRenderCanvasLayer::GetForwarder()
-{
-  return WrManager()->WrBridge();
-}
-
-void
 WebRenderCanvasLayer::ClearCachedResources()
 {
-  ClearWrResources();
-  if (mBufferProvider) {
-    mBufferProvider->ClearCachedResources();
-  }
-  if (mCanvasClient) {
-    mCanvasClient->Clear();
-  }
+  mCanvasRenderer->ClearCachedResources();
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/wr/WebRenderCanvasLayer.h
+++ b/gfx/layers/wr/WebRenderCanvasLayer.h
@@ -1,55 +1,46 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_WEBRENDERCANVASLAYER_H
 #define GFX_WEBRENDERCANVASLAYER_H
 
+#include "Layers.h"
 #include "mozilla/layers/WebRenderLayer.h"
 #include "mozilla/layers/WebRenderLayerManager.h"
-#include "ShareableCanvasLayer.h"
 
 namespace mozilla {
 namespace gfx {
 class SourceSurface;
 }; // namespace gfx
 
 namespace layers {
 
 class WebRenderCanvasLayer : public WebRenderLayer,
-                             public ShareableCanvasLayer
+                             public CanvasLayer
 {
 public:
   explicit WebRenderCanvasLayer(WebRenderLayerManager* aLayerManager)
-    : ShareableCanvasLayer(aLayerManager, static_cast<WebRenderLayer*>(this))
+    : CanvasLayer(aLayerManager, static_cast<WebRenderLayer*>(this))
   {
     MOZ_COUNT_CTOR(WebRenderCanvasLayer);
   }
 
-  virtual void Initialize(const Data& aData) override;
-
-  virtual CompositableForwarder* GetForwarder() override;
-
-  virtual void AttachCompositable() override;
+  CanvasRenderer* CreateCanvasRendererInternal() override;
 
   virtual void ClearCachedResources() override;
 
 protected:
   virtual ~WebRenderCanvasLayer();
 
-  void ClearWrResources();
-
 public:
   Layer* GetLayer() override { return this; }
   void RenderLayer(wr::DisplayListBuilder& aBuilder,
                    const StackingContextHelper& aSc) override;
-
-protected:
-  wr::MaybeExternalImageId mExternalImageId;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // GFX_WEBRENDERCANVASLAYER_H
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderCanvasRenderer.cpp
@@ -0,0 +1,165 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebRenderCanvasRenderer.h"
+
+namespace mozilla {
+namespace layers {
+
+CompositableForwarder*
+WebRenderCanvasRenderer::GetForwarder()
+{
+  return mManager->WrBridge();
+}
+
+void
+WebRenderCanvasRenderer::Initialize(const CanvasInitializeData& aData)
+{
+  ShareableCanvasRenderer::Initialize(aData);
+
+  // XXX: Use basic surface factory until we support shared surface.
+  if (!mGLContext || mGLFrontbuffer)
+    return;
+
+  gl::GLScreenBuffer* screen = mGLContext->Screen();
+  auto factory = MakeUnique<gl::SurfaceFactory_Basic>(mGLContext,
+                                                      screen->mCaps,
+                                                      mFlags);
+  screen->Morph(Move(factory));
+}
+
+WebRenderCanvasRendererSync::~WebRenderCanvasRendererSync()
+{
+  Destroy();
+}
+
+void
+WebRenderCanvasRendererSync::Initialize(const CanvasInitializeData& aData)
+{
+  WebRenderCanvasRenderer::Initialize(aData);
+
+  if (mExternalImageId.isSome()) {
+    mManager->WrBridge()->DeallocExternalImageId(mExternalImageId.ref());
+    mExternalImageId.reset();
+  }
+}
+
+bool
+WebRenderCanvasRendererSync::CreateCompositable()
+{
+  if (!mCanvasClient) {
+    TextureFlags flags = TextureFlags::DEFAULT;
+    if (mOriginPos == gl::OriginPos::BottomLeft) {
+      flags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
+    }
+
+    if (!mIsAlphaPremultiplied) {
+      flags |= TextureFlags::NON_PREMULTIPLIED;
+    }
+
+    mCanvasClient = CanvasClient::CreateCanvasClient(GetCanvasClientType(),
+                                                     GetForwarder(),
+                                                     flags);
+    if (!mCanvasClient) {
+      return false;
+    }
+
+    mCanvasClient->Connect();
+  }
+
+  if (mExternalImageId.isNothing()) {
+    mExternalImageId = Some(mManager->WrBridge()->AllocExternalImageIdForCompositable(mCanvasClient));
+  }
+
+  return true;
+}
+
+void
+WebRenderCanvasRendererSync::ClearCachedResources()
+{
+  if (mExternalImageId.isSome()) {
+    mManager->WrBridge()->DeallocExternalImageId(mExternalImageId.ref());
+    mExternalImageId.reset();
+  }
+}
+
+void
+WebRenderCanvasRendererSync::Destroy()
+{
+  if (mExternalImageId.isSome()) {
+    mManager->WrBridge()->DeallocExternalImageId(mExternalImageId.ref());
+    mExternalImageId.reset();
+  }
+}
+
+WebRenderCanvasRendererAsync::~WebRenderCanvasRendererAsync()
+{
+  Destroy();
+}
+
+void
+WebRenderCanvasRendererAsync::Initialize(const CanvasInitializeData& aData)
+{
+  WebRenderCanvasRenderer::Initialize(aData);
+
+  if (mPipelineId.isSome()) {
+    mManager->WrBridge()->RemovePipelineIdForCompositable(mPipelineId.ref());
+    mPipelineId.reset();
+  }
+}
+
+bool
+WebRenderCanvasRendererAsync::CreateCompositable()
+{
+  if (!mCanvasClient) {
+    TextureFlags flags = TextureFlags::DEFAULT;
+    if (mOriginPos == gl::OriginPos::BottomLeft) {
+      flags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
+    }
+
+    if (!mIsAlphaPremultiplied) {
+      flags |= TextureFlags::NON_PREMULTIPLIED;
+    }
+
+    mCanvasClient = CanvasClient::CreateCanvasClient(GetCanvasClientType(),
+                                                     GetForwarder(),
+                                                     flags);
+    if (!mCanvasClient) {
+      return false;
+    }
+
+    mCanvasClient->Connect();
+  }
+
+  if (!mPipelineId) {
+    // Alloc async image pipeline id.
+    mPipelineId = Some(mManager->WrBridge()->GetCompositorBridgeChild()->GetNextPipelineId());
+    mManager->WrBridge()->AddPipelineIdForCompositable(mPipelineId.ref(),
+                                                       mCanvasClient->GetIPCHandle());
+  }
+
+  return true;
+}
+
+void
+WebRenderCanvasRendererAsync::ClearCachedResources()
+{
+  if (mPipelineId.isSome()) {
+    mManager->WrBridge()->RemovePipelineIdForCompositable(mPipelineId.ref());
+    mPipelineId.reset();
+  }
+}
+
+void
+WebRenderCanvasRendererAsync::Destroy()
+{
+  if (mPipelineId.isSome()) {
+    mManager->WrBridge()->RemovePipelineIdForCompositable(mPipelineId.ref());
+    mPipelineId.reset();
+  }
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderCanvasRenderer.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_WEBRENDERCANVASRENDERER_H
+#define GFX_WEBRENDERCANVASRENDERER_H
+
+#include "ShareableCanvasRenderer.h"
+
+namespace mozilla {
+namespace layers {
+
+class WebRenderLayerManager;
+
+class WebRenderCanvasRenderer : public ShareableCanvasRenderer
+{
+public:
+  explicit WebRenderCanvasRenderer(WebRenderLayerManager* aManager)
+    : mManager(aManager)
+  { }
+
+  void Initialize(const CanvasInitializeData& aData) override;
+
+  CompositableForwarder* GetForwarder() override;
+
+protected:
+  WebRenderLayerManager* mManager;
+};
+
+class WebRenderCanvasRendererSync : public WebRenderCanvasRenderer
+{
+public:
+  explicit WebRenderCanvasRendererSync(WebRenderLayerManager* aManager)
+    : WebRenderCanvasRenderer(aManager)
+  { }
+  virtual ~WebRenderCanvasRendererSync();
+
+  WebRenderCanvasRendererSync* AsWebRenderCanvasRendererSync() override { return this; }
+
+  void Initialize(const CanvasInitializeData& aData) override;
+  bool CreateCompositable() override;
+
+  void ClearCachedResources() override;
+  void Destroy() override;
+
+  wr::MaybeExternalImageId GetExternalImageId() { return mExternalImageId; }
+protected:
+  wr::MaybeExternalImageId mExternalImageId;
+};
+
+class WebRenderCanvasRendererAsync : public WebRenderCanvasRenderer
+{
+public:
+  explicit WebRenderCanvasRendererAsync(WebRenderLayerManager* aManager)
+    : WebRenderCanvasRenderer(aManager)
+  { }
+  virtual ~WebRenderCanvasRendererAsync();
+
+  WebRenderCanvasRendererAsync* AsWebRenderCanvasRendererAsync() override { return this; }
+
+  void Initialize(const CanvasInitializeData& aData) override;
+  bool CreateCompositable() override;
+
+  void ClearCachedResources() override;
+  void Destroy() override;
+
+  Maybe<wr::PipelineId> GetPipelineId() { return mPipelineId; }
+protected:
+  Maybe<wr::PipelineId> mPipelineId;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
--- a/layout/generic/nsHTMLCanvasFrame.cpp
+++ b/layout/generic/nsHTMLCanvasFrame.cpp
@@ -352,25 +352,36 @@ nsHTMLCanvasFrame::BuildLayer(nsDisplayL
   gfxPoint p = destGFXRect.TopLeft() + aContainerParameters.mOffset;
   Matrix transform = Matrix::Translation(p.x, p.y);
   transform.PreScale(destGFXRect.Width() / canvasSizeInPx.width,
                      destGFXRect.Height() / canvasSizeInPx.height);
   layer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
   if (layer->GetType() == layers::Layer::TYPE_CANVAS) {
     RefPtr<CanvasLayer> canvasLayer = static_cast<CanvasLayer*>(layer.get());
     canvasLayer->SetSamplingFilter(nsLayoutUtils::GetSamplingFilterForFrame(this));
+    nsIntRect bounds;
+    bounds.SetRect(0, 0, canvasSizeInPx.width, canvasSizeInPx.height);
+    canvasLayer->SetBounds(bounds);
   } else if (layer->GetType() == layers::Layer::TYPE_IMAGE) {
     RefPtr<ImageLayer> imageLayer = static_cast<ImageLayer*>(layer.get());
     imageLayer->SetSamplingFilter(nsLayoutUtils::GetSamplingFilterForFrame(this));
   }
 
   return layer.forget();
 }
 
 void
+nsHTMLCanvasFrame::InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+                                            CanvasRenderer* aRenderer)
+{
+  HTMLCanvasElement* element = static_cast<HTMLCanvasElement*>(GetContent());
+  element->InitializeCanvasRenderer(aBuilder, aRenderer);
+}
+
+void
 nsHTMLCanvasFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                     const nsRect&           aDirtyRect,
                                     const nsDisplayListSet& aLists)
 {
   if (!IsVisibleForPainting(aBuilder))
     return;
 
   DisplayBorderBackgroundOutline(aBuilder, aLists);
--- a/layout/generic/nsHTMLCanvasFrame.h
+++ b/layout/generic/nsHTMLCanvasFrame.h
@@ -23,16 +23,17 @@ class nsPresContext;
 class nsDisplayItem;
 class nsAString;
 
 nsIFrame* NS_NewHTMLCanvasFrame (nsIPresShell* aPresShell, nsStyleContext* aContext);
 
 class nsHTMLCanvasFrame final : public nsContainerFrame
 {
 public:
+  typedef mozilla::layers::CanvasRenderer CanvasRenderer;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
 
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS(nsHTMLCanvasFrame)
 
   explicit nsHTMLCanvasFrame(nsStyleContext* aContext)
@@ -47,16 +48,18 @@ public:
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) override;
 
   already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                      LayerManager* aManager,
                                      nsDisplayItem* aItem,
                                      const ContainerLayerParameters& aContainerParameters);
+  void InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+                                CanvasRenderer* aRenderer);
 
   /* get the size of the canvas's image */
   nsIntSize GetCanvasSize();
 
   virtual nscoord GetMinISize(gfxContext *aRenderingContext) override;
   virtual nscoord GetPrefISize(gfxContext *aRenderingContext) override;
   virtual mozilla::IntrinsicSize GetIntrinsicSize() override;
   virtual nsSize GetIntrinsicRatio() override;