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 max_pointer_delta_0_(0.0f
),
20 gesture_source_type_(SyntheticGestureParams::DEFAULT_INPUT
),
22 DCHECK_GT(params_
.scale_factor
, 0.0f
);
25 SyntheticPinchGesture::~SyntheticPinchGesture() {}
27 SyntheticGesture::Result
SyntheticPinchGesture::ForwardInputEvents(
28 const base::TimeTicks
& timestamp
, SyntheticGestureTarget
* target
) {
29 if (state_
== SETUP
) {
30 gesture_source_type_
= params_
.gesture_source_type
;
31 if (gesture_source_type_
== SyntheticGestureParams::DEFAULT_INPUT
)
32 gesture_source_type_
= target
->GetDefaultSyntheticGestureSourceType();
35 start_time_
= timestamp
;
38 DCHECK_NE(gesture_source_type_
, SyntheticGestureParams::DEFAULT_INPUT
);
39 if (gesture_source_type_
== SyntheticGestureParams::TOUCH_INPUT
)
40 ForwardTouchInputEvents(timestamp
, target
);
42 return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED
;
44 return (state_
== DONE
) ? SyntheticGesture::GESTURE_FINISHED
45 : SyntheticGesture::GESTURE_RUNNING
;
48 void SyntheticPinchGesture::ForwardTouchInputEvents(
49 const base::TimeTicks
& timestamp
, SyntheticGestureTarget
* target
) {
52 // Check for an early finish.
53 if (params_
.scale_factor
== 1.0f
) {
57 SetupCoordinatesAndStopTime(target
);
58 PressTouchPoints(target
, timestamp
);
62 base::TimeTicks event_timestamp
= ClampTimestamp(timestamp
);
63 float delta
= GetDeltaForPointer0AtTime(event_timestamp
);
64 MoveTouchPoints(target
, delta
, event_timestamp
);
65 if (HasReachedTarget(event_timestamp
)) {
66 ReleaseTouchPoints(target
, event_timestamp
);
71 NOTREACHED() << "State SETUP invalid for synthetic pinch.";
73 NOTREACHED() << "State DONE invalid for synthetic pinch.";
77 void SyntheticPinchGesture::PressTouchPoints(SyntheticGestureTarget
* target
,
78 const base::TimeTicks
& timestamp
) {
79 touch_event_
.PressPoint(params_
.anchor
.x(), start_y_0_
);
80 touch_event_
.PressPoint(params_
.anchor
.x(), start_y_1_
);
81 ForwardTouchEvent(target
, timestamp
);
84 void SyntheticPinchGesture::MoveTouchPoints(SyntheticGestureTarget
* target
,
86 const base::TimeTicks
& timestamp
) {
87 // The two pointers move in opposite directions.
88 float current_y_0
= start_y_0_
+ delta
;
89 float current_y_1
= start_y_1_
- delta
;
91 touch_event_
.MovePoint(0, params_
.anchor
.x(), current_y_0
);
92 touch_event_
.MovePoint(1, params_
.anchor
.x(), current_y_1
);
93 ForwardTouchEvent(target
, timestamp
);
96 void SyntheticPinchGesture::ReleaseTouchPoints(
97 SyntheticGestureTarget
* target
, const base::TimeTicks
& timestamp
) {
98 touch_event_
.ReleasePoint(0);
99 touch_event_
.ReleasePoint(1);
100 ForwardTouchEvent(target
, timestamp
);
103 void SyntheticPinchGesture::ForwardTouchEvent(
104 SyntheticGestureTarget
* target
, const base::TimeTicks
& timestamp
) {
105 touch_event_
.timeStampSeconds
= ConvertTimestampToSeconds(timestamp
);
106 target
->DispatchInputEventToPlatform(touch_event_
);
109 void SyntheticPinchGesture::SetupCoordinatesAndStopTime(
110 SyntheticGestureTarget
* target
) {
111 // To achieve the specified scaling factor, the ratio of the final to the
112 // initial span (distance between the pointers) has to be equal to the scaling
113 // factor. Since we're moving both pointers at the same speed, each pointer's
114 // distance to the anchor is half the span.
115 float initial_distance_to_anchor
, final_distance_to_anchor
;
116 if (params_
.scale_factor
> 1.0f
) { // zooming in
117 initial_distance_to_anchor
= target
->GetMinScalingSpanInDips() / 2.0f
;
118 final_distance_to_anchor
=
119 (initial_distance_to_anchor
+ target
->GetTouchSlopInDips()) *
120 params_
.scale_factor
;
121 } else { // zooming out
122 final_distance_to_anchor
= target
->GetMinScalingSpanInDips() / 2.0f
;
123 initial_distance_to_anchor
=
124 (final_distance_to_anchor
/ params_
.scale_factor
) +
125 target
->GetTouchSlopInDips();
128 start_y_0_
= params_
.anchor
.y() - initial_distance_to_anchor
;
129 start_y_1_
= params_
.anchor
.y() + initial_distance_to_anchor
;
131 max_pointer_delta_0_
= initial_distance_to_anchor
- final_distance_to_anchor
;
133 int64 total_duration_in_us
= static_cast<int64
>(
134 1e6
* (static_cast<double>(std::abs(2 * max_pointer_delta_0_
)) /
135 params_
.relative_pointer_speed_in_pixels_s
));
136 DCHECK_GT(total_duration_in_us
, 0);
138 start_time_
+ base::TimeDelta::FromMicroseconds(total_duration_in_us
);
141 float SyntheticPinchGesture::GetDeltaForPointer0AtTime(
142 const base::TimeTicks
& timestamp
) const {
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 return max_pointer_delta_0_
;
148 float total_abs_delta
= params_
.relative_pointer_speed_in_pixels_s
*
149 (timestamp
- start_time_
).InSecondsF();
150 float abs_delta_pointer_0
= total_abs_delta
/ 2.0f
;
151 return (params_
.scale_factor
> 1.0f
) ? -abs_delta_pointer_0
152 : 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