Update from https://crrev.com/306655

Includes updates to ui/ and mojo/services for cc and gpu changes and
a minor update to a unit test in sky/ for skia interface changes.

Review URL: https://codereview.chromium.org/761903003
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 6d5fec4..7e66bd9 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -323,10 +323,24 @@
     "resources/bitmap_raster_worker_pool.h",
     "resources/bitmap_skpicture_content_layer_updater.cc",
     "resources/bitmap_skpicture_content_layer_updater.h",
+    "resources/clip_display_item.cc",
+    "resources/clip_display_item.h",
     "resources/content_layer_updater.cc",
     "resources/content_layer_updater.h",
+    "resources/display_item.cc",
+    "resources/display_item.h",
+    "resources/display_item_list.cc",
+    "resources/display_item_list.h",
+    "resources/display_list_raster_source.cc",
+    "resources/display_list_raster_source.h",
+    "resources/display_list_recording_source.cc",
+    "resources/display_list_recording_source.h",
+    "resources/drawing_display_item.cc",
+    "resources/drawing_display_item.h",
     "resources/eviction_tile_priority_queue.cc",
     "resources/eviction_tile_priority_queue.h",
+    "resources/filter_display_item.cc",
+    "resources/filter_display_item.h",
     "resources/gpu_raster_worker_pool.cc",
     "resources/gpu_raster_worker_pool.h",
     "resources/image_layer_updater.cc",
@@ -366,6 +380,8 @@
     "resources/raster_buffer.cc",
     "resources/raster_buffer.h",
     "resources/raster_source.h",
+    "resources/raster_source_helper.cc",
+    "resources/raster_source_helper.h",
     "resources/raster_tile_priority_queue.cc",
     "resources/raster_tile_priority_queue.h",
     "resources/raster_worker_pool.cc",
@@ -417,8 +433,14 @@
     "resources/tile_manager.h",
     "resources/tile_priority.cc",
     "resources/tile_priority.h",
+    "resources/tiling_set_eviction_queue.cc",
+    "resources/tiling_set_eviction_queue.h",
     "resources/transferable_resource.cc",
     "resources/transferable_resource.h",
+    "resources/transform_display_item.cc",
+    "resources/transform_display_item.h",
+    "resources/transparency_display_item.cc",
+    "resources/transparency_display_item.h",
     "resources/ui_resource_bitmap.cc",
     "resources/ui_resource_bitmap.h",
     "resources/ui_resource_client.h",
@@ -482,6 +504,7 @@
   deps = [
     "//base",
     "//base/third_party/dynamic_annotations",
+    "//cc/surfaces:surface_id",
     "//gpu",
     "//gpu/command_buffer/client:gles2_interface",
     "//gpu/command_buffer/client:gpu_memory_buffer_manager",
@@ -635,6 +658,7 @@
   ]
   deps = [
     "//base",
+    "//base/test:test_support",
     "//base/third_party/dynamic_annotations",
     "//gpu/command_buffer/client:gles2_c_lib",
     "//gpu/command_buffer/client:gles2_implementation",
@@ -720,6 +744,7 @@
     "quads/draw_quad_unittest.cc",
     "quads/list_container_unittest.cc",
     "quads/render_pass_unittest.cc",
+    "resources/display_item_list_unittest.cc",
     "resources/layer_quad_unittest.cc",
     "resources/picture_layer_tiling_set_unittest.cc",
     "resources/picture_layer_tiling_unittest.cc",
@@ -786,6 +811,7 @@
     ":test_support",
     "//base/test:test_support",
     "//cc/surfaces",
+    "//cc/surfaces:surface_id",
     "//gpu",
     "//gpu:test_support",
     "//gpu/command_buffer/client:gles2_interface",
@@ -795,6 +821,8 @@
     "//ui/events:events_base",
     "//ui/gfx",
     "//ui/gfx/geometry",
+    "//ui/gfx:test_support",
+    "//ui/gl",
   ]
 }
 
@@ -818,6 +846,7 @@
     ":cc",
     ":test_support",
     "//base",
+    "//base/test:test_support",
     "//gpu",
     "//gpu:test_support",
     "//gpu/command_buffer/common:gles2_utils",
@@ -827,5 +856,6 @@
     "//testing/perf",
     "//ui/gfx",
     "//ui/gfx/geometry",
+    "//ui/gl",
   ]
 }
diff --git a/cc/base/rolling_time_delta_history.cc b/cc/base/rolling_time_delta_history.cc
index 0f95cc5..db04f58 100644
--- a/cc/base/rolling_time_delta_history.cc
+++ b/cc/base/rolling_time_delta_history.cc
@@ -26,10 +26,6 @@
   chronological_sample_deque_.push_back(it);
 }
 
-size_t RollingTimeDeltaHistory::SampleCount() {
-  return sample_set_.size();
-}
-
 void RollingTimeDeltaHistory::Clear() {
   chronological_sample_deque_.clear();
   sample_set_.clear();
diff --git a/cc/base/rolling_time_delta_history.h b/cc/base/rolling_time_delta_history.h
index 603c813..e51fb86 100644
--- a/cc/base/rolling_time_delta_history.h
+++ b/cc/base/rolling_time_delta_history.h
@@ -23,8 +23,6 @@
 
   void InsertSample(base::TimeDelta time);
 
-  size_t SampleCount();
-
   void Clear();
 
   // Returns the smallest sample that is greater than or equal to the specified
diff --git a/cc/blink/BUILD.gn b/cc/blink/BUILD.gn
index fac991b..138be59 100644
--- a/cc/blink/BUILD.gn
+++ b/cc/blink/BUILD.gn
@@ -33,6 +33,8 @@
     "web_compositor_support_impl.h",
     "web_content_layer_impl.cc",
     "web_content_layer_impl.h",
+    "web_display_item_list_impl.cc",
+    "web_display_item_list_impl.h",
     "web_external_bitmap_impl.cc",
     "web_external_bitmap_impl.h",
     "web_external_texture_layer_impl.cc",
diff --git a/cc/blink/cc_blink.gyp b/cc/blink/cc_blink.gyp
index d9f19ea..892082c 100644
--- a/cc/blink/cc_blink.gyp
+++ b/cc/blink/cc_blink.gyp
@@ -36,6 +36,8 @@
         'web_compositor_support_impl.h',
         'web_content_layer_impl.cc',
         'web_content_layer_impl.h',
+        'web_display_item_list_impl.cc',
+        'web_display_item_list_impl.h',
         'web_external_bitmap_impl.cc',
         'web_external_bitmap_impl.h',
         'web_external_texture_layer_impl.cc',
diff --git a/cc/blink/web_compositor_support_impl.cc b/cc/blink/web_compositor_support_impl.cc
index ae098fc..042908c 100644
--- a/cc/blink/web_compositor_support_impl.cc
+++ b/cc/blink/web_compositor_support_impl.cc
@@ -9,6 +9,7 @@
 #include "cc/animation/transform_operations.h"
 #include "cc/blink/web_animation_impl.h"
 #include "cc/blink/web_content_layer_impl.h"
+#include "cc/blink/web_display_item_list_impl.h"
 #include "cc/blink/web_external_texture_layer_impl.h"
 #include "cc/blink/web_filter_animation_curve_impl.h"
 #include "cc/blink/web_filter_operations_impl.h"
@@ -27,6 +28,9 @@
 using blink::WebCompositorAnimationCurve;
 using blink::WebContentLayer;
 using blink::WebContentLayerClient;
+#if WEB_DISPLAY_ITEM_LIST_IS_DEFINED
+using blink::WebDisplayItemList;
+#endif
 using blink::WebExternalTextureLayer;
 using blink::WebExternalTextureLayerClient;
 using blink::WebFilterAnimationCurve;
@@ -91,6 +95,12 @@
                                    is_left_side_vertical_scrollbar);
 }
 
+#if WEB_DISPLAY_ITEM_LIST_IS_DEFINED
+WebDisplayItemList* WebCompositorSupportImpl::createDisplayItemList() {
+  return new WebDisplayItemListImpl();
+}
+#endif
+
 WebCompositorAnimation* WebCompositorSupportImpl::createAnimation(
     const blink::WebCompositorAnimationCurve& curve,
     blink::WebCompositorAnimation::TargetProperty target,
diff --git a/cc/blink/web_compositor_support_impl.h b/cc/blink/web_compositor_support_impl.h
index 0f6371a..1c5198c 100644
--- a/cc/blink/web_compositor_support_impl.h
+++ b/cc/blink/web_compositor_support_impl.h
@@ -10,6 +10,7 @@
 #include "cc/blink/cc_blink_export.h"
 #include "third_party/WebKit/public/platform/WebCompositorAnimationCurve.h"
 #include "third_party/WebKit/public/platform/WebCompositorSupport.h"
+#include "third_party/WebKit/public/platform/WebContentLayerClient.h"
 #include "third_party/WebKit/public/platform/WebLayer.h"
 #include "third_party/WebKit/public/platform/WebTransformOperations.h"
 
@@ -41,6 +42,9 @@
       int thumb_thickness,
       int track_start,
       bool is_left_side_vertical_scrollbar);
+#if WEB_DISPLAY_ITEM_LIST_IS_DEFINED
+  virtual blink::WebDisplayItemList* createDisplayItemList();
+#endif
   virtual blink::WebCompositorAnimation* createAnimation(
       const blink::WebCompositorAnimationCurve& curve,
       blink::WebCompositorAnimation::TargetProperty target,
diff --git a/cc/blink/web_content_layer_impl.cc b/cc/blink/web_content_layer_impl.cc
index d0a4cca..9757ff3 100644
--- a/cc/blink/web_content_layer_impl.cc
+++ b/cc/blink/web_content_layer_impl.cc
@@ -4,6 +4,7 @@
 
 #include "cc/blink/web_content_layer_impl.h"
 
+#include "cc/blink/web_display_item_list_impl.h"
 #include "cc/layers/content_layer.h"
 #include "cc/layers/picture_layer.h"
 #include "third_party/WebKit/public/platform/WebContentLayerClient.h"
@@ -63,6 +64,25 @@
           : blink::WebContentLayerClient::GraphicsContextDisabled);
 }
 
+scoped_refptr<cc::DisplayItemList>
+WebContentLayerImpl::PaintContentsToDisplayList(
+    const gfx::Rect& clip,
+    ContentLayerClient::GraphicsContextStatus graphics_context_status) {
+  if (!client_)
+    return cc::DisplayItemList::Create();
+
+  WebDisplayItemListImpl list;
+#if WEB_DISPLAY_ITEM_LIST_IS_DEFINED
+  bool can_use_lcd_text = true;
+  client_->paintContents(
+      &list, clip, can_use_lcd_text,
+      graphics_context_status == ContentLayerClient::GRAPHICS_CONTEXT_ENABLED
+          ? blink::WebContentLayerClient::GraphicsContextEnabled
+          : blink::WebContentLayerClient::GraphicsContextDisabled);
+#endif
+  return list.ToDisplayItemList();
+}
+
 bool WebContentLayerImpl::FillsBoundsCompletely() const {
   return false;
 }
diff --git a/cc/blink/web_content_layer_impl.h b/cc/blink/web_content_layer_impl.h
index 2966bd4..148f4fc 100644
--- a/cc/blink/web_content_layer_impl.h
+++ b/cc/blink/web_content_layer_impl.h
@@ -40,6 +40,9 @@
                      const gfx::Rect& clip,
                      ContentLayerClient::GraphicsContextStatus
                          graphics_context_status) override;
+  scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList(
+      const gfx::Rect& clip,
+      GraphicsContextStatus graphics_context_status) override;
   bool FillsBoundsCompletely() const override;
 
   scoped_ptr<WebLayerImpl> layer_;
@@ -47,9 +50,6 @@
   bool draws_content_;
 
  private:
-  bool can_use_lcd_text_;
-  bool ignore_lcd_text_change_;
-
   DISALLOW_COPY_AND_ASSIGN(WebContentLayerImpl);
 };
 
diff --git a/cc/blink/web_display_item_list_impl.cc b/cc/blink/web_display_item_list_impl.cc
new file mode 100644
index 0000000..4ba3431
--- /dev/null
+++ b/cc/blink/web_display_item_list_impl.cc
@@ -0,0 +1,90 @@
+// Copyright 2014 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/blink/web_display_item_list_impl.h"
+
+#include <vector>
+
+#include "cc/blink/web_blend_mode.h"
+#include "cc/resources/clip_display_item.h"
+#include "cc/resources/drawing_display_item.h"
+#include "cc/resources/filter_display_item.h"
+#include "cc/resources/transform_display_item.h"
+#include "cc/resources/transparency_display_item.h"
+#include "skia/ext/refptr.h"
+#include "third_party/WebKit/public/platform/WebFloatRect.h"
+#include "third_party/WebKit/public/platform/WebRect.h"
+#include "third_party/skia/include/core/SkImageFilter.h"
+#include "third_party/skia/include/core/SkPicture.h"
+#include "third_party/skia/include/utils/SkMatrix44.h"
+#include "ui/gfx/transform.h"
+
+namespace cc_blink {
+
+WebDisplayItemListImpl::WebDisplayItemListImpl()
+    : display_item_list_(cc::DisplayItemList::Create()) {
+}
+
+scoped_refptr<cc::DisplayItemList> WebDisplayItemListImpl::ToDisplayItemList() {
+  return display_item_list_;
+}
+
+void WebDisplayItemListImpl::appendDrawingItem(
+    SkPicture* picture,
+    const blink::WebFloatPoint& location) {
+  display_item_list_->AppendItem(
+      cc::DrawingDisplayItem::Create(skia::SharePtr(picture), location));
+}
+
+void WebDisplayItemListImpl::appendClipItem(
+    const blink::WebRect& clip_rect,
+    const blink::WebVector<SkRRect>& rounded_clip_rects) {
+  std::vector<SkRRect> rounded_rects;
+  for (size_t i = 0; i < rounded_clip_rects.size(); ++i) {
+    rounded_rects.push_back(rounded_clip_rects[i]);
+  }
+  display_item_list_->AppendItem(
+      cc::ClipDisplayItem::Create(clip_rect, rounded_rects));
+}
+
+void WebDisplayItemListImpl::appendEndClipItem() {
+  display_item_list_->AppendItem(cc::EndClipDisplayItem::Create());
+}
+
+void WebDisplayItemListImpl::appendTransformItem(const SkMatrix44& matrix) {
+  gfx::Transform transform;
+  transform.matrix() = matrix;
+  display_item_list_->AppendItem(cc::TransformDisplayItem::Create(transform));
+}
+
+void WebDisplayItemListImpl::appendTransparencyItem(
+    float opacity,
+    blink::WebBlendMode blend_mode) {
+  display_item_list_->AppendItem(cc::TransparencyDisplayItem::Create(
+      opacity, BlendModeToSkia(blend_mode)));
+}
+
+void WebDisplayItemListImpl::appendEndTransformItem() {
+  display_item_list_->AppendItem(cc::EndTransformDisplayItem::Create());
+}
+
+void WebDisplayItemListImpl::appendEndTransparencyItem() {
+  display_item_list_->AppendItem(cc::EndTransparencyDisplayItem::Create());
+}
+
+void WebDisplayItemListImpl::appendFilterItem(
+    SkImageFilter* filter,
+    const blink::WebFloatRect& bounds) {
+  display_item_list_->AppendItem(
+      cc::FilterDisplayItem::Create(skia::SharePtr(filter), bounds));
+}
+
+void WebDisplayItemListImpl::appendEndFilterItem() {
+  display_item_list_->AppendItem(cc::EndFilterDisplayItem::Create());
+}
+
+WebDisplayItemListImpl::~WebDisplayItemListImpl() {
+}
+
+}  // namespace cc_blink
diff --git a/cc/blink/web_display_item_list_impl.h b/cc/blink/web_display_item_list_impl.h
new file mode 100644
index 0000000..4725498
--- /dev/null
+++ b/cc/blink/web_display_item_list_impl.h
@@ -0,0 +1,63 @@
+// Copyright 2014 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_BLINK_WEB_DISPLAY_ITEM_LIST_IMPL_H_
+#define CC_BLINK_WEB_DISPLAY_ITEM_LIST_IMPL_H_
+
+#include "base/memory/ref_counted.h"
+#include "cc/blink/cc_blink_export.h"
+#include "cc/resources/display_item_list.h"
+#include "third_party/WebKit/public/platform/WebBlendMode.h"
+#include "third_party/WebKit/public/platform/WebContentLayerClient.h"
+#include "third_party/WebKit/public/platform/WebFloatPoint.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+
+#if WEB_DISPLAY_ITEM_LIST_IS_DEFINED
+#include "third_party/WebKit/public/platform/WebDisplayItemList.h"
+#endif
+
+class SkImageFilter;
+class SkMatrix44;
+class SkPicture;
+class SkRRect;
+
+namespace cc_blink {
+
+#if WEB_DISPLAY_ITEM_LIST_IS_DEFINED
+class WebDisplayItemListImpl : public blink::WebDisplayItemList {
+#else
+class WebDisplayItemListImpl {
+#endif
+
+ public:
+  CC_BLINK_EXPORT WebDisplayItemListImpl();
+  virtual ~WebDisplayItemListImpl();
+
+  scoped_refptr<cc::DisplayItemList> ToDisplayItemList();
+
+  // blink::WebDisplayItemList implementation.
+  virtual void appendDrawingItem(SkPicture* picture,
+                                 const blink::WebFloatPoint& location);
+  virtual void appendClipItem(
+      const blink::WebRect& clip_rect,
+      const blink::WebVector<SkRRect>& rounded_clip_rects);
+  virtual void appendEndClipItem();
+  virtual void appendTransformItem(const SkMatrix44& matrix);
+  virtual void appendEndTransformItem();
+  virtual void appendTransparencyItem(float opacity,
+                                      blink::WebBlendMode blend_mode);
+  virtual void appendEndTransparencyItem();
+  virtual void appendFilterItem(SkImageFilter* filter,
+                                const blink::WebFloatRect& bounds);
+  virtual void appendEndFilterItem();
+
+ private:
+  scoped_refptr<cc::DisplayItemList> display_item_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebDisplayItemListImpl);
+};
+
+}  // namespace cc_blink
+
+#endif  // CC_BLINK_WEB_DISPLAY_ITEM_LIST_IMPL_H_
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 046d43c..3374251 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -358,10 +358,24 @@
         'resources/bitmap_raster_worker_pool.h',
         'resources/bitmap_skpicture_content_layer_updater.cc',
         'resources/bitmap_skpicture_content_layer_updater.h',
+        'resources/clip_display_item.cc',
+        'resources/clip_display_item.h',
         'resources/content_layer_updater.cc',
         'resources/content_layer_updater.h',
+        'resources/display_item.cc',
+        'resources/display_item.h',
+        'resources/display_item_list.cc',
+        'resources/display_item_list.h',
+        'resources/display_list_raster_source.cc',
+        'resources/display_list_raster_source.h',
+        'resources/display_list_recording_source.cc',
+        'resources/display_list_recording_source.h',
+        'resources/drawing_display_item.cc',
+        'resources/drawing_display_item.h',
         'resources/eviction_tile_priority_queue.cc',
         'resources/eviction_tile_priority_queue.h',
+        'resources/filter_display_item.cc',
+        'resources/filter_display_item.h',
         'resources/gpu_raster_worker_pool.cc',
         'resources/gpu_raster_worker_pool.h',
         'resources/image_layer_updater.cc',
@@ -401,6 +415,8 @@
         'resources/raster_buffer.cc',
         'resources/raster_buffer.h',
         'resources/raster_source.h',
+        'resources/raster_source_helper.cc',
+        'resources/raster_source_helper.h',
         'resources/raster_tile_priority_queue.cc',
         'resources/raster_tile_priority_queue.h',
         'resources/raster_worker_pool.cc',
@@ -453,8 +469,14 @@
         'resources/tile_manager.h',
         'resources/tile_priority.cc',
         'resources/tile_priority.h',
+        'resources/tiling_set_eviction_queue.cc',
+        'resources/tiling_set_eviction_queue.h',
         'resources/transferable_resource.cc',
         'resources/transferable_resource.h',
+        'resources/transform_display_item.cc',
+        'resources/transform_display_item.h',
+        'resources/transparency_display_item.cc',
+        'resources/transparency_display_item.h',
         'resources/ui_resource_bitmap.cc',
         'resources/ui_resource_bitmap.h',
         'resources/ui_resource_client.h',
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index d4a031f..d0b1000 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -74,6 +74,7 @@
       'quads/draw_quad_unittest.cc',
       'quads/list_container_unittest.cc',
       'quads/render_pass_unittest.cc',
+      'resources/display_item_list_unittest.cc',
       'resources/layer_quad_unittest.cc',
       'resources/picture_layer_tiling_set_unittest.cc',
       'resources/picture_layer_tiling_unittest.cc',
diff --git a/cc/debug/rasterize_and_record_benchmark.cc b/cc/debug/rasterize_and_record_benchmark.cc
index a2052ab..41d6210 100644
--- a/cc/debug/rasterize_and_record_benchmark.cc
+++ b/cc/debug/rasterize_and_record_benchmark.cc
@@ -18,6 +18,7 @@
 #include "cc/resources/picture_pile.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_host_common.h"
+#include "third_party/skia/include/utils/SkPictureUtils.h"
 #include "ui/gfx/geometry/rect.h"
 
 namespace cc {
@@ -64,6 +65,7 @@
   DCHECK(!results_.get());
   results_ = make_scoped_ptr(new base::DictionaryValue);
   results_->SetInteger("pixels_recorded", record_results_.pixels_recorded);
+  results_->SetInteger("picture_memory_usage", record_results_.bytes_used);
 
   for (int i = 0; i < Picture::RECORDING_MODE_COUNT; i++) {
     std::string name = base::StringPrintf("record_time%s_ms", kModeSuffixes[i]);
@@ -119,6 +121,7 @@
     Picture::RecordingMode mode =
         static_cast<Picture::RecordingMode>(mode_index);
     base::TimeDelta min_time = base::TimeDelta::Max();
+    size_t memory_used = 0;
 
     // Parameters for LapTimer.
     const int kTimeLimitMillis = 1;
@@ -131,18 +134,21 @@
       LapTimer timer(kWarmupRuns,
                      base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
                      kTimeCheckInterval);
+      scoped_refptr<Picture> picture;
       do {
-        scoped_refptr<Picture> picture = Picture::Create(
-            visible_content_rect, painter, tile_grid_info, false, mode);
+        picture = Picture::Create(visible_content_rect, painter, tile_grid_info,
+                                  false, mode);
         timer.NextLap();
       } while (!timer.HasTimeLimitExpired());
       base::TimeDelta duration =
           base::TimeDelta::FromMillisecondsD(timer.MsPerLap());
       if (duration < min_time)
         min_time = duration;
+      memory_used = picture->ApproximateMemoryUsage();
     }
 
     if (mode == Picture::RECORD_NORMALLY) {
+      record_results_.bytes_used += memory_used;
       record_results_.pixels_recorded +=
           visible_content_rect.width() * visible_content_rect.height();
     }
@@ -151,7 +157,8 @@
 }
 
 RasterizeAndRecordBenchmark::RecordResults::RecordResults()
-    : pixels_recorded(0) {}
+    : pixels_recorded(0), bytes_used(0) {
+}
 
 RasterizeAndRecordBenchmark::RecordResults::~RecordResults() {}
 
diff --git a/cc/debug/rasterize_and_record_benchmark.h b/cc/debug/rasterize_and_record_benchmark.h
index 68d5d05..8a23292 100644
--- a/cc/debug/rasterize_and_record_benchmark.h
+++ b/cc/debug/rasterize_and_record_benchmark.h
@@ -46,6 +46,7 @@
     ~RecordResults();
 
     int pixels_recorded;
+    size_t bytes_used;
     base::TimeDelta total_best_time[Picture::RECORDING_MODE_COUNT];
   };
 
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.cc b/cc/debug/rasterize_and_record_benchmark_impl.cc
index e276a41..c1fc809 100644
--- a/cc/debug/rasterize_and_record_benchmark_impl.cc
+++ b/cc/debug/rasterize_and_record_benchmark_impl.cc
@@ -173,6 +173,8 @@
   scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
   result->SetDouble("rasterize_time_ms",
                     rasterize_results_.total_best_time.InMillisecondsF());
+  result->SetDouble("total_pictures_in_pile_size",
+                    rasterize_results_.total_memory_usage);
   result->SetInteger("pixels_rasterized", rasterize_results_.pixels_rasterized);
   result->SetInteger("pixels_rasterized_with_non_solid_color",
                      rasterize_results_.pixels_rasterized_with_non_solid_color);
@@ -263,16 +265,22 @@
     rasterize_results_.pixels_rasterized += tile_size;
     rasterize_results_.total_best_time += min_time;
   }
+
+  const RasterSource* layer_raster_source = layer->GetRasterSource();
+  rasterize_results_.total_memory_usage +=
+      layer_raster_source->GetPictureMemoryUsage();
 }
 
 RasterizeAndRecordBenchmarkImpl::RasterizeResults::RasterizeResults()
     : pixels_rasterized(0),
       pixels_rasterized_with_non_solid_color(0),
       pixels_rasterized_as_opaque(0),
+      total_memory_usage(0),
       total_layers(0),
       total_picture_layers(0),
       total_picture_layers_with_no_content(0),
-      total_picture_layers_off_screen(0) {}
+      total_picture_layers_off_screen(0) {
+}
 
 RasterizeAndRecordBenchmarkImpl::RasterizeResults::~RasterizeResults() {}
 
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.h b/cc/debug/rasterize_and_record_benchmark_impl.h
index c0f26fd..7ca471a 100644
--- a/cc/debug/rasterize_and_record_benchmark_impl.h
+++ b/cc/debug/rasterize_and_record_benchmark_impl.h
@@ -41,6 +41,7 @@
     int pixels_rasterized_with_non_solid_color;
     int pixels_rasterized_as_opaque;
     base::TimeDelta total_best_time;
+    int total_memory_usage;
     int total_layers;
     int total_picture_layers;
     int total_picture_layers_with_no_content;
diff --git a/cc/layers/content_layer_client.h b/cc/layers/content_layer_client.h
index ea22e97..c8d3a7e 100644
--- a/cc/layers/content_layer_client.h
+++ b/cc/layers/content_layer_client.h
@@ -6,6 +6,7 @@
 #define CC_LAYERS_CONTENT_LAYER_CLIENT_H_
 
 #include "cc/base/cc_export.h"
+#include "cc/resources/display_item_list.h"
 
 class SkCanvas;
 
@@ -27,6 +28,10 @@
                              const gfx::Rect& clip,
                              GraphicsContextStatus gc_status) = 0;
 
+  virtual scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+      const gfx::Rect& clip,
+      GraphicsContextStatus gc_status) = 0;
+
   // If true the layer may skip clearing the background before rasterizing,
   // because it will cover any uncleared data with content.
   virtual bool FillsBoundsCompletely() const = 0;
diff --git a/cc/layers/picture_image_layer.cc b/cc/layers/picture_image_layer.cc
index dba506e..5d76618 100644
--- a/cc/layers/picture_image_layer.cc
+++ b/cc/layers/picture_image_layer.cc
@@ -60,6 +60,13 @@
   canvas->drawBitmap(bitmap_, 0, 0);
 }
 
+scoped_refptr<DisplayItemList> PictureImageLayer::PaintContentsToDisplayList(
+    const gfx::Rect& clip,
+    GraphicsContextStatus gc_status) {
+  NOTIMPLEMENTED();
+  return DisplayItemList::Create();
+}
+
 bool PictureImageLayer::FillsBoundsCompletely() const {
   return false;
 }
diff --git a/cc/layers/picture_image_layer.h b/cc/layers/picture_image_layer.h
index 3f8d68d..57c7de2 100644
--- a/cc/layers/picture_image_layer.h
+++ b/cc/layers/picture_image_layer.h
@@ -27,6 +27,9 @@
       SkCanvas* canvas,
       const gfx::Rect& clip,
       ContentLayerClient::GraphicsContextStatus gc_status) override;
+  scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+      const gfx::Rect& clip,
+      GraphicsContextStatus gc_status) override;
   bool FillsBoundsCompletely() const override;
 
  protected:
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc
index d734538..55241d0 100644
--- a/cc/layers/picture_layer.cc
+++ b/cc/layers/picture_layer.cc
@@ -7,6 +7,7 @@
 #include "base/auto_reset.h"
 #include "cc/layers/content_layer_client.h"
 #include "cc/layers/picture_layer_impl.h"
+#include "cc/resources/display_list_recording_source.h"
 #include "cc/resources/picture_pile.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "third_party/skia/include/core/SkPictureRecorder.h"
@@ -20,7 +21,6 @@
 
 PictureLayer::PictureLayer(ContentLayerClient* client)
     : client_(client),
-      recording_source_(new PicturePile),
       instrumentation_object_tracker_(id()),
       update_source_frame_number_(-1),
       can_use_lcd_text_for_update_(true),
@@ -79,6 +79,13 @@
 void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
   Layer::SetLayerTreeHost(host);
   if (host) {
+    if (!recording_source_) {
+      if (host->settings().use_display_lists) {
+        recording_source_.reset(new DisplayListRecordingSource);
+      } else {
+        recording_source_.reset(new PicturePile);
+      }
+    }
     recording_source_->SetMinContentsScale(
         host->settings().minimum_contents_scale);
     recording_source_->SetTileGridSize(host->settings().default_tile_grid_size);
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 0eb9621..1827bea 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -98,6 +98,14 @@
   layer_tree_impl()->UnregisterPictureLayerImpl(this);
 }
 
+scoped_ptr<TilingSetEvictionQueue> PictureLayerImpl::CreateEvictionQueue(
+    TreePriority tree_priority) {
+  if (!tilings_)
+    return make_scoped_ptr(new TilingSetEvictionQueue());
+  return make_scoped_ptr(
+      new TilingSetEvictionQueue(tilings_.get(), tree_priority));
+}
+
 const char* PictureLayerImpl::LayerTypeAsString() const {
   return "cc::PictureLayerImpl";
 }
@@ -1475,158 +1483,4 @@
   }
 }
 
-PictureLayerImpl::LayerEvictionTileIterator::LayerEvictionTileIterator()
-    : layer_(nullptr),
-      tree_priority_(SAME_PRIORITY_FOR_BOTH_TREES),
-      current_category_(PictureLayerTiling::EVENTUALLY),
-      current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
-      current_tiling_(0u) {
-}
-
-PictureLayerImpl::LayerEvictionTileIterator::LayerEvictionTileIterator(
-    PictureLayerImpl* layer,
-    TreePriority tree_priority)
-    : layer_(layer),
-      tree_priority_(tree_priority),
-      current_category_(PictureLayerTiling::EVENTUALLY),
-      current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
-      current_tiling_(0u) {
-  // Early out if the layer has no tilings.
-  if (!layer_->tilings_ || !layer_->tilings_->num_tilings())
-    return;
-
-  current_tiling_ = CurrentTilingRange().start - 1u;
-  do {
-    if (!AdvanceToNextTiling())
-      break;
-
-    current_iterator_ = PictureLayerTiling::TilingEvictionTileIterator(
-        layer_->tilings_->tiling_at(CurrentTilingIndex()),
-        tree_priority,
-        current_category_);
-  } while (!current_iterator_);
-}
-
-PictureLayerImpl::LayerEvictionTileIterator::~LayerEvictionTileIterator() {
-}
-
-Tile* PictureLayerImpl::LayerEvictionTileIterator::operator*() {
-  DCHECK(*this);
-  return *current_iterator_;
-}
-
-const Tile* PictureLayerImpl::LayerEvictionTileIterator::operator*() const {
-  DCHECK(*this);
-  return *current_iterator_;
-}
-
-PictureLayerImpl::LayerEvictionTileIterator&
-PictureLayerImpl::LayerEvictionTileIterator::
-operator++() {
-  DCHECK(*this);
-  ++current_iterator_;
-  while (!current_iterator_) {
-    if (!AdvanceToNextTiling())
-      break;
-
-    current_iterator_ = PictureLayerTiling::TilingEvictionTileIterator(
-        layer_->tilings_->tiling_at(CurrentTilingIndex()),
-        tree_priority_,
-        current_category_);
-  }
-  return *this;
-}
-
-PictureLayerImpl::LayerEvictionTileIterator::operator bool() const {
-  return !!current_iterator_;
-}
-
-bool PictureLayerImpl::LayerEvictionTileIterator::AdvanceToNextCategory() {
-  switch (current_category_) {
-    case PictureLayerTiling::EVENTUALLY:
-      current_category_ =
-          PictureLayerTiling::EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION;
-      return true;
-    case PictureLayerTiling::EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION:
-      current_category_ = PictureLayerTiling::SOON;
-      return true;
-    case PictureLayerTiling::SOON:
-      current_category_ = PictureLayerTiling::SOON_AND_REQUIRED_FOR_ACTIVATION;
-      return true;
-    case PictureLayerTiling::SOON_AND_REQUIRED_FOR_ACTIVATION:
-      current_category_ = PictureLayerTiling::NOW;
-      return true;
-    case PictureLayerTiling::NOW:
-      current_category_ = PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION;
-      return true;
-    case PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION:
-      return false;
-  }
-  NOTREACHED();
-  return false;
-}
-
-bool
-PictureLayerImpl::LayerEvictionTileIterator::AdvanceToNextTilingRangeType() {
-  switch (current_tiling_range_type_) {
-    case PictureLayerTilingSet::HIGHER_THAN_HIGH_RES:
-      current_tiling_range_type_ = PictureLayerTilingSet::LOWER_THAN_LOW_RES;
-      return true;
-    case PictureLayerTilingSet::LOWER_THAN_LOW_RES:
-      current_tiling_range_type_ =
-          PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES;
-      return true;
-    case PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES:
-      current_tiling_range_type_ = PictureLayerTilingSet::LOW_RES;
-      return true;
-    case PictureLayerTilingSet::LOW_RES:
-      current_tiling_range_type_ = PictureLayerTilingSet::HIGH_RES;
-      return true;
-    case PictureLayerTilingSet::HIGH_RES:
-      if (!AdvanceToNextCategory())
-        return false;
-
-      current_tiling_range_type_ = PictureLayerTilingSet::HIGHER_THAN_HIGH_RES;
-      return true;
-  }
-  NOTREACHED();
-  return false;
-}
-
-bool PictureLayerImpl::LayerEvictionTileIterator::AdvanceToNextTiling() {
-  DCHECK_NE(current_tiling_, CurrentTilingRange().end);
-  ++current_tiling_;
-  while (current_tiling_ == CurrentTilingRange().end) {
-    if (!AdvanceToNextTilingRangeType())
-      return false;
-
-    current_tiling_ = CurrentTilingRange().start;
-  }
-  return true;
-}
-
-PictureLayerTilingSet::TilingRange
-PictureLayerImpl::LayerEvictionTileIterator::CurrentTilingRange() const {
-  return layer_->tilings_->GetTilingRange(current_tiling_range_type_);
-}
-
-size_t PictureLayerImpl::LayerEvictionTileIterator::CurrentTilingIndex() const {
-  DCHECK_NE(current_tiling_, CurrentTilingRange().end);
-  switch (current_tiling_range_type_) {
-    case PictureLayerTilingSet::HIGHER_THAN_HIGH_RES:
-    case PictureLayerTilingSet::LOW_RES:
-    case PictureLayerTilingSet::HIGH_RES:
-      return current_tiling_;
-    // Tilings in the following ranges are accessed in reverse order.
-    case PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES:
-    case PictureLayerTilingSet::LOWER_THAN_LOW_RES: {
-      PictureLayerTilingSet::TilingRange tiling_range = CurrentTilingRange();
-      size_t current_tiling_range_offset = current_tiling_ - tiling_range.start;
-      return tiling_range.end - 1 - current_tiling_range_offset;
-    }
-  }
-  NOTREACHED();
-  return 0;
-}
-
 }  // namespace cc
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h
index 9a77546..52d8433 100644
--- a/cc/layers/picture_layer_impl.h
+++ b/cc/layers/picture_layer_impl.h
@@ -15,6 +15,7 @@
 #include "cc/resources/picture_layer_tiling.h"
 #include "cc/resources/picture_layer_tiling_set.h"
 #include "cc/resources/picture_pile_impl.h"
+#include "cc/resources/tiling_set_eviction_queue.h"
 #include "skia/ext/refptr.h"
 #include "third_party/skia/include/core/SkPicture.h"
 
@@ -67,40 +68,14 @@
     PictureLayerTiling::TilingRasterTileIterator iterators_[NUM_ITERATORS];
   };
 
-  class CC_EXPORT LayerEvictionTileIterator {
-   public:
-    LayerEvictionTileIterator();
-    LayerEvictionTileIterator(PictureLayerImpl* layer,
-                              TreePriority tree_priority);
-    ~LayerEvictionTileIterator();
-
-    Tile* operator*();
-    const Tile* operator*() const;
-    LayerEvictionTileIterator& operator++();
-    operator bool() const;
-
-   private:
-    bool AdvanceToNextCategory();
-    bool AdvanceToNextTilingRangeType();
-    bool AdvanceToNextTiling();
-
-    PictureLayerTilingSet::TilingRange CurrentTilingRange() const;
-    size_t CurrentTilingIndex() const;
-
-    PictureLayerImpl* layer_;
-    TreePriority tree_priority_;
-
-    PictureLayerTiling::EvictionCategory current_category_;
-    PictureLayerTilingSet::TilingRangeType current_tiling_range_type_;
-    size_t current_tiling_;
-    PictureLayerTiling::TilingEvictionTileIterator current_iterator_;
-  };
-
   static scoped_ptr<PictureLayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
     return make_scoped_ptr(new PictureLayerImpl(tree_impl, id));
   }
   ~PictureLayerImpl() override;
 
+  scoped_ptr<TilingSetEvictionQueue> CreateEvictionQueue(
+      TreePriority tree_priority);
+
   // LayerImpl overrides.
   const char* LayerTypeAsString() const override;
   scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
@@ -154,6 +129,9 @@
   bool AllTilesRequiredForActivationAreReadyToDraw() const;
   bool AllTilesRequiredForDrawAreReadyToDraw() const;
 
+  // Used for benchmarking
+  const RasterSource* GetRasterSource() const { return raster_source_.get(); }
+
  protected:
   friend class LayerRasterTileIterator;
   using TileRequirementCheck = bool (PictureLayerTiling::*)(const Tile*) const;
diff --git a/cc/layers/picture_layer_impl_perftest.cc b/cc/layers/picture_layer_impl_perftest.cc
index 1f98a68..bfb5703 100644
--- a/cc/layers/picture_layer_impl_perftest.cc
+++ b/cc/layers/picture_layer_impl_perftest.cc
@@ -115,7 +115,7 @@
                            true);
   }
 
-  void RunEvictionIteratorConstructAndIterateTest(
+  void RunEvictionQueueConstructAndIterateTest(
       const std::string& test_name,
       int num_tiles,
       const gfx::Size& viewport_size) {
@@ -129,12 +129,12 @@
     timer_.Reset();
     do {
       int count = num_tiles;
-      PictureLayerImpl::LayerEvictionTileIterator it(
-          pending_layer_, priorities[priority_count]);
+      scoped_ptr<TilingSetEvictionQueue> queue =
+          pending_layer_->CreateEvictionQueue(priorities[priority_count]);
       while (count--) {
-        ASSERT_TRUE(it) << "count: " << count;
-        ASSERT_TRUE(*it != nullptr) << "count: " << count;
-        ++it;
+        ASSERT_TRUE(!queue->IsEmpty()) << "count: " << count;
+        ASSERT_TRUE(queue->Top() != nullptr) << "count: " << count;
+        queue->Pop();
       }
       priority_count = (priority_count + 1) % arraysize(priorities);
       timer_.NextLap();
@@ -148,8 +148,8 @@
                            true);
   }
 
-  void RunEvictionIteratorConstructTest(const std::string& test_name,
-                                        const gfx::Rect& viewport) {
+  void RunEvictionQueueConstructTest(const std::string& test_name,
+                                     const gfx::Rect& viewport) {
     host_impl_.SetViewportSize(viewport.size());
     pending_layer_->SetScrollOffset(
         gfx::ScrollOffset(viewport.x(), viewport.y()));
@@ -161,8 +161,8 @@
     int priority_count = 0;
     timer_.Reset();
     do {
-      PictureLayerImpl::LayerEvictionTileIterator it(
-          pending_layer_, priorities[priority_count]);
+      scoped_ptr<TilingSetEvictionQueue> queue =
+          pending_layer_->CreateEvictionQueue(priorities[priority_count]);
       priority_count = (priority_count + 1) % arraysize(priorities);
       timer_.NextLap();
     } while (!timer_.HasTimeLimitExpired());
@@ -225,6 +225,7 @@
                                  gfx::Rect(9999, 0, 100, 100));
 }
 
+// TODO(e_hakkinen): Rename these tests once the perf numbers are in.
 TEST_F(PictureLayerImplPerfTest, LayerEvictionTileIteratorConstructAndIterate) {
   SetupPendingTree(gfx::Size(10000, 10000), gfx::Size(256, 256));
 
@@ -240,16 +241,17 @@
   ASSERT_TRUE(host_impl_.tile_manager() != nullptr);
   host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
 
-  RunEvictionIteratorConstructAndIterateTest(
+  RunEvictionQueueConstructAndIterateTest(
       "32_100x100", 32, gfx::Size(100, 100));
-  RunEvictionIteratorConstructAndIterateTest(
+  RunEvictionQueueConstructAndIterateTest(
       "32_500x500", 32, gfx::Size(500, 500));
-  RunEvictionIteratorConstructAndIterateTest(
+  RunEvictionQueueConstructAndIterateTest(
       "64_100x100", 64, gfx::Size(100, 100));
-  RunEvictionIteratorConstructAndIterateTest(
+  RunEvictionQueueConstructAndIterateTest(
       "64_500x500", 64, gfx::Size(500, 500));
 }
 
+// TODO(e_hakkinen): Rename these tests once the perf numbers are in.
 TEST_F(PictureLayerImplPerfTest, LayerEvictionTileIteratorConstruct) {
   SetupPendingTree(gfx::Size(10000, 10000), gfx::Size(256, 256));
 
@@ -265,11 +267,9 @@
   ASSERT_TRUE(host_impl_.tile_manager() != nullptr);
   host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
 
-  RunEvictionIteratorConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100));
-  RunEvictionIteratorConstructTest("5000_0_100x100",
-                                   gfx::Rect(5000, 0, 100, 100));
-  RunEvictionIteratorConstructTest("9999_0_100x100",
-                                   gfx::Rect(9999, 0, 100, 100));
+  RunEvictionQueueConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100));
+  RunEvictionQueueConstructTest("5000_0_100x100", gfx::Rect(5000, 0, 100, 100));
+  RunEvictionQueueConstructTest("9999_0_100x100", gfx::Rect(9999, 0, 100, 100));
 }
 
 }  // namespace
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index 246e625..ce66675 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -330,7 +330,7 @@
   base::TimeTicks time_ticks;
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(400, 400);
 
@@ -347,7 +347,7 @@
 
   time_ticks += base::TimeDelta::FromMilliseconds(200);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
   // Update tiles with viewport for tile priority as (0, 0, 100, 100) and the
   // identify transform for tile priority.
@@ -385,7 +385,7 @@
   // should be (200, 200, 100, 100) applied with the said transform.
   time_ticks += base::TimeDelta::FromMilliseconds(200);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
   viewport_rect_for_tile_priority = gfx::Rect(200, 200, 100, 100);
   transform_for_tile_priority.Translate(100, 100);
@@ -426,7 +426,7 @@
   base::TimeTicks time_ticks;
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(400, 400);
@@ -468,7 +468,7 @@
   // Should update viewport and transform, but not update visible rect.
   time_ticks += base::TimeDelta::FromMilliseconds(200);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
   resourceless_software_draw = true;
   viewport = gfx::ScaleToEnclosingRect(viewport, 2);
   transform.Translate(1.f, 1.f);
@@ -492,7 +492,7 @@
   // Keep expanded viewport but mark it valid. Should update tile viewport.
   time_ticks += base::TimeDelta::FromMilliseconds(200);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
   resourceless_software_draw = false;
   host_impl_.SetExternalDrawConstraints(transform,
                                         viewport,
@@ -1561,7 +1561,7 @@
   base::TimeTicks time_ticks;
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
   pending_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
   EXPECT_EQ(HIGH_RESOLUTION, tiling->resolution());
 
@@ -1589,7 +1589,7 @@
   base::TimeTicks time_ticks;
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(400, 400);
@@ -1625,7 +1625,7 @@
   pending_layer_->draw_properties().visible_content_rect = visible_content_rect;
   time_ticks += base::TimeDelta::FromMilliseconds(200);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
   pending_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
 
   // Intersect the two rects. Any tile outside should not be required for
@@ -1678,7 +1678,7 @@
   base::TimeTicks time_ticks;
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(200, 200);
@@ -1714,7 +1714,7 @@
   base::TimeTicks time_ticks;
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(200, 200);
@@ -1745,7 +1745,7 @@
   base::TimeTicks time_ticks;
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(200, 200);
@@ -1779,7 +1779,7 @@
   base::TimeTicks time_ticks;
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(200, 200);
@@ -1822,7 +1822,7 @@
   base::TimeTicks time_ticks;
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(200, 200);
@@ -1890,6 +1890,9 @@
 TEST_F(PictureLayerImplTest, HighResRequiredWhenUnsharedActiveAllReady) {
   gfx::Size layer_bounds(400, 400);
   gfx::Size tile_size(100, 100);
+
+  host_impl_.SetViewportSize(layer_bounds);
+
   SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
 
   // No tiles shared.
@@ -1911,6 +1914,9 @@
 TEST_F(PictureLayerImplTest, HighResRequiredWhenMissingHighResFlagOn) {
   gfx::Size layer_bounds(400, 400);
   gfx::Size tile_size(100, 100);
+
+  host_impl_.SetViewportSize(layer_bounds);
+
   SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
 
   // All tiles shared (no invalidation).
@@ -1935,6 +1941,9 @@
 TEST_F(PictureLayerImplTest, AllHighResRequiredEvenIfShared) {
   gfx::Size layer_bounds(400, 400);
   gfx::Size tile_size(100, 100);
+
+  host_impl_.SetViewportSize(layer_bounds);
+
   SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
 
   CreateHighLowResAndSetAllTilesVisible();
@@ -2009,6 +2018,9 @@
 TEST_F(PictureLayerImplTest, HighResRequiredIfActiveCantHaveTiles) {
   gfx::Size layer_bounds(400, 400);
   gfx::Size tile_size(100, 100);
+
+  host_impl_.SetViewportSize(layer_bounds);
+
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
   scoped_refptr<FakePicturePileImpl> active_pile =
@@ -2767,7 +2779,7 @@
   base::TimeTicks time_ticks;
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(1000, 1000);
@@ -2837,7 +2849,7 @@
   // No NOW tiles.
   time_ticks += base::TimeDelta::FromMilliseconds(200);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
   pending_layer_->draw_properties().visible_content_rect =
       gfx::Rect(1100, 1100, 500, 500);
@@ -2868,7 +2880,7 @@
 
   time_ticks += base::TimeDelta::FromMilliseconds(200);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
   pending_layer_->draw_properties().visible_content_rect =
       gfx::Rect(0, 0, 500, 500);
@@ -2903,7 +2915,7 @@
   EXPECT_EQ(0u, high_res_tile_count);
 }
 
-TEST_F(PictureLayerImplTest, LayerEvictionTileIterator) {
+TEST_F(PictureLayerImplTest, TilingSetEvictionQueue) {
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(1000, 1000);
 
@@ -2964,14 +2976,10 @@
   EXPECT_GT(number_of_marked_tiles, 1u);
   EXPECT_GT(number_of_unmarked_tiles, 1u);
 
-  // Empty iterator.
-  PictureLayerImpl::LayerEvictionTileIterator it;
-  EXPECT_FALSE(it);
-
   // Tiles don't have resources yet.
-  it = PictureLayerImpl::LayerEvictionTileIterator(
-      pending_layer_, SAME_PRIORITY_FOR_BOTH_TREES);
-  EXPECT_FALSE(it);
+  scoped_ptr<TilingSetEvictionQueue> queue =
+      pending_layer_->CreateEvictionQueue(SAME_PRIORITY_FOR_BOTH_TREES);
+  EXPECT_TRUE(queue->IsEmpty());
 
   host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
 
@@ -2980,11 +2988,9 @@
   size_t scale_index = 0;
   bool reached_visible = false;
   Tile* last_tile = nullptr;
-  for (it = PictureLayerImpl::LayerEvictionTileIterator(
-           pending_layer_, SAME_PRIORITY_FOR_BOTH_TREES);
-       it;
-       ++it) {
-    Tile* tile = *it;
+  queue = pending_layer_->CreateEvictionQueue(SAME_PRIORITY_FOR_BOTH_TREES);
+  while (!queue->IsEmpty()) {
+    Tile* tile = queue->Top();
     if (!last_tile)
       last_tile = tile;
 
@@ -3022,6 +3028,7 @@
     }
 
     last_tile = tile;
+    queue->Pop();
   }
 
   EXPECT_TRUE(reached_visible);
@@ -3029,8 +3036,8 @@
 
   scale_index = 0;
   bool reached_required = false;
-  for (; it; ++it) {
-    Tile* tile = *it;
+  while (!queue->IsEmpty()) {
+    Tile* tile = queue->Top();
     EXPECT_TRUE(tile);
 
     TilePriority priority = tile->priority(PENDING_TREE);
@@ -3051,6 +3058,7 @@
 
     EXPECT_FLOAT_EQ(tile->contents_scale(), expected_scales[scale_index]);
     unique_tiles.insert(tile);
+    queue->Pop();
   }
 
   EXPECT_TRUE(reached_required);
@@ -3155,6 +3163,8 @@
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(1000, 1000);
 
+  host_impl_.SetViewportSize(layer_bounds);
+
   SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
 
   // Make sure some tiles are not shared.
@@ -3182,6 +3192,8 @@
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(1000, 1000);
 
+  host_impl_.SetViewportSize(layer_bounds);
+
   SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
 
   // Make sure some tiles are not shared.
@@ -3205,6 +3217,8 @@
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(1000, 1000);
 
+  host_impl_.SetViewportSize(layer_bounds);
+
   SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
 
   // Make sure some tiles are not shared.
@@ -3229,6 +3243,8 @@
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(1000, 1000);
 
+  host_impl_.SetViewportSize(layer_bounds);
+
   SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
 
   // Make sure some tiles are not shared.
@@ -3316,6 +3332,9 @@
 TEST_F(NoLowResPictureLayerImplTest, AllHighResRequiredEvenIfShared) {
   gfx::Size layer_bounds(400, 400);
   gfx::Size tile_size(100, 100);
+
+  host_impl_.SetViewportSize(layer_bounds);
+
   SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
 
   CreateHighLowResAndSetAllTilesVisible();
@@ -3374,7 +3393,7 @@
   base::TimeTicks time_ticks;
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(400, 400);
@@ -3416,7 +3435,7 @@
   // Should update viewport and transform, but not update visible rect.
   time_ticks += base::TimeDelta::FromMilliseconds(200);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
   resourceless_software_draw = true;
   viewport = gfx::ScaleToEnclosingRect(viewport, 2);
   transform.Translate(1.f, 1.f);
@@ -3440,7 +3459,7 @@
   // Keep expanded viewport but mark it valid. Should update tile viewport.
   time_ticks += base::TimeDelta::FromMilliseconds(200);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
   resourceless_software_draw = false;
   host_impl_.SetExternalDrawConstraints(transform,
                                         viewport,
@@ -3677,6 +3696,8 @@
   gfx::Size tile_size(400, 400);
   gfx::Size layer_bounds(1000, 2000);
 
+  host_impl_.SetViewportSize(layer_bounds);
+
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
   scoped_refptr<FakePicturePileImpl> active_pile =
@@ -3841,12 +3862,10 @@
       size_t occluded_tile_count = 0u;
       Tile* last_tile = nullptr;
 
-      for (PictureLayerImpl::LayerEvictionTileIterator it =
-               PictureLayerImpl::LayerEvictionTileIterator(layer,
-                                                           tree_priority);
-           it;
-           ++it) {
-        Tile* tile = *it;
+      scoped_ptr<TilingSetEvictionQueue> queue =
+          layer->CreateEvictionQueue(tree_priority);
+      while (!queue->IsEmpty()) {
+        Tile* tile = queue->Top();
         if (!last_tile)
           last_tile = tile;
 
@@ -3874,6 +3893,7 @@
           }
         }
         last_tile = tile;
+        queue->Pop();
       }
       EXPECT_EQ(expected_occluded_tile_count[priority_count],
                 occluded_tile_count);
@@ -3886,7 +3906,7 @@
   base::TimeTicks time_ticks;
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
   gfx::Size tile_size(102, 102);
   gfx::Size layer_bounds(1000, 1000);
@@ -3932,7 +3952,7 @@
 
   time_ticks += base::TimeDelta::FromMilliseconds(200);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
   host_impl_.pending_tree()->UpdateDrawProperties();
 
   unoccluded_tile_count = 0;
@@ -3956,7 +3976,7 @@
 
   time_ticks += base::TimeDelta::FromMilliseconds(200);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
   host_impl_.pending_tree()->UpdateDrawProperties();
 
   unoccluded_tile_count = 0;
@@ -3981,7 +4001,7 @@
   base::TimeTicks time_ticks;
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
   gfx::Size tile_size(102, 102);
   gfx::Size layer_bounds(1000, 1000);
@@ -4032,7 +4052,7 @@
 
   time_ticks += base::TimeDelta::FromMilliseconds(200);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
   host_impl_.pending_tree()->UpdateDrawProperties();
 
   for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
@@ -4072,7 +4092,7 @@
 
   time_ticks += base::TimeDelta::FromMilliseconds(200);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
   host_impl_.pending_tree()->UpdateDrawProperties();
 
   for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
@@ -4501,7 +4521,7 @@
   base::TimeTicks time_ticks;
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(200, 200);
@@ -4568,7 +4588,7 @@
   base::TimeTicks time_ticks;
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(200, 200);
@@ -4625,7 +4645,7 @@
   base::TimeTicks time_ticks;
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
-      CreateBeginFrameArgsForTesting(time_ticks));
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(400, 4000);
diff --git a/cc/layers/picture_layer_unittest.cc b/cc/layers/picture_layer_unittest.cc
index 3f81ef8..ac20e4c 100644
--- a/cc/layers/picture_layer_unittest.cc
+++ b/cc/layers/picture_layer_unittest.cc
@@ -24,6 +24,12 @@
       SkCanvas* canvas,
       const gfx::Rect& clip,
       ContentLayerClient::GraphicsContextStatus gc_status) override {}
+  scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+      const gfx::Rect& clip,
+      GraphicsContextStatus gc_status) override {
+    NOTIMPLEMENTED();
+    return DisplayItemList::Create();
+  }
   bool FillsBoundsCompletely() const override { return false; };
 };
 
@@ -73,6 +79,9 @@
 TEST(PictureLayerTest, SuitableForGpuRasterization) {
   MockContentLayerClient client;
   scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client);
+  FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D);
+  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&host_client);
+  host->SetRootLayer(layer);
   RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
 
   // Layer is suitable for gpu rasterization by default.
diff --git a/cc/layers/tiled_layer_unittest.cc b/cc/layers/tiled_layer_unittest.cc
index 908d428..512fa51 100644
--- a/cc/layers/tiled_layer_unittest.cc
+++ b/cc/layers/tiled_layer_unittest.cc
@@ -261,6 +261,8 @@
 };
 
 TEST_F(TiledLayerTest, PushDirtyTiles) {
+  layer_tree_host_->SetViewportSize(gfx::Size(1000, 1000));
+
   scoped_refptr<FakeTiledLayer> layer =
       make_scoped_refptr(new FakeTiledLayer(resource_manager_.get()));
   scoped_ptr<FakeTiledLayerImpl> layer_impl =
@@ -290,6 +292,8 @@
 }
 
 TEST_F(TiledLayerTest, Scale) {
+  layer_tree_host_->SetViewportSize(gfx::Size(1000, 1000));
+
   layer_tree_host_->SetDeviceScaleFactor(1.5);
 
   scoped_refptr<FakeTiledLayer> layer =
@@ -352,6 +356,8 @@
 }
 
 TEST_F(TiledLayerTest, PushDeletedTiles) {
+  layer_tree_host_->SetViewportSize(gfx::Size(1000, 1000));
+
   scoped_refptr<FakeTiledLayer> layer =
       make_scoped_refptr(new FakeTiledLayer(resource_manager_.get()));
   scoped_ptr<FakeTiledLayerImpl> layer_impl =
@@ -1201,6 +1207,8 @@
 }
 
 TEST_F(TiledLayerTest, TilesPaintedWithoutOcclusion) {
+  layer_tree_host_->SetViewportSize(gfx::Size(1000, 1000));
+
   scoped_refptr<FakeTiledLayer> layer =
       make_scoped_refptr(new FakeTiledLayer(resource_manager_.get()));
   RenderSurfaceLayerList render_surface_layer_list;
diff --git a/cc/output/begin_frame_args.cc b/cc/output/begin_frame_args.cc
index 0be9318..5744d9d 100644
--- a/cc/output/begin_frame_args.cc
+++ b/cc/output/begin_frame_args.cc
@@ -41,12 +41,19 @@
       type(type) {
 }
 
-BeginFrameArgs BeginFrameArgs::Create(base::TimeTicks frame_time,
+BeginFrameArgs BeginFrameArgs::Create(BeginFrameArgs::CreationLocation location,
+                                      base::TimeTicks frame_time,
                                       base::TimeTicks deadline,
                                       base::TimeDelta interval,
                                       BeginFrameArgs::BeginFrameArgsType type) {
   DCHECK_NE(type, BeginFrameArgs::INVALID);
+#ifdef NDEBUG
   return BeginFrameArgs(frame_time, deadline, interval, type);
+#else
+  BeginFrameArgs args = BeginFrameArgs(frame_time, deadline, interval, type);
+  args.created_from = location;
+  return args;
+#endif
 }
 
 scoped_refptr<base::debug::ConvertableToTraceFormat> BeginFrameArgs::AsValue()
@@ -63,6 +70,9 @@
   state->SetDouble("frame_time_us", frame_time.ToInternalValue());
   state->SetDouble("deadline_us", deadline.ToInternalValue());
   state->SetDouble("interval_us", interval.InMicroseconds());
+#ifndef NDEBUG
+  state->SetString("created_from", created_from.ToString());
+#endif
 }
 
 // This is a hard-coded deadline adjustment that assumes 60Hz, to be used in
diff --git a/cc/output/begin_frame_args.h b/cc/output/begin_frame_args.h
index 0be5241..ba29523 100644
--- a/cc/output/begin_frame_args.h
+++ b/cc/output/begin_frame_args.h
@@ -5,6 +5,7 @@
 #ifndef CC_OUTPUT_BEGIN_FRAME_ARGS_H_
 #define CC_OUTPUT_BEGIN_FRAME_ARGS_H_
 
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
 #include "base/values.h"
@@ -17,6 +18,22 @@
 }
 }
 
+/**
+ * In debug builds we trace the creation origin of BeginFrameArgs objects. We
+ * reuse the tracked_objects::Location system to do that.
+ *
+ * However, in release builds we don't want this as it doubles the size of the
+ * BeginFrameArgs object. As well it adds a number of largish strings to the
+ * binary. Despite the argument being unused, most compilers are unable to
+ * optimise it away even when unused. Instead we use the BEGINFRAME_FROM_HERE
+ * macro to prevent the data even getting referenced.
+ */
+#ifdef NDEBUG
+#define BEGINFRAME_FROM_HERE nullptr
+#else
+#define BEGINFRAME_FROM_HERE FROM_HERE
+#endif
+
 namespace cc {
 
 struct CC_EXPORT BeginFrameArgs {
@@ -31,9 +48,18 @@
   // Creates an invalid set of values.
   BeginFrameArgs();
 
+#ifdef NDEBUG
+  typedef const void* CreationLocation;
+#else
+  typedef const tracked_objects::Location& CreationLocation;
+  tracked_objects::Location created_from;
+#endif
+
   // You should be able to find all instances where a BeginFrame has been
   // created by searching for "BeginFrameArgs::Create".
-  static BeginFrameArgs Create(base::TimeTicks frame_time,
+  // The location argument should **always** be BEGINFRAME_FROM_HERE macro.
+  static BeginFrameArgs Create(CreationLocation location,
+                               base::TimeTicks frame_time,
                                base::TimeTicks deadline,
                                base::TimeDelta interval,
                                BeginFrameArgsType type);
diff --git a/cc/output/begin_frame_args_unittest.cc b/cc/output/begin_frame_args_unittest.cc
index 9d77a45..877a857 100644
--- a/cc/output/begin_frame_args_unittest.cc
+++ b/cc/output/begin_frame_args_unittest.cc
@@ -15,26 +15,29 @@
 
 TEST(BeginFrameArgsTest, Helpers) {
   // Quick create methods work
-  BeginFrameArgs args0 = CreateBeginFrameArgsForTesting();
+  BeginFrameArgs args0 = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE);
   EXPECT_TRUE(args0.IsValid()) << args0;
 
-  BeginFrameArgs args1 = CreateBeginFrameArgsForTesting(0, 0, -1);
+  BeginFrameArgs args1 =
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 0, -1);
   EXPECT_FALSE(args1.IsValid()) << args1;
 
-  BeginFrameArgs args2 = CreateBeginFrameArgsForTesting(1, 2, 3);
+  BeginFrameArgs args2 =
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 1, 2, 3);
   EXPECT_TRUE(args2.IsValid()) << args2;
   EXPECT_EQ(1, args2.frame_time.ToInternalValue());
   EXPECT_EQ(2, args2.deadline.ToInternalValue());
   EXPECT_EQ(3, args2.interval.ToInternalValue());
   EXPECT_EQ(BeginFrameArgs::NORMAL, args2.type);
 
-  BeginFrameArgs args3 = CreateExpiredBeginFrameArgsForTesting();
+  BeginFrameArgs args3 =
+      CreateExpiredBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE);
   EXPECT_TRUE(args3.IsValid()) << args3;
   EXPECT_GT(gfx::FrameTime::Now(), args3.deadline);
   EXPECT_EQ(BeginFrameArgs::NORMAL, args3.type);
 
-  BeginFrameArgs args4 =
-      CreateBeginFrameArgsForTesting(1, 2, 3, BeginFrameArgs::MISSED);
+  BeginFrameArgs args4 = CreateBeginFrameArgsForTesting(
+      BEGINFRAME_FROM_HERE, 1, 2, 3, BeginFrameArgs::MISSED);
   EXPECT_TRUE(args4.IsValid()) << args4;
   EXPECT_EQ(1, args4.frame_time.ToInternalValue());
   EXPECT_EQ(2, args4.deadline.ToInternalValue());
@@ -42,16 +45,19 @@
   EXPECT_EQ(BeginFrameArgs::MISSED, args4.type);
 
   // operator==
-  EXPECT_EQ(CreateBeginFrameArgsForTesting(4, 5, 6),
-            CreateBeginFrameArgsForTesting(4, 5, 6));
+  EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 4, 5, 6),
+            CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 4, 5, 6));
 
   EXPECT_NONFATAL_FAILURE(
-      EXPECT_EQ(CreateBeginFrameArgsForTesting(7, 8, 9, BeginFrameArgs::MISSED),
-                CreateBeginFrameArgsForTesting(7, 8, 9)),
+      EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 7, 8, 9,
+                                               BeginFrameArgs::MISSED),
+                CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 7, 8, 9)),
       "");
-  EXPECT_NONFATAL_FAILURE(EXPECT_EQ(CreateBeginFrameArgsForTesting(4, 5, 6),
-                                    CreateBeginFrameArgsForTesting(7, 8, 9)),
-                          "");
+
+  EXPECT_NONFATAL_FAILURE(
+      EXPECT_EQ(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 4, 5, 6),
+                CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 7, 8, 9)),
+      "");
 
   // operator<<
   std::stringstream out1;
@@ -74,7 +80,7 @@
   EXPECT_FALSE(args1.IsValid()) << args1;
 
   BeginFrameArgs args2 = BeginFrameArgs::Create(
-      base::TimeTicks::FromInternalValue(1),
+      BEGINFRAME_FROM_HERE, base::TimeTicks::FromInternalValue(1),
       base::TimeTicks::FromInternalValue(2),
       base::TimeDelta::FromInternalValue(3), BeginFrameArgs::NORMAL);
   EXPECT_TRUE(args2.IsValid()) << args2;
@@ -84,5 +90,14 @@
   EXPECT_EQ(BeginFrameArgs::NORMAL, args2.type) << args2;
 }
 
+#ifndef NDEBUG
+TEST(BeginFrameArgsTest, Location) {
+  tracked_objects::Location expected_location = BEGINFRAME_FROM_HERE;
+
+  BeginFrameArgs args = CreateBeginFrameArgsForTesting(expected_location);
+  EXPECT_EQ(expected_location.ToString(), args.created_from.ToString());
+}
+#endif
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/output/renderer_settings.cc b/cc/output/renderer_settings.cc
index bacde5b..2277af3 100644
--- a/cc/output/renderer_settings.cc
+++ b/cc/output/renderer_settings.cc
@@ -15,6 +15,7 @@
       force_antialiasing(false),
       force_blending_with_shaders(false),
       partial_swap_enabled(false),
+      finish_rendering_on_resize(false),
       should_clear_root_render_pass(true),
       refresh_rate(60.0),
       highp_threshold_min(0),
diff --git a/cc/output/renderer_settings.h b/cc/output/renderer_settings.h
index 748d230..6da0238 100644
--- a/cc/output/renderer_settings.h
+++ b/cc/output/renderer_settings.h
@@ -19,6 +19,7 @@
   bool force_antialiasing;
   bool force_blending_with_shaders;
   bool partial_swap_enabled;
+  bool finish_rendering_on_resize;
   bool should_clear_root_render_pass;
   double refresh_rate;
   int highp_threshold_min;
diff --git a/cc/quads/largest_draw_quad.cc b/cc/quads/largest_draw_quad.cc
index 55fcb22..6445204 100644
--- a/cc/quads/largest_draw_quad.cc
+++ b/cc/quads/largest_draw_quad.cc
@@ -6,15 +6,62 @@
 
 #include <algorithm>
 
+#include "cc/quads/checkerboard_draw_quad.h"
+#include "cc/quads/debug_border_draw_quad.h"
+#include "cc/quads/io_surface_draw_quad.h"
+#include "cc/quads/picture_draw_quad.h"
 #include "cc/quads/render_pass_draw_quad.h"
+#include "cc/quads/solid_color_draw_quad.h"
 #include "cc/quads/stream_video_draw_quad.h"
+#include "cc/quads/surface_draw_quad.h"
+#include "cc/quads/texture_draw_quad.h"
+#include "cc/quads/tile_draw_quad.h"
+#include "cc/quads/yuv_video_draw_quad.h"
+
+namespace {
+const size_t kLargestDrawQuadSize =
+    sizeof(cc::RenderPassDrawQuad) > sizeof(cc::StreamVideoDrawQuad)
+        ? sizeof(cc::RenderPassDrawQuad)
+        : sizeof(cc::StreamVideoDrawQuad);
+}  // namespace
 
 namespace cc {
 
 size_t LargestDrawQuadSize() {
-  // The largest quad is either a RenderPassDrawQuad or a StreamVideoDrawQuad
-  // depends on hardware structure.
-  return std::max(sizeof(RenderPassDrawQuad), sizeof(StreamVideoDrawQuad));
+  // Currently the largest quad is either a RenderPassDrawQuad or a
+  // StreamVideoDrawQuad depends on hardware structure.
+
+  // Use compile assert to make sure largest is actually larger than all other
+  // type of draw quads.
+  COMPILE_ASSERT(sizeof(CheckerboardDrawQuad) <= kLargestDrawQuadSize,
+                 "Largest Draw Quad size needs update. CheckerboardDrawQuad is "
+                 "currently largest.");
+  COMPILE_ASSERT(sizeof(DebugBorderDrawQuad) <= kLargestDrawQuadSize,
+                 "Largest Draw Quad size needs update. DebugBorderDrawQuad is "
+                 "currently largest.");
+  COMPILE_ASSERT(sizeof(IOSurfaceDrawQuad) <= kLargestDrawQuadSize,
+                 "Largest Draw Quad size needs update. IOSurfaceDrawQuad is "
+                 "currently largest.");
+  COMPILE_ASSERT(sizeof(PictureDrawQuad) <= kLargestDrawQuadSize,
+                 "Largest Draw Quad size needs update. PictureDrawQuad is "
+                 "currently largest.");
+  COMPILE_ASSERT(sizeof(TextureDrawQuad) <= kLargestDrawQuadSize,
+                 "Largest Draw Quad size needs update. TextureDrawQuad is "
+                 "currently largest.");
+  COMPILE_ASSERT(sizeof(SolidColorDrawQuad) <= kLargestDrawQuadSize,
+                 "Largest Draw Quad size needs update. SolidColorDrawQuad is "
+                 "currently largest.");
+  COMPILE_ASSERT(sizeof(SurfaceDrawQuad) <= kLargestDrawQuadSize,
+                 "Largest Draw Quad size needs update. SurfaceDrawQuad is "
+                 "currently largest.");
+  COMPILE_ASSERT(sizeof(TileDrawQuad) <= kLargestDrawQuadSize,
+                 "Largest Draw Quad size needs update. TileDrawQuad is "
+                 "currently largest.");
+  COMPILE_ASSERT(sizeof(YUVVideoDrawQuad) <= kLargestDrawQuadSize,
+                 "Largest Draw Quad size needs update. YUVVideoDrawQuad is "
+                 "currently largest.");
+
+  return kLargestDrawQuadSize;
 }
 
 }  // namespace cc
diff --git a/cc/resources/clip_display_item.cc b/cc/resources/clip_display_item.cc
new file mode 100644
index 0000000..731c605
--- /dev/null
+++ b/cc/resources/clip_display_item.cc
@@ -0,0 +1,74 @@
+// Copyright 2014 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/resources/clip_display_item.h"
+
+#include "third_party/skia/include/core/SkCanvas.h"
+
+namespace cc {
+
+ClipDisplayItem::ClipDisplayItem(gfx::Rect clip_rect,
+                                 const std::vector<SkRRect>& rounded_clip_rects)
+    : clip_rect_(clip_rect), rounded_clip_rects_(rounded_clip_rects) {
+}
+
+ClipDisplayItem::~ClipDisplayItem() {
+}
+
+void ClipDisplayItem::Raster(SkCanvas* canvas,
+                             SkDrawPictureCallback* callback) const {
+  canvas->save();
+  canvas->clipRect(SkRect::MakeXYWH(clip_rect_.x(), clip_rect_.y(),
+                                    clip_rect_.width(), clip_rect_.height()));
+  for (size_t i = 0; i < rounded_clip_rects_.size(); ++i) {
+    if (rounded_clip_rects_[i].isRect()) {
+      canvas->clipRect(rounded_clip_rects_[i].rect());
+    } else {
+      bool antialiased = true;
+      canvas->clipRRect(rounded_clip_rects_[i], SkRegion::kIntersect_Op,
+                        antialiased);
+    }
+  }
+}
+
+bool ClipDisplayItem::IsSuitableForGpuRasterization() const {
+  return true;
+}
+
+int ClipDisplayItem::ApproximateOpCount() const {
+  return 1;
+}
+
+size_t ClipDisplayItem::PictureMemoryUsage() const {
+  size_t total_size = sizeof(gfx::Rect);
+  for (size_t i = 0; i < rounded_clip_rects_.size(); ++i) {
+    total_size += sizeof(rounded_clip_rects_[i]);
+  }
+  return total_size;
+}
+
+EndClipDisplayItem::EndClipDisplayItem() {
+}
+
+EndClipDisplayItem::~EndClipDisplayItem() {
+}
+
+void EndClipDisplayItem::Raster(SkCanvas* canvas,
+                                SkDrawPictureCallback* callback) const {
+  canvas->restore();
+}
+
+bool EndClipDisplayItem::IsSuitableForGpuRasterization() const {
+  return true;
+}
+
+int EndClipDisplayItem::ApproximateOpCount() const {
+  return 0;
+}
+
+size_t EndClipDisplayItem::PictureMemoryUsage() const {
+  return 0;
+}
+
+}  // namespace cc
diff --git a/cc/resources/clip_display_item.h b/cc/resources/clip_display_item.h
new file mode 100644
index 0000000..55c1ffd
--- /dev/null
+++ b/cc/resources/clip_display_item.h
@@ -0,0 +1,66 @@
+// Copyright 2014 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_RESOURCES_CLIP_DISPLAY_ITEM_H_
+#define CC_RESOURCES_CLIP_DISPLAY_ITEM_H_
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/resources/display_item.h"
+#include "third_party/skia/include/core/SkRRect.h"
+#include "ui/gfx/geometry/rect.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+
+namespace cc {
+
+class CC_EXPORT ClipDisplayItem : public DisplayItem {
+ public:
+  virtual ~ClipDisplayItem();
+
+  static scoped_ptr<ClipDisplayItem> Create(
+      gfx::Rect clip_rect,
+      const std::vector<SkRRect>& rounded_clip_rects) {
+    return make_scoped_ptr(new ClipDisplayItem(clip_rect, rounded_clip_rects));
+  }
+
+  void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+  bool IsSuitableForGpuRasterization() const override;
+  int ApproximateOpCount() const override;
+  size_t PictureMemoryUsage() const override;
+
+ protected:
+  ClipDisplayItem(gfx::Rect clip_rect,
+                  const std::vector<SkRRect>& rounded_clip_rects);
+
+ private:
+  gfx::Rect clip_rect_;
+  std::vector<SkRRect> rounded_clip_rects_;
+};
+
+class CC_EXPORT EndClipDisplayItem : public DisplayItem {
+ public:
+  virtual ~EndClipDisplayItem();
+
+  static scoped_ptr<EndClipDisplayItem> Create() {
+    return make_scoped_ptr(new EndClipDisplayItem());
+  }
+
+  void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+  bool IsSuitableForGpuRasterization() const override;
+  int ApproximateOpCount() const override;
+  size_t PictureMemoryUsage() const override;
+
+ protected:
+  EndClipDisplayItem();
+};
+
+}  // namespace cc
+
+#endif  // CC_RESOURCES_CLIP_DISPLAY_ITEM_H_
diff --git a/cc/resources/display_item.cc b/cc/resources/display_item.cc
new file mode 100644
index 0000000..33069a5
--- /dev/null
+++ b/cc/resources/display_item.cc
@@ -0,0 +1,12 @@
+// Copyright 2014 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/resources/display_item.h"
+
+namespace cc {
+
+DisplayItem::DisplayItem() {
+}
+
+}  // namespace cc
diff --git a/cc/resources/display_item.h b/cc/resources/display_item.h
new file mode 100644
index 0000000..6f1b5f7
--- /dev/null
+++ b/cc/resources/display_item.h
@@ -0,0 +1,34 @@
+// Copyright 2014 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_RESOURCES_DISPLAY_ITEM_H_
+#define CC_RESOURCES_DISPLAY_ITEM_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "ui/gfx/rect.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+
+namespace cc {
+
+class CC_EXPORT DisplayItem {
+ public:
+  virtual ~DisplayItem() {}
+
+  virtual void Raster(SkCanvas* canvas,
+                      SkDrawPictureCallback* callback) const = 0;
+
+  virtual bool IsSuitableForGpuRasterization() const = 0;
+  virtual int ApproximateOpCount() const = 0;
+  virtual size_t PictureMemoryUsage() const = 0;
+
+ protected:
+  DisplayItem();
+};
+
+}  // namespace cc
+
+#endif  // CC_RESOURCES_DISPLAY_ITEM_H_
diff --git a/cc/resources/display_item_list.cc b/cc/resources/display_item_list.cc
new file mode 100644
index 0000000..2ead28d
--- /dev/null
+++ b/cc/resources/display_item_list.cc
@@ -0,0 +1,79 @@
+// Copyright 2014 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/resources/display_item_list.h"
+
+#include "base/debug/trace_event.h"
+#include "base/debug/trace_event_argument.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+
+namespace cc {
+
+DisplayItemList::DisplayItemList()
+    : is_suitable_for_gpu_rasterization_(true), approximate_op_count_(0) {
+}
+
+scoped_refptr<DisplayItemList> DisplayItemList::Create() {
+  return make_scoped_refptr(new DisplayItemList());
+}
+
+DisplayItemList::~DisplayItemList() {
+}
+
+void DisplayItemList::Raster(SkCanvas* canvas,
+                             SkDrawPictureCallback* callback,
+                             float contents_scale) const {
+  canvas->save();
+  canvas->scale(contents_scale, contents_scale);
+  for (size_t i = 0; i < items_.size(); ++i) {
+    items_[i]->Raster(canvas, callback);
+  }
+  canvas->restore();
+}
+
+void DisplayItemList::AppendItem(scoped_ptr<DisplayItem> item) {
+  is_suitable_for_gpu_rasterization_ &= item->IsSuitableForGpuRasterization();
+  approximate_op_count_ += item->ApproximateOpCount();
+  items_.push_back(item.Pass());
+}
+
+bool DisplayItemList::IsSuitableForGpuRasterization() const {
+  // This is more permissive than Picture's implementation, since none of the
+  // items might individually trigger a veto even though they collectively have
+  // enough "bad" operations that a corresponding Picture would get vetoed.
+  return is_suitable_for_gpu_rasterization_;
+}
+
+int DisplayItemList::ApproximateOpCount() const {
+  return approximate_op_count_;
+}
+
+size_t DisplayItemList::PictureMemoryUsage() const {
+  size_t total_size = 0;
+
+  for (const auto& item : items_) {
+    total_size += item->PictureMemoryUsage();
+  }
+
+  return total_size;
+}
+
+scoped_refptr<base::debug::ConvertableToTraceFormat> DisplayItemList::AsValue()
+    const {
+  scoped_refptr<base::debug::TracedValue> state =
+      new base::debug::TracedValue();
+
+  // TODO(ajuma): Include the value of each item.
+  state->SetInteger("length", items_.size());
+  return state;
+}
+
+void DisplayItemList::EmitTraceSnapshot() const {
+  TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
+      TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT(
+          "devtools.timeline.picture"),
+      "cc::DisplayItemList", this, AsValue());
+}
+
+}  // namespace cc
diff --git a/cc/resources/display_item_list.h b/cc/resources/display_item_list.h
new file mode 100644
index 0000000..10d052f
--- /dev/null
+++ b/cc/resources/display_item_list.h
@@ -0,0 +1,53 @@
+// Copyright 2014 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_RESOURCES_DISPLAY_ITEM_LIST_H_
+#define CC_RESOURCES_DISPLAY_ITEM_LIST_H_
+
+#include "base/debug/trace_event.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/base/scoped_ptr_vector.h"
+#include "cc/resources/display_item.h"
+#include "ui/gfx/rect.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+
+namespace cc {
+
+class CC_EXPORT DisplayItemList
+    : public base::RefCountedThreadSafe<DisplayItemList> {
+ public:
+  static scoped_refptr<DisplayItemList> Create();
+
+  void Raster(SkCanvas* canvas,
+              SkDrawPictureCallback* callback,
+              float contents_scale) const;
+
+  void AppendItem(scoped_ptr<DisplayItem> item);
+
+  bool IsSuitableForGpuRasterization() const;
+  int ApproximateOpCount() const;
+  size_t PictureMemoryUsage() const;
+
+  scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
+
+  void EmitTraceSnapshot() const;
+
+ private:
+  DisplayItemList();
+  ~DisplayItemList();
+  ScopedPtrVector<DisplayItem> items_;
+  bool is_suitable_for_gpu_rasterization_;
+  int approximate_op_count_;
+
+  friend class base::RefCountedThreadSafe<DisplayItemList>;
+  DISALLOW_COPY_AND_ASSIGN(DisplayItemList);
+};
+
+}  // namespace cc
+
+#endif  // CC_RESOURCES_DISPLAY_ITEM_LIST_H_
diff --git a/cc/resources/display_item_list_unittest.cc b/cc/resources/display_item_list_unittest.cc
new file mode 100644
index 0000000..d6455a2
--- /dev/null
+++ b/cc/resources/display_item_list_unittest.cc
@@ -0,0 +1,166 @@
+// Copyright 2014 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/resources/display_item_list.h"
+
+#include <vector>
+
+#include "cc/resources/clip_display_item.h"
+#include "cc/resources/drawing_display_item.h"
+#include "cc/resources/transform_display_item.h"
+#include "cc/test/skia_common.h"
+#include "skia/ext/refptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+namespace {
+
+TEST(DisplayItemListTest, SingleDrawingItem) {
+  gfx::Rect layer_rect(100, 100);
+  SkPictureRecorder recorder;
+  skia::RefPtr<SkCanvas> canvas;
+  skia::RefPtr<SkPicture> picture;
+  SkPaint blue_paint;
+  blue_paint.setColor(SK_ColorBLUE);
+  SkPaint red_paint;
+  red_paint.setColor(SK_ColorRED);
+  unsigned char pixels[4 * 100 * 100] = {0};
+  scoped_refptr<DisplayItemList> list = DisplayItemList::Create();
+
+  canvas = skia::SharePtr(
+      recorder.beginRecording(layer_rect.width(), layer_rect.height()));
+  canvas->drawRectCoords(0.f, 0.f, 60.f, 60.f, red_paint);
+  canvas->drawRectCoords(50.f, 50.f, 75.f, 75.f, blue_paint);
+  picture = skia::AdoptRef(recorder.endRecording());
+  gfx::PointF offset(8.f, 9.f);
+  list->AppendItem(DrawingDisplayItem::Create(picture, offset));
+  DrawDisplayList(pixels, layer_rect, list);
+
+  SkBitmap expected_bitmap;
+  unsigned char expected_pixels[4 * 100 * 100] = {0};
+  SkImageInfo info =
+      SkImageInfo::MakeN32Premul(layer_rect.width(), layer_rect.height());
+  expected_bitmap.installPixels(info, expected_pixels, info.minRowBytes());
+  SkCanvas expected_canvas(expected_bitmap);
+  expected_canvas.clipRect(gfx::RectToSkRect(layer_rect));
+  expected_canvas.drawRectCoords(0.f + offset.x(), 0.f + offset.y(),
+                                 60.f + offset.x(), 60.f + offset.y(),
+                                 red_paint);
+  expected_canvas.drawRectCoords(50.f + offset.x(), 50.f + offset.y(),
+                                 75.f + offset.x(), 75.f + offset.y(),
+                                 blue_paint);
+
+  EXPECT_EQ(0, memcmp(pixels, expected_pixels, 4 * 100 * 100));
+}
+
+TEST(DisplayItemListTest, ClipItem) {
+  gfx::Rect layer_rect(100, 100);
+  SkPictureRecorder recorder;
+  skia::RefPtr<SkCanvas> canvas;
+  skia::RefPtr<SkPicture> picture;
+  SkPaint blue_paint;
+  blue_paint.setColor(SK_ColorBLUE);
+  SkPaint red_paint;
+  red_paint.setColor(SK_ColorRED);
+  unsigned char pixels[4 * 100 * 100] = {0};
+  scoped_refptr<DisplayItemList> list = DisplayItemList::Create();
+
+  canvas = skia::SharePtr(
+      recorder.beginRecording(layer_rect.width(), layer_rect.height()));
+  canvas->drawRectCoords(0.f, 0.f, 60.f, 60.f, red_paint);
+  picture = skia::AdoptRef(recorder.endRecording());
+  gfx::PointF first_offset(8.f, 9.f);
+  list->AppendItem(DrawingDisplayItem::Create(picture, first_offset));
+
+  gfx::Rect clip_rect(60, 60, 10, 10);
+  list->AppendItem(ClipDisplayItem::Create(clip_rect, std::vector<SkRRect>()));
+
+  canvas = skia::SharePtr(
+      recorder.beginRecording(layer_rect.width(), layer_rect.height()));
+  canvas->drawRectCoords(50.f, 50.f, 75.f, 75.f, blue_paint);
+  picture = skia::AdoptRef(recorder.endRecording());
+  gfx::PointF second_offset(2.f, 3.f);
+  list->AppendItem(DrawingDisplayItem::Create(picture, second_offset));
+
+  list->AppendItem(EndClipDisplayItem::Create());
+
+  DrawDisplayList(pixels, layer_rect, list);
+
+  SkBitmap expected_bitmap;
+  unsigned char expected_pixels[4 * 100 * 100] = {0};
+  SkImageInfo info =
+      SkImageInfo::MakeN32Premul(layer_rect.width(), layer_rect.height());
+  expected_bitmap.installPixels(info, expected_pixels, info.minRowBytes());
+  SkCanvas expected_canvas(expected_bitmap);
+  expected_canvas.clipRect(gfx::RectToSkRect(layer_rect));
+  expected_canvas.drawRectCoords(0.f + first_offset.x(), 0.f + first_offset.y(),
+                                 60.f + first_offset.x(),
+                                 60.f + first_offset.y(), red_paint);
+  expected_canvas.clipRect(gfx::RectToSkRect(clip_rect));
+  expected_canvas.drawRectCoords(
+      50.f + second_offset.x(), 50.f + second_offset.y(),
+      75.f + second_offset.x(), 75.f + second_offset.y(), blue_paint);
+
+  EXPECT_EQ(0, memcmp(pixels, expected_pixels, 4 * 100 * 100));
+}
+
+TEST(DisplayItemListTest, TransformItem) {
+  gfx::Rect layer_rect(100, 100);
+  SkPictureRecorder recorder;
+  skia::RefPtr<SkCanvas> canvas;
+  skia::RefPtr<SkPicture> picture;
+  SkPaint blue_paint;
+  blue_paint.setColor(SK_ColorBLUE);
+  SkPaint red_paint;
+  red_paint.setColor(SK_ColorRED);
+  unsigned char pixels[4 * 100 * 100] = {0};
+  scoped_refptr<DisplayItemList> list = DisplayItemList::Create();
+
+  canvas = skia::SharePtr(
+      recorder.beginRecording(layer_rect.width(), layer_rect.height()));
+  canvas->drawRectCoords(0.f, 0.f, 60.f, 60.f, red_paint);
+  picture = skia::AdoptRef(recorder.endRecording());
+  gfx::PointF first_offset(8.f, 9.f);
+  list->AppendItem(DrawingDisplayItem::Create(picture, first_offset));
+
+  gfx::Transform transform;
+  transform.Rotate(45.0);
+  list->AppendItem(TransformDisplayItem::Create(transform));
+
+  canvas = skia::SharePtr(
+      recorder.beginRecording(layer_rect.width(), layer_rect.height()));
+  canvas->drawRectCoords(50.f, 50.f, 75.f, 75.f, blue_paint);
+  picture = skia::AdoptRef(recorder.endRecording());
+  gfx::PointF second_offset(2.f, 3.f);
+  list->AppendItem(DrawingDisplayItem::Create(picture, second_offset));
+
+  list->AppendItem(EndTransformDisplayItem::Create());
+
+  DrawDisplayList(pixels, layer_rect, list);
+
+  SkBitmap expected_bitmap;
+  unsigned char expected_pixels[4 * 100 * 100] = {0};
+  SkImageInfo info =
+      SkImageInfo::MakeN32Premul(layer_rect.width(), layer_rect.height());
+  expected_bitmap.installPixels(info, expected_pixels, info.minRowBytes());
+  SkCanvas expected_canvas(expected_bitmap);
+  expected_canvas.clipRect(gfx::RectToSkRect(layer_rect));
+  expected_canvas.drawRectCoords(0.f + first_offset.x(), 0.f + first_offset.y(),
+                                 60.f + first_offset.x(),
+                                 60.f + first_offset.y(), red_paint);
+  expected_canvas.setMatrix(transform.matrix());
+  expected_canvas.drawRectCoords(
+      50.f + second_offset.x(), 50.f + second_offset.y(),
+      75.f + second_offset.x(), 75.f + second_offset.y(), blue_paint);
+
+  EXPECT_EQ(0, memcmp(pixels, expected_pixels, 4 * 100 * 100));
+}
+
+}  // namespace
+}  // namespace cc
diff --git a/cc/resources/display_list_raster_source.cc b/cc/resources/display_list_raster_source.cc
new file mode 100644
index 0000000..f3ff816
--- /dev/null
+++ b/cc/resources/display_list_raster_source.cc
@@ -0,0 +1,208 @@
+// Copyright 2014 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/resources/display_list_raster_source.h"
+
+#include "base/debug/trace_event.h"
+#include "cc/base/region.h"
+#include "cc/debug/debug_colors.h"
+#include "cc/resources/display_item_list.h"
+#include "cc/resources/raster_source_helper.h"
+#include "skia/ext/analysis_canvas.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+
+namespace {
+
+#ifdef NDEBUG
+const bool kDefaultClearCanvasSetting = false;
+#else
+const bool kDefaultClearCanvasSetting = true;
+#endif
+
+}  // namespace
+
+namespace cc {
+
+scoped_refptr<DisplayListRasterSource> DisplayListRasterSource::Create() {
+  return make_scoped_refptr(new DisplayListRasterSource);
+}
+
+scoped_refptr<DisplayListRasterSource>
+DisplayListRasterSource::CreateFromDisplayListRecordingSource(
+    const DisplayListRecordingSource* other) {
+  return make_scoped_refptr(new DisplayListRasterSource(other));
+}
+
+DisplayListRasterSource::DisplayListRasterSource()
+    : background_color_(SK_ColorTRANSPARENT),
+      requires_clear_(true),
+      can_use_lcd_text_(true),
+      is_solid_color_(false),
+      solid_color_(SK_ColorTRANSPARENT),
+      clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
+      slow_down_raster_scale_factor_for_debug_(0),
+      should_attempt_to_use_distance_field_text_(false) {
+}
+
+DisplayListRasterSource::DisplayListRasterSource(
+    const DisplayListRecordingSource* other)
+    : display_list_(other->display_list_),
+      background_color_(SK_ColorTRANSPARENT),
+      requires_clear_(true),
+      can_use_lcd_text_(other->can_use_lcd_text_),
+      is_solid_color_(other->is_solid_color_),
+      solid_color_(other->solid_color_),
+      recorded_viewport_(other->recorded_viewport_),
+      size_(other->size_),
+      clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
+      slow_down_raster_scale_factor_for_debug_(
+          other->slow_down_raster_scale_factor_for_debug_),
+      should_attempt_to_use_distance_field_text_(false) {
+}
+
+DisplayListRasterSource::~DisplayListRasterSource() {
+}
+
+void DisplayListRasterSource::PlaybackToSharedCanvas(
+    SkCanvas* canvas,
+    const gfx::Rect& canvas_rect,
+    float contents_scale) const {
+  RasterCommon(canvas, NULL, canvas_rect, contents_scale, false);
+}
+
+void DisplayListRasterSource::RasterForAnalysis(skia::AnalysisCanvas* canvas,
+                                                const gfx::Rect& canvas_rect,
+                                                float contents_scale) const {
+  RasterCommon(canvas, canvas, canvas_rect, contents_scale, true);
+}
+
+void DisplayListRasterSource::PlaybackToCanvas(SkCanvas* canvas,
+                                               const gfx::Rect& canvas_rect,
+                                               float contents_scale) const {
+  RasterSourceHelper::PrepareForPlaybackToCanvas(
+      canvas, canvas_rect, gfx::Rect(size_), contents_scale, background_color_,
+      clear_canvas_with_debug_color_, requires_clear_);
+
+  RasterCommon(canvas, NULL, canvas_rect, contents_scale, false);
+}
+
+void DisplayListRasterSource::RasterCommon(SkCanvas* canvas,
+                                           SkDrawPictureCallback* callback,
+                                           const gfx::Rect& canvas_rect,
+                                           float contents_scale,
+                                           bool is_analysis) const {
+  canvas->translate(-canvas_rect.x(), -canvas_rect.y());
+  gfx::Rect content_rect =
+      gfx::ToEnclosingRect(gfx::ScaleRect(gfx::Rect(size_), contents_scale));
+  content_rect.Intersect(canvas_rect);
+
+  canvas->clipRect(gfx::RectToSkRect(content_rect), SkRegion::kIntersect_Op);
+
+  DCHECK(display_list_.get());
+  display_list_->Raster(canvas, callback, contents_scale);
+}
+
+skia::RefPtr<SkPicture> DisplayListRasterSource::GetFlattenedPicture() {
+  TRACE_EVENT0("cc", "DisplayListRasterSource::GetFlattenedPicture");
+
+  gfx::Rect display_list_rect(size_);
+  SkPictureRecorder recorder;
+  SkCanvas* canvas = recorder.beginRecording(display_list_rect.width(),
+                                             display_list_rect.height());
+  if (!display_list_rect.IsEmpty())
+    PlaybackToCanvas(canvas, display_list_rect, 1.0);
+  skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording());
+
+  return picture;
+}
+
+size_t DisplayListRasterSource::GetPictureMemoryUsage() const {
+  return display_list_->PictureMemoryUsage();
+}
+
+void DisplayListRasterSource::PerformSolidColorAnalysis(
+    const gfx::Rect& content_rect,
+    float contents_scale,
+    RasterSource::SolidColorAnalysis* analysis) const {
+  DCHECK(analysis);
+  TRACE_EVENT0("cc", "DisplayListRasterSource::PerformSolidColorAnalysis");
+
+  gfx::Rect layer_rect =
+      gfx::ScaleToEnclosingRect(content_rect, 1.0f / contents_scale);
+
+  layer_rect.Intersect(gfx::Rect(size_));
+  skia::AnalysisCanvas canvas(layer_rect.width(), layer_rect.height());
+  RasterForAnalysis(&canvas, layer_rect, 1.0f);
+  analysis->is_solid_color = canvas.GetColorIfSolid(&analysis->solid_color);
+}
+
+void DisplayListRasterSource::GatherPixelRefs(
+    const gfx::Rect& content_rect,
+    float contents_scale,
+    std::vector<SkPixelRef*>* pixel_refs) const {
+  // TODO(ajuma): Implement this.
+}
+
+bool DisplayListRasterSource::CoversRect(const gfx::Rect& content_rect,
+                                         float contents_scale) const {
+  if (size_.IsEmpty())
+    return false;
+  gfx::Rect layer_rect =
+      gfx::ScaleToEnclosingRect(content_rect, 1.f / contents_scale);
+  layer_rect.Intersect(gfx::Rect(size_));
+
+  return recorded_viewport_.Contains(layer_rect);
+}
+
+gfx::Size DisplayListRasterSource::GetSize() const {
+  return size_;
+}
+
+bool DisplayListRasterSource::IsSolidColor() const {
+  return is_solid_color_;
+}
+
+SkColor DisplayListRasterSource::GetSolidColor() const {
+  DCHECK(IsSolidColor());
+  return solid_color_;
+}
+
+bool DisplayListRasterSource::HasRecordings() const {
+  return !!display_list_.get();
+}
+
+void DisplayListRasterSource::SetShouldAttemptToUseDistanceFieldText() {
+  should_attempt_to_use_distance_field_text_ = true;
+}
+
+void DisplayListRasterSource::SetBackgoundColor(SkColor background_color) {
+  background_color_ = background_color;
+}
+
+void DisplayListRasterSource::SetRequiresClear(bool requires_clear) {
+  requires_clear_ = requires_clear;
+}
+
+bool DisplayListRasterSource::ShouldAttemptToUseDistanceFieldText() const {
+  return should_attempt_to_use_distance_field_text_;
+}
+
+void DisplayListRasterSource::AsValueInto(
+    base::debug::TracedValue* array) const {
+  if (display_list_.get())
+    TracedValue::AppendIDRef(display_list_.get(), array);
+}
+
+void DisplayListRasterSource::DidBeginTracing() {
+  if (display_list_.get())
+    display_list_->EmitTraceSnapshot();
+}
+
+bool DisplayListRasterSource::CanUseLCDText() const {
+  return can_use_lcd_text_;
+}
+
+}  // namespace cc
diff --git a/cc/resources/display_list_raster_source.h b/cc/resources/display_list_raster_source.h
new file mode 100644
index 0000000..8f1fd12
--- /dev/null
+++ b/cc/resources/display_list_raster_source.h
@@ -0,0 +1,94 @@
+// Copyright 2014 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_RESOURCES_DISPLAY_LIST_RASTER_SOURCE_H_
+#define CC_RESOURCES_DISPLAY_LIST_RASTER_SOURCE_H_
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/debug/rendering_stats_instrumentation.h"
+#include "cc/resources/display_list_recording_source.h"
+#include "cc/resources/raster_source.h"
+#include "skia/ext/analysis_canvas.h"
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkPicture.h"
+
+namespace cc {
+class DisplayItemList;
+
+class CC_EXPORT DisplayListRasterSource : public RasterSource {
+ public:
+  static scoped_refptr<DisplayListRasterSource> Create();
+  static scoped_refptr<DisplayListRasterSource>
+  CreateFromDisplayListRecordingSource(const DisplayListRecordingSource* other);
+
+  // RasterSource overrides.
+  void PlaybackToCanvas(SkCanvas* canvas,
+                        const gfx::Rect& canvas_rect,
+                        float contents_scale) const override;
+  void PlaybackToSharedCanvas(SkCanvas* canvas,
+                              const gfx::Rect& canvas_rect,
+                              float contents_scale) const override;
+  void PerformSolidColorAnalysis(
+      const gfx::Rect& content_rect,
+      float contents_scale,
+      RasterSource::SolidColorAnalysis* analysis) const override;
+  bool IsSolidColor() const override;
+  SkColor GetSolidColor() const override;
+  gfx::Size GetSize() const override;
+  void GatherPixelRefs(const gfx::Rect& content_rect,
+                       float contents_scale,
+                       std::vector<SkPixelRef*>* pixel_refs) const override;
+  bool CoversRect(const gfx::Rect& content_rect,
+                  float contents_scale) const override;
+  bool HasRecordings() const override;
+  void SetShouldAttemptToUseDistanceFieldText() override;
+  void SetBackgoundColor(SkColor background_color) override;
+  void SetRequiresClear(bool requires_clear) override;
+  bool ShouldAttemptToUseDistanceFieldText() const override;
+  void DidBeginTracing() override;
+  void AsValueInto(base::debug::TracedValue* array) const override;
+  skia::RefPtr<SkPicture> GetFlattenedPicture() override;
+  size_t GetPictureMemoryUsage() const override;
+  bool CanUseLCDText() const override;
+
+ protected:
+  DisplayListRasterSource();
+  explicit DisplayListRasterSource(const DisplayListRecordingSource* other);
+  ~DisplayListRasterSource() override;
+
+  scoped_refptr<DisplayItemList> display_list_;
+  SkColor background_color_;
+  bool requires_clear_;
+  bool can_use_lcd_text_;
+  bool is_solid_color_;
+  SkColor solid_color_;
+  gfx::Rect recorded_viewport_;
+  gfx::Size size_;
+  bool clear_canvas_with_debug_color_;
+  int slow_down_raster_scale_factor_for_debug_;
+
+ private:
+  // Called when analyzing a tile. We can use AnalysisCanvas as
+  // SkDrawPictureCallback, which allows us to early out from analysis.
+  void RasterForAnalysis(skia::AnalysisCanvas* canvas,
+                         const gfx::Rect& canvas_rect,
+                         float contents_scale) const;
+
+  void RasterCommon(SkCanvas* canvas,
+                    SkDrawPictureCallback* callback,
+                    const gfx::Rect& canvas_rect,
+                    float contents_scale,
+                    bool is_analysis) const;
+
+  bool should_attempt_to_use_distance_field_text_;
+
+  DISALLOW_COPY_AND_ASSIGN(DisplayListRasterSource);
+};
+
+}  // namespace cc
+
+#endif  // CC_RESOURCES_DISPLAY_LIST_RASTER_SOURCE_H_
diff --git a/cc/resources/display_list_recording_source.cc b/cc/resources/display_list_recording_source.cc
new file mode 100644
index 0000000..3c0e0e4
--- /dev/null
+++ b/cc/resources/display_list_recording_source.cc
@@ -0,0 +1,158 @@
+// Copyright 2014 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/resources/display_list_recording_source.h"
+
+#include <algorithm>
+
+#include "cc/base/region.h"
+#include "cc/layers/content_layer_client.h"
+#include "cc/resources/display_item_list.h"
+#include "cc/resources/display_list_raster_source.h"
+#include "skia/ext/analysis_canvas.h"
+
+namespace {
+
+// Layout pixel buffer around the visible layer rect to record.  Any base
+// picture that intersects the visible layer rect expanded by this distance
+// will be recorded.
+const int kPixelDistanceToRecord = 8000;
+// We don't perform solid color analysis on images that have more than 10 skia
+// operations.
+const int kOpCountThatIsOkToAnalyze = 10;
+
+}  // namespace
+
+namespace cc {
+
+DisplayListRecordingSource::DisplayListRecordingSource()
+    : slow_down_raster_scale_factor_for_debug_(0),
+      can_use_lcd_text_(true),
+      is_solid_color_(false),
+      solid_color_(SK_ColorTRANSPARENT),
+      pixel_record_distance_(kPixelDistanceToRecord),
+      is_suitable_for_gpu_rasterization_(true) {
+}
+
+DisplayListRecordingSource::~DisplayListRecordingSource() {
+}
+
+bool DisplayListRecordingSource::UpdateAndExpandInvalidation(
+    ContentLayerClient* painter,
+    Region* invalidation,
+    bool can_use_lcd_text,
+    const gfx::Size& layer_size,
+    const gfx::Rect& visible_layer_rect,
+    int frame_number,
+    Picture::RecordingMode recording_mode) {
+  bool updated = false;
+
+  if (size_ != layer_size) {
+    size_ = layer_size;
+    updated = true;
+  }
+
+  if (can_use_lcd_text_ != can_use_lcd_text) {
+    can_use_lcd_text_ = can_use_lcd_text;
+    invalidation->Union(gfx::Rect(GetSize()));
+    updated = true;
+  }
+
+  gfx::Rect old_recorded_viewport = recorded_viewport_;
+  recorded_viewport_ = visible_layer_rect;
+  recorded_viewport_.Inset(-pixel_record_distance_, -pixel_record_distance_);
+  recorded_viewport_.Intersect(gfx::Rect(GetSize()));
+
+  if (recorded_viewport_ != old_recorded_viewport) {
+    // Invalidate newly-exposed and no-longer-exposed areas.
+    Region newly_exposed_region(recorded_viewport_);
+    newly_exposed_region.Subtract(old_recorded_viewport);
+    invalidation->Union(newly_exposed_region);
+
+    Region no_longer_exposed_region(old_recorded_viewport);
+    no_longer_exposed_region.Subtract(recorded_viewport_);
+    invalidation->Union(no_longer_exposed_region);
+
+    updated = true;
+  }
+
+  if (!updated && !invalidation->Intersects(recorded_viewport_))
+    return false;
+
+  // TODO(ajuma): Does repeating this way really makes sense with display lists?
+  // With Blink caching recordings, repeated calls will not cause re-recording.
+  int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_);
+  for (int i = 0; i < repeat_count; ++i) {
+    display_list_ = painter->PaintContentsToDisplayList(
+        recorded_viewport_, ContentLayerClient::GRAPHICS_CONTEXT_ENABLED);
+  }
+  is_suitable_for_gpu_rasterization_ =
+      display_list_->IsSuitableForGpuRasterization();
+
+  DetermineIfSolidColor();
+  display_list_->EmitTraceSnapshot();
+  return true;
+}
+
+gfx::Size DisplayListRecordingSource::GetSize() const {
+  return size_;
+}
+
+void DisplayListRecordingSource::SetEmptyBounds() {
+  size_ = gfx::Size();
+  Clear();
+}
+
+void DisplayListRecordingSource::SetMinContentsScale(float min_contents_scale) {
+}
+
+void DisplayListRecordingSource::SetTileGridSize(
+    const gfx::Size& tile_grid_size) {
+}
+
+void DisplayListRecordingSource::SetSlowdownRasterScaleFactor(int factor) {
+  slow_down_raster_scale_factor_for_debug_ = factor;
+}
+
+void DisplayListRecordingSource::SetUnsuitableForGpuRasterizationForTesting() {
+  is_suitable_for_gpu_rasterization_ = false;
+}
+
+bool DisplayListRecordingSource::IsSuitableForGpuRasterization() const {
+  return is_suitable_for_gpu_rasterization_;
+}
+
+scoped_refptr<RasterSource> DisplayListRecordingSource::CreateRasterSource()
+    const {
+  return scoped_refptr<RasterSource>(
+      DisplayListRasterSource::CreateFromDisplayListRecordingSource(this));
+}
+
+SkTileGridFactory::TileGridInfo
+DisplayListRecordingSource::GetTileGridInfoForTesting() const {
+  return SkTileGridFactory::TileGridInfo();
+}
+
+void DisplayListRecordingSource::DetermineIfSolidColor() {
+  DCHECK(display_list_.get());
+  is_solid_color_ = false;
+  solid_color_ = SK_ColorTRANSPARENT;
+
+  if (display_list_->ApproximateOpCount() > kOpCountThatIsOkToAnalyze)
+    return;
+
+  skia::AnalysisCanvas canvas(recorded_viewport_.width(),
+                              recorded_viewport_.height());
+  canvas.translate(-recorded_viewport_.x(), -recorded_viewport_.y());
+  display_list_->Raster(&canvas, nullptr, 1.f);
+  is_solid_color_ = canvas.GetColorIfSolid(&solid_color_);
+}
+
+void DisplayListRecordingSource::Clear() {
+  recorded_viewport_ = gfx::Rect();
+  display_list_ = NULL;
+  is_solid_color_ = false;
+}
+
+}  // namespace cc
diff --git a/cc/resources/display_list_recording_source.h b/cc/resources/display_list_recording_source.h
new file mode 100644
index 0000000..6bc8208
--- /dev/null
+++ b/cc/resources/display_list_recording_source.h
@@ -0,0 +1,64 @@
+// Copyright 2014 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_RESOURCES_DISPLAY_LIST_RECORDING_SOURCE_H_
+#define CC_RESOURCES_DISPLAY_LIST_RECORDING_SOURCE_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/resources/recording_source.h"
+
+namespace cc {
+class DisplayItemList;
+class DisplayListRasterSource;
+
+class CC_EXPORT DisplayListRecordingSource : public RecordingSource {
+ public:
+  DisplayListRecordingSource();
+  ~DisplayListRecordingSource() override;
+
+  // RecordingSource overrides.
+  bool UpdateAndExpandInvalidation(
+      ContentLayerClient* painter,
+      Region* invalidation,
+      bool can_use_lcd_text,
+      const gfx::Size& layer_size,
+      const gfx::Rect& visible_layer_rect,
+      int frame_number,
+      Picture::RecordingMode recording_mode) override;
+  scoped_refptr<RasterSource> CreateRasterSource() const override;
+  gfx::Size GetSize() const final;
+  void SetEmptyBounds() override;
+  void SetMinContentsScale(float min_contents_scale) override;
+  void SetSlowdownRasterScaleFactor(int factor) override;
+  bool IsSuitableForGpuRasterization() const override;
+  void SetTileGridSize(const gfx::Size& tile_grid_size) override;
+  void SetUnsuitableForGpuRasterizationForTesting() override;
+  SkTileGridFactory::TileGridInfo GetTileGridInfoForTesting() const override;
+
+ protected:
+  void Clear();
+
+  gfx::Rect recorded_viewport_;
+  gfx::Size size_;
+  int slow_down_raster_scale_factor_for_debug_;
+  bool can_use_lcd_text_;
+  bool is_solid_color_;
+  SkColor solid_color_;
+  int pixel_record_distance_;
+
+  scoped_refptr<DisplayItemList> display_list_;
+
+ private:
+  friend class DisplayListRasterSource;
+
+  void DetermineIfSolidColor();
+
+  bool is_suitable_for_gpu_rasterization_;
+
+  DISALLOW_COPY_AND_ASSIGN(DisplayListRecordingSource);
+};
+
+}  // namespace cc
+
+#endif  // CC_RESOURCES_DISPLAY_LIST_RECORDING_SOURCE_H_
diff --git a/cc/resources/drawing_display_item.cc b/cc/resources/drawing_display_item.cc
new file mode 100644
index 0000000..9466d5c
--- /dev/null
+++ b/cc/resources/drawing_display_item.cc
@@ -0,0 +1,47 @@
+// Copyright 2014 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/resources/drawing_display_item.h"
+
+#include "base/logging.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkMatrix.h"
+#include "third_party/skia/include/core/SkPicture.h"
+#include "third_party/skia/include/utils/SkPictureUtils.h"
+
+namespace cc {
+
+DrawingDisplayItem::DrawingDisplayItem(skia::RefPtr<SkPicture> picture,
+                                       gfx::PointF location)
+    : picture_(picture), location_(location) {
+}
+
+DrawingDisplayItem::~DrawingDisplayItem() {
+}
+
+void DrawingDisplayItem::Raster(SkCanvas* canvas,
+                                SkDrawPictureCallback* callback) const {
+  canvas->save();
+  canvas->translate(location_.x(), location_.y());
+  if (callback)
+    picture_->draw(canvas, callback);
+  else
+    canvas->drawPicture(picture_.get());
+  canvas->restore();
+}
+
+bool DrawingDisplayItem::IsSuitableForGpuRasterization() const {
+  return picture_->suitableForGpuRasterization(NULL);
+}
+
+int DrawingDisplayItem::ApproximateOpCount() const {
+  return picture_->approximateOpCount() + sizeof(gfx::PointF);
+}
+
+size_t DrawingDisplayItem::PictureMemoryUsage() const {
+  DCHECK(picture_);
+  return SkPictureUtils::ApproximateBytesUsed(picture_.get());
+}
+
+}  // namespace cc
diff --git a/cc/resources/drawing_display_item.h b/cc/resources/drawing_display_item.h
new file mode 100644
index 0000000..544e4eb
--- /dev/null
+++ b/cc/resources/drawing_display_item.h
@@ -0,0 +1,45 @@
+// Copyright 2014 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_RESOURCES_DRAWING_DISPLAY_ITEM_H_
+#define CC_RESOURCES_DRAWING_DISPLAY_ITEM_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/resources/display_item.h"
+#include "skia/ext/refptr.h"
+#include "ui/gfx/geometry/point_f.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+class SkPicture;
+
+namespace cc {
+
+class CC_EXPORT DrawingDisplayItem : public DisplayItem {
+ public:
+  virtual ~DrawingDisplayItem();
+
+  static scoped_ptr<DrawingDisplayItem> Create(skia::RefPtr<SkPicture> picture,
+                                               gfx::PointF location) {
+    return make_scoped_ptr(new DrawingDisplayItem(picture, location));
+  }
+
+  void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+  bool IsSuitableForGpuRasterization() const override;
+  int ApproximateOpCount() const override;
+  size_t PictureMemoryUsage() const override;
+
+ protected:
+  DrawingDisplayItem(skia::RefPtr<SkPicture> picture, gfx::PointF location);
+
+ private:
+  skia::RefPtr<SkPicture> picture_;
+  gfx::PointF location_;
+};
+
+}  // namespace cc
+
+#endif  // CC_RESOURCES_DRAWING_DISPLAY_ITEM_H_
diff --git a/cc/resources/eviction_tile_priority_queue.cc b/cc/resources/eviction_tile_priority_queue.cc
index 9f05e81..4d66987 100644
--- a/cc/resources/eviction_tile_priority_queue.cc
+++ b/cc/resources/eviction_tile_priority_queue.cc
@@ -14,8 +14,8 @@
       : tree_priority_(tree_priority) {}
 
   bool operator()(
-      const EvictionTilePriorityQueue::PairedPictureLayerQueue* a,
-      const EvictionTilePriorityQueue::PairedPictureLayerQueue* b) const {
+      const EvictionTilePriorityQueue::PairedTilingSetQueue* a,
+      const EvictionTilePriorityQueue::PairedTilingSetQueue* b) const {
     // Note that in this function, we have to return true if and only if
     // b is strictly lower priority than a. Note that for the sake of
     // completeness, empty queue is considered to have lowest priority.
@@ -23,15 +23,15 @@
       return b->IsEmpty() < a->IsEmpty();
 
     WhichTree a_tree = a->NextTileIteratorTree(tree_priority_);
-    const PictureLayerImpl::LayerEvictionTileIterator* a_iterator =
-        a_tree == ACTIVE_TREE ? &a->active_iterator : &a->pending_iterator;
+    const TilingSetEvictionQueue* a_queue =
+        a_tree == ACTIVE_TREE ? a->active_queue.get() : a->pending_queue.get();
 
     WhichTree b_tree = b->NextTileIteratorTree(tree_priority_);
-    const PictureLayerImpl::LayerEvictionTileIterator* b_iterator =
-        b_tree == ACTIVE_TREE ? &b->active_iterator : &b->pending_iterator;
+    const TilingSetEvictionQueue* b_queue =
+        b_tree == ACTIVE_TREE ? b->active_queue.get() : b->pending_queue.get();
 
-    const Tile* a_tile = **a_iterator;
-    const Tile* b_tile = **b_iterator;
+    const Tile* a_tile = a_queue->Top();
+    const Tile* b_tile = b_queue->Top();
 
     const TilePriority& a_priority =
         a_tile->priority_for_tree_priority(tree_priority_);
@@ -94,7 +94,7 @@
        it != paired_layers.end();
        ++it) {
     paired_queues_.push_back(
-        make_scoped_ptr(new PairedPictureLayerQueue(*it, tree_priority_)));
+        make_scoped_ptr(new PairedTilingSetQueue(*it, tree_priority_)));
   }
 
   paired_queues_.make_heap(EvictionOrderComparator(tree_priority_));
@@ -117,94 +117,89 @@
   DCHECK(!IsEmpty());
 
   paired_queues_.pop_heap(EvictionOrderComparator(tree_priority_));
-  PairedPictureLayerQueue* paired_queue = paired_queues_.back();
+  PairedTilingSetQueue* paired_queue = paired_queues_.back();
   paired_queue->Pop(tree_priority_);
   paired_queues_.push_heap(EvictionOrderComparator(tree_priority_));
 }
 
-EvictionTilePriorityQueue::PairedPictureLayerQueue::PairedPictureLayerQueue() {
+EvictionTilePriorityQueue::PairedTilingSetQueue::PairedTilingSetQueue() {
 }
 
-EvictionTilePriorityQueue::PairedPictureLayerQueue::PairedPictureLayerQueue(
+EvictionTilePriorityQueue::PairedTilingSetQueue::PairedTilingSetQueue(
     const PictureLayerImpl::Pair& layer_pair,
-    TreePriority tree_priority)
-    : active_iterator(
-          layer_pair.active
-              ? PictureLayerImpl::LayerEvictionTileIterator(layer_pair.active,
-                                                            tree_priority)
-              : PictureLayerImpl::LayerEvictionTileIterator()),
-      pending_iterator(
-          layer_pair.pending
-              ? PictureLayerImpl::LayerEvictionTileIterator(layer_pair.pending,
-                                                            tree_priority)
-              : PictureLayerImpl::LayerEvictionTileIterator()) {
+    TreePriority tree_priority) {
+  if (layer_pair.active)
+    active_queue = layer_pair.active->CreateEvictionQueue(tree_priority);
+  if (layer_pair.pending)
+    pending_queue = layer_pair.pending->CreateEvictionQueue(tree_priority);
 }
 
-EvictionTilePriorityQueue::PairedPictureLayerQueue::~PairedPictureLayerQueue() {
+EvictionTilePriorityQueue::PairedTilingSetQueue::~PairedTilingSetQueue() {
 }
 
-bool EvictionTilePriorityQueue::PairedPictureLayerQueue::IsEmpty() const {
-  return !active_iterator && !pending_iterator;
+bool EvictionTilePriorityQueue::PairedTilingSetQueue::IsEmpty() const {
+  return (!active_queue || active_queue->IsEmpty()) &&
+         (!pending_queue || pending_queue->IsEmpty());
 }
 
-Tile* EvictionTilePriorityQueue::PairedPictureLayerQueue::Top(
+Tile* EvictionTilePriorityQueue::PairedTilingSetQueue::Top(
     TreePriority tree_priority) {
   DCHECK(!IsEmpty());
 
   WhichTree next_tree = NextTileIteratorTree(tree_priority);
-  PictureLayerImpl::LayerEvictionTileIterator* next_iterator =
-      next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator;
-  DCHECK(*next_iterator);
+  TilingSetEvictionQueue* next_queue =
+      next_tree == ACTIVE_TREE ? active_queue.get() : pending_queue.get();
+  DCHECK(next_queue && !next_queue->IsEmpty());
 
-  Tile* tile = **next_iterator;
+  Tile* tile = next_queue->Top();
   DCHECK(std::find(returned_shared_tiles.begin(),
                    returned_shared_tiles.end(),
                    tile) == returned_shared_tiles.end());
   return tile;
 }
 
-void EvictionTilePriorityQueue::PairedPictureLayerQueue::Pop(
+void EvictionTilePriorityQueue::PairedTilingSetQueue::Pop(
     TreePriority tree_priority) {
   DCHECK(!IsEmpty());
 
   WhichTree next_tree = NextTileIteratorTree(tree_priority);
-  PictureLayerImpl::LayerEvictionTileIterator* next_iterator =
-      next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator;
-  DCHECK(*next_iterator);
-  returned_shared_tiles.push_back(**next_iterator);
-  ++(*next_iterator);
+  TilingSetEvictionQueue* next_queue =
+      next_tree == ACTIVE_TREE ? active_queue.get() : pending_queue.get();
+  DCHECK(next_queue && !next_queue->IsEmpty());
+  returned_shared_tiles.push_back(next_queue->Top());
+  next_queue->Pop();
 
   if (IsEmpty())
     return;
 
   next_tree = NextTileIteratorTree(tree_priority);
-  next_iterator =
-      next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator;
+  next_queue =
+      next_tree == ACTIVE_TREE ? active_queue.get() : pending_queue.get();
   while (std::find(returned_shared_tiles.begin(),
                    returned_shared_tiles.end(),
-                   **next_iterator) != returned_shared_tiles.end()) {
-    ++(*next_iterator);
+                   next_queue->Top()) != returned_shared_tiles.end()) {
+    next_queue->Pop();
     if (IsEmpty())
       break;
     next_tree = NextTileIteratorTree(tree_priority);
-    next_iterator =
-        next_tree == ACTIVE_TREE ? &active_iterator : &pending_iterator;
+    next_queue =
+        next_tree == ACTIVE_TREE ? active_queue.get() : pending_queue.get();
   }
 }
 
 WhichTree
-EvictionTilePriorityQueue::PairedPictureLayerQueue::NextTileIteratorTree(
+EvictionTilePriorityQueue::PairedTilingSetQueue::NextTileIteratorTree(
     TreePriority tree_priority) const {
   DCHECK(!IsEmpty());
 
   // If we only have one iterator with tiles, return it.
-  if (!active_iterator)
+  if (!active_queue || active_queue->IsEmpty())
     return PENDING_TREE;
-  if (!pending_iterator)
+  if (!pending_queue || pending_queue->IsEmpty())
     return ACTIVE_TREE;
 
-  const Tile* active_tile = *active_iterator;
-  const Tile* pending_tile = *pending_iterator;
+  const Tile* active_tile = active_queue->Top();
+  const Tile* pending_tile = pending_queue->Top();
   if (active_tile == pending_tile)
     return ACTIVE_TREE;
 
diff --git a/cc/resources/eviction_tile_priority_queue.h b/cc/resources/eviction_tile_priority_queue.h
index e91f0d2..6f5d964 100644
--- a/cc/resources/eviction_tile_priority_queue.h
+++ b/cc/resources/eviction_tile_priority_queue.h
@@ -11,16 +11,17 @@
 #include "cc/base/cc_export.h"
 #include "cc/layers/picture_layer_impl.h"
 #include "cc/resources/tile_priority.h"
+#include "cc/resources/tiling_set_eviction_queue.h"
 
 namespace cc {
 
 class CC_EXPORT EvictionTilePriorityQueue {
  public:
-  struct PairedPictureLayerQueue {
-    PairedPictureLayerQueue();
-    PairedPictureLayerQueue(const PictureLayerImpl::Pair& layer_pair,
-                            TreePriority tree_priority);
-    ~PairedPictureLayerQueue();
+  struct PairedTilingSetQueue {
+    PairedTilingSetQueue();
+    PairedTilingSetQueue(const PictureLayerImpl::Pair& layer_pair,
+                         TreePriority tree_priority);
+    ~PairedTilingSetQueue();
 
     bool IsEmpty() const;
     Tile* Top(TreePriority tree_priority);
@@ -28,8 +29,8 @@
 
     WhichTree NextTileIteratorTree(TreePriority tree_priority) const;
 
-    PictureLayerImpl::LayerEvictionTileIterator active_iterator;
-    PictureLayerImpl::LayerEvictionTileIterator pending_iterator;
+    scoped_ptr<TilingSetEvictionQueue> active_queue;
+    scoped_ptr<TilingSetEvictionQueue> pending_queue;
 
     // TODO(vmpstr): Investigate removing this.
     std::vector<Tile*> returned_shared_tiles;
@@ -48,9 +49,9 @@
 
  private:
   // TODO(vmpstr): This is potentially unnecessary if it becomes the case that
-  // PairedPictureLayerQueue is fast enough to copy. In that case, we can use
-  // objects directly (ie std::vector<PairedPictureLayerQueue>).
-  ScopedPtrVector<PairedPictureLayerQueue> paired_queues_;
+  // PairedTilingSetQueue is fast enough to copy. In that case, we can use
+  // objects directly (ie std::vector<PairedTilingSetQueue>).
+  ScopedPtrVector<PairedTilingSetQueue> paired_queues_;
   TreePriority tree_priority_;
 
   DISALLOW_COPY_AND_ASSIGN(EvictionTilePriorityQueue);
diff --git a/cc/resources/filter_display_item.cc b/cc/resources/filter_display_item.cc
new file mode 100644
index 0000000..63bfeee
--- /dev/null
+++ b/cc/resources/filter_display_item.cc
@@ -0,0 +1,75 @@
+// Copyright 2014 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/resources/filter_display_item.h"
+
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkImageFilter.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkXfermode.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+
+FilterDisplayItem::FilterDisplayItem(skia::RefPtr<SkImageFilter> filter,
+                                     gfx::RectF bounds)
+    : filter_(filter), bounds_(bounds) {
+}
+
+FilterDisplayItem::~FilterDisplayItem() {
+}
+
+void FilterDisplayItem::Raster(SkCanvas* canvas,
+                               SkDrawPictureCallback* callback) const {
+  canvas->save();
+  SkRect boundaries;
+  filter_->computeFastBounds(gfx::RectFToSkRect(bounds_), &boundaries);
+  canvas->translate(bounds_.x(), bounds_.y());
+  boundaries.offset(-bounds_.x(), -bounds_.y());
+
+  SkPaint paint;
+  paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
+  paint.setImageFilter(filter_.get());
+  canvas->saveLayer(&boundaries, &paint);
+
+  canvas->translate(-bounds_.x(), -bounds_.y());
+}
+
+bool FilterDisplayItem::IsSuitableForGpuRasterization() const {
+  return true;
+}
+
+int FilterDisplayItem::ApproximateOpCount() const {
+  return 1;
+}
+
+size_t FilterDisplayItem::PictureMemoryUsage() const {
+  return sizeof(skia::RefPtr<SkImageFilter>) + sizeof(gfx::RectF);
+}
+
+EndFilterDisplayItem::EndFilterDisplayItem() {
+}
+
+EndFilterDisplayItem::~EndFilterDisplayItem() {
+}
+
+void EndFilterDisplayItem::Raster(SkCanvas* canvas,
+                                  SkDrawPictureCallback* callback) const {
+  canvas->restore();
+  canvas->restore();
+}
+
+bool EndFilterDisplayItem::IsSuitableForGpuRasterization() const {
+  return true;
+}
+
+int EndFilterDisplayItem::ApproximateOpCount() const {
+  return 0;
+}
+
+size_t EndFilterDisplayItem::PictureMemoryUsage() const {
+  return 0;
+}
+
+}  // namespace cc
diff --git a/cc/resources/filter_display_item.h b/cc/resources/filter_display_item.h
new file mode 100644
index 0000000..4c1b265
--- /dev/null
+++ b/cc/resources/filter_display_item.h
@@ -0,0 +1,64 @@
+// Copyright 2014 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_RESOURCES_FILTER_DISPLAY_ITEM_H_
+#define CC_RESOURCES_FILTER_DISPLAY_ITEM_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/resources/display_item.h"
+#include "skia/ext/refptr.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+class SkImageFilter;
+
+namespace cc {
+
+class CC_EXPORT FilterDisplayItem : public DisplayItem {
+ public:
+  virtual ~FilterDisplayItem();
+
+  static scoped_ptr<FilterDisplayItem> Create(
+      skia::RefPtr<SkImageFilter> filter,
+      gfx::RectF bounds) {
+    return make_scoped_ptr(new FilterDisplayItem(filter, bounds));
+  }
+
+  void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+  bool IsSuitableForGpuRasterization() const override;
+  int ApproximateOpCount() const override;
+  size_t PictureMemoryUsage() const override;
+
+ protected:
+  FilterDisplayItem(skia::RefPtr<SkImageFilter> filter, gfx::RectF bounds);
+
+ private:
+  skia::RefPtr<SkImageFilter> filter_;
+  gfx::RectF bounds_;
+};
+
+class CC_EXPORT EndFilterDisplayItem : public DisplayItem {
+ public:
+  virtual ~EndFilterDisplayItem();
+
+  static scoped_ptr<EndFilterDisplayItem> Create() {
+    return make_scoped_ptr(new EndFilterDisplayItem());
+  }
+
+  void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+  bool IsSuitableForGpuRasterization() const override;
+  int ApproximateOpCount() const override;
+  size_t PictureMemoryUsage() const override;
+
+ protected:
+  EndFilterDisplayItem();
+};
+
+}  // namespace cc
+
+#endif  // CC_RESOURCES_FILTER_DISPLAY_ITEM_H_
diff --git a/cc/resources/managed_tile_state.cc b/cc/resources/managed_tile_state.cc
index 2841711..a60c28af 100644
--- a/cc/resources/managed_tile_state.cc
+++ b/cc/resources/managed_tile_state.cc
@@ -12,38 +12,9 @@
 
 namespace cc {
 
-std::string ManagedTileBinToString(ManagedTileBin bin) {
-  switch (bin) {
-    case NOW_AND_READY_TO_DRAW_BIN:
-      return "NOW_AND_READY_TO_DRAW_BIN";
-    case NOW_BIN:
-      return "NOW_BIN";
-    case SOON_BIN:
-      return "SOON_BIN";
-    case EVENTUALLY_AND_ACTIVE_BIN:
-      return "EVENTUALLY_AND_ACTIVE_BIN";
-    case EVENTUALLY_BIN:
-      return "EVENTUALLY_BIN";
-    case AT_LAST_AND_ACTIVE_BIN:
-      return "AT_LAST_AND_ACTIVE_BIN";
-    case AT_LAST_BIN:
-      return "AT_LAST_BIN";
-    case NEVER_BIN:
-      return "NEVER_BIN";
-    case NUM_BINS:
-      NOTREACHED();
-      return "Invalid Bin (NUM_BINS)";
-  }
-  return "Invalid Bin (UNKNOWN)";
-}
-
 ManagedTileState::ManagedTileState()
-    : bin(NEVER_BIN),
-      resolution(NON_IDEAL_RESOLUTION),
-      required_for_activation(false),
+    : resolution(NON_IDEAL_RESOLUTION),
       priority_bin(TilePriority::EVENTUALLY),
-      distance_to_visible(std::numeric_limits<float>::infinity()),
-      visible_and_ready_to_draw(false),
       scheduled_priority(0) {
 }
 
@@ -77,12 +48,8 @@
 
   state->SetBoolean("has_resource", has_resource);
   state->SetBoolean("is_using_gpu_memory", is_using_gpu_memory);
-  state->SetString("bin", ManagedTileBinToString(bin));
   state->SetString("resolution", TileResolutionToString(resolution));
   state->SetString("priority_bin", TilePriorityBinToString(priority_bin));
-  state->SetDouble("distance_to_visible",
-                   MathUtil::AsFloatSafely(distance_to_visible));
-  state->SetBoolean("required_for_activation", required_for_activation);
   state->SetBoolean("is_solid_color",
                     draw_info.mode_ == DrawInfo::SOLID_COLOR_MODE);
   state->SetBoolean("is_transparent",
diff --git a/cc/resources/managed_tile_state.h b/cc/resources/managed_tile_state.h
index 58b77c6..a0905c7 100644
--- a/cc/resources/managed_tile_state.h
+++ b/cc/resources/managed_tile_state.h
@@ -15,24 +15,6 @@
 
 namespace cc {
 
-class TileManager;
-
-// Tile manager classifying tiles into a few basic bins:
-enum ManagedTileBin {
-  NOW_AND_READY_TO_DRAW_BIN = 0,  // Ready to draw and within viewport.
-  NOW_BIN = 1,                    // Needed ASAP.
-  SOON_BIN = 2,                   // Impl-side version of prepainting.
-  EVENTUALLY_AND_ACTIVE_BIN = 3,  // Nice to have, and has a task or resource.
-  EVENTUALLY_BIN = 4,             // Nice to have, if we've got memory and time.
-  AT_LAST_AND_ACTIVE_BIN = 5,     // Only do this after all other bins.
-  AT_LAST_BIN = 6,                // Only do this after all other bins.
-  NEVER_BIN = 7,                  // Dont bother.
-  NUM_BINS = 8
-  // NOTE: Be sure to update ManagedTileBinAsValue and kBinPolicyMap when adding
-  // or reordering fields.
-};
-scoped_ptr<base::Value> ManagedTileBinAsValue(ManagedTileBin bin);
-
 // This is state that is specific to a tile that is
 // managed by the TileManager.
 class CC_EXPORT ManagedTileState {
@@ -107,13 +89,8 @@
   DrawInfo draw_info;
   scoped_refptr<RasterTask> raster_task;
 
-  ManagedTileBin bin;
-
   TileResolution resolution;
-  bool required_for_activation;
   TilePriority::PriorityBin priority_bin;
-  float distance_to_visible;
-  bool visible_and_ready_to_draw;
 
   // Priority for this state from the last time we assigned memory.
   unsigned scheduled_priority;
diff --git a/cc/resources/picture.cc b/cc/resources/picture.cc
index 9a45ad1..5b90571 100644
--- a/cc/resources/picture.cc
+++ b/cc/resources/picture.cc
@@ -25,6 +25,7 @@
 #include "third_party/skia/include/core/SkPictureRecorder.h"
 #include "third_party/skia/include/core/SkStream.h"
 #include "third_party/skia/include/utils/SkNullCanvas.h"
+#include "third_party/skia/include/utils/SkPictureUtils.h"
 #include "ui/gfx/codec/jpeg_codec.h"
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/geometry/rect_conversions.h"
@@ -192,6 +193,11 @@
   return picture_->approximateOpCount();
 }
 
+size_t Picture::ApproximateMemoryUsage() const {
+  DCHECK(picture_);
+  return SkPictureUtils::ApproximateBytesUsed(picture_.get());
+}
+
 bool Picture::HasText() const {
   DCHECK(picture_);
   return picture_->hasText();
diff --git a/cc/resources/picture.h b/cc/resources/picture.h
index 1677309..771d715 100644
--- a/cc/resources/picture.h
+++ b/cc/resources/picture.h
@@ -67,6 +67,7 @@
 
   bool IsSuitableForGpuRasterization() const;
   int ApproximateOpCount() const;
+  size_t ApproximateMemoryUsage() const;
 
   bool HasText() const;
 
diff --git a/cc/resources/picture_layer_tiling.cc b/cc/resources/picture_layer_tiling.cc
index 9d8ea84..e9e3b86 100644
--- a/cc/resources/picture_layer_tiling.cc
+++ b/cc/resources/picture_layer_tiling.cc
@@ -1216,50 +1216,4 @@
   return *this;
 }
 
-PictureLayerTiling::TilingEvictionTileIterator::TilingEvictionTileIterator()
-    : eviction_tiles_(NULL), current_eviction_tiles_index_(0u) {
-}
-
-PictureLayerTiling::TilingEvictionTileIterator::TilingEvictionTileIterator(
-    PictureLayerTiling* tiling,
-    TreePriority tree_priority,
-    EvictionCategory category)
-    : eviction_tiles_(tiling->GetEvictionTiles(tree_priority, category)),
-      // Note: initializing to "0 - 1" works as overflow is well defined for
-      // unsigned integers.
-      current_eviction_tiles_index_(static_cast<size_t>(0) - 1) {
-  DCHECK(eviction_tiles_);
-  ++(*this);
-}
-
-PictureLayerTiling::TilingEvictionTileIterator::~TilingEvictionTileIterator() {
-}
-
-PictureLayerTiling::TilingEvictionTileIterator::operator bool() const {
-  return eviction_tiles_ &&
-         current_eviction_tiles_index_ != eviction_tiles_->size();
-}
-
-Tile* PictureLayerTiling::TilingEvictionTileIterator::operator*() {
-  DCHECK(*this);
-  return (*eviction_tiles_)[current_eviction_tiles_index_];
-}
-
-const Tile* PictureLayerTiling::TilingEvictionTileIterator::operator*() const {
-  DCHECK(*this);
-  return (*eviction_tiles_)[current_eviction_tiles_index_];
-}
-
-PictureLayerTiling::TilingEvictionTileIterator&
-PictureLayerTiling::TilingEvictionTileIterator::
-operator++() {
-  DCHECK(*this);
-  do {
-    ++current_eviction_tiles_index_;
-  } while (current_eviction_tiles_index_ != eviction_tiles_->size() &&
-           !(*eviction_tiles_)[current_eviction_tiles_index_]->HasResources());
-
-  return *this;
-}
-
 }  // namespace cc
diff --git a/cc/resources/picture_layer_tiling.h b/cc/resources/picture_layer_tiling.h
index e1ccde4..daa0485 100644
--- a/cc/resources/picture_layer_tiling.h
+++ b/cc/resources/picture_layer_tiling.h
@@ -118,24 +118,6 @@
     TilingData::SpiralDifferenceIterator spiral_iterator_;
   };
 
-  class CC_EXPORT TilingEvictionTileIterator {
-   public:
-    TilingEvictionTileIterator();
-    TilingEvictionTileIterator(PictureLayerTiling* tiling,
-                               TreePriority tree_priority,
-                               EvictionCategory category);
-    ~TilingEvictionTileIterator();
-
-    operator bool() const;
-    const Tile* operator*() const;
-    Tile* operator*();
-    TilingEvictionTileIterator& operator++();
-
-   private:
-    const std::vector<Tile*>* eviction_tiles_;
-    size_t current_eviction_tiles_index_;
-  };
-
   ~PictureLayerTiling();
 
   // Create a tiling with no tiles.  CreateTiles must be called to add some.
@@ -299,7 +281,7 @@
  protected:
   friend class CoverageIterator;
   friend class TilingRasterTileIterator;
-  friend class TilingEvictionTileIterator;
+  friend class TilingSetEvictionQueue;
 
   typedef std::pair<int, int> TileMapKey;
   typedef base::hash_map<TileMapKey, scoped_refptr<Tile>> TileMap;
diff --git a/cc/resources/picture_layer_tiling_perftest.cc b/cc/resources/picture_layer_tiling_perftest.cc
index 55d495b..3944e46 100644
--- a/cc/resources/picture_layer_tiling_perftest.cc
+++ b/cc/resources/picture_layer_tiling_perftest.cc
@@ -178,98 +178,6 @@
                            true);
   }
 
-  void RunEvictionIteratorConstructTest(const std::string& test_name,
-                                        const gfx::Rect& viewport) {
-    gfx::Size bounds(viewport.size());
-    picture_layer_tiling_ =
-        PictureLayerTiling::Create(1, bounds, &picture_layer_tiling_client_);
-    picture_layer_tiling_client_.set_tree(ACTIVE_TREE);
-    picture_layer_tiling_->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
-                                                    Occlusion());
-
-    timer_.Reset();
-    TreePriority priorities[] = {SAME_PRIORITY_FOR_BOTH_TREES,
-                                 SMOOTHNESS_TAKES_PRIORITY,
-                                 NEW_CONTENT_TAKES_PRIORITY};
-    int priority_count = 0;
-    do {
-      PictureLayerTiling::TilingEvictionTileIterator it(
-          picture_layer_tiling_.get(),
-          priorities[priority_count],
-          PictureLayerTiling::NOW);
-      priority_count = (priority_count + 1) % arraysize(priorities);
-      timer_.NextLap();
-    } while (!timer_.HasTimeLimitExpired());
-
-    perf_test::PrintResult("tiling_eviction_tile_iterator_construct",
-                           "",
-                           test_name,
-                           timer_.LapsPerSecond(),
-                           "runs/s",
-                           true);
-  }
-
-  void RunEvictionIteratorConstructAndIterateTest(const std::string& test_name,
-                                                  int num_tiles,
-                                                  const gfx::Rect& viewport) {
-    gfx::Size bounds(10000, 10000);
-    picture_layer_tiling_ =
-        PictureLayerTiling::Create(1, bounds, &picture_layer_tiling_client_);
-    picture_layer_tiling_client_.set_tree(ACTIVE_TREE);
-    picture_layer_tiling_->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
-                                                    Occlusion());
-
-    TreePriority priorities[] = {SAME_PRIORITY_FOR_BOTH_TREES,
-                                 SMOOTHNESS_TAKES_PRIORITY,
-                                 NEW_CONTENT_TAKES_PRIORITY};
-
-    // Ensure all tiles have resources.
-    std::vector<Tile*> all_tiles = picture_layer_tiling_->AllTilesForTesting();
-    for (std::vector<Tile*>::iterator tile_it = all_tiles.begin();
-         tile_it != all_tiles.end();
-         ++tile_it) {
-      Tile* tile = *tile_it;
-      ManagedTileState::DrawInfo& draw_info = tile->draw_info();
-      draw_info.SetResourceForTesting(
-          ScopedResource::Create(resource_provider_.get()).Pass());
-    }
-
-    int priority_count = 0;
-    timer_.Reset();
-    do {
-      int count = num_tiles;
-      PictureLayerTiling::TilingEvictionTileIterator it(
-          picture_layer_tiling_.get(),
-          priorities[priority_count],
-          PictureLayerTiling::EVENTUALLY);
-      while (count--) {
-        ASSERT_TRUE(it) << "count: " << count;
-        ASSERT_TRUE(*it != NULL) << "count: " << count;
-        ++it;
-      }
-      priority_count = (priority_count + 1) % arraysize(priorities);
-      timer_.NextLap();
-    } while (!timer_.HasTimeLimitExpired());
-
-    // Remove all resources from tiles to make sure the tile version destructor
-    // doesn't complain.
-    for (std::vector<Tile*>::iterator tile_it = all_tiles.begin();
-         tile_it != all_tiles.end();
-         ++tile_it) {
-      Tile* tile = *tile_it;
-      ManagedTileState::DrawInfo& draw_info = tile->draw_info();
-      draw_info.SetResourceForTesting(nullptr);
-    }
-
-    perf_test::PrintResult(
-        "tiling_eviction_tile_iterator_construct_and_iterate",
-        "",
-        test_name,
-        timer_.LapsPerSecond(),
-        "runs/s",
-        true);
-  }
-
  private:
   FakePictureLayerTilingClient picture_layer_tiling_client_;
   scoped_ptr<PictureLayerTiling> picture_layer_tiling_;
@@ -333,27 +241,6 @@
       "64_500x500", 64, gfx::Rect(0, 0, 500, 500));
 }
 
-TEST_F(PictureLayerTilingPerfTest, TilingEvictionTileIteratorConstruct) {
-  RunEvictionIteratorConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100));
-  RunEvictionIteratorConstructTest("50_0_100x100", gfx::Rect(50, 0, 100, 100));
-  RunEvictionIteratorConstructTest("100_0_100x100",
-                                   gfx::Rect(100, 0, 100, 100));
-  RunEvictionIteratorConstructTest("150_0_100x100",
-                                   gfx::Rect(150, 0, 100, 100));
-}
-
-TEST_F(PictureLayerTilingPerfTest,
-       TilingEvictionTileIteratorConstructAndIterate) {
-  RunEvictionIteratorConstructAndIterateTest(
-      "32_100x100", 32, gfx::Rect(0, 0, 100, 100));
-  RunEvictionIteratorConstructAndIterateTest(
-      "32_500x500", 32, gfx::Rect(0, 0, 500, 500));
-  RunEvictionIteratorConstructAndIterateTest(
-      "64_100x100", 64, gfx::Rect(0, 0, 100, 100));
-  RunEvictionIteratorConstructAndIterateTest(
-      "64_500x500", 64, gfx::Rect(0, 0, 500, 500));
-}
-
 }  // namespace
 
 }  // namespace cc
diff --git a/cc/resources/picture_layer_tiling_unittest.cc b/cc/resources/picture_layer_tiling_unittest.cc
index b982dc1..9190b98 100644
--- a/cc/resources/picture_layer_tiling_unittest.cc
+++ b/cc/resources/picture_layer_tiling_unittest.cc
@@ -1247,102 +1247,6 @@
   EXPECT_EQ(exists, tile != NULL) << geometry_rect.ToString();
 }
 
-TEST(PictureLayerTilingTest, TilingEvictionTileIteratorStaticViewport) {
-  FakeOutputSurfaceClient output_surface_client;
-  scoped_ptr<FakeOutputSurface> output_surface = FakeOutputSurface::Create3d();
-  CHECK(output_surface->BindToClient(&output_surface_client));
-  TestSharedBitmapManager shared_bitmap_manager;
-  scoped_ptr<ResourceProvider> resource_provider = ResourceProvider::Create(
-      output_surface.get(), &shared_bitmap_manager, NULL, NULL, 0, false, 1);
-
-  FakePictureLayerTilingClient client(resource_provider.get());
-  scoped_ptr<TestablePictureLayerTiling> tiling;
-
-  gfx::Rect viewport(50, 50, 100, 100);
-  gfx::Size layer_bounds(2000, 2000);
-
-  client.SetTileSize(gfx::Size(30, 30));
-  client.set_tree(ACTIVE_TREE);
-
-  tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client);
-  tiling->ComputeTilePriorityRects(viewport, 1.0f, 1.0, Occlusion());
-  tiling->UpdateAllTilePrioritiesForTesting();
-
-  PictureLayerTiling::TilingRasterTileIterator empty_iterator;
-  EXPECT_FALSE(empty_iterator);
-
-  std::vector<Tile*> all_tiles = tiling->AllTilesForTesting();
-
-  PictureLayerTiling::TilingEvictionTileIterator it(
-      tiling.get(), SMOOTHNESS_TAKES_PRIORITY, PictureLayerTiling::NOW);
-
-  // Tiles don't have resources to evict.
-  EXPECT_FALSE(it);
-
-  // Sanity check.
-  EXPECT_EQ(5184u, all_tiles.size());
-
-  client.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
-
-  std::set<Tile*> all_tiles_set(all_tiles.begin(), all_tiles.end());
-
-  std::set<Tile*> eviction_tiles;
-
-  it = PictureLayerTiling::TilingEvictionTileIterator(
-      tiling.get(), SMOOTHNESS_TAKES_PRIORITY, PictureLayerTiling::EVENTUALLY);
-  EXPECT_TRUE(it);
-  for (; it; ++it) {
-    Tile* tile = *it;
-    EXPECT_TRUE(tile);
-    EXPECT_EQ(TilePriority::EVENTUALLY,
-              tile->priority(ACTIVE_TREE).priority_bin);
-    EXPECT_FALSE(tile->required_for_activation());
-    eviction_tiles.insert(tile);
-  }
-
-  it = PictureLayerTiling::TilingEvictionTileIterator(
-      tiling.get(), SMOOTHNESS_TAKES_PRIORITY, PictureLayerTiling::SOON);
-  EXPECT_TRUE(it);
-  for (; it; ++it) {
-    Tile* tile = *it;
-    EXPECT_TRUE(tile);
-    EXPECT_EQ(TilePriority::SOON, tile->priority(ACTIVE_TREE).priority_bin);
-    EXPECT_FALSE(tile->required_for_activation());
-    eviction_tiles.insert(tile);
-  }
-
-  it = PictureLayerTiling::TilingEvictionTileIterator(
-      tiling.get(), SMOOTHNESS_TAKES_PRIORITY, PictureLayerTiling::NOW);
-  EXPECT_TRUE(it);
-  for (; it; ++it) {
-    Tile* tile = *it;
-    EXPECT_TRUE(tile);
-    EXPECT_EQ(TilePriority::NOW, tile->priority(ACTIVE_TREE).priority_bin);
-    EXPECT_FALSE(tile->required_for_activation());
-    eviction_tiles.insert(tile);
-  }
-
-  it = PictureLayerTiling::TilingEvictionTileIterator(
-      tiling.get(),
-      SMOOTHNESS_TAKES_PRIORITY,
-      PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION);
-  EXPECT_FALSE(it);
-
-  EXPECT_GT(all_tiles_set.size(), 0u);
-  EXPECT_EQ(all_tiles_set, eviction_tiles);
-
-  EXPECT_TRUE(tiling->eviction_tiles_cache_valid());
-  tiling->RemoveTileAt(0, 0, nullptr);
-  EXPECT_FALSE(tiling->eviction_tiles_cache_valid());
-
-  it = PictureLayerTiling::TilingEvictionTileIterator(
-      tiling.get(), SMOOTHNESS_TAKES_PRIORITY,
-      PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION);
-  EXPECT_TRUE(tiling->eviction_tiles_cache_valid());
-  tiling->Reset();
-  EXPECT_FALSE(tiling->eviction_tiles_cache_valid());
-}
-
 TEST_F(PictureLayerTilingIteratorTest, TilesExist) {
   gfx::Size layer_bounds(1099, 801);
   Initialize(gfx::Size(100, 100), 1.f, layer_bounds);
diff --git a/cc/resources/picture_pile_impl.cc b/cc/resources/picture_pile_impl.cc
index 2655d24..5cd7bd6 100644
--- a/cc/resources/picture_pile_impl.cc
+++ b/cc/resources/picture_pile_impl.cc
@@ -4,11 +4,13 @@
 
 #include <algorithm>
 #include <limits>
+#include <set>
 
 #include "base/debug/trace_event.h"
 #include "cc/base/region.h"
 #include "cc/debug/debug_colors.h"
 #include "cc/resources/picture_pile_impl.h"
+#include "cc/resources/raster_source_helper.h"
 #include "skia/ext/analysis_canvas.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkPictureRecorder.h"
@@ -87,62 +89,9 @@
 void PicturePileImpl::PlaybackToCanvas(SkCanvas* canvas,
                                        const gfx::Rect& canvas_rect,
                                        float contents_scale) const {
-  canvas->discard();
-  if (clear_canvas_with_debug_color_) {
-    // Any non-painted areas in the content bounds will be left in this color.
-    canvas->clear(DebugColors::NonPaintedFillColor());
-  }
-
-  // If this picture has opaque contents, it is guaranteeing that it will
-  // draw an opaque rect the size of the layer.  If it is not, then we must
-  // clear this canvas ourselves.
-  if (requires_clear_) {
-    TRACE_EVENT_INSTANT0("cc", "SkCanvas::clear", TRACE_EVENT_SCOPE_THREAD);
-    // Clearing is about ~4x faster than drawing a rect even if the content
-    // isn't covering a majority of the canvas.
-    canvas->clear(SK_ColorTRANSPARENT);
-  } else {
-    // Even if completely covered, for rasterizations that touch the edge of the
-    // layer, we also need to raster the background color underneath the last
-    // texel (since the recording won't cover it) and outside the last texel
-    // (due to linear filtering when using this texture).
-    gfx::Rect content_tiling_rect = gfx::ToEnclosingRect(
-        gfx::ScaleRect(gfx::Rect(tiling_.tiling_size()), contents_scale));
-
-    // The final texel of content may only be partially covered by a
-    // rasterization; this rect represents the content rect that is fully
-    // covered by content.
-    gfx::Rect deflated_content_tiling_rect = content_tiling_rect;
-    deflated_content_tiling_rect.Inset(0, 0, 1, 1);
-    if (!deflated_content_tiling_rect.Contains(canvas_rect)) {
-      if (clear_canvas_with_debug_color_) {
-        // Any non-painted areas outside of the content bounds are left in
-        // this color.  If this is seen then it means that cc neglected to
-        // rerasterize a tile that used to intersect with the content rect
-        // after the content bounds grew.
-        canvas->save();
-        canvas->translate(-canvas_rect.x(), -canvas_rect.y());
-        canvas->clipRect(gfx::RectToSkRect(content_tiling_rect),
-                         SkRegion::kDifference_Op);
-        canvas->drawColor(DebugColors::MissingResizeInvalidations(),
-                          SkXfermode::kSrc_Mode);
-        canvas->restore();
-      }
-
-      // Drawing at most 2 x 2 x (canvas width + canvas height) texels is 2-3X
-      // faster than clearing, so special case this.
-      canvas->save();
-      canvas->translate(-canvas_rect.x(), -canvas_rect.y());
-      gfx::Rect inflated_content_tiling_rect = content_tiling_rect;
-      inflated_content_tiling_rect.Inset(0, 0, -1, -1);
-      canvas->clipRect(gfx::RectToSkRect(inflated_content_tiling_rect),
-                       SkRegion::kReplace_Op);
-      canvas->clipRect(gfx::RectToSkRect(deflated_content_tiling_rect),
-                       SkRegion::kDifference_Op);
-      canvas->drawColor(background_color_, SkXfermode::kSrc_Mode);
-      canvas->restore();
-    }
-  }
+  RasterSourceHelper::PrepareForPlaybackToCanvas(
+      canvas, canvas_rect, gfx::Rect(tiling_.tiling_size()), contents_scale,
+      background_color_, clear_canvas_with_debug_color_, requires_clear_);
 
   RasterCommon(canvas,
                NULL,
@@ -319,6 +268,19 @@
   return picture;
 }
 
+size_t PicturePileImpl::GetPictureMemoryUsage() const {
+  // Place all pictures in a set to de-dupe.
+  size_t total_size = 0;
+  std::set<const Picture*> pictures_seen;
+  for (const auto& map_value : picture_map_) {
+    const Picture* picture = map_value.second.GetPicture();
+    if (picture && pictures_seen.insert(picture).second)
+      total_size += picture->ApproximateMemoryUsage();
+  }
+
+  return total_size;
+}
+
 void PicturePileImpl::PerformSolidColorAnalysis(
     const gfx::Rect& content_rect,
     float contents_scale,
diff --git a/cc/resources/picture_pile_impl.h b/cc/resources/picture_pile_impl.h
index d7d0399..3e0dd78 100644
--- a/cc/resources/picture_pile_impl.h
+++ b/cc/resources/picture_pile_impl.h
@@ -67,6 +67,7 @@
   void DidBeginTracing() override;
   void AsValueInto(base::debug::TracedValue* array) const override;
   skia::RefPtr<SkPicture> GetFlattenedPicture() override;
+  size_t GetPictureMemoryUsage() const override;
 
   // Iterator used to return SkPixelRefs from this picture pile.
   // Public for testing.
diff --git a/cc/resources/raster_source.h b/cc/resources/raster_source.h
index 3584436..88c9962 100644
--- a/cc/resources/raster_source.h
+++ b/cc/resources/raster_source.h
@@ -18,6 +18,8 @@
 
 namespace cc {
 
+class Picture;
+
 class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> {
  public:
   struct CC_EXPORT SolidColorAnalysis {
@@ -92,6 +94,7 @@
   virtual void DidBeginTracing() = 0;
   virtual void AsValueInto(base::debug::TracedValue* array) const = 0;
   virtual skia::RefPtr<SkPicture> GetFlattenedPicture() = 0;
+  virtual size_t GetPictureMemoryUsage() const = 0;
 
   // Return true if LCD anti-aliasing may be used when rastering text.
   virtual bool CanUseLCDText() const = 0;
diff --git a/cc/resources/raster_source_helper.cc b/cc/resources/raster_source_helper.cc
new file mode 100644
index 0000000..f7ef305
--- /dev/null
+++ b/cc/resources/raster_source_helper.cc
@@ -0,0 +1,81 @@
+// Copyright 2014 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/resources/raster_source_helper.h"
+
+#include "base/debug/trace_event.h"
+#include "cc/debug/debug_colors.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+
+void RasterSourceHelper::PrepareForPlaybackToCanvas(
+    SkCanvas* canvas,
+    const gfx::Rect& canvas_rect,
+    const gfx::Rect& source_rect,
+    float contents_scale,
+    SkColor background_color,
+    bool clear_canvas_with_debug_color,
+    bool requires_clear) {
+  canvas->discard();
+  if (clear_canvas_with_debug_color) {
+    // Any non-painted areas in the content bounds will be left in this color.
+    canvas->clear(DebugColors::NonPaintedFillColor());
+  }
+
+  // If this raster source has opaque contents, it is guaranteeing that it will
+  // draw an opaque rect the size of the layer.  If it is not, then we must
+  // clear this canvas ourselves.
+  if (requires_clear) {
+    TRACE_EVENT_INSTANT0("cc", "SkCanvas::clear", TRACE_EVENT_SCOPE_THREAD);
+    // Clearing is about ~4x faster than drawing a rect even if the content
+    // isn't covering a majority of the canvas.
+    canvas->clear(SK_ColorTRANSPARENT);
+  } else {
+    // Even if completely covered, for rasterizations that touch the edge of the
+    // layer, we also need to raster the background color underneath the last
+    // texel (since the recording won't cover it) and outside the last texel
+    // (due to linear filtering when using this texture).
+    gfx::Rect content_rect =
+        gfx::ToEnclosingRect(gfx::ScaleRect(source_rect, contents_scale));
+
+    // The final texel of content may only be partially covered by a
+    // rasterization; this rect represents the content rect that is fully
+    // covered by content.
+    gfx::Rect deflated_content_rect = content_rect;
+    deflated_content_rect.Inset(0, 0, 1, 1);
+    if (!deflated_content_rect.Contains(canvas_rect)) {
+      if (clear_canvas_with_debug_color) {
+        // Any non-painted areas outside of the content bounds are left in
+        // this color.  If this is seen then it means that cc neglected to
+        // rerasterize a tile that used to intersect with the content rect
+        // after the content bounds grew.
+        canvas->save();
+        canvas->translate(-canvas_rect.x(), -canvas_rect.y());
+        canvas->clipRect(gfx::RectToSkRect(content_rect),
+                         SkRegion::kDifference_Op);
+        canvas->drawColor(DebugColors::MissingResizeInvalidations(),
+                          SkXfermode::kSrc_Mode);
+        canvas->restore();
+      }
+
+      // Drawing at most 2 x 2 x (canvas width + canvas height) texels is 2-3X
+      // faster than clearing, so special case this.
+      canvas->save();
+      canvas->translate(-canvas_rect.x(), -canvas_rect.y());
+      gfx::Rect inflated_content_rect = content_rect;
+      inflated_content_rect.Inset(0, 0, -1, -1);
+      canvas->clipRect(gfx::RectToSkRect(inflated_content_rect),
+                       SkRegion::kReplace_Op);
+      canvas->clipRect(gfx::RectToSkRect(deflated_content_rect),
+                       SkRegion::kDifference_Op);
+      canvas->drawColor(background_color, SkXfermode::kSrc_Mode);
+      canvas->restore();
+    }
+  }
+}
+
+}  // namespace cc
diff --git a/cc/resources/raster_source_helper.h b/cc/resources/raster_source_helper.h
new file mode 100644
index 0000000..abdea3e
--- /dev/null
+++ b/cc/resources/raster_source_helper.h
@@ -0,0 +1,29 @@
+// Copyright 2014 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_RESOURCES_RASTER_SOURCE_HELPER_H_
+#define CC_RESOURCES_RASTER_SOURCE_HELPER_H_
+
+#include "cc/base/cc_export.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/geometry/rect.h"
+
+class SkCanvas;
+
+namespace cc {
+
+class CC_EXPORT RasterSourceHelper {
+ public:
+  static void PrepareForPlaybackToCanvas(SkCanvas* canvas,
+                                         const gfx::Rect& canvas_rect,
+                                         const gfx::Rect& source_rect,
+                                         float contents_scale,
+                                         SkColor background_color,
+                                         bool clear_canvas_with_debug_color,
+                                         bool requires_clear);
+};
+
+}  // namespace cc
+
+#endif  // CC_RESOURCES_RASTER_SOURCE_HELPER_H_
diff --git a/cc/resources/raster_worker_pool.cc b/cc/resources/raster_worker_pool.cc
index 4511f9d..ca951f6 100644
--- a/cc/resources/raster_worker_pool.cc
+++ b/cc/resources/raster_worker_pool.cc
@@ -206,6 +206,7 @@
     case LUMINANCE_8:
     case RGB_565:
     case ETC1:
+    case RED_8:
       return false;
   }
   NOTREACHED();
diff --git a/cc/resources/resource_format.cc b/cc/resources/resource_format.cc
index 6cd0a93..45581b8 100644
--- a/cc/resources/resource_format.cc
+++ b/cc/resources/resource_format.cc
@@ -17,6 +17,7 @@
     case ALPHA_8:
     case LUMINANCE_8:
     case RGB_565:
+    case RED_8:
       NOTREACHED();
       break;
   }
diff --git a/cc/resources/resource_format.h b/cc/resources/resource_format.h
index b51ac7c..d785ab7 100644
--- a/cc/resources/resource_format.h
+++ b/cc/resources/resource_format.h
@@ -19,7 +19,8 @@
   LUMINANCE_8,
   RGB_565,
   ETC1,
-  RESOURCE_FORMAT_MAX = ETC1,
+  RED_8,
+  RESOURCE_FORMAT_MAX = RED_8,
 };
 
 SkColorType ResourceFormatToSkColorType(ResourceFormat format);
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 636e797..fe7cc00 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -76,6 +76,7 @@
     case LUMINANCE_8:
     case RGB_565:
     case ETC1:
+    case RED_8:
       NOTREACHED();
       break;
   }
@@ -94,6 +95,7 @@
     case LUMINANCE_8:
     case RGB_565:
     case ETC1:
+    case RED_8:
       return false;
   }
   return false;
@@ -125,6 +127,7 @@
     case LUMINANCE_8:
     case RGB_565:
     case ETC1:
+    case RED_8:
       break;
   }
   NOTREACHED();
@@ -1216,6 +1219,7 @@
       use_texture_format_bgra_(false),
       use_texture_usage_hint_(false),
       use_compressed_texture_etc1_(false),
+      yuv_resource_format_(LUMINANCE_8),
       max_texture_size_(0),
       best_texture_format_(RGBA_8888),
       use_rgba_4444_texture_format_(use_rgba_4444_texture_format),
@@ -1254,6 +1258,7 @@
   use_texture_format_bgra_ = caps.gpu.texture_format_bgra8888;
   use_texture_usage_hint_ = caps.gpu.texture_usage;
   use_compressed_texture_etc1_ = caps.gpu.texture_format_etc1;
+  yuv_resource_format_ = caps.gpu.texture_rg ? RED_8 : LUMINANCE_8;
   use_sync_query_ = caps.gpu.sync_query;
 
   GLES2Interface* gl = ContextGL();
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index bfd3ebb..3a8d2e0 100644
--- a/cc/resources/resource_provider.h
+++ b/cc/resources/resource_provider.h
@@ -99,6 +99,7 @@
     return use_rgba_4444_texture_format_ ? RGBA_4444 : best_texture_format_;
   }
   ResourceFormat best_texture_format() const { return best_texture_format_; }
+  ResourceFormat yuv_resource_format() const { return yuv_resource_format_; }
   bool use_sync_query() const { return use_sync_query_; }
   size_t num_resources() const { return resources_.size(); }
 
@@ -578,6 +579,7 @@
   bool use_texture_format_bgra_;
   bool use_texture_usage_hint_;
   bool use_compressed_texture_etc1_;
+  ResourceFormat yuv_resource_format_;
   scoped_ptr<TextureUploader> texture_uploader_;
   int max_texture_size_;
   ResourceFormat best_texture_format_;
@@ -610,6 +612,7 @@
       return 16;
     case ALPHA_8:
     case LUMINANCE_8:
+    case RED_8:
       return 8;
     case ETC1:
       return 4;
@@ -621,13 +624,14 @@
 inline GLenum GLDataType(ResourceFormat format) {
   DCHECK_LE(format, RESOURCE_FORMAT_MAX);
   static const unsigned format_gl_data_type[RESOURCE_FORMAT_MAX + 1] = {
-    GL_UNSIGNED_BYTE,           // RGBA_8888
-    GL_UNSIGNED_SHORT_4_4_4_4,  // RGBA_4444
-    GL_UNSIGNED_BYTE,           // BGRA_8888
-    GL_UNSIGNED_BYTE,           // ALPHA_8
-    GL_UNSIGNED_BYTE,           // LUMINANCE_8
-    GL_UNSIGNED_SHORT_5_6_5,    // RGB_565,
-    GL_UNSIGNED_BYTE            // ETC1
+      GL_UNSIGNED_BYTE,           // RGBA_8888
+      GL_UNSIGNED_SHORT_4_4_4_4,  // RGBA_4444
+      GL_UNSIGNED_BYTE,           // BGRA_8888
+      GL_UNSIGNED_BYTE,           // ALPHA_8
+      GL_UNSIGNED_BYTE,           // LUMINANCE_8
+      GL_UNSIGNED_SHORT_5_6_5,    // RGB_565,
+      GL_UNSIGNED_BYTE,           // ETC1
+      GL_UNSIGNED_BYTE            // RED_8
   };
   return format_gl_data_type[format];
 }
@@ -635,13 +639,14 @@
 inline GLenum GLDataFormat(ResourceFormat format) {
   DCHECK_LE(format, RESOURCE_FORMAT_MAX);
   static const unsigned format_gl_data_format[RESOURCE_FORMAT_MAX + 1] = {
-    GL_RGBA,           // RGBA_8888
-    GL_RGBA,           // RGBA_4444
-    GL_BGRA_EXT,       // BGRA_8888
-    GL_ALPHA,          // ALPHA_8
-    GL_LUMINANCE,      // LUMINANCE_8
-    GL_RGB,            // RGB_565
-    GL_ETC1_RGB8_OES   // ETC1
+      GL_RGBA,           // RGBA_8888
+      GL_RGBA,           // RGBA_4444
+      GL_BGRA_EXT,       // BGRA_8888
+      GL_ALPHA,          // ALPHA_8
+      GL_LUMINANCE,      // LUMINANCE_8
+      GL_RGB,            // RGB_565
+      GL_ETC1_RGB8_OES,  // ETC1
+      GL_RED_EXT         // RED_8
   };
   return format_gl_data_format[format];
 }
diff --git a/cc/resources/shared_bitmap.cc b/cc/resources/shared_bitmap.cc
index 31cf245..1ac0323 100644
--- a/cc/resources/shared_bitmap.cc
+++ b/cc/resources/shared_bitmap.cc
@@ -10,25 +10,13 @@
 
 namespace cc {
 
-SharedBitmap::SharedBitmap(
-    base::SharedMemory* memory,
-    const SharedBitmapId& id,
-    const base::Callback<void(SharedBitmap* bitmap)>& free_callback)
-    : memory_(memory),
-      pixels_(static_cast<uint8*>(memory_->memory())),
-      id_(id),
-      free_callback_(free_callback) {
+SharedBitmap::SharedBitmap(uint8* pixels, const SharedBitmapId& id)
+    : pixels_(pixels), id_(id) {
 }
 
-SharedBitmap::SharedBitmap(
-    uint8* pixels,
-    const SharedBitmapId& id,
-    const base::Callback<void(SharedBitmap* bitmap)>& free_callback)
-    : memory_(NULL), pixels_(pixels), id_(id), free_callback_(free_callback) {
+SharedBitmap::~SharedBitmap() {
 }
 
-SharedBitmap::~SharedBitmap() { free_callback_.Run(this); }
-
 // static
 bool SharedBitmap::SizeInBytes(const gfx::Size& size, size_t* size_in_bytes) {
   if (size.IsEmpty())
diff --git a/cc/resources/shared_bitmap.h b/cc/resources/shared_bitmap.h
index ca12710..bbf0823 100644
--- a/cc/resources/shared_bitmap.h
+++ b/cc/resources/shared_bitmap.h
@@ -6,8 +6,7 @@
 #define CC_RESOURCES_SHARED_BITMAP_H_
 
 #include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/memory/shared_memory.h"
+#include "base/memory/scoped_ptr.h"
 #include "cc/base/cc_export.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "ui/gfx/geometry/size.h"
@@ -19,29 +18,15 @@
 
 class CC_EXPORT SharedBitmap {
  public:
-  SharedBitmap(base::SharedMemory* memory,
-               const SharedBitmapId& id,
-               const base::Callback<void(SharedBitmap* bitmap)>& free_callback);
+  SharedBitmap(uint8* pixels, const SharedBitmapId& id);
 
-  SharedBitmap(uint8* pixels,
-               const SharedBitmapId& id,
-               const base::Callback<void(SharedBitmap* bitmap)>& free_callback);
-
-  ~SharedBitmap();
-
-  bool operator<(const SharedBitmap& right) const {
-    if (memory_ < right.memory_)
-      return true;
-    if (memory_ > right.memory_)
-      return false;
-    return id_ < right.id_;
-  }
+  virtual ~SharedBitmap();
 
   uint8* pixels() { return pixels_; }
 
-  base::SharedMemory* memory() { return memory_; }
+  virtual base::SharedMemory* memory() = 0;
 
-  SharedBitmapId id() { return id_; }
+  const SharedBitmapId& id() { return id_; }
 
   // Returns true if the size is valid and false otherwise.
   static bool SizeInBytes(const gfx::Size& size, size_t* size_in_bytes);
@@ -57,10 +42,8 @@
   static SharedBitmapId GenerateId();
 
  private:
-  base::SharedMemory* memory_;
   uint8* pixels_;
   SharedBitmapId id_;
-  base::Callback<void(SharedBitmap* bitmap)> free_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(SharedBitmap);
 };
diff --git a/cc/resources/texture_uploader_unittest.cc b/cc/resources/texture_uploader_unittest.cc
index 7249172..b168962 100644
--- a/cc/resources/texture_uploader_unittest.cc
+++ b/cc/resources/texture_uploader_unittest.cc
@@ -111,6 +111,14 @@
         EXPECT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
         bytes_per_pixel = 2;
         break;
+      case GL_RED_EXT:
+        EXPECT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
+        bytes_per_pixel = 1;
+        break;
+      case GL_RG_EXT:
+        EXPECT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
+        bytes_per_pixel = 2;
+        break;
     }
 
     // If NULL, we aren't checking texture contents.
@@ -232,6 +240,15 @@
     buffer[(i + 1) * 82 - 1] = 0x2;
   }
   UploadTexture(uploader.get(), LUMINANCE_8, gfx::Size(82, 86), buffer);
+
+  // Upload a tightly packed 82x86 RED texture.
+  memset(buffer, 0, sizeof(buffer));
+  for (int i = 0; i < 86; ++i) {
+    // Mark the beginning and end of each row, for the test.
+    buffer[i * 1 * 82] = 0x1;
+    buffer[(i + 1) * 82 - 1] = 0x2;
+  }
+  UploadTexture(uploader.get(), RED_8, gfx::Size(82, 86), buffer);
 }
 
 }  // namespace
diff --git a/cc/resources/tile.h b/cc/resources/tile.h
index 042d5ae..a35cffe 100644
--- a/cc/resources/tile.h
+++ b/cc/resources/tile.h
@@ -15,6 +15,8 @@
 
 namespace cc {
 
+class TileManager;
+
 class CC_EXPORT Tile : public RefCountedManaged<Tile> {
  public:
   enum TileRasterFlags { USE_PICTURE_ANALYSIS = 1 << 0 };
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
index d83b824..66f95da 100644
--- a/cc/resources/tile_manager.cc
+++ b/cc/resources/tile_manager.cc
@@ -239,9 +239,11 @@
           task_runner_.get(),
           base::Bind(&TileManager::CheckIfReadyToActivate,
                      base::Unretained(this))),
-      ready_to_draw_check_notifier_(task_runner_.get(),
-                                    base::Bind(&TileManager::CheckIfReadyToDraw,
-                                               base::Unretained(this))) {
+      ready_to_draw_check_notifier_(
+          task_runner_.get(),
+          base::Bind(&TileManager::CheckIfReadyToDraw, base::Unretained(this))),
+      did_notify_ready_to_activate_(false),
+      did_notify_ready_to_draw_(false) {
   rasterizer_->SetClient(this);
 }
 
@@ -416,9 +418,12 @@
   TileVector tiles_that_need_to_be_rasterized;
   AssignGpuMemoryToTiles(&tiles_that_need_to_be_rasterized);
 
-  // Finally, schedule rasterizer tasks.
+  // Schedule rasterizer tasks.
   ScheduleTasks(tiles_that_need_to_be_rasterized);
 
+  did_notify_ready_to_activate_ = false;
+  did_notify_ready_to_draw_ = false;
+
   TRACE_EVENT_INSTANT1("cc",
                        "DidManage",
                        TRACE_EVENT_SCOPE_THREAD,
@@ -882,8 +887,13 @@
   rasterizer_->CheckForCompletedTasks();
   did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
 
-  if (IsReadyToActivate())
-    client_->NotifyReadyToActivate();
+  if (did_notify_ready_to_activate_)
+    return;
+  if (!IsReadyToActivate())
+    return;
+
+  client_->NotifyReadyToActivate();
+  did_notify_ready_to_activate_ = true;
 }
 
 void TileManager::CheckIfReadyToDraw() {
@@ -892,8 +902,13 @@
   rasterizer_->CheckForCompletedTasks();
   did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
 
-  if (IsReadyToDraw())
-    client_->NotifyReadyToDraw();
+  if (did_notify_ready_to_draw_)
+    return;
+  if (!IsReadyToDraw())
+    return;
+
+  client_->NotifyReadyToDraw();
+  did_notify_ready_to_draw_ = true;
 }
 
 TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) {
diff --git a/cc/resources/tile_manager.h b/cc/resources/tile_manager.h
index e94fb7c..8d19520 100644
--- a/cc/resources/tile_manager.h
+++ b/cc/resources/tile_manager.h
@@ -162,6 +162,10 @@
     return tiles;
   }
 
+  void SetScheduledRasterTaskLimitForTesting(size_t limit) {
+    scheduled_raster_task_limit_ = limit;
+  }
+
  protected:
   TileManager(TileManagerClient* client,
               const scoped_refptr<base::SequencedTaskRunner>& task_runner,
@@ -243,7 +247,7 @@
   ResourcePool* resource_pool_;
   Rasterizer* rasterizer_;
   GlobalStateThatImpactsTilePriority global_state_;
-  const size_t scheduled_raster_task_limit_;
+  size_t scheduled_raster_task_limit_;
 
   typedef base::hash_map<Tile::Id, Tile*> TileMap;
   TileMap tiles_;
@@ -282,6 +286,9 @@
   EvictionTilePriorityQueue eviction_priority_queue_;
   bool eviction_priority_queue_is_up_to_date_;
 
+  bool did_notify_ready_to_activate_;
+  bool did_notify_ready_to_draw_;
+
   DISALLOW_COPY_AND_ASSIGN(TileManager);
 };
 
diff --git a/cc/resources/tile_manager_perftest.cc b/cc/resources/tile_manager_perftest.cc
index 7b096bd..2204ab8 100644
--- a/cc/resources/tile_manager_perftest.cc
+++ b/cc/resources/tile_manager_perftest.cc
@@ -400,7 +400,8 @@
     timer_.Reset();
     bool resourceless_software_draw = false;
     do {
-      BeginFrameArgs args = CreateBeginFrameArgsForTesting();
+      BeginFrameArgs args =
+          CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE);
       host_impl_.UpdateCurrentBeginFrameArgs(args);
       for (unsigned i = 0; i < layers.size(); ++i) {
         layers[i]->UpdateTiles(Occlusion(), resourceless_software_draw);
diff --git a/cc/resources/tile_manager_unittest.cc b/cc/resources/tile_manager_unittest.cc
index 49a93d3..fdd876e 100644
--- a/cc/resources/tile_manager_unittest.cc
+++ b/cc/resources/tile_manager_unittest.cc
@@ -149,7 +149,9 @@
 };
 
 TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueue) {
-  SetupDefaultTrees(gfx::Size(1000, 1000));
+  const gfx::Size layer_bounds(1000, 1000);
+  host_impl_.SetViewportSize(layer_bounds);
+  SetupDefaultTrees(layer_bounds);
 
   active_layer_->CreateDefaultTilingsAndTiles();
   pending_layer_->CreateDefaultTilingsAndTiles();
@@ -391,7 +393,9 @@
 }
 
 TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueue) {
-  SetupDefaultTrees(gfx::Size(1000, 1000));
+  const gfx::Size layer_bounds(1000, 1000);
+  host_impl_.SetViewportSize(layer_bounds);
+  SetupDefaultTrees(layer_bounds);
 
   active_layer_->CreateDefaultTilingsAndTiles();
   pending_layer_->CreateDefaultTilingsAndTiles();
@@ -560,6 +564,8 @@
   gfx::Size tile_size(102, 102);
   gfx::Size layer_bounds(1000, 1000);
 
+  host_impl_.SetViewportSize(layer_bounds);
+
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
   SetupPendingTree(pending_pile);
@@ -768,7 +774,9 @@
 }
 
 TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueueEmptyLayers) {
-  SetupDefaultTrees(gfx::Size(1000, 1000));
+  const gfx::Size layer_bounds(1000, 1000);
+  host_impl_.SetViewportSize(layer_bounds);
+  SetupDefaultTrees(layer_bounds);
 
   active_layer_->CreateDefaultTilingsAndTiles();
   pending_layer_->CreateDefaultTilingsAndTiles();
@@ -815,7 +823,9 @@
 }
 
 TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueueEmptyLayers) {
-  SetupDefaultTrees(gfx::Size(1000, 1000));
+  const gfx::Size layer_bounds(1000, 1000);
+  host_impl_.SetViewportSize(layer_bounds);
+  SetupDefaultTrees(layer_bounds);
 
   active_layer_->CreateDefaultTilingsAndTiles();
   pending_layer_->CreateDefaultTilingsAndTiles();
diff --git a/cc/resources/tiling_set_eviction_queue.cc b/cc/resources/tiling_set_eviction_queue.cc
new file mode 100644
index 0000000..8c5ff52
--- /dev/null
+++ b/cc/resources/tiling_set_eviction_queue.cc
@@ -0,0 +1,197 @@
+// Copyright 2014 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/resources/tiling_set_eviction_queue.h"
+
+namespace cc {
+
+TilingSetEvictionQueue::TilingSetEvictionQueue()
+    : tiling_set_(nullptr),
+      tree_priority_(SAME_PRIORITY_FOR_BOTH_TREES),
+      current_category_(PictureLayerTiling::EVENTUALLY),
+      current_tiling_index_(0u),
+      current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
+      current_eviction_tile_(nullptr),
+      eviction_tiles_(nullptr),
+      next_eviction_tile_index_(0u) {
+}
+
+TilingSetEvictionQueue::TilingSetEvictionQueue(
+    PictureLayerTilingSet* tiling_set,
+    TreePriority tree_priority)
+    : tiling_set_(tiling_set),
+      tree_priority_(tree_priority),
+      current_category_(PictureLayerTiling::EVENTUALLY),
+      current_tiling_index_(0u),
+      current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
+      current_eviction_tile_(nullptr),
+      eviction_tiles_(nullptr),
+      next_eviction_tile_index_(0u) {
+  DCHECK(tiling_set_);
+
+  // Early out if the layer has no tilings.
+  if (!tiling_set_->num_tilings())
+    return;
+
+  current_tiling_index_ = CurrentTilingRange().start - 1u;
+  AdvanceToNextValidTiling();
+}
+
+TilingSetEvictionQueue::~TilingSetEvictionQueue() {
+}
+
+bool TilingSetEvictionQueue::IsEmpty() const {
+  return !current_eviction_tile_;
+}
+
+void TilingSetEvictionQueue::Pop() {
+  DCHECK(!IsEmpty());
+
+  if (!AdvanceToNextEvictionTile())
+    AdvanceToNextValidTiling();
+}
+
+Tile* TilingSetEvictionQueue::Top() {
+  DCHECK(!IsEmpty());
+  return current_eviction_tile_;
+}
+
+const Tile* TilingSetEvictionQueue::Top() const {
+  DCHECK(!IsEmpty());
+  return current_eviction_tile_;
+}
+
+bool TilingSetEvictionQueue::AdvanceToNextCategory() {
+  // Advance to the next category. This is done only after all tiling range
+  // types within the previous category have been gone through.
+  DCHECK_EQ(current_tiling_range_type_, PictureLayerTilingSet::HIGH_RES);
+
+  switch (current_category_) {
+    case PictureLayerTiling::EVENTUALLY:
+      current_category_ =
+          PictureLayerTiling::EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION;
+      return true;
+    case PictureLayerTiling::EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION:
+      current_category_ = PictureLayerTiling::SOON;
+      return true;
+    case PictureLayerTiling::SOON:
+      current_category_ = PictureLayerTiling::SOON_AND_REQUIRED_FOR_ACTIVATION;
+      return true;
+    case PictureLayerTiling::SOON_AND_REQUIRED_FOR_ACTIVATION:
+      current_category_ = PictureLayerTiling::NOW;
+      return true;
+    case PictureLayerTiling::NOW:
+      current_category_ = PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION;
+      return true;
+    case PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION:
+      return false;
+  }
+  NOTREACHED();
+  return false;
+}
+
+bool TilingSetEvictionQueue::AdvanceToNextEvictionTile() {
+  // Advance to the next eviction tile within the current category and tiling.
+  // This is done while advancing to a new tiling (in which case the next
+  // eviction tile index is 0) and while popping the current tile (in which
+  // case the next eviction tile index is greater than 0).
+  DCHECK_EQ(next_eviction_tile_index_ > 0, current_eviction_tile_ != nullptr);
+
+  while (next_eviction_tile_index_ < eviction_tiles_->size()) {
+    Tile* tile = (*eviction_tiles_)[next_eviction_tile_index_];
+    ++next_eviction_tile_index_;
+    if (tile->HasResources()) {
+      current_eviction_tile_ = tile;
+      return true;
+    }
+  }
+
+  current_eviction_tile_ = nullptr;
+  return false;
+}
+
+bool TilingSetEvictionQueue::AdvanceToNextTilingRangeType() {
+  // Advance to the next tiling range type within the current category or to
+  // the first tiling range type within the next category. This is done only
+  // after all tilings within the previous tiling range type have been gone
+  // through.
+  DCHECK_EQ(current_tiling_index_, CurrentTilingRange().end);
+
+  switch (current_tiling_range_type_) {
+    case PictureLayerTilingSet::HIGHER_THAN_HIGH_RES:
+      current_tiling_range_type_ = PictureLayerTilingSet::LOWER_THAN_LOW_RES;
+      return true;
+    case PictureLayerTilingSet::LOWER_THAN_LOW_RES:
+      current_tiling_range_type_ =
+          PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES;
+      return true;
+    case PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES:
+      current_tiling_range_type_ = PictureLayerTilingSet::LOW_RES;
+      return true;
+    case PictureLayerTilingSet::LOW_RES:
+      current_tiling_range_type_ = PictureLayerTilingSet::HIGH_RES;
+      return true;
+    case PictureLayerTilingSet::HIGH_RES:
+      if (!AdvanceToNextCategory())
+        return false;
+
+      current_tiling_range_type_ = PictureLayerTilingSet::HIGHER_THAN_HIGH_RES;
+      return true;
+  }
+  NOTREACHED();
+  return false;
+}
+
+bool TilingSetEvictionQueue::AdvanceToNextValidTiling() {
+  // Advance to the next tiling within current tiling range type or to
+  // the first tiling within the next tiling range type or category until
+  // the next eviction tile is found. This is done only after all eviction
+  // tiles within the previous tiling within the current category and tiling
+  // range type have been gone through.
+  DCHECK(!current_eviction_tile_);
+  DCHECK_NE(current_tiling_index_, CurrentTilingRange().end);
+
+  for (;;) {
+    ++current_tiling_index_;
+    while (current_tiling_index_ == CurrentTilingRange().end) {
+      if (!AdvanceToNextTilingRangeType())
+        return false;
+      current_tiling_index_ = CurrentTilingRange().start;
+    }
+
+    PictureLayerTiling* tiling = tiling_set_->tiling_at(CurrentTilingIndex());
+    eviction_tiles_ =
+        tiling->GetEvictionTiles(tree_priority_, current_category_);
+    next_eviction_tile_index_ = 0u;
+    if (AdvanceToNextEvictionTile())
+      return true;
+  }
+}
+
+PictureLayerTilingSet::TilingRange
+TilingSetEvictionQueue::CurrentTilingRange() const {
+  return tiling_set_->GetTilingRange(current_tiling_range_type_);
+}
+
+size_t TilingSetEvictionQueue::CurrentTilingIndex() const {
+  DCHECK_NE(current_tiling_index_, CurrentTilingRange().end);
+  switch (current_tiling_range_type_) {
+    case PictureLayerTilingSet::HIGHER_THAN_HIGH_RES:
+    case PictureLayerTilingSet::LOW_RES:
+    case PictureLayerTilingSet::HIGH_RES:
+      return current_tiling_index_;
+    // Tilings in the following ranges are accessed in reverse order.
+    case PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES:
+    case PictureLayerTilingSet::LOWER_THAN_LOW_RES: {
+      PictureLayerTilingSet::TilingRange tiling_range = CurrentTilingRange();
+      size_t current_tiling_range_offset =
+          current_tiling_index_ - tiling_range.start;
+      return tiling_range.end - 1 - current_tiling_range_offset;
+    }
+  }
+  NOTREACHED();
+  return 0;
+}
+
+}
diff --git a/cc/resources/tiling_set_eviction_queue.h b/cc/resources/tiling_set_eviction_queue.h
new file mode 100644
index 0000000..f88ce3b
--- /dev/null
+++ b/cc/resources/tiling_set_eviction_queue.h
@@ -0,0 +1,48 @@
+// Copyright 2014 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_RESOURCES_TILING_SET_EVICTION_QUEUE_H_
+#define CC_RESOURCES_TILING_SET_EVICTION_QUEUE_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/resources/picture_layer_tiling_set.h"
+
+namespace cc {
+
+class CC_EXPORT TilingSetEvictionQueue {
+ public:
+  TilingSetEvictionQueue();
+  TilingSetEvictionQueue(PictureLayerTilingSet* tiling_set,
+                         TreePriority tree_priority);
+  ~TilingSetEvictionQueue();
+
+  Tile* Top();
+  const Tile* Top() const;
+  void Pop();
+  bool IsEmpty() const;
+
+ private:
+  bool AdvanceToNextCategory();
+  bool AdvanceToNextEvictionTile();
+  bool AdvanceToNextTilingRangeType();
+  bool AdvanceToNextValidTiling();
+
+  PictureLayerTilingSet::TilingRange CurrentTilingRange() const;
+  size_t CurrentTilingIndex() const;
+
+  PictureLayerTilingSet* tiling_set_;
+  TreePriority tree_priority_;
+
+  PictureLayerTiling::EvictionCategory current_category_;
+  size_t current_tiling_index_;
+  PictureLayerTilingSet::TilingRangeType current_tiling_range_type_;
+  Tile* current_eviction_tile_;
+
+  const std::vector<Tile*>* eviction_tiles_;
+  size_t next_eviction_tile_index_;
+};
+
+}  // namespace cc
+
+#endif  // CC_RESOURCES_TILING_SET_RASTER_QUEUE_H_
diff --git a/cc/resources/transform_display_item.cc b/cc/resources/transform_display_item.cc
new file mode 100644
index 0000000..c7f4d60
--- /dev/null
+++ b/cc/resources/transform_display_item.cc
@@ -0,0 +1,60 @@
+// Copyright 2014 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/resources/transform_display_item.h"
+
+#include "third_party/skia/include/core/SkCanvas.h"
+
+namespace cc {
+
+TransformDisplayItem::TransformDisplayItem(const gfx::Transform& transform)
+    : transform_(transform) {
+}
+
+TransformDisplayItem::~TransformDisplayItem() {
+}
+
+void TransformDisplayItem::Raster(SkCanvas* canvas,
+                                  SkDrawPictureCallback* callback) const {
+  canvas->save();
+  if (!transform_.IsIdentity())
+    canvas->concat(transform_.matrix());
+}
+
+bool TransformDisplayItem::IsSuitableForGpuRasterization() const {
+  return true;
+}
+
+int TransformDisplayItem::ApproximateOpCount() const {
+  return 1;
+}
+
+size_t TransformDisplayItem::PictureMemoryUsage() const {
+  return sizeof(gfx::Transform);
+}
+
+EndTransformDisplayItem::EndTransformDisplayItem() {
+}
+
+EndTransformDisplayItem::~EndTransformDisplayItem() {
+}
+
+void EndTransformDisplayItem::Raster(SkCanvas* canvas,
+                                     SkDrawPictureCallback* callback) const {
+  canvas->restore();
+}
+
+bool EndTransformDisplayItem::IsSuitableForGpuRasterization() const {
+  return true;
+}
+
+int EndTransformDisplayItem::ApproximateOpCount() const {
+  return 0;
+}
+
+size_t EndTransformDisplayItem::PictureMemoryUsage() const {
+  return 0;
+}
+
+}  // namespace cc
diff --git a/cc/resources/transform_display_item.h b/cc/resources/transform_display_item.h
new file mode 100644
index 0000000..1671f49
--- /dev/null
+++ b/cc/resources/transform_display_item.h
@@ -0,0 +1,60 @@
+// Copyright 2014 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_RESOURCES_TRANSFORM_DISPLAY_ITEM_H_
+#define CC_RESOURCES_TRANSFORM_DISPLAY_ITEM_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/resources/display_item.h"
+#include "ui/gfx/transform.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+
+namespace cc {
+
+class CC_EXPORT TransformDisplayItem : public DisplayItem {
+ public:
+  virtual ~TransformDisplayItem();
+
+  static scoped_ptr<TransformDisplayItem> Create(
+      const gfx::Transform& transform) {
+    return make_scoped_ptr(new TransformDisplayItem(transform));
+  }
+
+  void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+  bool IsSuitableForGpuRasterization() const override;
+  int ApproximateOpCount() const override;
+  size_t PictureMemoryUsage() const override;
+
+ protected:
+  explicit TransformDisplayItem(const gfx::Transform& transform);
+
+ private:
+  gfx::Transform transform_;
+};
+
+class CC_EXPORT EndTransformDisplayItem : public DisplayItem {
+ public:
+  virtual ~EndTransformDisplayItem();
+
+  static scoped_ptr<EndTransformDisplayItem> Create() {
+    return make_scoped_ptr(new EndTransformDisplayItem());
+  }
+
+  void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+  bool IsSuitableForGpuRasterization() const override;
+  int ApproximateOpCount() const override;
+  size_t PictureMemoryUsage() const override;
+
+ protected:
+  EndTransformDisplayItem();
+};
+
+}  // namespace cc
+
+#endif  // CC_RESOURCES_TRANSFORM_DISPLAY_ITEM_H_
diff --git a/cc/resources/transparency_display_item.cc b/cc/resources/transparency_display_item.cc
new file mode 100644
index 0000000..0401d90
--- /dev/null
+++ b/cc/resources/transparency_display_item.cc
@@ -0,0 +1,65 @@
+// Copyright 2014 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/resources/transparency_display_item.h"
+
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkXfermode.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+
+TransparencyDisplayItem::TransparencyDisplayItem(float opacity,
+                                                 SkXfermode::Mode blend_mode)
+    : opacity_(opacity), blend_mode_(blend_mode) {
+}
+
+TransparencyDisplayItem::~TransparencyDisplayItem() {
+}
+
+void TransparencyDisplayItem::Raster(SkCanvas* canvas,
+                                     SkDrawPictureCallback* callback) const {
+  SkPaint paint;
+  paint.setXfermodeMode(blend_mode_);
+  paint.setAlpha(opacity_ * 255);
+  canvas->saveLayer(NULL, &paint);
+}
+
+bool TransparencyDisplayItem::IsSuitableForGpuRasterization() const {
+  return true;
+}
+
+int TransparencyDisplayItem::ApproximateOpCount() const {
+  return 1;
+}
+
+size_t TransparencyDisplayItem::PictureMemoryUsage() const {
+  return sizeof(float) + sizeof(SkXfermode::Mode);
+}
+
+EndTransparencyDisplayItem::EndTransparencyDisplayItem() {
+}
+
+EndTransparencyDisplayItem::~EndTransparencyDisplayItem() {
+}
+
+void EndTransparencyDisplayItem::Raster(SkCanvas* canvas,
+                                        SkDrawPictureCallback* callback) const {
+  canvas->restore();
+}
+
+bool EndTransparencyDisplayItem::IsSuitableForGpuRasterization() const {
+  return true;
+}
+
+int EndTransparencyDisplayItem::ApproximateOpCount() const {
+  return 0;
+}
+
+size_t EndTransparencyDisplayItem::PictureMemoryUsage() const {
+  return 0;
+}
+
+}  // namespace cc
diff --git a/cc/resources/transparency_display_item.h b/cc/resources/transparency_display_item.h
new file mode 100644
index 0000000..6766d91
--- /dev/null
+++ b/cc/resources/transparency_display_item.h
@@ -0,0 +1,64 @@
+// Copyright 2014 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_RESOURCES_TRANSPARENCY_DISPLAY_ITEM_H_
+#define CC_RESOURCES_TRANSPARENCY_DISPLAY_ITEM_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/resources/display_item.h"
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkXfermode.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+
+namespace cc {
+
+class CC_EXPORT TransparencyDisplayItem : public DisplayItem {
+ public:
+  virtual ~TransparencyDisplayItem();
+
+  static scoped_ptr<TransparencyDisplayItem> Create(
+      float opacity,
+      SkXfermode::Mode blend_mode) {
+    return make_scoped_ptr(new TransparencyDisplayItem(opacity, blend_mode));
+  }
+
+  void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+  bool IsSuitableForGpuRasterization() const override;
+  int ApproximateOpCount() const override;
+  size_t PictureMemoryUsage() const override;
+
+ protected:
+  TransparencyDisplayItem(float opacity, SkXfermode::Mode blend_mode);
+
+ private:
+  float opacity_;
+  SkXfermode::Mode blend_mode_;
+};
+
+class CC_EXPORT EndTransparencyDisplayItem : public DisplayItem {
+ public:
+  virtual ~EndTransparencyDisplayItem();
+
+  static scoped_ptr<EndTransparencyDisplayItem> Create() {
+    return make_scoped_ptr(new EndTransparencyDisplayItem());
+  }
+
+  void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+  bool IsSuitableForGpuRasterization() const override;
+  int ApproximateOpCount() const override;
+  size_t PictureMemoryUsage() const override;
+
+ protected:
+  EndTransparencyDisplayItem();
+};
+
+}  // namespace cc
+
+#endif  // CC_RESOURCES_TRANSPARENCY_DISPLAY_ITEM_H_
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
index 7a775d9..2c9a688 100644
--- a/cc/resources/video_resource_updater.cc
+++ b/cc/resources/video_resource_updater.cc
@@ -20,7 +20,6 @@
 
 namespace {
 
-const ResourceFormat kYUVResourceFormat = LUMINANCE_8;
 const ResourceFormat kRGBResourceFormat = RGBA_8888;
 
 class SyncPointClientImpl : public media::VideoFrame::SyncPointClient {
@@ -40,6 +39,37 @@
 
 }  // namespace
 
+VideoResourceUpdater::PlaneResource::PlaneResource(
+    unsigned int resource_id,
+    const gfx::Size& resource_size,
+    ResourceFormat resource_format,
+    gpu::Mailbox mailbox)
+    : resource_id(resource_id),
+      resource_size(resource_size),
+      resource_format(resource_format),
+      mailbox(mailbox),
+      frame_ptr(nullptr),
+      plane_index(0) {
+}
+
+bool VideoResourceUpdater::PlaneResourceMatchesUniqueID(
+    const PlaneResource& plane_resource,
+    const media::VideoFrame* video_frame,
+    int plane_index) {
+  return plane_resource.frame_ptr == video_frame &&
+         plane_resource.plane_index == plane_index &&
+         plane_resource.timestamp == video_frame->timestamp();
+}
+
+void VideoResourceUpdater::SetPlaneResourceUniqueId(
+    const media::VideoFrame* video_frame,
+    int plane_index,
+    PlaneResource* plane_resource) {
+  plane_resource->frame_ptr = video_frame;
+  plane_resource->plane_index = plane_index;
+  plane_resource->timestamp = video_frame->timestamp();
+}
+
 VideoFrameExternalResources::VideoFrameExternalResources() : type(NONE) {}
 
 VideoFrameExternalResources::~VideoFrameExternalResources() {}
@@ -104,14 +134,12 @@
 // each plane in the frame.
 static gfx::Size SoftwarePlaneDimension(
     const scoped_refptr<media::VideoFrame>& input_frame,
-    ResourceFormat output_resource_format,
+    bool software_compositor,
     size_t plane_index) {
-  if (output_resource_format == kYUVResourceFormat) {
+  if (!software_compositor) {
     return media::VideoFrame::PlaneSize(
         input_frame->format(), plane_index, input_frame->coded_size());
   }
-
-  DCHECK_EQ(output_resource_format, kRGBResourceFormat);
   return input_frame->coded_size();
 }
 
@@ -145,7 +173,8 @@
 
   bool software_compositor = context_provider_ == NULL;
 
-  ResourceFormat output_resource_format = kYUVResourceFormat;
+  ResourceFormat output_resource_format =
+      resource_provider_->yuv_resource_format();
   size_t output_plane_count = media::VideoFrame::NumPlanes(input_frame_format);
 
   // TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB
@@ -163,7 +192,7 @@
 
   for (size_t i = 0; i < output_plane_count; ++i) {
     gfx::Size output_plane_resource_size =
-        SoftwarePlaneDimension(video_frame, output_resource_format, i);
+        SoftwarePlaneDimension(video_frame, software_compositor, i);
     if (output_plane_resource_size.IsEmpty() ||
         output_plane_resource_size.width() > max_resource_size ||
         output_plane_resource_size.height() > max_resource_size) {
@@ -171,57 +200,56 @@
       break;
     }
 
-    ResourceProvider::ResourceId resource_id = 0;
-    gpu::Mailbox mailbox;
-
     // Try recycle a previously-allocated resource.
-    for (size_t i = 0; i < recycled_resources_.size(); ++i) {
-      bool resource_matches =
-          recycled_resources_[i].resource_format == output_resource_format &&
-          recycled_resources_[i].resource_size == output_plane_resource_size;
-      bool not_in_use =
-          !software_compositor || !resource_provider_->InUseByConsumer(
-                                       recycled_resources_[i].resource_id);
-      if (resource_matches && not_in_use) {
-        resource_id = recycled_resources_[i].resource_id;
-        mailbox = recycled_resources_[i].mailbox;
-        recycled_resources_.erase(recycled_resources_.begin() + i);
-        break;
+    auto recycled_it = recycled_resources_.end();
+    for (auto it = recycled_resources_.begin(); it != recycled_resources_.end();
+         ++it) {
+      const bool resource_matches =
+          it->resource_format == output_resource_format &&
+          it->resource_size == output_plane_resource_size;
+      const bool in_use = software_compositor &&
+                          resource_provider_->InUseByConsumer(it->resource_id);
+      if (resource_matches && !in_use) {
+        // We found a recycled resource with the allocation size and format we
+        // are looking for.
+        recycled_it = it;
+        // Keep looking for a recycled resource that also contains the data we
+        // are planning to put in it.
+        if (PlaneResourceMatchesUniqueID(*it, video_frame.get(), i))
+          break;
       }
     }
 
-    if (resource_id == 0) {
-      // TODO(danakj): Abstract out hw/sw resource create/delete from
-      // ResourceProvider and stop using ResourceProvider in this class.
-      resource_id = resource_provider_->CreateResource(
-          output_plane_resource_size,
-          GL_CLAMP_TO_EDGE,
-          ResourceProvider::TextureHintImmutable,
-          output_resource_format);
-
-      DCHECK(mailbox.IsZero());
-
-      if (!software_compositor) {
-        DCHECK(context_provider_);
-
-        gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
-
-        GLC(gl, gl->GenMailboxCHROMIUM(mailbox.name));
-        ResourceProvider::ScopedWriteLockGL lock(resource_provider_,
-                                                 resource_id);
-        GLC(gl,
-            gl->ProduceTextureDirectCHROMIUM(
-                lock.texture_id(), GL_TEXTURE_2D, mailbox.name));
-      }
-
-      if (resource_id)
-        all_resources_.push_back(resource_id);
+    // Check if we can avoid allocating a new resource.
+    if (recycled_it != recycled_resources_.end()) {
+      plane_resources.push_back(*recycled_it);
+      recycled_resources_.erase(recycled_it);
+      continue;
     }
 
+    // TODO(danakj): Abstract out hw/sw resource create/delete from
+    // ResourceProvider and stop using ResourceProvider in this class.
+    const ResourceProvider::ResourceId resource_id =
+        resource_provider_->CreateResource(
+            output_plane_resource_size, GL_CLAMP_TO_EDGE,
+            ResourceProvider::TextureHintImmutable, output_resource_format);
     if (resource_id == 0) {
       allocation_success = false;
       break;
     }
+    all_resources_.push_back(resource_id);
+
+    gpu::Mailbox mailbox;
+    if (!software_compositor) {
+      DCHECK(context_provider_);
+
+      gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
+
+      GLC(gl, gl->GenMailboxCHROMIUM(mailbox.name));
+      ResourceProvider::ScopedWriteLockGL lock(resource_provider_, resource_id);
+      GLC(gl, gl->ProduceTextureDirectCHROMIUM(lock.texture_id(), GL_TEXTURE_2D,
+                                               mailbox.name));
+    }
 
     DCHECK(software_compositor || !mailbox.IsZero());
     plane_resources.push_back(PlaneResource(resource_id,
@@ -243,26 +271,23 @@
     DCHECK_EQ(plane_resources[0].resource_format, kRGBResourceFormat);
     DCHECK(plane_resources[0].mailbox.IsZero());
 
-    if (!video_renderer_)
-      video_renderer_.reset(new media::SkCanvasVideoRenderer);
+    if (!PlaneResourceMatchesUniqueID(plane_resources[0], video_frame.get(),
+                                      0)) {
+      // We need to transfer data from |video_frame| to the plane resource.
+      if (!video_renderer_)
+        video_renderer_.reset(new media::SkCanvasVideoRenderer);
 
-    {
       ResourceProvider::ScopedWriteLockSoftware lock(
           resource_provider_, plane_resources[0].resource_id);
       SkCanvas canvas(lock.sk_bitmap());
       video_renderer_->Copy(video_frame, &canvas);
+      SetPlaneResourceUniqueId(video_frame.get(), 0, &plane_resources[0]);
     }
 
-    RecycleResourceData recycle_data = {
-      plane_resources[0].resource_id,
-      plane_resources[0].resource_size,
-      plane_resources[0].resource_format,
-      gpu::Mailbox()
-    };
     external_resources.software_resources.push_back(
         plane_resources[0].resource_id);
     external_resources.software_release_callback =
-        base::Bind(&RecycleResource, AsWeakPtr(), recycle_data);
+        base::Bind(&RecycleResource, AsWeakPtr(), plane_resources[0]);
     external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE;
 
     return external_resources;
@@ -270,32 +295,27 @@
 
   for (size_t i = 0; i < plane_resources.size(); ++i) {
     // Update each plane's resource id with its content.
-    DCHECK_EQ(plane_resources[i].resource_format, kYUVResourceFormat);
+    DCHECK_EQ(plane_resources[i].resource_format,
+              resource_provider_->yuv_resource_format());
 
-    const uint8_t* input_plane_pixels = video_frame->data(i);
+    if (!PlaneResourceMatchesUniqueID(plane_resources[i], video_frame.get(),
+                                      i)) {
+      // We need to transfer data from |video_frame| to the plane resource.
+      const uint8_t* input_plane_pixels = video_frame->data(i);
 
-    gfx::Rect image_rect(0,
-                         0,
-                         video_frame->stride(i),
-                         plane_resources[i].resource_size.height());
-    gfx::Rect source_rect(plane_resources[i].resource_size);
-    resource_provider_->SetPixels(plane_resources[i].resource_id,
-                                  input_plane_pixels,
-                                  image_rect,
-                                  source_rect,
-                                  gfx::Vector2d());
-
-    RecycleResourceData recycle_data = {
-      plane_resources[i].resource_id,
-      plane_resources[i].resource_size,
-      plane_resources[i].resource_format,
-      plane_resources[i].mailbox
-    };
+      gfx::Rect image_rect(0, 0, video_frame->stride(i),
+                           plane_resources[i].resource_size.height());
+      gfx::Rect source_rect(plane_resources[i].resource_size);
+      resource_provider_->SetPixels(plane_resources[i].resource_id,
+                                    input_plane_pixels, image_rect, source_rect,
+                                    gfx::Vector2d());
+      SetPlaneResourceUniqueId(video_frame.get(), i, &plane_resources[i]);
+    }
 
     external_resources.mailboxes.push_back(
         TextureMailbox(plane_resources[i].mailbox, GL_TEXTURE_2D, 0));
     external_resources.release_callbacks.push_back(
-        base::Bind(&RecycleResource, AsWeakPtr(), recycle_data));
+        base::Bind(&RecycleResource, AsWeakPtr(), plane_resources[i]));
   }
 
   external_resources.type = VideoFrameExternalResources::YUV_RESOURCE;
@@ -362,7 +382,7 @@
 // static
 void VideoResourceUpdater::RecycleResource(
     base::WeakPtr<VideoResourceUpdater> updater,
-    RecycleResourceData data,
+    PlaneResource data,
     uint32 sync_point,
     bool lost_resource,
     BlockingTaskRunner* main_thread_task_runner) {
@@ -385,16 +405,12 @@
   // Drop recycled resources that are the wrong format.
   while (!updater->recycled_resources_.empty() &&
          updater->recycled_resources_.back().resource_format !=
-         data.resource_format) {
+             data.resource_format) {
     updater->DeleteResource(updater->recycled_resources_.back().resource_id);
     updater->recycled_resources_.pop_back();
   }
 
-  PlaneResource recycled_resource(data.resource_id,
-                                  data.resource_size,
-                                  data.resource_format,
-                                  data.mailbox);
-  updater->recycled_resources_.push_back(recycled_resource);
+  updater->recycled_resources_.push_back(data);
 }
 
 }  // namespace cc
diff --git a/cc/resources/video_resource_updater.h b/cc/resources/video_resource_updater.h
index 99800b4..38f6033 100644
--- a/cc/resources/video_resource_updater.h
+++ b/cc/resources/video_resource_updater.h
@@ -10,6 +10,7 @@
 #include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
 #include "cc/base/cc_export.h"
 #include "cc/resources/release_callback_impl.h"
 #include "cc/resources/resource_format.h"
@@ -77,17 +78,28 @@
     gfx::Size resource_size;
     ResourceFormat resource_format;
     gpu::Mailbox mailbox;
+    // These last three members will be used for identifying the data stored in
+    // this resource, and uniquely identifies a media::VideoFrame plane. The
+    // frame pointer will only be used for pointer comparison, i.e. the
+    // underlying data will not be accessed.
+    const void* frame_ptr;
+    int plane_index;
+    base::TimeDelta timestamp;
 
     PlaneResource(unsigned resource_id,
                   const gfx::Size& resource_size,
                   ResourceFormat resource_format,
-                  gpu::Mailbox mailbox)
-        : resource_id(resource_id),
-          resource_size(resource_size),
-          resource_format(resource_format),
-          mailbox(mailbox) {}
+                  gpu::Mailbox mailbox);
   };
 
+  static bool PlaneResourceMatchesUniqueID(const PlaneResource& plane_resource,
+                                           const media::VideoFrame* video_frame,
+                                           int plane_index);
+
+  static void SetPlaneResourceUniqueId(const media::VideoFrame* video_frame,
+                                       int plane_index,
+                                       PlaneResource* plane_resource);
+
   void DeleteResource(unsigned resource_id);
   bool VerifyFrame(const scoped_refptr<media::VideoFrame>& video_frame);
   VideoFrameExternalResources CreateForHardwarePlanes(
@@ -95,14 +107,8 @@
   VideoFrameExternalResources CreateForSoftwarePlanes(
       const scoped_refptr<media::VideoFrame>& video_frame);
 
-  struct RecycleResourceData {
-    unsigned resource_id;
-    gfx::Size resource_size;
-    ResourceFormat resource_format;
-    gpu::Mailbox mailbox;
-  };
   static void RecycleResource(base::WeakPtr<VideoResourceUpdater> updater,
-                              RecycleResourceData data,
+                              PlaneResource data,
                               uint32 sync_point,
                               bool lost_resource,
                               BlockingTaskRunner* main_thread_task_runner);
@@ -117,6 +123,8 @@
   scoped_ptr<media::SkCanvasVideoRenderer> video_renderer_;
 
   std::vector<unsigned> all_resources_;
+  // Recycle resources so that we can reduce the number of allocations and
+  // data transfers.
   std::vector<PlaneResource> recycled_resources_;
 
   DISALLOW_COPY_AND_ASSIGN(VideoResourceUpdater);
diff --git a/cc/resources/video_resource_updater_unittest.cc b/cc/resources/video_resource_updater_unittest.cc
index c0a4af4..1e3481b 100644
--- a/cc/resources/video_resource_updater_unittest.cc
+++ b/cc/resources/video_resource_updater_unittest.cc
@@ -17,11 +17,33 @@
 namespace cc {
 namespace {
 
+class WebGraphicsContext3DUploadCounter : public TestWebGraphicsContext3D {
+ public:
+  void texSubImage2D(GLenum target,
+                     GLint level,
+                     GLint xoffset,
+                     GLint yoffset,
+                     GLsizei width,
+                     GLsizei height,
+                     GLenum format,
+                     GLenum type,
+                     const void* pixels) override {
+    ++upload_count_;
+  }
+
+  int UploadCount() { return upload_count_; }
+  void ResetUploadCount() { upload_count_ = 0; }
+
+ private:
+  int upload_count_;
+};
+
 class VideoResourceUpdaterTest : public testing::Test {
  protected:
   VideoResourceUpdaterTest() {
-    scoped_ptr<TestWebGraphicsContext3D> context3d =
-        TestWebGraphicsContext3D::Create();
+    scoped_ptr<WebGraphicsContext3DUploadCounter> context3d(
+        new WebGraphicsContext3DUploadCounter());
+
     context3d_ = context3d.get();
 
     output_surface3d_ =
@@ -60,7 +82,7 @@
         base::Closure());         // no_longer_needed_cb
   }
 
-  TestWebGraphicsContext3D* context3d_;
+  WebGraphicsContext3DUploadCounter* context3d_;
   FakeOutputSurfaceClient client_;
   scoped_ptr<FakeOutputSurface> output_surface3d_;
   scoped_ptr<TestSharedBitmapManager> shared_bitmap_manager_;
@@ -77,5 +99,52 @@
   EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
 }
 
+TEST_F(VideoResourceUpdaterTest, ReuseResource) {
+  VideoResourceUpdater updater(output_surface3d_->context_provider(),
+                               resource_provider3d_.get());
+  scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
+  video_frame->set_timestamp(base::TimeDelta::FromSeconds(1234));
+
+  // Allocate the resources for a YUV video frame.
+  context3d_->ResetUploadCount();
+  VideoFrameExternalResources resources =
+      updater.CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+  EXPECT_EQ(size_t(3), resources.mailboxes.size());
+  EXPECT_EQ(size_t(3), resources.release_callbacks.size());
+  // Expect exactly three texture uploads, one for each plane.
+  EXPECT_EQ(3, context3d_->UploadCount());
+
+  const ResourceProvider::ResourceId y_resource =
+      resource_provider3d_->CreateResourceFromTextureMailbox(
+          resources.mailboxes[media::VideoFrame::kYPlane],
+          SingleReleaseCallbackImpl::Create(
+              resources.release_callbacks[media::VideoFrame::kYPlane]));
+  const ResourceProvider::ResourceId u_resource =
+      resource_provider3d_->CreateResourceFromTextureMailbox(
+          resources.mailboxes[media::VideoFrame::kUPlane],
+          SingleReleaseCallbackImpl::Create(
+              resources.release_callbacks[media::VideoFrame::kUPlane]));
+  const ResourceProvider::ResourceId v_resource =
+      resource_provider3d_->CreateResourceFromTextureMailbox(
+          resources.mailboxes[media::VideoFrame::kVPlane],
+          SingleReleaseCallbackImpl::Create(
+              resources.release_callbacks[media::VideoFrame::kVPlane]));
+
+  // Delete the resources.
+  resource_provider3d_->DeleteResource(y_resource);
+  resource_provider3d_->DeleteResource(u_resource);
+  resource_provider3d_->DeleteResource(v_resource);
+
+  // Allocate resources for the same frame.
+  context3d_->ResetUploadCount();
+  resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+  EXPECT_EQ(size_t(3), resources.mailboxes.size());
+  EXPECT_EQ(size_t(3), resources.release_callbacks.size());
+  // The data should be reused so expect no texture uploads.
+  EXPECT_EQ(0, context3d_->UploadCount());
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/scheduler/begin_frame_source.cc b/cc/scheduler/begin_frame_source.cc
index 5252dcc..89b794e 100644
--- a/cc/scheduler/begin_frame_source.cc
+++ b/cc/scheduler/begin_frame_source.cc
@@ -7,6 +7,7 @@
 #include "base/auto_reset.h"
 #include "base/debug/trace_event.h"
 #include "base/debug/trace_event_argument.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "cc/scheduler/delay_based_time_source.h"
@@ -182,7 +183,7 @@
 
   base::TimeTicks now = Now();
   BeginFrameArgs args = BeginFrameArgs::Create(
-      now, now + BeginFrameArgs::DefaultInterval(),
+      BEGINFRAME_FROM_HERE, now, now + BeginFrameArgs::DefaultInterval(),
       BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
   CallOnBeginFrame(args);
 }
@@ -242,8 +243,8 @@
     base::TimeTicks frame_time,
     BeginFrameArgs::BeginFrameArgsType type) {
   base::TimeTicks deadline = time_source_->NextTickTime();
-  return BeginFrameArgs::Create(frame_time, deadline, time_source_->Interval(),
-                                type);
+  return BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline,
+                                time_source_->Interval(), type);
 }
 
 // TimeSourceClient support
diff --git a/cc/scheduler/begin_frame_source_unittest.cc b/cc/scheduler/begin_frame_source_unittest.cc
index 498d10b..0972762 100644
--- a/cc/scheduler/begin_frame_source_unittest.cc
+++ b/cc/scheduler/begin_frame_source_unittest.cc
@@ -15,19 +15,18 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 // Macros to help set up expected calls on the MockBeginFrameObserver.
-#define EXPECT_BEGIN_FRAME_DROP(obs, frame_time, deadline, interval) \
-  {                                                                  \
-    ::testing::Expectation exp =                                     \
-        EXPECT_CALL((obs),                                           \
-                    OnBeginFrame(CreateBeginFrameArgsForTesting(     \
-                        frame_time, deadline, interval)))            \
-            .InSequence((obs).sequence);                             \
+#define EXPECT_BEGIN_FRAME_DROP(obs, frame_time, deadline, interval)       \
+  {                                                                        \
+    ::testing::Expectation exp =                                           \
+        EXPECT_CALL((obs), OnBeginFrame(CreateBeginFrameArgsForTesting(    \
+                               BEGINFRAME_FROM_HERE, frame_time, deadline, \
+                               interval))).InSequence((obs).sequence);     \
   }
 
 #define EXPECT_BEGIN_FRAME_USED(obs, frame_time, deadline, interval)       \
   {                                                                        \
-    BeginFrameArgs args =                                                  \
-        CreateBeginFrameArgsForTesting(frame_time, deadline, interval);    \
+    BeginFrameArgs args = CreateBeginFrameArgsForTesting(                  \
+        BEGINFRAME_FROM_HERE, frame_time, deadline, interval);             \
     ::testing::Expectation exp =                                           \
         EXPECT_CALL((obs), OnBeginFrame(args)).InSequence((obs).sequence); \
     EXPECT_CALL((obs), LastUsedBeginFrameArgs())                           \
@@ -38,15 +37,15 @@
 
 // Macros to send BeginFrameArgs on a FakeBeginFrameSink (and verify resulting
 // observer behaviour).
-#define SEND_BEGIN_FRAME(args_equal_to, source, frame_time, deadline,   \
-                         interval)                                      \
-  {                                                                     \
-    BeginFrameArgs old_args = (source).TestLastUsedBeginFrameArgs();    \
-    BeginFrameArgs new_args =                                           \
-        CreateBeginFrameArgsForTesting(frame_time, deadline, interval); \
-    ASSERT_FALSE(old_args == new_args);                                 \
-    (source).TestOnBeginFrame(new_args);                                \
-    EXPECT_EQ(args_equal_to, (source).TestLastUsedBeginFrameArgs());    \
+#define SEND_BEGIN_FRAME(args_equal_to, source, frame_time, deadline, \
+                         interval)                                    \
+  {                                                                   \
+    BeginFrameArgs old_args = (source).TestLastUsedBeginFrameArgs();  \
+    BeginFrameArgs new_args = CreateBeginFrameArgsForTesting(         \
+        BEGINFRAME_FROM_HERE, frame_time, deadline, interval);        \
+    ASSERT_FALSE(old_args == new_args);                               \
+    (source).TestOnBeginFrame(new_args);                              \
+    EXPECT_EQ(args_equal_to, (source).TestLastUsedBeginFrameArgs());  \
   }
 
 // When dropping LastUsedBeginFrameArgs **shouldn't** change.
@@ -99,19 +98,25 @@
             MockBeginFrameObserver::kDefaultBeginFrameArgs);
 
   obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
-      100, 200, 300));  // One call to LastUsedBeginFrameArgs
-  EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
-            CreateBeginFrameArgsForTesting(100, 200, 300));
+      BEGINFRAME_FROM_HERE, 100, 200,
+      300));  // One call to LastUsedBeginFrameArgs
+  EXPECT_EQ(
+      obs.LastUsedBeginFrameArgs(),
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
 
   obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
-      400, 600, 300));  // Multiple calls to LastUsedBeginFrameArgs
-  EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
-            CreateBeginFrameArgsForTesting(400, 600, 300));
-  EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
-            CreateBeginFrameArgsForTesting(400, 600, 300));
+      BEGINFRAME_FROM_HERE, 400, 600,
+      300));  // Multiple calls to LastUsedBeginFrameArgs
+  EXPECT_EQ(
+      obs.LastUsedBeginFrameArgs(),
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
+  EXPECT_EQ(
+      obs.LastUsedBeginFrameArgs(),
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
 
   obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
-      700, 900, 300));  // No calls to LastUsedBeginFrameArgs
+      BEGINFRAME_FROM_HERE, 700, 900,
+      300));  // No calls to LastUsedBeginFrameArgs
 }
 
 TEST(MockBeginFrameObserverTest, ExpectOnBeginFrameStatus) {
@@ -125,28 +130,45 @@
             MockBeginFrameObserver::kDefaultBeginFrameArgs);
 
   // Used
-  obs.OnBeginFrame(CreateBeginFrameArgsForTesting(100, 200, 300));
-  EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
-            CreateBeginFrameArgsForTesting(100, 200, 300));
+  obs.OnBeginFrame(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
+  EXPECT_EQ(
+      obs.LastUsedBeginFrameArgs(),
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
 
   // Dropped
-  obs.OnBeginFrame(CreateBeginFrameArgsForTesting(400, 600, 300));
-  EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
-            CreateBeginFrameArgsForTesting(100, 200, 300));
+  obs.OnBeginFrame(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 400, 600, 300));
+  EXPECT_EQ(
+      obs.LastUsedBeginFrameArgs(),
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
 
   // Dropped
-  obs.OnBeginFrame(CreateBeginFrameArgsForTesting(450, 650, 300));
-  EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
-            CreateBeginFrameArgsForTesting(100, 200, 300));
+  obs.OnBeginFrame(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 450, 650, 300));
+  EXPECT_EQ(
+      obs.LastUsedBeginFrameArgs(),
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300));
 
   // Used
-  obs.OnBeginFrame(CreateBeginFrameArgsForTesting(700, 900, 300));
-  EXPECT_EQ(obs.LastUsedBeginFrameArgs(),
-            CreateBeginFrameArgsForTesting(700, 900, 300));
+  obs.OnBeginFrame(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 700, 900, 300));
+  EXPECT_EQ(
+      obs.LastUsedBeginFrameArgs(),
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 700, 900, 300));
 }
 
 const BeginFrameArgs MockBeginFrameObserver::kDefaultBeginFrameArgs =
-    CreateBeginFrameArgsForTesting(-1, -1, -1);
+    CreateBeginFrameArgsForTesting(
+#ifdef NDEBUG
+        nullptr,
+#else
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(
+            "MockBeginFrameObserver::kDefaultBeginFrameArgs"),
+#endif
+        -1,
+        -1,
+        -1);
 
 // BeginFrameObserverMixIn testing ---------------------------------------
 class MockMinimalBeginFrameObserverMixIn : public BeginFrameObserverMixIn {
@@ -168,25 +190,31 @@
   EXPECT_DEATH({ obs.OnBeginFrame(BeginFrameArgs()); }, "");
 #endif
 
-  BeginFrameArgs args1 = CreateBeginFrameArgsForTesting(100, 200, 300);
+  BeginFrameArgs args1 =
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 100, 200, 300);
   EXPECT_CALL(obs, OnBeginFrameMixInDelegate(args1)).WillOnce(Return(true));
   obs.OnBeginFrame(args1);
   EXPECT_EQ(args1, obs.LastUsedBeginFrameArgs());
   EXPECT_EQ(0, obs.dropped_begin_frame_args());
 
 #ifndef NDEBUG
-  EXPECT_DEATH(
-      { obs.OnBeginFrame(CreateBeginFrameArgsForTesting(50, 200, 300)); }, "");
+  EXPECT_DEATH({
+                 obs.OnBeginFrame(CreateBeginFrameArgsForTesting(
+                     BEGINFRAME_FROM_HERE, 50, 200, 300));
+               },
+               "");
 #endif
 
   // Returning false shouldn't update the LastUsedBeginFrameArgs value.
-  BeginFrameArgs args2 = CreateBeginFrameArgsForTesting(200, 300, 400);
+  BeginFrameArgs args2 =
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 200, 300, 400);
   EXPECT_CALL(obs, OnBeginFrameMixInDelegate(args2)).WillOnce(Return(false));
   obs.OnBeginFrame(args2);
   EXPECT_EQ(args1, obs.LastUsedBeginFrameArgs());
   EXPECT_EQ(1, obs.dropped_begin_frame_args());
 
-  BeginFrameArgs args3 = CreateBeginFrameArgsForTesting(150, 300, 400);
+  BeginFrameArgs args3 =
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 150, 300, 400);
   EXPECT_CALL(obs, OnBeginFrameMixInDelegate(args3)).WillOnce(Return(true));
   obs.OnBeginFrame(args3);
   EXPECT_EQ(args3, obs.LastUsedBeginFrameArgs());
@@ -495,7 +523,8 @@
        SetNeedsBeginFramesCallsOnBeginFrameWithMissedTick) {
   now_src_->SetNowMicroseconds(10010);
   EXPECT_CALL((*obs_), OnBeginFrame(CreateBeginFrameArgsForTesting(
-                           10000, 20000, 10000, BeginFrameArgs::MISSED)));
+                           BEGINFRAME_FROM_HERE, 10000, 20000, 10000,
+                           BeginFrameArgs::MISSED)));
   source_->SetNeedsBeginFrames(true);  // Should cause the last tick to be sent
   // No tasks should need to be run for this to occur.
 }
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 3e6f6c6..0cce5dc 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -470,20 +470,16 @@
   // draining the queue if we don't catch up. If we consistently can't catch
   // up, our fallback should be to lower our frame rate.
   base::TimeTicks now = Now();
-  base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
-  while (!begin_retro_frame_args_.empty()) {
-    base::TimeTicks adjusted_deadline = AdjustedBeginImplFrameDeadline(
-        begin_retro_frame_args_.front(), draw_duration_estimate);
-    if (now <= adjusted_deadline)
-      break;
 
-    TRACE_EVENT_INSTANT2("cc",
-                         "Scheduler::BeginRetroFrame discarding",
-                         TRACE_EVENT_SCOPE_THREAD,
-                         "deadline - now",
-                         (adjusted_deadline - now).InMicroseconds(),
-                         "BeginFrameArgs",
-                         begin_retro_frame_args_.front().AsValue());
+  while (!begin_retro_frame_args_.empty()) {
+    const BeginFrameArgs& args = begin_retro_frame_args_.front();
+    base::TimeTicks expiration_time = args.frame_time + args.interval;
+    if (now <= expiration_time)
+      break;
+    TRACE_EVENT_INSTANT2(
+        "cc", "Scheduler::BeginRetroFrame discarding", TRACE_EVENT_SCOPE_THREAD,
+        "expiration_time - now", (expiration_time - now).InMillisecondsF(),
+        "BeginFrameArgs", begin_retro_frame_args_.front().AsValue());
     begin_retro_frame_args_.pop_front();
     frame_source_->DidFinishFrame(begin_retro_frame_args_.size());
   }
@@ -564,19 +560,38 @@
   ProcessScheduledActions();
 
   state_machine_.OnBeginImplFrameDeadlinePending();
-  ScheduleBeginImplFrameDeadline(
-      AdjustedBeginImplFrameDeadline(args, draw_duration_estimate));
+
+  if (settings_.using_synchronous_renderer_compositor) {
+    // The synchronous renderer compositor has to make its GL calls
+    // within this call.
+    // TODO(brianderson): Have the OutputSurface initiate the deadline tasks
+    // so the synchronous renderer compositor can take advantage of splitting
+    // up the BeginImplFrame and deadline as well.
+    OnBeginImplFrameDeadline();
+  } else {
+    ScheduleBeginImplFrameDeadline(
+        AdjustedBeginImplFrameDeadline(args, draw_duration_estimate));
+  }
 }
 
 base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline(
     const BeginFrameArgs& args,
     base::TimeDelta draw_duration_estimate) const {
-  if (settings_.using_synchronous_renderer_compositor) {
-    // The synchronous compositor needs to draw right away.
+  // The synchronous compositor does not post a deadline task.
+  DCHECK(!settings_.using_synchronous_renderer_compositor);
+  if (settings_.main_thread_should_always_be_low_latency) {
+    // In main thread low latency mode, always start deadline early.
     return base::TimeTicks();
   } else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
     // We are ready to draw a new active tree immediately.
+    // We don't use Now() here because it's somewhat expensive to call.
     return base::TimeTicks();
+  } else if (settings_.main_thread_should_always_be_low_latency) {
+    // Post long deadline to keep advancing during idle period. After activation
+    // we will be able to trigger deadline early.
+    // TODO(weiliangc): Don't post deadline once input is deferred with
+    // BeginRetroFrames.
+    return args.frame_time + args.interval;
   } else if (state_machine_.needs_redraw()) {
     // We have an animation or fast input path on the impl thread that wants
     // to draw, so don't wait too long for a new active tree.
@@ -596,15 +611,6 @@
 void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) {
   TRACE_EVENT1(
       "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline);
-  if (settings_.using_synchronous_renderer_compositor) {
-    // The synchronous renderer compositor has to make its GL calls
-    // within this call.
-    // TODO(brianderson): Have the OutputSurface initiate the deadline tasks
-    // so the sychronous renderer compositor can take advantage of splitting
-    // up the BeginImplFrame and deadline as well.
-    OnBeginImplFrameDeadline();
-    return;
-  }
   begin_impl_frame_deadline_task_.Cancel();
   begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_);
 
@@ -618,7 +624,6 @@
 void Scheduler::OnBeginImplFrameDeadline() {
   TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline");
   begin_impl_frame_deadline_task_.Cancel();
-
   // We split the deadline actions up into two phases so the state machine
   // has a chance to trigger actions that should occur durring and after
   // the deadline separately. For example:
diff --git a/cc/scheduler/scheduler_settings.cc b/cc/scheduler/scheduler_settings.cc
index 84f0fcd..53abe7b 100644
--- a/cc/scheduler/scheduler_settings.cc
+++ b/cc/scheduler/scheduler_settings.cc
@@ -19,6 +19,7 @@
       using_synchronous_renderer_compositor(false),
       throttle_frame_production(true),
       disable_hi_res_timer_tasks_on_battery(false),
+      main_thread_should_always_be_low_latency(false),
       background_frame_interval(base::TimeDelta::FromSeconds(1)) {
 }
 
@@ -38,6 +39,8 @@
       throttle_frame_production(settings.throttle_frame_production),
       disable_hi_res_timer_tasks_on_battery(
           settings.disable_hi_res_timer_tasks_on_battery),
+      main_thread_should_always_be_low_latency(
+          settings.main_thread_should_always_be_low_latency),
       background_frame_interval(base::TimeDelta::FromSecondsD(
           1.0 / settings.background_animation_rate)) {
 }
@@ -64,6 +67,8 @@
   state->SetBoolean("throttle_frame_production", throttle_frame_production);
   state->SetBoolean("disable_hi_res_timer_tasks_on_battery",
                     disable_hi_res_timer_tasks_on_battery);
+  state->SetBoolean("main_thread_should_always_be_low_latency",
+                    main_thread_should_always_be_low_latency);
   state->SetInteger("background_frame_interval",
                     background_frame_interval.InMicroseconds());
   return state;
diff --git a/cc/scheduler/scheduler_settings.h b/cc/scheduler/scheduler_settings.h
index e3fd425..4ff3c7e 100644
--- a/cc/scheduler/scheduler_settings.h
+++ b/cc/scheduler/scheduler_settings.h
@@ -35,6 +35,12 @@
   bool throttle_frame_production;
   bool disable_hi_res_timer_tasks_on_battery;
 
+  // In main thread low latency mode the entire
+  // BeginMainFrame->Commit->Activation->Draw cycle should complete before
+  // starting the next cycle.  Additionally, BeginMainFrame and Commit are
+  // completed atomically with no other tasks or actions occuring between them.
+  bool main_thread_should_always_be_low_latency;
+
   base::TimeDelta background_frame_interval;
 
   scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index 5f56255..2946a2c 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -97,6 +97,8 @@
       return "COMMIT_STATE_READY_TO_COMMIT";
     case COMMIT_STATE_WAITING_FOR_ACTIVATION:
       return "COMMIT_STATE_WAITING_FOR_ACTIVATION";
+    case COMMIT_STATE_WAITING_FOR_DRAW:
+      return "COMMIT_STATE_WAITING_FOR_DRAW";
   }
   NOTREACHED();
   return "???";
@@ -592,9 +594,11 @@
 
   if (commit_was_aborted || settings_.main_frame_before_activation_enabled) {
     commit_state_ = COMMIT_STATE_IDLE;
+  } else if (settings_.impl_side_painting) {
+    commit_state_ = COMMIT_STATE_WAITING_FOR_ACTIVATION;
   } else {
-    commit_state_ = settings_.impl_side_painting
-                        ? COMMIT_STATE_WAITING_FOR_ACTIVATION
+    commit_state_ = settings_.main_thread_should_always_be_low_latency
+                        ? COMMIT_STATE_WAITING_FOR_DRAW
                         : COMMIT_STATE_IDLE;
   }
 
@@ -637,8 +641,11 @@
 }
 
 void SchedulerStateMachine::UpdateStateOnActivation() {
-  if (commit_state_ == COMMIT_STATE_WAITING_FOR_ACTIVATION)
-    commit_state_ = COMMIT_STATE_IDLE;
+  if (commit_state_ == COMMIT_STATE_WAITING_FOR_ACTIVATION) {
+    commit_state_ = settings_.main_thread_should_always_be_low_latency
+                        ? COMMIT_STATE_WAITING_FOR_DRAW
+                        : COMMIT_STATE_IDLE;
+  }
 
   if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION)
     output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
@@ -656,6 +663,9 @@
   if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
     forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
 
+  if (commit_state_ == COMMIT_STATE_WAITING_FOR_DRAW)
+    commit_state_ = COMMIT_STATE_IDLE;
+
   needs_redraw_ = false;
   active_tree_needs_first_draw_ = false;
 
@@ -991,6 +1001,11 @@
   DCHECK(commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED)
       << AsValue()->ToString();
   commit_state_ = COMMIT_STATE_READY_TO_COMMIT;
+  // In main thread low latency mode, commit should happen right after
+  // BeginFrame, meaning when this function is called, next action should be
+  // commit.
+  if (settings_.main_thread_should_always_be_low_latency)
+    DCHECK(ShouldCommit());
 }
 
 void SchedulerStateMachine::BeginMainFrameAborted(bool did_handle) {
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h
index c69c959..12f8635 100644
--- a/cc/scheduler/scheduler_state_machine.h
+++ b/cc/scheduler/scheduler_state_machine.h
@@ -68,6 +68,7 @@
     COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED,
     COMMIT_STATE_READY_TO_COMMIT,
     COMMIT_STATE_WAITING_FOR_ACTIVATION,
+    COMMIT_STATE_WAITING_FOR_DRAW,
   };
   static const char* CommitStateToString(CommitState state);
 
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc
index af6d83a..f46389b 100644
--- a/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -44,7 +44,8 @@
     SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
     SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED,
     SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
-    SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION};
+    SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION,
+    SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_DRAW};
 
 // Exposes the protected state fields of the SchedulerStateMachine for testing
 class StateMachine : public SchedulerStateMachine {
@@ -122,7 +123,8 @@
 
     EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
     EXPECT_FALSE(state.BeginFrameNeeded());
-    state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+    state.OnBeginImplFrame(
+        CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
 
     EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
     state.OnBeginImplFrameDeadline();
@@ -140,7 +142,8 @@
 
     EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
     EXPECT_FALSE(state.BeginFrameNeeded());
-    state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+    state.OnBeginImplFrame(
+        CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
     EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
     state.OnBeginImplFrameDeadline();
   }
@@ -158,7 +161,8 @@
 
     EXPECT_TRUE(state.BeginFrameNeeded());
 
-    state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+    state.OnBeginImplFrame(
+        CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
     EXPECT_ACTION_UPDATE_STATE(
         SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
   }
@@ -195,7 +199,7 @@
   EXPECT_TRUE(state.BeginFrameNeeded());
 
   // Commit to the pending tree.
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -211,7 +215,7 @@
 
   // Verify that the next commit starts while there is still a pending tree.
   state.SetNeedsCommit();
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -252,7 +256,7 @@
   state.SetNeedsRedraw(true);
   EXPECT_TRUE(state.RedrawPending());
   EXPECT_TRUE(state.BeginFrameNeeded());
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
   state.OnBeginImplFrameDeadline();
@@ -269,7 +273,7 @@
 
   // Failing the draw makes us require a commit.
   state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS);
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -289,7 +293,7 @@
   EXPECT_TRUE(state.RedrawPending());
   EXPECT_TRUE(state.BeginFrameNeeded());
 
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
   state.OnBeginImplFrameDeadline();
@@ -303,7 +307,7 @@
 
   // Missing high res content requires a commit (but not a redraw)
   state.DidDrawIfPossibleCompleted(DRAW_ABORTED_MISSING_HIGH_RES_CONTENT);
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
   EXPECT_FALSE(state.RedrawPending());
@@ -323,7 +327,7 @@
   state.SetNeedsRedraw(true);
   EXPECT_TRUE(state.RedrawPending());
   EXPECT_TRUE(state.BeginFrameNeeded());
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
   state.OnBeginImplFrameDeadline();
@@ -344,7 +348,7 @@
 
   // Failing the draw for animation checkerboards makes us require a commit.
   state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS);
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -365,7 +369,7 @@
   // Start a commit.
   state.SetNeedsCommit();
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -395,7 +399,7 @@
   EXPECT_TRUE(state.RedrawPending());
 
   // The redraw should be forced at the end of the next BeginImplFrame.
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -423,7 +427,7 @@
   // Start a commit.
   state.SetNeedsCommit();
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -480,7 +484,7 @@
   // Start a draw.
   state.SetNeedsRedraw(true);
   EXPECT_TRUE(state.BeginFrameNeeded());
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
   state.OnBeginImplFrameDeadline();
@@ -497,7 +501,7 @@
 
   // We should not be trying to draw again now, but we have a commit pending.
   EXPECT_TRUE(state.BeginFrameNeeded());
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
@@ -523,7 +527,7 @@
 
   // Draw the first frame.
   EXPECT_TRUE(state.BeginFrameNeeded());
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
@@ -542,7 +546,7 @@
 
   // Move to another frame. This should now draw.
   EXPECT_TRUE(state.BeginFrameNeeded());
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
 
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -680,7 +684,8 @@
       state.SetVisible(false);
       state.SetNeedsRedraw(true);
       if (j == 1)
-        state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+        state.OnBeginImplFrame(
+            CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
 
       state.SetCanDraw(false);
       EXPECT_NE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
@@ -702,7 +707,7 @@
   state.SetNeedsRedraw(true);
   state.SetVisible(true);
   state.SetCanDraw(false);
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
   EXPECT_ACTION_UPDATE_STATE(
@@ -730,7 +735,7 @@
   EXPECT_TRUE(state.BeginFrameNeeded());
 
   // Begin the frame.
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
   EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
@@ -766,7 +771,7 @@
             state.begin_impl_frame_state());
   EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
 
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
             state.begin_impl_frame_state());
   EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
@@ -803,7 +808,7 @@
   state.SetNeedsCommit();
 
   // Begin the frame.
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
   EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
@@ -840,6 +845,160 @@
   EXPECT_FALSE(state.needs_redraw());
 }
 
+TEST(SchedulerStateMachineTest, TestFullCycleWithMainThreadLowLatencyMode) {
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.main_thread_should_always_be_low_latency = true;
+  StateMachine state(scheduler_settings);
+  state.SetCanStart();
+  state.UpdateState(state.NextAction());
+  state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+  state.SetVisible(true);
+  state.SetCanDraw(true);
+
+  // Start clean and set commit.
+  state.SetNeedsCommit();
+
+  // Begin the frame.
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+  EXPECT_ACTION_UPDATE_STATE(
+      SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
+            state.CommitState());
+  EXPECT_FALSE(state.NeedsCommit());
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+  // Tell the scheduler the frame finished.
+  state.NotifyBeginMainFrameStarted();
+  state.NotifyReadyToCommit();
+  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
+            state.CommitState());
+
+  // Commit.
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+  EXPECT_TRUE(state.active_tree_needs_first_draw());
+  EXPECT_TRUE(state.needs_redraw());
+
+  // Now commit should wait for draw.
+  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_DRAW,
+            state.CommitState());
+
+  // Swap throttled. Do not draw.
+  state.DidSwapBuffers();
+  state.OnBeginImplFrameDeadline();
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+  state.DidSwapBuffersComplete();
+
+  // Haven't draw since last commit, do not begin new main frame.
+  state.SetNeedsCommit();
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+  // At BeginImplFrame deadline, draw.
+  state.OnBeginImplFrameDeadline();
+  EXPECT_ACTION_UPDATE_STATE(
+      SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+  state.DidSwapBuffers();
+  state.DidDrawIfPossibleCompleted(DRAW_SUCCESS);
+  state.DidSwapBuffersComplete();
+
+  // Now will be able to start main frame.
+  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+  EXPECT_FALSE(state.needs_redraw());
+  EXPECT_ACTION_UPDATE_STATE(
+      SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+}
+
+TEST(SchedulerStateMachineTest,
+     TestFullCycleWithMainThreadLowLatencyMode_ImplSidePaint) {
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.main_thread_should_always_be_low_latency = true;
+  scheduler_settings.impl_side_painting = true;
+  StateMachine state(scheduler_settings);
+  state.SetCanStart();
+  state.UpdateState(state.NextAction());
+  state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+  state.SetVisible(true);
+  state.SetCanDraw(true);
+
+  // Start clean and set commit.
+  state.SetNeedsCommit();
+
+  // Begin the frame.
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+  EXPECT_ACTION_UPDATE_STATE(
+      SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
+            state.CommitState());
+  EXPECT_FALSE(state.NeedsCommit());
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+  // Tell the scheduler the frame finished.
+  state.NotifyBeginMainFrameStarted();
+  state.NotifyReadyToCommit();
+  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
+            state.CommitState());
+
+  // Commit.
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+
+  // Now commit should wait for activation.
+  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION,
+            state.CommitState());
+
+  // No activation yet, so this commit is not drawn yet. Force to draw this
+  // frame, and still block BeginMainFrame.
+  state.SetNeedsRedraw(true);
+  state.SetNeedsCommit();
+  state.OnBeginImplFrameDeadline();
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+  EXPECT_ACTION_UPDATE_STATE(
+      SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+  // Cannot BeginMainFrame yet since last commit is not yet activated and drawn.
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION,
+            state.CommitState());
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+  // Now activate sync tree.
+  state.NotifyReadyToActivate();
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE);
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+  EXPECT_TRUE(state.active_tree_needs_first_draw());
+  EXPECT_TRUE(state.needs_redraw());
+  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_DRAW,
+            state.CommitState());
+
+  // Swap throttled. Do not draw.
+  state.DidSwapBuffers();
+  state.OnBeginImplFrameDeadline();
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+  state.DidSwapBuffersComplete();
+
+  // Haven't draw since last commit, do not begin new main frame.
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+  // At BeginImplFrame deadline, draw. This draws unblocks BeginMainFrame.
+  state.OnBeginImplFrameDeadline();
+  EXPECT_ACTION_UPDATE_STATE(
+      SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+  state.DidSwapBuffers();
+  state.DidDrawIfPossibleCompleted(DRAW_SUCCESS);
+  state.DidSwapBuffersComplete();
+
+  // Now will be able to start main frame.
+  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+  EXPECT_FALSE(state.needs_redraw());
+  EXPECT_ACTION_UPDATE_STATE(
+      SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+}
+
 TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) {
   SchedulerSettings default_scheduler_settings;
   StateMachine state(default_scheduler_settings);
@@ -853,7 +1012,7 @@
   state.SetNeedsCommit();
 
   // Begin the frame.
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
   EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
@@ -894,7 +1053,7 @@
   EXPECT_FALSE(state.needs_redraw());
 
   // Next BeginImplFrame should initiate second commit.
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
 }
@@ -922,7 +1081,7 @@
   state.SetNeedsCommit();
 
   // Begin the frame while visible.
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
   EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
@@ -952,7 +1111,7 @@
   EXPECT_TRUE(state.NeedsCommit());
 
   // Start a new frame.
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
 
@@ -991,7 +1150,7 @@
 
   // Start a new frame; draw because this is the first frame since output
   // surface init'd.
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
   state.OnBeginImplFrameDeadline();
@@ -1043,7 +1202,7 @@
 
   // Become visible and start a new frame.
   state.SetVisible(true);
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
@@ -1108,7 +1267,7 @@
   EXPECT_TRUE(state.NeedsCommit());
 
   // We should get that commit when we begin the next frame.
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1145,7 +1304,7 @@
   EXPECT_TRUE(state.NeedsCommit());
 
   // Begin a frame when not visible, the scheduler animates but does not commit.
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
@@ -1171,14 +1330,14 @@
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
   // Check that the first init does not SetNeedsCommit.
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
   state.OnBeginImplFrameDeadline();
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
   // Check that a needs commit initiates a BeginMainFrame.
   state.SetNeedsCommit();
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
 }
@@ -1208,7 +1367,7 @@
   state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
 
   // When the context is recreated, we should begin a commit.
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
 }
@@ -1232,14 +1391,14 @@
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
   // Once context recreation begins, nothing should happen.
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
   state.OnBeginImplFrameDeadline();
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
   // While context is recreating, commits shouldn't begin.
   state.SetNeedsCommit();
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
   state.OnBeginImplFrameDeadline();
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1265,7 +1424,7 @@
 
   // Once the context is recreated, whether we draw should be based on
   // SetCanDraw.
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
   state.OnBeginImplFrameDeadline();
@@ -1293,7 +1452,7 @@
 
   // Set damage and expect a draw.
   state.SetNeedsRedraw(true);
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1328,7 +1487,7 @@
   EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
             state.NextAction());
 
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
             state.begin_impl_frame_state());
   EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
@@ -1360,7 +1519,7 @@
 
   // Set damage and expect a draw.
   state.SetNeedsRedraw(true);
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1395,7 +1554,7 @@
   EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
             state.NextAction());
 
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
             state.begin_impl_frame_state());
   EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
@@ -1416,7 +1575,7 @@
 
   // After we get a new output surface, the commit flow should start.
   state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1452,7 +1611,7 @@
   state.DidCreateAndInitializeOutputSurface();
 
   EXPECT_FALSE(state.RedrawPending());
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME,
             state.NextAction());
 }
@@ -1584,7 +1743,7 @@
 
   // This test mirrors what happens during the first frame of a scroll gesture.
   // First we get the input event and a BeginFrame.
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
 
   // As a response the compositor requests a redraw and a commit to tell the
   // main thread about the new scroll offset.
@@ -1619,7 +1778,7 @@
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
@@ -1644,7 +1803,7 @@
   // in prefer impl latency mode.
   state.SetNeedsRedraw(true);
   state.SetNeedsCommit();
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1681,7 +1840,7 @@
   // and did not just swap.
   state.SetNeedsCommit();
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
   EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
   state.OnBeginImplFrameDeadline();
@@ -1699,7 +1858,7 @@
 
   state.SetNeedsCommit();
 
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1726,7 +1885,7 @@
   EXPECT_TRUE(state.BeginFrameNeeded());
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
 
   state.OnBeginImplFrameDeadlinePending();
@@ -1752,7 +1911,7 @@
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
   EXPECT_TRUE(state.BeginFrameNeeded());
 
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1780,7 +1939,7 @@
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
   EXPECT_TRUE(state.BeginFrameNeeded());
 
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1812,7 +1971,7 @@
   EXPECT_TRUE(state.BeginFrameNeeded());
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
-  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
 
   state.SetNeedsAnimate();
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index 636beb0..2992dbc 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -168,19 +168,32 @@
   void AdvanceFrame() {
     TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"),
                  "FakeSchedulerClient::AdvanceFrame");
+    bool previous_deadline_pending =
+        scheduler_->BeginImplFrameDeadlinePending();
     if (ExternalBeginFrame()) {
-      // Creep the time forward so that any BeginFrameArgs is not equal to the
-      // last one otherwise we violate the BeginFrameSource contract.
-      now_src_->AdvanceNowMicroseconds(1);
-      fake_external_begin_frame_source_->TestOnBeginFrame(
-          CreateBeginFrameArgsForTesting(now_src_));
+      SendNextBeginFrame();
+      // This could be the previous deadline or a new one.
       EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
     }
-
+    // Consume previous deadline first. It is important that we check for the
+    // existence of a previous deadline so that we do not consume the new one.
+    if (previous_deadline_pending) {
+      EXPECT_TRUE(task_runner().RunTasksWhile(ImplFrameDeadlinePending(true)));
+    }
+    // Then run tasks until new deadline is scheduled.
     EXPECT_TRUE(task_runner().RunTasksWhile(ImplFrameDeadlinePending(false)));
     EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
   }
 
+  void SendNextBeginFrame() {
+    DCHECK(ExternalBeginFrame());
+    // Creep the time forward so that any BeginFrameArgs is not equal to the
+    // last one otherwise we violate the BeginFrameSource contract.
+    now_src_->AdvanceNow(BeginFrameArgs::DefaultInterval());
+    fake_external_begin_frame_source_->TestOnBeginFrame(
+        CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, now_src_));
+  }
+
   OrderedSimpleTaskRunner& task_runner() { return *task_runner_; }
   TestNowSource* now_src() { return now_src_.get(); }
 
@@ -1167,7 +1180,8 @@
   scheduler->NotifyReadyToCommit();
   scheduler->SetNeedsRedraw();
 
-  BeginFrameArgs frame_args = CreateBeginFrameArgsForTesting(client.now_src());
+  BeginFrameArgs frame_args =
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, client.now_src());
   frame_args.interval = base::TimeDelta::FromMilliseconds(1000);
   client.fake_external_begin_frame_source()->TestOnBeginFrame(frame_args);
 
@@ -1240,7 +1254,8 @@
 
   // Create a BeginFrame with a long deadline to avoid race conditions.
   // This is the first BeginFrame, which will be handled immediately.
-  BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+  BeginFrameArgs args =
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, client.now_src());
   args.deadline += base::TimeDelta::FromHours(1);
   client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
   EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
@@ -1318,7 +1333,8 @@
 
   // Create a BeginFrame with a long deadline to avoid race conditions.
   // This is the first BeginFrame, which will be handled immediately.
-  BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+  BeginFrameArgs args =
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, client.now_src());
   args.deadline += base::TimeDelta::FromHours(1);
   client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
   EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
@@ -1387,6 +1403,131 @@
   client.Reset();
 }
 
+TEST(SchedulerTest, RetroFrameDoesNotExpireTooEarly) {
+  FakeSchedulerClient client;
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  scheduler->SetCanStart();
+  scheduler->SetVisible(true);
+  scheduler->SetCanDraw(true);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+  client.Reset();
+  scheduler->SetNeedsCommit();
+  EXPECT_TRUE(client.needs_begin_frames());
+  EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
+
+  client.Reset();
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+  client.Reset();
+  scheduler->NotifyBeginMainFrameStarted();
+
+  client.Reset();
+  client.SendNextBeginFrame();
+  // This BeginFrame is queued up as a retro frame.
+  EXPECT_NO_ACTION(client);
+  // The previous deadline is still pending.
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+  client.Reset();
+  // This commit should schedule the (previous) deadline to trigger immediately.
+  scheduler->NotifyReadyToCommit();
+  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+
+  client.Reset();
+  // The deadline task should trigger causing a draw.
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
+  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+
+  // Keep animating.
+  client.Reset();
+  scheduler->SetNeedsAnimate();
+  scheduler->SetNeedsRedraw();
+  EXPECT_NO_ACTION(client);
+
+  // Let's advance sufficiently past the next frame's deadline.
+  client.now_src()->AdvanceNow(
+      BeginFrameArgs::DefaultInterval() -
+      BeginFrameArgs::DefaultEstimatedParentDrawTime() +
+      base::TimeDelta::FromMicroseconds(1));
+
+  // The retro frame hasn't expired yet.
+  client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(false));
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+  // This is an immediate deadline case.
+  client.Reset();
+  client.task_runner().RunPendingTasks();
+  EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+  EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client);
+}
+
+TEST(SchedulerTest, RetroFrameDoesNotExpireTooLate) {
+  FakeSchedulerClient client;
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+  scheduler->SetCanStart();
+  scheduler->SetVisible(true);
+  scheduler->SetCanDraw(true);
+  InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+  client.Reset();
+  scheduler->SetNeedsCommit();
+  EXPECT_TRUE(client.needs_begin_frames());
+  EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
+
+  client.Reset();
+  client.AdvanceFrame();
+  EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+  client.Reset();
+  scheduler->NotifyBeginMainFrameStarted();
+
+  client.Reset();
+  client.SendNextBeginFrame();
+  // This BeginFrame is queued up as a retro frame.
+  EXPECT_NO_ACTION(client);
+  // The previous deadline is still pending.
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+  client.Reset();
+  // This commit should schedule the (previous) deadline to trigger immediately.
+  scheduler->NotifyReadyToCommit();
+  EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+
+  client.Reset();
+  // The deadline task should trigger causing a draw.
+  EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+  client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
+  EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+  EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+
+  // Keep animating.
+  client.Reset();
+  scheduler->SetNeedsAnimate();
+  scheduler->SetNeedsRedraw();
+  EXPECT_NO_ACTION(client);
+
+  // Let's advance sufficiently past the next frame's deadline.
+  client.now_src()->AdvanceNow(BeginFrameArgs::DefaultInterval() +
+                               base::TimeDelta::FromMicroseconds(1));
+
+  // The retro frame should've expired.
+  EXPECT_NO_ACTION(client);
+}
+
 void BeginFramesNotFromClient(bool use_external_begin_frame_source,
                               bool throttle_frame_production) {
   FakeSchedulerClient client;
@@ -1793,7 +1934,8 @@
   // Create a BeginFrame with a long deadline to avoid race conditions.
   // This is the first BeginFrame, which will be handled immediately.
   client.Reset();
-  BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+  BeginFrameArgs args =
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, client.now_src());
   args.deadline += base::TimeDelta::FromHours(1);
   client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
   EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
@@ -1852,7 +1994,8 @@
   // Create a BeginFrame with a long deadline to avoid race conditions.
   // This is the first BeginFrame, which will be handled immediately.
   client.Reset();
-  BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
+  BeginFrameArgs args =
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, client.now_src());
   args.deadline += base::TimeDelta::FromHours(1);
   client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
   EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
diff --git a/cc/surfaces/BUILD.gn b/cc/surfaces/BUILD.gn
index a45e786..ea44068 100644
--- a/cc/surfaces/BUILD.gn
+++ b/cc/surfaces/BUILD.gn
@@ -2,6 +2,14 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+source_set("surface_id") {
+  sources = [
+    "surface_id.h",
+  ]
+
+  deps = [ "//base" ]
+}
+
 component("surfaces") {
   output_name = "cc_surfaces"
   sources = [
@@ -15,7 +23,6 @@
     "surface_factory.cc",
     "surface_factory.h",
     "surface_factory_client.h",
-    "surface_id.h",
     "surface_id_allocator.cc",
     "surface_id_allocator.h",
     "surface_manager.cc",
@@ -28,6 +35,7 @@
   defines = [ "CC_SURFACES_IMPLEMENTATION=1" ]
 
   deps = [
+    ":surface_id",
     "//base",
     "//base/third_party/dynamic_annotations",
     "//cc",
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc
index a8ae27a..9257446 100644
--- a/cc/surfaces/display.cc
+++ b/cc/surfaces/display.cc
@@ -49,15 +49,23 @@
   return output_surface_->BindToClient(this);
 }
 
-void Display::Resize(SurfaceId id,
-                     const gfx::Size& size,
-                     float device_scale_factor) {
+void Display::SetSurfaceId(SurfaceId id, float device_scale_factor) {
   current_surface_id_ = id;
-  current_surface_size_ = size;
   device_scale_factor_ = device_scale_factor;
   client_->DisplayDamaged();
 }
 
+void Display::Resize(const gfx::Size& size) {
+  if (size == current_surface_size_)
+    return;
+  // Need to ensure all pending swaps have executed before the window is
+  // resized, or D3D11 will scale the swap output.
+  if (renderer_ && settings_.finish_rendering_on_resize)
+    renderer_->Finish();
+  current_surface_size_ = size;
+  client_->DisplayDamaged();
+}
+
 void Display::InitializeRenderer() {
   if (resource_provider_)
     return;
@@ -112,6 +120,9 @@
   benchmark_instrumentation::IssueDisplayRenderingStatsEvent();
   DelegatedFrameData* frame_data = frame->delegated_frame_data.get();
 
+  gfx::Size surface_size =
+      frame_data->render_pass_list.back()->output_rect.size();
+
   gfx::Rect device_viewport_rect = gfx::Rect(current_surface_size_);
   gfx::Rect device_clip_rect = device_viewport_rect;
   bool disable_picture_quad_image_filtering = false;
@@ -122,7 +133,14 @@
                        device_viewport_rect,
                        device_clip_rect,
                        disable_picture_quad_image_filtering);
-  renderer_->SwapBuffers(frame->metadata);
+
+  bool disable_swap = surface_size != current_surface_size_;
+  if (disable_swap) {
+    DidSwapBuffers();
+  } else {
+    renderer_->SwapBuffers(frame->metadata);
+  }
+
   for (SurfaceAggregator::SurfaceIndexMap::iterator it =
            aggregator_->previous_contained_surfaces().begin();
        it != aggregator_->previous_contained_surfaces().end();
@@ -131,6 +149,8 @@
     if (surface)
       surface->RunDrawCallbacks();
   }
+  if (disable_swap)
+    DidSwapBuffersComplete();
   return true;
 }
 
diff --git a/cc/surfaces/display.h b/cc/surfaces/display.h
index a0bb62a..47c55bb 100644
--- a/cc/surfaces/display.h
+++ b/cc/surfaces/display.h
@@ -51,9 +51,8 @@
 
   // device_scale_factor is used to communicate to the external window system
   // what scale this was rendered at.
-  void Resize(SurfaceId id,
-              const gfx::Size& new_size,
-              float device_scale_factor);
+  void SetSurfaceId(SurfaceId id, float device_scale_factor);
+  void Resize(const gfx::Size& new_size);
   bool Draw();
 
   SurfaceId CurrentSurfaceId();
diff --git a/cc/surfaces/surface.cc b/cc/surfaces/surface.cc
index 600455f..c7b1145 100644
--- a/cc/surfaces/surface.cc
+++ b/cc/surfaces/surface.cc
@@ -18,9 +18,8 @@
 // completely damaged the first time they're drawn from.
 static const int kFrameIndexStart = 2;
 
-Surface::Surface(SurfaceId id, const gfx::Size& size, SurfaceFactory* factory)
+Surface::Surface(SurfaceId id, SurfaceFactory* factory)
     : surface_id_(id),
-      size_(size),
       factory_(factory->AsWeakPtr()),
       frame_index_(kFrameIndexStart) {
 }
diff --git a/cc/surfaces/surface.h b/cc/surfaces/surface.h
index 7b3fbc1..ed0061d 100644
--- a/cc/surfaces/surface.h
+++ b/cc/surfaces/surface.h
@@ -34,10 +34,9 @@
 
 class CC_SURFACES_EXPORT Surface {
  public:
-  Surface(SurfaceId id, const gfx::Size& size, SurfaceFactory* factory);
+  Surface(SurfaceId id, SurfaceFactory* factory);
   ~Surface();
 
-  const gfx::Size& size() const { return size_; }
   SurfaceId surface_id() const { return surface_id_; }
 
   void QueueFrame(scoped_ptr<CompositorFrame> frame,
@@ -74,7 +73,6 @@
   void ClearCopyRequests();
 
   SurfaceId surface_id_;
-  gfx::Size size_;
   base::WeakPtr<SurfaceFactory> factory_;
   // TODO(jamesr): Support multiple frames in flight.
   scoped_ptr<CompositorFrame> current_frame_;
diff --git a/cc/surfaces/surface_aggregator.cc b/cc/surfaces/surface_aggregator.cc
index f5689c5..2334d14 100644
--- a/cc/surfaces/surface_aggregator.cc
+++ b/cc/surfaces/surface_aggregator.cc
@@ -153,13 +153,14 @@
 }
 
 gfx::Rect SurfaceAggregator::DamageRectForSurface(const Surface* surface,
-                                                  const RenderPass& source) {
+                                                  const RenderPass& source,
+                                                  const gfx::Rect& full_rect) {
   int previous_index = previous_contained_surfaces_[surface->surface_id()];
   if (previous_index == surface->frame_index())
     return gfx::Rect();
   else if (previous_index == surface->frame_index() - 1)
     return source.damage_rect;
-  return gfx::Rect(surface->size());
+  return full_rect;
 }
 
 void SurfaceAggregator::HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad,
@@ -267,7 +268,8 @@
       gfx::UnionRects(dest_pass->damage_rect,
                       MathUtil::MapEnclosingClippedRect(
                           surface_quad->quadTransform(),
-                          DamageRectForSurface(surface, last_pass)));
+                          DamageRectForSurface(surface, last_pass,
+                                               surface_quad->visible_rect)));
 
   referenced_surfaces_.erase(it);
 }
@@ -364,9 +366,8 @@
     RenderPassId remapped_pass_id =
         RemapPassId(source.id, surface->surface_id());
 
-    copy_pass->SetAll(remapped_pass_id,
-                      source.output_rect,
-                      DamageRectForSurface(surface, source),
+    copy_pass->SetAll(remapped_pass_id, source.output_rect,
+                      DamageRectForSurface(surface, source, source.output_rect),
                       source.transform_to_root_target,
                       source.has_transparent_background);
 
@@ -415,6 +416,9 @@
   referenced_surfaces_.erase(it);
   DCHECK(referenced_surfaces_.empty());
 
+  if (dest_pass_list_->empty())
+    return nullptr;
+
   dest_pass_list_ = NULL;
   RemoveUnreferencedChildren();
   contained_surfaces_.swap(previous_contained_surfaces_);
diff --git a/cc/surfaces/surface_aggregator.h b/cc/surfaces/surface_aggregator.h
index 6965041..1e68643 100644
--- a/cc/surfaces/surface_aggregator.h
+++ b/cc/surfaces/surface_aggregator.h
@@ -63,7 +63,8 @@
                      RenderPassList* render_pass_list);
   int ChildIdForSurface(Surface* surface);
   gfx::Rect DamageRectForSurface(const Surface* surface,
-                                 const RenderPass& source);
+                                 const RenderPass& source,
+                                 const gfx::Rect& full_rect);
 
   SurfaceManager* manager_;
   ResourceProvider* provider_;
diff --git a/cc/surfaces/surface_aggregator_unittest.cc b/cc/surfaces/surface_aggregator_unittest.cc
index 2e47708..1daff52 100644
--- a/cc/surfaces/surface_aggregator_unittest.cc
+++ b/cc/surfaces/surface_aggregator_unittest.cc
@@ -59,7 +59,7 @@
 
 TEST_F(SurfaceAggregatorTest, ValidSurfaceNoFrame) {
   SurfaceId one_id(7);
-  factory_.Create(one_id, SurfaceSize());
+  factory_.Create(one_id);
   scoped_ptr<CompositorFrame> frame = aggregator_.Aggregate(one_id);
   EXPECT_FALSE(frame);
   factory_.Destroy(one_id);
@@ -72,7 +72,7 @@
   virtual void SetUp() {
     SurfaceAggregatorTest::SetUp();
     root_surface_id_ = allocator_.GenerateId();
-    factory_.Create(root_surface_id_, SurfaceSize());
+    factory_.Create(root_surface_id_);
   }
 
   virtual void TearDown() {
@@ -157,7 +157,7 @@
 
 TEST_F(SurfaceAggregatorValidSurfaceTest, OpacityCopied) {
   SurfaceId embedded_surface_id = allocator_.GenerateId();
-  factory_.Create(embedded_surface_id, SurfaceSize());
+  factory_.Create(embedded_surface_id);
 
   test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
   test::Pass embedded_passes[] = {
@@ -190,9 +190,9 @@
 
 TEST_F(SurfaceAggregatorValidSurfaceTest, OpacityCombinedWithNesting) {
   SurfaceId surface_id1 = allocator_.GenerateId();
-  factory_.Create(surface_id1, SurfaceSize());
+  factory_.Create(surface_id1);
   SurfaceId surface_id2 = allocator_.GenerateId();
-  factory_.Create(surface_id2, SurfaceSize());
+  factory_.Create(surface_id2);
 
   // |surface_id1| is color quad.
   {
@@ -258,7 +258,7 @@
 // color quad should be aggregated into the final frame.
 TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleSurfaceReference) {
   SurfaceId embedded_surface_id = allocator_.GenerateId();
-  factory_.Create(embedded_surface_id, SurfaceSize());
+  factory_.Create(embedded_surface_id);
 
   test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
   test::Pass embedded_passes[] = {
@@ -287,7 +287,7 @@
 
 TEST_F(SurfaceAggregatorValidSurfaceTest, CopyRequest) {
   SurfaceId embedded_surface_id = allocator_.GenerateId();
-  factory_.Create(embedded_surface_id, SurfaceSize());
+  factory_.Create(embedded_surface_id);
 
   test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
   test::Pass embedded_passes[] = {
@@ -344,7 +344,7 @@
 // Root surface may contain copy requests.
 TEST_F(SurfaceAggregatorValidSurfaceTest, RootCopyRequest) {
   SurfaceId embedded_surface_id = allocator_.GenerateId();
-  factory_.Create(embedded_surface_id, SurfaceSize());
+  factory_.Create(embedded_surface_id);
 
   test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
   test::Pass embedded_passes[] = {
@@ -432,7 +432,7 @@
 // This tests referencing a surface that has multiple render passes.
 TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSurfaceReference) {
   SurfaceId embedded_surface_id = child_allocator_.GenerateId();
-  factory_.Create(embedded_surface_id, SurfaceSize());
+  factory_.Create(embedded_surface_id);
 
   RenderPassId pass_ids[] = {RenderPassId(1, 1), RenderPassId(1, 2),
                              RenderPassId(1, 3)};
@@ -590,7 +590,7 @@
 // should also just be dropped.
 TEST_F(SurfaceAggregatorValidSurfaceTest, ValidSurfaceReferenceWithNoFrame) {
   SurfaceId surface_with_no_frame_id = allocator_.GenerateId();
-  factory_.Create(surface_with_no_frame_id, gfx::Size(5, 5));
+  factory_.Create(surface_with_no_frame_id);
   test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
                         test::Quad::SurfaceQuad(surface_with_no_frame_id, 1.f),
                         test::Quad::SolidColorQuad(SK_ColorBLUE)};
@@ -628,7 +628,7 @@
 // Tests a more complex cycle with one intermediate surface.
 TEST_F(SurfaceAggregatorValidSurfaceTest, TwoSurfaceCyclicalReference) {
   SurfaceId child_surface_id = allocator_.GenerateId();
-  factory_.Create(child_surface_id, SurfaceSize());
+  factory_.Create(child_surface_id);
 
   test::Quad parent_quads[] = {test::Quad::SolidColorQuad(SK_ColorBLUE),
                                test::Quad::SurfaceQuad(child_surface_id, 1.f),
@@ -667,7 +667,7 @@
 // namespace and update RenderPassDrawQuad's id references to match.
 TEST_F(SurfaceAggregatorValidSurfaceTest, RenderPassIdMapping) {
   SurfaceId child_surface_id = allocator_.GenerateId();
-  factory_.Create(child_surface_id, SurfaceSize());
+  factory_.Create(child_surface_id);
 
   RenderPassId child_pass_id[] = {RenderPassId(1, 1), RenderPassId(1, 2)};
   test::Quad child_quad[][1] = {{test::Quad::SolidColorQuad(SK_ColorGREEN)},
@@ -795,7 +795,7 @@
 
   RenderPassId pass_id(1, 1);
   SurfaceId grandchild_surface_id = allocator_.GenerateId();
-  factory_.Create(grandchild_surface_id, SurfaceSize());
+  factory_.Create(grandchild_surface_id);
   scoped_ptr<RenderPass> grandchild_pass = RenderPass::Create();
   gfx::Rect output_rect(SurfaceSize());
   gfx::Rect damage_rect(SurfaceSize());
@@ -807,7 +807,7 @@
   QueuePassAsFrame(grandchild_pass.Pass(), grandchild_surface_id);
 
   SurfaceId child_one_surface_id = allocator_.GenerateId();
-  factory_.Create(child_one_surface_id, SurfaceSize());
+  factory_.Create(child_one_surface_id);
 
   scoped_ptr<RenderPass> child_one_pass = RenderPass::Create();
   child_one_pass->SetNew(
@@ -825,7 +825,7 @@
   QueuePassAsFrame(child_one_pass.Pass(), child_one_surface_id);
 
   SurfaceId child_two_surface_id = allocator_.GenerateId();
-  factory_.Create(child_two_surface_id, SurfaceSize());
+  factory_.Create(child_two_surface_id);
 
   scoped_ptr<RenderPass> child_two_pass = RenderPass::Create();
   child_two_pass->SetNew(
@@ -903,7 +903,7 @@
 // affected.
 TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
   SurfaceId child_surface_id = allocator_.GenerateId();
-  factory_.Create(child_surface_id, SurfaceSize());
+  factory_.Create(child_surface_id);
   RenderPassId child_pass_id[] = {RenderPassId(1, 1), RenderPassId(1, 2)};
   test::Quad child_quads[][1] = {
       {test::Quad::SolidColorQuad(SK_ColorGREEN)},
@@ -1038,7 +1038,7 @@
 // Tests that damage rects are aggregated correctly when surfaces change.
 TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
   SurfaceId child_surface_id = allocator_.GenerateId();
-  factory_.Create(child_surface_id, SurfaceSize());
+  factory_.Create(child_surface_id);
   RenderPassId child_pass_id = RenderPassId(1, 1);
   test::Quad child_quads[] = {test::Quad::RenderPassQuad(child_pass_id)};
   test::Pass child_passes[] = {
@@ -1300,7 +1300,7 @@
   ResourceTrackingSurfaceFactoryClient client;
   SurfaceFactory factory(&manager_, &client);
   SurfaceId surface_id(7u);
-  factory.Create(surface_id, SurfaceSize());
+  factory.Create(surface_id);
 
   ResourceProvider::ResourceId ids[] = {11, 12, 13};
   SubmitFrameWithResources(ids, arraysize(ids), &factory, surface_id);
@@ -1328,9 +1328,9 @@
   ResourceTrackingSurfaceFactoryClient client;
   SurfaceFactory factory(&manager_, &client);
   SurfaceId surface_id(7u);
-  factory.Create(surface_id, SurfaceSize());
+  factory.Create(surface_id);
   SurfaceId surface_id2(8u);
-  factory.Create(surface_id2, SurfaceSize());
+  factory.Create(surface_id2);
 
   ResourceProvider::ResourceId ids[] = {11, 12, 13};
   SubmitFrameWithResources(ids, arraysize(ids), &factory, surface_id);
diff --git a/cc/surfaces/surface_factory.cc b/cc/surfaces/surface_factory.cc
index 574f5d1..fd5a6d4 100644
--- a/cc/surfaces/surface_factory.cc
+++ b/cc/surfaces/surface_factory.cc
@@ -30,8 +30,8 @@
   surface_map_.clear();
 }
 
-void SurfaceFactory::Create(SurfaceId surface_id, const gfx::Size& size) {
-  scoped_ptr<Surface> surface(new Surface(surface_id, size, this));
+void SurfaceFactory::Create(SurfaceId surface_id) {
+  scoped_ptr<Surface> surface(new Surface(surface_id, this));
   manager_->RegisterSurface(surface.get());
   DCHECK(!surface_map_.count(surface_id));
   surface_map_.add(surface_id, surface.Pass());
diff --git a/cc/surfaces/surface_factory.h b/cc/surfaces/surface_factory.h
index 8e9211c..eba32d2 100644
--- a/cc/surfaces/surface_factory.h
+++ b/cc/surfaces/surface_factory.h
@@ -38,7 +38,7 @@
   SurfaceFactory(SurfaceManager* manager, SurfaceFactoryClient* client);
   ~SurfaceFactory();
 
-  void Create(SurfaceId surface_id, const gfx::Size& size);
+  void Create(SurfaceId surface_id);
   void Destroy(SurfaceId surface_id);
   void DestroyAll();
   // A frame can only be submitted to a surface created by this factory,
diff --git a/cc/surfaces/surface_factory_unittest.cc b/cc/surfaces/surface_factory_unittest.cc
index 14a25fd..84dcc5e 100644
--- a/cc/surfaces/surface_factory_unittest.cc
+++ b/cc/surfaces/surface_factory_unittest.cc
@@ -39,7 +39,7 @@
 class SurfaceFactoryTest : public testing::Test {
  public:
   SurfaceFactoryTest() : factory_(&manager_, &client_), surface_id_(3) {
-    factory_.Create(surface_id_, gfx::Size(5, 5));
+    factory_.Create(surface_id_);
   }
 
   virtual ~SurfaceFactoryTest() {
@@ -361,7 +361,7 @@
 // Tests doing a DestroyAll before shutting down the factory;
 TEST_F(SurfaceFactoryTest, DestroyAll) {
   SurfaceId id(7);
-  factory_.Create(id, gfx::Size(1, 1));
+  factory_.Create(id);
 
   scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
   TransferableResource resource;
@@ -378,7 +378,7 @@
 
 TEST_F(SurfaceFactoryTest, DestroySequence) {
   SurfaceId id2(5);
-  factory_.Create(id2, gfx::Size(5, 5));
+  factory_.Create(id2);
 
   // Check that waiting before the sequence is satisfied works.
   manager_.GetSurfaceForId(id2)
@@ -395,7 +395,7 @@
   DCHECK(!manager_.GetSurfaceForId(id2));
 
   // Check that waiting after the sequence is satisfied works.
-  factory_.Create(id2, gfx::Size(5, 5));
+  factory_.Create(id2);
   DCHECK(manager_.GetSurfaceForId(id2));
   manager_.GetSurfaceForId(id2)
       ->AddDestructionDependency(SurfaceSequence(0, 6));
diff --git a/cc/surfaces/surface_unittest.cc b/cc/surfaces/surface_unittest.cc
index b8990c5..7f2de36 100644
--- a/cc/surfaces/surface_unittest.cc
+++ b/cc/surfaces/surface_unittest.cc
@@ -17,7 +17,7 @@
 
   SurfaceId surface_id(6);
   {
-    factory.Create(surface_id, gfx::Size(5, 5));
+    factory.Create(surface_id);
     EXPECT_TRUE(!!manager.GetSurfaceForId(surface_id));
     factory.Destroy(surface_id);
   }
diff --git a/cc/surfaces/surfaces_pixeltest.cc b/cc/surfaces/surfaces_pixeltest.cc
index c70028b..bf9d483 100644
--- a/cc/surfaces/surfaces_pixeltest.cc
+++ b/cc/surfaces/surfaces_pixeltest.cc
@@ -85,7 +85,7 @@
   root_frame->delegated_frame_data = delegated_frame_data.Pass();
 
   SurfaceId root_surface_id = allocator_.GenerateId();
-  factory_.Create(root_surface_id, device_viewport_size_);
+  factory_.Create(root_surface_id);
   factory_.SubmitFrame(root_surface_id, root_frame.Pass(), base::Closure());
 
   SurfaceAggregator aggregator(&manager_, resource_provider_.get());
@@ -107,8 +107,8 @@
   gfx::Size child_size(200, 100);
   SurfaceId child_surface_id = allocator_.GenerateId();
   SurfaceId root_surface_id = allocator_.GenerateId();
-  factory_.Create(child_surface_id, child_size);
-  factory_.Create(root_surface_id, device_viewport_size_);
+  factory_.Create(child_surface_id);
+  factory_.Create(root_surface_id);
   {
     gfx::Rect rect(device_viewport_size_);
     RenderPassId id(1, 1);
@@ -199,9 +199,9 @@
   SurfaceId left_child_id = allocator_.GenerateId();
   SurfaceId right_child_id = allocator_.GenerateId();
   SurfaceId root_surface_id = allocator_.GenerateId();
-  factory_.Create(left_child_id, child_size);
-  factory_.Create(right_child_id, child_size);
-  factory_.Create(root_surface_id, device_viewport_size_);
+  factory_.Create(left_child_id);
+  factory_.Create(right_child_id);
+  factory_.Create(root_surface_id);
 
   {
     gfx::Rect rect(device_viewport_size_);
diff --git a/cc/test/begin_frame_args_test.cc b/cc/test/begin_frame_args_test.cc
index f70d0c5..7b29748 100644
--- a/cc/test/begin_frame_args_test.cc
+++ b/cc/test/begin_frame_args_test.cc
@@ -10,57 +10,67 @@
 
 namespace cc {
 
-BeginFrameArgs CreateBeginFrameArgsForTesting() {
-  return CreateBeginFrameArgsForTesting(gfx::FrameTime::Now());
-}
-
-BeginFrameArgs CreateBeginFrameArgsForTesting(base::TimeTicks frame_time) {
-  return BeginFrameArgs::Create(
-      frame_time, frame_time + (BeginFrameArgs::DefaultInterval() / 2),
-      BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
-}
-
-BeginFrameArgs CreateBeginFrameArgsForTesting(int64 frame_time,
-                                              int64 deadline,
-                                              int64 interval) {
-  return BeginFrameArgs::Create(base::TimeTicks::FromInternalValue(frame_time),
-                                base::TimeTicks::FromInternalValue(deadline),
-                                base::TimeDelta::FromInternalValue(interval),
-                                BeginFrameArgs::NORMAL);
+BeginFrameArgs CreateBeginFrameArgsForTesting(
+    BeginFrameArgs::CreationLocation location) {
+  return CreateBeginFrameArgsForTesting(location, gfx::FrameTime::Now());
 }
 
 BeginFrameArgs CreateBeginFrameArgsForTesting(
+    BeginFrameArgs::CreationLocation location,
+    base::TimeTicks frame_time) {
+  return BeginFrameArgs::Create(
+      location, frame_time,
+      frame_time + (BeginFrameArgs::DefaultInterval() / 2),
+      BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
+}
+
+BeginFrameArgs CreateBeginFrameArgsForTesting(
+    BeginFrameArgs::CreationLocation location,
+    int64 frame_time,
+    int64 deadline,
+    int64 interval) {
+  return BeginFrameArgs::Create(
+      location, base::TimeTicks::FromInternalValue(frame_time),
+      base::TimeTicks::FromInternalValue(deadline),
+      base::TimeDelta::FromInternalValue(interval), BeginFrameArgs::NORMAL);
+}
+
+BeginFrameArgs CreateBeginFrameArgsForTesting(
+    BeginFrameArgs::CreationLocation location,
     int64 frame_time,
     int64 deadline,
     int64 interval,
     BeginFrameArgs::BeginFrameArgsType type) {
-  return BeginFrameArgs::Create(base::TimeTicks::FromInternalValue(frame_time),
-                                base::TimeTicks::FromInternalValue(deadline),
-                                base::TimeDelta::FromInternalValue(interval),
-                                type);
+  return BeginFrameArgs::Create(
+      location, base::TimeTicks::FromInternalValue(frame_time),
+      base::TimeTicks::FromInternalValue(deadline),
+      base::TimeDelta::FromInternalValue(interval), type);
 }
 
-BeginFrameArgs CreateExpiredBeginFrameArgsForTesting() {
+BeginFrameArgs CreateExpiredBeginFrameArgsForTesting(
+    BeginFrameArgs::CreationLocation location) {
   base::TimeTicks now = gfx::FrameTime::Now();
-  return BeginFrameArgs::Create(now, now - BeginFrameArgs::DefaultInterval(),
-                                BeginFrameArgs::DefaultInterval(),
-                                BeginFrameArgs::NORMAL);
+  return BeginFrameArgs::Create(
+      location, now, now - BeginFrameArgs::DefaultInterval(),
+      BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
 }
 
 BeginFrameArgs CreateBeginFrameArgsForTesting(
+    BeginFrameArgs::CreationLocation location,
     scoped_refptr<TestNowSource> now_src) {
   base::TimeTicks now = now_src->Now();
   return BeginFrameArgs::Create(
-      now, now + (BeginFrameArgs::DefaultInterval() / 2),
+      location, now, now + (BeginFrameArgs::DefaultInterval() / 2),
       BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
 }
 
 BeginFrameArgs CreateExpiredBeginFrameArgsForTesting(
+    BeginFrameArgs::CreationLocation location,
     scoped_refptr<TestNowSource> now_src) {
   base::TimeTicks now = now_src->Now();
-  return BeginFrameArgs::Create(now, now - BeginFrameArgs::DefaultInterval(),
-                                BeginFrameArgs::DefaultInterval(),
-                                BeginFrameArgs::NORMAL);
+  return BeginFrameArgs::Create(
+      location, now, now - BeginFrameArgs::DefaultInterval(),
+      BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
 }
 
 bool operator==(const BeginFrameArgs& lhs, const BeginFrameArgs& rhs) {
diff --git a/cc/test/begin_frame_args_test.h b/cc/test/begin_frame_args_test.h
index ca4aa45..73aaf02 100644
--- a/cc/test/begin_frame_args_test.h
+++ b/cc/test/begin_frame_args_test.h
@@ -15,23 +15,32 @@
 namespace cc {
 
 // Functions for quickly creating BeginFrameArgs
-BeginFrameArgs CreateBeginFrameArgsForTesting();
-BeginFrameArgs CreateBeginFrameArgsForTesting(base::TimeTicks frame_time);
-BeginFrameArgs CreateBeginFrameArgsForTesting(int64 frame_time,
-                                              int64 deadline,
-                                              int64 interval);
 BeginFrameArgs CreateBeginFrameArgsForTesting(
+    BeginFrameArgs::CreationLocation location);
+BeginFrameArgs CreateBeginFrameArgsForTesting(
+    BeginFrameArgs::CreationLocation location,
+    base::TimeTicks frame_time);
+BeginFrameArgs CreateBeginFrameArgsForTesting(
+    BeginFrameArgs::CreationLocation location,
+    int64 frame_time,
+    int64 deadline,
+    int64 interval);
+BeginFrameArgs CreateBeginFrameArgsForTesting(
+    BeginFrameArgs::CreationLocation location,
     int64 frame_time,
     int64 deadline,
     int64 interval,
     BeginFrameArgs::BeginFrameArgsType type);
-BeginFrameArgs CreateExpiredBeginFrameArgsForTesting();
+BeginFrameArgs CreateExpiredBeginFrameArgsForTesting(
+    BeginFrameArgs::CreationLocation location);
 
 // Creates a BeginFrameArgs using the fake Now value stored on the
 // OrderSimpleTaskRunner.
 BeginFrameArgs CreateBeginFrameArgsForTesting(
+    BeginFrameArgs::CreationLocation location,
     scoped_refptr<TestNowSource> now_src);
 BeginFrameArgs CreateExpiredBeginFrameArgsForTesting(
+    BeginFrameArgs::CreationLocation location,
     scoped_refptr<TestNowSource> now_src);
 
 // gtest helpers -- these *must* be in the same namespace as the types they
diff --git a/cc/test/fake_content_layer_client.cc b/cc/test/fake_content_layer_client.cc
index 5463aed..46d1baa 100644
--- a/cc/test/fake_content_layer_client.cc
+++ b/cc/test/fake_content_layer_client.cc
@@ -4,7 +4,10 @@
 
 #include "cc/test/fake_content_layer_client.h"
 
+#include "cc/resources/clip_display_item.h"
+#include "cc/resources/drawing_display_item.h"
 #include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
 #include "ui/gfx/skia_util.h"
 
 namespace cc {
@@ -52,6 +55,58 @@
   }
 }
 
+scoped_refptr<DisplayItemList>
+FakeContentLayerClient::PaintContentsToDisplayList(
+    const gfx::Rect& clip,
+    GraphicsContextStatus gc_status) {
+  SkPictureRecorder recorder;
+  skia::RefPtr<SkCanvas> canvas;
+  skia::RefPtr<SkPicture> picture;
+  scoped_refptr<DisplayItemList> list = DisplayItemList::Create();
+  list->AppendItem(ClipDisplayItem::Create(clip, std::vector<SkRRect>()));
+
+  for (RectPaintVector::const_iterator it = draw_rects_.begin();
+       it != draw_rects_.end(); ++it) {
+    const gfx::RectF& draw_rect = it->first;
+    const SkPaint& paint = it->second;
+    canvas = skia::SharePtr(
+        recorder.beginRecording(draw_rect.width(), draw_rect.height()));
+    canvas->drawRectCoords(0.f, 0.f, draw_rect.width(), draw_rect.height(),
+                           paint);
+    picture = skia::AdoptRef(recorder.endRecording());
+    list->AppendItem(DrawingDisplayItem::Create(
+        picture, gfx::PointF(draw_rect.x(), draw_rect.y())));
+  }
+
+  for (BitmapVector::const_iterator it = draw_bitmaps_.begin();
+       it != draw_bitmaps_.end(); ++it) {
+    canvas = skia::SharePtr(
+        recorder.beginRecording(it->bitmap.width(), it->bitmap.height()));
+    canvas->drawBitmap(it->bitmap, 0.f, 0.f, &it->paint);
+    picture = skia::AdoptRef(recorder.endRecording());
+    list->AppendItem(DrawingDisplayItem::Create(
+        picture, gfx::PointF(it->point.x(), it->point.y())));
+  }
+
+  if (fill_with_nonsolid_color_) {
+    gfx::RectF draw_rect = clip;
+    bool red = true;
+    while (!draw_rect.IsEmpty()) {
+      SkPaint paint;
+      paint.setColor(red ? SK_ColorRED : SK_ColorBLUE);
+      canvas =
+          skia::SharePtr(recorder.beginRecording(clip.width(), clip.height()));
+      canvas->drawRect(gfx::RectFToSkRect(draw_rect), paint);
+      picture = skia::AdoptRef(recorder.endRecording());
+      list->AppendItem(DrawingDisplayItem::Create(picture, gfx::PointF()));
+      draw_rect.Inset(1, 1);
+    }
+  }
+
+  list->AppendItem(EndClipDisplayItem::Create());
+  return list;
+}
+
 bool FakeContentLayerClient::FillsBoundsCompletely() const { return false; }
 
 }  // namespace cc
diff --git a/cc/test/fake_content_layer_client.h b/cc/test/fake_content_layer_client.h
index 141bc97..1060d08 100644
--- a/cc/test/fake_content_layer_client.h
+++ b/cc/test/fake_content_layer_client.h
@@ -31,6 +31,9 @@
       SkCanvas* canvas,
       const gfx::Rect& rect,
       ContentLayerClient::GraphicsContextStatus gc_status) override;
+  scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+      const gfx::Rect& clip,
+      GraphicsContextStatus gc_status) override;
   bool FillsBoundsCompletely() const override;
 
   void set_fill_with_nonsolid_color(bool nonsolid) {
diff --git a/cc/test/fake_layer_tree_host_impl.cc b/cc/test/fake_layer_tree_host_impl.cc
index ea19e14..305b856 100644
--- a/cc/test/fake_layer_tree_host_impl.cc
+++ b/cc/test/fake_layer_tree_host_impl.cc
@@ -24,7 +24,8 @@
 
   // Avoid using Now() as the frame time in unit tests.
   base::TimeTicks time_ticks = base::TimeTicks::FromInternalValue(1);
-  SetCurrentBeginFrameArgs(CreateBeginFrameArgsForTesting(time_ticks));
+  SetCurrentBeginFrameArgs(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 }
 
 FakeLayerTreeHostImpl::FakeLayerTreeHostImpl(const LayerTreeSettings& settings,
@@ -42,7 +43,8 @@
 
   // Avoid using Now() as the frame time in unit tests.
   base::TimeTicks time_ticks = base::TimeTicks::FromInternalValue(1);
-  SetCurrentBeginFrameArgs(CreateBeginFrameArgsForTesting(time_ticks));
+  SetCurrentBeginFrameArgs(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 }
 
 FakeLayerTreeHostImpl::~FakeLayerTreeHostImpl() {}
diff --git a/cc/test/layer_tree_pixel_resource_test.cc b/cc/test/layer_tree_pixel_resource_test.cc
index 9bd75ac..1839643 100644
--- a/cc/test/layer_tree_pixel_resource_test.cc
+++ b/cc/test/layer_tree_pixel_resource_test.cc
@@ -159,7 +159,7 @@
     case ZERO_COPY_RASTER_WORKER_POOL:
       EXPECT_TRUE(context_provider);
       EXPECT_EQ(PIXEL_TEST_GL, test_type_);
-      EXPECT_TRUE(host_impl->CanUseZeroCopyRasterizer());
+      EXPECT_TRUE(host_impl->GetRendererCapabilities().using_image);
       *resource_pool =
           ResourcePool::Create(resource_provider,
                                draw_texture_target_,
@@ -173,7 +173,7 @@
     case ONE_COPY_RASTER_WORKER_POOL:
       EXPECT_TRUE(context_provider);
       EXPECT_EQ(PIXEL_TEST_GL, test_type_);
-      EXPECT_TRUE(host_impl->CanUseOneCopyRasterizer());
+      EXPECT_TRUE(host_impl->GetRendererCapabilities().using_image);
       // We need to create a staging resource pool when using copy rasterizer.
       *staging_resource_pool =
           ResourcePool::Create(resource_provider,
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 80e9f11..9f08677 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -91,7 +91,7 @@
 
   void TestOnBeginFrame() {
     DCHECK(CalledOnValidThread());
-    CallOnBeginFrame(CreateBeginFrameArgsForTesting());
+    CallOnBeginFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   }
 
  private:
@@ -153,6 +153,11 @@
     test_hooks_->ScheduledActionBeginOutputSurfaceCreation();
   }
 
+  void ScheduledActionManageTiles() override {
+    ThreadProxy::ScheduledActionManageTiles();
+    test_hooks_->ScheduledActionManageTiles();
+  }
+
   ThreadProxyForTest(
       TestHooks* test_hooks,
       LayerTreeHost* host,
@@ -780,6 +785,11 @@
   RunTest(true, false, true);
 }
 
+void LayerTreeTest::RunTestWithMainThreadLowLatency() {
+  settings_.main_thread_should_always_be_low_latency = true;
+  RunTest(false, false, false);
+}
+
 void LayerTreeTest::RequestNewOutputSurface(bool fallback) {
   layer_tree_host_->SetOutputSurface(CreateOutputSurface(fallback));
 }
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index 2914cfc..ba2ef69 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -98,6 +98,7 @@
   virtual void ScheduledActionAnimate() {}
   virtual void ScheduledActionCommit() {}
   virtual void ScheduledActionBeginOutputSurfaceCreation() {}
+  virtual void ScheduledActionManageTiles() {}
 
   // Implementation of AnimationDelegate:
   void NotifyAnimationStarted(base::TimeTicks monotonic_time,
@@ -175,6 +176,7 @@
                        bool delegating_renderer,
                        bool impl_side_painting);
   virtual void RunTestWithImplSidePainting();
+  virtual void RunTestWithMainThreadLowLatency();
 
   bool HasImplThread() { return proxy() ? proxy()->HasImplThread() : false; }
   base::SingleThreadTaskRunner* ImplThreadTaskRunner() {
@@ -235,7 +237,18 @@
 
 }  // namespace cc
 
+#define SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_MAIN_THREAD_LOW_LATENCY_TEST_F( \
+    TEST_FIXTURE_NAME)                                                       \
+  TEST_F(                                                                    \
+      TEST_FIXTURE_NAME,                                                     \
+      RunSingleThread_DirectRenderer_MainThreadPaint_MainThreadLowLatency) { \
+    RunTestWithMainThreadLowLatency();                                       \
+  }                                                                          \
+  class SingleThreadDirectNoImplLowLatencyNeedsSemicolon##TEST_FIXTURE_NAME {}
+
 #define SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME)        \
+  SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_MAIN_THREAD_LOW_LATENCY_TEST_F(        \
+      TEST_FIXTURE_NAME);                                                     \
   TEST_F(TEST_FIXTURE_NAME, RunSingleThread_DirectRenderer_MainThreadPaint) { \
     RunTest(false, false, false);                                             \
   }                                                                           \
diff --git a/cc/test/skia_common.cc b/cc/test/skia_common.cc
index 1ccb2d1..ef61e21 100644
--- a/cc/test/skia_common.cc
+++ b/cc/test/skia_common.cc
@@ -4,6 +4,7 @@
 
 #include "cc/test/skia_common.h"
 
+#include "cc/resources/display_item_list.h"
 #include "cc/resources/picture.h"
 #include "skia/ext/refptr.h"
 #include "third_party/skia/include/core/SkCanvas.h"
@@ -26,6 +27,18 @@
   picture->Raster(&canvas, NULL, negated_content_region, 1.0f);
 }
 
+void DrawDisplayList(unsigned char* buffer,
+                     const gfx::Rect& layer_rect,
+                     scoped_refptr<DisplayItemList> list) {
+  SkImageInfo info =
+      SkImageInfo::MakeN32Premul(layer_rect.width(), layer_rect.height());
+  SkBitmap bitmap;
+  bitmap.installPixels(info, buffer, info.minRowBytes());
+  SkCanvas canvas(bitmap);
+  canvas.clipRect(gfx::RectToSkRect(layer_rect));
+  list->Raster(&canvas, NULL, 1.0f);
+}
+
 void CreateBitmap(const gfx::Size& size, const char* uri, SkBitmap* bitmap) {
   SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height());
 
diff --git a/cc/test/skia_common.h b/cc/test/skia_common.h
index 3bafa0b..51ebcc5 100644
--- a/cc/test/skia_common.h
+++ b/cc/test/skia_common.h
@@ -18,11 +18,16 @@
 
 namespace cc {
 class Picture;
+class DisplayItemList;
 
 void DrawPicture(unsigned char* buffer,
                  const gfx::Rect& layer_rect,
                  scoped_refptr<Picture> picture);
 
+void DrawDisplayList(unsigned char* buffer,
+                     const gfx::Rect& layer_rect,
+                     scoped_refptr<DisplayItemList> list);
+
 void CreateBitmap(const gfx::Size& size, const char* uri, SkBitmap* bitmap);
 
 }  // namespace cc
diff --git a/cc/test/solid_color_content_layer_client.cc b/cc/test/solid_color_content_layer_client.cc
index 237dbb6..701f004 100644
--- a/cc/test/solid_color_content_layer_client.cc
+++ b/cc/test/solid_color_content_layer_client.cc
@@ -25,6 +25,14 @@
       paint);
 }
 
+scoped_refptr<DisplayItemList>
+SolidColorContentLayerClient::PaintContentsToDisplayList(
+    const gfx::Rect& clip,
+    GraphicsContextStatus gc_status) {
+  NOTIMPLEMENTED();
+  return DisplayItemList::Create();
+}
+
 bool SolidColorContentLayerClient::FillsBoundsCompletely() const {
   return false;
 }
diff --git a/cc/test/solid_color_content_layer_client.h b/cc/test/solid_color_content_layer_client.h
index 7a962cf..93fca84 100644
--- a/cc/test/solid_color_content_layer_client.h
+++ b/cc/test/solid_color_content_layer_client.h
@@ -20,6 +20,9 @@
       SkCanvas* canvas,
       const gfx::Rect& rect,
       ContentLayerClient::GraphicsContextStatus gc_status) override;
+  scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+      const gfx::Rect& clip,
+      GraphicsContextStatus gc_status) override;
   bool FillsBoundsCompletely() const override;
 
  private:
diff --git a/cc/test/test_shared_bitmap_manager.cc b/cc/test/test_shared_bitmap_manager.cc
index d7716dd..933dcd2 100644
--- a/cc/test/test_shared_bitmap_manager.cc
+++ b/cc/test/test_shared_bitmap_manager.cc
@@ -4,15 +4,41 @@
 
 #include "cc/test/test_shared_bitmap_manager.h"
 
-#include "base/bind.h"
+#include "base/memory/shared_memory.h"
 
 namespace cc {
 
-void FreeSharedBitmap(SharedBitmap* shared_bitmap) {
-  delete shared_bitmap->memory();
-}
+namespace {
+class OwnedSharedBitmap : public SharedBitmap {
+ public:
+  OwnedSharedBitmap(scoped_ptr<base::SharedMemory> shared_memory,
+                    const SharedBitmapId& id)
+      : SharedBitmap(static_cast<uint8*>(shared_memory->memory()), id),
+        shared_memory_(shared_memory.Pass()) {}
 
-void IgnoreSharedBitmap(SharedBitmap* shared_bitmap) {}
+  ~OwnedSharedBitmap() override {}
+
+  base::SharedMemory* memory() override { return shared_memory_.get(); }
+
+ private:
+  scoped_ptr<base::SharedMemory> shared_memory_;
+};
+
+class UnownedSharedBitmap : public SharedBitmap {
+ public:
+  UnownedSharedBitmap(base::SharedMemory* shared_memory,
+                      const SharedBitmapId& id)
+      : SharedBitmap(static_cast<uint8*>(shared_memory->memory()), id),
+        shared_memory_(shared_memory) {}
+
+  ~UnownedSharedBitmap() override {}
+
+  base::SharedMemory* memory() override { return shared_memory_; }
+
+ private:
+  base::SharedMemory* shared_memory_;
+};
+}  // namespace
 
 TestSharedBitmapManager::TestSharedBitmapManager() {}
 
@@ -25,8 +51,7 @@
   memory->CreateAndMapAnonymous(size.GetArea() * 4);
   SharedBitmapId id = SharedBitmap::GenerateId();
   bitmap_map_[id] = memory.get();
-  return make_scoped_ptr(
-      new SharedBitmap(memory.release(), id, base::Bind(&FreeSharedBitmap)));
+  return make_scoped_ptr(new OwnedSharedBitmap(memory.Pass(), id));
 }
 
 scoped_ptr<SharedBitmap> TestSharedBitmapManager::GetSharedBitmapFromId(
@@ -35,8 +60,7 @@
   base::AutoLock lock(lock_);
   if (bitmap_map_.find(id) == bitmap_map_.end())
     return nullptr;
-  return make_scoped_ptr(
-      new SharedBitmap(bitmap_map_[id], id, base::Bind(&IgnoreSharedBitmap)));
+  return make_scoped_ptr(new UnownedSharedBitmap(bitmap_map_[id], id));
 }
 
 scoped_ptr<SharedBitmap> TestSharedBitmapManager::GetBitmapForSharedMemory(
@@ -44,8 +68,7 @@
   base::AutoLock lock(lock_);
   SharedBitmapId id = SharedBitmap::GenerateId();
   bitmap_map_[id] = memory;
-  return make_scoped_ptr(
-      new SharedBitmap(memory, id, base::Bind(&IgnoreSharedBitmap)));
+  return make_scoped_ptr(new UnownedSharedBitmap(memory, id));
 }
 
 }  // namespace cc
diff --git a/cc/test/test_web_graphics_context_3d.h b/cc/test/test_web_graphics_context_3d.h
index ff2c704..56c17c0 100644
--- a/cc/test/test_web_graphics_context_3d.h
+++ b/cc/test/test_web_graphics_context_3d.h
@@ -330,6 +330,9 @@
   void set_support_image(bool support) {
     test_capabilities_.gpu.image = support;
   }
+  void set_support_texture_rectangle(bool support) {
+    test_capabilities_.gpu.texture_rectangle = support;
+  }
 
   // When this context is lost, all contexts in its share group are also lost.
   void add_share_group_context(TestWebGraphicsContext3D* context3d) {
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 6863850..6d75687 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -392,7 +392,7 @@
   gfx::Rect visible_rect_in_target_surface_space =
       layer->drawable_content_rect();
 
-  if (!layer->render_target()->render_surface()->clip_rect().IsEmpty()) {
+  if (layer->render_target()->render_surface()->is_clipped()) {
     // The |layer| L has a target T which owns a surface Ts. The surface Ts
     // has a target TsT.
     //
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index 7a282c1..8c02bd3 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -59,6 +59,12 @@
       SkCanvas* canvas,
       const gfx::Rect& clip,
       ContentLayerClient::GraphicsContextStatus gc_status) override {}
+  scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+      const gfx::Rect& clip,
+      GraphicsContextStatus gc_status) override {
+    NOTIMPLEMENTED();
+    return DisplayItemList::Create();
+  }
   bool FillsBoundsCompletely() const override { return false; }
 };
 
@@ -2820,6 +2826,56 @@
 }
 
 TEST_F(LayerTreeHostCommonTest,
+       VisibleContentRectsForClippedSurfaceWithEmptyClip) {
+  scoped_refptr<Layer> root = Layer::Create();
+  scoped_refptr<LayerWithForcedDrawsContent> child1 =
+      make_scoped_refptr(new LayerWithForcedDrawsContent());
+  scoped_refptr<LayerWithForcedDrawsContent> child2 =
+      make_scoped_refptr(new LayerWithForcedDrawsContent());
+  scoped_refptr<LayerWithForcedDrawsContent> child3 =
+      make_scoped_refptr(new LayerWithForcedDrawsContent());
+  root->AddChild(child1);
+  root->AddChild(child2);
+  root->AddChild(child3);
+
+  scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+  host->SetRootLayer(root);
+
+  gfx::Transform identity_matrix;
+  SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(),
+                               gfx::PointF(), gfx::Size(100, 100), true, false);
+  SetLayerPropertiesForTesting(child1.get(), identity_matrix, gfx::Point3F(),
+                               gfx::PointF(5.f, 5.f), gfx::Size(50, 50), true,
+                               false);
+  SetLayerPropertiesForTesting(child2.get(), identity_matrix, gfx::Point3F(),
+                               gfx::PointF(75.f, 75.f), gfx::Size(50, 50), true,
+                               false);
+  SetLayerPropertiesForTesting(child3.get(), identity_matrix, gfx::Point3F(),
+                               gfx::PointF(125.f, 125.f), gfx::Size(50, 50),
+                               true, false);
+
+  RenderSurfaceLayerList render_surface_layer_list;
+  // Now set the root render surface an empty clip.
+  LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
+      root.get(), gfx::Size(), &render_surface_layer_list);
+
+  LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+  ASSERT_TRUE(root->render_surface());
+  EXPECT_FALSE(root->is_clipped());
+
+  gfx::Rect empty;
+  EXPECT_EQ(empty, root->render_surface()->clip_rect());
+  EXPECT_TRUE(root->render_surface()->is_clipped());
+
+  // Visible content rect calculation will check if the target surface is
+  // clipped or not. An empty clip rect does not indicate the render surface
+  // is unclipped.
+  EXPECT_EQ(empty, child1->visible_content_rect());
+  EXPECT_EQ(empty, child2->visible_content_rect());
+  EXPECT_EQ(empty, child3->visible_content_rect());
+}
+
+TEST_F(LayerTreeHostCommonTest,
        DrawableAndVisibleContentRectsForLayersWithUninvertibleTransform) {
   scoped_refptr<Layer> root = Layer::Create();
   scoped_refptr<LayerWithForcedDrawsContent> child =
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index e49dcfe..10b0685 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -151,22 +151,6 @@
                   max_transfer_buffer_usage_bytes);
 }
 
-unsigned GetMapImageTextureTarget(
-    const ContextProvider::Capabilities& context_capabilities) {
-// TODO(reveman): This should be a setting passed to the compositor instead
-// of hard-coded here. The target that need to be used depends on our choice
-// of GpuMemoryBuffer type. Note: SURFACE_TEXTURE needs EXTERNAL_OES,
-// IO_SURFACE needs RECTANGLE_ARB. crbug.com/431059
-#if defined(OS_ANDROID)
-  if (context_capabilities.gpu.egl_image_external)
-    return GL_TEXTURE_EXTERNAL_OES;
-#endif
-  if (context_capabilities.gpu.texture_rectangle)
-    return GL_TEXTURE_RECTANGLE_ARB;
-
-  return GL_TEXTURE_2D;
-}
-
 size_t GetMaxStagingResourceCount() {
   // Upper bound for number of staging resource to allow.
   return 32;
@@ -2005,9 +1989,6 @@
   DCHECK(task_runner);
 
   ContextProvider* context_provider = output_surface_->context_provider();
-  bool should_use_zero_copy_rasterizer =
-      settings_.use_zero_copy || IsSynchronousSingleThreaded();
-
   if (!context_provider) {
     *resource_pool =
         ResourcePool::Create(resource_provider_.get(),
@@ -2018,7 +1999,10 @@
         BitmapRasterWorkerPool::Create(task_runner,
                                        RasterWorkerPool::GetTaskGraphRunner(),
                                        resource_provider_.get());
-  } else if (use_gpu_rasterization_) {
+    return;
+  }
+
+  if (use_gpu_rasterization_) {
     *resource_pool =
         ResourcePool::Create(resource_provider_.get(),
                              GL_TEXTURE_2D,
@@ -2029,53 +2013,65 @@
                                     context_provider,
                                     resource_provider_.get(),
                                     settings_.use_distance_field_text);
-  } else if (should_use_zero_copy_rasterizer && CanUseZeroCopyRasterizer()) {
-    *resource_pool = ResourcePool::Create(
-        resource_provider_.get(),
-        GetMapImageTextureTarget(context_provider->ContextCapabilities()),
-        resource_provider_->best_texture_format());
+    return;
+  }
 
-    TaskGraphRunner* task_graph_runner;
-    if (IsSynchronousSingleThreaded()) {
-      DCHECK(!single_thread_synchronous_task_graph_runner_);
-      single_thread_synchronous_task_graph_runner_.reset(new TaskGraphRunner);
-      task_graph_runner = single_thread_synchronous_task_graph_runner_.get();
-    } else {
-      task_graph_runner = RasterWorkerPool::GetTaskGraphRunner();
+  if (GetRendererCapabilities().using_image) {
+    unsigned image_target = GL_TEXTURE_2D;
+#if defined(OS_MACOSX)
+    // GL_TEXTURE_RECTANGLE_ARB target is required by IOSurface backed images.
+    DCHECK(context_provider->ContextCapabilities().gpu.texture_rectangle);
+    image_target = GL_TEXTURE_RECTANGLE_ARB;
+#endif
+    if (settings_.use_image_external) {
+      DCHECK(context_provider->ContextCapabilities().gpu.egl_image_external);
+      image_target = GL_TEXTURE_EXTERNAL_OES;
     }
 
-    *raster_worker_pool = ZeroCopyRasterWorkerPool::Create(
-        task_runner, task_graph_runner, resource_provider_.get());
-  } else if (settings_.use_one_copy && CanUseOneCopyRasterizer()) {
-    // We need to create a staging resource pool when using copy rasterizer.
-    *staging_resource_pool = ResourcePool::Create(
-        resource_provider_.get(),
-        GetMapImageTextureTarget(context_provider->ContextCapabilities()),
-        resource_provider_->best_texture_format());
-    *resource_pool =
-        ResourcePool::Create(resource_provider_.get(),
-                             GL_TEXTURE_2D,
-                             resource_provider_->best_texture_format());
+    if (settings_.use_zero_copy || IsSynchronousSingleThreaded()) {
+      *resource_pool =
+          ResourcePool::Create(resource_provider_.get(), image_target,
+                               resource_provider_->best_texture_format());
 
-    *raster_worker_pool =
-        OneCopyRasterWorkerPool::Create(task_runner,
-                                        RasterWorkerPool::GetTaskGraphRunner(),
-                                        context_provider,
-                                        resource_provider_.get(),
-                                        staging_resource_pool_.get());
-  } else {
-    *resource_pool = ResourcePool::Create(
-        resource_provider_.get(),
-        GL_TEXTURE_2D,
-        resource_provider_->memory_efficient_texture_format());
+      TaskGraphRunner* task_graph_runner;
+      if (IsSynchronousSingleThreaded()) {
+        DCHECK(!single_thread_synchronous_task_graph_runner_);
+        single_thread_synchronous_task_graph_runner_.reset(new TaskGraphRunner);
+        task_graph_runner = single_thread_synchronous_task_graph_runner_.get();
+      } else {
+        task_graph_runner = RasterWorkerPool::GetTaskGraphRunner();
+      }
 
-    *raster_worker_pool = PixelBufferRasterWorkerPool::Create(
-        task_runner, RasterWorkerPool::GetTaskGraphRunner(), context_provider,
-        resource_provider_.get(),
-        GetMaxTransferBufferUsageBytes(
-            context_provider->ContextCapabilities(),
-            settings_.renderer_settings.refresh_rate));
+      *raster_worker_pool = ZeroCopyRasterWorkerPool::Create(
+          task_runner, task_graph_runner, resource_provider_.get());
+      return;
+    }
+
+    if (settings_.use_one_copy) {
+      // We need to create a staging resource pool when using copy rasterizer.
+      *staging_resource_pool =
+          ResourcePool::Create(resource_provider_.get(), image_target,
+                               resource_provider_->best_texture_format());
+      *resource_pool =
+          ResourcePool::Create(resource_provider_.get(), GL_TEXTURE_2D,
+                               resource_provider_->best_texture_format());
+
+      *raster_worker_pool = OneCopyRasterWorkerPool::Create(
+          task_runner, RasterWorkerPool::GetTaskGraphRunner(), context_provider,
+          resource_provider_.get(), staging_resource_pool_.get());
+      return;
+    }
   }
+
+  *resource_pool = ResourcePool::Create(
+      resource_provider_.get(), GL_TEXTURE_2D,
+      resource_provider_->memory_efficient_texture_format());
+
+  *raster_worker_pool = PixelBufferRasterWorkerPool::Create(
+      task_runner, RasterWorkerPool::GetTaskGraphRunner(), context_provider,
+      resource_provider_.get(),
+      GetMaxTransferBufferUsageBytes(context_provider->ContextCapabilities(),
+                                     settings_.renderer_settings.refresh_rate));
 }
 
 void LayerTreeHostImpl::DestroyTileManager() {
@@ -2096,14 +2092,6 @@
   return !proxy_->HasImplThread() && !settings_.single_thread_proxy_scheduler;
 }
 
-bool LayerTreeHostImpl::CanUseZeroCopyRasterizer() const {
-  return GetRendererCapabilities().using_image;
-}
-
-bool LayerTreeHostImpl::CanUseOneCopyRasterizer() const {
-  return GetRendererCapabilities().using_image;
-}
-
 void LayerTreeHostImpl::EnforceZeroBudget(bool zero_budget) {
   SetManagedMemoryPolicy(cached_managed_memory_policy_, zero_budget);
 }
@@ -2563,10 +2551,14 @@
   return actual_viewport_end_point - viewport_point;
 }
 
-static gfx::Vector2dF ScrollLayerWithLocalDelta(LayerImpl* layer_impl,
-    const gfx::Vector2dF& local_delta) {
+static gfx::Vector2dF ScrollLayerWithLocalDelta(
+    LayerImpl* layer_impl,
+    const gfx::Vector2dF& local_delta,
+    float page_scale_factor) {
   gfx::Vector2dF previous_delta(layer_impl->ScrollDelta());
-  layer_impl->ScrollBy(local_delta);
+  gfx::Vector2dF delta = local_delta;
+  delta.Scale(1.f / page_scale_factor);
+  layer_impl->ScrollBy(delta);
   return layer_impl->ScrollDelta() - previous_delta;
 }
 
@@ -2644,7 +2636,8 @@
     // Gesture events need to be transformed from viewport coordinates to local
     // layer coordinates so that the scrolling contents exactly follow the
     // user's finger. In contrast, wheel events represent a fixed amount of
-    // scrolling so we can just apply them directly.
+    // scrolling so we can just apply them directly, but the page scale factor
+    // is applied to the scroll delta.
     if (!wheel_scrolling_) {
       float scale_from_viewport_to_screen_space = device_scale_factor_;
       applied_delta =
@@ -2652,7 +2645,8 @@
                                             scale_from_viewport_to_screen_space,
                                             viewport_point, pending_delta);
     } else {
-      applied_delta = ScrollLayerWithLocalDelta(layer_impl, pending_delta);
+      applied_delta = ScrollLayerWithLocalDelta(
+          layer_impl, pending_delta, active_tree_->total_page_scale_factor());
     }
 
     const float kEpsilon = 0.1f;
@@ -2774,7 +2768,8 @@
 
     gfx::Vector2dF delta = gfx::Vector2dF(0.f, page);
 
-    gfx::Vector2dF applied_delta = ScrollLayerWithLocalDelta(layer_impl, delta);
+    gfx::Vector2dF applied_delta =
+        ScrollLayerWithLocalDelta(layer_impl, delta, 1.f);
 
     if (!applied_delta.IsZero()) {
       client_->SetNeedsCommitOnImplThread();
@@ -3251,9 +3246,9 @@
   // task), fall back to physical time.  This should still be monotonic.
   if (current_begin_frame_args_.IsValid())
     return current_begin_frame_args_;
-  return BeginFrameArgs::Create(gfx::FrameTime::Now(), base::TimeTicks(),
-                                BeginFrameArgs::DefaultInterval(),
-                                BeginFrameArgs::NORMAL);
+  return BeginFrameArgs::Create(
+      BEGINFRAME_FROM_HERE, gfx::FrameTime::Now(), base::TimeTicks(),
+      BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
 }
 
 scoped_refptr<base::debug::ConvertableToTraceFormat>
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index d1b29ca..900e658 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -481,8 +481,6 @@
   // Only valid for synchronous (non-scheduled) single-threaded case.
   void SynchronouslyInitializeAllTiles();
 
-  bool CanUseZeroCopyRasterizer() const;
-  bool CanUseOneCopyRasterizer() const;
   virtual void CreateResourceAndRasterWorkerPool(
       scoped_ptr<RasterWorkerPool>* raster_worker_pool,
       scoped_ptr<ResourcePool>* resource_pool,
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 7151689..4e070e2 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -945,7 +945,7 @@
   }
 
   // Scrolling after a pinch gesture should always be in local space.  The
-  // scroll deltas do not have the page scale factor applied.
+  // scroll deltas have the page scale factor applied.
   {
     host_impl_->active_tree()->SetPageScaleFactorAndLimits(
         page_scale_factor, min_page_scale, max_page_scale);
@@ -968,9 +968,8 @@
 
     scoped_ptr<ScrollAndScaleSet> scroll_info =
         host_impl_->ProcessScrollDeltas();
-    ExpectContains(*scroll_info.get(),
-                   scroll_layer->id(),
-                   scroll_delta);
+    ExpectContains(*scroll_info.get(), scroll_layer->id(),
+                   gfx::Vector2d(0, scroll_delta.y() / page_scale_delta));
   }
 }
 
@@ -1395,7 +1394,8 @@
                           0) {}
 
   BeginFrameArgs CurrentBeginFrameArgs() const override {
-    return CreateBeginFrameArgsForTesting(fake_current_physical_time_);
+    return CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE,
+                                          fake_current_physical_time_);
   }
 
   void SetCurrentPhysicalTimeTicksForTest(base::TimeTicks fake_now) {
@@ -3596,7 +3596,7 @@
   host_impl_->ScrollBy(gfx::Point(), wheel_scroll_delta);
   host_impl_->ScrollEnd();
 
-  // The scale should not have been applied to the scroll delta.
+  // It should apply the scale factor to the scroll delta for the wheel event.
   scroll_info = host_impl_->ProcessScrollDeltas();
   ExpectContains(*scroll_info.get(),
                  scroll_layer->id(),
@@ -7800,6 +7800,41 @@
   EXPECT_EQ(1u, raw_replica_mask_layer->did_become_active_call_count());
 }
 
+TEST_F(LayerTreeHostImplTest, WheelScrollWithPageScaleFactorOnInnerLayer) {
+  LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100));
+  host_impl_->SetViewportSize(gfx::Size(50, 50));
+  DrawFrame();
+
+  EXPECT_EQ(scroll_layer, host_impl_->InnerViewportScrollLayer());
+
+  float min_page_scale = 1.f, max_page_scale = 4.f;
+  float page_scale_factor = 1.f;
+
+  // The scroll deltas should have the page scale factor applied.
+  {
+    host_impl_->active_tree()->SetPageScaleFactorAndLimits(
+        page_scale_factor, min_page_scale, max_page_scale);
+    host_impl_->active_tree()->SetPageScaleDelta(1.f);
+    scroll_layer->SetScrollDelta(gfx::Vector2d());
+
+    float page_scale_delta = 2.f;
+    host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+    host_impl_->PinchGestureBegin();
+    host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point());
+    host_impl_->PinchGestureEnd();
+    host_impl_->ScrollEnd();
+
+    gfx::Vector2dF scroll_delta(0, 5);
+    EXPECT_EQ(InputHandler::ScrollStarted,
+              host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+    EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->TotalScrollOffset());
+
+    host_impl_->ScrollBy(gfx::Point(), scroll_delta);
+    host_impl_->ScrollEnd();
+    EXPECT_VECTOR_EQ(gfx::Vector2dF(0, 2.5), scroll_layer->TotalScrollOffset());
+  }
+}
+
 class LayerTreeHostImplCountingLostSurfaces : public LayerTreeHostImplTest {
  public:
   LayerTreeHostImplCountingLostSurfaces() : num_lost_surfaces_(0) {}
diff --git a/cc/trees/layer_tree_host_pixeltest_masks.cc b/cc/trees/layer_tree_host_pixeltest_masks.cc
index c494914..1235e15 100644
--- a/cc/trees/layer_tree_host_pixeltest_masks.cc
+++ b/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -47,6 +47,13 @@
     }
   }
 
+  scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+      const gfx::Rect& clip,
+      GraphicsContextStatus gc_status) override {
+    NOTIMPLEMENTED();
+    return DisplayItemList::Create();
+  }
+
  private:
   gfx::Size bounds_;
 };
diff --git a/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc b/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
index e7dd149..a5ccb8b 100644
--- a/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
+++ b/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
@@ -80,6 +80,13 @@
         paint);
   }
 
+  scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+      const gfx::Rect& clip,
+      GraphicsContextStatus gc_status) override {
+    NOTIMPLEMENTED();
+    return DisplayItemList::Create();
+  }
+
  private:
   gfx::Rect layer_rect_;
 };
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index f589c84..51c5d7e 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -1112,6 +1112,12 @@
     if (test_layer_)
       test_layer_->SetOpacity(0.f);
   }
+  scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+      const gfx::Rect& clip,
+      GraphicsContextStatus gc_status) override {
+    NOTIMPLEMENTED();
+    return DisplayItemList::Create();
+  }
   bool FillsBoundsCompletely() const override { return false; }
 
  private:
@@ -2321,6 +2327,13 @@
       ++paint_count_;
     }
 
+    scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+        const gfx::Rect& clip,
+        GraphicsContextStatus gc_status) override {
+      NOTIMPLEMENTED();
+      return DisplayItemList::Create();
+    }
+
     bool FillsBoundsCompletely() const override { return false; }
 
    private:
@@ -2591,6 +2604,13 @@
       layer_->SetBounds(gfx::Size(2, 2));
     }
 
+    scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
+        const gfx::Rect& clip,
+        GraphicsContextStatus gc_status) override {
+      NOTIMPLEMENTED();
+      return DisplayItemList::Create();
+    }
+
     bool FillsBoundsCompletely() const override { return false; }
 
    private:
@@ -5653,6 +5673,9 @@
         TestWebGraphicsContext3D::Create();
     context3d->set_support_image(true);
     context3d->set_support_sync_query(true);
+#if defined(OS_MACOSX)
+    context3d->set_support_texture_rectangle(true);
+#endif
 
     if (delegating_renderer())
       return FakeOutputSurface::CreateDelegating3d(context3d.Pass());
@@ -5840,4 +5863,59 @@
 
 MULTI_THREAD_TEST_F(LayerTreeHostTestContinuousDrawWhenCreatingVisibleTiles);
 
+class LayerTreeHostTestOneActivatePerManageTiles : public LayerTreeHostTest {
+ public:
+  LayerTreeHostTestOneActivatePerManageTiles()
+      : notify_ready_to_activate_count_(0u), scheduled_manage_tiles_count_(0) {}
+
+  void SetupTree() override {
+    client_.set_fill_with_nonsolid_color(true);
+    scoped_refptr<FakePictureLayer> root_layer =
+        FakePictureLayer::Create(&client_);
+    root_layer->SetBounds(gfx::Size(1500, 1500));
+    root_layer->SetIsDrawable(true);
+
+    layer_tree_host()->SetRootLayer(root_layer);
+    LayerTreeHostTest::SetupTree();
+  }
+
+  void BeginTest() override {
+    layer_tree_host()->SetViewportSize(gfx::Size(16, 16));
+    PostSetNeedsCommitToMainThread();
+  }
+
+  void InitializedRendererOnThread(LayerTreeHostImpl* host_impl,
+                                   bool success) override {
+    ASSERT_TRUE(success);
+    host_impl->tile_manager()->SetScheduledRasterTaskLimitForTesting(1);
+  }
+
+  void NotifyReadyToActivateOnThread(LayerTreeHostImpl* impl) override {
+    ++notify_ready_to_activate_count_;
+    EndTestAfterDelayMs(100);
+  }
+
+  void ScheduledActionManageTiles() override {
+    ++scheduled_manage_tiles_count_;
+  }
+
+  void AfterTest() override {
+    // Expect at most a notification for each scheduled manage tiles, plus one
+    // for the initial commit (which doesn't go through scheduled actions).
+    // The reason this is not an equality is because depending on timing, we
+    // might get a manage tiles but not yet get a notification that we're
+    // ready to activate. The intent of a test is to ensure that we don't
+    // get more than one notification per manage tiles, so this is OK.
+    EXPECT_LE(notify_ready_to_activate_count_,
+              1u + scheduled_manage_tiles_count_);
+  }
+
+ protected:
+  FakeContentLayerClient client_;
+  size_t notify_ready_to_activate_count_;
+  size_t scheduled_manage_tiles_count_;
+};
+
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestOneActivatePerManageTiles);
+
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc
index 8318192..f6bc4d9 100644
--- a/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/cc/trees/layer_tree_host_unittest_animation.cc
@@ -106,13 +106,12 @@
     LayerTreeHostAnimationTestSetNeedsAnimateInsideAnimationCallback);
 
 // Add a layer animation and confirm that
-// LayerTreeHostImpl::updateAnimationState does get called and continues to
-// get called.
+// LayerTreeHostImpl::UpdateAnimationState does get called.
 class LayerTreeHostAnimationTestAddAnimation
     : public LayerTreeHostAnimationTest {
  public:
   LayerTreeHostAnimationTestAddAnimation()
-      : num_begin_frames_(0), received_animation_started_notification_(false) {}
+      : update_animation_state_was_called_(false) {}
 
   void BeginTest() override {
     PostAddInstantAnimationToMainThread(layer_tree_host()->root_layer());
@@ -120,53 +119,28 @@
 
   void UpdateAnimationState(LayerTreeHostImpl* host_impl,
                             bool has_unfinished_animation) override {
-    if (!num_begin_frames_) {
-      // The animation had zero duration so LayerTreeHostImpl should no
-      // longer need to animate its layers.
-      EXPECT_FALSE(has_unfinished_animation);
-      num_begin_frames_++;
-      return;
-    }
-
-    if (received_animation_started_notification_) {
-      EXPECT_LT(base::TimeTicks(), start_time_);
-
-      LayerAnimationController* controller_impl =
-          host_impl->active_tree()->root_layer()->layer_animation_controller();
-      Animation* animation_impl =
-          controller_impl->GetAnimation(Animation::Opacity);
-      if (animation_impl)
-        controller_impl->RemoveAnimation(animation_impl->id());
-
-      EndTest();
-    }
+    EXPECT_FALSE(has_unfinished_animation);
+    update_animation_state_was_called_ = true;
   }
 
   void NotifyAnimationStarted(base::TimeTicks monotonic_time,
                               Animation::TargetProperty target_property,
                               int group) override {
-    received_animation_started_notification_ = true;
-    start_time_ = monotonic_time;
-    if (num_begin_frames_) {
-      EXPECT_LT(base::TimeTicks(), start_time_);
+    EXPECT_LT(base::TimeTicks(), monotonic_time);
 
-      LayerAnimationController* controller =
-          layer_tree_host()->root_layer()->layer_animation_controller();
-      Animation* animation =
-          controller->GetAnimation(Animation::Opacity);
-      if (animation)
-        controller->RemoveAnimation(animation->id());
+    LayerAnimationController* controller =
+        layer_tree_host()->root_layer()->layer_animation_controller();
+    Animation* animation = controller->GetAnimation(Animation::Opacity);
+    if (animation)
+      controller->RemoveAnimation(animation->id());
 
-      EndTest();
-    }
+    EndTest();
   }
 
-  void AfterTest() override {}
+  void AfterTest() override { EXPECT_TRUE(update_animation_state_was_called_); }
 
  private:
-  int num_begin_frames_;
-  bool received_animation_started_notification_;
-  base::TimeTicks start_time_;
+  bool update_animation_state_was_called_;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestAddAnimation);
@@ -531,9 +505,7 @@
 class LayerTreeHostAnimationTestSynchronizeAnimationStartTimes
     : public LayerTreeHostAnimationTest {
  public:
-  LayerTreeHostAnimationTestSynchronizeAnimationStartTimes()
-      : main_start_time_(-1.0),
-        impl_start_time_(-1.0) {}
+  LayerTreeHostAnimationTestSynchronizeAnimationStartTimes() {}
 
   void SetupTree() override {
     LayerTreeHostAnimationTest::SetupTree();
@@ -553,12 +525,9 @@
         layer_animation_controller();
     Animation* animation =
         controller->GetAnimation(Animation::Opacity);
-    main_start_time_ =
-        (animation->start_time() - base::TimeTicks()).InSecondsF();
+    main_start_time_ = animation->start_time();
     controller->RemoveAnimation(animation->id());
-
-    if (impl_start_time_ > 0.0)
-      EndTest();
+    EndTest();
   }
 
   void UpdateAnimationState(LayerTreeHostImpl* impl_host,
@@ -571,21 +540,17 @@
     if (!animation)
       return;
 
-    impl_start_time_ =
-        (animation->start_time() - base::TimeTicks()).InSecondsF();
-    controller->RemoveAnimation(animation->id());
-
-    if (main_start_time_ > 0.0)
-      EndTest();
+    impl_start_time_ = animation->start_time();
   }
 
   void AfterTest() override {
-    EXPECT_FLOAT_EQ(impl_start_time_, main_start_time_);
+    EXPECT_EQ(impl_start_time_, main_start_time_);
+    EXPECT_LT(base::TimeTicks(), impl_start_time_);
   }
 
  private:
-  double main_start_time_;
-  double impl_start_time_;
+  base::TimeTicks main_start_time_;
+  base::TimeTicks impl_start_time_;
   FakeContentLayerClient client_;
   scoped_refptr<FakeContentLayer> content_;
 };
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index e792427..0771eb8 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -61,10 +61,13 @@
       strict_layer_property_change_checking(false),
       use_one_copy(false),
       use_zero_copy(false),
+      use_image_external(false),
       ignore_root_layer_flings(false),
       scheduled_raster_task_limit(32),
       use_occlusion_for_tile_prioritization(false),
-      record_full_layer(false) {
+      record_full_layer(false),
+      use_display_lists(false),
+      main_thread_should_always_be_low_latency(false) {
 }
 
 LayerTreeSettings::~LayerTreeSettings() {}
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index ebbe7f7..438344b 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -73,10 +73,13 @@
   bool strict_layer_property_change_checking;
   bool use_one_copy;
   bool use_zero_copy;
+  bool use_image_external;
   bool ignore_root_layer_flings;
   size_t scheduled_raster_task_limit;
   bool use_occlusion_for_tile_prioritization;
   bool record_full_layer;
+  bool use_display_lists;
+  bool main_thread_should_always_be_low_latency;
 
   LayerTreeDebugState initial_debug_state;
 };
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 5a40d7e..9a13457 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -430,9 +430,8 @@
     // equivalent of blocking commit until activation and also running
     // all tasks posted during commit/activation before CommitComplete.
     MainThreadTaskRunner()->PostTask(
-        FROM_HERE,
-        base::Bind(&SingleThreadProxy::CommitComplete,
-                   weak_factory_.GetWeakPtr()));
+        FROM_HERE, base::Bind(&SingleThreadProxy::CommitComplete,
+                              weak_factory_.GetWeakPtr()));
   }
 
   timing_history_.DidActivateSyncTree();
@@ -493,8 +492,8 @@
 
   {
     BeginFrameArgs begin_frame_args(BeginFrameArgs::Create(
-        frame_begin_time, base::TimeTicks(), BeginFrameArgs::DefaultInterval(),
-        BeginFrameArgs::SYNCHRONOUS));
+        BEGINFRAME_FROM_HERE, frame_begin_time, base::TimeTicks(),
+        BeginFrameArgs::DefaultInterval(), BeginFrameArgs::SYNCHRONOUS));
     DoBeginMainFrame(begin_frame_args);
     DoCommit();