| 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/histogram_macros.h" | 7 #include "base/metrics/histogram_macros.h" |
| 8 #include "content/common/input/event_with_latency_info.h" | 8 #include "content/common/input/event_with_latency_info.h" |
| 9 #include "content/common/input_messages.h" | 9 #include "content/common/input_messages.h" |
| 10 | 10 |
| 11 namespace content { | 11 namespace content { |
| 12 | 12 |
| 13 namespace { | 13 namespace { |
| 14 | 14 |
| 15 const size_t kTenSeconds = 10 * 1000 * 1000; | 15 const size_t kTenSeconds = 10 * 1000 * 1000; |
| 16 | 16 |
| 17 bool isContinuousEvent(const std::unique_ptr<EventWithDispatchType>& event) { | 17 bool IsContinuousEvent(const std::unique_ptr<EventWithDispatchType>& event) { |
| 18 switch (event->event().type) { | 18 switch (event->event().type) { |
| 19 case blink::WebInputEvent::MouseMove: | 19 case blink::WebInputEvent::MouseMove: |
| 20 case blink::WebInputEvent::MouseWheel: | 20 case blink::WebInputEvent::MouseWheel: |
| 21 return true; | 21 return true; |
| 22 case blink::WebInputEvent::TouchMove: | 22 case blink::WebInputEvent::TouchMove: |
| 23 // TouchMoves that are blocking end up blocking scroll. Do not treat | 23 // TouchMoves that are blocking end up blocking scroll. Do not treat |
| 24 // them as continuous events otherwise we will end up waiting up to an | 24 // them as continuous events otherwise we will end up waiting up to an |
| 25 // additional frame. | 25 // additional frame. |
| 26 return static_cast<const blink::WebTouchEvent&>(event->event()) | 26 return static_cast<const blink::WebTouchEvent&>(event->event()) |
| 27 .dispatchType != blink::WebInputEvent::Blocking; | 27 .dispatchType != blink::WebInputEvent::Blocking; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 int routing_id, | 65 int routing_id, |
| 66 MainThreadEventQueueClient* client, | 66 MainThreadEventQueueClient* client, |
| 67 const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner, | 67 const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner, |
| 68 blink::scheduler::RendererScheduler* renderer_scheduler) | 68 blink::scheduler::RendererScheduler* renderer_scheduler) |
| 69 : routing_id_(routing_id), | 69 : routing_id_(routing_id), |
| 70 client_(client), | 70 client_(client), |
| 71 is_flinging_(false), | 71 is_flinging_(false), |
| 72 last_touch_start_forced_nonblocking_due_to_fling_(false), | 72 last_touch_start_forced_nonblocking_due_to_fling_(false), |
| 73 enable_fling_passive_listener_flag_(base::FeatureList::IsEnabled( | 73 enable_fling_passive_listener_flag_(base::FeatureList::IsEnabled( |
| 74 features::kPassiveEventListenersDueToFling)), | 74 features::kPassiveEventListenersDueToFling)), |
| 75 handle_raf_aligned_input_( | 75 handle_raf_aligned_touch_input_( |
| 76 base::FeatureList::IsEnabled(features::kRafAlignedInputEvents)), | 76 base::FeatureList::IsEnabled(features::kRafAlignedTouchInputEvents)), |
| 77 handle_raf_aligned_mouse_input_( |
| 78 base::FeatureList::IsEnabled(features::kRafAlignedMouseInputEvents)), |
| 77 main_task_runner_(main_task_runner), | 79 main_task_runner_(main_task_runner), |
| 78 renderer_scheduler_(renderer_scheduler) {} | 80 renderer_scheduler_(renderer_scheduler) {} |
| 79 | 81 |
| 80 MainThreadEventQueue::~MainThreadEventQueue() {} | 82 MainThreadEventQueue::~MainThreadEventQueue() {} |
| 81 | 83 |
| 82 bool MainThreadEventQueue::HandleEvent( | 84 bool MainThreadEventQueue::HandleEvent( |
| 83 ui::ScopedWebInputEvent event, | 85 ui::ScopedWebInputEvent event, |
| 84 const ui::LatencyInfo& latency, | 86 const ui::LatencyInfo& latency, |
| 85 InputEventDispatchType original_dispatch_type, | 87 InputEventDispatchType original_dispatch_type, |
| 86 InputEventAckState ack_result) { | 88 InputEventAckState ack_result) { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 136 | 138 |
| 137 // send an ack when we are non-blocking. | 139 // send an ack when we are non-blocking. |
| 138 return non_blocking; | 140 return non_blocking; |
| 139 } | 141 } |
| 140 | 142 |
| 141 void MainThreadEventQueue::DispatchInFlightEvent() { | 143 void MainThreadEventQueue::DispatchInFlightEvent() { |
| 142 if (in_flight_event_) { | 144 if (in_flight_event_) { |
| 143 // Report the coalesced count only for continuous events; otherwise | 145 // Report the coalesced count only for continuous events; otherwise |
| 144 // the zero value would be dominated by non-continuous events. | 146 // the zero value would be dominated by non-continuous events. |
| 145 base::TimeTicks now = base::TimeTicks::Now(); | 147 base::TimeTicks now = base::TimeTicks::Now(); |
| 146 if (isContinuousEvent(in_flight_event_)) { | 148 if (IsContinuousEvent(in_flight_event_)) { |
| 147 UMA_HISTOGRAM_CUSTOM_COUNTS( | 149 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 148 "Event.MainThreadEventQueue.Continuous.QueueingTime", | 150 "Event.MainThreadEventQueue.Continuous.QueueingTime", |
| 149 (now - in_flight_event_->creationTimestamp()).InMicroseconds(), 1, | 151 (now - in_flight_event_->creationTimestamp()).InMicroseconds(), 1, |
| 150 kTenSeconds, 50); | 152 kTenSeconds, 50); |
| 151 | 153 |
| 152 UMA_HISTOGRAM_CUSTOM_COUNTS( | 154 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 153 "Event.MainThreadEventQueue.Continuous.FreshnessTime", | 155 "Event.MainThreadEventQueue.Continuous.FreshnessTime", |
| 154 (now - in_flight_event_->lastCoalescedTimestamp()).InMicroseconds(), | 156 (now - in_flight_event_->lastCoalescedTimestamp()).InMicroseconds(), |
| 155 1, kTenSeconds, 50); | 157 1, kTenSeconds, 50); |
| 156 | 158 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 171 | 173 |
| 172 client_->HandleEventOnMainThread(routing_id_, &in_flight_event_->event(), | 174 client_->HandleEventOnMainThread(routing_id_, &in_flight_event_->event(), |
| 173 in_flight_event_->latencyInfo(), | 175 in_flight_event_->latencyInfo(), |
| 174 dispatch_type); | 176 dispatch_type); |
| 175 } | 177 } |
| 176 | 178 |
| 177 in_flight_event_.reset(); | 179 in_flight_event_.reset(); |
| 178 } | 180 } |
| 179 | 181 |
| 180 void MainThreadEventQueue::PossiblyScheduleMainFrame() { | 182 void MainThreadEventQueue::PossiblyScheduleMainFrame() { |
| 181 if (!handle_raf_aligned_input_) | 183 if (IsRafAlignedInputDisabled()) |
| 182 return; | 184 return; |
| 183 bool needs_main_frame = false; | 185 bool needs_main_frame = false; |
| 184 { | 186 { |
| 185 base::AutoLock lock(shared_state_lock_); | 187 base::AutoLock lock(shared_state_lock_); |
| 186 if (!shared_state_.sent_main_frame_request_ && | 188 if (!shared_state_.sent_main_frame_request_ && |
| 187 !shared_state_.events_.empty() && | 189 !shared_state_.events_.empty() && |
| 188 isContinuousEvent(shared_state_.events_.front())) { | 190 IsRafAlignedEvent(shared_state_.events_.front())) { |
| 189 needs_main_frame = !shared_state_.sent_main_frame_request_; | 191 needs_main_frame = !shared_state_.sent_main_frame_request_; |
| 190 shared_state_.sent_main_frame_request_ = false; | 192 shared_state_.sent_main_frame_request_ = false; |
| 191 } | 193 } |
| 192 } | 194 } |
| 193 if (needs_main_frame) | 195 if (needs_main_frame) |
| 194 client_->NeedsMainFrame(routing_id_); | 196 client_->NeedsMainFrame(routing_id_); |
| 195 } | 197 } |
| 196 | 198 |
| 197 void MainThreadEventQueue::DispatchSingleEvent() { | 199 void MainThreadEventQueue::DispatchSingleEvent() { |
| 198 { | 200 { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 214 client_->SendInputEventAck(routing_id_, type, ack_result, id); | 216 client_->SendInputEventAck(routing_id_, type, ack_result, id); |
| 215 if (renderer_scheduler_) { | 217 if (renderer_scheduler_) { |
| 216 renderer_scheduler_->DidHandleInputEventOnMainThread( | 218 renderer_scheduler_->DidHandleInputEventOnMainThread( |
| 217 in_flight_event_->event()); | 219 in_flight_event_->event()); |
| 218 } | 220 } |
| 219 } | 221 } |
| 220 } | 222 } |
| 221 } | 223 } |
| 222 | 224 |
| 223 void MainThreadEventQueue::DispatchRafAlignedInput() { | 225 void MainThreadEventQueue::DispatchRafAlignedInput() { |
| 224 if (!handle_raf_aligned_input_) | 226 if (IsRafAlignedInputDisabled()) |
| 225 return; | 227 return; |
| 226 | 228 |
| 227 std::deque<std::unique_ptr<EventWithDispatchType>> events_to_process; | 229 std::deque<std::unique_ptr<EventWithDispatchType>> events_to_process; |
| 228 { | 230 { |
| 229 base::AutoLock lock(shared_state_lock_); | 231 base::AutoLock lock(shared_state_lock_); |
| 230 shared_state_.sent_main_frame_request_ = false; | 232 shared_state_.sent_main_frame_request_ = false; |
| 231 | 233 |
| 232 while(!shared_state_.events_.empty()) { | 234 while(!shared_state_.events_.empty()) { |
| 233 if (!isContinuousEvent(shared_state_.events_.front())) | 235 if (!IsRafAlignedEvent(shared_state_.events_.front())) |
| 234 break; | 236 break; |
| 235 events_to_process.emplace_back(shared_state_.events_.Pop()); | 237 events_to_process.emplace_back(shared_state_.events_.Pop()); |
| 236 } | 238 } |
| 237 } | 239 } |
| 238 | 240 |
| 239 while(!events_to_process.empty()) { | 241 while(!events_to_process.empty()) { |
| 240 in_flight_event_ = std::move(events_to_process.front()); | 242 in_flight_event_ = std::move(events_to_process.front()); |
| 241 events_to_process.pop_front(); | 243 events_to_process.pop_front(); |
| 242 DispatchInFlightEvent(); | 244 DispatchInFlightEvent(); |
| 243 } | 245 } |
| 244 PossiblyScheduleMainFrame(); | 246 PossiblyScheduleMainFrame(); |
| 245 } | 247 } |
| 246 | 248 |
| 247 void MainThreadEventQueue::SendEventNotificationToMainThread() { | 249 void MainThreadEventQueue::SendEventNotificationToMainThread() { |
| 248 main_task_runner_->PostTask( | 250 main_task_runner_->PostTask( |
| 249 FROM_HERE, base::Bind(&MainThreadEventQueue::DispatchSingleEvent, this)); | 251 FROM_HERE, base::Bind(&MainThreadEventQueue::DispatchSingleEvent, this)); |
| 250 } | 252 } |
| 251 | 253 |
| 252 void MainThreadEventQueue::QueueEvent( | 254 void MainThreadEventQueue::QueueEvent( |
| 253 std::unique_ptr<EventWithDispatchType> event) { | 255 std::unique_ptr<EventWithDispatchType> event) { |
| 254 bool is_continuous = isContinuousEvent(event); | 256 bool is_raf_aligned = IsRafAlignedEvent(event); |
| 255 size_t send_notification_count = 0; | 257 size_t send_notification_count = 0; |
| 256 bool needs_main_frame = false; | 258 bool needs_main_frame = false; |
| 257 { | 259 { |
| 258 base::AutoLock lock(shared_state_lock_); | 260 base::AutoLock lock(shared_state_lock_); |
| 259 size_t size_before = shared_state_.events_.size(); | 261 size_t size_before = shared_state_.events_.size(); |
| 260 shared_state_.events_.Queue(std::move(event)); | 262 shared_state_.events_.Queue(std::move(event)); |
| 261 size_t size_after = shared_state_.events_.size(); | 263 size_t size_after = shared_state_.events_.size(); |
| 264 |
| 262 if (size_before != size_after) { | 265 if (size_before != size_after) { |
| 263 if (!handle_raf_aligned_input_) { | 266 if (IsRafAlignedInputDisabled()) { |
| 264 send_notification_count = 1; | 267 send_notification_count = 1; |
| 265 } else if (!is_continuous) { | 268 } else if (!is_raf_aligned) { |
| 266 send_notification_count = 1; | 269 send_notification_count = 1; |
| 267 // If we had just enqueued a non-rAF input event we will send a series | 270 // If we had just enqueued a non-rAF input event we will send a series |
| 268 // of normal post messages to ensure they are all handled right away. | 271 // of normal post messages to ensure they are all handled right away. |
| 269 for (size_t pos = size_after - 1; pos >= 1; --pos) { | 272 for (size_t pos = size_after - 1; pos >= 1; --pos) { |
| 270 if (isContinuousEvent(shared_state_.events_.at(pos - 1))) | 273 if (IsRafAlignedEvent(shared_state_.events_.at(pos - 1))) |
| 271 send_notification_count++; | 274 send_notification_count++; |
| 272 else | 275 else |
| 273 break; | 276 break; |
| 274 } | 277 } |
| 275 } else { | 278 } else { |
| 276 needs_main_frame = !shared_state_.sent_main_frame_request_; | 279 needs_main_frame = !shared_state_.sent_main_frame_request_; |
| 277 shared_state_.sent_main_frame_request_ = true; | 280 shared_state_.sent_main_frame_request_ = true; |
| 278 } | 281 } |
| 279 } | 282 } |
| 280 } | 283 } |
| 281 for (size_t i = 0; i < send_notification_count; ++i) | 284 for (size_t i = 0; i < send_notification_count; ++i) |
| 282 SendEventNotificationToMainThread(); | 285 SendEventNotificationToMainThread(); |
| 283 if (needs_main_frame) | 286 if (needs_main_frame) |
| 284 client_->NeedsMainFrame(routing_id_); | 287 client_->NeedsMainFrame(routing_id_); |
| 285 } | 288 } |
| 286 | 289 |
| 290 bool MainThreadEventQueue::IsRafAlignedInputDisabled() { |
| 291 return !handle_raf_aligned_mouse_input_ && !handle_raf_aligned_touch_input_; |
| 292 } |
| 293 |
| 294 bool MainThreadEventQueue::IsRafAlignedEvent( |
| 295 const std::unique_ptr<EventWithDispatchType>& event) { |
| 296 switch (event->event().type) { |
| 297 case blink::WebInputEvent::MouseMove: |
| 298 case blink::WebInputEvent::MouseWheel: |
| 299 return handle_raf_aligned_mouse_input_; |
| 300 case blink::WebInputEvent::TouchMove: |
| 301 // TouchMoves that are blocking end up blocking scroll. Do not treat |
| 302 // them as continuous events otherwise we will end up waiting up to an |
| 303 // additional frame. |
| 304 return static_cast<const blink::WebTouchEvent&>(event->event()) |
| 305 .dispatchType != blink::WebInputEvent::Blocking && |
| 306 handle_raf_aligned_touch_input_; |
| 307 default: |
| 308 return false; |
| 309 } |
| 310 } |
| 311 |
| 287 } // namespace content | 312 } // namespace content |
| OLD | NEW |