Skip to content

Commit

Permalink
cc: Make ScrollOffsetAnimationCurve::UpdateTarget better handle large…
Browse files Browse the repository at this point in the history
… velocity

When ScrollOffsetAnimationCurve::UpdateTarget computes a new initial
velocity, it doesn't address the possibility that this velocity will
be large enough to trigger Inf or NaN when used elsewhere. However,
given infinite precision math, increasing the velocity above 1000
has little effect on the cubic bezier curve used for the animation.
This CL makes ScrollOffsetAnimationCurve no longer perform computations
using large velocities; instead, we set the parameters of the cubic
bezier curver directly to the values they approach as velocity
approaches infinity.

BUG=507252
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel

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

Cr-Commit-Position: refs/heads/master@{#337668}
  • Loading branch information
alijuma authored and Commit bot committed Jul 7, 2015
1 parent fd3dd99 commit 45889f7
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 5 deletions.
17 changes: 12 additions & 5 deletions cc/animation/scroll_offset_animation_curve.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,18 @@ static base::TimeDelta DurationFromDelta(const gfx::Vector2dF& delta) {

static scoped_ptr<TimingFunction> EaseOutWithInitialVelocity(double velocity) {
// Based on EaseInOutTimingFunction::Create with first control point rotated.
const double r2 = 0.42 * 0.42;
const double v2 = velocity * velocity;
const double x1 = std::sqrt(r2 / (v2 + 1));
const double y1 = std::sqrt(r2 * v2 / (v2 + 1));
return CubicBezierTimingFunction::Create(x1, y1, 0.58, 1);
if (std::abs(velocity) < 1000.0) {
const double r2 = 0.42 * 0.42;
const double v2 = velocity * velocity;
const double x1 = std::sqrt(r2 / (v2 + 1));
const double y1 = std::sqrt(r2 * v2 / (v2 + 1));
return CubicBezierTimingFunction::Create(x1, y1, 0.58, 1);
}

// For large |velocity|, x1 approaches 0 and y1 approaches 0.42. To avoid the
// risk of floating point arithmetic involving infinity and NaN, use those
// values directly rather than computing them above.
return CubicBezierTimingFunction::Create(0, 0.42, 0.58, 1);
}

} // namespace
Expand Down
23 changes: 23 additions & 0 deletions cc/animation/scroll_offset_animation_curve_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -154,5 +154,28 @@ TEST(ScrollOffsetAnimationCurveTest, UpdateTarget) {
EXPECT_EQ(7200.0, curve->GetValue(base::TimeDelta::FromSecondsD(1.674)).y());
}

TEST(ScrollOffsetAnimationCurveTest, UpdateTargetWithLargeVelocity) {
gfx::ScrollOffset initial_value(0.f, 0.f);
gfx::ScrollOffset target_value(0.f, 900.f);
scoped_ptr<ScrollOffsetAnimationCurve> curve(
ScrollOffsetAnimationCurve::Create(
target_value, EaseInOutTimingFunction::Create().Pass()));
curve->SetInitialValue(initial_value);
EXPECT_EQ(0.5, curve->Duration().InSecondsF());

EXPECT_EQ(450.0, curve->GetValue(base::TimeDelta::FromSecondsD(0.25)).y());

// This leads to a new computed velocity larger than 5000.
curve->UpdateTarget(0.25, gfx::ScrollOffset(0.0, 450.0001));

EXPECT_NEAR(0.25015, curve->Duration().InSecondsF(), 0.0001);
EXPECT_NEAR(450.0,
curve->GetValue(base::TimeDelta::FromSecondsD(0.22501)).y(),
0.001);
EXPECT_NEAR(450.0,
curve->GetValue(base::TimeDelta::FromSecondsD(0.225015)).y(),
0.001);
}

} // namespace
} // namespace cc

0 comments on commit 45889f7

Please sign in to comment.