Skip to content
This repository has been archived by the owner on Apr 3, 2020. It is now read-only.

Commit

Permalink
Fix smooth scroll overshooting when mouse held down in scrollbar track.
Browse files Browse the repository at this point in the history
Scrollbar::autoscrollPressedPart now checks if the mouse is under the thumb's
eventual (target) position, rather than its current position.

BUG=578554

Review URL: https://codereview.chromium.org/1601303003

Cr-Commit-Position: refs/heads/master@{#370285}
(cherry picked from commit ef53ba3)

Review URL: https://codereview.chromium.org/1617893002 .

Cr-Commit-Position: refs/branch-heads/2623@{#42}
Cr-Branched-From: 92d7753-refs/heads/master@{#369907}
  • Loading branch information
skobes-chromium committed Jan 21, 2016
1 parent d3caa27 commit 6d000ed
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
This test scrolls by clicking in the scrollbar track.

On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".


PASS scrollY became pageStep
PASS scrollY is pageStep
PASS successfullyParsed is true

TEST COMPLETE

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!DOCTYPE html>
<script src="../../../resources/js-test.js"></script>
<style>
body {
height: 1800px;
}
</style>
<body>
<script>
window.jsTestIsAsync = true;

description("This test scrolls by clicking in the scrollbar track.");

// Compute ScrollableArea::pageStep.
var pageStep = innerHeight * 0.875;
if (navigator.userAgent.indexOf("Mac OS X") >= 0)
pageStep = Math.max(pageStep, innerHeight - 40);

onload = function() {
if (!window.eventSender || !window.internals) {
finishJSTest();
return;
}

// Turn on smooth scrolling.
internals.settings.setScrollAnimatorEnabled(true);

// Click in the vertical scrollbar track, below the thumb.
eventSender.mouseMoveTo(790, 280);
eventSender.mouseDown();
eventSender.mouseUp();

// A second click should have no effect since we will be under the thumb
// by the time the animation completes.
eventSender.mouseDown();
eventSender.mouseUp();

shouldBecomeEqual("scrollY", "pageStep", function() {
requestAnimationFrame(function() {
// Make sure we stopped here.
shouldBe("scrollY", "pageStep");
finishJSTest();
});
});
};
</script>
</body>
3 changes: 1 addition & 2 deletions third_party/WebKit/Source/platform/scroll/ScrollAnimator.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class PLATFORM_EXPORT ScrollAnimator final : public ScrollAnimatorBase {

ScrollResultOneDimensional userScroll(ScrollbarOrientation, ScrollGranularity, float step, float delta) override;
void scrollToOffsetWithoutAnimation(const FloatPoint&) override;
FloatPoint desiredTargetPosition() const override;

// ScrollAnimatorCompositorCoordinator implementation.
void tickAnimation(double monotonicTime) override;
Expand All @@ -71,8 +72,6 @@ class PLATFORM_EXPORT ScrollAnimator final : public ScrollAnimatorBase {
WTF::TimeFunction m_timeFunction;

private:
FloatPoint desiredTargetPosition() const;

// Returns true if the animation was scheduled successfully. If animation
// could not be scheduled (e.g. because the frame is detached), scrolls
// immediately to the target and returns false.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

#include "platform/PlatformExport.h"
#include "platform/PlatformWheelEvent.h"
#include "platform/geometry/FloatPoint.h"
#include "platform/geometry/FloatSize.h"
#include "platform/heap/Handle.h"
#include "platform/scroll/ScrollAnimatorCompositorCoordinator.h"
Expand All @@ -41,7 +42,6 @@

namespace blink {

class FloatPoint;
class ScrollableArea;
class Scrollbar;
class WebCompositorAnimationTimeline;
Expand Down Expand Up @@ -71,6 +71,7 @@ class PLATFORM_EXPORT ScrollAnimatorBase : public ScrollAnimatorCompositorCoordi

void setCurrentPosition(const FloatPoint&);
FloatPoint currentPosition() const;
virtual FloatPoint desiredTargetPosition() const { return currentPosition(); }

// Returns how much of pixelDelta will be used by the underlying scrollable
// area.
Expand Down
23 changes: 17 additions & 6 deletions third_party/WebKit/Source/platform/scroll/Scrollbar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,11 @@ void Scrollbar::autoscrollTimerFired(Timer<Scrollbar>*)
autoscrollPressedPart(theme().autoscrollTimerDelay());
}

static bool thumbUnderMouse(Scrollbar& scrollbar)
bool Scrollbar::thumbWillBeUnderMouse() const
{
int thumbPos = scrollbar.theme().trackPosition(scrollbar) + scrollbar.theme().thumbPosition(scrollbar);
int thumbLength = scrollbar.theme().thumbLength(scrollbar);
return scrollbar.pressedPos() >= thumbPos && scrollbar.pressedPos() < thumbPos + thumbLength;
int thumbPos = theme().trackPosition(*this) + theme().thumbPosition(*this, scrollableAreaTargetPos());
int thumbLength = theme().thumbLength(*this);
return pressedPos() >= thumbPos && pressedPos() < thumbPos + thumbLength;
}

void Scrollbar::autoscrollPressedPart(double delay)
Expand All @@ -193,7 +193,7 @@ void Scrollbar::autoscrollPressedPart(double delay)
return;

// Handle the track.
if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse(*this)) {
if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbWillBeUnderMouse()) {
setHoveredPart(ThumbPart);
return;
}
Expand All @@ -211,7 +211,7 @@ void Scrollbar::startTimerIfNeeded(double delay)

// Handle the track. We halt track scrolling once the thumb is level
// with us.
if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse(*this)) {
if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbWillBeUnderMouse()) {
setHoveredPart(ThumbPart);
return;
}
Expand Down Expand Up @@ -560,6 +560,17 @@ float Scrollbar::scrollableAreaCurrentPos() const
return m_scrollableArea->scrollPosition().y() - m_scrollableArea->minimumScrollPosition().y();
}

float Scrollbar::scrollableAreaTargetPos() const
{
if (!m_scrollableArea)
return 0;

if (m_orientation == HorizontalScrollbar)
return m_scrollableArea->scrollAnimator().desiredTargetPosition().x() - m_scrollableArea->minimumScrollPosition().x();

return m_scrollableArea->scrollAnimator().desiredTargetPosition().y() - m_scrollableArea->minimumScrollPosition().y();
}

void Scrollbar::setNeedsPaintInvalidation(ScrollbarPart invalidParts)
{
if (m_theme.shouldRepaintAllPartsOnInvalidation())
Expand Down
2 changes: 2 additions & 0 deletions third_party/WebKit/Source/platform/scroll/Scrollbar.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ class PLATFORM_EXPORT Scrollbar : public Widget, public ScrollbarThemeClient {
void invalidateRect(const IntRect&) override { setNeedsPaintInvalidation(AllParts); }

float scrollableAreaCurrentPos() const;
float scrollableAreaTargetPos() const;
bool thumbWillBeUnderMouse() const;

bool m_trackNeedsRepaint;
bool m_thumbNeedsRepaint;
Expand Down
4 changes: 2 additions & 2 deletions third_party/WebKit/Source/platform/scroll/ScrollbarTheme.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,14 +207,14 @@ bool ScrollbarTheme::shouldSnapBackToDragOrigin(const ScrollbarThemeClient& scro
return Platform::current()->scrollbarBehavior()->shouldSnapBackToDragOrigin(mousePosition, trackRect(scrollbar), scrollbar.orientation() == HorizontalScrollbar);
}

int ScrollbarTheme::thumbPosition(const ScrollbarThemeClient& scrollbar)
int ScrollbarTheme::thumbPosition(const ScrollbarThemeClient& scrollbar, float scrollPosition)
{
if (scrollbar.enabled()) {
float size = scrollbar.totalSize() - scrollbar.visibleSize();
// Avoid doing a floating point divide by zero and return 1 when usedTotalSize == visibleSize.
if (!size)
return 0;
float pos = std::max(0.0f, scrollbar.currentPos()) * (trackLength(scrollbar) - thumbLength(scrollbar)) / size;
float pos = std::max(0.0f, scrollPosition) * (trackLength(scrollbar) - thumbLength(scrollbar)) / size;
return (pos < 1 && pos > 0) ? 1 : pos;
}
return 0;
Expand Down
6 changes: 4 additions & 2 deletions third_party/WebKit/Source/platform/scroll/ScrollbarTheme.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@
#include "platform/geometry/IntRect.h"
#include "platform/graphics/paint/DisplayItem.h"
#include "platform/scroll/ScrollTypes.h"
#include "platform/scroll/ScrollbarThemeClient.h"
#include "public/platform/WebScrollbarButtonsPlacement.h"

namespace blink {

class CullRect;
class GraphicsContext;
class PlatformMouseEvent;
class ScrollbarThemeClient;
class ScrollbarThemePaintParams;

class PLATFORM_EXPORT ScrollbarTheme {
Expand Down Expand Up @@ -79,7 +79,9 @@ class PLATFORM_EXPORT ScrollbarTheme {
virtual bool shouldDragDocumentInsteadOfThumb(const ScrollbarThemeClient&, const PlatformMouseEvent&) { return false; }

// The position of the thumb relative to the track.
virtual int thumbPosition(const ScrollbarThemeClient&);
int thumbPosition(const ScrollbarThemeClient& scrollbar) { return thumbPosition(scrollbar, scrollbar.currentPos()); }
// The position the thumb would have, relative to the track, at the specified scroll position.
virtual int thumbPosition(const ScrollbarThemeClient&, float scrollPosition);
// The length of the thumb along the axis of the scrollbar.
virtual int thumbLength(const ScrollbarThemeClient&);
// The position of the track relative to the scrollbar.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,13 @@ bool ScrollbarThemeOverlay::usesOverlayScrollbars() const
return true;
}

int ScrollbarThemeOverlay::thumbPosition(const ScrollbarThemeClient& scrollbar)
int ScrollbarThemeOverlay::thumbPosition(const ScrollbarThemeClient& scrollbar, float scrollPosition)
{
if (!scrollbar.totalSize())
return 0;

int trackLen = trackLength(scrollbar);
float proportion = static_cast<float>(scrollbar.currentPos()) / scrollbar.totalSize();
float proportion = static_cast<float>(scrollPosition) / scrollbar.totalSize();
return round(proportion * trackLen);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class PLATFORM_EXPORT ScrollbarThemeOverlay : public ScrollbarTheme {
int scrollbarMargin() const override;
bool usesOverlayScrollbars() const override;

int thumbPosition(const ScrollbarThemeClient&) override;
int thumbPosition(const ScrollbarThemeClient&, float scrollPosition) override;
int thumbLength(const ScrollbarThemeClient&) override;

bool hasButtons(const ScrollbarThemeClient&) override { return false; }
Expand Down

0 comments on commit 6d000ed

Please sign in to comment.