| // Copyright 2011 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "cc/trees/layer_tree_host.h" | 
 |  | 
 | #include <stddef.h> | 
 | #include <stdint.h> | 
 |  | 
 | #include <algorithm> | 
 |  | 
 | #include "base/auto_reset.h" | 
 | #include "base/bind.h" | 
 | #include "base/bind_helpers.h" | 
 | #include "base/location.h" | 
 | #include "base/single_thread_task_runner.h" | 
 | #include "base/stl_util.h" | 
 | #include "base/strings/stringprintf.h" | 
 | #include "base/synchronization/lock.h" | 
 | #include "base/threading/thread_task_runner_handle.h" | 
 | #include "base/time/time.h" | 
 | #include "build/build_config.h" | 
 | #include "cc/animation/animation_host.h" | 
 | #include "cc/animation/timing_function.h" | 
 | #include "cc/input/scroll_elasticity_helper.h" | 
 | #include "cc/layers/content_layer_client.h" | 
 | #include "cc/layers/heads_up_display_layer.h" | 
 | #include "cc/layers/layer_impl.h" | 
 | #include "cc/layers/painted_scrollbar_layer.h" | 
 | #include "cc/layers/picture_layer.h" | 
 | #include "cc/layers/solid_color_layer.h" | 
 | #include "cc/layers/video_layer.h" | 
 | #include "cc/paint/image_animation_count.h" | 
 | #include "cc/resources/ui_resource_manager.h" | 
 | #include "cc/test/fake_content_layer_client.h" | 
 | #include "cc/test/fake_layer_tree_host_client.h" | 
 | #include "cc/test/fake_paint_image_generator.h" | 
 | #include "cc/test/fake_painted_scrollbar_layer.h" | 
 | #include "cc/test/fake_picture_layer.h" | 
 | #include "cc/test/fake_picture_layer_impl.h" | 
 | #include "cc/test/fake_proxy.h" | 
 | #include "cc/test/fake_recording_source.h" | 
 | #include "cc/test/fake_scoped_ui_resource.h" | 
 | #include "cc/test/fake_video_frame_provider.h" | 
 | #include "cc/test/geometry_test_utils.h" | 
 | #include "cc/test/layer_test_common.h" | 
 | #include "cc/test/layer_tree_test.h" | 
 | #include "cc/test/push_properties_counting_layer.h" | 
 | #include "cc/test/push_properties_counting_layer_impl.h" | 
 | #include "cc/test/render_pass_test_utils.h" | 
 | #include "cc/test/skia_common.h" | 
 | #include "cc/test/test_layer_tree_frame_sink.h" | 
 | #include "cc/trees/clip_node.h" | 
 | #include "cc/trees/effect_node.h" | 
 | #include "cc/trees/layer_tree_host_impl.h" | 
 | #include "cc/trees/layer_tree_impl.h" | 
 | #include "cc/trees/scroll_and_scale_set.h" | 
 | #include "cc/trees/scroll_node.h" | 
 | #include "cc/trees/single_thread_proxy.h" | 
 | #include "cc/trees/swap_promise.h" | 
 | #include "cc/trees/swap_promise_manager.h" | 
 | #include "cc/trees/transform_node.h" | 
 | #include "components/ukm/test_ukm_recorder.h" | 
 | #include "components/viz/common/frame_sinks/begin_frame_args.h" | 
 | #include "components/viz/common/frame_sinks/copy_output_request.h" | 
 | #include "components/viz/common/frame_sinks/copy_output_result.h" | 
 | #include "components/viz/common/quads/draw_quad.h" | 
 | #include "components/viz/common/quads/render_pass_draw_quad.h" | 
 | #include "components/viz/common/quads/tile_draw_quad.h" | 
 | #include "components/viz/service/display/output_surface.h" | 
 | #include "components/viz/test/begin_frame_args_test.h" | 
 | #include "components/viz/test/fake_output_surface.h" | 
 | #include "components/viz/test/test_gles2_interface.h" | 
 | #include "gpu/GLES2/gl2extchromium.h" | 
 | #include "testing/gmock/include/gmock/gmock.h" | 
 | #include "third_party/khronos/GLES2/gl2.h" | 
 | #include "third_party/khronos/GLES2/gl2ext.h" | 
 | #include "third_party/skia/include/core/SkPicture.h" | 
 | #include "third_party/skia/include/gpu/GrContext.h" | 
 | #include "ui/gfx/geometry/point_conversions.h" | 
 | #include "ui/gfx/geometry/size_conversions.h" | 
 | #include "ui/gfx/geometry/vector2d_conversions.h" | 
 |  | 
 | using testing::_; | 
 | using testing::AnyNumber; | 
 | using testing::AtLeast; | 
 | using testing::Mock; | 
 |  | 
 | namespace cc { | 
 | namespace { | 
 | const char kUserInteraction[] = "Compositor.UserInteraction"; | 
 | const char kCheckerboardArea[] = "CheckerboardedContentArea"; | 
 | const char kCheckerboardAreaRatio[] = "CheckerboardedContentAreaRatio"; | 
 | const char kMissingTiles[] = "NumMissingTiles"; | 
 |  | 
 | bool LayerSubtreeHasCopyRequest(Layer* layer) { | 
 |   LayerTreeHost* host = layer->layer_tree_host(); | 
 |   int index = layer->effect_tree_index(); | 
 |   auto* node = host->property_trees()->effect_tree.Node(index); | 
 |   return node->subtree_has_copy_request; | 
 | } | 
 |  | 
 | using LayerTreeHostTest = LayerTreeTest; | 
 |  | 
 | class LayerTreeHostTestHasImplThreadTest : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestHasImplThreadTest() : single_threaded_(false) {} | 
 |  | 
 |   void RunTest(CompositorMode mode) override { | 
 |     single_threaded_ = mode == CompositorMode::SINGLE_THREADED; | 
 |     LayerTreeHostTest::RunTest(mode); | 
 |   } | 
 |  | 
 |   void BeginTest() override { | 
 |     EXPECT_EQ(single_threaded_, !HasImplThread()); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void AfterTest() override { EXPECT_EQ(single_threaded_, !HasImplThread()); } | 
 |  | 
 |  private: | 
 |   bool single_threaded_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestHasImplThreadTest); | 
 |  | 
 | class LayerTreeHostTestSetNeedsCommitInsideLayout : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void UpdateLayerTreeHost() override { | 
 |     // This shouldn't cause a second commit to happen. | 
 |     layer_tree_host()->SetNeedsCommit(); | 
 |   } | 
 |  | 
 |   void DidCommit() override { | 
 |     EXPECT_EQ(1, layer_tree_host()->SourceFrameNumber()); | 
 |     EndTest(); | 
 |   } | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSetNeedsCommitInsideLayout); | 
 |  | 
 | class LayerTreeHostTestFrameOrdering : public LayerTreeHostTest { | 
 |  protected: | 
 |   enum MainOrder : int { | 
 |     MAIN_START = 1, | 
 |     MAIN_LAYOUT, | 
 |     MAIN_COMMIT_COMPLETE, | 
 |     MAIN_DID_BEGIN_FRAME, | 
 |     MAIN_END, | 
 |   }; | 
 |  | 
 |   enum ImplOrder : int { | 
 |     IMPL_START = 1, | 
 |     IMPL_READY_TO_COMMIT, | 
 |     IMPL_COMMIT, | 
 |     IMPL_COMMIT_COMPLETE, | 
 |     IMPL_ACTIVATE, | 
 |     IMPL_DRAW, | 
 |     IMPL_END, | 
 |   }; | 
 |  | 
 |   template <typename T> | 
 |   bool CheckStep(T next, T* var) { | 
 |     int expected = next - 1; | 
 |     EXPECT_EQ(expected, *var); | 
 |     bool correct = expected == *var; | 
 |     *var = next; | 
 |     return correct; | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void UpdateLayerTreeHost() override { | 
 |     EXPECT_TRUE(CheckStep(MAIN_LAYOUT, &main_)); | 
 |   } | 
 |  | 
 |   void DidCommit() override { | 
 |     EXPECT_TRUE(CheckStep(MAIN_COMMIT_COMPLETE, &main_)); | 
 |   } | 
 |  | 
 |   void DidBeginMainFrame() override { | 
 |     EXPECT_TRUE(CheckStep(MAIN_DID_BEGIN_FRAME, &main_)); | 
 |   } | 
 |  | 
 |   void ReadyToCommitOnThread(LayerTreeHostImpl* impl) override { | 
 |     EXPECT_TRUE(CheckStep(IMPL_READY_TO_COMMIT, &impl_)); | 
 |   } | 
 |  | 
 |   void BeginCommitOnThread(LayerTreeHostImpl* impl) override { | 
 |     EXPECT_TRUE(CheckStep(IMPL_COMMIT, &impl_)); | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | 
 |     EXPECT_TRUE(CheckStep(IMPL_COMMIT_COMPLETE, &impl_)); | 
 |   } | 
 |  | 
 |   void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override { | 
 |     EXPECT_TRUE(CheckStep(IMPL_ACTIVATE, &impl_)); | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* impl) override { | 
 |     EXPECT_TRUE(CheckStep(IMPL_DRAW, &impl_)); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     EXPECT_TRUE(CheckStep(MAIN_END, &main_)); | 
 |     EXPECT_TRUE(CheckStep(IMPL_END, &impl_)); | 
 |   } | 
 |  | 
 |   MainOrder main_ = MAIN_START; | 
 |   ImplOrder impl_ = IMPL_START; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestFrameOrdering); | 
 |  | 
 | class LayerTreeHostTestRequestedMainFrame : public LayerTreeHostTest { | 
 |  public: | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void WillBeginMainFrame() override { | 
 |     // Post NextStep() so it happens after the MainFrame completes. | 
 |     MainThreadTaskRunner()->PostTask( | 
 |         FROM_HERE, | 
 |         base::BindOnce(&LayerTreeHostTestRequestedMainFrame::NextStep, | 
 |                        base::Unretained(this))); | 
 |   } | 
 |  | 
 |   void NextStep() { | 
 |     // The MainFrame request is cleared once a MainFrame happens. | 
 |     EXPECT_FALSE(layer_tree_host()->RequestedMainFramePendingForTesting()); | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 0: | 
 |         ADD_FAILURE() | 
 |             << "Case 0 is the initial commit used to send the test here"; | 
 |         FALLTHROUGH; | 
 |       case 1: | 
 |         layer_tree_host()->SetNeedsAnimate(); | 
 |         break; | 
 |       case 2: | 
 |         layer_tree_host()->SetNeedsUpdateLayers(); | 
 |         break; | 
 |       case 3: | 
 |         layer_tree_host()->SetNeedsCommit(); | 
 |         break; | 
 |       case 4: | 
 |         EndTest(); | 
 |         return; | 
 |     } | 
 |     // SetNeeds{Animate,UpdateLayers,Commit}() will mean a MainFrame is pending. | 
 |     EXPECT_TRUE(layer_tree_host()->RequestedMainFramePendingForTesting()); | 
 |   } | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestRequestedMainFrame); | 
 |  | 
 | class LayerTreeHostTestSchedulingClient : public LayerTreeHostTest { | 
 |  public: | 
 |   void BeginTest() override { | 
 |     PostSetNeedsCommitToMainThread(); | 
 |     EXPECT_EQ(0, main_frame_scheduled_count_); | 
 |     EXPECT_EQ(0, main_frame_run_count_); | 
 |   } | 
 |  | 
 |   void DidScheduleBeginMainFrame() override { main_frame_scheduled_count_++; } | 
 |   void DidRunBeginMainFrame() override { main_frame_run_count_++; } | 
 |  | 
 |   void DidBeginMainFrame() override { | 
 |     EXPECT_EQ(1, main_frame_scheduled_count_); | 
 |     EXPECT_EQ(1, main_frame_run_count_); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void AfterTest() override {} | 
 |  | 
 |  private: | 
 |   int main_frame_scheduled_count_ = 0; | 
 |   int main_frame_run_count_ = 0; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestSchedulingClient); | 
 |  | 
 | class LayerTreeHostTestSetNeedsUpdateInsideLayout : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void UpdateLayerTreeHost() override { | 
 |     // This shouldn't cause a second commit to happen. | 
 |     layer_tree_host()->SetNeedsUpdateLayers(); | 
 |   } | 
 |  | 
 |   void DidCommit() override { | 
 |     EXPECT_EQ(1, layer_tree_host()->SourceFrameNumber()); | 
 |     EndTest(); | 
 |   } | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSetNeedsUpdateInsideLayout); | 
 |  | 
 | // Test if the LTHI receives ReadyToActivate notifications from the TileManager | 
 | // when no raster tasks get scheduled. | 
 | class LayerTreeHostTestReadyToActivateEmpty : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestReadyToActivateEmpty() | 
 |       : did_notify_ready_to_activate_(false), | 
 |         all_tiles_required_for_activation_are_ready_to_draw_(false), | 
 |         required_for_activation_count_(0) {} | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | 
 |     const std::vector<PictureLayerImpl*>& layers = | 
 |         impl->sync_tree()->picture_layers(); | 
 |     required_for_activation_count_ = 0; | 
 |     for (auto* layer : layers) { | 
 |       FakePictureLayerImpl* fake_layer = | 
 |           static_cast<FakePictureLayerImpl*>(layer); | 
 |       required_for_activation_count_ += | 
 |           fake_layer->CountTilesRequiredForActivation(); | 
 |     } | 
 |   } | 
 |  | 
 |   void NotifyReadyToActivateOnThread(LayerTreeHostImpl* impl) override { | 
 |     did_notify_ready_to_activate_ = true; | 
 |     all_tiles_required_for_activation_are_ready_to_draw_ = | 
 |         impl->tile_manager()->IsReadyToActivate(); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     EXPECT_TRUE(did_notify_ready_to_activate_); | 
 |     EXPECT_TRUE(all_tiles_required_for_activation_are_ready_to_draw_); | 
 |     EXPECT_EQ(size_t(0), required_for_activation_count_); | 
 |   } | 
 |  | 
 |  protected: | 
 |   bool did_notify_ready_to_activate_; | 
 |   bool all_tiles_required_for_activation_are_ready_to_draw_; | 
 |   size_t required_for_activation_count_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestReadyToActivateEmpty); | 
 |  | 
 | // Test if the LTHI receives ReadyToActivate notifications from the TileManager | 
 | // when some raster tasks flagged as REQUIRED_FOR_ACTIVATION got scheduled. | 
 | class LayerTreeHostTestReadyToActivateNonEmpty | 
 |     : public LayerTreeHostTestReadyToActivateEmpty { | 
 |  public: | 
 |   void SetupTree() override { | 
 |     client_.set_fill_with_nonsolid_color(true); | 
 |     scoped_refptr<FakePictureLayer> root_layer = | 
 |         FakePictureLayer::Create(&client_); | 
 |     root_layer->SetBounds(gfx::Size(1024, 1024)); | 
 |     root_layer->SetIsDrawable(true); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_layer); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     client_.set_bounds(root_layer->bounds()); | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     EXPECT_TRUE(did_notify_ready_to_activate_); | 
 |     EXPECT_TRUE(all_tiles_required_for_activation_are_ready_to_draw_); | 
 |     EXPECT_LE(size_t(1), required_for_activation_count_); | 
 |   } | 
 |  | 
 |  private: | 
 |   FakeContentLayerClient client_; | 
 | }; | 
 |  | 
 | // No single thread test because the commit goes directly to the active tree in | 
 | // single thread mode, so notify ready to activate is skipped. | 
 | // Flaky: https://crbug.com/947673 | 
 | // MULTI_THREAD_TEST_F(LayerTreeHostTestReadyToActivateNonEmpty); | 
 |  | 
 | // Test if the LTHI receives ReadyToDraw notifications from the TileManager when | 
 | // no raster tasks get scheduled. | 
 | class LayerTreeHostTestReadyToDrawEmpty : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestReadyToDrawEmpty() | 
 |       : did_notify_ready_to_draw_(false), | 
 |         all_tiles_required_for_draw_are_ready_to_draw_(false), | 
 |         required_for_draw_count_(0) {} | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void NotifyReadyToDrawOnThread(LayerTreeHostImpl* impl) override { | 
 |     did_notify_ready_to_draw_ = true; | 
 |     const std::vector<PictureLayerImpl*>& layers = | 
 |         impl->active_tree()->picture_layers(); | 
 |     all_tiles_required_for_draw_are_ready_to_draw_ = | 
 |         impl->tile_manager()->IsReadyToDraw(); | 
 |     for (auto* layer : layers) { | 
 |       FakePictureLayerImpl* fake_layer = | 
 |           static_cast<FakePictureLayerImpl*>(layer); | 
 |       required_for_draw_count_ += fake_layer->CountTilesRequiredForDraw(); | 
 |     } | 
 |  | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     EXPECT_TRUE(did_notify_ready_to_draw_); | 
 |     EXPECT_TRUE(all_tiles_required_for_draw_are_ready_to_draw_); | 
 |     EXPECT_EQ(size_t(0), required_for_draw_count_); | 
 |   } | 
 |  | 
 |  protected: | 
 |   bool did_notify_ready_to_draw_; | 
 |   bool all_tiles_required_for_draw_are_ready_to_draw_; | 
 |   size_t required_for_draw_count_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestReadyToDrawEmpty); | 
 |  | 
 | // Test if the LTHI receives ReadyToDraw notifications from the TileManager when | 
 | // some raster tasks flagged as REQUIRED_FOR_DRAW got scheduled. | 
 | class LayerTreeHostTestReadyToDrawNonEmpty | 
 |     : public LayerTreeHostTestReadyToDrawEmpty { | 
 |  public: | 
 |   void SetupTree() override { | 
 |     client_.set_fill_with_nonsolid_color(true); | 
 |     scoped_refptr<FakePictureLayer> root_layer = | 
 |         FakePictureLayer::Create(&client_); | 
 |     root_layer->SetBounds(gfx::Size(1024, 1024)); | 
 |     root_layer->SetIsDrawable(true); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_layer); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     client_.set_bounds(root_layer->bounds()); | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     EXPECT_TRUE(did_notify_ready_to_draw_); | 
 |     EXPECT_TRUE(all_tiles_required_for_draw_are_ready_to_draw_); | 
 |     EXPECT_LE(size_t(1), required_for_draw_count_); | 
 |   } | 
 |  | 
 |  private: | 
 |   FakeContentLayerClient client_; | 
 | }; | 
 |  | 
 | // Note: With this test setup, we only get tiles flagged as REQUIRED_FOR_DRAW in | 
 | // single threaded mode. | 
 | SINGLE_THREAD_TEST_F(LayerTreeHostTestReadyToDrawNonEmpty); | 
 |  | 
 | // This tests if we get the READY_TO_DRAW signal and draw if we become invisible | 
 | // and then become visible again. | 
 | class LayerTreeHostTestReadyToDrawVisibility : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestReadyToDrawVisibility() | 
 |       : LayerTreeHostTest(), | 
 |         toggled_visibility_(false), | 
 |         did_notify_ready_to_draw_(false), | 
 |         did_draw_(false) {} | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void SetupTree() override { | 
 |     client_.set_fill_with_nonsolid_color(true); | 
 |     scoped_refptr<FakePictureLayer> root_layer = | 
 |         FakePictureLayer::Create(&client_); | 
 |     root_layer->SetBounds(gfx::Size(1024, 1024)); | 
 |     client_.set_bounds(root_layer->bounds()); | 
 |     root_layer->SetIsDrawable(true); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_layer); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     if (!toggled_visibility_) { | 
 |       { | 
 |         DebugScopedSetMainThread main(task_runner_provider()); | 
 |         layer_tree_host()->SetVisible(false); | 
 |       } | 
 |       toggled_visibility_ = true; | 
 |       EXPECT_FALSE(host_impl->visible()); | 
 |     } | 
 |   } | 
 |  | 
 |   void NotifyReadyToDrawOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     // Sometimes the worker thread posts NotifyReadyToDraw in the extremely | 
 |     // short duration of time between PrepareTiles and SetVisible(false) so we | 
 |     // might get two NotifyReadyToDraw signals for this test. | 
 |     did_notify_ready_to_draw_ = true; | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     EXPECT_FALSE(did_draw_); | 
 |     did_draw_ = true; | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void DidFinishImplFrameOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     if (!host_impl->visible()) { | 
 |       { | 
 |         DebugScopedSetMainThread main(task_runner_provider()); | 
 |         layer_tree_host()->SetVisible(true); | 
 |       } | 
 |       EXPECT_TRUE(host_impl->visible()); | 
 |     } | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     EXPECT_TRUE(did_notify_ready_to_draw_); | 
 |     EXPECT_TRUE(did_draw_); | 
 |   } | 
 |  | 
 |  private: | 
 |   FakeContentLayerClient client_; | 
 |   bool toggled_visibility_; | 
 |   bool did_notify_ready_to_draw_; | 
 |   bool did_draw_; | 
 | }; | 
 |  | 
 | // Note: With this test setup, we only get tiles flagged as REQUIRED_FOR_DRAW in | 
 | // single threaded mode. | 
 | SINGLE_THREAD_TEST_F(LayerTreeHostTestReadyToDrawVisibility); | 
 |  | 
 | class LayerTreeHostContextCacheTest : public LayerTreeHostTest { | 
 |  public: | 
 |   std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink( | 
 |       const viz::RendererSettings& renderer_settings, | 
 |       double refresh_rate, | 
 |       scoped_refptr<viz::ContextProvider> compositor_context_provider, | 
 |       scoped_refptr<viz::RasterContextProvider> worker_context_provider) | 
 |       override { | 
 |     // Create the main viz::ContextProvider with a MockContextSupport. | 
 |     auto main_support = std::make_unique<MockContextSupport>(); | 
 |     mock_main_context_support_ = main_support.get(); | 
 |     auto test_main_context_provider = | 
 |         viz::TestContextProvider::Create(std::move(main_support)); | 
 |  | 
 |     // Create the main viz::ContextProvider with a MockContextSupport. | 
 |     auto worker_support = std::make_unique<MockContextSupport>(); | 
 |     mock_worker_context_support_ = worker_support.get(); | 
 |     auto test_worker_context_provider = | 
 |         viz::TestContextProvider::CreateWorker(std::move(worker_support)); | 
 |  | 
 |     // At init, visibility is set to true, so SetAggressivelyFreeResources will | 
 |     // be disabled. | 
 |     EXPECT_CALL(*mock_main_context_support_, | 
 |                 SetAggressivelyFreeResources(false)); | 
 |     EXPECT_CALL(*mock_worker_context_support_, | 
 |                 SetAggressivelyFreeResources(false)); | 
 |  | 
 |     return LayerTreeHostTest::CreateLayerTreeFrameSink( | 
 |         renderer_settings, refresh_rate, std::move(test_main_context_provider), | 
 |         std::move(test_worker_context_provider)); | 
 |   } | 
 |  | 
 |   void BeginTest() override {} | 
 |  | 
 |  protected: | 
 |   class MockContextSupport : public viz::TestContextSupport { | 
 |    public: | 
 |     MockContextSupport() = default; | 
 |     MOCK_METHOD1(SetAggressivelyFreeResources, | 
 |                  void(bool aggressively_free_resources)); | 
 |   }; | 
 |  | 
 |   MockContextSupport* mock_main_context_support_; | 
 |   MockContextSupport* mock_worker_context_support_; | 
 | }; | 
 |  | 
 | // Test if the LTH successfully frees resources on the main/worker | 
 | // ContextSupport when visibility is set to false. | 
 | class LayerTreeHostFreesContextResourcesOnInvisible | 
 |     : public LayerTreeHostContextCacheTest { | 
 |  public: | 
 |   void InitializedRendererOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    bool success) override { | 
 |     // Ensure that our initialization expectations have completed. | 
 |     Mock::VerifyAndClearExpectations(mock_main_context_support_); | 
 |     Mock::VerifyAndClearExpectations(mock_worker_context_support_); | 
 |  | 
 |     // Update visibility and make sure resources are freed. | 
 |     EXPECT_CALL(*mock_main_context_support_, | 
 |                 SetAggressivelyFreeResources(true)); | 
 |     EXPECT_CALL(*mock_worker_context_support_, | 
 |                 SetAggressivelyFreeResources(true)) | 
 |         .WillOnce(testing::Invoke([this](bool is_visible) { EndTest(); })); | 
 |     PostSetVisibleToMainThread(false); | 
 |   } | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostFreesContextResourcesOnInvisible); | 
 |  | 
 | // Test if the LTH successfully frees worker context resources when the hard | 
 | // memory limit is set to zero. | 
 | class LayerTreeHostFreesWorkerContextResourcesOnZeroMemoryLimit | 
 |     : public LayerTreeHostContextCacheTest { | 
 |  public: | 
 |   void InitializedRendererOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    bool success) override { | 
 |     // Ensure that our initialization expectations have completed. | 
 |     Mock::VerifyAndClearExpectations(mock_worker_context_support_); | 
 |  | 
 |     // Worker context support should start freeing resources when hard memory | 
 |     // limit is zeroed. | 
 |     EXPECT_CALL(*mock_worker_context_support_, | 
 |                 SetAggressivelyFreeResources(true)) | 
 |         .WillOnce(testing::Invoke([this](bool is_visible) { | 
 |           // Main context is unchanged. It will start freeing on destruction. | 
 |           EXPECT_CALL(*mock_main_context_support_, | 
 |                       SetAggressivelyFreeResources(true)); | 
 |           EndTest(); | 
 |         })); | 
 |     ManagedMemoryPolicy zero_policy( | 
 |         0, gpu::MemoryAllocation::CUTOFF_ALLOW_NOTHING, 0); | 
 |     host_impl->SetMemoryPolicy(zero_policy); | 
 |   } | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F( | 
 |     LayerTreeHostFreesWorkerContextResourcesOnZeroMemoryLimit); | 
 |  | 
 | // Test if the LTH successfully frees worker context resources when hard memory | 
 | // limit is set to zero while using a synchronous compositor (Android WebView). | 
 | class LayerTreeHostFreesWorkerContextResourcesOnZeroMemoryLimitSynchronous | 
 |     : public LayerTreeHostFreesWorkerContextResourcesOnZeroMemoryLimit { | 
 |  public: | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     LayerTreeHostContextCacheTest::InitializeSettings(settings); | 
 |     settings->using_synchronous_renderer_compositor = true; | 
 |   } | 
 | }; | 
 |  | 
 | // Android Webview only runs in multi-threaded compositing mode. | 
 | MULTI_THREAD_TEST_F( | 
 |     LayerTreeHostFreesWorkerContextResourcesOnZeroMemoryLimitSynchronous); | 
 |  | 
 | // Test if the LTH successfully frees main and worker resources when the | 
 | // OutputSurface is destroyed. | 
 | class LayerTreeHostFreeContextResourcesOnDestroy | 
 |     : public LayerTreeHostContextCacheTest { | 
 |  public: | 
 |   void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl, | 
 |                                   const viz::BeginFrameArgs& args) override { | 
 |     if (!first_will_begin_impl_frame_) | 
 |       return; | 
 |  | 
 |     first_will_begin_impl_frame_ = false; | 
 |  | 
 |     // Ensure that our initialization expectations have completed. | 
 |     Mock::VerifyAndClearExpectations(mock_main_context_support_); | 
 |     Mock::VerifyAndClearExpectations(mock_worker_context_support_); | 
 |  | 
 |     // We leave the LTHI visible, so it start freeing resources on destruction. | 
 |     EXPECT_CALL(*mock_worker_context_support_, | 
 |                 SetAggressivelyFreeResources(true)); | 
 |     EXPECT_CALL(*mock_main_context_support_, | 
 |                 SetAggressivelyFreeResources(true)); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |  private: | 
 |   bool first_will_begin_impl_frame_ = true; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostFreeContextResourcesOnDestroy); | 
 |  | 
 | // Test if the LTH successfully frees and stops freeing context resources | 
 | // when the LayerTreeFrameSink is lost and recreated. | 
 | class LayerTreeHostCacheBehaviorOnLayerTreeFrameSinkRecreated | 
 |     : public LayerTreeHostContextCacheTest { | 
 |  public: | 
 |   void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl, | 
 |                                   const viz::BeginFrameArgs& args) override { | 
 |     // This code is run once, to trigger recreation of our LayerTreeFrameSink. | 
 |     if (test_state_ != TestState::INIT) | 
 |       return; | 
 |  | 
 |     // Ensure that our initialization expectations have completed. | 
 |     Mock::VerifyAndClearExpectations(mock_main_context_support_); | 
 |     Mock::VerifyAndClearExpectations(mock_worker_context_support_); | 
 |  | 
 |     // LayerTreeFrameSink lost expectations. | 
 |     EXPECT_CALL(*mock_worker_context_support_, | 
 |                 SetAggressivelyFreeResources(true)); | 
 |     EXPECT_CALL(*mock_main_context_support_, | 
 |                 SetAggressivelyFreeResources(true)); | 
 |     host_impl->DidLoseLayerTreeFrameSink(); | 
 |     test_state_ = TestState::RECREATED; | 
 |   } | 
 |  | 
 |   void InitializedRendererOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    bool success) override { | 
 |     // This is run after we have recreated our LayerTreeFrameSink. | 
 |     if (test_state_ != TestState::RECREATED) | 
 |       return; | 
 |  | 
 |     // Ensure that our expectations have completed. | 
 |     Mock::VerifyAndClearExpectations(mock_main_context_support_); | 
 |     Mock::VerifyAndClearExpectations(mock_worker_context_support_); | 
 |  | 
 |     // Destruction exptectations. | 
 |     EXPECT_CALL(*mock_worker_context_support_, | 
 |                 SetAggressivelyFreeResources(true)); | 
 |     EXPECT_CALL(*mock_main_context_support_, | 
 |                 SetAggressivelyFreeResources(true)); | 
 |     EndTest(); | 
 |     test_state_ = TestState::DONE; | 
 |   } | 
 |  | 
 |  private: | 
 |   enum class TestState { INIT, RECREATED, DONE }; | 
 |   TestState test_state_ = TestState::INIT; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F( | 
 |     LayerTreeHostCacheBehaviorOnLayerTreeFrameSinkRecreated); | 
 |  | 
 | // Two setNeedsCommits in a row should lead to at least 1 commit and at least 1 | 
 | // draw with frame 0. | 
 | class LayerTreeHostTestSetNeedsCommit1 : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestSetNeedsCommit1() : num_commits_(0), num_draws_(0) {} | 
 |  | 
 |   void BeginTest() override { | 
 |     PostSetNeedsCommitToMainThread(); | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* impl) override { | 
 |     num_draws_++; | 
 |     if (!impl->active_tree()->source_frame_number()) | 
 |       EndTest(); | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | 
 |     num_commits_++; | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     EXPECT_LE(1, num_commits_); | 
 |     EXPECT_LE(1, num_draws_); | 
 |   } | 
 |  | 
 |  private: | 
 |   int num_commits_; | 
 |   int num_draws_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSetNeedsCommit1); | 
 |  | 
 | // A SetNeedsCommit should lead to 1 commit. Issuing a second commit after that | 
 | // first committed frame draws should lead to another commit. | 
 | class LayerTreeHostTestSetNeedsCommit2 : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestSetNeedsCommit2() : num_commits_(0), num_draws_(0) {} | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* impl) override { ++num_draws_; } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | 
 |     ++num_commits_; | 
 |     switch (num_commits_) { | 
 |       case 1: | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 2: | 
 |         EndTest(); | 
 |         break; | 
 |       default: | 
 |         NOTREACHED(); | 
 |     } | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     EXPECT_EQ(2, num_commits_); | 
 |     EXPECT_LE(1, num_draws_); | 
 |   } | 
 |  | 
 |  private: | 
 |   int num_commits_; | 
 |   int num_draws_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestSetNeedsCommit2); | 
 |  | 
 | // Verify that we pass property values in PushPropertiesTo. | 
 | class LayerTreeHostTestPushPropertiesTo : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     SetInitialRootBounds(gfx::Size(10, 10)); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   enum Properties { | 
 |     STARTUP, | 
 |     BOUNDS, | 
 |     HIDE_LAYER_AND_SUBTREE, | 
 |     DRAWS_CONTENT, | 
 |     DONE, | 
 |   }; | 
 |  | 
 |   void BeginTest() override { | 
 |     index_ = STARTUP; | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* impl) override { | 
 |     VerifyAfterValues(impl->active_tree()->root_layer()); | 
 |   } | 
 |  | 
 |   void DidCommitAndDrawFrame() override { | 
 |     SetBeforeValues(layer_tree_host()->root_layer()); | 
 |     VerifyBeforeValues(layer_tree_host()->root_layer()); | 
 |  | 
 |     ++index_; | 
 |     if (index_ == DONE) { | 
 |       EndTest(); | 
 |       return; | 
 |     } | 
 |  | 
 |     SetAfterValues(layer_tree_host()->root_layer()); | 
 |   } | 
 |  | 
 |   void VerifyBeforeValues(Layer* layer) { | 
 |     EXPECT_EQ(gfx::Size(10, 10).ToString(), layer->bounds().ToString()); | 
 |     EXPECT_FALSE(layer->hide_layer_and_subtree()); | 
 |     EXPECT_FALSE(layer->DrawsContent()); | 
 |   } | 
 |  | 
 |   void SetBeforeValues(Layer* layer) { | 
 |     layer->SetBounds(gfx::Size(10, 10)); | 
 |     layer->SetHideLayerAndSubtree(false); | 
 |     layer->SetIsDrawable(false); | 
 |   } | 
 |  | 
 |   void VerifyAfterValues(LayerImpl* layer) { | 
 |     EffectTree& tree = layer->layer_tree_impl()->property_trees()->effect_tree; | 
 |     EffectNode* node = tree.Node(layer->effect_tree_index()); | 
 |     switch (static_cast<Properties>(index_)) { | 
 |       case STARTUP: | 
 |       case DONE: | 
 |         break; | 
 |       case BOUNDS: | 
 |         EXPECT_EQ(gfx::Size(20, 20).ToString(), layer->bounds().ToString()); | 
 |         break; | 
 |       case HIDE_LAYER_AND_SUBTREE: | 
 |         EXPECT_EQ(tree.EffectiveOpacity(node), 0.f); | 
 |         break; | 
 |       case DRAWS_CONTENT: | 
 |         EXPECT_TRUE(layer->DrawsContent()); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void SetAfterValues(Layer* layer) { | 
 |     switch (static_cast<Properties>(index_)) { | 
 |       case STARTUP: | 
 |       case DONE: | 
 |         break; | 
 |       case BOUNDS: | 
 |         layer->SetBounds(gfx::Size(20, 20)); | 
 |         break; | 
 |       case HIDE_LAYER_AND_SUBTREE: | 
 |         layer->SetHideLayerAndSubtree(true); | 
 |         break; | 
 |       case DRAWS_CONTENT: | 
 |         layer->SetIsDrawable(true); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   int index_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestPushPropertiesTo); | 
 |  | 
 | // Verify that invisible render passes are excluded in CompositorFrame. | 
 | class LayerTreeHostTestInvisibleLayersSkipRenderPass | 
 |     : public LayerTreeHostTest { | 
 |  protected: | 
 |   enum Step { | 
 |     kAllInvisible, | 
 |     kOneVisible, | 
 |     kAllVisible, | 
 |     kAllInvisibleAgain, | 
 |     kDone, | 
 |   }; | 
 |  | 
 |   void SetupTree() override { | 
 |     SetInitialRootBounds(gfx::Size(10, 10)); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     auto* root = layer_tree_host()->root_layer(); | 
 |     child1_ = CreateChild(root); | 
 |     child2_ = CreateChild(root); | 
 |   } | 
 |  | 
 |   scoped_refptr<Layer> CreateChild(scoped_refptr<Layer> root) { | 
 |     auto child = Layer::Create(); | 
 |     // Initially hidden. | 
 |     child->SetHideLayerAndSubtree(true); | 
 |     AddBackgroundBlurFilter(child.get()); | 
 |     root->AddChild(child.get()); | 
 |     return child; | 
 |   } | 
 |  | 
 |   void AddBackgroundBlurFilter(Layer* layer) { | 
 |     FilterOperations filters; | 
 |     filters.Append(FilterOperation::CreateBlurFilter( | 
 |         30, SkBlurImageFilter::kClamp_TileMode)); | 
 |     layer->SetBackdropFilters(filters); | 
 |   } | 
 |  | 
 |   void BeginTest() override { | 
 |     index_ = kAllInvisible; | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void DidCommitAndDrawFrame() override { | 
 |     ++index_; | 
 |     switch (index_) { | 
 |       case kAllInvisible: | 
 |         NOTREACHED(); | 
 |         break; | 
 |       case kOneVisible: | 
 |         child1_->SetHideLayerAndSubtree(false); | 
 |         break; | 
 |       case kAllVisible: | 
 |         child2_->SetHideLayerAndSubtree(false); | 
 |         break; | 
 |       case kAllInvisibleAgain: | 
 |         child1_->SetHideLayerAndSubtree(true); | 
 |         child2_->SetHideLayerAndSubtree(true); | 
 |         break; | 
 |       case kDone: | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void DisplayReceivedCompositorFrameOnThread( | 
 |       const viz::CompositorFrame& frame) override { | 
 |     size_t num_render_passes = frame.render_pass_list.size(); | 
 |     switch (index_) { | 
 |       case kAllInvisible: | 
 |         // There is only a root render pass. | 
 |         EXPECT_EQ(1u, num_render_passes); | 
 |         break; | 
 |       case kOneVisible: | 
 |         EXPECT_EQ(2u, num_render_passes); | 
 |         break; | 
 |       case kAllVisible: | 
 |         EXPECT_EQ(3u, num_render_passes); | 
 |         break; | 
 |       case kAllInvisibleAgain: | 
 |         EXPECT_EQ(1u, num_render_passes); | 
 |         break; | 
 |       case kDone: | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   int index_ = kAllInvisible; | 
 |   scoped_refptr<Layer> child1_; | 
 |   scoped_refptr<Layer> child2_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestInvisibleLayersSkipRenderPass); | 
 |  | 
 | class LayerTreeHostTestPushNodeOwnerToNodeIdMap : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     root_ = Layer::Create(); | 
 |     child_ = Layer::Create(); | 
 |     root_->AddChild(child_); | 
 |     layer_tree_host()->SetRootLayer(root_); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommit() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         // child_ should create transform, effect node. | 
 |         child_->SetForceRenderSurfaceForTesting(true); | 
 |         break; | 
 |       case 2: | 
 |         // child_ should create a scroll node. | 
 |         child_->SetScrollable(gfx::Size(1, 1)); | 
 |         break; | 
 |       case 3: | 
 |         // child_ should create a clip node. | 
 |         child_->SetMasksToBounds(true); | 
 |         break; | 
 |       case 4: | 
 |         // child_ should only create the scroll-related nodes. | 
 |         child_->SetMasksToBounds(false); | 
 |         child_->SetForceRenderSurfaceForTesting(false); | 
 |         // Should have no effect because empty bounds do not prevent scrolling. | 
 |         child_->SetScrollable(gfx::Size(0, 0)); | 
 |     } | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | 
 |     PropertyTrees* property_trees = impl->sync_tree()->property_trees(); | 
 |     const TransformNode* root_transform_node = | 
 |         property_trees->transform_tree.Node(root_->transform_tree_index()); | 
 |     const TransformNode* child_transform_node = | 
 |         property_trees->transform_tree.Node(child_->transform_tree_index()); | 
 |     const EffectNode* root_effect_node = | 
 |         property_trees->effect_tree.Node(root_->effect_tree_index()); | 
 |     const EffectNode* child_effect_node = | 
 |         property_trees->effect_tree.Node(child_->effect_tree_index()); | 
 |     const ClipNode* root_clip_node = | 
 |         property_trees->clip_tree.Node(root_->clip_tree_index()); | 
 |     const ClipNode* child_clip_node = | 
 |         property_trees->clip_tree.Node(child_->clip_tree_index()); | 
 |     const ScrollNode* root_scroll_node = | 
 |         property_trees->scroll_tree.Node(root_->scroll_tree_index()); | 
 |     const ScrollNode* child_scroll_node = | 
 |         property_trees->scroll_tree.Node(child_->scroll_tree_index()); | 
 |     switch (impl->sync_tree()->source_frame_number()) { | 
 |       case 0: | 
 |         // root_ should create transform, scroll and effect tree nodes but not | 
 |         // a clip node. | 
 |         EXPECT_NE(nullptr, root_transform_node); | 
 |         EXPECT_NE(nullptr, root_effect_node); | 
 |         EXPECT_NE(nullptr, root_scroll_node); | 
 |         EXPECT_NE(nullptr, root_clip_node); | 
 |         EXPECT_EQ(root_transform_node, child_transform_node); | 
 |         EXPECT_EQ(child_effect_node, root_effect_node); | 
 |         EXPECT_EQ(root_clip_node, child_clip_node); | 
 |         EXPECT_EQ(root_scroll_node, child_scroll_node); | 
 |  | 
 |         break; | 
 |       case 1: | 
 |         // child_ should create a transfrom, effect nodes but not a scroll, clip | 
 |         // node. | 
 |         EXPECT_NE(root_transform_node, child_transform_node); | 
 |         EXPECT_NE(child_effect_node, root_effect_node); | 
 |         EXPECT_EQ(root_clip_node, child_clip_node); | 
 |         EXPECT_EQ(root_scroll_node, child_scroll_node); | 
 |  | 
 |         break; | 
 |       case 2: | 
 |         // child_ should create a scroll node. | 
 |         EXPECT_NE(root_scroll_node, child_scroll_node); | 
 |         break; | 
 |       case 3: | 
 |         // child_ should create a clip node. | 
 |         EXPECT_NE(root_clip_node, child_clip_node); | 
 |         break; | 
 |       case 4: | 
 |         // child_ should only create the scroll-related nodes. | 
 |         EXPECT_EQ(child_transform_node->id, child_scroll_node->transform_id); | 
 |         EXPECT_EQ(child_effect_node, root_effect_node); | 
 |         EXPECT_EQ(root_clip_node, child_clip_node); | 
 |         EXPECT_NE(root_scroll_node, child_scroll_node); | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   scoped_refptr<Layer> root_; | 
 |   scoped_refptr<Layer> child_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestPushNodeOwnerToNodeIdMap); | 
 |  | 
 | class LayerTreeHostTestPushElementIdToNodeIdMap : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     root_ = Layer::Create(); | 
 |     child_ = Layer::Create(); | 
 |     root_->AddChild(child_); | 
 |     layer_tree_host()->SetRootLayer(root_); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommit() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         child_->SetForceRenderSurfaceForTesting(true); | 
 |         // Add a non-fast region to ensure a scroll node is created. | 
 |         child_->SetNonFastScrollableRegion(Region(gfx::Rect(50, 50, 50, 50))); | 
 |         break; | 
 |       case 2: | 
 |         child_->SetForceRenderSurfaceForTesting(false); | 
 |         // Remove the non-fast region to ensure a scroll node is removed. | 
 |         child_->SetNonFastScrollableRegion(Region()); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | 
 |     PropertyTrees* property_trees = impl->sync_tree()->property_trees(); | 
 |     LayerImpl* child_impl_ = impl->sync_tree()->LayerById(child_->id()); | 
 |     switch (impl->sync_tree()->source_frame_number()) { | 
 |       case 0: | 
 |         EXPECT_EQ(2U, child_impl_->layer_tree_impl() | 
 |                           ->property_trees() | 
 |                           ->transform_tree.size()); | 
 |         EXPECT_EQ(2U, child_impl_->layer_tree_impl() | 
 |                           ->property_trees() | 
 |                           ->effect_tree.size()); | 
 |         EXPECT_EQ(2U, child_impl_->layer_tree_impl() | 
 |                           ->property_trees() | 
 |                           ->scroll_tree.size()); | 
 |         EXPECT_TRUE(property_trees->element_id_to_transform_node_index.find( | 
 |                         child_->element_id()) == | 
 |                     property_trees->element_id_to_transform_node_index.end()); | 
 |         EXPECT_TRUE(property_trees->element_id_to_effect_node_index.find( | 
 |                         child_->element_id()) == | 
 |                     property_trees->element_id_to_effect_node_index.end()); | 
 |         EXPECT_TRUE(property_trees->element_id_to_scroll_node_index.find( | 
 |                         child_->element_id()) == | 
 |                     property_trees->element_id_to_scroll_node_index.end()); | 
 |         break; | 
 |       case 1: | 
 |         EXPECT_EQ(3U, child_impl_->layer_tree_impl() | 
 |                           ->property_trees() | 
 |                           ->transform_tree.size()); | 
 |         EXPECT_EQ(3U, child_impl_->layer_tree_impl() | 
 |                           ->property_trees() | 
 |                           ->effect_tree.size()); | 
 |         EXPECT_EQ(3U, child_impl_->layer_tree_impl() | 
 |                           ->property_trees() | 
 |                           ->scroll_tree.size()); | 
 |         EXPECT_EQ( | 
 |             2, property_trees | 
 |                    ->element_id_to_transform_node_index[child_->element_id()]); | 
 |         EXPECT_EQ(2, | 
 |                   property_trees | 
 |                       ->element_id_to_effect_node_index[child_->element_id()]); | 
 |         EXPECT_EQ(2, | 
 |                   property_trees | 
 |                       ->element_id_to_scroll_node_index[child_->element_id()]); | 
 |         break; | 
 |       case 2: | 
 |         EXPECT_EQ(2U, child_impl_->layer_tree_impl() | 
 |                           ->property_trees() | 
 |                           ->transform_tree.size()); | 
 |         EXPECT_EQ(2U, child_impl_->layer_tree_impl() | 
 |                           ->property_trees() | 
 |                           ->effect_tree.size()); | 
 |         EXPECT_TRUE(property_trees->element_id_to_transform_node_index.find( | 
 |                         child_->element_id()) == | 
 |                     property_trees->element_id_to_transform_node_index.end()); | 
 |         EXPECT_TRUE(property_trees->element_id_to_effect_node_index.find( | 
 |                         child_->element_id()) == | 
 |                     property_trees->element_id_to_effect_node_index.end()); | 
 |         EXPECT_TRUE(property_trees->element_id_to_scroll_node_index.find( | 
 |                         child_->element_id()) == | 
 |                     property_trees->element_id_to_scroll_node_index.end()); | 
 |         break; | 
 |     } | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |  private: | 
 |   scoped_refptr<Layer> root_; | 
 |   scoped_refptr<Layer> child_; | 
 | }; | 
 |  | 
 | // Validates that, for a layer with a compositor element id set on it, mappings | 
 | // from compositor element id to transform/effect node indexes are created as | 
 | // part of building a layer's property tree and are present on the impl thread. | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestPushElementIdToNodeIdMap); | 
 |  | 
 | class LayerTreeHostTestSurfaceDamage : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     root_ = Layer::Create(); | 
 |     child_ = Layer::Create(); | 
 |     grand_child_ = Layer::Create(); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_); | 
 |     root_->AddChild(child_); | 
 |     child_->AddChild(grand_child_); | 
 |  | 
 |     root_->SetBounds(gfx::Size(50, 50)); | 
 |     root_->SetMasksToBounds(true); | 
 |     child_->SetForceRenderSurfaceForTesting(true); | 
 |  | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommit() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         grand_child_->SetOpacity(0.9f); | 
 |         break; | 
 |       case 2: | 
 |         root_->SetBounds(gfx::Size(20, 20)); | 
 |         break; | 
 |       case 3: | 
 |         child_->SetOpacity(0.8f); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     LayerImpl* root_impl = impl->active_tree()->LayerById(root_->id()); | 
 |     LayerImpl* child_impl = impl->active_tree()->LayerById(child_->id()); | 
 |     switch (impl->active_tree()->source_frame_number()) { | 
 |       case 0: | 
 |         EXPECT_TRUE(GetRenderSurface(root_impl)->AncestorPropertyChanged()); | 
 |         EXPECT_TRUE(GetRenderSurface(child_impl)->AncestorPropertyChanged()); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 1: | 
 |         EXPECT_FALSE(GetRenderSurface(root_impl)->AncestorPropertyChanged()); | 
 |         EXPECT_FALSE(GetRenderSurface(child_impl)->AncestorPropertyChanged()); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 2: | 
 |         EXPECT_TRUE(GetRenderSurface(root_impl)->AncestorPropertyChanged()); | 
 |         EXPECT_TRUE(GetRenderSurface(child_impl)->AncestorPropertyChanged()); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 3: | 
 |         EXPECT_FALSE(GetRenderSurface(root_impl)->AncestorPropertyChanged()); | 
 |         EXPECT_TRUE(GetRenderSurface(child_impl)->AncestorPropertyChanged()); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 4: | 
 |         EXPECT_FALSE(GetRenderSurface(root_impl)->AncestorPropertyChanged()); | 
 |         EXPECT_FALSE(GetRenderSurface(child_impl)->AncestorPropertyChanged()); | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |  | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |  private: | 
 |   scoped_refptr<Layer> root_; | 
 |   scoped_refptr<Layer> child_; | 
 |   scoped_refptr<Layer> grand_child_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSurfaceDamage); | 
 |  | 
 | class LayerTreeHostTestLayerListSurfaceDamage : public LayerTreeHostTest { | 
 |  protected: | 
 |   LayerTreeHostTestLayerListSurfaceDamage() { SetUseLayerLists(); } | 
 |  | 
 |   void SetupTree() override { | 
 |     SetInitialRootBounds(gfx::Size(50, 50)); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     root_ = layer_tree_host()->root_layer(); | 
 |  | 
 |     child_a_ = Layer::Create(); | 
 |     child_a_->SetBounds(gfx::Size(10, 20)); | 
 |     child_a_->SetIsDrawable(true); | 
 |     CopyProperties(root_, child_a_.get()); | 
 |     auto& effect_a = CreateEffectNode(child_a_.get()); | 
 |     effect_a.render_surface_reason = RenderSurfaceReason::kTest; | 
 |     root_->AddChild(child_a_); | 
 |  | 
 |     child_b_ = Layer::Create(); | 
 |     child_b_->SetBounds(gfx::Size(20, 10)); | 
 |     child_b_->SetIsDrawable(true); | 
 |     CopyProperties(root_, child_b_.get()); | 
 |     auto& effect_b = CreateEffectNode(child_b_.get()); | 
 |     effect_b.render_surface_reason = RenderSurfaceReason::kTest; | 
 |     root_->AddChild(child_b_); | 
 |  | 
 |     child_c_ = Layer::Create(); | 
 |     child_c_->SetBounds(gfx::Size(15, 15)); | 
 |     child_c_->SetIsDrawable(true); | 
 |     CopyProperties(root_, child_c_.get()); | 
 |     auto& effect_c = CreateEffectNode(child_c_.get()); | 
 |     effect_c.render_surface_reason = RenderSurfaceReason::kTest; | 
 |     root_->AddChild(child_c_); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommit() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         // Push an unchanged list. This should cause no damage. | 
 |         { | 
 |           LayerList same_list = root_->children(); | 
 |           root_->SetChildLayerList(same_list); | 
 |         } | 
 |         break; | 
 |       case 2: | 
 |         // Reverse the last two layers so the order becomes: [a, c, b]. This | 
 |         // should only damage the 'b' layer. | 
 |         { | 
 |           LayerList last_two_reversed; | 
 |           last_two_reversed.push_back(child_a_); | 
 |           last_two_reversed.push_back(child_c_); | 
 |           last_two_reversed.push_back(child_b_); | 
 |           root_->SetChildLayerList(last_two_reversed); | 
 |         } | 
 |         break; | 
 |       case 3: | 
 |         // Reverse the first two layers so the order becomes: [c, a, b]. This | 
 |         // should damage the last two layers, 'a' and 'b'. | 
 |         { | 
 |           LayerList last_pair_reversed; | 
 |           last_pair_reversed.push_back(child_c_); | 
 |           last_pair_reversed.push_back(child_a_); | 
 |           last_pair_reversed.push_back(child_b_); | 
 |           root_->SetChildLayerList(last_pair_reversed); | 
 |         } | 
 |         break; | 
 |       case 4: | 
 |         // Remove the first layer, 'c', so the order becomes: ['a', 'b']. This | 
 |         // should not damage 'a' or 'b'. | 
 |         { | 
 |           LayerList first_removed = root_->children(); | 
 |           first_removed.erase(first_removed.begin()); | 
 |           root_->SetChildLayerList(first_removed); | 
 |         } | 
 |         break; | 
 |       case 5: | 
 |         // Add a new layer, 'c', so the order becomes: ['a', 'b', 'c']. This | 
 |         // should only damage 'c'. | 
 |         { | 
 |           LayerList existing_plus_new_child = root_->children(); | 
 |           existing_plus_new_child.push_back(child_c_); | 
 |           root_->SetChildLayerList(existing_plus_new_child); | 
 |         } | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     LayerImpl* child_a_impl = impl->active_tree()->LayerById(child_a_->id()); | 
 |     LayerImpl* child_b_impl = impl->active_tree()->LayerById(child_b_->id()); | 
 |     LayerImpl* child_c_impl = impl->active_tree()->LayerById(child_c_->id()); | 
 |     switch (impl->active_tree()->source_frame_number()) { | 
 |       case 0: | 
 |         // Full damage on first frame. | 
 |         EXPECT_EQ(GetRenderSurface(child_a_impl)->GetDamageRect(), | 
 |                   gfx::Rect(0, 0, 10, 20)); | 
 |         EXPECT_EQ(GetRenderSurface(child_b_impl)->GetDamageRect(), | 
 |                   gfx::Rect(0, 0, 20, 10)); | 
 |         EXPECT_EQ(GetRenderSurface(child_c_impl)->GetDamageRect(), | 
 |                   gfx::Rect(0, 0, 15, 15)); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 1: | 
 |         // No damage after pushing the same list. | 
 |         EXPECT_TRUE(GetRenderSurface(child_a_impl)->GetDamageRect().IsEmpty()); | 
 |         EXPECT_TRUE(GetRenderSurface(child_b_impl)->GetDamageRect().IsEmpty()); | 
 |         EXPECT_TRUE(GetRenderSurface(child_c_impl)->GetDamageRect().IsEmpty()); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 2: | 
 |         // Only 'b' damaged after reversing the last two layers. | 
 |         EXPECT_TRUE(GetRenderSurface(child_a_impl)->GetDamageRect().IsEmpty()); | 
 |         EXPECT_EQ(GetRenderSurface(child_b_impl)->GetDamageRect(), | 
 |                   gfx::Rect(0, 0, 20, 10)); | 
 |         EXPECT_TRUE(GetRenderSurface(child_c_impl)->GetDamageRect().IsEmpty()); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 3: | 
 |         // 'a' and 'b' damaged after reversing the first two layers. | 
 |         EXPECT_EQ(GetRenderSurface(child_a_impl)->GetDamageRect(), | 
 |                   gfx::Rect(0, 0, 10, 20)); | 
 |         EXPECT_EQ(GetRenderSurface(child_b_impl)->GetDamageRect(), | 
 |                   gfx::Rect(0, 0, 20, 10)); | 
 |         EXPECT_TRUE(GetRenderSurface(child_c_impl)->GetDamageRect().IsEmpty()); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 4: | 
 |         // When the first layer, 'c', is removed, 'a' and 'b' should not be | 
 |         // damaged. | 
 |         EXPECT_TRUE(GetRenderSurface(child_a_impl)->GetDamageRect().IsEmpty()); | 
 |         EXPECT_TRUE(GetRenderSurface(child_b_impl)->GetDamageRect().IsEmpty()); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 5: | 
 |         // When 'c' is added, 'a' and 'b' should not be damaged. | 
 |         EXPECT_TRUE(GetRenderSurface(child_a_impl)->GetDamageRect().IsEmpty()); | 
 |         EXPECT_TRUE(GetRenderSurface(child_b_impl)->GetDamageRect().IsEmpty()); | 
 |         EXPECT_EQ(GetRenderSurface(child_c_impl)->GetDamageRect(), | 
 |                   gfx::Rect(0, 0, 15, 15)); | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |  | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |  private: | 
 |   Layer* root_; | 
 |   scoped_refptr<Layer> child_a_; | 
 |   scoped_refptr<Layer> child_b_; | 
 |   scoped_refptr<Layer> child_c_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestLayerListSurfaceDamage); | 
 |  | 
 | // When settings->enable_early_damage_check is true, verify that invalidate is | 
 | // not called when changes to a layer don't cause visible damage. | 
 | class LayerTreeHostTestNoDamageCausesNoInvalidate : public LayerTreeHostTest { | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     settings->using_synchronous_renderer_compositor = true; | 
 |     settings->enable_early_damage_check = true; | 
 |   } | 
 |  | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     scoped_refptr<Layer> root = Layer::Create(); | 
 |     layer_ = Layer::Create(); | 
 |     root->AddChild(layer_); | 
 |  | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(10, 10), 1.f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |     layer_tree_host()->SetRootLayer(root); | 
 |  | 
 |     // Translate the root layer past the viewport. | 
 |     gfx::Transform translation; | 
 |     translation.Translate(100, 100); | 
 |     layer_->SetTransform(translation); | 
 |  | 
 |     root->SetBounds(gfx::Size(50, 50)); | 
 |     layer_->SetBounds(gfx::Size(50, 50)); | 
 |  | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommit() override { | 
 |     // This does not damage the frame because the root layer is outside the | 
 |     // viewport. | 
 |     if (layer_tree_host()->SourceFrameNumber() == 2) | 
 |       layer_->SetOpacity(0.9f); | 
 |   } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     PostSetNeedsCommitToMainThread(); | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | 
 |     switch (impl->active_tree()->source_frame_number()) { | 
 |       // This gives us some assurance that invalidates happen before this call, | 
 |       // so invalidating on frame 2 will cause a failure before the test ends. | 
 |       case 0: | 
 |         EXPECT_TRUE(first_frame_invalidate_before_commit_); | 
 |         break; | 
 |       case 2: | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void DidInvalidateLayerTreeFrameSink(LayerTreeHostImpl* impl) override { | 
 |     int source_frame_number = impl->active_tree()->source_frame_number(); | 
 |     if (source_frame_number == 0) { | 
 |       // Be sure that invalidates happen before commits, so the below failure | 
 |       // works. | 
 |       first_frame_invalidate_before_commit_ = true; | 
 |     } else if (source_frame_number > 0) { | 
 |       // The first frame (frame number 0) has damage because it's the first | 
 |       // frame. All subsequent frames in this test are set up to have no damage. | 
 |       // The early damage check will prevent further invalidates without damage | 
 |       // after 2 consecutive invalidates without damage. So check there is no | 
 |       // more than 2. | 
 |       invalidate_without_damage_count_++; | 
 |       EXPECT_LT(invalidate_without_damage_count_, 2); | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   scoped_refptr<Layer> layer_; | 
 |   bool first_frame_invalidate_before_commit_ = false; | 
 |   int invalidate_without_damage_count_ = 0; | 
 | }; | 
 |  | 
 | // This behavior is specific to Android WebView, which only uses | 
 | // multi-threaded compositor. | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestNoDamageCausesNoInvalidate); | 
 |  | 
 | // When settings->enable_early_damage_check is true, verify that the early | 
 | // damage check is turned off after |settings->damaged_frame_limit| frames | 
 | // have consecutive damage. | 
 | // The test verifies that frames come in as follows: | 
 | // 0: visible damage as the root appears; invalidated | 
 | // 1: no visible damage; invalidate because all previous frames had damage | 
 | // 2: no visible damage; check early since frame 1 had no damage; no invalidate | 
 | // 3: visible damage | 
 | // ... (visible damage) | 
 | // 3 + damaged_frame_limit - 1: visible damage | 
 | // 3 + damaged_frame_limit: no visible damage, but invalidate because all of | 
 | // the last |damaged_frame_limit| frames had damage. | 
 | class LayerTreeHostTestEarlyDamageCheckStops : public LayerTreeHostTest { | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     settings->using_synchronous_renderer_compositor = true; | 
 |     settings->enable_early_damage_check = true; | 
 |     damaged_frame_limit_ = settings->damaged_frame_limit; | 
 |   } | 
 |  | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     root_ = Layer::Create(); | 
 |     child_ = Layer::Create(); | 
 |     root_->AddChild(child_); | 
 |  | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(100, 100), 1.f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_); | 
 |     root_->SetBounds(gfx::Size(50, 50)); | 
 |     child_->SetBounds(gfx::Size(50, 50)); | 
 |  | 
 |     // Translate the child layer past the viewport. | 
 |     gfx::Transform translation; | 
 |     translation.Translate(200, 200); | 
 |     child_->SetTransform(translation); | 
 |  | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void WillBeginMainFrame() override { | 
 |     int frame = layer_tree_host()->SourceFrameNumber(); | 
 |     // Change the child layer each frame. Since the child layer is translated | 
 |     // past the viewport, it should not cause damage, but webview will still | 
 |     // invalidate if the frame doesn't check for damage early. | 
 |     child_->SetOpacity(1.0 / (float)(frame + 1)); | 
 |  | 
 |     // For |damaged_frame_limit| consecutive frames, cause actual damage. | 
 |     if (frame >= 3 && frame < (damaged_frame_limit_ + 3)) { | 
 |       root_->SetOpacity(1.0 / (float)frame); | 
 |     } | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override { | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void DidInvalidateLayerTreeFrameSink(LayerTreeHostImpl* impl) override { | 
 |     int frame_number = impl->active_tree()->source_frame_number(); | 
 |     // Frames 0 and 1 invalidate because the early damage check is not enabled | 
 |     // during this setup. But frames 1 and 2 are not damaged, so the early | 
 |     // check should prevent frame 2 from invalidating. | 
 |     if (frame_number == 2) { | 
 |       ADD_FAILURE(); | 
 |     } else if (frame_number > 2) { | 
 |       invalidate_count_++; | 
 |     } | 
 |  | 
 |     // Frame number |damaged_frame_limit_ + 3| was not damaged, but it should | 
 |     // invalidate since the previous |damaged_frame_limit_| frames had damage | 
 |     // and should have turned off the early damage check. | 
 |     if (frame_number == damaged_frame_limit_ + 3) { | 
 |       EndTest(); | 
 |       return; | 
 |     } | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     // We should invalidate |damaged_frame_limit_| frames that had actual damage | 
 |     // and one additional frame after, since the early check is disabled. | 
 |     EXPECT_EQ(invalidate_count_, damaged_frame_limit_ + 1); | 
 |   } | 
 |  | 
 |  private: | 
 |   scoped_refptr<Layer> root_; | 
 |   scoped_refptr<Layer> child_; | 
 |   int invalidate_count_ = 0; | 
 |   int damaged_frame_limit_; | 
 | }; | 
 |  | 
 | // This behavior is specific to Android WebView, which only uses | 
 | // multi-threaded compositor. | 
 | // TODO(crbug.com/1043900): Disabled because test is flaky on Mac10.13. | 
 | // MULTI_THREAD_TEST_F(LayerTreeHostTestEarlyDamageCheckStops); | 
 |  | 
 | // When settings->enable_early_damage_check is true, verifies that PrepareTiles | 
 | // need not cause a draw when there is no visible damage. Here, a child layer is | 
 | // translated outside of the viewport. After two draws, the early damage check | 
 | // should prevent further draws, but preventing further draws should not prevent | 
 | // PrepareTiles. | 
 | class LayerTreeHostTestPrepareTilesWithoutDraw : public LayerTreeHostTest { | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     settings->using_synchronous_renderer_compositor = true; | 
 |     settings->enable_early_damage_check = true; | 
 |   } | 
 |  | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     child_layer_ = Layer::Create(); | 
 |     layer_tree_host()->root_layer()->AddChild(child_layer_); | 
 |  | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(10, 10), 1.f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |  | 
 |     layer_tree_host()->root_layer()->SetBounds(gfx::Size(50, 50)); | 
 |     child_layer_->SetBounds(gfx::Size(50, 50)); | 
 |  | 
 |     // Translate the child layer past the viewport. | 
 |     gfx::Transform translation; | 
 |     translation.Translate(100, 100); | 
 |     child_layer_->SetTransform(translation); | 
 |     child_layer_->SetBounds(gfx::Size(50, 50)); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommit() override { | 
 |     int frame_number = layer_tree_host()->SourceFrameNumber(); | 
 |     if (frame_number > 3) { | 
 |       EndTest(); | 
 |       return; | 
 |     } | 
 |  | 
 |     // Modify the child layer each frame. | 
 |     float new_opacity = 0.9f / (frame_number + 1); | 
 |     child_layer_->SetOpacity(new_opacity); | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void WillPrepareTilesOnThread(LayerTreeHostImpl* impl) override { | 
 |     if (impl->active_tree()->source_frame_number() >= 0) | 
 |       prepare_tiles_count_++; | 
 |  | 
 |     switch (impl->active_tree()->source_frame_number()) { | 
 |       case 0: | 
 |         EXPECT_EQ(1, prepare_tiles_count_); | 
 |         break; | 
 |       case 1: | 
 |         EXPECT_EQ(2, prepare_tiles_count_); | 
 |         break; | 
 |       case 2: | 
 |         EXPECT_EQ(3, prepare_tiles_count_); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* impl) override { | 
 |     draw_count_++; | 
 |  | 
 |     switch (impl->active_tree()->source_frame_number()) { | 
 |       case 0: | 
 |         // There is actual damage as the layers are set up. | 
 |         EXPECT_EQ(1, draw_count_); | 
 |         break; | 
 |       case 1: | 
 |         // There is no damage, but draw because the early damage check | 
 |         // didn't occur. | 
 |         EXPECT_EQ(2, draw_count_); | 
 |         break; | 
 |       default: | 
 |         // After the first two draws, the early damage check should kick | 
 |         // in and prevent further draws. | 
 |         ADD_FAILURE(); | 
 |     } | 
 |   } | 
 |  | 
 |   void AfterTest() override { EXPECT_EQ(2, draw_count_); } | 
 |  | 
 |  private: | 
 |   scoped_refptr<Layer> child_layer_; | 
 |   int prepare_tiles_count_ = 0; | 
 |   int draw_count_ = 0; | 
 | }; | 
 |  | 
 | // This behavior is specific to Android WebView, which only uses | 
 | // multi-threaded compositor. | 
 | // Flaky: https://crbug.com/947673 | 
 | // MULTI_THREAD_TEST_F(LayerTreeHostTestPrepareTilesWithoutDraw); | 
 |  | 
 | // Verify CanDraw() is false until first commit. | 
 | class LayerTreeHostTestCantDrawBeforeCommit : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void ReadyToCommitOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     EXPECT_FALSE(host_impl->CanDraw()); | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     EXPECT_TRUE(host_impl->CanDraw()); | 
 |     EndTest(); | 
 |   } | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestCantDrawBeforeCommit); | 
 |  | 
 | // Verify CanDraw() is false until first commit+activate. | 
 | class LayerTreeHostTestCantDrawBeforeCommitActivate : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     EXPECT_FALSE(host_impl->CanDraw()); | 
 |   } | 
 |  | 
 |   void WillActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     EXPECT_FALSE(host_impl->CanDraw()); | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     EXPECT_TRUE(host_impl->CanDraw()); | 
 |     EndTest(); | 
 |   } | 
 | }; | 
 |  | 
 | // Single thread mode commits directly to the active tree, so CanDraw() | 
 | // is true by the time WillActivateTreeOnThread is called. | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestCantDrawBeforeCommitActivate); | 
 |  | 
 | // Verify damage status of property trees is preserved after commit. | 
 | class LayerTreeHostTestPropertyTreesChangedSync : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     root_ = Layer::Create(); | 
 |     child_ = Layer::Create(); | 
 |     // This is to force the child to create a transform and effect node. | 
 |     child_->SetForceRenderSurfaceForTesting(true); | 
 |     root_->AddChild(child_); | 
 |     layer_tree_host()->SetRootLayer(root_); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   enum Animations { | 
 |     OPACITY, | 
 |     TRANSFORM, | 
 |     FILTER, | 
 |     END, | 
 |   }; | 
 |  | 
 |   void BeginTest() override { | 
 |     index_ = OPACITY; | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void DidCommit() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 2: | 
 |         // We rebuild property trees for this case to test the code path of | 
 |         // damage status synchronization when property trees are different. | 
 |         layer_tree_host()->property_trees()->needs_rebuild = true; | 
 |         break; | 
 |       default: | 
 |         EXPECT_FALSE(layer_tree_host()->property_trees()->needs_rebuild); | 
 |     } | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | 
 |     gfx::Transform transform; | 
 |     FilterOperations filters; | 
 |     LayerImpl* root = impl->active_tree()->root_layer(); | 
 |     switch (static_cast<Animations>(index_)) { | 
 |       case OPACITY: | 
 |         index_++; | 
 |         impl->active_tree()->ResetAllChangeTracking(); | 
 |         impl->active_tree()->SetOpacityMutated(root->element_id(), 0.5f); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case TRANSFORM: | 
 |         index_++; | 
 |         EXPECT_TRUE(impl->active_tree() | 
 |                         ->LayerById(root_->id()) | 
 |                         ->LayerPropertyChanged()); | 
 |         impl->active_tree()->ResetAllChangeTracking(); | 
 |         EXPECT_FALSE(impl->active_tree() | 
 |                          ->LayerById(root_->id()) | 
 |                          ->LayerPropertyChanged()); | 
 |         EXPECT_FALSE(impl->active_tree() | 
 |                          ->LayerById(child_->id()) | 
 |                          ->LayerPropertyChanged()); | 
 |         transform.Translate(10, 10); | 
 |         impl->active_tree()->SetTransformMutated(root->element_id(), transform); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case FILTER: | 
 |         index_++; | 
 |         EXPECT_TRUE(root->LayerPropertyChanged()); | 
 |         EXPECT_TRUE(impl->active_tree() | 
 |                         ->LayerById(child_->id()) | 
 |                         ->LayerPropertyChanged()); | 
 |         impl->active_tree()->ResetAllChangeTracking(); | 
 |         EXPECT_FALSE(root->LayerPropertyChanged()); | 
 |         EXPECT_FALSE(impl->active_tree() | 
 |                          ->LayerById(child_->id()) | 
 |                          ->LayerPropertyChanged()); | 
 |         filters.Append(FilterOperation::CreateOpacityFilter(0.5f)); | 
 |         impl->active_tree()->SetFilterMutated(root->element_id(), filters); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case END: | 
 |         EXPECT_TRUE(root->LayerPropertyChanged()); | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   int index_; | 
 |   scoped_refptr<Layer> root_; | 
 |   scoped_refptr<Layer> child_; | 
 | }; | 
 |  | 
 | SINGLE_THREAD_TEST_F(LayerTreeHostTestPropertyTreesChangedSync); | 
 |  | 
 | class LayerTreeHostTestAnimationOpacityMutatedNotUsingLayerLists | 
 |     : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override { | 
 |     Layer* root = layer_tree_host()->root_layer(); | 
 |     EXPECT_EQ(1.0f, root->opacity()); | 
 |     layer_tree_host()->SetElementOpacityMutated(root->element_id(), | 
 |                                                 ElementListType::ACTIVE, 0.3f); | 
 |     // When not using layer lists, opacity is stored on the layer. | 
 |     EXPECT_EQ(0.3f, root->opacity()); | 
 |     EndTest(); | 
 |   } | 
 | }; | 
 |  | 
 | SINGLE_THREAD_TEST_F( | 
 |     LayerTreeHostTestAnimationOpacityMutatedNotUsingLayerLists); | 
 |  | 
 | class LayerTreeHostTestAnimationOpacityMutatedUsingLayerLists | 
 |     : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestAnimationOpacityMutatedUsingLayerLists() { | 
 |     SetUseLayerLists(); | 
 |   } | 
 |  | 
 |  protected: | 
 |   void BeginTest() override { | 
 |     Layer* root = layer_tree_host()->root_layer(); | 
 |     EXPECT_EQ(1.0f, layer_tree_host() | 
 |                         ->property_trees() | 
 |                         ->effect_tree.FindNodeFromElementId(root->element_id()) | 
 |                         ->opacity); | 
 |  | 
 |     layer_tree_host()->SetElementOpacityMutated(root->element_id(), | 
 |                                                 ElementListType::ACTIVE, 0.3f); | 
 |  | 
 |     // The opacity should have been set directly on the effect node instead. | 
 |     EXPECT_EQ(0.3f, layer_tree_host() | 
 |                         ->property_trees() | 
 |                         ->effect_tree.FindNodeFromElementId(root->element_id()) | 
 |                         ->opacity); | 
 |     EndTest(); | 
 |   } | 
 | }; | 
 |  | 
 | SINGLE_THREAD_TEST_F(LayerTreeHostTestAnimationOpacityMutatedUsingLayerLists); | 
 |  | 
 | class LayerTreeHostTestAnimationTransformMutatedNotUsingLayerLists | 
 |     : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     root_ = Layer::Create(); | 
 |     child_ = Layer::Create(); | 
 |     root_->AddChild(child_); | 
 |     layer_tree_host()->SetRootLayer(root_); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void BeginTest() override { | 
 |     EXPECT_EQ(gfx::Transform(), child_->transform()); | 
 |     gfx::Transform expected_transform; | 
 |     expected_transform.Translate(42, 42); | 
 |     layer_tree_host()->SetElementTransformMutated( | 
 |         child_->element_id(), ElementListType::ACTIVE, expected_transform); | 
 |     // When not using layer lists, transform is stored on the layer. | 
 |     EXPECT_EQ(expected_transform, child_->transform()); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |  private: | 
 |   scoped_refptr<Layer> root_; | 
 |   scoped_refptr<Layer> child_; | 
 | }; | 
 |  | 
 | SINGLE_THREAD_TEST_F( | 
 |     LayerTreeHostTestAnimationTransformMutatedNotUsingLayerLists); | 
 |  | 
 | class LayerTreeHostTestAnimationTransformMutatedUsingLayerLists | 
 |     : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestAnimationTransformMutatedUsingLayerLists() { | 
 |     SetUseLayerLists(); | 
 |   } | 
 |  | 
 |  protected: | 
 |   void BeginTest() override { | 
 |     Layer* root = layer_tree_host()->root_layer(); | 
 |     EXPECT_EQ(gfx::Transform(), | 
 |               layer_tree_host() | 
 |                   ->property_trees() | 
 |                   ->transform_tree.FindNodeFromElementId(root->element_id()) | 
 |                   ->local); | 
 |  | 
 |     gfx::Transform expected_transform; | 
 |     expected_transform.Translate(42, 42); | 
 |     layer_tree_host()->SetElementTransformMutated( | 
 |         root->element_id(), ElementListType::ACTIVE, expected_transform); | 
 |  | 
 |     // The transform should have been set directly on the transform node | 
 |     // instead. | 
 |     EXPECT_EQ(expected_transform, | 
 |               layer_tree_host() | 
 |                   ->property_trees() | 
 |                   ->transform_tree.FindNodeFromElementId(root->element_id()) | 
 |                   ->local); | 
 |     EndTest(); | 
 |   } | 
 | }; | 
 |  | 
 | SINGLE_THREAD_TEST_F(LayerTreeHostTestAnimationTransformMutatedUsingLayerLists); | 
 |  | 
 | class LayerTreeHostTestAnimationFilterMutatedNotUsingLayerLists | 
 |     : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override { | 
 |     Layer* root = layer_tree_host()->root_layer(); | 
 |     FilterOperations filters; | 
 |     EXPECT_EQ(FilterOperations(), root->filters()); | 
 |     filters.Append(FilterOperation::CreateOpacityFilter(0.5f)); | 
 |     layer_tree_host()->SetElementFilterMutated( | 
 |         root->element_id(), ElementListType::ACTIVE, filters); | 
 |     // When not using layer lists, filters are just stored directly on the | 
 |     // layer. | 
 |     EXPECT_EQ(filters, root->filters()); | 
 |     EndTest(); | 
 |   } | 
 | }; | 
 |  | 
 | SINGLE_THREAD_TEST_F(LayerTreeHostTestAnimationFilterMutatedNotUsingLayerLists); | 
 |  | 
 | class LayerTreeHostTestAnimationFilterMutatedUsingLayerLists | 
 |     : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestAnimationFilterMutatedUsingLayerLists() { | 
 |     SetUseLayerLists(); | 
 |   } | 
 |  | 
 |  protected: | 
 |   void BeginTest() override { | 
 |     Layer* root = layer_tree_host()->root_layer(); | 
 |     EXPECT_EQ(FilterOperations(), | 
 |               layer_tree_host() | 
 |                   ->property_trees() | 
 |                   ->effect_tree.FindNodeFromElementId(root->element_id()) | 
 |                   ->filters); | 
 |  | 
 |     FilterOperations filters; | 
 |     filters.Append(FilterOperation::CreateOpacityFilter(0.5f)); | 
 |     layer_tree_host()->SetElementFilterMutated( | 
 |         root->element_id(), ElementListType::ACTIVE, filters); | 
 |  | 
 |     // The filter should have been set directly on the effect node instead. | 
 |     EXPECT_EQ(filters, | 
 |               layer_tree_host() | 
 |                   ->property_trees() | 
 |                   ->effect_tree.FindNodeFromElementId(root->element_id()) | 
 |                   ->filters); | 
 |     EndTest(); | 
 |   } | 
 | }; | 
 |  | 
 | SINGLE_THREAD_TEST_F(LayerTreeHostTestAnimationFilterMutatedUsingLayerLists); | 
 |  | 
 | class LayerTreeHostTestEffectTreeSync : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     root_ = Layer::Create(); | 
 |     layer_tree_host()->SetRootLayer(root_); | 
 |     blur_filter_.Append(FilterOperation::CreateBlurFilter(0.5f)); | 
 |     brightness_filter_.Append(FilterOperation::CreateBrightnessFilter(0.25f)); | 
 |     sepia_filter_.Append(FilterOperation::CreateSepiaFilter(0.75f)); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommit() override { | 
 |     EffectTree& effect_tree = layer_tree_host()->property_trees()->effect_tree; | 
 |     EffectNode* node = effect_tree.Node(root_->effect_tree_index()); | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         node->opacity = 0.5f; | 
 |         node->is_currently_animating_opacity = true; | 
 |         break; | 
 |       case 2: | 
 |         node->is_currently_animating_opacity = true; | 
 |         break; | 
 |       case 3: | 
 |         node->is_currently_animating_opacity = false; | 
 |         break; | 
 |       case 4: | 
 |         node->opacity = 0.25f; | 
 |         node->is_currently_animating_opacity = true; | 
 |         break; | 
 |       case 5: | 
 |         node->filters = blur_filter_; | 
 |         node->is_currently_animating_filter = true; | 
 |         break; | 
 |       case 6: | 
 |         node->is_currently_animating_filter = true; | 
 |         break; | 
 |       case 7: | 
 |         node->is_currently_animating_filter = false; | 
 |         break; | 
 |       case 8: | 
 |         node->filters = sepia_filter_; | 
 |         node->is_currently_animating_filter = true; | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | 
 |     EffectTree& effect_tree = impl->sync_tree()->property_trees()->effect_tree; | 
 |     LayerImpl* root = impl->sync_tree()->root_layer(); | 
 |     EffectNode* node = effect_tree.Node(root->effect_tree_index()); | 
 |     switch (impl->sync_tree()->source_frame_number()) { | 
 |       case 0: | 
 |         impl->sync_tree()->SetOpacityMutated(root->element_id(), 0.75f); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 1: | 
 |         EXPECT_EQ(node->opacity, 0.75f); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 2: | 
 |         EXPECT_EQ(node->opacity, 0.75f); | 
 |         impl->sync_tree()->SetOpacityMutated(root->element_id(), 0.75f); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 3: | 
 |         EXPECT_EQ(node->opacity, 0.5f); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 4: | 
 |         EXPECT_EQ(node->opacity, 0.25f); | 
 |         impl->sync_tree()->SetFilterMutated(root->element_id(), | 
 |                                             brightness_filter_); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 5: | 
 |         EXPECT_EQ(node->filters, brightness_filter_); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 6: | 
 |         EXPECT_EQ(node->filters, brightness_filter_); | 
 |         impl->sync_tree()->SetFilterMutated(root->element_id(), | 
 |                                             brightness_filter_); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 7: | 
 |         EXPECT_EQ(node->filters, blur_filter_); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 8: | 
 |         EXPECT_EQ(node->filters, sepia_filter_); | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   scoped_refptr<Layer> root_; | 
 |   FilterOperations blur_filter_; | 
 |   FilterOperations brightness_filter_; | 
 |   FilterOperations sepia_filter_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestEffectTreeSync); | 
 |  | 
 | class LayerTreeHostTestTransformTreeSync : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     scoped_refptr<Layer> root = Layer::Create(); | 
 |     layer_ = Layer::Create(); | 
 |     // Force a transform node for the layer. | 
 |     gfx::Transform rotate5; | 
 |     rotate5.Rotate(5.f); | 
 |     layer_->SetTransform(rotate5); | 
 |     root->AddChild(layer_); | 
 |     layer_tree_host()->SetRootLayer(root); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommit() override { | 
 |     TransformTree& transform_tree = | 
 |         layer_tree_host()->property_trees()->transform_tree; | 
 |     TransformNode* node = transform_tree.Node(layer_->transform_tree_index()); | 
 |     gfx::Transform rotate10; | 
 |     rotate10.Rotate(10.f); | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         node->local = rotate10; | 
 |         node->is_currently_animating = true; | 
 |         break; | 
 |       case 2: | 
 |         node->is_currently_animating = true; | 
 |         break; | 
 |       case 3: | 
 |         node->is_currently_animating = false; | 
 |         break; | 
 |       case 4: | 
 |         node->local = gfx::Transform(); | 
 |         node->is_currently_animating = true; | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | 
 |     TransformTree& transform_tree = | 
 |         impl->sync_tree()->property_trees()->transform_tree; | 
 |     const LayerImpl* layer = impl->sync_tree()->LayerById(layer_->id()); | 
 |     const TransformNode* node = | 
 |         transform_tree.Node(layer->transform_tree_index()); | 
 |     gfx::Transform rotate10; | 
 |     rotate10.Rotate(10.f); | 
 |     gfx::Transform rotate20; | 
 |     rotate20.Rotate(20.f); | 
 |     switch (impl->sync_tree()->source_frame_number()) { | 
 |       case 0: | 
 |         impl->sync_tree()->SetTransformMutated(layer->element_id(), rotate20); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 1: | 
 |         EXPECT_EQ(node->local, rotate20); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 2: | 
 |         EXPECT_EQ(node->local, rotate20); | 
 |         impl->sync_tree()->SetTransformMutated(layer->element_id(), rotate20); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 3: | 
 |         EXPECT_EQ(node->local, rotate10); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 4: | 
 |         EXPECT_EQ(node->local, gfx::Transform()); | 
 |         EndTest(); | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   scoped_refptr<Layer> layer_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestTransformTreeSync); | 
 |  | 
 | // Verify damage status is updated even when the transform tree doesn't need | 
 | // to be updated at draw time. | 
 | class LayerTreeHostTestTransformTreeDamageIsUpdated : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     root_ = Layer::Create(); | 
 |     child_ = Layer::Create(); | 
 |     grand_child_ = Layer::Create(); | 
 |  | 
 |     root_->SetBounds(gfx::Size(50, 50)); | 
 |  | 
 |     // Make sure child is registered for animation. | 
 |     child_->SetElementId(ElementId(2)); | 
 |  | 
 |     // Make sure child and grand_child have transform nodes. | 
 |     gfx::Transform rotation; | 
 |     rotation.RotateAboutZAxis(45.0); | 
 |     child_->SetTransform(rotation); | 
 |     grand_child_->SetTransform(rotation); | 
 |  | 
 |     root_->AddChild(child_); | 
 |     child_->AddChild(grand_child_); | 
 |     layer_tree_host()->SetRootLayer(root_); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommit() override { | 
 |     if (layer_tree_host()->SourceFrameNumber() == 1) { | 
 |       gfx::Transform scale; | 
 |       scale.Scale(2.0, 2.0); | 
 |       layer_tree_host()->SetElementTransformMutated( | 
 |           child_->element_id(), ElementListType::ACTIVE, scale); | 
 |     } | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | 
 |     if (impl->sync_tree()->source_frame_number() == 0) | 
 |       PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     if (impl->active_tree()->source_frame_number() == 1) { | 
 |       EXPECT_FALSE( | 
 |           impl->active_tree()->LayerById(root_->id())->LayerPropertyChanged()); | 
 |       EXPECT_TRUE( | 
 |           impl->active_tree()->LayerById(child_->id())->LayerPropertyChanged()); | 
 |       EXPECT_TRUE(impl->active_tree() | 
 |                       ->LayerById(grand_child_->id()) | 
 |                       ->LayerPropertyChanged()); | 
 |       EndTest(); | 
 |     } | 
 |  | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* impl) override { | 
 |     if (impl->active_tree()->source_frame_number() == 0) { | 
 |       gfx::Transform scale; | 
 |       scale.Scale(2.0, 2.0); | 
 |       impl->active_tree()->SetTransformMutated(child_->element_id(), scale); | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   scoped_refptr<Layer> root_; | 
 |   scoped_refptr<Layer> child_; | 
 |   scoped_refptr<Layer> grand_child_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestTransformTreeDamageIsUpdated); | 
 |  | 
 | class UpdateCountingLayer : public PictureLayer { | 
 |  public: | 
 |   explicit UpdateCountingLayer(ContentLayerClient* client) | 
 |       : PictureLayer(client) {} | 
 |  | 
 |   bool Update() override { | 
 |     update_count_++; | 
 |     return false; | 
 |   } | 
 |  | 
 |   int update_count() const { return update_count_; } | 
 |  | 
 |  private: | 
 |   ~UpdateCountingLayer() override = default; | 
 |  | 
 |   int update_count_ = 0; | 
 | }; | 
 |  | 
 | // Test that when mask layers switches layers, this gets pushed onto impl. | 
 | // Also test that mask layer is in the layer update list even if its owning | 
 | // layer isn't. | 
 | class LayerTreeHostTestSwitchMaskLayer : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     scoped_refptr<Layer> root = Layer::Create(); | 
 |     root->SetBounds(gfx::Size(10, 10)); | 
 |     // child_layer_ is not drawable. | 
 |     child_layer_ = base::MakeRefCounted<UpdateCountingLayer>(&client_); | 
 |     child_layer_->SetBounds(gfx::Size(10, 10)); | 
 |     mask_layer_ = base::MakeRefCounted<UpdateCountingLayer>(&client_); | 
 |     mask_layer_->SetBounds(gfx::Size(10, 10)); | 
 |     mask_layer_->SetIsDrawable(true); | 
 |     child_layer_->SetMaskLayer(mask_layer_); | 
 |     root->AddChild(child_layer_); | 
 |     layer_tree_host()->SetRootLayer(root); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void BeginTest() override { | 
 |     index_ = 0; | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void DidCommit() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         // Root and mask layer should have the same source frame number as they | 
 |         // will be in the layer update list but the child is not as it doesn't | 
 |         // draw content. | 
 |         EXPECT_EQ(mask_layer_->update_count(), 1); | 
 |         EXPECT_EQ(child_layer_->update_count(), 0); | 
 |  | 
 |         layer_tree_host()->root_layer()->RemoveAllChildren(); | 
 |         layer_tree_host()->root_layer()->SetMaskLayer(mask_layer_); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | 
 |     auto* mask_surface = | 
 |         GetRenderSurface(impl->sync_tree()->LayerById(mask_layer_->id())); | 
 |     auto* root_surface = GetRenderSurface(impl->sync_tree()->root_layer()); | 
 |     ASSERT_TRUE(mask_surface); | 
 |     switch (index_) { | 
 |       case 0: { | 
 |         index_++; | 
 |         auto* child_surface = | 
 |             GetRenderSurface(impl->sync_tree()->LayerById(child_layer_->id())); | 
 |         EXPECT_EQ(child_surface, mask_surface->render_target()); | 
 |         EXPECT_NE(child_surface, root_surface); | 
 |         break; | 
 |       } | 
 |       case 1: | 
 |         EXPECT_EQ(mask_surface->render_target(), root_surface); | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   FakeContentLayerClient client_; | 
 |   scoped_refptr<UpdateCountingLayer> mask_layer_; | 
 |   scoped_refptr<UpdateCountingLayer> child_layer_; | 
 |   int index_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSwitchMaskLayer); | 
 |  | 
 | // 1 setNeedsRedraw after the first commit has completed should lead to 1 | 
 | // additional draw. | 
 | class LayerTreeHostTestSetNeedsRedraw : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestSetNeedsRedraw() : num_commits_(0), num_draws_(0) {} | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* impl) override { | 
 |     EXPECT_EQ(0, impl->active_tree()->source_frame_number()); | 
 |     if (!num_draws_) { | 
 |       // Redraw again to verify that the second redraw doesn't commit. | 
 |       PostSetNeedsRedrawToMainThread(); | 
 |     } else { | 
 |       EndTest(); | 
 |     } | 
 |     num_draws_++; | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | 
 |     EXPECT_EQ(0, num_draws_); | 
 |     num_commits_++; | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     EXPECT_GE(2, num_draws_); | 
 |     EXPECT_EQ(1, num_commits_); | 
 |   } | 
 |  | 
 |  private: | 
 |   int num_commits_; | 
 |   int num_draws_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestSetNeedsRedraw); | 
 |  | 
 | // After setNeedsRedrawRect(invalid_rect) the final damage_rect | 
 | // must contain invalid_rect. | 
 | class LayerTreeHostTestSetNeedsRedrawRect : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestSetNeedsRedrawRect() | 
 |       : num_draws_(0), bounds_(50, 50), invalid_rect_(10, 10, 20, 20) {} | 
 |  | 
 |   void BeginTest() override { | 
 |     root_layer_ = FakePictureLayer::Create(&client_); | 
 |     root_layer_->SetIsDrawable(true); | 
 |     root_layer_->SetBounds(bounds_); | 
 |     layer_tree_host()->SetRootLayer(root_layer_); | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(bounds_), 1.f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |     PostSetNeedsCommitToMainThread(); | 
 |     client_.set_bounds(root_layer_->bounds()); | 
 |   } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     EXPECT_EQ(DRAW_SUCCESS, draw_result); | 
 |  | 
 |     gfx::Rect root_damage_rect; | 
 |     if (!frame_data->render_passes.empty()) | 
 |       root_damage_rect = frame_data->render_passes.back()->damage_rect; | 
 |  | 
 |     if (!num_draws_) { | 
 |       // If this is the first frame, expect full frame damage. | 
 |       EXPECT_EQ(root_damage_rect, gfx::Rect(bounds_)); | 
 |     } else { | 
 |       // Check that invalid_rect_ is indeed repainted. | 
 |       EXPECT_TRUE(root_damage_rect.Contains(invalid_rect_)); | 
 |     } | 
 |  | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* impl) override { | 
 |     if (!num_draws_) { | 
 |       PostSetNeedsRedrawRectToMainThread(invalid_rect_); | 
 |     } else { | 
 |       EndTest(); | 
 |     } | 
 |     num_draws_++; | 
 |   } | 
 |  | 
 |   void AfterTest() override { EXPECT_EQ(2, num_draws_); } | 
 |  | 
 |  private: | 
 |   int num_draws_; | 
 |   const gfx::Size bounds_; | 
 |   const gfx::Rect invalid_rect_; | 
 |   FakeContentLayerClient client_; | 
 |   scoped_refptr<FakePictureLayer> root_layer_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSetNeedsRedrawRect); | 
 |  | 
 | // Ensure the texture size of the pending and active trees are identical when a | 
 | // layer is not in the viewport and a resize happens on the viewport | 
 | class LayerTreeHostTestGpuRasterDeviceSizeChanged : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestGpuRasterDeviceSizeChanged() | 
 |       : num_draws_(0), bounds_(500, 64), invalid_rect_(10, 10, 20, 20) {} | 
 |  | 
 |   void BeginTest() override { | 
 |     client_.set_fill_with_nonsolid_color(true); | 
 |     scoped_refptr<Layer> root = Layer::Create(); | 
 |     layer_ = FakePictureLayer::Create(&client_); | 
 |     root->AddChild(layer_); | 
 |     layer_->SetIsDrawable(true); | 
 |     gfx::Transform transform; | 
 |     // Translate the layer out of the viewport to force it to not update its | 
 |     // tile size via PushProperties. | 
 |     transform.Translate(10000.0, 10000.0); | 
 |     layer_->SetTransform(transform); | 
 |     root->SetBounds(bounds_); | 
 |     layer_->SetBounds(bounds_); | 
 |     layer_tree_host()->SetRootLayer(root); | 
 |     layer_tree_host()->SetViewportRectAndScale( | 
 |         gfx::Rect(bounds_), 1.f, GetCurrentLocalSurfaceIdAllocation()); | 
 |  | 
 |     PostSetNeedsCommitToMainThread(); | 
 |     client_.set_bounds(layer_->bounds()); | 
 |   } | 
 |  | 
 |   void SetUpUnboundContextProviders( | 
 |       viz::TestContextProvider* context_provider, | 
 |       viz::TestContextProvider* worker_provider) override { | 
 |     context_provider->UnboundTestContextGL()->set_gpu_rasterization(true); | 
 |     worker_provider->UnboundTestContextGL()->set_gpu_rasterization(true); | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     if (num_draws_ == 2) { | 
 |       auto* pending_tree = host_impl->pending_tree(); | 
 |       auto* pending_layer_impl = static_cast<FakePictureLayerImpl*>( | 
 |           pending_tree->LayerById(layer_->id())); | 
 |       EXPECT_NE(pending_layer_impl, nullptr); | 
 |  | 
 |       auto* active_tree = host_impl->pending_tree(); | 
 |       auto* active_layer_impl = static_cast<FakePictureLayerImpl*>( | 
 |           active_tree->LayerById(layer_->id())); | 
 |       EXPECT_NE(pending_layer_impl, nullptr); | 
 |  | 
 |       auto* active_tiling_set = active_layer_impl->picture_layer_tiling_set(); | 
 |       auto* active_tiling = active_tiling_set->tiling_at(0); | 
 |       auto* pending_tiling_set = pending_layer_impl->picture_layer_tiling_set(); | 
 |       auto* pending_tiling = pending_tiling_set->tiling_at(0); | 
 |       EXPECT_EQ( | 
 |           pending_tiling->TilingDataForTesting().max_texture_size().width(), | 
 |           active_tiling->TilingDataForTesting().max_texture_size().width()); | 
 |     } | 
 |   } | 
 |  | 
 |   void DidCommitAndDrawFrame() override { | 
 |     // On the second commit, resize the viewport. | 
 |     if (num_draws_ == 1) { | 
 |       GenerateNewLocalSurfaceId(); | 
 |       layer_tree_host()->SetViewportRectAndScale( | 
 |           gfx::Rect(400, 64), 1.f, GetCurrentLocalSurfaceIdAllocation()); | 
 |     } | 
 |     if (num_draws_ < 2) { | 
 |       layer_tree_host()->SetNeedsRedrawRect(invalid_rect_); | 
 |       layer_tree_host()->SetNeedsCommit(); | 
 |       num_draws_++; | 
 |     } else { | 
 |       EndTest(); | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   int num_draws_; | 
 |   const gfx::Size bounds_; | 
 |   const gfx::Rect invalid_rect_; | 
 |   FakeContentLayerClient client_; | 
 |   scoped_refptr<FakePictureLayer> layer_; | 
 | }; | 
 |  | 
 | // As there's no pending tree in single-threaded case, this test should run | 
 | // only for multi-threaded case. | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterDeviceSizeChanged); | 
 |  | 
 | class LayerTreeHostTestNoExtraCommitFromInvalidate : public LayerTreeHostTest { | 
 |  public: | 
 |   void SetupTree() override { | 
 |     root_layer_ = Layer::Create(); | 
 |     root_layer_->SetBounds(gfx::Size(10, 20)); | 
 |  | 
 |     scaled_layer_ = FakePictureLayer::Create(&client_); | 
 |     scaled_layer_->SetBounds(gfx::Size(1, 1)); | 
 |     root_layer_->AddChild(scaled_layer_); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_layer_); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     client_.set_bounds(root_layer_->bounds()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     if (host_impl->active_tree()->source_frame_number() == 1) | 
 |       EndTest(); | 
 |   } | 
 |  | 
 |   void DidCommit() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         // SetBounds grows the layer and exposes new content. | 
 |         scaled_layer_->SetBounds(gfx::Size(4, 4)); | 
 |         break; | 
 |       default: | 
 |         // No extra commits. | 
 |         EXPECT_EQ(2, layer_tree_host()->SourceFrameNumber()); | 
 |     } | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     EXPECT_EQ(gfx::Size(4, 4).ToString(), scaled_layer_->bounds().ToString()); | 
 |   } | 
 |  | 
 |  private: | 
 |   FakeContentLayerClient client_; | 
 |   scoped_refptr<Layer> root_layer_; | 
 |   scoped_refptr<Layer> scaled_layer_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestNoExtraCommitFromInvalidate); | 
 |  | 
 | class LayerTreeHostTestNoExtraCommitFromScrollbarInvalidate | 
 |     : public LayerTreeHostTest { | 
 |  public: | 
 |   void SetupTree() override { | 
 |     root_layer_ = Layer::Create(); | 
 |     root_layer_->SetBounds(gfx::Size(10, 20)); | 
 |  | 
 |     bool paint_scrollbar = true; | 
 |     bool has_thumb = false; | 
 |     scrollbar_ = FakePaintedScrollbarLayer::Create(paint_scrollbar, has_thumb, | 
 |                                                    root_layer_->element_id()); | 
 |     scrollbar_->SetPosition(gfx::PointF(0.f, 10.f)); | 
 |     scrollbar_->SetBounds(gfx::Size(10, 10)); | 
 |  | 
 |     root_layer_->AddChild(scrollbar_); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_layer_); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     client_.set_bounds(root_layer_->bounds()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     if (host_impl->active_tree()->source_frame_number() == 1) | 
 |       EndTest(); | 
 |   } | 
 |  | 
 |   void DidCommit() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         // Changing the device scale factor causes a commit. It also changes | 
 |         // the content bounds of |scrollbar_|, which should not generate | 
 |         // a second commit as a result. | 
 |         layer_tree_host()->SetViewportRectAndScale( | 
 |             layer_tree_host()->device_viewport_rect(), 4.f, | 
 |             layer_tree_host()->local_surface_id_allocation_from_parent()); | 
 |         break; | 
 |       default: | 
 |         // No extra commits. | 
 |         EXPECT_EQ(2, layer_tree_host()->SourceFrameNumber()); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   FakeContentLayerClient client_; | 
 |   scoped_refptr<Layer> root_layer_; | 
 |   scoped_refptr<FakePaintedScrollbarLayer> scrollbar_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F( | 
 |     LayerTreeHostTestNoExtraCommitFromScrollbarInvalidate); | 
 |  | 
 | class LayerTreeHostTestDeviceScaleFactorChange : public LayerTreeHostTest { | 
 |  public: | 
 |   void SetupTree() override { | 
 |     root_layer_ = Layer::Create(); | 
 |     root_layer_->SetBounds(gfx::Size(10, 20)); | 
 |  | 
 |     child_layer_ = FakePictureLayer::Create(&client_); | 
 |     child_layer_->SetBounds(gfx::Size(10, 10)); | 
 |     root_layer_->AddChild(child_layer_); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_layer_); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     client_.set_bounds(root_layer_->bounds()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommit() override { | 
 |     if (layer_tree_host()->SourceFrameNumber() == 1) { | 
 |       layer_tree_host()->SetViewportRectAndScale( | 
 |           layer_tree_host()->device_viewport_rect(), 4.f, | 
 |           layer_tree_host()->local_surface_id_allocation_from_parent()); | 
 |     } | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     if (host_impl->sync_tree()->source_frame_number() == 1) { | 
 |       EXPECT_EQ(4.f, host_impl->sync_tree()->device_scale_factor()); | 
 |       if (host_impl->pending_tree()) { | 
 |         // The active tree's device scale factor shouldn't change until | 
 |         // activation. | 
 |         EXPECT_EQ(1.f, host_impl->active_tree()->device_scale_factor()); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     if (host_impl->active_tree()->source_frame_number() == 0) { | 
 |       EXPECT_EQ(1.f, host_impl->active_tree()->device_scale_factor()); | 
 |     } else { | 
 |       gfx::Rect root_damage_rect = | 
 |           frame_data->render_passes.back()->damage_rect; | 
 |       EXPECT_EQ(gfx::Rect(host_impl->active_tree()->root_layer()->bounds()), | 
 |                 root_damage_rect); | 
 |       EXPECT_EQ(4.f, host_impl->active_tree()->device_scale_factor()); | 
 |       EndTest(); | 
 |     } | 
 |  | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |  private: | 
 |   FakeContentLayerClient client_; | 
 |   scoped_refptr<Layer> root_layer_; | 
 |   scoped_refptr<Layer> child_layer_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestDeviceScaleFactorChange); | 
 |  | 
 | class LayerTreeHostTestRasterColorSpaceChange : public LayerTreeHostTest { | 
 |  public: | 
 |   void SetupTree() override { | 
 |     space1_ = gfx::ColorSpace::CreateXYZD50(); | 
 |     space2_ = gfx::ColorSpace::CreateSRGB(); | 
 |  | 
 |     root_layer_ = Layer::Create(); | 
 |     root_layer_->SetBounds(gfx::Size(10, 20)); | 
 |  | 
 |     child_layer_ = FakePictureLayer::Create(&client_); | 
 |     child_layer_->SetBounds(gfx::Size(10, 10)); | 
 |     root_layer_->AddChild(child_layer_); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_layer_); | 
 |     layer_tree_host()->SetRasterColorSpace(space1_); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     client_.set_bounds(root_layer_->bounds()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     EXPECT_EQ(DRAW_SUCCESS, draw_result); | 
 |  | 
 |     int source_frame = host_impl->active_tree()->source_frame_number(); | 
 |     switch (source_frame) { | 
 |       case 0: | 
 |         // The first frame will have full damage, and should be in the initial | 
 |         // color space. | 
 |         EXPECT_FALSE(frame_data->has_no_damage); | 
 |         EXPECT_TRUE(space1_ == host_impl->active_tree()->raster_color_space()); | 
 |         break; | 
 |       case 1: | 
 |         // Empty commit. | 
 |         EXPECT_TRUE(frame_data->has_no_damage); | 
 |         EXPECT_TRUE(space1_ == host_impl->active_tree()->raster_color_space()); | 
 |         break; | 
 |       case 2: | 
 |         // The change from space1 to space2 should cause full damage. | 
 |         EXPECT_FALSE(frame_data->has_no_damage); | 
 |         EXPECT_TRUE(space2_ == host_impl->active_tree()->raster_color_space()); | 
 |         break; | 
 |       case 3: | 
 |         // Empty commit with the color space set to space2 redundantly. | 
 |         EXPECT_TRUE(frame_data->has_no_damage); | 
 |         EXPECT_TRUE(space2_ == host_impl->active_tree()->raster_color_space()); | 
 |         break; | 
 |       case 4: | 
 |         // The change from space2 to space1 should cause full damage. | 
 |         EXPECT_FALSE(frame_data->has_no_damage); | 
 |         EXPECT_TRUE(space1_ == host_impl->active_tree()->raster_color_space()); | 
 |         break; | 
 |       case 5: | 
 |         // Empty commit. | 
 |         EXPECT_TRUE(frame_data->has_no_damage); | 
 |         EXPECT_TRUE(space1_ == host_impl->active_tree()->raster_color_space()); | 
 |         EndTest(); | 
 |         break; | 
 |       default: | 
 |         NOTREACHED(); | 
 |         break; | 
 |     } | 
 |  | 
 |     if (!frame_data->has_no_damage) { | 
 |       gfx::Rect root_damage_rect = | 
 |           frame_data->render_passes.back()->damage_rect; | 
 |       EXPECT_EQ(gfx::Rect(host_impl->active_tree()->root_layer()->bounds()), | 
 |                 root_damage_rect); | 
 |     } | 
 |  | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |   void DidCommit() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 2: | 
 |         EXPECT_TRUE(child_layer_->update_rect().IsEmpty()); | 
 |         layer_tree_host()->SetRasterColorSpace(space2_); | 
 |         EXPECT_FALSE(child_layer_->update_rect().IsEmpty()); | 
 |         break; | 
 |       case 3: | 
 |         // The redundant SetRasterColorSpace should cause no commit and no | 
 |         // damage. Force a commit for the test to continue. | 
 |         layer_tree_host()->SetRasterColorSpace(space2_); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         EXPECT_TRUE(child_layer_->update_rect().IsEmpty()); | 
 |         break; | 
 |       case 4: | 
 |         EXPECT_TRUE(child_layer_->update_rect().IsEmpty()); | 
 |         layer_tree_host()->SetRasterColorSpace(space1_); | 
 |         EXPECT_FALSE(child_layer_->update_rect().IsEmpty()); | 
 |         break; | 
 |       case 5: | 
 |         EXPECT_TRUE(child_layer_->update_rect().IsEmpty()); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 6: | 
 |         break; | 
 |       default: | 
 |         NOTREACHED(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   gfx::ColorSpace space1_; | 
 |   gfx::ColorSpace space2_; | 
 |   FakeContentLayerClient client_; | 
 |   scoped_refptr<Layer> root_layer_; | 
 |   scoped_refptr<Layer> child_layer_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestRasterColorSpaceChange); | 
 |  | 
 | class LayerTreeHostTestSetNeedsCommitWithForcedRedraw | 
 |     : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestSetNeedsCommitWithForcedRedraw() | 
 |       : num_draws_(0), bounds_(50, 50), invalid_rect_(10, 10, 20, 20) {} | 
 |  | 
 |   void BeginTest() override { | 
 |     root_layer_ = FakePictureLayer::Create(&client_); | 
 |     root_layer_->SetIsDrawable(true); | 
 |     root_layer_->SetBounds(bounds_); | 
 |     layer_tree_host()->SetRootLayer(root_layer_); | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(bounds_), 1.f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |     PostSetNeedsCommitToMainThread(); | 
 |     client_.set_bounds(root_layer_->bounds()); | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     if (num_draws_ == 3) { | 
 |       host_impl->SetViewportDamage(invalid_rect_); | 
 |       host_impl->SetNeedsRedraw(); | 
 |     } | 
 |   } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     EXPECT_EQ(DRAW_SUCCESS, draw_result); | 
 |  | 
 |     gfx::Rect root_damage_rect; | 
 |     if (!frame_data->render_passes.empty()) | 
 |       root_damage_rect = frame_data->render_passes.back()->damage_rect; | 
 |  | 
 |     switch (num_draws_) { | 
 |       case 0: | 
 |         EXPECT_EQ(gfx::Rect(bounds_), root_damage_rect); | 
 |         break; | 
 |       case 1: | 
 |       case 2: | 
 |         EXPECT_EQ(gfx::Rect(), root_damage_rect); | 
 |         break; | 
 |       case 3: | 
 |         EXPECT_EQ(invalid_rect_, root_damage_rect); | 
 |         break; | 
 |       case 4: | 
 |         EXPECT_EQ(gfx::Rect(bounds_), root_damage_rect); | 
 |         break; | 
 |       default: | 
 |         NOTREACHED(); | 
 |     } | 
 |  | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     switch (num_draws_) { | 
 |       case 0: | 
 |       case 1: | 
 |         // Cycle through a couple of empty commits to ensure we're observing the | 
 |         // right behavior | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 2: | 
 |         // Should force full frame damage on the next commit | 
 |         PostSetNeedsCommitWithForcedRedrawToMainThread(); | 
 |         host_impl->BlockNotifyReadyToActivateForTesting(true); | 
 |         break; | 
 |       case 3: | 
 |         host_impl->BlockNotifyReadyToActivateForTesting(false); | 
 |         break; | 
 |       default: | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |     num_draws_++; | 
 |   } | 
 |  | 
 |   void AfterTest() override { EXPECT_EQ(5, num_draws_); } | 
 |  | 
 |  private: | 
 |   int num_draws_; | 
 |   const gfx::Size bounds_; | 
 |   const gfx::Rect invalid_rect_; | 
 |   FakeContentLayerClient client_; | 
 |   scoped_refptr<FakePictureLayer> root_layer_; | 
 | }; | 
 |  | 
 | // This test blocks activation which is not supported for single thread mode. | 
 | MULTI_THREAD_BLOCKNOTIFY_TEST_F( | 
 |     LayerTreeHostTestSetNeedsCommitWithForcedRedraw); | 
 |  | 
 | // Tests that if a layer is not drawn because of some reason in the parent then | 
 | // its damage is preserved until the next time it is drawn. | 
 | class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest { | 
 |  public: | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     // If we don't set the minimum contents scale, it's harder to verify whether | 
 |     // the damage we get is correct. For other scale amounts, please see | 
 |     // LayerTreeHostTestDamageWithScale. | 
 |     settings->minimum_contents_scale = 1.f; | 
 |   } | 
 |  | 
 |   void SetupTree() override { | 
 |     root_layer_ = FakePictureLayer::Create(&client_); | 
 |     root_layer_->SetIsDrawable(true); | 
 |     root_layer_->SetBounds(gfx::Size(50, 50)); | 
 |     layer_tree_host()->SetRootLayer(root_layer_); | 
 |  | 
 |     // The initially transparent layer has a larger child layer, which is | 
 |     // not initially drawn because of the this (parent) layer. | 
 |     parent_layer_ = FakePictureLayer::Create(&client_); | 
 |     parent_layer_->SetBounds(gfx::Size(15, 15)); | 
 |     parent_layer_->SetOpacity(0.0f); | 
 |     root_layer_->AddChild(parent_layer_); | 
 |  | 
 |     child_layer_ = FakePictureLayer::Create(&client_); | 
 |     child_layer_->SetBounds(gfx::Size(25, 25)); | 
 |     parent_layer_->AddChild(child_layer_); | 
 |     client_.set_bounds(root_layer_->bounds()); | 
 |  | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     EXPECT_EQ(DRAW_SUCCESS, draw_result); | 
 |  | 
 |     gfx::Rect root_damage_rect; | 
 |     if (!frame_data->render_passes.empty()) | 
 |       root_damage_rect = frame_data->render_passes.back()->damage_rect; | 
 |  | 
 |     // The first time, the whole view needs be drawn. | 
 |     // Afterwards, just the opacity of surface_layer1 is changed a few times, | 
 |     // and each damage should be the bounding box of it and its child. If this | 
 |     // was working improperly, the damage might not include its childs bounding | 
 |     // box. | 
 |     switch (host_impl->active_tree()->source_frame_number()) { | 
 |       case 0: | 
 |         EXPECT_EQ(gfx::Rect(root_layer_->bounds()), root_damage_rect); | 
 |         break; | 
 |       case 1: | 
 |       case 2: | 
 |       case 3: | 
 |         EXPECT_EQ(gfx::Rect(child_layer_->bounds()), root_damage_rect); | 
 |         break; | 
 |       default: | 
 |         NOTREACHED(); | 
 |     } | 
 |  | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |   void DidCommitAndDrawFrame() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         // Test not owning the surface. | 
 |         parent_layer_->SetOpacity(1.0f); | 
 |         break; | 
 |       case 2: | 
 |         parent_layer_->SetOpacity(0.0f); | 
 |         break; | 
 |       case 3: | 
 |         // Test owning the surface. | 
 |         parent_layer_->SetOpacity(0.5f); | 
 |         parent_layer_->SetForceRenderSurfaceForTesting(true); | 
 |         break; | 
 |       case 4: | 
 |         EndTest(); | 
 |         break; | 
 |       default: | 
 |         NOTREACHED(); | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   FakeContentLayerClient client_; | 
 |   scoped_refptr<FakePictureLayer> root_layer_; | 
 |   scoped_refptr<FakePictureLayer> parent_layer_; | 
 |   scoped_refptr<FakePictureLayer> child_layer_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestUndrawnLayersDamageLater); | 
 |  | 
 | // Tests that if a layer is not drawn because of some reason in the parent then | 
 | // its damage is preserved until the next time it is drawn. | 
 | class LayerTreeHostTestDamageWithScale : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestDamageWithScale() = default; | 
 |  | 
 |   void SetupTree() override { | 
 |     client_.set_fill_with_nonsolid_color(true); | 
 |  | 
 |     std::unique_ptr<FakeRecordingSource> recording(new FakeRecordingSource); | 
 |     root_layer_ = FakePictureLayer::CreateWithRecordingSource( | 
 |         &client_, std::move(recording)); | 
 |     root_layer_->SetBounds(gfx::Size(50, 50)); | 
 |  | 
 |     recording.reset(new FakeRecordingSource); | 
 |     child_layer_ = FakePictureLayer::CreateWithRecordingSource( | 
 |         &client_, std::move(recording)); | 
 |     child_layer_->SetBounds(gfx::Size(25, 25)); | 
 |     child_layer_->SetIsDrawable(true); | 
 |     child_layer_->SetContentsOpaque(true); | 
 |     root_layer_->AddChild(child_layer_); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_layer_); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     client_.set_bounds(root_layer_->bounds()); | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     // Force the layer to have a tiling at 1.3f scale. Note that if we simply | 
 |     // add tiling, it will be gone by the time we draw because of aggressive | 
 |     // cleanup. AddTilingUntilNextDraw ensures that it remains there during | 
 |     // damage calculation. | 
 |     FakePictureLayerImpl* child_layer_impl = static_cast<FakePictureLayerImpl*>( | 
 |         host_impl->active_tree()->LayerById(child_layer_->id())); | 
 |     child_layer_impl->AddTilingUntilNextDraw(1.3f); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     EXPECT_EQ(DRAW_SUCCESS, draw_result); | 
 |  | 
 |     gfx::Rect root_damage_rect; | 
 |     if (!frame_data->render_passes.empty()) | 
 |       root_damage_rect = frame_data->render_passes.back()->damage_rect; | 
 |  | 
 |     // The first time, the whole view needs be drawn. | 
 |     // Afterwards, just the opacity of surface_layer1 is changed a few times, | 
 |     // and each damage should be the bounding box of it and its child. If this | 
 |     // was working improperly, the damage might not include its childs bounding | 
 |     // box. | 
 |     switch (host_impl->active_tree()->source_frame_number()) { | 
 |       case 0: | 
 |         EXPECT_EQ(gfx::Rect(root_layer_->bounds()), root_damage_rect); | 
 |         break; | 
 |       case 1: { | 
 |         FakePictureLayerImpl* child_layer_impl = | 
 |             static_cast<FakePictureLayerImpl*>( | 
 |                 host_impl->active_tree()->LayerById(child_layer_->id())); | 
 |         // We remove tilings pretty aggressively if they are not ideal. Add this | 
 |         // back in so that we can compare | 
 |         // child_layer_impl->GetEnclosingRectInTargetSpace to the damage. | 
 |         child_layer_impl->AddTilingUntilNextDraw(1.3f); | 
 |  | 
 |         EXPECT_EQ(gfx::Rect(26, 26), root_damage_rect); | 
 |         EXPECT_EQ(child_layer_impl->GetEnclosingRectInTargetSpace(), | 
 |                   root_damage_rect); | 
 |         EXPECT_TRUE(child_layer_impl->GetEnclosingRectInTargetSpace().Contains( | 
 |             gfx::Rect(child_layer_->bounds()))); | 
 |         break; | 
 |       } | 
 |       default: | 
 |         NOTREACHED(); | 
 |     } | 
 |  | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |   void DidCommitAndDrawFrame() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: { | 
 |         // Test not owning the surface. | 
 |         child_layer_->SetOpacity(0.5f); | 
 |         break; | 
 |       } | 
 |       case 2: | 
 |         EndTest(); | 
 |         break; | 
 |       default: | 
 |         NOTREACHED(); | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   FakeContentLayerClient client_; | 
 |   scoped_refptr<Layer> root_layer_; | 
 |   scoped_refptr<Layer> child_layer_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestDamageWithScale); | 
 |  | 
 | // This test verifies that properties on the layer tree host are commited | 
 | // to the impl side. | 
 | class LayerTreeHostTestCommit : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestCommit() = default; | 
 |  | 
 |   void BeginTest() override { | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(20, 20), 1.f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |     layer_tree_host()->set_background_color(SK_ColorGRAY); | 
 |     layer_tree_host()->SetEventListenerProperties( | 
 |         EventListenerClass::kMouseWheel, EventListenerProperties::kPassive); | 
 |     layer_tree_host()->SetEventListenerProperties( | 
 |         EventListenerClass::kTouchStartOrMove, | 
 |         EventListenerProperties::kBlocking); | 
 |     layer_tree_host()->SetEventListenerProperties( | 
 |         EventListenerClass::kTouchEndOrCancel, | 
 |         EventListenerProperties::kBlockingAndPassive); | 
 |     layer_tree_host()->SetHaveScrollEventHandlers(true); | 
 |  | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override { | 
 |     EXPECT_EQ(gfx::Rect(20, 20), impl->active_tree()->GetDeviceViewport()); | 
 |     EXPECT_EQ(SK_ColorGRAY, impl->active_tree()->background_color()); | 
 |     EXPECT_EQ(EventListenerProperties::kPassive, | 
 |               impl->active_tree()->event_listener_properties( | 
 |                   EventListenerClass::kMouseWheel)); | 
 |     EXPECT_EQ(EventListenerProperties::kBlocking, | 
 |               impl->active_tree()->event_listener_properties( | 
 |                   EventListenerClass::kTouchStartOrMove)); | 
 |     EXPECT_EQ(EventListenerProperties::kBlockingAndPassive, | 
 |               impl->active_tree()->event_listener_properties( | 
 |                   EventListenerClass::kTouchEndOrCancel)); | 
 |     EXPECT_TRUE(impl->active_tree()->have_scroll_event_handlers()); | 
 |  | 
 |     EndTest(); | 
 |   } | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestCommit); | 
 |  | 
 | // This test verifies that LayerTreeHostImpl's current frame time gets | 
 | // updated in consecutive frames when it doesn't draw due to tree | 
 | // activation failure. | 
 | class LayerTreeHostTestFrameTimeUpdatesAfterActivationFails | 
 |     : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestFrameTimeUpdatesAfterActivationFails() | 
 |       : frame_count_with_pending_tree_(0) {} | 
 |  | 
 |   void BeginTest() override { | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(20, 20), 1.f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |     layer_tree_host()->set_background_color(SK_ColorGRAY); | 
 |  | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void BeginCommitOnThread(LayerTreeHostImpl* impl) override { | 
 |     EXPECT_EQ(frame_count_with_pending_tree_, 0); | 
 |     impl->BlockNotifyReadyToActivateForTesting(true); | 
 |   } | 
 |  | 
 |   void WillBeginImplFrameOnThread(LayerTreeHostImpl* impl, | 
 |                                   const viz::BeginFrameArgs& args) override { | 
 |     if (impl->pending_tree()) | 
 |       frame_count_with_pending_tree_++; | 
 |  | 
 |     if (frame_count_with_pending_tree_ == 1) { | 
 |       EXPECT_EQ(base::TimeTicks(), first_frame_time_); | 
 |       first_frame_time_ = impl->CurrentBeginFrameArgs().frame_time; | 
 |     } else if (frame_count_with_pending_tree_ == 2) { | 
 |       impl->BlockNotifyReadyToActivateForTesting(false); | 
 |     } | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* impl) override { | 
 |     EXPECT_GT(frame_count_with_pending_tree_, 1); | 
 |     EXPECT_NE(base::TimeTicks(), first_frame_time_); | 
 |     EXPECT_NE(first_frame_time_, impl->CurrentBeginFrameArgs().frame_time); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override { | 
 |     EXPECT_GT(frame_count_with_pending_tree_, 1); | 
 |   } | 
 |  | 
 |  private: | 
 |   int frame_count_with_pending_tree_; | 
 |   base::TimeTicks first_frame_time_; | 
 | }; | 
 |  | 
 | // This test blocks activation which is not supported for single thread mode. | 
 | MULTI_THREAD_BLOCKNOTIFY_TEST_F( | 
 |     LayerTreeHostTestFrameTimeUpdatesAfterActivationFails); | 
 |  | 
 | // This test verifies that LayerTreeHostImpl's current frame time gets | 
 | // updated in consecutive frames when it draws in each frame. | 
 | class LayerTreeHostTestFrameTimeUpdatesAfterDraw : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestFrameTimeUpdatesAfterDraw() : frame_(0) {} | 
 |  | 
 |   void BeginTest() override { | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(20, 20), 1.f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |     layer_tree_host()->set_background_color(SK_ColorGRAY); | 
 |  | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* impl) override { | 
 |     frame_++; | 
 |     if (frame_ == 1) { | 
 |       first_frame_time_ = impl->CurrentBeginFrameArgs().frame_time; | 
 |       impl->SetNeedsRedraw(); | 
 |  | 
 |       // 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_ == base::TimeTicks::Now()) { | 
 |       } | 
 |  | 
 |       return; | 
 |     } | 
 |  | 
 |     EXPECT_NE(first_frame_time_, impl->CurrentBeginFrameArgs().frame_time); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     // Ensure there isn't a commit between the two draws, to ensure that a | 
 |     // commit isn't required for updating the current frame time. We can | 
 |     // only check for this in the multi-threaded case, since in the single- | 
 |     // threaded case there will always be a commit between consecutive draws. | 
 |     if (HasImplThread()) | 
 |       EXPECT_EQ(0, frame_); | 
 |   } | 
 |  | 
 |  private: | 
 |   int frame_; | 
 |   base::TimeTicks first_frame_time_; | 
 | }; | 
 |  | 
 | 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 { | 
 |  public: | 
 |   LayerTreeHostTestStartPageScaleAnimation() { SetUseLayerLists(); } | 
 |  | 
 |   void SetupTree() override { | 
 |     LayerTreeHostTest::SetupTree(); | 
 |  | 
 |     Layer* root_layer = layer_tree_host()->root_layer(); | 
 |  | 
 |     scroll_layer_ = FakePictureLayer::Create(&client_); | 
 |     scroll_layer_->set_always_update_resources(true); | 
 |  | 
 |     scroll_layer_->SetBounds(gfx::Size(2 * root_layer->bounds().width(), | 
 |                                        2 * root_layer->bounds().height())); | 
 |     scroll_layer_->SetScrollOffset(gfx::ScrollOffset()); | 
 |  | 
 |     SetupViewport(root_layer, scroll_layer_, root_layer->bounds()); | 
 |  | 
 |     layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.5f, 2.f); | 
 |     client_.set_bounds(root_layer->bounds()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void ApplyViewportChanges(const ApplyViewportChangesArgs& args) override { | 
 |     gfx::ScrollOffset offset = CurrentScrollOffset(scroll_layer_.get()); | 
 |     SetScrollOffset(scroll_layer_.get(), offset + args.inner_delta); | 
 |     layer_tree_host()->SetPageScaleFactorAndLimits(args.page_scale_delta, 0.5f, | 
 |                                                    2.f); | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override { | 
 |     // We get one commit before the first draw, and the animation doesn't happen | 
 |     // until the second draw. | 
 |     switch (impl->active_tree()->source_frame_number()) { | 
 |       case 0: | 
 |         EXPECT_EQ(1.f, impl->active_tree()->current_page_scale_factor()); | 
 |         // We'll start an animation when we get back to the main thread. | 
 |         break; | 
 |       case 1: | 
 |         EXPECT_EQ(1.f, impl->active_tree()->current_page_scale_factor()); | 
 |         // Once the animation starts, an ImplFrame will be requested. However, | 
 |         // main frames may be happening in the mean-time due to high-latency | 
 |         // mode. If one happens before the next impl frame, then the source | 
 |         // frame number may increment twice instead of just once. | 
 |         break; | 
 |       case 2: | 
 |       case 3: | 
 |         EXPECT_EQ(1.25f, impl->active_tree()->current_page_scale_factor()); | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void DidCommitAndDrawFrame() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         layer_tree_host()->StartPageScaleAnimation(gfx::Vector2d(), false, | 
 |                                                    1.25f, base::TimeDelta()); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   FakeContentLayerClient client_; | 
 |   scoped_refptr<FakePictureLayer> scroll_layer_; | 
 | }; | 
 |  | 
 | // Single thread proxy does not support impl-side page scale changes. | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestStartPageScaleAnimation); | 
 |  | 
 | class ViewportDeltasAppliedDuringPinch : public LayerTreeHostTest, | 
 |                                          public ScrollCallbacks { | 
 |  protected: | 
 |   ViewportDeltasAppliedDuringPinch() : sent_gesture_(false) { | 
 |     SetUseLayerLists(); | 
 |   } | 
 |  | 
 |   void SetupTree() override { | 
 |     SetInitialRootBounds(gfx::Size(200, 200)); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     Layer* root = layer_tree_host()->root_layer(); | 
 |     SetupViewport(root, gfx::Size(500, 500), gfx::Size(500, 500)); | 
 |     layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f); | 
 |     layer_tree_host()->property_trees()->scroll_tree.SetScrollCallbacks( | 
 |         weak_ptr_factory_.GetWeakPtr()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     if (!sent_gesture_) { | 
 |       host_impl->PinchGestureBegin(); | 
 |       host_impl->PinchGestureUpdate(2, gfx::Point(100, 100)); | 
 |       host_impl->PinchGestureEnd(gfx::Point(100, 100), true); | 
 |       sent_gesture_ = true; | 
 |     } | 
 |   } | 
 |  | 
 |   void ApplyViewportChanges(const ApplyViewportChangesArgs& args) override { | 
 |     EXPECT_TRUE(sent_gesture_); | 
 |     EXPECT_EQ(gfx::ScrollOffset(50, 50), args.inner_delta); | 
 |     EXPECT_EQ(2, args.page_scale_delta); | 
 |  | 
 |     auto* scroll_layer = | 
 |         layer_tree_host()->InnerViewportScrollLayerForTesting(); | 
 |     EXPECT_EQ(scroll_layer->element_id(), last_scrolled_element_id_); | 
 |     EXPECT_EQ(gfx::ScrollOffset(50, 50), last_scrolled_offset_); | 
 |     // The scroll offset in scroll tree needs update from blink which doesn't | 
 |     // exist in this test. | 
 |     EXPECT_EQ(gfx::ScrollOffset(), CurrentScrollOffset(scroll_layer)); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void AfterTest() override { EXPECT_TRUE(sent_gesture_); } | 
 |  | 
 |   // ScrollCallbacks | 
 |   void DidScroll(ElementId element_id, | 
 |                  const gfx::ScrollOffset& scroll_offset, | 
 |                  const base::Optional<TargetSnapAreaElementIds>& | 
 |                      snap_target_ids) override { | 
 |     last_scrolled_element_id_ = element_id; | 
 |     last_scrolled_offset_ = scroll_offset; | 
 |   } | 
 |   void DidChangeScrollbarsHidden(ElementId, bool) override {} | 
 |  | 
 |  private: | 
 |   bool sent_gesture_; | 
 |   ElementId last_scrolled_element_id_; | 
 |   gfx::ScrollOffset last_scrolled_offset_; | 
 |   base::WeakPtrFactory<ViewportDeltasAppliedDuringPinch> weak_ptr_factory_{ | 
 |       this}; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(ViewportDeltasAppliedDuringPinch); | 
 |  | 
 | class LayerTreeHostTestSetVisible : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestSetVisible() : num_draws_(0) {} | 
 |  | 
 |   void BeginTest() override { | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void WillCommit() override { | 
 |     PostSetVisibleToMainThread(false); | 
 |     // This is suppressed while we're invisible. | 
 |     PostSetNeedsRedrawToMainThread(); | 
 |     // Triggers the redraw. | 
 |     PostSetVisibleToMainThread(true); | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* impl) override { | 
 |     EXPECT_TRUE(impl->visible()); | 
 |     ++num_draws_; | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void AfterTest() override { EXPECT_EQ(1, num_draws_); } | 
 |  | 
 |  private: | 
 |   int num_draws_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestSetVisible); | 
 |  | 
 | class LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers | 
 |     : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers() = default; | 
 |  | 
 |   void BeginTest() override { | 
 |     client_.set_fill_with_nonsolid_color(true); | 
 |     root_layer_ = FakePictureLayer::Create(&client_); | 
 |     child_layer_ = FakePictureLayer::Create(&client_); | 
 |  | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(60, 60), 1.5f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |     EXPECT_EQ(gfx::Size(60, 60), | 
 |               layer_tree_host()->device_viewport_rect().size()); | 
 |  | 
 |     root_layer_->AddChild(child_layer_); | 
 |  | 
 |     root_layer_->SetIsDrawable(true); | 
 |     root_layer_->SetBounds(gfx::Size(30, 30)); | 
 |  | 
 |     child_layer_->SetIsDrawable(true); | 
 |     child_layer_->SetPosition(gfx::PointF(2.f, 2.f)); | 
 |     child_layer_->SetBounds(gfx::Size(10, 10)); | 
 |     client_.set_bounds(gfx::Size(10, 10)); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_layer_); | 
 |  | 
 |     PostSetNeedsCommitToMainThread(); | 
 |     client_.set_bounds(root_layer_->bounds()); | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override { | 
 |     // Should only do one commit. | 
 |     EXPECT_EQ(0, impl->active_tree()->source_frame_number()); | 
 |     // Device scale factor should come over to impl. | 
 |     EXPECT_NEAR(impl->active_tree()->device_scale_factor(), 1.5f, 0.00001f); | 
 |  | 
 |     // Device viewport is scaled. | 
 |     EXPECT_EQ(gfx::Rect(60, 60), impl->active_tree()->GetDeviceViewport()); | 
 |  | 
 |     FakePictureLayerImpl* root = | 
 |         static_cast<FakePictureLayerImpl*>(impl->active_tree()->root_layer()); | 
 |     FakePictureLayerImpl* child = static_cast<FakePictureLayerImpl*>( | 
 |         impl->active_tree()->LayerById(child_layer_->id())); | 
 |  | 
 |     // Compute all the layer transforms for the frame. | 
 |     LayerTreeHostImpl::FrameData frame_data; | 
 |     impl->PrepareToDraw(&frame_data); | 
 |     impl->DidDrawAllLayers(frame_data); | 
 |  | 
 |     const RenderSurfaceList& render_surface_list = | 
 |         *frame_data.render_surface_list; | 
 |  | 
 |     // Both layers should be drawing into the root render surface. | 
 |     ASSERT_EQ(1u, render_surface_list.size()); | 
 |     ASSERT_EQ(GetRenderSurface(root), render_surface_list[0]); | 
 |     ASSERT_EQ(2, GetRenderSurface(root)->num_contributors()); | 
 |  | 
 |     // The root render surface is the size of the viewport. | 
 |     EXPECT_EQ(gfx::Rect(0, 0, 60, 60), GetRenderSurface(root)->content_rect()); | 
 |  | 
 |     // The max tiling scale of the child should be scaled. | 
 |     EXPECT_FLOAT_EQ(1.5f, child->MaximumTilingContentsScale()); | 
 |  | 
 |     gfx::Transform scale_transform; | 
 |     scale_transform.Scale(impl->active_tree()->device_scale_factor(), | 
 |                           impl->active_tree()->device_scale_factor()); | 
 |  | 
 |     // The root layer is scaled by 2x. | 
 |     gfx::Transform root_screen_space_transform = scale_transform; | 
 |     gfx::Transform root_draw_transform = scale_transform; | 
 |  | 
 |     EXPECT_EQ(root_draw_transform, root->DrawTransform()); | 
 |     EXPECT_EQ(root_screen_space_transform, root->ScreenSpaceTransform()); | 
 |  | 
 |     // The child is at position 2,2, which is transformed to 3,3 after the scale | 
 |     gfx::Transform child_transform; | 
 |     child_transform.Translate(3.f, 3.f); | 
 |     child_transform.Scale(child->MaximumTilingContentsScale(), | 
 |                           child->MaximumTilingContentsScale()); | 
 |  | 
 |     EXPECT_TRANSFORMATION_MATRIX_EQ(child_transform, child->DrawTransform()); | 
 |     EXPECT_TRANSFORMATION_MATRIX_EQ(child_transform, | 
 |                                     child->ScreenSpaceTransform()); | 
 |  | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |  private: | 
 |   FakeContentLayerClient client_; | 
 |   scoped_refptr<FakePictureLayer> root_layer_; | 
 |   scoped_refptr<FakePictureLayer> child_layer_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers); | 
 |  | 
 | class LayerTreeHostTestContinuousInvalidate : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestContinuousInvalidate() | 
 |       : num_commit_complete_(0), num_draw_layers_(0) {} | 
 |  | 
 |   void BeginTest() override { | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(10, 10), 1.f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |     layer_tree_host()->root_layer()->SetBounds(gfx::Size(10, 10)); | 
 |  | 
 |     layer_ = FakePictureLayer::Create(&client_); | 
 |     layer_->SetBounds(gfx::Size(10, 10)); | 
 |     layer_->SetPosition(gfx::PointF(0.f, 0.f)); | 
 |     layer_->SetIsDrawable(true); | 
 |     layer_tree_host()->root_layer()->AddChild(layer_); | 
 |  | 
 |     PostSetNeedsCommitToMainThread(); | 
 |     client_.set_bounds(layer_->bounds()); | 
 |   } | 
 |  | 
 |   void DidCommitAndDrawFrame() override { | 
 |     if (num_draw_layers_ == 2) | 
 |       return; | 
 |     layer_->SetNeedsDisplay(); | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | 
 |     if (num_draw_layers_ == 1) | 
 |       num_commit_complete_++; | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* impl) override { | 
 |     num_draw_layers_++; | 
 |     if (num_draw_layers_ == 2) | 
 |       EndTest(); | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     // Check that we didn't commit twice between first and second draw. | 
 |     EXPECT_EQ(1, num_commit_complete_); | 
 |   } | 
 |  | 
 |  private: | 
 |   FakeContentLayerClient client_; | 
 |   scoped_refptr<Layer> layer_; | 
 |   int num_commit_complete_; | 
 |   int num_draw_layers_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestContinuousInvalidate); | 
 |  | 
 | class LayerTreeHostTestDeferMainFrameUpdate : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestDeferMainFrameUpdate() = default; | 
 |  | 
 |   void BeginTest() override { | 
 |     // Start with commits deferred. | 
 |     PostGetDeferMainFrameUpdateToMainThread(&scoped_defer_main_frame_update_); | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl, | 
 |                                   const viz::BeginFrameArgs& args) override { | 
 |     // Impl frames happen while commits are deferred. | 
 |     num_will_begin_impl_frame_++; | 
 |     switch (num_will_begin_impl_frame_) { | 
 |       case 1: | 
 |       case 2: | 
 |       case 3: | 
 |       case 4: | 
 |         // Post a number of frames to increase the chance that, if there exist | 
 |         // bugs, an unexpected BeginMainFrame will be issued. | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         PostSetNeedsRedrawToMainThread(); | 
 |         break; | 
 |       case 5: | 
 |         MainThreadTaskRunner()->PostTask( | 
 |             FROM_HERE, | 
 |             // Unretained because the test should not end before allowing | 
 |             // commits via this running. | 
 |             base::BindOnce(&LayerTreeHostTestDeferMainFrameUpdate::AllowCommits, | 
 |                            base::Unretained(this))); | 
 |         break; | 
 |       default: | 
 |         // Sometimes |num_will_begin_impl_frame_| will be greater than 5 if the | 
 |         // main thread is slow to respond. | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void WillBeginMainFrame() override { | 
 |     EXPECT_FALSE(scoped_defer_main_frame_update_); | 
 |     EXPECT_TRUE(IsCommitAllowed()); | 
 |     num_send_begin_main_frame_++; | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     EXPECT_GE(num_will_begin_impl_frame_, 5); | 
 |     EXPECT_EQ(1, num_send_begin_main_frame_); | 
 |   } | 
 |  | 
 |   virtual void AllowCommits() { | 
 |     allow_commits_ = true; | 
 |     scoped_defer_main_frame_update_.reset(); | 
 |   } | 
 |  | 
 |   virtual bool IsCommitAllowed() const { return allow_commits_; } | 
 |  | 
 |  private: | 
 |   std::unique_ptr<ScopedDeferMainFrameUpdate> scoped_defer_main_frame_update_; | 
 |   bool allow_commits_ = false; | 
 |   int num_will_begin_impl_frame_ = 0; | 
 |   int num_send_begin_main_frame_ = 0; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestDeferMainFrameUpdate); | 
 |  | 
 | // This verifies that changing the size of a LayerTreeHost without providing a | 
 | // LocalSurfaceId defers commits. | 
 | class LayerTreeHostInvalidLocalSurfaceIdDefersCommit | 
 |     : public LayerTreeHostTestDeferMainFrameUpdate { | 
 |  public: | 
 |   LayerTreeHostInvalidLocalSurfaceIdDefersCommit() { | 
 |     SkipAllocateInitialLocalSurfaceId(); | 
 |   } | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void AllowCommits() override { | 
 |     GenerateNewLocalSurfaceId(); | 
 |     PostSetLocalSurfaceIdAllocationToMainThread( | 
 |         GetCurrentLocalSurfaceIdAllocation()); | 
 |   } | 
 |  | 
 |   bool IsCommitAllowed() const override { | 
 |     return GetCurrentLocalSurfaceIdAllocation().IsValid(); | 
 |   } | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostInvalidLocalSurfaceIdDefersCommit); | 
 |  | 
 | // This verifies that we can abort a commit inside the main frame, and | 
 | // we don't leave any weird states around if we never allow the commit | 
 | // to happen. | 
 | class LayerTreeHostTestDeferMainFrameUpdateInsideBeginMainFrame | 
 |     : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestDeferMainFrameUpdateInsideBeginMainFrame() = default; | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void WillBeginMainFrame() override { | 
 |     ++begin_main_frame_count_; | 
 |  | 
 |     // This should prevent the commit from happening. | 
 |     scoped_defer_main_frame_update_ = layer_tree_host()->DeferMainFrameUpdate(); | 
 |     // Wait to see if the commit happens. It's possible the deferred | 
 |     // commit happens when it shouldn't but takes long enough that | 
 |     // this passes. But it won't fail when it shouldn't. | 
 |     MainThreadTaskRunner()->PostDelayedTask( | 
 |         FROM_HERE, | 
 |         // Unretained because the test doesn't end before this runs. | 
 |         base::BindOnce(&LayerTreeTest::EndTest, base::Unretained(this)), | 
 |         base::TimeDelta::FromMilliseconds(100)); | 
 |   } | 
 |  | 
 |   void DidCommit() override { ++commit_count_; } | 
 |  | 
 |   void AfterTest() override { | 
 |     EXPECT_EQ(0, commit_count_); | 
 |     EXPECT_EQ(1, begin_main_frame_count_); | 
 |   } | 
 |  | 
 |  private: | 
 |   std::unique_ptr<ScopedDeferMainFrameUpdate> scoped_defer_main_frame_update_; | 
 |   int commit_count_ = 0; | 
 |   int begin_main_frame_count_ = 0; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F( | 
 |     LayerTreeHostTestDeferMainFrameUpdateInsideBeginMainFrame); | 
 |  | 
 | // This verifies that we can abort a commit inside the main frame, and | 
 | // we will finish the commit once it is allowed. | 
 | class LayerTreeHostTestDeferInsideBeginMainFrameWithCommitAfter | 
 |     : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestDeferInsideBeginMainFrameWithCommitAfter() = default; | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void WillBeginMainFrame() override { | 
 |     ++begin_main_frame_count_; | 
 |     if (allow_commits_) | 
 |       return; | 
 |  | 
 |     // This should prevent the commit from happening. | 
 |     scoped_defer_main_frame_update_ = layer_tree_host()->DeferMainFrameUpdate(); | 
 |     // Wait to see if the commit happens. It's possible the deferred | 
 |     // commit happens when it shouldn't but takes long enough that | 
 |     // this passes. But it won't fail when it shouldn't. | 
 |     MainThreadTaskRunner()->PostDelayedTask( | 
 |         FROM_HERE, | 
 |         // Unretained because the test doesn't end before this runs. | 
 |         base::BindOnce( | 
 |             &LayerTreeHostTestDeferInsideBeginMainFrameWithCommitAfter:: | 
 |                 AllowCommits, | 
 |             base::Unretained(this)), | 
 |         base::TimeDelta::FromMilliseconds(100)); | 
 |   } | 
 |  | 
 |   void AllowCommits() { | 
 |     // Once we've waited and seen that commit did not happen, we | 
 |     // allow commits and should see this one go through. | 
 |     allow_commits_ = true; | 
 |     scoped_defer_main_frame_update_.reset(); | 
 |   } | 
 |  | 
 |   void DidCommit() override { | 
 |     ++commit_count_; | 
 |     EXPECT_TRUE(allow_commits_); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     EXPECT_EQ(1, commit_count_); | 
 |     EXPECT_EQ(2, begin_main_frame_count_); | 
 |     // The commit should not have been aborted. | 
 |     EXPECT_EQ(1, ready_to_commit_count_); | 
 |   } | 
 |  | 
 |   void ReadyToCommitOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     ++ready_to_commit_count_; | 
 |   } | 
 |  | 
 |  private: | 
 |   std::unique_ptr<ScopedDeferMainFrameUpdate> scoped_defer_main_frame_update_; | 
 |   bool allow_commits_ = false; | 
 |   int commit_count_ = 0; | 
 |   int begin_main_frame_count_ = 0; | 
 |   int ready_to_commit_count_ = 0; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F( | 
 |     LayerTreeHostTestDeferInsideBeginMainFrameWithCommitAfter); | 
 |  | 
 | // This verifies that animate_only BeginFrames only run animation/layout | 
 | // updates, i.e. abort commits after the paint stage and only request layer | 
 | // tree updates for layout. | 
 | // | 
 | // The tests sends four Begin(Main)Frames in sequence: three animate_only | 
 | // Begin(Main)Frames followed by a normal Begin(Main)Frame. The first three | 
 | // should result in aborted commits, whereas the last one should complete the | 
 | // previously aborted commits. | 
 | // | 
 | // Between BeginMainFrames 2 and 3, the client also requests a new commit | 
 | // (SetNeedsCommit), but not between BeginMainFrames 1 and 2. In multi-threaded | 
 | // mode, ProxyMain will run the animate pipeline stage only for BeginMainFrames | 
 | // 1 and 3, as no new commit was requested between 1 and 2. | 
 | // | 
 | // The test uses the full-pipeline mode to ensure that each BeginFrame also | 
 | // incurs a BeginMainFrame. | 
 | class LayerTreeHostTestAnimateOnlyBeginFrames | 
 |     : public LayerTreeHostTest, | 
 |       public viz::ExternalBeginFrameSourceClient { | 
 |  public: | 
 |   LayerTreeHostTestAnimateOnlyBeginFrames() | 
 |       : external_begin_frame_source_(this) { | 
 |     UseBeginFrameSource(&external_begin_frame_source_); | 
 |   } | 
 |  | 
 |   void IssueBeginFrame(bool animate_only) { | 
 |     ++begin_frame_count_; | 
 |  | 
 |     last_begin_frame_time_ += viz::BeginFrameArgs::DefaultInterval(); | 
 |     uint64_t sequence_number = next_begin_frame_sequence_number_++; | 
 |  | 
 |     auto args = viz::BeginFrameArgs::Create( | 
 |         BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, | 
 |         sequence_number, last_begin_frame_time_, | 
 |         last_begin_frame_time_ + viz::BeginFrameArgs::DefaultInterval(), | 
 |         viz::BeginFrameArgs::DefaultInterval(), viz::BeginFrameArgs::NORMAL); | 
 |     args.animate_only = animate_only; | 
 |  | 
 |     external_begin_frame_source_.OnBeginFrame(args); | 
 |   } | 
 |  | 
 |   void PostIssueBeginFrame(bool animate_only) { | 
 |     // Post a new task so that BeginFrame is not issued within same callstack. | 
 |     ImplThreadTaskRunner()->PostTask( | 
 |         FROM_HERE, | 
 |         base::BindOnce( | 
 |             &LayerTreeHostTestAnimateOnlyBeginFrames::IssueBeginFrame, | 
 |             base::Unretained(this), animate_only)); | 
 |   } | 
 |  | 
 |   // viz::ExternalBeginFrameSourceClient implementation: | 
 |   void OnNeedsBeginFrames(bool needs_begin_frames) override { | 
 |     if (needs_begin_frames) { | 
 |       EXPECT_EQ(0, begin_frame_count_); | 
 |       // Send a first animation_only BeginFrame. | 
 |       PostIssueBeginFrame(true); | 
 |     } | 
 |   } | 
 |  | 
 |   // LayerTreeHostTest implementation: | 
 |   void BeginTest() override { | 
 |     PostSetNeedsCommitToMainThread(); | 
 |     // OnNeedsBeginFrames(true) will be called during tree initialization. | 
 |   } | 
 |  | 
 |   void WillBeginMainFrame() override { ++will_begin_main_frame_count_; } | 
 |  | 
 |   void DidSendBeginMainFrameOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     ++sent_begin_main_frame_count_; | 
 |     EXPECT_EQ(begin_frame_count_, sent_begin_main_frame_count_); | 
 |   } | 
 |  | 
 |   void DidFinishImplFrameOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     if (begin_frame_count_ < 3) { | 
 |       if (begin_frame_count_ == 2) { | 
 |         // Request another commit before sending the third BeginMainFrame. | 
 |         PostSetNeedsCommitToMainThread(); | 
 |       } | 
 |  | 
 |       // Send another animation_only BeginFrame. | 
 |       PostIssueBeginFrame(true); | 
 |     } else if (begin_frame_count_ == 3) { | 
 |       PostIssueBeginFrame(false); | 
 |     } | 
 |   } | 
 |  | 
 |   void UpdateLayerTreeHost() override { ++update_layer_tree_host_count_; } | 
 |  | 
 |   void DidCommit() override { | 
 |     ++commit_count_; | 
 |  | 
 |     // Fourth BeginMainFrame should lead to commit. | 
 |     EXPECT_EQ(4, begin_frame_count_); | 
 |     EXPECT_EQ(4, sent_begin_main_frame_count_); | 
 |  | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void ReadyToCommitOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     ++ready_to_commit_count_; | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     EXPECT_EQ(1, commit_count_); | 
 |     EXPECT_EQ(4, begin_frame_count_); | 
 |     EXPECT_EQ(4, sent_begin_main_frame_count_); | 
 |  | 
 |     if (HasImplThread()) { | 
 |       // ProxyMain aborts the second BeginMainFrame before running the animate | 
 |       // pipeline stage, since no further updates were made since the first one. | 
 |       // Thus, we expect not to be called for the second BeginMainFrame. | 
 |       EXPECT_EQ(3, will_begin_main_frame_count_); | 
 |       EXPECT_EQ(3, update_layer_tree_host_count_); | 
 |     } else { | 
 |       EXPECT_EQ(4, will_begin_main_frame_count_); | 
 |       EXPECT_EQ(4, update_layer_tree_host_count_); | 
 |     } | 
 |  | 
 |     // The final commit should not have been aborted. | 
 |     EXPECT_EQ(1, ready_to_commit_count_); | 
 |   } | 
 |  | 
 |  protected: | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     // Use full-pipeline mode to make BeginFrame handling deterministic. | 
 |     EXPECT_FALSE(settings->wait_for_all_pipeline_stages_before_draw); | 
 |     settings->wait_for_all_pipeline_stages_before_draw = true; | 
 |   } | 
 |  | 
 |  private: | 
 |   viz::ExternalBeginFrameSource external_begin_frame_source_; | 
 |  | 
 |   base::TimeTicks last_begin_frame_time_ = base::TimeTicks::Now(); | 
 |   uint64_t next_begin_frame_sequence_number_ = | 
 |       viz::BeginFrameArgs::kStartingFrameNumber; | 
 |   int commit_count_ = 0; | 
 |   int begin_frame_count_ = 0; | 
 |   int sent_begin_main_frame_count_ = 0; | 
 |   int will_begin_main_frame_count_ = 0; | 
 |   int update_layer_tree_host_count_ = 0; | 
 |   int ready_to_commit_count_ = 0; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestAnimateOnlyBeginFrames); | 
 |  | 
 | class LayerTreeHostTestCompositeImmediatelyStateTransitions | 
 |     : public LayerTreeHostTest { | 
 |  public: | 
 |   enum { | 
 |     kInvalid, | 
 |     kStartedTest, | 
 |     kStartedImplFrame, | 
 |     kStartedMainFrame, | 
 |     kStartedCommit, | 
 |     kCompletedCommit, | 
 |     kCompletedMainFrame, | 
 |     kCompletedImplFrame, | 
 |   }; | 
 |  | 
 |   LayerTreeHostTestCompositeImmediatelyStateTransitions() | 
 |       : current_state_(kInvalid), current_begin_frame_args_() {} | 
 |  | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     settings->single_thread_proxy_scheduler = false; | 
 |     settings->use_zero_copy = true; | 
 |   } | 
 |  | 
 |   void BeginTest() override { | 
 |     current_state_ = kStartedTest; | 
 |     PostCompositeImmediatelyToMainThread(); | 
 |   } | 
 |  | 
 |   void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl, | 
 |                                   const viz::BeginFrameArgs& args) override { | 
 |     EXPECT_EQ(current_state_, kStartedTest); | 
 |     current_state_ = kStartedImplFrame; | 
 |  | 
 |     EXPECT_FALSE(current_begin_frame_args_.IsValid()); | 
 |     EXPECT_TRUE(args.IsValid()); | 
 |     current_begin_frame_args_ = args; | 
 |   } | 
 |   void WillBeginMainFrame() override { | 
 |     EXPECT_EQ(current_state_, kStartedImplFrame); | 
 |     current_state_ = kStartedMainFrame; | 
 |   } | 
 |   void BeginMainFrame(const viz::BeginFrameArgs& args) override { | 
 |     EXPECT_EQ(current_state_, kStartedMainFrame); | 
 |     EXPECT_EQ(args.frame_time, current_begin_frame_args_.frame_time); | 
 |   } | 
 |   void BeginCommitOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     EXPECT_EQ(current_state_, kStartedMainFrame); | 
 |     current_state_ = kStartedCommit; | 
 |   } | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     EXPECT_EQ(current_state_, kStartedCommit); | 
 |     current_state_ = kCompletedCommit; | 
 |   } | 
 |   void DidBeginMainFrame() override { | 
 |     EXPECT_EQ(current_state_, kCompletedCommit); | 
 |     current_state_ = kCompletedMainFrame; | 
 |   } | 
 |   void DidFinishImplFrameOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     EXPECT_EQ(current_state_, kCompletedMainFrame); | 
 |     current_state_ = kCompletedImplFrame; | 
 |     EndTest(); | 
 |   } | 
 |   void AfterTest() override { EXPECT_EQ(current_state_, kCompletedImplFrame); } | 
 |  | 
 |  private: | 
 |   int current_state_; | 
 |   viz::BeginFrameArgs current_begin_frame_args_; | 
 | }; | 
 |  | 
 | SINGLE_THREAD_TEST_F(LayerTreeHostTestCompositeImmediatelyStateTransitions); | 
 |  | 
 | class LayerTreeHostTestLCDChange : public LayerTreeHostTest { | 
 |  public: | 
 |   void SetupTree() override { | 
 |     num_tiles_rastered_ = 0; | 
 |  | 
 |     scoped_refptr<Layer> root_layer = PictureLayer::Create(&client_); | 
 |     client_.set_fill_with_nonsolid_color(true); | 
 |     root_layer->SetIsDrawable(true); | 
 |     root_layer->SetBounds(gfx::Size(10, 10)); | 
 |     root_layer->SetContentsOpaque(true); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_layer); | 
 |  | 
 |     // The expectations are based on the assumption that the default | 
 |     // LCD settings are: | 
 |     EXPECT_TRUE(layer_tree_host()->GetSettings().can_use_lcd_text); | 
 |  | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     client_.set_bounds(root_layer->bounds()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommitAndDrawFrame() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 2: | 
 |         // Change contents_opaque that should trigger lcd change. | 
 |         layer_tree_host()->root_layer()->SetContentsOpaque(false); | 
 |         break; | 
 |       case 3: | 
 |         // Change contents_opaque that should trigger lcd change. | 
 |         layer_tree_host()->root_layer()->SetContentsOpaque(true); | 
 |         break; | 
 |       case 4: | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl, | 
 |                                       const Tile* tile) override { | 
 |     ++num_tiles_rastered_; | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     PictureLayerImpl* root_layer = | 
 |         static_cast<PictureLayerImpl*>(host_impl->active_tree()->root_layer()); | 
 |     bool can_use_lcd_text = | 
 |         root_layer->ComputeLCDTextDisallowedReasonForTesting() == | 
 |         LCDTextDisallowedReason::kNone; | 
 |     switch (host_impl->active_tree()->source_frame_number()) { | 
 |       case 0: | 
 |         // The first draw. | 
 |         EXPECT_EQ(1, num_tiles_rastered_); | 
 |         EXPECT_TRUE(can_use_lcd_text); | 
 |         EXPECT_TRUE(root_layer->can_use_lcd_text()); | 
 |         break; | 
 |       case 1: | 
 |         // Nothing changed on the layer. | 
 |         EXPECT_EQ(1, num_tiles_rastered_); | 
 |         EXPECT_TRUE(can_use_lcd_text); | 
 |         EXPECT_TRUE(root_layer->can_use_lcd_text()); | 
 |         break; | 
 |       case 2: | 
 |         // LCD text was disabled; it should be re-rastered with LCD text off. | 
 |         EXPECT_EQ(2, num_tiles_rastered_); | 
 |         EXPECT_FALSE(can_use_lcd_text); | 
 |         EXPECT_FALSE(root_layer->can_use_lcd_text()); | 
 |         break; | 
 |       case 3: | 
 |         // LCD text was enabled, but it's sticky and stays off. | 
 |         EXPECT_EQ(2, num_tiles_rastered_); | 
 |         EXPECT_TRUE(can_use_lcd_text); | 
 |         EXPECT_FALSE(root_layer->can_use_lcd_text()); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   FakeContentLayerClient client_; | 
 |   int num_tiles_rastered_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestLCDChange); | 
 |  | 
 | class LayerTreeHostTestBeginFrameNotificationShutdownWhileEnabled | 
 |     : public LayerTreeHostTest { | 
 |  public: | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     settings->using_synchronous_renderer_compositor = true; | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     // 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::BindOnce(&LayerTreeHostTest::EndTest, base::Unretained(this))); | 
 |   } | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F( | 
 |     LayerTreeHostTestBeginFrameNotificationShutdownWhileEnabled); | 
 |  | 
 | class LayerTreeHostTestAbortedCommitDoesntStall : public LayerTreeHostTest { | 
 |  protected: | 
 |   LayerTreeHostTestAbortedCommitDoesntStall() | 
 |       : commit_count_(0), commit_abort_count_(0), commit_complete_count_(0) {} | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommit() override { | 
 |     commit_count_++; | 
 |     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(); | 
 |     } | 
 |   } | 
 |  | 
 |   void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl, | 
 |                                      CommitEarlyOutReason reason) override { | 
 |     commit_abort_count_++; | 
 |     // Initiate another abortable commit. | 
 |     host_impl->SetNeedsCommit(); | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     commit_complete_count_++; | 
 |     if (commit_complete_count_ == 1) { | 
 |       // Initiate an abortable commit after the first commit. | 
 |       host_impl->SetNeedsCommit(); | 
 |     } else { | 
 |       EndTest(); | 
 |     } | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     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_; | 
 | }; | 
 |  | 
 | class OnDrawLayerTreeFrameSink : public TestLayerTreeFrameSink { | 
 |  public: | 
 |   OnDrawLayerTreeFrameSink( | 
 |       scoped_refptr<viz::ContextProvider> compositor_context_provider, | 
 |       scoped_refptr<viz::RasterContextProvider> worker_context_provider, | 
 |       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, | 
 |       const viz::RendererSettings& renderer_settings, | 
 |       base::SingleThreadTaskRunner* task_runner, | 
 |       bool synchronous_composite, | 
 |       double refresh_rate, | 
 |       base::RepeatingClosure invalidate_callback) | 
 |       : TestLayerTreeFrameSink(std::move(compositor_context_provider), | 
 |                                std::move(worker_context_provider), | 
 |                                gpu_memory_buffer_manager, | 
 |                                renderer_settings, | 
 |                                task_runner, | 
 |                                synchronous_composite, | 
 |                                false /* disable_display_vsync */, | 
 |                                refresh_rate), | 
 |         invalidate_callback_(std::move(invalidate_callback)) {} | 
 |  | 
 |   // TestLayerTreeFrameSink overrides. | 
 |   void Invalidate(bool needs_draw) override { invalidate_callback_.Run(); } | 
 |  | 
 |   void OnDraw(bool resourceless_software_draw) { | 
 |     gfx::Transform identity; | 
 |     gfx::Rect empty_rect; | 
 |     client_->OnDraw(identity, empty_rect, resourceless_software_draw, false); | 
 |   } | 
 |  | 
 |  private: | 
 |   const base::RepeatingClosure invalidate_callback_; | 
 | }; | 
 |  | 
 | class LayerTreeHostTestAbortedCommitDoesntStallSynchronousCompositor | 
 |     : public LayerTreeHostTestAbortedCommitDoesntStall { | 
 |  protected: | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     LayerTreeHostTestAbortedCommitDoesntStall::InitializeSettings(settings); | 
 |     settings->using_synchronous_renderer_compositor = true; | 
 |   } | 
 |  | 
 |   std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink( | 
 |       const viz::RendererSettings& renderer_settings, | 
 |       double refresh_rate, | 
 |       scoped_refptr<viz::ContextProvider> compositor_context_provider, | 
 |       scoped_refptr<viz::RasterContextProvider> worker_context_provider) | 
 |       override { | 
 |     auto on_draw_callback = base::BindRepeating( | 
 |         &LayerTreeHostTestAbortedCommitDoesntStallSynchronousCompositor:: | 
 |             CallOnDraw, | 
 |         base::Unretained(this)); | 
 |     auto frame_sink = std::make_unique<OnDrawLayerTreeFrameSink>( | 
 |         compositor_context_provider, std::move(worker_context_provider), | 
 |         gpu_memory_buffer_manager(), renderer_settings, ImplThreadTaskRunner(), | 
 |         false /* synchronous_composite */, refresh_rate, | 
 |         std::move(on_draw_callback)); | 
 |     layer_tree_frame_sink_ = frame_sink.get(); | 
 |     return std::move(frame_sink); | 
 |   } | 
 |  | 
 |   void CallOnDraw() { | 
 |     if (!TestEnded()) { | 
 |       // Synchronous compositor does not draw unless told to do so by the output | 
 |       // surface. But it needs to be done on a new stack frame. | 
 |       bool resourceless_software_draw = false; | 
 |       ImplThreadTaskRunner()->PostTask( | 
 |           FROM_HERE, base::BindOnce(&OnDrawLayerTreeFrameSink::OnDraw, | 
 |                                     base::Unretained(layer_tree_frame_sink_), | 
 |                                     resourceless_software_draw)); | 
 |     } | 
 |   } | 
 |  | 
 |   OnDrawLayerTreeFrameSink* layer_tree_frame_sink_ = nullptr; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F( | 
 |     LayerTreeHostTestAbortedCommitDoesntStallSynchronousCompositor); | 
 |  | 
 | class LayerTreeHostTestSynchronousCompositorActivateWithoutDraw | 
 |     : public LayerTreeHostTest { | 
 |  protected: | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     settings->using_synchronous_renderer_compositor = true; | 
 |   } | 
 |  | 
 |   std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink( | 
 |       const viz::RendererSettings& renderer_settings, | 
 |       double refresh_rate, | 
 |       scoped_refptr<viz::ContextProvider> compositor_context_provider, | 
 |       scoped_refptr<viz::RasterContextProvider> worker_context_provider) | 
 |       override { | 
 |     // Make |invalidate_callback| do nothing so there is no draw. | 
 |     auto frame_sink = std::make_unique<OnDrawLayerTreeFrameSink>( | 
 |         compositor_context_provider, std::move(worker_context_provider), | 
 |         gpu_memory_buffer_manager(), renderer_settings, ImplThreadTaskRunner(), | 
 |         /*synchronous_composite=*/false, refresh_rate, | 
 |         /*invalidate_callback=*/base::DoNothing()); | 
 |     return std::move(frame_sink); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommit() override { commit_count_++; } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     activate_count_++; | 
 |     if (activate_count_ == 1) { | 
 |       PostSetNeedsCommitToMainThread(); | 
 |     } else if (activate_count_ == 2) { | 
 |       EndTest(); | 
 |     } else { | 
 |       NOTREACHED(); | 
 |     } | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     // This test specifically tests that two commit-activate cycles without | 
 |     // draw in between them. | 
 |     ADD_FAILURE(); | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     // There should be two commits and activations without any draw. | 
 |     EXPECT_EQ(commit_count_, 2); | 
 |     EXPECT_EQ(activate_count_, 2); | 
 |   } | 
 |  | 
 |  private: | 
 |   int commit_count_ = 0; | 
 |   int activate_count_ = 0; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestSynchronousCompositorActivateWithoutDraw); | 
 |  | 
 | class LayerTreeHostTestUninvertibleTransformDoesNotBlockActivation | 
 |     : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     LayerTreeHostTest::SetupTree(); | 
 |  | 
 |     scoped_refptr<Layer> layer = PictureLayer::Create(&client_); | 
 |     layer->SetTransform(gfx::Transform(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); | 
 |     layer->SetBounds(gfx::Size(10, 10)); | 
 |     layer_tree_host()->root_layer()->AddChild(layer); | 
 |     client_.set_bounds(layer->bounds()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   FakeContentLayerClient client_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F( | 
 |     LayerTreeHostTestUninvertibleTransformDoesNotBlockActivation); | 
 |  | 
 | class LayerTreeHostTestNumFramesPending : public LayerTreeHostTest { | 
 |  public: | 
 |   void BeginTest() override { | 
 |     frame_ = 0; | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   // Round 1: commit + draw | 
 |   // Round 2: commit only (no draw/swap) | 
 |   // Round 3: draw only (no commit) | 
 |  | 
 |   void DidCommit() override { | 
 |     int commit = layer_tree_host()->SourceFrameNumber(); | 
 |     switch (commit) { | 
 |       case 2: | 
 |         // Round 2 done. | 
 |         EXPECT_EQ(1, frame_); | 
 |         layer_tree_host()->SetNeedsRedrawRect( | 
 |             layer_tree_host()->device_viewport_rect()); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void DidReceiveCompositorFrameAck() override { | 
 |     int commit = layer_tree_host()->SourceFrameNumber(); | 
 |     ++frame_; | 
 |     switch (frame_) { | 
 |       case 1: | 
 |         // Round 1 done. | 
 |         EXPECT_EQ(1, commit); | 
 |         layer_tree_host()->SetNeedsCommit(); | 
 |         break; | 
 |       case 2: | 
 |         // Round 3 done. | 
 |         EXPECT_EQ(2, commit); | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |  protected: | 
 |   int frame_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestNumFramesPending); | 
 |  | 
 | // Test for UI Resource management. | 
 | class LayerTreeHostTestUIResource : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestUIResource() : num_ui_resources_(0) {} | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommit() override { | 
 |     int frame = layer_tree_host()->SourceFrameNumber(); | 
 |     switch (frame) { | 
 |       case 1: | 
 |         CreateResource(); | 
 |         CreateResource(); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         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()->GetUIResourceManager()->DeleteUIResource( | 
 |             ui_resources_[0]->id()); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 3: | 
 |         // DeleteUIResource can be called with an invalid id. | 
 |         layer_tree_host()->GetUIResourceManager()->DeleteUIResource( | 
 |             ui_resources_[0]->id()); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 4: | 
 |         CreateResource(); | 
 |         CreateResource(); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 5: | 
 |         ClearResources(); | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override { | 
 |     auto* sii = static_cast<viz::TestContextProvider*>( | 
 |                     impl->layer_tree_frame_sink()->context_provider()) | 
 |                     ->SharedImageInterface(); | 
 |  | 
 |     int frame = impl->active_tree()->source_frame_number(); | 
 |     switch (frame) { | 
 |       case 0: | 
 |         ASSERT_EQ(0u, sii->shared_image_count()); | 
 |         break; | 
 |       case 1: | 
 |         // Created two textures. | 
 |         ASSERT_EQ(2u, sii->shared_image_count()); | 
 |         break; | 
 |       case 2: | 
 |         // One texture left after one deletion. | 
 |         ASSERT_EQ(1u, sii->shared_image_count()); | 
 |         break; | 
 |       case 3: | 
 |         // Resource manager state should not change when delete is called on an | 
 |         // invalid id. | 
 |         ASSERT_EQ(1u, sii->shared_image_count()); | 
 |         break; | 
 |       case 4: | 
 |         // Creation after deletion: two more creates should total up to | 
 |         // three textures. | 
 |         ASSERT_EQ(3u, sii->shared_image_count()); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   // Must clear all resources before exiting. | 
 |   void ClearResources() { | 
 |     for (int i = 0; i < num_ui_resources_; i++) | 
 |       ui_resources_[i] = nullptr; | 
 |   } | 
 |  | 
 |   void CreateResource() { | 
 |     ui_resources_[num_ui_resources_++] = | 
 |         FakeScopedUIResource::Create(layer_tree_host()->GetUIResourceManager()); | 
 |   } | 
 |  | 
 |   std::unique_ptr<FakeScopedUIResource> ui_resources_[5]; | 
 |   int num_ui_resources_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestUIResource); | 
 |  | 
 | class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest { | 
 |  protected: | 
 |   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(); | 
 |   } | 
 |  | 
 |   void SetupTree() override { | 
 |     root_ = PushPropertiesCountingLayer::Create(); | 
 |     child_ = PushPropertiesCountingLayer::Create(); | 
 |     child2_ = PushPropertiesCountingLayer::Create(); | 
 |     grandchild_ = PushPropertiesCountingLayer::Create(); | 
 |     leaf_always_pushing_layer_ = PushPropertiesCountingLayer::Create(); | 
 |  | 
 |     root_->AddChild(child_); | 
 |     root_->AddChild(child2_); | 
 |     child_->AddChild(grandchild_); | 
 |     child2_->AddChild(leaf_always_pushing_layer_); | 
 |  | 
 |     other_root_ = PushPropertiesCountingLayer::Create(); | 
 |  | 
 |     // Don't set the root layer here. | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     client_.set_bounds(root_->bounds()); | 
 |   } | 
 |  | 
 |   void DidCommitAndDrawFrame() override { | 
 |     EXPECT_EQ(expected_push_properties_root_, root_->push_properties_count()) | 
 |         << "num_commits: " << num_commits_; | 
 |     EXPECT_EQ(expected_push_properties_child_, child_->push_properties_count()) | 
 |         << "num_commits: " << num_commits_; | 
 |     EXPECT_EQ(expected_push_properties_grandchild_, | 
 |               grandchild_->push_properties_count()) | 
 |         << "num_commits: " << num_commits_; | 
 |     EXPECT_EQ(expected_push_properties_child2_, | 
 |               child2_->push_properties_count()) | 
 |         << "num_commits: " << num_commits_; | 
 |     EXPECT_EQ(expected_push_properties_other_root_, | 
 |               other_root_->push_properties_count()) | 
 |         << "num_commits: " << num_commits_; | 
 |     EXPECT_EQ(expected_push_properties_leaf_layer_, | 
 |               leaf_always_pushing_layer_->push_properties_count()) | 
 |         << "num_commits: " << num_commits_; | 
 |  | 
 |     ++num_commits_; | 
 |  | 
 |     // The scrollbar layer always needs to be pushed. | 
 |     if (root_->layer_tree_host()) { | 
 |       EXPECT_FALSE(base::Contains( | 
 |           root_->layer_tree_host()->LayersThatShouldPushProperties(), | 
 |           root_.get())); | 
 |     } | 
 |     if (child2_->layer_tree_host()) { | 
 |       EXPECT_FALSE(base::Contains( | 
 |           child2_->layer_tree_host()->LayersThatShouldPushProperties(), | 
 |           child2_.get())); | 
 |     } | 
 |     if (leaf_always_pushing_layer_->layer_tree_host()) { | 
 |       leaf_always_pushing_layer_->SetNeedsPushProperties(); | 
 |       EXPECT_TRUE(base::Contains(leaf_always_pushing_layer_->layer_tree_host() | 
 |                                      ->LayersThatShouldPushProperties(), | 
 |                                  leaf_always_pushing_layer_.get())); | 
 |     } | 
 |  | 
 |     // child_ and grandchild_ don't persist their need to push properties. | 
 |     if (child_->layer_tree_host()) { | 
 |       EXPECT_FALSE(base::Contains( | 
 |           child_->layer_tree_host()->LayersThatShouldPushProperties(), | 
 |           child_.get())); | 
 |     } | 
 |     if (grandchild_->layer_tree_host()) { | 
 |       EXPECT_FALSE(base::Contains( | 
 |           grandchild_->layer_tree_host()->LayersThatShouldPushProperties(), | 
 |           grandchild_.get())); | 
 |     } | 
 |  | 
 |     if (other_root_->layer_tree_host()) { | 
 |       EXPECT_FALSE(base::Contains( | 
 |           other_root_->layer_tree_host()->LayersThatShouldPushProperties(), | 
 |           other_root_.get())); | 
 |     } | 
 |  | 
 |     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: | 
 |         GenerateNewLocalSurfaceId(); | 
 |         layer_tree_host()->SetViewportRectAndScale( | 
 |             gfx::Rect(20, 20), 1.f, GetCurrentLocalSurfaceIdAllocation()); | 
 |         // 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_->MakePushProperties(); | 
 |         // The modified layer needs commit | 
 |         ++expected_push_properties_child_; | 
 |         ++expected_push_properties_grandchild_; | 
 |         break; | 
 |       case 13: | 
 |         child2_->MakePushProperties(); | 
 |         // 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_->MakePushProperties(); | 
 |         // 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; | 
 |     } | 
 |  | 
 |     // The leaf layer always pushes. | 
 |     if (leaf_always_pushing_layer_->layer_tree_host()) | 
 |       ++expected_push_properties_leaf_layer_; | 
 |   } | 
 |  | 
 |   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); | 
 |  | 
 | class LayerTreeHostTestImplLayersPushProperties | 
 |     : public LayerTreeHostTestLayersPushProperties { | 
 |  protected: | 
 |   void BeginTest() override { | 
 |     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(); | 
 |   } | 
 |  | 
 |   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: | 
 |         // Tree doesn't change but the one leaf that always pushes is pushed. | 
 |         ++expected_push_properties_grandchild2_impl_; | 
 |         break; | 
 |       case 3: | 
 |         // 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->active_tree()->root_layer()) | 
 |                           ->push_properties_count()); | 
 |         return; | 
 |       case 4: | 
 |         // 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. | 
 |         expected_push_properties_child_impl_ = 0; | 
 |         expected_push_properties_grandchild_impl_ = 0; | 
 |  | 
 |         // The leaf that always pushes is pushed. | 
 |         ++expected_push_properties_grandchild2_impl_; | 
 |         break; | 
 |       case 7: | 
 |         // The leaf that always pushes is pushed. | 
 |         ++expected_push_properties_grandchild2_impl_; | 
 |  | 
 |         // Child is added back. New layers are initialized. | 
 |         ++expected_push_properties_grandchild_impl_; | 
 |         ++expected_push_properties_child_impl_; | 
 |         break; | 
 |       case 8: | 
 |         // Leaf is removed. | 
 |         expected_push_properties_grandchild_impl_ = 0; | 
 |  | 
 |         // Always pushing. | 
 |         ++expected_push_properties_grandchild2_impl_; | 
 |         break; | 
 |       case 9: | 
 |         // Leaf is added back | 
 |         ++expected_push_properties_grandchild_impl_; | 
 |  | 
 |         // The leaf that always pushes is pushed. | 
 |         ++expected_push_properties_grandchild2_impl_; | 
 |         break; | 
 |       case 10: | 
 |         // The leaf that always pushes is pushed. | 
 |         ++expected_push_properties_grandchild2_impl_; | 
 |         break; | 
 |       case 11: | 
 |         // The leaf that always pushes is pushed. | 
 |         ++expected_push_properties_grandchild2_impl_; | 
 |         break; | 
 |       case 12: | 
 |         // The leaf that always pushes is pushed. | 
 |         ++expected_push_properties_grandchild2_impl_; | 
 |  | 
 |         // This child position was changed. So the subtree needs to push | 
 |         // properties. | 
 |         ++expected_push_properties_child_impl_; | 
 |         ++expected_push_properties_grandchild_impl_; | 
 |         break; | 
 |       case 13: | 
 |         // The position of this child was changed. | 
 |         ++expected_push_properties_child2_impl_; | 
 |  | 
 |         // The leaf that always pushes is pushed. | 
 |         ++expected_push_properties_grandchild2_impl_; | 
 |         break; | 
 |       case 14: | 
 |         // Second child is removed from tree. Don't discard counts because | 
 |         // they are added back before commit. | 
 |  | 
 |         // The leaf that always pushes is pushed. | 
 |         ++expected_push_properties_grandchild2_impl_; | 
 |  | 
 |         // Second child added back. | 
 |         ++expected_push_properties_child_impl_; | 
 |         ++expected_push_properties_grandchild_impl_; | 
 |  | 
 |         break; | 
 |       case 15: | 
 |         // The position of this child was changed. | 
 |         ++expected_push_properties_grandchild_impl_; | 
 |  | 
 |         // The leaf that always pushes is pushed. | 
 |         ++expected_push_properties_grandchild2_impl_; | 
 |         break; | 
 |       case 16: | 
 |         // Second child is invalidated with SetNeedsDisplay | 
 |         ++expected_push_properties_child_impl_; | 
 |  | 
 |         // The leaf that always pushed is pushed. | 
 |         ++expected_push_properties_grandchild2_impl_; | 
 |         break; | 
 |     } | 
 |  | 
 |     PushPropertiesCountingLayerImpl* root_impl_ = nullptr; | 
 |     PushPropertiesCountingLayerImpl* child_impl_ = nullptr; | 
 |     PushPropertiesCountingLayerImpl* child2_impl_ = nullptr; | 
 |     PushPropertiesCountingLayerImpl* grandchild_impl_ = nullptr; | 
 |     PushPropertiesCountingLayerImpl* leaf_always_pushing_layer_impl_ = nullptr; | 
 |  | 
 |     // Pull the layers that we need from the tree assuming the same structure | 
 |     // as LayerTreeHostTestLayersPushProperties | 
 |     root_impl_ = static_cast<PushPropertiesCountingLayerImpl*>( | 
 |         host_impl->active_tree()->root_layer()); | 
 |  | 
 |     LayerTreeImpl* impl = root_impl_->layer_tree_impl(); | 
 |     if (impl->LayerById(child_->id())) { | 
 |       child_impl_ = static_cast<PushPropertiesCountingLayerImpl*>( | 
 |           impl->LayerById(child_->id())); | 
 |  | 
 |       if (impl->LayerById(grandchild_->id())) | 
 |         grandchild_impl_ = static_cast<PushPropertiesCountingLayerImpl*>( | 
 |             impl->LayerById(grandchild_->id())); | 
 |     } | 
 |  | 
 |     if (impl->LayerById(child2_->id())) { | 
 |       child2_impl_ = static_cast<PushPropertiesCountingLayerImpl*>( | 
 |           impl->LayerById(child2_->id())); | 
 |  | 
 |       if (impl->LayerById(leaf_always_pushing_layer_->id())) | 
 |         leaf_always_pushing_layer_impl_ = | 
 |             static_cast<PushPropertiesCountingLayerImpl*>( | 
 |                 impl->LayerById(leaf_always_pushing_layer_->id())); | 
 |     } | 
 |  | 
 |     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_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestImplLayersPushProperties); | 
 |  | 
 | class LayerTreeHostTestPropertyChangesDuringUpdateArePushed | 
 |     : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void SetupTree() override { | 
 |     root_ = Layer::Create(); | 
 |     root_->SetBounds(gfx::Size(1, 1)); | 
 |  | 
 |     bool paint_scrollbar = true; | 
 |     bool has_thumb = false; | 
 |     scrollbar_layer_ = FakePaintedScrollbarLayer::Create( | 
 |         paint_scrollbar, has_thumb, root_->element_id()); | 
 |  | 
 |     root_->AddChild(scrollbar_layer_); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void DidCommitAndDrawFrame() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       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. | 
 |         auto ignore = scrollbar_layer_->IgnoreSetNeedsCommit(); | 
 |  | 
 |         scrollbar_layer_->SetBounds(gfx::Size(30, 30)); | 
 |  | 
 |         EXPECT_TRUE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            scrollbar_layer_.get())); | 
 |         layer_tree_host()->SetNeedsCommit(); | 
 |  | 
 |         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()); | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   scoped_refptr<Layer> root_; | 
 |   scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestPropertyChangesDuringUpdateArePushed); | 
 |  | 
 | class LayerTreeHostTestSetDrawableCausesCommit : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void SetupTree() override { | 
 |     root_ = PushPropertiesCountingLayer::Create(); | 
 |     child_ = PushPropertiesCountingLayer::Create(); | 
 |     root_->AddChild(child_); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void DidCommitAndDrawFrame() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       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. | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |         EXPECT_EQ(0, root_->NumDescendantsThatDrawContent()); | 
 |         root_->reset_push_properties_count(); | 
 |         child_->reset_push_properties_count(); | 
 |         child_->SetIsDrawable(true); | 
 |         EXPECT_EQ(1, root_->NumDescendantsThatDrawContent()); | 
 |         EXPECT_EQ(0u, root_->push_properties_count()); | 
 |         EXPECT_EQ(0u, child_->push_properties_count()); | 
 |         EXPECT_TRUE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_TRUE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |         break; | 
 |       } | 
 |       case 2: | 
 |         EXPECT_EQ(1u, root_->push_properties_count()); | 
 |         EXPECT_EQ(1u, child_->push_properties_count()); | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   scoped_refptr<PushPropertiesCountingLayer> root_; | 
 |   scoped_refptr<PushPropertiesCountingLayer> child_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestSetDrawableCausesCommit); | 
 |  | 
 | class LayerTreeHostTestCasePushPropertiesThreeGrandChildren | 
 |     : public LayerTreeHostTest { | 
 |  protected: | 
 |   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(); | 
 |   } | 
 |  | 
 |   void SetupTree() override { | 
 |     root_ = PushPropertiesCountingLayer::Create(); | 
 |     child_ = PushPropertiesCountingLayer::Create(); | 
 |     grandchild1_ = PushPropertiesCountingLayer::Create(); | 
 |     grandchild2_ = PushPropertiesCountingLayer::Create(); | 
 |     grandchild3_ = PushPropertiesCountingLayer::Create(); | 
 |  | 
 |     root_->AddChild(child_); | 
 |     child_->AddChild(grandchild1_); | 
 |     child_->AddChild(grandchild2_); | 
 |     child_->AddChild(grandchild3_); | 
 |  | 
 |     // Don't set the root layer here. | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     client_.set_bounds(root_->bounds()); | 
 |   } | 
 |  | 
 |   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_; | 
 | }; | 
 |  | 
 | class LayerTreeHostTestPushPropertiesAddingToTreeRequiresPush | 
 |     : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren { | 
 |  protected: | 
 |   void DidCommitAndDrawFrame() override { | 
 |     int last_source_frame_number = layer_tree_host()->SourceFrameNumber() - 1; | 
 |     switch (last_source_frame_number) { | 
 |       case 0: | 
 |         // All layers will need push properties as we set their layer tree host | 
 |         layer_tree_host()->SetRootLayer(root_); | 
 |         EXPECT_TRUE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_TRUE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |         EXPECT_TRUE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild1_.get())); | 
 |         EXPECT_TRUE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild2_.get())); | 
 |         EXPECT_TRUE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild3_.get())); | 
 |         break; | 
 |       case 1: | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestPushPropertiesAddingToTreeRequiresPush); | 
 |  | 
 | class LayerTreeHostTestPushPropertiesRemovingChildStopsRecursion | 
 |     : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren { | 
 |  protected: | 
 |   void DidCommitAndDrawFrame() override { | 
 |     int last_source_frame_number = layer_tree_host()->SourceFrameNumber() - 1; | 
 |     switch (last_source_frame_number) { | 
 |       case 0: | 
 |         layer_tree_host()->SetRootLayer(root_); | 
 |         break; | 
 |       case 1: | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild1_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild2_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild3_.get())); | 
 |  | 
 |         grandchild1_->RemoveFromParent(); | 
 |         grandchild1_->SetPosition(gfx::PointF(1.f, 1.f)); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild2_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild3_.get())); | 
 |  | 
 |         child_->AddChild(grandchild1_); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |         EXPECT_TRUE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild1_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild2_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild3_.get())); | 
 |  | 
 |         grandchild2_->SetPosition(gfx::PointF(1.f, 1.f)); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |         EXPECT_TRUE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild1_.get())); | 
 |         EXPECT_TRUE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild2_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild3_.get())); | 
 |  | 
 |         // grandchild2_ will still need a push properties. | 
 |         grandchild1_->RemoveFromParent(); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |  | 
 |         // grandchild3_ does not need a push properties, so recursing should | 
 |         // no longer be needed. | 
 |         grandchild2_->RemoveFromParent(); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestPushPropertiesRemovingChildStopsRecursion); | 
 |  | 
 | class LayerTreeHostTestPushPropertiesRemovingChildStopsRecursionWithPersistence | 
 |     : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren { | 
 |  protected: | 
 |   void DidCommitAndDrawFrame() override { | 
 |     // The grand children are set to need push properties, to verify the impact | 
 |     // on their ancestors. | 
 |     grandchild1_->SetNeedsPushProperties(); | 
 |     grandchild2_->SetNeedsPushProperties(); | 
 |  | 
 |     int last_source_frame_number = layer_tree_host()->SourceFrameNumber() - 1; | 
 |     switch (last_source_frame_number) { | 
 |       case 0: | 
 |         layer_tree_host()->SetRootLayer(root_); | 
 |         break; | 
 |       case 1: | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |         EXPECT_TRUE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild1_.get())); | 
 |         EXPECT_TRUE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild2_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild3_.get())); | 
 |  | 
 |         // grandchild2_ will still need a push properties. | 
 |         grandchild1_->RemoveFromParent(); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |  | 
 |         // grandchild3_ does not need a push properties, so recursing should | 
 |         // no longer be needed. | 
 |         grandchild2_->RemoveFromParent(); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F( | 
 |     LayerTreeHostTestPushPropertiesRemovingChildStopsRecursionWithPersistence); | 
 |  | 
 | class LayerTreeHostTestPushPropertiesSetPropertiesWhileOutsideTree | 
 |     : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren { | 
 |  protected: | 
 |   void DidCommitAndDrawFrame() override { | 
 |     int last_source_frame_number = layer_tree_host()->SourceFrameNumber() - 1; | 
 |     switch (last_source_frame_number) { | 
 |       case 0: | 
 |         layer_tree_host()->SetRootLayer(root_); | 
 |         break; | 
 |       case 1: | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild1_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild2_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild3_.get())); | 
 |  | 
 |         // Change grandchildren while their parent is not in the tree. | 
 |         child_->RemoveFromParent(); | 
 |         grandchild1_->SetPosition(gfx::PointF(1.f, 1.f)); | 
 |         grandchild2_->SetPosition(gfx::PointF(1.f, 1.f)); | 
 |         root_->AddChild(child_); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_TRUE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |         EXPECT_TRUE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild1_.get())); | 
 |         EXPECT_TRUE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild2_.get())); | 
 |         EXPECT_TRUE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild3_.get())); | 
 |  | 
 |         grandchild1_->RemoveFromParent(); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_TRUE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |  | 
 |         grandchild2_->RemoveFromParent(); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_TRUE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |  | 
 |         grandchild3_->RemoveFromParent(); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_TRUE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |  | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F( | 
 |     LayerTreeHostTestPushPropertiesSetPropertiesWhileOutsideTree); | 
 |  | 
 | class LayerTreeHostTestPushPropertiesSetPropertyInParentThenChild | 
 |     : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren { | 
 |  protected: | 
 |   void DidCommitAndDrawFrame() override { | 
 |     int last_source_frame_number = layer_tree_host()->SourceFrameNumber() - 1; | 
 |     switch (last_source_frame_number) { | 
 |       case 0: | 
 |         layer_tree_host()->SetRootLayer(root_); | 
 |         break; | 
 |       case 1: | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild1_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild2_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild3_.get())); | 
 |  | 
 |         child_->SetPosition(gfx::PointF(1.f, 1.f)); | 
 |         grandchild1_->SetPosition(gfx::PointF(1.f, 1.f)); | 
 |         grandchild2_->SetPosition(gfx::PointF(1.f, 1.f)); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_TRUE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |         EXPECT_TRUE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild1_.get())); | 
 |         EXPECT_TRUE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild2_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild3_.get())); | 
 |  | 
 |         grandchild1_->RemoveFromParent(); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_TRUE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |  | 
 |         grandchild2_->RemoveFromParent(); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_TRUE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |  | 
 |         child_->RemoveFromParent(); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |  | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F( | 
 |     LayerTreeHostTestPushPropertiesSetPropertyInParentThenChild); | 
 |  | 
 | class LayerTreeHostTestPushPropertiesSetPropertyInChildThenParent | 
 |     : public LayerTreeHostTestCasePushPropertiesThreeGrandChildren { | 
 |  protected: | 
 |   void DidCommitAndDrawFrame() override { | 
 |     int last_source_frame_number = layer_tree_host()->SourceFrameNumber() - 1; | 
 |     switch (last_source_frame_number) { | 
 |       case 0: | 
 |         layer_tree_host()->SetRootLayer(root_); | 
 |         break; | 
 |       case 1: | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild1_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild2_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild3_.get())); | 
 |  | 
 |         grandchild1_->SetPosition(gfx::PointF(1.f, 1.f)); | 
 |         grandchild2_->SetPosition(gfx::PointF(1.f, 1.f)); | 
 |         child_->SetPosition(gfx::PointF(1.f, 1.f)); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_TRUE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |         EXPECT_TRUE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild1_.get())); | 
 |         EXPECT_TRUE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild2_.get())); | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            grandchild3_.get())); | 
 |  | 
 |         grandchild1_->RemoveFromParent(); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_TRUE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |  | 
 |         grandchild2_->RemoveFromParent(); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |         EXPECT_TRUE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), child_.get())); | 
 |  | 
 |         child_->RemoveFromParent(); | 
 |  | 
 |         EXPECT_FALSE(base::Contains( | 
 |             layer_tree_host()->LayersThatShouldPushProperties(), root_.get())); | 
 |  | 
 |         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) {} | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     ++num_commits_; | 
 |     switch (num_commits_) { | 
 |       case 1: | 
 |         EXPECT_EQ(0, callback_count_); | 
 |         callback_count_ = 0; | 
 |         SetCallback(host_impl, true); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 2: | 
 |         EXPECT_EQ(1, callback_count_); | 
 |         callback_count_ = 0; | 
 |         SetCallback(host_impl, 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); | 
 |   } | 
 |  | 
 |   void AfterTest() override { EXPECT_EQ(3, num_commits_); } | 
 |  | 
 |   void SetCallback(LayerTreeHostImpl* host_impl, bool enable) { | 
 |     host_impl->SetTreeActivationCallback( | 
 |         enable | 
 |             ? base::BindRepeating( | 
 |                   &LayerTreeHostTestTreeActivationCallback::ActivationCallback, | 
 |                   base::Unretained(this)) | 
 |             : base::RepeatingClosure()); | 
 |   } | 
 |  | 
 |   void ActivationCallback() { ++callback_count_; } | 
 |  | 
 |   int num_commits_; | 
 |   int callback_count_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestTreeActivationCallback); | 
 |  | 
 | class LayerInvalidateCausesDraw : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerInvalidateCausesDraw() : num_commits_(0), num_draws_(0) {} | 
 |  | 
 |   void BeginTest() override { | 
 |     ASSERT_TRUE(invalidate_layer_) | 
 |         << "Derived tests must set this in SetupTree"; | 
 |  | 
 |     // One initial commit. | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void DidCommitAndDrawFrame() override { | 
 |     // After commit, invalidate the layer.  This should cause a commit. | 
 |     if (layer_tree_host()->SourceFrameNumber() == 1) | 
 |       invalidate_layer_->SetNeedsDisplay(); | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* impl) override { | 
 |     num_draws_++; | 
 |     if (impl->active_tree()->source_frame_number() == 1) | 
 |       EndTest(); | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | 
 |     num_commits_++; | 
 |   } | 
 |  | 
 |   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: | 
 |   void SetupTree() override { | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     scoped_refptr<VideoLayer> video_layer = | 
 |         VideoLayer::Create(&provider_, media::VIDEO_ROTATION_0); | 
 |     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); | 
 |  | 
 | class LayerTreeHostTestPushHiddenLayer : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     root_layer_ = Layer::Create(); | 
 |     root_layer_->SetPosition(gfx::PointF()); | 
 |     root_layer_->SetBounds(gfx::Size(10, 10)); | 
 |  | 
 |     parent_layer_ = SolidColorLayer::Create(); | 
 |     parent_layer_->SetPosition(gfx::PointF()); | 
 |     parent_layer_->SetBounds(gfx::Size(10, 10)); | 
 |     parent_layer_->SetIsDrawable(true); | 
 |     root_layer_->AddChild(parent_layer_); | 
 |  | 
 |     child_layer_ = SolidColorLayer::Create(); | 
 |     child_layer_->SetPosition(gfx::PointF()); | 
 |     child_layer_->SetBounds(gfx::Size(10, 10)); | 
 |     child_layer_->SetIsDrawable(true); | 
 |     parent_layer_->AddChild(child_layer_); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_layer_); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommitAndDrawFrame() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         // The layer type used does not need to push properties every frame. | 
 |         EXPECT_FALSE( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            child_layer_.get())); | 
 |  | 
 |         // 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( | 
 |             base::Contains(layer_tree_host()->LayersThatShouldPushProperties(), | 
 |                            child_layer_.get())); | 
 |  | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override { | 
 |     LayerImpl* child = impl->active_tree()->LayerById(child_layer_->id()); | 
 |  | 
 |     switch (impl->active_tree()->source_frame_number()) { | 
 |       case 1: | 
 |         EXPECT_EQ(gfx::Size(5, 5).ToString(), child->bounds().ToString()); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   scoped_refptr<Layer> root_layer_; | 
 |   scoped_refptr<SolidColorLayer> parent_layer_; | 
 |   scoped_refptr<SolidColorLayer> child_layer_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestPushHiddenLayer); | 
 |  | 
 | class LayerTreeHostTestUpdateLayerInEmptyViewport : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     root_layer_ = FakePictureLayer::Create(&client_); | 
 |     root_layer_->SetBounds(gfx::Size(10, 10)); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_layer_); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     client_.set_bounds(root_layer_->bounds()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { | 
 |     // The viewport is empty, but we still need to update layers on the main | 
 |     // thread. | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(0, 0), 1.f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   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(), 0); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   FakeContentLayerClient client_; | 
 |   scoped_refptr<FakePictureLayer> root_layer_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestUpdateLayerInEmptyViewport); | 
 |  | 
 | class LayerTreeHostTestElasticOverscroll : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestElasticOverscroll() | 
 |       : scroll_elasticity_helper_(nullptr), num_draws_(0) { | 
 |     SetUseLayerLists(); | 
 |   } | 
 |  | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     settings->enable_elastic_overscroll = true; | 
 |   } | 
 |  | 
 |   void SetupTree() override { | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     root_layer_ = layer_tree_host()->root_layer(); | 
 |     SetupViewport(root_layer_, root_layer_->bounds(), root_layer_->bounds()); | 
 |  | 
 |     scoped_refptr<Layer> content_layer = FakePictureLayer::Create(&client_); | 
 |     content_layer_id_ = content_layer->id(); | 
 |     content_layer->SetBounds(gfx::Size(10, 10)); | 
 |     CopyProperties(layer_tree_host()->OuterViewportScrollLayerForTesting(), | 
 |                    content_layer.get()); | 
 |     root_layer_->AddChild(content_layer); | 
 |  | 
 |     client_.set_bounds(content_layer->bounds()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     if (host_impl->sync_tree()->source_frame_number() == 0) { | 
 |       scroll_elasticity_helper_ = host_impl->CreateScrollElasticityHelper(); | 
 |     } | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     num_draws_++; | 
 |     LayerImpl* content_layer_impl = | 
 |         host_impl->active_tree()->LayerById(content_layer_id_); | 
 |     gfx::Transform expected_draw_transform; | 
 |     switch (num_draws_) { | 
 |       case 1: | 
 |         // Initially, there's no overscroll. | 
 |         EXPECT_EQ(expected_draw_transform, content_layer_impl->DrawTransform()); | 
 |  | 
 |         // Begin overscrolling. This should be reflected in the draw transform | 
 |         // the next time we draw. | 
 |         scroll_elasticity_helper_->SetStretchAmount(gfx::Vector2dF(5.f, 6.f)); | 
 |         break; | 
 |       case 2: | 
 |         expected_draw_transform.Translate(-5.0, -6.0); | 
 |         EXPECT_EQ(expected_draw_transform, content_layer_impl->DrawTransform()); | 
 |  | 
 |         scroll_elasticity_helper_->SetStretchAmount(gfx::Vector2dF(3.f, 2.f)); | 
 |         break; | 
 |       case 3: | 
 |         expected_draw_transform.Translate(-3.0, -2.0); | 
 |         EXPECT_EQ(expected_draw_transform, content_layer_impl->DrawTransform()); | 
 |  | 
 |         scroll_elasticity_helper_->SetStretchAmount(gfx::Vector2dF()); | 
 |         break; | 
 |       case 4: | 
 |         EXPECT_EQ(expected_draw_transform, content_layer_impl->DrawTransform()); | 
 |         EndTest(); | 
 |         break; | 
 |       default: | 
 |         NOTREACHED(); | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   FakeContentLayerClient client_; | 
 |   Layer* root_layer_; | 
 |   ScrollElasticityHelper* scroll_elasticity_helper_; | 
 |   int content_layer_id_; | 
 |   int num_draws_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestElasticOverscroll); | 
 |  | 
 | struct TestSwapPromiseResult { | 
 |   TestSwapPromiseResult() | 
 |       : did_activate_called(false), | 
 |         did_swap_called(false), | 
 |         did_not_swap_called(false), | 
 |         dtor_called(false), | 
 |         reason(SwapPromise::COMMIT_FAILS) {} | 
 |  | 
 |   bool did_activate_called; | 
 |   bool did_swap_called; | 
 |   bool did_not_swap_called; | 
 |   bool dtor_called; | 
 |   SwapPromise::DidNotSwapReason reason; | 
 |   base::Lock lock; | 
 | }; | 
 |  | 
 | class TestSwapPromise : public SwapPromise { | 
 |  public: | 
 |   explicit TestSwapPromise(TestSwapPromiseResult* result) : result_(result) {} | 
 |  | 
 |   ~TestSwapPromise() override { | 
 |     base::AutoLock lock(result_->lock); | 
 |     result_->dtor_called = true; | 
 |   } | 
 |  | 
 |   void DidActivate() override { | 
 |     base::AutoLock lock(result_->lock); | 
 |     EXPECT_FALSE(result_->did_activate_called); | 
 |     EXPECT_FALSE(result_->did_swap_called); | 
 |     EXPECT_TRUE(!result_->did_not_swap_called || | 
 |                 action_ == SwapPromise::DidNotSwapAction::KEEP_ACTIVE); | 
 |     result_->did_activate_called = true; | 
 |   } | 
 |  | 
 |   void WillSwap(viz::CompositorFrameMetadata* metadata) override { | 
 |     base::AutoLock lock(result_->lock); | 
 |     EXPECT_FALSE(result_->did_swap_called); | 
 |     EXPECT_TRUE(!result_->did_not_swap_called || | 
 |                 action_ == SwapPromise::DidNotSwapAction::KEEP_ACTIVE); | 
 |     result_->did_swap_called = true; | 
 |   } | 
 |  | 
 |   void DidSwap() override {} | 
 |  | 
 |   DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override { | 
 |     base::AutoLock lock(result_->lock); | 
 |     EXPECT_FALSE(result_->did_swap_called); | 
 |     EXPECT_FALSE(result_->did_not_swap_called); | 
 |     EXPECT_FALSE(result_->did_activate_called && | 
 |                  reason != DidNotSwapReason::SWAP_FAILS); | 
 |     result_->did_not_swap_called = true; | 
 |     result_->reason = reason; | 
 |     return action_; | 
 |   } | 
 |  | 
 |   void set_action(DidNotSwapAction action) { action_ = action; } | 
 |  | 
 |   int64_t TraceId() const override { return 0; } | 
 |  | 
 |  private: | 
 |   // Not owned. | 
 |   TestSwapPromiseResult* result_; | 
 |   DidNotSwapAction action_ = DidNotSwapAction::BREAK_PROMISE; | 
 | }; | 
 |  | 
 | class PinnedLayerTreeSwapPromise : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override { | 
 |     layer_tree_host()->SetNeedsCommitWithForcedRedraw(); | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     int frame = host_impl->active_tree()->source_frame_number(); | 
 |     if (frame == -1) { | 
 |       host_impl->active_tree()->QueuePinnedSwapPromise( | 
 |           std::make_unique<TestSwapPromise>( | 
 |               &pinned_active_swap_promise_result_)); | 
 |       host_impl->pending_tree()->QueueSwapPromise( | 
 |           std::make_unique<TestSwapPromise>(&pending_swap_promise_result_)); | 
 |       host_impl->active_tree()->QueueSwapPromise( | 
 |           std::make_unique<TestSwapPromise>(&active_swap_promise_result_)); | 
 |     } | 
 |   } | 
 |  | 
 |   void DisplayDidDrawAndSwapOnThread() override { EndTest(); } | 
 |  | 
 |   void AfterTest() override { | 
 |     // The pending swap promise should activate and swap. | 
 |     EXPECT_TRUE(pending_swap_promise_result_.did_activate_called); | 
 |     EXPECT_TRUE(pending_swap_promise_result_.did_swap_called); | 
 |  | 
 |     // The active swap promise should fail to swap (it is cancelled by | 
 |     // the activation of a new frame). | 
 |     EXPECT_FALSE(active_swap_promise_result_.did_activate_called); | 
 |     EXPECT_FALSE(active_swap_promise_result_.did_swap_called); | 
 |     EXPECT_TRUE(active_swap_promise_result_.did_not_swap_called); | 
 |     EXPECT_EQ(active_swap_promise_result_.reason, SwapPromise::SWAP_FAILS); | 
 |  | 
 |     // The pinned active swap promise should not activate, but should swap. | 
 |     EXPECT_FALSE(pinned_active_swap_promise_result_.did_activate_called); | 
 |     EXPECT_TRUE(pinned_active_swap_promise_result_.did_swap_called); | 
 |   } | 
 |  | 
 |   TestSwapPromiseResult pending_swap_promise_result_; | 
 |   TestSwapPromiseResult active_swap_promise_result_; | 
 |   TestSwapPromiseResult pinned_active_swap_promise_result_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(PinnedLayerTreeSwapPromise); | 
 |  | 
 | class LayerTreeHostTestBreakSwapPromise : public LayerTreeHostTest { | 
 |  protected: | 
 |   LayerTreeHostTestBreakSwapPromise() | 
 |       : commit_count_(0), commit_complete_count_(0) {} | 
 |  | 
 |   void WillBeginMainFrame() override { | 
 |     ASSERT_LE(commit_count_, 2); | 
 |     std::unique_ptr<SwapPromise> swap_promise( | 
 |         new TestSwapPromise(&swap_promise_result_[commit_count_])); | 
 |     layer_tree_host()->GetSwapPromiseManager()->QueueSwapPromise( | 
 |         std::move(swap_promise)); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommit() override { | 
 |     commit_count_++; | 
 |     if (commit_count_ == 2) { | 
 |       // This commit will finish. | 
 |       layer_tree_host()->SetNeedsCommit(); | 
 |     } | 
 |   } | 
 |  | 
 |   void WillActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     if (host_impl->pending_tree()) { | 
 |       int frame = host_impl->pending_tree()->source_frame_number(); | 
 |       base::AutoLock lock(swap_promise_result_[frame].lock); | 
 |       EXPECT_FALSE(swap_promise_result_[frame].did_activate_called); | 
 |       EXPECT_FALSE(swap_promise_result_[frame].did_swap_called); | 
 |     } | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     int frame = host_impl->active_tree()->source_frame_number(); | 
 |     base::AutoLock lock(swap_promise_result_[frame].lock); | 
 |     EXPECT_TRUE(swap_promise_result_[frame].did_activate_called); | 
 |     EXPECT_FALSE(swap_promise_result_[frame].did_swap_called); | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     commit_complete_count_++; | 
 |     if (commit_complete_count_ == 1) { | 
 |       // This commit will be aborted because no actual update. | 
 |       PostSetNeedsUpdateLayersToMainThread(); | 
 |     } | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     int frame = host_impl->active_tree()->source_frame_number(); | 
 |     if (frame == 2) { | 
 |       EndTest(); | 
 |     } | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     // 3 commits are scheduled. 2 completes. 1 is aborted. | 
 |     EXPECT_EQ(commit_count_, 3); | 
 |     EXPECT_EQ(commit_complete_count_, 2); | 
 |  | 
 |     { | 
 |       // 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); | 
 |     } | 
 |  | 
 |     { | 
 |       // The second commit is aborted since it contains no updates. | 
 |       base::AutoLock lock(swap_promise_result_[1].lock); | 
 |       EXPECT_FALSE(swap_promise_result_[1].did_activate_called); | 
 |       EXPECT_FALSE(swap_promise_result_[1].did_swap_called); | 
 |       EXPECT_TRUE(swap_promise_result_[1].did_not_swap_called); | 
 |       EXPECT_EQ(SwapPromise::COMMIT_NO_UPDATE, swap_promise_result_[1].reason); | 
 |       EXPECT_TRUE(swap_promise_result_[1].dtor_called); | 
 |     } | 
 |  | 
 |     { | 
 |       // 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_TRUE(swap_promise_result_[2].did_activate_called); | 
 |       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); | 
 |     } | 
 |   } | 
 |  | 
 |   int commit_count_; | 
 |   int commit_complete_count_; | 
 |   TestSwapPromiseResult swap_promise_result_[3]; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestBreakSwapPromise); | 
 |  | 
 | class LayerTreeHostTestKeepSwapPromise : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestKeepSwapPromise() = default; | 
 |  | 
 |   void BeginTest() override { | 
 |     layer_ = SolidColorLayer::Create(); | 
 |     layer_->SetIsDrawable(true); | 
 |     layer_->SetBounds(gfx::Size(10, 10)); | 
 |     layer_tree_host()->SetRootLayer(layer_); | 
 |     gfx::Size bounds(100, 100); | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(bounds), 1.f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void DidCommit() override { | 
 |     MainThreadTaskRunner()->PostTask( | 
 |         FROM_HERE, | 
 |         base::BindOnce(&LayerTreeHostTestKeepSwapPromise::ChangeFrame, | 
 |                        base::Unretained(this))); | 
 |   } | 
 |  | 
 |   void ChangeFrame() { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         layer_->SetBounds(gfx::Size(10, 11)); | 
 |         layer_tree_host()->GetSwapPromiseManager()->QueueSwapPromise( | 
 |             std::make_unique<TestSwapPromise>(&swap_promise_result_)); | 
 |         break; | 
 |       case 2: | 
 |         break; | 
 |       default: | 
 |         NOTREACHED(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void WillActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     if (host_impl->pending_tree()) { | 
 |       if (host_impl->pending_tree()->source_frame_number() == 1) { | 
 |         base::AutoLock lock(swap_promise_result_.lock); | 
 |         EXPECT_FALSE(swap_promise_result_.did_activate_called); | 
 |         EXPECT_FALSE(swap_promise_result_.did_swap_called); | 
 |         SetCallback(host_impl, true); | 
 |       } else { | 
 |         SetCallback(host_impl, false); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     if (host_impl->active_tree()->source_frame_number() == 1) { | 
 |       base::AutoLock lock(swap_promise_result_.lock); | 
 |       EXPECT_TRUE(swap_promise_result_.did_activate_called); | 
 |       EXPECT_FALSE(swap_promise_result_.did_swap_called); | 
 |     } | 
 |   } | 
 |  | 
 |   void ActivationCallback() { | 
 |     // DidActivate needs to happen before the tree activation callback. | 
 |     base::AutoLock lock(swap_promise_result_.lock); | 
 |     EXPECT_TRUE(swap_promise_result_.did_activate_called); | 
 |   } | 
 |  | 
 |   void SetCallback(LayerTreeHostImpl* host_impl, bool enable) { | 
 |     host_impl->SetTreeActivationCallback( | 
 |         enable ? base::BindRepeating( | 
 |                      &LayerTreeHostTestKeepSwapPromise::ActivationCallback, | 
 |                      base::Unretained(this)) | 
 |                : base::RepeatingClosure()); | 
 |   } | 
 |  | 
 |   void DisplayDidDrawAndSwapOnThread() override { | 
 |     if (num_swaps_++ >= 1) { | 
 |       // The commit changes layers so it should cause a swap. | 
 |       base::AutoLock lock(swap_promise_result_.lock); | 
 |       EXPECT_TRUE(swap_promise_result_.did_swap_called); | 
 |       EXPECT_FALSE(swap_promise_result_.did_not_swap_called); | 
 |       EXPECT_TRUE(swap_promise_result_.dtor_called); | 
 |       EndTest(); | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   int num_swaps_ = 0; | 
 |   scoped_refptr<Layer> layer_; | 
 |   TestSwapPromiseResult swap_promise_result_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestKeepSwapPromise); | 
 |  | 
 | class LayerTreeHostTestKeepSwapPromiseMFBA : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestKeepSwapPromiseMFBA() = default; | 
 |  | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     settings->main_frame_before_activation_enabled = true; | 
 |   } | 
 |  | 
 |   void BeginTest() override { | 
 |     layer_ = SolidColorLayer::Create(); | 
 |     layer_->SetIsDrawable(true); | 
 |     layer_->SetBounds(gfx::Size(10, 10)); | 
 |     layer_tree_host()->SetRootLayer(layer_); | 
 |     gfx::Size bounds(100, 100); | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(bounds), 1.f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void BeginCommitOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     // Safe to check frame number here because main thread is blocked. | 
 |     if (layer_tree_host()->SourceFrameNumber() == 0) { | 
 |       host_impl->BlockNotifyReadyToActivateForTesting(true); | 
 |     } else { | 
 |       NOTREACHED(); | 
 |     } | 
 |   } | 
 |  | 
 |   void DidCommit() override { | 
 |     MainThreadTaskRunner()->PostTask( | 
 |         FROM_HERE, | 
 |         base::BindOnce(&LayerTreeHostTestKeepSwapPromiseMFBA::ChangeFrame, | 
 |                        base::Unretained(this))); | 
 |   } | 
 |  | 
 |   void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl, | 
 |                                      CommitEarlyOutReason reason) override { | 
 |     base::AutoLock lock(swap_promise_result_.lock); | 
 |     EXPECT_FALSE(swap_promise_result_.did_not_swap_called); | 
 |     EXPECT_FALSE(swap_promise_result_.did_activate_called); | 
 |     EXPECT_FALSE(swap_promise_result_.did_swap_called); | 
 |     host_impl->BlockNotifyReadyToActivateForTesting(false); | 
 |   } | 
 |  | 
 |   void ChangeFrame() { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         // Make no changes so that we abort the next commit caused by queuing | 
 |         // the swap promise. | 
 |         layer_tree_host()->GetSwapPromiseManager()->QueueSwapPromise( | 
 |             std::make_unique<TestSwapPromise>(&swap_promise_result_)); | 
 |         layer_tree_host()->SetNeedsUpdateLayers(); | 
 |         break; | 
 |       case 2: | 
 |         break; | 
 |       default: | 
 |         NOTREACHED(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void WillActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     if (host_impl->pending_tree()) { | 
 |       if (host_impl->pending_tree()->source_frame_number() == 1) { | 
 |         base::AutoLock lock(swap_promise_result_.lock); | 
 |         EXPECT_FALSE(swap_promise_result_.did_activate_called); | 
 |         EXPECT_FALSE(swap_promise_result_.did_swap_called); | 
 |         SetCallback(host_impl, true); | 
 |       } else { | 
 |         SetCallback(host_impl, false); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     if (host_impl->active_tree()->source_frame_number() == 1) { | 
 |       base::AutoLock lock(swap_promise_result_.lock); | 
 |       EXPECT_TRUE(swap_promise_result_.did_activate_called); | 
 |       EXPECT_FALSE(swap_promise_result_.did_swap_called); | 
 |     } | 
 |   } | 
 |  | 
 |   void ActivationCallback() { | 
 |     // DidActivate needs to happen before the tree activation callback. | 
 |     base::AutoLock lock(swap_promise_result_.lock); | 
 |     EXPECT_TRUE(swap_promise_result_.did_activate_called); | 
 |   } | 
 |  | 
 |   void SetCallback(LayerTreeHostImpl* host_impl, bool enable) { | 
 |     host_impl->SetTreeActivationCallback( | 
 |         enable ? base::BindRepeating( | 
 |                      &LayerTreeHostTestKeepSwapPromiseMFBA::ActivationCallback, | 
 |                      base::Unretained(this)) | 
 |                : base::RepeatingClosure()); | 
 |   } | 
 |  | 
 |   void DisplayDidDrawAndSwapOnThread() override { | 
 |     num_swaps_++; | 
 |     base::AutoLock lock(swap_promise_result_.lock); | 
 |     EXPECT_TRUE(swap_promise_result_.did_swap_called); | 
 |     EXPECT_FALSE(swap_promise_result_.did_not_swap_called); | 
 |     EXPECT_TRUE(swap_promise_result_.dtor_called); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void AfterTest() override { EXPECT_EQ(1, num_swaps_); } | 
 |  | 
 |  private: | 
 |   int num_swaps_ = 0; | 
 |   scoped_refptr<Layer> layer_; | 
 |   TestSwapPromiseResult swap_promise_result_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestKeepSwapPromiseMFBA); | 
 |  | 
 | class LayerTreeHostTestDeferSwapPromiseForVisibility | 
 |     : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void SetVisibleFalseAndQueueSwapPromise() { | 
 |     layer_tree_host()->SetVisible(false); | 
 |     auto swap_promise = | 
 |         std::make_unique<TestSwapPromise>(&swap_promise_result_); | 
 |     swap_promise->set_action(SwapPromise::DidNotSwapAction::KEEP_ACTIVE); | 
 |     layer_tree_host()->GetSwapPromiseManager()->QueueSwapPromise( | 
 |         std::move(swap_promise)); | 
 |   } | 
 |  | 
 |   void WillBeginImplFrameOnThread(LayerTreeHostImpl* impl, | 
 |                                   const viz::BeginFrameArgs& args) override { | 
 |     if (!sent_queue_request_) { | 
 |       sent_queue_request_ = true; | 
 |       MainThreadTaskRunner()->PostTask( | 
 |           FROM_HERE, | 
 |           base::BindOnce(&LayerTreeHostTestDeferSwapPromiseForVisibility:: | 
 |                              SetVisibleFalseAndQueueSwapPromise, | 
 |                          base::Unretained(this))); | 
 |     } | 
 |   } | 
 |  | 
 |   void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl, | 
 |                                      CommitEarlyOutReason reason) override { | 
 |     MainThreadTaskRunner()->PostTask( | 
 |         FROM_HERE, | 
 |         base::BindOnce(&LayerTreeHostTestDeferSwapPromiseForVisibility:: | 
 |                            CheckSwapPromiseNotCalled, | 
 |                        base::Unretained(this))); | 
 |   } | 
 |  | 
 |   void CheckSwapPromiseNotCalled() { | 
 |     { | 
 |       base::AutoLock lock(swap_promise_result_.lock); | 
 |       EXPECT_FALSE(swap_promise_result_.did_activate_called); | 
 |       EXPECT_FALSE(swap_promise_result_.did_swap_called); | 
 |       EXPECT_TRUE(swap_promise_result_.did_not_swap_called); | 
 |       EXPECT_EQ(SwapPromise::COMMIT_FAILS, swap_promise_result_.reason); | 
 |       EXPECT_FALSE(swap_promise_result_.dtor_called); | 
 |     } | 
 |     layer_tree_host()->SetVisible(true); | 
 |   } | 
 |  | 
 |   void DidCommitAndDrawFrame() override { | 
 |     { | 
 |       base::AutoLock lock(swap_promise_result_.lock); | 
 |       EXPECT_TRUE(swap_promise_result_.did_activate_called); | 
 |       EXPECT_TRUE(swap_promise_result_.did_swap_called); | 
 |       EXPECT_TRUE(swap_promise_result_.dtor_called); | 
 |     } | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   TestSwapPromiseResult swap_promise_result_; | 
 |   bool sent_queue_request_ = false; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestDeferSwapPromiseForVisibility); | 
 |  | 
 | 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->GetSwapPromiseManager() | 
 |                              : nullptr), | 
 |             layer_tree_host_impl), | 
 |         set_needs_commit_count_(set_needs_commit_count) {} | 
 |  | 
 |   ~SimpleSwapPromiseMonitor() override = default; | 
 |  | 
 |   void OnSetNeedsCommitOnMain() override { (*set_needs_commit_count_)++; } | 
 |  | 
 |   void OnSetNeedsRedrawOnImpl() override { | 
 |     ADD_FAILURE() << "Should not get called on main thread."; | 
 |   } | 
 |  | 
 |  private: | 
 |   int* set_needs_commit_count_; | 
 | }; | 
 |  | 
 | class LayerTreeHostTestSwapPromiseDuringCommit : public LayerTreeHostTest { | 
 |  protected: | 
 |   LayerTreeHostTestSwapPromiseDuringCommit() = default; | 
 |  | 
 |   void WillBeginMainFrame() override { | 
 |     if (TestEnded()) | 
 |       return; | 
 |  | 
 |     std::unique_ptr<SwapPromise> swap_promise( | 
 |         new TestSwapPromise(&swap_promise_result_[0])); | 
 |     int set_needs_commit_count = 0; | 
 |     int set_needs_redraw_count = 0; | 
 |  | 
 |     { | 
 |       std::unique_ptr<SimpleSwapPromiseMonitor> swap_promise_monitor( | 
 |           new SimpleSwapPromiseMonitor(layer_tree_host(), nullptr, | 
 |                                        &set_needs_commit_count, | 
 |                                        &set_needs_redraw_count)); | 
 |       layer_tree_host()->QueueSwapPromise(std::move(swap_promise)); | 
 |       // Queueing a swap promise from WillBeginMainFrame should not cause | 
 |       // another commit to be scheduled. | 
 |       EXPECT_EQ(0, set_needs_commit_count); | 
 |     } | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidBeginMainFrame() override { | 
 |     if (TestEnded()) | 
 |       return; | 
 |  | 
 |     std::unique_ptr<SwapPromise> swap_promise( | 
 |         new TestSwapPromise(&swap_promise_result_[1])); | 
 |     int set_needs_commit_count = 0; | 
 |     int set_needs_redraw_count = 0; | 
 |  | 
 |     { | 
 |       std::unique_ptr<SimpleSwapPromiseMonitor> swap_promise_monitor( | 
 |           new SimpleSwapPromiseMonitor(layer_tree_host(), nullptr, | 
 |                                        &set_needs_commit_count, | 
 |                                        &set_needs_redraw_count)); | 
 |       layer_tree_host()->QueueSwapPromise(std::move(swap_promise)); | 
 |       // Queueing a swap promise from DidBeginMainFrame should not cause a | 
 |       // subsequent main frame to be scheduled. | 
 |       EXPECT_EQ(0, set_needs_commit_count); | 
 |     } | 
 |  | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   TestSwapPromiseResult swap_promise_result_[2]; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestSwapPromiseDuringCommit); | 
 |  | 
 | class LayerTreeHostTestSimpleSwapPromiseMonitor : public LayerTreeHostTest { | 
 |  public: | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void WillBeginMainFrame() override { | 
 |     if (TestEnded()) | 
 |       return; | 
 |  | 
 |     int set_needs_commit_count = 0; | 
 |     int set_needs_redraw_count = 0; | 
 |  | 
 |     { | 
 |       std::unique_ptr<SimpleSwapPromiseMonitor> swap_promise_monitor( | 
 |           new SimpleSwapPromiseMonitor(layer_tree_host(), nullptr, | 
 |                                        &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); | 
 |     } | 
 |  | 
 |     // 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); | 
 |  | 
 |     { | 
 |       std::unique_ptr<SimpleSwapPromiseMonitor> swap_promise_monitor( | 
 |           new SimpleSwapPromiseMonitor(layer_tree_host(), nullptr, | 
 |                                        &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); | 
 |     } | 
 |  | 
 |     { | 
 |       std::unique_ptr<SimpleSwapPromiseMonitor> swap_promise_monitor( | 
 |           new SimpleSwapPromiseMonitor(layer_tree_host(), nullptr, | 
 |                                        &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); | 
 |     } | 
 |  | 
 |     EndTest(); | 
 |   } | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSimpleSwapPromiseMonitor); | 
 |  | 
 | class LayerTreeHostTestHighResRequiredAfterEvictingUIResources | 
 |     : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     ui_resource_ = | 
 |         FakeScopedUIResource::Create(layer_tree_host()->GetUIResourceManager()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     if (TestEnded()) | 
 |       return; | 
 |  | 
 |     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->RequiresHighResToDraw()); | 
 |  | 
 |     MainThreadTaskRunner()->PostTask( | 
 |         FROM_HERE, | 
 |         base::BindOnce( | 
 |             &LayerTreeHostTestHighResRequiredAfterEvictingUIResources:: | 
 |                 DeleteResourceAndEndTest, | 
 |             base::Unretained(this))); | 
 |   } | 
 |  | 
 |   void DeleteResourceAndEndTest() { | 
 |     // This must be destroyed before the test ends and tears down the | 
 |     // LayerTreeHost. It causes another commit+activation though, which | 
 |     // may run before the test exits. | 
 |     ui_resource_ = nullptr; | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   std::unique_ptr<FakeScopedUIResource> ui_resource_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestHighResRequiredAfterEvictingUIResources); | 
 |  | 
 | class LayerTreeHostTestGpuRasterizationDisabled : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetUpUnboundContextProviders( | 
 |       viz::TestContextProvider* context_provider, | 
 |       viz::TestContextProvider* worker_provider) override { | 
 |     // The test contexts have gpu raster disabled by default. | 
 |     gpu::Capabilities caps = | 
 |         context_provider->UnboundTestContextGL()->test_capabilities(); | 
 |     EXPECT_FALSE(caps.gpu_rasterization); | 
 |     gpu::Capabilities worker_caps = | 
 |         context_provider->UnboundTestContextGL()->test_capabilities(); | 
 |     EXPECT_FALSE(worker_caps.gpu_rasterization); | 
 |   } | 
 |  | 
 |   void SetupTree() override { | 
 |     LayerTreeHostTest::SetupTree(); | 
 |  | 
 |     std::unique_ptr<FakeRecordingSource> recording_source( | 
 |         new FakeRecordingSource); | 
 |     recording_source_ = recording_source.get(); | 
 |  | 
 |     scoped_refptr<FakePictureLayer> layer = | 
 |         FakePictureLayer::CreateWithRecordingSource( | 
 |             &layer_client_, std::move(recording_source)); | 
 |     layer_ = layer.get(); | 
 |     layer->SetBounds(gfx::Size(10, 10)); | 
 |     layer->SetIsDrawable(true); | 
 |     layer_tree_host()->root_layer()->AddChild(layer); | 
 |     layer_client_.set_bounds(layer_->bounds()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     EXPECT_FALSE(host_impl->pending_tree()->use_gpu_rasterization()); | 
 |     EXPECT_FALSE(host_impl->use_gpu_rasterization()); | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     EXPECT_FALSE(host_impl->active_tree()->use_gpu_rasterization()); | 
 |     EXPECT_FALSE(host_impl->use_gpu_rasterization()); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   FakeContentLayerClient layer_client_; | 
 |   FakePictureLayer* layer_; | 
 |   FakeRecordingSource* recording_source_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationDisabled); | 
 |  | 
 | class LayerTreeHostTestGpuRasterizationSupportedButDisabled | 
 |     : public LayerTreeTest { | 
 |  protected: | 
 |   void SetUpUnboundContextProviders( | 
 |       viz::TestContextProvider* context_provider, | 
 |       viz::TestContextProvider* worker_provider) override { | 
 |     context_provider->UnboundTestContextGL()->set_gpu_rasterization(true); | 
 |     worker_provider->UnboundTestContextGL()->set_gpu_rasterization(true); | 
 |   } | 
 |  | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     settings->gpu_rasterization_disabled = true; | 
 |   } | 
 |  | 
 |   void SetupTree() override { | 
 |     LayerTreeHostTest::SetupTree(); | 
 |  | 
 |     std::unique_ptr<FakeRecordingSource> recording_source( | 
 |         new FakeRecordingSource); | 
 |     recording_source_ = recording_source.get(); | 
 |  | 
 |     scoped_refptr<FakePictureLayer> layer = | 
 |         FakePictureLayer::CreateWithRecordingSource( | 
 |             &layer_client_, std::move(recording_source)); | 
 |     layer_ = layer.get(); | 
 |  | 
 |     layer->SetBounds(gfx::Size(10, 10)); | 
 |     layer->SetIsDrawable(true); | 
 |     layer_tree_host()->root_layer()->AddChild(layer); | 
 |     layer_client_.set_bounds(layer_->bounds()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     EXPECT_FALSE(host_impl->sync_tree()->use_gpu_rasterization()); | 
 |     EXPECT_FALSE(host_impl->use_gpu_rasterization()); | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     EXPECT_FALSE(host_impl->active_tree()->use_gpu_rasterization()); | 
 |     EXPECT_FALSE(host_impl->use_gpu_rasterization()); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   FakeContentLayerClient layer_client_; | 
 |   FakePictureLayer* layer_; | 
 |   FakeRecordingSource* recording_source_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationSupportedButDisabled); | 
 |  | 
 | class LayerTreeHostTestGpuRasterizationEnabled : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetUpUnboundContextProviders( | 
 |       viz::TestContextProvider* context_provider, | 
 |       viz::TestContextProvider* worker_provider) override { | 
 |     context_provider->UnboundTestContextGL()->set_gpu_rasterization(true); | 
 |     worker_provider->UnboundTestContextGL()->set_gpu_rasterization(true); | 
 |   } | 
 |  | 
 |   void SetupTree() override { | 
 |     LayerTreeHostTest::SetupTree(); | 
 |  | 
 |     std::unique_ptr<FakeRecordingSource> recording_source( | 
 |         new FakeRecordingSource); | 
 |     recording_source_ = recording_source.get(); | 
 |  | 
 |     scoped_refptr<FakePictureLayer> layer = | 
 |         FakePictureLayer::CreateWithRecordingSource( | 
 |             &layer_client_, std::move(recording_source)); | 
 |     layer_ = layer.get(); | 
 |  | 
 |     layer->SetBounds(gfx::Size(10, 10)); | 
 |     layer->SetIsDrawable(true); | 
 |     layer_tree_host()->root_layer()->AddChild(layer); | 
 |     layer_client_.set_bounds(layer_->bounds()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     EXPECT_TRUE(host_impl->sync_tree()->use_gpu_rasterization()); | 
 |     EXPECT_TRUE(host_impl->use_gpu_rasterization()); | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     EXPECT_TRUE(host_impl->active_tree()->use_gpu_rasterization()); | 
 |     EXPECT_TRUE(host_impl->use_gpu_rasterization()); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   FakeContentLayerClient layer_client_; | 
 |   FakePictureLayer* layer_; | 
 |   FakeRecordingSource* recording_source_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationEnabled); | 
 |  | 
 | class LayerTreeHostTestGpuRasterizationEnabledWithMSAA : public LayerTreeTest { | 
 |  protected: | 
 |   void SetUpUnboundContextProviders( | 
 |       viz::TestContextProvider* context_provider, | 
 |       viz::TestContextProvider* worker_provider) override { | 
 |     viz::TestGLES2Interface* gl = context_provider->UnboundTestContextGL(); | 
 |     gl->set_gpu_rasterization(true); | 
 |     gl->set_support_multisample_compatibility(false); | 
 |     gl->SetMaxSamples(4); | 
 |     viz::TestGLES2Interface* worker = worker_provider->UnboundTestContextGL(); | 
 |     worker->set_gpu_rasterization(true); | 
 |     worker->set_support_multisample_compatibility(false); | 
 |     worker->SetMaxSamples(4); | 
 |   } | 
 |  | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     // GetMSAASampleCountForRaster() will return this value if there are too | 
 |     // many slow paths. | 
 |     settings->gpu_rasterization_msaa_sample_count = 4; | 
 |   } | 
 |  | 
 |   void SetupTree() override { | 
 |     LayerTreeHostTest::SetupTree(); | 
 |  | 
 |     auto recording_source = std::make_unique<FakeRecordingSource>(); | 
 |     recording_source_ = recording_source.get(); | 
 |  | 
 |     scoped_refptr<FakePictureLayer> layer = | 
 |         FakePictureLayer::CreateWithRecordingSource( | 
 |             &layer_client_, std::move(recording_source)); | 
 |     layer_ = layer.get(); | 
 |     layer->SetBounds(gfx::Size(10, 10)); | 
 |     layer->SetIsDrawable(true); | 
 |     layer_tree_host()->root_layer()->AddChild(layer); | 
 |     layer_client_.set_bounds(layer_->bounds()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { | 
 |     // Content-based MSAA trigger. | 
 |     layer_client_.set_contains_slow_paths(true); | 
 |     // MSAA trigger will take effect when layers are updated. | 
 |     // The results will be verified after commit is completed below. | 
 |     // Since we are manually marking the source as containing slow paths, | 
 |     // make sure that the layer gets a chance to update. | 
 |     layer_->SetNeedsDisplay(); | 
 |  | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     auto* raster_source = static_cast<PictureLayerImpl*>( | 
 |                               host_impl->sync_tree()->LayerById(layer_->id())) | 
 |                               ->GetRasterSource(); | 
 |     EXPECT_GT(host_impl->GetMSAASampleCountForRaster( | 
 |                   raster_source->GetDisplayItemList()), | 
 |               0); | 
 |     EXPECT_TRUE(host_impl->pending_tree()->use_gpu_rasterization()); | 
 |     EXPECT_TRUE(host_impl->use_gpu_rasterization()); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   FakeContentLayerClient layer_client_; | 
 |   FakePictureLayer* layer_; | 
 |   FakeRecordingSource* recording_source_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationEnabledWithMSAA); | 
 |  | 
 | class LayerTreeHostTestWillBeginImplFrameHasDidFinishImplFrame | 
 |     : public LayerTreeHostTest { | 
 |  public: | 
 |   enum { kExpectedNumImplFrames = 10 }; | 
 |  | 
 |   LayerTreeHostTestWillBeginImplFrameHasDidFinishImplFrame() | 
 |       : will_begin_impl_frame_count_(0), did_finish_impl_frame_count_(0) {} | 
 |  | 
 |   void BeginTest() override { | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl, | 
 |                                   const viz::BeginFrameArgs& args) override { | 
 |     EXPECT_EQ(will_begin_impl_frame_count_, did_finish_impl_frame_count_); | 
 |     EXPECT_FALSE(TestEnded()); | 
 |     will_begin_impl_frame_count_++; | 
 |   } | 
 |  | 
 |   void DidFinishImplFrameOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     did_finish_impl_frame_count_++; | 
 |     EXPECT_EQ(will_begin_impl_frame_count_, did_finish_impl_frame_count_); | 
 |  | 
 |     // Trigger a new impl frame until we are done testing. | 
 |     if (did_finish_impl_frame_count_ < kExpectedNumImplFrames) | 
 |       PostSetNeedsRedrawToMainThread(); | 
 |     else | 
 |       EndTest(); | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     EXPECT_GT(will_begin_impl_frame_count_, 0); | 
 |     EXPECT_GT(did_finish_impl_frame_count_, 0); | 
 |     EXPECT_EQ(will_begin_impl_frame_count_, did_finish_impl_frame_count_); | 
 |  | 
 |     EXPECT_EQ(will_begin_impl_frame_count_, kExpectedNumImplFrames); | 
 |     EXPECT_EQ(did_finish_impl_frame_count_, kExpectedNumImplFrames); | 
 |   } | 
 |  | 
 |  private: | 
 |   int will_begin_impl_frame_count_; | 
 |   int did_finish_impl_frame_count_; | 
 | }; | 
 |  | 
 | // TODO(crbug.com/842038): Disabled as flaky. | 
 | // SINGLE_AND_MULTI_THREAD_TEST_F( | 
 | //     LayerTreeHostTestWillBeginImplFrameHasDidFinishImplFrame); | 
 |  | 
 | ::testing::AssertionResult AssertFrameTimeContained( | 
 |     const char* haystack_expr, | 
 |     const char* needle_expr, | 
 |     const std::vector<viz::BeginFrameArgs> haystack, | 
 |     const viz::BeginFrameArgs needle) { | 
 |   auto failure = ::testing::AssertionFailure() | 
 |                  << needle.frame_time << " (" << needle_expr | 
 |                  << ") not found in " << haystack_expr; | 
 |  | 
 |   if (haystack.size() == 0) { | 
 |     failure << " which is empty."; | 
 |   } else { | 
 |     failure << " which contains:\n"; | 
 |     for (size_t i = 0; i < haystack.size(); i++) { | 
 |       if (haystack[i].frame_time == needle.frame_time) | 
 |         return ::testing::AssertionSuccess(); | 
 |       failure << "  [" << i << "]: " << haystack[i].frame_time << "\n"; | 
 |     } | 
 |   } | 
 |  | 
 |   return failure; | 
 | } | 
 |  | 
 | class LayerTreeHostTestBeginMainFrameTimeIsAlsoImplTime | 
 |     : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestBeginMainFrameTimeIsAlsoImplTime() | 
 |       : impl_frame_args_(), will_begin_impl_frame_count_(0) {} | 
 |  | 
 |   void BeginTest() override { | 
 |     // Test terminates when a main frame is no longer expected so request that | 
 |     // this message is actually sent. | 
 |     layer_tree_host()->RequestBeginMainFrameNotExpected(true); | 
 |     // Kick off the test with a commit. | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void WillBeginImplFrameOnThread(LayerTreeHostImpl* impl, | 
 |                                   const viz::BeginFrameArgs& args) override { | 
 |     impl_frame_args_.push_back(args); | 
 |  | 
 |     will_begin_impl_frame_count_++; | 
 |     if (will_begin_impl_frame_count_ < 10) | 
 |       PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void BeginMainFrame(const viz::BeginFrameArgs& args) override { | 
 |     ASSERT_GT(impl_frame_args_.size(), 0U) | 
 |         << "BeginMainFrame called before BeginImplFrame called!"; | 
 |     EXPECT_PRED_FORMAT2(AssertFrameTimeContained, impl_frame_args_, args); | 
 |   } | 
 |  | 
 |   void BeginMainFrameNotExpectedSoon() override { EndTest(); } | 
 |  | 
 |   void AfterTest() override { | 
 |     EXPECT_GT(impl_frame_args_.size(), 0U); | 
 |     EXPECT_GE(will_begin_impl_frame_count_, 10); | 
 |   } | 
 |  | 
 |  private: | 
 |   std::vector<viz::BeginFrameArgs> impl_frame_args_; | 
 |   int will_begin_impl_frame_count_; | 
 | }; | 
 |  | 
 | // TODO(mithro): Re-enable the multi-threaded version of this test | 
 | // http://crbug.com/537621 | 
 | // SINGLE_AND_MULTI_THREAD_TEST_F( | 
 | //    LayerTreeHostTestBeginMainFrameTimeIsAlsoImplTime); | 
 | SINGLE_THREAD_TEST_F(LayerTreeHostTestBeginMainFrameTimeIsAlsoImplTime); | 
 |  | 
 | class LayerTreeHostTestActivateOnInvisible : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestActivateOnInvisible() | 
 |       : activation_count_(0), visible_(true) {} | 
 |  | 
 |   void BeginTest() override { | 
 |     // Kick off the test with a commit. | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void BeginCommitOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     // Make sure we don't activate using the notify signal from tile manager. | 
 |     host_impl->BlockNotifyReadyToActivateForTesting(true); | 
 |   } | 
 |  | 
 |   void DidCommit() override { layer_tree_host()->SetVisible(false); } | 
 |  | 
 |   void DidSetVisibleOnImplTree(LayerTreeHostImpl* host_impl, | 
 |                                bool visible) override { | 
 |     visible_ = visible; | 
 |  | 
 |     // Once invisible, we can go visible again. | 
 |     if (!visible) { | 
 |       PostSetVisibleToMainThread(true); | 
 |     } else if (activation_count_) { | 
 |       EXPECT_TRUE(host_impl->RequiresHighResToDraw()); | 
 |       EndTest(); | 
 |     } | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     ++activation_count_; | 
 |     EXPECT_FALSE(visible_); | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     // Ensure we activated even though the signal was blocked. | 
 |     EXPECT_EQ(1, activation_count_); | 
 |     EXPECT_TRUE(visible_); | 
 |   } | 
 |  | 
 |  private: | 
 |   int activation_count_; | 
 |   bool visible_; | 
 | }; | 
 |  | 
 | // TODO(vmpstr): Enable with single thread impl-side painting. | 
 | // This test blocks activation which is not supported for single thread mode. | 
 | MULTI_THREAD_BLOCKNOTIFY_TEST_F(LayerTreeHostTestActivateOnInvisible); | 
 |  | 
 | class LayerTreeHostTestRenderSurfaceEffectTreeIndex : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestRenderSurfaceEffectTreeIndex() = default; | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void SetupTree() override { | 
 |     root_ = Layer::Create(); | 
 |     child_ = Layer::Create(); | 
 |     grand_child_ = Layer::Create(); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_); | 
 |     root_->AddChild(child_); | 
 |     child_->AddChild(grand_child_); | 
 |  | 
 |     root_->SetBounds(gfx::Size(50, 50)); | 
 |     child_->SetBounds(gfx::Size(50, 50)); | 
 |     grand_child_->SetBounds(gfx::Size(50, 50)); | 
 |     child_->SetForceRenderSurfaceForTesting(true); | 
 |     grand_child_->SetForceRenderSurfaceForTesting(true); | 
 |  | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     if (host_impl->sync_tree()->source_frame_number() >= 1) { | 
 |       LayerImpl* grand_child_impl = | 
 |           host_impl->sync_tree()->LayerById(grand_child_->id()); | 
 |       EXPECT_EQ(grand_child_impl->effect_tree_index(), | 
 |                 GetRenderSurface(grand_child_impl)->EffectTreeIndex()); | 
 |     } | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     LayerImpl* grand_child_impl = | 
 |         host_impl->active_tree()->LayerById(grand_child_->id()); | 
 |     switch (host_impl->active_tree()->source_frame_number()) { | 
 |       case 0: | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 1: | 
 |       case 2: | 
 |         EXPECT_EQ(grand_child_impl->effect_tree_index(), | 
 |                   GetRenderSurface(grand_child_impl)->EffectTreeIndex()); | 
 |         PostSetNeedsCommitToMainThread(); | 
 |         break; | 
 |       case 3: | 
 |         EXPECT_EQ(grand_child_impl->effect_tree_index(), | 
 |                   GetRenderSurface(grand_child_impl)->EffectTreeIndex()); | 
 |         EndTest(); | 
 |     } | 
 |   } | 
 |  | 
 |   void DidCommit() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 2: | 
 |         // Setting an empty viewport causes draws to get skipped, so the active | 
 |         // tree won't update draw properties. | 
 |         layer_tree_host()->SetViewportRectAndScale( | 
 |             gfx::Rect(), 1.f, GetCurrentLocalSurfaceIdAllocation()); | 
 |         child_->SetForceRenderSurfaceForTesting(false); | 
 |         break; | 
 |       case 3: | 
 |         layer_tree_host()->SetViewportRectAndScale( | 
 |             gfx::Rect(root_->bounds()), 1.f, | 
 |             GetCurrentLocalSurfaceIdAllocation()); | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   scoped_refptr<Layer> root_; | 
 |   scoped_refptr<Layer> child_; | 
 |   scoped_refptr<Layer> grand_child_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestRenderSurfaceEffectTreeIndex); | 
 |  | 
 | // Do a synchronous composite and assert that the swap promise succeeds. | 
 | class LayerTreeHostTestSynchronousCompositeSwapPromise | 
 |     : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestSynchronousCompositeSwapPromise() = default; | 
 |  | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     settings->single_thread_proxy_scheduler = false; | 
 |     settings->use_zero_copy = true; | 
 |   } | 
 |  | 
 |   std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink( | 
 |       const viz::RendererSettings& renderer_settings, | 
 |       double refresh_rate, | 
 |       scoped_refptr<viz::ContextProvider> compositor_context_provider, | 
 |       scoped_refptr<viz::RasterContextProvider> worker_context_provider) | 
 |       override { | 
 |     constexpr bool disable_display_vsync = false; | 
 |     bool synchronous_composite = | 
 |         !HasImplThread() && | 
 |         !layer_tree_host()->GetSettings().single_thread_proxy_scheduler; | 
 |     return std::make_unique<TestLayerTreeFrameSink>( | 
 |         compositor_context_provider, std::move(worker_context_provider), | 
 |         gpu_memory_buffer_manager(), renderer_settings, ImplThreadTaskRunner(), | 
 |         synchronous_composite, disable_display_vsync, refresh_rate); | 
 |   } | 
 |  | 
 |   void BeginTest() override { | 
 |     // Successful composite. | 
 |     const bool raster = true; | 
 |     std::unique_ptr<SwapPromise> swap_promise0( | 
 |         new TestSwapPromise(&swap_promise_result_[0])); | 
 |     layer_tree_host()->GetSwapPromiseManager()->QueueSwapPromise( | 
 |         std::move(swap_promise0)); | 
 |     layer_tree_host()->Composite(base::TimeTicks::Now(), raster); | 
 |  | 
 |     // Fail to swap (no damage) if not reclaiming resources from the Display. | 
 |     std::unique_ptr<SwapPromise> swap_promise1( | 
 |         new TestSwapPromise(&swap_promise_result_[1])); | 
 |     layer_tree_host()->GetSwapPromiseManager()->QueueSwapPromise( | 
 |         std::move(swap_promise1)); | 
 |     layer_tree_host()->SetNeedsCommit(); | 
 |     layer_tree_host()->Composite(base::TimeTicks::Now(), raster); | 
 |  | 
 |     // Fail to draw (not visible). | 
 |     std::unique_ptr<SwapPromise> swap_promise2( | 
 |         new TestSwapPromise(&swap_promise_result_[2])); | 
 |     layer_tree_host()->GetSwapPromiseManager()->QueueSwapPromise( | 
 |         std::move(swap_promise2)); | 
 |     layer_tree_host()->SetNeedsDisplayOnAllLayers(); | 
 |     layer_tree_host()->SetVisible(false); | 
 |     layer_tree_host()->Composite(base::TimeTicks::Now(), raster); | 
 |  | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void DidCommit() override { | 
 |     commit_count_++; | 
 |     ASSERT_LE(commit_count_, 3); | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     EXPECT_EQ(3, commit_count_); | 
 |  | 
 |     // Initial swap promise should have succeded. | 
 |     { | 
 |       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); | 
 |     } | 
 |  | 
 |     // Second swap promise fails to swap. | 
 |     { | 
 |       base::AutoLock lock(swap_promise_result_[1].lock); | 
 |       EXPECT_TRUE(swap_promise_result_[1].did_activate_called); | 
 |       EXPECT_FALSE(swap_promise_result_[1].did_swap_called); | 
 |       EXPECT_TRUE(swap_promise_result_[1].did_not_swap_called); | 
 |       EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[1].reason); | 
 |       EXPECT_TRUE(swap_promise_result_[1].dtor_called); | 
 |     } | 
 |  | 
 |     // Third swap promises also fails to swap (and draw). | 
 |     { | 
 |       base::AutoLock lock(swap_promise_result_[2].lock); | 
 |       EXPECT_TRUE(swap_promise_result_[2].did_activate_called); | 
 |       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); | 
 |     } | 
 |   } | 
 |  | 
 |   int commit_count_ = 0; | 
 |   TestSwapPromiseResult swap_promise_result_[3]; | 
 | }; | 
 |  | 
 | // Synchronous composite is a single-threaded only feature. | 
 | SINGLE_THREAD_TEST_F(LayerTreeHostTestSynchronousCompositeSwapPromise); | 
 |  | 
 | // Make sure page scale and top control deltas are applied to the client even | 
 | // when the LayerTreeHost doesn't have a root layer. | 
 | class LayerTreeHostAcceptsDeltasFromImplWithoutRootLayer | 
 |     : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostAcceptsDeltasFromImplWithoutRootLayer() | 
 |       : deltas_sent_to_client_(false) {} | 
 |  | 
 |   void BeginTest() override { | 
 |     layer_tree_host()->SetRootLayer(nullptr); | 
 |     info_.page_scale_delta = 3.14f; | 
 |     info_.top_controls_delta = 2.73f; | 
 |  | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void BeginMainFrame(const viz::BeginFrameArgs& args) override { | 
 |     EXPECT_EQ(nullptr, layer_tree_host()->root_layer()); | 
 |  | 
 |     layer_tree_host()->ApplyScrollAndScale(&info_); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void ApplyViewportChanges(const ApplyViewportChangesArgs& args) override { | 
 |     EXPECT_EQ(info_.page_scale_delta, args.page_scale_delta); | 
 |     EXPECT_EQ(info_.top_controls_delta, args.top_controls_delta); | 
 |     EXPECT_EQ(info_.browser_controls_constraint, | 
 |               args.browser_controls_constraint); | 
 |     deltas_sent_to_client_ = true; | 
 |   } | 
 |  | 
 |   void AfterTest() override { EXPECT_TRUE(deltas_sent_to_client_); } | 
 |  | 
 |   ScrollAndScaleSet info_; | 
 |   bool deltas_sent_to_client_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostAcceptsDeltasFromImplWithoutRootLayer); | 
 |  | 
 | class LayerTreeHostTestCrispUpAfterPinchEnds : public LayerTreeHostTest { | 
 |  protected: | 
 |   LayerTreeHostTestCrispUpAfterPinchEnds() | 
 |       : playback_allowed_event_(base::WaitableEvent::ResetPolicy::MANUAL, | 
 |                                 base::WaitableEvent::InitialState::SIGNALED) { | 
 |     SetUseLayerLists(); | 
 |   } | 
 |  | 
 |   void SetupTree() override { | 
 |     frame_ = 1; | 
 |     posted_ = false; | 
 |     client_.set_fill_with_nonsolid_color(true); | 
 |  | 
 |     SetInitialRootBounds(gfx::Size(500, 500)); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     Layer* root = layer_tree_host()->root_layer(); | 
 |     SetupViewport(root, root->bounds(), root->bounds()); | 
 |  | 
 |     std::unique_ptr<FakeRecordingSource> recording(new FakeRecordingSource); | 
 |     recording->SetPlaybackAllowedEvent(&playback_allowed_event_); | 
 |     scoped_refptr<FakePictureLayer> layer = | 
 |         FakePictureLayer::CreateWithRecordingSource(&client_, | 
 |                                                     std::move(recording)); | 
 |     layer->SetBounds(gfx::Size(500, 500)); | 
 |     layer->SetContentsOpaque(true); | 
 |     // Avoid LCD text on the layer so we don't cause extra commits when we | 
 |     // pinch. | 
 |     CopyProperties(layer_tree_host()->InnerViewportScrollLayerForTesting(), | 
 |                    layer.get()); | 
 |     root->AddChild(layer); | 
 |  | 
 |     layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f); | 
 |     client_.set_bounds(root->bounds()); | 
 |   } | 
 |  | 
 |   // Returns the delta scale of all quads in the frame's root pass from their | 
 |   // ideal, or 0 if they are not all the same. | 
 |   float FrameQuadScaleDeltaFromIdeal(LayerTreeHostImpl::FrameData* frame_data) { | 
 |     if (frame_data->has_no_damage) | 
 |       return 0.f; | 
 |     float frame_scale = 0.f; | 
 |     viz::RenderPass* root_pass = frame_data->render_passes.back().get(); | 
 |     for (auto* draw_quad : root_pass->quad_list) { | 
 |       // Checkerboards mean an incomplete frame. | 
 |       if (draw_quad->material != viz::DrawQuad::Material::kTiledContent) | 
 |         return 0.f; | 
 |       const viz::TileDrawQuad* quad = | 
 |           viz::TileDrawQuad::MaterialCast(draw_quad); | 
 |       float quad_scale = | 
 |           quad->tex_coord_rect.width() / static_cast<float>(quad->rect.width()); | 
 |       float transform_scale = SkScalarToFloat( | 
 |           quad->shared_quad_state->quad_to_target_transform.matrix().get(0, 0)); | 
 |       float scale = quad_scale / transform_scale; | 
 |       if (frame_scale != 0.f && frame_scale != scale) | 
 |         return 0.f; | 
 |       frame_scale = scale; | 
 |     } | 
 |     return frame_scale; | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     float quad_scale_delta = FrameQuadScaleDeltaFromIdeal(frame_data); | 
 |     switch (frame_) { | 
 |       case 1: | 
 |         // Drew at page scale 1 before any pinching. | 
 |         EXPECT_EQ(1.f, host_impl->active_tree()->current_page_scale_factor()); | 
 |         EXPECT_EQ(1.f, quad_scale_delta); | 
 |         PostNextAfterDraw(host_impl); | 
 |         break; | 
 |       case 2: | 
 |         if (quad_scale_delta != 1.f) | 
 |           break; | 
 |         // Drew at page scale 1.5 after pinching in. | 
 |         EXPECT_EQ(1.5f, host_impl->active_tree()->current_page_scale_factor()); | 
 |         EXPECT_EQ(1.f, quad_scale_delta); | 
 |         PostNextAfterDraw(host_impl); | 
 |         break; | 
 |       case 3: | 
 |         // By pinching out, we will create a new tiling and raster it. This may | 
 |         // cause some additional draws, though we should still be drawing with | 
 |         // the old 1.5 tiling. | 
 |         if (frame_data->has_no_damage) | 
 |           break; | 
 |         // Drew at page scale 1 with the 1.5 tiling while pinching out. | 
 |         EXPECT_EQ(1.f, host_impl->active_tree()->current_page_scale_factor()); | 
 |         EXPECT_EQ(1.5f, quad_scale_delta); | 
 |         // We don't PostNextAfterDraw here, instead we wait for the new tiling | 
 |         // to finish rastering so we don't get any noise in further steps. | 
 |         break; | 
 |       case 4: | 
 |         // Drew at page scale 1 with the 1.5 tiling after pinching out completed | 
 |         // while waiting for texture uploads to complete. | 
 |         EXPECT_EQ(1.f, host_impl->active_tree()->current_page_scale_factor()); | 
 |         // This frame will not have any damage, since it's actually the same as | 
 |         // the last frame, and should contain no incomplete tiles. We just want | 
 |         // to make sure we drew here at least once after the pinch ended to be | 
 |         // sure that drawing after pinch doesn't leave us at the wrong scale | 
 |         EXPECT_TRUE(frame_data->has_no_damage); | 
 |         PostNextAfterDraw(host_impl); | 
 |         break; | 
 |       case 5: | 
 |         if (quad_scale_delta != 1.f) | 
 |           break; | 
 |         // Drew at scale 1 after texture uploads are done. | 
 |         EXPECT_EQ(1.f, host_impl->active_tree()->current_page_scale_factor()); | 
 |         EXPECT_EQ(1.f, quad_scale_delta); | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |   void PostNextAfterDraw(LayerTreeHostImpl* host_impl) { | 
 |     if (posted_) | 
 |       return; | 
 |     posted_ = true; | 
 |     ImplThreadTaskRunner()->PostDelayedTask( | 
 |         FROM_HERE, | 
 |         base::BindOnce(&LayerTreeHostTestCrispUpAfterPinchEnds::Next, | 
 |                        base::Unretained(this), host_impl), | 
 |         // Use a delay to allow raster/upload to happen in between frames. This | 
 |         // should cause flakiness if we fail to block raster/upload when | 
 |         // desired. | 
 |         base::TimeDelta::FromMilliseconds(16 * 4)); | 
 |   } | 
 |  | 
 |   void Next(LayerTreeHostImpl* host_impl) { | 
 |     ++frame_; | 
 |     posted_ = false; | 
 |     switch (frame_) { | 
 |       case 2: | 
 |         // Pinch zoom in. | 
 |         host_impl->PinchGestureBegin(); | 
 |         host_impl->PinchGestureUpdate(1.5f, gfx::Point(100, 100)); | 
 |         host_impl->PinchGestureEnd(gfx::Point(100, 100), true); | 
 |         break; | 
 |       case 3: | 
 |         // Pinch zoom back to 1.f but don't end it. | 
 |         host_impl->PinchGestureBegin(); | 
 |         host_impl->PinchGestureUpdate(1.f / 1.5f, gfx::Point(100, 100)); | 
 |         break; | 
 |       case 4: | 
 |         // End the pinch, but delay tile production. | 
 |         playback_allowed_event_.Reset(); | 
 |         host_impl->PinchGestureEnd(gfx::Point(100, 100), true); | 
 |         break; | 
 |       case 5: | 
 |         // Let tiles complete. | 
 |         playback_allowed_event_.Signal(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl, | 
 |                                       const Tile* tile) override { | 
 |     if (frame_ == 3) { | 
 |       // On frame 3, we will have a lower res tile complete for the pinch-out | 
 |       // gesture even though it's not displayed. We wait for it here to prevent | 
 |       // flakiness. | 
 |       EXPECT_EQ(gfx::AxisTransform2d(0.75f, gfx::Vector2dF()), | 
 |                 tile->raster_transform()); | 
 |       PostNextAfterDraw(host_impl); | 
 |     } | 
 |     // On frame_ == 4, we are preventing texture uploads from completing, | 
 |     // so this verifies they are not completing before frame_ == 5. | 
 |     // Flaky failures here indicate we're failing to prevent uploads from | 
 |     // completing. | 
 |     EXPECT_NE(4, frame_) << tile->contents_scale_key(); | 
 |   } | 
 |  | 
 |   FakeContentLayerClient client_; | 
 |   int frame_; | 
 |   bool posted_; | 
 |   base::WaitableEvent playback_allowed_event_; | 
 | }; | 
 |  | 
 | // This test does pinching on the impl side which is not supported in single | 
 | // thread. | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestCrispUpAfterPinchEnds); | 
 |  | 
 | class LayerTreeHostTestCrispUpAfterPinchEndsWithOneCopy | 
 |     : public LayerTreeHostTestCrispUpAfterPinchEnds { | 
 |  protected: | 
 |   std::unique_ptr<viz::OutputSurface> CreateDisplayOutputSurfaceOnThread( | 
 |       scoped_refptr<viz::ContextProvider> compositor_context_provider) | 
 |       override { | 
 |     scoped_refptr<viz::TestContextProvider> display_context_provider = | 
 |         viz::TestContextProvider::Create(); | 
 |     viz::TestGLES2Interface* gl = | 
 |         display_context_provider->UnboundTestContextGL(); | 
 |     gl->set_support_sync_query(true); | 
 | #if defined(OS_MACOSX) | 
 |     gl->set_support_texture_rectangle(true); | 
 | #endif | 
 |     display_context_provider->BindToCurrentThread(); | 
 |     return LayerTreeTest::CreateDisplayOutputSurfaceOnThread( | 
 |         std::move(display_context_provider)); | 
 |   } | 
 | }; | 
 |  | 
 | // This test does pinching on the impl side which is not supported in single | 
 | // thread. | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestCrispUpAfterPinchEndsWithOneCopy); | 
 |  | 
 | class RasterizeWithGpuRasterizationCreatesResources : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetUpUnboundContextProviders( | 
 |       viz::TestContextProvider* context_provider, | 
 |       viz::TestContextProvider* worker_provider) override { | 
 |     context_provider->UnboundTestContextGL()->set_gpu_rasterization(true); | 
 |     worker_provider->UnboundTestContextGL()->set_gpu_rasterization(true); | 
 |   } | 
 |  | 
 |   void SetupTree() override { | 
 |     client_.set_fill_with_nonsolid_color(true); | 
 |  | 
 |     scoped_refptr<Layer> root = Layer::Create(); | 
 |     root->SetBounds(gfx::Size(500, 500)); | 
 |     client_.set_bounds(root->bounds()); | 
 |  | 
 |     std::unique_ptr<FakeRecordingSource> recording(new FakeRecordingSource); | 
 |     scoped_refptr<FakePictureLayer> layer = | 
 |         FakePictureLayer::CreateWithRecordingSource(&client_, | 
 |                                                     std::move(recording)); | 
 |     layer->SetBounds(gfx::Size(500, 500)); | 
 |     layer->SetContentsOpaque(true); | 
 |     root->AddChild(layer); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     client_.set_bounds(root->bounds()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     EXPECT_NE(0u, host_impl->resource_pool()->resource_count()); | 
 |     EndTest(); | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |   FakeContentLayerClient client_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(RasterizeWithGpuRasterizationCreatesResources); | 
 |  | 
 | class GpuRasterizationRasterizesBorderTiles : public LayerTreeHostTest { | 
 |  protected: | 
 |   GpuRasterizationRasterizesBorderTiles() : viewport_size_(1024, 2048) {} | 
 |  | 
 |   void SetUpUnboundContextProviders( | 
 |       viz::TestContextProvider* context_provider, | 
 |       viz::TestContextProvider* worker_provider) override { | 
 |     context_provider->UnboundTestContextGL()->set_gpu_rasterization(true); | 
 |     worker_provider->UnboundTestContextGL()->set_gpu_rasterization(true); | 
 |   } | 
 |  | 
 |   void SetupTree() override { | 
 |     client_.set_fill_with_nonsolid_color(true); | 
 |  | 
 |     std::unique_ptr<FakeRecordingSource> recording(new FakeRecordingSource); | 
 |     scoped_refptr<FakePictureLayer> root = | 
 |         FakePictureLayer::CreateWithRecordingSource(&client_, | 
 |                                                     std::move(recording)); | 
 |     root->SetBounds(gfx::Size(10000, 10000)); | 
 |     client_.set_bounds(root->bounds()); | 
 |     root->SetContentsOpaque(true); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(viewport_size_), 1.f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |     client_.set_bounds(root->bounds()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     EXPECT_EQ(15u, host_impl->resource_pool()->resource_count()); | 
 |     EndTest(); | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |  private: | 
 |   FakeContentLayerClient client_; | 
 |   gfx::Size viewport_size_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(GpuRasterizationRasterizesBorderTiles); | 
 |  | 
 | class LayerTreeHostTestContinuousDrawWhenCreatingVisibleTiles | 
 |     : public LayerTreeHostTest { | 
 |  protected: | 
 |   LayerTreeHostTestContinuousDrawWhenCreatingVisibleTiles() | 
 |       : playback_allowed_event_(base::WaitableEvent::ResetPolicy::MANUAL, | 
 |                                 base::WaitableEvent::InitialState::SIGNALED) { | 
 |     SetUseLayerLists(); | 
 |   } | 
 |  | 
 |   void SetupTree() override { | 
 |     step_ = 1; | 
 |     continuous_draws_ = 0; | 
 |     client_.set_fill_with_nonsolid_color(true); | 
 |  | 
 |     SetInitialRootBounds(gfx::Size(500, 500)); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |  | 
 |     Layer* root = layer_tree_host()->root_layer(); | 
 |     SetupViewport(root, root->bounds(), root->bounds()); | 
 |  | 
 |     std::unique_ptr<FakeRecordingSource> recording(new FakeRecordingSource); | 
 |     recording->SetPlaybackAllowedEvent(&playback_allowed_event_); | 
 |     scoped_refptr<FakePictureLayer> layer = | 
 |         FakePictureLayer::CreateWithRecordingSource(&client_, | 
 |                                                     std::move(recording)); | 
 |     layer->SetBounds(gfx::Size(500, 500)); | 
 |     layer->SetContentsOpaque(true); | 
 |     CopyProperties(layer_tree_host()->InnerViewportScrollLayerForTesting(), | 
 |                    layer.get()); | 
 |     root->AddChild(layer); | 
 |  | 
 |     layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f); | 
 |     client_.set_bounds(root->bounds()); | 
 |   } | 
 |  | 
 |   // Returns the delta scale of all quads in the frame's root pass from their | 
 |   // ideal, or 0 if they are not all the same. | 
 |   float FrameQuadScaleDeltaFromIdeal(LayerTreeHostImpl::FrameData* frame_data) { | 
 |     if (frame_data->has_no_damage) | 
 |       return 0.f; | 
 |     float frame_scale = 0.f; | 
 |     viz::RenderPass* root_pass = frame_data->render_passes.back().get(); | 
 |     for (auto* draw_quad : root_pass->quad_list) { | 
 |       const viz::TileDrawQuad* quad = | 
 |           viz::TileDrawQuad::MaterialCast(draw_quad); | 
 |       float quad_scale = | 
 |           quad->tex_coord_rect.width() / static_cast<float>(quad->rect.width()); | 
 |       float transform_scale = SkScalarToFloat( | 
 |           quad->shared_quad_state->quad_to_target_transform.matrix().get(0, 0)); | 
 |       float scale = quad_scale / transform_scale; | 
 |       if (frame_scale != 0.f && frame_scale != scale) | 
 |         return 0.f; | 
 |       frame_scale = scale; | 
 |     } | 
 |     return frame_scale; | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     float quad_scale_delta = FrameQuadScaleDeltaFromIdeal(frame_data); | 
 |     switch (step_) { | 
 |       case 1: | 
 |         // Drew at scale 1 before any pinching. | 
 |         EXPECT_EQ(1.f, host_impl->active_tree()->current_page_scale_factor()); | 
 |         EXPECT_EQ(1.f, quad_scale_delta); | 
 |         break; | 
 |       case 2: | 
 |         if (quad_scale_delta != 1.f / 1.5f) | 
 |           break; | 
 |         // Drew at scale 1 still though the ideal is 1.5. | 
 |         EXPECT_EQ(1.5f, host_impl->active_tree()->current_page_scale_factor()); | 
 |         EXPECT_EQ(1.f / 1.5f, quad_scale_delta); | 
 |         break; | 
 |       case 3: | 
 |         // Continuous draws are attempted. | 
 |         EXPECT_EQ(1.5f, host_impl->active_tree()->current_page_scale_factor()); | 
 |         if (!frame_data->has_no_damage) | 
 |           EXPECT_EQ(1.f / 1.5f, quad_scale_delta); | 
 |         break; | 
 |       case 4: | 
 |         if (quad_scale_delta != 1.f) | 
 |           break; | 
 |         // Drew at scale 1.5 when all the tiles completed. | 
 |         EXPECT_EQ(1.5f, host_impl->active_tree()->current_page_scale_factor()); | 
 |         EXPECT_EQ(1.f, quad_scale_delta); | 
 |         break; | 
 |       case 5: | 
 |         // TODO(danakj): We get more draws before the NotifyReadyToDraw | 
 |         // because it is asynchronous from the previous draw and happens late. | 
 |         break; | 
 |       case 6: | 
 |         // NotifyReadyToDraw happened. If we were already inside a frame, we may | 
 |         // try to draw once more. | 
 |         break; | 
 |       case 7: | 
 |         NOTREACHED() << "No draws should happen once we have a complete frame."; | 
 |         break; | 
 |     } | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     switch (step_) { | 
 |       case 1: | 
 |         // Delay tile production. | 
 |         playback_allowed_event_.Reset(); | 
 |         // Pinch zoom in to cause new tiles to be required. | 
 |         host_impl->PinchGestureBegin(); | 
 |         host_impl->PinchGestureUpdate(1.5f, gfx::Point(100, 100)); | 
 |         host_impl->PinchGestureEnd(gfx::Point(100, 100), true); | 
 |         ++step_; | 
 |         break; | 
 |       case 2: | 
 |         ++step_; | 
 |         break; | 
 |       case 3: | 
 |         // We should continue to try draw while there are incomplete visible | 
 |         // tiles. | 
 |         if (++continuous_draws_ > 5) { | 
 |           // Allow the tiles to complete. | 
 |           playback_allowed_event_.Signal(); | 
 |           ++step_; | 
 |         } | 
 |         break; | 
 |       case 4: | 
 |         ++step_; | 
 |         break; | 
 |       case 5: | 
 |         // Waiting for NotifyReadyToDraw. | 
 |         break; | 
 |       case 6: | 
 |         // NotifyReadyToDraw happened. | 
 |         ++step_; | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void NotifyReadyToDrawOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     if (step_ == 5) { | 
 |       ++step_; | 
 |       // NotifyReadyToDraw has happened, we may draw once more, but should not | 
 |       // get any more draws after that. End the test after a timeout to watch | 
 |       // for any extraneous draws. | 
 |       // TODO(brianderson): We could remove this delay and instead wait until | 
 |       // the viz::BeginFrameSource decides it doesn't need to send frames | 
 |       // anymore, or test that it already doesn't here. | 
 |       EndTestAfterDelayMs(16 * 4); | 
 |     } | 
 |   } | 
 |  | 
 |   void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl, | 
 |                                       const Tile* tile) override { | 
 |     // On step_ == 2, we are preventing texture uploads from completing, | 
 |     // so this verifies they are not completing before step_ == 3. | 
 |     // Flaky failures here indicate we're failing to prevent uploads from | 
 |     // completing. | 
 |     EXPECT_NE(2, step_); | 
 |   } | 
 |  | 
 |   void AfterTest() override { EXPECT_GT(continuous_draws_, 5); } | 
 |  | 
 |   FakeContentLayerClient client_; | 
 |   int step_; | 
 |   int continuous_draws_; | 
 |   base::WaitableEvent playback_allowed_event_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestContinuousDrawWhenCreatingVisibleTiles); | 
 |  | 
 | class LayerTreeHostTestOneActivatePerPrepareTiles : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestOneActivatePerPrepareTiles() | 
 |       : notify_ready_to_activate_count_(0u), | 
 |         scheduled_prepare_tiles_count_(0) {} | 
 |  | 
 |   void SetupTree() override { | 
 |     client_.set_fill_with_nonsolid_color(true); | 
 |     scoped_refptr<FakePictureLayer> root_layer = | 
 |         FakePictureLayer::Create(&client_); | 
 |     root_layer->SetBounds(gfx::Size(1500, 1500)); | 
 |     root_layer->SetIsDrawable(true); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_layer); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     client_.set_bounds(root_layer->bounds()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(16, 16), 1.f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void InitializedRendererOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    bool success) override { | 
 |     ASSERT_TRUE(success); | 
 |     host_impl->tile_manager()->SetScheduledRasterTaskLimitForTesting(1); | 
 |   } | 
 |  | 
 |   void NotifyReadyToActivateOnThread(LayerTreeHostImpl* impl) override { | 
 |     ++notify_ready_to_activate_count_; | 
 |     EndTestAfterDelayMs(100); | 
 |   } | 
 |  | 
 |   void WillPrepareTilesOnThread(LayerTreeHostImpl* impl) override { | 
 |     ++scheduled_prepare_tiles_count_; | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     // Expect at most a notification for each scheduled prepare tiles, plus one | 
 |     // for the initial commit (which doesn't go through scheduled actions). | 
 |     // The reason this is not an equality is because depending on timing, we | 
 |     // might get a prepare tiles but not yet get a notification that we're | 
 |     // ready to activate. The intent of a test is to ensure that we don't | 
 |     // get more than one notification per prepare tiles, so this is OK. | 
 |     EXPECT_LE(notify_ready_to_activate_count_, | 
 |               1u + scheduled_prepare_tiles_count_); | 
 |   } | 
 |  | 
 |  protected: | 
 |   FakeContentLayerClient client_; | 
 |   size_t notify_ready_to_activate_count_; | 
 |   size_t scheduled_prepare_tiles_count_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestOneActivatePerPrepareTiles); | 
 |  | 
 | class LayerTreeHostTestActivationCausesPrepareTiles : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestActivationCausesPrepareTiles() | 
 |       : scheduled_prepare_tiles_count_(0) {} | 
 |  | 
 |   void SetupTree() override { | 
 |     client_.set_fill_with_nonsolid_color(true); | 
 |     scoped_refptr<FakePictureLayer> root_layer = | 
 |         FakePictureLayer::Create(&client_); | 
 |     root_layer->SetBounds(gfx::Size(150, 150)); | 
 |     root_layer->SetIsDrawable(true); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root_layer); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     client_.set_bounds(root_layer->bounds()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void NotifyReadyToActivateOnThread(LayerTreeHostImpl* impl) override { | 
 |     // Ensure we've already activated. | 
 |     EXPECT_FALSE(impl->pending_tree()); | 
 |  | 
 |     // After activating, we either need to prepare tiles, or we've already | 
 |     // called a scheduled prepare tiles. This is done because activation might | 
 |     // cause us to have to memory available (old active tree is gone), so we | 
 |     // need to ensure we will get a PrepareTiles call. | 
 |     if (!impl->prepare_tiles_needed()) | 
 |       EXPECT_GE(scheduled_prepare_tiles_count_, 1); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void WillPrepareTilesOnThread(LayerTreeHostImpl* impl) override { | 
 |     ++scheduled_prepare_tiles_count_; | 
 |   } | 
 |  | 
 |  protected: | 
 |   FakeContentLayerClient client_; | 
 |   int scheduled_prepare_tiles_count_; | 
 | }; | 
 |  | 
 | // This test is testing activation from a pending tree and doesn't make sense | 
 | // with single thread commit-to-active. | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestActivationCausesPrepareTiles); | 
 |  | 
 | // This tests an assertion that DidCommit and WillCommit happen in the same | 
 | // stack frame with no tasks that run between them.  Various embedders of | 
 | // cc depend on this logic.  ui::Compositor holds a compositor lock between | 
 | // these events and the inspector timeline wants begin/end CompositeLayers | 
 | // to be properly nested with other begin/end events. | 
 | class LayerTreeHostTestNoTasksBetweenWillAndDidCommit | 
 |     : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestNoTasksBetweenWillAndDidCommit() : did_commit_(false) {} | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void WillCommit() override { | 
 |     MainThreadTaskRunner()->PostTask( | 
 |         FROM_HERE, | 
 |         base::BindOnce(&LayerTreeHostTestNoTasksBetweenWillAndDidCommit:: | 
 |                            EndTestShouldRunAfterDidCommit, | 
 |                        base::Unretained(this))); | 
 |   } | 
 |  | 
 |   void EndTestShouldRunAfterDidCommit() { | 
 |     EXPECT_TRUE(did_commit_); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void DidCommit() override { | 
 |     EXPECT_FALSE(did_commit_); | 
 |     did_commit_ = true; | 
 |   } | 
 |  | 
 |   void AfterTest() override { EXPECT_TRUE(did_commit_); } | 
 |  | 
 |  private: | 
 |   bool did_commit_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestNoTasksBetweenWillAndDidCommit); | 
 |  | 
 | class LayerTreeHostTestUpdateCopyRequests : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     root = Layer::Create(); | 
 |     child = Layer::Create(); | 
 |     root->AddChild(child); | 
 |     layer_tree_host()->SetRootLayer(root); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void WillCommit() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         EXPECT_TRUE(LayerSubtreeHasCopyRequest(root.get())); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   void DidCommit() override { | 
 |     gfx::Transform transform; | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         child->RequestCopyOfOutput( | 
 |             viz::CopyOutputRequest::CreateStubForTesting()); | 
 |         transform.Scale(2.0, 2.0); | 
 |         child->SetTransform(transform); | 
 |         break; | 
 |       case 2: | 
 |         // By changing the scale of a layer which already owns a transform node, | 
 |         // a commit will be triggered but a property tree rebuild will not, this | 
 |         // is used to test sure that clearing copy requestts does trigger a | 
 |         // rebuild whenever next commit happens. | 
 |         transform.Scale(1.5, 1.5); | 
 |         child->SetTransform(transform); | 
 |         break; | 
 |       case 3: | 
 |         EXPECT_FALSE(LayerSubtreeHasCopyRequest(root.get())); | 
 |         EndTest(); | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   scoped_refptr<Layer> root; | 
 |   scoped_refptr<Layer> child; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestUpdateCopyRequests); | 
 |  | 
 | class LayerTreeTestPageScaleFlags : public LayerTreeTest { | 
 |  public: | 
 |   LayerTreeTestPageScaleFlags() { SetUseLayerLists(); } | 
 |  | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     // -root | 
 |     //   -pre page scale | 
 |     //   -viewport layers | 
 |     //   -post page scale | 
 |  | 
 |     LayerTreeTest::SetupTree(); | 
 |     Layer* root = layer_tree_host()->root_layer(); | 
 |  | 
 |     scoped_refptr<Layer> pre_page_scale = Layer::Create(); | 
 |     CopyProperties(root, pre_page_scale.get()); | 
 |     root->AddChild(pre_page_scale); | 
 |  | 
 |     SetupViewport(root, root->bounds(), root->bounds()); | 
 |  | 
 |     scoped_refptr<Layer> post_page_scale = Layer::Create(); | 
 |     CopyProperties(root, post_page_scale.get()); | 
 |     root->AddChild(post_page_scale); | 
 |  | 
 |     affected_by_page_scale_.push_back( | 
 |         layer_tree_host()->InnerViewportScrollLayerForTesting()->id()); | 
 |     affected_by_page_scale_.push_back( | 
 |         layer_tree_host()->OuterViewportScrollLayerForTesting()->id()); | 
 |  | 
 |     not_affected_by_page_scale_.push_back(root->id()); | 
 |     not_affected_by_page_scale_.push_back(pre_page_scale->id()); | 
 |     not_affected_by_page_scale_.push_back(post_page_scale->id()); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     for (auto* layer : *host_impl->sync_tree()) { | 
 |       const std::vector<int>& list = layer->IsAffectedByPageScale() | 
 |                                          ? this->affected_by_page_scale_ | 
 |                                          : this->not_affected_by_page_scale_; | 
 |       EXPECT_TRUE(base::Contains(list, layer->id())); | 
 |     } | 
 |  | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   std::vector<int> affected_by_page_scale_; | 
 |   std::vector<int> not_affected_by_page_scale_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeTestPageScaleFlags); | 
 |  | 
 | class LayerTreeHostTestDestroyWhileInitializingOutputSurface | 
 |     : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override { | 
 |     // By ending the test immediately we start initialization of an output | 
 |     // surface but destroy the LTH before it completes. This test verifies | 
 |     // that this works correctly and the output surface is destroyed on | 
 |     // the correct thread. | 
 |     EndTest(); | 
 |   } | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestDestroyWhileInitializingOutputSurface); | 
 |  | 
 | // Makes sure that painted_device_scale_factor is propagated to the | 
 | // frame's metadata. | 
 | class LayerTreeHostTestPaintedDeviceScaleFactor : public LayerTreeHostTest { | 
 |  protected: | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     settings->use_painted_device_scale_factor = true; | 
 |     LayerTreeHostTest::InitializeSettings(settings); | 
 |   } | 
 |  | 
 |   void SetupTree() override { | 
 |     SetInitialDeviceScaleFactor(2.f); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void BeginTest() override { | 
 |     EXPECT_EQ(1.0f, layer_tree_host()->device_scale_factor()); | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     EXPECT_EQ(DRAW_SUCCESS, draw_result); | 
 |     EXPECT_EQ(2.0f, host_impl->active_tree()->painted_device_scale_factor()); | 
 |     EXPECT_EQ(1.0f, host_impl->active_tree()->device_scale_factor()); | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |   void DisplayReceivedCompositorFrameOnThread( | 
 |       const viz::CompositorFrame& frame) override { | 
 |     EXPECT_EQ(2.0f, frame.metadata.device_scale_factor); | 
 |     EndTest(); | 
 |   } | 
 | }; | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestPaintedDeviceScaleFactor); | 
 |  | 
 | // Tests that a presentation-timestamps are received for a frame. | 
 | class LayerTreeHostTestPresentationTime : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override { | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void DisplayReceivedCompositorFrameOnThread( | 
 |       const viz::CompositorFrame& frame) override { | 
 |     frame_token_ = frame.metadata.frame_token; | 
 |   } | 
 |  | 
 |   void DidReceivePresentationTimeOnThread( | 
 |       LayerTreeHostImpl* host_impl, | 
 |       uint32_t frame_token, | 
 |       const gfx::PresentationFeedback& feedback) override { | 
 |     EXPECT_EQ(frame_token_, frame_token); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void AfterTest() override { ASSERT_GT(frame_token_, 0u); } | 
 |  | 
 |  private: | 
 |   uint32_t frame_token_ = 0; | 
 | }; | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestPresentationTime); | 
 |  | 
 | // Makes sure that viz::LocalSurfaceId is propagated to the LayerTreeFrameSink. | 
 | class LayerTreeHostTestLocalSurfaceId : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override {} | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     EXPECT_EQ(DRAW_SUCCESS, draw_result); | 
 |     EXPECT_EQ( | 
 |         GetCurrentLocalSurfaceIdAllocation(), | 
 |         host_impl->active_tree()->local_surface_id_allocation_from_parent()); | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |   void DisplayReceivedLocalSurfaceIdOnThread( | 
 |       const viz::LocalSurfaceId& local_surface_id) override { | 
 |     EXPECT_EQ(GetCurrentLocalSurfaceIdAllocation().local_surface_id(), | 
 |               local_surface_id); | 
 |     EndTest(); | 
 |   } | 
 | }; | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestLocalSurfaceId); | 
 |  | 
 | // Makes sure that LayerTreeHost does not pick up changes to | 
 | // viz::LocalSurfaceIds that only involve the child sequence number. | 
 | class LayerTreeHostTestLocalSurfaceIdSkipChildNum : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override { | 
 |     EXPECT_TRUE(child_allocator_.UpdateFromParent( | 
 |         GetCurrentLocalSurfaceIdAllocation())); | 
 |   } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     EXPECT_EQ(DRAW_SUCCESS, draw_result); | 
 |     // We should not be picking up the newer |child_local_surface_id_|. | 
 |     EXPECT_EQ( | 
 |         GetCurrentLocalSurfaceIdAllocation(), | 
 |         host_impl->active_tree()->local_surface_id_allocation_from_parent()); | 
 |  | 
 |     // This initial test setup triggers a commit and subsequent draw. Upon the | 
 |     // first draw, enqueue the second portion of the test. The newly pushed id, | 
 |     // with an advanced child sequence number, but no change in parent sequence, | 
 |     // should not trigger a commit. If it does, then PrepareToDrawOnThread will | 
 |     // be called a second time, and the expectation upon viz::LocalSurfaceId | 
 |     // will fail. We do not assert on frame number, as that interferes with | 
 |     // returning from this method. We do not just have an expectation either, | 
 |     // as then we would continuously increment that child sequence until the | 
 |     // test times out. | 
 |     if (!host_impl->active_tree()->source_frame_number()) { | 
 |       child_allocator_.GenerateId(); | 
 |       child_local_surface_id_allocation_ = | 
 |           child_allocator_.GetCurrentLocalSurfaceIdAllocation(); | 
 |       EXPECT_NE(GetCurrentLocalSurfaceIdAllocation(), | 
 |                 child_local_surface_id_allocation_); | 
 |       PostSetLocalSurfaceIdAllocationToMainThread( | 
 |           child_local_surface_id_allocation_); | 
 |     } | 
 |  | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |   void DisplayReceivedLocalSurfaceIdOnThread( | 
 |       const viz::LocalSurfaceId& local_surface_id) override { | 
 |     EXPECT_EQ(GetCurrentLocalSurfaceIdAllocation().local_surface_id(), | 
 |               local_surface_id); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   viz::LocalSurfaceIdAllocation child_local_surface_id_allocation_; | 
 |   viz::ChildLocalSurfaceIdAllocator child_allocator_; | 
 | }; | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestLocalSurfaceIdSkipChildNum); | 
 |  | 
 | // Makes sure that viz::LocalSurfaceId allocation requests propagate all the way | 
 | // to LayerTreeFrameSink. | 
 | class LayerTreeHostTestRequestNewLocalSurfaceId : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override { | 
 |     PostRequestNewLocalSurfaceIdToMainThread(); | 
 |   } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     EXPECT_EQ(DRAW_SUCCESS, draw_result); | 
 |     EXPECT_EQ( | 
 |         GetCurrentLocalSurfaceIdAllocation(), | 
 |         host_impl->active_tree()->local_surface_id_allocation_from_parent()); | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |   void DisplayReceivedLocalSurfaceIdOnThread( | 
 |       const viz::LocalSurfaceId& local_surface_id) override { | 
 |     const viz::LocalSurfaceId& expected_parent_local_surface_id = | 
 |         GetCurrentLocalSurfaceIdAllocation().local_surface_id(); | 
 |     viz::LocalSurfaceId child_local_surface_id( | 
 |         expected_parent_local_surface_id.parent_sequence_number(), | 
 |         expected_parent_local_surface_id.child_sequence_number() + 1, | 
 |         expected_parent_local_surface_id.embed_token()); | 
 |     EXPECT_NE(expected_parent_local_surface_id, local_surface_id); | 
 |     EXPECT_EQ(child_local_surface_id, local_surface_id); | 
 |   } | 
 |  | 
 |   // This gets called after DispllayReceivedLocalSurfaceIdOnThread. | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     // Verify that the request bit doesn't stick after we submit a frame. | 
 |     EXPECT_FALSE( | 
 |         host_impl->active_tree()->new_local_surface_id_request_for_testing()); | 
 |     EndTest(); | 
 |   } | 
 | }; | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestRequestNewLocalSurfaceId); | 
 |  | 
 | // The GPU image decode controller hands images off to Skia for rasterization. | 
 | // When used with large images, the images in question could be deleted before | 
 | // Skia was done with them, causing a crash. This test performs an end-to-end | 
 | // check of large image rasterization to ensure we do not hit this crash. | 
 | // Note that this code path won't always hit the crash, even when incorrect | 
 | // behavior occurs, so this is more of a sanity check. | 
 | // TODO(ericrk): We should improve this so that we can reliably detect the | 
 | // crash. | 
 | class GpuRasterizationSucceedsWithLargeImage : public LayerTreeHostTest { | 
 |  protected: | 
 |   GpuRasterizationSucceedsWithLargeImage() | 
 |       : viewport_size_(1024, 2048), large_image_size_(20000, 10) {} | 
 |  | 
 |   void SetUpUnboundContextProviders( | 
 |       viz::TestContextProvider* context_provider, | 
 |       viz::TestContextProvider* worker_provider) override { | 
 |     context_provider->UnboundTestContextGL()->set_gpu_rasterization(true); | 
 |     worker_provider->UnboundTestContextGL()->set_gpu_rasterization(true); | 
 |   } | 
 |  | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     // Set to 0 to force at-raster GPU image decode. | 
 |     settings->decoded_image_working_set_budget_bytes = 0; | 
 |   } | 
 |  | 
 |   void SetupTree() override { | 
 |     client_.set_fill_with_nonsolid_color(true); | 
 |  | 
 |     std::unique_ptr<FakeRecordingSource> recording = | 
 |         FakeRecordingSource::CreateFilledRecordingSource( | 
 |             gfx::Size(10000, 10000)); | 
 |  | 
 |     recording->add_draw_image(CreateDiscardablePaintImage(large_image_size_), | 
 |                               gfx::Point(0, 0)); | 
 |     recording->Rerecord(); | 
 |  | 
 |     scoped_refptr<FakePictureLayer> root = | 
 |         FakePictureLayer::CreateWithRecordingSource(&client_, | 
 |                                                     std::move(recording)); | 
 |     root->SetBounds(gfx::Size(10000, 10000)); | 
 |     client_.set_bounds(root->bounds()); | 
 |     root->SetContentsOpaque(true); | 
 |  | 
 |     layer_tree_host()->SetRootLayer(root); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(viewport_size_), 1.f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |     client_.set_bounds(root->bounds()); | 
 |   } | 
 |  | 
 |   void InitializedRendererOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    bool success) override { | 
 |     // Check that our large_image_size_ is greater than max texture size. We do | 
 |     // this here to ensure that our otuput surface exists. | 
 |  | 
 |     // Retrieve max texture size from Skia. | 
 |     viz::ContextProvider* context_provider = | 
 |         host_impl->layer_tree_frame_sink()->context_provider(); | 
 |     ASSERT_TRUE(context_provider); | 
 |  | 
 |     GrContext* gr_context = context_provider->GrContext(); | 
 |     ASSERT_TRUE(gr_context); | 
 |     const uint32_t max_texture_size = gr_context->maxTextureSize(); | 
 |     ASSERT_GT(static_cast<uint32_t>(large_image_size_.width()), | 
 |               max_texture_size); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommit() override { EndTest(); } | 
 |  | 
 |  private: | 
 |   FakeContentLayerClient client_; | 
 |   const gfx::Size viewport_size_; | 
 |   const gfx::Size large_image_size_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(GpuRasterizationSucceedsWithLargeImage); | 
 |  | 
 | class LayerTreeHostTestSubmitFrameMetadata : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override { | 
 |     layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f); | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     EXPECT_EQ(DRAW_SUCCESS, draw_result); | 
 |     EXPECT_EQ(0, num_swaps_); | 
 |     drawn_viewport_ = host_impl->active_tree()->GetDeviceViewport(); | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |   void DisplayReceivedCompositorFrameOnThread( | 
 |       const viz::CompositorFrame& frame) override { | 
 |     EXPECT_EQ(1, ++num_swaps_); | 
 |  | 
 |     EXPECT_EQ(drawn_viewport_, frame.render_pass_list.back()->output_rect); | 
 |     EXPECT_EQ(0.5f, frame.metadata.min_page_scale_factor); | 
 |     EXPECT_EQ(0u, frame.resource_list.size()); | 
 |     EXPECT_EQ(1u, frame.render_pass_list.size()); | 
 |  | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   int num_swaps_ = 0; | 
 |   gfx::Rect drawn_viewport_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSubmitFrameMetadata); | 
 |  | 
 | class LayerTreeHostTestSubmitFrameResources : public LayerTreeHostTest { | 
 |  protected: | 
 |   std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink( | 
 |       const viz::RendererSettings& renderer_settings, | 
 |       double refresh_rate, | 
 |       scoped_refptr<viz::ContextProvider> compositor_context_provider, | 
 |       scoped_refptr<viz::RasterContextProvider> worker_context_provider) | 
 |       override { | 
 |     auto gl = std::make_unique<viz::TestGLES2Interface>(); | 
 |     gl->set_have_extension_egl_image(true); | 
 |     auto provider = viz::TestContextProvider::Create(std::move(gl)); | 
 |     return LayerTreeTest::CreateLayerTreeFrameSink( | 
 |         renderer_settings, refresh_rate, std::move(provider), | 
 |         std::move(worker_context_provider)); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame, | 
 |                                    DrawResult draw_result) override { | 
 |     frame->render_passes.clear(); | 
 |  | 
 |     viz::RenderPass* child_pass = | 
 |         AddRenderPass(&frame->render_passes, 2, gfx::Rect(3, 3, 10, 10), | 
 |                       gfx::Transform(), FilterOperations()); | 
 |     std::vector<viz::ResourceId> child_resources = | 
 |         AddOneOfEveryQuadType(child_pass, host_impl->resource_provider(), 0); | 
 |  | 
 |     viz::RenderPass* pass = | 
 |         AddRenderPass(&frame->render_passes, 1, gfx::Rect(3, 3, 10, 10), | 
 |                       gfx::Transform(), FilterOperations()); | 
 |     std::vector<viz::ResourceId> root_resources = AddOneOfEveryQuadType( | 
 |         pass, host_impl->resource_provider(), child_pass->id); | 
 |  | 
 |     auto append = [](std::vector<viz::ResourceId>* to, | 
 |                      std::vector<viz::ResourceId> from) { | 
 |       to->insert(to->end(), from.begin(), from.end()); | 
 |     }; | 
 |     append(&resources_, child_resources); | 
 |     append(&resources_, root_resources); | 
 |  | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     // The resources have been submitted to the display compositor by now, we | 
 |     // can remove them from cc now, so that they are not leaked. | 
 |     for (viz::ResourceId id : resources_) | 
 |       host_impl->resource_provider()->RemoveImportedResource(id); | 
 |   } | 
 |  | 
 |   void DisplayReceivedCompositorFrameOnThread( | 
 |       const viz::CompositorFrame& frame) override { | 
 |     EXPECT_EQ(2u, frame.render_pass_list.size()); | 
 |     // Each render pass has 10 resources in it. And the root render pass has a | 
 |     // mask resource used when drawing the child render pass. The number 10 may | 
 |     // change if AppendOneOfEveryQuadType() is updated, and the value here | 
 |     // should be updated accordingly. | 
 |     EXPECT_EQ(21u, frame.resource_list.size()); | 
 |  | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   std::vector<viz::ResourceId> resources_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSubmitFrameResources); | 
 |  | 
 | class LayerTreeHostTestBeginFrameAcks : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void WillBeginImplFrameOnThread(LayerTreeHostImpl* impl, | 
 |                                   const viz::BeginFrameArgs& args) override { | 
 |     EXPECT_TRUE(args.IsValid()); | 
 |     current_begin_frame_args_ = args; | 
 |   } | 
 |  | 
 |   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* impl, | 
 |                                    LayerTreeHostImpl::FrameData* frame_data, | 
 |                                    DrawResult draw_result) override { | 
 |     frame_data_ = frame_data; | 
 |     return draw_result; | 
 |   } | 
 |  | 
 |   void DisplayReceivedCompositorFrameOnThread( | 
 |       const viz::CompositorFrame& frame) override { | 
 |     if (compositor_frame_submitted_) | 
 |       return; | 
 |     compositor_frame_submitted_ = true; | 
 |  | 
 |     EXPECT_EQ(viz::BeginFrameAck(current_begin_frame_args_, true), | 
 |               frame.metadata.begin_frame_ack); | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* impl) override { | 
 |     if (layers_drawn_) | 
 |       return; | 
 |     layers_drawn_ = true; | 
 |  | 
 |     EXPECT_TRUE(frame_data_); | 
 |     EXPECT_TRUE(compositor_frame_submitted_); | 
 |     EXPECT_EQ(viz::BeginFrameAck(current_begin_frame_args_, true), | 
 |               frame_data_->begin_frame_ack); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   void AfterTest() override { EXPECT_TRUE(layers_drawn_); } | 
 |  | 
 |  private: | 
 |   bool compositor_frame_submitted_ = false; | 
 |   bool layers_drawn_ = false; | 
 |   viz::BeginFrameArgs current_begin_frame_args_; | 
 |   LayerTreeHostImpl::FrameData* frame_data_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_BLOCKNOTIFY_TEST_F(LayerTreeHostTestBeginFrameAcks); | 
 |  | 
 | class LayerTreeHostTestQueueImageDecode : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     settings->enable_checker_imaging = true; | 
 |     settings->min_image_bytes_to_checker = 512 * 1024; | 
 |   } | 
 |  | 
 |   void WillBeginMainFrame() override { | 
 |     if (!first_) | 
 |       return; | 
 |     first_ = false; | 
 |  | 
 |     image_ = DrawImage(CreateDiscardablePaintImage(gfx::Size(400, 400)), | 
 |                        SkIRect::MakeWH(400, 400), kNone_SkFilterQuality, | 
 |                        SkMatrix::I(), PaintImage::kDefaultFrameIndex, | 
 |                        gfx::ColorSpace()); | 
 |     auto callback = base::BindRepeating( | 
 |         &LayerTreeHostTestQueueImageDecode::ImageDecodeFinished, | 
 |         base::Unretained(this)); | 
 |     // Schedule the decode twice for the same image. | 
 |     layer_tree_host()->QueueImageDecode(image_.paint_image(), callback); | 
 |     layer_tree_host()->QueueImageDecode(image_.paint_image(), callback); | 
 |   } | 
 |  | 
 |   void ReadyToCommitOnThread(LayerTreeHostImpl* impl) override { | 
 |     if (one_commit_done_) | 
 |       return; | 
 |     EXPECT_FALSE( | 
 |         impl->tile_manager()->checker_image_tracker().ShouldCheckerImage( | 
 |             image_, WhichTree::PENDING_TREE)); | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | 
 |     one_commit_done_ = true; | 
 |     EXPECT_FALSE( | 
 |         impl->tile_manager()->checker_image_tracker().ShouldCheckerImage( | 
 |             image_, WhichTree::PENDING_TREE)); | 
 |   } | 
 |  | 
 |   void ImageDecodeFinished(bool decode_succeeded) { | 
 |     EXPECT_TRUE(decode_succeeded); | 
 |     ++finished_decode_count_; | 
 |     EXPECT_LE(finished_decode_count_, 2); | 
 |     if (finished_decode_count_ == 2) | 
 |       EndTest(); | 
 |   } | 
 |  | 
 |  private: | 
 |   bool first_ = true; | 
 |   bool one_commit_done_ = false; | 
 |   int finished_decode_count_ = 0; | 
 |   DrawImage image_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestQueueImageDecode); | 
 |  | 
 | class LayerTreeHostTestQueueImageDecodeNonLazy : public LayerTreeHostTest { | 
 |  protected: | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void WillBeginMainFrame() override { | 
 |     if (!first_) | 
 |       return; | 
 |     first_ = false; | 
 |  | 
 |     bitmap_.allocN32Pixels(10, 10); | 
 |     PaintImage image = PaintImageBuilder::WithDefault() | 
 |                            .set_id(PaintImage::GetNextId()) | 
 |                            .set_image(SkImage::MakeFromBitmap(bitmap_), | 
 |                                       PaintImage::GetNextContentId()) | 
 |                            .TakePaintImage(); | 
 |     auto callback = base::BindOnce( | 
 |         &LayerTreeHostTestQueueImageDecodeNonLazy::ImageDecodeFinished, | 
 |         base::Unretained(this)); | 
 |     layer_tree_host()->QueueImageDecode(image, std::move(callback)); | 
 |   } | 
 |  | 
 |   void ImageDecodeFinished(bool decode_succeeded) { | 
 |     EXPECT_TRUE(decode_succeeded); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |  private: | 
 |   bool first_ = true; | 
 |   SkBitmap bitmap_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestQueueImageDecodeNonLazy); | 
 |  | 
 | class LayerTreeHostTestHudLayerWithLayerLists : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestHudLayerWithLayerLists() { SetUseLayerLists(); } | 
 |  | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     settings->initial_debug_state.show_paint_rects = true; | 
 |   } | 
 |  | 
 |   void BeginTest() override { | 
 |     // The HUD layer should not have been setup. | 
 |     DCHECK_EQ(layer_tree_host()->hud_layer(), nullptr); | 
 |     PostSetNeedsCommitToMainThread(); | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { EndTest(); } | 
 |  | 
 |   void DidCommit() override { | 
 |     auto* hud = layer_tree_host()->hud_layer(); | 
 |     DCHECK(hud); | 
 |     auto* root_layer = layer_tree_host()->root_layer(); | 
 |     DCHECK_EQ(hud->transform_tree_index(), root_layer->transform_tree_index()); | 
 |     DCHECK_EQ(hud->clip_tree_index(), root_layer->clip_tree_index()); | 
 |     DCHECK_EQ(hud->effect_tree_index(), root_layer->effect_tree_index()); | 
 |     DCHECK_EQ(hud->scroll_tree_index(), root_layer->scroll_tree_index()); | 
 |   } | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestHudLayerWithLayerLists); | 
 |  | 
 | // Verifies that LayerTreeHostClient does not receive frame acks from a released | 
 | // LayerTreeFrameSink. | 
 | class LayerTreeHostTestDiscardAckAfterRelease : public LayerTreeHostTest { | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     scoped_refptr<Layer> root = Layer::Create(); | 
 |     root->SetBounds(gfx::Size(10, 10)); | 
 |     layer_tree_host()->SetRootLayer(std::move(root)); | 
 |     LayerTreeHostTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void WillReceiveCompositorFrameAckOnThread( | 
 |       LayerTreeHostImpl* host_impl) override { | 
 |     // This method is called before ack is posted to main thread. This ensures | 
 |     // that WillReceiveCompositorFrameAck which we PostTask below will be called | 
 |     // before DidReceiveCompositorFrameAck. | 
 |     MainThreadTaskRunner()->PostTask( | 
 |         FROM_HERE, base::BindOnce(&LayerTreeHostTestDiscardAckAfterRelease:: | 
 |                                       WillReceiveCompositorFrameAck, | 
 |                                   base::Unretained(this))); | 
 |   } | 
 |  | 
 |   void WillReceiveCompositorFrameAck() { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         // For the first commit, don't release the LayerTreeFrameSink. We must | 
 |         // receive the ack later on. | 
 |         break; | 
 |       case 2: | 
 |         // Release the LayerTreeFrameSink for the second commit. We'll later | 
 |         // check that the ack is discarded. | 
 |         layer_tree_host()->SetVisible(false); | 
 |         layer_tree_host()->ReleaseLayerTreeFrameSink(); | 
 |         break; | 
 |       default: | 
 |         NOTREACHED(); | 
 |     } | 
 |   } | 
 |  | 
 |   void DidReceiveCompositorFrameAckOnThread( | 
 |       LayerTreeHostImpl* host_impl) override { | 
 |     // Since this method is called after ack is posted to main thread, we can be | 
 |     // sure that if the ack is not discarded, it will be definitely received | 
 |     // before we are in CheckFrameAck. | 
 |     MainThreadTaskRunner()->PostTask( | 
 |         FROM_HERE, | 
 |         base::BindOnce(&LayerTreeHostTestDiscardAckAfterRelease::CheckFrameAck, | 
 |                        base::Unretained(this))); | 
 |   } | 
 |  | 
 |   void DidReceiveCompositorFrameAck() override { received_ack_ = true; } | 
 |  | 
 |   void CheckFrameAck() { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         // LayerTreeFrameSink was not released. We must receive the ack. | 
 |         EXPECT_TRUE(received_ack_); | 
 |         // Cause damage so that we draw and swap. | 
 |         layer_tree_host()->root_layer()->SetBackgroundColor(SK_ColorGREEN); | 
 |         break; | 
 |       case 2: | 
 |         // LayerTreeFrameSink was released. The ack must be discarded. | 
 |         EXPECT_FALSE(received_ack_); | 
 |         EndTest(); | 
 |         break; | 
 |       default: | 
 |         NOTREACHED(); | 
 |     } | 
 |     received_ack_ = false; | 
 |   } | 
 |  | 
 |  private: | 
 |   bool received_ack_ = false; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestDiscardAckAfterRelease); | 
 |  | 
 | class LayerTreeHostTestImageAnimation : public LayerTreeHostTest { | 
 |  public: | 
 |   explicit LayerTreeHostTestImageAnimation(RendererType type = RENDERER_GL) | 
 |       : LayerTreeHostTest(type) {} | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   virtual void AddImageOp(const PaintImage& image) = 0; | 
 |  | 
 |   void SetupTree() override { | 
 |     gfx::Size layer_size(1000, 500); | 
 |     content_layer_client_.set_bounds(layer_size); | 
 |     content_layer_client_.set_fill_with_nonsolid_color(true); | 
 |     std::vector<FrameMetadata> frames = { | 
 |         FrameMetadata(true, base::TimeDelta::FromSeconds(1)), | 
 |         FrameMetadata(true, base::TimeDelta::FromSeconds(1)), | 
 |         FrameMetadata(true, base::TimeDelta::FromSeconds(1))}; | 
 |     generator_ = sk_make_sp<FakePaintImageGenerator>( | 
 |         SkImageInfo::MakeN32Premul(500, 500, SkColorSpace::MakeSRGB()), frames); | 
 |     PaintImage image = | 
 |         PaintImageBuilder::WithDefault() | 
 |             .set_id(PaintImage::GetNextId()) | 
 |             .set_paint_image_generator(generator_) | 
 |             .set_animation_type(PaintImage::AnimationType::ANIMATED) | 
 |             .set_repetition_count(kAnimationLoopOnce) | 
 |             .TakePaintImage(); | 
 |     AddImageOp(image); | 
 |  | 
 |     layer_tree_host()->SetRootLayer( | 
 |         FakePictureLayer::Create(&content_layer_client_)); | 
 |     layer_tree_host()->root_layer()->SetBounds(layer_size); | 
 |     LayerTreeTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void WillPrepareToDrawOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     gfx::Rect image_rect(-1, -1, 502, 502); | 
 |     auto* layer = | 
 |         static_cast<PictureLayerImpl*>(host_impl->active_tree()->root_layer()); | 
 |     switch (++draw_count_) { | 
 |       case 1: | 
 |         // First draw, everything is invalid. | 
 |         EXPECT_EQ(layer->InvalidationForTesting().bounds(), | 
 |                   gfx::Rect(layer->bounds())); | 
 |         EXPECT_EQ(layer->update_rect(), gfx::Rect(layer->bounds())); | 
 |         EXPECT_EQ(generator_->frames_decoded().size(), 1u); | 
 |         EXPECT_EQ(generator_->frames_decoded().count(0u), 1u); | 
 |         break; | 
 |       case 2: | 
 |         // Every frame after the first one should invalidate only the image. | 
 |         EXPECT_EQ(layer->InvalidationForTesting().bounds(), image_rect); | 
 |         EXPECT_EQ(layer->update_rect(), image_rect); | 
 |         EXPECT_EQ(generator_->frames_decoded().size(), 2u); | 
 |         EXPECT_EQ(generator_->frames_decoded().count(1u), 1u); | 
 |         break; | 
 |       case 3: | 
 |         EXPECT_EQ(layer->InvalidationForTesting().bounds(), image_rect); | 
 |         EXPECT_EQ(layer->update_rect(), image_rect); | 
 |         EXPECT_EQ(generator_->frames_decoded().size(), 3u); | 
 |         EXPECT_EQ(generator_->frames_decoded().count(2u), 1u); | 
 |         break; | 
 |       default: | 
 |         // Only 3 draws should happen for 3 frames of the animate image. | 
 |         NOTREACHED(); | 
 |     } | 
 |  | 
 |     if (draw_count_ == 3) | 
 |       EndTest(); | 
 |   } | 
 |  | 
 |   void AfterTest() override { | 
 |     EXPECT_EQ(generator_->frames_decoded().size(), 3u); | 
 |   } | 
 |  | 
 |  protected: | 
 |   FakeContentLayerClient content_layer_client_; | 
 |   sk_sp<FakePaintImageGenerator> generator_; | 
 |   int draw_count_ = 0; | 
 | }; | 
 |  | 
 | class LayerTreeHostTestImageAnimationDrawImage | 
 |     : public LayerTreeHostTestImageAnimation { | 
 |  public: | 
 |   explicit LayerTreeHostTestImageAnimationDrawImage( | 
 |       RendererType type = RENDERER_GL) | 
 |       : LayerTreeHostTestImageAnimation(type) {} | 
 |  | 
 |  private: | 
 |   void AddImageOp(const PaintImage& image) override { | 
 |     content_layer_client_.add_draw_image(image, gfx::Point(0, 0), PaintFlags()); | 
 |   } | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestImageAnimationDrawImage); | 
 |  | 
 | class LayerTreeHostTestImageAnimationDrawImageShader | 
 |     : public LayerTreeHostTestImageAnimation { | 
 |   void AddImageOp(const PaintImage& image) override { | 
 |     PaintFlags flags; | 
 |     flags.setShader(PaintShader::MakeImage(image, SkTileMode::kRepeat, | 
 |                                            SkTileMode::kRepeat, nullptr)); | 
 |     content_layer_client_.add_draw_rect(gfx::Rect(500, 500), flags); | 
 |   } | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestImageAnimationDrawImageShader); | 
 |  | 
 | class LayerTreeHostTestImageAnimationDrawRecordShader | 
 |     : public LayerTreeHostTestImageAnimation { | 
 |   void AddImageOp(const PaintImage& image) override { | 
 |     auto record = sk_make_sp<PaintOpBuffer>(); | 
 |     record->push<DrawImageOp>(image, 0.f, 0.f, nullptr); | 
 |     PaintFlags flags; | 
 |     flags.setShader(PaintShader::MakePaintRecord( | 
 |         record, SkRect::MakeWH(500, 500), SkTileMode::kClamp, | 
 |         SkTileMode::kClamp, nullptr)); | 
 |     content_layer_client_.add_draw_rect(gfx::Rect(500, 500), flags); | 
 |   } | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestImageAnimationDrawRecordShader); | 
 |  | 
 | class LayerTreeHostTestImageAnimationPaintFilter | 
 |     : public LayerTreeHostTestImageAnimation { | 
 |   void AddImageOp(const PaintImage& image) override { | 
 |     auto record = sk_make_sp<PaintOpBuffer>(); | 
 |     record->push<DrawImageOp>(image, 0.f, 0.f, nullptr); | 
 |     PaintFlags flags; | 
 |     flags.setImageFilter( | 
 |         sk_make_sp<RecordPaintFilter>(record, SkRect::MakeWH(500, 500))); | 
 |     content_layer_client_.add_draw_rect(gfx::Rect(500, 500), flags); | 
 |   } | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestImageAnimationPaintFilter); | 
 |  | 
 | class LayerTreeHostTestImageAnimationSynchronousScheduling | 
 |     : public LayerTreeHostTestImageAnimationDrawImage { | 
 |  public: | 
 |   explicit LayerTreeHostTestImageAnimationSynchronousScheduling( | 
 |       RendererType type = RENDERER_GL) | 
 |       : LayerTreeHostTestImageAnimationDrawImage(type) {} | 
 |  | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     LayerTreeHostTestImageAnimation::InitializeSettings(settings); | 
 |     settings->using_synchronous_renderer_compositor = true; | 
 |   } | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestImageAnimationSynchronousScheduling); | 
 |  | 
 | class LayerTreeHostTestImageAnimationSynchronousSchedulingSoftwareDraw | 
 |     : public LayerTreeHostTestImageAnimationSynchronousScheduling { | 
 |  public: | 
 |   LayerTreeHostTestImageAnimationSynchronousSchedulingSoftwareDraw() | 
 |       : LayerTreeHostTestImageAnimationSynchronousScheduling( | 
 |             RENDERER_SOFTWARE) {} | 
 |  | 
 |   void AfterTest() override { | 
 |     LayerTreeHostTestImageAnimationSynchronousScheduling::AfterTest(); | 
 |     // 3 frames decoded twice, once during tile raster and once during raster | 
 |     // for PictureDrawQuad. | 
 |     for (size_t i = 0u; i < 3u; ++i) { | 
 |       EXPECT_EQ(generator_->frames_decoded().find(i)->second, 2); | 
 |     } | 
 |   } | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F( | 
 |     LayerTreeHostTestImageAnimationSynchronousSchedulingSoftwareDraw); | 
 |  | 
 | class LayerTreeHostTestImageDecodingHints : public LayerTreeHostTest { | 
 |  public: | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     LayerTreeHostTest::InitializeSettings(settings); | 
 |     settings->enable_checker_imaging = true; | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void SetupTree() override { | 
 |     gfx::Size layer_size(100, 100); | 
 |     content_layer_client_.set_bounds(layer_size); | 
 |     content_layer_client_.set_fill_with_nonsolid_color(true); | 
 |     PaintImage async_image = | 
 |         PaintImageBuilder::WithCopy( | 
 |             CreateDiscardablePaintImage(gfx::Size(10, 10))) | 
 |             .set_id(1) | 
 |             .set_decoding_mode(PaintImage::DecodingMode::kAsync) | 
 |             .TakePaintImage(); | 
 |     PaintImage sync_image = | 
 |         PaintImageBuilder::WithCopy( | 
 |             CreateDiscardablePaintImage(gfx::Size(10, 10))) | 
 |             .set_id(2) | 
 |             .set_decoding_mode(PaintImage::DecodingMode::kSync) | 
 |             .TakePaintImage(); | 
 |     PaintImage unspecified_image = | 
 |         PaintImageBuilder::WithCopy( | 
 |             CreateDiscardablePaintImage(gfx::Size(10, 10))) | 
 |             .set_id(3) | 
 |             .set_decoding_mode(PaintImage::DecodingMode::kUnspecified) | 
 |             .TakePaintImage(); | 
 |     content_layer_client_.add_draw_image(async_image, gfx::Point(0, 0), | 
 |                                          PaintFlags()); | 
 |     content_layer_client_.add_draw_image(sync_image, gfx::Point(1, 2), | 
 |                                          PaintFlags()); | 
 |     content_layer_client_.add_draw_image(unspecified_image, gfx::Point(3, 4), | 
 |                                          PaintFlags()); | 
 |  | 
 |     layer_tree_host()->SetRootLayer( | 
 |         FakePictureLayer::Create(&content_layer_client_)); | 
 |     layer_tree_host()->root_layer()->SetBounds(layer_size); | 
 |     LayerTreeTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void WillPrepareToDrawOnThread(LayerTreeHostImpl* host_impl) override { | 
 |     auto& tracker = host_impl->tile_manager()->checker_image_tracker(); | 
 |     EXPECT_EQ(tracker.get_decoding_mode_hint_for_testing(1), | 
 |               PaintImage::DecodingMode::kAsync); | 
 |     EXPECT_EQ(tracker.get_decoding_mode_hint_for_testing(2), | 
 |               PaintImage::DecodingMode::kSync); | 
 |     EXPECT_EQ(tracker.get_decoding_mode_hint_for_testing(3), | 
 |               PaintImage::DecodingMode::kUnspecified); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |  private: | 
 |   FakeContentLayerClient content_layer_client_; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestImageDecodingHints); | 
 |  | 
 | class LayerTreeHostTestCheckerboardUkm : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestCheckerboardUkm() : url_(GURL("https://example.com")), | 
 |                                        ukm_source_id_(123) {} | 
 |   void BeginTest() override { | 
 |     PostSetNeedsCommitToMainThread(); | 
 |     layer_tree_host()->SetSourceURL(ukm_source_id_, url_); | 
 |   } | 
 |  | 
 |   void SetupTree() override { | 
 |     gfx::Size layer_size(100, 100); | 
 |     content_layer_client_.set_bounds(layer_size); | 
 |     content_layer_client_.set_fill_with_nonsolid_color(true); | 
 |     layer_tree_host()->SetRootLayer( | 
 |         FakePictureLayer::Create(&content_layer_client_)); | 
 |     layer_tree_host()->root_layer()->SetBounds(layer_size); | 
 |     LayerTreeTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override { | 
 |     if (impl->active_tree()->source_frame_number() != 0) | 
 |       return; | 
 |  | 
 |     // We have an active tree. Start a pinch gesture so we start recording | 
 |     // stats. | 
 |     impl->PinchGestureBegin(); | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* impl) override { | 
 |     if (!impl->pinch_gesture_active()) | 
 |       return; | 
 |  | 
 |     // We just drew a frame, stats for it should have been recorded. End the | 
 |     // gesture so they are flushed to the recorder. | 
 |     impl->PinchGestureEnd(gfx::Point(50, 50), false); | 
 |  | 
 |     // RenewTreePriority will run when the smoothness expiration timer fires. | 
 |     // Synthetically do it here so the UkmManager is notified. | 
 |     impl->RenewTreePriorityForTesting(); | 
 |  | 
 |     auto* recorder = static_cast<ukm::TestUkmRecorder*>( | 
 |         impl->ukm_manager()->recorder_for_testing()); | 
 |     // Tie the source id to the URL. In production, this is already done in | 
 |     // Document, and the source id is passed down to cc. | 
 |     recorder->UpdateSourceURL(ukm_source_id_, url_); | 
 |  | 
 |     const auto& entries = recorder->GetEntriesByName(kUserInteraction); | 
 |     EXPECT_EQ(1u, entries.size()); | 
 |     for (const auto* entry : entries) { | 
 |       recorder->ExpectEntrySourceHasUrl(entry, url_); | 
 |       recorder->ExpectEntryMetric(entry, kCheckerboardArea, 0); | 
 |       recorder->ExpectEntryMetric(entry, kMissingTiles, 0); | 
 |       recorder->ExpectEntryMetric(entry, kCheckerboardAreaRatio, 0); | 
 |     } | 
 |  | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |  private: | 
 |   const GURL url_; | 
 |   const ukm::SourceId ukm_source_id_; | 
 |   FakeContentLayerClient content_layer_client_; | 
 | }; | 
 |  | 
 | // Only multi-thread mode needs to record UKMs. | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestCheckerboardUkm); | 
 |  | 
 | class DontUpdateLayersWithEmptyBounds : public LayerTreeTest { | 
 |  protected: | 
 |   void SetupTree() override { | 
 |     auto root = FakePictureLayer::Create(&root_client_); | 
 |     child_ = FakePictureLayer::Create(&child_client_); | 
 |     mask_ = FakePictureLayer::Create(&mask_client_); | 
 |  | 
 |     // Add a lot of draw ops, to make sure the recording source | 
 |     // hits the early out and avoids being detected as solid color even | 
 |     // though it is empty. This ensures we hit later code paths that would | 
 |     // early out if solid color in CanHaveTilings(). | 
 |     PaintFlags flags; | 
 |     flags.setColor(SK_ColorRED); | 
 |     for (int i = 0; i < 100; ++i) { | 
 |       child_client_.add_draw_rect(gfx::Rect(3, 3), flags); | 
 |       mask_client_.add_draw_rect(gfx::Rect(2, 2), flags); | 
 |     } | 
 |  | 
 |     root_client_.set_bounds(gfx::Size(10, 10)); | 
 |     root->SetBounds(gfx::Size(10, 10)); | 
 |  | 
 |     child_client_.set_bounds(gfx::Size(9, 9)); | 
 |     child_->SetBounds(gfx::Size(9, 9)); | 
 |     mask_client_.set_bounds(gfx::Size(9, 9)); | 
 |     mask_->SetBounds(gfx::Size(9, 9)); | 
 |  | 
 |     child_->SetMaskLayer(mask_); | 
 |     root->AddChild(child_); | 
 |     layer_tree_host()->SetRootLayer(std::move(root)); | 
 |     LayerTreeTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommit() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         // The child and mask are updated when they have non-empty bounds. | 
 |         EXPECT_EQ(1, child_->update_count()); | 
 |         EXPECT_EQ(1, mask_->update_count()); | 
 |  | 
 |         // The child and mask become empty bounds. | 
 |         child_client_.set_bounds(gfx::Size()); | 
 |         child_->SetBounds(gfx::Size()); | 
 |         mask_client_.set_bounds(gfx::Size()); | 
 |         mask_->SetBounds(gfx::Size()); | 
 |         break; | 
 |       case 2: { | 
 |         scoped_refptr<RasterSource> child_raster = | 
 |             child_->GetRecordingSourceForTesting()->CreateRasterSource(); | 
 |         EXPECT_FALSE(child_raster->IsSolidColor()); | 
 |         scoped_refptr<RasterSource> mask_raster = | 
 |             mask_->GetRecordingSourceForTesting()->CreateRasterSource(); | 
 |         EXPECT_FALSE(mask_raster->IsSolidColor()); | 
 |       } | 
 |  | 
 |         // The child and mask are not updated when they have empty bounds. | 
 |         EXPECT_EQ(1, child_->update_count()); | 
 |         EXPECT_EQ(1, mask_->update_count()); | 
 |         EndTest(); | 
 |         break; | 
 |       default: | 
 |         ADD_FAILURE() << layer_tree_host()->SourceFrameNumber(); | 
 |     } | 
 |   } | 
 |  | 
 |   scoped_refptr<FakePictureLayer> child_; | 
 |   scoped_refptr<FakePictureLayer> mask_; | 
 |   FakeContentLayerClient root_client_; | 
 |   FakeContentLayerClient child_client_; | 
 |   FakeContentLayerClient mask_client_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(DontUpdateLayersWithEmptyBounds); | 
 |  | 
 | // Verifies that if we have a new LocalSurfaceId we submit a CompositorFrame | 
 | // even if there is no damage. | 
 | class LayerTreeHostTestNewLocalSurfaceIdForcesDraw : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestNewLocalSurfaceIdForcesDraw() {} | 
 |  | 
 |   void BeginTest() override { | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(10, 10), 1.f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |     layer_tree_host()->root_layer()->SetBounds(gfx::Size(10, 10)); | 
 |   } | 
 |  | 
 |   void DidReceiveCompositorFrameAck() override { | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         GenerateNewLocalSurfaceId(); | 
 |         PostSetLocalSurfaceIdAllocationToMainThread( | 
 |             GetCurrentLocalSurfaceIdAllocation()); | 
 |         break; | 
 |       case 2: | 
 |         EndTest(); | 
 |         break; | 
 |       default: | 
 |         NOTREACHED(); | 
 |     } | 
 |   } | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestNewLocalSurfaceIdForcesDraw); | 
 |  | 
 | // Verifies that DidReceiveCompositorFrameAck does not get sent with PostTask | 
 | // when not needed. | 
 | class DidReceiveCompositorFrameAckNotSentWhenNotNeeded | 
 |     : public LayerTreeHostTest { | 
 |  public: | 
 |   DidReceiveCompositorFrameAckNotSentWhenNotNeeded() {} | 
 |  | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     settings->send_compositor_frame_ack = false; | 
 |   } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidReceiveCompositorFrameAck() override { ADD_FAILURE(); } | 
 |  | 
 |   // DrawLayersOnThread gets called after the conditional call to | 
 |   // DidReceiveCompositorFrameAck, so we wait for it to end the test. | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* impl) override { | 
 |     if (!received_first_frame_) { | 
 |       received_first_frame_ = true; | 
 |       PostSetNeedsCommitToMainThread(); | 
 |     } else { | 
 |       EndTest(); | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   bool received_first_frame_ = false; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F( | 
 |     DidReceiveCompositorFrameAckNotSentWhenNotNeeded); | 
 |  | 
 | // Confirms that requests to force send RFM are forwarded once (and exactly | 
 | // once) to the RFM observer. Does this by drawing 3 frames and requesting | 
 | // force send from only the second then validating the request. | 
 | class LayerTreeHostTestRequestForceSendMetadata | 
 |     : public LayerTreeHostTest, | 
 |       public RenderFrameMetadataObserver { | 
 |  public: | 
 |   // Provides a wrapper which can be passed to LayerTreeHost, but just forwards | 
 |   // to the test class. | 
 |   class ForwardingRenderFrameMetadataObserver | 
 |       : public RenderFrameMetadataObserver { | 
 |    public: | 
 |     explicit ForwardingRenderFrameMetadataObserver( | 
 |         RenderFrameMetadataObserver* target) | 
 |         : target_(target) {} | 
 |  | 
 |     // RenderFrameMetadataObserver implementation. | 
 |     void BindToCurrentThread() override { target_->BindToCurrentThread(); } | 
 |     void OnRenderFrameSubmission( | 
 |         const RenderFrameMetadata& render_frame_metadata, | 
 |         viz::CompositorFrameMetadata* compositor_frame_metadata, | 
 |         bool force_send) override { | 
 |       target_->OnRenderFrameSubmission(render_frame_metadata, | 
 |                                        compositor_frame_metadata, force_send); | 
 |     } | 
 |  | 
 |    private: | 
 |     RenderFrameMetadataObserver* target_ = nullptr; | 
 |   }; | 
 |  | 
 |   LayerTreeHostTestRequestForceSendMetadata() = default; | 
 |  | 
 |   void BeginTest() override { | 
 |     // Just set up a basic frame which can be repeatedly re-drawn. | 
 |     layer_tree_host()->SetRenderFrameObserver( | 
 |         std::make_unique<ForwardingRenderFrameMetadataObserver>(this)); | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(10, 10), 1.f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |     layer_tree_host()->root_layer()->SetBounds(gfx::Size(10, 10)); | 
 |  | 
 |     layer_ = FakePictureLayer::Create(&client_); | 
 |     layer_->SetBounds(gfx::Size(10, 10)); | 
 |     layer_->SetPosition(gfx::PointF(0.f, 0.f)); | 
 |     layer_->SetIsDrawable(true); | 
 |     layer_tree_host()->root_layer()->AddChild(layer_); | 
 |  | 
 |     PostSetNeedsCommitToMainThread(); | 
 |     client_.set_bounds(layer_->bounds()); | 
 |   } | 
 |  | 
 |   void DidCommitAndDrawFrame() override { | 
 |     // Draw three frames, sending a request to force send metadata on the | 
 |     // middle (second) frame. | 
 |     if (num_draw_layers_ == 3) | 
 |       return; | 
 |     if (num_draw_layers_ == 2) | 
 |       layer_tree_host()->RequestForceSendMetadata(); | 
 |     layer_->SetNeedsDisplay(); | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* impl) override { | 
 |     num_draw_layers_++; | 
 |     if (num_draw_layers_ == 3) | 
 |       EndTest(); | 
 |   } | 
 |  | 
 |   void AfterTest() override { EXPECT_EQ(1, num_force_sends_); } | 
 |  | 
 |   // RenderFrameMetadataObserver implementation. Called on thread. | 
 |   void BindToCurrentThread() override {} | 
 |   void OnRenderFrameSubmission( | 
 |       const RenderFrameMetadata& render_frame_metadata, | 
 |       viz::CompositorFrameMetadata* compositor_frame_metadata, | 
 |       bool force_send) override { | 
 |     if (force_send) | 
 |       num_force_sends_++; | 
 |   } | 
 |  | 
 |  private: | 
 |   FakeContentLayerClient client_; | 
 |   scoped_refptr<Layer> layer_; | 
 |   int num_draw_layers_ = 0; | 
 |   int num_force_sends_ = 0; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestRequestForceSendMetadata); | 
 |  | 
 | class LayerTreeHostTestPartialTileDamage : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTestPartialTileDamage() | 
 |       : partial_damage_(20, 20, 45, 60), layer_size_(512, 512) {} | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void InitializeSettings(LayerTreeSettings* settings) override { | 
 |     settings->default_tile_size = gfx::Size(256, 256); | 
 |   } | 
 |  | 
 |   void SetupTree() override { | 
 |     content_layer_client_.set_bounds(layer_size_); | 
 |     content_layer_client_.set_fill_with_nonsolid_color(true); | 
 |     layer_tree_host()->SetRootLayer( | 
 |         FakePictureLayer::Create(&content_layer_client_)); | 
 |     layer_tree_host()->root_layer()->SetBounds(layer_size_); | 
 |     LayerTreeTest::SetupTree(); | 
 |   } | 
 |  | 
 |   void DoPartialTileInvalidation() { | 
 |     layer_tree_host()->root_layer()->SetNeedsDisplayRect(partial_damage_); | 
 |   } | 
 |  | 
 |   void DisplayReceivedCompositorFrameOnThread( | 
 |       const viz::CompositorFrame& frame) override { | 
 |     frame_count_on_impl_thread_++; | 
 |     gfx::Rect frame_damage = frame.render_pass_list.back()->damage_rect; | 
 |  | 
 |     switch (frame_count_on_impl_thread_) { | 
 |       case 1: | 
 |         // We have the first frame, which should damage everything. Schedule | 
 |         // another which partially damages one of tiles. | 
 |         MainThreadTaskRunner()->PostTask( | 
 |             FROM_HERE, | 
 |             base::BindOnce( | 
 |                 &LayerTreeHostTestPartialTileDamage::DoPartialTileInvalidation, | 
 |                 base::Unretained(this))); | 
 |         EXPECT_EQ(frame_damage, gfx::Rect(layer_size_)); | 
 |         break; | 
 |       case 2: | 
 |         EXPECT_EQ(frame_damage, partial_damage_); | 
 |         EndTest(); | 
 |     } | 
 |   } | 
 |  | 
 |  protected: | 
 |   const gfx::Rect partial_damage_; | 
 |   const gfx::Size layer_size_; | 
 |  | 
 |   // Main thread. | 
 |   FakeContentLayerClient content_layer_client_; | 
 |  | 
 |   // Impl thread. | 
 |   int frame_count_on_impl_thread_ = 0; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTestPartialTileDamage); | 
 |  | 
 | // Make sure that a change in top controls shown ratio causes an update to the | 
 | // pending tree's viewports. | 
 | class LayerTreeHostTopControlsDeltaTriggersViewportUpdate | 
 |     : public LayerTreeHostTest { | 
 |  public: | 
 |   LayerTreeHostTopControlsDeltaTriggersViewportUpdate() { SetUseLayerLists(); } | 
 |  | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void SetupTree() override { | 
 |     LayerTreeHostTest::SetupTree(); | 
 |     Layer* root_layer = layer_tree_host()->root_layer(); | 
 |     // Set up scrollable root. | 
 |     root_layer->SetBounds(gfx::Size(100, 100)); | 
 |     SetupViewport(root_layer, gfx::Size(50, 50), root_layer->bounds()); | 
 |     layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 1.f); | 
 |     // Set browser controls to be partially shown. | 
 |     layer_tree_host()->SetBrowserControlsParams( | 
 |         {kTopControlsHeight, 0, kBottomControlsHeight, 0, false /* animate */, | 
 |          true /* shrink */}); | 
 |     layer_tree_host()->SetBrowserControlsShownRatio(kTopControlsShownRatio, | 
 |                                                     kBottomControlsShownRatio); | 
 |   } | 
 |  | 
 |   void BeginCommitOnThread(LayerTreeHostImpl* impl) override { | 
 |     // Before commit the inner_viewport_container_bounds_delta() value should | 
 |     // not reflect the partially shown top controls. | 
 |     float bounds_delta = impl->pending_tree() | 
 |                              ->property_trees() | 
 |                              ->inner_viewport_container_bounds_delta() | 
 |                              .y(); | 
 |     EXPECT_EQ(bounds_delta, 0.0f); | 
 |   } | 
 |  | 
 |   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override { | 
 |     // After commit the inner_viewport_container_bounds_delta() value should | 
 |     // reflect the partially shown top controls. | 
 |     float bounds_delta = impl->pending_tree() | 
 |                              ->property_trees() | 
 |                              ->inner_viewport_container_bounds_delta() | 
 |                              .y(); | 
 |     EXPECT_EQ(bounds_delta, | 
 |               kTopControlsHeight - kTopControlsHeight * kTopControlsShownRatio); | 
 |     EndTest(); | 
 |   } | 
 |  | 
 |   static constexpr float kTopControlsHeight = 10.0f; | 
 |   static constexpr float kTopControlsShownRatio = 0.3f; | 
 |   static constexpr float kBottomControlsHeight = 10.0f; | 
 |   static constexpr float kBottomControlsShownRatio = 1.f; | 
 | }; | 
 |  | 
 | MULTI_THREAD_TEST_F(LayerTreeHostTopControlsDeltaTriggersViewportUpdate); | 
 |  | 
 | // Tests that custom sequence throughput tracking result is reported to | 
 | // LayerTreeHostClient. | 
 | constexpr MutatorHost::TrackedAnimationSequenceId kSequenceId = 1u; | 
 | class LayerTreeHostCustomThrougputTrackerTest : public LayerTreeHostTest { | 
 |  public: | 
 |   void BeginTest() override { PostSetNeedsCommitToMainThread(); } | 
 |  | 
 |   void DidCommit() override { | 
 |     // FrameSequenceTracker typically sees the following sequence: | 
 |     //   e(2,2)b(3)B(0,3)E(3)s(3)S(3)e(3,3)P(3)b(4)B(3,4)E(4)s(4)S(4)e(4,4)P(4) | 
 |     switch (layer_tree_host()->SourceFrameNumber()) { | 
 |       case 1: | 
 |         animation_host()->StartThroughputTracking(kSequenceId); | 
 |         break; | 
 |       case 3: | 
 |         animation_host()->StopThroughputTracking(kSequenceId); | 
 |         break; | 
 |       default: | 
 |         break; | 
 |     } | 
 |  | 
 |     PostSetNeedsCommitWithForcedRedrawToMainThread(); | 
 |   } | 
 |  | 
 |   void NotifyThroughputTrackerResults(CustomTrackerResults results) override { | 
 |     // Check that data for kSequenceId is captured. Ideally, we should get | 
 |     // 2 frame_expected and 2 frame_produced. But on slow bots, it is difficult | 
 |     // to infer the correct numbers. Both frame_expected and frame_produced | 
 |     // could drop to 1 (or even below). So no sanity check on data itself. | 
 |     ASSERT_TRUE(base::Contains(results, kSequenceId)); | 
 |  | 
 |     EndTest(); | 
 |   } | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCustomThrougputTrackerTest); | 
 |  | 
 | // Confirm that DelegatedInkMetadata set on the LTH propagates to the | 
 | // CompositorFrameMetadata and RenderFrameMetadata, and then both are correctly | 
 | // reset when another frame is drawn without DelegatedInkMetadata. | 
 | class LayerTreeHostTestDelegatedInkMetadataOnAndOff | 
 |     : public LayerTreeHostTest, | 
 |       public RenderFrameMetadataObserver { | 
 |  public: | 
 |   // Provides a wrapper which can be passed to LayerTreeHost, but just forwards | 
 |   // to the test class. | 
 |   class ForwardingRenderFrameMetadataObserver | 
 |       : public RenderFrameMetadataObserver { | 
 |    public: | 
 |     explicit ForwardingRenderFrameMetadataObserver( | 
 |         RenderFrameMetadataObserver* target) | 
 |         : target_(target) {} | 
 |  | 
 |     // RenderFrameMetadataObserver implementation. | 
 |     void BindToCurrentThread() override { target_->BindToCurrentThread(); } | 
 |     void OnRenderFrameSubmission( | 
 |         const RenderFrameMetadata& render_frame_metadata, | 
 |         viz::CompositorFrameMetadata* compositor_frame_metadata, | 
 |         bool force_send) override { | 
 |       target_->OnRenderFrameSubmission(render_frame_metadata, | 
 |                                        compositor_frame_metadata, force_send); | 
 |     } | 
 |  | 
 |    private: | 
 |     RenderFrameMetadataObserver* target_ = nullptr; | 
 |   }; | 
 |  | 
 |   void BeginTest() override { | 
 |     // Set up a basic render frame observer for the LTH/LTHI to forward to. | 
 |     layer_tree_host()->SetRenderFrameObserver( | 
 |         std::make_unique<ForwardingRenderFrameMetadataObserver>(this)); | 
 |  | 
 |     // Setting up a basic frame that can be redrawn. | 
 |     layer_tree_host()->SetViewportRectAndScale(gfx::Rect(10, 10), 1.f, | 
 |                                                viz::LocalSurfaceIdAllocation()); | 
 |     layer_tree_host()->root_layer()->SetBounds(gfx::Size(10, 10)); | 
 |     layer_ = FakePictureLayer::Create(&client_); | 
 |     layer_tree_host()->root_layer()->AddChild(layer_); | 
 |     client_.set_bounds(layer_->bounds()); | 
 |  | 
 |     // Values chosen arbitrarily | 
 |     SkColor color = SK_ColorDKGRAY; | 
 |     double diameter = 1.000002; | 
 |     gfx::PointF point = gfx::PointF(135, 45); | 
 |     gfx::RectF area = gfx::RectF(173, 438); | 
 |     base::TimeTicks timestamp = base::TimeTicks::Now(); | 
 |  | 
 |     expected_metadata_ = | 
 |         viz::DelegatedInkMetadata(point, diameter, color, timestamp, area); | 
 |     layer_tree_host()->SetDelegatedInkMetadata( | 
 |         std::make_unique<viz::DelegatedInkMetadata>( | 
 |             expected_metadata_.value())); | 
 |   } | 
 |  | 
 |   void DidCommitAndDrawFrame() override { | 
 |     // Cause a redraw to occur. | 
 |     layer_->SetNeedsDisplay(); | 
 |   } | 
 |  | 
 |   void DrawLayersOnThread(LayerTreeHostImpl* impl) override { | 
 |     if (expected_metadata_.has_value()) { | 
 |       // Now try again with no metadata to confirm everything is cleared out. | 
 |       expected_metadata_.reset(); | 
 |     } | 
 |   } | 
 |  | 
 |   void ExpectMetadata(bool had_delegated_ink_metadata, | 
 |                       viz::DelegatedInkMetadata* actual_metadata) { | 
 |     if (expected_metadata_.has_value()) { | 
 |       EXPECT_TRUE(had_delegated_ink_metadata); | 
 |       EXPECT_TRUE(actual_metadata); | 
 |       EXPECT_EQ(expected_metadata_->point(), actual_metadata->point()); | 
 |       EXPECT_EQ(expected_metadata_->color(), actual_metadata->color()); | 
 |       EXPECT_EQ(expected_metadata_->diameter(), actual_metadata->diameter()); | 
 |       EXPECT_EQ(expected_metadata_->presentation_area(), | 
 |                 actual_metadata->presentation_area()); | 
 |       EXPECT_EQ(expected_metadata_->timestamp(), actual_metadata->timestamp()); | 
 |     } else { | 
 |       EXPECT_FALSE(had_delegated_ink_metadata); | 
 |       EXPECT_FALSE(actual_metadata); | 
 |       EndTest(); | 
 |     } | 
 |   } | 
 |  | 
 |   void AfterTest() override {} | 
 |  | 
 |   // RenderFrameMetadataObserver implementation. | 
 |   void BindToCurrentThread() override {} | 
 |   void OnRenderFrameSubmission( | 
 |       const RenderFrameMetadata& render_frame_metadata, | 
 |       viz::CompositorFrameMetadata* compositor_frame_metadata, | 
 |       bool force_send) override { | 
 |     ExpectMetadata(render_frame_metadata.has_delegated_ink_metadata, | 
 |                    compositor_frame_metadata->delegated_ink_metadata.get()); | 
 |   } | 
 |  | 
 |  private: | 
 |   base::Optional<viz::DelegatedInkMetadata> expected_metadata_; | 
 |   FakeContentLayerClient client_; | 
 |   scoped_refptr<Layer> layer_; | 
 | }; | 
 |  | 
 | SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestDelegatedInkMetadataOnAndOff); | 
 |  | 
 | }  // namespace | 
 | }  // namespace cc |