Update from https://crrev.com/316786

List of manually-modified files:
gpu/command_buffer/service/in_process_command_buffer.cc
examples/sample_app/BUILD.gn
examples/sample_app/spinning_cube.cc
mojo/android/javatests/src/org/chromium/mojo/MojoTestCase.java
mojo/cc/context_provider_mojo.cc
mojo/cc/context_provider_mojo.h
mojo/common/trace_controller_impl.cc
mojo/gles2/command_buffer_client_impl.cc
mojo/gles2/command_buffer_client_impl.h
services/gles2/gpu_impl.cc
shell/android/apk/src/org/chromium/mojo/shell/MojoShellApplication.java
sky/engine/core/dom/Node.cpp
sky/shell/apk/src/org/domokit/sky/shell/SkyShellApplication.java
ui/events/latency_info.cc
ui/gfx/transform.cc
ui/gfx/transform.h
ui/gfx/transform_util.cc
ui/gfx/transform_util.h

Review URL: https://codereview.chromium.org/935333002
diff --git a/cc/base/math_util.cc b/cc/base/math_util.cc
index 70090d9..e2fd565 100644
--- a/cc/base/math_util.cc
+++ b/cc/base/math_util.cc
@@ -735,7 +735,7 @@
 
 void MathUtil::AddToTracedValue(const char* name,
                                 const gfx::Size& s,
-                                base::debug::TracedValue* res) {
+                                base::trace_event::TracedValue* res) {
   res->BeginDictionary(name);
   res->SetDouble("width", s.width());
   res->SetDouble("height", s.height());
@@ -744,7 +744,7 @@
 
 void MathUtil::AddToTracedValue(const char* name,
                                 const gfx::SizeF& s,
-                                base::debug::TracedValue* res) {
+                                base::trace_event::TracedValue* res) {
   res->BeginDictionary(name);
   res->SetDouble("width", s.width());
   res->SetDouble("height", s.height());
@@ -753,7 +753,7 @@
 
 void MathUtil::AddToTracedValue(const char* name,
                                 const gfx::Rect& r,
-                                base::debug::TracedValue* res) {
+                                base::trace_event::TracedValue* res) {
   res->BeginArray(name);
   res->AppendInteger(r.x());
   res->AppendInteger(r.y());
@@ -764,7 +764,7 @@
 
 void MathUtil::AddToTracedValue(const char* name,
                                 const gfx::PointF& pt,
-                                base::debug::TracedValue* res) {
+                                base::trace_event::TracedValue* res) {
   res->BeginArray(name);
   res->AppendDouble(pt.x());
   res->AppendDouble(pt.y());
@@ -773,7 +773,7 @@
 
 void MathUtil::AddToTracedValue(const char* name,
                                 const gfx::Point3F& pt,
-                                base::debug::TracedValue* res) {
+                                base::trace_event::TracedValue* res) {
   res->BeginArray(name);
   res->AppendDouble(pt.x());
   res->AppendDouble(pt.y());
@@ -783,7 +783,7 @@
 
 void MathUtil::AddToTracedValue(const char* name,
                                 const gfx::Vector2d& v,
-                                base::debug::TracedValue* res) {
+                                base::trace_event::TracedValue* res) {
   res->BeginArray(name);
   res->AppendInteger(v.x());
   res->AppendInteger(v.y());
@@ -792,7 +792,7 @@
 
 void MathUtil::AddToTracedValue(const char* name,
                                 const gfx::Vector2dF& v,
-                                base::debug::TracedValue* res) {
+                                base::trace_event::TracedValue* res) {
   res->BeginArray(name);
   res->AppendDouble(v.x());
   res->AppendDouble(v.y());
@@ -801,7 +801,7 @@
 
 void MathUtil::AddToTracedValue(const char* name,
                                 const gfx::ScrollOffset& v,
-                                base::debug::TracedValue* res) {
+                                base::trace_event::TracedValue* res) {
   res->BeginArray(name);
   res->AppendDouble(v.x());
   res->AppendDouble(v.y());
@@ -810,7 +810,7 @@
 
 void MathUtil::AddToTracedValue(const char* name,
                                 const gfx::QuadF& q,
-                                base::debug::TracedValue* res) {
+                                base::trace_event::TracedValue* res) {
   res->BeginArray(name);
   res->AppendDouble(q.p1().x());
   res->AppendDouble(q.p1().y());
@@ -825,7 +825,7 @@
 
 void MathUtil::AddToTracedValue(const char* name,
                                 const gfx::RectF& rect,
-                                base::debug::TracedValue* res) {
+                                base::trace_event::TracedValue* res) {
   res->BeginArray(name);
   res->AppendDouble(rect.x());
   res->AppendDouble(rect.y());
@@ -836,7 +836,7 @@
 
 void MathUtil::AddToTracedValue(const char* name,
                                 const gfx::Transform& transform,
-                                base::debug::TracedValue* res) {
+                                base::trace_event::TracedValue* res) {
   res->BeginArray(name);
   const SkMatrix44& m = transform.matrix();
   for (int row = 0; row < 4; ++row) {
@@ -848,7 +848,7 @@
 
 void MathUtil::AddToTracedValue(const char* name,
                                 const gfx::BoxF& box,
-                                base::debug::TracedValue* res) {
+                                base::trace_event::TracedValue* res) {
   res->BeginArray(name);
   res->AppendInteger(box.x());
   res->AppendInteger(box.y());
diff --git a/cc/base/math_util.h b/cc/base/math_util.h
index ddc8955..56fdd17 100644
--- a/cc/base/math_util.h
+++ b/cc/base/math_util.h
@@ -24,12 +24,6 @@
 namespace trace_event {
 class TracedValue;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015.
-namespace debug {
-using ::base::trace_event::TracedValue;
-}
 }  // namespace base
 
 namespace gfx {
@@ -207,40 +201,40 @@
 
   static void AddToTracedValue(const char* name,
                                const gfx::Size& s,
-                               base::debug::TracedValue* res);
+                               base::trace_event::TracedValue* res);
   static void AddToTracedValue(const char* name,
                                const gfx::SizeF& s,
-                               base::debug::TracedValue* res);
+                               base::trace_event::TracedValue* res);
   static void AddToTracedValue(const char* name,
                                const gfx::Rect& r,
-                               base::debug::TracedValue* res);
+                               base::trace_event::TracedValue* res);
   static void AddToTracedValue(const char* name,
                                const gfx::PointF& q,
-                               base::debug::TracedValue* res);
+                               base::trace_event::TracedValue* res);
   static void AddToTracedValue(const char* name,
                                const gfx::Point3F&,
-                               base::debug::TracedValue* res);
+                               base::trace_event::TracedValue* res);
   static void AddToTracedValue(const char* name,
                                const gfx::Vector2d& v,
-                               base::debug::TracedValue* res);
+                               base::trace_event::TracedValue* res);
   static void AddToTracedValue(const char* name,
                                const gfx::Vector2dF& v,
-                               base::debug::TracedValue* res);
+                               base::trace_event::TracedValue* res);
   static void AddToTracedValue(const char* name,
                                const gfx::ScrollOffset& v,
-                               base::debug::TracedValue* res);
+                               base::trace_event::TracedValue* res);
   static void AddToTracedValue(const char* name,
                                const gfx::QuadF& q,
-                               base::debug::TracedValue* res);
+                               base::trace_event::TracedValue* res);
   static void AddToTracedValue(const char* name,
                                const gfx::RectF& rect,
-                               base::debug::TracedValue* res);
+                               base::trace_event::TracedValue* res);
   static void AddToTracedValue(const char* name,
                                const gfx::Transform& transform,
-                               base::debug::TracedValue* res);
+                               base::trace_event::TracedValue* res);
   static void AddToTracedValue(const char* name,
                                const gfx::BoxF& box,
-                               base::debug::TracedValue* res);
+                               base::trace_event::TracedValue* res);
 
   // Returns a base::Value representation of the floating point value.
   // If the value is inf, returns max double/float representation.
diff --git a/cc/base/region.cc b/cc/base/region.cc
index 22d9585..c048c89 100644
--- a/cc/base/region.cc
+++ b/cc/base/region.cc
@@ -130,7 +130,7 @@
   return result.Pass();
 }
 
-void Region::AsValueInto(base::debug::TracedValue* result) const {
+void Region::AsValueInto(base::trace_event::TracedValue* result) const {
   for (Iterator it(*this); it.has_rect(); it.next()) {
     gfx::Rect rect(it.rect());
     result->AppendInteger(rect.x());
diff --git a/cc/base/region.h b/cc/base/region.h
index b84dbd5..583311e 100644
--- a/cc/base/region.h
+++ b/cc/base/region.h
@@ -18,13 +18,7 @@
 namespace trace_event {
 class TracedValue;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015.
-namespace debug {
-using ::base::trace_event::TracedValue;
 }
-}  // namespace base
 
 namespace cc {
 class SimpleEnclosedRegion;
@@ -69,7 +63,7 @@
 
   std::string ToString() const;
   scoped_ptr<base::Value> AsValue() const;
-  void AsValueInto(base::debug::TracedValue* array) const;
+  void AsValueInto(base::trace_event::TracedValue* array) const;
 
   class CC_EXPORT Iterator {
    public:
diff --git a/cc/base/switches.cc b/cc/base/switches.cc
index d34821e..c3fad97 100644
--- a/cc/base/switches.cc
+++ b/cc/base/switches.cc
@@ -99,16 +99,6 @@
 const char kUIShowReplicaScreenSpaceRects[] =
     "ui-show-replica-screenspace-rects";
 
-// Show rects in the HUD wherever something is known to be drawn opaque and is
-// considered occluding the pixels behind it.
-const char kShowOccludingRects[] = "show-occluding-rects";
-const char kUIShowOccludingRects[] = "ui-show-occluding-rects";
-
-// Show rects in the HUD wherever something is not known to be drawn opaque and
-// is not considered to be occluding the pixels behind it.
-const char kShowNonOccludingRects[] = "show-nonoccluding-rects";
-const char kUIShowNonOccludingRects[] = "ui-show-nonoccluding-rects";
-
 // Prevents the layer tree unit tests from timing out.
 const char kCCLayerTreeTestNoTimeout[] = "cc-layer-tree-test-no-timeout";
 
diff --git a/cc/base/switches.h b/cc/base/switches.h
index 611f0da..5b7c92e 100644
--- a/cc/base/switches.h
+++ b/cc/base/switches.h
@@ -51,10 +51,6 @@
 CC_EXPORT extern const char kUIShowScreenSpaceRects[];
 CC_EXPORT extern const char kShowReplicaScreenSpaceRects[];
 CC_EXPORT extern const char kUIShowReplicaScreenSpaceRects[];
-CC_EXPORT extern const char kShowOccludingRects[];
-CC_EXPORT extern const char kUIShowOccludingRects[];
-CC_EXPORT extern const char kShowNonOccludingRects[];
-CC_EXPORT extern const char kUIShowNonOccludingRects[];
 
 // Unit test related.
 CC_EXPORT extern const char kCCLayerTreeTestNoTimeout[];
diff --git a/cc/blink/web_display_item_list_impl.cc b/cc/blink/web_display_item_list_impl.cc
index fdd05df..dc1d430 100644
--- a/cc/blink/web_display_item_list_impl.cc
+++ b/cc/blink/web_display_item_list_impl.cc
@@ -7,6 +7,7 @@
 #include <vector>
 
 #include "cc/blink/web_blend_mode.h"
+#include "cc/blink/web_filter_operations_impl.h"
 #include "cc/resources/clip_display_item.h"
 #include "cc/resources/clip_path_display_item.h"
 #include "cc/resources/drawing_display_item.h"
@@ -32,6 +33,11 @@
   return display_item_list_;
 }
 
+void WebDisplayItemListImpl::appendDrawingItem(const SkPicture* picture) {
+  display_item_list_->AppendItem(cc::DrawingDisplayItem::Create(
+      skia::SharePtr(const_cast<SkPicture*>(picture)), gfx::PointF(0, 0)));
+}
+
 void WebDisplayItemListImpl::appendDrawingItem(
     SkPicture* picture,
     const blink::WebFloatPoint& location) {
@@ -95,12 +101,26 @@
   display_item_list_->AppendItem(cc::EndTransparencyDisplayItem::Create());
 }
 
+#if FILTER_DISPLAY_ITEM_USES_FILTER_OPERATIONS
+void WebDisplayItemListImpl::appendFilterItem(
+    const blink::WebFilterOperations& filters,
+    const blink::WebFloatRect& bounds) {
+  const WebFilterOperationsImpl& filters_impl =
+      static_cast<const WebFilterOperationsImpl&>(filters);
+  display_item_list_->AppendItem(
+      cc::FilterDisplayItem::Create(filters_impl.AsFilterOperations(), bounds));
+}
+#else
 void WebDisplayItemListImpl::appendFilterItem(
     SkImageFilter* filter,
     const blink::WebFloatRect& bounds) {
+  cc::FilterOperations filter_operations;
+  filter_operations.Append(
+      cc::FilterOperation::CreateReferenceFilter(skia::SharePtr(filter)));
   display_item_list_->AppendItem(
-      cc::FilterDisplayItem::Create(skia::SharePtr(filter), bounds));
+      cc::FilterDisplayItem::Create(filter_operations, bounds));
 }
+#endif
 
 void WebDisplayItemListImpl::appendEndFilterItem() {
   display_item_list_->AppendItem(cc::EndFilterDisplayItem::Create());
diff --git a/cc/blink/web_display_item_list_impl.h b/cc/blink/web_display_item_list_impl.h
index cd35975..f2ff8c6 100644
--- a/cc/blink/web_display_item_list_impl.h
+++ b/cc/blink/web_display_item_list_impl.h
@@ -14,6 +14,7 @@
 #include "third_party/WebKit/public/platform/WebFloatPoint.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
 #include "third_party/skia/include/core/SkRegion.h"
+#include "ui/gfx/geometry/point_f.h"
 
 class SkImageFilter;
 class SkMatrix44;
@@ -31,7 +32,8 @@
   scoped_refptr<cc::DisplayItemList> ToDisplayItemList();
 
   // blink::WebDisplayItemList implementation.
-  virtual void appendDrawingItem(SkPicture* picture,
+  virtual void appendDrawingItem(const SkPicture*);
+  virtual void appendDrawingItem(SkPicture*,
                                  const blink::WebFloatPoint& location);
   virtual void appendClipItem(
       const blink::WebRect& clip_rect,
@@ -48,8 +50,13 @@
   virtual void appendTransparencyItem(float opacity,
                                       blink::WebBlendMode blend_mode);
   virtual void appendEndTransparencyItem();
+#if FILTER_DISPLAY_ITEM_USES_FILTER_OPERATIONS
+  virtual void appendFilterItem(const blink::WebFilterOperations& filters,
+                                const blink::WebFloatRect& bounds);
+#else
   virtual void appendFilterItem(SkImageFilter* filter,
                                 const blink::WebFloatRect& bounds);
+#endif
   virtual void appendEndFilterItem();
 
  private:
diff --git a/cc/blink/web_layer_impl.cc b/cc/blink/web_layer_impl.cc
index bcebfec..2d5e459 100644
--- a/cc/blink/web_layer_impl.cc
+++ b/cc/blink/web_layer_impl.cc
@@ -4,6 +4,9 @@
 
 #include "cc/blink/web_layer_impl.h"
 
+#include <utility>
+#include <vector>
+
 #include "base/bind.h"
 #include "base/lazy_instance.h"
 #include "base/strings/string_util.h"
@@ -358,6 +361,16 @@
   return result;
 }
 
+void WebLayerImpl::setFrameTimingRequests(
+    const WebVector<std::pair<int64_t, WebRect>>& requests) {
+  std::vector<cc::FrameTimingRequest> frame_timing_requests(requests.size());
+  for (size_t i = 0; i < requests.size(); ++i) {
+    frame_timing_requests.push_back(cc::FrameTimingRequest(
+        requests[i].first, gfx::Rect(requests[i].second)));
+  }
+  layer_->SetFrameTimingRequests(frame_timing_requests);
+}
+
 void WebLayerImpl::setTouchEventHandlerRegion(const WebVector<WebRect>& rects) {
   cc::Region region;
   for (size_t i = 0; i < rects.size(); ++i)
@@ -458,7 +471,7 @@
   web_layer_client_ = client;
 }
 
-class TracedDebugInfo : public base::debug::ConvertableToTraceFormat {
+class TracedDebugInfo : public base::trace_event::ConvertableToTraceFormat {
  public:
   // This object takes ownership of the debug_info object.
   explicit TracedDebugInfo(blink::WebGraphicsLayerDebugInfo* debug_info)
@@ -476,7 +489,7 @@
   base::ThreadChecker thread_checker_;
 };
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 WebLayerImpl::TakeDebugInfo() {
   if (!web_layer_client_)
     return nullptr;
diff --git a/cc/blink/web_layer_impl.h b/cc/blink/web_layer_impl.h
index 787f632..0560bed 100644
--- a/cc/blink/web_layer_impl.h
+++ b/cc/blink/web_layer_impl.h
@@ -6,6 +6,7 @@
 #define CC_BLINK_WEB_LAYER_IMPL_H_
 
 #include <string>
+#include <utility>
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
@@ -34,13 +35,7 @@
 namespace trace_event {
 class ConvertableToTraceFormat;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015.
-namespace debug {
-using ::base::trace_event::ConvertableToTraceFormat;
 }
-}  // namespace base
 
 namespace cc {
 class Layer;
@@ -131,6 +126,8 @@
   virtual blink::WebVector<blink::WebRect> touchEventHandlerRegion() const;
   virtual void setScrollBlocksOn(blink::WebScrollBlocksOn);
   virtual blink::WebScrollBlocksOn scrollBlocksOn() const;
+  virtual void setFrameTimingRequests(
+      const blink::WebVector<std::pair<int64_t, blink::WebRect>>& requests);
   virtual void setIsContainerForFixedPositionLayers(bool is_container);
   virtual bool isContainerForFixedPositionLayers() const;
   virtual void setPositionConstraint(
@@ -141,7 +138,8 @@
   virtual void setWebLayerClient(blink::WebLayerClient* client);
 
   // LayerClient implementation.
-  scoped_refptr<base::debug::ConvertableToTraceFormat> TakeDebugInfo() override;
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> TakeDebugInfo()
+      override;
 
   virtual void setScrollParent(blink::WebLayer* parent);
   virtual void setClipParent(blink::WebLayer* parent);
diff --git a/cc/cc_unittests.isolate b/cc/cc_unittests.isolate
index 5d652d9..db47aab 100644
--- a/cc/cc_unittests.isolate
+++ b/cc/cc_unittests.isolate
@@ -82,6 +82,13 @@
         ],
       },
     }],
+    ['OS=="mac" and asan==1 and fastbuild==0', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/cc_unittests.dSYM/',
+        ],
+      },
+    }],
   ],
   'includes': [
     '../base/base.isolate',
diff --git a/cc/debug/benchmark_instrumentation.cc b/cc/debug/benchmark_instrumentation.cc
index bf8ec00..5a04e21 100644
--- a/cc/debug/benchmark_instrumentation.cc
+++ b/cc/debug/benchmark_instrumentation.cc
@@ -20,15 +20,15 @@
 }
 
 void IssueDisplayRenderingStatsEvent() {
-  scoped_refptr<base::debug::TracedValue> record_data =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> record_data =
+      new base::trace_event::TracedValue();
   record_data->SetInteger("frame_count", 1);
   TRACE_EVENT_INSTANT1(
       "benchmark",
       "BenchmarkInstrumentation::DisplayRenderingStats",
       TRACE_EVENT_SCOPE_THREAD,
       "data",
-      scoped_refptr<base::debug::ConvertableToTraceFormat>(record_data));
+      scoped_refptr<base::trace_event::ConvertableToTraceFormat>(record_data));
 }
 
 }  // namespace benchmark_instrumentation
diff --git a/cc/debug/debug_colors.cc b/cc/debug/debug_colors.cc
index 6cbbfe9..daec5cc 100644
--- a/cc/debug/debug_colors.cc
+++ b/cc/debug/debug_colors.cc
@@ -216,24 +216,6 @@
   return SkColorSetARGB(10, 100, 0, 200);
 }
 
-// Occluding rects in pink.
-SkColor DebugColors::OccludingRectBorderColor() {
-  return SkColorSetARGB(255, 245, 136, 255);
-}
-int DebugColors::OccludingRectBorderWidth() { return 2; }
-SkColor DebugColors::OccludingRectFillColor() {
-  return SkColorSetARGB(10, 245, 136, 255);
-}
-
-// Non-Occluding rects in a reddish color.
-SkColor DebugColors::NonOccludingRectBorderColor() {
-  return SkColorSetARGB(255, 200, 0, 100);
-}
-int DebugColors::NonOccludingRectBorderWidth() { return 2; }
-SkColor DebugColors::NonOccludingRectFillColor() {
-  return SkColorSetARGB(10, 200, 0, 100);
-}
-
 // Touch-event-handler rects in yellow.
 SkColor DebugColors::TouchEventHandlerRectBorderColor() {
   return SkColorSetARGB(255, 239, 229, 60);
diff --git a/cc/debug/debug_colors.h b/cc/debug/debug_colors.h
index 3b00d84..52dab85 100644
--- a/cc/debug/debug_colors.h
+++ b/cc/debug/debug_colors.h
@@ -87,14 +87,6 @@
   static int ScreenSpaceSurfaceReplicaRectBorderWidth();
   static SkColor ScreenSpaceSurfaceReplicaRectFillColor();
 
-  static SkColor OccludingRectBorderColor();
-  static int OccludingRectBorderWidth();
-  static SkColor OccludingRectFillColor();
-
-  static SkColor NonOccludingRectBorderColor();
-  static int NonOccludingRectBorderWidth();
-  static SkColor NonOccludingRectFillColor();
-
   static SkColor TouchEventHandlerRectBorderColor();
   static int TouchEventHandlerRectBorderWidth();
   static SkColor TouchEventHandlerRectFillColor();
diff --git a/cc/debug/debug_rect_history.cc b/cc/debug/debug_rect_history.cc
index a8c5030..cde7765 100644
--- a/cc/debug/debug_rect_history.cc
+++ b/cc/debug/debug_rect_history.cc
@@ -29,8 +29,6 @@
     LayerImpl* root_layer,
     LayerImpl* hud_layer,
     const LayerImplList& render_surface_layer_list,
-    const std::vector<gfx::Rect>& occluding_screen_space_rects,
-    const std::vector<gfx::Rect>& non_occluding_screen_space_rects,
     const LayerTreeDebugState& debug_state) {
   // For now, clear all rects from previous frames. In the future we may want to
   // store all debug rects for a history of many frames.
@@ -60,12 +58,6 @@
   if (debug_state.show_screen_space_rects)
     SaveScreenSpaceRects(render_surface_layer_list);
 
-  if (debug_state.show_occluding_rects)
-    SaveOccludingRects(occluding_screen_space_rects);
-
-  if (debug_state.show_non_occluding_rects)
-    SaveNonOccludingRects(non_occluding_screen_space_rects);
-
   if (debug_state.show_layer_animation_bounds_rects)
     SaveLayerAnimationBoundsRects(render_surface_layer_list);
 }
@@ -170,20 +162,6 @@
   }
 }
 
-void DebugRectHistory::SaveOccludingRects(
-    const std::vector<gfx::Rect>& occluding_rects) {
-  for (size_t i = 0; i < occluding_rects.size(); ++i)
-    debug_rects_.push_back(DebugRect(OCCLUDING_RECT_TYPE, occluding_rects[i]));
-}
-
-void DebugRectHistory::SaveNonOccludingRects(
-    const std::vector<gfx::Rect>& non_occluding_rects) {
-  for (size_t i = 0; i < non_occluding_rects.size(); ++i) {
-    debug_rects_.push_back(
-        DebugRect(NONOCCLUDING_RECT_TYPE, non_occluding_rects[i]));
-  }
-}
-
 void DebugRectHistory::SaveTouchEventHandlerRects(LayerImpl* layer) {
   LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>(
       layer,
diff --git a/cc/debug/debug_rect_history.h b/cc/debug/debug_rect_history.h
index 6d25b29..6bcf438 100644
--- a/cc/debug/debug_rect_history.h
+++ b/cc/debug/debug_rect_history.h
@@ -34,21 +34,12 @@
 //
 // - Replica screen space rects: this is the region the replica's contents
 // occupy in screen space.
-//
-// - Occluding rects: these are the regions that contribute to the occluded
-// region.
-//
-// - Non-Occluding rects: these are the regions of composited layers that do not
-//   contribute to the occluded region.
-//
 enum DebugRectType {
   PAINT_RECT_TYPE,
   PROPERTY_CHANGED_RECT_TYPE,
   SURFACE_DAMAGE_RECT_TYPE,
   SCREEN_SPACE_RECT_TYPE,
   REPLICA_SCREEN_SPACE_RECT_TYPE,
-  OCCLUDING_RECT_TYPE,
-  NONOCCLUDING_RECT_TYPE,
   TOUCH_EVENT_HANDLER_RECT_TYPE,
   WHEEL_EVENT_HANDLER_RECT_TYPE,
   SCROLL_EVENT_HANDLER_RECT_TYPE,
@@ -79,8 +70,6 @@
       LayerImpl* root_layer,
       LayerImpl* hud_layer,
       const LayerImplList& render_surface_layer_list,
-      const std::vector<gfx::Rect>& occluding_screen_space_rects,
-      const std::vector<gfx::Rect>& non_occluding_screen_space_rects,
       const LayerTreeDebugState& debug_state);
 
   const std::vector<DebugRect>& debug_rects() { return debug_rects_; }
@@ -95,10 +84,6 @@
       const LayerImplList& render_surface_layer_list);
   void SaveScreenSpaceRects(
       const LayerImplList& render_surface_layer_list);
-  void SaveOccludingRects(
-      const std::vector<gfx::Rect>& occluding_screen_space_rects);
-  void SaveNonOccludingRects(
-      const std::vector<gfx::Rect>& non_occluding_screen_space_rects);
   void SaveTouchEventHandlerRects(LayerImpl* layer);
   void SaveTouchEventHandlerRectsCallback(LayerImpl* layer);
   void SaveWheelEventHandlerRects(LayerImpl* layer);
diff --git a/cc/debug/devtools_instrumentation.h b/cc/debug/devtools_instrumentation.h
index 73788a5..f1faf6f 100644
--- a/cc/debug/devtools_instrumentation.h
+++ b/cc/debug/devtools_instrumentation.h
@@ -96,9 +96,9 @@
 };
 
 struct ScopedLayerObjectTracker
-    : public base::debug::TraceScopedTrackableObject<int> {
+    : public base::trace_event::TraceScopedTrackableObject<int> {
   explicit ScopedLayerObjectTracker(int layer_id)
-      : base::debug::TraceScopedTrackableObject<int>(
+      : base::trace_event::TraceScopedTrackableObject<int>(
             internal::kCategory,
             internal::kLayerId,
             layer_id) {
@@ -142,10 +142,10 @@
                        layer_tree_host_id);
 }
 
-inline scoped_refptr<base::debug::ConvertableToTraceFormat>
+inline scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 BeginMainThreadFrameData(int frame_id) {
-  scoped_refptr<base::debug::TracedValue> value =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> value =
+      new base::trace_event::TracedValue();
   value->SetInteger("frameId", frame_id);
   return value;
 }
diff --git a/cc/debug/frame_timing_tracker_unittest.cc b/cc/debug/frame_timing_tracker_unittest.cc
index ed862c5..85f5716 100644
--- a/cc/debug/frame_timing_tracker_unittest.cc
+++ b/cc/debug/frame_timing_tracker_unittest.cc
@@ -15,8 +15,8 @@
 
 static std::string ToString(
     scoped_ptr<FrameTimingTracker::CompositeTimingSet> timingset) {
-  scoped_refptr<base::debug::TracedValue> value =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> value =
+      new base::trace_event::TracedValue();
   value->BeginArray("values");
   for (const auto& it : *timingset) {
     value->BeginDictionary();
diff --git a/cc/debug/frame_viewer_instrumentation.cc b/cc/debug/frame_viewer_instrumentation.cc
index bd0fbdc..53c1551 100644
--- a/cc/debug/frame_viewer_instrumentation.cc
+++ b/cc/debug/frame_viewer_instrumentation.cc
@@ -18,12 +18,13 @@
 const char kAnalyzeTask[] = "AnalyzeTask";
 const char kRasterTask[] = "RasterTask";
 
-scoped_refptr<base::debug::ConvertableToTraceFormat> TileDataAsValue(
+scoped_refptr<base::trace_event::ConvertableToTraceFormat> TileDataAsValue(
     const void* tile_id,
     TileResolution tile_resolution,
     int source_frame_number,
     int layer_id) {
-  scoped_refptr<base::debug::TracedValue> res(new base::debug::TracedValue());
+  scoped_refptr<base::trace_event::TracedValue> res(
+      new base::trace_event::TracedValue());
   TracedValue::SetIDRef(tile_id, res.get(), kTileId);
   res->SetString(kTileResolution, TileResolutionToString(tile_resolution));
   res->SetInteger(kSourceFrameNumber, source_frame_number);
diff --git a/cc/debug/layer_tree_debug_state.cc b/cc/debug/layer_tree_debug_state.cc
index d89bca3..e840220 100644
--- a/cc/debug/layer_tree_debug_state.cc
+++ b/cc/debug/layer_tree_debug_state.cc
@@ -18,8 +18,6 @@
       show_surface_damage_rects(false),
       show_screen_space_rects(false),
       show_replica_screen_space_rects(false),
-      show_occluding_rects(false),
-      show_non_occluding_rects(false),
       show_touch_event_handler_rects(false),
       show_wheel_event_handler_rects(false),
       show_scroll_event_handler_rects(false),
@@ -48,8 +46,7 @@
 bool LayerTreeDebugState::ShowHudRects() const {
   return show_paint_rects || show_property_changed_rects ||
          show_surface_damage_rects || show_screen_space_rects ||
-         show_replica_screen_space_rects || show_occluding_rects ||
-         show_non_occluding_rects || show_touch_event_handler_rects ||
+         show_replica_screen_space_rects || show_touch_event_handler_rects ||
          show_wheel_event_handler_rects || show_scroll_event_handler_rects ||
          show_non_fast_scrollable_rects || show_layer_animation_bounds_rects;
 }
@@ -69,8 +66,6 @@
       a.show_surface_damage_rects == b.show_surface_damage_rects &&
       a.show_screen_space_rects == b.show_screen_space_rects &&
       a.show_replica_screen_space_rects == b.show_replica_screen_space_rects &&
-      a.show_occluding_rects == b.show_occluding_rects &&
-      a.show_non_occluding_rects == b.show_non_occluding_rects &&
       a.show_touch_event_handler_rects == b.show_touch_event_handler_rects &&
       a.show_wheel_event_handler_rects == b.show_wheel_event_handler_rects &&
       a.show_scroll_event_handler_rects == b.show_scroll_event_handler_rects &&
@@ -96,8 +91,6 @@
   r.show_surface_damage_rects |= b.show_surface_damage_rects;
   r.show_screen_space_rects |= b.show_screen_space_rects;
   r.show_replica_screen_space_rects |= b.show_replica_screen_space_rects;
-  r.show_occluding_rects |= b.show_occluding_rects;
-  r.show_non_occluding_rects |= b.show_non_occluding_rects;
   r.show_touch_event_handler_rects |= b.show_touch_event_handler_rects;
   r.show_wheel_event_handler_rects |= b.show_wheel_event_handler_rects;
   r.show_scroll_event_handler_rects |= b.show_scroll_event_handler_rects;
diff --git a/cc/debug/layer_tree_debug_state.h b/cc/debug/layer_tree_debug_state.h
index c3970e1..4b71cd9 100644
--- a/cc/debug/layer_tree_debug_state.h
+++ b/cc/debug/layer_tree_debug_state.h
@@ -24,8 +24,6 @@
   bool show_surface_damage_rects;
   bool show_screen_space_rects;
   bool show_replica_screen_space_rects;
-  bool show_occluding_rects;
-  bool show_non_occluding_rects;
   bool show_touch_event_handler_rects;
   bool show_wheel_event_handler_rects;
   bool show_scroll_event_handler_rects;
diff --git a/cc/debug/rendering_stats.cc b/cc/debug/rendering_stats.cc
index 2247b3a..3a27c1d 100644
--- a/cc/debug/rendering_stats.cc
+++ b/cc/debug/rendering_stats.cc
@@ -18,7 +18,7 @@
 
 void RenderingStats::TimeDeltaList::AddToTracedValue(
     const char* name,
-    base::debug::TracedValue* list_value) const {
+    base::trace_event::TracedValue* list_value) const {
   list_value->BeginArray(name);
   for (const auto& value : values) {
     list_value->AppendDouble(value.InMillisecondsF());
@@ -43,10 +43,10 @@
 RenderingStats::~RenderingStats() {
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 RenderingStats::AsTraceableData() const {
-  scoped_refptr<base::debug::TracedValue> record_data =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> record_data =
+      new base::trace_event::TracedValue();
   record_data->SetInteger("frame_count", frame_count);
   record_data->SetInteger("visible_content_area", visible_content_area);
   record_data->SetInteger("approximated_visible_content_area",
diff --git a/cc/debug/rendering_stats.h b/cc/debug/rendering_stats.h
index 3a72371..1e97be1 100644
--- a/cc/debug/rendering_stats.h
+++ b/cc/debug/rendering_stats.h
@@ -25,7 +25,7 @@
 
     void Append(base::TimeDelta value);
     void AddToTracedValue(const char* name,
-                          base::debug::TracedValue* list_value) const;
+                          base::trace_event::TracedValue* list_value) const;
 
     void Add(const TimeDeltaList& other);
 
@@ -52,7 +52,8 @@
   TimeDeltaList commit_to_activate_duration;
   TimeDeltaList commit_to_activate_duration_estimate;
 
-  scoped_refptr<base::debug::ConvertableToTraceFormat> AsTraceableData() const;
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsTraceableData()
+      const;
   void Add(const RenderingStats& other);
 };
 
diff --git a/cc/debug/rendering_stats_unittest.cc b/cc/debug/rendering_stats_unittest.cc
index c1e189a..6784e09 100644
--- a/cc/debug/rendering_stats_unittest.cc
+++ b/cc/debug/rendering_stats_unittest.cc
@@ -13,8 +13,8 @@
 namespace {
 
 static std::string ToString(const RenderingStats::TimeDeltaList& list) {
-  scoped_refptr<base::debug::TracedValue> value =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> value =
+      new base::trace_event::TracedValue();
   list.AddToTracedValue("list_value", value.get());
   return value->ToString();
 }
diff --git a/cc/debug/traced_picture.cc b/cc/debug/traced_picture.cc
index 2db5492..2c7622b 100644
--- a/cc/debug/traced_picture.cc
+++ b/cc/debug/traced_picture.cc
@@ -16,17 +16,17 @@
 TracedPicture::~TracedPicture() {
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 TracedPicture::AsTraceablePicture(const Picture* picture) {
-  return scoped_refptr<base::debug::ConvertableToTraceFormat>(
+  return scoped_refptr<base::trace_event::ConvertableToTraceFormat>(
       new TracedPicture(picture));
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 TracedPicture::AsTraceablePictureAlias(const Picture* original) {
   scoped_refptr<TracedPicture> ptr = new TracedPicture(original);
   ptr->is_alias_ = true;
-  return scoped_refptr<base::debug::ConvertableToTraceFormat>(ptr);
+  return scoped_refptr<base::trace_event::ConvertableToTraceFormat>(ptr);
 }
 
 void TracedPicture::AppendAsTraceFormat(std::string* out) const {
diff --git a/cc/debug/traced_picture.h b/cc/debug/traced_picture.h
index 7212277..b9d232d 100644
--- a/cc/debug/traced_picture.h
+++ b/cc/debug/traced_picture.h
@@ -13,14 +13,14 @@
 
 namespace cc {
 
-class TracedPicture : public base::debug::ConvertableToTraceFormat {
+class TracedPicture : public base::trace_event::ConvertableToTraceFormat {
  public:
   explicit TracedPicture(scoped_refptr<const Picture>);
 
-  static scoped_refptr<base::debug::ConvertableToTraceFormat>
+  static scoped_refptr<base::trace_event::ConvertableToTraceFormat>
       AsTraceablePicture(const Picture* picture);
 
-  static scoped_refptr<base::debug::ConvertableToTraceFormat>
+  static scoped_refptr<base::trace_event::ConvertableToTraceFormat>
       AsTraceablePictureAlias(const Picture* original);
 
   void AppendAsTraceFormat(std::string* out) const override;
diff --git a/cc/debug/traced_value.cc b/cc/debug/traced_value.cc
index 72b7ff3..c2ac7f5 100644
--- a/cc/debug/traced_value.cc
+++ b/cc/debug/traced_value.cc
@@ -9,29 +9,31 @@
 
 namespace cc {
 
-void TracedValue::AppendIDRef(const void* id, base::debug::TracedValue* state) {
+void TracedValue::AppendIDRef(const void* id,
+                              base::trace_event::TracedValue* state) {
   state->BeginDictionary();
   state->SetString("id_ref", base::StringPrintf("%p", id));
   state->EndDictionary();
 }
 
 void TracedValue::SetIDRef(const void* id,
-                           base::debug::TracedValue* state,
+                           base::trace_event::TracedValue* state,
                            const char* name) {
   state->BeginDictionary(name);
   state->SetString("id_ref", base::StringPrintf("%p", id));
   state->EndDictionary();
 }
 
-void TracedValue::MakeDictIntoImplicitSnapshot(base::debug::TracedValue* dict,
-                                               const char* object_name,
-                                               const void* id) {
+void TracedValue::MakeDictIntoImplicitSnapshot(
+    base::trace_event::TracedValue* dict,
+    const char* object_name,
+    const void* id) {
   dict->SetString("id", base::StringPrintf("%s/%p", object_name, id));
 }
 
 void TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
     const char* category,
-    base::debug::TracedValue* dict,
+    base::trace_event::TracedValue* dict,
     const char* object_name,
     const void* id) {
   dict->SetString("cat", category);
@@ -40,7 +42,7 @@
 
 void TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
     const char* category,
-    base::debug::TracedValue* dict,
+    base::trace_event::TracedValue* dict,
     const char* object_base_type_name,
     const char* object_name,
     const void* id) {
diff --git a/cc/debug/traced_value.h b/cc/debug/traced_value.h
index db0a08a..34e79a7 100644
--- a/cc/debug/traced_value.h
+++ b/cc/debug/traced_value.h
@@ -9,33 +9,28 @@
 namespace trace_event {
 class TracedValue;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015.
-namespace debug {
-using ::base::trace_event::TracedValue;
 }
-}  // namespace base
 
 namespace cc {
 
 class TracedValue {
  public:
-  static void AppendIDRef(const void* id, base::debug::TracedValue* array);
+  static void AppendIDRef(const void* id,
+                          base::trace_event::TracedValue* array);
   static void SetIDRef(const void* id,
-                       base::debug::TracedValue* dict,
+                       base::trace_event::TracedValue* dict,
                        const char* name);
-  static void MakeDictIntoImplicitSnapshot(base::debug::TracedValue* dict,
+  static void MakeDictIntoImplicitSnapshot(base::trace_event::TracedValue* dict,
                                            const char* object_name,
                                            const void* id);
   static void MakeDictIntoImplicitSnapshotWithCategory(
       const char* category,
-      base::debug::TracedValue* dict,
+      base::trace_event::TracedValue* dict,
       const char* object_name,
       const void* id);
   static void MakeDictIntoImplicitSnapshotWithCategory(
       const char* category,
-      base::debug::TracedValue* dict,
+      base::trace_event::TracedValue* dict,
       const char* object_base_type_name,
       const char* object_name,
       const void* id);
diff --git a/cc/input/top_controls_manager.cc b/cc/input/top_controls_manager.cc
index 1615d7f..615afb0 100644
--- a/cc/input/top_controls_manager.cc
+++ b/cc/input/top_controls_manager.cc
@@ -39,7 +39,6 @@
     : client_(client),
       animation_direction_(NO_ANIMATION),
       permitted_state_(BOTH),
-      top_controls_height_(0.f),
       current_scroll_delta_(0.f),
       controls_scroll_begin_offset_(0.f),
       top_controls_show_threshold_(top_controls_hide_threshold),
@@ -51,12 +50,20 @@
 TopControlsManager::~TopControlsManager() {
 }
 
-float TopControlsManager::ControlsTopOffset() {
-  return client_->ControlsTopOffset();
+float TopControlsManager::ControlsTopOffset() const {
+  return ContentTopOffset() - TopControlsHeight();
 }
 
-float TopControlsManager::ContentTopOffset() {
-  return client_->ControlsTopOffset() + top_controls_height_;
+float TopControlsManager::ContentTopOffset() const {
+  return TopControlsShownRatio() * TopControlsHeight();
+}
+
+float TopControlsManager::TopControlsShownRatio() const {
+  return client_->CurrentTopControlsShownRatio();
+}
+
+float TopControlsManager::TopControlsHeight() const {
+  return client_->TopControlsHeight();
 }
 
 void TopControlsManager::UpdateTopControlsState(TopControlsState constraints,
@@ -72,31 +79,25 @@
     return;
 
   // Don't do anything if there is no change in offset.
-  float final_controls_position = 0.f;
-  if (constraints == HIDDEN || current == HIDDEN) {
-    final_controls_position = -top_controls_height_;
-  }
-  if (final_controls_position == client_->ControlsTopOffset()) {
-    return;
-  }
-
-  AnimationDirection animation_direction = SHOWING_CONTROLS;
+  float final_shown_ratio = 1.f;
   if (constraints == HIDDEN || current == HIDDEN)
-    animation_direction = HIDING_CONTROLS;
-  ResetAnimations();
+    final_shown_ratio = 0.f;
+  if (final_shown_ratio == TopControlsShownRatio())
+    return;
+
   if (animate) {
-    SetupAnimation(animation_direction);
+    SetupAnimation(final_shown_ratio ? SHOWING_CONTROLS : HIDING_CONTROLS);
   } else {
-    client_->SetControlsTopOffset(final_controls_position);
+    ResetAnimations();
+    client_->SetCurrentTopControlsShownRatio(final_shown_ratio);
   }
-  client_->DidChangeTopControlsPosition();
 }
 
 void TopControlsManager::ScrollBegin() {
   DCHECK(!pinch_gesture_active_);
   ResetAnimations();
   current_scroll_delta_ = 0.f;
-  controls_scroll_begin_offset_ = client_->ControlsTopOffset();
+  controls_scroll_begin_offset_ = ContentTopOffset();
 }
 
 gfx::Vector2dF TopControlsManager::ScrollBy(
@@ -111,19 +112,21 @@
 
   current_scroll_delta_ += pending_delta.y();
 
-  float old_offset = client_->ControlsTopOffset();
-  SetControlsTopOffset(controls_scroll_begin_offset_ - current_scroll_delta_);
+  float old_offset = ContentTopOffset();
+  client_->SetCurrentTopControlsShownRatio(
+      (controls_scroll_begin_offset_ - current_scroll_delta_) /
+      TopControlsHeight());
 
   // If the controls are fully visible, treat the current position as the
   // new baseline even if the gesture didn't end.
-  if (client_->ControlsTopOffset() == 0.f) {
+  if (TopControlsShownRatio() == 1.f) {
     current_scroll_delta_ = 0.f;
-    controls_scroll_begin_offset_ = 0.f;
+    controls_scroll_begin_offset_ = ContentTopOffset();
   }
 
   ResetAnimations();
 
-  gfx::Vector2dF applied_delta(0.f, old_offset - client_->ControlsTopOffset());
+  gfx::Vector2dF applied_delta(0.f, old_offset - ContentTopOffset());
   return pending_delta - applied_delta;
 }
 
@@ -146,44 +149,20 @@
   ScrollBegin();
 }
 
-void TopControlsManager::SetControlsTopOffset(float controls_top_offset) {
-  controls_top_offset = std::max(controls_top_offset, -top_controls_height_);
-  controls_top_offset = std::min(controls_top_offset, 0.f);
-
-  if (client_->ControlsTopOffset() == controls_top_offset)
-    return;
-
-  client_->SetControlsTopOffset(controls_top_offset);
-
-  client_->DidChangeTopControlsPosition();
-}
-
-void TopControlsManager::SetTopControlsHeight(float top_controls_height) {
-  DCHECK_GE(top_controls_height, 0);
-
-  if (top_controls_height == top_controls_height_)
-    return;
-
-  ResetAnimations();
-  float top_controls_offset = client_->ControlsTopOffset();
-  top_controls_height_ = top_controls_height;
-  SetControlsTopOffset(top_controls_offset);
-  StartAnimationIfNecessary();
-}
-
 gfx::Vector2dF TopControlsManager::Animate(base::TimeTicks monotonic_time) {
   if (!top_controls_animation_ || !client_->HaveRootScrollLayer())
     return gfx::Vector2dF();
 
   base::TimeDelta time = monotonic_time - base::TimeTicks();
 
-  float old_offset = client_->ControlsTopOffset();
-  SetControlsTopOffset(top_controls_animation_->GetValue(time));
+  float old_offset = ContentTopOffset();
+  client_->SetCurrentTopControlsShownRatio(
+      top_controls_animation_->GetValue(time));
 
   if (IsAnimationCompleteAtTime(monotonic_time))
     ResetAnimations();
 
-  gfx::Vector2dF scroll_delta(0.f, client_->ControlsTopOffset() - old_offset);
+  gfx::Vector2dF scroll_delta(0.f, ContentTopOffset() - old_offset);
   return scroll_delta;
 }
 
@@ -193,15 +172,9 @@
 }
 
 void TopControlsManager::SetupAnimation(AnimationDirection direction) {
-  DCHECK(direction != NO_ANIMATION);
-
-  if (direction == SHOWING_CONTROLS && client_->ControlsTopOffset() == 0)
-    return;
-
-  if (direction == HIDING_CONTROLS &&
-      client_->ControlsTopOffset() == -top_controls_height_) {
-    return;
-  }
+  DCHECK_NE(NO_ANIMATION, direction);
+  DCHECK_IMPLIES(direction == HIDING_CONTROLS, TopControlsShownRatio() > 0.f);
+  DCHECK_IMPLIES(direction == SHOWING_CONTROLS, TopControlsShownRatio() < 1.f);
 
   if (top_controls_animation_ && animation_direction_ == direction)
     return;
@@ -209,42 +182,32 @@
   top_controls_animation_ = KeyframedFloatAnimationCurve::Create();
   base::TimeDelta start_time = gfx::FrameTime::Now() - base::TimeTicks();
   top_controls_animation_->AddKeyframe(
-      FloatKeyframe::Create(start_time, client_->ControlsTopOffset(), nullptr));
-  float max_ending_offset =
-      (direction == SHOWING_CONTROLS ? 1 : -1) * top_controls_height_;
+      FloatKeyframe::Create(start_time, TopControlsShownRatio(), nullptr));
+  float max_ending_ratio = (direction == SHOWING_CONTROLS ? 1 : -1);
   top_controls_animation_->AddKeyframe(FloatKeyframe::Create(
       start_time + base::TimeDelta::FromMilliseconds(kShowHideMaxDurationMs),
-      client_->ControlsTopOffset() + max_ending_offset,
+      TopControlsShownRatio() + max_ending_ratio,
       EaseTimingFunction::Create()));
   animation_direction_ = direction;
   client_->DidChangeTopControlsPosition();
 }
 
 void TopControlsManager::StartAnimationIfNecessary() {
-  if (client_->ControlsTopOffset() != 0
-      && client_->ControlsTopOffset() != -top_controls_height_) {
-    AnimationDirection show_controls = NO_ANIMATION;
+  if (TopControlsShownRatio() == 0.f || TopControlsShownRatio() == 1.f)
+    return;
 
-    float top_controls_show_height =
-        top_controls_height_ * top_controls_hide_threshold_;
-    float top_controls_hide_height =
-        top_controls_height_ * (1.f - top_controls_show_threshold_);
-    if (client_->ControlsTopOffset() >= -top_controls_show_height) {
-      // If we're showing so much that the hide threshold won't trigger, show.
-      show_controls = SHOWING_CONTROLS;
-    } else if (client_->ControlsTopOffset() <= -top_controls_hide_height) {
-      // If we're showing so little that the show threshold won't trigger, hide.
-      show_controls = HIDING_CONTROLS;
-    } else {
-      // If we could be either showing or hiding, we determine which one to
-      // do based on whether or not the total scroll delta was moving up or
-      // down.
-      show_controls = current_scroll_delta_ <= 0.f ?
-          SHOWING_CONTROLS : HIDING_CONTROLS;
-    }
-
-    if (show_controls != NO_ANIMATION)
-      SetupAnimation(show_controls);
+  if (TopControlsShownRatio() >= 1.f - top_controls_hide_threshold_) {
+    // If we're showing so much that the hide threshold won't trigger, show.
+    SetupAnimation(SHOWING_CONTROLS);
+  } else if (TopControlsShownRatio() <= top_controls_show_threshold_) {
+    // If we're showing so little that the show threshold won't trigger, hide.
+    SetupAnimation(HIDING_CONTROLS);
+  } else {
+    // If we could be either showing or hiding, we determine which one to
+    // do based on whether or not the total scroll delta was moving up or
+    // down.
+    SetupAnimation(current_scroll_delta_ <= 0.f ? SHOWING_CONTROLS
+                                                : HIDING_CONTROLS);
   }
 }
 
@@ -253,11 +216,10 @@
     return true;
 
   base::TimeDelta animation_time = time - base::TimeTicks();
-  float new_offset = top_controls_animation_->GetValue(animation_time);
+  float new_ratio = top_controls_animation_->GetValue(animation_time);
 
-  if ((animation_direction_ == SHOWING_CONTROLS && new_offset >= 0) ||
-      (animation_direction_ == HIDING_CONTROLS
-          && new_offset <= -top_controls_height_)) {
+  if ((animation_direction_ == SHOWING_CONTROLS && new_ratio >= 1.f) ||
+      (animation_direction_ == HIDING_CONTROLS && new_ratio <= 0.f)) {
     return true;
   }
   return false;
diff --git a/cc/input/top_controls_manager.h b/cc/input/top_controls_manager.h
index 69408ae..06f623d 100644
--- a/cc/input/top_controls_manager.h
+++ b/cc/input/top_controls_manager.h
@@ -38,8 +38,10 @@
       float top_controls_hide_threshold);
   virtual ~TopControlsManager();
 
-  float ControlsTopOffset();
-  float ContentTopOffset();
+  float ControlsTopOffset() const;
+  float ContentTopOffset() const;
+  float TopControlsShownRatio() const;
+  float TopControlsHeight() const;
 
   KeyframedFloatAnimationCurve* animation() {
     return top_controls_animation_.get();
@@ -60,9 +62,6 @@
   void PinchEnd();
 
   gfx::Vector2dF Animate(base::TimeTicks monotonic_time);
-  void SetControlsTopOffset(float offset);
-  void SetTopControlsHeight(float top_controls_height);
-  float top_controls_height() { return top_controls_height_; }
 
  protected:
   TopControlsManager(TopControlsManagerClient* client,
@@ -81,7 +80,6 @@
   scoped_ptr<KeyframedFloatAnimationCurve> top_controls_animation_;
   AnimationDirection animation_direction_;
   TopControlsState permitted_state_;
-  float top_controls_height_;
 
   float current_scroll_delta_;
   float controls_scroll_begin_offset_;
diff --git a/cc/input/top_controls_manager_client.h b/cc/input/top_controls_manager_client.h
index 53b5978..a0f2f5b 100644
--- a/cc/input/top_controls_manager_client.h
+++ b/cc/input/top_controls_manager_client.h
@@ -11,8 +11,9 @@
 
 class CC_EXPORT TopControlsManagerClient {
  public:
-  virtual void SetControlsTopOffset(float offset) = 0;
-  virtual float ControlsTopOffset() const = 0;
+  virtual float TopControlsHeight() const = 0;
+  virtual void SetCurrentTopControlsShownRatio(float ratio) = 0;
+  virtual float CurrentTopControlsShownRatio() const = 0;
   virtual void DidChangeTopControlsPosition() = 0;
   virtual bool HaveRootScrollLayer() const = 0;
 
diff --git a/cc/input/top_controls_manager_unittest.cc b/cc/input/top_controls_manager_unittest.cc
index 0be40ca..16d0e5d 100644
--- a/cc/input/top_controls_manager_unittest.cc
+++ b/cc/input/top_controls_manager_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "cc/input/top_controls_manager.h"
 
+#include <algorithm>
+
 #include "base/memory/scoped_ptr.h"
 #include "base/time/time.h"
 #include "cc/input/top_controls_manager_client.h"
@@ -27,13 +29,13 @@
       : host_impl_(&proxy_, &shared_bitmap_manager_),
         redraw_needed_(false),
         update_draw_properties_needed_(false),
-        top_controls_top_offset_(0.f),
+        top_controls_shown_ratio_(1.f),
         top_controls_height_(top_controls_height),
         top_controls_show_threshold_(top_controls_show_threshold),
         top_controls_hide_threshold_(top_controls_hide_threshold) {
-    active_tree_ =
-        LayerTreeImpl::create(&host_impl_, new SyncedProperty<ScaleGroup>,
-                              new SyncedElasticOverscroll);
+    active_tree_ = LayerTreeImpl::create(
+        &host_impl_, new SyncedProperty<ScaleGroup>, new SyncedTopControls,
+        new SyncedElasticOverscroll);
     root_scroll_layer_ = LayerImpl::Create(active_tree_.get(), 1);
   }
 
@@ -46,11 +48,17 @@
 
   bool HaveRootScrollLayer() const override { return true; }
 
-  void SetControlsTopOffset(float offset) override {
-    top_controls_top_offset_ = offset;
+  float TopControlsHeight() const override { return top_controls_height_; }
+
+  void SetCurrentTopControlsShownRatio(float ratio) override {
+    ratio = std::max(ratio, 0.f);
+    ratio = std::min(ratio, 1.f);
+    top_controls_shown_ratio_ = ratio;
   }
 
-  float ControlsTopOffset() const override { return top_controls_top_offset_; }
+  float CurrentTopControlsShownRatio() const override {
+    return top_controls_shown_ratio_;
+  }
 
   LayerImpl* rootScrollLayer() {
     return root_scroll_layer_.get();
@@ -61,11 +69,12 @@
       manager_ = TopControlsManager::Create(this,
                                             top_controls_show_threshold_,
                                             top_controls_hide_threshold_);
-      manager_->SetTopControlsHeight(top_controls_height_);
     }
     return manager_.get();
   }
 
+  void SetTopControlsHeight(float height) { top_controls_height_ = height; }
+
  private:
   FakeImplProxy proxy_;
   TestSharedBitmapManager shared_bitmap_manager_;
@@ -76,7 +85,7 @@
   bool redraw_needed_;
   bool update_draw_properties_needed_;
 
-  float top_controls_top_offset_;
+  float top_controls_shown_ratio_;
   float top_controls_height_;
   float top_controls_show_threshold_;
   float top_controls_hide_threshold_;
@@ -90,38 +99,38 @@
 
   // Scroll down to hide the controls entirely.
   manager->ScrollBy(gfx::Vector2dF(0.f, 30.f));
-  EXPECT_EQ(-30.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(-30.f, manager->ControlsTopOffset());
 
   manager->ScrollBy(gfx::Vector2dF(0.f, 30.f));
-  EXPECT_EQ(-60.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(-60.f, manager->ControlsTopOffset());
 
   manager->ScrollBy(gfx::Vector2dF(0.f, 100.f));
-  EXPECT_EQ(-100.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
 
   // Scroll back up a bit and ensure the controls don't move until we cross
   // the threshold.
   manager->ScrollBy(gfx::Vector2dF(0.f, -10.f));
-  EXPECT_EQ(-100.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
 
   manager->ScrollBy(gfx::Vector2dF(0.f, -50.f));
-  EXPECT_EQ(-100.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
 
   // After hitting the threshold, further scrolling up should result in the top
   // controls showing.
   manager->ScrollBy(gfx::Vector2dF(0.f, -10.f));
-  EXPECT_EQ(-90.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(-90.f, manager->ControlsTopOffset());
 
   manager->ScrollBy(gfx::Vector2dF(0.f, -50.f));
-  EXPECT_EQ(-40.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(-40.f, manager->ControlsTopOffset());
 
   // Reset the scroll threshold by going further up the page than the initial
   // threshold.
   manager->ScrollBy(gfx::Vector2dF(0.f, -100.f));
-  EXPECT_EQ(0.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
 
   // See that scrolling down the page now will result in the controls hiding.
   manager->ScrollBy(gfx::Vector2dF(0.f, 20.f));
-  EXPECT_EQ(-20.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(-20.f, manager->ControlsTopOffset());
 
   manager->ScrollEnd();
 }
@@ -131,29 +140,29 @@
   TopControlsManager* manager = client.manager();
   manager->ScrollBegin();
   manager->ScrollBy(gfx::Vector2dF(0.f, 300.f));
-  EXPECT_EQ(-100.f, manager->ControlsTopOffset());
-  EXPECT_EQ(0.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
   manager->ScrollEnd();
 
   manager->ScrollBegin();
   manager->ScrollBy(gfx::Vector2dF(0.f, -15.f));
-  EXPECT_EQ(-85.f, manager->ControlsTopOffset());
-  EXPECT_EQ(15.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-85.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(15.f, manager->ContentTopOffset());
   manager->ScrollEnd();
 
   EXPECT_TRUE(manager->animation());
 
   base::TimeTicks time = gfx::FrameTime::Now();
-  float previous_offset = manager->ControlsTopOffset();
+  float previous;
   while (manager->animation()) {
+    previous = manager->TopControlsShownRatio();
     time = base::TimeDelta::FromMicroseconds(100) + time;
     manager->Animate(time);
-    EXPECT_LT(manager->ControlsTopOffset(), previous_offset);
-    previous_offset = manager->ControlsTopOffset();
+    EXPECT_LT(manager->TopControlsShownRatio(), previous);
   }
   EXPECT_FALSE(manager->animation());
-  EXPECT_EQ(-100.f, manager->ControlsTopOffset());
-  EXPECT_EQ(0.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
 }
 
 TEST(TopControlsManagerTest, PartialShownShowAnimation) {
@@ -161,29 +170,29 @@
   TopControlsManager* manager = client.manager();
   manager->ScrollBegin();
   manager->ScrollBy(gfx::Vector2dF(0.f, 300.f));
-  EXPECT_EQ(-100.f, manager->ControlsTopOffset());
-  EXPECT_EQ(0.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
   manager->ScrollEnd();
 
   manager->ScrollBegin();
   manager->ScrollBy(gfx::Vector2dF(0.f, -70.f));
-  EXPECT_EQ(-30.f, manager->ControlsTopOffset());
-  EXPECT_EQ(70.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-30.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(70.f, manager->ContentTopOffset());
   manager->ScrollEnd();
 
   EXPECT_TRUE(manager->animation());
 
   base::TimeTicks time = gfx::FrameTime::Now();
-  float previous_offset = manager->ControlsTopOffset();
+  float previous;
   while (manager->animation()) {
+    previous = manager->TopControlsShownRatio();
     time = base::TimeDelta::FromMicroseconds(100) + time;
     manager->Animate(time);
-    EXPECT_GT(manager->ControlsTopOffset(), previous_offset);
-    previous_offset = manager->ControlsTopOffset();
+    EXPECT_GT(manager->TopControlsShownRatio(), previous);
   }
   EXPECT_FALSE(manager->animation());
-  EXPECT_EQ(0.f, manager->ControlsTopOffset());
-  EXPECT_EQ(100.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(100.f, manager->ContentTopOffset());
 }
 
 TEST(TopControlsManagerTest, PartialHiddenWithAmbiguousThresholdShows) {
@@ -193,23 +202,23 @@
   manager->ScrollBegin();
 
   manager->ScrollBy(gfx::Vector2dF(0.f, 20.f));
-  EXPECT_EQ(-20.f, manager->ControlsTopOffset());
-  EXPECT_EQ(80.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-20.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(80.f, manager->ContentTopOffset());
 
   manager->ScrollEnd();
   EXPECT_TRUE(manager->animation());
 
   base::TimeTicks time = gfx::FrameTime::Now();
-  float previous_offset = manager->ControlsTopOffset();
+  float previous;
   while (manager->animation()) {
+    previous = manager->TopControlsShownRatio();
     time = base::TimeDelta::FromMicroseconds(100) + time;
     manager->Animate(time);
-    EXPECT_GT(manager->ControlsTopOffset(), previous_offset);
-    previous_offset = manager->ControlsTopOffset();
+    EXPECT_GT(manager->TopControlsShownRatio(), previous);
   }
   EXPECT_FALSE(manager->animation());
-  EXPECT_EQ(0.f, manager->ControlsTopOffset());
-  EXPECT_EQ(100.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(100.f, manager->ContentTopOffset());
 }
 
 TEST(TopControlsManagerTest, PartialHiddenWithAmbiguousThresholdHides) {
@@ -219,23 +228,23 @@
   manager->ScrollBegin();
 
   manager->ScrollBy(gfx::Vector2dF(0.f, 30.f));
-  EXPECT_EQ(-30.f, manager->ControlsTopOffset());
-  EXPECT_EQ(70.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-30.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(70.f, manager->ContentTopOffset());
 
   manager->ScrollEnd();
   EXPECT_TRUE(manager->animation());
 
   base::TimeTicks time = gfx::FrameTime::Now();
-  float previous_offset = manager->ControlsTopOffset();
+  float previous;
   while (manager->animation()) {
+    previous = manager->TopControlsShownRatio();
     time = base::TimeDelta::FromMicroseconds(100) + time;
     manager->Animate(time);
-    EXPECT_LT(manager->ControlsTopOffset(), previous_offset);
-    previous_offset = manager->ControlsTopOffset();
+    EXPECT_LT(manager->TopControlsShownRatio(), previous);
   }
   EXPECT_FALSE(manager->animation());
-  EXPECT_EQ(-100.f, manager->ControlsTopOffset());
-  EXPECT_EQ(0.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
 }
 
 TEST(TopControlsManagerTest, PartialShownWithAmbiguousThresholdHides) {
@@ -243,29 +252,29 @@
   TopControlsManager* manager = client.manager();
 
   manager->ScrollBy(gfx::Vector2dF(0.f, 200.f));
-  EXPECT_EQ(-100.f, manager->ControlsTopOffset());
-  EXPECT_EQ(0.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
 
   manager->ScrollBegin();
 
   manager->ScrollBy(gfx::Vector2dF(0.f, -20.f));
-  EXPECT_EQ(-80.f, manager->ControlsTopOffset());
-  EXPECT_EQ(20.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-80.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(20.f, manager->ContentTopOffset());
 
   manager->ScrollEnd();
   EXPECT_TRUE(manager->animation());
 
   base::TimeTicks time = gfx::FrameTime::Now();
-  float previous_offset = manager->ControlsTopOffset();
+  float previous;
   while (manager->animation()) {
+    previous = manager->TopControlsShownRatio();
     time = base::TimeDelta::FromMicroseconds(100) + time;
     manager->Animate(time);
-    EXPECT_LT(manager->ControlsTopOffset(), previous_offset);
-    previous_offset = manager->ControlsTopOffset();
+    EXPECT_LT(manager->TopControlsShownRatio(), previous);
   }
   EXPECT_FALSE(manager->animation());
-  EXPECT_EQ(-100.f, manager->ControlsTopOffset());
-  EXPECT_EQ(0.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
 }
 
 TEST(TopControlsManagerTest, PartialShownWithAmbiguousThresholdShows) {
@@ -273,29 +282,29 @@
   TopControlsManager* manager = client.manager();
 
   manager->ScrollBy(gfx::Vector2dF(0.f, 200.f));
-  EXPECT_EQ(-100.f, manager->ControlsTopOffset());
-  EXPECT_EQ(0.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
 
   manager->ScrollBegin();
 
   manager->ScrollBy(gfx::Vector2dF(0.f, -30.f));
-  EXPECT_EQ(-70.f, manager->ControlsTopOffset());
-  EXPECT_EQ(30.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-70.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(30.f, manager->ContentTopOffset());
 
   manager->ScrollEnd();
   EXPECT_TRUE(manager->animation());
 
   base::TimeTicks time = gfx::FrameTime::Now();
-  float previous_offset = manager->ControlsTopOffset();
+  float previous;
   while (manager->animation()) {
+    previous = manager->TopControlsShownRatio();
     time = base::TimeDelta::FromMicroseconds(100) + time;
     manager->Animate(time);
-    EXPECT_GT(manager->ControlsTopOffset(), previous_offset);
-    previous_offset = manager->ControlsTopOffset();
+    EXPECT_GT(manager->TopControlsShownRatio(), previous);
   }
   EXPECT_FALSE(manager->animation());
-  EXPECT_EQ(0.f, manager->ControlsTopOffset());
-  EXPECT_EQ(100.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(100.f, manager->ContentTopOffset());
 }
 
 TEST(TopControlsManagerTest, PinchIgnoresScroll) {
@@ -304,24 +313,24 @@
 
   // Hide the controls.
   manager->ScrollBegin();
-  EXPECT_EQ(0.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
 
   manager->ScrollBy(gfx::Vector2dF(0.f, 300.f));
-  EXPECT_EQ(-100.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
 
   manager->PinchBegin();
-  EXPECT_EQ(-100.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
 
   // Scrolls are ignored during pinch.
   manager->ScrollBy(gfx::Vector2dF(0.f, -15.f));
-  EXPECT_EQ(-100.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
   manager->PinchEnd();
-  EXPECT_EQ(-100.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
 
   // Scrolls should no long be ignored.
   manager->ScrollBy(gfx::Vector2dF(0.f, -15.f));
-  EXPECT_EQ(-85.f, manager->ControlsTopOffset());
-  EXPECT_EQ(15.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-85.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(15.f, manager->ContentTopOffset());
   manager->ScrollEnd();
 
   EXPECT_TRUE(manager->animation());
@@ -333,7 +342,7 @@
 
   manager->ScrollBegin();
   manager->ScrollBy(gfx::Vector2dF(0.f, 300.f));
-  EXPECT_EQ(-100.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
 
   manager->PinchBegin();
   EXPECT_FALSE(manager->animation());
@@ -342,19 +351,19 @@
   EXPECT_FALSE(manager->animation());
 
   manager->ScrollBy(gfx::Vector2dF(0.f, -15.f));
-  EXPECT_EQ(-85.f, manager->ControlsTopOffset());
-  EXPECT_EQ(15.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-85.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(15.f, manager->ContentTopOffset());
 
   manager->PinchBegin();
   EXPECT_TRUE(manager->animation());
 
   base::TimeTicks time = base::TimeTicks::Now();
-  float previous_offset = manager->ControlsTopOffset();
+  float previous;
   while (manager->animation()) {
+    previous = manager->TopControlsShownRatio();
     time = base::TimeDelta::FromMicroseconds(100) + time;
     manager->Animate(time);
-    EXPECT_LT(manager->ControlsTopOffset(), previous_offset);
-    previous_offset = manager->ControlsTopOffset();
+    EXPECT_LT(manager->TopControlsShownRatio(), previous);
   }
   EXPECT_FALSE(manager->animation());
 
@@ -362,41 +371,57 @@
   EXPECT_FALSE(manager->animation());
 
   manager->ScrollBy(gfx::Vector2dF(0.f, -55.f));
-  EXPECT_EQ(-45.f, manager->ControlsTopOffset());
-  EXPECT_EQ(55.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-45.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(55.f, manager->ContentTopOffset());
   EXPECT_FALSE(manager->animation());
 
   manager->ScrollEnd();
   EXPECT_TRUE(manager->animation());
 
   time = base::TimeTicks::Now();
-  previous_offset = manager->ControlsTopOffset();
   while (manager->animation()) {
+    previous = manager->TopControlsShownRatio();
     time = base::TimeDelta::FromMicroseconds(100) + time;
     manager->Animate(time);
-    EXPECT_GT(manager->ControlsTopOffset(), previous_offset);
-    previous_offset = manager->ControlsTopOffset();
+    EXPECT_GT(manager->TopControlsShownRatio(), previous);
   }
   EXPECT_FALSE(manager->animation());
-  EXPECT_EQ(0.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
 }
 
 TEST(TopControlsManagerTest, HeightChangeMaintainsFullyVisibleControls) {
   MockTopControlsManagerClient client(0.f, 0.5f, 0.5f);
   TopControlsManager* manager = client.manager();
 
-  EXPECT_EQ(0.f, manager->top_controls_height());
-  EXPECT_EQ(0.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
 
-  manager->SetTopControlsHeight(100.f);
+  client.SetTopControlsHeight(100.f);
   EXPECT_FALSE(manager->animation());
-  EXPECT_EQ(100.f, manager->top_controls_height());
-  EXPECT_EQ(0, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(100.f, manager->TopControlsHeight());
+  EXPECT_FLOAT_EQ(0, manager->ControlsTopOffset());
 
-  manager->SetTopControlsHeight(50.f);
+  client.SetTopControlsHeight(50.f);
   EXPECT_FALSE(manager->animation());
-  EXPECT_EQ(50.f, manager->top_controls_height());
+  EXPECT_FLOAT_EQ(50.f, manager->TopControlsHeight());
+  EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
+}
+
+TEST(TopControlsManagerTest, GrowingHeightKeepsTopControlsHidden) {
+  MockTopControlsManagerClient client(0.f, 0.5f, 0.5f);
+  TopControlsManager* manager = client.manager();
+  manager->UpdateTopControlsState(HIDDEN, HIDDEN, false);
   EXPECT_EQ(0.f, manager->ControlsTopOffset());
+  EXPECT_EQ(0.f, manager->ContentTopOffset());
+
+  client.SetTopControlsHeight(50.f);
+  EXPECT_FALSE(manager->animation());
+  EXPECT_EQ(-50.f, manager->ControlsTopOffset());
+  EXPECT_EQ(0.f, manager->ContentTopOffset());
+
+  client.SetTopControlsHeight(100.f);
+  EXPECT_FALSE(manager->animation());
+  EXPECT_EQ(-100.f, manager->ControlsTopOffset());
+  EXPECT_EQ(0.f, manager->ContentTopOffset());
 }
 
 TEST(TopControlsManagerTest, ShrinkingHeightKeepsTopControlsHidden) {
@@ -405,56 +430,20 @@
 
   manager->ScrollBegin();
   manager->ScrollBy(gfx::Vector2dF(0.f, 300.f));
-  EXPECT_EQ(-100.f, manager->ControlsTopOffset());
-  EXPECT_EQ(0.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-100.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
   manager->ScrollEnd();
 
-  manager->SetTopControlsHeight(50.f);
+  client.SetTopControlsHeight(50.f);
   EXPECT_FALSE(manager->animation());
-  EXPECT_EQ(-50.f, manager->ControlsTopOffset());
-  EXPECT_EQ(0.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-50.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
 
-  manager->SetTopControlsHeight(0.f);
+  client.SetTopControlsHeight(0.f);
   EXPECT_FALSE(manager->animation());
-  EXPECT_EQ(0.f, manager->ControlsTopOffset());
-  EXPECT_EQ(0.f, manager->ContentTopOffset());
+  EXPECT_FLOAT_EQ(0.f, manager->ControlsTopOffset());
+  EXPECT_FLOAT_EQ(0.f, manager->ContentTopOffset());
 }
 
-TEST(TopControlsManagerTest, HiddenTopControlsReadjustOnIncreasedHeight) {
-  MockTopControlsManagerClient client(10.f, 0.5f, 0.5f);
-  TopControlsManager* manager = client.manager();
-
-  manager->ScrollBegin();
-  manager->ScrollBy(gfx::Vector2dF(0.f, 300.f));
-  EXPECT_EQ(-10.f, manager->ControlsTopOffset());
-  EXPECT_EQ(0.f, manager->ContentTopOffset());
-  manager->ScrollEnd();
-
-  manager->SetTopControlsHeight(15.f);
-  EXPECT_TRUE(manager->animation());
-  base::TimeTicks time = base::TimeTicks::Now();
-  float previous_offset = manager->ControlsTopOffset();
-  while (manager->animation()) {
-    time = base::TimeDelta::FromMicroseconds(100) + time;
-    manager->Animate(time);
-    EXPECT_LT(manager->ControlsTopOffset(), previous_offset);
-    previous_offset = manager->ControlsTopOffset();
-  }
-  EXPECT_FALSE(manager->animation());
-  EXPECT_EQ(-15.f, manager->ControlsTopOffset());
-
-  manager->SetTopControlsHeight(35.f);
-  EXPECT_TRUE(manager->animation());
-  time = base::TimeTicks::Now();
-  previous_offset = manager->ControlsTopOffset();
-  while (manager->animation()) {
-    time = base::TimeDelta::FromMicroseconds(100) + time;
-    manager->Animate(time);
-    EXPECT_GT(manager->ControlsTopOffset(), previous_offset);
-    previous_offset = manager->ControlsTopOffset();
-  }
-  EXPECT_FALSE(manager->animation());
-  EXPECT_EQ(0.f, manager->ControlsTopOffset());
-}
 }  // namespace
 }  // namespace cc
diff --git a/cc/layers/delegated_renderer_layer_impl.cc b/cc/layers/delegated_renderer_layer_impl.cc
index 8a95b9e..e1056be 100644
--- a/cc/layers/delegated_renderer_layer_impl.cc
+++ b/cc/layers/delegated_renderer_layer_impl.cc
@@ -255,7 +255,6 @@
 
 void DelegatedRendererLayerImpl::AppendQuads(
     RenderPass* render_pass,
-    const Occlusion& occlusion_in_content_space,
     AppendQuadsData* append_quads_data) {
   AppendRainbowDebugBorder(render_pass);
 
@@ -282,7 +281,6 @@
     DCHECK(target_render_pass_id.layer_id == render_target()->id());
 
     AppendRenderPassQuads(render_pass,
-                          occlusion_in_content_space,
                           root_delegated_render_pass,
                           frame_size);
   } else {
@@ -293,7 +291,6 @@
     const RenderPass* delegated_render_pass =
         render_passes_in_draw_order_[render_pass_index];
     AppendRenderPassQuads(render_pass,
-                          occlusion_in_content_space,
                           delegated_render_pass,
                           frame_size);
   }
@@ -349,39 +346,52 @@
       break;
 
     if (!top.IsEmpty()) {
+      bool force_anti_aliasing_off = false;
       SolidColorDrawQuad* top_quad =
           render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
-      top_quad->SetNew(
-          shared_quad_state, top, top, colors[i % kNumColors], false);
+      top_quad->SetNew(shared_quad_state, top, top, colors[i % kNumColors],
+                       force_anti_aliasing_off);
 
       SolidColorDrawQuad* bottom_quad =
           render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
-      bottom_quad->SetNew(shared_quad_state,
-                          bottom,
-                          bottom,
+      bottom_quad->SetNew(shared_quad_state, bottom, bottom,
                           colors[kNumColors - 1 - (i % kNumColors)],
-                          false);
+                          force_anti_aliasing_off);
+
+      if (contents_opaque()) {
+        // Draws a stripe filling the layer vertically with the same color and
+        // width as the horizontal stipes along the layer's top border.
+        SolidColorDrawQuad* solid_quad =
+            render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+        // The inner fill is more transparent then the border.
+        static const float kFillOpacity = 0.1f;
+        SkColor fill_color = SkColorSetA(
+            colors[i % kNumColors],
+            static_cast<uint8_t>(SkColorGetA(colors[i % kNumColors]) *
+                                 kFillOpacity));
+        gfx::Rect fill_rect(x, 0, width, content_bounds().height());
+        solid_quad->SetNew(shared_quad_state, fill_rect, fill_rect, fill_color,
+                           force_anti_aliasing_off);
+      }
     }
     if (!left.IsEmpty()) {
+      bool force_anti_aliasing_off = false;
       SolidColorDrawQuad* left_quad =
           render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
-      left_quad->SetNew(shared_quad_state,
-                        left,
-                        left,
+      left_quad->SetNew(shared_quad_state, left, left,
                         colors[kNumColors - 1 - (i % kNumColors)],
-                        false);
+                        force_anti_aliasing_off);
 
       SolidColorDrawQuad* right_quad =
           render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
-      right_quad->SetNew(
-          shared_quad_state, right, right, colors[i % kNumColors], false);
+      right_quad->SetNew(shared_quad_state, right, right,
+                         colors[i % kNumColors], force_anti_aliasing_off);
     }
   }
 }
 
 void DelegatedRendererLayerImpl::AppendRenderPassQuads(
     RenderPass* render_pass,
-    const Occlusion& occlusion_in_content_space,
     const RenderPass* delegated_render_pass,
     const gfx::Size& frame_size) const {
   const SharedQuadState* delegated_shared_quad_state = nullptr;
@@ -437,8 +447,9 @@
     }
 
     Occlusion occlusion_in_quad_space =
-        occlusion_in_content_space.GetOcclusionWithGivenDrawTransform(
-            quad_content_to_delegated_target_space);
+        draw_properties()
+            .occlusion_in_content_space.GetOcclusionWithGivenDrawTransform(
+                quad_content_to_delegated_target_space);
 
     gfx::Rect quad_visible_rect =
         occlusion_in_quad_space.GetUnoccludedContentRect(
diff --git a/cc/layers/delegated_renderer_layer_impl.h b/cc/layers/delegated_renderer_layer_impl.h
index 1ae3228..4a61ba1 100644
--- a/cc/layers/delegated_renderer_layer_impl.h
+++ b/cc/layers/delegated_renderer_layer_impl.h
@@ -34,7 +34,6 @@
   bool WillDraw(DrawMode draw_mode,
                 ResourceProvider* resource_provider) override;
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override;
   void PushPropertiesTo(LayerImpl* layer) override;
 
@@ -77,7 +76,6 @@
                                     RenderPassId* output_render_pass_id) const;
 
   void AppendRenderPassQuads(RenderPass* render_pass,
-                             const Occlusion& occlusion_in_content_space,
                              const RenderPass* delegated_render_pass,
                              const gfx::Size& frame_size) const;
 
diff --git a/cc/layers/draw_properties.h b/cc/layers/draw_properties.h
index 5c78000..7cf89e7 100644
--- a/cc/layers/draw_properties.h
+++ b/cc/layers/draw_properties.h
@@ -6,6 +6,7 @@
 #define CC_LAYERS_DRAW_PROPERTIES_H_
 
 #include "base/memory/scoped_ptr.h"
+#include "cc/trees/occlusion.h"
 #include "third_party/skia/include/core/SkXfermode.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/transform.h"
@@ -50,6 +51,9 @@
   // Transforms objects from content space to screen space (viewport space).
   gfx::Transform screen_space_transform;
 
+  // Known occlusion above the layer mapped to the content space of the layer.
+  Occlusion occlusion_in_content_space;
+
   // DrawProperties::opacity may be different than LayerType::opacity,
   // particularly in the case when a RenderSurface re-parents the layer's
   // opacity, or when opacity is compounded by the hierarchy.
diff --git a/cc/layers/heads_up_display_layer.h b/cc/layers/heads_up_display_layer.h
index 7ca0992..ddc34f2 100644
--- a/cc/layers/heads_up_display_layer.h
+++ b/cc/layers/heads_up_display_layer.h
@@ -9,11 +9,11 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "cc/base/cc_export.h"
-#include "cc/layers/contents_scaling_layer.h"
+#include "cc/layers/layer.h"
 
 namespace cc {
 
-class CC_EXPORT HeadsUpDisplayLayer : public ContentsScalingLayer {
+class CC_EXPORT HeadsUpDisplayLayer : public Layer {
  public:
   static scoped_refptr<HeadsUpDisplayLayer> Create();
 
diff --git a/cc/layers/heads_up_display_layer_impl.cc b/cc/layers/heads_up_display_layer_impl.cc
index 60d984b..97fddae 100644
--- a/cc/layers/heads_up_display_layer_impl.cc
+++ b/cc/layers/heads_up_display_layer_impl.cc
@@ -28,6 +28,7 @@
 #include "third_party/skia/include/effects/SkColorMatrixFilter.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/size_conversions.h"
 
 namespace cc {
 
@@ -69,6 +70,7 @@
 HeadsUpDisplayLayerImpl::HeadsUpDisplayLayerImpl(LayerTreeImpl* tree_impl,
                                                  int id)
     : LayerImpl(tree_impl, id),
+      internal_contents_scale_(1.f),
       fps_graph_(60.0, 80.0),
       paint_time_graph_(16.0, 48.0),
       fade_step_(0) {
@@ -94,8 +96,8 @@
 
   scoped_ptr<ScopedResource> resource =
       ScopedResource::Create(resource_provider);
-  resource->Allocate(
-      content_bounds(), ResourceProvider::TextureHintImmutable, RGBA_8888);
+  resource->Allocate(internal_content_bounds_,
+                     ResourceProvider::TextureHintImmutable, RGBA_8888);
   resources_.push_back(resource.Pass());
 }
 
@@ -115,7 +117,7 @@
 void HeadsUpDisplayLayerImpl::ReleaseUnmatchedSizeResources(
     ResourceProvider* resource_provider) {
   ScopedPtrVector<ScopedResource>::iterator it_erase =
-      resources_.partition(ResourceSizeIsEqualTo(content_bounds()));
+      resources_.partition(ResourceSizeIsEqualTo(internal_content_bounds_));
   resources_.erase(it_erase, resources_.end());
 }
 
@@ -124,6 +126,10 @@
   if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
     return false;
 
+  internal_contents_scale_ = draw_properties().ideal_contents_scale;
+  internal_content_bounds_ =
+      gfx::ToCeiledSize(gfx::ScaleSize(bounds(), internal_contents_scale_));
+
   ReleaseUnmatchedSizeResources(resource_provider);
   AcquireResource(resource_provider);
   return LayerImpl::WillDraw(draw_mode, resource_provider);
@@ -131,16 +137,15 @@
 
 void HeadsUpDisplayLayerImpl::AppendQuads(
     RenderPass* render_pass,
-    const Occlusion& occlusion_in_content_space,
     AppendQuadsData* append_quads_data) {
   if (!resources_.back()->id())
     return;
 
   SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
-  PopulateSharedQuadState(shared_quad_state);
+  PopulateScaledSharedQuadState(shared_quad_state, internal_contents_scale_);
 
-  gfx::Rect quad_rect(content_bounds());
+  gfx::Rect quad_rect(internal_content_bounds_);
   gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect());
   gfx::Rect visible_quad_rect(quad_rect);
   bool premultiplied_alpha = true;
@@ -177,12 +182,13 @@
   else
     canvas_size.set(0, 0);
 
-  if (canvas_size.width() != content_bounds().width() ||
-      canvas_size.height() != content_bounds().height() || !hud_surface_) {
+  if (canvas_size.width() != internal_content_bounds_.width() ||
+      canvas_size.height() != internal_content_bounds_.height() ||
+      !hud_surface_) {
     TRACE_EVENT0("cc", "ResizeHudCanvas");
 
     hud_surface_ = skia::AdoptRef(SkSurface::NewRasterN32Premul(
-        content_bounds().width(), content_bounds().height()));
+        internal_content_bounds_.width(), internal_content_bounds_.height()));
   }
 
   UpdateHudContents();
@@ -191,7 +197,8 @@
     TRACE_EVENT0("cc", "DrawHudContents");
     hud_surface_->getCanvas()->clear(SkColorSetARGB(0, 0, 0, 0));
     hud_surface_->getCanvas()->save();
-    hud_surface_->getCanvas()->scale(contents_scale_x(), contents_scale_y());
+    hud_surface_->getCanvas()->scale(internal_contents_scale_,
+                                     internal_contents_scale_);
 
     DrawHudContents(hud_surface_->getCanvas());
 
@@ -203,7 +210,7 @@
   size_t row_bytes = 0;
   const void* pixels = hud_surface_->getCanvas()->peekPixels(&info, &row_bytes);
   DCHECK(pixels);
-  gfx::Rect content_rect(content_bounds());
+  gfx::Rect content_rect(internal_content_bounds_);
   DCHECK(info.colorType() == kN32_SkColorType);
   resource_provider->SetPixels(resources_.back()->id(),
                                static_cast<const uint8_t*>(pixels),
@@ -677,8 +684,9 @@
     SkColor fill_color,
     float stroke_width,
     const std::string& label_text) const {
-  gfx::Rect debug_layer_rect = gfx::ScaleToEnclosingRect(
-      rect.rect, 1.0 / contents_scale_x(), 1.0 / contents_scale_y());
+  gfx::Rect debug_layer_rect =
+      gfx::ScaleToEnclosingRect(rect.rect, 1.0 / internal_contents_scale_,
+                                1.0 / internal_contents_scale_);
   SkIRect sk_rect = RectToSkIRect(debug_layer_rect);
   paint->setColor(fill_color);
   paint->setStyle(SkPaint::kFill_Style);
@@ -696,7 +704,7 @@
     // The debug_layer_rect may be huge, and converting to a floating point may
     // be lossy, so intersect with the HUD layer bounds first to prevent that.
     gfx::Rect clip_rect = debug_layer_rect;
-    clip_rect.Intersect(gfx::Rect(content_bounds()));
+    clip_rect.Intersect(gfx::Rect(internal_content_bounds_));
     SkRect sk_clip_rect = RectToSkRect(clip_rect);
 
     canvas->save();
@@ -764,16 +772,6 @@
         fill_color = DebugColors::ScreenSpaceLayerRectFillColor();
         stroke_width = DebugColors::ScreenSpaceLayerRectBorderWidth();
         break;
-      case OCCLUDING_RECT_TYPE:
-        stroke_color = DebugColors::OccludingRectBorderColor();
-        fill_color = DebugColors::OccludingRectFillColor();
-        stroke_width = DebugColors::OccludingRectBorderWidth();
-        break;
-      case NONOCCLUDING_RECT_TYPE:
-        stroke_color = DebugColors::NonOccludingRectBorderColor();
-        fill_color = DebugColors::NonOccludingRectFillColor();
-        stroke_width = DebugColors::NonOccludingRectBorderWidth();
-        break;
       case TOUCH_EVENT_HANDLER_RECT_TYPE:
         stroke_color = DebugColors::TouchEventHandlerRectBorderColor();
         fill_color = DebugColors::TouchEventHandlerRectFillColor();
@@ -838,7 +836,7 @@
 }
 
 void HeadsUpDisplayLayerImpl::AsValueInto(
-    base::debug::TracedValue* dict) const {
+    base::trace_event::TracedValue* dict) const {
   LayerImpl::AsValueInto(dict);
   dict->SetString("layer_name", "Heads Up Display Layer");
 }
diff --git a/cc/layers/heads_up_display_layer_impl.h b/cc/layers/heads_up_display_layer_impl.h
index abba5dc..5c3720e 100644
--- a/cc/layers/heads_up_display_layer_impl.h
+++ b/cc/layers/heads_up_display_layer_impl.h
@@ -39,7 +39,6 @@
   bool WillDraw(DrawMode draw_mode,
                 ResourceProvider* resource_provider) override;
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override;
   void UpdateHudTexture(DrawMode draw_mode,
                         ResourceProvider* resource_provider);
@@ -71,7 +70,7 @@
 
   const char* LayerTypeAsString() const override;
 
-  void AsValueInto(base::debug::TracedValue* dict) const override;
+  void AsValueInto(base::trace_event::TracedValue* dict) const override;
 
   void UpdateHudContents();
   void DrawHudContents(SkCanvas* canvas);
@@ -128,6 +127,9 @@
   ScopedPtrVector<ScopedResource> resources_;
   skia::RefPtr<SkSurface> hud_surface_;
 
+  float internal_contents_scale_;
+  gfx::Size internal_content_bounds_;
+
   Graph fps_graph_;
   Graph paint_time_graph_;
   MemoryHistory::Entry memory_entry_;
diff --git a/cc/layers/heads_up_display_layer_impl_unittest.cc b/cc/layers/heads_up_display_layer_impl_unittest.cc
index d342d4f..4b07323 100644
--- a/cc/layers/heads_up_display_layer_impl_unittest.cc
+++ b/cc/layers/heads_up_display_layer_impl_unittest.cc
@@ -20,7 +20,7 @@
   AppendQuadsData data;
   bool will_draw = layer->WillDraw(draw_mode, resource_provider);
   if (will_draw)
-    layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+    layer->AppendQuads(render_pass.get(), &data);
   layer->UpdateHudTexture(draw_mode, resource_provider);
   if (will_draw)
     layer->DidDraw(resource_provider);
@@ -37,7 +37,8 @@
   host_impl.InitializeRenderer(FakeOutputSurface::Create3d());
   scoped_ptr<HeadsUpDisplayLayerImpl> layer =
     HeadsUpDisplayLayerImpl::Create(host_impl.pending_tree(), 1);
-  layer->SetContentBounds(gfx::Size(100, 100));
+  layer->SetBounds(gfx::Size(100, 100));
+  layer->draw_properties().ideal_contents_scale = 1.f;
 
   // Check regular hardware draw is ok.
   CheckDrawLayer(
diff --git a/cc/layers/io_surface_layer_impl.cc b/cc/layers/io_surface_layer_impl.cc
index 8d22195..6bd03fd 100644
--- a/cc/layers/io_surface_layer_impl.cc
+++ b/cc/layers/io_surface_layer_impl.cc
@@ -66,7 +66,6 @@
 
 void IOSurfaceLayerImpl::AppendQuads(
     RenderPass* render_pass,
-    const Occlusion& occlusion_in_content_space,
     AppendQuadsData* append_quads_data) {
   SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
@@ -78,7 +77,8 @@
   gfx::Rect quad_rect(content_bounds());
   gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect());
   gfx::Rect visible_quad_rect =
-      occlusion_in_content_space.GetUnoccludedContentRect(quad_rect);
+      draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+          quad_rect);
   if (visible_quad_rect.IsEmpty())
     return;
 
diff --git a/cc/layers/io_surface_layer_impl.h b/cc/layers/io_surface_layer_impl.h
index 663bcef..8317760 100644
--- a/cc/layers/io_surface_layer_impl.h
+++ b/cc/layers/io_surface_layer_impl.h
@@ -27,7 +27,6 @@
   void PushPropertiesTo(LayerImpl* layer_tree_impl) override;
 
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override;
 
   bool WillDraw(DrawMode draw_mode,
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 01e67c5..19b505b 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -1108,7 +1108,8 @@
   return true;
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat> Layer::TakeDebugInfo() {
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+Layer::TakeDebugInfo() {
   if (client_)
     return client_->TakeDebugInfo();
   else
@@ -1298,13 +1299,24 @@
 
 gfx::Transform Layer::draw_transform_from_property_trees(
     const TransformTree& tree) const {
-  gfx::Transform xform(1, 0, 0, 1, offset_to_transform_parent().x(),
-                       offset_to_transform_parent().y());
-  if (transform_tree_index() >= 0) {
-    const TransformNode* node = tree.Node(transform_tree_index());
-    gfx::Transform ssxform;
-    tree.ComputeTransform(node->id, node->data.target_id, &ssxform);
-    xform.ConcatTransform(ssxform);
+  const TransformNode* node = tree.Node(transform_tree_index());
+  // TODO(vollick): ultimately we'll need to find this information (whether or
+  // not we establish a render surface) somewhere other than the layer.
+  const TransformNode* target_node =
+      has_render_surface_ ? node : tree.Node(node->data.content_target_id);
+
+  gfx::Transform xform;
+  const bool owns_non_root_surface = parent() && render_surface();
+  if (!owns_non_root_surface) {
+    // If you're not the root, or you don't own a surface, you need to apply
+    // your local offset.
+    xform = node->data.to_target;
+    xform.Translate(offset_to_transform_parent().x(),
+                    offset_to_transform_parent().y());
+  } else {
+    // Surfaces need to apply their sublayer scale.
+    xform.Scale(target_node->data.sublayer_scale.x(),
+                target_node->data.sublayer_scale.y());
   }
   xform.Scale(1.0 / contents_scale_x(), 1.0 / contents_scale_y());
   return xform;
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index cf1356c..873f360 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -47,13 +47,7 @@
 namespace trace_event {
 class ConvertableToTraceFormat;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::ConvertableToTraceFormat;
 }
-}  // namespace base
 
 namespace cc {
 
@@ -383,7 +377,8 @@
   virtual void OnOutputSurfaceCreated() {}
   virtual bool IsSuitableForGpuRasterization() const;
 
-  virtual scoped_refptr<base::debug::ConvertableToTraceFormat> TakeDebugInfo();
+  virtual scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+  TakeDebugInfo();
 
   void SetLayerClient(LayerClient* client) { client_ = client; }
 
diff --git a/cc/layers/layer_client.h b/cc/layers/layer_client.h
index efdbe51..bcdf1c3 100644
--- a/cc/layers/layer_client.h
+++ b/cc/layers/layer_client.h
@@ -14,13 +14,7 @@
 namespace trace_event {
 class ConvertableToTraceFormat;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::ConvertableToTraceFormat;
 }
-}  // namespace base
 
 namespace cc {
 
@@ -30,7 +24,7 @@
   // If not, returns nullptr.
   // If the returned pointer is non-nullptr, the caller takes
   // ownership of the pointer.
-  virtual scoped_refptr<base::debug::ConvertableToTraceFormat>
+  virtual scoped_refptr<base::trace_event::ConvertableToTraceFormat>
       TakeDebugInfo() = 0;
 
  protected:
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index eae3685..6e11644 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -175,7 +175,7 @@
 }
 
 void LayerImpl::SetDebugInfo(
-    scoped_refptr<base::debug::ConvertableToTraceFormat> other) {
+    scoped_refptr<base::trace_event::ConvertableToTraceFormat> other) {
   debug_info_ = other;
   SetNeedsPushProperties();
 }
@@ -261,6 +261,23 @@
       draw_properties_.blend_mode, sorting_context_id_);
 }
 
+void LayerImpl::PopulateScaledSharedQuadState(SharedQuadState* state,
+                                              float scale) const {
+  gfx::Transform scaled_draw_transform =
+      draw_properties_.target_space_transform;
+  scaled_draw_transform.Scale(SK_MScalar1 / scale, SK_MScalar1 / scale);
+  gfx::Size scaled_content_bounds =
+      gfx::ToCeiledSize(gfx::ScaleSize(bounds(), scale));
+  gfx::Rect scaled_visible_content_rect =
+      gfx::ScaleToEnclosingRect(visible_content_rect(), scale);
+  scaled_visible_content_rect.Intersect(gfx::Rect(scaled_content_bounds));
+
+  state->SetAll(scaled_draw_transform, scaled_content_bounds,
+                scaled_visible_content_rect, draw_properties().clip_rect,
+                draw_properties().is_clipped, draw_properties().opacity,
+                draw_properties().blend_mode, sorting_context_id_);
+}
+
 bool LayerImpl::WillDraw(DrawMode draw_mode,
                          ResourceProvider* resource_provider) {
   // WillDraw/DidDraw must be matched.
@@ -327,6 +344,22 @@
       render_pass->CreateAndAppendDrawQuad<DebugBorderDrawQuad>();
   debug_border_quad->SetNew(
       shared_quad_state, quad_rect, visible_quad_rect, color, width);
+  if (contents_opaque()) {
+    // When opaque, draw a second inner border that is thicker than the outer
+    // border, but more transparent.
+    static const float kFillOpacity = 0.3f;
+    SkColor fill_color = SkColorSetA(
+        color, static_cast<uint8_t>(SkColorGetA(color) * kFillOpacity));
+    float fill_width = width * 3;
+    gfx::Rect fill_rect = quad_rect;
+    fill_rect.Inset(fill_width / 2.f, fill_width / 2.f);
+    gfx::Rect visible_fill_rect =
+        gfx::IntersectRects(visible_quad_rect, fill_rect);
+    DebugBorderDrawQuad* fill_quad =
+        render_pass->CreateAndAppendDrawQuad<DebugBorderDrawQuad>();
+    fill_quad->SetNew(shared_quad_state, fill_rect, visible_fill_rect,
+                      fill_color, fill_width);
+  }
 }
 
 bool LayerImpl::HasDelegatedContent() const {
@@ -345,11 +378,6 @@
   return RenderPassId(0, 0);
 }
 
-bool LayerImpl::UpdateTiles(const Occlusion& occlusion_in_layer_space,
-                            bool resourceless_software_draw) {
-  return false;
-}
-
 void LayerImpl::GetContentsResourceId(ResourceProvider::ResourceId* resource_id,
                                       gfx::Size* resource_size) const {
   NOTREACHED();
@@ -1401,7 +1429,7 @@
 void LayerImpl::GetAllTilesForTracing(std::set<const Tile*>* tiles) const {
 }
 
-void LayerImpl::AsValueInto(base::debug::TracedValue* state) const {
+void LayerImpl::AsValueInto(base::trace_event::TracedValue* state) const {
   TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
       TRACE_DISABLED_BY_DEFAULT("cc.debug"),
       state,
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 96f915f..97fd205 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -46,15 +46,8 @@
 class ConvertableToTraceFormat;
 class TracedValue;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::ConvertableToTraceFormat;
-using ::base::trace_event::TracedValue;
-}
 class DictionaryValue;
-}  // namespace base
+}
 
 namespace cc {
 
@@ -205,6 +198,7 @@
   LayerTreeImpl* layer_tree_impl() const { return layer_tree_impl_; }
 
   void PopulateSharedQuadState(SharedQuadState* state) const;
+  void PopulateScaledSharedQuadState(SharedQuadState* state, float scale) const;
   // WillDraw must be called before AppendQuads. If WillDraw returns false,
   // AppendQuads and DidDraw will not be called. If WillDraw returns true,
   // DidDraw is guaranteed to be called before another WillDraw or before
@@ -214,7 +208,6 @@
   virtual bool WillDraw(DrawMode draw_mode,
                         ResourceProvider* resource_provider);
   virtual void AppendQuads(RenderPass* render_pass,
-                           const Occlusion& occlusion_in_content_space,
                            AppendQuadsData* append_quads_data) {}
   virtual void DidDraw(ResourceProvider* resource_provider);
 
@@ -226,11 +219,6 @@
   virtual RenderPassId FirstContributingRenderPassId() const;
   virtual RenderPassId NextContributingRenderPassId(RenderPassId id) const;
 
-  // Updates the layer's tiles. This should return true if meaningful work was
-  // done. That is, if an early-out was hit and as a result the internal state
-  // of tiles didn't change, this function should return false.
-  virtual bool UpdateTiles(const Occlusion& occlusion_in_layer_space,
-                           bool resourceless_software_draw);
   virtual void NotifyTileStateChanged(const Tile* tile) {}
 
   virtual ScrollbarLayerImplBase* ToScrollbarLayer();
@@ -574,7 +562,7 @@
   virtual void PushPropertiesTo(LayerImpl* layer);
 
   virtual void GetAllTilesForTracing(std::set<const Tile*>* tiles) const;
-  virtual void AsValueInto(base::debug::TracedValue* dict) const;
+  virtual void AsValueInto(base::trace_event::TracedValue* dict) const;
 
   virtual size_t GPUMemoryUsageInBytes() const;
 
@@ -593,7 +581,7 @@
   virtual void RunMicroBenchmark(MicroBenchmarkImpl* benchmark);
 
   virtual void SetDebugInfo(
-      scoped_refptr<base::debug::ConvertableToTraceFormat> other);
+      scoped_refptr<base::trace_event::ConvertableToTraceFormat> other);
 
   bool IsDrawnRenderSurfaceLayerListMember() const;
 
@@ -769,7 +757,7 @@
   // hierarchy before layers can be drawn.
   DrawProperties<LayerImpl> draw_properties_;
 
-  scoped_refptr<base::debug::ConvertableToTraceFormat> debug_info_;
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> debug_info_;
   scoped_ptr<RenderSurfaceImpl> render_surface_;
 
   std::vector<FrameTimingRequest> frame_timing_requests_;
diff --git a/cc/layers/nine_patch_layer_impl.cc b/cc/layers/nine_patch_layer_impl.cc
index 82ba480..832efb3 100644
--- a/cc/layers/nine_patch_layer_impl.cc
+++ b/cc/layers/nine_patch_layer_impl.cc
@@ -82,7 +82,6 @@
 
 void NinePatchLayerImpl::AppendQuads(
     RenderPass* render_pass,
-    const Occlusion& occlusion_in_content_space,
     AppendQuadsData* append_quads_data) {
   CheckGeometryLimitations();
   SharedQuadState* shared_quad_state =
@@ -214,7 +213,8 @@
   const bool opaque = layer_tree_impl()->IsUIResourceOpaque(ui_resource_id_);
 
   visible_rect =
-      occlusion_in_content_space.GetUnoccludedContentRect(layer_top_left);
+      draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+          layer_top_left);
   opaque_rect = opaque ? visible_rect : gfx::Rect();
   if (!visible_rect.IsEmpty()) {
     TextureDrawQuad* quad =
@@ -234,7 +234,8 @@
   }
 
   visible_rect =
-      occlusion_in_content_space.GetUnoccludedContentRect(layer_top_right);
+      draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+          layer_top_right);
   opaque_rect = opaque ? visible_rect : gfx::Rect();
   if (!visible_rect.IsEmpty()) {
     TextureDrawQuad* quad =
@@ -254,7 +255,8 @@
   }
 
   visible_rect =
-      occlusion_in_content_space.GetUnoccludedContentRect(layer_bottom_left);
+      draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+          layer_bottom_left);
   opaque_rect = opaque ? visible_rect : gfx::Rect();
   if (!visible_rect.IsEmpty()) {
     TextureDrawQuad* quad =
@@ -274,7 +276,8 @@
   }
 
   visible_rect =
-      occlusion_in_content_space.GetUnoccludedContentRect(layer_bottom_right);
+      draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+          layer_bottom_right);
   opaque_rect = opaque ? visible_rect : gfx::Rect();
   if (!visible_rect.IsEmpty()) {
     TextureDrawQuad* quad =
@@ -293,7 +296,9 @@
                  nearest_neighbor);
   }
 
-  visible_rect = occlusion_in_content_space.GetUnoccludedContentRect(layer_top);
+  visible_rect =
+      draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+          layer_top);
   opaque_rect = opaque ? visible_rect : gfx::Rect();
   if (!visible_rect.IsEmpty()) {
     TextureDrawQuad* quad =
@@ -313,7 +318,8 @@
   }
 
   visible_rect =
-      occlusion_in_content_space.GetUnoccludedContentRect(layer_left);
+      draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+          layer_left);
   opaque_rect = opaque ? visible_rect : gfx::Rect();
   if (!visible_rect.IsEmpty()) {
     TextureDrawQuad* quad =
@@ -333,7 +339,8 @@
   }
 
   visible_rect =
-      occlusion_in_content_space.GetUnoccludedContentRect(layer_right);
+      draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+          layer_right);
   opaque_rect = opaque ? visible_rect : gfx::Rect();
   if (!visible_rect.IsEmpty()) {
     TextureDrawQuad* quad =
@@ -353,7 +360,8 @@
   }
 
   visible_rect =
-      occlusion_in_content_space.GetUnoccludedContentRect(layer_bottom);
+      draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+          layer_bottom);
   opaque_rect = opaque ? visible_rect : gfx::Rect();
   if (!visible_rect.IsEmpty()) {
     TextureDrawQuad* quad =
@@ -374,7 +382,8 @@
 
   if (fill_center_) {
     visible_rect =
-        occlusion_in_content_space.GetUnoccludedContentRect(layer_center);
+        draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+            layer_center);
     opaque_rect = opaque ? visible_rect : gfx::Rect();
     if (!visible_rect.IsEmpty()) {
       TextureDrawQuad* quad =
diff --git a/cc/layers/nine_patch_layer_impl.h b/cc/layers/nine_patch_layer_impl.h
index 5320d39..948758a 100644
--- a/cc/layers/nine_patch_layer_impl.h
+++ b/cc/layers/nine_patch_layer_impl.h
@@ -61,7 +61,6 @@
   void PushPropertiesTo(LayerImpl* layer) override;
 
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override;
 
   base::DictionaryValue* LayerTreeAsJson() const override;
diff --git a/cc/layers/nine_patch_layer_impl_unittest.cc b/cc/layers/nine_patch_layer_impl_unittest.cc
index de1bf40..beee519 100644
--- a/cc/layers/nine_patch_layer_impl_unittest.cc
+++ b/cc/layers/nine_patch_layer_impl_unittest.cc
@@ -62,7 +62,7 @@
   layer->SetImageBounds(bitmap_size);
   layer->SetLayout(aperture_rect, border, fill_center);
   AppendQuadsData data;
-  layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+  layer->AppendQuads(render_pass.get(), &data);
 
   // Verify quad rects
   const QuadList& quads = render_pass->quad_list;
diff --git a/cc/layers/painted_scrollbar_layer.cc b/cc/layers/painted_scrollbar_layer.cc
index 8f4d675..36c9f82 100644
--- a/cc/layers/painted_scrollbar_layer.cc
+++ b/cc/layers/painted_scrollbar_layer.cc
@@ -4,9 +4,12 @@
 
 #include "cc/layers/painted_scrollbar_layer.h"
 
+#include <algorithm>
+
 #include "base/auto_reset.h"
 #include "base/basictypes.h"
 #include "base/trace_event/trace_event.h"
+#include "cc/base/math_util.h"
 #include "cc/layers/painted_scrollbar_layer_impl.h"
 #include "cc/resources/ui_resource_bitmap.h"
 #include "cc/trees/layer_tree_host.h"
@@ -16,6 +19,7 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkSize.h"
+#include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/skia_util.h"
 
 namespace cc {
@@ -38,6 +42,7 @@
     : scrollbar_(scrollbar.Pass()),
       scroll_layer_id_(scroll_layer_id),
       clip_layer_id_(Layer::INVALID_ID),
+      internal_contents_scale_(0.f),
       thumb_thickness_(scrollbar_->ThumbThickness()),
       thumb_length_(scrollbar_->ThumbLength()),
       is_overlay_(scrollbar_->IsOverlay()),
@@ -82,10 +87,10 @@
 }
 
 float PaintedScrollbarLayer::ClampScaleToMaxTextureSize(float scale) {
-  // If the scaled content_bounds() is bigger than the max texture size of the
-  // device, we need to clamp it by rescaling, since content_bounds() is used
+  // If the scaled bounds() is bigger than the max texture size of the
+  // device, we need to clamp it by rescaling, since this is used
   // below to set the texture size.
-  gfx::Size scaled_bounds = ComputeContentBoundsForScale(scale, scale);
+  gfx::Size scaled_bounds = gfx::ToCeiledSize(gfx::ScaleSize(bounds(), scale));
   if (scaled_bounds.width() > MaxTextureSize() ||
       scaled_bounds.height() > MaxTextureSize()) {
     if (scaled_bounds.width() > scaled_bounds.height())
@@ -96,26 +101,17 @@
   return scale;
 }
 
-void PaintedScrollbarLayer::CalculateContentsScale(
-    float ideal_contents_scale,
-    float* contents_scale_x,
-    float* contents_scale_y,
-    gfx::Size* content_bounds) {
-  ContentsScalingLayer::CalculateContentsScale(
-      ClampScaleToMaxTextureSize(ideal_contents_scale),
-      contents_scale_x,
-      contents_scale_y,
-      content_bounds);
-}
-
 void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
-  ContentsScalingLayer::PushPropertiesTo(layer);
+  Layer::PushPropertiesTo(layer);
 
   PushScrollClipPropertiesTo(layer);
 
   PaintedScrollbarLayerImpl* scrollbar_layer =
       static_cast<PaintedScrollbarLayerImpl*>(layer);
 
+  scrollbar_layer->set_internal_contents_scale_and_bounds(
+      internal_contents_scale_, internal_content_bounds_);
+
   scrollbar_layer->SetThumbThickness(thumb_thickness_);
   scrollbar_layer->SetThumbLength(thumb_length_);
   if (orientation() == HORIZONTAL) {
@@ -160,7 +156,7 @@
     thumb_resource_ = nullptr;
   }
 
-  ContentsScalingLayer::SetLayerTreeHost(host);
+  Layer::SetLayerTreeHost(host);
 }
 
 gfx::Rect PaintedScrollbarLayer::ScrollbarLayerRectToContentRect(
@@ -168,10 +164,10 @@
   // Don't intersect with the bounds as in LayerRectToContentRect() because
   // layer_rect here might be in coordinates of the containing layer.
   gfx::Rect expanded_rect = gfx::ScaleToEnclosingRect(
-      layer_rect, contents_scale_x(), contents_scale_y());
-  // We should never return a rect bigger than the content_bounds().
+      layer_rect, internal_contents_scale_, internal_contents_scale_);
+  // We should never return a rect bigger than the content bounds.
   gfx::Size clamped_size = expanded_rect.size();
-  clamped_size.SetToMin(content_bounds());
+  clamped_size.SetToMin(internal_content_bounds_);
   expanded_rect.set_size(clamped_size);
   return expanded_rect;
 }
@@ -202,8 +198,36 @@
   }
 }
 
+void PaintedScrollbarLayer::UpdateInternalContentScale() {
+  float scale = layer_tree_host()->device_scale_factor();
+  if (layer_tree_host()
+          ->settings()
+          .layer_transforms_should_scale_layer_contents) {
+    gfx::Vector2dF transform_scales =
+        MathUtil::ComputeTransform2dScaleComponents(draw_transform(), scale);
+    scale = std::max(transform_scales.x(), transform_scales.y());
+  }
+  bool changed = false;
+  changed |= UpdateProperty(ClampScaleToMaxTextureSize(scale),
+                            &internal_contents_scale_);
+  changed |= UpdateProperty(
+      gfx::ToCeiledSize(gfx::ScaleSize(bounds(), internal_contents_scale_)),
+      &internal_content_bounds_);
+  if (changed) {
+    // If the content scale or bounds change, repaint.
+    SetNeedsDisplay();
+  }
+}
+
 bool PaintedScrollbarLayer::Update(ResourceUpdateQueue* queue,
                                    const OcclusionTracker<Layer>* occlusion) {
+  {
+    base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
+                                                  true);
+    Layer::Update(queue, occlusion);
+    UpdateInternalContentScale();
+  }
+
   UpdateThumbAndTrackGeometry();
 
   gfx::Rect track_layer_rect = gfx::Rect(location_, bounds());
@@ -225,12 +249,7 @@
   if (!has_thumb_ && thumb_resource_) {
     thumb_resource_ = nullptr;
     SetNeedsPushProperties();
-  }
-
-  {
-    base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
-                                                  true);
-    ContentsScalingLayer::Update(queue, occlusion);
+    updated = true;
   }
 
   if (update_rect_.IsEmpty() && track_resource_)
diff --git a/cc/layers/painted_scrollbar_layer.h b/cc/layers/painted_scrollbar_layer.h
index 950c165..ae2b125 100644
--- a/cc/layers/painted_scrollbar_layer.h
+++ b/cc/layers/painted_scrollbar_layer.h
@@ -7,7 +7,7 @@
 
 #include "cc/base/cc_export.h"
 #include "cc/input/scrollbar.h"
-#include "cc/layers/contents_scaling_layer.h"
+#include "cc/layers/layer.h"
 #include "cc/layers/scrollbar_layer_interface.h"
 #include "cc/layers/scrollbar_theme_painter.h"
 #include "cc/resources/layer_updater.h"
@@ -17,7 +17,7 @@
 class ScrollbarThemeComposite;
 
 class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface,
-                                        public ContentsScalingLayer {
+                                        public Layer {
  public:
   scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
 
@@ -41,10 +41,10 @@
   void SetLayerTreeHost(LayerTreeHost* host) override;
   void PushPropertiesTo(LayerImpl* layer) override;
   void PushScrollClipPropertiesTo(LayerImpl* layer) override;
-  void CalculateContentsScale(float ideal_contents_scale,
-                              float* contents_scale_x,
-                              float* contents_scale_y,
-                              gfx::Size* content_bounds) override;
+
+  const gfx::Size& internal_content_bounds() const {
+    return internal_content_bounds_;
+  }
 
  protected:
   PaintedScrollbarLayer(scoped_ptr<Scrollbar> scrollbar, int scroll_layer_id);
@@ -57,17 +57,20 @@
   UIResourceId thumb_resource_id() {
     return thumb_resource_.get() ? thumb_resource_->id() : 0;
   }
+  void UpdateInternalContentScale();
   void UpdateThumbAndTrackGeometry();
 
  private:
   gfx::Rect ScrollbarLayerRectToContentRect(const gfx::Rect& layer_rect) const;
   gfx::Rect OriginThumbRect() const;
 
-  template<typename T> void UpdateProperty(T value, T* prop) {
+  template <typename T>
+  bool UpdateProperty(T value, T* prop) {
     if (*prop == value)
-      return;
+      return false;
     *prop = value;
     SetNeedsPushProperties();
+    return true;
   }
 
   int MaxTextureSize();
@@ -81,6 +84,9 @@
   int scroll_layer_id_;
   int clip_layer_id_;
 
+  float internal_contents_scale_;
+  gfx::Size internal_content_bounds_;
+
   // Snapshot of properties taken in UpdateThumbAndTrackGeometry and used in
   // PushPropertiesTo.
   int thumb_thickness_;
diff --git a/cc/layers/painted_scrollbar_layer_impl.cc b/cc/layers/painted_scrollbar_layer_impl.cc
index 068d42f..b05d51e 100644
--- a/cc/layers/painted_scrollbar_layer_impl.cc
+++ b/cc/layers/painted_scrollbar_layer_impl.cc
@@ -32,6 +32,7 @@
     : ScrollbarLayerImplBase(tree_impl, id, orientation, false, false),
       track_ui_resource_id_(0),
       thumb_ui_resource_id_(0),
+      internal_contents_scale_(1.f),
       thumb_thickness_(0),
       thumb_length_(0),
       track_start_(0),
@@ -51,6 +52,9 @@
   PaintedScrollbarLayerImpl* scrollbar_layer =
       static_cast<PaintedScrollbarLayerImpl*>(layer);
 
+  scrollbar_layer->set_internal_contents_scale_and_bounds(
+      internal_contents_scale_, internal_content_bounds_);
+
   scrollbar_layer->SetThumbThickness(thumb_thickness_);
   scrollbar_layer->SetThumbLength(thumb_length_);
   scrollbar_layer->SetTrackStart(track_start_);
@@ -68,26 +72,28 @@
 
 void PaintedScrollbarLayerImpl::AppendQuads(
     RenderPass* render_pass,
-    const Occlusion& occlusion_in_content_space,
     AppendQuadsData* append_quads_data) {
   bool premultipled_alpha = true;
   bool flipped = false;
   bool nearest_neighbor = false;
   gfx::PointF uv_top_left(0.f, 0.f);
   gfx::PointF uv_bottom_right(1.f, 1.f);
-  gfx::Rect bounds_rect(bounds());
-  gfx::Rect content_bounds_rect(content_bounds());
 
   SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
-  PopulateSharedQuadState(shared_quad_state);
+  PopulateScaledSharedQuadState(shared_quad_state, internal_contents_scale_);
 
-  AppendDebugBorderQuad(
-      render_pass, content_bounds(), shared_quad_state, append_quads_data);
+  AppendDebugBorderQuad(render_pass, internal_content_bounds_,
+                        shared_quad_state, append_quads_data);
 
   gfx::Rect thumb_quad_rect = ComputeThumbQuadRect();
+  gfx::Rect scaled_thumb_quad_rect =
+      gfx::ScaleToEnclosingRect(thumb_quad_rect, internal_contents_scale_);
   gfx::Rect visible_thumb_quad_rect =
-      occlusion_in_content_space.GetUnoccludedContentRect(thumb_quad_rect);
+      draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+          thumb_quad_rect);
+  gfx::Rect scaled_visible_thumb_quad_rect = gfx::ScaleToEnclosingRect(
+      visible_thumb_quad_rect, internal_contents_scale_);
 
   ResourceProvider::ResourceId thumb_resource_id =
       layer_tree_impl()->ResourceIdForUIResource(thumb_ui_resource_id_);
@@ -99,40 +105,29 @@
     const float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
     TextureDrawQuad* quad =
         render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
-    quad->SetNew(shared_quad_state,
-                 thumb_quad_rect,
-                 opaque_rect,
-                 visible_thumb_quad_rect,
-                 thumb_resource_id,
-                 premultipled_alpha,
-                 uv_top_left,
-                 uv_bottom_right,
-                 SK_ColorTRANSPARENT,
-                 opacity,
-                 flipped,
-                 nearest_neighbor);
+    quad->SetNew(shared_quad_state, scaled_thumb_quad_rect, opaque_rect,
+                 scaled_visible_thumb_quad_rect, thumb_resource_id,
+                 premultipled_alpha, uv_top_left, uv_bottom_right,
+                 SK_ColorTRANSPARENT, opacity, flipped, nearest_neighbor);
   }
 
-  gfx::Rect track_quad_rect = content_bounds_rect;
+  gfx::Rect track_quad_rect(bounds());
+  gfx::Rect scaled_track_quad_rect(internal_content_bounds_);
   gfx::Rect visible_track_quad_rect =
-      occlusion_in_content_space.GetUnoccludedContentRect(track_quad_rect);
+      draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+          track_quad_rect);
+  gfx::Rect scaled_visible_track_quad_rect = gfx::ScaleToEnclosingRect(
+      visible_track_quad_rect, internal_contents_scale_);
   if (track_resource_id && !visible_track_quad_rect.IsEmpty()) {
-    gfx::Rect opaque_rect(contents_opaque() ? track_quad_rect : gfx::Rect());
+    gfx::Rect opaque_rect(contents_opaque() ? scaled_track_quad_rect
+                                            : gfx::Rect());
     const float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
     TextureDrawQuad* quad =
         render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
-    quad->SetNew(shared_quad_state,
-                 track_quad_rect,
-                 opaque_rect,
-                 visible_track_quad_rect,
-                 track_resource_id,
-                 premultipled_alpha,
-                 uv_top_left,
-                 uv_bottom_right,
-                 SK_ColorTRANSPARENT,
-                 opacity,
-                 flipped,
-                 nearest_neighbor);
+    quad->SetNew(shared_quad_state, scaled_track_quad_rect, opaque_rect,
+                 scaled_visible_track_quad_rect, track_resource_id,
+                 premultipled_alpha, uv_top_left, uv_bottom_right,
+                 SK_ColorTRANSPARENT, opacity, flipped, nearest_neighbor);
   }
 }
 
diff --git a/cc/layers/painted_scrollbar_layer_impl.h b/cc/layers/painted_scrollbar_layer_impl.h
index 8708b74..36a9be9 100644
--- a/cc/layers/painted_scrollbar_layer_impl.h
+++ b/cc/layers/painted_scrollbar_layer_impl.h
@@ -30,7 +30,6 @@
   bool WillDraw(DrawMode draw_mode,
                 ResourceProvider* resource_provider) override;
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override;
 
   void SetThumbThickness(int thumb_thickness);
@@ -45,6 +44,12 @@
     thumb_ui_resource_id_ = uid;
   }
 
+  void set_internal_contents_scale_and_bounds(float content_scale,
+                                              const gfx::Size& content_bounds) {
+    internal_contents_scale_ = content_scale;
+    internal_content_bounds_ = content_bounds;
+  }
+
  protected:
   PaintedScrollbarLayerImpl(LayerTreeImpl* tree_impl,
                             int id,
@@ -63,6 +68,9 @@
   UIResourceId track_ui_resource_id_;
   UIResourceId thumb_ui_resource_id_;
 
+  float internal_contents_scale_;
+  gfx::Size internal_content_bounds_;
+
   int thumb_thickness_;
   int thumb_length_;
   int track_start_;
diff --git a/cc/layers/painted_scrollbar_layer_impl_unittest.cc b/cc/layers/painted_scrollbar_layer_impl_unittest.cc
index 3994cc3..3fb3fb2 100644
--- a/cc/layers/painted_scrollbar_layer_impl_unittest.cc
+++ b/cc/layers/painted_scrollbar_layer_impl_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "cc/layers/painted_scrollbar_layer_impl.h"
 
+#include "cc/quads/draw_quad.h"
 #include "cc/test/layer_test_common.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -12,6 +13,8 @@
 
 TEST(PaintedScrollbarLayerImplTest, Occlusion) {
   gfx::Size layer_size(10, 1000);
+  float scale = 2.f;
+  gfx::Size scaled_layer_size(20, 2000);
   gfx::Size viewport_size(1000, 1000);
 
   LayerTestCommon::LayerImplTest impl;
@@ -36,6 +39,9 @@
       impl.AddChildToRoot<PaintedScrollbarLayerImpl>(orientation);
   scrollbar_layer_impl->SetBounds(layer_size);
   scrollbar_layer_impl->SetContentBounds(layer_size);
+  scrollbar_layer_impl->SetContentsOpaque(true);
+  scrollbar_layer_impl->set_internal_contents_scale_and_bounds(
+      scale, scaled_layer_size);
   scrollbar_layer_impl->SetDrawsContent(true);
   scrollbar_layer_impl->SetThumbThickness(layer_size.width());
   scrollbar_layer_impl->SetThumbLength(500);
@@ -62,6 +68,23 @@
         impl.quad_list(), occluded, &partially_occluded_count);
     EXPECT_EQ(2u, impl.quad_list().size());
     EXPECT_EQ(0u, partially_occluded_count);
+
+    // Note: this is also testing that the thumb and track are both
+    // scaled by the internal contents scale.  It's not occlusion-related
+    // but is easy to verify here.
+    const DrawQuad* thumb_quad = impl.quad_list().ElementAt(0);
+    const DrawQuad* track_quad = impl.quad_list().ElementAt(1);
+
+    gfx::Rect scaled_thumb_rect = gfx::ScaleToEnclosingRect(thumb_rect, scale);
+    EXPECT_EQ(track_quad->rect.ToString(),
+              gfx::Rect(scaled_layer_size).ToString());
+    EXPECT_EQ(track_quad->opaque_rect.ToString(),
+              gfx::Rect(scaled_layer_size).ToString());
+    EXPECT_EQ(track_quad->visible_rect.ToString(),
+              gfx::Rect(scaled_layer_size).ToString());
+    EXPECT_EQ(thumb_quad->rect.ToString(), scaled_thumb_rect.ToString());
+    EXPECT_EQ(thumb_quad->visible_rect.ToString(),
+              scaled_thumb_rect.ToString());
   }
 
   {
diff --git a/cc/layers/picture_image_layer_impl_unittest.cc b/cc/layers/picture_image_layer_impl_unittest.cc
index cf22855..d40f555 100644
--- a/cc/layers/picture_image_layer_impl_unittest.cc
+++ b/cc/layers/picture_image_layer_impl_unittest.cc
@@ -80,7 +80,7 @@
         animating_transform_to_screen;
     layer->draw_properties().visible_content_rect = viewport_rect;
     bool resourceless_software_draw = false;
-    layer->UpdateTiles(Occlusion(), resourceless_software_draw);
+    layer->UpdateTiles(resourceless_software_draw);
   }
 
  protected:
@@ -149,7 +149,7 @@
   scoped_ptr<RenderPass> render_pass = RenderPass::Create();
   AppendQuadsData data;
   active_layer->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
-  active_layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+  active_layer->AppendQuads(render_pass.get(), &data);
   active_layer->DidDraw(nullptr);
 
   EXPECT_EQ(DrawQuad::TILED_CONTENT, render_pass->quad_list.front()->material);
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc
index 52288e9..0ca2ae7 100644
--- a/cc/layers/picture_layer.cc
+++ b/cc/layers/picture_layer.cc
@@ -71,9 +71,6 @@
 
   scoped_refptr<RasterSource> raster_source =
       recording_source_->CreateRasterSource();
-  raster_source->SetBackgoundColor(SafeOpaqueBackgroundColor());
-  raster_source->SetRequiresClear(!contents_opaque() &&
-                                  !client_->FillsBoundsCompletely());
   layer_impl->UpdateRasterSource(raster_source, &recording_invalidation_,
                                  nullptr);
   DCHECK(recording_invalidation_.IsEmpty());
@@ -123,6 +120,10 @@
     return updated;
   }
 
+  recording_source_->SetBackgroundColor(SafeOpaqueBackgroundColor());
+  recording_source_->SetRequiresClear(!contents_opaque() &&
+                                      !client_->FillsBoundsCompletely());
+
   TRACE_EVENT1("cc", "PictureLayer::Update",
                "source_frame_number",
                layer_tree_host()->source_frame_number());
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 3a0753f..f62a866 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -153,7 +153,6 @@
 }
 
 void PictureLayerImpl::AppendQuads(RenderPass* render_pass,
-                                   const Occlusion& occlusion_in_content_space,
                                    AppendQuadsData* append_quads_data) {
   // The bounds and the pile size may differ if the pile wasn't updated (ie.
   // PictureLayer::Update didn't happen). In that case the pile will be empty.
@@ -172,50 +171,35 @@
         render_pass, bounds(), shared_quad_state, append_quads_data);
 
     SolidColorLayerImpl::AppendSolidQuads(
-        render_pass, occlusion_in_content_space, shared_quad_state,
-        visible_content_rect(), raster_source_->GetSolidColor(),
-        append_quads_data);
+        render_pass, draw_properties().occlusion_in_content_space,
+        shared_quad_state, visible_content_rect(),
+        raster_source_->GetSolidColor(), append_quads_data);
     return;
   }
 
   float max_contents_scale = MaximumTilingContentsScale();
-  gfx::Transform scaled_draw_transform = draw_transform();
-  scaled_draw_transform.Scale(SK_MScalar1 / max_contents_scale,
-                              SK_MScalar1 / max_contents_scale);
-  gfx::Size scaled_content_bounds =
-      gfx::ToCeiledSize(gfx::ScaleSize(bounds(), max_contents_scale));
-  gfx::Rect scaled_visible_content_rect =
-      gfx::ScaleToEnclosingRect(visible_content_rect(), max_contents_scale);
-  scaled_visible_content_rect.Intersect(gfx::Rect(scaled_content_bounds));
+  PopulateScaledSharedQuadState(shared_quad_state, max_contents_scale);
   Occlusion scaled_occlusion =
-      occlusion_in_content_space.GetOcclusionWithGivenDrawTransform(
-          scaled_draw_transform);
-
-  shared_quad_state->SetAll(
-      scaled_draw_transform, scaled_content_bounds, scaled_visible_content_rect,
-      draw_properties().clip_rect, draw_properties().is_clipped,
-      draw_properties().opacity, draw_properties().blend_mode,
-      sorting_context_id_);
+      draw_properties()
+          .occlusion_in_content_space.GetOcclusionWithGivenDrawTransform(
+              shared_quad_state->content_to_target_transform);
 
   if (current_draw_mode_ == DRAW_MODE_RESOURCELESS_SOFTWARE) {
     AppendDebugBorderQuad(
-        render_pass,
-        scaled_content_bounds,
-        shared_quad_state,
-        append_quads_data,
-        DebugColors::DirectPictureBorderColor(),
+        render_pass, shared_quad_state->content_bounds, shared_quad_state,
+        append_quads_data, DebugColors::DirectPictureBorderColor(),
         DebugColors::DirectPictureBorderWidth(layer_tree_impl()));
 
-    gfx::Rect geometry_rect = scaled_visible_content_rect;
+    gfx::Rect geometry_rect = shared_quad_state->visible_content_rect;
     gfx::Rect opaque_rect = contents_opaque() ? geometry_rect : gfx::Rect();
     gfx::Rect visible_geometry_rect =
         scaled_occlusion.GetUnoccludedContentRect(geometry_rect);
     if (visible_geometry_rect.IsEmpty())
       return;
 
-    gfx::Size texture_size = scaled_visible_content_rect.size();
+    gfx::Rect quad_content_rect = shared_quad_state->visible_content_rect;
+    gfx::Size texture_size = quad_content_rect.size();
     gfx::RectF texture_rect = gfx::RectF(texture_size);
-    gfx::Rect quad_content_rect = scaled_visible_content_rect;
 
     PictureDrawQuad* quad =
         render_pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
@@ -226,17 +210,14 @@
     return;
   }
 
-  AppendDebugBorderQuad(
-      render_pass, scaled_content_bounds, shared_quad_state, append_quads_data);
+  AppendDebugBorderQuad(render_pass, shared_quad_state->content_bounds,
+                        shared_quad_state, append_quads_data);
 
   if (ShowDebugBorders()) {
     for (PictureLayerTilingSet::CoverageIterator iter(
-             tilings_.get(),
-             max_contents_scale,
-             scaled_visible_content_rect,
-             ideal_contents_scale_);
-         iter;
-         ++iter) {
+             tilings_.get(), max_contents_scale,
+             shared_quad_state->visible_content_rect, ideal_contents_scale_);
+         iter; ++iter) {
       SkColor color;
       float width;
       if (*iter && iter->IsReadyToDraw()) {
@@ -290,12 +271,10 @@
   size_t missing_tile_count = 0u;
   size_t on_demand_missing_tile_count = 0u;
   only_used_low_res_last_append_quads_ = true;
-  for (PictureLayerTilingSet::CoverageIterator iter(tilings_.get(),
-                                                    max_contents_scale,
-                                                    scaled_visible_content_rect,
-                                                    ideal_contents_scale_);
-       iter;
-       ++iter) {
+  for (PictureLayerTilingSet::CoverageIterator iter(
+           tilings_.get(), max_contents_scale,
+           shared_quad_state->visible_content_rect, ideal_contents_scale_);
+       iter; ++iter) {
     gfx::Rect geometry_rect = iter.geometry_rect();
     gfx::Rect opaque_rect = contents_opaque() ? geometry_rect : gfx::Rect();
     gfx::Rect visible_geometry_rect =
@@ -429,8 +408,7 @@
   CleanUpTilingsOnActiveLayer(last_append_quads_tilings_);
 }
 
-bool PictureLayerImpl::UpdateTiles(const Occlusion& occlusion_in_content_space,
-                                   bool resourceless_software_draw) {
+bool PictureLayerImpl::UpdateTiles(bool resourceless_software_draw) {
   DCHECK_EQ(1.f, contents_scale_x());
   DCHECK_EQ(1.f, contents_scale_y());
 
@@ -452,7 +430,7 @@
   // only have one or two tilings (high and low res), so only clean up the
   // active layer. This cleans it up here in case AppendQuads didn't run.
   // If it did run, this would not remove any additional tilings.
-  if (GetTree() == ACTIVE_TREE)
+  if (layer_tree_impl()->IsActiveTree())
     CleanUpTilingsOnActiveLayer(last_append_quads_tilings_);
 
   UpdateIdealScales();
@@ -473,12 +451,6 @@
 
   if (draw_transform_is_animating())
     raster_source_->SetShouldAttemptToUseDistanceFieldText();
-  return UpdateTilePriorities(occlusion_in_content_space);
-}
-
-bool PictureLayerImpl::UpdateTilePriorities(
-    const Occlusion& occlusion_in_content_space) {
-  DCHECK_IMPLIES(raster_source_->IsSolidColor(), tilings_->num_tilings() == 0);
 
   double current_frame_time_in_seconds =
       (layer_tree_impl()->CurrentBeginFrameArgs().frame_time -
@@ -501,6 +473,12 @@
       !only_used_low_res_last_append_quads_ || RequiresHighResToDraw() ||
       !layer_tree_impl()->SmoothnessTakesPriority();
 
+  static const Occlusion kEmptyOcclusion;
+  const Occlusion& occlusion_in_content_space =
+      layer_tree_impl()->settings().use_occlusion_for_tile_prioritization
+          ? draw_properties().occlusion_in_content_space
+          : kEmptyOcclusion;
+
   // Pass |occlusion_in_content_space| for |occlusion_in_layer_space| since
   // they are the same space in picture layer, as contents scale is always 1.
   bool updated = tilings_->UpdateTilePriorities(
@@ -1139,7 +1117,7 @@
   return PictureLayerTilingSet::Create(
       this, settings.max_tiles_for_interest_area,
       layer_tree_impl()->use_gpu_rasterization()
-          ? 0.f
+          ? settings.gpu_rasterization_skewport_target_time_in_seconds
           : settings.skewport_target_time_in_seconds,
       settings.skewport_extrapolation_limit_in_content_pixels);
 }
@@ -1180,7 +1158,8 @@
   tilings_->GetAllTilesForTracing(tiles);
 }
 
-void PictureLayerImpl::AsValueInto(base::debug::TracedValue* state) const {
+void PictureLayerImpl::AsValueInto(
+    base::trace_event::TracedValue* state) const {
   LayerImpl::AsValueInto(state);
   state->SetDouble("ideal_contents_scale", ideal_contents_scale_);
   state->SetDouble("geometry_contents_scale", MaximumTilingContentsScale());
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h
index e7f4fba..f32e56f 100644
--- a/cc/layers/picture_layer_impl.h
+++ b/cc/layers/picture_layer_impl.h
@@ -55,10 +55,7 @@
   scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
   void PushPropertiesTo(LayerImpl* layer) override;
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override;
-  bool UpdateTiles(const Occlusion& occlusion_in_content_space,
-                   bool resourceless_software_draw) override;
   void NotifyTileStateChanged(const Tile* tile) override;
   void DidBeginTracing() override;
   void ReleaseResources() override;
@@ -81,6 +78,7 @@
   void UpdateRasterSource(scoped_refptr<RasterSource> raster_source,
                           Region* new_invalidation,
                           const PictureLayerTilingSet* pending_set);
+  bool UpdateTiles(bool resourceless_software_draw);
 
   // Mask-related functions.
   void GetContentsResourceId(ResourceProvider::ResourceId* resource_id,
@@ -116,7 +114,6 @@
   PictureLayerTiling* AddTiling(float contents_scale);
   void RemoveAllTilings();
   void AddTilingsForRasterScale();
-  bool UpdateTilePriorities(const Occlusion& occlusion_in_content_space);
   virtual bool ShouldAdjustRasterScale() const;
   virtual void RecalculateRasterScales();
   void CleanUpTilingsOnActiveLayer(
@@ -132,7 +129,7 @@
 
   void GetDebugBorderProperties(SkColor* color, float* width) const override;
   void GetAllTilesForTracing(std::set<const Tile*>* tiles) const override;
-  void AsValueInto(base::debug::TracedValue* dict) const override;
+  void AsValueInto(base::trace_event::TracedValue* dict) const override;
 
   virtual void UpdateIdealScales();
   float MaximumTilingContentsScale() const;
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index 600f3e2..f00b2e4 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -240,7 +240,7 @@
     layer->draw_properties().screen_space_transform_is_animating =
         animating_transform_to_screen;
     bool resourceless_software_draw = false;
-    layer->UpdateTiles(Occlusion(), resourceless_software_draw);
+    layer->UpdateTiles(resourceless_software_draw);
   }
   static void VerifyAllTilesExistAndHavePile(
       const PictureLayerTiling* tiling,
@@ -332,8 +332,11 @@
 
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(layer_size, layer_size);
+
+  scoped_ptr<FakePicturePile> active_recording =
+      FakePicturePile::CreateFilledPile(layer_size, layer_size);
   scoped_refptr<FakePicturePileImpl> active_pile =
-      FakePicturePileImpl::CreateFilledPile(layer_size, layer_size);
+      FakePicturePileImpl::CreateFromPile(active_recording.get(), nullptr);
 
   SetupTrees(pending_pile, active_pile);
 
@@ -347,18 +350,22 @@
   for (tile_iter = tiles.begin(); tile_iter < tiles.end(); tile_iter++) {
     gfx::Point tile_center = (*tile_iter)->content_rect().CenterPoint();
     gfx::Rect rect(tile_center.x(), tile_center.y(), 1, 1);
-    active_pile->add_draw_rect(rect);
+    active_recording->add_draw_rect(rect);
     rects.push_back(SkRect::MakeXYWH(rect.x(), rect.y(), 1, 1));
   }
+
   // Force re-raster with newly injected content
-  active_pile->RemoveRecordingAt(0, 0);
-  active_pile->AddRecordingAt(0, 0);
+  active_recording->RemoveRecordingAt(0, 0);
+  active_recording->AddRecordingAt(0, 0);
+
+  scoped_refptr<FakePicturePileImpl> updated_active_pile =
+      FakePicturePileImpl::CreateFromPile(active_recording.get(), nullptr);
 
   std::vector<SkRect>::const_iterator rect_iter = rects.begin();
   for (tile_iter = tiles.begin(); tile_iter < tiles.end(); tile_iter++) {
     MockCanvas mock_canvas(1000, 1000);
-    active_pile->PlaybackToSharedCanvas(&mock_canvas,
-                                        (*tile_iter)->content_rect(), 1.0f);
+    updated_active_pile->PlaybackToSharedCanvas(
+        &mock_canvas, (*tile_iter)->content_rect(), 1.0f);
 
     // This test verifies that when drawing the contents of a specific tile
     // at content scale 1.0, the playback canvas never receives content from
@@ -516,7 +523,7 @@
                                         resourceless_software_draw);
   active_layer_->draw_properties().visible_content_rect = viewport;
   active_layer_->draw_properties().screen_space_transform = transform;
-  active_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+  active_layer_->UpdateTiles(resourceless_software_draw);
 
   gfx::Rect visible_rect_for_tile_priority =
       active_layer_->visible_rect_for_tile_priority();
@@ -540,7 +547,7 @@
                                         viewport,
                                         transform,
                                         resourceless_software_draw);
-  active_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+  active_layer_->UpdateTiles(resourceless_software_draw);
 
   // Transform for tile priority is updated.
   EXPECT_TRANSFORMATION_MATRIX_EQ(transform,
@@ -560,7 +567,7 @@
                                         viewport,
                                         transform,
                                         resourceless_software_draw);
-  active_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+  active_layer_->UpdateTiles(resourceless_software_draw);
 
   EXPECT_TRANSFORMATION_MATRIX_EQ(transform,
                                   active_layer_->screen_space_transform());
@@ -1616,7 +1623,7 @@
 
   AppendQuadsData data;
   active_layer_->WillDraw(DRAW_MODE_RESOURCELESS_SOFTWARE, nullptr);
-  active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+  active_layer_->AppendQuads(render_pass.get(), &data);
   active_layer_->DidDraw(nullptr);
 
   ASSERT_EQ(1U, render_pass->quad_list.size());
@@ -1631,13 +1638,14 @@
   gfx::Size layer_bounds(1500, 1500);
   gfx::Rect visible_rect(250, 250, 1000, 1000);
 
-  scoped_refptr<FakePicturePileImpl> pending_pile =
-      FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
-  scoped_refptr<FakePicturePileImpl> active_pile =
-      FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
+  scoped_ptr<FakePicturePile> empty_recording =
+      FakePicturePile::CreateEmptyPile(tile_size, layer_bounds);
+  empty_recording->SetIsSolidColor(true);
 
-  pending_pile->set_is_solid_color(true);
-  active_pile->set_is_solid_color(true);
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFromPile(empty_recording.get(), nullptr);
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateFromPile(empty_recording.get(), nullptr);
 
   SetupTrees(pending_pile, active_pile);
 
@@ -1645,7 +1653,7 @@
 
   AppendQuadsData data;
   active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
-  active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+  active_layer_->AppendQuads(render_pass.get(), &data);
   active_layer_->DidDraw(nullptr);
 
   Region remaining = visible_rect;
@@ -1663,13 +1671,11 @@
   gfx::Size tile_size(host_impl_.settings().default_tile_size);
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings(
-          tile_size, layer_bounds);
+          tile_size, layer_bounds, false);
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings(
-          tile_size, layer_bounds);
+          tile_size, layer_bounds, true);
 
-  pending_pile->set_is_solid_color(false);
-  active_pile->set_is_solid_color(true);
   SetupTrees(pending_pile, active_pile);
   // Solid color pile should not allow tilings at any scale.
   EXPECT_FALSE(active_layer_->CanHaveTilings());
@@ -1707,7 +1713,7 @@
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
       CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
-  pending_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+  pending_layer_->UpdateTiles(resourceless_software_draw);
 
   int num_visible = 0;
   int num_offscreen = 0;
@@ -1773,7 +1779,7 @@
   time_ticks += base::TimeDelta::FromMilliseconds(200);
   host_impl_.SetCurrentBeginFrameArgs(
       CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
-  pending_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+  pending_layer_->UpdateTiles(resourceless_software_draw);
 
   // Intersect the two rects. Any tile outside should not be required for
   // activation.
@@ -1811,7 +1817,7 @@
   scoped_ptr<RenderPass> render_pass = RenderPass::Create();
   AppendQuadsData data;
   active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
-  active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+  active_layer_->AppendQuads(render_pass.get(), &data);
   active_layer_->DidDraw(nullptr);
 
   // All tiles in activation rect is ready to draw.
@@ -1843,7 +1849,7 @@
   scoped_ptr<RenderPass> render_pass = RenderPass::Create();
   AppendQuadsData data;
   active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
-  active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+  active_layer_->AppendQuads(render_pass.get(), &data);
   active_layer_->DidDraw(nullptr);
 
   // All high res tiles drew, nothing was incomplete.
@@ -1870,7 +1876,7 @@
   scoped_ptr<RenderPass> render_pass = RenderPass::Create();
   AppendQuadsData data;
   active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
-  active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+  active_layer_->AppendQuads(render_pass.get(), &data);
   active_layer_->DidDraw(nullptr);
 
   EXPECT_EQ(1u, render_pass->quad_list.size());
@@ -1900,7 +1906,7 @@
   scoped_ptr<RenderPass> render_pass = RenderPass::Create();
   AppendQuadsData data;
   active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
-  active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+  active_layer_->AppendQuads(render_pass.get(), &data);
   active_layer_->DidDraw(nullptr);
 
   EXPECT_EQ(1u, render_pass->quad_list.size());
@@ -1937,7 +1943,7 @@
   scoped_ptr<RenderPass> render_pass = RenderPass::Create();
   AppendQuadsData data;
   active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
-  active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+  active_layer_->AppendQuads(render_pass.get(), &data);
   active_layer_->DidDraw(nullptr);
 
   // The missing high res tile was replaced by a low res tile.
@@ -1995,7 +2001,7 @@
   scoped_ptr<RenderPass> render_pass = RenderPass::Create();
   AppendQuadsData data;
   active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
-  active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+  active_layer_->AppendQuads(render_pass.get(), &data);
   active_layer_->DidDraw(nullptr);
 
   // All high res tiles drew, and the one ideal res tile drew.
@@ -2105,9 +2111,10 @@
   // tiles.  This is attempting to simulate scrolling past the end of recorded
   // content on the active layer, where the recordings are so far away that
   // no tiles are created.
+  bool is_solid_color = false;
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings(
-          tile_size, layer_bounds);
+          tile_size, layer_bounds, is_solid_color);
 
   SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region());
 
@@ -2597,7 +2604,7 @@
   FakeOutputSurface* fake_output_surface =
       static_cast<FakeOutputSurface*>(host_impl_.output_surface());
   ASSERT_TRUE(fake_output_surface->InitializeAndSetContext3d(
-      TestContextProvider::Create()));
+      TestContextProvider::Create(), TestContextProvider::Create()));
 
   // These will crash PictureLayerImpl if this is not true.
   ASSERT_TRUE(host_impl_.pending_tree()->needs_update_draw_properties());
@@ -2928,7 +2935,7 @@
   pending_layer_->draw_properties().visible_content_rect =
       gfx::Rect(1100, 1100, 500, 500);
   bool resourceless_software_draw = false;
-  pending_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+  pending_layer_->UpdateTiles(resourceless_software_draw);
 
   unique_tiles.clear();
   high_res_tile_count = 0u;
@@ -2959,7 +2966,7 @@
 
   pending_layer_->draw_properties().visible_content_rect =
       gfx::Rect(0, 0, 500, 500);
-  pending_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+  pending_layer_->UpdateTiles(resourceless_software_draw);
 
   std::vector<Tile*> high_res_tiles =
       pending_layer_->HighResTiling()->AllTilesForTesting();
@@ -3030,10 +3037,13 @@
 }
 
 TEST_F(PictureLayerImplTest, TilingSetRasterQueueRequiredNoHighRes) {
+  scoped_ptr<FakePicturePile> empty_recording =
+      FakePicturePile::CreateEmptyPile(gfx::Size(256, 256),
+                                       gfx::Size(1024, 1024));
+  empty_recording->SetIsSolidColor(true);
+
   scoped_refptr<FakePicturePileImpl> pending_pile =
-      FakePicturePileImpl::CreateEmptyPile(gfx::Size(256, 256),
-                                           gfx::Size(1024, 1024));
-  pending_pile->set_is_solid_color(true);
+      FakePicturePileImpl::CreateFromPile(empty_recording.get(), nullptr);
 
   SetupPendingTree(pending_pile);
   EXPECT_FALSE(
@@ -3144,8 +3154,6 @@
 
     if (tile->required_for_activation() ==
             last_tile->required_for_activation() &&
-        priority.priority_bin ==
-            last_tile->priority(PENDING_TREE).priority_bin &&
         std::abs(tile->contents_scale() - last_tile->contents_scale()) <
             std::numeric_limits<float>::epsilon()) {
       if (priority.distance_to_visible <=
@@ -3523,9 +3531,10 @@
   // tiles.  This is attempting to simulate scrolling past the end of recorded
   // content on the active layer, where the recordings are so far away that
   // no tiles are created.
+  bool is_solid_color = false;
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings(
-          tile_size, layer_bounds);
+          tile_size, layer_bounds, is_solid_color);
 
   SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region());
 
@@ -3578,7 +3587,7 @@
                                         resourceless_software_draw);
   active_layer_->draw_properties().visible_content_rect = viewport;
   active_layer_->draw_properties().screen_space_transform = transform;
-  active_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+  active_layer_->UpdateTiles(resourceless_software_draw);
 
   gfx::Rect visible_rect_for_tile_priority =
       active_layer_->visible_rect_for_tile_priority();
@@ -3602,7 +3611,7 @@
                                         viewport,
                                         transform,
                                         resourceless_software_draw);
-  active_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+  active_layer_->UpdateTiles(resourceless_software_draw);
 
   // Transform for tile priority is updated.
   EXPECT_TRANSFORMATION_MATRIX_EQ(transform,
@@ -3622,7 +3631,7 @@
                                         viewport,
                                         transform,
                                         resourceless_software_draw);
-  active_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
+  active_layer_->UpdateTiles(resourceless_software_draw);
 
   EXPECT_TRANSFORMATION_MATRIX_EQ(transform,
                                   active_layer_->screen_space_transform());
@@ -3803,7 +3812,7 @@
                               SK_MScalar1 / max_contents_scale);
 
   AppendQuadsData data;
-  active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+  active_layer_->AppendQuads(render_pass.get(), &data);
 
   // SharedQuadState should have be of size 1, as we are doing AppenQuad once.
   EXPECT_EQ(1u, render_pass->shared_quad_state_list.size());
@@ -3869,7 +3878,7 @@
   scoped_ptr<RenderPass> render_pass = RenderPass::Create();
   AppendQuadsData data;
   active_layer_->WillDraw(DRAW_MODE_HARDWARE, nullptr);
-  active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+  active_layer_->AppendQuads(render_pass.get(), &data);
   active_layer_->DidDraw(nullptr);
 
   // Even when OOM, quads should be produced, and should be different material
@@ -3971,8 +3980,7 @@
                          tile->is_occluded(twin_tree)) {
                 EXPECT_TRUE(tile->is_occluded(tree));
                 EXPECT_FALSE(tile->is_occluded(twin_tree));
-                EXPECT_FALSE(
-                    tile->is_occluded_for_tree_priority(tree_priority));
+                EXPECT_FALSE(tile->is_occluded_combined());
               } else if (priority.distance_to_visible !=
                          twin_priority.distance_to_visible) {
                 EXPECT_LT(priority_for_tree_priority.distance_to_visible,
@@ -4685,7 +4693,7 @@
   scoped_ptr<RenderPass> render_pass = RenderPass::Create();
   AppendQuadsData data;
   active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
-  active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
+  active_layer_->AppendQuads(render_pass.get(), &data);
   active_layer_->DidDraw(nullptr);
 
   DrawQuad::Material expected = test_for_solid
@@ -4822,12 +4830,15 @@
 
   scoped_refptr<FakePicturePileImpl> filled_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-  scoped_refptr<FakePicturePileImpl> partial_pile =
-      FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
-  for (int i = 1; i < partial_pile->tiling().num_tiles_x(); ++i) {
-    for (int j = 1; j < partial_pile->tiling().num_tiles_y(); ++j)
-      partial_pile->AddRecordingAt(i, j);
+
+  scoped_ptr<FakePicturePile> partial_recording =
+      FakePicturePile::CreateEmptyPile(tile_size, layer_bounds);
+  for (int i = 1; i < partial_recording->tiling().num_tiles_x(); ++i) {
+    for (int j = 1; j < partial_recording->tiling().num_tiles_y(); ++j)
+      partial_recording->AddRecordingAt(i, j);
   }
+  scoped_refptr<FakePicturePileImpl> partial_pile =
+      FakePicturePileImpl::CreateFromPile(partial_recording.get(), nullptr);
 
   SetupPendingTreeWithFixedTileSize(filled_pile, tile_size, Region());
   ActivateTree();
diff --git a/cc/layers/render_surface_impl.cc b/cc/layers/render_surface_impl.cc
index 9d36235..2ca1241 100644
--- a/cc/layers/render_surface_impl.cc
+++ b/cc/layers/render_surface_impl.cc
@@ -18,7 +18,7 @@
 #include "cc/quads/render_pass_draw_quad.h"
 #include "cc/quads/shared_quad_state.h"
 #include "cc/trees/damage_tracker.h"
-#include "cc/trees/occlusion_tracker.h"
+#include "cc/trees/occlusion.h"
 #include "third_party/skia/include/core/SkImageFilter.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/transform.h"
@@ -53,6 +53,23 @@
   return drawable_content_rect;
 }
 
+SkColor RenderSurfaceImpl::GetDebugBorderColor() const {
+  return DebugColors::SurfaceBorderColor();
+}
+
+SkColor RenderSurfaceImpl::GetReplicaDebugBorderColor() const {
+  return DebugColors::SurfaceReplicaBorderColor();
+}
+
+float RenderSurfaceImpl::GetDebugBorderWidth() const {
+  return DebugColors::SurfaceBorderWidth(owning_layer_->layer_tree_impl());
+}
+
+float RenderSurfaceImpl::GetReplicaDebugBorderWidth() const {
+  return DebugColors::SurfaceReplicaBorderWidth(
+      owning_layer_->layer_tree_impl());
+}
+
 int RenderSurfaceImpl::OwningLayerId() const {
   return owning_layer_ ? owning_layer_->id() : 0;
 }
@@ -132,71 +149,39 @@
   pass_sink->AppendRenderPass(pass.Pass());
 }
 
-void RenderSurfaceImpl::AppendQuads(
-    RenderPass* render_pass,
-    const OcclusionTracker<LayerImpl>& occlusion_tracker,
-    AppendQuadsData* append_quads_data,
-    bool for_replica,
-    RenderPassId render_pass_id) {
-  DCHECK(!for_replica || owning_layer_->has_replica());
-
-  const gfx::Transform& draw_transform =
-      for_replica ? replica_draw_transform_ : draw_transform_;
+void RenderSurfaceImpl::AppendQuads(RenderPass* render_pass,
+                                    const gfx::Transform& draw_transform,
+                                    const Occlusion& occlusion_in_content_space,
+                                    SkColor debug_border_color,
+                                    float debug_border_width,
+                                    LayerImpl* mask_layer,
+                                    AppendQuadsData* append_quads_data,
+                                    RenderPassId render_pass_id) {
   gfx::Rect visible_content_rect =
-      occlusion_tracker.UnoccludedContributingSurfaceContentRect(
-          content_rect_, draw_transform);
+      occlusion_in_content_space.GetUnoccludedContentRect(content_rect_);
   if (visible_content_rect.IsEmpty())
     return;
 
   SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
-  shared_quad_state->SetAll(draw_transform,
-                            content_rect_.size(),
-                            content_rect_,
-                            clip_rect_,
-                            is_clipped_,
-                            draw_opacity_,
+  shared_quad_state->SetAll(draw_transform, content_rect_.size(), content_rect_,
+                            clip_rect_, is_clipped_, draw_opacity_,
                             owning_layer_->blend_mode(),
                             owning_layer_->sorting_context_id());
 
   if (owning_layer_->ShowDebugBorders()) {
-    SkColor color = for_replica ?
-                    DebugColors::SurfaceReplicaBorderColor() :
-                    DebugColors::SurfaceBorderColor();
-    float width = for_replica ?
-                  DebugColors::SurfaceReplicaBorderWidth(
-                      owning_layer_->layer_tree_impl()) :
-                  DebugColors::SurfaceBorderWidth(
-                      owning_layer_->layer_tree_impl());
     DebugBorderDrawQuad* debug_border_quad =
         render_pass->CreateAndAppendDrawQuad<DebugBorderDrawQuad>();
-    debug_border_quad->SetNew(
-        shared_quad_state, content_rect_, visible_content_rect, color, width);
-  }
-
-  // TODO(shawnsingh): By using the same RenderSurfaceImpl for both the content
-  // and its reflection, it's currently not possible to apply a separate mask to
-  // the reflection layer or correctly handle opacity in reflections (opacity
-  // must be applied after drawing both the layer and its reflection). The
-  // solution is to introduce yet another RenderSurfaceImpl to draw the layer
-  // and its reflection in. For now we only apply a separate reflection mask if
-  // the contents don't have a mask of their own.
-  LayerImpl* mask_layer = owning_layer_->mask_layer();
-  if (mask_layer &&
-      (!mask_layer->DrawsContent() || mask_layer->bounds().IsEmpty()))
-    mask_layer = nullptr;
-
-  if (!mask_layer && for_replica) {
-    mask_layer = owning_layer_->replica_layer()->mask_layer();
-    if (mask_layer &&
-        (!mask_layer->DrawsContent() || mask_layer->bounds().IsEmpty()))
-      mask_layer = nullptr;
+    debug_border_quad->SetNew(shared_quad_state, content_rect_,
+                              visible_content_rect, debug_border_color,
+                              debug_border_width);
   }
 
   ResourceProvider::ResourceId mask_resource_id = 0;
   gfx::Size mask_texture_size;
   gfx::Vector2dF mask_uv_scale;
-  if (mask_layer) {
+  if (mask_layer && mask_layer->DrawsContent() &&
+      !mask_layer->bounds().IsEmpty()) {
     mask_layer->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
     gfx::Vector2dF owning_layer_draw_scale =
         MathUtil::ComputeTransform2dScaleComponents(
diff --git a/cc/layers/render_surface_impl.h b/cc/layers/render_surface_impl.h
index 3303e94..2035e28 100644
--- a/cc/layers/render_surface_impl.h
+++ b/cc/layers/render_surface_impl.h
@@ -14,6 +14,7 @@
 #include "cc/layers/layer_lists.h"
 #include "cc/quads/render_pass.h"
 #include "cc/quads/shared_quad_state.h"
+#include "cc/trees/occlusion.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/transform.h"
@@ -22,8 +23,7 @@
 
 class DamageTracker;
 class DelegatedRendererLayerImpl;
-template <typename LayerType>
-class OcclusionTracker;
+class Occlusion;
 class RenderPassId;
 class RenderPassSink;
 class LayerImpl;
@@ -60,6 +60,12 @@
   }
   bool draw_opacity_is_animating() const { return draw_opacity_is_animating_; }
 
+  SkColor GetDebugBorderColor() const;
+  SkColor GetReplicaDebugBorderColor() const;
+
+  float GetDebugBorderWidth() const;
+  float GetReplicaDebugBorderWidth() const;
+
   void SetDrawTransform(const gfx::Transform& draw_transform) {
     draw_transform_ = draw_transform;
   }
@@ -120,6 +126,13 @@
   void SetContentRect(const gfx::Rect& content_rect);
   gfx::Rect content_rect() const { return content_rect_; }
 
+  const Occlusion& occlusion_in_content_space() const {
+    return occlusion_in_content_space_;
+  }
+  void set_occlusion_in_content_space(const Occlusion& occlusion) {
+    occlusion_in_content_space_ = occlusion;
+  }
+
   LayerImplList& layer_list() { return layer_list_; }
   void AddContributingDelegatedRenderPassLayer(LayerImpl* layer);
   void ClearLayerLists();
@@ -136,9 +149,12 @@
 
   void AppendRenderPasses(RenderPassSink* pass_sink);
   void AppendQuads(RenderPass* render_pass,
-                   const OcclusionTracker<LayerImpl>& occlusion_tracker,
+                   const gfx::Transform& draw_transform,
+                   const Occlusion& occlusion_in_content_space,
+                   SkColor debug_border_color,
+                   float debug_border_width,
+                   LayerImpl* mask_layer,
                    AppendQuadsData* append_quads_data,
-                   bool for_replica,
                    RenderPassId render_pass_id);
 
  private:
@@ -166,6 +182,7 @@
   LayerImplList layer_list_;
   std::vector<DelegatedRendererLayerImpl*>
       contributing_delegated_render_pass_layer_list_;
+  Occlusion occlusion_in_content_space_;
 
   // The nearest ancestor target surface that will contain the contents of this
   // surface, and that ignores outside occlusion. This can point to itself.
diff --git a/cc/layers/render_surface_unittest.cc b/cc/layers/render_surface_unittest.cc
index 6afbdcb..81b15ad 100644
--- a/cc/layers/render_surface_unittest.cc
+++ b/cc/layers/render_surface_unittest.cc
@@ -102,23 +102,17 @@
   gfx::Rect content_rect(0, 0, 50, 50);
   gfx::Rect clip_rect(5, 5, 40, 40);
   gfx::Transform origin;
-
   origin.Translate(30, 40);
 
-  render_surface->SetDrawTransform(origin);
   render_surface->SetContentRect(content_rect);
   render_surface->SetClipRect(clip_rect);
   render_surface->SetDrawOpacity(1.f);
 
-  MockOcclusionTracker<LayerImpl> occlusion_tracker;
   scoped_ptr<RenderPass> render_pass = RenderPass::Create();
   AppendQuadsData append_quads_data;
 
-  bool for_replica = false;
-  render_surface->AppendQuads(render_pass.get(),
-                              occlusion_tracker,
-                              &append_quads_data,
-                              for_replica,
+  render_surface->AppendQuads(render_pass.get(), origin, Occlusion(),
+                              SK_ColorBLACK, 1.f, nullptr, &append_quads_data,
                               RenderPassId(2, 0));
 
   ASSERT_EQ(1u, render_pass->shared_quad_state_list.size());
diff --git a/cc/layers/scrollbar_layer_impl_base.h b/cc/layers/scrollbar_layer_impl_base.h
index 4a96b49..d905c88 100644
--- a/cc/layers/scrollbar_layer_impl_base.h
+++ b/cc/layers/scrollbar_layer_impl_base.h
@@ -51,6 +51,7 @@
   void PushScrollClipPropertiesTo(LayerImpl* layer);
 
   bool SetVisibleToTotalLengthRatio(float ratio);
+  // Thumb quad rect in layer space.
   virtual gfx::Rect ComputeThumbQuadRect() const;
 
   float thumb_thickness_scale_factor() {
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc
index b24dcb1..c70b93a 100644
--- a/cc/layers/scrollbar_layer_unittest.cc
+++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -59,12 +59,84 @@
   return host->CommitAndCreateLayerImplTree();
 }
 
-TEST(ScrollbarLayerTest, ResolveScrollLayerPointer) {
-  FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
-  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
+class FakeResourceTrackingLayerTreeHost : public FakeLayerTreeHost {
+ public:
+  FakeResourceTrackingLayerTreeHost(FakeLayerTreeHostClient* client,
+                                    const LayerTreeSettings& settings)
+      : FakeLayerTreeHost(client, settings),
+        next_id_(1),
+        total_ui_resource_created_(0),
+        total_ui_resource_deleted_(0) {
+    InitializeSingleThreaded(client, base::MessageLoopProxy::current(),
+                             nullptr);
+  }
+
+  UIResourceId CreateUIResource(UIResourceClient* content) override {
+    total_ui_resource_created_++;
+    UIResourceId nid = next_id_++;
+    ui_resource_bitmap_map_.insert(
+        std::make_pair(nid, content->GetBitmap(nid, false)));
+    return nid;
+  }
+
+  // Deletes a UI resource.  May safely be called more than once.
+  void DeleteUIResource(UIResourceId id) override {
+    UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
+    if (iter != ui_resource_bitmap_map_.end()) {
+      ui_resource_bitmap_map_.erase(iter);
+      total_ui_resource_deleted_++;
+    }
+  }
+
+  size_t UIResourceCount() { return ui_resource_bitmap_map_.size(); }
+  int TotalUIResourceDeleted() { return total_ui_resource_deleted_; }
+  int TotalUIResourceCreated() { return total_ui_resource_created_; }
+
+  gfx::Size ui_resource_size(UIResourceId id) {
+    UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
+    if (iter != ui_resource_bitmap_map_.end())
+      return iter->second.GetSize();
+    return gfx::Size();
+  }
+
+  UIResourceBitmap* ui_resource_bitmap(UIResourceId id) {
+    UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
+    if (iter != ui_resource_bitmap_map_.end())
+      return &iter->second;
+    return nullptr;
+  }
+
+ private:
+  using UIResourceBitmapMap = base::hash_map<UIResourceId, UIResourceBitmap>;
+  UIResourceBitmapMap ui_resource_bitmap_map_;
+
+  int next_id_;
+  int total_ui_resource_created_;
+  int total_ui_resource_deleted_;
+};
+
+class ScrollbarLayerTest : public testing::Test {
+ public:
+  ScrollbarLayerTest() : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {
+    layer_tree_settings_.single_thread_proxy_scheduler = false;
+    layer_tree_host_.reset(new FakeResourceTrackingLayerTreeHost(
+        &fake_client_, layer_tree_settings_));
+    fake_client_.SetLayerTreeHost(layer_tree_host_.get());
+    // Force output surface creation for renderer capabilities.
+    layer_tree_host_->Composite(base::TimeTicks());
+    EXPECT_FALSE(layer_tree_host_->output_surface_lost());
+  }
+
+ protected:
+  FakeLayerTreeHostClient fake_client_;
+  LayerTreeSettings layer_tree_settings_;
+  scoped_ptr<FakeResourceTrackingLayerTreeHost> layer_tree_host_;
+};
+
+TEST_F(ScrollbarLayerTest, ResolveScrollLayerPointer) {
   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
   LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
-      host.get(), scrollbar.Pass(), false, false, 0, 0);
+      layer_tree_host_.get(), scrollbar.Pass(), false, false, 0, 0);
 
   LayerImpl* cc_child1 = layer_impl_tree_root->children()[0];
   PaintedScrollbarLayerImpl* cc_child2 =
@@ -75,12 +147,10 @@
   EXPECT_EQ(*(cc_child1->scrollbars()->begin()), cc_child2);
 }
 
-TEST(ScrollbarLayerTest, ResolveScrollLayerPointer_ReverseOrder) {
-  FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
-  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
+TEST_F(ScrollbarLayerTest, ResolveScrollLayerPointer_ReverseOrder) {
   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
   LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
-      host.get(), scrollbar.Pass(), true, false, 0, 0);
+      layer_tree_host_.get(), scrollbar.Pass(), true, false, 0, 0);
 
   PaintedScrollbarLayerImpl* cc_child1 =
       static_cast<PaintedScrollbarLayerImpl*>(
@@ -91,14 +161,11 @@
   EXPECT_EQ(*(cc_child2->scrollbars()->begin()), cc_child1);
 }
 
-TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) {
-  FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
-  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
-
+TEST_F(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) {
   // Create and attach a non-overlay scrollbar.
   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
   LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
-      host.get(), scrollbar.Pass(), false, false, 0, 0);
+      layer_tree_host_.get(), scrollbar.Pass(), false, false, 0, 0);
   PaintedScrollbarLayerImpl* scrollbar_layer_impl =
       static_cast<PaintedScrollbarLayerImpl*>(
           layer_impl_tree_root->children()[1]);
@@ -114,7 +181,7 @@
   scrollbar.reset(new FakeScrollbar(false, false, true));
 
   layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
-      host.get(), scrollbar.Pass(), false, false, 0, 0);
+      layer_tree_host_.get(), scrollbar.Pass(), false, false, 0, 0);
   scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
       layer_impl_tree_root->children()[1]);
 
@@ -125,10 +192,7 @@
                 gfx::Point(0, 0), InputHandler::Gesture, ScrollBlocksOnNone));
 }
 
-TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) {
-  FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
-  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
-
+TEST_F(ScrollbarLayerTest, ScrollOffsetSynchronization) {
   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
   scoped_refptr<Layer> layer_tree_root = Layer::Create();
   scoped_refptr<Layer> scroll_layer = Layer::Create();
@@ -143,7 +207,7 @@
   scroll_layer->SetBounds(gfx::Size(100, 200));
   content_layer->SetBounds(gfx::Size(100, 200));
 
-  host->SetRootLayer(layer_tree_root);
+  layer_tree_host_->SetRootLayer(layer_tree_root);
   layer_tree_root->AddChild(scroll_layer);
   scroll_layer->AddChild(content_layer);
   layer_tree_root->AddChild(scrollbar_layer);
@@ -153,7 +217,8 @@
   layer_tree_root->SavePaintProperties();
   content_layer->SavePaintProperties();
 
-  LayerImpl* layer_impl_tree_root = host->CommitAndCreateLayerImplTree();
+  LayerImpl* layer_impl_tree_root =
+      layer_tree_host_->CommitAndCreateLayerImplTree();
 
   ScrollbarLayerImplBase* cc_scrollbar_layer =
       static_cast<PaintedScrollbarLayerImpl*>(
@@ -172,7 +237,7 @@
 
   ScrollbarAnimationController* scrollbar_controller =
       layer_impl_tree_root->scrollbar_animation_controller();
-  layer_impl_tree_root = host->CommitAndCreateLayerImplTree();
+  layer_impl_tree_root = layer_tree_host_->CommitAndCreateLayerImplTree();
   EXPECT_EQ(scrollbar_controller,
             layer_impl_tree_root->scrollbar_animation_controller());
 
@@ -186,19 +251,18 @@
   EXPECT_EQ(300, cc_scrollbar_layer->maximum());
 }
 
-#define UPDATE_AND_EXTRACT_LAYER_POINTERS()                         \
-  do {                                                              \
-    scrollbar_layer->UpdateThumbAndTrackGeometry();                 \
-    root_clip_layer_impl = host->CommitAndCreateLayerImplTree();    \
-    root_layer_impl = root_clip_layer_impl->children()[0];          \
-    scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( \
-        root_layer_impl->children()[1]);                            \
-    scrollbar_layer_impl->ScrollbarParametersDidChange(false);      \
+#define UPDATE_AND_EXTRACT_LAYER_POINTERS()                                  \
+  do {                                                                       \
+    scrollbar_layer->UpdateInternalContentScale();                           \
+    scrollbar_layer->UpdateThumbAndTrackGeometry();                          \
+    root_clip_layer_impl = layer_tree_host_->CommitAndCreateLayerImplTree(); \
+    root_layer_impl = root_clip_layer_impl->children()[0];                   \
+    scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(          \
+        root_layer_impl->children()[1]);                                     \
+    scrollbar_layer_impl->ScrollbarParametersDidChange(false);               \
   } while (false)
 
-TEST(ScrollbarLayerTest, UpdatePropertiesOfScrollBarWhenThumbRemoved) {
-  FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
-  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
+TEST_F(ScrollbarLayerTest, UpdatePropertiesOfScrollBarWhenThumbRemoved) {
   scoped_refptr<Layer> root_clip_layer = Layer::Create();
   scoped_refptr<Layer> root_layer = Layer::Create();
   scoped_refptr<Layer> content_layer = Layer::Create();
@@ -211,7 +275,7 @@
   root_layer->SetBounds(gfx::Size(100, 50));
   content_layer->SetBounds(gfx::Size(100, 50));
 
-  host->SetRootLayer(root_clip_layer);
+  layer_tree_host_->SetRootLayer(root_clip_layer);
   root_clip_layer->AddChild(root_layer);
   root_layer->AddChild(content_layer);
   root_layer->AddChild(scrollbar_layer);
@@ -224,8 +288,6 @@
   scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
   scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10);
   scrollbar_layer->fake_scrollbar()->set_thumb_length(4);
-
-  scrollbar_layer->UpdateThumbAndTrackGeometry();
   LayerImpl* root_clip_layer_impl = nullptr;
   LayerImpl* root_layer_impl = nullptr;
   PaintedScrollbarLayerImpl* scrollbar_layer_impl = nullptr;
@@ -241,9 +303,7 @@
             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
 }
 
-TEST(ScrollbarLayerTest, ThumbRect) {
-  FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
-  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
+TEST_F(ScrollbarLayerTest, ThumbRect) {
   scoped_refptr<Layer> root_clip_layer = Layer::Create();
   scoped_refptr<Layer> root_layer = Layer::Create();
   scoped_refptr<Layer> content_layer = Layer::Create();
@@ -256,7 +316,7 @@
   root_layer->SetBounds(gfx::Size(100, 50));
   content_layer->SetBounds(gfx::Size(100, 50));
 
-  host->SetRootLayer(root_clip_layer);
+  layer_tree_host_->SetRootLayer(root_clip_layer);
   root_clip_layer->AddChild(root_layer);
   root_layer->AddChild(content_layer);
   root_layer->AddChild(scrollbar_layer);
@@ -269,7 +329,6 @@
   scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
   scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10);
   scrollbar_layer->fake_scrollbar()->set_thumb_length(4);
-  scrollbar_layer->UpdateThumbAndTrackGeometry();
   LayerImpl* root_clip_layer_impl = nullptr;
   LayerImpl* root_layer_impl = nullptr;
   PaintedScrollbarLayerImpl* scrollbar_layer_impl = nullptr;
@@ -322,19 +381,15 @@
             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
 }
 
-TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
+TEST_F(ScrollbarLayerTest, SolidColorDrawQuads) {
   const int kThumbThickness = 3;
   const int kTrackStart = 1;
   const int kTrackLength = 100;
 
-  FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
-  LayerTreeSettings layer_tree_settings;
-  scoped_ptr<FakeLayerTreeHost> host =
-      FakeLayerTreeHost::Create(&client, layer_tree_settings);
-
   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
   LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
-      host.get(), scrollbar.Pass(), false, true, kThumbThickness, kTrackStart);
+      layer_tree_host_.get(), scrollbar.Pass(), false, true, kThumbThickness,
+      kTrackStart);
   ScrollbarLayerImplBase* scrollbar_layer_impl =
       static_cast<SolidColorScrollbarLayerImpl*>(
           layer_impl_tree_root->children()[1]);
@@ -347,7 +402,7 @@
   {
     scoped_ptr<RenderPass> render_pass = RenderPass::Create();
     AppendQuadsData data;
-    scrollbar_layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
+    scrollbar_layer_impl->AppendQuads(render_pass.get(), &data);
 
     const QuadList& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
@@ -361,7 +416,7 @@
   {
     scoped_ptr<RenderPass> render_pass = RenderPass::Create();
     AppendQuadsData data;
-    scrollbar_layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
+    scrollbar_layer_impl->AppendQuads(render_pass.get(), &data);
 
     const QuadList& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
@@ -377,7 +432,7 @@
   {
     scoped_ptr<RenderPass> render_pass = RenderPass::Create();
     AppendQuadsData data;
-    scrollbar_layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
+    scrollbar_layer_impl->AppendQuads(render_pass.get(), &data);
 
     const QuadList& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
@@ -391,7 +446,7 @@
   {
     scoped_ptr<RenderPass> render_pass = RenderPass::Create();
     AppendQuadsData data;
-    scrollbar_layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
+    scrollbar_layer_impl->AppendQuads(render_pass.get(), &data);
 
     const QuadList& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
@@ -400,16 +455,11 @@
   }
 }
 
-TEST(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) {
+TEST_F(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) {
   const int kThumbThickness = 3;
   const int kTrackStart = 0;
   const int kTrackLength = 10;
 
-  FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
-  LayerTreeSettings layer_tree_settings;
-  scoped_ptr<FakeLayerTreeHost> host =
-      FakeLayerTreeHost::Create(&client, layer_tree_settings);
-
   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
 
   {
@@ -429,9 +479,10 @@
     scroll_layer->AddChild(child1);
     scroll_layer->InsertChild(child2, 1);
     layer_tree_root->AddChild(scroll_layer);
-    host->SetRootLayer(layer_tree_root);
+    layer_tree_host_->SetRootLayer(layer_tree_root);
   }
-  LayerImpl* layer_impl_tree_root = host->CommitAndCreateLayerImplTree();
+  LayerImpl* layer_impl_tree_root =
+      layer_tree_host_->CommitAndCreateLayerImplTree();
   LayerImpl* scroll_layer_impl = layer_impl_tree_root->children()[0];
 
   ScrollbarLayerImplBase* scrollbar_layer_impl =
@@ -450,7 +501,7 @@
     scoped_ptr<RenderPass> render_pass = RenderPass::Create();
 
     AppendQuadsData data;
-    scrollbar_layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
+    scrollbar_layer_impl->AppendQuads(render_pass.get(), &data);
 
     const QuadList& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
@@ -578,6 +629,7 @@
     scrollbar_layer_->SetScrollLayer(scroll_layer_->id());
     scrollbar_layer_->SetLayerTreeHost(layer_tree_host());
     scrollbar_layer_->SetBounds(bounds_);
+    scrollbar_layer_->SetIsDrawable(true);
     layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
 
     PostSetNeedsCommitToMainThread();
@@ -590,9 +642,9 @@
     // Check first that we're actually testing something.
     EXPECT_GT(scrollbar_layer_->bounds().width(), kMaxTextureSize);
 
-    EXPECT_EQ(scrollbar_layer_->content_bounds().width(),
+    EXPECT_EQ(scrollbar_layer_->internal_content_bounds().width(),
               kMaxTextureSize - 1);
-    EXPECT_EQ(scrollbar_layer_->content_bounds().height(),
+    EXPECT_EQ(scrollbar_layer_->internal_content_bounds().height(),
               kMaxTextureSize - 1);
 
     EndTest();
@@ -624,77 +676,13 @@
   RunTest(true, true, true);
 }
 
-class FakeLayerTreeHost : public LayerTreeHost {
+class ScrollbarLayerTestResourceCreationAndRelease : public ScrollbarLayerTest {
  public:
-  FakeLayerTreeHost(FakeLayerTreeHostClient* client,
-                    const LayerTreeSettings& settings)
-      : LayerTreeHost(client, nullptr, nullptr, settings),
-        next_id_(1),
-        total_ui_resource_created_(0),
-        total_ui_resource_deleted_(0) {
-    InitializeSingleThreaded(client,
-                             base::MessageLoopProxy::current(),
-                             nullptr);
-  }
-
-  UIResourceId CreateUIResource(UIResourceClient* content) override {
-    total_ui_resource_created_++;
-    UIResourceId nid = next_id_++;
-    ui_resource_bitmap_map_.insert(
-        std::make_pair(nid, content->GetBitmap(nid, false)));
-    return nid;
-  }
-
-  // Deletes a UI resource.  May safely be called more than once.
-  void DeleteUIResource(UIResourceId id) override {
-    UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
-    if (iter != ui_resource_bitmap_map_.end()) {
-      ui_resource_bitmap_map_.erase(iter);
-      total_ui_resource_deleted_++;
-    }
-  }
-
-  size_t UIResourceCount() { return ui_resource_bitmap_map_.size(); }
-  int TotalUIResourceDeleted() { return total_ui_resource_deleted_; }
-  int TotalUIResourceCreated() { return total_ui_resource_created_; }
-
-  gfx::Size ui_resource_size(UIResourceId id) {
-    UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
-    if (iter != ui_resource_bitmap_map_.end())
-      return iter->second.GetSize();
-    return gfx::Size();
-  }
-
-  UIResourceBitmap* ui_resource_bitmap(UIResourceId id) {
-    UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
-    if (iter != ui_resource_bitmap_map_.end())
-      return &iter->second;
-    return nullptr;
-  }
-
- private:
-  typedef base::hash_map<UIResourceId, UIResourceBitmap>
-      UIResourceBitmapMap;
-  UIResourceBitmapMap ui_resource_bitmap_map_;
-
-  int next_id_;
-  int total_ui_resource_created_;
-  int total_ui_resource_deleted_;
-};
-
-class ScrollbarLayerTestResourceCreationAndRelease : public testing::Test {
- public:
-  ScrollbarLayerTestResourceCreationAndRelease()
-      : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
-
   void TestResourceUpload(int num_updates,
                           size_t expected_resources,
                           int expected_created,
                           int expected_deleted,
                           bool use_solid_color_scrollbar) {
-    layer_tree_host_.reset(
-        new FakeLayerTreeHost(&fake_client_, layer_tree_settings_));
-
     scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, false));
     scoped_refptr<Layer> layer_tree_root = Layer::Create();
     scoped_refptr<Layer> content_layer = Layer::Create();
@@ -749,22 +737,18 @@
 
     scrollbar_layer->ClearRenderSurface();
   }
-
- protected:
-  FakeLayerTreeHostClient fake_client_;
-  LayerTreeSettings layer_tree_settings_;
-  scoped_ptr<FakeLayerTreeHost> layer_tree_host_;
 };
 
 TEST_F(ScrollbarLayerTestResourceCreationAndRelease, ResourceUpload) {
   bool use_solid_color_scrollbars = false;
   TestResourceUpload(0, 0, 0, 0, use_solid_color_scrollbars);
   int num_updates[3] = {1, 5, 10};
+  int created = 0;
+  int deleted = 0;
   for (int j = 0; j < 3; j++) {
-    TestResourceUpload(num_updates[j],
-                       2,
-                       num_updates[j] * 2,
-                       (num_updates[j] - 1) * 2,
+    created += num_updates[j] * 2;
+    deleted = created - 2;
+    TestResourceUpload(num_updates[j], 2, created, deleted,
                        use_solid_color_scrollbars);
   }
 }
@@ -777,13 +761,6 @@
 }
 
 TEST_F(ScrollbarLayerTestResourceCreationAndRelease, TestResourceUpdate) {
-  FakeLayerTreeHostClient fake_client_(FakeLayerTreeHostClient::DIRECT_3D);
-  LayerTreeSettings layer_tree_settings_;
-  scoped_ptr<FakeLayerTreeHost> layer_tree_host_;
-
-  layer_tree_host_.reset(
-      new FakeLayerTreeHost(&fake_client_, layer_tree_settings_));
-
   gfx::Point scrollbar_location(0, 185);
   scoped_refptr<Layer> layer_tree_root = Layer::Create();
   scoped_refptr<Layer> content_layer = Layer::Create();
@@ -918,15 +895,9 @@
   scrollbar_layer->ClearRenderSurface();
 }
 
-class ScaledScrollbarLayerTestResourceCreation : public testing::Test {
+class ScaledScrollbarLayerTestResourceCreation : public ScrollbarLayerTest {
  public:
-  ScaledScrollbarLayerTestResourceCreation()
-      : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
-
   void TestResourceUpload(const float test_scale) {
-    layer_tree_host_.reset(
-        new FakeLayerTreeHost(&fake_client_, layer_tree_settings_));
-
     gfx::Point scrollbar_location(0, 185);
     scoped_refptr<Layer> layer_tree_root = Layer::Create();
     scoped_refptr<Layer> content_layer = Layer::Create();
@@ -976,20 +947,19 @@
     gfx::Size thumb_size = layer_tree_host_->ui_resource_size(
         scrollbar_layer->thumb_resource_id());
 
-    EXPECT_LE(track_size.width(), scrollbar_layer->content_bounds().width());
-    EXPECT_LE(track_size.height(), scrollbar_layer->content_bounds().height());
-    EXPECT_LE(thumb_size.width(), scrollbar_layer->content_bounds().width());
-    EXPECT_LE(thumb_size.height(), scrollbar_layer->content_bounds().height());
+    EXPECT_LE(track_size.width(),
+              scrollbar_layer->internal_content_bounds().width());
+    EXPECT_LE(track_size.height(),
+              scrollbar_layer->internal_content_bounds().height());
+    EXPECT_LE(thumb_size.width(),
+              scrollbar_layer->internal_content_bounds().width());
+    EXPECT_LE(thumb_size.height(),
+              scrollbar_layer->internal_content_bounds().height());
 
     testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
 
     scrollbar_layer->ClearRenderSurface();
   }
-
- protected:
-  FakeLayerTreeHostClient fake_client_;
-  LayerTreeSettings layer_tree_settings_;
-  scoped_ptr<FakeLayerTreeHost> layer_tree_host_;
 };
 
 TEST_F(ScaledScrollbarLayerTestResourceCreation, ScaledResourceUpload) {
@@ -1000,15 +970,9 @@
   TestResourceUpload(4.1f);
 }
 
-class ScaledScrollbarLayerTestScaledRasterization : public testing::Test {
+class ScaledScrollbarLayerTestScaledRasterization : public ScrollbarLayerTest {
  public:
-  ScaledScrollbarLayerTestScaledRasterization()
-      : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
-
   void TestScale(const gfx::Rect scrollbar_rect, const float test_scale) {
-    layer_tree_host_.reset(
-        new FakeLayerTreeHost(&fake_client_, layer_tree_settings_));
-
     bool paint_during_update = true;
     bool has_thumb = false;
     scoped_refptr<Layer> layer_tree_root = Layer::Create();
@@ -1082,10 +1046,6 @@
              (SkColorGetG(c) << SK_G32_SHIFT) |
              (SkColorGetB(c) << SK_B32_SHIFT);
   }
-
-  FakeLayerTreeHostClient fake_client_;
-  LayerTreeSettings layer_tree_settings_;
-  scoped_ptr<FakeLayerTreeHost> layer_tree_host_;
 };
 
 TEST_F(ScaledScrollbarLayerTestScaledRasterization, TestLostPrecisionInClip) {
diff --git a/cc/layers/solid_color_layer_impl.cc b/cc/layers/solid_color_layer_impl.cc
index 3376693..2762497 100644
--- a/cc/layers/solid_color_layer_impl.cc
+++ b/cc/layers/solid_color_layer_impl.cc
@@ -64,7 +64,6 @@
 
 void SolidColorLayerImpl::AppendQuads(
     RenderPass* render_pass,
-    const Occlusion& occlusion_in_content_space,
     AppendQuadsData* append_quads_data) {
   SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
@@ -75,12 +74,9 @@
 
   // TODO(hendrikw): We need to pass the visible content rect rather than
   // |content_bounds()| here.
-  AppendSolidQuads(render_pass,
-                   occlusion_in_content_space,
-                   shared_quad_state,
-                   gfx::Rect(content_bounds()),
-                   background_color(),
-                   append_quads_data);
+  AppendSolidQuads(render_pass, draw_properties().occlusion_in_content_space,
+                   shared_quad_state, gfx::Rect(content_bounds()),
+                   background_color(), append_quads_data);
 }
 
 const char* SolidColorLayerImpl::LayerTypeAsString() const {
diff --git a/cc/layers/solid_color_layer_impl.h b/cc/layers/solid_color_layer_impl.h
index 3793481..213e3f1 100644
--- a/cc/layers/solid_color_layer_impl.h
+++ b/cc/layers/solid_color_layer_impl.h
@@ -30,7 +30,6 @@
   // LayerImpl overrides.
   scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override;
 
  protected:
diff --git a/cc/layers/solid_color_layer_impl_unittest.cc b/cc/layers/solid_color_layer_impl_unittest.cc
index 7150f80..d10f35d 100644
--- a/cc/layers/solid_color_layer_impl_unittest.cc
+++ b/cc/layers/solid_color_layer_impl_unittest.cc
@@ -38,7 +38,7 @@
   layer->draw_properties().render_target = layer.get();
 
   AppendQuadsData data;
-  layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+  layer->AppendQuads(render_pass.get(), &data);
 
   LayerTestCommon::VerifyQuadsExactlyCoverRect(render_pass->quad_list,
                                                visible_content_rect);
@@ -65,7 +65,7 @@
   layer->draw_properties().render_target = layer.get();
 
   AppendQuadsData data;
-  layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+  layer->AppendQuads(render_pass.get(), &data);
 
   ASSERT_EQ(render_pass->quad_list.size(), 1U);
   EXPECT_EQ(
@@ -94,7 +94,7 @@
   layer->draw_properties().render_target = layer.get();
 
   AppendQuadsData data;
-  layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+  layer->AppendQuads(render_pass.get(), &data);
 
   ASSERT_EQ(render_pass->quad_list.size(), 1U);
   EXPECT_EQ(opacity,
@@ -120,7 +120,7 @@
   layer->draw_properties().blend_mode = blend_mode;
 
   AppendQuadsData data;
-  layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+  layer->AppendQuads(render_pass.get(), &data);
 
   ASSERT_EQ(render_pass->quad_list.size(), 1U);
   EXPECT_EQ(blend_mode,
@@ -166,7 +166,7 @@
     scoped_ptr<RenderPass> render_pass = RenderPass::Create();
 
     AppendQuadsData data;
-    layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
+    layer_impl->AppendQuads(render_pass.get(), &data);
 
     ASSERT_EQ(render_pass->quad_list.size(), 1U);
     EXPECT_EQ(visible_content_rect.ToString(),
@@ -192,7 +192,7 @@
     scoped_ptr<RenderPass> render_pass = RenderPass::Create();
 
     AppendQuadsData data;
-    layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
+    layer_impl->AppendQuads(render_pass.get(), &data);
 
     ASSERT_EQ(render_pass->quad_list.size(), 1U);
     EXPECT_EQ(gfx::Rect().ToString(),
diff --git a/cc/layers/solid_color_scrollbar_layer_impl.cc b/cc/layers/solid_color_scrollbar_layer_impl.cc
index db6a502..fa1849e 100644
--- a/cc/layers/solid_color_scrollbar_layer_impl.cc
+++ b/cc/layers/solid_color_scrollbar_layer_impl.cc
@@ -95,7 +95,6 @@
 
 void SolidColorScrollbarLayerImpl::AppendQuads(
     RenderPass* render_pass,
-    const Occlusion& occlusion_in_content_space,
     AppendQuadsData* append_quads_data) {
   SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
@@ -106,7 +105,8 @@
 
   gfx::Rect thumb_quad_rect(ComputeThumbQuadRect());
   gfx::Rect visible_quad_rect =
-      occlusion_in_content_space.GetUnoccludedContentRect(thumb_quad_rect);
+      draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+          thumb_quad_rect);
   if (visible_quad_rect.IsEmpty())
     return;
 
diff --git a/cc/layers/solid_color_scrollbar_layer_impl.h b/cc/layers/solid_color_scrollbar_layer_impl.h
index 1abf552..df6179d 100644
--- a/cc/layers/solid_color_scrollbar_layer_impl.h
+++ b/cc/layers/solid_color_scrollbar_layer_impl.h
@@ -27,7 +27,6 @@
   void PushPropertiesTo(LayerImpl* layer) override;
 
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override;
 
  protected:
diff --git a/cc/layers/surface_layer_impl.cc b/cc/layers/surface_layer_impl.cc
index c3df89b..966112d 100644
--- a/cc/layers/surface_layer_impl.cc
+++ b/cc/layers/surface_layer_impl.cc
@@ -38,7 +38,6 @@
 }
 
 void SurfaceLayerImpl::AppendQuads(RenderPass* render_pass,
-                                   const Occlusion& occlusion_in_content_space,
                                    AppendQuadsData* append_quads_data) {
   SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
@@ -52,7 +51,8 @@
 
   gfx::Rect quad_rect(content_bounds());
   gfx::Rect visible_quad_rect =
-      occlusion_in_content_space.GetUnoccludedContentRect(quad_rect);
+      draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+          quad_rect);
   if (visible_quad_rect.IsEmpty())
     return;
   SurfaceDrawQuad* quad =
@@ -66,7 +66,7 @@
   *width = DebugColors::SurfaceLayerBorderWidth(layer_tree_impl());
 }
 
-void SurfaceLayerImpl::AsValueInto(base::debug::TracedValue* dict) const {
+void SurfaceLayerImpl::AsValueInto(base::trace_event::TracedValue* dict) const {
   LayerImpl::AsValueInto(dict);
   dict->SetInteger("surface_id", surface_id_.id);
 }
diff --git a/cc/layers/surface_layer_impl.h b/cc/layers/surface_layer_impl.h
index 9ef3c6d..90c0f45 100644
--- a/cc/layers/surface_layer_impl.h
+++ b/cc/layers/surface_layer_impl.h
@@ -25,7 +25,6 @@
   scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
   void PushPropertiesTo(LayerImpl* layer) override;
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override;
 
  protected:
@@ -33,7 +32,7 @@
 
  private:
   void GetDebugBorderProperties(SkColor* color, float* width) const override;
-  void AsValueInto(base::debug::TracedValue* dict) const override;
+  void AsValueInto(base::trace_event::TracedValue* dict) const override;
   const char* LayerTypeAsString() const override;
 
   SurfaceId surface_id_;
diff --git a/cc/layers/texture_layer_impl.cc b/cc/layers/texture_layer_impl.cc
index 6e9cea1..d9ddee7 100644
--- a/cc/layers/texture_layer_impl.cc
+++ b/cc/layers/texture_layer_impl.cc
@@ -141,7 +141,6 @@
 }
 
 void TextureLayerImpl::AppendQuads(RenderPass* render_pass,
-                                   const Occlusion& occlusion_in_content_space,
                                    AppendQuadsData* append_quads_data) {
   DCHECK(external_texture_resource_ || valid_texture_copy_);
 
@@ -159,7 +158,8 @@
   gfx::Rect quad_rect(content_bounds());
   gfx::Rect opaque_rect = opaque ? quad_rect : gfx::Rect();
   gfx::Rect visible_quad_rect =
-      occlusion_in_content_space.GetUnoccludedContentRect(quad_rect);
+      draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+          quad_rect);
   if (visible_quad_rect.IsEmpty())
     return;
 
diff --git a/cc/layers/texture_layer_impl.h b/cc/layers/texture_layer_impl.h
index 64de268..3d2c165 100644
--- a/cc/layers/texture_layer_impl.h
+++ b/cc/layers/texture_layer_impl.h
@@ -29,7 +29,6 @@
   bool WillDraw(DrawMode draw_mode,
                 ResourceProvider* resource_provider) override;
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override;
   SimpleEnclosedRegion VisibleContentOpaqueRegion() const override;
   void ReleaseResources() override;
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc
index 33291be..6405db3 100644
--- a/cc/layers/texture_layer_unittest.cc
+++ b/cc/layers/texture_layer_unittest.cc
@@ -1402,10 +1402,7 @@
  public:
   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
     LayerTreeImpl* tree = nullptr;
-    if (host_impl->settings().impl_side_painting)
-      tree = host_impl->pending_tree();
-    else
-      tree = host_impl->active_tree();
+    tree = host_impl->sync_tree();
     tree->root_layer()->children()[0]->ReleaseResources();
   }
 };
diff --git a/cc/layers/tiled_layer_impl.cc b/cc/layers/tiled_layer_impl.cc
index 535744d..234bd44 100644
--- a/cc/layers/tiled_layer_impl.cc
+++ b/cc/layers/tiled_layer_impl.cc
@@ -113,7 +113,7 @@
   return TiledLayerImpl::Create(tree_impl, id(), synced_scroll_offset());
 }
 
-void TiledLayerImpl::AsValueInto(base::debug::TracedValue* state) const {
+void TiledLayerImpl::AsValueInto(base::trace_event::TracedValue* state) const {
   LayerImpl::AsValueInto(state);
   MathUtil::AddToTracedValue("invalidation", update_rect(), state);
 }
@@ -166,7 +166,6 @@
 }
 
 void TiledLayerImpl::AppendQuads(RenderPass* render_pass,
-                                 const Occlusion& occlusion_in_content_space,
                                  AppendQuadsData* append_quads_data) {
   DCHECK(tiler_);
   DCHECK(!tiler_->has_empty_bounds());
@@ -225,7 +224,8 @@
         continue;
 
       gfx::Rect visible_tile_rect =
-          occlusion_in_content_space.GetUnoccludedContentRect(tile_rect);
+          draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+              tile_rect);
       if (visible_tile_rect.IsEmpty())
         continue;
 
diff --git a/cc/layers/tiled_layer_impl.h b/cc/layers/tiled_layer_impl.h
index 039bf19..c292790 100644
--- a/cc/layers/tiled_layer_impl.h
+++ b/cc/layers/tiled_layer_impl.h
@@ -36,7 +36,6 @@
   bool WillDraw(DrawMode draw_mode,
                 ResourceProvider* resource_provider) override;
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override;
 
   void GetContentsResourceId(ResourceProvider::ResourceId* resource_id,
@@ -68,7 +67,7 @@
   bool HasResourceIdForTileAt(int i, int j) const;
 
   void GetDebugBorderProperties(SkColor* color, float* width) const override;
-  void AsValueInto(base::debug::TracedValue* dict) const override;
+  void AsValueInto(base::trace_event::TracedValue* dict) const override;
 
  private:
   const char* LayerTypeAsString() const override;
diff --git a/cc/layers/tiled_layer_impl_unittest.cc b/cc/layers/tiled_layer_impl_unittest.cc
index 148f36a..e98fd09 100644
--- a/cc/layers/tiled_layer_impl_unittest.cc
+++ b/cc/layers/tiled_layer_impl_unittest.cc
@@ -71,7 +71,7 @@
     layer->SetBounds(layer_size);
 
     AppendQuadsData data;
-    layer->AppendQuads(render_pass, Occlusion(), &data);
+    layer->AppendQuads(render_pass, &data);
   }
 
  protected:
@@ -95,7 +95,7 @@
 
     AppendQuadsData data;
     EXPECT_TRUE(layer->WillDraw(DRAW_MODE_HARDWARE, nullptr));
-    layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+    layer->AppendQuads(render_pass.get(), &data);
     layer->DidDraw(nullptr);
     unsigned num_tiles = num_tiles_x * num_tiles_y;
     EXPECT_EQ(render_pass->quad_list.size(), num_tiles);
@@ -124,7 +124,7 @@
 
     AppendQuadsData data;
     EXPECT_TRUE(layer->WillDraw(DRAW_MODE_HARDWARE, nullptr));
-    layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+    layer->AppendQuads(render_pass.get(), &data);
     layer->DidDraw(nullptr);
     EXPECT_EQ(render_pass->quad_list.size(), 0u);
   }
@@ -138,7 +138,7 @@
     scoped_ptr<RenderPass> render_pass = RenderPass::Create();
 
     AppendQuadsData data;
-    layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+    layer->AppendQuads(render_pass.get(), &data);
     EXPECT_EQ(render_pass->quad_list.size(), 0u);
   }
 }
@@ -158,7 +158,7 @@
     scoped_ptr<RenderPass> render_pass = RenderPass::Create();
 
     AppendQuadsData data;
-    layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+    layer->AppendQuads(render_pass.get(), &data);
     EXPECT_EQ(render_pass->quad_list.size(), 4u);
     EXPECT_EQ(0u, data.num_missing_tiles);
 
@@ -175,7 +175,7 @@
     scoped_ptr<RenderPass> render_pass = RenderPass::Create();
 
     AppendQuadsData data;
-    layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+    layer->AppendQuads(render_pass.get(), &data);
     EXPECT_LT(0u, data.num_missing_tiles);
     EXPECT_EQ(render_pass->quad_list.size(), 4u);
     for (const auto& quad : render_pass->quad_list)
diff --git a/cc/layers/ui_resource_layer_impl.cc b/cc/layers/ui_resource_layer_impl.cc
index c7653e7..76900e4 100644
--- a/cc/layers/ui_resource_layer_impl.cc
+++ b/cc/layers/ui_resource_layer_impl.cc
@@ -93,7 +93,6 @@
 
 void UIResourceLayerImpl::AppendQuads(
     RenderPass* render_pass,
-    const Occlusion& occlusion_in_content_space,
     AppendQuadsData* append_quads_data) {
   SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
@@ -123,7 +122,8 @@
   gfx::Rect quad_rect(bounds());
   gfx::Rect opaque_rect(opaque ? quad_rect : gfx::Rect());
   gfx::Rect visible_quad_rect =
-      occlusion_in_content_space.GetUnoccludedContentRect(quad_rect);
+      draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
+          quad_rect);
   if (visible_quad_rect.IsEmpty())
     return;
 
diff --git a/cc/layers/ui_resource_layer_impl.h b/cc/layers/ui_resource_layer_impl.h
index d98f1fb..87d77e8 100644
--- a/cc/layers/ui_resource_layer_impl.h
+++ b/cc/layers/ui_resource_layer_impl.h
@@ -45,7 +45,6 @@
   bool WillDraw(DrawMode draw_mode,
                 ResourceProvider* resource_provider) override;
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override;
 
   base::DictionaryValue* LayerTreeAsJson() const override;
diff --git a/cc/layers/ui_resource_layer_impl_unittest.cc b/cc/layers/ui_resource_layer_impl_unittest.cc
index 7149b07..4509ae3 100644
--- a/cc/layers/ui_resource_layer_impl_unittest.cc
+++ b/cc/layers/ui_resource_layer_impl_unittest.cc
@@ -48,7 +48,7 @@
   scoped_ptr<RenderPass> render_pass = RenderPass::Create();
 
   AppendQuadsData data;
-  layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+  layer->AppendQuads(render_pass.get(), &data);
 
   // Verify quad rects
   const QuadList& quads = render_pass->quad_list;
@@ -88,7 +88,7 @@
   scoped_ptr<RenderPass> render_pass = RenderPass::Create();
 
   AppendQuadsData data;
-  layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+  layer->AppendQuads(render_pass.get(), &data);
 
   // Verify quad rects
   const QuadList& quads = render_pass->quad_list;
diff --git a/cc/layers/video_frame_provider_client_impl.cc b/cc/layers/video_frame_provider_client_impl.cc
deleted file mode 100644
index e69de29..0000000
--- a/cc/layers/video_frame_provider_client_impl.cc
+++ /dev/null
diff --git a/cc/layers/video_frame_provider_client_impl.h b/cc/layers/video_frame_provider_client_impl.h
index b6eb86f..39f66fb 100644
--- a/cc/layers/video_frame_provider_client_impl.h
+++ b/cc/layers/video_frame_provider_client_impl.h
@@ -7,6 +7,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
 #include "cc/layers/video_frame_provider.h"
 #include "ui/gfx/transform.h"
 
@@ -23,12 +24,10 @@
       VideoFrameProvider* provider);
 
   VideoLayerImpl* active_video_layer() { return active_video_layer_; }
-  void set_active_video_layer(VideoLayerImpl* video_layer) {
-    active_video_layer_ = video_layer;
-  }
+  void SetActiveVideoLayer(VideoLayerImpl* video_layer);
 
   void Stop();
-  bool Stopped() const { return !provider_; }
+  bool Stopped();
 
   scoped_refptr<media::VideoFrame> AcquireLockAndCurrentFrame();
   void PutCurrentFrame(const scoped_refptr<media::VideoFrame>& frame);
@@ -53,6 +52,7 @@
   // Guards the destruction of provider_ and the frame that it provides
   base::Lock provider_lock_;
   VideoFrameProvider* provider_;
+  base::ThreadChecker thread_checker_;
 
   gfx::Transform stream_texture_matrix_;
 
diff --git a/cc/layers/video_layer_impl.cc b/cc/layers/video_layer_impl.cc
index 091f2a9..559e0ac 100644
--- a/cc/layers/video_layer_impl.cc
+++ b/cc/layers/video_layer_impl.cc
@@ -72,7 +72,7 @@
 }
 
 void VideoLayerImpl::DidBecomeActive() {
-  provider_client_impl_->set_active_video_layer(this);
+  provider_client_impl_->SetActiveVideoLayer(this);
 }
 
 bool VideoLayerImpl::WillDraw(DrawMode draw_mode,
@@ -132,7 +132,6 @@
 }
 
 void VideoLayerImpl::AppendQuads(RenderPass* render_pass,
-                                 const Occlusion& occlusion_in_content_space,
                                  AppendQuadsData* append_quads_data) {
   DCHECK(frame_.get());
 
@@ -172,7 +171,9 @@
   gfx::Size coded_size = frame_->coded_size();
 
   Occlusion occlusion_in_video_space =
-      occlusion_in_content_space.GetOcclusionWithGivenDrawTransform(transform);
+      draw_properties()
+          .occlusion_in_content_space.GetOcclusionWithGivenDrawTransform(
+              transform);
   gfx::Rect visible_quad_rect =
       occlusion_in_video_space.GetUnoccludedContentRect(quad_rect);
   if (visible_quad_rect.IsEmpty())
diff --git a/cc/layers/video_layer_impl.h b/cc/layers/video_layer_impl.h
index 1843ec7..d05bd57 100644
--- a/cc/layers/video_layer_impl.h
+++ b/cc/layers/video_layer_impl.h
@@ -35,7 +35,6 @@
   bool WillDraw(DrawMode draw_mode,
                 ResourceProvider* resource_provider) override;
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override;
   void DidDraw(ResourceProvider* resource_provider) override;
   void DidBecomeActive() override;
diff --git a/cc/output/begin_frame_args.cc b/cc/output/begin_frame_args.cc
index acf24aa..3663125 100644
--- a/cc/output/begin_frame_args.cc
+++ b/cc/output/begin_frame_args.cc
@@ -59,15 +59,15 @@
 #endif
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat> BeginFrameArgs::AsValue()
-    const {
-  scoped_refptr<base::debug::TracedValue> state =
-      new base::debug::TracedValue();
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+BeginFrameArgs::AsValue() const {
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
   AsValueInto(state.get());
   return state;
 }
 
-void BeginFrameArgs::AsValueInto(base::debug::TracedValue* state) const {
+void BeginFrameArgs::AsValueInto(base::trace_event::TracedValue* state) const {
   state->SetString("type", "BeginFrameArgs");
   state->SetString("subtype", TypeToString(type));
   state->SetDouble("frame_time_us", frame_time.ToInternalValue());
diff --git a/cc/output/begin_frame_args.h b/cc/output/begin_frame_args.h
index 47430ca..10f7f28 100644
--- a/cc/output/begin_frame_args.h
+++ b/cc/output/begin_frame_args.h
@@ -16,14 +16,7 @@
 class ConvertableToTraceFormat;
 class TracedValue;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::ConvertableToTraceFormat;
-using ::base::trace_event::TracedValue;
 }
-}  // namespace base
 
 /**
  * In debug builds we trace the creation origin of BeginFrameArgs objects. We
@@ -84,8 +77,8 @@
 
   bool IsValid() const { return interval >= base::TimeDelta(); }
 
-  scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
-  void AsValueInto(base::debug::TracedValue* dict) const;
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+  void AsValueInto(base::trace_event::TracedValue* dict) const;
 
   base::TimeTicks frame_time;
   base::TimeTicks deadline;
diff --git a/cc/output/compositor_frame_metadata.cc b/cc/output/compositor_frame_metadata.cc
index 039f69d..dad78a0 100644
--- a/cc/output/compositor_frame_metadata.cc
+++ b/cc/output/compositor_frame_metadata.cc
@@ -10,7 +10,9 @@
     : device_scale_factor(0.f),
       page_scale_factor(0.f),
       min_page_scale_factor(0.f),
-      max_page_scale_factor(0.f) {
+      max_page_scale_factor(0.f),
+      root_overflow_x_hidden(false),
+      root_overflow_y_hidden(false) {
 }
 
 CompositorFrameMetadata::~CompositorFrameMetadata() {
diff --git a/cc/output/compositor_frame_metadata.h b/cc/output/compositor_frame_metadata.h
index a6fe2d4..e92a84d 100644
--- a/cc/output/compositor_frame_metadata.h
+++ b/cc/output/compositor_frame_metadata.h
@@ -34,6 +34,8 @@
   gfx::SizeF root_layer_size;
   float min_page_scale_factor;
   float max_page_scale_factor;
+  bool root_overflow_x_hidden;
+  bool root_overflow_y_hidden;
 
   // Used to position the Android location top bar and page content, whose
   // precise position is computed by the renderer compositor.
diff --git a/cc/output/context_provider.h b/cc/output/context_provider.h
index 7362e8b..71d06bd 100644
--- a/cc/output/context_provider.h
+++ b/cc/output/context_provider.h
@@ -12,6 +12,10 @@
 
 class GrContext;
 
+namespace base {
+class Lock;
+}
+
 namespace gpu {
 class ContextSupport;
 namespace gles2 { class GLES2Interface; }
@@ -27,6 +31,7 @@
   // Once this function has been called, the class should only be accessed
   // from the same thread.
   virtual bool BindToCurrentThread() = 0;
+  virtual void DetachFromThread() {}
 
   virtual gpu::gles2::GLES2Interface* ContextGL() = 0;
   virtual gpu::ContextSupport* ContextSupport() = 0;
@@ -39,6 +44,13 @@
     CC_EXPORT Capabilities();
   };
 
+  // Sets up a lock so this context can be used from multiple threads.
+  virtual void SetupLock() = 0;
+
+  // Returns the lock that should be held if using this context from multiple
+  // threads.
+  virtual base::Lock* GetLock() = 0;
+
   // Returns the capabilities of the currently bound 3d context.
   virtual Capabilities ContextCapabilities() = 0;
 
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc
index 65a94d8..9fbd4a5 100644
--- a/cc/output/direct_renderer.cc
+++ b/cc/output/direct_renderer.cc
@@ -235,7 +235,7 @@
              pass->copy_requests.begin();
          it != pass->copy_requests.end();
          ++it) {
-      if (i > 0) {
+      if (it != pass->copy_requests.begin()) {
         // Doing a readback is destructive of our state on Mac, so make sure
         // we restore the state between readbacks. http://crbug.com/99393.
         UseRenderPass(&frame, pass);
diff --git a/cc/output/filter_operation.cc b/cc/output/filter_operation.cc
index e01b901..1579e55 100644
--- a/cc/output/filter_operation.cc
+++ b/cc/output/filter_operation.cc
@@ -255,7 +255,7 @@
   return blended_filter;
 }
 
-void FilterOperation::AsValueInto(base::debug::TracedValue* value) const {
+void FilterOperation::AsValueInto(base::trace_event::TracedValue* value) const {
   value->SetInteger("type", type_);
   switch (type_) {
     case FilterOperation::GRAYSCALE:
diff --git a/cc/output/filter_operation.h b/cc/output/filter_operation.h
index 157db99..44590c2 100644
--- a/cc/output/filter_operation.h
+++ b/cc/output/filter_operation.h
@@ -19,14 +19,8 @@
 namespace trace_event {
 class TracedValue;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::TracedValue;
-}
 class Value;
-}  // namespace base
+}
 
 namespace cc {
 
@@ -229,7 +223,7 @@
                                const FilterOperation* to,
                                double progress);
 
-  void AsValueInto(base::debug::TracedValue* value) const;
+  void AsValueInto(base::trace_event::TracedValue* value) const;
 
  private:
   FilterOperation(FilterType type, float amount);
diff --git a/cc/output/filter_operations.cc b/cc/output/filter_operations.cc
index 96c316c..92423de 100644
--- a/cc/output/filter_operations.cc
+++ b/cc/output/filter_operations.cc
@@ -197,7 +197,8 @@
   return blended_filters;
 }
 
-void FilterOperations::AsValueInto(base::debug::TracedValue* value) const {
+void FilterOperations::AsValueInto(
+    base::trace_event::TracedValue* value) const {
   for (size_t i = 0; i < operations_.size(); ++i) {
     value->BeginDictionary();
     operations_[i].AsValueInto(value);
diff --git a/cc/output/filter_operations.h b/cc/output/filter_operations.h
index 8e37933..7018b82 100644
--- a/cc/output/filter_operations.h
+++ b/cc/output/filter_operations.h
@@ -15,14 +15,8 @@
 namespace trace_event {
 class TracedValue;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::TracedValue;
-}
 class Value;
-}  // namespace base
+}
 
 namespace cc {
 
@@ -76,7 +70,7 @@
   // a copy of this.
   FilterOperations Blend(const FilterOperations& from, double progress) const;
 
-  void AsValueInto(base::debug::TracedValue* value) const;
+  void AsValueInto(base::trace_event::TracedValue* value) const;
 
  private:
   std::vector<FilterOperation> operations_;
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index 5a15efa..2612f10 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -624,7 +624,7 @@
 static skia::RefPtr<SkImage> ApplyImageFilter(
     scoped_ptr<GLRenderer::ScopedUseGrContext> use_gr_context,
     ResourceProvider* resource_provider,
-    const gfx::Point& origin,
+    const gfx::Rect& rect,
     const gfx::Vector2dF& scale,
     SkImageFilter* filter,
     ScopedResource* source_texture_resource) {
@@ -693,7 +693,12 @@
   paint.setImageFilter(filter);
   canvas->clear(SK_ColorTRANSPARENT);
 
-  canvas->translate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
+  // The origin of the filter is top-left and the origin of the source is
+  // bottom-left, but the orientation is the same, so we must translate the
+  // filter so that it renders at the bottom of the texture to avoid
+  // misregistration.
+  int y_translate = source.height() - rect.height() - rect.origin().y();
+  canvas->translate(-rect.origin().x(), y_translate);
   canvas->scale(scale.x(), scale.y());
   canvas->drawSprite(source, 0, 0, &paint);
 
@@ -858,13 +863,9 @@
   skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter(
       quad->background_filters, background_texture->size());
 
-  skia::RefPtr<SkImage> background_with_filters =
-      ApplyImageFilter(ScopedUseGrContext::Create(this, frame),
-                       resource_provider_,
-                       quad->rect.origin(),
-                       quad->filters_scale,
-                       filter.get(),
-                       background_texture);
+  skia::RefPtr<SkImage> background_with_filters = ApplyImageFilter(
+      ScopedUseGrContext::Create(this, frame), resource_provider_, quad->rect,
+      quad->filters_scale, filter.get(), background_texture);
   return background_with_filters;
 }
 
@@ -970,12 +971,9 @@
         // in the compositor.
         use_color_matrix = true;
       } else {
-        filter_image = ApplyImageFilter(ScopedUseGrContext::Create(this, frame),
-                                        resource_provider_,
-                                        quad->rect.origin(),
-                                        quad->filters_scale,
-                                        filter.get(),
-                                        contents_texture);
+        filter_image = ApplyImageFilter(
+            ScopedUseGrContext::Create(this, frame), resource_provider_,
+            quad->rect, quad->filters_scale, filter.get(), contents_texture);
       }
     }
   }
@@ -2711,6 +2709,8 @@
                                           const gfx::Rect& target_rect) {
   DCHECK(texture->id());
 
+  // Explicitly release lock, otherwise we can crash when try to lock
+  // same texture again.
   current_framebuffer_lock_ = nullptr;
 
   SetStencilEnabled(false);
diff --git a/cc/output/output_surface.cc b/cc/output/output_surface.cc
index b65887e..b1a2b9a 100644
--- a/cc/output/output_surface.cc
+++ b/cc/output/output_surface.cc
@@ -18,16 +18,12 @@
 namespace cc {
 
 OutputSurface::OutputSurface(
-    const scoped_refptr<ContextProvider>& context_provider)
+    const scoped_refptr<ContextProvider>& context_provider,
+    const scoped_refptr<ContextProvider>& worker_context_provider,
+    scoped_ptr<SoftwareOutputDevice> software_device)
     : client_(NULL),
       context_provider_(context_provider),
-      device_scale_factor_(-1),
-      external_stencil_test_enabled_(false),
-      weak_ptr_factory_(this) {
-}
-
-OutputSurface::OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device)
-    : client_(NULL),
+      worker_context_provider_(worker_context_provider),
       software_device_(software_device.Pass()),
       device_scale_factor_(-1),
       external_stencil_test_enabled_(false),
@@ -35,14 +31,24 @@
 }
 
 OutputSurface::OutputSurface(
+    const scoped_refptr<ContextProvider>& context_provider)
+    : OutputSurface(context_provider, nullptr, nullptr) {
+}
+
+OutputSurface::OutputSurface(
+    const scoped_refptr<ContextProvider>& context_provider,
+    const scoped_refptr<ContextProvider>& worker_context_provider)
+    : OutputSurface(context_provider, worker_context_provider, nullptr) {
+}
+
+OutputSurface::OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device)
+    : OutputSurface(nullptr, nullptr, software_device.Pass()) {
+}
+
+OutputSurface::OutputSurface(
     const scoped_refptr<ContextProvider>& context_provider,
     scoped_ptr<SoftwareOutputDevice> software_device)
-    : client_(NULL),
-      context_provider_(context_provider),
-      software_device_(software_device.Pass()),
-      device_scale_factor_(-1),
-      external_stencil_test_enabled_(false),
-      weak_ptr_factory_(this) {
+    : OutputSurface(context_provider, nullptr, software_device.Pass()) {
 }
 
 void OutputSurface::CommitVSyncParameters(base::TimeTicks timebase,
@@ -109,6 +115,18 @@
       SetUpContext3d();
   }
 
+  if (success && worker_context_provider_.get()) {
+    success = worker_context_provider_->BindToCurrentThread();
+    if (success) {
+      worker_context_provider_->SetupLock();
+      // The destructor resets the context lost callback, so base::Unretained
+      // is safe, as long as the worker threads stop using the context before
+      // the output surface is destroyed.
+      worker_context_provider_->SetLostContextCallback(base::Bind(
+          &OutputSurface::DidLoseOutputSurface, base::Unretained(this)));
+    }
+  }
+
   if (!success)
     client_ = NULL;
 
@@ -116,21 +134,33 @@
 }
 
 bool OutputSurface::InitializeAndSetContext3d(
-    scoped_refptr<ContextProvider> context_provider) {
+    scoped_refptr<ContextProvider> context_provider,
+    scoped_refptr<ContextProvider> worker_context_provider) {
   DCHECK(!context_provider_.get());
   DCHECK(context_provider.get());
   DCHECK(client_);
 
-  bool success = false;
-  if (context_provider->BindToCurrentThread()) {
+  bool success = context_provider->BindToCurrentThread();
+  if (success) {
     context_provider_ = context_provider;
     SetUpContext3d();
-    client_->DeferredInitialize();
-    success = true;
+  }
+  if (success && worker_context_provider.get()) {
+    success = worker_context_provider->BindToCurrentThread();
+    if (success) {
+      worker_context_provider_ = worker_context_provider;
+      // The destructor resets the context lost callback, so base::Unretained
+      // is safe, as long as the worker threads stop using the context before
+      // the output surface is destroyed.
+      worker_context_provider_->SetLostContextCallback(base::Bind(
+          &OutputSurface::DidLoseOutputSurface, base::Unretained(this)));
+    }
   }
 
   if (!success)
     ResetContext3d();
+  else
+    client_->DeferredInitialize();
 
   return success;
 }
@@ -167,7 +197,12 @@
     context_provider_->SetMemoryPolicyChangedCallback(
         ContextProvider::MemoryPolicyChangedCallback());
   }
+  if (worker_context_provider_.get()) {
+    worker_context_provider_->SetLostContextCallback(
+        ContextProvider::LostContextCallback());
+  }
   context_provider_ = NULL;
+  worker_context_provider_ = NULL;
 }
 
 void OutputSurface::EnsureBackbuffer() {
diff --git a/cc/output/output_surface.h b/cc/output/output_surface.h
index 29e32a5..3e3b085 100644
--- a/cc/output/output_surface.h
+++ b/cc/output/output_surface.h
@@ -46,6 +46,11 @@
     DEFAULT_MAX_FRAMES_PENDING = 2
   };
 
+  OutputSurface(const scoped_refptr<ContextProvider>& context_provider,
+                const scoped_refptr<ContextProvider>& worker_context_provider,
+                scoped_ptr<SoftwareOutputDevice> software_device);
+  OutputSurface(const scoped_refptr<ContextProvider>& context_provider,
+                const scoped_refptr<ContextProvider>& worker_context_provider);
   explicit OutputSurface(
       const scoped_refptr<ContextProvider>& context_provider);
 
@@ -94,6 +99,9 @@
   // In the event of a lost context, the entire output surface should be
   // recreated.
   ContextProvider* context_provider() const { return context_provider_.get(); }
+  ContextProvider* worker_context_provider() const {
+    return worker_context_provider_.get();
+  }
   SoftwareOutputDevice* software_device() const {
     return software_device_.get();
   }
@@ -149,13 +157,15 @@
   // Synchronously initialize context3d and enter hardware mode.
   // This can only supported in threaded compositing mode.
   bool InitializeAndSetContext3d(
-      scoped_refptr<ContextProvider> context_provider);
+      scoped_refptr<ContextProvider> context_provider,
+      scoped_refptr<ContextProvider> worker_context_provider);
   void ReleaseGL();
 
   void PostSwapBuffersComplete();
 
   struct OutputSurface::Capabilities capabilities_;
   scoped_refptr<ContextProvider> context_provider_;
+  scoped_refptr<ContextProvider> worker_context_provider_;
   scoped_ptr<SoftwareOutputDevice> software_device_;
   scoped_ptr<OverlayCandidateValidator> overlay_candidate_validator_;
   gfx::Size surface_size_;
diff --git a/cc/output/output_surface_unittest.cc b/cc/output/output_surface_unittest.cc
index 4336f07..f32a96f 100644
--- a/cc/output/output_surface_unittest.cc
+++ b/cc/output/output_surface_unittest.cc
@@ -25,6 +25,10 @@
   explicit TestOutputSurface(scoped_refptr<ContextProvider> context_provider)
       : OutputSurface(context_provider) {}
 
+  TestOutputSurface(scoped_refptr<ContextProvider> context_provider,
+                    scoped_refptr<ContextProvider> worker_context_provider)
+      : OutputSurface(worker_context_provider) {}
+
   explicit TestOutputSurface(scoped_ptr<SoftwareOutputDevice> software_device)
       : OutputSurface(software_device.Pass()) {}
 
@@ -37,9 +41,8 @@
     client_->DidSwapBuffersComplete();
   }
 
-  bool InitializeNewContext3d(
-      scoped_refptr<ContextProvider> new_context_provider) {
-    return InitializeAndSetContext3d(new_context_provider);
+  bool InitializeNewContext3d(scoped_refptr<ContextProvider> context_provider) {
+    return InitializeAndSetContext3d(context_provider, nullptr);
   }
 
   using OutputSurface::ReleaseGL;
@@ -106,6 +109,26 @@
   EXPECT_TRUE(client.did_lose_output_surface_called());
 }
 
+TEST(OutputSurfaceTest, ClientPointerIndicatesWorkerBindToClientSuccess) {
+  scoped_refptr<TestContextProvider> provider = TestContextProvider::Create();
+  scoped_refptr<TestContextProvider> worker_provider =
+      TestContextProvider::Create();
+  TestOutputSurface output_surface(provider, worker_provider);
+  EXPECT_FALSE(output_surface.HasClient());
+
+  FakeOutputSurfaceClient client;
+  EXPECT_TRUE(output_surface.BindToClient(&client));
+  EXPECT_TRUE(output_surface.HasClient());
+  EXPECT_FALSE(client.deferred_initialize_called());
+
+  // Verify DidLoseOutputSurface callback is hooked up correctly.
+  EXPECT_FALSE(client.did_lose_output_surface_called());
+  output_surface.context_provider()->ContextGL()->LoseContextCHROMIUM(
+      GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
+  output_surface.context_provider()->ContextGL()->Flush();
+  EXPECT_TRUE(client.did_lose_output_surface_called());
+}
+
 TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientFailure) {
   scoped_refptr<TestContextProvider> context_provider =
       TestContextProvider::Create();
@@ -121,6 +144,23 @@
   EXPECT_FALSE(output_surface.HasClient());
 }
 
+TEST(OutputSurfaceTest, ClientPointerIndicatesWorkerBindToClientFailure) {
+  scoped_refptr<TestContextProvider> context_provider =
+      TestContextProvider::Create();
+  scoped_refptr<TestContextProvider> worker_context_provider =
+      TestContextProvider::Create();
+
+  // Lose the context so BindToClient fails.
+  worker_context_provider->UnboundTestContext3d()->set_context_lost(true);
+
+  TestOutputSurface output_surface(context_provider, worker_context_provider);
+  EXPECT_FALSE(output_surface.HasClient());
+
+  FakeOutputSurfaceClient client;
+  EXPECT_FALSE(output_surface.BindToClient(&client));
+  EXPECT_FALSE(output_surface.HasClient());
+}
+
 class OutputSurfaceTestInitializeNewContext3d : public ::testing::Test {
  public:
   OutputSurfaceTestInitializeNewContext3d()
diff --git a/cc/output/overlay_strategy_single_on_top.cc b/cc/output/overlay_strategy_single_on_top.cc
index 9a95206..71897ed 100644
--- a/cc/output/overlay_strategy_single_on_top.cc
+++ b/cc/output/overlay_strategy_single_on_top.cc
@@ -119,6 +119,20 @@
   return true;
 }
 
+bool OverlayStrategySingleOnTop::IsInvisibleQuad(const DrawQuad* draw_quad) {
+  if (draw_quad->material == DrawQuad::SOLID_COLOR) {
+    const SolidColorDrawQuad* solid_quad =
+        SolidColorDrawQuad::MaterialCast(draw_quad);
+    SkColor color = solid_quad->color;
+    float opacity = solid_quad->opacity();
+    float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity;
+    // Ignore transparent solid color quads.
+    return solid_quad->ShouldDrawWithBlending() &&
+           alpha < std::numeric_limits<float>::epsilon();
+  }
+  return false;
+}
+
 bool OverlayStrategySingleOnTop::Attempt(
     RenderPassList* render_passes_in_draw_order,
     OverlayCandidateList* candidate_list) {
@@ -143,7 +157,7 @@
            ++overlap_iter) {
         gfx::RectF overlap_rect = overlap_iter->rect;
         overlap_iter->quadTransform().TransformRect(&overlap_rect);
-        if (rect.Intersects(overlap_rect)) {
+        if (rect.Intersects(overlap_rect) && !IsInvisibleQuad(*overlap_iter)) {
           intersects = true;
           break;
         }
diff --git a/cc/output/overlay_strategy_single_on_top.h b/cc/output/overlay_strategy_single_on_top.h
index f92e104..a3fec0a 100644
--- a/cc/output/overlay_strategy_single_on_top.h
+++ b/cc/output/overlay_strategy_single_on_top.h
@@ -29,6 +29,10 @@
   bool GetCandidateQuadInfo(const DrawQuad& draw_quad,
                             OverlayCandidate* quad_info);
 
+  // Returns true if |draw_quad| will not block quads underneath from becoming
+  // an overlay.
+  bool IsInvisibleQuad(const DrawQuad* draw_quad);
+
   bool GetTextureQuadInfo(const TextureDrawQuad& quad,
                           OverlayCandidate* quad_info);
   bool GetVideoQuadInfo(const StreamVideoDrawQuad& quad,
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc
index 4682679..6ee388a 100644
--- a/cc/output/overlay_unittest.cc
+++ b/cc/output/overlay_unittest.cc
@@ -156,6 +156,17 @@
       mailbox, release_callback.Pass());
 }
 
+SolidColorDrawQuad* CreateSolidColorQuadAt(
+    const SharedQuadState* shared_quad_state,
+    SkColor color,
+    RenderPass* render_pass,
+    const gfx::Rect& rect) {
+  SolidColorDrawQuad* quad =
+      render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+  quad->SetNew(shared_quad_state, rect, rect, color, false);
+  return quad;
+}
+
 TextureDrawQuad* CreateCandidateQuadAt(ResourceProvider* resource_provider,
                                        const SharedQuadState* shared_quad_state,
                                        RenderPass* render_pass,
@@ -592,6 +603,94 @@
   EXPECT_EQ(2U, candidate_list.size());
 }
 
+TEST_F(SingleOverlayOnTopTest, AllowTransparentOnTop) {
+  scoped_ptr<RenderPass> pass = CreateRenderPass();
+  SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
+  shared_state->opacity = 0.f;
+  CreateSolidColorQuadAt(shared_state, SK_ColorBLACK, pass.get(),
+                         kOverlayBottomRightRect);
+  shared_state = pass->CreateAndAppendSharedQuadState();
+  shared_state->opacity = 1.f;
+  CreateCandidateQuadAt(resource_provider_.get(), shared_state, pass.get(),
+                        kOverlayBottomRightRect);
+
+  RenderPassList pass_list;
+  pass_list.push_back(pass.Pass());
+
+  RenderPassList original_pass_list;
+  RenderPass::CopyAll(pass_list, &original_pass_list);
+
+  OverlayCandidateList candidate_list;
+  overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+  EXPECT_EQ(1U, pass_list.size());
+  EXPECT_EQ(2U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, AllowTransparentColorOnTop) {
+  scoped_ptr<RenderPass> pass = CreateRenderPass();
+  CreateSolidColorQuadAt(pass->shared_quad_state_list.back(),
+                         SK_ColorTRANSPARENT, pass.get(),
+                         kOverlayBottomRightRect);
+  CreateCandidateQuadAt(resource_provider_.get(),
+                        pass->shared_quad_state_list.back(), pass.get(),
+                        kOverlayBottomRightRect);
+
+  RenderPassList pass_list;
+  pass_list.push_back(pass.Pass());
+
+  RenderPassList original_pass_list;
+  RenderPass::CopyAll(pass_list, &original_pass_list);
+
+  OverlayCandidateList candidate_list;
+  overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+  EXPECT_EQ(1U, pass_list.size());
+  EXPECT_EQ(2U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, RejectOpaqueColorOnTop) {
+  scoped_ptr<RenderPass> pass = CreateRenderPass();
+  SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
+  shared_state->opacity = 0.5f;
+  CreateSolidColorQuadAt(shared_state, SK_ColorBLACK, pass.get(),
+                         kOverlayBottomRightRect);
+  shared_state = pass->CreateAndAppendSharedQuadState();
+  shared_state->opacity = 1.f;
+  CreateCandidateQuadAt(resource_provider_.get(), shared_state, pass.get(),
+                        kOverlayBottomRightRect);
+
+  RenderPassList pass_list;
+  pass_list.push_back(pass.Pass());
+
+  RenderPassList original_pass_list;
+  RenderPass::CopyAll(pass_list, &original_pass_list);
+
+  OverlayCandidateList candidate_list;
+  overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+  EXPECT_EQ(1U, pass_list.size());
+  EXPECT_EQ(0U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, RejectTransparentColorOnTopWithoutBlending) {
+  scoped_ptr<RenderPass> pass = CreateRenderPass();
+  SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
+  CreateSolidColorQuadAt(shared_state, SK_ColorTRANSPARENT, pass.get(),
+                         kOverlayBottomRightRect)->opaque_rect =
+      kOverlayBottomRightRect;
+  CreateCandidateQuadAt(resource_provider_.get(), shared_state, pass.get(),
+                        kOverlayBottomRightRect);
+
+  RenderPassList pass_list;
+  pass_list.push_back(pass.Pass());
+
+  RenderPassList original_pass_list;
+  RenderPass::CopyAll(pass_list, &original_pass_list);
+
+  OverlayCandidateList candidate_list;
+  overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+  EXPECT_EQ(1U, pass_list.size());
+  EXPECT_EQ(0U, candidate_list.size());
+}
+
 TEST_F(SingleOverlayOnTopTest, RejectVideoSwapTransform) {
   scoped_ptr<RenderPass> pass = CreateRenderPass();
   CreateFullscreenCandidateVideoQuad(resource_provider_.get(),
diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc
index c7582fe..d7d1211 100644
--- a/cc/output/renderer_pixeltest.cc
+++ b/cc/output/renderer_pixeltest.cc
@@ -1395,15 +1395,19 @@
   // is red, which should not appear.
   gfx::Rect blue_rect(gfx::Size(100, 100));
   gfx::Rect blue_clip_rect(gfx::Point(50, 50), gfx::Size(50, 50));
-  scoped_refptr<FakePicturePileImpl> blue_pile =
-      FakePicturePileImpl::CreateFilledPile(pile_tile_size, blue_rect.size());
+
+  scoped_ptr<FakePicturePile> blue_recording =
+      FakePicturePile::CreateFilledPile(pile_tile_size, blue_rect.size());
   SkPaint red_paint;
   red_paint.setColor(SK_ColorRED);
-  blue_pile->add_draw_rect_with_paint(blue_rect, red_paint);
+  blue_recording->add_draw_rect_with_paint(blue_rect, red_paint);
   SkPaint blue_paint;
   blue_paint.setColor(SK_ColorBLUE);
-  blue_pile->add_draw_rect_with_paint(blue_clip_rect, blue_paint);
-  blue_pile->RerecordPile();
+  blue_recording->add_draw_rect_with_paint(blue_clip_rect, blue_paint);
+  blue_recording->RerecordPile();
+
+  scoped_refptr<FakePicturePileImpl> blue_pile =
+      FakePicturePileImpl::CreateFromPile(blue_recording.get(), nullptr);
 
   gfx::Transform blue_content_to_target_transform;
   gfx::Vector2d offset(viewport.bottom_right() - blue_rect.bottom_right());
@@ -1425,12 +1429,14 @@
                     1.f, blue_pile.get());
 
   // One viewport-filling green quad.
-  scoped_refptr<FakePicturePileImpl> green_pile =
-      FakePicturePileImpl::CreateFilledPile(pile_tile_size, viewport.size());
+  scoped_ptr<FakePicturePile> green_recording =
+      FakePicturePile::CreateFilledPile(pile_tile_size, viewport.size());
   SkPaint green_paint;
   green_paint.setColor(SK_ColorGREEN);
-  green_pile->add_draw_rect_with_paint(viewport, green_paint);
-  green_pile->RerecordPile();
+  green_recording->add_draw_rect_with_paint(viewport, green_paint);
+  green_recording->RerecordPile();
+  scoped_refptr<FakePicturePileImpl> green_pile =
+      FakePicturePileImpl::CreateFromPile(green_recording.get(), nullptr);
 
   gfx::Transform green_content_to_target_transform;
   SharedQuadState* green_shared_state = CreateTestSharedQuadState(
@@ -1465,12 +1471,14 @@
       CreateTestRenderPass(id, viewport, transform_to_root);
 
   // One viewport-filling 0.5-opacity green quad.
-  scoped_refptr<FakePicturePileImpl> green_pile =
-      FakePicturePileImpl::CreateFilledPile(pile_tile_size, viewport.size());
+  scoped_ptr<FakePicturePile> green_recording =
+      FakePicturePile::CreateFilledPile(pile_tile_size, viewport.size());
   SkPaint green_paint;
   green_paint.setColor(SK_ColorGREEN);
-  green_pile->add_draw_rect_with_paint(viewport, green_paint);
-  green_pile->RerecordPile();
+  green_recording->add_draw_rect_with_paint(viewport, green_paint);
+  green_recording->RerecordPile();
+  scoped_refptr<FakePicturePileImpl> green_pile =
+      FakePicturePileImpl::CreateFromPile(green_recording.get(), nullptr);
 
   gfx::Transform green_content_to_target_transform;
   SharedQuadState* green_shared_state = CreateTestSharedQuadState(
@@ -1484,12 +1492,14 @@
                      texture_format, viewport, 1.f, green_pile.get());
 
   // One viewport-filling white quad.
-  scoped_refptr<FakePicturePileImpl> white_pile =
-      FakePicturePileImpl::CreateFilledPile(pile_tile_size, viewport.size());
+  scoped_ptr<FakePicturePile> white_recording =
+      FakePicturePile::CreateFilledPile(pile_tile_size, viewport.size());
   SkPaint white_paint;
   white_paint.setColor(SK_ColorWHITE);
-  white_pile->add_draw_rect_with_paint(viewport, white_paint);
-  white_pile->RerecordPile();
+  white_recording->add_draw_rect_with_paint(viewport, white_paint);
+  white_recording->RerecordPile();
+  scoped_refptr<FakePicturePileImpl> white_pile =
+      FakePicturePileImpl::CreateFromPile(white_recording.get(), nullptr);
 
   gfx::Transform white_content_to_target_transform;
   SharedQuadState* white_shared_state = CreateTestSharedQuadState(
@@ -1553,12 +1563,14 @@
     canvas.drawPoint(1, 1, SK_ColorGREEN);
   }
 
-  scoped_refptr<FakePicturePileImpl> pile =
-      FakePicturePileImpl::CreateFilledPile(pile_tile_size, viewport.size());
+  scoped_ptr<FakePicturePile> recording =
+      FakePicturePile::CreateFilledPile(pile_tile_size, viewport.size());
   SkPaint paint;
   paint.setFilterLevel(SkPaint::kLow_FilterLevel);
-  pile->add_draw_bitmap_with_paint(bitmap, gfx::Point(), paint);
-  pile->RerecordPile();
+  recording->add_draw_bitmap_with_paint(bitmap, gfx::Point(), paint);
+  recording->RerecordPile();
+  scoped_refptr<FakePicturePileImpl> pile =
+      FakePicturePileImpl::CreateFromPile(recording.get(), nullptr);
 
   gfx::Transform content_to_target_transform;
   SharedQuadState* shared_state = CreateTestSharedQuadState(
@@ -1603,12 +1615,14 @@
     canvas.drawPoint(1, 1, SK_ColorGREEN);
   }
 
-  scoped_refptr<FakePicturePileImpl> pile =
-      FakePicturePileImpl::CreateFilledPile(pile_tile_size, viewport.size());
+  scoped_ptr<FakePicturePile> recording =
+      FakePicturePile::CreateFilledPile(pile_tile_size, viewport.size());
   SkPaint paint;
   paint.setFilterLevel(SkPaint::kLow_FilterLevel);
-  pile->add_draw_bitmap_with_paint(bitmap, gfx::Point(), paint);
-  pile->RerecordPile();
+  recording->add_draw_bitmap_with_paint(bitmap, gfx::Point(), paint);
+  recording->RerecordPile();
+  scoped_refptr<FakePicturePileImpl> pile =
+      FakePicturePileImpl::CreateFromPile(recording.get(), nullptr);
 
   gfx::Transform content_to_target_transform;
   SharedQuadState* shared_state = CreateTestSharedQuadState(
@@ -1705,16 +1719,20 @@
   gfx::Transform green_content_to_target_transform;
   gfx::Rect green_rect1(gfx::Point(80, 0), gfx::Size(20, 100));
   gfx::Rect green_rect2(gfx::Point(0, 80), gfx::Size(100, 20));
-  scoped_refptr<FakePicturePileImpl> green_pile =
-      FakePicturePileImpl::CreateFilledPile(pile_tile_size, viewport.size());
+
+  scoped_ptr<FakePicturePile> green_recording =
+      FakePicturePile::CreateFilledPile(pile_tile_size, viewport.size());
+
   SkPaint red_paint;
   red_paint.setColor(SK_ColorRED);
-  green_pile->add_draw_rect_with_paint(viewport, red_paint);
+  green_recording->add_draw_rect_with_paint(viewport, red_paint);
   SkPaint green_paint;
   green_paint.setColor(SK_ColorGREEN);
-  green_pile->add_draw_rect_with_paint(green_rect1, green_paint);
-  green_pile->add_draw_rect_with_paint(green_rect2, green_paint);
-  green_pile->RerecordPile();
+  green_recording->add_draw_rect_with_paint(green_rect1, green_paint);
+  green_recording->add_draw_rect_with_paint(green_rect2, green_paint);
+  green_recording->RerecordPile();
+  scoped_refptr<FakePicturePileImpl> green_pile =
+      FakePicturePileImpl::CreateFromPile(green_recording.get(), nullptr);
 
   SharedQuadState* top_right_green_shared_quad_state =
       CreateTestSharedQuadState(
@@ -1769,20 +1787,22 @@
   blue_layer_rect1.Inset(inset, inset, inset, inset);
   blue_layer_rect2.Inset(inset, inset, inset, inset);
 
-  scoped_refptr<FakePicturePileImpl> pile =
-      FakePicturePileImpl::CreateFilledPile(pile_tile_size, layer_rect.size());
+  scoped_ptr<FakePicturePile> recording =
+      FakePicturePile::CreateFilledPile(pile_tile_size, layer_rect.size());
 
   Region outside(layer_rect);
   outside.Subtract(gfx::ToEnclosingRect(union_layer_rect));
   for (Region::Iterator iter(outside); iter.has_rect(); iter.next()) {
-    pile->add_draw_rect_with_paint(iter.rect(), red_paint);
+    recording->add_draw_rect_with_paint(iter.rect(), red_paint);
   }
 
   SkPaint blue_paint;
   blue_paint.setColor(SK_ColorBLUE);
-  pile->add_draw_rect_with_paint(blue_layer_rect1, blue_paint);
-  pile->add_draw_rect_with_paint(blue_layer_rect2, blue_paint);
-  pile->RerecordPile();
+  recording->add_draw_rect_with_paint(blue_layer_rect1, blue_paint);
+  recording->add_draw_rect_with_paint(blue_layer_rect2, blue_paint);
+  recording->RerecordPile();
+  scoped_refptr<FakePicturePileImpl> pile =
+      FakePicturePileImpl::CreateFromPile(recording.get(), nullptr);
 
   gfx::Rect content_rect(
       gfx::ScaleToEnclosingRect(layer_rect, contents_scale));
@@ -1993,12 +2013,14 @@
       CreateTestRenderPass(id, viewport, transform_to_root);
 
   // One viewport-filling blue quad
-  scoped_refptr<FakePicturePileImpl> blue_pile =
-      FakePicturePileImpl::CreateFilledPile(pile_tile_size, viewport.size());
+  scoped_ptr<FakePicturePile> blue_recording =
+      FakePicturePile::CreateFilledPile(pile_tile_size, viewport.size());
   SkPaint blue_paint;
   blue_paint.setColor(SK_ColorBLUE);
-  blue_pile->add_draw_rect_with_paint(viewport, blue_paint);
-  blue_pile->RerecordPile();
+  blue_recording->add_draw_rect_with_paint(viewport, blue_paint);
+  blue_recording->RerecordPile();
+  scoped_refptr<FakePicturePileImpl> blue_pile =
+      FakePicturePileImpl::CreateFromPile(blue_recording.get(), nullptr);
 
   gfx::Transform blue_content_to_target_transform;
   SharedQuadState* blue_shared_state = CreateTestSharedQuadState(
diff --git a/cc/output/shader.cc b/cc/output/shader.cc
index eb0dede..0a33e53 100644
--- a/cc/output/shader.cc
+++ b/cc/output/shader.cc
@@ -11,12 +11,24 @@
 #include "cc/output/gl_renderer.h"  // For the GLC() macro.
 #include "gpu/command_buffer/client/gles2_interface.h"
 
-#define SHADER0(Src) #Src
-#define VERTEX_SHADER(Src) SetVertexTexCoordPrecision(SHADER0(Src))
-#define FRAGMENT_SHADER(Src)    \
-  SetFragmentTexCoordPrecision( \
-      precision,                \
-      SetFragmentSamplerType(sampler, SetBlendModeFunctions(SHADER0(Src))))
+template <size_t size>
+std::string StripLambda(const char(&shader)[size]) {
+  // Must contain at least "[]() {}" and trailing null (included in size).
+  static_assert(size >= 8,
+                "String passed to StripLambda must be at least 8 characters");
+  DCHECK_EQ(strncmp("[]() {", shader, 6), 0);
+  DCHECK_EQ(shader[size - 2], '}');
+  return std::string(shader + 6, shader + size - 2);
+}
+
+// Shaders are passed in with lambda syntax, which tricks clang-format into
+// handling them correctly. StipLambda removes this.
+#define SHADER0(Src) StripLambda(#Src)
+#define VERTEX_SHADER(Head, Body) SetVertexTexCoordPrecision(Head + Body)
+#define FRAGMENT_SHADER(Head, Body) \
+  SetFragmentTexCoordPrecision(     \
+      precision,                    \
+      SetFragmentSamplerType(sampler, SetBlendModeFunctions(Head + Body)))
 
 using gpu::gles2::GLES2Interface;
 
@@ -63,12 +75,13 @@
   return shader_string;
 }
 
-static std::string SetVertexTexCoordPrecision(const char* shader_string) {
+static std::string SetVertexTexCoordPrecision(
+    const std::string& shader_string) {
   // We unconditionally use highp in the vertex shader since
   // we are unlikely to be vertex shader bound when drawing large quads.
   // Also, some vertex shaders mutate the texture coordinate in such a
   // way that the effective precision might be lower than expected.
-  return "#define TexCoordPrecision highp\n" + std::string(shader_string);
+  return "#define TexCoordPrecision highp\n" + shader_string;
 }
 
 TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
@@ -174,20 +187,25 @@
 }
 
 std::string VertexShaderPosTex::GetShaderString() const {
-  // clang-format off
-  return VERTEX_SHADER(
-      // clang-format on
-      attribute vec4 a_position;
-      attribute TexCoordPrecision vec2 a_texCoord;
-      uniform mat4 matrix;
-      varying TexCoordPrecision vec2 v_texCoord;
-      void main() {
-        gl_Position = matrix * a_position;
-        v_texCoord = a_texCoord;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderPosTex::GetShaderHead() {
+  return SHADER0([]() {
+    attribute vec4 a_position;
+    attribute TexCoordPrecision vec2 a_texCoord;
+    uniform mat4 matrix;
+    varying TexCoordPrecision vec2 v_texCoord;
+  });
+}
+
+std::string VertexShaderPosTex::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      gl_Position = matrix * a_position;
+      v_texCoord = a_texCoord;
+    }
+  });
 }
 
 VertexShaderPosTexYUVStretchOffset::VertexShaderPosTexYUVStretchOffset()
@@ -214,23 +232,28 @@
 }
 
 std::string VertexShaderPosTexYUVStretchOffset::GetShaderString() const {
-  // clang-format off
-  return VERTEX_SHADER(
-      // clang-format on
-      precision mediump float;
-      attribute vec4 a_position;
-      attribute TexCoordPrecision vec2 a_texCoord;
-      uniform mat4 matrix;
-      varying TexCoordPrecision vec2 v_texCoord;
-      uniform TexCoordPrecision vec2 texScale;
-      uniform TexCoordPrecision vec2 texOffset;
-      void main() {
-        gl_Position = matrix * a_position;
-        v_texCoord = a_texCoord * texScale + texOffset;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderPosTexYUVStretchOffset::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    attribute vec4 a_position;
+    attribute TexCoordPrecision vec2 a_texCoord;
+    uniform mat4 matrix;
+    varying TexCoordPrecision vec2 v_texCoord;
+    uniform TexCoordPrecision vec2 texScale;
+    uniform TexCoordPrecision vec2 texOffset;
+  });
+}
+
+std::string VertexShaderPosTexYUVStretchOffset::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      gl_Position = matrix * a_position;
+      v_texCoord = a_texCoord * texScale + texOffset;
+    }
+  });
 }
 
 VertexShaderPos::VertexShaderPos() : matrix_location_(-1) {
@@ -254,15 +277,20 @@
 }
 
 std::string VertexShaderPos::GetShaderString() const {
-  // clang-format off
-  return VERTEX_SHADER(
-      // clang-format on
-      attribute vec4 a_position;
-      uniform mat4 matrix;
-      void main() { gl_Position = matrix * a_position; }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderPos::GetShaderHead() {
+  return SHADER0([]() {
+    attribute vec4 a_position;
+    uniform mat4 matrix;
+  });
+}
+
+std::string VertexShaderPos::GetShaderBody() {
+  return SHADER0([]() {
+    void main() { gl_Position = matrix * a_position; }
+  });
 }
 
 VertexShaderPosTexTransform::VertexShaderPosTexTransform()
@@ -291,42 +319,52 @@
 }
 
 std::string VertexShaderPosTexTransform::GetShaderString() const {
-  // clang-format off
-  return VERTEX_SHADER(
-      // clang-format on
-      attribute vec4 a_position;
-      attribute TexCoordPrecision vec2 a_texCoord;
-      attribute float a_index;
-      uniform mat4 matrix[8];
-      uniform TexCoordPrecision vec4 texTransform[8];
-      uniform float opacity[32];
-      varying TexCoordPrecision vec2 v_texCoord;
-      varying float v_alpha;
-      void main() {
-        int quad_index = int(a_index * 0.25);  // NOLINT
-        gl_Position = matrix[quad_index] * a_position;
-        TexCoordPrecision vec4 texTrans = texTransform[quad_index];
-        v_texCoord = a_texCoord * texTrans.zw + texTrans.xy;
-        v_alpha = opacity[int(a_index)];  // NOLINT
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderPosTexTransform::GetShaderHead() {
+  return SHADER0([]() {
+    attribute vec4 a_position;
+    attribute TexCoordPrecision vec2 a_texCoord;
+    attribute float a_index;
+    uniform mat4 matrix[8];
+    uniform TexCoordPrecision vec4 texTransform[8];
+    uniform float opacity[32];
+    varying TexCoordPrecision vec2 v_texCoord;
+    varying float v_alpha;
+  });
+}
+
+std::string VertexShaderPosTexTransform::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      int quad_index = int(a_index * 0.25);  // NOLINT
+      gl_Position = matrix[quad_index] * a_position;
+      TexCoordPrecision vec4 texTrans = texTransform[quad_index];
+      v_texCoord = a_texCoord * texTrans.zw + texTrans.xy;
+      v_alpha = opacity[int(a_index)];  // NOLINT
+    }
+  });
 }
 
 std::string VertexShaderPosTexIdentity::GetShaderString() const {
-  // clang-format off
-  return VERTEX_SHADER(
-      // clang-format on
-      attribute vec4 a_position;
-      varying TexCoordPrecision vec2 v_texCoord;
-      void main() {
-        gl_Position = a_position;
-        v_texCoord = (a_position.xy + vec2(1.0)) * 0.5;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderPosTexIdentity::GetShaderHead() {
+  return SHADER0([]() {
+    attribute vec4 a_position;
+    varying TexCoordPrecision vec2 v_texCoord;
+  });
+}
+
+std::string VertexShaderPosTexIdentity::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      gl_Position = a_position;
+      v_texCoord = (a_position.xy + vec2(1.0)) * 0.5;
+    }
+  });
 }
 
 VertexShaderQuad::VertexShaderQuad()
@@ -352,42 +390,48 @@
 }
 
 std::string VertexShaderQuad::GetShaderString() const {
+  return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderQuad::GetShaderHead() {
 #if defined(OS_ANDROID)
   // TODO(epenner): Find the cause of this 'quad' uniform
   // being missing if we don't add dummy variables.
   // http://crbug.com/240602
-  // clang-format off
-  return VERTEX_SHADER(
-      // clang-format on
-      attribute TexCoordPrecision vec4 a_position;
-      attribute float a_index;
-      uniform mat4 matrix;
-      uniform TexCoordPrecision vec2 quad[4];
-      uniform TexCoordPrecision vec2 dummy_uniform;
-      varying TexCoordPrecision vec2 dummy_varying;
-      void main() {
-        vec2 pos = quad[int(a_index)];  // NOLINT
-        gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
-        dummy_varying = dummy_uniform;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-// clang-format on
+  return SHADER0([]() {
+    attribute TexCoordPrecision vec4 a_position;
+    attribute float a_index;
+    uniform mat4 matrix;
+    uniform TexCoordPrecision vec2 quad[4];
+    uniform TexCoordPrecision vec2 dummy_uniform;
+    varying TexCoordPrecision vec2 dummy_varying;
+  });
 #else
-  // clang-format off
-  return VERTEX_SHADER(
-      // clang-format on
-      attribute TexCoordPrecision vec4 a_position;
-      attribute float a_index;
-      uniform mat4 matrix;
-      uniform TexCoordPrecision vec2 quad[4];
-      void main() {
-        vec2 pos = quad[int(a_index)];  // NOLINT
-        gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-// clang-format on
+  return SHADER0([]() {
+    attribute TexCoordPrecision vec4 a_position;
+    attribute float a_index;
+    uniform mat4 matrix;
+    uniform TexCoordPrecision vec2 quad[4];
+  });
+#endif
+}
+
+std::string VertexShaderQuad::GetShaderBody() {
+#if defined(OS_ANDROID)
+  return SHADER0([]() {
+    void main() {
+      vec2 pos = quad[int(a_index)];  // NOLINT
+      gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
+      dummy_varying = dummy_uniform;
+    }
+  });
+#else
+  return SHADER0([]() {
+    void main() {
+      vec2 pos = quad[int(a_index)];  // NOLINT
+      gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
+    }
+  });
 #endif
 }
 
@@ -419,36 +463,36 @@
 }
 
 std::string VertexShaderQuadAA::GetShaderString() const {
-  // clang-format off
-  return VERTEX_SHADER(
-      // clang-format on
-      attribute TexCoordPrecision vec4 a_position;
-      attribute float a_index;
-      uniform mat4 matrix;
-      uniform vec4 viewport;
-      uniform TexCoordPrecision vec2 quad[4];
-      uniform TexCoordPrecision vec3 edge[8];
-      varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
+  return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
 
-      void main() {
-        vec2 pos = quad[int(a_index)];  // NOLINT
-        gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
-        vec2 ndc_pos = 0.5 * (1.0 + gl_Position.xy / gl_Position.w);
-        vec3 screen_pos = vec3(viewport.xy + viewport.zw * ndc_pos, 1.0);
-        edge_dist[0] = vec4(dot(edge[0], screen_pos),
-                            dot(edge[1], screen_pos),
-                            dot(edge[2], screen_pos),
-                            dot(edge[3], screen_pos)) *
-                       gl_Position.w;
-        edge_dist[1] = vec4(dot(edge[4], screen_pos),
-                            dot(edge[5], screen_pos),
-                            dot(edge[6], screen_pos),
-                            dot(edge[7], screen_pos)) *
-                       gl_Position.w;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+std::string VertexShaderQuadAA::GetShaderHead() {
+  return SHADER0([]() {
+    attribute TexCoordPrecision vec4 a_position;
+    attribute float a_index;
+    uniform mat4 matrix;
+    uniform vec4 viewport;
+    uniform TexCoordPrecision vec2 quad[4];
+    uniform TexCoordPrecision vec3 edge[8];
+    varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
+  });
+}
+
+std::string VertexShaderQuadAA::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec2 pos = quad[int(a_index)];  // NOLINT
+      gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
+      vec2 ndc_pos = 0.5 * (1.0 + gl_Position.xy / gl_Position.w);
+      vec3 screen_pos = vec3(viewport.xy + viewport.zw * ndc_pos, 1.0);
+      edge_dist[0] = vec4(dot(edge[0], screen_pos), dot(edge[1], screen_pos),
+                          dot(edge[2], screen_pos), dot(edge[3], screen_pos)) *
+                     gl_Position.w;
+      edge_dist[1] = vec4(dot(edge[4], screen_pos), dot(edge[5], screen_pos),
+                          dot(edge[6], screen_pos), dot(edge[7], screen_pos)) *
+                     gl_Position.w;
+    }
+  });
 }
 
 VertexShaderQuadTexTransformAA::VertexShaderQuadTexTransformAA()
@@ -481,39 +525,39 @@
 }
 
 std::string VertexShaderQuadTexTransformAA::GetShaderString() const {
-  // clang-format off
-  return VERTEX_SHADER(
-      // clang-format on
-      attribute TexCoordPrecision vec4 a_position;
-      attribute float a_index;
-      uniform mat4 matrix;
-      uniform vec4 viewport;
-      uniform TexCoordPrecision vec2 quad[4];
-      uniform TexCoordPrecision vec3 edge[8];
-      uniform TexCoordPrecision vec4 texTrans;
-      varying TexCoordPrecision vec2 v_texCoord;
-      varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
+  return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
 
-      void main() {
-        vec2 pos = quad[int(a_index)];  // NOLINT
-        gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
-        vec2 ndc_pos = 0.5 * (1.0 + gl_Position.xy / gl_Position.w);
-        vec3 screen_pos = vec3(viewport.xy + viewport.zw * ndc_pos, 1.0);
-        edge_dist[0] = vec4(dot(edge[0], screen_pos),
-                            dot(edge[1], screen_pos),
-                            dot(edge[2], screen_pos),
-                            dot(edge[3], screen_pos)) *
-                       gl_Position.w;
-        edge_dist[1] = vec4(dot(edge[4], screen_pos),
-                            dot(edge[5], screen_pos),
-                            dot(edge[6], screen_pos),
-                            dot(edge[7], screen_pos)) *
-                       gl_Position.w;
-        v_texCoord = (pos.xy + vec2(0.5)) * texTrans.zw + texTrans.xy;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+std::string VertexShaderQuadTexTransformAA::GetShaderHead() {
+  return SHADER0([]() {
+    attribute TexCoordPrecision vec4 a_position;
+    attribute float a_index;
+    uniform mat4 matrix;
+    uniform vec4 viewport;
+    uniform TexCoordPrecision vec2 quad[4];
+    uniform TexCoordPrecision vec3 edge[8];
+    uniform TexCoordPrecision vec4 texTrans;
+    varying TexCoordPrecision vec2 v_texCoord;
+    varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
+  });
+}
+
+std::string VertexShaderQuadTexTransformAA::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec2 pos = quad[int(a_index)];  // NOLINT
+      gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
+      vec2 ndc_pos = 0.5 * (1.0 + gl_Position.xy / gl_Position.w);
+      vec3 screen_pos = vec3(viewport.xy + viewport.zw * ndc_pos, 1.0);
+      edge_dist[0] = vec4(dot(edge[0], screen_pos), dot(edge[1], screen_pos),
+                          dot(edge[2], screen_pos), dot(edge[3], screen_pos)) *
+                     gl_Position.w;
+      edge_dist[1] = vec4(dot(edge[4], screen_pos), dot(edge[5], screen_pos),
+                          dot(edge[6], screen_pos), dot(edge[7], screen_pos)) *
+                     gl_Position.w;
+      v_texCoord = (pos.xy + vec2(0.5)) * texTrans.zw + texTrans.xy;
+    }
+  });
 }
 
 VertexShaderTile::VertexShaderTile()
@@ -542,24 +586,29 @@
 }
 
 std::string VertexShaderTile::GetShaderString() const {
-  // clang-format off
-  return VERTEX_SHADER(
-      // clang-format on
-      attribute TexCoordPrecision vec4 a_position;
-      attribute TexCoordPrecision vec2 a_texCoord;
-      attribute float a_index;
-      uniform mat4 matrix;
-      uniform TexCoordPrecision vec2 quad[4];
-      uniform TexCoordPrecision vec4 vertexTexTransform;
-      varying TexCoordPrecision vec2 v_texCoord;
-      void main() {
-        vec2 pos = quad[int(a_index)];  // NOLINT
-        gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
-        v_texCoord = a_texCoord * vertexTexTransform.zw + vertexTexTransform.xy;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderTile::GetShaderHead() {
+  return SHADER0([]() {
+    attribute TexCoordPrecision vec4 a_position;
+    attribute TexCoordPrecision vec2 a_texCoord;
+    attribute float a_index;
+    uniform mat4 matrix;
+    uniform TexCoordPrecision vec2 quad[4];
+    uniform TexCoordPrecision vec4 vertexTexTransform;
+    varying TexCoordPrecision vec2 v_texCoord;
+  });
+}
+
+std::string VertexShaderTile::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec2 pos = quad[int(a_index)];  // NOLINT
+      gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
+      v_texCoord = a_texCoord * vertexTexTransform.zw + vertexTexTransform.xy;
+    }
+  });
 }
 
 VertexShaderTileAA::VertexShaderTileAA()
@@ -592,39 +641,39 @@
 }
 
 std::string VertexShaderTileAA::GetShaderString() const {
-  // clang-format off
-  return VERTEX_SHADER(
-      // clang-format on
-      attribute TexCoordPrecision vec4 a_position;
-      attribute float a_index;
-      uniform mat4 matrix;
-      uniform vec4 viewport;
-      uniform TexCoordPrecision vec2 quad[4];
-      uniform TexCoordPrecision vec3 edge[8];
-      uniform TexCoordPrecision vec4 vertexTexTransform;
-      varying TexCoordPrecision vec2 v_texCoord;
-      varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
+  return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
 
-      void main() {
-        vec2 pos = quad[int(a_index)];  // NOLINT
-        gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
-        vec2 ndc_pos = 0.5 * (1.0 + gl_Position.xy / gl_Position.w);
-        vec3 screen_pos = vec3(viewport.xy + viewport.zw * ndc_pos, 1.0);
-        edge_dist[0] = vec4(dot(edge[0], screen_pos),
-                            dot(edge[1], screen_pos),
-                            dot(edge[2], screen_pos),
-                            dot(edge[3], screen_pos)) *
-                       gl_Position.w;
-        edge_dist[1] = vec4(dot(edge[4], screen_pos),
-                            dot(edge[5], screen_pos),
-                            dot(edge[6], screen_pos),
-                            dot(edge[7], screen_pos)) *
-                       gl_Position.w;
-        v_texCoord = pos.xy * vertexTexTransform.zw + vertexTexTransform.xy;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+std::string VertexShaderTileAA::GetShaderHead() {
+  return SHADER0([]() {
+    attribute TexCoordPrecision vec4 a_position;
+    attribute float a_index;
+    uniform mat4 matrix;
+    uniform vec4 viewport;
+    uniform TexCoordPrecision vec2 quad[4];
+    uniform TexCoordPrecision vec3 edge[8];
+    uniform TexCoordPrecision vec4 vertexTexTransform;
+    varying TexCoordPrecision vec2 v_texCoord;
+    varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
+  });
+}
+
+std::string VertexShaderTileAA::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec2 pos = quad[int(a_index)];  // NOLINT
+      gl_Position = matrix * vec4(pos, a_position.z, a_position.w);
+      vec2 ndc_pos = 0.5 * (1.0 + gl_Position.xy / gl_Position.w);
+      vec3 screen_pos = vec3(viewport.xy + viewport.zw * ndc_pos, 1.0);
+      edge_dist[0] = vec4(dot(edge[0], screen_pos), dot(edge[1], screen_pos),
+                          dot(edge[2], screen_pos), dot(edge[3], screen_pos)) *
+                     gl_Position.w;
+      edge_dist[1] = vec4(dot(edge[4], screen_pos), dot(edge[5], screen_pos),
+                          dot(edge[6], screen_pos), dot(edge[7], screen_pos)) *
+                     gl_Position.w;
+      v_texCoord = pos.xy * vertexTexTransform.zw + vertexTexTransform.xy;
+    }
+  });
 }
 
 VertexShaderVideoTransform::VertexShaderVideoTransform()
@@ -650,22 +699,27 @@
 }
 
 std::string VertexShaderVideoTransform::GetShaderString() const {
-  // clang-format off
-  return VERTEX_SHADER(
-      // clang-format on
-      attribute vec4 a_position;
-      attribute TexCoordPrecision vec2 a_texCoord;
-      uniform mat4 matrix;
-      uniform TexCoordPrecision mat4 texMatrix;
-      varying TexCoordPrecision vec2 v_texCoord;
-      void main() {
-        gl_Position = matrix * a_position;
-        v_texCoord =
-            vec2(texMatrix * vec4(a_texCoord.x, 1.0 - a_texCoord.y, 0.0, 1.0));
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return VERTEX_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string VertexShaderVideoTransform::GetShaderHead() {
+  return SHADER0([]() {
+    attribute vec4 a_position;
+    attribute TexCoordPrecision vec2 a_texCoord;
+    uniform mat4 matrix;
+    uniform TexCoordPrecision mat4 texMatrix;
+    varying TexCoordPrecision vec2 v_texCoord;
+  });
+}
+
+std::string VertexShaderVideoTransform::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      gl_Position = matrix * a_position;
+      v_texCoord =
+          vec2(texMatrix * vec4(a_texCoord.x, 1.0 - a_texCoord.y, 0.0, 1.0));
+    }
+  });
 }
 
 #define BLEND_MODE_UNIFORMS "s_backdropTexture", "backdropRect"
@@ -692,183 +746,166 @@
     return "#define ApplyBlendMode(X) (X)\n" + shader_string;
   }
 
-  // clang-format off
-  static const std::string kFunctionApplyBlendMode = SHADER0(
-      // clang-format on
-      uniform sampler2D s_backdropTexture;
-      uniform TexCoordPrecision vec4 backdropRect;
+  static const std::string kFunctionApplyBlendMode = SHADER0([]() {
+    uniform sampler2D s_backdropTexture;
+    uniform TexCoordPrecision vec4 backdropRect;
 
-      vec4 GetBackdropColor() {
-        TexCoordPrecision vec2 bgTexCoord = gl_FragCoord.xy - backdropRect.xy;
-        bgTexCoord.x /= backdropRect.z;
-        bgTexCoord.y /= backdropRect.w;
-        return texture2D(s_backdropTexture, bgTexCoord);
-      }
+    vec4 GetBackdropColor() {
+      TexCoordPrecision vec2 bgTexCoord = gl_FragCoord.xy - backdropRect.xy;
+      bgTexCoord.x /= backdropRect.z;
+      bgTexCoord.y /= backdropRect.w;
+      return texture2D(s_backdropTexture, bgTexCoord);
+    }
 
-      vec4 ApplyBlendMode(vec4 src) {
-        vec4 dst = GetBackdropColor();
-        return Blend(src, dst);
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+    vec4 ApplyBlendMode(vec4 src) {
+      vec4 dst = GetBackdropColor();
+      return Blend(src, dst);
+    }
+  });
 
   return "precision mediump float;" + GetHelperFunctions() +
          GetBlendFunction() + kFunctionApplyBlendMode + shader_string;
 }
 
 std::string FragmentTexBlendMode::GetHelperFunctions() const {
-  // clang-format off
-  static const std::string kFunctionHardLight = SHADER0(
-      // clang-format on
-      vec3 hardLight(vec4 src, vec4 dst) {
-        vec3 result;
-        result.r =
-            (2.0 * src.r <= src.a)
-                ? (2.0 * src.r * dst.r)
-                : (src.a * dst.a - 2.0 * (dst.a - dst.r) * (src.a - src.r));
-        result.g =
-            (2.0 * src.g <= src.a)
-                ? (2.0 * src.g * dst.g)
-                : (src.a * dst.a - 2.0 * (dst.a - dst.g) * (src.a - src.g));
-        result.b =
-            (2.0 * src.b <= src.a)
-                ? (2.0 * src.b * dst.b)
-                : (src.a * dst.a - 2.0 * (dst.a - dst.b) * (src.a - src.b));
-        result.rgb += src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a);
-        return result;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
+  static const std::string kFunctionHardLight = SHADER0([]() {
+    vec3 hardLight(vec4 src, vec4 dst) {
+      vec3 result;
+      result.r =
+          (2.0 * src.r <= src.a)
+              ? (2.0 * src.r * dst.r)
+              : (src.a * dst.a - 2.0 * (dst.a - dst.r) * (src.a - src.r));
+      result.g =
+          (2.0 * src.g <= src.a)
+              ? (2.0 * src.g * dst.g)
+              : (src.a * dst.a - 2.0 * (dst.a - dst.g) * (src.a - src.g));
+      result.b =
+          (2.0 * src.b <= src.a)
+              ? (2.0 * src.b * dst.b)
+              : (src.a * dst.a - 2.0 * (dst.a - dst.b) * (src.a - src.b));
+      result.rgb += src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a);
+      return result;
+    }
+  });
 
-  static const std::string kFunctionColorDodgeComponent = SHADER0(
-      // clang-format on
-      float getColorDodgeComponent(
-          float srcc, float srca, float dstc, float dsta) {
-        if (0.0 == dstc)
-          return srcc * (1.0 - dsta);
-        float d = srca - srcc;
-        if (0.0 == d)
-          return srca * dsta + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
-        d = min(dsta, dstc * srca / d);
-        return d * srca + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
+  static const std::string kFunctionColorDodgeComponent = SHADER0([]() {
+    float getColorDodgeComponent(float srcc, float srca, float dstc,
+                                 float dsta) {
+      if (0.0 == dstc)
+        return srcc * (1.0 - dsta);
+      float d = srca - srcc;
+      if (0.0 == d)
+        return srca * dsta + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+      d = min(dsta, dstc * srca / d);
+      return d * srca + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+    }
+  });
 
-  static const std::string kFunctionColorBurnComponent = SHADER0(
-      // clang-format on
-      float getColorBurnComponent(
-          float srcc, float srca, float dstc, float dsta) {
-        if (dsta == dstc)
-          return srca * dsta + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
-        if (0.0 == srcc)
-          return dstc * (1.0 - srca);
-        float d = max(0.0, dsta - (dsta - dstc) * srca / srcc);
-        return srca * d + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
+  static const std::string kFunctionColorBurnComponent = SHADER0([]() {
+    float getColorBurnComponent(float srcc, float srca, float dstc,
+                                float dsta) {
+      if (dsta == dstc)
+        return srca * dsta + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+      if (0.0 == srcc)
+        return dstc * (1.0 - srca);
+      float d = max(0.0, dsta - (dsta - dstc) * srca / srcc);
+      return srca * d + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+    }
+  });
 
-  static const std::string kFunctionSoftLightComponentPosDstAlpha = SHADER0(
-      // clang-format on
-      float getSoftLightComponent(
-          float srcc, float srca, float dstc, float dsta) {
-        if (2.0 * srcc <= srca) {
-          return (dstc * dstc * (srca - 2.0 * srcc)) / dsta +
-                 (1.0 - dsta) * srcc + dstc * (-srca + 2.0 * srcc + 1.0);
-        } else if (4.0 * dstc <= dsta) {
-          float DSqd = dstc * dstc;
-          float DCub = DSqd * dstc;
-          float DaSqd = dsta * dsta;
-          float DaCub = DaSqd * dsta;
-          return (-DaCub * srcc +
-                  DaSqd * (srcc - dstc * (3.0 * srca - 6.0 * srcc - 1.0)) +
-                  12.0 * dsta * DSqd * (srca - 2.0 * srcc) -
-                  16.0 * DCub * (srca - 2.0 * srcc)) /
-                 DaSqd;
-        } else {
-          return -sqrt(dsta * dstc) * (srca - 2.0 * srcc) - dsta * srcc +
-                 dstc * (srca - 2.0 * srcc + 1.0) + srcc;
-        }
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-
-  static const std::string kFunctionLum = SHADER0(
-      // clang-format on
-      float luminance(vec3 color) { return dot(vec3(0.3, 0.59, 0.11), color); }
-
-      vec3 set_luminance(vec3 hueSat, float alpha, vec3 lumColor) {
-        float diff = luminance(lumColor - hueSat);
-        vec3 outColor = hueSat + diff;
-        float outLum = luminance(outColor);
-        float minComp = min(min(outColor.r, outColor.g), outColor.b);
-        float maxComp = max(max(outColor.r, outColor.g), outColor.b);
-        if (minComp < 0.0 && outLum != minComp) {
-          outColor = outLum +
-                     ((outColor - vec3(outLum, outLum, outLum)) * outLum) /
-                         (outLum - minComp);
-        }
-        if (maxComp > alpha && maxComp != outLum) {
-          outColor =
-              outLum +
-              ((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) /
-                  (maxComp - outLum);
-        }
-        return outColor;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-
-  static const std::string kFunctionSat = SHADER0(
-      // clang-format on
-      float saturation(vec3 color) {
-        return max(max(color.r, color.g), color.b) -
-               min(min(color.r, color.g), color.b);
-      }
-
-      vec3 set_saturation_helper(
-          float minComp, float midComp, float maxComp, float sat) {
-        if (minComp < maxComp) {
-          vec3 result;
-          result.r = 0.0;
-          result.g = sat * (midComp - minComp) / (maxComp - minComp);
-          result.b = sat;
-          return result;
-        } else {
-          return vec3(0, 0, 0);
-        }
-      }
-
-      vec3 set_saturation(vec3 hueLumColor, vec3 satColor) {
-        float sat = saturation(satColor);
-        if (hueLumColor.r <= hueLumColor.g) {
-          if (hueLumColor.g <= hueLumColor.b) {
-            hueLumColor.rgb = set_saturation_helper(
-                hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);
-          } else if (hueLumColor.r <= hueLumColor.b) {
-            hueLumColor.rbg = set_saturation_helper(
-                hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);
+  static const std::string kFunctionSoftLightComponentPosDstAlpha =
+      SHADER0([]() {
+        float getSoftLightComponent(float srcc, float srca, float dstc,
+                                    float dsta) {
+          if (2.0 * srcc <= srca) {
+            return (dstc * dstc * (srca - 2.0 * srcc)) / dsta +
+                   (1.0 - dsta) * srcc + dstc * (-srca + 2.0 * srcc + 1.0);
+          } else if (4.0 * dstc <= dsta) {
+            float DSqd = dstc * dstc;
+            float DCub = DSqd * dstc;
+            float DaSqd = dsta * dsta;
+            float DaCub = DaSqd * dsta;
+            return (-DaCub * srcc +
+                    DaSqd * (srcc - dstc * (3.0 * srca - 6.0 * srcc - 1.0)) +
+                    12.0 * dsta * DSqd * (srca - 2.0 * srcc) -
+                    16.0 * DCub * (srca - 2.0 * srcc)) /
+                   DaSqd;
           } else {
-            hueLumColor.brg = set_saturation_helper(
-                hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);
+            return -sqrt(dsta * dstc) * (srca - 2.0 * srcc) - dsta * srcc +
+                   dstc * (srca - 2.0 * srcc + 1.0) + srcc;
           }
-        } else if (hueLumColor.r <= hueLumColor.b) {
-          hueLumColor.grb = set_saturation_helper(
-              hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);
-        } else if (hueLumColor.g <= hueLumColor.b) {
-          hueLumColor.gbr = set_saturation_helper(
-              hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);
-        } else {
-          hueLumColor.bgr = set_saturation_helper(
-              hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);
         }
-        return hueLumColor;
+      });
+
+  static const std::string kFunctionLum = SHADER0([]() {
+    float luminance(vec3 color) { return dot(vec3(0.3, 0.59, 0.11), color); }
+
+    vec3 set_luminance(vec3 hueSat, float alpha, vec3 lumColor) {
+      float diff = luminance(lumColor - hueSat);
+      vec3 outColor = hueSat + diff;
+      float outLum = luminance(outColor);
+      float minComp = min(min(outColor.r, outColor.g), outColor.b);
+      float maxComp = max(max(outColor.r, outColor.g), outColor.b);
+      if (minComp < 0.0 && outLum != minComp) {
+        outColor = outLum +
+                   ((outColor - vec3(outLum, outLum, outLum)) * outLum) /
+                       (outLum - minComp);
       }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+      if (maxComp > alpha && maxComp != outLum) {
+        outColor =
+            outLum +
+            ((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) /
+                (maxComp - outLum);
+      }
+      return outColor;
+    }
+  });
+
+  static const std::string kFunctionSat = SHADER0([]() {
+    float saturation(vec3 color) {
+      return max(max(color.r, color.g), color.b) -
+             min(min(color.r, color.g), color.b);
+    }
+
+    vec3 set_saturation_helper(float minComp, float midComp, float maxComp,
+                               float sat) {
+      if (minComp < maxComp) {
+        vec3 result;
+        result.r = 0.0;
+        result.g = sat * (midComp - minComp) / (maxComp - minComp);
+        result.b = sat;
+        return result;
+      } else {
+        return vec3(0, 0, 0);
+      }
+    }
+
+    vec3 set_saturation(vec3 hueLumColor, vec3 satColor) {
+      float sat = saturation(satColor);
+      if (hueLumColor.r <= hueLumColor.g) {
+        if (hueLumColor.g <= hueLumColor.b) {
+          hueLumColor.rgb = set_saturation_helper(hueLumColor.r, hueLumColor.g,
+                                                  hueLumColor.b, sat);
+        } else if (hueLumColor.r <= hueLumColor.b) {
+          hueLumColor.rbg = set_saturation_helper(hueLumColor.r, hueLumColor.b,
+                                                  hueLumColor.g, sat);
+        } else {
+          hueLumColor.brg = set_saturation_helper(hueLumColor.b, hueLumColor.r,
+                                                  hueLumColor.g, sat);
+        }
+      } else if (hueLumColor.r <= hueLumColor.b) {
+        hueLumColor.grb = set_saturation_helper(hueLumColor.g, hueLumColor.r,
+                                                hueLumColor.b, sat);
+      } else if (hueLumColor.g <= hueLumColor.b) {
+        hueLumColor.gbr = set_saturation_helper(hueLumColor.g, hueLumColor.b,
+                                                hueLumColor.r, sat);
+      } else {
+        hueLumColor.bgr = set_saturation_helper(hueLumColor.b, hueLumColor.g,
+                                                hueLumColor.r, sat);
+      }
+      return hueLumColor;
+    }
+  });
 
   switch (blend_mode_) {
     case BlendModeOverlay:
@@ -1048,85 +1085,105 @@
 std::string FragmentShaderRGBATexAlpha::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      varying TexCoordPrecision vec2 v_texCoord;
-      uniform SamplerType s_texture;
-      uniform float alpha;
-      void main() {
-        vec4 texColor = TextureLookup(s_texture, v_texCoord);
-        gl_FragColor = ApplyBlendMode(texColor * alpha);
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexAlpha::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    varying TexCoordPrecision vec2 v_texCoord;
+    uniform SamplerType s_texture;
+    uniform float alpha;
+  });
+}
+
+std::string FragmentShaderRGBATexAlpha::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec4 texColor = TextureLookup(s_texture, v_texCoord);
+      gl_FragColor = ApplyBlendMode(texColor * alpha);
+    }
+  });
 }
 
 std::string FragmentShaderRGBATexColorMatrixAlpha::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      varying TexCoordPrecision vec2 v_texCoord;
-      uniform SamplerType s_texture;
-      uniform float alpha;
-      uniform mat4 colorMatrix;
-      uniform vec4 colorOffset;
-      void main() {
-        vec4 texColor = TextureLookup(s_texture, v_texCoord);
-        float nonZeroAlpha = max(texColor.a, 0.00001);
-        texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
-        texColor = colorMatrix * texColor + colorOffset;
-        texColor.rgb *= texColor.a;
-        texColor = clamp(texColor, 0.0, 1.0);
-        gl_FragColor = ApplyBlendMode(texColor * alpha);
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexColorMatrixAlpha::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    varying TexCoordPrecision vec2 v_texCoord;
+    uniform SamplerType s_texture;
+    uniform float alpha;
+    uniform mat4 colorMatrix;
+    uniform vec4 colorOffset;
+  });
+}
+
+std::string FragmentShaderRGBATexColorMatrixAlpha::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec4 texColor = TextureLookup(s_texture, v_texCoord);
+      float nonZeroAlpha = max(texColor.a, 0.00001);
+      texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
+      texColor = colorMatrix * texColor + colorOffset;
+      texColor.rgb *= texColor.a;
+      texColor = clamp(texColor, 0.0, 1.0);
+      gl_FragColor = ApplyBlendMode(texColor * alpha);
+    }
+  });
 }
 
 std::string FragmentShaderRGBATexVaryingAlpha::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      varying TexCoordPrecision vec2 v_texCoord;
-      varying float v_alpha;
-      uniform SamplerType s_texture;
-      void main() {
-        vec4 texColor = TextureLookup(s_texture, v_texCoord);
-        gl_FragColor = texColor * v_alpha;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexVaryingAlpha::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    varying TexCoordPrecision vec2 v_texCoord;
+    varying float v_alpha;
+    uniform SamplerType s_texture;
+  });
+}
+
+std::string FragmentShaderRGBATexVaryingAlpha::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec4 texColor = TextureLookup(s_texture, v_texCoord);
+      gl_FragColor = texColor * v_alpha;
+    }
+  });
 }
 
 std::string FragmentShaderRGBATexPremultiplyAlpha::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      varying TexCoordPrecision vec2 v_texCoord;
-      varying float v_alpha;
-      uniform SamplerType s_texture;
-      void main() {
-        vec4 texColor = TextureLookup(s_texture, v_texCoord);
-        texColor.rgb *= texColor.a;
-        gl_FragColor = texColor * v_alpha;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexPremultiplyAlpha::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    varying TexCoordPrecision vec2 v_texCoord;
+    varying float v_alpha;
+    uniform SamplerType s_texture;
+  });
+}
+
+std::string FragmentShaderRGBATexPremultiplyAlpha::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec4 texColor = TextureLookup(s_texture, v_texCoord);
+      texColor.rgb *= texColor.a;
+      gl_FragColor = texColor * v_alpha;
+    }
+  });
 }
 
 FragmentTexBackgroundBinding::FragmentTexBackgroundBinding()
@@ -1158,114 +1215,144 @@
 std::string FragmentShaderTexBackgroundVaryingAlpha::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      varying TexCoordPrecision vec2 v_texCoord;
-      varying float v_alpha;
-      uniform vec4 background_color;
-      uniform SamplerType s_texture;
-      void main() {
-        vec4 texColor = TextureLookup(s_texture, v_texCoord);
-        texColor += background_color * (1.0 - texColor.a);
-        gl_FragColor = texColor * v_alpha;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderTexBackgroundVaryingAlpha::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    varying TexCoordPrecision vec2 v_texCoord;
+    varying float v_alpha;
+    uniform vec4 background_color;
+    uniform SamplerType s_texture;
+  });
+}
+
+std::string FragmentShaderTexBackgroundVaryingAlpha::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec4 texColor = TextureLookup(s_texture, v_texCoord);
+      texColor += background_color * (1.0 - texColor.a);
+      gl_FragColor = texColor * v_alpha;
+    }
+  });
 }
 
 std::string FragmentShaderTexBackgroundPremultiplyAlpha::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      varying TexCoordPrecision vec2 v_texCoord;
-      varying float v_alpha;
-      uniform vec4 background_color;
-      uniform SamplerType s_texture;
-      void main() {
-        vec4 texColor = TextureLookup(s_texture, v_texCoord);
-        texColor.rgb *= texColor.a;
-        texColor += background_color * (1.0 - texColor.a);
-        gl_FragColor = texColor * v_alpha;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderTexBackgroundPremultiplyAlpha::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    varying TexCoordPrecision vec2 v_texCoord;
+    varying float v_alpha;
+    uniform vec4 background_color;
+    uniform SamplerType s_texture;
+  });
+}
+
+std::string FragmentShaderTexBackgroundPremultiplyAlpha::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec4 texColor = TextureLookup(s_texture, v_texCoord);
+      texColor.rgb *= texColor.a;
+      texColor += background_color * (1.0 - texColor.a);
+      gl_FragColor = texColor * v_alpha;
+    }
+  });
 }
 
 std::string FragmentShaderRGBATexOpaque::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      varying TexCoordPrecision vec2 v_texCoord;
-      uniform SamplerType s_texture;
-      void main() {
-        vec4 texColor = TextureLookup(s_texture, v_texCoord);
-        gl_FragColor = vec4(texColor.rgb, 1.0);
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexOpaque::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    varying TexCoordPrecision vec2 v_texCoord;
+    uniform SamplerType s_texture;
+  });
+}
+
+std::string FragmentShaderRGBATexOpaque::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec4 texColor = TextureLookup(s_texture, v_texCoord);
+      gl_FragColor = vec4(texColor.rgb, 1.0);
+    }
+  });
 }
 
 std::string FragmentShaderRGBATex::GetShaderString(TexCoordPrecision precision,
                                                    SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      varying TexCoordPrecision vec2 v_texCoord;
-      uniform SamplerType s_texture;
-      void main() { gl_FragColor = TextureLookup(s_texture, v_texCoord); }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATex::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    varying TexCoordPrecision vec2 v_texCoord;
+    uniform SamplerType s_texture;
+  });
+}
+
+std::string FragmentShaderRGBATex::GetShaderBody() {
+  return SHADER0([]() {
+    void main() { gl_FragColor = TextureLookup(s_texture, v_texCoord); }
+  });
 }
 
 std::string FragmentShaderRGBATexSwizzleAlpha::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      varying TexCoordPrecision vec2 v_texCoord;
-      uniform SamplerType s_texture;
-      uniform float alpha;
-      void main() {
-        vec4 texColor = TextureLookup(s_texture, v_texCoord);
-        gl_FragColor =
-            vec4(texColor.z, texColor.y, texColor.x, texColor.w) * alpha;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexSwizzleAlpha::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    varying TexCoordPrecision vec2 v_texCoord;
+    uniform SamplerType s_texture;
+    uniform float alpha;
+  });
+}
+
+std::string FragmentShaderRGBATexSwizzleAlpha::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec4 texColor = TextureLookup(s_texture, v_texCoord);
+      gl_FragColor =
+          vec4(texColor.z, texColor.y, texColor.x, texColor.w) * alpha;
+    }
+  });
 }
 
 std::string FragmentShaderRGBATexSwizzleOpaque::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      varying TexCoordPrecision vec2 v_texCoord;
-      uniform SamplerType s_texture;
-      void main() {
-        vec4 texColor = TextureLookup(s_texture, v_texCoord);
-        gl_FragColor = vec4(texColor.z, texColor.y, texColor.x, 1.0);
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexSwizzleOpaque::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    varying TexCoordPrecision vec2 v_texCoord;
+    uniform SamplerType s_texture;
+  });
+}
+
+std::string FragmentShaderRGBATexSwizzleOpaque::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec4 texColor = TextureLookup(s_texture, v_texCoord);
+      gl_FragColor = vec4(texColor.z, texColor.y, texColor.x, 1.0);
+    }
+  });
 }
 
 FragmentShaderRGBATexAlphaAA::FragmentShaderRGBATexAlphaAA()
@@ -1294,25 +1381,29 @@
 std::string FragmentShaderRGBATexAlphaAA::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      uniform SamplerType s_texture;
-      uniform float alpha;
-      varying TexCoordPrecision vec2 v_texCoord;
-      varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
 
-      void main() {
-        vec4 texColor = TextureLookup(s_texture, v_texCoord);
-        vec4 d4 = min(edge_dist[0], edge_dist[1]);
-        vec2 d2 = min(d4.xz, d4.yw);
-        float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
-        gl_FragColor = ApplyBlendMode(texColor * alpha * aa);
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+std::string FragmentShaderRGBATexAlphaAA::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    uniform SamplerType s_texture;
+    uniform float alpha;
+    varying TexCoordPrecision vec2 v_texCoord;
+    varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
+  });
+}
+
+std::string FragmentShaderRGBATexAlphaAA::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec4 texColor = TextureLookup(s_texture, v_texCoord);
+      vec4 d4 = min(edge_dist[0], edge_dist[1]);
+      vec2 d2 = min(d4.xz, d4.yw);
+      float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
+      gl_FragColor = ApplyBlendMode(texColor * alpha * aa);
+    }
+  });
 }
 
 FragmentTexClampAlphaAABinding::FragmentTexClampAlphaAABinding()
@@ -1343,58 +1434,66 @@
 std::string FragmentShaderRGBATexClampAlphaAA::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      uniform SamplerType s_texture;
-      uniform float alpha;
-      uniform TexCoordPrecision vec4 fragmentTexTransform;
-      varying TexCoordPrecision vec2 v_texCoord;
-      varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
 
-      void main() {
-        TexCoordPrecision vec2 texCoord =
-            clamp(v_texCoord, 0.0, 1.0) * fragmentTexTransform.zw +
-            fragmentTexTransform.xy;
-        vec4 texColor = TextureLookup(s_texture, texCoord);
-        vec4 d4 = min(edge_dist[0], edge_dist[1]);
-        vec2 d2 = min(d4.xz, d4.yw);
-        float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
-        gl_FragColor = texColor * alpha * aa;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+std::string FragmentShaderRGBATexClampAlphaAA::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    uniform SamplerType s_texture;
+    uniform float alpha;
+    uniform TexCoordPrecision vec4 fragmentTexTransform;
+    varying TexCoordPrecision vec2 v_texCoord;
+    varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
+  });
+}
+
+std::string FragmentShaderRGBATexClampAlphaAA::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      TexCoordPrecision vec2 texCoord =
+          clamp(v_texCoord, 0.0, 1.0) * fragmentTexTransform.zw +
+          fragmentTexTransform.xy;
+      vec4 texColor = TextureLookup(s_texture, texCoord);
+      vec4 d4 = min(edge_dist[0], edge_dist[1]);
+      vec2 d2 = min(d4.xz, d4.yw);
+      float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
+      gl_FragColor = texColor * alpha * aa;
+    }
+  });
 }
 
 std::string FragmentShaderRGBATexClampSwizzleAlphaAA::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      uniform SamplerType s_texture;
-      uniform float alpha;
-      uniform TexCoordPrecision vec4 fragmentTexTransform;
-      varying TexCoordPrecision vec2 v_texCoord;
-      varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
 
-      void main() {
-        TexCoordPrecision vec2 texCoord =
-            clamp(v_texCoord, 0.0, 1.0) * fragmentTexTransform.zw +
-            fragmentTexTransform.xy;
-        vec4 texColor = TextureLookup(s_texture, texCoord);
-        vec4 d4 = min(edge_dist[0], edge_dist[1]);
-        vec2 d2 = min(d4.xz, d4.yw);
-        float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
-        gl_FragColor =
-            vec4(texColor.z, texColor.y, texColor.x, texColor.w) * alpha * aa;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+std::string FragmentShaderRGBATexClampSwizzleAlphaAA::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    uniform SamplerType s_texture;
+    uniform float alpha;
+    uniform TexCoordPrecision vec4 fragmentTexTransform;
+    varying TexCoordPrecision vec2 v_texCoord;
+    varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
+  });
+}
+
+std::string FragmentShaderRGBATexClampSwizzleAlphaAA::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      TexCoordPrecision vec2 texCoord =
+          clamp(v_texCoord, 0.0, 1.0) * fragmentTexTransform.zw +
+          fragmentTexTransform.xy;
+      vec4 texColor = TextureLookup(s_texture, texCoord);
+      vec4 d4 = min(edge_dist[0], edge_dist[1]);
+      vec2 d2 = min(d4.xz, d4.yw);
+      float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
+      gl_FragColor =
+          vec4(texColor.z, texColor.y, texColor.x, texColor.w) * alpha * aa;
+    }
+  });
 }
 
 FragmentShaderRGBATexAlphaMask::FragmentShaderRGBATexAlphaMask()
@@ -1434,27 +1533,32 @@
 std::string FragmentShaderRGBATexAlphaMask::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      varying TexCoordPrecision vec2 v_texCoord;
-      uniform sampler2D s_texture;
-      uniform SamplerType s_mask;
-      uniform TexCoordPrecision vec2 maskTexCoordScale;
-      uniform TexCoordPrecision vec2 maskTexCoordOffset;
-      uniform float alpha;
-      void main() {
-        vec4 texColor = texture2D(s_texture, v_texCoord);
-        TexCoordPrecision vec2 maskTexCoord =
-            vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
-                 maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
-        vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
-        gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w);
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexAlphaMask::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    varying TexCoordPrecision vec2 v_texCoord;
+    uniform sampler2D s_texture;
+    uniform SamplerType s_mask;
+    uniform TexCoordPrecision vec2 maskTexCoordScale;
+    uniform TexCoordPrecision vec2 maskTexCoordOffset;
+    uniform float alpha;
+  });
+}
+
+std::string FragmentShaderRGBATexAlphaMask::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec4 texColor = texture2D(s_texture, v_texCoord);
+      TexCoordPrecision vec2 maskTexCoord =
+          vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
+               maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
+      vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
+      gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w);
+    }
+  });
 }
 
 FragmentShaderRGBATexAlphaMaskAA::FragmentShaderRGBATexAlphaMaskAA()
@@ -1495,32 +1599,36 @@
 std::string FragmentShaderRGBATexAlphaMaskAA::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      uniform sampler2D s_texture;
-      uniform SamplerType s_mask;
-      uniform TexCoordPrecision vec2 maskTexCoordScale;
-      uniform TexCoordPrecision vec2 maskTexCoordOffset;
-      uniform float alpha;
-      varying TexCoordPrecision vec2 v_texCoord;
-      varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
 
-      void main() {
-        vec4 texColor = texture2D(s_texture, v_texCoord);
-        TexCoordPrecision vec2 maskTexCoord =
-            vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
-                 maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
-        vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
-        vec4 d4 = min(edge_dist[0], edge_dist[1]);
-        vec2 d2 = min(d4.xz, d4.yw);
-        float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
-        gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w * aa);
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+std::string FragmentShaderRGBATexAlphaMaskAA::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    uniform sampler2D s_texture;
+    uniform SamplerType s_mask;
+    uniform TexCoordPrecision vec2 maskTexCoordScale;
+    uniform TexCoordPrecision vec2 maskTexCoordOffset;
+    uniform float alpha;
+    varying TexCoordPrecision vec2 v_texCoord;
+    varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
+  });
+}
+
+std::string FragmentShaderRGBATexAlphaMaskAA::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec4 texColor = texture2D(s_texture, v_texCoord);
+      TexCoordPrecision vec2 maskTexCoord =
+          vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
+               maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
+      vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
+      vec4 d4 = min(edge_dist[0], edge_dist[1]);
+      vec2 d2 = min(d4.xz, d4.yw);
+      float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
+      gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w * aa);
+    }
+  });
 }
 
 FragmentShaderRGBATexAlphaMaskColorMatrixAA::
@@ -1568,39 +1676,43 @@
 std::string FragmentShaderRGBATexAlphaMaskColorMatrixAA::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      uniform sampler2D s_texture;
-      uniform SamplerType s_mask;
-      uniform vec2 maskTexCoordScale;
-      uniform vec2 maskTexCoordOffset;
-      uniform mat4 colorMatrix;
-      uniform vec4 colorOffset;
-      uniform float alpha;
-      varying TexCoordPrecision vec2 v_texCoord;
-      varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
 
-      void main() {
-        vec4 texColor = texture2D(s_texture, v_texCoord);
-        float nonZeroAlpha = max(texColor.a, 0.00001);
-        texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
-        texColor = colorMatrix * texColor + colorOffset;
-        texColor.rgb *= texColor.a;
-        texColor = clamp(texColor, 0.0, 1.0);
-        TexCoordPrecision vec2 maskTexCoord =
-            vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
-                 maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
-        vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
-        vec4 d4 = min(edge_dist[0], edge_dist[1]);
-        vec2 d2 = min(d4.xz, d4.yw);
-        float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
-        gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w * aa);
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+std::string FragmentShaderRGBATexAlphaMaskColorMatrixAA::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    uniform sampler2D s_texture;
+    uniform SamplerType s_mask;
+    uniform vec2 maskTexCoordScale;
+    uniform vec2 maskTexCoordOffset;
+    uniform mat4 colorMatrix;
+    uniform vec4 colorOffset;
+    uniform float alpha;
+    varying TexCoordPrecision vec2 v_texCoord;
+    varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
+  });
+}
+
+std::string FragmentShaderRGBATexAlphaMaskColorMatrixAA::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec4 texColor = texture2D(s_texture, v_texCoord);
+      float nonZeroAlpha = max(texColor.a, 0.00001);
+      texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
+      texColor = colorMatrix * texColor + colorOffset;
+      texColor.rgb *= texColor.a;
+      texColor = clamp(texColor, 0.0, 1.0);
+      TexCoordPrecision vec2 maskTexCoord =
+          vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
+               maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
+      vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
+      vec4 d4 = min(edge_dist[0], edge_dist[1]);
+      vec2 d2 = min(d4.xz, d4.yw);
+      float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
+      gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w * aa);
+    }
+  });
 }
 
 FragmentShaderRGBATexAlphaColorMatrixAA::
@@ -1635,32 +1747,36 @@
 std::string FragmentShaderRGBATexAlphaColorMatrixAA::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      uniform SamplerType s_texture;
-      uniform float alpha;
-      uniform mat4 colorMatrix;
-      uniform vec4 colorOffset;
-      varying TexCoordPrecision vec2 v_texCoord;
-      varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
 
-      void main() {
-        vec4 texColor = TextureLookup(s_texture, v_texCoord);
-        float nonZeroAlpha = max(texColor.a, 0.00001);
-        texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
-        texColor = colorMatrix * texColor + colorOffset;
-        texColor.rgb *= texColor.a;
-        texColor = clamp(texColor, 0.0, 1.0);
-        vec4 d4 = min(edge_dist[0], edge_dist[1]);
-        vec2 d2 = min(d4.xz, d4.yw);
-        float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
-        gl_FragColor = ApplyBlendMode(texColor * alpha * aa);
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+std::string FragmentShaderRGBATexAlphaColorMatrixAA::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    uniform SamplerType s_texture;
+    uniform float alpha;
+    uniform mat4 colorMatrix;
+    uniform vec4 colorOffset;
+    varying TexCoordPrecision vec2 v_texCoord;
+    varying TexCoordPrecision vec4 edge_dist[2];  // 8 edge distances.
+  });
+}
+
+std::string FragmentShaderRGBATexAlphaColorMatrixAA::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec4 texColor = TextureLookup(s_texture, v_texCoord);
+      float nonZeroAlpha = max(texColor.a, 0.00001);
+      texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
+      texColor = colorMatrix * texColor + colorOffset;
+      texColor.rgb *= texColor.a;
+      texColor = clamp(texColor, 0.0, 1.0);
+      vec4 d4 = min(edge_dist[0], edge_dist[1]);
+      vec2 d2 = min(d4.xz, d4.yw);
+      float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
+      gl_FragColor = ApplyBlendMode(texColor * alpha * aa);
+    }
+  });
 }
 
 FragmentShaderRGBATexAlphaMaskColorMatrix::
@@ -1705,34 +1821,39 @@
 std::string FragmentShaderRGBATexAlphaMaskColorMatrix::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      varying TexCoordPrecision vec2 v_texCoord;
-      uniform sampler2D s_texture;
-      uniform SamplerType s_mask;
-      uniform vec2 maskTexCoordScale;
-      uniform vec2 maskTexCoordOffset;
-      uniform mat4 colorMatrix;
-      uniform vec4 colorOffset;
-      uniform float alpha;
-      void main() {
-        vec4 texColor = texture2D(s_texture, v_texCoord);
-        float nonZeroAlpha = max(texColor.a, 0.00001);
-        texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
-        texColor = colorMatrix * texColor + colorOffset;
-        texColor.rgb *= texColor.a;
-        texColor = clamp(texColor, 0.0, 1.0);
-        TexCoordPrecision vec2 maskTexCoord =
-            vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
-                 maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
-        vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
-        gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w);
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderRGBATexAlphaMaskColorMatrix::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    varying TexCoordPrecision vec2 v_texCoord;
+    uniform sampler2D s_texture;
+    uniform SamplerType s_mask;
+    uniform vec2 maskTexCoordScale;
+    uniform vec2 maskTexCoordOffset;
+    uniform mat4 colorMatrix;
+    uniform vec4 colorOffset;
+    uniform float alpha;
+  });
+}
+
+std::string FragmentShaderRGBATexAlphaMaskColorMatrix::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec4 texColor = texture2D(s_texture, v_texCoord);
+      float nonZeroAlpha = max(texColor.a, 0.00001);
+      texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);
+      texColor = colorMatrix * texColor + colorOffset;
+      texColor.rgb *= texColor.a;
+      texColor = clamp(texColor, 0.0, 1.0);
+      TexCoordPrecision vec2 maskTexCoord =
+          vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
+               maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
+      vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
+      gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w);
+    }
+  });
 }
 
 FragmentShaderYUVVideo::FragmentShaderYUVVideo()
@@ -1774,31 +1895,36 @@
 
 std::string FragmentShaderYUVVideo::GetShaderString(TexCoordPrecision precision,
                                                     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      precision mediump int;
-      varying TexCoordPrecision vec2 v_texCoord;
-      uniform SamplerType y_texture;
-      uniform SamplerType u_texture;
-      uniform SamplerType v_texture;
-      uniform float alpha;
-      uniform vec3 yuv_adj;
-      uniform mat3 yuv_matrix;
-      uniform vec4 clamp_rect;
-      void main() {
-        vec2 clamped = max(clamp_rect.xy, min(clamp_rect.zw, v_texCoord));
-        float y_raw = TextureLookup(y_texture, clamped).x;
-        float u_unsigned = TextureLookup(u_texture, clamped).x;
-        float v_unsigned = TextureLookup(v_texture, clamped).x;
-        vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;
-        vec3 rgb = yuv_matrix * yuv;
-        gl_FragColor = vec4(rgb, 1.0) * alpha;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderYUVVideo::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    precision mediump int;
+    varying TexCoordPrecision vec2 v_texCoord;
+    uniform SamplerType y_texture;
+    uniform SamplerType u_texture;
+    uniform SamplerType v_texture;
+    uniform float alpha;
+    uniform vec3 yuv_adj;
+    uniform mat3 yuv_matrix;
+    uniform vec4 clamp_rect;
+  });
+}
+
+std::string FragmentShaderYUVVideo::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec2 clamped = max(clamp_rect.xy, min(clamp_rect.zw, v_texCoord));
+      float y_raw = TextureLookup(y_texture, clamped).x;
+      float u_unsigned = TextureLookup(u_texture, clamped).x;
+      float v_unsigned = TextureLookup(v_texture, clamped).x;
+      vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;
+      vec3 rgb = yuv_matrix * yuv;
+      gl_FragColor = vec4(rgb, 1.0) * alpha;
+    }
+  });
 }
 
 FragmentShaderYUVAVideo::FragmentShaderYUVAVideo()
@@ -1845,33 +1971,38 @@
 std::string FragmentShaderYUVAVideo::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      precision mediump int;
-      varying TexCoordPrecision vec2 v_texCoord;
-      uniform SamplerType y_texture;
-      uniform SamplerType u_texture;
-      uniform SamplerType v_texture;
-      uniform SamplerType a_texture;
-      uniform float alpha;
-      uniform vec3 yuv_adj;
-      uniform mat3 yuv_matrix;
-      uniform vec4 clamp_rect;
-      void main() {
-        vec2 clamped = max(clamp_rect.xy, min(clamp_rect.zw, v_texCoord));
-        float y_raw = TextureLookup(y_texture, clamped).x;
-        float u_unsigned = TextureLookup(u_texture, clamped).x;
-        float v_unsigned = TextureLookup(v_texture, clamped).x;
-        float a_raw = TextureLookup(a_texture, clamped).x;
-        vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;
-        vec3 rgb = yuv_matrix * yuv;
-        gl_FragColor = vec4(rgb, 1.0) * (alpha * a_raw);
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderYUVAVideo::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    precision mediump int;
+    varying TexCoordPrecision vec2 v_texCoord;
+    uniform SamplerType y_texture;
+    uniform SamplerType u_texture;
+    uniform SamplerType v_texture;
+    uniform SamplerType a_texture;
+    uniform float alpha;
+    uniform vec3 yuv_adj;
+    uniform mat3 yuv_matrix;
+    uniform vec4 clamp_rect;
+  });
+}
+
+std::string FragmentShaderYUVAVideo::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec2 clamped = max(clamp_rect.xy, min(clamp_rect.zw, v_texCoord));
+      float y_raw = TextureLookup(y_texture, clamped).x;
+      float u_unsigned = TextureLookup(u_texture, clamped).x;
+      float v_unsigned = TextureLookup(v_texture, clamped).x;
+      float a_raw = TextureLookup(a_texture, clamped).x;
+      vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;
+      vec3 rgb = yuv_matrix * yuv;
+      gl_FragColor = vec4(rgb, 1.0) * (alpha * a_raw);
+    }
+  });
 }
 
 FragmentShaderColor::FragmentShaderColor() : color_location_(-1) {
@@ -1896,15 +2027,20 @@
 
 std::string FragmentShaderColor::GetShaderString(TexCoordPrecision precision,
                                                  SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      uniform vec4 color;
-      void main() { gl_FragColor = color; }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderColor::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    uniform vec4 color;
+  });
+}
+
+std::string FragmentShaderColor::GetShaderBody() {
+  return SHADER0([]() {
+    void main() { gl_FragColor = color; }
+  });
 }
 
 FragmentShaderColorAA::FragmentShaderColorAA() : color_location_(-1) {
@@ -1929,22 +2065,26 @@
 
 std::string FragmentShaderColorAA::GetShaderString(TexCoordPrecision precision,
                                                    SamplerType sampler) const {
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      uniform vec4 color;
-      varying vec4 edge_dist[2];  // 8 edge distances.
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
 
-      void main() {
-        vec4 d4 = min(edge_dist[0], edge_dist[1]);
-        vec2 d2 = min(d4.xz, d4.yw);
-        float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
-        gl_FragColor = color * aa;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+std::string FragmentShaderColorAA::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    uniform vec4 color;
+    varying vec4 edge_dist[2];  // 8 edge distances.
+  });
+}
+
+std::string FragmentShaderColorAA::GetShaderBody() {
+  return SHADER0([]() {
+    void main() {
+      vec4 d4 = min(edge_dist[0], edge_dist[1]);
+      vec2 d2 = min(d4.xz, d4.yw);
+      float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
+      gl_FragColor = color * aa;
+    }
+  });
 }
 
 FragmentShaderCheckerboard::FragmentShaderCheckerboard()
@@ -1976,30 +2116,35 @@
 std::string FragmentShaderCheckerboard::GetShaderString(
     TexCoordPrecision precision,
     SamplerType sampler) const {
+  return FRAGMENT_SHADER(GetShaderHead(), GetShaderBody());
+}
+
+std::string FragmentShaderCheckerboard::GetShaderHead() {
+  return SHADER0([]() {
+    precision mediump float;
+    precision mediump int;
+    varying vec2 v_texCoord;
+    uniform float alpha;
+    uniform float frequency;
+    uniform vec4 texTransform;
+    uniform vec4 color;
+  });
+}
+
+std::string FragmentShaderCheckerboard::GetShaderBody() {
   // Shader based on Example 13-17 of "OpenGL ES 2.0 Programming Guide"
   // by Munshi, Ginsburg, Shreiner.
-  // clang-format off
-  return FRAGMENT_SHADER(
-      // clang-format on
-      precision mediump float;
-      precision mediump int;
-      varying vec2 v_texCoord;
-      uniform float alpha;
-      uniform float frequency;
-      uniform vec4 texTransform;
-      uniform vec4 color;
-      void main() {
-        vec4 color1 = vec4(1.0, 1.0, 1.0, 1.0);
-        vec4 color2 = color;
-        vec2 texCoord =
-            clamp(v_texCoord, 0.0, 1.0) * texTransform.zw + texTransform.xy;
-        vec2 coord = mod(floor(texCoord * frequency * 2.0), 2.0);
-        float picker = abs(coord.x - coord.y);  // NOLINT
-        gl_FragColor = mix(color1, color2, picker) * alpha;
-      }
-      // clang-format off
-  );  // NOLINT(whitespace/parens)
-  // clang-format on
+  return SHADER0([]() {
+    void main() {
+      vec4 color1 = vec4(1.0, 1.0, 1.0, 1.0);
+      vec4 color2 = color;
+      vec2 texCoord =
+          clamp(v_texCoord, 0.0, 1.0) * texTransform.zw + texTransform.xy;
+      vec2 coord = mod(floor(texCoord * frequency * 2.0), 2.0);
+      float picker = abs(coord.x - coord.y);  // NOLINT
+      gl_FragColor = mix(color1, color2, picker) * alpha;
+    }
+  });
 }
 
 }  // namespace cc
diff --git a/cc/output/shader.h b/cc/output/shader.h
index 5adca47..3c8102e 100644
--- a/cc/output/shader.h
+++ b/cc/output/shader.h
@@ -83,6 +83,8 @@
             unsigned program,
             int* base_uniform_index);
   std::string GetShaderString() const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   int matrix_location() const { return matrix_location_; }
 
@@ -100,6 +102,8 @@
             unsigned program,
             int* base_uniform_index);
   std::string GetShaderString() const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   int matrix_location() const { return matrix_location_; }
   int tex_scale_location() const { return tex_scale_location_; }
@@ -121,6 +125,8 @@
             unsigned program,
             int* base_uniform_index);
   std::string GetShaderString() const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   int matrix_location() const { return matrix_location_; }
 
@@ -136,6 +142,8 @@
             unsigned program,
             int* base_uniform_index) {}
   std::string GetShaderString() const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 };
 
 class VertexShaderPosTexTransform {
@@ -146,6 +154,8 @@
             unsigned program,
             int* base_uniform_index);
   std::string GetShaderString() const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   int matrix_location() const { return matrix_location_; }
   int tex_transform_location() const { return tex_transform_location_; }
@@ -167,6 +177,8 @@
            unsigned program,
            int* base_uniform_index);
   std::string GetShaderString() const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   int matrix_location() const { return matrix_location_; }
   int viewport_location() const { return -1; }
@@ -188,6 +200,8 @@
            unsigned program,
            int* base_uniform_index);
   std::string GetShaderString() const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   int matrix_location() const { return matrix_location_; }
   int viewport_location() const { return viewport_location_; }
@@ -212,6 +226,8 @@
            unsigned program,
            int* base_uniform_index);
   std::string GetShaderString() const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   int matrix_location() const { return matrix_location_; }
   int viewport_location() const { return viewport_location_; }
@@ -237,6 +253,8 @@
             unsigned program,
             int* base_uniform_index);
   std::string GetShaderString() const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   int matrix_location() const { return matrix_location_; }
   int viewport_location() const { return -1; }
@@ -262,6 +280,8 @@
             unsigned program,
             int* base_uniform_index);
   std::string GetShaderString() const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   int matrix_location() const { return matrix_location_; }
   int viewport_location() const { return viewport_location_; }
@@ -289,6 +309,8 @@
             unsigned program,
             int* base_uniform_index);
   std::string GetShaderString() const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   int matrix_location() const { return matrix_location_; }
   int tex_matrix_location() const { return tex_matrix_location_; }
@@ -402,12 +424,16 @@
  public:
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 };
 
 class FragmentShaderRGBATexPremultiplyAlpha : public FragmentTexOpaqueBinding {
  public:
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 };
 
 class FragmentShaderTexBackgroundVaryingAlpha
@@ -415,6 +441,8 @@
  public:
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 };
 
 class FragmentShaderTexBackgroundPremultiplyAlpha
@@ -422,31 +450,41 @@
  public:
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 };
 
 class FragmentShaderRGBATexAlpha : public FragmentTexAlphaBinding {
  public:
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 };
 
 class FragmentShaderRGBATexColorMatrixAlpha
     : public FragmentTexColorMatrixAlphaBinding {
  public:
-    std::string GetShaderString(
-        TexCoordPrecision precision, SamplerType sampler) const;
+  std::string GetShaderString(TexCoordPrecision precision,
+                              SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 };
 
 class FragmentShaderRGBATexOpaque : public FragmentTexOpaqueBinding {
  public:
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 };
 
 class FragmentShaderRGBATex : public FragmentTexOpaqueBinding {
  public:
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 };
 
 // Swizzles the red and blue component of sampled texel with alpha.
@@ -454,6 +492,8 @@
  public:
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 };
 
 // Swizzles the red and blue component of sampled texel without alpha.
@@ -461,6 +501,8 @@
  public:
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 };
 
 class FragmentShaderRGBATexAlphaAA : public FragmentTexBlendMode {
@@ -472,6 +514,8 @@
             int* base_uniform_index);
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   int alpha_location() const { return alpha_location_; }
   int sampler_location() const { return sampler_location_; }
@@ -509,6 +553,8 @@
  public:
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 };
 
 // Swizzles the red and blue component of sampled texel.
@@ -517,6 +563,8 @@
  public:
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 };
 
 class FragmentShaderRGBATexAlphaMask : public FragmentTexBlendMode {
@@ -524,6 +572,8 @@
   FragmentShaderRGBATexAlphaMask();
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   void Init(gpu::gles2::GLES2Interface* context,
             unsigned program,
@@ -553,6 +603,8 @@
   FragmentShaderRGBATexAlphaMaskAA();
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   void Init(gpu::gles2::GLES2Interface* context,
             unsigned program,
@@ -583,6 +635,8 @@
   FragmentShaderRGBATexAlphaMaskColorMatrixAA();
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   void Init(gpu::gles2::GLES2Interface* context,
             unsigned program,
@@ -614,6 +668,8 @@
   FragmentShaderRGBATexAlphaColorMatrixAA();
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   void Init(gpu::gles2::GLES2Interface* context,
             unsigned program,
@@ -635,6 +691,8 @@
   FragmentShaderRGBATexAlphaMaskColorMatrix();
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   void Init(gpu::gles2::GLES2Interface* context,
             unsigned program,
@@ -666,6 +724,8 @@
   FragmentShaderYUVVideo();
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   void Init(gpu::gles2::GLES2Interface* context,
             unsigned program,
@@ -695,6 +755,8 @@
   FragmentShaderYUVAVideo();
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   void Init(gpu::gles2::GLES2Interface* context,
             unsigned program,
@@ -727,6 +789,8 @@
   FragmentShaderColor();
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   void Init(gpu::gles2::GLES2Interface* context,
             unsigned program,
@@ -744,6 +808,8 @@
   FragmentShaderColorAA();
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   void Init(gpu::gles2::GLES2Interface* context,
             unsigned program,
@@ -761,6 +827,8 @@
   FragmentShaderCheckerboard();
   std::string GetShaderString(
       TexCoordPrecision precision, SamplerType sampler) const;
+  static std::string GetShaderHead();
+  static std::string GetShaderBody();
 
   void Init(gpu::gles2::GLES2Interface* context,
             unsigned program,
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc
index ceedac6..488ca09 100644
--- a/cc/output/software_renderer.cc
+++ b/cc/output/software_renderer.cc
@@ -160,6 +160,11 @@
     DrawingFrame* frame,
     const ScopedResource* texture,
     const gfx::Rect& target_rect) {
+  DCHECK(texture->id());
+
+  // Explicitly release lock, otherwise we can crash when try to lock
+  // same texture again.
+  current_framebuffer_lock_ = nullptr;
   current_framebuffer_lock_ = make_scoped_ptr(
       new ResourceProvider::ScopedWriteLockSoftware(
           resource_provider_, texture->id()));
diff --git a/cc/output/software_renderer_unittest.cc b/cc/output/software_renderer_unittest.cc
index 7f689a8..fa25200 100644
--- a/cc/output/software_renderer_unittest.cc
+++ b/cc/output/software_renderer_unittest.cc
@@ -135,7 +135,7 @@
   scoped_ptr<SkBitmap> output =
       DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
   EXPECT_EQ(outer_rect.width(), output->info().fWidth);
-  EXPECT_EQ(outer_rect.width(), output->info().fHeight);
+  EXPECT_EQ(outer_rect.height(), output->info().fHeight);
 
   EXPECT_EQ(SK_ColorYELLOW, output->getColor(0, 0));
   EXPECT_EQ(SK_ColorYELLOW,
@@ -233,7 +233,7 @@
   scoped_ptr<SkBitmap> output =
       DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
   EXPECT_EQ(outer_rect.width(), output->info().fWidth);
-  EXPECT_EQ(outer_rect.width(), output->info().fHeight);
+  EXPECT_EQ(outer_rect.height(), output->info().fHeight);
 
   EXPECT_EQ(SK_ColorYELLOW, output->getColor(0, 0));
   EXPECT_EQ(SK_ColorYELLOW,
@@ -308,7 +308,7 @@
   scoped_ptr<SkBitmap> output =
       DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
   EXPECT_EQ(tile_rect.width(), output->info().fWidth);
-  EXPECT_EQ(tile_rect.width(), output->info().fHeight);
+  EXPECT_EQ(tile_rect.height(), output->info().fHeight);
 
   // Check portion of tile not in visible rect isn't drawn.
   const unsigned int kTransparent = SK_ColorTRANSPARENT;
@@ -350,7 +350,7 @@
   scoped_ptr<SkBitmap> output =
       DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
   EXPECT_EQ(device_viewport_rect.width(), output->info().fWidth);
-  EXPECT_EQ(device_viewport_rect.width(), output->info().fHeight);
+  EXPECT_EQ(device_viewport_rect.height(), output->info().fHeight);
 
   EXPECT_EQ(SK_ColorGREEN, output->getColor(0, 0));
   EXPECT_EQ(SK_ColorGREEN,
@@ -372,7 +372,7 @@
 
   output = DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
   EXPECT_EQ(device_viewport_rect.width(), output->info().fWidth);
-  EXPECT_EQ(device_viewport_rect.width(), output->info().fHeight);
+  EXPECT_EQ(device_viewport_rect.height(), output->info().fHeight);
 
   // If we didn't clear, the borders should still be green.
   EXPECT_EQ(SK_ColorGREEN, output->getColor(0, 0));
@@ -417,7 +417,7 @@
   scoped_ptr<SkBitmap> output =
       DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
   EXPECT_EQ(device_viewport_rect.width(), output->info().fWidth);
-  EXPECT_EQ(device_viewport_rect.width(), output->info().fHeight);
+  EXPECT_EQ(device_viewport_rect.height(), output->info().fHeight);
 
   EXPECT_EQ(SK_ColorGREEN, output->getColor(0, 0));
   EXPECT_EQ(SK_ColorGREEN,
diff --git a/cc/quads/checkerboard_draw_quad.cc b/cc/quads/checkerboard_draw_quad.cc
index 68d81c7..2d8957d 100644
--- a/cc/quads/checkerboard_draw_quad.cc
+++ b/cc/quads/checkerboard_draw_quad.cc
@@ -43,7 +43,8 @@
   return static_cast<const CheckerboardDrawQuad*>(quad);
 }
 
-void CheckerboardDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void CheckerboardDrawQuad::ExtendValue(
+    base::trace_event::TracedValue* value) const {
   value->SetInteger("color", color);
 }
 
diff --git a/cc/quads/checkerboard_draw_quad.h b/cc/quads/checkerboard_draw_quad.h
index 64c583f..1ab6338 100644
--- a/cc/quads/checkerboard_draw_quad.h
+++ b/cc/quads/checkerboard_draw_quad.h
@@ -35,7 +35,7 @@
   static const CheckerboardDrawQuad* MaterialCast(const DrawQuad*);
 
  private:
-  void ExtendValue(base::debug::TracedValue* value) const override;
+  void ExtendValue(base::trace_event::TracedValue* value) const override;
 };
 
 }  // namespace cc
diff --git a/cc/quads/content_draw_quad_base.cc b/cc/quads/content_draw_quad_base.cc
index 171e90d..66fa147 100644
--- a/cc/quads/content_draw_quad_base.cc
+++ b/cc/quads/content_draw_quad_base.cc
@@ -54,7 +54,8 @@
   this->nearest_neighbor = nearest_neighbor;
 }
 
-void ContentDrawQuadBase::ExtendValue(base::debug::TracedValue* value) const {
+void ContentDrawQuadBase::ExtendValue(
+    base::trace_event::TracedValue* value) const {
   MathUtil::AddToTracedValue("tex_coord_rect", tex_coord_rect, value);
   MathUtil::AddToTracedValue("texture_size", texture_size, value);
 
diff --git a/cc/quads/content_draw_quad_base.h b/cc/quads/content_draw_quad_base.h
index 58aa727..8dcd2b9 100644
--- a/cc/quads/content_draw_quad_base.h
+++ b/cc/quads/content_draw_quad_base.h
@@ -45,7 +45,7 @@
  protected:
   ContentDrawQuadBase();
   ~ContentDrawQuadBase() override;
-  void ExtendValue(base::debug::TracedValue* value) const override;
+  void ExtendValue(base::trace_event::TracedValue* value) const override;
 };
 
 }  // namespace cc
diff --git a/cc/quads/debug_border_draw_quad.cc b/cc/quads/debug_border_draw_quad.cc
index 43c7e6a..f91bf3b 100644
--- a/cc/quads/debug_border_draw_quad.cc
+++ b/cc/quads/debug_border_draw_quad.cc
@@ -50,7 +50,8 @@
   return static_cast<const DebugBorderDrawQuad*>(quad);
 }
 
-void DebugBorderDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void DebugBorderDrawQuad::ExtendValue(
+    base::trace_event::TracedValue* value) const {
   value->SetInteger("color", color);
   value->SetInteger("width", width);
 }
diff --git a/cc/quads/debug_border_draw_quad.h b/cc/quads/debug_border_draw_quad.h
index a511ce1..7ee0d82 100644
--- a/cc/quads/debug_border_draw_quad.h
+++ b/cc/quads/debug_border_draw_quad.h
@@ -38,7 +38,7 @@
   static const DebugBorderDrawQuad* MaterialCast(const DrawQuad*);
 
  private:
-  void ExtendValue(base::debug::TracedValue* value) const override;
+  void ExtendValue(base::trace_event::TracedValue* value) const override;
 };
 
 }  // namespace cc
diff --git a/cc/quads/draw_quad.cc b/cc/quads/draw_quad.cc
index 402dffe..8b8fd78 100644
--- a/cc/quads/draw_quad.cc
+++ b/cc/quads/draw_quad.cc
@@ -57,7 +57,7 @@
 DrawQuad::~DrawQuad() {
 }
 
-void DrawQuad::AsValueInto(base::debug::TracedValue* value) const {
+void DrawQuad::AsValueInto(base::trace_event::TracedValue* value) const {
   value->SetInteger("material", material);
   TracedValue::SetIDRef(shared_quad_state, value, "shared_state");
 
diff --git a/cc/quads/draw_quad.h b/cc/quads/draw_quad.h
index d9395cd..3897d1d 100644
--- a/cc/quads/draw_quad.h
+++ b/cc/quads/draw_quad.h
@@ -14,15 +14,9 @@
 namespace trace_event {
 class TracedValue;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::TracedValue;
-}
 class Value;
 class DictionaryValue;
-}  // namespace base
+}
 
 namespace cc {
 
@@ -132,7 +126,7 @@
     return IsLeftEdge() || IsTopEdge() || IsRightEdge() || IsBottomEdge();
   }
 
-  void AsValueInto(base::debug::TracedValue* value) const;
+  void AsValueInto(base::trace_event::TracedValue* value) const;
 
  protected:
   DrawQuad();
@@ -143,7 +137,7 @@
               const gfx::Rect& opaque_rect,
               const gfx::Rect& visible_rect,
               bool needs_blending);
-  virtual void ExtendValue(base::debug::TracedValue* value) const = 0;
+  virtual void ExtendValue(base::trace_event::TracedValue* value) const = 0;
 };
 
 }  // namespace cc
diff --git a/cc/quads/io_surface_draw_quad.cc b/cc/quads/io_surface_draw_quad.cc
index 0cc8773..8a37b0a 100644
--- a/cc/quads/io_surface_draw_quad.cc
+++ b/cc/quads/io_surface_draw_quad.cc
@@ -57,7 +57,8 @@
   return static_cast<const IOSurfaceDrawQuad*>(quad);
 }
 
-void IOSurfaceDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void IOSurfaceDrawQuad::ExtendValue(
+    base::trace_event::TracedValue* value) const {
   MathUtil::AddToTracedValue("io_surface_size", io_surface_size, value);
 
   value->SetInteger("io_surface_resource_id", io_surface_resource_id);
diff --git a/cc/quads/io_surface_draw_quad.h b/cc/quads/io_surface_draw_quad.h
index ba64384..2c77905 100644
--- a/cc/quads/io_surface_draw_quad.h
+++ b/cc/quads/io_surface_draw_quad.h
@@ -48,7 +48,7 @@
   static const IOSurfaceDrawQuad* MaterialCast(const DrawQuad*);
 
  private:
-  void ExtendValue(base::debug::TracedValue* value) const override;
+  void ExtendValue(base::trace_event::TracedValue* value) const override;
 };
 
 }  // namespace cc
diff --git a/cc/quads/list_container_unittest.cc b/cc/quads/list_container_unittest.cc
index d41d8bd..de88750 100644
--- a/cc/quads/list_container_unittest.cc
+++ b/cc/quads/list_container_unittest.cc
@@ -34,7 +34,7 @@
 
   void set_value(int val) { value = val; }
   int get_value() { return value; }
-  void ExtendValue(base::debug::TracedValue* value) const override {}
+  void ExtendValue(base::trace_event::TracedValue* value) const override {}
 
  private:
   int value;
@@ -58,7 +58,7 @@
  public:
   ~MockDrawQuad() override { Destruct(); }
   void IterateResources(const ResourceIteratorCallback& callback) override {}
-  void ExtendValue(base::debug::TracedValue* value) const override {}
+  void ExtendValue(base::trace_event::TracedValue* value) const override {}
   MOCK_METHOD0(Destruct, void());
 };
 
diff --git a/cc/quads/picture_draw_quad.cc b/cc/quads/picture_draw_quad.cc
index f36a782..af6fba1 100644
--- a/cc/quads/picture_draw_quad.cc
+++ b/cc/quads/picture_draw_quad.cc
@@ -84,7 +84,7 @@
   return static_cast<const PictureDrawQuad*>(quad);
 }
 
-void PictureDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void PictureDrawQuad::ExtendValue(base::trace_event::TracedValue* value) const {
   ContentDrawQuadBase::ExtendValue(value);
   MathUtil::AddToTracedValue("content_rect", content_rect, value);
   value->SetDouble("contents_scale", contents_scale);
diff --git a/cc/quads/picture_draw_quad.h b/cc/quads/picture_draw_quad.h
index 624b69c..31e5601 100644
--- a/cc/quads/picture_draw_quad.h
+++ b/cc/quads/picture_draw_quad.h
@@ -57,7 +57,7 @@
   static const PictureDrawQuad* MaterialCast(const DrawQuad* quad);
 
  private:
-  void ExtendValue(base::debug::TracedValue* value) const override;
+  void ExtendValue(base::trace_event::TracedValue* value) const override;
 };
 
 }  // namespace cc
diff --git a/cc/quads/render_pass.cc b/cc/quads/render_pass.cc
index 2a6e69f..567145a 100644
--- a/cc/quads/render_pass.cc
+++ b/cc/quads/render_pass.cc
@@ -180,7 +180,7 @@
   DCHECK(shared_quad_state_list.empty());
 }
 
-void RenderPass::AsValueInto(base::debug::TracedValue* value) const {
+void RenderPass::AsValueInto(base::trace_event::TracedValue* value) const {
   MathUtil::AddToTracedValue("output_rect", output_rect, value);
   MathUtil::AddToTracedValue("damage_rect", damage_rect, value);
 
diff --git a/cc/quads/render_pass.h b/cc/quads/render_pass.h
index 8a40f17..46a8084 100644
--- a/cc/quads/render_pass.h
+++ b/cc/quads/render_pass.h
@@ -24,13 +24,7 @@
 class TracedValue;
 }
 class Value;
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::TracedValue;
 }
-}  // namespace base
 
 namespace cc {
 
@@ -83,7 +77,7 @@
               const gfx::Transform& transform_to_root_target,
               bool has_transparent_background);
 
-  void AsValueInto(base::debug::TracedValue* dict) const;
+  void AsValueInto(base::trace_event::TracedValue* dict) const;
 
   SharedQuadState* CreateAndAppendSharedQuadState();
 
diff --git a/cc/quads/render_pass_draw_quad.cc b/cc/quads/render_pass_draw_quad.cc
index 41824c3..963a190 100644
--- a/cc/quads/render_pass_draw_quad.cc
+++ b/cc/quads/render_pass_draw_quad.cc
@@ -95,7 +95,8 @@
   return static_cast<const RenderPassDrawQuad*>(quad);
 }
 
-void RenderPassDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void RenderPassDrawQuad::ExtendValue(
+    base::trace_event::TracedValue* value) const {
   TracedValue::SetIDRef(render_pass_id.AsTracingId(), value, "render_pass_id");
   value->SetInteger("mask_resource_id", mask_resource_id);
   MathUtil::AddToTracedValue("mask_texture_size", mask_texture_size, value);
diff --git a/cc/quads/render_pass_draw_quad.h b/cc/quads/render_pass_draw_quad.h
index 95ca2f2..758b8e8 100644
--- a/cc/quads/render_pass_draw_quad.h
+++ b/cc/quads/render_pass_draw_quad.h
@@ -70,7 +70,7 @@
   static const RenderPassDrawQuad* MaterialCast(const DrawQuad*);
 
  private:
-  void ExtendValue(base::debug::TracedValue* value) const override;
+  void ExtendValue(base::trace_event::TracedValue* value) const override;
 };
 
 }  // namespace cc
diff --git a/cc/quads/shared_quad_state.cc b/cc/quads/shared_quad_state.cc
index 57670c6..5e46fcc 100644
--- a/cc/quads/shared_quad_state.cc
+++ b/cc/quads/shared_quad_state.cc
@@ -46,7 +46,7 @@
   this->sorting_context_id = sorting_context_id;
 }
 
-void SharedQuadState::AsValueInto(base::debug::TracedValue* value) const {
+void SharedQuadState::AsValueInto(base::trace_event::TracedValue* value) const {
   MathUtil::AddToTracedValue("transform", content_to_target_transform, value);
   MathUtil::AddToTracedValue("layer_content_bounds", content_bounds, value);
   MathUtil::AddToTracedValue("layer_visible_content_rect", visible_content_rect,
diff --git a/cc/quads/shared_quad_state.h b/cc/quads/shared_quad_state.h
index 0db23e1..6f0ef92 100644
--- a/cc/quads/shared_quad_state.h
+++ b/cc/quads/shared_quad_state.h
@@ -16,13 +16,7 @@
 class TracedValue;
 }
 class Value;
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::TracedValue;
 }
-}  // namespace base
 
 namespace cc {
 
@@ -46,7 +40,7 @@
               float opacity,
               SkXfermode::Mode blend_mode,
               int sorting_context_id);
-  void AsValueInto(base::debug::TracedValue* dict) const;
+  void AsValueInto(base::trace_event::TracedValue* dict) const;
 
   // Transforms from quad's original content space to its target content space.
   gfx::Transform content_to_target_transform;
diff --git a/cc/quads/solid_color_draw_quad.cc b/cc/quads/solid_color_draw_quad.cc
index 8b856e0..229e98b 100644
--- a/cc/quads/solid_color_draw_quad.cc
+++ b/cc/quads/solid_color_draw_quad.cc
@@ -48,7 +48,8 @@
   return static_cast<const SolidColorDrawQuad*>(quad);
 }
 
-void SolidColorDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void SolidColorDrawQuad::ExtendValue(
+    base::trace_event::TracedValue* value) const {
   value->SetInteger("color", color);
   value->SetBoolean("force_anti_aliasing_off", force_anti_aliasing_off);
 }
diff --git a/cc/quads/solid_color_draw_quad.h b/cc/quads/solid_color_draw_quad.h
index f70e5e3..f0f5f5a 100644
--- a/cc/quads/solid_color_draw_quad.h
+++ b/cc/quads/solid_color_draw_quad.h
@@ -38,7 +38,7 @@
   static const SolidColorDrawQuad* MaterialCast(const DrawQuad*);
 
  private:
-  void ExtendValue(base::debug::TracedValue* value) const override;
+  void ExtendValue(base::trace_event::TracedValue* value) const override;
 };
 
 }  // namespace cc
diff --git a/cc/quads/stream_video_draw_quad.cc b/cc/quads/stream_video_draw_quad.cc
index 3f12d39..fb6f728 100644
--- a/cc/quads/stream_video_draw_quad.cc
+++ b/cc/quads/stream_video_draw_quad.cc
@@ -50,7 +50,8 @@
   return static_cast<const StreamVideoDrawQuad*>(quad);
 }
 
-void StreamVideoDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void StreamVideoDrawQuad::ExtendValue(
+    base::trace_event::TracedValue* value) const {
   value->SetInteger("resource_id", resource_id);
   MathUtil::AddToTracedValue("matrix", matrix, value);
 }
diff --git a/cc/quads/stream_video_draw_quad.h b/cc/quads/stream_video_draw_quad.h
index cdba60c..45c28f2 100644
--- a/cc/quads/stream_video_draw_quad.h
+++ b/cc/quads/stream_video_draw_quad.h
@@ -39,7 +39,7 @@
   static const StreamVideoDrawQuad* MaterialCast(const DrawQuad*);
 
  private:
-  void ExtendValue(base::debug::TracedValue* value) const override;
+  void ExtendValue(base::trace_event::TracedValue* value) const override;
 };
 
 }  // namespace cc
diff --git a/cc/quads/surface_draw_quad.cc b/cc/quads/surface_draw_quad.cc
index 7ed193c..5823558 100644
--- a/cc/quads/surface_draw_quad.cc
+++ b/cc/quads/surface_draw_quad.cc
@@ -43,7 +43,7 @@
   return static_cast<const SurfaceDrawQuad*>(quad);
 }
 
-void SurfaceDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void SurfaceDrawQuad::ExtendValue(base::trace_event::TracedValue* value) const {
   value->SetInteger("surface_id", surface_id.id);
 }
 
diff --git a/cc/quads/surface_draw_quad.h b/cc/quads/surface_draw_quad.h
index bdf7838..36dc809 100644
--- a/cc/quads/surface_draw_quad.h
+++ b/cc/quads/surface_draw_quad.h
@@ -35,7 +35,7 @@
   static const SurfaceDrawQuad* MaterialCast(const DrawQuad* quad);
 
  private:
-  void ExtendValue(base::debug::TracedValue* value) const override;
+  void ExtendValue(base::trace_event::TracedValue* value) const override;
 };
 
 }  // namespace cc
diff --git a/cc/quads/texture_draw_quad.cc b/cc/quads/texture_draw_quad.cc
index 4169090..318d4f8 100644
--- a/cc/quads/texture_draw_quad.cc
+++ b/cc/quads/texture_draw_quad.cc
@@ -91,7 +91,7 @@
   return static_cast<const TextureDrawQuad*>(quad);
 }
 
-void TextureDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void TextureDrawQuad::ExtendValue(base::trace_event::TracedValue* value) const {
   value->SetInteger("resource_id", resource_id);
   value->SetBoolean("premultiplied_alpha", premultiplied_alpha);
 
diff --git a/cc/quads/texture_draw_quad.h b/cc/quads/texture_draw_quad.h
index 990b276..afac6bf 100644
--- a/cc/quads/texture_draw_quad.h
+++ b/cc/quads/texture_draw_quad.h
@@ -57,7 +57,7 @@
   static const TextureDrawQuad* MaterialCast(const DrawQuad*);
 
  private:
-  void ExtendValue(base::debug::TracedValue* value) const override;
+  void ExtendValue(base::trace_event::TracedValue* value) const override;
 };
 
 }  // namespace cc
diff --git a/cc/quads/tile_draw_quad.cc b/cc/quads/tile_draw_quad.cc
index 5d60bae..fbdae88 100644
--- a/cc/quads/tile_draw_quad.cc
+++ b/cc/quads/tile_draw_quad.cc
@@ -66,7 +66,7 @@
   return static_cast<const TileDrawQuad*>(quad);
 }
 
-void TileDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void TileDrawQuad::ExtendValue(base::trace_event::TracedValue* value) const {
   ContentDrawQuadBase::ExtendValue(value);
   value->SetInteger("resource_id", resource_id);
 }
diff --git a/cc/quads/tile_draw_quad.h b/cc/quads/tile_draw_quad.h
index e668ddb..d7ef20a 100644
--- a/cc/quads/tile_draw_quad.h
+++ b/cc/quads/tile_draw_quad.h
@@ -42,7 +42,7 @@
   static const TileDrawQuad* MaterialCast(const DrawQuad*);
 
  private:
-  void ExtendValue(base::debug::TracedValue* value) const override;
+  void ExtendValue(base::trace_event::TracedValue* value) const override;
 };
 
 }  // namespace cc
diff --git a/cc/quads/yuv_video_draw_quad.cc b/cc/quads/yuv_video_draw_quad.cc
index 38b726d..1d0e2f3 100644
--- a/cc/quads/yuv_video_draw_quad.cc
+++ b/cc/quads/yuv_video_draw_quad.cc
@@ -79,7 +79,8 @@
   return static_cast<const YUVVideoDrawQuad*>(quad);
 }
 
-void YUVVideoDrawQuad::ExtendValue(base::debug::TracedValue* value) const {
+void YUVVideoDrawQuad::ExtendValue(
+    base::trace_event::TracedValue* value) const {
   MathUtil::AddToTracedValue("tex_coord_rect", tex_coord_rect, value);
   MathUtil::AddToTracedValue("tex_size", tex_size, value);
   value->SetInteger("y_plane_resource_id", y_plane_resource_id);
diff --git a/cc/quads/yuv_video_draw_quad.h b/cc/quads/yuv_video_draw_quad.h
index 7ad0ba4..d57d56f 100644
--- a/cc/quads/yuv_video_draw_quad.h
+++ b/cc/quads/yuv_video_draw_quad.h
@@ -63,7 +63,7 @@
   static const YUVVideoDrawQuad* MaterialCast(const DrawQuad*);
 
  private:
-  void ExtendValue(base::debug::TracedValue* value) const override;
+  void ExtendValue(base::trace_event::TracedValue* value) const override;
 };
 
 }  // namespace cc
diff --git a/cc/resources/bitmap_tile_task_worker_pool.cc b/cc/resources/bitmap_tile_task_worker_pool.cc
index 77abd8d..1abbb46 100644
--- a/cc/resources/bitmap_tile_task_worker_pool.cc
+++ b/cc/resources/bitmap_tile_task_worker_pool.cc
@@ -191,10 +191,10 @@
   client_->DidFinishRunningTileTasks(task_set);
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 BitmapTileTaskWorkerPool::StateAsValue() const {
-  scoped_refptr<base::debug::TracedValue> state =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
 
   state->BeginArray("tasks_pending");
   for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set)
diff --git a/cc/resources/bitmap_tile_task_worker_pool.h b/cc/resources/bitmap_tile_task_worker_pool.h
index 20d57d2..3f03c2d 100644
--- a/cc/resources/bitmap_tile_task_worker_pool.h
+++ b/cc/resources/bitmap_tile_task_worker_pool.h
@@ -14,13 +14,7 @@
 namespace trace_event {
 class ConvertableToTraceFormat;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::ConvertableToTraceFormat;
 }
-}  // namespace base
 
 namespace cc {
 class ResourceProvider;
@@ -58,7 +52,8 @@
 
  private:
   void OnTaskSetFinished(TaskSet task_set);
-  scoped_refptr<base::debug::ConvertableToTraceFormat> StateAsValue() const;
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> StateAsValue()
+      const;
 
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
   TaskGraphRunner* task_graph_runner_;
diff --git a/cc/resources/clip_display_item.cc b/cc/resources/clip_display_item.cc
index 5a34dac..b124ba1 100644
--- a/cc/resources/clip_display_item.cc
+++ b/cc/resources/clip_display_item.cc
@@ -53,7 +53,7 @@
   return total_size;
 }
 
-void ClipDisplayItem::AsValueInto(base::debug::TracedValue* array) const {
+void ClipDisplayItem::AsValueInto(base::trace_event::TracedValue* array) const {
   std::string value = base::StringPrintf("ClipDisplayItem rect: [%s]",
                                          clip_rect_.ToString().c_str());
   for (const SkRRect& rounded_rect : rounded_clip_rects_) {
@@ -102,7 +102,8 @@
   return 0;
 }
 
-void EndClipDisplayItem::AsValueInto(base::debug::TracedValue* array) const {
+void EndClipDisplayItem::AsValueInto(
+    base::trace_event::TracedValue* array) const {
   array->AppendString("EndClipDisplayItem");
 }
 
diff --git a/cc/resources/clip_display_item.h b/cc/resources/clip_display_item.h
index 70725f3..e5e72bf 100644
--- a/cc/resources/clip_display_item.h
+++ b/cc/resources/clip_display_item.h
@@ -33,7 +33,7 @@
   bool IsSuitableForGpuRasterization() const override;
   int ApproximateOpCount() const override;
   size_t PictureMemoryUsage() const override;
-  void AsValueInto(base::debug::TracedValue* array) const override;
+  void AsValueInto(base::trace_event::TracedValue* array) const override;
 
  protected:
   ClipDisplayItem(gfx::Rect clip_rect,
@@ -57,7 +57,7 @@
   bool IsSuitableForGpuRasterization() const override;
   int ApproximateOpCount() const override;
   size_t PictureMemoryUsage() const override;
-  void AsValueInto(base::debug::TracedValue* array) const override;
+  void AsValueInto(base::trace_event::TracedValue* array) const override;
 
  protected:
   EndClipDisplayItem();
diff --git a/cc/resources/clip_path_display_item.cc b/cc/resources/clip_path_display_item.cc
index 1600e55..275a7ef 100644
--- a/cc/resources/clip_path_display_item.cc
+++ b/cc/resources/clip_path_display_item.cc
@@ -38,7 +38,8 @@
   return total_size;
 }
 
-void ClipPathDisplayItem::AsValueInto(base::debug::TracedValue* array) const {
+void ClipPathDisplayItem::AsValueInto(
+    base::trace_event::TracedValue* array) const {
   array->AppendString(base::StringPrintf("ClipPathDisplayItem length: %d",
                                          clip_path_.countPoints()));
 }
@@ -67,7 +68,7 @@
 }
 
 void EndClipPathDisplayItem::AsValueInto(
-    base::debug::TracedValue* array) const {
+    base::trace_event::TracedValue* array) const {
   array->AppendString("EndClipPathDisplayItem");
 }
 
diff --git a/cc/resources/clip_path_display_item.h b/cc/resources/clip_path_display_item.h
index b9fa01b..a3f8e0d 100644
--- a/cc/resources/clip_path_display_item.h
+++ b/cc/resources/clip_path_display_item.h
@@ -31,7 +31,7 @@
   bool IsSuitableForGpuRasterization() const override;
   int ApproximateOpCount() const override;
   size_t PictureMemoryUsage() const override;
-  void AsValueInto(base::debug::TracedValue* array) const override;
+  void AsValueInto(base::trace_event::TracedValue* array) const override;
 
  protected:
   ClipPathDisplayItem(const SkPath& path, SkRegion::Op clip_op, bool antialias);
@@ -55,7 +55,7 @@
   bool IsSuitableForGpuRasterization() const override;
   int ApproximateOpCount() const override;
   size_t PictureMemoryUsage() const override;
-  void AsValueInto(base::debug::TracedValue* array) const override;
+  void AsValueInto(base::trace_event::TracedValue* array) const override;
 
  protected:
   EndClipPathDisplayItem();
diff --git a/cc/resources/display_item.h b/cc/resources/display_item.h
index b2c4054..ba4e733 100644
--- a/cc/resources/display_item.h
+++ b/cc/resources/display_item.h
@@ -26,7 +26,7 @@
   virtual bool IsSuitableForGpuRasterization() const = 0;
   virtual int ApproximateOpCount() const = 0;
   virtual size_t PictureMemoryUsage() const = 0;
-  virtual void AsValueInto(base::debug::TracedValue* array) const = 0;
+  virtual void AsValueInto(base::trace_event::TracedValue* array) const = 0;
 
  protected:
   DisplayItem();
diff --git a/cc/resources/display_item_list.cc b/cc/resources/display_item_list.cc
index 7a6929a..ac6ab57 100644
--- a/cc/resources/display_item_list.cc
+++ b/cc/resources/display_item_list.cc
@@ -65,10 +65,10 @@
   return total_size;
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat> DisplayItemList::AsValue()
-    const {
-  scoped_refptr<base::debug::TracedValue> state =
-      new base::debug::TracedValue();
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+DisplayItemList::AsValue() const {
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
 
   state->SetInteger("length", items_.size());
   state->BeginArray("params.items");
diff --git a/cc/resources/display_item_list.h b/cc/resources/display_item_list.h
index 2147848..e16b8b8 100644
--- a/cc/resources/display_item_list.h
+++ b/cc/resources/display_item_list.h
@@ -36,7 +36,7 @@
   int ApproximateOpCount() const;
   size_t PictureMemoryUsage() const;
 
-  scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
 
   void EmitTraceSnapshot() const;
 
diff --git a/cc/resources/display_item_list_unittest.cc b/cc/resources/display_item_list_unittest.cc
index d6455a2..ddf2cb7 100644
--- a/cc/resources/display_item_list_unittest.cc
+++ b/cc/resources/display_item_list_unittest.cc
@@ -6,8 +6,11 @@
 
 #include <vector>
 
+#include "cc/output/filter_operation.h"
+#include "cc/output/filter_operations.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/test/skia_common.h"
 #include "skia/ext/refptr.h"
@@ -16,6 +19,7 @@
 #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 "third_party/skia/include/effects/SkBitmapSource.h"
 #include "ui/gfx/skia_util.h"
 
 namespace cc {
@@ -162,5 +166,50 @@
   EXPECT_EQ(0, memcmp(pixels, expected_pixels, 4 * 100 * 100));
 }
 
+TEST(DisplayItemList, FilterItem) {
+  gfx::Rect layer_rect(100, 100);
+  FilterOperations filters;
+  unsigned char pixels[4 * 100 * 100] = {0};
+  scoped_refptr<DisplayItemList> list = DisplayItemList::Create();
+
+  SkBitmap source_bitmap;
+  source_bitmap.allocN32Pixels(50, 50);
+  SkCanvas source_canvas(source_bitmap);
+  source_canvas.clear(SkColorSetRGB(128, 128, 128));
+
+  // For most SkImageFilters, the |dst| bounds computed by computeFastBounds are
+  // dependent on the provided |src| bounds. This means, for example, that
+  // translating |src| results in a corresponding translation of |dst|. But this
+  // is not the case for all SkImageFilters; for some of them (e.g.
+  // SkBitmapSource), the computation of |dst| in computeFastBounds doesn't
+  // involve |src| at all. Incorrectly assuming such a relationship (e.g. by
+  // translating |dst| after it is computed by computeFastBounds, rather than
+  // translating |src| before it provided to computedFastBounds) can cause
+  // incorrect clipping of filter output. To test for this, we include an
+  // SkBitmapSource filter in |filters|. Here, |src| is |filter_bounds|, defined
+  // below.
+  skia::RefPtr<SkImageFilter> image_filter =
+      skia::AdoptRef(SkBitmapSource::Create(source_bitmap));
+  filters.Append(FilterOperation::CreateReferenceFilter(image_filter));
+  filters.Append(FilterOperation::CreateBrightnessFilter(0.5f));
+  gfx::RectF filter_bounds(10.f, 10.f, 50.f, 50.f);
+  list->AppendItem(FilterDisplayItem::Create(filters, filter_bounds));
+  list->AppendItem(EndFilterDisplayItem::Create());
+
+  DrawDisplayList(pixels, layer_rect, list);
+
+  SkBitmap expected_bitmap;
+  unsigned char expected_pixels[4 * 100 * 100] = {0};
+  SkPaint paint;
+  paint.setColor(SkColorSetRGB(64, 64, 64));
+  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.drawRect(RectFToSkRect(filter_bounds), 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
index 8ae2918..4479a16 100644
--- a/cc/resources/display_list_raster_source.cc
+++ b/cc/resources/display_list_raster_source.cc
@@ -50,8 +50,8 @@
 DisplayListRasterSource::DisplayListRasterSource(
     const DisplayListRecordingSource* other)
     : display_list_(other->display_list_),
-      background_color_(SK_ColorTRANSPARENT),
-      requires_clear_(true),
+      background_color_(other->background_color_),
+      requires_clear_(other->requires_clear_),
       can_use_lcd_text_(other->can_use_lcd_text_),
       is_solid_color_(other->is_solid_color_),
       solid_color_(other->solid_color_),
@@ -178,20 +178,12 @@
   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 {
+    base::trace_event::TracedValue* array) const {
   if (display_list_.get())
     TracedValue::AppendIDRef(display_list_.get(), array);
 }
diff --git a/cc/resources/display_list_raster_source.h b/cc/resources/display_list_raster_source.h
index 8f1fd12..f095231 100644
--- a/cc/resources/display_list_raster_source.h
+++ b/cc/resources/display_list_raster_source.h
@@ -46,11 +46,9 @@
                   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;
+  void AsValueInto(base::trace_event::TracedValue* array) const override;
   skia::RefPtr<SkPicture> GetFlattenedPicture() override;
   size_t GetPictureMemoryUsage() const override;
   bool CanUseLCDText() const override;
@@ -60,16 +58,21 @@
   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_;
+  // These members are const as this raster source may be in use on another
+  // thread and so should not be touched after construction.
+  const scoped_refptr<DisplayItemList> display_list_;
+  const SkColor background_color_;
+  const bool requires_clear_;
+  const bool can_use_lcd_text_;
+  const bool is_solid_color_;
+  const SkColor solid_color_;
+  const gfx::Rect recorded_viewport_;
+  const gfx::Size size_;
+  const bool clear_canvas_with_debug_color_;
+  const int slow_down_raster_scale_factor_for_debug_;
+  // TODO(enne/vmiura): this has a read/write race between raster and compositor
+  // threads with multi-threaded Ganesh.  Make this const or remove it.
+  bool should_attempt_to_use_distance_field_text_;
 
  private:
   // Called when analyzing a tile. We can use AnalysisCanvas as
@@ -84,8 +87,6 @@
                     float contents_scale,
                     bool is_analysis) const;
 
-  bool should_attempt_to_use_distance_field_text_;
-
   DISALLOW_COPY_AND_ASSIGN(DisplayListRasterSource);
 };
 
diff --git a/cc/resources/display_list_recording_source.cc b/cc/resources/display_list_recording_source.cc
index e60e4c1..01a3bce 100644
--- a/cc/resources/display_list_recording_source.cc
+++ b/cc/resources/display_list_recording_source.cc
@@ -29,8 +29,10 @@
 DisplayListRecordingSource::DisplayListRecordingSource()
     : slow_down_raster_scale_factor_for_debug_(0),
       can_use_lcd_text_(true),
+      requires_clear_(false),
       is_solid_color_(false),
       solid_color_(SK_ColorTRANSPARENT),
+      background_color_(SK_ColorTRANSPARENT),
       pixel_record_distance_(kPixelDistanceToRecord),
       is_suitable_for_gpu_rasterization_(true) {
 }
@@ -60,10 +62,9 @@
   }
 
   gfx::Rect old_recorded_viewport = recorded_viewport_;
-  // TODO(wangxianzhu): Blink slimming paint doesn't support incremental
-  // painting for now so we must record for the whole layer. Should measure
-  // performance and determine the best choice. Consider display item caching.
-  recorded_viewport_ = gfx::Rect(GetSize());
+  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.
@@ -135,6 +136,14 @@
   slow_down_raster_scale_factor_for_debug_ = factor;
 }
 
+void DisplayListRecordingSource::SetBackgroundColor(SkColor background_color) {
+  background_color_ = background_color;
+}
+
+void DisplayListRecordingSource::SetRequiresClear(bool requires_clear) {
+  requires_clear_ = requires_clear;
+}
+
 void DisplayListRecordingSource::SetUnsuitableForGpuRasterizationForTesting() {
   is_suitable_for_gpu_rasterization_ = false;
 }
diff --git a/cc/resources/display_list_recording_source.h b/cc/resources/display_list_recording_source.h
index 05e2ed7..21a24fb 100644
--- a/cc/resources/display_list_recording_source.h
+++ b/cc/resources/display_list_recording_source.h
@@ -29,6 +29,8 @@
   gfx::Size GetSize() const final;
   void SetEmptyBounds() override;
   void SetSlowdownRasterScaleFactor(int factor) override;
+  void SetBackgroundColor(SkColor background_color) override;
+  void SetRequiresClear(bool requires_clear) override;
   bool IsSuitableForGpuRasterization() const override;
   void SetUnsuitableForGpuRasterizationForTesting() override;
   gfx::Size GetTileGridSizeForTesting() const override;
@@ -40,8 +42,10 @@
   gfx::Size size_;
   int slow_down_raster_scale_factor_for_debug_;
   bool can_use_lcd_text_;
+  bool requires_clear_;
   bool is_solid_color_;
   SkColor solid_color_;
+  SkColor background_color_;
   int pixel_record_distance_;
 
   scoped_refptr<DisplayItemList> display_list_;
diff --git a/cc/resources/drawing_display_item.cc b/cc/resources/drawing_display_item.cc
index 351fade..1ef149f 100644
--- a/cc/resources/drawing_display_item.cc
+++ b/cc/resources/drawing_display_item.cc
@@ -62,7 +62,8 @@
   return SkPictureUtils::ApproximateBytesUsed(picture_.get());
 }
 
-void DrawingDisplayItem::AsValueInto(base::debug::TracedValue* array) const {
+void DrawingDisplayItem::AsValueInto(
+    base::trace_event::TracedValue* array) const {
   array->BeginDictionary();
   array->SetString("name", "DrawingDisplayItem");
   array->SetString("location",
diff --git a/cc/resources/drawing_display_item.h b/cc/resources/drawing_display_item.h
index 49aa762..1f63ed3 100644
--- a/cc/resources/drawing_display_item.h
+++ b/cc/resources/drawing_display_item.h
@@ -32,7 +32,7 @@
   bool IsSuitableForGpuRasterization() const override;
   int ApproximateOpCount() const override;
   size_t PictureMemoryUsage() const override;
-  void AsValueInto(base::debug::TracedValue* array) const override;
+  void AsValueInto(base::trace_event::TracedValue* array) const override;
 
  protected:
   DrawingDisplayItem(skia::RefPtr<SkPicture> picture, gfx::PointF location);
diff --git a/cc/resources/eviction_tile_priority_queue.cc b/cc/resources/eviction_tile_priority_queue.cc
index b1ca48d..503b26d 100644
--- a/cc/resources/eviction_tile_priority_queue.cc
+++ b/cc/resources/eviction_tile_priority_queue.cc
@@ -22,21 +22,19 @@
     if (a->IsEmpty() || b->IsEmpty())
       return b->IsEmpty() < a->IsEmpty();
 
-    WhichTree a_tree = a->NextTileIteratorTree(tree_priority_);
+    WhichTree a_tree = a->NextTileIteratorTree();
     const TilingSetEvictionQueue* a_queue =
         a_tree == ACTIVE_TREE ? a->active_queue.get() : a->pending_queue.get();
 
-    WhichTree b_tree = b->NextTileIteratorTree(tree_priority_);
+    WhichTree b_tree = b->NextTileIteratorTree();
     const TilingSetEvictionQueue* b_queue =
         b_tree == ACTIVE_TREE ? b->active_queue.get() : b->pending_queue.get();
 
     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_);
-    const TilePriority& b_priority =
-        b_tile->priority_for_tree_priority(tree_priority_);
+    const TilePriority& a_priority = a_tile->combined_priority();
+    const TilePriority& b_priority = b_tile->combined_priority();
     bool prioritize_low_res = tree_priority_ == SMOOTHNESS_TAKES_PRIORITY;
 
     // If the priority bin differs, b is lower priority if it has the higher
@@ -63,8 +61,8 @@
 
     // Otherwise if the occlusion differs, b is lower priority if it is
     // occluded.
-    bool a_is_occluded = a_tile->is_occluded_for_tree_priority(tree_priority_);
-    bool b_is_occluded = b_tile->is_occluded_for_tree_priority(tree_priority_);
+    bool a_is_occluded = a_tile->is_occluded_combined();
+    bool b_is_occluded = b_tile->is_occluded_combined();
     if (a_is_occluded != b_is_occluded)
       return b_is_occluded;
 
@@ -106,7 +104,7 @@
 
 Tile* EvictionTilePriorityQueue::Top() {
   DCHECK(!IsEmpty());
-  return paired_queues_.front()->Top(tree_priority_);
+  return paired_queues_.front()->Top();
 }
 
 void EvictionTilePriorityQueue::Pop() {
@@ -114,7 +112,7 @@
 
   paired_queues_.pop_heap(EvictionOrderComparator(tree_priority_));
   PairedTilingSetQueue* paired_queue = paired_queues_.back();
-  paired_queue->Pop(tree_priority_);
+  paired_queue->Pop();
   paired_queues_.push_heap(EvictionOrderComparator(tree_priority_));
 }
 
@@ -145,11 +143,10 @@
          (!pending_queue || pending_queue->IsEmpty());
 }
 
-Tile* EvictionTilePriorityQueue::PairedTilingSetQueue::Top(
-    TreePriority tree_priority) {
+Tile* EvictionTilePriorityQueue::PairedTilingSetQueue::Top() {
   DCHECK(!IsEmpty());
 
-  WhichTree next_tree = NextTileIteratorTree(tree_priority);
+  WhichTree next_tree = NextTileIteratorTree();
   TilingSetEvictionQueue* next_queue =
       next_tree == ACTIVE_TREE ? active_queue.get() : pending_queue.get();
   DCHECK(next_queue && !next_queue->IsEmpty());
@@ -159,11 +156,10 @@
   return tile;
 }
 
-void EvictionTilePriorityQueue::PairedTilingSetQueue::Pop(
-    TreePriority tree_priority) {
+void EvictionTilePriorityQueue::PairedTilingSetQueue::Pop() {
   DCHECK(!IsEmpty());
 
-  WhichTree next_tree = NextTileIteratorTree(tree_priority);
+  WhichTree next_tree = NextTileIteratorTree();
   TilingSetEvictionQueue* next_queue =
       next_tree == ACTIVE_TREE ? active_queue.get() : pending_queue.get();
   DCHECK(next_queue && !next_queue->IsEmpty());
@@ -171,12 +167,11 @@
   next_queue->Pop();
 
   // If not empty, use Top to DCHECK the next iterator.
-  DCHECK_IMPLIES(!IsEmpty(), Top(tree_priority));
+  DCHECK_IMPLIES(!IsEmpty(), Top());
 }
 
 WhichTree
-EvictionTilePriorityQueue::PairedTilingSetQueue::NextTileIteratorTree(
-    TreePriority tree_priority) const {
+EvictionTilePriorityQueue::PairedTilingSetQueue::NextTileIteratorTree() const {
   DCHECK(!IsEmpty());
 
   // If we only have one iterator with tiles, return it.
@@ -192,10 +187,8 @@
   if (active_tile == pending_tile)
     return ACTIVE_TREE;
 
-  const TilePriority& active_priority =
-      active_tile->priority_for_tree_priority(tree_priority);
-  const TilePriority& pending_priority =
-      pending_tile->priority_for_tree_priority(tree_priority);
+  const TilePriority& active_priority = active_tile->combined_priority();
+  const TilePriority& pending_priority = pending_tile->combined_priority();
 
   // If the bins are the same and activation differs, then return the tree of
   // the tile not required for activation.
diff --git a/cc/resources/eviction_tile_priority_queue.h b/cc/resources/eviction_tile_priority_queue.h
index ab705f7..32ea9af 100644
--- a/cc/resources/eviction_tile_priority_queue.h
+++ b/cc/resources/eviction_tile_priority_queue.h
@@ -25,10 +25,10 @@
     ~PairedTilingSetQueue();
 
     bool IsEmpty() const;
-    Tile* Top(TreePriority tree_priority);
-    void Pop(TreePriority tree_priority);
+    Tile* Top();
+    void Pop();
 
-    WhichTree NextTileIteratorTree(TreePriority tree_priority) const;
+    WhichTree NextTileIteratorTree() const;
 
     scoped_ptr<TilingSetEvictionQueue> active_queue;
     scoped_ptr<TilingSetEvictionQueue> pending_queue;
diff --git a/cc/resources/filter_display_item.cc b/cc/resources/filter_display_item.cc
index bfdd425..31abf28 100644
--- a/cc/resources/filter_display_item.cc
+++ b/cc/resources/filter_display_item.cc
@@ -6,6 +6,8 @@
 
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event_argument.h"
+#include "cc/output/render_surface_filters.h"
+#include "skia/ext/refptr.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"
@@ -14,9 +16,9 @@
 
 namespace cc {
 
-FilterDisplayItem::FilterDisplayItem(skia::RefPtr<SkImageFilter> filter,
+FilterDisplayItem::FilterDisplayItem(const FilterOperations& filters,
                                      gfx::RectF bounds)
-    : filter_(filter), bounds_(bounds) {
+    : filters_(filters), bounds_(bounds) {
 }
 
 FilterDisplayItem::~FilterDisplayItem() {
@@ -25,14 +27,18 @@
 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());
+
+  skia::RefPtr<SkImageFilter> image_filter =
+      RenderSurfaceFilters::BuildImageFilter(
+          filters_, gfx::SizeF(bounds_.width(), bounds_.height()));
+  SkRect boundaries;
+  image_filter->computeFastBounds(
+      SkRect::MakeWH(bounds_.width(), bounds_.height()), &boundaries);
 
   SkPaint paint;
   paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
-  paint.setImageFilter(filter_.get());
+  paint.setImageFilter(image_filter.get());
   canvas->saveLayer(&boundaries, &paint);
 
   canvas->translate(-bounds_.x(), -bounds_.y());
@@ -50,7 +56,8 @@
   return sizeof(skia::RefPtr<SkImageFilter>) + sizeof(gfx::RectF);
 }
 
-void FilterDisplayItem::AsValueInto(base::debug::TracedValue* array) const {
+void FilterDisplayItem::AsValueInto(
+    base::trace_event::TracedValue* array) const {
   array->AppendString(base::StringPrintf("FilterDisplayItem bounds: [%s]",
                                          bounds_.ToString().c_str()));
 }
@@ -79,7 +86,8 @@
   return 0;
 }
 
-void EndFilterDisplayItem::AsValueInto(base::debug::TracedValue* array) const {
+void EndFilterDisplayItem::AsValueInto(
+    base::trace_event::TracedValue* array) const {
   array->AppendString("EndFilterDisplayItem");
 }
 
diff --git a/cc/resources/filter_display_item.h b/cc/resources/filter_display_item.h
index 958647b..28eeb95 100644
--- a/cc/resources/filter_display_item.h
+++ b/cc/resources/filter_display_item.h
@@ -7,13 +7,12 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "cc/base/cc_export.h"
+#include "cc/output/filter_operations.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 {
 
@@ -21,10 +20,9 @@
  public:
   ~FilterDisplayItem() override;
 
-  static scoped_ptr<FilterDisplayItem> Create(
-      skia::RefPtr<SkImageFilter> filter,
-      gfx::RectF bounds) {
-    return make_scoped_ptr(new FilterDisplayItem(filter, bounds));
+  static scoped_ptr<FilterDisplayItem> Create(const FilterOperations& filters,
+                                              gfx::RectF bounds) {
+    return make_scoped_ptr(new FilterDisplayItem(filters, bounds));
   }
 
   void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
@@ -32,13 +30,13 @@
   bool IsSuitableForGpuRasterization() const override;
   int ApproximateOpCount() const override;
   size_t PictureMemoryUsage() const override;
-  void AsValueInto(base::debug::TracedValue* array) const override;
+  void AsValueInto(base::trace_event::TracedValue* array) const override;
 
  protected:
-  FilterDisplayItem(skia::RefPtr<SkImageFilter> filter, gfx::RectF bounds);
+  FilterDisplayItem(const FilterOperations& filters, gfx::RectF bounds);
 
  private:
-  skia::RefPtr<SkImageFilter> filter_;
+  FilterOperations filters_;
   gfx::RectF bounds_;
 };
 
@@ -55,7 +53,7 @@
   bool IsSuitableForGpuRasterization() const override;
   int ApproximateOpCount() const override;
   size_t PictureMemoryUsage() const override;
-  void AsValueInto(base::debug::TracedValue* array) const override;
+  void AsValueInto(base::trace_event::TracedValue* array) const override;
 
  protected:
   EndFilterDisplayItem();
diff --git a/cc/resources/float_clip_display_item.cc b/cc/resources/float_clip_display_item.cc
index 0cfe463..ba98fe5 100644
--- a/cc/resources/float_clip_display_item.cc
+++ b/cc/resources/float_clip_display_item.cc
@@ -36,7 +36,8 @@
   return sizeof(gfx::RectF);
 }
 
-void FloatClipDisplayItem::AsValueInto(base::debug::TracedValue* array) const {
+void FloatClipDisplayItem::AsValueInto(
+    base::trace_event::TracedValue* array) const {
   array->AppendString(base::StringPrintf("FloatClipDisplayItem rect: [%s]",
                                          clip_rect_.ToString().c_str()));
 }
@@ -65,7 +66,7 @@
 }
 
 void EndFloatClipDisplayItem::AsValueInto(
-    base::debug::TracedValue* array) const {
+    base::trace_event::TracedValue* array) const {
   array->AppendString("EndFloatClipDisplayItem");
 }
 
diff --git a/cc/resources/float_clip_display_item.h b/cc/resources/float_clip_display_item.h
index c9920f2..af88c50 100644
--- a/cc/resources/float_clip_display_item.h
+++ b/cc/resources/float_clip_display_item.h
@@ -30,7 +30,7 @@
   bool IsSuitableForGpuRasterization() const override;
   int ApproximateOpCount() const override;
   size_t PictureMemoryUsage() const override;
-  void AsValueInto(base::debug::TracedValue* array) const override;
+  void AsValueInto(base::trace_event::TracedValue* array) const override;
 
  protected:
   explicit FloatClipDisplayItem(gfx::RectF clip_rect);
@@ -52,7 +52,7 @@
   bool IsSuitableForGpuRasterization() const override;
   int ApproximateOpCount() const override;
   size_t PictureMemoryUsage() const override;
-  void AsValueInto(base::debug::TracedValue* array) const override;
+  void AsValueInto(base::trace_event::TracedValue* array) const override;
 
  protected:
   EndFloatClipDisplayItem();
diff --git a/cc/resources/gpu_rasterizer.cc b/cc/resources/gpu_rasterizer.cc
index 369f12c..e0097f8 100644
--- a/cc/resources/gpu_rasterizer.cc
+++ b/cc/resources/gpu_rasterizer.cc
@@ -43,19 +43,25 @@
                              bool use_distance_field_text,
                              bool threaded_gpu_rasterization_enabled,
                              int msaa_sample_count)
-    : context_provider_(context_provider),
-      resource_provider_(resource_provider),
+    : resource_provider_(resource_provider),
       use_distance_field_text_(use_distance_field_text),
       threaded_gpu_rasterization_enabled_(threaded_gpu_rasterization_enabled),
       msaa_sample_count_(msaa_sample_count) {
-  DCHECK(context_provider_);
 }
 
 GpuRasterizer::~GpuRasterizer() {
 }
 
 PrepareTilesMode GpuRasterizer::GetPrepareTilesMode() {
-  return PrepareTilesMode::PREPARE_NONE;
+  return threaded_gpu_rasterization_enabled_
+             ? PrepareTilesMode::RASTERIZE_PRIORITIZED_TILES
+             : PrepareTilesMode::PREPARE_NONE;
+}
+
+ContextProvider* GpuRasterizer::GetContextProvider(bool worker_context) {
+  return worker_context
+             ? resource_provider_->output_surface()->worker_context_provider()
+             : resource_provider_->output_surface()->context_provider();
 }
 
 void GpuRasterizer::RasterizeTiles(
@@ -63,7 +69,7 @@
     ResourcePool* resource_pool,
     ResourceFormat resource_format,
     const UpdateTileDrawInfoCallback& update_tile_draw_info) {
-  ScopedGpuRaster gpu_raster(context_provider_);
+  ScopedGpuRaster gpu_raster(GetContextProvider(false));
 
   ScopedResourceWriteLocks locks;
 
@@ -86,6 +92,42 @@
   multi_picture_draw_.draw(msaa_sample_count_ > 0);
 }
 
+void GpuRasterizer::RasterizeSource(
+    bool use_worker_context,
+    ResourceProvider::ScopedWriteLockGr* write_lock,
+    const RasterSource* raster_source,
+    const gfx::Rect& rect,
+    float scale) {
+  // Play back raster_source into temp SkPicture.
+  SkPictureRecorder recorder;
+  gfx::Size size = write_lock->resource()->size;
+  const int flags = SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag;
+  skia::RefPtr<SkCanvas> canvas = skia::SharePtr(
+      recorder.beginRecording(size.width(), size.height(), NULL, flags));
+  canvas->save();
+  raster_source->PlaybackToCanvas(canvas.get(), rect, scale);
+  canvas->restore();
+  skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording());
+
+  // Turn on distance fields for layers that have ever animated.
+  bool use_distance_field_text =
+      use_distance_field_text_ ||
+      raster_source->ShouldAttemptToUseDistanceFieldText();
+
+  // Playback picture into resource.
+  {
+    ScopedGpuRaster gpu_raster(GetContextProvider(use_worker_context));
+    write_lock->InitSkSurface(use_worker_context, use_distance_field_text,
+                              raster_source->CanUseLCDText(),
+                              msaa_sample_count_);
+    SkMultiPictureDraw multi_picture_draw;
+    multi_picture_draw.add(write_lock->sk_surface()->getCanvas(),
+                           picture.get());
+    multi_picture_draw.draw(false);
+    write_lock->ReleaseSkSurface();
+  }
+}
+
 void GpuRasterizer::PerformSolidColorAnalysis(
     const Tile* tile,
     RasterSource::SolidColorAnalysis* analysis) {
@@ -119,11 +161,14 @@
       use_distance_field_text_ ||
       tile->raster_source()->ShouldAttemptToUseDistanceFieldText();
   scoped_ptr<ResourceProvider::ScopedWriteLockGr> lock(
-      new ResourceProvider::ScopedWriteLockGr(
-          resource_provider_, resource->id(), use_distance_field_text,
-          tile->raster_source()->CanUseLCDText(), msaa_sample_count_));
+      new ResourceProvider::ScopedWriteLockGr(resource_provider_,
+                                              resource->id()));
 
-  SkSurface* sk_surface = lock->get_sk_surface();
+  lock->InitSkSurface(false, use_distance_field_text,
+                      tile->raster_source()->CanUseLCDText(),
+                      msaa_sample_count_);
+
+  SkSurface* sk_surface = lock->sk_surface();
   if (!sk_surface)
     return;
 
diff --git a/cc/resources/gpu_rasterizer.h b/cc/resources/gpu_rasterizer.h
index 79a0596..8c75f32 100644
--- a/cc/resources/gpu_rasterizer.h
+++ b/cc/resources/gpu_rasterizer.h
@@ -28,6 +28,8 @@
       bool use_distance_field_text,
       bool threaded_gpu_rasterization_enabled,
       int msaa_sample_count);
+
+  // Overriden from Rasterizer.
   PrepareTilesMode GetPrepareTilesMode() override;
   void RasterizeTiles(
       const TileVector& tiles,
@@ -35,6 +37,14 @@
       ResourceFormat resource_format,
       const UpdateTileDrawInfoCallback& update_tile_draw_info) override;
 
+  void RasterizeSource(bool use_worker_context,
+                       ResourceProvider::ScopedWriteLockGr* write_lock,
+                       const RasterSource* raster_source,
+                       const gfx::Rect& rect,
+                       float scale);
+
+  ResourceProvider* resource_provider() { return resource_provider_; }
+
  private:
   GpuRasterizer(ContextProvider* context_provider,
                 ResourceProvider* resource_provider,
@@ -45,13 +55,13 @@
   using ScopedResourceWriteLocks =
       ScopedPtrVector<ResourceProvider::ScopedWriteLockGr>;
 
+  ContextProvider* GetContextProvider(bool worker_context);
   void PerformSolidColorAnalysis(const Tile* tile,
                                  RasterSource::SolidColorAnalysis* analysis);
   void AddToMultiPictureDraw(const Tile* tile,
                              const ScopedResource* resource,
                              ScopedResourceWriteLocks* locks);
 
-  ContextProvider* context_provider_;
   ResourceProvider* resource_provider_;
   SkMultiPictureDraw multi_picture_draw_;
 
diff --git a/cc/resources/gpu_tile_task_worker_pool.cc b/cc/resources/gpu_tile_task_worker_pool.cc
index 8249457..c57d25a 100644
--- a/cc/resources/gpu_tile_task_worker_pool.cc
+++ b/cc/resources/gpu_tile_task_worker_pool.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 
 #include "base/trace_event/trace_event.h"
+#include "cc/resources/gpu_rasterizer.h"
 #include "cc/resources/raster_buffer.h"
 #include "cc/resources/raster_source.h"
 #include "cc/resources/resource.h"
@@ -22,39 +23,64 @@
 
 class RasterBufferImpl : public RasterBuffer {
  public:
-  RasterBufferImpl() {}
+  RasterBufferImpl(GpuRasterizer* rasterizer, const Resource* resource)
+      : rasterizer_(rasterizer),
+        lock_(rasterizer->resource_provider(), resource->id()),
+        resource_(resource) {}
 
   // Overridden from RasterBuffer:
   void Playback(const RasterSource* raster_source,
                 const gfx::Rect& rect,
                 float scale) override {
-    // Don't do anything.
+    TRACE_EVENT0("cc", "RasterBufferImpl::Playback");
+    ContextProvider* context_provider = rasterizer_->resource_provider()
+                                            ->output_surface()
+                                            ->worker_context_provider();
+
+    // The context lock must be held while accessing the context on a
+    // worker thread.
+    base::AutoLock context_lock(*context_provider->GetLock());
+
+    // Allow this worker thread to bind to context_provider.
+    context_provider->DetachFromThread();
+
+    // Rasterize source into resource.
+    rasterizer_->RasterizeSource(true, &lock_, raster_source, rect, scale);
+
+    // Barrier to sync worker context output to cc context.
+    context_provider->ContextGL()->OrderingBarrierCHROMIUM();
+
+    // Allow compositor thread to bind to context_provider.
+    context_provider->DetachFromThread();
   }
 
  private:
+  GpuRasterizer* rasterizer_;
+  ResourceProvider::ScopedWriteLockGr lock_;
+  const Resource* resource_;
+
   DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl);
 };
 
 }  // namespace
+
 // static
 scoped_ptr<TileTaskWorkerPool> GpuTileTaskWorkerPool::Create(
     base::SequencedTaskRunner* task_runner,
     TaskGraphRunner* task_graph_runner,
-    ResourceProvider* resource_provider) {
+    GpuRasterizer* rasterizer) {
   return make_scoped_ptr<TileTaskWorkerPool>(
-      new GpuTileTaskWorkerPool(
-          task_runner, task_graph_runner, resource_provider));
+      new GpuTileTaskWorkerPool(task_runner, task_graph_runner, rasterizer));
 }
 
-// TODO(hendrikw): This class should be removed.  See crbug.com/444938.
 GpuTileTaskWorkerPool::GpuTileTaskWorkerPool(
     base::SequencedTaskRunner* task_runner,
     TaskGraphRunner* task_graph_runner,
-    ResourceProvider* resource_provider)
+    GpuRasterizer* rasterizer)
     : task_runner_(task_runner),
       task_graph_runner_(task_graph_runner),
       namespace_token_(task_graph_runner_->GetNamespaceToken()),
-      resource_provider_(resource_provider),
+      rasterizer_(rasterizer),
       task_set_finished_weak_ptr_factory_(this),
       weak_ptr_factory_(this) {
 }
@@ -129,6 +155,14 @@
   }
 
   ScheduleTasksOnOriginThread(this, &graph_);
+
+  // Barrier to sync any new resources to the worker context.
+  rasterizer_->resource_provider()
+      ->output_surface()
+      ->context_provider()
+      ->ContextGL()
+      ->OrderingBarrierCHROMIUM();
+
   task_graph_runner_->ScheduleTasks(namespace_token_, &graph_);
 
   std::copy(new_task_set_finished_tasks,
@@ -146,7 +180,7 @@
 }
 
 ResourceFormat GpuTileTaskWorkerPool::GetResourceFormat() {
-  return resource_provider_->best_texture_format();
+  return rasterizer_->resource_provider()->best_texture_format();
 }
 
 void GpuTileTaskWorkerPool::CompleteTasks(const Task::Vector& tasks) {
@@ -164,7 +198,8 @@
 
 scoped_ptr<RasterBuffer> GpuTileTaskWorkerPool::AcquireBufferForRaster(
     const Resource* resource) {
-  return make_scoped_ptr<RasterBuffer>(new RasterBufferImpl());
+  return make_scoped_ptr<RasterBuffer>(
+      new RasterBufferImpl(rasterizer_, resource));
 }
 
 void GpuTileTaskWorkerPool::ReleaseBufferForRaster(
diff --git a/cc/resources/gpu_tile_task_worker_pool.h b/cc/resources/gpu_tile_task_worker_pool.h
index 6ac8548..5941852 100644
--- a/cc/resources/gpu_tile_task_worker_pool.h
+++ b/cc/resources/gpu_tile_task_worker_pool.h
@@ -10,7 +10,7 @@
 #include "cc/resources/tile_task_worker_pool.h"
 
 namespace cc {
-class ResourceProvider;
+class GpuRasterizer;
 
 class CC_EXPORT GpuTileTaskWorkerPool : public TileTaskWorkerPool,
                                         public TileTaskRunner,
@@ -21,7 +21,7 @@
   static scoped_ptr<TileTaskWorkerPool> Create(
       base::SequencedTaskRunner* task_runner,
       TaskGraphRunner* task_graph_runner,
-      ResourceProvider* resource_provider);
+      GpuRasterizer* rasterizer);
 
   // Overridden from TileTaskWorkerPool:
   TileTaskRunner* AsTileTaskRunner() override;
@@ -41,7 +41,7 @@
  private:
   GpuTileTaskWorkerPool(base::SequencedTaskRunner* task_runner,
                         TaskGraphRunner* task_graph_runner,
-                        ResourceProvider* resource_provider);
+                        GpuRasterizer* rasterizer);
 
   void OnTaskSetFinished(TaskSet task_set);
   void CompleteTasks(const Task::Vector& tasks);
@@ -50,7 +50,7 @@
   TaskGraphRunner* task_graph_runner_;
   const NamespaceToken namespace_token_;
   TileTaskRunnerClient* client_;
-  ResourceProvider* resource_provider_;
+  GpuRasterizer* rasterizer_;
 
   TaskSetCollection tasks_pending_;
 
diff --git a/cc/resources/one_copy_tile_task_worker_pool.cc b/cc/resources/one_copy_tile_task_worker_pool.cc
index 23c9538..cee568a 100644
--- a/cc/resources/one_copy_tile_task_worker_pool.cc
+++ b/cc/resources/one_copy_tile_task_worker_pool.cc
@@ -467,10 +467,10 @@
   }
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 OneCopyTileTaskWorkerPool::StateAsValue() const {
-  scoped_refptr<base::debug::TracedValue> state =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
 
   state->BeginArray("tasks_pending");
   for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set)
@@ -484,7 +484,7 @@
 }
 
 void OneCopyTileTaskWorkerPool::StagingStateAsValueInto(
-    base::debug::TracedValue* staging_state) const {
+    base::trace_event::TracedValue* staging_state) const {
   staging_state->SetInteger("staging_resource_count",
                             resource_pool_->total_resource_count());
   staging_state->SetInteger("bytes_used_for_staging_resources",
diff --git a/cc/resources/one_copy_tile_task_worker_pool.h b/cc/resources/one_copy_tile_task_worker_pool.h
index 85b3f32..5199667 100644
--- a/cc/resources/one_copy_tile_task_worker_pool.h
+++ b/cc/resources/one_copy_tile_task_worker_pool.h
@@ -19,14 +19,7 @@
 class ConvertableToTraceFormat;
 class TracedValue;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::ConvertableToTraceFormat;
-using ::base::trace_event::TracedValue;
 }
-}  // namespace base
 
 namespace cc {
 class ResourcePool;
@@ -104,8 +97,10 @@
   void ScheduleCheckForCompletedCopyOperationsWithLockAcquired(
       bool wait_if_needed);
   void CheckForCompletedCopyOperations(bool wait_if_needed);
-  scoped_refptr<base::debug::ConvertableToTraceFormat> StateAsValue() const;
-  void StagingStateAsValueInto(base::debug::TracedValue* staging_state) const;
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> StateAsValue()
+      const;
+  void StagingStateAsValueInto(
+      base::trace_event::TracedValue* staging_state) const;
 
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
   TaskGraphRunner* task_graph_runner_;
diff --git a/cc/resources/picture.cc b/cc/resources/picture.cc
index 6bbeeaa..cf5e59b 100644
--- a/cc/resources/picture.cc
+++ b/cc/resources/picture.cc
@@ -461,19 +461,19 @@
   return *this;
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
     Picture::AsTraceableRasterData(float scale) const {
-  scoped_refptr<base::debug::TracedValue> raster_data =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> raster_data =
+      new base::trace_event::TracedValue();
   TracedValue::SetIDRef(this, raster_data.get(), "picture_id");
   raster_data->SetDouble("scale", scale);
   return raster_data;
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
     Picture::AsTraceableRecordData() const {
-  scoped_refptr<base::debug::TracedValue> record_data =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> record_data =
+      new base::trace_event::TracedValue();
   TracedValue::SetIDRef(this, record_data.get(), "picture_id");
   MathUtil::AddToTracedValue("layer_rect", layer_rect_, record_data.get());
   return record_data;
diff --git a/cc/resources/picture.h b/cc/resources/picture.h
index a2a4ec2..81c9c53 100644
--- a/cc/resources/picture.h
+++ b/cc/resources/picture.h
@@ -149,9 +149,9 @@
   gfx::Point max_pixel_cell_;
   gfx::Size cell_size_;
 
-  scoped_refptr<base::debug::ConvertableToTraceFormat>
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat>
     AsTraceableRasterData(float scale) const;
-  scoped_refptr<base::debug::ConvertableToTraceFormat>
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat>
     AsTraceableRecordData() const;
 
   friend class base::RefCountedThreadSafe<Picture>;
diff --git a/cc/resources/picture_layer_tiling.cc b/cc/resources/picture_layer_tiling.cc
index 033f9f6..1e7281d 100644
--- a/cc/resources/picture_layer_tiling.cc
+++ b/cc/resources/picture_layer_tiling.cc
@@ -23,7 +23,8 @@
 namespace cc {
 namespace {
 
-const float kSoonBorderDistanceInScreenPixels = 312.f;
+const float kSoonBorderDistanceViewportPercentage = 0.15f;
+const float kMaxSoonBorderDistanceInScreenPixels = 312.f;
 
 }  // namespace
 
@@ -83,6 +84,17 @@
     it->second->set_shared(false);
 }
 
+// static
+float PictureLayerTiling::CalculateSoonBorderDistance(
+    const gfx::Rect& visible_rect_in_content_space,
+    float content_to_screen_scale) {
+  float max_dimension = std::max(visible_rect_in_content_space.width(),
+                                 visible_rect_in_content_space.height());
+  return std::min(
+      kMaxSoonBorderDistanceInScreenPixels / content_to_screen_scale,
+      max_dimension * kSoonBorderDistanceViewportPercentage);
+}
+
 Tile* PictureLayerTiling::CreateTile(int i,
                                      int j,
                                      const PictureLayerTiling* twin_tiling,
@@ -605,7 +617,8 @@
   // Calculate the soon border rect.
   float content_to_screen_scale = ideal_contents_scale / contents_scale_;
   gfx::Rect soon_border_rect = visible_rect_in_content_space;
-  float border = kSoonBorderDistanceInScreenPixels / content_to_screen_scale;
+  float border = CalculateSoonBorderDistance(visible_rect_in_content_space,
+                                             content_to_screen_scale);
   soon_border_rect.Inset(-border, -border, -border, -border);
 
   last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
@@ -866,7 +879,8 @@
     tiles->insert(it->second.get());
 }
 
-void PictureLayerTiling::AsValueInto(base::debug::TracedValue* state) const {
+void PictureLayerTiling::AsValueInto(
+    base::trace_event::TracedValue* state) const {
   state->SetInteger("num_tiles", tiles_.size());
   state->SetDouble("content_scale", contents_scale_);
   MathUtil::AddToTracedValue("tiling_size", tiling_size(), state);
diff --git a/cc/resources/picture_layer_tiling.h b/cc/resources/picture_layer_tiling.h
index c9672c9..65e7ee0 100644
--- a/cc/resources/picture_layer_tiling.h
+++ b/cc/resources/picture_layer_tiling.h
@@ -24,13 +24,7 @@
 namespace trace_event {
 class TracedValue;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::TracedValue;
 }
-}  // namespace base
 
 namespace cc {
 
@@ -66,6 +60,10 @@
 
   ~PictureLayerTiling();
 
+  static float CalculateSoonBorderDistance(
+      const gfx::Rect& visible_rect_in_content_space,
+      float content_to_screen_scale);
+
   // Create a tiling with no tiles. CreateTile() must be called to add some.
   static scoped_ptr<PictureLayerTiling> Create(
       float contents_scale,
@@ -214,7 +212,7 @@
                                 const Occlusion& occlusion_in_layer_space);
 
   void GetAllTilesForTracing(std::set<const Tile*>* tiles) const;
-  void AsValueInto(base::debug::TracedValue* array) const;
+  void AsValueInto(base::trace_event::TracedValue* array) const;
   size_t GPUMemoryUsageInBytes() const;
 
   struct RectExpansionCache {
diff --git a/cc/resources/picture_layer_tiling_set.cc b/cc/resources/picture_layer_tiling_set.cc
index 7c36a3f..d931543 100644
--- a/cc/resources/picture_layer_tiling_set.cc
+++ b/cc/resources/picture_layer_tiling_set.cc
@@ -65,6 +65,13 @@
   // Copy over tilings that are shared with the |twin_set| tiling set (if it
   // exists).
   if (twin_set) {
+    if (twin_set->tilings_.empty()) {
+      // If the twin (pending) tiling set is empty, it was not updated for the
+      // current frame. So we drop tilings from our set as well, instead of
+      // leaving behind unshared tilings that are all non-ideal.
+      RemoveAllTilings();
+    }
+
     for (PictureLayerTiling* twin_tiling : twin_set->tilings_) {
       float contents_scale = twin_tiling->contents_scale();
       DCHECK_GE(contents_scale, minimum_contents_scale);
@@ -479,7 +486,8 @@
       region_iter_.has_rect();
 }
 
-void PictureLayerTilingSet::AsValueInto(base::debug::TracedValue* state) const {
+void PictureLayerTilingSet::AsValueInto(
+    base::trace_event::TracedValue* state) const {
   for (size_t i = 0; i < tilings_.size(); ++i) {
     state->BeginDictionary();
     tilings_[i]->AsValueInto(state);
diff --git a/cc/resources/picture_layer_tiling_set.h b/cc/resources/picture_layer_tiling_set.h
index 3e31ed9..fc1e581 100644
--- a/cc/resources/picture_layer_tiling_set.h
+++ b/cc/resources/picture_layer_tiling_set.h
@@ -17,13 +17,7 @@
 namespace trace_event {
 class TracedValue;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::TracedValue;
 }
-}  // namespace base
 
 namespace cc {
 
@@ -157,7 +151,7 @@
     Region::Iterator region_iter_;
   };
 
-  void AsValueInto(base::debug::TracedValue* array) const;
+  void AsValueInto(base::trace_event::TracedValue* array) const;
   size_t GPUMemoryUsageInBytes() const;
 
   TilingRange GetTilingRange(TilingRangeType type) const;
diff --git a/cc/resources/picture_layer_tiling_unittest.cc b/cc/resources/picture_layer_tiling_unittest.cc
index fccd3c8..d4a8778 100644
--- a/cc/resources/picture_layer_tiling_unittest.cc
+++ b/cc/resources/picture_layer_tiling_unittest.cc
@@ -691,10 +691,11 @@
   tiling->ComputeTilePriorityRects(viewport, 1.f, 1.0, Occlusion());
   tiling->UpdateAllTilePrioritiesForTesting();
 
-  gfx::Rect soon_rect = viewport;
-  soon_rect.Inset(-312.f, -312.f, -312.f, -312.f);
-  gfx::Rect soon_rect_in_content_space =
-      gfx::ToEnclosedRect(gfx::ScaleRect(soon_rect, 0.25f));
+  // Compute the soon border.
+  float inset = PictureLayerTiling::CalculateSoonBorderDistance(
+      viewport_in_content_space, 1.0f / 0.25f);
+  gfx::Rect soon_rect_in_content_space = viewport_in_content_space;
+  soon_rect_in_content_space.Inset(-inset, -inset);
 
   // Sanity checks.
   for (int i = 0; i < 47; ++i) {
@@ -763,10 +764,11 @@
       gfx::ToEnclosedRect(gfx::ScaleRect(viewport, 0.25f));
   gfx::Rect skewport = tiling->ComputeSkewport(2.0, viewport_in_content_space);
 
-  soon_rect = viewport;
-  soon_rect.Inset(-312.f, -312.f, -312.f, -312.f);
-  soon_rect_in_content_space =
-      gfx::ToEnclosedRect(gfx::ScaleRect(soon_rect, 0.25f));
+  // Compute the soon border.
+  inset = PictureLayerTiling::CalculateSoonBorderDistance(
+      viewport_in_content_space, 1.0f / 0.25f);
+  soon_rect_in_content_space = viewport_in_content_space;
+  soon_rect_in_content_space.Inset(-inset, -inset);
 
   EXPECT_EQ(0, skewport.x());
   EXPECT_EQ(10, skewport.y());
diff --git a/cc/resources/picture_pile.cc b/cc/resources/picture_pile.cc
index dcfe49e..7e94e18 100644
--- a/cc/resources/picture_pile.cc
+++ b/cc/resources/picture_pile.cc
@@ -152,6 +152,12 @@
   *record_rects = vertical_clustering;
 }
 
+#ifdef NDEBUG
+const bool kDefaultClearCanvasSetting = false;
+#else
+const bool kDefaultClearCanvasSetting = true;
+#endif
+
 }  // namespace
 
 namespace cc {
@@ -162,8 +168,11 @@
       slow_down_raster_scale_factor_for_debug_(0),
       can_use_lcd_text_(true),
       has_any_recordings_(false),
+      clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
+      requires_clear_(true),
       is_solid_color_(false),
       solid_color_(SK_ColorTRANSPARENT),
+      background_color_(SK_ColorTRANSPARENT),
       pixel_record_distance_(kPixelDistanceToRecord),
       is_suitable_for_gpu_rasterization_(true) {
   tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize));
@@ -623,6 +632,14 @@
   slow_down_raster_scale_factor_for_debug_ = factor;
 }
 
+void PicturePile::SetBackgroundColor(SkColor background_color) {
+  background_color_ = background_color;
+}
+
+void PicturePile::SetRequiresClear(bool requires_clear) {
+  requires_clear_ = requires_clear;
+}
+
 bool PicturePile::IsSuitableForGpuRasterization() const {
   return is_suitable_for_gpu_rasterization_;
 }
diff --git a/cc/resources/picture_pile.h b/cc/resources/picture_pile.h
index 8000c42..2a9a3ce 100644
--- a/cc/resources/picture_pile.h
+++ b/cc/resources/picture_pile.h
@@ -34,6 +34,8 @@
   gfx::Size GetSize() const final;
   void SetEmptyBounds() override;
   void SetSlowdownRasterScaleFactor(int factor) override;
+  void SetBackgroundColor(SkColor background_color) override;
+  void SetRequiresClear(bool requires_clear) override;
   bool IsSuitableForGpuRasterization() const override;
   void SetUnsuitableForGpuRasterizationForTesting() override;
   gfx::Size GetTileGridSizeForTesting() const override;
@@ -97,8 +99,11 @@
   // A hint about whether there are any recordings. This may be a false
   // positive.
   bool has_any_recordings_;
+  bool clear_canvas_with_debug_color_;
+  bool requires_clear_;
   bool is_solid_color_;
   SkColor solid_color_;
+  SkColor background_color_;
   int pixel_record_distance_;
 
  private:
diff --git a/cc/resources/picture_pile_impl.cc b/cc/resources/picture_pile_impl.cc
index c56a88f..d629888 100644
--- a/cc/resources/picture_pile_impl.cc
+++ b/cc/resources/picture_pile_impl.cc
@@ -16,16 +16,6 @@
 #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<PicturePileImpl> PicturePileImpl::CreateFromPicturePile(
@@ -40,7 +30,7 @@
       is_solid_color_(false),
       solid_color_(SK_ColorTRANSPARENT),
       has_any_recordings_(false),
-      clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
+      clear_canvas_with_debug_color_(false),
       min_contents_scale_(0.f),
       slow_down_raster_scale_factor_for_debug_(0),
       should_attempt_to_use_distance_field_text_(false) {
@@ -49,14 +39,14 @@
 PicturePileImpl::PicturePileImpl(const PicturePile* other)
     : picture_map_(other->picture_map_),
       tiling_(other->tiling_),
-      background_color_(SK_ColorTRANSPARENT),
-      requires_clear_(true),
+      background_color_(other->background_color_),
+      requires_clear_(other->requires_clear_),
       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_),
       has_any_recordings_(other->has_any_recordings_),
-      clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
+      clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
       min_contents_scale_(other->min_contents_scale_),
       slow_down_raster_scale_factor_for_debug_(
           other->slow_down_raster_scale_factor_for_debug_),
@@ -88,7 +78,6 @@
   RasterSourceHelper::PrepareForPlaybackToCanvas(
       canvas, canvas_rect, gfx::Rect(tiling_.tiling_size()), contents_scale,
       background_color_, clear_canvas_with_debug_color_, requires_clear_);
-
   RasterCommon(canvas,
                NULL,
                canvas_rect,
@@ -367,19 +356,12 @@
   should_attempt_to_use_distance_field_text_ = true;
 }
 
-void PicturePileImpl::SetBackgoundColor(SkColor background_color) {
-  background_color_ = background_color;
-}
-
-void PicturePileImpl::SetRequiresClear(bool requires_clear) {
-  requires_clear_ = requires_clear;
-}
-
 bool PicturePileImpl::ShouldAttemptToUseDistanceFieldText() const {
   return should_attempt_to_use_distance_field_text_;
 }
 
-void PicturePileImpl::AsValueInto(base::debug::TracedValue* pictures) const {
+void PicturePileImpl::AsValueInto(
+    base::trace_event::TracedValue* pictures) const {
   gfx::Rect tiling_rect(tiling_.tiling_size());
   std::set<const void*> appended_pictures;
   bool include_borders = true;
@@ -453,10 +435,8 @@
 
 void PicturePileImpl::DidBeginTracing() {
   std::set<const void*> processed_pictures;
-  for (PictureMap::iterator it = picture_map_.begin();
-       it != picture_map_.end();
-       ++it) {
-    const Picture* picture = it->second.GetPicture();
+  for (const auto& map_pair : picture_map_) {
+    const Picture* picture = map_pair.second.GetPicture();
     if (picture && (processed_pictures.count(picture) == 0)) {
       picture->EmitTraceSnapshot();
       processed_pictures.insert(picture);
diff --git a/cc/resources/picture_pile_impl.h b/cc/resources/picture_pile_impl.h
index b3bfa60..1f94cec 100644
--- a/cc/resources/picture_pile_impl.h
+++ b/cc/resources/picture_pile_impl.h
@@ -52,8 +52,6 @@
   bool CoversRect(const gfx::Rect& content_rect,
                   float contents_scale) const override;
   void SetShouldAttemptToUseDistanceFieldText() override;
-  void SetBackgoundColor(SkColor background_color) override;
-  void SetRequiresClear(bool requires_clear) override;
   bool ShouldAttemptToUseDistanceFieldText() const override;
   gfx::Size GetSize() const override;
   bool IsSolidColor() const override;
@@ -63,7 +61,7 @@
 
   // Tracing functionality.
   void DidBeginTracing() override;
-  void AsValueInto(base::debug::TracedValue* array) const override;
+  void AsValueInto(base::trace_event::TracedValue* array) const override;
   skia::RefPtr<SkPicture> GetFlattenedPicture() override;
   size_t GetPictureMemoryUsage() const override;
 
@@ -106,18 +104,23 @@
 
   int buffer_pixels() const { return tiling_.border_texels(); }
 
-  PictureMap picture_map_;
-  TilingData tiling_;
-  SkColor background_color_;
-  bool requires_clear_;
-  bool can_use_lcd_text_;
-  bool is_solid_color_;
-  SkColor solid_color_;
-  gfx::Rect recorded_viewport_;
-  bool has_any_recordings_;
-  bool clear_canvas_with_debug_color_;
-  float min_contents_scale_;
-  int slow_down_raster_scale_factor_for_debug_;
+  // These members are const as this raster source may be in use on another
+  // thread and so should not be touched after construction.
+  const PictureMap picture_map_;
+  const TilingData tiling_;
+  const SkColor background_color_;
+  const bool requires_clear_;
+  const bool can_use_lcd_text_;
+  const bool is_solid_color_;
+  const SkColor solid_color_;
+  const gfx::Rect recorded_viewport_;
+  const bool has_any_recordings_;
+  const bool clear_canvas_with_debug_color_;
+  const float min_contents_scale_;
+  const int slow_down_raster_scale_factor_for_debug_;
+  // TODO(enne/vmiura): this has a read/write race between raster and compositor
+  // threads with multi-threaded Ganesh.  Make this const or remove it.
+  bool should_attempt_to_use_distance_field_text_;
 
  private:
   typedef std::map<const Picture*, Region> PictureRegionMap;
@@ -146,8 +149,6 @@
 
   gfx::Rect PaddedRect(const PictureMapKey& key) const;
 
-  bool should_attempt_to_use_distance_field_text_;
-
   DISALLOW_COPY_AND_ASSIGN(PicturePileImpl);
 };
 
diff --git a/cc/resources/picture_pile_impl_unittest.cc b/cc/resources/picture_pile_impl_unittest.cc
index 6e9afc7..72a8158 100644
--- a/cc/resources/picture_pile_impl_unittest.cc
+++ b/cc/resources/picture_pile_impl_unittest.cc
@@ -19,21 +19,25 @@
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(400, 400);
 
-  scoped_refptr<FakePicturePileImpl> pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_ptr<FakePicturePile> recording_source =
+      FakePicturePile::CreateFilledPile(tile_size, layer_bounds);
 
-  SkColor solid_color = SkColorSetARGB(255, 12, 23, 34);
   SkPaint solid_paint;
+  SkColor solid_color = SkColorSetARGB(255, 12, 23, 34);
   solid_paint.setColor(solid_color);
 
   SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67);
   SkPaint non_solid_paint;
   non_solid_paint.setColor(non_solid_color);
 
-  pile->add_draw_rect_with_paint(gfx::Rect(0, 0, 400, 400), solid_paint);
-  pile->RerecordPile();
+  recording_source->add_draw_rect_with_paint(gfx::Rect(0, 0, 400, 400),
+                                             solid_paint);
+  recording_source->RerecordPile();
 
-  // Ensure everything is solid
+  scoped_refptr<FakePicturePileImpl> pile =
+      FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
+
+  // Ensure everything is solid.
   for (int y = 0; y <= 300; y += 100) {
     for (int x = 0; x <= 300; x += 100) {
       RasterSource::SolidColorAnalysis analysis;
@@ -44,9 +48,11 @@
     }
   }
 
-  // One pixel non solid
-  pile->add_draw_rect_with_paint(gfx::Rect(50, 50, 1, 1), non_solid_paint);
-  pile->RerecordPile();
+  // Add one non-solid pixel and recreate the raster source.
+  recording_source->add_draw_rect_with_paint(gfx::Rect(50, 50, 1, 1),
+                                             non_solid_paint);
+  recording_source->RerecordPile();
+  pile = FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
 
   RasterSource::SolidColorAnalysis analysis;
   pile->PerformSolidColorAnalysis(gfx::Rect(0, 0, 100, 100), 1.0, &analysis);
@@ -56,7 +62,7 @@
   EXPECT_TRUE(analysis.is_solid_color);
   EXPECT_EQ(analysis.solid_color, solid_color);
 
-  // Boundaries should be clipped
+  // Boundaries should be clipped.
   analysis.is_solid_color = false;
   pile->PerformSolidColorAnalysis(gfx::Rect(350, 0, 100, 100), 1.0, &analysis);
   EXPECT_TRUE(analysis.is_solid_color);
@@ -78,8 +84,8 @@
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(400, 400);
 
-  scoped_refptr<FakePicturePileImpl> pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_ptr<FakePicturePile> recording_source =
+      FakePicturePile::CreateFilledPile(tile_size, layer_bounds);
 
   SkColor solid_color = SkColorSetARGB(255, 12, 23, 34);
   SkPaint solid_paint;
@@ -89,10 +95,14 @@
   SkPaint non_solid_paint;
   non_solid_paint.setColor(non_solid_color);
 
-  pile->add_draw_rect_with_paint(gfx::Rect(0, 0, 400, 400), solid_paint);
-  pile->RerecordPile();
+  recording_source->add_draw_rect_with_paint(gfx::Rect(0, 0, 400, 400),
+                                             solid_paint);
+  recording_source->RerecordPile();
 
-  // Ensure everything is solid
+  scoped_refptr<FakePicturePileImpl> pile =
+      FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
+
+  // Ensure everything is solid.
   for (int y = 0; y <= 30; y += 10) {
     for (int x = 0; x <= 30; x += 10) {
       RasterSource::SolidColorAnalysis analysis;
@@ -103,9 +113,11 @@
     }
   }
 
-  // One pixel non solid
-  pile->add_draw_rect_with_paint(gfx::Rect(50, 50, 1, 1), non_solid_paint);
-  pile->RerecordPile();
+  // Add one non-solid pixel and recreate the raster source.
+  recording_source->add_draw_rect_with_paint(gfx::Rect(50, 50, 1, 1),
+                                             non_solid_paint);
+  recording_source->RerecordPile();
+  pile = FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
 
   RasterSource::SolidColorAnalysis analysis;
   pile->PerformSolidColorAnalysis(gfx::Rect(0, 0, 10, 10), 0.1f, &analysis);
@@ -115,7 +127,7 @@
   EXPECT_TRUE(analysis.is_solid_color);
   EXPECT_EQ(analysis.solid_color, solid_color);
 
-  // Boundaries should be clipped
+  // Boundaries should be clipped.
   analysis.is_solid_color = false;
   pile->PerformSolidColorAnalysis(gfx::Rect(35, 0, 10, 10), 0.1f, &analysis);
   EXPECT_TRUE(analysis.is_solid_color);
@@ -209,24 +221,30 @@
   gfx::Size tile_size(128, 128);
   gfx::Size layer_bounds(256, 256);
 
-  scoped_refptr<FakePicturePileImpl> pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-
+  scoped_ptr<FakePicturePile> recording_source =
+      FakePicturePile::CreateFilledPile(tile_size, layer_bounds);
   SkPaint simple_paint;
   simple_paint.setColor(SkColorSetARGB(255, 12, 23, 34));
 
   SkBitmap non_discardable_bitmap;
   CreateBitmap(gfx::Size(128, 128), "notdiscardable", &non_discardable_bitmap);
 
-  pile->add_draw_rect_with_paint(gfx::Rect(0, 0, 256, 256), simple_paint);
-  pile->add_draw_rect_with_paint(gfx::Rect(128, 128, 512, 512), simple_paint);
-  pile->add_draw_rect_with_paint(gfx::Rect(512, 0, 256, 256), simple_paint);
-  pile->add_draw_rect_with_paint(gfx::Rect(0, 512, 256, 256), simple_paint);
-  pile->add_draw_bitmap(non_discardable_bitmap, gfx::Point(128, 0));
-  pile->add_draw_bitmap(non_discardable_bitmap, gfx::Point(0, 128));
-  pile->add_draw_bitmap(non_discardable_bitmap, gfx::Point(150, 150));
+  recording_source->add_draw_rect_with_paint(gfx::Rect(0, 0, 256, 256),
+                                             simple_paint);
+  recording_source->add_draw_rect_with_paint(gfx::Rect(128, 128, 512, 512),
+                                             simple_paint);
+  recording_source->add_draw_rect_with_paint(gfx::Rect(512, 0, 256, 256),
+                                             simple_paint);
+  recording_source->add_draw_rect_with_paint(gfx::Rect(0, 512, 256, 256),
+                                             simple_paint);
+  recording_source->add_draw_bitmap(non_discardable_bitmap, gfx::Point(128, 0));
+  recording_source->add_draw_bitmap(non_discardable_bitmap, gfx::Point(0, 128));
+  recording_source->add_draw_bitmap(non_discardable_bitmap,
+                                    gfx::Point(150, 150));
+  recording_source->RerecordPile();
 
-  pile->RerecordPile();
+  scoped_refptr<FakePicturePileImpl> pile =
+      FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
 
   // Tile sized iterators.
   {
@@ -282,8 +300,8 @@
   gfx::Size tile_size(128, 128);
   gfx::Size layer_bounds(256, 256);
 
-  scoped_refptr<FakePicturePileImpl> pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_ptr<FakePicturePile> recording_source =
+      FakePicturePile::CreateFilledPile(tile_size, layer_bounds);
 
   SkBitmap discardable_bitmap[2][2];
   CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[0][0]);
@@ -296,11 +314,15 @@
   // |---|---|
   // | x | x |
   // |---|---|
-  pile->add_draw_bitmap(discardable_bitmap[0][0], gfx::Point(0, 0));
-  pile->add_draw_bitmap(discardable_bitmap[1][0], gfx::Point(0, 130));
-  pile->add_draw_bitmap(discardable_bitmap[1][1], gfx::Point(140, 140));
+  recording_source->add_draw_bitmap(discardable_bitmap[0][0], gfx::Point(0, 0));
+  recording_source->add_draw_bitmap(discardable_bitmap[1][0],
+                                    gfx::Point(0, 130));
+  recording_source->add_draw_bitmap(discardable_bitmap[1][1],
+                                    gfx::Point(140, 140));
+  recording_source->RerecordPile();
 
-  pile->RerecordPile();
+  scoped_refptr<FakePicturePileImpl> pile =
+      FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
 
   // Tile sized iterators. These should find only one pixel ref.
   {
@@ -392,8 +414,8 @@
   gfx::Size tile_size(256, 256);
   gfx::Size layer_bounds(512, 512);
 
-  scoped_refptr<FakePicturePileImpl> pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_ptr<FakePicturePile> recording_source =
+      FakePicturePile::CreateFilledPile(tile_size, layer_bounds);
 
   SkBitmap discardable_bitmap[2][2];
   CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[0][0]);
@@ -406,11 +428,15 @@
   // |---|---|
   // |   | x |
   // |---|---|
-  pile->add_draw_bitmap(discardable_bitmap[0][0], gfx::Point(0, 0));
-  pile->add_draw_bitmap(discardable_bitmap[0][1], gfx::Point(260, 0));
-  pile->add_draw_bitmap(discardable_bitmap[1][1], gfx::Point(260, 260));
+  recording_source->add_draw_bitmap(discardable_bitmap[0][0], gfx::Point(0, 0));
+  recording_source->add_draw_bitmap(discardable_bitmap[0][1],
+                                    gfx::Point(260, 0));
+  recording_source->add_draw_bitmap(discardable_bitmap[1][1],
+                                    gfx::Point(260, 260));
+  recording_source->RerecordPile();
 
-  pile->RerecordPile();
+  scoped_refptr<FakePicturePileImpl> pile =
+      FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
 
   // Tile sized iterators. These should find only one pixel ref.
   {
@@ -523,8 +549,8 @@
   gfx::Size tile_size(256, 256);
   gfx::Size layer_bounds(512, 512);
 
-  scoped_refptr<FakePicturePileImpl> pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_ptr<FakePicturePile> recording_source =
+      FakePicturePile::CreateFilledPile(tile_size, layer_bounds);
 
   SkBitmap non_discardable_bitmap;
   CreateBitmap(gfx::Size(512, 512), "notdiscardable", &non_discardable_bitmap);
@@ -541,12 +567,16 @@
   // |---|---|
   // |   | x |
   // |---|---|
-  pile->add_draw_bitmap(non_discardable_bitmap, gfx::Point(0, 0));
-  pile->add_draw_bitmap(discardable_bitmap[0][0], gfx::Point(0, 0));
-  pile->add_draw_bitmap(discardable_bitmap[0][1], gfx::Point(260, 0));
-  pile->add_draw_bitmap(discardable_bitmap[1][1], gfx::Point(260, 260));
+  recording_source->add_draw_bitmap(non_discardable_bitmap, gfx::Point(0, 0));
+  recording_source->add_draw_bitmap(discardable_bitmap[0][0], gfx::Point(0, 0));
+  recording_source->add_draw_bitmap(discardable_bitmap[0][1],
+                                    gfx::Point(260, 0));
+  recording_source->add_draw_bitmap(discardable_bitmap[1][1],
+                                    gfx::Point(260, 260));
+  recording_source->RerecordPile();
 
-  pile->RerecordPile();
+  scoped_refptr<FakePicturePileImpl> pile =
+      FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
 
   // Tile sized iterators. These should find only one pixel ref.
   {
@@ -640,19 +670,25 @@
   float contents_scale = 1.5f;
   float raster_divisions = 2.f;
 
-  scoped_refptr<FakePicturePileImpl> pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_ptr<FakePicturePile> recording_source =
+      FakePicturePile::CreateFilledPile(tile_size, layer_bounds);
+  recording_source->SetBackgroundColor(SK_ColorBLACK);
+  recording_source->SetIsSolidColor(false);
+  recording_source->SetRequiresClear(false);
+  recording_source->SetClearCanvasWithDebugColor(false);
+
   // Because the caller sets content opaque, it also promises that it
   // has at least filled in layer_bounds opaquely.
   SkPaint white_paint;
   white_paint.setColor(SK_ColorWHITE);
-  pile->add_draw_rect_with_paint(gfx::Rect(layer_bounds), white_paint);
+  recording_source->add_draw_rect_with_paint(gfx::Rect(layer_bounds),
+                                             white_paint);
 
-  pile->SetMinContentsScale(contents_scale);
-  pile->set_background_color(SK_ColorBLACK);
-  pile->SetRequiresClear(false);
-  pile->set_clear_canvas_with_debug_color(false);
-  pile->RerecordPile();
+  recording_source->SetMinContentsScale(contents_scale);
+  recording_source->RerecordPile();
+
+  scoped_refptr<FakePicturePileImpl> pile =
+      FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
 
   gfx::Size content_bounds(
       gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale)));
@@ -703,14 +739,16 @@
   gfx::Size layer_bounds(5, 3);
   float contents_scale = 0.5f;
 
-  scoped_refptr<FakePicturePileImpl> pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-  pile->set_background_color(SK_ColorTRANSPARENT);
-  pile->SetRequiresClear(true);
-  pile->SetMinContentsScale(contents_scale);
-  pile->set_clear_canvas_with_debug_color(false);
-  pile->RerecordPile();
+  scoped_ptr<FakePicturePile> recording_source =
+      FakePicturePile::CreateFilledPile(tile_size, layer_bounds);
+  recording_source->SetBackgroundColor(SK_ColorTRANSPARENT);
+  recording_source->SetRequiresClear(true);
+  recording_source->SetMinContentsScale(contents_scale);
+  recording_source->SetClearCanvasWithDebugColor(false);
+  recording_source->RerecordPile();
 
+  scoped_refptr<FakePicturePileImpl> pile =
+      FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
   gfx::Size content_bounds(
       gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale)));
 
@@ -743,21 +781,24 @@
   // Pick an opaque color to not have to deal with premultiplication off-by-one.
   SkColor test_color = SkColorSetARGB(255, 45, 56, 67);
 
-  scoped_refptr<FakePicturePileImpl> pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-  pile->set_background_color(SK_ColorTRANSPARENT);
-  pile->SetRequiresClear(true);
-  pile->SetMinContentsScale(MinContentsScale());
-  pile->set_clear_canvas_with_debug_color(true);
+  scoped_ptr<FakePicturePile> recording_source =
+      FakePicturePile::CreateFilledPile(tile_size, layer_bounds);
+  recording_source->SetBackgroundColor(SK_ColorTRANSPARENT);
+  recording_source->SetRequiresClear(true);
+  recording_source->SetMinContentsScale(MinContentsScale());
+  recording_source->SetClearCanvasWithDebugColor(true);
+
   SkPaint color_paint;
   color_paint.setColor(test_color);
   // Additive paint, so that if two paints overlap, the color will change.
   color_paint.setXfermodeMode(SkXfermode::kPlus_Mode);
   // Paint outside the layer to make sure that blending works.
-  pile->add_draw_rect_with_paint(gfx::RectF(bigger_than_layer_bounds),
-                                 color_paint);
-  pile->RerecordPile();
+  recording_source->add_draw_rect_with_paint(
+      gfx::RectF(bigger_than_layer_bounds), color_paint);
+  recording_source->RerecordPile();
 
+  scoped_refptr<FakePicturePileImpl> pile =
+      FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
   gfx::Size content_bounds(
       gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale)));
 
@@ -793,25 +834,33 @@
   gfx::Size tile_size(128, 128);
   gfx::Size layer_bounds(320, 128);
 
-  // Fake picture pile impl uses a tile grid the size of the tile.  So,
+  // Fake picture pile uses a tile grid the size of the tile.  So,
   // any iteration that intersects with a tile will return all pixel refs
   // inside of it.
-  scoped_refptr<FakePicturePileImpl> pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-  pile->SetMinContentsScale(0.5f);
+  scoped_ptr<FakePicturePile> recording_source =
+      FakePicturePile::CreateFilledPile(tile_size, layer_bounds);
+  recording_source->SetMinContentsScale(0.5f);
 
   // Bitmaps 0-2 are exactly on tiles 0-2, so that they overlap the borders
   // of adjacent tiles.
-  gfx::Rect bitmap_rects[] = {pile->tiling().TileBounds(0, 0),
-                              pile->tiling().TileBounds(1, 0),
-                              pile->tiling().TileBounds(2, 0), };
+  gfx::Rect bitmap_rects[] = {
+      recording_source->tiling().TileBounds(0, 0),
+      recording_source->tiling().TileBounds(1, 0),
+      recording_source->tiling().TileBounds(2, 0),
+  };
   SkBitmap discardable_bitmap[arraysize(bitmap_rects)];
 
   for (size_t i = 0; i < arraysize(bitmap_rects); ++i) {
     CreateBitmap(bitmap_rects[i].size(), "discardable", &discardable_bitmap[i]);
-    pile->add_draw_bitmap(discardable_bitmap[i], bitmap_rects[i].origin());
+    recording_source->add_draw_bitmap(discardable_bitmap[i],
+                                      bitmap_rects[i].origin());
   }
 
+  recording_source->RerecordPile();
+
+  scoped_refptr<FakePicturePileImpl> pile =
+      FakePicturePileImpl::CreateFromPile(recording_source.get(), nullptr);
+
   // Sanity check that bitmaps 0-2 intersect the borders of their adjacent
   // tiles, but not the actual tiles.
   EXPECT_TRUE(
@@ -827,8 +876,6 @@
       bitmap_rects[2].Intersects(pile->tiling().TileBoundsWithBorder(1, 0)));
   EXPECT_FALSE(bitmap_rects[2].Intersects(pile->tiling().TileBounds(1, 0)));
 
-  pile->RerecordPile();
-
   // Tile-sized iterators.
   {
     // Because tile 0's borders extend onto tile 1, it will include both
diff --git a/cc/resources/pixel_buffer_tile_task_worker_pool.cc b/cc/resources/pixel_buffer_tile_task_worker_pool.cc
index 69afb83..f74e066 100644
--- a/cc/resources/pixel_buffer_tile_task_worker_pool.cc
+++ b/cc/resources/pixel_buffer_tile_task_worker_pool.cc
@@ -701,10 +701,10 @@
   completed_tasks_.clear();
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 PixelBufferTileTaskWorkerPool::StateAsValue() const {
-  scoped_refptr<base::debug::TracedValue> state =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
   state->SetInteger("completed_count", completed_raster_tasks_.size());
   state->BeginArray("pending_count");
   for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set)
@@ -719,7 +719,7 @@
 }
 
 void PixelBufferTileTaskWorkerPool::ThrottleStateAsValueInto(
-    base::debug::TracedValue* throttle_state) const {
+    base::trace_event::TracedValue* throttle_state) const {
   throttle_state->SetInteger("bytes_available_for_upload",
                              max_bytes_pending_upload_ - bytes_pending_upload_);
   throttle_state->SetInteger("bytes_pending_upload", bytes_pending_upload_);
diff --git a/cc/resources/pixel_buffer_tile_task_worker_pool.h b/cc/resources/pixel_buffer_tile_task_worker_pool.h
index edff89a..82e5916 100644
--- a/cc/resources/pixel_buffer_tile_task_worker_pool.h
+++ b/cc/resources/pixel_buffer_tile_task_worker_pool.h
@@ -20,14 +20,7 @@
 class ConvertableToTraceFormat;
 class TracedValue;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::ConvertableToTraceFormat;
-using ::base::trace_event::TracedValue;
 }
-}  // namespace base
 
 namespace cc {
 class ResourceProvider;
@@ -101,8 +94,10 @@
   void CheckForCompletedRasterizerTasks();
 
   const char* StateName() const;
-  scoped_refptr<base::debug::ConvertableToTraceFormat> StateAsValue() const;
-  void ThrottleStateAsValueInto(base::debug::TracedValue* throttle_state) const;
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> StateAsValue()
+      const;
+  void ThrottleStateAsValueInto(
+      base::trace_event::TracedValue* throttle_state) const;
 
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
   TaskGraphRunner* task_graph_runner_;
diff --git a/cc/resources/raster_source.h b/cc/resources/raster_source.h
index e890375..929e49d 100644
--- a/cc/resources/raster_source.h
+++ b/cc/resources/raster_source.h
@@ -86,16 +86,13 @@
   // during rasterization.
   virtual void SetShouldAttemptToUseDistanceFieldText() = 0;
 
-  virtual void SetBackgoundColor(SkColor background_color) = 0;
-  virtual void SetRequiresClear(bool requires_clear) = 0;
-
   // Return true iff this raster source would benefit from using distance
   // field text.
   virtual bool ShouldAttemptToUseDistanceFieldText() const = 0;
 
   // Tracing functionality.
   virtual void DidBeginTracing() = 0;
-  virtual void AsValueInto(base::debug::TracedValue* array) const = 0;
+  virtual void AsValueInto(base::trace_event::TracedValue* array) const = 0;
   virtual skia::RefPtr<SkPicture> GetFlattenedPicture() = 0;
   virtual size_t GetPictureMemoryUsage() const = 0;
 
diff --git a/cc/resources/raster_tile_priority_queue_all.cc b/cc/resources/raster_tile_priority_queue_all.cc
index e9836cd..9baa9b3 100644
--- a/cc/resources/raster_tile_priority_queue_all.cc
+++ b/cc/resources/raster_tile_priority_queue_all.cc
@@ -280,10 +280,10 @@
                             pending_queue_.get(), nullptr);
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 RasterTilePriorityQueueAll::PairedTilingSetQueue::StateAsValue() const {
-  scoped_refptr<base::debug::TracedValue> state =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
 
   bool active_queue_has_tile = active_queue_ && !active_queue_->IsEmpty();
   TilePriority::PriorityBin active_priority_bin = TilePriority::EVENTUALLY;
diff --git a/cc/resources/raster_tile_priority_queue_all.h b/cc/resources/raster_tile_priority_queue_all.h
index c2b8910..4bd1085 100644
--- a/cc/resources/raster_tile_priority_queue_all.h
+++ b/cc/resources/raster_tile_priority_queue_all.h
@@ -33,7 +33,8 @@
     WhichTree NextTileIteratorTree(TreePriority tree_priority) const;
     void SkipTilesReturnedByTwin(TreePriority tree_priority);
 
-    scoped_refptr<base::debug::ConvertableToTraceFormat> StateAsValue() const;
+    scoped_refptr<base::trace_event::ConvertableToTraceFormat> StateAsValue()
+        const;
 
     const TilingSetRasterQueueAll* active_queue() const {
       return active_queue_.get();
diff --git a/cc/resources/recording_source.h b/cc/resources/recording_source.h
index d96c0fa..8915361 100644
--- a/cc/resources/recording_source.h
+++ b/cc/resources/recording_source.h
@@ -45,6 +45,8 @@
   virtual gfx::Size GetSize() const = 0;
   virtual void SetEmptyBounds() = 0;
   virtual void SetSlowdownRasterScaleFactor(int factor) = 0;
+  virtual void SetBackgroundColor(SkColor background_color) = 0;
+  virtual void SetRequiresClear(bool requires_clear) = 0;
   virtual bool IsSuitableForGpuRasterization() const = 0;
 
   // TODO(hendrikw): Figure out how to remove this.
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index b90b594..42ef4b3 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -1087,17 +1087,25 @@
 
 ResourceProvider::ScopedWriteLockGr::ScopedWriteLockGr(
     ResourceProvider* resource_provider,
-    ResourceProvider::ResourceId resource_id,
-    bool use_distance_field_text,
-    bool can_use_lcd_text,
-    int msaa_sample_count)
+    ResourceProvider::ResourceId resource_id)
     : resource_provider_(resource_provider),
       resource_(resource_provider->LockForWrite(resource_id)) {
-  // Create the sk_surface.
+  DCHECK(thread_checker_.CalledOnValidThread());
+  resource_provider_->LazyAllocate(resource_);
+}
+
+ResourceProvider::ScopedWriteLockGr::~ScopedWriteLockGr() {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(resource_->locked_for_write);
+  resource_provider_->UnlockForWrite(resource_);
+}
 
-  resource_provider_->LazyAllocate(resource_);
+void ResourceProvider::ScopedWriteLockGr::InitSkSurface(
+    bool use_worker_context,
+    bool use_distance_field_text,
+    bool can_use_lcd_text,
+    int msaa_sample_count) {
+  DCHECK(resource_->locked_for_write);
 
   GrBackendTextureDesc desc;
   desc.fFlags = kRenderTarget_GrBackendTextureFlag;
@@ -1108,7 +1116,8 @@
   desc.fTextureHandle = resource_->gl_id;
   desc.fSampleCnt = msaa_sample_count;
 
-  class GrContext* gr_context = resource_provider_->GrContext();
+  class GrContext* gr_context =
+      resource_provider_->GrContext(use_worker_context);
   skia::RefPtr<GrTexture> gr_texture =
       skia::AdoptRef(gr_context->wrapBackendTexture(desc));
   if (gr_texture) {
@@ -1124,12 +1133,13 @@
     }
     sk_surface_ = skia::AdoptRef(SkSurface::NewRenderTargetDirect(
         gr_texture->asRenderTarget(), &surface_props));
+    return;
   }
+  sk_surface_.clear();
 }
 
-ResourceProvider::ScopedWriteLockGr::~ScopedWriteLockGr() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  resource_provider_->UnlockForWrite(resource_);
+void ResourceProvider::ScopedWriteLockGr::ReleaseSkSurface() {
+  sk_surface_.clear();
 }
 
 ResourceProvider::SynchronousFence::SynchronousFence(
@@ -2135,8 +2145,10 @@
   return context_provider ? context_provider->ContextGL() : NULL;
 }
 
-class GrContext* ResourceProvider::GrContext() const {
-  ContextProvider* context_provider = output_surface_->context_provider();
+class GrContext* ResourceProvider::GrContext(bool worker_context) const {
+  ContextProvider* context_provider =
+      worker_context ? output_surface_->worker_context_provider()
+                     : output_surface_->context_provider();
   return context_provider ? context_provider->GrContext() : NULL;
 }
 
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index 1fb5b60..167ef20 100644
--- a/cc/resources/resource_provider.h
+++ b/cc/resources/resource_provider.h
@@ -332,13 +332,17 @@
   class CC_EXPORT ScopedWriteLockGr {
    public:
     ScopedWriteLockGr(ResourceProvider* resource_provider,
-                      ResourceProvider::ResourceId resource_id,
-                      bool use_distance_field_text,
-                      bool can_use_lcd_text,
-                      int msaa_sample_count);
+                      ResourceProvider::ResourceId resource_id);
     ~ScopedWriteLockGr();
 
-    SkSurface* get_sk_surface() { return sk_surface_.get(); }
+    void InitSkSurface(bool use_worker_context,
+                       bool use_distance_field_text,
+                       bool can_use_lcd_text,
+                       int msaa_sample_count);
+    void ReleaseSkSurface();
+
+    SkSurface* sk_surface() { return sk_surface_.get(); }
+    ResourceProvider::Resource* resource() { return resource_; }
 
    private:
     ResourceProvider* resource_provider_;
@@ -426,6 +430,8 @@
 
   static GLint GetActiveTextureUnit(gpu::gles2::GLES2Interface* gl);
 
+  OutputSurface* output_surface() { return output_surface_; }
+
  private:
   struct Resource {
     enum Origin { Internal, External, Delegated };
@@ -560,7 +566,7 @@
 
   // Returns NULL if the output_surface_ does not have a ContextProvider.
   gpu::gles2::GLES2Interface* ContextGL() const;
-  class GrContext* GrContext() const;
+  class GrContext* GrContext(bool worker_context) const;
 
   OutputSurface* output_surface_;
   SharedBitmapManager* shared_bitmap_manager_;
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc
index 53741ab..2bba801 100644
--- a/cc/resources/resource_provider_unittest.cc
+++ b/cc/resources/resource_provider_unittest.cc
@@ -3518,7 +3518,7 @@
 
   scoped_refptr<TestContextProvider> context_provider =
       TestContextProvider::Create(context_owned.Pass());
-  output_surface->InitializeAndSetContext3d(context_provider);
+  output_surface->InitializeAndSetContext3d(context_provider, nullptr);
   resource_provider->InitializeGL();
 
   CheckCreateResource(ResourceProvider::GLTexture, resource_provider, context);
diff --git a/cc/resources/tile.cc b/cc/resources/tile.cc
index b0b4525..39d48a8 100644
--- a/cc/resources/tile.cc
+++ b/cc/resources/tile.cc
@@ -49,7 +49,7 @@
       "cc::Tile", this);
 }
 
-void Tile::AsValueInto(base::debug::TracedValue* res) const {
+void Tile::AsValueInto(base::trace_event::TracedValue* res) const {
   TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
       TRACE_DISABLED_BY_DEFAULT("cc.debug"), res, "cc::Tile", this);
   TracedValue::SetIDRef(raster_source_.get(), res, "picture_pile");
diff --git a/cc/resources/tile.h b/cc/resources/tile.h
index 2394dcb..698f43d 100644
--- a/cc/resources/tile.h
+++ b/cc/resources/tile.h
@@ -68,18 +68,8 @@
   void set_shared(bool is_shared) { is_shared_ = is_shared; }
   bool is_shared() const { return is_shared_; }
 
-  bool is_occluded_for_tree_priority(TreePriority tree_priority) const {
-    switch (tree_priority) {
-      case SMOOTHNESS_TAKES_PRIORITY:
-        return is_occluded_[ACTIVE_TREE];
-      case NEW_CONTENT_TAKES_PRIORITY:
-        return is_occluded_[PENDING_TREE];
-      case SAME_PRIORITY_FOR_BOTH_TREES:
-        return is_occluded_[ACTIVE_TREE] && is_occluded_[PENDING_TREE];
-      default:
-        NOTREACHED();
-        return false;
-    }
+  bool is_occluded_combined() const {
+    return is_occluded_[ACTIVE_TREE] && is_occluded_[PENDING_TREE];
   }
 
   // TODO(vmpstr): Move this to the iterators.
@@ -102,7 +92,7 @@
            !draw_info_.IsReadyToDraw();
   }
 
-  void AsValueInto(base::debug::TracedValue* dict) const;
+  void AsValueInto(base::trace_event::TracedValue* dict) const;
 
   inline bool IsReadyToDraw() const { return draw_info_.IsReadyToDraw(); }
 
diff --git a/cc/resources/tile_draw_info.cc b/cc/resources/tile_draw_info.cc
index 518a74b..7761d72 100644
--- a/cc/resources/tile_draw_info.cc
+++ b/cc/resources/tile_draw_info.cc
@@ -28,7 +28,7 @@
   return false;
 }
 
-void TileDrawInfo::AsValueInto(base::debug::TracedValue* state) const {
+void TileDrawInfo::AsValueInto(base::trace_event::TracedValue* state) const {
   state->SetBoolean("is_solid_color", mode_ == SOLID_COLOR_MODE);
   state->SetBoolean("is_transparent",
                     mode_ == SOLID_COLOR_MODE && !SkColorGetA(solid_color_));
diff --git a/cc/resources/tile_draw_info.h b/cc/resources/tile_draw_info.h
index 8437f5b..54ca946 100644
--- a/cc/resources/tile_draw_info.h
+++ b/cc/resources/tile_draw_info.h
@@ -59,7 +59,7 @@
     resource_ = resource.Pass();
   }
 
-  void AsValueInto(base::debug::TracedValue* state) const;
+  void AsValueInto(base::trace_event::TracedValue* state) const;
 
  private:
   friend class Tile;
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
index 2b247aa..94b6332 100644
--- a/cc/resources/tile_manager.cc
+++ b/cc/resources/tile_manager.cc
@@ -184,10 +184,10 @@
 RasterTaskCompletionStats::RasterTaskCompletionStats()
     : completed_count(0u), canceled_count(0u) {}
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats) {
-  scoped_refptr<base::debug::TracedValue> state =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
   state->SetInteger("completed_count", stats.completed_count);
   state->SetInteger("canceled_count", stats.canceled_count);
   return state;
@@ -477,15 +477,16 @@
   update_visible_tiles_stats_ = RasterTaskCompletionStats();
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 TileManager::BasicStateAsValue() const {
-  scoped_refptr<base::debug::TracedValue> value =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> value =
+      new base::trace_event::TracedValue();
   BasicStateAsValueInto(value.get());
   return value;
 }
 
-void TileManager::BasicStateAsValueInto(base::debug::TracedValue* state) const {
+void TileManager::BasicStateAsValueInto(
+    base::trace_event::TracedValue* state) const {
   state->SetInteger("tile_count", tiles_.size());
   state->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_);
   state->BeginDictionary("global_state");
diff --git a/cc/resources/tile_manager.h b/cc/resources/tile_manager.h
index 0af823e..2bdc9e1 100644
--- a/cc/resources/tile_manager.h
+++ b/cc/resources/tile_manager.h
@@ -30,14 +30,7 @@
 class ConvertableToTraceFormat;
 class TracedValue;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::ConvertableToTraceFormat;
-using ::base::trace_event::TracedValue;
 }
-}  // namespace base
 
 namespace cc {
 class PictureLayerImpl;
@@ -87,8 +80,8 @@
   size_t completed_count;
   size_t canceled_count;
 };
-scoped_refptr<base::debug::ConvertableToTraceFormat>
-    RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats);
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats);
 
 // This class manages tiles, deciding which should get rasterized and which
 // should no longer have any memory assigned to them. Tile objects are "owned"
@@ -135,9 +128,9 @@
                                  int source_frame_number,
                                  int flags);
 
-  scoped_refptr<base::debug::ConvertableToTraceFormat> BasicStateAsValue()
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> BasicStateAsValue()
       const;
-  void BasicStateAsValueInto(base::debug::TracedValue* dict) const;
+  void BasicStateAsValueInto(base::trace_event::TracedValue* dict) const;
   const MemoryHistory::Entry& memory_stats_from_last_assign() const {
     return memory_stats_from_last_assign_;
   }
diff --git a/cc/resources/tile_manager_perftest.cc b/cc/resources/tile_manager_perftest.cc
index bb4ce7c..7c316ac 100644
--- a/cc/resources/tile_manager_perftest.cc
+++ b/cc/resources/tile_manager_perftest.cc
@@ -179,7 +179,7 @@
     std::vector<FakePictureLayerImpl*> layers = CreateLayers(layer_count, 10);
     bool resourceless_software_draw = false;
     for (const auto& layer : layers)
-      layer->UpdateTiles(Occlusion(), resourceless_software_draw);
+      layer->UpdateTiles(resourceless_software_draw);
 
     timer_.Reset();
     do {
@@ -207,7 +207,7 @@
     std::vector<FakePictureLayerImpl*> layers = CreateLayers(layer_count, 100);
     bool resourceless_software_draw = false;
     for (const auto& layer : layers)
-      layer->UpdateTiles(Occlusion(), resourceless_software_draw);
+      layer->UpdateTiles(resourceless_software_draw);
 
     int priority_count = 0;
     timer_.Reset();
@@ -243,7 +243,7 @@
     std::vector<FakePictureLayerImpl*> layers = CreateLayers(layer_count, 10);
     bool resourceless_software_draw = false;
     for (const auto& layer : layers) {
-      layer->UpdateTiles(Occlusion(), resourceless_software_draw);
+      layer->UpdateTiles(resourceless_software_draw);
       for (size_t i = 0; i < layer->num_tilings(); ++i) {
         tile_manager()->InitializeTilesWithResourcesForTesting(
             layer->tilings()->tiling_at(i)->AllTilesForTesting());
@@ -278,7 +278,7 @@
         CreateLayers(layer_count, tile_count);
     bool resourceless_software_draw = false;
     for (const auto& layer : layers) {
-      layer->UpdateTiles(Occlusion(), resourceless_software_draw);
+      layer->UpdateTiles(resourceless_software_draw);
       for (size_t i = 0; i < layer->num_tilings(); ++i) {
         tile_manager()->InitializeTilesWithResourcesForTesting(
             layer->tilings()->tiling_at(i)->AllTilesForTesting());
@@ -387,7 +387,7 @@
           CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE);
       host_impl_.UpdateCurrentBeginFrameArgs(args);
       for (const auto& layer : layers)
-        layer->UpdateTiles(Occlusion(), resourceless_software_draw);
+        layer->UpdateTiles(resourceless_software_draw);
 
       GlobalStateThatImpactsTilePriority global_state(GlobalStateForTest());
       tile_manager()->PrepareTiles(global_state);
diff --git a/cc/resources/tile_manager_unittest.cc b/cc/resources/tile_manager_unittest.cc
index 0e12af6..4f441b3 100644
--- a/cc/resources/tile_manager_unittest.cc
+++ b/cc/resources/tile_manager_unittest.cc
@@ -662,7 +662,7 @@
   Tile* last_tile = NULL;
   smoothness_tiles.clear();
   tile_count = 0;
-  // Here we expect to get increasing ACTIVE_TREE priority_bin.
+  // Here we expect to get increasing combined priority_bin.
   queue = host_impl_.BuildEvictionQueue(SMOOTHNESS_TAKES_PRIORITY);
   int distance_increasing = 0;
   int distance_decreasing = 0;
@@ -674,16 +674,16 @@
     if (!last_tile)
       last_tile = tile;
 
-    EXPECT_GE(last_tile->priority(ACTIVE_TREE).priority_bin,
-              tile->priority(ACTIVE_TREE).priority_bin);
-    if (last_tile->priority(ACTIVE_TREE).priority_bin ==
-        tile->priority(ACTIVE_TREE).priority_bin) {
+    const TilePriority& last_priority = last_tile->combined_priority();
+    const TilePriority& priority = tile->combined_priority();
+
+    EXPECT_GE(last_priority.priority_bin, priority.priority_bin);
+    if (last_priority.priority_bin == priority.priority_bin) {
       EXPECT_LE(last_tile->required_for_activation(),
                 tile->required_for_activation());
       if (last_tile->required_for_activation() ==
           tile->required_for_activation()) {
-        if (last_tile->priority(ACTIVE_TREE).distance_to_visible >=
-            tile->priority(ACTIVE_TREE).distance_to_visible)
+        if (last_priority.distance_to_visible >= priority.distance_to_visible)
           ++distance_decreasing;
         else
           ++distance_increasing;
@@ -696,14 +696,15 @@
     queue->Pop();
   }
 
+  // Ensure that the distance is decreasing many more times than increasing.
   EXPECT_EQ(3, distance_increasing);
-  EXPECT_EQ(16, distance_decreasing);
+  EXPECT_EQ(17, distance_decreasing);
   EXPECT_EQ(tile_count, smoothness_tiles.size());
   EXPECT_EQ(all_tiles, smoothness_tiles);
 
   std::set<Tile*> new_content_tiles;
   last_tile = NULL;
-  // Here we expect to get increasing PENDING_TREE priority_bin.
+  // Again, we expect to get increasing combined priority_bin.
   queue = host_impl_.BuildEvictionQueue(NEW_CONTENT_TAKES_PRIORITY);
   distance_decreasing = 0;
   distance_increasing = 0;
@@ -714,16 +715,16 @@
     if (!last_tile)
       last_tile = tile;
 
-    EXPECT_GE(last_tile->priority(PENDING_TREE).priority_bin,
-              tile->priority(PENDING_TREE).priority_bin);
-    if (last_tile->priority(PENDING_TREE).priority_bin ==
-        tile->priority(PENDING_TREE).priority_bin) {
+    const TilePriority& last_priority = last_tile->combined_priority();
+    const TilePriority& priority = tile->combined_priority();
+
+    EXPECT_GE(last_priority.priority_bin, priority.priority_bin);
+    if (last_priority.priority_bin == priority.priority_bin) {
       EXPECT_LE(last_tile->required_for_activation(),
                 tile->required_for_activation());
       if (last_tile->required_for_activation() ==
           tile->required_for_activation()) {
-        if (last_tile->priority(PENDING_TREE).distance_to_visible >=
-            tile->priority(PENDING_TREE).distance_to_visible)
+        if (last_priority.distance_to_visible >= priority.distance_to_visible)
           ++distance_decreasing;
         else
           ++distance_increasing;
@@ -735,8 +736,9 @@
     queue->Pop();
   }
 
+  // Ensure that the distance is decreasing many more times than increasing.
   EXPECT_EQ(3, distance_increasing);
-  EXPECT_EQ(16, distance_decreasing);
+  EXPECT_EQ(17, distance_decreasing);
   EXPECT_EQ(tile_count, new_content_tiles.size());
   EXPECT_EQ(all_tiles, new_content_tiles);
 }
@@ -771,6 +773,12 @@
       CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
   host_impl_.pending_tree()->UpdateDrawProperties();
 
+  ActivateTree();
+  SetupPendingTree(pending_pile);
+
+  FakePictureLayerImpl* active_child_layer =
+      static_cast<FakePictureLayerImpl*>(active_layer_->children()[0]);
+
   std::set<Tile*> all_tiles;
   size_t tile_count = 0;
   scoped_ptr<RasterTilePriorityQueue> raster_queue(host_impl_.BuildRasterQueue(
@@ -797,6 +805,15 @@
   pending_child_layer->LowResTiling()->ComputeTilePriorityRects(
       viewport, 1.0f, 1.0, Occlusion());
 
+  active_layer_->HighResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+                                                           Occlusion());
+  active_layer_->LowResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+                                                          Occlusion());
+  active_child_layer->HighResTiling()->ComputeTilePriorityRects(
+      viewport, 1.0f, 1.0, Occlusion());
+  active_child_layer->LowResTiling()->ComputeTilePriorityRects(
+      viewport, 1.0f, 1.0, Occlusion());
+
   // Populate all tiles directly from the tilings.
   all_tiles.clear();
   std::vector<Tile*> pending_high_res_tiles =
@@ -812,12 +829,14 @@
   std::vector<Tile*> pending_child_high_res_tiles =
       pending_child_layer->HighResTiling()->AllTilesForTesting();
   pending_child_layer->HighResTiling()->SetAllTilesOccludedForTesting();
+  active_child_layer->HighResTiling()->SetAllTilesOccludedForTesting();
   all_tiles.insert(pending_child_high_res_tiles.begin(),
                    pending_child_high_res_tiles.end());
 
   std::vector<Tile*> pending_child_low_res_tiles =
       pending_child_layer->LowResTiling()->AllTilesForTesting();
   pending_child_layer->LowResTiling()->SetAllTilesOccludedForTesting();
+  active_child_layer->LowResTiling()->SetAllTilesOccludedForTesting();
   all_tiles.insert(pending_child_low_res_tiles.begin(),
                    pending_child_low_res_tiles.end());
 
@@ -835,7 +854,7 @@
     if (!last_tile)
       last_tile = tile;
 
-    bool tile_is_occluded = tile->is_occluded_for_tree_priority(tree_priority);
+    bool tile_is_occluded = tile->is_occluded_combined();
 
     // The only way we will encounter an occluded tile after an unoccluded
     // tile is if the priorty bin decreased, the tile is required for
@@ -843,8 +862,7 @@
     if (tile_is_occluded) {
       occluded_count++;
 
-      bool last_tile_is_occluded =
-          last_tile->is_occluded_for_tree_priority(tree_priority);
+      bool last_tile_is_occluded = last_tile->is_occluded_combined();
       if (!last_tile_is_occluded) {
         TilePriority::PriorityBin tile_priority_bin =
             tile->priority_for_tree_priority(tree_priority).priority_bin;
@@ -1069,11 +1087,12 @@
        RasterTilePriorityQueueStaticViewport) {
   FakePictureLayerTilingClient client;
 
-  gfx::Rect viewport(50, 50, 100, 100);
-  gfx::Size layer_bounds(800, 800);
+  gfx::Rect viewport(50, 50, 500, 500);
+  gfx::Size layer_bounds(1600, 1600);
 
+  float inset = PictureLayerTiling::CalculateSoonBorderDistance(viewport, 1.0f);
   gfx::Rect soon_rect = viewport;
-  soon_rect.Inset(-312.f, -312.f, -312.f, -312.f);
+  soon_rect.Inset(-inset, -inset);
 
   client.SetTileSize(gfx::Size(30, 30));
   client.set_tree(ACTIVE_TREE);
@@ -1093,7 +1112,7 @@
   tiling_set->UpdateTilePriorities(viewport, 1.0f, 1.0, Occlusion(), true);
   std::vector<Tile*> all_tiles = tiling->AllTilesForTesting();
   // Sanity check.
-  EXPECT_EQ(841u, all_tiles.size());
+  EXPECT_EQ(3364u, all_tiles.size());
 
   // The explanation of each iteration is as follows:
   // 1. First iteration tests that we can get all of the tiles correctly.
@@ -1205,8 +1224,10 @@
   tiling_set->UpdateTilePriorities(moved_viewport, 1.0f, 2.0, Occlusion(),
                                    true);
 
+  float inset =
+      PictureLayerTiling::CalculateSoonBorderDistance(moved_viewport, 1.0f);
   gfx::Rect soon_rect = moved_viewport;
-  soon_rect.Inset(-312.f, -312.f, -312.f, -312.f);
+  soon_rect.Inset(-inset, -inset);
 
   // There are 3 bins in TilePriority.
   bool have_tiles[3] = {};
diff --git a/cc/resources/tile_priority.cc b/cc/resources/tile_priority.cc
index 5ef26f2..33dfcbe 100644
--- a/cc/resources/tile_priority.cc
+++ b/cc/resources/tile_priority.cc
@@ -48,7 +48,7 @@
   return "<unknown TilePriority::PriorityBin value>";
 }
 
-void TilePriority::AsValueInto(base::debug::TracedValue* state) const {
+void TilePriority::AsValueInto(base::trace_event::TracedValue* state) const {
   state->SetString("resolution", TileResolutionToString(resolution));
   state->SetString("priority_bin", TilePriorityBinToString(priority_bin));
   state->SetDouble("distance_to_visible",
@@ -86,7 +86,7 @@
 }
 
 void GlobalStateThatImpactsTilePriority::AsValueInto(
-    base::debug::TracedValue* state) const {
+    base::trace_event::TracedValue* state) const {
   state->SetString("memory_limit_policy",
                    TileMemoryLimitPolicyToString(memory_limit_policy));
   state->SetInteger("soft_memory_limit_in_bytes", soft_memory_limit_in_bytes);
diff --git a/cc/resources/tile_priority.h b/cc/resources/tile_priority.h
index 405ca92..5067aa6 100644
--- a/cc/resources/tile_priority.h
+++ b/cc/resources/tile_priority.h
@@ -74,7 +74,7 @@
     }
   }
 
-  void AsValueInto(base::debug::TracedValue* dict) const;
+  void AsValueInto(base::trace_event::TracedValue* dict) const;
 
   bool operator ==(const TilePriority& other) const {
     return resolution == other.resolution &&
@@ -151,7 +151,7 @@
     return !(*this == other);
   }
 
-  void AsValueInto(base::debug::TracedValue* dict) const;
+  void AsValueInto(base::trace_event::TracedValue* dict) const;
 };
 
 }  // namespace cc
diff --git a/cc/resources/tile_task_worker_pool_perftest.cc b/cc/resources/tile_task_worker_pool_perftest.cc
index 483b71f..450bcbe 100644
--- a/cc/resources/tile_task_worker_pool_perftest.cc
+++ b/cc/resources/tile_task_worker_pool_perftest.cc
@@ -9,6 +9,7 @@
 #include "cc/debug/lap_timer.h"
 #include "cc/output/context_provider.h"
 #include "cc/resources/bitmap_tile_task_worker_pool.h"
+#include "cc/resources/gpu_rasterizer.h"
 #include "cc/resources/gpu_tile_task_worker_pool.h"
 #include "cc/resources/one_copy_tile_task_worker_pool.h"
 #include "cc/resources/pixel_buffer_tile_task_worker_pool.h"
@@ -89,6 +90,8 @@
         reinterpret_cast<GrBackendContext>(null_interface.get())));
     return gr_context_.get();
   }
+  void SetupLock() override {}
+  base::Lock* GetLock() override { return &context_lock_; }
   bool IsContextLost() override { return false; }
   void VerifyContexts() override {}
   void DeleteCachedResources() override {}
@@ -103,6 +106,7 @@
   scoped_ptr<PerfGLES2Interface> context_gl_;
   skia::RefPtr<class GrContext> gr_context_;
   TestContextSupport support_;
+  base::Lock context_lock_;
 };
 
 enum TileTaskWorkerPoolType {
@@ -228,6 +232,7 @@
   FakeOutputSurfaceClient output_surface_client_;
   scoped_ptr<FakeOutputSurface> output_surface_;
   scoped_ptr<ResourceProvider> resource_provider_;
+  scoped_ptr<Rasterizer> rasterizer_;
   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
   scoped_ptr<TaskGraphRunner> task_graph_runner_;
   LapTimer timer_;
@@ -267,7 +272,7 @@
         Create3dOutputSurfaceAndResourceProvider();
         tile_task_worker_pool_ = GpuTileTaskWorkerPool::Create(
             task_runner_.get(), task_graph_runner_.get(),
-            resource_provider_.get());
+            static_cast<GpuRasterizer*>(rasterizer_.get()));
         break;
       case TILE_TASK_WORKER_POOL_TYPE_BITMAP:
         CreateSoftwareOutputSurfaceAndResourceProvider();
diff --git a/cc/resources/tile_task_worker_pool_unittest.cc b/cc/resources/tile_task_worker_pool_unittest.cc
index 68758f6..1e84674 100644
--- a/cc/resources/tile_task_worker_pool_unittest.cc
+++ b/cc/resources/tile_task_worker_pool_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/cancelable_callback.h"
 #include "cc/base/unique_notifier.h"
 #include "cc/resources/bitmap_tile_task_worker_pool.h"
+#include "cc/resources/gpu_rasterizer.h"
 #include "cc/resources/gpu_tile_task_worker_pool.h"
 #include "cc/resources/one_copy_tile_task_worker_pool.h"
 #include "cc/resources/picture_pile.h"
@@ -126,6 +127,7 @@
 
   TileTaskWorkerPoolTest()
       : context_provider_(TestContextProvider::Create()),
+        worker_context_provider_(TestContextProvider::Create()),
         all_tile_tasks_finished_(
             base::MessageLoopProxy::current().get(),
             base::Bind(&TileTaskWorkerPoolTest::AllTileTasksFinished,
@@ -160,10 +162,12 @@
         break;
       case TILE_TASK_WORKER_POOL_TYPE_GPU:
         Create3dOutputSurfaceAndResourceProvider();
+        rasterizer_ = GpuRasterizer::Create(
+            context_provider_.get(), resource_provider_.get(), false, false, 0);
         tile_task_worker_pool_ = GpuTileTaskWorkerPool::Create(
             base::MessageLoopProxy::current().get(),
             TileTaskWorkerPool::GetTaskGraphRunner(),
-            resource_provider_.get());
+            static_cast<GpuRasterizer*>(rasterizer_.get()));
         break;
       case TILE_TASK_WORKER_POOL_TYPE_BITMAP:
         CreateSoftwareOutputSurfaceAndResourceProvider();
@@ -271,7 +275,8 @@
 
  private:
   void Create3dOutputSurfaceAndResourceProvider() {
-    output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass();
+    output_surface_ = FakeOutputSurface::Create3d(
+                          context_provider_, worker_context_provider_).Pass();
     CHECK(output_surface_->BindToClient(&output_surface_client_));
     TestWebGraphicsContext3D* context3d = context_provider_->TestContext3d();
     context3d->set_support_sync_query(true);
@@ -306,6 +311,8 @@
 
  protected:
   scoped_refptr<TestContextProvider> context_provider_;
+  scoped_refptr<TestContextProvider> worker_context_provider_;
+  scoped_ptr<Rasterizer> rasterizer_;
   FakeOutputSurfaceClient output_surface_client_;
   scoped_ptr<FakeOutputSurface> output_surface_;
   scoped_ptr<ResourceProvider> resource_provider_;
diff --git a/cc/resources/transform_display_item.cc b/cc/resources/transform_display_item.cc
index 7ab2421..a25f347 100644
--- a/cc/resources/transform_display_item.cc
+++ b/cc/resources/transform_display_item.cc
@@ -36,7 +36,8 @@
   return sizeof(gfx::Transform);
 }
 
-void TransformDisplayItem::AsValueInto(base::debug::TracedValue* array) const {
+void TransformDisplayItem::AsValueInto(
+    base::trace_event::TracedValue* array) const {
   array->AppendString(base::StringPrintf("TransformDisplayItem transform: [%s]",
                                          transform_.ToString().c_str()));
 }
@@ -65,7 +66,7 @@
 }
 
 void EndTransformDisplayItem::AsValueInto(
-    base::debug::TracedValue* array) const {
+    base::trace_event::TracedValue* array) const {
   array->AppendString("EndTransformDisplayItem");
 }
 
diff --git a/cc/resources/transform_display_item.h b/cc/resources/transform_display_item.h
index 0e62623..fe0dbd2 100644
--- a/cc/resources/transform_display_item.h
+++ b/cc/resources/transform_display_item.h
@@ -29,7 +29,7 @@
   bool IsSuitableForGpuRasterization() const override;
   int ApproximateOpCount() const override;
   size_t PictureMemoryUsage() const override;
-  void AsValueInto(base::debug::TracedValue* array) const override;
+  void AsValueInto(base::trace_event::TracedValue* array) const override;
 
  protected:
   explicit TransformDisplayItem(const gfx::Transform& transform);
@@ -51,7 +51,7 @@
   bool IsSuitableForGpuRasterization() const override;
   int ApproximateOpCount() const override;
   size_t PictureMemoryUsage() const override;
-  void AsValueInto(base::debug::TracedValue* array) const override;
+  void AsValueInto(base::trace_event::TracedValue* array) const override;
 
  protected:
   EndTransformDisplayItem();
diff --git a/cc/resources/transparency_display_item.cc b/cc/resources/transparency_display_item.cc
index 369e51b..1c37b73 100644
--- a/cc/resources/transparency_display_item.cc
+++ b/cc/resources/transparency_display_item.cc
@@ -42,7 +42,7 @@
 }
 
 void TransparencyDisplayItem::AsValueInto(
-    base::debug::TracedValue* array) const {
+    base::trace_event::TracedValue* array) const {
   array->AppendString(
       base::StringPrintf("TransparencyDisplayItem opacity: %f, blend_mode: %d",
                          opacity_, blend_mode_));
@@ -72,7 +72,7 @@
 }
 
 void EndTransparencyDisplayItem::AsValueInto(
-    base::debug::TracedValue* array) const {
+    base::trace_event::TracedValue* array) const {
   array->AppendString("EndTransparencyDisplayItem");
 }
 
diff --git a/cc/resources/transparency_display_item.h b/cc/resources/transparency_display_item.h
index 9697406..d7ae7be 100644
--- a/cc/resources/transparency_display_item.h
+++ b/cc/resources/transparency_display_item.h
@@ -32,7 +32,7 @@
   bool IsSuitableForGpuRasterization() const override;
   int ApproximateOpCount() const override;
   size_t PictureMemoryUsage() const override;
-  void AsValueInto(base::debug::TracedValue* array) const override;
+  void AsValueInto(base::trace_event::TracedValue* array) const override;
 
  protected:
   TransparencyDisplayItem(float opacity, SkXfermode::Mode blend_mode);
@@ -55,7 +55,7 @@
   bool IsSuitableForGpuRasterization() const override;
   int ApproximateOpCount() const override;
   size_t PictureMemoryUsage() const override;
-  void AsValueInto(base::debug::TracedValue* array) const override;
+  void AsValueInto(base::trace_event::TracedValue* array) const override;
 
  protected:
   EndTransparencyDisplayItem();
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
index 6375057..0e772eb 100644
--- a/cc/resources/video_resource_updater.cc
+++ b/cc/resources/video_resource_updater.cc
@@ -296,7 +296,9 @@
       ResourceProvider::ScopedWriteLockSoftware lock(
           resource_provider_, plane_resource.resource_id);
       SkCanvas canvas(lock.sk_bitmap());
-      video_renderer_->Copy(video_frame, &canvas);
+      // This is software path, so canvas and video_frame are always backed
+      // by software.
+      video_renderer_->Copy(video_frame, &canvas, media::Context3D());
       SetPlaneResourceUniqueId(video_frame.get(), 0, &plane_resource);
     }
 
diff --git a/cc/resources/zero_copy_tile_task_worker_pool.cc b/cc/resources/zero_copy_tile_task_worker_pool.cc
index 9432214..8b80aa3 100644
--- a/cc/resources/zero_copy_tile_task_worker_pool.cc
+++ b/cc/resources/zero_copy_tile_task_worker_pool.cc
@@ -196,10 +196,10 @@
   client_->DidFinishRunningTileTasks(task_set);
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 ZeroCopyTileTaskWorkerPool::StateAsValue() const {
-  scoped_refptr<base::debug::TracedValue> state =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
 
   state->BeginArray("tasks_pending");
   for (TaskSet task_set = 0; task_set < kNumberOfTaskSets; ++task_set)
diff --git a/cc/resources/zero_copy_tile_task_worker_pool.h b/cc/resources/zero_copy_tile_task_worker_pool.h
index 4f3085c..b64e0f5 100644
--- a/cc/resources/zero_copy_tile_task_worker_pool.h
+++ b/cc/resources/zero_copy_tile_task_worker_pool.h
@@ -14,13 +14,7 @@
 namespace trace_event {
 class ConvertableToTraceFormat;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::ConvertableToTraceFormat;
 }
-}  // namespace base
 
 namespace cc {
 class ResourceProvider;
@@ -58,7 +52,8 @@
 
  private:
   void OnTaskSetFinished(TaskSet task_set);
-  scoped_refptr<base::debug::ConvertableToTraceFormat> StateAsValue() const;
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> StateAsValue()
+      const;
 
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
   TaskGraphRunner* task_graph_runner_;
diff --git a/cc/scheduler/begin_frame_source.cc b/cc/scheduler/begin_frame_source.cc
index 9b200e9..42b8f6f 100644
--- a/cc/scheduler/begin_frame_source.cc
+++ b/cc/scheduler/begin_frame_source.cc
@@ -53,7 +53,7 @@
 }
 
 void BeginFrameObserverMixIn::AsValueInto(
-    base::debug::TracedValue* dict) const {
+    base::trace_event::TracedValue* dict) const {
   dict->BeginDictionary("last_begin_frame_args_");
   last_begin_frame_args_.AsValueInto(dict);
   dict->EndDictionary();
@@ -117,7 +117,8 @@
 }
 
 // Tracing support
-void BeginFrameSourceMixIn::AsValueInto(base::debug::TracedValue* dict) const {
+void BeginFrameSourceMixIn::AsValueInto(
+    base::trace_event::TracedValue* dict) const {
   // As the observer might try to trace the source, prevent an infinte loop
   // from occuring.
   if (inside_as_value_into_) {
@@ -198,7 +199,7 @@
 
 // Tracing support
 void BackToBackBeginFrameSource::AsValueInto(
-    base::debug::TracedValue* dict) const {
+    base::trace_event::TracedValue* dict) const {
   dict->SetString("type", "BackToBackBeginFrameSource");
   BeginFrameSourceMixIn::AsValueInto(dict);
   dict->SetBoolean("send_begin_frame_posted_", send_begin_frame_posted_);
@@ -264,13 +265,9 @@
   }
 }
 
-bool SyntheticBeginFrameSource::NeedsBeginFrames() const {
-  return time_source_->Active();
-}
-
 // Tracing support
 void SyntheticBeginFrameSource::AsValueInto(
-    base::debug::TracedValue* dict) const {
+    base::trace_event::TracedValue* dict) const {
   dict->SetString("type", "SyntheticBeginFrameSource");
   BeginFrameSourceMixIn::AsValueInto(dict);
 
@@ -406,14 +403,6 @@
 }
 
 // BeginFrameSource support
-bool BeginFrameSourceMultiplexer::NeedsBeginFrames() const {
-  if (active_source_) {
-    return active_source_->NeedsBeginFrames();
-  } else {
-    return false;
-  }
-}
-
 void BeginFrameSourceMultiplexer::OnNeedsBeginFramesChange(
     bool needs_begin_frames) {
   DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnNeedsBeginFramesChange",
@@ -439,7 +428,7 @@
 
 // Tracing support
 void BeginFrameSourceMultiplexer::AsValueInto(
-    base::debug::TracedValue* dict) const {
+    base::trace_event::TracedValue* dict) const {
   dict->SetString("type", "BeginFrameSourceMultiplexer");
 
   dict->SetInteger("minimum_interval_us", minimum_interval_.InMicroseconds());
diff --git a/cc/scheduler/begin_frame_source.h b/cc/scheduler/begin_frame_source.h
index 1612a28..d845dac 100644
--- a/cc/scheduler/begin_frame_source.h
+++ b/cc/scheduler/begin_frame_source.h
@@ -50,7 +50,7 @@
   virtual const BeginFrameArgs LastUsedBeginFrameArgs() const = 0;
 
   // Tracing support
-  virtual void AsValueInto(base::debug::TracedValue* dict) const = 0;
+  virtual void AsValueInto(base::trace_event::TracedValue* dict) const = 0;
 };
 
 // Simple mix in which implements a BeginFrameObserver which checks the
@@ -75,7 +75,7 @@
   const BeginFrameArgs LastUsedBeginFrameArgs() const override;
 
   // Outputs last_begin_frame_args_
-  void AsValueInto(base::debug::TracedValue* dict) const override;
+  void AsValueInto(base::trace_event::TracedValue* dict) const override;
 
  protected:
   // Subclasses should override this method!
@@ -122,7 +122,7 @@
 
   // Tracing support - Recommend (but not required) to call this implementation
   // in any override.
-  virtual void AsValueInto(base::debug::TracedValue* dict) const = 0;
+  virtual void AsValueInto(base::trace_event::TracedValue* dict) const = 0;
 };
 
 // Simple mix in which implements a BeginFrameSource.
@@ -137,7 +137,7 @@
   ~BeginFrameSourceMixIn() override {}
 
   // BeginFrameSource
-  bool NeedsBeginFrames() const override;
+  bool NeedsBeginFrames() const final;
   void SetNeedsBeginFrames(bool needs_begin_frames) final;
   void DidFinishFrame(size_t remaining_frames) override {}
   void AddObserver(BeginFrameObserver* obs) final;
@@ -146,7 +146,7 @@
 
   // Tracing support - Recommend (but not required) to call this implementation
   // in any override.
-  void AsValueInto(base::debug::TracedValue* dict) const override;
+  void AsValueInto(base::trace_event::TracedValue* dict) const override;
 
  protected:
   BeginFrameSourceMixIn();
@@ -178,7 +178,7 @@
   void DidFinishFrame(size_t remaining_frames) override;
 
   // Tracing
-  void AsValueInto(base::debug::TracedValue* dict) const override;
+  void AsValueInto(base::trace_event::TracedValue* dict) const override;
 
  protected:
   explicit BackToBackBeginFrameSource(
@@ -210,11 +210,8 @@
       base::TimeDelta initial_vsync_interval);
   ~SyntheticBeginFrameSource() override;
 
-  // BeginFrameSource
-  bool NeedsBeginFrames() const override;
-
   // Tracing
-  void AsValueInto(base::debug::TracedValue* dict) const override;
+  void AsValueInto(base::trace_event::TracedValue* dict) const override;
 
   // VSyncParameterObserver
   void OnUpdateVSyncParameters(base::TimeTicks new_vsync_timebase,
@@ -260,14 +257,13 @@
   const BeginFrameArgs LastUsedBeginFrameArgs() const override;
 
   // BeginFrameSource
-  bool NeedsBeginFrames() const override;
   void DidFinishFrame(size_t remaining_frames) override;
 
   // BeginFrameSourceMixIn
   void OnNeedsBeginFramesChange(bool needs_begin_frames) override;
 
   // Tracing
-  void AsValueInto(base::debug::TracedValue* dict) const override;
+  void AsValueInto(base::trace_event::TracedValue* dict) const override;
 
  protected:
   BeginFrameSourceMultiplexer();
diff --git a/cc/scheduler/begin_frame_source_unittest.cc b/cc/scheduler/begin_frame_source_unittest.cc
index 0972762..22126be 100644
--- a/cc/scheduler/begin_frame_source_unittest.cc
+++ b/cc/scheduler/begin_frame_source_unittest.cc
@@ -64,7 +64,7 @@
   MOCK_METHOD1(OnBeginFrame, void(const BeginFrameArgs&));
   MOCK_CONST_METHOD0(LastUsedBeginFrameArgs, const BeginFrameArgs());
 
-  virtual void AsValueInto(base::debug::TracedValue* dict) const {
+  virtual void AsValueInto(base::trace_event::TracedValue* dict) const {
     dict->SetString("type", "MockBeginFrameObserver");
     dict->BeginDictionary("last_begin_frame_args");
     LastUsedBeginFrameArgs().AsValueInto(dict);
@@ -284,7 +284,7 @@
  public:
   BeginFrameSource* source_;
 
-  void AsValueInto(base::debug::TracedValue* dict) const override {
+  void AsValueInto(base::trace_event::TracedValue* dict) const override {
     dict->SetString("type", "LoopingBeginFrameObserver");
     dict->BeginDictionary("source");
     source_->AsValueInto(dict);
@@ -305,8 +305,8 @@
   obs.source_ = &source;
   source.AddObserver(&obs);
 
-  scoped_refptr<base::debug::TracedValue> state =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
   source.AsValueInto(state.get());
 }
 
diff --git a/cc/scheduler/delay_based_time_source.cc b/cc/scheduler/delay_based_time_source.cc
index 457f718..ef43524 100644
--- a/cc/scheduler/delay_based_time_source.cc
+++ b/cc/scheduler/delay_based_time_source.cc
@@ -234,34 +234,20 @@
 //      now=37   tick_target=16.667  new_target=50.000  -->
 //          tick(), PostDelayedTask(floor(50.000-37)) --> PostDelayedTask(13)
 base::TimeTicks DelayBasedTimeSource::NextTickTarget(base::TimeTicks now) {
-  base::TimeDelta new_interval = next_parameters_.interval;
-
-  // |interval_offset| is the offset from |now| to the next multiple of
-  // |interval| after |tick_target|, possibly negative if in the past.
-  base::TimeDelta interval_offset = base::TimeDelta::FromInternalValue(
-      (next_parameters_.tick_target - now).ToInternalValue() %
-      new_interval.ToInternalValue());
-  // If |now| is exactly on the interval (i.e. offset==0), don't adjust.
-  // Otherwise, if |tick_target| was in the past, adjust forward to the next
-  // tick after |now|.
-  if (interval_offset.ToInternalValue() != 0 &&
-      next_parameters_.tick_target < now) {
-    interval_offset += new_interval;
-  }
-
-  base::TimeTicks new_tick_target = now + interval_offset;
+  base::TimeTicks new_tick_target = now.SnappedToNextTick(
+      next_parameters_.tick_target, next_parameters_.interval);
   DCHECK(now <= new_tick_target)
       << "now = " << now.ToInternalValue()
       << "; new_tick_target = " << new_tick_target.ToInternalValue()
-      << "; new_interval = " << new_interval.InMicroseconds()
-      << "; tick_target = " << next_parameters_.tick_target.ToInternalValue()
-      << "; interval_offset = " << interval_offset.ToInternalValue();
+      << "; new_interval = " << next_parameters_.interval.InMicroseconds()
+      << "; tick_target = " << next_parameters_.tick_target.ToInternalValue();
 
   // Avoid double ticks when:
   // 1) Turning off the timer and turning it right back on.
   // 2) Jittery data is passed to SetTimebaseAndInterval().
-  if (new_tick_target - last_tick_time_ <= new_interval / kDoubleTickDivisor)
-    new_tick_target += new_interval;
+  if (new_tick_target - last_tick_time_ <=
+      next_parameters_.interval / kDoubleTickDivisor)
+    new_tick_target += next_parameters_.interval;
 
   return new_tick_target;
 }
@@ -290,7 +276,8 @@
   return "DelayBasedTimeSourceHighRes";
 }
 
-void DelayBasedTimeSource::AsValueInto(base::debug::TracedValue* state) const {
+void DelayBasedTimeSource::AsValueInto(
+    base::trace_event::TracedValue* state) const {
   state->SetString("type", TypeString());
   state->SetDouble("last_tick_time_us", LastTickTime().ToInternalValue());
   state->SetDouble("next_tick_time_us", NextTickTime().ToInternalValue());
diff --git a/cc/scheduler/delay_based_time_source.h b/cc/scheduler/delay_based_time_source.h
index da968a6..4d7276c 100644
--- a/cc/scheduler/delay_based_time_source.h
+++ b/cc/scheduler/delay_based_time_source.h
@@ -15,14 +15,8 @@
 namespace trace_event {
 class TracedValue;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::TracedValue;
-}
 class SingleThreadTaskRunner;
-}  // namespace base
+}
 
 namespace cc {
 
@@ -61,7 +55,7 @@
   // Virtual for testing.
   virtual base::TimeTicks Now() const;
 
-  virtual void AsValueInto(base::debug::TracedValue* dict) const;
+  virtual void AsValueInto(base::trace_event::TracedValue* dict) const;
 
  protected:
   DelayBasedTimeSource(base::TimeDelta interval,
diff --git a/cc/scheduler/delay_based_time_source_unittest.cc b/cc/scheduler/delay_based_time_source_unittest.cc
index 0af8b02..f721b11 100644
--- a/cc/scheduler/delay_based_time_source_unittest.cc
+++ b/cc/scheduler/delay_based_time_source_unittest.cc
@@ -508,23 +508,6 @@
   EXPECT_EQ(13, task_runner->NextPendingTaskDelay().InMilliseconds());
 }
 
-TEST(DelayBasedTimeSourceTest, TestOverflow) {
-  // int(big_now / interval) < 0, so this causes a crash if the number of
-  // intervals elapsed is attempted to be stored in an int.
-  base::TimeDelta interval = base::TimeDelta::FromInternalValue(4000);
-  base::TimeTicks big_now = base::TimeTicks::FromInternalValue(8635916564000);
-
-  scoped_refptr<base::TestSimpleTaskRunner> task_runner =
-      new base::TestSimpleTaskRunner;
-  FakeTimeSourceClient client;
-  scoped_refptr<FakeDelayBasedTimeSource> timer =
-      FakeDelayBasedTimeSource::Create(interval, task_runner.get());
-  timer->SetClient(&client);
-  timer->SetNow(big_now);
-  timer->SetActive(true);
-  EXPECT_EQ(0, task_runner->NextPendingTaskDelay().InMilliseconds());
-}
-
 TEST(DelayBasedTimeSourceTest, TestReturnValueWhenTimerIsDeActivated) {
   scoped_refptr<base::TestSimpleTaskRunner> task_runner =
       new base::TestSimpleTaskRunner;
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 43812e8..ed8c0a2 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -740,15 +740,15 @@
   RescheduleBeginImplFrameDeadlineIfNeeded();
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat> Scheduler::AsValue()
+scoped_refptr<base::trace_event::ConvertableToTraceFormat> Scheduler::AsValue()
     const {
-  scoped_refptr<base::debug::TracedValue> state =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
   AsValueInto(state.get());
   return state;
 }
 
-void Scheduler::AsValueInto(base::debug::TracedValue* state) const {
+void Scheduler::AsValueInto(base::trace_event::TracedValue* state) const {
   state->BeginDictionary("state_machine");
   state_machine_.AsValueInto(state, Now());
   state->EndDictionary();
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index ddc3f2f..82f305a 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -27,14 +27,8 @@
 namespace trace_event {
 class ConvertableToTraceFormat;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::ConvertableToTraceFormat;
-}
 class SingleThreadTaskRunner;
-}  // namespace base
+}
 
 namespace cc {
 
@@ -170,8 +164,8 @@
 
   void SetDeferCommits(bool defer_commits);
 
-  scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
-  void AsValueInto(base::debug::TracedValue* value) const override;
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+  void AsValueInto(base::trace_event::TracedValue* value) const override;
 
   void SetContinuousPainting(bool continuous_painting) {
     state_machine_.SetContinuousPainting(continuous_painting);
diff --git a/cc/scheduler/scheduler_settings.cc b/cc/scheduler/scheduler_settings.cc
index c1db76b..8713391 100644
--- a/cc/scheduler/scheduler_settings.cc
+++ b/cc/scheduler/scheduler_settings.cc
@@ -46,10 +46,10 @@
 
 SchedulerSettings::~SchedulerSettings() {}
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 SchedulerSettings::AsValue() const {
-  scoped_refptr<base::debug::TracedValue> state =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
   state->SetBoolean("use_external_begin_frame_source",
                     use_external_begin_frame_source);
   state->SetBoolean("forward_begin_frames_to_children",
diff --git a/cc/scheduler/scheduler_settings.h b/cc/scheduler/scheduler_settings.h
index 90c1a9c..fe90f43 100644
--- a/cc/scheduler/scheduler_settings.h
+++ b/cc/scheduler/scheduler_settings.h
@@ -14,13 +14,7 @@
 namespace trace_event {
 class ConvertableToTraceFormat;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::ConvertableToTraceFormat;
 }
-}  // namespace base
 
 namespace cc {
 class LayerTreeSettings;
@@ -49,7 +43,7 @@
 
   base::TimeDelta background_frame_interval;
 
-  scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
 };
 
 }  // namespace cc
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index 7bce7ee..4e6509f 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -148,15 +148,15 @@
   return "???";
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 SchedulerStateMachine::AsValue() const {
-  scoped_refptr<base::debug::TracedValue> state =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
   AsValueInto(state.get(), gfx::FrameTime::Now());
   return state;
 }
 
-void SchedulerStateMachine::AsValueInto(base::debug::TracedValue* state,
+void SchedulerStateMachine::AsValueInto(base::trace_event::TracedValue* state,
                                         base::TimeTicks now) const {
   state->BeginDictionary("major_state");
   state->SetString("next_action", ActionToString(NextAction()));
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h
index fb87c84..f77df28 100644
--- a/cc/scheduler/scheduler_state_machine.h
+++ b/cc/scheduler/scheduler_state_machine.h
@@ -21,15 +21,8 @@
 class ConvertableToTraceFormat;
 class TracedValue;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::ConvertableToTraceFormat;
-using ::base::trace_event::TracedValue;
-}
 class Value;
-}  // namespace base
+}
 
 namespace cc {
 
@@ -121,8 +114,9 @@
   };
   static const char* ActionToString(Action action);
 
-  scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
-  void AsValueInto(base::debug::TracedValue* dict, base::TimeTicks now) const;
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+  void AsValueInto(base::trace_event::TracedValue* dict,
+                   base::TimeTicks now) const;
 
   Action NextAction() const;
   void UpdateState(Action action);
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index e4ce6b3..ac52271 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -189,7 +189,8 @@
   bool begin_frame_is_sent_to_children_;
   base::TimeTicks posted_begin_impl_frame_deadline_;
   std::vector<const char*> actions_;
-  std::vector<scoped_refptr<base::debug::ConvertableToTraceFormat>> states_;
+  std::vector<scoped_refptr<base::trace_event::ConvertableToTraceFormat>>
+      states_;
   TestScheduler* scheduler_;
 };
 
diff --git a/cc/surfaces/surface_display_output_surface.cc b/cc/surfaces/surface_display_output_surface.cc
index 068fe03..b99e2b4 100644
--- a/cc/surfaces/surface_display_output_surface.cc
+++ b/cc/surfaces/surface_display_output_surface.cc
@@ -17,7 +17,7 @@
     SurfaceManager* surface_manager,
     SurfaceIdAllocator* allocator,
     const scoped_refptr<ContextProvider>& context_provider)
-    : OutputSurface(context_provider, nullptr),
+    : OutputSurface(context_provider),
       display_client_(NULL),
       surface_manager_(surface_manager),
       factory_(surface_manager, this),
diff --git a/cc/test/data/enlarged_texture_on_threshold.png b/cc/test/data/enlarged_texture_on_threshold.png
new file mode 100644
index 0000000..6b232be
--- /dev/null
+++ b/cc/test/data/enlarged_texture_on_threshold.png
Binary files differ
diff --git a/cc/test/failure_output_surface.cc b/cc/test/failure_output_surface.cc
index 2c87853..c0d5fdb 100644
--- a/cc/test/failure_output_surface.cc
+++ b/cc/test/failure_output_surface.cc
@@ -7,7 +7,7 @@
 namespace cc {
 
 FailureOutputSurface::FailureOutputSurface(bool is_delegating)
-    : FakeOutputSurface(nullptr, nullptr, is_delegating) {
+    : FakeOutputSurface(static_cast<ContextProvider*>(nullptr), is_delegating) {
 }
 
 bool FailureOutputSurface::BindToClient(OutputSurfaceClient* client) {
diff --git a/cc/test/fake_layer_tree_host.h b/cc/test/fake_layer_tree_host.h
index 3daf471..858574f 100644
--- a/cc/test/fake_layer_tree_host.h
+++ b/cc/test/fake_layer_tree_host.h
@@ -51,10 +51,11 @@
 
   bool needs_commit() { return needs_commit_; }
 
- private:
+ protected:
   FakeLayerTreeHost(FakeLayerTreeHostClient* client,
                     const LayerTreeSettings& settings);
 
+ private:
   FakeImplProxy proxy_;
   FakeLayerTreeHostClient* client_;
   TestSharedBitmapManager manager_;
diff --git a/cc/test/fake_output_surface.cc b/cc/test/fake_output_surface.cc
index d54d2d1..0279421 100644
--- a/cc/test/fake_output_surface.cc
+++ b/cc/test/fake_output_surface.cc
@@ -16,6 +16,21 @@
 
 FakeOutputSurface::FakeOutputSurface(
     scoped_refptr<ContextProvider> context_provider,
+    scoped_refptr<ContextProvider> worker_context_provider,
+    bool delegated_rendering)
+    : OutputSurface(context_provider, worker_context_provider),
+      client_(NULL),
+      num_sent_frames_(0),
+      has_external_stencil_test_(false),
+      framebuffer_(0) {
+  if (delegated_rendering) {
+    capabilities_.delegated_rendering = true;
+    capabilities_.max_frames_pending = 1;
+  }
+}
+
+FakeOutputSurface::FakeOutputSurface(
+    scoped_refptr<ContextProvider> context_provider,
     bool delegated_rendering)
     : OutputSurface(context_provider),
       client_(NULL),
diff --git a/cc/test/fake_output_surface.h b/cc/test/fake_output_surface.h
index a564eef..39a78ea 100644
--- a/cc/test/fake_output_surface.h
+++ b/cc/test/fake_output_surface.h
@@ -24,7 +24,7 @@
 
   static scoped_ptr<FakeOutputSurface> Create3d() {
     return make_scoped_ptr(new FakeOutputSurface(
-        TestContextProvider::Create(), false));
+        TestContextProvider::Create(), TestContextProvider::Create(), false));
   }
 
   static scoped_ptr<FakeOutputSurface> Create3d(
@@ -33,6 +33,13 @@
   }
 
   static scoped_ptr<FakeOutputSurface> Create3d(
+      scoped_refptr<ContextProvider> context_provider,
+      scoped_refptr<ContextProvider> worker_context_provider) {
+    return make_scoped_ptr(new FakeOutputSurface(
+        context_provider, worker_context_provider, false));
+  }
+
+  static scoped_ptr<FakeOutputSurface> Create3d(
       scoped_ptr<TestWebGraphicsContext3D> context) {
     return make_scoped_ptr(new FakeOutputSurface(
         TestContextProvider::Create(context.Pass()), false));
@@ -46,7 +53,7 @@
 
   static scoped_ptr<FakeOutputSurface> CreateDelegating3d() {
     return make_scoped_ptr(new FakeOutputSurface(
-        TestContextProvider::Create(), true));
+        TestContextProvider::Create(), TestContextProvider::Create(), true));
   }
 
   static scoped_ptr<FakeOutputSurface> CreateDelegating3d(
@@ -128,9 +135,12 @@
       scoped_refptr<ContextProvider> context_provider,
       bool delegated_rendering);
 
-  FakeOutputSurface(
-      scoped_ptr<SoftwareOutputDevice> software_device,
-      bool delegated_rendering);
+  FakeOutputSurface(scoped_refptr<ContextProvider> context_provider,
+                    scoped_refptr<ContextProvider> worker_context_provider,
+                    bool delegated_rendering);
+
+  FakeOutputSurface(scoped_ptr<SoftwareOutputDevice> software_device,
+                    bool delegated_rendering);
 
   FakeOutputSurface(
       scoped_refptr<ContextProvider> context_provider,
diff --git a/cc/test/fake_painted_scrollbar_layer.h b/cc/test/fake_painted_scrollbar_layer.h
index e86a2e9..033d920 100644
--- a/cc/test/fake_painted_scrollbar_layer.h
+++ b/cc/test/fake_painted_scrollbar_layer.h
@@ -40,6 +40,7 @@
   FakeScrollbar* fake_scrollbar() {
     return fake_scrollbar_;
   }
+  using PaintedScrollbarLayer::UpdateInternalContentScale;
   using PaintedScrollbarLayer::UpdateThumbAndTrackGeometry;
 
  private:
diff --git a/cc/test/fake_picture_layer_impl.cc b/cc/test/fake_picture_layer_impl.cc
index 43db7bc..5ac6f69 100644
--- a/cc/test/fake_picture_layer_impl.cc
+++ b/cc/test/fake_picture_layer_impl.cc
@@ -86,10 +86,8 @@
 
 void FakePictureLayerImpl::AppendQuads(
     RenderPass* render_pass,
-    const Occlusion& occlusion_in_content_space,
     AppendQuadsData* append_quads_data) {
-  PictureLayerImpl::AppendQuads(
-      render_pass, occlusion_in_content_space, append_quads_data);
+  PictureLayerImpl::AppendQuads(render_pass, append_quads_data);
   ++append_quads_count_;
 }
 
@@ -137,6 +135,12 @@
   UpdateRasterSource(raster_source, &invalidation_temp, pending_set);
 }
 
+void FakePictureLayerImpl::SetIsDrawnRenderSurfaceLayerListMember(bool is) {
+  draw_properties().last_drawn_render_surface_layer_list_id =
+      is ? layer_tree_impl()->current_render_surface_list_id()
+         : layer_tree_impl()->current_render_surface_list_id() - 1;
+}
+
 void FakePictureLayerImpl::CreateAllTiles() {
   for (size_t i = 0; i < num_tilings(); ++i)
     tilings_->tiling_at(i)->CreateAllTilesForTesting();
diff --git a/cc/test/fake_picture_layer_impl.h b/cc/test/fake_picture_layer_impl.h
index caac373..115fe55 100644
--- a/cc/test/fake_picture_layer_impl.h
+++ b/cc/test/fake_picture_layer_impl.h
@@ -53,7 +53,6 @@
   scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
   void PushPropertiesTo(LayerImpl* layer_impl) override;
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override;
   gfx::Size CalculateTileSize(const gfx::Size& content_bounds) const override;
 
@@ -113,6 +112,8 @@
 
   void set_fixed_tile_size(const gfx::Size& size) { fixed_tile_size_ = size; }
 
+  void SetIsDrawnRenderSurfaceLayerListMember(bool is);
+
   void CreateAllTiles();
   void SetAllTilesVisible();
   void SetAllTilesReady();
diff --git a/cc/test/fake_picture_pile.cc b/cc/test/fake_picture_pile.cc
index 912ec06..cc0a7ba 100644
--- a/cc/test/fake_picture_pile.cc
+++ b/cc/test/fake_picture_pile.cc
@@ -4,12 +4,101 @@
 
 #include "cc/test/fake_picture_pile.h"
 
+#include <utility>
+
 #include "cc/test/fake_picture_pile_impl.h"
+#include "testing/gtest/include/gtest/gtest.h"
 
 namespace cc {
 
+namespace {
+
+scoped_ptr<FakePicturePile> CreatePile(const gfx::Size& tile_size,
+                                       const gfx::Size& layer_bounds,
+                                       bool is_filled) {
+  scoped_ptr<FakePicturePile> pile(
+      new FakePicturePile(ImplSidePaintingSettings().minimum_contents_scale,
+                          ImplSidePaintingSettings().default_tile_grid_size));
+  pile->tiling().SetBorderTexels(0);
+  pile->tiling().SetTilingSize(layer_bounds);
+  pile->tiling().SetMaxTextureSize(tile_size);
+  pile->SetRecordedViewport(is_filled ? gfx::Rect(layer_bounds) : gfx::Rect());
+  pile->SetHasAnyRecordings(is_filled);
+  if (is_filled) {
+    for (int x = 0; x < pile->tiling().num_tiles_x(); ++x) {
+      for (int y = 0; y < pile->tiling().num_tiles_y(); ++y)
+        pile->AddRecordingAt(x, y);
+    }
+  }
+  return pile;
+}
+
+}  // namespace
+
+scoped_ptr<FakePicturePile> FakePicturePile::CreateFilledPile(
+    const gfx::Size& tile_size,
+    const gfx::Size& layer_bounds) {
+  bool is_filled = true;
+  return CreatePile(tile_size, layer_bounds, is_filled);
+}
+
+scoped_ptr<FakePicturePile> FakePicturePile::CreateEmptyPile(
+    const gfx::Size& tile_size,
+    const gfx::Size& layer_bounds) {
+  bool is_filled = false;
+  return CreatePile(tile_size, layer_bounds, is_filled);
+}
+
 scoped_refptr<RasterSource> FakePicturePile::CreateRasterSource() const {
   return FakePicturePileImpl::CreateFromPile(this, playback_allowed_event_);
 }
 
+void FakePicturePile::AddRecordingAt(int x, int y) {
+  EXPECT_GE(x, 0);
+  EXPECT_GE(y, 0);
+  EXPECT_LT(x, tiling_.num_tiles_x());
+  EXPECT_LT(y, tiling_.num_tiles_y());
+
+  if (HasRecordingAt(x, y))
+    return;
+  gfx::Rect bounds(tiling().TileBounds(x, y));
+  bounds.Inset(-buffer_pixels(), -buffer_pixels());
+
+  scoped_refptr<Picture> picture(
+      Picture::Create(bounds, &client_, tile_grid_size_, true,
+                      RecordingSource::RECORD_NORMALLY));
+  picture_map_[std::pair<int, int>(x, y)].SetPicture(picture);
+  EXPECT_TRUE(HasRecordingAt(x, y));
+
+  has_any_recordings_ = true;
+}
+
+void FakePicturePile::RemoveRecordingAt(int x, int y) {
+  EXPECT_GE(x, 0);
+  EXPECT_GE(y, 0);
+  EXPECT_LT(x, tiling_.num_tiles_x());
+  EXPECT_LT(y, tiling_.num_tiles_y());
+
+  if (!HasRecordingAt(x, y))
+    return;
+  picture_map_.erase(std::pair<int, int>(x, y));
+  EXPECT_FALSE(HasRecordingAt(x, y));
+}
+
+bool FakePicturePile::HasRecordingAt(int x, int y) const {
+  PictureMap::const_iterator found = picture_map_.find(PictureMapKey(x, y));
+  if (found == picture_map_.end())
+    return false;
+  return !!found->second.GetPicture();
+}
+
+void FakePicturePile::RerecordPile() {
+  for (int y = 0; y < num_tiles_y(); ++y) {
+    for (int x = 0; x < num_tiles_x(); ++x) {
+      RemoveRecordingAt(x, y);
+      AddRecordingAt(x, y);
+    }
+  }
+}
+
 }  // namespace cc
diff --git a/cc/test/fake_picture_pile.h b/cc/test/fake_picture_pile.h
index 55b4c36..054eaa2 100644
--- a/cc/test/fake_picture_pile.h
+++ b/cc/test/fake_picture_pile.h
@@ -6,6 +6,8 @@
 #define CC_TEST_FAKE_PICTURE_PILE_H_
 
 #include "cc/resources/picture_pile.h"
+#include "cc/test/fake_content_layer_client.h"
+#include "cc/test/impl_side_painting_settings.h"
 
 namespace base {
 class WaitableEvent;
@@ -24,6 +26,13 @@
         playback_allowed_event_(nullptr) {}
   ~FakePicturePile() override {}
 
+  static scoped_ptr<FakePicturePile> CreateFilledPile(
+      const gfx::Size& tile_size,
+      const gfx::Size& layer_bounds);
+  static scoped_ptr<FakePicturePile> CreateEmptyPile(
+      const gfx::Size& tile_size,
+      const gfx::Size& layer_bounds);
+
   // PicturePile overrides.
   scoped_refptr<RasterSource> CreateRasterSource() const override;
 
@@ -53,6 +62,10 @@
     has_any_recordings_ = has_recordings;
   }
 
+  void SetClearCanvasWithDebugColor(bool clear) {
+    clear_canvas_with_debug_color_ = clear;
+  }
+
   void SetPlaybackAllowedEvent(base::WaitableEvent* event) {
     playback_allowed_event_ = event;
   }
@@ -61,11 +74,42 @@
 
   bool is_solid_color() const { return is_solid_color_; }
   SkColor solid_color() const { return solid_color_; }
+  void SetIsSolidColor(bool is_solid) { is_solid_color_ = is_solid; }
 
   void SetPixelRecordDistance(int d) { pixel_record_distance_ = d; }
 
+  void add_draw_rect(const gfx::RectF& rect) {
+    client_.add_draw_rect(rect, default_paint_);
+  }
+
+  void add_draw_bitmap(const SkBitmap& bitmap, const gfx::Point& point) {
+    client_.add_draw_bitmap(bitmap, point, default_paint_);
+  }
+
+  void add_draw_rect_with_paint(const gfx::RectF& rect, const SkPaint& paint) {
+    client_.add_draw_rect(rect, paint);
+  }
+
+  void add_draw_bitmap_with_paint(const SkBitmap& bitmap,
+                                  const gfx::Point& point,
+                                  const SkPaint& paint) {
+    client_.add_draw_bitmap(bitmap, point, paint);
+  }
+
+  void set_default_paint(const SkPaint& paint) { default_paint_ = paint; }
+
+  void AddRecordingAt(int x, int y);
+  void RemoveRecordingAt(int x, int y);
+  bool HasRecordingAt(int x, int y) const;
+  int num_tiles_x() const { return tiling_.num_tiles_x(); }
+  int num_tiles_y() const { return tiling_.num_tiles_y(); }
+  void RerecordPile();
+
  private:
   base::WaitableEvent* playback_allowed_event_;
+
+  FakeContentLayerClient client_;
+  SkPaint default_paint_;
 };
 
 }  // namespace cc
diff --git a/cc/test/fake_picture_pile_impl.cc b/cc/test/fake_picture_pile_impl.cc
index bdba092..8353d27 100644
--- a/cc/test/fake_picture_pile_impl.cc
+++ b/cc/test/fake_picture_pile_impl.cc
@@ -10,7 +10,6 @@
 
 #include "base/synchronization/waitable_event.h"
 #include "cc/resources/picture_pile.h"
-#include "cc/test/fake_picture_pile.h"
 #include "cc/test/impl_side_painting_settings.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -29,43 +28,47 @@
 
 FakePicturePileImpl::~FakePicturePileImpl() {}
 
-scoped_refptr<FakePicturePileImpl> FakePicturePileImpl::CreateFilledPile(
+scoped_refptr<FakePicturePileImpl> FakePicturePileImpl::CreatePile(
     const gfx::Size& tile_size,
-    const gfx::Size& layer_bounds) {
+    const gfx::Size& layer_bounds,
+    bool is_filled) {
   FakePicturePile pile(ImplSidePaintingSettings().minimum_contents_scale,
                        ImplSidePaintingSettings().default_tile_grid_size);
   pile.tiling().SetBorderTexels(0);
   pile.tiling().SetTilingSize(layer_bounds);
   pile.tiling().SetMaxTextureSize(tile_size);
-  pile.SetRecordedViewport(gfx::Rect(layer_bounds));
-  pile.SetHasAnyRecordings(true);
-
+  pile.SetRecordedViewport(is_filled ? gfx::Rect(layer_bounds) : gfx::Rect());
+  pile.SetHasAnyRecordings(is_filled);
+  if (is_filled) {
+    for (int x = 0; x < pile.tiling().num_tiles_x(); ++x) {
+      for (int y = 0; y < pile.tiling().num_tiles_y(); ++y)
+        pile.AddRecordingAt(x, y);
+    }
+  }
   scoped_refptr<FakePicturePileImpl> pile_impl(
       new FakePicturePileImpl(&pile, nullptr));
-  for (int x = 0; x < pile_impl->tiling().num_tiles_x(); ++x) {
-    for (int y = 0; y < pile_impl->tiling().num_tiles_y(); ++y)
-      pile_impl->AddRecordingAt(x, y);
-  }
   return pile_impl;
 }
 
+scoped_refptr<FakePicturePileImpl> FakePicturePileImpl::CreateFilledPile(
+    const gfx::Size& tile_size,
+    const gfx::Size& layer_bounds) {
+  bool is_filled = true;
+  return CreatePile(tile_size, layer_bounds, is_filled);
+}
+
 scoped_refptr<FakePicturePileImpl> FakePicturePileImpl::CreateEmptyPile(
     const gfx::Size& tile_size,
     const gfx::Size& layer_bounds) {
-  FakePicturePile pile(ImplSidePaintingSettings().minimum_contents_scale,
-                       ImplSidePaintingSettings().default_tile_grid_size);
-  pile.tiling().SetBorderTexels(0);
-  pile.tiling().SetTilingSize(layer_bounds);
-  pile.tiling().SetMaxTextureSize(tile_size);
-  pile.SetRecordedViewport(gfx::Rect());
-  pile.SetHasAnyRecordings(false);
-  return make_scoped_refptr(new FakePicturePileImpl(&pile, nullptr));
+  bool is_filled = false;
+  return CreatePile(tile_size, layer_bounds, is_filled);
 }
 
 scoped_refptr<FakePicturePileImpl>
 FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings(
     const gfx::Size& tile_size,
-    const gfx::Size& layer_bounds) {
+    const gfx::Size& layer_bounds,
+    bool is_solid_color) {
   FakePicturePile pile(ImplSidePaintingSettings().minimum_contents_scale,
                        ImplSidePaintingSettings().default_tile_grid_size);
   pile.tiling().SetBorderTexels(0);
@@ -74,6 +77,7 @@
   // This simulates a false positive for this flag.
   pile.SetRecordedViewport(gfx::Rect());
   pile.SetHasAnyRecordings(true);
+  pile.SetIsSolidColor(is_solid_color);
   return make_scoped_refptr(new FakePicturePileImpl(&pile, nullptr));
 }
 
@@ -87,10 +91,9 @@
   pile.tiling().SetMaxTextureSize(size);
   pile.SetRecordedViewport(gfx::Rect(size));
   pile.SetHasAnyRecordings(true);
-
+  pile.AddRecordingAt(0, 0);
   scoped_refptr<FakePicturePileImpl> pile_impl(
       new FakePicturePileImpl(&pile, nullptr));
-  pile_impl->AddRecordingAt(0, 0);
   return pile_impl;
 }
 
@@ -109,38 +112,6 @@
   PicturePileImpl::PlaybackToCanvas(canvas, canvas_rect, contents_scale);
 }
 
-void FakePicturePileImpl::AddRecordingAt(int x, int y) {
-  EXPECT_GE(x, 0);
-  EXPECT_GE(y, 0);
-  EXPECT_LT(x, tiling_.num_tiles_x());
-  EXPECT_LT(y, tiling_.num_tiles_y());
-
-  if (HasRecordingAt(x, y))
-    return;
-  gfx::Rect bounds(tiling().TileBounds(x, y));
-  bounds.Inset(-buffer_pixels(), -buffer_pixels());
-
-  scoped_refptr<Picture> picture(
-      Picture::Create(bounds, &client_, tile_grid_size_, true,
-                      RecordingSource::RECORD_NORMALLY));
-  picture_map_[std::pair<int, int>(x, y)].SetPicture(picture);
-  EXPECT_TRUE(HasRecordingAt(x, y));
-
-  has_any_recordings_ = true;
-}
-
-void FakePicturePileImpl::RemoveRecordingAt(int x, int y) {
-  EXPECT_GE(x, 0);
-  EXPECT_GE(y, 0);
-  EXPECT_LT(x, tiling_.num_tiles_x());
-  EXPECT_LT(y, tiling_.num_tiles_y());
-
-  if (!HasRecordingAt(x, y))
-    return;
-  picture_map_.erase(std::pair<int, int>(x, y));
-  EXPECT_FALSE(HasRecordingAt(x, y));
-}
-
 bool FakePicturePileImpl::HasRecordingAt(int x, int y) const {
   PictureMap::const_iterator found = picture_map_.find(PictureMapKey(x, y));
   if (found == picture_map_.end())
@@ -148,46 +119,4 @@
   return !!found->second.GetPicture();
 }
 
-void FakePicturePileImpl::RerecordPile() {
-  for (int y = 0; y < num_tiles_y(); ++y) {
-    for (int x = 0; x < num_tiles_x(); ++x) {
-      RemoveRecordingAt(x, y);
-      AddRecordingAt(x, y);
-    }
-  }
-}
-
-void FakePicturePileImpl::SetMinContentsScale(float min_contents_scale) {
-  if (min_contents_scale_ == min_contents_scale)
-    return;
-
-  // Picture contents are played back scaled. When the final contents scale is
-  // less than 1 (i.e. low res), then multiple recorded pixels will be used
-  // to raster one final pixel.  To avoid splitting a final pixel across
-  // pictures (which would result in incorrect rasterization due to blending), a
-  // buffer margin is added so that any picture can be snapped to integral
-  // final pixels.
-  //
-  // For example, if a 1/4 contents scale is used, then that would be 3 buffer
-  // pixels, since that's the minimum number of pixels to add so that resulting
-  // content can be snapped to a four pixel aligned grid.
-  int buffer_pixels = static_cast<int>(ceil(1 / min_contents_scale) - 1);
-  buffer_pixels = std::max(0, buffer_pixels);
-  SetBufferPixels(buffer_pixels);
-  min_contents_scale_ = min_contents_scale;
-}
-
-void FakePicturePileImpl::SetBufferPixels(int new_buffer_pixels) {
-  if (new_buffer_pixels == buffer_pixels())
-    return;
-
-  Clear();
-  tiling_.SetBorderTexels(new_buffer_pixels);
-}
-
-void FakePicturePileImpl::Clear() {
-  picture_map_.clear();
-  recorded_viewport_ = gfx::Rect();
-}
-
 }  // namespace cc
diff --git a/cc/test/fake_picture_pile_impl.h b/cc/test/fake_picture_pile_impl.h
index 3a43702..a21509a 100644
--- a/cc/test/fake_picture_pile_impl.h
+++ b/cc/test/fake_picture_pile_impl.h
@@ -7,7 +7,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "cc/resources/picture_pile_impl.h"
-#include "cc/test/fake_content_layer_client.h"
+#include "cc/test/fake_picture_pile.h"
 
 namespace base {
 class WaitableEvent;
@@ -17,6 +17,11 @@
 
 class FakePicturePileImpl : public PicturePileImpl {
  public:
+  static scoped_refptr<FakePicturePileImpl> CreatePile(
+      const gfx::Size& tile_size,
+      const gfx::Size& layer_bounds,
+      bool is_filled);
+
   static scoped_refptr<FakePicturePileImpl> CreateFilledPileWithDefaultTileSize(
       const gfx::Size& layer_bounds) {
     return CreateFilledPile(gfx::Size(512, 512), layer_bounds);
@@ -32,8 +37,9 @@
       const gfx::Size& tile_size,
       const gfx::Size& layer_bounds);
   static scoped_refptr<FakePicturePileImpl>
-      CreateEmptyPileThatThinksItHasRecordings(const gfx::Size& tile_size,
-                                               const gfx::Size& layer_bounds);
+  CreateEmptyPileThatThinksItHasRecordings(const gfx::Size& tile_size,
+                                           const gfx::Size& layer_bounds,
+                                           bool is_solid_color);
   static scoped_refptr<FakePicturePileImpl> CreateInfiniteFilledPile();
   static scoped_refptr<FakePicturePileImpl> CreateFromPile(
       const PicturePile* other,
@@ -44,63 +50,18 @@
                         const gfx::Rect& canvas_rect,
                         float contents_scale) const override;
 
-  TilingData& tiling() { return tiling_; }
-
-  void AddRecordingAt(int x, int y);
-  void RemoveRecordingAt(int x, int y);
-  void RerecordPile();
-
-  void add_draw_rect(const gfx::RectF& rect) {
-    client_.add_draw_rect(rect, default_paint_);
-  }
-
-  void add_draw_bitmap(const SkBitmap& bitmap, const gfx::Point& point) {
-    client_.add_draw_bitmap(bitmap, point, default_paint_);
-  }
-
-  void add_draw_rect_with_paint(const gfx::RectF& rect, const SkPaint& paint) {
-    client_.add_draw_rect(rect, paint);
-  }
-
-  void add_draw_bitmap_with_paint(const SkBitmap& bitmap,
-                                  const gfx::Point& point,
-                                  const SkPaint& paint) {
-    client_.add_draw_bitmap(bitmap, point, paint);
-  }
-
-  void set_default_paint(const SkPaint& paint) {
-    default_paint_ = paint;
-  }
-
-  void set_background_color(SkColor color) {
-    background_color_ = color;
-  }
-
-  void set_clear_canvas_with_debug_color(bool clear) {
-    clear_canvas_with_debug_color_ = clear;
-  }
-
-  void set_is_solid_color(bool is_solid_color) {
-    is_solid_color_ = is_solid_color;
-  }
+  const TilingData& tiling() { return tiling_; }
 
   bool HasRecordingAt(int x, int y) const;
-
   int num_tiles_x() const { return tiling_.num_tiles_x(); }
   int num_tiles_y() const { return tiling_.num_tiles_y(); }
 
-  void SetMinContentsScale(float scale);
-  void SetBufferPixels(int new_buffer_pixels);
-  void Clear();
-
  protected:
   FakePicturePileImpl();
   FakePicturePileImpl(const PicturePile* other,
                       base::WaitableEvent* playback_allowed_event);
   ~FakePicturePileImpl() override;
 
-  FakeContentLayerClient client_;
-  SkPaint default_paint_;
   base::WaitableEvent* playback_allowed_event_;
   gfx::Size tile_grid_size_;
 };
diff --git a/cc/test/fake_proxy.cc b/cc/test/fake_proxy.cc
index 4490c76..b288c07 100644
--- a/cc/test/fake_proxy.cc
+++ b/cc/test/fake_proxy.cc
@@ -12,6 +12,10 @@
 
 bool FakeProxy::IsStarted() const { return true; }
 
+bool FakeProxy::CommitToActiveTree() const {
+  return false;
+}
+
 const RendererCapabilities& FakeProxy::GetRendererCapabilities() const {
   return capabilities_;
 }
@@ -38,7 +42,7 @@
   return false;
 }
 
-void FakeProxy::AsValueInto(base::debug::TracedValue*) const {
+void FakeProxy::AsValueInto(base::trace_event::TracedValue*) const {
 }
 
 }  // namespace cc
diff --git a/cc/test/fake_proxy.h b/cc/test/fake_proxy.h
index e77d4f9..2309fef 100644
--- a/cc/test/fake_proxy.h
+++ b/cc/test/fake_proxy.h
@@ -23,6 +23,7 @@
 
   void FinishAllRendering() override {}
   bool IsStarted() const override;
+  bool CommitToActiveTree() const override;
   void SetOutputSurface(scoped_ptr<OutputSurface>) override {}
   void SetLayerTreeHostClientReady() override {}
   void SetVisible(bool visible) override {}
@@ -45,7 +46,7 @@
   bool SupportsImplScrolling() const override;
   void SetDebugState(const LayerTreeDebugState& debug_state) override {}
   bool MainFrameWillHappenForTesting() override;
-  void AsValueInto(base::debug::TracedValue* state) const override;
+  void AsValueInto(base::trace_event::TracedValue* state) const override;
   void SetChildrenNeedBeginFrames(bool children_need_begin_frames) override {}
 
   virtual RendererCapabilities& GetRendererCapabilities();
diff --git a/cc/test/layer_test_common.cc b/cc/test/layer_test_common.cc
index 7e835b8..83f756d 100644
--- a/cc/test/layer_test_common.cc
+++ b/cc/test/layer_test_common.cc
@@ -75,9 +75,17 @@
 
   // Quads that are fully occluded on one axis only should be shrunken.
   for (const auto& quad : quads) {
-    DCHECK(quad->quadTransform().IsIdentityOrIntegerTranslation());
     gfx::Rect target_rect =
         MathUtil::MapEnclosingClippedRect(quad->quadTransform(), quad->rect);
+    if (!quad->quadTransform().IsIdentityOrIntegerTranslation()) {
+      DCHECK(quad->quadTransform().IsPositiveScaleOrTranslation())
+          << quad->quadTransform().ToString();
+      gfx::RectF target_rectf =
+          MathUtil::MapClippedRect(quad->quadTransform(), quad->rect);
+      // Scale transforms allowed, as long as the final transformed rect
+      // ends up on integer boundaries for ease of testing.
+      DCHECK_EQ(target_rectf.ToString(), gfx::RectF(target_rect).ToString());
+    }
     gfx::Rect target_visible_rect = MathUtil::MapEnclosingClippedRect(
         quad->quadTransform(), quad->visible_rect);
 
@@ -129,9 +137,10 @@
   Occlusion occlusion(layer_impl->draw_transform(),
                       SimpleEnclosedRegion(occluded),
                       SimpleEnclosedRegion());
+  layer_impl->draw_properties().occlusion_in_content_space = occlusion;
 
   layer_impl->WillDraw(DRAW_MODE_HARDWARE, resource_provider());
-  layer_impl->AppendQuads(render_pass_.get(), occlusion, &data);
+  layer_impl->AppendQuads(render_pass_.get(), &data);
   layer_impl->DidDraw(resource_provider());
 }
 
@@ -147,9 +156,10 @@
   Occlusion occlusion(layer_impl->draw_transform(),
                       SimpleEnclosedRegion(occluded),
                       SimpleEnclosedRegion());
+  layer_impl->draw_properties().occlusion_in_content_space = occlusion;
 
   layer_impl->WillDraw(DRAW_MODE_HARDWARE, resource_provider());
-  layer_impl->AppendQuads(given_render_pass, occlusion, &data);
+  layer_impl->AppendQuads(given_render_pass, &data);
   layer_impl->DidDraw(resource_provider());
 }
 
@@ -160,12 +170,12 @@
 
   render_pass_->quad_list.clear();
   render_pass_->shared_quad_state_list.clear();
-  occlusion_tracker_.set_occluded_target_rect_for_contributing_surface(
-      occluded);
-  bool for_replica = false;
-  RenderPassId id(1, 1);
+
   surface_impl->AppendQuads(
-      render_pass_.get(), occlusion_tracker_, &data, for_replica, id);
+      render_pass_.get(), gfx::Transform(),
+      Occlusion(gfx::Transform(), SimpleEnclosedRegion(occluded),
+                SimpleEnclosedRegion()),
+      SK_ColorBLACK, 1.f, nullptr, &data, RenderPassId(1, 1));
 }
 
 }  // namespace cc
diff --git a/cc/test/layer_test_common.h b/cc/test/layer_test_common.h
index 9b63f3f..dfd9729 100644
--- a/cc/test/layer_test_common.h
+++ b/cc/test/layer_test_common.h
@@ -9,7 +9,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "cc/quads/render_pass.h"
 #include "cc/test/fake_layer_tree_host.h"
-#include "cc/test/mock_occlusion_tracker.h"
 #include "cc/trees/layer_tree_host_impl.h"
 
 #define EXPECT_SET_NEEDS_COMMIT(expect, code_to_test)                 \
@@ -128,7 +127,6 @@
     scoped_ptr<FakeLayerTreeHost> host_;
     scoped_ptr<LayerImpl> root_layer_impl_;
     scoped_ptr<RenderPass> render_pass_;
-    MockOcclusionTracker<LayerImpl> occlusion_tracker_;
   };
 };
 
diff --git a/cc/test/layer_tree_pixel_resource_test.cc b/cc/test/layer_tree_pixel_resource_test.cc
index cf62d53..6b6c00b 100644
--- a/cc/test/layer_tree_pixel_resource_test.cc
+++ b/cc/test/layer_tree_pixel_resource_test.cc
@@ -183,7 +183,7 @@
 
       *tile_task_worker_pool = GpuTileTaskWorkerPool::Create(
           task_runner, TileTaskWorkerPool::GetTaskGraphRunner(),
-          resource_provider);
+          static_cast<GpuRasterizer*>(host_impl->rasterizer()));
       break;
     case ZERO_COPY_TILE_TASK_WORKER_POOL:
       EXPECT_TRUE(context_provider);
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc
index 8a053fa..f7ab9c2 100644
--- a/cc/test/layer_tree_pixel_test.cc
+++ b/cc/test/layer_tree_pixel_test.cc
@@ -11,6 +11,7 @@
 #include "cc/layers/texture_layer.h"
 #include "cc/output/copy_output_request.h"
 #include "cc/output/copy_output_result.h"
+#include "cc/output/direct_renderer.h"
 #include "cc/resources/texture_mailbox.h"
 #include "cc/test/paths.h"
 #include "cc/test/pixel_comparator.h"
@@ -52,7 +53,8 @@
     case PIXEL_TEST_GL: {
       bool flipped_output_surface = false;
       output_surface = make_scoped_ptr(new PixelTestOutputSurface(
-          new TestInProcessContextProvider, flipped_output_surface));
+          new TestInProcessContextProvider, new TestInProcessContextProvider,
+          flipped_output_surface));
       break;
     }
   }
@@ -67,6 +69,9 @@
   if (commit_tree->source_frame_number() != 0)
     return;
 
+  DirectRenderer* renderer = static_cast<DirectRenderer*>(impl->renderer());
+  renderer->SetEnlargePassTextureAmountForTesting(enlarge_texture_amount_);
+
   gfx::Rect viewport = impl->DeviceViewport();
   // The viewport has a 0,0 origin without external influence.
   EXPECT_EQ(gfx::Point().ToString(), viewport.origin().ToString());
diff --git a/cc/test/layer_tree_pixel_test.h b/cc/test/layer_tree_pixel_test.h
index 91081f8..8d02280 100644
--- a/cc/test/layer_tree_pixel_test.h
+++ b/cc/test/layer_tree_pixel_test.h
@@ -91,6 +91,10 @@
                              uint32 sync_point,
                              bool lost_resource);
 
+  void set_enlarge_texture_amount(const gfx::Vector2d& enlarge_texture_amount) {
+    enlarge_texture_amount_ = enlarge_texture_amount;
+  }
+
   // Common CSS colors defined for tests to use.
   static const SkColor kCSSOrange = 0xffffa500;
   static const SkColor kCSSBrown = 0xffa52a2a;
@@ -106,6 +110,7 @@
   std::vector<scoped_refptr<TextureLayer>> texture_layers_;
   int pending_texture_mailbox_callbacks_;
   bool impl_side_painting_;
+  gfx::Vector2d enlarge_texture_amount_;
 };
 
 }  // namespace cc
diff --git a/cc/test/ordered_simple_task_runner.cc b/cc/test/ordered_simple_task_runner.cc
index 852396e..e337909 100644
--- a/cc/test/ordered_simple_task_runner.cc
+++ b/cc/test/ordered_simple_task_runner.cc
@@ -60,16 +60,16 @@
   return ShouldRunBefore(other);
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 TestOrderablePendingTask::AsValue() const {
-  scoped_refptr<base::debug::TracedValue> state =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
   AsValueInto(state.get());
   return state;
 }
 
 void TestOrderablePendingTask::AsValueInto(
-    base::debug::TracedValue* state) const {
+    base::trace_event::TracedValue* state) const {
   state->SetInteger("id", task_id_);
   state->SetInteger("run_at", GetTimeToRun().ToInternalValue());
   state->SetString("posted_from", location.ToString());
@@ -255,17 +255,17 @@
   return RunUntilTime(now_src_->Now() + period);
 }
 
-// base::debug tracing functionality
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+// base::trace_event tracing functionality
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 OrderedSimpleTaskRunner::AsValue() const {
-  scoped_refptr<base::debug::TracedValue> state =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
   AsValueInto(state.get());
   return state;
 }
 
 void OrderedSimpleTaskRunner::AsValueInto(
-    base::debug::TracedValue* state) const {
+    base::trace_event::TracedValue* state) const {
   state->SetInteger("pending_tasks", pending_tasks_.size());
 
   state->BeginArray("tasks");
diff --git a/cc/test/ordered_simple_task_runner.h b/cc/test/ordered_simple_task_runner.h
index b6e03ba..54b1db4 100644
--- a/cc/test/ordered_simple_task_runner.h
+++ b/cc/test/ordered_simple_task_runner.h
@@ -34,9 +34,9 @@
   bool operator==(const TestOrderablePendingTask& other) const;
   bool operator<(const TestOrderablePendingTask& other) const;
 
-  // debug tracing functions
-  scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
-  void AsValueInto(base::debug::TracedValue* state) const;
+  // base::trace_event tracing functionality
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+  void AsValueInto(base::trace_event::TracedValue* state) const;
 
  private:
   static size_t task_id_counter;
@@ -102,9 +102,9 @@
   bool RunUntilTime(base::TimeTicks time);
   bool RunForPeriod(base::TimeDelta period);
 
-  // base::debug tracing functionality
-  scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
-  virtual void AsValueInto(base::debug::TracedValue* state) const;
+  // base::trace_event tracing functionality
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+  virtual void AsValueInto(base::trace_event::TracedValue* state) const;
 
   // Common conditions to run for, exposed publicly to allow external users to
   // use their own combinations.
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index aecd657..c2dc5b5 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -127,7 +127,8 @@
   enable_pixel_output_.reset(new gfx::DisableNullDrawGLBindings);
 
   output_surface_.reset(new PixelTestOutputSurface(
-      new TestInProcessContextProvider, flipped_output_surface));
+      new TestInProcessContextProvider, new TestInProcessContextProvider,
+      flipped_output_surface));
   output_surface_->BindToClient(output_surface_client_.get());
 
   shared_bitmap_manager_.reset(new TestSharedBitmapManager);
diff --git a/cc/test/pixel_test_output_surface.cc b/cc/test/pixel_test_output_surface.cc
index ced1898..616103c 100644
--- a/cc/test/pixel_test_output_surface.cc
+++ b/cc/test/pixel_test_output_surface.cc
@@ -11,14 +11,25 @@
 
 PixelTestOutputSurface::PixelTestOutputSurface(
     scoped_refptr<ContextProvider> context_provider,
+    scoped_refptr<ContextProvider> worker_context_provider,
     bool flipped_output_surface)
-    : OutputSurface(context_provider), external_stencil_test_(false) {
+    : OutputSurface(context_provider, worker_context_provider),
+      external_stencil_test_(false) {
   capabilities_.flipped_output_surface = flipped_output_surface;
 }
 
 PixelTestOutputSurface::PixelTestOutputSurface(
+    scoped_refptr<ContextProvider> context_provider,
+    bool flipped_output_surface)
+    : PixelTestOutputSurface(context_provider,
+                             nullptr,
+                             flipped_output_surface) {
+}
+
+PixelTestOutputSurface::PixelTestOutputSurface(
     scoped_ptr<SoftwareOutputDevice> software_device)
-    : OutputSurface(software_device.Pass()), external_stencil_test_(false) {}
+    : OutputSurface(software_device.Pass()), external_stencil_test_(false) {
+}
 
 void PixelTestOutputSurface::Reshape(const gfx::Size& size,
                                      float scale_factor) {
diff --git a/cc/test/pixel_test_output_surface.h b/cc/test/pixel_test_output_surface.h
index a58e2c4..27819c1 100644
--- a/cc/test/pixel_test_output_surface.h
+++ b/cc/test/pixel_test_output_surface.h
@@ -13,6 +13,10 @@
  public:
   explicit PixelTestOutputSurface(
       scoped_refptr<ContextProvider> context_provider,
+      scoped_refptr<ContextProvider> worker_context_provider,
+      bool flipped_output_surface);
+  explicit PixelTestOutputSurface(
+      scoped_refptr<ContextProvider> context_provider,
       bool flipped_output_surface);
   explicit PixelTestOutputSurface(
       scoped_ptr<SoftwareOutputDevice> software_device);
diff --git a/cc/test/scheduler_test_common.cc b/cc/test/scheduler_test_common.cc
index 03e65ab..94bcf5f 100644
--- a/cc/test/scheduler_test_common.cc
+++ b/cc/test/scheduler_test_common.cc
@@ -37,7 +37,8 @@
 void FakeBeginFrameSource::DidFinishFrame(size_t remaining_frames) {
   remaining_frames_ = remaining_frames;
 }
-void FakeBeginFrameSource::AsValueInto(base::debug::TracedValue* dict) const {
+void FakeBeginFrameSource::AsValueInto(
+    base::trace_event::TracedValue* dict) const {
   dict->SetString("type", "FakeBeginFrameSource");
   BeginFrameSourceMixIn::AsValueInto(dict);
 }
diff --git a/cc/test/scheduler_test_common.h b/cc/test/scheduler_test_common.h
index 93cff9b..00cdd75 100644
--- a/cc/test/scheduler_test_common.h
+++ b/cc/test/scheduler_test_common.h
@@ -90,7 +90,7 @@
 
   // BeginFrameSource
   void DidFinishFrame(size_t remaining_frames) override;
-  void AsValueInto(base::debug::TracedValue* dict) const override;
+  void AsValueInto(base::trace_event::TracedValue* dict) const override;
 
   ~FakeBeginFrameSource() override {}
 };
diff --git a/cc/test/test_context_provider.cc b/cc/test/test_context_provider.cc
index 4c24fe1..bf85ea3 100644
--- a/cc/test/test_context_provider.cc
+++ b/cc/test/test_context_provider.cc
@@ -13,7 +13,7 @@
 #include "cc/test/test_gles2_interface.h"
 #include "cc/test/test_web_graphics_context_3d.h"
 #include "third_party/skia/include/gpu/GrContext.h"
-#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
+#include "third_party/skia/include/gpu/gl/SkNullGLContext.h"
 
 namespace cc {
 
@@ -69,6 +69,10 @@
   return true;
 }
 
+void TestContextProvider::DetachFromThread() {
+  context_thread_checker_.DetachFromThread();
+}
+
 ContextProvider::Capabilities TestContextProvider::ContextCapabilities() {
   DCHECK(bound_);
   DCHECK(context_thread_checker_.CalledOnValidThread());
@@ -95,14 +99,21 @@
   if (gr_context_)
     return gr_context_.get();
 
-  skia::RefPtr<const GrGLInterface> null_interface =
-      skia::AdoptRef(GrGLCreateNullInterface());
+  skia::RefPtr<class SkGLContext> gl_context =
+      skia::AdoptRef(SkNullGLContext::Create(kNone_GrGLStandard));
+  gl_context->makeCurrent();
   gr_context_ = skia::AdoptRef(GrContext::Create(
-      kOpenGL_GrBackend,
-      reinterpret_cast<GrBackendContext>(null_interface.get())));
+      kOpenGL_GrBackend, reinterpret_cast<GrBackendContext>(gl_context->gl())));
   return gr_context_.get();
 }
 
+void TestContextProvider::SetupLock() {
+}
+
+base::Lock* TestContextProvider::GetLock() {
+  return &context_lock_;
+}
+
 bool TestContextProvider::IsContextLost() {
   DCHECK(bound_);
   DCHECK(context_thread_checker_.CalledOnValidThread());
diff --git a/cc/test/test_context_provider.h b/cc/test/test_context_provider.h
index 3be8b43..9dd7b62 100644
--- a/cc/test/test_context_provider.h
+++ b/cc/test/test_context_provider.h
@@ -29,10 +29,13 @@
       scoped_ptr<TestWebGraphicsContext3D> context);
 
   bool BindToCurrentThread() override;
+  void DetachFromThread() override;
   Capabilities ContextCapabilities() override;
   gpu::gles2::GLES2Interface* ContextGL() override;
   gpu::ContextSupport* ContextSupport() override;
   class GrContext* GrContext() override;
+  void SetupLock() override;
+  base::Lock* GetLock() override;
   bool IsContextLost() override;
   void VerifyContexts() override;
   void DeleteCachedResources() override;
@@ -74,6 +77,8 @@
   base::Lock destroyed_lock_;
   bool destroyed_;
 
+  base::Lock context_lock_;
+
   LostContextCallback lost_context_callback_;
   MemoryPolicyChangedCallback memory_policy_changed_callback_;
   skia::RefPtr<class GrContext> gr_context_;
diff --git a/cc/test/test_in_process_context_provider.cc b/cc/test/test_in_process_context_provider.cc
index 34b0493..3539bd2 100644
--- a/cc/test/test_in_process_context_provider.cc
+++ b/cc/test/test_in_process_context_provider.cc
@@ -124,6 +124,13 @@
   return gr_context_.get();
 }
 
+void TestInProcessContextProvider::SetupLock() {
+}
+
+base::Lock* TestInProcessContextProvider::GetLock() {
+  return &context_lock_;
+}
+
 ContextProvider::Capabilities
 TestInProcessContextProvider::ContextCapabilities() {
   ContextProvider::Capabilities capabilities;
diff --git a/cc/test/test_in_process_context_provider.h b/cc/test/test_in_process_context_provider.h
index 0533ff4..9fa77b7 100644
--- a/cc/test/test_in_process_context_provider.h
+++ b/cc/test/test_in_process_context_provider.h
@@ -5,6 +5,7 @@
 #ifndef CC_TEST_TEST_IN_PROCESS_CONTEXT_PROVIDER_H_
 #define CC_TEST_TEST_IN_PROCESS_CONTEXT_PROVIDER_H_
 
+#include "base/synchronization/lock.h"
 #include "cc/output/context_provider.h"
 #include "cc/test/test_gpu_memory_buffer_manager.h"
 #include "cc/test/test_image_factory.h"
@@ -31,6 +32,8 @@
   gpu::gles2::GLES2Interface* ContextGL() override;
   gpu::ContextSupport* ContextSupport() override;
   class GrContext* GrContext() override;
+  void SetupLock() override;
+  base::Lock* GetLock() override;
   Capabilities ContextCapabilities() override;
   bool IsContextLost() override;
   void VerifyContexts() override;
@@ -51,6 +54,7 @@
   TestImageFactory image_factory_;
   scoped_ptr<gpu::GLInProcessContext> context_;
   skia::RefPtr<class GrContext> gr_context_;
+  base::Lock context_lock_;
 };
 
 }  // namespace cc
diff --git a/cc/test/test_now_source.cc b/cc/test/test_now_source.cc
index 2ffb36e..0576d06 100644
--- a/cc/test/test_now_source.cc
+++ b/cc/test/test_now_source.cc
@@ -93,14 +93,14 @@
 }
 
 // TestNowSource::Tracing functions
-void TestNowSource::AsValueInto(base::debug::TracedValue* state) const {
+void TestNowSource::AsValueInto(base::trace_event::TracedValue* state) const {
   state->SetInteger("now_in_microseconds", now_.ToInternalValue());
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat> TestNowSource::AsValue()
-    const {
-  scoped_refptr<base::debug::TracedValue> state =
-      new base::debug::TracedValue();
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+TestNowSource::AsValue() const {
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
   AsValueInto(state.get());
   return state;
 }
diff --git a/cc/test/test_now_source.h b/cc/test/test_now_source.h
index 5538e89..54e5a28 100644
--- a/cc/test/test_now_source.h
+++ b/cc/test/test_now_source.h
@@ -33,8 +33,8 @@
   static const base::TimeTicks kAbsoluteMaxNow;
 
   // Tracing functions
-  scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
-  void AsValueInto(base::debug::TracedValue* state) const;
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+  void AsValueInto(base::trace_event::TracedValue* state) const;
   std::string ToString() const;
 
  protected:
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc
index 8217ce0..c9ead98 100644
--- a/cc/trees/draw_property_utils.cc
+++ b/cc/trees/draw_property_utils.cc
@@ -250,8 +250,8 @@
 }
 
 void ComputeTransforms(TransformTree* transform_tree) {
-  for (int i = 0; i < static_cast<int>(transform_tree->size()); ++i)
-    transform_tree->UpdateScreenSpaceTransform(i);
+  for (int i = 1; i < static_cast<int>(transform_tree->size()); ++i)
+    transform_tree->UpdateTransforms(i);
 }
 
 void ComputeVisibleRectsUsingPropertyTrees(
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index fa4dd5d..f478078 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -119,7 +119,7 @@
       debug_state_(settings.initial_debug_state),
       top_controls_shrink_blink_size_(false),
       top_controls_height_(0.f),
-      top_controls_content_offset_(0.f),
+      top_controls_shown_ratio_(0.f),
       device_scale_factor_(1.f),
       visible_(true),
       page_scale_factor_(1.f),
@@ -335,20 +335,10 @@
 
   sync_tree->PassSwapPromises(&swap_promise_list_);
 
-  // Track the change in top controls height to offset the top_controls_delta
-  // properly.  This is so that the top controls offset will be maintained
-  // across height changes.
-  float top_controls_height_delta =
-      sync_tree->top_controls_height() - top_controls_height_;
-
   sync_tree->set_top_controls_shrink_blink_size(
       top_controls_shrink_blink_size_);
   sync_tree->set_top_controls_height(top_controls_height_);
-  sync_tree->set_top_controls_content_offset(top_controls_content_offset_);
-  sync_tree->set_top_controls_delta(sync_tree->top_controls_delta() -
-                                    sync_tree->sent_top_controls_delta() -
-                                    top_controls_height_delta);
-  sync_tree->set_sent_top_controls_delta(0.f);
+  sync_tree->PushTopControlsFromMainThread(top_controls_shown_ratio_);
 
   host_impl->SetUseGpuRasterization(UseGpuRasterization());
   host_impl->set_gpu_rasterization_status(GetGpuRasterizationStatus());
@@ -691,11 +681,11 @@
   SetNeedsCommit();
 }
 
-void LayerTreeHost::SetTopControlsContentOffset(float offset) {
-  if (top_controls_content_offset_ == offset)
+void LayerTreeHost::SetTopControlsShownRatio(float ratio) {
+  if (top_controls_shown_ratio_ == ratio)
     return;
 
-  top_controls_content_offset_ = offset;
+  top_controls_shown_ratio_ = ratio;
   SetNeedsCommit();
 }
 
@@ -1229,7 +1219,7 @@
                  animate));
 }
 
-void LayerTreeHost::AsValueInto(base::debug::TracedValue* state) const {
+void LayerTreeHost::AsValueInto(base::trace_event::TracedValue* state) const {
   state->BeginDictionary("proxy");
   proxy_->AsValueInto(state);
   state->EndDictionary();
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index f41e023..b17b5a4 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -212,7 +212,7 @@
   void SetViewportSize(const gfx::Size& device_viewport_size);
   void SetTopControlsShrinkBlinkSize(bool shrink);
   void SetTopControlsHeight(float height);
-  void SetTopControlsContentOffset(float offset);
+  void SetTopControlsShownRatio(float ratio);
 
   gfx::Size device_viewport_size() const { return device_viewport_size_; }
 
@@ -273,7 +273,7 @@
   }
 
   // Obtains a thorough dump of the LayerTreeHost as a value.
-  void AsValueInto(base::debug::TracedValue* value) const;
+  void AsValueInto(base::trace_event::TracedValue* value) const;
 
   bool in_paint_layer_contents() const { return in_paint_layer_contents_; }
 
@@ -416,7 +416,7 @@
   gfx::Size device_viewport_size_;
   bool top_controls_shrink_blink_size_;
   float top_controls_height_;
-  float top_controls_content_offset_;
+  float top_controls_shown_ratio_;
   float device_scale_factor_;
 
   bool visible_;
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index f21ed3f..70c5037 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -21,6 +21,7 @@
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/vector2d_conversions.h"
 #include "ui/gfx/transform.h"
+#include "ui/gfx/transform_util.h"
 
 namespace cc {
 
@@ -1202,30 +1203,12 @@
   }
 };
 
-static bool ValidateRenderSurface(LayerImpl* layer) {
-  // There are a few cases in which it is incorrect to not have a
-  // render_surface.
-  if (layer->render_surface())
-    return true;
-
-  return layer->filters().IsEmpty() && layer->background_filters().IsEmpty() &&
-         !layer->mask_layer() && !layer->replica_layer() &&
-         !IsRootLayer(layer) && !layer->is_root_for_isolated_group() &&
-         !layer->HasCopyRequest();
-}
-
-static bool ValidateRenderSurface(Layer* layer) {
-  return true;
-}
-
 // Recursively walks the layer tree to compute any information that is needed
 // before doing the main recursion.
 template <typename LayerType>
 static void PreCalculateMetaInformation(
     LayerType* layer,
     PreCalculateMetaInformationRecursiveData* recursive_data) {
-  DCHECK(ValidateRenderSurface(layer));
-
   layer->draw_properties().sorted_for_recursion = false;
   layer->draw_properties().has_child_with_a_scroll_parent = false;
 
@@ -1271,11 +1254,6 @@
       recursive_data->layer_or_descendant_has_input_handler;
 }
 
-static void RoundTranslationComponents(gfx::Transform* transform) {
-  transform->matrix().set(0, 3, MathUtil::Round(transform->matrix().get(0, 3)));
-  transform->matrix().set(1, 3, MathUtil::Round(transform->matrix().get(1, 3)));
-}
-
 template <typename LayerType>
 struct SubtreeGlobals {
   LayerSorter* layer_sorter;
@@ -1701,7 +1679,7 @@
     // blurriness.  To avoid side-effects, do this only if the transform is
     // simple.
     gfx::Vector2dF previous_translation = combined_transform.To2dTranslation();
-    RoundTranslationComponents(&combined_transform);
+    combined_transform.RoundTranslationComponents();
     gfx::Vector2dF current_translation = combined_transform.To2dTranslation();
 
     // This rounding changes the scroll delta, and so must be included
@@ -2491,6 +2469,12 @@
          std::abs(r1.height() - r2.height()) <= tolerance;
 }
 
+static bool ApproximatelyEqual(const gfx::Transform& a,
+                               const gfx::Transform& b) {
+  static const float tolerance = 0.01f;
+  return gfx::MatrixDistance(a, b) < tolerance;
+}
+
 void LayerTreeHostCommon::CalculateDrawProperties(
     CalcDrawPropsMainInputs* inputs) {
   UpdateRenderSurfaces(inputs->root_layer,
@@ -2520,8 +2504,8 @@
   DCHECK(inputs->root_layer->render_surface());
 
   if (inputs->verify_property_trees) {
-    // TODO(ajuma): Can we efficiently cache some of this rather than
-    // starting from scratch every frame?
+    // The translation from layer to property trees is an intermediate state. We
+    // will eventually get these data passed directly to the compositor.
     TransformTree transform_tree;
     ClipTree clip_tree;
     ComputeVisibleRectsUsingPropertyTrees(
@@ -2530,23 +2514,24 @@
         gfx::Rect(inputs->device_viewport_size), inputs->device_transform,
         &transform_tree, &clip_tree);
 
-    bool failed = false;
     LayerIterator<Layer> it, end;
     for (it = LayerIterator<Layer>::Begin(inputs->render_surface_layer_list),
         end = LayerIterator<Layer>::End(inputs->render_surface_layer_list);
          it != end; ++it) {
       Layer* current_layer = *it;
-      if (it.represents_itself()) {
-        if (!failed && current_layer->DrawsContent() &&
-            !ApproximatelyEqual(
-                current_layer->visible_content_rect(),
-                current_layer->visible_rect_from_property_trees())) {
-          failed = true;
-        }
-      }
-    }
+      if (!it.represents_itself() || !current_layer->DrawsContent())
+        continue;
 
-    CHECK(!failed);
+      const bool visible_rects_match =
+          ApproximatelyEqual(current_layer->visible_content_rect(),
+                             current_layer->visible_rect_from_property_trees());
+      CHECK(visible_rects_match);
+
+      const bool draw_transforms_match = ApproximatelyEqual(
+          current_layer->draw_transform(),
+          current_layer->draw_transform_from_property_trees(transform_tree));
+      CHECK(draw_transforms_match);
+    }
   }
 }
 
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 672ffe8..3cb2858 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -68,7 +68,6 @@
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_host_common.h"
 #include "cc/trees/layer_tree_impl.h"
-#include "cc/trees/occlusion_tracker.h"
 #include "cc/trees/single_thread_proxy.h"
 #include "cc/trees/tree_synchronizer.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
@@ -235,8 +234,9 @@
   SetDebugState(settings.initial_debug_state);
 
   // LTHI always has an active tree.
-  active_tree_ = LayerTreeImpl::create(this, new SyncedProperty<ScaleGroup>(),
-                                       new SyncedElasticOverscroll);
+  active_tree_ =
+      LayerTreeImpl::create(this, new SyncedProperty<ScaleGroup>(),
+                            new SyncedTopControls, new SyncedElasticOverscroll);
 
   TRACE_EVENT_OBJECT_CREATED_WITH_ID(
       TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::LayerTreeHostImpl", id_);
@@ -295,7 +295,7 @@
   if (!settings_.impl_side_painting && output_surface_)
     output_surface_->ForceReclaimResources();
 
-  if (UsePendingTreeForSync())
+  if (settings_.impl_side_painting && !proxy_->CommitToActiveTree())
     CreatePendingTree();
 }
 
@@ -548,7 +548,7 @@
 }
 
 void LayerTreeHostImpl::FrameData::AsValueInto(
-    base::debug::TracedValue* value) const {
+    base::trace_event::TracedValue* value) const {
   value->SetBoolean("has_no_damage", has_no_damage);
 
   // Quad data can be quite large, so only dump render passes if we select
@@ -588,51 +588,54 @@
   }
 }
 
-static void AppendQuadsForLayer(
-    RenderPass* target_render_pass,
-    LayerImpl* layer,
-    const OcclusionTracker<LayerImpl>& occlusion_tracker,
-    AppendQuadsData* append_quads_data) {
-  layer->AppendQuads(
-      target_render_pass,
-      occlusion_tracker.GetCurrentOcclusionForLayer(layer->draw_transform()),
-      append_quads_data);
-}
-
 static void AppendQuadsForRenderSurfaceLayer(
     RenderPass* target_render_pass,
     LayerImpl* layer,
     const RenderPass* contributing_render_pass,
-    const OcclusionTracker<LayerImpl>& occlusion_tracker,
     AppendQuadsData* append_quads_data) {
-  bool is_replica = false;
-  layer->render_surface()->AppendQuads(target_render_pass,
-                                       occlusion_tracker,
-                                       append_quads_data,
-                                       is_replica,
-                                       contributing_render_pass->id);
+  RenderSurfaceImpl* surface = layer->render_surface();
+  const gfx::Transform& draw_transform = surface->draw_transform();
+  const Occlusion& occlusion = surface->occlusion_in_content_space();
+  SkColor debug_border_color = surface->GetDebugBorderColor();
+  float debug_border_width = surface->GetDebugBorderWidth();
+  LayerImpl* mask_layer = layer->mask_layer();
+
+  surface->AppendQuads(target_render_pass, draw_transform, occlusion,
+                       debug_border_color, debug_border_width, mask_layer,
+                       append_quads_data, contributing_render_pass->id);
 
   // Add replica after the surface so that it appears below the surface.
   if (layer->has_replica()) {
-    is_replica = true;
-    layer->render_surface()->AppendQuads(target_render_pass,
-                                         occlusion_tracker,
-                                         append_quads_data,
-                                         is_replica,
-                                         contributing_render_pass->id);
+    const gfx::Transform& replica_draw_transform =
+        surface->replica_draw_transform();
+    Occlusion replica_occlusion = occlusion.GetOcclusionWithGivenDrawTransform(
+        surface->replica_draw_transform());
+    SkColor replica_debug_border_color = surface->GetReplicaDebugBorderColor();
+    float replica_debug_border_width = surface->GetReplicaDebugBorderWidth();
+    // TODO(danakj): By using the same RenderSurfaceImpl for both the
+    // content and its reflection, it's currently not possible to apply a
+    // separate mask to the reflection layer or correctly handle opacity in
+    // reflections (opacity must be applied after drawing both the layer and its
+    // reflection). The solution is to introduce yet another RenderSurfaceImpl
+    // to draw the layer and its reflection in. For now we only apply a separate
+    // reflection mask if the contents don't have a mask of their own.
+    LayerImpl* replica_mask_layer =
+        mask_layer ? mask_layer : layer->replica_layer()->mask_layer();
+
+    surface->AppendQuads(target_render_pass, replica_draw_transform,
+                         replica_occlusion, replica_debug_border_color,
+                         replica_debug_border_width, replica_mask_layer,
+                         append_quads_data, contributing_render_pass->id);
   }
 }
 
-static void AppendQuadsToFillScreen(
-    const gfx::Rect& root_scroll_layer_rect,
-    RenderPass* target_render_pass,
-    LayerImpl* root_layer,
-    SkColor screen_background_color,
-    const OcclusionTracker<LayerImpl>& occlusion_tracker) {
+static void AppendQuadsToFillScreen(const gfx::Rect& root_scroll_layer_rect,
+                                    RenderPass* target_render_pass,
+                                    LayerImpl* root_layer,
+                                    SkColor screen_background_color,
+                                    const Region& fill_region) {
   if (!root_layer || !SkColorGetA(screen_background_color))
     return;
-
-  Region fill_region = occlusion_tracker.ComputeVisibleRegionInScreen();
   if (fill_region.IsEmpty())
     return;
 
@@ -736,23 +739,14 @@
     root_pass->damage_rect = root_pass->output_rect;
   }
 
-  OcclusionTracker<LayerImpl> occlusion_tracker(
-      active_tree_->root_layer()->render_surface()->content_rect());
-  occlusion_tracker.set_minimum_tracking_size(
-      settings_.minimum_occlusion_tracking_size);
-
-  if (debug_state_.show_occluding_rects) {
-    occlusion_tracker.set_occluding_screen_space_rects_container(
-        &frame->occluding_screen_space_rects);
-  }
-  if (debug_state_.show_non_occluding_rects) {
-    occlusion_tracker.set_non_occluding_screen_space_rects_container(
-        &frame->non_occluding_screen_space_rects);
-  }
-
-  // Add quads to the Render passes in front-to-back order to allow for testing
-  // occlusion and performing culling during the tree walk.
-  typedef LayerIterator<LayerImpl> LayerIteratorType;
+  // Grab this region here before iterating layers. Taking copy requests from
+  // the layers while constructing the render passes will dirty the render
+  // surface layer list and this unoccluded region, flipping the dirty bit to
+  // true, and making us able to query for it without doing
+  // UpdateDrawProperties again. The value inside the Region is not actually
+  // changed until UpdateDrawProperties happens, so a reference to it is safe.
+  const Region& unoccluded_screen_space_region =
+      active_tree_->UnoccludedScreenSpaceRegion();
 
   // Typically when we are missing a texture and use a checkerboard quad, we
   // still draw the frame. However when the layer being checkerboarded is moving
@@ -770,19 +764,15 @@
   int num_missing_tiles = 0;
   int num_incomplete_tiles = 0;
 
-  LayerIteratorType end =
-      LayerIteratorType::End(frame->render_surface_layer_list);
-  for (LayerIteratorType it =
-           LayerIteratorType::Begin(frame->render_surface_layer_list);
-       it != end;
-       ++it) {
+  auto end = LayerIterator<LayerImpl>::End(frame->render_surface_layer_list);
+  for (auto it =
+           LayerIterator<LayerImpl>::Begin(frame->render_surface_layer_list);
+       it != end; ++it) {
     RenderPassId target_render_pass_id =
         it.target_render_surface_layer()->render_surface()->GetRenderPassId();
     RenderPass* target_render_pass =
         frame->render_passes_by_id[target_render_pass_id];
 
-    occlusion_tracker.EnterLayer(it);
-
     AppendQuadsData append_quads_data;
 
     if (it.represents_target_render_surface()) {
@@ -800,13 +790,12 @@
       AppendQuadsForRenderSurfaceLayer(target_render_pass,
                                        *it,
                                        contributing_render_pass,
-                                       occlusion_tracker,
                                        &append_quads_data);
     } else if (it.represents_itself() &&
                !it->visible_content_rect().IsEmpty()) {
       bool occluded =
-          occlusion_tracker.GetCurrentOcclusionForLayer(it->draw_transform())
-              .IsOccluded(it->visible_content_rect());
+          it->draw_properties().occlusion_in_content_space.IsOccluded(
+              it->visible_content_rect());
       if (!occluded && it->WillDraw(draw_mode, resource_provider_.get())) {
         DCHECK_EQ(active_tree_, it->layer_tree_impl());
 
@@ -820,20 +809,14 @@
             RenderPass* render_pass =
                 frame->render_passes_by_id[contributing_render_pass_id];
 
-            AppendQuadsForLayer(render_pass,
-                                *it,
-                                occlusion_tracker,
-                                &append_quads_data);
+            it->AppendQuads(render_pass, &append_quads_data);
 
             contributing_render_pass_id =
                 it->NextContributingRenderPassId(contributing_render_pass_id);
           }
         }
 
-        AppendQuadsForLayer(target_render_pass,
-                            *it,
-                            occlusion_tracker,
-                            &append_quads_data);
+        it->AppendQuads(target_render_pass, &append_quads_data);
 
         // For layers that represent themselves, add composite frame timing
         // requests if the visible rect intersects the requested rect.
@@ -872,8 +855,6 @@
       if (RequiresHighResToDraw())
         draw_result = DRAW_ABORTED_MISSING_HIGH_RES_CONTENT;
     }
-
-    occlusion_tracker.LeaveLayer(it);
   }
 
   if (have_copy_request ||
@@ -894,10 +875,8 @@
     frame->render_passes.back()->has_transparent_background = false;
     AppendQuadsToFillScreen(
         active_tree_->RootScrollLayerDeviceViewportBounds(),
-        frame->render_passes.back(),
-        active_tree_->root_layer(),
-        active_tree_->background_color(),
-        occlusion_tracker);
+        frame->render_passes.back(), active_tree_->root_layer(),
+        active_tree_->background_color(), unoccluded_screen_space_region);
   }
 
   RemoveRenderPasses(CullRenderPassesWithNoQuads(), frame);
@@ -1113,8 +1092,10 @@
 void LayerTreeHostImpl::ResetTreesForTesting() {
   if (active_tree_)
     active_tree_->DetachLayerTree();
-  active_tree_ = LayerTreeImpl::create(this, active_tree()->page_scale_factor(),
-                                       active_tree()->elastic_overscroll());
+  active_tree_ =
+      LayerTreeImpl::create(this, active_tree()->page_scale_factor(),
+                            active_tree()->top_controls_shown_ratio(),
+                            active_tree()->elastic_overscroll());
   if (pending_tree_)
     pending_tree_->DetachLayerTree();
   pending_tree_ = nullptr;
@@ -1206,32 +1187,31 @@
     std::vector<PictureLayerImpl::Pair>* layer_pairs,
     bool need_valid_tile_priorities) const {
   DCHECK(layer_pairs->empty());
-  for (std::vector<PictureLayerImpl*>::const_iterator it =
-           picture_layers_.begin();
-       it != picture_layers_.end();
-       ++it) {
-    PictureLayerImpl* layer = *it;
 
-    if (!layer->IsOnActiveOrPendingTree() ||
-        (need_valid_tile_priorities && !layer->HasValidTilePriorities()))
+  for (auto& layer : active_tree_->picture_layers()) {
+    if (need_valid_tile_priorities && !layer->HasValidTilePriorities())
       continue;
-
     PictureLayerImpl* twin_layer = layer->GetPendingOrActiveTwinLayer();
-
     // Ignore the twin layer when tile priorities are invalid.
     if (need_valid_tile_priorities && twin_layer &&
-        !twin_layer->HasValidTilePriorities())
-      twin_layer = NULL;
+        !twin_layer->HasValidTilePriorities()) {
+      twin_layer = nullptr;
+    }
+    layer_pairs->push_back(PictureLayerImpl::Pair(layer, twin_layer));
+  }
 
-    // If the current tree is ACTIVE_TREE, then always generate a layer_pair.
-    // If current tree is PENDING_TREE, then only generate a layer_pair if
-    // there is no twin layer.
-    if (layer->GetTree() == ACTIVE_TREE) {
-      DCHECK_IMPLIES(twin_layer, twin_layer->GetTree() == PENDING_TREE);
-      layer_pairs->push_back(PictureLayerImpl::Pair(layer, twin_layer));
-    } else if (!twin_layer) {
-      DCHECK(layer->GetTree() == PENDING_TREE);
-      layer_pairs->push_back(PictureLayerImpl::Pair(NULL, layer));
+  if (pending_tree_) {
+    for (auto& layer : pending_tree_->picture_layers()) {
+      if (need_valid_tile_priorities && !layer->HasValidTilePriorities())
+        continue;
+      if (PictureLayerImpl* twin_layer = layer->GetPendingOrActiveTwinLayer()) {
+        if (!need_valid_tile_priorities ||
+            twin_layer->HasValidTilePriorities()) {
+          // Already captured from the active tree.
+          continue;
+        }
+      }
+      layer_pairs->push_back(PictureLayerImpl::Pair(nullptr, layer));
     }
   }
 }
@@ -1265,11 +1245,6 @@
   is_likely_to_require_a_draw_ = is_likely_to_require_a_draw;
 }
 
-const std::vector<PictureLayerImpl*>& LayerTreeHostImpl::GetPictureLayers()
-    const {
-  return picture_layers_;
-}
-
 void LayerTreeHostImpl::NotifyReadyToActivate() {
   client_->NotifyReadyToActivate();
 }
@@ -1452,6 +1427,16 @@
   active_tree_->GetViewportSelection(&metadata.selection_start,
                                      &metadata.selection_end);
 
+  LayerImpl* root_layer_for_overflow = OuterViewportScrollLayer()
+                                           ? OuterViewportScrollLayer()
+                                           : InnerViewportScrollLayer();
+  if (root_layer_for_overflow) {
+    metadata.root_overflow_x_hidden =
+        !root_layer_for_overflow->user_scrollable_horizontal();
+    metadata.root_overflow_y_hidden =
+        !root_layer_for_overflow->user_scrollable_vertical();
+  }
+
   if (!InnerViewportScrollLayer())
     return metadata;
 
@@ -1499,8 +1484,6 @@
         active_tree_->root_layer(),
         active_tree_->hud_layer(),
         *frame->render_surface_layer_list,
-        frame->occluding_screen_space_rects,
-        frame->non_occluding_screen_space_rects,
         debug_state_);
   }
 
@@ -1678,9 +1661,9 @@
       active_tree_->top_controls_shrink_blink_size()
           ? active_tree_->top_controls_height()
           : 0.f;
-  inner_container->SetBoundsDelta(
-      gfx::Vector2dF(0, top_controls_layout_height -
-                            active_tree_->total_top_controls_content_offset()));
+  inner_container->SetBoundsDelta(gfx::Vector2dF(
+      0,
+      top_controls_layout_height - top_controls_manager_->ContentTopOffset()));
 
   if (!outer_container || outer_container->BoundsForScrolling().IsEmpty())
     return;
@@ -1768,16 +1751,9 @@
   else
     pending_tree_ =
         LayerTreeImpl::create(this, active_tree()->page_scale_factor(),
+                              active_tree()->top_controls_shown_ratio(),
                               active_tree()->elastic_overscroll());
 
-  // Update the delta from the active tree, which may have
-  // adjusted its delta prior to the pending tree being created.
-  DCHECK_EQ(0.f, pending_tree_->sent_top_controls_delta());
-  pending_tree_->set_top_controls_delta(
-      active_tree_->top_controls_delta() -
-      active_tree_->sent_top_controls_delta());
-  pending_tree_->set_top_controls_height(active_tree_->top_controls_height());
-
   client_->OnCanDrawStateChanged(CanDraw());
   TRACE_EVENT_ASYNC_BEGIN0("cc", "PendingTree:waiting", pending_tree_.get());
 }
@@ -1812,14 +1788,6 @@
     active_tree_->SetRootLayerScrollOffsetDelegate(
         root_layer_scroll_offset_delegate_);
 
-    if (top_controls_manager_) {
-      top_controls_manager_->SetTopControlsHeight(
-          active_tree_->top_controls_height());
-      top_controls_manager_->SetControlsTopOffset(
-          active_tree_->total_top_controls_content_offset() -
-          active_tree_->top_controls_height());
-    }
-
     UpdateViewportContainerSizes();
   } else {
     active_tree_->ProcessUIResourceRequestQueue();
@@ -1831,7 +1799,7 @@
     client_->RenewTreePriority();
     // If we have any picture layers, then by activating we also modified tile
     // priorities.
-    if (!picture_layers_.empty())
+    if (!active_tree_->picture_layers().empty())
       DidModifyTilePriorities();
   }
 
@@ -2039,7 +2007,7 @@
 
     *tile_task_worker_pool = GpuTileTaskWorkerPool::Create(
         task_runner, TileTaskWorkerPool::GetTaskGraphRunner(),
-        resource_provider_.get());
+        static_cast<GpuRasterizer*>(rasterizer_.get()));
     return;
   }
 
@@ -2104,12 +2072,6 @@
   single_thread_synchronous_task_graph_runner_ = nullptr;
 }
 
-bool LayerTreeHostImpl::UsePendingTreeForSync() const {
-  // In impl-side painting, synchronize to the pending tree so that it has
-  // time to raster before being displayed.
-  return settings_.impl_side_painting;
-}
-
 bool LayerTreeHostImpl::IsSynchronousSingleThreaded() const {
   return !proxy_->HasImplThread() && !settings_.single_thread_proxy_scheduler;
 }
@@ -2298,15 +2260,17 @@
   SetFullRootLayerDamage();
 }
 
-void LayerTreeHostImpl::SetControlsTopOffset(float offset) {
-  float current_top_offset = active_tree_->top_controls_content_offset() -
-                             active_tree_->top_controls_height();
-  active_tree_->set_top_controls_delta(offset - current_top_offset);
+float LayerTreeHostImpl::TopControlsHeight() const {
+  return active_tree_->top_controls_height();
 }
 
-float LayerTreeHostImpl::ControlsTopOffset() const {
-  return active_tree_->total_top_controls_content_offset() -
-         active_tree_->top_controls_height();
+void LayerTreeHostImpl::SetCurrentTopControlsShownRatio(float ratio) {
+  if (active_tree_->SetCurrentTopControlsShownRatio(ratio))
+    DidChangeTopControlsPosition();
+}
+
+float LayerTreeHostImpl::CurrentTopControlsShownRatio() const {
+  return active_tree_->CurrentTopControlsShownRatio();
 }
 
 void LayerTreeHostImpl::BindToClient(InputHandlerClient* client) {
@@ -3059,11 +3023,11 @@
   CollectScrollDeltas(scroll_info.get(), active_tree_->root_layer());
   scroll_info->page_scale_delta =
       active_tree_->page_scale_factor()->PullDeltaForMainThread();
+  scroll_info->top_controls_delta =
+      active_tree()->top_controls_shown_ratio()->PullDeltaForMainThread();
   scroll_info->elastic_overscroll_delta =
       active_tree_->elastic_overscroll()->PullDeltaForMainThread();
   scroll_info->swap_promises.swap(swap_promises_for_main_thread_scroll_update_);
-  scroll_info->top_controls_delta = active_tree()->top_controls_delta();
-  active_tree_->set_sent_top_controls_delta(scroll_info->top_controls_delta);
 
   return scroll_info.Pass();
 }
@@ -3282,26 +3246,27 @@
       BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 LayerTreeHostImpl::AsValue() const {
   return AsValueWithFrame(NULL);
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 LayerTreeHostImpl::AsValueWithFrame(FrameData* frame) const {
-  scoped_refptr<base::debug::TracedValue> state =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
   AsValueWithFrameInto(frame, state.get());
   return state;
 }
 
-void LayerTreeHostImpl::AsValueInto(base::debug::TracedValue* value) const {
+void LayerTreeHostImpl::AsValueInto(
+    base::trace_event::TracedValue* value) const {
   return AsValueWithFrameInto(NULL, value);
 }
 
 void LayerTreeHostImpl::AsValueWithFrameInto(
     FrameData* frame,
-    base::debug::TracedValue* state) const {
+    base::trace_event::TracedValue* state) const {
   if (this->pending_tree_) {
     state->BeginDictionary("activation_state");
     ActivationStateAsValueInto(state);
@@ -3347,16 +3312,16 @@
   }
 }
 
-scoped_refptr<base::debug::ConvertableToTraceFormat>
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
 LayerTreeHostImpl::ActivationStateAsValue() const {
-  scoped_refptr<base::debug::TracedValue> state =
-      new base::debug::TracedValue();
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
   ActivationStateAsValueInto(state.get());
   return state;
 }
 
 void LayerTreeHostImpl::ActivationStateAsValueInto(
-    base::debug::TracedValue* state) const {
+    base::trace_event::TracedValue* state) const {
   TracedValue::SetIDRef(this, state, "lthi");
   if (tile_manager_) {
     state->BeginDictionary("tile_manager");
@@ -3509,17 +3474,4 @@
     (*it)->OnForwardScrollUpdateToMainThreadOnImpl();
 }
 
-void LayerTreeHostImpl::RegisterPictureLayerImpl(PictureLayerImpl* layer) {
-  DCHECK(std::find(picture_layers_.begin(), picture_layers_.end(), layer) ==
-         picture_layers_.end());
-  picture_layers_.push_back(layer);
-}
-
-void LayerTreeHostImpl::UnregisterPictureLayerImpl(PictureLayerImpl* layer) {
-  std::vector<PictureLayerImpl*>::iterator it =
-      std::find(picture_layers_.begin(), picture_layers_.end(), layer);
-  DCHECK(it != picture_layers_.end());
-  picture_layers_.erase(it);
-}
-
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index f4052f1..6dd0d5a 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -174,15 +174,18 @@
   ScrollElasticityHelper* CreateScrollElasticityHelper() override;
 
   // TopControlsManagerClient implementation.
-  void SetControlsTopOffset(float offset) override;
-  float ControlsTopOffset() const override;
+  float TopControlsHeight() const override;
+  void SetCurrentTopControlsShownRatio(float offset) override;
+  float CurrentTopControlsShownRatio() const override;
   void DidChangeTopControlsPosition() override;
   bool HaveRootScrollLayer() const override;
 
+  void UpdateViewportContainerSizes();
+
   struct CC_EXPORT FrameData : public RenderPassSink {
     FrameData();
     ~FrameData() override;
-    void AsValueInto(base::debug::TracedValue* value) const;
+    void AsValueInto(base::trace_event::TracedValue* value) const;
 
     std::vector<gfx::Rect> occluding_screen_space_rects;
     std::vector<gfx::Rect> non_occluding_screen_space_rects;
@@ -254,10 +257,6 @@
       TreePriority tree_priority) override;
   void SetIsLikelyToRequireADraw(bool is_likely_to_require_a_draw) override;
 
-  // Returns existing picture layers.
-  // TODO(vmpstr): Remove this, it's only used in tests.
-  const std::vector<PictureLayerImpl*>& GetPictureLayers() const;
-
   // ScrollbarAnimationControllerClient implementation.
   void PostDelayedScrollbarFade(const base::Closure& start_fade,
                                 base::TimeDelta delay) override;
@@ -314,6 +313,7 @@
   }
   ResourcePool* resource_pool() { return resource_pool_.get(); }
   Renderer* renderer() { return renderer_.get(); }
+  Rasterizer* rasterizer() { return rasterizer_.get(); }
   const RendererCapabilitiesImpl& GetRendererCapabilities() const;
 
   virtual bool SwapBuffers(const FrameData& frame);
@@ -449,15 +449,15 @@
     return begin_impl_frame_interval_;
   }
 
-  void AsValueInto(base::debug::TracedValue* value) const;
+  void AsValueInto(base::trace_event::TracedValue* value) const;
   void AsValueWithFrameInto(FrameData* frame,
-                            base::debug::TracedValue* value) const;
-  scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
-  scoped_refptr<base::debug::ConvertableToTraceFormat> AsValueWithFrame(
+                            base::trace_event::TracedValue* value) const;
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValueWithFrame(
       FrameData* frame) const;
-  scoped_refptr<base::debug::ConvertableToTraceFormat> ActivationStateAsValue()
-      const;
-  void ActivationStateAsValueInto(base::debug::TracedValue* value) const;
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+  ActivationStateAsValue() const;
+  void ActivationStateAsValueInto(base::trace_event::TracedValue* value) const;
 
   bool page_scale_animation_active() const { return !!page_scale_animation_; }
 
@@ -495,9 +495,6 @@
   void InsertSwapPromiseMonitor(SwapPromiseMonitor* monitor);
   void RemoveSwapPromiseMonitor(SwapPromiseMonitor* monitor);
 
-  void RegisterPictureLayerImpl(PictureLayerImpl* layer);
-  void UnregisterPictureLayerImpl(PictureLayerImpl* layer);
-
   void GetPictureLayerImplPairs(std::vector<PictureLayerImpl::Pair>* layers,
                                 bool need_valid_tile_priorities) const;
 
@@ -530,7 +527,6 @@
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
       int id);
 
-  void UpdateViewportContainerSizes();
 
   // Virtual for testing.
   virtual void AnimateLayers(base::TimeTicks monotonic_time);
@@ -550,7 +546,6 @@
   void RecreateTreeResources();
   void EnforceZeroBudget(bool zero_budget);
 
-  bool UsePendingTreeForSync() const;
   bool IsSynchronousSingleThreaded() const;
 
   // Scroll by preferring to move the outer viewport first, only moving the
@@ -732,8 +727,6 @@
   int id_;
 
   std::set<SwapPromiseMonitor*> swap_promise_monitor_;
-
-  std::vector<PictureLayerImpl*> picture_layers_;
   std::vector<PictureLayerImpl::Pair> picture_layer_pairs_;
 
   bool requires_high_res_to_draw_;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 1c486e3..07fb048 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -1839,6 +1839,8 @@
     EXPECT_EQ(gfx::SizeF(100.f, 100.f), metadata.root_layer_size);
     EXPECT_EQ(0.5f, metadata.min_page_scale_factor);
     EXPECT_EQ(4.f, metadata.max_page_scale_factor);
+    EXPECT_FALSE(metadata.root_overflow_x_hidden);
+    EXPECT_FALSE(metadata.root_overflow_y_hidden);
   }
 
   // Scrolling should update metadata immediately.
@@ -1857,6 +1859,24 @@
     EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset);
   }
 
+  // Root "overflow: hidden" properties should be reflected.
+  {
+    host_impl_->active_tree()
+        ->InnerViewportScrollLayer()
+        ->set_user_scrollable_horizontal(false);
+    CompositorFrameMetadata metadata =
+        host_impl_->MakeCompositorFrameMetadata();
+    EXPECT_TRUE(metadata.root_overflow_x_hidden);
+    EXPECT_FALSE(metadata.root_overflow_y_hidden);
+
+    host_impl_->active_tree()
+        ->InnerViewportScrollLayer()
+        ->set_user_scrollable_vertical(false);
+    metadata = host_impl_->MakeCompositorFrameMetadata();
+    EXPECT_TRUE(metadata.root_overflow_x_hidden);
+    EXPECT_TRUE(metadata.root_overflow_y_hidden);
+  }
+
   // Page scale should update metadata correctly (shrinking only the viewport).
   host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
   host_impl_->PinchGestureBegin();
@@ -1904,11 +1924,9 @@
   }
 
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override {
     append_quads_called_ = true;
-    LayerImpl::AppendQuads(
-        render_pass, occlusion_in_content_space, append_quads_data);
+    LayerImpl::AppendQuads(render_pass, append_quads_data);
   }
 
   void DidDraw(ResourceProvider* provider) override {
@@ -2131,10 +2149,8 @@
   }
 
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override {
-    LayerImpl::AppendQuads(
-        render_pass, occlusion_in_content_space, append_quads_data);
+    LayerImpl::AppendQuads(render_pass, append_quads_data);
     if (had_incomplete_tile_)
       append_quads_data->num_incomplete_tiles++;
     if (tile_missing_)
@@ -2456,10 +2472,7 @@
         LayerTreeHostImplTest::CreateHostImpl(settings, output_surface.Pass());
     if (init && settings.calculate_top_controls_position) {
       host_impl_->active_tree()->set_top_controls_height(top_controls_height_);
-      host_impl_->active_tree()->set_top_controls_delta(top_controls_height_);
-      host_impl_->top_controls_manager()->SetTopControlsHeight(
-          top_controls_height_);
-      host_impl_->DidChangeTopControlsPosition();
+      host_impl_->active_tree()->SetCurrentTopControlsShownRatio(1.f);
     }
     return init;
   }
@@ -2493,6 +2506,7 @@
     host_impl_->DidChangeTopControlsPosition();
 
     host_impl_->CreatePendingTree();
+    host_impl_->sync_tree()->set_top_controls_height(top_controls_height_);
     root =
         LayerImpl::Create(host_impl_->sync_tree(), 1);
     root_clip =
@@ -2524,6 +2538,7 @@
       const gfx::Size& scroll_layer_size) {
     CreateHostImpl(settings_, CreateOutputSurface());
     host_impl_->sync_tree()->set_top_controls_shrink_blink_size(true);
+    host_impl_->sync_tree()->set_top_controls_height(top_controls_height_);
     host_impl_->DidChangeTopControlsPosition();
 
     scoped_ptr<LayerImpl> root =
@@ -2602,8 +2617,8 @@
       host_impl_->active_tree()->InnerViewportScrollLayer();
   DCHECK(inner_viewport_scroll_layer);
   host_impl_->ScrollEnd();
-  EXPECT_EQ(top_controls_scroll_delta,
-            inner_viewport_scroll_layer->FixedContainerSizeDelta());
+  EXPECT_FLOAT_EQ(top_controls_scroll_delta.y(),
+                  inner_viewport_scroll_layer->FixedContainerSizeDelta().y());
 }
 
 // In this test, the outer viewport is initially unscrollable. We test that a
@@ -2634,8 +2649,7 @@
 
   // The entire scroll delta should have been used to hide the top controls.
   // The viewport layers should be resized back to their full sizes.
-  EXPECT_EQ(0.f,
-      host_impl_->active_tree()->total_top_controls_content_offset());
+  EXPECT_EQ(0.f, host_impl_->active_tree()->CurrentTopControlsShownRatio());
   EXPECT_EQ(0.f, inner_scroll->CurrentScrollOffset().y());
   EXPECT_EQ(100.f, inner_container->BoundsForScrolling().height());
   EXPECT_EQ(100.f, outer_container->BoundsForScrolling().height());
@@ -2657,8 +2671,7 @@
   // The entire scroll delta should have been used to show the top controls.
   // The outer viewport should be resized to accomodate and scrolled to the
   // bottom of the document to keep the viewport in place.
-  EXPECT_EQ(50.f,
-      host_impl_->active_tree()->total_top_controls_content_offset());
+  EXPECT_EQ(1.f, host_impl_->active_tree()->CurrentTopControlsShownRatio());
   EXPECT_EQ(50.f, outer_container->BoundsForScrolling().height());
   EXPECT_EQ(50.f, inner_container->BoundsForScrolling().height());
   EXPECT_EQ(25.f, outer_scroll->CurrentScrollOffset().y());
@@ -2704,8 +2717,8 @@
   gfx::Vector2dF top_controls_scroll_delta(0.f, 20.f);
   host_impl_->top_controls_manager()->ScrollBegin();
   host_impl_->top_controls_manager()->ScrollBy(top_controls_scroll_delta);
-  EXPECT_EQ(top_controls_height_ - top_controls_scroll_delta.y(),
-            host_impl_->top_controls_manager()->ContentTopOffset());
+  EXPECT_FLOAT_EQ(top_controls_height_ - top_controls_scroll_delta.y(),
+                  host_impl_->top_controls_manager()->ContentTopOffset());
   EXPECT_VECTOR_EQ(top_controls_scroll_delta,
                    outer_viewport_scroll_layer->FixedContainerSizeDelta());
   host_impl_->ScrollEnd();
@@ -2742,8 +2755,7 @@
   DrawFrame();
 
   // Show top controls
-  EXPECT_EQ(top_controls_height_,
-            host_impl_->active_tree()->total_top_controls_content_offset());
+  EXPECT_EQ(1.f, host_impl_->active_tree()->CurrentTopControlsShownRatio());
 
   LayerImpl* outer_viewport_scroll_layer =
       host_impl_->active_tree()->OuterViewportScrollLayer();
@@ -2777,7 +2789,7 @@
   // Top controls should be hidden
   EXPECT_EQ(scroll_delta.y(),
             top_controls_height_ -
-                host_impl_->active_tree()->total_top_controls_content_offset());
+                host_impl_->top_controls_manager()->ContentTopOffset());
 }
 
 // Ensure setting the top controls position explicitly using the setters on the
@@ -2787,14 +2799,18 @@
   SetupTopControlsAndScrollLayer();
   DrawFrame();
 
-  host_impl_->active_tree()->set_top_controls_delta(0.f);
-  host_impl_->active_tree()->set_top_controls_content_offset(30.f);
-  EXPECT_EQ(30.f, host_impl_->top_controls_manager()->ContentTopOffset());
-  EXPECT_EQ(-20.f, host_impl_->top_controls_manager()->ControlsTopOffset());
+  host_impl_->active_tree()->SetCurrentTopControlsShownRatio(0.f);
+  host_impl_->active_tree()->top_controls_shown_ratio()->PushFromMainThread(
+      30.f / top_controls_height_);
+  host_impl_->active_tree()->top_controls_shown_ratio()->PushPendingToActive();
+  EXPECT_FLOAT_EQ(30.f, host_impl_->top_controls_manager()->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-20.f,
+                  host_impl_->top_controls_manager()->ControlsTopOffset());
 
-  host_impl_->active_tree()->set_top_controls_delta(-30.f);
-  EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ContentTopOffset());
-  EXPECT_EQ(-50.f, host_impl_->top_controls_manager()->ControlsTopOffset());
+  host_impl_->active_tree()->SetCurrentTopControlsShownRatio(0.f);
+  EXPECT_FLOAT_EQ(0.f, host_impl_->top_controls_manager()->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-50.f,
+                  host_impl_->top_controls_manager()->ControlsTopOffset());
 
   host_impl_->DidChangeTopControlsPosition();
 
@@ -2811,18 +2827,22 @@
   SetupTopControlsAndScrollLayer();
   DrawFrame();
 
-  host_impl_->sync_tree()->set_top_controls_content_offset(15.f);
-
-  host_impl_->active_tree()->set_top_controls_content_offset(20.f);
-  host_impl_->active_tree()->set_top_controls_delta(-20.f);
-  host_impl_->active_tree()->set_sent_top_controls_delta(-5.f);
+  host_impl_->active_tree()->top_controls_shown_ratio()->PushFromMainThread(
+      20.f / top_controls_height_);
+  host_impl_->active_tree()->top_controls_shown_ratio()->PushPendingToActive();
+  host_impl_->active_tree()->SetCurrentTopControlsShownRatio(
+      15.f / top_controls_height_);
+  host_impl_->active_tree()
+      ->top_controls_shown_ratio()
+      ->PullDeltaForMainThread();
+  host_impl_->active_tree()->SetCurrentTopControlsShownRatio(0.f);
+  host_impl_->sync_tree()->PushTopControlsFromMainThread(15.f /
+                                                         top_controls_height_);
 
   host_impl_->DidChangeTopControlsPosition();
   LayerImpl* root_clip_ptr = host_impl_->active_tree()->root_layer();
   EXPECT_EQ(viewport_size_, root_clip_ptr->bounds());
   EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ContentTopOffset());
-  EXPECT_EQ(0.f,
-      host_impl_->active_tree()->total_top_controls_content_offset());
 
   host_impl_->ActivateSyncTree();
 
@@ -2830,11 +2850,13 @@
   EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ContentTopOffset());
   EXPECT_EQ(viewport_size_, root_clip_ptr->bounds());
 
-  EXPECT_EQ(0.f, host_impl_->active_tree()->sent_top_controls_delta());
-  EXPECT_EQ(-15.f, host_impl_->active_tree()->top_controls_delta());
-  EXPECT_EQ(15.f, host_impl_->active_tree()->top_controls_content_offset());
-  EXPECT_EQ(0.f,
-      host_impl_->active_tree()->total_top_controls_content_offset());
+  EXPECT_FLOAT_EQ(
+      -15.f, host_impl_->active_tree()->top_controls_shown_ratio()->Delta() *
+                 top_controls_height_);
+  EXPECT_FLOAT_EQ(
+      15.f,
+      host_impl_->active_tree()->top_controls_shown_ratio()->ActiveBase() *
+          top_controls_height_);
 }
 
 // Test that changing the top controls layout height is correctly applied to
@@ -2846,11 +2868,13 @@
   SetupTopControlsAndScrollLayer();
   DrawFrame();
 
-  host_impl_->sync_tree()->set_top_controls_content_offset(50.f);
+  host_impl_->sync_tree()->PushTopControlsFromMainThread(1.f);
   host_impl_->sync_tree()->set_top_controls_shrink_blink_size(true);
 
-  host_impl_->active_tree()->set_top_controls_content_offset(50.f);
-  host_impl_->active_tree()->set_top_controls_delta(-50.f);
+  host_impl_->active_tree()->top_controls_shown_ratio()->PushFromMainThread(
+      1.f);
+  host_impl_->active_tree()->top_controls_shown_ratio()->PushPendingToActive();
+  host_impl_->active_tree()->SetCurrentTopControlsShownRatio(0.f);
 
   host_impl_->DidChangeTopControlsPosition();
   LayerImpl* root_clip_ptr = host_impl_->active_tree()->root_layer();
@@ -2872,9 +2896,11 @@
   EXPECT_EQ(viewport_size_, root_clip_ptr->bounds());
   EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, 50.f), root_clip_ptr->bounds_delta());
 
-  host_impl_->active_tree()->set_top_controls_delta(0.f);
+  host_impl_->active_tree()->SetCurrentTopControlsShownRatio(1.f);
   host_impl_->DidChangeTopControlsPosition();
 
+  EXPECT_EQ(1.f, host_impl_->top_controls_manager()->TopControlsShownRatio());
+  EXPECT_EQ(50.f, host_impl_->top_controls_manager()->TopControlsHeight());
   EXPECT_EQ(50.f, host_impl_->top_controls_manager()->ContentTopOffset());
   EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, 0.f), root_clip_ptr->bounds_delta());
   EXPECT_EQ(gfx::Size(viewport_size_.width(), viewport_size_.height() - 50.f),
@@ -2889,8 +2915,7 @@
       gfx::Size(100, 100), gfx::Size(200, 200), gfx::Size(200, 400));
   DrawFrame();
 
-  EXPECT_EQ(top_controls_height_,
-            host_impl_->active_tree()->total_top_controls_content_offset());
+  EXPECT_EQ(1.f, host_impl_->active_tree()->CurrentTopControlsShownRatio());
 
   LayerImpl* outer_scroll = host_impl_->OuterViewportScrollLayer();
   LayerImpl* inner_scroll = host_impl_->InnerViewportScrollLayer();
@@ -2910,17 +2935,15 @@
   host_impl_->ScrollBy(gfx::Point(), scroll_delta);
 
   // scrolling down at the max extents no longer hides the top controls
-  EXPECT_EQ(0.f,
-            top_controls_height_ -
-                host_impl_->active_tree()->total_top_controls_content_offset());
+  EXPECT_EQ(1.f, host_impl_->active_tree()->CurrentTopControlsShownRatio());
 
   // forcefully hide the top controls by 25px
   host_impl_->top_controls_manager()->ScrollBy(scroll_delta);
   host_impl_->ScrollEnd();
 
-  EXPECT_EQ(scroll_delta.y(),
-            top_controls_height_ -
-                host_impl_->active_tree()->total_top_controls_content_offset());
+  EXPECT_FLOAT_EQ(scroll_delta.y(),
+                  top_controls_height_ -
+                      host_impl_->top_controls_manager()->ContentTopOffset());
 
   inner_scroll->ClampScrollToMaxScrollOffset();
   outer_scroll->ClampScrollToMaxScrollOffset();
@@ -2956,8 +2979,8 @@
       gfx::Size(100, 100), gfx::Size(200, 200), gfx::Size(200, 400));
   DrawFrame();
 
-  EXPECT_EQ(top_controls_height_,
-            host_impl_->active_tree()->total_top_controls_content_offset());
+  EXPECT_FLOAT_EQ(top_controls_height_,
+                  host_impl_->top_controls_manager()->ContentTopOffset());
 
   gfx::Vector2dF scroll_delta(0.f, 25.f);
   EXPECT_EQ(InputHandler::ScrollStarted,
@@ -2965,9 +2988,9 @@
   host_impl_->ScrollBy(gfx::Point(), scroll_delta);
   host_impl_->ScrollEnd();
 
-  EXPECT_EQ(scroll_delta.y(),
-            top_controls_height_ -
-                host_impl_->active_tree()->total_top_controls_content_offset());
+  EXPECT_FLOAT_EQ(scroll_delta.y(),
+                  top_controls_height_ -
+                      host_impl_->top_controls_manager()->ContentTopOffset());
 
   // Top controls were hidden by 25px so the inner viewport should have expanded
   // by that much.
@@ -2993,7 +3016,7 @@
   DrawFrame();
 
   EXPECT_EQ(top_controls_height_,
-            host_impl_->active_tree()->total_top_controls_content_offset());
+            host_impl_->top_controls_manager()->ContentTopOffset());
 
   // Send a gesture scroll that will scroll the outer viewport, make sure the
   // top controls get scrolled.
@@ -3005,16 +3028,16 @@
             host_impl_->CurrentlyScrollingLayer());
   host_impl_->ScrollEnd();
 
-  EXPECT_EQ(scroll_delta.y(),
-            top_controls_height_ -
-                host_impl_->active_tree()->total_top_controls_content_offset());
+  EXPECT_FLOAT_EQ(scroll_delta.y(),
+                  top_controls_height_ -
+                      host_impl_->top_controls_manager()->ContentTopOffset());
 
   scroll_delta = gfx::Vector2dF(0.f, 50.f);
   EXPECT_EQ(InputHandler::ScrollStarted,
             host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
   host_impl_->ScrollBy(gfx::Point(), scroll_delta);
 
-  EXPECT_EQ(0, host_impl_->active_tree()->total_top_controls_content_offset());
+  EXPECT_EQ(0, host_impl_->top_controls_manager()->ContentTopOffset());
   EXPECT_EQ(host_impl_->OuterViewportScrollLayer(),
             host_impl_->CurrentlyScrollingLayer());
 
@@ -3031,8 +3054,8 @@
   host_impl_->ScrollBy(gfx::Point(), scroll_delta);
 
   EXPECT_EQ(top_controls_height_,
-            host_impl_->active_tree()->total_top_controls_content_offset());
-  EXPECT_EQ(
+            host_impl_->top_controls_manager()->ContentTopOffset());
+  EXPECT_FLOAT_EQ(
       inner_viewport_offset.y() + (scroll_delta.y() + top_controls_height_),
       host_impl_->InnerViewportScrollLayer()->ScrollDelta().y());
 
@@ -3065,8 +3088,8 @@
   host_impl_->top_controls_manager()->ScrollBegin();
   host_impl_->top_controls_manager()->ScrollBy(
       gfx::Vector2dF(0.f, scroll_increment_y));
-  EXPECT_EQ(-scroll_increment_y,
-            host_impl_->top_controls_manager()->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-scroll_increment_y,
+                  host_impl_->top_controls_manager()->ContentTopOffset());
   // Now that top controls have moved, expect the clip to resize.
   EXPECT_EQ(gfx::Size(viewport_size_.width(),
                       viewport_size_.height() + scroll_increment_y),
@@ -3075,8 +3098,8 @@
   host_impl_->top_controls_manager()->ScrollBy(
       gfx::Vector2dF(0.f, scroll_increment_y));
   host_impl_->top_controls_manager()->ScrollEnd();
-  EXPECT_EQ(-2 * scroll_increment_y,
-            host_impl_->top_controls_manager()->ContentTopOffset());
+  EXPECT_FLOAT_EQ(-2 * scroll_increment_y,
+                  host_impl_->top_controls_manager()->ContentTopOffset());
   // Now that top controls have moved, expect the clip to resize.
   EXPECT_EQ(clip_size_, root_clip_ptr->bounds());
 
@@ -4413,7 +4436,6 @@
   }
 
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override {
     quads_appended_ = true;
 
@@ -5138,7 +5160,6 @@
   }
 
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override {
     SharedQuadState* shared_quad_state =
         render_pass->CreateAndAppendSharedQuadState();
@@ -6592,8 +6613,8 @@
 
   // DeferredInitialize and hardware draw.
   did_update_renderer_capabilities_ = false;
-  EXPECT_TRUE(
-      output_surface_->InitializeAndSetContext3d(onscreen_context_provider_));
+  EXPECT_TRUE(output_surface_->InitializeAndSetContext3d(
+      onscreen_context_provider_, nullptr));
   EXPECT_EQ(onscreen_context_provider_.get(),
             host_impl_->output_surface()->context_provider());
   EXPECT_TRUE(did_update_renderer_capabilities_);
@@ -6623,8 +6644,8 @@
 
   // DeferredInitialize fails.
   did_update_renderer_capabilities_ = false;
-  EXPECT_FALSE(
-      output_surface_->InitializeAndSetContext3d(onscreen_context_provider_));
+  EXPECT_FALSE(output_surface_->InitializeAndSetContext3d(
+      onscreen_context_provider_, nullptr));
   EXPECT_FALSE(host_impl_->output_surface()->context_provider());
   EXPECT_FALSE(did_update_renderer_capabilities_);
 
@@ -7412,9 +7433,8 @@
     settings.calculate_top_controls_position = true;
     CreateHostImpl(settings, CreateOutputSurface());
     host_impl_->active_tree()->set_top_controls_height(top_controls_height_);
-    host_impl_->active_tree()->set_top_controls_delta(top_controls_height_);
-    host_impl_->top_controls_manager()->SetTopControlsHeight(
-        top_controls_height_);
+    host_impl_->sync_tree()->set_top_controls_height(top_controls_height_);
+    host_impl_->active_tree()->SetCurrentTopControlsShownRatio(1.f);
   }
 
  protected:
@@ -7436,23 +7456,23 @@
   host_impl_->CreatePendingTree();
   host_impl_->sync_tree()->set_top_controls_height(100);
   host_impl_->ActivateSyncTree();
-  EXPECT_EQ(100, host_impl_->top_controls_manager()->top_controls_height());
+  EXPECT_EQ(100, host_impl_->top_controls_manager()->TopControlsHeight());
 }
 
 TEST_F(LayerTreeHostImplWithTopControlsTest,
        TopControlsStayFullyVisibleOnHeightChange) {
   SetupScrollAndContentsLayers(gfx::Size(100, 100));
-  EXPECT_EQ(0.f, host_impl_->ControlsTopOffset());
+  EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ControlsTopOffset());
 
   host_impl_->CreatePendingTree();
   host_impl_->sync_tree()->set_top_controls_height(0);
   host_impl_->ActivateSyncTree();
-  EXPECT_EQ(0.f, host_impl_->ControlsTopOffset());
+  EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ControlsTopOffset());
 
   host_impl_->CreatePendingTree();
   host_impl_->sync_tree()->set_top_controls_height(50);
   host_impl_->ActivateSyncTree();
-  EXPECT_EQ(0.f, host_impl_->ControlsTopOffset());
+  EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ControlsTopOffset());
 }
 
 TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsAnimationScheduling) {
@@ -8017,17 +8037,26 @@
   scoped_ptr<PictureLayerImpl> layer =
       FakePictureLayerImpl::Create(host_impl_->pending_tree(), 10);
   layer->SetBounds(gfx::Size(10, 10));
+  scoped_ptr<FakePictureLayerImpl> nondraw_layer =
+      FakePictureLayerImpl::Create(host_impl_->pending_tree(), 12);
+  nondraw_layer->SetBounds(gfx::Size(10, 10));
 
   scoped_refptr<RasterSource> pile(FakePicturePileImpl::CreateEmptyPile(
       gfx::Size(10, 10), gfx::Size(10, 10)));
   Region empty_invalidation;
   const PictureLayerTilingSet* null_tiling_set = nullptr;
   layer->UpdateRasterSource(pile, &empty_invalidation, null_tiling_set);
+  nondraw_layer->UpdateRasterSource(pile, &empty_invalidation, null_tiling_set);
 
+  layer->AddChild(nondraw_layer.Pass());
   host_impl_->pending_tree()->SetRootLayer(layer.Pass());
 
   LayerTreeImpl* pending_tree = host_impl_->pending_tree();
   LayerImpl* pending_layer = pending_tree->root_layer();
+  FakePictureLayerImpl* pending_nondraw_layer =
+      static_cast<FakePictureLayerImpl*>(pending_layer->children()[0]);
+
+  pending_nondraw_layer->SetIsDrawnRenderSurfaceLayerListMember(false);
 
   std::vector<PictureLayerImpl::Pair> layer_pairs;
   host_impl_->GetPictureLayerImplPairs(&layer_pairs, true);
@@ -8039,10 +8068,16 @@
 
   LayerTreeImpl* active_tree = host_impl_->active_tree();
   LayerImpl* active_layer = active_tree->root_layer();
+  FakePictureLayerImpl* active_nondraw_layer =
+      static_cast<FakePictureLayerImpl*>(active_layer->children()[0]);
   EXPECT_NE(active_tree, pending_tree);
   EXPECT_NE(active_layer, pending_layer);
+  EXPECT_NE(active_nondraw_layer, pending_nondraw_layer);
   EXPECT_NE(nullptr, active_tree);
   EXPECT_NE(nullptr, active_layer);
+  EXPECT_NE(nullptr, active_nondraw_layer);
+
+  active_nondraw_layer->SetIsDrawnRenderSurfaceLayerListMember(false);
 
   host_impl_->CreatePendingTree();
 
@@ -8067,20 +8102,192 @@
   host_impl_->pending_tree()->root_layer()->AddChild(
       FakePictureLayerImpl::Create(host_impl_->pending_tree(), 11));
 
-  LayerImpl* new_pending_layer = pending_tree->root_layer()->children()[0];
+  LayerImpl* new_pending_layer = pending_tree->root_layer()->children()[1];
 
   layer_pairs.clear();
   host_impl_->GetPictureLayerImplPairs(&layer_pairs, true);
   EXPECT_EQ(2u, layer_pairs.size());
-
   // The pair ordering is flaky, so make it consistent.
   if (layer_pairs[0].active != active_layer)
     std::swap(layer_pairs[0], layer_pairs[1]);
-
   EXPECT_EQ(active_layer, layer_pairs[0].active);
   EXPECT_EQ(pending_layer, layer_pairs[0].pending);
   EXPECT_EQ(new_pending_layer, layer_pairs[1].pending);
   EXPECT_EQ(nullptr, layer_pairs[1].active);
+
+  host_impl_->pending_tree()->root_layer()->RemoveChild(new_pending_layer);
+
+  // Have the pending layer be part of the RSLL now. It should appear in the
+  // list without an active twin.
+  pending_nondraw_layer->SetIsDrawnRenderSurfaceLayerListMember(true);
+
+  layer_pairs.clear();
+  host_impl_->GetPictureLayerImplPairs(&layer_pairs, true);
+  EXPECT_EQ(2u, layer_pairs.size());
+  // The pair ordering is flaky, so make it consistent.
+  if (layer_pairs[0].active != active_layer)
+    std::swap(layer_pairs[0], layer_pairs[1]);
+  EXPECT_EQ(active_layer, layer_pairs[0].active);
+  EXPECT_EQ(pending_layer, layer_pairs[0].pending);
+  EXPECT_EQ(pending_nondraw_layer, layer_pairs[1].pending);
+  EXPECT_EQ(nullptr, layer_pairs[1].active);
+
+  // Have the active layer be part of the RSLL now instead. It should appear in
+  // the list without a pending twin.
+  pending_nondraw_layer->SetIsDrawnRenderSurfaceLayerListMember(false);
+  active_nondraw_layer->SetIsDrawnRenderSurfaceLayerListMember(true);
+
+  layer_pairs.clear();
+  host_impl_->GetPictureLayerImplPairs(&layer_pairs, true);
+  EXPECT_EQ(2u, layer_pairs.size());
+  // The pair ordering is flaky, so make it consistent.
+  if (layer_pairs[0].active != active_layer)
+    std::swap(layer_pairs[0], layer_pairs[1]);
+  EXPECT_EQ(active_layer, layer_pairs[0].active);
+  EXPECT_EQ(pending_layer, layer_pairs[0].pending);
+  EXPECT_EQ(nullptr, layer_pairs[1].pending);
+  EXPECT_EQ(active_nondraw_layer, layer_pairs[1].active);
+}
+
+TEST_F(LayerTreeHostImplTest, GetPictureLayerImplPairsWithNonRSLLMembers) {
+  host_impl_->CreatePendingTree();
+
+  scoped_ptr<PictureLayerImpl> layer =
+      FakePictureLayerImpl::Create(host_impl_->pending_tree(), 10);
+  layer->SetBounds(gfx::Size(10, 10));
+  scoped_ptr<FakePictureLayerImpl> nondraw_layer =
+      FakePictureLayerImpl::Create(host_impl_->pending_tree(), 12);
+  nondraw_layer->SetBounds(gfx::Size(10, 10));
+
+  scoped_refptr<RasterSource> pile(FakePicturePileImpl::CreateEmptyPile(
+      gfx::Size(10, 10), gfx::Size(10, 10)));
+  Region empty_invalidation;
+  const PictureLayerTilingSet* null_tiling_set = nullptr;
+  layer->UpdateRasterSource(pile, &empty_invalidation, null_tiling_set);
+  nondraw_layer->UpdateRasterSource(pile, &empty_invalidation, null_tiling_set);
+
+  layer->AddChild(nondraw_layer.Pass());
+  host_impl_->pending_tree()->SetRootLayer(layer.Pass());
+
+  LayerTreeImpl* pending_tree = host_impl_->pending_tree();
+  LayerImpl* pending_layer = pending_tree->root_layer();
+  FakePictureLayerImpl* pending_nondraw_layer =
+      static_cast<FakePictureLayerImpl*>(pending_layer->children()[0]);
+
+  pending_nondraw_layer->SetIsDrawnRenderSurfaceLayerListMember(false);
+
+  std::vector<PictureLayerImpl::Pair> layer_pairs;
+  host_impl_->GetPictureLayerImplPairs(&layer_pairs, false);
+  EXPECT_EQ(2u, layer_pairs.size());
+  // The pair ordering is flaky, so make it consistent.
+  if (layer_pairs[0].pending != pending_layer)
+    std::swap(layer_pairs[0], layer_pairs[1]);
+  EXPECT_EQ(pending_layer, layer_pairs[0].pending);
+  EXPECT_EQ(nullptr, layer_pairs[0].active);
+  EXPECT_EQ(pending_nondraw_layer, layer_pairs[1].pending);
+  EXPECT_EQ(nullptr, layer_pairs[1].active);
+
+  host_impl_->ActivateSyncTree();
+
+  LayerTreeImpl* active_tree = host_impl_->active_tree();
+  LayerImpl* active_layer = active_tree->root_layer();
+  FakePictureLayerImpl* active_nondraw_layer =
+      static_cast<FakePictureLayerImpl*>(active_layer->children()[0]);
+  EXPECT_NE(active_tree, pending_tree);
+  EXPECT_NE(active_layer, pending_layer);
+  EXPECT_NE(active_nondraw_layer, pending_nondraw_layer);
+  EXPECT_NE(nullptr, active_tree);
+  EXPECT_NE(nullptr, active_layer);
+  EXPECT_NE(nullptr, active_nondraw_layer);
+
+  active_nondraw_layer->SetIsDrawnRenderSurfaceLayerListMember(false);
+
+  host_impl_->CreatePendingTree();
+
+  layer_pairs.clear();
+  host_impl_->GetPictureLayerImplPairs(&layer_pairs, false);
+  EXPECT_EQ(2u, layer_pairs.size());
+  // The pair ordering is flaky, so make it consistent.
+  if (layer_pairs[0].active != active_layer)
+    std::swap(layer_pairs[0], layer_pairs[1]);
+  EXPECT_EQ(active_layer, layer_pairs[0].active);
+  EXPECT_EQ(pending_layer, layer_pairs[0].pending);
+  EXPECT_EQ(pending_nondraw_layer, layer_pairs[1].pending);
+  EXPECT_EQ(active_nondraw_layer, layer_pairs[1].active);
+
+  // Activate, the active layer has no twin now.
+  host_impl_->ActivateSyncTree();
+
+  layer_pairs.clear();
+  host_impl_->GetPictureLayerImplPairs(&layer_pairs, false);
+  EXPECT_EQ(2u, layer_pairs.size());
+  // The pair ordering is flaky, so make it consistent.
+  if (layer_pairs[0].active != active_layer)
+    std::swap(layer_pairs[0], layer_pairs[1]);
+  EXPECT_EQ(active_layer, layer_pairs[0].active);
+  EXPECT_EQ(nullptr, layer_pairs[0].pending);
+  EXPECT_EQ(active_nondraw_layer, layer_pairs[1].active);
+  EXPECT_EQ(nullptr, layer_pairs[1].pending);
+
+  // Create another layer in the pending tree that's not in the active tree. We
+  // should get three pairs including the nondraw layers.
+  host_impl_->CreatePendingTree();
+  host_impl_->pending_tree()->root_layer()->AddChild(
+      FakePictureLayerImpl::Create(host_impl_->pending_tree(), 11));
+
+  LayerImpl* new_pending_layer = pending_tree->root_layer()->children()[1];
+
+  layer_pairs.clear();
+  host_impl_->GetPictureLayerImplPairs(&layer_pairs, false);
+  EXPECT_EQ(3u, layer_pairs.size());
+  // The pair ordering is flaky, so make it consistent.
+  if (layer_pairs[0].active != active_layer)
+    std::swap(layer_pairs[0], layer_pairs[1]);
+  if (layer_pairs[0].active != active_layer)
+    std::swap(layer_pairs[0], layer_pairs[2]);
+  if (layer_pairs[1].pending != new_pending_layer)
+    std::swap(layer_pairs[1], layer_pairs[2]);
+  EXPECT_EQ(active_layer, layer_pairs[0].active);
+  EXPECT_EQ(pending_layer, layer_pairs[0].pending);
+  EXPECT_EQ(new_pending_layer, layer_pairs[1].pending);
+  EXPECT_EQ(nullptr, layer_pairs[1].active);
+  EXPECT_EQ(active_nondraw_layer, layer_pairs[2].active);
+  EXPECT_EQ(pending_nondraw_layer, layer_pairs[2].pending);
+
+  host_impl_->pending_tree()->root_layer()->RemoveChild(new_pending_layer);
+
+  // Have the pending layer be part of the RSLL now. It should appear in the
+  // list, as should its active twin since we don't request only layers with
+  // valid draw properties.
+  pending_nondraw_layer->SetIsDrawnRenderSurfaceLayerListMember(true);
+
+  layer_pairs.clear();
+  host_impl_->GetPictureLayerImplPairs(&layer_pairs, false);
+  EXPECT_EQ(2u, layer_pairs.size());
+  // The pair ordering is flaky, so make it consistent.
+  if (layer_pairs[0].active != active_layer)
+    std::swap(layer_pairs[0], layer_pairs[1]);
+  EXPECT_EQ(active_layer, layer_pairs[0].active);
+  EXPECT_EQ(pending_layer, layer_pairs[0].pending);
+  EXPECT_EQ(pending_nondraw_layer, layer_pairs[1].pending);
+  EXPECT_EQ(active_nondraw_layer, layer_pairs[1].active);
+
+  // Have the active layer be part of the RSLL now instead. It should appear in
+  // the list, as should its pending twin since we don't request only layers
+  // with valid draw properties.
+  pending_nondraw_layer->SetIsDrawnRenderSurfaceLayerListMember(false);
+  active_nondraw_layer->SetIsDrawnRenderSurfaceLayerListMember(true);
+
+  layer_pairs.clear();
+  host_impl_->GetPictureLayerImplPairs(&layer_pairs, false);
+  EXPECT_EQ(2u, layer_pairs.size());
+  // The pair ordering is flaky, so make it consistent.
+  if (layer_pairs[0].active != active_layer)
+    std::swap(layer_pairs[0], layer_pairs[1]);
+  EXPECT_EQ(active_layer, layer_pairs[0].active);
+  EXPECT_EQ(pending_layer, layer_pairs[0].pending);
+  EXPECT_EQ(active_nondraw_layer, layer_pairs[1].active);
+  EXPECT_EQ(pending_nondraw_layer, layer_pairs[1].pending);
 }
 
 TEST_F(LayerTreeHostImplTest, DidBecomeActive) {
diff --git a/cc/trees/layer_tree_host_pixeltest_filters.cc b/cc/trees/layer_tree_host_pixeltest_filters.cc
index bf8e3e2..76acaa8 100644
--- a/cc/trees/layer_tree_host_pixeltest_filters.cc
+++ b/cc/trees/layer_tree_host_pixeltest_filters.cc
@@ -395,6 +395,62 @@
       base::FilePath(FILE_PATH_LITERAL("scaled_render_surface_layer_sw.png")));
 }
 
+class EnlargedTextureWithAlphaThresholdFilter
+    : public LayerTreeHostFiltersPixelTest {
+ protected:
+  void RunPixelTestType(PixelTestType test_type, base::FilePath image_name) {
+    // Rectangles choosen so that if flipped, the test will fail.
+    gfx::Rect rect1(10, 10, 10, 15);
+    gfx::Rect rect2(20, 25, 70, 65);
+
+    scoped_refptr<SolidColorLayer> child1 =
+        CreateSolidColorLayer(rect1, SK_ColorRED);
+    scoped_refptr<SolidColorLayer> child2 =
+        CreateSolidColorLayer(rect2, SK_ColorGREEN);
+    scoped_refptr<SolidColorLayer> background =
+        CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLUE);
+    scoped_refptr<SolidColorLayer> filter_layer =
+        CreateSolidColorLayer(gfx::Rect(100, 100), SK_ColorWHITE);
+
+    // Make sure a transformation does not cause misregistration of the filter
+    // and source texture.
+    gfx::Transform filter_transform;
+    filter_transform.Scale(2.f, 2.f);
+    filter_layer->SetTransform(filter_transform);
+    filter_layer->AddChild(child1);
+    filter_layer->AddChild(child2);
+
+    rect1.Inset(-5, -5);
+    rect2.Inset(-5, -5);
+    SkRegion alpha_region;
+    SkIRect rects[2] = {gfx::RectToSkIRect(rect1), gfx::RectToSkIRect(rect2)};
+    alpha_region.setRects(rects, 2);
+    FilterOperations filters;
+    filters.Append(
+        FilterOperation::CreateAlphaThresholdFilter(alpha_region, 0.f, 0.f));
+    filter_layer->SetFilters(filters);
+
+    background->AddChild(filter_layer);
+
+    // Force the allocation a larger textures.
+    set_enlarge_texture_amount(gfx::Vector2d(50, 50));
+
+    RunPixelTest(test_type, background, image_name);
+  }
+};
+
+TEST_F(EnlargedTextureWithAlphaThresholdFilter, GL) {
+  RunPixelTestType(
+      PIXEL_TEST_GL,
+      base::FilePath(FILE_PATH_LITERAL("enlarged_texture_on_threshold.png")));
+}
+
+TEST_F(EnlargedTextureWithAlphaThresholdFilter, Software) {
+  RunPixelTestType(
+      PIXEL_TEST_SOFTWARE,
+      base::FilePath(FILE_PATH_LITERAL("enlarged_texture_on_threshold.png")));
+}
+
 }  // namespace
 }  // namespace cc
 
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 5d828c5..d32817c 100644
--- a/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
+++ b/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
@@ -42,7 +42,7 @@
     scoped_ptr<RenderPass> render_pass = RenderPass::Create();
 
     AppendQuadsData data;
-    picture_layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+    picture_layer->AppendQuads(render_pass.get(), &data);
 
     for (const auto& quad : render_pass->quad_list)
       EXPECT_EQ(quad->material, DrawQuad::PICTURE_CONTENT);
diff --git a/cc/trees/layer_tree_host_pixeltest_readback.cc b/cc/trees/layer_tree_host_pixeltest_readback.cc
index 0a06144..b372904 100644
--- a/cc/trees/layer_tree_host_pixeltest_readback.cc
+++ b/cc/trees/layer_tree_host_pixeltest_readback.cc
@@ -19,18 +19,30 @@
 namespace cc {
 namespace {
 
-class LayerTreeHostReadbackPixelTest : public LayerTreePixelTest {
+// Can't templatize a class on its own members, so ReadbackType and
+// ReadbackTestConfig are declared here, before LayerTreeHostReadbackPixelTest.
+enum ReadbackType {
+  READBACK_INVALID,
+  READBACK_DEFAULT,
+  READBACK_BITMAP,
+};
+
+struct ReadbackTestConfig {
+  ReadbackTestConfig(LayerTreePixelTest::PixelTestType pixel_test_type_,
+                     ReadbackType readback_type_)
+      : pixel_test_type(pixel_test_type_), readback_type(readback_type_) {}
+  LayerTreePixelTest::PixelTestType pixel_test_type;
+  ReadbackType readback_type;
+};
+
+class LayerTreeHostReadbackPixelTest
+    : public LayerTreePixelTest,
+      public testing::WithParamInterface<ReadbackTestConfig> {
  protected:
   LayerTreeHostReadbackPixelTest()
       : readback_type_(READBACK_INVALID),
         insert_copy_request_after_frame_count_(0) {}
 
-  enum ReadbackType {
-    READBACK_INVALID,
-    READBACK_DEFAULT,
-    READBACK_BITMAP,
-  };
-
   void RunReadbackTest(PixelTestType test_type,
                        ReadbackType readback_type,
                        scoped_refptr<Layer> content_root,
@@ -124,7 +136,7 @@
 void IgnoreReadbackResult(scoped_ptr<CopyOutputResult> result) {
 }
 
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayer_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackRootLayer) {
   scoped_refptr<SolidColorLayer> background =
       CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
 
@@ -132,55 +144,11 @@
       CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
   background->AddChild(green);
 
-  RunReadbackTest(PIXEL_TEST_SOFTWARE,
-                  READBACK_DEFAULT,
-                  background,
-                  base::FilePath(FILE_PATH_LITERAL("green.png")));
+  RunReadbackTest(GetParam().pixel_test_type, GetParam().readback_type,
+                  background, base::FilePath(FILE_PATH_LITERAL("green.png")));
 }
 
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayer_Software_Bitmap) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
-  background->AddChild(green);
-
-  RunReadbackTest(PIXEL_TEST_SOFTWARE,
-                  READBACK_BITMAP,
-                  background,
-                  base::FilePath(FILE_PATH_LITERAL("green.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayer_GL_Bitmap) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
-  background->AddChild(green);
-
-  RunReadbackTest(PIXEL_TEST_GL,
-                  READBACK_BITMAP,
-                  background,
-                  base::FilePath(FILE_PATH_LITERAL("green.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayer_GL) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
-  background->AddChild(green);
-
-  RunReadbackTest(PIXEL_TEST_GL,
-                  READBACK_DEFAULT,
-                  background,
-                  base::FilePath(FILE_PATH_LITERAL("green.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayerWithChild_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackRootLayerWithChild) {
   scoped_refptr<SolidColorLayer> background =
       CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
 
@@ -193,51 +161,11 @@
   green->AddChild(blue);
 
   RunReadbackTest(
-      PIXEL_TEST_SOFTWARE,
-      READBACK_DEFAULT,
-      background,
+      GetParam().pixel_test_type, GetParam().readback_type, background,
       base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
 }
 
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayerWithChild_GL_Bitmap) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
-  background->AddChild(green);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
-  green->AddChild(blue);
-
-  RunReadbackTest(
-      PIXEL_TEST_GL,
-      READBACK_BITMAP,
-      background,
-      base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayerWithChild_GL) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
-  background->AddChild(green);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
-  green->AddChild(blue);
-
-  RunReadbackTest(
-      PIXEL_TEST_GL,
-      READBACK_DEFAULT,
-      background,
-      base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayer_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayer) {
   scoped_refptr<SolidColorLayer> background =
       CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
 
@@ -246,46 +174,11 @@
   background->AddChild(green);
 
   RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_SOFTWARE,
-      READBACK_DEFAULT,
-      background,
-      green.get(),
-      base::FilePath(FILE_PATH_LITERAL("green.png")));
+      GetParam().pixel_test_type, GetParam().readback_type, background,
+      green.get(), base::FilePath(FILE_PATH_LITERAL("green.png")));
 }
 
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayer_GL_Bitmap) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
-  background->AddChild(green);
-
-  RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_BITMAP,
-      background,
-      green.get(),
-      base::FilePath(FILE_PATH_LITERAL("green.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayer_GL) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
-  background->AddChild(green);
-
-  RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_DEFAULT,
-      background,
-      green.get(),
-      base::FilePath(FILE_PATH_LITERAL("green.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayer_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayer) {
   scoped_refptr<SolidColorLayer> background =
       CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
 
@@ -294,47 +187,11 @@
   background->AddChild(green);
 
   RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_SOFTWARE,
-      READBACK_DEFAULT,
-      background,
-      green.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_small.png")));
+      GetParam().pixel_test_type, GetParam().readback_type, background,
+      green.get(), base::FilePath(FILE_PATH_LITERAL("green_small.png")));
 }
 
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayer_GL_Bitmap) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(100, 100, 100, 100), SK_ColorGREEN);
-  background->AddChild(green);
-
-  RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_BITMAP,
-      background,
-      green.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_small.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayer_GL) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(100, 100, 100, 100), SK_ColorGREEN);
-  background->AddChild(green);
-
-  RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_DEFAULT,
-      background,
-      green.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_small.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest,
-       ReadbackSmallNonRootLayerWithChild_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayerWithChild) {
   scoped_refptr<SolidColorLayer> background =
       CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
 
@@ -347,56 +204,12 @@
   green->AddChild(blue);
 
   RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_SOFTWARE,
-      READBACK_DEFAULT,
-      background,
+      GetParam().pixel_test_type, GetParam().readback_type, background,
       green.get(),
       base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
 }
 
-TEST_F(LayerTreeHostReadbackPixelTest,
-       ReadbackSmallNonRootLayerWithChild_GL_Bitmap) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(100, 100, 100, 100), SK_ColorGREEN);
-  background->AddChild(green);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
-  green->AddChild(blue);
-
-  RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_BITMAP,
-      background,
-      green.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSmallNonRootLayerWithChild_GL) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(100, 100, 100, 100), SK_ColorGREEN);
-  background->AddChild(green);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
-  green->AddChild(blue);
-
-  RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_DEFAULT,
-      background,
-      green.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest,
-       ReadbackSubtreeSurroundsTargetLayer_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSubtreeSurroundsTargetLayer) {
   scoped_refptr<SolidColorLayer> background =
       CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
 
@@ -414,66 +227,13 @@
 
   copy_subrect_ = gfx::Rect(0, 0, 100, 100);
   RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_SOFTWARE,
-      READBACK_DEFAULT,
-      background,
+      GetParam().pixel_test_type, GetParam().readback_type, background,
       target.get(),
       base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
 }
 
-TEST_F(LayerTreeHostReadbackPixelTest,
-       ReadbackSubtreeSurroundsLayer_GL_Bitmap) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> target =
-      CreateSolidColorLayer(gfx::Rect(100, 100, 100, 100), SK_ColorRED);
-  background->AddChild(target);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(-100, -100, 300, 300), SK_ColorGREEN);
-  target->AddChild(green);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
-  target->AddChild(blue);
-
-  copy_subrect_ = gfx::Rect(0, 0, 100, 100);
-  RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_BITMAP,
-      background,
-      target.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSubtreeSurroundsTargetLayer_GL) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> target =
-      CreateSolidColorLayer(gfx::Rect(100, 100, 100, 100), SK_ColorRED);
-  background->AddChild(target);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(-100, -100, 300, 300), SK_ColorGREEN);
-  target->AddChild(green);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
-  target->AddChild(blue);
-
-  copy_subrect_ = gfx::Rect(0, 0, 100, 100);
-  RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_DEFAULT,
-      background,
-      target.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest,
-       ReadbackSubtreeExtendsBeyondTargetLayer_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest,
+       ReadbackSubtreeExtendsBeyondTargetLayer) {
   scoped_refptr<SolidColorLayer> background =
       CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
 
@@ -491,66 +251,12 @@
 
   copy_subrect_ = gfx::Rect(50, 50, 100, 100);
   RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_SOFTWARE,
-      READBACK_DEFAULT,
-      background,
+      GetParam().pixel_test_type, GetParam().readback_type, background,
       target.get(),
       base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
 }
 
-TEST_F(LayerTreeHostReadbackPixelTest,
-       ReadbackSubtreeExtendsBeyondTargetLayer_GL_Bitmap) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> target =
-      CreateSolidColorLayer(gfx::Rect(50, 50, 150, 150), SK_ColorRED);
-  background->AddChild(target);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(50, 50, 200, 200), SK_ColorGREEN);
-  target->AddChild(green);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(100, 100, 50, 50), SK_ColorBLUE);
-  target->AddChild(blue);
-
-  copy_subrect_ = gfx::Rect(50, 50, 100, 100);
-  RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_BITMAP,
-      background,
-      target.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest,
-       ReadbackSubtreeExtendsBeyondTargetLayer_GL) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> target =
-      CreateSolidColorLayer(gfx::Rect(50, 50, 150, 150), SK_ColorRED);
-  background->AddChild(target);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(50, 50, 200, 200), SK_ColorGREEN);
-  target->AddChild(green);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(100, 100, 50, 50), SK_ColorBLUE);
-  target->AddChild(blue);
-
-  copy_subrect_ = gfx::Rect(50, 50, 100, 100);
-  RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_DEFAULT,
-      background,
-      target.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackHiddenSubtree_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackHiddenSubtree) {
   scoped_refptr<SolidColorLayer> background =
       CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
 
@@ -564,57 +270,13 @@
   hidden_target->AddChild(blue);
 
   RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_SOFTWARE,
-      READBACK_DEFAULT,
-      background,
+      GetParam().pixel_test_type, GetParam().readback_type, background,
       hidden_target.get(),
       base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
 }
 
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackHiddenSubtree_GL_Bitmap) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
-
-  scoped_refptr<SolidColorLayer> hidden_target =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
-  hidden_target->SetHideLayerAndSubtree(true);
-  background->AddChild(hidden_target);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
-  hidden_target->AddChild(blue);
-
-  RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_BITMAP,
-      background,
-      hidden_target.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackHiddenSubtree_GL) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
-
-  scoped_refptr<SolidColorLayer> hidden_target =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
-  hidden_target->SetHideLayerAndSubtree(true);
-  background->AddChild(hidden_target);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
-  hidden_target->AddChild(blue);
-
-  RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_DEFAULT,
-      background,
-      hidden_target.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest,
-       HiddenSubtreeNotVisibleWhenDrawnForReadback_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest,
+       HiddenSubtreeNotVisibleWhenDrawnForReadback) {
   scoped_refptr<SolidColorLayer> background =
       CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
 
@@ -629,57 +291,11 @@
 
   hidden_target->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
       base::Bind(&IgnoreReadbackResult)));
-  RunReadbackTest(PIXEL_TEST_SOFTWARE,
-                  READBACK_DEFAULT,
-                  background,
-                  base::FilePath(FILE_PATH_LITERAL("black.png")));
+  RunReadbackTest(GetParam().pixel_test_type, GetParam().readback_type,
+                  background, base::FilePath(FILE_PATH_LITERAL("black.png")));
 }
 
-TEST_F(LayerTreeHostReadbackPixelTest,
-       HiddenSubtreeNotVisibleWhenDrawnForReadback_GL_Bitmap) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
-
-  scoped_refptr<SolidColorLayer> hidden_target =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
-  hidden_target->SetHideLayerAndSubtree(true);
-  background->AddChild(hidden_target);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
-  hidden_target->AddChild(blue);
-
-  hidden_target->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
-      base::Bind(&IgnoreReadbackResult)));
-  RunReadbackTest(PIXEL_TEST_GL,
-                  READBACK_BITMAP,
-                  background,
-                  base::FilePath(FILE_PATH_LITERAL("black.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest,
-       HiddenSubtreeNotVisibleWhenDrawnForReadback_GL) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
-
-  scoped_refptr<SolidColorLayer> hidden_target =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
-  hidden_target->SetHideLayerAndSubtree(true);
-  background->AddChild(hidden_target);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
-  hidden_target->AddChild(blue);
-
-  hidden_target->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
-      base::Bind(&IgnoreReadbackResult)));
-  RunReadbackTest(PIXEL_TEST_GL,
-                  READBACK_DEFAULT,
-                  background,
-                  base::FilePath(FILE_PATH_LITERAL("black.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSubrect_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackSubrect) {
   scoped_refptr<SolidColorLayer> background =
       CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
 
@@ -695,57 +311,11 @@
   copy_subrect_ = gfx::Rect(50, 50, 100, 100);
 
   RunReadbackTest(
-      PIXEL_TEST_SOFTWARE,
-      READBACK_DEFAULT,
-      background,
+      GetParam().pixel_test_type, GetParam().readback_type, background,
       base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
 }
 
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSubrect_GL_Bitmap) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
-  background->AddChild(green);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(100, 100, 50, 50), SK_ColorBLUE);
-  green->AddChild(blue);
-
-  // Grab the middle of the root layer.
-  copy_subrect_ = gfx::Rect(50, 50, 100, 100);
-
-  RunReadbackTest(
-      PIXEL_TEST_GL,
-      READBACK_BITMAP,
-      background,
-      base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSubrect_GL) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
-  background->AddChild(green);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(100, 100, 50, 50), SK_ColorBLUE);
-  green->AddChild(blue);
-
-  // Grab the middle of the root layer.
-  copy_subrect_ = gfx::Rect(50, 50, 100, 100);
-
-  RunReadbackTest(
-      PIXEL_TEST_GL,
-      READBACK_DEFAULT,
-      background,
-      base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerSubrect_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerSubrect) {
   scoped_refptr<SolidColorLayer> background =
       CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
 
@@ -761,60 +331,12 @@
   copy_subrect_ = gfx::Rect(25, 25, 100, 100);
 
   RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_SOFTWARE,
-      READBACK_DEFAULT,
-      background,
+      GetParam().pixel_test_type, GetParam().readback_type, background,
       green.get(),
       base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
 }
 
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerSubrect_GL_Bitmap) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(25, 25, 150, 150), SK_ColorGREEN);
-  background->AddChild(green);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(75, 75, 50, 50), SK_ColorBLUE);
-  green->AddChild(blue);
-
-  // Grab the middle of the green layer.
-  copy_subrect_ = gfx::Rect(25, 25, 100, 100);
-
-  RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_BITMAP,
-      background,
-      green.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerSubrect_GL) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(25, 25, 150, 150), SK_ColorGREEN);
-  background->AddChild(green);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(75, 75, 50, 50), SK_ColorBLUE);
-  green->AddChild(blue);
-
-  // Grab the middle of the green layer.
-  copy_subrect_ = gfx::Rect(25, 25, 100, 100);
-
-  RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_DEFAULT,
-      background,
-      green.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackWhenNoDamage_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackWhenNoDamage) {
   scoped_refptr<SolidColorLayer> background =
       CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
 
@@ -832,65 +354,12 @@
 
   insert_copy_request_after_frame_count_ = 1;
   RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_SOFTWARE,
-      READBACK_DEFAULT,
-      background,
+      GetParam().pixel_test_type, GetParam().readback_type, background,
       target.get(),
       base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
 }
 
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackWhenNoDamage_GL_Bitmap) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> parent =
-      CreateSolidColorLayer(gfx::Rect(0, 0, 150, 150), SK_ColorRED);
-  background->AddChild(parent);
-
-  scoped_refptr<SolidColorLayer> target =
-      CreateSolidColorLayer(gfx::Rect(0, 0, 100, 100), SK_ColorGREEN);
-  parent->AddChild(target);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
-  target->AddChild(blue);
-
-  insert_copy_request_after_frame_count_ = 1;
-  RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_BITMAP,
-      background,
-      target.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackWhenNoDamage_GL) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> parent =
-      CreateSolidColorLayer(gfx::Rect(0, 0, 150, 150), SK_ColorRED);
-  background->AddChild(parent);
-
-  scoped_refptr<SolidColorLayer> target =
-      CreateSolidColorLayer(gfx::Rect(0, 0, 100, 100), SK_ColorGREEN);
-  parent->AddChild(target);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
-  target->AddChild(blue);
-
-  insert_copy_request_after_frame_count_ = 1;
-  RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_DEFAULT,
-      background,
-      target.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest,
-       ReadbackOutsideViewportWhenNoDamage_Software) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackOutsideViewportWhenNoDamage) {
   scoped_refptr<SolidColorLayer> background =
       CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
 
@@ -909,66 +378,81 @@
 
   insert_copy_request_after_frame_count_ = 1;
   RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_SOFTWARE,
-      READBACK_DEFAULT,
-      background,
+      GetParam().pixel_test_type, GetParam().readback_type, background,
       target.get(),
       base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
 }
 
-TEST_F(LayerTreeHostReadbackPixelTest,
-       ReadbackOutsideViewportWhenNoDamage_GL_Bitmap) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerOutsideViewport) {
   scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
+      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
 
-  scoped_refptr<SolidColorLayer> parent =
-      CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorRED);
-  EXPECT_FALSE(parent->masks_to_bounds());
-  background->AddChild(parent);
-
-  scoped_refptr<SolidColorLayer> target =
-      CreateSolidColorLayer(gfx::Rect(250, 250, 100, 100), SK_ColorGREEN);
-  parent->AddChild(target);
+  scoped_refptr<SolidColorLayer> green =
+      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
+  // Only the top left quarter of the layer is inside the viewport, so the
+  // blue layer is entirely outside.
+  green->SetPosition(gfx::Point(100, 100));
+  background->AddChild(green);
 
   scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
-  target->AddChild(blue);
+      CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
+  green->AddChild(blue);
 
-  insert_copy_request_after_frame_count_ = 1;
   RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_BITMAP,
-      background,
-      target.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
+      GetParam().pixel_test_type, GetParam().readback_type, background,
+      green.get(),
+      base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
 }
 
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackOutsideViewportWhenNoDamage_GL) {
+TEST_P(LayerTreeHostReadbackPixelTest, ReadbackNonRootOrFirstLayer) {
+  // This test has 3 render passes with the copy request on the render pass in
+  // the middle. This test caught an issue where copy requests on non-root
+  // non-first render passes were being treated differently from the first
+  // render pass.
   scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> parent =
-      CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorRED);
-  EXPECT_FALSE(parent->masks_to_bounds());
-  background->AddChild(parent);
-
-  scoped_refptr<SolidColorLayer> target =
-      CreateSolidColorLayer(gfx::Rect(250, 250, 100, 100), SK_ColorGREEN);
-  parent->AddChild(target);
+      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
 
   scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
-  target->AddChild(blue);
+      CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
+  blue->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
+      base::Bind(&IgnoreReadbackResult)));
+  background->AddChild(blue);
 
-  insert_copy_request_after_frame_count_ = 1;
   RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_DEFAULT,
-      background,
-      target.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
+      GetParam().pixel_test_type, GetParam().readback_type, background,
+      background.get(),
+      base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
 }
 
+TEST_P(LayerTreeHostReadbackPixelTest, MultipleReadbacksOnLayer) {
+  // This test has 2 copy requests on the background layer. One is added in the
+  // test body, another is added in RunReadbackTestWithReadbackTarget. For every
+  // copy request after the first, state must be restored via a call to
+  // UseRenderPass (see http://crbug.com/99393). This test ensures that the
+  // renderer correctly handles cases where UseRenderPass is called multiple
+  // times for a single layer.
+  scoped_refptr<SolidColorLayer> background =
+      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
+
+  background->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
+      base::Bind(&IgnoreReadbackResult)));
+
+  RunReadbackTestWithReadbackTarget(
+      GetParam().pixel_test_type, GetParam().readback_type, background,
+      background.get(), base::FilePath(FILE_PATH_LITERAL("green.png")));
+}
+
+INSTANTIATE_TEST_CASE_P(
+    LayerTreeHostReadbackPixelTests,
+    LayerTreeHostReadbackPixelTest,
+    ::testing::Values(
+        ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_SOFTWARE,
+                           READBACK_DEFAULT),
+        ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL,
+                           READBACK_DEFAULT),
+        ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL,
+                           READBACK_BITMAP)));
+
 class LayerTreeHostReadbackDeviceScalePixelTest
     : public LayerTreeHostReadbackPixelTest {
  protected:
@@ -999,7 +483,7 @@
   SolidColorContentLayerClient blue_client_;
 };
 
-TEST_F(LayerTreeHostReadbackDeviceScalePixelTest, ReadbackSubrect_Software) {
+TEST_P(LayerTreeHostReadbackDeviceScalePixelTest, ReadbackSubrect) {
   scoped_refptr<FakePictureLayer> background =
       FakePictureLayer::Create(&white_client_);
   background->SetBounds(gfx::Size(100, 100));
@@ -1022,43 +506,11 @@
   copy_subrect_ = gfx::Rect(25, 25, 50, 50);
   device_scale_factor_ = 2.f;
   RunReadbackTest(
-      PIXEL_TEST_SOFTWARE,
-      READBACK_DEFAULT,
-      background,
+      GetParam().pixel_test_type, GetParam().readback_type, background,
       base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
 }
 
-TEST_F(LayerTreeHostReadbackDeviceScalePixelTest, ReadbackSubrect_GL) {
-  scoped_refptr<FakePictureLayer> background =
-      FakePictureLayer::Create(&white_client_);
-  background->SetBounds(gfx::Size(100, 100));
-  background->SetIsDrawable(true);
-
-  scoped_refptr<FakePictureLayer> green =
-      FakePictureLayer::Create(&green_client_);
-  green->SetBounds(gfx::Size(100, 100));
-  green->SetIsDrawable(true);
-  background->AddChild(green);
-
-  scoped_refptr<FakePictureLayer> blue =
-      FakePictureLayer::Create(&blue_client_);
-  blue->SetPosition(gfx::Point(50, 50));
-  blue->SetBounds(gfx::Size(25, 25));
-  blue->SetIsDrawable(true);
-  green->AddChild(blue);
-
-  // Grab the middle of the root layer.
-  copy_subrect_ = gfx::Rect(25, 25, 50, 50);
-  device_scale_factor_ = 2.f;
-  RunReadbackTest(
-      PIXEL_TEST_GL,
-      READBACK_DEFAULT,
-      background,
-      base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackDeviceScalePixelTest,
-       ReadbackNonRootLayerSubrect_Software) {
+TEST_P(LayerTreeHostReadbackDeviceScalePixelTest, ReadbackNonRootLayerSubrect) {
   scoped_refptr<FakePictureLayer> background =
       FakePictureLayer::Create(&white_client_);
   background->SetBounds(gfx::Size(100, 100));
@@ -1082,67 +534,21 @@
   copy_subrect_ = gfx::Rect(25, 25, 50, 50);
   device_scale_factor_ = 2.f;
   RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_SOFTWARE,
-      READBACK_DEFAULT,
-      background,
+      GetParam().pixel_test_type, GetParam().readback_type, background,
       green.get(),
       base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
 }
 
-TEST_F(LayerTreeHostReadbackDeviceScalePixelTest,
-       ReadbackNonRootLayerSubrect_GL) {
-  scoped_refptr<FakePictureLayer> background =
-      FakePictureLayer::Create(&white_client_);
-  background->SetBounds(gfx::Size(100, 100));
-  background->SetIsDrawable(true);
-
-  scoped_refptr<FakePictureLayer> green =
-      FakePictureLayer::Create(&green_client_);
-  green->SetPosition(gfx::Point(10, 20));
-  green->SetBounds(gfx::Size(90, 80));
-  green->SetIsDrawable(true);
-  background->AddChild(green);
-
-  scoped_refptr<FakePictureLayer> blue =
-      FakePictureLayer::Create(&blue_client_);
-  blue->SetPosition(gfx::Point(50, 50));
-  blue->SetBounds(gfx::Size(25, 25));
-  blue->SetIsDrawable(true);
-  green->AddChild(blue);
-
-  // Grab the green layer's content with blue in the bottom right.
-  copy_subrect_ = gfx::Rect(25, 25, 50, 50);
-  device_scale_factor_ = 2.f;
-  RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_DEFAULT,
-      background,
-      green.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerOutsideViewport) {
-  scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
-
-  scoped_refptr<SolidColorLayer> green =
-      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
-  // Only the top left quarter of the layer is inside the viewport, so the
-  // blue layer is entirely outside.
-  green->SetPosition(gfx::Point(100, 100));
-  background->AddChild(green);
-
-  scoped_refptr<SolidColorLayer> blue =
-      CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
-  green->AddChild(blue);
-
-  RunReadbackTestWithReadbackTarget(
-      PIXEL_TEST_GL,
-      READBACK_DEFAULT,
-      background,
-      green.get(),
-      base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
-}
+INSTANTIATE_TEST_CASE_P(
+    LayerTreeHostReadbackDeviceScalePixelTests,
+    LayerTreeHostReadbackDeviceScalePixelTest,
+    ::testing::Values(
+        ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_SOFTWARE,
+                           READBACK_DEFAULT),
+        ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL,
+                           READBACK_DEFAULT),
+        ReadbackTestConfig(LayerTreeHostReadbackPixelTest::PIXEL_TEST_GL,
+                           READBACK_BITMAP)));
 
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index cff3b1f..bb6dc17 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -82,7 +82,8 @@
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
-    const std::vector<PictureLayerImpl*>& layers = impl->GetPictureLayers();
+    const std::vector<PictureLayerImpl*>& layers =
+        impl->sync_tree()->picture_layers();
     required_for_activation_count_ = 0;
     for (const auto& layer : layers) {
       FakePictureLayerImpl* fake_layer =
@@ -139,7 +140,9 @@
   FakeContentLayerClient client_;
 };
 
-SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestReadyToActivateNonEmpty);
+// Multi-thread only because in single thread the commit goes directly to the
+// active tree, so notify ready to activate is skipped.
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestReadyToActivateNonEmpty);
 
 // Test if the LTHI receives ReadyToDraw notifications from the TileManager when
 // no raster tasks get scheduled.
@@ -154,7 +157,8 @@
 
   void NotifyReadyToDrawOnThread(LayerTreeHostImpl* impl) override {
     did_notify_ready_to_draw_ = true;
-    const std::vector<PictureLayerImpl*>& layers = impl->GetPictureLayers();
+    const std::vector<PictureLayerImpl*>& layers =
+        impl->active_tree()->picture_layers();
     all_tiles_required_for_draw_are_ready_to_draw_ =
         impl->tile_manager()->IsReadyToDraw();
     for (const auto& layer : layers) {
@@ -578,7 +582,7 @@
 
   void AfterTest() override {
     EXPECT_EQ(gfx::Size(40, 40).ToString(),
-              scrollbar_->content_bounds().ToString());
+              scrollbar_->internal_content_bounds().ToString());
   }
 
  private:
@@ -1793,7 +1797,6 @@
   ~EvictionTestLayerImpl() override {}
 
   void AppendQuads(RenderPass* render_pass,
-                   const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override {
     ASSERT_TRUE(has_texture_);
     ASSERT_NE(0u, layer_tree_impl()->resource_provider()->num_resources());
@@ -2940,8 +2943,10 @@
         static_cast<FakeOutputSurface*>(host_impl->output_surface());
     scoped_refptr<TestContextProvider> context_provider =
         TestContextProvider::Create();  // Not bound to thread.
-    EXPECT_TRUE(
-        fake_output_surface->InitializeAndSetContext3d(context_provider));
+    scoped_refptr<TestContextProvider> worker_context_provider =
+        TestContextProvider::Create();  // Not bound to thread.
+    EXPECT_TRUE(fake_output_surface->InitializeAndSetContext3d(
+        context_provider, worker_context_provider));
     did_initialize_gl_ = true;
   }
 
@@ -5172,7 +5177,7 @@
   }
 
   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
-    EXPECT_TRUE(host_impl->pending_tree()->use_gpu_rasterization());
+    EXPECT_TRUE(host_impl->sync_tree()->use_gpu_rasterization());
     EXPECT_TRUE(host_impl->use_gpu_rasterization());
   }
 
@@ -5797,14 +5802,17 @@
 
 MULTI_THREAD_IMPL_TEST_F(RasterizeWithGpuRasterizationCreatesResources);
 
-class GpuRasterizationRasterizesVisibleOnly : public LayerTreeHostTest {
+class SynchronousGpuRasterizationRasterizesVisibleOnly
+    : public LayerTreeHostTest {
  protected:
-  GpuRasterizationRasterizesVisibleOnly() : viewport_size_(1024, 2048) {}
+  SynchronousGpuRasterizationRasterizesVisibleOnly()
+      : viewport_size_(1024, 2048) {}
 
   void InitializeSettings(LayerTreeSettings* settings) override {
     settings->impl_side_painting = true;
     settings->gpu_rasterization_enabled = true;
     settings->gpu_rasterization_forced = true;
+    settings->threaded_gpu_rasterization_enabled = false;
   }
 
   void SetupTree() override {
@@ -5856,7 +5864,54 @@
   gfx::Size viewport_size_;
 };
 
-MULTI_THREAD_IMPL_TEST_F(GpuRasterizationRasterizesVisibleOnly);
+MULTI_THREAD_IMPL_TEST_F(SynchronousGpuRasterizationRasterizesVisibleOnly);
+
+class ThreadedGpuRasterizationRasterizesBorderTiles : public LayerTreeHostTest {
+ protected:
+  ThreadedGpuRasterizationRasterizesBorderTiles()
+      : viewport_size_(1024, 2048) {}
+
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->impl_side_painting = true;
+    settings->gpu_rasterization_enabled = true;
+    settings->gpu_rasterization_forced = true;
+    settings->threaded_gpu_rasterization_enabled = true;
+  }
+
+  void SetupTree() override {
+    client_.set_fill_with_nonsolid_color(true);
+
+    scoped_ptr<FakePicturePile> pile(
+        new FakePicturePile(ImplSidePaintingSettings().minimum_contents_scale,
+                            ImplSidePaintingSettings().default_tile_grid_size));
+    scoped_refptr<FakePictureLayer> root =
+        FakePictureLayer::CreateWithRecordingSource(&client_, pile.Pass());
+    root->SetBounds(gfx::Size(10000, 10000));
+    root->SetContentsOpaque(true);
+
+    layer_tree_host()->SetRootLayer(root);
+    LayerTreeHostTest::SetupTree();
+    layer_tree_host()->SetViewportSize(viewport_size_);
+  }
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+                                   LayerTreeHostImpl::FrameData* frame_data,
+                                   DrawResult draw_result) override {
+    EXPECT_EQ(10u, host_impl->resource_provider()->num_resources());
+    EndTest();
+    return draw_result;
+  }
+
+  void AfterTest() override {}
+
+ private:
+  FakeContentLayerClient client_;
+  gfx::Size viewport_size_;
+};
+
+MULTI_THREAD_IMPL_TEST_F(ThreadedGpuRasterizationRasterizesBorderTiles);
 
 class LayerTreeHostTestContinuousDrawWhenCreatingVisibleTiles
     : public LayerTreeHostTest {
diff --git a/cc/trees/layer_tree_host_unittest_occlusion.cc b/cc/trees/layer_tree_host_unittest_occlusion.cc
index fe87e44..9974ae4 100644
--- a/cc/trees/layer_tree_host_unittest_occlusion.cc
+++ b/cc/trees/layer_tree_host_unittest_occlusion.cc
@@ -5,623 +5,266 @@
 #include "cc/trees/layer_tree_host.h"
 
 #include "cc/layers/layer.h"
-#include "cc/output/copy_output_request.h"
-#include "cc/output/copy_output_result.h"
+#include "cc/layers/picture_layer.h"
+#include "cc/test/fake_content_layer_client.h"
 #include "cc/test/layer_tree_test.h"
-#include "cc/test/test_occlusion_tracker.h"
+#include "cc/trees/layer_tree_impl.h"
 
 namespace cc {
 namespace {
 
-class TestLayer : public Layer {
- public:
-  static scoped_refptr<TestLayer> Create() {
-    return make_scoped_refptr(new TestLayer());
-  }
-
-  bool Update(ResourceUpdateQueue* update_queue,
-              const OcclusionTracker<Layer>* occlusion) override {
-    if (!occlusion)
-      return false;
-
-    const TestOcclusionTracker<Layer>* test_occlusion =
-        static_cast<const TestOcclusionTracker<Layer>*>(occlusion);
-    occlusion_ = UnionSimpleEnclosedRegions(
-        test_occlusion->occlusion_from_inside_target(),
-        test_occlusion->occlusion_from_outside_target());
-    return false;
-  }
-
-  const SimpleEnclosedRegion& occlusion() const { return occlusion_; }
-  const SimpleEnclosedRegion& expected_occlusion() const {
-    return expected_occlusion_;
-  }
-  void set_expected_occlusion(const gfx::Rect& occlusion) {
-    expected_occlusion_ = SimpleEnclosedRegion(occlusion);
-  }
-
- private:
-  TestLayer() : Layer() {
-    SetIsDrawable(true);
-  }
-  ~TestLayer() override {}
-
-  SimpleEnclosedRegion occlusion_;
-  SimpleEnclosedRegion expected_occlusion_;
-};
+#define EXPECT_OCCLUSION_EQ(expected, actual)              \
+  EXPECT_TRUE(expected.IsEqual(actual))                    \
+      << " Expected: " << expected.ToString() << std::endl \
+      << " Actual: " << actual.ToString();
 
 class LayerTreeHostOcclusionTest : public LayerTreeTest {
+ protected:
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->minimum_occlusion_tracking_size = gfx::Size();
+  }
+};
+
+// Verify occlusion is set on the layer draw properties.
+class LayerTreeHostOcclusionTestDrawPropertiesOnLayer
+    : public LayerTreeHostOcclusionTest {
  public:
-  LayerTreeHostOcclusionTest()
-      : root_(TestLayer::Create()),
-        child_(TestLayer::Create()),
-        child2_(TestLayer::Create()),
-        grand_child_(TestLayer::Create()),
-        mask_(TestLayer::Create()) {
+  void SetupTree() override {
+    scoped_refptr<Layer> root = Layer::Create();
+    root->SetBounds(gfx::Size(100, 100));
+    root->SetIsDrawable(true);
+
+    scoped_refptr<Layer> child = Layer::Create();
+    child->SetBounds(gfx::Size(50, 60));
+    child->SetPosition(gfx::PointF(10.f, 5.5f));
+    child->SetContentsOpaque(true);
+    child->SetIsDrawable(true);
+    root->AddChild(child);
+
+    layer_tree_host()->SetRootLayer(root);
+    LayerTreeTest::SetupTree();
   }
 
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
-  void DidCommit() override {
-    TestLayer* root = static_cast<TestLayer*>(layer_tree_host()->root_layer());
-    VerifyOcclusion(root);
+  void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+    LayerImpl* root = impl->active_tree()->root_layer();
+    LayerImpl* child = root->children()[0];
 
+    // Verify the draw properties are valid.
+    EXPECT_TRUE(root->IsDrawnRenderSurfaceLayerListMember());
+    EXPECT_TRUE(child->IsDrawnRenderSurfaceLayerListMember());
+
+    EXPECT_OCCLUSION_EQ(
+        Occlusion(child->draw_transform(), SimpleEnclosedRegion(),
+                  SimpleEnclosedRegion()),
+        child->draw_properties().occlusion_in_content_space);
+    EXPECT_OCCLUSION_EQ(
+        Occlusion(root->draw_transform(), SimpleEnclosedRegion(),
+                  SimpleEnclosedRegion(gfx::Rect(10, 6, 50, 59))),
+        root->draw_properties().occlusion_in_content_space);
+    EndTest();
+  }
+
+  void AfterTest() override {}
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestDrawPropertiesOnLayer);
+
+// Verify occlusion is set on the render surfaces.
+class LayerTreeHostOcclusionTestDrawPropertiesOnSurface
+    : public LayerTreeHostOcclusionTest {
+ public:
+  void SetupTree() override {
+    scoped_refptr<Layer> root = Layer::Create();
+    root->SetBounds(gfx::Size(100, 100));
+    root->SetIsDrawable(true);
+
+    scoped_refptr<Layer> child = Layer::Create();
+    child->SetBounds(gfx::Size(1, 1));
+    child->SetPosition(gfx::PointF(10.f, 5.5f));
+    child->SetIsDrawable(true);
+    child->SetForceRenderSurface(true);
+    root->AddChild(child);
+
+    scoped_refptr<Layer> child2 = Layer::Create();
+    child2->SetBounds(gfx::Size(10, 12));
+    child2->SetPosition(gfx::PointF(13.f, 8.5f));
+    child2->SetContentsOpaque(true);
+    child2->SetIsDrawable(true);
+    root->AddChild(child2);
+
+    layer_tree_host()->SetRootLayer(root);
+    LayerTreeTest::SetupTree();
+  }
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+    LayerImpl* root = impl->active_tree()->root_layer();
+    LayerImpl* child = root->children()[0];
+    RenderSurfaceImpl* surface = child->render_surface();
+
+    // Verify the draw properties are valid.
+    EXPECT_TRUE(root->IsDrawnRenderSurfaceLayerListMember());
+    EXPECT_TRUE(child->IsDrawnRenderSurfaceLayerListMember());
+    EXPECT_EQ(child, child->render_target());
+
+    EXPECT_OCCLUSION_EQ(
+        Occlusion(surface->draw_transform(), SimpleEnclosedRegion(),
+                  SimpleEnclosedRegion(gfx::Rect(13, 9, 10, 11))),
+        surface->occlusion_in_content_space());
+    EndTest();
+  }
+
+  void AfterTest() override {}
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+    LayerTreeHostOcclusionTestDrawPropertiesOnSurface);
+
+// Verify occlusion is set on mask layers.
+class LayerTreeHostOcclusionTestDrawPropertiesOnMask
+    : public LayerTreeHostOcclusionTest {
+ public:
+  void SetupTree() override {
+    scoped_refptr<Layer> root = Layer::Create();
+    root->SetBounds(gfx::Size(100, 100));
+    root->SetIsDrawable(true);
+
+    scoped_refptr<Layer> child = Layer::Create();
+    child->SetBounds(gfx::Size(30, 40));
+    child->SetPosition(gfx::PointF(10.f, 5.5f));
+    child->SetIsDrawable(true);
+    root->AddChild(child);
+
+    scoped_refptr<Layer> make_surface_bigger = Layer::Create();
+    make_surface_bigger->SetBounds(gfx::Size(100, 100));
+    make_surface_bigger->SetPosition(gfx::PointF(-10.f, -15.f));
+    make_surface_bigger->SetIsDrawable(true);
+    child->AddChild(make_surface_bigger);
+
+    scoped_refptr<Layer> mask = PictureLayer::Create(&client_);
+    mask->SetBounds(gfx::Size(30, 40));
+    mask->SetIsDrawable(true);
+    child->SetMaskLayer(mask.get());
+
+    scoped_refptr<Layer> child2 = Layer::Create();
+    child2->SetBounds(gfx::Size(10, 12));
+    child2->SetPosition(gfx::PointF(13.f, 8.5f));
+    child2->SetContentsOpaque(true);
+    child2->SetIsDrawable(true);
+    root->AddChild(child2);
+
+    layer_tree_host()->SetRootLayer(root);
+    LayerTreeTest::SetupTree();
+  }
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+    LayerImpl* root = impl->active_tree()->root_layer();
+    LayerImpl* child = root->children()[0];
+    RenderSurfaceImpl* surface = child->render_surface();
+    LayerImpl* mask = child->mask_layer();
+
+    // Verify the draw properties are valid.
+    EXPECT_TRUE(root->IsDrawnRenderSurfaceLayerListMember());
+    EXPECT_TRUE(child->IsDrawnRenderSurfaceLayerListMember());
+    EXPECT_EQ(child, child->render_target());
+
+    gfx::Transform transform = surface->draw_transform();
+    transform.PreconcatTransform(child->draw_transform());
+
+    EXPECT_OCCLUSION_EQ(
+        Occlusion(transform, SimpleEnclosedRegion(),
+                  SimpleEnclosedRegion(gfx::Rect(13, 9, 10, 11))),
+        mask->draw_properties().occlusion_in_content_space);
     EndTest();
   }
 
   void AfterTest() override {}
 
-  void VerifyOcclusion(TestLayer* layer) const {
-    EXPECT_EQ(layer->expected_occlusion().ToString(),
-              layer->occlusion().ToString());
-
-    for (size_t i = 0; i < layer->children().size(); ++i) {
-      TestLayer* child = static_cast<TestLayer*>(layer->children()[i].get());
-      VerifyOcclusion(child);
-    }
-  }
-
-  void SetLayerPropertiesForTesting(TestLayer* layer,
-                                    TestLayer* parent,
-                                    const gfx::Transform& transform,
-                                    const gfx::PointF& position,
-                                    const gfx::Size& bounds,
-                                    bool opaque) const {
-    layer->RemoveAllChildren();
-    if (parent)
-      parent->AddChild(layer);
-    layer->SetTransform(transform);
-    layer->SetPosition(position);
-    layer->SetBounds(bounds);
-    layer->SetContentsOpaque(opaque);
-  }
-
- protected:
-  void InitializeSettings(LayerTreeSettings* settings) override {
-    settings->minimum_occlusion_tracking_size = gfx::Size();
-  }
-
-  scoped_refptr<TestLayer> root_;
-  scoped_refptr<TestLayer> child_;
-  scoped_refptr<TestLayer> child2_;
-  scoped_refptr<TestLayer> grand_child_;
-  scoped_refptr<TestLayer> mask_;
-
-  gfx::Transform identity_matrix_;
+  FakeContentLayerClient client_;
 };
 
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestDrawPropertiesOnMask);
 
-class LayerTreeHostOcclusionTestOcclusionSurfaceClipping
+// Verify occlusion is set to empty inside the subtree of a replica. This is
+// done because the tile system does not know about replicas, and so would not
+// know that something is unoccluded on the replica even though it's occluded on
+// the original.
+class LayerTreeHostOcclusionTestDrawPropertiesInsideReplica
     : public LayerTreeHostOcclusionTest {
  public:
   void SetupTree() override {
-    // The child layer is a surface and the grand_child is opaque, but clipped
-    // to the child and root
-    SetLayerPropertiesForTesting(
-        root_.get(), NULL, identity_matrix_,
-        gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
-    SetLayerPropertiesForTesting(
-        child_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(10.f, 10.f), gfx::Size(500, 500), false);
-    SetLayerPropertiesForTesting(
-        grand_child_.get(), child_.get(), identity_matrix_,
-        gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
+    scoped_refptr<Layer> root = Layer::Create();
+    root->SetBounds(gfx::Size(100, 100));
+    root->SetIsDrawable(true);
 
-    child_->SetMasksToBounds(true);
-    child_->SetForceRenderSurface(true);
+    scoped_refptr<Layer> child = Layer::Create();
+    child->SetBounds(gfx::Size(1, 1));
+    child->SetPosition(gfx::PointF(10.f, 5.5f));
+    child->SetIsDrawable(true);
+    child->SetForceRenderSurface(true);
+    root->AddChild(child);
 
-    child_->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
-    root_->set_expected_occlusion(gfx::Rect(10, 10, 10, 190));
+    scoped_refptr<Layer> replica = Layer::Create();
+    gfx::Transform translate;
+    translate.Translate(20.f, 4.f);
+    replica->SetTransform(translate);
+    child->SetReplicaLayer(replica.get());
 
-    layer_tree_host()->SetRootLayer(root_);
+    scoped_refptr<Layer> mask = PictureLayer::Create(&client_);
+    mask->SetBounds(gfx::Size(30, 40));
+    mask->SetIsDrawable(true);
+    child->SetMaskLayer(mask.get());
+
+    scoped_refptr<Layer> child2 = Layer::Create();
+    child2->SetBounds(gfx::Size(10, 12));
+    child2->SetPosition(gfx::PointF(13.f, 8.5f));
+    child2->SetContentsOpaque(true);
+    child2->SetIsDrawable(true);
+    root->AddChild(child2);
+
+    layer_tree_host()->SetRootLayer(root);
     LayerTreeTest::SetupTree();
   }
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+    LayerImpl* root = impl->active_tree()->root_layer();
+    LayerImpl* child = root->children()[0];
+    RenderSurfaceImpl* surface = child->render_surface();
+    LayerImpl* mask = child->mask_layer();
+
+    // Verify the draw properties are valid.
+    EXPECT_TRUE(root->IsDrawnRenderSurfaceLayerListMember());
+    EXPECT_TRUE(child->IsDrawnRenderSurfaceLayerListMember());
+    EXPECT_EQ(child, child->render_target());
+
+    // No occlusion from on child, which is part of the replica.
+    EXPECT_OCCLUSION_EQ(Occlusion(),
+                        child->draw_properties().occlusion_in_content_space);
+    // Occlusion on the surface is okay.
+    EXPECT_OCCLUSION_EQ(
+        Occlusion(surface->draw_transform(), SimpleEnclosedRegion(),
+                  SimpleEnclosedRegion(gfx::Rect(13, 9, 10, 11))),
+        surface->occlusion_in_content_space());
+    // No occlusion on the replica'd mask.
+    EXPECT_OCCLUSION_EQ(Occlusion(),
+                        mask->draw_properties().occlusion_in_content_space);
+    EndTest();
+  }
+
+  void AfterTest() override {}
+
+  FakeContentLayerClient client_;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(
-    LayerTreeHostOcclusionTestOcclusionSurfaceClipping);
-
-class LayerTreeHostOcclusionTestOcclusionSurfaceClippingOpaque
-    : public LayerTreeHostOcclusionTest {
- public:
-  void SetupTree() override {
-    // If the child layer is opaque, then it adds to the occlusion seen by the
-    // root_.
-    SetLayerPropertiesForTesting(
-        root_.get(), NULL, identity_matrix_,
-        gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
-    SetLayerPropertiesForTesting(
-        child_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
-    SetLayerPropertiesForTesting(
-        grand_child_.get(), child_.get(), identity_matrix_,
-        gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
-
-    child_->SetMasksToBounds(true);
-    child_->SetForceRenderSurface(true);
-
-    child_->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
-    root_->set_expected_occlusion(gfx::Rect(10, 10, 190, 190));
-
-    layer_tree_host()->SetRootLayer(root_);
-    LayerTreeTest::SetupTree();
-  }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
-    LayerTreeHostOcclusionTestOcclusionSurfaceClippingOpaque);
-
-class LayerTreeHostOcclusionTestOcclusionTwoChildren
-    : public LayerTreeHostOcclusionTest {
- public:
-  void SetupTree() override {
-    // Add a second child to the root layer and the regions should merge
-    SetLayerPropertiesForTesting(
-        root_.get(), NULL, identity_matrix_,
-        gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
-    SetLayerPropertiesForTesting(
-        child_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(10.f, 10.f), gfx::Size(500, 500), false);
-    SetLayerPropertiesForTesting(
-        grand_child_.get(), child_.get(), identity_matrix_,
-        gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
-    SetLayerPropertiesForTesting(
-        child2_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
-
-    child_->SetMasksToBounds(true);
-    child_->SetForceRenderSurface(true);
-
-    grand_child_->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
-    child_->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
-    root_->set_expected_occlusion(gfx::Rect(10, 10, 20, 190));
-
-    layer_tree_host()->SetRootLayer(root_);
-    LayerTreeTest::SetupTree();
-  }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
-    LayerTreeHostOcclusionTestOcclusionTwoChildren);
-
-class LayerTreeHostOcclusionTestOcclusionMask
-    : public LayerTreeHostOcclusionTest {
- public:
-  void SetupTree() override {
-    // If the child layer has a mask on it, then it shouldn't contribute to
-    // occlusion on stuff below it.
-    SetLayerPropertiesForTesting(
-        root_.get(), NULL, identity_matrix_,
-        gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
-    SetLayerPropertiesForTesting(
-        child2_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
-    SetLayerPropertiesForTesting(
-        child_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(20.f, 20.f), gfx::Size(500, 500), true);
-    SetLayerPropertiesForTesting(
-        grand_child_.get(), child_.get(), identity_matrix_,
-        gfx::PointF(-10.f, -10.f), gfx::Size(500, 500), true);
-
-    child_->SetMasksToBounds(true);
-    child_->SetForceRenderSurface(true);
-    child_->SetMaskLayer(mask_.get());
-
-    child_->set_expected_occlusion(gfx::Rect(0, 0, 180, 180));
-    root_->set_expected_occlusion(gfx::Rect(10, 10, 190, 190));
-
-    layer_tree_host()->SetRootLayer(root_);
-    LayerTreeTest::SetupTree();
-  }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionMask);
-
-class LayerTreeHostOcclusionTestOcclusionMaskBelowOcclusion
-    : public LayerTreeHostOcclusionTest {
- public:
-  void SetupTree() override {
-    // If the child layer with a mask is below child2, then child2 should
-    // contribute to occlusion on everything, and child shouldn't contribute
-    // to the root_.
-    SetLayerPropertiesForTesting(
-        root_.get(), NULL, identity_matrix_,
-        gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
-    SetLayerPropertiesForTesting(
-        child_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
-    SetLayerPropertiesForTesting(
-        grand_child_.get(), child_.get(), identity_matrix_,
-        gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
-    SetLayerPropertiesForTesting(
-        child2_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
-
-    child_->SetMasksToBounds(true);
-    child_->SetForceRenderSurface(true);
-    child_->SetMaskLayer(mask_.get());
-
-    grand_child_->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
-    child_->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
-    root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
-
-    layer_tree_host()->SetRootLayer(root_);
-    LayerTreeTest::SetupTree();
-  }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
-    LayerTreeHostOcclusionTestOcclusionMaskBelowOcclusion);
-
-class LayerTreeHostOcclusionTestOcclusionOpacity
-    : public LayerTreeHostOcclusionTest {
- public:
-  void SetupTree() override {
-    // If the child layer has a non-opaque opacity, then it shouldn't
-    // contribute to occlusion on stuff below it
-    SetLayerPropertiesForTesting(
-        root_.get(), NULL, identity_matrix_,
-        gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
-    SetLayerPropertiesForTesting(
-        child2_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
-    SetLayerPropertiesForTesting(
-        child_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
-    SetLayerPropertiesForTesting(
-        grand_child_.get(), child_.get(), identity_matrix_,
-        gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
-
-    child_->SetMasksToBounds(true);
-    child_->SetForceRenderSurface(true);
-    child_->SetOpacity(0.5f);
-
-    child_->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
-    root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
-
-    layer_tree_host()->SetRootLayer(root_);
-    LayerTreeTest::SetupTree();
-  }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionOpacity);
-
-class LayerTreeHostOcclusionTestOcclusionOpacityBelowOcclusion
-    : public LayerTreeHostOcclusionTest {
- public:
-  void SetupTree() override {
-    // If the child layer with non-opaque opacity is below child2, then
-    // child2 should contribute to occlusion on everything, and child shouldn't
-    // contribute to the root_.
-    SetLayerPropertiesForTesting(
-        root_.get(), NULL, identity_matrix_,
-        gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
-    SetLayerPropertiesForTesting(
-        child_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
-    SetLayerPropertiesForTesting(
-        grand_child_.get(), child_.get(), identity_matrix_,
-        gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
-    SetLayerPropertiesForTesting(
-        child2_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
-
-    child_->SetMasksToBounds(true);
-    child_->SetForceRenderSurface(true);
-    child_->SetOpacity(0.5f);
-
-    grand_child_->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
-    child_->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
-    root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
-
-    layer_tree_host()->SetRootLayer(root_);
-    LayerTreeTest::SetupTree();
-  }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
-    LayerTreeHostOcclusionTestOcclusionOpacityBelowOcclusion);
-
-class LayerTreeHostOcclusionTestOcclusionBlending
-    : public LayerTreeHostOcclusionTest {
- public:
-  void SetupTree() override {
-    // If the child layer has a blend mode, then it shouldn't
-    // contribute to occlusion on stuff below it
-    SetLayerPropertiesForTesting(
-        root_.get(), NULL, identity_matrix_,
-        gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
-    SetLayerPropertiesForTesting(
-        child2_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
-    SetLayerPropertiesForTesting(
-        child_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
-    SetLayerPropertiesForTesting(
-        grand_child_.get(), child_.get(), identity_matrix_,
-        gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
-
-    child_->SetMasksToBounds(true);
-    child_->SetBlendMode(SkXfermode::kMultiply_Mode);
-    child_->SetForceRenderSurface(true);
-
-    child_->set_expected_occlusion(gfx::Rect(0, 0, 10, 190));
-    root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
-
-    layer_tree_host()->SetRootLayer(root_);
-    LayerTreeTest::SetupTree();
-  }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionBlending);
-
-class LayerTreeHostOcclusionTestOcclusionBlendingBelowOcclusion
-    : public LayerTreeHostOcclusionTest {
- public:
-  void SetupTree() override {
-    // If the child layer with a blend mode is below child2, then
-    // child2 should contribute to occlusion on everything, and child shouldn't
-    // contribute to the root_.
-    SetLayerPropertiesForTesting(
-        root_.get(), NULL, identity_matrix_,
-        gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
-    SetLayerPropertiesForTesting(
-        child_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
-    SetLayerPropertiesForTesting(
-        grand_child_.get(), child_.get(), identity_matrix_,
-        gfx::PointF(-10.f, -10.f), gfx::Size(20, 500), true);
-    SetLayerPropertiesForTesting(
-        child2_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(20.f, 10.f), gfx::Size(10, 500), true);
-
-    child_->SetMasksToBounds(true);
-    child_->SetBlendMode(SkXfermode::kMultiply_Mode);
-
-    grand_child_->set_expected_occlusion(gfx::Rect(10, 0, 10, 190));
-    child_->set_expected_occlusion(gfx::Rect(0, 0, 20, 190));
-    root_->set_expected_occlusion(gfx::Rect(20, 10, 10, 190));
-
-    layer_tree_host()->SetRootLayer(root_);
-    LayerTreeTest::SetupTree();
-  }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
-    LayerTreeHostOcclusionTestOcclusionBlendingBelowOcclusion);
-
-class LayerTreeHostOcclusionTestOcclusionOpacityFilter
-    : public LayerTreeHostOcclusionTest {
- public:
-  void SetupTree() override {
-    FilterOperations filters;
-    filters.Append(FilterOperation::CreateOpacityFilter(0.5f));
-
-    // If the child layer has a filter that changes alpha values, and is below
-    // child2, then child2 should contribute to occlusion on everything,
-    // and child shouldn't contribute to the root
-    SetLayerPropertiesForTesting(
-        root_.get(), NULL, identity_matrix_,
-        gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
-    SetLayerPropertiesForTesting(child_.get(),
-                                 root_.get(),
-                                 identity_matrix_,
-                                 gfx::PointF(0.f, 0.f),
-                                 gfx::Size(500, 500),
-                                 true);
-    SetLayerPropertiesForTesting(grand_child_.get(),
-                                 child_.get(),
-                                 identity_matrix_,
-                                 gfx::PointF(0.f, 0.f),
-                                 gfx::Size(500, 500),
-                                 true);
-    SetLayerPropertiesForTesting(child2_.get(),
-                                 root_.get(),
-                                 identity_matrix_,
-                                 gfx::PointF(10.f, 10.f),
-                                 gfx::Size(30, 30),
-                                 true);
-
-    child_->SetMasksToBounds(true);
-    child_->SetFilters(filters);
-
-    // child2_ occludes grand_child_, showing it does occlude inside child_'s
-    // subtree.
-    grand_child_->set_expected_occlusion(gfx::Rect(10, 10, 30, 30));
-    // grand_child_ occludes child_, showing there is more occlusion in
-    // child_'s subtree.
-    child_->set_expected_occlusion(gfx::Rect(0, 0, 200, 200));
-    // child2_'s occlusion reaches the root, but child_'s subtree does not.
-    root_->set_expected_occlusion(gfx::Rect(10, 10, 30, 30));
-
-    layer_tree_host()->SetRootLayer(root_);
-    LayerTreeTest::SetupTree();
-  }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
-    LayerTreeHostOcclusionTestOcclusionOpacityFilter);
-
-class LayerTreeHostOcclusionTestOcclusionBlurFilter
-    : public LayerTreeHostOcclusionTest {
- public:
-  void SetupTree() override {
-    gfx::Transform child_transform;
-    child_transform.Translate(250.0, 250.0);
-    child_transform.Rotate(90.0);
-    child_transform.Translate(-250.0, -250.0);
-
-    FilterOperations filters;
-    filters.Append(FilterOperation::CreateBlurFilter(10.f));
-
-    // If the child layer has a filter that moves pixels/changes alpha, and is
-    // below child2, then child should not inherit occlusion from outside its
-    // subtree, and should not contribute to the root
-    SetLayerPropertiesForTesting(
-        root_.get(), NULL, identity_matrix_,
-        gfx::PointF(0.f, 0.f), gfx::Size(200, 200), true);
-    SetLayerPropertiesForTesting(
-        child_.get(), root_.get(), child_transform,
-        gfx::PointF(30.f, 30.f), gfx::Size(500, 500), true);
-    SetLayerPropertiesForTesting(
-        grand_child_.get(), child_.get(), identity_matrix_,
-        gfx::PointF(10.f, 10.f), gfx::Size(500, 500), true);
-    SetLayerPropertiesForTesting(
-        child2_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(10.f, 70.f), gfx::Size(500, 500), true);
-
-    child_->SetMasksToBounds(true);
-    child_->SetFilters(filters);
-
-    child_->set_expected_occlusion(gfx::Rect(10, 330, 160, 170));
-    root_->set_expected_occlusion(gfx::Rect(10, 70, 190, 130));
-
-    layer_tree_host()->SetRootLayer(root_);
-    LayerTreeTest::SetupTree();
-  }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
-    LayerTreeHostOcclusionTestOcclusionBlurFilter);
-
-class LayerTreeHostOcclusionTestOcclusionCopyRequest
-    : public LayerTreeHostOcclusionTest {
- public:
-  static void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {}
-
-  void SetupTree() override {
-    // If the child layer has copy request, and is below child2,
-    // then child should not inherit occlusion from outside its subtree.
-    // The child layer will still receive occlusion from inside, and
-    // the root layer will recive occlusion from child.
-    SetLayerPropertiesForTesting(
-        root_.get(), NULL, identity_matrix_,
-        gfx::PointF(), gfx::Size(100, 100), true);
-    SetLayerPropertiesForTesting(
-        child_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(), gfx::Size(75, 75), true);
-    SetLayerPropertiesForTesting(
-        grand_child_.get(), child_.get(), identity_matrix_,
-        gfx::PointF(), gfx::Size(75, 50), true);
-    SetLayerPropertiesForTesting(
-        child2_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(0.f, 25.f), gfx::Size(75, 75), true);
-
-    child_->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
-        base::Bind(&CopyOutputCallback)));
-    EXPECT_TRUE(child_->HasCopyRequest());
-
-    child_->set_expected_occlusion(gfx::Rect(0, 0, 75, 50));
-    root_->set_expected_occlusion(gfx::Rect(0, 0, 75, 100));
-
-    layer_tree_host()->SetRootLayer(root_);
-    LayerTreeTest::SetupTree();
-  }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionCopyRequest);
-
-class LayerTreeHostOcclusionTestOcclusionReplica
-    : public LayerTreeHostOcclusionTest {
- public:
-  void SetupTree() override {
-    // If the child layer has copy request, and is below child2,
-    // then child should not inherit occlusion from outside its subtree.
-    // The child layer will still receive occlusion from inside, and
-    // the root layer will recive occlusion from child.
-    SetLayerPropertiesForTesting(
-        root_.get(), NULL, identity_matrix_,
-        gfx::PointF(), gfx::Size(100, 100), true);
-    SetLayerPropertiesForTesting(
-        child_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(), gfx::Size(75, 75), true);
-    SetLayerPropertiesForTesting(
-        grand_child_.get(), child_.get(), identity_matrix_,
-        gfx::PointF(), gfx::Size(75, 50), true);
-    SetLayerPropertiesForTesting(
-        child2_.get(), root_.get(), identity_matrix_,
-        gfx::PointF(0.f, 25.f), gfx::Size(75, 75), true);
-
-    scoped_refptr<Layer> replica_layer(Layer::Create());
-    child_->SetReplicaLayer(replica_layer.get());
-    EXPECT_TRUE(child_->has_replica());
-
-    child_->set_expected_occlusion(gfx::Rect(0, 0, 75, 50));
-    root_->set_expected_occlusion(gfx::Rect(0, 0, 75, 100));
-
-    layer_tree_host()->SetRootLayer(root_);
-    LayerTreeTest::SetupTree();
-  }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestOcclusionReplica);
-
-class LayerTreeHostOcclusionTestManySurfaces
-    : public LayerTreeHostOcclusionTest {
- public:
-  void SetupTree() override {
-    // We create enough RenderSurfaces that it will trigger Vector reallocation
-    // while computing occlusion.
-    std::vector<scoped_refptr<TestLayer>> layers;
-    int num_surfaces = 200;
-    int root_width = 400;
-    int root_height = 400;
-
-    for (int i = 0; i < num_surfaces; ++i) {
-      layers.push_back(TestLayer::Create());
-      if (i == 0) {
-        SetLayerPropertiesForTesting(
-            layers.back().get(), NULL, identity_matrix_,
-            gfx::PointF(0.f, 0.f),
-            gfx::Size(root_width, root_height), true);
-      } else {
-        SetLayerPropertiesForTesting(
-            layers.back().get(), layers[layers.size() - 2].get(),
-            identity_matrix_,
-            gfx::PointF(1.f, 1.f),
-            gfx::Size(root_width-i, root_height-i), true);
-        layers.back()->SetForceRenderSurface(true);
-      }
-    }
-
-    for (int i = 1; i < num_surfaces; ++i) {
-      scoped_refptr<TestLayer> child = TestLayer::Create();
-      SetLayerPropertiesForTesting(
-          child.get(), layers[i].get(), identity_matrix_,
-          gfx::PointF(0.f, 0.f), gfx::Size(root_width, root_height), false);
-    }
-
-    for (int i = 0; i < num_surfaces-1; ++i) {
-      gfx::Rect expected_occlusion(1, 1, root_width-i-1, root_height-i-1);
-      layers[i]->set_expected_occlusion(expected_occlusion);
-    }
-
-    layer_tree_host()->SetRootLayer(layers[0]);
-    LayerTreeTest::SetupTree();
-  }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostOcclusionTestManySurfaces);
+    LayerTreeHostOcclusionTestDrawPropertiesInsideReplica);
 
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_unittest_picture.cc b/cc/trees/layer_tree_host_unittest_picture.cc
index 159200a..5ce47cd 100644
--- a/cc/trees/layer_tree_host_unittest_picture.cc
+++ b/cc/trees/layer_tree_host_unittest_picture.cc
@@ -135,7 +135,8 @@
   int activates_;
 };
 
-SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostPictureTestTwinLayer);
+// There is no pending layers in single thread mode.
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostPictureTestTwinLayer);
 
 class LayerTreeHostPictureTestResizeViewportWithGpuRaster
     : public LayerTreeHostPictureTest {
@@ -158,7 +159,7 @@
 
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
-  void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override {
+  void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
     LayerImpl* child = impl->sync_tree()->root_layer()->children()[0];
     FakePictureLayerImpl* picture_impl =
         static_cast<FakePictureLayerImpl*>(child);
@@ -324,8 +325,247 @@
   scoped_refptr<FakePictureLayer> picture_;
 };
 
-SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(
+// Multi-thread only since there is no recycle tree in single thread.
+MULTI_THREAD_IMPL_TEST_F(
     LayerTreeHostPictureTestChangeLiveTilesRectWithRecycleTree);
 
+class LayerTreeHostPictureTestRSLLMembership : public LayerTreeHostPictureTest {
+  void SetupTree() override {
+    scoped_refptr<Layer> root = Layer::Create();
+    root->SetBounds(gfx::Size(100, 100));
+
+    child_ = Layer::Create();
+    root->AddChild(child_);
+
+    // Don't be solid color so the layer has tilings/tiles.
+    client_.set_fill_with_nonsolid_color(true);
+    picture_ = FakePictureLayer::Create(&client_);
+    picture_->SetBounds(gfx::Size(100, 100));
+    child_->AddChild(picture_);
+
+    layer_tree_host()->SetRootLayer(root);
+    LayerTreeHostPictureTest::SetupTree();
+  }
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
+    LayerImpl* root = impl->sync_tree()->root_layer();
+    LayerImpl* child = root->children()[0];
+    LayerImpl* gchild = child->children()[0];
+    FakePictureLayerImpl* picture = static_cast<FakePictureLayerImpl*>(gchild);
+
+    switch (impl->sync_tree()->source_frame_number()) {
+      case 0:
+        // On 1st commit the layer has tilings.
+        EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+        break;
+      case 1:
+        // On 2nd commit, the layer is transparent, but its tilings are left
+        // there.
+        EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+        break;
+      case 2:
+        // On 3rd commit, the layer is visible again, so has tilings.
+        EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+    }
+  }
+
+  void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
+    LayerImpl* root = impl->active_tree()->root_layer();
+    LayerImpl* child = root->children()[0];
+    LayerImpl* gchild = child->children()[0];
+    FakePictureLayerImpl* picture = static_cast<FakePictureLayerImpl*>(gchild);
+
+    switch (impl->active_tree()->source_frame_number()) {
+      case 0:
+        // On 1st commit the layer has tilings.
+        EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+        break;
+      case 1:
+        // On 2nd commit, the layer is transparent, but its tilings are left
+        // there.
+        EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+        break;
+      case 2:
+        // On 3rd commit, the layer is visible again, so has tilings.
+        EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+        EndTest();
+    }
+  }
+
+  void DidCommit() override {
+    switch (layer_tree_host()->source_frame_number()) {
+      case 1:
+        // For the 2nd commit, change opacity to 0 so that the layer will not be
+        // part of the visible frame.
+        child_->SetOpacity(0.f);
+        break;
+      case 2:
+        // For the 3rd commit, change opacity to 1 so that the layer will again
+        // be part of the visible frame.
+        child_->SetOpacity(1.f);
+    }
+  }
+
+  void AfterTest() override {}
+
+  FakeContentLayerClient client_;
+  scoped_refptr<Layer> child_;
+  scoped_refptr<FakePictureLayer> picture_;
+};
+
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostPictureTestRSLLMembership);
+
+class LayerTreeHostPictureTestRSLLMembershipWithScale
+    : public LayerTreeHostPictureTest {
+  void SetupTree() override {
+    scoped_refptr<Layer> root = Layer::Create();
+    root->SetBounds(gfx::Size(100, 100));
+
+    pinch_ = Layer::Create();
+    pinch_->SetBounds(gfx::Size(500, 500));
+    pinch_->SetScrollClipLayerId(root->id());
+    pinch_->SetIsContainerForFixedPositionLayers(true);
+    root->AddChild(pinch_);
+
+    // Don't be solid color so the layer has tilings/tiles.
+    client_.set_fill_with_nonsolid_color(true);
+    picture_ = FakePictureLayer::Create(&client_);
+    picture_->SetBounds(gfx::Size(100, 100));
+    pinch_->AddChild(picture_);
+
+    layer_tree_host()->RegisterViewportLayers(NULL, root, pinch_, pinch_);
+    layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f);
+    layer_tree_host()->SetRootLayer(root);
+    LayerTreeHostPictureTest::SetupTree();
+  }
+
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->layer_transforms_should_scale_layer_contents = true;
+  }
+
+  void BeginTest() override {
+    frame_ = 0;
+    draws_in_frame_ = 0;
+    last_frame_drawn_ = -1;
+    PostSetNeedsCommitToMainThread();
+  }
+
+  void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override {
+    LayerImpl* root = impl->sync_tree()->root_layer();
+    LayerImpl* pinch = root->children()[0];
+    LayerImpl* gchild = pinch->children()[0];
+    FakePictureLayerImpl* picture = static_cast<FakePictureLayerImpl*>(gchild);
+
+    switch (frame_) {
+      case 0:
+        // On 1st commit the layer has tilings.
+        EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+        break;
+      case 1:
+        // On 2nd commit, the layer is transparent, so does not have tilings.
+        EXPECT_EQ(0u, picture->tilings()->num_tilings());
+        break;
+      case 2:
+        // On 3rd commit, the layer is visible again, so has tilings.
+        EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+    }
+  }
+
+  void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+    LayerImpl* root = impl->active_tree()->root_layer();
+    LayerImpl* pinch = root->children()[0];
+    LayerImpl* gchild = pinch->children()[0];
+    FakePictureLayerImpl* picture = static_cast<FakePictureLayerImpl*>(gchild);
+
+    if (frame_ != last_frame_drawn_)
+      draws_in_frame_ = 0;
+    ++draws_in_frame_;
+    last_frame_drawn_ = frame_;
+
+    switch (frame_) {
+      case 0:
+        if (draws_in_frame_ == 1) {
+          // On 1st commit the layer has tilings.
+          EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+          EXPECT_EQ(1.f, picture->HighResTiling()->contents_scale());
+
+          // Pinch zoom in to change the scale on the active tree.
+          impl->PinchGestureBegin();
+          impl->PinchGestureUpdate(2.f, gfx::Point(1, 1));
+          impl->PinchGestureEnd();
+        } else if (picture->tilings()->num_tilings() == 1) {
+          // If the pinch gesture caused a commit we could get here with a
+          // pending tree.
+          EXPECT_FALSE(impl->pending_tree());
+          // The active layer now has only a 2.f scale tiling, which means the
+          // recycled layer's tiling is destroyed.
+          EXPECT_EQ(2.f, picture->HighResTiling()->contents_scale());
+          EXPECT_EQ(0u, picture->GetRecycledTwinLayer()
+                            ->picture_layer_tiling_set()
+                            ->num_tilings());
+
+          ++frame_;
+          MainThreadTaskRunner()->PostTask(
+              FROM_HERE,
+              base::Bind(
+                  &LayerTreeHostPictureTestRSLLMembershipWithScale::NextStep,
+                  base::Unretained(this)));
+        }
+        break;
+      case 1:
+        EXPECT_EQ(1, draws_in_frame_);
+        // On 2nd commit, the layer is transparent, so does not create
+        // tilings. Since the 1.f tiling was destroyed in the recycle tree, it
+        // has no tilings left. This is propogated to the active tree.
+        EXPECT_EQ(0u, picture->picture_layer_tiling_set()->num_tilings());
+        EXPECT_EQ(0u, picture->GetRecycledTwinLayer()
+                          ->picture_layer_tiling_set()
+                          ->num_tilings());
+        ++frame_;
+        MainThreadTaskRunner()->PostTask(
+            FROM_HERE,
+            base::Bind(
+                &LayerTreeHostPictureTestRSLLMembershipWithScale::NextStep,
+                base::Unretained(this)));
+        break;
+      case 2:
+        EXPECT_EQ(1, draws_in_frame_);
+        // On 3rd commit, the layer is visible again, so has tilings.
+        EXPECT_GT(picture->tilings()->num_tilings(), 0u);
+        EndTest();
+    }
+  }
+
+  void NextStep() {
+    switch (frame_) {
+      case 1:
+        // For the 2nd commit, change opacity to 0 so that the layer will not be
+        // part of the visible frame.
+        pinch_->SetOpacity(0.f);
+        break;
+      case 2:
+        // For the 3rd commit, change opacity to 1 so that the layer will again
+        // be part of the visible frame.
+        pinch_->SetOpacity(1.f);
+        break;
+    }
+  }
+
+  void AfterTest() override {}
+
+  FakeContentLayerClient client_;
+  scoped_refptr<Layer> pinch_;
+  scoped_refptr<FakePictureLayer> picture_;
+  int frame_;
+  int draws_in_frame_;
+  int last_frame_drawn_;
+};
+
+// Multi-thread only because in single thread you can't pinch zoom on the
+// compositor thread.
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostPictureTestRSLLMembershipWithScale);
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 80ccf14..4093c42 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -4,6 +4,7 @@
 
 #include "cc/trees/layer_tree_impl.h"
 
+#include <algorithm>
 #include <limits>
 #include <set>
 
@@ -76,6 +77,7 @@
 LayerTreeImpl::LayerTreeImpl(
     LayerTreeHostImpl* layer_tree_host_impl,
     scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor,
+    scoped_refptr<SyncedTopControls> top_controls_shown_ratio,
     scoped_refptr<SyncedElasticOverscroll> elastic_overscroll)
     : layer_tree_host_impl_(layer_tree_host_impl),
       source_frame_number_(-1),
@@ -102,9 +104,7 @@
       render_surface_layer_list_id_(0),
       top_controls_shrink_blink_size_(false),
       top_controls_height_(0),
-      top_controls_content_offset_(0),
-      top_controls_delta_(0),
-      sent_top_controls_delta_(0) {
+      top_controls_shown_ratio_(top_controls_shown_ratio) {
 }
 
 LayerTreeImpl::~LayerTreeImpl() {
@@ -210,20 +210,10 @@
 
   target_tree->PassSwapPromises(&swap_promise_list_);
 
-  // Track the change in top controls height to offset the top_controls_delta
-  // properly.  This is so that the top controls offset will be maintained
-  // across height changes.
-  float top_controls_height_delta =
-      target_tree->top_controls_height_ - top_controls_height_;
-
-  target_tree->top_controls_shrink_blink_size_ =
-      top_controls_shrink_blink_size_;
-  target_tree->top_controls_height_ = top_controls_height_;
-  target_tree->top_controls_content_offset_ = top_controls_content_offset_;
-  target_tree->top_controls_delta_ = target_tree->top_controls_delta_ -
-                                     target_tree->sent_top_controls_delta_ -
-                                     top_controls_height_delta;
-  target_tree->sent_top_controls_delta_ = 0.f;
+  target_tree->set_top_controls_shrink_blink_size(
+      top_controls_shrink_blink_size_);
+  target_tree->set_top_controls_height(top_controls_height_);
+  target_tree->PushTopControls(nullptr);
 
   // Active tree already shares the page_scale_factor object with pending
   // tree so only the limits need to be provided.
@@ -364,6 +354,48 @@
     DidUpdatePageScale();
 }
 
+void LayerTreeImpl::set_top_controls_shrink_blink_size(bool shrink) {
+  if (top_controls_shrink_blink_size_ == shrink)
+    return;
+
+  top_controls_shrink_blink_size_ = shrink;
+  if (IsActiveTree())
+    layer_tree_host_impl_->UpdateViewportContainerSizes();
+}
+
+void LayerTreeImpl::set_top_controls_height(float top_controls_height) {
+  if (top_controls_height_ == top_controls_height)
+    return;
+
+  top_controls_height_ = top_controls_height;
+  if (IsActiveTree())
+    layer_tree_host_impl_->UpdateViewportContainerSizes();
+}
+
+bool LayerTreeImpl::SetCurrentTopControlsShownRatio(float ratio) {
+  ratio = std::max(ratio, 0.f);
+  ratio = std::min(ratio, 1.f);
+  return top_controls_shown_ratio_->SetCurrent(ratio);
+}
+
+void LayerTreeImpl::PushTopControlsFromMainThread(
+    float top_controls_shown_ratio) {
+  PushTopControls(&top_controls_shown_ratio);
+}
+
+void LayerTreeImpl::PushTopControls(const float* top_controls_shown_ratio) {
+  DCHECK(top_controls_shown_ratio || IsActiveTree());
+
+  if (top_controls_shown_ratio) {
+    DCHECK(!IsActiveTree() || !layer_tree_host_impl_->pending_tree());
+    top_controls_shown_ratio_->PushFromMainThread(*top_controls_shown_ratio);
+  }
+  if (IsActiveTree()) {
+    if (top_controls_shown_ratio_->PushPendingToActive())
+      layer_tree_host_impl_->DidChangeTopControlsPosition();
+  }
+}
+
 bool LayerTreeImpl::SetPageScaleFactorLimits(float min_page_scale_factor,
                                              float max_page_scale_factor) {
   if (min_page_scale_factor == min_page_scale_factor_ &&
@@ -451,12 +483,9 @@
   DCHECK(IsActiveTree());
 
   page_scale_factor()->AbortCommit();
+  top_controls_shown_ratio()->AbortCommit();
   elastic_overscroll()->AbortCommit();
 
-  top_controls_content_offset_ += sent_top_controls_delta_;
-  top_controls_delta_ -= sent_top_controls_delta_;
-  sent_top_controls_delta_ = 0.f;
-
   if (!root_layer())
     return;
 
@@ -520,12 +549,9 @@
   render_surface_layer_list_.clear();
 
   {
-    TRACE_EVENT2("cc",
-                 "LayerTreeImpl::UpdateDrawProperties",
-                 "IsActive",
-                 IsActiveTree(),
-                 "SourceFrameNumber",
-                 source_frame_number_);
+    TRACE_EVENT2(
+        "cc", "LayerTreeImpl::UpdateDrawProperties::CalculateDrawProperties",
+        "IsActive", IsActiveTree(), "SourceFrameNumber", source_frame_number_);
     LayerImpl* page_scale_layer =
         page_scale_layer_ ? page_scale_layer_ : InnerViewportContainerLayer();
     bool can_render_to_separate_surface =
@@ -548,66 +574,93 @@
   }
 
   {
-    TRACE_EVENT_BEGIN2("cc", "LayerTreeImpl::UpdateTilePriorities", "IsActive",
-                       IsActiveTree(), "SourceFrameNumber",
-                       source_frame_number_);
-    scoped_ptr<OcclusionTracker<LayerImpl>> occlusion_tracker;
-    if (settings().use_occlusion_for_tile_prioritization) {
-      occlusion_tracker.reset(new OcclusionTracker<LayerImpl>(
-          root_layer()->render_surface()->content_rect()));
-      occlusion_tracker->set_minimum_tracking_size(
-          settings().minimum_occlusion_tracking_size);
-    }
-
-    bool resourceless_software_draw = (layer_tree_host_impl_->GetDrawMode() ==
-                                       DRAW_MODE_RESOURCELESS_SOFTWARE);
+    TRACE_EVENT2("cc", "LayerTreeImpl::UpdateDrawProperties::Occlusion",
+                 "IsActive", IsActiveTree(), "SourceFrameNumber",
+                 source_frame_number_);
+    OcclusionTracker<LayerImpl> occlusion_tracker(
+        root_layer()->render_surface()->content_rect());
+    occlusion_tracker.set_minimum_tracking_size(
+        settings().minimum_occlusion_tracking_size);
 
     // LayerIterator is used here instead of CallFunctionForSubtree to only
     // UpdateTilePriorities on layers that will be visible (and thus have valid
     // draw properties) and not because any ordering is required.
-    typedef LayerIterator<LayerImpl> LayerIteratorType;
-    LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list_);
-    size_t layers_updated_count = 0;
-    bool tile_priorities_updated = false;
-    for (LayerIteratorType it =
-             LayerIteratorType::Begin(&render_surface_layer_list_);
-         it != end;
-         ++it) {
-      if (occlusion_tracker)
-        occlusion_tracker->EnterLayer(it);
+    auto end = LayerIterator<LayerImpl>::End(&render_surface_layer_list_);
+    for (auto it = LayerIterator<LayerImpl>::Begin(&render_surface_layer_list_);
+         it != end; ++it) {
+      occlusion_tracker.EnterLayer(it);
 
-      LayerImpl* layer = *it;
-      const Occlusion& occlusion_in_content_space =
-          occlusion_tracker ? occlusion_tracker->GetCurrentOcclusionForLayer(
-                                  layer->draw_transform())
-                            : Occlusion();
+      // There are very few render targets so this should be cheap to do for
+      // each layer instead of something more complicated.
+      bool inside_replica = false;
+      LayerImpl* layer = it->render_target();
+      while (layer && !inside_replica) {
+        if (layer->render_target()->has_replica())
+          inside_replica = true;
+        layer = layer->render_target()->parent();
+      }
+
+      // Don't use occlusion if a layer will appear in a replica, since the
+      // tile raster code does not know how to look for the replica and would
+      // consider it occluded even though the replica is visible.
+      // Since occlusion is only used for browser compositor (i.e.
+      // use_occlusion_for_tile_prioritization) and it won't use replicas,
+      // this should matter not.
 
       if (it.represents_itself()) {
-        tile_priorities_updated |= layer->UpdateTiles(
-            occlusion_in_content_space, resourceless_software_draw);
-        ++layers_updated_count;
+        Occlusion occlusion =
+            inside_replica ? Occlusion()
+                           : occlusion_tracker.GetCurrentOcclusionForLayer(
+                                 it->draw_transform());
+        it->draw_properties().occlusion_in_content_space = occlusion;
       }
 
-      if (!it.represents_contributing_render_surface()) {
-        if (occlusion_tracker)
-          occlusion_tracker->LeaveLayer(it);
+      if (it.represents_contributing_render_surface()) {
+        // Surfaces aren't used by the tile raster code, so they can have
+        // occlusion regardless of replicas.
+        Occlusion occlusion =
+            occlusion_tracker.GetCurrentOcclusionForContributingSurface(
+                it->render_surface()->draw_transform());
+        it->render_surface()->set_occlusion_in_content_space(occlusion);
+        // Masks are used to draw the contributing surface, so should have
+        // the same occlusion as the surface (nothing inside the surface
+        // occludes them).
+        if (LayerImpl* mask = it->mask_layer()) {
+          Occlusion mask_occlusion =
+              inside_replica
+                  ? Occlusion()
+                  : occlusion_tracker.GetCurrentOcclusionForContributingSurface(
+                        it->render_surface()->draw_transform() *
+                        it->draw_transform());
+          mask->draw_properties().occlusion_in_content_space = mask_occlusion;
+        }
+        if (LayerImpl* replica = it->replica_layer()) {
+          if (LayerImpl* mask = replica->mask_layer())
+            mask->draw_properties().occlusion_in_content_space = Occlusion();
+        }
+      }
+
+      occlusion_tracker.LeaveLayer(it);
+    }
+
+    unoccluded_screen_space_region_ =
+        occlusion_tracker.ComputeVisibleRegionInScreen();
+  }
+
+  {
+    TRACE_EVENT_BEGIN2("cc", "LayerTreeImpl::UpdateDrawProperties::UpdateTiles",
+                       "IsActive", IsActiveTree(), "SourceFrameNumber",
+                       source_frame_number_);
+    const bool resourceless_software_draw =
+        (layer_tree_host_impl_->GetDrawMode() ==
+         DRAW_MODE_RESOURCELESS_SOFTWARE);
+    size_t layers_updated_count = 0;
+    bool tile_priorities_updated = false;
+    for (PictureLayerImpl* layer : picture_layers_) {
+      if (!layer->IsDrawnRenderSurfaceLayerListMember())
         continue;
-      }
-
-      if (layer->mask_layer()) {
-        tile_priorities_updated |= layer->mask_layer()->UpdateTiles(
-            occlusion_in_content_space, resourceless_software_draw);
-        ++layers_updated_count;
-      }
-      if (layer->replica_layer() && layer->replica_layer()->mask_layer()) {
-        tile_priorities_updated |=
-            layer->replica_layer()->mask_layer()->UpdateTiles(
-                occlusion_in_content_space, resourceless_software_draw);
-        ++layers_updated_count;
-      }
-
-      if (occlusion_tracker)
-        occlusion_tracker->LeaveLayer(it);
+      ++layers_updated_count;
+      tile_priorities_updated |= layer->UpdateTiles(resourceless_software_draw);
     }
 
     if (tile_priorities_updated)
@@ -628,6 +681,13 @@
   return render_surface_layer_list_;
 }
 
+const Region& LayerTreeImpl::UnoccludedScreenSpaceRegion() const {
+  // If this assert triggers, then the render_surface_layer_list_ is dirty, so
+  // the unoccluded_screen_space_region_ is not valid anymore.
+  DCHECK(!needs_update_draw_properties_);
+  return unoccluded_screen_space_region_;
+}
+
 gfx::Size LayerTreeImpl::ScrollableSize() const {
   LayerImpl* root_scroll_layer = OuterViewportScrollLayer()
                                      ? OuterViewportScrollLayer()
@@ -739,6 +799,10 @@
   return layer_tree_host_impl_->settings();
 }
 
+const LayerTreeDebugState& LayerTreeImpl::debug_state() const {
+  return layer_tree_host_impl_->debug_state();
+}
+
 const RendererCapabilitiesImpl& LayerTreeImpl::GetRendererCapabilities() const {
   return layer_tree_host_impl_->GetRendererCapabilities();
 }
@@ -775,6 +839,14 @@
   return layer_tree_host_impl_->device_viewport_size();
 }
 
+float LayerTreeImpl::device_scale_factor() const {
+  return layer_tree_host_impl_->device_scale_factor();
+}
+
+DebugRectHistory* LayerTreeImpl::debug_rect_history() const {
+  return layer_tree_host_impl_->debug_rect_history();
+}
+
 bool LayerTreeImpl::IsActiveTree() const {
   return layer_tree_host_impl_->active_tree() == this;
 }
@@ -882,18 +954,6 @@
   layer_tree_host_impl_->SetNeedsRedraw();
 }
 
-const LayerTreeDebugState& LayerTreeImpl::debug_state() const {
-  return layer_tree_host_impl_->debug_state();
-}
-
-float LayerTreeImpl::device_scale_factor() const {
-  return layer_tree_host_impl_->device_scale_factor();
-}
-
-DebugRectHistory* LayerTreeImpl::debug_rect_history() const {
-  return layer_tree_host_impl_->debug_rect_history();
-}
-
 AnimationRegistrar* LayerTreeImpl::animationRegistrar() const {
   return layer_tree_host_impl_->animation_registrar();
 }
@@ -912,7 +972,7 @@
   }
 }
 
-void LayerTreeImpl::AsValueInto(base::debug::TracedValue* state) const {
+void LayerTreeImpl::AsValueInto(base::trace_event::TracedValue* state) const {
   TracedValue::MakeDictIntoImplicitSnapshot(state, "cc::LayerTreeImpl", this);
   state->SetInteger("source_frame_number", source_frame_number_);
 
@@ -1120,6 +1180,19 @@
     layer_tree_host_impl_->SetNeedsCommit();
 }
 
+void LayerTreeImpl::RegisterPictureLayerImpl(PictureLayerImpl* layer) {
+  DCHECK(std::find(picture_layers_.begin(), picture_layers_.end(), layer) ==
+         picture_layers_.end());
+  picture_layers_.push_back(layer);
+}
+
+void LayerTreeImpl::UnregisterPictureLayerImpl(PictureLayerImpl* layer) {
+  std::vector<PictureLayerImpl*>::iterator it =
+      std::find(picture_layers_.begin(), picture_layers_.end(), layer);
+  DCHECK(it != picture_layers_.end());
+  picture_layers_.erase(it);
+}
+
 void LayerTreeImpl::AddLayerWithCopyOutputRequest(LayerImpl* layer) {
   // Only the active tree needs to know about layers with copy requests, as
   // they are aborted if not serviced during draw.
@@ -1532,14 +1605,6 @@
   }
 }
 
-void LayerTreeImpl::RegisterPictureLayerImpl(PictureLayerImpl* layer) {
-  layer_tree_host_impl_->RegisterPictureLayerImpl(layer);
-}
-
-void LayerTreeImpl::UnregisterPictureLayerImpl(PictureLayerImpl* layer) {
-  layer_tree_host_impl_->UnregisterPictureLayerImpl(layer);
-}
-
 void LayerTreeImpl::InputScrollAnimationFinished() {
   layer_tree_host_impl_->ScrollEnd();
 }
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index 2329139..54c8660 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -22,13 +22,7 @@
 namespace trace_event {
 class TracedValue;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::TracedValue;
 }
-}  // namespace base
 
 namespace cc {
 
@@ -55,6 +49,7 @@
 struct SelectionHandle;
 
 typedef std::vector<UIResourceRequest> UIResourceRequestQueue;
+typedef SyncedProperty<AdditionGroup<float>> SyncedTopControls;
 typedef SyncedProperty<AdditionGroup<gfx::Vector2dF>> SyncedElasticOverscroll;
 
 class CC_EXPORT LayerTreeImpl {
@@ -62,9 +57,11 @@
   static scoped_ptr<LayerTreeImpl> create(
       LayerTreeHostImpl* layer_tree_host_impl,
       scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor,
+      scoped_refptr<SyncedTopControls> top_controls_shown_ratio,
       scoped_refptr<SyncedElasticOverscroll> elastic_overscroll) {
-    return make_scoped_ptr(new LayerTreeImpl(
-        layer_tree_host_impl, page_scale_factor, elastic_overscroll));
+    return make_scoped_ptr(
+        new LayerTreeImpl(layer_tree_host_impl, page_scale_factor,
+                          top_controls_shown_ratio, elastic_overscroll));
   }
   virtual ~LayerTreeImpl();
 
@@ -75,6 +72,7 @@
   // Methods called by the layer tree that pass-through or access LTHI.
   // ---------------------------------------------------------------------------
   const LayerTreeSettings& settings() const;
+  const LayerTreeDebugState& debug_state() const;
   const RendererCapabilitiesImpl& GetRendererCapabilities() const;
   ContextProvider* context_provider() const;
   OutputSurface* output_surface() const;
@@ -84,6 +82,8 @@
   PaintTimeCounter* paint_time_counter() const;
   MemoryHistory* memory_history() const;
   gfx::Size device_viewport_size() const;
+  float device_scale_factor() const;
+  DebugRectHistory* debug_rect_history() const;
   bool IsActiveTree() const;
   bool IsPendingTree() const;
   bool IsRecycleTree() const;
@@ -111,13 +111,10 @@
   // ---------------------------------------------------------------------------
   void SetNeedsRedraw();
 
-  // TODO(nduca): These are implemented in cc files temporarily, but will become
-  // trivial accessors in a followup patch.
-  const LayerTreeDebugState& debug_state() const;
-  float device_scale_factor() const;
-  DebugRectHistory* debug_rect_history() const;
+  // Tracing methods.
+  // ---------------------------------------------------------------------------
   void GetAllTilesForTracing(std::set<const Tile*>* tiles) const;
-  void AsValueInto(base::debug::TracedValue* dict) const;
+  void AsValueInto(base::trace_event::TracedValue* dict) const;
 
   // Other public methods
   // ---------------------------------------------------------------------------
@@ -192,6 +189,13 @@
     return elastic_overscroll_.get();
   }
 
+  SyncedTopControls* top_controls_shown_ratio() {
+    return top_controls_shown_ratio_.get();
+  }
+  const SyncedTopControls* top_controls_shown_ratio() const {
+    return top_controls_shown_ratio_.get();
+  }
+
   // Updates draw properties and render surface layer list, as well as tile
   // priorities. Returns false if it was unable to update.
   bool UpdateDrawProperties();
@@ -216,6 +220,7 @@
   void set_ui_resource_request_queue(const UIResourceRequestQueue& queue);
 
   const LayerImplList& RenderSurfaceLayerList() const;
+  const Region& UnoccludedScreenSpaceRegion() const;
 
   // These return the size of the root scrollable area and the size of
   // the user-visible scrolling viewport, in CSS layout coordinates.
@@ -273,6 +278,12 @@
 
   bool IsUIResourceOpaque(UIResourceId uid) const;
 
+  void RegisterPictureLayerImpl(PictureLayerImpl* layer);
+  void UnregisterPictureLayerImpl(PictureLayerImpl* layer);
+  const std::vector<PictureLayerImpl*>& picture_layers() const {
+    return picture_layers_;
+  }
+
   void AddLayerWithCopyOutputRequest(LayerImpl* layer);
   void RemoveLayerWithCopyOutputRequest(LayerImpl* layer);
   const std::vector<LayerImpl*>& LayersWithCopyOutputRequest() const;
@@ -300,39 +311,17 @@
   void GetViewportSelection(ViewportSelectionBound* start,
                             ViewportSelectionBound* end);
 
-  void RegisterPictureLayerImpl(PictureLayerImpl* layer);
-  void UnregisterPictureLayerImpl(PictureLayerImpl* layer);
-
-  void set_top_controls_shrink_blink_size(bool shrink) {
-    top_controls_shrink_blink_size_ = shrink;
-  }
-  void set_top_controls_height(float height) { top_controls_height_ = height; }
-  void set_top_controls_content_offset(float offset) {
-    top_controls_content_offset_ = offset;
-  }
-  void set_top_controls_delta(float delta) {
-    top_controls_delta_ = delta;
-  }
-  void set_sent_top_controls_delta(float sent_delta) {
-    sent_top_controls_delta_ = sent_delta;
-  }
-
+  void set_top_controls_shrink_blink_size(bool shrink);
   bool top_controls_shrink_blink_size() const {
     return top_controls_shrink_blink_size_;
   }
+  bool SetCurrentTopControlsShownRatio(float ratio);
+  float CurrentTopControlsShownRatio() const {
+    return top_controls_shown_ratio_->Current(IsActiveTree());
+  }
+  void set_top_controls_height(float top_controls_height);
   float top_controls_height() const { return top_controls_height_; }
-  float top_controls_content_offset() const {
-    return top_controls_content_offset_;
-  }
-  float top_controls_delta() const {
-    return top_controls_delta_;
-  }
-  float sent_top_controls_delta() const {
-    return sent_top_controls_delta_;
-  }
-  float total_top_controls_content_offset() const {
-    return top_controls_content_offset_ + top_controls_delta_;
-  }
+  void PushTopControlsFromMainThread(float top_controls_shown_ratio);
 
   void SetPendingPageScaleAnimation(
       scoped_ptr<PendingPageScaleAnimation> pending_animation);
@@ -342,6 +331,7 @@
   explicit LayerTreeImpl(
       LayerTreeHostImpl* layer_tree_host_impl,
       scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor,
+      scoped_refptr<SyncedTopControls> top_controls_shown_ratio,
       scoped_refptr<SyncedElasticOverscroll> elastic_overscroll);
   void ProcessLayersRecursive(LayerImpl* current,
                               void (LayerImpl::*function)());
@@ -353,7 +343,7 @@
                                 float max_page_scale_factor);
   void DidUpdatePageScale();
   void HideInnerViewportScrollbarsIfNearMinimumScale();
-
+  void PushTopControls(const float* top_controls_shown_ratio);
   LayerTreeHostImpl* layer_tree_host_impl_;
   int source_frame_number_;
   scoped_ptr<LayerImpl> root_layer_;
@@ -384,6 +374,7 @@
   typedef base::hash_map<int, LayerImpl*> LayerIdMap;
   LayerIdMap layer_id_map_;
 
+  std::vector<PictureLayerImpl*> picture_layers_;
   std::vector<LayerImpl*> layers_with_copy_output_request_;
 
   // Persisted state for non-impl-side-painting.
@@ -391,6 +382,9 @@
 
   // List of visible layers for the most recently prepared frame.
   LayerImplList render_surface_layer_list_;
+  // After drawing the |render_surface_layer_list_| the areas in this region
+  // would not be fully covered by opaque content.
+  Region unoccluded_screen_space_region_;
 
   bool contents_textures_purged_;
   bool viewport_size_invalid_;
@@ -416,11 +410,9 @@
 
   float top_controls_height_;
 
-  // The up-to-date content offset of the top controls, i.e. the amount that the
-  // web contents have been shifted down from the top of the device viewport.
-  float top_controls_content_offset_;
-  float top_controls_delta_;
-  float sent_top_controls_delta_;
+  // The amount that the top controls are shown from 0 (hidden) to 1 (fully
+  // shown).
+  scoped_refptr<SyncedTopControls> top_controls_shown_ratio_;
 
   scoped_ptr<PendingPageScaleAnimation> pending_page_scale_animation_;
 
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index 07dfc29..d3afbe2 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -30,6 +30,7 @@
       gpu_rasterization_enabled(false),
       gpu_rasterization_forced(false),
       gpu_rasterization_msaa_sample_count(0),
+      gpu_rasterization_skewport_target_time_in_seconds(0.0f),
       threaded_gpu_rasterization_enabled(false),
       create_low_res_tiling(false),
       scrollbar_animator(NoAnimator),
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index 8ba859a..fd108f4 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -38,6 +38,7 @@
   bool gpu_rasterization_enabled;
   bool gpu_rasterization_forced;
   int gpu_rasterization_msaa_sample_count;
+  float gpu_rasterization_skewport_target_time_in_seconds;
   bool threaded_gpu_rasterization_enabled;
   bool create_low_res_tiling;
 
diff --git a/cc/trees/occlusion.cc b/cc/trees/occlusion.cc
index 14168f9..6a71496 100644
--- a/cc/trees/occlusion.cc
+++ b/cc/trees/occlusion.cc
@@ -85,4 +85,16 @@
   return unoccluded_rect_in_target_surface;
 }
 
+bool Occlusion::IsEqual(const Occlusion& other) const {
+  return draw_transform_ == other.draw_transform_ &&
+         occlusion_from_inside_target_ == other.occlusion_from_inside_target_ &&
+         occlusion_from_outside_target_ == other.occlusion_from_outside_target_;
+}
+
+std::string Occlusion::ToString() const {
+  return draw_transform_.ToString() + "outside(" +
+         occlusion_from_outside_target_.ToString() + ") inside(" +
+         occlusion_from_inside_target_.ToString() + ")";
+}
+
 }  // namespace cc
diff --git a/cc/trees/occlusion.h b/cc/trees/occlusion.h
index 56f9962..fec4915 100644
--- a/cc/trees/occlusion.h
+++ b/cc/trees/occlusion.h
@@ -5,6 +5,8 @@
 #ifndef CC_TREES_OCCLUSION_H_
 #define CC_TREES_OCCLUSION_H_
 
+#include <string>
+
 #include "base/basictypes.h"
 #include "cc/base/cc_export.h"
 #include "cc/base/simple_enclosed_region.h"
@@ -26,6 +28,9 @@
   bool IsOccluded(const gfx::Rect& content_rect) const;
   gfx::Rect GetUnoccludedContentRect(const gfx::Rect& content_rect) const;
 
+  bool IsEqual(const Occlusion& other) const;
+  std::string ToString() const;
+
  private:
   gfx::Rect GetUnoccludedRectInTargetSurface(
       const gfx::Rect& content_rect) const;
diff --git a/cc/trees/occlusion_tracker.cc b/cc/trees/occlusion_tracker.cc
index bce1fd5..388eb6e 100644
--- a/cc/trees/occlusion_tracker.cc
+++ b/cc/trees/occlusion_tracker.cc
@@ -20,12 +20,12 @@
 template <typename LayerType>
 OcclusionTracker<LayerType>::OcclusionTracker(
     const gfx::Rect& screen_space_clip_rect)
-    : screen_space_clip_rect_(screen_space_clip_rect),
-      occluding_screen_space_rects_(NULL),
-      non_occluding_screen_space_rects_(NULL) {}
+    : screen_space_clip_rect_(screen_space_clip_rect) {
+}
 
 template <typename LayerType>
-OcclusionTracker<LayerType>::~OcclusionTracker() {}
+OcclusionTracker<LayerType>::~OcclusionTracker() {
+}
 
 template <typename LayerType>
 Occlusion OcclusionTracker<LayerType>::GetCurrentOcclusionForLayer(
@@ -38,6 +38,21 @@
 }
 
 template <typename LayerType>
+Occlusion
+OcclusionTracker<LayerType>::GetCurrentOcclusionForContributingSurface(
+    const gfx::Transform& draw_transform) const {
+  DCHECK(!stack_.empty());
+  if (stack_.size() < 2)
+    return Occlusion();
+  // A contributing surface doesn't get occluded by things inside its own
+  // surface, so only things outside the surface can occlude it. That occlusion
+  // is found just below the top of the stack (if it exists).
+  const StackObject& second_last = stack_[stack_.size() - 2];
+  return Occlusion(draw_transform, second_last.occlusion_from_outside_target,
+                   second_last.occlusion_from_inside_target);
+}
+
+template <typename LayerType>
 void OcclusionTracker<LayerType>::EnterLayer(
     const LayerIteratorPosition<LayerType>& layer_iterator) {
   LayerType* render_target = layer_iterator.target_render_surface_layer;
@@ -340,12 +355,15 @@
   gfx::Rect unoccluded_surface_rect;
   gfx::Rect unoccluded_replica_rect;
   if (old_target->background_filters().HasFilterThatMovesPixels()) {
-    unoccluded_surface_rect = UnoccludedContributingSurfaceContentRect(
-        old_surface->content_rect(), old_surface->draw_transform());
+    Occlusion surface_occlusion = GetCurrentOcclusionForContributingSurface(
+        old_surface->draw_transform());
+    unoccluded_surface_rect =
+        surface_occlusion.GetUnoccludedContentRect(old_surface->content_rect());
     if (old_target->has_replica()) {
-      unoccluded_replica_rect = UnoccludedContributingSurfaceContentRect(
-          old_surface->content_rect(),
+      Occlusion replica_occlusion = GetCurrentOcclusionForContributingSurface(
           old_surface->replica_draw_transform());
+      unoccluded_replica_rect = replica_occlusion.GetUnoccludedContentRect(
+          old_surface->content_rect());
     }
   }
 
@@ -447,96 +465,7 @@
         transformed_rect.height() < minimum_tracking_size_.height())
       continue;
     stack_.back().occlusion_from_inside_target.Union(transformed_rect);
-
-    if (!occluding_screen_space_rects_)
-      continue;
-
-    // Save the occluding area in screen space for debug visualization.
-    bool clipped;
-    gfx::QuadF screen_space_quad = MathUtil::MapQuad(
-        layer->render_target()->render_surface()->screen_space_transform(),
-        gfx::QuadF(transformed_rect), &clipped);
-    // TODO(danakj): Store the quad in the debug info instead of the bounding
-    // box.
-    gfx::Rect screen_space_rect =
-        gfx::ToEnclosedRect(screen_space_quad.BoundingBox());
-    occluding_screen_space_rects_->push_back(screen_space_rect);
   }
-
-  if (!non_occluding_screen_space_rects_)
-    return;
-
-  Region non_opaque_contents(gfx::Rect(layer->content_bounds()));
-  non_opaque_contents.Subtract(opaque_contents);
-
-  for (Region::Iterator non_opaque_content_rects(non_opaque_contents);
-       non_opaque_content_rects.has_rect();
-       non_opaque_content_rects.next()) {
-    gfx::Rect transformed_rect =
-        MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
-            layer->draw_transform(), non_opaque_content_rects.rect());
-    transformed_rect.Intersect(clip_rect_in_target);
-    if (transformed_rect.IsEmpty())
-      continue;
-
-    bool clipped;
-    gfx::QuadF screen_space_quad = MathUtil::MapQuad(
-        layer->render_target()->render_surface()->screen_space_transform(),
-        gfx::QuadF(transformed_rect),
-        &clipped);
-    // TODO(danakj): Store the quad in the debug info instead of the bounding
-    // box.
-    gfx::Rect screen_space_rect =
-        gfx::ToEnclosedRect(screen_space_quad.BoundingBox());
-    non_occluding_screen_space_rects_->push_back(screen_space_rect);
-  }
-}
-
-template <typename LayerType>
-gfx::Rect OcclusionTracker<LayerType>::UnoccludedContributingSurfaceContentRect(
-    const gfx::Rect& content_rect,
-    const gfx::Transform& draw_transform) const {
-  if (content_rect.IsEmpty())
-    return content_rect;
-
-  // A contributing surface doesn't get occluded by things inside its own
-  // surface, so only things outside the surface can occlude it. That occlusion
-  // is found just below the top of the stack (if it exists).
-  bool has_occlusion = stack_.size() > 1;
-  if (!has_occlusion)
-    return content_rect;
-
-  const StackObject& second_last = stack_[stack_.size() - 2];
-  if (second_last.occlusion_from_inside_target.IsEmpty() &&
-      second_last.occlusion_from_outside_target.IsEmpty())
-    return content_rect;
-
-  gfx::Transform inverse_draw_transform(gfx::Transform::kSkipInitialization);
-  bool ok = draw_transform.GetInverse(&inverse_draw_transform);
-  DCHECK(ok);
-
-  // Take the ToEnclosingRect at each step, as we want to contain any unoccluded
-  // partial pixels in the resulting Rect.
-  gfx::Rect unoccluded_rect_in_target_surface =
-      MathUtil::MapEnclosingClippedRect(draw_transform, content_rect);
-  DCHECK_LE(second_last.occlusion_from_inside_target.GetRegionComplexity(), 1u);
-  DCHECK_LE(second_last.occlusion_from_outside_target.GetRegionComplexity(),
-            1u);
-  // These subtract operations are more lossy than if we did both operations at
-  // once.
-  unoccluded_rect_in_target_surface.Subtract(
-      second_last.occlusion_from_inside_target.bounds());
-  unoccluded_rect_in_target_surface.Subtract(
-      second_last.occlusion_from_outside_target.bounds());
-
-  if (unoccluded_rect_in_target_surface.IsEmpty())
-    return gfx::Rect();
-
-  gfx::Rect unoccluded_rect = MathUtil::ProjectEnclosingClippedRect(
-      inverse_draw_transform, unoccluded_rect_in_target_surface);
-  unoccluded_rect.Intersect(content_rect);
-
-  return unoccluded_rect;
 }
 
 template <typename LayerType>
diff --git a/cc/trees/occlusion_tracker.h b/cc/trees/occlusion_tracker.h
index 4d6555a..ff6f18d 100644
--- a/cc/trees/occlusion_tracker.h
+++ b/cc/trees/occlusion_tracker.h
@@ -40,6 +40,8 @@
   // and can be used outside of a layer walk to check occlusion.
   Occlusion GetCurrentOcclusionForLayer(
       const gfx::Transform& draw_transform) const;
+  Occlusion GetCurrentOcclusionForContributingSurface(
+      const gfx::Transform& draw_transform) const;
 
   // Called at the beginning of each step in the LayerIterator's front-to-back
   // traversal.
@@ -48,13 +50,6 @@
   // traversal.
   void LeaveLayer(const LayerIteratorPosition<LayerType>& layer_iterator);
 
-  // Gives an unoccluded sub-rect of |content_rect| in the content space of the
-  // render_target owned by the layer. Used when considering occlusion for a
-  // contributing surface that is rendering into another target.
-  gfx::Rect UnoccludedContributingSurfaceContentRect(
-      const gfx::Rect& content_rect,
-      const gfx::Transform& draw_transform) const;
-
   // Gives the region of the screen that is not occluded by something opaque.
   Region ComputeVisibleRegionInScreen() const;
 
@@ -62,16 +57,6 @@
     minimum_tracking_size_ = size;
   }
 
-  // The following is used for visualization purposes.
-  void set_occluding_screen_space_rects_container(
-      std::vector<gfx::Rect>* rects) {
-    occluding_screen_space_rects_ = rects;
-  }
-  void set_non_occluding_screen_space_rects_container(
-      std::vector<gfx::Rect>* rects) {
-    non_occluding_screen_space_rects_ = rects;
-  }
-
  protected:
   struct StackObject {
     StackObject() : target(0) {}
@@ -120,10 +105,6 @@
   gfx::Rect screen_space_clip_rect_;
   gfx::Size minimum_tracking_size_;
 
-  // This is used for visualizing the occlusion tracking process.
-  std::vector<gfx::Rect>* occluding_screen_space_rects_;
-  std::vector<gfx::Rect>* non_occluding_screen_space_rects_;
-
   DISALLOW_COPY_AND_ASSIGN(OcclusionTracker);
 };
 
diff --git a/cc/trees/occlusion_tracker_unittest.cc b/cc/trees/occlusion_tracker_unittest.cc
index 172b227..e3639ad 100644
--- a/cc/trees/occlusion_tracker_unittest.cc
+++ b/cc/trees/occlusion_tracker_unittest.cc
@@ -101,8 +101,9 @@
   gfx::Rect UnoccludedSurfaceContentRect(const LayerType* layer,
                                          const gfx::Rect& content_rect) const {
     typename LayerType::RenderSurfaceType* surface = layer->render_surface();
-    return this->UnoccludedContributingSurfaceContentRect(
-        content_rect, surface->draw_transform());
+    return this->GetCurrentOcclusionForContributingSurface(
+                     surface->draw_transform())
+        .GetUnoccludedContentRect(content_rect);
   }
 };
 
@@ -2671,6 +2672,53 @@
     OcclusionTrackerTestReduceOcclusionWhenBackgroundFilterIsPartiallyOccluded);
 
 template <class Types>
+class OcclusionTrackerTestBlendModeDoesNotOcclude
+    : public OcclusionTrackerTest<Types> {
+ protected:
+  explicit OcclusionTrackerTestBlendModeDoesNotOcclude(bool opaque_layers)
+      : OcclusionTrackerTest<Types>(opaque_layers) {}
+  void RunMyTest() override {
+    typename Types::ContentLayerType* parent = this->CreateRoot(
+        this->identity_matrix, gfx::PointF(), gfx::Size(100, 100));
+    typename Types::LayerType* blend_mode_layer = this->CreateDrawingLayer(
+        parent, this->identity_matrix, gfx::PointF(0.f, 0.f),
+        gfx::Size(100, 100), true);
+    typename Types::LayerType* top_layer = this->CreateDrawingLayer(
+        parent, this->identity_matrix, gfx::PointF(10.f, 12.f),
+        gfx::Size(20, 22), true);
+
+    // Blend mode makes the layer own a surface.
+    Types::SetForceRenderSurface(blend_mode_layer, true);
+    blend_mode_layer->SetBlendMode(SkXfermode::kMultiply_Mode);
+
+    this->CalcDrawEtc(parent);
+
+    TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
+        gfx::Rect(0, 0, 1000, 1000));
+
+    this->VisitLayer(top_layer, &occlusion);
+    // |top_layer| occludes.
+    EXPECT_EQ(gfx::Rect(10, 12, 20, 22).ToString(),
+              occlusion.occlusion_from_inside_target().ToString());
+    EXPECT_TRUE(occlusion.occlusion_from_outside_target().IsEmpty());
+
+    this->VisitLayer(blend_mode_layer, &occlusion);
+    // |top_layer| occludes but not |blend_mode_layer|.
+    EXPECT_EQ(gfx::Rect(10, 12, 20, 22).ToString(),
+              occlusion.occlusion_from_outside_target().ToString());
+    EXPECT_TRUE(occlusion.occlusion_from_inside_target().IsEmpty());
+
+    this->VisitContributingSurface(blend_mode_layer, &occlusion);
+    // |top_layer| occludes but not |blend_mode_layer|.
+    EXPECT_EQ(gfx::Rect(10, 12, 20, 22).ToString(),
+              occlusion.occlusion_from_inside_target().ToString());
+    EXPECT_TRUE(occlusion.occlusion_from_outside_target().IsEmpty());
+  }
+};
+
+ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestBlendModeDoesNotOcclude);
+
+template <class Types>
 class OcclusionTrackerTestMinimumTrackingSize
     : public OcclusionTrackerTest<Types> {
  protected:
@@ -2816,12 +2864,22 @@
         gfx::PointF(),
         gfx::Size(200, 400),
         true);
+    typename Types::LayerType* top_layer =
+        this->CreateDrawingLayer(root, this->identity_matrix,
+                                 gfx::PointF(50, 0), gfx::Size(50, 400), true);
     this->CalcDrawEtc(root);
 
     TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
         gfx::Rect(0, 0, 1000, 1000));
 
+    this->VisitLayer(top_layer, &occlusion);
+    EXPECT_EQ(gfx::Rect().ToString(),
+              occlusion.occlusion_from_outside_target().ToString());
+    EXPECT_EQ(gfx::Rect(50, 0, 50, 400).ToString(),
+              occlusion.occlusion_from_inside_target().ToString());
+
     this->VisitLayer(copy_child, &occlusion);
+    // Layers outside the copy request do not occlude.
     EXPECT_EQ(gfx::Rect().ToString(),
               occlusion.occlusion_from_outside_target().ToString());
     EXPECT_EQ(gfx::Rect(200, 400).ToString(),
@@ -2833,7 +2891,7 @@
     // The occlusion from the copy should be kept.
     EXPECT_EQ(gfx::Rect().ToString(),
               occlusion.occlusion_from_outside_target().ToString());
-    EXPECT_EQ(gfx::Rect(100, 0, 200, 400).ToString(),
+    EXPECT_EQ(gfx::Rect(50, 0, 250, 400).ToString(),
               occlusion.occlusion_from_inside_target().ToString());
   }
 };
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index 95c2b5a..25d42aa 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -5,6 +5,7 @@
 #include <set>
 
 #include "base/logging.h"
+#include "cc/base/math_util.h"
 #include "cc/trees/property_tree.h"
 
 namespace cc {
@@ -35,11 +36,16 @@
 
 TransformNodeData::TransformNodeData()
     : target_id(-1),
+      content_target_id(-1),
+      needs_local_transform_update(true),
       is_invertible(true),
       ancestors_are_invertible(true),
       is_animated(false),
       to_screen_is_animated(false),
-      flattens(false) {
+      flattens(false),
+      scrolls(false),
+      needs_sublayer_scale(false),
+      layer_scale_factor(1.0f) {
 }
 
 TransformNodeData::~TransformNodeData() {
@@ -79,47 +85,18 @@
          transform.Preserves2dAxisAlignment();
 }
 
-void TransformTree::UpdateScreenSpaceTransform(int id) {
-  TransformNode* current_node = Node(id);
-  TransformNode* parent_node = parent(current_node);
-  TransformNode* target_node = Node(current_node->data.target_id);
-
-  if (!parent_node) {
-    current_node->data.to_screen = current_node->data.to_parent;
-    current_node->data.ancestors_are_invertible = true;
-    current_node->data.to_screen_is_animated = false;
-  } else if (parent_node->data.flattens) {
-    // Flattening is tricky. Once a layer is drawn into its render target, it
-    // cannot escape, so we only need to consider transforms between the layer
-    // and its target when flattening (i.e., its draw transform). To compute the
-    // screen space transform when flattening is involved we combine three
-    // transforms, A * B * C, where A is the screen space transform of the
-    // target, B is the flattened draw transform of the layer's parent, and C is
-    // the local transform.
-    current_node->data.to_screen = target_node->data.to_screen;
-    gfx::Transform flattened;
-    ComputeTransform(parent_node->id, target_node->id, &flattened);
-    flattened.FlattenTo2d();
-    current_node->data.to_screen.PreconcatTransform(flattened);
-    current_node->data.to_screen.PreconcatTransform(
-        current_node->data.to_parent);
-    current_node->data.ancestors_are_invertible =
-        parent_node->data.ancestors_are_invertible;
-  } else {
-    current_node->data.to_screen = parent_node->data.to_screen;
-    current_node->data.to_screen.PreconcatTransform(
-        current_node->data.to_parent);
-    current_node->data.ancestors_are_invertible =
-        parent_node->data.ancestors_are_invertible;
-  }
-  if (!current_node->data.to_screen.GetInverse(&current_node->data.from_screen))
-    current_node->data.ancestors_are_invertible = false;
-
-  if (parent_node) {
-    current_node->data.to_screen_is_animated =
-        current_node->data.is_animated ||
-        parent_node->data.to_screen_is_animated;
-  }
+void TransformTree::UpdateTransforms(int id) {
+  TransformNode* node = Node(id);
+  TransformNode* parent_node = parent(node);
+  TransformNode* target_node = Node(node->data.target_id);
+  if (node->data.needs_local_transform_update)
+    UpdateLocalTransform(node);
+  UpdateLocalTransform(node);
+  UpdateScreenSpaceTransform(node, parent_node, target_node);
+  UpdateSublayerScale(node);
+  UpdateTargetSpaceTransform(node, target_node);
+  UpdateIsAnimated(node, parent_node);
+  UpdateSnapping(node);
 }
 
 bool TransformTree::IsDescendant(int desc_id, int source_id) const {
@@ -196,4 +173,123 @@
   return all_are_invertible;
 }
 
+void TransformTree::UpdateLocalTransform(TransformNode* node) {
+  gfx::Transform transform = node->data.post_local;
+  transform.Translate(-node->data.scroll_offset.x(),
+                      -node->data.scroll_offset.y());
+  transform.PreconcatTransform(node->data.local);
+  transform.PreconcatTransform(node->data.pre_local);
+  node->data.set_to_parent(transform);
+  node->data.needs_local_transform_update = false;
+}
+
+void TransformTree::UpdateScreenSpaceTransform(TransformNode* node,
+                                               TransformNode* parent_node,
+                                               TransformNode* target_node) {
+  if (!parent_node) {
+    node->data.to_screen = node->data.to_parent;
+    node->data.ancestors_are_invertible = true;
+    node->data.to_screen_is_animated = false;
+  } else if (parent_node->data.flattens) {
+    // Flattening is tricky. Once a layer is drawn into its render target, it
+    // cannot escape, so we only need to consider transforms between the layer
+    // and its target when flattening (i.e., its draw transform). To compute the
+    // screen space transform when flattening is involved we combine three
+    // transforms, A * B * C, where A is the screen space transform of the
+    // target, B is the flattened draw transform of the layer's parent, and C is
+    // the local transform.
+    node->data.to_screen = target_node->data.to_screen;
+    gfx::Transform flattened;
+    ComputeTransform(parent_node->id, target_node->id, &flattened);
+    flattened.FlattenTo2d();
+    node->data.to_screen.PreconcatTransform(flattened);
+    node->data.to_screen.PreconcatTransform(node->data.to_parent);
+    node->data.ancestors_are_invertible =
+        parent_node->data.ancestors_are_invertible;
+  } else {
+    node->data.to_screen = parent_node->data.to_screen;
+    node->data.to_screen.PreconcatTransform(node->data.to_parent);
+    node->data.ancestors_are_invertible =
+        parent_node->data.ancestors_are_invertible;
+  }
+
+  if (!node->data.to_screen.GetInverse(&node->data.from_screen))
+    node->data.ancestors_are_invertible = false;
+}
+
+void TransformTree::UpdateSublayerScale(TransformNode* node) {
+  // The sublayer scale depends on the screen space transform, so update it too.
+  node->data.sublayer_scale =
+      node->data.needs_sublayer_scale
+          ? MathUtil::ComputeTransform2dScaleComponents(
+                node->data.to_screen, node->data.layer_scale_factor)
+          : gfx::Vector2dF(1.0f, 1.0f);
+}
+
+void TransformTree::UpdateTargetSpaceTransform(TransformNode* node,
+                                               TransformNode* target_node) {
+  node->data.to_target.MakeIdentity();
+  if (node->data.needs_sublayer_scale) {
+    node->data.to_target.Scale(node->data.sublayer_scale.x(),
+                               node->data.sublayer_scale.y());
+  } else {
+    const bool target_is_root_surface = target_node->id == 1;
+    // In order to include the root transform for the root surface, we walk up
+    // to the root of the transform tree in ComputeTransform.
+    int target_id = target_is_root_surface ? 0 : target_node->id;
+    if (target_node) {
+      node->data.to_target.Scale(target_node->data.sublayer_scale.x(),
+                                 target_node->data.sublayer_scale.y());
+    }
+
+    gfx::Transform unscaled_target_transform;
+    ComputeTransform(node->id, target_id, &unscaled_target_transform);
+    node->data.to_target.PreconcatTransform(unscaled_target_transform);
+  }
+
+  if (!node->data.to_target.GetInverse(&node->data.from_target))
+    node->data.ancestors_are_invertible = false;
+}
+
+void TransformTree::UpdateIsAnimated(TransformNode* node,
+                                     TransformNode* parent_node) {
+  if (parent_node) {
+    node->data.to_screen_is_animated =
+        node->data.is_animated || parent_node->data.to_screen_is_animated;
+  }
+}
+
+void TransformTree::UpdateSnapping(TransformNode* node) {
+  if (!node->data.scrolls || node->data.to_screen_is_animated ||
+      !node->data.to_target.IsScaleOrTranslation()) {
+    return;
+  }
+
+  // Scroll snapping must be done in target space (the pixels we care about).
+  // This means we effectively snap the target space transform. If TT is the
+  // target space transform and TT' is TT with its translation components
+  // rounded, then what we're after is the scroll delta X, where TT * X = TT'.
+  // I.e., we want a transform that will realize our scroll snap. It follows
+  // that X = TT^-1 * TT'. We cache TT and TT^-1 to make this more efficient.
+  gfx::Transform rounded = node->data.to_target;
+  rounded.RoundTranslationComponents();
+  gfx::Transform delta = node->data.from_target;
+  delta *= rounded;
+  gfx::Transform inverse_delta(gfx::Transform::kSkipInitialization);
+  bool invertible_delta = delta.GetInverse(&inverse_delta);
+
+  // The delta should be a translation, modulo floating point error, and should
+  // therefore be invertible.
+  DCHECK(invertible_delta);
+
+  // Now that we have our scroll delta, we must apply it to each of our
+  // combined, to/from matrices.
+  node->data.to_parent.PreconcatTransform(delta);
+  node->data.from_parent.ConcatTransform(inverse_delta);
+  node->data.to_target.PreconcatTransform(delta);
+  node->data.from_target.ConcatTransform(inverse_delta);
+  node->data.to_screen.PreconcatTransform(delta);
+  node->data.from_screen.ConcatTransform(inverse_delta);
+}
+
 }  // namespace cc
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h
index 4c10be1..ef47bce 100644
--- a/cc/trees/property_tree.h
+++ b/cc/trees/property_tree.h
@@ -26,13 +26,42 @@
   TransformNodeData();
   ~TransformNodeData();
 
+  // The local transform information is combined to form to_parent (ignoring
+  // snapping) as follows:
+  //
+  //   to_parent = M_post_local * T_scroll * M_local * M_pre_local.
+  //
+  // The pre/post may seem odd when read LTR, but we multiply our points from
+  // the right, so the pre_local matrix affects the result "first". This lines
+  // up with the notions of pre/post used in skia and gfx::Transform.
+  //
+  // TODO(vollick): The values labeled with "will be moved..." take up a lot of
+  // space, but are only necessary for animated or scrolled nodes (otherwise
+  // we'll just use the baked to_parent). These values will be ultimately stored
+  // directly on the transform/scroll display list items when that's possible,
+  // or potentially in a scroll tree.
+  //
+  // TODO(vollick): will be moved when accelerated effects are implemented.
+  gfx::Transform pre_local;
+  gfx::Transform local;
+  gfx::Transform post_local;
+
   gfx::Transform to_parent;
   gfx::Transform from_parent;
 
+  gfx::Transform to_target;
+  gfx::Transform from_target;
+
   gfx::Transform to_screen;
   gfx::Transform from_screen;
 
   int target_id;
+  // This id is used for all content that draws into a render surface associated
+  // with this transform node.
+  int content_target_id;
+
+  // TODO(vollick): will be moved when accelerated effects are implemented.
+  bool needs_local_transform_update;
 
   bool is_invertible;
   bool ancestors_are_invertible;
@@ -41,6 +70,16 @@
   bool to_screen_is_animated;
 
   bool flattens;
+  bool scrolls;
+
+  bool needs_sublayer_scale;
+  // This is used as a fallback when we either cannot adjust raster scale or if
+  // the raster scale cannot be extracted from the screen space transform.
+  float layer_scale_factor;
+  gfx::Vector2dF sublayer_scale;
+
+  // TODO(vollick): will be moved when accelerated effects are implemented.
+  gfx::Vector2dF scroll_offset;
 
   void set_to_parent(const gfx::Transform& transform) {
     to_parent = transform;
@@ -105,9 +144,8 @@
   // aligned with respect to one another.
   bool Are2DAxisAligned(int source_id, int dest_id) const;
 
-  // This recomputes the screen space transform (and its inverse) for the node
-  // at |id|.
-  void UpdateScreenSpaceTransform(int id);
+  // Updates the parent, target, and screen space transforms and snapping.
+  void UpdateTransforms(int id);
 
  private:
   // Returns true iff the node at |desc_id| is a descendant of the node at
@@ -130,6 +168,16 @@
   bool CombineInversesBetween(int source_id,
                               int dest_id,
                               gfx::Transform* transform) const;
+
+  void UpdateLocalTransform(TransformNode* node);
+  void UpdateScreenSpaceTransform(TransformNode* node,
+                                  TransformNode* parent_node,
+                                  TransformNode* target_node);
+  void UpdateSublayerScale(TransformNode* node);
+  void UpdateTargetSpaceTransform(TransformNode* node,
+                                  TransformNode* target_node);
+  void UpdateIsAnimated(TransformNode* node, TransformNode* parent_node);
+  void UpdateSnapping(TransformNode* node);
 };
 
 class CC_EXPORT ClipTree final : public PropertyTree<ClipNode> {};
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
index 934e1fc..ae39f03 100644
--- a/cc/trees/property_tree_builder.cc
+++ b/cc/trees/property_tree_builder.cc
@@ -30,6 +30,8 @@
   const Layer* page_scale_layer;
   float page_scale_factor;
   float device_scale_factor;
+  bool in_subtree_of_page_scale_application_layer;
+  const gfx::Transform* device_transform;
 };
 
 static Layer* GetTransformParent(const DataForRecursion& data, Layer* layer) {
@@ -165,55 +167,58 @@
     return;
   }
 
-  if (!is_root) {
-    data_for_children->transform_tree->Insert(
-        TransformNode(), transform_parent->transform_tree_index());
-  }
+  int parent_index = 0;
+  if (transform_parent)
+    parent_index = transform_parent->transform_tree_index();
+
+  data_for_children->transform_tree->Insert(TransformNode(), parent_index);
 
   TransformNode* node = data_for_children->transform_tree->back();
   layer->set_transform_tree_index(node->id);
 
+  node->data.scrolls = is_scrollable;
   node->data.flattens = layer->should_flatten_transform();
   node->data.target_id =
       data_from_ancestor.render_target->transform_tree_index();
+  node->data.content_target_id =
+      data_for_children->render_target->transform_tree_index();
   DCHECK_NE(node->data.target_id, -1);
   node->data.is_animated = layer->TransformIsAnimating();
 
-  gfx::Transform transform;
-  float device_and_page_scale_factors = 1.0f;
-  if (is_root)
-    device_and_page_scale_factors = data_from_ancestor.device_scale_factor;
-  if (is_page_scale_application_layer)
-    device_and_page_scale_factors *= data_from_ancestor.page_scale_factor;
-
-  transform.Scale(device_and_page_scale_factors, device_and_page_scale_factors);
-
-  // TODO(vollick): We've accounted for the scroll offset here but we haven't
-  // taken into account snapping to screen space pixels. For the purposes of
-  // computing rects we need to record, this should be fine (the visible rects
-  // we compute may be slightly different than what we'd compute with snapping,
-  // but since we significantly expand the visible rect when determining what to
-  // record, the slight difference should be inconsequential).
-  gfx::Vector2dF position = layer->position().OffsetFromOrigin();
-  if (!layer->scroll_parent()) {
-    position -= gfx::Vector2dF(layer->CurrentScrollOffset().x(),
-                               layer->CurrentScrollOffset().y());
+  float scale_factors = 1.0f;
+  if (is_root) {
+    node->data.post_local = *data_from_ancestor.device_transform;
+    scale_factors = data_from_ancestor.device_scale_factor;
   }
 
-  position += parent_offset;
+  if (is_page_scale_application_layer)
+    scale_factors *= data_from_ancestor.page_scale_factor;
 
-  transform.Translate3d(position.x() + layer->transform_origin().x(),
-                        position.y() + layer->transform_origin().y(),
-                        layer->transform_origin().z());
-  transform.PreconcatTransform(layer->transform());
-  transform.Translate3d(-layer->transform_origin().x(),
-                        -layer->transform_origin().y(),
-                        -layer->transform_origin().z());
+  if (has_surface && !is_root) {
+    node->data.needs_sublayer_scale = true;
+    node->data.layer_scale_factor = data_from_ancestor.device_scale_factor;
+    if (data_from_ancestor.in_subtree_of_page_scale_application_layer)
+      node->data.layer_scale_factor *= data_from_ancestor.page_scale_factor;
+  }
 
-  node->data.to_parent = transform;
-  node->data.is_invertible = transform.GetInverse(&node->data.from_parent);
+  node->data.post_local.Scale(scale_factors, scale_factors);
+  node->data.post_local.Translate3d(
+      layer->position().x() + parent_offset.x() + layer->transform_origin().x(),
+      layer->position().y() + parent_offset.y() + layer->transform_origin().y(),
+      layer->transform_origin().z());
 
-  data_from_ancestor.transform_tree->UpdateScreenSpaceTransform(node->id);
+  if (!layer->scroll_parent()) {
+    node->data.scroll_offset =
+        gfx::ScrollOffsetToVector2dF(layer->CurrentScrollOffset());
+  }
+
+  node->data.local = layer->transform();
+  node->data.pre_local.Translate3d(-layer->transform_origin().x(),
+                                   -layer->transform_origin().y(),
+                                   -layer->transform_origin().z());
+
+  node->data.needs_local_transform_update = true;
+  data_from_ancestor.transform_tree->UpdateTransforms(node->id);
 
   layer->set_offset_to_transform_parent(gfx::Vector2dF());
 }
@@ -227,6 +232,9 @@
   AddTransformNodeIfNeeded(data_from_parent, layer, &data_for_children);
   AddClipNodeIfNeeded(data_from_parent, layer, &data_for_children);
 
+  if (layer == data_from_parent.page_scale_layer)
+    data_for_children.in_subtree_of_page_scale_application_layer = true;
+
   for (size_t i = 0; i < layer->children().size(); ++i) {
     if (!layer->children()[i]->scroll_parent())
       BuildPropertyTreesInternal(layer->children()[i].get(), data_for_children);
@@ -263,19 +271,14 @@
   data_for_recursion.page_scale_layer = page_scale_layer;
   data_for_recursion.page_scale_factor = page_scale_factor;
   data_for_recursion.device_scale_factor = device_scale_factor;
-
-  int transform_root_id = transform_tree->Insert(TransformNode(), 0);
+  data_for_recursion.in_subtree_of_page_scale_application_layer = false;
+  data_for_recursion.device_transform = &device_transform;
 
   ClipNode root_clip;
   root_clip.data.clip = viewport;
   root_clip.data.transform_id = 0;
   data_for_recursion.clip_tree_parent = clip_tree->Insert(root_clip, 0);
-
   BuildPropertyTreesInternal(root_layer, data_for_recursion);
-
-  TransformNode* transform_root = transform_tree->Node(transform_root_id);
-  transform_root->data.set_to_parent(device_transform *
-                                     transform_root->data.to_parent);
 }
 
 }  // namespace cc
diff --git a/cc/trees/property_tree_unittest.cc b/cc/trees/property_tree_unittest.cc
index e6de967..014bfcb 100644
--- a/cc/trees/property_tree_unittest.cc
+++ b/cc/trees/property_tree_unittest.cc
@@ -12,9 +12,9 @@
 TEST(PropertyTreeTest, ComputeTransformRoot) {
   TransformTree tree;
   TransformNode& root = *tree.Node(0);
-  root.data.to_parent.Translate(2, 2);
-  root.data.from_parent.Translate(-2, -2);
-  tree.UpdateScreenSpaceTransform(0);
+  root.data.local.Translate(2, 2);
+  root.data.target_id = 0;
+  tree.UpdateTransforms(0);
 
   gfx::Transform expected;
   gfx::Transform transform;
@@ -39,16 +39,16 @@
 TEST(PropertyTreeTest, ComputeTransformChild) {
   TransformTree tree;
   TransformNode& root = *tree.Node(0);
-  root.data.to_parent.Translate(2, 2);
-  root.data.from_parent.Translate(-2, -2);
-  tree.UpdateScreenSpaceTransform(0);
+  root.data.local.Translate(2, 2);
+  root.data.target_id = 0;
+  tree.UpdateTransforms(0);
 
   TransformNode child;
-  child.data.to_parent.Translate(3, 3);
-  child.data.from_parent.Translate(-3, -3);
+  child.data.local.Translate(3, 3);
+  child.data.target_id = 0;
 
   tree.Insert(child, 0);
-  tree.UpdateScreenSpaceTransform(1);
+  tree.UpdateTransforms(1);
 
   gfx::Transform expected;
   gfx::Transform transform;
@@ -83,23 +83,23 @@
 TEST(PropertyTreeTest, ComputeTransformSibling) {
   TransformTree tree;
   TransformNode& root = *tree.Node(0);
-  root.data.to_parent.Translate(2, 2);
-  root.data.from_parent.Translate(-2, -2);
-  tree.UpdateScreenSpaceTransform(0);
+  root.data.local.Translate(2, 2);
+  root.data.target_id = 0;
+  tree.UpdateTransforms(0);
 
   TransformNode child;
-  child.data.to_parent.Translate(3, 3);
-  child.data.from_parent.Translate(-3, -3);
+  child.data.local.Translate(3, 3);
+  child.data.target_id = 0;
 
   TransformNode sibling;
-  sibling.data.to_parent.Translate(7, 7);
-  sibling.data.from_parent.Translate(-7, -7);
+  sibling.data.local.Translate(7, 7);
+  sibling.data.target_id = 0;
 
   tree.Insert(child, 0);
   tree.Insert(sibling, 0);
 
-  tree.UpdateScreenSpaceTransform(1);
-  tree.UpdateScreenSpaceTransform(2);
+  tree.UpdateTransforms(1);
+  tree.UpdateTransforms(2);
 
   gfx::Transform expected;
   gfx::Transform transform;
@@ -128,32 +128,29 @@
   // |sibling|.
   TransformTree tree;
   TransformNode& root = *tree.Node(0);
-  root.data.to_parent.Translate(2, 2);
-  root.data.from_parent.Translate(-2, -2);
-  tree.UpdateScreenSpaceTransform(0);
+  root.data.local.Translate(2, 2);
+  root.data.target_id = 0;
+  tree.UpdateTransforms(0);
 
   TransformNode singular;
-  singular.data.to_parent.matrix().set(2, 2, 0.0);
-  singular.data.is_invertible = false;
-  singular.data.ancestors_are_invertible = false;
+  singular.data.local.matrix().set(2, 2, 0.0);
+  singular.data.target_id = 0;
 
   TransformNode child;
-  child.data.to_parent.Translate(3, 3);
-  child.data.from_parent.Translate(-3, -3);
-  child.data.ancestors_are_invertible = false;
+  child.data.local.Translate(3, 3);
+  child.data.target_id = 0;
 
   TransformNode sibling;
-  sibling.data.to_parent.Translate(7, 7);
-  sibling.data.from_parent.Translate(-7, -7);
-  sibling.data.ancestors_are_invertible = false;
+  sibling.data.local.Translate(7, 7);
+  sibling.data.target_id = 0;
 
   tree.Insert(singular, 0);
   tree.Insert(child, 1);
   tree.Insert(sibling, 1);
 
-  tree.UpdateScreenSpaceTransform(1);
-  tree.UpdateScreenSpaceTransform(2);
-  tree.UpdateScreenSpaceTransform(3);
+  tree.UpdateTransforms(1);
+  tree.UpdateTransforms(2);
+  tree.UpdateTransforms(3);
 
   gfx::Transform expected;
   gfx::Transform transform;
@@ -174,16 +171,16 @@
 TEST(PropertyTreeTest, MultiplicationOrder) {
   TransformTree tree;
   TransformNode& root = *tree.Node(0);
-  root.data.to_parent.Translate(2, 2);
-  root.data.from_parent.Translate(-2, -2);
-  tree.UpdateScreenSpaceTransform(0);
+  root.data.local.Translate(2, 2);
+  root.data.target_id = 0;
+  tree.UpdateTransforms(0);
 
   TransformNode child;
-  child.data.to_parent.Scale(2, 2);
-  child.data.from_parent.Scale(0.5, 0.5);
+  child.data.local.Scale(2, 2);
+  child.data.target_id = 0;
 
   tree.Insert(child, 0);
-  tree.UpdateScreenSpaceTransform(1);
+  tree.UpdateTransforms(1);
 
   gfx::Transform expected;
   expected.Translate(2, 2);
diff --git a/cc/trees/proxy.h b/cc/trees/proxy.h
index 2f181fc..539effe 100644
--- a/cc/trees/proxy.h
+++ b/cc/trees/proxy.h
@@ -20,14 +20,8 @@
 namespace trace_event {
 class TracedValue;
 }
-
-// TODO(ssid): remove these aliases after the tracing clients are moved to the
-// new trace_event namespace. See crbug.com/451032. ETA: March 2015
-namespace debug {
-using ::base::trace_event::TracedValue;
-}
 class SingleThreadTaskRunner;
-}  // namespace base
+}
 
 namespace gfx {
 class Rect;
@@ -62,6 +56,7 @@
   virtual void FinishAllRendering() = 0;
 
   virtual bool IsStarted() const = 0;
+  virtual bool CommitToActiveTree() const = 0;
 
   // Will call LayerTreeHost::OnCreateAndInitializeOutputSurfaceAttempted
   // with the result of this function.
@@ -108,7 +103,7 @@
 
   virtual bool SupportsImplScrolling() const = 0;
 
-  virtual void AsValueInto(base::debug::TracedValue* value) const = 0;
+  virtual void AsValueInto(base::trace_event::TracedValue* value) const = 0;
 
   virtual void SetDebugState(const LayerTreeDebugState& debug_state) = 0;
 
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index f913c1f..4a079f3 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -82,6 +82,12 @@
   return layer_tree_host_impl_;
 }
 
+bool SingleThreadProxy::CommitToActiveTree() const {
+  // With SingleThreadProxy we skip the pending tree and commit directly to the
+  // active tree.
+  return true;
+}
+
 void SingleThreadProxy::SetLayerTreeHostClientReady() {
   TRACE_EVENT0("cc", "SingleThreadProxy::SetLayerTreeHostClientReady");
   // Scheduling is controlled by the embedder in the single thread case, so
@@ -240,8 +246,6 @@
 
     layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get());
 
-    layer_tree_host_impl_->CommitComplete();
-
 #if DCHECK_IS_ON()
     // In the single-threaded case, the scale and scroll deltas should never be
     // touched on the impl layer tree.
@@ -250,18 +254,17 @@
     DCHECK(!scroll_info->scrolls.size());
     DCHECK_EQ(1.f, scroll_info->page_scale_delta);
 #endif
-  }
 
-  if (layer_tree_host_->settings().impl_side_painting) {
-    // TODO(enne): just commit directly to the active tree.
-    //
-    // Synchronously activate during commit to satisfy any potential
-    // SetNextCommitWaitsForActivation calls.  Unfortunately, the tree
-    // might not be ready to draw, so DidActivateSyncTree must set
-    // the flag to force the tree to not draw until textures are ready.
-    NotifyReadyToActivate();
-  } else {
-    CommitComplete();
+    if (layer_tree_host_->settings().impl_side_painting) {
+      // Commit goes directly to the active tree, but we need to synchronously
+      // "activate" the tree still during commit to satisfy any potential
+      // SetNextCommitWaitsForActivation calls.  Unfortunately, the tree
+      // might not be ready to draw, so DidActivateSyncTree must set
+      // the flag to force the tree to not draw until textures are ready.
+      NotifyReadyToActivate();
+    } else {
+      CommitComplete();
+    }
   }
 }
 
@@ -270,6 +273,10 @@
       << "Activation is expected to have synchronously occurred by now.";
   DCHECK(commit_blocking_task_runner_);
 
+  // Notify commit complete on the impl side after activate to satisfy any
+  // SetNextCommitWaitsForActivation calls.
+  layer_tree_host_impl_->CommitComplete();
+
   DebugScopedSetMainThread main(this);
   commit_blocking_task_runner_.reset();
   layer_tree_host_->CommitComplete();
@@ -433,8 +440,8 @@
   // Non-impl-side painting finishes commit in DoCommit.  Impl-side painting
   // defers until here to simulate SetNextCommitWaitsForActivation.
   if (layer_tree_host_impl_->settings().impl_side_painting) {
-    // This is required because NotifyReadyToActivate gets called when
-    // the pending tree is not actually ready in the SingleThreadProxy.
+    // This is required because NotifyReadyToActivate gets called immediately
+    // after commit since single thread commits directly to the active tree.
     layer_tree_host_impl_->SetRequiresHighResToDraw();
 
     // Synchronously call to CommitComplete. Resetting
@@ -542,7 +549,8 @@
   }
 }
 
-void SingleThreadProxy::AsValueInto(base::debug::TracedValue* state) const {
+void SingleThreadProxy::AsValueInto(
+    base::trace_event::TracedValue* state) const {
   // The following line casts away const modifiers because it is just
   // setting debug state. We still want the AsValue() function and its
   // call chain to be const throughout.
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index 132610a..52dd876 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -38,6 +38,7 @@
   // Proxy implementation
   void FinishAllRendering() override;
   bool IsStarted() const override;
+  bool CommitToActiveTree() const override;
   void SetOutputSurface(scoped_ptr<OutputSurface>) override;
   void SetLayerTreeHostClientReady() override;
   void SetVisible(bool visible) override;
@@ -58,7 +59,7 @@
   size_t MaxPartialTextureUpdates() const override;
   void ForceSerializeOnSwapBuffers() override;
   bool SupportsImplScrolling() const override;
-  void AsValueInto(base::debug::TracedValue* state) const override;
+  void AsValueInto(base::trace_event::TracedValue* state) const override;
   bool MainFrameWillHappenForTesting() override;
   void SetChildrenNeedBeginFrames(bool children_need_begin_frames) override;
 
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
index 5ee43ab..167cca9 100644
--- a/cc/trees/thread_proxy.cc
+++ b/cc/trees/thread_proxy.cc
@@ -153,6 +153,12 @@
   return main().started;
 }
 
+bool ThreadProxy::CommitToActiveTree() const {
+  // With ThreadProxy we use a pending tree and activate it once it's ready to
+  // draw.
+  return false;
+}
+
 void ThreadProxy::SetLayerTreeHostClientReady() {
   TRACE_EVENT0("cc", "ThreadProxy::SetLayerTreeHostClientReady");
   Proxy::ImplThreadTaskRunner()->PostTask(
@@ -1232,12 +1238,12 @@
 
 ThreadProxy::BeginMainFrameAndCommitState::~BeginMainFrameAndCommitState() {}
 
-void ThreadProxy::AsValueInto(base::debug::TracedValue* state) const {
+void ThreadProxy::AsValueInto(base::trace_event::TracedValue* state) const {
   CompletionEvent completion;
   {
     DebugScopedSetMainThreadBlocked main_thread_blocked(
         const_cast<ThreadProxy*>(this));
-    scoped_refptr<base::debug::TracedValue> state_refptr(state);
+    scoped_refptr<base::trace_event::TracedValue> state_refptr(state);
     Proxy::ImplThreadTaskRunner()->PostTask(
         FROM_HERE,
         base::Bind(&ThreadProxy::AsValueOnImplThread,
@@ -1248,8 +1254,9 @@
   }
 }
 
-void ThreadProxy::AsValueOnImplThread(CompletionEvent* completion,
-                                      base::debug::TracedValue* state) const {
+void ThreadProxy::AsValueOnImplThread(
+    CompletionEvent* completion,
+    base::trace_event::TracedValue* state) const {
   state->BeginDictionary("layer_tree_host_impl");
   impl().layer_tree_host_impl->AsValueInto(state);
   state->EndDictionary();
diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h
index b4050bd..570d240 100644
--- a/cc/trees/thread_proxy.h
+++ b/cc/trees/thread_proxy.h
@@ -153,6 +153,7 @@
   // Proxy implementation
   void FinishAllRendering() override;
   bool IsStarted() const override;
+  bool CommitToActiveTree() const override;
   void SetOutputSurface(scoped_ptr<OutputSurface>) override;
   void SetLayerTreeHostClientReady() override;
   void SetVisible(bool visible) override;
@@ -174,7 +175,7 @@
   void ForceSerializeOnSwapBuffers() override;
   bool SupportsImplScrolling() const override;
   void SetDebugState(const LayerTreeDebugState& debug_state) override;
-  void AsValueInto(base::debug::TracedValue* value) const override;
+  void AsValueInto(base::trace_event::TracedValue* value) const override;
   bool MainFrameWillHappenForTesting() override;
   void SetChildrenNeedBeginFrames(bool children_need_begin_frames) override;
 
@@ -277,7 +278,7 @@
   void MainFrameWillHappenOnImplThreadForTesting(CompletionEvent* completion,
                                                  bool* main_frame_will_happen);
   void AsValueOnImplThread(CompletionEvent* completion,
-                           base::debug::TracedValue* state) const;
+                           base::trace_event::TracedValue* state) const;
   void SetSwapUsedIncompleteTileOnImplThread(bool used_incomplete_tile);
   void MainThreadHasStoppedFlingingOnImplThread();
   void SetInputThrottledUntilCommitOnImplThread(bool is_throttled);