• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "content/browser/renderer_host/input/synthetic_pinch_gesture.h"
6 
7 #include <cmath>
8 
9 #include "base/logging.h"
10 #include "ui/events/latency_info.h"
11 
12 namespace content {
13 
SyntheticPinchGesture(const SyntheticPinchGestureParams & params)14 SyntheticPinchGesture::SyntheticPinchGesture(
15     const SyntheticPinchGestureParams& params)
16     : params_(params),
17       start_y_0_(0.0f),
18       start_y_1_(0.0f),
19       max_pointer_delta_0_(0.0f),
20       gesture_source_type_(SyntheticGestureParams::DEFAULT_INPUT),
21       state_(SETUP) {
22     DCHECK_GT(params_.scale_factor, 0.0f);
23 }
24 
~SyntheticPinchGesture()25 SyntheticPinchGesture::~SyntheticPinchGesture() {}
26 
ForwardInputEvents(const base::TimeTicks & timestamp,SyntheticGestureTarget * target)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();
33 
34     state_ = STARTED;
35     start_time_ = timestamp;
36   }
37 
38   DCHECK_NE(gesture_source_type_, SyntheticGestureParams::DEFAULT_INPUT);
39   if (gesture_source_type_ == SyntheticGestureParams::TOUCH_INPUT)
40     ForwardTouchInputEvents(timestamp, target);
41   else
42     return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED;
43 
44   return (state_ == DONE) ? SyntheticGesture::GESTURE_FINISHED
45                           : SyntheticGesture::GESTURE_RUNNING;
46 }
47 
ForwardTouchInputEvents(const base::TimeTicks & timestamp,SyntheticGestureTarget * target)48 void SyntheticPinchGesture::ForwardTouchInputEvents(
49     const base::TimeTicks& timestamp, SyntheticGestureTarget* target) {
50   switch (state_) {
51     case STARTED:
52       // Check for an early finish.
53       if (params_.scale_factor == 1.0f) {
54         state_ = DONE;
55         break;
56       }
57       SetupCoordinatesAndStopTime(target);
58       PressTouchPoints(target, timestamp);
59       state_ = MOVING;
60       break;
61     case MOVING: {
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);
67         state_ = DONE;
68       }
69     } break;
70     case SETUP:
71       NOTREACHED() << "State SETUP invalid for synthetic pinch.";
72     case DONE:
73       NOTREACHED() << "State DONE invalid for synthetic pinch.";
74   }
75 }
76 
PressTouchPoints(SyntheticGestureTarget * target,const base::TimeTicks & timestamp)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);
82 }
83 
MoveTouchPoints(SyntheticGestureTarget * target,float delta,const base::TimeTicks & timestamp)84 void SyntheticPinchGesture::MoveTouchPoints(SyntheticGestureTarget* target,
85                                             float delta,
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;
90 
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);
94 }
95 
ReleaseTouchPoints(SyntheticGestureTarget * target,const base::TimeTicks & 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);
101 }
102 
ForwardTouchEvent(SyntheticGestureTarget * target,const base::TimeTicks & timestamp)103 void SyntheticPinchGesture::ForwardTouchEvent(
104     SyntheticGestureTarget* target, const base::TimeTicks& timestamp) {
105   touch_event_.timeStampSeconds = ConvertTimestampToSeconds(timestamp);
106   target->DispatchInputEventToPlatform(touch_event_);
107 }
108 
SetupCoordinatesAndStopTime(SyntheticGestureTarget * target)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();
126   }
127 
128   start_y_0_ = params_.anchor.y() - initial_distance_to_anchor;
129   start_y_1_ = params_.anchor.y() + initial_distance_to_anchor;
130 
131   max_pointer_delta_0_ = initial_distance_to_anchor - final_distance_to_anchor;
132 
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);
137   stop_time_ =
138       start_time_ + base::TimeDelta::FromMicroseconds(total_duration_in_us);
139 }
140 
GetDeltaForPointer0AtTime(const base::TimeTicks & timestamp) const141 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_;
147 
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;
153 }
154 
ClampTimestamp(const base::TimeTicks & timestamp) const155 base::TimeTicks SyntheticPinchGesture::ClampTimestamp(
156     const base::TimeTicks& timestamp) const {
157   return std::min(timestamp, stop_time_);
158 }
159 
HasReachedTarget(const base::TimeTicks & timestamp) const160 bool SyntheticPinchGesture::HasReachedTarget(const base::TimeTicks& timestamp)
161     const {
162   return timestamp >= stop_time_;
163 }
164 
165 }  // namespace content
166