summaryrefslogtreecommitdiff
path: root/chromium/cc/trees/layer_tree_host_unittest_damage.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/cc/trees/layer_tree_host_unittest_damage.cc')
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_damage.cc391
1 files changed, 391 insertions, 0 deletions
diff --git a/chromium/cc/trees/layer_tree_host_unittest_damage.cc b/chromium/cc/trees/layer_tree_host_unittest_damage.cc
new file mode 100644
index 00000000000..805c9275c14
--- /dev/null
+++ b/chromium/cc/trees/layer_tree_host_unittest_damage.cc
@@ -0,0 +1,391 @@
+// Copyright 2012 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 "cc/test/fake_content_layer.h"
+#include "cc/test/fake_content_layer_client.h"
+#include "cc/test/fake_scrollbar_layer.h"
+#include "cc/test/layer_tree_test.h"
+#include "cc/trees/damage_tracker.h"
+#include "cc/trees/layer_tree_impl.h"
+
+namespace cc {
+namespace {
+
+// These tests deal with damage tracking.
+class LayerTreeHostDamageTest : public LayerTreeTest {};
+
+class LayerTreeHostDamageTestNoDamageDoesNotSwap
+ : public LayerTreeHostDamageTest {
+ virtual void BeginTest() OVERRIDE {
+ expect_swap_and_succeed_ = 0;
+ did_swaps_ = 0;
+ did_swap_and_succeed_ = 0;
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void SetupTree() OVERRIDE {
+ scoped_refptr<FakeContentLayer> root = FakeContentLayer::Create(&client_);
+ root->SetBounds(gfx::Size(10, 10));
+
+ // Most of the layer isn't visible.
+ content_ = FakeContentLayer::Create(&client_);
+ content_->SetBounds(gfx::Size(2000, 100));
+ root->AddChild(content_);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeHostDamageTest::SetupTree();
+ }
+
+ virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ bool result) OVERRIDE {
+ EXPECT_TRUE(result);
+
+ int source_frame = host_impl->active_tree()->source_frame_number();
+ switch (source_frame) {
+ case 0:
+ // The first frame has damage, so we should draw and swap.
+ ++expect_swap_and_succeed_;
+ break;
+ case 1:
+ // The second frame has no damage, so we should not draw and swap.
+ break;
+ case 2:
+ // The third frame has damage again, so we should draw and swap.
+ ++expect_swap_and_succeed_;
+ break;
+ case 3:
+ // The fourth frame has no visible damage, so we should not draw and
+ // swap.
+ EndTest();
+ break;
+ }
+ return result;
+ }
+
+ virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
+ bool result) OVERRIDE {
+ ++did_swaps_;
+ if (result)
+ ++did_swap_and_succeed_;
+ EXPECT_EQ(expect_swap_and_succeed_, did_swap_and_succeed_);
+ }
+
+ virtual void DidCommit() OVERRIDE {
+ int next_frame = layer_tree_host()->source_frame_number();
+ switch (next_frame) {
+ case 1:
+ layer_tree_host()->SetNeedsCommit();
+ break;
+ case 2:
+ // Cause visible damage.
+ content_->SetNeedsDisplayRect(
+ gfx::Rect(layer_tree_host()->device_viewport_size()));
+ break;
+ case 3:
+ // Cause non-visible damage.
+ content_->SetNeedsDisplayRect(gfx::Rect(1990, 1990, 10, 10));
+ layer_tree_host()->SetNeedsCommit();
+ break;
+ }
+ }
+
+ virtual void AfterTest() OVERRIDE {
+ EXPECT_EQ(4, did_swaps_);
+ EXPECT_EQ(2, expect_swap_and_succeed_);
+ EXPECT_EQ(expect_swap_and_succeed_, did_swap_and_succeed_);
+ }
+
+ FakeContentLayerClient client_;
+ scoped_refptr<FakeContentLayer> content_;
+ int expect_swap_and_succeed_;
+ int did_swaps_;
+ int did_swap_and_succeed_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestNoDamageDoesNotSwap);
+
+class LayerTreeHostDamageTestNoDamageReadbackDoesDraw
+ : public LayerTreeHostDamageTest {
+ virtual void BeginTest() OVERRIDE {
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void SetupTree() OVERRIDE {
+ scoped_refptr<FakeContentLayer> root = FakeContentLayer::Create(&client_);
+ root->SetBounds(gfx::Size(10, 10));
+
+ // Most of the layer isn't visible.
+ content_ = FakeContentLayer::Create(&client_);
+ content_->SetBounds(gfx::Size(100, 100));
+ root->AddChild(content_);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeHostDamageTest::SetupTree();
+ }
+
+ virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ bool result) OVERRIDE {
+ EXPECT_TRUE(result);
+
+ int source_frame = host_impl->active_tree()->source_frame_number();
+ switch (source_frame) {
+ case 0:
+ // The first frame draws and clears any damage.
+ break;
+ case 1: {
+ // The second frame is a readback, we should have damage in the readback
+ // rect, but not swap.
+ RenderSurfaceImpl* root_surface =
+ host_impl->active_tree()->root_layer()->render_surface();
+ gfx::RectF root_damage =
+ root_surface->damage_tracker()->current_damage_rect();
+ root_damage.Intersect(root_surface->content_rect());
+ EXPECT_TRUE(root_damage.Contains(gfx::Rect(3, 3, 1, 1)));
+ break;
+ }
+ case 2:
+ // CompositeAndReadback causes a follow-up commit.
+ break;
+ case 3:
+ NOTREACHED();
+ break;
+ }
+ return result;
+ }
+
+ virtual void DidCommitAndDrawFrame() OVERRIDE {
+ int next_frame = layer_tree_host()->source_frame_number();
+ switch (next_frame) {
+ case 1: {
+ char pixels[4];
+ layer_tree_host()->CompositeAndReadback(static_cast<void*>(&pixels),
+ gfx::Rect(3, 3, 1, 1));
+ EndTest();
+ break;
+ }
+ }
+ }
+
+ virtual void AfterTest() OVERRIDE {}
+
+ FakeContentLayerClient client_;
+ scoped_refptr<FakeContentLayer> content_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestNoDamageReadbackDoesDraw);
+
+class LayerTreeHostDamageTestForcedFullDamage : public LayerTreeHostDamageTest {
+ virtual void BeginTest() OVERRIDE {
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void SetupTree() OVERRIDE {
+ root_ = FakeContentLayer::Create(&client_);
+ child_ = FakeContentLayer::Create(&client_);
+
+ root_->SetBounds(gfx::Size(500, 500));
+ child_->SetPosition(gfx::Point(100, 100));
+ child_->SetBounds(gfx::Size(30, 30));
+
+ root_->AddChild(child_);
+ layer_tree_host()->SetRootLayer(root_);
+ LayerTreeHostDamageTest::SetupTree();
+ }
+
+ virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ bool result) OVERRIDE {
+ EXPECT_TRUE(result);
+
+ RenderSurfaceImpl* root_surface =
+ host_impl->active_tree()->root_layer()->render_surface();
+ gfx::RectF root_damage =
+ root_surface->damage_tracker()->current_damage_rect();
+ root_damage.Intersect(root_surface->content_rect());
+
+ int source_frame = host_impl->active_tree()->source_frame_number();
+ switch (source_frame) {
+ case 0:
+ // The first frame draws and clears any damage.
+ EXPECT_EQ(gfx::RectF(root_surface->content_rect()).ToString(),
+ root_damage.ToString());
+ EXPECT_FALSE(frame_data->has_no_damage);
+ break;
+ case 1:
+ // If we get a frame without damage then we don't draw.
+ EXPECT_EQ(gfx::RectF().ToString(), root_damage.ToString());
+ EXPECT_TRUE(frame_data->has_no_damage);
+
+ // Then we set full damage for the next frame.
+ host_impl->SetFullRootLayerDamage();
+ break;
+ case 2:
+ // The whole frame should be damaged as requested.
+ EXPECT_EQ(gfx::RectF(root_surface->content_rect()).ToString(),
+ root_damage.ToString());
+ EXPECT_FALSE(frame_data->has_no_damage);
+
+ // Just a part of the next frame should be damaged.
+ child_damage_rect_ = gfx::RectF(10, 11, 12, 13);
+ break;
+ case 3:
+ if (!delegating_renderer() &&
+ !host_impl->settings().impl_side_painting) {
+ // The update rect in the child should be damaged.
+ // TODO(danakj): Remove this when impl side painting is always on.
+ EXPECT_EQ(gfx::RectF(100+10, 100+11, 12, 13).ToString(),
+ root_damage.ToString());
+ } else {
+ // When using a delegating renderer, or using impl side painting, the
+ // entire child is considered damaged as we need to replace its
+ // resources with newly created ones.
+ EXPECT_EQ(gfx::RectF(child_->position(), child_->bounds()).ToString(),
+ root_damage.ToString());
+ }
+ EXPECT_FALSE(frame_data->has_no_damage);
+
+ // If we damage part of the frame, but also damage the full
+ // frame, then the whole frame should be damaged.
+ child_damage_rect_ = gfx::RectF(10, 11, 12, 13);
+ host_impl->SetFullRootLayerDamage();
+ break;
+ case 4:
+ // The whole frame is damaged.
+ EXPECT_EQ(gfx::RectF(root_surface->content_rect()).ToString(),
+ root_damage.ToString());
+ EXPECT_FALSE(frame_data->has_no_damage);
+
+ EndTest();
+ break;
+ }
+ return result;
+ }
+
+ virtual void DidCommitAndDrawFrame() OVERRIDE {
+ if (!TestEnded())
+ layer_tree_host()->SetNeedsCommit();
+
+ if (!child_damage_rect_.IsEmpty()) {
+ child_->SetNeedsDisplayRect(child_damage_rect_);
+ child_damage_rect_ = gfx::RectF();
+ }
+ }
+
+ virtual void AfterTest() OVERRIDE {}
+
+ FakeContentLayerClient client_;
+ scoped_refptr<FakeContentLayer> root_;
+ scoped_refptr<FakeContentLayer> child_;
+ gfx::RectF child_damage_rect_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestForcedFullDamage);
+
+class LayerTreeHostDamageTestScrollbarDoesDamage
+ : public LayerTreeHostDamageTest {
+ virtual void BeginTest() OVERRIDE {
+ did_swaps_ = 0;
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void SetupTree() OVERRIDE {
+ scoped_refptr<Layer> root_layer = Layer::Create();
+ root_layer->SetBounds(gfx::Size(400,400));
+ layer_tree_host()->SetRootLayer(root_layer);
+
+ scoped_refptr<Layer> content_layer = FakeContentLayer::Create(&client_);
+ content_layer->SetScrollable(true);
+ content_layer->SetScrollOffset(gfx::Vector2d(10, 20));
+ content_layer->SetMaxScrollOffset(gfx::Vector2d(30, 50));
+ content_layer->SetBounds(gfx::Size(100, 200));
+ root_layer->AddChild(content_layer);
+
+ scoped_refptr<Layer> scrollbar_layer =
+ FakeScrollbarLayer::Create(false, true, content_layer->id());
+ scrollbar_layer->SetPosition(gfx::Point(300, 300));
+ scrollbar_layer->SetBounds(gfx::Size(10, 100));
+ root_layer->AddChild(scrollbar_layer);
+
+ gfx::RectF content_rect(content_layer->position(),
+ content_layer->bounds());
+ gfx::RectF scrollbar_rect(scrollbar_layer->position(),
+ scrollbar_layer->bounds());
+ EXPECT_FALSE(content_rect.Intersects(scrollbar_rect));
+
+ LayerTreeHostDamageTest::SetupTree();
+ }
+
+ virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ bool result) OVERRIDE {
+ EXPECT_TRUE(result);
+ RenderSurfaceImpl* root_surface =
+ host_impl->active_tree()->root_layer()->render_surface();
+ gfx::RectF root_damage =
+ root_surface->damage_tracker()->current_damage_rect();
+ root_damage.Intersect(root_surface->content_rect());
+ switch (did_swaps_) {
+ case 0:
+ // The first frame has damage, so we should draw and swap.
+ break;
+ case 1:
+ // The second frame should damage the scrollbars.
+ EXPECT_TRUE(root_damage.Contains(gfx::Rect(300, 300, 10, 100)));
+ break;
+ case 2:
+ // The third frame should damage the scrollbars.
+ EXPECT_TRUE(root_damage.Contains(gfx::Rect(300, 300, 10, 100)));
+ break;
+ case 3:
+ // The fourth frame should not damage the scrollbars.
+ EXPECT_FALSE(root_damage.Intersects(gfx::Rect(300, 300, 10, 100)));
+ EndTest();
+ break;
+ }
+ return result;
+ }
+
+ virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
+ bool result) OVERRIDE {
+ ++did_swaps_;
+ EXPECT_TRUE(result);
+ LayerImpl* root = host_impl->active_tree()->root_layer();
+ LayerImpl* scroll_layer = root->children()[0];
+ switch (did_swaps_) {
+ case 1:
+ host_impl->ScrollBegin(gfx::Point(1,1), InputHandler::Wheel);
+ EXPECT_TRUE(host_impl->ScrollBy(gfx::Point(),
+ gfx::Vector2dF(10.0, 10.0)));
+ break;
+ case 2:
+ scroll_layer->SetMaxScrollOffset(gfx::Vector2d(60, 100));
+ host_impl->SetNeedsRedraw();
+ break;
+ case 3:
+ // Test that modifying the position of the content layer (not
+ // scrolling) won't damage the scrollbar.
+ scroll_layer->SetPosition(gfx::Point(1,1));
+ scroll_layer->SetScrollOffset(scroll_layer->scroll_offset());
+ host_impl->SetNeedsRedraw();
+ break;
+ }
+
+ }
+
+ virtual void AfterTest() OVERRIDE {
+ EXPECT_EQ(4, did_swaps_);
+ }
+
+ FakeContentLayerClient client_;
+ int did_swaps_;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostDamageTestScrollbarDoesDamage);
+
+} // namespace
+} // namespace cc