Tear down ImageBuffer's reference to HTMLCanvasElement via ImageBufferClient

As a first step to remove ImageBuffer(Surface), this CL refactors the
followings:
- Remove ImageBufferClient and break ImageBuffer's reference to canvas element
- Move ImageBuffer's various functions to HTMLCanvasElement, including
    UpdateGPUMemoryUsage, DisableAcceleration, gpu_readback_frame computation,
    etc.)
- Introduce abstract class CanvasResourceHost as a way for
    Canvas2DLayerBridge (and temporarily, RecordingImageBufferSurface) to point
    to HTMLCanvasElement.
- Reconcile UpdateGPUMemoryUsage() and UpdateExternallyAllocatedMemory() in one
    single function.


Bug: 776806
Cq-Include-Trybots: master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: I7b3fdfad476c02b6e4368d3ef1e5eca9688cbf5b
Reviewed-on: https://chromium-review.googlesource.com/774996
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Reviewed-by: Justin Novosad <junov@chromium.org>
Commit-Queue: Olivia Lai <xlai@chromium.org>
Cr-Commit-Position: refs/heads/master@{#518980}
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
index 8ff3278..59635f3 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -81,7 +81,6 @@
 #include "platform/graphics/paint/PaintCanvas.h"
 #include "platform/image-encoders/ImageEncoderUtils.h"
 #include "platform/runtime_enabled_features.h"
-#include "platform/transforms/AffineTransform.h"
 #include "platform/wtf/CheckedNumeric.h"
 #include "platform/wtf/PtrUtil.h"
 #include "public/platform/Platform.h"
@@ -112,8 +111,8 @@
 // to be equivalent to memory used by 100 accelerated canvases, each has a size
 // of 1000*500 and 2d context.
 // Each such canvas occupies 4000000 = 1000 * 500 * 2 * 4 bytes, where 2 is the
-// gpuBufferCount in ImageBuffer::updateGPUMemoryUsage() and 4 means four bytes
-// per pixel per buffer.
+// gpuBufferCount in UpdateMemoryUsage() and 4 means four bytes per pixel per
+// buffer.
 const int kMaxGlobalGPUMemoryUsage =
     4000000 * kMaxGlobalAcceleratedImageBufferCount;
 
@@ -140,17 +139,23 @@
       PageVisibilityObserver(document.GetPage()),
       size_(kDefaultWidth, kDefaultHeight),
       ignore_reset_(false),
-      externally_allocated_memory_(0),
       origin_clean_(true),
       did_fail_to_create_image_buffer_(false),
       image_buffer_is_clear_(false),
-      surface_layer_bridge_(nullptr) {
+      surface_layer_bridge_(nullptr),
+      gpu_memory_usage_(0),
+      externally_allocated_memory_(0),
+      gpu_readback_invoked_in_current_frame_(false),
+      gpu_readback_successive_frames_(0) {
   CanvasMetrics::CountCanvasContextUsage(CanvasMetrics::kCanvasCreated);
   UseCounter::Count(document, WebFeature::kHTMLCanvasElement);
 }
 
 DEFINE_NODE_FACTORY(HTMLCanvasElement)
 
+intptr_t HTMLCanvasElement::global_gpu_memory_usage_ = 0;
+unsigned HTMLCanvasElement::global_accelerated_context_count_ = 0;
+
 HTMLCanvasElement::~HTMLCanvasElement() {
   if (surface_layer_bridge_ && surface_layer_bridge_->GetWebLayer()) {
     GraphicsLayer::UnregisterContentsLayer(
@@ -170,9 +175,15 @@
   }
 
   if (image_buffer_) {
-    image_buffer_->SetClient(nullptr);
+    image_buffer_->OnCanvasDisposed();
     image_buffer_ = nullptr;
   }
+
+  if (gpu_memory_usage_) {
+    DCHECK_GT(global_accelerated_context_count_, 0u);
+    global_accelerated_context_count_--;
+  }
+  global_gpu_memory_usage_ -= gpu_memory_usage_;
 }
 
 void HTMLCanvasElement::ParseAttribute(
@@ -296,7 +307,7 @@
   probe::didCreateCanvasContext(&GetDocument());
 
   if (Is3d()) {
-    UpdateExternallyAllocatedMemory();
+    UpdateMemoryUsage();
   }
 
   LayoutObject* layout_object = this->GetLayoutObject();
@@ -380,8 +391,26 @@
 }
 
 void HTMLCanvasElement::FinalizeFrame() {
-  if (GetImageBuffer())
+  if (GetImageBuffer()) {
+    // Compute to determine whether disable accleration is needed
+    if (IsAccelerated() &&
+        CanvasHeuristicParameters::kGPUReadbackForcesNoAcceleration &&
+        !RuntimeEnabledFeatures::Canvas2dFixedRenderingModeEnabled()) {
+      if (gpu_readback_invoked_in_current_frame_) {
+        gpu_readback_successive_frames_++;
+        gpu_readback_invoked_in_current_frame_ = false;
+      } else {
+        gpu_readback_successive_frames_ = 0;
+      }
+
+      if (gpu_readback_successive_frames_ >=
+          CanvasHeuristicParameters::kGPUReadbackMinSuccessiveFrames) {
+        DisableAcceleration();
+      }
+    }
+
     image_buffer_->FinalizeFrame();
+  }
 
   // If the canvas is visible, notifying listeners is taken
   // care of in the in doDeferredPaintInvalidation, which allows
@@ -395,7 +424,17 @@
   did_notify_listeners_for_current_frame_ = false;
 }
 
-void HTMLCanvasElement::DidDisableAcceleration() {
+void HTMLCanvasElement::DisableAcceleration() {
+  // Create and configure a recording (unaccelerated) surface.
+  std::unique_ptr<ImageBufferSurface> surface =
+      WTF::WrapUnique(new RecordingImageBufferSurface(
+          Size(), RecordingImageBufferSurface::kAllowFallback, ColorParams()));
+  if (image_buffer_) {
+    RestoreCanvasMatrixClipStack(surface->Canvas());
+    image_buffer_->SetSurface(std::move(surface));
+    UpdateMemoryUsage();
+  }
+
   // We must force a paint invalidation on the canvas even if it's
   // content did not change because it layer was destroyed.
   DidDraw();
@@ -918,13 +957,13 @@
     // accelerated canvases), the compositor starves and browser becomes laggy.
     // Thus, we should stop allocating more GPU memory to new canvases created
     // when the current memory usage exceeds the threshold.
-    if (ImageBuffer::GetGlobalGPUMemoryUsage() >= kMaxGlobalGPUMemoryUsage)
+    if (global_gpu_memory_usage_ >= kMaxGlobalGPUMemoryUsage)
       return false;
 
     // Allocating too many GPU resources can makes us run into the driver's
     // resource limits. So we need to keep the number of texture resources
     // under tight control
-    if (ImageBuffer::GetGlobalAcceleratedImageBufferCount() >=
+    if (global_accelerated_context_count_ >=
         kMaxGlobalAcceleratedImageBufferCount)
       return false;
   }
@@ -1080,13 +1119,12 @@
   if (!surface)
     return;
   DCHECK(surface->IsValid());
+  surface->SetCanvasResourceHost(this);
   image_buffer_ = ImageBuffer::Create(std::move(surface));
-  DCHECK(image_buffer_);
-  image_buffer_->SetClient(this);
 
   did_fail_to_create_image_buffer_ = false;
 
-  UpdateExternallyAllocatedMemory();
+  UpdateMemoryUsage();
 
   if (Is3d()) {
     // Early out for WebGL canvases
@@ -1124,42 +1162,6 @@
   HTMLElement::TraceWrappers(visitor);
 }
 
-void HTMLCanvasElement::UpdateExternallyAllocatedMemory() const {
-  int buffer_count = 0;
-  if (image_buffer_) {
-    buffer_count++;
-    if (image_buffer_->IsAccelerated()) {
-      // The number of internal GPU buffers vary between one (stable
-      // non-displayed state) and three (triple-buffered animations).
-      // Adding 2 is a pessimistic but relevant estimate.
-      // Note: These buffers might be allocated in GPU memory.
-      buffer_count += 2;
-    }
-  }
-  if (copied_image_)
-    buffer_count++;
-
-  // Multiplying number of buffers by bytes per pixel
-  CheckedNumeric<intptr_t> checked_externally_allocated_memory =
-      buffer_count * ColorParams().BytesPerPixel();
-  if (Is3d()) {
-    checked_externally_allocated_memory +=
-        context_->ExternallyAllocatedBytesPerPixel();
-  }
-
-  checked_externally_allocated_memory *= width();
-  checked_externally_allocated_memory *= height();
-  intptr_t externally_allocated_memory =
-      checked_externally_allocated_memory.ValueOrDefault(
-          std::numeric_limits<intptr_t>::max());
-
-  // Subtracting two intptr_t that are known to be positive will never
-  // underflow.
-  v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(
-      externally_allocated_memory - externally_allocated_memory_);
-  externally_allocated_memory_ = externally_allocated_memory;
-}
-
 PaintCanvas* HTMLCanvasElement::DrawingCanvas() {
   return GetOrCreateImageBuffer() ? GetImageBuffer()->Canvas() : nullptr;
 }
@@ -1193,17 +1195,6 @@
   CreateImageBufferInternal(std::move(surface));
 }
 
-void HTMLCanvasElement::EnsureUnacceleratedImageBuffer() {
-  DCHECK(context_);
-  if ((GetImageBuffer() && !GetImageBuffer()->IsAccelerated()) ||
-      did_fail_to_create_image_buffer_)
-    return;
-  DiscardImageBuffer();
-  image_buffer_ = ImageBuffer::Create(Size(), kInitializeImagePixels,
-                                      context_->ColorParams());
-  did_fail_to_create_image_buffer_ = !image_buffer_;
-}
-
 scoped_refptr<Image> HTMLCanvasElement::CopiedImage(
     SourceDrawingBuffer source_buffer,
     AccelerationHint hint,
@@ -1235,7 +1226,7 @@
     need_to_update |= context_->PaintRenderingResultsToCanvas(source_buffer);
   if (need_to_update && GetOrCreateImageBuffer()) {
     copied_image_ = GetImageBuffer()->NewImageSnapshot(hint, snapshot_reason);
-    UpdateExternallyAllocatedMemory();
+    UpdateMemoryUsage();
   }
   return copied_image_;
 }
@@ -1243,21 +1234,16 @@
 void HTMLCanvasElement::DiscardImageBuffer() {
   image_buffer_.reset();
   dirty_rect_ = FloatRect();
-  UpdateExternallyAllocatedMemory();
+  UpdateMemoryUsage();
 }
 
 void HTMLCanvasElement::ClearCopiedImage() {
   if (copied_image_) {
     copied_image_ = nullptr;
-    UpdateExternallyAllocatedMemory();
+    UpdateMemoryUsage();
   }
 }
 
-AffineTransform HTMLCanvasElement::BaseTransform() const {
-  DCHECK(GetImageBuffer() && !did_fail_to_create_image_buffer_);
-  return image_buffer_->BaseTransform();
-}
-
 void HTMLCanvasElement::PageVisibilityChanged() {
   bool hidden = !GetPage()->IsPageVisible();
   SetSuspendOffscreenCanvasAnimation(hidden);
@@ -1301,7 +1287,9 @@
     std::unique_ptr<ImageBufferSurface> surface =
         CreateAcceleratedImageBufferSurface(&msaa_sample_count);
     if (surface) {
+      RestoreCanvasMatrixClipStack(surface->Canvas());
       GetOrCreateImageBuffer()->SetSurface(std::move(surface));
+      UpdateMemoryUsage();
       SetNeedsCompositingUpdate();
     }
   }
@@ -1361,7 +1349,7 @@
         !RuntimeEnabledFeatures::Canvas2dFixedRenderingModeEnabled() &&
         hint == kPreferNoAcceleration && GetImageBuffer() &&
         GetImageBuffer()->IsAccelerated()) {
-      GetImageBuffer()->DisableAcceleration();
+      DisableAcceleration();
     }
     image = RenderingContext()->GetImage(hint, reason);
     if (!image) {
@@ -1538,4 +1526,58 @@
   return GetDocument().GetStyleEngine().GetFontSelector();
 }
 
+void HTMLCanvasElement::UpdateMemoryUsage() {
+  int non_gpu_buffer_count = 0;
+  int gpu_buffer_count = 0;
+  if (image_buffer_) {
+    non_gpu_buffer_count++;
+    if (image_buffer_->IsAccelerated()) {
+      // The number of internal GPU buffers vary between one (stable
+      // non-displayed state) and three (triple-buffered animations).
+      // Adding 2 is a pessimistic but relevant estimate.
+      // Note: These buffers might be allocated in GPU memory.
+      gpu_buffer_count = 2;
+    }
+  }
+
+  if (copied_image_)
+    non_gpu_buffer_count++;
+
+  if (Is3d())
+    non_gpu_buffer_count += context_->ExternallyAllocatedBufferCountPerPixel();
+
+  int multiplier = ColorParams().BytesPerPixel() * width() * height();
+  CheckedNumeric<intptr_t> checked_usage = 0;
+
+  // Re-computation of gpu memory usage is only carried out when there is a
+  // a change from acceleration to non-accleration or vice versa.
+  if (gpu_buffer_count && !gpu_memory_usage_) {
+    // Switch from non-acceleration mode to acceleration mode
+    checked_usage += multiplier * gpu_buffer_count;
+    intptr_t gpu_memory_usage =
+        checked_usage.ValueOrDefault(std::numeric_limits<intptr_t>::max());
+
+    global_gpu_memory_usage_ += (gpu_memory_usage - gpu_memory_usage_);
+    gpu_memory_usage_ = gpu_memory_usage;
+    global_accelerated_context_count_++;
+  } else if (!gpu_buffer_count && gpu_memory_usage_) {
+    // Switch from acceleration mode to non-acceleration mode
+    DCHECK_GT(global_accelerated_context_count_, 0u);
+    global_accelerated_context_count_--;
+    global_gpu_memory_usage_ -= gpu_memory_usage_;
+    gpu_memory_usage_ = 0;
+  }
+
+  // Recomputation of externally memory usage computation is carried out
+  // in all cases.
+  checked_usage += multiplier * non_gpu_buffer_count;
+  intptr_t externally_allocated_memory =
+      checked_usage.ValueOrDefault(std::numeric_limits<intptr_t>::max());
+  // Subtracting two intptr_t that are known to be positive will never
+  // underflow.
+  v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(
+      externally_allocated_memory - externally_allocated_memory_);
+  externally_allocated_memory_ = externally_allocated_memory;
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
index 6167745..4a5d7c1 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
@@ -44,9 +44,9 @@
 #include "platform/bindings/ScriptWrappableVisitor.h"
 #include "platform/geometry/FloatRect.h"
 #include "platform/geometry/IntSize.h"
+#include "platform/graphics/CanvasResourceHost.h"
 #include "platform/graphics/GraphicsTypes.h"
 #include "platform/graphics/GraphicsTypes3D.h"
-#include "platform/graphics/ImageBufferClient.h"
 #include "platform/graphics/OffscreenCanvasPlaceholder.h"
 #include "platform/graphics/SurfaceLayerBridge.h"
 #include "platform/heap/Handle.h"
@@ -55,7 +55,6 @@
 
 namespace blink {
 
-class AffineTransform;
 class CanvasColorParams;
 class CanvasContextCreationAttributes;
 class CanvasRenderingContext;
@@ -82,9 +81,9 @@
       public CanvasImageSource,
       public CanvasRenderingContextHost,
       public WebSurfaceLayerBridgeObserver,
-      public ImageBufferClient,
       public ImageBitmapSource,
-      public OffscreenCanvasPlaceholder {
+      public OffscreenCanvasPlaceholder,
+      public CanvasResourceHost {
   DEFINE_WRAPPERTYPEINFO();
   USING_GARBAGE_COLLECTED_MIXIN(HTMLCanvasElement);
   USING_PRE_FINALIZER(HTMLCanvasElement, Dispose);
@@ -147,7 +146,6 @@
 
   CanvasRenderingContext* RenderingContext() const { return context_.Get(); }
 
-  void EnsureUnacceleratedImageBuffer();
   scoped_refptr<Image> CopiedImage(SourceDrawingBuffer,
                                    AccelerationHint,
                                    SnapshotReason);
@@ -156,8 +154,6 @@
   bool OriginClean() const;
   void SetOriginTainted() { origin_clean_ = false; }
 
-  AffineTransform BaseTransform() const;
-
   bool Is3d() const;
   bool Is2d() const;
   bool IsAnimated2d() const;
@@ -204,11 +200,13 @@
   void RegisterContentsLayer(WebLayer*) override;
   void UnregisterContentsLayer(WebLayer*) override;
 
-  // ImageBufferClient implementation
+  // CanvasResourceHost implementation
   void NotifySurfaceInvalid() override;
-  void DidDisableAcceleration() override;
   void RestoreCanvasMatrixClipStack(PaintCanvas*) const override;
   void SetNeedsCompositingUpdate() override;
+  void UpdateMemoryUsage() override;
+
+  void DisableAcceleration();
 
   // ImageBitmapSource implementation
   IntSize BitmapSourceSize() const override;
@@ -231,7 +229,6 @@
 
   static void RegisterRenderingContextFactory(
       std::unique_ptr<CanvasRenderingContextFactory>);
-  void UpdateExternallyAllocatedMemory() const;
 
   void StyleDidChange(const ComputedStyle* old_style,
                       const ComputedStyle& new_style);
@@ -269,6 +266,16 @@
   bool IsWebGL2Enabled() const override;
   bool IsWebGLBlocked() const override;
 
+  // Memory Management
+  static intptr_t GetGlobalGPUMemoryUsage() { return global_gpu_memory_usage_; }
+  static unsigned GetGlobalAcceleratedContextCount() {
+    return global_accelerated_context_count_;
+  }
+  intptr_t GetGPUMemoryUsage() { return gpu_memory_usage_; }
+  void DidInvokeGPUReadbackInCurrentFrame() {
+    gpu_readback_invoked_in_current_frame_ = true;
+  }
+
  protected:
   void DidMoveToNewDocument(Document& old_document) override;
 
@@ -322,8 +329,6 @@
   bool ignore_reset_;
   FloatRect dirty_rect_;
 
-  mutable intptr_t externally_allocated_memory_;
-
   bool origin_clean_;
 
   // It prevents HTMLCanvasElement::buffer() from continuously re-attempting to
@@ -340,6 +345,15 @@
   std::unique_ptr<::blink::SurfaceLayerBridge> surface_layer_bridge_;
 
   bool did_notify_listeners_for_current_frame_ = false;
+
+  // GPU Memory Management
+  static intptr_t global_gpu_memory_usage_;
+  static unsigned global_accelerated_context_count_;
+  mutable intptr_t gpu_memory_usage_;
+  mutable intptr_t externally_allocated_memory_;
+
+  mutable bool gpu_readback_invoked_in_current_frame_;
+  int gpu_readback_successive_frames_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
index e7282f81..3e1fbc0 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
@@ -168,7 +168,7 @@
     NOTREACHED();
     return nullptr;
   }
-  virtual int ExternallyAllocatedBytesPerPixel() {
+  virtual int ExternallyAllocatedBufferCountPerPixel() {
     NOTREACHED();
     return 0;
   }
diff --git a/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.cpp
index dcd8a3f..ca837ec 100644
--- a/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.cpp
@@ -544,7 +544,7 @@
 
   // resetTransform() resolves the non-invertible CTM state.
   ModifiableState().ResetTransform();
-  c->setMatrix(AffineTransformToSkMatrix(BaseTransform()));
+  c->setMatrix(AffineTransformToSkMatrix(AffineTransform()));
 
   if (invertible_ctm)
     path_.Transform(ctm);
@@ -1297,7 +1297,7 @@
     float src_area = src_rect.Width() * src_rect.Height();
     if (src_area >
         CanvasHeuristicParameters::kDrawImageTextureUploadHardSizeLimit) {
-      buffer->DisableAcceleration();
+      this->DisableAcceleration();
     } else if (src_area > CanvasHeuristicParameters::
                               kDrawImageTextureUploadSoftSizeLimit) {
       SkRect bounds = dst_rect;
@@ -1307,7 +1307,7 @@
       if (src_area >
           dst_area * CanvasHeuristicParameters::
                          kDrawImageTextureUploadSoftSizeLimitScaleThreshold) {
-        buffer->DisableAcceleration();
+        this->DisableAcceleration();
       }
     }
   }
@@ -1647,11 +1647,17 @@
   }
 
   WTF::ArrayBufferContents contents;
-  if (!buffer->GetImageData(image_data_rect, contents)) {
+  bool is_gpu_readback_invoked = false;
+  if (!buffer->GetImageData(image_data_rect, contents,
+                            &is_gpu_readback_invoked)) {
     exception_state.ThrowRangeError("Out of memory at ImageData creation");
     return nullptr;
   }
 
+  if (is_gpu_readback_invoked) {
+    DidInvokeGPUReadbackInCurrentFrame();
+  }
+
   NeedsFinalizeFrame();
 
   // Convert pixels to proper storage format if needed
diff --git a/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.h b/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.h
index 26554d29..967335d0 100644
--- a/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.h
+++ b/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.h
@@ -234,8 +234,6 @@
   virtual PaintCanvas* ExistingDrawingCanvas() const = 0;
   virtual void DisableDeferral(DisableDeferralReason) = 0;
 
-  virtual AffineTransform BaseTransform() const = 0;
-
   virtual void DidDraw(const SkIRect& dirty_rect) = 0;
 
   virtual bool StateHasFilter() = 0;
@@ -367,6 +365,9 @@
   // Canvas is device independent
   static const double kCDeviceScaleFactor;
 
+  virtual void DisableAcceleration() {}
+  virtual void DidInvokeGPUReadbackInCurrentFrame() {}
+
  private:
   void RealizeSaves();
 
diff --git a/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2D.cpp
index 430d007..41957f1 100644
--- a/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2D.cpp
@@ -410,10 +410,6 @@
   canvas()->DisableDeferral(reason);
 }
 
-AffineTransform CanvasRenderingContext2D::BaseTransform() const {
-  return canvas()->BaseTransform();
-}
-
 String CanvasRenderingContext2D::font() const {
   if (!GetState().HasRealizedFont())
     return kDefaultFont;
@@ -1070,4 +1066,12 @@
   return 0;
 }
 
+void CanvasRenderingContext2D::DisableAcceleration() {
+  canvas()->DisableAcceleration();
+}
+
+void CanvasRenderingContext2D::DidInvokeGPUReadbackInCurrentFrame() {
+  canvas()->DidInvokeGPUReadbackInCurrentFrame();
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2D.h b/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2D.h
index e27059df..a72cd92 100644
--- a/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2D.h
+++ b/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2D.h
@@ -165,6 +165,8 @@
     return CanvasRenderingContext::WouldTaintOrigin(
         source, execution_context->GetSecurityOrigin());
   }
+  void DisableAcceleration() override;
+  void DidInvokeGPUReadbackInCurrentFrame() override;
 
   int Width() const final;
   int Height() const final;
@@ -178,7 +180,6 @@
   PaintCanvas* ExistingDrawingCanvas() const final;
   void DisableDeferral(DisableDeferralReason) final;
 
-  AffineTransform BaseTransform() const final;
   void DidDraw(const SkIRect& dirty_rect) final;  // overrides
                                                   // BaseRenderingContext2D and
                                                   // CanvasRenderingContext
diff --git a/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2DTest.cpp b/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2DTest.cpp
index 3e7f34cb..85f7afb 100644
--- a/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2DTest.cpp
+++ b/third_party/WebKit/Source/modules/canvas/canvas2d/CanvasRenderingContext2DTest.cpp
@@ -112,13 +112,13 @@
         CanvasElement().RenderingContext());
   }
   intptr_t GetGlobalGPUMemoryUsage() const {
-    return ImageBuffer::GetGlobalGPUMemoryUsage();
+    return HTMLCanvasElement::GetGlobalGPUMemoryUsage();
   }
-  unsigned GetGlobalAcceleratedImageBufferCount() const {
-    return ImageBuffer::GetGlobalAcceleratedImageBufferCount();
+  unsigned GetGlobalAcceleratedContextCount() const {
+    return HTMLCanvasElement::GetGlobalAcceleratedContextCount();
   }
   intptr_t GetCurrentGPUMemoryUsage() const {
-    return CanvasElement().GetImageBuffer()->GetGPUMemoryUsage();
+    return CanvasElement().GetGPUMemoryUsage();
   }
 
   void CreateContext(OpacityMode,
@@ -213,7 +213,7 @@
       IntSize(800, 600), &page_clients, nullptr, override_settings_function_);
   document_ = &dummy_page_holder_->GetDocument();
   document_->documentElement()->SetInnerHTMLFromString(
-      "<body><canvas id='c'></canvas></body>");
+      "<body><canvas id='c'></canvas><canvas id='d'></canvas></body>");
   document_->View()->UpdateAllLifecyclePhases();
   canvas_element_ = ToHTMLCanvasElement(document_->getElementById("c"));
 
@@ -253,8 +253,10 @@
 std::unique_ptr<Canvas2DLayerBridge> CanvasRenderingContext2DTest::MakeBridge(
     const IntSize& size,
     Canvas2DLayerBridge::AccelerationMode acceleration_mode) {
-  return WTF::WrapUnique(
+  std::unique_ptr<Canvas2DLayerBridge> bridge = WTF::WrapUnique(
       new Canvas2DLayerBridge(size, 0, acceleration_mode, CanvasColorParams()));
+  bridge->SetCanvasResourceHost(canvas_element_);
+  return bridge;
 }
 
 //============================================================================
@@ -870,42 +872,46 @@
   // pixel per buffer, and 2 is an estimate of num of gpu buffers required
   EXPECT_EQ(800, GetCurrentGPUMemoryUsage());
   EXPECT_EQ(800, GetGlobalGPUMemoryUsage());
-  EXPECT_EQ(1u, GetGlobalAcceleratedImageBufferCount());
+  EXPECT_EQ(1u, GetGlobalAcceleratedContextCount());
 
   // Switching accelerated mode to non-accelerated mode
   fake_accelerate_surface_ptr->SetIsAccelerated(false);
-  CanvasElement().GetImageBuffer()->UpdateGPUMemoryUsage();
+  CanvasElement().UpdateMemoryUsage();
   EXPECT_EQ(0, GetCurrentGPUMemoryUsage());
   EXPECT_EQ(0, GetGlobalGPUMemoryUsage());
-  EXPECT_EQ(0u, GetGlobalAcceleratedImageBufferCount());
+  EXPECT_EQ(0u, GetGlobalAcceleratedContextCount());
 
   // Switching non-accelerated mode to accelerated mode
   fake_accelerate_surface_ptr->SetIsAccelerated(true);
-  CanvasElement().GetImageBuffer()->UpdateGPUMemoryUsage();
+  CanvasElement().UpdateMemoryUsage();
   EXPECT_EQ(800, GetCurrentGPUMemoryUsage());
   EXPECT_EQ(800, GetGlobalGPUMemoryUsage());
-  EXPECT_EQ(1u, GetGlobalAcceleratedImageBufferCount());
+  EXPECT_EQ(1u, GetGlobalAcceleratedContextCount());
 
   // Creating a different accelerated image buffer
+  HTMLCanvasElement* anotherCanvas =
+      ToHTMLCanvasElement(GetDocument().getElementById("d"));
+  CanvasContextCreationAttributes attributes;
+  anotherCanvas->GetCanvasRenderingContext("2d", attributes);
   auto fake_accelerate_surface2 =
       std::make_unique<FakeAcceleratedImageBufferSurface>(IntSize(10, 5),
                                                           CanvasColorParams());
-  std::unique_ptr<ImageBuffer> image_buffer2 =
-      ImageBuffer::Create(std::move(fake_accelerate_surface2));
+  anotherCanvas->CreateImageBufferUsingSurfaceForTesting(
+      std::move(fake_accelerate_surface2));
   EXPECT_EQ(800, GetCurrentGPUMemoryUsage());
   EXPECT_EQ(1200, GetGlobalGPUMemoryUsage());
-  EXPECT_EQ(2u, GetGlobalAcceleratedImageBufferCount());
+  EXPECT_EQ(2u, GetGlobalAcceleratedContextCount());
 
   // Tear down the first image buffer that resides in current canvas element
   CanvasElement().SetSize(IntSize(20, 20));
   Mock::VerifyAndClearExpectations(fake_accelerate_surface_ptr);
   EXPECT_EQ(400, GetGlobalGPUMemoryUsage());
-  EXPECT_EQ(1u, GetGlobalAcceleratedImageBufferCount());
+  EXPECT_EQ(1u, GetGlobalAcceleratedContextCount());
 
   // Tear down the second image buffer
-  image_buffer2.reset();
+  anotherCanvas->SetSize(IntSize(20, 20));
   EXPECT_EQ(0, GetGlobalGPUMemoryUsage());
-  EXPECT_EQ(0u, GetGlobalAcceleratedImageBufferCount());
+  EXPECT_EQ(0u, GetGlobalAcceleratedContextCount());
 }
 
 TEST_F(CanvasRenderingContext2DTest, CanvasDisposedBeforeContext) {
@@ -945,7 +951,7 @@
   CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(bridge));
 
   EXPECT_TRUE(CanvasElement().GetImageBuffer()->IsAccelerated());
-  EXPECT_EQ(1u, GetGlobalAcceleratedImageBufferCount());
+  EXPECT_EQ(1u, GetGlobalAcceleratedContextCount());
   EXPECT_EQ(720000, GetGlobalGPUMemoryUsage());
 
   DummyExceptionStateForTesting exception_state;
@@ -957,7 +963,7 @@
 
     EXPECT_FALSE(exception_state.HadException());
     EXPECT_TRUE(CanvasElement().GetImageBuffer()->IsAccelerated());
-    EXPECT_EQ(1u, GetGlobalAcceleratedImageBufferCount());
+    EXPECT_EQ(1u, GetGlobalAcceleratedContextCount());
     EXPECT_EQ(720000, GetGlobalGPUMemoryUsage());
   }
 
@@ -967,11 +973,11 @@
   EXPECT_FALSE(exception_state.HadException());
   if (CanvasHeuristicParameters::kGPUReadbackForcesNoAcceleration) {
     EXPECT_FALSE(CanvasElement().GetImageBuffer()->IsAccelerated());
-    EXPECT_EQ(0u, GetGlobalAcceleratedImageBufferCount());
+    EXPECT_EQ(0u, GetGlobalAcceleratedContextCount());
     EXPECT_EQ(0, GetGlobalGPUMemoryUsage());
   } else {
     EXPECT_TRUE(CanvasElement().GetImageBuffer()->IsAccelerated());
-    EXPECT_EQ(1u, GetGlobalAcceleratedImageBufferCount());
+    EXPECT_EQ(1u, GetGlobalAcceleratedContextCount());
     EXPECT_EQ(720000, GetGlobalGPUMemoryUsage());
   }
 }
@@ -1006,7 +1012,7 @@
     CanvasElement().CreateImageBufferUsingSurfaceForTesting(std::move(bridge));
 
     EXPECT_TRUE(CanvasElement().GetImageBuffer()->IsAccelerated());
-    EXPECT_EQ(1u, GetGlobalAcceleratedImageBufferCount());
+    EXPECT_EQ(1u, GetGlobalAcceleratedContextCount());
     // 4 bytes per pixel * 2 buffers = 8
     EXPECT_EQ(8 * dst_size * dst_size, GetGlobalGPUMemoryUsage());
     sk_sp<SkSurface> sk_surface =
@@ -1022,11 +1028,11 @@
 
     if (test_variant == kLargeTextureDisablesAcceleration) {
       EXPECT_FALSE(CanvasElement().GetImageBuffer()->IsAccelerated());
-      EXPECT_EQ(0u, GetGlobalAcceleratedImageBufferCount());
+      EXPECT_EQ(0u, GetGlobalAcceleratedContextCount());
       EXPECT_EQ(0, GetGlobalGPUMemoryUsage());
     } else {
       EXPECT_TRUE(CanvasElement().GetImageBuffer()->IsAccelerated());
-      EXPECT_EQ(1u, GetGlobalAcceleratedImageBufferCount());
+      EXPECT_EQ(1u, GetGlobalAcceleratedContextCount());
       EXPECT_EQ(8 * dst_size * dst_size, GetGlobalGPUMemoryUsage());
     }
   }
@@ -1046,19 +1052,19 @@
   // pixel per buffer, and 2 is an estimate of num of gpu buffers required
   EXPECT_EQ(800, GetCurrentGPUMemoryUsage());
   EXPECT_EQ(800, GetGlobalGPUMemoryUsage());
-  EXPECT_EQ(1u, GetGlobalAcceleratedImageBufferCount());
+  EXPECT_EQ(1u, GetGlobalAcceleratedContextCount());
 
   context->fillRect(10, 10, 100, 100);
   EXPECT_TRUE(CanvasElement().GetImageBuffer()->IsAccelerated());
 
-  CanvasElement().GetImageBuffer()->DisableAcceleration();
+  CanvasElement().DisableAcceleration();
   EXPECT_FALSE(CanvasElement().GetImageBuffer()->IsAccelerated());
 
   context->fillRect(10, 10, 100, 100);
 
   EXPECT_EQ(0, GetCurrentGPUMemoryUsage());
   EXPECT_EQ(0, GetGlobalGPUMemoryUsage());
-  EXPECT_EQ(0u, GetGlobalAcceleratedImageBufferCount());
+  EXPECT_EQ(0u, GetGlobalAcceleratedContextCount());
 }
 
 enum class ColorSpaceConversion : uint8_t {
diff --git a/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
index b3ca9e2..f4207d8 100644
--- a/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
@@ -197,12 +197,6 @@
 void OffscreenCanvasRenderingContext2D::DisableDeferral(DisableDeferralReason) {
 }
 
-AffineTransform OffscreenCanvasRenderingContext2D::BaseTransform() const {
-  if (!HasImageBuffer())
-    return AffineTransform();  // identity
-  return GetImageBuffer()->BaseTransform();
-}
-
 void OffscreenCanvasRenderingContext2D::DidDraw(const SkIRect& dirty_rect) {
   dirty_rect_for_commit_.join(dirty_rect);
 }
diff --git a/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h b/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h
index e979c33c..c00b22d 100644
--- a/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h
+++ b/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h
@@ -97,7 +97,6 @@
   PaintCanvas* ExistingDrawingCanvas() const final;
   void DisableDeferral(DisableDeferralReason) final;
 
-  AffineTransform BaseTransform() const final;
   void DidDraw(const SkIRect& dirty_rect) final;  // overrides
                                                   // BaseRenderingContext2D and
                                                   // CanvasRenderingContext
diff --git a/third_party/WebKit/Source/modules/csspaint/PaintRenderingContext2D.cpp b/third_party/WebKit/Source/modules/csspaint/PaintRenderingContext2D.cpp
index 3b42c2a..0ac5223 100644
--- a/third_party/WebKit/Source/modules/csspaint/PaintRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/csspaint/PaintRenderingContext2D.cpp
@@ -58,11 +58,6 @@
   return image_buffer_->Canvas();
 }
 
-AffineTransform PaintRenderingContext2D::BaseTransform() const {
-  DCHECK(image_buffer_);
-  return image_buffer_->BaseTransform();
-}
-
 void PaintRenderingContext2D::DidDraw(const SkIRect& dirty_rect) {
   DCHECK(image_buffer_);
   return image_buffer_->DidDraw(SkRect::Make(dirty_rect));
diff --git a/third_party/WebKit/Source/modules/csspaint/PaintRenderingContext2D.h b/third_party/WebKit/Source/modules/csspaint/PaintRenderingContext2D.h
index aa1d9e6..513c05d 100644
--- a/third_party/WebKit/Source/modules/csspaint/PaintRenderingContext2D.h
+++ b/third_party/WebKit/Source/modules/csspaint/PaintRenderingContext2D.h
@@ -59,8 +59,6 @@
   PaintCanvas* ExistingDrawingCanvas() const final;
   void DisableDeferral(DisableDeferralReason) final {}
 
-  AffineTransform BaseTransform() const final;
-
   void DidDraw(const SkIRect& dirty_rect) final;
 
   bool StateHasFilter() final;
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index dcd06b0..3d7abab 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -7821,13 +7821,12 @@
   CanvasRenderingContext::TraceWrappers(visitor);
 }
 
-int WebGLRenderingContextBase::ExternallyAllocatedBytesPerPixel() {
+int WebGLRenderingContextBase::ExternallyAllocatedBufferCountPerPixel() {
   if (isContextLost())
     return 0;
 
-  int bytes_per_pixel = 4;
-  int total_bytes_per_pixel =
-      bytes_per_pixel * 2;  // WebGL's front and back color buffers.
+  int buffer_count = 1;
+  buffer_count *= 2;  // WebGL's front and back color buffers.
   int samples = GetDrawingBuffer() ? GetDrawingBuffer()->SampleCount() : 0;
   Nullable<WebGLContextAttributes> attribs;
   getContextAttributes(attribs);
@@ -7838,16 +7837,14 @@
     if (attribs.Get().antialias() && samples > 0 &&
         GetDrawingBuffer()->ExplicitResolveOfMultisampleData()) {
       if (attribs.Get().depth() || attribs.Get().stencil())
-        total_bytes_per_pixel +=
-            samples * bytes_per_pixel;  // depth/stencil multisample buffer
-      total_bytes_per_pixel +=
-          samples * bytes_per_pixel;  // color multisample buffer
+        buffer_count += samples;  // depth/stencil multisample buffer
+      buffer_count += samples;    // color multisample buffer
     } else if (attribs.Get().depth() || attribs.Get().stencil()) {
-      total_bytes_per_pixel += bytes_per_pixel;  // regular depth/stencil buffer
+      buffer_count += 1;  // regular depth/stencil buffer
     }
   }
 
-  return total_bytes_per_pixel;
+  return buffer_count;
 }
 
 DrawingBuffer* WebGLRenderingContextBase::GetDrawingBuffer() const {
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
index 311b108..c991fd5 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
@@ -569,7 +569,7 @@
   virtual void TraceWrappers(const ScriptWrappableVisitor*) const;
 
   // Returns approximate gpu memory allocated per pixel.
-  int ExternallyAllocatedBytesPerPixel() override;
+  int ExternallyAllocatedBufferCountPerPixel() override;
 
   class TextureUnitState {
     DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index fca1215..461ca53 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -863,6 +863,7 @@
     "graphics/CanvasMetrics.h",
     "graphics/CanvasResource.cpp",
     "graphics/CanvasResource.h",
+    "graphics/CanvasResourceHost.h",
     "graphics/CanvasResourceProvider.cpp",
     "graphics/CanvasResourceProvider.h",
     "graphics/Color.cpp",
@@ -928,7 +929,6 @@
     "graphics/ImageAnimationPolicy.h",
     "graphics/ImageBuffer.cpp",
     "graphics/ImageBuffer.h",
-    "graphics/ImageBufferClient.h",
     "graphics/ImageBufferSurface.cpp",
     "graphics/ImageBufferSurface.h",
     "graphics/ImageDecodingStore.cpp",
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
index 296b9ff..519442d 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
@@ -62,8 +62,7 @@
 Canvas2DLayerBridge::Canvas2DLayerBridge(const IntSize& size,
                                          int msaa_sample_count,
                                          AccelerationMode acceleration_mode,
-                                         const CanvasColorParams& color_params,
-                                         bool is_unit_test)
+                                         const CanvasColorParams& color_params)
     : ImageBufferSurface(size, color_params),
       logger_(WTF::WrapUnique(new Logger)),
       weak_ptr_factory_(this),
@@ -77,11 +76,11 @@
       is_deferral_enabled_(true),
       software_rendering_while_hidden_(false),
       acceleration_mode_(acceleration_mode),
-      color_params_(color_params) {
+      color_params_(color_params),
+      resource_host_(nullptr) {
   // Used by browser tests to detect the use of a Canvas2DLayerBridge.
   TRACE_EVENT_INSTANT0("test_gpu", "Canvas2DLayerBridgeCreation",
                        TRACE_EVENT_SCOPE_GLOBAL);
-
   StartRecording();
   Clear();
 }
@@ -101,9 +100,10 @@
   // and clip.
   canvas->save();
 
-  if (image_buffer_) {
-    image_buffer_->ResetCanvas(canvas);
+  if (resource_host_) {
+    resource_host_->RestoreCanvasMatrixClipStack(canvas);
   }
+
   recording_pixel_count_ = 0;
 }
 
@@ -229,8 +229,8 @@
   layer_->ClearTexture();
 
   // shouldBeDirectComposited() may have changed.
-  if (image_buffer_)
-    image_buffer_->SetNeedsCompositingUpdate();
+  if (resource_host_)
+    resource_host_->SetNeedsCompositingUpdate();
   logger_->DidStartHibernating();
 }
 
@@ -317,14 +317,16 @@
                                             &copy_paint);
     hibernation_image_.reset();
 
-    if (image_buffer_) {
-      image_buffer_->UpdateGPUMemoryUsage();
+    if (resource_host_) {
+      resource_host_->UpdateMemoryUsage();
 
-      if (!is_deferral_enabled_)
-        image_buffer_->ResetCanvas(resource_provider_->Canvas());
+      if (!is_deferral_enabled_) {
+        resource_host_->RestoreCanvasMatrixClipStack(
+            resource_provider_->Canvas());
+      }
 
       // shouldBeDirectComposited() may have changed.
-      image_buffer_->SetNeedsCompositingUpdate();
+      resource_host_->SetNeedsCompositingUpdate();
     }
   }
 
@@ -367,15 +369,12 @@
   recorder_.reset();
   // install the current matrix/clip stack onto the immediate canvas
   GetOrCreateResourceProvider();
-  if (image_buffer_ && resource_provider_)
-    image_buffer_->ResetCanvas(resource_provider_->Canvas());
+  if (resource_host_ && resource_provider_)
+    resource_host_->RestoreCanvasMatrixClipStack(resource_provider_->Canvas());
 }
 
 void Canvas2DLayerBridge::SetImageBuffer(ImageBuffer* image_buffer) {
   image_buffer_ = image_buffer;
-  if (image_buffer_ && is_deferral_enabled_) {
-    image_buffer_->ResetCanvas(recorder_->getRecordingCanvas());
-  }
 }
 
 void Canvas2DLayerBridge::BeginDestruction() {
@@ -454,8 +453,9 @@
             old_resource_provider->Snapshot()->PaintImageForCurrentFrame();
         resource_provider_->Canvas()->drawImage(snapshot, 0, 0, &copy_paint);
       }
-      if (image_buffer_ && !is_deferral_enabled_) {
-        image_buffer_->ResetCanvas(resource_provider_->Canvas());
+      if (resource_host_ && !is_deferral_enabled_) {
+        resource_host_->RestoreCanvasMatrixClipStack(
+            resource_provider_->Canvas());
       }
     } else {
       // New resource provider could not be created. Stay with old one.
@@ -504,8 +504,8 @@
   canvas->drawImage(builder.TakePaintImage(), x, y, &copy_paint);
 
   canvas->save();  // intial save
-  if (image_buffer_ && !is_deferral_enabled_) {
-    image_buffer_->ResetCanvas(canvas);
+  if (resource_host_ && !is_deferral_enabled_) {
+    resource_host_->RestoreCanvasMatrixClipStack(canvas);
   }
 
   // We did not make a copy of the pixel data, so it needs to be consumed
@@ -564,8 +564,8 @@
       resource_provider_->IsGpuContextLost()) {
     context_lost_ = true;
     ResetResourceProvider();
-    if (image_buffer_)
-      image_buffer_->NotifySurfaceInvalid();
+    if (resource_host_)
+      resource_host_->NotifySurfaceInvalid();
     CanvasMetrics::CountCanvasContextUsage(
         CanvasMetrics::kAccelerated2DCanvasGPUContextLost);
     return false;
@@ -609,8 +609,9 @@
     }
     context_lost_ = false;
   }
-  if (image_buffer_)
-    image_buffer_->UpdateGPUMemoryUsage();
+
+  if (resource_host_)
+    resource_host_->UpdateMemoryUsage();
 
   return resource_provider_.get();
 }
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
index 4125b6a..2996480 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
@@ -33,6 +33,7 @@
 #include "cc/layers/texture_layer_client.h"
 #include "platform/PlatformExport.h"
 #include "platform/geometry/IntSize.h"
+#include "platform/graphics/CanvasResourceHost.h"
 #include "platform/graphics/ImageBufferSurface.h"
 #include "platform/graphics/paint/PaintRecorder.h"
 #include "platform/wtf/Allocator.h"
@@ -79,8 +80,7 @@
   Canvas2DLayerBridge(const IntSize&,
                       int msaa_sample_count,
                       AccelerationMode,
-                      const CanvasColorParams&,
-                      bool is_unit_test = false);
+                      const CanvasColorParams&);
 
   ~Canvas2DLayerBridge() override;
 
@@ -111,6 +111,9 @@
   void DontUseIdleSchedulingForTesting() {
     dont_use_idle_scheduling_for_testing_ = true;
   }
+  void SetCanvasResourceHost(CanvasResourceHost* host) {
+    resource_host_ = host;
+  }
 
   void BeginDestruction();
   void Hibernate();
@@ -193,6 +196,8 @@
   AccelerationMode acceleration_mode_;
   CanvasColorParams color_params_;
   CheckedNumeric<int> recording_pixel_count_;
+
+  CanvasResourceHost* resource_host_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
index 39049e0..d131bf4 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
@@ -36,6 +36,7 @@
 #include "platform/CrossThreadFunctional.h"
 #include "platform/WaitableEvent.h"
 #include "platform/WebTaskRunner.h"
+#include "platform/graphics/CanvasResourceHost.h"
 #include "platform/graphics/CanvasResourceProvider.h"
 #include "platform/graphics/ImageBuffer.h"
 #include "platform/graphics/StaticBitmapImage.h"
@@ -131,8 +132,8 @@
       const IntSize& size,
       Canvas2DLayerBridge::AccelerationMode acceleration_mode) {
     std::unique_ptr<Canvas2DLayerBridge> bridge =
-        WTF::WrapUnique(new Canvas2DLayerBridge(
-            size, 0, acceleration_mode, CanvasColorParams(), IsUnitTest()));
+        WTF::WrapUnique(new Canvas2DLayerBridge(size, 0, acceleration_mode,
+                                                CanvasColorParams()));
     bridge->DontUseIdleSchedulingForTesting();
     return bridge;
   }
@@ -146,7 +147,6 @@
         WTF::Bind(factory, WTF::Unretained(&gl_)));
   }
   void TearDown() override { SharedGpuContext::ResetForTesting(); }
-  bool IsUnitTest() { return true; }
 
  protected:
   MockGLES2InterfaceWithImageSupport gl_;
@@ -154,7 +154,7 @@
   void FullLifecycleTest() {
     Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
         IntSize(300, 150), 0, Canvas2DLayerBridge::kDisableAcceleration,
-        CanvasColorParams(), IsUnitTest())));
+        CanvasColorParams())));
 
     const GrGLTextureInfo* texture_info =
         skia::GrBackendObjectToGrGLTextureInfo(
@@ -172,7 +172,7 @@
     gl_.SetIsContextLost(true);
     Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
         IntSize(300, 150), 0, Canvas2DLayerBridge::kEnableAcceleration,
-        CanvasColorParams(), IsUnitTest())));
+        CanvasColorParams())));
     EXPECT_TRUE(bridge->IsValid());
     EXPECT_FALSE(bridge->IsAccelerated());
   }
@@ -182,7 +182,7 @@
       // No fallback case.
       Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
           IntSize(300, 150), 0, Canvas2DLayerBridge::kEnableAcceleration,
-          CanvasColorParams(), IsUnitTest())));
+          CanvasColorParams())));
       EXPECT_TRUE(bridge->IsValid());
       EXPECT_TRUE(bridge->IsAccelerated());
       scoped_refptr<StaticBitmapImage> snapshot = bridge->NewImageSnapshot(
@@ -198,7 +198,7 @@
                           ->GetGrContext();
       Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
           IntSize(300, 150), 0, Canvas2DLayerBridge::kEnableAcceleration,
-          CanvasColorParams(), IsUnitTest())));
+          CanvasColorParams())));
       EXPECT_TRUE(bridge->IsValid());
       EXPECT_TRUE(bridge->IsAccelerated());  // We don't yet know that
                                              // allocation will fail.
@@ -215,7 +215,7 @@
   void NoDrawOnContextLostTest() {
     Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
         IntSize(300, 150), 0, Canvas2DLayerBridge::kForceAccelerationForTesting,
-        CanvasColorParams(), IsUnitTest())));
+        CanvasColorParams())));
     EXPECT_TRUE(bridge->IsValid());
     PaintFlags flags;
     uint32_t gen_id = bridge->GetOrCreateResourceProvider()->ContentUniqueID();
@@ -237,7 +237,7 @@
   void PrepareMailboxWhenContextIsLost() {
     Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
         IntSize(300, 150), 0, Canvas2DLayerBridge::kForceAccelerationForTesting,
-        CanvasColorParams(), IsUnitTest())));
+        CanvasColorParams())));
 
     EXPECT_TRUE(bridge->IsAccelerated());
     bridge->FinalizeFrame();  // Trigger the creation of a backing store
@@ -254,7 +254,7 @@
   void PrepareMailboxWhenContextIsLostWithFailedRestore() {
     Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
         IntSize(300, 150), 0, Canvas2DLayerBridge::kForceAccelerationForTesting,
-        CanvasColorParams(), IsUnitTest())));
+        CanvasColorParams())));
 
     bridge->GetOrCreateResourceProvider();
     EXPECT_TRUE(bridge->IsValid());
@@ -305,7 +305,7 @@
       Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
           IntSize(300, 150), 0,
           Canvas2DLayerBridge::kForceAccelerationForTesting,
-          CanvasColorParams(), IsUnitTest())));
+          CanvasColorParams())));
       bridge->FinalizeFrame();
       viz::TransferableResource resource;
       std::unique_ptr<viz::SingleReleaseCallback> release_callback;
@@ -325,7 +325,7 @@
         Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
             IntSize(300, 150), 0,
             Canvas2DLayerBridge::kForceAccelerationForTesting,
-            CanvasColorParams(), IsUnitTest())));
+            CanvasColorParams())));
         bridge->FinalizeFrame();
         bridge->PrepareTransferableResource(&resource, &release_callback);
         // |bridge| goes out of scope and would normally be destroyed, but
@@ -345,7 +345,7 @@
     {
       Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
           IntSize(300, 300), 0, Canvas2DLayerBridge::kEnableAcceleration,
-          CanvasColorParams(), IsUnitTest())));
+          CanvasColorParams())));
       PaintFlags flags;
       bridge->Canvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), flags);
       scoped_refptr<StaticBitmapImage> image = bridge->NewImageSnapshot(
@@ -357,7 +357,7 @@
     {
       Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
           IntSize(300, 300), 0, Canvas2DLayerBridge::kEnableAcceleration,
-          CanvasColorParams(), IsUnitTest())));
+          CanvasColorParams())));
       PaintFlags flags;
       bridge->Canvas()->drawRect(SkRect::MakeXYWH(0, 0, 1, 1), flags);
       scoped_refptr<StaticBitmapImage> image = bridge->NewImageSnapshot(
@@ -424,6 +424,14 @@
   virtual ~MockImageBuffer() {}
 };
 
+class MockCanvasResourceHost : public CanvasResourceHost {
+ public:
+  void NotifySurfaceInvalid() {}
+  void SetNeedsCompositingUpdate() {}
+  void UpdateMemoryUsage() {}
+  MOCK_CONST_METHOD1(RestoreCanvasMatrixClipStack, void(PaintCanvas*));
+};
+
 void DrawSomething(Canvas2DLayerBridgePtr& bridge) {
   bridge->DidDraw(FloatRect(0, 0, 1, 1));
   bridge->FinalizeFrame();
@@ -440,7 +448,7 @@
   ScopedTestingPlatformSupport<FakePlatformSupport> platform;
   Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
       IntSize(300, 300), 0, Canvas2DLayerBridge::kEnableAcceleration,
-      CanvasColorParams(), IsUnitTest())));
+      CanvasColorParams())));
   bridge->DontUseIdleSchedulingForTesting();
   DrawSomething(bridge);
 
@@ -485,7 +493,7 @@
   ScopedTestingPlatformSupport<FakePlatformSupport> platform;
   Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
       IntSize(300, 300), 0, Canvas2DLayerBridge::kEnableAcceleration,
-      CanvasColorParams(), IsUnitTest())));
+      CanvasColorParams())));
   bridge->DontUseIdleSchedulingForTesting();
   DrawSomething(bridge);
 
@@ -533,15 +541,17 @@
 #endif
 {
   ScopedTestingPlatformSupport<FakePlatformSupport> platform;
+  MockCanvasResourceHost mock_host;
+  EXPECT_CALL(mock_host, RestoreCanvasMatrixClipStack(_)).Times(AnyNumber());
+
   Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
       IntSize(300, 300), 0, Canvas2DLayerBridge::kEnableAcceleration,
-      CanvasColorParams(), IsUnitTest())));
+      CanvasColorParams())));
+
+  bridge->SetCanvasResourceHost(&mock_host);
   bridge->DontUseIdleSchedulingForTesting();
   DrawSomething(bridge);
   bridge->DisableDeferral(kDisableDeferralReasonUnknown);
-  MockImageBuffer mock_image_buffer;
-  EXPECT_CALL(mock_image_buffer, ResetCanvas(_)).Times(AnyNumber());
-  bridge->SetImageBuffer(&mock_image_buffer);
 
   // Register an alternate Logger for tracking hibernation events
   std::unique_ptr<MockLogger> mock_logger = WTF::WrapUnique(new MockLogger);
@@ -556,7 +566,7 @@
   bridge->SetIsHidden(true);
   platform->RunUntilIdle();
   ::testing::Mock::VerifyAndClearExpectations(mock_logger_ptr);
-  ::testing::Mock::VerifyAndClearExpectations(&mock_image_buffer);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_host);
   EXPECT_FALSE(bridge->IsAccelerated());
   EXPECT_TRUE(bridge->IsHibernating());
   EXPECT_TRUE(bridge->IsValid());
@@ -565,11 +575,11 @@
   EXPECT_CALL(
       *mock_logger_ptr,
       ReportHibernationEvent(Canvas2DLayerBridge::kHibernationEndedNormally));
-  EXPECT_CALL(mock_image_buffer, ResetCanvas(_))
+  EXPECT_CALL(mock_host, RestoreCanvasMatrixClipStack(_))
       .Times(AtLeast(1));  // Because deferred rendering is disabled
   bridge->SetIsHidden(false);
   ::testing::Mock::VerifyAndClearExpectations(mock_logger_ptr);
-  ::testing::Mock::VerifyAndClearExpectations(&mock_image_buffer);
+  ::testing::Mock::VerifyAndClearExpectations(&mock_host);
   EXPECT_TRUE(bridge->IsAccelerated());
   EXPECT_FALSE(bridge->IsHibernating());
   EXPECT_TRUE(bridge->IsValid());
@@ -584,7 +594,7 @@
   ScopedTestingPlatformSupport<FakePlatformSupport> platform;
   Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
       IntSize(300, 300), 0, Canvas2DLayerBridge::kEnableAcceleration,
-      CanvasColorParams(), IsUnitTest())));
+      CanvasColorParams())));
   bridge->DontUseIdleSchedulingForTesting();
   DrawSomething(bridge);
 
@@ -637,7 +647,7 @@
   ScopedTestingPlatformSupport<FakePlatformSupport> platform;
   Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
       IntSize(300, 300), 0, Canvas2DLayerBridge::kEnableAcceleration,
-      CanvasColorParams(), IsUnitTest())));
+      CanvasColorParams())));
   bridge->DontUseIdleSchedulingForTesting();
   DrawSomething(bridge);
   MockImageBuffer mock_image_buffer;
@@ -697,7 +707,7 @@
   ScopedTestingPlatformSupport<FakePlatformSupport> platform;
   Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
       IntSize(300, 300), 0, Canvas2DLayerBridge::kEnableAcceleration,
-      CanvasColorParams(), IsUnitTest())));
+      CanvasColorParams())));
   bridge->DontUseIdleSchedulingForTesting();
   DrawSomething(bridge);
 
@@ -760,7 +770,7 @@
   ScopedTestingPlatformSupport<FakePlatformSupport> platform;
   Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
       IntSize(300, 300), 0, Canvas2DLayerBridge::kEnableAcceleration,
-      CanvasColorParams(), IsUnitTest())));
+      CanvasColorParams())));
   bridge->DontUseIdleSchedulingForTesting();
   DrawSomething(bridge);
 
@@ -798,7 +808,7 @@
   ScopedTestingPlatformSupport<FakePlatformSupport> platform;
   Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
       IntSize(300, 300), 0, Canvas2DLayerBridge::kEnableAcceleration,
-      CanvasColorParams(), IsUnitTest())));
+      CanvasColorParams())));
   bridge->DontUseIdleSchedulingForTesting();
   DrawSomething(bridge);
 
@@ -847,7 +857,7 @@
   ScopedTestingPlatformSupport<FakePlatformSupport> platform;
   Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
       IntSize(300, 300), 0, Canvas2DLayerBridge::kEnableAcceleration,
-      CanvasColorParams(), IsUnitTest())));
+      CanvasColorParams())));
   bridge->DontUseIdleSchedulingForTesting();
   DrawSomething(bridge);
 
@@ -880,7 +890,7 @@
   ScopedTestingPlatformSupport<FakePlatformSupport> platform;
   Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
       IntSize(300, 300), 0, Canvas2DLayerBridge::kEnableAcceleration,
-      CanvasColorParams(), IsUnitTest())));
+      CanvasColorParams())));
   bridge->DontUseIdleSchedulingForTesting();
   DrawSomething(bridge);
 
@@ -915,7 +925,7 @@
   ScopedTestingPlatformSupport<FakePlatformSupport> platform;
   Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
       IntSize(300, 300), 0, Canvas2DLayerBridge::kEnableAcceleration,
-      CanvasColorParams(), IsUnitTest())));
+      CanvasColorParams())));
   bridge->DontUseIdleSchedulingForTesting();
   DrawSomething(bridge);
 
@@ -951,7 +961,7 @@
   ScopedTestingPlatformSupport<FakePlatformSupport> platform;
   Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
       IntSize(300, 300), 0, Canvas2DLayerBridge::kEnableAcceleration,
-      CanvasColorParams(), IsUnitTest())));
+      CanvasColorParams())));
   bridge->DontUseIdleSchedulingForTesting();
   DrawSomething(bridge);
 
@@ -986,7 +996,7 @@
   ScopedTestingPlatformSupport<FakePlatformSupport> platform;
   Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
       IntSize(300, 300), 0, Canvas2DLayerBridge::kEnableAcceleration,
-      CanvasColorParams(), IsUnitTest())));
+      CanvasColorParams())));
   bridge->DontUseIdleSchedulingForTesting();
   DrawSomething(bridge);
 
@@ -1029,7 +1039,7 @@
   ScopedTestingPlatformSupport<FakePlatformSupport> platform;
   Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
       IntSize(300, 300), 0, Canvas2DLayerBridge::kEnableAcceleration,
-      CanvasColorParams(), IsUnitTest())));
+      CanvasColorParams())));
   DrawSomething(bridge);
 
   // Register an alternate Logger for tracking hibernation events
@@ -1086,7 +1096,7 @@
 
   Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
       IntSize(300, 150), 0, Canvas2DLayerBridge::kForceAccelerationForTesting,
-      CanvasColorParams(), IsUnitTest())));
+      CanvasColorParams())));
 
   ::testing::Mock::VerifyAndClearExpectations(&gl_);
 
@@ -1152,7 +1162,7 @@
 
   Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
       IntSize(300, 150), 0, Canvas2DLayerBridge::kForceAccelerationForTesting,
-      CanvasColorParams(), IsUnitTest())));
+      CanvasColorParams())));
 
   ::testing::Mock::VerifyAndClearExpectations(&gl_);
 
@@ -1213,7 +1223,7 @@
 
   Canvas2DLayerBridgePtr bridge(WTF::WrapUnique(new Canvas2DLayerBridge(
       IntSize(300, 150), 0, Canvas2DLayerBridge::kForceAccelerationForTesting,
-      CanvasColorParams(), IsUnitTest())));
+      CanvasColorParams())));
 
   ::testing::Mock::VerifyAndClearExpectations(&gl_);
 
diff --git a/third_party/WebKit/Source/platform/graphics/CanvasResourceHost.h b/third_party/WebKit/Source/platform/graphics/CanvasResourceHost.h
new file mode 100644
index 0000000..911e45dd5
--- /dev/null
+++ b/third_party/WebKit/Source/platform/graphics/CanvasResourceHost.h
@@ -0,0 +1,24 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CanvasResourceHost_h
+#define CanvasResourceHost_h
+
+#include "platform/PlatformExport.h"
+#include "platform/graphics/paint/PaintCanvas.h"
+
+namespace blink {
+
+class PLATFORM_EXPORT CanvasResourceHost {
+ public:
+  virtual ~CanvasResourceHost() {}
+  virtual void NotifySurfaceInvalid() = 0;
+  virtual void SetNeedsCompositingUpdate() = 0;
+  virtual void RestoreCanvasMatrixClipStack(PaintCanvas*) const = 0;
+  virtual void UpdateMemoryUsage() = 0;
+};
+
+}  // namespace blink
+
+#endif
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
index c4d26cc..6f041c6 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
@@ -39,7 +39,6 @@
 #include "platform/geometry/IntRect.h"
 #include "platform/graphics/CanvasHeuristicParameters.h"
 #include "platform/graphics/GraphicsContext.h"
-#include "platform/graphics/ImageBufferClient.h"
 #include "platform/graphics/RecordingImageBufferSurface.h"
 #include "platform/graphics/StaticBitmapImage.h"
 #include "platform/graphics/UnacceleratedImageBufferSurface.h"
@@ -51,7 +50,6 @@
 #include "platform/image-encoders/ImageEncoder.h"
 #include "platform/network/mime/MIMETypeRegistry.h"
 #include "platform/runtime_enabled_features.h"
-#include "platform/wtf/CheckedNumeric.h"
 #include "platform/wtf/MathExtras.h"
 #include "platform/wtf/PtrUtil.h"
 #include "platform/wtf/Vector.h"
@@ -92,24 +90,11 @@
 ImageBuffer::ImageBuffer(std::unique_ptr<ImageBufferSurface> surface)
     : weak_ptr_factory_(this),
       snapshot_state_(kInitialSnapshotState),
-      surface_(std::move(surface)),
-      client_(nullptr),
-      gpu_readback_invoked_in_current_frame_(false),
-      gpu_readback_successive_frames_(0),
-      gpu_memory_usage_(0) {
+      surface_(std::move(surface)) {
   surface_->SetImageBuffer(this);
-  UpdateGPUMemoryUsage();
 }
 
-intptr_t ImageBuffer::global_gpu_memory_usage_ = 0;
-unsigned ImageBuffer::global_accelerated_image_buffer_count_ = 0;
-
 ImageBuffer::~ImageBuffer() {
-  if (gpu_memory_usage_) {
-    DCHECK_GT(global_accelerated_image_buffer_count_, 0u);
-    global_accelerated_image_buffer_count_--;
-  }
-  ImageBuffer::global_gpu_memory_usage_ -= gpu_memory_usage_;
   surface_->SetImageBuffer(nullptr);
 }
 
@@ -138,22 +123,6 @@
 }
 
 void ImageBuffer::FinalizeFrame() {
-  if (IsAccelerated() &&
-      CanvasHeuristicParameters::kGPUReadbackForcesNoAcceleration &&
-      !RuntimeEnabledFeatures::Canvas2dFixedRenderingModeEnabled()) {
-    if (gpu_readback_invoked_in_current_frame_) {
-      gpu_readback_successive_frames_++;
-      gpu_readback_invoked_in_current_frame_ = false;
-    } else {
-      gpu_readback_successive_frames_ = 0;
-    }
-
-    if (gpu_readback_successive_frames_ >=
-        CanvasHeuristicParameters::kGPUReadbackMinSuccessiveFrames) {
-      DisableAcceleration();
-    }
-  }
-
   surface_->FinalizeFrame();
 }
 
@@ -165,16 +134,6 @@
   return surface_->IsValid() || surface_->Restore();
 }
 
-void ImageBuffer::NotifySurfaceInvalid() {
-  if (client_)
-    client_->NotifySurfaceInvalid();
-}
-
-void ImageBuffer::ResetCanvas(PaintCanvas* canvas) const {
-  if (client_)
-    client_->RestoreCanvasMatrixClipStack(canvas);
-}
-
 scoped_refptr<StaticBitmapImage> ImageBuffer::NewImageSnapshot(
     AccelerationHint hint,
     SnapshotReason reason) const {
@@ -311,7 +270,8 @@
 }
 
 bool ImageBuffer::GetImageData(const IntRect& rect,
-                               WTF::ArrayBufferContents& contents) const {
+                               WTF::ArrayBufferContents& contents,
+                               bool* is_gpu_readback_invoked) const {
   uint8_t bytes_per_pixel = surface_->ColorParams().BytesPerPixel();
   CheckedNumeric<int> data_size = bytes_per_pixel;
   data_size *= rect.Width();
@@ -367,7 +327,9 @@
   DCHECK(read_pixels_successful ||
          !sk_image->bounds().intersect(SkIRect::MakeXYWH(
              rect.X(), rect.Y(), info.width(), info.height())));
-  gpu_readback_invoked_in_current_frame_ = true;
+  if (is_gpu_readback_invoked) {
+    *is_gpu_readback_invoked = true;
+  }
   result.Transfer(contents);
   return true;
 }
@@ -428,47 +390,6 @@
   surface_->WritePixels(info, src_addr, src_bytes_per_row, dest_x, dest_y);
 }
 
-void ImageBuffer::UpdateGPUMemoryUsage() const {
-  if (this->IsAccelerated()) {
-    // If image buffer is accelerated, we should keep track of GPU memory usage.
-    int gpu_buffer_count = 2;
-    CheckedNumeric<intptr_t> checked_gpu_usage =
-        surface_->ColorParams().BytesPerPixel() * gpu_buffer_count;
-    checked_gpu_usage *= this->Size().Width();
-    checked_gpu_usage *= this->Size().Height();
-    intptr_t gpu_memory_usage =
-        checked_gpu_usage.ValueOrDefault(std::numeric_limits<intptr_t>::max());
-
-    if (!gpu_memory_usage_)  // was not accelerated before
-      global_accelerated_image_buffer_count_++;
-
-    global_gpu_memory_usage_ += (gpu_memory_usage - gpu_memory_usage_);
-    gpu_memory_usage_ = gpu_memory_usage;
-  } else if (gpu_memory_usage_) {
-    // In case of switching from accelerated to non-accelerated mode,
-    // the GPU memory usage needs to be updated too.
-    DCHECK_GT(global_accelerated_image_buffer_count_, 0u);
-    global_accelerated_image_buffer_count_--;
-    global_gpu_memory_usage_ -= gpu_memory_usage_;
-    gpu_memory_usage_ = 0;
-
-    if (client_)
-      client_->DidDisableAcceleration();
-  }
-}
-
-void ImageBuffer::DisableAcceleration() {
-  if (!IsAccelerated())
-    return;
-
-  // Create and configure a recording (unaccelerated) surface.
-  std::unique_ptr<ImageBufferSurface> surface =
-      WTF::WrapUnique(new RecordingImageBufferSurface(
-          surface_->Size(), RecordingImageBufferSurface::kAllowFallback,
-          surface_->ColorParams()));
-  SetSurface(std::move(surface));
-}
-
 void ImageBuffer::SetSurface(std::unique_ptr<ImageBufferSurface> surface) {
   scoped_refptr<StaticBitmapImage> image =
       surface_->NewImageSnapshot(kPreferNoAcceleration, kSnapshotReasonPaint);
@@ -491,16 +412,12 @@
   }
   surface->Canvas()->drawImage(image->PaintImageForCurrentFrame(), 0, 0);
   surface->SetImageBuffer(this);
-  if (client_)
-    client_->RestoreCanvasMatrixClipStack(surface->Canvas());
   surface_ = std::move(surface);
-
-  UpdateGPUMemoryUsage();
 }
 
-void ImageBuffer::SetNeedsCompositingUpdate() {
-  if (client_)
-    client_->SetNeedsCompositingUpdate();
+void ImageBuffer::OnCanvasDisposed() {
+  if (surface_)
+    surface_->SetCanvasResourceHost(nullptr);
 }
 
 bool ImageDataBuffer::EncodeImage(const String& mime_type,
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.h b/third_party/WebKit/Source/platform/graphics/ImageBuffer.h
index 216b2fa..4a26bed 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.h
+++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.h
@@ -62,7 +62,6 @@
 
 class DrawingBuffer;
 class GraphicsContext;
-class ImageBufferClient;
 class IntPoint;
 class IntRect;
 
@@ -80,8 +79,6 @@
 
   virtual ~ImageBuffer();
 
-  void SetClient(ImageBufferClient* client) { client_ = client; }
-
   static bool CanCreateImageBuffer(const IntSize&);
   const IntSize& Size() const { return surface_->Size(); }
   bool IsAccelerated() const { return surface_->IsAccelerated(); }
@@ -103,10 +100,6 @@
   }
   void SetIsHidden(bool hidden) { surface_->SetIsHidden(hidden); }
 
-  // Called by subclasses of ImageBufferSurface to install a new canvas object.
-  // Virtual for mocking
-  virtual void ResetCanvas(PaintCanvas*) const;
-
   PaintCanvas* Canvas() const;
   void DisableDeferral(DisableDeferralReason) const;
 
@@ -116,14 +109,15 @@
 
   void WillOverwriteCanvas() { surface_->WillOverwriteCanvas(); }
 
-  bool GetImageData(const IntRect&, WTF::ArrayBufferContents&) const;
+  bool GetImageData(const IntRect&,
+                    WTF::ArrayBufferContents&,
+                    bool* is_gpu_readback_invoked = nullptr) const;
 
   void PutByteArray(const unsigned char* source,
                     const IntSize& source_size,
                     const IntRect& source_rect,
                     const IntPoint& dest_point);
 
-  AffineTransform BaseTransform() const { return AffineTransform(); }
   WebLayer* PlatformLayer() const;
 
   // Destroys the TEXTURE_2D binding for the active texture unit of the passed
@@ -140,8 +134,6 @@
   bool CopyRenderingResultsFromDrawingBuffer(DrawingBuffer*,
                                              SourceDrawingBuffer);
 
-  void NotifySurfaceInvalid();
-
   scoped_refptr<StaticBitmapImage> NewImageSnapshot(
       AccelerationHint = kPreferNoAcceleration,
       SnapshotReason = kSnapshotReasonUnknown) const;
@@ -150,17 +142,11 @@
 
   void Draw(GraphicsContext&, const FloatRect&, const FloatRect*, SkBlendMode);
 
-  void UpdateGPUMemoryUsage() const;
-  static intptr_t GetGlobalGPUMemoryUsage() { return global_gpu_memory_usage_; }
-  static unsigned GetGlobalAcceleratedImageBufferCount() {
-    return global_accelerated_image_buffer_count_;
-  }
-  intptr_t GetGPUMemoryUsage() { return gpu_memory_usage_; }
-
-  void DisableAcceleration();
   void SetSurface(std::unique_ptr<ImageBufferSurface>);
 
-  void SetNeedsCompositingUpdate();
+  // TODO(xlai): This function is an intermediate step making canvas element
+  // have reference to Canvas2DLayerBridge. See crbug.com/776806.
+  void OnCanvasDisposed();
 
   WeakPtrFactory<ImageBuffer> weak_ptr_factory_;
 
@@ -175,14 +161,6 @@
   };
   mutable SnapshotState snapshot_state_;
   std::unique_ptr<ImageBufferSurface> surface_;
-  ImageBufferClient* client_;
-
-  mutable bool gpu_readback_invoked_in_current_frame_;
-  int gpu_readback_successive_frames_;
-
-  mutable intptr_t gpu_memory_usage_;
-  static intptr_t global_gpu_memory_usage_;
-  static unsigned global_accelerated_image_buffer_count_;
 };
 
 struct ImageDataBuffer {
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBufferClient.h b/third_party/WebKit/Source/platform/graphics/ImageBufferClient.h
deleted file mode 100644
index 55b567b..0000000
--- a/third_party/WebKit/Source/platform/graphics/ImageBufferClient.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2014, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ImageBufferClient_h
-#define ImageBufferClient_h
-
-#include "platform/PlatformExport.h"
-#include "platform/graphics/paint/PaintCanvas.h"
-
-namespace blink {
-
-class PLATFORM_EXPORT ImageBufferClient {
- public:
-  virtual ~ImageBufferClient() {}
-  virtual void NotifySurfaceInvalid() = 0;
-  virtual void DidDisableAcceleration() = 0;
-  virtual void RestoreCanvasMatrixClipStack(PaintCanvas*) const = 0;
-  virtual void SetNeedsCompositingUpdate() = 0;
-};
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h b/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h
index a33328b..ac81313 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h
+++ b/third_party/WebKit/Source/platform/graphics/ImageBufferSurface.h
@@ -48,6 +48,7 @@
 
 namespace blink {
 
+class CanvasResourceHost;
 class FloatRect;
 class GraphicsContext;
 class ImageBuffer;
@@ -89,6 +90,7 @@
                            size_t row_bytes,
                            int x,
                            int y) = 0;
+  virtual void SetCanvasResourceHost(CanvasResourceHost*) {}
 
   // May return nullptr if the surface is GPU-backed and the GPU context was
   // lost.
diff --git a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp
index 955c1005..53fdbc2 100644
--- a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp
+++ b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.cpp
@@ -32,7 +32,8 @@
       frame_was_cleared_(true),
       did_record_draw_commands_in_current_frame_(false),
       current_frame_has_expensive_op_(false),
-      previous_frame_has_expensive_op_(false) {
+      previous_frame_has_expensive_op_(false),
+      resource_host_(nullptr) {
   InitializeCurrentFrame();
 }
 
@@ -46,8 +47,8 @@
   // and clip.
   canvas->save();
 
-  if (image_buffer_) {
-    image_buffer_->ResetCanvas(canvas);
+  if (resource_host_) {
+    resource_host_->RestoreCanvasMatrixClipStack(canvas);
   }
   did_record_draw_commands_in_current_frame_ = false;
   current_frame_has_expensive_op_ = false;
@@ -56,13 +57,6 @@
 
 void RecordingImageBufferSurface::SetImageBuffer(ImageBuffer* image_buffer) {
   image_buffer_ = image_buffer;
-  if (current_frame_ && image_buffer_) {
-    image_buffer_->ResetCanvas(current_frame_->getRecordingCanvas());
-  }
-  if (fallback_surface_) {
-    DCHECK(fallback_surface_->IsValid());
-    fallback_surface_->SetImageBuffer(image_buffer);
-  }
 }
 
 bool RecordingImageBufferSurface::WritePixels(const SkImageInfo& orig_info,
@@ -102,8 +96,6 @@
   if (!fallback_surface_->IsValid())
     return;
 
-  fallback_surface_->SetImageBuffer(image_buffer_);
-
   if (previous_frame_) {
     fallback_surface_->Canvas()->drawPicture(previous_frame_);
     previous_frame_.reset();
@@ -116,8 +108,8 @@
     current_frame_.reset();
   }
 
-  if (image_buffer_) {
-    image_buffer_->ResetCanvas(fallback_surface_->Canvas());
+  if (resource_host_) {
+    resource_host_->RestoreCanvasMatrixClipStack(fallback_surface_->Canvas());
   }
 
   CanvasMetrics::CountCanvasContextUsage(
@@ -263,13 +255,6 @@
     FallBackToRasterCanvas(fallback_reason);
 }
 
-void RecordingImageBufferSurface::DoPaintInvalidation(
-    const FloatRect& dirty_rect) {
-  if (fallback_surface_) {
-    fallback_surface_->DoPaintInvalidation(dirty_rect);
-  }
-}
-
 void RecordingImageBufferSurface::WillOverwriteCanvas() {
   frame_was_cleared_ = true;
   previous_frame_.reset();
diff --git a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.h b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.h
index 52efa48..a22738a 100644
--- a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.h
+++ b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurface.h
@@ -6,6 +6,7 @@
 #define RecordingImageBufferSurface_h
 
 #include <memory>
+#include "platform/graphics/CanvasResourceHost.h"
 #include "platform/graphics/GraphicsContext.h"
 #include "platform/graphics/ImageBufferSurface.h"
 #include "platform/wtf/Allocator.h"
@@ -38,6 +39,9 @@
   PaintCanvas* Canvas() override;
   void DisableDeferral(DisableDeferralReason) override;
   sk_sp<PaintRecord> GetRecord() override;
+  void SetCanvasResourceHost(CanvasResourceHost* host) {
+    resource_host_ = host;
+  }
 
   void DidDraw(const FloatRect&) override;
   bool IsValid() const override { return true; }
@@ -49,7 +53,6 @@
                    int y) override;
   void WillOverwriteCanvas() override;
   void FinalizeFrame() override;
-  void DoPaintInvalidation(const FloatRect&) override;
   void SetImageBuffer(ImageBuffer*) override;
   scoped_refptr<StaticBitmapImage> NewImageSnapshot(AccelerationHint,
                                                     SnapshotReason) override;
@@ -120,6 +123,8 @@
   bool did_record_draw_commands_in_current_frame_;
   bool current_frame_has_expensive_op_;
   bool previous_frame_has_expensive_op_;
+
+  CanvasResourceHost* resource_host_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp
index 3b7e441..dc90243 100644
--- a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp
@@ -9,7 +9,6 @@
 #include "platform/WebTaskRunner.h"
 #include "platform/graphics/GraphicsContext.h"
 #include "platform/graphics/ImageBuffer.h"
-#include "platform/graphics/ImageBufferClient.h"
 #include "platform/graphics/UnacceleratedImageBufferSurface.h"
 #include "platform/graphics/paint/PaintCanvas.h"
 #include "platform/graphics/paint/PaintRecord.h"
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/SharedGpuContextTest.cpp b/third_party/WebKit/Source/platform/graphics/gpu/SharedGpuContextTest.cpp
index 88c39a7..4706492 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/SharedGpuContextTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/gpu/SharedGpuContextTest.cpp
@@ -36,8 +36,6 @@
 
   void TearDown() override { SharedGpuContext::ResetForTesting(); }
 
-  bool IsUnitTest() { return true; }
-
   GLES2InterfaceType gl_;
 };
 
@@ -124,10 +122,10 @@
   EXPECT_FALSE(SharedGpuContext::IsValidWithoutRestoring());
   IntSize size(10, 10);
   CanvasColorParams color_params;
-  std::unique_ptr<Canvas2DLayerBridge> bridge = WTF::WrapUnique(
-      new Canvas2DLayerBridge(size, 0, /*msaa sample count*/
-                              Canvas2DLayerBridge::kEnableAcceleration,
-                              color_params, IsUnitTest()));
+  std::unique_ptr<Canvas2DLayerBridge> bridge =
+      WTF::WrapUnique(new Canvas2DLayerBridge(
+          size, 0, /*msaa sample count*/
+          Canvas2DLayerBridge::kEnableAcceleration, color_params));
   EXPECT_TRUE(bridge->IsAccelerated());
   EXPECT_TRUE(SharedGpuContext::IsValidWithoutRestoring());
   bridge->BeginDestruction();