// Copyright 2021 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "ash/controls/gradient_layer_delegate.h" #include "ash/controls/scroll_view_gradient_helper.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_type.h" #include "ui/gfx/geometry/rect.h" #include "ui/views/controls/scroll_view.h" #include "ui/views/test/views_test_base.h" #include "ui/views/widget/unique_widget_ptr.h" #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_utils.h" namespace ash { namespace { constexpr int kWidgetHeight = 100; constexpr int kWidgetWidth = 100; constexpr int kGradientSize = 16; // Uses ViewsTestBase because we may want to move this helper into //ui/views // in the future. class ScrollViewGradientHelperTest : public views::ViewsTestBase { public: ScrollViewGradientHelperTest() = default; ~ScrollViewGradientHelperTest() override = default; // testing::Test: void SetUp() override { ViewsTestBase::SetUp(); // Create a small widget. widget_ = std::make_unique(); views::Widget::InitParams params = CreateParams(views::Widget::InitParams::TYPE_POPUP); params.bounds = gfx::Rect(10, 10, kWidgetWidth, kWidgetHeight); widget_->Init(std::move(params)); widget_->Show(); // Add a scroll view and gradient helper. auto* contents = widget_->SetContentsView(std::make_unique()); scroll_view_ = contents->AddChildView(std::make_unique()); scroll_view_->SetBounds(0, 0, kWidgetWidth, kWidgetHeight); scroll_view_->SetPaintToLayer(ui::LAYER_NOT_DRAWN); gradient_helper_ = std::make_unique(scroll_view_, kGradientSize); } void TearDown() override { gradient_helper_.reset(); widget_.reset(); ViewsTestBase::TearDown(); } void AddScrollViewContentsWithHeight(int height) { auto contents = std::make_unique(); contents->SetSize({kWidgetWidth, height}); scroll_view_->SetContents(std::move(contents)); scroll_view_->Layout(); } bool HasGradientAtTop() { auto* gradient_layer = gradient_helper_->gradient_layer_for_test(); return !gradient_layer->start_fade_zone_bounds().IsEmpty(); } bool HasGradientAtBottom() { auto* gradient_layer = gradient_helper_->gradient_layer_for_test(); return !gradient_layer->end_fade_zone_bounds().IsEmpty(); } views::UniqueWidgetPtr widget_; views::ScrollView* scroll_view_ = nullptr; std::unique_ptr gradient_helper_; }; TEST_F(ScrollViewGradientHelperTest, NoGradientForViewThatDoesNotScroll) { // Create a short contents view, so the scroll view won't scroll. AddScrollViewContentsWithHeight(10); gradient_helper_->UpdateGradientZone(); EXPECT_FALSE(scroll_view_->layer()->layer_mask_layer()); EXPECT_FALSE(gradient_helper_->gradient_layer_for_test()); } TEST_F(ScrollViewGradientHelperTest, HasGradientForViewThatScrolls) { // Create a tall contents view. AddScrollViewContentsWithHeight(500); gradient_helper_->UpdateGradientZone(); // Gradient is shown. EXPECT_TRUE(scroll_view_->layer()->layer_mask_layer()); EXPECT_TRUE(gradient_helper_->gradient_layer_for_test()); // Shrink the contents view. scroll_view_->contents()->SetSize({kWidgetWidth, 10}); scroll_view_->Layout(); gradient_helper_->UpdateGradientZone(); // Gradient is removed. EXPECT_FALSE(scroll_view_->layer()->layer_mask_layer()); EXPECT_FALSE(gradient_helper_->gradient_layer_for_test()); } TEST_F(ScrollViewGradientHelperTest, ShowsGradientsBasedOnScrollPosition) { // Create a tall contents view. AddScrollViewContentsWithHeight(500); ASSERT_TRUE(scroll_view_->vertical_scroll_bar()); gradient_helper_->UpdateGradientZone(); // Because the scroll position is at the top, only the bottom gradient shows. EXPECT_FALSE(HasGradientAtTop()); EXPECT_TRUE(HasGradientAtBottom()); // Scroll down. Now both top and bottom should have gradients. scroll_view_->vertical_scroll_bar()->ScrollByAmount( views::ScrollBar::ScrollAmount::kNextLine); EXPECT_TRUE(HasGradientAtTop()); EXPECT_TRUE(HasGradientAtBottom()); // Scroll to end. Now only the top should have a gradient. scroll_view_->vertical_scroll_bar()->ScrollByAmount( views::ScrollBar::ScrollAmount::kEnd); EXPECT_TRUE(HasGradientAtTop()); EXPECT_FALSE(HasGradientAtBottom()); } TEST_F(ScrollViewGradientHelperTest, DeletingHelperRemovesMaskLayer) { // Create a tall contents view. AddScrollViewContentsWithHeight(500); gradient_helper_->UpdateGradientZone(); // Precondition: Mask layer exists. ASSERT_TRUE(scroll_view_->layer()->layer_mask_layer()); // Deleting the helper removes the mask layer. gradient_helper_.reset(); EXPECT_FALSE(scroll_view_->layer()->layer_mask_layer()); } } // namespace } // namespace ash