| 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 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 } | 31 } |
| 32 | 32 |
| 33 } // namespace | 33 } // namespace |
| 34 | 34 |
| 35 EventWithDispatchType::EventWithDispatchType( | 35 EventWithDispatchType::EventWithDispatchType( |
| 36 ui::ScopedWebInputEvent event, | 36 ui::ScopedWebInputEvent event, |
| 37 const ui::LatencyInfo& latency, | 37 const ui::LatencyInfo& latency, |
| 38 InputEventDispatchType dispatch_type) | 38 InputEventDispatchType dispatch_type) |
| 39 : ScopedWebInputEventWithLatencyInfo(std::move(event), latency), | 39 : ScopedWebInputEventWithLatencyInfo(std::move(event), latency), |
| 40 dispatch_type_(dispatch_type), | 40 dispatch_type_(dispatch_type), |
| 41 non_blocking_coalesced_count_(0), |
| 41 creation_timestamp_(base::TimeTicks::Now()), | 42 creation_timestamp_(base::TimeTicks::Now()), |
| 42 last_coalesced_timestamp_(creation_timestamp_) {} | 43 last_coalesced_timestamp_(creation_timestamp_) {} |
| 43 | 44 |
| 44 EventWithDispatchType::~EventWithDispatchType() {} | 45 EventWithDispatchType::~EventWithDispatchType() {} |
| 45 | 46 |
| 46 bool EventWithDispatchType::CanCoalesceWith( | |
| 47 const EventWithDispatchType& other) const { | |
| 48 return other.dispatch_type_ == dispatch_type_ && | |
| 49 ScopedWebInputEventWithLatencyInfo::CanCoalesceWith(other); | |
| 50 } | |
| 51 | |
| 52 void EventWithDispatchType::CoalesceWith(const EventWithDispatchType& other) { | 47 void EventWithDispatchType::CoalesceWith(const EventWithDispatchType& other) { |
| 53 coalesced_event_ids_.push_back( | 48 if (other.dispatch_type_ == DISPATCH_TYPE_BLOCKING) { |
| 54 ui::WebInputEventTraits::GetUniqueTouchEventId(other.event())); | 49 blocking_coalesced_event_ids_.push_back( |
| 50 ui::WebInputEventTraits::GetUniqueTouchEventId(other.event())); |
| 51 } else { |
| 52 non_blocking_coalesced_count_++; |
| 53 } |
| 55 ScopedWebInputEventWithLatencyInfo::CoalesceWith(other); | 54 ScopedWebInputEventWithLatencyInfo::CoalesceWith(other); |
| 56 last_coalesced_timestamp_ = base::TimeTicks::Now(); | 55 last_coalesced_timestamp_ = base::TimeTicks::Now(); |
| 57 } | 56 } |
| 58 | 57 |
| 59 MainThreadEventQueue::SharedState::SharedState() | 58 MainThreadEventQueue::SharedState::SharedState() |
| 60 : sent_main_frame_request_(false) {} | 59 : sent_main_frame_request_(false) {} |
| 61 | 60 |
| 62 MainThreadEventQueue::SharedState::~SharedState() {} | 61 MainThreadEventQueue::SharedState::~SharedState() {} |
| 63 | 62 |
| 64 MainThreadEventQueue::MainThreadEventQueue( | 63 MainThreadEventQueue::MainThreadEventQueue( |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 115 // If the touch start is forced to be passive due to fling, its following | 114 // If the touch start is forced to be passive due to fling, its following |
| 116 // touch move should also be passive. | 115 // touch move should also be passive. |
| 117 if (ack_result == INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING_DUE_TO_FLING || | 116 if (ack_result == INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING_DUE_TO_FLING || |
| 118 last_touch_start_forced_nonblocking_due_to_fling_) { | 117 last_touch_start_forced_nonblocking_due_to_fling_) { |
| 119 touch_event->dispatchType = | 118 touch_event->dispatchType = |
| 120 blink::WebInputEvent::ListenersForcedNonBlockingDueToFling; | 119 blink::WebInputEvent::ListenersForcedNonBlockingDueToFling; |
| 121 non_blocking = true; | 120 non_blocking = true; |
| 122 last_touch_start_forced_nonblocking_due_to_fling_ = true; | 121 last_touch_start_forced_nonblocking_due_to_fling_ = true; |
| 123 } | 122 } |
| 124 } | 123 } |
| 124 // If handling rAF aligned touch input ACK non-cancelable events right |
| 125 // away. |
| 126 if (!non_blocking && IsRafAlignedEvent(*touch_event)) |
| 127 non_blocking = true; |
| 125 } | 128 } |
| 126 if (is_wheel && non_blocking) { | 129 if (is_wheel && non_blocking) { |
| 127 // Adjust the |dispatchType| on the event since the compositor | 130 // Adjust the |dispatchType| on the event since the compositor |
| 128 // determined all event listeners are passive. | 131 // determined all event listeners are passive. |
| 129 static_cast<blink::WebMouseWheelEvent*>(event.get()) | 132 static_cast<blink::WebMouseWheelEvent*>(event.get()) |
| 130 ->dispatchType = blink::WebInputEvent::ListenersNonBlockingPassive; | 133 ->dispatchType = blink::WebInputEvent::ListenersNonBlockingPassive; |
| 131 } | 134 } |
| 132 | 135 |
| 133 InputEventDispatchType dispatch_type = | 136 InputEventDispatchType dispatch_type = |
| 134 non_blocking ? DISPATCH_TYPE_NON_BLOCKING : DISPATCH_TYPE_BLOCKING; | 137 non_blocking ? DISPATCH_TYPE_NON_BLOCKING : DISPATCH_TYPE_BLOCKING; |
| 138 |
| 135 std::unique_ptr<EventWithDispatchType> event_with_dispatch_type( | 139 std::unique_ptr<EventWithDispatchType> event_with_dispatch_type( |
| 136 new EventWithDispatchType(std::move(event), latency, dispatch_type)); | 140 new EventWithDispatchType(std::move(event), latency, dispatch_type)); |
| 137 | 141 |
| 138 QueueEvent(std::move(event_with_dispatch_type)); | 142 QueueEvent(std::move(event_with_dispatch_type)); |
| 139 | 143 |
| 140 // send an ack when we are non-blocking. | 144 // send an ack when we are non-blocking. |
| 141 return non_blocking; | 145 return non_blocking; |
| 142 } | 146 } |
| 143 | 147 |
| 144 void MainThreadEventQueue::DispatchInFlightEvent() { | 148 void MainThreadEventQueue::DispatchInFlightEvent() { |
| 145 if (in_flight_event_) { | 149 if (in_flight_event_) { |
| 146 // Report the coalesced count only for continuous events; otherwise | 150 // Report the coalesced count only for continuous events; otherwise |
| 147 // the zero value would be dominated by non-continuous events. | 151 // the zero value would be dominated by non-continuous events. |
| 148 base::TimeTicks now = base::TimeTicks::Now(); | 152 base::TimeTicks now = base::TimeTicks::Now(); |
| 149 if (IsContinuousEvent(in_flight_event_)) { | 153 if (IsContinuousEvent(in_flight_event_)) { |
| 150 UMA_HISTOGRAM_CUSTOM_COUNTS( | 154 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 151 "Event.MainThreadEventQueue.Continuous.QueueingTime", | 155 "Event.MainThreadEventQueue.Continuous.QueueingTime", |
| 152 (now - in_flight_event_->creationTimestamp()).InMicroseconds(), 1, | 156 (now - in_flight_event_->creationTimestamp()).InMicroseconds(), 1, |
| 153 kTenSeconds, 50); | 157 kTenSeconds, 50); |
| 154 | 158 |
| 155 UMA_HISTOGRAM_CUSTOM_COUNTS( | 159 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 156 "Event.MainThreadEventQueue.Continuous.FreshnessTime", | 160 "Event.MainThreadEventQueue.Continuous.FreshnessTime", |
| 157 (now - in_flight_event_->lastCoalescedTimestamp()).InMicroseconds(), | 161 (now - in_flight_event_->lastCoalescedTimestamp()).InMicroseconds(), |
| 158 1, kTenSeconds, 50); | 162 1, kTenSeconds, 50); |
| 159 | 163 |
| 160 UMA_HISTOGRAM_COUNTS_1000("Event.MainThreadEventQueue.CoalescedCount", | 164 UMA_HISTOGRAM_COUNTS_1000("Event.MainThreadEventQueue.CoalescedCount", |
| 161 in_flight_event_->coalescedEventIds().size()); | 165 in_flight_event_->coalescedCount()); |
| 162 } else { | 166 } else { |
| 163 UMA_HISTOGRAM_CUSTOM_COUNTS( | 167 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 164 "Event.MainThreadEventQueue.NonContinuous.QueueingTime", | 168 "Event.MainThreadEventQueue.NonContinuous.QueueingTime", |
| 165 (now - in_flight_event_->creationTimestamp()).InMicroseconds(), 1, | 169 (now - in_flight_event_->creationTimestamp()).InMicroseconds(), 1, |
| 166 kTenSeconds, 50); | 170 kTenSeconds, 50); |
| 167 } | 171 } |
| 168 | 172 |
| 169 InputEventDispatchType dispatch_type = in_flight_event_->dispatchType(); | 173 InputEventDispatchType dispatch_type = in_flight_event_->dispatchType(); |
| 170 if (!in_flight_event_->coalescedEventIds().empty() && | 174 if (!in_flight_event_->blockingCoalescedEventIds().empty()) { |
| 171 dispatch_type == DISPATCH_TYPE_BLOCKING) { | 175 switch (dispatch_type) { |
| 172 dispatch_type = DISPATCH_TYPE_BLOCKING_NOTIFY_MAIN; | 176 case DISPATCH_TYPE_BLOCKING: |
| 177 dispatch_type = DISPATCH_TYPE_BLOCKING_NOTIFY_MAIN; |
| 178 break; |
| 179 case DISPATCH_TYPE_NON_BLOCKING: |
| 180 dispatch_type = DISPATCH_TYPE_NON_BLOCKING_NOTIFY_MAIN; |
| 181 break; |
| 182 default: |
| 183 NOTREACHED(); |
| 184 } |
| 173 } | 185 } |
| 174 | |
| 175 client_->HandleEventOnMainThread(routing_id_, &in_flight_event_->event(), | 186 client_->HandleEventOnMainThread(routing_id_, &in_flight_event_->event(), |
| 176 in_flight_event_->latencyInfo(), | 187 in_flight_event_->latencyInfo(), |
| 177 dispatch_type); | 188 dispatch_type); |
| 178 } | 189 } |
| 179 | 190 |
| 180 in_flight_event_.reset(); | 191 in_flight_event_.reset(); |
| 181 } | 192 } |
| 182 | 193 |
| 183 void MainThreadEventQueue::PossiblyScheduleMainFrame() { | 194 void MainThreadEventQueue::PossiblyScheduleMainFrame() { |
| 184 if (IsRafAlignedInputDisabled()) | 195 if (IsRafAlignedInputDisabled()) |
| 185 return; | 196 return; |
| 186 bool needs_main_frame = false; | 197 bool needs_main_frame = false; |
| 187 { | 198 { |
| 188 base::AutoLock lock(shared_state_lock_); | 199 base::AutoLock lock(shared_state_lock_); |
| 189 if (!shared_state_.sent_main_frame_request_ && | 200 if (!shared_state_.sent_main_frame_request_ && |
| 190 !shared_state_.events_.empty() && | 201 !shared_state_.events_.empty() && |
| 191 IsRafAlignedEvent(shared_state_.events_.front())) { | 202 IsRafAlignedEvent(shared_state_.events_.front()->event())) { |
| 192 needs_main_frame = !shared_state_.sent_main_frame_request_; | 203 needs_main_frame = !shared_state_.sent_main_frame_request_; |
| 193 shared_state_.sent_main_frame_request_ = false; | 204 shared_state_.sent_main_frame_request_ = false; |
| 194 } | 205 } |
| 195 } | 206 } |
| 196 if (needs_main_frame) | 207 if (needs_main_frame) |
| 197 client_->NeedsMainFrame(routing_id_); | 208 client_->NeedsMainFrame(routing_id_); |
| 198 } | 209 } |
| 199 | 210 |
| 200 void MainThreadEventQueue::DispatchSingleEvent() { | 211 void MainThreadEventQueue::DispatchSingleEvent() { |
| 201 { | 212 { |
| 202 base::AutoLock lock(shared_state_lock_); | 213 base::AutoLock lock(shared_state_lock_); |
| 203 if (shared_state_.events_.empty()) | 214 if (shared_state_.events_.empty()) |
| 204 return; | 215 return; |
| 205 | 216 |
| 206 in_flight_event_ = shared_state_.events_.Pop(); | 217 in_flight_event_ = shared_state_.events_.Pop(); |
| 207 } | 218 } |
| 208 DispatchInFlightEvent(); | 219 DispatchInFlightEvent(); |
| 209 PossiblyScheduleMainFrame(); | 220 PossiblyScheduleMainFrame(); |
| 210 } | 221 } |
| 211 | 222 |
| 212 void MainThreadEventQueue::EventHandled(blink::WebInputEvent::Type type, | 223 void MainThreadEventQueue::EventHandled(blink::WebInputEvent::Type type, |
| 213 InputEventAckState ack_result) { | 224 InputEventAckState ack_result) { |
| 214 if (in_flight_event_ && | 225 if (in_flight_event_) { |
| 215 in_flight_event_->dispatchType() == DISPATCH_TYPE_BLOCKING) { | 226 for (const auto id : in_flight_event_->blockingCoalescedEventIds()) { |
| 216 for (const auto id : in_flight_event_->coalescedEventIds()) { | |
| 217 client_->SendInputEventAck(routing_id_, type, ack_result, id); | 227 client_->SendInputEventAck(routing_id_, type, ack_result, id); |
| 218 if (renderer_scheduler_) { | 228 if (renderer_scheduler_) { |
| 219 renderer_scheduler_->DidHandleInputEventOnMainThread( | 229 renderer_scheduler_->DidHandleInputEventOnMainThread( |
| 220 in_flight_event_->event()); | 230 in_flight_event_->event()); |
| 221 } | 231 } |
| 222 } | 232 } |
| 223 } | 233 } |
| 224 } | 234 } |
| 225 | 235 |
| 226 void MainThreadEventQueue::DispatchRafAlignedInput() { | 236 void MainThreadEventQueue::DispatchRafAlignedInput() { |
| 227 if (IsRafAlignedInputDisabled()) | 237 if (IsRafAlignedInputDisabled()) |
| 228 return; | 238 return; |
| 229 | 239 |
| 230 std::deque<std::unique_ptr<EventWithDispatchType>> events_to_process; | 240 std::deque<std::unique_ptr<EventWithDispatchType>> events_to_process; |
| 231 { | 241 { |
| 232 base::AutoLock lock(shared_state_lock_); | 242 base::AutoLock lock(shared_state_lock_); |
| 233 shared_state_.sent_main_frame_request_ = false; | 243 shared_state_.sent_main_frame_request_ = false; |
| 234 | 244 |
| 235 while(!shared_state_.events_.empty()) { | 245 while(!shared_state_.events_.empty()) { |
| 236 if (!IsRafAlignedEvent(shared_state_.events_.front())) | 246 if (!IsRafAlignedEvent(shared_state_.events_.front()->event())) |
| 237 break; | 247 break; |
| 238 events_to_process.emplace_back(shared_state_.events_.Pop()); | 248 events_to_process.emplace_back(shared_state_.events_.Pop()); |
| 239 } | 249 } |
| 240 } | 250 } |
| 241 | 251 |
| 242 while(!events_to_process.empty()) { | 252 while(!events_to_process.empty()) { |
| 243 in_flight_event_ = std::move(events_to_process.front()); | 253 in_flight_event_ = std::move(events_to_process.front()); |
| 244 events_to_process.pop_front(); | 254 events_to_process.pop_front(); |
| 245 DispatchInFlightEvent(); | 255 DispatchInFlightEvent(); |
| 246 } | 256 } |
| 247 PossiblyScheduleMainFrame(); | 257 PossiblyScheduleMainFrame(); |
| 248 } | 258 } |
| 249 | 259 |
| 250 void MainThreadEventQueue::SendEventNotificationToMainThread() { | 260 void MainThreadEventQueue::SendEventNotificationToMainThread() { |
| 251 main_task_runner_->PostTask( | 261 main_task_runner_->PostTask( |
| 252 FROM_HERE, base::Bind(&MainThreadEventQueue::DispatchSingleEvent, this)); | 262 FROM_HERE, base::Bind(&MainThreadEventQueue::DispatchSingleEvent, this)); |
| 253 } | 263 } |
| 254 | 264 |
| 255 void MainThreadEventQueue::QueueEvent( | 265 void MainThreadEventQueue::QueueEvent( |
| 256 std::unique_ptr<EventWithDispatchType> event) { | 266 std::unique_ptr<EventWithDispatchType> event) { |
| 257 bool is_raf_aligned = IsRafAlignedEvent(event); | 267 bool is_raf_aligned = IsRafAlignedEvent(event->event()); |
| 258 size_t send_notification_count = 0; | 268 size_t send_notification_count = 0; |
| 259 bool needs_main_frame = false; | 269 bool needs_main_frame = false; |
| 260 { | 270 { |
| 261 base::AutoLock lock(shared_state_lock_); | 271 base::AutoLock lock(shared_state_lock_); |
| 262 size_t size_before = shared_state_.events_.size(); | 272 size_t size_before = shared_state_.events_.size(); |
| 273 |
| 274 // Stash if the tail of the queue was rAF aligned. |
| 275 bool was_raf_aligned = false; |
| 276 if (size_before > 0) { |
| 277 was_raf_aligned = |
| 278 IsRafAlignedEvent(shared_state_.events_.at(size_before - 1)->event()); |
| 279 } |
| 263 shared_state_.events_.Queue(std::move(event)); | 280 shared_state_.events_.Queue(std::move(event)); |
| 264 size_t size_after = shared_state_.events_.size(); | 281 size_t size_after = shared_state_.events_.size(); |
| 265 | 282 |
| 266 if (size_before != size_after) { | 283 if (size_before != size_after) { |
| 267 if (IsRafAlignedInputDisabled()) { | 284 if (IsRafAlignedInputDisabled()) { |
| 268 send_notification_count = 1; | 285 send_notification_count = 1; |
| 269 } else if (!is_raf_aligned) { | 286 } else if (!is_raf_aligned) { |
| 270 send_notification_count = 1; | 287 send_notification_count = 1; |
| 271 // If we had just enqueued a non-rAF input event we will send a series | 288 // If we had just enqueued a non-rAF input event we will send a series |
| 272 // of normal post messages to ensure they are all handled right away. | 289 // of normal post messages to ensure they are all handled right away. |
| 273 for (size_t pos = size_after - 1; pos >= 1; --pos) { | 290 for (size_t pos = size_after - 1; pos >= 1; --pos) { |
| 274 if (IsRafAlignedEvent(shared_state_.events_.at(pos - 1))) | 291 if (IsRafAlignedEvent(shared_state_.events_.at(pos - 1)->event())) |
| 275 send_notification_count++; | 292 send_notification_count++; |
| 276 else | 293 else |
| 277 break; | 294 break; |
| 278 } | 295 } |
| 279 } else { | 296 } else { |
| 280 needs_main_frame = !shared_state_.sent_main_frame_request_; | 297 needs_main_frame = !shared_state_.sent_main_frame_request_; |
| 281 shared_state_.sent_main_frame_request_ = true; | 298 shared_state_.sent_main_frame_request_ = true; |
| 282 } | 299 } |
| 300 } else if (size_before > 0) { |
| 301 // The event was coalesced. The queue size didn't change but |
| 302 // the rAF alignment of the event may have and we need to schedule |
| 303 // a notification. |
| 304 bool is_coalesced_raf_aligned = |
| 305 IsRafAlignedEvent(shared_state_.events_.at(size_before - 1)->event()); |
| 306 if (was_raf_aligned != is_coalesced_raf_aligned) |
| 307 send_notification_count = 1; |
| 283 } | 308 } |
| 284 } | 309 } |
| 310 |
| 285 for (size_t i = 0; i < send_notification_count; ++i) | 311 for (size_t i = 0; i < send_notification_count; ++i) |
| 286 SendEventNotificationToMainThread(); | 312 SendEventNotificationToMainThread(); |
| 287 if (needs_main_frame) | 313 if (needs_main_frame) |
| 288 client_->NeedsMainFrame(routing_id_); | 314 client_->NeedsMainFrame(routing_id_); |
| 289 } | 315 } |
| 290 | 316 |
| 291 bool MainThreadEventQueue::IsRafAlignedInputDisabled() { | 317 bool MainThreadEventQueue::IsRafAlignedInputDisabled() { |
| 292 return !handle_raf_aligned_mouse_input_ && !handle_raf_aligned_touch_input_; | 318 return !handle_raf_aligned_mouse_input_ && !handle_raf_aligned_touch_input_; |
| 293 } | 319 } |
| 294 | 320 |
| 295 bool MainThreadEventQueue::IsRafAlignedEvent( | 321 bool MainThreadEventQueue::IsRafAlignedEvent( |
| 296 const std::unique_ptr<EventWithDispatchType>& event) { | 322 const blink::WebInputEvent& event) { |
| 297 switch (event->event().type) { | 323 switch (event.type) { |
| 298 case blink::WebInputEvent::MouseMove: | 324 case blink::WebInputEvent::MouseMove: |
| 299 case blink::WebInputEvent::MouseWheel: | 325 case blink::WebInputEvent::MouseWheel: |
| 300 return handle_raf_aligned_mouse_input_; | 326 return handle_raf_aligned_mouse_input_; |
| 301 case blink::WebInputEvent::TouchMove: | 327 case blink::WebInputEvent::TouchMove: |
| 302 // TouchMoves that are blocking end up blocking scroll. Do not treat | 328 // TouchMoves that are blocking end up blocking scroll. Do not treat |
| 303 // them as continuous events otherwise we will end up waiting up to an | 329 // them as continuous events otherwise we will end up waiting up to an |
| 304 // additional frame. | 330 // additional frame. |
| 305 return static_cast<const blink::WebTouchEvent&>(event->event()) | 331 return static_cast<const blink::WebTouchEvent&>(event).dispatchType != |
| 306 .dispatchType != blink::WebInputEvent::Blocking && | 332 blink::WebInputEvent::Blocking && |
| 307 handle_raf_aligned_touch_input_; | 333 handle_raf_aligned_touch_input_; |
| 308 default: | 334 default: |
| 309 return false; | 335 return false; |
| 310 } | 336 } |
| 311 } | 337 } |
| 312 | 338 |
| 313 } // namespace content | 339 } // namespace content |
| OLD | NEW |