Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / cc / trees / layer_tree_host_unittest.cc
index 0b2598b..ea490cd 100644 (file)
@@ -9,6 +9,7 @@
 #include "base/auto_reset.h"
 #include "base/synchronization/lock.h"
 #include "cc/animation/timing_function.h"
+#include "cc/base/swap_promise.h"
 #include "cc/debug/frame_rate_counter.h"
 #include "cc/layers/content_layer.h"
 #include "cc/layers/content_layer_client.h"
 #include "cc/output/copy_output_request.h"
 #include "cc/output/copy_output_result.h"
 #include "cc/output/output_surface.h"
+#include "cc/quads/draw_quad.h"
+#include "cc/quads/io_surface_draw_quad.h"
 #include "cc/resources/prioritized_resource.h"
 #include "cc/resources/prioritized_resource_manager.h"
 #include "cc/resources/resource_update_queue.h"
-#include "cc/scheduler/frame_rate_controller.h"
 #include "cc/test/fake_content_layer.h"
 #include "cc/test/fake_content_layer_client.h"
 #include "cc/test/fake_content_layer_impl.h"
@@ -39,7 +41,7 @@
 #include "cc/test/fake_video_frame_provider.h"
 #include "cc/test/geometry_test_utils.h"
 #include "cc/test/layer_tree_test.h"
-#include "cc/test/occlusion_tracker_test_common.h"
+#include "cc/test/test_shared_bitmap_manager.h"
 #include "cc/test/test_web_graphics_context_3d.h"
 #include "cc/trees/layer_tree_host_impl.h"
 #include "cc/trees/layer_tree_impl.h"
@@ -64,8 +66,7 @@ using testing::Mock;
 namespace cc {
 namespace {
 
-class LayerTreeHostTest : public LayerTreeTest {
-};
+class LayerTreeHostTest : public LayerTreeTest {};
 
 // Two setNeedsCommits in a row should lead to at least 1 commit and at least 1
 // draw with frame 0.
@@ -275,8 +276,7 @@ class LayerTreeHostTestSetNeedsRedrawRect : public LayerTreeHostTest {
       : num_draws_(0),
         bounds_(50, 50),
         invalid_rect_(10, 10, 20, 20),
-        root_layer_(ContentLayer::Create(&client_)) {
-  }
+        root_layer_(ContentLayer::Create(&client_)) {}
 
   virtual void BeginTest() OVERRIDE {
     root_layer_->SetIsDrawable(true);
@@ -286,10 +286,11 @@ class LayerTreeHostTestSetNeedsRedrawRect : public LayerTreeHostTest {
     PostSetNeedsCommitToMainThread();
   }
 
-  virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
-                                     LayerTreeHostImpl::FrameData* frame_data,
-                                     bool result) OVERRIDE {
-    EXPECT_TRUE(result);
+  virtual DrawSwapReadbackResult::DrawResult PrepareToDrawOnThread(
+      LayerTreeHostImpl* host_impl,
+      LayerTreeHostImpl::FrameData* frame_data,
+      DrawSwapReadbackResult::DrawResult draw_result) OVERRIDE {
+    EXPECT_EQ(DrawSwapReadbackResult::DRAW_SUCCESS, draw_result);
 
     gfx::RectF root_damage_rect;
     if (!frame_data->render_passes.empty())
@@ -303,7 +304,7 @@ class LayerTreeHostTestSetNeedsRedrawRect : public LayerTreeHostTest {
       EXPECT_TRUE(root_damage_rect.Contains(invalid_rect_));
     }
 
-    return result;
+    return draw_result;
   }
 
   virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
@@ -315,9 +316,7 @@ class LayerTreeHostTestSetNeedsRedrawRect : public LayerTreeHostTest {
     num_draws_++;
   }
 
-  virtual void AfterTest() OVERRIDE {
-    EXPECT_EQ(2, num_draws_);
-  }
+  virtual void AfterTest() OVERRIDE { EXPECT_EQ(2, num_draws_); }
 
  private:
   int num_draws_;
@@ -347,9 +346,7 @@ class LayerTreeHostTestNoExtraCommitFromInvalidate : public LayerTreeHostTest {
     LayerTreeHostTest::SetupTree();
   }
 
-  virtual void BeginTest() OVERRIDE {
-    PostSetNeedsCommitToMainThread();
-  }
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
     if (host_impl->active_tree()->source_frame_number() == 1)
@@ -407,9 +404,7 @@ class LayerTreeHostTestNoExtraCommitFromScrollbarInvalidate
     LayerTreeHostTest::SetupTree();
   }
 
-  virtual void BeginTest() OVERRIDE {
-    PostSetNeedsCommitToMainThread();
-  }
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
     if (host_impl->active_tree()->source_frame_number() == 1)
@@ -523,9 +518,10 @@ class LayerTreeHostTestCompositeAndReadbackDuringForcedDraw
 
   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
-  virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
-                                     LayerTreeHostImpl::FrameData* frame_data,
-                                     bool result) OVERRIDE {
+  virtual DrawSwapReadbackResult::DrawResult PrepareToDrawOnThread(
+      LayerTreeHostImpl* host_impl,
+      LayerTreeHostImpl::FrameData* frame_data,
+      DrawSwapReadbackResult::DrawResult draw_result) OVERRIDE {
     int sfn = host_impl->active_tree()->source_frame_number();
     EXPECT_TRUE(sfn == kFirstCommitSourceFrameNumber ||
                 sfn == kReadbackSourceFrameNumber ||
@@ -539,8 +535,8 @@ class LayerTreeHostTestCompositeAndReadbackDuringForcedDraw
       PostReadbackToMainThread();
     }
 
-    // Returning false will result in a forced draw.
-    return false;
+    // Aborting for checkerboarding animations will result in a forced draw.
+    return DrawSwapReadbackResult::DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
   }
 
   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
@@ -583,9 +579,10 @@ class LayerTreeHostTestCompositeAndReadbackAfterForcedDraw
 
   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
-  virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
-                                     LayerTreeHostImpl::FrameData* frame_data,
-                                     bool result) OVERRIDE {
+  virtual DrawSwapReadbackResult::DrawResult PrepareToDrawOnThread(
+      LayerTreeHostImpl* host_impl,
+      LayerTreeHostImpl::FrameData* frame_data,
+      DrawSwapReadbackResult::DrawResult draw_result) OVERRIDE {
     int sfn = host_impl->active_tree()->source_frame_number();
     EXPECT_TRUE(sfn == kFirstCommitSourceFrameNumber ||
                 sfn == kForcedDrawSourceFrameNumber ||
@@ -593,8 +590,8 @@ class LayerTreeHostTestCompositeAndReadbackAfterForcedDraw
                 sfn == kReadbackReplacementSourceFrameNumber)
         << sfn;
 
-    // Returning false will result in a forced draw.
-    return false;
+    // Aborting for checkerboarding animations will result in a forced draw.
+    return DrawSwapReadbackResult::DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
   }
 
   virtual void DidCommit() OVERRIDE {
@@ -644,8 +641,7 @@ class LayerTreeHostTestSetNextCommitForcesRedraw : public LayerTreeHostTest {
       : num_draws_(0),
         bounds_(50, 50),
         invalid_rect_(10, 10, 20, 20),
-        root_layer_(ContentLayer::Create(&client_)) {
-  }
+        root_layer_(ContentLayer::Create(&client_)) {}
 
   virtual void BeginTest() OVERRIDE {
     root_layer_->SetIsDrawable(true);
@@ -660,10 +656,11 @@ class LayerTreeHostTestSetNextCommitForcesRedraw : public LayerTreeHostTest {
       host_impl->SetNeedsRedrawRect(invalid_rect_);
   }
 
-  virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
-                                     LayerTreeHostImpl::FrameData* frame_data,
-                                     bool result) OVERRIDE {
-    EXPECT_TRUE(result);
+  virtual DrawSwapReadbackResult::DrawResult PrepareToDrawOnThread(
+      LayerTreeHostImpl* host_impl,
+      LayerTreeHostImpl::FrameData* frame_data,
+      DrawSwapReadbackResult::DrawResult draw_result) OVERRIDE {
+    EXPECT_EQ(DrawSwapReadbackResult::DRAW_SUCCESS, draw_result);
 
     gfx::RectF root_damage_rect;
     if (!frame_data->render_passes.empty())
@@ -687,7 +684,7 @@ class LayerTreeHostTestSetNextCommitForcesRedraw : public LayerTreeHostTest {
         NOTREACHED();
     }
 
-    return result;
+    return draw_result;
   }
 
   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
@@ -717,9 +714,7 @@ class LayerTreeHostTestSetNextCommitForcesRedraw : public LayerTreeHostTest {
     num_draws_++;
   }
 
-  virtual void AfterTest() OVERRIDE {
-    EXPECT_EQ(5, num_draws_);
-  }
+  virtual void AfterTest() OVERRIDE { EXPECT_EQ(5, num_draws_); }
 
  private:
   int num_draws_;
@@ -736,8 +731,7 @@ SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSetNextCommitForcesRedraw);
 class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest {
  public:
   LayerTreeHostTestUndrawnLayersDamageLater()
-      : root_layer_(ContentLayer::Create(&client_)) {
-  }
+      : root_layer_(ContentLayer::Create(&client_)) {}
 
   virtual void SetupTree() OVERRIDE {
     root_layer_->SetIsDrawable(true);
@@ -758,14 +752,13 @@ class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest {
     LayerTreeHostTest::SetupTree();
   }
 
-  virtual void BeginTest() OVERRIDE {
-    PostSetNeedsCommitToMainThread();
-  }
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
-  virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
-                                     LayerTreeHostImpl::FrameData* frame_data,
-                                     bool result) OVERRIDE {
-    EXPECT_TRUE(result);
+  virtual DrawSwapReadbackResult::DrawResult PrepareToDrawOnThread(
+      LayerTreeHostImpl* host_impl,
+      LayerTreeHostImpl::FrameData* frame_data,
+      DrawSwapReadbackResult::DrawResult draw_result) OVERRIDE {
+    EXPECT_EQ(DrawSwapReadbackResult::DRAW_SUCCESS, draw_result);
 
     gfx::RectF root_damage_rect;
     if (!frame_data->render_passes.empty())
@@ -789,7 +782,7 @@ class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest {
         NOTREACHED();
     }
 
-    return result;
+    return draw_result;
   }
 
   virtual void DidCommitAndDrawFrame() OVERRIDE {
@@ -814,7 +807,6 @@ class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest {
     }
   }
 
-
   virtual void AfterTest() OVERRIDE {}
 
  private:
@@ -826,115 +818,128 @@ class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest {
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestUndrawnLayersDamageLater);
 
-// If the layerTreeHost says it can't draw, Then we should not try to draw.
-class LayerTreeHostTestCanDrawBlocksDrawing : public LayerTreeHostTest {
+// Tests that if a layer is not drawn because of some reason in the parent,
+// causing its content bounds to not be computed, then when it is later drawn,
+// its content bounds get pushed.
+class LayerTreeHostTestUndrawnLayersPushContentBoundsLater
+    : public LayerTreeHostTest {
  public:
-  LayerTreeHostTestCanDrawBlocksDrawing() : num_commits_(0), done_(false) {}
+  LayerTreeHostTestUndrawnLayersPushContentBoundsLater()
+      : root_layer_(Layer::Create()) {}
 
-  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+  virtual void SetupTree() OVERRIDE {
+    root_layer_->SetIsDrawable(true);
+    root_layer_->SetBounds(gfx::Size(20, 20));
+    layer_tree_host()->SetRootLayer(root_layer_);
 
-  virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
-    if (done_)
-      return;
-    // Only the initial draw should bring us here.
-    EXPECT_TRUE(impl->CanDraw());
-    EXPECT_EQ(0, impl->active_tree()->source_frame_number());
+    parent_layer_ = Layer::Create();
+    parent_layer_->SetBounds(gfx::Size(20, 20));
+    parent_layer_->SetOpacity(0.0f);
+    root_layer_->AddChild(parent_layer_);
+
+    child_layer_ = Layer::Create();
+    child_layer_->SetBounds(gfx::Size(15, 15));
+    parent_layer_->AddChild(child_layer_);
+
+    LayerTreeHostTest::SetupTree();
   }
 
-  virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
-    if (done_)
-      return;
-    if (num_commits_ >= 1) {
-      // After the first commit, we should not be able to draw.
-      EXPECT_FALSE(impl->CanDraw());
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+
+  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+    LayerImpl* root = host_impl->active_tree()->root_layer();
+    LayerImpl* parent = root->children()[0];
+    LayerImpl* child = parent->children()[0];
+
+    switch (host_impl->active_tree()->source_frame_number()) {
+      case 0:
+        EXPECT_EQ(0.f, parent->opacity());
+        EXPECT_EQ(gfx::SizeF(), child->content_bounds());
+        break;
+      case 1:
+        EXPECT_EQ(1.f, parent->opacity());
+        EXPECT_EQ(gfx::SizeF(15.f, 15.f), child->content_bounds());
+        EndTest();
+        break;
+      default:
+        NOTREACHED();
     }
   }
 
   virtual void DidCommit() OVERRIDE {
-    num_commits_++;
-    if (num_commits_ == 1) {
-      // Make the viewport empty so the host says it can't draw.
-      layer_tree_host()->SetViewportSize(gfx::Size(0, 0));
-    } else if (num_commits_ == 2) {
-      char pixels[4];
-      layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(0, 0, 1, 1));
-    } else if (num_commits_ == 3) {
-      // Let it draw so we go idle and end the test.
-      layer_tree_host()->SetViewportSize(gfx::Size(1, 1));
-      done_ = true;
-      EndTest();
+    switch (layer_tree_host()->source_frame_number()) {
+      case 1:
+        parent_layer_->SetOpacity(1.0f);
+        break;
+      case 2:
+        break;
+      default:
+        NOTREACHED();
     }
   }
 
   virtual void AfterTest() OVERRIDE {}
 
  private:
-  int num_commits_;
-  bool done_;
+  scoped_refptr<Layer> root_layer_;
+  scoped_refptr<Layer> parent_layer_;
+  scoped_refptr<Layer> child_layer_;
 };
 
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestCanDrawBlocksDrawing);
+SINGLE_AND_MULTI_THREAD_TEST_F(
+    LayerTreeHostTestUndrawnLayersPushContentBoundsLater);
 
-// beginLayerWrite should prevent draws from executing until a commit occurs
-class LayerTreeHostTestWriteLayersRedraw : public LayerTreeHostTest {
+// If the layerTreeHost says it can't draw, Then we should not try to draw.
+class LayerTreeHostTestCanDrawBlocksDrawing : public LayerTreeHostTest {
  public:
-  LayerTreeHostTestWriteLayersRedraw() : num_commits_(0), num_draws_(0) {}
+  LayerTreeHostTestCanDrawBlocksDrawing() : done_(false) {}
 
-  virtual void BeginTest() OVERRIDE {
-    PostAcquireLayerTextures();
-    PostSetNeedsRedrawToMainThread();  // should be inhibited without blocking
-    PostSetNeedsCommitToMainThread();
-  }
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
   virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
-    num_draws_++;
-    EXPECT_EQ(num_draws_, num_commits_);
+    if (done_)
+      return;
+    // Only the initial draw should bring us here.
+    EXPECT_TRUE(impl->CanDraw());
+    EXPECT_EQ(0, impl->active_tree()->source_frame_number());
   }
 
   virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
-    num_commits_++;
-    EndTest();
+    if (done_)
+      return;
+    if (LastCommittedSourceFrameNumber(impl) >= 1) {
+      // After the first commit, we should not be able to draw.
+      EXPECT_FALSE(impl->CanDraw());
+    }
   }
 
-  virtual void AfterTest() OVERRIDE { EXPECT_EQ(1, num_commits_); }
-
- private:
-  int num_commits_;
-  int num_draws_;
-};
-
-MULTI_THREAD_TEST_F(LayerTreeHostTestWriteLayersRedraw);
-
-// Verify that when resuming visibility, Requesting layer write permission
-// will not deadlock the main thread even though there are not yet any
-// scheduled redraws. This behavior is critical for reliably surviving tab
-// switching. There are no failure conditions to this test, it just passes
-// by not timing out.
-class LayerTreeHostTestWriteLayersAfterVisible : public LayerTreeHostTest {
- public:
-  LayerTreeHostTestWriteLayersAfterVisible() : num_commits_(0) {}
-
-  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
-
-  virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
-    num_commits_++;
-    if (num_commits_ == 2)
-      EndTest();
-    else if (num_commits_ < 2) {
-      PostSetVisibleToMainThread(false);
-      PostSetVisibleToMainThread(true);
-      PostAcquireLayerTextures();
-      PostSetNeedsCommitToMainThread();
+  virtual void DidCommit() OVERRIDE {
+    switch (layer_tree_host()->source_frame_number()) {
+      case 1:
+        // Make the viewport empty so the host says it can't draw.
+        layer_tree_host()->SetViewportSize(gfx::Size(0, 0));
+        break;
+      case 2: {
+        char pixels[4];
+        layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(0, 0, 1, 1));
+        break;
+      }
+      case 3:
+        // Let it draw so we go idle and end the test.
+        layer_tree_host()->SetViewportSize(gfx::Size(1, 1));
+        done_ = true;
+        EndTest();
+        break;
     }
   }
 
   virtual void AfterTest() OVERRIDE {}
 
  private:
-  int num_commits_;
+  bool done_;
 };
 
-MULTI_THREAD_TEST_F(LayerTreeHostTestWriteLayersAfterVisible);
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestCanDrawBlocksDrawing);
 
 // A compositeAndReadback while invisible should force a normal commit without
 // assertion.
@@ -1032,7 +1037,7 @@ class LayerTreeHostTestFrameTimeUpdatesAfterActivationFails
     PostSetNeedsCommitToMainThread();
   }
 
-  virtual void BeginCommitOnThread(LayerTreeHostImpl *impl) OVERRIDE {
+  virtual void BeginCommitOnThread(LayerTreeHostImplimpl) OVERRIDE {
     EXPECT_EQ(frame_count_with_pending_tree_, 0);
     impl->BlockNotifyReadyToActivateForTesting(true);
   }
@@ -1042,15 +1047,11 @@ class LayerTreeHostTestFrameTimeUpdatesAfterActivationFails
     if (impl->pending_tree())
       frame_count_with_pending_tree_++;
 
-    if (frame_count_with_pending_tree_ == 2)
-      impl->BlockNotifyReadyToActivateForTesting(false);
-  }
-
-  virtual void DidBeginImplFrameOnThread(LayerTreeHostImpl* impl,
-                                         const BeginFrameArgs& args) OVERRIDE {
     if (frame_count_with_pending_tree_ == 1) {
       EXPECT_EQ(first_frame_time_.ToInternalValue(), 0);
       first_frame_time_ = impl->CurrentFrameTimeTicks();
+    } else if (frame_count_with_pending_tree_ == 2) {
+      impl->BlockNotifyReadyToActivateForTesting(false);
     }
   }
 
@@ -1102,7 +1103,8 @@ class LayerTreeHostTestFrameTimeUpdatesAfterDraw : public LayerTreeHostTest {
 
       // Since we might use a low-resolution clock on Windows, we need to
       // make sure that the clock has incremented past first_frame_time_.
-      while (first_frame_time_ == gfx::FrameTime::Now()) {}
+      while (first_frame_time_ == gfx::FrameTime::Now()) {
+      }
 
       return;
     }
@@ -1131,8 +1133,7 @@ SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestFrameTimeUpdatesAfterDraw);
 
 // Verifies that StartPageScaleAnimation events propagate correctly
 // from LayerTreeHost to LayerTreeHostImpl in the MT compositor.
-class LayerTreeHostTestStartPageScaleAnimation
-    : public LayerTreeHostTest {
+class LayerTreeHostTestStartPageScaleAnimation : public LayerTreeHostTest {
  public:
   LayerTreeHostTestStartPageScaleAnimation() {}
 
@@ -1148,18 +1149,24 @@ class LayerTreeHostTestStartPageScaleAnimation
       scroll_layer_ = FakeContentLayer::Create(&client_);
     }
 
-    scroll_layer_->SetScrollable(true);
+    Layer* root_layer = layer_tree_host()->root_layer();
+    scroll_layer_->SetScrollClipLayerId(root_layer->id());
+    scroll_layer_->SetIsContainerForFixedPositionLayers(true);
+    scroll_layer_->SetBounds(gfx::Size(2 * root_layer->bounds().width(),
+                                       2 * root_layer->bounds().height()));
     scroll_layer_->SetScrollOffset(gfx::Vector2d());
     layer_tree_host()->root_layer()->AddChild(scroll_layer_);
+    // This test requires the page_scale and inner viewport layers to be
+    // identified.
+    layer_tree_host()->RegisterViewportLayers(
+        root_layer, scroll_layer_.get(), NULL);
     layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.5f, 2.f);
   }
 
-  virtual void BeginTest() OVERRIDE {
-    PostSetNeedsCommitToMainThread();
-  }
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
-  virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta, float scale)
-      OVERRIDE {
+  virtual void ApplyScrollAndScale(const gfx::Vector2d& scroll_delta,
+                                   float scale) OVERRIDE {
     gfx::Vector2d offset = scroll_layer_->scroll_offset();
     scroll_layer_->SetScrollOffset(offset + scroll_delta);
     layer_tree_host()->SetPageScaleFactorAndLimits(scale, 0.5f, 2.f);
@@ -1235,12 +1242,17 @@ class TestOpacityChangeLayerDelegate : public ContentLayerClient {
 
   void SetTestLayer(Layer* test_layer) { test_layer_ = test_layer; }
 
-  virtual void PaintContents(SkCanvas*, gfx::Rect, gfx::RectF*) OVERRIDE {
+  virtual void PaintContents(
+      SkCanvas* canvas,
+      const gfx::Rect& clip,
+      gfx::RectF* opaque,
+      ContentLayerClient::GraphicsContextStatus gc_status) OVERRIDE {
     // Set layer opacity to 0.
     if (test_layer_)
       test_layer_->SetOpacity(0.f);
   }
   virtual void DidChangeLayerCanUseLCDText() OVERRIDE {}
+  virtual bool FillsBoundsCompletely() const OVERRIDE { return false; }
 
  private:
   Layer* test_layer_;
@@ -1257,7 +1269,7 @@ class ContentLayerWithUpdateTracking : public ContentLayer {
   void ResetPaintContentsCount() { paint_contents_count_ = 0; }
 
   virtual bool Update(ResourceUpdateQueue* queue,
-                      const OcclusionTracker* occlusion) OVERRIDE {
+                      const OcclusionTracker<Layer>* occlusion) OVERRIDE {
     bool updated = ContentLayer::Update(queue, occlusion);
     paint_contents_count_++;
     return updated;
@@ -1318,6 +1330,7 @@ class NoScaleContentLayer : public ContentLayer {
   virtual void CalculateContentsScale(float ideal_contents_scale,
                                       float device_scale_factor,
                                       float page_scale_factor,
+                                      float maximum_animation_contents_scale,
                                       bool animating_transform_to_screen,
                                       float* contents_scale_x,
                                       float* contents_scale_y,
@@ -1326,6 +1339,7 @@ class NoScaleContentLayer : public ContentLayer {
     Layer::CalculateContentsScale(ideal_contents_scale,
                                   device_scale_factor,
                                   page_scale_factor,
+                                  maximum_animation_contents_scale,
                                   animating_transform_to_screen,
                                   contents_scale_x,
                                   contents_scale_y,
@@ -1478,8 +1492,7 @@ class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest {
   virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
     ASSERT_EQ(0u, layer_tree_host()->settings().max_partial_texture_updates);
 
-    TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
-        impl->output_surface()->context_provider()->Context3d());
+    TestWebGraphicsContext3D* context = TestContext();
 
     switch (impl->active_tree()->source_frame_number()) {
       case 0:
@@ -1492,7 +1505,6 @@ class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest {
         EXPECT_TRUE(context->UsedTexture(context->TextureAt(1)));
 
         context->ResetUsedTextures();
-        PostSetNeedsCommitToMainThread();
         break;
       case 1:
         // Number of textures should be one for scrollbar layer since it was
@@ -1508,7 +1520,6 @@ class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest {
         // New textures should have been used.
         EXPECT_TRUE(context->UsedTexture(context->TextureAt(2)));
         context->ResetUsedTextures();
-        PostSetNeedsCommitToMainThread();
         break;
       case 2:
         EndTest();
@@ -1520,8 +1531,7 @@ class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest {
   }
 
   virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
-    TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
-        impl->output_surface()->context_provider()->Context3d());
+    TestWebGraphicsContext3D* context = TestContext();
 
     if (drew_frame_ == impl->active_tree()->source_frame_number()) {
       EXPECT_EQ(0u, context->NumUsedTextures()) << "For frame " << drew_frame_;
@@ -1532,6 +1542,9 @@ class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest {
     // We draw/ship one texture each frame for each layer.
     EXPECT_EQ(2u, context->NumUsedTextures());
     context->ResetUsedTextures();
+
+    if (!TestEnded())
+      PostSetNeedsCommitToMainThread();
   }
 
   virtual void Layout() OVERRIDE {
@@ -1557,8 +1570,7 @@ class LayerTreeHostTestDelegatingRendererAtomicCommit
   virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
     ASSERT_EQ(0u, layer_tree_host()->settings().max_partial_texture_updates);
 
-    TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
-        impl->output_surface()->context_provider()->Context3d());
+    TestWebGraphicsContext3D* context = TestContext();
 
     switch (impl->active_tree()->source_frame_number()) {
       case 0:
@@ -1570,7 +1582,6 @@ class LayerTreeHostTestDelegatingRendererAtomicCommit
         EXPECT_TRUE(context->UsedTexture(context->TextureAt(0)));
         EXPECT_TRUE(context->UsedTexture(context->TextureAt(1)));
         context->ResetUsedTextures();
-        PostSetNeedsCommitToMainThread();
         break;
       case 1:
         // Number of textures should be doubled as the first context layer
@@ -1589,7 +1600,6 @@ class LayerTreeHostTestDelegatingRendererAtomicCommit
         EXPECT_TRUE(context->UsedTexture(context->TextureAt(2)));
         EXPECT_TRUE(context->UsedTexture(context->TextureAt(3)));
         context->ResetUsedTextures();
-        PostSetNeedsCommitToMainThread();
         break;
       case 2:
         EndTest();
@@ -1607,9 +1617,9 @@ MULTI_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(
 static void SetLayerPropertiesForTesting(Layer* layer,
                                          Layer* parent,
                                          const gfx::Transform& transform,
-                                         gfx::PointF anchor,
-                                         gfx::PointF position,
-                                         gfx::Size bounds,
+                                         const gfx::PointF& anchor,
+                                         const gfx::PointF& position,
+                                         const gfx::Size& bounds,
                                          bool opaque) {
   layer->RemoveAllChildren();
   if (parent)
@@ -1646,9 +1656,7 @@ class LayerTreeHostTestAtomicCommitWithPartialUpdate
     LayerTreeHostTest::SetupTree();
   }
 
-  virtual void BeginTest() OVERRIDE {
-    PostSetNeedsCommitToMainThread();
-  }
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
   virtual void DidCommitAndDrawFrame() OVERRIDE {
     switch (layer_tree_host()->source_frame_number()) {
@@ -1680,8 +1688,7 @@ class LayerTreeHostTestAtomicCommitWithPartialUpdate
   virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
     ASSERT_EQ(1u, layer_tree_host()->settings().max_partial_texture_updates);
 
-    TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
-        impl->output_surface()->context_provider()->Context3d());
+    TestWebGraphicsContext3D* context = TestContext();
 
     switch (impl->active_tree()->source_frame_number()) {
       case 0:
@@ -1771,16 +1778,15 @@ class LayerTreeHostTestAtomicCommitWithPartialUpdate
   virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
     EXPECT_LT(impl->active_tree()->source_frame_number(), 5);
 
-    TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
-        impl->output_surface()->context_provider()->Context3d());
+    TestWebGraphicsContext3D* context = TestContext();
 
     // Number of textures used for drawing should one per layer except for
     // frame 3 where the viewport only contains one layer.
     if (impl->active_tree()->source_frame_number() == 3) {
       EXPECT_EQ(1u, context->NumUsedTextures());
     } else {
-      EXPECT_EQ(2u, context->NumUsedTextures()) <<
-        "For frame " << impl->active_tree()->source_frame_number();
+      EXPECT_EQ(2u, context->NumUsedTextures())
+          << "For frame " << impl->active_tree()->source_frame_number();
     }
 
     context->ResetUsedTextures();
@@ -1812,7 +1818,6 @@ class LayerTreeHostTestFinishAllRendering : public LayerTreeHostTest {
       return;
     once_ = true;
     layer_tree_host()->SetNeedsRedraw();
-    layer_tree_host()->AcquireLayerTextures();
     {
       base::AutoLock lock(lock_);
       draw_count_ = 0;
@@ -1887,24 +1892,28 @@ class LayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit
     LayerTreeHostTest::SetupTree();
   }
 
-  virtual void BeginTest() OVERRIDE {
-    PostSetNeedsCommitToMainThread();
-  }
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
     Renderer* renderer = host_impl->renderer();
     RenderPass::Id surface1_render_pass_id = host_impl->active_tree()
-        ->root_layer()->children()[0]->render_surface()->RenderPassId();
-    RenderPass::Id surface2_render_pass_id =
-        host_impl->active_tree()->root_layer()->children()[0]->children()[0]
-        ->render_surface()->RenderPassId();
+                                                 ->root_layer()
+                                                 ->children()[0]
+                                                 ->render_surface()
+                                                 ->RenderPassId();
+    RenderPass::Id surface2_render_pass_id = host_impl->active_tree()
+                                                 ->root_layer()
+                                                 ->children()[0]
+                                                 ->children()[0]
+                                                 ->render_surface()
+                                                 ->RenderPassId();
 
     switch (host_impl->active_tree()->source_frame_number()) {
       case 0:
-        EXPECT_TRUE(renderer->HasAllocatedResourcesForTesting(
-            surface1_render_pass_id));
-        EXPECT_TRUE(renderer->HasAllocatedResourcesForTesting(
-            surface2_render_pass_id));
+        EXPECT_TRUE(
+            renderer->HasAllocatedResourcesForTesting(surface1_render_pass_id));
+        EXPECT_TRUE(
+            renderer->HasAllocatedResourcesForTesting(surface2_render_pass_id));
 
         // Reduce the memory limit to only fit the root layer and one render
         // surface. This prevents any contents drawing into surfaces
@@ -1912,10 +1921,10 @@ class LayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit
         host_impl->SetMemoryPolicy(ManagedMemoryPolicy(100 * 100 * 4 * 2));
         break;
       case 1:
-        EXPECT_FALSE(renderer->HasAllocatedResourcesForTesting(
-            surface1_render_pass_id));
-        EXPECT_FALSE(renderer->HasAllocatedResourcesForTesting(
-            surface2_render_pass_id));
+        EXPECT_FALSE(
+            renderer->HasAllocatedResourcesForTesting(surface1_render_pass_id));
+        EXPECT_FALSE(
+            renderer->HasAllocatedResourcesForTesting(surface2_render_pass_id));
 
         EndTest();
         break;
@@ -1952,7 +1961,7 @@ class EvictionTestLayer : public Layer {
   }
 
   virtual bool Update(ResourceUpdateQueue*,
-                      const OcclusionTracker*) OVERRIDE;
+                      const OcclusionTracker<Layer>*) OVERRIDE;
   virtual bool DrawsContent() const OVERRIDE { return true; }
 
   virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
@@ -1974,8 +1983,7 @@ class EvictionTestLayer : public Layer {
     texture_ = PrioritizedResource::Create(
         layer_tree_host()->contents_texture_manager());
     texture_->SetDimensions(gfx::Size(10, 10), RGBA_8888);
-    bitmap_.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
-    bitmap_.allocPixels();
+    bitmap_.allocN32Pixels(10, 10);
   }
 
   scoped_ptr<PrioritizedResource> texture_;
@@ -2013,7 +2021,7 @@ void EvictionTestLayer::SetTexturePriorities(const PriorityCalculator&) {
 }
 
 bool EvictionTestLayer::Update(ResourceUpdateQueue* queue,
-                               const OcclusionTracker*) {
+                               const OcclusionTracker<Layer>* occlusion) {
   CreateTextureIfNeeded();
   if (!texture_)
     return false;
@@ -2307,7 +2315,7 @@ class LayerTreeHostWithProxy : public LayerTreeHost {
                          scoped_ptr<FakeProxy> proxy)
       : LayerTreeHost(client, NULL, settings) {
     proxy->SetLayerTreeHost(this);
-    EXPECT_TRUE(InitializeForTesting(proxy.PassAs<Proxy>()));
+    InitializeForTesting(proxy.PassAs<Proxy>());
   }
 };
 
@@ -2372,8 +2380,10 @@ TEST(LayerTreeHostTest, PartialUpdatesWithGLRenderer) {
   LayerTreeSettings settings;
   settings.max_partial_texture_updates = 4;
 
-  scoped_ptr<LayerTreeHost> host =
-      LayerTreeHost::Create(&client, NULL, settings, NULL);
+  scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+      new TestSharedBitmapManager());
+  scoped_ptr<LayerTreeHost> host = LayerTreeHost::CreateSingleThreaded(
+      &client, &client, shared_bitmap_manager.get(), settings);
   EXPECT_TRUE(host->InitializeOutputSurfaceIfNeeded());
   EXPECT_EQ(4u, host->settings().max_partial_texture_updates);
 }
@@ -2384,8 +2394,10 @@ TEST(LayerTreeHostTest, PartialUpdatesWithSoftwareRenderer) {
   LayerTreeSettings settings;
   settings.max_partial_texture_updates = 4;
 
-  scoped_ptr<LayerTreeHost> host =
-      LayerTreeHost::Create(&client, NULL, settings, NULL);
+  scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+      new TestSharedBitmapManager());
+  scoped_ptr<LayerTreeHost> host = LayerTreeHost::CreateSingleThreaded(
+      &client, &client, shared_bitmap_manager.get(), settings);
   EXPECT_TRUE(host->InitializeOutputSurfaceIfNeeded());
   EXPECT_EQ(4u, host->settings().max_partial_texture_updates);
 }
@@ -2396,8 +2408,10 @@ TEST(LayerTreeHostTest, PartialUpdatesWithDelegatingRendererAndGLContent) {
   LayerTreeSettings settings;
   settings.max_partial_texture_updates = 4;
 
-  scoped_ptr<LayerTreeHost> host =
-      LayerTreeHost::Create(&client, NULL, settings, NULL);
+  scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+      new TestSharedBitmapManager());
+  scoped_ptr<LayerTreeHost> host = LayerTreeHost::CreateSingleThreaded(
+      &client, &client, shared_bitmap_manager.get(), settings);
   EXPECT_TRUE(host->InitializeOutputSurfaceIfNeeded());
   EXPECT_EQ(0u, host->MaxPartialTextureUpdates());
 }
@@ -2409,8 +2423,10 @@ TEST(LayerTreeHostTest,
   LayerTreeSettings settings;
   settings.max_partial_texture_updates = 4;
 
-  scoped_ptr<LayerTreeHost> host =
-      LayerTreeHost::Create(&client, NULL, settings, NULL);
+  scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+      new TestSharedBitmapManager());
+  scoped_ptr<LayerTreeHost> host = LayerTreeHost::CreateSingleThreaded(
+      &client, &client, shared_bitmap_manager.get(), settings);
   EXPECT_TRUE(host->InitializeOutputSurfaceIfNeeded());
   EXPECT_EQ(0u, host->MaxPartialTextureUpdates());
 }
@@ -2444,8 +2460,7 @@ class LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted
           layer_tree_host()->contents_texture_manager()->MemoryUseBytes());
     } else {
       EXPECT_EQ(
-          0u,
-          layer_tree_host()->contents_texture_manager()->MemoryUseBytes());
+          0u, layer_tree_host()->contents_texture_manager()->MemoryUseBytes());
     }
 
     // Make sure that contents textures are marked as having been
@@ -2511,15 +2526,18 @@ class LayerTreeHostTestLCDNotification : public LayerTreeHostTest {
     int paint_count() const { return paint_count_; }
     int lcd_notification_count() const { return lcd_notification_count_; }
 
-    virtual void PaintContents(SkCanvas* canvas,
-                               gfx::Rect clip,
-                               gfx::RectF* opaque) OVERRIDE {
+    virtual void PaintContents(
+        SkCanvas* canvas,
+        const gfx::Rect& clip,
+        gfx::RectF* opaque,
+        ContentLayerClient::GraphicsContextStatus gc_status) OVERRIDE {
       ++paint_count_;
     }
     virtual void DidChangeLayerCanUseLCDText() OVERRIDE {
       ++lcd_notification_count_;
       layer_->SetNeedsDisplay();
     }
+    virtual bool FillsBoundsCompletely() const OVERRIDE { return false; }
 
    private:
     Layer* layer_;
@@ -2588,25 +2606,25 @@ class LayerTreeHostTestLCDNotification : public LayerTreeHostTest {
 
 SINGLE_THREAD_TEST_F(LayerTreeHostTestLCDNotification);
 
-// Verify that the BeginImplFrame notification is used to initiate rendering.
-class LayerTreeHostTestBeginImplFrameNotification : public LayerTreeHostTest {
+// Verify that the BeginFrame notification is used to initiate rendering.
+class LayerTreeHostTestBeginFrameNotification : public LayerTreeHostTest {
  public:
   virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
-    settings->begin_impl_frame_scheduling_enabled = true;
+    settings->begin_frame_scheduling_enabled = true;
   }
 
   virtual void BeginTest() OVERRIDE {
-    // This will trigger a SetNeedsBeginImplFrame which will trigger a
-    // BeginImplFrame.
+    // This will trigger a SetNeedsBeginFrame which will trigger a
+    // BeginFrame.
     PostSetNeedsCommitToMainThread();
   }
 
-  virtual bool PrepareToDrawOnThread(
+  virtual DrawSwapReadbackResult::DrawResult PrepareToDrawOnThread(
       LayerTreeHostImpl* host_impl,
       LayerTreeHostImpl::FrameData* frame,
-      bool result) OVERRIDE {
+      DrawSwapReadbackResult::DrawResult draw_result) OVERRIDE {
     EndTest();
-    return true;
+    return DrawSwapReadbackResult::DRAW_SUCCESS;
   }
 
   virtual void AfterTest() OVERRIDE {}
@@ -2615,24 +2633,24 @@ class LayerTreeHostTestBeginImplFrameNotification : public LayerTreeHostTest {
   base::TimeTicks frame_time_;
 };
 
-MULTI_THREAD_TEST_F(LayerTreeHostTestBeginImplFrameNotification);
+MULTI_THREAD_TEST_F(LayerTreeHostTestBeginFrameNotification);
 
-class LayerTreeHostTestBeginImplFrameNotificationShutdownWhileEnabled
+class LayerTreeHostTestBeginFrameNotificationShutdownWhileEnabled
     : public LayerTreeHostTest {
  public:
   virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
-    settings->begin_impl_frame_scheduling_enabled = true;
+    settings->begin_frame_scheduling_enabled = true;
     settings->using_synchronous_renderer_compositor = true;
   }
 
   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
   virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
-    // The BeginImplFrame notification is turned off now but will get enabled
+    // The BeginFrame notification is turned off now but will get enabled
     // once we return. End test while it's enabled.
     ImplThreadTaskRunner()->PostTask(
         FROM_HERE,
-        base::Bind(&LayerTreeHostTestBeginImplFrameNotification::EndTest,
+        base::Bind(&LayerTreeHostTestBeginFrameNotification::EndTest,
                    base::Unretained(this)));
   }
 
@@ -2640,33 +2658,40 @@ class LayerTreeHostTestBeginImplFrameNotificationShutdownWhileEnabled
 };
 
 MULTI_THREAD_TEST_F(
-    LayerTreeHostTestBeginImplFrameNotificationShutdownWhileEnabled);
+    LayerTreeHostTestBeginFrameNotificationShutdownWhileEnabled);
 
 class LayerTreeHostTestAbortedCommitDoesntStall : public LayerTreeHostTest {
  protected:
   LayerTreeHostTestAbortedCommitDoesntStall()
-      : commit_count_(0), commit_complete_count_(0) {}
+      : commit_count_(0), commit_abort_count_(0), commit_complete_count_(0) {}
 
   virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
-    settings->begin_impl_frame_scheduling_enabled = true;
+    settings->begin_frame_scheduling_enabled = true;
   }
 
   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
   virtual void DidCommit() OVERRIDE {
     commit_count_++;
-    if (commit_count_ == 2) {
-      // A commit was just aborted, request a real commit now to make sure a
+    if (commit_count_ == 4) {
+      // After two aborted commits, request a real commit now to make sure a
       // real commit following an aborted commit will still complete and
       // end the test even when the Impl thread is idle.
       layer_tree_host()->SetNeedsCommit();
     }
   }
 
+  virtual void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl,
+                                             bool did_handle) OVERRIDE {
+    commit_abort_count_++;
+    // Initiate another abortable commit.
+    host_impl->SetNeedsCommit();
+  }
+
   virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
     commit_complete_count_++;
     if (commit_complete_count_ == 1) {
-      // Initiate an aborted commit after the first commit.
+      // Initiate an abortable commit after the first commit.
       host_impl->SetNeedsCommit();
     } else {
       EndTest();
@@ -2674,11 +2699,13 @@ class LayerTreeHostTestAbortedCommitDoesntStall : public LayerTreeHostTest {
   }
 
   virtual void AfterTest() OVERRIDE {
-    EXPECT_EQ(commit_count_, 3);
+    EXPECT_EQ(commit_count_, 5);
+    EXPECT_EQ(commit_abort_count_, 3);
     EXPECT_EQ(commit_complete_count_, 2);
   }
 
   int commit_count_;
+  int commit_abort_count_;
   int commit_complete_count_;
 };
 
@@ -2719,16 +2746,13 @@ class LayerTreeHostTestUninvertibleTransformDoesNotBlockActivation
     layer_tree_host()->root_layer()->AddChild(layer);
   }
 
-  virtual void BeginTest() OVERRIDE {
-    PostSetNeedsCommitToMainThread();
-  }
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
   virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
     EndTest();
   }
 
-  virtual void AfterTest() OVERRIDE {
-  }
+  virtual void AfterTest() OVERRIDE {}
 
   FakeContentLayerClient client_;
 };
@@ -2745,14 +2769,18 @@ class LayerTreeHostTestChangeLayerPropertiesInPaintContents
 
     void set_layer(Layer* layer) { layer_ = layer; }
 
-    virtual void PaintContents(SkCanvas* canvas,
-                               gfx::Rect clip,
-                               gfx::RectF* opaque) OVERRIDE {
+    virtual void PaintContents(
+        SkCanvas* canvas,
+        const gfx::Rect& clip,
+        gfx::RectF* opaque,
+        ContentLayerClient::GraphicsContextStatus gc_status) OVERRIDE {
       layer_->SetBounds(gfx::Size(2, 2));
     }
 
     virtual void DidChangeLayerCanUseLCDText() OVERRIDE {}
 
+    virtual bool FillsBoundsCompletely() const OVERRIDE { return false; }
+
    private:
     Layer* layer_;
   };
@@ -2795,44 +2823,48 @@ SINGLE_THREAD_TEST_F(LayerTreeHostTestChangeLayerPropertiesInPaintContents);
 class MockIOSurfaceWebGraphicsContext3D : public TestWebGraphicsContext3D {
  public:
   MockIOSurfaceWebGraphicsContext3D() {
-    test_capabilities_.iosurface = true;
-    test_capabilities_.texture_rectangle = true;
+    test_capabilities_.gpu.iosurface = true;
+    test_capabilities_.gpu.texture_rectangle = true;
   }
 
-  virtual WebKit::WebGLId createTexture() OVERRIDE {
+  virtual GLuint createTexture() OVERRIDE {
     return 1;
   }
-
-  MOCK_METHOD1(activeTexture, void(WebKit::WGC3Denum texture));
-  MOCK_METHOD2(bindTexture, void(WebKit::WGC3Denum target,
-                                 WebKit::WebGLId texture_id));
-  MOCK_METHOD3(texParameteri, void(WebKit::WGC3Denum target,
-                                   WebKit::WGC3Denum pname,
-                                   WebKit::WGC3Dint param));
-  MOCK_METHOD5(texImageIOSurface2DCHROMIUM, void(WebKit::WGC3Denum target,
-                                                 WebKit::WGC3Dint width,
-                                                 WebKit::WGC3Dint height,
-                                                 WebKit::WGC3Duint ioSurfaceId,
-                                                 WebKit::WGC3Duint plane));
-  MOCK_METHOD4(drawElements, void(WebKit::WGC3Denum mode,
-                                  WebKit::WGC3Dsizei count,
-                                  WebKit::WGC3Denum type,
-                                  WebKit::WGC3Dintptr offset));
-  MOCK_METHOD1(deleteTexture, void(WebKit::WGC3Denum texture));
+  MOCK_METHOD1(activeTexture, void(GLenum texture));
+  MOCK_METHOD2(bindTexture, void(GLenum target,
+                                 GLuint texture_id));
+  MOCK_METHOD3(texParameteri, void(GLenum target,
+                                   GLenum pname,
+                                   GLint param));
+  MOCK_METHOD5(texImageIOSurface2DCHROMIUM, void(GLenum target,
+                                                 GLint width,
+                                                 GLint height,
+                                                 GLuint ioSurfaceId,
+                                                 GLuint plane));
+  MOCK_METHOD4(drawElements, void(GLenum mode,
+                                  GLsizei count,
+                                  GLenum type,
+                                  GLintptr offset));
+  MOCK_METHOD1(deleteTexture, void(GLenum texture));
+  MOCK_METHOD2(produceTextureCHROMIUM,
+               void(GLenum target, const GLbyte* mailbox));
 };
 
-
 class LayerTreeHostTestIOSurfaceDrawing : public LayerTreeHostTest {
  protected:
-  virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
+  virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
       OVERRIDE {
     scoped_ptr<MockIOSurfaceWebGraphicsContext3D> mock_context_owned(
         new MockIOSurfaceWebGraphicsContext3D);
     mock_context_ = mock_context_owned.get();
 
-    scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
-        mock_context_owned.PassAs<TestWebGraphicsContext3D>()));
-    return output_surface.Pass();
+    if (delegating_renderer()) {
+      return FakeOutputSurface::CreateDelegating3d(
+          mock_context_owned.PassAs<TestWebGraphicsContext3D>());
+    } else {
+      return FakeOutputSurface::Create3d(
+          mock_context_owned.PassAs<TestWebGraphicsContext3D>());
+    }
   }
 
   virtual void SetupTree() OVERRIDE {
@@ -2847,71 +2879,90 @@ class LayerTreeHostTestIOSurfaceDrawing : public LayerTreeHostTest {
     io_surface_layer->SetBounds(gfx::Size(10, 10));
     io_surface_layer->SetAnchorPoint(gfx::PointF());
     io_surface_layer->SetIsDrawable(true);
+    io_surface_layer->SetContentsOpaque(true);
     io_surface_layer->SetIOSurfaceProperties(io_surface_id_, io_surface_size_);
     layer_tree_host()->root_layer()->AddChild(io_surface_layer);
   }
 
-  virtual void BeginTest() OVERRIDE {
-    PostSetNeedsCommitToMainThread();
-  }
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
   virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+    EXPECT_EQ(0u, host_impl->resource_provider()->num_resources());
     // In WillDraw, the IOSurfaceLayer sets up the io surface texture.
 
-    EXPECT_CALL(*mock_context_, activeTexture(_))
-        .Times(0);
+    EXPECT_CALL(*mock_context_, activeTexture(_)).Times(0);
     EXPECT_CALL(*mock_context_, bindTexture(GL_TEXTURE_RECTANGLE_ARB, 1))
         .Times(AtLeast(1));
-    EXPECT_CALL(*mock_context_, texParameteri(GL_TEXTURE_RECTANGLE_ARB,
-                                              GL_TEXTURE_MIN_FILTER,
-                                              GL_LINEAR))
-        .Times(1);
-    EXPECT_CALL(*mock_context_, texParameteri(GL_TEXTURE_RECTANGLE_ARB,
-                                              GL_TEXTURE_MAG_FILTER,
-                                              GL_LINEAR))
+    EXPECT_CALL(*mock_context_,
+                texParameteri(
+                    GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR))
         .Times(1);
-    EXPECT_CALL(*mock_context_, texParameteri(GL_TEXTURE_RECTANGLE_ARB,
-                                              GL_TEXTURE_WRAP_S,
-                                              GL_CLAMP_TO_EDGE))
+    EXPECT_CALL(*mock_context_,
+                texParameteri(
+                    GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR))
         .Times(1);
-    EXPECT_CALL(*mock_context_, texParameteri(GL_TEXTURE_RECTANGLE_ARB,
-                                              GL_TEXTURE_WRAP_T,
-                                              GL_CLAMP_TO_EDGE))
-        .Times(1);
-
-    EXPECT_CALL(*mock_context_, texImageIOSurface2DCHROMIUM(
-        GL_TEXTURE_RECTANGLE_ARB,
-        io_surface_size_.width(),
-        io_surface_size_.height(),
-        io_surface_id_,
-        0))
-        .Times(1);
-
-    EXPECT_CALL(*mock_context_, bindTexture(_, 0))
-        .Times(AnyNumber());
-  }
-
-  virtual bool PrepareToDrawOnThread(
+    EXPECT_CALL(*mock_context_,
+                texParameteri(GL_TEXTURE_RECTANGLE_ARB,
+                              GL_TEXTURE_POOL_CHROMIUM,
+                              GL_TEXTURE_POOL_UNMANAGED_CHROMIUM)).Times(1);
+    EXPECT_CALL(*mock_context_,
+                texParameteri(GL_TEXTURE_RECTANGLE_ARB,
+                              GL_TEXTURE_WRAP_S,
+                              GL_CLAMP_TO_EDGE)).Times(1);
+    EXPECT_CALL(*mock_context_,
+                texParameteri(GL_TEXTURE_RECTANGLE_ARB,
+                              GL_TEXTURE_WRAP_T,
+                              GL_CLAMP_TO_EDGE)).Times(1);
+
+    EXPECT_CALL(*mock_context_,
+                texImageIOSurface2DCHROMIUM(GL_TEXTURE_RECTANGLE_ARB,
+                                            io_surface_size_.width(),
+                                            io_surface_size_.height(),
+                                            io_surface_id_,
+                                            0)).Times(1);
+
+    EXPECT_CALL(*mock_context_, bindTexture(_, 0)).Times(AnyNumber());
+  }
+
+  virtual DrawSwapReadbackResult::DrawResult PrepareToDrawOnThread(
       LayerTreeHostImpl* host_impl,
       LayerTreeHostImpl::FrameData* frame,
-      bool result) OVERRIDE {
+      DrawSwapReadbackResult::DrawResult draw_result) OVERRIDE {
     Mock::VerifyAndClearExpectations(&mock_context_);
+    ResourceProvider* resource_provider = host_impl->resource_provider();
+    EXPECT_EQ(1u, resource_provider->num_resources());
+    CHECK_EQ(1u, frame->render_passes.size());
+    CHECK_LE(1u, frame->render_passes[0]->quad_list.size());
+    const DrawQuad* quad = frame->render_passes[0]->quad_list[0];
+    CHECK_EQ(DrawQuad::IO_SURFACE_CONTENT, quad->material);
+    const IOSurfaceDrawQuad* io_surface_draw_quad =
+        IOSurfaceDrawQuad::MaterialCast(quad);
+    EXPECT_SIZE_EQ(io_surface_size_, io_surface_draw_quad->io_surface_size);
+    EXPECT_NE(0u, io_surface_draw_quad->io_surface_resource_id);
+    EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_RECTANGLE_ARB),
+              resource_provider->TargetForTesting(
+                  io_surface_draw_quad->io_surface_resource_id));
 
-    // The io surface layer's texture is drawn.
-    EXPECT_CALL(*mock_context_, activeTexture(GL_TEXTURE0))
-        .Times(AtLeast(1));
     EXPECT_CALL(*mock_context_, bindTexture(GL_TEXTURE_RECTANGLE_ARB, 1))
         .Times(1);
-    EXPECT_CALL(*mock_context_, drawElements(GL_TRIANGLES, 6, _, _))
-        .Times(AtLeast(1));
+    if (delegating_renderer()) {
+      // The io surface layer's resource should be sent to the parent.
+      EXPECT_CALL(*mock_context_,
+                  produceTextureCHROMIUM(GL_TEXTURE_RECTANGLE_ARB, _)).Times(1);
+    } else {
+      // The io surface layer's texture is drawn.
+      EXPECT_CALL(*mock_context_, activeTexture(GL_TEXTURE0)).Times(AtLeast(1));
+      EXPECT_CALL(*mock_context_, drawElements(GL_TRIANGLES, 6, _, _))
+          .Times(AtLeast(1));
+    }
 
-    return result;
+    return draw_result;
   }
 
   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
     Mock::VerifyAndClearExpectations(&mock_context_);
 
-    EXPECT_CALL(*mock_context_, deleteTexture(1)).Times(1);
+    EXPECT_CALL(*mock_context_, deleteTexture(1)).Times(AtLeast(1));
     EndTest();
   }
 
@@ -2922,1281 +2973,1102 @@ class LayerTreeHostTestIOSurfaceDrawing : public LayerTreeHostTest {
   gfx::Size io_surface_size_;
 };
 
-// TODO(danakj): IOSurface layer can not be transported. crbug.com/239335
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
-    LayerTreeHostTestIOSurfaceDrawing);
-
-class LayerTreeHostTestAsyncReadback : public LayerTreeHostTest {
- protected:
-  virtual void SetupTree() OVERRIDE {
-    root = FakeContentLayer::Create(&client_);
-    root->SetBounds(gfx::Size(20, 20));
-
-    child = FakeContentLayer::Create(&client_);
-    child->SetBounds(gfx::Size(10, 10));
-    root->AddChild(child);
-
-    layer_tree_host()->SetRootLayer(root);
-    LayerTreeHostTest::SetupTree();
-  }
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestIOSurfaceDrawing);
 
+class LayerTreeHostTestNumFramesPending : public LayerTreeHostTest {
+ public:
   virtual void BeginTest() OVERRIDE {
+    frame_ = 0;
     PostSetNeedsCommitToMainThread();
   }
 
-  virtual void DidCommitAndDrawFrame() OVERRIDE {
-    WaitForCallback();
-  }
+  // Round 1: commit + draw
+  // Round 2: commit only (no draw/swap)
+  // Round 3: draw only (no commit)
+  // Round 4: composite & readback (2 commits, no draw/swap)
+  // Round 5: commit + draw
 
-  void WaitForCallback() {
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(
-            &LayerTreeHostTestAsyncReadback::NextStep,
-            base::Unretained(this)));
+  virtual void DidCommit() OVERRIDE {
+    int commit = layer_tree_host()->source_frame_number();
+    switch (commit) {
+      case 2:
+        // Round 2 done.
+        EXPECT_EQ(1, frame_);
+        layer_tree_host()->SetNeedsRedraw();
+        break;
+      case 3:
+        // CompositeAndReadback in Round 4, first commit.
+        EXPECT_EQ(2, frame_);
+        break;
+      case 4:
+        // Round 4 done.
+        EXPECT_EQ(2, frame_);
+        layer_tree_host()->SetNeedsCommit();
+        layer_tree_host()->SetNeedsRedraw();
+        break;
+    }
   }
 
-  void NextStep() {
-    int frame = layer_tree_host()->source_frame_number();
-    switch (frame) {
+  virtual void DidCompleteSwapBuffers() OVERRIDE {
+    int commit = layer_tree_host()->source_frame_number();
+    ++frame_;
+    char pixels[4] = {0};
+    switch (frame_) {
       case 1:
-        child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
-            base::Bind(&LayerTreeHostTestAsyncReadback::CopyOutputCallback,
-                       base::Unretained(this))));
-        EXPECT_EQ(0u, callbacks_.size());
+        // Round 1 done.
+        EXPECT_EQ(1, commit);
+        layer_tree_host()->SetNeedsCommit();
         break;
       case 2:
-        if (callbacks_.size() < 1u) {
-          WaitForCallback();
-          return;
-        }
-        EXPECT_EQ(1u, callbacks_.size());
-        EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[0].ToString());
-
-        child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
-            base::Bind(&LayerTreeHostTestAsyncReadback::CopyOutputCallback,
-                       base::Unretained(this))));
-        root->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
-            base::Bind(&LayerTreeHostTestAsyncReadback::CopyOutputCallback,
-                       base::Unretained(this))));
-        child->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
-            base::Bind(&LayerTreeHostTestAsyncReadback::CopyOutputCallback,
-                       base::Unretained(this))));
-        EXPECT_EQ(1u, callbacks_.size());
+        // Round 3 done.
+        EXPECT_EQ(2, commit);
+        layer_tree_host()->CompositeAndReadback(pixels, gfx::Rect(0, 0, 1, 1));
         break;
       case 3:
-        if (callbacks_.size() < 4u) {
-          WaitForCallback();
-          return;
-        }
-        EXPECT_EQ(4u, callbacks_.size());
-        // The child was copied to a bitmap and passed back twice.
-        EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[1].ToString());
-        EXPECT_EQ(gfx::Size(10, 10).ToString(), callbacks_[2].ToString());
-        // The root was copied to a bitmap and passed back also.
-        EXPECT_EQ(gfx::Size(20, 20).ToString(), callbacks_[3].ToString());
+        // Round 5 done.
+        EXPECT_EQ(5, commit);
         EndTest();
         break;
     }
   }
 
-  void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
-    EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
-    EXPECT_TRUE(result->HasBitmap());
-    scoped_ptr<SkBitmap> bitmap = result->TakeBitmap().Pass();
-    EXPECT_EQ(result->size().ToString(),
-              gfx::Size(bitmap->width(), bitmap->height()).ToString());
-    callbacks_.push_back(result->size());
-  }
+  virtual void AfterTest() OVERRIDE {}
 
-  virtual void AfterTest() OVERRIDE {
-    EXPECT_EQ(4u, callbacks_.size());
-  }
-
-  virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
-      OVERRIDE {
-    scoped_ptr<FakeOutputSurface> output_surface;
-    if (use_gl_renderer_) {
-      output_surface = FakeOutputSurface::Create3d().Pass();
-    } else {
-      output_surface = FakeOutputSurface::CreateSoftware(
-          make_scoped_ptr(new SoftwareOutputDevice)).Pass();
-    }
-    return output_surface.PassAs<OutputSurface>();
-  }
-
-  bool use_gl_renderer_;
-  std::vector<gfx::Size> callbacks_;
-  FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root;
-  scoped_refptr<FakeContentLayer> child;
+ protected:
+  int frame_;
 };
 
-// Readback can't be done with a delegating renderer.
-TEST_F(LayerTreeHostTestAsyncReadback, GLRenderer_RunSingleThread) {
-  use_gl_renderer_ = true;
-  RunTest(false, false, false);
-}
-
-TEST_F(LayerTreeHostTestAsyncReadback,
-       GLRenderer_RunMultiThread_MainThreadPainting) {
-  use_gl_renderer_ = true;
-  RunTest(true, false, false);
+// Flaky on all platforms: http://crbug.com/327498
+TEST_F(LayerTreeHostTestNumFramesPending, DISABLED_DelegatingRenderer) {
+  RunTest(true, true, true);
 }
 
-TEST_F(LayerTreeHostTestAsyncReadback, SoftwareRenderer_RunSingleThread) {
-  use_gl_renderer_ = false;
-  RunTest(false, false, false);
+TEST_F(LayerTreeHostTestNumFramesPending, DISABLED_GLRenderer) {
+  RunTest(true, false, true);
 }
 
-TEST_F(LayerTreeHostTestAsyncReadback,
-       SoftwareRenderer_RunMultiThread_MainThreadPainting) {
-  use_gl_renderer_ = false;
-  RunTest(true, false, false);
-}
+class LayerTreeHostTestDeferredInitialize : public LayerTreeHostTest {
+ public:
+  virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
+    // PictureLayer can only be used with impl side painting enabled.
+    settings->impl_side_painting = true;
+  }
 
-class LayerTreeHostTestAsyncReadbackLayerDestroyed : public LayerTreeHostTest {
- protected:
   virtual void SetupTree() OVERRIDE {
-    root_ = FakeContentLayer::Create(&client_);
-    root_->SetBounds(gfx::Size(20, 20));
-
-    main_destroyed_ = FakeContentLayer::Create(&client_);
-    main_destroyed_->SetBounds(gfx::Size(15, 15));
-    root_->AddChild(main_destroyed_);
-
-    impl_destroyed_ = FakeContentLayer::Create(&client_);
-    impl_destroyed_->SetBounds(gfx::Size(10, 10));
-    root_->AddChild(impl_destroyed_);
-
-    layer_tree_host()->SetRootLayer(root_);
+    layer_ = FakePictureLayer::Create(&client_);
+    // Force commits to not be aborted so new frames get drawn, otherwise
+    // the renderer gets deferred initialized but nothing new needs drawing.
+    layer_->set_always_update_resources(true);
+    layer_tree_host()->SetRootLayer(layer_);
     LayerTreeHostTest::SetupTree();
   }
 
   virtual void BeginTest() OVERRIDE {
-    callback_count_ = 0;
+    did_initialize_gl_ = false;
+    did_release_gl_ = false;
+    last_source_frame_number_drawn_ = -1;  // Never drawn.
     PostSetNeedsCommitToMainThread();
   }
 
-  virtual void DidCommit() OVERRIDE {
-    int frame = layer_tree_host()->source_frame_number();
-    switch (frame) {
-      case 1:
-        main_destroyed_->RequestCopyOfOutput(
-            CopyOutputRequest::CreateBitmapRequest(base::Bind(
-                &LayerTreeHostTestAsyncReadbackLayerDestroyed::
-                    CopyOutputCallback,
-                base::Unretained(this))));
-        impl_destroyed_->RequestCopyOfOutput(
-            CopyOutputRequest::CreateBitmapRequest(base::Bind(
-                &LayerTreeHostTestAsyncReadbackLayerDestroyed::
-                    CopyOutputCallback,
-                base::Unretained(this))));
-        EXPECT_EQ(0, callback_count_);
+  virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
+      OVERRIDE {
+    scoped_ptr<TestWebGraphicsContext3D> context3d(
+        TestWebGraphicsContext3D::Create());
 
-        // Destroy the main thread layer right away.
-        main_destroyed_->RemoveFromParent();
-        main_destroyed_ = NULL;
+    return FakeOutputSurface::CreateDeferredGL(
+        scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice));
+  }
 
-        // Should callback with a NULL bitmap.
-        EXPECT_EQ(1, callback_count_);
+  virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+    ASSERT_TRUE(host_impl->RootLayer());
+    FakePictureLayerImpl* layer_impl =
+        static_cast<FakePictureLayerImpl*>(host_impl->RootLayer());
 
-        // Prevent drawing so we can't make a copy of the impl_destroyed layer.
-        layer_tree_host()->SetViewportSize(gfx::Size());
-        break;
-      case 2:
-        // Flush the message loops and make sure the callbacks run.
-        layer_tree_host()->SetNeedsCommit();
-        break;
-      case 3:
-        // No drawing means no readback yet.
-        EXPECT_EQ(1, callback_count_);
+    // The same frame can be draw multiple times if new visible tiles are
+    // rasterized. But we want to make sure we only post DeferredInitialize
+    // and ReleaseGL once, so early out if the same frame is drawn again.
+    if (last_source_frame_number_drawn_ ==
+        host_impl->active_tree()->source_frame_number())
+      return;
 
-        // Destroy the impl thread layer.
-        impl_destroyed_->RemoveFromParent();
-        impl_destroyed_ = NULL;
+    last_source_frame_number_drawn_ =
+        host_impl->active_tree()->source_frame_number();
 
-        // No callback yet because it's on the impl side.
-        EXPECT_EQ(1, callback_count_);
-        break;
-      case 4:
-        // Flush the message loops and make sure the callbacks run.
-        layer_tree_host()->SetNeedsCommit();
-        break;
-      case 5:
-        // We should get another callback with a NULL bitmap.
-        EXPECT_EQ(2, callback_count_);
-        EndTest();
-        break;
+    if (!did_initialize_gl_) {
+      EXPECT_LE(1u, layer_impl->append_quads_count());
+      ImplThreadTaskRunner()->PostTask(
+          FROM_HERE,
+          base::Bind(
+              &LayerTreeHostTestDeferredInitialize::DeferredInitializeAndRedraw,
+              base::Unretained(this),
+              base::Unretained(host_impl)));
+    } else if (did_initialize_gl_ && !did_release_gl_) {
+      EXPECT_LE(2u, layer_impl->append_quads_count());
+      ImplThreadTaskRunner()->PostTask(
+          FROM_HERE,
+          base::Bind(&LayerTreeHostTestDeferredInitialize::ReleaseGLAndRedraw,
+                     base::Unretained(this),
+                     base::Unretained(host_impl)));
+    } else if (did_initialize_gl_ && did_release_gl_) {
+      EXPECT_LE(3u, layer_impl->append_quads_count());
+      EndTest();
     }
   }
 
-  void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
-    EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
-    EXPECT_TRUE(result->IsEmpty());
-    ++callback_count_;
+  void DeferredInitializeAndRedraw(LayerTreeHostImpl* host_impl) {
+    EXPECT_FALSE(did_initialize_gl_);
+    // SetAndInitializeContext3D calls SetNeedsCommit.
+    FakeOutputSurface* fake_output_surface =
+        static_cast<FakeOutputSurface*>(host_impl->output_surface());
+    scoped_refptr<TestContextProvider> context_provider =
+        TestContextProvider::Create();  // Not bound to thread.
+    EXPECT_TRUE(
+        fake_output_surface->InitializeAndSetContext3d(context_provider));
+    did_initialize_gl_ = true;
+  }
+
+  void ReleaseGLAndRedraw(LayerTreeHostImpl* host_impl) {
+    EXPECT_TRUE(did_initialize_gl_);
+    EXPECT_FALSE(did_release_gl_);
+    // ReleaseGL calls SetNeedsCommit.
+    static_cast<FakeOutputSurface*>(host_impl->output_surface())->ReleaseGL();
+    did_release_gl_ = true;
   }
 
-  virtual void AfterTest() OVERRIDE {}
+  virtual void AfterTest() OVERRIDE {
+    EXPECT_TRUE(did_initialize_gl_);
+    EXPECT_TRUE(did_release_gl_);
+  }
 
-  int callback_count_;
+ private:
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_;
-  scoped_refptr<FakeContentLayer> main_destroyed_;
-  scoped_refptr<FakeContentLayer> impl_destroyed_;
+  scoped_refptr<FakePictureLayer> layer_;
+  bool did_initialize_gl_;
+  bool did_release_gl_;
+  int last_source_frame_number_drawn_;
 };
 
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestAsyncReadbackLayerDestroyed);
-
-class LayerTreeHostTestAsyncReadbackInHiddenSubtree : public LayerTreeHostTest {
- protected:
-  virtual void SetupTree() OVERRIDE {
-    root_ = FakeContentLayer::Create(&client_);
-    root_->SetBounds(gfx::Size(20, 20));
-
-    grand_parent_layer_ = FakeContentLayer::Create(&client_);
-    grand_parent_layer_->SetBounds(gfx::Size(15, 15));
-    root_->AddChild(grand_parent_layer_);
-
-    // parent_layer_ owns a render surface.
-    parent_layer_ = FakeContentLayer::Create(&client_);
-    parent_layer_->SetBounds(gfx::Size(15, 15));
-    parent_layer_->SetForceRenderSurface(true);
-    grand_parent_layer_->AddChild(parent_layer_);
-
-    copy_layer_ = FakeContentLayer::Create(&client_);
-    copy_layer_->SetBounds(gfx::Size(10, 10));
-    parent_layer_->AddChild(copy_layer_);
-
-    layer_tree_host()->SetRootLayer(root_);
-    LayerTreeHostTest::SetupTree();
-  }
-
-  void AddCopyRequest(Layer* layer) {
-    layer->RequestCopyOfOutput(
-        CopyOutputRequest::CreateBitmapRequest(base::Bind(
-            &LayerTreeHostTestAsyncReadbackInHiddenSubtree::CopyOutputCallback,
-            base::Unretained(this))));
-  }
+MULTI_THREAD_DIRECT_RENDERER_TEST_F(LayerTreeHostTestDeferredInitialize);
 
-  virtual void BeginTest() OVERRIDE {
-    callback_count_ = 0;
-    PostSetNeedsCommitToMainThread();
+// Test for UI Resource management.
+class LayerTreeHostTestUIResource : public LayerTreeHostTest {
+ public:
+  LayerTreeHostTestUIResource() : num_ui_resources_(0) {}
 
-    AddCopyRequest(copy_layer_.get());
+  virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
+    settings->texture_id_allocation_chunk_size = 1;
   }
 
-  void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
-    EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
-    EXPECT_EQ(copy_layer_->bounds().ToString(), result->size().ToString());
-    ++callback_count_;
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
-    switch (callback_count_) {
+  virtual void DidCommit() OVERRIDE {
+    int frame = layer_tree_host()->source_frame_number();
+    switch (frame) {
       case 1:
-        // Hide the copy request layer.
-        grand_parent_layer_->SetHideLayerAndSubtree(false);
-        parent_layer_->SetHideLayerAndSubtree(false);
-        copy_layer_->SetHideLayerAndSubtree(true);
-        AddCopyRequest(copy_layer_.get());
+        CreateResource();
+        CreateResource();
+        PostSetNeedsCommitToMainThread();
         break;
       case 2:
-        // Hide the copy request layer's parent only.
-        grand_parent_layer_->SetHideLayerAndSubtree(false);
-        parent_layer_->SetHideLayerAndSubtree(true);
-        copy_layer_->SetHideLayerAndSubtree(false);
-        AddCopyRequest(copy_layer_.get());
+        // Usually ScopedUIResource are deleted from the manager in their
+        // destructor.  Here we just want to test that a direct call to
+        // DeleteUIResource works.
+        layer_tree_host()->DeleteUIResource(ui_resources_[0]->id());
+        PostSetNeedsCommitToMainThread();
         break;
       case 3:
-        // Hide the copy request layer's grand parent only.
-        grand_parent_layer_->SetHideLayerAndSubtree(true);
-        parent_layer_->SetHideLayerAndSubtree(false);
-        copy_layer_->SetHideLayerAndSubtree(false);
-        AddCopyRequest(copy_layer_.get());
+        // DeleteUIResource can be called with an invalid id.
+        layer_tree_host()->DeleteUIResource(ui_resources_[0]->id());
+        PostSetNeedsCommitToMainThread();
         break;
       case 4:
-        // Hide the copy request layer's parent and grandparent.
-        grand_parent_layer_->SetHideLayerAndSubtree(true);
-        parent_layer_->SetHideLayerAndSubtree(true);
-        copy_layer_->SetHideLayerAndSubtree(false);
-        AddCopyRequest(copy_layer_.get());
+        CreateResource();
+        CreateResource();
+        PostSetNeedsCommitToMainThread();
         break;
       case 5:
-        // Hide the copy request layer as well as its parent and grandparent.
-        grand_parent_layer_->SetHideLayerAndSubtree(true);
-        parent_layer_->SetHideLayerAndSubtree(true);
-        copy_layer_->SetHideLayerAndSubtree(true);
-        AddCopyRequest(copy_layer_.get());
-        break;
-      case 6:
+        ClearResources();
         EndTest();
         break;
     }
   }
 
-  virtual void AfterTest() OVERRIDE {}
-
-  int callback_count_;
-  FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_;
-  scoped_refptr<FakeContentLayer> grand_parent_layer_;
-  scoped_refptr<FakeContentLayer> parent_layer_;
-  scoped_refptr<FakeContentLayer> copy_layer_;
-};
-
-// No output to copy for delegated renderers.
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
-    LayerTreeHostTestAsyncReadbackInHiddenSubtree);
-
-class LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest
-    : public LayerTreeHostTest {
- protected:
-  virtual void SetupTree() OVERRIDE {
-    root_ = FakeContentLayer::Create(&client_);
-    root_->SetBounds(gfx::Size(20, 20));
-
-    grand_parent_layer_ = FakeContentLayer::Create(&client_);
-    grand_parent_layer_->SetBounds(gfx::Size(15, 15));
-    grand_parent_layer_->SetHideLayerAndSubtree(true);
-    root_->AddChild(grand_parent_layer_);
+  void PerformTest(LayerTreeHostImpl* impl) {
+    TestWebGraphicsContext3D* context = TestContext();
 
-    // parent_layer_ owns a render surface.
-    parent_layer_ = FakeContentLayer::Create(&client_);
-    parent_layer_->SetBounds(gfx::Size(15, 15));
-    parent_layer_->SetForceRenderSurface(true);
-    grand_parent_layer_->AddChild(parent_layer_);
+    int frame = impl->active_tree()->source_frame_number();
+    switch (frame) {
+      case 0:
+        ASSERT_EQ(0u, context->NumTextures());
+        break;
+      case 1:
+        // Created two textures.
+        ASSERT_EQ(2u, context->NumTextures());
+        break;
+      case 2:
+        // One texture left after one deletion.
+        ASSERT_EQ(1u, context->NumTextures());
+        break;
+      case 3:
+        // Resource manager state should not change when delete is called on an
+        // invalid id.
+        ASSERT_EQ(1u, context->NumTextures());
+        break;
+      case 4:
+        // Creation after deletion: two more creates should total up to
+        // three textures.
+        ASSERT_EQ(3u, context->NumTextures());
+        break;
+    }
+  }
 
-    copy_layer_ = FakeContentLayer::Create(&client_);
-    copy_layer_->SetBounds(gfx::Size(10, 10));
-    parent_layer_->AddChild(copy_layer_);
+  virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+    if (!layer_tree_host()->settings().impl_side_painting)
+      PerformTest(impl);
+  }
 
-    layer_tree_host()->SetRootLayer(root_);
-    LayerTreeHostTest::SetupTree();
+  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+    if (layer_tree_host()->settings().impl_side_painting)
+      PerformTest(impl);
   }
 
-  virtual void BeginTest() OVERRIDE {
-    did_draw_ = false;
-    PostSetNeedsCommitToMainThread();
+  virtual void AfterTest() OVERRIDE {}
 
-    copy_layer_->RequestCopyOfOutput(
-        CopyOutputRequest::CreateBitmapRequest(base::Bind(
-            &LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest::
-                CopyOutputCallback,
-            base::Unretained(this))));
+ private:
+  // Must clear all resources before exiting.
+  void ClearResources() {
+    for (int i = 0; i < num_ui_resources_; i++)
+      ui_resources_[i].reset();
   }
 
-  void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
-    EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
-    EXPECT_EQ(copy_layer_->bounds().ToString(), result->size().ToString());
-    EndTest();
+  void CreateResource() {
+    ui_resources_[num_ui_resources_++] =
+        FakeScopedUIResource::Create(layer_tree_host());
   }
 
-  virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
-    Renderer* renderer = host_impl->renderer();
+  scoped_ptr<FakeScopedUIResource> ui_resources_[5];
+  int num_ui_resources_;
+};
 
-    LayerImpl* root = host_impl->active_tree()->root_layer();
-    LayerImpl* grand_parent = root->children()[0];
-    LayerImpl* parent = grand_parent->children()[0];
-    LayerImpl* copy_layer = parent->children()[0];
+MULTI_THREAD_TEST_F(LayerTreeHostTestUIResource);
 
-    // |parent| owns a surface, but it was hidden and not part of the copy
-    // request so it should not allocate any resource.
-    EXPECT_FALSE(renderer->HasAllocatedResourcesForTesting(
-        parent->render_surface()->RenderPassId()));
+class PushPropertiesCountingLayerImpl : public LayerImpl {
+ public:
+  static scoped_ptr<PushPropertiesCountingLayerImpl> Create(
+      LayerTreeImpl* tree_impl, int id) {
+    return make_scoped_ptr(new PushPropertiesCountingLayerImpl(tree_impl, id));
+  }
 
-    // |copy_layer| should have been rendered to a texture since it was needed
-    // for a copy request.
-    EXPECT_TRUE(renderer->HasAllocatedResourcesForTesting(
-        copy_layer->render_surface()->RenderPassId()));
+  virtual ~PushPropertiesCountingLayerImpl() {}
 
-    did_draw_ = true;
+  virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE {
+    LayerImpl::PushPropertiesTo(layer);
+    push_properties_count_++;
+    // Push state to the active tree because we can only access it from there.
+    static_cast<PushPropertiesCountingLayerImpl*>(
+        layer)->push_properties_count_ = push_properties_count_;
   }
 
-  virtual void AfterTest() OVERRIDE { EXPECT_TRUE(did_draw_); }
-
-  FakeContentLayerClient client_;
-  bool did_draw_;
-  scoped_refptr<FakeContentLayer> root_;
-  scoped_refptr<FakeContentLayer> grand_parent_layer_;
-  scoped_refptr<FakeContentLayer> parent_layer_;
-  scoped_refptr<FakeContentLayer> copy_layer_;
-};
+  virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
+      OVERRIDE {
+    return PushPropertiesCountingLayerImpl::Create(tree_impl, id()).
+        PassAs<LayerImpl>();
+  }
 
-// No output to copy for delegated renderers.
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
-      LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest);
+  size_t push_properties_count() const { return push_properties_count_; }
+  void reset_push_properties_count() { push_properties_count_ = 0; }
 
-class LayerTreeHostTestAsyncReadbackClippedOut : public LayerTreeHostTest {
- protected:
-  virtual void SetupTree() OVERRIDE {
-    root_ = FakeContentLayer::Create(&client_);
-    root_->SetBounds(gfx::Size(20, 20));
+ private:
+  size_t push_properties_count_;
 
-    parent_layer_ = FakeContentLayer::Create(&client_);
-    parent_layer_->SetBounds(gfx::Size(15, 15));
-    parent_layer_->SetMasksToBounds(true);
-    root_->AddChild(parent_layer_);
-
-    copy_layer_ = FakeContentLayer::Create(&client_);
-    copy_layer_->SetPosition(gfx::Point(15, 15));
-    copy_layer_->SetBounds(gfx::Size(10, 10));
-    parent_layer_->AddChild(copy_layer_);
-
-    layer_tree_host()->SetRootLayer(root_);
-    LayerTreeHostTest::SetupTree();
-  }
-
-  virtual void BeginTest() OVERRIDE {
-    PostSetNeedsCommitToMainThread();
-
-    copy_layer_->RequestCopyOfOutput(
-        CopyOutputRequest::CreateBitmapRequest(base::Bind(
-            &LayerTreeHostTestAsyncReadbackClippedOut::CopyOutputCallback,
-            base::Unretained(this))));
-  }
-
-  void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
-    // We should still get a callback with no output if the copy requested layer
-    // was completely clipped away.
-    EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
-    EXPECT_EQ(gfx::Size().ToString(), result->size().ToString());
-    EndTest();
+  PushPropertiesCountingLayerImpl(LayerTreeImpl* tree_impl, int id)
+      : LayerImpl(tree_impl, id),
+        push_properties_count_(0) {
+    SetAnchorPoint(gfx::PointF());
+    SetBounds(gfx::Size(1, 1));
   }
-
-  virtual void AfterTest() OVERRIDE {}
-
-  FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_;
-  scoped_refptr<FakeContentLayer> parent_layer_;
-  scoped_refptr<FakeContentLayer> copy_layer_;
 };
 
-// No output to copy for delegated renderers.
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
-    LayerTreeHostTestAsyncReadbackClippedOut);
-
-class LayerTreeHostTestAsyncTwoReadbacksWithoutDraw : public LayerTreeHostTest {
- protected:
-  virtual void SetupTree() OVERRIDE {
-    root_ = FakeContentLayer::Create(&client_);
-    root_->SetBounds(gfx::Size(20, 20));
-
-    copy_layer_ = FakeContentLayer::Create(&client_);
-    copy_layer_->SetBounds(gfx::Size(10, 10));
-    root_->AddChild(copy_layer_);
-
-    layer_tree_host()->SetRootLayer(root_);
-    LayerTreeHostTest::SetupTree();
-  }
-
-  void AddCopyRequest(Layer* layer) {
-    layer->RequestCopyOfOutput(
-        CopyOutputRequest::CreateBitmapRequest(base::Bind(
-            &LayerTreeHostTestAsyncTwoReadbacksWithoutDraw::CopyOutputCallback,
-            base::Unretained(this))));
+class PushPropertiesCountingLayer : public Layer {
+ public:
+  static scoped_refptr<PushPropertiesCountingLayer> Create() {
+    return new PushPropertiesCountingLayer();
   }
 
-  virtual void BeginTest() OVERRIDE {
-    saw_copy_request_ = false;
-    callback_count_ = 0;
-    PostSetNeedsCommitToMainThread();
-
-    // Prevent drawing.
-    layer_tree_host()->SetViewportSize(gfx::Size(0, 0));
-
-    AddCopyRequest(copy_layer_.get());
+  virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE {
+    Layer::PushPropertiesTo(layer);
+    push_properties_count_++;
+    if (persist_needs_push_properties_)
+      needs_push_properties_ = true;
   }
 
-  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
-    if (impl->active_tree()->source_frame_number() == 0) {
-      LayerImpl* root = impl->active_tree()->root_layer();
-      EXPECT_TRUE(root->children()[0]->HasCopyRequest());
-      saw_copy_request_ = true;
-    }
+  virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
+      OVERRIDE {
+    return PushPropertiesCountingLayerImpl::Create(tree_impl, id()).
+        PassAs<LayerImpl>();
   }
 
-  virtual void DidCommit() OVERRIDE {
-    if (layer_tree_host()->source_frame_number() == 1) {
-      // Allow drawing.
-      layer_tree_host()->SetViewportSize(gfx::Size(root_->bounds()));
+  size_t push_properties_count() const { return push_properties_count_; }
+  void reset_push_properties_count() { push_properties_count_ = 0; }
 
-      AddCopyRequest(copy_layer_.get());
-    }
+  void set_persist_needs_push_properties(bool persist) {
+    persist_needs_push_properties_ = persist;
   }
 
-  void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
-    EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
-    EXPECT_EQ(copy_layer_->bounds().ToString(), result->size().ToString());
-    ++callback_count_;
-
-    if (callback_count_ == 2)
-      EndTest();
+ private:
+  PushPropertiesCountingLayer()
+      : push_properties_count_(0), persist_needs_push_properties_(false) {
+    SetAnchorPoint(gfx::PointF());
+    SetBounds(gfx::Size(1, 1));
+    SetIsDrawable(true);
   }
+  virtual ~PushPropertiesCountingLayer() {}
 
-  virtual void AfterTest() OVERRIDE { EXPECT_TRUE(saw_copy_request_); }
-
-  bool saw_copy_request_;
-  int callback_count_;
-  FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_;
-  scoped_refptr<FakeContentLayer> copy_layer_;
+  size_t push_properties_count_;
+  bool persist_needs_push_properties_;
 };
 
-// No output to copy for delegated renderers.
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
-    LayerTreeHostTestAsyncTwoReadbacksWithoutDraw);
-
-class LayerTreeHostTestAsyncReadbackLostOutputSurface
-    : public LayerTreeHostTest {
+class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest {
  protected:
-  virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
-      OVERRIDE {
-    if (!first_context_provider_.get()) {
-      first_context_provider_ = TestContextProvider::Create();
-      return FakeOutputSurface::Create3d(first_context_provider_)
-          .PassAs<OutputSurface>();
-    }
-
-    EXPECT_FALSE(second_context_provider_.get());
-    second_context_provider_ = TestContextProvider::Create();
-    return FakeOutputSurface::Create3d(second_context_provider_)
-        .PassAs<OutputSurface>();
+  virtual void BeginTest() OVERRIDE {
+    num_commits_ = 0;
+    expected_push_properties_root_ = 0;
+    expected_push_properties_child_ = 0;
+    expected_push_properties_grandchild_ = 0;
+    expected_push_properties_child2_ = 0;
+    expected_push_properties_other_root_ = 0;
+    expected_push_properties_leaf_layer_ = 0;
+    PostSetNeedsCommitToMainThread();
   }
 
   virtual void SetupTree() OVERRIDE {
-    root_ = FakeContentLayer::Create(&client_);
-    root_->SetBounds(gfx::Size(20, 20));
+    root_ = PushPropertiesCountingLayer::Create();
+    child_ = PushPropertiesCountingLayer::Create();
+    child2_ = PushPropertiesCountingLayer::Create();
+    grandchild_ = PushPropertiesCountingLayer::Create();
+    leaf_always_pushing_layer_ = PushPropertiesCountingLayer::Create();
+    leaf_always_pushing_layer_->set_persist_needs_push_properties(true);
 
-    copy_layer_ = FakeContentLayer::Create(&client_);
-    copy_layer_->SetBounds(gfx::Size(10, 10));
-    root_->AddChild(copy_layer_);
+    root_->AddChild(child_);
+    root_->AddChild(child2_);
+    child_->AddChild(grandchild_);
+    child2_->AddChild(leaf_always_pushing_layer_);
 
-    layer_tree_host()->SetRootLayer(root_);
+    other_root_ = PushPropertiesCountingLayer::Create();
+
+    // Don't set the root layer here.
     LayerTreeHostTest::SetupTree();
   }
 
-  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
-
-  void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
-    EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
-    EXPECT_EQ(gfx::Size(10, 10).ToString(), result->size().ToString());
-    EXPECT_TRUE(result->HasTexture());
+  virtual void DidCommitAndDrawFrame() OVERRIDE {
+    ++num_commits_;
 
-    // Save the result for later.
-    EXPECT_FALSE(result_);
-    result_ = result.Pass();
+    EXPECT_EQ(expected_push_properties_root_, root_->push_properties_count());
+    EXPECT_EQ(expected_push_properties_child_, child_->push_properties_count());
+    EXPECT_EQ(expected_push_properties_grandchild_,
+              grandchild_->push_properties_count());
+    EXPECT_EQ(expected_push_properties_child2_,
+              child2_->push_properties_count());
+    EXPECT_EQ(expected_push_properties_other_root_,
+              other_root_->push_properties_count());
+    EXPECT_EQ(expected_push_properties_leaf_layer_,
+              leaf_always_pushing_layer_->push_properties_count());
 
-    // Post a commit to lose the output surface.
-    layer_tree_host()->SetNeedsCommit();
-  }
+    // The scrollbar layer always needs to be pushed.
+    if (root_->layer_tree_host()) {
+      EXPECT_TRUE(root_->descendant_needs_push_properties());
+      EXPECT_FALSE(root_->needs_push_properties());
+    }
+    if (child2_->layer_tree_host()) {
+      EXPECT_TRUE(child2_->descendant_needs_push_properties());
+      EXPECT_FALSE(child2_->needs_push_properties());
+    }
+    if (leaf_always_pushing_layer_->layer_tree_host()) {
+      EXPECT_FALSE(
+          leaf_always_pushing_layer_->descendant_needs_push_properties());
+      EXPECT_TRUE(leaf_always_pushing_layer_->needs_push_properties());
+    }
 
-  virtual void DidCommitAndDrawFrame() OVERRIDE {
-    switch (layer_tree_host()->source_frame_number()) {
-      case 1:
-        // The layers have been pushed to the impl side. The layer textures have
-        // been allocated.
+    // child_ and grandchild_ don't persist their need to push properties.
+    if (child_->layer_tree_host()) {
+      EXPECT_FALSE(child_->descendant_needs_push_properties());
+      EXPECT_FALSE(child_->needs_push_properties());
+    }
+    if (grandchild_->layer_tree_host()) {
+      EXPECT_FALSE(grandchild_->descendant_needs_push_properties());
+      EXPECT_FALSE(grandchild_->needs_push_properties());
+    }
 
-        // Request a copy of the layer. This will use another texture.
-        copy_layer_->RequestCopyOfOutput(
-            CopyOutputRequest::CreateRequest(base::Bind(
-                &LayerTreeHostTestAsyncReadbackLostOutputSurface::
-                CopyOutputCallback,
-                base::Unretained(this))));
-        break;
-      case 4:
-        // With SingleThreadProxy it takes two commits to finally swap after a
-        // context loss.
-      case 5:
-        // Now destroy the CopyOutputResult, releasing the texture inside back
-        // to the compositor.
-        EXPECT_TRUE(result_);
-        result_.reset();
-
-        // Check that it is released.
-        ImplThreadTaskRunner()->PostTask(
-            FROM_HERE,
-            base::Bind(&LayerTreeHostTestAsyncReadbackLostOutputSurface::
-                            CheckNumTextures,
-                       base::Unretained(this),
-                       num_textures_after_loss_ - 1));
-        break;
+    if (other_root_->layer_tree_host()) {
+      EXPECT_FALSE(other_root_->descendant_needs_push_properties());
+      EXPECT_FALSE(other_root_->needs_push_properties());
     }
-  }
 
-  virtual void SwapBuffersOnThread(LayerTreeHostImpl *impl, bool result)
-      OVERRIDE {
-    switch (impl->active_tree()->source_frame_number()) {
-      case 0:
-        // The layers have been drawn, so their textures have been allocated.
-        EXPECT_FALSE(result_);
-        num_textures_without_readback_ =
-            first_context_provider_->TestContext3d()->NumTextures();
-        break;
+    switch (num_commits_) {
       case 1:
-        // We did a readback, so there will be a readback texture around now.
-        EXPECT_LT(num_textures_without_readback_,
-                  first_context_provider_->TestContext3d()->NumTextures());
+        layer_tree_host()->SetRootLayer(root_);
+        // Layers added to the tree get committed.
+        ++expected_push_properties_root_;
+        ++expected_push_properties_child_;
+        ++expected_push_properties_grandchild_;
+        ++expected_push_properties_child2_;
         break;
       case 2:
-        // The readback texture is collected.
-        EXPECT_TRUE(result_);
-
-        // Lose the output surface.
-        first_context_provider_->TestContext3d()->loseContextCHROMIUM(
-            GL_GUILTY_CONTEXT_RESET_ARB,
-            GL_INNOCENT_CONTEXT_RESET_ARB);
+        layer_tree_host()->SetNeedsCommit();
+        // No layers need commit.
         break;
       case 3:
-        // With SingleThreadProxy it takes two commits to finally swap after a
-        // context loss.
+        layer_tree_host()->SetRootLayer(other_root_);
+        // Layers added to the tree get committed.
+        ++expected_push_properties_other_root_;
+        break;
       case 4:
-        // The output surface has been recreated.
-        EXPECT_TRUE(second_context_provider_.get());
-
-        num_textures_after_loss_ =
-            first_context_provider_->TestContext3d()->NumTextures();
+        layer_tree_host()->SetRootLayer(root_);
+        // Layers added to the tree get committed.
+        ++expected_push_properties_root_;
+        ++expected_push_properties_child_;
+        ++expected_push_properties_grandchild_;
+        ++expected_push_properties_child2_;
+        break;
+      case 5:
+        layer_tree_host()->SetNeedsCommit();
+        // No layers need commit.
+        break;
+      case 6:
+        child_->RemoveFromParent();
+        // No layers need commit.
+        break;
+      case 7:
+        root_->AddChild(child_);
+        // Layers added to the tree get committed.
+        ++expected_push_properties_child_;
+        ++expected_push_properties_grandchild_;
+        break;
+      case 8:
+        grandchild_->RemoveFromParent();
+        // No layers need commit.
+        break;
+      case 9:
+        child_->AddChild(grandchild_);
+        // Layers added to the tree get committed.
+        ++expected_push_properties_grandchild_;
+        break;
+      case 10:
+        layer_tree_host()->SetViewportSize(gfx::Size(20, 20));
+        // No layers need commit.
+        break;
+      case 11:
+        layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.8f, 1.1f);
+        // No layers need commit.
+        break;
+      case 12:
+        child_->SetPosition(gfx::Point(1, 1));
+        // The modified layer needs commit
+        ++expected_push_properties_child_;
+        break;
+      case 13:
+        child2_->SetPosition(gfx::Point(1, 1));
+        // The modified layer needs commit
+        ++expected_push_properties_child2_;
+        break;
+      case 14:
+        child_->RemoveFromParent();
+        root_->AddChild(child_);
+        // Layers added to the tree get committed.
+        ++expected_push_properties_child_;
+        ++expected_push_properties_grandchild_;
+        break;
+      case 15:
+        grandchild_->SetPosition(gfx::Point(1, 1));
+        // The modified layer needs commit
+        ++expected_push_properties_grandchild_;
+        break;
+      case 16:
+        // SetNeedsDisplay does not always set needs commit (so call it
+        // explicitly), but is a property change.
+        child_->SetNeedsDisplay();
+        ++expected_push_properties_child_;
+        layer_tree_host()->SetNeedsCommit();
+        break;
+      case 17:
+        EndTest();
         break;
     }
-  }
 
-  void CheckNumTextures(size_t expected_num_textures) {
-    EXPECT_EQ(expected_num_textures,
-              first_context_provider_->TestContext3d()->NumTextures());
-    EndTest();
+    // The leaf layer always pushes.
+    if (leaf_always_pushing_layer_->layer_tree_host())
+      ++expected_push_properties_leaf_layer_;
   }
 
   virtual void AfterTest() OVERRIDE {}
 
-  scoped_refptr<TestContextProvider> first_context_provider_;
-  scoped_refptr<TestContextProvider> second_context_provider_;
-  size_t num_textures_without_readback_;
-  size_t num_textures_after_loss_;
+  int num_commits_;
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_;
-  scoped_refptr<FakeContentLayer> copy_layer_;
-  scoped_ptr<CopyOutputResult> result_;
-};
+  scoped_refptr<PushPropertiesCountingLayer> root_;
+  scoped_refptr<PushPropertiesCountingLayer> child_;
+  scoped_refptr<PushPropertiesCountingLayer> child2_;
+  scoped_refptr<PushPropertiesCountingLayer> grandchild_;
+  scoped_refptr<PushPropertiesCountingLayer> other_root_;
+  scoped_refptr<PushPropertiesCountingLayer> leaf_always_pushing_layer_;
+  size_t expected_push_properties_root_;
+  size_t expected_push_properties_child_;
+  size_t expected_push_properties_child2_;
+  size_t expected_push_properties_grandchild_;
+  size_t expected_push_properties_other_root_;
+  size_t expected_push_properties_leaf_layer_;
+};
 
-// No output to copy for delegated renderers.
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
-    LayerTreeHostTestAsyncReadbackLostOutputSurface);
+MULTI_THREAD_TEST_F(LayerTreeHostTestLayersPushProperties);
 
-class LayerTreeHostTestNumFramesPending : public LayerTreeHostTest {
- public:
+class LayerTreeHostTestImplLayersPushProperties
+    : public LayerTreeHostTestLayersPushProperties {
+ protected:
   virtual void BeginTest() OVERRIDE {
-    frame_ = 0;
-    PostSetNeedsCommitToMainThread();
+    expected_push_properties_root_impl_ = 0;
+    expected_push_properties_child_impl_ = 0;
+    expected_push_properties_grandchild_impl_ = 0;
+    expected_push_properties_child2_impl_ = 0;
+    expected_push_properties_grandchild2_impl_ = 0;
+    LayerTreeHostTestLayersPushProperties::BeginTest();
   }
 
-  // Round 1: commit + draw
-  // Round 2: commit only (no draw/swap)
-  // Round 3: draw only (no commit)
-  // Round 4: composite & readback (2 commits, no draw/swap)
-  // Round 5: commit + draw
-
-  virtual void DidCommit() OVERRIDE {
-    int commit = layer_tree_host()->source_frame_number();
-    switch (commit) {
+  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+    // These commits are in response to the changes made in
+    // LayerTreeHostTestLayersPushProperties::DidCommitAndDrawFrame()
+    switch (num_commits_) {
+      case 0:
+        // Tree hasn't been setup yet don't bother to check anything.
+        return;
+      case 1:
+        // Root gets set up, Everyone is initialized.
+        ++expected_push_properties_root_impl_;
+        ++expected_push_properties_child_impl_;
+        ++expected_push_properties_grandchild_impl_;
+        ++expected_push_properties_child2_impl_;
+        ++expected_push_properties_grandchild2_impl_;
+        break;
       case 2:
-        // Round 2 done.
-        EXPECT_EQ(1, frame_);
-        layer_tree_host()->SetNeedsRedraw();
+        // Tree doesn't change but the one leaf that always pushes is pushed.
+        ++expected_push_properties_grandchild2_impl_;
         break;
       case 3:
-        // CompositeAndReadback in Round 4, first commit.
-        EXPECT_EQ(2, frame_);
-        break;
+        // Root is swapped here.
+        // Clear the expected push properties the tree will be rebuilt.
+        expected_push_properties_root_impl_ = 0;
+        expected_push_properties_child_impl_ = 0;
+        expected_push_properties_grandchild_impl_ = 0;
+        expected_push_properties_child2_impl_ = 0;
+        expected_push_properties_grandchild2_impl_ = 0;
+
+        // Make sure the new root is pushed.
+        EXPECT_EQ(1u, static_cast<PushPropertiesCountingLayerImpl*>(
+                host_impl->RootLayer())->push_properties_count());
+        return;
       case 4:
-        // Round 4 done.
-        EXPECT_EQ(2, frame_);
-        layer_tree_host()->SetNeedsCommit();
-        layer_tree_host()->SetNeedsRedraw();
+        // Root is swapped back all of the layers in the tree get pushed.
+        ++expected_push_properties_root_impl_;
+        ++expected_push_properties_child_impl_;
+        ++expected_push_properties_grandchild_impl_;
+        ++expected_push_properties_child2_impl_;
+        ++expected_push_properties_grandchild2_impl_;
         break;
-    }
-  }
+      case 5:
+        // Tree doesn't change but the one leaf that always pushes is pushed.
+        ++expected_push_properties_grandchild2_impl_;
+        break;
+      case 6:
+        // First child is removed. Structure of the tree changes here so swap
+        // some of the values. child_impl becomes child2_impl.
+        expected_push_properties_child_impl_ =
+            expected_push_properties_child2_impl_;
+        expected_push_properties_child2_impl_ = 0;
+        // grandchild_impl becomes grandchild2_impl.
+        expected_push_properties_grandchild_impl_ =
+            expected_push_properties_grandchild2_impl_;
+        expected_push_properties_grandchild2_impl_ = 0;
+
+        // grandchild_impl is now the leaf that always pushes. It is pushed.
+        ++expected_push_properties_grandchild_impl_;
+        break;
+      case 7:
+        // The leaf that always pushes is pushed.
+        ++expected_push_properties_grandchild_impl_;
 
-  virtual void DidCompleteSwapBuffers() OVERRIDE {
-    int commit = layer_tree_host()->source_frame_number();
-    ++frame_;
-    char pixels[4] = {0};
-    switch (frame_) {
-      case 1:
-        // Round 1 done.
-        EXPECT_EQ(1, commit);
-        layer_tree_host()->SetNeedsCommit();
+        // Child is added back. New layers are initialized.
+        ++expected_push_properties_grandchild2_impl_;
+        ++expected_push_properties_child2_impl_;
         break;
-      case 2:
-        // Round 3 done.
-        EXPECT_EQ(2, commit);
-        layer_tree_host()->CompositeAndReadback(pixels, gfx::Rect(0, 0, 1, 1));
+      case 8:
+        // Leaf is removed.
+        expected_push_properties_grandchild2_impl_ = 0;
+
+        // Always pushing.
+        ++expected_push_properties_grandchild_impl_;
         break;
-      case 3:
-        // Round 5 done.
-        EXPECT_EQ(5, commit);
-        EndTest();
+      case 9:
+        // Leaf is added back
+        ++expected_push_properties_grandchild2_impl_;
+
+        // The leaf that always pushes is pushed.
+        ++expected_push_properties_grandchild_impl_;
         break;
-    }
-  }
+      case 10:
+        // The leaf that always pushes is pushed.
+        ++expected_push_properties_grandchild_impl_;
+        break;
+      case 11:
+        // The leaf that always pushes is pushed.
+        ++expected_push_properties_grandchild_impl_;
+        break;
+      case 12:
+        // The leaf that always pushes is pushed.
+        ++expected_push_properties_grandchild_impl_;
 
-  virtual void AfterTest() OVERRIDE {}
+        // This child position was changed.
+        ++expected_push_properties_child2_impl_;
+        break;
+      case 13:
+        // The position of this child was changed.
+        ++expected_push_properties_child_impl_;
 
- protected:
-  int frame_;
-};
+        // The leaf that always pushes is pushed.
+        ++expected_push_properties_grandchild_impl_;
+        break;
+      case 14:
+        // Second child is removed from tree. Don't discard counts because
+        // they are added back before commit.
 
-TEST_F(LayerTreeHostTestNumFramesPending, DelegatingRenderer) {
-  RunTest(true, true, true);
-}
+        // The leaf that always pushes is pushed.
+        ++expected_push_properties_grandchild_impl_;
 
-TEST_F(LayerTreeHostTestNumFramesPending, GLRenderer) {
-  RunTest(true, false, true);
-}
+        // Second child added back.
+        ++expected_push_properties_child2_impl_;
+        ++expected_push_properties_grandchild2_impl_;
 
-class LayerTreeHostTestDeferredInitialize : public LayerTreeHostTest {
- public:
-  virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
-    // PictureLayer can only be used with impl side painting enabled.
-    settings->impl_side_painting = true;
-  }
+        break;
+      case 15:
+        // The position of this child was changed.
+        ++expected_push_properties_grandchild2_impl_;
 
-  virtual void SetupTree() OVERRIDE {
-    layer_ = FakePictureLayer::Create(&client_);
-    // Force commits to not be aborted so new frames get drawn, otherwise
-    // the renderer gets deferred initialized but nothing new needs drawing.
-    layer_->set_always_update_resources(true);
-    layer_tree_host()->SetRootLayer(layer_);
-    LayerTreeHostTest::SetupTree();
-  }
+        // The leaf that always pushes is pushed.
+        ++expected_push_properties_grandchild_impl_;
+        break;
+      case 16:
+        // Second child is invalidated with SetNeedsDisplay
+        ++expected_push_properties_child2_impl_;
 
-  virtual void BeginTest() OVERRIDE {
-    did_initialize_gl_ = false;
-    did_release_gl_ = false;
-    last_source_frame_number_drawn_ = -1;  // Never drawn.
-    PostSetNeedsCommitToMainThread();
-  }
+        // The leaf that always pushed is pushed.
+        ++expected_push_properties_grandchild_impl_;
+        break;
+    }
 
-  virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
-      OVERRIDE {
-    scoped_ptr<TestWebGraphicsContext3D> context3d(
-        TestWebGraphicsContext3D::Create());
-    context3d->set_support_swapbuffers_complete_callback(false);
+    PushPropertiesCountingLayerImpl* root_impl_ = NULL;
+    PushPropertiesCountingLayerImpl* child_impl_ = NULL;
+    PushPropertiesCountingLayerImpl* child2_impl_ = NULL;
+    PushPropertiesCountingLayerImpl* grandchild_impl_ = NULL;
+    PushPropertiesCountingLayerImpl* leaf_always_pushing_layer_impl_ = NULL;
 
-    return FakeOutputSurface::CreateDeferredGL(
-        scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice))
-        .PassAs<OutputSurface>();
-  }
+    // Pull the layers that we need from the tree assuming the same structure
+    // as LayerTreeHostTestLayersPushProperties
+    root_impl_ = static_cast<PushPropertiesCountingLayerImpl*>(
+        host_impl->RootLayer());
 
-  virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
-    ASSERT_TRUE(host_impl->RootLayer());
-    FakePictureLayerImpl* layer_impl =
-        static_cast<FakePictureLayerImpl*>(host_impl->RootLayer());
+    if (root_impl_ && root_impl_->children().size() > 0) {
+      child_impl_ = static_cast<PushPropertiesCountingLayerImpl*>(
+          root_impl_->children()[0]);
 
-    // The same frame can be draw multiple times if new visible tiles are
-    // rasterized. But we want to make sure we only post DeferredInitialize
-    // and ReleaseGL once, so early out if the same frame is drawn again.
-    if (last_source_frame_number_drawn_ ==
-        host_impl->active_tree()->source_frame_number())
-      return;
+      if (child_impl_ && child_impl_->children().size() > 0)
+        grandchild_impl_ = static_cast<PushPropertiesCountingLayerImpl*>(
+            child_impl_->children()[0]);
+    }
 
-    last_source_frame_number_drawn_ =
-        host_impl->active_tree()->source_frame_number();
+    if (root_impl_ && root_impl_->children().size() > 1) {
+      child2_impl_ = static_cast<PushPropertiesCountingLayerImpl*>(
+          root_impl_->children()[1]);
 
-    if (!did_initialize_gl_) {
-      EXPECT_LE(1u, layer_impl->append_quads_count());
-      ImplThreadTaskRunner()->PostTask(
-          FROM_HERE,
-          base::Bind(
-              &LayerTreeHostTestDeferredInitialize::DeferredInitializeAndRedraw,
-              base::Unretained(this),
-              base::Unretained(host_impl)));
-    } else if (did_initialize_gl_ && !did_release_gl_) {
-      EXPECT_LE(2u, layer_impl->append_quads_count());
-      ImplThreadTaskRunner()->PostTask(
-          FROM_HERE,
-          base::Bind(
-              &LayerTreeHostTestDeferredInitialize::ReleaseGLAndRedraw,
-              base::Unretained(this),
-              base::Unretained(host_impl)));
-    } else if (did_initialize_gl_ && did_release_gl_) {
-      EXPECT_LE(3u, layer_impl->append_quads_count());
-      EndTest();
+      if (child2_impl_ && child2_impl_->children().size() > 0)
+        leaf_always_pushing_layer_impl_ =
+            static_cast<PushPropertiesCountingLayerImpl*>(
+                child2_impl_->children()[0]);
     }
-  }
 
-  void DeferredInitializeAndRedraw(LayerTreeHostImpl* host_impl) {
-    EXPECT_FALSE(did_initialize_gl_);
-    // SetAndInitializeContext3D calls SetNeedsCommit.
-    FakeOutputSurface* fake_output_surface =
-        static_cast<FakeOutputSurface*>(host_impl->output_surface());
-    scoped_refptr<TestContextProvider> context_provider =
-        TestContextProvider::Create();  // Not bound to thread.
-    EXPECT_TRUE(fake_output_surface->InitializeAndSetContext3d(
-        context_provider, NULL));
-    did_initialize_gl_ = true;
-  }
+    if (root_impl_)
+      EXPECT_EQ(expected_push_properties_root_impl_,
+                root_impl_->push_properties_count());
+    if (child_impl_)
+      EXPECT_EQ(expected_push_properties_child_impl_,
+                child_impl_->push_properties_count());
+    if (grandchild_impl_)
+      EXPECT_EQ(expected_push_properties_grandchild_impl_,
+                grandchild_impl_->push_properties_count());
+    if (child2_impl_)
+      EXPECT_EQ(expected_push_properties_child2_impl_,
+                child2_impl_->push_properties_count());
+    if (leaf_always_pushing_layer_impl_)
+      EXPECT_EQ(expected_push_properties_grandchild2_impl_,
+                leaf_always_pushing_layer_impl_->push_properties_count());
+  }
+
+  size_t expected_push_properties_root_impl_;
+  size_t expected_push_properties_child_impl_;
+  size_t expected_push_properties_child2_impl_;
+  size_t expected_push_properties_grandchild_impl_;
+  size_t expected_push_properties_grandchild2_impl_;
+};
 
-  void ReleaseGLAndRedraw(LayerTreeHostImpl* host_impl) {
-    EXPECT_TRUE(did_initialize_gl_);
-    EXPECT_FALSE(did_release_gl_);
-    // ReleaseGL calls SetNeedsCommit.
-    static_cast<FakeOutputSurface*>(host_impl->output_surface())->ReleaseGL();
-    did_release_gl_ = true;
-  }
+TEST_F(LayerTreeHostTestImplLayersPushProperties, DelegatingRenderer) {
+  RunTestWithImplSidePainting();
+}
 
-  virtual void AfterTest() OVERRIDE {
-    EXPECT_TRUE(did_initialize_gl_);
-    EXPECT_TRUE(did_release_gl_);
-  }
+class LayerTreeHostTestPropertyChangesDuringUpdateArePushed
+    : public LayerTreeHostTest {
+ protected:
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
- private:
-  FakeContentLayerClient client_;
-  scoped_refptr<FakePictureLayer> layer_;
-  bool did_initialize_gl_;
-  bool did_release_gl_;
-  int last_source_frame_number_drawn_;
-};
+  virtual void SetupTree() OVERRIDE {
+    root_ = Layer::Create();
+    root_->SetBounds(gfx::Size(1, 1));
 
-MULTI_THREAD_TEST_F(LayerTreeHostTestDeferredInitialize);
+    bool paint_scrollbar = true;
+    bool has_thumb = false;
+    scrollbar_layer_ = FakePaintedScrollbarLayer::Create(
+        paint_scrollbar, has_thumb, root_->id());
 
-// Test for UI Resource management.
-class LayerTreeHostTestUIResource : public LayerTreeHostTest {
- public:
-  LayerTreeHostTestUIResource() : num_ui_resources_(0), num_commits_(0) {}
+    root_->AddChild(scrollbar_layer_);
 
-  virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
-    settings->texture_id_allocation_chunk_size = 1;
+    layer_tree_host()->SetRootLayer(root_);
+    LayerTreeHostTest::SetupTree();
   }
 
-  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+  virtual void DidCommitAndDrawFrame() OVERRIDE {
+    switch (layer_tree_host()->source_frame_number()) {
+      case 0:
+        break;
+      case 1: {
+        // During update, the ignore_set_needs_commit_ bit is set to true to
+        // avoid causing a second commit to be scheduled. If a property change
+        // is made during this, however, it needs to be pushed in the upcoming
+        // commit.
+        scoped_ptr<base::AutoReset<bool> > ignore =
+            scrollbar_layer_->IgnoreSetNeedsCommit();
 
-  virtual void DidCommit() OVERRIDE {
-    int frame = num_commits_;
-    switch (frame) {
-      case 1:
-        CreateResource();
-        CreateResource();
-        PostSetNeedsCommitToMainThread();
+        scrollbar_layer_->SetBounds(gfx::Size(30, 30));
+
+        EXPECT_TRUE(scrollbar_layer_->needs_push_properties());
+        EXPECT_TRUE(root_->descendant_needs_push_properties());
+        layer_tree_host()->SetNeedsCommit();
+
+        scrollbar_layer_->reset_push_properties_count();
+        EXPECT_EQ(0u, scrollbar_layer_->push_properties_count());
         break;
+      }
       case 2:
-        // Usually ScopedUIResource are deleted from the manager in their
-        // destructor.  Here we just want to test that a direct call to
-        // DeleteUIResource works.
-        layer_tree_host()->DeleteUIResource(ui_resources_[0]->id());
-        PostSetNeedsCommitToMainThread();
-        break;
-      case 3:
-        // DeleteUIResource can be called with an invalid id.
-        layer_tree_host()->DeleteUIResource(ui_resources_[0]->id());
-        PostSetNeedsCommitToMainThread();
-        break;
-      case 4:
-        CreateResource();
-        CreateResource();
-        PostSetNeedsCommitToMainThread();
-        break;
-      case 5:
-        ClearResources();
+        EXPECT_EQ(1u, scrollbar_layer_->push_properties_count());
         EndTest();
         break;
     }
   }
 
-  void PerformTest(LayerTreeHostImpl* impl) {
-    TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
-        impl->output_surface()->context_provider()->Context3d());
+  virtual void AfterTest() OVERRIDE {}
 
-    int frame = num_commits_;
-    switch (frame) {
-      case 1:
-        ASSERT_EQ(0u, context->NumTextures());
-        break;
-      case 2:
-        // Created two textures.
-        ASSERT_EQ(2u, context->NumTextures());
-        break;
-      case 3:
-        // One texture left after one deletion.
-        ASSERT_EQ(1u, context->NumTextures());
-        break;
-      case 4:
-        // Resource manager state should not change when delete is called on an
-        // invalid id.
-        ASSERT_EQ(1u, context->NumTextures());
-        break;
-      case 5:
-        // Creation after deletion: two more creates should total up to
-        // three textures.
-        ASSERT_EQ(3u, context->NumTextures());
-        break;
-    }
-  }
-
-  virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
-    ++num_commits_;
-    if (!layer_tree_host()->settings().impl_side_painting)
-      PerformTest(impl);
-  }
-
-  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
-    if (layer_tree_host()->settings().impl_side_painting)
-      PerformTest(impl);
-  }
-
-  virtual void AfterTest() OVERRIDE {}
-
- private:
-  // Must clear all resources before exiting.
-  void ClearResources() {
-    for (int i = 0; i < num_ui_resources_; i++)
-      ui_resources_[i].reset();
-  }
-
-  void CreateResource() {
-    ui_resources_[num_ui_resources_++] =
-        FakeScopedUIResource::Create(layer_tree_host());
-  }
-
-  scoped_ptr<FakeScopedUIResource> ui_resources_[5];
-  int num_ui_resources_;
-  int num_commits_;
+  scoped_refptr<Layer> root_;
+  scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer_;
 };
 
-MULTI_THREAD_TEST_F(LayerTreeHostTestUIResource);
-
-class PushPropertiesCountingLayer : public Layer {
- public:
-  static scoped_refptr<PushPropertiesCountingLayer> Create() {
-    return new PushPropertiesCountingLayer();
-  }
-
-  virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE {
-    Layer::PushPropertiesTo(layer);
-    push_properties_count_++;
-    if (persist_needs_push_properties_)
-      needs_push_properties_ = true;
-  }
-
-  size_t push_properties_count() const { return push_properties_count_; }
-  void reset_push_properties_count() { push_properties_count_ = 0; }
-
-  void set_persist_needs_push_properties(bool persist) {
-    persist_needs_push_properties_ = persist;
-  }
-
- private:
-  PushPropertiesCountingLayer()
-      : push_properties_count_(0),
-        persist_needs_push_properties_(false) {
-    SetAnchorPoint(gfx::PointF());
-    SetBounds(gfx::Size(1, 1));
-    SetIsDrawable(true);
-  }
-  virtual ~PushPropertiesCountingLayer() {}
-
-  size_t push_properties_count_;
-  bool persist_needs_push_properties_;
-};
+MULTI_THREAD_TEST_F(LayerTreeHostTestPropertyChangesDuringUpdateArePushed);
 
-class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest {
+class LayerTreeHostTestCasePushPropertiesThreeGrandChildren
+    : public LayerTreeHostTest {
  protected:
   virtual void BeginTest() OVERRIDE {
-    num_commits_ = 0;
     expected_push_properties_root_ = 0;
     expected_push_properties_child_ = 0;
-    expected_push_properties_grandchild_ = 0;
-    expected_push_properties_child2_ = 0;
-    expected_push_properties_other_root_ = 0;
-    expected_push_properties_leaf_layer_ = 0;
+    expected_push_properties_grandchild1_ = 0;
+    expected_push_properties_grandchild2_ = 0;
+    expected_push_properties_grandchild3_ = 0;
     PostSetNeedsCommitToMainThread();
   }
 
   virtual void SetupTree() OVERRIDE {
     root_ = PushPropertiesCountingLayer::Create();
     child_ = PushPropertiesCountingLayer::Create();
-    child2_ = PushPropertiesCountingLayer::Create();
-    grandchild_ = PushPropertiesCountingLayer::Create();
-    leaf_always_pushing_layer_ = PushPropertiesCountingLayer::Create();
-    leaf_always_pushing_layer_->set_persist_needs_push_properties(true);
+    grandchild1_ = PushPropertiesCountingLayer::Create();
+    grandchild2_ = PushPropertiesCountingLayer::Create();
+    grandchild3_ = PushPropertiesCountingLayer::Create();
 
     root_->AddChild(child_);
-    root_->AddChild(child2_);
-    child_->AddChild(grandchild_);
-    child2_->AddChild(leaf_always_pushing_layer_);
-
-    other_root_ = PushPropertiesCountingLayer::Create();
+    child_->AddChild(grandchild1_);
+    child_->AddChild(grandchild2_);
+    child_->AddChild(grandchild3_);
 
     // Don't set the root layer here.
     LayerTreeHostTest::SetupTree();
   }
 
-  virtual void DidCommitAndDrawFrame() OVERRIDE {
-    ++num_commits_;
-
-    EXPECT_EQ(expected_push_properties_root_, root_->push_properties_count());
-    EXPECT_EQ(expected_push_properties_child_, child_->push_properties_count());
-    EXPECT_EQ(expected_push_properties_grandchild_,
-              grandchild_->push_properties_count());
-    EXPECT_EQ(expected_push_properties_child2_,
-              child2_->push_properties_count());
-    EXPECT_EQ(expected_push_properties_other_root_,
-              other_root_->push_properties_count());
-    EXPECT_EQ(expected_push_properties_leaf_layer_,
-              leaf_always_pushing_layer_->push_properties_count());
-
-    // The scrollbar layer always needs to be pushed.
-    if (root_->layer_tree_host()) {
-      EXPECT_TRUE(root_->descendant_needs_push_properties());
-      EXPECT_FALSE(root_->needs_push_properties());
-    }
-    if (child2_->layer_tree_host()) {
-      EXPECT_TRUE(child2_->descendant_needs_push_properties());
-      EXPECT_FALSE(child2_->needs_push_properties());
-    }
-    if (leaf_always_pushing_layer_->layer_tree_host()) {
-      EXPECT_FALSE(
-          leaf_always_pushing_layer_->descendant_needs_push_properties());
-      EXPECT_TRUE(leaf_always_pushing_layer_->needs_push_properties());
-    }
-
-    // child_ and grandchild_ don't persist their need to push properties.
-    if (child_->layer_tree_host()) {
-      EXPECT_FALSE(child_->descendant_needs_push_properties());
-      EXPECT_FALSE(child_->needs_push_properties());
-    }
-    if (grandchild_->layer_tree_host()) {
-      EXPECT_FALSE(grandchild_->descendant_needs_push_properties());
-      EXPECT_FALSE(grandchild_->needs_push_properties());
-    }
+  virtual void AfterTest() OVERRIDE {}
 
-    if (other_root_->layer_tree_host()) {
-      EXPECT_FALSE(other_root_->descendant_needs_push_properties());
-      EXPECT_FALSE(other_root_->needs_push_properties());
-    }
+  FakeContentLayerClient client_;
+  scoped_refptr<PushPropertiesCountingLayer> root_;
+  scoped_refptr<PushPropertiesCountingLayer> child_;
+  scoped_refptr<PushPropertiesCountingLayer> grandchild1_;
+  scoped_refptr<PushPropertiesCountingLayer> grandchild2_;
+  scoped_refptr<PushPropertiesCountingLayer> grandchild3_;
+  size_t expected_push_properties_root_;
+  size_t expected_push_properties_child_;
+  size_t expected_push_properties_grandchild1_;
+  size_t expected_push_properties_grandchild2_;
+  size_t expected_push_properties_grandchild3_;
+};
 
-    switch (num_commits_) {
-      case 1:
-        layer_tree_host()->SetRootLayer(root_);
-        // Layers added to the tree get committed.
-        ++expected_push_properties_root_;
-        ++expected_push_properties_child_;
-        ++expected_push_properties_grandchild_;
-        ++expected_push_properties_child2_;
-        break;
-      case 2:
-        layer_tree_host()->SetNeedsCommit();
-        // No layers need commit.
-        break;
-      case 3:
-        layer_tree_host()->SetRootLayer(other_root_);
-        // Layers added to the tree get committed.
-        ++expected_push_properties_other_root_;
-        break;
-      case 4:
-        layer_tree_host()->SetRootLayer(root_);
-        // Layers added to the tree get committed.
-        ++expected_push_properties_root_;
-        ++expected_push_properties_child_;
-        ++expected_push_properties_grandchild_;
-        ++expected_push_properties_child2_;
-        break;
-      case 5:
-        layer_tree_host()->SetNeedsCommit();
-        // No layers need commit.
-        break;
-      case 6:
-        child_->RemoveFromParent();
-        // No layers need commit.
-        break;
-      case 7:
-        root_->AddChild(child_);
-        // Layers added to the tree get committed.
-        ++expected_push_properties_child_;
-        ++expected_push_properties_grandchild_;
-        break;
-      case 8:
-        grandchild_->RemoveFromParent();
-        // No layers need commit.
-        break;
-      case 9:
-        child_->AddChild(grandchild_);
-        // Layers added to the tree get committed.
-        ++expected_push_properties_grandchild_;
-        break;
-      case 10:
-        layer_tree_host()->SetViewportSize(gfx::Size(20, 20));
-        // No layers need commit.
-        break;
-      case 11:
-        layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.8f, 1.1f);
-        // No layers need commit.
-        break;
-      case 12:
-        child_->SetPosition(gfx::Point(1, 1));
-        // The modified layer needs commit
-        ++expected_push_properties_child_;
-        break;
-      case 13:
-        child2_->SetPosition(gfx::Point(1, 1));
-        // The modified layer needs commit
-        ++expected_push_properties_child2_;
-        break;
-      case 14:
-        child_->RemoveFromParent();
-        root_->AddChild(child_);
-        // Layers added to the tree get committed.
-        ++expected_push_properties_child_;
-        ++expected_push_properties_grandchild_;
-        break;
-      case 15:
-        grandchild_->SetPosition(gfx::Point(1, 1));
-        // The modified layer needs commit
-        ++expected_push_properties_grandchild_;
-        break;
-      case 16:
-        // SetNeedsDisplay does not always set needs commit (so call it
-        // explicitly), but is a property change.
-        child_->SetNeedsDisplay();
-        ++expected_push_properties_child_;
-        layer_tree_host()->SetNeedsCommit();
+class LayerTreeHostTestPushPropertiesAddingToTreeRequiresPush
+    : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren {
+ protected:
+  virtual void DidCommitAndDrawFrame() OVERRIDE {
+    int last_source_frame_number = layer_tree_host()->source_frame_number() - 1;
+    switch (last_source_frame_number) {
+      case 0:
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_FALSE(root_->descendant_needs_push_properties());
+        EXPECT_FALSE(child_->needs_push_properties());
+        EXPECT_FALSE(child_->descendant_needs_push_properties());
+        EXPECT_FALSE(grandchild1_->needs_push_properties());
+        EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
+        EXPECT_FALSE(grandchild2_->needs_push_properties());
+        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
+        EXPECT_FALSE(grandchild3_->needs_push_properties());
+        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
+
+        layer_tree_host()->SetRootLayer(root_);
+
+        EXPECT_TRUE(root_->needs_push_properties());
+        EXPECT_TRUE(root_->descendant_needs_push_properties());
+        EXPECT_TRUE(child_->needs_push_properties());
+        EXPECT_TRUE(child_->descendant_needs_push_properties());
+        EXPECT_TRUE(grandchild1_->needs_push_properties());
+        EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
+        EXPECT_TRUE(grandchild2_->needs_push_properties());
+        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
+        EXPECT_TRUE(grandchild3_->needs_push_properties());
+        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
         break;
-      case 17:
+      case 1:
         EndTest();
         break;
     }
-
-    // The leaf layer always pushes.
-    if (leaf_always_pushing_layer_->layer_tree_host())
-      ++expected_push_properties_leaf_layer_;
   }
-
-  virtual void AfterTest() OVERRIDE {}
-
-  int num_commits_;
-  FakeContentLayerClient client_;
-  scoped_refptr<PushPropertiesCountingLayer> root_;
-  scoped_refptr<PushPropertiesCountingLayer> child_;
-  scoped_refptr<PushPropertiesCountingLayer> child2_;
-  scoped_refptr<PushPropertiesCountingLayer> grandchild_;
-  scoped_refptr<PushPropertiesCountingLayer> other_root_;
-  scoped_refptr<PushPropertiesCountingLayer> leaf_always_pushing_layer_;
-  size_t expected_push_properties_root_;
-  size_t expected_push_properties_child_;
-  size_t expected_push_properties_child2_;
-  size_t expected_push_properties_grandchild_;
-  size_t expected_push_properties_other_root_;
-  size_t expected_push_properties_leaf_layer_;
 };
 
-MULTI_THREAD_TEST_F(LayerTreeHostTestLayersPushProperties);
+MULTI_THREAD_TEST_F(LayerTreeHostTestPushPropertiesAddingToTreeRequiresPush);
 
-class LayerTreeHostTestPropertyChangesDuringUpdateArePushed
-    : public LayerTreeHostTest {
+class LayerTreeHostTestPushPropertiesRemovingChildStopsRecursion
+    : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren {
  protected:
-  virtual void BeginTest() OVERRIDE {
-    PostSetNeedsCommitToMainThread();
-  }
+  virtual void DidCommitAndDrawFrame() OVERRIDE {
+    int last_source_frame_number = layer_tree_host()->source_frame_number() - 1;
+    switch (last_source_frame_number) {
+      case 0:
+        layer_tree_host()->SetRootLayer(root_);
+        break;
+      case 1:
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_FALSE(root_->descendant_needs_push_properties());
+        EXPECT_FALSE(child_->needs_push_properties());
+        EXPECT_FALSE(child_->descendant_needs_push_properties());
+        EXPECT_FALSE(grandchild1_->needs_push_properties());
+        EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
+        EXPECT_FALSE(grandchild2_->needs_push_properties());
+        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
+        EXPECT_FALSE(grandchild3_->needs_push_properties());
+        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
 
-  virtual void SetupTree() OVERRIDE {
-    root_ = Layer::Create();
-    root_->SetBounds(gfx::Size(1, 1));
+        grandchild1_->RemoveFromParent();
+        grandchild1_->SetPosition(gfx::Point(1, 1));
 
-    bool paint_scrollbar = true;
-    bool has_thumb = false;
-    scrollbar_layer_ = FakePaintedScrollbarLayer::Create(
-        paint_scrollbar, has_thumb, root_->id());
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_FALSE(root_->descendant_needs_push_properties());
+        EXPECT_FALSE(child_->needs_push_properties());
+        EXPECT_FALSE(child_->descendant_needs_push_properties());
+        EXPECT_FALSE(grandchild2_->needs_push_properties());
+        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
+        EXPECT_FALSE(grandchild3_->needs_push_properties());
+        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
 
-    root_->AddChild(scrollbar_layer_);
+        child_->AddChild(grandchild1_);
 
-    layer_tree_host()->SetRootLayer(root_);
-    LayerTreeHostTest::SetupTree();
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_TRUE(root_->descendant_needs_push_properties());
+        EXPECT_FALSE(child_->needs_push_properties());
+        EXPECT_TRUE(child_->descendant_needs_push_properties());
+        EXPECT_TRUE(grandchild1_->needs_push_properties());
+        EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
+        EXPECT_FALSE(grandchild2_->needs_push_properties());
+        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
+        EXPECT_FALSE(grandchild3_->needs_push_properties());
+        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
+
+        grandchild2_->SetPosition(gfx::Point(1, 1));
+
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_TRUE(root_->descendant_needs_push_properties());
+        EXPECT_FALSE(child_->needs_push_properties());
+        EXPECT_TRUE(child_->descendant_needs_push_properties());
+        EXPECT_TRUE(grandchild1_->needs_push_properties());
+        EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
+        EXPECT_TRUE(grandchild2_->needs_push_properties());
+        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
+        EXPECT_FALSE(grandchild3_->needs_push_properties());
+        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
+
+        // grandchild2_ will still need a push properties.
+        grandchild1_->RemoveFromParent();
+
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_TRUE(root_->descendant_needs_push_properties());
+        EXPECT_FALSE(child_->needs_push_properties());
+        EXPECT_TRUE(child_->descendant_needs_push_properties());
+
+        // grandchild3_ does not need a push properties, so recursing should
+        // no longer be needed.
+        grandchild2_->RemoveFromParent();
+
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_FALSE(root_->descendant_needs_push_properties());
+        EXPECT_FALSE(child_->needs_push_properties());
+        EXPECT_FALSE(child_->descendant_needs_push_properties());
+        EndTest();
+        break;
+    }
   }
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostTestPushPropertiesRemovingChildStopsRecursion);
 
+class LayerTreeHostTestPushPropertiesRemovingChildStopsRecursionWithPersistence
+    : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren {
+ protected:
   virtual void DidCommitAndDrawFrame() OVERRIDE {
-    switch (layer_tree_host()->source_frame_number()) {
+    int last_source_frame_number = layer_tree_host()->source_frame_number() - 1;
+    switch (last_source_frame_number) {
       case 0:
+        layer_tree_host()->SetRootLayer(root_);
+        grandchild1_->set_persist_needs_push_properties(true);
+        grandchild2_->set_persist_needs_push_properties(true);
         break;
-      case 1: {
-        // During update, the ignore_set_needs_commit_ bit is set to true to
-        // avoid causing a second commit to be scheduled. If a property change
-        // is made during this, however, it needs to be pushed in the upcoming
-        // commit.
-        scoped_ptr<base::AutoReset<bool> > ignore =
-            scrollbar_layer_->IgnoreSetNeedsCommit();
+      case 1:
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_TRUE(root_->descendant_needs_push_properties());
+        EXPECT_FALSE(child_->needs_push_properties());
+        EXPECT_TRUE(child_->descendant_needs_push_properties());
+        EXPECT_TRUE(grandchild1_->needs_push_properties());
+        EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
+        EXPECT_TRUE(grandchild2_->needs_push_properties());
+        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
+        EXPECT_FALSE(grandchild3_->needs_push_properties());
+        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
 
-        scrollbar_layer_->SetBounds(gfx::Size(30, 30));
+        // grandchild2_ will still need a push properties.
+        grandchild1_->RemoveFromParent();
 
-        EXPECT_TRUE(scrollbar_layer_->needs_push_properties());
+        EXPECT_FALSE(root_->needs_push_properties());
         EXPECT_TRUE(root_->descendant_needs_push_properties());
-        layer_tree_host()->SetNeedsCommit();
+        EXPECT_FALSE(child_->needs_push_properties());
+        EXPECT_TRUE(child_->descendant_needs_push_properties());
 
-        scrollbar_layer_->reset_push_properties_count();
-        EXPECT_EQ(0u, scrollbar_layer_->push_properties_count());
-        break;
-      }
-      case 2:
-        EXPECT_EQ(1u, scrollbar_layer_->push_properties_count());
+        // grandchild3_ does not need a push properties, so recursing should
+        // no longer be needed.
+        grandchild2_->RemoveFromParent();
+
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_FALSE(root_->descendant_needs_push_properties());
+        EXPECT_FALSE(child_->needs_push_properties());
+        EXPECT_FALSE(child_->descendant_needs_push_properties());
         EndTest();
         break;
     }
   }
-
-  virtual void AfterTest() OVERRIDE {}
-
-  scoped_refptr<Layer> root_;
-  scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer_;
 };
 
-MULTI_THREAD_TEST_F(LayerTreeHostTestPropertyChangesDuringUpdateArePushed);
+MULTI_THREAD_TEST_F(
+    LayerTreeHostTestPushPropertiesRemovingChildStopsRecursionWithPersistence);
 
-class LayerTreeHostTestCasePushPropertiesThreeGrandChildren
-    : public LayerTreeHostTest {
+class LayerTreeHostTestPushPropertiesSetPropertiesWhileOutsideTree
+    : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren {
  protected:
-  virtual void BeginTest() OVERRIDE {
-    expected_push_properties_root_ = 0;
-    expected_push_properties_child_ = 0;
-    expected_push_properties_grandchild1_ = 0;
-    expected_push_properties_grandchild2_ = 0;
-    expected_push_properties_grandchild3_ = 0;
-    PostSetNeedsCommitToMainThread();
-  }
+  virtual void DidCommitAndDrawFrame() OVERRIDE {
+    int last_source_frame_number = layer_tree_host()->source_frame_number() - 1;
+    switch (last_source_frame_number) {
+      case 0:
+        layer_tree_host()->SetRootLayer(root_);
+        break;
+      case 1:
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_FALSE(root_->descendant_needs_push_properties());
+        EXPECT_FALSE(child_->needs_push_properties());
+        EXPECT_FALSE(child_->descendant_needs_push_properties());
+        EXPECT_FALSE(grandchild1_->needs_push_properties());
+        EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
+        EXPECT_FALSE(grandchild2_->needs_push_properties());
+        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
+        EXPECT_FALSE(grandchild3_->needs_push_properties());
+        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
 
-  virtual void SetupTree() OVERRIDE {
-    root_ = PushPropertiesCountingLayer::Create();
-    child_ = PushPropertiesCountingLayer::Create();
-    grandchild1_ = PushPropertiesCountingLayer::Create();
-    grandchild2_ = PushPropertiesCountingLayer::Create();
-    grandchild3_ = PushPropertiesCountingLayer::Create();
+        // Change grandchildren while their parent is not in the tree.
+        child_->RemoveFromParent();
+        grandchild1_->SetPosition(gfx::Point(1, 1));
+        grandchild2_->SetPosition(gfx::Point(1, 1));
+        root_->AddChild(child_);
 
-    root_->AddChild(child_);
-    child_->AddChild(grandchild1_);
-    child_->AddChild(grandchild2_);
-    child_->AddChild(grandchild3_);
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_TRUE(root_->descendant_needs_push_properties());
+        EXPECT_TRUE(child_->needs_push_properties());
+        EXPECT_TRUE(child_->descendant_needs_push_properties());
+        EXPECT_TRUE(grandchild1_->needs_push_properties());
+        EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
+        EXPECT_TRUE(grandchild2_->needs_push_properties());
+        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
+        EXPECT_TRUE(grandchild3_->needs_push_properties());
+        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
+
+        grandchild1_->RemoveFromParent();
+
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_TRUE(root_->descendant_needs_push_properties());
+        EXPECT_TRUE(child_->needs_push_properties());
+        EXPECT_TRUE(child_->descendant_needs_push_properties());
+
+        grandchild2_->RemoveFromParent();
+
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_TRUE(root_->descendant_needs_push_properties());
+        EXPECT_TRUE(child_->needs_push_properties());
+        EXPECT_TRUE(child_->descendant_needs_push_properties());
 
-    // Don't set the root layer here.
-    LayerTreeHostTest::SetupTree();
-  }
+        grandchild3_->RemoveFromParent();
 
-  virtual void AfterTest() OVERRIDE {}
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_TRUE(root_->descendant_needs_push_properties());
+        EXPECT_TRUE(child_->needs_push_properties());
+        EXPECT_FALSE(child_->descendant_needs_push_properties());
 
-  FakeContentLayerClient client_;
-  scoped_refptr<PushPropertiesCountingLayer> root_;
-  scoped_refptr<PushPropertiesCountingLayer> child_;
-  scoped_refptr<PushPropertiesCountingLayer> grandchild1_;
-  scoped_refptr<PushPropertiesCountingLayer> grandchild2_;
-  scoped_refptr<PushPropertiesCountingLayer> grandchild3_;
-  size_t expected_push_properties_root_;
-  size_t expected_push_properties_child_;
-  size_t expected_push_properties_grandchild1_;
-  size_t expected_push_properties_grandchild2_;
-  size_t expected_push_properties_grandchild3_;
+        EndTest();
+        break;
+    }
+  }
 };
 
-class LayerTreeHostTestPushPropertiesAddingToTreeRequiresPush
+MULTI_THREAD_TEST_F(
+    LayerTreeHostTestPushPropertiesSetPropertiesWhileOutsideTree);
+
+class LayerTreeHostTestPushPropertiesSetPropertyInParentThenChild
     : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren {
  protected:
   virtual void DidCommitAndDrawFrame() OVERRIDE {
     int last_source_frame_number = layer_tree_host()->source_frame_number() - 1;
     switch (last_source_frame_number) {
       case 0:
+        layer_tree_host()->SetRootLayer(root_);
+        break;
+      case 1:
         EXPECT_FALSE(root_->needs_push_properties());
         EXPECT_FALSE(root_->descendant_needs_push_properties());
         EXPECT_FALSE(child_->needs_push_properties());
@@ -4208,9 +4080,11 @@ class LayerTreeHostTestPushPropertiesAddingToTreeRequiresPush
         EXPECT_FALSE(grandchild3_->needs_push_properties());
         EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
 
-        layer_tree_host()->SetRootLayer(root_);
+        child_->SetPosition(gfx::Point(1, 1));
+        grandchild1_->SetPosition(gfx::Point(1, 1));
+        grandchild2_->SetPosition(gfx::Point(1, 1));
 
-        EXPECT_TRUE(root_->needs_push_properties());
+        EXPECT_FALSE(root_->needs_push_properties());
         EXPECT_TRUE(root_->descendant_needs_push_properties());
         EXPECT_TRUE(child_->needs_push_properties());
         EXPECT_TRUE(child_->descendant_needs_push_properties());
@@ -4218,19 +4092,38 @@ class LayerTreeHostTestPushPropertiesAddingToTreeRequiresPush
         EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
         EXPECT_TRUE(grandchild2_->needs_push_properties());
         EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
-        EXPECT_TRUE(grandchild3_->needs_push_properties());
+        EXPECT_FALSE(grandchild3_->needs_push_properties());
         EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
-        break;
-      case 1:
+
+        grandchild1_->RemoveFromParent();
+
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_TRUE(root_->descendant_needs_push_properties());
+        EXPECT_TRUE(child_->needs_push_properties());
+        EXPECT_TRUE(child_->descendant_needs_push_properties());
+
+        grandchild2_->RemoveFromParent();
+
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_TRUE(root_->descendant_needs_push_properties());
+        EXPECT_TRUE(child_->needs_push_properties());
+        EXPECT_FALSE(child_->descendant_needs_push_properties());
+
+        child_->RemoveFromParent();
+
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_FALSE(root_->descendant_needs_push_properties());
+
         EndTest();
         break;
     }
   }
 };
 
-MULTI_THREAD_TEST_F(LayerTreeHostTestPushPropertiesAddingToTreeRequiresPush);
+MULTI_THREAD_TEST_F(
+    LayerTreeHostTestPushPropertiesSetPropertyInParentThenChild);
 
-class LayerTreeHostTestPushPropertiesRemovingChildStopsRecursion
+class LayerTreeHostTestPushPropertiesSetPropertyInChildThenParent
     : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren {
  protected:
   virtual void DidCommitAndDrawFrame() OVERRIDE {
@@ -4251,964 +4144,1149 @@ class LayerTreeHostTestPushPropertiesRemovingChildStopsRecursion
         EXPECT_FALSE(grandchild3_->needs_push_properties());
         EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
 
-        grandchild1_->RemoveFromParent();
         grandchild1_->SetPosition(gfx::Point(1, 1));
-
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_FALSE(root_->descendant_needs_push_properties());
-        EXPECT_FALSE(child_->needs_push_properties());
-        EXPECT_FALSE(child_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild2_->needs_push_properties());
-        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild3_->needs_push_properties());
-        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
-
-        child_->AddChild(grandchild1_);
+        grandchild2_->SetPosition(gfx::Point(1, 1));
+        child_->SetPosition(gfx::Point(1, 1));
 
         EXPECT_FALSE(root_->needs_push_properties());
         EXPECT_TRUE(root_->descendant_needs_push_properties());
-        EXPECT_FALSE(child_->needs_push_properties());
+        EXPECT_TRUE(child_->needs_push_properties());
         EXPECT_TRUE(child_->descendant_needs_push_properties());
         EXPECT_TRUE(grandchild1_->needs_push_properties());
         EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild2_->needs_push_properties());
+        EXPECT_TRUE(grandchild2_->needs_push_properties());
         EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
         EXPECT_FALSE(grandchild3_->needs_push_properties());
         EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
 
-        grandchild2_->SetPosition(gfx::Point(1, 1));
+        grandchild1_->RemoveFromParent();
 
         EXPECT_FALSE(root_->needs_push_properties());
         EXPECT_TRUE(root_->descendant_needs_push_properties());
-        EXPECT_FALSE(child_->needs_push_properties());
+        EXPECT_TRUE(child_->needs_push_properties());
         EXPECT_TRUE(child_->descendant_needs_push_properties());
-        EXPECT_TRUE(grandchild1_->needs_push_properties());
-        EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
-        EXPECT_TRUE(grandchild2_->needs_push_properties());
-        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild3_->needs_push_properties());
-        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
 
-        // grandchild2_ will still need a push properties.
-        grandchild1_->RemoveFromParent();
+        grandchild2_->RemoveFromParent();
+
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_TRUE(root_->descendant_needs_push_properties());
+        EXPECT_TRUE(child_->needs_push_properties());
+        EXPECT_FALSE(child_->descendant_needs_push_properties());
+
+        child_->RemoveFromParent();
+
+        EXPECT_FALSE(root_->needs_push_properties());
+        EXPECT_FALSE(root_->descendant_needs_push_properties());
+
+        EndTest();
+        break;
+    }
+  }
+};
+
+MULTI_THREAD_TEST_F(
+    LayerTreeHostTestPushPropertiesSetPropertyInChildThenParent);
+
+// This test verifies that the tree activation callback is invoked correctly.
+class LayerTreeHostTestTreeActivationCallback : public LayerTreeHostTest {
+ public:
+  LayerTreeHostTestTreeActivationCallback()
+      : num_commits_(0), callback_count_(0) {}
+
+  virtual void BeginTest() OVERRIDE {
+    EXPECT_TRUE(HasImplThread());
+    PostSetNeedsCommitToMainThread();
+  }
+
+  virtual DrawSwapReadbackResult::DrawResult PrepareToDrawOnThread(
+      LayerTreeHostImpl* host_impl,
+      LayerTreeHostImpl::FrameData* frame_data,
+      DrawSwapReadbackResult::DrawResult draw_result) OVERRIDE {
+    ++num_commits_;
+    switch (num_commits_) {
+      case 1:
+        EXPECT_EQ(0, callback_count_);
+        callback_count_ = 0;
+        SetCallback(true);
+        PostSetNeedsCommitToMainThread();
+        break;
+      case 2:
+        EXPECT_EQ(1, callback_count_);
+        callback_count_ = 0;
+        SetCallback(false);
+        PostSetNeedsCommitToMainThread();
+        break;
+      case 3:
+        EXPECT_EQ(0, callback_count_);
+        callback_count_ = 0;
+        EndTest();
+        break;
+      default:
+        ADD_FAILURE() << num_commits_;
+        EndTest();
+        break;
+    }
+    return LayerTreeHostTest::PrepareToDrawOnThread(
+        host_impl, frame_data, draw_result);
+  }
+
+  virtual void AfterTest() OVERRIDE { EXPECT_EQ(3, num_commits_); }
+
+  void SetCallback(bool enable) {
+    output_surface()->SetTreeActivationCallback(
+        enable
+            ? base::Bind(
+                  &LayerTreeHostTestTreeActivationCallback::ActivationCallback,
+                  base::Unretained(this))
+            : base::Closure());
+  }
+
+  void ActivationCallback() { ++callback_count_; }
+
+  int num_commits_;
+  int callback_count_;
+};
+
+TEST_F(LayerTreeHostTestTreeActivationCallback, DirectRenderer) {
+  RunTest(true, false, true);
+}
+
+TEST_F(LayerTreeHostTestTreeActivationCallback, DelegatingRenderer) {
+  RunTest(true, true, true);
+}
+
+class LayerInvalidateCausesDraw : public LayerTreeHostTest {
+ public:
+  LayerInvalidateCausesDraw() : num_commits_(0), num_draws_(0) {}
+
+  virtual void BeginTest() OVERRIDE {
+    ASSERT_TRUE(!!invalidate_layer_)
+        << "Derived tests must set this in SetupTree";
+
+    // One initial commit.
+    PostSetNeedsCommitToMainThread();
+  }
+
+  virtual void DidCommitAndDrawFrame() OVERRIDE {
+    // After commit, invalidate the layer.  This should cause a commit.
+    if (layer_tree_host()->source_frame_number() == 1)
+      invalidate_layer_->SetNeedsDisplay();
+  }
+
+  virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+    num_draws_++;
+    if (impl->active_tree()->source_frame_number() == 1)
+      EndTest();
+  }
+
+  virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+    num_commits_++;
+  }
+
+  virtual void AfterTest() OVERRIDE {
+    EXPECT_GE(2, num_commits_);
+    EXPECT_GE(2, num_draws_);
+  }
+
+ protected:
+  scoped_refptr<Layer> invalidate_layer_;
+
+ private:
+  int num_commits_;
+  int num_draws_;
+};
+
+// VideoLayer must support being invalidated and then passing that along
+// to the compositor thread, even though no resources are updated in
+// response to that invalidation.
+class LayerTreeHostTestVideoLayerInvalidate : public LayerInvalidateCausesDraw {
+ public:
+  virtual void SetupTree() OVERRIDE {
+    LayerTreeHostTest::SetupTree();
+    scoped_refptr<VideoLayer> video_layer = VideoLayer::Create(&provider_);
+    video_layer->SetBounds(gfx::Size(10, 10));
+    video_layer->SetIsDrawable(true);
+    layer_tree_host()->root_layer()->AddChild(video_layer);
+
+    invalidate_layer_ = video_layer;
+  }
+
+ private:
+  FakeVideoFrameProvider provider_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestVideoLayerInvalidate);
+
+// IOSurfaceLayer must support being invalidated and then passing that along
+// to the compositor thread, even though no resources are updated in
+// response to that invalidation.
+class LayerTreeHostTestIOSurfaceLayerInvalidate
+    : public LayerInvalidateCausesDraw {
+ public:
+  virtual void SetupTree() OVERRIDE {
+    LayerTreeHostTest::SetupTree();
+    scoped_refptr<IOSurfaceLayer> layer = IOSurfaceLayer::Create();
+    layer->SetBounds(gfx::Size(10, 10));
+    uint32_t fake_io_surface_id = 7;
+    layer->SetIOSurfaceProperties(fake_io_surface_id, layer->bounds());
+    layer->SetIsDrawable(true);
+    layer_tree_host()->root_layer()->AddChild(layer);
+
+    invalidate_layer_ = layer;
+  }
+};
+
+// TODO(danakj): IOSurface layer can not be transported. crbug.com/239335
+SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
+    LayerTreeHostTestIOSurfaceLayerInvalidate);
+
+class LayerTreeHostTestPushHiddenLayer : public LayerTreeHostTest {
+ protected:
+  virtual void SetupTree() OVERRIDE {
+    root_layer_ = Layer::Create();
+    root_layer_->SetAnchorPoint(gfx::PointF());
+    root_layer_->SetPosition(gfx::Point());
+    root_layer_->SetBounds(gfx::Size(10, 10));
 
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_TRUE(root_->descendant_needs_push_properties());
-        EXPECT_FALSE(child_->needs_push_properties());
-        EXPECT_TRUE(child_->descendant_needs_push_properties());
+    parent_layer_ = SolidColorLayer::Create();
+    parent_layer_->SetAnchorPoint(gfx::PointF());
+    parent_layer_->SetPosition(gfx::Point());
+    parent_layer_->SetBounds(gfx::Size(10, 10));
+    parent_layer_->SetIsDrawable(true);
+    root_layer_->AddChild(parent_layer_);
 
-        // grandchild3_ does not need a push properties, so recursing should
-        // no longer be needed.
-        grandchild2_->RemoveFromParent();
+    child_layer_ = SolidColorLayer::Create();
+    child_layer_->SetAnchorPoint(gfx::PointF());
+    child_layer_->SetPosition(gfx::Point());
+    child_layer_->SetBounds(gfx::Size(10, 10));
+    child_layer_->SetIsDrawable(true);
+    parent_layer_->AddChild(child_layer_);
 
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_FALSE(root_->descendant_needs_push_properties());
-        EXPECT_FALSE(child_->needs_push_properties());
-        EXPECT_FALSE(child_->descendant_needs_push_properties());
-        EndTest();
-        break;
-    }
+    layer_tree_host()->SetRootLayer(root_layer_);
+    LayerTreeHostTest::SetupTree();
   }
-};
 
-MULTI_THREAD_TEST_F(LayerTreeHostTestPushPropertiesRemovingChildStopsRecursion);
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
-class LayerTreeHostTestPushPropertiesRemovingChildStopsRecursionWithPersistence
-    : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren {
- protected:
   virtual void DidCommitAndDrawFrame() OVERRIDE {
-    int last_source_frame_number = layer_tree_host()->source_frame_number() - 1;
-    switch (last_source_frame_number) {
-      case 0:
-        layer_tree_host()->SetRootLayer(root_);
-        grandchild1_->set_persist_needs_push_properties(true);
-        grandchild2_->set_persist_needs_push_properties(true);
-        break;
+    switch (layer_tree_host()->source_frame_number()) {
       case 1:
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_TRUE(root_->descendant_needs_push_properties());
-        EXPECT_FALSE(child_->needs_push_properties());
-        EXPECT_TRUE(child_->descendant_needs_push_properties());
-        EXPECT_TRUE(grandchild1_->needs_push_properties());
-        EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
-        EXPECT_TRUE(grandchild2_->needs_push_properties());
-        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild3_->needs_push_properties());
-        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
-
-        // grandchild2_ will still need a push properties.
-        grandchild1_->RemoveFromParent();
-
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_TRUE(root_->descendant_needs_push_properties());
-        EXPECT_FALSE(child_->needs_push_properties());
-        EXPECT_TRUE(child_->descendant_needs_push_properties());
+        // The layer type used does not need to push properties every frame.
+        EXPECT_FALSE(child_layer_->needs_push_properties());
 
-        // grandchild3_ does not need a push properties, so recursing should
-        // no longer be needed.
-        grandchild2_->RemoveFromParent();
+        // Change the bounds of the child layer, but make it skipped
+        // by CalculateDrawProperties.
+        parent_layer_->SetOpacity(0.f);
+        child_layer_->SetBounds(gfx::Size(5, 5));
+        break;
+      case 2:
+        // The bounds of the child layer were pushed to the impl side.
+        EXPECT_FALSE(child_layer_->needs_push_properties());
 
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_FALSE(root_->descendant_needs_push_properties());
-        EXPECT_FALSE(child_->needs_push_properties());
-        EXPECT_FALSE(child_->descendant_needs_push_properties());
         EndTest();
         break;
     }
   }
-};
 
-MULTI_THREAD_TEST_F(
-    LayerTreeHostTestPushPropertiesRemovingChildStopsRecursionWithPersistence);
+  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+    LayerImpl* root = impl->active_tree()->root_layer();
+    LayerImpl* parent = root->children()[0];
+    LayerImpl* child = parent->children()[0];
 
-class LayerTreeHostTestPushPropertiesSetPropertiesWhileOutsideTree
-    : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren {
- protected:
-  virtual void DidCommitAndDrawFrame() OVERRIDE {
-    int last_source_frame_number = layer_tree_host()->source_frame_number() - 1;
-    switch (last_source_frame_number) {
-      case 0:
-        layer_tree_host()->SetRootLayer(root_);
-        break;
+    switch (impl->active_tree()->source_frame_number()) {
       case 1:
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_FALSE(root_->descendant_needs_push_properties());
-        EXPECT_FALSE(child_->needs_push_properties());
-        EXPECT_FALSE(child_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild1_->needs_push_properties());
-        EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild2_->needs_push_properties());
-        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild3_->needs_push_properties());
-        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
-
-        // Change grandchildren while their parent is not in the tree.
-        child_->RemoveFromParent();
-        grandchild1_->SetPosition(gfx::Point(1, 1));
-        grandchild2_->SetPosition(gfx::Point(1, 1));
-        root_->AddChild(child_);
-
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_TRUE(root_->descendant_needs_push_properties());
-        EXPECT_TRUE(child_->needs_push_properties());
-        EXPECT_TRUE(child_->descendant_needs_push_properties());
-        EXPECT_TRUE(grandchild1_->needs_push_properties());
-        EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
-        EXPECT_TRUE(grandchild2_->needs_push_properties());
-        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
-        EXPECT_TRUE(grandchild3_->needs_push_properties());
-        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
+        EXPECT_EQ(gfx::Size(5, 5).ToString(), child->bounds().ToString());
+        break;
+    }
+  }
 
-        grandchild1_->RemoveFromParent();
+  virtual void AfterTest() OVERRIDE {}
 
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_TRUE(root_->descendant_needs_push_properties());
-        EXPECT_TRUE(child_->needs_push_properties());
-        EXPECT_TRUE(child_->descendant_needs_push_properties());
+  scoped_refptr<Layer> root_layer_;
+  scoped_refptr<SolidColorLayer> parent_layer_;
+  scoped_refptr<SolidColorLayer> child_layer_;
+};
 
-        grandchild2_->RemoveFromParent();
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestPushHiddenLayer);
 
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_TRUE(root_->descendant_needs_push_properties());
-        EXPECT_TRUE(child_->needs_push_properties());
-        EXPECT_TRUE(child_->descendant_needs_push_properties());
+class LayerTreeHostTestUpdateLayerInEmptyViewport : public LayerTreeHostTest {
+ protected:
+  virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
+    settings->impl_side_painting = true;
+  }
 
-        grandchild3_->RemoveFromParent();
+  virtual void SetupTree() OVERRIDE {
+    root_layer_ = FakePictureLayer::Create(&client_);
+    root_layer_->SetAnchorPoint(gfx::PointF());
+    root_layer_->SetBounds(gfx::Size(10, 10));
 
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_TRUE(root_->descendant_needs_push_properties());
-        EXPECT_TRUE(child_->needs_push_properties());
-        EXPECT_FALSE(child_->descendant_needs_push_properties());
+    layer_tree_host()->SetRootLayer(root_layer_);
+    LayerTreeHostTest::SetupTree();
+  }
 
-        EndTest();
-        break;
-    }
+  virtual void BeginTest() OVERRIDE {
+    // The viewport is empty, but we still need to update layers on the main
+    // thread.
+    layer_tree_host()->SetViewportSize(gfx::Size(0, 0));
+    PostSetNeedsCommitToMainThread();
   }
-};
 
-MULTI_THREAD_TEST_F(
-    LayerTreeHostTestPushPropertiesSetPropertiesWhileOutsideTree);
+  virtual void DidCommit() OVERRIDE {
+    // The layer should be updated even though the viewport is empty, so we
+    // are capable of drawing it on the impl tree.
+    EXPECT_GT(root_layer_->update_count(), 0u);
+    EndTest();
+  }
 
-class LayerTreeHostTestPushPropertiesSetPropertyInParentThenChild
-    : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren {
- protected:
-  virtual void DidCommitAndDrawFrame() OVERRIDE {
-    int last_source_frame_number = layer_tree_host()->source_frame_number() - 1;
-    switch (last_source_frame_number) {
-      case 0:
-        layer_tree_host()->SetRootLayer(root_);
-        break;
-      case 1:
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_FALSE(root_->descendant_needs_push_properties());
-        EXPECT_FALSE(child_->needs_push_properties());
-        EXPECT_FALSE(child_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild1_->needs_push_properties());
-        EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild2_->needs_push_properties());
-        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild3_->needs_push_properties());
-        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
+  virtual void AfterTest() OVERRIDE {}
 
-        child_->SetPosition(gfx::Point(1, 1));
-        grandchild1_->SetPosition(gfx::Point(1, 1));
-        grandchild2_->SetPosition(gfx::Point(1, 1));
+  FakeContentLayerClient client_;
+  scoped_refptr<FakePictureLayer> root_layer_;
+};
 
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_TRUE(root_->descendant_needs_push_properties());
-        EXPECT_TRUE(child_->needs_push_properties());
-        EXPECT_TRUE(child_->descendant_needs_push_properties());
-        EXPECT_TRUE(grandchild1_->needs_push_properties());
-        EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
-        EXPECT_TRUE(grandchild2_->needs_push_properties());
-        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild3_->needs_push_properties());
-        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
+MULTI_THREAD_TEST_F(LayerTreeHostTestUpdateLayerInEmptyViewport);
 
-        grandchild1_->RemoveFromParent();
+class LayerTreeHostTestAbortEvictedTextures : public LayerTreeHostTest {
+ public:
+  LayerTreeHostTestAbortEvictedTextures()
+      : num_will_begin_main_frames_(0), num_impl_commits_(0) {}
 
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_TRUE(root_->descendant_needs_push_properties());
-        EXPECT_TRUE(child_->needs_push_properties());
-        EXPECT_TRUE(child_->descendant_needs_push_properties());
+ protected:
+  virtual void SetupTree() OVERRIDE {
+    scoped_refptr<SolidColorLayer> root_layer = SolidColorLayer::Create();
+    root_layer->SetBounds(gfx::Size(200, 200));
+    root_layer->SetIsDrawable(true);
 
-        grandchild2_->RemoveFromParent();
+    layer_tree_host()->SetRootLayer(root_layer);
+    LayerTreeHostTest::SetupTree();
+  }
 
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_TRUE(root_->descendant_needs_push_properties());
-        EXPECT_TRUE(child_->needs_push_properties());
-        EXPECT_FALSE(child_->descendant_needs_push_properties());
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
-        child_->RemoveFromParent();
+  virtual void WillBeginMainFrame() OVERRIDE {
+    num_will_begin_main_frames_++;
+    switch (num_will_begin_main_frames_) {
+      case 2:
+        // Send a redraw to the compositor thread.  This will (wrongly) be
+        // ignored unless aborting resets the texture state.
+        layer_tree_host()->SetNeedsRedraw();
+        break;
+    }
+  }
 
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_FALSE(root_->descendant_needs_push_properties());
+  virtual void BeginCommitOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+    num_impl_commits_++;
+  }
 
+  virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+    switch (impl->SourceAnimationFrameNumber()) {
+      case 1:
+        // Prevent draws until commit.
+        impl->active_tree()->SetContentsTexturesPurged();
+        EXPECT_FALSE(impl->CanDraw());
+        // Trigger an abortable commit.
+        impl->SetNeedsCommit();
+        break;
+      case 2:
         EndTest();
         break;
     }
   }
+
+  virtual void AfterTest() OVERRIDE {
+    // Ensure that the commit was truly aborted.
+    EXPECT_EQ(2, num_will_begin_main_frames_);
+    EXPECT_EQ(1, num_impl_commits_);
+  }
+
+ private:
+  int num_will_begin_main_frames_;
+  int num_impl_commits_;
 };
 
-MULTI_THREAD_TEST_F(
-    LayerTreeHostTestPushPropertiesSetPropertyInParentThenChild);
+// Commits can only be aborted when using the thread proxy.
+MULTI_THREAD_TEST_F(LayerTreeHostTestAbortEvictedTextures);
 
-class LayerTreeHostTestPushPropertiesSetPropertyInChildThenParent
-    : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren {
+class LayerTreeHostTestMaxTransferBufferUsageBytes : public LayerTreeHostTest {
  protected:
-  virtual void DidCommitAndDrawFrame() OVERRIDE {
-    int last_source_frame_number = layer_tree_host()->source_frame_number() - 1;
-    switch (last_source_frame_number) {
-      case 0:
-        layer_tree_host()->SetRootLayer(root_);
-        break;
-      case 1:
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_FALSE(root_->descendant_needs_push_properties());
-        EXPECT_FALSE(child_->needs_push_properties());
-        EXPECT_FALSE(child_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild1_->needs_push_properties());
-        EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild2_->needs_push_properties());
-        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild3_->needs_push_properties());
-        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
-
-        grandchild1_->SetPosition(gfx::Point(1, 1));
-        grandchild2_->SetPosition(gfx::Point(1, 1));
-        child_->SetPosition(gfx::Point(1, 1));
+  virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
+    settings->impl_side_painting = true;
+  }
 
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_TRUE(root_->descendant_needs_push_properties());
-        EXPECT_TRUE(child_->needs_push_properties());
-        EXPECT_TRUE(child_->descendant_needs_push_properties());
-        EXPECT_TRUE(grandchild1_->needs_push_properties());
-        EXPECT_FALSE(grandchild1_->descendant_needs_push_properties());
-        EXPECT_TRUE(grandchild2_->needs_push_properties());
-        EXPECT_FALSE(grandchild2_->descendant_needs_push_properties());
-        EXPECT_FALSE(grandchild3_->needs_push_properties());
-        EXPECT_FALSE(grandchild3_->descendant_needs_push_properties());
+  virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
+      OVERRIDE {
+    scoped_refptr<TestContextProvider> context_provider =
+        TestContextProvider::Create();
+    context_provider->SetMaxTransferBufferUsageBytes(1024 * 1024);
+    if (delegating_renderer())
+      return FakeOutputSurface::CreateDelegating3d(context_provider);
+    else
+      return FakeOutputSurface::Create3d(context_provider);
+  }
 
-        grandchild1_->RemoveFromParent();
+  virtual void SetupTree() OVERRIDE {
+    scoped_refptr<FakePictureLayer> root_layer =
+        FakePictureLayer::Create(&client_);
+    root_layer->SetBounds(gfx::Size(6000, 6000));
+    root_layer->SetIsDrawable(true);
 
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_TRUE(root_->descendant_needs_push_properties());
-        EXPECT_TRUE(child_->needs_push_properties());
-        EXPECT_TRUE(child_->descendant_needs_push_properties());
+    layer_tree_host()->SetRootLayer(root_layer);
+    LayerTreeHostTest::SetupTree();
+  }
 
-        grandchild2_->RemoveFromParent();
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_TRUE(root_->descendant_needs_push_properties());
-        EXPECT_TRUE(child_->needs_push_properties());
-        EXPECT_FALSE(child_->descendant_needs_push_properties());
+  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+    TestWebGraphicsContext3D* context = TestContext();
 
-        child_->RemoveFromParent();
+    // Expect that the transfer buffer memory used is equal to the
+    // MaxTransferBufferUsageBytes value set in CreateOutputSurface.
+    EXPECT_EQ(1024 * 1024u, context->GetTransferBufferMemoryUsedBytes());
+    EndTest();
+  }
 
-        EXPECT_FALSE(root_->needs_push_properties());
-        EXPECT_FALSE(root_->descendant_needs_push_properties());
+  virtual void AfterTest() OVERRIDE {}
 
-        EndTest();
-        break;
-    }
-  }
+ private:
+  FakeContentLayerClient client_;
 };
 
-MULTI_THREAD_TEST_F(
-    LayerTreeHostTestPushPropertiesSetPropertyInChildThenParent);
+// Impl-side painting is a multi-threaded compositor feature.
+MULTI_THREAD_TEST_F(LayerTreeHostTestMaxTransferBufferUsageBytes);
 
-// This test verifies that the tree activation callback is invoked correctly.
-class LayerTreeHostTestTreeActivationCallback : public LayerTreeHostTest {
+// Test ensuring that memory limits are sent to the prioritized resource
+// manager.
+class LayerTreeHostTestMemoryLimits : public LayerTreeHostTest {
  public:
-  LayerTreeHostTestTreeActivationCallback()
-      : num_commits_(0), callback_count_(0) {}
+  LayerTreeHostTestMemoryLimits() : num_commits_(0) {}
 
-  virtual void BeginTest() OVERRIDE {
-    EXPECT_TRUE(HasImplThread());
-    PostSetNeedsCommitToMainThread();
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+
+  virtual void WillCommit() OVERRIDE {
+    // Some commits are aborted, so increment number of attempted commits here.
+    num_commits_++;
   }
 
-  virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
-                                     LayerTreeHostImpl::FrameData* frame_data,
-                                     bool result) OVERRIDE {
-    ++num_commits_;
+  virtual void DidCommit() OVERRIDE {
     switch (num_commits_) {
       case 1:
-        EXPECT_EQ(0, callback_count_);
-        callback_count_ = 0;
-        SetCallback(true);
+        // Verify default values.
+        EXPECT_EQ(PrioritizedResourceManager::DefaultMemoryAllocationLimit(),
+                  layer_tree_host()
+                      ->contents_texture_manager()
+                      ->MaxMemoryLimitBytes());
+        EXPECT_EQ(PriorityCalculator::AllowEverythingCutoff(),
+                  layer_tree_host()
+                      ->contents_texture_manager()
+                      ->ExternalPriorityCutoff());
         PostSetNeedsCommitToMainThread();
         break;
       case 2:
-        EXPECT_EQ(1, callback_count_);
-        callback_count_ = 0;
-        SetCallback(false);
-        PostSetNeedsCommitToMainThread();
+        // The values should remain the same until the commit after the policy
+        // is changed.
+        EXPECT_EQ(PrioritizedResourceManager::DefaultMemoryAllocationLimit(),
+                  layer_tree_host()
+                      ->contents_texture_manager()
+                      ->MaxMemoryLimitBytes());
+        EXPECT_EQ(PriorityCalculator::AllowEverythingCutoff(),
+                  layer_tree_host()
+                      ->contents_texture_manager()
+                      ->ExternalPriorityCutoff());
         break;
       case 3:
-        EXPECT_EQ(0, callback_count_);
-        callback_count_ = 0;
+        // Verify values were correctly passed.
+        EXPECT_EQ(16u * 1024u * 1024u,
+                  layer_tree_host()
+                      ->contents_texture_manager()
+                      ->MaxMemoryLimitBytes());
+        EXPECT_EQ(PriorityCalculator::AllowVisibleAndNearbyCutoff(),
+                  layer_tree_host()
+                      ->contents_texture_manager()
+                      ->ExternalPriorityCutoff());
         EndTest();
         break;
-      default:
-        ADD_FAILURE() << num_commits_;
-        EndTest();
+      case 4:
+        // Make sure no extra commits happen.
+        NOTREACHED();
+        break;
+    }
+  }
+
+  virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+    switch (num_commits_) {
+      case 1:
+        break;
+      case 2:
+        // This will trigger a commit because the priority cutoff has changed.
+        impl->SetMemoryPolicy(ManagedMemoryPolicy(
+            16u * 1024u * 1024u,
+            gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
+            1000));
+        break;
+      case 3:
+        // This will not trigger a commit because the priority cutoff has not
+        // changed, and there is already enough memory for all allocations.
+        impl->SetMemoryPolicy(ManagedMemoryPolicy(
+            32u * 1024u * 1024u,
+            gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
+            1000));
         break;
+      case 4:
+        NOTREACHED();
+        break;
+    }
+  }
+
+  virtual void AfterTest() OVERRIDE {}
+
+ private:
+  int num_commits_;
+};
+
+SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(LayerTreeHostTestMemoryLimits);
+
+class LayerTreeHostTestNoQuadsForEmptyLayer : public LayerTreeHostTest {
+ protected:
+  virtual void SetupTree() OVERRIDE {
+    LayerTreeHostTest::SetupTree();
+    root_layer_ = FakeContentLayer::Create(&client_);
+    root_layer_->SetBounds(gfx::Size(10, 10));
+    root_layer_->SetIsDrawable(false);
+    root_layer_->SetHaveWheelEventHandlers(true);
+    layer_tree_host()->SetRootLayer(root_layer_);
+    LayerTreeHostTest::SetupTree();
+  }
+
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+
+  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+    FakeContentLayerImpl* layer_impl =
+        static_cast<FakeContentLayerImpl*>(impl->RootLayer());
+    EXPECT_FALSE(layer_impl->DrawsContent());
+    EXPECT_EQ(0u, layer_impl->append_quads_count());
+  }
+
+  virtual void DidCommit() OVERRIDE {
+    // The layer is not drawable, so it should not be updated.
+    EXPECT_EQ(0u, root_layer_->update_count());
+    EndTest();
+  }
+  virtual void AfterTest() OVERRIDE {}
+
+ private:
+  FakeContentLayerClient client_;
+  scoped_refptr<FakeContentLayer> root_layer_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestNoQuadsForEmptyLayer);
+
+}  // namespace
+
+class LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface
+    : public LayerTreeHostTest {
+ protected:
+  LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface()
+      : first_output_surface_memory_limit_(4321234),
+        second_output_surface_memory_limit_(1234321) {}
+
+  virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
+      OVERRIDE {
+    if (!first_context_provider_) {
+      first_context_provider_ = TestContextProvider::Create();
+    } else {
+      EXPECT_FALSE(second_context_provider_);
+      second_context_provider_ = TestContextProvider::Create();
+    }
+
+    scoped_refptr<TestContextProvider> provider(second_context_provider_
+                                                    ? second_context_provider_
+                                                    : first_context_provider_);
+    scoped_ptr<FakeOutputSurface> output_surface;
+    if (delegating_renderer())
+      output_surface = FakeOutputSurface::CreateDelegating3d(provider);
+    else
+      output_surface = FakeOutputSurface::Create3d(provider);
+    output_surface->SetMemoryPolicyToSetAtBind(
+        make_scoped_ptr(new ManagedMemoryPolicy(
+            second_context_provider_ ? second_output_surface_memory_limit_
+                                     : first_output_surface_memory_limit_,
+            gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
+            ManagedMemoryPolicy::kDefaultNumResourcesLimit)));
+    return output_surface.Pass();
+  }
+
+  virtual void SetupTree() OVERRIDE {
+    root_ = FakeContentLayer::Create(&client_);
+    root_->SetBounds(gfx::Size(20, 20));
+    layer_tree_host()->SetRootLayer(root_);
+    LayerTreeHostTest::SetupTree();
+  }
+
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+
+  virtual void DidCommitAndDrawFrame() OVERRIDE {
+    // Lost context sometimes takes two frames to recreate. The third frame
+    // is sometimes aborted, so wait until the fourth frame to verify that
+    // the memory has been set, and the fifth frame to end the test.
+    if (layer_tree_host()->source_frame_number() < 5) {
+      layer_tree_host()->SetNeedsCommit();
+    } else if (layer_tree_host()->source_frame_number() == 5) {
+      EndTest();
     }
-    return LayerTreeHostTest::PrepareToDrawOnThread(host_impl, frame_data,
-                                                    result);
-  }
-
-  virtual void AfterTest() OVERRIDE {
-    EXPECT_EQ(3, num_commits_);
   }
 
-  void SetCallback(bool enable) {
-    output_surface()->SetTreeActivationCallback(enable ?
-        base::Bind(&LayerTreeHostTestTreeActivationCallback::ActivationCallback,
-                   base::Unretained(this)) :
-        base::Closure());
+  virtual void SwapBuffersOnThread(LayerTreeHostImpl* impl,
+                                   bool result) OVERRIDE {
+    switch (impl->active_tree()->source_frame_number()) {
+      case 1:
+        EXPECT_EQ(first_output_surface_memory_limit_,
+                  impl->memory_allocation_limit_bytes());
+        // Lose the output surface.
+        first_context_provider_->TestContext3d()->loseContextCHROMIUM(
+            GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
+        break;
+      case 4:
+        EXPECT_EQ(second_output_surface_memory_limit_,
+                  impl->memory_allocation_limit_bytes());
+        break;
+    }
   }
 
-  void ActivationCallback() {
-    ++callback_count_;
-  }
+  virtual void AfterTest() OVERRIDE {}
 
-  int num_commits_;
-  int callback_count_;
+  scoped_refptr<TestContextProvider> first_context_provider_;
+  scoped_refptr<TestContextProvider> second_context_provider_;
+  size_t first_output_surface_memory_limit_;
+  size_t second_output_surface_memory_limit_;
+  FakeContentLayerClient client_;
+  scoped_refptr<FakeContentLayer> root_;
 };
 
-TEST_F(LayerTreeHostTestTreeActivationCallback, DirectRenderer) {
-  RunTest(true, false, true);
-}
+// No output to copy for delegated renderers.
+SINGLE_AND_MULTI_THREAD_TEST_F(
+    LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface);
 
-TEST_F(LayerTreeHostTestTreeActivationCallback, DelegatingRenderer) {
-  RunTest(true, true, true);
-}
+struct TestSwapPromiseResult {
+  TestSwapPromiseResult()
+      : did_swap_called(false),
+        did_not_swap_called(false),
+        dtor_called(false),
+        reason(SwapPromise::DID_NOT_SWAP_UNKNOWN) {}
+
+  bool did_swap_called;
+  bool did_not_swap_called;
+  bool dtor_called;
+  SwapPromise::DidNotSwapReason reason;
+  base::Lock lock;
+};
 
-class LayerInvalidateCausesDraw : public LayerTreeHostTest {
+class TestSwapPromise : public SwapPromise {
  public:
-  LayerInvalidateCausesDraw() : num_commits_(0), num_draws_(0) {}
-
-  virtual void BeginTest() OVERRIDE {
-    ASSERT_TRUE(!!invalidate_layer_)
-        << "Derived tests must set this in SetupTree";
-
-    // One initial commit.
-    PostSetNeedsCommitToMainThread();
-  }
+  explicit TestSwapPromise(TestSwapPromiseResult* result) : result_(result) {}
 
-  virtual void DidCommitAndDrawFrame() OVERRIDE {
-    // After commit, invalidate the layer.  This should cause a commit.
-    if (layer_tree_host()->source_frame_number() == 1)
-     invalidate_layer_->SetNeedsDisplay();
-  }
-
-  virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
-    num_draws_++;
-    if (impl->active_tree()->source_frame_number() == 1)
-      EndTest();
+  virtual ~TestSwapPromise() {
+    base::AutoLock lock(result_->lock);
+    result_->dtor_called = true;
   }
 
-  virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
-    num_commits_++;
+  virtual void DidSwap(CompositorFrameMetadata* metadata) OVERRIDE {
+    base::AutoLock lock(result_->lock);
+    EXPECT_FALSE(result_->did_swap_called);
+    EXPECT_FALSE(result_->did_not_swap_called);
+    result_->did_swap_called = true;
   }
 
-  virtual void AfterTest() OVERRIDE {
-    EXPECT_GE(2, num_commits_);
-    EXPECT_GE(2, num_draws_);
+  virtual void DidNotSwap(DidNotSwapReason reason) OVERRIDE {
+    base::AutoLock lock(result_->lock);
+    EXPECT_FALSE(result_->did_swap_called);
+    EXPECT_FALSE(result_->did_not_swap_called);
+    result_->did_not_swap_called = true;
+    result_->reason = reason;
   }
 
- protected:
-  scoped_refptr<Layer> invalidate_layer_;
-
  private:
-  int num_commits_;
-  int num_draws_;
+  // Not owned.
+  TestSwapPromiseResult* result_;
 };
 
-// VideoLayer must support being invalidated and then passing that along
-// to the compositor thread, even though no resources are updated in
-// response to that invalidation.
-class LayerTreeHostTestVideoLayerInvalidate : public LayerInvalidateCausesDraw {
- public:
-  virtual void SetupTree() OVERRIDE {
-    LayerTreeHostTest::SetupTree();
-    scoped_refptr<VideoLayer> video_layer = VideoLayer::Create(&provider_);
-    video_layer->SetBounds(gfx::Size(10, 10));
-    video_layer->SetIsDrawable(true);
-    layer_tree_host()->root_layer()->AddChild(video_layer);
+class LayerTreeHostTestBreakSwapPromise : public LayerTreeHostTest {
+ protected:
+  LayerTreeHostTestBreakSwapPromise()
+      : commit_count_(0), commit_complete_count_(0) {}
 
-    invalidate_layer_ = video_layer;
+  virtual void WillBeginMainFrame() OVERRIDE {
+    ASSERT_LE(commit_count_, 2);
+    scoped_ptr<SwapPromise> swap_promise(
+        new TestSwapPromise(&swap_promise_result_[commit_count_]));
+    layer_tree_host()->QueueSwapPromise(swap_promise.Pass());
   }
 
- private:
-  FakeVideoFrameProvider provider_;
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestVideoLayerInvalidate);
-
-// IOSurfaceLayer must support being invalidated and then passing that along
-// to the compositor thread, even though no resources are updated in
-// response to that invalidation.
-class LayerTreeHostTestIOSurfaceLayerInvalidate
-    : public LayerInvalidateCausesDraw {
- public:
-  virtual void SetupTree() OVERRIDE {
-    LayerTreeHostTest::SetupTree();
-    scoped_refptr<IOSurfaceLayer> layer = IOSurfaceLayer::Create();
-    layer->SetBounds(gfx::Size(10, 10));
-    uint32_t fake_io_surface_id = 7;
-    layer->SetIOSurfaceProperties(fake_io_surface_id, layer->bounds());
-    layer->SetIsDrawable(true);
-    layer_tree_host()->root_layer()->AddChild(layer);
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
-    invalidate_layer_ = layer;
+  virtual void DidCommit() OVERRIDE {
+    commit_count_++;
+    if (commit_count_ == 2) {
+      // This commit will finish.
+      layer_tree_host()->SetNeedsCommit();
+    }
   }
-};
 
-// TODO(danakj): IOSurface layer can not be transported. crbug.com/239335
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
-    LayerTreeHostTestIOSurfaceLayerInvalidate);
+  virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+    commit_complete_count_++;
+    if (commit_complete_count_ == 1) {
+      // This commit will be aborted because no actual update.
+      PostSetNeedsUpdateLayersToMainThread();
+    } else {
+      EndTest();
+    }
+  }
 
-class LayerTreeHostTestPushHiddenLayer : public LayerTreeHostTest {
- protected:
-  virtual void SetupTree() OVERRIDE {
-    root_layer_ = Layer::Create();
-    root_layer_->SetAnchorPoint(gfx::PointF());
-    root_layer_->SetPosition(gfx::Point());
-    root_layer_->SetBounds(gfx::Size(10, 10));
+  virtual void AfterTest() OVERRIDE {
+    // 3 commits are scheduled. 2 completes. 1 is aborted.
+    EXPECT_EQ(commit_count_, 3);
+    EXPECT_EQ(commit_complete_count_, 2);
 
-    parent_layer_ = SolidColorLayer::Create();
-    parent_layer_->SetAnchorPoint(gfx::PointF());
-    parent_layer_->SetPosition(gfx::Point());
-    parent_layer_->SetBounds(gfx::Size(10, 10));
-    parent_layer_->SetIsDrawable(true);
-    root_layer_->AddChild(parent_layer_);
+    {
+      // The first commit completes and causes swap buffer which finishes
+      // the promise.
+      base::AutoLock lock(swap_promise_result_[0].lock);
+      EXPECT_TRUE(swap_promise_result_[0].did_swap_called);
+      EXPECT_FALSE(swap_promise_result_[0].did_not_swap_called);
+      EXPECT_TRUE(swap_promise_result_[0].dtor_called);
+    }
 
-    child_layer_ = SolidColorLayer::Create();
-    child_layer_->SetAnchorPoint(gfx::PointF());
-    child_layer_->SetPosition(gfx::Point());
-    child_layer_->SetBounds(gfx::Size(10, 10));
-    child_layer_->SetIsDrawable(true);
-    parent_layer_->AddChild(child_layer_);
+    {
+      // The second commit aborts.
+      base::AutoLock lock(swap_promise_result_[1].lock);
+      EXPECT_FALSE(swap_promise_result_[1].did_swap_called);
+      EXPECT_TRUE(swap_promise_result_[1].did_not_swap_called);
+      EXPECT_EQ(SwapPromise::COMMIT_FAILS, swap_promise_result_[1].reason);
+      EXPECT_TRUE(swap_promise_result_[1].dtor_called);
+    }
 
-    layer_tree_host()->SetRootLayer(root_layer_);
-    LayerTreeHostTest::SetupTree();
+    {
+      // The last commit completes but it does not cause swap buffer because
+      // there is no damage in the frame data.
+      base::AutoLock lock(swap_promise_result_[2].lock);
+      EXPECT_FALSE(swap_promise_result_[2].did_swap_called);
+      EXPECT_TRUE(swap_promise_result_[2].did_not_swap_called);
+      EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[2].reason);
+      EXPECT_TRUE(swap_promise_result_[2].dtor_called);
+    }
   }
 
-  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
-
-  virtual void DidCommitAndDrawFrame() OVERRIDE {
-    switch (layer_tree_host()->source_frame_number()) {
-      case 1:
-        // The layer type used does not need to push properties every frame.
-        EXPECT_FALSE(child_layer_->needs_push_properties());
+  int commit_count_;
+  int commit_complete_count_;
+  TestSwapPromiseResult swap_promise_result_[3];
+};
 
-        // Change the bounds of the child layer, but make it skipped
-        // by CalculateDrawProperties.
-        parent_layer_->SetOpacity(0.f);
-        child_layer_->SetBounds(gfx::Size(5, 5));
-        break;
-      case 2:
-        // The bounds of the child layer were pushed to the impl side.
-        EXPECT_FALSE(child_layer_->needs_push_properties());
+MULTI_THREAD_TEST_F(LayerTreeHostTestBreakSwapPromise);
 
-        EndTest();
-        break;
-    }
-  }
+class SimpleSwapPromiseMonitor : public SwapPromiseMonitor {
+ public:
+  SimpleSwapPromiseMonitor(LayerTreeHost* layer_tree_host,
+                           LayerTreeHostImpl* layer_tree_host_impl,
+                           int* set_needs_commit_count,
+                           int* set_needs_redraw_count)
+      : SwapPromiseMonitor(layer_tree_host, layer_tree_host_impl),
+        set_needs_commit_count_(set_needs_commit_count),
+        set_needs_redraw_count_(set_needs_redraw_count) {}
 
-  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
-    LayerImpl* root = impl->active_tree()->root_layer();
-    LayerImpl* parent = root->children()[0];
-    LayerImpl* child = parent->children()[0];
+  virtual ~SimpleSwapPromiseMonitor() {}
 
-    switch (impl->active_tree()->source_frame_number()) {
-      case 1:
-        EXPECT_EQ(gfx::Size(5, 5).ToString(), child->bounds().ToString());
-        break;
-    }
+  virtual void OnSetNeedsCommitOnMain() OVERRIDE {
+    (*set_needs_commit_count_)++;
   }
 
-  virtual void AfterTest() OVERRIDE {}
+  virtual void OnSetNeedsRedrawOnImpl() OVERRIDE {
+    (*set_needs_redraw_count_)++;
+  }
 
-  scoped_refptr<Layer> root_layer_;
-  scoped_refptr<SolidColorLayer> parent_layer_;
-  scoped_refptr<SolidColorLayer> child_layer_;
+ private:
+  int* set_needs_commit_count_;
+  int* set_needs_redraw_count_;
 };
 
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestPushHiddenLayer);
+class LayerTreeHostTestSimpleSwapPromiseMonitor : public LayerTreeHostTest {
+ public:
+  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
-class LayerTreeHostTestUpdateLayerInEmptyViewport : public LayerTreeHostTest {
- protected:
-  virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
-    settings->impl_side_painting = true;
-  }
+  virtual void WillBeginMainFrame() OVERRIDE {
+    int set_needs_commit_count = 0;
+    int set_needs_redraw_count = 0;
 
-  virtual void SetupTree() OVERRIDE {
-    root_layer_ = FakePictureLayer::Create(&client_);
-    root_layer_->SetAnchorPoint(gfx::PointF());
-    root_layer_->SetBounds(gfx::Size(10, 10));
+    {
+      scoped_ptr<SimpleSwapPromiseMonitor> swap_promise_monitor(
+          new SimpleSwapPromiseMonitor(layer_tree_host(),
+                                       NULL,
+                                       &set_needs_commit_count,
+                                       &set_needs_redraw_count));
+      layer_tree_host()->SetNeedsCommit();
+      EXPECT_EQ(1, set_needs_commit_count);
+      EXPECT_EQ(0, set_needs_redraw_count);
+    }
 
-    layer_tree_host()->SetRootLayer(root_layer_);
-    LayerTreeHostTest::SetupTree();
-  }
+    // Now the monitor is destroyed, SetNeedsCommit() is no longer being
+    // monitored.
+    layer_tree_host()->SetNeedsCommit();
+    EXPECT_EQ(1, set_needs_commit_count);
+    EXPECT_EQ(0, set_needs_redraw_count);
 
-  virtual void BeginTest() OVERRIDE {
-    // The viewport is empty, but we still need to update layers on the main
-    // thread.
-    layer_tree_host()->SetViewportSize(gfx::Size(0, 0));
-    PostSetNeedsCommitToMainThread();
-  }
+    {
+      scoped_ptr<SimpleSwapPromiseMonitor> swap_promise_monitor(
+          new SimpleSwapPromiseMonitor(layer_tree_host(),
+                                       NULL,
+                                       &set_needs_commit_count,
+                                       &set_needs_redraw_count));
+      layer_tree_host()->SetNeedsUpdateLayers();
+      EXPECT_EQ(2, set_needs_commit_count);
+      EXPECT_EQ(0, set_needs_redraw_count);
+    }
+
+    {
+      scoped_ptr<SimpleSwapPromiseMonitor> swap_promise_monitor(
+          new SimpleSwapPromiseMonitor(layer_tree_host(),
+                                       NULL,
+                                       &set_needs_commit_count,
+                                       &set_needs_redraw_count));
+      layer_tree_host()->SetNeedsAnimate();
+      EXPECT_EQ(3, set_needs_commit_count);
+      EXPECT_EQ(0, set_needs_redraw_count);
+    }
 
-  virtual void DidCommit() OVERRIDE {
-    // The layer should be updated even though the viewport is empty, so we
-    // are capable of drawing it on the impl tree.
-    EXPECT_GT(root_layer_->update_count(), 0u);
     EndTest();
   }
 
   virtual void AfterTest() OVERRIDE {}
-
-  FakeContentLayerClient client_;
-  scoped_refptr<FakePictureLayer> root_layer_;
 };
 
-MULTI_THREAD_TEST_F(LayerTreeHostTestUpdateLayerInEmptyViewport);
-
-class LayerTreeHostTestAbortEvictedTextures : public LayerTreeHostTest {
- public:
-  LayerTreeHostTestAbortEvictedTextures()
-      : num_will_begin_main_frames_(0), num_impl_commits_(0) {}
+MULTI_THREAD_TEST_F(LayerTreeHostTestSimpleSwapPromiseMonitor);
 
+class LayerTreeHostTestHighResRequiredAfterEvictingUIResources
+    : public LayerTreeHostTest {
  protected:
-  virtual void SetupTree() OVERRIDE {
-    scoped_refptr<SolidColorLayer> root_layer = SolidColorLayer::Create();
-    root_layer->SetBounds(gfx::Size(200, 200));
-    root_layer->SetIsDrawable(true);
+  virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
+    settings->impl_side_painting = true;
+  }
 
-    layer_tree_host()->SetRootLayer(root_layer);
+  virtual void SetupTree() OVERRIDE {
     LayerTreeHostTest::SetupTree();
+    ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
   }
 
   virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
 
-  virtual void WillBeginMainFrame() OVERRIDE {
-    num_will_begin_main_frames_++;
-    switch (num_will_begin_main_frames_) {
-      case 2:
-        // Send a redraw to the compositor thread.  This will (wrongly) be
-        // ignored unless aborting resets the texture state.
-        layer_tree_host()->SetNeedsRedraw();
-        break;
-    }
-  }
-
-  virtual void BeginCommitOnThread(LayerTreeHostImpl* impl) OVERRIDE {
-    num_impl_commits_++;
+  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+    host_impl->EvictAllUIResources();
+    // Existence of evicted UI resources will trigger NEW_CONTENT_TAKES_PRIORITY
+    // mode. Active tree should require high-res to draw after entering this
+    // mode to ensure that high-res tiles are also required for a pending tree
+    // to be activated.
+    EXPECT_TRUE(host_impl->active_tree()->RequiresHighResToDraw());
   }
 
-  virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
-    switch (impl->SourceAnimationFrameNumber()) {
+  virtual void DidCommit() OVERRIDE {
+    int frame = layer_tree_host()->source_frame_number();
+    switch (frame) {
       case 1:
-        // Prevent draws until commit.
-        impl->active_tree()->SetContentsTexturesPurged();
-        EXPECT_FALSE(impl->CanDraw());
-        // Trigger an abortable commit.
-        impl->SetNeedsCommit();
+        PostSetNeedsCommitToMainThread();
         break;
       case 2:
+        ui_resource_.reset();
         EndTest();
         break;
     }
   }
 
-  virtual void AfterTest() OVERRIDE {
-    // Ensure that the commit was truly aborted.
-    EXPECT_EQ(2, num_will_begin_main_frames_);
-    EXPECT_EQ(1, num_impl_commits_);
-  }
+  virtual void AfterTest() OVERRIDE {}
 
- private:
-  int num_will_begin_main_frames_;
-  int num_impl_commits_;
+  FakeContentLayerClient client_;
+  scoped_ptr<FakeScopedUIResource> ui_resource_;
 };
 
-// Commits can only be aborted when using the thread proxy.
-MULTI_THREAD_TEST_F(LayerTreeHostTestAbortEvictedTextures);
+MULTI_THREAD_TEST_F(LayerTreeHostTestHighResRequiredAfterEvictingUIResources);
 
-class LayerTreeHostTestMaxTransferBufferUsageBytes : public LayerTreeHostTest {
+class LayerTreeHostTestGpuRasterizationDefault : public LayerTreeHostTest {
  protected:
   virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
     settings->impl_side_painting = true;
-  }
 
-  virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
-      OVERRIDE {
-    scoped_refptr<TestContextProvider> context_provider =
-        TestContextProvider::Create();
-    context_provider->SetMaxTransferBufferUsageBytes(1024 * 1024);
-    return FakeOutputSurface::Create3d(context_provider)
-        .PassAs<OutputSurface>();
+    EXPECT_FALSE(settings->gpu_rasterization_enabled);
+    EXPECT_FALSE(settings->gpu_rasterization_forced);
   }
 
   virtual void SetupTree() OVERRIDE {
-    scoped_refptr<FakePictureLayer> root_layer =
-        FakePictureLayer::Create(&client_);
-    root_layer->SetBounds(gfx::Size(6000, 6000));
-    root_layer->SetIsDrawable(true);
-
-    layer_tree_host()->SetRootLayer(root_layer);
     LayerTreeHostTest::SetupTree();
+
+    scoped_refptr<PictureLayer> layer = PictureLayer::Create(&layer_client_);
+    layer->SetBounds(gfx::Size(10, 10));
+    layer->SetIsDrawable(true);
+    layer_tree_host()->root_layer()->AddChild(layer);
   }
 
   virtual void BeginTest() OVERRIDE {
+    Layer* root = layer_tree_host()->root_layer();
+    PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0));
+    PicturePile* pile = layer->GetPicturePileForTesting();
+
+    // Verify default values.
+    EXPECT_TRUE(root->IsSuitableForGpuRasterization());
+    EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
+    EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+    EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger());
+    EXPECT_FALSE(layer_tree_host()->UseGpuRasterization());
+
+    // Setting gpu rasterization trigger does not enable gpu rasterization.
+    layer_tree_host()->set_has_gpu_rasterization_trigger(true);
+    EXPECT_TRUE(layer_tree_host()->has_gpu_rasterization_trigger());
+    EXPECT_FALSE(layer_tree_host()->UseGpuRasterization());
+
     PostSetNeedsCommitToMainThread();
   }
 
-  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
-    TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
-        impl->output_surface()->context_provider()->Context3d());
+  virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+    LayerImpl* root = host_impl->pending_tree()->root_layer();
+    PictureLayerImpl* layer_impl =
+        static_cast<PictureLayerImpl*>(root->children()[0]);
 
-    // Expect that the transfer buffer memory used is equal to the
-    // MaxTransferBufferUsageBytes value set in CreateOutputSurface.
-    EXPECT_EQ(1024 * 1024u,
-              context->GetTransferBufferMemoryUsedBytes());
+    EXPECT_FALSE(layer_impl->use_gpu_rasterization());
+  }
+
+  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+    LayerImpl* root = host_impl->active_tree()->root_layer();
+    PictureLayerImpl* layer_impl =
+        static_cast<PictureLayerImpl*>(root->children()[0]);
+
+    EXPECT_FALSE(layer_impl->use_gpu_rasterization());
     EndTest();
   }
 
   virtual void AfterTest() OVERRIDE {}
 
- private:
-  FakeContentLayerClient client_;
+  FakeContentLayerClient layer_client_;
 };
 
-// Impl-side painting is a multi-threaded compositor feature.
-MULTI_THREAD_TEST_F(LayerTreeHostTestMaxTransferBufferUsageBytes);
-
-// Test ensuring that memory limits are sent to the prioritized resource
-// manager.
-class LayerTreeHostTestMemoryLimits : public LayerTreeHostTest {
- public:
-  LayerTreeHostTestMemoryLimits() : num_commits_(0) {}
-
-  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
-
-  virtual void DidCommit() OVERRIDE {
-    int frame = num_commits_;
-    switch (frame) {
-      case 0:
-        // Verify default values.
-        EXPECT_EQ(
-            PrioritizedResourceManager::DefaultMemoryAllocationLimit(),
-            layer_tree_host()->contents_texture_manager()->
-                MaxMemoryLimitBytes());
-        EXPECT_EQ(
-            PriorityCalculator::AllowEverythingCutoff(),
-            layer_tree_host()->contents_texture_manager()->
-                ExternalPriorityCutoff());
-        PostSetNeedsCommitToMainThread();
-        break;
-      case 1:
-        // The values should remain the same until the commit after the policy
-        // is changed.
-        EXPECT_EQ(
-            PrioritizedResourceManager::DefaultMemoryAllocationLimit(),
-            layer_tree_host()->contents_texture_manager()->
-                MaxMemoryLimitBytes());
-        EXPECT_EQ(
-            PriorityCalculator::AllowEverythingCutoff(),
-            layer_tree_host()->contents_texture_manager()->
-                ExternalPriorityCutoff());
-        break;
-      case 2:
-        // Verify values were correctly passed.
-        EXPECT_EQ(
-            16u*1024u*1024u,
-            layer_tree_host()->contents_texture_manager()->
-                MaxMemoryLimitBytes());
-        EXPECT_EQ(
-            PriorityCalculator::AllowVisibleAndNearbyCutoff(),
-            layer_tree_host()->contents_texture_manager()->
-                ExternalPriorityCutoff());
-        EndTest();
-        break;
-      case 3:
-        // Make sure no extra commits happen.
-        NOTREACHED();
-        break;
-    }
+MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationDefault);
 
-    ++num_commits_;
-  }
+class LayerTreeHostTestGpuRasterizationEnabled : public LayerTreeHostTest {
+ protected:
+  virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
+    settings->impl_side_painting = true;
 
-  virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
-    int frame = num_commits_;
-    switch (frame) {
-      case 0:
-        break;
-      case 1:
-        // This will trigger a commit because the priority cutoff has changed.
-        impl->SetMemoryPolicy(ManagedMemoryPolicy(
-            16u*1024u*1024u,
-            gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
-            1000));
-        break;
-      case 2:
-        // This will not trigger a commit because the priority cutoff has not
-        // changed, and there is already enough memory for all allocations.
-        impl->SetMemoryPolicy(ManagedMemoryPolicy(
-            32u*1024u*1024u,
-            gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
-            1000));
-        break;
-      case 3:
-        NOTREACHED();
-        break;
-    }
+    EXPECT_FALSE(settings->gpu_rasterization_enabled);
+    settings->gpu_rasterization_enabled = true;
   }
 
-  virtual void AfterTest() OVERRIDE {}
-
- private:
-  int num_commits_;
-};
-
-SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(LayerTreeHostTestMemoryLimits);
+  virtual void SetupTree() OVERRIDE {
+    LayerTreeHostTest::SetupTree();
 
-class LayerSetsNeedsFilterContext : public Layer {
- public:
-  static scoped_refptr<LayerSetsNeedsFilterContext> Create() {
-    return make_scoped_refptr(new LayerSetsNeedsFilterContext());
+    scoped_refptr<PictureLayer> layer = PictureLayer::Create(&layer_client_);
+    layer->SetBounds(gfx::Size(10, 10));
+    layer->SetIsDrawable(true);
+    layer_tree_host()->root_layer()->AddChild(layer);
   }
 
-  virtual bool Update(ResourceUpdateQueue* queue,
-                      const OcclusionTracker* occlusion) OVERRIDE {
-    bool updated = Layer::Update(queue, occlusion);
-    if (needs_context_) {
-      layer_tree_host()->set_needs_filter_context();
-      return true;
-    }
-    return updated;
+  virtual void BeginTest() OVERRIDE {
+    Layer* root = layer_tree_host()->root_layer();
+    PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0));
+    PicturePile* pile = layer->GetPicturePileForTesting();
+
+    // Verify default values.
+    EXPECT_TRUE(root->IsSuitableForGpuRasterization());
+    EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
+    EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+    EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger());
+    EXPECT_FALSE(layer_tree_host()->UseGpuRasterization());
+
+    // Gpu rasterization trigger is relevant.
+    layer_tree_host()->set_has_gpu_rasterization_trigger(true);
+    EXPECT_TRUE(layer_tree_host()->has_gpu_rasterization_trigger());
+    EXPECT_TRUE(layer_tree_host()->UseGpuRasterization());
+
+    // Content-based veto is relevant as well.
+    pile->SetUnsuitableForGpuRasterizationForTesting();
+    EXPECT_FALSE(pile->is_suitable_for_gpu_rasterization());
+    EXPECT_FALSE(layer->IsSuitableForGpuRasterization());
+    // Veto will take effect when layers are updated.
+    // The results will be verified after commit is completed below.
+    // Since we are manually marking picture pile as unsuitable,
+    // make sure that the layer gets a chance to update.
+    layer->SetNeedsDisplay();
+    PostSetNeedsCommitToMainThread();
   }
 
-  void set_needs_context(bool need) { needs_context_ = need; }
-
- private:
-  LayerSetsNeedsFilterContext() : needs_context_(false) {}
-  virtual ~LayerSetsNeedsFilterContext() {}
-
-  bool needs_context_;
-};
+  virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+    LayerImpl* root = host_impl->pending_tree()->root_layer();
+    PictureLayerImpl* layer_impl =
+        static_cast<PictureLayerImpl*>(root->children()[0]);
 
-class LayerTreeHostTestOffscreenContext : public LayerTreeHostTest {
- protected:
-  virtual void SetupTree() OVERRIDE {
-    scoped_refptr<LayerSetsNeedsFilterContext> root =
-        LayerSetsNeedsFilterContext::Create();
-    root->SetIsDrawable(true);
-    root->SetAnchorPoint(gfx::PointF());
-    root->SetBounds(gfx::Size(10, 10));
-    root->set_needs_context(with_context_);
-    layer_tree_host()->SetRootLayer(root);
-    LayerTreeHostTest::SetupTree();
+    EXPECT_FALSE(layer_impl->use_gpu_rasterization());
   }
 
-  virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+    LayerImpl* root = host_impl->active_tree()->root_layer();
+    PictureLayerImpl* layer_impl =
+        static_cast<PictureLayerImpl*>(root->children()[0]);
 
-  virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
-    bool expect_context = with_context_;
-    if (delegating_renderer())
-      expect_context = false;
-    EXPECT_EQ(expect_context, !!host_impl->offscreen_context_provider());
+    EXPECT_FALSE(layer_impl->use_gpu_rasterization());
     EndTest();
   }
 
   virtual void AfterTest() OVERRIDE {}
 
-  bool with_context_;
-};
-
-class LayerTreeHostTestOffscreenContext_NoContext
-    : public LayerTreeHostTestOffscreenContext {
- protected:
-  LayerTreeHostTestOffscreenContext_NoContext() { with_context_ = false; }
+  FakeContentLayerClient layer_client_;
 };
 
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestOffscreenContext_NoContext);
+MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationEnabled);
 
-class LayerTreeHostTestOffscreenContext_WithContext
-    : public LayerTreeHostTestOffscreenContext {
+class LayerTreeHostTestGpuRasterizationForced : public LayerTreeHostTest {
  protected:
-  LayerTreeHostTestOffscreenContext_WithContext() { with_context_ = true; }
-};
+  virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
+    settings->impl_side_painting = true;
 
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestOffscreenContext_WithContext);
+    EXPECT_FALSE(settings->gpu_rasterization_forced);
+    settings->gpu_rasterization_forced = true;
+  }
 
-class LayerTreeHostTestNoQuadsForEmptyLayer : public LayerTreeHostTest {
- protected:
   virtual void SetupTree() OVERRIDE {
     LayerTreeHostTest::SetupTree();
-    root_layer_ = FakeContentLayer::Create(&client_);
-    root_layer_->SetBounds(gfx::Size(10, 10));
-    root_layer_->SetIsDrawable(false);
-    root_layer_->SetHaveWheelEventHandlers(true);
-    layer_tree_host()->SetRootLayer(root_layer_);
-    LayerTreeHostTest::SetupTree();
+
+    scoped_refptr<PictureLayer> layer = PictureLayer::Create(&layer_client_);
+    layer->SetBounds(gfx::Size(10, 10));
+    layer->SetIsDrawable(true);
+    layer_tree_host()->root_layer()->AddChild(layer);
   }
 
   virtual void BeginTest() OVERRIDE {
+    Layer* root = layer_tree_host()->root_layer();
+    PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0));
+    PicturePile* pile = layer->GetPicturePileForTesting();
+
+    // Verify default values.
+    EXPECT_TRUE(root->IsSuitableForGpuRasterization());
+    EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
+    EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+    EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger());
+
+    // With gpu rasterization forced, gpu rasterization trigger is irrelevant.
+    EXPECT_TRUE(layer_tree_host()->UseGpuRasterization());
+    layer_tree_host()->set_has_gpu_rasterization_trigger(true);
+    EXPECT_TRUE(layer_tree_host()->has_gpu_rasterization_trigger());
+    EXPECT_TRUE(layer_tree_host()->UseGpuRasterization());
+
+    // Content-based veto is irrelevant as well.
+    pile->SetUnsuitableForGpuRasterizationForTesting();
+    EXPECT_FALSE(pile->is_suitable_for_gpu_rasterization());
+    EXPECT_FALSE(layer->IsSuitableForGpuRasterization());
+    // Veto will take effect when layers are updated.
+    // The results will be verified after commit is completed below.
+    // Since we are manually marking picture pile as unsuitable,
+    // make sure that the layer gets a chance to update.
+    layer->SetNeedsDisplay();
     PostSetNeedsCommitToMainThread();
   }
 
-  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
-    FakeContentLayerImpl* layer_impl =
-          static_cast<FakeContentLayerImpl*>(impl->RootLayer());
-    EXPECT_FALSE(layer_impl->DrawsContent());
-    EXPECT_EQ(0u, layer_impl->append_quads_count());
+  virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+    LayerImpl* root = host_impl->pending_tree()->root_layer();
+    PictureLayerImpl* layer_impl =
+        static_cast<PictureLayerImpl*>(root->children()[0]);
+
+    EXPECT_TRUE(layer_impl->use_gpu_rasterization());
   }
 
-  virtual void DidCommit() OVERRIDE {
-    // The layer is not drawable, so it should not be updated.
-    EXPECT_EQ(0u, root_layer_->update_count());
+  virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+    LayerImpl* root = host_impl->active_tree()->root_layer();
+    PictureLayerImpl* layer_impl =
+        static_cast<PictureLayerImpl*>(root->children()[0]);
+
+    EXPECT_TRUE(layer_impl->use_gpu_rasterization());
     EndTest();
   }
+
   virtual void AfterTest() OVERRIDE {}
 
- private:
-  FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_layer_;
+  FakeContentLayerClient layer_client_;
 };
 
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestNoQuadsForEmptyLayer);
-
+MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationForced);
 
-}  // namespace
+class LayerTreeHostTestContinuousPainting : public LayerTreeHostTest {
+ public:
+  LayerTreeHostTestContinuousPainting()
+      : num_commits_(0), num_draws_(0), bounds_(20, 20), child_layer_(NULL) {}
 
-class LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface
-    : public LayerTreeHostTest {
  protected:
-  LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface()
-      : first_output_surface_memory_limit_(4321234),
-        second_output_surface_memory_limit_(1234321) {}
+  enum { kExpectedNumCommits = 10 };
 
-  virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
-      OVERRIDE {
-    if (!first_context_provider_) {
-      first_context_provider_ = TestContextProvider::Create();
+  virtual void SetupTree() OVERRIDE {
+    scoped_refptr<Layer> root_layer = Layer::Create();
+    root_layer->SetBounds(bounds_);
+
+    if (layer_tree_host()->settings().impl_side_painting) {
+      picture_layer_ = FakePictureLayer::Create(&client_);
+      child_layer_ = picture_layer_.get();
     } else {
-      EXPECT_FALSE(second_context_provider_);
-      second_context_provider_ = TestContextProvider::Create();
+      content_layer_ = ContentLayerWithUpdateTracking::Create(&client_);
+      child_layer_ = content_layer_.get();
     }
+    child_layer_->SetBounds(bounds_);
+    child_layer_->SetIsDrawable(true);
+    root_layer->AddChild(child_layer_);
 
-    scoped_ptr<FakeOutputSurface> output_surface(
-        FakeOutputSurface::Create3d(
-            second_context_provider_ ?
-                second_context_provider_ :
-                first_context_provider_));
-    output_surface->SetMemoryPolicyToSetAtBind(make_scoped_ptr(
-        new ManagedMemoryPolicy(
-            second_context_provider_ ?
-                second_output_surface_memory_limit_ :
-                first_output_surface_memory_limit_,
-            gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
-            ManagedMemoryPolicy::kDefaultNumResourcesLimit)));
-    return output_surface.PassAs<OutputSurface>();
-  }
-
-  virtual void SetupTree() OVERRIDE {
-    root_ = FakeContentLayer::Create(&client_);
-    root_->SetBounds(gfx::Size(20, 20));
-    layer_tree_host()->SetRootLayer(root_);
+    layer_tree_host()->SetRootLayer(root_layer);
+    layer_tree_host()->SetViewportSize(bounds_);
     LayerTreeHostTest::SetupTree();
   }
 
   virtual void BeginTest() OVERRIDE {
-    PostSetNeedsCommitToMainThread();
+    // Wait 50x longer than expected.
+    double milliseconds_per_frame =
+        1000 / layer_tree_host()->settings().refresh_rate;
+    EndTestAfterDelay(50 * kExpectedNumCommits * milliseconds_per_frame);
+    MainThreadTaskRunner()->PostTask(
+        FROM_HERE,
+        base::Bind(
+            &LayerTreeHostTestContinuousPainting::EnableContinuousPainting,
+            base::Unretained(this)));
   }
 
-  virtual void DidCommitAndDrawFrame() OVERRIDE {
-    // Lost context sometimes takes two frames to recreate. The third frame
-    // is sometimes aborted, so wait until the fourth frame to verify that
-    // the memory has been set, and the fifth frame to end the test.
-    if (layer_tree_host()->source_frame_number() < 5) {
-      layer_tree_host()->SetNeedsCommit();
-    } else if (layer_tree_host()->source_frame_number() == 5) {
+  virtual void Animate(base::TimeTicks monotonic_time) OVERRIDE {
+    child_layer_->SetNeedsDisplay();
+  }
+
+  virtual void AfterTest() OVERRIDE {
+    EXPECT_LE(kExpectedNumCommits, num_commits_);
+    EXPECT_LE(kExpectedNumCommits, num_draws_);
+    int update_count = content_layer_ ? content_layer_->PaintContentsCount()
+                                      : picture_layer_->update_count();
+    EXPECT_LE(kExpectedNumCommits, update_count);
+  }
+
+  virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+    if (++num_draws_ == kExpectedNumCommits)
       EndTest();
-    }
   }
 
-  virtual void SwapBuffersOnThread(LayerTreeHostImpl *impl, bool result)
-      OVERRIDE {
-    switch (impl->active_tree()->source_frame_number()) {
-      case 1:
-        EXPECT_EQ(first_output_surface_memory_limit_,
-                  impl->memory_allocation_limit_bytes());
-        // Lose the output surface.
-        first_context_provider_->TestContext3d()->loseContextCHROMIUM(
-            GL_GUILTY_CONTEXT_RESET_ARB,
-            GL_INNOCENT_CONTEXT_RESET_ARB);
-        break;
-      case 4:
-        EXPECT_EQ(second_output_surface_memory_limit_,
-                  impl->memory_allocation_limit_bytes());
-        break;
-    }
+  virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+    ++num_commits_;
   }
 
-  virtual void AfterTest() OVERRIDE {}
+ private:
+  void EnableContinuousPainting() {
+    LayerTreeDebugState debug_state = layer_tree_host()->debug_state();
+    debug_state.continuous_painting = true;
+    layer_tree_host()->SetDebugState(debug_state);
+  }
 
-  scoped_refptr<TestContextProvider> first_context_provider_;
-  scoped_refptr<TestContextProvider> second_context_provider_;
-  size_t first_output_surface_memory_limit_;
-  size_t second_output_surface_memory_limit_;
+  int num_commits_;
+  int num_draws_;
+  const gfx::Size bounds_;
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_;
+  scoped_refptr<ContentLayerWithUpdateTracking> content_layer_;
+  scoped_refptr<FakePictureLayer> picture_layer_;
+  Layer* child_layer_;
 };
 
-// No output to copy for delegated renderers.
-SINGLE_AND_MULTI_THREAD_TEST_F(
-    LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface);
+MULTI_THREAD_TEST_F(LayerTreeHostTestContinuousPainting);
 
 }  // namespace cc