Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / input / input_router_impl.cc
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.
4
5 #include "content/browser/renderer_host/input/input_router_impl.h"
6
7 #include "base/auto_reset.h"
8 #include "base/command_line.h"
9 #include "base/metrics/histogram.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "content/browser/renderer_host/input/gesture_event_queue.h"
12 #include "content/browser/renderer_host/input/input_ack_handler.h"
13 #include "content/browser/renderer_host/input/input_router_client.h"
14 #include "content/browser/renderer_host/input/touch_event_queue.h"
15 #include "content/browser/renderer_host/input/touchpad_tap_suppression_controller.h"
16 #include "content/browser/renderer_host/overscroll_controller.h"
17 #include "content/common/content_constants_internal.h"
18 #include "content/common/edit_command.h"
19 #include "content/common/input/touch_action.h"
20 #include "content/common/input/web_input_event_traits.h"
21 #include "content/common/input_messages.h"
22 #include "content/common/view_messages.h"
23 #include "content/port/common/input_event_ack_state.h"
24 #include "content/public/browser/notification_service.h"
25 #include "content/public/browser/notification_types.h"
26 #include "content/public/browser/user_metrics.h"
27 #include "content/public/common/content_switches.h"
28 #include "ipc/ipc_sender.h"
29 #include "ui/events/event.h"
30 #include "ui/events/keycodes/keyboard_codes.h"
31
32 #if defined(OS_ANDROID)
33 #include "ui/gfx/android/view_configuration.h"
34 #include "ui/gfx/screen.h"
35 #else
36 #include "ui/events/gestures/gesture_configuration.h"
37 #endif
38
39 using base::Time;
40 using base::TimeDelta;
41 using base::TimeTicks;
42 using blink::WebGestureEvent;
43 using blink::WebInputEvent;
44 using blink::WebKeyboardEvent;
45 using blink::WebMouseEvent;
46 using blink::WebMouseWheelEvent;
47
48 namespace content {
49 namespace {
50
51 // TODO(jdduke): Instead of relying on command line flags or conditional
52 // conditional compilation here, we should instead use an InputRouter::Settings
53 // construct, supplied and customized by the RenderWidgetHostView. See
54 // crbug.com/343917.
55 bool GetTouchAckTimeoutDelayMs(size_t* touch_ack_timeout_delay_ms) {
56   CommandLine* parsed_command_line = CommandLine::ForCurrentProcess();
57   if (!parsed_command_line->HasSwitch(switches::kTouchAckTimeoutDelayMs))
58     return false;
59
60   std::string timeout_string = parsed_command_line->GetSwitchValueASCII(
61       switches::kTouchAckTimeoutDelayMs);
62   size_t timeout_value;
63   if (!base::StringToSizeT(timeout_string, &timeout_value))
64     return false;
65
66   *touch_ack_timeout_delay_ms = timeout_value;
67   return true;
68 }
69
70 #if defined(OS_ANDROID)
71 double GetTouchMoveSlopSuppressionLengthDips() {
72   const double touch_slop_length_pixels =
73       static_cast<double>(gfx::ViewConfiguration::GetTouchSlopInPixels());
74   const double device_scale_factor =
75       gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().device_scale_factor();
76   return touch_slop_length_pixels / device_scale_factor;
77 }
78 #elif defined(USE_AURA)
79 double GetTouchMoveSlopSuppressionLengthDips() {
80   return ui::GestureConfiguration::max_touch_move_in_pixels_for_click();
81 }
82 #else
83 double GetTouchMoveSlopSuppressionLengthDips() {
84   return 0;
85 }
86 #endif
87
88 TouchEventQueue::TouchScrollingMode GetTouchScrollingMode() {
89   std::string modeString = CommandLine::ForCurrentProcess()->
90       GetSwitchValueASCII(switches::kTouchScrollingMode);
91   if (modeString == switches::kTouchScrollingModeSyncTouchmove)
92     return TouchEventQueue::TOUCH_SCROLLING_MODE_SYNC_TOUCHMOVE;
93   if (modeString == switches::kTouchScrollingModeAbsorbTouchmove)
94     return TouchEventQueue::TOUCH_SCROLLING_MODE_ABSORB_TOUCHMOVE;
95   if (modeString != "" &&
96       modeString != switches::kTouchScrollingModeTouchcancel)
97     LOG(ERROR) << "Invalid --touch-scrolling-mode option: " << modeString;
98   return TouchEventQueue::TOUCH_SCROLLING_MODE_DEFAULT;
99 }
100
101 GestureEventWithLatencyInfo MakeGestureEvent(WebInputEvent::Type type,
102                                              double timestamp_seconds,
103                                              int x,
104                                              int y,
105                                              int modifiers,
106                                              const ui::LatencyInfo latency) {
107   WebGestureEvent result;
108
109   result.type = type;
110   result.x = x;
111   result.y = y;
112   result.sourceDevice = WebGestureEvent::Touchscreen;
113   result.timeStampSeconds = timestamp_seconds;
114   result.modifiers = modifiers;
115
116   return GestureEventWithLatencyInfo(result, latency);
117 }
118
119 const char* GetEventAckName(InputEventAckState ack_result) {
120   switch(ack_result) {
121     case INPUT_EVENT_ACK_STATE_UNKNOWN: return "UNKNOWN";
122     case INPUT_EVENT_ACK_STATE_CONSUMED: return "CONSUMED";
123     case INPUT_EVENT_ACK_STATE_NOT_CONSUMED: return "NOT_CONSUMED";
124     case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS: return "NO_CONSUMER_EXISTS";
125     case INPUT_EVENT_ACK_STATE_IGNORED: return "IGNORED";
126   }
127   DLOG(WARNING) << "Unhandled InputEventAckState in GetEventAckName.";
128   return "";
129 }
130
131 } // namespace
132
133 InputRouterImpl::InputRouterImpl(IPC::Sender* sender,
134                                  InputRouterClient* client,
135                                  InputAckHandler* ack_handler,
136                                  int routing_id)
137     : sender_(sender),
138       client_(client),
139       ack_handler_(ack_handler),
140       routing_id_(routing_id),
141       select_range_pending_(false),
142       move_caret_pending_(false),
143       mouse_move_pending_(false),
144       mouse_wheel_pending_(false),
145       touch_ack_timeout_enabled_(false),
146       touch_ack_timeout_delay_ms_(std::numeric_limits<size_t>::max()),
147       current_ack_source_(ACK_SOURCE_NONE),
148       gesture_event_queue_(new GestureEventQueue(this, this)) {
149   DCHECK(sender);
150   DCHECK(client);
151   DCHECK(ack_handler);
152   touch_event_queue_.reset(new TouchEventQueue(
153       this, GetTouchScrollingMode(), GetTouchMoveSlopSuppressionLengthDips()));
154   touch_ack_timeout_enabled_ =
155       GetTouchAckTimeoutDelayMs(&touch_ack_timeout_delay_ms_);
156   touch_event_queue_->SetAckTimeoutEnabled(touch_ack_timeout_enabled_,
157                                            touch_ack_timeout_delay_ms_);
158 }
159
160 InputRouterImpl::~InputRouterImpl() {}
161
162 void InputRouterImpl::Flush() {}
163
164 bool InputRouterImpl::SendInput(scoped_ptr<IPC::Message> message) {
165   DCHECK(IPC_MESSAGE_ID_CLASS(message->type()) == InputMsgStart);
166   switch (message->type()) {
167     // Check for types that require an ACK.
168     case InputMsg_SelectRange::ID:
169       return SendSelectRange(message.Pass());
170     case InputMsg_MoveCaret::ID:
171       return SendMoveCaret(message.Pass());
172     case InputMsg_HandleInputEvent::ID:
173       NOTREACHED() << "WebInputEvents should never be sent via SendInput.";
174       return false;
175     default:
176       return Send(message.release());
177   }
178 }
179
180 void InputRouterImpl::SendMouseEvent(
181     const MouseEventWithLatencyInfo& mouse_event) {
182   // Order is important here; we need to convert all MouseEvents before they
183   // propagate further, e.g., to the tap suppression controller.
184   if (CommandLine::ForCurrentProcess()->HasSwitch(
185           switches::kSimulateTouchScreenWithMouse)) {
186     SimulateTouchGestureWithMouse(mouse_event);
187     return;
188   }
189
190   if (mouse_event.event.type == WebInputEvent::MouseDown &&
191       gesture_event_queue_->GetTouchpadTapSuppressionController()->
192           ShouldDeferMouseDown(mouse_event))
193       return;
194   if (mouse_event.event.type == WebInputEvent::MouseUp &&
195       gesture_event_queue_->GetTouchpadTapSuppressionController()->
196           ShouldSuppressMouseUp())
197       return;
198
199   SendMouseEventImmediately(mouse_event);
200 }
201
202 void InputRouterImpl::SendWheelEvent(
203     const MouseWheelEventWithLatencyInfo& wheel_event) {
204   // If there's already a mouse wheel event waiting to be sent to the renderer,
205   // add the new deltas to that event. Not doing so (e.g., by dropping the old
206   // event, as for mouse moves) results in very slow scrolling on the Mac (on
207   // which many, very small wheel events are sent).
208   if (mouse_wheel_pending_) {
209     if (coalesced_mouse_wheel_events_.empty() ||
210         !coalesced_mouse_wheel_events_.back().CanCoalesceWith(wheel_event)) {
211       coalesced_mouse_wheel_events_.push_back(wheel_event);
212     } else {
213       coalesced_mouse_wheel_events_.back().CoalesceWith(wheel_event);
214     }
215     return;
216   }
217   mouse_wheel_pending_ = true;
218   current_wheel_event_ = wheel_event;
219
220   HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize",
221                        coalesced_mouse_wheel_events_.size());
222
223   FilterAndSendWebInputEvent(wheel_event.event, wheel_event.latency, false);
224 }
225
226 void InputRouterImpl::SendKeyboardEvent(const NativeWebKeyboardEvent& key_event,
227                                         const ui::LatencyInfo& latency_info,
228                                         bool is_keyboard_shortcut) {
229   // Put all WebKeyboardEvent objects in a queue since we can't trust the
230   // renderer and we need to give something to the HandleKeyboardEvent
231   // handler.
232   key_queue_.push_back(key_event);
233   HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size());
234
235   gesture_event_queue_->FlingHasBeenHalted();
236
237   // Only forward the non-native portions of our event.
238   FilterAndSendWebInputEvent(key_event, latency_info, is_keyboard_shortcut);
239 }
240
241 void InputRouterImpl::SendGestureEvent(
242     const GestureEventWithLatencyInfo& original_gesture_event) {
243   GestureEventWithLatencyInfo gesture_event(original_gesture_event);
244   if (touch_action_filter_.FilterGestureEvent(&gesture_event.event))
245     return;
246
247   touch_event_queue_->OnGestureScrollEvent(gesture_event);
248
249   if (!IsInOverscrollGesture() &&
250       !gesture_event_queue_->ShouldForward(gesture_event)) {
251     OverscrollController* controller = client_->GetOverscrollController();
252     if (controller)
253       controller->DiscardingGestureEvent(gesture_event.event);
254     return;
255   }
256
257   FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency, false);
258 }
259
260 void InputRouterImpl::SendTouchEvent(
261     const TouchEventWithLatencyInfo& touch_event) {
262   touch_event_queue_->QueueEvent(touch_event);
263 }
264
265 // Forwards MouseEvent without passing it through
266 // TouchpadTapSuppressionController.
267 void InputRouterImpl::SendMouseEventImmediately(
268     const MouseEventWithLatencyInfo& mouse_event) {
269   // Avoid spamming the renderer with mouse move events.  It is important
270   // to note that WM_MOUSEMOVE events are anyways synthetic, but since our
271   // thread is able to rapidly consume WM_MOUSEMOVE events, we may get way
272   // more WM_MOUSEMOVE events than we wish to send to the renderer.
273   if (mouse_event.event.type == WebInputEvent::MouseMove) {
274     if (mouse_move_pending_) {
275       if (!next_mouse_move_)
276         next_mouse_move_.reset(new MouseEventWithLatencyInfo(mouse_event));
277       else
278         next_mouse_move_->CoalesceWith(mouse_event);
279       return;
280     }
281     mouse_move_pending_ = true;
282   }
283
284   FilterAndSendWebInputEvent(mouse_event.event, mouse_event.latency, false);
285 }
286
287 void InputRouterImpl::SendTouchEventImmediately(
288     const TouchEventWithLatencyInfo& touch_event) {
289   FilterAndSendWebInputEvent(touch_event.event, touch_event.latency, false);
290 }
291
292 void InputRouterImpl::SendGestureEventImmediately(
293     const GestureEventWithLatencyInfo& gesture_event) {
294   FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency, false);
295 }
296
297 const NativeWebKeyboardEvent* InputRouterImpl::GetLastKeyboardEvent() const {
298   if (key_queue_.empty())
299     return NULL;
300   return &key_queue_.front();
301 }
302
303 bool InputRouterImpl::ShouldForwardTouchEvent() const {
304   // Always send a touch event if the renderer has a touch-event handler.
305   return touch_event_queue_->has_handlers();
306 }
307
308 void InputRouterImpl::OnViewUpdated(int view_flags) {
309   bool fixed_page_scale = (view_flags & FIXED_PAGE_SCALE) != 0;
310   bool mobile_viewport = (view_flags & MOBILE_VIEWPORT) != 0;
311   touch_event_queue_->SetAckTimeoutEnabled(
312       touch_ack_timeout_enabled_ && !(fixed_page_scale || mobile_viewport),
313       touch_ack_timeout_delay_ms_);
314 }
315
316 bool InputRouterImpl::OnMessageReceived(const IPC::Message& message) {
317   bool handled = true;
318   bool message_is_ok = true;
319   IPC_BEGIN_MESSAGE_MAP_EX(InputRouterImpl, message, message_is_ok)
320     IPC_MESSAGE_HANDLER(InputHostMsg_HandleInputEvent_ACK, OnInputEventAck)
321     IPC_MESSAGE_HANDLER(ViewHostMsg_MoveCaret_ACK, OnMsgMoveCaretAck)
322     IPC_MESSAGE_HANDLER(ViewHostMsg_SelectRange_ACK, OnSelectRangeAck)
323     IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
324                         OnHasTouchEventHandlers)
325     IPC_MESSAGE_HANDLER(InputHostMsg_SetTouchAction,
326                         OnSetTouchAction)
327     IPC_MESSAGE_UNHANDLED(handled = false)
328   IPC_END_MESSAGE_MAP()
329
330   if (!message_is_ok)
331     ack_handler_->OnUnexpectedEventAck(InputAckHandler::BAD_ACK_MESSAGE);
332
333   return handled;
334 }
335
336 void InputRouterImpl::OnTouchEventAck(const TouchEventWithLatencyInfo& event,
337                                       InputEventAckState ack_result) {
338   ack_handler_->OnTouchEventAck(event, ack_result);
339 }
340
341 void InputRouterImpl::OnGestureEventAck(
342     const GestureEventWithLatencyInfo& event,
343     InputEventAckState ack_result) {
344   touch_event_queue_->OnGestureEventAck(event, ack_result);
345   ProcessAckForOverscroll(event.event, ack_result);
346   ack_handler_->OnGestureEventAck(event, ack_result);
347 }
348
349 bool InputRouterImpl::SendSelectRange(scoped_ptr<IPC::Message> message) {
350   DCHECK(message->type() == InputMsg_SelectRange::ID);
351   if (select_range_pending_) {
352     next_selection_range_ = message.Pass();
353     return true;
354   }
355
356   select_range_pending_ = true;
357   return Send(message.release());
358 }
359
360 bool InputRouterImpl::SendMoveCaret(scoped_ptr<IPC::Message> message) {
361   DCHECK(message->type() == InputMsg_MoveCaret::ID);
362   if (move_caret_pending_) {
363     next_move_caret_ = message.Pass();
364     return true;
365   }
366
367   move_caret_pending_ = true;
368   return Send(message.release());
369 }
370
371 bool InputRouterImpl::Send(IPC::Message* message) {
372   return sender_->Send(message);
373 }
374
375 void InputRouterImpl::FilterAndSendWebInputEvent(
376     const WebInputEvent& input_event,
377     const ui::LatencyInfo& latency_info,
378     bool is_keyboard_shortcut) {
379   TRACE_EVENT1("input",
380                "InputRouterImpl::FilterAndSendWebInputEvent",
381                "type",
382                WebInputEventTraits::GetName(input_event.type));
383
384   // Transmit any pending wheel events on a non-wheel event. This ensures that
385   // final PhaseEnded wheel event is received, which is necessary to terminate
386   // rubber-banding, for example.
387    if (input_event.type != WebInputEvent::MouseWheel) {
388     WheelEventQueue mouse_wheel_events;
389     mouse_wheel_events.swap(coalesced_mouse_wheel_events_);
390     for (size_t i = 0; i < mouse_wheel_events.size(); ++i) {
391       OfferToHandlers(mouse_wheel_events[i].event,
392                       mouse_wheel_events[i].latency,
393                       false);
394      }
395   }
396
397   // Any input event cancels a pending mouse move event.
398   next_mouse_move_.reset();
399
400   OfferToHandlers(input_event, latency_info, is_keyboard_shortcut);
401 }
402
403 void InputRouterImpl::OfferToHandlers(const WebInputEvent& input_event,
404                                       const ui::LatencyInfo& latency_info,
405                                       bool is_keyboard_shortcut) {
406   if (OfferToOverscrollController(input_event, latency_info))
407     return;
408
409   if (OfferToClient(input_event, latency_info))
410     return;
411
412   OfferToRenderer(input_event, latency_info, is_keyboard_shortcut);
413
414   // If we don't care about the ack disposition, send the ack immediately.
415   if (WebInputEventTraits::IgnoresAckDisposition(input_event.type)) {
416     ProcessInputEventAck(input_event.type,
417                          INPUT_EVENT_ACK_STATE_IGNORED,
418                          latency_info,
419                          IGNORING_DISPOSITION);
420   }
421 }
422
423 bool InputRouterImpl::OfferToOverscrollController(
424     const WebInputEvent& input_event,
425     const ui::LatencyInfo& latency_info) {
426   OverscrollController* controller = client_->GetOverscrollController();
427   if (!controller)
428     return false;
429
430   OverscrollController::Disposition disposition =
431       controller->DispatchEvent(input_event, latency_info);
432
433   bool consumed = disposition == OverscrollController::CONSUMED;
434
435   if (disposition == OverscrollController::SHOULD_FORWARD_TO_GESTURE_QUEUE) {
436     DCHECK(WebInputEvent::isGestureEventType(input_event.type));
437     const blink::WebGestureEvent& gesture_event =
438         static_cast<const blink::WebGestureEvent&>(input_event);
439     // An ACK is expected for the event, so mark it as consumed.
440     consumed = !gesture_event_queue_->ShouldForward(
441         GestureEventWithLatencyInfo(gesture_event, latency_info));
442   }
443
444   if (consumed) {
445     InputEventAckState overscroll_ack =
446         WebInputEvent::isTouchEventType(input_event.type) ?
447             INPUT_EVENT_ACK_STATE_NOT_CONSUMED : INPUT_EVENT_ACK_STATE_CONSUMED;
448     ProcessInputEventAck(input_event.type,
449                          overscroll_ack,
450                          latency_info,
451                          OVERSCROLL_CONTROLLER);
452     // WARNING: |this| may be deleted at this point.
453   }
454
455   return consumed;
456 }
457
458 bool InputRouterImpl::OfferToClient(const WebInputEvent& input_event,
459                                     const ui::LatencyInfo& latency_info) {
460   bool consumed = false;
461
462   InputEventAckState filter_ack =
463       client_->FilterInputEvent(input_event, latency_info);
464   switch (filter_ack) {
465     case INPUT_EVENT_ACK_STATE_CONSUMED:
466     case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS:
467       // Send the ACK and early exit.
468       next_mouse_move_.reset();
469       ProcessInputEventAck(input_event.type, filter_ack, latency_info, CLIENT);
470       // WARNING: |this| may be deleted at this point.
471       consumed = true;
472       break;
473     case INPUT_EVENT_ACK_STATE_UNKNOWN:
474       // Simply drop the event.
475       consumed = true;
476       break;
477     default:
478       break;
479   }
480
481   return consumed;
482 }
483
484 bool InputRouterImpl::OfferToRenderer(const WebInputEvent& input_event,
485                                       const ui::LatencyInfo& latency_info,
486                                       bool is_keyboard_shortcut) {
487   if (Send(new InputMsg_HandleInputEvent(
488           routing_id(), &input_event, latency_info, is_keyboard_shortcut))) {
489     // Ack messages for ignored ack event types are not required, and might
490     // never be sent by the renderer. Consequently, such event types should not
491     // affect event timing or in-flight event count metrics.
492     if (!WebInputEventTraits::IgnoresAckDisposition(input_event.type)) {
493       input_event_start_time_ = TimeTicks::Now();
494       client_->IncrementInFlightEventCount();
495     }
496     return true;
497   }
498   return false;
499 }
500
501 void InputRouterImpl::OnInputEventAck(WebInputEvent::Type event_type,
502                                       InputEventAckState ack_result,
503                                       const ui::LatencyInfo& latency_info) {
504   // A synthetic ack will already have been sent for this event, and it should
505   // not affect event timing or in-flight count metrics.
506   if (WebInputEventTraits::IgnoresAckDisposition(event_type))
507     return;
508
509   client_->DecrementInFlightEventCount();
510
511   // Log the time delta for processing an input event.
512   TimeDelta delta = TimeTicks::Now() - input_event_start_time_;
513   UMA_HISTOGRAM_TIMES("MPArch.IIR_InputEventDelta", delta);
514
515   ProcessInputEventAck(event_type, ack_result, latency_info, RENDERER);
516   // WARNING: |this| may be deleted at this point.
517
518   // This is used only for testing, and the other end does not use the
519   // source object.  On linux, specifying
520   // Source<RenderWidgetHost> results in a very strange
521   // runtime error in the epilogue of the enclosing
522   // (ProcessInputEventAck) method, but not on other platforms; using
523   // 'void' instead is just as safe (since NotificationSource
524   // is not actually typesafe) and avoids this error.
525   int type = static_cast<int>(event_type);
526   NotificationService::current()->Notify(
527       NOTIFICATION_RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK,
528       Source<void>(this),
529       Details<int>(&type));
530 }
531
532 void InputRouterImpl::OnMsgMoveCaretAck() {
533   move_caret_pending_ = false;
534   if (next_move_caret_)
535     SendMoveCaret(next_move_caret_.Pass());
536 }
537
538 void InputRouterImpl::OnSelectRangeAck() {
539   select_range_pending_ = false;
540   if (next_selection_range_)
541     SendSelectRange(next_selection_range_.Pass());
542 }
543
544 void InputRouterImpl::OnHasTouchEventHandlers(bool has_handlers) {
545   TRACE_EVENT1("input", "InputRouterImpl::OnHasTouchEventHandlers",
546                "has_handlers", has_handlers);
547
548   touch_event_queue_->OnHasTouchEventHandlers(has_handlers);
549   client_->OnHasTouchEventHandlers(has_handlers);
550 }
551
552 void InputRouterImpl::OnSetTouchAction(
553     content::TouchAction touch_action) {
554   // Synthetic touchstart events should get filtered out in RenderWidget.
555   DCHECK(touch_event_queue_->IsPendingAckTouchStart());
556
557   touch_action_filter_.OnSetTouchAction(touch_action);
558 }
559
560 void InputRouterImpl::ProcessInputEventAck(
561     WebInputEvent::Type event_type,
562     InputEventAckState ack_result,
563     const ui::LatencyInfo& latency_info,
564     AckSource ack_source) {
565   TRACE_EVENT2("input", "InputRouterImpl::ProcessInputEventAck",
566                "type", WebInputEventTraits::GetName(event_type),
567                "ack", GetEventAckName(ack_result));
568
569   // Note: The keyboard ack must be treated carefully, as it may result in
570   // synchronous destruction of |this|. Handling immediately guards against
571   // future references to |this|, as with |auto_reset_current_ack_source| below.
572   if (WebInputEvent::isKeyboardEventType(event_type)) {
573     ProcessKeyboardAck(event_type, ack_result);
574     // WARNING: |this| may be deleted at this point.
575     return;
576   }
577
578   base::AutoReset<AckSource> auto_reset_current_ack_source(
579       &current_ack_source_, ack_source);
580
581   if (WebInputEvent::isMouseEventType(event_type)) {
582     ProcessMouseAck(event_type, ack_result);
583   } else if (event_type == WebInputEvent::MouseWheel) {
584     ProcessWheelAck(ack_result, latency_info);
585   } else if (WebInputEvent::isTouchEventType(event_type)) {
586     ProcessTouchAck(ack_result, latency_info);
587   } else if (WebInputEvent::isGestureEventType(event_type)) {
588     ProcessGestureAck(event_type, ack_result, latency_info);
589   } else if (event_type != WebInputEvent::Undefined) {
590     ack_handler_->OnUnexpectedEventAck(InputAckHandler::BAD_ACK_MESSAGE);
591   }
592 }
593
594 void InputRouterImpl::ProcessKeyboardAck(blink::WebInputEvent::Type type,
595                                          InputEventAckState ack_result) {
596   if (key_queue_.empty()) {
597     ack_handler_->OnUnexpectedEventAck(InputAckHandler::UNEXPECTED_ACK);
598   } else if (key_queue_.front().type != type) {
599     // Something must be wrong. Clear the |key_queue_| and char event
600     // suppression so that we can resume from the error.
601     key_queue_.clear();
602     ack_handler_->OnUnexpectedEventAck(InputAckHandler::UNEXPECTED_EVENT_TYPE);
603   } else {
604     NativeWebKeyboardEvent front_item = key_queue_.front();
605     key_queue_.pop_front();
606
607     ack_handler_->OnKeyboardEventAck(front_item, ack_result);
608     // WARNING: This InputRouterImpl can be deallocated at this point
609     // (i.e.  in the case of Ctrl+W, where the call to
610     // HandleKeyboardEvent destroys this InputRouterImpl).
611     // TODO(jdduke): crbug.com/274029 - Make ack-triggered shutdown async.
612   }
613 }
614
615 void InputRouterImpl::ProcessMouseAck(blink::WebInputEvent::Type type,
616                                       InputEventAckState ack_result) {
617   if (type != WebInputEvent::MouseMove)
618     return;
619
620   mouse_move_pending_ = false;
621
622   if (next_mouse_move_) {
623     DCHECK(next_mouse_move_->event.type == WebInputEvent::MouseMove);
624     scoped_ptr<MouseEventWithLatencyInfo> next_mouse_move
625         = next_mouse_move_.Pass();
626     SendMouseEvent(*next_mouse_move);
627   }
628 }
629
630 void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result,
631                                       const ui::LatencyInfo& latency) {
632   ProcessAckForOverscroll(current_wheel_event_.event, ack_result);
633
634   // TODO(miletus): Add renderer side latency to each uncoalesced mouse
635   // wheel event and add terminal component to each of them.
636   current_wheel_event_.latency.AddNewLatencyFrom(latency);
637   // Process the unhandled wheel event here before calling SendWheelEvent()
638   // since it will mutate current_wheel_event_.
639   ack_handler_->OnWheelEventAck(current_wheel_event_, ack_result);
640   mouse_wheel_pending_ = false;
641
642   // Now send the next (coalesced) mouse wheel event.
643   if (!coalesced_mouse_wheel_events_.empty()) {
644     MouseWheelEventWithLatencyInfo next_wheel_event =
645         coalesced_mouse_wheel_events_.front();
646     coalesced_mouse_wheel_events_.pop_front();
647     SendWheelEvent(next_wheel_event);
648   }
649 }
650
651 void InputRouterImpl::ProcessGestureAck(WebInputEvent::Type type,
652                                         InputEventAckState ack_result,
653                                         const ui::LatencyInfo& latency) {
654   // If |ack_result| originated from the overscroll controller, only
655   // feed |gesture_event_queue_| the ack if it was expecting one.
656   if (current_ack_source_ == OVERSCROLL_CONTROLLER &&
657       !gesture_event_queue_->HasQueuedGestureEvents()) {
658     return;
659   }
660
661   // |gesture_event_queue_| will forward to OnGestureEventAck when appropriate.
662   gesture_event_queue_->ProcessGestureAck(ack_result, type, latency);
663 }
664
665 void InputRouterImpl::ProcessTouchAck(
666     InputEventAckState ack_result,
667     const ui::LatencyInfo& latency) {
668   // |touch_event_queue_| will forward to OnTouchEventAck when appropriate.
669   touch_event_queue_->ProcessTouchAck(ack_result, latency);
670 }
671
672 void InputRouterImpl::ProcessAckForOverscroll(const WebInputEvent& event,
673                                               InputEventAckState ack_result) {
674   // Acks sent from the overscroll controller need not be fed back into the
675   // overscroll controller.
676   if (current_ack_source_ == OVERSCROLL_CONTROLLER)
677     return;
678
679   OverscrollController* controller = client_->GetOverscrollController();
680   if (!controller)
681     return;
682
683   controller->ReceivedEventACK(
684       event, (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result));
685 }
686
687 void InputRouterImpl::SimulateTouchGestureWithMouse(
688     const MouseEventWithLatencyInfo& event) {
689   const WebMouseEvent& mouse_event = event.event;
690   int x = mouse_event.x, y = mouse_event.y;
691   float dx = mouse_event.movementX, dy = mouse_event.movementY;
692   static int startX = 0, startY = 0;
693
694   switch (mouse_event.button) {
695     case WebMouseEvent::ButtonLeft:
696       if (mouse_event.type == WebInputEvent::MouseDown) {
697         startX = x;
698         startY = y;
699         SendGestureEvent(MakeGestureEvent(
700             WebInputEvent::GestureScrollBegin, mouse_event.timeStampSeconds,
701             x, y, 0, event.latency));
702       }
703       if (dx != 0 || dy != 0) {
704         GestureEventWithLatencyInfo gesture_event = MakeGestureEvent(
705             WebInputEvent::GestureScrollUpdate, mouse_event.timeStampSeconds,
706             x, y, 0, event.latency);
707         gesture_event.event.data.scrollUpdate.deltaX = dx;
708         gesture_event.event.data.scrollUpdate.deltaY = dy;
709         SendGestureEvent(gesture_event);
710       }
711       if (mouse_event.type == WebInputEvent::MouseUp) {
712         SendGestureEvent(MakeGestureEvent(
713             WebInputEvent::GestureScrollEnd, mouse_event.timeStampSeconds,
714             x, y, 0, event.latency));
715       }
716       break;
717     case WebMouseEvent::ButtonMiddle:
718       if (mouse_event.type == WebInputEvent::MouseDown) {
719         startX = x;
720         startY = y;
721         SendGestureEvent(MakeGestureEvent(
722             WebInputEvent::GestureShowPress, mouse_event.timeStampSeconds,
723             x, y, 0, event.latency));
724         SendGestureEvent(MakeGestureEvent(
725             WebInputEvent::GestureTapDown, mouse_event.timeStampSeconds,
726             x, y, 0, event.latency));
727       }
728       if (mouse_event.type == WebInputEvent::MouseUp) {
729         SendGestureEvent(MakeGestureEvent(
730             WebInputEvent::GestureTap, mouse_event.timeStampSeconds,
731             x, y, 0, event.latency));
732       }
733       break;
734     case WebMouseEvent::ButtonRight:
735       if (mouse_event.type == WebInputEvent::MouseDown) {
736         startX = x;
737         startY = y;
738         SendGestureEvent(MakeGestureEvent(
739             WebInputEvent::GestureScrollBegin, mouse_event.timeStampSeconds,
740             x, y, 0, event.latency));
741         SendGestureEvent(MakeGestureEvent(
742             WebInputEvent::GesturePinchBegin, mouse_event.timeStampSeconds,
743             x, y, 0, event.latency));
744       }
745       if (dx != 0 || dy != 0) {
746         dx = pow(dy < 0 ? 0.998f : 1.002f, fabs(dy));
747         GestureEventWithLatencyInfo gesture_event = MakeGestureEvent(
748             WebInputEvent::GesturePinchUpdate, mouse_event.timeStampSeconds,
749             startX, startY, 0, event.latency);
750         gesture_event.event.data.pinchUpdate.scale = dx;
751         SendGestureEvent(gesture_event);
752       }
753       if (mouse_event.type == WebInputEvent::MouseUp) {
754         SendGestureEvent(MakeGestureEvent(
755             WebInputEvent::GesturePinchEnd, mouse_event.timeStampSeconds,
756             x, y, 0, event.latency));
757         SendGestureEvent(MakeGestureEvent(
758             WebInputEvent::GestureScrollEnd, mouse_event.timeStampSeconds,
759             x, y, 0, event.latency));
760       }
761       break;
762     case WebMouseEvent::ButtonNone:
763       break;
764   }
765 }
766
767 bool InputRouterImpl::IsInOverscrollGesture() const {
768   OverscrollController* controller = client_->GetOverscrollController();
769   return controller && controller->overscroll_mode() != OVERSCROLL_NONE;
770 }
771
772 }  // namespace content