summaryrefslogtreecommitdiffstats
path: root/chromium/cc/input
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/cc/input')
-rw-r--r--chromium/cc/input/input_handler.h4
-rw-r--r--chromium/cc/input/scrollbar.h26
-rw-r--r--chromium/cc/input/scrollbar_animation_controller.cc3
-rw-r--r--chromium/cc/input/scrollbar_animation_controller_unittest.cc229
-rw-r--r--chromium/cc/input/scrollbar_controller.cc370
-rw-r--r--chromium/cc/input/scrollbar_controller.h62
-rw-r--r--chromium/cc/input/single_scrollbar_animation_controller_thinning.cc3
-rw-r--r--chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc59
8 files changed, 486 insertions, 270 deletions
diff --git a/chromium/cc/input/input_handler.h b/chromium/cc/input/input_handler.h
index e7794a5be53..f39e0062ffe 100644
--- a/chromium/cc/input/input_handler.h
+++ b/chromium/cc/input/input_handler.h
@@ -198,8 +198,8 @@ class CC_EXPORT InputHandler {
virtual InputHandlerPointerResult MouseMoveAt(
const gfx::Point& mouse_position) = 0;
- virtual InputHandlerPointerResult MouseDown(
- const gfx::PointF& mouse_position) = 0;
+ virtual InputHandlerPointerResult MouseDown(const gfx::PointF& mouse_position,
+ bool shift_modifier) = 0;
virtual InputHandlerPointerResult MouseUp(
const gfx::PointF& mouse_position) = 0;
virtual void MouseLeave() = 0;
diff --git a/chromium/cc/input/scrollbar.h b/chromium/cc/input/scrollbar.h
index c63c800b1e4..4c739c69dba 100644
--- a/chromium/cc/input/scrollbar.h
+++ b/chromium/cc/input/scrollbar.h
@@ -20,10 +20,16 @@ static constexpr float kAutoscrollMultiplier = 20.f;
static constexpr base::TimeDelta kInitialAutoscrollTimerDelay =
base::TimeDelta::FromMilliseconds(250);
+// Constants used to figure the how far out in the non-scrolling direction
+// should trigger the thumb to snap back to its origin. These calculations are
+// based on observing the behavior of the MSVC8 main window scrollbar + some
+// guessing/extrapolation.
+static constexpr int kOffSideMultiplier = 8;
+static constexpr int kDefaultWinScrollbarThickness = 17;
+
namespace cc {
enum ScrollbarOrientation { HORIZONTAL, VERTICAL };
-enum ScrollDirection { SCROLL_BACKWARD, SCROLL_FORWARD };
enum ScrollbarPart {
THUMB,
@@ -45,17 +51,29 @@ class Scrollbar {
virtual gfx::Point Location() const = 0;
virtual bool IsOverlay() const = 0;
virtual bool HasThumb() const = 0;
+ virtual bool SupportsDragSnapBack() const = 0;
virtual int ThumbThickness() const = 0;
virtual int ThumbLength() const = 0;
+
+ // Returns the track rect relative to the scrollbar's origin.
virtual gfx::Rect TrackRect() const = 0;
+ // Returns the back button rect relative to the scrollbar's origin.
virtual gfx::Rect BackButtonRect() const = 0;
+ // Returns the forward button rect relative to the scrollbar's origin.
virtual gfx::Rect ForwardButtonRect() const = 0;
+
virtual float ThumbOpacity() const = 0;
virtual bool HasTickmarks() const = 0;
+
+ // Whether we need to repaint the part. Only THUMB and TRACK are supported.
+ // For TRACK, the return value means that the track, any buttons or tickmarks
+ // need repaint.
virtual bool NeedsPaintPart(ScrollbarPart part) const = 0;
- virtual void PaintPart(PaintCanvas* canvas,
- ScrollbarPart part,
- const gfx::Rect& content_rect) = 0;
+ // Paints the part. Only THUMB, TRACK and TICKMARKS are supported. When TRACK
+ // is specified, track, buttons and tickmarks will be painted. The canvas's
+ // coordinate space is relative to the part's origin.
+ virtual void PaintPart(PaintCanvas* canvas, ScrollbarPart part) = 0;
+
virtual bool UsesNinePatchThumbResource() const = 0;
virtual gfx::Size NinePatchThumbCanvasSize() const = 0;
virtual gfx::Rect NinePatchThumbAperture() const = 0;
diff --git a/chromium/cc/input/scrollbar_animation_controller.cc b/chromium/cc/input/scrollbar_animation_controller.cc
index bed51a0282d..60d7ecb8f31 100644
--- a/chromium/cc/input/scrollbar_animation_controller.cc
+++ b/chromium/cc/input/scrollbar_animation_controller.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include "base/bind.h"
+#include "base/numerics/ranges.h"
#include "base/time/time.h"
#include "cc/trees/layer_tree_impl.h"
@@ -162,7 +163,7 @@ float ScrollbarAnimationController::AnimationProgressAtTime(
base::TimeTicks now) {
base::TimeDelta delta = now - last_awaken_time_;
float progress = delta.InSecondsF() / fade_duration_.InSecondsF();
- return std::max(std::min(progress, 1.f), 0.f);
+ return base::ClampToRange(progress, 0.0f, 1.0f);
}
void ScrollbarAnimationController::RunAnimationFrame(float progress) {
diff --git a/chromium/cc/input/scrollbar_animation_controller_unittest.cc b/chromium/cc/input/scrollbar_animation_controller_unittest.cc
index 0836aeb1afa..d88bbdbf5b5 100644
--- a/chromium/cc/input/scrollbar_animation_controller_unittest.cc
+++ b/chromium/cc/input/scrollbar_animation_controller_unittest.cc
@@ -5,10 +5,8 @@
#include "cc/input/scrollbar_animation_controller.h"
#include "cc/layers/solid_color_scrollbar_layer_impl.h"
-#include "cc/test/fake_impl_task_runner_provider.h"
-#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
-#include "cc/test/test_task_graph_runner.h"
+#include "cc/test/layer_tree_impl_test_base.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -58,11 +56,11 @@ class MockScrollbarAnimationControllerClient
LayerTreeHostImpl* host_impl_;
};
-class ScrollbarAnimationControllerAuraOverlayTest : public testing::Test {
+class ScrollbarAnimationControllerAuraOverlayTest
+ : public LayerTreeImplTestBase,
+ public testing::Test {
public:
- ScrollbarAnimationControllerAuraOverlayTest()
- : host_impl_(&task_runner_provider_, &task_graph_runner_),
- client_(&host_impl_) {}
+ ScrollbarAnimationControllerAuraOverlayTest() : client_(host_impl()) {}
void ExpectScrollbarsOpacity(float opacity) {
EXPECT_FLOAT_EQ(opacity, v_scrollbar_layer_->Opacity());
@@ -75,57 +73,47 @@ class ScrollbarAnimationControllerAuraOverlayTest : public testing::Test {
const base::TimeDelta kThinningDuration = base::TimeDelta::FromSeconds(2);
void SetUp() override {
- std::unique_ptr<LayerImpl> scroll_layer =
- LayerImpl::Create(host_impl_.active_tree(), 1);
- std::unique_ptr<LayerImpl> clip =
- LayerImpl::Create(host_impl_.active_tree(), 2);
- clip_layer_ = clip.get();
- scroll_layer->SetElementId(
- LayerIdToElementIdForTesting(scroll_layer->id()));
- LayerImpl* scroll_layer_ptr = scroll_layer.get();
-
const int kTrackStart = 0;
const int kTrackLength = 100;
const bool kIsLeftSideVerticalScrollbar = false;
- const bool kIsOverlayScrollbar = true;
-
- std::unique_ptr<SolidColorScrollbarLayerImpl> h_scrollbar =
- SolidColorScrollbarLayerImpl::Create(
- host_impl_.active_tree(), 3, HORIZONTAL, kThumbThickness,
- kTrackStart, kIsLeftSideVerticalScrollbar, kIsOverlayScrollbar);
- h_scrollbar->test_properties()->opacity = 0.0f;
- std::unique_ptr<SolidColorScrollbarLayerImpl> v_scrollbar =
- SolidColorScrollbarLayerImpl::Create(
- host_impl_.active_tree(), 4, VERTICAL, kThumbThickness, kTrackStart,
- kIsLeftSideVerticalScrollbar, kIsOverlayScrollbar);
- v_scrollbar->test_properties()->opacity = 0.0f;
- v_scrollbar_layer_ = v_scrollbar.get();
- h_scrollbar_layer_ = h_scrollbar.get();
-
- scroll_layer->test_properties()->AddChild(std::move(v_scrollbar));
- scroll_layer->test_properties()->AddChild(std::move(h_scrollbar));
- clip_layer_->test_properties()->AddChild(std::move(scroll_layer));
- host_impl_.active_tree()->SetRootLayerForTesting(std::move(clip));
+
+ scroll_layer_ = AddLayer<LayerImpl>();
+ h_scrollbar_layer_ = AddLayer<SolidColorScrollbarLayerImpl>(
+ HORIZONTAL, kThumbThickness, kTrackStart, kIsLeftSideVerticalScrollbar);
+ v_scrollbar_layer_ = AddLayer<SolidColorScrollbarLayerImpl>(
+ VERTICAL, kThumbThickness, kTrackStart, kIsLeftSideVerticalScrollbar);
+ SetElementIdsForTesting();
+
+ clip_layer_ = root_layer();
+ clip_layer_->SetBounds(gfx::Size(100, 100));
+
+ scroll_layer_->SetScrollable(gfx::Size(100, 100));
+ scroll_layer_->SetBounds(gfx::Size(200, 200));
+ CopyProperties(clip_layer_, scroll_layer_);
+ CreateTransformNode(scroll_layer_);
+ CreateScrollNode(scroll_layer_);
v_scrollbar_layer_->SetBounds(gfx::Size(kThumbThickness, kTrackLength));
- v_scrollbar_layer_->test_properties()->position = gfx::PointF(90, 0);
- v_scrollbar_layer_->SetScrollElementId(scroll_layer_ptr->element_id());
- v_scrollbar_layer_->test_properties()->opacity_can_animate = true;
+ v_scrollbar_layer_->SetScrollElementId(scroll_layer_->element_id());
+ CopyProperties(scroll_layer_, v_scrollbar_layer_);
+ v_scrollbar_layer_->SetOffsetToTransformParent(gfx::Vector2dF(90, 0));
+ auto& v_scrollbar_effect = CreateEffectNode(v_scrollbar_layer_);
+ v_scrollbar_effect.opacity = 0.f;
+ v_scrollbar_effect.has_potential_opacity_animation = true;
h_scrollbar_layer_->SetBounds(gfx::Size(kTrackLength, kThumbThickness));
- h_scrollbar_layer_->test_properties()->position = gfx::PointF(0, 90);
- h_scrollbar_layer_->SetScrollElementId(scroll_layer_ptr->element_id());
- h_scrollbar_layer_->test_properties()->opacity_can_animate = true;
+ h_scrollbar_layer_->SetScrollElementId(scroll_layer_->element_id());
+ CopyProperties(scroll_layer_, h_scrollbar_layer_);
+ h_scrollbar_layer_->SetOffsetToTransformParent(gfx::Vector2dF(0, 90));
+ auto& h_scrollbar_effect = CreateEffectNode(h_scrollbar_layer_);
+ h_scrollbar_effect.opacity = 0.f;
+ h_scrollbar_effect.has_potential_opacity_animation = true;
- clip_layer_->SetBounds(gfx::Size(100, 100));
- scroll_layer_ptr->SetScrollable(gfx::Size(100, 100));
- scroll_layer_ptr->SetBounds(gfx::Size(200, 200));
- host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
- host_impl_.active_tree()->UpdateScrollbarGeometries();
+ UpdateActiveTreeDrawProperties();
scrollbar_controller_ = ScrollbarAnimationController::
CreateScrollbarAnimationControllerAuraOverlay(
- scroll_layer_ptr->element_id(), &client_, kFadeDelay, kFadeDuration,
+ scroll_layer_->element_id(), &client_, kFadeDelay, kFadeDuration,
kThinningDuration, 0.0f);
v_scrollbar_layer_->SetCurrentPos(0);
h_scrollbar_layer_->SetCurrentPos(0);
@@ -153,11 +141,9 @@ class ScrollbarAnimationControllerAuraOverlayTest : public testing::Test {
return p;
}
- FakeImplTaskRunnerProvider task_runner_provider_;
- TestTaskGraphRunner task_graph_runner_;
- FakeLayerTreeHostImpl host_impl_;
std::unique_ptr<ScrollbarAnimationController> scrollbar_controller_;
LayerImpl* clip_layer_;
+ LayerImpl* scroll_layer_;
SolidColorScrollbarLayerImpl* v_scrollbar_layer_;
SolidColorScrollbarLayerImpl* h_scrollbar_layer_;
NiceMock<MockScrollbarAnimationControllerClient> client_;
@@ -185,16 +171,17 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, AppearOnResize) {
// Make the Layer non-scrollable, scrollbar disappears.
clip_layer_->SetBounds(gfx::Size(200, 200));
- LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1);
- scroll_layer->SetScrollable(gfx::Size(200, 200));
- host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
+ scroll_layer_->SetScrollable(gfx::Size(200, 200));
+ GetScrollNode(scroll_layer_)->container_bounds = gfx::Size(200, 200);
+ UpdateActiveTreeDrawProperties();
scrollbar_controller_->DidScrollUpdate();
ExpectScrollbarsOpacity(0);
// Make the layer scrollable, scrollbar appears again.
clip_layer_->SetBounds(gfx::Size(100, 100));
- scroll_layer->SetScrollable(gfx::Size(100, 100));
- host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
+ scroll_layer_->SetScrollable(gfx::Size(100, 100));
+ GetScrollNode(scroll_layer_)->container_bounds = gfx::Size(100, 100);
+ UpdateActiveTreeDrawProperties();
scrollbar_controller_->DidScrollUpdate();
ExpectScrollbarsOpacity(1);
}
@@ -204,15 +191,14 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, HideOnResize) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1);
- ASSERT_TRUE(scroll_layer);
- EXPECT_EQ(gfx::Size(200, 200), scroll_layer->bounds());
+ EXPECT_EQ(gfx::Size(200, 200), scroll_layer_->bounds());
// Shrink along X axis, horizontal scrollbar should appear.
clip_layer_->SetBounds(gfx::Size(100, 200));
EXPECT_EQ(gfx::Size(100, 200), clip_layer_->bounds());
- scroll_layer->SetScrollable(gfx::Size(100, 200));
- host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
+ scroll_layer_->SetScrollable(gfx::Size(100, 200));
+ GetScrollNode(scroll_layer_)->container_bounds = gfx::Size(100, 200);
+ UpdateActiveTreeDrawProperties();
scrollbar_controller_->DidScrollBegin();
@@ -225,8 +211,9 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, HideOnResize) {
// should disappear.
clip_layer_->SetBounds(gfx::Size(200, 100));
EXPECT_EQ(gfx::Size(200, 100), clip_layer_->bounds());
- scroll_layer->SetScrollable(gfx::Size(200, 100));
- host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
+ scroll_layer_->SetScrollable(gfx::Size(200, 100));
+ GetScrollNode(scroll_layer_)->container_bounds = gfx::Size(200, 100);
+ UpdateActiveTreeDrawProperties();
scrollbar_controller_->DidScrollBegin();
@@ -1363,13 +1350,12 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, TickmakrsShowHide) {
}
class ScrollbarAnimationControllerAndroidTest
- : public testing::Test,
+ : public LayerTreeImplTestBase,
+ public testing::Test,
public ScrollbarAnimationControllerClient {
public:
ScrollbarAnimationControllerAndroidTest()
- : host_impl_(&task_runner_provider_, &task_graph_runner_),
- did_request_redraw_(false),
- did_request_animate_(false) {}
+ : did_request_redraw_(false), did_request_animate_(false) {}
void PostDelayedScrollbarAnimationTask(base::OnceClosure start_fade,
base::TimeDelta delay) override {
@@ -1383,7 +1369,7 @@ class ScrollbarAnimationControllerAndroidTest
did_request_animate_ = true;
}
ScrollbarSet ScrollbarsFor(ElementId scroll_element_id) const override {
- return host_impl_.ScrollbarsFor(scroll_element_id);
+ return host_impl()->ScrollbarsFor(scroll_element_id);
}
void DidChangeScrollbarVisibility() override {}
@@ -1391,47 +1377,38 @@ class ScrollbarAnimationControllerAndroidTest
void SetUp() override {
const int kTrackStart = 0;
const bool kIsLeftSideVerticalScrollbar = false;
- const bool kIsOverlayScrollbar = true; // Allow opacity animations.
-
- std::unique_ptr<LayerImpl> scroll_layer =
- LayerImpl::Create(host_impl_.active_tree(), 1);
- std::unique_ptr<SolidColorScrollbarLayerImpl> scrollbar =
- SolidColorScrollbarLayerImpl::Create(
- host_impl_.active_tree(), 2, orientation(), kThumbThickness,
- kTrackStart, kIsLeftSideVerticalScrollbar, kIsOverlayScrollbar);
- scrollbar->test_properties()->opacity = 0.0f;
- scrollbar_layer_ = scrollbar.get();
- scrollbar_layer_->test_properties()->opacity_can_animate = true;
- std::unique_ptr<LayerImpl> root =
- LayerImpl::Create(host_impl_.active_tree(), 3);
-
- scroll_layer->SetScrollable(gfx::Size(100, 100));
- scroll_layer->SetElementId(
- LayerIdToElementIdForTesting(scroll_layer->id()));
- LayerImpl* scroll_layer_ptr = scroll_layer.get();
- scroll_layer->test_properties()->AddChild(std::move(scrollbar));
- root->test_properties()->AddChild(std::move(scroll_layer));
- host_impl_.active_tree()->SetRootLayerForTesting(std::move(root));
-
- scrollbar_layer_->SetScrollElementId(scroll_layer_ptr->element_id());
- scroll_layer_ptr->SetBounds(gfx::Size(200, 200));
- host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
- DCHECK(host_impl_.active_tree()->ScrollbarGeometriesNeedUpdate());
- host_impl_.active_tree()->UpdateScrollbarGeometries();
+
+ LayerImpl* root = root_layer();
+ scroll_layer_ = AddLayer<LayerImpl>();
+ scrollbar_layer_ = AddLayer<SolidColorScrollbarLayerImpl>(
+ orientation(), kThumbThickness, kTrackStart,
+ kIsLeftSideVerticalScrollbar);
+ SetElementIdsForTesting();
+
+ scroll_layer_->SetBounds(gfx::Size(200, 200));
+ scroll_layer_->SetScrollable(gfx::Size(100, 100));
+ CopyProperties(root, scroll_layer_);
+ CreateTransformNode(scroll_layer_);
+ CreateScrollNode(scroll_layer_);
+
+ scrollbar_layer_->SetScrollElementId(scroll_layer_->element_id());
+ CopyProperties(scroll_layer_, scrollbar_layer_);
+ auto& scrollbar_effect = CreateEffectNode(scrollbar_layer_);
+ scrollbar_effect.opacity = 0.f;
+ scrollbar_effect.has_potential_opacity_animation = true;
+
+ UpdateActiveTreeDrawProperties();
scrollbar_controller_ =
ScrollbarAnimationController::CreateScrollbarAnimationControllerAndroid(
- scroll_layer_ptr->element_id(), this,
- base::TimeDelta::FromSeconds(2), base::TimeDelta::FromSeconds(3),
- 0.0f);
+ scroll_layer_->element_id(), this, base::TimeDelta::FromSeconds(2),
+ base::TimeDelta::FromSeconds(3), 0.0f);
}
virtual ScrollbarOrientation orientation() const { return HORIZONTAL; }
- FakeImplTaskRunnerProvider task_runner_provider_;
- TestTaskGraphRunner task_graph_runner_;
- FakeLayerTreeHostImpl host_impl_;
std::unique_ptr<ScrollbarAnimationController> scrollbar_controller_;
+ LayerImpl* scroll_layer_;
SolidColorScrollbarLayerImpl* scrollbar_layer_;
base::OnceClosure start_fade_;
@@ -1490,15 +1467,14 @@ TEST_F(ScrollbarAnimationControllerAndroidTest,
}
TEST_F(ScrollbarAnimationControllerAndroidTest, HideOnResize) {
- LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1);
- ASSERT_TRUE(scroll_layer);
- EXPECT_EQ(gfx::Size(200, 200), scroll_layer->bounds());
+ EXPECT_EQ(gfx::Size(200, 200), scroll_layer_->bounds());
EXPECT_EQ(HORIZONTAL, scrollbar_layer_->orientation());
// Shrink along X axis, horizontal scrollbar should appear.
- scroll_layer->SetScrollable(gfx::Size(100, 200));
- host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
+ scroll_layer_->SetScrollable(gfx::Size(100, 200));
+ GetScrollNode(scroll_layer_)->container_bounds = gfx::Size(100, 200);
+ UpdateActiveTreeDrawProperties();
scrollbar_controller_->DidScrollBegin();
scrollbar_controller_->DidScrollUpdate();
@@ -1507,8 +1483,9 @@ TEST_F(ScrollbarAnimationControllerAndroidTest, HideOnResize) {
// Shrink along Y axis and expand along X, horizontal scrollbar
// should disappear.
- scroll_layer->SetScrollable(gfx::Size(200, 100));
- host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
+ scroll_layer_->SetScrollable(gfx::Size(200, 100));
+ GetScrollNode(scroll_layer_)->container_bounds = gfx::Size(200, 100);
+ UpdateActiveTreeDrawProperties();
scrollbar_controller_->DidScrollBegin();
@@ -1519,15 +1496,14 @@ TEST_F(ScrollbarAnimationControllerAndroidTest, HideOnResize) {
}
TEST_F(VerticalScrollbarAnimationControllerAndroidTest, HideOnResize) {
- LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1);
- ASSERT_TRUE(scroll_layer);
- EXPECT_EQ(gfx::Size(200, 200), scroll_layer->bounds());
+ EXPECT_EQ(gfx::Size(200, 200), scroll_layer_->bounds());
EXPECT_EQ(VERTICAL, scrollbar_layer_->orientation());
// Shrink along X axis, vertical scrollbar should remain invisible.
- scroll_layer->SetScrollable(gfx::Size(100, 200));
- host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
+ scroll_layer_->SetScrollable(gfx::Size(100, 200));
+ GetScrollNode(scroll_layer_)->container_bounds = gfx::Size(100, 200);
+ UpdateActiveTreeDrawProperties();
scrollbar_controller_->DidScrollBegin();
scrollbar_controller_->DidScrollUpdate();
@@ -1535,8 +1511,9 @@ TEST_F(VerticalScrollbarAnimationControllerAndroidTest, HideOnResize) {
scrollbar_controller_->DidScrollEnd();
// Shrink along Y axis and expand along X, vertical scrollbar should appear.
- scroll_layer->SetScrollable(gfx::Size(200, 100));
- host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
+ scroll_layer_->SetScrollable(gfx::Size(200, 100));
+ GetScrollNode(scroll_layer_)->container_bounds = gfx::Size(200, 100);
+ UpdateActiveTreeDrawProperties();
scrollbar_controller_->DidScrollBegin();
@@ -1549,10 +1526,8 @@ TEST_F(VerticalScrollbarAnimationControllerAndroidTest, HideOnResize) {
TEST_F(ScrollbarAnimationControllerAndroidTest, HideOnUserNonScrollableHorz) {
EXPECT_EQ(HORIZONTAL, scrollbar_layer_->orientation());
- LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1);
- ASSERT_TRUE(scroll_layer);
- scroll_layer->test_properties()->user_scrollable_horizontal = false;
- host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
+ GetScrollNode(scroll_layer_)->user_scrollable_horizontal = false;
+ UpdateActiveTreeDrawProperties();
scrollbar_controller_->DidScrollBegin();
@@ -1565,10 +1540,8 @@ TEST_F(ScrollbarAnimationControllerAndroidTest, HideOnUserNonScrollableHorz) {
TEST_F(ScrollbarAnimationControllerAndroidTest, ShowOnUserNonScrollableVert) {
EXPECT_EQ(HORIZONTAL, scrollbar_layer_->orientation());
- LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1);
- ASSERT_TRUE(scroll_layer);
- scroll_layer->test_properties()->user_scrollable_vertical = false;
- host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
+ GetScrollNode(scroll_layer_)->user_scrollable_vertical = false;
+ UpdateActiveTreeDrawProperties();
scrollbar_controller_->DidScrollBegin();
@@ -1582,10 +1555,8 @@ TEST_F(VerticalScrollbarAnimationControllerAndroidTest,
HideOnUserNonScrollableVert) {
EXPECT_EQ(VERTICAL, scrollbar_layer_->orientation());
- LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1);
- ASSERT_TRUE(scroll_layer);
- scroll_layer->test_properties()->user_scrollable_vertical = false;
- host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
+ GetScrollNode(scroll_layer_)->user_scrollable_vertical = false;
+ UpdateActiveTreeDrawProperties();
scrollbar_controller_->DidScrollBegin();
@@ -1599,10 +1570,8 @@ TEST_F(VerticalScrollbarAnimationControllerAndroidTest,
ShowOnUserNonScrollableHorz) {
EXPECT_EQ(VERTICAL, scrollbar_layer_->orientation());
- LayerImpl* scroll_layer = host_impl_.active_tree()->LayerById(1);
- ASSERT_TRUE(scroll_layer);
- scroll_layer->test_properties()->user_scrollable_horizontal = false;
- host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
+ GetScrollNode(scroll_layer_)->user_scrollable_horizontal = false;
+ UpdateActiveTreeDrawProperties();
scrollbar_controller_->DidScrollBegin();
diff --git a/chromium/cc/input/scrollbar_controller.cc b/chromium/cc/input/scrollbar_controller.cc
index b66d42df486..2f4221e3d59 100644
--- a/chromium/cc/input/scrollbar_controller.cc
+++ b/chromium/cc/input/scrollbar_controller.cc
@@ -26,38 +26,13 @@ ScrollbarController::ScrollbarController(
: layer_tree_host_impl_(layer_tree_host_impl),
scrollbar_scroll_is_active_(false),
currently_captured_scrollbar_(nullptr),
- previous_pointer_position_(gfx::PointF(0, 0)),
+ last_known_pointer_position_(gfx::PointF(0, 0)),
drag_processed_for_current_frame_(false),
cancelable_autoscroll_task_(nullptr) {}
void ScrollbarController::WillBeginImplFrame() {
drag_processed_for_current_frame_ = false;
- if (!autoscroll_state_.has_value())
- return;
-
- // TODO(arakeri): Revisit this when addressing crbug.com/967004. The
- // animations need to be aborted/restarted based on the pointer location (i.e
- // leaving/entering the track/arrows, reaching the track end etc). The
- // autoscroll_state_ however, needs to be reset on pointer changes.
- if (ShouldCancelTrackAutoscroll())
- layer_tree_host_impl_->mutator_host()->ScrollAnimationAbort();
-
- // When the scroller is autoscrolling forward, its dimensions need to be
- // monitored. If the length of the scroller layer increases, the old one needs
- // to be aborted and a new autoscroll animation needs to start. This needs to
- // be done only for the "autoscroll forward" case. Autoscrolling backward
- // always has a constant value to animate to (which is '0'. See the function
- // ScrollbarController::StartAutoScrollAnimation).
- if (autoscroll_state_->direction == AutoScrollDirection::AUTOSCROLL_FORWARD) {
- const float scroll_layer_length =
- currently_captured_scrollbar_->scroll_layer_length();
- if (autoscroll_state_->scroll_layer_length != scroll_layer_length) {
- layer_tree_host_impl_->mutator_host()->ScrollAnimationAbort();
- StartAutoScrollAnimation(
- autoscroll_state_->velocity,
- currently_captured_scrollbar_->scroll_element_id());
- }
- }
+ RecomputeAutoscrollStateIfNeeded();
}
gfx::Vector2dF ScrollbarController::GetThumbRelativePoint(
@@ -78,16 +53,20 @@ gfx::Vector2dF ScrollbarController::GetThumbRelativePoint(
// Performs hit test and prepares scroll deltas that will be used by GSB and
// GSU.
InputHandlerPointerResult ScrollbarController::HandlePointerDown(
- const gfx::PointF position_in_widget) {
- InputHandlerPointerResult scroll_result;
+ const gfx::PointF position_in_widget,
+ bool shift_modifier) {
LayerImpl* layer_impl = GetLayerHitByPoint(position_in_widget);
// If a non-custom scrollbar layer was not found, we return early as there is
- // no point in setting additional state in the ScrollbarController.
+ // no point in setting additional state in the ScrollbarController. Return an
+ // empty InputHandlerPointerResult in this case so that when it is bubbled up
+ // to InputHandlerProxy::RouteToTypeSpecificHandler, the pointer event gets
+ // passed on to the main thread.
if (!(layer_impl && layer_impl->ToScrollbarLayer()))
- return scroll_result;
+ return InputHandlerPointerResult();
currently_captured_scrollbar_ = layer_impl->ToScrollbarLayer();
+ InputHandlerPointerResult scroll_result;
scroll_result.target_scroller =
currently_captured_scrollbar_->scroll_element_id();
scroll_result.type = PointerResultType::kScrollbarScroll;
@@ -95,18 +74,21 @@ InputHandlerPointerResult ScrollbarController::HandlePointerDown(
const ScrollbarPart scrollbar_part =
GetScrollbarPartFromPointerDown(position_in_widget);
scroll_result.scroll_offset = GetScrollOffsetForScrollbarPart(
- scrollbar_part, currently_captured_scrollbar_->orientation());
- previous_pointer_position_ = position_in_widget;
+ scrollbar_part, currently_captured_scrollbar_->orientation(),
+ shift_modifier);
+ last_known_pointer_position_ = position_in_widget;
scrollbar_scroll_is_active_ = true;
+ scroll_result.scroll_units = Granularity(scrollbar_part, shift_modifier);
if (scrollbar_part == ScrollbarPart::THUMB) {
- scroll_result.scroll_units =
- ui::input_types::ScrollGranularity::kScrollByPrecisePixel;
- drag_anchor_relative_to_thumb_ = GetThumbRelativePoint(position_in_widget);
- } else {
- // TODO(arakeri): This needs to be updated to kLine once cc implements
- // handling it. crbug.com/959441
- scroll_result.scroll_units =
- ui::input_types::ScrollGranularity::kScrollByPixel;
+ drag_state_ = DragState();
+ drag_state_->anchor_relative_to_thumb_ =
+ GetThumbRelativePoint(position_in_widget);
+
+ // Record the current scroller offset. This will be needed to snap the
+ // thumb back to its original position if the pointer moves too far away
+ // from the track during a thumb drag.
+ drag_state_->scroll_position_at_start_ =
+ currently_captured_scrollbar_->current_pos();
}
if (!scroll_result.scroll_offset.IsZero()) {
@@ -120,7 +102,8 @@ InputHandlerPointerResult ScrollbarController::HandlePointerDown(
&ScrollbarController::StartAutoScrollAnimation,
base::Unretained(this),
InitialDeltaToAutoscrollVelocity(scroll_result.scroll_offset),
- currently_captured_scrollbar_->scroll_element_id()));
+ currently_captured_scrollbar_->scroll_element_id(),
+ scrollbar_part));
layer_tree_host_impl_->task_runner_provider()
->ImplThreadTaskRunner()
->PostDelayedTask(FROM_HERE, cancelable_autoscroll_task_->callback(),
@@ -129,14 +112,134 @@ InputHandlerPointerResult ScrollbarController::HandlePointerDown(
return scroll_result;
}
+bool ScrollbarController::SnapToDragOrigin(
+ const gfx::PointF pointer_position_in_widget) {
+ // Consult the ScrollbarTheme to check if thumb snapping is supported on the
+ // current platform.
+ if (!currently_captured_scrollbar_->SupportsDragSnapBack())
+ return false;
+
+ bool clipped = false;
+ const gfx::PointF pointer_position_in_layer =
+ GetScrollbarRelativePosition(pointer_position_in_widget, &clipped);
+
+ if (clipped)
+ return false;
+
+ layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries();
+ const ScrollbarOrientation orientation =
+ currently_captured_scrollbar_->orientation();
+ const gfx::Rect forward_track_rect =
+ currently_captured_scrollbar_->ForwardTrackRect();
+
+ // When dragging the thumb, there needs to exist "gutters" on either side of
+ // the track. The thickness of these gutters is a multiple of the track (or
+ // thumb) thickness. As long as the pointer remains within the bounds of these
+ // gutters in the non-scrolling direction, thumb drag proceeds as expected.
+ // The moment the pointer moves outside the bounds, the scroller needs to snap
+ // back to the drag_origin (aka the scroll offset of the parent scroller
+ // before the thumb drag initiated).
+ int track_thickness = orientation == ScrollbarOrientation::VERTICAL
+ ? forward_track_rect.width()
+ : forward_track_rect.height();
+
+ if (!track_thickness) {
+ // For overlay scrollbars (or for tests that do not set up a track
+ // thickness), use the thumb_thickness instead to determine the gutters.
+ const int thumb_thickness = currently_captured_scrollbar_->ThumbThickness();
+
+ // If the thumb doesn't have thickness, the gutters can't be determined.
+ // Snapping shouldn't occur in this case.
+ if (!thumb_thickness)
+ return false;
+
+ track_thickness = thumb_thickness;
+ }
+
+ const float gutter_thickness = kOffSideMultiplier * track_thickness;
+ const float gutter_min_bound =
+ orientation == ScrollbarOrientation::VERTICAL
+ ? (forward_track_rect.x() - gutter_thickness)
+ : (forward_track_rect.y() - gutter_thickness);
+ const float gutter_max_bound =
+ orientation == ScrollbarOrientation::VERTICAL
+ ? (forward_track_rect.x() + track_thickness + gutter_thickness)
+ : (forward_track_rect.y() + track_thickness + gutter_thickness);
+
+ const float pointer_location = orientation == ScrollbarOrientation::VERTICAL
+ ? pointer_position_in_layer.x()
+ : pointer_position_in_layer.y();
+
+ return pointer_location < gutter_min_bound ||
+ pointer_location > gutter_max_bound;
+}
+
+ui::input_types::ScrollGranularity ScrollbarController::Granularity(
+ const ScrollbarPart scrollbar_part,
+ const bool shift_modifier) {
+ const bool shift_click_on_scrollbar_track =
+ shift_modifier && (scrollbar_part == ScrollbarPart::FORWARD_TRACK ||
+ scrollbar_part == ScrollbarPart::BACK_TRACK);
+ if (shift_click_on_scrollbar_track || scrollbar_part == ScrollbarPart::THUMB)
+ return ui::input_types::ScrollGranularity::kScrollByPrecisePixel;
+
+ // TODO(arakeri): This needs to be updated to kLine once cc implements
+ // handling it. crbug.com/959441
+ return ui::input_types::ScrollGranularity::kScrollByPixel;
+}
+
+float ScrollbarController::GetScrollDeltaForShiftClick() {
+ layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries();
+
+ bool clipped = false;
+ const gfx::PointF pointer_position_in_layer =
+ GetScrollbarRelativePosition(last_known_pointer_position_, &clipped);
+
+ if (clipped)
+ return 0;
+
+ const ScrollbarOrientation orientation =
+ currently_captured_scrollbar_->orientation();
+ const float pointer_location = orientation == ScrollbarOrientation::VERTICAL
+ ? pointer_position_in_layer.y()
+ : pointer_position_in_layer.x();
+
+ // During a shift + click, the pointers current location (on the track) needs
+ // to be considered as the center of the thumb and the thumb origin needs to
+ // be calculated based on that. This will ensure that when shift + click is
+ // processed, the thumb will be centered on the pointer.
+ const int thumb_length = currently_captured_scrollbar_->ThumbLength();
+ const float desired_thumb_origin = pointer_location - thumb_length / 2.f;
+
+ const gfx::Rect thumb_rect(
+ currently_captured_scrollbar_->ComputeThumbQuadRect());
+ const float current_thumb_origin =
+ orientation == ScrollbarOrientation::VERTICAL ? thumb_rect.y()
+ : thumb_rect.x();
+
+ const float delta =
+ round(std::abs(desired_thumb_origin - current_thumb_origin));
+ return delta * GetScrollerToScrollbarRatio();
+}
+
gfx::ScrollOffset ScrollbarController::GetScrollOffsetForDragPosition(
const gfx::PointF pointer_position_in_widget) {
layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries();
+ const ScrollbarOrientation orientation =
+ currently_captured_scrollbar_->orientation();
+ if (SnapToDragOrigin(pointer_position_in_widget)) {
+ const float delta = currently_captured_scrollbar_->current_pos() -
+ drag_state_->scroll_position_at_start_;
+ return orientation == ScrollbarOrientation::VERTICAL
+ ? gfx::ScrollOffset(0, -delta)
+ : gfx::ScrollOffset(-delta, 0);
+ }
+
const gfx::Rect thumb_rect(
currently_captured_scrollbar_->ComputeThumbQuadRect());
const gfx::PointF drag_position_relative_to_layer =
- gfx::PointF(thumb_rect.origin()) + drag_anchor_relative_to_thumb_.value();
+ gfx::PointF(thumb_rect.origin()) + drag_state_->anchor_relative_to_thumb_;
bool clipped = false;
const gfx::PointF pointer_position_in_layer =
@@ -149,29 +252,52 @@ gfx::ScrollOffset ScrollbarController::GetScrollOffsetForDragPosition(
const gfx::Vector2dF pointer_delta =
pointer_position_in_layer - drag_position_relative_to_layer;
+ float scaled_scroller_to_scrollbar_ratio = GetScrollerToScrollbarRatio();
+ float current_scroll_position = currently_captured_scrollbar_->current_pos();
+
+ // Thumb position needs to be floored and Values between 0 and 1 are rounded
+ // to one to match main thread per pixel behavior. Corresponding main thread
+ // code in ScrollbarTheme::ThumbPosition
+ float thumb_position = std::max(0.0f, current_scroll_position) /
+ scaled_scroller_to_scrollbar_ratio;
+ thumb_position = (thumb_position < 1.0 && thumb_position > 0.0)
+ ? 1.0
+ : floorf(thumb_position);
+
+ float delta_in_orientation = orientation == ScrollbarOrientation::VERTICAL
+ ? pointer_delta.y()
+ : pointer_delta.x();
+
+ // This is effectively equal to delta_in_orientation *
+ // scaled_scroller_to_scrollbar_ratio but is necessary due to truncated delta
+ // value. Floored thumb_position cancels out the rounding error introduced
+ // in pointer_delta due to static_cast<int> in
+ // ScrollbarLayerImplBase::ComputeThumbQuadRectWithThumbThicknessScale
+ float scroll_delta = (delta_in_orientation + thumb_position) *
+ scaled_scroller_to_scrollbar_ratio -
+ current_scroll_position;
+
gfx::ScrollOffset scaled_thumb_drag_delta;
- const ScrollbarOrientation orientation =
- currently_captured_scrollbar_->orientation();
+
+ // Scroll delta floored to match main thread per pixel behavior
orientation == ScrollbarOrientation::VERTICAL
- ? scaled_thumb_drag_delta.set_y(pointer_delta.y())
- : scaled_thumb_drag_delta.set_x(pointer_delta.x());
+ ? scaled_thumb_drag_delta.set_y(floorf(scroll_delta))
+ : scaled_thumb_drag_delta.set_x(floorf(scroll_delta));
- float scaled_scroller_to_scrollbar_ratio = GetScrollerToScrollbarRatio();
- scaled_thumb_drag_delta.Scale(scaled_scroller_to_scrollbar_ratio);
return scaled_thumb_drag_delta;
}
// Performs hit test and prepares scroll deltas that will be used by GSU.
-InputHandlerPointerResult ScrollbarController::HandleMouseMove(
+InputHandlerPointerResult ScrollbarController::HandlePointerMove(
const gfx::PointF position_in_widget) {
- previous_pointer_position_ = position_in_widget;
+ last_known_pointer_position_ = position_in_widget;
+ RecomputeAutoscrollStateIfNeeded();
InputHandlerPointerResult scroll_result;
// If a thumb drag is not in progress or if a GSU was already produced for a
// thumb drag in this frame, there's no point in continuing on. Please see the
// header file for details.
- if (!drag_anchor_relative_to_thumb_.has_value() ||
- drag_processed_for_current_frame_)
+ if (!drag_state_.has_value() || drag_processed_for_current_frame_)
return scroll_result;
const ScrollNode* currently_scrolling_node =
@@ -180,7 +306,7 @@ InputHandlerPointerResult ScrollbarController::HandleMouseMove(
// Thumb drag needs a scroll_node. Clear the thumb drag state and exit if it
// is unset.
if (currently_scrolling_node == nullptr) {
- drag_anchor_relative_to_thumb_ = base::nullopt;
+ drag_state_ = base::nullopt;
return scroll_result;
}
@@ -258,30 +384,27 @@ float ScrollbarController::GetScrollerToScrollbarRatio() {
const LayerImpl* owner_scroll_layer =
layer_tree_host_impl_->active_tree()->ScrollableLayerByElementId(
currently_captured_scrollbar_->scroll_element_id());
- float viewport_length =
+ const float viewport_length =
orientation == ScrollbarOrientation::VERTICAL
? owner_scroll_layer->scroll_container_bounds().height()
: (owner_scroll_layer->scroll_container_bounds().width());
+
+ // For platforms which have use_zoom_for_dsf set to false (like Mac), the
+ // device_scale_factor should not be used while determining the
+ // scaled_scroller_to_scrollbar_ratio as thumb drag would appear jittery due
+ // to constant over and under corrections.
+ // (See ScrollbarController::ScreenSpaceScaleFactor()).
float scaled_scroller_to_scrollbar_ratio =
((scroll_layer_length - viewport_length) /
(scrollbar_track_length - scrollbar_thumb_length)) *
- layer_tree_host_impl_->active_tree()->device_scale_factor();
-
- // Avoid precision loss later on by rounding up 3 decimal places here.
- // TODO(arakeri): Revisit this while fixing crbug.com/986174. There is a
- // precision loss that is happening somewhere which affects root scrollbars
- // only. Even though it is not visible to the end user, without rounding up,
- // the scrolling tests will fail due to this precision loss.
- DCHECK_GT(scaled_scroller_to_scrollbar_ratio, 0);
- scaled_scroller_to_scrollbar_ratio =
- ceil(scaled_scroller_to_scrollbar_ratio * 1000.0) / 1000.0;
+ ScreenSpaceScaleFactor();
return scaled_scroller_to_scrollbar_ratio;
}
-bool ScrollbarController::ShouldCancelTrackAutoscroll() {
- // This function should only ever be called if an autoscroll is in progress.
- DCHECK(autoscroll_state_.has_value());
+void ScrollbarController::RecomputeAutoscrollStateIfNeeded() {
+ if (!autoscroll_state_.has_value())
+ return;
layer_tree_host_impl_->active_tree()->UpdateScrollbarGeometries();
const ScrollbarOrientation orientation =
@@ -291,10 +414,10 @@ bool ScrollbarController::ShouldCancelTrackAutoscroll() {
bool clipped;
gfx::PointF scroller_relative_position(
- GetScrollbarRelativePosition(previous_pointer_position_, &clipped));
+ GetScrollbarRelativePosition(last_known_pointer_position_, &clipped));
if (clipped)
- return false;
+ return;
// Based on the orientation of the scrollbar and the direction of the
// autoscroll, the code below makes a decision of whether the track autoscroll
@@ -312,15 +435,49 @@ bool ScrollbarController::ShouldCancelTrackAutoscroll() {
pointer_position = scroller_relative_position.x();
}
+ // If the thumb reaches the pointer while autoscrolling, abort.
if ((autoscroll_state_->direction ==
AutoScrollDirection::AUTOSCROLL_FORWARD &&
thumb_end > pointer_position) ||
(autoscroll_state_->direction ==
AutoScrollDirection::AUTOSCROLL_BACKWARD &&
thumb_start < pointer_position))
- return true;
+ layer_tree_host_impl_->mutator_host()->ScrollAnimationAbort();
+
+ // When the scroller is autoscrolling forward, its dimensions need to be
+ // monitored. If the length of the scroller layer increases, the old one needs
+ // to be aborted and a new autoscroll animation needs to start. This needs to
+ // be done only for the "autoscroll forward" case. Autoscrolling backward
+ // always has a constant value to animate to (which is '0'. See the function
+ // ScrollbarController::StartAutoScrollAnimation).
+ if (autoscroll_state_->direction == AutoScrollDirection::AUTOSCROLL_FORWARD) {
+ const float scroll_layer_length =
+ currently_captured_scrollbar_->scroll_layer_length();
+ if (autoscroll_state_->scroll_layer_length != scroll_layer_length) {
+ layer_tree_host_impl_->mutator_host()->ScrollAnimationAbort();
+ StartAutoScrollAnimation(
+ autoscroll_state_->velocity,
+ currently_captured_scrollbar_->scroll_element_id(),
+ autoscroll_state_->pressed_scrollbar_part);
+ }
+ }
- return false;
+ // The animations need to be aborted/restarted based on the pointer location
+ // (i.e leaving/entering the track/arrows, reaching the track end etc). The
+ // autoscroll_state_ however, needs to be reset on pointer changes.
+ const gfx::RectF scrollbar_part_rect(
+ GetRectForScrollbarPart(autoscroll_state_->pressed_scrollbar_part));
+ if (!scrollbar_part_rect.Contains(scroller_relative_position)) {
+ // Stop animating if pointer moves outside the rect bounds.
+ layer_tree_host_impl_->mutator_host()->ScrollAnimationAbort();
+ } else if (scrollbar_part_rect.Contains(scroller_relative_position) &&
+ !layer_tree_host_impl_->mutator_host()->IsElementAnimating(
+ currently_captured_scrollbar_->scroll_element_id())) {
+ // Start animating if pointer re-enters the bounds.
+ StartAutoScrollAnimation(autoscroll_state_->velocity,
+ currently_captured_scrollbar_->scroll_element_id(),
+ autoscroll_state_->pressed_scrollbar_part);
+ }
}
// Helper to calculate the autoscroll velocity.
@@ -333,11 +490,13 @@ float ScrollbarController::InitialDeltaToAutoscrollVelocity(
return scroll_delta * kAutoscrollMultiplier;
}
-void ScrollbarController::StartAutoScrollAnimation(const float velocity,
- ElementId element_id) {
+void ScrollbarController::StartAutoScrollAnimation(
+ const float velocity,
+ ElementId element_id,
+ ScrollbarPart pressed_scrollbar_part) {
// Autoscroll and thumb drag are mutually exclusive. Both can't be active at
// the same time.
- DCHECK(!drag_anchor_relative_to_thumb_.has_value());
+ DCHECK(!drag_state_.has_value());
DCHECK_NE(velocity, 0);
// scroll_node is set up while handling GSB. If there's no node to scroll, we
@@ -372,6 +531,7 @@ void ScrollbarController::StartAutoScrollAnimation(const float velocity,
autoscroll_state_ = AutoScrollState();
autoscroll_state_->velocity = velocity;
autoscroll_state_->scroll_layer_length = scroll_layer_length;
+ autoscroll_state_->pressed_scrollbar_part = pressed_scrollbar_part;
autoscroll_state_->direction = velocity < 0
? AutoScrollDirection::AUTOSCROLL_BACKWARD
: AutoScrollDirection::AUTOSCROLL_FORWARD;
@@ -400,7 +560,7 @@ InputHandlerPointerResult ScrollbarController::HandlePointerUp(
cancelable_autoscroll_task_.reset();
}
- drag_anchor_relative_to_thumb_ = base::nullopt;
+ drag_state_ = base::nullopt;
autoscroll_state_ = base::nullopt;
return scroll_result;
}
@@ -414,14 +574,14 @@ LayerImpl* ScrollbarController::GetLayerHitByPoint(
gfx::PointF device_viewport_point = gfx::ScalePoint(
gfx::PointF(viewport_point), active_tree->device_scale_factor());
LayerImpl* layer_impl =
- active_tree->FindFirstScrollingLayerOrScrollbarThatIsHitByPoint(
- device_viewport_point);
+ active_tree->FindLayerThatIsHitByPoint(device_viewport_point);
return layer_impl;
}
int ScrollbarController::GetScrollDeltaForScrollbarPart(
- ScrollbarPart scrollbar_part) {
+ const ScrollbarPart scrollbar_part,
+ const bool shift_modifier) {
int scroll_delta = 0;
int viewport_length = 0;
LayerImpl* owner_scroll_layer = nullptr;
@@ -433,6 +593,10 @@ int ScrollbarController::GetScrollDeltaForScrollbarPart(
break;
case ScrollbarPart::BACK_TRACK:
case ScrollbarPart::FORWARD_TRACK:
+ if (shift_modifier) {
+ scroll_delta = GetScrollDeltaForShiftClick();
+ break;
+ }
owner_scroll_layer =
layer_tree_host_impl_->active_tree()->ScrollableLayerByElementId(
currently_captured_scrollbar_->scroll_element_id());
@@ -446,8 +610,20 @@ int ScrollbarController::GetScrollDeltaForScrollbarPart(
default:
scroll_delta = 0;
}
- return scroll_delta *
- layer_tree_host_impl_->active_tree()->device_scale_factor();
+
+ return scroll_delta * ScreenSpaceScaleFactor();
+}
+
+float ScrollbarController::ScreenSpaceScaleFactor() const {
+ // TODO(arakeri): When crbug.com/716231 is fixed, this needs to be updated.
+ // If use_zoom_for_dsf is false, the click deltas and thumb drag ratios
+ // shouldn't be scaled. For example: On Mac, when the use_zoom_for_dsf is
+ // false and the device_scale_factor is 2, the scroll delta for pointer clicks
+ // on arrows would be incorrectly calculated as 80px instead of 40px. This is
+ // also necessary to ensure that hit testing works as intended.
+ return layer_tree_host_impl_->settings().use_zoom_for_dsf
+ ? layer_tree_host_impl_->active_tree()->device_scale_factor()
+ : 1.f;
}
gfx::PointF ScrollbarController::GetScrollbarRelativePosition(
@@ -455,7 +631,17 @@ gfx::PointF ScrollbarController::GetScrollbarRelativePosition(
bool* clipped) {
gfx::Transform inverse_screen_space_transform(
gfx::Transform::kSkipInitialization);
- if (!currently_captured_scrollbar_->ScreenSpaceTransform().GetInverse(
+
+ // If use_zoom_for_dsf is false, the ScreenSpaceTransform needs to be scaled
+ // down by the DSF to ensure that position_in_widget is transformed correctly.
+ const float scale =
+ !layer_tree_host_impl_->settings().use_zoom_for_dsf
+ ? 1.f / layer_tree_host_impl_->active_tree()->device_scale_factor()
+ : 1.f;
+ gfx::Transform scaled_screen_space_transform(
+ currently_captured_scrollbar_->ScreenSpaceTransform());
+ scaled_screen_space_transform.PostScale(scale, scale);
+ if (!scaled_screen_space_transform.GetInverse(
&inverse_screen_space_transform))
return gfx::PointF(0, 0);
@@ -480,12 +666,28 @@ ScrollbarPart ScrollbarController::GetScrollbarPartFromPointerDown(
scroller_relative_position);
}
+// Determines the corresponding rect for the given scrollbar part.
+gfx::Rect ScrollbarController::GetRectForScrollbarPart(
+ const ScrollbarPart scrollbar_part) {
+ if (scrollbar_part == ScrollbarPart::BACK_BUTTON)
+ return currently_captured_scrollbar_->BackButtonRect();
+ if (scrollbar_part == ScrollbarPart::FORWARD_BUTTON)
+ return currently_captured_scrollbar_->ForwardButtonRect();
+ if (scrollbar_part == ScrollbarPart::BACK_TRACK)
+ return currently_captured_scrollbar_->BackTrackRect();
+ if (scrollbar_part == ScrollbarPart::FORWARD_TRACK)
+ return currently_captured_scrollbar_->ForwardTrackRect();
+ return gfx::Rect(0, 0);
+}
+
// Determines the scroll offsets based on the ScrollbarPart and the scrollbar
// orientation.
gfx::ScrollOffset ScrollbarController::GetScrollOffsetForScrollbarPart(
const ScrollbarPart scrollbar_part,
- const ScrollbarOrientation orientation) {
- float scroll_delta = GetScrollDeltaForScrollbarPart(scrollbar_part);
+ const ScrollbarOrientation orientation,
+ const bool shift_modifier) {
+ float scroll_delta =
+ GetScrollDeltaForScrollbarPart(scrollbar_part, shift_modifier);
// See CreateScrollStateForGesture for more information on how these values
// will be interpreted.
diff --git a/chromium/cc/input/scrollbar_controller.h b/chromium/cc/input/scrollbar_controller.h
index a407640ce0b..e1b13dc2e03 100644
--- a/chromium/cc/input/scrollbar_controller.h
+++ b/chromium/cc/input/scrollbar_controller.h
@@ -20,8 +20,9 @@ class CC_EXPORT ScrollbarController {
virtual ~ScrollbarController();
InputHandlerPointerResult HandlePointerDown(
- const gfx::PointF position_in_widget);
- InputHandlerPointerResult HandleMouseMove(
+ const gfx::PointF position_in_widget,
+ const bool shift_modifier);
+ InputHandlerPointerResult HandlePointerMove(
const gfx::PointF position_in_widget);
InputHandlerPointerResult HandlePointerUp(
const gfx::PointF position_in_widget);
@@ -30,7 +31,9 @@ class CC_EXPORT ScrollbarController {
// InitialDeltaToAutoscrollVelocity). This value carries a "sign" which is
// needed to determine whether we should set up the autoscrolling in the
// forwards or the backwards direction.
- void StartAutoScrollAnimation(float velocity, ElementId element_id);
+ void StartAutoScrollAnimation(float velocity,
+ ElementId element_id,
+ ScrollbarPart pressed_scrollbar_part);
bool ScrollbarScrollIsActive() { return scrollbar_scroll_is_active_; }
ScrollbarOrientation orientation() {
return currently_captured_scrollbar_->orientation();
@@ -54,8 +57,26 @@ class CC_EXPORT ScrollbarController {
// Used to track the scroller length while autoscrolling. Helpful for
// setting up infinite scrolling.
float scroll_layer_length = 0.f;
+
+ // Used to lookup the rect corresponding to the ScrollbarPart so that
+ // autoscroll animations can be played/paused depending on the current
+ // pointer location.
+ ScrollbarPart pressed_scrollbar_part;
+ };
+
+ struct CC_EXPORT DragState {
+ // This is used to track the pointer location relative to the thumb origin
+ // when a drag has started.
+ gfx::Vector2dF anchor_relative_to_thumb_;
+
+ // This is needed for thumb snapping when the pointer moves too far away
+ // from the track while scrolling.
+ float scroll_position_at_start_;
};
+ // Returns the DSF based on whether use-zoom-for-dsf is enabled.
+ float ScreenSpaceScaleFactor() const;
+
// Helper to convert scroll offset to autoscroll velocity.
float InitialDeltaToAutoscrollVelocity(gfx::ScrollOffset scroll_offset) const;
@@ -66,17 +87,36 @@ class CC_EXPORT ScrollbarController {
// Returns scroll offsets based on which ScrollbarPart was hit tested.
gfx::ScrollOffset GetScrollOffsetForScrollbarPart(
const ScrollbarPart scrollbar_part,
- const ScrollbarOrientation orientation);
+ const ScrollbarOrientation orientation,
+ const bool shift_modifier);
+
+ // Returns the rect for the ScrollbarPart.
+ gfx::Rect GetRectForScrollbarPart(const ScrollbarPart scrollbar_part);
LayerImpl* GetLayerHitByPoint(const gfx::PointF position_in_widget);
- int GetScrollDeltaForScrollbarPart(ScrollbarPart scrollbar_part);
+ int GetScrollDeltaForScrollbarPart(const ScrollbarPart scrollbar_part,
+ const bool shift_modifier);
// Makes position_in_widget relative to the scrollbar.
gfx::PointF GetScrollbarRelativePosition(const gfx::PointF position_in_widget,
bool* clipped);
- // Decides whether a track autoscroll should be aborted.
- bool ShouldCancelTrackAutoscroll();
+ // Decides if the scroller should snap to the offset that it was originally at
+ // (i.e the offset before the thumb drag).
+ bool SnapToDragOrigin(const gfx::PointF pointer_position_in_widget);
+
+ // Decides whether a track autoscroll should be aborted (or restarted) due to
+ // the thumb reaching the pointer or the pointer leaving (or re-entering) the
+ // bounds.
+ void RecomputeAutoscrollStateIfNeeded();
+
+ // Shift + click is expected to do a non-animated jump to a certain offset.
+ float GetScrollDeltaForShiftClick();
+
+ // Determines if the delta needs to be animated.
+ ui::input_types::ScrollGranularity Granularity(
+ const ScrollbarPart scrollbar_part,
+ bool shift_modifier);
// Calculates the scroll_offset based on position_in_widget and
// drag_anchor_relative_to_thumb_.
@@ -98,15 +138,15 @@ class CC_EXPORT ScrollbarController {
const ScrollbarLayerImplBase* currently_captured_scrollbar_;
// This is relative to the RenderWidget's origin.
- gfx::PointF previous_pointer_position_;
+ gfx::PointF last_known_pointer_position_;
// Holds information pertaining to autoscrolling. This member is empty if and
// only if an autoscroll is *not* in progress.
base::Optional<AutoScrollState> autoscroll_state_;
- // This is used to track the pointer location relative to the thumb origin
- // when a drag has started. It is empty if a thumb drag is *not* in progress.
- base::Optional<gfx::Vector2dF> drag_anchor_relative_to_thumb_;
+ // Holds information pertaining to thumb drags. Useful while making decisions
+ // about thumb anchoring/snapping.
+ base::Optional<DragState> drag_state_;
// Used to track if a GSU was processed for the current frame or not. Without
// this, thumb drag will appear jittery. The reason this happens is because
diff --git a/chromium/cc/input/single_scrollbar_animation_controller_thinning.cc b/chromium/cc/input/single_scrollbar_animation_controller_thinning.cc
index 0515aaff879..d01e1ac2bcd 100644
--- a/chromium/cc/input/single_scrollbar_animation_controller_thinning.cc
+++ b/chromium/cc/input/single_scrollbar_animation_controller_thinning.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include "base/memory/ptr_util.h"
+#include "base/numerics/ranges.h"
#include "base/time/time.h"
#include "cc/input/scrollbar_animation_controller.h"
#include "cc/layers/layer_impl.h"
@@ -95,7 +96,7 @@ float SingleScrollbarAnimationControllerThinning::AnimationProgressAtTime(
base::TimeTicks now) {
base::TimeDelta delta = now - last_awaken_time_;
float progress = delta.InSecondsF() / Duration().InSecondsF();
- return std::max(std::min(progress, 1.f), 0.f);
+ return base::ClampToRange(progress, 0.0f, 1.0f);
}
const base::TimeDelta& SingleScrollbarAnimationControllerThinning::Duration() {
diff --git a/chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc b/chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc
index a08e6aa8838..b851a58f77f 100644
--- a/chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc
+++ b/chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc
@@ -5,10 +5,8 @@
#include "cc/input/single_scrollbar_animation_controller_thinning.h"
#include "cc/layers/solid_color_scrollbar_layer_impl.h"
-#include "cc/test/fake_impl_task_runner_provider.h"
-#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
-#include "cc/test/test_task_graph_runner.h"
+#include "cc/test/layer_tree_impl_test_base.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -51,62 +49,49 @@ class MockSingleScrollbarAnimationControllerClient
LayerTreeHostImpl* host_impl_;
};
-class SingleScrollbarAnimationControllerThinningTest : public testing::Test {
+class SingleScrollbarAnimationControllerThinningTest
+ : public LayerTreeImplTestBase,
+ public testing::Test {
public:
- SingleScrollbarAnimationControllerThinningTest()
- : host_impl_(&task_runner_provider_, &task_graph_runner_),
- client_(&host_impl_) {}
+ SingleScrollbarAnimationControllerThinningTest() : client_(host_impl()) {}
protected:
const base::TimeDelta kThinningDuration = base::TimeDelta::FromSeconds(2);
void SetUp() override {
- std::unique_ptr<LayerImpl> scroll_layer =
- LayerImpl::Create(host_impl_.active_tree(), 1);
- std::unique_ptr<LayerImpl> clip =
- LayerImpl::Create(host_impl_.active_tree(), 3);
+ root_layer()->SetBounds(gfx::Size(100, 100));
+ auto* scroll_layer = AddLayer<LayerImpl>();
+ scroll_layer->SetBounds(gfx::Size(200, 200));
+ scroll_layer->SetScrollable(gfx::Size(100, 100));
scroll_layer->SetElementId(
LayerIdToElementIdForTesting(scroll_layer->id()));
- clip_layer_ = clip.get();
- LayerImpl* scroll_layer_ptr = scroll_layer.get();
- const int kId = 2;
const int kThumbThickness = 10;
const int kTrackStart = 0;
const int kTrackLength = 100;
const bool kIsLeftSideVerticalScrollbar = false;
- const bool kIsOverlayScrollbar = true;
- std::unique_ptr<SolidColorScrollbarLayerImpl> scrollbar =
- SolidColorScrollbarLayerImpl::Create(
- host_impl_.active_tree(), kId, HORIZONTAL, kThumbThickness,
- kTrackStart, kIsLeftSideVerticalScrollbar, kIsOverlayScrollbar);
- scrollbar_layer_ = scrollbar.get();
-
- scroll_layer->test_properties()->AddChild(std::move(scrollbar));
- clip_layer_->test_properties()->AddChild(std::move(scroll_layer));
- host_impl_.active_tree()->SetRootLayerForTesting(std::move(clip));
+ scrollbar_layer_ = AddLayer<SolidColorScrollbarLayerImpl>(
+ HORIZONTAL, kThumbThickness, kTrackStart, kIsLeftSideVerticalScrollbar);
scrollbar_layer_->SetBounds(gfx::Size(kThumbThickness, kTrackLength));
- scrollbar_layer_->test_properties()->position = gfx::PointF(90, 0);
- scrollbar_layer_->SetScrollElementId(scroll_layer_ptr->element_id());
- scrollbar_layer_->test_properties()->opacity_can_animate = true;
- clip_layer_->SetBounds(gfx::Size(100, 100));
- scroll_layer_ptr->SetBounds(gfx::Size(200, 200));
- host_impl_.active_tree()->UpdateScrollbarGeometries();
- host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
+ scrollbar_layer_->SetScrollElementId(scroll_layer->element_id());
+
+ CopyProperties(root_layer(), scroll_layer);
+ CreateTransformNode(scroll_layer);
+ CreateScrollNode(scroll_layer);
+ CopyProperties(scroll_layer, scrollbar_layer_);
+ scrollbar_layer_->SetOffsetToTransformParent(gfx::Vector2dF(90, 0));
+ CreateEffectNode(scrollbar_layer_).has_potential_opacity_animation = true;
+
+ UpdateActiveTreeDrawProperties();
scrollbar_controller_ = SingleScrollbarAnimationControllerThinning::Create(
- scroll_layer_ptr->element_id(), HORIZONTAL, &client_,
- kThinningDuration);
+ scroll_layer->element_id(), HORIZONTAL, &client_, kThinningDuration);
}
- FakeImplTaskRunnerProvider task_runner_provider_;
- TestTaskGraphRunner task_graph_runner_;
- FakeLayerTreeHostImpl host_impl_;
std::unique_ptr<SingleScrollbarAnimationControllerThinning>
scrollbar_controller_;
- LayerImpl* clip_layer_;
SolidColorScrollbarLayerImpl* scrollbar_layer_;
NiceMock<MockSingleScrollbarAnimationControllerClient> client_;
};