Index: content/browser/renderer_host/input/synthetic_touchpad_pinch_gesture.cc |
diff --git a/content/browser/renderer_host/input/synthetic_touchpad_pinch_gesture.cc b/content/browser/renderer_host/input/synthetic_touchpad_pinch_gesture.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0bf75acb6a6e92896094e654d610e9fb1baf8e53 |
--- /dev/null |
+++ b/content/browser/renderer_host/input/synthetic_touchpad_pinch_gesture.cc |
@@ -0,0 +1,150 @@ |
+// Copyright 2015 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 "content/browser/renderer_host/input/synthetic_touchpad_pinch_gesture.h" |
+ |
+namespace content { |
+namespace { |
+ |
+float Lerp(float start, float end, float progress) { |
+ return start + progress * (end - start); |
+} |
+ |
+} // namespace |
+ |
+SyntheticTouchpadPinchGesture::SyntheticTouchpadPinchGesture( |
+ const SyntheticPinchGestureParams& params) |
+ : params_(params), |
+ gesture_source_type_(SyntheticGestureParams::DEFAULT_INPUT), |
+ state_(SETUP), |
+ current_scale_(1.0f) { |
+ DCHECK_GT(params_.scale_factor, 0.0f); |
+} |
+ |
+SyntheticTouchpadPinchGesture::~SyntheticTouchpadPinchGesture() {} |
+ |
+SyntheticGesture::Result SyntheticTouchpadPinchGesture::ForwardInputEvents( |
+ const base::TimeTicks& timestamp, |
+ SyntheticGestureTarget* target) { |
+ if (state_ == SETUP) { |
+ gesture_source_type_ = params_.gesture_source_type; |
+ if (gesture_source_type_ == SyntheticGestureParams::DEFAULT_INPUT) |
+ gesture_source_type_ = target->GetDefaultSyntheticGestureSourceType(); |
+ |
+ state_ = STARTED; |
+ start_time_ = timestamp; |
+ } |
+ |
+ DCHECK_NE(gesture_source_type_, SyntheticGestureParams::DEFAULT_INPUT); |
+ if (gesture_source_type_ == SyntheticGestureParams::MOUSE_INPUT) { |
+ ForwardGestureEvents(timestamp, target); |
+ } else { |
+ // Touch input should be using SyntheticTouchscreenPinchGesture. |
+ return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED; |
+ } |
+ |
+ return (state_ == DONE) ? SyntheticGesture::GESTURE_FINISHED |
+ : SyntheticGesture::GESTURE_RUNNING; |
+} |
+ |
+void SyntheticTouchpadPinchGesture::ForwardGestureEvents( |
+ const base::TimeTicks& timestamp, |
+ SyntheticGestureTarget* target) { |
+ switch (state_) { |
+ case STARTED: |
+ // Check for an early finish. |
+ if (params_.scale_factor == 1.0f) { |
+ state_ = DONE; |
+ break; |
+ } |
+ |
+ CalculateEndTime(target); |
+ |
+ // Send the start event. |
+ target->DispatchInputEventToPlatform( |
+ SyntheticWebGestureEventBuilder::Build( |
+ blink::WebGestureEvent::GesturePinchBegin, |
+ blink::WebGestureDeviceTouchpad)); |
+ state_ = IN_PROGRESS; |
+ break; |
+ case IN_PROGRESS: { |
+ base::TimeTicks event_timestamp = ClampTimestamp(timestamp); |
+ |
+ float target_scale = CalculateTargetScale(event_timestamp); |
+ float incremental_scale = target_scale / current_scale_; |
+ current_scale_ = target_scale; |
+ |
+ // Send the incremental scale event. |
+ target->DispatchInputEventToPlatform( |
+ SyntheticWebGestureEventBuilder::BuildPinchUpdate( |
+ incremental_scale, params_.anchor.x(), params_.anchor.y(), |
+ 0 /* modifierFlags */, blink::WebGestureDeviceTouchpad)); |
+ |
+ if (HasReachedTarget(event_timestamp)) { |
+ target->DispatchInputEventToPlatform( |
+ SyntheticWebGestureEventBuilder::Build( |
+ blink::WebGestureEvent::GesturePinchEnd, |
+ blink::WebGestureDeviceTouchpad)); |
+ state_ = DONE; |
+ } |
+ break; |
+ } |
+ case SETUP: |
+ NOTREACHED() << "State SETUP invalid for synthetic pinch."; |
+ case DONE: |
+ NOTREACHED() << "State DONE invalid for synthetic pinch."; |
+ } |
+} |
+ |
+float SyntheticTouchpadPinchGesture::CalculateTargetScale( |
+ const base::TimeTicks& timestamp) const { |
+ // Make sure the final delta is correct. Using the computation below can lead |
+ // to issues with floating point precision. |
+ if (HasReachedTarget(timestamp)) |
+ return params_.scale_factor; |
+ |
+ float progress = (timestamp - start_time_).InSecondsF() / |
+ (stop_time_ - start_time_).InSecondsF(); |
+ return Lerp(1.0f, params_.scale_factor, progress); |
+} |
+ |
+// Calculate an end time based on the amount of scaling to be done and the |
+// |relative_pointer_speed_in_pixels_s|. Because we don't have an actual pixel |
+// delta, we assume that a pinch of 200 pixels is needed to double the screen |
+// size and generate a stop time based on that. |
+// TODO(ericrk): We should not calculate duration from |
+// |relative_pointer_speed_in_pixels_s|, but should instead get a duration from |
+// a SyntheticTouchpadPinchGestureParams type. crbug.com/534976 |
+void SyntheticTouchpadPinchGesture::CalculateEndTime( |
+ SyntheticGestureTarget* target) { |
+ const int kPixelsNeededToDoubleOrHalve = 200; |
+ |
+ float scale_factor = params_.scale_factor; |
+ if (scale_factor < 1.0f) { |
+ // If we are scaling down, calculate the time based on the inverse so that |
+ // halving or doubling the scale takes the same amount of time. |
+ scale_factor = 1.0f / scale_factor; |
+ } |
+ float scale_factor_delta = |
+ (scale_factor - 1.0f) * kPixelsNeededToDoubleOrHalve; |
+ |
+ int64 total_duration_in_us = |
+ static_cast<int64>(1e6 * (static_cast<double>(scale_factor_delta) / |
+ params_.relative_pointer_speed_in_pixels_s)); |
+ DCHECK_GT(total_duration_in_us, 0); |
+ stop_time_ = |
+ start_time_ + base::TimeDelta::FromMicroseconds(total_duration_in_us); |
+} |
+ |
+base::TimeTicks SyntheticTouchpadPinchGesture::ClampTimestamp( |
+ const base::TimeTicks& timestamp) const { |
+ return std::min(timestamp, stop_time_); |
+} |
+ |
+bool SyntheticTouchpadPinchGesture::HasReachedTarget( |
+ const base::TimeTicks& timestamp) const { |
+ return timestamp >= stop_time_; |
+} |
+ |
+} // namespace content |