Revert 268405 "Make sure that ScratchBuffer::Allocate() always r..."
[chromium-blink-merge.git] / content / browser / renderer_host / input / synthetic_pinch_gesture.cc
blob7a72dfdbdee78e395a0775ca1e0a81180ff86108
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/input/synthetic_pinch_gesture.h"
7 #include <cmath>
9 #include "base/logging.h"
10 #include "ui/events/latency_info.h"
12 namespace content {
14 SyntheticPinchGesture::SyntheticPinchGesture(
15 const SyntheticPinchGestureParams& params)
16 : params_(params),
17 start_y_0_(0.0f),
18 start_y_1_(0.0f),
19 gesture_source_type_(SyntheticGestureParams::DEFAULT_INPUT),
20 state_(SETUP) {
21 DCHECK_GE(params_.total_num_pixels_covered, 0);
24 SyntheticPinchGesture::~SyntheticPinchGesture() {}
26 SyntheticGesture::Result SyntheticPinchGesture::ForwardInputEvents(
27 const base::TimeTicks& timestamp, SyntheticGestureTarget* target) {
28 if (state_ == SETUP) {
29 gesture_source_type_ = params_.gesture_source_type;
30 if (gesture_source_type_ == SyntheticGestureParams::DEFAULT_INPUT)
31 gesture_source_type_ = target->GetDefaultSyntheticGestureSourceType();
33 state_ = STARTED;
34 start_time_ = timestamp;
37 DCHECK_NE(gesture_source_type_, SyntheticGestureParams::DEFAULT_INPUT);
38 if (gesture_source_type_ == SyntheticGestureParams::TOUCH_INPUT)
39 ForwardTouchInputEvents(timestamp, target);
40 else
41 return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED;
43 return (state_ == DONE) ? SyntheticGesture::GESTURE_FINISHED
44 : SyntheticGesture::GESTURE_RUNNING;
47 void SyntheticPinchGesture::ForwardTouchInputEvents(
48 const base::TimeTicks& timestamp, SyntheticGestureTarget* target) {
49 switch (state_) {
50 case STARTED:
51 // Check for an early finish.
52 if (params_.total_num_pixels_covered == 0) {
53 state_ = DONE;
54 break;
56 SetupCoordinatesAndStopTime(target);
57 PressTouchPoints(target, timestamp);
58 state_ = MOVING;
59 break;
60 case MOVING: {
61 base::TimeTicks event_timestamp = ClampTimestamp(timestamp);
62 float delta = GetDeltaForPointer0AtTime(event_timestamp);
63 MoveTouchPoints(target, delta, event_timestamp);
64 if (HasReachedTarget(event_timestamp)) {
65 ReleaseTouchPoints(target, event_timestamp);
66 state_ = DONE;
68 } break;
69 case SETUP:
70 NOTREACHED() << "State SETUP invalid for synthetic pinch.";
71 case DONE:
72 NOTREACHED() << "State DONE invalid for synthetic pinch.";
76 void SyntheticPinchGesture::PressTouchPoints(SyntheticGestureTarget* target,
77 const base::TimeTicks& timestamp) {
78 touch_event_.PressPoint(params_.anchor.x(), start_y_0_);
79 touch_event_.PressPoint(params_.anchor.x(), start_y_1_);
80 ForwardTouchEvent(target, timestamp);
83 void SyntheticPinchGesture::MoveTouchPoints(SyntheticGestureTarget* target,
84 float delta,
85 const base::TimeTicks& timestamp) {
86 // The two pointers move in opposite directions.
87 float current_y_0 = start_y_0_ + delta;
88 float current_y_1 = start_y_1_ - delta;
90 // The current pointer positions are stored as float but the pointer
91 // coordinates of the input event are integers. Floor both positions so that
92 // in case of an odd distance one of the pointers (the one whose position goes
93 // down) moves one pixel further than the other. The explicit flooring is only
94 // needed for negative values.
95 touch_event_.MovePoint(0, params_.anchor.x(), floor(current_y_0));
96 touch_event_.MovePoint(1, params_.anchor.x(), floor(current_y_1));
97 ForwardTouchEvent(target, timestamp);
100 void SyntheticPinchGesture::ReleaseTouchPoints(
101 SyntheticGestureTarget* target, const base::TimeTicks& timestamp) {
102 touch_event_.ReleasePoint(0);
103 touch_event_.ReleasePoint(1);
104 ForwardTouchEvent(target, timestamp);
107 void SyntheticPinchGesture::ForwardTouchEvent(
108 SyntheticGestureTarget* target, const base::TimeTicks& timestamp) {
109 touch_event_.timeStampSeconds = ConvertTimestampToSeconds(timestamp);
110 target->DispatchInputEventToPlatform(touch_event_);
113 void SyntheticPinchGesture::SetupCoordinatesAndStopTime(
114 SyntheticGestureTarget* target) {
115 const int kTouchSlopInDips = target->GetTouchSlopInDips();
116 params_.total_num_pixels_covered += 2 * kTouchSlopInDips;
117 float inner_distance_to_anchor = 2 * kTouchSlopInDips;
118 float outer_distance_to_anchor =
119 inner_distance_to_anchor + params_.total_num_pixels_covered / 2.0f;
121 // Move pointers away from each other to zoom in
122 // or towards each other to zoom out.
123 if (params_.zoom_in) {
124 start_y_0_ = params_.anchor.y() - inner_distance_to_anchor;
125 start_y_1_ = params_.anchor.y() + inner_distance_to_anchor;
126 } else {
127 start_y_0_ = params_.anchor.y() - outer_distance_to_anchor;
128 start_y_1_ = params_.anchor.y() + outer_distance_to_anchor;
131 int64 total_duration_in_us = static_cast<int64>(
132 1e6 * (static_cast<double>(params_.total_num_pixels_covered) /
133 params_.relative_pointer_speed_in_pixels_s));
134 DCHECK_GT(total_duration_in_us, 0);
135 stop_time_ =
136 start_time_ + base::TimeDelta::FromMicroseconds(total_duration_in_us);
139 float SyntheticPinchGesture::GetDeltaForPointer0AtTime(
140 const base::TimeTicks& timestamp) const {
141 float total_abs_delta;
143 // Make sure the final delta is correct. Using the computation below can lead
144 // to issues with floating point precision.
145 if (HasReachedTarget(timestamp))
146 total_abs_delta = params_.total_num_pixels_covered;
147 else
148 total_abs_delta = params_.relative_pointer_speed_in_pixels_s *
149 (timestamp - start_time_).InSecondsF();
151 float abs_delta_pointer_0 = total_abs_delta / 2.0f;
152 return params_.zoom_in ? -abs_delta_pointer_0 : abs_delta_pointer_0;
155 base::TimeTicks SyntheticPinchGesture::ClampTimestamp(
156 const base::TimeTicks& timestamp) const {
157 return std::min(timestamp, stop_time_);
160 bool SyntheticPinchGesture::HasReachedTarget(const base::TimeTicks& timestamp)
161 const {
162 return timestamp >= stop_time_;
165 } // namespace content