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

Side by Side Diff: ui/events/gesture_detection/motion_event_buffer.cc

Issue 1287103004: Sync ui/events to chromium @ https://codereview.chromium.org/1210203002 (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: rebased Created 5 years, 4 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
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "ui/events/gesture_detection/motion_event_buffer.h" 5 #include "ui/events/gesture_detection/motion_event_buffer.h"
6 6
7 #include "base/trace_event/trace_event.h" 7 #include "base/trace_event/trace_event.h"
8 #include "ui/events/gesture_detection/motion_event.h"
9 #include "ui/events/gesture_detection/motion_event_generic.h" 8 #include "ui/events/gesture_detection/motion_event_generic.h"
10 9
11 namespace ui { 10 namespace ui {
12 namespace { 11 namespace {
13 12
14 // Latency added during resampling. A few milliseconds doesn't hurt much but 13 // Latency added during resampling. A few milliseconds doesn't hurt much but
15 // reduces the impact of mispredicted touch positions. 14 // reduces the impact of mispredicted touch positions.
16 const int kResampleLatencyMs = 5; 15 const int kResampleLatencyMs = 5;
17 16
18 // Minimum time difference between consecutive samples before attempting to 17 // Minimum time difference between consecutive samples before attempting to
19 // resample. 18 // resample.
20 const int kResampleMinDeltaMs = 2; 19 const int kResampleMinDeltaMs = 2;
21 20
22 // Maximum time to predict forward from the last known state, to avoid 21 // Maximum time to predict forward from the last known state, to avoid
23 // predicting too far into the future. This time is further bounded by 50% of 22 // predicting too far into the future. This time is further bounded by 50% of
24 // the last time delta. 23 // the last time delta.
25 const int kResampleMaxPredictionMs = 8; 24 const int kResampleMaxPredictionMs = 8;
26 25
27 typedef ScopedVector<MotionEvent> MotionEventVector; 26 typedef ScopedVector<MotionEventGeneric> MotionEventVector;
28 27
29 float Lerp(float a, float b, float alpha) { 28 float Lerp(float a, float b, float alpha) {
30 return a + alpha * (b - a); 29 return a + alpha * (b - a);
31 } 30 }
32 31
33 bool CanAddSample(const MotionEvent& event0, const MotionEvent& event1) { 32 bool CanAddSample(const MotionEvent& event0, const MotionEvent& event1) {
34 DCHECK_EQ(event0.GetAction(), MotionEvent::ACTION_MOVE); 33 DCHECK_EQ(event0.GetAction(), MotionEvent::ACTION_MOVE);
35 if (event1.GetAction() != MotionEvent::ACTION_MOVE) 34 if (event1.GetAction() != MotionEvent::ACTION_MOVE)
36 return false; 35 return false;
37 36
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 MotionEventVector unconsumed_batch; 78 MotionEventVector unconsumed_batch;
80 unconsumed_batch.insert( 79 unconsumed_batch.insert(
81 unconsumed_batch.begin(), batch->begin() + count, batch->end()); 80 unconsumed_batch.begin(), batch->begin() + count, batch->end());
82 batch->weak_erase(batch->begin() + count, batch->end()); 81 batch->weak_erase(batch->begin() + count, batch->end());
83 82
84 unconsumed_batch.swap(*batch); 83 unconsumed_batch.swap(*batch);
85 DCHECK_GE(unconsumed_batch.size(), 1U); 84 DCHECK_GE(unconsumed_batch.size(), 1U);
86 return unconsumed_batch.Pass(); 85 return unconsumed_batch.Pass();
87 } 86 }
88 87
89 PointerProperties PointerFromMotionEvent(const MotionEvent& event, 88 // Linearly interpolate the pointer position between two MotionEvent samples.
90 size_t pointer_index) { 89 // Only pointers of finger or unknown type will be resampled.
91 PointerProperties result;
92 result.id = event.GetPointerId(pointer_index);
93 result.tool_type = event.GetToolType(pointer_index);
94 result.x = event.GetX(pointer_index);
95 result.y = event.GetY(pointer_index);
96 result.raw_x = event.GetRawX(pointer_index);
97 result.raw_y = event.GetRawY(pointer_index);
98 result.pressure = event.GetPressure(pointer_index);
99 result.touch_major = event.GetTouchMajor(pointer_index);
100 result.touch_minor = event.GetTouchMinor(pointer_index);
101 result.orientation = event.GetOrientation(pointer_index);
102 return result;
103 }
104
105 PointerProperties ResamplePointer(const MotionEvent& event0, 90 PointerProperties ResamplePointer(const MotionEvent& event0,
106 const MotionEvent& event1, 91 const MotionEvent& event1,
107 size_t event0_pointer_index, 92 size_t event0_pointer_index,
108 size_t event1_pointer_index, 93 size_t event1_pointer_index,
109 float alpha) { 94 float alpha) {
110 DCHECK_EQ(event0.GetPointerId(event0_pointer_index), 95 DCHECK_EQ(event0.GetPointerId(event0_pointer_index),
111 event1.GetPointerId(event1_pointer_index)); 96 event1.GetPointerId(event1_pointer_index));
112 // If the tool should not be resampled, use the latest event in the valid 97 // If the tool should not be resampled, use the latest event in the valid
113 // horizon (i.e., the event no later than the time interpolated by alpha). 98 // horizon (i.e., the event no later than the time interpolated by alpha).
114 if (!ShouldResampleTool(event0.GetToolType(event0_pointer_index))) { 99 if (!ShouldResampleTool(event0.GetToolType(event0_pointer_index))) {
115 if (alpha > 1) 100 if (alpha > 1)
116 return PointerFromMotionEvent(event1, event1_pointer_index); 101 return PointerProperties(event1, event1_pointer_index);
117 else 102 else
118 return PointerFromMotionEvent(event0, event0_pointer_index); 103 return PointerProperties(event0, event0_pointer_index);
119 } 104 }
120 105
121 PointerProperties p(PointerFromMotionEvent(event0, event0_pointer_index)); 106 PointerProperties p(event0, event0_pointer_index);
122 p.x = Lerp(p.x, event1.GetX(event1_pointer_index), alpha); 107 p.x = Lerp(p.x, event1.GetX(event1_pointer_index), alpha);
123 p.y = Lerp(p.y, event1.GetY(event1_pointer_index), alpha); 108 p.y = Lerp(p.y, event1.GetY(event1_pointer_index), alpha);
124 p.raw_x = Lerp(p.raw_x, event1.GetRawX(event1_pointer_index), alpha); 109 p.raw_x = Lerp(p.raw_x, event1.GetRawX(event1_pointer_index), alpha);
125 p.raw_y = Lerp(p.raw_y, event1.GetRawY(event1_pointer_index), alpha); 110 p.raw_y = Lerp(p.raw_y, event1.GetRawY(event1_pointer_index), alpha);
126 return p; 111 return p;
127 } 112 }
128 113
129 scoped_ptr<MotionEvent> ResampleMotionEvent(const MotionEvent& event0, 114 // Linearly interpolate the pointers between two event samples using the
130 const MotionEvent& event1, 115 // provided |resample_time|.
131 base::TimeTicks resample_time) { 116 scoped_ptr<MotionEventGeneric> ResampleMotionEvent(
117 const MotionEvent& event0,
118 const MotionEvent& event1,
119 base::TimeTicks resample_time) {
132 DCHECK_EQ(MotionEvent::ACTION_MOVE, event0.GetAction()); 120 DCHECK_EQ(MotionEvent::ACTION_MOVE, event0.GetAction());
133 DCHECK_EQ(event0.GetPointerCount(), event1.GetPointerCount()); 121 DCHECK_EQ(event0.GetPointerCount(), event1.GetPointerCount());
134 122
135 const base::TimeTicks time0 = event0.GetEventTime(); 123 const base::TimeTicks time0 = event0.GetEventTime();
136 const base::TimeTicks time1 = event1.GetEventTime(); 124 const base::TimeTicks time1 = event1.GetEventTime();
137 DCHECK(time0 < time1); 125 DCHECK(time0 < time1);
138 DCHECK(time0 <= resample_time); 126 DCHECK(time0 <= resample_time);
139 127
140 const float alpha = (resample_time - time0).InMillisecondsF() / 128 const float alpha = (resample_time - time0).InMillisecondsF() /
141 (time1 - time0).InMillisecondsF(); 129 (time1 - time0).InMillisecondsF();
142 130
143 scoped_ptr<MotionEventGeneric> event; 131 scoped_ptr<MotionEventGeneric> event;
144 const size_t pointer_count = event0.GetPointerCount(); 132 const size_t pointer_count = event0.GetPointerCount();
145 DCHECK_EQ(pointer_count, event1.GetPointerCount()); 133 DCHECK_EQ(pointer_count, event1.GetPointerCount());
146 for (size_t event0_i = 0; event0_i < pointer_count; ++event0_i) { 134 for (size_t event0_i = 0; event0_i < pointer_count; ++event0_i) {
147 int event1_i = event1.FindPointerIndexOfId(event0.GetPointerId(event0_i)); 135 int event1_i = event1.FindPointerIndexOfId(event0.GetPointerId(event0_i));
148 DCHECK_NE(event1_i, -1); 136 DCHECK_NE(event1_i, -1);
149 PointerProperties pointer = ResamplePointer( 137 PointerProperties pointer = ResamplePointer(
150 event0, event1, event0_i, static_cast<size_t>(event1_i), alpha); 138 event0, event1, event0_i, static_cast<size_t>(event1_i), alpha);
151 139
152 if (event0_i == 0) { 140 if (event0_i == 0) {
153 event.reset(new MotionEventGeneric( 141 event.reset(new MotionEventGeneric(
154 MotionEvent::ACTION_MOVE, resample_time, pointer)); 142 MotionEvent::ACTION_MOVE, resample_time, pointer));
155 } else { 143 } else {
156 event->PushPointer(pointer); 144 event->PushPointer(pointer);
157 } 145 }
158 } 146 }
159 147
160 DCHECK(event); 148 DCHECK(event);
161 event->set_id(event0.GetId());
162 event->set_action_index(event0.GetActionIndex());
163 event->set_button_state(event0.GetButtonState()); 149 event->set_button_state(event0.GetButtonState());
164
165 return event.Pass(); 150 return event.Pass();
166 } 151 }
167 152
168 // MotionEvent implementation for storing multiple events, with the most 153 // Synthesize a compound MotionEventGeneric event from a sequence of events.
169 // recent event used as the base event, and prior events used as the history. 154 // Events must be in non-decreasing (time) order.
170 class CompoundMotionEvent : public ui::MotionEvent { 155 scoped_ptr<MotionEventGeneric> ConsumeSamples(MotionEventVector events) {
171 public: 156 DCHECK(!events.empty());
172 explicit CompoundMotionEvent(MotionEventVector events) 157 scoped_ptr<MotionEventGeneric> event(events.back());
173 : events_(events.Pass()) { 158 for (size_t i = 0; i + 1 < events.size(); ++i)
174 DCHECK_GE(events_.size(), 1U); 159 event->PushHistoricalEvent(scoped_ptr<MotionEvent>(events[i]));
175 } 160 events.weak_clear();
176 ~CompoundMotionEvent() override {} 161 return event.Pass();
162 }
177 163
178 int GetId() const override { return latest().GetId(); } 164 // Consume a series of event samples, attempting to synthesize a new, synthetic
165 // event if the samples and sample time meet certain interpolation/extrapolation
166 // conditions. If such conditions are met, the provided samples will be added
167 // to the synthetic event's history, otherwise, the samples will be used to
168 // generate a basic, compound event.
169 // TODO(jdduke): Revisit resampling to handle cases where alternating frames
170 // are resampled or resampling is otherwise inconsistent, e.g., a 90hz input
171 // and 60hz frame signal could phase-align such that even frames yield an
172 // extrapolated event and odd frames are not resampled, crbug.com/399381.
173 scoped_ptr<MotionEventGeneric> ConsumeSamplesAndTryResampling(
174 base::TimeTicks resample_time,
175 MotionEventVector events,
176 const MotionEvent* next) {
177 const ui::MotionEvent* event0 = nullptr;
178 const ui::MotionEvent* event1 = nullptr;
179 if (next) {
180 DCHECK(resample_time < next->GetEventTime());
181 // Interpolate between current sample and future sample.
182 event0 = events.back();
183 event1 = next;
184 } else if (events.size() >= 2) {
185 // Extrapolate future sample using current sample and past sample.
186 event0 = events[events.size() - 2];
187 event1 = events[events.size() - 1];
179 188
180 Action GetAction() const override { return latest().GetAction(); } 189 const base::TimeTicks time1 = event1->GetEventTime();
181 190 base::TimeTicks max_predict =
182 int GetActionIndex() const override { return latest().GetActionIndex(); } 191 time1 +
183 192 std::min((event1->GetEventTime() - event0->GetEventTime()) / 2,
184 size_t GetPointerCount() const override { return latest().GetPointerCount(); } 193 base::TimeDelta::FromMilliseconds(kResampleMaxPredictionMs));
185 194 if (resample_time > max_predict) {
186 int GetPointerId(size_t pointer_index) const override { 195 TRACE_EVENT_INSTANT2("input",
187 return latest().GetPointerId(pointer_index); 196 "MotionEventBuffer::TryResample prediction adjust",
197 TRACE_EVENT_SCOPE_THREAD,
198 "original(ms)",
199 (resample_time - time1).InMilliseconds(),
200 "adjusted(ms)",
201 (max_predict - time1).InMilliseconds());
202 resample_time = max_predict;
203 }
204 } else {
205 TRACE_EVENT_INSTANT0("input",
206 "MotionEventBuffer::TryResample insufficient data",
207 TRACE_EVENT_SCOPE_THREAD);
208 return ConsumeSamples(events.Pass());
188 } 209 }
189 210
190 float GetX(size_t pointer_index) const override { 211 DCHECK(event0);
191 return latest().GetX(pointer_index); 212 DCHECK(event1);
213 const base::TimeTicks time0 = event0->GetEventTime();
214 const base::TimeTicks time1 = event1->GetEventTime();
215 base::TimeDelta delta = time1 - time0;
216 if (delta < base::TimeDelta::FromMilliseconds(kResampleMinDeltaMs)) {
217 TRACE_EVENT_INSTANT1("input",
218 "MotionEventBuffer::TryResample failure",
219 TRACE_EVENT_SCOPE_THREAD,
220 "event_delta_too_small(ms)",
221 delta.InMilliseconds());
222 return ConsumeSamples(events.Pass());
192 } 223 }
193 224
194 float GetY(size_t pointer_index) const override { 225 scoped_ptr<MotionEventGeneric> resampled_event =
195 return latest().GetY(pointer_index); 226 ResampleMotionEvent(*event0, *event1, resample_time);
196 } 227 for (size_t i = 0; i < events.size(); ++i)
197 228 resampled_event->PushHistoricalEvent(scoped_ptr<MotionEvent>(events[i]));
198 float GetRawX(size_t pointer_index) const override { 229 events.weak_clear();
199 return latest().GetRawX(pointer_index); 230 return resampled_event.Pass();
200 } 231 }
201
202 float GetRawY(size_t pointer_index) const override {
203 return latest().GetRawY(pointer_index);
204 }
205
206 float GetTouchMajor(size_t pointer_index) const override {
207 return latest().GetTouchMajor(pointer_index);
208 }
209
210 float GetTouchMinor(size_t pointer_index) const override {
211 return latest().GetTouchMinor(pointer_index);
212 }
213
214 float GetOrientation(size_t pointer_index) const override {
215 return latest().GetOrientation(pointer_index);
216 }
217
218 float GetPressure(size_t pointer_index) const override {
219 return latest().GetPressure(pointer_index);
220 }
221
222 ToolType GetToolType(size_t pointer_index) const override {
223 return latest().GetToolType(pointer_index);
224 }
225
226 int GetButtonState() const override { return latest().GetButtonState(); }
227
228 int GetFlags() const override { return latest().GetFlags(); }
229
230 base::TimeTicks GetEventTime() const override {
231 return latest().GetEventTime();
232 }
233
234 size_t GetHistorySize() const override { return events_.size() - 1; }
235
236 base::TimeTicks GetHistoricalEventTime(
237 size_t historical_index) const override {
238 DCHECK_LT(historical_index, GetHistorySize());
239 return events_[historical_index]->GetEventTime();
240 }
241
242 float GetHistoricalTouchMajor(size_t pointer_index,
243 size_t historical_index) const override {
244 DCHECK_LT(historical_index, GetHistorySize());
245 return events_[historical_index]->GetTouchMajor();
246 }
247
248 float GetHistoricalX(size_t pointer_index,
249 size_t historical_index) const override {
250 DCHECK_LT(historical_index, GetHistorySize());
251 return events_[historical_index]->GetX(pointer_index);
252 }
253
254 float GetHistoricalY(size_t pointer_index,
255 size_t historical_index) const override {
256 DCHECK_LT(historical_index, GetHistorySize());
257 return events_[historical_index]->GetY(pointer_index);
258 }
259
260 scoped_ptr<MotionEvent> Clone() const override {
261 MotionEventVector cloned_events;
262 cloned_events.reserve(events_.size());
263 for (size_t i = 0; i < events_.size(); ++i)
264 cloned_events.push_back(events_[i]->Clone().release());
265 return scoped_ptr<MotionEvent>(
266 new CompoundMotionEvent(cloned_events.Pass()));
267 }
268
269 scoped_ptr<MotionEvent> Cancel() const override { return latest().Cancel(); }
270
271 // Returns the new, resampled event, or NULL if none was created.
272 // TODO(jdduke): Revisit resampling to handle cases where alternating frames
273 // are resampled or resampling is otherwise inconsistent, e.g., a 90hz input
274 // and 60hz frame signal could phase-align such that even frames yield an
275 // extrapolated event and odd frames are not resampled, crbug.com/399381.
276 const MotionEvent* TryResample(base::TimeTicks resample_time,
277 const ui::MotionEvent* next) {
278 DCHECK_EQ(GetAction(), ACTION_MOVE);
279 const ui::MotionEvent* event0 = NULL;
280 const ui::MotionEvent* event1 = NULL;
281 if (next) {
282 DCHECK(resample_time < next->GetEventTime());
283 // Interpolate between current sample and future sample.
284 event0 = events_.back();
285 event1 = next;
286 } else if (events_.size() >= 2) {
287 // Extrapolate future sample using current sample and past sample.
288 event0 = events_[events_.size() - 2];
289 event1 = events_[events_.size() - 1];
290
291 const base::TimeTicks time1 = event1->GetEventTime();
292 base::TimeTicks max_predict =
293 time1 +
294 std::min((event1->GetEventTime() - event0->GetEventTime()) / 2,
295 base::TimeDelta::FromMilliseconds(kResampleMaxPredictionMs));
296 if (resample_time > max_predict) {
297 TRACE_EVENT_INSTANT2("input",
298 "MotionEventBuffer::TryResample prediction adjust",
299 TRACE_EVENT_SCOPE_THREAD,
300 "original(ms)",
301 (resample_time - time1).InMilliseconds(),
302 "adjusted(ms)",
303 (max_predict - time1).InMilliseconds());
304 resample_time = max_predict;
305 }
306 } else {
307 TRACE_EVENT_INSTANT0("input",
308 "MotionEventBuffer::TryResample insufficient data",
309 TRACE_EVENT_SCOPE_THREAD);
310 return NULL;
311 }
312
313 DCHECK(event0);
314 DCHECK(event1);
315 const base::TimeTicks time0 = event0->GetEventTime();
316 const base::TimeTicks time1 = event1->GetEventTime();
317 base::TimeDelta delta = time1 - time0;
318 if (delta < base::TimeDelta::FromMilliseconds(kResampleMinDeltaMs)) {
319 TRACE_EVENT_INSTANT1("input",
320 "MotionEventBuffer::TryResample failure",
321 TRACE_EVENT_SCOPE_THREAD,
322 "event_delta_too_small(ms)",
323 delta.InMilliseconds());
324 return NULL;
325 }
326
327 events_.push_back(
328 ResampleMotionEvent(*event0, *event1, resample_time).release());
329 return events_.back();
330 }
331
332 size_t samples() const { return events_.size(); }
333
334 private:
335 const MotionEvent& latest() const { return *events_.back(); }
336
337 // Events are in order from oldest to newest.
338 MotionEventVector events_;
339
340 DISALLOW_COPY_AND_ASSIGN(CompoundMotionEvent);
341 };
342 232
343 } // namespace 233 } // namespace
344 234
345 MotionEventBuffer::MotionEventBuffer(MotionEventBufferClient* client, 235 MotionEventBuffer::MotionEventBuffer(MotionEventBufferClient* client,
346 bool enable_resampling) 236 bool enable_resampling)
347 : client_(client), resample_(enable_resampling) { 237 : client_(client), resample_(enable_resampling) {
348 } 238 }
349 239
350 MotionEventBuffer::~MotionEventBuffer() { 240 MotionEventBuffer::~MotionEventBuffer() {
351 } 241 }
352 242
353 void MotionEventBuffer::OnMotionEvent(const MotionEvent& event) { 243 void MotionEventBuffer::OnMotionEvent(const MotionEvent& event) {
244 DCHECK_EQ(0U, event.GetHistorySize());
354 if (event.GetAction() != MotionEvent::ACTION_MOVE) { 245 if (event.GetAction() != MotionEvent::ACTION_MOVE) {
355 last_extrapolated_event_time_ = base::TimeTicks(); 246 last_extrapolated_event_time_ = base::TimeTicks();
356 if (!buffered_events_.empty()) 247 if (!buffered_events_.empty())
357 FlushWithoutResampling(buffered_events_.Pass()); 248 FlushWithoutResampling(buffered_events_.Pass());
358 client_->ForwardMotionEvent(event); 249 client_->ForwardMotionEvent(event);
359 return; 250 return;
360 } 251 }
361 252
362 // Guard against events that are *older* than the last one that may have been 253 // Guard against events that are *older* than the last one that may have been
363 // artificially synthesized. 254 // artificially synthesized.
364 if (!last_extrapolated_event_time_.is_null()) { 255 if (!last_extrapolated_event_time_.is_null()) {
365 DCHECK(buffered_events_.empty()); 256 DCHECK(buffered_events_.empty());
366 if (event.GetEventTime() < last_extrapolated_event_time_) 257 if (event.GetEventTime() < last_extrapolated_event_time_)
367 return; 258 return;
368 last_extrapolated_event_time_ = base::TimeTicks(); 259 last_extrapolated_event_time_ = base::TimeTicks();
369 } 260 }
370 261
371 scoped_ptr<MotionEvent> clone = event.Clone(); 262 scoped_ptr<MotionEventGeneric> clone = MotionEventGeneric::CloneEvent(event);
372 if (buffered_events_.empty()) { 263 if (buffered_events_.empty()) {
373 buffered_events_.push_back(clone.release()); 264 buffered_events_.push_back(clone.Pass());
374 client_->SetNeedsFlush(); 265 client_->SetNeedsFlush();
375 return; 266 return;
376 } 267 }
377 268
378 if (CanAddSample(*buffered_events_.front(), *clone)) { 269 if (CanAddSample(*buffered_events_.front(), *clone)) {
379 DCHECK(buffered_events_.back()->GetEventTime() <= clone->GetEventTime()); 270 DCHECK(buffered_events_.back()->GetEventTime() <= clone->GetEventTime());
380 } else { 271 } else {
381 FlushWithoutResampling(buffered_events_.Pass()); 272 FlushWithoutResampling(buffered_events_.Pass());
382 } 273 }
383 274
384 buffered_events_.push_back(clone.release()); 275 buffered_events_.push_back(clone.Pass());
385 // No need to request another flush as the first event will have requested it. 276 // No need to request another flush as the first event will have requested it.
386 } 277 }
387 278
388 void MotionEventBuffer::Flush(base::TimeTicks frame_time) { 279 void MotionEventBuffer::Flush(base::TimeTicks frame_time) {
389 if (buffered_events_.empty()) 280 if (buffered_events_.empty())
390 return; 281 return;
391 282
392 // Shifting the sample time back slightly minimizes the potential for 283 // Shifting the sample time back slightly minimizes the potential for
393 // misprediction when extrapolating events. 284 // misprediction when extrapolating events.
394 if (resample_) 285 if (resample_)
395 frame_time -= base::TimeDelta::FromMilliseconds(kResampleLatencyMs); 286 frame_time -= base::TimeDelta::FromMilliseconds(kResampleLatencyMs);
396 287
397 // TODO(jdduke): Use a persistent MotionEventVector vector for temporary 288 // TODO(jdduke): Use a persistent MotionEventVector vector for temporary
398 // storage. 289 // storage.
399 MotionEventVector events( 290 MotionEventVector events(
400 ConsumeSamplesNoLaterThan(&buffered_events_, frame_time)); 291 ConsumeSamplesNoLaterThan(&buffered_events_, frame_time));
401 if (events.empty()) { 292 if (events.empty()) {
402 DCHECK(!buffered_events_.empty()); 293 DCHECK(!buffered_events_.empty());
403 client_->SetNeedsFlush(); 294 client_->SetNeedsFlush();
404 return; 295 return;
405 } 296 }
406 297
407 if (!resample_ || (events.size() == 1 && buffered_events_.empty())) { 298 if (!resample_ || (events.size() == 1 && buffered_events_.empty())) {
408 FlushWithoutResampling(events.Pass()); 299 FlushWithoutResampling(events.Pass());
409 if (!buffered_events_.empty()) 300 if (!buffered_events_.empty())
410 client_->SetNeedsFlush(); 301 client_->SetNeedsFlush();
411 return; 302 return;
412 } 303 }
413 304
414 CompoundMotionEvent resampled_event(events.Pass()); 305 FlushWithResampling(events.Pass(), frame_time);
415 base::TimeTicks original_event_time = resampled_event.GetEventTime(); 306 }
307
308 void MotionEventBuffer::FlushWithResampling(MotionEventVector events,
309 base::TimeTicks resample_time) {
310 DCHECK(!events.empty());
311 base::TimeTicks original_event_time = events.back()->GetEventTime();
416 const MotionEvent* next_event = 312 const MotionEvent* next_event =
417 !buffered_events_.empty() ? buffered_events_.front() : NULL; 313 !buffered_events_.empty() ? buffered_events_.front() : nullptr;
418 314
419 // Try to interpolate/extrapolate a new event at |frame_time|. Note that 315 scoped_ptr<MotionEventGeneric> resampled_event =
420 // |new_event|, if non-NULL, is owned by |resampled_event_|. 316 ConsumeSamplesAndTryResampling(resample_time, events.Pass(), next_event);
421 const MotionEvent* new_event = 317 DCHECK(resampled_event);
422 resampled_event.TryResample(frame_time, next_event);
423 318
424 // Log the extrapolated event time, guarding against subsequently queued 319 // Log the extrapolated event time, guarding against subsequently queued
425 // events that might have an earlier timestamp. 320 // events that might have an earlier timestamp.
426 if (!next_event && new_event && 321 if (!next_event && resampled_event->GetEventTime() > original_event_time) {
427 new_event->GetEventTime() > original_event_time) { 322 last_extrapolated_event_time_ = resampled_event->GetEventTime();
428 last_extrapolated_event_time_ = new_event->GetEventTime();
429 } else { 323 } else {
430 last_extrapolated_event_time_ = base::TimeTicks(); 324 last_extrapolated_event_time_ = base::TimeTicks();
431 } 325 }
432 326
433 client_->ForwardMotionEvent(resampled_event); 327 client_->ForwardMotionEvent(*resampled_event);
434 if (!buffered_events_.empty()) 328 if (!buffered_events_.empty())
435 client_->SetNeedsFlush(); 329 client_->SetNeedsFlush();
436 } 330 }
437 331
438 void MotionEventBuffer::FlushWithoutResampling(MotionEventVector events) { 332 void MotionEventBuffer::FlushWithoutResampling(MotionEventVector events) {
439 last_extrapolated_event_time_ = base::TimeTicks(); 333 last_extrapolated_event_time_ = base::TimeTicks();
440 if (events.empty()) 334 if (events.empty())
441 return; 335 return;
442 336
443 if (events.size() == 1) { 337 client_->ForwardMotionEvent(*ConsumeSamples(events.Pass()));
444 // Avoid CompoundEvent creation to prevent unnecessary allocations.
445 scoped_ptr<MotionEvent> event(events.front());
446 events.weak_clear();
447 client_->ForwardMotionEvent(*event);
448 return;
449 }
450
451 CompoundMotionEvent compound_event(events.Pass());
452 client_->ForwardMotionEvent(compound_event);
453 } 338 }
454 339
455 } // namespace ui 340 } // namespace ui
OLDNEW
« no previous file with comments | « ui/events/gesture_detection/motion_event_buffer.h ('k') | ui/events/gesture_detection/motion_event_buffer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698