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

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

Issue 2557153002: Fix issues related to a continuous event getting coalesced with a discrete event. (Closed)
Patch Set: Fix nits Created 4 years 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/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
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
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
OLDNEW
« no previous file with comments | « content/renderer/input/main_thread_event_queue.h ('k') | content/renderer/input/main_thread_event_queue_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698