1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// found in the LICENSE file.
4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/events/gesture_detection/scale_gesture_detector.h"
6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <limits.h>
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include <cmath>
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/float_util.h"
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/logging.h"
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/events/gesture_detection/motion_event.h"
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)using base::TimeDelta;
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)using base::TimeTicks;
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace ui {
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace {
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
20a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// Using a small epsilon when comparing slop distances allows pixel perfect
21a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// slop determination when using fractional DPI coordinates (assuming the slop
22a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch// region and DPI scale are reasonably proportioned).
23a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochconst float kSlopEpsilon = .05f;
24a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const int kTouchStabilizeTimeMs = 128;
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const float kScaleFactor = .5f;
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Note: These constants were taken directly from the default (unscaled)
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// versions found in Android's ViewConfiguration.
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)ScaleGestureDetector::Config::Config()
3403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    : span_slop(16),
3503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      min_scaling_touch_major(48),
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      min_scaling_span(200),
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      min_pinch_update_span_delta(0) {
38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)ScaleGestureDetector::Config::~Config() {}
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ScaleGestureDetector::SimpleScaleGestureListener::OnScale(
43c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const ScaleGestureDetector&, const MotionEvent&) {
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return false;
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ScaleGestureDetector::SimpleScaleGestureListener::OnScaleBegin(
48c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const ScaleGestureDetector&, const MotionEvent&) {
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return true;
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ScaleGestureDetector::SimpleScaleGestureListener::OnScaleEnd(
53c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const ScaleGestureDetector&, const MotionEvent&) {}
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)ScaleGestureDetector::ScaleGestureDetector(const Config& config,
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                           ScaleGestureListener* listener)
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : listener_(listener),
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      focus_x_(0),
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      focus_y_(0),
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      curr_span_(0),
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      prev_span_(0),
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      initial_span_(0),
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      curr_span_x_(0),
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      curr_span_y_(0),
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      prev_span_x_(0),
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      prev_span_y_(0),
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      in_progress_(0),
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      span_slop_(0),
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      min_span_(0),
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      touch_upper_(0),
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      touch_lower_(0),
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      touch_history_last_accepted_(0),
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      touch_history_direction_(0),
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      touch_min_major_(0),
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      touch_max_major_(0),
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      double_tap_focus_x_(0),
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      double_tap_focus_y_(0),
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      double_tap_mode_(DOUBLE_TAP_MODE_NONE),
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      event_before_or_above_starting_gesture_event_(false) {
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(listener_);
8103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  span_slop_ = config.span_slop + kSlopEpsilon;
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  touch_min_major_ = config.min_scaling_touch_major;
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  touch_max_major_ = std::min(config.min_scaling_span / std::sqrt(2.f),
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                              2.f * touch_min_major_);
85a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  min_span_ = config.min_scaling_span + kSlopEpsilon;
86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ResetTouchHistory();
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)ScaleGestureDetector::~ScaleGestureDetector() {}
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ScaleGestureDetector::OnTouchEvent(const MotionEvent& event) {
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  curr_time_ = event.GetEventTime();
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const int action = event.GetAction();
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const bool stream_complete =
97c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      action == MotionEvent::ACTION_UP ||
98c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      action == MotionEvent::ACTION_CANCEL ||
99c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      (action == MotionEvent::ACTION_POINTER_DOWN && InDoubleTapMode());
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (action == MotionEvent::ACTION_DOWN || stream_complete) {
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Reset any scale in progress with the listener.
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // If it's an ACTION_DOWN we're beginning a new event stream.
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // This means the app probably didn't give us all the events. Shame on it.
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (in_progress_) {
106c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      listener_->OnScaleEnd(*this, event);
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ResetScaleWithSpan(0);
108c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    } else if (InDoubleTapMode() && stream_complete) {
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ResetScaleWithSpan(0);
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (stream_complete) {
113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      ResetTouchHistory();
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return true;
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const bool config_changed = action == MotionEvent::ACTION_DOWN ||
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                              action == MotionEvent::ACTION_POINTER_UP ||
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                              action == MotionEvent::ACTION_POINTER_DOWN;
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const bool pointer_up = action == MotionEvent::ACTION_POINTER_UP;
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const int skip_index = pointer_up ? event.GetActionIndex() : -1;
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Determine focal point.
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float sum_x = 0, sum_y = 0;
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const int count = static_cast<int>(event.GetPointerCount());
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const int unreleased_point_count = pointer_up ? count - 1 : count;
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const float inverse_unreleased_point_count = 1.0f / unreleased_point_count;
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float focus_x;
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float focus_y;
133c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (InDoubleTapMode()) {
134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // In double tap mode, the focal pt is always where the double tap
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // gesture started.
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    focus_x = double_tap_focus_x_;
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    focus_y = double_tap_focus_y_;
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (event.GetY() < focus_y) {
139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      event_before_or_above_starting_gesture_event_ = true;
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else {
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      event_before_or_above_starting_gesture_event_ = false;
142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for (int i = 0; i < count; i++) {
145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (skip_index == i)
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        continue;
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      sum_x += event.GetX(i);
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      sum_y += event.GetY(i);
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    focus_x = sum_x * inverse_unreleased_point_count;
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    focus_y = sum_y * inverse_unreleased_point_count;
153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  AddTouchHistory(event);
156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Determine average deviation from focal point.
158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float dev_sum_x = 0, dev_sum_y = 0;
159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (int i = 0; i < count; i++) {
160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (skip_index == i)
161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      continue;
162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    dev_sum_x += std::abs(event.GetX(i) - focus_x);
164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    dev_sum_y += std::abs(event.GetY(i) - focus_y);
165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Convert the resulting diameter into a radius, to include touch
167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // radius in overall deviation.
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const float touch_radius = touch_history_last_accepted_ / 2;
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const float dev_x = dev_sum_x * inverse_unreleased_point_count + touch_radius;
171116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const float dev_y = dev_sum_y * inverse_unreleased_point_count + touch_radius;
172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Span is the average distance between touch points through the focal point;
174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // i.e. the diameter of the circle with a radius of the average deviation from
175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // the focal point.
176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const float span_x = dev_x * 2;
177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const float span_y = dev_y * 2;
178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float span;
179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (InDoubleTapMode()) {
180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    span = span_y;
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    span = std::sqrt(span_x * span_x + span_y * span_y);
183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Dispatch begin/end events as needed.
186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If the configuration changes, notify the app to reset its current state by
187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // beginning a fresh scale event stream.
188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const bool was_in_progress = in_progress_;
189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  focus_x_ = focus_x;
190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  focus_y_ = focus_y;
191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!InDoubleTapMode() && in_progress_ &&
192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      (span < min_span_ || config_changed)) {
193c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    listener_->OnScaleEnd(*this, event);
194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ResetScaleWithSpan(span);
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (config_changed) {
197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    prev_span_x_ = curr_span_x_ = span_x;
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    prev_span_y_ = curr_span_y_ = span_y;
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    initial_span_ = prev_span_ = curr_span_ = span;
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
202a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  const float min_span = InDoubleTapMode() ? span_slop_ : min_span_;
2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!in_progress_ && span >= min_span &&
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      (was_in_progress || std::abs(span - initial_span_) > span_slop_)) {
205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    prev_span_x_ = curr_span_x_ = span_x;
206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    prev_span_y_ = curr_span_y_ = span_y;
207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    prev_span_ = curr_span_ = span;
208a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    prev_time_ = curr_time_;
209c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    in_progress_ = listener_->OnScaleBegin(*this, event);
210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
212a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Handle motion; focal point and span/scale factor are changing.
213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (action == MotionEvent::ACTION_MOVE) {
214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    curr_span_x_ = span_x;
215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    curr_span_y_ = span_y;
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    curr_span_ = span;
217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    bool update_prev = true;
219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (in_progress_) {
221c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      update_prev = listener_->OnScale(*this, event);
222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (update_prev) {
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      prev_span_x_ = curr_span_x_;
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      prev_span_y_ = curr_span_y_;
227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      prev_span_ = curr_span_;
228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      prev_time_ = curr_time_;
229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return true;
233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
235a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ScaleGestureDetector::IsInProgress() const { return in_progress_; }
236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
237c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool ScaleGestureDetector::InDoubleTapMode() const {
238c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return double_tap_mode_ == DOUBLE_TAP_MODE_IN_PROGRESS;
239c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
240c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float ScaleGestureDetector::GetFocusX() const { return focus_x_; }
242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float ScaleGestureDetector::GetFocusY() const { return focus_y_; }
244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float ScaleGestureDetector::GetCurrentSpan() const { return curr_span_; }
246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float ScaleGestureDetector::GetCurrentSpanX() const { return curr_span_x_; }
248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float ScaleGestureDetector::GetCurrentSpanY() const { return curr_span_y_; }
250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float ScaleGestureDetector::GetPreviousSpan() const { return prev_span_; }
252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float ScaleGestureDetector::GetPreviousSpanX() const { return prev_span_x_; }
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float ScaleGestureDetector::GetPreviousSpanY() const { return prev_span_y_; }
256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)float ScaleGestureDetector::GetScaleFactor() const {
258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (InDoubleTapMode()) {
259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Drag is moving up; the further away from the gesture start, the smaller
260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // the span should be, the closer, the larger the span, and therefore the
261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // larger the scale.
262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const bool scale_up = (event_before_or_above_starting_gesture_event_ &&
263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           (curr_span_ < prev_span_)) ||
264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                          (!event_before_or_above_starting_gesture_event_ &&
265a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           (curr_span_ > prev_span_));
266a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const float span_diff =
267a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        (std::abs(1.f - (curr_span_ / prev_span_)) * kScaleFactor);
268a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return prev_span_ <= 0 ? 1.f
269a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           : (scale_up ? (1.f + span_diff) : (1.f - span_diff));
270a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
271a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return prev_span_ > 0 ? curr_span_ / prev_span_ : 1;
272a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)base::TimeDelta ScaleGestureDetector::GetTimeDelta() const {
275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return curr_time_ - prev_time_;
276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)base::TimeTicks ScaleGestureDetector::GetEventTime() const {
279a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return curr_time_;
280a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
281a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
282a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ScaleGestureDetector::OnDoubleTap(const MotionEvent& ev) {
283a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Double tap: start watching for a swipe.
284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  double_tap_focus_x_ = ev.GetX();
285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  double_tap_focus_y_ = ev.GetY();
286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  double_tap_mode_ = DOUBLE_TAP_MODE_IN_PROGRESS;
287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return true;
288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
290a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ScaleGestureDetector::AddTouchHistory(const MotionEvent& ev) {
291f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const base::TimeTicks current_time = ev.GetEventTime();
292f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(!current_time.is_null());
293a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const int count = static_cast<int>(ev.GetPointerCount());
294f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool accept = touch_history_last_accepted_time_.is_null() ||
295f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                (current_time - touch_history_last_accepted_time_) >=
296f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                    base::TimeDelta::FromMilliseconds(kTouchStabilizeTimeMs);
297a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  float total = 0;
298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int sample_count = 0;
299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (int i = 0; i < count; i++) {
300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const bool has_last_accepted = !base::IsNaN(touch_history_last_accepted_);
301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const int history_size = static_cast<int>(ev.GetHistorySize());
302a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const int pointersample_count = history_size + 1;
303a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for (int h = 0; h < pointersample_count; h++) {
304a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      float major;
305a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (h < history_size) {
306a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        major = ev.GetHistoricalTouchMajor(i, h);
307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      } else {
308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        major = ev.GetTouchMajor(i);
309a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
310a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (major < touch_min_major_)
311a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        major = touch_min_major_;
312116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if (major > touch_max_major_)
313116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        major = touch_max_major_;
314a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      total += major;
315a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
316a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (base::IsNaN(touch_upper_) || major > touch_upper_) {
317a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        touch_upper_ = major;
318a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
319a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (base::IsNaN(touch_lower_) || major < touch_lower_) {
320a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        touch_lower_ = major;
321a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
322a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
323a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (has_last_accepted) {
324a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        const float major_delta = major - touch_history_last_accepted_;
325a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        const int direction_sig =
326a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            major_delta > 0 ? 1 : (major_delta < 0 ? -1 : 0);
327a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        if (direction_sig != touch_history_direction_ ||
328a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            (direction_sig == 0 && touch_history_direction_ == 0)) {
329a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          touch_history_direction_ = direction_sig;
330a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          touch_history_last_accepted_time_ = h < history_size
331a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                  ? ev.GetHistoricalEventTime(h)
332a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                  : ev.GetEventTime();
333a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          accept = false;
334a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        }
335a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
336a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
337a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    sample_count += pointersample_count;
338a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
339a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
340a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const float avg = total / sample_count;
341a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
342a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (accept) {
343a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    float new_accepted = (touch_upper_ + touch_lower_ + avg) / 3;
344a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    touch_upper_ = (touch_upper_ + new_accepted) / 2;
345a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    touch_lower_ = (touch_lower_ + new_accepted) / 2;
346a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    touch_history_last_accepted_ = new_accepted;
347a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    touch_history_direction_ = 0;
348a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    touch_history_last_accepted_time_ = ev.GetEventTime();
349a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
350a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
351a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
352f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ScaleGestureDetector::ResetTouchHistory() {
353a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  touch_upper_ = std::numeric_limits<float>::quiet_NaN();
354a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  touch_lower_ = std::numeric_limits<float>::quiet_NaN();
355a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  touch_history_last_accepted_ = std::numeric_limits<float>::quiet_NaN();
356a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  touch_history_direction_ = 0;
357a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  touch_history_last_accepted_time_ = base::TimeTicks();
358a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
359a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
360cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ScaleGestureDetector::ResetScaleWithSpan(float span) {
361cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  in_progress_ = false;
362cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  initial_span_ = span;
363cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  double_tap_mode_ = DOUBLE_TAP_MODE_NONE;
364cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
365cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
366a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace ui
367