diff options
author | fsamuel@chromium.org <fsamuel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-01 05:50:10 +0000 |
---|---|---|
committer | fsamuel@chromium.org <fsamuel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-01 05:50:10 +0000 |
commit | 6dd17a8a78dd24d3849af8fd9c3887b33adcde28 (patch) | |
tree | ce8cda771ca7a84d4a022a392192547f1d5ad3af /content | |
parent | eca3fc962d8903f91d52b458f6c39bc7fb02a8a1 (diff) | |
download | chromium_src-6dd17a8a78dd24d3849af8fd9c3887b33adcde28.zip chromium_src-6dd17a8a78dd24d3849af8fd9c3887b33adcde28.tar.gz chromium_src-6dd17a8a78dd24d3849af8fd9c3887b33adcde28.tar.bz2 |
Browser Plugin: Plumb edit commands from BrowserPlugin to the guest
This fixes edit commands on Mac. When a <webview> has focus, all key events go to it. Unhandled key events get plumbed back to the embedder, where it gets an opportunity to give the keys back to the system (Chrome OS search key for example) or convert them to edit commands. Once converted to edit commands, they are issued back to the embedder. The embedder will send the edit commands to the focused plugin if it wishes to process them. The BrowserPlugin consumes the edit commands and plumbs them to the guest.
The issue with this design, that will be addressed in a subsequent CL is that it is possible for subsequent keyboard events to be processed by the embedder process prior to receiving unconsumed key events from the guests back to the embedder. This means edit commands might appear after additional input has been sent to the embedder.
This requires a blink side change:
https://codereview.chromium.org/14150012/
BUG=230148
Test=WebViewInteractiveTest.EditCommands
Review URL: https://chromiumcodereview.appspot.com/13973016
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@197569 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
8 files changed, 96 insertions, 54 deletions
diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc index 18a25c0..568303d 100644 --- a/content/browser/browser_plugin/browser_plugin_guest.cc +++ b/content/browser/browser_plugin/browser_plugin_guest.cc @@ -42,6 +42,7 @@ #include "net/base/net_errors.h" #include "net/url_request/url_request.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" +#include "ui/base/keycodes/keyboard_codes.h" #include "ui/surface/transport_dib.h" #include "webkit/glue/resource_type.h" #include "webkit/glue/webdropdata.h" @@ -113,6 +114,7 @@ class BrowserPluginGuest::EmbedderRenderViewHostObserver // RenderViewHostObserver: virtual void RenderViewHostDestroyed( RenderViewHost* render_view_host) OVERRIDE { + browser_plugin_guest_->embedder_web_contents_ = NULL; browser_plugin_guest_->Destroy(); } @@ -138,7 +140,6 @@ BrowserPluginGuest::BrowserPluginGuest( mouse_locked_(false), pending_lock_request_(false), embedder_visible_(true), - opener_(NULL), next_permission_request_id_(0) { DCHECK(web_contents); web_contents->SetDelegate(this); @@ -199,6 +200,8 @@ bool BrowserPluginGuest::OnMessageReceivedFromEmbedder( OnCompositorFrameACK) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate, OnDragStatusUpdate) + IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand, + OnExecuteEditCommand) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_Go, OnGo) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_HandleInputEvent, OnHandleInputEvent) @@ -385,6 +388,22 @@ bool BrowserPluginGuest::HandleContextMenu( return true; } +void BrowserPluginGuest::HandleKeyboardEvent( + WebContents* source, + const NativeWebKeyboardEvent& event) { + if (!attached()) + return; + + // Send the unhandled keyboard events back to the embedder to reprocess them. + // TODO(fsamuel): This introduces the possibility of out-of-order keyboard + // events because the guest may be arbitrarily delayed when responding to + // keyboard events. In that time, the embedder may have received and processed + // additional key events. This needs to be fixed as soon as possible. + // See http://crbug.com/229882. + embedder_web_contents_->GetDelegate()->HandleKeyboardEvent( + web_contents(), event); +} + void BrowserPluginGuest::WebContentsCreated(WebContents* source_contents, int64 source_frame_id, const string16& frame_name, @@ -393,7 +412,7 @@ void BrowserPluginGuest::WebContentsCreated(WebContents* source_contents, WebContentsImpl* new_contents_impl = static_cast<WebContentsImpl*>(new_contents); BrowserPluginGuest* guest = new_contents_impl->GetBrowserPluginGuest(); - guest->opener_ = this; + guest->opener_ = AsWeakPtr(); guest->name_ = UTF16ToUTF8(frame_name); // Take ownership of the new guest until it is attached to the embedder's DOM // tree to avoid leaking a guest if this guest is destroyed before attaching @@ -694,6 +713,7 @@ bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest( case BrowserPluginHostMsg_BuffersSwappedACK::ID: case BrowserPluginHostMsg_CompositorFrameACK::ID: case BrowserPluginHostMsg_DragStatusUpdate::ID: + case BrowserPluginHostMsg_ExecuteEditCommand::ID: case BrowserPluginHostMsg_Go::ID: case BrowserPluginHostMsg_HandleInputEvent::ID: case BrowserPluginHostMsg_LockMouse_ACK::ID: @@ -831,6 +851,11 @@ void BrowserPluginGuest::OnDragStatusUpdate(int instance_id, } } +void BrowserPluginGuest::OnExecuteEditCommand(int instance_id, + const std::string& name) { + Send(new InputMsg_ExecuteEditCommand(routing_id(), name, std::string())); +} + void BrowserPluginGuest::OnGo(int instance_id, int relative_index) { GetWebContents()->GetController().GoToOffset(relative_index); } @@ -866,12 +891,12 @@ void BrowserPluginGuest::OnHandleInputEvent( } if (WebKit::WebInputEvent::isKeyboardEventType(event->type)) { - NativeWebKeyboardEvent keyboard_event; - const WebKit::WebKeyboardEvent* original_event = - static_cast<const WebKit::WebKeyboardEvent*>(event); - memcpy(&keyboard_event, original_event, sizeof(WebKit::WebKeyboardEvent)); - if (keyboard_event.type == WebKit::WebInputEvent::KeyDown) - keyboard_event.type = WebKit::WebInputEvent::RawKeyDown; + RenderViewHostImpl* embedder_rvh = static_cast<RenderViewHostImpl*>( + embedder_web_contents_->GetRenderViewHost()); + if (!embedder_rvh->GetLastKeyboardEvent()) + return; + NativeWebKeyboardEvent keyboard_event( + *embedder_rvh->GetLastKeyboardEvent()); guest_rvh->ForwardKeyboardEvent(keyboard_event); return; } diff --git a/content/browser/browser_plugin/browser_plugin_guest.h b/content/browser/browser_plugin/browser_plugin_guest.h index 526d183..7fd03c4 100644 --- a/content/browser/browser_plugin/browser_plugin_guest.h +++ b/content/browser/browser_plugin/browser_plugin_guest.h @@ -79,9 +79,11 @@ struct MediaStreamRequest; // A BrowserPluginGuest can also create a new unattached guest via // CreateNewWindow. The newly created guest will live in the same partition, // which means it can share storage and can script this guest. -class CONTENT_EXPORT BrowserPluginGuest : public NotificationObserver, - public WebContentsDelegate, - public WebContentsObserver { +class CONTENT_EXPORT BrowserPluginGuest + : public NotificationObserver, + public WebContentsDelegate, + public WebContentsObserver, + public base::SupportsWeakPtr<BrowserPluginGuest> { public: typedef base::Callback<void(bool)> GeolocationCallback; virtual ~BrowserPluginGuest(); @@ -182,6 +184,9 @@ class CONTENT_EXPORT BrowserPluginGuest : public NotificationObserver, const std::string& request_method, const base::Callback<void(bool)>& callback) OVERRIDE; virtual bool HandleContextMenu(const ContextMenuParams& params) OVERRIDE; + virtual void HandleKeyboardEvent( + WebContents* source, + const NativeWebKeyboardEvent& event) OVERRIDE; virtual void WebContentsCreated(WebContents* source_contents, int64 source_frame_id, const string16& frame_name, @@ -303,6 +308,9 @@ class CONTENT_EXPORT BrowserPluginGuest : public NotificationObserver, const WebDropData& drop_data, WebKit::WebDragOperationsMask drag_mask, const gfx::Point& location); + // Instructs the guest to execute an edit command decoded in the embedder. + void OnExecuteEditCommand(int instance_id, + const std::string& command); // If possible, navigate the guest to |relative_index| entries away from the // current navigation entry. virtual void OnGo(int instance_id, int relative_index); @@ -440,7 +448,7 @@ class CONTENT_EXPORT BrowserPluginGuest : public NotificationObserver, typedef std::map<BrowserPluginGuest*, std::string> PendingWindowMap; PendingWindowMap pending_new_windows_; - BrowserPluginGuest* opener_; + base::WeakPtr<BrowserPluginGuest> opener_; // A counter to generate a unique request id for a permission request. // We only need the ids to be unique for a given BrowserPluginGuest. int next_permission_request_id_; diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 036e641..d988126 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc @@ -1255,6 +1255,13 @@ void RenderWidgetHostImpl::GetWebScreenInfo(WebKit::WebScreenInfo* result) { RenderWidgetHostViewPort::GetDefaultScreenInfo(result); } +const NativeWebKeyboardEvent* + RenderWidgetHostImpl::GetLastKeyboardEvent() const { + if (key_queue_.empty()) + return NULL; + return &key_queue_.front(); +} + void RenderWidgetHostImpl::NotifyScreenInfoChanged() { WebKit::WebScreenInfo screen_info; GetWebScreenInfo(&screen_info); diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index dc13dd8..b8ad8bc 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h @@ -157,6 +157,8 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, const gfx::Rect& src_subrect, const base::Callback<void(bool, const SkBitmap&)>& callback) OVERRIDE; + const NativeWebKeyboardEvent* GetLastKeyboardEvent() const; + // Notification that the screen info has changed. void NotifyScreenInfoChanged(); diff --git a/content/common/browser_plugin/browser_plugin_messages.h b/content/common/browser_plugin/browser_plugin_messages.h index 2d97618..00deebe 100644 --- a/content/common/browser_plugin/browser_plugin_messages.h +++ b/content/common/browser_plugin/browser_plugin_messages.h @@ -146,6 +146,12 @@ IPC_STRUCT_END() IPC_MESSAGE_ROUTED1(BrowserPluginHostMsg_AllocateInstanceID, int /* request_id */) +// This message is sent from BrowserPlugin to BrowserPluginGuest to issue an +// edit command. +IPC_MESSAGE_ROUTED2(BrowserPluginHostMsg_ExecuteEditCommand, + int /* instance_id */, + std::string /* command */) + // This message is sent to the browser process to enable or disable autosize // mode. IPC_MESSAGE_ROUTED3( diff --git a/content/renderer/browser_plugin/browser_plugin.cc b/content/renderer/browser_plugin/browser_plugin.cc index 2a5d9e8..c064f6c 100644 --- a/content/renderer/browser_plugin/browser_plugin.cc +++ b/content/renderer/browser_plugin/browser_plugin.cc @@ -52,25 +52,6 @@ namespace content { namespace { -static bool shouldIgnoreKeyBoardEvent(const WebKit::WebKeyboardEvent* event) { - if (event->type == WebKit::WebInputEvent::Char) - return false; - int keycode = event->windowsKeyCode; - if (keycode == ui::VKEY_SHIFT || - keycode == ui::VKEY_CONTROL || - keycode == ui::VKEY_MENU || - keycode == ui::VKEY_LWIN) // The search key on chromeOS. - return true; - // We don't want to handle keys like volume control, or app launchers inside - // of BrowserPlugin. These keys should be handled either by the browser, or - // the OS. - if ((keycode >= ui::VKEY_BROWSER_BACK && - keycode <= ui::VKEY_MEDIA_LAUNCH_APP2) || - (keycode >= ui::VKEY_F1 && keycode <= ui::VKEY_F24)) - return true; - return false; -} - static std::string TerminationStatusToString(base::TerminationStatus status) { switch (status) { case base::TERMINATION_STATUS_NORMAL_TERMINATION: @@ -1446,16 +1427,6 @@ bool BrowserPlugin::handleInputEvent(const WebKit::WebInputEvent& event, event.type == WebKit::WebInputEvent::ContextMenu) return false; - if (WebKit::WebInputEvent::isKeyboardEventType(event.type)) { - // TODO(mthiesse): This is a temporary solution for BrowserPlugin capturing - // keys like the search key on chromeOS. The guest should be allowed to - // handle these key events (as javascript allows this), so a better solution - // is needed. - if (shouldIgnoreKeyBoardEvent( - static_cast<const WebKit::WebKeyboardEvent*>(&event))) - return false; - } - const WebKit::WebInputEvent* modified_event = &event; scoped_ptr<WebKit::WebTouchEvent> touch_event; // WebKit gives BrowserPlugin a list of touches that are down, but the browser @@ -1524,6 +1495,16 @@ void BrowserPlugin::didFailLoadingFrameRequest( const WebKit::WebURLError& error) { } +bool BrowserPlugin::executeEditCommand(const WebKit::WebString& name) { + browser_plugin_manager()->Send(new BrowserPluginHostMsg_ExecuteEditCommand( + render_view_routing_id_, + instance_id_, + name.utf8())); + + // BrowserPlugin swallows edit commands. + return true; +} + void BrowserPlugin::OnLockMouseACK(bool succeeded) { browser_plugin_manager()->Send(new BrowserPluginHostMsg_LockMouse_ACK( render_view_routing_id_, diff --git a/content/renderer/browser_plugin/browser_plugin.h b/content/renderer/browser_plugin/browser_plugin.h index defe4fc..d49058d 100644 --- a/content/renderer/browser_plugin/browser_plugin.h +++ b/content/renderer/browser_plugin/browser_plugin.h @@ -203,6 +203,7 @@ class CONTENT_EXPORT BrowserPlugin : const WebKit::WebURL& url, void* notify_data, const WebKit::WebURLError& error) OVERRIDE; + virtual bool executeEditCommand(const WebKit::WebString& name) OVERRIDE; // MouseLockDispatcher::LockTarget implementation. virtual void OnLockMouseACK(bool succeeded) OVERRIDE; diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 6f0a219..e0543f2 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc @@ -1379,8 +1379,10 @@ void RenderViewImpl::OnCopy() { return; base::AutoReset<bool> handling_select_range(&handling_select_range_, true); + WebNode current_node = context_menu_node_.isNull() ? + GetFocusedNode() : context_menu_node_; webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Copy"), - context_menu_node_); + current_node); } void RenderViewImpl::OnCut() { @@ -1388,14 +1390,16 @@ void RenderViewImpl::OnCut() { return; base::AutoReset<bool> handling_select_range(&handling_select_range_, true); - webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Cut")); + webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Cut"), + GetFocusedNode()); } void RenderViewImpl::OnDelete() { if (!webview()) return; - webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Delete")); + webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Delete"), + GetFocusedNode()); } void RenderViewImpl::OnExecuteEditCommand(const std::string& name, @@ -1421,7 +1425,8 @@ void RenderViewImpl::OnPaste() { return; base::AutoReset<bool> handling_select_range(&handling_select_range_, true); - webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Paste")); + webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Paste"), + GetFocusedNode()); } void RenderViewImpl::OnPasteAndMatchStyle() { @@ -1430,14 +1435,15 @@ void RenderViewImpl::OnPasteAndMatchStyle() { base::AutoReset<bool> handling_select_range(&handling_select_range_, true); webview()->focusedFrame()->executeCommand( - WebString::fromUTF8("PasteAndMatchStyle")); + WebString::fromUTF8("PasteAndMatchStyle"), GetFocusedNode()); } void RenderViewImpl::OnRedo() { if (!webview()) return; - webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Redo")); + webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Redo"), + GetFocusedNode()); } void RenderViewImpl::OnReplace(const string16& text) { @@ -1479,7 +1485,7 @@ void RenderViewImpl::OnSelectAll() { base::AutoReset<bool> handling_select_range(&handling_select_range_, true); webview()->focusedFrame()->executeCommand( - WebString::fromUTF8("SelectAll")); + WebString::fromUTF8("SelectAll"), GetFocusedNode()); } void RenderViewImpl::OnSelectRange(const gfx::Point& start, @@ -1502,7 +1508,8 @@ void RenderViewImpl::OnUndo() { if (!webview()) return; - webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Undo")); + webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Undo"), + GetFocusedNode()); } void RenderViewImpl::OnUnselect() { @@ -1510,7 +1517,8 @@ void RenderViewImpl::OnUnselect() { return; base::AutoReset<bool> handling_select_range(&handling_select_range_, true); - webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Unselect")); + webview()->focusedFrame()->executeCommand(WebString::fromUTF8("Unselect"), + GetFocusedNode()); } #if defined(OS_MACOSX) @@ -4806,7 +4814,8 @@ void RenderViewImpl::OnFind(int request_id, if (!result) { // don't leave text selected as you move to the next frame. - search_frame->executeCommand(WebString::fromUTF8("Unselect")); + search_frame->executeCommand(WebString::fromUTF8("Unselect"), + GetFocusedNode()); // Find the next frame, but skip the invisible ones. do { @@ -4819,7 +4828,8 @@ void RenderViewImpl::OnFind(int request_id, search_frame != focused_frame); // Make sure selection doesn't affect the search operation in new frame. - search_frame->executeCommand(WebString::fromUTF8("Unselect")); + search_frame->executeCommand(WebString::fromUTF8("Unselect"), + GetFocusedNode()); // If we have multiple frames and we have wrapped back around to the // focused frame, we need to search it once more allowing wrap within @@ -4892,8 +4902,10 @@ void RenderViewImpl::OnStopFinding(StopFindAction action) { } bool clear_selection = action == STOP_FIND_ACTION_CLEAR_SELECTION; - if (clear_selection) - view->focusedFrame()->executeCommand(WebString::fromUTF8("Unselect")); + if (clear_selection) { + view->focusedFrame()->executeCommand(WebString::fromUTF8("Unselect"), + GetFocusedNode()); + } WebFrame* frame = view->mainFrame(); while (frame) { |