Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / input / input_router_impl.cc
index 1050511..4f12318 100644 (file)
@@ -4,6 +4,8 @@
 
 #include "content/browser/renderer_host/input/input_router_impl.h"
 
+#include <math.h>
+
 #include "base/auto_reset.h"
 #include "base/command_line.h"
 #include "base/metrics/histogram.h"
 #include "content/browser/renderer_host/input/input_router_client.h"
 #include "content/browser/renderer_host/input/touch_event_queue.h"
 #include "content/browser/renderer_host/input/touchpad_tap_suppression_controller.h"
-#include "content/browser/renderer_host/input/web_touch_event_traits.h"
 #include "content/browser/renderer_host/overscroll_controller.h"
 #include "content/common/content_constants_internal.h"
 #include "content/common/edit_command.h"
+#include "content/common/input/input_event_ack_state.h"
 #include "content/common/input/touch_action.h"
+#include "content/common/input/web_touch_event_traits.h"
 #include "content/common/input_messages.h"
 #include "content/common/view_messages.h"
-#include "content/port/common/input_event_ack_state.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/user_metrics.h"
 #include "ui/events/event.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 
-#if defined(OS_ANDROID)
-#include "ui/gfx/android/view_configuration.h"
-#include "ui/gfx/screen.h"
-#else
-#include "ui/events/gestures/gesture_configuration.h"
-#endif
-
 using base::Time;
 using base::TimeDelta;
 using base::TimeTicks;
@@ -48,75 +43,6 @@ using blink::WebMouseWheelEvent;
 namespace content {
 namespace {
 
-// TODO(jdduke): Instead of relying on command line flags or conditional
-// conditional compilation here, we should instead use an InputRouter::Settings
-// construct, supplied and customized by the RenderWidgetHostView. See
-// crbug.com/343917.
-bool GetTouchAckTimeoutDelay(base::TimeDelta* touch_ack_timeout_delay) {
-  CommandLine* parsed_command_line = CommandLine::ForCurrentProcess();
-  if (!parsed_command_line->HasSwitch(switches::kTouchAckTimeoutDelayMs))
-    return false;
-
-  std::string timeout_string = parsed_command_line->GetSwitchValueASCII(
-      switches::kTouchAckTimeoutDelayMs);
-  size_t timeout_ms;
-  if (!base::StringToSizeT(timeout_string, &timeout_ms))
-    return false;
-
-  *touch_ack_timeout_delay = base::TimeDelta::FromMilliseconds(timeout_ms);
-  return true;
-}
-
-#if defined(OS_ANDROID)
-double GetTouchMoveSlopSuppressionLengthDips() {
-  const double touch_slop_length_pixels =
-      static_cast<double>(gfx::ViewConfiguration::GetTouchSlopInPixels());
-  const double device_scale_factor =
-      gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().device_scale_factor();
-  return touch_slop_length_pixels / device_scale_factor;
-}
-#elif defined(USE_AURA)
-double GetTouchMoveSlopSuppressionLengthDips() {
-  return ui::GestureConfiguration::max_touch_move_in_pixels_for_click();
-}
-#else
-double GetTouchMoveSlopSuppressionLengthDips() {
-  return 0;
-}
-#endif
-
-TouchEventQueue::TouchScrollingMode GetTouchScrollingMode() {
-  std::string modeString = CommandLine::ForCurrentProcess()->
-      GetSwitchValueASCII(switches::kTouchScrollingMode);
-  if (modeString == switches::kTouchScrollingModeSyncTouchmove)
-    return TouchEventQueue::TOUCH_SCROLLING_MODE_SYNC_TOUCHMOVE;
-  if (modeString == switches::kTouchScrollingModeAbsorbTouchmove)
-    return TouchEventQueue::TOUCH_SCROLLING_MODE_ABSORB_TOUCHMOVE;
-  if (modeString == switches::kTouchScrollingModeTouchcancel)
-    return TouchEventQueue::TOUCH_SCROLLING_MODE_TOUCHCANCEL;
-  if (modeString != "")
-    LOG(ERROR) << "Invalid --touch-scrolling-mode option: " << modeString;
-  return TouchEventQueue::TOUCH_SCROLLING_MODE_DEFAULT;
-}
-
-GestureEventWithLatencyInfo MakeGestureEvent(WebInputEvent::Type type,
-                                             double timestamp_seconds,
-                                             int x,
-                                             int y,
-                                             int modifiers,
-                                             const ui::LatencyInfo& latency) {
-  WebGestureEvent result;
-
-  result.type = type;
-  result.x = x;
-  result.y = y;
-  result.sourceDevice = WebGestureEvent::Touchscreen;
-  result.timeStampSeconds = timestamp_seconds;
-  result.modifiers = modifiers;
-
-  return GestureEventWithLatencyInfo(result, latency);
-}
-
 const char* GetEventAckName(InputEventAckState ack_result) {
   switch(ack_result) {
     case INPUT_EVENT_ACK_STATE_UNKNOWN: return "UNKNOWN";
@@ -131,10 +57,14 @@ const char* GetEventAckName(InputEventAckState ack_result) {
 
 } // namespace
 
+InputRouterImpl::Config::Config() {
+}
+
 InputRouterImpl::InputRouterImpl(IPC::Sender* sender,
                                  InputRouterClient* client,
                                  InputAckHandler* ack_handler,
-                                 int routing_id)
+                                 int routing_id,
+                                 const Config& config)
     : sender_(sender),
       client_(client),
       ack_handler_(ack_handler),
@@ -143,23 +73,23 @@ InputRouterImpl::InputRouterImpl(IPC::Sender* sender,
       move_caret_pending_(false),
       mouse_move_pending_(false),
       mouse_wheel_pending_(false),
-      touch_ack_timeout_supported_(false),
       current_view_flags_(0),
       current_ack_source_(ACK_SOURCE_NONE),
-      gesture_event_queue_(new GestureEventQueue(this, this)) {
+      flush_requested_(false),
+      touch_event_queue_(this, config.touch_config),
+      gesture_event_queue_(this, this, config.gesture_config) {
   DCHECK(sender);
   DCHECK(client);
   DCHECK(ack_handler);
-  touch_event_queue_.reset(new TouchEventQueue(
-      this, GetTouchScrollingMode(), GetTouchMoveSlopSuppressionLengthDips()));
-  touch_ack_timeout_supported_ =
-      GetTouchAckTimeoutDelay(&touch_ack_timeout_delay_);
   UpdateTouchAckTimeoutEnabled();
 }
 
 InputRouterImpl::~InputRouterImpl() {}
 
-void InputRouterImpl::Flush() {}
+void InputRouterImpl::Flush() {
+  flush_requested_ = true;
+  SignalFlushedIfNecessary();
+}
 
 bool InputRouterImpl::SendInput(scoped_ptr<IPC::Message> message) {
   DCHECK(IPC_MESSAGE_ID_CLASS(message->type()) == InputMsgStart);
@@ -179,20 +109,12 @@ bool InputRouterImpl::SendInput(scoped_ptr<IPC::Message> message) {
 
 void InputRouterImpl::SendMouseEvent(
     const MouseEventWithLatencyInfo& mouse_event) {
-  // Order is important here; we need to convert all MouseEvents before they
-  // propagate further, e.g., to the tap suppression controller.
-  if (CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kSimulateTouchScreenWithMouse)) {
-    SimulateTouchGestureWithMouse(mouse_event);
-    return;
-  }
-
   if (mouse_event.event.type == WebInputEvent::MouseDown &&
-      gesture_event_queue_->GetTouchpadTapSuppressionController()->
+      gesture_event_queue_.GetTouchpadTapSuppressionController()->
           ShouldDeferMouseDown(mouse_event))
       return;
   if (mouse_event.event.type == WebInputEvent::MouseUp &&
-      gesture_event_queue_->GetTouchpadTapSuppressionController()->
+      gesture_event_queue_.GetTouchpadTapSuppressionController()->
           ShouldSuppressMouseUp())
       return;
 
@@ -201,26 +123,39 @@ void InputRouterImpl::SendMouseEvent(
 
 void InputRouterImpl::SendWheelEvent(
     const MouseWheelEventWithLatencyInfo& wheel_event) {
-  // If there's already a mouse wheel event waiting to be sent to the renderer,
-  // add the new deltas to that event. Not doing so (e.g., by dropping the old
-  // event, as for mouse moves) results in very slow scrolling on the Mac (on
-  // which many, very small wheel events are sent).
+  SendWheelEvent(QueuedWheelEvent(wheel_event, false));
+}
+
+void InputRouterImpl::SendWheelEvent(const QueuedWheelEvent& wheel_event) {
   if (mouse_wheel_pending_) {
+    // If there's already a mouse wheel event waiting to be sent to the
+    // renderer, add the new deltas to that event. Not doing so (e.g., by
+    // dropping the old event, as for mouse moves) results in very slow
+    // scrolling on the Mac (on which many, very small wheel events are sent).
+    // Note that we can't coalesce wheel events for pinches because the GEQ
+    // expects one ACK for each (but it's fine to coalesce non-pinch wheels
+    // into a pinch one).  Note that the GestureEventQueue ensures we only
+    // ever have a single pinch event queued here.
     if (coalesced_mouse_wheel_events_.empty() ||
-        !coalesced_mouse_wheel_events_.back().CanCoalesceWith(wheel_event)) {
+        wheel_event.synthesized_from_pinch ||
+        !coalesced_mouse_wheel_events_.back().event.CanCoalesceWith(
+            wheel_event.event)) {
       coalesced_mouse_wheel_events_.push_back(wheel_event);
     } else {
-      coalesced_mouse_wheel_events_.back().CoalesceWith(wheel_event);
+      coalesced_mouse_wheel_events_.back().event.CoalesceWith(
+          wheel_event.event);
     }
     return;
   }
+
   mouse_wheel_pending_ = true;
   current_wheel_event_ = wheel_event;
 
   HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize",
                        coalesced_mouse_wheel_events_.size());
 
-  FilterAndSendWebInputEvent(wheel_event.event, wheel_event.latency, false);
+  FilterAndSendWebInputEvent(
+      wheel_event.event.event, wheel_event.event.latency, false);
 }
 
 void InputRouterImpl::SendKeyboardEvent(const NativeWebKeyboardEvent& key_event,
@@ -232,7 +167,7 @@ void InputRouterImpl::SendKeyboardEvent(const NativeWebKeyboardEvent& key_event,
   key_queue_.push_back(key_event);
   HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size());
 
-  gesture_event_queue_->FlingHasBeenHalted();
+  gesture_event_queue_.FlingHasBeenHalted();
 
   // Only forward the non-native portions of our event.
   FilterAndSendWebInputEvent(key_event, latency_info, is_keyboard_shortcut);
@@ -242,25 +177,27 @@ void InputRouterImpl::SendGestureEvent(
     const GestureEventWithLatencyInfo& original_gesture_event) {
   event_stream_validator_.OnEvent(original_gesture_event.event);
   GestureEventWithLatencyInfo gesture_event(original_gesture_event);
+
   if (touch_action_filter_.FilterGestureEvent(&gesture_event.event))
     return;
 
-  touch_event_queue_->OnGestureScrollEvent(gesture_event);
+  if (gesture_event.event.sourceDevice == WebGestureEvent::Touchscreen)
+    touch_event_queue_.OnGestureScrollEvent(gesture_event);
 
   if (!IsInOverscrollGesture() &&
-      !gesture_event_queue_->ShouldForward(gesture_event)) {
+      !gesture_event_queue_.ShouldForward(gesture_event)) {
     OverscrollController* controller = client_->GetOverscrollController();
     if (controller)
       controller->DiscardingGestureEvent(gesture_event.event);
     return;
   }
 
-  FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency, false);
+  SendGestureEventImmediately(gesture_event);
 }
 
 void InputRouterImpl::SendTouchEvent(
     const TouchEventWithLatencyInfo& touch_event) {
-  touch_event_queue_->QueueEvent(touch_event);
+  touch_event_queue_.QueueEvent(touch_event);
 }
 
 // Forwards MouseEvent without passing it through
@@ -301,6 +238,12 @@ void InputRouterImpl::SendTouchEventImmediately(
 
 void InputRouterImpl::SendGestureEventImmediately(
     const GestureEventWithLatencyInfo& gesture_event) {
+  if (gesture_event.event.type == WebInputEvent::GesturePinchUpdate &&
+      gesture_event.event.sourceDevice == WebGestureEvent::Touchpad) {
+    SendSyntheticWheelEventForPinch(gesture_event);
+    return;
+  }
+
   FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency, false);
 }
 
@@ -311,8 +254,9 @@ const NativeWebKeyboardEvent* InputRouterImpl::GetLastKeyboardEvent() const {
 }
 
 bool InputRouterImpl::ShouldForwardTouchEvent() const {
-  // Always send a touch event if the renderer has a touch-event handler.
-  return touch_event_queue_->has_handlers();
+  // Always send a touch event if the renderer has a touch-event handler or
+  // there are pending touch events.
+  return touch_event_queue_.has_handlers() || !touch_event_queue_.empty();
 }
 
 void InputRouterImpl::OnViewUpdated(int view_flags) {
@@ -357,7 +301,7 @@ void InputRouterImpl::OnTouchEventAck(const TouchEventWithLatencyInfo& event,
 void InputRouterImpl::OnGestureEventAck(
     const GestureEventWithLatencyInfo& event,
     InputEventAckState ack_result) {
-  touch_event_queue_->OnGestureEventAck(event, ack_result);
+  touch_event_queue_.OnGestureEventAck(event, ack_result);
   ProcessAckForOverscroll(event.event, ack_result);
   ack_handler_->OnGestureEventAck(event, ack_result);
 }
@@ -397,19 +341,6 @@ void InputRouterImpl::FilterAndSendWebInputEvent(
                "type",
                WebInputEventTraits::GetName(input_event.type));
 
-  // Transmit any pending wheel events on a non-wheel event. This ensures that
-  // final PhaseEnded wheel event is received, which is necessary to terminate
-  // rubber-banding, for example.
-   if (input_event.type != WebInputEvent::MouseWheel) {
-    WheelEventQueue mouse_wheel_events;
-    mouse_wheel_events.swap(coalesced_mouse_wheel_events_);
-    for (size_t i = 0; i < mouse_wheel_events.size(); ++i) {
-      OfferToHandlers(mouse_wheel_events[i].event,
-                      mouse_wheel_events[i].latency,
-                      false);
-     }
-  }
-
   // Any input event cancels a pending mouse move event.
   next_mouse_move_.reset();
 
@@ -427,8 +358,16 @@ void InputRouterImpl::OfferToHandlers(const WebInputEvent& input_event,
 
   OfferToRenderer(input_event, latency_info, is_keyboard_shortcut);
 
+  // Touch events should always indicate in the event whether they are
+  // cancelable (respect ACK disposition) or not.
+  bool ignores_ack = WebInputEventTraits::IgnoresAckDisposition(input_event);
+  if (WebInputEvent::isTouchEventType(input_event.type)) {
+    DCHECK(!ignores_ack ==
+           static_cast<const blink::WebTouchEvent&>(input_event).cancelable);
+  }
+
   // If we don't care about the ack disposition, send the ack immediately.
-  if (WebInputEventTraits::IgnoresAckDisposition(input_event.type)) {
+  if (ignores_ack) {
     ProcessInputEventAck(input_event.type,
                          INPUT_EVENT_ACK_STATE_IGNORED,
                          latency_info,
@@ -453,7 +392,7 @@ bool InputRouterImpl::OfferToOverscrollController(
     const blink::WebGestureEvent& gesture_event =
         static_cast<const blink::WebGestureEvent&>(input_event);
     // An ACK is expected for the event, so mark it as consumed.
-    consumed = !gesture_event_queue_->ShouldForward(
+    consumed = !gesture_event_queue_.ShouldForward(
         GestureEventWithLatencyInfo(gesture_event, latency_info));
   }
 
@@ -502,10 +441,10 @@ bool InputRouterImpl::OfferToRenderer(const WebInputEvent& input_event,
                                       bool is_keyboard_shortcut) {
   if (Send(new InputMsg_HandleInputEvent(
           routing_id(), &input_event, latency_info, is_keyboard_shortcut))) {
-    // Ack messages for ignored ack event types are not required, and might
-    // never be sent by the renderer. Consequently, such event types should not
-    // affect event timing or in-flight event count metrics.
-    if (!WebInputEventTraits::IgnoresAckDisposition(input_event.type)) {
+    // Ack messages for ignored ack event types should never be sent by the
+    // renderer. Consequently, such event types should not affect event time
+    // or in-flight event count metrics.
+    if (!WebInputEventTraits::IgnoresAckDisposition(input_event)) {
       input_event_start_time_ = TimeTicks::Now();
       client_->IncrementInFlightEventCount();
     }
@@ -514,14 +453,46 @@ bool InputRouterImpl::OfferToRenderer(const WebInputEvent& input_event,
   return false;
 }
 
+void InputRouterImpl::SendSyntheticWheelEventForPinch(
+    const GestureEventWithLatencyInfo& pinch_event) {
+  // We match typical trackpad behavior on Windows by sending fake wheel events
+  // with the ctrl modifier set when we see trackpad pinch gestures.  Ideally
+  // we'd someday get a standard 'pinch' event and send that instead.
+
+  WebMouseWheelEvent wheelEvent;
+  wheelEvent.type = WebInputEvent::MouseWheel;
+  wheelEvent.timeStampSeconds = pinch_event.event.timeStampSeconds;
+  wheelEvent.windowX = wheelEvent.x = pinch_event.event.x;
+  wheelEvent.windowY = wheelEvent.y = pinch_event.event.y;
+  wheelEvent.globalX = pinch_event.event.globalX;
+  wheelEvent.globalY = pinch_event.event.globalY;
+  wheelEvent.modifiers =
+      pinch_event.event.modifiers | WebInputEvent::ControlKey;
+  wheelEvent.deltaX = 0;
+  // The function to convert scales to deltaY values is designed to be
+  // compatible with websites existing use of wheel events, and with existing
+  // Windows trackpad behavior.  In particular, we want:
+  //  - deltas should accumulate via addition: f(s1*s2)==f(s1)+f(s2)
+  //  - deltas should invert via negation: f(1/s) == -f(s)
+  //  - zoom in should be positive: f(s) > 0 iff s > 1
+  //  - magnitude roughly matches wheels: f(2) > 25 && f(2) < 100
+  //  - a formula that's relatively easy to use from JavaScript
+  // Note that 'wheel' event deltaY values have their sign inverted.  So to
+  // convert a wheel deltaY back to a scale use Math.exp(-deltaY/100).
+  DCHECK_GT(pinch_event.event.data.pinchUpdate.scale, 0);
+  wheelEvent.deltaY = 100.0f * log(pinch_event.event.data.pinchUpdate.scale);
+  wheelEvent.hasPreciseScrollingDeltas = true;
+  wheelEvent.wheelTicksX = 0;
+  wheelEvent.wheelTicksY =
+      pinch_event.event.data.pinchUpdate.scale > 1 ? 1 : -1;
+
+  SendWheelEvent(QueuedWheelEvent(
+      MouseWheelEventWithLatencyInfo(wheelEvent, pinch_event.latency), true));
+}
+
 void InputRouterImpl::OnInputEventAck(WebInputEvent::Type event_type,
                                       InputEventAckState ack_result,
                                       const ui::LatencyInfo& latency_info) {
-  // A synthetic ack will already have been sent for this event, and it should
-  // not affect event timing or in-flight count metrics.
-  if (WebInputEventTraits::IgnoresAckDisposition(event_type))
-    return;
-
   client_->DecrementInFlightEventCount();
 
   // Log the time delta for processing an input event.
@@ -561,13 +532,13 @@ void InputRouterImpl::OnHasTouchEventHandlers(bool has_handlers) {
   TRACE_EVENT1("input", "InputRouterImpl::OnHasTouchEventHandlers",
                "has_handlers", has_handlers);
 
-  touch_event_queue_->OnHasTouchEventHandlers(has_handlers);
+  touch_event_queue_.OnHasTouchEventHandlers(has_handlers);
   client_->OnHasTouchEventHandlers(has_handlers);
 }
 
 void InputRouterImpl::OnSetTouchAction(TouchAction touch_action) {
   // Synthetic touchstart events should get filtered out in RenderWidget.
-  DCHECK(touch_event_queue_->IsPendingAckTouchStart());
+  DCHECK(touch_event_queue_.IsPendingAckTouchStart());
   TRACE_EVENT1("input", "InputRouterImpl::OnSetTouchAction",
                "action", touch_action);
 
@@ -609,6 +580,8 @@ void InputRouterImpl::ProcessInputEventAck(
   } else if (event_type != WebInputEvent::Undefined) {
     ack_handler_->OnUnexpectedEventAck(InputAckHandler::BAD_ACK_MESSAGE);
   }
+
+  SignalFlushedIfNecessary();
 }
 
 void InputRouterImpl::ProcessKeyboardAck(blink::WebInputEvent::Type type,
@@ -649,20 +622,32 @@ void InputRouterImpl::ProcessMouseAck(blink::WebInputEvent::Type type,
 
 void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result,
                                       const ui::LatencyInfo& latency) {
-  ProcessAckForOverscroll(current_wheel_event_.event, ack_result);
-
   // TODO(miletus): Add renderer side latency to each uncoalesced mouse
   // wheel event and add terminal component to each of them.
-  current_wheel_event_.latency.AddNewLatencyFrom(latency);
-  // Process the unhandled wheel event here before calling SendWheelEvent()
-  // since it will mutate current_wheel_event_.
-  ack_handler_->OnWheelEventAck(current_wheel_event_, ack_result);
+  current_wheel_event_.event.latency.AddNewLatencyFrom(latency);
+
+  if (current_wheel_event_.synthesized_from_pinch) {
+    // Ack the GesturePinchUpdate event that generated this wheel event.
+    ProcessInputEventAck(WebInputEvent::GesturePinchUpdate,
+                         ack_result,
+                         current_wheel_event_.event.latency,
+                         current_ack_source_);
+  } else {
+    // Process the unhandled wheel event here before calling SendWheelEvent()
+    // since it will mutate current_wheel_event_.
+    ProcessAckForOverscroll(current_wheel_event_.event.event, ack_result);
+    ack_handler_->OnWheelEventAck(current_wheel_event_.event, ack_result);
+  }
+
+  // Mark the wheel event complete only after the ACKs have been handled above.
+  // For example, ACKing the GesturePinchUpdate could cause another
+  // GesturePinchUpdate to be sent, which should queue a wheel event rather than
+  // send it immediately.
   mouse_wheel_pending_ = false;
 
-  // Now send the next (coalesced) mouse wheel event.
+  // Send the next (coalesced or synthetic) mouse wheel event.
   if (!coalesced_mouse_wheel_events_.empty()) {
-    MouseWheelEventWithLatencyInfo next_wheel_event =
-        coalesced_mouse_wheel_events_.front();
+    QueuedWheelEvent next_wheel_event = coalesced_mouse_wheel_events_.front();
     coalesced_mouse_wheel_events_.pop_front();
     SendWheelEvent(next_wheel_event);
   }
@@ -674,19 +659,19 @@ void InputRouterImpl::ProcessGestureAck(WebInputEvent::Type type,
   // If |ack_result| originated from the overscroll controller, only
   // feed |gesture_event_queue_| the ack if it was expecting one.
   if (current_ack_source_ == OVERSCROLL_CONTROLLER &&
-      !gesture_event_queue_->HasQueuedGestureEvents()) {
+      !gesture_event_queue_.ExpectingGestureAck()) {
     return;
   }
 
   // |gesture_event_queue_| will forward to OnGestureEventAck when appropriate.
-  gesture_event_queue_->ProcessGestureAck(ack_result, type, latency);
+  gesture_event_queue_.ProcessGestureAck(ack_result, type, latency);
 }
 
 void InputRouterImpl::ProcessTouchAck(
     InputEventAckState ack_result,
     const ui::LatencyInfo& latency) {
   // |touch_event_queue_| will forward to OnTouchEventAck when appropriate.
-  touch_event_queue_->ProcessTouchAck(ack_result, latency);
+  touch_event_queue_.ProcessTouchAck(ack_result, latency);
 }
 
 void InputRouterImpl::ProcessAckForOverscroll(const WebInputEvent& event,
@@ -704,92 +689,7 @@ void InputRouterImpl::ProcessAckForOverscroll(const WebInputEvent& event,
       event, (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result));
 }
 
-void InputRouterImpl::SimulateTouchGestureWithMouse(
-    const MouseEventWithLatencyInfo& event) {
-  const WebMouseEvent& mouse_event = event.event;
-  int x = mouse_event.x, y = mouse_event.y;
-  float dx = mouse_event.movementX, dy = mouse_event.movementY;
-  static int startX = 0, startY = 0;
-
-  switch (mouse_event.button) {
-    case WebMouseEvent::ButtonLeft:
-      if (mouse_event.type == WebInputEvent::MouseDown) {
-        startX = x;
-        startY = y;
-        SendGestureEvent(MakeGestureEvent(
-            WebInputEvent::GestureScrollBegin, mouse_event.timeStampSeconds,
-            x, y, 0, event.latency));
-      }
-      if (dx != 0 || dy != 0) {
-        GestureEventWithLatencyInfo gesture_event = MakeGestureEvent(
-            WebInputEvent::GestureScrollUpdate, mouse_event.timeStampSeconds,
-            x, y, 0, event.latency);
-        gesture_event.event.data.scrollUpdate.deltaX = dx;
-        gesture_event.event.data.scrollUpdate.deltaY = dy;
-        SendGestureEvent(gesture_event);
-      }
-      if (mouse_event.type == WebInputEvent::MouseUp) {
-        SendGestureEvent(MakeGestureEvent(
-            WebInputEvent::GestureScrollEnd, mouse_event.timeStampSeconds,
-            x, y, 0, event.latency));
-      }
-      break;
-    case WebMouseEvent::ButtonMiddle:
-      if (mouse_event.type == WebInputEvent::MouseDown) {
-        startX = x;
-        startY = y;
-        SendGestureEvent(MakeGestureEvent(
-            WebInputEvent::GestureShowPress, mouse_event.timeStampSeconds,
-            x, y, 0, event.latency));
-        SendGestureEvent(MakeGestureEvent(
-            WebInputEvent::GestureTapDown, mouse_event.timeStampSeconds,
-            x, y, 0, event.latency));
-      }
-      if (mouse_event.type == WebInputEvent::MouseUp) {
-        SendGestureEvent(MakeGestureEvent(
-            WebInputEvent::GestureTap, mouse_event.timeStampSeconds,
-            x, y, 0, event.latency));
-      }
-      break;
-    case WebMouseEvent::ButtonRight:
-      if (mouse_event.type == WebInputEvent::MouseDown) {
-        startX = x;
-        startY = y;
-        SendGestureEvent(MakeGestureEvent(
-            WebInputEvent::GestureScrollBegin, mouse_event.timeStampSeconds,
-            x, y, 0, event.latency));
-        SendGestureEvent(MakeGestureEvent(
-            WebInputEvent::GesturePinchBegin, mouse_event.timeStampSeconds,
-            x, y, 0, event.latency));
-      }
-      if (dx != 0 || dy != 0) {
-        dx = pow(dy < 0 ? 0.998f : 1.002f, fabs(dy));
-        GestureEventWithLatencyInfo gesture_event = MakeGestureEvent(
-            WebInputEvent::GesturePinchUpdate, mouse_event.timeStampSeconds,
-            startX, startY, 0, event.latency);
-        gesture_event.event.data.pinchUpdate.scale = dx;
-        SendGestureEvent(gesture_event);
-      }
-      if (mouse_event.type == WebInputEvent::MouseUp) {
-        SendGestureEvent(MakeGestureEvent(
-            WebInputEvent::GesturePinchEnd, mouse_event.timeStampSeconds,
-            x, y, 0, event.latency));
-        SendGestureEvent(MakeGestureEvent(
-            WebInputEvent::GestureScrollEnd, mouse_event.timeStampSeconds,
-            x, y, 0, event.latency));
-      }
-      break;
-    case WebMouseEvent::ButtonNone:
-      break;
-  }
-}
-
 void InputRouterImpl::UpdateTouchAckTimeoutEnabled() {
-  if (!touch_ack_timeout_supported_) {
-    touch_event_queue_->SetAckTimeoutEnabled(false, base::TimeDelta());
-    return;
-  }
-
   // Mobile sites tend to be well-behaved with respect to touch handling, so
   // they have less need for the touch timeout fallback.
   const bool fixed_page_scale = (current_view_flags_ & FIXED_PAGE_SCALE) != 0;
@@ -804,8 +704,28 @@ void InputRouterImpl::UpdateTouchAckTimeoutEnabled() {
   const bool touch_ack_timeout_enabled = !fixed_page_scale &&
                                          !mobile_viewport &&
                                          !touch_action_none;
-  touch_event_queue_->SetAckTimeoutEnabled(touch_ack_timeout_enabled,
-                                           touch_ack_timeout_delay_);
+  touch_event_queue_.SetAckTimeoutEnabled(touch_ack_timeout_enabled);
+}
+
+void InputRouterImpl::SignalFlushedIfNecessary() {
+  if (!flush_requested_)
+    return;
+
+  if (HasPendingEvents())
+    return;
+
+  flush_requested_ = false;
+  client_->DidFlush();
+}
+
+bool InputRouterImpl::HasPendingEvents() const {
+  return !touch_event_queue_.empty() ||
+         !gesture_event_queue_.empty() ||
+         !key_queue_.empty() ||
+         mouse_move_pending_ ||
+         mouse_wheel_pending_ ||
+         select_range_pending_ ||
+         move_caret_pending_;
 }
 
 bool InputRouterImpl::IsInOverscrollGesture() const {
@@ -813,4 +733,17 @@ bool InputRouterImpl::IsInOverscrollGesture() const {
   return controller && controller->overscroll_mode() != OVERSCROLL_NONE;
 }
 
+InputRouterImpl::QueuedWheelEvent::QueuedWheelEvent()
+    : synthesized_from_pinch(false) {
+}
+
+InputRouterImpl::QueuedWheelEvent::QueuedWheelEvent(
+    const MouseWheelEventWithLatencyInfo& event,
+    bool synthesized_from_pinch)
+    : event(event), synthesized_from_pinch(synthesized_from_pinch) {
+}
+
+InputRouterImpl::QueuedWheelEvent::~QueuedWheelEvent() {
+}
+
 }  // namespace content