diff options
-rw-r--r-- | content/browser/renderer_host/render_widget_host.cc | 152 | ||||
-rw-r--r-- | content/browser/renderer_host/render_widget_host.h | 44 | ||||
-rw-r--r-- | content/common/view_messages.h | 5 | ||||
-rw-r--r-- | content/renderer/render_widget.cc | 19 | ||||
-rw-r--r-- | content/renderer/render_widget.h | 3 |
5 files changed, 124 insertions, 99 deletions
diff --git a/content/browser/renderer_host/render_widget_host.cc b/content/browser/renderer_host/render_widget_host.cc index 1eeb8e8..f636de3 100644 --- a/content/browser/renderer_host/render_widget_host.cc +++ b/content/browser/renderer_host/render_widget_host.cc @@ -101,7 +101,8 @@ RenderWidgetHost::RenderWidgetHost(content::RenderProcessHost* process, text_direction_updated_(false), text_direction_(WebKit::WebTextDirectionLeftToRight), text_direction_canceled_(false), - suppress_next_char_events_(false), + suppress_incoming_char_events_(false), + suppress_outgoing_char_events_(false), pending_mouse_lock_request_(false), ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { if (routing_id_ == MSG_ROUTING_NONE) @@ -574,7 +575,7 @@ void RenderWidgetHost::ForwardMouseEvent(const WebMouseEvent& mouse_event) { OnUserGesture(); } - ForwardInputEvent(mouse_event, sizeof(WebMouseEvent), false); + ForwardInputEvent(mouse_event, sizeof(WebMouseEvent)); } void RenderWidgetHost::OnMouseActivate() { @@ -612,7 +613,7 @@ void RenderWidgetHost::ForwardWheelEvent( HISTOGRAM_COUNTS_100("MPArch.RWH_WheelQueueSize", coalesced_mouse_wheel_events_.size()); - ForwardInputEvent(wheel_event, sizeof(WebMouseWheelEvent), false); + ForwardInputEvent(wheel_event, sizeof(WebMouseWheelEvent)); } void RenderWidgetHost::ForwardGestureEvent( @@ -621,7 +622,7 @@ void RenderWidgetHost::ForwardGestureEvent( if (ignore_input_events_ || process_->IgnoreInputEvents()) return; - ForwardInputEvent(gesture_event, sizeof(WebGestureEvent), false); + ForwardInputEvent(gesture_event, sizeof(WebGestureEvent)); } void RenderWidgetHost::ForwardKeyboardEvent( @@ -630,64 +631,84 @@ void RenderWidgetHost::ForwardKeyboardEvent( if (ignore_input_events_ || process_->IgnoreInputEvents()) return; + // Double check the type to make sure caller hasn't sent us nonsense that + // will mess up our key queue. + if (!WebInputEvent::isKeyboardEventType(key_event.type)) + return; + if (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 (!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 (PreHandleKeyboardEvent(key_event, &is_keyboard_shortcut)) - return; - - if (key_event.type == WebKeyboardEvent::RawKeyDown) - suppress_next_char_events_ = false; - } + if (suppress_incoming_char_events_) { + // If the preceding RawKeyDown event was handled by the browser, then we + // need to suppress all Char events generated by it. Please note that, one + // RawKeyDown event may generate multiple Char events, so we can't reset + // |suppress_incoming_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_incoming_char_events_ = false; + } - // Don't add this key to the queue if we have no way to send the message... - if (!process_->HasConnection()) + bool is_keyboard_shortcut = false; + // Only pre-handle the key event if it's not handled by the input method. + if (!key_event.skip_in_browser) { + // We need to set |suppress_incoming_char_events_| to true if + // PreHandleKeyboardEvent() returns true, but |this| may already be + // destroyed at that time. So set |suppress_incoming_char_events_| true + // here, then revert it afterwards when necessary. + if (key_event.type == WebKeyboardEvent::RawKeyDown) + suppress_incoming_char_events_ = true; + + // Tab switching/closing accelerators aren't sent to the renderer to avoid + // a hung/malicious renderer from interfering. + if (PreHandleKeyboardEvent(key_event, &is_keyboard_shortcut)) return; - // Put all WebKeyboardEvent objects in a queue since we can't trust the - // renderer and we need to give something to the UnhandledInputEvent - // handler. - key_queue_.push_back(key_event); - HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size()); + if (key_event.type == WebKeyboardEvent::RawKeyDown) + suppress_incoming_char_events_ = false; + } + + // Don't add this key to the queue if we have no way to send the message... + if (!process_->HasConnection()) + return; + + bool has_pending_key = !key_queue_.empty(); + + // We keep track of all pending keyboard events so that if any are not + // processed by the renderer, we have the ability to process them in the + // browser (via UnhandledKeyboardEvent). We also delay sending the next + // keyboard event until the previous has been ACK'd by the renderer. + key_queue_.push_back(Key(key_event, is_keyboard_shortcut)); + HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size()); + + if (!has_pending_key) + ForwardNextKeyboardEvent(); +} + +void RenderWidgetHost::ForwardNextKeyboardEvent() { + while (!key_queue_.empty()) { + const Key& front_item = key_queue_.front(); - // Only forward the non-native portions of our event. - ForwardInputEvent(key_event, sizeof(WebKeyboardEvent), - is_keyboard_shortcut); + if (suppress_outgoing_char_events_) { + if (front_item.event.type == WebInputEvent::Char) { + key_queue_.pop_front(); + continue; + } + suppress_outgoing_char_events_ = false; + } + + // The renderer only cares about the platform-independent event data. + ForwardInputEvent(front_item.event, sizeof(WebKeyboardEvent)); + break; } } void RenderWidgetHost::ForwardInputEvent(const WebInputEvent& input_event, - int event_size, - bool is_keyboard_shortcut) { + int event_size) { TRACE_EVENT0("renderer_host", "RenderWidgetHost::ForwardInputEvent"); if (!process_->HasConnection()) @@ -698,9 +719,6 @@ void RenderWidgetHost::ForwardInputEvent(const WebInputEvent& input_event, IPC::Message* message = new ViewMsg_HandleInputEvent(routing_id_); message->WriteData( reinterpret_cast<const char*>(&input_event), event_size); - // |is_keyboard_shortcut| only makes sense for RawKeyDown events. - if (input_event.type == WebInputEvent::RawKeyDown) - message->WriteBool(is_keyboard_shortcut); input_event_start_time_ = TimeTicks::Now(); Send(message); @@ -733,7 +751,7 @@ void RenderWidgetHost::ForwardTouchEvent( touch_move_pending_ = true; else touch_move_pending_ = false; - ForwardInputEvent(touch_event, sizeof(WebKit::WebTouchEvent), false); + ForwardInputEvent(touch_event, sizeof(WebKit::WebTouchEvent)); } void RenderWidgetHost::RendererExited(base::TerminationStatus status, @@ -753,7 +771,8 @@ void RenderWidgetHost::RendererExited(base::TerminationStatus status, // Must reset these to ensure that keyboard events work with a new renderer. key_queue_.clear(); - suppress_next_char_events_ = false; + suppress_incoming_char_events_ = false; + suppress_outgoing_char_events_ = false; // Reset some fields in preparation for recovering from a crash. resize_ack_pending_ = false; @@ -1323,29 +1342,40 @@ void RenderWidgetHost::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) { + } else if (key_queue_.front().event.type != type) { LOG(ERROR) << "We seem to have a different key type sent from " - << "the renderer. (" << key_queue_.front().type << " vs. " + << "the renderer. (" << key_queue_.front().event.type << " vs. " << type << "). Ignoring event."; // Something must be wrong. Clear the |key_queue_| and - // |suppress_next_char_events_| so that we can resume from the error. + // |suppress_incoming_char_events_| so that we can resume from the error. key_queue_.clear(); - suppress_next_char_events_ = false; + suppress_incoming_char_events_ = false; + suppress_outgoing_char_events_ = false; } else { - NativeWebKeyboardEvent front_item = key_queue_.front(); + Key front_item = key_queue_.front(); key_queue_.pop_front(); #if defined(OS_MACOSX) - if (!is_hidden_ && view_->PostProcessEventForPluginIme(front_item)) + if (!is_hidden_ && view_->PostProcessEventForPluginIme(front_item.event)) return; #endif + // If this RawKeyDown event corresponds to a browser keyboard shortcut and + // it's not processed by the renderer, then we need to suppress the + // upcoming Char event. + if (!processed && front_item.is_shortcut) { + DCHECK(front_item.event.type == WebInputEvent::RawKeyDown); + suppress_outgoing_char_events_ = true; + } + + ForwardNextKeyboardEvent(); + // 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 (!processed && !is_hidden_ && !front_item.skip_in_browser) { - UnhandledKeyboardEvent(front_item); + if (!processed && !is_hidden_ && !front_item.event.skip_in_browser) { + UnhandledKeyboardEvent(front_item.event); // WARNING: This RenderWidgetHost can be deallocated at this point // (i.e. in the case of Ctrl+W, where the call to diff --git a/content/browser/renderer_host/render_widget_host.h b/content/browser/renderer_host/render_widget_host.h index 71db8b7..efbd444 100644 --- a/content/browser/renderer_host/render_widget_host.h +++ b/content/browser/renderer_host/render_widget_host.h @@ -283,6 +283,7 @@ class CONTENT_EXPORT RenderWidgetHost : public IPC::Channel::Listener, void ForwardWheelEvent(const WebKit::WebMouseWheelEvent& wheel_event); void ForwardGestureEvent(const WebKit::WebGestureEvent& gesture_event); virtual void ForwardKeyboardEvent(const NativeWebKeyboardEvent& key_event); + virtual void ForwardNextKeyboardEvent(); virtual void ForwardTouchEvent(const WebKit::WebTouchEvent& touch_event); @@ -450,7 +451,7 @@ class CONTENT_EXPORT RenderWidgetHost : public IPC::Channel::Listener, protected: // Internal implementation of the public Forward*Event() methods. void ForwardInputEvent(const WebKit::WebInputEvent& input_event, - int event_size, bool is_keyboard_shortcut); + int event_size); // Called when we receive a notification indicating that the renderer // process has gone. This will reset our state so that our state will be @@ -738,7 +739,14 @@ class CONTENT_EXPORT RenderWidgetHost : public IPC::Channel::Listener, base::TimeTicks repaint_start_time_; // Queue of keyboard events that we need to track. - typedef std::deque<NativeWebKeyboardEvent> KeyQueue; + struct Key { + Key(const NativeWebKeyboardEvent& event, bool is_shortcut) + : event(event), is_shortcut(is_shortcut) { + } + NativeWebKeyboardEvent event; + bool is_shortcut; + }; + typedef std::deque<Key> 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 @@ -758,19 +766,27 @@ class CONTENT_EXPORT RenderWidgetHost : public IPC::Channel::Listener, bool text_direction_canceled_; // Indicates if the next sequence of Char events should be suppressed or not. - // System may translate a RawKeyDown event into zero or more Char events, + // + // The system may translate a RawKeyDown event into zero or more Char events, // usually we send them to the renderer directly in sequence. However, If a - // RawKeyDown event was not handled by the renderer but was handled by - // our UnhandledKeyboardEvent() method, e.g. as an accelerator key, then we - // shall not send the following sequence of Char events, which was generated - // by this RawKeyDown event, to the renderer. Otherwise the renderer may - // handle the Char events and cause unexpected behavior. - // For example, pressing alt-2 may let the browser switch to the second tab, - // but the Char event generated by alt-2 may also activate a HTML element - // if its accesskey happens to be "2", then the user may get confused when - // switching back to the original tab, because the content may already be - // changed. - bool suppress_next_char_events_; + // RawKeyDown event was not handled by the renderer but was handled by our + // UnhandledKeyboardEvent() method, e.g. as an accelerator key, then we shall + // not send the following sequence of Char events, which was generated by + // this RawKeyDown event, to the renderer. Otherwise the renderer may handle + // the Char events and cause unexpected behavior. For example, pressing + // alt-2 may let the browser switch to the second tab, but the Char event + // generated by alt-2 may also activate a HTML element if its accesskey + // happens to be "2", then the user may get confused when switching back to + // the original tab, because the content may already be changed. + // + // If true, suppress_incoming_char_events_ prevents Char events from being + // added to key_queue_. + // + // If true, suppress_outgoing_char_events_ prevents Char events from being + // removed from key_queue_ and forwarded to the renderer. + // + bool suppress_incoming_char_events_; + bool suppress_outgoing_char_events_; std::vector<gfx::PluginWindowHandle> deferred_plugin_handles_; diff --git a/content/common/view_messages.h b/content/common/view_messages.h index 9c175e3..971e565 100644 --- a/content/common/view_messages.h +++ b/content/common/view_messages.h @@ -727,10 +727,7 @@ IPC_MESSAGE_ROUTED4(ViewMsg_PaintAtSize, // This signals the render view that it can send another UpdateRect message. IPC_MESSAGE_ROUTED0(ViewMsg_UpdateRect_ACK) -// Message payload includes: -// 1. A blob that should be cast to WebInputEvent -// 2. An optional boolean value indicating if a RawKeyDown event is associated -// to a keyboard shortcut of the browser. +// Message payload includes a blob that should be cast to WebInputEvent IPC_MESSAGE_ROUTED0(ViewMsg_HandleInputEvent) // This message notifies the renderer that the next key event is bound to one diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index 5197c01..b16c5ba 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc @@ -91,7 +91,6 @@ RenderWidget::RenderWidget(WebKit::WebPopupType popup_type) can_compose_inline_(true), popup_type_(popup_type), pending_window_rect_count_(0), - suppress_next_char_events_(false), is_accelerated_compositing_active_(false), animation_update_pending_(false), animation_task_posted_(false), @@ -446,11 +445,6 @@ void RenderWidget::OnHandleInputEvent(const IPC::Message& message) { const WebInputEvent* input_event = reinterpret_cast<const WebInputEvent*>(data); - bool is_keyboard_shortcut = false; - // is_keyboard_shortcut flag is only available for RawKeyDown events. - if (input_event->type == WebInputEvent::RawKeyDown) - message.ReadBool(&iter, &is_keyboard_shortcut); - bool prevent_default = false; if (WebInputEvent::isMouseEventType(input_event->type)) { prevent_default = WillHandleMouseEvent( @@ -458,17 +452,8 @@ void RenderWidget::OnHandleInputEvent(const IPC::Message& message) { } bool processed = prevent_default; - if (input_event->type != WebInputEvent::Char || !suppress_next_char_events_) { - suppress_next_char_events_ = false; - if (!processed && webwidget_) - processed = webwidget_->handleInputEvent(*input_event); - } - - // If this RawKeyDown event corresponds to a browser keyboard shortcut and - // it's not processed by webkit, then we need to suppress the upcoming Char - // events. - if (!processed && is_keyboard_shortcut) - suppress_next_char_events_ = true; + if (!processed && webwidget_) + processed = webwidget_->handleInputEvent(*input_event); IPC::Message* response = new ViewHostMsg_HandleInputEvent_ACK(routing_id_, input_event->type, diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h index 1bb4bae..206c473 100644 --- a/content/renderer/render_widget.h +++ b/content/renderer/render_widget.h @@ -458,9 +458,6 @@ class CONTENT_EXPORT RenderWidget scoped_ptr<IPC::Message> pending_input_event_ack_; - // Indicates if the next sequence of Char events should be suppressed or not. - bool suppress_next_char_events_; - // Set to true if painting to the window is handled by the accelerated // compositor. bool is_accelerated_compositing_active_; |