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"
9 #include "base/logging.h"
10 #include "ui/events/latency_info.h"
14 SyntheticPinchGesture::SyntheticPinchGesture(
15 const SyntheticPinchGestureParams
& params
)
19 gesture_source_type_(SyntheticGestureParams::DEFAULT_INPUT
),
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();
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
);
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
) {
51 // Check for an early finish.
52 if (params_
.total_num_pixels_covered
== 0) {
56 SetupCoordinatesAndStopTime(target
);
57 PressTouchPoints(target
, timestamp
);
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
);
70 NOTREACHED() << "State SETUP invalid for synthetic pinch.";
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
,
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
;
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);
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
;
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
)
162 return timestamp
>= stop_time_
;
165 } // namespace content