Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/views/controls/scroll_view.h" | 5 #include "ui/views/controls/scroll_view.h" |
| 6 | 6 |
| 7 #include "base/macros.h" | 7 #include "base/macros.h" |
| 8 #include "base/run_loop.h" | |
| 9 #include "base/test/test_timeouts.h" | |
| 10 #include "base/threading/thread_task_runner_handle.h" | |
| 8 #include "testing/gtest/include/gtest/gtest.h" | 11 #include "testing/gtest/include/gtest/gtest.h" |
| 9 #include "ui/views/border.h" | 12 #include "ui/views/border.h" |
| 10 #include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h" | 13 #include "ui/views/controls/scrollbar/base_scroll_bar_thumb.h" |
| 11 #include "ui/views/controls/scrollbar/native_scroll_bar.h" | 14 #include "ui/views/controls/scrollbar/native_scroll_bar.h" |
| 12 #include "ui/views/controls/scrollbar/native_scroll_bar_views.h" | 15 #include "ui/views/controls/scrollbar/native_scroll_bar_views.h" |
| 13 #include "ui/views/controls/scrollbar/overlay_scroll_bar.h" | 16 #include "ui/views/controls/scrollbar/overlay_scroll_bar.h" |
| 14 #include "ui/views/test/test_views.h" | 17 #include "ui/views/test/test_views.h" |
| 15 #include "ui/views/test/widget_test.h" | 18 #include "ui/views/test/widget_test.h" |
| 16 | 19 |
| 17 #if defined(OS_MACOSX) | 20 #if defined(OS_MACOSX) |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 39 } | 42 } |
| 40 | 43 |
| 41 const base::Timer& GetScrollBarTimer(ScrollBarOrientation orientation) { | 44 const base::Timer& GetScrollBarTimer(ScrollBarOrientation orientation) { |
| 42 return GetBaseScrollBar(orientation)->repeater_.timer_for_testing(); | 45 return GetBaseScrollBar(orientation)->repeater_.timer_for_testing(); |
| 43 } | 46 } |
| 44 | 47 |
| 45 BaseScrollBarThumb* GetScrollBarThumb(ScrollBarOrientation orientation) { | 48 BaseScrollBarThumb* GetScrollBarThumb(ScrollBarOrientation orientation) { |
| 46 return GetBaseScrollBar(orientation)->thumb_; | 49 return GetBaseScrollBar(orientation)->thumb_; |
| 47 } | 50 } |
| 48 | 51 |
| 52 gfx::Point IntegralViewOffset() { | |
| 53 return gfx::Point() - gfx::ScrollOffsetToFlooredVector2d(CurrentOffset()); | |
| 54 } | |
| 55 | |
| 56 gfx::ScrollOffset CurrentOffset() { return scroll_view_->CurrentOffset(); } | |
| 57 | |
| 49 View* corner_view() { return scroll_view_->corner_view_; } | 58 View* corner_view() { return scroll_view_->corner_view_; } |
| 59 View* contents_viewport() { return scroll_view_->contents_viewport_; } | |
| 50 | 60 |
| 51 private: | 61 private: |
| 52 ScrollView* scroll_view_; | 62 ScrollView* scroll_view_; |
| 53 | 63 |
| 54 DISALLOW_COPY_AND_ASSIGN(ScrollViewTestApi); | 64 DISALLOW_COPY_AND_ASSIGN(ScrollViewTestApi); |
| 55 }; | 65 }; |
| 56 | 66 |
| 57 } // namespace test | 67 } // namespace test |
| 58 | 68 |
| 59 namespace { | 69 namespace { |
| 60 | 70 |
| 61 const int kWidth = 100; | 71 const int kWidth = 100; |
| 62 const int kMinHeight = 50; | 72 const int kMinHeight = 50; |
| 63 const int kMaxHeight = 100; | 73 const int kMaxHeight = 100; |
| 64 | 74 |
| 65 // View implementation that allows setting the preferred size. | 75 // View implementation that allows setting the preferred size. |
| 66 class CustomView : public View { | 76 class CustomView : public View { |
| 67 public: | 77 public: |
| 68 CustomView() {} | 78 CustomView() {} |
| 69 | 79 |
| 70 void SetPreferredSize(const gfx::Size& size) { | 80 void SetPreferredSize(const gfx::Size& size) { |
| 71 preferred_size_ = size; | 81 preferred_size_ = size; |
| 72 PreferredSizeChanged(); | 82 PreferredSizeChanged(); |
| 73 } | 83 } |
| 74 | 84 |
| 85 const gfx::Point last_location() const { return last_location_; } | |
| 86 | |
| 75 gfx::Size GetPreferredSize() const override { return preferred_size_; } | 87 gfx::Size GetPreferredSize() const override { return preferred_size_; } |
| 76 | 88 |
| 77 void Layout() override { | 89 void Layout() override { |
| 78 gfx::Size pref = GetPreferredSize(); | 90 gfx::Size pref = GetPreferredSize(); |
| 79 int width = pref.width(); | 91 int width = pref.width(); |
| 80 int height = pref.height(); | 92 int height = pref.height(); |
| 81 if (parent()) { | 93 if (parent()) { |
| 82 width = std::max(parent()->width(), width); | 94 width = std::max(parent()->width(), width); |
| 83 height = std::max(parent()->height(), height); | 95 height = std::max(parent()->height(), height); |
| 84 } | 96 } |
| 85 SetBounds(x(), y(), width, height); | 97 SetBounds(x(), y(), width, height); |
| 86 } | 98 } |
| 87 | 99 |
| 100 bool OnMousePressed(const ui::MouseEvent& event) override { | |
| 101 last_location_ = event.location(); | |
| 102 return true; | |
| 103 } | |
| 104 | |
| 88 private: | 105 private: |
| 89 gfx::Size preferred_size_; | 106 gfx::Size preferred_size_; |
| 107 gfx::Point last_location_; | |
| 90 | 108 |
| 91 DISALLOW_COPY_AND_ASSIGN(CustomView); | 109 DISALLOW_COPY_AND_ASSIGN(CustomView); |
| 92 }; | 110 }; |
| 93 | 111 |
| 94 void CheckScrollbarVisibility(const ScrollView& scroll_view, | 112 void CheckScrollbarVisibility(const ScrollView& scroll_view, |
| 95 ScrollBarOrientation orientation, | 113 ScrollBarOrientation orientation, |
| 96 bool should_be_visible) { | 114 bool should_be_visible) { |
| 97 const ScrollBar* scrollbar = orientation == HORIZONTAL | 115 const ScrollBar* scrollbar = orientation == HORIZONTAL |
| 98 ? scroll_view.horizontal_scroll_bar() | 116 ? scroll_view.horizontal_scroll_bar() |
| 99 : scroll_view.vertical_scroll_bar(); | 117 : scroll_view.vertical_scroll_bar(); |
| 100 if (should_be_visible) { | 118 if (should_be_visible) { |
| 101 ASSERT_TRUE(scrollbar); | 119 ASSERT_TRUE(scrollbar); |
| 102 EXPECT_TRUE(scrollbar->visible()); | 120 EXPECT_TRUE(scrollbar->visible()); |
| 103 } else { | 121 } else { |
| 104 EXPECT_TRUE(!scrollbar || !scrollbar->visible()); | 122 EXPECT_TRUE(!scrollbar || !scrollbar->visible()); |
| 105 } | 123 } |
| 106 } | 124 } |
| 107 | 125 |
| 108 ui::MouseEvent TestLeftMouseAt(const gfx::Point& location, ui::EventType type) { | 126 ui::MouseEvent TestLeftMouseAt(const gfx::Point& location, ui::EventType type) { |
| 109 return ui::MouseEvent(type, location, location, base::TimeTicks(), | 127 return ui::MouseEvent(type, location, location, base::TimeTicks(), |
| 110 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); | 128 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); |
| 111 } | 129 } |
| 112 | 130 |
| 113 } // namespace | 131 } // namespace |
| 114 | 132 |
| 115 using test::ScrollViewTestApi; | 133 using test::ScrollViewTestApi; |
| 116 | 134 |
| 117 // Test harness that includes a Widget to help test ui::Event handling. | 135 // Test harness that includes a Widget to help test ui::Event handling. |
| 118 class WidgetScrollViewTest : public test::WidgetTest { | 136 class WidgetScrollViewTest : public test::WidgetTest, |
| 137 public ui::CompositorObserver { | |
| 119 public: | 138 public: |
| 120 static const int kDefaultHeight = 100; | 139 static const int kDefaultHeight = 100; |
| 121 static const int kDefaultWidth = 100; | 140 static const int kDefaultWidth = 100; |
| 122 | 141 |
| 123 WidgetScrollViewTest() { | 142 WidgetScrollViewTest() { |
| 124 #if defined(OS_MACOSX) | 143 #if defined(OS_MACOSX) |
| 125 // Disable scrollbar hiding (i.e. disable overlay scrollbars) by default. | 144 // Disable scrollbar hiding (i.e. disable overlay scrollbars) by default. |
| 126 scroller_style_.reset(new ui::test::ScopedPreferredScrollerStyle(false)); | 145 scroller_style_.reset(new ui::test::ScopedPreferredScrollerStyle(false)); |
| 127 #endif | 146 #endif |
| 128 } | 147 } |
| 129 | 148 |
| 130 // Adds a ScrollView with a contents view of the given |size| and does layout. | 149 // Adds a ScrollView with the given |contents_view| and does layout. |
| 131 ScrollView* AddScrollViewWithContentSize(const gfx::Size& contents_size) { | 150 ScrollView* AddScrollViewWithContents(View* contents, |
| 151 bool commit_layers = true) { | |
| 132 const gfx::Rect default_bounds(50, 50, kDefaultWidth, kDefaultHeight); | 152 const gfx::Rect default_bounds(50, 50, kDefaultWidth, kDefaultHeight); |
| 133 widget_ = CreateTopLevelFramelessPlatformWidget(); | 153 widget_ = CreateTopLevelFramelessPlatformWidget(); |
| 134 | 154 |
| 135 ScrollView* scroll_view = new ScrollView(); | 155 ScrollView* scroll_view = new ScrollView(); |
| 136 View* contents = new View; | |
| 137 scroll_view->SetContents(contents); | 156 scroll_view->SetContents(contents); |
| 138 contents->SetSize(contents_size); | |
| 139 | 157 |
| 140 widget_->SetBounds(default_bounds); | 158 widget_->SetBounds(default_bounds); |
| 141 widget_->Show(); | 159 widget_->Show(); |
| 142 | 160 |
| 143 widget_->SetContentsView(scroll_view); | 161 widget_->SetContentsView(scroll_view); |
| 144 scroll_view->Layout(); | 162 scroll_view->Layout(); |
| 163 | |
| 164 widget_->GetCompositor()->AddObserver(this); | |
| 165 | |
| 166 // Ensure the Compositor has committed layer changes before attempting to | |
| 167 // use them for impl-side scrolling. Note that simply RunUntilIdle() works | |
| 168 // when tests are run in isolation, but compositor scheduling can interact | |
| 169 // between test runs in the general case. | |
| 170 if (commit_layers) | |
| 171 WaitForCommit(); | |
| 145 return scroll_view; | 172 return scroll_view; |
| 146 } | 173 } |
| 147 | 174 |
| 175 // Adds a ScrollView with a contents view of the given |size| and does layout. | |
| 176 ScrollView* AddScrollViewWithContentSize(const gfx::Size& contents_size, | |
| 177 bool commit_layers = true) { | |
| 178 View* contents = new View; | |
| 179 contents->SetSize(contents_size); | |
| 180 return AddScrollViewWithContents(contents, commit_layers); | |
| 181 } | |
| 182 | |
| 183 // Wait for a commit to be observed on the compositor. | |
| 184 void WaitForCommit() { | |
| 185 base::RunLoop run_loop; | |
| 186 quit_closure_ = run_loop.QuitClosure(); | |
| 187 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
| 188 FROM_HERE, quit_closure_, TestTimeouts::action_timeout()); | |
| 189 run_loop.Run(); | |
| 190 EXPECT_TRUE(quit_closure_.is_null()) << "Timed out waiting for a commit."; | |
| 191 } | |
| 192 | |
| 193 void TestClickAt(const gfx::Point& location) { | |
| 194 ui::MouseEvent press(TestLeftMouseAt(location, ui::ET_MOUSE_PRESSED)); | |
| 195 ui::MouseEvent release(TestLeftMouseAt(location, ui::ET_MOUSE_RELEASED)); | |
| 196 widget_->OnMouseEvent(&press); | |
| 197 widget_->OnMouseEvent(&release); | |
| 198 } | |
| 199 | |
| 148 // testing::Test: | 200 // testing::Test: |
| 149 void TearDown() override { | 201 void TearDown() override { |
| 202 widget_->GetCompositor()->RemoveObserver(this); | |
| 150 if (widget_) | 203 if (widget_) |
| 151 widget_->CloseNow(); | 204 widget_->CloseNow(); |
| 152 WidgetTest::TearDown(); | 205 WidgetTest::TearDown(); |
| 153 } | 206 } |
| 154 | 207 |
| 155 private: | 208 private: |
| 209 // ui::CompositorObserver: | |
| 210 void OnCompositingDidCommit(ui::Compositor* compositor) override { | |
| 211 quit_closure_.Run(); | |
| 212 quit_closure_.Reset(); | |
| 213 } | |
| 214 void OnCompositingStarted(ui::Compositor* compositor, | |
| 215 base::TimeTicks start_time) override {} | |
| 216 void OnCompositingEnded(ui::Compositor* compositor) override {} | |
| 217 void OnCompositingAborted(ui::Compositor* compositor) override {} | |
| 218 void OnCompositingLockStateChanged(ui::Compositor* compositor) override {} | |
| 219 void OnCompositingShuttingDown(ui::Compositor* compositor) override {} | |
| 220 | |
| 156 Widget* widget_ = nullptr; | 221 Widget* widget_ = nullptr; |
| 157 | 222 |
| 223 base::Closure quit_closure_; | |
| 224 | |
| 158 #if defined(OS_MACOSX) | 225 #if defined(OS_MACOSX) |
| 159 std::unique_ptr<ui::test::ScopedPreferredScrollerStyle> scroller_style_; | 226 std::unique_ptr<ui::test::ScopedPreferredScrollerStyle> scroller_style_; |
| 160 #endif | 227 #endif |
| 161 | 228 |
| 162 DISALLOW_COPY_AND_ASSIGN(WidgetScrollViewTest); | 229 DISALLOW_COPY_AND_ASSIGN(WidgetScrollViewTest); |
| 163 }; | 230 }; |
| 164 | 231 |
| 165 const int WidgetScrollViewTest::kDefaultHeight; | 232 const int WidgetScrollViewTest::kDefaultHeight; |
| 166 const int WidgetScrollViewTest::kDefaultWidth; | 233 const int WidgetScrollViewTest::kDefaultWidth; |
| 167 | 234 |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 297 scroll_view.SetHeader(header); | 364 scroll_view.SetHeader(header); |
| 298 View* header_parent = header->parent(); | 365 View* header_parent = header->parent(); |
| 299 scroll_view.SetContents(contents); | 366 scroll_view.SetContents(contents); |
| 300 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); | 367 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); |
| 301 scroll_view.Layout(); | 368 scroll_view.Layout(); |
| 302 // |header|s preferred size is empty, which should result in all space going | 369 // |header|s preferred size is empty, which should result in all space going |
| 303 // to contents. | 370 // to contents. |
| 304 EXPECT_EQ("0,0 100x0", header->parent()->bounds().ToString()); | 371 EXPECT_EQ("0,0 100x0", header->parent()->bounds().ToString()); |
| 305 EXPECT_EQ("0,0 100x100", contents->parent()->bounds().ToString()); | 372 EXPECT_EQ("0,0 100x100", contents->parent()->bounds().ToString()); |
| 306 | 373 |
| 374 // With layered scrolling, ScrollView::Layout() will impose a size on the | |
| 375 // contents that fills the viewport. Since the test view doesn't have its own | |
| 376 // Layout, reset it in this case so that adding a header doesn't shift the | |
| 377 // contents down and require scrollbars. | |
| 378 if (contents->layer()) { | |
| 379 EXPECT_EQ("0,0 100x100", contents->bounds().ToString()); | |
| 380 contents->SetBoundsRect(gfx::Rect()); | |
| 381 } | |
| 382 EXPECT_EQ("0,0 0x0", contents->bounds().ToString()); | |
| 383 | |
| 307 // Get the header a height of 20. | 384 // Get the header a height of 20. |
| 308 header->SetPreferredSize(gfx::Size(10, 20)); | 385 header->SetPreferredSize(gfx::Size(10, 20)); |
| 309 EXPECT_EQ("0,0 100x20", header->parent()->bounds().ToString()); | 386 EXPECT_EQ("0,0 100x20", header->parent()->bounds().ToString()); |
| 310 EXPECT_EQ("0,20 100x80", contents->parent()->bounds().ToString()); | 387 EXPECT_EQ("0,20 100x80", contents->parent()->bounds().ToString()); |
| 388 if (contents->layer()) { | |
| 389 EXPECT_EQ("0,0 100x80", contents->bounds().ToString()); | |
| 390 contents->SetBoundsRect(gfx::Rect()); | |
| 391 } | |
| 392 EXPECT_EQ("0,0 0x0", contents->bounds().ToString()); | |
| 311 | 393 |
| 312 // Remove the header. | 394 // Remove the header. |
| 313 scroll_view.SetHeader(NULL); | 395 scroll_view.SetHeader(NULL); |
| 314 // SetHeader(NULL) deletes header. | 396 // SetHeader(NULL) deletes header. |
| 315 header = NULL; | 397 header = NULL; |
| 316 EXPECT_EQ("0,0 100x0", header_parent->bounds().ToString()); | 398 EXPECT_EQ("0,0 100x0", header_parent->bounds().ToString()); |
| 317 EXPECT_EQ("0,0 100x100", contents->parent()->bounds().ToString()); | 399 EXPECT_EQ("0,0 100x100", contents->parent()->bounds().ToString()); |
| 318 } | 400 } |
| 319 | 401 |
| 320 // Verifies the scrollbars are added as necessary when a header is present. | 402 // Verifies the scrollbars are added as necessary when a header is present. |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 378 EXPECT_EQ(20, header->parent()->height()); | 460 EXPECT_EQ(20, header->parent()->height()); |
| 379 ASSERT_TRUE(scroll_view.horizontal_scroll_bar() != NULL); | 461 ASSERT_TRUE(scroll_view.horizontal_scroll_bar() != NULL); |
| 380 EXPECT_TRUE(scroll_view.horizontal_scroll_bar()->visible()); | 462 EXPECT_TRUE(scroll_view.horizontal_scroll_bar()->visible()); |
| 381 ASSERT_TRUE(scroll_view.vertical_scroll_bar() != NULL); | 463 ASSERT_TRUE(scroll_view.vertical_scroll_bar() != NULL); |
| 382 EXPECT_TRUE(scroll_view.vertical_scroll_bar()->visible()); | 464 EXPECT_TRUE(scroll_view.vertical_scroll_bar()->visible()); |
| 383 } | 465 } |
| 384 | 466 |
| 385 // Verifies the header scrolls horizontally with the content. | 467 // Verifies the header scrolls horizontally with the content. |
| 386 TEST(ScrollViewTest, HeaderScrollsWithContent) { | 468 TEST(ScrollViewTest, HeaderScrollsWithContent) { |
| 387 ScrollView scroll_view; | 469 ScrollView scroll_view; |
| 470 ScrollViewTestApi test_api(&scroll_view); | |
| 388 CustomView* contents = new CustomView; | 471 CustomView* contents = new CustomView; |
| 389 scroll_view.SetContents(contents); | 472 scroll_view.SetContents(contents); |
| 390 contents->SetPreferredSize(gfx::Size(500, 500)); | 473 contents->SetPreferredSize(gfx::Size(500, 500)); |
| 391 | 474 |
| 392 CustomView* header = new CustomView; | 475 CustomView* header = new CustomView; |
| 393 scroll_view.SetHeader(header); | 476 scroll_view.SetHeader(header); |
| 394 header->SetPreferredSize(gfx::Size(500, 20)); | 477 header->SetPreferredSize(gfx::Size(500, 20)); |
| 395 | 478 |
| 396 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); | 479 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); |
| 397 EXPECT_EQ("0,0", contents->bounds().origin().ToString()); | 480 EXPECT_EQ("0,0", test_api.IntegralViewOffset().ToString()); |
| 398 EXPECT_EQ("0,0", header->bounds().origin().ToString()); | 481 EXPECT_EQ("0,0", header->bounds().origin().ToString()); |
| 399 | 482 |
| 400 // Scroll the horizontal scrollbar. | 483 // Scroll the horizontal scrollbar. |
| 401 ASSERT_TRUE(scroll_view.horizontal_scroll_bar()); | 484 ASSERT_TRUE(scroll_view.horizontal_scroll_bar()); |
| 402 scroll_view.ScrollToPosition( | 485 scroll_view.ScrollToPosition( |
| 403 const_cast<ScrollBar*>(scroll_view.horizontal_scroll_bar()), 1); | 486 const_cast<ScrollBar*>(scroll_view.horizontal_scroll_bar()), 1); |
| 404 EXPECT_EQ("-1,0", contents->bounds().origin().ToString()); | 487 EXPECT_EQ("-1,0", test_api.IntegralViewOffset().ToString()); |
| 405 EXPECT_EQ("-1,0", header->bounds().origin().ToString()); | 488 EXPECT_EQ("-1,0", header->bounds().origin().ToString()); |
| 406 | 489 |
| 407 // Scrolling the vertical scrollbar shouldn't effect the header. | 490 // Scrolling the vertical scrollbar shouldn't effect the header. |
| 408 ASSERT_TRUE(scroll_view.vertical_scroll_bar()); | 491 ASSERT_TRUE(scroll_view.vertical_scroll_bar()); |
| 409 scroll_view.ScrollToPosition( | 492 scroll_view.ScrollToPosition( |
| 410 const_cast<ScrollBar*>(scroll_view.vertical_scroll_bar()), 1); | 493 const_cast<ScrollBar*>(scroll_view.vertical_scroll_bar()), 1); |
| 411 EXPECT_EQ("-1,-1", contents->bounds().origin().ToString()); | 494 EXPECT_EQ("-1,-1", test_api.IntegralViewOffset().ToString()); |
| 412 EXPECT_EQ("-1,0", header->bounds().origin().ToString()); | 495 EXPECT_EQ("-1,0", header->bounds().origin().ToString()); |
| 413 } | 496 } |
| 414 | 497 |
| 415 // Verifies ScrollRectToVisible() on the child works. | 498 // Verifies ScrollRectToVisible() on the child works. |
| 416 TEST(ScrollViewTest, ScrollRectToVisible) { | 499 TEST(ScrollViewTest, ScrollRectToVisible) { |
| 500 #if defined(OS_MACOSX) | |
| 501 ui::test::ScopedPreferredScrollerStyle scroller_style_override(false); | |
| 502 #endif | |
| 417 ScrollView scroll_view; | 503 ScrollView scroll_view; |
| 504 ScrollViewTestApi test_api(&scroll_view); | |
| 418 CustomView* contents = new CustomView; | 505 CustomView* contents = new CustomView; |
| 419 scroll_view.SetContents(contents); | 506 scroll_view.SetContents(contents); |
| 420 contents->SetPreferredSize(gfx::Size(500, 1000)); | 507 contents->SetPreferredSize(gfx::Size(500, 1000)); |
| 421 | 508 |
| 422 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); | 509 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); |
| 423 scroll_view.Layout(); | 510 scroll_view.Layout(); |
| 424 EXPECT_EQ("0,0", contents->bounds().origin().ToString()); | 511 EXPECT_EQ("0,0", test_api.IntegralViewOffset().ToString()); |
| 425 | 512 |
| 426 // Scroll to y=405 height=10, this should make the y position of the content | 513 // Scroll to y=405 height=10, this should make the y position of the content |
| 427 // at (405 + 10) - viewport_height (scroll region bottom aligned). | 514 // at (405 + 10) - viewport_height (scroll region bottom aligned). |
| 428 contents->ScrollRectToVisible(gfx::Rect(0, 405, 10, 10)); | 515 contents->ScrollRectToVisible(gfx::Rect(0, 405, 10, 10)); |
| 429 const int viewport_height = contents->parent()->height(); | 516 const int viewport_height = test_api.contents_viewport()->height(); |
| 430 EXPECT_EQ(-(415 - viewport_height), contents->y()); | 517 |
| 518 // Expect there to be a horizontal scrollbar, making the viewport shorter. | |
| 519 EXPECT_LT(viewport_height, 100); | |
| 520 | |
| 521 gfx::ScrollOffset offset = test_api.CurrentOffset(); | |
| 522 EXPECT_EQ(415 - viewport_height, offset.y()); | |
| 431 | 523 |
| 432 // Scroll to the current y-location and 10x10; should do nothing. | 524 // Scroll to the current y-location and 10x10; should do nothing. |
| 433 contents->ScrollRectToVisible(gfx::Rect(0, -contents->y(), 10, 10)); | 525 contents->ScrollRectToVisible(gfx::Rect(0, offset.y(), 10, 10)); |
| 434 EXPECT_EQ(-(415 - viewport_height), contents->y()); | 526 EXPECT_EQ(415 - viewport_height, test_api.CurrentOffset().y()); |
| 435 } | 527 } |
| 436 | 528 |
| 437 // Verifies ClipHeightTo() uses the height of the content when it is between the | 529 // Verifies ClipHeightTo() uses the height of the content when it is between the |
| 438 // minimum and maximum height values. | 530 // minimum and maximum height values. |
| 439 TEST(ScrollViewTest, ClipHeightToNormalContentHeight) { | 531 TEST(ScrollViewTest, ClipHeightToNormalContentHeight) { |
| 440 ScrollView scroll_view; | 532 ScrollView scroll_view; |
| 441 | 533 |
| 442 scroll_view.ClipHeightTo(kMinHeight, kMaxHeight); | 534 scroll_view.ClipHeightTo(kMinHeight, kMaxHeight); |
| 443 | 535 |
| 444 const int kNormalContentHeight = 75; | 536 const int kNormalContentHeight = 75; |
| 445 scroll_view.SetContents( | 537 scroll_view.SetContents( |
| 446 new views::StaticSizedView(gfx::Size(kWidth, kNormalContentHeight))); | 538 new views::StaticSizedView(gfx::Size(kWidth, kNormalContentHeight))); |
| 447 | 539 |
| 448 EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight), | 540 EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight), |
| 449 scroll_view.GetPreferredSize()); | 541 scroll_view.GetPreferredSize()); |
| 450 | 542 |
| 451 scroll_view.SizeToPreferredSize(); | 543 scroll_view.SizeToPreferredSize(); |
| 452 scroll_view.Layout(); | 544 scroll_view.Layout(); |
| 453 | 545 |
| 454 EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight), | 546 EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight), |
| 455 scroll_view.contents()->size()); | 547 scroll_view.contents()->size()); |
| 456 EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight), scroll_view.size()); | 548 EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight), scroll_view.size()); |
| 457 } | 549 } |
| 458 | 550 |
| 459 // Verifies ClipHeightTo() uses the minimum height when the content is shorter | 551 // Verifies ClipHeightTo() uses the minimum height when the content is shorter |
| 460 // thamn the minimum height value. | 552 // than the minimum height value. |
| 461 TEST(ScrollViewTest, ClipHeightToShortContentHeight) { | 553 TEST(ScrollViewTest, ClipHeightToShortContentHeight) { |
| 462 ScrollView scroll_view; | 554 ScrollView scroll_view; |
| 463 | 555 |
| 464 scroll_view.ClipHeightTo(kMinHeight, kMaxHeight); | 556 scroll_view.ClipHeightTo(kMinHeight, kMaxHeight); |
| 465 | 557 |
| 466 const int kShortContentHeight = 10; | 558 const int kShortContentHeight = 10; |
| 467 scroll_view.SetContents( | 559 View* contents = |
| 468 new views::StaticSizedView(gfx::Size(kWidth, kShortContentHeight))); | 560 new views::StaticSizedView(gfx::Size(kWidth, kShortContentHeight)); |
| 561 scroll_view.SetContents(contents); | |
| 469 | 562 |
| 470 EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view.GetPreferredSize()); | 563 EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view.GetPreferredSize()); |
| 471 | 564 |
| 472 scroll_view.SizeToPreferredSize(); | 565 scroll_view.SizeToPreferredSize(); |
| 473 scroll_view.Layout(); | 566 scroll_view.Layout(); |
| 474 | 567 |
| 475 EXPECT_EQ(gfx::Size(kWidth, kShortContentHeight), | 568 // Layered scrolling requires the contents to fill the viewport. |
| 476 scroll_view.contents()->size()); | 569 if (contents->layer()) { |
| 570 EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view.contents()->size()); | |
|
tapted
2016/08/05 07:12:31
Technically.... this violates StaticSizedView::Get
| |
| 571 } else { | |
| 572 EXPECT_EQ(gfx::Size(kWidth, kShortContentHeight), | |
| 573 scroll_view.contents()->size()); | |
| 574 } | |
| 477 EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view.size()); | 575 EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view.size()); |
| 478 } | 576 } |
| 479 | 577 |
| 480 // Verifies ClipHeightTo() uses the maximum height when the content is longer | 578 // Verifies ClipHeightTo() uses the maximum height when the content is longer |
| 481 // thamn the maximum height value. | 579 // thamn the maximum height value. |
| 482 TEST(ScrollViewTest, ClipHeightToTallContentHeight) { | 580 TEST(ScrollViewTest, ClipHeightToTallContentHeight) { |
| 483 ScrollView scroll_view; | 581 ScrollView scroll_view; |
| 484 | 582 |
| 485 // Use a scrollbar that is disabled by default, so the width of the content is | 583 // Use a scrollbar that is disabled by default, so the width of the content is |
| 486 // not affected. | 584 // not affected. |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 654 | 752 |
| 655 // While the mouse is pressed, timer should trigger more scroll events. | 753 // While the mouse is pressed, timer should trigger more scroll events. |
| 656 EXPECT_TRUE(timer.IsRunning()); | 754 EXPECT_TRUE(timer.IsRunning()); |
| 657 | 755 |
| 658 // Upon release timer should stop (and scroll position should remain). | 756 // Upon release timer should stop (and scroll position should remain). |
| 659 scroll_bar->OnMouseEvent(&release); | 757 scroll_bar->OnMouseEvent(&release); |
| 660 EXPECT_FALSE(timer.IsRunning()); | 758 EXPECT_FALSE(timer.IsRunning()); |
| 661 EXPECT_EQ(kDefaultHeight, scroll_view->GetVisibleRect().y()); | 759 EXPECT_EQ(kDefaultHeight, scroll_view->GetVisibleRect().y()); |
| 662 } | 760 } |
| 663 | 761 |
| 762 // Test that LocatedEvents are transformed correctly when scrolling. | |
| 763 TEST_F(WidgetScrollViewTest, EventLocation) { | |
| 764 // Set up with both scrollers. | |
| 765 CustomView* contents = new CustomView; | |
| 766 contents->SetPreferredSize(gfx::Size(kDefaultHeight * 5, kDefaultHeight * 5)); | |
| 767 AddScrollViewWithContents(contents); | |
| 768 | |
| 769 const gfx::Point location_in_widget(10, 10); | |
| 770 | |
| 771 // Click without scrolling. | |
| 772 TestClickAt(location_in_widget); | |
| 773 EXPECT_EQ(location_in_widget, contents->last_location()); | |
| 774 | |
| 775 // Scroll down a page. | |
| 776 contents->ScrollRectToVisible( | |
| 777 gfx::Rect(0, kDefaultHeight, 1, kDefaultHeight)); | |
| 778 TestClickAt(location_in_widget); | |
| 779 EXPECT_EQ(gfx::Point(10, 10 + kDefaultHeight), contents->last_location()); | |
| 780 | |
| 781 // Scroll right a page (and back up). | |
| 782 contents->ScrollRectToVisible(gfx::Rect(kDefaultWidth, 0, kDefaultWidth, 1)); | |
| 783 TestClickAt(location_in_widget); | |
| 784 EXPECT_EQ(gfx::Point(10 + kDefaultWidth, 10), contents->last_location()); | |
| 785 | |
| 786 // Scroll both directions. | |
| 787 contents->ScrollRectToVisible( | |
| 788 gfx::Rect(kDefaultWidth, kDefaultHeight, kDefaultWidth, kDefaultHeight)); | |
| 789 TestClickAt(location_in_widget); | |
| 790 EXPECT_EQ(gfx::Point(10 + kDefaultWidth, 10 + kDefaultHeight), | |
| 791 contents->last_location()); | |
| 792 } | |
| 793 | |
| 794 // Test that views scroll offsets are in sync with the layer scroll offsets. | |
| 795 TEST_F(WidgetScrollViewTest, ScrollOffsetUsingLayers) { | |
| 796 // Set up with a vertical scroller, but don't commit the layer changes yet. | |
| 797 ScrollView* scroll_view = | |
| 798 AddScrollViewWithContentSize(gfx::Size(10, kDefaultHeight * 5), false); | |
| 799 ScrollViewTestApi test_api(scroll_view); | |
| 800 | |
| 801 EXPECT_EQ(gfx::ScrollOffset(0, 0), test_api.CurrentOffset()); | |
| 802 | |
| 803 // UI code may request a scroll before layer changes are committed. | |
| 804 gfx::Rect offset(0, kDefaultHeight * 2, 1, kDefaultHeight); | |
| 805 scroll_view->contents()->ScrollRectToVisible(offset); | |
| 806 EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), test_api.CurrentOffset()); | |
| 807 | |
| 808 // The following only makes sense when layered scrolling is enabled. | |
| 809 View* container = scroll_view->contents(); | |
| 810 #if defined(OS_MACOSX) | |
| 811 // Sanity check: Mac should always scroll with layers. | |
| 812 EXPECT_TRUE(container->layer()); | |
| 813 #endif | |
| 814 if (!container->layer()) | |
| 815 return; | |
| 816 | |
| 817 // Container and viewport should have layers. | |
| 818 EXPECT_TRUE(container->layer()); | |
| 819 EXPECT_TRUE(test_api.contents_viewport()->layer()); | |
| 820 | |
| 821 // In a Widget, so there should be a compositor. | |
| 822 ui::Compositor* compositor = container->layer()->GetCompositor(); | |
| 823 EXPECT_TRUE(compositor); | |
| 824 | |
| 825 // But setting on the impl side should fail since the layer isn't committed. | |
| 826 int layer_id = container->layer()->cc_layer_for_testing()->id(); | |
| 827 EXPECT_FALSE(compositor->ScrollLayerTo(layer_id, gfx::ScrollOffset(0, 0))); | |
| 828 EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), test_api.CurrentOffset()); | |
| 829 | |
| 830 WaitForCommit(); | |
| 831 EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), test_api.CurrentOffset()); | |
| 832 | |
| 833 // Upon commit, the impl side should report the same value too. | |
| 834 gfx::ScrollOffset impl_offset; | |
| 835 EXPECT_TRUE(compositor->GetScrollOffsetForLayer(layer_id, &impl_offset)); | |
| 836 EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), impl_offset); | |
| 837 | |
| 838 // Now impl-side scrolling should work, and also update the ScrollView. | |
| 839 offset.set_y(kDefaultHeight * 3); | |
| 840 EXPECT_TRUE( | |
| 841 compositor->ScrollLayerTo(layer_id, gfx::ScrollOffset(0, offset.y()))); | |
| 842 EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), test_api.CurrentOffset()); | |
| 843 | |
| 844 // Scroll via ScrollView API. Should be reflected on the impl side. | |
| 845 offset.set_y(kDefaultHeight * 4); | |
| 846 scroll_view->contents()->ScrollRectToVisible(offset); | |
| 847 EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), test_api.CurrentOffset()); | |
| 848 | |
| 849 EXPECT_TRUE(compositor->GetScrollOffsetForLayer(layer_id, &impl_offset)); | |
| 850 EXPECT_EQ(gfx::ScrollOffset(0, offset.y()), impl_offset); | |
| 851 } | |
| 852 | |
| 664 } // namespace views | 853 } // namespace views |
| OLD | NEW |