diff options
author | asargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-19 23:43:35 +0000 |
---|---|---|
committer | asargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-19 23:43:35 +0000 |
commit | 37f36b763a2cfd0cb86c3779005cd15225a43362 (patch) | |
tree | 947651d88f3532853b1b6ffa016109b664f6597b /content/browser | |
parent | 518024c161921db45e32d6eb4f177a91888ade74 (diff) | |
download | chromium_src-37f36b763a2cfd0cb86c3779005cd15225a43362.zip chromium_src-37f36b763a2cfd0cb86c3779005cd15225a43362.tar.gz chromium_src-37f36b763a2cfd0cb86c3779005cd15225a43362.tar.bz2 |
Revert 212684 "Factor out input event handling code from RenderW..."
This seems to have broken RenderViewHostTest.BadMessageHandlerInputEventAck on
linux and chromeos on the waterfall.
> Factor out input event handling code from RenderWidgetHostImpl to InputRouter
>
> Input event handling code in RenderWidgetHostImpl has evolved such that making
> making related changes is a fragile and delicate process. This code factors out
> such code into a single ImmediateInputRouter class, implementing an abstract
> InputRouter. This makes minor input-related changes more self-contained, and
> enables major changes to progress in parallel, as with the implementation of
> the BufferedInputRouter.
>
> BUG=245499
>
> Review URL: https://chromiumcodereview.appspot.com/15789009
TBR=jdduke@chromium.org
Review URL: https://codereview.chromium.org/19492016
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@212695 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser')
17 files changed, 761 insertions, 1325 deletions
diff --git a/content/browser/renderer_host/gesture_event_filter.cc b/content/browser/renderer_host/gesture_event_filter.cc index bdf360d..7f8d170 100644 --- a/content/browser/renderer_host/gesture_event_filter.cc +++ b/content/browser/renderer_host/gesture_event_filter.cc @@ -6,7 +6,7 @@ #include "base/command_line.h" #include "base/strings/string_number_conversions.h" -#include "content/browser/renderer_host/input/input_router.h" +#include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/touchpad_tap_suppression_controller.h" #include "content/browser/renderer_host/touchscreen_tap_suppression_controller.h" #include "content/public/common/content_switches.h" @@ -58,14 +58,14 @@ static int GetTapDownDeferralTimeMs() { } } // namespace -GestureEventFilter::GestureEventFilter(InputRouter* input_router) - : input_router_(input_router), +GestureEventFilter::GestureEventFilter(RenderWidgetHostImpl* rwhv) + : render_widget_host_(rwhv), fling_in_progress_(false), scrolling_in_progress_(false), ignore_next_ack_(false), combined_scroll_pinch_(gfx::Transform()), touchpad_tap_suppression_controller_( - new TouchpadTapSuppressionController(input_router)), + new TouchpadTapSuppressionController(rwhv)), touchscreen_tap_suppression_controller_( new TouchscreenTapSuppressionController(this)), maximum_tap_gap_time_ms_(GetTapDownDeferralTimeMs()), @@ -242,6 +242,19 @@ bool GestureEventFilter::ShouldForwardForCoalescing( return ShouldHandleEventNow(); } +void GestureEventFilter::Reset() { + fling_in_progress_ = false; + scrolling_in_progress_ = false; + ignore_next_ack_ = false; + combined_scroll_pinch_ = gfx::Transform(); + coalesced_gesture_events_.clear(); + deferred_tap_down_event_.event.type = WebInputEvent::Undefined; + debouncing_deferral_queue_.clear(); + send_gtd_timer_.Stop(); + debounce_deferring_timer_.Stop(); + // TODO(rjkroege): Reset the tap suppression controller. +} + void GestureEventFilter::ProcessGestureAck(bool processed, int type) { if (coalesced_gesture_events_.empty()) { DLOG(ERROR) << "Received unexpected ACK for event type " << type; @@ -261,7 +274,7 @@ void GestureEventFilter::ProcessGestureAck(bool processed, int type) { } else if (!coalesced_gesture_events_.empty()) { const GestureEventWithLatencyInfo& next_gesture_event = coalesced_gesture_events_.front(); - input_router_->SendGestureEventImmediately(next_gesture_event); + render_widget_host_->ForwardGestureEventImmediately(next_gesture_event); // TODO(yusufo): Introduce GesturePanScroll so that these can be combined // into one gesture and kept inside the queue that way. if (coalesced_gesture_events_.size() > 1) { @@ -271,7 +284,8 @@ void GestureEventFilter::ProcessGestureAck(bool processed, int type) { WebInputEvent::GestureScrollUpdate && second_gesture_event.event.type == WebInputEvent::GesturePinchUpdate) { - input_router_->SendGestureEventImmediately(second_gesture_event); + render_widget_host_-> + ForwardGestureEventImmediately(second_gesture_event); ignore_next_ack_ = true; combined_scroll_pinch_ = gfx::Transform(); } @@ -288,7 +302,7 @@ bool GestureEventFilter::HasQueuedGestureEvents() const { return !coalesced_gesture_events_.empty(); } -const WebKit::WebGestureEvent& +const WebKit::WebInputEvent& GestureEventFilter::GetGestureEventAwaitingAck() const { DCHECK(!coalesced_gesture_events_.empty()); if (!ignore_next_ack_) @@ -314,7 +328,7 @@ void GestureEventFilter::ForwardGestureEventForDeferral( void GestureEventFilter::ForwardGestureEventSkipDeferral( const GestureEventWithLatencyInfo& gesture_event) { if (ShouldForwardForCoalescing(gesture_event)) - input_router_->SendGestureEventImmediately(gesture_event); + render_widget_host_->ForwardGestureEventImmediately(gesture_event); } void GestureEventFilter::SendGestureTapDownNow() { @@ -335,7 +349,7 @@ void GestureEventFilter::SendScrollEndingEventsNow() { ShouldForwardForTapSuppression(*it) && ShouldForwardForTapDeferral(*it) && ShouldForwardForCoalescing(*it)) { - input_router_->SendGestureEventImmediately(*it); + render_widget_host_->ForwardGestureEventImmediately(*it); } } debouncing_deferral_queue_.clear(); diff --git a/content/browser/renderer_host/gesture_event_filter.h b/content/browser/renderer_host/gesture_event_filter.h index 8330502..23cce42 100644 --- a/content/browser/renderer_host/gesture_event_filter.h +++ b/content/browser/renderer_host/gesture_event_filter.h @@ -15,8 +15,8 @@ #include "ui/gfx/transform.h" namespace content { -class InputRouter; class MockRenderWidgetHost; +class RenderWidgetHostImpl; class TouchpadTapSuppressionController; class TouchscreenTapSuppressionController; @@ -43,19 +43,21 @@ class TouchscreenTapSuppressionController; // http://crbug.com/148443. class GestureEventFilter { public: - // The |input_router| must outlive the GestureEventFilter. - explicit GestureEventFilter(InputRouter* input_router); + explicit GestureEventFilter(RenderWidgetHostImpl*); ~GestureEventFilter(); // Returns |true| if the caller should immediately forward the provided // |GestureEventWithLatencyInfo| argument to the renderer. bool ShouldForward(const GestureEventWithLatencyInfo&); - // Indicates that the caller has received an acknowledgement from the renderer - // with state |processed| and event |type|. May send events if the queue is - // not empty. + // Indicates that the calling RenderWidgetHostImpl has received an + // acknowledgement from the renderer with state |processed| and event |type|. + // May send events if the queue is not empty. void ProcessGestureAck(bool processed, int type); + // Resets the state of the filter as would be needed when the renderer exits. + void Reset(); + // Sets the state of the |fling_in_progress_| field to indicate that a fling // is definitely not in progress. void FlingHasBeenHalted(); @@ -67,7 +69,7 @@ class GestureEventFilter { bool HasQueuedGestureEvents() const; // Returns the last gesture event that was sent to the renderer. - const WebKit::WebGestureEvent& GetGestureEventAwaitingAck() const; + const WebKit::WebInputEvent& GetGestureEventAwaitingAck() const; // Tries forwarding the event to the tap deferral sub-filter. void ForwardGestureEventForDeferral( @@ -144,8 +146,8 @@ class GestureEventFilter { gfx::Transform GetTransformForEvent( const GestureEventWithLatencyInfo& gesture_event); - // The receiver of all forwarded gesture events. - InputRouter* input_router_; + // Only a RenderWidgetHostViewImpl can own an instance. + RenderWidgetHostImpl* render_widget_host_; // True if a GestureFlingStart is in progress on the renderer or // queued without a subsequent queued GestureFlingCancel event. diff --git a/content/browser/renderer_host/input/OWNERS b/content/browser/renderer_host/input/OWNERS deleted file mode 100644 index 4dabaf0..0000000 --- a/content/browser/renderer_host/input/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -nduca@chromium.org -aelias@chromium.org diff --git a/content/browser/renderer_host/input/immediate_input_router.cc b/content/browser/renderer_host/input/immediate_input_router.cc deleted file mode 100644 index cd1e490..0000000 --- a/content/browser/renderer_host/input/immediate_input_router.cc +++ /dev/null @@ -1,547 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/renderer_host/input/immediate_input_router.h" - -#include "base/command_line.h" -#include "base/metrics/histogram.h" -#include "content/browser/renderer_host/gesture_event_filter.h" -#include "content/browser/renderer_host/input/input_router_client.h" -#include "content/browser/renderer_host/render_process_host_impl.h" -#include "content/browser/renderer_host/touch_event_queue.h" -#include "content/browser/renderer_host/touchpad_tap_suppression_controller.h" -#include "content/common/content_constants_internal.h" -#include "content/common/edit_command.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 "content/public/common/content_switches.h" -#include "ui/base/events/event.h" -#include "ui/base/keycodes/keyboard_codes.h" - -using base::Time; -using base::TimeDelta; -using base::TimeTicks; -using WebKit::WebGestureEvent; -using WebKit::WebInputEvent; -using WebKit::WebKeyboardEvent; -using WebKit::WebMouseEvent; -using WebKit::WebMouseWheelEvent; - -namespace content { -namespace { - -// Returns |true| if the two wheel events should be coalesced. -bool ShouldCoalesceMouseWheelEvents(const WebMouseWheelEvent& last_event, - const WebMouseWheelEvent& new_event) { - return last_event.modifiers == new_event.modifiers && - last_event.scrollByPage == new_event.scrollByPage && - last_event.hasPreciseScrollingDeltas - == new_event.hasPreciseScrollingDeltas && - last_event.phase == new_event.phase && - last_event.momentumPhase == new_event.momentumPhase; -} - -float GetUnacceleratedDelta(float accelerated_delta, float acceleration_ratio) { - return accelerated_delta * acceleration_ratio; -} - -float GetAccelerationRatio(float accelerated_delta, float unaccelerated_delta) { - if (unaccelerated_delta == 0.f || accelerated_delta == 0.f) - return 1.f; - return unaccelerated_delta / accelerated_delta; -} - -const char* GetEventAckName(InputEventAckState ack_result) { - switch(ack_result) { - case INPUT_EVENT_ACK_STATE_UNKNOWN: return "UNKNOWN"; - case INPUT_EVENT_ACK_STATE_CONSUMED: return "CONSUMED"; - case INPUT_EVENT_ACK_STATE_NOT_CONSUMED: return "NOT_CONSUMED"; - case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS: return "NO_CONSUMER_EXISTS"; - default: - DLOG(WARNING) << "Unhandled InputEventAckState in GetEventAckName.\n"; - break; - } - return ""; -} - -} // namespace - -ImmediateInputRouter::ImmediateInputRouter( - RenderProcessHost* process, - InputRouterClient* client, - int routing_id) - : process_(process), - client_(client), - routing_id_(routing_id), - select_range_pending_(false), - move_caret_pending_(false), - mouse_move_pending_(false), - mouse_wheel_pending_(false), - has_touch_handler_(false), - touch_event_queue_(new TouchEventQueue(this)), - gesture_event_filter_(new GestureEventFilter(this)) { - DCHECK(process); - DCHECK(client); -} - -ImmediateInputRouter::~ImmediateInputRouter() { -} - -bool ImmediateInputRouter::SendInput(IPC::Message* message) { - DCHECK(IPC_MESSAGE_ID_CLASS(message->type()) == InputMsgStart); - scoped_ptr<IPC::Message> scoped_message(message); - switch (scoped_message->type()) { - // Check for types that require an ACK. - case InputMsg_SelectRange::ID: - return SendSelectRange(scoped_message.release()); - case InputMsg_MoveCaret::ID: - return SendMoveCaret(scoped_message.release()); - case InputMsg_HandleInputEvent::ID: - NOTREACHED() << "WebInputEvents should never be sent via SendInput."; - return false; - default: - return Send(scoped_message.release()); - } -} - -void ImmediateInputRouter::SendMouseEvent( - const MouseEventWithLatencyInfo& mouse_event) { - if (!client_->OnSendMouseEvent(mouse_event)) - return; - - if (mouse_event.event.type == WebInputEvent::MouseDown && - gesture_event_filter_->GetTouchpadTapSuppressionController()-> - ShouldDeferMouseDown(mouse_event)) - return; - if (mouse_event.event.type == WebInputEvent::MouseUp && - gesture_event_filter_->GetTouchpadTapSuppressionController()-> - ShouldSuppressMouseUp()) - return; - - SendMouseEventImmediately(mouse_event); -} - -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 - // which many, very small wheel events are sent). - if (mouse_wheel_pending_) { - if (coalesced_mouse_wheel_events_.empty() || - !ShouldCoalesceMouseWheelEvents( - coalesced_mouse_wheel_events_.back().event, wheel_event.event)) { - coalesced_mouse_wheel_events_.push_back(wheel_event); - } else { - MouseWheelEventWithLatencyInfo* last_wheel_event = - &coalesced_mouse_wheel_events_.back(); - float unaccelerated_x = - GetUnacceleratedDelta(last_wheel_event->event.deltaX, - last_wheel_event->event.accelerationRatioX) + - GetUnacceleratedDelta(wheel_event.event.deltaX, - wheel_event.event.accelerationRatioX); - float unaccelerated_y = - GetUnacceleratedDelta(last_wheel_event->event.deltaY, - last_wheel_event->event.accelerationRatioY) + - GetUnacceleratedDelta(wheel_event.event.deltaY, - wheel_event.event.accelerationRatioY); - last_wheel_event->event.deltaX += wheel_event.event.deltaX; - last_wheel_event->event.deltaY += wheel_event.event.deltaY; - last_wheel_event->event.wheelTicksX += wheel_event.event.wheelTicksX; - last_wheel_event->event.wheelTicksY += wheel_event.event.wheelTicksY; - last_wheel_event->event.accelerationRatioX = - GetAccelerationRatio(last_wheel_event->event.deltaX, unaccelerated_x); - last_wheel_event->event.accelerationRatioY = - GetAccelerationRatio(last_wheel_event->event.deltaY, unaccelerated_y); - DCHECK_GE(wheel_event.event.timeStampSeconds, - last_wheel_event->event.timeStampSeconds); - last_wheel_event->event.timeStampSeconds = - wheel_event.event.timeStampSeconds; - last_wheel_event->latency.MergeWith(wheel_event.latency); - } - 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); -} - -void ImmediateInputRouter::SendKeyboardEvent( - const NativeWebKeyboardEvent& key_event, - 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. - key_queue_.push_back(key_event); - HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size()); - - gesture_event_filter_->FlingHasBeenHalted(); - - // Only forward the non-native portions of our event. - FilterAndSendWebInputEvent(key_event, latency_info, is_shortcut); -} - -void ImmediateInputRouter::SendGestureEvent( - const GestureEventWithLatencyInfo& gesture_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); -} - -// Forwards MouseEvent without passing it through -// 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 - // more WM_MOUSEMOVE events than we wish to send to the renderer. - if (mouse_event.event.type == WebInputEvent::MouseMove) { - if (mouse_move_pending_) { - if (!next_mouse_move_) { - next_mouse_move_.reset(new MouseEventWithLatencyInfo(mouse_event)); - } else { - // Accumulate movement deltas. - int x = next_mouse_move_->event.movementX; - int y = next_mouse_move_->event.movementY; - next_mouse_move_->event = mouse_event.event; - next_mouse_move_->event.movementX += x; - next_mouse_move_->event.movementY += y; - next_mouse_move_->latency.MergeWith(mouse_event.latency); - } - return; - } - mouse_move_pending_ = true; - } - - FilterAndSendWebInputEvent(mouse_event.event, mouse_event.latency, false); -} - -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) { - if (!client_->OnSendGestureEventImmediately(gesture_event)) - return; - FilterAndSendWebInputEvent(gesture_event.event, gesture_event.latency, false); -} - -const NativeWebKeyboardEvent* - ImmediateInputRouter::GetLastKeyboardEvent() const { - if (key_queue_.empty()) - return NULL; - return &key_queue_.front(); -} - -bool ImmediateInputRouter::ShouldForwardTouchEvent() const { - // Always send a touch event if the renderer has a touch-event handler. It is - // possible that a renderer stops listening to touch-events while there are - // still events in the touch-queue. In such cases, the new events should still - // get into the queue. - return has_touch_handler_ || !touch_event_queue_->empty(); -} - -bool ImmediateInputRouter::ShouldForwardGestureEvent( - const GestureEventWithLatencyInfo& touch_event) const { - return gesture_event_filter_->ShouldForward(touch_event); -} - -bool ImmediateInputRouter::HasQueuedGestureEvents() const { - return gesture_event_filter_->HasQueuedGestureEvents(); -} - -bool ImmediateInputRouter::OnMessageReceived(const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(ImmediateInputRouter, message) - IPC_MESSAGE_HANDLER(InputHostMsg_HandleInputEvent_ACK, OnInputEventAck) - IPC_MESSAGE_HANDLER(ViewHostMsg_MoveCaret_ACK, OnMsgMoveCaretAck) - IPC_MESSAGE_HANDLER(ViewHostMsg_SelectRange_ACK, OnSelectRangeAck) - IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers, - OnHasTouchEventHandlers) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void ImmediateInputRouter::OnTouchEventAck( - const TouchEventWithLatencyInfo& event, - InputEventAckState ack_result) { - client_->OnTouchEventAck(event, ack_result); -} - -bool ImmediateInputRouter::SendSelectRange(IPC::Message* message) { - DCHECK(message->type() == InputMsg_SelectRange::ID); - if (select_range_pending_) { - next_selection_range_.reset(message); - return true; - } - - select_range_pending_ = true; - return Send(message); -} - -bool ImmediateInputRouter::SendMoveCaret(IPC::Message* message) { - DCHECK(message->type() == InputMsg_MoveCaret::ID); - if (move_caret_pending_) { - next_move_caret_.reset(message); - return true; - } - - move_caret_pending_ = true; - return Send(message); -} - -bool ImmediateInputRouter::Send(IPC::Message* message) { - return process_->Send(message); -} - -void ImmediateInputRouter::SendWebInputEvent( - const WebInputEvent& input_event, - const ui::LatencyInfo& latency_info, - bool is_keyboard_shortcut) { - input_event_start_time_ = TimeTicks::Now(); - Send(new InputMsg_HandleInputEvent( - routing_id(), &input_event, latency_info, is_keyboard_shortcut)); - client_->IncrementInFlightEventCount(); -} - -void ImmediateInputRouter::FilterAndSendWebInputEvent( - const WebInputEvent& input_event, - const ui::LatencyInfo& latency_info, - bool is_keyboard_shortcut) { - TRACE_EVENT0("input", "ImmediateInputRouter::FilterAndSendWebInputEvent"); - - if (!process_->HasConnection()) - return; - - 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) { - // Send the ACK and early exit. - case INPUT_EVENT_ACK_STATE_CONSUMED: - case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS: - next_mouse_move_.reset(); - ProcessInputEventAck(input_event.type, filter_ack); - // WARNING: |this| may be deleted at this point. - return; - - 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. - gesture_event_filter_->ProcessGestureAck(true, input_event.type); - } 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. - touch_event_queue_->ProcessTouchAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); - } - return; - } - - // Proceed as normal. - case INPUT_EVENT_ACK_STATE_NOT_CONSUMED: - break; - }; - - // Transmit any pending wheel events on a non-wheel event. This ensures that - // the renderer receives the final PhaseEnded wheel event, which is necessary - // to terminate rubber-banding, for example. - 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_.clear(); - } - - SendWebInputEvent(input_event, latency_info, is_keyboard_shortcut); - - // Any input event cancels a pending mouse move event. - next_mouse_move_.reset(); -} - -void ImmediateInputRouter::OnInputEventAck(WebInputEvent::Type event_type, - InputEventAckState ack_result) { - // Log the time delta for processing an input event. - TimeDelta delta = TimeTicks::Now() - input_event_start_time_; - UMA_HISTOGRAM_TIMES("MPArch.IIR_InputEventDelta", delta); - - client_->DecrementInFlightEventCount(); - - ProcessInputEventAck(event_type, ack_result); -} - -void ImmediateInputRouter::OnMsgMoveCaretAck() { - move_caret_pending_ = false; - if (next_move_caret_) - SendMoveCaret(next_move_caret_.release()); -} - -void ImmediateInputRouter::OnSelectRangeAck() { - select_range_pending_ = false; - if (next_selection_range_) - SendSelectRange(next_selection_range_.release()); -} - -void ImmediateInputRouter::OnHasTouchEventHandlers(bool has_handlers) { - if (has_touch_handler_ == has_handlers) - return; - has_touch_handler_ = has_handlers; - if (!has_handlers) - touch_event_queue_->FlushQueue(); - client_->OnHasTouchEventHandlers(has_handlers); -} - -void ImmediateInputRouter::ProcessInputEventAck(WebInputEvent::Type event_type, - InputEventAckState ack_result) { - TRACE_EVENT1("input", "ImmediateInputRouter::ProcessInputEventAck", - "ack", GetEventAckName(ack_result)); - - int type = static_cast<int>(event_type); - if (type < WebInputEvent::Undefined) { - client_->OnUnexpectedEventAck(true); - } 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(type, ack_result); - } else if (type == WebInputEvent::MouseWheel) { - ProcessWheelAck(ack_result); - } else if (WebInputEvent::isTouchEventType(type)) { - ProcessTouchAck(ack_result); - } else if (WebInputEvent::isGestureEventType(type)) { - ProcessGestureAck(type, ack_result); - } - - // 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( - int type, - InputEventAckState ack_result) { - if (key_queue_.empty()) { - LOG(ERROR) << "Got a KeyEvent back from the renderer but we " - << "don't seem to have sent it to the renderer!"; - } else if (key_queue_.front().type != type) { - LOG(ERROR) << "We seem to have a different key type sent from " - << "the renderer. (" << key_queue_.front().type << " vs. " - << type << "). Ignoring event."; - - // Something must be wrong. Clear the |key_queue_| and char event - // suppression so that we can resume from the error. - key_queue_.clear(); - client_->OnUnexpectedEventAck(false); - } else { - NativeWebKeyboardEvent front_item = key_queue_.front(); - key_queue_.pop_front(); - - client_->OnKeyboardEventAck(front_item, ack_result); - - // 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). - } -} - -void ImmediateInputRouter::ProcessWheelAck(InputEventAckState ack_result) { - mouse_wheel_pending_ = false; - - // Process the unhandled wheel event here before calling - // ForwardWheelEventWithLatencyInfo() since it will mutate - // current_wheel_event_. - client_->OnWheelEventAck(current_wheel_event_.event, ack_result); - - // Now send the next (coalesced) mouse wheel event. - if (!coalesced_mouse_wheel_events_.empty()) { - MouseWheelEventWithLatencyInfo next_wheel_event = - coalesced_mouse_wheel_events_.front(); - coalesced_mouse_wheel_events_.pop_front(); - SendWheelEvent(next_wheel_event); - } -} - -void ImmediateInputRouter::ProcessGestureAck(int type, - InputEventAckState ack_result) { - const bool processed = (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result); - client_->OnGestureEventAck( - gesture_event_filter_->GetGestureEventAwaitingAck(), ack_result); - gesture_event_filter_->ProcessGestureAck(processed, type); -} - -void ImmediateInputRouter::ProcessTouchAck(InputEventAckState ack_result) { - // |touch_event_queue_| will forward to OnTouchEventAck when appropriate. - touch_event_queue_->ProcessTouchAck(ack_result); -} - -} // namespace content diff --git a/content/browser/renderer_host/input/immediate_input_router.h b/content/browser/renderer_host/input/immediate_input_router.h deleted file mode 100644 index ca3fd24..0000000 --- a/content/browser/renderer_host/input/immediate_input_router.h +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_RENDERER_HOST_INPUT_IMMEDIATE_INPUT_ROUTER_H_ -#define CONTENT_BROWSER_RENDERER_HOST_INPUT_IMMEDIATE_INPUT_ROUTER_H_ - -#include <queue> - -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/time/time.h" -#include "content/browser/renderer_host/input/input_router.h" -#include "content/browser/renderer_host/touch_event_queue.h" -#include "content/public/browser/native_web_keyboard_event.h" - -namespace ui { -struct LatencyInfo; -} - -namespace content { - -class GestureEventFilter; -class InputRouterClient; -class RenderProcessHost; -class RenderWidgetHostImpl; - -// A default implementation for browser input event routing. Input commands are -// forwarded to the renderer immediately upon receipt. -class ImmediateInputRouter : public InputRouter, - public TouchEventQueueClient { - public: - ImmediateInputRouter(RenderProcessHost* process, - InputRouterClient* client, - int routing_id); - virtual ~ImmediateInputRouter(); - - // InputRouter - virtual bool SendInput(IPC::Message* message) OVERRIDE; - virtual void SendMouseEvent( - const MouseEventWithLatencyInfo& mouse_event) OVERRIDE; - virtual void SendWheelEvent( - const MouseWheelEventWithLatencyInfo& wheel_event) OVERRIDE; - virtual void SendKeyboardEvent( - const NativeWebKeyboardEvent& key_event, - 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( - const GestureEventWithLatencyInfo& gesture_event) const OVERRIDE; - virtual bool HasQueuedGestureEvents() const OVERRIDE; - - // 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: - // TouchEventQueueClient - virtual void OnTouchEventAck(const TouchEventWithLatencyInfo& event, - InputEventAckState ack_result) OVERRIDE; - - bool SendMoveCaret(IPC::Message* message); - bool SendSelectRange(IPC::Message* message); - bool Send(IPC::Message* message); - - // Transmits the given input event an as an IPC::Message. This is an internal - // helper for |FilterAndSendInputEvent()| and should not be used otherwise. - void SendWebInputEvent(const WebKit::WebInputEvent& input_event, - const ui::LatencyInfo& latency_info, - bool is_keyboard_shortcut); - - // Filters and forwards the given WebInputEvent to |SendWebInputEvent()|. This - // is an internal helper for |Send*Event()| and should not be used otherwise. - void FilterAndSendWebInputEvent(const WebKit::WebInputEvent& input_event, - const ui::LatencyInfo& latency_info, - bool is_keyboard_shortcut); - - // IPC message handlers - void OnInputEventAck(WebKit::WebInputEvent::Type event_type, - InputEventAckState ack_result); - void OnMsgMoveCaretAck(); - void OnSelectRangeAck(); - void OnHasTouchEventHandlers(bool has_handlers); - - // 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); - - // Called by ProcessInputEventAck() to process a keyboard event ack message. - void ProcessKeyboardAck(int type, InputEventAckState ack_result); - - // 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); - - // 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(int type, InputEventAckState ack_result); - - // 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); - - int routing_id() const { return routing_id_; } - - - RenderProcessHost* process_; - InputRouterClient* client_; - int routing_id_; - - // (Similar to |mouse_move_pending_|.) True while waiting for SelectRange_ACK. - bool select_range_pending_; - - // (Similar to |next_mouse_move_|.) The next SelectRange to send, if any. - scoped_ptr<IPC::Message> next_selection_range_; - - // (Similar to |mouse_move_pending_|.) True while waiting for MoveCaret_ACK. - bool move_caret_pending_; - - // (Similar to |next_mouse_move_|.) The next MoveCaret to send, if any. - scoped_ptr<IPC::Message> next_move_caret_; - - // True if a mouse move event was sent to the render view and we are waiting - // for a corresponding InputHostMsg_HandleInputEvent_ACK message. - bool mouse_move_pending_; - - // The next mouse move event to send (only non-null while mouse_move_pending_ - // is true). - scoped_ptr<MouseEventWithLatencyInfo> next_mouse_move_; - - // (Similar to |mouse_move_pending_|.) True if a mouse wheel event was sent - // and we are waiting for a corresponding ack. - bool mouse_wheel_pending_; - MouseWheelEventWithLatencyInfo current_wheel_event_; - - typedef std::deque<MouseWheelEventWithLatencyInfo> WheelEventQueue; - - // (Similar to |next_mouse_move_|.) The next mouse wheel events to send. - // Unlike mouse moves, mouse wheel events received while one is pending are - // coalesced (by accumulating deltas) if they match the previous event in - // modifiers. On the Mac, in particular, mouse wheel events are received at a - // high rate; not waiting for the ack results in jankiness, and using the same - // mechanism as for mouse moves (just dropping old events when multiple ones - // would be queued) results in very slow scrolling. - WheelEventQueue coalesced_mouse_wheel_events_; - - // The time when an input event was sent to the RenderWidget. - base::TimeTicks input_event_start_time_; - - // Queue of keyboard events that we need to track. - typedef std::deque<NativeWebKeyboardEvent> KeyQueue; - - // A queue of keyboard events. We can't trust data from the renderer so we - // stuff key events into a queue and pop them out on ACK, feeding our copy - // back to whatever unhandled handler instead of the returned version. - KeyQueue key_queue_; - - // Keeps track of whether the webpage has any touch event handler. If it does, - // then touch events are sent to the renderer. Otherwise, the touch events are - // not sent to the renderer. - bool has_touch_handler_; - - scoped_ptr<TouchEventQueue> touch_event_queue_; - scoped_ptr<GestureEventFilter> gesture_event_filter_; - - DISALLOW_COPY_AND_ASSIGN(ImmediateInputRouter); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_IMMEDIATE_INPUT_ROUTER_H_ diff --git a/content/browser/renderer_host/input/input_router.h b/content/browser/renderer_host/input/input_router.h deleted file mode 100644 index 2d8a4c6..0000000 --- a/content/browser/renderer_host/input/input_router.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_RENDERER_HOST_INPUT_INPUT_ROUTER_H_ -#define CONTENT_BROWSER_RENDERER_HOST_INPUT_INPUT_ROUTER_H_ - -#include "base/basictypes.h" -#include "content/port/browser/event_with_latency_info.h" -#include "content/port/common/input_event_ack_state.h" -#include "content/public/browser/native_web_keyboard_event.h" -#include "ipc/ipc_listener.h" -#include "third_party/WebKit/public/web/WebInputEvent.h" - -namespace content { - -class InputRouterClient; - -// The InputRouter allows the embedder to customize how input events are -// sent to the renderer, and how responses are dispatched to the browser. -// While the router should respect the relative order in which events are -// received, it is free to customize when those events are dispatched. -class InputRouter : public IPC::Listener { - public: - virtual ~InputRouter() {} - - // Send and take ownership of the the given InputMsg_*. This should be used - // only for event types not associated with a WebInputEvent. Returns true on - // success and false otherwise. - virtual bool SendInput(IPC::Message* message) = 0; - - // WebInputEvents - virtual void SendMouseEvent( - const MouseEventWithLatencyInfo& mouse_event) = 0; - virtual void SendWheelEvent( - const MouseWheelEventWithLatencyInfo& wheel_event) = 0; - virtual void SendKeyboardEvent( - const NativeWebKeyboardEvent& key_event, - 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; - - // Returns |true| if the caller should immediately forward touch events to the - // router. When |false|, the caller can forego sending touch events, and - // instead consume them directly. - virtual bool ShouldForwardTouchEvent() const = 0; - - // Returns |true| if the caller should immediately forward the provided - // |gesture_event| to the router. - virtual bool ShouldForwardGestureEvent( - const GestureEventWithLatencyInfo& gesture_event) const = 0; - - // Returns |true| if the router has any queued or in-flight gesture events. - virtual bool HasQueuedGestureEvents() const = 0; -}; - -} // namespace content - -#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_INPUT_ROUTER_H_ diff --git a/content/browser/renderer_host/input/input_router_client.h b/content/browser/renderer_host/input/input_router_client.h deleted file mode 100644 index 9c85422..0000000 --- a/content/browser/renderer_host/input/input_router_client.h +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_RENDERER_HOST_INPUT_INPUT_ROUTER_CLIENT_H_ -#define CONTENT_BROWSER_RENDERER_HOST_INPUT_INPUT_ROUTER_CLIENT_H_ - -#include "content/common/content_export.h" -#include "content/port/browser/event_with_latency_info.h" -#include "content/port/common/input_event_ack_state.h" -#include "content/public/browser/native_web_keyboard_event.h" -#include "third_party/WebKit/public/web/WebInputEvent.h" - -namespace ui { -struct LatencyInfo; -} - -namespace content { - -class CONTENT_EXPORT InputRouterClient { - public: - virtual ~InputRouterClient() {} - - // Called just prior to events being sent to the renderer, giving the client - // a chance to perform in-process event filtering. - // The returned disposition will yield the following behavior: - // * |NOT_CONSUMED| will result in |input_event| being sent as usual. - // * |CONSUMED| or |NO_CONSUMER_EXISTS| will trigger the appropriate ack. - // * |UNKNOWN| will result in |input_event| being dropped. - virtual InputEventAckState FilterInputEvent( - const WebKit::WebInputEvent& input_event, - const ui::LatencyInfo& latency_info) = 0; - - // Called each time a WebInputEvent IPC is sent. - virtual void IncrementInFlightEventCount() = 0; - - // Called each time a WebInputEvent ACK IPC is received. - virtual void DecrementInFlightEventCount() = 0; - - // Called when the renderer notifies that it has touch event handlers. - virtual void OnHasTouchEventHandlers(bool has_handlers) = 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; - - // Called upon event ack receipt from the renderer. - virtual void OnKeyboardEventAck(const NativeWebKeyboardEvent& event, - InputEventAckState ack_result) = 0; - virtual void OnWheelEventAck(const WebKit::WebMouseWheelEvent& event, - InputEventAckState ack_result) = 0; - virtual void OnTouchEventAck(const TouchEventWithLatencyInfo& event, - InputEventAckState ack_result) = 0; - virtual void OnGestureEventAck(const WebKit::WebGestureEvent& event, - InputEventAckState ack_result) = 0; - virtual void OnUnexpectedEventAck(bool bad_message) = 0; -}; - -} // namespace content - -#endif // CONTENT_BROWSER_RENDERER_HOST_INPUT_INPUT_ROUTER_CLIENT_H_ diff --git a/content/browser/renderer_host/overscroll_controller.cc b/content/browser/renderer_host/overscroll_controller.cc index 7e9ba4b..2babec8 100644 --- a/content/browser/renderer_host/overscroll_controller.cc +++ b/content/browser/renderer_host/overscroll_controller.cc @@ -4,6 +4,7 @@ #include "content/browser/renderer_host/overscroll_controller.h" +#include "content/browser/renderer_host/gesture_event_filter.h" #include "content/browser/renderer_host/overscroll_controller_delegate.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/public/browser/overscroll_configuration.h" @@ -62,12 +63,12 @@ bool OverscrollController::WillDispatchEvent( // touch-scrolls maintain state in the renderer side (in the compositor, for // example), and the event that completes this action needs to be sent to // the renderer so that those states can be updated/reset appropriately. - // Send the event through the host when appropriate. - if (ShouldForwardToHost(event)) { + // Send the event through the gesture-event filter when appropriate. + if (ShouldForwardToGestureFilter(event)) { const WebKit::WebGestureEvent& gevent = static_cast<const WebKit::WebGestureEvent&>(event); - return render_widget_host_->ShouldForwardGestureEvent( - GestureEventWithLatencyInfo(gevent, latency_info)); + return render_widget_host_->gesture_event_filter()-> + ShouldForward(GestureEventWithLatencyInfo(gevent, latency_info)); } return false; @@ -77,11 +78,12 @@ bool OverscrollController::WillDispatchEvent( SetOverscrollMode(OVERSCROLL_NONE); // The overscroll gesture status is being reset. If the event is a // gesture event (from either touchscreen or trackpad), then make sure the - // host gets the event first (if it didn't already process it). - if (ShouldForwardToHost(event)) { + // gesture event filter gets the event first (if it didn't already process + // it). + if (ShouldForwardToGestureFilter(event)) { const WebKit::WebGestureEvent& gevent = static_cast<const WebKit::WebGestureEvent&>(event); - return render_widget_host_->ShouldForwardGestureEvent( + return render_widget_host_->gesture_event_filter()->ShouldForward( GestureEventWithLatencyInfo(gevent, latency_info)); } @@ -360,14 +362,14 @@ void OverscrollController::SetOverscrollMode(OverscrollMode mode) { delegate_->OnOverscrollModeChange(old_mode, overscroll_mode_); } -bool OverscrollController::ShouldForwardToHost( +bool OverscrollController::ShouldForwardToGestureFilter( const WebKit::WebInputEvent& event) const { if (!WebKit::WebInputEvent::isGestureEventType(event.type)) return false; - // If the RenderWidgetHost already processed this event, then the event must - // not be sent again. - return !render_widget_host_->HasQueuedGestureEvents(); + // If the GestureEventFilter already processed this event, then the event must + // not be sent to the filter again. + return !render_widget_host_->gesture_event_filter()->HasQueuedGestureEvents(); } } // namespace content diff --git a/content/browser/renderer_host/overscroll_controller.h b/content/browser/renderer_host/overscroll_controller.h index c9e477b..2259f3f 100644 --- a/content/browser/renderer_host/overscroll_controller.h +++ b/content/browser/renderer_host/overscroll_controller.h @@ -103,8 +103,8 @@ class OverscrollController { void SetOverscrollMode(OverscrollMode new_mode); // Returns whether the input event should be forwarded to the - // RenderWidgetHost. - bool ShouldForwardToHost(const WebKit::WebInputEvent& event) const; + // GestureEventFilter. + bool ShouldForwardToGestureFilter(const WebKit::WebInputEvent& event) const; // The RenderWidgetHost that owns this overscroll controller. RenderWidgetHostImpl* render_widget_host_; diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 0eb19cb..c1696a7 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc @@ -28,12 +28,14 @@ #include "content/browser/renderer_host/backing_store.h" #include "content/browser/renderer_host/backing_store_manager.h" #include "content/browser/renderer_host/dip_util.h" -#include "content/browser/renderer_host/input/immediate_input_router.h" +#include "content/browser/renderer_host/gesture_event_filter.h" #include "content/browser/renderer_host/overscroll_controller.h" #include "content/browser/renderer_host/render_process_host_impl.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/renderer_host/render_widget_helper.h" #include "content/browser/renderer_host/render_widget_host_delegate.h" +#include "content/browser/renderer_host/touch_event_queue.h" +#include "content/browser/renderer_host/touchpad_tap_suppression_controller.h" #include "content/common/accessibility_messages.h" #include "content/common/content_constants_internal.h" #include "content/common/gpu/gpu_messages.h" @@ -88,6 +90,27 @@ bool g_check_for_pending_resize_ack = true; // This timeout impacts the "choppiness" of our window resize perf. const int kPaintMsgTimeoutMS = 50; +// Returns |true| if the two wheel events should be coalesced. +bool ShouldCoalesceMouseWheelEvents(const WebMouseWheelEvent& last_event, + const WebMouseWheelEvent& new_event) { + return last_event.modifiers == new_event.modifiers && + last_event.scrollByPage == new_event.scrollByPage && + last_event.hasPreciseScrollingDeltas + == new_event.hasPreciseScrollingDeltas && + last_event.phase == new_event.phase && + last_event.momentumPhase == new_event.momentumPhase; +} + +float GetUnacceleratedDelta(float accelerated_delta, float acceleration_ratio) { + return accelerated_delta * acceleration_ratio; +} + +float GetAccelerationRatio(float accelerated_delta, float unaccelerated_delta) { + if (unaccelerated_delta == 0.f || accelerated_delta == 0.f) + return 1.f; + return unaccelerated_delta / accelerated_delta; +} + base::LazyInstance<std::vector<RenderWidgetHost::CreatedCallback> > g_created_callbacks = LAZY_INSTANCE_INITIALIZER; @@ -133,7 +156,11 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate, overdraw_bottom_height_(0.f), should_auto_resize_(false), waiting_for_screen_rects_ack_(false), + mouse_move_pending_(false), + mouse_wheel_pending_(false), accessibility_mode_(AccessibilityModeOff), + select_range_pending_(false), + move_caret_pending_(false), needs_repainting_on_restore_(false), is_unresponsive_(false), in_flight_event_count_(0), @@ -150,6 +177,8 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate, allow_privileged_mouse_lock_(false), has_touch_handler_(false), weak_factory_(this), + touch_event_queue_(new TouchEventQueue(this)), + gesture_event_filter_(new GestureEventFilter(this)), last_input_number_(0) { CHECK(delegate_); if (routing_id_ == MSG_ROUTING_NONE) { @@ -186,8 +215,6 @@ RenderWidgetHostImpl::RenderWidgetHostImpl(RenderWidgetHostDelegate* delegate, for (size_t i = 0; i < g_created_callbacks.Get().size(); i++) g_created_callbacks.Get().at(i).Run(this); - input_router_.reset(new ImmediateInputRouter(process, this, routing_id_)); - #if defined(USE_AURA) bool overscroll_enabled = CommandLine::ForCurrentProcess()-> GetSwitchValueASCII(switches::kOverscrollHistoryNavigation) != "0"; @@ -430,9 +457,14 @@ bool RenderWidgetHostImpl::OnMessageReceived(const IPC::Message &msg) { IPC_MESSAGE_HANDLER(ViewHostMsg_DidOverscroll, OnOverscrolled) IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnUpdateRect) IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateIsDelayed, OnUpdateIsDelayed) + IPC_MESSAGE_HANDLER(InputHostMsg_HandleInputEvent_ACK, OnInputEventAck) IPC_MESSAGE_HANDLER(ViewHostMsg_BeginSmoothScroll, OnBeginSmoothScroll) + IPC_MESSAGE_HANDLER(ViewHostMsg_SelectRange_ACK, OnSelectRangeAck) + IPC_MESSAGE_HANDLER(ViewHostMsg_MoveCaret_ACK, OnMsgMoveCaretAck) IPC_MESSAGE_HANDLER(ViewHostMsg_Focus, OnFocus) IPC_MESSAGE_HANDLER(ViewHostMsg_Blur, OnBlur) + IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers, + OnHasTouchEventHandlers) IPC_MESSAGE_HANDLER(ViewHostMsg_SetCursor, OnSetCursor) IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputTypeChanged, OnTextInputTypeChanged) @@ -458,9 +490,6 @@ bool RenderWidgetHostImpl::OnMessageReceived(const IPC::Message &msg) { IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP_EX() - if (!handled && input_router_ && input_router_->OnMessageReceived(msg)) - return true; - if (!handled && view_ && view_->OnMessageReceived(msg)) return true; @@ -473,9 +502,6 @@ bool RenderWidgetHostImpl::OnMessageReceived(const IPC::Message &msg) { } bool RenderWidgetHostImpl::Send(IPC::Message* msg) { - if (IPC_MESSAGE_ID_CLASS(msg->type()) == InputMsgStart) - return input_router_->SendInput(msg); - return process_->Send(msg); } @@ -1003,9 +1029,28 @@ void RenderWidgetHostImpl::ForwardMouseEvent(const WebMouseEvent& mouse_event) { void RenderWidgetHostImpl::ForwardMouseEventWithLatencyInfo( const MouseEventWithLatencyInfo& mouse_event) { - TRACE_EVENT2("input", "RenderWidgetHostImpl::ForwardMouseEvent", + TRACE_EVENT2("input", + "RenderWidgetHostImpl::ForwardMouseEventWithLatencyInfo", "x", mouse_event.event.x, "y", mouse_event.event.y); - input_router_->SendMouseEvent(mouse_event); + if (ignore_input_events_ || process_->IgnoreInputEvents()) + return; + + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kSimulateTouchScreenWithMouse)) { + SimulateTouchGestureWithMouse(mouse_event.event); + return; + } + + if (mouse_event.event.type == WebInputEvent::MouseDown && + gesture_event_filter_->GetTouchpadTapSuppressionController()-> + ShouldDeferMouseDown(mouse_event)) + return; + if (mouse_event.event.type == WebInputEvent::MouseUp && + gesture_event_filter_->GetTouchpadTapSuppressionController()-> + ShouldSuppressMouseUp()) + return; + + ForwardMouseEventImmediately(mouse_event); } void RenderWidgetHostImpl::OnPointerEventActivate() { @@ -1013,15 +1058,67 @@ void RenderWidgetHostImpl::OnPointerEventActivate() { void RenderWidgetHostImpl::ForwardWheelEvent( const WebMouseWheelEvent& wheel_event) { - ForwardWheelEventWithLatencyInfo( - MouseWheelEventWithLatencyInfo(wheel_event, - CreateRWHLatencyInfoIfNotExist(NULL))); + ForwardWheelEventWithLatencyInfo(wheel_event, + CreateRWHLatencyInfoIfNotExist(NULL)); } void RenderWidgetHostImpl::ForwardWheelEventWithLatencyInfo( - const MouseWheelEventWithLatencyInfo& wheel_event) { - TRACE_EVENT0("input", "RenderWidgetHostImpl::ForwardWheelEvent"); - input_router_->SendWheelEvent(wheel_event); + const WebMouseWheelEvent& wheel_event, + const ui::LatencyInfo& latency_info) { + TRACE_EVENT0("input", + "RenderWidgetHostImpl::ForwardWheelEventWithLatencyInfo"); + if (ignore_input_events_ || process_->IgnoreInputEvents()) + return; + + if (delegate_->PreHandleWheelEvent(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 + // which many, very small wheel events are sent). + if (mouse_wheel_pending_) { + if (coalesced_mouse_wheel_events_.empty() || + !ShouldCoalesceMouseWheelEvents( + coalesced_mouse_wheel_events_.back().event, wheel_event)) { + coalesced_mouse_wheel_events_.push_back( + MouseWheelEventWithLatencyInfo(wheel_event, latency_info)); + } else { + MouseWheelEventWithLatencyInfo* last_wheel_event = + &coalesced_mouse_wheel_events_.back(); + float unaccelerated_x = + GetUnacceleratedDelta(last_wheel_event->event.deltaX, + last_wheel_event->event.accelerationRatioX) + + GetUnacceleratedDelta(wheel_event.deltaX, + wheel_event.accelerationRatioX); + float unaccelerated_y = + GetUnacceleratedDelta(last_wheel_event->event.deltaY, + last_wheel_event->event.accelerationRatioY) + + GetUnacceleratedDelta(wheel_event.deltaY, + wheel_event.accelerationRatioY); + last_wheel_event->event.deltaX += wheel_event.deltaX; + last_wheel_event->event.deltaY += wheel_event.deltaY; + last_wheel_event->event.wheelTicksX += wheel_event.wheelTicksX; + last_wheel_event->event.wheelTicksY += wheel_event.wheelTicksY; + last_wheel_event->event.accelerationRatioX = + GetAccelerationRatio(last_wheel_event->event.deltaX, unaccelerated_x); + last_wheel_event->event.accelerationRatioY = + GetAccelerationRatio(last_wheel_event->event.deltaY, unaccelerated_y); + DCHECK_GE(wheel_event.timeStampSeconds, + last_wheel_event->event.timeStampSeconds); + last_wheel_event->event.timeStampSeconds = wheel_event.timeStampSeconds; + last_wheel_event->latency.MergeWith(latency_info); + } + return; + } + mouse_wheel_pending_ = true; + current_wheel_event_ = wheel_event; + + HISTOGRAM_COUNTS_100("MPArch.RWH_WheelQueueSize", + coalesced_mouse_wheel_events_.size()); + + ForwardInputEvent(wheel_event, sizeof(WebMouseWheelEvent), latency_info, + false); } void RenderWidgetHostImpl::ForwardGestureEvent( @@ -1033,8 +1130,7 @@ void RenderWidgetHostImpl::ForwardGestureEventWithLatencyInfo( const WebKit::WebGestureEvent& gesture_event, const ui::LatencyInfo& ui_latency) { TRACE_EVENT0("input", "RenderWidgetHostImpl::ForwardGestureEvent"); - // Early out if necessary, prior to performing latency logic. - if (IgnoreInputEvents()) + if (ignore_input_events_ || process_->IgnoreInputEvents()) return; ui::LatencyInfo latency_info = CreateRWHLatencyInfoIfNotExist(&ui_latency); @@ -1061,24 +1157,152 @@ void RenderWidgetHostImpl::ForwardGestureEventWithLatencyInfo( } } - GestureEventWithLatencyInfo gesture_with_latency(gesture_event, latency_info); - input_router_->SendGestureEvent(gesture_with_latency); + if (!IsInOverscrollGesture() && + !gesture_event_filter_->ShouldForward( + GestureEventWithLatencyInfo(gesture_event, latency_info))) { + if (overscroll_controller_.get()) + overscroll_controller_->DiscardingGestureEvent(gesture_event); + return; + } + + ForwardInputEvent(gesture_event, sizeof(WebGestureEvent), + latency_info, false); } -void RenderWidgetHostImpl::ForwardTouchEventWithLatencyInfo( - const WebKit::WebTouchEvent& touch_event, - const ui::LatencyInfo& ui_latency) { +// Forwards MouseEvent without passing it through +// TouchpadTapSuppressionController. +void RenderWidgetHostImpl::ForwardMouseEventImmediately( + const MouseEventWithLatencyInfo& mouse_event) { + TRACE_EVENT2("input", + "RenderWidgetHostImpl::ForwardMouseEventImmediately", + "x", mouse_event.event.x, "y", mouse_event.event.y); + if (ignore_input_events_ || process_->IgnoreInputEvents()) + return; + + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kSimulateTouchScreenWithMouse)) { + SimulateTouchGestureWithMouse(mouse_event.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 + // more WM_MOUSEMOVE events than we wish to send to the renderer. + if (mouse_event.event.type == WebInputEvent::MouseMove) { + if (mouse_move_pending_) { + if (!next_mouse_move_) { + next_mouse_move_.reset(new MouseEventWithLatencyInfo(mouse_event)); + } else { + // Accumulate movement deltas. + int x = next_mouse_move_->event.movementX; + int y = next_mouse_move_->event.movementY; + next_mouse_move_->event = mouse_event.event; + next_mouse_move_->event.movementX += x; + next_mouse_move_->event.movementY += y; + next_mouse_move_->latency.MergeWith(mouse_event.latency); + } + return; + } + mouse_move_pending_ = true; + } else if (mouse_event.event.type == WebInputEvent::MouseDown) { + OnUserGesture(); + } + + ForwardInputEvent(mouse_event.event, sizeof(WebMouseEvent), + mouse_event.latency, false); +} + +void RenderWidgetHostImpl::ForwardTouchEventImmediately( + const TouchEventWithLatencyInfo& touch_event) { TRACE_EVENT0("input", "RenderWidgetHostImpl::ForwardTouchEvent"); - ui::LatencyInfo latency_info = CreateRWHLatencyInfoIfNotExist(&ui_latency); - TouchEventWithLatencyInfo touch_with_latency(touch_event, latency_info); - input_router_->SendTouchEvent(touch_with_latency); + if (ignore_input_events_ || process_->IgnoreInputEvents()) + return; + + ForwardInputEvent(touch_event.event, sizeof(WebKit::WebTouchEvent), + touch_event.latency, false); +} + +void RenderWidgetHostImpl::ForwardGestureEventImmediately( + const GestureEventWithLatencyInfo& gesture_event) { + if (ignore_input_events_ || process_->IgnoreInputEvents()) + return; + ForwardInputEvent(gesture_event.event, sizeof(WebGestureEvent), + gesture_event.latency, false); } void RenderWidgetHostImpl::ForwardKeyboardEvent( const NativeWebKeyboardEvent& key_event) { TRACE_EVENT0("input", "RenderWidgetHostImpl::ForwardKeyboardEvent"); - input_router_->SendKeyboardEvent(key_event, - CreateRWHLatencyInfoIfNotExist(NULL)); + if (ignore_input_events_ || process_->IgnoreInputEvents()) + 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)) { + 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_keyboard_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_keyboard_shortcut)) + return; + + if (key_event.type == WebKeyboardEvent::RawKeyDown) + suppress_next_char_events_ = false; + } + + // Don't add this key to the queue if we have no way to send the message... + if (!process_->HasConnection()) + 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. + key_queue_.push_back(key_event); + HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size()); + + gesture_event_filter_->FlingHasBeenHalted(); + + // Only forward the non-native portions of our event. + ForwardInputEvent(key_event, sizeof(WebKeyboardEvent), + CreateRWHLatencyInfoIfNotExist(NULL), + is_keyboard_shortcut); + } } void RenderWidgetHostImpl::SendCursorVisibilityState(bool is_visible) { @@ -1111,6 +1335,111 @@ ui::LatencyInfo RenderWidgetHostImpl::CreateRWHLatencyInfoIfNotExist( return info; } +void RenderWidgetHostImpl::SendInputEvent(const WebInputEvent& input_event, + int event_size, + const ui::LatencyInfo& latency_info, + bool is_keyboard_shortcut) { + DCHECK(latency_info.FindLatency(ui::INPUT_EVENT_LATENCY_RWH_COMPONENT, + GetLatencyComponentId(), + NULL)); + input_event_start_time_ = TimeTicks::Now(); + Send(new InputMsg_HandleInputEvent( + routing_id_, &input_event, latency_info, is_keyboard_shortcut)); + increment_in_flight_event_count(); +} + +void RenderWidgetHostImpl::ForwardInputEvent( + const WebInputEvent& input_event, int event_size, + const ui::LatencyInfo& latency_info, bool is_keyboard_shortcut) { + TRACE_EVENT0("input", "RenderWidgetHostImpl::ForwardInputEvent"); + + if (!process_->HasConnection()) + return; + + DCHECK(!process_->IgnoreInputEvents()); + + if (overscroll_controller_.get() && + !overscroll_controller_->WillDispatchEvent(input_event, latency_info)) { + 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 + // is awaiting an ack for the event. Since the event is being consumed by + // the over scroll here, 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. + gesture_event_filter_->ProcessGestureAck(true, input_event.type); + } 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 and 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. + touch_event_queue_->ProcessTouchAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + } + return; + } + + // Transmit any pending wheel events on a non-wheel event. This ensures that + // the renderer receives the final PhaseEnded wheel event, which is necessary + // to terminate rubber-banding, for example. + if (input_event.type != WebInputEvent::MouseWheel) { + for (size_t i = 0; i < coalesced_mouse_wheel_events_.size(); ++i) { + SendInputEvent(coalesced_mouse_wheel_events_[i].event, + sizeof(WebMouseWheelEvent), + coalesced_mouse_wheel_events_[i].latency, + false); + } + coalesced_mouse_wheel_events_.clear(); + } + + if (view_) { + // Perform optional, synchronous event handling, sending ACK messages for + // processed events, or proceeding as usual. + InputEventAckState filter_ack = view_->FilterInputEvent(input_event); + switch (filter_ack) { + // Send the ACK and early exit. + case INPUT_EVENT_ACK_STATE_CONSUMED: + case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS: + next_mouse_move_.reset(); + OnInputEventAck(input_event.type, filter_ack); + // WARNING: |this| may be deleted at this point. + return; + + // Proceed as normal. + case INPUT_EVENT_ACK_STATE_UNKNOWN: + case INPUT_EVENT_ACK_STATE_NOT_CONSUMED: + default: + break; + }; + } + + SendInputEvent(input_event, event_size, latency_info, is_keyboard_shortcut); + + // Any input event cancels a pending mouse move event. Note that + // |next_mouse_move_| possibly owns |input_event|, so don't use |input_event| + // after this line. + next_mouse_move_.reset(); + + StartHangMonitorTimeout( + TimeDelta::FromMilliseconds(hung_renderer_delay_ms_)); +} + +void RenderWidgetHostImpl::ForwardTouchEventWithLatencyInfo( + const WebKit::WebTouchEvent& touch_event, + const ui::LatencyInfo& ui_latency) { + ui::LatencyInfo latency_info = CreateRWHLatencyInfoIfNotExist(&ui_latency); + TouchEventWithLatencyInfo touch_with_latency(touch_event, latency_info); + touch_event_queue_->QueueEvent(touch_with_latency); +} void RenderWidgetHostImpl::AddKeyboardListener(KeyboardListener* listener) { keyboard_listeners_.AddObserver(listener); @@ -1133,7 +1462,9 @@ void RenderWidgetHostImpl::GetWebScreenInfo(WebKit::WebScreenInfo* result) { const NativeWebKeyboardEvent* RenderWidgetHostImpl::GetLastKeyboardEvent() const { - return input_router_->GetLastKeyboardEvent(); + if (key_queue_.empty()) + return NULL; + return &key_queue_.front(); } void RenderWidgetHostImpl::NotifyScreenInfoChanged() { @@ -1191,13 +1522,31 @@ void RenderWidgetHostImpl::RendererExited(base::TerminationStatus status, waiting_for_screen_rects_ack_ = false; - // Reset to ensure that input routing works with a new renderer. - input_router_.reset(new ImmediateInputRouter(process_, this, routing_id_)); + // Must reset these to ensure that mouse move/wheel events work with a new + // renderer. + mouse_move_pending_ = false; + next_mouse_move_.reset(); + mouse_wheel_pending_ = false; + coalesced_mouse_wheel_events_.clear(); + + // Must reset these to ensure that SelectRange works with a new renderer. + select_range_pending_ = false; + next_selection_range_.reset(); + + // Must reset these to ensure that MoveCaret works with a new renderer. + move_caret_pending_ = false; + next_move_caret_.reset(); + + touch_event_queue_->Reset(); + + // Must reset these to ensure that gesture events work with a new renderer. + gesture_event_filter_->Reset(); if (overscroll_controller_) overscroll_controller_->Reset(); - // Must reset these to ensure that keyboard events work with a new renderer. + // Must reset these to ensure that keyboard events work with a new renderer. + key_queue_.clear(); suppress_next_char_events_ = false; // Reset some fields in preparation for recovering from a crash. @@ -1653,6 +2002,56 @@ void RenderWidgetHostImpl::DidUpdateBackingStore( UMA_HISTOGRAM_TIMES("MPArch.RWH_TotalPaintTime", delta); } +void RenderWidgetHostImpl::OnInputEventAck( + WebInputEvent::Type event_type, InputEventAckState ack_result) { + TRACE_EVENT0("input", "RenderWidgetHostImpl::OnInputEventAck"); + bool processed = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED); + + // Log the time delta for processing an input event. + TimeDelta delta = TimeTicks::Now() - input_event_start_time_; + UMA_HISTOGRAM_TIMES("MPArch.RWH_InputEventDelta", delta); + + // Cancel pending hung renderer checks since the renderer is responsive. + if (decrement_in_flight_event_count() == 0) + StopHangMonitorTimeout(); + + int type = static_cast<int>(event_type); + if (type < WebInputEvent::Undefined) { + RecordAction(UserMetricsAction("BadMessageTerminate_RWH2")); + process_->ReceivedBadMessage(); + } 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); + ForwardMouseEventWithLatencyInfo(*next_mouse_move_); + } + } else if (WebInputEvent::isKeyboardEventType(type)) { + ProcessKeyboardEventAck(type, processed); + } else if (type == WebInputEvent::MouseWheel) { + ProcessWheelAck(processed); + } else if (WebInputEvent::isTouchEventType(type)) { + ProcessTouchAck(ack_result); + } else if (WebInputEvent::isGestureEventType(type)) { + ProcessGestureAck(processed, type); + } + + // 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 + // (OnInputEventAck) 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 RenderWidgetHostImpl::OnBeginSmoothScroll( const ViewHostMsg_BeginSmoothScroll_Params& params) { if (!view_) @@ -1660,6 +2059,59 @@ void RenderWidgetHostImpl::OnBeginSmoothScroll( smooth_scroll_gesture_controller_.BeginSmoothScroll(view_, params); } +void RenderWidgetHostImpl::OnSelectRangeAck() { + select_range_pending_ = false; + if (next_selection_range_) { + scoped_ptr<SelectionRange> next(next_selection_range_.Pass()); + SelectRange(next->start, next->end); + } +} + +void RenderWidgetHostImpl::OnMsgMoveCaretAck() { + move_caret_pending_ = false; + if (next_move_caret_) { + scoped_ptr<gfx::Point> next(next_move_caret_.Pass()); + MoveCaret(*next); + } +} + +void RenderWidgetHostImpl::ProcessWheelAck(bool processed) { + mouse_wheel_pending_ = false; + + if (overscroll_controller_) + overscroll_controller_->ReceivedEventACK(current_wheel_event_, processed); + + // Process the unhandled wheel event here before calling + // ForwardWheelEventWithLatencyInfo() since it will mutate + // current_wheel_event_. + if (!processed && !is_hidden_ && view_) + view_->UnhandledWheelEvent(current_wheel_event_); + + // Now send the next (coalesced) mouse wheel event. + if (!coalesced_mouse_wheel_events_.empty()) { + MouseWheelEventWithLatencyInfo next_wheel_event = + coalesced_mouse_wheel_events_.front(); + coalesced_mouse_wheel_events_.pop_front(); + ForwardWheelEventWithLatencyInfo(next_wheel_event.event, + next_wheel_event.latency); + } +} + +void RenderWidgetHostImpl::ProcessGestureAck(bool processed, int type) { + if (overscroll_controller_) { + overscroll_controller_->ReceivedEventACK( + gesture_event_filter_->GetGestureEventAwaitingAck(), processed); + } + gesture_event_filter_->ProcessGestureAck(processed, type); + + if (view_) + view_->GestureEventAck(type); +} + +void RenderWidgetHostImpl::ProcessTouchAck(InputEventAckState ack_result) { + touch_event_queue_->ProcessTouchAck(ack_result); +} + void RenderWidgetHostImpl::OnFocus() { // Only RenderViewHost can deal with that message. RecordAction(UserMetricsAction("BadMessageTerminate_RWH4")); @@ -1672,6 +2124,18 @@ void RenderWidgetHostImpl::OnBlur() { GetProcess()->ReceivedBadMessage(); } +void RenderWidgetHostImpl::OnHasTouchEventHandlers(bool has_handlers) { + if (has_touch_handler_ == has_handlers) + return; + has_touch_handler_ = has_handlers; + if (!has_touch_handler_) + touch_event_queue_->FlushQueue(); +#if defined(OS_ANDROID) + if (view_) + view_->HasTouchEventHandlers(has_touch_handler_); +#endif +} + void RenderWidgetHostImpl::OnSetCursor(const WebCursor& cursor) { if (!view_) { return; @@ -1881,263 +2345,51 @@ bool RenderWidgetHostImpl::KeyPressListenersHandleEvent( return false; } -InputEventAckState RenderWidgetHostImpl::FilterInputEvent( - const WebKit::WebInputEvent& event, const ui::LatencyInfo& latency_info) { - if (overscroll_controller() && - !overscroll_controller()->WillDispatchEvent(event, latency_info)) { - return INPUT_EVENT_ACK_STATE_UNKNOWN; - } - - return view_ ? view_->FilterInputEvent(event) - : INPUT_EVENT_ACK_STATE_NOT_CONSUMED; -} - -void RenderWidgetHostImpl::IncrementInFlightEventCount() { - StartHangMonitorTimeout( - TimeDelta::FromMilliseconds(hung_renderer_delay_ms_)); - increment_in_flight_event_count(); -} - -void RenderWidgetHostImpl::DecrementInFlightEventCount() { - DCHECK(in_flight_event_count_ >= 0); - // Cancel pending hung renderer checks since the renderer is responsive. - if (decrement_in_flight_event_count() <= 0) - StopHangMonitorTimeout(); -} - -void RenderWidgetHostImpl::OnHasTouchEventHandlers(bool has_handlers) { - if (has_touch_handler_ == has_handlers) - return; - has_touch_handler_ = has_handlers; -#if defined(OS_ANDROID) - if (view_) - view_->HasTouchEventHandlers(has_touch_handler_); -#endif -} - -bool RenderWidgetHostImpl::OnSendKeyboardEvent( - const NativeWebKeyboardEvent& key_event, - const ui::LatencyInfo& latency_info, - bool* is_shortcut) { - if (IgnoreInputEvents()) - return false; +void RenderWidgetHostImpl::ProcessKeyboardEventAck(int type, bool processed) { + if (key_queue_.empty()) { + LOG(ERROR) << "Got a KeyEvent back from the renderer but we " + << "don't seem to have sent it to the renderer!"; + } else if (key_queue_.front().type != type) { + LOG(ERROR) << "We seem to have a different key type sent from " + << "the renderer. (" << key_queue_.front().type << " vs. " + << type << "). Ignoring event."; - 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. + // Something must be wrong. Clear the |key_queue_| and + // |suppress_next_char_events_| so that we can resume from the error. + key_queue_.clear(); 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(); -} + } else { + NativeWebKeyboardEvent front_item = key_queue_.front(); + key_queue_.pop_front(); -void RenderWidgetHostImpl::OnKeyboardEventAck( - const NativeWebKeyboardEvent& event, - InputEventAckState ack_result) { #if defined(OS_MACOSX) - if (!is_hidden() && view_ && view_->PostProcessEventForPluginIme(event)) - return; + if (!is_hidden_ && view_->PostProcessEventForPluginIme(front_item)) + return; #endif - // We only send unprocessed key event upwards if we are not hidden, - // because the user has moved away from us and no longer expect any effect - // of this key event. - const bool processed = (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result); - if (delegate_ && !processed && !is_hidden() && !event.skip_in_browser) { - delegate_->HandleKeyboardEvent(event); - - // WARNING: This RenderWidgetHostImpl can be deallocated at this point - // (i.e. in the case of Ctrl+W, where the call to - // HandleKeyboardEvent destroys this RenderWidgetHostImpl). - } -} - -void RenderWidgetHostImpl::OnWheelEventAck( - const WebKit::WebMouseWheelEvent& wheel_event, - InputEventAckState ack_result) { - const bool processed = (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result); - if (overscroll_controller_) - overscroll_controller_->ReceivedEventACK(wheel_event, processed); - - if (!processed && !is_hidden() && view_) - view_->UnhandledWheelEvent(wheel_event); -} - -void RenderWidgetHostImpl::OnGestureEventAck( - const WebKit::WebGestureEvent& event, - InputEventAckState ack_result) { - const bool processed = (INPUT_EVENT_ACK_STATE_CONSUMED == ack_result); - if (overscroll_controller_) - overscroll_controller_->ReceivedEventACK(event, processed); + // We only send unprocessed key event upwards if we are not hidden, + // because the user has moved away from us and no longer expect any effect + // of this key event. + if (delegate_ && !processed && !is_hidden_ && !front_item.skip_in_browser) { + delegate_->HandleKeyboardEvent(front_item); - if (view_) - view_->GestureEventAck(event.type); -} - -void RenderWidgetHostImpl::OnTouchEventAck( - const TouchEventWithLatencyInfo& event, - InputEventAckState ack_result) { - ComputeTouchLatency(event.latency); - if (view_) - view_->ProcessAckedTouchEvent(event, ack_result); -} - -void RenderWidgetHostImpl::OnUnexpectedEventAck(bool bad_message) { - if (bad_message) { - RecordAction(UserMetricsAction("BadMessageTerminate_RWH2")); - process_->ReceivedBadMessage(); + // WARNING: This RenderWidgetHostImpl can be deallocated at this point + // (i.e. in the case of Ctrl+W, where the call to + // HandleKeyboardEvent destroys this RenderWidgetHostImpl). + } } - - suppress_next_char_events_ = false; } const gfx::Vector2d& RenderWidgetHostImpl::GetLastScrollOffset() const { return last_scroll_offset_; } -bool RenderWidgetHostImpl::IgnoreInputEvents() const { - return ignore_input_events_ || process_->IgnoreInputEvents(); -} - bool RenderWidgetHostImpl::ShouldForwardTouchEvent() const { - return input_router_->ShouldForwardTouchEvent(); -} - -bool RenderWidgetHostImpl::ShouldForwardGestureEvent( - const GestureEventWithLatencyInfo& gesture_event) const { - return input_router_->ShouldForwardGestureEvent(gesture_event); -} - -bool RenderWidgetHostImpl::HasQueuedGestureEvents() const { - return input_router_->HasQueuedGestureEvents(); + // Always send a touch event if the renderer has a touch-event handler. It is + // possible that a renderer stops listening to touch-events while there are + // still events in the touch-queue. In such cases, the new events should still + // get into the queue. + return has_touch_handler_ || !touch_event_queue_->empty(); } void RenderWidgetHostImpl::StartUserGesture() { @@ -2159,7 +2411,7 @@ void RenderWidgetHostImpl::SetEditCommandsForNextKeyEvent( void RenderWidgetHostImpl::SetAccessibilityMode(AccessibilityMode mode) { accessibility_mode_ = mode; - Send(new ViewMsg_SetAccessibilityMode(GetRoutingID(), mode)); + Send(new ViewMsg_SetAccessibilityMode(routing_id_, mode)); } void RenderWidgetHostImpl::AccessibilityDoDefaultAction(int object_id) { @@ -2217,10 +2469,26 @@ void RenderWidgetHostImpl::ScrollFocusedEditableNodeIntoRect( void RenderWidgetHostImpl::SelectRange(const gfx::Point& start, const gfx::Point& end) { + if (select_range_pending_) { + if (!next_selection_range_) { + next_selection_range_.reset(new SelectionRange()); + } + next_selection_range_->start = start; + next_selection_range_->end = end; + return; + } + + select_range_pending_ = true; Send(new InputMsg_SelectRange(GetRoutingID(), start, end)); } void RenderWidgetHostImpl::MoveCaret(const gfx::Point& point) { + if (move_caret_pending_) { + next_move_caret_.reset(new gfx::Point(point)); + return; + } + + move_caret_pending_ = true; Send(new InputMsg_MoveCaret(GetRoutingID(), point)); } diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index 752c7c0..c848aa1 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h @@ -23,7 +23,6 @@ #include "base/time/time.h" #include "base/timer/timer.h" #include "build/build_config.h" -#include "content/browser/renderer_host/input/input_router_client.h" #include "content/browser/renderer_host/smooth_scroll_gesture_controller.h" #include "content/common/browser_rendering_stats.h" #include "content/common/view_message_enums.h" @@ -73,18 +72,18 @@ class WebLayer; namespace content { class BackingStore; -class InputRouter; +class GestureEventFilter; class MockRenderWidgetHost; class OverscrollController; class RenderWidgetHostDelegate; class RenderWidgetHostViewPort; class SmoothScrollGestureController; +class TouchEventQueue; struct EditCommand; // This implements the RenderWidgetHost interface that is exposed to // embedders of content, and adds things only visible to content. class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, - public InputRouterClient, public IPC::Listener { public: // routing_id can be MSG_ROUTING_NONE, in which case the next available @@ -281,13 +280,17 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, void ForwardGestureEventWithLatencyInfo( const WebKit::WebGestureEvent& gesture_event, const ui::LatencyInfo& ui_latency); - void ForwardTouchEventWithLatencyInfo( + virtual void ForwardTouchEventWithLatencyInfo( const WebKit::WebTouchEvent& touch_event, const ui::LatencyInfo& ui_latency); - void ForwardMouseEventWithLatencyInfo( + + // Forwards the given event immediately to the renderer. + void ForwardMouseEventImmediately( const MouseEventWithLatencyInfo& mouse_event); - void ForwardWheelEventWithLatencyInfo( - const MouseWheelEventWithLatencyInfo& wheel_event); + void ForwardTouchEventImmediately( + const TouchEventWithLatencyInfo& touch_event); + void ForwardGestureEventImmediately( + const GestureEventWithLatencyInfo& gesture_event); void CancelUpdateTextDirection(); @@ -352,15 +355,7 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, return input_method_active_; } - // Whether forwarded WebInputEvents should be ignored. True if either - // |ignore_input_events_| or |process_->IgnoreInputEvents()| is true. - bool IgnoreInputEvents() const; - - // Event queries delegated to the |input_router_|. bool ShouldForwardTouchEvent() const; - bool ShouldForwardGestureEvent( - const GestureEventWithLatencyInfo& gesture_event) const; - bool HasQueuedGestureEvents() const; bool has_touch_handler() const { return has_touch_handler_; } @@ -494,7 +489,11 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, // Update the renderer's cache of the screen rect of the view and window. void SendScreenRects(); - OverscrollController* overscroll_controller() const { + GestureEventFilter* gesture_event_filter() { + return gesture_event_filter_.get(); + } + + OverscrollController* overscroll_controller() { return overscroll_controller_.get(); } @@ -527,6 +526,24 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, protected: virtual RenderWidgetHostImpl* AsRenderWidgetHostImpl() OVERRIDE; + // Transmits the given input event. This is an internal helper for + // |ForwardInputEvent()| and should not be used directly from elsewhere. + void SendInputEvent(const WebKit::WebInputEvent& input_event, + int event_size, const ui::LatencyInfo& latency_info, + bool is_keyboard_shortcut); + + // Internal implementation of the public Forward*Event() methods. + void ForwardInputEvent(const WebKit::WebInputEvent& input_event, + int event_size, const ui::LatencyInfo& latency_info, + bool is_keyboard_shortcut); + + // Internal forwarding implementations that take a LatencyInfo. + virtual void ForwardMouseEventWithLatencyInfo( + const MouseEventWithLatencyInfo& mouse_event); + virtual void ForwardWheelEventWithLatencyInfo( + const WebKit::WebMouseWheelEvent& wheel_event, + const ui::LatencyInfo& latency_info); + // Create a LatencyInfo struct with INPUT_EVENT_LATENCY_RWH_COMPONENT // component if it is not already in |original|. And if |original| is // not NULL, it is also merged into the resulting LatencyInfo. @@ -641,10 +658,15 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, gfx::Vector2dF current_fling_velocity); void OnUpdateRect(const ViewHostMsg_UpdateRect_Params& params); void OnUpdateIsDelayed(); + void OnInputEventAck(WebKit::WebInputEvent::Type event_type, + InputEventAckState ack_result); void OnBeginSmoothScroll( const ViewHostMsg_BeginSmoothScroll_Params& params); + void OnSelectRangeAck(); + void OnMsgMoveCaretAck(); virtual void OnFocus(); virtual void OnBlur(); + void OnHasTouchEventHandlers(bool has_handlers); void OnSetCursor(const WebCursor& cursor); void OnTextInputTypeChanged(ui::TextInputType type, bool can_compose_inline, @@ -699,43 +721,26 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, // widgets that don't have focus to still handle key presses. bool KeyPressListenersHandleEvent(const NativeWebKeyboardEvent& event); - // InputRouterClient - virtual InputEventAckState FilterInputEvent( - const WebKit::WebInputEvent& event, - const ui::LatencyInfo& latency_info) OVERRIDE; - virtual void IncrementInFlightEventCount() OVERRIDE; - virtual void DecrementInFlightEventCount() OVERRIDE; - virtual void OnHasTouchEventHandlers(bool has_handlers) 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 OnKeyboardEventAck(const NativeWebKeyboardEvent& event, - InputEventAckState ack_result) OVERRIDE; - virtual void OnWheelEventAck(const WebKit::WebMouseWheelEvent& event, - InputEventAckState ack_result) OVERRIDE; - virtual void OnTouchEventAck(const TouchEventWithLatencyInfo& event, - InputEventAckState ack_result) OVERRIDE; - virtual void OnGestureEventAck(const WebKit::WebGestureEvent& event, - InputEventAckState ack_result) OVERRIDE; - virtual void OnUnexpectedEventAck(bool bad_message) OVERRIDE; + // Called by OnInputEventAck() to process a keyboard event ack message. + void ProcessKeyboardEventAck(int type, bool processed); + + // Called by OnInputEventAck() 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(bool processed); + + // Called by OnInputEventAck() 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(bool processed, int type); void SimulateTouchGestureWithMouse(const WebKit::WebMouseEvent& mouse_event); + // Called on OnInputEventAck() 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); + // Called when there is a new auto resize (using a post to avoid a stack // which may get in recursive loops). void DelayedAutoResized(); @@ -813,8 +818,50 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, gfx::Rect last_view_screen_rect_; gfx::Rect last_window_screen_rect_; + // True if a mouse move event was sent to the render view and we are waiting + // for a corresponding InputHostMsg_HandleInputEvent_ACK message. + bool mouse_move_pending_; + + // The next mouse move event to send (only non-null while mouse_move_pending_ + // is true). + scoped_ptr<MouseEventWithLatencyInfo> next_mouse_move_; + + // (Similar to |mouse_move_pending_|.) True if a mouse wheel event was sent + // and we are waiting for a corresponding ack. + bool mouse_wheel_pending_; + WebKit::WebMouseWheelEvent current_wheel_event_; + + typedef std::deque<MouseWheelEventWithLatencyInfo> WheelEventQueue; + + // (Similar to |next_mouse_move_|.) The next mouse wheel events to send. + // Unlike mouse moves, mouse wheel events received while one is pending are + // coalesced (by accumulating deltas) if they match the previous event in + // modifiers. On the Mac, in particular, mouse wheel events are received at a + // high rate; not waiting for the ack results in jankiness, and using the same + // mechanism as for mouse moves (just dropping old events when multiple ones + // would be queued) results in very slow scrolling. + WheelEventQueue coalesced_mouse_wheel_events_; + AccessibilityMode accessibility_mode_; + // (Similar to |mouse_move_pending_|.) True while waiting for SelectRange_ACK. + bool select_range_pending_; + + // (Similar to |next_mouse_move_|.) The next SelectRange to send, if any. + struct SelectionRange { + gfx::Point start, end; + }; + scoped_ptr<SelectionRange> next_selection_range_; + + // (Similar to |mouse_move_pending_|.) True while waiting for MoveCaret_ACK. + bool move_caret_pending_; + + // (Similar to |next_mouse_move_|.) The next MoveCaret to send, if any. + scoped_ptr<gfx::Point> next_move_caret_; + + // The time when an input event was sent to the RenderWidget. + base::TimeTicks input_event_start_time_; + // Keyboard event listeners. ObserverList<KeyboardListener> keyboard_listeners_; @@ -851,6 +898,14 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, // operation to finish. base::TimeTicks repaint_start_time_; + // Queue of keyboard events that we need to track. + typedef std::deque<NativeWebKeyboardEvent> KeyQueue; + + // A queue of keyboard events. We can't trust data from the renderer so we + // stuff key events into a queue and pop them out on ACK, feeding our copy + // back to whatever unhandled handler instead of the returned version. + KeyQueue key_queue_; + // Set to true if we shouldn't send input events from the render widget. bool ignore_input_events_; @@ -895,10 +950,8 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, base::WeakPtrFactory<RenderWidgetHostImpl> weak_factory_; SmoothScrollGestureController smooth_scroll_gesture_controller_; - - // Receives and handles all input events. - scoped_ptr<InputRouter> input_router_; - + scoped_ptr<TouchEventQueue> touch_event_queue_; + scoped_ptr<GestureEventFilter> gesture_event_filter_; scoped_ptr<OverscrollController> overscroll_controller_; #if defined(OS_WIN) diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc index 9911354..9109c30 100644 --- a/content/browser/renderer_host/render_widget_host_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_unittest.cc @@ -9,7 +9,6 @@ #include "content/browser/browser_thread_impl.h" #include "content/browser/renderer_host/backing_store.h" #include "content/browser/renderer_host/gesture_event_filter.h" -#include "content/browser/renderer_host/input/immediate_input_router.h" #include "content/browser/renderer_host/overscroll_controller.h" #include "content/browser/renderer_host/overscroll_controller_delegate.h" #include "content/browser/renderer_host/render_widget_host_delegate.h" @@ -114,8 +113,6 @@ class MockRenderWidgetHost : public RenderWidgetHostImpl { int routing_id) : RenderWidgetHostImpl(delegate, process, routing_id), unresponsive_timer_fired_(false) { - immediate_input_router_ = - static_cast<ImmediateInputRouter*>(input_router_.get()); } // Allow poking at a few private members. @@ -125,7 +122,9 @@ class MockRenderWidgetHost : public RenderWidgetHostImpl { using RenderWidgetHostImpl::last_requested_size_; using RenderWidgetHostImpl::is_hidden_; using RenderWidgetHostImpl::resize_ack_pending_; - using RenderWidgetHostImpl::input_router_; + using RenderWidgetHostImpl::gesture_event_filter_; + using RenderWidgetHostImpl::touch_event_queue_; + using RenderWidgetHostImpl::overscroll_controller_; bool unresponsive_timer_fired() const { return unresponsive_timer_fired_; @@ -136,40 +135,40 @@ class MockRenderWidgetHost : public RenderWidgetHostImpl { } unsigned GestureEventLastQueueEventSize() { - return gesture_event_filter()->coalesced_gesture_events_.size(); + return gesture_event_filter_->coalesced_gesture_events_.size(); } WebGestureEvent GestureEventSecondFromLastQueueEvent() { - return gesture_event_filter()->coalesced_gesture_events_.at( + return gesture_event_filter_->coalesced_gesture_events_.at( GestureEventLastQueueEventSize() - 2).event; } WebGestureEvent GestureEventLastQueueEvent() { - return gesture_event_filter()->coalesced_gesture_events_.back().event; + return gesture_event_filter_->coalesced_gesture_events_.back().event; } unsigned GestureEventDebouncingQueueSize() { - return gesture_event_filter()->debouncing_deferral_queue_.size(); + return gesture_event_filter_->debouncing_deferral_queue_.size(); } WebGestureEvent GestureEventQueueEventAt(int i) { - return gesture_event_filter()->coalesced_gesture_events_.at(i).event; + return gesture_event_filter_->coalesced_gesture_events_.at(i).event; } bool shouldDeferTapDownEvents() { - return gesture_event_filter()->maximum_tap_gap_time_ms_ != 0; + return gesture_event_filter_->maximum_tap_gap_time_ms_ != 0; } bool ScrollingInProgress() { - return gesture_event_filter()->scrolling_in_progress_; + return gesture_event_filter_->scrolling_in_progress_; } bool FlingInProgress() { - return gesture_event_filter()->fling_in_progress_; + return gesture_event_filter_->fling_in_progress_; } bool WillIgnoreNextACK() { - return gesture_event_filter()->ignore_next_ack_; + return gesture_event_filter_->ignore_next_ack_; } void SetupForOverscrollControllerTest() { @@ -179,15 +178,15 @@ class MockRenderWidgetHost : public RenderWidgetHostImpl { } void set_maximum_tap_gap_time_ms(int delay_ms) { - gesture_event_filter()->maximum_tap_gap_time_ms_ = delay_ms; + gesture_event_filter_->maximum_tap_gap_time_ms_ = delay_ms; } void set_debounce_interval_time_ms(int delay_ms) { - gesture_event_filter()->debounce_interval_time_ms_ = delay_ms; + gesture_event_filter_->debounce_interval_time_ms_ = delay_ms; } size_t TouchEventQueueSize() { - return touch_event_queue()->GetQueueSize(); + return touch_event_queue_->GetQueueSize(); } bool ScrollStateIsContentScrolling() const { @@ -207,7 +206,7 @@ class MockRenderWidgetHost : public RenderWidgetHostImpl { } const WebTouchEvent& latest_event() const { - return touch_event_queue()->GetLatestEvent().event; + return touch_event_queue_->GetLatestEvent().event; } OverscrollMode overscroll_mode() const { @@ -231,18 +230,9 @@ class MockRenderWidgetHost : public RenderWidgetHostImpl { unresponsive_timer_fired_ = true; } - TouchEventQueue* touch_event_queue() const { - return immediate_input_router_->touch_event_queue(); - } - - GestureEventFilter* gesture_event_filter() const { - return immediate_input_router_->gesture_event_filter(); - } - private: bool unresponsive_timer_fired_; - ImmediateInputRouter* immediate_input_router_; scoped_ptr<TestOverscrollDelegate> overscroll_delegate_; DISALLOW_COPY_AND_ASSIGN(MockRenderWidgetHost); diff --git a/content/browser/renderer_host/touch_event_queue.cc b/content/browser/renderer_host/touch_event_queue.cc index 70804e3..5f69c41 100644 --- a/content/browser/renderer_host/touch_event_queue.cc +++ b/content/browser/renderer_host/touch_event_queue.cc @@ -7,6 +7,9 @@ #include "base/auto_reset.h" #include "base/debug/trace_event.h" #include "base/stl_util.h" +#include "content/browser/renderer_host/render_widget_host_impl.h" +#include "content/public/browser/render_widget_host_view.h" +#include "content/port/browser/render_widget_host_view_port.h" namespace content { @@ -15,8 +18,8 @@ typedef std::vector<TouchEventWithLatencyInfo> WebTouchEventWithLatencyList; // This class represents a single coalesced touch event. However, it also keeps // track of all the original touch-events that were coalesced into a single // event. The coalesced event is forwarded to the renderer, while the original -// touch-events are sent to the Client (on ACK for the coalesced event) so that -// the Client receives the event with their original timestamp. +// touch-events are sent to the View (on ACK for the coalesced event) so that +// the View receives the event with their original timestamp. class CoalescedWebTouchEvent { public: explicit CoalescedWebTouchEvent(const TouchEventWithLatencyInfo& event) @@ -41,8 +44,6 @@ class CoalescedWebTouchEvent { event_with_latency.event.modifiers && coalesced_event_.event.touchesLength == event_with_latency.event.touchesLength) { - TRACE_EVENT_INSTANT0( - "input", "TouchEventQueue::MoveCoalesced", TRACE_EVENT_SCOPE_THREAD); events_.push_back(event_with_latency); // The WebTouchPoints include absolute position information. So it is // sufficient to simply replace the previous event with the new event. @@ -89,10 +90,9 @@ class CoalescedWebTouchEvent { DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent); }; -TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client) - : client_(client), +TouchEventQueue::TouchEventQueue(RenderWidgetHostImpl* host) + : render_widget_host_(host), dispatching_touch_ack_(false) { - DCHECK(client); } TouchEventQueue::~TouchEventQueue() { @@ -108,9 +108,9 @@ void TouchEventQueue::QueueEvent(const TouchEventWithLatencyInfo& event) { // immediately. touch_queue_.push_back(new CoalescedWebTouchEvent(event)); if (ShouldForwardToRenderer(event.event)) - client_->SendTouchEventImmediately(event); + render_widget_host_->ForwardTouchEventImmediately(event); else - PopTouchEventWithAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); + PopTouchEventToView(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); return; } @@ -149,25 +149,30 @@ void TouchEventQueue::ProcessTouchAck(InputEventAckState ack_result) { } } - PopTouchEventWithAck(ack_result); + PopTouchEventToView(ack_result); // If there are queued touch events, then try to forward them to the renderer - // immediately, or ACK the events back to the client if appropriate. + // immediately, or ACK the events back to the view if appropriate. while (!touch_queue_.empty()) { const TouchEventWithLatencyInfo& touch = touch_queue_.front()->coalesced_event(); if (ShouldForwardToRenderer(touch.event)) { - client_->SendTouchEventImmediately(touch); + render_widget_host_->ForwardTouchEventImmediately(touch); break; } - PopTouchEventWithAck(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); + PopTouchEventToView(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS); } } void TouchEventQueue::FlushQueue() { DCHECK(!dispatching_touch_ack_); while (!touch_queue_.empty()) - PopTouchEventWithAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); + PopTouchEventToView(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); +} + +void TouchEventQueue::Reset() { + if (!touch_queue_.empty()) + STLDeleteElements(&touch_queue_); } size_t TouchEventQueue::GetQueueSize() const { @@ -178,7 +183,7 @@ const TouchEventWithLatencyInfo& TouchEventQueue::GetLatestEvent() const { return touch_queue_.back()->coalesced_event(); } -void TouchEventQueue::PopTouchEventWithAck(InputEventAckState ack_result) { +void TouchEventQueue::PopTouchEventToView(InputEventAckState ack_result) { if (touch_queue_.empty()) return; scoped_ptr<CoalescedWebTouchEvent> acked_event(touch_queue_.front()); @@ -188,13 +193,16 @@ void TouchEventQueue::PopTouchEventWithAck(InputEventAckState ack_result) { // to the renderer, or touch-events being queued. base::AutoReset<bool> dispatching_touch_ack(&dispatching_touch_ack_, true); + RenderWidgetHostViewPort* view = RenderWidgetHostViewPort::FromRWHV( + render_widget_host_->GetView()); for (WebTouchEventWithLatencyList::const_iterator iter = acked_event->begin(), end = acked_event->end(); iter != end; ++iter) { ui::LatencyInfo* latency = const_cast<ui::LatencyInfo*>(&(iter->latency)); latency->AddLatencyNumber( ui::INPUT_EVENT_LATENCY_ACKED_COMPONENT, 0, 0); - client_->OnTouchEventAck((*iter), ack_result); + render_widget_host_->ComputeTouchLatency(*latency); + view->ProcessAckedTouchEvent((*iter), ack_result); } } diff --git a/content/browser/renderer_host/touch_event_queue.h b/content/browser/renderer_host/touch_event_queue.h index 09783a8..8149ebf 100644 --- a/content/browser/renderer_host/touch_event_queue.h +++ b/content/browser/renderer_host/touch_event_queue.h @@ -17,27 +17,13 @@ namespace content { class CoalescedWebTouchEvent; - -// Interface with which TouchEventQueue can forward touch events, and dispatch -// touch event responses. -class TouchEventQueueClient { - public: - virtual ~TouchEventQueueClient() {} - - virtual void SendTouchEventImmediately( - const TouchEventWithLatencyInfo& event) = 0; - - virtual void OnTouchEventAck( - const TouchEventWithLatencyInfo& event, - InputEventAckState ack_result) = 0; -}; +class MockRenderWidgetHost; +class RenderWidgetHostImpl; // A queue for throttling and coalescing touch-events. class TouchEventQueue { public: - - // The |client| must outlive the TouchEventQueue. - explicit TouchEventQueue(TouchEventQueueClient* client); + explicit TouchEventQueue(RenderWidgetHostImpl* host); virtual ~TouchEventQueue(); // Adds an event to the queue. The event may be coalesced with previously @@ -55,6 +41,10 @@ class TouchEventQueue { // events being sent to the renderer. void FlushQueue(); + // Resets all internal state. This does not trigger any touch or gesture + // events to be sent. + void Reset(); + // Returns whether the event-queue is empty. bool empty() const WARN_UNUSED_RESULT { return touch_queue_.empty(); @@ -67,13 +57,13 @@ class TouchEventQueue { CONTENT_EXPORT const TouchEventWithLatencyInfo& GetLatestEvent() const; // Pops the touch-event from the top of the queue and sends it to the - // TouchEventQueueClient. This reduces the size of the queue by one. - void PopTouchEventWithAck(InputEventAckState ack_result); + // RenderWidgetHostView. This reduces the size of the queue by one. + void PopTouchEventToView(InputEventAckState ack_result); bool ShouldForwardToRenderer(const WebKit::WebTouchEvent& event) const; - // Handles touch event forwarding and ack'ed event dispatch. - TouchEventQueueClient* client_; + // The RenderWidgetHost that owns this event-queue. + RenderWidgetHostImpl* render_widget_host_; typedef std::deque<CoalescedWebTouchEvent*> TouchQueue; TouchQueue touch_queue_; diff --git a/content/browser/renderer_host/touchpad_tap_suppression_controller.cc b/content/browser/renderer_host/touchpad_tap_suppression_controller.cc index e69b640..0e8ee71 100644 --- a/content/browser/renderer_host/touchpad_tap_suppression_controller.cc +++ b/content/browser/renderer_host/touchpad_tap_suppression_controller.cc @@ -13,8 +13,8 @@ namespace content { TouchpadTapSuppressionController::TouchpadTapSuppressionController( - InputRouter* /*input_router*/) - : input_router_(NULL) {} + RenderWidgetHostImpl* /*rwhv*/) + : render_widget_host_(NULL) {} TouchpadTapSuppressionController::~TouchpadTapSuppressionController() {} diff --git a/content/browser/renderer_host/touchpad_tap_suppression_controller.h b/content/browser/renderer_host/touchpad_tap_suppression_controller.h index e78f5f1..d2cd3cc 100644 --- a/content/browser/renderer_host/touchpad_tap_suppression_controller.h +++ b/content/browser/renderer_host/touchpad_tap_suppression_controller.h @@ -12,15 +12,14 @@ namespace content { -class InputRouter; +class RenderWidgetHostImpl; class TapSuppressionController; // Controls the suppression of touchpad taps immediately following the dispatch // of a GestureFlingCancel event. class TouchpadTapSuppressionController : public TapSuppressionControllerClient { public: - // The |input_router| must outlive the TouchpadTapSupressionController. - explicit TouchpadTapSuppressionController(InputRouter* input_router); + explicit TouchpadTapSuppressionController(RenderWidgetHostImpl* rwhv); virtual ~TouchpadTapSuppressionController(); // Should be called on arrival of GestureFlingCancel events. @@ -49,7 +48,7 @@ class TouchpadTapSuppressionController : public TapSuppressionControllerClient { virtual void ForwardStashedTapDownForDeferral() OVERRIDE; virtual void ForwardStashedTapDownSkipDeferral() OVERRIDE; - InputRouter* input_router_; + RenderWidgetHostImpl* render_widget_host_; MouseEventWithLatencyInfo stashed_mouse_down_; // The core controller of tap suppression. diff --git a/content/browser/renderer_host/touchpad_tap_suppression_controller_aura.cc b/content/browser/renderer_host/touchpad_tap_suppression_controller_aura.cc index 940dc2b..a9ef442 100644 --- a/content/browser/renderer_host/touchpad_tap_suppression_controller_aura.cc +++ b/content/browser/renderer_host/touchpad_tap_suppression_controller_aura.cc @@ -4,7 +4,7 @@ #include "content/browser/renderer_host/touchpad_tap_suppression_controller.h" -#include "content/browser/renderer_host/input/input_router.h" +#include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/tap_suppression_controller.h" #include "content/browser/renderer_host/tap_suppression_controller_client.h" #include "ui/base/gestures/gesture_configuration.h" @@ -12,8 +12,8 @@ namespace content { TouchpadTapSuppressionController::TouchpadTapSuppressionController( - InputRouter* input_router) - : input_router_(input_router), + RenderWidgetHostImpl* rwhv) + : render_widget_host_(rwhv), controller_(new TapSuppressionController(this)) { } @@ -53,13 +53,13 @@ void TouchpadTapSuppressionController::DropStashedTapDown() { void TouchpadTapSuppressionController::ForwardStashedTapDownForDeferral() { // Mouse downs are not handled by gesture event filter; so, they are // immediately forwarded to the renderer. - input_router_->SendMouseEventImmediately(stashed_mouse_down_); + render_widget_host_->ForwardMouseEventImmediately(stashed_mouse_down_); } void TouchpadTapSuppressionController::ForwardStashedTapDownSkipDeferral() { // Mouse downs are not handled by gesture event filter; so, they are // immediately forwarded to the renderer. - input_router_->SendMouseEventImmediately(stashed_mouse_down_); + render_widget_host_->ForwardMouseEventImmediately(stashed_mouse_down_); } } // namespace content |