Update from https://crrev.com/318214

TBR=qsr@chromium.org

Review URL: https://codereview.chromium.org/960873002
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index cffee57..c29cda8 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -337,6 +337,8 @@
     "resources/clip_display_item.h",
     "resources/clip_path_display_item.cc",
     "resources/clip_path_display_item.h",
+    "resources/compositing_display_item.cc",
+    "resources/compositing_display_item.h",
     "resources/content_layer_updater.cc",
     "resources/content_layer_updater.h",
     "resources/display_item.cc",
@@ -466,8 +468,6 @@
     "resources/transferable_resource.h",
     "resources/transform_display_item.cc",
     "resources/transform_display_item.h",
-    "resources/transparency_display_item.cc",
-    "resources/transparency_display_item.h",
     "resources/ui_resource_bitmap.cc",
     "resources/ui_resource_bitmap.h",
     "resources/ui_resource_client.h",
diff --git a/cc/animation/scrollbar_animation_controller.cc b/cc/animation/scrollbar_animation_controller.cc
index ffb2287..48b199d 100644
--- a/cc/animation/scrollbar_animation_controller.cc
+++ b/cc/animation/scrollbar_animation_controller.cc
@@ -7,15 +7,18 @@
 #include <algorithm>
 
 #include "base/time/time.h"
+#include "cc/trees/layer_tree_impl.h"
 
 namespace cc {
 
 ScrollbarAnimationController::ScrollbarAnimationController(
+    LayerImpl* scroll_layer,
     ScrollbarAnimationControllerClient* client,
     base::TimeDelta delay_before_starting,
     base::TimeDelta resize_delay_before_starting,
     base::TimeDelta duration)
-    : client_(client),
+    : scroll_layer_(scroll_layer),
+      client_(client),
       delay_before_starting_(delay_before_starting),
       resize_delay_before_starting_(resize_delay_before_starting),
       duration_(duration),
@@ -26,6 +29,8 @@
 }
 
 ScrollbarAnimationController::~ScrollbarAnimationController() {
+  if (is_animating_)
+    client_->StopAnimatingScrollbarAnimationController(this);
 }
 
 void ScrollbarAnimationController::Animate(base::TimeTicks now) {
@@ -37,11 +42,6 @@
 
   float progress = AnimationProgressAtTime(now);
   RunAnimationFrame(progress);
-
-  if (is_animating_) {
-    delayed_scrollbar_fade_.Cancel();
-    client_->SetNeedsScrollbarAnimationFrame();
-  }
 }
 
 float ScrollbarAnimationController::AnimationProgressAtTime(
@@ -62,38 +62,40 @@
   // As an optimization, we avoid spamming fade delay tasks during active fast
   // scrolls.  But if we're not within one, we need to post every scroll update.
   if (!currently_scrolling_)
-    PostDelayedFade(on_resize);
+    PostDelayedAnimationTask(on_resize);
   else
     scroll_gesture_has_scrolled_ = true;
 }
 
 void ScrollbarAnimationController::DidScrollEnd() {
   if (scroll_gesture_has_scrolled_) {
-    PostDelayedFade(false);
+    PostDelayedAnimationTask(false);
     scroll_gesture_has_scrolled_ = false;
   }
 
   currently_scrolling_ = false;
 }
 
-void ScrollbarAnimationController::PostDelayedFade(bool on_resize) {
+void ScrollbarAnimationController::PostDelayedAnimationTask(bool on_resize) {
   base::TimeDelta delay =
       on_resize ? resize_delay_before_starting_ : delay_before_starting_;
   delayed_scrollbar_fade_.Reset(
       base::Bind(&ScrollbarAnimationController::StartAnimation,
                  weak_factory_.GetWeakPtr()));
-  client_->PostDelayedScrollbarFade(delayed_scrollbar_fade_.callback(), delay);
+  client_->PostDelayedScrollbarAnimationTask(delayed_scrollbar_fade_.callback(),
+                                             delay);
 }
 
 void ScrollbarAnimationController::StartAnimation() {
   delayed_scrollbar_fade_.Cancel();
   is_animating_ = true;
   last_awaken_time_ = base::TimeTicks();
-  client_->SetNeedsScrollbarAnimationFrame();
+  client_->StartAnimatingScrollbarAnimationController(this);
 }
 
 void ScrollbarAnimationController::StopAnimation() {
   is_animating_ = false;
+  client_->StopAnimatingScrollbarAnimationController(this);
 }
 
 }  // namespace cc
diff --git a/cc/animation/scrollbar_animation_controller.h b/cc/animation/scrollbar_animation_controller.h
index 92efe75..795c7c1 100644
--- a/cc/animation/scrollbar_animation_controller.h
+++ b/cc/animation/scrollbar_animation_controller.h
@@ -9,17 +9,25 @@
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "cc/base/cc_export.h"
+#include "cc/layers/layer_impl.h"
 #include "ui/gfx/geometry/vector2d_f.h"
 
 namespace cc {
 
+class ScrollbarAnimationController;
+
 class CC_EXPORT ScrollbarAnimationControllerClient {
  public:
-  virtual ~ScrollbarAnimationControllerClient() {}
+  virtual void StartAnimatingScrollbarAnimationController(
+      ScrollbarAnimationController* controller) = 0;
+  virtual void StopAnimatingScrollbarAnimationController(
+      ScrollbarAnimationController* controller) = 0;
+  virtual void PostDelayedScrollbarAnimationTask(const base::Closure& task,
+                                                 base::TimeDelta delay) = 0;
+  virtual void SetNeedsRedrawForScrollbarAnimation() = 0;
 
-  virtual void PostDelayedScrollbarFade(const base::Closure& start_fade,
-                                        base::TimeDelta delay) = 0;
-  virtual void SetNeedsScrollbarAnimationFrame() = 0;
+ protected:
+  virtual ~ScrollbarAnimationControllerClient() {}
 };
 
 // This abstract class represents the compositor-side analogy of
@@ -38,7 +46,8 @@
   virtual void DidMouseMoveNear(float distance) {}
 
  protected:
-  ScrollbarAnimationController(ScrollbarAnimationControllerClient* client,
+  ScrollbarAnimationController(LayerImpl* scroll_layer,
+                               ScrollbarAnimationControllerClient* client,
                                base::TimeDelta delay_before_starting,
                                base::TimeDelta resize_delay_before_starting,
                                base::TimeDelta duration);
@@ -48,18 +57,21 @@
   void StartAnimation();
   void StopAnimation();
 
+  LayerImpl* scroll_layer_;
+  ScrollbarAnimationControllerClient* client_;
+
  private:
   // Returns how far through the animation we are as a progress value from
   // 0 to 1.
   float AnimationProgressAtTime(base::TimeTicks now);
 
-  void PostDelayedFade(bool on_resize);
+  void PostDelayedAnimationTask(bool on_resize);
 
-  ScrollbarAnimationControllerClient* client_;
   base::TimeTicks last_awaken_time_;
   base::TimeDelta delay_before_starting_;
   base::TimeDelta resize_delay_before_starting_;
   base::TimeDelta duration_;
+
   bool is_animating_;
 
   bool currently_scrolling_;
diff --git a/cc/animation/scrollbar_animation_controller_linear_fade.cc b/cc/animation/scrollbar_animation_controller_linear_fade.cc
index 1b5dfd9..d1049bd 100644
--- a/cc/animation/scrollbar_animation_controller_linear_fade.cc
+++ b/cc/animation/scrollbar_animation_controller_linear_fade.cc
@@ -17,12 +17,9 @@
     base::TimeDelta delay_before_starting,
     base::TimeDelta resize_delay_before_starting,
     base::TimeDelta duration) {
-  return make_scoped_ptr(
-      new ScrollbarAnimationControllerLinearFade(scroll_layer,
-                                                 client,
-                                                 delay_before_starting,
-                                                 resize_delay_before_starting,
-                                                 duration));
+  return make_scoped_ptr(new ScrollbarAnimationControllerLinearFade(
+      scroll_layer, client, delay_before_starting, resize_delay_before_starting,
+      duration));
 }
 
 ScrollbarAnimationControllerLinearFade::ScrollbarAnimationControllerLinearFade(
@@ -31,18 +28,20 @@
     base::TimeDelta delay_before_starting,
     base::TimeDelta resize_delay_before_starting,
     base::TimeDelta duration)
-    : ScrollbarAnimationController(client,
+    : ScrollbarAnimationController(scroll_layer,
+                                   client,
                                    delay_before_starting,
                                    resize_delay_before_starting,
-                                   duration),
-      scroll_layer_(scroll_layer) {
+                                   duration) {
 }
 
 ScrollbarAnimationControllerLinearFade::
-    ~ScrollbarAnimationControllerLinearFade() {}
+    ~ScrollbarAnimationControllerLinearFade() {
+}
 
 void ScrollbarAnimationControllerLinearFade::RunAnimationFrame(float progress) {
   ApplyOpacityToScrollbars(1.f - progress);
+  client_->SetNeedsRedrawForScrollbarAnimation();
   if (progress == 1.f)
     StopAnimation();
 }
@@ -59,8 +58,7 @@
 
   LayerImpl::ScrollbarSet* scrollbars = scroll_layer_->scrollbars();
   for (LayerImpl::ScrollbarSet::iterator it = scrollbars->begin();
-       it != scrollbars->end();
-       ++it) {
+       it != scrollbars->end(); ++it) {
     ScrollbarLayerImplBase* scrollbar = *it;
 
     if (scrollbar->is_overlay_scrollbar())
diff --git a/cc/animation/scrollbar_animation_controller_linear_fade.h b/cc/animation/scrollbar_animation_controller_linear_fade.h
index 73d6031..05940a0 100644
--- a/cc/animation/scrollbar_animation_controller_linear_fade.h
+++ b/cc/animation/scrollbar_animation_controller_linear_fade.h
@@ -40,8 +40,6 @@
   float OpacityAtTime(base::TimeTicks now) const;
   void ApplyOpacityToScrollbars(float opacity);
 
-  LayerImpl* scroll_layer_;
-
   DISALLOW_COPY_AND_ASSIGN(ScrollbarAnimationControllerLinearFade);
 };
 
diff --git a/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc b/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
index 2295124..f7a5878 100644
--- a/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
+++ b/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
@@ -20,14 +20,24 @@
       public ScrollbarAnimationControllerClient {
  public:
   ScrollbarAnimationControllerLinearFadeTest()
-      : host_impl_(&proxy_, &shared_bitmap_manager_), needs_frame_count_(0) {}
+      : host_impl_(&proxy_, &shared_bitmap_manager_) {}
 
-  void PostDelayedScrollbarFade(const base::Closure& start_fade,
-                                base::TimeDelta delay) override {
+  void StartAnimatingScrollbarAnimationController(
+      ScrollbarAnimationController* controller) override {
+    is_animating_ = true;
+  }
+  void StopAnimatingScrollbarAnimationController(
+      ScrollbarAnimationController* controller) override {
+    is_animating_ = false;
+  }
+  void PostDelayedScrollbarAnimationTask(const base::Closure& start_fade,
+                                         base::TimeDelta delay) override {
     start_fade_ = start_fade;
     delay_ = delay;
   }
-  void SetNeedsScrollbarAnimationFrame() override { needs_frame_count_++; }
+  void SetNeedsRedrawForScrollbarAnimation() override {
+    did_request_redraw_ = true;
+  }
 
  protected:
   void SetUp() override {
@@ -57,11 +67,8 @@
     scroll_layer_ptr->SetBounds(gfx::Size(200, 200));
 
     scrollbar_controller_ = ScrollbarAnimationControllerLinearFade::Create(
-        scroll_layer_ptr,
-        this,
-        base::TimeDelta::FromSeconds(2),
-        base::TimeDelta::FromSeconds(5),
-        base::TimeDelta::FromSeconds(3));
+        scroll_layer_ptr, this, base::TimeDelta::FromSeconds(2),
+        base::TimeDelta::FromSeconds(5), base::TimeDelta::FromSeconds(3));
   }
 
   virtual ScrollbarOrientation orientation() const { return HORIZONTAL; }
@@ -75,7 +82,8 @@
 
   base::Closure start_fade_;
   base::TimeDelta delay_;
-  int needs_frame_count_;
+  bool is_animating_;
+  bool did_request_redraw_;
 };
 
 class VerticalScrollbarAnimationControllerLinearFadeTest
@@ -104,7 +112,6 @@
   scrollbar_layer_->SetOpacity(0.0f);
   scrollbar_controller_->Animate(base::TimeTicks());
   EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->opacity());
-  EXPECT_EQ(0, needs_frame_count_);
 }
 
 TEST_F(ScrollbarAnimationControllerLinearFadeTest,
@@ -123,8 +130,6 @@
   time += base::TimeDelta::FromSeconds(100);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->opacity());
-
-  EXPECT_EQ(0, needs_frame_count_);
 }
 
 TEST_F(ScrollbarAnimationControllerLinearFadeTest, HideOnResize) {
@@ -263,20 +268,24 @@
   EXPECT_TRUE(start_fade_.Equals(base::Closure()));
 
   time += base::TimeDelta::FromSeconds(100);
+
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
   scrollbar_controller_->DidScrollEnd();
   start_fade_.Run();
 
   time += base::TimeDelta::FromSeconds(2);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->opacity());
 
@@ -285,50 +294,60 @@
   scrollbar_controller_->DidScrollBegin();
   scrollbar_controller_->DidScrollUpdate(false);
   scrollbar_controller_->DidScrollEnd();
+
   start_fade_.Run();
 
   time += base::TimeDelta::FromSeconds(2);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->opacity());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->opacity());
-
-  EXPECT_EQ(8, needs_frame_count_);
+  EXPECT_FALSE(is_animating_);
 }
 
 TEST_F(ScrollbarAnimationControllerLinearFadeTest, AwakenByProgrammaticScroll) {
   base::TimeTicks time;
   time += base::TimeDelta::FromSeconds(1);
   scrollbar_controller_->DidScrollUpdate(false);
+
   start_fade_.Run();
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
   scrollbar_controller_->DidScrollUpdate(false);
-  start_fade_.Run();
 
-  time += base::TimeDelta::FromSeconds(1);
+  start_fade_.Run();
+  time += base::TimeDelta::FromSeconds(2);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->opacity());
 
@@ -336,22 +355,25 @@
   scrollbar_controller_->DidScrollUpdate(false);
   start_fade_.Run();
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->opacity());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->opacity());
-
-  EXPECT_EQ(11, needs_frame_count_);
+  EXPECT_FALSE(is_animating_);
 }
 
 TEST_F(ScrollbarAnimationControllerLinearFadeTest,
@@ -360,10 +382,12 @@
   time += base::TimeDelta::FromSeconds(1);
   scrollbar_controller_->DidScrollUpdate(false);
   start_fade_.Run();
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
 
@@ -371,6 +395,7 @@
   EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->opacity());
 
@@ -378,12 +403,10 @@
   EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->opacity());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->opacity());
-
-  scrollbar_controller_->Animate(time);
-
-  EXPECT_EQ(4, needs_frame_count_);
+  EXPECT_FALSE(is_animating_);
 }
 
 TEST_F(ScrollbarAnimationControllerLinearFadeTest,
@@ -392,10 +415,12 @@
   time += base::TimeDelta::FromSeconds(1);
   scrollbar_controller_->DidScrollUpdate(false);
   start_fade_.Run();
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
 
@@ -403,6 +428,7 @@
   EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
 
   time += base::TimeDelta::FromSeconds(1);
+  EXPECT_TRUE(is_animating_);
   scrollbar_controller_->Animate(time);
   EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->opacity());
 
diff --git a/cc/animation/scrollbar_animation_controller_thinning.cc b/cc/animation/scrollbar_animation_controller_thinning.cc
index 0405074..af6987e 100644
--- a/cc/animation/scrollbar_animation_controller_thinning.cc
+++ b/cc/animation/scrollbar_animation_controller_thinning.cc
@@ -7,6 +7,7 @@
 #include "base/time/time.h"
 #include "cc/layers/layer_impl.h"
 #include "cc/layers/scrollbar_layer_impl_base.h"
+#include "cc/trees/layer_tree_impl.h"
 
 namespace {
 const float kIdleThicknessScale = 0.4f;
@@ -23,12 +24,9 @@
     base::TimeDelta delay_before_starting,
     base::TimeDelta resize_delay_before_starting,
     base::TimeDelta duration) {
-  return make_scoped_ptr(
-      new ScrollbarAnimationControllerThinning(scroll_layer,
-                                               client,
-                                               delay_before_starting,
-                                               resize_delay_before_starting,
-                                               duration));
+  return make_scoped_ptr(new ScrollbarAnimationControllerThinning(
+      scroll_layer, client, delay_before_starting, resize_delay_before_starting,
+      duration));
 }
 
 ScrollbarAnimationControllerThinning::ScrollbarAnimationControllerThinning(
@@ -37,11 +35,11 @@
     base::TimeDelta delay_before_starting,
     base::TimeDelta resize_delay_before_starting,
     base::TimeDelta duration)
-    : ScrollbarAnimationController(client,
+    : ScrollbarAnimationController(scroll_layer,
+                                   client,
                                    delay_before_starting,
                                    resize_delay_before_starting,
                                    duration),
-      scroll_layer_(scroll_layer),
       mouse_is_over_scrollbar_(false),
       mouse_is_near_scrollbar_(false),
       thickness_change_(NONE),
@@ -56,9 +54,10 @@
 
 void ScrollbarAnimationControllerThinning::RunAnimationFrame(float progress) {
   float opacity = OpacityAtAnimationProgress(progress);
-  float thumb_thickness_scale = ThumbThicknessScaleAtAnimationProgress(
-      progress);
+  float thumb_thickness_scale =
+      ThumbThicknessScaleAtAnimationProgress(progress);
   ApplyOpacityAndThumbThicknessScale(opacity, thumb_thickness_scale);
+  client_->SetNeedsRedrawForScrollbarAnimation();
   if (progress == 1.f) {
     opacity_change_ = NONE;
     thickness_change_ = NONE;
@@ -77,7 +76,7 @@
 void ScrollbarAnimationControllerThinning::DidScrollUpdate(bool on_resize) {
   ScrollbarAnimationController::DidScrollUpdate(on_resize);
   ApplyOpacityAndThumbThicknessScale(
-    1, mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale);
+      1, mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale);
 
   if (!mouse_is_over_scrollbar_)
     opacity_change_ = DECREASE;
@@ -114,9 +113,8 @@
   return ret;
 }
 
-float
-ScrollbarAnimationControllerThinning::ThumbThicknessScaleAtAnimationProgress(
-    float progress) {
+float ScrollbarAnimationControllerThinning::
+    ThumbThicknessScaleAtAnimationProgress(float progress) {
   if (thickness_change_ == NONE)
     return mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale;
   float factor = thickness_change_ == INCREASE ? progress : (1.f - progress);
@@ -135,14 +133,14 @@
 }
 
 void ScrollbarAnimationControllerThinning::ApplyOpacityAndThumbThicknessScale(
-    float opacity, float thumb_thickness_scale) {
+    float opacity,
+    float thumb_thickness_scale) {
   if (!scroll_layer_->scrollbars())
     return;
 
   LayerImpl::ScrollbarSet* scrollbars = scroll_layer_->scrollbars();
   for (LayerImpl::ScrollbarSet::iterator it = scrollbars->begin();
-       it != scrollbars->end();
-       ++it) {
+       it != scrollbars->end(); ++it) {
     ScrollbarLayerImplBase* scrollbar = *it;
     if (scrollbar->is_overlay_scrollbar()) {
       float effectiveOpacity =
@@ -151,10 +149,9 @@
               : 0;
 
       scrollbar->SetOpacity(effectiveOpacity);
-      scrollbar->SetThumbThicknessScaleFactor(
-          AdjustScale(thumb_thickness_scale,
-                      scrollbar->thumb_thickness_scale_factor(),
-                      thickness_change_));
+      scrollbar->SetThumbThicknessScaleFactor(AdjustScale(
+          thumb_thickness_scale, scrollbar->thumb_thickness_scale_factor(),
+          thickness_change_));
     }
   }
 }
diff --git a/cc/animation/scrollbar_animation_controller_thinning.h b/cc/animation/scrollbar_animation_controller_thinning.h
index 2cf30f5..f22d94c 100644
--- a/cc/animation/scrollbar_animation_controller_thinning.h
+++ b/cc/animation/scrollbar_animation_controller_thinning.h
@@ -62,8 +62,6 @@
   void ApplyOpacityAndThumbThicknessScale(float opacity,
                                           float thumb_thickness_scale);
 
-  LayerImpl* scroll_layer_;
-
   bool mouse_is_over_scrollbar_;
   bool mouse_is_near_scrollbar_;
   // Are we narrowing or thickening the bars.
diff --git a/cc/animation/scrollbar_animation_controller_thinning_unittest.cc b/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
index 04036ba..01763c9 100644
--- a/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
+++ b/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
@@ -22,11 +22,22 @@
   ScrollbarAnimationControllerThinningTest()
       : host_impl_(&proxy_, &shared_bitmap_manager_) {}
 
-  void PostDelayedScrollbarFade(const base::Closure& start_fade,
-                                base::TimeDelta delay) override {
-    start_fade_ = start_fade;
+  void StartAnimatingScrollbarAnimationController(
+      ScrollbarAnimationController* controller) override {
+    is_animating_ = true;
   }
-  void SetNeedsScrollbarAnimationFrame() override {}
+  void StopAnimatingScrollbarAnimationController(
+      ScrollbarAnimationController* controller) override {
+    is_animating_ = false;
+  }
+  void PostDelayedScrollbarAnimationTask(const base::Closure& start_fade,
+                                         base::TimeDelta delay) override {
+    start_fade_ = start_fade;
+    delay_ = delay;
+  }
+  void SetNeedsRedrawForScrollbarAnimation() override {
+    did_request_redraw_ = true;
+  }
 
  protected:
   void SetUp() override {
@@ -57,11 +68,8 @@
     scroll_layer_ptr->SetBounds(gfx::Size(200, 200));
 
     scrollbar_controller_ = ScrollbarAnimationControllerThinning::Create(
-        scroll_layer_ptr,
-        this,
-        base::TimeDelta::FromSeconds(2),
-        base::TimeDelta::FromSeconds(5),
-        base::TimeDelta::FromSeconds(3));
+        scroll_layer_ptr, this, base::TimeDelta::FromSeconds(2),
+        base::TimeDelta::FromSeconds(5), base::TimeDelta::FromSeconds(3));
   }
 
   FakeImplProxy proxy_;
@@ -72,6 +80,9 @@
   scoped_ptr<SolidColorScrollbarLayerImpl> scrollbar_layer_;
 
   base::Closure start_fade_;
+  base::TimeDelta delay_;
+  bool is_animating_;
+  bool did_request_redraw_;
 };
 
 // Check initialization of scrollbar.
diff --git a/cc/base/switches.cc b/cc/base/switches.cc
index c3fad97..504e787 100644
--- a/cc/base/switches.cc
+++ b/cc/base/switches.cc
@@ -58,6 +58,11 @@
 const char kEnablePinchVirtualViewport[] = "enable-pinch-virtual-viewport";
 const char kDisablePinchVirtualViewport[] = "disable-pinch-virtual-viewport";
 
+// Ensures that the draw properties computed via the property trees match those
+// computed by CalcDrawProperties.
+const char kEnablePropertyTreeVerification[] =
+    "enable-property-tree-verification";
+
 // Disable partial swap which is needed for some OpenGL drivers / emulators.
 const char kUIDisablePartialSwap[] = "ui-disable-partial-swap";
 
diff --git a/cc/base/switches.h b/cc/base/switches.h
index 5b7c92e..90caef8 100644
--- a/cc/base/switches.h
+++ b/cc/base/switches.h
@@ -31,6 +31,7 @@
 CC_EXPORT extern const char kEnablePinchVirtualViewport[];
 CC_EXPORT extern const char kDisablePinchVirtualViewport[];
 CC_EXPORT extern const char kStrictLayerPropertyChangeChecking[];
+CC_EXPORT extern const char kEnablePropertyTreeVerification[];
 
 // Switches for both the renderer and ui compositors.
 CC_EXPORT extern const char kUIDisablePartialSwap[];
diff --git a/cc/blink/BUILD.gn b/cc/blink/BUILD.gn
index efbf0f1..9d4007b 100644
--- a/cc/blink/BUILD.gn
+++ b/cc/blink/BUILD.gn
@@ -9,6 +9,7 @@
   output_name = "cc_blink"
 
   sources = [
+    "context_provider_web_context.h",
     "cc_blink_export.h",
     "scrollbar_impl.cc",
     "scrollbar_impl.h",
diff --git a/cc/blink/cc_blink.gyp b/cc/blink/cc_blink.gyp
index 892082c..e9934bf 100644
--- a/cc/blink/cc_blink.gyp
+++ b/cc/blink/cc_blink.gyp
@@ -26,6 +26,7 @@
       # This sources list is duplicated in //cc/blink/BUILD.gn
       'sources': [
         'cc_blink_export.h',
+        'context_provider_web_context.h',
         'scrollbar_impl.cc',
         'scrollbar_impl.h',
         'web_animation_curve_common.cc',
diff --git a/cc/blink/web_display_item_list_impl.cc b/cc/blink/web_display_item_list_impl.cc
index 4941afe..6a4ab90 100644
--- a/cc/blink/web_display_item_list_impl.cc
+++ b/cc/blink/web_display_item_list_impl.cc
@@ -10,14 +10,15 @@
 #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/compositing_display_item.h"
 #include "cc/resources/drawing_display_item.h"
 #include "cc/resources/filter_display_item.h"
 #include "cc/resources/float_clip_display_item.h"
 #include "cc/resources/transform_display_item.h"
-#include "cc/resources/transparency_display_item.h"
 #include "skia/ext/refptr.h"
 #include "third_party/WebKit/public/platform/WebFloatRect.h"
 #include "third_party/WebKit/public/platform/WebRect.h"
+#include "third_party/skia/include/core/SkColorFilter.h"
 #include "third_party/skia/include/core/SkImageFilter.h"
 #include "third_party/skia/include/core/SkPicture.h"
 #include "third_party/skia/include/utils/SkMatrix44.h"
@@ -79,19 +80,29 @@
   display_item_list_->AppendItem(cc::TransformDisplayItem::Create(transform));
 }
 
-void WebDisplayItemListImpl::appendTransparencyItem(
-    float opacity,
-    blink::WebBlendMode blend_mode) {
-  display_item_list_->AppendItem(cc::TransparencyDisplayItem::Create(
-      opacity, BlendModeToSkia(blend_mode)));
-}
-
 void WebDisplayItemListImpl::appendEndTransformItem() {
   display_item_list_->AppendItem(cc::EndTransformDisplayItem::Create());
 }
 
-void WebDisplayItemListImpl::appendEndTransparencyItem() {
-  display_item_list_->AppendItem(cc::EndTransparencyDisplayItem::Create());
+// TODO(pdr): Remove this once the blink-side callers have been removed.
+void WebDisplayItemListImpl::appendCompositingItem(
+    float opacity,
+    SkXfermode::Mode xfermode,
+    SkColorFilter* color_filter) {
+  appendCompositingItem(opacity, xfermode, nullptr, color_filter);
+}
+
+void WebDisplayItemListImpl::appendCompositingItem(
+    float opacity,
+    SkXfermode::Mode xfermode,
+    SkRect* bounds,
+    SkColorFilter* color_filter) {
+  display_item_list_->AppendItem(cc::CompositingDisplayItem::Create(
+      opacity, xfermode, bounds, skia::SharePtr(color_filter)));
+}
+
+void WebDisplayItemListImpl::appendEndCompositingItem() {
+  display_item_list_->AppendItem(cc::EndCompositingDisplayItem::Create());
 }
 
 void WebDisplayItemListImpl::appendFilterItem(
diff --git a/cc/blink/web_display_item_list_impl.h b/cc/blink/web_display_item_list_impl.h
index 8ec7a15..2bb1b90 100644
--- a/cc/blink/web_display_item_list_impl.h
+++ b/cc/blink/web_display_item_list_impl.h
@@ -14,8 +14,10 @@
 #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 "third_party/skia/include/core/SkXfermode.h"
 #include "ui/gfx/geometry/point_f.h"
 
+class SkColorFilter;
 class SkImageFilter;
 class SkMatrix44;
 class SkPath;
@@ -45,9 +47,15 @@
   virtual void appendEndFloatClipItem();
   virtual void appendTransformItem(const SkMatrix44& matrix);
   virtual void appendEndTransformItem();
-  virtual void appendTransparencyItem(float opacity,
-                                      blink::WebBlendMode blend_mode);
-  virtual void appendEndTransparencyItem();
+  // TODO(pdr): Remove this once the blink-side callers have been removed.
+  virtual void appendCompositingItem(float opacity,
+                                     SkXfermode::Mode,
+                                     SkColorFilter*);
+  virtual void appendCompositingItem(float opacity,
+                                     SkXfermode::Mode,
+                                     SkRect* bounds,
+                                     SkColorFilter*);
+  virtual void appendEndCompositingItem();
   virtual void appendFilterItem(const blink::WebFilterOperations& filters,
                                 const blink::WebFloatRect& bounds);
   virtual void appendEndFilterItem();
diff --git a/cc/blink/web_layer_impl.cc b/cc/blink/web_layer_impl.cc
index 0ef5ae7..3c688a6 100644
--- a/cc/blink/web_layer_impl.cc
+++ b/cc/blink/web_layer_impl.cc
@@ -256,7 +256,7 @@
 void WebLayerImpl::removeAnimation(
     int animation_id,
     blink::WebCompositorAnimation::TargetProperty target_property) {
-  layer_->layer_animation_controller()->RemoveAnimation(
+  layer_->RemoveAnimation(
       animation_id, static_cast<Animation::TargetProperty>(target_property));
 }
 
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 84a0930..0c4ee74 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -370,6 +370,8 @@
         'resources/clip_display_item.h',
         'resources/clip_path_display_item.cc',
         'resources/clip_path_display_item.h',
+        'resources/compositing_display_item.cc',
+        'resources/compositing_display_item.h',
         'resources/content_layer_updater.cc',
         'resources/content_layer_updater.h',
         'resources/display_item.cc',
@@ -500,8 +502,6 @@
         'resources/transferable_resource.h',
         'resources/transform_display_item.cc',
         'resources/transform_display_item.h',
-        'resources/transparency_display_item.cc',
-        'resources/transparency_display_item.h',
         'resources/ui_resource_bitmap.cc',
         'resources/ui_resource_bitmap.h',
         'resources/ui_resource_client.h',
diff --git a/cc/input/top_controls_manager.cc b/cc/input/top_controls_manager.cc
index 615afb0..7362805 100644
--- a/cc/input/top_controls_manager.cc
+++ b/cc/input/top_controls_manager.cc
@@ -39,8 +39,8 @@
     : client_(client),
       animation_direction_(NO_ANIMATION),
       permitted_state_(BOTH),
-      current_scroll_delta_(0.f),
-      controls_scroll_begin_offset_(0.f),
+      accumulated_scroll_delta_(0.f),
+      baseline_content_offset_(0.f),
       top_controls_show_threshold_(top_controls_hide_threshold),
       top_controls_hide_threshold_(top_controls_show_threshold),
       pinch_gesture_active_(false) {
@@ -96,8 +96,7 @@
 void TopControlsManager::ScrollBegin() {
   DCHECK(!pinch_gesture_active_);
   ResetAnimations();
-  current_scroll_delta_ = 0.f;
-  controls_scroll_begin_offset_ = ContentTopOffset();
+  ResetBaseline();
 }
 
 gfx::Vector2dF TopControlsManager::ScrollBy(
@@ -110,19 +109,17 @@
   else if (permitted_state_ == HIDDEN && pending_delta.y() < 0)
     return pending_delta;
 
-  current_scroll_delta_ += pending_delta.y();
+  accumulated_scroll_delta_ += pending_delta.y();
 
   float old_offset = ContentTopOffset();
   client_->SetCurrentTopControlsShownRatio(
-      (controls_scroll_begin_offset_ - current_scroll_delta_) /
+      (baseline_content_offset_ - accumulated_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 (TopControlsShownRatio() == 1.f) {
-    current_scroll_delta_ = 0.f;
-    controls_scroll_begin_offset_ = ContentTopOffset();
-  }
+  if (TopControlsShownRatio() == 1.f)
+    ResetBaseline();
 
   ResetAnimations();
 
@@ -149,6 +146,10 @@
   ScrollBegin();
 }
 
+void TopControlsManager::MainThreadHasStoppedFlinging() {
+  StartAnimationIfNecessary();
+}
+
 gfx::Vector2dF TopControlsManager::Animate(base::TimeTicks monotonic_time) {
   if (!top_controls_animation_ || !client_->HaveRootScrollLayer())
     return gfx::Vector2dF();
@@ -206,8 +207,8 @@
     // 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);
+    SetupAnimation(accumulated_scroll_delta_ <= 0.f ? SHOWING_CONTROLS
+                                                    : HIDING_CONTROLS);
   }
 }
 
@@ -225,4 +226,9 @@
   return false;
 }
 
+void TopControlsManager::ResetBaseline() {
+  accumulated_scroll_delta_ = 0.f;
+  baseline_content_offset_ = ContentTopOffset();
+}
+
 }  // namespace cc
diff --git a/cc/input/top_controls_manager.h b/cc/input/top_controls_manager.h
index 06f623d..fc40378 100644
--- a/cc/input/top_controls_manager.h
+++ b/cc/input/top_controls_manager.h
@@ -61,6 +61,8 @@
   void PinchBegin();
   void PinchEnd();
 
+  void MainThreadHasStoppedFlinging();
+
   gfx::Vector2dF Animate(base::TimeTicks monotonic_time);
 
  protected:
@@ -73,6 +75,7 @@
   void SetupAnimation(AnimationDirection direction);
   void StartAnimationIfNecessary();
   bool IsAnimationCompleteAtTime(base::TimeTicks time);
+  void ResetBaseline();
 
   TopControlsManagerClient* client_;  // The client manages the lifecycle of
                                       // this.
@@ -81,8 +84,11 @@
   AnimationDirection animation_direction_;
   TopControlsState permitted_state_;
 
-  float current_scroll_delta_;
-  float controls_scroll_begin_offset_;
+  // Accumulated scroll delta since last baseline reset
+  float accumulated_scroll_delta_;
+
+  // Content offset when last baseline reset occurred
+  float baseline_content_offset_;
 
   // The percent height of the visible top control such that it must be shown
   // when the user stops the scroll.
diff --git a/cc/layers/draw_properties.h b/cc/layers/draw_properties.h
index 7cf89e7..ff5abd9 100644
--- a/cc/layers/draw_properties.h
+++ b/cc/layers/draw_properties.h
@@ -34,6 +34,7 @@
         layer_or_descendant_has_input_handler(false),
         has_child_with_a_scroll_parent(false),
         sorted_for_recursion(false),
+        visited(false),
         index_of_first_descendants_addition(0),
         num_descendants_added(0),
         index_of_first_render_surface_layer_list_addition(0),
@@ -123,6 +124,9 @@
   // layer will be visited while computing draw properties has been determined.
   bool sorted_for_recursion;
 
+  // This is used to sanity-check CDP and ensure that we don't revisit a layer.
+  bool visited;
+
   // If this layer is visited out of order, its contribution to the descendant
   // and render surface layer lists will be put aside in a temporary list.
   // These values will allow for an efficient reordering of these additions.
diff --git a/cc/layers/heads_up_display_layer_impl.cc b/cc/layers/heads_up_display_layer_impl.cc
index 19217c9..2ed00a6 100644
--- a/cc/layers/heads_up_display_layer_impl.cc
+++ b/cc/layers/heads_up_display_layer_impl.cc
@@ -70,6 +70,8 @@
 HeadsUpDisplayLayerImpl::HeadsUpDisplayLayerImpl(LayerTreeImpl* tree_impl,
                                                  int id)
     : LayerImpl(tree_impl, id),
+      typeface_(skia::AdoptRef(
+          SkTypeface::CreateFromName("monospace", SkTypeface::kBold))),
       internal_contents_scale_(1.f),
       fps_graph_(60.0, 80.0),
       paint_time_graph_(16.0, 48.0),
@@ -303,7 +305,7 @@
 
   paint->setTextSize(size);
   paint->setTextAlign(align);
-  paint->setTypeface(layer_tree_impl()->settings().hud_typeface.get());
+  paint->setTypeface(typeface_.get());
   canvas->drawText(text.c_str(), text.length(), x, y, *paint);
 
   paint->setAntiAlias(anti_alias);
@@ -710,7 +712,7 @@
 
     SkPaint label_paint = CreatePaint();
     label_paint.setTextSize(kFontHeight);
-    label_paint.setTypeface(layer_tree_impl()->settings().hud_typeface.get());
+    label_paint.setTypeface(typeface_.get());
     label_paint.setColor(stroke_color);
 
     const SkScalar label_text_width =
diff --git a/cc/layers/heads_up_display_layer_impl.h b/cc/layers/heads_up_display_layer_impl.h
index 5c3720e..54bf153 100644
--- a/cc/layers/heads_up_display_layer_impl.h
+++ b/cc/layers/heads_up_display_layer_impl.h
@@ -127,6 +127,8 @@
   ScopedPtrVector<ScopedResource> resources_;
   skia::RefPtr<SkSurface> hud_surface_;
 
+  skia::RefPtr<SkTypeface> typeface_;
+
   float internal_contents_scale_;
   gfx::Size internal_content_bounds_;
 
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index ca0e3b8..bf2f26a 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -1204,6 +1204,12 @@
   SetNeedsCommit();
 }
 
+void Layer::RemoveAnimation(int animation_id,
+                            Animation::TargetProperty property) {
+  layer_animation_controller_->RemoveAnimation(animation_id, property);
+  SetNeedsCommit();
+}
+
 void Layer::SetLayerAnimationControllerForTest(
     scoped_refptr<LayerAnimationController> controller) {
   layer_animation_controller_->RemoveValueObserver(this);
@@ -1318,6 +1324,24 @@
   return xform;
 }
 
+float Layer::DrawOpacityFromPropertyTrees(const OpacityTree& tree) const {
+  if (!render_target())
+    return 0.f;
+
+  const OpacityNode* target_node =
+      tree.Node(render_target()->opacity_tree_index());
+  const OpacityNode* node = tree.Node(opacity_tree_index());
+  if (node == target_node)
+    return 1.f;
+
+  float draw_opacity = 1.f;
+  while (node != target_node) {
+    draw_opacity *= node->data;
+    node = tree.parent(node);
+  }
+  return draw_opacity;
+}
+
 void Layer::SetFrameTimingRequests(
     const std::vector<FrameTimingRequest>& requests) {
   frame_timing_requests_ = requests;
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 8eb7c3d..a82da24 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -410,6 +410,7 @@
   bool AddAnimation(scoped_ptr<Animation> animation);
   void PauseAnimation(int animation_id, double time_offset);
   void RemoveAnimation(int animation_id);
+  void RemoveAnimation(int animation_id, Animation::TargetProperty property);
 
   LayerAnimationController* layer_animation_controller() {
     return layer_animation_controller_.get();
@@ -472,8 +473,10 @@
 
   void set_transform_tree_index(int index) { transform_tree_index_ = index; }
   void set_clip_tree_index(int index) { clip_tree_index_ = index; }
+  void set_opacity_tree_index(int index) { opacity_tree_index_ = index; }
   int clip_tree_index() const { return clip_tree_index_; }
   int transform_tree_index() const { return transform_tree_index_; }
+  int opacity_tree_index() const { return opacity_tree_index_; }
 
   void set_offset_to_transform_parent(gfx::Vector2dF offset) {
     offset_to_transform_parent_ = offset;
@@ -499,6 +502,7 @@
       const TransformTree& tree) const;
   gfx::Transform draw_transform_from_property_trees(
       const TransformTree& tree) const;
+  float DrawOpacityFromPropertyTrees(const OpacityTree& tree) const;
 
   // TODO(vollick): These values are temporary and will be removed as soon as
   // render surface determinations are moved out of CDP. They only exist because
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 63fd4dc..0c6ddf5 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -83,7 +83,7 @@
   DCHECK_GT(layer_id_, 0);
   DCHECK(layer_tree_impl_);
   layer_tree_impl_->RegisterLayer(this);
-  AnimationRegistrar* registrar = layer_tree_impl_->animationRegistrar();
+  AnimationRegistrar* registrar = layer_tree_impl_->GetAnimationRegistrar();
   layer_animation_controller_ =
       registrar->GetAnimationControllerForId(layer_id_);
   layer_animation_controller_->AddValueObserver(this);
diff --git a/cc/resources/compositing_display_item.cc b/cc/resources/compositing_display_item.cc
new file mode 100644
index 0000000..c33d4ca
--- /dev/null
+++ b/cc/resources/compositing_display_item.cc
@@ -0,0 +1,93 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/resources/compositing_display_item.h"
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkXfermode.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+
+CompositingDisplayItem::CompositingDisplayItem(float opacity,
+                                               SkXfermode::Mode xfermode,
+                                               SkRect* bounds,
+                                               skia::RefPtr<SkColorFilter> cf)
+    : opacity_(opacity),
+      xfermode_(xfermode),
+      has_bounds_(!!bounds),
+      color_filter_(cf) {
+  if (bounds)
+    bounds_ = SkRect(*bounds);
+}
+
+CompositingDisplayItem::~CompositingDisplayItem() {
+}
+
+void CompositingDisplayItem::Raster(SkCanvas* canvas,
+                                    SkDrawPictureCallback* callback) const {
+  SkPaint paint;
+  paint.setXfermodeMode(xfermode_);
+  paint.setAlpha(opacity_ * 255);
+  paint.setColorFilter(color_filter_.get());
+  canvas->saveLayer(has_bounds_ ? &bounds_ : nullptr, &paint);
+}
+
+bool CompositingDisplayItem::IsSuitableForGpuRasterization() const {
+  return true;
+}
+
+int CompositingDisplayItem::ApproximateOpCount() const {
+  return 1;
+}
+
+size_t CompositingDisplayItem::PictureMemoryUsage() const {
+  // TODO(pdr): Include color_filter's memory here.
+  return sizeof(float) + sizeof(bool) + sizeof(SkRect) +
+         sizeof(SkXfermode::Mode);
+}
+
+void CompositingDisplayItem::AsValueInto(
+    base::trace_event::TracedValue* array) const {
+  array->AppendString(base::StringPrintf(
+      "CompositingDisplayItem opacity: %f, xfermode: %d", opacity_, xfermode_));
+  if (has_bounds_)
+    array->AppendString(base::StringPrintf(
+        ", bounds: [%f, %f, %f, %f]", static_cast<float>(bounds_.x()),
+        static_cast<float>(bounds_.y()), static_cast<float>(bounds_.width()),
+        static_cast<float>(bounds_.height())));
+}
+
+EndCompositingDisplayItem::EndCompositingDisplayItem() {
+}
+
+EndCompositingDisplayItem::~EndCompositingDisplayItem() {
+}
+
+void EndCompositingDisplayItem::Raster(SkCanvas* canvas,
+                                       SkDrawPictureCallback* callback) const {
+  canvas->restore();
+}
+
+bool EndCompositingDisplayItem::IsSuitableForGpuRasterization() const {
+  return true;
+}
+
+int EndCompositingDisplayItem::ApproximateOpCount() const {
+  return 0;
+}
+
+size_t EndCompositingDisplayItem::PictureMemoryUsage() const {
+  return 0;
+}
+
+void EndCompositingDisplayItem::AsValueInto(
+    base::trace_event::TracedValue* array) const {
+  array->AppendString("EndCompositingDisplayItem");
+}
+
+}  // namespace cc
diff --git a/cc/resources/compositing_display_item.h b/cc/resources/compositing_display_item.h
new file mode 100644
index 0000000..fd42a37
--- /dev/null
+++ b/cc/resources/compositing_display_item.h
@@ -0,0 +1,77 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_RESOURCES_COMPOSITING_DISPLAY_ITEM_H_
+#define CC_RESOURCES_COMPOSITING_DISPLAY_ITEM_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/resources/display_item.h"
+#include "skia/ext/refptr.h"
+#include "third_party/skia/include/core/SkColorFilter.h"
+#include "third_party/skia/include/core/SkRect.h"
+#include "third_party/skia/include/core/SkXfermode.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+class SkCanvas;
+class SkDrawPictureCallback;
+
+namespace cc {
+
+class CC_EXPORT CompositingDisplayItem : public DisplayItem {
+ public:
+  ~CompositingDisplayItem() override;
+
+  static scoped_ptr<CompositingDisplayItem> Create(
+      float opacity,
+      SkXfermode::Mode xfermode,
+      SkRect* bounds,
+      skia::RefPtr<SkColorFilter> color_filter) {
+    return make_scoped_ptr(
+        new CompositingDisplayItem(opacity, xfermode, bounds, color_filter));
+  }
+
+  void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+  bool IsSuitableForGpuRasterization() const override;
+  int ApproximateOpCount() const override;
+  size_t PictureMemoryUsage() const override;
+  void AsValueInto(base::trace_event::TracedValue* array) const override;
+
+ protected:
+  CompositingDisplayItem(float opacity,
+                         SkXfermode::Mode,
+                         SkRect* bounds,
+                         skia::RefPtr<SkColorFilter>);
+
+ private:
+  float opacity_;
+  SkXfermode::Mode xfermode_;
+  bool has_bounds_;
+  SkRect bounds_;
+  skia::RefPtr<SkColorFilter> color_filter_;
+};
+
+class CC_EXPORT EndCompositingDisplayItem : public DisplayItem {
+ public:
+  ~EndCompositingDisplayItem() override;
+
+  static scoped_ptr<EndCompositingDisplayItem> Create() {
+    return make_scoped_ptr(new EndCompositingDisplayItem());
+  }
+
+  void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
+
+  bool IsSuitableForGpuRasterization() const override;
+  int ApproximateOpCount() const override;
+  size_t PictureMemoryUsage() const override;
+  void AsValueInto(base::trace_event::TracedValue* array) const override;
+
+ protected:
+  EndCompositingDisplayItem();
+};
+
+}  // namespace cc
+
+#endif  // CC_RESOURCES_COMPOSITING_DISPLAY_ITEM_H_
diff --git a/cc/resources/one_copy_tile_task_worker_pool.cc b/cc/resources/one_copy_tile_task_worker_pool.cc
index e6a367a..1139fbe 100644
--- a/cc/resources/one_copy_tile_task_worker_pool.cc
+++ b/cc/resources/one_copy_tile_task_worker_pool.cc
@@ -78,7 +78,7 @@
 const int kCopyFlushPeriod = 4;
 
 // Number of in-flight copy operations to allow.
-const int kMaxCopyOperations = 16;
+const int kMaxCopyOperations = 32;
 
 // Delay been checking for copy operations to complete.
 const int kCheckForCompletedCopyOperationsTickRateMs = 1;
diff --git a/cc/resources/transparency_display_item.cc b/cc/resources/transparency_display_item.cc
deleted file mode 100644
index 1c37b73..0000000
--- a/cc/resources/transparency_display_item.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/resources/transparency_display_item.h"
-
-#include "base/strings/stringprintf.h"
-#include "base/trace_event/trace_event_argument.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkPaint.h"
-#include "third_party/skia/include/core/SkXfermode.h"
-#include "ui/gfx/skia_util.h"
-
-namespace cc {
-
-TransparencyDisplayItem::TransparencyDisplayItem(float opacity,
-                                                 SkXfermode::Mode blend_mode)
-    : opacity_(opacity), blend_mode_(blend_mode) {
-}
-
-TransparencyDisplayItem::~TransparencyDisplayItem() {
-}
-
-void TransparencyDisplayItem::Raster(SkCanvas* canvas,
-                                     SkDrawPictureCallback* callback) const {
-  SkPaint paint;
-  paint.setXfermodeMode(blend_mode_);
-  paint.setAlpha(opacity_ * 255);
-  canvas->saveLayer(NULL, &paint);
-}
-
-bool TransparencyDisplayItem::IsSuitableForGpuRasterization() const {
-  return true;
-}
-
-int TransparencyDisplayItem::ApproximateOpCount() const {
-  return 1;
-}
-
-size_t TransparencyDisplayItem::PictureMemoryUsage() const {
-  return sizeof(float) + sizeof(SkXfermode::Mode);
-}
-
-void TransparencyDisplayItem::AsValueInto(
-    base::trace_event::TracedValue* array) const {
-  array->AppendString(
-      base::StringPrintf("TransparencyDisplayItem opacity: %f, blend_mode: %d",
-                         opacity_, blend_mode_));
-}
-
-EndTransparencyDisplayItem::EndTransparencyDisplayItem() {
-}
-
-EndTransparencyDisplayItem::~EndTransparencyDisplayItem() {
-}
-
-void EndTransparencyDisplayItem::Raster(SkCanvas* canvas,
-                                        SkDrawPictureCallback* callback) const {
-  canvas->restore();
-}
-
-bool EndTransparencyDisplayItem::IsSuitableForGpuRasterization() const {
-  return true;
-}
-
-int EndTransparencyDisplayItem::ApproximateOpCount() const {
-  return 0;
-}
-
-size_t EndTransparencyDisplayItem::PictureMemoryUsage() const {
-  return 0;
-}
-
-void EndTransparencyDisplayItem::AsValueInto(
-    base::trace_event::TracedValue* array) const {
-  array->AppendString("EndTransparencyDisplayItem");
-}
-
-}  // namespace cc
diff --git a/cc/resources/transparency_display_item.h b/cc/resources/transparency_display_item.h
deleted file mode 100644
index d7ae7be..0000000
--- a/cc/resources/transparency_display_item.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_RESOURCES_TRANSPARENCY_DISPLAY_ITEM_H_
-#define CC_RESOURCES_TRANSPARENCY_DISPLAY_ITEM_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "cc/base/cc_export.h"
-#include "cc/resources/display_item.h"
-#include "skia/ext/refptr.h"
-#include "third_party/skia/include/core/SkXfermode.h"
-#include "ui/gfx/geometry/rect_f.h"
-
-class SkCanvas;
-class SkDrawPictureCallback;
-
-namespace cc {
-
-class CC_EXPORT TransparencyDisplayItem : public DisplayItem {
- public:
-  ~TransparencyDisplayItem() override;
-
-  static scoped_ptr<TransparencyDisplayItem> Create(
-      float opacity,
-      SkXfermode::Mode blend_mode) {
-    return make_scoped_ptr(new TransparencyDisplayItem(opacity, blend_mode));
-  }
-
-  void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
-
-  bool IsSuitableForGpuRasterization() const override;
-  int ApproximateOpCount() const override;
-  size_t PictureMemoryUsage() const override;
-  void AsValueInto(base::trace_event::TracedValue* array) const override;
-
- protected:
-  TransparencyDisplayItem(float opacity, SkXfermode::Mode blend_mode);
-
- private:
-  float opacity_;
-  SkXfermode::Mode blend_mode_;
-};
-
-class CC_EXPORT EndTransparencyDisplayItem : public DisplayItem {
- public:
-  ~EndTransparencyDisplayItem() override;
-
-  static scoped_ptr<EndTransparencyDisplayItem> Create() {
-    return make_scoped_ptr(new EndTransparencyDisplayItem());
-  }
-
-  void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
-
-  bool IsSuitableForGpuRasterization() const override;
-  int ApproximateOpCount() const override;
-  size_t PictureMemoryUsage() const override;
-  void AsValueInto(base::trace_event::TracedValue* array) const override;
-
- protected:
-  EndTransparencyDisplayItem();
-};
-
-}  // namespace cc
-
-#endif  // CC_RESOURCES_TRANSPARENCY_DISPLAY_ITEM_H_
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
index 1b089df..ed57e6f 100644
--- a/cc/resources/video_resource_updater.cc
+++ b/cc/resources/video_resource_updater.cc
@@ -14,7 +14,7 @@
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "media/base/video_frame.h"
-#include "media/filters/skcanvas_video_renderer.h"
+#include "media/blink/skcanvas_video_renderer.h"
 #include "third_party/khronos/GLES2/gl2.h"
 #include "third_party/khronos/GLES2/gl2ext.h"
 #include "ui/gfx/geometry/size_conversions.h"
diff --git a/cc/surfaces/surface_display_output_surface.cc b/cc/surfaces/surface_display_output_surface.cc
index b99e2b4..88e166c 100644
--- a/cc/surfaces/surface_display_output_surface.cc
+++ b/cc/surfaces/surface_display_output_surface.cc
@@ -46,7 +46,7 @@
 void SurfaceDisplayOutputSurface::SwapBuffers(CompositorFrame* frame) {
   gfx::Size frame_size =
       frame->delegated_frame_data->render_pass_list.back()->output_rect.size();
-  if (frame_size != display_size_) {
+  if (frame_size.IsEmpty() || frame_size != display_size_) {
     if (!surface_id_.is_null()) {
       factory_.Destroy(surface_id_);
     }
diff --git a/cc/test/fake_layer_tree_host_impl_client.h b/cc/test/fake_layer_tree_host_impl_client.h
index d7a785b..63d7f43 100644
--- a/cc/test/fake_layer_tree_host_impl_client.h
+++ b/cc/test/fake_layer_tree_host_impl_client.h
@@ -35,7 +35,7 @@
                                                int priority_cutoff) override;
   bool IsInsideDraw() override;
   void RenewTreePriority() override {}
-  void PostDelayedScrollbarFadeOnImplThread(const base::Closure& start_fade,
+  void PostDelayedAnimationTaskOnImplThread(const base::Closure& task,
                                             base::TimeDelta delay) override {}
   void DidActivateSyncTree() override {}
   void DidPrepareTiles() override {}
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 129a27d..9690362 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -349,10 +349,9 @@
   void UpdateAnimationState(bool start_ready_animations) override {
     LayerTreeHostImpl::UpdateAnimationState(start_ready_animations);
     bool has_unfinished_animation = false;
-    AnimationRegistrar::AnimationControllerMap::const_iterator iter =
-        active_animation_controllers().begin();
-    for (; iter != active_animation_controllers().end(); ++iter) {
-      if (iter->second->HasActiveAnimation()) {
+    for (const auto& it :
+         animation_registrar()->active_animation_controllers()) {
+      if (it.second->HasActiveAnimation()) {
         has_unfinished_animation = true;
         break;
       }
diff --git a/cc/test/test_gpu_memory_buffer_manager.cc b/cc/test/test_gpu_memory_buffer_manager.cc
index 196922f..7430051 100644
--- a/cc/test/test_gpu_memory_buffer_manager.cc
+++ b/cc/test/test_gpu_memory_buffer_manager.cc
@@ -12,6 +12,14 @@
 
 size_t StrideInBytes(size_t width, gfx::GpuMemoryBuffer::Format format) {
   switch (format) {
+    case gfx::GpuMemoryBuffer::ATCIA:
+    case gfx::GpuMemoryBuffer::DXT5:
+      return width;
+    case gfx::GpuMemoryBuffer::ATC:
+    case gfx::GpuMemoryBuffer::DXT1:
+    case gfx::GpuMemoryBuffer::ETC1:
+      DCHECK_EQ(width % 2, 0U);
+      return width / 2;
     case gfx::GpuMemoryBuffer::RGBA_8888:
     case gfx::GpuMemoryBuffer::RGBX_8888:
     case gfx::GpuMemoryBuffer::BGRA_8888:
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc
index c9ead98..1e6d2c7 100644
--- a/cc/trees/draw_property_utils.cc
+++ b/cc/trees/draw_property_utils.cc
@@ -157,11 +157,14 @@
                                     const TransformTree& tree,
                                     bool subtree_is_visible_from_ancestor,
                                     std::vector<Layer*>* layers_to_update) {
-  const bool subtree_is_invisble =
-      layer->opacity() == 0.0f ||
+  const bool layer_is_invisible =
+      (!layer->opacity() && !layer->OpacityIsAnimating() &&
+       !layer->OpacityCanAnimateOnImplThread());
+  const bool layer_is_backfacing =
       (layer->has_render_surface() && !layer->double_sided() &&
        IsSurfaceBackFaceExposed(layer, tree));
 
+  const bool subtree_is_invisble = layer_is_invisible || layer_is_backfacing;
   if (subtree_is_invisble)
     return;
 
@@ -262,10 +265,11 @@
     const gfx::Rect& viewport,
     const gfx::Transform& device_transform,
     TransformTree* transform_tree,
-    ClipTree* clip_tree) {
+    ClipTree* clip_tree,
+    OpacityTree* opacity_tree) {
   PropertyTreeBuilder::BuildPropertyTrees(
       root_layer, page_scale_layer, page_scale_factor, device_scale_factor,
-      viewport, device_transform, transform_tree, clip_tree);
+      viewport, device_transform, transform_tree, clip_tree, opacity_tree);
   ComputeTransforms(transform_tree);
   ComputeClips(clip_tree, *transform_tree);
 
diff --git a/cc/trees/draw_property_utils.h b/cc/trees/draw_property_utils.h
index 6da912b..78c3c53 100644
--- a/cc/trees/draw_property_utils.h
+++ b/cc/trees/draw_property_utils.h
@@ -16,6 +16,7 @@
 
 class ClipTree;
 class Layer;
+class OpacityTree;
 class TransformTree;
 
 // Computes combined clips for every node in |clip_tree|. This function requires
@@ -40,7 +41,8 @@
                                       const gfx::Rect& viewport,
                                       const gfx::Transform& device_transform,
                                       TransformTree* transform_tree,
-                                      ClipTree* clip_tree);
+                                      ClipTree* clip_tree,
+                                      OpacityTree* opacity_tree);
 
 }  // namespace cc
 
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 49e374d..abc63fc 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -558,8 +558,7 @@
     // controllers may still receive events for impl-only animations.
     const AnimationRegistrar::AnimationControllerMap& animation_controllers =
         animation_registrar_->all_animation_controllers();
-    AnimationRegistrar::AnimationControllerMap::const_iterator iter =
-        animation_controllers.find(event_layer_id);
+    auto iter = animation_controllers.find(event_layer_id);
     if (iter != animation_controllers.end()) {
       switch ((*events)[event_index].type) {
         case AnimationEvent::STARTED:
@@ -668,19 +667,13 @@
   SetNeedsCommit();
 }
 
-void LayerTreeHost::SetTopControlsShrinkBlinkSize(bool shrink) {
-  if (top_controls_shrink_blink_size_ == shrink)
-    return;
-
-  top_controls_shrink_blink_size_ = shrink;
-  SetNeedsCommit();
-}
-
-void LayerTreeHost::SetTopControlsHeight(float height) {
-  if (top_controls_height_ == height)
+void LayerTreeHost::SetTopControlsHeight(float height, bool shrink) {
+  if (top_controls_height_ == height &&
+      top_controls_shrink_blink_size_ == shrink)
     return;
 
   top_controls_height_ = height;
+  top_controls_shrink_blink_size_ = shrink;
   SetNeedsCommit();
 }
 
@@ -1200,14 +1193,12 @@
 
   TRACE_EVENT0("cc", "LayerTreeHost::AnimateLayers");
 
-  AnimationRegistrar::AnimationControllerMap copy =
+  AnimationRegistrar::AnimationControllerMap active_controllers_copy =
       animation_registrar_->active_animation_controllers();
-  for (AnimationRegistrar::AnimationControllerMap::iterator iter = copy.begin();
-       iter != copy.end();
-       ++iter) {
-    (*iter).second->Animate(monotonic_time);
+  for (auto& it : active_controllers_copy) {
+    it.second->Animate(monotonic_time);
     bool start_ready_animations = true;
-    (*iter).second->UpdateState(start_ready_animations, NULL);
+    it.second->UpdateState(start_ready_animations, NULL);
   }
 }
 
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index d41e73d..e677f89 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -211,8 +211,7 @@
   GpuRasterizationStatus GetGpuRasterizationStatus() const;
 
   void SetViewportSize(const gfx::Size& device_viewport_size);
-  void SetTopControlsShrinkBlinkSize(bool shrink);
-  void SetTopControlsHeight(float height);
+  void SetTopControlsHeight(float height, bool shrink);
   void SetTopControlsShownRatio(float ratio);
 
   gfx::Size device_viewport_size() const { return device_viewport_size_; }
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 7a3b5ad..a84cae6 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -31,7 +31,7 @@
 
 ScrollAndScaleSet::~ScrollAndScaleSet() {}
 
-static void SortLayers(LayerList::iterator forst,
+static void SortLayers(LayerList::iterator first,
                        LayerList::iterator end,
                        void* layer_sorter) {
   NOTREACHED();
@@ -337,7 +337,8 @@
 template <typename LayerType>
 static inline bool LayerIsInExisting3DRenderingContext(LayerType* layer) {
   return layer->Is3dSorted() && layer->parent() &&
-         layer->parent()->Is3dSorted();
+         layer->parent()->Is3dSorted() &&
+         (layer->parent()->sorting_context_id() == layer->sorting_context_id());
 }
 
 template <typename LayerType>
@@ -590,6 +591,13 @@
     return true;
   }
 
+  // If the layer will use a CSS filter.  In this case, the animation
+  // will start and add a filter to this layer, so it needs a surface.
+  if (layer->FilterIsAnimating()) {
+    DCHECK(!is_root);
+    return true;
+  }
+
   int num_descendants_that_draw_content =
       layer->NumDescendantsThatDrawContent();
 
@@ -1197,20 +1205,22 @@
   }
 };
 
-static bool ValidateRenderSurface(LayerImpl* layer) {
+static void ValidateRenderSurface(LayerImpl* layer) {
   // This test verifies that there are no cases where a LayerImpl needs
   // a render surface, but doesn't have one.
   if (layer->render_surface())
-    return true;
+    return;
 
-  return layer->filters().IsEmpty() && layer->background_filters().IsEmpty() &&
-         !layer->mask_layer() && !layer->replica_layer() &&
-         !IsRootLayer(layer) && !layer->is_root_for_isolated_group() &&
-         !layer->HasCopyRequest();
+  DCHECK(layer->filters().IsEmpty()) << "layer: " << layer->id();
+  DCHECK(layer->background_filters().IsEmpty()) << "layer: " << layer->id();
+  DCHECK(!layer->mask_layer()) << "layer: " << layer->id();
+  DCHECK(!layer->replica_layer()) << "layer: " << layer->id();
+  DCHECK(!IsRootLayer(layer)) << "layer: " << layer->id();
+  DCHECK(!layer->is_root_for_isolated_group()) << "layer: " << layer->id();
+  DCHECK(!layer->HasCopyRequest()) << "layer: " << layer->id();
 }
 
-static bool ValidateRenderSurface(Layer* layer) {
-  return true;
+static void ValidateRenderSurface(Layer* layer) {
 }
 
 // Recursively walks the layer tree to compute any information that is needed
@@ -1219,10 +1229,11 @@
 static void PreCalculateMetaInformation(
     LayerType* layer,
     PreCalculateMetaInformationRecursiveData* recursive_data) {
-  DCHECK(ValidateRenderSurface(layer));
+  ValidateRenderSurface(layer);
 
   layer->draw_properties().sorted_for_recursion = false;
   layer->draw_properties().has_child_with_a_scroll_parent = false;
+  layer->draw_properties().visited = false;
 
   if (!HasInvertibleOrAnimatedTransform(layer)) {
     // Layers with singular transforms should not be drawn, the whole subtree
@@ -1590,6 +1601,9 @@
   DCHECK(globals.page_scale_application_layer ||
          (globals.page_scale_factor == 1.f));
 
+  CHECK(!layer->draw_properties().visited);
+  layer->draw_properties().visited = true;
+
   DataForRecursion<LayerType> data_for_children;
   typename LayerType::RenderSurfaceType*
       nearest_occlusion_immune_ancestor_surface =
@@ -2501,13 +2515,9 @@
   PreCalculateMetaInformation(inputs->root_layer, &recursive_data);
   std::vector<AccumulatedSurfaceState<Layer>> accumulated_surface_state;
   CalculateDrawPropertiesInternal<Layer>(
-      inputs->root_layer,
-      globals,
-      data_for_recursion,
-      inputs->render_surface_layer_list,
-      &dummy_layer_list,
-      &accumulated_surface_state,
-      inputs->current_render_surface_layer_list_id);
+      inputs->root_layer, globals, data_for_recursion,
+      inputs->render_surface_layer_list, &dummy_layer_list,
+      &accumulated_surface_state, inputs->current_render_surface_layer_list_id);
 
   // The dummy layer list should not have been used.
   DCHECK_EQ(0u, dummy_layer_list.size());
@@ -2520,11 +2530,12 @@
     // will eventually get these data passed directly to the compositor.
     TransformTree transform_tree;
     ClipTree clip_tree;
+    OpacityTree opacity_tree;
     ComputeVisibleRectsUsingPropertyTrees(
         inputs->root_layer, inputs->page_scale_application_layer,
         inputs->page_scale_factor, inputs->device_scale_factor,
         gfx::Rect(inputs->device_viewport_size), inputs->device_transform,
-        &transform_tree, &clip_tree);
+        &transform_tree, &clip_tree, &opacity_tree);
 
     LayerIterator<Layer> it, end;
     for (it = LayerIterator<Layer>::Begin(inputs->render_surface_layer_list),
@@ -2543,6 +2554,11 @@
           current_layer->draw_transform(),
           current_layer->draw_transform_from_property_trees(transform_tree));
       CHECK(draw_transforms_match);
+
+      const bool draw_opacities_match =
+          current_layer->draw_opacity() ==
+          current_layer->DrawOpacityFromPropertyTrees(opacity_tree);
+      CHECK(draw_opacities_match);
     }
   }
 }
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index 30cc15a..6f05035 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -2975,6 +2975,78 @@
   EXPECT_FALSE(child->draw_properties().sorted_for_recursion);
 }
 
+TEST_F(LayerTreeHostCommonTest, WillSortAtContextBoundary) {
+  // Creates a layer tree that looks as follows:
+  // * root (sorting-context-id1)
+  //   * parent (sorting-context-id2)
+  //     * child1 (sorting-context-id2)
+  //     * child2 (sorting-context-id2)
+  //
+  // This test ensures that we sort at |parent| even though both it and root are
+  // set to be 3d sorted.
+  FakeImplProxy proxy;
+  TestSharedBitmapManager shared_bitmap_manager;
+  FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+
+  scoped_ptr<LayerImpl> root_ptr(LayerImpl::Create(host_impl.active_tree(), 1));
+  LayerImpl* root = root_ptr.get();
+  scoped_ptr<LayerImpl> parent_ptr(
+      LayerImpl::Create(host_impl.active_tree(), 2));
+  LayerImpl* parent = parent_ptr.get();
+  scoped_ptr<LayerImpl> child1_ptr(
+      LayerImpl::Create(host_impl.active_tree(), 3));
+  LayerImpl* child1 = child1_ptr.get();
+  scoped_ptr<LayerImpl> child2_ptr(
+      LayerImpl::Create(host_impl.active_tree(), 4));
+  LayerImpl* child2 = child2_ptr.get();
+
+  gfx::Transform identity_matrix;
+  gfx::Transform below_matrix;
+  below_matrix.Translate3d(0.f, 0.f, -10.f);
+  gfx::Transform above_matrix;
+  above_matrix.Translate3d(0.f, 0.f, 10.f);
+
+  SetLayerPropertiesForTesting(root, identity_matrix, gfx::Point3F(),
+                               gfx::PointF(), gfx::Size(100, 100), true, true,
+                               true);
+  SetLayerPropertiesForTesting(parent, identity_matrix, gfx::Point3F(),
+                               gfx::PointF(), gfx::Size(50, 50), true, true,
+                               true);
+  SetLayerPropertiesForTesting(child1, above_matrix, gfx::Point3F(),
+                               gfx::PointF(), gfx::Size(50, 50), true, true,
+                               false);
+  SetLayerPropertiesForTesting(child2, below_matrix, gfx::Point3F(),
+                               gfx::PointF(), gfx::Size(50, 50), true, true,
+                               false);
+
+  root->Set3dSortingContextId(3);
+  root->SetDrawsContent(true);
+  parent->Set3dSortingContextId(7);
+  parent->SetDrawsContent(true);
+  child1->Set3dSortingContextId(7);
+  child1->SetDrawsContent(true);
+  child2->Set3dSortingContextId(7);
+  child2->SetDrawsContent(true);
+
+  parent->AddChild(child1_ptr.Pass());
+  parent->AddChild(child2_ptr.Pass());
+  root->AddChild(parent_ptr.Pass());
+
+  LayerImplList render_surface_layer_list;
+  LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
+      root_ptr.get(), root->bounds(), &render_surface_layer_list);
+  inputs.can_adjust_raster_scales = true;
+  LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+  EXPECT_TRUE(root->render_surface());
+  EXPECT_EQ(2u, render_surface_layer_list.size());
+
+  EXPECT_EQ(3u, parent->render_surface()->layer_list().size());
+  EXPECT_EQ(child2->id(), parent->render_surface()->layer_list().at(0)->id());
+  EXPECT_EQ(parent->id(), parent->render_surface()->layer_list().at(1)->id());
+  EXPECT_EQ(child1->id(), parent->render_surface()->layer_list().at(2)->id());
+}
+
 TEST_F(LayerTreeHostCommonTest,
        SingularNonAnimatingTransformDoesNotPreventClearingDrawProperties) {
   scoped_refptr<Layer> root = Layer::Create();
@@ -8675,5 +8747,70 @@
   EXPECT_EQ(affected_by_delta, sublayer->visible_content_rect());
 }
 
+TEST_F(LayerTreeHostCommonTest, VisibleContentRectForAnimatedLayer) {
+  const gfx::Transform identity_matrix;
+  scoped_refptr<Layer> root = Layer::Create();
+  scoped_refptr<LayerWithForcedDrawsContent> animated =
+      make_scoped_refptr(new LayerWithForcedDrawsContent());
+
+  root->AddChild(animated);
+
+  scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+  host->SetRootLayer(root);
+
+  SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(),
+                               gfx::PointF(), gfx::Size(100, 100), true, false);
+  SetLayerPropertiesForTesting(animated.get(), identity_matrix, gfx::Point3F(),
+                               gfx::PointF(), gfx::Size(20, 20), true, false);
+
+  root->SetMasksToBounds(true);
+  root->SetForceRenderSurface(true);
+  animated->SetOpacity(0.f);
+
+  AddOpacityTransitionToController(animated->layer_animation_controller(), 10.0,
+                                   0.f, 1.f, false);
+
+  ExecuteCalculateDrawProperties(root.get());
+
+  EXPECT_FALSE(animated->visible_rect_from_property_trees().IsEmpty());
+}
+
+// Verify that having an animated filter (but no current filter, as these
+// are mutually exclusive) correctly creates a render surface.
+TEST_F(LayerTreeHostCommonTest, AnimatedFilterCreatesRenderSurface) {
+  scoped_refptr<Layer> root = Layer::Create();
+  scoped_refptr<Layer> child = Layer::Create();
+  scoped_refptr<Layer> grandchild = Layer::Create();
+  root->AddChild(child);
+  child->AddChild(grandchild);
+
+  gfx::Transform identity_transform;
+  SetLayerPropertiesForTesting(root.get(), identity_transform, gfx::Point3F(),
+                               gfx::PointF(), gfx::Size(50, 50), true, false);
+  SetLayerPropertiesForTesting(child.get(), identity_transform, gfx::Point3F(),
+                               gfx::PointF(), gfx::Size(50, 50), true, false);
+  SetLayerPropertiesForTesting(grandchild.get(), identity_transform,
+                               gfx::Point3F(), gfx::PointF(), gfx::Size(50, 50),
+                               true, false);
+  scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+  host->SetRootLayer(root);
+
+  AddAnimatedFilterToLayer(child.get(), 10.0, 0.1f, 0.2f);
+
+  ExecuteCalculateDrawProperties(root.get());
+
+  EXPECT_TRUE(root->render_surface());
+  EXPECT_TRUE(child->render_surface());
+  EXPECT_FALSE(grandchild->render_surface());
+
+  EXPECT_TRUE(root->filters().IsEmpty());
+  EXPECT_TRUE(child->filters().IsEmpty());
+  EXPECT_TRUE(grandchild->filters().IsEmpty());
+
+  EXPECT_FALSE(root->FilterIsAnimating());
+  EXPECT_TRUE(child->FilterIsAnimating());
+  EXPECT_FALSE(grandchild->FilterIsAnimating());
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index eef1cc3..eddbc60 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -916,6 +916,8 @@
 }
 
 void LayerTreeHostImpl::MainThreadHasStoppedFlinging() {
+  if (top_controls_manager_)
+    top_controls_manager_->MainThreadHasStoppedFlinging();
   if (input_handler_client_)
     input_handler_client_->MainThreadHasStoppedFlinging();
 }
@@ -3112,6 +3114,19 @@
   client_->RenewTreePriority();
 }
 
+void LayerTreeHostImpl::AnimateScrollbars(base::TimeTicks monotonic_time) {
+  if (scrollbar_animation_controllers_.empty())
+    return;
+
+  TRACE_EVENT0("cc", "LayerTreeHostImpl::AnimateScrollbars");
+  std::set<ScrollbarAnimationController*> controllers_copy =
+      scrollbar_animation_controllers_;
+  for (auto& it : controllers_copy)
+    it->Animate(monotonic_time);
+
+  SetNeedsAnimate();
+}
+
 void LayerTreeHostImpl::AnimateLayers(base::TimeTicks monotonic_time) {
   if (!settings_.accelerated_animation_enabled ||
       !needs_animate_layers() ||
@@ -3119,31 +3134,26 @@
     return;
 
   TRACE_EVENT0("cc", "LayerTreeHostImpl::AnimateLayers");
-  AnimationRegistrar::AnimationControllerMap copy =
+  AnimationRegistrar::AnimationControllerMap controllers_copy =
       animation_registrar_->active_animation_controllers();
-  for (AnimationRegistrar::AnimationControllerMap::iterator iter = copy.begin();
-       iter != copy.end();
-       ++iter)
-    (*iter).second->Animate(monotonic_time);
+  for (auto& it : controllers_copy)
+    it.second->Animate(monotonic_time);
 
   SetNeedsAnimate();
 }
 
 void LayerTreeHostImpl::UpdateAnimationState(bool start_ready_animations) {
-  if (!settings_.accelerated_animation_enabled ||
-      !needs_animate_layers() ||
+  if (!settings_.accelerated_animation_enabled || !needs_animate_layers() ||
       !active_tree_->root_layer())
     return;
 
   TRACE_EVENT0("cc", "LayerTreeHostImpl::UpdateAnimationState");
   scoped_ptr<AnimationEventsVector> events =
       make_scoped_ptr(new AnimationEventsVector);
-  AnimationRegistrar::AnimationControllerMap copy =
+  AnimationRegistrar::AnimationControllerMap active_controllers_copy =
       animation_registrar_->active_animation_controllers();
-  for (AnimationRegistrar::AnimationControllerMap::iterator iter = copy.begin();
-       iter != copy.end();
-       ++iter)
-    (*iter).second->UpdateState(start_ready_animations, events.get());
+  for (auto& it : active_controllers_copy)
+    it.second->UpdateState(start_ready_animations, events.get());
 
   if (!events->empty()) {
     client_->PostAnimationEventsToMainThreadOnImplThread(events.Pass());
@@ -3158,12 +3168,10 @@
     return;
 
   TRACE_EVENT0("cc", "LayerTreeHostImpl::ActivateAnimations");
-  AnimationRegistrar::AnimationControllerMap copy =
+  AnimationRegistrar::AnimationControllerMap active_controllers_copy =
       animation_registrar_->active_animation_controllers();
-  for (AnimationRegistrar::AnimationControllerMap::iterator iter = copy.begin();
-       iter != copy.end();
-       ++iter)
-    (*iter).second->ActivateAnimations();
+  for (auto& it : active_controllers_copy)
+    it.second->ActivateAnimations();
 
   SetNeedsAnimate();
 }
@@ -3182,38 +3190,27 @@
   return fps_counter_->current_frame_number();
 }
 
-void LayerTreeHostImpl::AnimateScrollbars(base::TimeTicks time) {
-  AnimateScrollbarsRecursive(active_tree_->root_layer(), time);
-}
-
-void LayerTreeHostImpl::AnimateScrollbarsRecursive(LayerImpl* layer,
-                                                   base::TimeTicks time) {
-  if (!layer)
-    return;
-
-  ScrollbarAnimationController* scrollbar_controller =
-      layer->scrollbar_animation_controller();
-  if (scrollbar_controller)
-    scrollbar_controller->Animate(time);
-
-  for (size_t i = 0; i < layer->children().size(); ++i)
-    AnimateScrollbarsRecursive(layer->children()[i], time);
-}
-
-void LayerTreeHostImpl::PostDelayedScrollbarFade(
-    const base::Closure& start_fade,
-    base::TimeDelta delay) {
-  client_->PostDelayedScrollbarFadeOnImplThread(start_fade, delay);
-}
-
-void LayerTreeHostImpl::SetNeedsScrollbarAnimationFrame() {
-  TRACE_EVENT_INSTANT0(
-      "cc",
-      "LayerTreeHostImpl::SetNeedsRedraw due to scrollbar fade",
-      TRACE_EVENT_SCOPE_THREAD);
+void LayerTreeHostImpl::StartAnimatingScrollbarAnimationController(
+    ScrollbarAnimationController* controller) {
+  scrollbar_animation_controllers_.insert(controller);
   SetNeedsAnimate();
 }
 
+void LayerTreeHostImpl::StopAnimatingScrollbarAnimationController(
+    ScrollbarAnimationController* controller) {
+  scrollbar_animation_controllers_.erase(controller);
+}
+
+void LayerTreeHostImpl::PostDelayedScrollbarAnimationTask(
+    const base::Closure& task,
+    base::TimeDelta delay) {
+  client_->PostDelayedAnimationTaskOnImplThread(task, delay);
+}
+
+void LayerTreeHostImpl::SetNeedsRedrawForScrollbarAnimation() {
+  SetNeedsRedraw();
+}
+
 void LayerTreeHostImpl::SetTreePriority(TreePriority priority) {
   if (!tile_manager_)
     return;
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 60f4b44..73ed039 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -103,9 +103,8 @@
       int priority_cutoff) = 0;
   virtual bool IsInsideDraw() = 0;
   virtual void RenewTreePriority() = 0;
-  virtual void PostDelayedScrollbarFadeOnImplThread(
-      const base::Closure& start_fade,
-      base::TimeDelta delay) = 0;
+  virtual void PostDelayedAnimationTaskOnImplThread(const base::Closure& task,
+                                                    base::TimeDelta delay) = 0;
   virtual void DidActivateSyncTree() = 0;
   virtual void DidPrepareTiles() = 0;
 
@@ -258,9 +257,13 @@
   void SetIsLikelyToRequireADraw(bool is_likely_to_require_a_draw) override;
 
   // ScrollbarAnimationControllerClient implementation.
-  void PostDelayedScrollbarFade(const base::Closure& start_fade,
-                                base::TimeDelta delay) override;
-  void SetNeedsScrollbarAnimationFrame() override;
+  void StartAnimatingScrollbarAnimationController(
+      ScrollbarAnimationController* controller) override;
+  void StopAnimatingScrollbarAnimationController(
+      ScrollbarAnimationController* controller) override;
+  void PostDelayedScrollbarAnimationTask(const base::Closure& task,
+                                         base::TimeDelta delay) override;
+  void SetNeedsRedrawForScrollbarAnimation() override;
 
   // OutputSurfaceClient implementation.
   void DeferredInitialize() override;
@@ -532,10 +535,6 @@
 
   // Virtual for testing.
   virtual void AnimateLayers(base::TimeTicks monotonic_time);
-  const AnimationRegistrar::AnimationControllerMap&
-      active_animation_controllers() const {
-    return animation_registrar_->active_animation_controllers();
-  }
 
   LayerTreeHostImplClient* client_;
   Proxy* proxy_;
@@ -584,9 +583,6 @@
   bool HandleMouseOverScrollbar(LayerImpl* layer_impl,
                                 const gfx::PointF& device_viewport_point);
 
-  void AnimateScrollbarsRecursive(LayerImpl* layer,
-                                  base::TimeTicks time);
-
   LayerImpl* FindScrollLayerForDeviceViewportPoint(
       const gfx::PointF& device_viewport_point,
       InputHandler::ScrollInputType type,
@@ -716,6 +712,7 @@
   base::TimeDelta begin_impl_frame_interval_;
 
   scoped_ptr<AnimationRegistrar> animation_registrar_;
+  std::set<ScrollbarAnimationController*> scrollbar_animation_controllers_;
 
   RenderingStatsInstrumentation* rendering_stats_instrumentation_;
   MicroBenchmarkControllerImpl micro_benchmark_controller_;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 38b2d66..b5e3a81 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -145,10 +145,10 @@
   }
   bool IsInsideDraw() override { return false; }
   void RenewTreePriority() override {}
-  void PostDelayedScrollbarFadeOnImplThread(const base::Closure& start_fade,
+  void PostDelayedAnimationTaskOnImplThread(const base::Closure& task,
                                             base::TimeDelta delay) override {
-    scrollbar_fade_start_ = start_fade;
-    requested_scrollbar_animation_delay_ = delay;
+    animation_task_ = task;
+    requested_animation_delay_ = delay;
   }
   void DidActivateSyncTree() override {}
   void DidPrepareTiles() override {}
@@ -401,8 +401,8 @@
   bool did_request_prepare_tiles_;
   bool did_complete_page_scale_animation_;
   bool reduce_memory_result_;
-  base::Closure scrollbar_fade_start_;
-  base::TimeDelta requested_scrollbar_animation_delay_;
+  base::Closure animation_task_;
+  base::TimeDelta requested_animation_delay_;
   size_t current_limit_bytes_;
   int current_priority_cutoff_value_;
 };
@@ -1616,52 +1616,77 @@
 
   base::TimeTicks fake_now = gfx::FrameTime::Now();
 
-  EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
+  EXPECT_FALSE(did_request_animate_);
   EXPECT_FALSE(did_request_redraw_);
+  EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
+  EXPECT_TRUE(animation_task_.Equals(base::Closure()));
 
   // If no scroll happened during a scroll gesture, it should have no effect.
   host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL);
   host_impl_->ScrollEnd();
-  EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
+  EXPECT_FALSE(did_request_animate_);
   EXPECT_FALSE(did_request_redraw_);
-  EXPECT_TRUE(scrollbar_fade_start_.Equals(base::Closure()));
+  EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
+  EXPECT_TRUE(animation_task_.Equals(base::Closure()));
 
   // After a scroll, a fade animation should be scheduled about 20ms from now.
   host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL);
   host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, 5));
-  host_impl_->ScrollEnd();
-  did_request_redraw_ = false;
-  did_request_animate_ = false;
-  EXPECT_LT(base::TimeDelta::FromMilliseconds(19),
-            requested_scrollbar_animation_delay_);
-  EXPECT_FALSE(did_request_redraw_);
   EXPECT_FALSE(did_request_animate_);
-  requested_scrollbar_animation_delay_ = base::TimeDelta();
-  scrollbar_fade_start_.Run();
-  host_impl_->Animate(fake_now);
+  EXPECT_TRUE(did_request_redraw_);
+  did_request_redraw_ = false;
+  EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
+  EXPECT_TRUE(animation_task_.Equals(base::Closure()));
+
+  host_impl_->ScrollEnd();
+  EXPECT_FALSE(did_request_animate_);
+  EXPECT_FALSE(did_request_redraw_);
+  EXPECT_EQ(base::TimeDelta::FromMilliseconds(20), requested_animation_delay_);
+  EXPECT_FALSE(animation_task_.Equals(base::Closure()));
+
+  fake_now += requested_animation_delay_;
+  requested_animation_delay_ = base::TimeDelta();
+  animation_task_.Run();
+  animation_task_ = base::Closure();
+  EXPECT_TRUE(did_request_animate_);
+  did_request_animate_ = false;
+  EXPECT_FALSE(did_request_redraw_);
 
   // After the fade begins, we should start getting redraws instead of a
   // scheduled animation.
-  fake_now += base::TimeDelta::FromMilliseconds(25);
-  EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
+  host_impl_->Animate(fake_now);
   EXPECT_TRUE(did_request_animate_);
   did_request_animate_ = false;
+  EXPECT_TRUE(did_request_redraw_);
+  did_request_redraw_ = false;
+  EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
+  EXPECT_TRUE(animation_task_.Equals(base::Closure()));
 
   // Setting the scroll offset outside a scroll should also cause the scrollbar
   // to appear and to schedule a fade.
   host_impl_->InnerViewportScrollLayer()->PushScrollOffsetFromMainThread(
       gfx::ScrollOffset(5, 5));
-  EXPECT_LT(base::TimeDelta::FromMilliseconds(19),
-            requested_scrollbar_animation_delay_);
-  EXPECT_FALSE(did_request_redraw_);
   EXPECT_FALSE(did_request_animate_);
-  requested_scrollbar_animation_delay_ = base::TimeDelta();
+  EXPECT_FALSE(did_request_redraw_);
+  EXPECT_EQ(base::TimeDelta::FromMilliseconds(20), requested_animation_delay_);
+  EXPECT_FALSE(animation_task_.Equals(base::Closure()));
+  requested_animation_delay_ = base::TimeDelta();
+  animation_task_ = base::Closure();
 
   // Unnecessarily Fade animation of solid color scrollbar is not triggered.
   host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL);
   host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(5, 0));
+  EXPECT_FALSE(did_request_animate_);
+  EXPECT_TRUE(did_request_redraw_);
+  did_request_redraw_ = false;
+  EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
+  EXPECT_TRUE(animation_task_.Equals(base::Closure()));
+
   host_impl_->ScrollEnd();
-  EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
+  EXPECT_FALSE(did_request_animate_);
+  EXPECT_FALSE(did_request_redraw_);
+  EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
+  EXPECT_TRUE(animation_task_.Equals(base::Closure()));
 }
 
 TEST_F(LayerTreeHostImplTest, ScrollbarFadePinchZoomScrollbars) {
@@ -1677,28 +1702,28 @@
 
   host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 4.f);
 
-  EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
+  EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
   EXPECT_FALSE(did_request_animate_);
 
   // If no scroll happened during a scroll gesture, it should have no effect.
   host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL);
   host_impl_->ScrollEnd();
-  EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
+  EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
   EXPECT_FALSE(did_request_animate_);
-  EXPECT_TRUE(scrollbar_fade_start_.Equals(base::Closure()));
+  EXPECT_TRUE(animation_task_.Equals(base::Closure()));
 
   // After a scroll, no fade animation should be scheduled.
   host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL);
   host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(5, 0));
   host_impl_->ScrollEnd();
   did_request_redraw_ = false;
-  EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
+  EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
   EXPECT_FALSE(did_request_animate_);
-  requested_scrollbar_animation_delay_ = base::TimeDelta();
+  requested_animation_delay_ = base::TimeDelta();
 
   // We should not see any draw requests.
   fake_now += base::TimeDelta::FromMilliseconds(25);
-  EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
+  EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
   EXPECT_FALSE(did_request_animate_);
 
   // Make page scale > min so that subsequent scrolls will trigger fades.
@@ -1709,11 +1734,10 @@
   host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(5, 0));
   host_impl_->ScrollEnd();
   did_request_redraw_ = false;
-  EXPECT_LT(base::TimeDelta::FromMilliseconds(19),
-            requested_scrollbar_animation_delay_);
+  EXPECT_LT(base::TimeDelta::FromMilliseconds(19), requested_animation_delay_);
   EXPECT_FALSE(did_request_animate_);
-  requested_scrollbar_animation_delay_ = base::TimeDelta();
-  scrollbar_fade_start_.Run();
+  requested_animation_delay_ = base::TimeDelta();
+  animation_task_.Run();
 
   // After the fade begins, we should start getting redraws instead of a
   // scheduled animation.
@@ -7639,6 +7663,69 @@
     }
   }
   EXPECT_FALSE(host_impl_->top_controls_manager()->animation());
+  EXPECT_EQ(-top_controls_height_,
+            host_impl_->top_controls_manager()->ControlsTopOffset());
+}
+
+TEST_F(LayerTreeHostImplWithTopControlsTest,
+       TopControlsAnimationAfterMainThreadFlingStopped) {
+  LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 200));
+  host_impl_->SetViewportSize(gfx::Size(100, 100));
+  host_impl_->top_controls_manager()->UpdateTopControlsState(BOTH, SHOWN,
+                                                             false);
+  float initial_scroll_offset = 50;
+  scroll_layer->PushScrollOffsetFromMainThread(
+      gfx::ScrollOffset(0, initial_scroll_offset));
+  DrawFrame();
+
+  EXPECT_EQ(InputHandler::SCROLL_STARTED,
+            host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
+  EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
+  EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(),
+            scroll_layer->CurrentScrollOffset().ToString());
+
+  // Scroll the top controls partially.
+  const float residue = 15;
+  float offset = top_controls_height_ - residue;
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
+  EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset());
+  EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(),
+            scroll_layer->CurrentScrollOffset().ToString());
+
+  did_request_redraw_ = false;
+  did_request_animate_ = false;
+  did_request_commit_ = false;
+
+  // End the fling while the controls are still offset from the limit.
+  host_impl_->MainThreadHasStoppedFlinging();
+  ASSERT_TRUE(host_impl_->top_controls_manager()->animation());
+  EXPECT_TRUE(did_request_animate_);
+  EXPECT_TRUE(did_request_redraw_);
+  EXPECT_FALSE(did_request_commit_);
+
+  // Animate the top controls to the limit.
+  base::TimeTicks animation_time = gfx::FrameTime::Now();
+  while (did_request_animate_) {
+    did_request_redraw_ = false;
+    did_request_animate_ = false;
+    did_request_commit_ = false;
+
+    float old_offset = host_impl_->top_controls_manager()->ControlsTopOffset();
+
+    animation_time += base::TimeDelta::FromMilliseconds(5);
+    host_impl_->Animate(animation_time);
+
+    float new_offset = host_impl_->top_controls_manager()->ControlsTopOffset();
+
+    if (new_offset != old_offset) {
+      EXPECT_TRUE(did_request_redraw_);
+      EXPECT_TRUE(did_request_commit_);
+    }
+  }
+  EXPECT_FALSE(host_impl_->top_controls_manager()->animation());
+  EXPECT_EQ(-top_controls_height_,
+            host_impl_->top_controls_manager()->ControlsTopOffset());
 }
 
 TEST_F(LayerTreeHostImplWithTopControlsTest,
diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc
index b8d0320..c1da07e 100644
--- a/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/cc/trees/layer_tree_host_unittest_animation.cc
@@ -195,8 +195,9 @@
 
   void AnimateLayers(LayerTreeHostImpl* host_impl,
                      base::TimeTicks monotonic_time) override {
-    bool have_animations = !host_impl->animation_registrar()->
-        active_animation_controllers().empty();
+    bool have_animations = !host_impl->animation_registrar()
+                                ->active_animation_controllers()
+                                .empty();
     if (!started_animating_ && have_animations) {
       started_animating_ = true;
       return;
@@ -1241,21 +1242,18 @@
     // After both animations have started, verify that they have valid
     // start times.
     num_swap_buffers_++;
-    AnimationRegistrar::AnimationControllerMap copy =
+    AnimationRegistrar::AnimationControllerMap controllers_copy =
         host_impl->animation_registrar()->active_animation_controllers();
-    if (copy.size() == 2u) {
+    if (controllers_copy.size() == 2u) {
       EndTest();
       EXPECT_GE(num_swap_buffers_, 3);
-      for (AnimationRegistrar::AnimationControllerMap::iterator iter =
-               copy.begin();
-           iter != copy.end();
-           ++iter) {
-        int id = ((*iter).second->id());
+      for (auto& it : controllers_copy) {
+        int id = it.first;
         if (id == host_impl->RootLayer()->id()) {
-          Animation* anim = (*iter).second->GetAnimation(Animation::TRANSFORM);
+          Animation* anim = it.second->GetAnimation(Animation::TRANSFORM);
           EXPECT_GT((anim->start_time() - base::TimeTicks()).InSecondsF(), 0);
         } else if (id == host_impl->RootLayer()->children()[0]->id()) {
-          Animation* anim = (*iter).second->GetAnimation(Animation::OPACITY);
+          Animation* anim = it.second->GetAnimation(Animation::OPACITY);
           EXPECT_GT((anim->start_time() - base::TimeTicks()).InSecondsF(), 0);
         }
       }
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index e86e785..62e4cd3 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -984,7 +984,7 @@
   layer_tree_host_impl_->SetNeedsRedraw();
 }
 
-AnimationRegistrar* LayerTreeImpl::animationRegistrar() const {
+AnimationRegistrar* LayerTreeImpl::GetAnimationRegistrar() const {
   return layer_tree_host_impl_->animation_registrar();
 }
 
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index 5935d29..f7b6ee4 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -239,7 +239,7 @@
 
   size_t NumLayers();
 
-  AnimationRegistrar* animationRegistrar() const;
+  AnimationRegistrar* GetAnimationRegistrar() const;
 
   void PushPersistedState(LayerTreeImpl* pending_tree);
 
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index a0fbeaa..06c319a 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -9,9 +9,7 @@
 #include "cc/base/cc_export.h"
 #include "cc/debug/layer_tree_debug_state.h"
 #include "cc/output/renderer_settings.h"
-#include "skia/ext/refptr.h"
 #include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkTypeface.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace cc {
@@ -86,7 +84,6 @@
   bool record_full_layer;
   bool use_display_lists;
   bool verify_property_trees;
-  skia::RefPtr<SkTypeface> hud_typeface;
 
   LayerTreeDebugState initial_debug_state;
 };
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index 25d42aa..95e4366 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -33,6 +33,7 @@
 
 template class PropertyTree<TransformNode>;
 template class PropertyTree<ClipNode>;
+template class PropertyTree<OpacityNode>;
 
 TransformNodeData::TransformNodeData()
     : target_id(-1),
@@ -91,7 +92,6 @@
   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);
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h
index ef47bce..404f498 100644
--- a/cc/trees/property_tree.h
+++ b/cc/trees/property_tree.h
@@ -100,6 +100,8 @@
 
 typedef TreeNode<ClipNodeData> ClipNode;
 
+typedef TreeNode<float> OpacityNode;
+
 template <typename T>
 class CC_EXPORT PropertyTree {
  public:
@@ -182,6 +184,8 @@
 
 class CC_EXPORT ClipTree final : public PropertyTree<ClipNode> {};
 
+class CC_EXPORT OpacityTree final : public PropertyTree<OpacityNode> {};
+
 }  // namespace cc
 
 #endif  // CC_TREES_PROPERTY_TREE_H_
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
index 7fe0494..0c080dd 100644
--- a/cc/trees/property_tree_builder.cc
+++ b/cc/trees/property_tree_builder.cc
@@ -21,10 +21,12 @@
 struct DataForRecursion {
   TransformTree* transform_tree;
   ClipTree* clip_tree;
+  OpacityTree* opacity_tree;
   Layer* transform_tree_parent;
   Layer* transform_fixed_parent;
   Layer* render_target;
   int clip_tree_parent;
+  int opacity_tree_parent;
   gfx::Vector2dF offset_to_transform_tree_parent;
   gfx::Vector2dF offset_to_transform_fixed_parent;
   const Layer* page_scale_layer;
@@ -120,8 +122,6 @@
       layer->layer_animation_controller()->IsAnimatingProperty(
           Animation::TRANSFORM);
 
-  const bool has_transform_origin = layer->transform_origin() != gfx::Point3F();
-
   const bool has_surface = !!layer->render_surface();
 
   const bool flattening_change = layer->parent() &&
@@ -131,7 +131,7 @@
   bool requires_node = is_root || is_scrollable || is_fixed ||
                        has_significant_transform || has_animated_transform ||
                        is_page_scale_application_layer || flattening_change ||
-                       has_transform_origin || has_surface;
+                       has_surface;
 
   Layer* transform_parent = GetTransformParent(data_from_ancestor, layer);
 
@@ -223,6 +223,32 @@
   layer->set_offset_to_transform_parent(gfx::Vector2dF());
 }
 
+void AddOpacityNodeIfNeeded(const DataForRecursion& data_from_ancestor,
+                            Layer* layer,
+                            DataForRecursion* data_for_children) {
+  const bool is_root = !layer->parent();
+  const bool has_transparency = layer->opacity() != 1.f;
+  const bool has_animated_opacity =
+      layer->layer_animation_controller()->IsAnimatingProperty(
+          Animation::OPACITY) ||
+      layer->OpacityCanAnimateOnImplThread();
+  bool requires_node = is_root || has_transparency || has_animated_opacity;
+
+  int parent_id = data_from_ancestor.opacity_tree_parent;
+
+  if (!requires_node) {
+    layer->set_opacity_tree_index(parent_id);
+    data_for_children->opacity_tree_parent = parent_id;
+    return;
+  }
+
+  OpacityNode node;
+  node.data = layer->opacity();
+  data_for_children->opacity_tree_parent =
+      data_for_children->opacity_tree->Insert(node, parent_id);
+  layer->set_opacity_tree_index(data_for_children->opacity_tree_parent);
+}
+
 void BuildPropertyTreesInternal(Layer* layer,
                                 const DataForRecursion& data_from_parent) {
   DataForRecursion data_for_children(data_from_parent);
@@ -232,6 +258,9 @@
   AddTransformNodeIfNeeded(data_from_parent, layer, &data_for_children);
   AddClipNodeIfNeeded(data_from_parent, layer, &data_for_children);
 
+  if (data_from_parent.opacity_tree)
+    AddOpacityNodeIfNeeded(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;
 
@@ -260,14 +289,17 @@
     const gfx::Rect& viewport,
     const gfx::Transform& device_transform,
     TransformTree* transform_tree,
-    ClipTree* clip_tree) {
+    ClipTree* clip_tree,
+    OpacityTree* opacity_tree) {
   DataForRecursion data_for_recursion;
   data_for_recursion.transform_tree = transform_tree;
   data_for_recursion.clip_tree = clip_tree;
+  data_for_recursion.opacity_tree = opacity_tree;
   data_for_recursion.transform_tree_parent = nullptr;
   data_for_recursion.transform_fixed_parent = nullptr;
   data_for_recursion.render_target = root_layer;
   data_for_recursion.clip_tree_parent = 0;
+  data_for_recursion.opacity_tree_parent = -1;
   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;
diff --git a/cc/trees/property_tree_builder.h b/cc/trees/property_tree_builder.h
index f949c9a..7f5f479 100644
--- a/cc/trees/property_tree_builder.h
+++ b/cc/trees/property_tree_builder.h
@@ -16,6 +16,8 @@
 
 class PropertyTreeBuilder {
  public:
+  // Building an opacity tree is optional, and can be skipped by passing
+  // in a null |opacity_tree|.
   static void BuildPropertyTrees(Layer* root_layer,
                                  const Layer* page_scale_layer,
                                  float page_scale_factor,
@@ -23,7 +25,8 @@
                                  const gfx::Rect& viewport,
                                  const gfx::Transform& device_transform,
                                  TransformTree* transform_tree,
-                                 ClipTree* clip_tree);
+                                 ClipTree* clip_tree,
+                                 OpacityTree* opacity_tree);
 };
 
 }  // namespace cc
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index f463db1..2612a4d 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -104,7 +104,7 @@
                                                int priority_cutoff) override;
   bool IsInsideDraw() override;
   void RenewTreePriority() override {}
-  void PostDelayedScrollbarFadeOnImplThread(const base::Closure& start_fade,
+  void PostDelayedAnimationTaskOnImplThread(const base::Closure& task,
                                             base::TimeDelta delay) override {}
   void DidActivateSyncTree() override;
   void DidPrepareTiles() override;
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
index 1097805..4efb401 100644
--- a/cc/trees/thread_proxy.cc
+++ b/cc/trees/thread_proxy.cc
@@ -1362,10 +1362,10 @@
   }
 }
 
-void ThreadProxy::PostDelayedScrollbarFadeOnImplThread(
-    const base::Closure& start_fade,
+void ThreadProxy::PostDelayedAnimationTaskOnImplThread(
+    const base::Closure& task,
     base::TimeDelta delay) {
-  Proxy::ImplThreadTaskRunner()->PostDelayedTask(FROM_HERE, start_fade, delay);
+  Proxy::ImplThreadTaskRunner()->PostDelayedTask(FROM_HERE, task, delay);
 }
 
 void ThreadProxy::DidActivateSyncTree() {
diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h
index 8b4c302..c2dd348 100644
--- a/cc/trees/thread_proxy.h
+++ b/cc/trees/thread_proxy.h
@@ -205,7 +205,7 @@
                                                int priority_cutoff) override;
   bool IsInsideDraw() override;
   void RenewTreePriority() override;
-  void PostDelayedScrollbarFadeOnImplThread(const base::Closure& start_fade,
+  void PostDelayedAnimationTaskOnImplThread(const base::Closure& task,
                                             base::TimeDelta delay) override;
   void DidActivateSyncTree() override;
   void DidPrepareTiles() override;