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