[go: nahoru, domu]

Add framework for (de)serialization of images in SkPicture

This CL adds Plumbing for picture serialization and deserialization
from //blimp to DrawingDisplayItem.

BUG=577262
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel

Review URL: https://codereview.chromium.org/1675763002

Cr-Commit-Position: refs/heads/master@{#375053}
diff --git a/blimp/client/feature/compositor/blimp_compositor.cc b/blimp/client/feature/compositor/blimp_compositor.cc
index 1205745..e420d570 100644
--- a/blimp/client/feature/compositor/blimp_compositor.cc
+++ b/blimp/client/feature/compositor/blimp_compositor.cc
@@ -17,6 +17,7 @@
 #include "blimp/client/feature/compositor/blimp_layer_tree_settings.h"
 #include "blimp/client/feature/compositor/blimp_output_surface.h"
 #include "blimp/client/feature/render_widget_feature.h"
+#include "blimp/common/compositor/blimp_image_serialization_processor.h"
 #include "blimp/common/compositor/blimp_task_graph_runner.h"
 #include "cc/layers/layer.h"
 #include "cc/layers/layer_settings.h"
@@ -44,7 +45,10 @@
       host_should_be_visible_(false),
       output_surface_request_pending_(false),
       remote_proto_channel_receiver_(nullptr),
-      render_widget_feature_(render_widget_feature) {
+      render_widget_feature_(render_widget_feature),
+      image_serialization_processor_(
+          make_scoped_ptr(new BlimpImageSerializationProcessor(
+              BlimpImageSerializationProcessor::Mode::DESERIALIZATION))) {
   DCHECK(render_widget_feature_);
   render_widget_feature_->SetDelegate(kDummyTabId, this);
 }
@@ -244,6 +248,7 @@
   params.gpu_memory_buffer_manager = &gpu_memory_buffer_manager_;
   params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
   params.settings = settings_.get();
+  params.image_serialization_processor = image_serialization_processor_.get();
 
   // TODO(khushalsagar): Add the GpuMemoryBufferManager to params
 
diff --git a/blimp/client/feature/compositor/blimp_compositor.h b/blimp/client/feature/compositor/blimp_compositor.h
index 6879da0..3f14994 100644
--- a/blimp/client/feature/compositor/blimp_compositor.h
+++ b/blimp/client/feature/compositor/blimp_compositor.h
@@ -36,6 +36,7 @@
 
 namespace blimp {
 
+class BlimpImageSerializationProcessor;
 class BlimpMessage;
 
 namespace client {
@@ -187,6 +188,9 @@
   // widget.
   scoped_ptr<BlimpInputManager> input_manager_;
 
+  // Provides the functionality to deserialize images in SkPicture.
+  scoped_ptr<BlimpImageSerializationProcessor> image_serialization_processor_;
+
   DISALLOW_COPY_AND_ASSIGN(BlimpCompositor);
 };
 
diff --git a/blimp/common/BUILD.gn b/blimp/common/BUILD.gn
index 5b7ba5ab..1835b40 100644
--- a/blimp/common/BUILD.gn
+++ b/blimp/common/BUILD.gn
@@ -7,6 +7,8 @@
 component("blimp_common") {
   sources = [
     "blimp_common_export.h",
+    "compositor/blimp_image_serialization_processor.cc",
+    "compositor/blimp_image_serialization_processor.h",
     "compositor/blimp_task_graph_runner.cc",
     "compositor/blimp_task_graph_runner.h",
     "create_blimp_message.cc",
diff --git a/blimp/common/compositor/blimp_image_serialization_processor.cc b/blimp/common/compositor/blimp_image_serialization_processor.cc
new file mode 100644
index 0000000..36ea6af
--- /dev/null
+++ b/blimp/common/compositor/blimp_image_serialization_processor.cc
@@ -0,0 +1,50 @@
+// Copyright 2016 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.
+
+#include "blimp/common/compositor/blimp_image_serialization_processor.h"
+
+#include <stddef.h>
+#include <vector>
+
+#include "base/logging.h"
+#include "third_party/skia/include/core/SkPicture.h"
+#include "third_party/skia/include/core/SkPixelSerializer.h"
+
+namespace {
+bool NoopDecoder(const void* input, size_t input_size, SkBitmap* bitmap) {
+  // TODO(nyquist): Add an image decoder.
+  return false;
+}
+
+}  // namespace
+
+namespace blimp {
+
+BlimpImageSerializationProcessor::BlimpImageSerializationProcessor(Mode mode) {
+  switch (mode) {
+    case Mode::SERIALIZATION:
+      pixel_serializer_ = nullptr;
+      pixel_deserializer_ = nullptr;
+      break;
+    case Mode::DESERIALIZATION:
+      pixel_serializer_ = nullptr;
+      pixel_deserializer_ = &NoopDecoder;
+      break;
+    default:
+      NOTREACHED() << "Unknown serialization mode";
+  }
+}
+
+BlimpImageSerializationProcessor::~BlimpImageSerializationProcessor() {}
+
+SkPixelSerializer* BlimpImageSerializationProcessor::GetPixelSerializer() {
+  return pixel_serializer_.get();
+}
+
+SkPicture::InstallPixelRefProc
+BlimpImageSerializationProcessor::GetPixelDeserializer() {
+  return pixel_deserializer_;
+}
+
+}  // namespace blimp
diff --git a/blimp/common/compositor/blimp_image_serialization_processor.h b/blimp/common/compositor/blimp_image_serialization_processor.h
new file mode 100644
index 0000000..040f2455
--- /dev/null
+++ b/blimp/common/compositor/blimp_image_serialization_processor.h
@@ -0,0 +1,42 @@
+// Copyright 2016 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 BLIMP_COMMON_COMPOSITOR_BLIMP_IMAGE_SERIALIZATION_PROCESSOR_H_
+#define BLIMP_COMMON_COMPOSITOR_BLIMP_IMAGE_SERIALIZATION_PROCESSOR_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "blimp/common/blimp_common_export.h"
+#include "cc/proto/image_serialization_processor.h"
+#include "third_party/skia/include/core/SkPicture.h"
+
+class SkPixelSerializer;
+
+namespace blimp {
+
+// BlimpImageSerializationProcessor provides functionality to serialize and
+// deserialize Skia images.
+class BLIMP_COMMON_EXPORT BlimpImageSerializationProcessor
+    : public cc::ImageSerializationProcessor {
+ public:
+  // Denotes whether the BlimpImageSerializationProcessor should act as a
+  // serializer (engine) or deserializer (client).
+  enum class Mode { SERIALIZATION, DESERIALIZATION };
+  explicit BlimpImageSerializationProcessor(Mode mode);
+  ~BlimpImageSerializationProcessor();
+
+  // cc::ImageSerializationProcessor implementation.
+  SkPixelSerializer* GetPixelSerializer() override;
+  SkPicture::InstallPixelRefProc GetPixelDeserializer() override;
+
+ private:
+  scoped_ptr<SkPixelSerializer> pixel_serializer_;
+  SkPicture::InstallPixelRefProc pixel_deserializer_;
+
+  DISALLOW_COPY_AND_ASSIGN(BlimpImageSerializationProcessor);
+};
+
+}  // namespace blimp
+
+#endif  // BLIMP_COMMON_COMPOSITOR_BLIMP_IMAGE_SERIALIZATION_PROCESSOR_H_
diff --git a/blimp/engine/app/blimp_content_main_delegate.cc b/blimp/engine/app/blimp_content_main_delegate.cc
index cd60b9fb..6fe0b41 100644
--- a/blimp/engine/app/blimp_content_main_delegate.cc
+++ b/blimp/engine/app/blimp_content_main_delegate.cc
@@ -8,6 +8,7 @@
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/path_service.h"
+#include "blimp/common/compositor/blimp_image_serialization_processor.h"
 #include "blimp/engine/app/blimp_content_browser_client.h"
 #include "blimp/engine/app/blimp_content_renderer_client.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -63,7 +64,11 @@
 content::ContentRendererClient*
 BlimpContentMainDelegate::CreateContentRendererClient() {
   DCHECK(!renderer_client_);
-  renderer_client_.reset(new BlimpContentRendererClient);
+  scoped_ptr<BlimpImageSerializationProcessor> image_serialization_processor =
+      make_scoped_ptr(new BlimpImageSerializationProcessor(
+          BlimpImageSerializationProcessor::Mode::SERIALIZATION));
+  renderer_client_.reset(
+      new BlimpContentRendererClient(std::move(image_serialization_processor)));
   return renderer_client_.get();
 }
 
diff --git a/blimp/engine/app/blimp_content_renderer_client.cc b/blimp/engine/app/blimp_content_renderer_client.cc
index c9e51ae..43b388d5 100644
--- a/blimp/engine/app/blimp_content_renderer_client.cc
+++ b/blimp/engine/app/blimp_content_renderer_client.cc
@@ -4,13 +4,17 @@
 
 #include "blimp/engine/app/blimp_content_renderer_client.h"
 
+#include "blimp/common/compositor/blimp_image_serialization_processor.h"
 #include "components/web_cache/renderer/web_cache_render_process_observer.h"
 #include "content/public/renderer/render_thread.h"
 
 namespace blimp {
 namespace engine {
 
-BlimpContentRendererClient::BlimpContentRendererClient() {}
+BlimpContentRendererClient::BlimpContentRendererClient(
+    scoped_ptr<BlimpImageSerializationProcessor> image_serialization_processor)
+    : image_serialization_processor_(std::move(image_serialization_processor)) {
+}
 
 BlimpContentRendererClient::~BlimpContentRendererClient() {}
 
@@ -19,5 +23,10 @@
   content::RenderThread::Get()->AddObserver(web_cache_observer_.get());
 }
 
+cc::ImageSerializationProcessor*
+BlimpContentRendererClient::GetImageSerializationProcessor() {
+  return image_serialization_processor_.get();
+}
+
 }  // namespace engine
 }  // namespace blimp
diff --git a/blimp/engine/app/blimp_content_renderer_client.h b/blimp/engine/app/blimp_content_renderer_client.h
index 56e9cc0..8e86966 100644
--- a/blimp/engine/app/blimp_content_renderer_client.h
+++ b/blimp/engine/app/blimp_content_renderer_client.h
@@ -14,20 +14,27 @@
 }
 
 namespace blimp {
+class BlimpImageSerializationProcessor;
+
 namespace engine {
 
 class BlimpContentRendererClient : public content::ContentRendererClient {
  public:
-  BlimpContentRendererClient();
+  BlimpContentRendererClient(scoped_ptr<BlimpImageSerializationProcessor>
+                                 image_serialization_processor);
   ~BlimpContentRendererClient() override;
 
   // content::ContentRendererClient implementation.
   void RenderThreadStarted() override;
+  cc::ImageSerializationProcessor* GetImageSerializationProcessor() override;
 
  private:
   // This observer manages the process-global web cache.
   scoped_ptr<web_cache::WebCacheRenderProcessObserver> web_cache_observer_;
 
+  // Provides the functionality to serialize images in SkPicture.
+  scoped_ptr<BlimpImageSerializationProcessor> image_serialization_processor_;
+
   DISALLOW_COPY_AND_ASSIGN(BlimpContentRendererClient);
 };
 
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 70f28d2..69c41c9 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -319,6 +319,7 @@
     "proto/gfx_conversions.h",
     "proto/gpu_conversions.cc",
     "proto/gpu_conversions.h",
+    "proto/image_serialization_processor.h",
     "proto/skia_conversions.cc",
     "proto/skia_conversions.h",
     "quads/content_draw_quad_base.cc",
@@ -584,6 +585,8 @@
     "test/fake_display_list_recording_source.h",
     "test/fake_external_begin_frame_source.cc",
     "test/fake_external_begin_frame_source.h",
+    "test/fake_image_serialization_processor.cc",
+    "test/fake_image_serialization_processor.h",
     "test/fake_impl_task_runner_provider.h",
     "test/fake_layer_tree_host.cc",
     "test/fake_layer_tree_host.h",
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 8a5e6cef..a3cbc5f 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -381,6 +381,7 @@
         'proto/gfx_conversions.h',
         'proto/gpu_conversions.cc',
         'proto/gpu_conversions.h',
+        'proto/image_serialization_processor.h',
         'proto/skia_conversions.cc',
         'proto/skia_conversions.h',
         'quads/content_draw_quad_base.cc',
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index d9fe4b1..b8f5b1c 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -187,6 +187,8 @@
       'test/fake_display_list_recording_source.h',
       'test/fake_external_begin_frame_source.cc',
       'test/fake_external_begin_frame_source.h',
+      'test/fake_image_serialization_processor.cc',
+      'test/fake_image_serialization_processor.h',
       'test/fake_impl_task_runner_provider.h',
       'test/fake_layer_tree_host.cc',
       'test/fake_layer_tree_host.h',
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc
index f9df22cd..17c920f 100644
--- a/cc/layers/picture_layer.cc
+++ b/cc/layers/picture_layer.cc
@@ -195,7 +195,9 @@
   DropRecordingSourceContentIfInvalid();
 
   proto::PictureLayerProperties* picture = proto->mutable_picture();
-  recording_source_->ToProtobuf(picture->mutable_recording_source());
+  recording_source_->ToProtobuf(
+      picture->mutable_recording_source(),
+      layer_tree_host()->image_serialization_processor());
   RegionToProto(*invalidation_.region(), picture->mutable_invalidation());
   RectToProto(last_updated_visible_layer_rect_,
               picture->mutable_last_updated_visible_layer_rect());
@@ -211,7 +213,9 @@
     const proto::LayerProperties& proto) {
   Layer::FromLayerSpecificPropertiesProto(proto);
   const proto::PictureLayerProperties& picture = proto.picture();
-  recording_source_->FromProtobuf(picture.recording_source());
+  recording_source_->FromProtobuf(
+      picture.recording_source(),
+      layer_tree_host()->image_serialization_processor());
 
   Region new_invalidation = RegionFromProto(picture.invalidation());
   invalidation_.Swap(&new_invalidation);
diff --git a/cc/layers/picture_layer_unittest.cc b/cc/layers/picture_layer_unittest.cc
index 1ce7567..7c35d55 100644
--- a/cc/layers/picture_layer_unittest.cc
+++ b/cc/layers/picture_layer_unittest.cc
@@ -15,6 +15,7 @@
 #include "cc/playback/display_item_list_settings.h"
 #include "cc/proto/layer.pb.h"
 #include "cc/test/fake_display_list_recording_source.h"
+#include "cc/test/fake_image_serialization_processor.h"
 #include "cc/test/fake_layer_tree_host.h"
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/fake_picture_layer.h"
@@ -69,8 +70,14 @@
 
     FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D);
     TestTaskGraphRunner task_graph_runner;
+    LayerTreeSettings settings;
+    scoped_ptr<FakeImageSerializationProcessor>
+        fake_image_serialization_processor =
+            make_scoped_ptr(new FakeImageSerializationProcessor);
     scoped_ptr<FakeLayerTreeHost> host =
-        FakeLayerTreeHost::Create(&host_client, &task_graph_runner);
+        FakeLayerTreeHost::Create(&host_client, &task_graph_runner, settings,
+                                  CompositorMode::SINGLE_THREADED,
+                                  fake_image_serialization_processor.get());
     scoped_refptr<TestSerializationPictureLayer> layer =
         TestSerializationPictureLayer::Create(recording_source_viewport_);
     host->SetRootLayer(layer);
@@ -104,8 +111,14 @@
 TEST(PictureLayerTest, TestSetAllPropsSerializationDeserialization) {
   FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D);
   TestTaskGraphRunner task_graph_runner;
+  LayerTreeSettings settings;
+  scoped_ptr<FakeImageSerializationProcessor>
+      fake_image_serialization_processor =
+          make_scoped_ptr(new FakeImageSerializationProcessor);
   scoped_ptr<FakeLayerTreeHost> host =
-      FakeLayerTreeHost::Create(&host_client, &task_graph_runner);
+      FakeLayerTreeHost::Create(&host_client, &task_graph_runner, settings,
+                                CompositorMode::SINGLE_THREADED,
+                                fake_image_serialization_processor.get());
 
   gfx::Size recording_source_viewport(256, 256);
   scoped_refptr<TestSerializationPictureLayer> layer =
@@ -131,9 +144,16 @@
 TEST(PictureLayerTest, TestSerializationDeserialization) {
   FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D);
   TestTaskGraphRunner task_graph_runner;
+  LayerTreeSettings settings;
+  settings.verify_property_trees = true;
+  settings.use_compositor_animation_timelines = true;
+  scoped_ptr<FakeImageSerializationProcessor>
+      fake_image_serialization_processor =
+          make_scoped_ptr(new FakeImageSerializationProcessor);
   scoped_ptr<FakeLayerTreeHost> host =
-      FakeLayerTreeHost::Create(&host_client, &task_graph_runner);
-
+      FakeLayerTreeHost::Create(&host_client, &task_graph_runner, settings,
+                                CompositorMode::SINGLE_THREADED,
+                                fake_image_serialization_processor.get());
   gfx::Size recording_source_viewport(256, 256);
   scoped_refptr<TestSerializationPictureLayer> layer =
       TestSerializationPictureLayer::Create(recording_source_viewport);
diff --git a/cc/playback/clip_display_item.cc b/cc/playback/clip_display_item.cc
index 4ab8e5d..92166c1 100644
--- a/cc/playback/clip_display_item.cc
+++ b/cc/playback/clip_display_item.cc
@@ -18,6 +18,7 @@
 #include "ui/gfx/skia_util.h"
 
 namespace cc {
+class ImageSerializationProcessor;
 
 ClipDisplayItem::ClipDisplayItem(
     const gfx::Rect& clip_rect,
@@ -46,7 +47,9 @@
 
 ClipDisplayItem::~ClipDisplayItem() {}
 
-void ClipDisplayItem::ToProtobuf(proto::DisplayItem* proto) const {
+void ClipDisplayItem::ToProtobuf(
+    proto::DisplayItem* proto,
+    ImageSerializationProcessor* image_serialization_processor) const {
   proto->set_type(proto::DisplayItem::Type_Clip);
 
   proto::ClipDisplayItem* details = proto->mutable_clip_item();
@@ -117,7 +120,9 @@
 EndClipDisplayItem::~EndClipDisplayItem() {
 }
 
-void EndClipDisplayItem::ToProtobuf(proto::DisplayItem* proto) const {
+void EndClipDisplayItem::ToProtobuf(
+    proto::DisplayItem* proto,
+    ImageSerializationProcessor* image_serialization_processor) const {
   proto->set_type(proto::DisplayItem::Type_EndClip);
 }
 
diff --git a/cc/playback/clip_display_item.h b/cc/playback/clip_display_item.h
index 97e877e4..2715ce3 100644
--- a/cc/playback/clip_display_item.h
+++ b/cc/playback/clip_display_item.h
@@ -18,6 +18,7 @@
 class SkCanvas;
 
 namespace cc {
+class ImageSerializationProcessor;
 
 class CC_EXPORT ClipDisplayItem : public DisplayItem {
  public:
@@ -26,7 +27,9 @@
   explicit ClipDisplayItem(const proto::DisplayItem& proto);
   ~ClipDisplayItem() override;
 
-  void ToProtobuf(proto::DisplayItem* proto) const override;
+  void ToProtobuf(proto::DisplayItem* proto,
+                  ImageSerializationProcessor* image_serialization_processor)
+      const override;
   void Raster(SkCanvas* canvas,
               const gfx::Rect& canvas_target_playback_rect,
               SkPicture::AbortCallback* callback) const override;
@@ -51,7 +54,9 @@
   explicit EndClipDisplayItem(const proto::DisplayItem& proto);
   ~EndClipDisplayItem() override;
 
-  void ToProtobuf(proto::DisplayItem* proto) const override;
+  void ToProtobuf(proto::DisplayItem* proto,
+                  ImageSerializationProcessor* image_serialization_processor)
+      const override;
   void Raster(SkCanvas* canvas,
               const gfx::Rect& canvas_target_playback_rect,
               SkPicture::AbortCallback* callback) const override;
diff --git a/cc/playback/clip_path_display_item.cc b/cc/playback/clip_path_display_item.cc
index 1a39af2..64ad813 100644
--- a/cc/playback/clip_path_display_item.cc
+++ b/cc/playback/clip_path_display_item.cc
@@ -14,6 +14,7 @@
 #include "third_party/skia/include/core/SkCanvas.h"
 
 namespace cc {
+class ImageSerializationProcessor;
 
 ClipPathDisplayItem::ClipPathDisplayItem(const SkPath& clip_path,
                                          SkRegion::Op clip_op,
@@ -49,7 +50,9 @@
   antialias_ = antialias;
 }
 
-void ClipPathDisplayItem::ToProtobuf(proto::DisplayItem* proto) const {
+void ClipPathDisplayItem::ToProtobuf(
+    proto::DisplayItem* proto,
+    ImageSerializationProcessor* image_serialization_processor) const {
   proto->set_type(proto::DisplayItem::Type_ClipPath);
 
   proto::ClipPathDisplayItem* details = proto->mutable_clip_path_item();
@@ -96,7 +99,9 @@
 EndClipPathDisplayItem::~EndClipPathDisplayItem() {
 }
 
-void EndClipPathDisplayItem::ToProtobuf(proto::DisplayItem* proto) const {
+void EndClipPathDisplayItem::ToProtobuf(
+    proto::DisplayItem* proto,
+    ImageSerializationProcessor* image_serialization_processor) const {
   proto->set_type(proto::DisplayItem::Type_EndClipPath);
 }
 
diff --git a/cc/playback/clip_path_display_item.h b/cc/playback/clip_path_display_item.h
index 0ad1effc..f946c147 100644
--- a/cc/playback/clip_path_display_item.h
+++ b/cc/playback/clip_path_display_item.h
@@ -16,6 +16,7 @@
 class SkCanvas;
 
 namespace cc {
+class ImageSerializationProcessor;
 
 class CC_EXPORT ClipPathDisplayItem : public DisplayItem {
  public:
@@ -23,7 +24,9 @@
   explicit ClipPathDisplayItem(const proto::DisplayItem& proto);
   ~ClipPathDisplayItem() override;
 
-  void ToProtobuf(proto::DisplayItem* proto) const override;
+  void ToProtobuf(proto::DisplayItem* proto,
+                  ImageSerializationProcessor* image_serialization_processor)
+      const override;
   void Raster(SkCanvas* canvas,
               const gfx::Rect& canvas_target_playback_rect,
               SkPicture::AbortCallback* callback) const override;
@@ -52,7 +55,9 @@
     return make_scoped_ptr(new EndClipPathDisplayItem());
   }
 
-  void ToProtobuf(proto::DisplayItem* proto) const override;
+  void ToProtobuf(proto::DisplayItem* proto,
+                  ImageSerializationProcessor* image_serialization_processor)
+      const override;
   void Raster(SkCanvas* canvas,
               const gfx::Rect& canvas_target_playback_rect,
               SkPicture::AbortCallback* callback) const override;
diff --git a/cc/playback/compositing_display_item.cc b/cc/playback/compositing_display_item.cc
index 6828fcf3c..964406a0 100644
--- a/cc/playback/compositing_display_item.cc
+++ b/cc/playback/compositing_display_item.cc
@@ -21,6 +21,7 @@
 #include "ui/gfx/skia_util.h"
 
 namespace cc {
+class ImageSerializationProcessor;
 
 CompositingDisplayItem::CompositingDisplayItem(
     uint8_t alpha,
@@ -77,7 +78,9 @@
   lcd_text_requires_opaque_layer_ = lcd_text_requires_opaque_layer;
 }
 
-void CompositingDisplayItem::ToProtobuf(proto::DisplayItem* proto) const {
+void CompositingDisplayItem::ToProtobuf(
+    proto::DisplayItem* proto,
+    ImageSerializationProcessor* image_serialization_processor) const {
   proto->set_type(proto::DisplayItem::Type_Compositing);
 
   proto::CompositingDisplayItem* details = proto->mutable_compositing_item();
@@ -139,7 +142,9 @@
 EndCompositingDisplayItem::~EndCompositingDisplayItem() {
 }
 
-void EndCompositingDisplayItem::ToProtobuf(proto::DisplayItem* proto) const {
+void EndCompositingDisplayItem::ToProtobuf(
+    proto::DisplayItem* proto,
+    ImageSerializationProcessor* image_serialization_processor) const {
   proto->set_type(proto::DisplayItem::Type_EndCompositing);
 }
 
diff --git a/cc/playback/compositing_display_item.h b/cc/playback/compositing_display_item.h
index 4745208..d723ce1 100644
--- a/cc/playback/compositing_display_item.h
+++ b/cc/playback/compositing_display_item.h
@@ -20,6 +20,7 @@
 class SkCanvas;
 
 namespace cc {
+class ImageSerializationProcessor;
 
 class CC_EXPORT CompositingDisplayItem : public DisplayItem {
  public:
@@ -31,7 +32,9 @@
   explicit CompositingDisplayItem(const proto::DisplayItem& proto);
   ~CompositingDisplayItem() override;
 
-  void ToProtobuf(proto::DisplayItem* proto) const override;
+  void ToProtobuf(proto::DisplayItem* proto,
+                  ImageSerializationProcessor* image_serialization_processor)
+      const override;
   void Raster(SkCanvas* canvas,
               const gfx::Rect& canvas_target_playback_rect,
               SkPicture::AbortCallback* callback) const override;
@@ -67,7 +70,9 @@
     return make_scoped_ptr(new EndCompositingDisplayItem());
   }
 
-  void ToProtobuf(proto::DisplayItem* proto) const override;
+  void ToProtobuf(proto::DisplayItem* proto,
+                  ImageSerializationProcessor* image_serialization_processor)
+      const override;
   void Raster(SkCanvas* canvas,
               const gfx::Rect& canvas_target_playback_rect,
               SkPicture::AbortCallback* callback) const override;
diff --git a/cc/playback/display_item.h b/cc/playback/display_item.h
index c4140f33..3f61adb 100644
--- a/cc/playback/display_item.h
+++ b/cc/playback/display_item.h
@@ -16,16 +16,19 @@
 class SkCanvas;
 
 namespace cc {
+class ImageSerializationProcessor;
 
 namespace proto {
 class DisplayItem;
-}
+}  // namespace proto
 
 class CC_EXPORT DisplayItem {
  public:
   virtual ~DisplayItem() {}
 
-  virtual void ToProtobuf(proto::DisplayItem* proto) const = 0;
+  virtual void ToProtobuf(
+      proto::DisplayItem* proto,
+      ImageSerializationProcessor* image_serialization_processor) const = 0;
   virtual void Raster(SkCanvas* canvas,
                       const gfx::Rect& canvas_target_playback_rect,
                       SkPicture::AbortCallback* callback) const = 0;
diff --git a/cc/playback/display_item_list.cc b/cc/playback/display_item_list.cc
index 6f2f52c..be5b9d4 100644
--- a/cc/playback/display_item_list.cc
+++ b/cc/playback/display_item_list.cc
@@ -29,6 +29,7 @@
 #include "ui/gfx/skia_util.h"
 
 namespace cc {
+class ImageSerializationProcessor;
 
 namespace {
 
@@ -56,7 +57,8 @@
 }
 
 scoped_refptr<DisplayItemList> DisplayItemList::CreateFromProto(
-    const proto::DisplayItemList& proto) {
+    const proto::DisplayItemList& proto,
+    ImageSerializationProcessor* image_serialization_processor) {
   gfx::Rect layer_rect = ProtoToRect(proto.layer_rect());
   scoped_refptr<DisplayItemList> list =
       DisplayItemList::Create(ProtoToRect(proto.layer_rect()),
@@ -64,8 +66,8 @@
 
   for (int i = 0; i < proto.items_size(); i++) {
     const proto::DisplayItem& item_proto = proto.items(i);
-    DisplayItemProtoFactory::AllocateAndConstruct(layer_rect, list.get(),
-                                                  item_proto);
+    DisplayItemProtoFactory::AllocateAndConstruct(
+        layer_rect, list.get(), item_proto, image_serialization_processor);
   }
 
   list->Finalize();
@@ -97,7 +99,9 @@
 DisplayItemList::~DisplayItemList() {
 }
 
-void DisplayItemList::ToProtobuf(proto::DisplayItemList* proto) {
+void DisplayItemList::ToProtobuf(
+    proto::DisplayItemList* proto,
+    ImageSerializationProcessor* image_serialization_processor) {
   // The flattened SkPicture approach is going away, and the proto
   // doesn't currently support serializing that flattened picture.
   DCHECK(retain_individual_display_items_);
@@ -107,7 +111,7 @@
 
   DCHECK_EQ(0, proto->items_size());
   for (const auto& item : items_)
-    item.ToProtobuf(proto->add_items());
+    item.ToProtobuf(proto->add_items(), image_serialization_processor);
 }
 
 void DisplayItemList::Raster(SkCanvas* canvas,
diff --git a/cc/playback/display_item_list.h b/cc/playback/display_item_list.h
index bab4c3f..d8b14b50 100644
--- a/cc/playback/display_item_list.h
+++ b/cc/playback/display_item_list.h
@@ -28,6 +28,7 @@
 namespace cc {
 class DisplayItem;
 class DrawingDisplayItem;
+class ImageSerializationProcessor;
 
 namespace proto {
 class DisplayItemList;
@@ -49,12 +50,14 @@
   // TODO(dtrainor): Pass in a list of possible DisplayItems to reuse
   // (crbug.com/548434).
   static scoped_refptr<DisplayItemList> CreateFromProto(
-      const proto::DisplayItemList& proto);
+      const proto::DisplayItemList& proto,
+      ImageSerializationProcessor* image_serialization_processor);
 
   // Creates a Protobuf representing the state of this DisplayItemList.
   // TODO(dtrainor): Don't resend DisplayItems that were already serialized
   // (crbug.com/548434).
-  void ToProtobuf(proto::DisplayItemList* proto);
+  void ToProtobuf(proto::DisplayItemList* proto,
+                  ImageSerializationProcessor* image_serialization_processor);
 
   void Raster(SkCanvas* canvas,
               SkPicture::AbortCallback* callback,
diff --git a/cc/playback/display_item_list_unittest.cc b/cc/playback/display_item_list_unittest.cc
index 60f91243..a6aac41 100644
--- a/cc/playback/display_item_list_unittest.cc
+++ b/cc/playback/display_item_list_unittest.cc
@@ -19,6 +19,7 @@
 #include "cc/playback/float_clip_display_item.h"
 #include "cc/playback/transform_display_item.h"
 #include "cc/proto/display_item.pb.h"
+#include "cc/test/fake_image_serialization_processor.h"
 #include "cc/test/skia_common.h"
 #include "skia/ext/refptr.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -79,11 +80,15 @@
                                           scoped_refptr<DisplayItemList> list) {
   list->Finalize();
 
+  scoped_ptr<FakeImageSerializationProcessor>
+      fake_image_serialization_processor =
+          make_scoped_ptr(new FakeImageSerializationProcessor);
+
   // Serialize and deserialize the DisplayItemList.
   proto::DisplayItemList proto;
-  list->ToProtobuf(&proto);
-  scoped_refptr<DisplayItemList> new_list =
-      DisplayItemList::CreateFromProto(proto);
+  list->ToProtobuf(&proto, fake_image_serialization_processor.get());
+  scoped_refptr<DisplayItemList> new_list = DisplayItemList::CreateFromProto(
+      proto, fake_image_serialization_processor.get());
 
   EXPECT_TRUE(
       AreDisplayListDrawingResultsSame(gfx::Rect(layer_size), list, new_list));
diff --git a/cc/playback/display_item_proto_factory.cc b/cc/playback/display_item_proto_factory.cc
index 88d5066..0dedda38 100644
--- a/cc/playback/display_item_proto_factory.cc
+++ b/cc/playback/display_item_proto_factory.cc
@@ -15,12 +15,14 @@
 #include "ui/gfx/geometry/rect.h"
 
 namespace cc {
+class ImageSerializationProcessor;
 
 // static
 void DisplayItemProtoFactory::AllocateAndConstruct(
     const gfx::Rect& visual_rect,
     DisplayItemList* list,
-    const proto::DisplayItem& proto) {
+    const proto::DisplayItem& proto,
+    ImageSerializationProcessor* image_serialization_processor) {
   switch (proto.type()) {
     case proto::DisplayItem::Type_Clip:
       list->CreateAndAppendItem<ClipDisplayItem>(visual_rect, proto);
@@ -41,7 +43,8 @@
       list->CreateAndAppendItem<EndCompositingDisplayItem>(visual_rect, proto);
       return;
     case proto::DisplayItem::Type_Drawing:
-      list->CreateAndAppendItem<DrawingDisplayItem>(visual_rect, proto);
+      list->CreateAndAppendItem<DrawingDisplayItem>(
+          visual_rect, proto, image_serialization_processor);
       return;
     case proto::DisplayItem::Type_Filter:
       list->CreateAndAppendItem<FilterDisplayItem>(visual_rect, proto);
diff --git a/cc/playback/display_item_proto_factory.h b/cc/playback/display_item_proto_factory.h
index edc6118..f881e793 100644
--- a/cc/playback/display_item_proto_factory.h
+++ b/cc/playback/display_item_proto_factory.h
@@ -11,6 +11,7 @@
 #include "cc/playback/display_item_list.h"
 
 namespace cc {
+class ImageSerializationProcessor;
 
 namespace proto {
 class DisplayItem;
@@ -18,9 +19,11 @@
 
 class DisplayItemProtoFactory {
  public:
-  static void AllocateAndConstruct(const gfx::Rect& visual_rect,
-                                   DisplayItemList* list,
-                                   const proto::DisplayItem& proto);
+  static void AllocateAndConstruct(
+      const gfx::Rect& visual_rect,
+      DisplayItemList* list,
+      const proto::DisplayItem& proto,
+      ImageSerializationProcessor* image_serialization_processor);
 
  private:
   DisplayItemProtoFactory() {}
diff --git a/cc/playback/display_list_recording_source.cc b/cc/playback/display_list_recording_source.cc
index d4e6a3e6e..52c8277 100644
--- a/cc/playback/display_list_recording_source.cc
+++ b/cc/playback/display_list_recording_source.cc
@@ -34,6 +34,7 @@
 }  // namespace
 
 namespace cc {
+class ImageSerializationProcessor;
 
 DisplayListRecordingSource::DisplayListRecordingSource()
     : slow_down_raster_scale_factor_for_debug_(0),
@@ -49,7 +50,8 @@
 }
 
 void DisplayListRecordingSource::ToProtobuf(
-    proto::DisplayListRecordingSource* proto) const {
+    proto::DisplayListRecordingSource* proto,
+    ImageSerializationProcessor* image_serialization_processor) const {
   RectToProto(recorded_viewport_, proto->mutable_recorded_viewport());
   SizeToProto(size_, proto->mutable_size());
   proto->set_slow_down_raster_scale_factor_for_debug(
@@ -61,12 +63,15 @@
   proto->set_clear_canvas_with_debug_color(clear_canvas_with_debug_color_);
   proto->set_solid_color(static_cast<uint64_t>(solid_color_));
   proto->set_background_color(static_cast<uint64_t>(background_color_));
-  if (display_list_)
-    display_list_->ToProtobuf(proto->mutable_display_list());
+  if (display_list_) {
+    display_list_->ToProtobuf(proto->mutable_display_list(),
+                              image_serialization_processor);
+  }
 }
 
 void DisplayListRecordingSource::FromProtobuf(
-    const proto::DisplayListRecordingSource& proto) {
+    const proto::DisplayListRecordingSource& proto,
+    ImageSerializationProcessor* image_serialization_processor) {
   recorded_viewport_ = ProtoToRect(proto.recorded_viewport());
   size_ = ProtoToSize(proto.size());
   slow_down_raster_scale_factor_for_debug_ =
@@ -83,7 +88,8 @@
   // DisplayListRecordingSource was null, wich can happen if |Clear()| is
   // called.
   if (proto.has_display_list()) {
-    display_list_ = DisplayItemList::CreateFromProto(proto.display_list());
+    display_list_ = DisplayItemList::CreateFromProto(
+        proto.display_list(), image_serialization_processor);
     FinishDisplayItemListUpdate();
   } else {
     display_list_ = nullptr;
diff --git a/cc/playback/display_list_recording_source.h b/cc/playback/display_list_recording_source.h
index 4fb2164..c69c1149 100644
--- a/cc/playback/display_list_recording_source.h
+++ b/cc/playback/display_list_recording_source.h
@@ -19,11 +19,12 @@
 
 namespace proto {
 class DisplayListRecordingSource;
-}
+}  // namespace proto
 
 class ContentLayerClient;
 class DisplayItemList;
 class DisplayListRasterSource;
+class ImageSerializationProcessor;
 class Region;
 
 class CC_EXPORT DisplayListRecordingSource {
@@ -43,8 +44,11 @@
   DisplayListRecordingSource();
   virtual ~DisplayListRecordingSource();
 
-  void ToProtobuf(proto::DisplayListRecordingSource* proto) const;
-  void FromProtobuf(const proto::DisplayListRecordingSource& proto);
+  void ToProtobuf(
+      proto::DisplayListRecordingSource* proto,
+      ImageSerializationProcessor* image_serialization_processor) const;
+  void FromProtobuf(const proto::DisplayListRecordingSource& proto,
+                    ImageSerializationProcessor* image_serialization_processor);
 
   bool UpdateAndExpandInvalidation(ContentLayerClient* painter,
                                    Region* invalidation,
diff --git a/cc/playback/display_list_recording_source_unittest.cc b/cc/playback/display_list_recording_source_unittest.cc
index 1649566..3b619bb 100644
--- a/cc/playback/display_list_recording_source_unittest.cc
+++ b/cc/playback/display_list_recording_source_unittest.cc
@@ -9,6 +9,7 @@
 #include "cc/proto/display_list_recording_source.pb.h"
 #include "cc/test/fake_content_layer_client.h"
 #include "cc/test/fake_display_list_recording_source.h"
+#include "cc/test/fake_image_serialization_processor.h"
 #include "cc/test/skia_common.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -33,11 +34,15 @@
 
 void ValidateRecordingSourceSerialization(
     FakeDisplayListRecordingSource* source) {
+  scoped_ptr<FakeImageSerializationProcessor>
+      fake_image_serialization_processor =
+          make_scoped_ptr(new FakeImageSerializationProcessor);
+
   proto::DisplayListRecordingSource proto;
-  source->ToProtobuf(&proto);
+  source->ToProtobuf(&proto, fake_image_serialization_processor.get());
 
   FakeDisplayListRecordingSource new_source;
-  new_source.FromProtobuf(proto);
+  new_source.FromProtobuf(proto, fake_image_serialization_processor.get());
 
   EXPECT_TRUE(source->EqualsTo(new_source));
 }
diff --git a/cc/playback/drawing_display_item.cc b/cc/playback/drawing_display_item.cc
index 36181ae..f8832cb 100644
--- a/cc/playback/drawing_display_item.cc
+++ b/cc/playback/drawing_display_item.cc
@@ -13,6 +13,7 @@
 #include "base/values.h"
 #include "cc/debug/picture_debug_util.h"
 #include "cc/proto/display_item.pb.h"
+#include "cc/proto/image_serialization_processor.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkData.h"
 #include "third_party/skia/include/core/SkMatrix.h"
@@ -29,7 +30,9 @@
   SetNew(std::move(picture));
 }
 
-DrawingDisplayItem::DrawingDisplayItem(const proto::DisplayItem& proto) {
+DrawingDisplayItem::DrawingDisplayItem(
+    const proto::DisplayItem& proto,
+    ImageSerializationProcessor* image_serialization_processor) {
   DCHECK_EQ(proto::DisplayItem::Type_Drawing, proto.type());
 
   skia::RefPtr<SkPicture> picture;
@@ -37,8 +40,8 @@
   if (details.has_picture()) {
     SkMemoryStream stream(details.picture().data(), details.picture().size());
 
-    // TODO(dtrainor, nyquist): Add an image decoder.
-    picture = skia::AdoptRef(SkPicture::CreateFromStream(&stream, nullptr));
+    picture = skia::AdoptRef(SkPicture::CreateFromStream(
+        &stream, image_serialization_processor->GetPixelDeserializer()));
   }
 
   SetNew(std::move(picture));
@@ -55,7 +58,9 @@
   picture_ = std::move(picture);
 }
 
-void DrawingDisplayItem::ToProtobuf(proto::DisplayItem* proto) const {
+void DrawingDisplayItem::ToProtobuf(
+    proto::DisplayItem* proto,
+    ImageSerializationProcessor* image_serialization_processor) const {
   proto->set_type(proto::DisplayItem::Type_Drawing);
 
   proto::DrawingDisplayItem* details = proto->mutable_drawing_item();
@@ -63,10 +68,8 @@
   // Just use skia's serialize() method for now.
   if (picture_) {
     SkDynamicMemoryWStream stream;
-
-    // TODO(dtrainor, nyquist): Add an SkPixelSerializer to not serialize images
-    // more than once (crbug.com/548434).
-    picture_->serialize(&stream, nullptr);
+    picture_->serialize(&stream,
+                        image_serialization_processor->GetPixelSerializer());
     if (stream.bytesWritten() > 0) {
       SkAutoDataUnref data(stream.copyToData());
       details->set_picture(data->data(), data->size());
diff --git a/cc/playback/drawing_display_item.h b/cc/playback/drawing_display_item.h
index 225bda41..8045904 100644
--- a/cc/playback/drawing_display_item.h
+++ b/cc/playback/drawing_display_item.h
@@ -17,16 +17,21 @@
 class SkPicture;
 
 namespace cc {
+class ImageSerializationProcessor;
 
 class CC_EXPORT DrawingDisplayItem : public DisplayItem {
  public:
   DrawingDisplayItem();
   explicit DrawingDisplayItem(skia::RefPtr<const SkPicture> picture);
-  explicit DrawingDisplayItem(const proto::DisplayItem& proto);
+  explicit DrawingDisplayItem(
+      const proto::DisplayItem& proto,
+      ImageSerializationProcessor* image_serialization_processor);
   explicit DrawingDisplayItem(const DrawingDisplayItem& item);
   ~DrawingDisplayItem() override;
 
-  void ToProtobuf(proto::DisplayItem* proto) const override;
+  void ToProtobuf(proto::DisplayItem* proto,
+                  ImageSerializationProcessor* image_serialization_processor)
+      const override;
   void Raster(SkCanvas* canvas,
               const gfx::Rect& canvas_playback_rect,
               SkPicture::AbortCallback* callback) const override;
diff --git a/cc/playback/filter_display_item.cc b/cc/playback/filter_display_item.cc
index 0c6ebe0a..af42baa 100644
--- a/cc/playback/filter_display_item.cc
+++ b/cc/playback/filter_display_item.cc
@@ -19,6 +19,7 @@
 #include "ui/gfx/skia_util.h"
 
 namespace cc {
+class ImageSerializationProcessor;
 
 FilterDisplayItem::FilterDisplayItem(const FilterOperations& filters,
                                      const gfx::RectF& bounds) {
@@ -45,7 +46,9 @@
   bounds_ = bounds;
 }
 
-void FilterDisplayItem::ToProtobuf(proto::DisplayItem* proto) const {
+void FilterDisplayItem::ToProtobuf(
+    proto::DisplayItem* proto,
+    ImageSerializationProcessor* image_serialization_processor) const {
   proto->set_type(proto::DisplayItem::Type_Filter);
 
   proto::FilterDisplayItem* details = proto->mutable_filter_item();
@@ -95,7 +98,9 @@
 
 EndFilterDisplayItem::~EndFilterDisplayItem() {}
 
-void EndFilterDisplayItem::ToProtobuf(proto::DisplayItem* proto) const {
+void EndFilterDisplayItem::ToProtobuf(
+    proto::DisplayItem* proto,
+    ImageSerializationProcessor* image_serialization_processor) const {
   proto->set_type(proto::DisplayItem::Type_EndFilter);
 }
 
diff --git a/cc/playback/filter_display_item.h b/cc/playback/filter_display_item.h
index d4506ed..b385538 100644
--- a/cc/playback/filter_display_item.h
+++ b/cc/playback/filter_display_item.h
@@ -16,6 +16,7 @@
 class SkCanvas;
 
 namespace cc {
+class ImageSerializationProcessor;
 
 class CC_EXPORT FilterDisplayItem : public DisplayItem {
  public:
@@ -23,7 +24,9 @@
   explicit FilterDisplayItem(const proto::DisplayItem& proto);
   ~FilterDisplayItem() override;
 
-  void ToProtobuf(proto::DisplayItem* proto) const override;
+  void ToProtobuf(proto::DisplayItem* proto,
+                  ImageSerializationProcessor* image_serialization_processor)
+      const override;
   void Raster(SkCanvas* canvas,
               const gfx::Rect& canvas_target_playback_rect,
               SkPicture::AbortCallback* callback) const override;
@@ -51,7 +54,9 @@
     return make_scoped_ptr(new EndFilterDisplayItem());
   }
 
-  void ToProtobuf(proto::DisplayItem* proto) const override;
+  void ToProtobuf(proto::DisplayItem* proto,
+                  ImageSerializationProcessor* image_serialization_processor)
+      const override;
   void Raster(SkCanvas* canvas,
               const gfx::Rect& canvas_target_playback_rect,
               SkPicture::AbortCallback* callback) const override;
diff --git a/cc/playback/float_clip_display_item.cc b/cc/playback/float_clip_display_item.cc
index 3601e9d..621c4d9 100644
--- a/cc/playback/float_clip_display_item.cc
+++ b/cc/playback/float_clip_display_item.cc
@@ -14,6 +14,7 @@
 #include "ui/gfx/skia_util.h"
 
 namespace cc {
+class ImageSerializationProcessor;
 
 FloatClipDisplayItem::FloatClipDisplayItem(const gfx::RectF& clip_rect) {
   SetNew(clip_rect);
@@ -35,7 +36,9 @@
   clip_rect_ = clip_rect;
 }
 
-void FloatClipDisplayItem::ToProtobuf(proto::DisplayItem* proto) const {
+void FloatClipDisplayItem::ToProtobuf(
+    proto::DisplayItem* proto,
+    ImageSerializationProcessor* image_serialization_processor) const {
   proto->set_type(proto::DisplayItem::Type_FloatClip);
 
   proto::FloatClipDisplayItem* details = proto->mutable_float_clip_item();
@@ -71,7 +74,9 @@
 EndFloatClipDisplayItem::~EndFloatClipDisplayItem() {
 }
 
-void EndFloatClipDisplayItem::ToProtobuf(proto::DisplayItem* proto) const {
+void EndFloatClipDisplayItem::ToProtobuf(
+    proto::DisplayItem* proto,
+    ImageSerializationProcessor* image_serialization_processor) const {
   proto->set_type(proto::DisplayItem::Type_EndFloatClip);
 }
 
diff --git a/cc/playback/float_clip_display_item.h b/cc/playback/float_clip_display_item.h
index 8c34c5fb..41d9ace 100644
--- a/cc/playback/float_clip_display_item.h
+++ b/cc/playback/float_clip_display_item.h
@@ -17,6 +17,7 @@
 class SkCanvas;
 
 namespace cc {
+class ImageSerializationProcessor;
 
 class CC_EXPORT FloatClipDisplayItem : public DisplayItem {
  public:
@@ -24,7 +25,9 @@
   explicit FloatClipDisplayItem(const proto::DisplayItem& proto);
   ~FloatClipDisplayItem() override;
 
-  void ToProtobuf(proto::DisplayItem* proto) const override;
+  void ToProtobuf(proto::DisplayItem* proto,
+                  ImageSerializationProcessor* image_serialization_processor)
+      const override;
   void Raster(SkCanvas* canvas,
               const gfx::Rect& canvas_target_playback_rect,
               SkPicture::AbortCallback* callback) const override;
@@ -51,7 +54,9 @@
     return make_scoped_ptr(new EndFloatClipDisplayItem());
   }
 
-  void ToProtobuf(proto::DisplayItem* proto) const override;
+  void ToProtobuf(proto::DisplayItem* proto,
+                  ImageSerializationProcessor* image_serialization_processor)
+      const override;
   void Raster(SkCanvas* canvas,
               const gfx::Rect& canvas_target_playback_rect,
               SkPicture::AbortCallback* callback) const override;
diff --git a/cc/playback/transform_display_item.cc b/cc/playback/transform_display_item.cc
index c4625ff..e3aa591 100644
--- a/cc/playback/transform_display_item.cc
+++ b/cc/playback/transform_display_item.cc
@@ -13,6 +13,7 @@
 #include "third_party/skia/include/core/SkCanvas.h"
 
 namespace cc {
+class ImageSerializationProcessor;
 
 TransformDisplayItem::TransformDisplayItem(const gfx::Transform& transform)
     : transform_(gfx::Transform::kSkipInitialization) {
@@ -35,7 +36,9 @@
   transform_ = transform;
 }
 
-void TransformDisplayItem::ToProtobuf(proto::DisplayItem* proto) const {
+void TransformDisplayItem::ToProtobuf(
+    proto::DisplayItem* proto,
+    ImageSerializationProcessor* image_serialization_processor) const {
   proto->set_type(proto::DisplayItem::Type_Transform);
 
   proto::TransformDisplayItem* details = proto->mutable_transform_item();
@@ -72,7 +75,9 @@
 EndTransformDisplayItem::~EndTransformDisplayItem() {
 }
 
-void EndTransformDisplayItem::ToProtobuf(proto::DisplayItem* proto) const {
+void EndTransformDisplayItem::ToProtobuf(
+    proto::DisplayItem* proto,
+    ImageSerializationProcessor* image_serialization_processor) const {
   proto->set_type(proto::DisplayItem::Type_EndTransform);
 }
 
diff --git a/cc/playback/transform_display_item.h b/cc/playback/transform_display_item.h
index 5b891361..7c1d934f 100644
--- a/cc/playback/transform_display_item.h
+++ b/cc/playback/transform_display_item.h
@@ -15,6 +15,7 @@
 class SkCanvas;
 
 namespace cc {
+class ImageSerializationProcessor;
 
 class CC_EXPORT TransformDisplayItem : public DisplayItem {
  public:
@@ -22,7 +23,9 @@
   explicit TransformDisplayItem(const proto::DisplayItem& proto);
   ~TransformDisplayItem() override;
 
-  void ToProtobuf(proto::DisplayItem* proto) const override;
+  void ToProtobuf(proto::DisplayItem* proto,
+                  ImageSerializationProcessor* image_serialization_processor)
+      const override;
   void Raster(SkCanvas* canvas,
               const gfx::Rect& canvas_target_playback_rect,
               SkPicture::AbortCallback* callback) const override;
@@ -49,7 +52,9 @@
     return make_scoped_ptr(new EndTransformDisplayItem());
   }
 
-  void ToProtobuf(proto::DisplayItem* proto) const override;
+  void ToProtobuf(proto::DisplayItem* proto,
+                  ImageSerializationProcessor* image_serialization_processor)
+      const override;
   void Raster(SkCanvas* canvas,
               const gfx::Rect& canvas_target_playback_rect,
               SkPicture::AbortCallback* callback) const override;
diff --git a/cc/proto/image_serialization_processor.h b/cc/proto/image_serialization_processor.h
new file mode 100644
index 0000000..75b9936
--- /dev/null
+++ b/cc/proto/image_serialization_processor.h
@@ -0,0 +1,30 @@
+// Copyright 2016 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 CC_PROTO_IMAGE_SERIALIZATION_PROCESSOR_H_
+#define CC_PROTO_IMAGE_SERIALIZATION_PROCESSOR_H_
+
+#include "third_party/skia/include/core/SkPicture.h"
+#include "third_party/skia/include/core/SkPixelSerializer.h"
+
+class SkPixelSerializer;
+
+namespace cc {
+
+// ImageSerializationProcessor provides functionality to serialize and
+// deserialize Skia images.
+class ImageSerializationProcessor {
+ public:
+  // The serializer returned from this function can be used to pass in to
+  // SkPicture::serialize(...) for serializing the SkPicture to a stream.
+  virtual SkPixelSerializer* GetPixelSerializer() = 0;
+
+  // Returns a function pointer valid to use for deserializing images when using
+  // SkPicture::CreateFromStream to create an SkPicture from a stream.
+  virtual SkPicture::InstallPixelRefProc GetPixelDeserializer() = 0;
+};
+
+}  // namespace cc
+
+#endif  // CC_PROTO_IMAGE_SERIALIZATION_PROCESSOR_H_
diff --git a/cc/test/fake_image_serialization_processor.cc b/cc/test/fake_image_serialization_processor.cc
new file mode 100644
index 0000000..c43b3e8
--- /dev/null
+++ b/cc/test/fake_image_serialization_processor.cc
@@ -0,0 +1,32 @@
+// Copyright 2016 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.
+
+#include "cc/test/fake_image_serialization_processor.h"
+
+#include "third_party/skia/include/core/SkPicture.h"
+
+namespace {
+bool NoopDecoder(const void* input, size_t input_size, SkBitmap* bitmap) {
+  return false;
+}
+}
+
+class SkPixelSerializer;
+
+namespace cc {
+
+FakeImageSerializationProcessor::FakeImageSerializationProcessor() {}
+
+FakeImageSerializationProcessor::~FakeImageSerializationProcessor() {}
+
+SkPixelSerializer* FakeImageSerializationProcessor::GetPixelSerializer() {
+  return nullptr;
+}
+
+SkPicture::InstallPixelRefProc
+FakeImageSerializationProcessor::GetPixelDeserializer() {
+  return &NoopDecoder;
+}
+
+}  // namespace cc
diff --git a/cc/test/fake_image_serialization_processor.h b/cc/test/fake_image_serialization_processor.h
new file mode 100644
index 0000000..613e93b1
--- /dev/null
+++ b/cc/test/fake_image_serialization_processor.h
@@ -0,0 +1,30 @@
+// Copyright 2016 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 CC_TEST_FAKE_IMAGE_SERIALIZATION_PROCESSOR_H_
+#define CC_TEST_FAKE_IMAGE_SERIALIZATION_PROCESSOR_H_
+
+#include "base/macros.h"
+#include "cc/proto/image_serialization_processor.h"
+
+class SkPixelSerializer;
+
+namespace cc {
+
+class FakeImageSerializationProcessor : public ImageSerializationProcessor {
+ public:
+  FakeImageSerializationProcessor();
+  ~FakeImageSerializationProcessor();
+
+  // ImageSerializationProcessor implementation.
+  SkPixelSerializer* GetPixelSerializer() override;
+  SkPicture::InstallPixelRefProc GetPixelDeserializer() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeImageSerializationProcessor);
+};
+
+}  // namespace cc
+
+#endif  // CC_TEST_FAKE_IMAGE_SERIALIZATION_PROCESSOR_H_
diff --git a/cc/test/fake_layer_tree_host.cc b/cc/test/fake_layer_tree_host.cc
index 2a8d242..ca054a7 100644
--- a/cc/test/fake_layer_tree_host.cc
+++ b/cc/test/fake_layer_tree_host.cc
@@ -5,6 +5,7 @@
 #include "cc/test/fake_layer_tree_host.h"
 
 #include "cc/layers/layer.h"
+#include "cc/test/fake_image_serialization_processor.h"
 #include "cc/test/test_task_graph_runner.h"
 
 namespace cc {
@@ -56,6 +57,20 @@
   return make_scoped_ptr(new FakeLayerTreeHost(client, &params, mode));
 }
 
+scoped_ptr<FakeLayerTreeHost> FakeLayerTreeHost::Create(
+    FakeLayerTreeHostClient* client,
+    TestTaskGraphRunner* task_graph_runner,
+    const LayerTreeSettings& settings,
+    CompositorMode mode,
+    ImageSerializationProcessor* image_serialization_processor) {
+  LayerTreeHost::InitParams params;
+  params.client = client;
+  params.settings = &settings;
+  params.task_graph_runner = task_graph_runner;
+  params.image_serialization_processor = image_serialization_processor;
+  return make_scoped_ptr(new FakeLayerTreeHost(client, &params, mode));
+}
+
 FakeLayerTreeHost::~FakeLayerTreeHost() {
   client_->SetLayerTreeHost(NULL);
 }
diff --git a/cc/test/fake_layer_tree_host.h b/cc/test/fake_layer_tree_host.h
index b0b9cdeb..11fe0d2d 100644
--- a/cc/test/fake_layer_tree_host.h
+++ b/cc/test/fake_layer_tree_host.h
@@ -15,6 +15,7 @@
 #include "cc/trees/tree_synchronizer.h"
 
 namespace cc {
+class ImageSerializationProcessor;
 class TestTaskGraphRunner;
 
 class FakeLayerTreeHost : public LayerTreeHost {
@@ -31,7 +32,18 @@
       TestTaskGraphRunner* task_graph_runner,
       const LayerTreeSettings& settings,
       CompositorMode mode);
-
+  static scoped_ptr<FakeLayerTreeHost> Create(
+      FakeLayerTreeHostClient* client,
+      TestTaskGraphRunner* task_graph_runner,
+      const LayerTreeSettings& settings,
+      CompositorMode mode,
+      InitParams params);
+  static scoped_ptr<FakeLayerTreeHost> Create(
+      FakeLayerTreeHostClient* client,
+      TestTaskGraphRunner* task_graph_runner,
+      const LayerTreeSettings& settings,
+      CompositorMode mode,
+      ImageSerializationProcessor* image_serialization_processor);
   ~FakeLayerTreeHost() override;
 
   const RendererCapabilities& GetRendererCapabilities() const override;
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index b7646a8..ce09a69 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -128,6 +128,7 @@
   // remote mode.
   DCHECK(!params->settings->use_external_begin_frame_source);
   DCHECK(!params->external_begin_frame_source);
+  DCHECK(params->image_serialization_processor);
 
   scoped_ptr<LayerTreeHost> layer_tree_host(
       new LayerTreeHost(params, CompositorMode::REMOTE));
@@ -149,6 +150,7 @@
   // source on the client LayerTreeHost. crbug/576962
   DCHECK(!params->settings->use_external_begin_frame_source);
   DCHECK(!params->external_begin_frame_source);
+  DCHECK(params->image_serialization_processor);
 
   scoped_ptr<LayerTreeHost> layer_tree_host(
       new LayerTreeHost(params, CompositorMode::REMOTE));
@@ -193,6 +195,7 @@
       shared_bitmap_manager_(params->shared_bitmap_manager),
       gpu_memory_buffer_manager_(params->gpu_memory_buffer_manager),
       task_graph_runner_(params->task_graph_runner),
+      image_serialization_processor_(params->image_serialization_processor),
       surface_id_namespace_(0u),
       next_surface_sequence_(1u) {
   DCHECK(task_graph_runner_);
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index 36807ff8..453c75f 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -58,6 +58,7 @@
 class AnimationHost;
 class BeginFrameSource;
 class HeadsUpDisplayLayer;
+class ImageSerializationProcessor;
 class Layer;
 class LayerTreeHostImpl;
 class LayerTreeHostImplClient;
@@ -92,6 +93,7 @@
     LayerTreeSettings const* settings = nullptr;
     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner;
     scoped_ptr<BeginFrameSource> external_begin_frame_source;
+    ImageSerializationProcessor* image_serialization_processor = nullptr;
 
     InitParams();
     ~InitParams();
@@ -418,6 +420,10 @@
   bool IsRemoteClient() const;
   void BuildPropertyTreesForTesting();
 
+  ImageSerializationProcessor* image_serialization_processor() const {
+    return image_serialization_processor_;
+  }
+
  protected:
   LayerTreeHost(InitParams* params, CompositorMode mode);
   void InitializeThreaded(
@@ -572,6 +578,8 @@
   gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
   TaskGraphRunner* task_graph_runner_;
 
+  ImageSerializationProcessor* image_serialization_processor_;
+
   std::vector<scoped_ptr<SwapPromise>> swap_promise_list_;
   std::set<SwapPromiseMonitor*> swap_promise_monitor_;
 
diff --git a/cc/trees/layer_tree_host_unittest_remote_server.cc b/cc/trees/layer_tree_host_unittest_remote_server.cc
index d902cfa..9873dca 100644
--- a/cc/trees/layer_tree_host_unittest_remote_server.cc
+++ b/cc/trees/layer_tree_host_unittest_remote_server.cc
@@ -4,7 +4,9 @@
 
 #include "cc/trees/layer_tree_host.h"
 
+#include "base/memory/scoped_ptr.h"
 #include "base/thread_task_runner_handle.h"
+#include "cc/test/fake_image_serialization_processor.h"
 #include "cc/test/test_task_graph_runner.h"
 #include "cc/trees/layer_tree_host_client.h"
 #include "cc/trees/proxy_common.h"
@@ -19,12 +21,16 @@
                                       public RemoteProtoChannel,
                                       public LayerTreeHostClient {
  public:
-  LayerTreeHostTestRemoteServer() : calls_received_(0) {
+  LayerTreeHostTestRemoteServer()
+      : calls_received_(0),
+        image_serialization_processor_(
+            make_scoped_ptr(new FakeImageSerializationProcessor)) {
     LayerTreeHost::InitParams params;
     params.client = this;
     params.task_graph_runner = &task_graph_runner_;
     params.settings = &settings_;
     params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
+    params.image_serialization_processor = image_serialization_processor_.get();
     layer_tree_host_ = LayerTreeHost::CreateRemoteServer(this, &params);
   }
 
@@ -66,6 +72,7 @@
   LayerTreeSettings settings_;
   scoped_ptr<LayerTreeHost> layer_tree_host_;
   RemoteProtoChannel::ProtoReceiver* receiver_;
+  scoped_ptr<FakeImageSerializationProcessor> image_serialization_processor_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(LayerTreeHostTestRemoteServer);
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc
index a9b28f8..d32ecccb 100644
--- a/content/public/renderer/content_renderer_client.cc
+++ b/content/public/renderer/content_renderer_client.cc
@@ -176,6 +176,11 @@
   return nullptr;
 }
 
+cc::ImageSerializationProcessor*
+ContentRendererClient::GetImageSerializationProcessor() {
+  return nullptr;
+}
+
 bool ContentRendererClient::ShouldReportDetailedMessageForSource(
     const base::string16& source) const {
   return false;
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h
index 241d95b..880550c 100644
--- a/content/public/renderer/content_renderer_client.h
+++ b/content/public/renderer/content_renderer_client.h
@@ -56,6 +56,10 @@
 struct WebURLError;
 }
 
+namespace cc {
+class ImageSerializationProcessor;
+}
+
 namespace media {
 class GpuVideoAcceleratorFactories;
 class MediaLog;
@@ -256,6 +260,9 @@
   virtual scoped_ptr<MediaStreamRendererFactory>
   CreateMediaStreamRendererFactory();
 
+  // Allows an embedder to provde a cc::ImageSerializationProcessor.
+  virtual cc::ImageSerializationProcessor* GetImageSerializationProcessor();
+
   // Gives the embedder a chance to register the key system(s) it supports by
   // populating |key_systems|.
   virtual void AddKeySystems(std::vector<media::KeySystemInfo>* key_systems);
diff --git a/content/renderer/gpu/compositor_dependencies.h b/content/renderer/gpu/compositor_dependencies.h
index fd46a11..3f82883d 100644
--- a/content/renderer/gpu/compositor_dependencies.h
+++ b/content/renderer/gpu/compositor_dependencies.h
@@ -17,6 +17,7 @@
 namespace cc {
 class BeginFrameSource;
 class ContextProvider;
+class ImageSerializationProcessor;
 class SharedBitmapManager;
 class TaskGraphRunner;
 }
@@ -55,6 +56,7 @@
   virtual cc::ContextProvider* GetSharedMainThreadContextProvider() = 0;
   virtual scoped_ptr<cc::BeginFrameSource> CreateExternalBeginFrameSource(
       int routing_id) = 0;
+  virtual cc::ImageSerializationProcessor* GetImageSerializationProcessor() = 0;
   virtual cc::TaskGraphRunner* GetTaskGraphRunner() = 0;
   virtual bool AreImageDecodeTasksEnabled() = 0;
   virtual bool IsThreadedAnimationEnabled() = 0;
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index 86a5167..64e1c8f 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -504,7 +504,8 @@
   params.external_begin_frame_source = std::move(external_begin_frame_source);
   if (use_remote_compositing) {
     DCHECK(!compositor_thread_task_runner.get());
-
+    params.image_serialization_processor =
+        compositor_deps_->GetImageSerializationProcessor();
     layer_tree_host_ = cc::LayerTreeHost::CreateRemoteServer(this, &params);
   } else if (compositor_thread_task_runner.get()) {
     layer_tree_host_ = cc::LayerTreeHost::CreateThreaded(
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index a62dd41..0746e71 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1703,6 +1703,11 @@
       compositor_message_filter_.get(), sync_message_filter(), routing_id));
 }
 
+cc::ImageSerializationProcessor*
+RenderThreadImpl::GetImageSerializationProcessor() {
+  return GetContentClient()->renderer()->GetImageSerializationProcessor();
+}
+
 cc::TaskGraphRunner* RenderThreadImpl::GetTaskGraphRunner() {
   return raster_worker_pool_->GetTaskGraphRunner();
 }
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index 1ea61a4..ab67cd9e 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -57,6 +57,7 @@
 
 namespace cc {
 class ContextProvider;
+class ImageSerializationProcessor;
 class TaskGraphRunner;
 }
 
@@ -215,6 +216,7 @@
   cc::ContextProvider* GetSharedMainThreadContextProvider() override;
   scoped_ptr<cc::BeginFrameSource> CreateExternalBeginFrameSource(
       int routing_id) override;
+  cc::ImageSerializationProcessor* GetImageSerializationProcessor() override;
   cc::TaskGraphRunner* GetTaskGraphRunner() override;
   bool AreImageDecodeTasksEnabled() override;
   bool IsThreadedAnimationEnabled() override;
diff --git a/content/test/fake_compositor_dependencies.cc b/content/test/fake_compositor_dependencies.cc
index 3126d2a..ea6ca2f 100644
--- a/content/test/fake_compositor_dependencies.cc
+++ b/content/test/fake_compositor_dependencies.cc
@@ -96,6 +96,11 @@
   return make_scoped_ptr(new cc::FakeExternalBeginFrameSource(refresh_rate));
 }
 
+cc::ImageSerializationProcessor*
+FakeCompositorDependencies::GetImageSerializationProcessor() {
+  return nullptr;
+}
+
 cc::TaskGraphRunner* FakeCompositorDependencies::GetTaskGraphRunner() {
   return &task_graph_runner_;
 }
diff --git a/content/test/fake_compositor_dependencies.h b/content/test/fake_compositor_dependencies.h
index f13a598..c9f6ed27 100644
--- a/content/test/fake_compositor_dependencies.h
+++ b/content/test/fake_compositor_dependencies.h
@@ -40,6 +40,7 @@
   cc::ContextProvider* GetSharedMainThreadContextProvider() override;
   scoped_ptr<cc::BeginFrameSource> CreateExternalBeginFrameSource(
       int routing_id) override;
+  cc::ImageSerializationProcessor* GetImageSerializationProcessor() override;
   cc::TaskGraphRunner* GetTaskGraphRunner() override;
   bool AreImageDecodeTasksEnabled() override;
   bool IsThreadedAnimationEnabled() override;