Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / renderer_host / input / input_router_impl.cc
blobb0198962fe284e3a677657e219253e78ec2662a3
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/renderer_host/input/input_router_impl.h"
7 #include <math.h>
9 #include "base/auto_reset.h"
10 #include "base/command_line.h"
11 #include "base/metrics/histogram.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "content/browser/renderer_host/input/gesture_event_queue.h"
14 #include "content/browser/renderer_host/input/input_ack_handler.h"
15 #include "content/browser/renderer_host/input/input_router_client.h"
16 #include "content/browser/renderer_host/input/touch_event_queue.h"
17 #include "content/browser/renderer_host/input/touchpad_tap_suppression_controller.h"
18 #include "content/common/content_constants_internal.h"
19 #include "content/common/edit_command.h"
20 #include "content/common/input/input_event_ack_state.h"
21 #include "content/common/input/touch_action.h"
22 #include "content/common/input/web_touch_event_traits.h"
23 #include "content/common/input_messages.h"
24 #include "content/common/view_messages.h"
25 #include "content/public/browser/notification_service.h"
26 #include "content/public/browser/notification_types.h"
27 #include "content/public/browser/user_metrics.h"
28 #include "content/public/common/content_switches.h"
29 #include "ipc/ipc_sender.h"
30 #include "ui/events/event.h"
31 #include "ui/events/keycodes/keyboard_codes.h"
33 using base::Time;
34 using base::TimeDelta;
35 using base::TimeTicks;
36 using blink::WebGestureEvent;
37 using blink::WebInputEvent;
38 using blink::WebKeyboardEvent;
39 using blink::WebMouseEvent;
40 using blink::WebMouseWheelEvent;
41 using blink::WebTouchEvent;
43 namespace content {
44 namespace {
46 const char* GetEventAckName(InputEventAckState ack_result) {
47 switch(ack_result) {
48 case INPUT_EVENT_ACK_STATE_UNKNOWN: return "UNKNOWN";
49 case INPUT_EVENT_ACK_STATE_CONSUMED: return "CONSUMED";
50 case INPUT_EVENT_ACK_STATE_NOT_CONSUMED: return "NOT_CONSUMED";
51 case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS: return "NO_CONSUMER_EXISTS";
52 case INPUT_EVENT_ACK_STATE_IGNORED: return "IGNORED";
54 DLOG(WARNING) << "Unhandled InputEventAckState in GetEventAckName.";
55 return "";
58 } // namespace
60 InputRouterImpl::Config::Config() {
63 InputRouterImpl::InputRouterImpl(IPC::Sender* sender,
64 InputRouterClient* client,
65 InputAckHandler* ack_handler,
66 int routing_id,
67 const Config& config)
68 : sender_(sender),
69 client_(client),
70 ack_handler_(ack_handler),
71 routing_id_(routing_id),
72 select_message_pending_(false),
73 move_caret_pending_(false),
74 mouse_move_pending_(false),
75 mouse_wheel_pending_(false),
76 current_ack_source_(ACK_SOURCE_NONE),
77 flush_requested_(false),
78 active_renderer_fling_count_(0),
79 touch_event_queue_(this, config.touch_config),
80 gesture_event_queue_(this, this, config.gesture_config) {
81 DCHECK(sender);
82 DCHECK(client);
83 DCHECK(ack_handler);
84 UpdateTouchAckTimeoutEnabled();
87 InputRouterImpl::~InputRouterImpl() {
88 STLDeleteElements(&pending_select_messages_);
91 bool InputRouterImpl::SendInput(scoped_ptr<IPC::Message> message) {
92 DCHECK(IPC_MESSAGE_ID_CLASS(message->type()) == InputMsgStart);
93 switch (message->type()) {
94 // Check for types that require an ACK.
95 case InputMsg_SelectRange::ID:
96 case InputMsg_MoveRangeSelectionExtent::ID:
97 return SendSelectMessage(message.Pass());
98 case InputMsg_MoveCaret::ID:
99 return SendMoveCaret(message.Pass());
100 case InputMsg_HandleInputEvent::ID:
101 NOTREACHED() << "WebInputEvents should never be sent via SendInput.";
102 return false;
103 default:
104 return Send(message.release());
108 void InputRouterImpl::SendMouseEvent(
109 const MouseEventWithLatencyInfo& mouse_event) {
110 if (mouse_event.event.type == WebInputEvent::MouseDown &&
111 gesture_event_queue_.GetTouchpadTapSuppressionController()->
112 ShouldDeferMouseDown(mouse_event))
113 return;
114 if (mouse_event.event.type == WebInputEvent::MouseUp &&
115 gesture_event_queue_.GetTouchpadTapSuppressionController()->
116 ShouldSuppressMouseUp())
117 return;
119 SendMouseEventImmediately(mouse_event);
122 void InputRouterImpl::SendWheelEvent(
123 const MouseWheelEventWithLatencyInfo& wheel_event) {
124 if (mouse_wheel_pending_) {
125 // If there's already a mouse wheel event waiting to be sent to the
126 // renderer, add the new deltas to that event. Not doing so (e.g., by
127 // dropping the old event, as for mouse moves) results in very slow
128 // scrolling on the Mac.
129 if (wheel_event.event.hasPreciseScrollingDeltas)
130 DCHECK(wheel_event.event.canScroll);
131 DCHECK(!(wheel_event.event.hasPreciseScrollingDeltas &&
132 !wheel_event.event.canScroll));
133 if (coalesced_mouse_wheel_events_.empty() ||
134 (!coalesced_mouse_wheel_events_.empty() &&
135 !coalesced_mouse_wheel_events_.back().CanCoalesceWith(wheel_event))) {
136 coalesced_mouse_wheel_events_.push_back(wheel_event);
137 } else {
138 coalesced_mouse_wheel_events_.back().CoalesceWith(wheel_event);
139 TRACE_EVENT_INSTANT2("input", "InputRouterImpl::CoalescedWheelEvent",
140 TRACE_EVENT_SCOPE_THREAD,
141 "total_dx",
142 coalesced_mouse_wheel_events_.back().event.deltaX,
143 "total_dy",
144 coalesced_mouse_wheel_events_.back().event.deltaY);
146 return;
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
163 // handler.
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,
171 key_event.latency,
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))
182 return;
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));
208 else
209 next_mouse_move_->CoalesceWith(mouse_event);
210 return;
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())
240 return NULL;
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) {
265 bool handled = true;
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,
272 OnSelectMessageAck)
273 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
274 OnHasTouchEventHandlers)
275 IPC_MESSAGE_HANDLER(InputHostMsg_SetTouchAction,
276 OnSetTouchAction)
277 IPC_MESSAGE_HANDLER(InputHostMsg_DidStopFlinging, OnDidStopFlinging)
278 IPC_MESSAGE_UNHANDLED(handled = false)
279 IPC_END_MESSAGE_MAP()
281 return handled;
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
309 // IPC messages.
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());
318 return true;
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();
329 return true;
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",
346 "type",
347 WebInputEventTraits::GetName(input_event.type));
348 TRACE_EVENT_WITH_FLOW1("input,benchmark",
349 "LatencyInfo.Flow",
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))
366 return;
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.
405 consumed = true;
406 break;
407 case INPUT_EVENT_ACK_STATE_UNKNOWN:
408 // Simply drop the event.
409 consumed = true;
410 break;
411 default:
412 break;
415 return consumed;
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();
430 return true;
432 return false;
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.
482 if (!has_handlers)
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.
527 return;
530 base::AutoReset<AckSource> auto_reset_current_ack_source(
531 &current_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.
556 key_queue_.clear();
557 ack_handler_->OnUnexpectedEventAck(InputAckHandler::UNEXPECTED_EVENT_TYPE);
558 } else {
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)
575 return;
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_)
647 return;
649 if (HasPendingEvents())
650 return;
652 flush_requested_ = false;
653 client_->DidFlush();
656 } // namespace content