| OLD | NEW |
| 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 #include "content/renderer/render_widget.h" |
| 12 | 13 |
| 13 namespace content { | 14 namespace content { |
| 14 | 15 |
| 15 namespace { | 16 namespace { |
| 16 | 17 |
| 17 const size_t kTenSeconds = 10 * 1000 * 1000; | 18 const size_t kTenSeconds = 10 * 1000 * 1000; |
| 18 | 19 |
| 19 class QueuedClosure : public MainThreadEventQueueTask { | 20 class QueuedClosure : public MainThreadEventQueueTask { |
| 20 public: | 21 public: |
| 21 QueuedClosure(const base::Closure& closure) : closure_(closure) {} | 22 QueuedClosure(const base::Closure& closure) : closure_(closure) {} |
| 22 | 23 |
| 23 ~QueuedClosure() override {} | 24 ~QueuedClosure() override {} |
| 24 | 25 |
| 25 FilterResult FilterNewEvent( | 26 FilterResult FilterNewEvent( |
| 26 const MainThreadEventQueueTask& other_task) override { | 27 const MainThreadEventQueueTask& other_task) override { |
| 27 return other_task.IsWebInputEvent() ? FilterResult::KeepIterating | 28 return other_task.IsWebInputEvent() ? FilterResult::KeepIterating |
| 28 : FilterResult::StopIterating; | 29 : FilterResult::StopIterating; |
| 29 } | 30 } |
| 30 | 31 |
| 31 bool IsWebInputEvent() const override { return false; } | 32 bool IsWebInputEvent() const override { return false; } |
| 32 | 33 |
| 33 void Dispatch(int routing_id, MainThreadEventQueueClient*) override { | 34 void Dispatch(MainThreadEventQueue*) override { closure_.Run(); } |
| 34 closure_.Run(); | |
| 35 } | |
| 36 | |
| 37 void EventHandled(int routing_id, | |
| 38 blink::scheduler::RendererScheduler* renderer_scheduler, | |
| 39 MainThreadEventQueueClient* client, | |
| 40 blink::WebInputEvent::Type type, | |
| 41 blink::WebInputEventResult result, | |
| 42 InputEventAckState ack_result) override {} | |
| 43 | 35 |
| 44 private: | 36 private: |
| 45 base::Closure closure_; | 37 base::Closure closure_; |
| 46 }; | 38 }; |
| 47 | 39 |
| 48 class QueuedWebInputEvent : public ScopedWebInputEventWithLatencyInfo, | 40 class QueuedWebInputEvent : public ScopedWebInputEventWithLatencyInfo, |
| 49 public MainThreadEventQueueTask { | 41 public MainThreadEventQueueTask { |
| 50 public: | 42 public: |
| 51 QueuedWebInputEvent(ui::WebScopedInputEvent event, | 43 QueuedWebInputEvent(ui::WebScopedInputEvent event, |
| 52 const ui::LatencyInfo& latency, | 44 const ui::LatencyInfo& latency, |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 | 84 |
| 93 // The newest event (|other_item|) always wins when updating fields. | 85 // The newest event (|other_item|) always wins when updating fields. |
| 94 dispatch_type_ = other_event.dispatch_type_; | 86 dispatch_type_ = other_event.dispatch_type_; |
| 95 originally_cancelable_ = other_event.originally_cancelable_; | 87 originally_cancelable_ = other_event.originally_cancelable_; |
| 96 | 88 |
| 97 return FilterResult::CoalescedEvent; | 89 return FilterResult::CoalescedEvent; |
| 98 } | 90 } |
| 99 | 91 |
| 100 bool IsWebInputEvent() const override { return true; } | 92 bool IsWebInputEvent() const override { return true; } |
| 101 | 93 |
| 102 void Dispatch(int routing_id, MainThreadEventQueueClient* client) override { | 94 void Dispatch(MainThreadEventQueue* queue) override { |
| 103 // Report the coalesced count only for continuous events; otherwise | 95 // Report the coalesced count only for continuous events; otherwise |
| 104 // the zero value would be dominated by non-continuous events. | 96 // the zero value would be dominated by non-continuous events. |
| 105 base::TimeTicks now = base::TimeTicks::Now(); | 97 base::TimeTicks now = base::TimeTicks::Now(); |
| 106 if (IsContinuousEvent()) { | 98 if (IsContinuousEvent()) { |
| 107 UMA_HISTOGRAM_CUSTOM_COUNTS( | 99 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 108 "Event.MainThreadEventQueue.Continuous.QueueingTime", | 100 "Event.MainThreadEventQueue.Continuous.QueueingTime", |
| 109 (now - creationTimestamp()).InMicroseconds(), 1, kTenSeconds, 50); | 101 (now - creationTimestamp()).InMicroseconds(), 1, kTenSeconds, 50); |
| 110 | 102 |
| 111 UMA_HISTOGRAM_CUSTOM_COUNTS( | 103 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 112 "Event.MainThreadEventQueue.Continuous.FreshnessTime", | 104 "Event.MainThreadEventQueue.Continuous.FreshnessTime", |
| 113 (now - lastCoalescedTimestamp()).InMicroseconds(), 1, kTenSeconds, | 105 (now - lastCoalescedTimestamp()).InMicroseconds(), 1, kTenSeconds, |
| 114 50); | 106 50); |
| 115 | 107 |
| 116 UMA_HISTOGRAM_COUNTS_1000("Event.MainThreadEventQueue.CoalescedCount", | 108 UMA_HISTOGRAM_COUNTS_1000("Event.MainThreadEventQueue.CoalescedCount", |
| 117 coalescedCount()); | 109 coalescedCount()); |
| 118 } else { | 110 } else { |
| 119 UMA_HISTOGRAM_CUSTOM_COUNTS( | 111 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 120 "Event.MainThreadEventQueue.NonContinuous.QueueingTime", | 112 "Event.MainThreadEventQueue.NonContinuous.QueueingTime", |
| 121 (now - creationTimestamp()).InMicroseconds(), 1, kTenSeconds, 50); | 113 (now - creationTimestamp()).InMicroseconds(), 1, kTenSeconds, 50); |
| 122 } | 114 } |
| 123 | 115 |
| 124 InputEventDispatchType dispatch_type = dispatchType(); | 116 InputEventAckState ack_result = queue->HandleEventOnMainThread( |
| 125 if (!blockingCoalescedEventIds().empty()) { | 117 coalesced_event(), latencyInfo(), dispatchType()); |
| 126 switch (dispatch_type) { | |
| 127 case DISPATCH_TYPE_BLOCKING: | |
| 128 dispatch_type = DISPATCH_TYPE_BLOCKING_NOTIFY_MAIN; | |
| 129 break; | |
| 130 case DISPATCH_TYPE_NON_BLOCKING: | |
| 131 dispatch_type = DISPATCH_TYPE_NON_BLOCKING_NOTIFY_MAIN; | |
| 132 break; | |
| 133 default: | |
| 134 NOTREACHED(); | |
| 135 } | |
| 136 } | |
| 137 client->HandleEventOnMainThread(routing_id, &coalesced_event(), | |
| 138 latencyInfo(), dispatch_type); | |
| 139 } | |
| 140 | |
| 141 void EventHandled(int routing_id, | |
| 142 blink::scheduler::RendererScheduler* renderer_scheduler, | |
| 143 MainThreadEventQueueClient* client, | |
| 144 blink::WebInputEvent::Type type, | |
| 145 blink::WebInputEventResult result, | |
| 146 InputEventAckState ack_result) override { | |
| 147 for (const auto id : blockingCoalescedEventIds()) { | 118 for (const auto id : blockingCoalescedEventIds()) { |
| 148 client->SendInputEventAck(routing_id, type, ack_result, id); | 119 queue->SendInputEventAck(event().GetType(), ack_result, id); |
| 149 if (renderer_scheduler) { | 120 queue->NotifySchedulerOfEventHandled(event(), ack_result); |
| 150 renderer_scheduler->DidHandleInputEventOnMainThread(event(), result); | |
| 151 } | |
| 152 } | 121 } |
| 153 } | 122 } |
| 154 | 123 |
| 155 bool originallyCancelable() const { return originally_cancelable_; } | 124 bool originallyCancelable() const { return originally_cancelable_; } |
| 156 | 125 |
| 157 private: | 126 private: |
| 158 FilterResult HandleTouchScrollStartQueued() { | 127 FilterResult HandleTouchScrollStartQueued() { |
| 159 // A TouchScrollStart will queued after this touch move which will make all | 128 // A TouchScrollStart will queued after this touch move which will make all |
| 160 // previous touch moves that are queued uncancelable. | 129 // previous touch moves that are queued uncancelable. |
| 161 switch (event().GetType()) { | 130 switch (event().GetType()) { |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 } | 207 } |
| 239 | 208 |
| 240 } // namespace | 209 } // namespace |
| 241 | 210 |
| 242 MainThreadEventQueue::SharedState::SharedState() | 211 MainThreadEventQueue::SharedState::SharedState() |
| 243 : sent_main_frame_request_(false), sent_post_task_(false) {} | 212 : sent_main_frame_request_(false), sent_post_task_(false) {} |
| 244 | 213 |
| 245 MainThreadEventQueue::SharedState::~SharedState() {} | 214 MainThreadEventQueue::SharedState::~SharedState() {} |
| 246 | 215 |
| 247 MainThreadEventQueue::MainThreadEventQueue( | 216 MainThreadEventQueue::MainThreadEventQueue( |
| 248 int routing_id, | |
| 249 MainThreadEventQueueClient* client, | |
| 250 const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner, | 217 const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner, |
| 251 blink::scheduler::RendererScheduler* renderer_scheduler) | 218 blink::scheduler::RendererScheduler* renderer_scheduler) |
| 252 : routing_id_(routing_id), | 219 : last_touch_start_forced_nonblocking_due_to_fling_(false), |
| 253 client_(client), | |
| 254 last_touch_start_forced_nonblocking_due_to_fling_(false), | |
| 255 enable_fling_passive_listener_flag_(base::FeatureList::IsEnabled( | 220 enable_fling_passive_listener_flag_(base::FeatureList::IsEnabled( |
| 256 features::kPassiveEventListenersDueToFling)), | 221 features::kPassiveEventListenersDueToFling)), |
| 257 enable_non_blocking_due_to_main_thread_responsiveness_flag_( | 222 enable_non_blocking_due_to_main_thread_responsiveness_flag_( |
| 258 base::FeatureList::IsEnabled( | 223 base::FeatureList::IsEnabled( |
| 259 features::kMainThreadBusyScrollIntervention)), | 224 features::kMainThreadBusyScrollIntervention)), |
| 260 handle_raf_aligned_touch_input_( | 225 handle_raf_aligned_touch_input_( |
| 261 base::FeatureList::IsEnabled(features::kRafAlignedTouchInputEvents)), | 226 base::FeatureList::IsEnabled(features::kRafAlignedTouchInputEvents)), |
| 262 handle_raf_aligned_mouse_input_( | 227 handle_raf_aligned_mouse_input_( |
| 263 base::FeatureList::IsEnabled(features::kRafAlignedMouseInputEvents)), | 228 base::FeatureList::IsEnabled(features::kRafAlignedMouseInputEvents)), |
| 264 main_task_runner_(main_task_runner), | 229 main_task_runner_(main_task_runner), |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 384 needs_post_task = !shared_state_.sent_post_task_; | 349 needs_post_task = !shared_state_.sent_post_task_; |
| 385 shared_state_.sent_post_task_ = true; | 350 shared_state_.sent_post_task_ = true; |
| 386 } | 351 } |
| 387 | 352 |
| 388 if (needs_post_task) | 353 if (needs_post_task) |
| 389 PostTaskToMainThread(); | 354 PostTaskToMainThread(); |
| 390 } | 355 } |
| 391 | 356 |
| 392 void MainThreadEventQueue::DispatchInFlightEvent() { | 357 void MainThreadEventQueue::DispatchInFlightEvent() { |
| 393 if (in_flight_event_) { | 358 if (in_flight_event_) { |
| 394 in_flight_event_->Dispatch(routing_id_, client_); | 359 in_flight_event_->Dispatch(this); |
| 395 in_flight_event_.reset(); | 360 in_flight_event_.reset(); |
| 396 } | 361 } |
| 397 } | 362 } |
| 398 | 363 |
| 399 void MainThreadEventQueue::PossiblyScheduleMainFrame() { | 364 void MainThreadEventQueue::PossiblyScheduleMainFrame() { |
| 400 if (IsRafAlignedInputDisabled()) | 365 if (IsRafAlignedInputDisabled()) |
| 401 return; | 366 return; |
| 402 bool needs_main_frame = false; | 367 bool needs_main_frame = false; |
| 403 { | 368 { |
| 404 base::AutoLock lock(shared_state_lock_); | 369 base::AutoLock lock(shared_state_lock_); |
| 405 if (!shared_state_.sent_main_frame_request_ && | 370 if (!shared_state_.sent_main_frame_request_ && |
| 406 !shared_state_.events_.empty() && | 371 !shared_state_.events_.empty() && |
| 407 IsRafAlignedEvent(shared_state_.events_.front())) { | 372 IsRafAlignedEvent(shared_state_.events_.front())) { |
| 408 needs_main_frame = true; | 373 needs_main_frame = true; |
| 409 shared_state_.sent_main_frame_request_ = true; | 374 shared_state_.sent_main_frame_request_ = true; |
| 410 } | 375 } |
| 411 } | 376 } |
| 412 if (needs_main_frame) | 377 if (needs_main_frame) |
| 413 client_->NeedsMainFrame(routing_id_); | 378 NeedsMainFrame(); |
| 414 } | 379 } |
| 415 | 380 |
| 416 void MainThreadEventQueue::DispatchEvents() { | 381 void MainThreadEventQueue::DispatchEvents() { |
| 417 size_t events_to_process; | 382 size_t events_to_process; |
| 418 | 383 |
| 419 // Record the queue size so that we only process | 384 // Record the queue size so that we only process |
| 420 // that maximum number of events. | 385 // that maximum number of events. |
| 421 { | 386 { |
| 422 base::AutoLock lock(shared_state_lock_); | 387 base::AutoLock lock(shared_state_lock_); |
| 423 shared_state_.sent_post_task_ = false; | 388 shared_state_.sent_post_task_ = false; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 437 return; | 402 return; |
| 438 in_flight_event_ = shared_state_.events_.Pop(); | 403 in_flight_event_ = shared_state_.events_.Pop(); |
| 439 } | 404 } |
| 440 | 405 |
| 441 // Dispatching the event is outside of critical section. | 406 // Dispatching the event is outside of critical section. |
| 442 DispatchInFlightEvent(); | 407 DispatchInFlightEvent(); |
| 443 } | 408 } |
| 444 PossiblyScheduleMainFrame(); | 409 PossiblyScheduleMainFrame(); |
| 445 } | 410 } |
| 446 | 411 |
| 447 void MainThreadEventQueue::EventHandled(blink::WebInputEvent::Type type, | |
| 448 blink::WebInputEventResult result, | |
| 449 InputEventAckState ack_result) { | |
| 450 if (in_flight_event_) { | |
| 451 in_flight_event_->EventHandled(routing_id_, renderer_scheduler_, client_, | |
| 452 type, result, ack_result); | |
| 453 } | |
| 454 } | |
| 455 | |
| 456 void MainThreadEventQueue::DispatchRafAlignedInput(base::TimeTicks frame_time) { | 412 void MainThreadEventQueue::DispatchRafAlignedInput(base::TimeTicks frame_time) { |
| 457 if (IsRafAlignedInputDisabled()) | 413 if (IsRafAlignedInputDisabled()) |
| 458 return; | 414 return; |
| 459 | 415 |
| 460 size_t queue_size_at_start; | 416 size_t queue_size_at_start; |
| 461 | 417 |
| 462 // Record the queue size so that we only process | 418 // Record the queue size so that we only process |
| 463 // that maximum number of events. | 419 // that maximum number of events. |
| 464 { | 420 { |
| 465 base::AutoLock lock(shared_state_lock_); | 421 base::AutoLock lock(shared_state_lock_); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 519 } else { | 475 } else { |
| 520 needs_main_frame = !shared_state_.sent_main_frame_request_; | 476 needs_main_frame = !shared_state_.sent_main_frame_request_; |
| 521 shared_state_.sent_main_frame_request_ = true; | 477 shared_state_.sent_main_frame_request_ = true; |
| 522 } | 478 } |
| 523 } | 479 } |
| 524 } | 480 } |
| 525 | 481 |
| 526 if (needs_post_task) | 482 if (needs_post_task) |
| 527 PostTaskToMainThread(); | 483 PostTaskToMainThread(); |
| 528 if (needs_main_frame) | 484 if (needs_main_frame) |
| 529 client_->NeedsMainFrame(routing_id_); | 485 NeedsMainFrame(); |
| 530 } | 486 } |
| 531 | 487 |
| 532 bool MainThreadEventQueue::IsRafAlignedInputDisabled() const { | 488 bool MainThreadEventQueue::IsRafAlignedInputDisabled() const { |
| 533 return !handle_raf_aligned_mouse_input_ && !handle_raf_aligned_touch_input_; | 489 return !handle_raf_aligned_mouse_input_ && !handle_raf_aligned_touch_input_; |
| 534 } | 490 } |
| 535 | 491 |
| 536 bool MainThreadEventQueue::IsRafAlignedEvent( | 492 bool MainThreadEventQueue::IsRafAlignedEvent( |
| 537 const std::unique_ptr<MainThreadEventQueueTask>& item) const { | 493 const std::unique_ptr<MainThreadEventQueueTask>& item) const { |
| 538 if (!item->IsWebInputEvent()) | 494 if (!item->IsWebInputEvent()) |
| 539 return false; | 495 return false; |
| 540 const QueuedWebInputEvent* event = | 496 const QueuedWebInputEvent* event = |
| 541 static_cast<const QueuedWebInputEvent*>(item.get()); | 497 static_cast<const QueuedWebInputEvent*>(item.get()); |
| 542 switch (event->event().GetType()) { | 498 switch (event->event().GetType()) { |
| 543 case blink::WebInputEvent::kMouseMove: | 499 case blink::WebInputEvent::kMouseMove: |
| 544 case blink::WebInputEvent::kMouseWheel: | 500 case blink::WebInputEvent::kMouseWheel: |
| 545 return handle_raf_aligned_mouse_input_; | 501 return handle_raf_aligned_mouse_input_; |
| 546 case blink::WebInputEvent::kTouchMove: | 502 case blink::WebInputEvent::kTouchMove: |
| 547 return handle_raf_aligned_touch_input_; | 503 return handle_raf_aligned_touch_input_; |
| 548 default: | 504 default: |
| 549 return false; | 505 return false; |
| 550 } | 506 } |
| 551 } | 507 } |
| 552 | 508 |
| 509 void MainThreadEventQueue::NotifySchedulerOfEventHandled( |
| 510 const blink::WebInputEvent& event, |
| 511 InputEventAckState ack_result) { |
| 512 if (renderer_scheduler_) { |
| 513 renderer_scheduler_->DidHandleInputEventOnMainThread( |
| 514 event, ack_result == INPUT_EVENT_ACK_STATE_CONSUMED |
| 515 ? blink::WebInputEventResult::kHandledApplication |
| 516 : blink::WebInputEventResult::kNotHandled); |
| 517 } |
| 518 } |
| 519 |
| 520 MainThreadEventQueueWithRenderWidget::MainThreadEventQueueWithRenderWidget( |
| 521 const base::WeakPtr<RenderWidget>& widget, |
| 522 blink::scheduler::RendererScheduler* renderer_scheduler) |
| 523 : MainThreadEventQueue(renderer_scheduler->CompositorTaskRunner(), |
| 524 renderer_scheduler), |
| 525 widget_(widget) {} |
| 526 |
| 527 MainThreadEventQueueWithRenderWidget::~MainThreadEventQueueWithRenderWidget() {} |
| 528 |
| 529 InputEventAckState |
| 530 MainThreadEventQueueWithRenderWidget::HandleEventOnMainThread( |
| 531 const blink::WebCoalescedInputEvent& event, |
| 532 const ui::LatencyInfo& latency, |
| 533 InputEventDispatchType dispatch_type) { |
| 534 if (widget_) |
| 535 return widget_->HandleInputEvent(event, latency, dispatch_type); |
| 536 return INPUT_EVENT_ACK_STATE_NOT_CONSUMED; |
| 537 } |
| 538 |
| 539 void MainThreadEventQueueWithRenderWidget::SendInputEventAck( |
| 540 blink::WebInputEvent::Type type, |
| 541 InputEventAckState ack_result, |
| 542 uint32_t touch_event_id) { |
| 543 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 544 if (!widget_) |
| 545 return; |
| 546 InputEventAck ack(InputEventAckSource::MAIN_THREAD, type, ack_result, |
| 547 touch_event_id); |
| 548 widget_->Send(new InputHostMsg_HandleInputEvent_ACK(MSG_ROUTING_NONE, ack)); |
| 549 } |
| 550 |
| 551 void MainThreadEventQueueWithRenderWidget::NeedsMainFrame() { |
| 552 if (main_task_runner_->BelongsToCurrentThread()) { |
| 553 if (widget_) |
| 554 widget_->SetNeedsMainFrame(); |
| 555 return; |
| 556 } |
| 557 |
| 558 main_task_runner_->PostTask( |
| 559 FROM_HERE, |
| 560 base::Bind(&MainThreadEventQueueWithRenderWidget::NeedsMainFrame, this)); |
| 561 } |
| 562 |
| 553 } // namespace content | 563 } // namespace content |
| OLD | NEW |