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
32using base::Time;
33using base::TimeDelta;
34using base::TimeTicks;
35using blink::WebGestureEvent;
36using blink::WebInputEvent;
37using blink::WebKeyboardEvent;
38using blink::WebMouseEvent;
39using blink::WebMouseWheelEvent;
40
41namespace content {
42namespace {
43
44bool 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
59GestureEventWithLatencyInfo 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
77const 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
91InputRouterImpl::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
118InputRouterImpl::~InputRouterImpl() {}
119
120void InputRouterImpl::Flush() {}
121
122bool 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
138void 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
160void 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
184void 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
199void 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
217void 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.
224void 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
244void InputRouterImpl::SendTouchEventImmediately(
245    const TouchEventWithLatencyInfo& touch_event) {
246  FilterAndSendWebInputEvent(touch_event.event, touch_event.latency, false);
247}
248
249void InputRouterImpl::SendGestureEventImmediately(
250    const GestureEventWithLatencyInfo& gesture_event) {
251  FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency, false);
252}
253
254const NativeWebKeyboardEvent* InputRouterImpl::GetLastKeyboardEvent() const {
255  if (key_queue_.empty())
256    return NULL;
257  return &key_queue_.front();
258}
259
260bool 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
268void 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
276bool 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
296void InputRouterImpl::OnTouchEventAck(const TouchEventWithLatencyInfo& event,
297                                      InputEventAckState ack_result) {
298  ack_handler_->OnTouchEventAck(event, ack_result);
299}
300
301void 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
308bool 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
319bool 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
330bool InputRouterImpl::Send(IPC::Message* message) {
331  return sender_->Send(message);
332}
333
334void 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
362void 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
382bool 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
417bool 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
443bool 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
457void 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
488void InputRouterImpl::OnMsgMoveCaretAck() {
489  move_caret_pending_ = false;
490  if (next_move_caret_)
491    SendMoveCaret(next_move_caret_.Pass());
492}
493
494void InputRouterImpl::OnSelectRangeAck() {
495  select_range_pending_ = false;
496  if (next_selection_range_)
497    SendSelectRange(next_selection_range_.Pass());
498}
499
500void 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
509void 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
517void 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
551void 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
572void 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
587void 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
608void 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
622void 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
629void 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
644void 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
724bool InputRouterImpl::IsInOverscrollGesture() const {
725  OverscrollController* controller = client_->GetOverscrollController();
726  return controller && controller->overscroll_mode() != OVERSCROLL_NONE;
727}
728
729}  // namespace content
730