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