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