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