diff options
author | eroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-14 23:58:08 +0000 |
---|---|---|
committer | eroman@chromium.org <eroman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-14 23:58:08 +0000 |
commit | 3a678cfe431c44d9397e4616c676578f58ed69ca (patch) | |
tree | 435a2268621b2bdad69819f76eb3f1c5925bf11f /content/browser/renderer_host | |
parent | 11296397e92f1354233581b91e8919bfb17d555b (diff) | |
download | chromium_src-3a678cfe431c44d9397e4616c676578f58ed69ca.zip chromium_src-3a678cfe431c44d9397e4616c676578f58ed69ca.tar.gz chromium_src-3a678cfe431c44d9397e4616c676578f58ed69ca.tar.bz2 |
Revert "Simplify InputRouter event filtering"
This reverts r228554 due to linux asan failure:
http://build.chromium.org/p/chromium.memory/builders/Linux%20ASAN%20Tests%20%283%29/builds/16857/steps/interactive_ui_tests/logs/HandlersRegistered
TBR=jdduke
BUG=302492
Review URL: https://codereview.chromium.org/26343004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@228567 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/renderer_host')
15 files changed, 712 insertions, 495 deletions
diff --git a/content/browser/renderer_host/input/immediate_input_router.cc b/content/browser/renderer_host/input/immediate_input_router.cc index df2db2b..dfc5187 100644 --- a/content/browser/renderer_host/input/immediate_input_router.cc +++ b/content/browser/renderer_host/input/immediate_input_router.cc @@ -4,7 +4,6 @@ #include "content/browser/renderer_host/input/immediate_input_router.h" -#include "base/auto_reset.h" #include "base/command_line.h" #include "base/metrics/histogram.h" #include "content/browser/renderer_host/input/gesture_event_filter.h" @@ -12,7 +11,7 @@ #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/overscroll_controller.h" +#include "content/browser/renderer_host/render_process_host_impl.h" #include "content/common/content_constants_internal.h" #include "content/common/edit_command.h" #include "content/common/input_messages.h" @@ -22,7 +21,6 @@ #include "content/public/browser/notification_types.h" #include "content/public/browser/user_metrics.h" #include "content/public/common/content_switches.h" -#include "ipc/ipc_sender.h" #include "ui/events/event.h" #include "ui/events/keycodes/keyboard_codes.h" @@ -59,24 +57,6 @@ float GetAccelerationRatio(float accelerated_delta, float unaccelerated_delta) { return unaccelerated_delta / accelerated_delta; } -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"; @@ -92,11 +72,11 @@ const char* GetEventAckName(InputEventAckState ack_result) { } // namespace -ImmediateInputRouter::ImmediateInputRouter(IPC::Sender* sender, +ImmediateInputRouter::ImmediateInputRouter(RenderProcessHost* process, InputRouterClient* client, InputAckHandler* ack_handler, int routing_id) - : sender_(sender), + : process_(process), client_(client), ack_handler_(ack_handler), routing_id_(routing_id), @@ -105,12 +85,10 @@ ImmediateInputRouter::ImmediateInputRouter(IPC::Sender* sender, mouse_move_pending_(false), mouse_wheel_pending_(false), has_touch_handler_(false), - current_ack_source_(ACK_SOURCE_NONE), touch_event_queue_(new TouchEventQueue(this)), gesture_event_filter_(new GestureEventFilter(this, this)) { - DCHECK(sender); + DCHECK(process); DCHECK(client); - DCHECK(ack_handler); } ImmediateInputRouter::~ImmediateInputRouter() { @@ -138,13 +116,8 @@ bool ImmediateInputRouter::SendInput(scoped_ptr<IPC::Message> message) { void ImmediateInputRouter::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); + if (!client_->OnSendMouseEvent(mouse_event)) return; - } if (mouse_event.event.type == WebInputEvent::MouseDown && gesture_event_filter_->GetTouchpadTapSuppressionController()-> @@ -160,6 +133,9 @@ void ImmediateInputRouter::SendMouseEvent( void ImmediateInputRouter::SendWheelEvent( const MouseWheelEventWithLatencyInfo& wheel_event) { + if (!client_->OnSendWheelEvent(wheel_event)) + return; + // 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 @@ -209,8 +185,11 @@ void ImmediateInputRouter::SendWheelEvent( void ImmediateInputRouter::SendKeyboardEvent( const NativeWebKeyboardEvent& key_event, - const ui::LatencyInfo& latency_info, - bool is_keyboard_shortcut) { + const ui::LatencyInfo& latency_info) { + bool is_shortcut = false; + if (!client_->OnSendKeyboardEvent(key_event, latency_info, &is_shortcut)) + return; + // Put all WebKeyboardEvent objects in a queue since we can't trust the // renderer and we need to give something to the HandleKeyboardEvent // handler. @@ -220,26 +199,21 @@ void ImmediateInputRouter::SendKeyboardEvent( gesture_event_filter_->FlingHasBeenHalted(); // Only forward the non-native portions of our event. - FilterAndSendWebInputEvent(key_event, latency_info, is_keyboard_shortcut); + FilterAndSendWebInputEvent(key_event, latency_info, is_shortcut); } void ImmediateInputRouter::SendGestureEvent( const GestureEventWithLatencyInfo& gesture_event) { HandleGestureScroll(gesture_event); - - if (!IsInOverscrollGesture() && - !ShouldForwardGestureEvent(gesture_event)) { - OverscrollController* controller = client_->GetOverscrollController(); - if (controller) - controller->DiscardingGestureEvent(gesture_event.event); + if (!client_->OnSendGestureEvent(gesture_event)) return; - } - FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency, false); } void ImmediateInputRouter::SendTouchEvent( const TouchEventWithLatencyInfo& touch_event) { + // Always queue TouchEvents, even if the client request they be dropped. + client_->OnSendTouchEvent(touch_event); touch_event_queue_->QueueEvent(touch_event); } @@ -247,6 +221,9 @@ void ImmediateInputRouter::SendTouchEvent( // TouchpadTapSuppressionController. void ImmediateInputRouter::SendMouseEventImmediately( const MouseEventWithLatencyInfo& mouse_event) { + if (!client_->OnSendMouseEventImmediately(mouse_event)) + return; + // Avoid spamming the renderer with mouse move events. It is important // to note that WM_MOUSEMOVE events are anyways synthetic, but since our // thread is able to rapidly consume WM_MOUSEMOVE events, we may get way @@ -274,12 +251,16 @@ void ImmediateInputRouter::SendMouseEventImmediately( void ImmediateInputRouter::SendTouchEventImmediately( const TouchEventWithLatencyInfo& touch_event) { + if (!client_->OnSendTouchEventImmediately(touch_event)) + return; FilterAndSendWebInputEvent(touch_event.event, touch_event.latency, false); } void ImmediateInputRouter::SendGestureEventImmediately( const GestureEventWithLatencyInfo& gesture_event) { HandleGestureScroll(gesture_event); + if (!client_->OnSendGestureEventImmediately(gesture_event)) + return; FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency, false); } @@ -330,7 +311,6 @@ void ImmediateInputRouter::OnTouchEventAck( void ImmediateInputRouter::OnGestureEventAck( const GestureEventWithLatencyInfo& event, InputEventAckState ack_result) { - ProcessAckForOverscroll(event.event, ack_result); ack_handler_->OnGestureEventAck(event, ack_result); } @@ -357,7 +337,7 @@ bool ImmediateInputRouter::SendMoveCaret(scoped_ptr<IPC::Message> message) { } bool ImmediateInputRouter::Send(IPC::Message* message) { - return sender_->Send(message); + return process_->Send(message); } void ImmediateInputRouter::SendWebInputEvent( @@ -365,10 +345,9 @@ void ImmediateInputRouter::SendWebInputEvent( const ui::LatencyInfo& latency_info, bool is_keyboard_shortcut) { input_event_start_time_ = TimeTicks::Now(); - if (Send(new InputMsg_HandleInputEvent( - routing_id(), &input_event, latency_info, is_keyboard_shortcut))) { - client_->IncrementInFlightEventCount(); - } + Send(new InputMsg_HandleInputEvent( + routing_id(), &input_event, latency_info, is_keyboard_shortcut)); + client_->IncrementInFlightEventCount(); } void ImmediateInputRouter::FilterAndSendWebInputEvent( @@ -377,22 +356,13 @@ void ImmediateInputRouter::FilterAndSendWebInputEvent( bool is_keyboard_shortcut) { TRACE_EVENT0("input", "ImmediateInputRouter::FilterAndSendWebInputEvent"); - // Yield events to the OverscrollController before forwarding. - OverscrollController* controller = client_->GetOverscrollController(); - if (controller && !controller->WillDispatchEvent(input_event, latency_info)) { - InputEventAckState overscroll_ack = - WebInputEvent::isTouchEventType(input_event.type) ? - INPUT_EVENT_ACK_STATE_NOT_CONSUMED : INPUT_EVENT_ACK_STATE_CONSUMED; - ProcessInputEventAck(input_event.type, - overscroll_ack, - latency_info, - OVERSCROLL_CONTROLLER); - // WARNING: |this| may be deleted at this point. + if (!process_->HasConnection()) return; - } - // Yield events to the client to either synchronously handle the event or drop - // it entirely. + DCHECK(!process_->IgnoreInputEvents()); + + // Perform optional, synchronous event handling, sending ACK messages for + // processed events, or proceeding as usual. InputEventAckState filter_ack = client_->FilterInputEvent(input_event, latency_info); switch (filter_ack) { @@ -400,12 +370,42 @@ void ImmediateInputRouter::FilterAndSendWebInputEvent( case INPUT_EVENT_ACK_STATE_CONSUMED: case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS: next_mouse_move_.reset(); - ProcessInputEventAck(input_event.type, filter_ack, latency_info, CLIENT); + ProcessInputEventAck(input_event.type, filter_ack, latency_info); // WARNING: |this| may be deleted at this point. return; - case INPUT_EVENT_ACK_STATE_UNKNOWN: + + case INPUT_EVENT_ACK_STATE_UNKNOWN: { + if (input_event.type == WebKit::WebInputEvent::MouseMove) { + // Since this mouse-move event has been consumed, there will be no ACKs. + // So reset the state here so that future mouse-move events do reach the + // renderer. + mouse_move_pending_ = false; + } else if (input_event.type == WebKit::WebInputEvent::MouseWheel) { + // Reset the wheel-event state when appropriate. + mouse_wheel_pending_ = false; + } else if (WebInputEvent::isGestureEventType(input_event.type) && + gesture_event_filter_->HasQueuedGestureEvents()) { + // If the gesture-event filter has queued gesture events, that implies + // it's awaiting an ack for the event. Since the event is being dropped, + // it is never sent to the renderer, and so it won't receive any ACKs. + // So send the ACK to the gesture event filter immediately, and mark it + // as having been processed. + ProcessGestureAck(input_event.type, INPUT_EVENT_ACK_STATE_CONSUMED, + latency_info); + } else if (WebInputEvent::isTouchEventType(input_event.type)) { + // During an overscroll gesture initiated by touch-scrolling, the + // touch-events do not reset or contribute to the overscroll gesture. + // However, the touch-events are not sent to the renderer. So send an + // ACK to the touch-event queue immediately. Mark the event as not + // processed, to make sure that the touch-scroll gesture that initiated + // the overscroll is updated properly. + ProcessTouchAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, latency_info); + } return; - default: + } + + // Proceed as normal. + case INPUT_EVENT_ACK_STATE_NOT_CONSUMED: break; } @@ -415,8 +415,8 @@ void ImmediateInputRouter::FilterAndSendWebInputEvent( if (input_event.type != WebInputEvent::MouseWheel) { for (size_t i = 0; i < coalesced_mouse_wheel_events_.size(); ++i) { SendWebInputEvent(coalesced_mouse_wheel_events_[i].event, - coalesced_mouse_wheel_events_[i].latency, - false); + coalesced_mouse_wheel_events_[i].latency, + false); } coalesced_mouse_wheel_events_.clear(); } @@ -437,21 +437,7 @@ void ImmediateInputRouter::OnInputEventAck( client_->DecrementInFlightEventCount(); - ProcessInputEventAck(event_type, ack_result, latency_info, RENDERER); - // WARNING: |this| may be deleted at this point. - - // This is used only for testing, and the other end does not use the - // source object. On linux, specifying - // Source<RenderWidgetHost> results in a very strange - // runtime error in the epilogue of the enclosing - // (ProcessInputEventAck) method, but not on other platforms; using - // 'void' instead is just as safe (since NotificationSource - // is not actually typesafe) and avoids this error. - int type = static_cast<int>(event_type); - NotificationService::current()->Notify( - NOTIFICATION_RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK, - Source<void>(this), - Details<int>(&type)); + ProcessInputEventAck(event_type, ack_result, latency_info); } void ImmediateInputRouter::OnMsgMoveCaretAck() { @@ -478,29 +464,46 @@ void ImmediateInputRouter::OnHasTouchEventHandlers(bool has_handlers) { void ImmediateInputRouter::ProcessInputEventAck( WebInputEvent::Type event_type, InputEventAckState ack_result, - const ui::LatencyInfo& latency_info, - AckSource ack_source) { + const ui::LatencyInfo& latency_info) { TRACE_EVENT1("input", "ImmediateInputRouter::ProcessInputEventAck", "ack", GetEventAckName(ack_result)); - base::AutoReset<AckSource> auto_reset_current_ack_source( - ¤t_ack_source_, ack_source); - - if (WebInputEvent::isMouseEventType(event_type)) { - ProcessMouseAck(event_type, ack_result); - } else if (WebInputEvent::isKeyboardEventType(event_type)) { + int type = static_cast<int>(event_type); + if (type < WebInputEvent::Undefined) { + ack_handler_->OnUnexpectedEventAck(InputAckHandler::BAD_ACK_MESSAGE); + } else if (type == WebInputEvent::MouseMove) { + mouse_move_pending_ = false; + + // now, we can send the next mouse move event + if (next_mouse_move_) { + DCHECK(next_mouse_move_->event.type == WebInputEvent::MouseMove); + scoped_ptr<MouseEventWithLatencyInfo> next_mouse_move + = next_mouse_move_.Pass(); + SendMouseEvent(*next_mouse_move); + } + } else if (WebInputEvent::isKeyboardEventType(type)) { ProcessKeyboardAck(event_type, ack_result); - } else if (event_type == WebInputEvent::MouseWheel) { + } else if (type == WebInputEvent::MouseWheel) { ProcessWheelAck(ack_result, latency_info); - } else if (WebInputEvent::isTouchEventType(event_type)) { + } else if (WebInputEvent::isTouchEventType(type)) { ProcessTouchAck(ack_result, latency_info); - } else if (WebInputEvent::isGestureEventType(event_type)) { + } else if (WebInputEvent::isGestureEventType(type)) { ProcessGestureAck(event_type, ack_result, latency_info); - } else if (event_type != WebInputEvent::Undefined) { - ack_handler_->OnUnexpectedEventAck(InputAckHandler::BAD_ACK_MESSAGE); } // WARNING: |this| may be deleted at this point. + + // This is used only for testing, and the other end does not use the + // source object. On linux, specifying + // Source<RenderWidgetHost> results in a very strange + // runtime error in the epilogue of the enclosing + // (ProcessInputEventAck) method, but not on other platforms; using + // 'void' instead is just as safe (since NotificationSource + // is not actually typesafe) and avoids this error. + NotificationService::current()->Notify( + NOTIFICATION_RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK, + Source<void>(this), + Details<int>(&type)); } void ImmediateInputRouter::ProcessKeyboardAck( @@ -521,34 +524,17 @@ void ImmediateInputRouter::ProcessKeyboardAck( // WARNING: This ImmediateInputRouter can be deallocated at this point // (i.e. in the case of Ctrl+W, where the call to // HandleKeyboardEvent destroys this ImmediateInputRouter). - // TODO(jdduke): crbug.com/274029 - Make ack-triggered shutdown async. - } -} - -void ImmediateInputRouter::ProcessMouseAck(WebKit::WebInputEvent::Type type, - InputEventAckState ack_result) { - if (type != WebInputEvent::MouseMove) - return; - - mouse_move_pending_ = false; - - if (next_mouse_move_) { - DCHECK(next_mouse_move_->event.type == WebInputEvent::MouseMove); - scoped_ptr<MouseEventWithLatencyInfo> next_mouse_move - = next_mouse_move_.Pass(); - SendMouseEvent(*next_mouse_move); } } void ImmediateInputRouter::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_. + // Process the unhandled wheel event here before calling + // ForwardWheelEventWithLatencyInfo() since it will mutate + // current_wheel_event_. ack_handler_->OnWheelEventAck(current_wheel_event_, ack_result); mouse_wheel_pending_ = false; @@ -564,13 +550,6 @@ void ImmediateInputRouter::ProcessWheelAck(InputEventAckState ack_result, void ImmediateInputRouter::ProcessGestureAck(WebInputEvent::Type type, InputEventAckState ack_result, const ui::LatencyInfo& latency) { - // If |ack_result| originated from the overscroll controller, only - // feed |gesture_event_filter_| the ack if it was expecting one. - if (current_ack_source_ == OVERSCROLL_CONTROLLER && - !gesture_event_filter_->HasQueuedGestureEvents()) { - return; - } - // |gesture_event_filter_| will forward to OnGestureEventAck when appropriate. gesture_event_filter_->ProcessGestureAck(ack_result, type, latency); } @@ -582,107 +561,9 @@ void ImmediateInputRouter::ProcessTouchAck( touch_event_queue_->ProcessTouchAck(ack_result, latency); } -void ImmediateInputRouter::ProcessAckForOverscroll( - const WebInputEvent& event, - InputEventAckState ack_result) { - // Acks sent from the overscroll controller need not be fed back into the - // overscroll controller. - if (current_ack_source_ == OVERSCROLL_CONTROLLER) - return; - - OverscrollController* controller = client_->GetOverscrollController(); - if (!controller) - return; - - controller->ReceivedEventACK( - event, (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result)); -} - void ImmediateInputRouter::HandleGestureScroll( const GestureEventWithLatencyInfo& gesture_event) { touch_event_queue_->OnGestureScrollEvent(gesture_event); } -void ImmediateInputRouter::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::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; - } -} - -bool ImmediateInputRouter::IsInOverscrollGesture() const { - OverscrollController* controller = client_->GetOverscrollController(); - return controller && controller->overscroll_mode() != OVERSCROLL_NONE; -} - } // namespace content diff --git a/content/browser/renderer_host/input/immediate_input_router.h b/content/browser/renderer_host/input/immediate_input_router.h index 9390a61..5f4f7fb 100644 --- a/content/browser/renderer_host/input/immediate_input_router.h +++ b/content/browser/renderer_host/input/immediate_input_router.h @@ -16,10 +16,6 @@ #include "content/browser/renderer_host/input/touchpad_tap_suppression_controller.h" #include "content/public/browser/native_web_keyboard_event.h" -namespace IPC { -class Sender; -} - namespace ui { struct LatencyInfo; } @@ -28,7 +24,7 @@ namespace content { class InputAckHandler; class InputRouterClient; -class OverscrollController; +class RenderProcessHost; class RenderWidgetHostImpl; // A default implementation for browser input event routing. Input commands are @@ -39,7 +35,7 @@ class CONTENT_EXPORT ImmediateInputRouter public NON_EXPORTED_BASE(TouchEventQueueClient), public NON_EXPORTED_BASE(TouchpadTapSuppressionControllerClient) { public: - ImmediateInputRouter(IPC::Sender* sender, + ImmediateInputRouter(RenderProcessHost* process, InputRouterClient* client, InputAckHandler* ack_handler, int routing_id); @@ -54,12 +50,17 @@ class CONTENT_EXPORT ImmediateInputRouter const MouseWheelEventWithLatencyInfo& wheel_event) OVERRIDE; virtual void SendKeyboardEvent( const NativeWebKeyboardEvent& key_event, - const ui::LatencyInfo& latency_info, - bool is_keyboard_shortcut) OVERRIDE; + const ui::LatencyInfo& latency_info) OVERRIDE; virtual void SendGestureEvent( const GestureEventWithLatencyInfo& gesture_event) OVERRIDE; virtual void SendTouchEvent( const TouchEventWithLatencyInfo& touch_event) OVERRIDE; + virtual void SendMouseEventImmediately( + const MouseEventWithLatencyInfo& mouse_event) OVERRIDE; + virtual void SendTouchEventImmediately( + const TouchEventWithLatencyInfo& touch_event) OVERRIDE; + virtual void SendGestureEventImmediately( + const GestureEventWithLatencyInfo& gesture_event) OVERRIDE; virtual const NativeWebKeyboardEvent* GetLastKeyboardEvent() const OVERRIDE; virtual bool ShouldForwardTouchEvent() const OVERRIDE; virtual bool ShouldForwardGestureEvent( @@ -68,23 +69,22 @@ class CONTENT_EXPORT ImmediateInputRouter // IPC::Listener virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + GestureEventFilter* gesture_event_filter() { + return gesture_event_filter_.get(); + } + + TouchEventQueue* touch_event_queue() { + return touch_event_queue_.get(); + } + private: friend class ImmediateInputRouterTest; - friend class MockRenderWidgetHost; - - // TouchpadTapSuppressionControllerClient - virtual void SendMouseEventImmediately( - const MouseEventWithLatencyInfo& mouse_event) OVERRIDE; // TouchEventQueueClient - virtual void SendTouchEventImmediately( - const TouchEventWithLatencyInfo& touch_event) OVERRIDE; virtual void OnTouchEventAck(const TouchEventWithLatencyInfo& event, InputEventAckState ack_result) OVERRIDE; // GetureEventFilterClient - virtual void SendGestureEventImmediately( - const GestureEventWithLatencyInfo& gesture_event) OVERRIDE; virtual void OnGestureEventAck(const GestureEventWithLatencyInfo& event, InputEventAckState ack_result) OVERRIDE; @@ -112,60 +112,43 @@ private: void OnSelectRangeAck(); void OnHasTouchEventHandlers(bool has_handlers); - // Indicates the source of an ack provided to |ProcessInputEventAck()|. - // The source is tracked by |current_ack_source_|, which aids in ack routing. - enum AckSource { - RENDERER, - CLIENT, - OVERSCROLL_CONTROLLER, - ACK_SOURCE_NONE - }; - // Note: This function may result in |this| being deleted, and as such - // should be the last method called in any internal chain of event handling. + // Handle the event ack. Triggered via |OnInputEventAck()| if the event was + // processed in the renderer, or synchonously from |FilterAndSendInputevent()| + // if the event was filtered by the |client_| prior to sending. void ProcessInputEventAck(WebKit::WebInputEvent::Type event_type, InputEventAckState ack_result, - const ui::LatencyInfo& latency_info, - AckSource ack_source); + const ui::LatencyInfo& latency_info); - // Dispatches the ack'ed event to |ack_handler_|. + // Called by ProcessInputEventAck() to process a keyboard event ack message. void ProcessKeyboardAck(WebKit::WebInputEvent::Type type, InputEventAckState ack_result); - // Forwards a valid |next_mouse_move_| if |type| is MouseMove. - void ProcessMouseAck(WebKit::WebInputEvent::Type type, - InputEventAckState ack_result); - - // Dispatches the ack'ed event to |ack_handler_|, forwarding queued events - // from |coalesced_mouse_wheel_events_|. + // Called by ProcessInputEventAck() to process a wheel event ack message. + // This could result in a task being posted to allow additional wheel + // input messages to be coalesced. void ProcessWheelAck(InputEventAckState ack_result, const ui::LatencyInfo& latency); - // Forwards the event ack to |gesture_event_filter|, potentially triggering - // dispatch of queued gesture events. - void ProcessGestureAck(WebKit::WebInputEvent::Type type, + // Called by ProcessInputEventAck() to process a gesture event ack message. + // This validates the gesture for suppression of touchpad taps and sends one + // previously queued coalesced gesture if it exists. + void ProcessGestureAck(WebKit::WebInputEvent::Type, InputEventAckState ack_result, const ui::LatencyInfo& latency); - // Forwards the event ack to |touch_event_queue_|, potentially triggering - // dispatch of queued touch events, or the creation of gesture events. + // Called on ProcessInputEventAck() to process a touch event ack message. + // This can result in a gesture event being generated and sent back to the + // renderer. void ProcessTouchAck(InputEventAckState ack_result, const ui::LatencyInfo& latency); - // Forwards |ack_result| to the client's OverscrollController, if necessary. - void ProcessAckForOverscroll(const WebKit::WebInputEvent& event, - InputEventAckState ack_result); - - void HandleGestureScroll(const GestureEventWithLatencyInfo& gesture_event); - - void SimulateTouchGestureWithMouse( - const MouseEventWithLatencyInfo& mouse_event); - - bool IsInOverscrollGesture() const; + void HandleGestureScroll( + const GestureEventWithLatencyInfo& gesture_event); int routing_id() const { return routing_id_; } - IPC::Sender* sender_; + RenderProcessHost* process_; InputRouterClient* client_; InputAckHandler* ack_handler_; int routing_id_; @@ -222,10 +205,6 @@ private: // not sent to the renderer. bool has_touch_handler_; - // The source of the ack within the scope of |ProcessInputEventAck()|. - // Defaults to ACK_SOURCE_NONE. - AckSource current_ack_source_; - scoped_ptr<TouchEventQueue> touch_event_queue_; scoped_ptr<GestureEventFilter> gesture_event_filter_; diff --git a/content/browser/renderer_host/input/immediate_input_router_unittest.cc b/content/browser/renderer_host/input/immediate_input_router_unittest.cc index b861289..0e7d097f 100644 --- a/content/browser/renderer_host/input/immediate_input_router_unittest.cc +++ b/content/browser/renderer_host/input/immediate_input_router_unittest.cc @@ -130,37 +130,32 @@ class ImmediateInputRouterTest : public InputRouterTest { } bool no_touch_to_renderer() { - return input_router()->touch_event_queue_->no_touch_to_renderer(); + return input_router()->touch_event_queue()->no_touch_to_renderer(); } bool TouchEventQueueEmpty() const { - return input_router()->touch_event_queue_->empty(); - } - - size_t GetSentMessageCountAndResetSink() { - size_t count = process_->sink().message_count(); - process_->sink().ClearMessages(); - return count; + return input_router()->touch_event_queue()->empty(); } }; TEST_F(ImmediateInputRouterTest, CoalescesRangeSelection) { input_router_->SendInput(scoped_ptr<IPC::Message>( new InputMsg_SelectRange(0, gfx::Point(1, 2), gfx::Point(3, 4)))); + EXPECT_EQ(1u, process_->sink().message_count()); ExpectIPCMessageWithArg2<InputMsg_SelectRange>( process_->sink().GetMessageAt(0), gfx::Point(1, 2), gfx::Point(3, 4)); - EXPECT_EQ(1u, GetSentMessageCountAndResetSink()); + process_->sink().ClearMessages(); // Send two more messages without acking. input_router_->SendInput(scoped_ptr<IPC::Message>( new InputMsg_SelectRange(0, gfx::Point(5, 6), gfx::Point(7, 8)))); - EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); + EXPECT_EQ(0u, process_->sink().message_count()); input_router_->SendInput(scoped_ptr<IPC::Message>( new InputMsg_SelectRange(0, gfx::Point(9, 10), gfx::Point(11, 12)))); - EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); + EXPECT_EQ(0u, process_->sink().message_count()); // Now ack the first message. { @@ -169,35 +164,37 @@ TEST_F(ImmediateInputRouterTest, CoalescesRangeSelection) { } // Verify that the two messages are coalesced into one message. + EXPECT_EQ(1u, process_->sink().message_count()); ExpectIPCMessageWithArg2<InputMsg_SelectRange>( process_->sink().GetMessageAt(0), gfx::Point(9, 10), gfx::Point(11, 12)); - EXPECT_EQ(1u, GetSentMessageCountAndResetSink()); + process_->sink().ClearMessages(); // Acking the coalesced msg should not send any more msg. { scoped_ptr<IPC::Message> response(new ViewHostMsg_SelectRange_ACK(0)); input_router_->OnMessageReceived(*response); } - EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); + EXPECT_EQ(0u, process_->sink().message_count()); } TEST_F(ImmediateInputRouterTest, CoalescesCaretMove) { input_router_->SendInput( scoped_ptr<IPC::Message>(new InputMsg_MoveCaret(0, gfx::Point(1, 2)))); + EXPECT_EQ(1u, process_->sink().message_count()); ExpectIPCMessageWithArg1<InputMsg_MoveCaret>( process_->sink().GetMessageAt(0), gfx::Point(1, 2)); - EXPECT_EQ(1u, GetSentMessageCountAndResetSink()); + process_->sink().ClearMessages(); // Send two more messages without acking. input_router_->SendInput( scoped_ptr<IPC::Message>(new InputMsg_MoveCaret(0, gfx::Point(5, 6)))); - EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); + EXPECT_EQ(0u, process_->sink().message_count()); input_router_->SendInput( scoped_ptr<IPC::Message>(new InputMsg_MoveCaret(0, gfx::Point(9, 10)))); - EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); + EXPECT_EQ(0u, process_->sink().message_count()); // Now ack the first message. { @@ -206,29 +203,30 @@ TEST_F(ImmediateInputRouterTest, CoalescesCaretMove) { } // Verify that the two messages are coalesced into one message. + EXPECT_EQ(1u, process_->sink().message_count()); ExpectIPCMessageWithArg1<InputMsg_MoveCaret>( process_->sink().GetMessageAt(0), gfx::Point(9, 10)); - EXPECT_EQ(1u, GetSentMessageCountAndResetSink()); + process_->sink().ClearMessages(); // Acking the coalesced msg should not send any more msg. { scoped_ptr<IPC::Message> response(new ViewHostMsg_MoveCaret_ACK(0)); input_router_->OnMessageReceived(*response); } - EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); + EXPECT_EQ(0u, process_->sink().message_count()); } TEST_F(ImmediateInputRouterTest, HandledInputEvent) { client_->set_filter_state(INPUT_EVENT_ACK_STATE_CONSUMED); // Simulate a keyboard event. - SimulateKeyboardEvent(WebInputEvent::RawKeyDown, false); + SimulateKeyboardEvent(WebInputEvent::RawKeyDown); // Make sure no input event is sent to the renderer. - EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); + EXPECT_EQ(0u, process_->sink().message_count()); // OnKeyboardEventAck should be triggered without actual ack. - EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount()); + ack_handler_->ExpectAckCalled(1); // As the event was acked already, keyboard event queue should be // empty. @@ -236,39 +234,32 @@ TEST_F(ImmediateInputRouterTest, HandledInputEvent) { } TEST_F(ImmediateInputRouterTest, ClientCanceledKeyboardEvent) { - client_->set_filter_state(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); + client_->set_allow_send_event(false); - // Simulate a keyboard event that has no consumer. - SimulateKeyboardEvent(WebInputEvent::RawKeyDown, false); + // Simulate a keyboard event. + SimulateKeyboardEvent(WebInputEvent::RawKeyDown); // Make sure no input event is sent to the renderer. - EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); - EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount()); - - - // Simulate a keyboard event that should be dropped. - client_->set_filter_state(INPUT_EVENT_ACK_STATE_UNKNOWN); - SimulateKeyboardEvent(WebInputEvent::RawKeyDown, false); - - // Make sure no input event is sent to the renderer, and no ack is sent. - EXPECT_EQ(0u, GetSentMessageCountAndResetSink()); - EXPECT_EQ(0U, ack_handler_->GetAndResetAckCount()); + EXPECT_EQ(0u, process_->sink().message_count()); + ack_handler_->ExpectAckCalled(0); } TEST_F(ImmediateInputRouterTest, ShortcutKeyboardEvent) { - SimulateKeyboardEvent(WebInputEvent::RawKeyDown, true); + client_->set_is_shortcut(true); + SimulateKeyboardEvent(WebInputEvent::RawKeyDown); EXPECT_TRUE(GetIsShortcutFromHandleInputEventMessage( process_->sink().GetMessageAt(0))); process_->sink().ClearMessages(); - SimulateKeyboardEvent(WebInputEvent::RawKeyDown, false); + client_->set_is_shortcut(false); + SimulateKeyboardEvent(WebInputEvent::RawKeyDown); EXPECT_FALSE(GetIsShortcutFromHandleInputEventMessage( process_->sink().GetMessageAt(0))); } TEST_F(ImmediateInputRouterTest, NoncorrespondingKeyEvents) { - SimulateKeyboardEvent(WebInputEvent::RawKeyDown, false); + SimulateKeyboardEvent(WebInputEvent::RawKeyDown); SendInputEventACK(WebInputEvent::KeyUp, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); @@ -279,7 +270,7 @@ TEST_F(ImmediateInputRouterTest, NoncorrespondingKeyEvents) { TEST_F(ImmediateInputRouterTest, HandleKeyEventsWeSent) { // Simulate a keyboard event. - SimulateKeyboardEvent(WebInputEvent::RawKeyDown, false); + SimulateKeyboardEvent(WebInputEvent::RawKeyDown); ASSERT_TRUE(input_router_->GetLastKeyboardEvent()); EXPECT_EQ(WebInputEvent::RawKeyDown, input_router_->GetLastKeyboardEvent()->type); @@ -292,7 +283,7 @@ TEST_F(ImmediateInputRouterTest, HandleKeyEventsWeSent) { // Send the simulated response from the renderer back. SendInputEventACK(WebInputEvent::RawKeyDown, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount()); + ack_handler_->ExpectAckCalled(1); EXPECT_EQ(WebInputEvent::RawKeyDown, ack_handler_->acked_keyboard_event().type); } @@ -302,7 +293,7 @@ TEST_F(ImmediateInputRouterTest, IgnoreKeyEventsWeDidntSend) { SendInputEventACK(WebInputEvent::RawKeyDown, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - EXPECT_EQ(0U, ack_handler_->GetAndResetAckCount()); + ack_handler_->ExpectAckCalled(0); } // GestureEventFilter tests should be factored out of @@ -315,9 +306,10 @@ TEST_F(ImmediateInputRouterTest, CoalescesWheelEvents) { SimulateWheelEvent(9, -7, 1, false); // enqueued, different modifiers // Check that only the first event was sent. + EXPECT_EQ(1U, process_->sink().message_count()); EXPECT_TRUE(process_->sink().GetUniqueMessageMatching( InputMsg_HandleInputEvent::ID)); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + process_->sink().ClearMessages(); // Check that the ACK sends the second message via ImmediateInputForwarder SendInputEventACK(WebInputEvent::MouseWheel, @@ -326,26 +318,28 @@ TEST_F(ImmediateInputRouterTest, CoalescesWheelEvents) { // so that additional input events can be processed before // we turn off coalescing. base::MessageLoop::current()->RunUntilIdle(); - EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount()); + ack_handler_->ExpectAckCalled(1); + EXPECT_EQ(1U, process_->sink().message_count()); EXPECT_TRUE(process_->sink().GetUniqueMessageMatching( InputMsg_HandleInputEvent::ID)); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + process_->sink().ClearMessages(); // One more time. SendInputEventACK(WebInputEvent::MouseWheel, INPUT_EVENT_ACK_STATE_CONSUMED); base::MessageLoop::current()->RunUntilIdle(); - EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount()); + ack_handler_->ExpectAckCalled(1); + EXPECT_EQ(1U, process_->sink().message_count()); EXPECT_TRUE(process_->sink().GetUniqueMessageMatching( InputMsg_HandleInputEvent::ID)); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + process_->sink().ClearMessages(); // After the final ack, the queue should be empty. SendInputEventACK(WebInputEvent::MouseWheel, INPUT_EVENT_ACK_STATE_CONSUMED); base::MessageLoop::current()->RunUntilIdle(); - EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount()); - EXPECT_EQ(0U, GetSentMessageCountAndResetSink()); + ack_handler_->ExpectAckCalled(1); + EXPECT_EQ(0U, process_->sink().message_count()); // FIXME(kouhei): Below is testing gesture event filter. Maybe separate test? { @@ -364,70 +358,72 @@ TEST_F(ImmediateInputRouterTest, // Send an initial gesture begin and ACK it. SimulateGestureEvent(WebInputEvent::GestureScrollBegin, WebGestureEvent::Touchpad); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + EXPECT_EQ(1U, process_->sink().message_count()); SendInputEventACK(WebInputEvent::GestureScrollBegin, INPUT_EVENT_ACK_STATE_CONSUMED); base::MessageLoop::current()->RunUntilIdle(); // Send a wheel event, should get sent directly. SimulateWheelEvent(0, -5, 0, false); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + EXPECT_EQ(2U, process_->sink().message_count()); // Send a wheel phase end event before an ACK is received for the previous // wheel event, which should get queued. SimulateWheelEventWithPhase(WebMouseWheelEvent::PhaseEnded); - EXPECT_EQ(0U, GetSentMessageCountAndResetSink()); + EXPECT_EQ(2U, process_->sink().message_count()); // A gesture event should now result in the queued phase ended event being // transmitted before it. SimulateGestureEvent(WebInputEvent::GestureScrollEnd, WebGestureEvent::Touchpad); + ASSERT_EQ(4U, process_->sink().message_count()); // Verify the events that were sent. const WebInputEvent* input_event = - GetInputEventFromMessage(*process_->sink().GetMessageAt(0)); + GetInputEventFromMessage(*process_->sink().GetMessageAt(2)); ASSERT_EQ(WebInputEvent::MouseWheel, input_event->type); const WebMouseWheelEvent* wheel_event = static_cast<const WebMouseWheelEvent*>(input_event); ASSERT_EQ(WebMouseWheelEvent::PhaseEnded, wheel_event->phase); - input_event = GetInputEventFromMessage(*process_->sink().GetMessageAt(1)); + input_event = GetInputEventFromMessage(*process_->sink().GetMessageAt(3)); EXPECT_EQ(WebInputEvent::GestureScrollEnd, input_event->type); - - ASSERT_EQ(2U, GetSentMessageCountAndResetSink()); } + // Tests that touch-events are queued properly. TEST_F(ImmediateInputRouterTest, TouchEventQueue) { PressTouchPoint(1, 1); SendTouchEvent(); - EXPECT_TRUE(client_->GetAndResetFilterEventCalled()); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + client_->ExpectSendImmediatelyCalled(true); + EXPECT_EQ(1U, process_->sink().message_count()); + process_->sink().ClearMessages(); EXPECT_FALSE(TouchEventQueueEmpty()); // The second touch should not be sent since one is already in queue. MoveTouchPoint(0, 5, 5); SendTouchEvent(); - EXPECT_FALSE(client_->GetAndResetFilterEventCalled()); - EXPECT_EQ(0U, GetSentMessageCountAndResetSink()); + client_->ExpectSendImmediatelyCalled(false); + EXPECT_EQ(0U, process_->sink().message_count()); EXPECT_FALSE(TouchEventQueueEmpty()); // Receive an ACK for the first touch-event. SendInputEventACK(WebInputEvent::TouchStart, INPUT_EVENT_ACK_STATE_CONSUMED); EXPECT_FALSE(TouchEventQueueEmpty()); - EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount()); + ack_handler_->ExpectAckCalled(1); EXPECT_EQ(WebInputEvent::TouchStart, ack_handler_->acked_touch_event().event.type); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + EXPECT_EQ(1U, process_->sink().message_count()); + process_->sink().ClearMessages(); SendInputEventACK(WebInputEvent::TouchMove, INPUT_EVENT_ACK_STATE_CONSUMED); EXPECT_TRUE(TouchEventQueueEmpty()); - EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount()); + ack_handler_->ExpectAckCalled(1); EXPECT_EQ(WebInputEvent::TouchMove, ack_handler_->acked_touch_event().event.type); - EXPECT_EQ(0U, GetSentMessageCountAndResetSink()); + EXPECT_EQ(0U, process_->sink().message_count()); } // Tests that the touch-queue is emptied if a page stops listening for touch @@ -435,7 +431,7 @@ TEST_F(ImmediateInputRouterTest, TouchEventQueue) { TEST_F(ImmediateInputRouterTest, TouchEventQueueFlush) { input_router_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true)); EXPECT_TRUE(client_->has_touch_handler()); - EXPECT_EQ(0U, GetSentMessageCountAndResetSink()); + EXPECT_EQ(0U, process_->sink().message_count()); EXPECT_TRUE(TouchEventQueueEmpty()); EXPECT_TRUE(input_router_->ShouldForwardTouchEvent()); @@ -444,14 +440,15 @@ TEST_F(ImmediateInputRouterTest, TouchEventQueueFlush) { PressTouchPoint(1, 1); SendTouchEvent(); EXPECT_FALSE(TouchEventQueueEmpty()); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + EXPECT_EQ(1U, process_->sink().message_count()); + process_->sink().ClearMessages(); // The page stops listening for touch-events. The touch-event queue should now // be emptied, but none of the queued touch-events should be sent to the // renderer. input_router_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false)); EXPECT_FALSE(client_->has_touch_handler()); - EXPECT_EQ(0U, GetSentMessageCountAndResetSink()); + EXPECT_EQ(0U, process_->sink().message_count()); EXPECT_TRUE(TouchEventQueueEmpty()); EXPECT_FALSE(input_router_->ShouldForwardTouchEvent()); } @@ -461,7 +458,7 @@ TEST_F(ImmediateInputRouterTest, TouchEventQueueFlush) { // windows and aura) TEST_F(ImmediateInputRouterTest, AckedTouchEventState) { input_router_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, true)); - EXPECT_EQ(0U, GetSentMessageCountAndResetSink()); + EXPECT_EQ(0U, process_->sink().message_count()); EXPECT_TRUE(TouchEventQueueEmpty()); EXPECT_TRUE(input_router_->ShouldForwardTouchEvent()); @@ -477,7 +474,8 @@ TEST_F(ImmediateInputRouterTest, AckedTouchEventState) { PressTouchPoint(1, 1); SetTouchTimestamp(timestamp); SendTouchEvent(); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + EXPECT_EQ(1U, process_->sink().message_count()); + process_->sink().ClearMessages(); expected_events.push_back(new ui::TouchEvent(ui::ET_TOUCH_PRESSED, gfx::Point(1, 1), 0, timestamp)); @@ -549,23 +547,25 @@ TEST_F(ImmediateInputRouterTest, UnhandledWheelEvent) { SimulateWheelEvent(0, -10, 0, false); // enqueued // Check that only the first event was sent. + EXPECT_EQ(1U, process_->sink().message_count()); EXPECT_TRUE(process_->sink().GetUniqueMessageMatching( InputMsg_HandleInputEvent::ID)); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + process_->sink().ClearMessages(); // Indicate that the wheel event was unhandled. SendInputEventACK(WebInputEvent::MouseWheel, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); // Check that the correct unhandled wheel event was received. - EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount()); + ack_handler_->ExpectAckCalled(1); EXPECT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, ack_handler_->ack_state()); EXPECT_EQ(ack_handler_->acked_wheel_event().deltaY, -5); // Check that the second event was sent. + EXPECT_EQ(1U, process_->sink().message_count()); EXPECT_TRUE(process_->sink().GetUniqueMessageMatching( InputMsg_HandleInputEvent::ID)); - EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); + process_->sink().ClearMessages(); // Check that the correct unhandled wheel event was received. EXPECT_EQ(ack_handler_->acked_wheel_event().deltaY, -5); diff --git a/content/browser/renderer_host/input/input_router.h b/content/browser/renderer_host/input/input_router.h index c4e19de..5e4533f 100644 --- a/content/browser/renderer_host/input/input_router.h +++ b/content/browser/renderer_host/input/input_router.h @@ -40,12 +40,17 @@ class InputRouter : public IPC::Listener { const MouseWheelEventWithLatencyInfo& wheel_event) = 0; virtual void SendKeyboardEvent( const NativeWebKeyboardEvent& key_event, - const ui::LatencyInfo& latency_info, - bool is_shortcut) = 0; + const ui::LatencyInfo& latency_info) = 0; virtual void SendGestureEvent( const GestureEventWithLatencyInfo& gesture_event) = 0; virtual void SendTouchEvent( const TouchEventWithLatencyInfo& touch_event) = 0; + virtual void SendMouseEventImmediately( + const MouseEventWithLatencyInfo& mouse_event) = 0; + virtual void SendTouchEventImmediately( + const TouchEventWithLatencyInfo& touch_event) = 0; + virtual void SendGestureEventImmediately( + const GestureEventWithLatencyInfo& gesture_event) = 0; // Returns the oldest queued or in-flight keyboard event sent to the router. virtual const NativeWebKeyboardEvent* GetLastKeyboardEvent() const = 0; diff --git a/content/browser/renderer_host/input/input_router_client.h b/content/browser/renderer_host/input/input_router_client.h index ebe04c6..6479332 100644 --- a/content/browser/renderer_host/input/input_router_client.h +++ b/content/browser/renderer_host/input/input_router_client.h @@ -17,8 +17,6 @@ struct LatencyInfo; namespace content { -class OverscrollController; - class CONTENT_EXPORT InputRouterClient { public: virtual ~InputRouterClient() {} @@ -42,10 +40,26 @@ class CONTENT_EXPORT InputRouterClient { // Called when the renderer notifies that it has touch event handlers. virtual void OnHasTouchEventHandlers(bool has_handlers) = 0; - // Returns an optional OverscrollController. If non-NULL, the controller - // will be fed events and event acks by the router, when appropriate. - // TODO(jdduke): crbug.com/306133 - Move the controller to the router. - virtual OverscrollController* GetOverscrollController() const = 0; + // Called upon Send*Event. Should return true if the event should be sent, and + // false if the event should be dropped. + virtual bool OnSendKeyboardEvent( + const NativeWebKeyboardEvent& key_event, + const ui::LatencyInfo& latency_info, + bool* is_shortcut) = 0; + virtual bool OnSendWheelEvent( + const MouseWheelEventWithLatencyInfo& wheel_event) = 0; + virtual bool OnSendMouseEvent( + const MouseEventWithLatencyInfo& mouse_event) = 0; + virtual bool OnSendTouchEvent( + const TouchEventWithLatencyInfo& touch_event) = 0; + virtual bool OnSendGestureEvent( + const GestureEventWithLatencyInfo& gesture_event) = 0; + virtual bool OnSendMouseEventImmediately( + const MouseEventWithLatencyInfo& mouse_event) = 0; + virtual bool OnSendTouchEventImmediately( + const TouchEventWithLatencyInfo& touch_event) = 0; + virtual bool OnSendGestureEventImmediately( + const GestureEventWithLatencyInfo& gesture_event) = 0; // Certain router implementations require periodic flushing of queued events. // When this method is called, the client should ensure a timely call, either diff --git a/content/browser/renderer_host/input/input_router_unittest.cc b/content/browser/renderer_host/input/input_router_unittest.cc index 3981d73..04b51be 100644 --- a/content/browser/renderer_host/input/input_router_unittest.cc +++ b/content/browser/renderer_host/input/input_router_unittest.cc @@ -42,11 +42,11 @@ void InputRouterTest::TearDown() { browser_context_.reset(); } -void InputRouterTest::SimulateKeyboardEvent(WebInputEvent::Type type, - bool is_shortcut) { +void InputRouterTest::SimulateKeyboardEvent(WebInputEvent::Type type) { input_router_->SendKeyboardEvent(MockWebKeyboardEventBuilder::Build(type), - ui::LatencyInfo(), - is_shortcut); + ui::LatencyInfo()); + client_->ExpectSendCalled(true); + EXPECT_EQ(type, client_->sent_key_event().type); } void InputRouterTest::SimulateWheelEvent(float dX, @@ -57,6 +57,9 @@ void InputRouterTest::SimulateWheelEvent(float dX, MouseWheelEventWithLatencyInfo( MockWebMouseWheelEventBuilder::Build(dX, dY, modifiers, precise), ui::LatencyInfo())); + client_->ExpectSendCalled(true); + EXPECT_EQ(WebInputEvent::MouseWheel, client_->sent_wheel_event().event.type); + EXPECT_EQ(dX, client_->sent_wheel_event().event.deltaX); } void InputRouterTest::SimulateMouseMove(int x, int y, int modifiers) { @@ -64,6 +67,9 @@ void InputRouterTest::SimulateMouseMove(int x, int y, int modifiers) { MouseEventWithLatencyInfo(MockWebMouseEventBuilder::Build( WebInputEvent::MouseMove, x, y, modifiers), ui::LatencyInfo())); + client_->ExpectSendCalled(true); + EXPECT_EQ(WebInputEvent::MouseMove, client_->sent_mouse_event().event.type); + EXPECT_EQ(x, client_->sent_mouse_event().event.x); } void InputRouterTest::SimulateWheelEventWithPhase( @@ -71,6 +77,9 @@ void InputRouterTest::SimulateWheelEventWithPhase( input_router_->SendWheelEvent( MouseWheelEventWithLatencyInfo( MockWebMouseWheelEventBuilder::Build(phase), ui::LatencyInfo())); + client_->ExpectSendCalled(true); + EXPECT_EQ(WebInputEvent::MouseWheel, client_->sent_wheel_event().event.type); + EXPECT_EQ(phase, client_->sent_wheel_event().event.phase); } // Inject provided synthetic WebGestureEvent instance. @@ -78,6 +87,10 @@ void InputRouterTest::SimulateGestureEvent( const WebGestureEvent& gesture) { GestureEventWithLatencyInfo gesture_with_latency(gesture, ui::LatencyInfo()); input_router_->SendGestureEvent(gesture_with_latency); + client_->ExpectSendCalled(true); + EXPECT_EQ(gesture.type, client_->sent_gesture_event().event.type); + EXPECT_EQ(gesture.sourceDevice, + client_->sent_gesture_event().event.sourceDevice); } // Inject simple synthetic WebGestureEvent instances. diff --git a/content/browser/renderer_host/input/input_router_unittest.h b/content/browser/renderer_host/input/input_router_unittest.h index 8901301..c969568 100644 --- a/content/browser/renderer_host/input/input_router_unittest.h +++ b/content/browser/renderer_host/input/input_router_unittest.h @@ -38,8 +38,7 @@ class InputRouterTest : public testing::Test { void SendInputEventACK(WebKit::WebInputEvent::Type type, InputEventAckState ack_result); - void SimulateKeyboardEvent(WebKit::WebInputEvent::Type type, - bool is_shortcut); + void SimulateKeyboardEvent(WebKit::WebInputEvent::Type type); void SimulateWheelEvent(float dX, float dY, int modifiers, bool precise); void SimulateMouseMove(int x, int y, int modifiers); void SimulateWheelEventWithPhase(WebKit::WebMouseWheelEvent::Phase phase); diff --git a/content/browser/renderer_host/input/mock_input_ack_handler.cc b/content/browser/renderer_host/input/mock_input_ack_handler.cc index 04f1cf8..2219b00 100644 --- a/content/browser/renderer_host/input/mock_input_ack_handler.cc +++ b/content/browser/renderer_host/input/mock_input_ack_handler.cc @@ -66,10 +66,9 @@ void MockInputAckHandler::OnUnexpectedEventAck(UnexpectedEventAckType type) { unexpected_event_ack_called_ = true; } -size_t MockInputAckHandler::GetAndResetAckCount() { - size_t ack_count = ack_count_; +void MockInputAckHandler::ExpectAckCalled(int times) { + EXPECT_EQ(times, ack_count_); ack_count_ = 0; - return ack_count; } void MockInputAckHandler::RecordAckCalled(InputEventAckState ack_result) { diff --git a/content/browser/renderer_host/input/mock_input_ack_handler.h b/content/browser/renderer_host/input/mock_input_ack_handler.h index 27b8229..890cde9 100644 --- a/content/browser/renderer_host/input/mock_input_ack_handler.h +++ b/content/browser/renderer_host/input/mock_input_ack_handler.h @@ -28,7 +28,7 @@ class MockInputAckHandler : public InputAckHandler { InputEventAckState ack_result) OVERRIDE; virtual void OnUnexpectedEventAck(UnexpectedEventAckType type) OVERRIDE; - size_t GetAndResetAckCount(); + void ExpectAckCalled(int times); void set_input_router(InputRouter* input_router) { input_router_ = input_router; @@ -65,7 +65,7 @@ class MockInputAckHandler : public InputAckHandler { InputRouter* input_router_; - size_t ack_count_; + int ack_count_; bool unexpected_event_ack_called_; InputEventAckState ack_state_; NativeWebKeyboardEvent acked_key_event_; diff --git a/content/browser/renderer_host/input/mock_input_router_client.cc b/content/browser/renderer_host/input/mock_input_router_client.cc index 1484d22..86fb53b 100644 --- a/content/browser/renderer_host/input/mock_input_router_client.cc +++ b/content/browser/renderer_host/input/mock_input_router_client.cc @@ -5,7 +5,6 @@ #include "content/browser/renderer_host/input/mock_input_router_client.h" #include "content/browser/renderer_host/input/input_router.h" -#include "content/common/input/input_event.h" #include "testing/gtest/include/gtest/gtest.h" using base::TimeDelta; @@ -23,7 +22,10 @@ MockInputRouterClient::MockInputRouterClient() in_flight_event_count_(0), has_touch_handler_(false), filter_state_(INPUT_EVENT_ACK_STATE_NOT_CONSUMED), - filter_input_event_called_(false), + is_shortcut_(false), + allow_send_event_(true), + send_called_(false), + send_immediately_called_(false), did_flush_called_(false), set_needs_flush_called_(false) {} @@ -31,17 +33,15 @@ MockInputRouterClient::~MockInputRouterClient() {} InputEventAckState MockInputRouterClient::FilterInputEvent( const WebInputEvent& input_event, - const ui::LatencyInfo& latency_info) { - filter_input_event_called_ = true; - last_filter_event_.reset(new InputEvent(input_event, latency_info, false)); + const ui::LatencyInfo& latency_info) { return filter_state_; } -void MockInputRouterClient::IncrementInFlightEventCount() { +void MockInputRouterClient::IncrementInFlightEventCount() { ++in_flight_event_count_; } -void MockInputRouterClient::DecrementInFlightEventCount() { +void MockInputRouterClient::DecrementInFlightEventCount() { --in_flight_event_count_; } @@ -50,14 +50,91 @@ void MockInputRouterClient::OnHasTouchEventHandlers( has_touch_handler_ = has_handlers; } -bool MockInputRouterClient::GetAndResetFilterEventCalled() { - bool filter_input_event_called = filter_input_event_called_; - filter_input_event_called_ = false; - return filter_input_event_called; +bool MockInputRouterClient::OnSendKeyboardEvent( + const NativeWebKeyboardEvent& key_event, + const ui::LatencyInfo& latency_info, + bool* is_shortcut) { + send_called_ = true; + sent_key_event_ = key_event; + *is_shortcut = is_shortcut_; + + return allow_send_event_; +} + +bool MockInputRouterClient::OnSendWheelEvent( + const MouseWheelEventWithLatencyInfo& wheel_event) { + send_called_ = true; + sent_wheel_event_ = wheel_event; + + return allow_send_event_; +} + +bool MockInputRouterClient::OnSendMouseEvent( + const MouseEventWithLatencyInfo& mouse_event) { + send_called_ = true; + sent_mouse_event_ = mouse_event; + + return allow_send_event_; +} + +bool MockInputRouterClient::OnSendTouchEvent( + const TouchEventWithLatencyInfo& touch_event) { + send_called_ = true; + sent_touch_event_ = touch_event; + + return allow_send_event_; +} + +bool MockInputRouterClient::OnSendGestureEvent( + const GestureEventWithLatencyInfo& gesture_event) { + send_called_ = true; + sent_gesture_event_ = gesture_event; + + return allow_send_event_ && + input_router_->ShouldForwardGestureEvent(gesture_event); +} + +bool MockInputRouterClient::OnSendMouseEventImmediately( + const MouseEventWithLatencyInfo& mouse_event) { + send_immediately_called_ = true; + immediately_sent_mouse_event_ = mouse_event; + + return allow_send_event_; +} + +bool MockInputRouterClient::OnSendTouchEventImmediately( + const TouchEventWithLatencyInfo& touch_event) { + send_immediately_called_ = true; + immediately_sent_touch_event_ = touch_event; + + return allow_send_event_; +} + +bool MockInputRouterClient::OnSendGestureEventImmediately( + const GestureEventWithLatencyInfo& gesture_event) { + send_immediately_called_ = true; + immediately_sent_gesture_event_ = gesture_event; + return allow_send_event_; +} + +void MockInputRouterClient::ExpectSendCalled(bool called) { + EXPECT_EQ(called, send_called_); + send_called_ = false; +} + +void MockInputRouterClient::ExpectSendImmediatelyCalled(bool called) { + EXPECT_EQ(called, send_immediately_called_); + send_immediately_called_ = false; +} + +void MockInputRouterClient::ExpectNeedsFlushCalled(bool called) { + EXPECT_EQ(called, set_needs_flush_called_); + set_needs_flush_called_ = false; } -OverscrollController* MockInputRouterClient::GetOverscrollController() const { - return NULL; +void MockInputRouterClient::ExpectDidFlushCalled(bool called) { + EXPECT_EQ(called, did_flush_called_); + did_flush_called_ = false; } void MockInputRouterClient::DidFlush() { diff --git a/content/browser/renderer_host/input/mock_input_router_client.h b/content/browser/renderer_host/input/mock_input_router_client.h index 05513728..a02f738 100644 --- a/content/browser/renderer_host/input/mock_input_router_client.h +++ b/content/browser/renderer_host/input/mock_input_router_client.h @@ -10,7 +10,6 @@ namespace content { -class InputEvent; class InputRouter; class MockInputRouterClient : public InputRouterClient { @@ -25,11 +24,31 @@ class MockInputRouterClient : public InputRouterClient { virtual void IncrementInFlightEventCount() OVERRIDE; virtual void DecrementInFlightEventCount() OVERRIDE; virtual void OnHasTouchEventHandlers(bool has_handlers) OVERRIDE; - virtual OverscrollController* GetOverscrollController() const OVERRIDE; + virtual bool OnSendKeyboardEvent( + const NativeWebKeyboardEvent& key_event, + const ui::LatencyInfo& latency_info, + bool* is_shortcut) OVERRIDE; + virtual bool OnSendWheelEvent( + const MouseWheelEventWithLatencyInfo& wheel_event) OVERRIDE; + virtual bool OnSendMouseEvent( + const MouseEventWithLatencyInfo& mouse_event) OVERRIDE; + virtual bool OnSendTouchEvent( + const TouchEventWithLatencyInfo& touch_event) OVERRIDE; + virtual bool OnSendGestureEvent( + const GestureEventWithLatencyInfo& gesture_event) OVERRIDE; + virtual bool OnSendMouseEventImmediately( + const MouseEventWithLatencyInfo& mouse_event) OVERRIDE; + virtual bool OnSendTouchEventImmediately( + const TouchEventWithLatencyInfo& touch_event) OVERRIDE; + virtual bool OnSendGestureEventImmediately( + const GestureEventWithLatencyInfo& gesture_event) OVERRIDE; virtual void DidFlush() OVERRIDE; virtual void SetNeedsFlush() OVERRIDE; - bool GetAndResetFilterEventCalled(); + void ExpectSendCalled(bool called); + void ExpectSendImmediatelyCalled(bool called); + void ExpectNeedsFlushCalled(bool called); + void ExpectDidFlushCalled(bool called); void set_input_router(InputRouter* input_router) { input_router_ = input_router; @@ -42,12 +61,39 @@ class MockInputRouterClient : public InputRouterClient { int in_flight_event_count() const { return in_flight_event_count_; } + void set_is_shortcut(bool is_shortcut) { + is_shortcut_ = is_shortcut; + } void set_allow_send_event(bool allow) { - filter_state_ = INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; + allow_send_event_ = allow; + } + const NativeWebKeyboardEvent& sent_key_event() { + return sent_key_event_; + } + const MouseWheelEventWithLatencyInfo& sent_wheel_event() { + return sent_wheel_event_; + } + const MouseEventWithLatencyInfo& sent_mouse_event() { + return sent_mouse_event_; + } + const GestureEventWithLatencyInfo& sent_gesture_event() { + return sent_gesture_event_; + } + const MouseEventWithLatencyInfo& immediately_sent_mouse_event() { + return immediately_sent_mouse_event_; + } + const TouchEventWithLatencyInfo& immediately_sent_touch_event() { + return immediately_sent_touch_event_; + } + const GestureEventWithLatencyInfo& immediately_sent_gesture_event() { + return immediately_sent_gesture_event_; } bool did_flush_called() const { return did_flush_called_; } bool needs_flush_called() const { return set_needs_flush_called_; } + void set_followup_touch_event(scoped_ptr<GestureEventWithLatencyInfo> event) { + touch_followup_event_ = event.Pass(); + } private: InputRouter* input_router_; @@ -56,11 +102,23 @@ class MockInputRouterClient : public InputRouterClient { InputEventAckState filter_state_; - bool filter_input_event_called_; - scoped_ptr<InputEvent> last_filter_event_; + bool is_shortcut_; + bool allow_send_event_; + bool send_called_; + NativeWebKeyboardEvent sent_key_event_; + MouseWheelEventWithLatencyInfo sent_wheel_event_; + MouseEventWithLatencyInfo sent_mouse_event_; + TouchEventWithLatencyInfo sent_touch_event_; + GestureEventWithLatencyInfo sent_gesture_event_; + + bool send_immediately_called_; + MouseEventWithLatencyInfo immediately_sent_mouse_event_; + TouchEventWithLatencyInfo immediately_sent_touch_event_; + GestureEventWithLatencyInfo immediately_sent_gesture_event_; bool did_flush_called_; bool set_needs_flush_called_; + scoped_ptr<GestureEventWithLatencyInfo> touch_followup_event_; }; } // namespace content diff --git a/content/browser/renderer_host/overscroll_controller.h b/content/browser/renderer_host/overscroll_controller.h index 9ddf98f..fab5319 100644 --- a/content/browser/renderer_host/overscroll_controller.h +++ b/content/browser/renderer_host/overscroll_controller.h @@ -38,7 +38,6 @@ class OverscrollController { public: // Creates an overscroll controller for the specified RenderWidgetHost. // The RenderWidgetHost owns this overscroll controller. - // TODO(jdduke): crbug.com/306194 - Take an OverscrollControllerClient. explicit OverscrollController(RenderWidgetHostImpl* widget_host); virtual ~OverscrollController(); diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 74fc640..17255b4 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc @@ -961,6 +961,99 @@ void RenderWidgetHostImpl::EnableFullAccessibilityMode() { SetAccessibilityMode(AccessibilityModeComplete); } +static WebGestureEvent MakeGestureEvent(WebInputEvent::Type type, + double timestamp_seconds, + int x, + int y, + int modifiers) { + WebGestureEvent result; + + result.type = type; + result.x = x; + result.y = y; + result.sourceDevice = WebGestureEvent::Touchscreen; + result.timeStampSeconds = timestamp_seconds; + result.modifiers = modifiers; + + return result; +} + +void RenderWidgetHostImpl::SimulateTouchGestureWithMouse( + const WebMouseEvent& mouse_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; + ForwardGestureEvent(MakeGestureEvent( + WebInputEvent::GestureScrollBegin, mouse_event.timeStampSeconds, + x, y, 0)); + } + if (dx != 0 || dy != 0) { + WebGestureEvent event = MakeGestureEvent( + WebInputEvent::GestureScrollUpdate, mouse_event.timeStampSeconds, + x, y, 0); + event.data.scrollUpdate.deltaX = dx; + event.data.scrollUpdate.deltaY = dy; + ForwardGestureEvent(event); + } + if (mouse_event.type == WebInputEvent::MouseUp) { + ForwardGestureEvent(MakeGestureEvent( + WebInputEvent::GestureScrollEnd, mouse_event.timeStampSeconds, + x, y, 0)); + } + break; + case WebMouseEvent::ButtonMiddle: + if (mouse_event.type == WebInputEvent::MouseDown) { + startX = x; + startY = y; + ForwardGestureEvent(MakeGestureEvent( + WebInputEvent::GestureTapDown, mouse_event.timeStampSeconds, + x, y, 0)); + } + if (mouse_event.type == WebInputEvent::MouseUp) { + ForwardGestureEvent(MakeGestureEvent( + WebInputEvent::GestureTap, mouse_event.timeStampSeconds, + x, y, 0)); + } + break; + case WebMouseEvent::ButtonRight: + if (mouse_event.type == WebInputEvent::MouseDown) { + startX = x; + startY = y; + ForwardGestureEvent(MakeGestureEvent( + WebInputEvent::GestureScrollBegin, mouse_event.timeStampSeconds, + x, y, 0)); + ForwardGestureEvent(MakeGestureEvent( + WebInputEvent::GesturePinchBegin, mouse_event.timeStampSeconds, + x, y, 0)); + } + if (dx != 0 || dy != 0) { + dx = pow(dy < 0 ? 0.998f : 1.002f, fabs(dy)); + WebGestureEvent event = MakeGestureEvent( + WebInputEvent::GesturePinchUpdate, mouse_event.timeStampSeconds, + startX, startY, 0); + event.data.pinchUpdate.scale = dx; + ForwardGestureEvent(event); + } + if (mouse_event.type == WebInputEvent::MouseUp) { + ForwardGestureEvent(MakeGestureEvent( + WebInputEvent::GesturePinchEnd, mouse_event.timeStampSeconds, + x, y, 0)); + ForwardGestureEvent(MakeGestureEvent( + WebInputEvent::GestureScrollEnd, mouse_event.timeStampSeconds, + x, y, 0)); + } + break; + case WebMouseEvent::ButtonNone: + break; + } +} + void RenderWidgetHostImpl::ForwardMouseEvent(const WebMouseEvent& mouse_event) { ForwardMouseEventWithLatencyInfo( MouseEventWithLatencyInfo(mouse_event, @@ -977,9 +1070,6 @@ void RenderWidgetHostImpl::ForwardMouseEventWithLatencyInfo( return; } - if (IgnoreInputEvents()) - return; - input_router_->SendMouseEvent(mouse_event); } @@ -996,12 +1086,6 @@ void RenderWidgetHostImpl::ForwardWheelEvent( void RenderWidgetHostImpl::ForwardWheelEventWithLatencyInfo( const MouseWheelEventWithLatencyInfo& wheel_event) { TRACE_EVENT0("input", "RenderWidgetHostImpl::ForwardWheelEvent"); - if (IgnoreInputEvents()) - return; - - if (delegate_->PreHandleWheelEvent(wheel_event.event)) - return; - input_router_->SendWheelEvent(wheel_event); } @@ -1051,9 +1135,6 @@ void RenderWidgetHostImpl::ForwardTouchEventWithLatencyInfo( const WebKit::WebTouchEvent& touch_event, const ui::LatencyInfo& ui_latency) { TRACE_EVENT0("input", "RenderWidgetHostImpl::ForwardTouchEvent"); - if (IgnoreInputEvents()) - return; - ui::LatencyInfo latency_info = CreateRWHLatencyInfoIfNotExist(&ui_latency); TouchEventWithLatencyInfo touch_with_latency(touch_event, latency_info); input_router_->SendTouchEvent(touch_with_latency); @@ -1062,67 +1143,8 @@ void RenderWidgetHostImpl::ForwardTouchEventWithLatencyInfo( void RenderWidgetHostImpl::ForwardKeyboardEvent( const NativeWebKeyboardEvent& key_event) { TRACE_EVENT0("input", "RenderWidgetHostImpl::ForwardKeyboardEvent"); - if (IgnoreInputEvents()) - return; - - if (!process_->HasConnection()) - return; - - // First, let keypress listeners take a shot at handling the event. If a - // listener handles the event, it should not be propagated to the renderer. - if (KeyPressListenersHandleEvent(key_event)) { - // Some keypresses that are accepted by the listener might have follow up - // char events, which should be ignored. - if (key_event.type == WebKeyboardEvent::RawKeyDown) - suppress_next_char_events_ = true; - return; - } - - if (key_event.type == WebKeyboardEvent::Char && - (key_event.windowsKeyCode == ui::VKEY_RETURN || - key_event.windowsKeyCode == ui::VKEY_SPACE)) { - OnUserGesture(); - } - - // Double check the type to make sure caller hasn't sent us nonsense that - // will mess up our key queue. - if (!WebInputEvent::isKeyboardEventType(key_event.type)) - return; - - if (suppress_next_char_events_) { - // If preceding RawKeyDown event was handled by the browser, then we need - // suppress all Char events generated by it. Please note that, one - // RawKeyDown event may generate multiple Char events, so we can't reset - // |suppress_next_char_events_| until we get a KeyUp or a RawKeyDown. - if (key_event.type == WebKeyboardEvent::Char) - return; - // We get a KeyUp or a RawKeyDown event. - suppress_next_char_events_ = false; - } - - bool is_shortcut = false; - - // Only pre-handle the key event if it's not handled by the input method. - if (delegate_ && !key_event.skip_in_browser) { - // We need to set |suppress_next_char_events_| to true if - // PreHandleKeyboardEvent() returns true, but |this| may already be - // destroyed at that time. So set |suppress_next_char_events_| true here, - // then revert it afterwards when necessary. - if (key_event.type == WebKeyboardEvent::RawKeyDown) - suppress_next_char_events_ = true; - - // Tab switching/closing accelerators aren't sent to the renderer to avoid - // a hung/malicious renderer from interfering. - if (delegate_->PreHandleKeyboardEvent(key_event, &is_shortcut)) - return; - - if (key_event.type == WebKeyboardEvent::RawKeyDown) - suppress_next_char_events_ = false; - } - input_router_->SendKeyboardEvent(key_event, - CreateRWHLatencyInfoIfNotExist(NULL), - is_shortcut); + CreateRWHLatencyInfoIfNotExist(NULL)); } void RenderWidgetHostImpl::SendCursorVisibilityState(bool is_visible) { @@ -1374,6 +1396,11 @@ void RenderWidgetHostImpl::SetShouldAutoResize(bool enable) { should_auto_resize_ = enable; } +bool RenderWidgetHostImpl::IsInOverscrollGesture() const { + return overscroll_controller_.get() && + overscroll_controller_->overscroll_mode() != OVERSCROLL_NONE; +} + void RenderWidgetHostImpl::Destroy() { NotificationService::current()->Notify( NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, @@ -1955,14 +1982,10 @@ bool RenderWidgetHostImpl::KeyPressListenersHandleEvent( InputEventAckState RenderWidgetHostImpl::FilterInputEvent( const WebKit::WebInputEvent& event, const ui::LatencyInfo& latency_info) { - if (IgnoreInputEvents()) - return INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS; - - if (!process_->HasConnection()) + if (overscroll_controller() && + !overscroll_controller()->WillDispatchEvent(event, latency_info)) { return INPUT_EVENT_ACK_STATE_UNKNOWN; - - if (event.type == WebInputEvent::MouseDown) - OnUserGesture(); + } return view_ ? view_->FilterInputEvent(event) : INPUT_EVENT_ACK_STATE_NOT_CONSUMED; @@ -1991,8 +2014,148 @@ void RenderWidgetHostImpl::OnHasTouchEventHandlers(bool has_handlers) { #endif } -OverscrollController* RenderWidgetHostImpl::GetOverscrollController() const { - return overscroll_controller_.get(); +bool RenderWidgetHostImpl::OnSendKeyboardEvent( + const NativeWebKeyboardEvent& key_event, + const ui::LatencyInfo& latency_info, + bool* is_shortcut) { + if (IgnoreInputEvents()) + return false; + + if (!process_->HasConnection()) + return false; + + // First, let keypress listeners take a shot at handling the event. If a + // listener handles the event, it should not be propagated to the renderer. + if (KeyPressListenersHandleEvent(key_event)) { + // Some keypresses that are accepted by the listener might have follow up + // char events, which should be ignored. + if (key_event.type == WebKeyboardEvent::RawKeyDown) + suppress_next_char_events_ = true; + return false; + } + + if (key_event.type == WebKeyboardEvent::Char && + (key_event.windowsKeyCode == ui::VKEY_RETURN || + key_event.windowsKeyCode == ui::VKEY_SPACE)) { + OnUserGesture(); + } + + // Double check the type to make sure caller hasn't sent us nonsense that + // will mess up our key queue. + if (!WebInputEvent::isKeyboardEventType(key_event.type)) + return false; + + if (suppress_next_char_events_) { + // If preceding RawKeyDown event was handled by the browser, then we need + // suppress all Char events generated by it. Please note that, one + // RawKeyDown event may generate multiple Char events, so we can't reset + // |suppress_next_char_events_| until we get a KeyUp or a RawKeyDown. + if (key_event.type == WebKeyboardEvent::Char) + return false; + // We get a KeyUp or a RawKeyDown event. + suppress_next_char_events_ = false; + } + + // Only pre-handle the key event if it's not handled by the input method. + if (delegate_ && !key_event.skip_in_browser) { + // We need to set |suppress_next_char_events_| to true if + // PreHandleKeyboardEvent() returns true, but |this| may already be + // destroyed at that time. So set |suppress_next_char_events_| true here, + // then revert it afterwards when necessary. + if (key_event.type == WebKeyboardEvent::RawKeyDown) + suppress_next_char_events_ = true; + + // Tab switching/closing accelerators aren't sent to the renderer to avoid + // a hung/malicious renderer from interfering. + if (delegate_->PreHandleKeyboardEvent(key_event, is_shortcut)) + return false; + + if (key_event.type == WebKeyboardEvent::RawKeyDown) + suppress_next_char_events_ = false; + } + + return true; +} + +bool RenderWidgetHostImpl::OnSendWheelEvent( + const MouseWheelEventWithLatencyInfo& wheel_event) { + if (IgnoreInputEvents()) + return false; + + if (delegate_->PreHandleWheelEvent(wheel_event.event)) + return false; + + return true; +} + +bool RenderWidgetHostImpl::OnSendMouseEvent( + const MouseEventWithLatencyInfo& mouse_event) { + if (IgnoreInputEvents()) + return false; + + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kSimulateTouchScreenWithMouse)) { + SimulateTouchGestureWithMouse(mouse_event.event); + return false; + } + + return true; +} + +bool RenderWidgetHostImpl::OnSendTouchEvent( + const TouchEventWithLatencyInfo& touch_event) { + return !IgnoreInputEvents(); +} + +bool RenderWidgetHostImpl::OnSendGestureEvent( + const GestureEventWithLatencyInfo& gesture_event) { + if (IgnoreInputEvents()) + return false; + + if (!IsInOverscrollGesture() && + !input_router_->ShouldForwardGestureEvent(gesture_event)) { + if (overscroll_controller_.get()) + overscroll_controller_->DiscardingGestureEvent(gesture_event.event); + return false; + } + + return true; +} + +bool RenderWidgetHostImpl::OnSendMouseEventImmediately( + const MouseEventWithLatencyInfo& mouse_event) { + TRACE_EVENT_INSTANT0("input", + "RenderWidgetHostImpl::OnSendMouseEventImmediately", + TRACE_EVENT_SCOPE_THREAD); + if (IgnoreInputEvents()) + return false; + + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kSimulateTouchScreenWithMouse)) { + SimulateTouchGestureWithMouse(mouse_event.event); + return false; + } + + if (mouse_event.event.type == WebInputEvent::MouseDown) + OnUserGesture(); + + return true; +} + +bool RenderWidgetHostImpl::OnSendTouchEventImmediately( + const TouchEventWithLatencyInfo& touch_event) { + TRACE_EVENT_INSTANT0("input", + "RenderWidgetHostImpl::OnSendTouchEventImmediately", + TRACE_EVENT_SCOPE_THREAD); + return !IgnoreInputEvents(); +} + +bool RenderWidgetHostImpl::OnSendGestureEventImmediately( + const GestureEventWithLatencyInfo& gesture_event) { + TRACE_EVENT_INSTANT0("input", + "RenderWidgetHostImpl::OnSendGestureEventImmediately", + TRACE_EVENT_SCOPE_THREAD); + return !IgnoreInputEvents(); } void RenderWidgetHostImpl::SetNeedsFlush() { @@ -2037,8 +2200,9 @@ void RenderWidgetHostImpl::OnWheelEventAck( latency.AddLatencyNumber( ui::INPUT_EVENT_LATENCY_TERMINATED_MOUSE_COMPONENT, 0, 0); } - const bool processed = (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result); + if (overscroll_controller_) + overscroll_controller_->ReceivedEventACK(wheel_event.event, processed); if (!processed && !is_hidden() && view_) view_->UnhandledWheelEvent(wheel_event.event); } @@ -2054,6 +2218,9 @@ void RenderWidgetHostImpl::OnGestureEventAck( latency.AddLatencyNumber( ui::INPUT_EVENT_LATENCY_TERMINATED_GESTURE_COMPONENT, 0 ,0); } + const bool processed = (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result); + if (overscroll_controller_) + overscroll_controller_->ReceivedEventACK(event.event, processed); if (view_) view_->GestureEventAck(event.event.type, ack_result); diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index 6882c34..820f5e0 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h @@ -726,7 +726,24 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, virtual void IncrementInFlightEventCount() OVERRIDE; virtual void DecrementInFlightEventCount() OVERRIDE; virtual void OnHasTouchEventHandlers(bool has_handlers) OVERRIDE; - virtual OverscrollController* GetOverscrollController() const OVERRIDE; + virtual bool OnSendKeyboardEvent( + const NativeWebKeyboardEvent& key_event, + const ui::LatencyInfo& latency_info, + bool* is_shortcut) OVERRIDE; + virtual bool OnSendWheelEvent( + const MouseWheelEventWithLatencyInfo& wheel_event) OVERRIDE; + virtual bool OnSendMouseEvent( + const MouseEventWithLatencyInfo& mouse_event) OVERRIDE; + virtual bool OnSendTouchEvent( + const TouchEventWithLatencyInfo& touch_event) OVERRIDE; + virtual bool OnSendGestureEvent( + const GestureEventWithLatencyInfo& gesture_event) OVERRIDE; + virtual bool OnSendMouseEventImmediately( + const MouseEventWithLatencyInfo& mouse_event) OVERRIDE; + virtual bool OnSendTouchEventImmediately( + const TouchEventWithLatencyInfo& touch_event) OVERRIDE; + virtual bool OnSendGestureEventImmediately( + const GestureEventWithLatencyInfo& gesture_event) OVERRIDE; virtual void SetNeedsFlush() OVERRIDE; virtual void DidFlush() OVERRIDE; @@ -741,6 +758,8 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, InputEventAckState ack_result) OVERRIDE; virtual void OnUnexpectedEventAck(UnexpectedEventAckType type) OVERRIDE; + void SimulateTouchGestureWithMouse(const WebKit::WebMouseEvent& mouse_event); + // Called when there is a new auto resize (using a post to avoid a stack // which may get in recursive loops). void DelayedAutoResized(); diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc index 5e78883..ed306b2 100644 --- a/content/browser/renderer_host/render_widget_host_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_unittest.cc @@ -132,26 +132,37 @@ class MockInputRouter : public InputRouter { } virtual void SendMouseEvent( const MouseEventWithLatencyInfo& mouse_event) OVERRIDE { - sent_mouse_event_ = true; + if (client_->OnSendMouseEvent(mouse_event)) + sent_mouse_event_ = true; } virtual void SendWheelEvent( const MouseWheelEventWithLatencyInfo& wheel_event) OVERRIDE { - sent_wheel_event_ = true; + if (client_->OnSendWheelEvent(wheel_event)) + sent_wheel_event_ = true; } virtual void SendKeyboardEvent( const NativeWebKeyboardEvent& key_event, - const ui::LatencyInfo& latency_info, - bool is_shortcut) OVERRIDE { - sent_keyboard_event_ = true; + const ui::LatencyInfo& latency_info) OVERRIDE { + bool is_shortcut = false; + if (client_->OnSendKeyboardEvent(key_event, latency_info, &is_shortcut)) + sent_keyboard_event_ = true; } virtual void SendGestureEvent( const GestureEventWithLatencyInfo& gesture_event) OVERRIDE { - sent_gesture_event_ = true; + if (client_->OnSendGestureEvent(gesture_event)) + sent_gesture_event_ = true; } virtual void SendTouchEvent( const TouchEventWithLatencyInfo& touch_event) OVERRIDE { - send_touch_event_not_cancelled_ = true; - } + if (client_->OnSendTouchEvent(touch_event)) + send_touch_event_not_cancelled_ = true; + } + virtual void SendMouseEventImmediately( + const MouseEventWithLatencyInfo& mouse_event) OVERRIDE {} + virtual void SendTouchEventImmediately( + const TouchEventWithLatencyInfo& touch_event) OVERRIDE {} + virtual void SendGestureEventImmediately( + const GestureEventWithLatencyInfo& gesture_event) OVERRIDE {} virtual const NativeWebKeyboardEvent* GetLastKeyboardEvent() const OVERRIDE { NOTREACHED(); return NULL; @@ -214,40 +225,40 @@ class MockRenderWidgetHost : public RenderWidgetHostImpl { hung_renderer_delay_ms_ = delay_ms; } - unsigned GestureEventLastQueueEventSize() const { + unsigned GestureEventLastQueueEventSize() { return gesture_event_filter()->coalesced_gesture_events_.size(); } - WebGestureEvent GestureEventSecondFromLastQueueEvent() const { + WebGestureEvent GestureEventSecondFromLastQueueEvent() { return gesture_event_filter()->coalesced_gesture_events_.at( GestureEventLastQueueEventSize() - 2).event; } - WebGestureEvent GestureEventLastQueueEvent() const { + WebGestureEvent GestureEventLastQueueEvent() { return gesture_event_filter()->coalesced_gesture_events_.back().event; } - unsigned GestureEventDebouncingQueueSize() const { + unsigned GestureEventDebouncingQueueSize() { return gesture_event_filter()->debouncing_deferral_queue_.size(); } - WebGestureEvent GestureEventQueueEventAt(int i) const { + WebGestureEvent GestureEventQueueEventAt(int i) { return gesture_event_filter()->coalesced_gesture_events_.at(i).event; } - bool shouldDeferTapDownEvents() const { + bool shouldDeferTapDownEvents() { return gesture_event_filter()->maximum_tap_gap_time_ms_ != 0; } - bool ScrollingInProgress() const { + bool ScrollingInProgress() { return gesture_event_filter()->scrolling_in_progress_; } - bool FlingInProgress() const { + bool FlingInProgress() { return gesture_event_filter()->fling_in_progress_; } - bool WillIgnoreNextACK() const { + bool WillIgnoreNextACK() { return gesture_event_filter()->ignore_next_ack_; } @@ -315,16 +326,12 @@ class MockRenderWidgetHost : public RenderWidgetHostImpl { unresponsive_timer_fired_ = true; } - const TouchEventQueue* touch_event_queue() const { - return immediate_input_router_->touch_event_queue_.get(); - } - - const GestureEventFilter* gesture_event_filter() const { - return immediate_input_router_->gesture_event_filter_.get(); + TouchEventQueue* touch_event_queue() const { + return immediate_input_router_->touch_event_queue(); } - GestureEventFilter* gesture_event_filter() { - return immediate_input_router_->gesture_event_filter_.get(); + GestureEventFilter* gesture_event_filter() const { + return immediate_input_router_->gesture_event_filter(); } private: |