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_view_flags_(0),
77 current_ack_source_(ACK_SOURCE_NONE
),
78 flush_requested_(false),
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 // Only forward the non-native portions of our event.
162 FilterAndSendWebInputEvent(key_event
, latency_info
, is_keyboard_shortcut
);
165 void InputRouterImpl::SendGestureEvent(
166 const GestureEventWithLatencyInfo
& original_gesture_event
) {
167 input_stream_validator_
.Validate(original_gesture_event
.event
);
169 GestureEventWithLatencyInfo
gesture_event(original_gesture_event
);
171 if (touch_action_filter_
.FilterGestureEvent(&gesture_event
.event
))
174 if (gesture_event
.event
.sourceDevice
== blink::WebGestureDeviceTouchscreen
)
175 touch_event_queue_
.OnGestureScrollEvent(gesture_event
);
177 gesture_event_queue_
.QueueEvent(gesture_event
);
180 void InputRouterImpl::SendTouchEvent(
181 const TouchEventWithLatencyInfo
& touch_event
) {
182 input_stream_validator_
.Validate(touch_event
.event
);
183 touch_event_queue_
.QueueEvent(touch_event
);
186 // Forwards MouseEvent without passing it through
187 // TouchpadTapSuppressionController.
188 void InputRouterImpl::SendMouseEventImmediately(
189 const MouseEventWithLatencyInfo
& mouse_event
) {
190 // Avoid spamming the renderer with mouse move events. It is important
191 // to note that WM_MOUSEMOVE events are anyways synthetic, but since our
192 // thread is able to rapidly consume WM_MOUSEMOVE events, we may get way
193 // more WM_MOUSEMOVE events than we wish to send to the renderer.
194 if (mouse_event
.event
.type
== WebInputEvent::MouseMove
) {
195 if (mouse_move_pending_
) {
196 if (!next_mouse_move_
)
197 next_mouse_move_
.reset(new MouseEventWithLatencyInfo(mouse_event
));
199 next_mouse_move_
->CoalesceWith(mouse_event
);
202 mouse_move_pending_
= true;
205 FilterAndSendWebInputEvent(mouse_event
.event
, mouse_event
.latency
, false);
208 void InputRouterImpl::SendTouchEventImmediately(
209 const TouchEventWithLatencyInfo
& touch_event
) {
210 if (WebTouchEventTraits::IsTouchSequenceStart(touch_event
.event
)) {
211 touch_action_filter_
.ResetTouchAction();
212 // Note that if the previous touch-action was TOUCH_ACTION_NONE, enabling
213 // the timeout here will not take effect until the *following* touch
214 // sequence. This is a desirable side-effect, giving the renderer a chance
215 // to send a touch-action response without racing against the ack timeout.
216 UpdateTouchAckTimeoutEnabled();
219 FilterAndSendWebInputEvent(touch_event
.event
, touch_event
.latency
, false);
222 void InputRouterImpl::SendGestureEventImmediately(
223 const GestureEventWithLatencyInfo
& gesture_event
) {
224 FilterAndSendWebInputEvent(gesture_event
.event
, gesture_event
.latency
, false);
227 const NativeWebKeyboardEvent
* InputRouterImpl::GetLastKeyboardEvent() const {
228 if (key_queue_
.empty())
230 return &key_queue_
.front();
233 void InputRouterImpl::OnViewUpdated(int view_flags
) {
234 current_view_flags_
= view_flags
;
236 // A fixed page scale or mobile viewport should disable the touch ack timeout.
237 UpdateTouchAckTimeoutEnabled();
240 void InputRouterImpl::RequestNotificationWhenFlushed() {
241 flush_requested_
= true;
242 SignalFlushedIfNecessary();
245 bool InputRouterImpl::HasPendingEvents() const {
246 return !touch_event_queue_
.empty() ||
247 !gesture_event_queue_
.empty() ||
248 gesture_event_queue_
.active_fling_count() ||
249 !key_queue_
.empty() ||
250 mouse_move_pending_
||
251 mouse_wheel_pending_
||
252 select_message_pending_
||
256 bool InputRouterImpl::OnMessageReceived(const IPC::Message
& message
) {
258 IPC_BEGIN_MESSAGE_MAP(InputRouterImpl
, message
)
259 IPC_MESSAGE_HANDLER(InputHostMsg_HandleInputEvent_ACK
, OnInputEventAck
)
260 IPC_MESSAGE_HANDLER(InputHostMsg_DidOverscroll
, OnDidOverscroll
)
261 IPC_MESSAGE_HANDLER(InputHostMsg_MoveCaret_ACK
, OnMsgMoveCaretAck
)
262 IPC_MESSAGE_HANDLER(InputHostMsg_SelectRange_ACK
, OnSelectMessageAck
)
263 IPC_MESSAGE_HANDLER(InputHostMsg_MoveRangeSelectionExtent_ACK
,
265 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers
,
266 OnHasTouchEventHandlers
)
267 IPC_MESSAGE_HANDLER(InputHostMsg_SetTouchAction
,
269 IPC_MESSAGE_HANDLER(InputHostMsg_DidStopFlinging
, OnDidStopFlinging
)
270 IPC_MESSAGE_UNHANDLED(handled
= false)
271 IPC_END_MESSAGE_MAP()
276 void InputRouterImpl::OnTouchEventAck(const TouchEventWithLatencyInfo
& event
,
277 InputEventAckState ack_result
) {
278 // Touchstart events sent to the renderer indicate a new touch sequence, but
279 // in some cases we may filter out sending the touchstart - catch those here.
280 if (WebTouchEventTraits::IsTouchSequenceStart(event
.event
) &&
281 ack_result
== INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
) {
282 touch_action_filter_
.ResetTouchAction();
283 UpdateTouchAckTimeoutEnabled();
285 ack_handler_
->OnTouchEventAck(event
, ack_result
);
288 void InputRouterImpl::OnGestureEventAck(
289 const GestureEventWithLatencyInfo
& event
,
290 InputEventAckState ack_result
) {
291 touch_event_queue_
.OnGestureEventAck(event
, ack_result
);
292 ack_handler_
->OnGestureEventAck(event
, ack_result
);
295 bool InputRouterImpl::SendSelectMessage(
296 scoped_ptr
<IPC::Message
> message
) {
297 DCHECK(message
->type() == InputMsg_SelectRange::ID
||
298 message
->type() == InputMsg_MoveRangeSelectionExtent::ID
);
300 // TODO(jdduke): Factor out common logic between selection and caret-related
302 if (select_message_pending_
) {
303 if (!pending_select_messages_
.empty() &&
304 pending_select_messages_
.back()->type() == message
->type()) {
305 delete pending_select_messages_
.back();
306 pending_select_messages_
.pop_back();
309 pending_select_messages_
.push_back(message
.release());
313 select_message_pending_
= true;
314 return Send(message
.release());
317 bool InputRouterImpl::SendMoveCaret(scoped_ptr
<IPC::Message
> message
) {
318 DCHECK(message
->type() == InputMsg_MoveCaret::ID
);
319 if (move_caret_pending_
) {
320 next_move_caret_
= message
.Pass();
324 move_caret_pending_
= true;
325 return Send(message
.release());
328 bool InputRouterImpl::Send(IPC::Message
* message
) {
329 return sender_
->Send(message
);
332 void InputRouterImpl::FilterAndSendWebInputEvent(
333 const WebInputEvent
& input_event
,
334 const ui::LatencyInfo
& latency_info
,
335 bool is_keyboard_shortcut
) {
336 TRACE_EVENT1("input",
337 "InputRouterImpl::FilterAndSendWebInputEvent",
339 WebInputEventTraits::GetName(input_event
.type
));
341 // Any input event cancels a pending mouse move event.
342 next_mouse_move_
.reset();
344 OfferToHandlers(input_event
, latency_info
, is_keyboard_shortcut
);
347 void InputRouterImpl::OfferToHandlers(const WebInputEvent
& input_event
,
348 const ui::LatencyInfo
& latency_info
,
349 bool is_keyboard_shortcut
) {
350 output_stream_validator_
.Validate(input_event
);
352 if (OfferToClient(input_event
, latency_info
))
355 OfferToRenderer(input_event
, latency_info
, is_keyboard_shortcut
);
357 // Touch events should always indicate in the event whether they are
358 // cancelable (respect ACK disposition) or not.
359 bool ignores_ack
= WebInputEventTraits::IgnoresAckDisposition(input_event
);
360 if (WebInputEvent::isTouchEventType(input_event
.type
)) {
361 const WebTouchEvent
& touch
= static_cast<const WebTouchEvent
&>(input_event
);
362 DCHECK_NE(ignores_ack
, !!touch
.cancelable
);
365 // If we don't care about the ack disposition, send the ack immediately.
367 ProcessInputEventAck(input_event
.type
,
368 INPUT_EVENT_ACK_STATE_IGNORED
,
370 IGNORING_DISPOSITION
);
374 bool InputRouterImpl::OfferToClient(const WebInputEvent
& input_event
,
375 const ui::LatencyInfo
& latency_info
) {
376 bool consumed
= false;
378 InputEventAckState filter_ack
=
379 client_
->FilterInputEvent(input_event
, latency_info
);
380 switch (filter_ack
) {
381 case INPUT_EVENT_ACK_STATE_CONSUMED
:
382 case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
:
383 // Send the ACK and early exit.
384 next_mouse_move_
.reset();
385 ProcessInputEventAck(input_event
.type
, filter_ack
, latency_info
, CLIENT
);
386 // WARNING: |this| may be deleted at this point.
389 case INPUT_EVENT_ACK_STATE_UNKNOWN
:
390 // Simply drop the event.
400 bool InputRouterImpl::OfferToRenderer(const WebInputEvent
& input_event
,
401 const ui::LatencyInfo
& latency_info
,
402 bool is_keyboard_shortcut
) {
403 if (Send(new InputMsg_HandleInputEvent(
404 routing_id(), &input_event
, latency_info
, is_keyboard_shortcut
))) {
405 // Ack messages for ignored ack event types should never be sent by the
406 // renderer. Consequently, such event types should not affect event time
407 // or in-flight event count metrics.
408 if (!WebInputEventTraits::IgnoresAckDisposition(input_event
)) {
409 input_event_start_time_
= TimeTicks::Now();
410 client_
->IncrementInFlightEventCount();
417 void InputRouterImpl::OnInputEventAck(
418 const InputHostMsg_HandleInputEvent_ACK_Params
& ack
) {
419 client_
->DecrementInFlightEventCount();
421 // Log the time delta for processing an input event.
422 TimeDelta delta
= TimeTicks::Now() - input_event_start_time_
;
423 UMA_HISTOGRAM_TIMES("MPArch.IIR_InputEventDelta", delta
);
425 if (ack
.overscroll
) {
426 DCHECK(ack
.type
== WebInputEvent::MouseWheel
||
427 ack
.type
== WebInputEvent::GestureScrollUpdate
);
428 OnDidOverscroll(*ack
.overscroll
);
431 ProcessInputEventAck(ack
.type
, ack
.state
, ack
.latency
, RENDERER
);
432 // WARNING: |this| may be deleted at this point.
434 // This is used only for testing, and the other end does not use the
435 // source object. On linux, specifying
436 // Source<RenderWidgetHost> results in a very strange
437 // runtime error in the epilogue of the enclosing
438 // (ProcessInputEventAck) method, but not on other platforms; using
439 // 'void' instead is just as safe (since NotificationSource
440 // is not actually typesafe) and avoids this error.
441 int type
= static_cast<int>(ack
.type
);
442 NotificationService::current()->Notify(
443 NOTIFICATION_RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK
,
445 Details
<int>(&type
));
448 void InputRouterImpl::OnDidOverscroll(const DidOverscrollParams
& params
) {
449 client_
->DidOverscroll(params
);
452 void InputRouterImpl::OnMsgMoveCaretAck() {
453 move_caret_pending_
= false;
454 if (next_move_caret_
)
455 SendMoveCaret(next_move_caret_
.Pass());
458 void InputRouterImpl::OnSelectMessageAck() {
459 select_message_pending_
= false;
460 if (!pending_select_messages_
.empty()) {
461 scoped_ptr
<IPC::Message
> next_message
=
462 make_scoped_ptr(pending_select_messages_
.front());
463 pending_select_messages_
.pop_front();
465 SendSelectMessage(next_message
.Pass());
469 void InputRouterImpl::OnHasTouchEventHandlers(bool has_handlers
) {
470 TRACE_EVENT1("input", "InputRouterImpl::OnHasTouchEventHandlers",
471 "has_handlers", has_handlers
);
473 // Lack of a touch handler indicates that the page either has no touch-action
474 // modifiers or that all its touch-action modifiers are auto. Resetting the
475 // touch-action here allows forwarding of subsequent gestures even if the
476 // underlying touches never reach the router.
477 // TODO(jdduke): Reset touch-action only at the end of a touch sequence to
478 // prevent potentially strange mid-sequence behavior, crbug.com/375940.
480 touch_action_filter_
.ResetTouchAction();
482 touch_event_queue_
.OnHasTouchEventHandlers(has_handlers
);
483 client_
->OnHasTouchEventHandlers(has_handlers
);
486 void InputRouterImpl::OnSetTouchAction(TouchAction touch_action
) {
487 // Synthetic touchstart events should get filtered out in RenderWidget.
488 DCHECK(touch_event_queue_
.IsPendingAckTouchStart());
489 TRACE_EVENT1("input", "InputRouterImpl::OnSetTouchAction",
490 "action", touch_action
);
492 touch_action_filter_
.OnSetTouchAction(touch_action
);
494 // TOUCH_ACTION_NONE should disable the touch ack timeout.
495 UpdateTouchAckTimeoutEnabled();
498 void InputRouterImpl::OnDidStopFlinging() {
499 gesture_event_queue_
.DidStopFlinging();
500 SignalFlushedIfNecessary();
501 client_
->DidStopFlinging();
504 void InputRouterImpl::ProcessInputEventAck(
505 WebInputEvent::Type event_type
,
506 InputEventAckState ack_result
,
507 const ui::LatencyInfo
& latency_info
,
508 AckSource ack_source
) {
509 TRACE_EVENT2("input", "InputRouterImpl::ProcessInputEventAck",
510 "type", WebInputEventTraits::GetName(event_type
),
511 "ack", GetEventAckName(ack_result
));
513 // Note: The keyboard ack must be treated carefully, as it may result in
514 // synchronous destruction of |this|. Handling immediately guards against
515 // future references to |this|, as with |auto_reset_current_ack_source| below.
516 if (WebInputEvent::isKeyboardEventType(event_type
)) {
517 ProcessKeyboardAck(event_type
, ack_result
);
518 // WARNING: |this| may be deleted at this point.
522 base::AutoReset
<AckSource
> auto_reset_current_ack_source(
523 ¤t_ack_source_
, ack_source
);
525 if (WebInputEvent::isMouseEventType(event_type
)) {
526 ProcessMouseAck(event_type
, ack_result
);
527 } else if (event_type
== WebInputEvent::MouseWheel
) {
528 ProcessWheelAck(ack_result
, latency_info
);
529 } else if (WebInputEvent::isTouchEventType(event_type
)) {
530 ProcessTouchAck(ack_result
, latency_info
);
531 } else if (WebInputEvent::isGestureEventType(event_type
)) {
532 ProcessGestureAck(event_type
, ack_result
, latency_info
);
533 } else if (event_type
!= WebInputEvent::Undefined
) {
534 ack_handler_
->OnUnexpectedEventAck(InputAckHandler::BAD_ACK_MESSAGE
);
537 SignalFlushedIfNecessary();
540 void InputRouterImpl::ProcessKeyboardAck(blink::WebInputEvent::Type type
,
541 InputEventAckState ack_result
) {
542 if (key_queue_
.empty()) {
543 ack_handler_
->OnUnexpectedEventAck(InputAckHandler::UNEXPECTED_ACK
);
544 } else if (key_queue_
.front().type
!= type
) {
545 // Something must be wrong. Clear the |key_queue_| and char event
546 // suppression so that we can resume from the error.
548 ack_handler_
->OnUnexpectedEventAck(InputAckHandler::UNEXPECTED_EVENT_TYPE
);
550 NativeWebKeyboardEvent front_item
= key_queue_
.front();
551 key_queue_
.pop_front();
553 ack_handler_
->OnKeyboardEventAck(front_item
, ack_result
);
554 // WARNING: This InputRouterImpl can be deallocated at this point
555 // (i.e. in the case of Ctrl+W, where the call to
556 // HandleKeyboardEvent destroys this InputRouterImpl).
557 // TODO(jdduke): crbug.com/274029 - Make ack-triggered shutdown async.
561 void InputRouterImpl::ProcessMouseAck(blink::WebInputEvent::Type type
,
562 InputEventAckState ack_result
) {
563 if (type
!= WebInputEvent::MouseMove
)
566 DCHECK(mouse_move_pending_
);
567 mouse_move_pending_
= false;
569 if (next_mouse_move_
) {
570 DCHECK(next_mouse_move_
->event
.type
== WebInputEvent::MouseMove
);
571 scoped_ptr
<MouseEventWithLatencyInfo
> next_mouse_move
572 = next_mouse_move_
.Pass();
573 SendMouseEvent(*next_mouse_move
);
577 void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result
,
578 const ui::LatencyInfo
& latency
) {
579 // TODO(miletus): Add renderer side latency to each uncoalesced mouse
580 // wheel event and add terminal component to each of them.
581 current_wheel_event_
.latency
.AddNewLatencyFrom(latency
);
583 // Process the unhandled wheel event here before calling SendWheelEvent()
584 // since it will mutate current_wheel_event_.
585 ack_handler_
->OnWheelEventAck(current_wheel_event_
, ack_result
);
587 // Mark the wheel event complete only after the ACKs have been handled above.
588 // For example, ACKing the GesturePinchUpdate could cause another
589 // GesturePinchUpdate to be sent, which should queue a wheel event rather than
590 // send it immediately.
591 mouse_wheel_pending_
= false;
593 // Send the next (coalesced or synthetic) mouse wheel event.
594 if (!coalesced_mouse_wheel_events_
.empty()) {
595 MouseWheelEventWithLatencyInfo next_wheel_event
=
596 coalesced_mouse_wheel_events_
.front();
597 coalesced_mouse_wheel_events_
.pop_front();
598 SendWheelEvent(next_wheel_event
);
602 void InputRouterImpl::ProcessGestureAck(WebInputEvent::Type type
,
603 InputEventAckState ack_result
,
604 const ui::LatencyInfo
& latency
) {
605 // |gesture_event_queue_| will forward to OnGestureEventAck when appropriate.
606 gesture_event_queue_
.ProcessGestureAck(ack_result
, type
, latency
);
609 void InputRouterImpl::ProcessTouchAck(
610 InputEventAckState ack_result
,
611 const ui::LatencyInfo
& latency
) {
612 // |touch_event_queue_| will forward to OnTouchEventAck when appropriate.
613 touch_event_queue_
.ProcessTouchAck(ack_result
, latency
);
616 void InputRouterImpl::UpdateTouchAckTimeoutEnabled() {
617 // Mobile sites tend to be well-behaved with respect to touch handling, so
618 // they have less need for the touch timeout fallback.
619 const bool fixed_page_scale
= (current_view_flags_
& FIXED_PAGE_SCALE
) != 0;
620 const bool mobile_viewport
= (current_view_flags_
& MOBILE_VIEWPORT
) != 0;
622 // TOUCH_ACTION_NONE will prevent scrolling, in which case the timeout serves
623 // little purpose. It's also a strong signal that touch handling is critical
624 // to page functionality, so the timeout could do more harm than good.
625 const bool touch_action_none
=
626 touch_action_filter_
.allowed_touch_action() == TOUCH_ACTION_NONE
;
628 const bool touch_ack_timeout_enabled
= !fixed_page_scale
&&
631 touch_event_queue_
.SetAckTimeoutEnabled(touch_ack_timeout_enabled
);
634 void InputRouterImpl::SignalFlushedIfNecessary() {
635 if (!flush_requested_
)
638 if (HasPendingEvents())
641 flush_requested_
= false;
645 } // namespace content