Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> | |
| 10 #include <iterator> | |
| 9 #include <utility> | 11 #include <utility> |
| 10 | 12 |
| 11 #include "base/trace_event/trace_event.h" | 13 #include "base/trace_event/trace_event.h" |
| 12 #include "ui/events/gesture_detection/motion_event_generic.h" | 14 #include "ui/events/gesture_detection/motion_event_generic.h" |
| 13 | 15 |
| 14 namespace ui { | 16 namespace ui { |
| 15 namespace { | 17 namespace { |
| 16 | 18 |
| 17 // Latency added during resampling. A few milliseconds doesn't hurt much but | 19 // Latency added during resampling. A few milliseconds doesn't hurt much but |
| 18 // reduces the impact of mispredicted touch positions. | 20 // reduces the impact of mispredicted touch positions. |
| 19 const int kResampleLatencyMs = 5; | 21 const int kResampleLatencyMs = 5; |
| 20 | 22 |
| 21 // Minimum time difference between consecutive samples before attempting to | 23 // Minimum time difference between consecutive samples before attempting to |
| 22 // resample. | 24 // resample. |
| 23 const int kResampleMinDeltaMs = 2; | 25 const int kResampleMinDeltaMs = 2; |
| 24 | 26 |
| 25 // Maximum time to predict forward from the last known state, to avoid | 27 // Maximum time to predict forward from the last known state, to avoid |
| 26 // predicting too far into the future. This time is further bounded by 50% of | 28 // predicting too far into the future. This time is further bounded by 50% of |
| 27 // the last time delta. | 29 // the last time delta. |
| 28 const int kResampleMaxPredictionMs = 8; | 30 const int kResampleMaxPredictionMs = 8; |
| 29 | 31 |
| 30 typedef ScopedVector<MotionEventGeneric> MotionEventVector; | 32 using MotionEventVector = std::vector<std::unique_ptr<MotionEventGeneric>>; |
| 31 | 33 |
| 32 float Lerp(float a, float b, float alpha) { | 34 float Lerp(float a, float b, float alpha) { |
| 33 return a + alpha * (b - a); | 35 return a + alpha * (b - a); |
| 34 } | 36 } |
| 35 | 37 |
| 36 bool CanAddSample(const MotionEvent& event0, const MotionEvent& event1) { | 38 bool CanAddSample(const MotionEvent& event0, const MotionEvent& event1) { |
| 37 DCHECK_EQ(event0.GetAction(), MotionEvent::ACTION_MOVE); | 39 DCHECK_EQ(event0.GetAction(), MotionEvent::ACTION_MOVE); |
| 38 if (event1.GetAction() != MotionEvent::ACTION_MOVE) | 40 if (event1.GetAction() != MotionEvent::ACTION_MOVE) |
| 39 return false; | 41 return false; |
| 40 | 42 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 52 } | 54 } |
| 53 | 55 |
| 54 return true; | 56 return true; |
| 55 } | 57 } |
| 56 | 58 |
| 57 bool ShouldResampleTool(MotionEvent::ToolType tool) { | 59 bool ShouldResampleTool(MotionEvent::ToolType tool) { |
| 58 return tool == MotionEvent::TOOL_TYPE_UNKNOWN || | 60 return tool == MotionEvent::TOOL_TYPE_UNKNOWN || |
| 59 tool == MotionEvent::TOOL_TYPE_FINGER; | 61 tool == MotionEvent::TOOL_TYPE_FINGER; |
| 60 } | 62 } |
| 61 | 63 |
| 62 size_t CountSamplesNoLaterThan(const MotionEventVector& batch, | 64 // Splits a chunk of events from the front of the provided |batch| and returns |
| 63 base::TimeTicks time) { | 65 // it. Requires that |batch| is sorted. |
| 64 size_t count = 0; | |
| 65 while (count < batch.size() && batch[count]->GetEventTime() <= time) | |
| 66 ++count; | |
| 67 return count; | |
| 68 } | |
| 69 | |
| 70 MotionEventVector ConsumeSamplesNoLaterThan(MotionEventVector* batch, | 66 MotionEventVector ConsumeSamplesNoLaterThan(MotionEventVector* batch, |
| 71 base::TimeTicks time) { | 67 base::TimeTicks time) { |
| 72 DCHECK(batch); | 68 DCHECK(batch); |
| 73 size_t count = CountSamplesNoLaterThan(*batch, time); | 69 auto first_kept_event = std::partition_point( |
|
Avi (use Gerrit)
2017/01/14 00:49:42
Note that the queue is sorted by time, which means
| |
| 74 DCHECK_GE(batch->size(), count); | 70 batch->begin(), batch->end(), |
| 75 if (count == 0) | 71 [time](const std::unique_ptr<MotionEventGeneric>& event) { |
| 76 return MotionEventVector(); | 72 return event->GetEventTime() <= time; |
| 77 | 73 }); |
| 78 if (count == batch->size()) | 74 MotionEventVector result(std::make_move_iterator(batch->begin()), |
| 79 return std::move(*batch); | 75 std::make_move_iterator(first_kept_event)); |
| 80 | 76 batch->erase(batch->begin(), first_kept_event); |
| 81 // TODO(jdduke): Use a ScopedDeque to work around this mess. | 77 return result; |
| 82 MotionEventVector unconsumed_batch; | |
| 83 unconsumed_batch.insert( | |
| 84 unconsumed_batch.begin(), batch->begin() + count, batch->end()); | |
| 85 batch->weak_erase(batch->begin() + count, batch->end()); | |
| 86 | |
| 87 unconsumed_batch.swap(*batch); | |
| 88 DCHECK_GE(unconsumed_batch.size(), 1U); | |
| 89 return unconsumed_batch; | |
| 90 } | 78 } |
| 91 | 79 |
| 92 // Linearly interpolate the pointer position between two MotionEvent samples. | 80 // Linearly interpolate the pointer position between two MotionEvent samples. |
| 93 // Only pointers of finger or unknown type will be resampled. | 81 // Only pointers of finger or unknown type will be resampled. |
| 94 PointerProperties ResamplePointer(const MotionEvent& event0, | 82 PointerProperties ResamplePointer(const MotionEvent& event0, |
| 95 const MotionEvent& event1, | 83 const MotionEvent& event1, |
| 96 size_t event0_pointer_index, | 84 size_t event0_pointer_index, |
| 97 size_t event1_pointer_index, | 85 size_t event1_pointer_index, |
| 98 float alpha) { | 86 float alpha) { |
| 99 DCHECK_EQ(event0.GetPointerId(event0_pointer_index), | 87 DCHECK_EQ(event0.GetPointerId(event0_pointer_index), |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 151 | 139 |
| 152 DCHECK(event); | 140 DCHECK(event); |
| 153 event->set_button_state(event0.GetButtonState()); | 141 event->set_button_state(event0.GetButtonState()); |
| 154 return event; | 142 return event; |
| 155 } | 143 } |
| 156 | 144 |
| 157 // Synthesize a compound MotionEventGeneric event from a sequence of events. | 145 // Synthesize a compound MotionEventGeneric event from a sequence of events. |
| 158 // Events must be in non-decreasing (time) order. | 146 // Events must be in non-decreasing (time) order. |
| 159 std::unique_ptr<MotionEventGeneric> ConsumeSamples(MotionEventVector events) { | 147 std::unique_ptr<MotionEventGeneric> ConsumeSamples(MotionEventVector events) { |
| 160 DCHECK(!events.empty()); | 148 DCHECK(!events.empty()); |
| 161 std::unique_ptr<MotionEventGeneric> event(events.back()); | 149 std::unique_ptr<MotionEventGeneric> event = std::move(events.back()); |
| 162 for (size_t i = 0; i + 1 < events.size(); ++i) | 150 events.pop_back(); |
| 163 event->PushHistoricalEvent(std::unique_ptr<MotionEvent>(events[i])); | 151 for (auto& historic_event : events) |
| 164 events.weak_clear(); | 152 event->PushHistoricalEvent(std::move(historic_event)); |
| 165 return event; | 153 return event; |
| 166 } | 154 } |
| 167 | 155 |
| 168 // Consume a series of event samples, attempting to synthesize a new, synthetic | 156 // Consume a series of event samples, attempting to synthesize a new, synthetic |
| 169 // event if the samples and sample time meet certain interpolation/extrapolation | 157 // event if the samples and sample time meet certain interpolation/extrapolation |
| 170 // conditions. If such conditions are met, the provided samples will be added | 158 // conditions. If such conditions are met, the provided samples will be added |
| 171 // to the synthetic event's history, otherwise, the samples will be used to | 159 // to the synthetic event's history, otherwise, the samples will be used to |
| 172 // generate a basic, compound event. | 160 // generate a basic, compound event. |
| 173 // TODO(jdduke): Revisit resampling to handle cases where alternating frames | 161 // TODO(jdduke): Revisit resampling to handle cases where alternating frames |
| 174 // are resampled or resampling is otherwise inconsistent, e.g., a 90hz input | 162 // are resampled or resampling is otherwise inconsistent, e.g., a 90hz input |
| 175 // and 60hz frame signal could phase-align such that even frames yield an | 163 // and 60hz frame signal could phase-align such that even frames yield an |
| 176 // extrapolated event and odd frames are not resampled, crbug.com/399381. | 164 // extrapolated event and odd frames are not resampled, crbug.com/399381. |
| 177 std::unique_ptr<MotionEventGeneric> ConsumeSamplesAndTryResampling( | 165 std::unique_ptr<MotionEventGeneric> ConsumeSamplesAndTryResampling( |
| 178 base::TimeTicks resample_time, | 166 base::TimeTicks resample_time, |
| 179 MotionEventVector events, | 167 MotionEventVector events, |
| 180 const MotionEvent* next) { | 168 const MotionEvent* next) { |
| 181 const ui::MotionEvent* event0 = nullptr; | 169 const ui::MotionEvent* event0 = nullptr; |
| 182 const ui::MotionEvent* event1 = nullptr; | 170 const ui::MotionEvent* event1 = nullptr; |
| 183 if (next) { | 171 if (next) { |
| 184 DCHECK(resample_time < next->GetEventTime()); | 172 DCHECK(resample_time < next->GetEventTime()); |
| 185 // Interpolate between current sample and future sample. | 173 // Interpolate between current sample and future sample. |
| 186 event0 = events.back(); | 174 event0 = events.back().get(); |
| 187 event1 = next; | 175 event1 = next; |
| 188 } else if (events.size() >= 2) { | 176 } else if (events.size() >= 2) { |
| 189 // Extrapolate future sample using current sample and past sample. | 177 // Extrapolate future sample using current sample and past sample. |
| 190 event0 = events[events.size() - 2]; | 178 event0 = events[events.size() - 2].get(); |
| 191 event1 = events[events.size() - 1]; | 179 event1 = events[events.size() - 1].get(); |
| 192 | 180 |
| 193 const base::TimeTicks time1 = event1->GetEventTime(); | 181 const base::TimeTicks time1 = event1->GetEventTime(); |
| 194 base::TimeTicks max_predict = | 182 base::TimeTicks max_predict = |
| 195 time1 + | 183 time1 + |
| 196 std::min((event1->GetEventTime() - event0->GetEventTime()) / 2, | 184 std::min((event1->GetEventTime() - event0->GetEventTime()) / 2, |
| 197 base::TimeDelta::FromMilliseconds(kResampleMaxPredictionMs)); | 185 base::TimeDelta::FromMilliseconds(kResampleMaxPredictionMs)); |
| 198 if (resample_time > max_predict) { | 186 if (resample_time > max_predict) { |
| 199 TRACE_EVENT_INSTANT2("input", | 187 TRACE_EVENT_INSTANT2("input", |
| 200 "MotionEventBuffer::TryResample prediction adjust", | 188 "MotionEventBuffer::TryResample prediction adjust", |
| 201 TRACE_EVENT_SCOPE_THREAD, | 189 TRACE_EVENT_SCOPE_THREAD, |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 221 TRACE_EVENT_INSTANT1("input", | 209 TRACE_EVENT_INSTANT1("input", |
| 222 "MotionEventBuffer::TryResample failure", | 210 "MotionEventBuffer::TryResample failure", |
| 223 TRACE_EVENT_SCOPE_THREAD, | 211 TRACE_EVENT_SCOPE_THREAD, |
| 224 "event_delta_too_small(ms)", | 212 "event_delta_too_small(ms)", |
| 225 delta.InMilliseconds()); | 213 delta.InMilliseconds()); |
| 226 return ConsumeSamples(std::move(events)); | 214 return ConsumeSamples(std::move(events)); |
| 227 } | 215 } |
| 228 | 216 |
| 229 std::unique_ptr<MotionEventGeneric> resampled_event = | 217 std::unique_ptr<MotionEventGeneric> resampled_event = |
| 230 ResampleMotionEvent(*event0, *event1, resample_time); | 218 ResampleMotionEvent(*event0, *event1, resample_time); |
| 231 for (size_t i = 0; i < events.size(); ++i) | 219 for (auto& historic_event : events) |
| 232 resampled_event->PushHistoricalEvent( | 220 resampled_event->PushHistoricalEvent(std::move(historic_event)); |
| 233 std::unique_ptr<MotionEvent>(events[i])); | |
| 234 events.weak_clear(); | |
| 235 return resampled_event; | 221 return resampled_event; |
| 236 } | 222 } |
| 237 | 223 |
| 238 } // namespace | 224 } // namespace |
| 239 | 225 |
| 240 MotionEventBuffer::MotionEventBuffer(MotionEventBufferClient* client, | 226 MotionEventBuffer::MotionEventBuffer(MotionEventBufferClient* client, |
| 241 bool enable_resampling) | 227 bool enable_resampling) |
| 242 : client_(client), resample_(enable_resampling) { | 228 : client_(client), resample_(enable_resampling) { |
| 243 } | 229 } |
| 244 | 230 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 266 | 252 |
| 267 std::unique_ptr<MotionEventGeneric> clone = | 253 std::unique_ptr<MotionEventGeneric> clone = |
| 268 MotionEventGeneric::CloneEvent(event); | 254 MotionEventGeneric::CloneEvent(event); |
| 269 if (buffered_events_.empty()) { | 255 if (buffered_events_.empty()) { |
| 270 buffered_events_.push_back(std::move(clone)); | 256 buffered_events_.push_back(std::move(clone)); |
| 271 client_->SetNeedsFlush(); | 257 client_->SetNeedsFlush(); |
| 272 return; | 258 return; |
| 273 } | 259 } |
| 274 | 260 |
| 275 if (CanAddSample(*buffered_events_.front(), *clone)) { | 261 if (CanAddSample(*buffered_events_.front(), *clone)) { |
| 262 // Ensure that buffered_events_ is ordered. | |
| 276 DCHECK(buffered_events_.back()->GetEventTime() <= clone->GetEventTime()); | 263 DCHECK(buffered_events_.back()->GetEventTime() <= clone->GetEventTime()); |
| 277 } else { | 264 } else { |
| 278 FlushWithoutResampling(std::move(buffered_events_)); | 265 FlushWithoutResampling(std::move(buffered_events_)); |
| 279 } | 266 } |
| 280 | 267 |
| 281 buffered_events_.push_back(std::move(clone)); | 268 buffered_events_.push_back(std::move(clone)); |
| 282 // No need to request another flush as the first event will have requested it. | 269 // No need to request another flush as the first event will have requested it. |
| 283 } | 270 } |
| 284 | 271 |
| 285 void MotionEventBuffer::Flush(base::TimeTicks frame_time) { | 272 void MotionEventBuffer::Flush(base::TimeTicks frame_time) { |
| 286 if (buffered_events_.empty()) | 273 if (buffered_events_.empty()) |
| 287 return; | 274 return; |
| 288 | 275 |
| 289 // Shifting the sample time back slightly minimizes the potential for | 276 // Shifting the sample time back slightly minimizes the potential for |
| 290 // misprediction when extrapolating events. | 277 // misprediction when extrapolating events. |
| 291 if (resample_) | 278 if (resample_) |
| 292 frame_time -= base::TimeDelta::FromMilliseconds(kResampleLatencyMs); | 279 frame_time -= base::TimeDelta::FromMilliseconds(kResampleLatencyMs); |
| 293 | 280 |
| 294 // TODO(jdduke): Use a persistent MotionEventVector vector for temporary | 281 // TODO(jdduke): Use a persistent MotionEventVector vector for temporary |
| 295 // storage. | 282 // storage. |
| 296 MotionEventVector events( | 283 MotionEventVector events = |
| 297 ConsumeSamplesNoLaterThan(&buffered_events_, frame_time)); | 284 ConsumeSamplesNoLaterThan(&buffered_events_, frame_time); |
| 298 if (events.empty()) { | 285 if (events.empty()) { |
| 299 DCHECK(!buffered_events_.empty()); | 286 DCHECK(!buffered_events_.empty()); |
| 300 client_->SetNeedsFlush(); | 287 client_->SetNeedsFlush(); |
| 301 return; | 288 return; |
| 302 } | 289 } |
| 303 | 290 |
| 304 if (!resample_ || (events.size() == 1 && buffered_events_.empty())) { | 291 if (!resample_ || (events.size() == 1 && buffered_events_.empty())) { |
| 305 FlushWithoutResampling(std::move(events)); | 292 FlushWithoutResampling(std::move(events)); |
| 306 if (!buffered_events_.empty()) | 293 if (!buffered_events_.empty()) |
| 307 client_->SetNeedsFlush(); | 294 client_->SetNeedsFlush(); |
| 308 return; | 295 return; |
| 309 } | 296 } |
| 310 | 297 |
| 311 FlushWithResampling(std::move(events), frame_time); | 298 FlushWithResampling(std::move(events), frame_time); |
| 312 } | 299 } |
| 313 | 300 |
| 314 void MotionEventBuffer::FlushWithResampling(MotionEventVector events, | 301 void MotionEventBuffer::FlushWithResampling(MotionEventVector events, |
| 315 base::TimeTicks resample_time) { | 302 base::TimeTicks resample_time) { |
| 316 DCHECK(!events.empty()); | 303 DCHECK(!events.empty()); |
| 317 base::TimeTicks original_event_time = events.back()->GetEventTime(); | 304 base::TimeTicks original_event_time = events.back()->GetEventTime(); |
| 318 const MotionEvent* next_event = | 305 const MotionEvent* next_event = |
| 319 !buffered_events_.empty() ? buffered_events_.front() : nullptr; | 306 !buffered_events_.empty() ? buffered_events_.front().get() : nullptr; |
| 320 | 307 |
| 321 std::unique_ptr<MotionEventGeneric> resampled_event = | 308 std::unique_ptr<MotionEventGeneric> resampled_event = |
| 322 ConsumeSamplesAndTryResampling(resample_time, std::move(events), | 309 ConsumeSamplesAndTryResampling(resample_time, std::move(events), |
| 323 next_event); | 310 next_event); |
| 324 DCHECK(resampled_event); | 311 DCHECK(resampled_event); |
| 325 | 312 |
| 326 // Log the extrapolated event time, guarding against subsequently queued | 313 // Log the extrapolated event time, guarding against subsequently queued |
| 327 // events that might have an earlier timestamp. | 314 // events that might have an earlier timestamp. |
| 328 if (!next_event && resampled_event->GetEventTime() > original_event_time) { | 315 if (!next_event && resampled_event->GetEventTime() > original_event_time) { |
| 329 last_extrapolated_event_time_ = resampled_event->GetEventTime(); | 316 last_extrapolated_event_time_ = resampled_event->GetEventTime(); |
| 330 } else { | 317 } else { |
| 331 last_extrapolated_event_time_ = base::TimeTicks(); | 318 last_extrapolated_event_time_ = base::TimeTicks(); |
| 332 } | 319 } |
| 333 | 320 |
| 334 client_->ForwardMotionEvent(*resampled_event); | 321 client_->ForwardMotionEvent(*resampled_event); |
| 335 if (!buffered_events_.empty()) | 322 if (!buffered_events_.empty()) |
| 336 client_->SetNeedsFlush(); | 323 client_->SetNeedsFlush(); |
| 337 } | 324 } |
| 338 | 325 |
| 339 void MotionEventBuffer::FlushWithoutResampling(MotionEventVector events) { | 326 void MotionEventBuffer::FlushWithoutResampling(MotionEventVector events) { |
| 340 last_extrapolated_event_time_ = base::TimeTicks(); | 327 last_extrapolated_event_time_ = base::TimeTicks(); |
| 341 if (events.empty()) | 328 if (events.empty()) |
| 342 return; | 329 return; |
| 343 | 330 |
| 344 client_->ForwardMotionEvent(*ConsumeSamples(std::move(events))); | 331 client_->ForwardMotionEvent(*ConsumeSamples(std::move(events))); |
| 345 } | 332 } |
| 346 | 333 |
| 347 } // namespace ui | 334 } // namespace ui |
| OLD | NEW |