#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;
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";
} // 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),
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);
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;
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,
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);
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
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);
}
}
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) {
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);
}
"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();
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,
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));
}
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();
}
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.
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);
} else if (event_type != WebInputEvent::Undefined) {
ack_handler_->OnUnexpectedEventAck(InputAckHandler::BAD_ACK_MESSAGE);
}
+
+ SignalFlushedIfNecessary();
}
void InputRouterImpl::ProcessKeyboardAck(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);
}
// 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,
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;
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 {
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