scrollbar_layer_unittest.cc revision 58537e28ecd584eab876aee8be7156509866d23a
1// Copyright 2012 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 "base/containers/hash_tables.h" 6#include "cc/animation/scrollbar_animation_controller.h" 7#include "cc/debug/test_web_graphics_context_3d.h" 8#include "cc/layers/append_quads_data.h" 9#include "cc/layers/painted_scrollbar_layer.h" 10#include "cc/layers/painted_scrollbar_layer_impl.h" 11#include "cc/layers/scrollbar_layer_interface.h" 12#include "cc/layers/solid_color_scrollbar_layer.h" 13#include "cc/layers/solid_color_scrollbar_layer_impl.h" 14#include "cc/quads/solid_color_draw_quad.h" 15#include "cc/resources/resource_update_queue.h" 16#include "cc/test/fake_impl_proxy.h" 17#include "cc/test/fake_layer_tree_host.h" 18#include "cc/test/fake_layer_tree_host_client.h" 19#include "cc/test/fake_layer_tree_host_impl.h" 20#include "cc/test/fake_painted_scrollbar_layer.h" 21#include "cc/test/fake_scrollbar.h" 22#include "cc/test/geometry_test_utils.h" 23#include "cc/test/layer_tree_test.h" 24#include "cc/test/mock_quad_culler.h" 25#include "cc/trees/layer_tree_host.h" 26#include "cc/trees/layer_tree_impl.h" 27#include "cc/trees/single_thread_proxy.h" 28#include "cc/trees/tree_synchronizer.h" 29#include "testing/gmock/include/gmock/gmock.h" 30#include "testing/gtest/include/gtest/gtest.h" 31 32namespace cc { 33namespace { 34 35LayerImpl* LayerImplForScrollAreaAndScrollbar( 36 FakeLayerTreeHost* host, 37 scoped_ptr<Scrollbar> scrollbar, 38 bool reverse_order, 39 bool use_solid_color_scrollbar, 40 int thumb_thickness) { 41 scoped_refptr<Layer> layer_tree_root = Layer::Create(); 42 scoped_refptr<Layer> child1 = Layer::Create(); 43 scoped_refptr<Layer> child2; 44 if (use_solid_color_scrollbar) { 45 const bool kIsLeftSideVerticalScrollbar = false; 46 child2 = SolidColorScrollbarLayer::Create( 47 scrollbar->Orientation(), thumb_thickness, 48 kIsLeftSideVerticalScrollbar, child1->id()); 49 } else { 50 child2 = PaintedScrollbarLayer::Create(scrollbar.Pass(), child1->id()); 51 } 52 layer_tree_root->AddChild(child1); 53 layer_tree_root->InsertChild(child2, reverse_order ? 0 : 1); 54 host->SetRootLayer(layer_tree_root); 55 return host->CommitAndCreateLayerImplTree(); 56} 57 58TEST(ScrollbarLayerTest, ResolveScrollLayerPointer) { 59 scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(); 60 scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar); 61 LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar( 62 host.get(), scrollbar.Pass(), false, false, 0); 63 64 LayerImpl* cc_child1 = layer_impl_tree_root->children()[0]; 65 PaintedScrollbarLayerImpl* cc_child2 = 66 static_cast<PaintedScrollbarLayerImpl*>( 67 layer_impl_tree_root->children()[1]); 68 69 EXPECT_EQ(cc_child1->horizontal_scrollbar_layer(), cc_child2); 70} 71 72TEST(ScrollbarLayerTest, ResolveScrollLayerPointer_ReverseOrder) { 73 scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(); 74 scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar); 75 LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar( 76 host.get(), scrollbar.Pass(), true, false, 0); 77 78 PaintedScrollbarLayerImpl* cc_child1 = 79 static_cast<PaintedScrollbarLayerImpl*>( 80 layer_impl_tree_root->children()[0]); 81 LayerImpl* cc_child2 = layer_impl_tree_root->children()[1]; 82 83 EXPECT_EQ(cc_child2->horizontal_scrollbar_layer(), cc_child1); 84} 85 86TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) { 87 scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(); 88 89 // Create and attach a non-overlay scrollbar. 90 scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar); 91 LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar( 92 host.get(), scrollbar.Pass(), false, false, 0); 93 PaintedScrollbarLayerImpl* scrollbar_layer_impl = 94 static_cast<PaintedScrollbarLayerImpl*>( 95 layer_impl_tree_root->children()[1]); 96 97 // When the scrollbar is not an overlay scrollbar, the scroll should be 98 // responded to on the main thread as the compositor does not yet implement 99 // scrollbar scrolling. 100 EXPECT_EQ(InputHandler::ScrollOnMainThread, 101 scrollbar_layer_impl->TryScroll(gfx::Point(0, 0), 102 InputHandler::Gesture)); 103 104 // Create and attach an overlay scrollbar. 105 scrollbar.reset(new FakeScrollbar(false, false, true)); 106 107 layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar( 108 host.get(), scrollbar.Pass(), false, false, 0); 109 scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( 110 layer_impl_tree_root->children()[1]); 111 112 // The user shouldn't be able to drag an overlay scrollbar and the scroll 113 // may be handled in the compositor. 114 EXPECT_EQ(InputHandler::ScrollIgnored, 115 scrollbar_layer_impl->TryScroll(gfx::Point(0, 0), 116 InputHandler::Gesture)); 117} 118 119TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) { 120 scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(); 121 122 scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar); 123 scoped_refptr<Layer> layer_tree_root = Layer::Create(); 124 scoped_refptr<Layer> content_layer = Layer::Create(); 125 scoped_refptr<Layer> scrollbar_layer = 126 PaintedScrollbarLayer::Create(scrollbar.Pass(), layer_tree_root->id()); 127 128 layer_tree_root->SetScrollable(true); 129 layer_tree_root->SetScrollOffset(gfx::Vector2d(10, 20)); 130 layer_tree_root->SetMaxScrollOffset(gfx::Vector2d(30, 50)); 131 layer_tree_root->SetBounds(gfx::Size(100, 200)); 132 content_layer->SetBounds(gfx::Size(100, 200)); 133 134 host->SetRootLayer(layer_tree_root); 135 layer_tree_root->AddChild(content_layer); 136 layer_tree_root->AddChild(scrollbar_layer); 137 138 layer_tree_root->SavePaintProperties(); 139 content_layer->SavePaintProperties(); 140 141 LayerImpl* layer_impl_tree_root = host->CommitAndCreateLayerImplTree(); 142 143 ScrollbarLayerImplBase* cc_scrollbar_layer = 144 static_cast<PaintedScrollbarLayerImpl*>( 145 layer_impl_tree_root->children()[1]); 146 147 EXPECT_EQ(10.f, cc_scrollbar_layer->current_pos()); 148 EXPECT_EQ(30, cc_scrollbar_layer->maximum()); 149 150 layer_tree_root->SetScrollOffset(gfx::Vector2d(100, 200)); 151 layer_tree_root->SetMaxScrollOffset(gfx::Vector2d(300, 500)); 152 layer_tree_root->SetBounds(gfx::Size(1000, 2000)); 153 layer_tree_root->SavePaintProperties(); 154 content_layer->SetBounds(gfx::Size(1000, 2000)); 155 content_layer->SavePaintProperties(); 156 157 ScrollbarAnimationController* scrollbar_controller = 158 layer_impl_tree_root->scrollbar_animation_controller(); 159 layer_impl_tree_root = host->CommitAndCreateLayerImplTree(); 160 EXPECT_EQ(scrollbar_controller, 161 layer_impl_tree_root->scrollbar_animation_controller()); 162 163 EXPECT_EQ(100.f, cc_scrollbar_layer->current_pos()); 164 EXPECT_EQ(300, cc_scrollbar_layer->maximum()); 165 166 layer_impl_tree_root->ScrollBy(gfx::Vector2d(12, 34)); 167 168 EXPECT_EQ(112.f, cc_scrollbar_layer->current_pos()); 169 EXPECT_EQ(300, cc_scrollbar_layer->maximum()); 170} 171 172TEST(ScrollbarLayerTest, ThumbRect) { 173 scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(); 174 scoped_refptr<Layer> root_layer = Layer::Create(); 175 scoped_refptr<Layer> content_layer = Layer::Create(); 176 scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer = 177 FakePaintedScrollbarLayer::Create(false, true, root_layer->id()); 178 179 root_layer->SetScrollable(true); 180 root_layer->SetMaxScrollOffset(gfx::Vector2d(80, 0)); 181 root_layer->SetBounds(gfx::Size(100, 50)); 182 content_layer->SetBounds(gfx::Size(100, 50)); 183 184 host->SetRootLayer(root_layer); 185 root_layer->AddChild(content_layer); 186 root_layer->AddChild(scrollbar_layer); 187 188 root_layer->SetScrollOffset(gfx::Vector2d(0, 0)); 189 scrollbar_layer->SetBounds(gfx::Size(70, 10)); 190 scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(20, 10)); 191 scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10)); 192 scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10); 193 scrollbar_layer->fake_scrollbar()->set_thumb_length(4); 194 scrollbar_layer->UpdateThumbAndTrackGeometry(); 195 LayerImpl* root_layer_impl = NULL; 196 PaintedScrollbarLayerImpl* scrollbar_layer_impl = NULL; 197 198 // Thumb is at the edge of the scrollbar (should be inset to 199 // the start of the track within the scrollbar layer's 200 // position). 201 scrollbar_layer->UpdateThumbAndTrackGeometry(); 202 root_layer_impl = host->CommitAndCreateLayerImplTree(); 203 scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( 204 root_layer_impl->children()[1]); 205 EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(), 206 scrollbar_layer_impl->ComputeThumbQuadRect().ToString()); 207 208 // Under-scroll (thumb position should clamp and be unchanged). 209 root_layer->SetScrollOffset(gfx::Vector2d(-5, 0)); 210 211 scrollbar_layer->UpdateThumbAndTrackGeometry(); 212 root_layer_impl = host->CommitAndCreateLayerImplTree(); 213 scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( 214 root_layer_impl->children()[1]); 215 EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(), 216 scrollbar_layer_impl->ComputeThumbQuadRect().ToString()); 217 218 // Over-scroll (thumb position should clamp on the far side). 219 root_layer->SetScrollOffset(gfx::Vector2d(85, 0)); 220 221 scrollbar_layer->UpdateThumbAndTrackGeometry(); 222 root_layer_impl = host->CommitAndCreateLayerImplTree(); 223 scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( 224 root_layer_impl->children()[1]); 225 EXPECT_EQ(gfx::Rect(56, 0, 4, 10).ToString(), 226 scrollbar_layer_impl->ComputeThumbQuadRect().ToString()); 227 228 // Change thumb thickness and length. 229 scrollbar_layer->fake_scrollbar()->set_thumb_thickness(4); 230 scrollbar_layer->fake_scrollbar()->set_thumb_length(6); 231 232 scrollbar_layer->UpdateThumbAndTrackGeometry(); 233 root_layer_impl = host->CommitAndCreateLayerImplTree(); 234 scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( 235 root_layer_impl->children()[1]); 236 EXPECT_EQ(gfx::Rect(54, 0, 6, 4).ToString(), 237 scrollbar_layer_impl->ComputeThumbQuadRect().ToString()); 238 239 // Shrink the scrollbar layer to cover only the track. 240 scrollbar_layer->SetBounds(gfx::Size(50, 10)); 241 scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(30, 10)); 242 scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10)); 243 244 scrollbar_layer->UpdateThumbAndTrackGeometry(); 245 root_layer_impl = host->CommitAndCreateLayerImplTree(); 246 scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( 247 root_layer_impl->children()[1]); 248 EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(), 249 scrollbar_layer_impl->ComputeThumbQuadRect().ToString()); 250 251 // Shrink the track in the non-scrolling dimension so that it only covers the 252 // middle third of the scrollbar layer (this does not affect the thumb 253 // position). 254 scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 12, 50, 6)); 255 256 scrollbar_layer->UpdateThumbAndTrackGeometry(); 257 root_layer_impl = host->CommitAndCreateLayerImplTree(); 258 scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( 259 root_layer_impl->children()[1]); 260 EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(), 261 scrollbar_layer_impl->ComputeThumbQuadRect().ToString()); 262} 263 264TEST(ScrollbarLayerTest, SolidColorDrawQuads) { 265 const int kThumbThickness = 3; 266 const int kTrackLength = 100; 267 268 LayerTreeSettings layer_tree_settings; 269 layer_tree_settings.solid_color_scrollbar_thickness_dip = kThumbThickness; 270 scoped_ptr<FakeLayerTreeHost> host = 271 FakeLayerTreeHost::Create(layer_tree_settings); 272 273 scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true)); 274 LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar( 275 host.get(), scrollbar.Pass(), false, true, kThumbThickness); 276 ScrollbarLayerImplBase* scrollbar_layer_impl = 277 static_cast<SolidColorScrollbarLayerImpl*>( 278 layer_impl_tree_root->children()[1]); 279 scrollbar_layer_impl->SetBounds(gfx::Size(kTrackLength, kThumbThickness)); 280 scrollbar_layer_impl->SetCurrentPos(10.f); 281 scrollbar_layer_impl->SetMaximum(100); 282 scrollbar_layer_impl->SetVisibleToTotalLengthRatio(0.4f); 283 284 // Thickness should be overridden to 3. 285 { 286 MockQuadCuller quad_culler; 287 AppendQuadsData data; 288 scrollbar_layer_impl->AppendQuads(&quad_culler, &data); 289 290 const QuadList& quads = quad_culler.quad_list(); 291 ASSERT_EQ(1u, quads.size()); 292 EXPECT_EQ(DrawQuad::SOLID_COLOR, quads[0]->material); 293 EXPECT_RECT_EQ(gfx::Rect(6, 0, 40, 3), quads[0]->rect); 294 } 295 296 // Contents scale should scale the draw quad. 297 scrollbar_layer_impl->draw_properties().contents_scale_x = 2.f; 298 scrollbar_layer_impl->draw_properties().contents_scale_y = 2.f; 299 { 300 MockQuadCuller quad_culler; 301 AppendQuadsData data; 302 scrollbar_layer_impl->AppendQuads(&quad_culler, &data); 303 304 const QuadList& quads = quad_culler.quad_list(); 305 ASSERT_EQ(1u, quads.size()); 306 EXPECT_EQ(DrawQuad::SOLID_COLOR, quads[0]->material); 307 EXPECT_RECT_EQ(gfx::Rect(12, 0, 80, 6), quads[0]->rect); 308 } 309 scrollbar_layer_impl->draw_properties().contents_scale_x = 1.f; 310 scrollbar_layer_impl->draw_properties().contents_scale_y = 1.f; 311 312 // For solid color scrollbars, position and size should reflect the 313 // current viewport state. 314 scrollbar_layer_impl->SetVisibleToTotalLengthRatio(0.2f); 315 { 316 MockQuadCuller quad_culler; 317 AppendQuadsData data; 318 scrollbar_layer_impl->AppendQuads(&quad_culler, &data); 319 320 const QuadList& quads = quad_culler.quad_list(); 321 ASSERT_EQ(1u, quads.size()); 322 EXPECT_EQ(DrawQuad::SOLID_COLOR, quads[0]->material); 323 EXPECT_RECT_EQ(gfx::Rect(8, 0, 20, 3), quads[0]->rect); 324 } 325} 326 327TEST(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) { 328 const int kThumbThickness = 3; 329 const int kTrackLength = 10; 330 331 LayerTreeSettings layer_tree_settings; 332 layer_tree_settings.solid_color_scrollbar_thickness_dip = 3; 333 scoped_ptr<FakeLayerTreeHost> host = 334 FakeLayerTreeHost::Create(layer_tree_settings); 335 336 scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true)); 337 LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar( 338 host.get(), scrollbar.Pass(), false, true, kThumbThickness); 339 ScrollbarLayerImplBase* scrollbar_layer_impl = 340 static_cast<PaintedScrollbarLayerImpl*>( 341 layer_impl_tree_root->children()[1]); 342 343 scrollbar_layer_impl->SetBounds(gfx::Size(kTrackLength, kThumbThickness)); 344 scrollbar_layer_impl->SetCurrentPos(4.f); 345 scrollbar_layer_impl->SetMaximum(8); 346 347 layer_impl_tree_root->SetScrollable(true); 348 layer_impl_tree_root->SetHorizontalScrollbarLayer(scrollbar_layer_impl); 349 layer_impl_tree_root->SetMaxScrollOffset(gfx::Vector2d(8, 8)); 350 layer_impl_tree_root->SetBounds(gfx::Size(2, 2)); 351 layer_impl_tree_root->ScrollBy(gfx::Vector2dF(4.f, 0.f)); 352 353 { 354 MockQuadCuller quad_culler; 355 AppendQuadsData data; 356 scrollbar_layer_impl->AppendQuads(&quad_culler, &data); 357 358 const QuadList& quads = quad_culler.quad_list(); 359 ASSERT_EQ(1u, quads.size()); 360 EXPECT_EQ(DrawQuad::SOLID_COLOR, quads[0]->material); 361 EXPECT_RECT_EQ(gfx::Rect(3, 0, 3, 3), quads[0]->rect); 362 } 363} 364 365class ScrollbarLayerSolidColorThumbTest : public testing::Test { 366 public: 367 ScrollbarLayerSolidColorThumbTest() { 368 LayerTreeSettings layer_tree_settings; 369 layer_tree_settings.solid_color_scrollbars = true; 370 host_impl_.reset(new FakeLayerTreeHostImpl(layer_tree_settings, &proxy_)); 371 372 const int kThumbThickness = 3; 373 const bool kIsLeftSideVerticalScrollbar = false; 374 375 horizontal_scrollbar_layer_ = SolidColorScrollbarLayerImpl::Create( 376 host_impl_->active_tree(), 1, HORIZONTAL, kThumbThickness, 377 kIsLeftSideVerticalScrollbar); 378 vertical_scrollbar_layer_ = SolidColorScrollbarLayerImpl::Create( 379 host_impl_->active_tree(), 2, VERTICAL, kThumbThickness, 380 kIsLeftSideVerticalScrollbar); 381 } 382 383 protected: 384 FakeImplProxy proxy_; 385 scoped_ptr<FakeLayerTreeHostImpl> host_impl_; 386 scoped_ptr<SolidColorScrollbarLayerImpl> horizontal_scrollbar_layer_; 387 scoped_ptr<SolidColorScrollbarLayerImpl> vertical_scrollbar_layer_; 388}; 389 390TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbLength) { 391 horizontal_scrollbar_layer_->SetCurrentPos(0); 392 horizontal_scrollbar_layer_->SetMaximum(10); 393 394 // Simple case - one third of the scrollable area is visible, so the thumb 395 // should be one third as long as the track. 396 horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(0.33f); 397 horizontal_scrollbar_layer_->SetBounds(gfx::Size(100, 3)); 398 EXPECT_EQ(33, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width()); 399 400 // The thumb's length should never be less than its thickness. 401 horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(0.01f); 402 horizontal_scrollbar_layer_->SetBounds(gfx::Size(100, 3)); 403 EXPECT_EQ(3, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width()); 404} 405 406TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbPosition) { 407 horizontal_scrollbar_layer_->SetBounds(gfx::Size(100, 3)); 408 horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(0.1f); 409 410 horizontal_scrollbar_layer_->SetCurrentPos(0); 411 horizontal_scrollbar_layer_->SetMaximum(100); 412 EXPECT_EQ(0, horizontal_scrollbar_layer_->ComputeThumbQuadRect().x()); 413 EXPECT_EQ(10, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width()); 414 415 horizontal_scrollbar_layer_->SetCurrentPos(100); 416 // The thumb is 10px long and the track is 100px, so the maximum thumb 417 // position is 90px. 418 EXPECT_EQ(90, horizontal_scrollbar_layer_->ComputeThumbQuadRect().x()); 419 420 horizontal_scrollbar_layer_->SetCurrentPos(80); 421 // The scroll position is 80% of the maximum, so the thumb's position should 422 // be at 80% of its maximum or 72px. 423 EXPECT_EQ(72, horizontal_scrollbar_layer_->ComputeThumbQuadRect().x()); 424} 425 426TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbVerticalAdjust) { 427 SolidColorScrollbarLayerImpl* layers[2] = 428 { horizontal_scrollbar_layer_.get(), vertical_scrollbar_layer_.get() }; 429 for (size_t i = 0; i < 2; ++i) { 430 layers[i]->SetVisibleToTotalLengthRatio(0.2f); 431 layers[i]->SetCurrentPos(25); 432 layers[i]->SetMaximum(100); 433 } 434 layers[0]->SetBounds(gfx::Size(100, 3)); 435 layers[1]->SetBounds(gfx::Size(3, 100)); 436 437 EXPECT_RECT_EQ(gfx::RectF(20.f, 0.f, 20.f, 3.f), 438 horizontal_scrollbar_layer_->ComputeThumbQuadRect()); 439 EXPECT_RECT_EQ(gfx::RectF(0.f, 20.f, 3.f, 20.f), 440 vertical_scrollbar_layer_->ComputeThumbQuadRect()); 441 442 horizontal_scrollbar_layer_->SetVerticalAdjust(10.f); 443 vertical_scrollbar_layer_->SetVerticalAdjust(10.f); 444 445 // The vertical adjustment factor has two effects: 446 // 1.) Moves the horizontal scrollbar down 447 // 2.) Increases the vertical scrollbar's effective track length which both 448 // increases the thumb's length and its position within the track. 449 EXPECT_RECT_EQ(gfx::Rect(20.f, 10.f, 20.f, 3.f), 450 horizontal_scrollbar_layer_->ComputeThumbQuadRect()); 451 EXPECT_RECT_EQ(gfx::Rect(0.f, 22, 3.f, 22.f), 452 vertical_scrollbar_layer_->ComputeThumbQuadRect()); 453} 454 455class ScrollbarLayerTestMaxTextureSize : public LayerTreeTest { 456 public: 457 ScrollbarLayerTestMaxTextureSize() {} 458 459 void SetScrollbarBounds(gfx::Size bounds) { bounds_ = bounds; } 460 461 virtual void BeginTest() OVERRIDE { 462 scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar); 463 scrollbar_layer_ = PaintedScrollbarLayer::Create(scrollbar.Pass(), 1); 464 scrollbar_layer_->SetLayerTreeHost(layer_tree_host()); 465 scrollbar_layer_->SetBounds(bounds_); 466 layer_tree_host()->root_layer()->AddChild(scrollbar_layer_); 467 468 scroll_layer_ = Layer::Create(); 469 scrollbar_layer_->SetScrollLayerId(scroll_layer_->id()); 470 layer_tree_host()->root_layer()->AddChild(scroll_layer_); 471 472 PostSetNeedsCommitToMainThread(); 473 } 474 475 virtual void DidCommitAndDrawFrame() OVERRIDE { 476 const int kMaxTextureSize = 477 layer_tree_host()->GetRendererCapabilities().max_texture_size; 478 479 // Check first that we're actually testing something. 480 EXPECT_GT(scrollbar_layer_->bounds().width(), kMaxTextureSize); 481 482 EXPECT_EQ(scrollbar_layer_->content_bounds().width(), 483 kMaxTextureSize - 1); 484 EXPECT_EQ(scrollbar_layer_->content_bounds().height(), 485 kMaxTextureSize - 1); 486 487 EndTest(); 488 } 489 490 virtual void AfterTest() OVERRIDE {} 491 492 private: 493 scoped_refptr<PaintedScrollbarLayer> scrollbar_layer_; 494 scoped_refptr<Layer> scroll_layer_; 495 gfx::Size bounds_; 496}; 497 498TEST_F(ScrollbarLayerTestMaxTextureSize, DirectRenderer) { 499 scoped_ptr<TestWebGraphicsContext3D> context = 500 TestWebGraphicsContext3D::Create(); 501 int max_size = 0; 502 context->getIntegerv(GL_MAX_TEXTURE_SIZE, &max_size); 503 SetScrollbarBounds(gfx::Size(max_size + 100, max_size + 100)); 504 RunTest(true, false, true); 505} 506 507TEST_F(ScrollbarLayerTestMaxTextureSize, DelegatingRenderer) { 508 scoped_ptr<TestWebGraphicsContext3D> context = 509 TestWebGraphicsContext3D::Create(); 510 int max_size = 0; 511 context->getIntegerv(GL_MAX_TEXTURE_SIZE, &max_size); 512 SetScrollbarBounds(gfx::Size(max_size + 100, max_size + 100)); 513 RunTest(true, true, true); 514} 515 516class MockLayerTreeHost : public LayerTreeHost { 517 public: 518 MockLayerTreeHost(LayerTreeHostClient* client, 519 const LayerTreeSettings& settings) 520 : LayerTreeHost(client, settings), 521 next_id_(1), 522 total_ui_resource_created_(0), 523 total_ui_resource_deleted_(0) { 524 Initialize(NULL); 525 } 526 527 virtual UIResourceId CreateUIResource(UIResourceClient* content) OVERRIDE { 528 total_ui_resource_created_++; 529 UIResourceId nid = next_id_++; 530 ui_resource_bitmap_map_.insert( 531 std::make_pair(nid, content->GetBitmap(nid, false))); 532 return nid; 533 } 534 535 // Deletes a UI resource. May safely be called more than once. 536 virtual void DeleteUIResource(UIResourceId id) OVERRIDE { 537 UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id); 538 if (iter != ui_resource_bitmap_map_.end()) { 539 ui_resource_bitmap_map_.erase(iter); 540 total_ui_resource_deleted_++; 541 } 542 } 543 544 size_t UIResourceCount() { return ui_resource_bitmap_map_.size(); } 545 int TotalUIResourceDeleted() { return total_ui_resource_deleted_; } 546 int TotalUIResourceCreated() { return total_ui_resource_created_; } 547 548 gfx::Size ui_resource_size(UIResourceId id) { 549 UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id); 550 if (iter != ui_resource_bitmap_map_.end()) 551 return iter->second.GetSize(); 552 return gfx::Size(); 553 } 554 555 private: 556 typedef base::hash_map<UIResourceId, UIResourceBitmap> 557 UIResourceBitmapMap; 558 UIResourceBitmapMap ui_resource_bitmap_map_; 559 560 int next_id_; 561 int total_ui_resource_created_; 562 int total_ui_resource_deleted_; 563}; 564 565 566class ScrollbarLayerTestResourceCreation : public testing::Test { 567 public: 568 ScrollbarLayerTestResourceCreation() 569 : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {} 570 571 void TestResourceUpload(int num_updates, 572 size_t expected_resources, 573 int expected_created, 574 int expected_deleted, 575 bool use_solid_color_scrollbar) { 576 layer_tree_host_.reset( 577 new MockLayerTreeHost(&fake_client_, layer_tree_settings_)); 578 579 scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, false)); 580 scoped_refptr<Layer> layer_tree_root = Layer::Create(); 581 scoped_refptr<Layer> content_layer = Layer::Create(); 582 scoped_refptr<Layer> scrollbar_layer; 583 if (use_solid_color_scrollbar) { 584 const int kThumbThickness = 3; 585 const bool kIsLeftSideVerticalScrollbar = false; 586 scrollbar_layer = 587 SolidColorScrollbarLayer::Create(scrollbar->Orientation(), 588 kThumbThickness, 589 kIsLeftSideVerticalScrollbar, 590 layer_tree_root->id()); 591 } else { 592 scrollbar_layer = PaintedScrollbarLayer::Create(scrollbar.Pass(), 593 layer_tree_root->id()); 594 } 595 layer_tree_root->AddChild(content_layer); 596 layer_tree_root->AddChild(scrollbar_layer); 597 598 layer_tree_host_->InitializeOutputSurfaceIfNeeded(); 599 layer_tree_host_->SetRootLayer(layer_tree_root); 600 601 scrollbar_layer->SetIsDrawable(true); 602 scrollbar_layer->SetBounds(gfx::Size(100, 100)); 603 layer_tree_root->SetScrollOffset(gfx::Vector2d(10, 20)); 604 layer_tree_root->SetMaxScrollOffset(gfx::Vector2d(30, 50)); 605 layer_tree_root->SetBounds(gfx::Size(100, 200)); 606 content_layer->SetBounds(gfx::Size(100, 200)); 607 scrollbar_layer->draw_properties().content_bounds = gfx::Size(100, 200); 608 scrollbar_layer->draw_properties().visible_content_rect = 609 gfx::Rect(0, 0, 100, 200); 610 scrollbar_layer->CreateRenderSurface(); 611 scrollbar_layer->draw_properties().render_target = scrollbar_layer.get(); 612 613 testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get()); 614 EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get()); 615 616 ResourceUpdateQueue queue; 617 OcclusionTracker occlusion_tracker(gfx::Rect(), false); 618 619 scrollbar_layer->SavePaintProperties(); 620 for (int update_counter = 0; update_counter < num_updates; update_counter++) 621 scrollbar_layer->Update(&queue, &occlusion_tracker); 622 623 // A non-solid-color scrollbar should have requested two textures. 624 EXPECT_EQ(expected_resources, layer_tree_host_->UIResourceCount()); 625 EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated()); 626 EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted()); 627 628 testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get()); 629 630 scrollbar_layer->ClearRenderSurface(); 631 } 632 633 protected: 634 FakeLayerTreeHostClient fake_client_; 635 LayerTreeSettings layer_tree_settings_; 636 scoped_ptr<MockLayerTreeHost> layer_tree_host_; 637}; 638 639TEST_F(ScrollbarLayerTestResourceCreation, ResourceUpload) { 640 bool use_solid_color_scrollbars = false; 641 TestResourceUpload(0, 0, 0, 0, use_solid_color_scrollbars); 642 int num_updates[3] = {1, 5, 10}; 643 for (int j = 0; j < 3; j++) { 644 TestResourceUpload(num_updates[j], 645 2, 646 num_updates[j] * 2, 647 (num_updates[j] - 1) * 2, 648 use_solid_color_scrollbars); 649 } 650} 651 652TEST_F(ScrollbarLayerTestResourceCreation, SolidColorNoResourceUpload) { 653 bool use_solid_color_scrollbars = true; 654 TestResourceUpload(0, 0, 0, 0, use_solid_color_scrollbars); 655 TestResourceUpload(1, 0, 0, 0, use_solid_color_scrollbars); 656} 657 658class ScaledScrollbarLayerTestResourceCreation : public testing::Test { 659 public: 660 ScaledScrollbarLayerTestResourceCreation() 661 : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {} 662 663 void TestResourceUpload(const float test_scale) { 664 layer_tree_host_.reset( 665 new MockLayerTreeHost(&fake_client_, layer_tree_settings_)); 666 667 gfx::Point scrollbar_location(0, 185); 668 scoped_refptr<Layer> layer_tree_root = Layer::Create(); 669 scoped_refptr<Layer> content_layer = Layer::Create(); 670 scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer = 671 FakePaintedScrollbarLayer::Create(false, true, layer_tree_root->id()); 672 673 layer_tree_root->AddChild(content_layer); 674 layer_tree_root->AddChild(scrollbar_layer); 675 676 layer_tree_host_->InitializeOutputSurfaceIfNeeded(); 677 layer_tree_host_->SetRootLayer(layer_tree_root); 678 679 scrollbar_layer->SetIsDrawable(true); 680 scrollbar_layer->SetBounds(gfx::Size(100, 15)); 681 scrollbar_layer->SetPosition(scrollbar_location); 682 layer_tree_root->SetBounds(gfx::Size(100, 200)); 683 content_layer->SetBounds(gfx::Size(100, 200)); 684 gfx::SizeF scaled_size = 685 gfx::ScaleSize(scrollbar_layer->bounds(), test_scale, test_scale); 686 gfx::PointF scaled_location = 687 gfx::ScalePoint(scrollbar_layer->position(), test_scale, test_scale); 688 scrollbar_layer->draw_properties().content_bounds = 689 gfx::Size(scaled_size.width(), scaled_size.height()); 690 scrollbar_layer->draw_properties().contents_scale_x = test_scale; 691 scrollbar_layer->draw_properties().contents_scale_y = test_scale; 692 scrollbar_layer->draw_properties().visible_content_rect = 693 gfx::Rect(scaled_location.x(), 694 scaled_location.y(), 695 scaled_size.width(), 696 scaled_size.height()); 697 scrollbar_layer->CreateRenderSurface(); 698 scrollbar_layer->draw_properties().render_target = scrollbar_layer.get(); 699 700 testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get()); 701 EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get()); 702 703 ResourceUpdateQueue queue; 704 OcclusionTracker occlusion_tracker(gfx::Rect(), false); 705 scrollbar_layer->SavePaintProperties(); 706 scrollbar_layer->Update(&queue, &occlusion_tracker); 707 708 // Verify that we have not generated any content uploads that are larger 709 // than their destination textures. 710 711 gfx::Size track_size = layer_tree_host_->ui_resource_size( 712 scrollbar_layer->track_resource_id()); 713 gfx::Size thumb_size = layer_tree_host_->ui_resource_size( 714 scrollbar_layer->thumb_resource_id()); 715 716 EXPECT_LE(track_size.width(), scrollbar_layer->content_bounds().width()); 717 EXPECT_LE(track_size.height(), scrollbar_layer->content_bounds().height()); 718 EXPECT_LE(thumb_size.width(), scrollbar_layer->content_bounds().width()); 719 EXPECT_LE(thumb_size.height(), scrollbar_layer->content_bounds().height()); 720 721 testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get()); 722 723 scrollbar_layer->ClearRenderSurface(); 724 } 725 726 protected: 727 FakeLayerTreeHostClient fake_client_; 728 LayerTreeSettings layer_tree_settings_; 729 scoped_ptr<MockLayerTreeHost> layer_tree_host_; 730}; 731 732TEST_F(ScaledScrollbarLayerTestResourceCreation, ScaledResourceUpload) { 733 // Pick a test scale that moves the scrollbar's (non-zero) position to 734 // a non-pixel-aligned location. 735 TestResourceUpload(.041f); 736 TestResourceUpload(1.41f); 737 TestResourceUpload(4.1f); 738} 739 740} // namespace 741} // namespace cc 742