layer_tree_host_impl_unittest.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
1// Copyright 2011 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "cc/trees/layer_tree_host_impl.h" 6 7#include <cmath> 8 9#include "base/bind.h" 10#include "base/command_line.h" 11#include "base/hash_tables.h" 12#include "cc/base/math_util.h" 13#include "cc/input/top_controls_manager.h" 14#include "cc/layers/delegated_renderer_layer_impl.h" 15#include "cc/layers/heads_up_display_layer_impl.h" 16#include "cc/layers/io_surface_layer_impl.h" 17#include "cc/layers/layer_impl.h" 18#include "cc/layers/quad_sink.h" 19#include "cc/layers/render_surface_impl.h" 20#include "cc/layers/scrollbar_geometry_fixed_thumb.h" 21#include "cc/layers/scrollbar_layer_impl.h" 22#include "cc/layers/solid_color_layer_impl.h" 23#include "cc/layers/texture_layer_impl.h" 24#include "cc/layers/tiled_layer_impl.h" 25#include "cc/layers/video_layer_impl.h" 26#include "cc/output/compositor_frame_ack.h" 27#include "cc/output/compositor_frame_metadata.h" 28#include "cc/output/gl_renderer.h" 29#include "cc/quads/render_pass_draw_quad.h" 30#include "cc/quads/solid_color_draw_quad.h" 31#include "cc/quads/texture_draw_quad.h" 32#include "cc/quads/tile_draw_quad.h" 33#include "cc/resources/layer_tiling_data.h" 34#include "cc/test/animation_test_common.h" 35#include "cc/test/fake_output_surface.h" 36#include "cc/test/fake_proxy.h" 37#include "cc/test/fake_rendering_stats_instrumentation.h" 38#include "cc/test/fake_video_frame_provider.h" 39#include "cc/test/fake_web_scrollbar_theme_geometry.h" 40#include "cc/test/geometry_test_utils.h" 41#include "cc/test/layer_test_common.h" 42#include "cc/test/render_pass_test_common.h" 43#include "cc/test/test_web_graphics_context_3d.h" 44#include "cc/trees/layer_tree_impl.h" 45#include "cc/trees/single_thread_proxy.h" 46#include "media/base/media.h" 47#include "testing/gmock/include/gmock/gmock.h" 48#include "testing/gtest/include/gtest/gtest.h" 49#include "ui/gfx/size_conversions.h" 50#include "ui/gfx/vector2d_conversions.h" 51 52using ::testing::Mock; 53using ::testing::Return; 54using ::testing::AnyNumber; 55using ::testing::AtLeast; 56using ::testing::_; 57using media::VideoFrame; 58 59namespace cc { 60namespace { 61 62class LayerTreeHostImplTest : public testing::Test, 63 public LayerTreeHostImplClient { 64 public: 65 LayerTreeHostImplTest() 66 : proxy_(scoped_ptr<Thread>(NULL)), 67 always_impl_thread_(&proxy_), 68 always_main_thread_blocked_(&proxy_), 69 on_can_draw_state_changed_called_(false), 70 has_pending_tree_(false), 71 did_request_commit_(false), 72 did_request_redraw_(false), 73 did_upload_visible_tile_(false), 74 reduce_memory_result_(true) { 75 media::InitializeMediaLibraryForTesting(); 76 } 77 78 virtual void OverrideSettings(LayerTreeSettings* settings) {} 79 80 virtual void SetUp() OVERRIDE { 81 LayerTreeSettings settings; 82 settings.minimum_occlusion_tracking_size = gfx::Size(); 83 OverrideSettings(&settings); 84 85 host_impl_ = LayerTreeHostImpl::Create(settings, 86 this, 87 &proxy_, 88 &stats_instrumentation_); 89 host_impl_->InitializeRenderer(CreateOutputSurface()); 90 host_impl_->SetViewportSize(gfx::Size(10, 10)); 91 } 92 93 virtual void TearDown() OVERRIDE {} 94 95 virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE {} 96 virtual void OnSwapBuffersCompleteOnImplThread() OVERRIDE {} 97 virtual void OnVSyncParametersChanged(base::TimeTicks timebase, 98 base::TimeDelta interval) OVERRIDE {} 99 virtual void DidVSync(base::TimeTicks frame_time) OVERRIDE {} 100 virtual void OnCanDrawStateChanged(bool can_draw) OVERRIDE { 101 on_can_draw_state_changed_called_ = true; 102 } 103 virtual void OnHasPendingTreeStateChanged(bool has_pending_tree) OVERRIDE { 104 has_pending_tree_ = has_pending_tree; 105 } 106 virtual void SetNeedsRedrawOnImplThread() OVERRIDE { 107 did_request_redraw_ = true; 108 } 109 virtual void SetNeedsRedrawRectOnImplThread(gfx::Rect damage_rect) OVERRIDE { 110 did_request_redraw_ = true; 111 } 112 virtual void DidInitializeVisibleTileOnImplThread() OVERRIDE { 113 did_upload_visible_tile_ = true; 114 } 115 virtual void SetNeedsCommitOnImplThread() OVERRIDE { 116 did_request_commit_ = true; 117 } 118 virtual void SetNeedsManageTilesOnImplThread() OVERRIDE {} 119 virtual void PostAnimationEventsToMainThreadOnImplThread( 120 scoped_ptr<AnimationEventsVector> events, 121 base::Time wall_clock_time) OVERRIDE {} 122 virtual bool ReduceContentsTextureMemoryOnImplThread( 123 size_t limit_bytes, int priority_cutoff) OVERRIDE { 124 return reduce_memory_result_; 125 } 126 virtual void ReduceWastedContentsTextureMemoryOnImplThread() OVERRIDE {} 127 virtual void SendManagedMemoryStats() OVERRIDE {} 128 virtual bool IsInsideDraw() OVERRIDE { return false; } 129 virtual void RenewTreePriority() OVERRIDE {} 130 virtual void RequestScrollbarAnimationOnImplThread(base::TimeDelta delay) 131 OVERRIDE {} 132 virtual void DidReceiveLastInputEventForVSync(base::TimeTicks frame_time) 133 OVERRIDE {} 134 135 void set_reduce_memory_result(bool reduce_memory_result) { 136 reduce_memory_result_ = reduce_memory_result; 137 } 138 139 void CreateLayerTreeHost(bool partial_swap, 140 scoped_ptr<OutputSurface> output_surface) { 141 LayerTreeSettings settings; 142 settings.minimum_occlusion_tracking_size = gfx::Size(); 143 settings.partial_swap_enabled = partial_swap; 144 145 host_impl_ = LayerTreeHostImpl::Create(settings, 146 this, 147 &proxy_, 148 &stats_instrumentation_); 149 150 host_impl_->InitializeRenderer(output_surface.Pass()); 151 host_impl_->SetViewportSize(gfx::Size(10, 10)); 152 } 153 154 void SetupRootLayerImpl(scoped_ptr<LayerImpl> root) { 155 root->SetAnchorPoint(gfx::PointF()); 156 root->SetPosition(gfx::PointF()); 157 root->SetBounds(gfx::Size(10, 10)); 158 root->SetContentBounds(gfx::Size(10, 10)); 159 root->SetDrawsContent(true); 160 root->draw_properties().visible_content_rect = gfx::Rect(0, 0, 10, 10); 161 host_impl_->active_tree()->SetRootLayer(root.Pass()); 162 } 163 164 static void ExpectClearedScrollDeltasRecursive(LayerImpl* layer) { 165 ASSERT_EQ(layer->ScrollDelta(), gfx::Vector2d()); 166 for (size_t i = 0; i < layer->children().size(); ++i) 167 ExpectClearedScrollDeltasRecursive(layer->children()[i]); 168 } 169 170 static void ExpectContains(const ScrollAndScaleSet& scroll_info, 171 int id, 172 gfx::Vector2d scroll_delta) { 173 int times_encountered = 0; 174 175 for (size_t i = 0; i < scroll_info.scrolls.size(); ++i) { 176 if (scroll_info.scrolls[i].layer_id != id) 177 continue; 178 EXPECT_VECTOR_EQ(scroll_delta, scroll_info.scrolls[i].scroll_delta); 179 times_encountered++; 180 } 181 182 ASSERT_EQ(times_encountered, 1); 183 } 184 185 static void ExpectNone(const ScrollAndScaleSet& scroll_info, int id) { 186 int times_encountered = 0; 187 188 for (size_t i = 0; i < scroll_info.scrolls.size(); ++i) { 189 if (scroll_info.scrolls[i].layer_id != id) 190 continue; 191 times_encountered++; 192 } 193 194 ASSERT_EQ(0, times_encountered); 195 } 196 197 void SetupScrollAndContentsLayers(gfx::Size content_size) { 198 scoped_ptr<LayerImpl> root = 199 LayerImpl::Create(host_impl_->active_tree(), 1); 200 root->SetScrollable(true); 201 root->SetScrollOffset(gfx::Vector2d()); 202 root->SetMaxScrollOffset(gfx::Vector2d(content_size.width(), 203 content_size.height())); 204 root->SetBounds(content_size); 205 root->SetContentBounds(content_size); 206 root->SetPosition(gfx::PointF()); 207 root->SetAnchorPoint(gfx::PointF()); 208 209 scoped_ptr<LayerImpl> contents = 210 LayerImpl::Create(host_impl_->active_tree(), 2); 211 contents->SetDrawsContent(true); 212 contents->SetBounds(content_size); 213 contents->SetContentBounds(content_size); 214 contents->SetPosition(gfx::PointF()); 215 contents->SetAnchorPoint(gfx::PointF()); 216 root->AddChild(contents.Pass()); 217 host_impl_->active_tree()->SetRootLayer(root.Pass()); 218 host_impl_->active_tree()->DidBecomeActive(); 219 } 220 221 scoped_ptr<LayerImpl> CreateScrollableLayer(int id, gfx::Size size) { 222 scoped_ptr<LayerImpl> layer = 223 LayerImpl::Create(host_impl_->active_tree(), id); 224 layer->SetScrollable(true); 225 layer->SetDrawsContent(true); 226 layer->SetBounds(size); 227 layer->SetContentBounds(size); 228 layer->SetMaxScrollOffset(gfx::Vector2d(size.width() * 2, 229 size.height() * 2)); 230 return layer.Pass(); 231 } 232 233 void InitializeRendererAndDrawFrame() { 234 host_impl_->InitializeRenderer(CreateOutputSurface()); 235 LayerTreeHostImpl::FrameData frame; 236 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 237 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 238 host_impl_->DidDrawAllLayers(frame); 239 } 240 241 void pinch_zoom_pan_viewport_forces_commit_redraw(float device_scale_factor); 242 void pinch_zoom_pan_viewport_test(float device_scale_factor); 243 void pinch_zoom_pan_viewport_and_scroll_test(float device_scale_factor); 244 void pinch_zoom_pan_viewport_and_scroll_boundary_test( 245 float device_scale_factor); 246 247 protected: 248 virtual scoped_ptr<OutputSurface> CreateOutputSurface() { 249 return CreateFakeOutputSurface(); 250 } 251 252 void DrawOneFrame() { 253 LayerTreeHostImpl::FrameData frame_data; 254 host_impl_->PrepareToDraw(&frame_data, gfx::Rect()); 255 host_impl_->DidDrawAllLayers(frame_data); 256 } 257 258 FakeProxy proxy_; 259 DebugScopedSetImplThread always_impl_thread_; 260 DebugScopedSetMainThreadBlocked always_main_thread_blocked_; 261 262 scoped_ptr<LayerTreeHostImpl> host_impl_; 263 FakeRenderingStatsInstrumentation stats_instrumentation_; 264 bool on_can_draw_state_changed_called_; 265 bool has_pending_tree_; 266 bool did_request_commit_; 267 bool did_request_redraw_; 268 bool did_upload_visible_tile_; 269 bool reduce_memory_result_; 270}; 271 272class TestWebGraphicsContext3DMakeCurrentFails 273 : public TestWebGraphicsContext3D { 274 public: 275 virtual bool makeContextCurrent() OVERRIDE { return false; } 276}; 277 278TEST_F(LayerTreeHostImplTest, NotifyIfCanDrawChanged) { 279 // Note: It is not possible to disable the renderer once it has been set, 280 // so we do not need to test that disabling the renderer notifies us 281 // that can_draw changed. 282 EXPECT_FALSE(host_impl_->CanDraw()); 283 on_can_draw_state_changed_called_ = false; 284 285 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 286 EXPECT_TRUE(host_impl_->CanDraw()); 287 EXPECT_TRUE(on_can_draw_state_changed_called_); 288 on_can_draw_state_changed_called_ = false; 289 290 // Toggle the root layer to make sure it toggles can_draw 291 host_impl_->active_tree()->SetRootLayer(scoped_ptr<LayerImpl>()); 292 EXPECT_FALSE(host_impl_->CanDraw()); 293 EXPECT_TRUE(on_can_draw_state_changed_called_); 294 on_can_draw_state_changed_called_ = false; 295 296 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 297 EXPECT_TRUE(host_impl_->CanDraw()); 298 EXPECT_TRUE(on_can_draw_state_changed_called_); 299 on_can_draw_state_changed_called_ = false; 300 301 // Toggle the device viewport size to make sure it toggles can_draw. 302 host_impl_->SetViewportSize(gfx::Size()); 303 EXPECT_FALSE(host_impl_->CanDraw()); 304 EXPECT_TRUE(on_can_draw_state_changed_called_); 305 on_can_draw_state_changed_called_ = false; 306 307 host_impl_->SetViewportSize(gfx::Size(100, 100)); 308 EXPECT_TRUE(host_impl_->CanDraw()); 309 EXPECT_TRUE(on_can_draw_state_changed_called_); 310 on_can_draw_state_changed_called_ = false; 311 312 // Toggle contents textures purged without causing any evictions, 313 // and make sure that it does not change can_draw. 314 set_reduce_memory_result(false); 315 host_impl_->SetManagedMemoryPolicy(ManagedMemoryPolicy( 316 host_impl_->memory_allocation_limit_bytes() - 1)); 317 EXPECT_TRUE(host_impl_->CanDraw()); 318 EXPECT_FALSE(on_can_draw_state_changed_called_); 319 on_can_draw_state_changed_called_ = false; 320 321 // Toggle contents textures purged to make sure it toggles can_draw. 322 set_reduce_memory_result(true); 323 host_impl_->SetManagedMemoryPolicy(ManagedMemoryPolicy( 324 host_impl_->memory_allocation_limit_bytes() - 1)); 325 EXPECT_FALSE(host_impl_->CanDraw()); 326 EXPECT_TRUE(on_can_draw_state_changed_called_); 327 on_can_draw_state_changed_called_ = false; 328 329 host_impl_->active_tree()->ResetContentsTexturesPurged(); 330 EXPECT_TRUE(host_impl_->CanDraw()); 331 EXPECT_TRUE(on_can_draw_state_changed_called_); 332 on_can_draw_state_changed_called_ = false; 333} 334 335TEST_F(LayerTreeHostImplTest, ScrollDeltaNoLayers) { 336 ASSERT_FALSE(host_impl_->active_tree()->root_layer()); 337 338 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); 339 ASSERT_EQ(scroll_info->scrolls.size(), 0u); 340} 341 342TEST_F(LayerTreeHostImplTest, ScrollDeltaTreeButNoChanges) { 343 { 344 scoped_ptr<LayerImpl> root = 345 LayerImpl::Create(host_impl_->active_tree(), 1); 346 root->AddChild(LayerImpl::Create(host_impl_->active_tree(), 2)); 347 root->AddChild(LayerImpl::Create(host_impl_->active_tree(), 3)); 348 root->children()[1]->AddChild( 349 LayerImpl::Create(host_impl_->active_tree(), 4)); 350 root->children()[1]->AddChild( 351 LayerImpl::Create(host_impl_->active_tree(), 5)); 352 root->children()[1]->children()[0]->AddChild( 353 LayerImpl::Create(host_impl_->active_tree(), 6)); 354 host_impl_->active_tree()->SetRootLayer(root.Pass()); 355 } 356 LayerImpl* root = host_impl_->active_tree()->root_layer(); 357 358 ExpectClearedScrollDeltasRecursive(root); 359 360 scoped_ptr<ScrollAndScaleSet> scroll_info; 361 362 scroll_info = host_impl_->ProcessScrollDeltas(); 363 ASSERT_EQ(scroll_info->scrolls.size(), 0u); 364 ExpectClearedScrollDeltasRecursive(root); 365 366 scroll_info = host_impl_->ProcessScrollDeltas(); 367 ASSERT_EQ(scroll_info->scrolls.size(), 0u); 368 ExpectClearedScrollDeltasRecursive(root); 369} 370 371TEST_F(LayerTreeHostImplTest, ScrollDeltaRepeatedScrolls) { 372 gfx::Vector2d scroll_offset(20, 30); 373 gfx::Vector2d scroll_delta(11, -15); 374 { 375 scoped_ptr<LayerImpl> root = 376 LayerImpl::Create(host_impl_->active_tree(), 1); 377 root->SetScrollOffset(scroll_offset); 378 root->SetScrollable(true); 379 root->SetMaxScrollOffset(gfx::Vector2d(100, 100)); 380 root->ScrollBy(scroll_delta); 381 host_impl_->active_tree()->SetRootLayer(root.Pass()); 382 } 383 LayerImpl* root = host_impl_->active_tree()->root_layer(); 384 385 scoped_ptr<ScrollAndScaleSet> scroll_info; 386 387 scroll_info = host_impl_->ProcessScrollDeltas(); 388 ASSERT_EQ(scroll_info->scrolls.size(), 1u); 389 EXPECT_VECTOR_EQ(root->sent_scroll_delta(), scroll_delta); 390 ExpectContains(*scroll_info, root->id(), scroll_delta); 391 392 gfx::Vector2d scroll_delta2(-5, 27); 393 root->ScrollBy(scroll_delta2); 394 scroll_info = host_impl_->ProcessScrollDeltas(); 395 ASSERT_EQ(scroll_info->scrolls.size(), 1u); 396 EXPECT_VECTOR_EQ(root->sent_scroll_delta(), scroll_delta + scroll_delta2); 397 ExpectContains(*scroll_info, root->id(), scroll_delta + scroll_delta2); 398 399 root->ScrollBy(gfx::Vector2d()); 400 scroll_info = host_impl_->ProcessScrollDeltas(); 401 EXPECT_EQ(root->sent_scroll_delta(), scroll_delta + scroll_delta2); 402} 403 404TEST_F(LayerTreeHostImplTest, ScrollRootCallsCommitAndRedraw) { 405 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 406 host_impl_->SetViewportSize(gfx::Size(50, 50)); 407 InitializeRendererAndDrawFrame(); 408 409 EXPECT_EQ(InputHandler::ScrollStarted, 410 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel)); 411 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)); 412 host_impl_->ScrollEnd(); 413 EXPECT_TRUE(did_request_redraw_); 414 EXPECT_TRUE(did_request_commit_); 415} 416 417TEST_F(LayerTreeHostImplTest, ScrollWithoutRootLayer) { 418 // We should not crash when trying to scroll an empty layer tree. 419 EXPECT_EQ(InputHandler::ScrollIgnored, 420 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel)); 421} 422 423TEST_F(LayerTreeHostImplTest, ScrollWithoutRenderer) { 424 LayerTreeSettings settings; 425 host_impl_ = LayerTreeHostImpl::Create(settings, 426 this, 427 &proxy_, 428 &stats_instrumentation_); 429 430 // Initialization will fail here. 431 host_impl_->InitializeRenderer(FakeOutputSurface::Create3d( 432 scoped_ptr<WebKit::WebGraphicsContext3D>( 433 new TestWebGraphicsContext3DMakeCurrentFails)) 434 .PassAs<OutputSurface>()); 435 host_impl_->SetViewportSize(gfx::Size(10, 10)); 436 437 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 438 439 // We should not crash when trying to scroll after the renderer initialization 440 // fails. 441 EXPECT_EQ(InputHandler::ScrollIgnored, 442 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel)); 443} 444 445TEST_F(LayerTreeHostImplTest, ReplaceTreeWhileScrolling) { 446 int scroll_layer_id = 1; 447 448 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 449 host_impl_->SetViewportSize(gfx::Size(50, 50)); 450 InitializeRendererAndDrawFrame(); 451 452 // We should not crash if the tree is replaced while we are scrolling. 453 EXPECT_EQ(InputHandler::ScrollStarted, 454 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel)); 455 host_impl_->active_tree()->DetachLayerTree(); 456 457 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 458 459 // We should still be scrolling, because the scrolled layer also exists in the 460 // new tree. 461 gfx::Vector2d scroll_delta(0, 10); 462 host_impl_->ScrollBy(gfx::Point(), scroll_delta); 463 host_impl_->ScrollEnd(); 464 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); 465 ExpectContains(*scroll_info, scroll_layer_id, scroll_delta); 466} 467 468TEST_F(LayerTreeHostImplTest, ClearRootRenderSurfaceAndScroll) { 469 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 470 host_impl_->SetViewportSize(gfx::Size(50, 50)); 471 InitializeRendererAndDrawFrame(); 472 473 // We should be able to scroll even if the root layer loses its render surface 474 // after the most recent render. 475 host_impl_->active_tree()->root_layer()->ClearRenderSurface(); 476 host_impl_->active_tree()->set_needs_update_draw_properties(); 477 478 EXPECT_EQ(InputHandler::ScrollStarted, 479 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel)); 480} 481 482TEST_F(LayerTreeHostImplTest, WheelEventHandlers) { 483 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 484 host_impl_->SetViewportSize(gfx::Size(50, 50)); 485 InitializeRendererAndDrawFrame(); 486 LayerImpl* root = host_impl_->active_tree()->root_layer(); 487 488 root->SetHaveWheelEventHandlers(true); 489 490 // With registered event handlers, wheel scrolls have to go to the main 491 // thread. 492 EXPECT_EQ(InputHandler::ScrollOnMainThread, 493 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel)); 494 495 // But gesture scrolls can still be handled. 496 EXPECT_EQ(InputHandler::ScrollStarted, 497 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); 498} 499 500TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchscreen) { 501 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 502 host_impl_->SetViewportSize(gfx::Size(50, 50)); 503 InitializeRendererAndDrawFrame(); 504 505 // Ignore the fling since no layer is being scrolled 506 EXPECT_EQ(InputHandler::ScrollIgnored, 507 host_impl_->FlingScrollBegin()); 508 509 // Start scrolling a layer 510 EXPECT_EQ(InputHandler::ScrollStarted, 511 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); 512 513 // Now the fling should go ahead since we've started scrolling a layer 514 EXPECT_EQ(InputHandler::ScrollStarted, 515 host_impl_->FlingScrollBegin()); 516} 517 518TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchpad) { 519 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 520 host_impl_->SetViewportSize(gfx::Size(50, 50)); 521 InitializeRendererAndDrawFrame(); 522 523 // Ignore the fling since no layer is being scrolled 524 EXPECT_EQ(InputHandler::ScrollIgnored, 525 host_impl_->FlingScrollBegin()); 526 527 // Start scrolling a layer 528 EXPECT_EQ(InputHandler::ScrollStarted, 529 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel)); 530 531 // Now the fling should go ahead since we've started scrolling a layer 532 EXPECT_EQ(InputHandler::ScrollStarted, 533 host_impl_->FlingScrollBegin()); 534} 535 536TEST_F(LayerTreeHostImplTest, NoFlingWhenScrollingOnMain) { 537 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 538 host_impl_->SetViewportSize(gfx::Size(50, 50)); 539 InitializeRendererAndDrawFrame(); 540 LayerImpl* root = host_impl_->active_tree()->root_layer(); 541 542 root->SetShouldScrollOnMainThread(true); 543 544 // Start scrolling a layer 545 EXPECT_EQ(InputHandler::ScrollOnMainThread, 546 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); 547 548 // The fling should be ignored since there's no layer being scrolled impl-side 549 EXPECT_EQ(InputHandler::ScrollIgnored, 550 host_impl_->FlingScrollBegin()); 551} 552 553TEST_F(LayerTreeHostImplTest, ShouldScrollOnMainThread) { 554 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 555 host_impl_->SetViewportSize(gfx::Size(50, 50)); 556 InitializeRendererAndDrawFrame(); 557 LayerImpl* root = host_impl_->active_tree()->root_layer(); 558 559 root->SetShouldScrollOnMainThread(true); 560 561 EXPECT_EQ(InputHandler::ScrollOnMainThread, 562 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel)); 563 EXPECT_EQ(InputHandler::ScrollOnMainThread, 564 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); 565} 566 567TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionBasic) { 568 SetupScrollAndContentsLayers(gfx::Size(200, 200)); 569 host_impl_->SetViewportSize(gfx::Size(100, 100)); 570 571 LayerImpl* root = host_impl_->active_tree()->root_layer(); 572 root->SetContentsScale(2.f, 2.f); 573 root->SetNonFastScrollableRegion(gfx::Rect(0, 0, 50, 50)); 574 575 InitializeRendererAndDrawFrame(); 576 577 // All scroll types inside the non-fast scrollable region should fail. 578 EXPECT_EQ(InputHandler::ScrollOnMainThread, 579 host_impl_->ScrollBegin(gfx::Point(25, 25), 580 InputHandler::Wheel)); 581 EXPECT_EQ(InputHandler::ScrollOnMainThread, 582 host_impl_->ScrollBegin(gfx::Point(25, 25), 583 InputHandler::Gesture)); 584 585 // All scroll types outside this region should succeed. 586 EXPECT_EQ(InputHandler::ScrollStarted, 587 host_impl_->ScrollBegin(gfx::Point(75, 75), 588 InputHandler::Wheel)); 589 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)); 590 host_impl_->ScrollEnd(); 591 EXPECT_EQ(InputHandler::ScrollStarted, 592 host_impl_->ScrollBegin(gfx::Point(75, 75), 593 InputHandler::Gesture)); 594 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)); 595 host_impl_->ScrollEnd(); 596} 597 598TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionWithOffset) { 599 SetupScrollAndContentsLayers(gfx::Size(200, 200)); 600 host_impl_->SetViewportSize(gfx::Size(100, 100)); 601 602 LayerImpl* root = host_impl_->active_tree()->root_layer(); 603 root->SetContentsScale(2.f, 2.f); 604 root->SetNonFastScrollableRegion(gfx::Rect(0, 0, 50, 50)); 605 root->SetPosition(gfx::PointF(-25.f, 0.f)); 606 607 InitializeRendererAndDrawFrame(); 608 609 // This point would fall into the non-fast scrollable region except that we've 610 // moved the layer down by 25 pixels. 611 EXPECT_EQ(InputHandler::ScrollStarted, 612 host_impl_->ScrollBegin(gfx::Point(40, 10), 613 InputHandler::Wheel)); 614 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 1)); 615 host_impl_->ScrollEnd(); 616 617 // This point is still inside the non-fast region. 618 EXPECT_EQ(InputHandler::ScrollOnMainThread, 619 host_impl_->ScrollBegin(gfx::Point(10, 10), 620 InputHandler::Wheel)); 621} 622 623TEST_F(LayerTreeHostImplTest, ScrollByReturnsCorrectValue) { 624 SetupScrollAndContentsLayers(gfx::Size(200, 200)); 625 host_impl_->SetViewportSize(gfx::Size(100, 100)); 626 627 InitializeRendererAndDrawFrame(); 628 629 EXPECT_EQ(InputHandler::ScrollStarted, 630 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); 631 632 // Trying to scroll to the left/top will not succeed. 633 EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0))); 634 EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10))); 635 EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, -10))); 636 637 // Scrolling to the right/bottom will succeed. 638 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 0))); 639 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10))); 640 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 10))); 641 642 // Scrolling to left/top will now succeed. 643 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0))); 644 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10))); 645 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, -10))); 646 647 // Scrolling diagonally against an edge will succeed. 648 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, -10))); 649 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0))); 650 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 10))); 651 652 // Trying to scroll more than the available space will also succeed. 653 EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(5000, 5000))); 654} 655 656TEST_F(LayerTreeHostImplTest, ScrollVerticallyByPageReturnsCorrectValue) { 657 SetupScrollAndContentsLayers(gfx::Size(200, 2000)); 658 host_impl_->SetViewportSize(gfx::Size(100, 1000)); 659 660 InitializeRendererAndDrawFrame(); 661 662 EXPECT_EQ(InputHandler::ScrollStarted, 663 host_impl_->ScrollBegin(gfx::Point(), 664 InputHandler::Wheel)); 665 666 // Trying to scroll without a vertical scrollbar will fail. 667 EXPECT_FALSE(host_impl_->ScrollVerticallyByPage( 668 gfx::Point(), WebKit::WebScrollbar::ScrollForward)); 669 EXPECT_FALSE(host_impl_->ScrollVerticallyByPage( 670 gfx::Point(), WebKit::WebScrollbar::ScrollBackward)); 671 672 scoped_ptr<cc::ScrollbarLayerImpl> vertical_scrollbar( 673 cc::ScrollbarLayerImpl::Create( 674 host_impl_->active_tree(), 675 20, 676 scoped_ptr<ScrollbarGeometryFixedThumb>())); 677 vertical_scrollbar->SetBounds(gfx::Size(15, 1000)); 678 host_impl_->RootScrollLayer()->SetVerticalScrollbarLayer( 679 vertical_scrollbar.get()); 680 681 // Trying to scroll with a vertical scrollbar will succeed. 682 EXPECT_TRUE(host_impl_->ScrollVerticallyByPage( 683 gfx::Point(), WebKit::WebScrollbar::ScrollForward)); 684 EXPECT_FLOAT_EQ(875.f, host_impl_->RootScrollLayer()->ScrollDelta().y()); 685 EXPECT_TRUE(host_impl_->ScrollVerticallyByPage( 686 gfx::Point(), WebKit::WebScrollbar::ScrollBackward)); 687} 688 689TEST_F(LayerTreeHostImplTest, 690 ClearRootRenderSurfaceAndHitTestTouchHandlerRegion) { 691 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 692 host_impl_->SetViewportSize(gfx::Size(50, 50)); 693 InitializeRendererAndDrawFrame(); 694 695 // We should be able to hit test for touch event handlers even if the root 696 // layer loses its render surface after the most recent render. 697 host_impl_->active_tree()->root_layer()->ClearRenderSurface(); 698 host_impl_->active_tree()->set_needs_update_draw_properties(); 699 700 EXPECT_EQ(host_impl_->HaveTouchEventHandlersAt(gfx::Point()), false); 701} 702 703TEST_F(LayerTreeHostImplTest, ImplPinchZoom) { 704 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 705 host_impl_->SetViewportSize(gfx::Size(50, 50)); 706 InitializeRendererAndDrawFrame(); 707 708 LayerImpl* scroll_layer = host_impl_->RootScrollLayer(); 709 DCHECK(scroll_layer); 710 711 float min_page_scale = 1.f, max_page_scale = 4.f; 712 713 // The impl-based pinch zoom should adjust the max scroll position. 714 { 715 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 716 min_page_scale, 717 max_page_scale); 718 host_impl_->active_tree()->SetPageScaleDelta(1.f); 719 scroll_layer->SetScrollDelta(gfx::Vector2d()); 720 721 float page_scale_delta = 2.f; 722 host_impl_->PinchGestureBegin(); 723 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50)); 724 host_impl_->PinchGestureEnd(); 725 EXPECT_TRUE(did_request_redraw_); 726 EXPECT_TRUE(did_request_commit_); 727 728 scoped_ptr<ScrollAndScaleSet> scroll_info = 729 host_impl_->ProcessScrollDeltas(); 730 EXPECT_EQ(scroll_info->page_scale_delta, page_scale_delta); 731 732 EXPECT_EQ(gfx::Vector2d(75, 75), 733 host_impl_->active_tree()->root_layer()->max_scroll_offset()); 734 } 735 736 // Scrolling after a pinch gesture should always be in local space. The 737 // scroll deltas do not have the page scale factor applied. 738 { 739 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 740 min_page_scale, 741 max_page_scale); 742 host_impl_->active_tree()->SetPageScaleDelta(1.f); 743 scroll_layer->SetScrollDelta(gfx::Vector2d()); 744 745 float page_scale_delta = 2.f; 746 host_impl_->PinchGestureBegin(); 747 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point()); 748 host_impl_->PinchGestureEnd(); 749 750 gfx::Vector2d scroll_delta(0, 10); 751 EXPECT_EQ(InputHandler::ScrollStarted, 752 host_impl_->ScrollBegin(gfx::Point(5, 5), 753 InputHandler::Wheel)); 754 host_impl_->ScrollBy(gfx::Point(), scroll_delta); 755 host_impl_->ScrollEnd(); 756 757 scoped_ptr<ScrollAndScaleSet> scroll_info = 758 host_impl_->ProcessScrollDeltas(); 759 ExpectContains(*scroll_info.get(), 760 host_impl_->active_tree()->root_layer()->id(), 761 scroll_delta); 762 } 763} 764 765TEST_F(LayerTreeHostImplTest, PinchGesture) { 766 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 767 host_impl_->SetViewportSize(gfx::Size(50, 50)); 768 InitializeRendererAndDrawFrame(); 769 770 LayerImpl* scroll_layer = host_impl_->RootScrollLayer(); 771 DCHECK(scroll_layer); 772 773 float min_page_scale = 1.f; 774 float max_page_scale = 4.f; 775 776 // Basic pinch zoom in gesture 777 { 778 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 779 min_page_scale, 780 max_page_scale); 781 scroll_layer->SetScrollDelta(gfx::Vector2d()); 782 783 float page_scale_delta = 2.f; 784 host_impl_->PinchGestureBegin(); 785 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50)); 786 host_impl_->PinchGestureEnd(); 787 EXPECT_TRUE(did_request_redraw_); 788 EXPECT_TRUE(did_request_commit_); 789 790 scoped_ptr<ScrollAndScaleSet> scroll_info = 791 host_impl_->ProcessScrollDeltas(); 792 EXPECT_EQ(scroll_info->page_scale_delta, page_scale_delta); 793 } 794 795 // Zoom-in clamping 796 { 797 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 798 min_page_scale, 799 max_page_scale); 800 scroll_layer->SetScrollDelta(gfx::Vector2d()); 801 float page_scale_delta = 10.f; 802 803 host_impl_->PinchGestureBegin(); 804 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50)); 805 host_impl_->PinchGestureEnd(); 806 807 scoped_ptr<ScrollAndScaleSet> scroll_info = 808 host_impl_->ProcessScrollDeltas(); 809 EXPECT_EQ(scroll_info->page_scale_delta, max_page_scale); 810 } 811 812 // Zoom-out clamping 813 { 814 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 815 min_page_scale, 816 max_page_scale); 817 scroll_layer->SetScrollDelta(gfx::Vector2d()); 818 scroll_layer->SetScrollOffset(gfx::Vector2d(50, 50)); 819 820 float page_scale_delta = 0.1f; 821 host_impl_->PinchGestureBegin(); 822 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point()); 823 host_impl_->PinchGestureEnd(); 824 825 scoped_ptr<ScrollAndScaleSet> scroll_info = 826 host_impl_->ProcessScrollDeltas(); 827 EXPECT_EQ(scroll_info->page_scale_delta, min_page_scale); 828 829 EXPECT_TRUE(scroll_info->scrolls.empty()); 830 } 831 832 // Two-finger panning should not happen based on pinch events only 833 { 834 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 835 min_page_scale, 836 max_page_scale); 837 scroll_layer->SetScrollDelta(gfx::Vector2d()); 838 scroll_layer->SetScrollOffset(gfx::Vector2d(20, 20)); 839 840 float page_scale_delta = 1.f; 841 host_impl_->PinchGestureBegin(); 842 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(10, 10)); 843 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(20, 20)); 844 host_impl_->PinchGestureEnd(); 845 846 scoped_ptr<ScrollAndScaleSet> scroll_info = 847 host_impl_->ProcessScrollDeltas(); 848 EXPECT_EQ(scroll_info->page_scale_delta, page_scale_delta); 849 EXPECT_TRUE(scroll_info->scrolls.empty()); 850 } 851 852 // Two-finger panning should work with interleaved scroll events 853 { 854 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 855 min_page_scale, 856 max_page_scale); 857 scroll_layer->SetScrollDelta(gfx::Vector2d()); 858 scroll_layer->SetScrollOffset(gfx::Vector2d(20, 20)); 859 860 float page_scale_delta = 1.f; 861 host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandler::Wheel); 862 host_impl_->PinchGestureBegin(); 863 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(10, 10)); 864 host_impl_->ScrollBy(gfx::Point(10, 10), gfx::Vector2d(-10, -10)); 865 host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(20, 20)); 866 host_impl_->PinchGestureEnd(); 867 host_impl_->ScrollEnd(); 868 869 scoped_ptr<ScrollAndScaleSet> scroll_info = 870 host_impl_->ProcessScrollDeltas(); 871 EXPECT_EQ(scroll_info->page_scale_delta, page_scale_delta); 872 ExpectContains(*scroll_info, scroll_layer->id(), gfx::Vector2d(-10, -10)); 873 } 874} 875 876TEST_F(LayerTreeHostImplTest, PageScaleAnimation) { 877 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 878 host_impl_->SetViewportSize(gfx::Size(50, 50)); 879 InitializeRendererAndDrawFrame(); 880 881 LayerImpl* scroll_layer = host_impl_->RootScrollLayer(); 882 DCHECK(scroll_layer); 883 884 float min_page_scale = 0.5f; 885 float max_page_scale = 4.f; 886 base::TimeTicks start_time = base::TimeTicks() + 887 base::TimeDelta::FromSeconds(1); 888 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(100); 889 base::TimeTicks halfway_through_animation = start_time + duration / 2; 890 base::TimeTicks end_time = start_time + duration; 891 892 // Non-anchor zoom-in 893 { 894 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 895 min_page_scale, 896 max_page_scale); 897 scroll_layer->SetScrollOffset(gfx::Vector2d(50, 50)); 898 899 host_impl_->StartPageScaleAnimation(gfx::Vector2d(), 900 false, 901 2.f, 902 start_time, 903 duration); 904 host_impl_->Animate(halfway_through_animation, base::Time()); 905 EXPECT_TRUE(did_request_redraw_); 906 host_impl_->Animate(end_time, base::Time()); 907 EXPECT_TRUE(did_request_commit_); 908 909 scoped_ptr<ScrollAndScaleSet> scroll_info = 910 host_impl_->ProcessScrollDeltas(); 911 EXPECT_EQ(scroll_info->page_scale_delta, 2); 912 ExpectContains(*scroll_info, scroll_layer->id(), gfx::Vector2d(-50, -50)); 913 } 914 915 // Anchor zoom-out 916 { 917 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 918 min_page_scale, 919 max_page_scale); 920 scroll_layer->SetScrollOffset(gfx::Vector2d(50, 50)); 921 922 host_impl_->StartPageScaleAnimation(gfx::Vector2d(25, 25), 923 true, 924 min_page_scale, 925 start_time, duration); 926 host_impl_->Animate(end_time, base::Time()); 927 EXPECT_TRUE(did_request_redraw_); 928 EXPECT_TRUE(did_request_commit_); 929 930 scoped_ptr<ScrollAndScaleSet> scroll_info = 931 host_impl_->ProcessScrollDeltas(); 932 EXPECT_EQ(scroll_info->page_scale_delta, min_page_scale); 933 // Pushed to (0,0) via clamping against contents layer size. 934 ExpectContains(*scroll_info, scroll_layer->id(), gfx::Vector2d(-50, -50)); 935 } 936} 937 938TEST_F(LayerTreeHostImplTest, PageScaleAnimationNoOp) { 939 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 940 host_impl_->SetViewportSize(gfx::Size(50, 50)); 941 InitializeRendererAndDrawFrame(); 942 943 LayerImpl* scroll_layer = host_impl_->RootScrollLayer(); 944 DCHECK(scroll_layer); 945 946 float min_page_scale = 0.5f; 947 float max_page_scale = 4.f; 948 base::TimeTicks start_time = base::TimeTicks() + 949 base::TimeDelta::FromSeconds(1); 950 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(100); 951 base::TimeTicks halfway_through_animation = start_time + duration / 2; 952 base::TimeTicks end_time = start_time + duration; 953 954 // Anchor zoom with unchanged page scale should not change scroll or scale. 955 { 956 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 957 min_page_scale, 958 max_page_scale); 959 scroll_layer->SetScrollOffset(gfx::Vector2d(50, 50)); 960 961 host_impl_->StartPageScaleAnimation(gfx::Vector2d(), 962 true, 963 1.f, 964 start_time, 965 duration); 966 host_impl_->Animate(halfway_through_animation, base::Time()); 967 EXPECT_TRUE(did_request_redraw_); 968 host_impl_->Animate(end_time, base::Time()); 969 EXPECT_TRUE(did_request_commit_); 970 971 scoped_ptr<ScrollAndScaleSet> scroll_info = 972 host_impl_->ProcessScrollDeltas(); 973 EXPECT_EQ(scroll_info->page_scale_delta, 1); 974 ExpectNone(*scroll_info, scroll_layer->id()); 975 } 976} 977 978TEST_F(LayerTreeHostImplTest, CompositorFrameMetadata) { 979 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 980 host_impl_->SetViewportSize(gfx::Size(50, 50)); 981 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f); 982 InitializeRendererAndDrawFrame(); 983 { 984 CompositorFrameMetadata metadata = 985 host_impl_->MakeCompositorFrameMetadata(); 986 EXPECT_EQ(gfx::Vector2dF(), metadata.root_scroll_offset); 987 EXPECT_EQ(1.f, metadata.page_scale_factor); 988 EXPECT_EQ(gfx::SizeF(50.f, 50.f), metadata.viewport_size); 989 EXPECT_EQ(gfx::SizeF(100.f, 100.f), metadata.root_layer_size); 990 EXPECT_EQ(0.5f, metadata.min_page_scale_factor); 991 EXPECT_EQ(4.f, metadata.max_page_scale_factor); 992 } 993 994 // Scrolling should update metadata immediately. 995 EXPECT_EQ(InputHandler::ScrollStarted, 996 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel)); 997 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)); 998 { 999 CompositorFrameMetadata metadata = 1000 host_impl_->MakeCompositorFrameMetadata(); 1001 EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset); 1002 } 1003 host_impl_->ScrollEnd(); 1004 { 1005 CompositorFrameMetadata metadata = 1006 host_impl_->MakeCompositorFrameMetadata(); 1007 EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset); 1008 } 1009 1010 // Page scale should update metadata correctly (shrinking only the viewport). 1011 host_impl_->PinchGestureBegin(); 1012 host_impl_->PinchGestureUpdate(2.f, gfx::Point()); 1013 host_impl_->PinchGestureEnd(); 1014 { 1015 CompositorFrameMetadata metadata = 1016 host_impl_->MakeCompositorFrameMetadata(); 1017 EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset); 1018 EXPECT_EQ(2.f, metadata.page_scale_factor); 1019 EXPECT_EQ(gfx::SizeF(25.f, 25.f), metadata.viewport_size); 1020 EXPECT_EQ(gfx::SizeF(100.f, 100.f), metadata.root_layer_size); 1021 EXPECT_EQ(0.5f, metadata.min_page_scale_factor); 1022 EXPECT_EQ(4.f, metadata.max_page_scale_factor); 1023 } 1024 1025 // Likewise if set from the main thread. 1026 host_impl_->ProcessScrollDeltas(); 1027 host_impl_->active_tree()->SetPageScaleFactorAndLimits(4.f, 0.5f, 4.f); 1028 host_impl_->active_tree()->SetPageScaleDelta(1.f); 1029 { 1030 CompositorFrameMetadata metadata = 1031 host_impl_->MakeCompositorFrameMetadata(); 1032 EXPECT_EQ(gfx::Vector2dF(0.f, 10.f), metadata.root_scroll_offset); 1033 EXPECT_EQ(4.f, metadata.page_scale_factor); 1034 EXPECT_EQ(gfx::SizeF(12.5f, 12.5f), metadata.viewport_size); 1035 EXPECT_EQ(gfx::SizeF(100.f, 100.f), metadata.root_layer_size); 1036 EXPECT_EQ(0.5f, metadata.min_page_scale_factor); 1037 EXPECT_EQ(4.f, metadata.max_page_scale_factor); 1038 } 1039} 1040 1041class DidDrawCheckLayer : public TiledLayerImpl { 1042 public: 1043 static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, int id) { 1044 return scoped_ptr<LayerImpl>(new DidDrawCheckLayer(tree_impl, id)); 1045 } 1046 1047 virtual void DidDraw(ResourceProvider* provider) OVERRIDE { 1048 did_draw_called_ = true; 1049 } 1050 1051 virtual void WillDraw(ResourceProvider* provider) OVERRIDE { 1052 will_draw_called_ = true; 1053 } 1054 1055 bool did_draw_called() const { return did_draw_called_; } 1056 bool will_draw_called() const { return will_draw_called_; } 1057 1058 void ClearDidDrawCheck() { 1059 did_draw_called_ = false; 1060 will_draw_called_ = false; 1061 } 1062 1063 protected: 1064 DidDrawCheckLayer(LayerTreeImpl* tree_impl, int id) 1065 : TiledLayerImpl(tree_impl, id), 1066 did_draw_called_(false), 1067 will_draw_called_(false) { 1068 SetAnchorPoint(gfx::PointF()); 1069 SetBounds(gfx::Size(10, 10)); 1070 SetContentBounds(gfx::Size(10, 10)); 1071 SetDrawsContent(true); 1072 set_skips_draw(false); 1073 draw_properties().visible_content_rect = gfx::Rect(0, 0, 10, 10); 1074 1075 scoped_ptr<LayerTilingData> tiler = 1076 LayerTilingData::Create(gfx::Size(100, 100), 1077 LayerTilingData::HAS_BORDER_TEXELS); 1078 tiler->SetBounds(content_bounds()); 1079 SetTilingData(*tiler.get()); 1080 } 1081 1082 private: 1083 bool did_draw_called_; 1084 bool will_draw_called_; 1085}; 1086 1087TEST_F(LayerTreeHostImplTest, DidDrawNotCalledOnHiddenLayer) { 1088 // The root layer is always drawn, so run this test on a child layer that 1089 // will be masked out by the root layer's bounds. 1090 host_impl_->active_tree()->SetRootLayer( 1091 DidDrawCheckLayer::Create(host_impl_->active_tree(), 1)); 1092 DidDrawCheckLayer* root = static_cast<DidDrawCheckLayer*>( 1093 host_impl_->active_tree()->root_layer()); 1094 root->SetMasksToBounds(true); 1095 1096 root->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 2)); 1097 DidDrawCheckLayer* layer = 1098 static_cast<DidDrawCheckLayer*>(root->children()[0]); 1099 // Ensure visible_content_rect for layer is empty. 1100 layer->SetPosition(gfx::PointF(100.f, 100.f)); 1101 layer->SetBounds(gfx::Size(10, 10)); 1102 layer->SetContentBounds(gfx::Size(10, 10)); 1103 1104 LayerTreeHostImpl::FrameData frame; 1105 1106 EXPECT_FALSE(layer->will_draw_called()); 1107 EXPECT_FALSE(layer->did_draw_called()); 1108 1109 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 1110 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 1111 host_impl_->DidDrawAllLayers(frame); 1112 1113 EXPECT_FALSE(layer->will_draw_called()); 1114 EXPECT_FALSE(layer->did_draw_called()); 1115 1116 EXPECT_TRUE(layer->visible_content_rect().IsEmpty()); 1117 1118 // Ensure visible_content_rect for layer is not empty 1119 layer->SetPosition(gfx::PointF()); 1120 1121 EXPECT_FALSE(layer->will_draw_called()); 1122 EXPECT_FALSE(layer->did_draw_called()); 1123 1124 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 1125 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 1126 host_impl_->DidDrawAllLayers(frame); 1127 1128 EXPECT_TRUE(layer->will_draw_called()); 1129 EXPECT_TRUE(layer->did_draw_called()); 1130 1131 EXPECT_FALSE(layer->visible_content_rect().IsEmpty()); 1132} 1133 1134TEST_F(LayerTreeHostImplTest, WillDrawNotCalledOnOccludedLayer) { 1135 gfx::Size big_size(1000, 1000); 1136 host_impl_->SetViewportSize(big_size); 1137 1138 host_impl_->active_tree()->SetRootLayer( 1139 DidDrawCheckLayer::Create(host_impl_->active_tree(), 1)); 1140 DidDrawCheckLayer* root = 1141 static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer()); 1142 1143 root->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 2)); 1144 DidDrawCheckLayer* occluded_layer = 1145 static_cast<DidDrawCheckLayer*>(root->children()[0]); 1146 1147 root->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 3)); 1148 DidDrawCheckLayer* top_layer = 1149 static_cast<DidDrawCheckLayer*>(root->children()[1]); 1150 // This layer covers the occluded_layer above. Make this layer large so it can 1151 // occlude. 1152 top_layer->SetBounds(big_size); 1153 top_layer->SetContentBounds(big_size); 1154 top_layer->SetContentsOpaque(true); 1155 1156 LayerTreeHostImpl::FrameData frame; 1157 1158 EXPECT_FALSE(occluded_layer->will_draw_called()); 1159 EXPECT_FALSE(occluded_layer->did_draw_called()); 1160 EXPECT_FALSE(top_layer->will_draw_called()); 1161 EXPECT_FALSE(top_layer->did_draw_called()); 1162 1163 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 1164 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 1165 host_impl_->DidDrawAllLayers(frame); 1166 1167 EXPECT_FALSE(occluded_layer->will_draw_called()); 1168 EXPECT_FALSE(occluded_layer->did_draw_called()); 1169 EXPECT_TRUE(top_layer->will_draw_called()); 1170 EXPECT_TRUE(top_layer->did_draw_called()); 1171} 1172 1173TEST_F(LayerTreeHostImplTest, DidDrawCalledOnAllLayers) { 1174 host_impl_->active_tree()->SetRootLayer( 1175 DidDrawCheckLayer::Create(host_impl_->active_tree(), 1)); 1176 DidDrawCheckLayer* root = 1177 static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer()); 1178 1179 root->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 2)); 1180 DidDrawCheckLayer* layer1 = 1181 static_cast<DidDrawCheckLayer*>(root->children()[0]); 1182 1183 layer1->AddChild(DidDrawCheckLayer::Create(host_impl_->active_tree(), 3)); 1184 DidDrawCheckLayer* layer2 = 1185 static_cast<DidDrawCheckLayer*>(layer1->children()[0]); 1186 1187 layer1->SetOpacity(0.3f); 1188 layer1->SetPreserves3d(false); 1189 1190 EXPECT_FALSE(root->did_draw_called()); 1191 EXPECT_FALSE(layer1->did_draw_called()); 1192 EXPECT_FALSE(layer2->did_draw_called()); 1193 1194 LayerTreeHostImpl::FrameData frame; 1195 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 1196 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 1197 host_impl_->DidDrawAllLayers(frame); 1198 1199 EXPECT_TRUE(root->did_draw_called()); 1200 EXPECT_TRUE(layer1->did_draw_called()); 1201 EXPECT_TRUE(layer2->did_draw_called()); 1202 1203 EXPECT_NE(root->render_surface(), layer1->render_surface()); 1204 EXPECT_TRUE(!!layer1->render_surface()); 1205} 1206 1207class MissingTextureAnimatingLayer : public DidDrawCheckLayer { 1208 public: 1209 static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, 1210 int id, 1211 bool tile_missing, 1212 bool skips_draw, 1213 bool animating, 1214 ResourceProvider* resource_provider) { 1215 return scoped_ptr<LayerImpl>(new MissingTextureAnimatingLayer( 1216 tree_impl, 1217 id, 1218 tile_missing, 1219 skips_draw, 1220 animating, 1221 resource_provider)); 1222 } 1223 1224 private: 1225 MissingTextureAnimatingLayer(LayerTreeImpl* tree_impl, 1226 int id, 1227 bool tile_missing, 1228 bool skips_draw, 1229 bool animating, 1230 ResourceProvider* resource_provider) 1231 : DidDrawCheckLayer(tree_impl, id) { 1232 scoped_ptr<LayerTilingData> tiling_data = 1233 LayerTilingData::Create(gfx::Size(10, 10), 1234 LayerTilingData::NO_BORDER_TEXELS); 1235 tiling_data->SetBounds(bounds()); 1236 SetTilingData(*tiling_data.get()); 1237 set_skips_draw(skips_draw); 1238 if (!tile_missing) { 1239 ResourceProvider::ResourceId resource = 1240 resource_provider->CreateResource(gfx::Size(1, 1), 1241 GL_RGBA, 1242 ResourceProvider::TextureUsageAny); 1243 resource_provider->AllocateForTesting(resource); 1244 PushTileProperties(0, 0, resource, gfx::Rect(), false); 1245 } 1246 if (animating) 1247 AddAnimatedTransformToLayer(this, 10.0, 3, 0); 1248 } 1249}; 1250 1251TEST_F(LayerTreeHostImplTest, PrepareToDrawFailsWhenAnimationUsesCheckerboard) { 1252 // When the texture is not missing, we draw as usual. 1253 host_impl_->active_tree()->SetRootLayer( 1254 DidDrawCheckLayer::Create(host_impl_->active_tree(), 1)); 1255 DidDrawCheckLayer* root = 1256 static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer()); 1257 root->AddChild( 1258 MissingTextureAnimatingLayer::Create(host_impl_->active_tree(), 1259 2, 1260 false, 1261 false, 1262 true, 1263 host_impl_->resource_provider())); 1264 1265 LayerTreeHostImpl::FrameData frame; 1266 1267 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 1268 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 1269 host_impl_->DidDrawAllLayers(frame); 1270 1271 // When a texture is missing and we're not animating, we draw as usual with 1272 // checkerboarding. 1273 host_impl_->active_tree()->SetRootLayer( 1274 DidDrawCheckLayer::Create(host_impl_->active_tree(), 3)); 1275 root = 1276 static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer()); 1277 root->AddChild( 1278 MissingTextureAnimatingLayer::Create(host_impl_->active_tree(), 1279 4, 1280 true, 1281 false, 1282 false, 1283 host_impl_->resource_provider())); 1284 1285 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 1286 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 1287 host_impl_->DidDrawAllLayers(frame); 1288 1289 // When a texture is missing and we're animating, we don't want to draw 1290 // anything. 1291 host_impl_->active_tree()->SetRootLayer( 1292 DidDrawCheckLayer::Create(host_impl_->active_tree(), 5)); 1293 root = 1294 static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer()); 1295 root->AddChild( 1296 MissingTextureAnimatingLayer::Create(host_impl_->active_tree(), 1297 6, 1298 true, 1299 false, 1300 true, 1301 host_impl_->resource_provider())); 1302 1303 EXPECT_FALSE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 1304 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 1305 host_impl_->DidDrawAllLayers(frame); 1306 1307 // When the layer skips draw and we're animating, we still draw the frame. 1308 host_impl_->active_tree()->SetRootLayer( 1309 DidDrawCheckLayer::Create(host_impl_->active_tree(), 7)); 1310 root = 1311 static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer()); 1312 root->AddChild( 1313 MissingTextureAnimatingLayer::Create(host_impl_->active_tree(), 1314 8, 1315 false, 1316 true, 1317 true, 1318 host_impl_->resource_provider())); 1319 1320 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 1321 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 1322 host_impl_->DidDrawAllLayers(frame); 1323} 1324 1325TEST_F(LayerTreeHostImplTest, ScrollRootIgnored) { 1326 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); 1327 root->SetScrollable(false); 1328 host_impl_->active_tree()->SetRootLayer(root.Pass()); 1329 InitializeRendererAndDrawFrame(); 1330 1331 // Scroll event is ignored because layer is not scrollable. 1332 EXPECT_EQ(InputHandler::ScrollIgnored, 1333 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel)); 1334 EXPECT_FALSE(did_request_redraw_); 1335 EXPECT_FALSE(did_request_commit_); 1336} 1337 1338TEST_F(LayerTreeHostImplTest, ScrollNonScrollableRootWithTopControls) { 1339 LayerTreeSettings settings; 1340 settings.calculate_top_controls_position = true; 1341 settings.top_controls_height = 50; 1342 1343 host_impl_ = LayerTreeHostImpl::Create(settings, 1344 this, 1345 &proxy_, 1346 &stats_instrumentation_); 1347 host_impl_->InitializeRenderer(CreateOutputSurface()); 1348 host_impl_->SetViewportSize(gfx::Size(10, 10)); 1349 1350 gfx::Size layer_size(5, 5); 1351 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); 1352 root->SetScrollable(true); 1353 root->SetMaxScrollOffset(gfx::Vector2d(layer_size.width(), 1354 layer_size.height())); 1355 root->SetBounds(layer_size); 1356 root->SetContentBounds(layer_size); 1357 root->SetPosition(gfx::PointF()); 1358 root->SetAnchorPoint(gfx::PointF()); 1359 root->SetDrawsContent(false); 1360 host_impl_->active_tree()->SetRootLayer(root.Pass()); 1361 host_impl_->active_tree()->FindRootScrollLayer(); 1362 InitializeRendererAndDrawFrame(); 1363 1364 EXPECT_EQ(InputHandler::ScrollIgnored, 1365 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); 1366 1367 host_impl_->top_controls_manager()->ScrollBegin(); 1368 host_impl_->top_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 50.f)); 1369 host_impl_->top_controls_manager()->ScrollEnd(); 1370 EXPECT_EQ(host_impl_->top_controls_manager()->content_top_offset(), 0.f); 1371 1372 EXPECT_EQ(InputHandler::ScrollStarted, 1373 host_impl_->ScrollBegin(gfx::Point(), 1374 InputHandler::Gesture)); 1375} 1376 1377TEST_F(LayerTreeHostImplTest, ScrollNonCompositedRoot) { 1378 // Test the configuration where a non-composited root layer is embedded in a 1379 // scrollable outer layer. 1380 gfx::Size surface_size(10, 10); 1381 1382 scoped_ptr<LayerImpl> content_layer = 1383 LayerImpl::Create(host_impl_->active_tree(), 1); 1384 content_layer->SetDrawsContent(true); 1385 content_layer->SetPosition(gfx::PointF()); 1386 content_layer->SetAnchorPoint(gfx::PointF()); 1387 content_layer->SetBounds(surface_size); 1388 content_layer->SetContentBounds(gfx::Size(surface_size.width() * 2, 1389 surface_size.height() * 2)); 1390 content_layer->SetContentsScale(2.f, 2.f); 1391 1392 scoped_ptr<LayerImpl> scroll_layer = 1393 LayerImpl::Create(host_impl_->active_tree(), 2); 1394 scroll_layer->SetScrollable(true); 1395 scroll_layer->SetMaxScrollOffset(gfx::Vector2d(surface_size.width(), 1396 surface_size.height())); 1397 scroll_layer->SetBounds(surface_size); 1398 scroll_layer->SetContentBounds(surface_size); 1399 scroll_layer->SetPosition(gfx::PointF()); 1400 scroll_layer->SetAnchorPoint(gfx::PointF()); 1401 scroll_layer->AddChild(content_layer.Pass()); 1402 1403 host_impl_->active_tree()->SetRootLayer(scroll_layer.Pass()); 1404 host_impl_->SetViewportSize(surface_size); 1405 InitializeRendererAndDrawFrame(); 1406 1407 EXPECT_EQ(InputHandler::ScrollStarted, 1408 host_impl_->ScrollBegin(gfx::Point(5, 5), 1409 InputHandler::Wheel)); 1410 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)); 1411 host_impl_->ScrollEnd(); 1412 EXPECT_TRUE(did_request_redraw_); 1413 EXPECT_TRUE(did_request_commit_); 1414} 1415 1416TEST_F(LayerTreeHostImplTest, ScrollChildCallsCommitAndRedraw) { 1417 gfx::Size surface_size(10, 10); 1418 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); 1419 root->SetBounds(surface_size); 1420 root->SetContentBounds(surface_size); 1421 root->AddChild(CreateScrollableLayer(2, surface_size)); 1422 host_impl_->active_tree()->SetRootLayer(root.Pass()); 1423 host_impl_->SetViewportSize(surface_size); 1424 InitializeRendererAndDrawFrame(); 1425 1426 EXPECT_EQ(InputHandler::ScrollStarted, 1427 host_impl_->ScrollBegin(gfx::Point(5, 5), 1428 InputHandler::Wheel)); 1429 host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)); 1430 host_impl_->ScrollEnd(); 1431 EXPECT_TRUE(did_request_redraw_); 1432 EXPECT_TRUE(did_request_commit_); 1433} 1434 1435TEST_F(LayerTreeHostImplTest, ScrollMissesChild) { 1436 gfx::Size surface_size(10, 10); 1437 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); 1438 root->AddChild(CreateScrollableLayer(2, surface_size)); 1439 host_impl_->active_tree()->SetRootLayer(root.Pass()); 1440 host_impl_->SetViewportSize(surface_size); 1441 InitializeRendererAndDrawFrame(); 1442 1443 // Scroll event is ignored because the input coordinate is outside the layer 1444 // boundaries. 1445 EXPECT_EQ(InputHandler::ScrollIgnored, 1446 host_impl_->ScrollBegin(gfx::Point(15, 5), 1447 InputHandler::Wheel)); 1448 EXPECT_FALSE(did_request_redraw_); 1449 EXPECT_FALSE(did_request_commit_); 1450} 1451 1452TEST_F(LayerTreeHostImplTest, ScrollMissesBackfacingChild) { 1453 gfx::Size surface_size(10, 10); 1454 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); 1455 scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, surface_size); 1456 host_impl_->SetViewportSize(surface_size); 1457 1458 gfx::Transform matrix; 1459 matrix.RotateAboutXAxis(180.0); 1460 child->SetTransform(matrix); 1461 child->SetDoubleSided(false); 1462 1463 root->AddChild(child.Pass()); 1464 host_impl_->active_tree()->SetRootLayer(root.Pass()); 1465 InitializeRendererAndDrawFrame(); 1466 1467 // Scroll event is ignored because the scrollable layer is not facing the 1468 // viewer and there is nothing scrollable behind it. 1469 EXPECT_EQ(InputHandler::ScrollIgnored, 1470 host_impl_->ScrollBegin(gfx::Point(5, 5), 1471 InputHandler::Wheel)); 1472 EXPECT_FALSE(did_request_redraw_); 1473 EXPECT_FALSE(did_request_commit_); 1474} 1475 1476TEST_F(LayerTreeHostImplTest, ScrollBlockedByContentLayer) { 1477 gfx::Size surface_size(10, 10); 1478 scoped_ptr<LayerImpl> content_layer = CreateScrollableLayer(1, surface_size); 1479 content_layer->SetShouldScrollOnMainThread(true); 1480 content_layer->SetScrollable(false); 1481 1482 scoped_ptr<LayerImpl> scroll_layer = CreateScrollableLayer(2, surface_size); 1483 scroll_layer->AddChild(content_layer.Pass()); 1484 1485 host_impl_->active_tree()->SetRootLayer(scroll_layer.Pass()); 1486 host_impl_->SetViewportSize(surface_size); 1487 InitializeRendererAndDrawFrame(); 1488 1489 // Scrolling fails because the content layer is asking to be scrolled on the 1490 // main thread. 1491 EXPECT_EQ(InputHandler::ScrollOnMainThread, 1492 host_impl_->ScrollBegin(gfx::Point(5, 5), 1493 InputHandler::Wheel)); 1494} 1495 1496TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) { 1497 gfx::Size surface_size(10, 10); 1498 float page_scale = 2.f; 1499 scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, surface_size); 1500 host_impl_->active_tree()->SetRootLayer(root.Pass()); 1501 host_impl_->active_tree()->DidBecomeActive(); 1502 host_impl_->SetViewportSize(surface_size); 1503 InitializeRendererAndDrawFrame(); 1504 1505 gfx::Vector2d scroll_delta(0, 10); 1506 gfx::Vector2d expected_scroll_delta = scroll_delta; 1507 gfx::Vector2d expected_max_scroll = 1508 host_impl_->active_tree()->root_layer()->max_scroll_offset(); 1509 EXPECT_EQ(InputHandler::ScrollStarted, 1510 host_impl_->ScrollBegin(gfx::Point(5, 5), 1511 InputHandler::Wheel)); 1512 host_impl_->ScrollBy(gfx::Point(), scroll_delta); 1513 host_impl_->ScrollEnd(); 1514 1515 // Set new page scale from main thread. 1516 host_impl_->active_tree()->SetPageScaleFactorAndLimits(page_scale, 1517 page_scale, 1518 page_scale); 1519 1520 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); 1521 ExpectContains(*scroll_info.get(), 1522 host_impl_->active_tree()->root_layer()->id(), 1523 expected_scroll_delta); 1524 1525 // The scroll range should also have been updated. 1526 EXPECT_EQ(expected_max_scroll, 1527 host_impl_->active_tree()->root_layer()->max_scroll_offset()); 1528 1529 // The page scale delta remains constant because the impl thread did not 1530 // scale. 1531 EXPECT_EQ(1.f, host_impl_->active_tree()->page_scale_delta()); 1532} 1533 1534TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) { 1535 gfx::Size surface_size(10, 10); 1536 float page_scale = 2.f; 1537 scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, surface_size); 1538 host_impl_->active_tree()->SetRootLayer(root.Pass()); 1539 host_impl_->active_tree()->DidBecomeActive(); 1540 host_impl_->SetViewportSize(surface_size); 1541 host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 1.f, page_scale); 1542 InitializeRendererAndDrawFrame(); 1543 1544 gfx::Vector2d scroll_delta(0, 10); 1545 gfx::Vector2d expected_scroll_delta = scroll_delta; 1546 gfx::Vector2d expected_max_scroll = 1547 host_impl_->active_tree()->root_layer()->max_scroll_offset(); 1548 EXPECT_EQ(InputHandler::ScrollStarted, 1549 host_impl_->ScrollBegin(gfx::Point(5, 5), 1550 InputHandler::Wheel)); 1551 host_impl_->ScrollBy(gfx::Point(), scroll_delta); 1552 host_impl_->ScrollEnd(); 1553 1554 // Set new page scale on impl thread by pinching. 1555 host_impl_->PinchGestureBegin(); 1556 host_impl_->PinchGestureUpdate(page_scale, gfx::Point()); 1557 host_impl_->PinchGestureEnd(); 1558 DrawOneFrame(); 1559 1560 // The scroll delta is not scaled because the main thread did not scale. 1561 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); 1562 ExpectContains(*scroll_info.get(), 1563 host_impl_->active_tree()->root_layer()->id(), 1564 expected_scroll_delta); 1565 1566 // The scroll range should also have been updated. 1567 EXPECT_EQ(expected_max_scroll, 1568 host_impl_->active_tree()->root_layer()->max_scroll_offset()); 1569 1570 // The page scale delta should match the new scale on the impl side. 1571 EXPECT_EQ(page_scale, host_impl_->active_tree()->total_page_scale_factor()); 1572} 1573 1574TEST_F(LayerTreeHostImplTest, PageScaleDeltaAppliedToRootScrollLayerOnly) { 1575 gfx::Size surface_size(10, 10); 1576 float default_page_scale = 1.f; 1577 gfx::Transform default_page_scale_matrix; 1578 default_page_scale_matrix.Scale(default_page_scale, default_page_scale); 1579 1580 float new_page_scale = 2.f; 1581 gfx::Transform new_page_scale_matrix; 1582 new_page_scale_matrix.Scale(new_page_scale, new_page_scale); 1583 1584 // Create a normal scrollable root layer and another scrollable child layer. 1585 SetupScrollAndContentsLayers(surface_size); 1586 LayerImpl* root = host_impl_->active_tree()->root_layer(); 1587 LayerImpl* child = root->children()[0]; 1588 1589 scoped_ptr<LayerImpl> scrollable_child = 1590 CreateScrollableLayer(3, surface_size); 1591 child->AddChild(scrollable_child.Pass()); 1592 LayerImpl* grand_child = child->children()[0]; 1593 1594 // Set new page scale on impl thread by pinching. 1595 host_impl_->PinchGestureBegin(); 1596 host_impl_->PinchGestureUpdate(new_page_scale, gfx::Point()); 1597 host_impl_->PinchGestureEnd(); 1598 DrawOneFrame(); 1599 1600 EXPECT_EQ(1.f, root->contents_scale_x()); 1601 EXPECT_EQ(1.f, root->contents_scale_y()); 1602 EXPECT_EQ(1.f, child->contents_scale_x()); 1603 EXPECT_EQ(1.f, child->contents_scale_y()); 1604 EXPECT_EQ(1.f, grand_child->contents_scale_x()); 1605 EXPECT_EQ(1.f, grand_child->contents_scale_y()); 1606 1607 // Make sure all the layers are drawn with the page scale delta applied, i.e., 1608 // the page scale delta on the root layer is applied hierarchically. 1609 LayerTreeHostImpl::FrameData frame; 1610 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 1611 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 1612 host_impl_->DidDrawAllLayers(frame); 1613 1614 EXPECT_EQ(new_page_scale, root->draw_transform().matrix().getDouble(0, 0)); 1615 EXPECT_EQ(new_page_scale, root->draw_transform().matrix().getDouble(1, 1)); 1616 EXPECT_EQ(new_page_scale, child->draw_transform().matrix().getDouble(0, 0)); 1617 EXPECT_EQ(new_page_scale, child->draw_transform().matrix().getDouble(1, 1)); 1618 EXPECT_EQ(new_page_scale, 1619 grand_child->draw_transform().matrix().getDouble(0, 0)); 1620 EXPECT_EQ(new_page_scale, 1621 grand_child->draw_transform().matrix().getDouble(1, 1)); 1622} 1623 1624TEST_F(LayerTreeHostImplTest, ScrollChildAndChangePageScaleOnMainThread) { 1625 gfx::Size surface_size(10, 10); 1626 scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1); 1627 root->SetBounds(surface_size); 1628 root->SetContentBounds(surface_size); 1629 // Also mark the root scrollable so it becomes the root scroll layer. 1630 root->SetScrollable(true); 1631 int scroll_layer_id = 2; 1632 root->AddChild(CreateScrollableLayer(scroll_layer_id, surface_size)); 1633 host_impl_->active_tree()->SetRootLayer(root.Pass()); 1634 host_impl_->active_tree()->DidBecomeActive(); 1635 host_impl_->SetViewportSize(surface_size); 1636 InitializeRendererAndDrawFrame(); 1637 1638 LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0]; 1639 1640 gfx::Vector2d scroll_delta(0, 10); 1641 gfx::Vector2d expected_scroll_delta(scroll_delta); 1642 gfx::Vector2d expected_max_scroll(child->max_scroll_offset()); 1643 EXPECT_EQ(InputHandler::ScrollStarted, 1644 host_impl_->ScrollBegin(gfx::Point(5, 5), 1645 InputHandler::Wheel)); 1646 host_impl_->ScrollBy(gfx::Point(), scroll_delta); 1647 host_impl_->ScrollEnd(); 1648 1649 float page_scale = 2.f; 1650 host_impl_->active_tree()->SetPageScaleFactorAndLimits(page_scale, 1651 1.f, 1652 page_scale); 1653 1654 DrawOneFrame(); 1655 1656 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); 1657 ExpectContains(*scroll_info.get(), scroll_layer_id, expected_scroll_delta); 1658 1659 // The scroll range should not have changed. 1660 EXPECT_EQ(child->max_scroll_offset(), expected_max_scroll); 1661 1662 // The page scale delta remains constant because the impl thread did not 1663 // scale. 1664 EXPECT_EQ(1.f, host_impl_->active_tree()->page_scale_delta()); 1665} 1666 1667TEST_F(LayerTreeHostImplTest, ScrollChildBeyondLimit) { 1668 // Scroll a child layer beyond its maximum scroll range and make sure the 1669 // parent layer is scrolled on the axis on which the child was unable to 1670 // scroll. 1671 gfx::Size surface_size(10, 10); 1672 scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, surface_size); 1673 1674 scoped_ptr<LayerImpl> grand_child = CreateScrollableLayer(3, surface_size); 1675 grand_child->SetScrollOffset(gfx::Vector2d(0, 5)); 1676 1677 scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, surface_size); 1678 child->SetScrollOffset(gfx::Vector2d(3, 0)); 1679 child->AddChild(grand_child.Pass()); 1680 1681 root->AddChild(child.Pass()); 1682 host_impl_->active_tree()->SetRootLayer(root.Pass()); 1683 host_impl_->active_tree()->DidBecomeActive(); 1684 host_impl_->SetViewportSize(surface_size); 1685 InitializeRendererAndDrawFrame(); 1686 { 1687 gfx::Vector2d scroll_delta(-8, -7); 1688 EXPECT_EQ(InputHandler::ScrollStarted, 1689 host_impl_->ScrollBegin(gfx::Point(5, 5), 1690 InputHandler::Wheel)); 1691 host_impl_->ScrollBy(gfx::Point(), scroll_delta); 1692 host_impl_->ScrollEnd(); 1693 1694 scoped_ptr<ScrollAndScaleSet> scroll_info = 1695 host_impl_->ProcessScrollDeltas(); 1696 1697 // The grand child should have scrolled up to its limit. 1698 LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0]; 1699 LayerImpl* grand_child = child->children()[0]; 1700 ExpectContains(*scroll_info.get(), grand_child->id(), gfx::Vector2d(0, -5)); 1701 1702 // The child should have only scrolled on the other axis. 1703 ExpectContains(*scroll_info.get(), child->id(), gfx::Vector2d(-3, 0)); 1704 } 1705} 1706 1707TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) { 1708 // Scroll a child layer beyond its maximum scroll range and make sure the 1709 // the scroll doesn't bubble up to the parent layer. 1710 gfx::Size surface_size(10, 10); 1711 scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, surface_size); 1712 1713 scoped_ptr<LayerImpl> grand_child = CreateScrollableLayer(3, surface_size); 1714 grand_child->SetScrollOffset(gfx::Vector2d(0, 2)); 1715 1716 scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, surface_size); 1717 child->SetScrollOffset(gfx::Vector2d(0, 3)); 1718 child->AddChild(grand_child.Pass()); 1719 1720 root->AddChild(child.Pass()); 1721 host_impl_->active_tree()->SetRootLayer(root.Pass()); 1722 host_impl_->active_tree()->DidBecomeActive(); 1723 host_impl_->SetViewportSize(surface_size); 1724 InitializeRendererAndDrawFrame(); 1725 { 1726 gfx::Vector2d scroll_delta(0, -10); 1727 EXPECT_EQ(InputHandler::ScrollStarted, 1728 host_impl_->ScrollBegin(gfx::Point(5, 5), 1729 InputHandler::NonBubblingGesture)); 1730 host_impl_->ScrollBy(gfx::Point(), scroll_delta); 1731 host_impl_->ScrollEnd(); 1732 1733 scoped_ptr<ScrollAndScaleSet> scroll_info = 1734 host_impl_->ProcessScrollDeltas(); 1735 1736 // The grand child should have scrolled up to its limit. 1737 LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0]; 1738 LayerImpl* grand_child = child->children()[0]; 1739 ExpectContains(*scroll_info.get(), grand_child->id(), gfx::Vector2d(0, -2)); 1740 1741 // The child should not have scrolled. 1742 ExpectNone(*scroll_info.get(), child->id()); 1743 1744 // The next time we scroll we should only scroll the parent. 1745 scroll_delta = gfx::Vector2d(0, -3); 1746 EXPECT_EQ(InputHandler::ScrollStarted, 1747 host_impl_->ScrollBegin(gfx::Point(5, 5), 1748 InputHandler::NonBubblingGesture)); 1749 EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child); 1750 host_impl_->ScrollBy(gfx::Point(), scroll_delta); 1751 EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child); 1752 host_impl_->ScrollEnd(); 1753 1754 scroll_info = host_impl_->ProcessScrollDeltas(); 1755 1756 // The child should have scrolled up to its limit. 1757 ExpectContains(*scroll_info.get(), child->id(), gfx::Vector2d(0, -3)); 1758 1759 // The grand child should not have scrolled. 1760 ExpectContains(*scroll_info.get(), grand_child->id(), gfx::Vector2d(0, -2)); 1761 1762 // After scrolling the parent, another scroll on the opposite direction 1763 // should still scroll the child. 1764 scroll_delta = gfx::Vector2d(0, 7); 1765 EXPECT_EQ(InputHandler::ScrollStarted, 1766 host_impl_->ScrollBegin(gfx::Point(5, 5), 1767 InputHandler::NonBubblingGesture)); 1768 EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child); 1769 host_impl_->ScrollBy(gfx::Point(), scroll_delta); 1770 EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child); 1771 host_impl_->ScrollEnd(); 1772 1773 scroll_info = host_impl_->ProcessScrollDeltas(); 1774 1775 // The grand child should have scrolled. 1776 ExpectContains(*scroll_info.get(), grand_child->id(), gfx::Vector2d(0, 5)); 1777 1778 // The child should not have scrolled. 1779 ExpectContains(*scroll_info.get(), child->id(), gfx::Vector2d(0, -3)); 1780 1781 1782 // Scrolling should be adjusted from viewport space. 1783 host_impl_->active_tree()->SetPageScaleFactorAndLimits(2.f, 2.f, 2.f); 1784 host_impl_->active_tree()->SetPageScaleDelta(1.f); 1785 1786 scroll_delta = gfx::Vector2d(0, -2); 1787 EXPECT_EQ(InputHandler::ScrollStarted, 1788 host_impl_->ScrollBegin(gfx::Point(1, 1), 1789 InputHandler::NonBubblingGesture)); 1790 EXPECT_EQ(grand_child, host_impl_->CurrentlyScrollingLayer()); 1791 host_impl_->ScrollBy(gfx::Point(), scroll_delta); 1792 host_impl_->ScrollEnd(); 1793 1794 scroll_info = host_impl_->ProcessScrollDeltas(); 1795 1796 // Should have scrolled by half the amount in layer space (5 - 2/2) 1797 ExpectContains(*scroll_info.get(), grand_child->id(), gfx::Vector2d(0, 4)); 1798 } 1799} 1800 1801TEST_F(LayerTreeHostImplTest, ScrollEventBubbling) { 1802 // When we try to scroll a non-scrollable child layer, the scroll delta 1803 // should be applied to one of its ancestors if possible. 1804 gfx::Size surface_size(10, 10); 1805 gfx::Size content_size(20, 20); 1806 scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, content_size); 1807 scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, content_size); 1808 1809 child->SetScrollable(false); 1810 root->AddChild(child.Pass()); 1811 1812 host_impl_->SetViewportSize(surface_size); 1813 host_impl_->active_tree()->SetRootLayer(root.Pass()); 1814 host_impl_->active_tree()->DidBecomeActive(); 1815 InitializeRendererAndDrawFrame(); 1816 { 1817 gfx::Vector2d scroll_delta(0, 4); 1818 EXPECT_EQ(InputHandler::ScrollStarted, 1819 host_impl_->ScrollBegin(gfx::Point(5, 5), 1820 InputHandler::Wheel)); 1821 host_impl_->ScrollBy(gfx::Point(), scroll_delta); 1822 host_impl_->ScrollEnd(); 1823 1824 scoped_ptr<ScrollAndScaleSet> scroll_info = 1825 host_impl_->ProcessScrollDeltas(); 1826 1827 // Only the root should have scrolled. 1828 ASSERT_EQ(scroll_info->scrolls.size(), 1u); 1829 ExpectContains(*scroll_info.get(), 1830 host_impl_->active_tree()->root_layer()->id(), 1831 scroll_delta); 1832 } 1833} 1834 1835TEST_F(LayerTreeHostImplTest, ScrollBeforeRedraw) { 1836 gfx::Size surface_size(10, 10); 1837 host_impl_->active_tree()->SetRootLayer( 1838 CreateScrollableLayer(1, surface_size)); 1839 host_impl_->active_tree()->DidBecomeActive(); 1840 host_impl_->SetViewportSize(surface_size); 1841 1842 // Draw one frame and then immediately rebuild the layer tree to mimic a tree 1843 // synchronization. 1844 InitializeRendererAndDrawFrame(); 1845 host_impl_->active_tree()->DetachLayerTree(); 1846 host_impl_->active_tree()->SetRootLayer( 1847 CreateScrollableLayer(2, surface_size)); 1848 host_impl_->active_tree()->DidBecomeActive(); 1849 1850 // Scrolling should still work even though we did not draw yet. 1851 EXPECT_EQ(InputHandler::ScrollStarted, 1852 host_impl_->ScrollBegin(gfx::Point(5, 5), 1853 InputHandler::Wheel)); 1854} 1855 1856TEST_F(LayerTreeHostImplTest, ScrollAxisAlignedRotatedLayer) { 1857 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 1858 1859 // Rotate the root layer 90 degrees counter-clockwise about its center. 1860 gfx::Transform rotate_transform; 1861 rotate_transform.Rotate(-90.0); 1862 host_impl_->active_tree()->root_layer()->SetTransform(rotate_transform); 1863 1864 gfx::Size surface_size(50, 50); 1865 host_impl_->SetViewportSize(surface_size); 1866 InitializeRendererAndDrawFrame(); 1867 1868 // Scroll to the right in screen coordinates with a gesture. 1869 gfx::Vector2d gesture_scroll_delta(10, 0); 1870 EXPECT_EQ(InputHandler::ScrollStarted, 1871 host_impl_->ScrollBegin(gfx::Point(), 1872 InputHandler::Gesture)); 1873 host_impl_->ScrollBy(gfx::Point(), gesture_scroll_delta); 1874 host_impl_->ScrollEnd(); 1875 1876 // The layer should have scrolled down in its local coordinates. 1877 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); 1878 ExpectContains(*scroll_info.get(), 1879 host_impl_->active_tree()->root_layer()->id(), 1880 gfx::Vector2d(0, gesture_scroll_delta.x())); 1881 1882 // Reset and scroll down with the wheel. 1883 host_impl_->active_tree()->root_layer()->SetScrollDelta(gfx::Vector2dF()); 1884 gfx::Vector2d wheel_scroll_delta(0, 10); 1885 EXPECT_EQ(InputHandler::ScrollStarted, 1886 host_impl_->ScrollBegin(gfx::Point(), 1887 InputHandler::Wheel)); 1888 host_impl_->ScrollBy(gfx::Point(), wheel_scroll_delta); 1889 host_impl_->ScrollEnd(); 1890 1891 // The layer should have scrolled down in its local coordinates. 1892 scroll_info = host_impl_->ProcessScrollDeltas(); 1893 ExpectContains(*scroll_info.get(), 1894 host_impl_->active_tree()->root_layer()->id(), 1895 wheel_scroll_delta); 1896} 1897 1898TEST_F(LayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) { 1899 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 1900 int child_layer_id = 3; 1901 float child_layer_angle = -20.f; 1902 1903 // Create a child layer that is rotated to a non-axis-aligned angle. 1904 scoped_ptr<LayerImpl> child = CreateScrollableLayer( 1905 child_layer_id, 1906 host_impl_->active_tree()->root_layer()->content_bounds()); 1907 gfx::Transform rotate_transform; 1908 rotate_transform.Translate(-50.0, -50.0); 1909 rotate_transform.Rotate(child_layer_angle); 1910 rotate_transform.Translate(50.0, 50.0); 1911 child->SetTransform(rotate_transform); 1912 1913 // Only allow vertical scrolling. 1914 child->SetMaxScrollOffset(gfx::Vector2d(0, child->content_bounds().height())); 1915 host_impl_->active_tree()->root_layer()->AddChild(child.Pass()); 1916 1917 gfx::Size surface_size(50, 50); 1918 host_impl_->SetViewportSize(surface_size); 1919 InitializeRendererAndDrawFrame(); 1920 { 1921 // Scroll down in screen coordinates with a gesture. 1922 gfx::Vector2d gesture_scroll_delta(0, 10); 1923 EXPECT_EQ(InputHandler::ScrollStarted, 1924 host_impl_->ScrollBegin(gfx::Point(), 1925 InputHandler::Gesture)); 1926 host_impl_->ScrollBy(gfx::Point(), gesture_scroll_delta); 1927 host_impl_->ScrollEnd(); 1928 1929 // The child layer should have scrolled down in its local coordinates an 1930 // amount proportional to the angle between it and the input scroll delta. 1931 gfx::Vector2d expected_scroll_delta( 1932 0, 1933 gesture_scroll_delta.y() * 1934 std::cos(MathUtil::Deg2Rad(child_layer_angle))); 1935 scoped_ptr<ScrollAndScaleSet> scroll_info = 1936 host_impl_->ProcessScrollDeltas(); 1937 ExpectContains(*scroll_info.get(), child_layer_id, expected_scroll_delta); 1938 1939 // The root layer should not have scrolled, because the input delta was 1940 // close to the layer's axis of movement. 1941 EXPECT_EQ(scroll_info->scrolls.size(), 1u); 1942 } 1943 { 1944 // Now reset and scroll the same amount horizontally. 1945 host_impl_->active_tree()->root_layer()->children()[1]->SetScrollDelta( 1946 gfx::Vector2dF()); 1947 gfx::Vector2d gesture_scroll_delta(10, 0); 1948 EXPECT_EQ(InputHandler::ScrollStarted, 1949 host_impl_->ScrollBegin(gfx::Point(), 1950 InputHandler::Gesture)); 1951 host_impl_->ScrollBy(gfx::Point(), gesture_scroll_delta); 1952 host_impl_->ScrollEnd(); 1953 1954 // The child layer should have scrolled down in its local coordinates an 1955 // amount proportional to the angle between it and the input scroll delta. 1956 gfx::Vector2d expected_scroll_delta( 1957 0, 1958 -gesture_scroll_delta.x() * 1959 std::sin(MathUtil::Deg2Rad(child_layer_angle))); 1960 scoped_ptr<ScrollAndScaleSet> scroll_info = 1961 host_impl_->ProcessScrollDeltas(); 1962 ExpectContains(*scroll_info.get(), child_layer_id, expected_scroll_delta); 1963 1964 // The root layer should have scrolled more, since the input scroll delta 1965 // was mostly orthogonal to the child layer's vertical scroll axis. 1966 gfx::Vector2d expected_root_scroll_delta( 1967 gesture_scroll_delta.x() * 1968 std::pow(std::cos(MathUtil::Deg2Rad(child_layer_angle)), 2), 1969 0); 1970 ExpectContains(*scroll_info.get(), 1971 host_impl_->active_tree()->root_layer()->id(), 1972 expected_root_scroll_delta); 1973 } 1974} 1975 1976TEST_F(LayerTreeHostImplTest, ScrollScaledLayer) { 1977 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 1978 1979 // Scale the layer to twice its normal size. 1980 int scale = 2; 1981 gfx::Transform scale_transform; 1982 scale_transform.Scale(scale, scale); 1983 host_impl_->active_tree()->root_layer()->SetTransform(scale_transform); 1984 1985 gfx::Size surface_size(50, 50); 1986 host_impl_->SetViewportSize(surface_size); 1987 InitializeRendererAndDrawFrame(); 1988 1989 // Scroll down in screen coordinates with a gesture. 1990 gfx::Vector2d scroll_delta(0, 10); 1991 EXPECT_EQ(InputHandler::ScrollStarted, 1992 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); 1993 host_impl_->ScrollBy(gfx::Point(), scroll_delta); 1994 host_impl_->ScrollEnd(); 1995 1996 // The layer should have scrolled down in its local coordinates, but half the 1997 // amount. 1998 scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas(); 1999 ExpectContains(*scroll_info.get(), 2000 host_impl_->active_tree()->root_layer()->id(), 2001 gfx::Vector2d(0, scroll_delta.y() / scale)); 2002 2003 // Reset and scroll down with the wheel. 2004 host_impl_->active_tree()->root_layer()->SetScrollDelta(gfx::Vector2dF()); 2005 gfx::Vector2d wheel_scroll_delta(0, 10); 2006 EXPECT_EQ(InputHandler::ScrollStarted, 2007 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel)); 2008 host_impl_->ScrollBy(gfx::Point(), wheel_scroll_delta); 2009 host_impl_->ScrollEnd(); 2010 2011 // The scale should not have been applied to the scroll delta. 2012 scroll_info = host_impl_->ProcessScrollDeltas(); 2013 ExpectContains(*scroll_info.get(), 2014 host_impl_->active_tree()->root_layer()->id(), 2015 wheel_scroll_delta); 2016} 2017 2018class TestScrollOffsetDelegate : public LayerScrollOffsetDelegate { 2019 public: 2020 TestScrollOffsetDelegate() {} 2021 virtual ~TestScrollOffsetDelegate() {} 2022 2023 virtual void SetTotalScrollOffset(gfx::Vector2dF new_value) OVERRIDE { 2024 last_set_scroll_offset_ = new_value; 2025 } 2026 2027 virtual gfx::Vector2dF GetTotalScrollOffset() OVERRIDE { 2028 return getter_return_value_; 2029 } 2030 2031 gfx::Vector2dF last_set_scroll_offset() { 2032 return last_set_scroll_offset_; 2033 } 2034 2035 void set_getter_return_value(gfx::Vector2dF value) { 2036 getter_return_value_ = value; 2037 } 2038 2039 private: 2040 gfx::Vector2dF last_set_scroll_offset_; 2041 gfx::Vector2dF getter_return_value_; 2042}; 2043 2044TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) { 2045 TestScrollOffsetDelegate scroll_delegate; 2046 SetupScrollAndContentsLayers(gfx::Size(100, 100)); 2047 2048 // Setting the delegate results in the current scroll offset being set. 2049 gfx::Vector2dF initial_scroll_delta(10, 10); 2050 host_impl_->active_tree()->root_layer()->SetScrollOffset(gfx::Vector2d()); 2051 host_impl_->active_tree()->root_layer()->SetScrollDelta(initial_scroll_delta); 2052 host_impl_->SetRootLayerScrollOffsetDelegate(&scroll_delegate); 2053 EXPECT_EQ(initial_scroll_delta, scroll_delegate.last_set_scroll_offset()); 2054 2055 // Scrolling should be relative to the offset as returned by the delegate. 2056 gfx::Vector2d scroll_delta(0, 10); 2057 gfx::Vector2d current_offset(7, 8); 2058 2059 scroll_delegate.set_getter_return_value(current_offset); 2060 EXPECT_EQ(InputHandler::ScrollStarted, 2061 host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture)); 2062 2063 host_impl_->ScrollBy(gfx::Point(), scroll_delta); 2064 EXPECT_EQ(current_offset + scroll_delta, 2065 scroll_delegate.last_set_scroll_offset()); 2066 2067 current_offset = gfx::Vector2d(42, 41); 2068 scroll_delegate.set_getter_return_value(current_offset); 2069 host_impl_->ScrollBy(gfx::Point(), scroll_delta); 2070 EXPECT_EQ(current_offset + scroll_delta, 2071 scroll_delegate.last_set_scroll_offset()); 2072 host_impl_->ScrollEnd(); 2073 2074 // Un-setting the delegate should propagate the delegate's current offset to 2075 // the root scrollable layer. 2076 current_offset = gfx::Vector2d(13, 12); 2077 scroll_delegate.set_getter_return_value(current_offset); 2078 host_impl_->SetRootLayerScrollOffsetDelegate(NULL); 2079 2080 EXPECT_EQ(current_offset, 2081 host_impl_->active_tree()->root_layer()->TotalScrollOffset()); 2082} 2083 2084class BlendStateTrackerContext: public TestWebGraphicsContext3D { 2085 public: 2086 BlendStateTrackerContext() : blend_(false) {} 2087 2088 virtual void enable(WebKit::WGC3Denum cap) OVERRIDE { 2089 if (cap == GL_BLEND) 2090 blend_ = true; 2091 } 2092 2093 virtual void disable(WebKit::WGC3Denum cap) OVERRIDE { 2094 if (cap == GL_BLEND) 2095 blend_ = false; 2096 } 2097 2098 bool blend() const { return blend_; } 2099 2100 private: 2101 bool blend_; 2102}; 2103 2104class BlendStateCheckLayer : public LayerImpl { 2105 public: 2106 static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, 2107 int id, 2108 ResourceProvider* resource_provider) { 2109 return scoped_ptr<LayerImpl>(new BlendStateCheckLayer(tree_impl, 2110 id, 2111 resource_provider)); 2112 } 2113 2114 virtual void AppendQuads(QuadSink* quad_sink, 2115 AppendQuadsData* append_quads_data) OVERRIDE { 2116 quads_appended_ = true; 2117 2118 gfx::Rect opaque_rect; 2119 if (contents_opaque()) 2120 opaque_rect = quad_rect_; 2121 else 2122 opaque_rect = opaque_content_rect_; 2123 2124 SharedQuadState* shared_quad_state = 2125 quad_sink->UseSharedQuadState(CreateSharedQuadState()); 2126 scoped_ptr<TileDrawQuad> test_blending_draw_quad = TileDrawQuad::Create(); 2127 test_blending_draw_quad->SetNew(shared_quad_state, 2128 quad_rect_, 2129 opaque_rect, 2130 resource_id_, 2131 gfx::RectF(0.f, 0.f, 1.f, 1.f), 2132 gfx::Size(1, 1), 2133 false); 2134 test_blending_draw_quad->visible_rect = quad_visible_rect_; 2135 EXPECT_EQ(blend_, test_blending_draw_quad->ShouldDrawWithBlending()); 2136 EXPECT_EQ(has_render_surface_, !!render_surface()); 2137 quad_sink->Append(test_blending_draw_quad.PassAs<DrawQuad>(), 2138 append_quads_data); 2139 } 2140 2141 void SetExpectation(bool blend, bool has_render_surface) { 2142 blend_ = blend; 2143 has_render_surface_ = has_render_surface; 2144 quads_appended_ = false; 2145 } 2146 2147 bool quads_appended() const { return quads_appended_; } 2148 2149 void SetQuadRect(gfx::Rect rect) { quad_rect_ = rect; } 2150 void SetQuadVisibleRect(gfx::Rect rect) { quad_visible_rect_ = rect; } 2151 void SetOpaqueContentRect(gfx::Rect rect) { opaque_content_rect_ = rect; } 2152 2153 private: 2154 BlendStateCheckLayer(LayerTreeImpl* tree_impl, 2155 int id, 2156 ResourceProvider* resource_provider) 2157 : LayerImpl(tree_impl, id), 2158 blend_(false), 2159 has_render_surface_(false), 2160 quads_appended_(false), 2161 quad_rect_(5, 5, 5, 5), 2162 quad_visible_rect_(5, 5, 5, 5), 2163 resource_id_(resource_provider->CreateResource( 2164 gfx::Size(1, 1), 2165 GL_RGBA, 2166 ResourceProvider::TextureUsageAny)) { 2167 resource_provider->AllocateForTesting(resource_id_); 2168 SetAnchorPoint(gfx::PointF()); 2169 SetBounds(gfx::Size(10, 10)); 2170 SetContentBounds(gfx::Size(10, 10)); 2171 SetDrawsContent(true); 2172 } 2173 2174 bool blend_; 2175 bool has_render_surface_; 2176 bool quads_appended_; 2177 gfx::Rect quad_rect_; 2178 gfx::Rect opaque_content_rect_; 2179 gfx::Rect quad_visible_rect_; 2180 ResourceProvider::ResourceId resource_id_; 2181}; 2182 2183TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) { 2184 { 2185 scoped_ptr<LayerImpl> root = 2186 LayerImpl::Create(host_impl_->active_tree(), 1); 2187 root->SetAnchorPoint(gfx::PointF()); 2188 root->SetBounds(gfx::Size(10, 10)); 2189 root->SetContentBounds(root->bounds()); 2190 root->SetDrawsContent(false); 2191 host_impl_->active_tree()->SetRootLayer(root.Pass()); 2192 } 2193 LayerImpl* root = host_impl_->active_tree()->root_layer(); 2194 2195 root->AddChild( 2196 BlendStateCheckLayer::Create(host_impl_->active_tree(), 2197 2, 2198 host_impl_->resource_provider())); 2199 BlendStateCheckLayer* layer1 = 2200 static_cast<BlendStateCheckLayer*>(root->children()[0]); 2201 layer1->SetPosition(gfx::PointF(2.f, 2.f)); 2202 2203 LayerTreeHostImpl::FrameData frame; 2204 2205 // Opaque layer, drawn without blending. 2206 layer1->SetContentsOpaque(true); 2207 layer1->SetExpectation(false, false); 2208 layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); 2209 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2210 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2211 EXPECT_TRUE(layer1->quads_appended()); 2212 host_impl_->DidDrawAllLayers(frame); 2213 2214 // Layer with translucent content and painting, so drawn with blending. 2215 layer1->SetContentsOpaque(false); 2216 layer1->SetExpectation(true, false); 2217 layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); 2218 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2219 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2220 EXPECT_TRUE(layer1->quads_appended()); 2221 host_impl_->DidDrawAllLayers(frame); 2222 2223 // Layer with translucent opacity, drawn with blending. 2224 layer1->SetContentsOpaque(true); 2225 layer1->SetOpacity(0.5f); 2226 layer1->SetExpectation(true, false); 2227 layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); 2228 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2229 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2230 EXPECT_TRUE(layer1->quads_appended()); 2231 host_impl_->DidDrawAllLayers(frame); 2232 2233 // Layer with translucent opacity and painting, drawn with blending. 2234 layer1->SetContentsOpaque(true); 2235 layer1->SetOpacity(0.5f); 2236 layer1->SetExpectation(true, false); 2237 layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); 2238 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2239 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2240 EXPECT_TRUE(layer1->quads_appended()); 2241 host_impl_->DidDrawAllLayers(frame); 2242 2243 layer1->AddChild( 2244 BlendStateCheckLayer::Create(host_impl_->active_tree(), 2245 3, 2246 host_impl_->resource_provider())); 2247 BlendStateCheckLayer* layer2 = 2248 static_cast<BlendStateCheckLayer*>(layer1->children()[0]); 2249 layer2->SetPosition(gfx::PointF(4.f, 4.f)); 2250 2251 // 2 opaque layers, drawn without blending. 2252 layer1->SetContentsOpaque(true); 2253 layer1->SetOpacity(1.f); 2254 layer1->SetExpectation(false, false); 2255 layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); 2256 layer2->SetContentsOpaque(true); 2257 layer2->SetOpacity(1.f); 2258 layer2->SetExpectation(false, false); 2259 layer2->set_update_rect(gfx::RectF(layer1->content_bounds())); 2260 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2261 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2262 EXPECT_TRUE(layer1->quads_appended()); 2263 EXPECT_TRUE(layer2->quads_appended()); 2264 host_impl_->DidDrawAllLayers(frame); 2265 2266 // Parent layer with translucent content, drawn with blending. 2267 // Child layer with opaque content, drawn without blending. 2268 layer1->SetContentsOpaque(false); 2269 layer1->SetExpectation(true, false); 2270 layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); 2271 layer2->SetExpectation(false, false); 2272 layer2->set_update_rect(gfx::RectF(layer1->content_bounds())); 2273 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2274 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2275 EXPECT_TRUE(layer1->quads_appended()); 2276 EXPECT_TRUE(layer2->quads_appended()); 2277 host_impl_->DidDrawAllLayers(frame); 2278 2279 // Parent layer with translucent content but opaque painting, drawn without 2280 // blending. 2281 // Child layer with opaque content, drawn without blending. 2282 layer1->SetContentsOpaque(true); 2283 layer1->SetExpectation(false, false); 2284 layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); 2285 layer2->SetExpectation(false, false); 2286 layer2->set_update_rect(gfx::RectF(layer1->content_bounds())); 2287 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2288 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2289 EXPECT_TRUE(layer1->quads_appended()); 2290 EXPECT_TRUE(layer2->quads_appended()); 2291 host_impl_->DidDrawAllLayers(frame); 2292 2293 // Parent layer with translucent opacity and opaque content. Since it has a 2294 // drawing child, it's drawn to a render surface which carries the opacity, 2295 // so it's itself drawn without blending. 2296 // Child layer with opaque content, drawn without blending (parent surface 2297 // carries the inherited opacity). 2298 layer1->SetContentsOpaque(true); 2299 layer1->SetOpacity(0.5f); 2300 layer1->SetExpectation(false, true); 2301 layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); 2302 layer2->SetExpectation(false, false); 2303 layer2->set_update_rect(gfx::RectF(layer1->content_bounds())); 2304 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2305 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2306 EXPECT_TRUE(layer1->quads_appended()); 2307 EXPECT_TRUE(layer2->quads_appended()); 2308 host_impl_->DidDrawAllLayers(frame); 2309 2310 // Draw again, but with child non-opaque, to make sure 2311 // layer1 not culled. 2312 layer1->SetContentsOpaque(true); 2313 layer1->SetOpacity(1.f); 2314 layer1->SetExpectation(false, false); 2315 layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); 2316 layer2->SetContentsOpaque(true); 2317 layer2->SetOpacity(0.5f); 2318 layer2->SetExpectation(true, false); 2319 layer2->set_update_rect(gfx::RectF(layer1->content_bounds())); 2320 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2321 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2322 EXPECT_TRUE(layer1->quads_appended()); 2323 EXPECT_TRUE(layer2->quads_appended()); 2324 host_impl_->DidDrawAllLayers(frame); 2325 2326 // A second way of making the child non-opaque. 2327 layer1->SetContentsOpaque(true); 2328 layer1->SetOpacity(1.f); 2329 layer1->SetExpectation(false, false); 2330 layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); 2331 layer2->SetContentsOpaque(false); 2332 layer2->SetOpacity(1.f); 2333 layer2->SetExpectation(true, false); 2334 layer2->set_update_rect(gfx::RectF(layer1->content_bounds())); 2335 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2336 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2337 EXPECT_TRUE(layer1->quads_appended()); 2338 EXPECT_TRUE(layer2->quads_appended()); 2339 host_impl_->DidDrawAllLayers(frame); 2340 2341 // And when the layer says its not opaque but is painted opaque, it is not 2342 // blended. 2343 layer1->SetContentsOpaque(true); 2344 layer1->SetOpacity(1.f); 2345 layer1->SetExpectation(false, false); 2346 layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); 2347 layer2->SetContentsOpaque(true); 2348 layer2->SetOpacity(1.f); 2349 layer2->SetExpectation(false, false); 2350 layer2->set_update_rect(gfx::RectF(layer1->content_bounds())); 2351 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2352 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2353 EXPECT_TRUE(layer1->quads_appended()); 2354 EXPECT_TRUE(layer2->quads_appended()); 2355 host_impl_->DidDrawAllLayers(frame); 2356 2357 // Layer with partially opaque contents, drawn with blending. 2358 layer1->SetContentsOpaque(false); 2359 layer1->SetQuadRect(gfx::Rect(5, 5, 5, 5)); 2360 layer1->SetQuadVisibleRect(gfx::Rect(5, 5, 5, 5)); 2361 layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5)); 2362 layer1->SetExpectation(true, false); 2363 layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); 2364 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2365 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2366 EXPECT_TRUE(layer1->quads_appended()); 2367 host_impl_->DidDrawAllLayers(frame); 2368 2369 // Layer with partially opaque contents partially culled, drawn with blending. 2370 layer1->SetContentsOpaque(false); 2371 layer1->SetQuadRect(gfx::Rect(5, 5, 5, 5)); 2372 layer1->SetQuadVisibleRect(gfx::Rect(5, 5, 5, 2)); 2373 layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5)); 2374 layer1->SetExpectation(true, false); 2375 layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); 2376 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2377 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2378 EXPECT_TRUE(layer1->quads_appended()); 2379 host_impl_->DidDrawAllLayers(frame); 2380 2381 // Layer with partially opaque contents culled, drawn with blending. 2382 layer1->SetContentsOpaque(false); 2383 layer1->SetQuadRect(gfx::Rect(5, 5, 5, 5)); 2384 layer1->SetQuadVisibleRect(gfx::Rect(7, 5, 3, 5)); 2385 layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5)); 2386 layer1->SetExpectation(true, false); 2387 layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); 2388 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2389 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2390 EXPECT_TRUE(layer1->quads_appended()); 2391 host_impl_->DidDrawAllLayers(frame); 2392 2393 // Layer with partially opaque contents and translucent contents culled, drawn 2394 // without blending. 2395 layer1->SetContentsOpaque(false); 2396 layer1->SetQuadRect(gfx::Rect(5, 5, 5, 5)); 2397 layer1->SetQuadVisibleRect(gfx::Rect(5, 5, 2, 5)); 2398 layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5)); 2399 layer1->SetExpectation(false, false); 2400 layer1->set_update_rect(gfx::RectF(layer1->content_bounds())); 2401 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2402 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2403 EXPECT_TRUE(layer1->quads_appended()); 2404 host_impl_->DidDrawAllLayers(frame); 2405} 2406 2407TEST_F(LayerTreeHostImplTest, ViewportCovered) { 2408 host_impl_->InitializeRenderer(CreateOutputSurface()); 2409 host_impl_->active_tree()->set_background_color(SK_ColorGRAY); 2410 2411 gfx::Size viewport_size(1000, 1000); 2412 host_impl_->SetViewportSize(viewport_size); 2413 2414 host_impl_->active_tree()->SetRootLayer( 2415 LayerImpl::Create(host_impl_->active_tree(), 1)); 2416 host_impl_->active_tree()->root_layer()->AddChild( 2417 BlendStateCheckLayer::Create(host_impl_->active_tree(), 2418 2, 2419 host_impl_->resource_provider())); 2420 BlendStateCheckLayer* child = static_cast<BlendStateCheckLayer*>( 2421 host_impl_->active_tree()->root_layer()->children()[0]); 2422 child->SetExpectation(false, false); 2423 child->SetContentsOpaque(true); 2424 2425 // No gutter rects 2426 { 2427 gfx::Rect layer_rect(0, 0, 1000, 1000); 2428 child->SetPosition(layer_rect.origin()); 2429 child->SetBounds(layer_rect.size()); 2430 child->SetContentBounds(layer_rect.size()); 2431 child->SetQuadRect(gfx::Rect(layer_rect.size())); 2432 child->SetQuadVisibleRect(gfx::Rect(layer_rect.size())); 2433 2434 LayerTreeHostImpl::FrameData frame; 2435 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2436 ASSERT_EQ(1u, frame.render_passes.size()); 2437 2438 size_t num_gutter_quads = 0; 2439 for (size_t i = 0; i < frame.render_passes[0]->quad_list.size(); ++i) 2440 num_gutter_quads += (frame.render_passes[0]->quad_list[i]->material == 2441 DrawQuad::SOLID_COLOR) ? 1 : 0; 2442 EXPECT_EQ(0u, num_gutter_quads); 2443 EXPECT_EQ(1u, frame.render_passes[0]->quad_list.size()); 2444 2445 LayerTestCommon::VerifyQuadsExactlyCoverRect( 2446 frame.render_passes[0]->quad_list, gfx::Rect(viewport_size)); 2447 host_impl_->DidDrawAllLayers(frame); 2448 } 2449 2450 // Empty visible content area (fullscreen gutter rect) 2451 { 2452 gfx::Rect layer_rect(0, 0, 0, 0); 2453 child->SetPosition(layer_rect.origin()); 2454 child->SetBounds(layer_rect.size()); 2455 child->SetContentBounds(layer_rect.size()); 2456 child->SetQuadRect(gfx::Rect(layer_rect.size())); 2457 child->SetQuadVisibleRect(gfx::Rect(layer_rect.size())); 2458 2459 LayerTreeHostImpl::FrameData frame; 2460 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2461 ASSERT_EQ(1u, frame.render_passes.size()); 2462 2463 size_t num_gutter_quads = 0; 2464 for (size_t i = 0; i < frame.render_passes[0]->quad_list.size(); ++i) 2465 num_gutter_quads += (frame.render_passes[0]->quad_list[i]->material == 2466 DrawQuad::SOLID_COLOR) ? 1 : 0; 2467 EXPECT_EQ(1u, num_gutter_quads); 2468 EXPECT_EQ(1u, frame.render_passes[0]->quad_list.size()); 2469 2470 LayerTestCommon::VerifyQuadsExactlyCoverRect( 2471 frame.render_passes[0]->quad_list, gfx::Rect(viewport_size)); 2472 host_impl_->DidDrawAllLayers(frame); 2473 } 2474 2475 // Content area in middle of clip rect (four surrounding gutter rects) 2476 { 2477 gfx::Rect layer_rect(500, 500, 200, 200); 2478 child->SetPosition(layer_rect.origin()); 2479 child->SetBounds(layer_rect.size()); 2480 child->SetContentBounds(layer_rect.size()); 2481 child->SetQuadRect(gfx::Rect(layer_rect.size())); 2482 child->SetQuadVisibleRect(gfx::Rect(layer_rect.size())); 2483 2484 LayerTreeHostImpl::FrameData frame; 2485 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2486 ASSERT_EQ(1u, frame.render_passes.size()); 2487 2488 size_t num_gutter_quads = 0; 2489 for (size_t i = 0; i < frame.render_passes[0]->quad_list.size(); ++i) 2490 num_gutter_quads += (frame.render_passes[0]->quad_list[i]->material == 2491 DrawQuad::SOLID_COLOR) ? 1 : 0; 2492 EXPECT_EQ(4u, num_gutter_quads); 2493 EXPECT_EQ(5u, frame.render_passes[0]->quad_list.size()); 2494 2495 LayerTestCommon::VerifyQuadsExactlyCoverRect( 2496 frame.render_passes[0]->quad_list, gfx::Rect(viewport_size)); 2497 host_impl_->DidDrawAllLayers(frame); 2498 } 2499} 2500 2501 2502class ReshapeTrackerContext: public TestWebGraphicsContext3D { 2503 public: 2504 ReshapeTrackerContext() : reshape_called_(false) {} 2505 2506 virtual void reshape(int width, int height) OVERRIDE { 2507 reshape_called_ = true; 2508 } 2509 2510 bool reshape_called() const { return reshape_called_; } 2511 2512 private: 2513 bool reshape_called_; 2514}; 2515 2516class FakeDrawableLayerImpl: public LayerImpl { 2517 public: 2518 static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, int id) { 2519 return scoped_ptr<LayerImpl>(new FakeDrawableLayerImpl(tree_impl, id)); 2520 } 2521 protected: 2522 FakeDrawableLayerImpl(LayerTreeImpl* tree_impl, int id) 2523 : LayerImpl(tree_impl, id) {} 2524}; 2525 2526// Only reshape when we know we are going to draw. Otherwise, the reshape 2527// can leave the window at the wrong size if we never draw and the proper 2528// viewport size is never set. 2529TEST_F(LayerTreeHostImplTest, ReshapeNotCalledUntilDraw) { 2530 scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d( 2531 scoped_ptr<WebKit::WebGraphicsContext3D>(new ReshapeTrackerContext)) 2532 .PassAs<OutputSurface>(); 2533 ReshapeTrackerContext* reshape_tracker = 2534 static_cast<ReshapeTrackerContext*>(output_surface->context3d()); 2535 host_impl_->InitializeRenderer(output_surface.Pass()); 2536 2537 scoped_ptr<LayerImpl> root = 2538 FakeDrawableLayerImpl::Create(host_impl_->active_tree(), 1); 2539 root->SetAnchorPoint(gfx::PointF()); 2540 root->SetBounds(gfx::Size(10, 10)); 2541 root->SetContentBounds(gfx::Size(10, 10)); 2542 root->SetDrawsContent(true); 2543 host_impl_->active_tree()->SetRootLayer(root.Pass()); 2544 EXPECT_FALSE(reshape_tracker->reshape_called()); 2545 2546 LayerTreeHostImpl::FrameData frame; 2547 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2548 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2549 EXPECT_TRUE(reshape_tracker->reshape_called()); 2550 host_impl_->DidDrawAllLayers(frame); 2551} 2552 2553class PartialSwapTrackerContext : public TestWebGraphicsContext3D { 2554 public: 2555 virtual void postSubBufferCHROMIUM(int x, int y, int width, int height) 2556 OVERRIDE { 2557 partial_swap_rect_ = gfx::Rect(x, y, width, height); 2558 } 2559 2560 virtual WebKit::WebString getString(WebKit::WGC3Denum name) OVERRIDE { 2561 if (name == GL_EXTENSIONS) { 2562 return WebKit::WebString( 2563 "GL_CHROMIUM_post_sub_buffer GL_CHROMIUM_set_visibility"); 2564 } 2565 2566 return WebKit::WebString(); 2567 } 2568 2569 gfx::Rect partial_swap_rect() const { return partial_swap_rect_; } 2570 2571 private: 2572 gfx::Rect partial_swap_rect_; 2573}; 2574 2575// Make sure damage tracking propagates all the way to the graphics context, 2576// where it should request to swap only the sub-buffer that is damaged. 2577TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) { 2578 scoped_ptr<OutputSurface> output_surface = 2579 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 2580 new PartialSwapTrackerContext)).PassAs<OutputSurface>(); 2581 PartialSwapTrackerContext* partial_swap_tracker = 2582 static_cast<PartialSwapTrackerContext*>(output_surface->context3d()); 2583 2584 // This test creates its own LayerTreeHostImpl, so 2585 // that we can force partial swap enabled. 2586 LayerTreeSettings settings; 2587 settings.partial_swap_enabled = true; 2588 scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl = 2589 LayerTreeHostImpl::Create(settings, 2590 this, 2591 &proxy_, 2592 &stats_instrumentation_); 2593 layer_tree_host_impl->InitializeRenderer(output_surface.Pass()); 2594 layer_tree_host_impl->SetViewportSize(gfx::Size(500, 500)); 2595 2596 scoped_ptr<LayerImpl> root = 2597 FakeDrawableLayerImpl::Create(layer_tree_host_impl->active_tree(), 1); 2598 scoped_ptr<LayerImpl> child = 2599 FakeDrawableLayerImpl::Create(layer_tree_host_impl->active_tree(), 2); 2600 child->SetPosition(gfx::PointF(12.f, 13.f)); 2601 child->SetAnchorPoint(gfx::PointF()); 2602 child->SetBounds(gfx::Size(14, 15)); 2603 child->SetContentBounds(gfx::Size(14, 15)); 2604 child->SetDrawsContent(true); 2605 root->SetAnchorPoint(gfx::PointF()); 2606 root->SetBounds(gfx::Size(500, 500)); 2607 root->SetContentBounds(gfx::Size(500, 500)); 2608 root->SetDrawsContent(true); 2609 root->AddChild(child.Pass()); 2610 layer_tree_host_impl->active_tree()->SetRootLayer(root.Pass()); 2611 2612 LayerTreeHostImpl::FrameData frame; 2613 2614 // First frame, the entire screen should get swapped. 2615 EXPECT_TRUE(layer_tree_host_impl->PrepareToDraw(&frame, gfx::Rect())); 2616 layer_tree_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 2617 layer_tree_host_impl->DidDrawAllLayers(frame); 2618 layer_tree_host_impl->SwapBuffers(frame); 2619 gfx::Rect actual_swap_rect = partial_swap_tracker->partial_swap_rect(); 2620 gfx::Rect expected_swap_rect = gfx::Rect(0, 0, 500, 500); 2621 EXPECT_EQ(expected_swap_rect.x(), actual_swap_rect.x()); 2622 EXPECT_EQ(expected_swap_rect.y(), actual_swap_rect.y()); 2623 EXPECT_EQ(expected_swap_rect.width(), actual_swap_rect.width()); 2624 EXPECT_EQ(expected_swap_rect.height(), actual_swap_rect.height()); 2625 2626 // Second frame, only the damaged area should get swapped. Damage should be 2627 // the union of old and new child rects. 2628 // expected damage rect: gfx::Rect(26, 28); 2629 // expected swap rect: vertically flipped, with origin at bottom left corner. 2630 layer_tree_host_impl->active_tree()->root_layer()->children()[0]->SetPosition( 2631 gfx::PointF()); 2632 EXPECT_TRUE(layer_tree_host_impl->PrepareToDraw(&frame, gfx::Rect())); 2633 layer_tree_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 2634 host_impl_->DidDrawAllLayers(frame); 2635 layer_tree_host_impl->SwapBuffers(frame); 2636 actual_swap_rect = partial_swap_tracker->partial_swap_rect(); 2637 expected_swap_rect = gfx::Rect(0, 500-28, 26, 28); 2638 EXPECT_EQ(expected_swap_rect.x(), actual_swap_rect.x()); 2639 EXPECT_EQ(expected_swap_rect.y(), actual_swap_rect.y()); 2640 EXPECT_EQ(expected_swap_rect.width(), actual_swap_rect.width()); 2641 EXPECT_EQ(expected_swap_rect.height(), actual_swap_rect.height()); 2642 2643 // Make sure that partial swap is constrained to the viewport dimensions 2644 // expected damage rect: gfx::Rect(500, 500); 2645 // expected swap rect: flipped damage rect, but also clamped to viewport 2646 layer_tree_host_impl->SetViewportSize(gfx::Size(10, 10)); 2647 // This will damage everything. 2648 layer_tree_host_impl->active_tree()->root_layer()->SetOpacity(0.7f); 2649 EXPECT_TRUE(layer_tree_host_impl->PrepareToDraw(&frame, gfx::Rect())); 2650 layer_tree_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 2651 host_impl_->DidDrawAllLayers(frame); 2652 layer_tree_host_impl->SwapBuffers(frame); 2653 actual_swap_rect = partial_swap_tracker->partial_swap_rect(); 2654 expected_swap_rect = gfx::Rect(10, 10); 2655 EXPECT_EQ(expected_swap_rect.x(), actual_swap_rect.x()); 2656 EXPECT_EQ(expected_swap_rect.y(), actual_swap_rect.y()); 2657 EXPECT_EQ(expected_swap_rect.width(), actual_swap_rect.width()); 2658 EXPECT_EQ(expected_swap_rect.height(), actual_swap_rect.height()); 2659} 2660 2661TEST_F(LayerTreeHostImplTest, RootLayerDoesntCreateExtraSurface) { 2662 scoped_ptr<LayerImpl> root = 2663 FakeDrawableLayerImpl::Create(host_impl_->active_tree(), 1); 2664 scoped_ptr<LayerImpl> child = 2665 FakeDrawableLayerImpl::Create(host_impl_->active_tree(), 2); 2666 child->SetAnchorPoint(gfx::PointF()); 2667 child->SetBounds(gfx::Size(10, 10)); 2668 child->SetContentBounds(gfx::Size(10, 10)); 2669 child->SetDrawsContent(true); 2670 root->SetAnchorPoint(gfx::PointF()); 2671 root->SetBounds(gfx::Size(10, 10)); 2672 root->SetContentBounds(gfx::Size(10, 10)); 2673 root->SetDrawsContent(true); 2674 root->SetOpacity(0.7f); 2675 root->AddChild(child.Pass()); 2676 2677 host_impl_->active_tree()->SetRootLayer(root.Pass()); 2678 2679 LayerTreeHostImpl::FrameData frame; 2680 2681 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2682 EXPECT_EQ(1u, frame.render_surface_layer_list->size()); 2683 EXPECT_EQ(1u, frame.render_passes.size()); 2684 host_impl_->DidDrawAllLayers(frame); 2685} 2686 2687class FakeLayerWithQuads : public LayerImpl { 2688 public: 2689 static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, int id) { 2690 return scoped_ptr<LayerImpl>(new FakeLayerWithQuads(tree_impl, id)); 2691 } 2692 2693 virtual void AppendQuads(QuadSink* quad_sink, 2694 AppendQuadsData* append_quads_data) OVERRIDE { 2695 SharedQuadState* shared_quad_state = 2696 quad_sink->UseSharedQuadState(CreateSharedQuadState()); 2697 2698 SkColor gray = SkColorSetRGB(100, 100, 100); 2699 gfx::Rect quad_rect(content_bounds()); 2700 scoped_ptr<SolidColorDrawQuad> my_quad = SolidColorDrawQuad::Create(); 2701 my_quad->SetNew(shared_quad_state, quad_rect, gray, false); 2702 quad_sink->Append(my_quad.PassAs<DrawQuad>(), append_quads_data); 2703 } 2704 2705 private: 2706 FakeLayerWithQuads(LayerTreeImpl* tree_impl, int id) 2707 : LayerImpl(tree_impl, id) {} 2708}; 2709 2710class MockContext : public TestWebGraphicsContext3D { 2711 public: 2712 MOCK_METHOD1(useProgram, void(WebKit::WebGLId program)); 2713 MOCK_METHOD5(uniform4f, void(WebKit::WGC3Dint location, 2714 WebKit::WGC3Dfloat x, 2715 WebKit::WGC3Dfloat y, 2716 WebKit::WGC3Dfloat z, 2717 WebKit::WGC3Dfloat w)); 2718 MOCK_METHOD4(uniformMatrix4fv, void(WebKit::WGC3Dint location, 2719 WebKit::WGC3Dsizei count, 2720 WebKit::WGC3Dboolean transpose, 2721 const WebKit::WGC3Dfloat* value)); 2722 MOCK_METHOD4(drawElements, void(WebKit::WGC3Denum mode, 2723 WebKit::WGC3Dsizei count, 2724 WebKit::WGC3Denum type, 2725 WebKit::WGC3Dintptr offset)); 2726 MOCK_METHOD1(getString, WebKit::WebString(WebKit::WGC3Denum name)); 2727 MOCK_METHOD0(getRequestableExtensionsCHROMIUM, WebKit::WebString()); 2728 MOCK_METHOD1(enable, void(WebKit::WGC3Denum cap)); 2729 MOCK_METHOD1(disable, void(WebKit::WGC3Denum cap)); 2730 MOCK_METHOD4(scissor, void(WebKit::WGC3Dint x, 2731 WebKit::WGC3Dint y, 2732 WebKit::WGC3Dsizei width, 2733 WebKit::WGC3Dsizei height)); 2734}; 2735 2736class MockContextHarness { 2737 private: 2738 MockContext* context_; 2739 2740 public: 2741 explicit MockContextHarness(MockContext* context) 2742 : context_(context) { 2743 // Catch "uninteresting" calls 2744 EXPECT_CALL(*context_, useProgram(_)) 2745 .Times(0); 2746 2747 EXPECT_CALL(*context_, drawElements(_, _, _, _)) 2748 .Times(0); 2749 2750 // These are not asserted 2751 EXPECT_CALL(*context_, uniformMatrix4fv(_, _, _, _)) 2752 .WillRepeatedly(Return()); 2753 2754 EXPECT_CALL(*context_, uniform4f(_, _, _, _, _)) 2755 .WillRepeatedly(Return()); 2756 2757 // Any other strings are empty 2758 EXPECT_CALL(*context_, getString(_)) 2759 .WillRepeatedly(Return(WebKit::WebString())); 2760 2761 // Support for partial swap, if needed 2762 EXPECT_CALL(*context_, getString(GL_EXTENSIONS)) 2763 .WillRepeatedly(Return( 2764 WebKit::WebString("GL_CHROMIUM_post_sub_buffer"))); 2765 2766 EXPECT_CALL(*context_, getRequestableExtensionsCHROMIUM()) 2767 .WillRepeatedly(Return( 2768 WebKit::WebString("GL_CHROMIUM_post_sub_buffer"))); 2769 2770 // Any un-sanctioned calls to enable() are OK 2771 EXPECT_CALL(*context_, enable(_)) 2772 .WillRepeatedly(Return()); 2773 2774 // Any un-sanctioned calls to disable() are OK 2775 EXPECT_CALL(*context_, disable(_)) 2776 .WillRepeatedly(Return()); 2777 } 2778 2779 void MustDrawSolidQuad() { 2780 EXPECT_CALL(*context_, drawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0)) 2781 .WillOnce(Return()) 2782 .RetiresOnSaturation(); 2783 2784 EXPECT_CALL(*context_, useProgram(_)) 2785 .WillOnce(Return()) 2786 .RetiresOnSaturation(); 2787 } 2788 2789 void MustSetScissor(int x, int y, int width, int height) { 2790 EXPECT_CALL(*context_, enable(GL_SCISSOR_TEST)) 2791 .WillRepeatedly(Return()); 2792 2793 EXPECT_CALL(*context_, scissor(x, y, width, height)) 2794 .Times(AtLeast(1)) 2795 .WillRepeatedly(Return()); 2796 } 2797 2798 void MustSetNoScissor() { 2799 EXPECT_CALL(*context_, disable(GL_SCISSOR_TEST)) 2800 .WillRepeatedly(Return()); 2801 2802 EXPECT_CALL(*context_, enable(GL_SCISSOR_TEST)) 2803 .Times(0); 2804 2805 EXPECT_CALL(*context_, scissor(_, _, _, _)) 2806 .Times(0); 2807 } 2808}; 2809 2810TEST_F(LayerTreeHostImplTest, NoPartialSwap) { 2811 scoped_ptr<OutputSurface> output_surface = 2812 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 2813 new MockContext)).PassAs<OutputSurface>(); 2814 MockContext* mock_context = 2815 static_cast<MockContext*>(output_surface->context3d()); 2816 MockContextHarness harness(mock_context); 2817 2818 // Run test case 2819 CreateLayerTreeHost(false, output_surface.Pass()); 2820 SetupRootLayerImpl(FakeLayerWithQuads::Create(host_impl_->active_tree(), 1)); 2821 2822 // Without partial swap, and no clipping, no scissor is set. 2823 harness.MustDrawSolidQuad(); 2824 harness.MustSetNoScissor(); 2825 { 2826 LayerTreeHostImpl::FrameData frame; 2827 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2828 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2829 host_impl_->DidDrawAllLayers(frame); 2830 } 2831 Mock::VerifyAndClearExpectations(&mock_context); 2832 2833 // Without partial swap, but a layer does clip its subtree, one scissor is 2834 // set. 2835 host_impl_->active_tree()->root_layer()->SetMasksToBounds(true); 2836 harness.MustDrawSolidQuad(); 2837 harness.MustSetScissor(0, 0, 10, 10); 2838 { 2839 LayerTreeHostImpl::FrameData frame; 2840 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2841 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2842 host_impl_->DidDrawAllLayers(frame); 2843 } 2844 Mock::VerifyAndClearExpectations(&mock_context); 2845} 2846 2847TEST_F(LayerTreeHostImplTest, PartialSwap) { 2848 scoped_ptr<OutputSurface> output_surface = 2849 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 2850 new MockContext)).PassAs<OutputSurface>(); 2851 MockContext* mock_context = 2852 static_cast<MockContext*>(output_surface->context3d()); 2853 MockContextHarness harness(mock_context); 2854 2855 CreateLayerTreeHost(true, output_surface.Pass()); 2856 SetupRootLayerImpl(FakeLayerWithQuads::Create(host_impl_->active_tree(), 1)); 2857 2858 // The first frame is not a partially-swapped one. 2859 harness.MustSetScissor(0, 0, 10, 10); 2860 harness.MustDrawSolidQuad(); 2861 { 2862 LayerTreeHostImpl::FrameData frame; 2863 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2864 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2865 host_impl_->DidDrawAllLayers(frame); 2866 } 2867 Mock::VerifyAndClearExpectations(&mock_context); 2868 2869 // Damage a portion of the frame. 2870 host_impl_->active_tree()->root_layer()->set_update_rect( 2871 gfx::Rect(0, 0, 2, 3)); 2872 2873 // The second frame will be partially-swapped (the y coordinates are flipped). 2874 harness.MustSetScissor(0, 7, 2, 3); 2875 harness.MustDrawSolidQuad(); 2876 { 2877 LayerTreeHostImpl::FrameData frame; 2878 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 2879 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 2880 host_impl_->DidDrawAllLayers(frame); 2881 } 2882 Mock::VerifyAndClearExpectations(&mock_context); 2883} 2884 2885class PartialSwapContext : public TestWebGraphicsContext3D { 2886 public: 2887 virtual WebKit::WebString getString(WebKit::WGC3Denum name) OVERRIDE { 2888 if (name == GL_EXTENSIONS) 2889 return WebKit::WebString("GL_CHROMIUM_post_sub_buffer"); 2890 return WebKit::WebString(); 2891 } 2892 2893 virtual WebKit::WebString getRequestableExtensionsCHROMIUM() OVERRIDE { 2894 return WebKit::WebString("GL_CHROMIUM_post_sub_buffer"); 2895 } 2896 2897 // Unlimited texture size. 2898 virtual void getIntegerv(WebKit::WGC3Denum pname, WebKit::WGC3Dint* value) 2899 OVERRIDE { 2900 if (pname == GL_MAX_TEXTURE_SIZE) 2901 *value = 8192; 2902 } 2903}; 2904 2905static scoped_ptr<LayerTreeHostImpl> SetupLayersForOpacity( 2906 bool partial_swap, 2907 LayerTreeHostImplClient* client, 2908 Proxy* proxy, 2909 RenderingStatsInstrumentation* stats_instrumentation) { 2910 scoped_ptr<OutputSurface> output_surface = 2911 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 2912 new PartialSwapContext)).PassAs<OutputSurface>(); 2913 2914 LayerTreeSettings settings; 2915 settings.partial_swap_enabled = partial_swap; 2916 scoped_ptr<LayerTreeHostImpl> my_host_impl = 2917 LayerTreeHostImpl::Create(settings, client, proxy, stats_instrumentation); 2918 my_host_impl->InitializeRenderer(output_surface.Pass()); 2919 my_host_impl->SetViewportSize(gfx::Size(100, 100)); 2920 2921 /* 2922 Layers are created as follows: 2923 2924 +--------------------+ 2925 | 1 | 2926 | +-----------+ | 2927 | | 2 | | 2928 | | +-------------------+ 2929 | | | 3 | 2930 | | +-------------------+ 2931 | | | | 2932 | +-----------+ | 2933 | | 2934 | | 2935 +--------------------+ 2936 2937 Layers 1, 2 have render surfaces 2938 */ 2939 scoped_ptr<LayerImpl> root = 2940 LayerImpl::Create(my_host_impl->active_tree(), 1); 2941 scoped_ptr<LayerImpl> child = 2942 LayerImpl::Create(my_host_impl->active_tree(), 2); 2943 scoped_ptr<LayerImpl> grand_child = 2944 FakeLayerWithQuads::Create(my_host_impl->active_tree(), 3); 2945 2946 gfx::Rect root_rect(0, 0, 100, 100); 2947 gfx::Rect child_rect(10, 10, 50, 50); 2948 gfx::Rect grand_child_rect(5, 5, 150, 150); 2949 2950 root->CreateRenderSurface(); 2951 root->SetAnchorPoint(gfx::PointF()); 2952 root->SetPosition(root_rect.origin()); 2953 root->SetBounds(root_rect.size()); 2954 root->SetContentBounds(root->bounds()); 2955 root->draw_properties().visible_content_rect = root_rect; 2956 root->SetDrawsContent(false); 2957 root->render_surface()->SetContentRect(gfx::Rect(root_rect.size())); 2958 2959 child->SetAnchorPoint(gfx::PointF()); 2960 child->SetPosition(gfx::PointF(child_rect.x(), child_rect.y())); 2961 child->SetOpacity(0.5f); 2962 child->SetBounds(gfx::Size(child_rect.width(), child_rect.height())); 2963 child->SetContentBounds(child->bounds()); 2964 child->draw_properties().visible_content_rect = child_rect; 2965 child->SetDrawsContent(false); 2966 child->SetForceRenderSurface(true); 2967 2968 grand_child->SetAnchorPoint(gfx::PointF()); 2969 grand_child->SetPosition(grand_child_rect.origin()); 2970 grand_child->SetBounds(grand_child_rect.size()); 2971 grand_child->SetContentBounds(grand_child->bounds()); 2972 grand_child->draw_properties().visible_content_rect = grand_child_rect; 2973 grand_child->SetDrawsContent(true); 2974 2975 child->AddChild(grand_child.Pass()); 2976 root->AddChild(child.Pass()); 2977 2978 my_host_impl->active_tree()->SetRootLayer(root.Pass()); 2979 return my_host_impl.Pass(); 2980} 2981 2982TEST_F(LayerTreeHostImplTest, ContributingLayerEmptyScissorPartialSwap) { 2983 scoped_ptr<LayerTreeHostImpl> my_host_impl = 2984 SetupLayersForOpacity(true, this, &proxy_, &stats_instrumentation_); 2985 { 2986 LayerTreeHostImpl::FrameData frame; 2987 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 2988 2989 // Verify all quads have been computed 2990 ASSERT_EQ(2U, frame.render_passes.size()); 2991 ASSERT_EQ(1U, frame.render_passes[0]->quad_list.size()); 2992 ASSERT_EQ(1U, frame.render_passes[1]->quad_list.size()); 2993 EXPECT_EQ(DrawQuad::SOLID_COLOR, 2994 frame.render_passes[0]->quad_list[0]->material); 2995 EXPECT_EQ(DrawQuad::RENDER_PASS, 2996 frame.render_passes[1]->quad_list[0]->material); 2997 2998 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 2999 my_host_impl->DidDrawAllLayers(frame); 3000 } 3001} 3002 3003TEST_F(LayerTreeHostImplTest, ContributingLayerEmptyScissorNoPartialSwap) { 3004 scoped_ptr<LayerTreeHostImpl> my_host_impl = 3005 SetupLayersForOpacity(false, this, &proxy_, &stats_instrumentation_); 3006 { 3007 LayerTreeHostImpl::FrameData frame; 3008 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3009 3010 // Verify all quads have been computed 3011 ASSERT_EQ(2U, frame.render_passes.size()); 3012 ASSERT_EQ(1U, frame.render_passes[0]->quad_list.size()); 3013 ASSERT_EQ(1U, frame.render_passes[1]->quad_list.size()); 3014 EXPECT_EQ(DrawQuad::SOLID_COLOR, 3015 frame.render_passes[0]->quad_list[0]->material); 3016 EXPECT_EQ(DrawQuad::RENDER_PASS, 3017 frame.render_passes[1]->quad_list[0]->material); 3018 3019 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3020 my_host_impl->DidDrawAllLayers(frame); 3021 } 3022} 3023 3024// Fake WebKit::WebGraphicsContext3D that tracks the number of textures in use. 3025class TrackingWebGraphicsContext3D : public TestWebGraphicsContext3D { 3026 public: 3027 TrackingWebGraphicsContext3D() 3028 : TestWebGraphicsContext3D(), 3029 num_textures_(0) {} 3030 3031 virtual WebKit::WebGLId createTexture() OVERRIDE { 3032 WebKit::WebGLId id = TestWebGraphicsContext3D::createTexture(); 3033 3034 textures_[id] = true; 3035 ++num_textures_; 3036 return id; 3037 } 3038 3039 virtual void deleteTexture(WebKit::WebGLId id) OVERRIDE { 3040 if (textures_.find(id) == textures_.end()) 3041 return; 3042 3043 textures_[id] = false; 3044 --num_textures_; 3045 } 3046 3047 virtual WebKit::WebString getString(WebKit::WGC3Denum name) OVERRIDE { 3048 if (name == GL_EXTENSIONS) { 3049 return WebKit::WebString( 3050 "GL_CHROMIUM_iosurface GL_ARB_texture_rectangle"); 3051 } 3052 3053 return WebKit::WebString(); 3054 } 3055 3056 unsigned num_textures() const { return num_textures_; } 3057 3058 private: 3059 base::hash_map<WebKit::WebGLId, bool> textures_; 3060 unsigned num_textures_; 3061}; 3062 3063TEST_F(LayerTreeHostImplTest, LayersFreeTextures) { 3064 scoped_ptr<TestWebGraphicsContext3D> context = 3065 TestWebGraphicsContext3D::Create(); 3066 TestWebGraphicsContext3D* context3d = context.get(); 3067 scoped_ptr<OutputSurface> output_surface = FakeOutputSurface::Create3d( 3068 context.PassAs<WebKit::WebGraphicsContext3D>()).PassAs<OutputSurface>(); 3069 host_impl_->InitializeRenderer(output_surface.Pass()); 3070 3071 scoped_ptr<LayerImpl> root_layer = 3072 LayerImpl::Create(host_impl_->active_tree(), 1); 3073 root_layer->SetBounds(gfx::Size(10, 10)); 3074 root_layer->SetAnchorPoint(gfx::PointF()); 3075 3076 scoped_refptr<VideoFrame> softwareFrame = 3077 media::VideoFrame::CreateColorFrame( 3078 gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta()); 3079 FakeVideoFrameProvider provider; 3080 provider.set_frame(softwareFrame); 3081 scoped_ptr<VideoLayerImpl> video_layer = 3082 VideoLayerImpl::Create(host_impl_->active_tree(), 4, &provider); 3083 video_layer->SetBounds(gfx::Size(10, 10)); 3084 video_layer->SetAnchorPoint(gfx::PointF()); 3085 video_layer->SetContentBounds(gfx::Size(10, 10)); 3086 video_layer->SetDrawsContent(true); 3087 root_layer->AddChild(video_layer.PassAs<LayerImpl>()); 3088 3089 scoped_ptr<IOSurfaceLayerImpl> io_surface_layer = 3090 IOSurfaceLayerImpl::Create(host_impl_->active_tree(), 5); 3091 io_surface_layer->SetBounds(gfx::Size(10, 10)); 3092 io_surface_layer->SetAnchorPoint(gfx::PointF()); 3093 io_surface_layer->SetContentBounds(gfx::Size(10, 10)); 3094 io_surface_layer->SetDrawsContent(true); 3095 io_surface_layer->SetIOSurfaceProperties(1, gfx::Size(10, 10)); 3096 root_layer->AddChild(io_surface_layer.PassAs<LayerImpl>()); 3097 3098 host_impl_->active_tree()->SetRootLayer(root_layer.Pass()); 3099 3100 EXPECT_EQ(0u, context3d->NumTextures()); 3101 3102 LayerTreeHostImpl::FrameData frame; 3103 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 3104 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 3105 host_impl_->DidDrawAllLayers(frame); 3106 host_impl_->SwapBuffers(frame); 3107 3108 EXPECT_GT(context3d->NumTextures(), 0u); 3109 3110 // Kill the layer tree. 3111 host_impl_->active_tree()->SetRootLayer( 3112 LayerImpl::Create(host_impl_->active_tree(), 100)); 3113 // There should be no textures left in use after. 3114 EXPECT_EQ(0u, context3d->NumTextures()); 3115} 3116 3117class MockDrawQuadsToFillScreenContext : public TestWebGraphicsContext3D { 3118 public: 3119 MOCK_METHOD1(useProgram, void(WebKit::WebGLId program)); 3120 MOCK_METHOD4(drawElements, void(WebKit::WGC3Denum mode, 3121 WebKit::WGC3Dsizei count, 3122 WebKit::WGC3Denum type, 3123 WebKit::WGC3Dintptr offset)); 3124}; 3125 3126TEST_F(LayerTreeHostImplTest, HasTransparentBackground) { 3127 scoped_ptr<OutputSurface> output_surface = 3128 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 3129 new MockDrawQuadsToFillScreenContext)).PassAs<OutputSurface>(); 3130 MockDrawQuadsToFillScreenContext* mock_context = 3131 static_cast<MockDrawQuadsToFillScreenContext*>( 3132 output_surface->context3d()); 3133 3134 // Run test case 3135 CreateLayerTreeHost(false, output_surface.Pass()); 3136 SetupRootLayerImpl(LayerImpl::Create(host_impl_->active_tree(), 1)); 3137 host_impl_->active_tree()->set_background_color(SK_ColorWHITE); 3138 3139 // Verify one quad is drawn when transparent background set is not set. 3140 host_impl_->active_tree()->set_has_transparent_background(false); 3141 EXPECT_CALL(*mock_context, useProgram(_)) 3142 .Times(1); 3143 EXPECT_CALL(*mock_context, drawElements(_, _, _, _)) 3144 .Times(1); 3145 LayerTreeHostImpl::FrameData frame; 3146 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 3147 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 3148 host_impl_->DidDrawAllLayers(frame); 3149 Mock::VerifyAndClearExpectations(&mock_context); 3150 3151 // Verify no quads are drawn when transparent background is set. 3152 host_impl_->active_tree()->set_has_transparent_background(true); 3153 host_impl_->SetFullRootLayerDamage(); 3154 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 3155 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 3156 host_impl_->DidDrawAllLayers(frame); 3157 Mock::VerifyAndClearExpectations(&mock_context); 3158} 3159 3160static void AddDrawingLayerTo(LayerImpl* parent, 3161 int id, 3162 gfx::Rect layer_rect, 3163 LayerImpl** result) { 3164 scoped_ptr<LayerImpl> layer = 3165 FakeLayerWithQuads::Create(parent->layer_tree_impl(), id); 3166 LayerImpl* layer_ptr = layer.get(); 3167 layer_ptr->SetAnchorPoint(gfx::PointF()); 3168 layer_ptr->SetPosition(gfx::PointF(layer_rect.origin())); 3169 layer_ptr->SetBounds(layer_rect.size()); 3170 layer_ptr->SetContentBounds(layer_rect.size()); 3171 layer_ptr->SetDrawsContent(true); // only children draw content 3172 layer_ptr->SetContentsOpaque(true); 3173 parent->AddChild(layer.Pass()); 3174 if (result) 3175 *result = layer_ptr; 3176} 3177 3178static void SetupLayersForTextureCaching( 3179 LayerTreeHostImpl* layer_tree_host_impl, 3180 LayerImpl*& root_ptr, 3181 LayerImpl*& intermediate_layer_ptr, 3182 LayerImpl*& surface_layer_ptr, 3183 LayerImpl*& child_ptr, 3184 gfx::Size root_size) { 3185 scoped_ptr<OutputSurface> output_surface = 3186 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 3187 new PartialSwapContext)).PassAs<OutputSurface>(); 3188 3189 layer_tree_host_impl->InitializeRenderer(output_surface.Pass()); 3190 layer_tree_host_impl->SetViewportSize(root_size); 3191 3192 scoped_ptr<LayerImpl> root = 3193 LayerImpl::Create(layer_tree_host_impl->active_tree(), 1); 3194 root_ptr = root.get(); 3195 3196 root->SetAnchorPoint(gfx::PointF()); 3197 root->SetPosition(gfx::PointF()); 3198 root->SetBounds(root_size); 3199 root->SetContentBounds(root_size); 3200 root->SetDrawsContent(true); 3201 layer_tree_host_impl->active_tree()->SetRootLayer(root.Pass()); 3202 3203 AddDrawingLayerTo(root_ptr, 3204 2, 3205 gfx::Rect(10, 10, root_size.width(), root_size.height()), 3206 &intermediate_layer_ptr); 3207 // Only children draw content. 3208 intermediate_layer_ptr->SetDrawsContent(false); 3209 3210 // Surface layer is the layer that changes its opacity 3211 // It will contain other layers that draw content. 3212 AddDrawingLayerTo(intermediate_layer_ptr, 3213 3, 3214 gfx::Rect(10, 10, root_size.width(), root_size.height()), 3215 &surface_layer_ptr); 3216 // Only children draw content. 3217 surface_layer_ptr->SetDrawsContent(false); 3218 surface_layer_ptr->SetOpacity(0.5f); 3219 surface_layer_ptr->SetForceRenderSurface(true); 3220 3221 // Child of the surface layer will produce some quads 3222 AddDrawingLayerTo(surface_layer_ptr, 3223 4, 3224 gfx::Rect(5, 3225 5, 3226 root_size.width() - 25, 3227 root_size.height() - 25), 3228 &child_ptr); 3229} 3230 3231class GLRendererWithReleaseTextures : public GLRenderer { 3232 public: 3233 using GLRenderer::ReleaseRenderPassTextures; 3234}; 3235 3236TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusion) { 3237 LayerTreeSettings settings; 3238 settings.minimum_occlusion_tracking_size = gfx::Size(); 3239 settings.cache_render_pass_contents = true; 3240 scoped_ptr<LayerTreeHostImpl> my_host_impl = 3241 LayerTreeHostImpl::Create(settings, 3242 this, 3243 &proxy_, 3244 &stats_instrumentation_); 3245 3246 // Layers are structure as follows: 3247 // 3248 // R +-- S1 +- L10 (owning) 3249 // | +- L11 3250 // | +- L12 3251 // | 3252 // +-- S2 +- L20 (owning) 3253 // +- L21 3254 // 3255 // Occlusion: 3256 // L12 occludes L11 (internal) 3257 // L20 occludes L10 (external) 3258 // L21 occludes L20 (internal) 3259 3260 LayerImpl* root_ptr; 3261 LayerImpl* layer_s1_ptr; 3262 LayerImpl* layer_s2_ptr; 3263 3264 scoped_ptr<OutputSurface> output_surface = 3265 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 3266 new PartialSwapContext)).PassAs<OutputSurface>(); 3267 3268 gfx::Size root_size(1000, 1000); 3269 3270 my_host_impl->InitializeRenderer(output_surface.Pass()); 3271 my_host_impl->SetViewportSize(root_size); 3272 3273 scoped_ptr<LayerImpl> root = 3274 LayerImpl::Create(my_host_impl->active_tree(), 1); 3275 root_ptr = root.get(); 3276 3277 root->SetAnchorPoint(gfx::PointF()); 3278 root->SetPosition(gfx::PointF()); 3279 root->SetBounds(root_size); 3280 root->SetContentBounds(root_size); 3281 root->SetDrawsContent(true); 3282 root->SetMasksToBounds(true); 3283 my_host_impl->active_tree()->SetRootLayer(root.Pass()); 3284 3285 AddDrawingLayerTo(root_ptr, 2, gfx::Rect(300, 300, 300, 300), &layer_s1_ptr); 3286 layer_s1_ptr->SetForceRenderSurface(true); 3287 3288 AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(10, 10, 10, 10), 0); // L11 3289 AddDrawingLayerTo(layer_s1_ptr, 4, gfx::Rect(0, 0, 30, 30), 0); // L12 3290 3291 AddDrawingLayerTo(root_ptr, 5, gfx::Rect(550, 250, 300, 400), &layer_s2_ptr); 3292 layer_s2_ptr->SetForceRenderSurface(true); 3293 3294 AddDrawingLayerTo(layer_s2_ptr, 6, gfx::Rect(20, 20, 5, 5), 0); // L21 3295 3296 // Initial draw - must receive all quads 3297 { 3298 LayerTreeHostImpl::FrameData frame; 3299 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3300 3301 // Must receive 3 render passes. 3302 // For Root, there are 2 quads; for S1, there are 2 quads (1 is occluded); 3303 // for S2, there is 2 quads. 3304 ASSERT_EQ(3U, frame.render_passes.size()); 3305 3306 EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size()); 3307 EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size()); 3308 EXPECT_EQ(2U, frame.render_passes[2]->quad_list.size()); 3309 3310 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3311 my_host_impl->DidDrawAllLayers(frame); 3312 } 3313 3314 // "Unocclude" surface S1 and repeat draw. 3315 // Must remove S2's render pass since it's cached; 3316 // Must keep S1 quads because texture contained external occlusion. 3317 gfx::Transform transform = layer_s2_ptr->transform(); 3318 transform.Translate(150.0, 150.0); 3319 layer_s2_ptr->SetTransform(transform); 3320 { 3321 LayerTreeHostImpl::FrameData frame; 3322 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3323 3324 // Must receive 2 render passes. 3325 // For Root, there are 2 quads 3326 // For S1, the number of quads depends on what got unoccluded, so not 3327 // asserted beyond being positive. 3328 // For S2, there is no render pass 3329 ASSERT_EQ(2U, frame.render_passes.size()); 3330 3331 EXPECT_GT(frame.render_passes[0]->quad_list.size(), 0U); 3332 EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size()); 3333 3334 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3335 my_host_impl->DidDrawAllLayers(frame); 3336 } 3337 3338 // "Re-occlude" surface S1 and repeat draw. 3339 // Must remove S1's render pass since it is now available in full. 3340 // S2 has no change so must also be removed. 3341 transform = layer_s2_ptr->transform(); 3342 transform.Translate(-15.0, -15.0); 3343 layer_s2_ptr->SetTransform(transform); 3344 { 3345 LayerTreeHostImpl::FrameData frame; 3346 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3347 3348 // Must receive 1 render pass - for the root. 3349 ASSERT_EQ(1U, frame.render_passes.size()); 3350 3351 EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size()); 3352 3353 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3354 my_host_impl->DidDrawAllLayers(frame); 3355 } 3356} 3357 3358TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusionEarlyOut) { 3359 LayerTreeSettings settings; 3360 settings.minimum_occlusion_tracking_size = gfx::Size(); 3361 settings.cache_render_pass_contents = true; 3362 scoped_ptr<LayerTreeHostImpl> my_host_impl = 3363 LayerTreeHostImpl::Create(settings, 3364 this, 3365 &proxy_, 3366 &stats_instrumentation_); 3367 3368 // Layers are structure as follows: 3369 // 3370 // R +-- S1 +- L10 (owning, non drawing) 3371 // | +- L11 (corner, unoccluded) 3372 // | +- L12 (corner, unoccluded) 3373 // | +- L13 (corner, unoccluded) 3374 // | +- L14 (corner, entirely occluded) 3375 // | 3376 // +-- S2 +- L20 (owning, drawing) 3377 // 3378 3379 LayerImpl* root_ptr; 3380 LayerImpl* layer_s1_ptr; 3381 LayerImpl* layer_s2_ptr; 3382 3383 scoped_ptr<OutputSurface> output_surface = 3384 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 3385 new PartialSwapContext)).PassAs<OutputSurface>(); 3386 3387 gfx::Size root_size(1000, 1000); 3388 3389 my_host_impl->InitializeRenderer(output_surface.Pass()); 3390 my_host_impl->SetViewportSize(root_size); 3391 3392 scoped_ptr<LayerImpl> root = 3393 LayerImpl::Create(my_host_impl->active_tree(), 1); 3394 root_ptr = root.get(); 3395 3396 root->SetAnchorPoint(gfx::PointF()); 3397 root->SetPosition(gfx::PointF()); 3398 root->SetBounds(root_size); 3399 root->SetContentBounds(root_size); 3400 root->SetDrawsContent(true); 3401 root->SetMasksToBounds(true); 3402 my_host_impl->active_tree()->SetRootLayer(root.Pass()); 3403 3404 AddDrawingLayerTo(root_ptr, 2, gfx::Rect(0, 0, 800, 800), &layer_s1_ptr); 3405 layer_s1_ptr->SetForceRenderSurface(true); 3406 layer_s1_ptr->SetDrawsContent(false); 3407 3408 AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(0, 0, 300, 300), 0); // L11 3409 AddDrawingLayerTo(layer_s1_ptr, 4, gfx::Rect(0, 500, 300, 300), 0); // L12 3410 AddDrawingLayerTo(layer_s1_ptr, 5, gfx::Rect(500, 0, 300, 300), 0); // L13 3411 AddDrawingLayerTo(layer_s1_ptr, 6, gfx::Rect(500, 500, 300, 300), 0); // L14 3412 AddDrawingLayerTo(layer_s1_ptr, 9, gfx::Rect(500, 500, 300, 300), 0); // L14 3413 3414 AddDrawingLayerTo(root_ptr, 7, gfx::Rect(450, 450, 450, 450), &layer_s2_ptr); 3415 layer_s2_ptr->SetForceRenderSurface(true); 3416 3417 // Initial draw - must receive all quads 3418 { 3419 LayerTreeHostImpl::FrameData frame; 3420 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3421 3422 // Must receive 3 render passes. 3423 // For Root, there are 2 quads; for S1, there are 3 quads; for S2, there is 3424 // 1 quad. 3425 ASSERT_EQ(3U, frame.render_passes.size()); 3426 3427 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); 3428 3429 // L14 is culled, so only 3 quads. 3430 EXPECT_EQ(3U, frame.render_passes[1]->quad_list.size()); 3431 EXPECT_EQ(2U, frame.render_passes[2]->quad_list.size()); 3432 3433 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3434 my_host_impl->DidDrawAllLayers(frame); 3435 } 3436 3437 // "Unocclude" surface S1 and repeat draw. 3438 // Must remove S2's render pass since it's cached; 3439 // Must keep S1 quads because texture contained external occlusion. 3440 gfx::Transform transform = layer_s2_ptr->transform(); 3441 transform.Translate(100.0, 100.0); 3442 layer_s2_ptr->SetTransform(transform); 3443 { 3444 LayerTreeHostImpl::FrameData frame; 3445 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3446 3447 // Must receive 2 render passes. 3448 // For Root, there are 2 quads 3449 // For S1, the number of quads depends on what got unoccluded, so not 3450 // asserted beyond being positive. 3451 // For S2, there is no render pass 3452 ASSERT_EQ(2U, frame.render_passes.size()); 3453 3454 EXPECT_GT(frame.render_passes[0]->quad_list.size(), 0U); 3455 EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size()); 3456 3457 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3458 my_host_impl->DidDrawAllLayers(frame); 3459 } 3460 3461 // "Re-occlude" surface S1 and repeat draw. 3462 // Must remove S1's render pass since it is now available in full. 3463 // S2 has no change so must also be removed. 3464 transform = layer_s2_ptr->transform(); 3465 transform.Translate(-15.0, -15.0); 3466 layer_s2_ptr->SetTransform(transform); 3467 { 3468 LayerTreeHostImpl::FrameData frame; 3469 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3470 3471 // Must receive 1 render pass - for the root. 3472 ASSERT_EQ(1U, frame.render_passes.size()); 3473 3474 EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size()); 3475 3476 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3477 my_host_impl->DidDrawAllLayers(frame); 3478 } 3479} 3480 3481TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusionExternalOverInternal) { 3482 LayerTreeSettings settings; 3483 settings.minimum_occlusion_tracking_size = gfx::Size(); 3484 settings.cache_render_pass_contents = true; 3485 scoped_ptr<LayerTreeHostImpl> my_host_impl = 3486 LayerTreeHostImpl::Create(settings, 3487 this, 3488 &proxy_, 3489 &stats_instrumentation_); 3490 3491 // Layers are structured as follows: 3492 // 3493 // R +-- S1 +- L10 (owning, drawing) 3494 // | +- L11 (corner, occluded by L12) 3495 // | +- L12 (opposite corner) 3496 // | 3497 // +-- S2 +- L20 (owning, drawing) 3498 // 3499 3500 LayerImpl* root_ptr; 3501 LayerImpl* layer_s1_ptr; 3502 LayerImpl* layer_s2_ptr; 3503 3504 scoped_ptr<OutputSurface> output_surface = 3505 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 3506 new PartialSwapContext)).PassAs<OutputSurface>(); 3507 3508 gfx::Size root_size(1000, 1000); 3509 3510 my_host_impl->InitializeRenderer(output_surface.Pass()); 3511 my_host_impl->SetViewportSize(root_size); 3512 3513 scoped_ptr<LayerImpl> root = 3514 LayerImpl::Create(my_host_impl->active_tree(), 1); 3515 root_ptr = root.get(); 3516 3517 root->SetAnchorPoint(gfx::PointF()); 3518 root->SetPosition(gfx::PointF()); 3519 root->SetBounds(root_size); 3520 root->SetContentBounds(root_size); 3521 root->SetDrawsContent(true); 3522 root->SetMasksToBounds(true); 3523 my_host_impl->active_tree()->SetRootLayer(root.Pass()); 3524 3525 AddDrawingLayerTo(root_ptr, 2, gfx::Rect(0, 0, 400, 400), &layer_s1_ptr); 3526 layer_s1_ptr->SetForceRenderSurface(true); 3527 3528 AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(0, 0, 300, 300), 0); // L11 3529 AddDrawingLayerTo(layer_s1_ptr, 4, gfx::Rect(100, 0, 300, 300), 0); // L12 3530 3531 AddDrawingLayerTo(root_ptr, 7, gfx::Rect(200, 0, 300, 300), &layer_s2_ptr); 3532 layer_s2_ptr->SetForceRenderSurface(true); 3533 3534 // Initial draw - must receive all quads 3535 { 3536 LayerTreeHostImpl::FrameData frame; 3537 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3538 3539 // Must receive 3 render passes. 3540 // For Root, there are 2 quads; for S1, there are 3 quads; for S2, there is 3541 // 1 quad. 3542 ASSERT_EQ(3U, frame.render_passes.size()); 3543 3544 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); 3545 EXPECT_EQ(3U, frame.render_passes[1]->quad_list.size()); 3546 EXPECT_EQ(2U, frame.render_passes[2]->quad_list.size()); 3547 3548 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3549 my_host_impl->DidDrawAllLayers(frame); 3550 } 3551 3552 // "Unocclude" surface S1 and repeat draw. 3553 // Must remove S2's render pass since it's cached; 3554 // Must keep S1 quads because texture contained external occlusion. 3555 gfx::Transform transform = layer_s2_ptr->transform(); 3556 transform.Translate(300.0, 0.0); 3557 layer_s2_ptr->SetTransform(transform); 3558 { 3559 LayerTreeHostImpl::FrameData frame; 3560 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3561 3562 // Must receive 2 render passes. 3563 // For Root, there are 2 quads 3564 // For S1, the number of quads depends on what got unoccluded, so not 3565 // asserted beyond being positive. 3566 // For S2, there is no render pass 3567 ASSERT_EQ(2U, frame.render_passes.size()); 3568 3569 EXPECT_GT(frame.render_passes[0]->quad_list.size(), 0U); 3570 EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size()); 3571 3572 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3573 my_host_impl->DidDrawAllLayers(frame); 3574 } 3575} 3576 3577TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusionExternalNotAligned) { 3578 LayerTreeSettings settings; 3579 settings.cache_render_pass_contents = true; 3580 scoped_ptr<LayerTreeHostImpl> my_host_impl = 3581 LayerTreeHostImpl::Create(settings, 3582 this, 3583 &proxy_, 3584 &stats_instrumentation_); 3585 3586 // Layers are structured as follows: 3587 // 3588 // R +-- S1 +- L10 (rotated, drawing) 3589 // +- L11 (occupies half surface) 3590 3591 LayerImpl* root_ptr; 3592 LayerImpl* layer_s1_ptr; 3593 3594 scoped_ptr<OutputSurface> output_surface = 3595 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 3596 new PartialSwapContext)).PassAs<OutputSurface>(); 3597 3598 gfx::Size root_size(1000, 1000); 3599 3600 my_host_impl->InitializeRenderer(output_surface.Pass()); 3601 my_host_impl->SetViewportSize(root_size); 3602 3603 scoped_ptr<LayerImpl> root = 3604 LayerImpl::Create(my_host_impl->active_tree(), 1); 3605 root_ptr = root.get(); 3606 3607 root->SetAnchorPoint(gfx::PointF()); 3608 root->SetPosition(gfx::PointF()); 3609 root->SetBounds(root_size); 3610 root->SetContentBounds(root_size); 3611 root->SetDrawsContent(true); 3612 root->SetMasksToBounds(true); 3613 my_host_impl->active_tree()->SetRootLayer(root.Pass()); 3614 3615 AddDrawingLayerTo(root_ptr, 2, gfx::Rect(0, 0, 400, 400), &layer_s1_ptr); 3616 layer_s1_ptr->SetForceRenderSurface(true); 3617 gfx::Transform transform = layer_s1_ptr->transform(); 3618 transform.Translate(200.0, 200.0); 3619 transform.Rotate(45.0); 3620 transform.Translate(-200.0, -200.0); 3621 layer_s1_ptr->SetTransform(transform); 3622 3623 AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(200, 0, 200, 400), 0); // L11 3624 3625 // Initial draw - must receive all quads 3626 { 3627 LayerTreeHostImpl::FrameData frame; 3628 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3629 3630 // Must receive 2 render passes. 3631 ASSERT_EQ(2U, frame.render_passes.size()); 3632 3633 EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size()); 3634 EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size()); 3635 3636 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3637 my_host_impl->DidDrawAllLayers(frame); 3638 } 3639 3640 // Change opacity and draw. Verify we used cached texture. 3641 layer_s1_ptr->SetOpacity(0.2f); 3642 { 3643 LayerTreeHostImpl::FrameData frame; 3644 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3645 3646 // One render pass must be gone due to cached texture. 3647 ASSERT_EQ(1U, frame.render_passes.size()); 3648 3649 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); 3650 3651 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3652 my_host_impl->DidDrawAllLayers(frame); 3653 } 3654} 3655 3656TEST_F(LayerTreeHostImplTest, TextureCachingWithOcclusionPartialSwap) { 3657 LayerTreeSettings settings; 3658 settings.minimum_occlusion_tracking_size = gfx::Size(); 3659 settings.partial_swap_enabled = true; 3660 settings.cache_render_pass_contents = true; 3661 scoped_ptr<LayerTreeHostImpl> my_host_impl = 3662 LayerTreeHostImpl::Create(settings, 3663 this, 3664 &proxy_, 3665 &stats_instrumentation_); 3666 3667 // Layers are structure as follows: 3668 // 3669 // R +-- S1 +- L10 (owning) 3670 // | +- L11 3671 // | +- L12 3672 // | 3673 // +-- S2 +- L20 (owning) 3674 // +- L21 3675 // 3676 // Occlusion: 3677 // L12 occludes L11 (internal) 3678 // L20 occludes L10 (external) 3679 // L21 occludes L20 (internal) 3680 3681 LayerImpl* root_ptr; 3682 LayerImpl* layer_s1_ptr; 3683 LayerImpl* layer_s2_ptr; 3684 3685 scoped_ptr<OutputSurface> output_surface = 3686 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 3687 new PartialSwapContext)).PassAs<OutputSurface>(); 3688 3689 gfx::Size root_size(1000, 1000); 3690 3691 my_host_impl->InitializeRenderer(output_surface.Pass()); 3692 my_host_impl->SetViewportSize(root_size); 3693 3694 scoped_ptr<LayerImpl> root = 3695 LayerImpl::Create(my_host_impl->active_tree(), 1); 3696 root_ptr = root.get(); 3697 3698 root->SetAnchorPoint(gfx::PointF()); 3699 root->SetPosition(gfx::PointF()); 3700 root->SetBounds(root_size); 3701 root->SetContentBounds(root_size); 3702 root->SetDrawsContent(true); 3703 root->SetMasksToBounds(true); 3704 my_host_impl->active_tree()->SetRootLayer(root.Pass()); 3705 3706 AddDrawingLayerTo(root_ptr, 2, gfx::Rect(300, 300, 300, 300), &layer_s1_ptr); 3707 layer_s1_ptr->SetForceRenderSurface(true); 3708 3709 AddDrawingLayerTo(layer_s1_ptr, 3, gfx::Rect(10, 10, 10, 10), 0); // L11 3710 AddDrawingLayerTo(layer_s1_ptr, 4, gfx::Rect(0, 0, 30, 30), 0); // L12 3711 3712 AddDrawingLayerTo(root_ptr, 5, gfx::Rect(550, 250, 300, 400), &layer_s2_ptr); 3713 layer_s2_ptr->SetForceRenderSurface(true); 3714 3715 AddDrawingLayerTo(layer_s2_ptr, 6, gfx::Rect(20, 20, 5, 5), 0); // L21 3716 3717 // Initial draw - must receive all quads 3718 { 3719 LayerTreeHostImpl::FrameData frame; 3720 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3721 3722 // Must receive 3 render passes. 3723 // For Root, there are 2 quads; for S1, there are 2 quads (one is occluded); 3724 // for S2, there is 2 quads. 3725 ASSERT_EQ(3U, frame.render_passes.size()); 3726 3727 EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size()); 3728 EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size()); 3729 EXPECT_EQ(2U, frame.render_passes[2]->quad_list.size()); 3730 3731 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3732 my_host_impl->DidDrawAllLayers(frame); 3733 } 3734 3735 // "Unocclude" surface S1 and repeat draw. 3736 // Must remove S2's render pass since it's cached; 3737 // Must keep S1 quads because texture contained external occlusion. 3738 gfx::Transform transform = layer_s2_ptr->transform(); 3739 transform.Translate(150.0, 150.0); 3740 layer_s2_ptr->SetTransform(transform); 3741 { 3742 LayerTreeHostImpl::FrameData frame; 3743 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3744 3745 // Must receive 2 render passes. 3746 // For Root, there are 2 quads. 3747 // For S1, there are 2 quads. 3748 // For S2, there is no render pass 3749 ASSERT_EQ(2U, frame.render_passes.size()); 3750 3751 EXPECT_EQ(2U, frame.render_passes[0]->quad_list.size()); 3752 EXPECT_EQ(2U, frame.render_passes[1]->quad_list.size()); 3753 3754 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3755 my_host_impl->DidDrawAllLayers(frame); 3756 } 3757 3758 // "Re-occlude" surface S1 and repeat draw. 3759 // Must remove S1's render pass since it is now available in full. 3760 // S2 has no change so must also be removed. 3761 transform = layer_s2_ptr->transform(); 3762 transform.Translate(-15.0, -15.0); 3763 layer_s2_ptr->SetTransform(transform); 3764 { 3765 LayerTreeHostImpl::FrameData frame; 3766 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3767 3768 // Root render pass only. 3769 ASSERT_EQ(1U, frame.render_passes.size()); 3770 3771 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3772 my_host_impl->DidDrawAllLayers(frame); 3773 } 3774} 3775 3776TEST_F(LayerTreeHostImplTest, TextureCachingWithScissor) { 3777 LayerTreeSettings settings; 3778 settings.minimum_occlusion_tracking_size = gfx::Size(); 3779 settings.cache_render_pass_contents = true; 3780 scoped_ptr<LayerTreeHostImpl> my_host_impl = 3781 LayerTreeHostImpl::Create(settings, 3782 this, 3783 &proxy_, 3784 &stats_instrumentation_); 3785 3786 /* 3787 Layers are created as follows: 3788 3789 +--------------------+ 3790 | 1 | 3791 | +-----------+ | 3792 | | 2 | | 3793 | | +-------------------+ 3794 | | | 3 | 3795 | | +-------------------+ 3796 | | | | 3797 | +-----------+ | 3798 | | 3799 | | 3800 +--------------------+ 3801 3802 Layers 1, 2 have render surfaces 3803 */ 3804 scoped_ptr<LayerImpl> root = 3805 LayerImpl::Create(my_host_impl->active_tree(), 1); 3806 scoped_ptr<TiledLayerImpl> child = 3807 TiledLayerImpl::Create(my_host_impl->active_tree(), 2); 3808 scoped_ptr<LayerImpl> grand_child = 3809 LayerImpl::Create(my_host_impl->active_tree(), 3); 3810 3811 gfx::Rect root_rect(0, 0, 100, 100); 3812 gfx::Rect child_rect(10, 10, 50, 50); 3813 gfx::Rect grand_child_rect(5, 5, 150, 150); 3814 3815 scoped_ptr<OutputSurface> output_surface = 3816 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 3817 new PartialSwapContext)).PassAs<OutputSurface>(); 3818 my_host_impl->InitializeRenderer(output_surface.Pass()); 3819 3820 root->SetAnchorPoint(gfx::PointF()); 3821 root->SetPosition(gfx::PointF(root_rect.x(), root_rect.y())); 3822 root->SetBounds(gfx::Size(root_rect.width(), root_rect.height())); 3823 root->SetContentBounds(root->bounds()); 3824 root->SetDrawsContent(true); 3825 root->SetMasksToBounds(true); 3826 3827 child->SetAnchorPoint(gfx::PointF()); 3828 child->SetPosition(gfx::PointF(child_rect.x(), child_rect.y())); 3829 child->SetOpacity(0.5f); 3830 child->SetBounds(gfx::Size(child_rect.width(), child_rect.height())); 3831 child->SetContentBounds(child->bounds()); 3832 child->SetDrawsContent(true); 3833 child->set_skips_draw(false); 3834 3835 // child layer has 10x10 tiles. 3836 scoped_ptr<LayerTilingData> tiler = 3837 LayerTilingData::Create(gfx::Size(10, 10), 3838 LayerTilingData::HAS_BORDER_TEXELS); 3839 tiler->SetBounds(child->content_bounds()); 3840 child->SetTilingData(*tiler.get()); 3841 3842 grand_child->SetAnchorPoint(gfx::PointF()); 3843 grand_child->SetPosition(grand_child_rect.origin()); 3844 grand_child->SetBounds(grand_child_rect.size()); 3845 grand_child->SetContentBounds(grand_child->bounds()); 3846 grand_child->SetDrawsContent(true); 3847 3848 TiledLayerImpl* child_ptr = child.get(); 3849 RenderPass::Id child_pass_id(child_ptr->id(), 0); 3850 3851 child->AddChild(grand_child.Pass()); 3852 root->AddChild(child.PassAs<LayerImpl>()); 3853 my_host_impl->active_tree()->SetRootLayer(root.Pass()); 3854 my_host_impl->SetViewportSize(root_rect.size()); 3855 3856 EXPECT_FALSE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId( 3857 child_pass_id)); 3858 { 3859 LayerTreeHostImpl::FrameData frame; 3860 host_impl_->SetFullRootLayerDamage(); 3861 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3862 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3863 my_host_impl->DidDrawAllLayers(frame); 3864 } 3865 3866 // We should have cached textures for surface 2. 3867 EXPECT_TRUE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId( 3868 child_pass_id)); 3869 { 3870 LayerTreeHostImpl::FrameData frame; 3871 host_impl_->SetFullRootLayerDamage(); 3872 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3873 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3874 my_host_impl->DidDrawAllLayers(frame); 3875 } 3876 3877 // We should still have cached textures for surface 2 after drawing with no 3878 // damage. 3879 EXPECT_TRUE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId( 3880 child_pass_id)); 3881 3882 // Damage a single tile of surface 2. 3883 child_ptr->set_update_rect(gfx::Rect(10, 10, 10, 10)); 3884 { 3885 LayerTreeHostImpl::FrameData frame; 3886 host_impl_->SetFullRootLayerDamage(); 3887 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3888 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3889 my_host_impl->DidDrawAllLayers(frame); 3890 } 3891 3892 // We should have a cached texture for surface 2 again even though it was 3893 // damaged. 3894 EXPECT_TRUE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId( 3895 child_pass_id)); 3896} 3897 3898TEST_F(LayerTreeHostImplTest, SurfaceTextureCaching) { 3899 LayerTreeSettings settings; 3900 settings.minimum_occlusion_tracking_size = gfx::Size(); 3901 settings.partial_swap_enabled = true; 3902 settings.cache_render_pass_contents = true; 3903 scoped_ptr<LayerTreeHostImpl> my_host_impl = 3904 LayerTreeHostImpl::Create(settings, 3905 this, 3906 &proxy_, 3907 &stats_instrumentation_); 3908 3909 LayerImpl* root_ptr; 3910 LayerImpl* intermediate_layer_ptr; 3911 LayerImpl* surface_layer_ptr; 3912 LayerImpl* child_ptr; 3913 3914 SetupLayersForTextureCaching(my_host_impl.get(), 3915 root_ptr, 3916 intermediate_layer_ptr, 3917 surface_layer_ptr, 3918 child_ptr, 3919 gfx::Size(100, 100)); 3920 { 3921 LayerTreeHostImpl::FrameData frame; 3922 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3923 3924 // Must receive two render passes, each with one quad 3925 ASSERT_EQ(2U, frame.render_passes.size()); 3926 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); 3927 EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size()); 3928 3929 EXPECT_EQ(DrawQuad::RENDER_PASS, 3930 frame.render_passes[1]->quad_list[0]->material); 3931 const RenderPassDrawQuad* quad = 3932 RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]); 3933 RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id]; 3934 ASSERT_TRUE(target_pass); 3935 EXPECT_FALSE(target_pass->damage_rect.IsEmpty()); 3936 3937 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3938 my_host_impl->DidDrawAllLayers(frame); 3939 } 3940 3941 // Draw without any change 3942 { 3943 LayerTreeHostImpl::FrameData frame; 3944 my_host_impl->SetFullRootLayerDamage(); 3945 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3946 3947 // Must receive one render pass, as the other one should be culled 3948 ASSERT_EQ(1U, frame.render_passes.size()); 3949 3950 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); 3951 EXPECT_EQ(DrawQuad::RENDER_PASS, 3952 frame.render_passes[0]->quad_list[0]->material); 3953 const RenderPassDrawQuad* quad = 3954 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); 3955 EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) == 3956 frame.render_passes_by_id.end()); 3957 3958 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3959 my_host_impl->DidDrawAllLayers(frame); 3960 } 3961 3962 // Change opacity and draw 3963 surface_layer_ptr->SetOpacity(0.6f); 3964 { 3965 LayerTreeHostImpl::FrameData frame; 3966 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3967 3968 // Must receive one render pass, as the other one should be culled 3969 ASSERT_EQ(1U, frame.render_passes.size()); 3970 3971 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); 3972 EXPECT_EQ(DrawQuad::RENDER_PASS, 3973 frame.render_passes[0]->quad_list[0]->material); 3974 const RenderPassDrawQuad* quad = 3975 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); 3976 EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) == 3977 frame.render_passes_by_id.end()); 3978 3979 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 3980 my_host_impl->DidDrawAllLayers(frame); 3981 } 3982 3983 // Change less benign property and draw - should have contents changed flag 3984 surface_layer_ptr->SetStackingOrderChanged(true); 3985 { 3986 LayerTreeHostImpl::FrameData frame; 3987 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 3988 3989 // Must receive two render passes, each with one quad 3990 ASSERT_EQ(2U, frame.render_passes.size()); 3991 3992 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); 3993 EXPECT_EQ(DrawQuad::SOLID_COLOR, 3994 frame.render_passes[0]->quad_list[0]->material); 3995 3996 EXPECT_EQ(DrawQuad::RENDER_PASS, 3997 frame.render_passes[1]->quad_list[0]->material); 3998 const RenderPassDrawQuad* quad = 3999 RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]); 4000 RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id]; 4001 ASSERT_TRUE(target_pass); 4002 EXPECT_FALSE(target_pass->damage_rect.IsEmpty()); 4003 4004 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 4005 my_host_impl->DidDrawAllLayers(frame); 4006 } 4007 4008 // Change opacity again, and evict the cached surface texture. 4009 surface_layer_ptr->SetOpacity(0.5f); 4010 static_cast<GLRendererWithReleaseTextures*>( 4011 my_host_impl->renderer())->ReleaseRenderPassTextures(); 4012 4013 // Change opacity and draw 4014 surface_layer_ptr->SetOpacity(0.6f); 4015 { 4016 LayerTreeHostImpl::FrameData frame; 4017 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 4018 4019 // Must receive two render passes 4020 ASSERT_EQ(2U, frame.render_passes.size()); 4021 4022 // Even though not enough properties changed, the entire thing must be 4023 // redrawn as we don't have cached textures 4024 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); 4025 EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size()); 4026 4027 EXPECT_EQ(DrawQuad::RENDER_PASS, 4028 frame.render_passes[1]->quad_list[0]->material); 4029 const RenderPassDrawQuad* quad = 4030 RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]); 4031 RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id]; 4032 ASSERT_TRUE(target_pass); 4033 EXPECT_TRUE(target_pass->damage_rect.IsEmpty()); 4034 4035 // Was our surface evicted? 4036 EXPECT_FALSE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId( 4037 target_pass->id)); 4038 4039 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 4040 my_host_impl->DidDrawAllLayers(frame); 4041 } 4042 4043 // Draw without any change, to make sure the state is clear 4044 { 4045 LayerTreeHostImpl::FrameData frame; 4046 my_host_impl->SetFullRootLayerDamage(); 4047 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 4048 4049 // Must receive one render pass, as the other one should be culled 4050 ASSERT_EQ(1U, frame.render_passes.size()); 4051 4052 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); 4053 EXPECT_EQ(DrawQuad::RENDER_PASS, 4054 frame.render_passes[0]->quad_list[0]->material); 4055 const RenderPassDrawQuad* quad = 4056 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); 4057 EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) == 4058 frame.render_passes_by_id.end()); 4059 4060 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 4061 my_host_impl->DidDrawAllLayers(frame); 4062 } 4063 4064 // Change location of the intermediate layer 4065 gfx::Transform transform = intermediate_layer_ptr->transform(); 4066 transform.matrix().setDouble(0, 3, 1.0001); 4067 intermediate_layer_ptr->SetTransform(transform); 4068 { 4069 LayerTreeHostImpl::FrameData frame; 4070 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 4071 4072 // Must receive one render pass, as the other one should be culled. 4073 ASSERT_EQ(1U, frame.render_passes.size()); 4074 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); 4075 4076 EXPECT_EQ(DrawQuad::RENDER_PASS, 4077 frame.render_passes[0]->quad_list[0]->material); 4078 const RenderPassDrawQuad* quad = 4079 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); 4080 EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) == 4081 frame.render_passes_by_id.end()); 4082 4083 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 4084 my_host_impl->DidDrawAllLayers(frame); 4085 } 4086} 4087 4088TEST_F(LayerTreeHostImplTest, SurfaceTextureCachingNoPartialSwap) { 4089 LayerTreeSettings settings; 4090 settings.minimum_occlusion_tracking_size = gfx::Size(); 4091 settings.cache_render_pass_contents = true; 4092 scoped_ptr<LayerTreeHostImpl> my_host_impl = 4093 LayerTreeHostImpl::Create(settings, 4094 this, 4095 &proxy_, 4096 &stats_instrumentation_); 4097 4098 LayerImpl* root_ptr; 4099 LayerImpl* intermediate_layer_ptr; 4100 LayerImpl* surface_layer_ptr; 4101 LayerImpl* child_ptr; 4102 4103 SetupLayersForTextureCaching(my_host_impl.get(), 4104 root_ptr, 4105 intermediate_layer_ptr, 4106 surface_layer_ptr, 4107 child_ptr, 4108 gfx::Size(100, 100)); 4109 { 4110 LayerTreeHostImpl::FrameData frame; 4111 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 4112 4113 // Must receive two render passes, each with one quad 4114 ASSERT_EQ(2U, frame.render_passes.size()); 4115 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); 4116 EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size()); 4117 4118 EXPECT_EQ(DrawQuad::RENDER_PASS, 4119 frame.render_passes[1]->quad_list[0]->material); 4120 const RenderPassDrawQuad* quad = 4121 RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]); 4122 RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id]; 4123 EXPECT_FALSE(target_pass->damage_rect.IsEmpty()); 4124 4125 EXPECT_FALSE(frame.render_passes[0]->damage_rect.IsEmpty()); 4126 EXPECT_FALSE(frame.render_passes[1]->damage_rect.IsEmpty()); 4127 4128 EXPECT_FALSE( 4129 frame.render_passes[0]->has_occlusion_from_outside_target_surface); 4130 EXPECT_FALSE( 4131 frame.render_passes[1]->has_occlusion_from_outside_target_surface); 4132 4133 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 4134 my_host_impl->DidDrawAllLayers(frame); 4135 } 4136 4137 // Draw without any change 4138 { 4139 LayerTreeHostImpl::FrameData frame; 4140 my_host_impl->SetFullRootLayerDamage(); 4141 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 4142 4143 // Even though there was no change, we set the damage to entire viewport. 4144 // One of the passes should be culled as a result, since contents didn't 4145 // change and we have cached texture. 4146 ASSERT_EQ(1U, frame.render_passes.size()); 4147 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); 4148 4149 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 4150 my_host_impl->DidDrawAllLayers(frame); 4151 } 4152 4153 // Change opacity and draw 4154 surface_layer_ptr->SetOpacity(0.6f); 4155 { 4156 LayerTreeHostImpl::FrameData frame; 4157 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 4158 4159 // Must receive one render pass, as the other one should be culled 4160 ASSERT_EQ(1U, frame.render_passes.size()); 4161 4162 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); 4163 EXPECT_EQ(DrawQuad::RENDER_PASS, 4164 frame.render_passes[0]->quad_list[0]->material); 4165 const RenderPassDrawQuad* quad = 4166 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); 4167 EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) == 4168 frame.render_passes_by_id.end()); 4169 4170 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 4171 my_host_impl->DidDrawAllLayers(frame); 4172 } 4173 4174 // Change less benign property and draw - should have contents changed flag 4175 surface_layer_ptr->SetStackingOrderChanged(true); 4176 { 4177 LayerTreeHostImpl::FrameData frame; 4178 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 4179 4180 // Must receive two render passes, each with one quad 4181 ASSERT_EQ(2U, frame.render_passes.size()); 4182 4183 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); 4184 EXPECT_EQ(DrawQuad::SOLID_COLOR, 4185 frame.render_passes[0]->quad_list[0]->material); 4186 4187 EXPECT_EQ(DrawQuad::RENDER_PASS, 4188 frame.render_passes[1]->quad_list[0]->material); 4189 const RenderPassDrawQuad* quad = 4190 RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]); 4191 RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id]; 4192 ASSERT_TRUE(target_pass); 4193 EXPECT_FALSE(target_pass->damage_rect.IsEmpty()); 4194 4195 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 4196 my_host_impl->DidDrawAllLayers(frame); 4197 } 4198 4199 // Change opacity again, and evict the cached surface texture. 4200 surface_layer_ptr->SetOpacity(0.5f); 4201 static_cast<GLRendererWithReleaseTextures*>( 4202 my_host_impl->renderer())->ReleaseRenderPassTextures(); 4203 4204 // Change opacity and draw 4205 surface_layer_ptr->SetOpacity(0.6f); 4206 { 4207 LayerTreeHostImpl::FrameData frame; 4208 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 4209 4210 // Must receive two render passes 4211 ASSERT_EQ(2U, frame.render_passes.size()); 4212 4213 // Even though not enough properties changed, the entire thing must be 4214 // redrawn as we don't have cached textures 4215 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); 4216 EXPECT_EQ(1U, frame.render_passes[1]->quad_list.size()); 4217 4218 EXPECT_EQ(DrawQuad::RENDER_PASS, 4219 frame.render_passes[1]->quad_list[0]->material); 4220 const RenderPassDrawQuad* quad = 4221 RenderPassDrawQuad::MaterialCast(frame.render_passes[1]->quad_list[0]); 4222 RenderPass* target_pass = frame.render_passes_by_id[quad->render_pass_id]; 4223 ASSERT_TRUE(target_pass); 4224 EXPECT_TRUE(target_pass->damage_rect.IsEmpty()); 4225 4226 // Was our surface evicted? 4227 EXPECT_FALSE(my_host_impl->renderer()->HaveCachedResourcesForRenderPassId( 4228 target_pass->id)); 4229 4230 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 4231 my_host_impl->DidDrawAllLayers(frame); 4232 } 4233 4234 // Draw without any change, to make sure the state is clear 4235 { 4236 LayerTreeHostImpl::FrameData frame; 4237 my_host_impl->SetFullRootLayerDamage(); 4238 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 4239 4240 // Even though there was no change, we set the damage to entire viewport. 4241 // One of the passes should be culled as a result, since contents didn't 4242 // change and we have cached texture. 4243 ASSERT_EQ(1U, frame.render_passes.size()); 4244 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); 4245 4246 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 4247 my_host_impl->DidDrawAllLayers(frame); 4248 } 4249 4250 // Change location of the intermediate layer 4251 gfx::Transform transform = intermediate_layer_ptr->transform(); 4252 transform.matrix().setDouble(0, 3, 1.0001); 4253 intermediate_layer_ptr->SetTransform(transform); 4254 { 4255 LayerTreeHostImpl::FrameData frame; 4256 EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect())); 4257 4258 // Must receive one render pass, as the other one should be culled. 4259 ASSERT_EQ(1U, frame.render_passes.size()); 4260 EXPECT_EQ(1U, frame.render_passes[0]->quad_list.size()); 4261 4262 EXPECT_EQ(DrawQuad::RENDER_PASS, 4263 frame.render_passes[0]->quad_list[0]->material); 4264 const RenderPassDrawQuad* quad = 4265 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); 4266 EXPECT_TRUE(frame.render_passes_by_id.find(quad->render_pass_id) == 4267 frame.render_passes_by_id.end()); 4268 4269 my_host_impl->DrawLayers(&frame, base::TimeTicks::Now()); 4270 my_host_impl->DidDrawAllLayers(frame); 4271 } 4272} 4273 4274TEST_F(LayerTreeHostImplTest, ReleaseContentsTextureShouldTriggerCommit) { 4275 set_reduce_memory_result(false); 4276 4277 // If changing the memory limit wouldn't result in changing what was 4278 // committed, then no commit should be requested. 4279 set_reduce_memory_result(false); 4280 host_impl_->set_max_memory_needed_bytes( 4281 host_impl_->memory_allocation_limit_bytes() - 1); 4282 host_impl_->SetManagedMemoryPolicy(ManagedMemoryPolicy( 4283 host_impl_->memory_allocation_limit_bytes() - 1)); 4284 EXPECT_FALSE(did_request_commit_); 4285 did_request_commit_ = false; 4286 4287 // If changing the memory limit would result in changing what was 4288 // committed, then a commit should be requested, even though nothing was 4289 // evicted. 4290 set_reduce_memory_result(false); 4291 host_impl_->set_max_memory_needed_bytes( 4292 host_impl_->memory_allocation_limit_bytes()); 4293 host_impl_->SetManagedMemoryPolicy(ManagedMemoryPolicy( 4294 host_impl_->memory_allocation_limit_bytes() - 1)); 4295 EXPECT_TRUE(did_request_commit_); 4296 did_request_commit_ = false; 4297 4298 // Especially if changing the memory limit caused evictions, we need 4299 // to re-commit. 4300 set_reduce_memory_result(true); 4301 host_impl_->set_max_memory_needed_bytes(1); 4302 host_impl_->SetManagedMemoryPolicy(ManagedMemoryPolicy( 4303 host_impl_->memory_allocation_limit_bytes() - 1)); 4304 EXPECT_TRUE(did_request_commit_); 4305 did_request_commit_ = false; 4306 4307 // But if we set it to the same value that it was before, we shouldn't 4308 // re-commit. 4309 host_impl_->SetManagedMemoryPolicy(ManagedMemoryPolicy( 4310 host_impl_->memory_allocation_limit_bytes())); 4311 EXPECT_FALSE(did_request_commit_); 4312} 4313 4314struct RenderPassRemovalTestData : public LayerTreeHostImpl::FrameData { 4315 ScopedPtrHashMap<RenderPass::Id, TestRenderPass> render_pass_cache; 4316 scoped_ptr<SharedQuadState> shared_quad_state; 4317}; 4318 4319class TestRenderer : public GLRenderer, public RendererClient { 4320 public: 4321 static scoped_ptr<TestRenderer> Create(ResourceProvider* resource_provider, 4322 OutputSurface* output_surface, 4323 Proxy* proxy) { 4324 scoped_ptr<TestRenderer> renderer(new TestRenderer(resource_provider, 4325 output_surface, 4326 proxy)); 4327 if (!renderer->Initialize()) 4328 return scoped_ptr<TestRenderer>(); 4329 4330 return renderer.Pass(); 4331 } 4332 4333 void ClearCachedTextures() { textures_.clear(); } 4334 void SetHaveCachedResourcesForRenderPassId(RenderPass::Id id) { 4335 textures_.insert(id); 4336 } 4337 4338 virtual bool HaveCachedResourcesForRenderPassId(RenderPass::Id id) const 4339 OVERRIDE { 4340 return textures_.count(id); 4341 } 4342 4343 // RendererClient implementation. 4344 virtual gfx::Size DeviceViewportSize() const OVERRIDE { 4345 return viewport_size_; 4346 } 4347 virtual const LayerTreeSettings& Settings() const OVERRIDE { 4348 return settings_; 4349 } 4350 virtual void SetFullRootLayerDamage() OVERRIDE {} 4351 virtual void SetManagedMemoryPolicy(const ManagedMemoryPolicy& policy) 4352 OVERRIDE {} 4353 virtual void EnforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy) 4354 OVERRIDE {} 4355 virtual bool HasImplThread() const OVERRIDE { return false; } 4356 virtual bool ShouldClearRootRenderPass() const OVERRIDE { return true; } 4357 virtual CompositorFrameMetadata MakeCompositorFrameMetadata() const 4358 OVERRIDE { return CompositorFrameMetadata(); } 4359 virtual bool AllowPartialSwap() const OVERRIDE { 4360 return true; 4361 } 4362 4363 protected: 4364 TestRenderer(ResourceProvider* resource_provider, 4365 OutputSurface* output_surface, 4366 Proxy* proxy) 4367 : GLRenderer(this, output_surface, resource_provider, 0) {} 4368 4369 private: 4370 LayerTreeSettings settings_; 4371 gfx::Size viewport_size_; 4372 base::hash_set<RenderPass::Id> textures_; 4373}; 4374 4375static void ConfigureRenderPassTestData(const char* test_script, 4376 RenderPassRemovalTestData* test_data, 4377 TestRenderer* renderer) { 4378 renderer->ClearCachedTextures(); 4379 4380 // One shared state for all quads - we don't need the correct details 4381 test_data->shared_quad_state = SharedQuadState::Create(); 4382 test_data->shared_quad_state->SetAll(gfx::Transform(), 4383 gfx::Size(), 4384 gfx::Rect(), 4385 gfx::Rect(), 4386 false, 4387 1.f); 4388 4389 const char* current_char = test_script; 4390 4391 // Pre-create root pass 4392 RenderPass::Id root_render_pass_id = 4393 RenderPass::Id(test_script[0], test_script[1]); 4394 scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); 4395 pass->SetNew(root_render_pass_id, gfx::Rect(), gfx::Rect(), gfx::Transform()); 4396 test_data->render_pass_cache.add(root_render_pass_id, pass.Pass()); 4397 while (*current_char) { 4398 int layer_id = *current_char; 4399 current_char++; 4400 ASSERT_TRUE(current_char); 4401 int index = *current_char; 4402 current_char++; 4403 4404 RenderPass::Id render_pass_id = RenderPass::Id(layer_id, index); 4405 4406 bool is_replica = false; 4407 if (!test_data->render_pass_cache.contains(render_pass_id)) 4408 is_replica = true; 4409 4410 scoped_ptr<TestRenderPass> render_pass = 4411 test_data->render_pass_cache.take(render_pass_id); 4412 4413 // Cycle through quad data and create all quads. 4414 while (*current_char && *current_char != '\n') { 4415 if (*current_char == 's') { 4416 // Solid color draw quad. 4417 scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create(); 4418 quad->SetNew(test_data->shared_quad_state.get(), 4419 gfx::Rect(0, 0, 10, 10), 4420 SK_ColorWHITE, 4421 false); 4422 4423 render_pass->AppendQuad(quad.PassAs<DrawQuad>()); 4424 current_char++; 4425 } else if ((*current_char >= 'A') && (*current_char <= 'Z')) { 4426 // RenderPass draw quad. 4427 int layer_id = *current_char; 4428 current_char++; 4429 ASSERT_TRUE(current_char); 4430 int index = *current_char; 4431 current_char++; 4432 RenderPass::Id new_render_pass_id = RenderPass::Id(layer_id, index); 4433 ASSERT_NE(root_render_pass_id, new_render_pass_id); 4434 bool has_texture = false; 4435 bool contents_changed = true; 4436 4437 if (*current_char == '[') { 4438 current_char++; 4439 while (*current_char && *current_char != ']') { 4440 switch (*current_char) { 4441 case 'c': 4442 contents_changed = false; 4443 break; 4444 case 't': 4445 has_texture = true; 4446 break; 4447 } 4448 current_char++; 4449 } 4450 if (*current_char == ']') 4451 current_char++; 4452 } 4453 4454 if (test_data->render_pass_cache.find(new_render_pass_id) == 4455 test_data->render_pass_cache.end()) { 4456 if (has_texture) 4457 renderer->SetHaveCachedResourcesForRenderPassId(new_render_pass_id); 4458 4459 scoped_ptr<TestRenderPass> pass = TestRenderPass::Create(); 4460 pass->SetNew(new_render_pass_id, 4461 gfx::Rect(), 4462 gfx::Rect(), 4463 gfx::Transform()); 4464 test_data->render_pass_cache.add(new_render_pass_id, pass.Pass()); 4465 } 4466 4467 gfx::Rect quad_rect = gfx::Rect(0, 0, 1, 1); 4468 gfx::Rect contents_changed_rect = 4469 contents_changed ? quad_rect : gfx::Rect(); 4470 scoped_ptr<RenderPassDrawQuad> quad = RenderPassDrawQuad::Create(); 4471 quad->SetNew(test_data->shared_quad_state.get(), 4472 quad_rect, 4473 new_render_pass_id, 4474 is_replica, 4475 1, 4476 contents_changed_rect, 4477 gfx::RectF(0.f, 0.f, 1.f, 1.f), 4478 WebKit::WebFilterOperations(), 4479 skia::RefPtr<SkImageFilter>(), 4480 WebKit::WebFilterOperations()); 4481 render_pass->AppendQuad(quad.PassAs<DrawQuad>()); 4482 } 4483 } 4484 test_data->render_passes_by_id[render_pass_id] = render_pass.get(); 4485 test_data->render_passes.insert(test_data->render_passes.begin(), 4486 render_pass.PassAs<RenderPass>()); 4487 if (*current_char) 4488 current_char++; 4489 } 4490} 4491 4492void DumpRenderPassTestData(const RenderPassRemovalTestData& test_data, 4493 char* buffer) { 4494 char* pos = buffer; 4495 for (RenderPassList::const_reverse_iterator it = 4496 test_data.render_passes.rbegin(); 4497 it != test_data.render_passes.rend(); 4498 ++it) { 4499 const RenderPass* current_pass = *it; 4500 *pos = current_pass->id.layer_id; 4501 pos++; 4502 *pos = current_pass->id.index; 4503 pos++; 4504 4505 QuadList::const_iterator quad_list_iterator = 4506 current_pass->quad_list.begin(); 4507 while (quad_list_iterator != current_pass->quad_list.end()) { 4508 DrawQuad* current_quad = *quad_list_iterator; 4509 switch (current_quad->material) { 4510 case DrawQuad::SOLID_COLOR: 4511 *pos = 's'; 4512 pos++; 4513 break; 4514 case DrawQuad::RENDER_PASS: 4515 *pos = RenderPassDrawQuad::MaterialCast(current_quad)-> 4516 render_pass_id.layer_id; 4517 pos++; 4518 *pos = RenderPassDrawQuad::MaterialCast(current_quad)-> 4519 render_pass_id.index; 4520 pos++; 4521 break; 4522 default: 4523 *pos = 'x'; 4524 pos++; 4525 break; 4526 } 4527 4528 quad_list_iterator++; 4529 } 4530 *pos = '\n'; 4531 pos++; 4532 } 4533 *pos = '\0'; 4534} 4535 4536// Each RenderPassList is represented by a string which describes the 4537// configuration. 4538// The syntax of the string is as follows: 4539// 4540// RsssssX[c]ssYsssZ[t]ssW[ct] 4541// Identifies the render pass------------------------^ ^^^ ^ ^ ^ ^ ^ 4542// These are solid color quads--------------------------+ | | | | | 4543// Identifies RenderPassDrawQuad's RenderPass--------------+ | | | | 4544// This quad's contents didn't change------------------------+ | | | 4545// This quad's contents changed and it has no texture------------+ | | 4546// This quad has texture but its contents changed----------------------+ | 4547// This quad's contents didn't change and it has texture - will be removed---+ 4548// 4549// Expected results have exactly the same syntax, except they do not use square 4550// brackets, since we only check the structure, not attributes. 4551// 4552// Test case configuration consists of initialization script and expected 4553// results, all in the same format. 4554struct TestCase { 4555 const char* name; 4556 const char* init_script; 4557 const char* expected_result; 4558}; 4559 4560TestCase remove_render_passes_cases[] = { 4561 { 4562 "Single root pass", 4563 "R0ssss\n", 4564 "R0ssss\n" 4565 }, { 4566 "Single pass - no quads", 4567 "R0\n", 4568 "R0\n" 4569 }, { 4570 "Two passes, no removal", 4571 "R0ssssA0sss\n" 4572 "A0ssss\n", 4573 "R0ssssA0sss\n" 4574 "A0ssss\n" 4575 }, { 4576 "Two passes, remove last", 4577 "R0ssssA0[ct]sss\n" 4578 "A0ssss\n", 4579 "R0ssssA0sss\n" 4580 }, { 4581 "Have texture but contents changed - leave pass", 4582 "R0ssssA0[t]sss\n" 4583 "A0ssss\n", 4584 "R0ssssA0sss\n" 4585 "A0ssss\n" 4586 }, { 4587 "Contents didn't change but no texture - leave pass", 4588 "R0ssssA0[c]sss\n" 4589 "A0ssss\n", 4590 "R0ssssA0sss\n" 4591 "A0ssss\n" 4592 }, { 4593 "Replica: two quads reference the same pass; remove", 4594 "R0ssssA0[ct]A0[ct]sss\n" 4595 "A0ssss\n", 4596 "R0ssssA0A0sss\n" 4597 }, { 4598 "Replica: two quads reference the same pass; leave", 4599 "R0ssssA0[c]A0[c]sss\n" 4600 "A0ssss\n", 4601 "R0ssssA0A0sss\n" 4602 "A0ssss\n", 4603 }, { 4604 "Many passes, remove all", 4605 "R0ssssA0[ct]sss\n" 4606 "A0sssB0[ct]C0[ct]s\n" 4607 "B0sssD0[ct]ssE0[ct]F0[ct]\n" 4608 "E0ssssss\n" 4609 "C0G0[ct]\n" 4610 "D0sssssss\n" 4611 "F0sssssss\n" 4612 "G0sss\n", 4613 4614 "R0ssssA0sss\n" 4615 }, { 4616 "Deep recursion, remove all", 4617 4618 "R0sssssA0[ct]ssss\n" 4619 "A0ssssB0sss\n" 4620 "B0C0\n" 4621 "C0D0\n" 4622 "D0E0\n" 4623 "E0F0\n" 4624 "F0G0\n" 4625 "G0H0\n" 4626 "H0sssI0sss\n" 4627 "I0J0\n" 4628 "J0ssss\n", 4629 4630 "R0sssssA0ssss\n" 4631 }, { 4632 "Wide recursion, remove all", 4633 "R0A0[ct]B0[ct]C0[ct]D0[ct]E0[ct]F0[ct]G0[ct]H0[ct]I0[ct]J0[ct]\n" 4634 "A0s\n" 4635 "B0s\n" 4636 "C0ssss\n" 4637 "D0ssss\n" 4638 "E0s\n" 4639 "F0\n" 4640 "G0s\n" 4641 "H0s\n" 4642 "I0s\n" 4643 "J0ssss\n", 4644 4645 "R0A0B0C0D0E0F0G0H0I0J0\n" 4646 }, { 4647 "Remove passes regardless of cache state", 4648 "R0ssssA0[ct]sss\n" 4649 "A0sssB0C0s\n" 4650 "B0sssD0[c]ssE0[t]F0\n" 4651 "E0ssssss\n" 4652 "C0G0\n" 4653 "D0sssssss\n" 4654 "F0sssssss\n" 4655 "G0sss\n", 4656 4657 "R0ssssA0sss\n" 4658 }, { 4659 "Leave some passes, remove others", 4660 4661 "R0ssssA0[c]sss\n" 4662 "A0sssB0[t]C0[ct]s\n" 4663 "B0sssD0[c]ss\n" 4664 "C0G0\n" 4665 "D0sssssss\n" 4666 "G0sss\n", 4667 4668 "R0ssssA0sss\n" 4669 "A0sssB0C0s\n" 4670 "B0sssD0ss\n" 4671 "D0sssssss\n" 4672 }, { 4673 0, 0, 0 4674 } 4675}; 4676 4677static void VerifyRenderPassTestData( 4678 const TestCase& test_case, 4679 const RenderPassRemovalTestData& test_data) { 4680 char actual_result[1024]; 4681 DumpRenderPassTestData(test_data, actual_result); 4682 EXPECT_STREQ(test_case.expected_result, actual_result) << "In test case: " << 4683 test_case.name; 4684} 4685 4686TEST_F(LayerTreeHostImplTest, TestRemoveRenderPasses) { 4687 scoped_ptr<OutputSurface> output_surface(CreateOutputSurface()); 4688 ASSERT_TRUE(output_surface->context3d()); 4689 scoped_ptr<ResourceProvider> resource_provider = 4690 ResourceProvider::Create(output_surface.get(), 0); 4691 4692 scoped_ptr<TestRenderer> renderer = 4693 TestRenderer::Create(resource_provider.get(), 4694 output_surface.get(), 4695 &proxy_); 4696 4697 int test_case_index = 0; 4698 while (remove_render_passes_cases[test_case_index].name) { 4699 RenderPassRemovalTestData test_data; 4700 ConfigureRenderPassTestData( 4701 remove_render_passes_cases[test_case_index].init_script, 4702 &test_data, 4703 renderer.get()); 4704 LayerTreeHostImpl::RemoveRenderPasses( 4705 LayerTreeHostImpl::CullRenderPassesWithCachedTextures(renderer.get()), 4706 &test_data); 4707 VerifyRenderPassTestData(remove_render_passes_cases[test_case_index], 4708 test_data); 4709 test_case_index++; 4710 } 4711} 4712 4713class LayerTreeHostImplTestWithDelegatingRenderer 4714 : public LayerTreeHostImplTest { 4715 protected: 4716 virtual scoped_ptr<OutputSurface> CreateOutputSurface() OVERRIDE { 4717 return FakeOutputSurface::CreateDelegating3d().PassAs<OutputSurface>(); 4718 } 4719 4720 void DrawFrameAndTestDamage(const gfx::RectF& expected_damage) { 4721 bool expect_to_draw = !expected_damage.IsEmpty(); 4722 4723 LayerTreeHostImpl::FrameData frame; 4724 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 4725 4726 if (!expect_to_draw) { 4727 // With no damage, we don't draw, and no quads are created. 4728 ASSERT_EQ(0u, frame.render_passes.size()); 4729 } else { 4730 ASSERT_EQ(1u, frame.render_passes.size()); 4731 4732 // Verify the damage rect for the root render pass. 4733 const RenderPass* root_render_pass = frame.render_passes.back(); 4734 EXPECT_RECT_EQ(expected_damage, root_render_pass->damage_rect); 4735 4736 // Verify the root and child layers' quads are generated and not being 4737 // culled. 4738 ASSERT_EQ(2u, root_render_pass->quad_list.size()); 4739 4740 LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0]; 4741 gfx::RectF expected_child_visible_rect(child->content_bounds()); 4742 EXPECT_RECT_EQ(expected_child_visible_rect, 4743 root_render_pass->quad_list[0]->visible_rect); 4744 4745 LayerImpl* root = host_impl_->active_tree()->root_layer(); 4746 gfx::RectF expected_root_visible_rect(root->content_bounds()); 4747 EXPECT_RECT_EQ(expected_root_visible_rect, 4748 root_render_pass->quad_list[1]->visible_rect); 4749 } 4750 4751 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 4752 host_impl_->DidDrawAllLayers(frame); 4753 EXPECT_EQ(expect_to_draw, host_impl_->SwapBuffers(frame)); 4754 } 4755}; 4756 4757TEST_F(LayerTreeHostImplTestWithDelegatingRenderer, FrameIncludesDamageRect) { 4758 scoped_ptr<SolidColorLayerImpl> root = 4759 SolidColorLayerImpl::Create(host_impl_->active_tree(), 1); 4760 root->SetAnchorPoint(gfx::PointF()); 4761 root->SetPosition(gfx::PointF()); 4762 root->SetBounds(gfx::Size(10, 10)); 4763 root->SetContentBounds(gfx::Size(10, 10)); 4764 root->SetDrawsContent(true); 4765 4766 // Child layer is in the bottom right corner. 4767 scoped_ptr<SolidColorLayerImpl> child = 4768 SolidColorLayerImpl::Create(host_impl_->active_tree(), 2); 4769 child->SetAnchorPoint(gfx::PointF(0.f, 0.f)); 4770 child->SetPosition(gfx::PointF(9.f, 9.f)); 4771 child->SetBounds(gfx::Size(1, 1)); 4772 child->SetContentBounds(gfx::Size(1, 1)); 4773 child->SetDrawsContent(true); 4774 root->AddChild(child.PassAs<LayerImpl>()); 4775 4776 host_impl_->active_tree()->SetRootLayer(root.PassAs<LayerImpl>()); 4777 4778 // Draw a frame. In the first frame, the entire viewport should be damaged. 4779 gfx::Rect full_frame_damage = gfx::Rect(host_impl_->device_viewport_size()); 4780 DrawFrameAndTestDamage(full_frame_damage); 4781 4782 // The second frame has damage that doesn't touch the child layer. Its quads 4783 // should still be generated. 4784 gfx::Rect small_damage = gfx::Rect(0, 0, 1, 1); 4785 host_impl_->active_tree()->root_layer()->set_update_rect(small_damage); 4786 DrawFrameAndTestDamage(small_damage); 4787 4788 // The third frame should have no damage, so no quads should be generated. 4789 gfx::Rect no_damage; 4790 DrawFrameAndTestDamage(no_damage); 4791} 4792 4793class FakeMaskLayerImpl : public LayerImpl { 4794 public: 4795 static scoped_ptr<FakeMaskLayerImpl> Create(LayerTreeImpl* tree_impl, 4796 int id) { 4797 return make_scoped_ptr(new FakeMaskLayerImpl(tree_impl, id)); 4798 } 4799 4800 virtual ResourceProvider::ResourceId ContentsResourceId() const OVERRIDE { 4801 return 0; 4802 } 4803 4804 private: 4805 FakeMaskLayerImpl(LayerTreeImpl* tree_impl, int id) 4806 : LayerImpl(tree_impl, id) {} 4807}; 4808 4809TEST_F(LayerTreeHostImplTest, MaskLayerWithScaling) { 4810 // Root 4811 // | 4812 // +-- Scaling Layer (adds a 2x scale) 4813 // | 4814 // +-- Content Layer 4815 // +--Mask 4816 scoped_ptr<LayerImpl> scoped_root = 4817 LayerImpl::Create(host_impl_->active_tree(), 1); 4818 LayerImpl* root = scoped_root.get(); 4819 host_impl_->active_tree()->SetRootLayer(scoped_root.Pass()); 4820 4821 scoped_ptr<LayerImpl> scoped_scaling_layer = 4822 LayerImpl::Create(host_impl_->active_tree(), 2); 4823 LayerImpl* scaling_layer = scoped_scaling_layer.get(); 4824 root->AddChild(scoped_scaling_layer.Pass()); 4825 4826 scoped_ptr<LayerImpl> scoped_content_layer = 4827 LayerImpl::Create(host_impl_->active_tree(), 3); 4828 LayerImpl* content_layer = scoped_content_layer.get(); 4829 scaling_layer->AddChild(scoped_content_layer.Pass()); 4830 4831 scoped_ptr<FakeMaskLayerImpl> scoped_mask_layer = 4832 FakeMaskLayerImpl::Create(host_impl_->active_tree(), 4); 4833 FakeMaskLayerImpl* mask_layer = scoped_mask_layer.get(); 4834 content_layer->SetMaskLayer(scoped_mask_layer.PassAs<LayerImpl>()); 4835 4836 gfx::Size root_size(100, 100); 4837 root->SetBounds(root_size); 4838 root->SetContentBounds(root_size); 4839 root->SetPosition(gfx::PointF()); 4840 root->SetAnchorPoint(gfx::PointF()); 4841 4842 gfx::Size scaling_layer_size(50, 50); 4843 scaling_layer->SetBounds(scaling_layer_size); 4844 scaling_layer->SetContentBounds(scaling_layer_size); 4845 scaling_layer->SetPosition(gfx::PointF()); 4846 scaling_layer->SetAnchorPoint(gfx::PointF()); 4847 gfx::Transform scale; 4848 scale.Scale(2.f, 2.f); 4849 scaling_layer->SetTransform(scale); 4850 4851 content_layer->SetBounds(scaling_layer_size); 4852 content_layer->SetContentBounds(scaling_layer_size); 4853 content_layer->SetPosition(gfx::PointF()); 4854 content_layer->SetAnchorPoint(gfx::PointF()); 4855 content_layer->SetDrawsContent(true); 4856 4857 mask_layer->SetBounds(scaling_layer_size); 4858 mask_layer->SetContentBounds(scaling_layer_size); 4859 mask_layer->SetPosition(gfx::PointF()); 4860 mask_layer->SetAnchorPoint(gfx::PointF()); 4861 mask_layer->SetDrawsContent(true); 4862 4863 4864 // Check that the tree scaling is correctly taken into account for the mask, 4865 // that should fully map onto the quad. 4866 float device_scale_factor = 1.f; 4867 host_impl_->SetViewportSize(root_size); 4868 host_impl_->SetDeviceScaleFactor(device_scale_factor); 4869 { 4870 LayerTreeHostImpl::FrameData frame; 4871 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 4872 4873 ASSERT_EQ(1u, frame.render_passes.size()); 4874 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size()); 4875 ASSERT_EQ(DrawQuad::RENDER_PASS, 4876 frame.render_passes[0]->quad_list[0]->material); 4877 const RenderPassDrawQuad* render_pass_quad = 4878 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); 4879 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(), 4880 render_pass_quad->rect.ToString()); 4881 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), 4882 render_pass_quad->mask_uv_rect.ToString()); 4883 4884 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 4885 host_impl_->DidDrawAllLayers(frame); 4886 } 4887 4888 4889 // Applying a DSF should change the render surface size, but won't affect 4890 // which part of the mask is used. 4891 device_scale_factor = 2.f; 4892 gfx::Size device_viewport = 4893 gfx::ToFlooredSize(gfx::ScaleSize(root_size, device_scale_factor)); 4894 host_impl_->SetViewportSize(device_viewport); 4895 host_impl_->SetDeviceScaleFactor(device_scale_factor); 4896 host_impl_->active_tree()->set_needs_update_draw_properties(); 4897 { 4898 LayerTreeHostImpl::FrameData frame; 4899 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 4900 4901 ASSERT_EQ(1u, frame.render_passes.size()); 4902 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size()); 4903 ASSERT_EQ(DrawQuad::RENDER_PASS, 4904 frame.render_passes[0]->quad_list[0]->material); 4905 const RenderPassDrawQuad* render_pass_quad = 4906 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); 4907 EXPECT_EQ(gfx::Rect(0, 0, 200, 200).ToString(), 4908 render_pass_quad->rect.ToString()); 4909 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), 4910 render_pass_quad->mask_uv_rect.ToString()); 4911 4912 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 4913 host_impl_->DidDrawAllLayers(frame); 4914 } 4915 4916 4917 // Applying an equivalent content scale on the content layer and the mask 4918 // should still result in the same part of the mask being used. 4919 gfx::Size content_bounds = 4920 gfx::ToRoundedSize(gfx::ScaleSize(scaling_layer_size, 4921 device_scale_factor)); 4922 content_layer->SetContentBounds(content_bounds); 4923 content_layer->SetContentsScale(device_scale_factor, device_scale_factor); 4924 mask_layer->SetContentBounds(content_bounds); 4925 mask_layer->SetContentsScale(device_scale_factor, device_scale_factor); 4926 host_impl_->active_tree()->set_needs_update_draw_properties(); 4927 { 4928 LayerTreeHostImpl::FrameData frame; 4929 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 4930 4931 ASSERT_EQ(1u, frame.render_passes.size()); 4932 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size()); 4933 ASSERT_EQ(DrawQuad::RENDER_PASS, 4934 frame.render_passes[0]->quad_list[0]->material); 4935 const RenderPassDrawQuad* render_pass_quad = 4936 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); 4937 EXPECT_EQ(gfx::Rect(0, 0, 200, 200).ToString(), 4938 render_pass_quad->rect.ToString()); 4939 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), 4940 render_pass_quad->mask_uv_rect.ToString()); 4941 4942 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 4943 host_impl_->DidDrawAllLayers(frame); 4944 } 4945} 4946 4947TEST_F(LayerTreeHostImplTest, MaskLayerWithDifferentBounds) { 4948 // The mask layer has bounds 100x100 but is attached to a layer with bounds 4949 // 50x50. 4950 4951 scoped_ptr<LayerImpl> scoped_root = 4952 LayerImpl::Create(host_impl_->active_tree(), 1); 4953 LayerImpl* root = scoped_root.get(); 4954 host_impl_->active_tree()->SetRootLayer(scoped_root.Pass()); 4955 4956 scoped_ptr<LayerImpl> scoped_content_layer = 4957 LayerImpl::Create(host_impl_->active_tree(), 3); 4958 LayerImpl* content_layer = scoped_content_layer.get(); 4959 root->AddChild(scoped_content_layer.Pass()); 4960 4961 scoped_ptr<FakeMaskLayerImpl> scoped_mask_layer = 4962 FakeMaskLayerImpl::Create(host_impl_->active_tree(), 4); 4963 FakeMaskLayerImpl* mask_layer = scoped_mask_layer.get(); 4964 content_layer->SetMaskLayer(scoped_mask_layer.PassAs<LayerImpl>()); 4965 4966 gfx::Size root_size(100, 100); 4967 root->SetBounds(root_size); 4968 root->SetContentBounds(root_size); 4969 root->SetPosition(gfx::PointF()); 4970 root->SetAnchorPoint(gfx::PointF()); 4971 4972 gfx::Size layer_size(50, 50); 4973 content_layer->SetBounds(layer_size); 4974 content_layer->SetContentBounds(layer_size); 4975 content_layer->SetPosition(gfx::PointF()); 4976 content_layer->SetAnchorPoint(gfx::PointF()); 4977 content_layer->SetDrawsContent(true); 4978 4979 gfx::Size mask_size(100, 100); 4980 mask_layer->SetBounds(mask_size); 4981 mask_layer->SetContentBounds(mask_size); 4982 mask_layer->SetPosition(gfx::PointF()); 4983 mask_layer->SetAnchorPoint(gfx::PointF()); 4984 mask_layer->SetDrawsContent(true); 4985 4986 // Check that the mask fills the surface. 4987 float device_scale_factor = 1.f; 4988 host_impl_->SetViewportSize(root_size); 4989 host_impl_->SetDeviceScaleFactor(device_scale_factor); 4990 { 4991 LayerTreeHostImpl::FrameData frame; 4992 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 4993 4994 ASSERT_EQ(1u, frame.render_passes.size()); 4995 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size()); 4996 ASSERT_EQ(DrawQuad::RENDER_PASS, 4997 frame.render_passes[0]->quad_list[0]->material); 4998 const RenderPassDrawQuad* render_pass_quad = 4999 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); 5000 EXPECT_EQ(gfx::Rect(0, 0, 50, 50).ToString(), 5001 render_pass_quad->rect.ToString()); 5002 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), 5003 render_pass_quad->mask_uv_rect.ToString()); 5004 5005 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 5006 host_impl_->DidDrawAllLayers(frame); 5007 } 5008 5009 // Applying a DSF should change the render surface size, but won't affect 5010 // which part of the mask is used. 5011 device_scale_factor = 2.f; 5012 gfx::Size device_viewport = 5013 gfx::ToFlooredSize(gfx::ScaleSize(root_size, device_scale_factor)); 5014 host_impl_->SetViewportSize(device_viewport); 5015 host_impl_->SetDeviceScaleFactor(device_scale_factor); 5016 host_impl_->active_tree()->set_needs_update_draw_properties(); 5017 { 5018 LayerTreeHostImpl::FrameData frame; 5019 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 5020 5021 ASSERT_EQ(1u, frame.render_passes.size()); 5022 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size()); 5023 ASSERT_EQ(DrawQuad::RENDER_PASS, 5024 frame.render_passes[0]->quad_list[0]->material); 5025 const RenderPassDrawQuad* render_pass_quad = 5026 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); 5027 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(), 5028 render_pass_quad->rect.ToString()); 5029 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), 5030 render_pass_quad->mask_uv_rect.ToString()); 5031 5032 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 5033 host_impl_->DidDrawAllLayers(frame); 5034 } 5035 5036 // Applying an equivalent content scale on the content layer and the mask 5037 // should still result in the same part of the mask being used. 5038 gfx::Size layer_size_large = 5039 gfx::ToRoundedSize(gfx::ScaleSize(layer_size, device_scale_factor)); 5040 content_layer->SetContentBounds(layer_size_large); 5041 content_layer->SetContentsScale(device_scale_factor, device_scale_factor); 5042 gfx::Size mask_size_large = 5043 gfx::ToRoundedSize(gfx::ScaleSize(mask_size, device_scale_factor)); 5044 mask_layer->SetContentBounds(mask_size_large); 5045 mask_layer->SetContentsScale(device_scale_factor, device_scale_factor); 5046 host_impl_->active_tree()->set_needs_update_draw_properties(); 5047 { 5048 LayerTreeHostImpl::FrameData frame; 5049 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 5050 5051 ASSERT_EQ(1u, frame.render_passes.size()); 5052 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size()); 5053 ASSERT_EQ(DrawQuad::RENDER_PASS, 5054 frame.render_passes[0]->quad_list[0]->material); 5055 const RenderPassDrawQuad* render_pass_quad = 5056 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); 5057 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(), 5058 render_pass_quad->rect.ToString()); 5059 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), 5060 render_pass_quad->mask_uv_rect.ToString()); 5061 5062 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 5063 host_impl_->DidDrawAllLayers(frame); 5064 } 5065 5066 // Applying a different contents scale to the mask layer means it will have 5067 // a larger texture, but it should use the same tex coords to cover the 5068 // layer it masks. 5069 mask_layer->SetContentBounds(mask_size); 5070 mask_layer->SetContentsScale(1.f, 1.f); 5071 host_impl_->active_tree()->set_needs_update_draw_properties(); 5072 { 5073 LayerTreeHostImpl::FrameData frame; 5074 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 5075 5076 ASSERT_EQ(1u, frame.render_passes.size()); 5077 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size()); 5078 ASSERT_EQ(DrawQuad::RENDER_PASS, 5079 frame.render_passes[0]->quad_list[0]->material); 5080 const RenderPassDrawQuad* render_pass_quad = 5081 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); 5082 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(), 5083 render_pass_quad->rect.ToString()); 5084 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), 5085 render_pass_quad->mask_uv_rect.ToString()); 5086 5087 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 5088 host_impl_->DidDrawAllLayers(frame); 5089 } 5090} 5091 5092TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerWithDifferentBounds) { 5093 // The replica's mask layer has bounds 100x100 but the replica is of a 5094 // layer with bounds 50x50. 5095 5096 scoped_ptr<LayerImpl> scoped_root = 5097 LayerImpl::Create(host_impl_->active_tree(), 1); 5098 LayerImpl* root = scoped_root.get(); 5099 host_impl_->active_tree()->SetRootLayer(scoped_root.Pass()); 5100 5101 scoped_ptr<LayerImpl> scoped_content_layer = 5102 LayerImpl::Create(host_impl_->active_tree(), 3); 5103 LayerImpl* content_layer = scoped_content_layer.get(); 5104 root->AddChild(scoped_content_layer.Pass()); 5105 5106 scoped_ptr<LayerImpl> scoped_replica_layer = 5107 LayerImpl::Create(host_impl_->active_tree(), 2); 5108 LayerImpl* replica_layer = scoped_replica_layer.get(); 5109 content_layer->SetReplicaLayer(scoped_replica_layer.Pass()); 5110 5111 scoped_ptr<FakeMaskLayerImpl> scoped_mask_layer = 5112 FakeMaskLayerImpl::Create(host_impl_->active_tree(), 4); 5113 FakeMaskLayerImpl* mask_layer = scoped_mask_layer.get(); 5114 replica_layer->SetMaskLayer(scoped_mask_layer.PassAs<LayerImpl>()); 5115 5116 gfx::Size root_size(100, 100); 5117 root->SetBounds(root_size); 5118 root->SetContentBounds(root_size); 5119 root->SetPosition(gfx::PointF()); 5120 root->SetAnchorPoint(gfx::PointF()); 5121 5122 gfx::Size layer_size(50, 50); 5123 content_layer->SetBounds(layer_size); 5124 content_layer->SetContentBounds(layer_size); 5125 content_layer->SetPosition(gfx::PointF()); 5126 content_layer->SetAnchorPoint(gfx::PointF()); 5127 content_layer->SetDrawsContent(true); 5128 5129 gfx::Size mask_size(100, 100); 5130 mask_layer->SetBounds(mask_size); 5131 mask_layer->SetContentBounds(mask_size); 5132 mask_layer->SetPosition(gfx::PointF()); 5133 mask_layer->SetAnchorPoint(gfx::PointF()); 5134 mask_layer->SetDrawsContent(true); 5135 5136 // Check that the mask fills the surface. 5137 float device_scale_factor = 1.f; 5138 host_impl_->SetViewportSize(root_size); 5139 host_impl_->SetDeviceScaleFactor(device_scale_factor); 5140 { 5141 LayerTreeHostImpl::FrameData frame; 5142 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 5143 5144 ASSERT_EQ(1u, frame.render_passes.size()); 5145 ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size()); 5146 ASSERT_EQ(DrawQuad::RENDER_PASS, 5147 frame.render_passes[0]->quad_list[1]->material); 5148 const RenderPassDrawQuad* replica_quad = 5149 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[1]); 5150 EXPECT_TRUE(replica_quad->is_replica); 5151 EXPECT_EQ(gfx::Rect(0, 0, 50, 50).ToString(), 5152 replica_quad->rect.ToString()); 5153 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), 5154 replica_quad->mask_uv_rect.ToString()); 5155 5156 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 5157 host_impl_->DidDrawAllLayers(frame); 5158 } 5159 5160 // Applying a DSF should change the render surface size, but won't affect 5161 // which part of the mask is used. 5162 device_scale_factor = 2.f; 5163 gfx::Size device_viewport = 5164 gfx::ToFlooredSize(gfx::ScaleSize(root_size, device_scale_factor)); 5165 host_impl_->SetViewportSize(device_viewport); 5166 host_impl_->SetDeviceScaleFactor(device_scale_factor); 5167 host_impl_->active_tree()->set_needs_update_draw_properties(); 5168 { 5169 LayerTreeHostImpl::FrameData frame; 5170 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 5171 5172 ASSERT_EQ(1u, frame.render_passes.size()); 5173 ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size()); 5174 ASSERT_EQ(DrawQuad::RENDER_PASS, 5175 frame.render_passes[0]->quad_list[1]->material); 5176 const RenderPassDrawQuad* replica_quad = 5177 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[1]); 5178 EXPECT_TRUE(replica_quad->is_replica); 5179 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(), 5180 replica_quad->rect.ToString()); 5181 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), 5182 replica_quad->mask_uv_rect.ToString()); 5183 5184 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 5185 host_impl_->DidDrawAllLayers(frame); 5186 } 5187 5188 // Applying an equivalent content scale on the content layer and the mask 5189 // should still result in the same part of the mask being used. 5190 gfx::Size layer_size_large = 5191 gfx::ToRoundedSize(gfx::ScaleSize(layer_size, device_scale_factor)); 5192 content_layer->SetContentBounds(layer_size_large); 5193 content_layer->SetContentsScale(device_scale_factor, device_scale_factor); 5194 gfx::Size mask_size_large = 5195 gfx::ToRoundedSize(gfx::ScaleSize(mask_size, device_scale_factor)); 5196 mask_layer->SetContentBounds(mask_size_large); 5197 mask_layer->SetContentsScale(device_scale_factor, device_scale_factor); 5198 host_impl_->active_tree()->set_needs_update_draw_properties(); 5199 { 5200 LayerTreeHostImpl::FrameData frame; 5201 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 5202 5203 ASSERT_EQ(1u, frame.render_passes.size()); 5204 ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size()); 5205 ASSERT_EQ(DrawQuad::RENDER_PASS, 5206 frame.render_passes[0]->quad_list[1]->material); 5207 const RenderPassDrawQuad* replica_quad = 5208 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[1]); 5209 EXPECT_TRUE(replica_quad->is_replica); 5210 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(), 5211 replica_quad->rect.ToString()); 5212 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), 5213 replica_quad->mask_uv_rect.ToString()); 5214 5215 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 5216 host_impl_->DidDrawAllLayers(frame); 5217 } 5218 5219 // Applying a different contents scale to the mask layer means it will have 5220 // a larger texture, but it should use the same tex coords to cover the 5221 // layer it masks. 5222 mask_layer->SetContentBounds(mask_size); 5223 mask_layer->SetContentsScale(1.f, 1.f); 5224 host_impl_->active_tree()->set_needs_update_draw_properties(); 5225 { 5226 LayerTreeHostImpl::FrameData frame; 5227 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 5228 5229 ASSERT_EQ(1u, frame.render_passes.size()); 5230 ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size()); 5231 ASSERT_EQ(DrawQuad::RENDER_PASS, 5232 frame.render_passes[0]->quad_list[1]->material); 5233 const RenderPassDrawQuad* replica_quad = 5234 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[1]); 5235 EXPECT_TRUE(replica_quad->is_replica); 5236 EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(), 5237 replica_quad->rect.ToString()); 5238 EXPECT_EQ(gfx::RectF(0.f, 0.f, 1.f, 1.f).ToString(), 5239 replica_quad->mask_uv_rect.ToString()); 5240 5241 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 5242 host_impl_->DidDrawAllLayers(frame); 5243 } 5244} 5245 5246TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerForSurfaceWithUnclippedChild) { 5247 // The replica is of a layer with bounds 50x50, but it has a child that causes 5248 // the surface bounds to be larger. 5249 5250 scoped_ptr<LayerImpl> scoped_root = 5251 LayerImpl::Create(host_impl_->active_tree(), 1); 5252 LayerImpl* root = scoped_root.get(); 5253 host_impl_->active_tree()->SetRootLayer(scoped_root.Pass()); 5254 5255 scoped_ptr<LayerImpl> scoped_content_layer = 5256 LayerImpl::Create(host_impl_->active_tree(), 2); 5257 LayerImpl* content_layer = scoped_content_layer.get(); 5258 root->AddChild(scoped_content_layer.Pass()); 5259 5260 scoped_ptr<LayerImpl> scoped_content_child_layer = 5261 LayerImpl::Create(host_impl_->active_tree(), 3); 5262 LayerImpl* content_child_layer = scoped_content_child_layer.get(); 5263 content_layer->AddChild(scoped_content_child_layer.Pass()); 5264 5265 scoped_ptr<LayerImpl> scoped_replica_layer = 5266 LayerImpl::Create(host_impl_->active_tree(), 4); 5267 LayerImpl* replica_layer = scoped_replica_layer.get(); 5268 content_layer->SetReplicaLayer(scoped_replica_layer.Pass()); 5269 5270 scoped_ptr<FakeMaskLayerImpl> scoped_mask_layer = 5271 FakeMaskLayerImpl::Create(host_impl_->active_tree(), 5); 5272 FakeMaskLayerImpl* mask_layer = scoped_mask_layer.get(); 5273 replica_layer->SetMaskLayer(scoped_mask_layer.PassAs<LayerImpl>()); 5274 5275 gfx::Size root_size(100, 100); 5276 root->SetBounds(root_size); 5277 root->SetContentBounds(root_size); 5278 root->SetPosition(gfx::PointF()); 5279 root->SetAnchorPoint(gfx::PointF()); 5280 5281 gfx::Size layer_size(50, 50); 5282 content_layer->SetBounds(layer_size); 5283 content_layer->SetContentBounds(layer_size); 5284 content_layer->SetPosition(gfx::PointF()); 5285 content_layer->SetAnchorPoint(gfx::PointF()); 5286 content_layer->SetDrawsContent(true); 5287 5288 gfx::Size child_size(50, 50); 5289 content_child_layer->SetBounds(child_size); 5290 content_child_layer->SetContentBounds(child_size); 5291 content_child_layer->SetPosition(gfx::Point(50, 0)); 5292 content_child_layer->SetAnchorPoint(gfx::PointF()); 5293 content_child_layer->SetDrawsContent(true); 5294 5295 gfx::Size mask_size(50, 50); 5296 mask_layer->SetBounds(mask_size); 5297 mask_layer->SetContentBounds(mask_size); 5298 mask_layer->SetPosition(gfx::PointF()); 5299 mask_layer->SetAnchorPoint(gfx::PointF()); 5300 mask_layer->SetDrawsContent(true); 5301 5302 float device_scale_factor = 1.f; 5303 host_impl_->SetViewportSize(root_size); 5304 host_impl_->SetDeviceScaleFactor(device_scale_factor); 5305 { 5306 LayerTreeHostImpl::FrameData frame; 5307 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 5308 5309 ASSERT_EQ(1u, frame.render_passes.size()); 5310 ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size()); 5311 5312 // The surface is 100x50. 5313 ASSERT_EQ(DrawQuad::RENDER_PASS, 5314 frame.render_passes[0]->quad_list[0]->material); 5315 const RenderPassDrawQuad* render_pass_quad = 5316 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); 5317 EXPECT_FALSE(render_pass_quad->is_replica); 5318 EXPECT_EQ(gfx::Rect(0, 0, 100, 50).ToString(), 5319 render_pass_quad->rect.ToString()); 5320 5321 // The mask covers the owning layer only. 5322 ASSERT_EQ(DrawQuad::RENDER_PASS, 5323 frame.render_passes[0]->quad_list[1]->material); 5324 const RenderPassDrawQuad* replica_quad = 5325 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[1]); 5326 EXPECT_TRUE(replica_quad->is_replica); 5327 EXPECT_EQ(gfx::Rect(0, 0, 100, 50).ToString(), 5328 replica_quad->rect.ToString()); 5329 EXPECT_EQ(gfx::RectF(0.f, 0.f, 2.f, 1.f).ToString(), 5330 replica_quad->mask_uv_rect.ToString()); 5331 5332 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 5333 host_impl_->DidDrawAllLayers(frame); 5334 } 5335 5336 // Move the child to (-50, 0) instead. Now the mask should be moved to still 5337 // cover the layer being replicated. 5338 content_child_layer->SetPosition(gfx::Point(-50, 0)); 5339 { 5340 LayerTreeHostImpl::FrameData frame; 5341 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 5342 5343 ASSERT_EQ(1u, frame.render_passes.size()); 5344 ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size()); 5345 5346 // The surface is 100x50 with its origin at (-50, 0). 5347 ASSERT_EQ(DrawQuad::RENDER_PASS, 5348 frame.render_passes[0]->quad_list[0]->material); 5349 const RenderPassDrawQuad* render_pass_quad = 5350 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); 5351 EXPECT_FALSE(render_pass_quad->is_replica); 5352 EXPECT_EQ(gfx::Rect(-50, 0, 100, 50).ToString(), 5353 render_pass_quad->rect.ToString()); 5354 5355 // The mask covers the owning layer only. 5356 ASSERT_EQ(DrawQuad::RENDER_PASS, 5357 frame.render_passes[0]->quad_list[1]->material); 5358 const RenderPassDrawQuad* replica_quad = 5359 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[1]); 5360 EXPECT_TRUE(replica_quad->is_replica); 5361 EXPECT_EQ(gfx::Rect(-50, 0, 100, 50).ToString(), 5362 replica_quad->rect.ToString()); 5363 EXPECT_EQ(gfx::RectF(-1.f, 0.f, 2.f, 1.f).ToString(), 5364 replica_quad->mask_uv_rect.ToString()); 5365 5366 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 5367 host_impl_->DidDrawAllLayers(frame); 5368 } 5369} 5370 5371TEST_F(LayerTreeHostImplTest, MaskLayerForSurfaceWithClippedLayer) { 5372 // The masked layer has bounds 50x50, but it has a child that causes 5373 // the surface bounds to be larger. It also has a parent that clips the 5374 // masked layer and its surface. 5375 5376 scoped_ptr<LayerImpl> scoped_root = 5377 LayerImpl::Create(host_impl_->active_tree(), 1); 5378 LayerImpl* root = scoped_root.get(); 5379 host_impl_->active_tree()->SetRootLayer(scoped_root.Pass()); 5380 5381 scoped_ptr<LayerImpl> scoped_clipping_layer = 5382 LayerImpl::Create(host_impl_->active_tree(), 2); 5383 LayerImpl* clipping_layer = scoped_clipping_layer.get(); 5384 root->AddChild(scoped_clipping_layer.Pass()); 5385 5386 scoped_ptr<LayerImpl> scoped_content_layer = 5387 LayerImpl::Create(host_impl_->active_tree(), 3); 5388 LayerImpl* content_layer = scoped_content_layer.get(); 5389 clipping_layer->AddChild(scoped_content_layer.Pass()); 5390 5391 scoped_ptr<LayerImpl> scoped_content_child_layer = 5392 LayerImpl::Create(host_impl_->active_tree(), 4); 5393 LayerImpl* content_child_layer = scoped_content_child_layer.get(); 5394 content_layer->AddChild(scoped_content_child_layer.Pass()); 5395 5396 scoped_ptr<FakeMaskLayerImpl> scoped_mask_layer = 5397 FakeMaskLayerImpl::Create(host_impl_->active_tree(), 6); 5398 FakeMaskLayerImpl* mask_layer = scoped_mask_layer.get(); 5399 content_layer->SetMaskLayer(scoped_mask_layer.PassAs<LayerImpl>()); 5400 5401 gfx::Size root_size(100, 100); 5402 root->SetBounds(root_size); 5403 root->SetContentBounds(root_size); 5404 root->SetPosition(gfx::PointF()); 5405 root->SetAnchorPoint(gfx::PointF()); 5406 5407 gfx::Rect clipping_rect(20, 10, 10, 20); 5408 clipping_layer->SetBounds(clipping_rect.size()); 5409 clipping_layer->SetContentBounds(clipping_rect.size()); 5410 clipping_layer->SetPosition(clipping_rect.origin()); 5411 clipping_layer->SetAnchorPoint(gfx::PointF()); 5412 clipping_layer->SetMasksToBounds(true); 5413 5414 gfx::Size layer_size(50, 50); 5415 content_layer->SetBounds(layer_size); 5416 content_layer->SetContentBounds(layer_size); 5417 content_layer->SetPosition(gfx::Point() - clipping_rect.OffsetFromOrigin()); 5418 content_layer->SetAnchorPoint(gfx::PointF()); 5419 content_layer->SetDrawsContent(true); 5420 5421 gfx::Size child_size(50, 50); 5422 content_child_layer->SetBounds(child_size); 5423 content_child_layer->SetContentBounds(child_size); 5424 content_child_layer->SetPosition(gfx::Point(50, 0)); 5425 content_child_layer->SetAnchorPoint(gfx::PointF()); 5426 content_child_layer->SetDrawsContent(true); 5427 5428 gfx::Size mask_size(100, 100); 5429 mask_layer->SetBounds(mask_size); 5430 mask_layer->SetContentBounds(mask_size); 5431 mask_layer->SetPosition(gfx::PointF()); 5432 mask_layer->SetAnchorPoint(gfx::PointF()); 5433 mask_layer->SetDrawsContent(true); 5434 5435 float device_scale_factor = 1.f; 5436 host_impl_->SetViewportSize(root_size); 5437 host_impl_->SetDeviceScaleFactor(device_scale_factor); 5438 { 5439 LayerTreeHostImpl::FrameData frame; 5440 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 5441 5442 ASSERT_EQ(1u, frame.render_passes.size()); 5443 ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size()); 5444 5445 // The surface is clipped to 10x20. 5446 ASSERT_EQ(DrawQuad::RENDER_PASS, 5447 frame.render_passes[0]->quad_list[0]->material); 5448 const RenderPassDrawQuad* render_pass_quad = 5449 RenderPassDrawQuad::MaterialCast(frame.render_passes[0]->quad_list[0]); 5450 EXPECT_FALSE(render_pass_quad->is_replica); 5451 EXPECT_EQ(gfx::Rect(20, 10, 10, 20).ToString(), 5452 render_pass_quad->rect.ToString()); 5453 5454 // The masked layer is 50x50, but the surface size is 10x20. So the texture 5455 // coords in the mask are scaled by 10/50 and 20/50. 5456 // The surface is clipped to (20,10) so the mask texture coords are offset 5457 // by 20/50 and 10/50 5458 EXPECT_EQ(gfx::ScaleRect(gfx::RectF(20.f, 10.f, 10.f, 20.f), 5459 1.f / 50.f).ToString(), 5460 render_pass_quad->mask_uv_rect.ToString()); 5461 5462 host_impl_->DrawLayers(&frame, base::TimeTicks::Now()); 5463 host_impl_->DidDrawAllLayers(frame); 5464 } 5465} 5466 5467class CompositorFrameMetadataTest : public LayerTreeHostImplTest { 5468 public: 5469 CompositorFrameMetadataTest() 5470 : swap_buffers_complete_(0) {} 5471 5472 virtual void OverrideSettings(LayerTreeSettings* settings) OVERRIDE { 5473 settings->compositor_frame_message = true; 5474 } 5475 virtual void OnSwapBuffersCompleteOnImplThread() OVERRIDE { 5476 swap_buffers_complete_++; 5477 } 5478 5479 int swap_buffers_complete_; 5480}; 5481 5482TEST_F(CompositorFrameMetadataTest, CompositorFrameAckCountsAsSwapComplete) { 5483 SetupRootLayerImpl(FakeLayerWithQuads::Create(host_impl_->active_tree(), 1)); 5484 { 5485 LayerTreeHostImpl::FrameData frame; 5486 EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect())); 5487 host_impl_->DrawLayers(&frame, base::TimeTicks()); 5488 host_impl_->DidDrawAllLayers(frame); 5489 } 5490 CompositorFrameAck ack; 5491 host_impl_->OnSendFrameToParentCompositorAck(ack); 5492 EXPECT_EQ(swap_buffers_complete_, 1); 5493} 5494 5495} // namespace 5496} // namespace cc 5497