handoff: Fix the origin so that it correctly reflects the sender.
[chromium-blink-merge.git] / content / browser / renderer_host / input / input_router_impl.cc
blobd6fcb1c4f8be948d350401fd1e234e4bea707931
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_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) {
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 // 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))
172 return;
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));
198 else
199 next_mouse_move_->CoalesceWith(mouse_event);
200 return;
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())
229 return NULL;
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_ ||
253 move_caret_pending_;
256 bool InputRouterImpl::OnMessageReceived(const IPC::Message& message) {
257 bool handled = true;
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,
264 OnSelectMessageAck)
265 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
266 OnHasTouchEventHandlers)
267 IPC_MESSAGE_HANDLER(InputHostMsg_SetTouchAction,
268 OnSetTouchAction)
269 IPC_MESSAGE_HANDLER(InputHostMsg_DidStopFlinging, OnDidStopFlinging)
270 IPC_MESSAGE_UNHANDLED(handled = false)
271 IPC_END_MESSAGE_MAP()
273 return handled;
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
301 // IPC messages.
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());
310 return true;
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();
321 return true;
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",
338 "type",
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))
353 return;
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.
366 if (ignores_ack) {
367 ProcessInputEventAck(input_event.type,
368 INPUT_EVENT_ACK_STATE_IGNORED,
369 latency_info,
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.
387 consumed = true;
388 break;
389 case INPUT_EVENT_ACK_STATE_UNKNOWN:
390 // Simply drop the event.
391 consumed = true;
392 break;
393 default:
394 break;
397 return consumed;
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();
412 return true;
414 return false;
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,
444 Source<void>(this),
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.
479 if (!has_handlers)
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.
519 return;
522 base::AutoReset<AckSource> auto_reset_current_ack_source(
523 &current_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.
547 key_queue_.clear();
548 ack_handler_->OnUnexpectedEventAck(InputAckHandler::UNEXPECTED_EVENT_TYPE);
549 } else {
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)
564 return;
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 &&
629 !mobile_viewport &&
630 !touch_action_none;
631 touch_event_queue_.SetAckTimeoutEnabled(touch_ack_timeout_enabled);
634 void InputRouterImpl::SignalFlushedIfNecessary() {
635 if (!flush_requested_)
636 return;
638 if (HasPendingEvents())
639 return;
641 flush_requested_ = false;
642 client_->DidFlush();
645 } // namespace content