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

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: Use timestamp to compute delta. 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 =
81 GetPositionDeltaAtTime(event_timestamp);
82 MoveTouchPoint(target, delta, event_timestamp);
78 83
79 if (HasScrolledEntireDistance()) { 84 if (HasScrolledEntireDistance(event_timestamp)) {
80 if (params_.prevent_fling) { 85 if (params_.prevent_fling) {
81 state_ = STOPPING; 86 state_ = STOPPING;
82 } else { 87 } else {
83 ReleaseTouchPoint(target); 88 ReleaseTouchPoint(target, event_timestamp);
84 state_ = DONE; 89 state_ = DONE;
85 } 90 }
86 } 91 }
87 break; 92 } break;
88 case STOPPING: 93 case STOPPING:
89 total_stopping_wait_time_ += interval; 94 if (timestamp - stop_scrolling_time_ >=
90 if (total_stopping_wait_time_ >= target->PointerAssumedStoppedTime()) { 95 target->PointerAssumedStoppedTime()) {
96 event_timestamp =
97 stop_scrolling_time_ + target->PointerAssumedStoppedTime();
91 // Send one last move event, but don't change the location. Without this 98 // Send one last move event, but don't change the location. Without this
92 // we'd still sometimes cause a fling on Android. 99 // we'd still sometimes cause a fling on Android.
93 MoveTouchPoint(target); 100 ForwardTouchEvent(target, event_timestamp);
94 ReleaseTouchPoint(target); 101 ReleaseTouchPoint(target, event_timestamp);
95 state_ = DONE; 102 state_ = DONE;
96 } 103 }
97 break; 104 break;
98 case SETUP: 105 case SETUP:
99 NOTREACHED() 106 NOTREACHED()
100 << "State STARTED invalid for synthetic scroll using touch input."; 107 << "State STARTED invalid for synthetic scroll using touch input.";
101 case DONE: 108 case DONE:
102 NOTREACHED() 109 NOTREACHED()
103 << "State DONE invalid for synthetic scroll using touch input."; 110 << "State DONE invalid for synthetic scroll using touch input.";
104 } 111 }
105 } 112 }
106 113
107 void SyntheticSmoothScrollGesture::ForwardMouseInputEvents( 114 void SyntheticSmoothScrollGesture::ForwardMouseInputEvents(
108 const base::TimeDelta& interval, SyntheticGestureTarget* target) { 115 const base::TimeTicks& timestamp, SyntheticGestureTarget* target) {
109 switch (state_) { 116 switch (state_) {
110 case STARTED: 117 case STARTED:
111 // Check for an early finish. 118 // Check for an early finish.
112 if (params_.distance.IsZero()) { 119 if (params_.distance.IsZero()) {
113 state_ = DONE; 120 state_ = DONE;
114 break; 121 break;
115 } 122 }
123 ComputeAndSetStopScrollingTime();
116 state_ = MOVING; 124 state_ = MOVING;
117 // Fall through to forward the first event. 125 // Fall through to forward the first event.
118 case MOVING: 126 case MOVING: {
119 { 127 // Even though WebMouseWheelEvents take floating point deltas,
120 // Even though WebMouseWheelEvents take floating point deltas, 128 // internally the scroll position is stored as an integer. We therefore
121 // internally the scroll position is stored as an integer. We therefore 129 // keep track of the discrete delta which is consistent with the
122 // keep track of the discrete delta which is consistent with the 130 // internal scrolling state. This ensures that when the gesture has
123 // internal scrolling state. This ensures that when the gesture has 131 // finished we've scrolled exactly the specified distance.
124 // finished we've scrolled exactly the specified distance. 132 base::TimeTicks event_timestamp = ClampTimestamp(timestamp);
125 total_delta_ += GetPositionDelta(interval); 133 gfx::Vector2dF total_delta =
126 gfx::Vector2d delta_discrete = 134 GetPositionDeltaAtTime(event_timestamp);
127 FloorTowardZero(total_delta_ - total_delta_discrete_); 135 gfx::Vector2d delta_discrete =
128 ForwardMouseWheelEvent(target, delta_discrete); 136 FloorTowardZero(total_delta - total_delta_discrete_);
129 total_delta_discrete_ += delta_discrete; 137 ForwardMouseWheelEvent(target, delta_discrete, event_timestamp);
130 } 138 total_delta_discrete_ += delta_discrete;
131 if (HasScrolledEntireDistance()) 139
140 if (HasScrolledEntireDistance(event_timestamp))
132 state_ = DONE; 141 state_ = DONE;
133 break; 142 } break;
134 case SETUP: 143 case SETUP:
135 NOTREACHED() 144 NOTREACHED()
136 << "State STARTED invalid for synthetic scroll using touch input."; 145 << "State STARTED invalid for synthetic scroll using touch input.";
137 case STOPPING: 146 case STOPPING:
138 NOTREACHED() 147 NOTREACHED()
139 << "State STOPPING invalid for synthetic scroll using touch input."; 148 << "State STOPPING invalid for synthetic scroll using touch input.";
140 case DONE: 149 case DONE:
141 NOTREACHED() 150 NOTREACHED()
142 << "State DONE invalid for synthetic scroll using touch input."; 151 << "State DONE invalid for synthetic scroll using touch input.";
143 } 152 }
144 } 153 }
145 154
146 void SyntheticSmoothScrollGesture::ForwardTouchEvent( 155 void SyntheticSmoothScrollGesture::ForwardTouchEvent(
147 SyntheticGestureTarget* target) const { 156 SyntheticGestureTarget* target, const base::TimeTicks& timestamp) {
157 touch_event_.timeStampSeconds = ConvertTimestampToSeconds(timestamp);
158
148 target->DispatchInputEventToPlatform( 159 target->DispatchInputEventToPlatform(
149 InputEvent(touch_event_, ui::LatencyInfo(), false)); 160 InputEvent(touch_event_, ui::LatencyInfo(), false));
150 } 161 }
151 162
152 void SyntheticSmoothScrollGesture::ForwardMouseWheelEvent( 163 void SyntheticSmoothScrollGesture::ForwardMouseWheelEvent(
153 SyntheticGestureTarget* target, const gfx::Vector2dF& delta) const { 164 SyntheticGestureTarget* target,
165 const gfx::Vector2dF& delta,
166 const base::TimeTicks& timestamp) const {
154 blink::WebMouseWheelEvent mouse_wheel_event = 167 blink::WebMouseWheelEvent mouse_wheel_event =
155 SyntheticWebMouseWheelEventBuilder::Build(delta.x(), delta.y(), 0, false); 168 SyntheticWebMouseWheelEventBuilder::Build(delta.x(), delta.y(), 0, false);
156 169
157 mouse_wheel_event.x = params_.anchor.x(); 170 mouse_wheel_event.x = params_.anchor.x();
158 mouse_wheel_event.y = params_.anchor.y(); 171 mouse_wheel_event.y = params_.anchor.y();
159 172
173 mouse_wheel_event.timeStampSeconds = ConvertTimestampToSeconds(timestamp);
174
160 target->DispatchInputEventToPlatform( 175 target->DispatchInputEventToPlatform(
161 InputEvent(mouse_wheel_event, ui::LatencyInfo(), false)); 176 InputEvent(mouse_wheel_event, ui::LatencyInfo(), false));
162 } 177 }
163 178
164 void SyntheticSmoothScrollGesture::PressTouchPoint( 179 void SyntheticSmoothScrollGesture::PressTouchPoint(
165 SyntheticGestureTarget* target) { 180 SyntheticGestureTarget* target, const base::TimeTicks& timestamp) {
166 touch_event_.PressPoint(params_.anchor.x(), params_.anchor.y()); 181 touch_event_.PressPoint(params_.anchor.x(), params_.anchor.y());
167 ForwardTouchEvent(target); 182 ForwardTouchEvent(target, timestamp);
168 } 183 }
169 184
170 void SyntheticSmoothScrollGesture::MoveTouchPoint( 185 void SyntheticSmoothScrollGesture::MoveTouchPoint(
171 SyntheticGestureTarget* target) { 186 SyntheticGestureTarget* target,
172 gfx::PointF touch_position = params_.anchor + total_delta_; 187 const gfx::Vector2dF& delta,
188 const base::TimeTicks& timestamp) {
189 gfx::PointF touch_position = params_.anchor + delta;
173 touch_event_.MovePoint(0, touch_position.x(), touch_position.y()); 190 touch_event_.MovePoint(0, touch_position.x(), touch_position.y());
174 ForwardTouchEvent(target); 191 ForwardTouchEvent(target, timestamp);
175 } 192 }
176 193
177 void SyntheticSmoothScrollGesture::ReleaseTouchPoint( 194 void SyntheticSmoothScrollGesture::ReleaseTouchPoint(
178 SyntheticGestureTarget* target) { 195 SyntheticGestureTarget* target, const base::TimeTicks& timestamp) {
179 touch_event_.ReleasePoint(0); 196 touch_event_.ReleasePoint(0);
180 ForwardTouchEvent(target); 197 ForwardTouchEvent(target, timestamp);
181 } 198 }
182 199
183 void SyntheticSmoothScrollGesture::AddTouchSlopToDistance( 200 void SyntheticSmoothScrollGesture::AddTouchSlopToDistance(
184 SyntheticGestureTarget* target) { 201 SyntheticGestureTarget* target) {
185 // Android uses euclidean distance to compute if a touch pointer has moved 202 // 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 203 // beyond the slop, while Aura uses Manhattan distance. We're using Euclidean
187 // distance and round up to the nearest integer. 204 // distance and round up to the nearest integer.
188 // For vertical and horizontal scrolls (the common case), both methods produce 205 // For vertical and horizontal scrolls (the common case), both methods produce
189 // the same result. 206 // the same result.
190 gfx::Vector2dF touch_slop_delta = ProjectLengthOntoScrollDirection( 207 gfx::Vector2dF touch_slop_delta =
191 target->GetTouchSlopInDips()); 208 ProjectLengthOntoScrollDirection(target->GetTouchSlopInDips());
192 params_.distance += CeilFromZero(touch_slop_delta); 209 params_.distance += CeilFromZero(touch_slop_delta);
193 } 210 }
194 211
195 gfx::Vector2dF SyntheticSmoothScrollGesture::GetPositionDelta( 212 gfx::Vector2dF SyntheticSmoothScrollGesture::GetPositionDeltaAtTime(
196 const base::TimeDelta& interval) const { 213 const base::TimeTicks& timestamp) const {
197 float delta_length = params_.speed_in_pixels_s * interval.InSecondsF(); 214 if (timestamp == stop_scrolling_time_)
jdduke (slow) 2014/01/06 18:56:28 Nit: Maybe put a note here about precision issues?
Dominik Grewe 2014/01/06 19:16:43 Done.
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 1e6f * (params_.distance.Length() / params_.speed_in_pixels_s));
231 stop_scrolling_time_ =
232 start_time_ + base::TimeDelta::FromMicroseconds(total_duration_in_us);
217 } 233 }
218 234
219 bool SyntheticSmoothScrollGesture::HasScrolledEntireDistance() const { 235 base::TimeTicks SyntheticSmoothScrollGesture::ClampTimestamp(
220 return ComputeRemainingDelta().IsZero(); 236 const base::TimeTicks& timestamp) const {
237 return timestamp > stop_scrolling_time_ ? stop_scrolling_time_ : timestamp;
jdduke (slow) 2014/01/06 18:56:28 Nit: std::min(timestamp, stop_scrolling_time_);
Dominik Grewe 2014/01/06 19:16:43 Done.
238 }
239
240 bool SyntheticSmoothScrollGesture::HasScrolledEntireDistance(
241 const base::TimeTicks& timestamp) const {
242 return timestamp == stop_scrolling_time_;
221 } 243 }
222 244
223 } // namespace content 245 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698