Skip to content

Commit

Permalink
Tweak smooth scrolling speed.
Browse files Browse the repository at this point in the history
Keyboard scrolls are reduced to 150ms.  Wheel scrolls retain the 200ms duration
for small deltas, but are tightened down to 100ms as delta increases.

This is a variation on mgiuca's patch in http://crrev.com/1563393003.

BUG=575409
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel

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

Cr-Commit-Position: refs/heads/master@{#369540}
  • Loading branch information
skobes-chromium authored and Commit bot committed Jan 14, 2016
1 parent 8dc9777 commit e07af43
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 39 deletions.
2 changes: 1 addition & 1 deletion cc/animation/animation_host.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class AnimationHost::ScrollOffsetAnimations : public AnimationDelegate {
scoped_ptr<ScrollOffsetAnimationCurve> curve =
ScrollOffsetAnimationCurve::Create(
target_offset, EaseInOutTimingFunction::Create(),
ScrollOffsetAnimationCurve::DurationBehavior::CONSTANT);
ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA);
curve->SetInitialValue(current_offset);

scoped_ptr<Animation> animation = Animation::Create(
Expand Down
54 changes: 36 additions & 18 deletions cc/animation/scroll_offset_animation_curve.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,23 @@
#include "cc/base/time_util.h"
#include "ui/gfx/animation/tween.h"

const double kConstantDuration = 12.0;
using DurationBehavior = cc::ScrollOffsetAnimationCurve::DurationBehavior;

const double kConstantDuration = 9.0;
const double kDurationDivisor = 60.0;

const double kInverseDeltaRampStartPx = 120.0;
const double kInverseDeltaRampEndPx = 480.0;
const double kInverseDeltaMinDuration = 6.0;
const double kInverseDeltaMaxDuration = 12.0;

const double kInverseDeltaSlope =
(kInverseDeltaMinDuration - kInverseDeltaMaxDuration) /
(kInverseDeltaRampEndPx - kInverseDeltaRampStartPx);

const double kInverseDeltaOffset =
kInverseDeltaMaxDuration - kInverseDeltaRampStartPx * kInverseDeltaSlope;

namespace cc {

namespace {
Expand All @@ -25,24 +39,28 @@ static float MaximumDimension(const gfx::Vector2dF& delta) {
return std::abs(delta.x()) > std::abs(delta.y()) ? delta.x() : delta.y();
}

static base::TimeDelta SegmentDuration(
const gfx::Vector2dF& delta,
ScrollOffsetAnimationCurve::DurationBehavior behavior) {
if (behavior == ScrollOffsetAnimationCurve::DurationBehavior::DELTA_BASED) {
// The duration of a JS scroll animation depends on the size of the scroll.
// The exact relationship between the size and the duration isn't specified
// by the CSSOM View smooth scroll spec and is instead left up to user
// agents to decide. The calculation performed here will very likely be
// further tweaked before the smooth scroll API ships.
return base::TimeDelta::FromMicroseconds(
(std::sqrt(std::abs(MaximumDimension(delta))) / kDurationDivisor) *
base::Time::kMicrosecondsPerSecond);
} else {
// Input-driven scroll animations use a constant duration.
return base::TimeDelta::FromMicroseconds(
(kConstantDuration / kDurationDivisor) *
base::Time::kMicrosecondsPerSecond);
static base::TimeDelta SegmentDuration(const gfx::Vector2dF& delta,
DurationBehavior behavior) {
double duration = kConstantDuration;
switch (behavior) {
case DurationBehavior::CONSTANT:
duration = kConstantDuration;
break;
case DurationBehavior::DELTA_BASED:
duration = std::sqrt(std::abs(MaximumDimension(delta)));
break;
case DurationBehavior::INVERSE_DELTA:
duration = std::min(
std::max(kInverseDeltaOffset +
std::abs(MaximumDimension(delta)) * kInverseDeltaSlope,
kInverseDeltaMinDuration),
kInverseDeltaMaxDuration);
break;
default:
NOTREACHED();
}
return base::TimeDelta::FromMicroseconds(duration / kDurationDivisor *
base::Time::kMicrosecondsPerSecond);
}

static scoped_ptr<TimingFunction> EaseOutWithInitialVelocity(double velocity) {
Expand Down
2 changes: 1 addition & 1 deletion cc/animation/scroll_offset_animation_curve.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class TimingFunction;

class CC_EXPORT ScrollOffsetAnimationCurve : public AnimationCurve {
public:
enum class DurationBehavior { DELTA_BASED, CONSTANT };
enum class DurationBehavior { DELTA_BASED, CONSTANT, INVERSE_DELTA };
static scoped_ptr<ScrollOffsetAnimationCurve> Create(
const gfx::ScrollOffset& target_value,
scoped_ptr<TimingFunction> timing_function,
Expand Down
74 changes: 58 additions & 16 deletions cc/animation/scroll_offset_animation_curve_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
#include "cc/test/geometry_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"

const double kConstantDuration = 9.0;
const double kDurationDivisor = 60.0;

namespace cc {
namespace {

TEST(ScrollOffsetAnimationCurveTest, Duration) {
TEST(ScrollOffsetAnimationCurveTest, DeltaBasedDuration) {
gfx::ScrollOffset target_value(100.f, 200.f);
scoped_ptr<ScrollOffsetAnimationCurve> curve(
ScrollOffsetAnimationCurve::Create(target_value,
Expand Down Expand Up @@ -127,30 +130,69 @@ TEST(ScrollOffsetAnimationCurveTest, Clone) {
TEST(ScrollOffsetAnimationCurveTest, UpdateTarget) {
gfx::ScrollOffset initial_value(0.f, 0.f);
gfx::ScrollOffset target_value(0.f, 3600.f);
double duration = kConstantDuration / kDurationDivisor;
scoped_ptr<ScrollOffsetAnimationCurve> curve(
ScrollOffsetAnimationCurve::Create(
target_value, EaseInOutTimingFunction::Create(),
ScrollOffsetAnimationCurve::DurationBehavior::CONSTANT));
curve->SetInitialValue(initial_value);
EXPECT_EQ(0.2, curve->Duration().InSecondsF());
EXPECT_EQ(1800.0, curve->GetValue(base::TimeDelta::FromSecondsD(0.1)).y());
EXPECT_EQ(3600.0, curve->GetValue(base::TimeDelta::FromSecondsD(0.2)).y());
EXPECT_NEAR(duration, curve->Duration().InSecondsF(), 0.0002f);
EXPECT_NEAR(
1800.0,
curve->GetValue(base::TimeDelta::FromSecondsD(duration / 2.0)).y(),
0.0002f);
EXPECT_NEAR(3600.0,
curve->GetValue(base::TimeDelta::FromSecondsD(duration)).y(),
0.0002f);

curve->UpdateTarget(duration / 2, gfx::ScrollOffset(0.0, 9900.0));

EXPECT_NEAR(duration * 1.5, curve->Duration().InSecondsF(), 0.0002f);
EXPECT_NEAR(
1800.0,
curve->GetValue(base::TimeDelta::FromSecondsD(duration / 2.0)).y(),
0.0002f);
EXPECT_NEAR(6827.6,
curve->GetValue(base::TimeDelta::FromSecondsD(duration)).y(),
0.1f);
EXPECT_NEAR(
9900.0,
curve->GetValue(base::TimeDelta::FromSecondsD(duration * 1.5)).y(),
0.0002f);

curve->UpdateTarget(duration, gfx::ScrollOffset(0.0, 7200.0));

curve->UpdateTarget(0.1, gfx::ScrollOffset(0.0, 9900.0));
// A closer target at high velocity reduces the duration.
EXPECT_NEAR(duration * 1.0794, curve->Duration().InSecondsF(), 0.0002f);
EXPECT_NEAR(6827.6,
curve->GetValue(base::TimeDelta::FromSecondsD(duration)).y(),
0.1f);
EXPECT_NEAR(
7200.0,
curve->GetValue(base::TimeDelta::FromSecondsD(duration * 1.08)).y(),
0.0002f);
}

EXPECT_EQ(0.3, curve->Duration().InSecondsF());
EXPECT_EQ(1800.0, curve->GetValue(base::TimeDelta::FromSecondsD(0.1)).y());
EXPECT_NEAR(6827.59, curve->GetValue(base::TimeDelta::FromSecondsD(0.2)).y(),
0.01);
EXPECT_EQ(9900.0, curve->GetValue(base::TimeDelta::FromSecondsD(0.3)).y());
TEST(ScrollOffsetAnimationCurveTest, InverseDeltaDuration) {
scoped_ptr<ScrollOffsetAnimationCurve> curve(
ScrollOffsetAnimationCurve::Create(
gfx::ScrollOffset(0.f, 100.f), EaseInOutTimingFunction::Create(),
ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA));

curve->UpdateTarget(0.2, gfx::ScrollOffset(0.0, 7200.0));
curve->SetInitialValue(gfx::ScrollOffset());
double smallDeltaDuration = curve->Duration().InSecondsF();

// A closer target at high velocity reduces the duration.
EXPECT_NEAR(0.22, curve->Duration().InSecondsF(), 0.01);
EXPECT_NEAR(6827.59, curve->GetValue(base::TimeDelta::FromSecondsD(0.2)).y(),
0.01);
EXPECT_EQ(7200.0, curve->GetValue(base::TimeDelta::FromSecondsD(0.22)).y());
curve->UpdateTarget(0.f, gfx::ScrollOffset(0.f, 300.f));
double mediumDeltaDuration = curve->Duration().InSecondsF();

curve->UpdateTarget(0.f, gfx::ScrollOffset(0.f, 500.f));
double largeDeltaDuration = curve->Duration().InSecondsF();

EXPECT_GT(smallDeltaDuration, mediumDeltaDuration);
EXPECT_GT(mediumDeltaDuration, largeDeltaDuration);

curve->UpdateTarget(0.f, gfx::ScrollOffset(0.f, 5000.f));
EXPECT_EQ(largeDeltaDuration, curve->Duration().InSecondsF());
}

} // namespace
Expand Down
3 changes: 3 additions & 0 deletions cc/blink/web_scroll_offset_animation_curve_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ static DurationBehavior GetDurationBehavior(

case WebScrollOffsetAnimationCurve::ScrollDurationConstant:
return DurationBehavior::CONSTANT;

case WebScrollOffsetAnimationCurve::ScrollDurationInverseDelta:
return DurationBehavior::INVERSE_DELTA;
}
NOTREACHED();
return DurationBehavior::DELTA_BASED;
Expand Down
2 changes: 1 addition & 1 deletion cc/trees/layer_tree_host_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3631,7 +3631,7 @@ void LayerTreeHostImpl::ScrollAnimationCreate(
scoped_ptr<ScrollOffsetAnimationCurve> curve =
ScrollOffsetAnimationCurve::Create(
target_offset, EaseInOutTimingFunction::Create(),
ScrollOffsetAnimationCurve::DurationBehavior::CONSTANT);
ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA);
curve->SetInitialValue(current_offset);

scoped_ptr<Animation> animation = Animation::Create(
Expand Down
6 changes: 5 additions & 1 deletion third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ PassOwnPtrWillBeRawPtr<ScrollAnimatorBase> ScrollAnimatorBase::create(Scrollable
ScrollAnimator::ScrollAnimator(ScrollableArea* scrollableArea, WTF::TimeFunction timeFunction)
: ScrollAnimatorBase(scrollableArea)
, m_timeFunction(timeFunction)
, m_lastGranularity(ScrollByPixel)
{
}

Expand Down Expand Up @@ -143,6 +144,7 @@ ScrollResultOneDimensional ScrollAnimator::userScroll(

m_targetOffset = targetPos;
m_startTime = m_timeFunction();
m_lastGranularity = granularity;

if (registerAndScheduleAnimation())
m_runState = RunState::WaitingToSendToCompositor;
Expand Down Expand Up @@ -226,7 +228,9 @@ void ScrollAnimator::updateCompositorAnimations()
->createScrollOffsetAnimationCurve(
m_targetOffset,
WebCompositorAnimationCurve::TimingFunctionTypeEaseInOut,
WebScrollOffsetAnimationCurve::ScrollDurationConstant));
m_lastGranularity == ScrollByPixel ?
WebScrollOffsetAnimationCurve::ScrollDurationInverseDelta :
WebScrollOffsetAnimationCurve::ScrollDurationConstant));
m_animationCurve->setInitialValue(currentPosition());
}

Expand Down
1 change: 1 addition & 0 deletions third_party/WebKit/Source/platform/scroll/ScrollAnimator.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class PLATFORM_EXPORT ScrollAnimator final : public ScrollAnimatorBase {
bool registerAndScheduleAnimation();

FloatPoint m_targetOffset;
ScrollGranularity m_lastGranularity;
};

} // namespace blink
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ class WebScrollOffsetAnimationCurve : public WebCompositorAnimationCurve {

enum ScrollDurationBehavior {
ScrollDurationDeltaBased = 0,
ScrollDurationConstant
ScrollDurationConstant,
ScrollDurationInverseDelta
};

virtual void setInitialValue(WebFloatPoint) = 0;
Expand Down

0 comments on commit e07af43

Please sign in to comment.