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
);
139 TRACE_EVENT_INSTANT2("input", "InputRouterImpl::CoalescedWheelEvent",
140 TRACE_EVENT_SCOPE_THREAD
,
142 coalesced_mouse_wheel_events_
.back().event
.deltaX
,
144 coalesced_mouse_wheel_events_
.back().event
.deltaY
);
149 mouse_wheel_pending_
= true;
150 current_wheel_event_
= wheel_event
;
152 LOCAL_HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize",
153 coalesced_mouse_wheel_events_
.size());
155 FilterAndSendWebInputEvent(wheel_event
.event
, wheel_event
.latency
, false);
158 void InputRouterImpl::SendKeyboardEvent(
159 const NativeWebKeyboardEventWithLatencyInfo
& key_event
,
160 bool is_keyboard_shortcut
) {
161 // Put all WebKeyboardEvent objects in a queue since we can't trust the
162 // renderer and we need to give something to the HandleKeyboardEvent
164 key_queue_
.push_back(key_event
);
165 LOCAL_HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_
.size());
167 gesture_event_queue_
.FlingHasBeenHalted();
169 // Only forward the non-native portions of our event.
170 FilterAndSendWebInputEvent(key_event
.event
,
172 is_keyboard_shortcut
);
175 void InputRouterImpl::SendGestureEvent(
176 const GestureEventWithLatencyInfo
& original_gesture_event
) {
177 input_stream_validator_
.Validate(original_gesture_event
.event
);
179 GestureEventWithLatencyInfo
gesture_event(original_gesture_event
);
181 if (touch_action_filter_
.FilterGestureEvent(&gesture_event
.event
))
184 if (gesture_event
.event
.sourceDevice
== blink::WebGestureDeviceTouchscreen
)
185 touch_event_queue_
.OnGestureScrollEvent(gesture_event
);
187 gesture_event_queue_
.QueueEvent(gesture_event
);
190 void InputRouterImpl::SendTouchEvent(
191 const TouchEventWithLatencyInfo
& touch_event
) {
192 input_stream_validator_
.Validate(touch_event
.event
);
193 touch_event_queue_
.QueueEvent(touch_event
);
196 // Forwards MouseEvent without passing it through
197 // TouchpadTapSuppressionController.
198 void InputRouterImpl::SendMouseEventImmediately(
199 const MouseEventWithLatencyInfo
& mouse_event
) {
200 // Avoid spamming the renderer with mouse move events. It is important
201 // to note that WM_MOUSEMOVE events are anyways synthetic, but since our
202 // thread is able to rapidly consume WM_MOUSEMOVE events, we may get way
203 // more WM_MOUSEMOVE events than we wish to send to the renderer.
204 if (mouse_event
.event
.type
== WebInputEvent::MouseMove
) {
205 if (mouse_move_pending_
) {
206 if (!next_mouse_move_
)
207 next_mouse_move_
.reset(new MouseEventWithLatencyInfo(mouse_event
));
209 next_mouse_move_
->CoalesceWith(mouse_event
);
212 mouse_move_pending_
= true;
213 current_mouse_move_
= mouse_event
;
216 FilterAndSendWebInputEvent(mouse_event
.event
, mouse_event
.latency
, false);
219 void InputRouterImpl::SendTouchEventImmediately(
220 const TouchEventWithLatencyInfo
& touch_event
) {
221 if (WebTouchEventTraits::IsTouchSequenceStart(touch_event
.event
)) {
222 touch_action_filter_
.ResetTouchAction();
223 // Note that if the previous touch-action was TOUCH_ACTION_NONE, enabling
224 // the timeout here will not take effect until the *following* touch
225 // sequence. This is a desirable side-effect, giving the renderer a chance
226 // to send a touch-action response without racing against the ack timeout.
227 UpdateTouchAckTimeoutEnabled();
230 FilterAndSendWebInputEvent(touch_event
.event
, touch_event
.latency
, false);
233 void InputRouterImpl::SendGestureEventImmediately(
234 const GestureEventWithLatencyInfo
& gesture_event
) {
235 FilterAndSendWebInputEvent(gesture_event
.event
, gesture_event
.latency
, false);
238 const NativeWebKeyboardEvent
* InputRouterImpl::GetLastKeyboardEvent() const {
239 if (key_queue_
.empty())
241 return &key_queue_
.front().event
;
244 void InputRouterImpl::NotifySiteIsMobileOptimized(bool is_mobile_optimized
) {
245 touch_event_queue_
.SetIsMobileOptimizedSite(is_mobile_optimized
);
248 void InputRouterImpl::RequestNotificationWhenFlushed() {
249 flush_requested_
= true;
250 SignalFlushedIfNecessary();
253 bool InputRouterImpl::HasPendingEvents() const {
254 return !touch_event_queue_
.empty() ||
255 !gesture_event_queue_
.empty() ||
256 !key_queue_
.empty() ||
257 mouse_move_pending_
||
258 mouse_wheel_pending_
||
259 select_message_pending_
||
260 move_caret_pending_
||
261 active_renderer_fling_count_
> 0;
264 bool InputRouterImpl::OnMessageReceived(const IPC::Message
& message
) {
266 IPC_BEGIN_MESSAGE_MAP(InputRouterImpl
, message
)
267 IPC_MESSAGE_HANDLER(InputHostMsg_HandleInputEvent_ACK
, OnInputEventAck
)
268 IPC_MESSAGE_HANDLER(InputHostMsg_DidOverscroll
, OnDidOverscroll
)
269 IPC_MESSAGE_HANDLER(InputHostMsg_MoveCaret_ACK
, OnMsgMoveCaretAck
)
270 IPC_MESSAGE_HANDLER(InputHostMsg_SelectRange_ACK
, OnSelectMessageAck
)
271 IPC_MESSAGE_HANDLER(InputHostMsg_MoveRangeSelectionExtent_ACK
,
273 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers
,
274 OnHasTouchEventHandlers
)
275 IPC_MESSAGE_HANDLER(InputHostMsg_SetTouchAction
,
277 IPC_MESSAGE_HANDLER(InputHostMsg_DidStopFlinging
, OnDidStopFlinging
)
278 IPC_MESSAGE_UNHANDLED(handled
= false)
279 IPC_END_MESSAGE_MAP()
284 void InputRouterImpl::OnTouchEventAck(const TouchEventWithLatencyInfo
& event
,
285 InputEventAckState ack_result
) {
286 // Touchstart events sent to the renderer indicate a new touch sequence, but
287 // in some cases we may filter out sending the touchstart - catch those here.
288 if (WebTouchEventTraits::IsTouchSequenceStart(event
.event
) &&
289 ack_result
== INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
) {
290 touch_action_filter_
.ResetTouchAction();
291 UpdateTouchAckTimeoutEnabled();
293 ack_handler_
->OnTouchEventAck(event
, ack_result
);
296 void InputRouterImpl::OnGestureEventAck(
297 const GestureEventWithLatencyInfo
& event
,
298 InputEventAckState ack_result
) {
299 touch_event_queue_
.OnGestureEventAck(event
, ack_result
);
300 ack_handler_
->OnGestureEventAck(event
, ack_result
);
303 bool InputRouterImpl::SendSelectMessage(
304 scoped_ptr
<IPC::Message
> message
) {
305 DCHECK(message
->type() == InputMsg_SelectRange::ID
||
306 message
->type() == InputMsg_MoveRangeSelectionExtent::ID
);
308 // TODO(jdduke): Factor out common logic between selection and caret-related
310 if (select_message_pending_
) {
311 if (!pending_select_messages_
.empty() &&
312 pending_select_messages_
.back()->type() == message
->type()) {
313 delete pending_select_messages_
.back();
314 pending_select_messages_
.pop_back();
317 pending_select_messages_
.push_back(message
.release());
321 select_message_pending_
= true;
322 return Send(message
.release());
325 bool InputRouterImpl::SendMoveCaret(scoped_ptr
<IPC::Message
> message
) {
326 DCHECK(message
->type() == InputMsg_MoveCaret::ID
);
327 if (move_caret_pending_
) {
328 next_move_caret_
= message
.Pass();
332 move_caret_pending_
= true;
333 return Send(message
.release());
336 bool InputRouterImpl::Send(IPC::Message
* message
) {
337 return sender_
->Send(message
);
340 void InputRouterImpl::FilterAndSendWebInputEvent(
341 const WebInputEvent
& input_event
,
342 const ui::LatencyInfo
& latency_info
,
343 bool is_keyboard_shortcut
) {
344 TRACE_EVENT1("input",
345 "InputRouterImpl::FilterAndSendWebInputEvent",
347 WebInputEventTraits::GetName(input_event
.type
));
348 TRACE_EVENT_WITH_FLOW1("input,benchmark",
350 TRACE_ID_DONT_MANGLE(latency_info
.trace_id()),
351 TRACE_EVENT_FLAG_FLOW_IN
| TRACE_EVENT_FLAG_FLOW_OUT
,
352 "step", "SendInputEventUI");
354 // Any input event cancels a pending mouse move event.
355 next_mouse_move_
.reset();
357 OfferToHandlers(input_event
, latency_info
, is_keyboard_shortcut
);
360 void InputRouterImpl::OfferToHandlers(const WebInputEvent
& input_event
,
361 const ui::LatencyInfo
& latency_info
,
362 bool is_keyboard_shortcut
) {
363 output_stream_validator_
.Validate(input_event
);
365 if (OfferToClient(input_event
, latency_info
))
368 OfferToRenderer(input_event
, latency_info
, is_keyboard_shortcut
);
370 // Touch events should always indicate in the event whether they are
371 // cancelable (respect ACK disposition) or not except touchmove.
372 bool needs_synthetic_ack
=
373 !WebInputEventTraits::WillReceiveAckFromRenderer(input_event
);
375 if (WebInputEvent::isTouchEventType(input_event
.type
) &&
376 input_event
.type
!= WebInputEvent::TouchMove
) {
377 const WebTouchEvent
& touch
= static_cast<const WebTouchEvent
&>(input_event
);
378 DCHECK_EQ(needs_synthetic_ack
, !touch
.cancelable
);
381 // The synthetic acks are sent immediately.
382 if (needs_synthetic_ack
) {
383 ProcessInputEventAck(
384 input_event
.type
, INPUT_EVENT_ACK_STATE_IGNORED
, latency_info
,
385 WebInputEventTraits::GetUniqueTouchEventId(input_event
),
386 IGNORING_DISPOSITION
);
390 bool InputRouterImpl::OfferToClient(const WebInputEvent
& input_event
,
391 const ui::LatencyInfo
& latency_info
) {
392 bool consumed
= false;
394 InputEventAckState filter_ack
=
395 client_
->FilterInputEvent(input_event
, latency_info
);
396 switch (filter_ack
) {
397 case INPUT_EVENT_ACK_STATE_CONSUMED
:
398 case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
:
399 // Send the ACK and early exit.
400 next_mouse_move_
.reset();
401 ProcessInputEventAck(
402 input_event
.type
, filter_ack
, latency_info
,
403 WebInputEventTraits::GetUniqueTouchEventId(input_event
), CLIENT
);
404 // WARNING: |this| may be deleted at this point.
407 case INPUT_EVENT_ACK_STATE_UNKNOWN
:
408 // Simply drop the event.
418 bool InputRouterImpl::OfferToRenderer(const WebInputEvent
& input_event
,
419 const ui::LatencyInfo
& latency_info
,
420 bool is_keyboard_shortcut
) {
421 if (Send(new InputMsg_HandleInputEvent(
422 routing_id(), &input_event
, latency_info
, is_keyboard_shortcut
))) {
423 // Ack messages for ignored ack event types should never be sent by the
424 // renderer. Consequently, such event types should not affect event time
425 // or in-flight event count metrics.
426 if (WebInputEventTraits::WillReceiveAckFromRenderer(input_event
)) {
427 input_event_start_time_
= TimeTicks::Now();
428 client_
->IncrementInFlightEventCount();
435 void InputRouterImpl::OnInputEventAck(const InputEventAck
& ack
) {
436 client_
->DecrementInFlightEventCount();
437 // Log the time delta for processing an input event.
438 TimeDelta delta
= TimeTicks::Now() - input_event_start_time_
;
439 UMA_HISTOGRAM_TIMES("MPArch.IIR_InputEventDelta", delta
);
441 if (ack
.overscroll
) {
442 DCHECK(ack
.type
== WebInputEvent::MouseWheel
||
443 ack
.type
== WebInputEvent::GestureScrollUpdate
);
444 OnDidOverscroll(*ack
.overscroll
);
447 ProcessInputEventAck(ack
.type
, ack
.state
, ack
.latency
,
448 ack
.unique_touch_event_id
, RENDERER
);
451 void InputRouterImpl::OnDidOverscroll(const DidOverscrollParams
& params
) {
452 client_
->DidOverscroll(params
);
455 void InputRouterImpl::OnMsgMoveCaretAck() {
456 move_caret_pending_
= false;
457 if (next_move_caret_
)
458 SendMoveCaret(next_move_caret_
.Pass());
461 void InputRouterImpl::OnSelectMessageAck() {
462 select_message_pending_
= false;
463 if (!pending_select_messages_
.empty()) {
464 scoped_ptr
<IPC::Message
> next_message
=
465 make_scoped_ptr(pending_select_messages_
.front());
466 pending_select_messages_
.pop_front();
468 SendSelectMessage(next_message
.Pass());
472 void InputRouterImpl::OnHasTouchEventHandlers(bool has_handlers
) {
473 TRACE_EVENT1("input", "InputRouterImpl::OnHasTouchEventHandlers",
474 "has_handlers", has_handlers
);
476 // Lack of a touch handler indicates that the page either has no touch-action
477 // modifiers or that all its touch-action modifiers are auto. Resetting the
478 // touch-action here allows forwarding of subsequent gestures even if the
479 // underlying touches never reach the router.
480 // TODO(jdduke): Reset touch-action only at the end of a touch sequence to
481 // prevent potentially strange mid-sequence behavior, crbug.com/375940.
483 touch_action_filter_
.ResetTouchAction();
485 touch_event_queue_
.OnHasTouchEventHandlers(has_handlers
);
486 client_
->OnHasTouchEventHandlers(has_handlers
);
489 void InputRouterImpl::OnSetTouchAction(TouchAction touch_action
) {
490 // Synthetic touchstart events should get filtered out in RenderWidget.
491 DCHECK(touch_event_queue_
.IsPendingAckTouchStart());
492 TRACE_EVENT1("input", "InputRouterImpl::OnSetTouchAction",
493 "action", touch_action
);
495 touch_action_filter_
.OnSetTouchAction(touch_action
);
497 // TOUCH_ACTION_NONE should disable the touch ack timeout.
498 UpdateTouchAckTimeoutEnabled();
501 void InputRouterImpl::OnDidStopFlinging() {
502 DCHECK_GT(active_renderer_fling_count_
, 0);
503 // Note that we're only guaranteed to get a fling end notification from the
504 // renderer, not from any other consumers. Consequently, the GestureEventQueue
505 // cannot use this bookkeeping for logic like tap suppression.
506 --active_renderer_fling_count_
;
507 SignalFlushedIfNecessary();
509 client_
->DidStopFlinging();
512 void InputRouterImpl::ProcessInputEventAck(WebInputEvent::Type event_type
,
513 InputEventAckState ack_result
,
514 const ui::LatencyInfo
& latency_info
,
515 uint32 unique_touch_event_id
,
516 AckSource ack_source
) {
517 TRACE_EVENT2("input", "InputRouterImpl::ProcessInputEventAck",
518 "type", WebInputEventTraits::GetName(event_type
),
519 "ack", GetEventAckName(ack_result
));
521 // Note: The keyboard ack must be treated carefully, as it may result in
522 // synchronous destruction of |this|. Handling immediately guards against
523 // future references to |this|, as with |auto_reset_current_ack_source| below.
524 if (WebInputEvent::isKeyboardEventType(event_type
)) {
525 ProcessKeyboardAck(event_type
, ack_result
, latency_info
);
526 // WARNING: |this| may be deleted at this point.
530 base::AutoReset
<AckSource
> auto_reset_current_ack_source(
531 ¤t_ack_source_
, ack_source
);
533 if (WebInputEvent::isMouseEventType(event_type
)) {
534 ProcessMouseAck(event_type
, ack_result
, latency_info
);
535 } else if (event_type
== WebInputEvent::MouseWheel
) {
536 ProcessWheelAck(ack_result
, latency_info
);
537 } else if (WebInputEvent::isTouchEventType(event_type
)) {
538 ProcessTouchAck(ack_result
, latency_info
, unique_touch_event_id
);
539 } else if (WebInputEvent::isGestureEventType(event_type
)) {
540 ProcessGestureAck(event_type
, ack_result
, latency_info
);
541 } else if (event_type
!= WebInputEvent::Undefined
) {
542 ack_handler_
->OnUnexpectedEventAck(InputAckHandler::BAD_ACK_MESSAGE
);
545 SignalFlushedIfNecessary();
548 void InputRouterImpl::ProcessKeyboardAck(blink::WebInputEvent::Type type
,
549 InputEventAckState ack_result
,
550 const ui::LatencyInfo
& latency
) {
551 if (key_queue_
.empty()) {
552 ack_handler_
->OnUnexpectedEventAck(InputAckHandler::UNEXPECTED_ACK
);
553 } else if (key_queue_
.front().event
.type
!= type
) {
554 // Something must be wrong. Clear the |key_queue_| and char event
555 // suppression so that we can resume from the error.
557 ack_handler_
->OnUnexpectedEventAck(InputAckHandler::UNEXPECTED_EVENT_TYPE
);
559 NativeWebKeyboardEventWithLatencyInfo front_item
= key_queue_
.front();
560 front_item
.latency
.AddNewLatencyFrom(latency
);
561 key_queue_
.pop_front();
563 ack_handler_
->OnKeyboardEventAck(front_item
, ack_result
);
564 // WARNING: This InputRouterImpl can be deallocated at this point
565 // (i.e. in the case of Ctrl+W, where the call to
566 // HandleKeyboardEvent destroys this InputRouterImpl).
567 // TODO(jdduke): crbug.com/274029 - Make ack-triggered shutdown async.
571 void InputRouterImpl::ProcessMouseAck(blink::WebInputEvent::Type type
,
572 InputEventAckState ack_result
,
573 const ui::LatencyInfo
& latency
) {
574 if (type
!= WebInputEvent::MouseMove
)
577 current_mouse_move_
.latency
.AddNewLatencyFrom(latency
);
578 ack_handler_
->OnMouseEventAck(current_mouse_move_
, ack_result
);
580 DCHECK(mouse_move_pending_
);
581 mouse_move_pending_
= false;
583 if (next_mouse_move_
) {
584 DCHECK(next_mouse_move_
->event
.type
== WebInputEvent::MouseMove
);
585 scoped_ptr
<MouseEventWithLatencyInfo
> next_mouse_move
586 = next_mouse_move_
.Pass();
587 SendMouseEvent(*next_mouse_move
);
591 void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result
,
592 const ui::LatencyInfo
& latency
) {
593 // TODO(miletus): Add renderer side latency to each uncoalesced mouse
594 // wheel event and add terminal component to each of them.
595 current_wheel_event_
.latency
.AddNewLatencyFrom(latency
);
597 // Process the unhandled wheel event here before calling SendWheelEvent()
598 // since it will mutate current_wheel_event_.
599 ack_handler_
->OnWheelEventAck(current_wheel_event_
, ack_result
);
601 // Mark the wheel event complete only after the ACKs have been handled above.
602 // For example, ACKing the GesturePinchUpdate could cause another
603 // GesturePinchUpdate to be sent, which should queue a wheel event rather than
604 // send it immediately.
605 mouse_wheel_pending_
= false;
607 // Send the next (coalesced or synthetic) mouse wheel event.
608 if (!coalesced_mouse_wheel_events_
.empty()) {
609 MouseWheelEventWithLatencyInfo next_wheel_event
=
610 coalesced_mouse_wheel_events_
.front();
611 coalesced_mouse_wheel_events_
.pop_front();
612 SendWheelEvent(next_wheel_event
);
616 void InputRouterImpl::ProcessGestureAck(WebInputEvent::Type type
,
617 InputEventAckState ack_result
,
618 const ui::LatencyInfo
& latency
) {
619 if (type
== blink::WebInputEvent::GestureFlingStart
&&
620 ack_result
== INPUT_EVENT_ACK_STATE_CONSUMED
) {
621 ++active_renderer_fling_count_
;
624 // |gesture_event_queue_| will forward to OnGestureEventAck when appropriate.
625 gesture_event_queue_
.ProcessGestureAck(ack_result
, type
, latency
);
628 void InputRouterImpl::ProcessTouchAck(InputEventAckState ack_result
,
629 const ui::LatencyInfo
& latency
,
630 uint32 unique_touch_event_id
) {
631 // |touch_event_queue_| will forward to OnTouchEventAck when appropriate.
632 touch_event_queue_
.ProcessTouchAck(ack_result
, latency
,
633 unique_touch_event_id
);
636 void InputRouterImpl::UpdateTouchAckTimeoutEnabled() {
637 // TOUCH_ACTION_NONE will prevent scrolling, in which case the timeout serves
638 // little purpose. It's also a strong signal that touch handling is critical
639 // to page functionality, so the timeout could do more harm than good.
640 const bool touch_ack_timeout_enabled
=
641 touch_action_filter_
.allowed_touch_action() != TOUCH_ACTION_NONE
;
642 touch_event_queue_
.SetAckTimeoutEnabled(touch_ack_timeout_enabled
);
645 void InputRouterImpl::SignalFlushedIfNecessary() {
646 if (!flush_requested_
)
649 if (HasPendingEvents())
652 flush_requested_
= false;
656 } // namespace content