DevTools: cut host and port from webSocketDebuggerUrl in addition to ws:// prefix
[chromium-blink-merge.git] / content / browser / renderer_host / input / input_router_impl.cc
blob4f9600d7e6765d51cdaf6666648b6f11619087b7
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/input/input_router_impl.h"
7 #include <math.h>
9 #include "base/auto_reset.h"
10 #include "base/command_line.h"
11 #include "base/metrics/histogram.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "content/browser/renderer_host/input/gesture_event_queue.h"
14 #include "content/browser/renderer_host/input/input_ack_handler.h"
15 #include "content/browser/renderer_host/input/input_router_client.h"
16 #include "content/browser/renderer_host/input/touch_event_queue.h"
17 #include "content/browser/renderer_host/input/touchpad_tap_suppression_controller.h"
18 #include "content/common/content_constants_internal.h"
19 #include "content/common/edit_command.h"
20 #include "content/common/input/input_event_ack_state.h"
21 #include "content/common/input/touch_action.h"
22 #include "content/common/input/web_touch_event_traits.h"
23 #include "content/common/input_messages.h"
24 #include "content/common/view_messages.h"
25 #include "content/public/browser/notification_service.h"
26 #include "content/public/browser/notification_types.h"
27 #include "content/public/browser/user_metrics.h"
28 #include "content/public/common/content_switches.h"
29 #include "ipc/ipc_sender.h"
30 #include "ui/events/event.h"
31 #include "ui/events/keycodes/keyboard_codes.h"
33 using base::Time;
34 using base::TimeDelta;
35 using base::TimeTicks;
36 using blink::WebGestureEvent;
37 using blink::WebInputEvent;
38 using blink::WebKeyboardEvent;
39 using blink::WebMouseEvent;
40 using blink::WebMouseWheelEvent;
41 using blink::WebTouchEvent;
43 namespace content {
44 namespace {
46 const char* GetEventAckName(InputEventAckState ack_result) {
47 switch(ack_result) {
48 case INPUT_EVENT_ACK_STATE_UNKNOWN: return "UNKNOWN";
49 case INPUT_EVENT_ACK_STATE_CONSUMED: return "CONSUMED";
50 case INPUT_EVENT_ACK_STATE_NOT_CONSUMED: return "NOT_CONSUMED";
51 case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS: return "NO_CONSUMER_EXISTS";
52 case INPUT_EVENT_ACK_STATE_IGNORED: return "IGNORED";
54 DLOG(WARNING) << "Unhandled InputEventAckState in GetEventAckName.";
55 return "";
58 } // namespace
60 InputRouterImpl::Config::Config() {
63 InputRouterImpl::InputRouterImpl(IPC::Sender* sender,
64 InputRouterClient* client,
65 InputAckHandler* ack_handler,
66 int routing_id,
67 const Config& config)
68 : sender_(sender),
69 client_(client),
70 ack_handler_(ack_handler),
71 routing_id_(routing_id),
72 select_message_pending_(false),
73 move_caret_pending_(false),
74 mouse_move_pending_(false),
75 mouse_wheel_pending_(false),
76 current_ack_source_(ACK_SOURCE_NONE),
77 flush_requested_(false),
78 active_renderer_fling_count_(0),
79 touch_event_queue_(this, config.touch_config),
80 gesture_event_queue_(this, this, config.gesture_config) {
81 DCHECK(sender);
82 DCHECK(client);
83 DCHECK(ack_handler);
84 UpdateTouchAckTimeoutEnabled();
87 InputRouterImpl::~InputRouterImpl() {
88 STLDeleteElements(&pending_select_messages_);
91 bool InputRouterImpl::SendInput(scoped_ptr<IPC::Message> message) {
92 DCHECK(IPC_MESSAGE_ID_CLASS(message->type()) == InputMsgStart);
93 switch (message->type()) {
94 // Check for types that require an ACK.
95 case InputMsg_SelectRange::ID:
96 case InputMsg_MoveRangeSelectionExtent::ID:
97 return SendSelectMessage(message.Pass());
98 case InputMsg_MoveCaret::ID:
99 return SendMoveCaret(message.Pass());
100 case InputMsg_HandleInputEvent::ID:
101 NOTREACHED() << "WebInputEvents should never be sent via SendInput.";
102 return false;
103 default:
104 return Send(message.release());
108 void InputRouterImpl::SendMouseEvent(
109 const MouseEventWithLatencyInfo& mouse_event) {
110 if (mouse_event.event.type == WebInputEvent::MouseDown &&
111 gesture_event_queue_.GetTouchpadTapSuppressionController()->
112 ShouldDeferMouseDown(mouse_event))
113 return;
114 if (mouse_event.event.type == WebInputEvent::MouseUp &&
115 gesture_event_queue_.GetTouchpadTapSuppressionController()->
116 ShouldSuppressMouseUp())
117 return;
119 SendMouseEventImmediately(mouse_event);
122 void InputRouterImpl::SendWheelEvent(
123 const MouseWheelEventWithLatencyInfo& wheel_event) {
124 if (mouse_wheel_pending_) {
125 // If there's already a mouse wheel event waiting to be sent to the
126 // renderer, add the new deltas to that event. Not doing so (e.g., by
127 // dropping the old event, as for mouse moves) results in very slow
128 // scrolling on the Mac.
129 if (wheel_event.event.hasPreciseScrollingDeltas)
130 DCHECK(wheel_event.event.canScroll);
131 DCHECK(!(wheel_event.event.hasPreciseScrollingDeltas &&
132 !wheel_event.event.canScroll));
133 if (coalesced_mouse_wheel_events_.empty() ||
134 (!coalesced_mouse_wheel_events_.empty() &&
135 !coalesced_mouse_wheel_events_.back().CanCoalesceWith(wheel_event))) {
136 coalesced_mouse_wheel_events_.push_back(wheel_event);
137 } else {
138 coalesced_mouse_wheel_events_.back().CoalesceWith(wheel_event);
140 return;
143 mouse_wheel_pending_ = true;
144 current_wheel_event_ = wheel_event;
146 LOCAL_HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize",
147 coalesced_mouse_wheel_events_.size());
149 FilterAndSendWebInputEvent(wheel_event.event, wheel_event.latency, false);
152 void InputRouterImpl::SendKeyboardEvent(const NativeWebKeyboardEvent& key_event,
153 const ui::LatencyInfo& latency_info,
154 bool is_keyboard_shortcut) {
155 // Put all WebKeyboardEvent objects in a queue since we can't trust the
156 // renderer and we need to give something to the HandleKeyboardEvent
157 // handler.
158 key_queue_.push_back(key_event);
159 LOCAL_HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size());
161 gesture_event_queue_.FlingHasBeenHalted();
163 // Only forward the non-native portions of our event.
164 FilterAndSendWebInputEvent(key_event, latency_info, is_keyboard_shortcut);
167 void InputRouterImpl::SendGestureEvent(
168 const GestureEventWithLatencyInfo& original_gesture_event) {
169 input_stream_validator_.Validate(original_gesture_event.event);
171 GestureEventWithLatencyInfo gesture_event(original_gesture_event);
173 if (touch_action_filter_.FilterGestureEvent(&gesture_event.event))
174 return;
176 if (gesture_event.event.sourceDevice == blink::WebGestureDeviceTouchscreen)
177 touch_event_queue_.OnGestureScrollEvent(gesture_event);
179 gesture_event_queue_.QueueEvent(gesture_event);
182 void InputRouterImpl::SendTouchEvent(
183 const TouchEventWithLatencyInfo& touch_event) {
184 input_stream_validator_.Validate(touch_event.event);
185 touch_event_queue_.QueueEvent(touch_event);
188 // Forwards MouseEvent without passing it through
189 // TouchpadTapSuppressionController.
190 void InputRouterImpl::SendMouseEventImmediately(
191 const MouseEventWithLatencyInfo& mouse_event) {
192 // Avoid spamming the renderer with mouse move events. It is important
193 // to note that WM_MOUSEMOVE events are anyways synthetic, but since our
194 // thread is able to rapidly consume WM_MOUSEMOVE events, we may get way
195 // more WM_MOUSEMOVE events than we wish to send to the renderer.
196 if (mouse_event.event.type == WebInputEvent::MouseMove) {
197 if (mouse_move_pending_) {
198 if (!next_mouse_move_)
199 next_mouse_move_.reset(new MouseEventWithLatencyInfo(mouse_event));
200 else
201 next_mouse_move_->CoalesceWith(mouse_event);
202 return;
204 mouse_move_pending_ = true;
207 FilterAndSendWebInputEvent(mouse_event.event, mouse_event.latency, false);
210 void InputRouterImpl::SendTouchEventImmediately(
211 const TouchEventWithLatencyInfo& touch_event) {
212 if (WebTouchEventTraits::IsTouchSequenceStart(touch_event.event)) {
213 touch_action_filter_.ResetTouchAction();
214 // Note that if the previous touch-action was TOUCH_ACTION_NONE, enabling
215 // the timeout here will not take effect until the *following* touch
216 // sequence. This is a desirable side-effect, giving the renderer a chance
217 // to send a touch-action response without racing against the ack timeout.
218 UpdateTouchAckTimeoutEnabled();
221 FilterAndSendWebInputEvent(touch_event.event, touch_event.latency, false);
224 void InputRouterImpl::SendGestureEventImmediately(
225 const GestureEventWithLatencyInfo& gesture_event) {
226 FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency, false);
229 const NativeWebKeyboardEvent* InputRouterImpl::GetLastKeyboardEvent() const {
230 if (key_queue_.empty())
231 return NULL;
232 return &key_queue_.front();
235 void InputRouterImpl::NotifySiteIsMobileOptimized(bool is_mobile_optimized) {
236 touch_event_queue_.SetIsMobileOptimizedSite(is_mobile_optimized);
239 void InputRouterImpl::RequestNotificationWhenFlushed() {
240 flush_requested_ = true;
241 SignalFlushedIfNecessary();
244 bool InputRouterImpl::HasPendingEvents() const {
245 return !touch_event_queue_.empty() ||
246 !gesture_event_queue_.empty() ||
247 !key_queue_.empty() ||
248 mouse_move_pending_ ||
249 mouse_wheel_pending_ ||
250 select_message_pending_ ||
251 move_caret_pending_ ||
252 active_renderer_fling_count_ > 0;
255 bool InputRouterImpl::OnMessageReceived(const IPC::Message& message) {
256 bool handled = true;
257 IPC_BEGIN_MESSAGE_MAP(InputRouterImpl, message)
258 IPC_MESSAGE_HANDLER(InputHostMsg_HandleInputEvent_ACK, OnInputEventAck)
259 IPC_MESSAGE_HANDLER(InputHostMsg_DidOverscroll, OnDidOverscroll)
260 IPC_MESSAGE_HANDLER(InputHostMsg_MoveCaret_ACK, OnMsgMoveCaretAck)
261 IPC_MESSAGE_HANDLER(InputHostMsg_SelectRange_ACK, OnSelectMessageAck)
262 IPC_MESSAGE_HANDLER(InputHostMsg_MoveRangeSelectionExtent_ACK,
263 OnSelectMessageAck)
264 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
265 OnHasTouchEventHandlers)
266 IPC_MESSAGE_HANDLER(InputHostMsg_SetTouchAction,
267 OnSetTouchAction)
268 IPC_MESSAGE_HANDLER(InputHostMsg_DidStopFlinging, OnDidStopFlinging)
269 IPC_MESSAGE_UNHANDLED(handled = false)
270 IPC_END_MESSAGE_MAP()
272 return handled;
275 void InputRouterImpl::OnTouchEventAck(const TouchEventWithLatencyInfo& event,
276 InputEventAckState ack_result) {
277 // Touchstart events sent to the renderer indicate a new touch sequence, but
278 // in some cases we may filter out sending the touchstart - catch those here.
279 if (WebTouchEventTraits::IsTouchSequenceStart(event.event) &&
280 ack_result == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) {
281 touch_action_filter_.ResetTouchAction();
282 UpdateTouchAckTimeoutEnabled();
284 ack_handler_->OnTouchEventAck(event, ack_result);
287 void InputRouterImpl::OnGestureEventAck(
288 const GestureEventWithLatencyInfo& event,
289 InputEventAckState ack_result) {
290 touch_event_queue_.OnGestureEventAck(event, ack_result);
291 ack_handler_->OnGestureEventAck(event, ack_result);
294 bool InputRouterImpl::SendSelectMessage(
295 scoped_ptr<IPC::Message> message) {
296 DCHECK(message->type() == InputMsg_SelectRange::ID ||
297 message->type() == InputMsg_MoveRangeSelectionExtent::ID);
299 // TODO(jdduke): Factor out common logic between selection and caret-related
300 // IPC messages.
301 if (select_message_pending_) {
302 if (!pending_select_messages_.empty() &&
303 pending_select_messages_.back()->type() == message->type()) {
304 delete pending_select_messages_.back();
305 pending_select_messages_.pop_back();
308 pending_select_messages_.push_back(message.release());
309 return true;
312 select_message_pending_ = true;
313 return Send(message.release());
316 bool InputRouterImpl::SendMoveCaret(scoped_ptr<IPC::Message> message) {
317 DCHECK(message->type() == InputMsg_MoveCaret::ID);
318 if (move_caret_pending_) {
319 next_move_caret_ = message.Pass();
320 return true;
323 move_caret_pending_ = true;
324 return Send(message.release());
327 bool InputRouterImpl::Send(IPC::Message* message) {
328 return sender_->Send(message);
331 void InputRouterImpl::FilterAndSendWebInputEvent(
332 const WebInputEvent& input_event,
333 const ui::LatencyInfo& latency_info,
334 bool is_keyboard_shortcut) {
335 TRACE_EVENT1("input",
336 "InputRouterImpl::FilterAndSendWebInputEvent",
337 "type",
338 WebInputEventTraits::GetName(input_event.type));
340 // Any input event cancels a pending mouse move event.
341 next_mouse_move_.reset();
343 OfferToHandlers(input_event, latency_info, is_keyboard_shortcut);
346 void InputRouterImpl::OfferToHandlers(const WebInputEvent& input_event,
347 const ui::LatencyInfo& latency_info,
348 bool is_keyboard_shortcut) {
349 output_stream_validator_.Validate(input_event);
351 if (OfferToClient(input_event, latency_info))
352 return;
354 OfferToRenderer(input_event, latency_info, is_keyboard_shortcut);
356 // Touch events should always indicate in the event whether they are
357 // cancelable (respect ACK disposition) or not except touchmove.
358 bool needs_synthetic_ack =
359 !WebInputEventTraits::WillReceiveAckFromRenderer(input_event);
361 if (WebInputEvent::isTouchEventType(input_event.type) &&
362 input_event.type != WebInputEvent::TouchMove) {
363 const WebTouchEvent& touch = static_cast<const WebTouchEvent&>(input_event);
364 DCHECK_EQ(needs_synthetic_ack, !touch.cancelable);
367 // The synthetic acks are sent immediately.
368 if (needs_synthetic_ack) {
369 ProcessInputEventAck(
370 input_event.type, INPUT_EVENT_ACK_STATE_IGNORED, latency_info,
371 WebInputEventTraits::GetUniqueTouchEventId(input_event),
372 IGNORING_DISPOSITION);
376 bool InputRouterImpl::OfferToClient(const WebInputEvent& input_event,
377 const ui::LatencyInfo& latency_info) {
378 bool consumed = false;
380 InputEventAckState filter_ack =
381 client_->FilterInputEvent(input_event, latency_info);
382 switch (filter_ack) {
383 case INPUT_EVENT_ACK_STATE_CONSUMED:
384 case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS:
385 // Send the ACK and early exit.
386 next_mouse_move_.reset();
387 ProcessInputEventAck(
388 input_event.type, filter_ack, latency_info,
389 WebInputEventTraits::GetUniqueTouchEventId(input_event), CLIENT);
390 // WARNING: |this| may be deleted at this point.
391 consumed = true;
392 break;
393 case INPUT_EVENT_ACK_STATE_UNKNOWN:
394 // Simply drop the event.
395 consumed = true;
396 break;
397 default:
398 break;
401 return consumed;
404 bool InputRouterImpl::OfferToRenderer(const WebInputEvent& input_event,
405 const ui::LatencyInfo& latency_info,
406 bool is_keyboard_shortcut) {
407 if (Send(new InputMsg_HandleInputEvent(
408 routing_id(), &input_event, latency_info, is_keyboard_shortcut))) {
409 // Ack messages for ignored ack event types should never be sent by the
410 // renderer. Consequently, such event types should not affect event time
411 // or in-flight event count metrics.
412 if (WebInputEventTraits::WillReceiveAckFromRenderer(input_event)) {
413 input_event_start_time_ = TimeTicks::Now();
414 client_->IncrementInFlightEventCount();
416 return true;
418 return false;
421 void InputRouterImpl::OnInputEventAck(const InputEventAck& ack) {
422 client_->DecrementInFlightEventCount();
423 // Log the time delta for processing an input event.
424 TimeDelta delta = TimeTicks::Now() - input_event_start_time_;
425 UMA_HISTOGRAM_TIMES("MPArch.IIR_InputEventDelta", delta);
427 if (ack.overscroll) {
428 DCHECK(ack.type == WebInputEvent::MouseWheel ||
429 ack.type == WebInputEvent::GestureScrollUpdate);
430 OnDidOverscroll(*ack.overscroll);
433 ProcessInputEventAck(ack.type, ack.state, ack.latency,
434 ack.unique_touch_event_id, RENDERER);
437 void InputRouterImpl::OnDidOverscroll(const DidOverscrollParams& params) {
438 client_->DidOverscroll(params);
441 void InputRouterImpl::OnMsgMoveCaretAck() {
442 move_caret_pending_ = false;
443 if (next_move_caret_)
444 SendMoveCaret(next_move_caret_.Pass());
447 void InputRouterImpl::OnSelectMessageAck() {
448 select_message_pending_ = false;
449 if (!pending_select_messages_.empty()) {
450 scoped_ptr<IPC::Message> next_message =
451 make_scoped_ptr(pending_select_messages_.front());
452 pending_select_messages_.pop_front();
454 SendSelectMessage(next_message.Pass());
458 void InputRouterImpl::OnHasTouchEventHandlers(bool has_handlers) {
459 TRACE_EVENT1("input", "InputRouterImpl::OnHasTouchEventHandlers",
460 "has_handlers", has_handlers);
462 // Lack of a touch handler indicates that the page either has no touch-action
463 // modifiers or that all its touch-action modifiers are auto. Resetting the
464 // touch-action here allows forwarding of subsequent gestures even if the
465 // underlying touches never reach the router.
466 // TODO(jdduke): Reset touch-action only at the end of a touch sequence to
467 // prevent potentially strange mid-sequence behavior, crbug.com/375940.
468 if (!has_handlers)
469 touch_action_filter_.ResetTouchAction();
471 touch_event_queue_.OnHasTouchEventHandlers(has_handlers);
472 client_->OnHasTouchEventHandlers(has_handlers);
475 void InputRouterImpl::OnSetTouchAction(TouchAction touch_action) {
476 // Synthetic touchstart events should get filtered out in RenderWidget.
477 DCHECK(touch_event_queue_.IsPendingAckTouchStart());
478 TRACE_EVENT1("input", "InputRouterImpl::OnSetTouchAction",
479 "action", touch_action);
481 touch_action_filter_.OnSetTouchAction(touch_action);
483 // TOUCH_ACTION_NONE should disable the touch ack timeout.
484 UpdateTouchAckTimeoutEnabled();
487 void InputRouterImpl::OnDidStopFlinging() {
488 DCHECK_GT(active_renderer_fling_count_, 0);
489 // Note that we're only guaranteed to get a fling end notification from the
490 // renderer, not from any other consumers. Consequently, the GestureEventQueue
491 // cannot use this bookkeeping for logic like tap suppression.
492 --active_renderer_fling_count_;
493 SignalFlushedIfNecessary();
495 client_->DidStopFlinging();
498 void InputRouterImpl::ProcessInputEventAck(WebInputEvent::Type event_type,
499 InputEventAckState ack_result,
500 const ui::LatencyInfo& latency_info,
501 uint32 unique_touch_event_id,
502 AckSource ack_source) {
503 TRACE_EVENT2("input", "InputRouterImpl::ProcessInputEventAck",
504 "type", WebInputEventTraits::GetName(event_type),
505 "ack", GetEventAckName(ack_result));
507 // Note: The keyboard ack must be treated carefully, as it may result in
508 // synchronous destruction of |this|. Handling immediately guards against
509 // future references to |this|, as with |auto_reset_current_ack_source| below.
510 if (WebInputEvent::isKeyboardEventType(event_type)) {
511 ProcessKeyboardAck(event_type, ack_result);
512 // WARNING: |this| may be deleted at this point.
513 return;
516 base::AutoReset<AckSource> auto_reset_current_ack_source(
517 &current_ack_source_, ack_source);
519 if (WebInputEvent::isMouseEventType(event_type)) {
520 ProcessMouseAck(event_type, ack_result);
521 } else if (event_type == WebInputEvent::MouseWheel) {
522 ProcessWheelAck(ack_result, latency_info);
523 } else if (WebInputEvent::isTouchEventType(event_type)) {
524 ProcessTouchAck(ack_result, latency_info, unique_touch_event_id);
525 } else if (WebInputEvent::isGestureEventType(event_type)) {
526 ProcessGestureAck(event_type, ack_result, latency_info);
527 } else if (event_type != WebInputEvent::Undefined) {
528 ack_handler_->OnUnexpectedEventAck(InputAckHandler::BAD_ACK_MESSAGE);
531 SignalFlushedIfNecessary();
534 void InputRouterImpl::ProcessKeyboardAck(blink::WebInputEvent::Type type,
535 InputEventAckState ack_result) {
536 if (key_queue_.empty()) {
537 ack_handler_->OnUnexpectedEventAck(InputAckHandler::UNEXPECTED_ACK);
538 } else if (key_queue_.front().type != type) {
539 // Something must be wrong. Clear the |key_queue_| and char event
540 // suppression so that we can resume from the error.
541 key_queue_.clear();
542 ack_handler_->OnUnexpectedEventAck(InputAckHandler::UNEXPECTED_EVENT_TYPE);
543 } else {
544 NativeWebKeyboardEvent front_item = key_queue_.front();
545 key_queue_.pop_front();
547 ack_handler_->OnKeyboardEventAck(front_item, ack_result);
548 // WARNING: This InputRouterImpl can be deallocated at this point
549 // (i.e. in the case of Ctrl+W, where the call to
550 // HandleKeyboardEvent destroys this InputRouterImpl).
551 // TODO(jdduke): crbug.com/274029 - Make ack-triggered shutdown async.
555 void InputRouterImpl::ProcessMouseAck(blink::WebInputEvent::Type type,
556 InputEventAckState ack_result) {
557 if (type != WebInputEvent::MouseMove)
558 return;
560 DCHECK(mouse_move_pending_);
561 mouse_move_pending_ = false;
563 if (next_mouse_move_) {
564 DCHECK(next_mouse_move_->event.type == WebInputEvent::MouseMove);
565 scoped_ptr<MouseEventWithLatencyInfo> next_mouse_move
566 = next_mouse_move_.Pass();
567 SendMouseEvent(*next_mouse_move);
571 void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result,
572 const ui::LatencyInfo& latency) {
573 // TODO(miletus): Add renderer side latency to each uncoalesced mouse
574 // wheel event and add terminal component to each of them.
575 current_wheel_event_.latency.AddNewLatencyFrom(latency);
577 // Process the unhandled wheel event here before calling SendWheelEvent()
578 // since it will mutate current_wheel_event_.
579 ack_handler_->OnWheelEventAck(current_wheel_event_, ack_result);
581 // Mark the wheel event complete only after the ACKs have been handled above.
582 // For example, ACKing the GesturePinchUpdate could cause another
583 // GesturePinchUpdate to be sent, which should queue a wheel event rather than
584 // send it immediately.
585 mouse_wheel_pending_ = false;
587 // Send the next (coalesced or synthetic) mouse wheel event.
588 if (!coalesced_mouse_wheel_events_.empty()) {
589 MouseWheelEventWithLatencyInfo next_wheel_event =
590 coalesced_mouse_wheel_events_.front();
591 coalesced_mouse_wheel_events_.pop_front();
592 SendWheelEvent(next_wheel_event);
596 void InputRouterImpl::ProcessGestureAck(WebInputEvent::Type type,
597 InputEventAckState ack_result,
598 const ui::LatencyInfo& latency) {
599 if (type == blink::WebInputEvent::GestureFlingStart &&
600 ack_result == INPUT_EVENT_ACK_STATE_CONSUMED) {
601 ++active_renderer_fling_count_;
604 // |gesture_event_queue_| will forward to OnGestureEventAck when appropriate.
605 gesture_event_queue_.ProcessGestureAck(ack_result, type, latency);
608 void InputRouterImpl::ProcessTouchAck(InputEventAckState ack_result,
609 const ui::LatencyInfo& latency,
610 uint32 unique_touch_event_id) {
611 // |touch_event_queue_| will forward to OnTouchEventAck when appropriate.
612 touch_event_queue_.ProcessTouchAck(ack_result, latency,
613 unique_touch_event_id);
616 void InputRouterImpl::UpdateTouchAckTimeoutEnabled() {
617 // TOUCH_ACTION_NONE will prevent scrolling, in which case the timeout serves
618 // little purpose. It's also a strong signal that touch handling is critical
619 // to page functionality, so the timeout could do more harm than good.
620 const bool touch_ack_timeout_enabled =
621 touch_action_filter_.allowed_touch_action() != TOUCH_ACTION_NONE;
622 touch_event_queue_.SetAckTimeoutEnabled(touch_ack_timeout_enabled);
625 void InputRouterImpl::SignalFlushedIfNecessary() {
626 if (!flush_requested_)
627 return;
629 if (HasPendingEvents())
630 return;
632 flush_requested_ = false;
633 client_->DidFlush();
636 } // namespace content