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"
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"
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
;
46 const char* GetEventAckName(InputEventAckState 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.";
60 InputRouterImpl::Config::Config() {
63 InputRouterImpl::InputRouterImpl(IPC::Sender
* sender
,
64 InputRouterClient
* client
,
65 InputAckHandler
* ack_handler
,
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
) {
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.";
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
))
114 if (mouse_event
.event
.type
== WebInputEvent::MouseUp
&&
115 gesture_event_queue_
.GetTouchpadTapSuppressionController()->
116 ShouldSuppressMouseUp())
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
);
138 coalesced_mouse_wheel_events_
.back().CoalesceWith(wheel_event
);
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
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
))
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
));
201 next_mouse_move_
->CoalesceWith(mouse_event
);
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())
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
) {
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
,
264 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers
,
265 OnHasTouchEventHandlers
)
266 IPC_MESSAGE_HANDLER(InputHostMsg_SetTouchAction
,
268 IPC_MESSAGE_HANDLER(InputHostMsg_DidStopFlinging
, OnDidStopFlinging
)
269 IPC_MESSAGE_UNHANDLED(handled
= false)
270 IPC_END_MESSAGE_MAP()
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
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());
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();
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",
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
))
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.
393 case INPUT_EVENT_ACK_STATE_UNKNOWN
:
394 // Simply drop the event.
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();
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.
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.
516 base::AutoReset
<AckSource
> auto_reset_current_ack_source(
517 ¤t_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.
542 ack_handler_
->OnUnexpectedEventAck(InputAckHandler::UNEXPECTED_EVENT_TYPE
);
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
)
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_
)
629 if (HasPendingEvents())
632 flush_requested_
= false;
636 } // namespace content