diff options
Diffstat (limited to 'chromium/ui/events/gesture_detection/velocity_tracker_unittest.cc')
-rw-r--r-- | chromium/ui/events/gesture_detection/velocity_tracker_unittest.cc | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/chromium/ui/events/gesture_detection/velocity_tracker_unittest.cc b/chromium/ui/events/gesture_detection/velocity_tracker_unittest.cc new file mode 100644 index 00000000000..eda1606d141 --- /dev/null +++ b/chromium/ui/events/gesture_detection/velocity_tracker_unittest.cc @@ -0,0 +1,193 @@ +// Copyright 2014 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 "base/basictypes.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/time/time.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/events/gesture_detection/mock_motion_event.h" +#include "ui/events/gesture_detection/velocity_tracker_state.h" +#include "ui/gfx/geometry/point_f.h" +#include "ui/gfx/geometry/vector2d_f.h" + +using base::TimeDelta; +using base::TimeTicks; + +namespace ui { +namespace { + +const TimeDelta kTenMillis = TimeDelta::FromMilliseconds(10); +const TimeDelta kOneSecond = TimeDelta::FromSeconds(1); +const float kEpsilson = .01f; + +const char* GetStrategyName(VelocityTracker::Strategy strategy) { + switch (strategy) { + case VelocityTracker::LSQ1: return "LSQ1"; + case VelocityTracker::LSQ2: return "LSQ2"; + case VelocityTracker::LSQ3: return "LSQ3"; + case VelocityTracker::WLSQ2_DELTA: return "WLSQ2_DELTA"; + case VelocityTracker::WLSQ2_CENTRAL: return "WLSQ2_CENTRAL"; + case VelocityTracker::WLSQ2_RECENT: return "WLSQ2_RECENT"; + case VelocityTracker::INT1: return "INT1"; + case VelocityTracker::INT2: return "INT2"; + }; + NOTREACHED() << "Invalid strategy"; + return ""; +} + +} // namespace + +class VelocityTrackerTest : public testing::Test { + public: + VelocityTrackerTest() {} + virtual ~VelocityTrackerTest() {} + + protected: + static MockMotionEvent Sample(MotionEvent::Action action, + gfx::PointF p0, + TimeTicks t0, + gfx::Vector2dF v, + TimeDelta dt) { + const gfx::PointF p = p0 + ScaleVector2d(v, dt.InSecondsF()); + return MockMotionEvent(action, t0 + dt, p.x(), p.y()); + } + + static void ApplyMovementSequence(VelocityTrackerState* state, + gfx::PointF p0, + gfx::Vector2dF v, + TimeTicks t0, + TimeDelta t, + size_t samples) { + EXPECT_TRUE(!!samples); + if (!samples) + return; + const base::TimeDelta dt = t / samples; + state->AddMovement(Sample(MotionEvent::ACTION_DOWN, p0, t0, v, dt * 0)); + ApplyMovement(state, p0, v, t0, t, samples); + state->AddMovement(Sample(MotionEvent::ACTION_UP, p0, t0, v, t)); + } + + static void ApplyMovement(VelocityTrackerState* state, + gfx::PointF p0, + gfx::Vector2dF v, + TimeTicks t0, + TimeDelta t, + size_t samples) { + EXPECT_TRUE(!!samples); + if (!samples) + return; + const base::TimeDelta dt = t / samples; + for (size_t i = 0; i < samples; ++i) + state->AddMovement(Sample(MotionEvent::ACTION_MOVE, p0, t0, v, dt * i)); + } +}; + +TEST_F(VelocityTrackerTest, Basic) { + const gfx::PointF p0(0, 0); + const gfx::Vector2dF v(0, 500); + const size_t samples = 60; + + for (int i = 0; i <= VelocityTracker::STRATEGY_MAX; ++i) { + VelocityTracker::Strategy strategy = + static_cast<VelocityTracker::Strategy>(i); + + SCOPED_TRACE(GetStrategyName(strategy)); + VelocityTrackerState state(strategy); + + // Default state should report zero velocity. + EXPECT_EQ(0, state.GetXVelocity(0)); + EXPECT_EQ(0, state.GetYVelocity(0)); + + // Sample a constant velocity sequence. + ApplyMovementSequence(&state, p0, v, TimeTicks::Now(), kOneSecond, samples); + + // The computed velocity should match that of the input. + state.ComputeCurrentVelocity(1000, 20000); + EXPECT_NEAR(v.x(), state.GetXVelocity(0), kEpsilson * v.x()); + EXPECT_NEAR(v.y(), state.GetYVelocity(0), kEpsilson * v.y()); + + // A pointer ID of -1 should report the velocity of the active pointer. + EXPECT_NEAR(v.x(), state.GetXVelocity(-1), kEpsilson * v.x()); + EXPECT_NEAR(v.y(), state.GetYVelocity(-1), kEpsilson * v.y()); + + // Invalid pointer ID's should report zero velocity. + EXPECT_EQ(0, state.GetXVelocity(1)); + EXPECT_EQ(0, state.GetYVelocity(1)); + EXPECT_EQ(0, state.GetXVelocity(7)); + EXPECT_EQ(0, state.GetYVelocity(7)); + } +} + +TEST_F(VelocityTrackerTest, MaxVelocity) { + const gfx::PointF p0(0, 0); + const gfx::Vector2dF v(-50000, 50000); + const size_t samples = 3; + const base::TimeDelta dt = kTenMillis * 2; + + VelocityTrackerState state; + ApplyMovementSequence(&state, p0, v, TimeTicks::Now(), dt, samples); + + // The computed velocity should be restricted to the provided maximum. + state.ComputeCurrentVelocity(1000, 100); + EXPECT_NEAR(-100, state.GetXVelocity(0), kEpsilson); + EXPECT_NEAR(100, state.GetYVelocity(0), kEpsilson); + + state.ComputeCurrentVelocity(1000, 1000); + EXPECT_NEAR(-1000, state.GetXVelocity(0), kEpsilson); + EXPECT_NEAR(1000, state.GetYVelocity(0), kEpsilson); +} + +TEST_F(VelocityTrackerTest, VaryingVelocity) { + const gfx::PointF p0(0, 0); + const gfx::Vector2dF vFast(0, 500); + const gfx::Vector2dF vSlow = ScaleVector2d(vFast, 0.5f); + const size_t samples = 12; + + for (int i = 0; i <= VelocityTracker::STRATEGY_MAX; ++i) { + VelocityTracker::Strategy strategy = + static_cast<VelocityTracker::Strategy>(i); + + SCOPED_TRACE(GetStrategyName(strategy)); + VelocityTrackerState state(strategy); + + base::TimeTicks t0 = base::TimeTicks::Now(); + base::TimeDelta dt = kTenMillis * 10; + state.AddMovement( + Sample(MotionEvent::ACTION_DOWN, p0, t0, vFast, base::TimeDelta())); + + // Apply some fast movement and compute the velocity. + gfx::PointF pCurr = p0; + base::TimeTicks tCurr = t0; + ApplyMovement(&state, pCurr, vFast, tCurr, dt, samples); + state.ComputeCurrentVelocity(1000, 20000); + float vOldY = state.GetYVelocity(0); + + // Apply some slow movement. + pCurr += ScaleVector2d(vFast, dt.InSecondsF()); + tCurr += dt; + ApplyMovement(&state, pCurr, vSlow, tCurr, dt, samples); + + // The computed velocity should have decreased. + state.ComputeCurrentVelocity(1000, 20000); + float vCurrentY = state.GetYVelocity(0); + EXPECT_GT(vFast.y(), vCurrentY); + EXPECT_GT(vOldY, vCurrentY); + vOldY = vCurrentY; + + // Apply some additional fast movement. + pCurr += ScaleVector2d(vSlow, dt.InSecondsF()); + tCurr += dt; + ApplyMovement(&state, pCurr, vFast, tCurr, dt, samples); + + // The computed velocity should have increased. + state.ComputeCurrentVelocity(1000, 20000); + vCurrentY = state.GetYVelocity(0); + EXPECT_LT(vSlow.y(), vCurrentY); + EXPECT_LT(vOldY, vCurrentY); + } +} + + +} // namespace ui |