Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(59)

Side by Side Diff: content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.cc

Issue 119323007: Add timestamps to synthesized events. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove target variables in pinch; fix computation of total duration. Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h" 5 #include "content/browser/renderer_host/input/synthetic_smooth_scroll_gesture.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "content/common/input/input_event.h" 8 #include "content/common/input/input_event.h"
9 #include "ui/events/latency_info.h" 9 #include "ui/events/latency_info.h"
10 #include "ui/gfx/point_f.h" 10 #include "ui/gfx/point_f.h"
(...skipping 17 matching lines...) Expand all
28 28
29 SyntheticSmoothScrollGesture::SyntheticSmoothScrollGesture( 29 SyntheticSmoothScrollGesture::SyntheticSmoothScrollGesture(
30 const SyntheticSmoothScrollGestureParams& params) 30 const SyntheticSmoothScrollGestureParams& params)
31 : params_(params), 31 : params_(params),
32 gesture_source_type_(SyntheticGestureParams::DEFAULT_INPUT), 32 gesture_source_type_(SyntheticGestureParams::DEFAULT_INPUT),
33 state_(SETUP) {} 33 state_(SETUP) {}
34 34
35 SyntheticSmoothScrollGesture::~SyntheticSmoothScrollGesture() {} 35 SyntheticSmoothScrollGesture::~SyntheticSmoothScrollGesture() {}
36 36
37 SyntheticGesture::Result SyntheticSmoothScrollGesture::ForwardInputEvents( 37 SyntheticGesture::Result SyntheticSmoothScrollGesture::ForwardInputEvents(
38 const base::TimeDelta& interval, SyntheticGestureTarget* target) { 38 const base::TimeTicks& timestamp, SyntheticGestureTarget* target) {
39 if (state_ == SETUP) { 39 if (state_ == SETUP) {
40 gesture_source_type_ = params_.gesture_source_type; 40 gesture_source_type_ = params_.gesture_source_type;
41 if (gesture_source_type_ == SyntheticGestureParams::DEFAULT_INPUT) 41 if (gesture_source_type_ == SyntheticGestureParams::DEFAULT_INPUT)
42 gesture_source_type_ = target->GetDefaultSyntheticGestureSourceType(); 42 gesture_source_type_ = target->GetDefaultSyntheticGestureSourceType();
43 43
44 if (!target->SupportsSyntheticGestureSourceType(gesture_source_type_)) 44 if (!target->SupportsSyntheticGestureSourceType(gesture_source_type_))
45 return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_SUPPORTED_BY_PLATFORM; 45 return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_SUPPORTED_BY_PLATFORM;
46 46
47 state_ = STARTED; 47 state_ = STARTED;
48 start_time_ = timestamp;
48 } 49 }
49 50
50 DCHECK_NE(gesture_source_type_, SyntheticGestureParams::DEFAULT_INPUT); 51 DCHECK_NE(gesture_source_type_, SyntheticGestureParams::DEFAULT_INPUT);
51 if (gesture_source_type_ == SyntheticGestureParams::TOUCH_INPUT) 52 if (gesture_source_type_ == SyntheticGestureParams::TOUCH_INPUT)
52 ForwardTouchInputEvents(interval, target); 53 ForwardTouchInputEvents(timestamp, target);
53 else if (gesture_source_type_ == SyntheticGestureParams::MOUSE_INPUT) 54 else if (gesture_source_type_ == SyntheticGestureParams::MOUSE_INPUT)
54 ForwardMouseInputEvents(interval, target); 55 ForwardMouseInputEvents(timestamp, target);
55 else 56 else
56 return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED; 57 return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED;
57 58
58 return (state_ == DONE) ? SyntheticGesture::GESTURE_FINISHED 59 return (state_ == DONE) ? SyntheticGesture::GESTURE_FINISHED
59 : SyntheticGesture::GESTURE_RUNNING; 60 : SyntheticGesture::GESTURE_RUNNING;
60 } 61 }
61 62
62 void SyntheticSmoothScrollGesture::ForwardTouchInputEvents( 63 void SyntheticSmoothScrollGesture::ForwardTouchInputEvents(
63 const base::TimeDelta& interval, SyntheticGestureTarget* target) { 64 const base::TimeTicks& timestamp, SyntheticGestureTarget* target) {
65 base::TimeTicks event_timestamp = timestamp;
64 switch (state_) { 66 switch (state_) {
65 case STARTED: 67 case STARTED:
66 // Check for an early finish. 68 // Check for an early finish.
67 if (params_.distance.IsZero()) { 69 if (params_.distance.IsZero()) {
68 state_ = DONE; 70 state_ = DONE;
69 break; 71 break;
70 } 72 }
71 AddTouchSlopToDistance(target); 73 AddTouchSlopToDistance(target);
72 PressTouchPoint(target); 74 ComputeAndSetStopScrollingTime();
75 PressTouchPoint(target, event_timestamp);
73 state_ = MOVING; 76 state_ = MOVING;
74 break; 77 break;
75 case MOVING: 78 case MOVING: {
76 total_delta_ += GetPositionDelta(interval); 79 event_timestamp = ClampTimestamp(timestamp);
77 MoveTouchPoint(target); 80 gfx::Vector2dF delta = GetPositionDeltaAtTime(event_timestamp);
81 MoveTouchPoint(target, delta, event_timestamp);
78 82
79 if (HasScrolledEntireDistance()) { 83 if (HasScrolledEntireDistance(event_timestamp)) {
80 if (params_.prevent_fling) { 84 if (params_.prevent_fling) {
81 state_ = STOPPING; 85 state_ = STOPPING;
82 } else { 86 } else {
83 ReleaseTouchPoint(target); 87 ReleaseTouchPoint(target, event_timestamp);
84 state_ = DONE; 88 state_ = DONE;
85 } 89 }
86 } 90 }
87 break; 91 } break;
88 case STOPPING: 92 case STOPPING:
89 total_stopping_wait_time_ += interval; 93 if (timestamp - stop_scrolling_time_ >=
90 if (total_stopping_wait_time_ >= target->PointerAssumedStoppedTime()) { 94 target->PointerAssumedStoppedTime()) {
95 event_timestamp =
96 stop_scrolling_time_ + target->PointerAssumedStoppedTime();
91 // Send one last move event, but don't change the location. Without this 97 // Send one last move event, but don't change the location. Without this
92 // we'd still sometimes cause a fling on Android. 98 // we'd still sometimes cause a fling on Android.
93 MoveTouchPoint(target); 99 ForwardTouchEvent(target, event_timestamp);
94 ReleaseTouchPoint(target); 100 ReleaseTouchPoint(target, event_timestamp);
95 state_ = DONE; 101 state_ = DONE;
96 } 102 }
97 break; 103 break;
98 case SETUP: 104 case SETUP:
99 NOTREACHED() 105 NOTREACHED()
100 << "State STARTED invalid for synthetic scroll using touch input."; 106 << "State STARTED invalid for synthetic scroll using touch input.";
101 case DONE: 107 case DONE:
102 NOTREACHED() 108 NOTREACHED()
103 << "State DONE invalid for synthetic scroll using touch input."; 109 << "State DONE invalid for synthetic scroll using touch input.";
104 } 110 }
105 } 111 }
106 112
107 void SyntheticSmoothScrollGesture::ForwardMouseInputEvents( 113 void SyntheticSmoothScrollGesture::ForwardMouseInputEvents(
108 const base::TimeDelta& interval, SyntheticGestureTarget* target) { 114 const base::TimeTicks& timestamp, SyntheticGestureTarget* target) {
109 switch (state_) { 115 switch (state_) {
110 case STARTED: 116 case STARTED:
111 // Check for an early finish. 117 // Check for an early finish.
112 if (params_.distance.IsZero()) { 118 if (params_.distance.IsZero()) {
113 state_ = DONE; 119 state_ = DONE;
114 break; 120 break;
115 } 121 }
122 ComputeAndSetStopScrollingTime();
116 state_ = MOVING; 123 state_ = MOVING;
117 // Fall through to forward the first event. 124 // Fall through to forward the first event.
118 case MOVING: 125 case MOVING: {
119 { 126 // Even though WebMouseWheelEvents take floating point deltas,
120 // Even though WebMouseWheelEvents take floating point deltas, 127 // internally the scroll position is stored as an integer. We therefore
121 // internally the scroll position is stored as an integer. We therefore 128 // keep track of the discrete delta which is consistent with the
122 // keep track of the discrete delta which is consistent with the 129 // internal scrolling state. This ensures that when the gesture has
123 // internal scrolling state. This ensures that when the gesture has 130 // finished we've scrolled exactly the specified distance.
124 // finished we've scrolled exactly the specified distance. 131 base::TimeTicks event_timestamp = ClampTimestamp(timestamp);
125 total_delta_ += GetPositionDelta(interval); 132 gfx::Vector2dF total_delta = GetPositionDeltaAtTime(event_timestamp);
126 gfx::Vector2d delta_discrete = 133 gfx::Vector2d delta_discrete =
127 FloorTowardZero(total_delta_ - total_delta_discrete_); 134 FloorTowardZero(total_delta - total_delta_discrete_);
128 ForwardMouseWheelEvent(target, delta_discrete); 135 ForwardMouseWheelEvent(target, delta_discrete, event_timestamp);
129 total_delta_discrete_ += delta_discrete; 136 total_delta_discrete_ += delta_discrete;
130 } 137
131 if (HasScrolledEntireDistance()) 138 if (HasScrolledEntireDistance(event_timestamp))
132 state_ = DONE; 139 state_ = DONE;
133 break; 140 } break;
134 case SETUP: 141 case SETUP:
135 NOTREACHED() 142 NOTREACHED()
136 << "State STARTED invalid for synthetic scroll using touch input."; 143 << "State STARTED invalid for synthetic scroll using touch input.";
137 case STOPPING: 144 case STOPPING:
138 NOTREACHED() 145 NOTREACHED()
139 << "State STOPPING invalid for synthetic scroll using touch input."; 146 << "State STOPPING invalid for synthetic scroll using touch input.";
140 case DONE: 147 case DONE:
141 NOTREACHED() 148 NOTREACHED()
142 << "State DONE invalid for synthetic scroll using touch input."; 149 << "State DONE invalid for synthetic scroll using touch input.";
143 } 150 }
144 } 151 }
145 152
146 void SyntheticSmoothScrollGesture::ForwardTouchEvent( 153 void SyntheticSmoothScrollGesture::ForwardTouchEvent(
147 SyntheticGestureTarget* target) const { 154 SyntheticGestureTarget* target, const base::TimeTicks& timestamp) {
155 touch_event_.timeStampSeconds = ConvertTimestampToSeconds(timestamp);
156
148 target->DispatchInputEventToPlatform( 157 target->DispatchInputEventToPlatform(
149 InputEvent(touch_event_, ui::LatencyInfo(), false)); 158 InputEvent(touch_event_, ui::LatencyInfo(), false));
150 } 159 }
151 160
152 void SyntheticSmoothScrollGesture::ForwardMouseWheelEvent( 161 void SyntheticSmoothScrollGesture::ForwardMouseWheelEvent(
153 SyntheticGestureTarget* target, const gfx::Vector2dF& delta) const { 162 SyntheticGestureTarget* target,
163 const gfx::Vector2dF& delta,
164 const base::TimeTicks& timestamp) const {
154 blink::WebMouseWheelEvent mouse_wheel_event = 165 blink::WebMouseWheelEvent mouse_wheel_event =
155 SyntheticWebMouseWheelEventBuilder::Build(delta.x(), delta.y(), 0, false); 166 SyntheticWebMouseWheelEventBuilder::Build(delta.x(), delta.y(), 0, false);
156 167
157 mouse_wheel_event.x = params_.anchor.x(); 168 mouse_wheel_event.x = params_.anchor.x();
158 mouse_wheel_event.y = params_.anchor.y(); 169 mouse_wheel_event.y = params_.anchor.y();
159 170
171 mouse_wheel_event.timeStampSeconds = ConvertTimestampToSeconds(timestamp);
172
160 target->DispatchInputEventToPlatform( 173 target->DispatchInputEventToPlatform(
161 InputEvent(mouse_wheel_event, ui::LatencyInfo(), false)); 174 InputEvent(mouse_wheel_event, ui::LatencyInfo(), false));
162 } 175 }
163 176
164 void SyntheticSmoothScrollGesture::PressTouchPoint( 177 void SyntheticSmoothScrollGesture::PressTouchPoint(
165 SyntheticGestureTarget* target) { 178 SyntheticGestureTarget* target, const base::TimeTicks& timestamp) {
166 touch_event_.PressPoint(params_.anchor.x(), params_.anchor.y()); 179 touch_event_.PressPoint(params_.anchor.x(), params_.anchor.y());
167 ForwardTouchEvent(target); 180 ForwardTouchEvent(target, timestamp);
168 } 181 }
169 182
170 void SyntheticSmoothScrollGesture::MoveTouchPoint( 183 void SyntheticSmoothScrollGesture::MoveTouchPoint(
171 SyntheticGestureTarget* target) { 184 SyntheticGestureTarget* target,
172 gfx::PointF touch_position = params_.anchor + total_delta_; 185 const gfx::Vector2dF& delta,
186 const base::TimeTicks& timestamp) {
187 gfx::PointF touch_position = params_.anchor + delta;
173 touch_event_.MovePoint(0, touch_position.x(), touch_position.y()); 188 touch_event_.MovePoint(0, touch_position.x(), touch_position.y());
174 ForwardTouchEvent(target); 189 ForwardTouchEvent(target, timestamp);
175 } 190 }
176 191
177 void SyntheticSmoothScrollGesture::ReleaseTouchPoint( 192 void SyntheticSmoothScrollGesture::ReleaseTouchPoint(
178 SyntheticGestureTarget* target) { 193 SyntheticGestureTarget* target, const base::TimeTicks& timestamp) {
179 touch_event_.ReleasePoint(0); 194 touch_event_.ReleasePoint(0);
180 ForwardTouchEvent(target); 195 ForwardTouchEvent(target, timestamp);
181 } 196 }
182 197
183 void SyntheticSmoothScrollGesture::AddTouchSlopToDistance( 198 void SyntheticSmoothScrollGesture::AddTouchSlopToDistance(
184 SyntheticGestureTarget* target) { 199 SyntheticGestureTarget* target) {
185 // Android uses euclidean distance to compute if a touch pointer has moved 200 // Android uses euclidean distance to compute if a touch pointer has moved
186 // beyond the slop, while Aura uses Manhattan distance. We're using Euclidean 201 // beyond the slop, while Aura uses Manhattan distance. We're using Euclidean
187 // distance and round up to the nearest integer. 202 // distance and round up to the nearest integer.
188 // For vertical and horizontal scrolls (the common case), both methods produce 203 // For vertical and horizontal scrolls (the common case), both methods produce
189 // the same result. 204 // the same result.
190 gfx::Vector2dF touch_slop_delta = ProjectLengthOntoScrollDirection( 205 gfx::Vector2dF touch_slop_delta =
191 target->GetTouchSlopInDips()); 206 ProjectLengthOntoScrollDirection(target->GetTouchSlopInDips());
192 params_.distance += CeilFromZero(touch_slop_delta); 207 params_.distance += CeilFromZero(touch_slop_delta);
193 } 208 }
194 209
195 gfx::Vector2dF SyntheticSmoothScrollGesture::GetPositionDelta( 210 gfx::Vector2dF SyntheticSmoothScrollGesture::GetPositionDeltaAtTime(
196 const base::TimeDelta& interval) const { 211 const base::TimeTicks& timestamp) const {
197 float delta_length = params_.speed_in_pixels_s * interval.InSecondsF(); 212 // Make sure the final delta is correct. Using the computation below can lead
213 // to issues with floating point precision.
214 if (HasScrolledEntireDistance(timestamp))
215 return -params_.distance;
198 216
199 // Make sure we're not scrolling too far. 217 float delta_length =
200 gfx::Vector2dF remaining_delta = ComputeRemainingDelta(); 218 params_.speed_in_pixels_s * (timestamp - start_time_).InSecondsF();
201 if (delta_length > remaining_delta.Length()) 219 return -ProjectLengthOntoScrollDirection(delta_length);
202 // In order to scroll in a certain direction we need to move the
203 // touch pointer/mouse wheel in the opposite direction.
204 return -remaining_delta;
205 else
206 return -ProjectLengthOntoScrollDirection(delta_length);
207 } 220 }
208 221
209 gfx::Vector2dF SyntheticSmoothScrollGesture::ProjectLengthOntoScrollDirection( 222 gfx::Vector2dF SyntheticSmoothScrollGesture::ProjectLengthOntoScrollDirection(
210 float delta_length) const { 223 float delta_length) const {
211 const float kTotalLength = params_.distance.Length(); 224 const float kTotalLength = params_.distance.Length();
212 return ScaleVector2d(params_.distance, delta_length / kTotalLength); 225 return ScaleVector2d(params_.distance, delta_length / kTotalLength);
213 } 226 }
214 227
215 gfx::Vector2dF SyntheticSmoothScrollGesture::ComputeRemainingDelta() const { 228 void SyntheticSmoothScrollGesture::ComputeAndSetStopScrollingTime() {
216 return params_.distance + total_delta_; 229 int64 total_duration_in_us = static_cast<int64>(
230 1e6 * (params_.distance.Length() / params_.speed_in_pixels_s));
231 DCHECK_GT(total_duration_in_us, 0);
232 stop_scrolling_time_ =
233 start_time_ + base::TimeDelta::FromMicroseconds(total_duration_in_us);
217 } 234 }
218 235
219 bool SyntheticSmoothScrollGesture::HasScrolledEntireDistance() const { 236 base::TimeTicks SyntheticSmoothScrollGesture::ClampTimestamp(
220 return ComputeRemainingDelta().IsZero(); 237 const base::TimeTicks& timestamp) const {
238 return std::min(timestamp, stop_scrolling_time_);
239 }
240
241 bool SyntheticSmoothScrollGesture::HasScrolledEntireDistance(
242 const base::TimeTicks& timestamp) const {
243 return timestamp >= stop_scrolling_time_;
221 } 244 }
222 245
223 } // namespace content 246 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698