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

Side by Side Diff: content/renderer/input/main_thread_event_queue.cc

Issue 2765583002: Teach main thread event queue about closures. (Closed)
Patch Set: Fix Mac issue Created 3 years, 8 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 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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/renderer/input/main_thread_event_queue.h" 5 #include "content/renderer/input/main_thread_event_queue.h"
6 6
7 #include "base/metrics/field_trial.h" 7 #include "base/metrics/field_trial.h"
8 #include "base/metrics/histogram_macros.h" 8 #include "base/metrics/histogram_macros.h"
9 #include "base/strings/string_number_conversions.h" 9 #include "base/strings/string_number_conversions.h"
10 #include "content/common/input/event_with_latency_info.h" 10 #include "content/common/input/event_with_latency_info.h"
11 #include "content/common/input_messages.h" 11 #include "content/common/input_messages.h"
12 12
13 namespace content { 13 namespace content {
14 14
15 namespace { 15 namespace {
16 16
17 const size_t kTenSeconds = 10 * 1000 * 1000;
18
19 class QueuedClosure : public MainThreadEventQueueTask {
20 public:
21 QueuedClosure(const base::Closure& closure) : closure_(closure) {}
22
23 ~QueuedClosure() override {}
24
25 bool CanCoalesceWith(const MainThreadEventQueueTask&) const override {
26 return false;
27 }
28
29 void CoalesceWith(const MainThreadEventQueueTask&) override { NOTREACHED(); }
30
31 bool ShouldSkipOverForCoalescing(
32 const MainThreadEventQueueTask&) const override {
33 return false;
34 }
35
36 bool IsWebInputEvent() const override { return false; }
37
38 void Dispatch(int routing_id, MainThreadEventQueueClient*) override {
39 closure_.Run();
40 }
41
42 void EventHandled(int routing_id,
43 blink::scheduler::RendererScheduler* renderer_scheduler,
44 MainThreadEventQueueClient* client,
45 blink::WebInputEvent::Type type,
46 blink::WebInputEventResult result,
47 InputEventAckState ack_result) override {}
48
49 private:
50 base::Closure closure_;
51 };
52
53 class QueuedWebInputEvent : public ScopedWebInputEventWithLatencyInfo,
54 public MainThreadEventQueueTask {
55 public:
56 QueuedWebInputEvent(ui::WebScopedInputEvent event,
57 const ui::LatencyInfo& latency,
58 InputEventDispatchType dispatch_type,
59 bool originally_cancelable)
60 : ScopedWebInputEventWithLatencyInfo(std::move(event), latency),
61 dispatch_type_(dispatch_type),
62 non_blocking_coalesced_count_(0),
63 creation_timestamp_(base::TimeTicks::Now()),
64 last_coalesced_timestamp_(creation_timestamp_),
65 originally_cancelable_(originally_cancelable) {}
66
67 ~QueuedWebInputEvent() override {}
68
69 bool CanCoalesceWith(
70 const MainThreadEventQueueTask& other_item) const override {
71 if (!other_item.IsWebInputEvent())
72 return false;
73 const QueuedWebInputEvent& other_event =
74 static_cast<const QueuedWebInputEvent&>(other_item);
75 return ScopedWebInputEventWithLatencyInfo::CanCoalesceWith(other_event);
76 }
77
78 void CoalesceWith(const MainThreadEventQueueTask& other_item) override {
79 DCHECK(CanCoalesceWith(other_item));
80 const QueuedWebInputEvent& other_event =
81 static_cast<const QueuedWebInputEvent&>(other_item);
82 // If this event was blocking push the event id to the blocking
83 // list before updating the dispatch_type of this event.
84 if (dispatch_type_ == DISPATCH_TYPE_BLOCKING) {
85 blocking_coalesced_event_ids_.push_back(
86 ui::WebInputEventTraits::GetUniqueTouchEventId(event()));
87 } else {
88 non_blocking_coalesced_count_++;
89 }
90 ScopedWebInputEventWithLatencyInfo::CoalesceWith(other_event);
91 last_coalesced_timestamp_ = base::TimeTicks::Now();
92
93 // The newest event (|other_item|) always wins when updating fields.
94 dispatch_type_ = other_event.dispatch_type_;
95 originally_cancelable_ = other_event.originally_cancelable_;
96 }
97
98 bool ShouldSkipOverForCoalescing(
99 const MainThreadEventQueueTask& other_item) const override {
100 if (!other_item.IsWebInputEvent())
101 return false;
102 const QueuedWebInputEvent& other_event =
103 static_cast<const QueuedWebInputEvent&>(other_item);
104 return !event().isSameEventClass(other_event.event());
105 }
106
107 bool IsWebInputEvent() const override { return true; }
108
109 void Dispatch(int routing_id, MainThreadEventQueueClient* client) override {
110 // Report the coalesced count only for continuous events; otherwise
111 // the zero value would be dominated by non-continuous events.
112 base::TimeTicks now = base::TimeTicks::Now();
113 if (IsContinuousEvent()) {
114 UMA_HISTOGRAM_CUSTOM_COUNTS(
115 "Event.MainThreadEventQueue.Continuous.QueueingTime",
116 (now - creationTimestamp()).InMicroseconds(), 1, kTenSeconds, 50);
117
118 UMA_HISTOGRAM_CUSTOM_COUNTS(
119 "Event.MainThreadEventQueue.Continuous.FreshnessTime",
120 (now - lastCoalescedTimestamp()).InMicroseconds(), 1, kTenSeconds,
121 50);
122
123 UMA_HISTOGRAM_COUNTS_1000("Event.MainThreadEventQueue.CoalescedCount",
124 coalescedCount());
125 } else {
126 UMA_HISTOGRAM_CUSTOM_COUNTS(
127 "Event.MainThreadEventQueue.NonContinuous.QueueingTime",
128 (now - creationTimestamp()).InMicroseconds(), 1, kTenSeconds, 50);
129 }
130
131 InputEventDispatchType dispatch_type = dispatchType();
132 if (!blockingCoalescedEventIds().empty()) {
133 switch (dispatch_type) {
134 case DISPATCH_TYPE_BLOCKING:
135 dispatch_type = DISPATCH_TYPE_BLOCKING_NOTIFY_MAIN;
136 break;
137 case DISPATCH_TYPE_NON_BLOCKING:
138 dispatch_type = DISPATCH_TYPE_NON_BLOCKING_NOTIFY_MAIN;
139 break;
140 default:
141 NOTREACHED();
142 }
143 }
144 client->HandleEventOnMainThread(routing_id, &coalesced_event(),
145 latencyInfo(), dispatch_type);
146 }
147
148 void EventHandled(int routing_id,
149 blink::scheduler::RendererScheduler* renderer_scheduler,
150 MainThreadEventQueueClient* client,
151 blink::WebInputEvent::Type type,
152 blink::WebInputEventResult result,
153 InputEventAckState ack_result) override {
154 for (const auto id : blockingCoalescedEventIds()) {
155 client->SendInputEventAck(routing_id, type, ack_result, id);
156 if (renderer_scheduler) {
157 renderer_scheduler->DidHandleInputEventOnMainThread(event(), result);
158 }
159 }
160 }
161
162 bool originallyCancelable() const { return originally_cancelable_; }
163
164 private:
165 const std::deque<uint32_t>& blockingCoalescedEventIds() const {
166 return blocking_coalesced_event_ids_;
167 }
168 InputEventDispatchType dispatchType() const { return dispatch_type_; }
169 base::TimeTicks creationTimestamp() const { return creation_timestamp_; }
170 base::TimeTicks lastCoalescedTimestamp() const {
171 return last_coalesced_timestamp_;
172 }
173
174 size_t coalescedCount() const {
175 return non_blocking_coalesced_count_ + blocking_coalesced_event_ids_.size();
176 }
177
178 bool IsContinuousEvent() const {
179 switch (event().type()) {
180 case blink::WebInputEvent::MouseMove:
181 case blink::WebInputEvent::MouseWheel:
182 case blink::WebInputEvent::TouchMove:
183 return true;
184 default:
185 return false;
186 }
187 }
188
189 InputEventDispatchType dispatch_type_;
190
191 // Contains the unique touch event ids to be acked. If
192 // the events are not TouchEvents the values will be 0. More importantly for
193 // those cases the deque ends up containing how many additional ACKs
194 // need to be sent.
195 std::deque<uint32_t> blocking_coalesced_event_ids_;
196 // Contains the number of non-blocking events coalesced.
197 size_t non_blocking_coalesced_count_;
198 base::TimeTicks creation_timestamp_;
199 base::TimeTicks last_coalesced_timestamp_;
200
201 // Whether the received event was originally cancelable or not. The compositor
202 // input handler can change the event based on presence of event handlers so
203 // this is the state at which the renderer received the event from the
204 // browser.
205 bool originally_cancelable_;
206 };
207
17 // Time interval at which touchmove events will be skipped during rAF signal. 208 // Time interval at which touchmove events will be skipped during rAF signal.
18 const base::TimeDelta kAsyncTouchMoveInterval = 209 const base::TimeDelta kAsyncTouchMoveInterval =
19 base::TimeDelta::FromMilliseconds(200); 210 base::TimeDelta::FromMilliseconds(200);
20 211
21 const size_t kTenSeconds = 10 * 1000 * 1000; 212 bool IsAsyncTouchMove(
22 213 const std::unique_ptr<MainThreadEventQueueTask>& queued_item) {
23 bool IsContinuousEvent(const std::unique_ptr<EventWithDispatchType>& event) { 214 if (!queued_item->IsWebInputEvent())
24 switch (event->event().type()) { 215 return false;
25 case blink::WebInputEvent::MouseMove: 216 const QueuedWebInputEvent* event =
26 case blink::WebInputEvent::MouseWheel: 217 static_cast<const QueuedWebInputEvent*>(queued_item.get());
27 case blink::WebInputEvent::TouchMove:
28 return true;
29 default:
30 return false;
31 }
32 }
33
34 bool IsAsyncTouchMove(const std::unique_ptr<EventWithDispatchType>& event) {
35 if (event->event().type() != blink::WebInputEvent::TouchMove) 218 if (event->event().type() != blink::WebInputEvent::TouchMove)
36 return false; 219 return false;
37 const blink::WebTouchEvent& touch_event = 220 const blink::WebTouchEvent& touch_event =
38 static_cast<const blink::WebTouchEvent&>(event->event()); 221 static_cast<const blink::WebTouchEvent&>(event->event());
39 return touch_event.movedBeyondSlopRegion && !event->originallyCancelable(); 222 return touch_event.movedBeyondSlopRegion && !event->originallyCancelable();
40 } 223 }
41 224
42 } // namespace 225 } // namespace
43 226
44 EventWithDispatchType::EventWithDispatchType(
45 ui::WebScopedInputEvent event,
46 const ui::LatencyInfo& latency,
47 InputEventDispatchType dispatch_type,
48 bool originally_cancelable)
49 : ScopedWebInputEventWithLatencyInfo(std::move(event), latency),
50 dispatch_type_(dispatch_type),
51 non_blocking_coalesced_count_(0),
52 creation_timestamp_(base::TimeTicks::Now()),
53 last_coalesced_timestamp_(creation_timestamp_),
54 originally_cancelable_(originally_cancelable) {}
55
56 EventWithDispatchType::~EventWithDispatchType() {}
57
58 void EventWithDispatchType::CoalesceWith(const EventWithDispatchType& other) {
59 // If this event was blocking push the event id to the blocking
60 // list before updating the dispatch_type of this event.
61 if (dispatch_type_ == DISPATCH_TYPE_BLOCKING) {
62 blocking_coalesced_event_ids_.push_back(
63 ui::WebInputEventTraits::GetUniqueTouchEventId(event()));
64 } else {
65 non_blocking_coalesced_count_++;
66 }
67 ScopedWebInputEventWithLatencyInfo::CoalesceWith(other);
68 dispatch_type_ = other.dispatch_type_;
69 last_coalesced_timestamp_ = base::TimeTicks::Now();
70 originally_cancelable_ = other.originally_cancelable_;
71 }
72
73 MainThreadEventQueue::SharedState::SharedState() 227 MainThreadEventQueue::SharedState::SharedState()
74 : sent_main_frame_request_(false) {} 228 : sent_main_frame_request_(false), sent_post_task_(false) {}
75 229
76 MainThreadEventQueue::SharedState::~SharedState() {} 230 MainThreadEventQueue::SharedState::~SharedState() {}
77 231
78 MainThreadEventQueue::MainThreadEventQueue( 232 MainThreadEventQueue::MainThreadEventQueue(
79 int routing_id, 233 int routing_id,
80 MainThreadEventQueueClient* client, 234 MainThreadEventQueueClient* client,
81 const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner, 235 const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner,
82 blink::scheduler::RendererScheduler* renderer_scheduler) 236 blink::scheduler::RendererScheduler* renderer_scheduler)
83 : routing_id_(routing_id), 237 : routing_id_(routing_id),
84 client_(client), 238 client_(client),
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 // Adjust the |dispatchType| on the event since the compositor 343 // Adjust the |dispatchType| on the event since the compositor
190 // determined all event listeners are passive. 344 // determined all event listeners are passive.
191 wheel_event->dispatchType = 345 wheel_event->dispatchType =
192 blink::WebInputEvent::ListenersNonBlockingPassive; 346 blink::WebInputEvent::ListenersNonBlockingPassive;
193 } 347 }
194 } 348 }
195 349
196 InputEventDispatchType dispatch_type = 350 InputEventDispatchType dispatch_type =
197 non_blocking ? DISPATCH_TYPE_NON_BLOCKING : DISPATCH_TYPE_BLOCKING; 351 non_blocking ? DISPATCH_TYPE_NON_BLOCKING : DISPATCH_TYPE_BLOCKING;
198 352
199 std::unique_ptr<EventWithDispatchType> event_with_dispatch_type( 353 std::unique_ptr<QueuedWebInputEvent> event_with_dispatch_type(
200 new EventWithDispatchType(std::move(event), latency, dispatch_type, 354 new QueuedWebInputEvent(std::move(event), latency, dispatch_type,
201 originally_cancelable)); 355 originally_cancelable));
202 356
203 QueueEvent(std::move(event_with_dispatch_type)); 357 QueueEvent(std::move(event_with_dispatch_type));
204 358
205 // send an ack when we are non-blocking. 359 // send an ack when we are non-blocking.
206 return non_blocking; 360 return non_blocking;
207 } 361 }
208 362
363 void MainThreadEventQueue::QueueClosure(const base::Closure& closure) {
364 bool needs_post_task = false;
365 std::unique_ptr<QueuedClosure> item(new QueuedClosure(closure));
366 {
367 base::AutoLock lock(shared_state_lock_);
368 shared_state_.events_.Queue(std::move(item));
369 needs_post_task = !shared_state_.sent_post_task_;
370 shared_state_.sent_post_task_ = true;
371 }
372
373 if (needs_post_task)
374 PostTaskToMainThread();
375 }
376
209 void MainThreadEventQueue::DispatchInFlightEvent() { 377 void MainThreadEventQueue::DispatchInFlightEvent() {
210 if (in_flight_event_) { 378 if (in_flight_event_) {
211 // Report the coalesced count only for continuous events; otherwise 379 in_flight_event_->Dispatch(routing_id_, client_);
212 // the zero value would be dominated by non-continuous events. 380 in_flight_event_.reset();
213 base::TimeTicks now = base::TimeTicks::Now();
214 if (IsContinuousEvent(in_flight_event_)) {
215 UMA_HISTOGRAM_CUSTOM_COUNTS(
216 "Event.MainThreadEventQueue.Continuous.QueueingTime",
217 (now - in_flight_event_->creationTimestamp()).InMicroseconds(), 1,
218 kTenSeconds, 50);
219
220 UMA_HISTOGRAM_CUSTOM_COUNTS(
221 "Event.MainThreadEventQueue.Continuous.FreshnessTime",
222 (now - in_flight_event_->lastCoalescedTimestamp()).InMicroseconds(),
223 1, kTenSeconds, 50);
224
225 UMA_HISTOGRAM_COUNTS_1000("Event.MainThreadEventQueue.CoalescedCount",
226 in_flight_event_->coalescedCount());
227 } else {
228 UMA_HISTOGRAM_CUSTOM_COUNTS(
229 "Event.MainThreadEventQueue.NonContinuous.QueueingTime",
230 (now - in_flight_event_->creationTimestamp()).InMicroseconds(), 1,
231 kTenSeconds, 50);
232 }
233
234 InputEventDispatchType dispatch_type = in_flight_event_->dispatchType();
235 if (!in_flight_event_->blockingCoalescedEventIds().empty()) {
236 switch (dispatch_type) {
237 case DISPATCH_TYPE_BLOCKING:
238 dispatch_type = DISPATCH_TYPE_BLOCKING_NOTIFY_MAIN;
239 break;
240 case DISPATCH_TYPE_NON_BLOCKING:
241 dispatch_type = DISPATCH_TYPE_NON_BLOCKING_NOTIFY_MAIN;
242 break;
243 default:
244 NOTREACHED();
245 }
246 }
247 client_->HandleEventOnMainThread(
248 routing_id_, &in_flight_event_->coalesced_event(),
249 in_flight_event_->latencyInfo(), dispatch_type);
250 } 381 }
251
252 in_flight_event_.reset();
253 } 382 }
254 383
255 void MainThreadEventQueue::PossiblyScheduleMainFrame() { 384 void MainThreadEventQueue::PossiblyScheduleMainFrame() {
256 if (IsRafAlignedInputDisabled()) 385 if (IsRafAlignedInputDisabled())
257 return; 386 return;
258 bool needs_main_frame = false; 387 bool needs_main_frame = false;
259 { 388 {
260 base::AutoLock lock(shared_state_lock_); 389 base::AutoLock lock(shared_state_lock_);
261 if (!shared_state_.sent_main_frame_request_ && 390 if (!shared_state_.sent_main_frame_request_ &&
262 !shared_state_.events_.empty() && 391 !shared_state_.events_.empty() &&
263 IsRafAlignedEvent(shared_state_.events_.front()->event())) { 392 IsRafAlignedEvent(shared_state_.events_.front())) {
264 needs_main_frame = !shared_state_.sent_main_frame_request_; 393 needs_main_frame = !shared_state_.sent_main_frame_request_;
265 shared_state_.sent_main_frame_request_ = false; 394 shared_state_.sent_main_frame_request_ = false;
266 } 395 }
267 } 396 }
268 if (needs_main_frame) 397 if (needs_main_frame)
269 client_->NeedsMainFrame(routing_id_); 398 client_->NeedsMainFrame(routing_id_);
270 } 399 }
271 400
272 void MainThreadEventQueue::DispatchSingleEvent() { 401 void MainThreadEventQueue::DispatchEvents() {
402 std::deque<std::unique_ptr<MainThreadEventQueueTask>> events_to_process;
273 { 403 {
274 base::AutoLock lock(shared_state_lock_); 404 base::AutoLock lock(shared_state_lock_);
275 if (shared_state_.events_.empty()) 405 shared_state_.sent_post_task_ = false;
276 return;
277 406
278 in_flight_event_ = shared_state_.events_.Pop(); 407 shared_state_.events_.swap(&events_to_process);
408
409 // Now take any raf aligned events that are at the tail of the queue
410 // and put them back.
411 while (!events_to_process.empty()) {
412 if (!IsRafAlignedEvent(events_to_process.back()))
413 break;
414 shared_state_.events_.emplace_front(std::move(events_to_process.back()));
415 events_to_process.pop_back();
416 }
279 } 417 }
280 DispatchInFlightEvent(); 418 while (!events_to_process.empty()) {
419 in_flight_event_ = std::move(events_to_process.front());
420 events_to_process.pop_front();
421 DispatchInFlightEvent();
422 }
281 PossiblyScheduleMainFrame(); 423 PossiblyScheduleMainFrame();
282 } 424 }
283 425
284 void MainThreadEventQueue::EventHandled(blink::WebInputEvent::Type type, 426 void MainThreadEventQueue::EventHandled(blink::WebInputEvent::Type type,
285 blink::WebInputEventResult result, 427 blink::WebInputEventResult result,
286 InputEventAckState ack_result) { 428 InputEventAckState ack_result) {
287 if (in_flight_event_) { 429 if (in_flight_event_) {
288 for (const auto id : in_flight_event_->blockingCoalescedEventIds()) { 430 in_flight_event_->EventHandled(routing_id_, renderer_scheduler_, client_,
289 client_->SendInputEventAck(routing_id_, type, ack_result, id); 431 type, result, ack_result);
290 if (renderer_scheduler_) {
291 renderer_scheduler_->DidHandleInputEventOnMainThread(
292 in_flight_event_->event(), result);
293 }
294 }
295 } 432 }
296 } 433 }
297 434
298 void MainThreadEventQueue::DispatchRafAlignedInput(base::TimeTicks frame_time) { 435 void MainThreadEventQueue::DispatchRafAlignedInput(base::TimeTicks frame_time) {
299 if (IsRafAlignedInputDisabled()) 436 if (IsRafAlignedInputDisabled())
300 return; 437 return;
301 438
302 std::deque<std::unique_ptr<EventWithDispatchType>> events_to_process; 439 std::deque<std::unique_ptr<MainThreadEventQueueTask>> events_to_process;
303 { 440 {
304 base::AutoLock lock(shared_state_lock_); 441 base::AutoLock lock(shared_state_lock_);
305 shared_state_.sent_main_frame_request_ = false; 442 shared_state_.sent_main_frame_request_ = false;
306 443
307 while (!shared_state_.events_.empty()) { 444 while (!shared_state_.events_.empty()) {
308 if (!IsRafAlignedEvent(shared_state_.events_.front()->event())) 445 if (IsRafAlignedEvent(shared_state_.events_.front())) {
309 break; 446 // Throttle touchmoves that are async.
310 447 if (handle_raf_aligned_touch_input_ &&
311 // Throttle touchmoves that are async. 448 IsAsyncTouchMove(shared_state_.events_.front())) {
312 if (handle_raf_aligned_touch_input_ && 449 if (shared_state_.events_.size() == 1 &&
313 IsAsyncTouchMove(shared_state_.events_.front())) { 450 frame_time < shared_state_.last_async_touch_move_timestamp_ +
314 if (shared_state_.events_.size() == 1 && 451 kAsyncTouchMoveInterval) {
315 frame_time < shared_state_.last_async_touch_move_timestamp_ + 452 break;
316 kAsyncTouchMoveInterval) { 453 }
317 break; 454 shared_state_.last_async_touch_move_timestamp_ = frame_time;
318 } 455 }
319 shared_state_.last_async_touch_move_timestamp_ = frame_time;
320 } 456 }
321 events_to_process.emplace_back(shared_state_.events_.Pop()); 457 events_to_process.emplace_back(shared_state_.events_.Pop());
322 } 458 }
323 } 459 }
324 460
325 while(!events_to_process.empty()) { 461 while(!events_to_process.empty()) {
326 in_flight_event_ = std::move(events_to_process.front()); 462 in_flight_event_ = std::move(events_to_process.front());
327 events_to_process.pop_front(); 463 events_to_process.pop_front();
328 DispatchInFlightEvent(); 464 DispatchInFlightEvent();
329 } 465 }
330 PossiblyScheduleMainFrame(); 466 PossiblyScheduleMainFrame();
331 } 467 }
332 468
333 void MainThreadEventQueue::SendEventNotificationToMainThread() { 469 void MainThreadEventQueue::PostTaskToMainThread() {
334 main_task_runner_->PostTask( 470 main_task_runner_->PostTask(
335 FROM_HERE, base::Bind(&MainThreadEventQueue::DispatchSingleEvent, this)); 471 FROM_HERE, base::Bind(&MainThreadEventQueue::DispatchEvents, this));
336 } 472 }
337 473
338 void MainThreadEventQueue::QueueEvent( 474 void MainThreadEventQueue::QueueEvent(
339 std::unique_ptr<EventWithDispatchType> event) { 475 std::unique_ptr<MainThreadEventQueueTask> event) {
340 bool is_raf_aligned = IsRafAlignedEvent(event->event()); 476 bool is_raf_aligned = IsRafAlignedEvent(event);
341 size_t send_notification_count = 0;
342 bool needs_main_frame = false; 477 bool needs_main_frame = false;
478 bool needs_post_task = false;
343 { 479 {
344 base::AutoLock lock(shared_state_lock_); 480 base::AutoLock lock(shared_state_lock_);
345 size_t size_before = shared_state_.events_.size(); 481 size_t size_before = shared_state_.events_.size();
346
347 // Stash if the tail of the queue was rAF aligned.
348 bool was_raf_aligned = false;
349 if (size_before > 0) {
350 was_raf_aligned =
351 IsRafAlignedEvent(shared_state_.events_.at(size_before - 1)->event());
352 }
353 shared_state_.events_.Queue(std::move(event)); 482 shared_state_.events_.Queue(std::move(event));
354 size_t size_after = shared_state_.events_.size(); 483 size_t size_after = shared_state_.events_.size();
355 484
356 if (size_before != size_after) { 485 if (size_before != size_after) {
357 if (IsRafAlignedInputDisabled()) { 486 if (!is_raf_aligned) {
358 send_notification_count = 1; 487 needs_post_task = !shared_state_.sent_post_task_;
359 } else if (!is_raf_aligned) { 488 shared_state_.sent_post_task_ = true;
360 send_notification_count = 1;
361 // If we had just enqueued a non-rAF input event we will send a series
362 // of normal post messages to ensure they are all handled right away.
363 for (size_t pos = size_after - 1; pos >= 1; --pos) {
364 if (IsRafAlignedEvent(shared_state_.events_.at(pos - 1)->event()))
365 send_notification_count++;
366 else
367 break;
368 }
369 } else { 489 } else {
370 needs_main_frame = !shared_state_.sent_main_frame_request_; 490 needs_main_frame = !shared_state_.sent_main_frame_request_;
371 shared_state_.sent_main_frame_request_ = true; 491 shared_state_.sent_main_frame_request_ = true;
372 } 492 }
373 } else if (size_before > 0) {
374 // The event was coalesced. The queue size didn't change but
375 // the rAF alignment of the event may have and we need to schedule
376 // a notification.
377 bool is_coalesced_raf_aligned =
378 IsRafAlignedEvent(shared_state_.events_.at(size_before - 1)->event());
379 if (was_raf_aligned != is_coalesced_raf_aligned)
380 send_notification_count = 1;
381 } 493 }
382 } 494 }
383 495
384 for (size_t i = 0; i < send_notification_count; ++i) 496 if (needs_post_task)
385 SendEventNotificationToMainThread(); 497 PostTaskToMainThread();
386 if (needs_main_frame) 498 if (needs_main_frame)
387 client_->NeedsMainFrame(routing_id_); 499 client_->NeedsMainFrame(routing_id_);
388 } 500 }
389 501
390 bool MainThreadEventQueue::IsRafAlignedInputDisabled() { 502 bool MainThreadEventQueue::IsRafAlignedInputDisabled() const {
391 return !handle_raf_aligned_mouse_input_ && !handle_raf_aligned_touch_input_; 503 return !handle_raf_aligned_mouse_input_ && !handle_raf_aligned_touch_input_;
392 } 504 }
393 505
394 bool MainThreadEventQueue::IsRafAlignedEvent( 506 bool MainThreadEventQueue::IsRafAlignedEvent(
395 const blink::WebInputEvent& event) { 507 const std::unique_ptr<MainThreadEventQueueTask>& item) const {
396 switch (event.type()) { 508 if (!item->IsWebInputEvent())
509 return false;
510 const QueuedWebInputEvent* event =
511 static_cast<const QueuedWebInputEvent*>(item.get());
512 switch (event->event().type()) {
397 case blink::WebInputEvent::MouseMove: 513 case blink::WebInputEvent::MouseMove:
398 case blink::WebInputEvent::MouseWheel: 514 case blink::WebInputEvent::MouseWheel:
399 return handle_raf_aligned_mouse_input_; 515 return handle_raf_aligned_mouse_input_;
400 case blink::WebInputEvent::TouchMove: 516 case blink::WebInputEvent::TouchMove:
401 return handle_raf_aligned_touch_input_; 517 return handle_raf_aligned_touch_input_;
402 default: 518 default:
403 return false; 519 return false;
404 } 520 }
405 } 521 }
406 522
407 } // namespace content 523 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698