| Index: ui/events/gesture_detection/velocity_tracker.cc
|
| diff --git a/ui/events/gesture_detection/velocity_tracker.cc b/ui/events/gesture_detection/velocity_tracker.cc
|
| index 46f87d4cf1a33c23561065951fbc24a06f05d42f..64583fdc25a31ad0e94e9cdc84beada1aa2fc43a 100644
|
| --- a/ui/events/gesture_detection/velocity_tracker.cc
|
| +++ b/ui/events/gesture_detection/velocity_tracker.cc
|
| @@ -32,7 +32,7 @@ class VelocityTrackerStrategy {
|
|
|
| namespace {
|
|
|
| -COMPILE_ASSERT(MotionEvent::MAX_POINTER_ID < 32, max_pointer_id_too_large);
|
| +static_assert(MotionEvent::MAX_POINTER_ID < 32, "max pointer id too large");
|
|
|
| // Threshold between ACTION_MOVE events for determining that a pointer has
|
| // stopped moving. Some input devices do not send ACTION_MOVE events in the case
|
| @@ -113,12 +113,24 @@ class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy {
|
| WEIGHTING_RECENT,
|
| };
|
|
|
| + enum Restriction {
|
| + // There's no restriction on the output of the velocity tracker.
|
| + RESTRICTION_NONE,
|
| +
|
| + // If the velocity determined by the tracker is in a sufficiently different
|
| + // direction from the primary motion of the finger for the events being
|
| + // considered for velocity calculation, return a velocity of 0.
|
| + RESTRICTION_ALIGNED_DIRECTIONS
|
| + };
|
| +
|
| // Number of samples to keep.
|
| static const uint8_t kHistorySize = 20;
|
|
|
| // Degree must be no greater than Estimator::kMaxDegree.
|
| - LeastSquaresVelocityTrackerStrategy(uint32_t degree,
|
| - Weighting weighting = WEIGHTING_NONE);
|
| + LeastSquaresVelocityTrackerStrategy(
|
| + uint32_t degree,
|
| + Weighting weighting,
|
| + Restriction restriction);
|
| ~LeastSquaresVelocityTrackerStrategy() override;
|
|
|
| void Clear() override;
|
| @@ -148,6 +160,7 @@ class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy {
|
|
|
| const uint32_t degree_;
|
| const Weighting weighting_;
|
| + const Restriction restriction_;
|
| uint32_t index_;
|
| Movement movements_[kHistorySize];
|
| };
|
| @@ -192,28 +205,40 @@ class IntegratingVelocityTrackerStrategy : public VelocityTrackerStrategy {
|
| };
|
|
|
| VelocityTrackerStrategy* CreateStrategy(VelocityTracker::Strategy strategy) {
|
| + LeastSquaresVelocityTrackerStrategy::Weighting none =
|
| + LeastSquaresVelocityTrackerStrategy::WEIGHTING_NONE;
|
| + LeastSquaresVelocityTrackerStrategy::Restriction no_restriction =
|
| + LeastSquaresVelocityTrackerStrategy::RESTRICTION_NONE;
|
| switch (strategy) {
|
| case VelocityTracker::LSQ1:
|
| - return new LeastSquaresVelocityTrackerStrategy(1);
|
| + return new LeastSquaresVelocityTrackerStrategy(1, none, no_restriction);
|
| case VelocityTracker::LSQ2:
|
| - return new LeastSquaresVelocityTrackerStrategy(2);
|
| + return new LeastSquaresVelocityTrackerStrategy(2, none, no_restriction);
|
| + case VelocityTracker::LSQ2_RESTRICTED:
|
| + return new LeastSquaresVelocityTrackerStrategy(
|
| + 2, LeastSquaresVelocityTrackerStrategy::WEIGHTING_NONE,
|
| + LeastSquaresVelocityTrackerStrategy::RESTRICTION_ALIGNED_DIRECTIONS);
|
| case VelocityTracker::LSQ3:
|
| - return new LeastSquaresVelocityTrackerStrategy(3);
|
| + return new LeastSquaresVelocityTrackerStrategy(3, none, no_restriction);
|
| case VelocityTracker::WLSQ2_DELTA:
|
| return new LeastSquaresVelocityTrackerStrategy(
|
| - 2, LeastSquaresVelocityTrackerStrategy::WEIGHTING_DELTA);
|
| + 2, LeastSquaresVelocityTrackerStrategy::WEIGHTING_DELTA,
|
| + no_restriction);
|
| case VelocityTracker::WLSQ2_CENTRAL:
|
| return new LeastSquaresVelocityTrackerStrategy(
|
| - 2, LeastSquaresVelocityTrackerStrategy::WEIGHTING_CENTRAL);
|
| + 2, LeastSquaresVelocityTrackerStrategy::WEIGHTING_CENTRAL,
|
| + no_restriction);
|
| case VelocityTracker::WLSQ2_RECENT:
|
| return new LeastSquaresVelocityTrackerStrategy(
|
| - 2, LeastSquaresVelocityTrackerStrategy::WEIGHTING_RECENT);
|
| + 2, LeastSquaresVelocityTrackerStrategy::WEIGHTING_RECENT,
|
| + no_restriction);
|
| case VelocityTracker::INT1:
|
| return new IntegratingVelocityTrackerStrategy(1);
|
| case VelocityTracker::INT2:
|
| return new IntegratingVelocityTrackerStrategy(2);
|
| }
|
| NOTREACHED() << "Unrecognized velocity tracker strategy: " << strategy;
|
| + // Quadratic regression is a safe default.
|
| return CreateStrategy(VelocityTracker::STRATEGY_DEFAULT);
|
| }
|
|
|
| @@ -221,11 +246,6 @@ VelocityTrackerStrategy* CreateStrategy(VelocityTracker::Strategy strategy) {
|
|
|
| // --- VelocityTracker ---
|
|
|
| -VelocityTracker::VelocityTracker()
|
| - : current_pointer_id_bits_(0),
|
| - active_pointer_id_(-1),
|
| - strategy_(CreateStrategy(STRATEGY_DEFAULT)) {}
|
| -
|
| VelocityTracker::VelocityTracker(Strategy strategy)
|
| : current_pointer_id_bits_(0),
|
| active_pointer_id_(-1),
|
| @@ -391,8 +411,11 @@ bool VelocityTracker::GetEstimator(uint32_t id,
|
|
|
| LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(
|
| uint32_t degree,
|
| - Weighting weighting)
|
| - : degree_(degree), weighting_(weighting) {
|
| + Weighting weighting,
|
| + Restriction restriction)
|
| + : degree_(degree),
|
| + weighting_(weighting),
|
| + restriction_(restriction) {
|
| DCHECK_LT(degree_, static_cast<uint32_t>(Estimator::kMaxDegree));
|
| Clear();
|
| }
|
| @@ -578,11 +601,14 @@ bool LeastSquaresVelocityTrackerStrategy::GetEstimator(
|
| uint32_t index = index_;
|
| const base::TimeDelta horizon = base::TimeDelta::FromMilliseconds(kHorizonMS);
|
| const Movement& newest_movement = movements_[index_];
|
| + const Movement* first_movement = nullptr;
|
| +
|
| do {
|
| const Movement& movement = movements_[index];
|
| if (!movement.id_bits.has_bit(id))
|
| break;
|
|
|
| + first_movement = &movement;
|
| TimeDelta age = newest_movement.event_time - movement.event_time;
|
| if (age > horizon)
|
| break;
|
| @@ -608,6 +634,19 @@ bool LeastSquaresVelocityTrackerStrategy::GetEstimator(
|
| uint32_t n = degree + 1;
|
| if (SolveLeastSquares(time, x, w, m, n, out_estimator->xcoeff, &xdet) &&
|
| SolveLeastSquares(time, y, w, m, n, out_estimator->ycoeff, &ydet)) {
|
| + if (restriction_ == RESTRICTION_ALIGNED_DIRECTIONS) {
|
| + DCHECK(first_movement);
|
| + float dx = newest_movement.GetPosition(id).x -
|
| + first_movement->GetPosition(id).x;
|
| + float dy = newest_movement.GetPosition(id).y -
|
| + first_movement->GetPosition(id).y;
|
| +
|
| + // If the velocity is in a sufficiently different direction from the
|
| + // primary movement, ignore it.
|
| + if (out_estimator->xcoeff[1] * dx + out_estimator->ycoeff[1] * dy < 0)
|
| + return false;
|
| + }
|
| +
|
| out_estimator->time = newest_movement.event_time;
|
| out_estimator->degree = degree;
|
| out_estimator->confidence = xdet * ydet;
|
|
|