diff options
author | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-31 21:41:08 +0000 |
---|---|---|
committer | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-31 21:41:08 +0000 |
commit | b29aa74b75d57e1dc78bb151f1b7b2153d13ae3f (patch) | |
tree | c06576af8874b736101b045e4e1d75cfed7ba897 | |
parent | 314e594492cfd5c23225763cb46c5cd190b5551c (diff) | |
download | chromium_src-b29aa74b75d57e1dc78bb151f1b7b2153d13ae3f.zip chromium_src-b29aa74b75d57e1dc78bb151f1b7b2153d13ae3f.tar.gz chromium_src-b29aa74b75d57e1dc78bb151f1b7b2153d13ae3f.tar.bz2 |
Pepper/Flapper: First pass at context menu implementation.
This meets the needs of Flapper. We may want to generalize/restrict/modify the
API for inclusion into PPAPI, but hopefully this lays a foundation.
BUG=none
TEST=Flapper context menus work (with the right version of Flapper)
Review URL: http://codereview.chromium.org/6253017
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@73193 0039d316-1c4b-4281-b951-d872f2087c98
32 files changed, 853 insertions, 128 deletions
diff --git a/chrome/browser/renderer_host/pepper_message_filter.cc b/chrome/browser/renderer_host/pepper_message_filter.cc index 2090667..5558cb3 100644 --- a/chrome/browser/renderer_host/pepper_message_filter.cc +++ b/chrome/browser/renderer_host/pepper_message_filter.cc @@ -42,8 +42,8 @@ bool PepperMessageFilter::OnMessageReceived(const IPC::Message& msg, #if defined(ENABLE_FLAPPER_HACKS) bool handled = true; IPC_BEGIN_MESSAGE_MAP_EX(PepperMessageFilter, msg, *message_was_ok) - IPC_MESSAGE_HANDLER(PepperMsg_ConnectTcp, OnPepperConnectTcp) - IPC_MESSAGE_HANDLER(PepperMsg_ConnectTcpAddress, OnPepperConnectTcpAddress) + IPC_MESSAGE_HANDLER(PepperMsg_ConnectTcp, OnConnectTcp) + IPC_MESSAGE_HANDLER(PepperMsg_ConnectTcpAddress, OnConnectTcpAddress) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP_EX() return handled; @@ -143,7 +143,7 @@ class PepperMessageFilter::LookupRequest { private: void OnLookupFinished(int /*result*/) { - pepper_message_filter_->PepperConnectTcpLookupFinished( + pepper_message_filter_->ConnectTcpLookupFinished( routing_id_, request_id_, addresses_); delete this; } @@ -163,11 +163,10 @@ class PepperMessageFilter::LookupRequest { DISALLOW_COPY_AND_ASSIGN(LookupRequest); }; -void PepperMessageFilter::OnPepperConnectTcp( - int routing_id, - int request_id, - const std::string& host, - uint16 port) { +void PepperMessageFilter::OnConnectTcp(int routing_id, + int request_id, + const std::string& host, + uint16 port) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); net::URLRequestContext* req_context = @@ -181,10 +180,9 @@ void PepperMessageFilter::OnPepperConnectTcp( lookup_request->Start(); } -void PepperMessageFilter::OnPepperConnectTcpAddress( - int routing_id, - int request_id, - const PP_Flash_NetAddress& addr) { +void PepperMessageFilter::OnConnectTcpAddress(int routing_id, + int request_id, + const PP_Flash_NetAddress& addr) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); // Validate the address and then continue (doing |connect()|) on a worker @@ -193,22 +191,22 @@ void PepperMessageFilter::OnPepperConnectTcpAddress( !base::WorkerPool::PostTask(FROM_HERE, NewRunnableMethod( this, - &PepperMessageFilter::PepperConnectTcpAddressOnWorkerThread, + &PepperMessageFilter::ConnectTcpAddressOnWorkerThread, routing_id, request_id, addr), true)) { - SendPepperConnectTcpACKError(routing_id, request_id); + SendConnectTcpACKError(routing_id, request_id); } } -bool PepperMessageFilter::SendPepperConnectTcpACKError(int routing_id, - int request_id) { +bool PepperMessageFilter::SendConnectTcpACKError(int routing_id, + int request_id) { return Send( new PepperMsg_ConnectTcpACK(routing_id, request_id, IPC::InvalidPlatformFileForTransit(), kInvalidNetAddress, kInvalidNetAddress)); } -void PepperMessageFilter::PepperConnectTcpLookupFinished( +void PepperMessageFilter::ConnectTcpLookupFinished( int routing_id, int request_id, const net::AddressList& addresses) { @@ -220,17 +218,16 @@ void PepperMessageFilter::PepperConnectTcpLookupFinished( !base::WorkerPool::PostTask(FROM_HERE, NewRunnableMethod( this, - &PepperMessageFilter::PepperConnectTcpOnWorkerThread, + &PepperMessageFilter::ConnectTcpOnWorkerThread, routing_id, request_id, addresses), true)) { - SendPepperConnectTcpACKError(routing_id, request_id); + SendConnectTcpACKError(routing_id, request_id); } } -void PepperMessageFilter::PepperConnectTcpOnWorkerThread( - int routing_id, - int request_id, - net::AddressList addresses) { +void PepperMessageFilter::ConnectTcpOnWorkerThread(int routing_id, + int request_id, + net::AddressList addresses) { DCHECK(!MessageLoop::current()); // Check we are on a worker thread. IPC::PlatformFileForTransit socket_for_transit = @@ -257,8 +254,8 @@ void PepperMessageFilter::PepperConnectTcpOnWorkerThread( } // TODO(vluu): Eliminate duplication between this and -// |PepperConnectTcpOnWorkerThread()|. -void PepperMessageFilter::PepperConnectTcpAddressOnWorkerThread( +// |ConnectTcpOnWorkerThread()|. +void PepperMessageFilter::ConnectTcpAddressOnWorkerThread( int routing_id, int request_id, PP_Flash_NetAddress addr) { diff --git a/chrome/browser/renderer_host/pepper_message_filter.h b/chrome/browser/renderer_host/pepper_message_filter.h index ec36c08..d907361 100644 --- a/chrome/browser/renderer_host/pepper_message_filter.h +++ b/chrome/browser/renderer_host/pepper_message_filter.h @@ -31,34 +31,34 @@ class PepperMessageFilter : public BrowserMessageFilter { #if defined(ENABLE_FLAPPER_HACKS) // Message handlers. - void OnPepperConnectTcp(int routing_id, - int request_id, - const std::string& host, - uint16 port); - void OnPepperConnectTcpAddress(int routing_id, - int request_id, - const PP_Flash_NetAddress& address); + void OnConnectTcp(int routing_id, + int request_id, + const std::string& host, + uint16 port); + void OnConnectTcpAddress(int routing_id, + int request_id, + const PP_Flash_NetAddress& address); - // |Send()| a |ViewMsg_PepperConnectTcpACK|, which reports an error. - bool SendPepperConnectTcpACKError(int routing_id, - int request_id); + // |Send()| a |PepperMsg_ConnectTcpACK|, which reports an error. + bool SendConnectTcpACKError(int routing_id, + int request_id); - // Used by |OnPepperConnectTcp()| (below). + // Used by |OnConnectTcp()| (below). class LookupRequest; friend class LookupRequest; - // Continuation of |OnPepperConnectTcp()|. - void PepperConnectTcpLookupFinished(int routing_id, - int request_id, - const net::AddressList& addresses); - void PepperConnectTcpOnWorkerThread(int routing_id, - int request_id, - net::AddressList addresses); + // Continuation of |OnConnectTcp()|. + void ConnectTcpLookupFinished(int routing_id, + int request_id, + const net::AddressList& addresses); + void ConnectTcpOnWorkerThread(int routing_id, + int request_id, + net::AddressList addresses); - // Continuation of |OnPepperConnectTcpAddress()|. - void PepperConnectTcpAddressOnWorkerThread(int routing_id, - int request_id, - PP_Flash_NetAddress addr); + // Continuation of |OnConnectTcpAddress()|. + void ConnectTcpAddressOnWorkerThread(int routing_id, + int request_id, + PP_Flash_NetAddress addr); #endif // ENABLE_FLAPPER_HACKS Profile* profile_; diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index 7378720..b5ea89e 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -1246,8 +1246,9 @@ void RenderViewHost::MediaPlayerActionAt(const gfx::Point& location, Send(new ViewMsg_MediaPlayerActionAt(routing_id(), location, action)); } -void RenderViewHost::ContextMenuClosed() { - Send(new ViewMsg_ContextMenuClosed(routing_id())); +void RenderViewHost::ContextMenuClosed( + const webkit_glue::CustomContextMenuContext& custom_context) { + Send(new ViewMsg_ContextMenuClosed(routing_id(), custom_context)); } void RenderViewHost::PrintNodeUnderContextMenu() { @@ -1500,8 +1501,12 @@ void RenderViewHost::UpdateBrowserWindowId(int window_id) { Send(new ViewMsg_UpdateBrowserWindowId(routing_id(), window_id)); } -void RenderViewHost::PerformCustomContextMenuAction(unsigned action) { - Send(new ViewMsg_CustomContextMenuAction(routing_id(), action)); +void RenderViewHost::PerformCustomContextMenuAction( + const webkit_glue::CustomContextMenuContext& custom_context, + unsigned action) { + Send(new ViewMsg_CustomContextMenuAction(routing_id(), + custom_context, + action)); } void RenderViewHost::SendContentSettings(const GURL& url, diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h index df00cb1..9c1b81d 100644 --- a/chrome/browser/renderer_host/render_view_host.h +++ b/chrome/browser/renderer_host/render_view_host.h @@ -58,6 +58,7 @@ class Point; } // namespace gfx namespace webkit_glue { +struct CustomContextMenuContext; struct WebAccessibility; } // namespace webkit_glue @@ -318,7 +319,8 @@ class RenderViewHost : public RenderWidgetHost { const WebKit::WebMediaPlayerAction& action); // Notifies the renderer that the context menu has closed. - void ContextMenuClosed(); + void ContextMenuClosed( + const webkit_glue::CustomContextMenuContext& custom_context); // Prints the node that's under the context menu. void PrintNodeUnderContextMenu(); @@ -462,7 +464,9 @@ class RenderViewHost : public RenderWidgetHost { void UpdateBrowserWindowId(int window_id); // Tells the render view that a custom context action has been selected. - void PerformCustomContextMenuAction(unsigned action); + void PerformCustomContextMenuAction( + const webkit_glue::CustomContextMenuContext& custom_context, + unsigned action); // Informs renderer of updated content settings. void SendContentSettings(const GURL& url, diff --git a/chrome/browser/tab_contents/render_view_context_menu.cc b/chrome/browser/tab_contents/render_view_context_menu.cc index 0339888..2bd6ff1 100644 --- a/chrome/browser/tab_contents/render_view_context_menu.cc +++ b/chrome/browser/tab_contents/render_view_context_menu.cc @@ -60,6 +60,98 @@ using WebKit::WebContextMenuData; using WebKit::WebMediaPlayerAction; +namespace { + +bool IsCustomItemEnabled(const std::vector<WebMenuItem>& items, int id) { + DCHECK(id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST && + id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST); + for (size_t i = 0; i < items.size(); ++i) { + int action_id = IDC_CONTENT_CONTEXT_CUSTOM_FIRST + items[i].action; + if (action_id == id) + return items[i].enabled; + if (items[i].type == WebMenuItem::SUBMENU) { + if (IsCustomItemEnabled(items[i].submenu, id)) + return true; + } + } + return false; +} + +bool IsCustomItemChecked(const std::vector<WebMenuItem>& items, int id) { + DCHECK(id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST && + id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST); + for (size_t i = 0; i < items.size(); ++i) { + int action_id = IDC_CONTENT_CONTEXT_CUSTOM_FIRST + items[i].action; + if (action_id == id) + return items[i].checked; + if (items[i].type == WebMenuItem::SUBMENU) { + if (IsCustomItemChecked(items[i].submenu, id)) + return true; + } + } + return false; +} + +const size_t kMaxCustomMenuDepth = 5; +const size_t kMaxCustomMenuTotalItems = 1000; + +void AddCustomItemsToMenu(const std::vector<WebMenuItem>& items, + size_t depth, + size_t* total_items, + ui::SimpleMenuModel::Delegate* delegate, + ui::SimpleMenuModel* menu_model) { + if (depth > kMaxCustomMenuDepth) { + LOG(ERROR) << "Custom menu too deeply nested."; + return; + } + for (size_t i = 0; i < items.size(); ++i) { + if (IDC_CONTENT_CONTEXT_CUSTOM_FIRST + items[i].action >= + IDC_CONTENT_CONTEXT_CUSTOM_LAST) { + LOG(ERROR) << "Custom menu action value too big."; + return; + } + if (*total_items >= kMaxCustomMenuTotalItems) { + LOG(ERROR) << "Custom menu too large (too many items)."; + return; + } + (*total_items)++; + switch (items[i].type) { + case WebMenuItem::OPTION: + menu_model->AddItem( + items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST, + items[i].label); + break; + case WebMenuItem::CHECKABLE_OPTION: + menu_model->AddCheckItem( + items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST, + items[i].label); + break; + case WebMenuItem::GROUP: + // TODO(viettrungluu): I don't know what this is supposed to do. + NOTREACHED(); + break; + case WebMenuItem::SEPARATOR: + menu_model->AddSeparator(); + break; + case WebMenuItem::SUBMENU: { + ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate); + AddCustomItemsToMenu(items[i].submenu, depth + 1, total_items, delegate, + submenu); + menu_model->AddSubMenu( + items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST, + items[i].label, + submenu); + break; + } + default: + NOTREACHED(); + break; + } + } +} + +} // namespace + // static const size_t RenderViewContextMenu::kMaxExtensionItemTitleLength = 75; // static @@ -358,7 +450,9 @@ void RenderViewContextMenu::InitMenu() { bool has_selection = !params_.selection_text.empty(); if (AppendCustomItems()) { - AppendDeveloperItems(); + // Don't add items for Pepper menu. + if (!params_.custom_context.is_pepper_menu) + AppendDeveloperItems(); return; } @@ -424,23 +518,10 @@ void RenderViewContextMenu::LookUpInDictionary() { } bool RenderViewContextMenu::AppendCustomItems() { - std::vector<WebMenuItem>& custom_items = params_.custom_items; - for (size_t i = 0; i < custom_items.size(); ++i) { - DCHECK(IDC_CONTENT_CONTEXT_CUSTOM_FIRST + custom_items[i].action < - IDC_CONTENT_CONTEXT_CUSTOM_LAST); - if (custom_items[i].type == WebMenuItem::SEPARATOR) { - menu_model_.AddSeparator(); - } else if (custom_items[i].type == WebMenuItem::CHECKABLE_OPTION) { - menu_model_.AddCheckItem( - custom_items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST, - custom_items[i].label); - } else { - menu_model_.AddItem( - custom_items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST, - custom_items[i].label); - } - } - return custom_items.size() > 0; + size_t total_items = 0; + AddCustomItemsToMenu(params_.custom_items, 0, &total_items, this, + &menu_model_); + return total_items > 0; } void RenderViewContextMenu::AppendDeveloperItems() { @@ -773,28 +854,10 @@ bool RenderViewContextMenu::IsCommandIdEnabled(int id) const { return profile_->GetPrefs()->GetBoolean(prefs::kEnableSpellCheck); } - // Process custom actions range. - if ((id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST) && - (id < IDC_CONTENT_CONTEXT_CUSTOM_LAST)) { - unsigned action = id - IDC_CONTENT_CONTEXT_CUSTOM_FIRST; - for (size_t i = 0; i < params_.custom_items.size(); ++i) { - if (params_.custom_items[i].action == action) - return params_.custom_items[i].enabled; - } - NOTREACHED(); - return false; - } - - // Custom WebKit items. + // Custom items. if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST && id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) { - const std::vector<WebMenuItem>& custom_items = params_.custom_items; - for (size_t i = 0; i < custom_items.size(); ++i) { - int action_id = IDC_CONTENT_CONTEXT_CUSTOM_FIRST + custom_items[i].action; - if (action_id == id) - return custom_items[i].enabled; - } - return true; + return IsCustomItemEnabled(params_.custom_items, id); } // Extension items. @@ -1020,16 +1083,10 @@ bool RenderViewContextMenu::IsCommandIdChecked(int id) const { WebContextMenuData::MediaControls) != 0; } - // Custom WebKit items. + // Custom items. if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST && id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) { - const std::vector<WebMenuItem>& custom_items = params_.custom_items; - for (size_t i = 0; i < custom_items.size(); ++i) { - int action_id = IDC_CONTENT_CONTEXT_CUSTOM_FIRST + custom_items[i].action; - if (action_id == id) - return custom_items[i].checked; - } - return false; + return IsCustomItemChecked(params_.custom_items, id); } // Extension items. @@ -1090,11 +1147,11 @@ void RenderViewContextMenu::ExecuteCommand(int id) { } // Process custom actions range. - if ((id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST) && - (id < IDC_CONTENT_CONTEXT_CUSTOM_LAST)) { + if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST && + id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) { unsigned action = id - IDC_CONTENT_CONTEXT_CUSTOM_FIRST; - source_tab_contents_->render_view_host()-> - PerformCustomContextMenuAction(action); + source_tab_contents_->render_view_host()->PerformCustomContextMenuAction( + params_.custom_context, action); return; } @@ -1399,7 +1456,8 @@ void RenderViewContextMenu::ExecuteCommand(int id) { } void RenderViewContextMenu::MenuClosed() { - source_tab_contents_->render_view_host()->ContextMenuClosed(); + source_tab_contents_->render_view_host()->ContextMenuClosed( + params_.custom_context); } bool RenderViewContextMenu::IsDevCommandEnabled(int id) const { diff --git a/chrome/common/render_messages.cc b/chrome/common/render_messages.cc index d872fec..28d8f90 100644 --- a/chrome/common/render_messages.cc +++ b/chrome/common/render_messages.cc @@ -55,12 +55,18 @@ struct ParamTraits<WebMenuItem::Type> { case WebMenuItem::OPTION: type = "OPTION"; break; + case WebMenuItem::CHECKABLE_OPTION: + type = "CHECKABLE_OPTION"; + break; case WebMenuItem::GROUP: type = "GROUP"; break; case WebMenuItem::SEPARATOR: type = "SEPARATOR"; break; + case WebMenuItem::SUBMENU: + type = "SUBMENU"; + break; default: type = "UNKNOWN"; break; @@ -78,9 +84,9 @@ void ParamTraits<FontDescriptor>::Write(Message* m, const param_type& p) { bool ParamTraits<FontDescriptor>::Read(const Message* m, void** iter, param_type* p) { - return( + return ReadParam(m, iter, &p->font_name) && - ReadParam(m, iter, &p->font_point_size)); + ReadParam(m, iter, &p->font_point_size); } void ParamTraits<FontDescriptor>::Log(const param_type& p, std::string* l) { @@ -88,6 +94,31 @@ void ParamTraits<FontDescriptor>::Log(const param_type& p, std::string* l) { } #endif +void ParamTraits<webkit_glue::CustomContextMenuContext>::Write( + Message* m, + const param_type& p) { + WriteParam(m, p.is_pepper_menu); + WriteParam(m, p.request_id); +} + +bool ParamTraits<webkit_glue::CustomContextMenuContext>::Read(const Message* m, + void** iter, + param_type* p) { + return + ReadParam(m, iter, &p->is_pepper_menu) && + ReadParam(m, iter, &p->request_id); +} + +void ParamTraits<webkit_glue::CustomContextMenuContext>::Log( + const param_type& p, + std::string* l) { + l->append("("); + LogParam(p.is_pepper_menu, l); + l->append(", "); + LogParam(p.request_id, l); + l->append(")"); +} + void ParamTraits<ContextMenuParams>::Write(Message* m, const param_type& p) { WriteParam(m, p.media_type); WriteParam(m, p.x); @@ -112,6 +143,7 @@ void ParamTraits<ContextMenuParams>::Write(Message* m, const param_type& p) { WriteParam(m, p.edit_flags); WriteParam(m, p.security_info); WriteParam(m, p.frame_charset); + WriteParam(m, p.custom_context); WriteParam(m, p.custom_items); } @@ -141,6 +173,7 @@ bool ParamTraits<ContextMenuParams>::Read(const Message* m, void** iter, ReadParam(m, iter, &p->edit_flags) && ReadParam(m, iter, &p->security_info) && ReadParam(m, iter, &p->frame_charset) && + ReadParam(m, iter, &p->custom_context) && ReadParam(m, iter, &p->custom_items); } @@ -742,6 +775,7 @@ void ParamTraits<WebMenuItem>::Write(Message* m, const param_type& p) { WriteParam(m, p.enabled); WriteParam(m, p.checked); WriteParam(m, p.action); + WriteParam(m, p.submenu); } bool ParamTraits<WebMenuItem>::Read(const Message* m, @@ -752,7 +786,8 @@ bool ParamTraits<WebMenuItem>::Read(const Message* m, ReadParam(m, iter, &p->type) && ReadParam(m, iter, &p->enabled) && ReadParam(m, iter, &p->checked) && - ReadParam(m, iter, &p->action); + ReadParam(m, iter, &p->action) && + ReadParam(m, iter, &p->submenu); } void ParamTraits<WebMenuItem>::Log(const param_type& p, std::string* l) { @@ -766,6 +801,8 @@ void ParamTraits<WebMenuItem>::Log(const param_type& p, std::string* l) { LogParam(p.checked, l); l->append(", "); LogParam(p.action, l); + l->append(", "); + LogParam(p.submenu, l); l->append(")"); } diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index 6e5959a..2e94d53 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h @@ -49,6 +49,7 @@ class BlobData; } namespace webkit_glue { +struct CustomContextMenuContext; struct ResourceDevToolsInfo; struct ResourceLoadTimingInfo; struct ResourceResponseInfo; @@ -144,6 +145,14 @@ struct ParamTraits<FontDescriptor> { #endif template <> +struct ParamTraits<webkit_glue::CustomContextMenuContext> { + typedef webkit_glue::CustomContextMenuContext param_type; + static void Write(Message* m, const param_type& p); + static bool Read(const Message* m, void** iter, param_type* p); + static void Log(const param_type& p, std::string* l); +}; + +template <> struct ParamTraits<ContextMenuParams> { typedef ContextMenuParams param_type; static void Write(Message* m, const param_type& p); diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index ba33f36..466f619 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -955,7 +955,8 @@ IPC_MESSAGE_CONTROL1(ViewMsg_SpellChecker_EnableAutoSpellCorrect, bool /* enable */) // Executes custom context menu action that was provided from WebKit. -IPC_MESSAGE_ROUTED1(ViewMsg_CustomContextMenuAction, +IPC_MESSAGE_ROUTED2(ViewMsg_CustomContextMenuAction, + webkit_glue::CustomContextMenuContext /* custom_context */, unsigned /* action */) // Tells the renderer to translate the page contents from one language to @@ -1057,7 +1058,8 @@ IPC_MESSAGE_CONTROL1(ViewMsg_SpeechInput_SetFeatureEnabled, // Sent in response to a ViewHostMsg_ContextMenu to let the renderer know that // the menu has been closed. -IPC_MESSAGE_ROUTED0(ViewMsg_ContextMenuClosed) +IPC_MESSAGE_ROUTED1(ViewMsg_ContextMenuClosed, + webkit_glue::CustomContextMenuContext /* custom_context */) //----------------------------------------------------------------------------- // TabContents messages diff --git a/chrome/renderer/blocked_plugin.cc b/chrome/renderer/blocked_plugin.cc index 69e6f18..3133873 100644 --- a/chrome/renderer/blocked_plugin.cc +++ b/chrome/renderer/blocked_plugin.cc @@ -148,7 +148,9 @@ bool BlockedPlugin::OnMessageReceived(const IPC::Message& message) { return false; } -void BlockedPlugin::OnMenuItemSelected(unsigned id) { +void BlockedPlugin::OnMenuItemSelected( + const webkit_glue::CustomContextMenuContext& /* ignored */, + unsigned id) { if (id == kMenuActionLoad) { LoadPlugin(); } else if (id == kMenuActionRemove) { diff --git a/chrome/renderer/blocked_plugin.h b/chrome/renderer/blocked_plugin.h index 44e6699..eecff79 100644 --- a/chrome/renderer/blocked_plugin.h +++ b/chrome/renderer/blocked_plugin.h @@ -19,6 +19,10 @@ class PluginGroup; } } +namespace webkit_glue { +struct CustomContextMenuContext; +} + class BlockedPlugin : public RenderViewObserver, public CppBoundClass, public webkit::npapi::WebViewPlugin::Delegate { @@ -45,7 +49,9 @@ class BlockedPlugin : public RenderViewObserver, // RenderViewObserver methods: virtual bool OnMessageReceived(const IPC::Message& message); - void OnMenuItemSelected(unsigned id); + void OnMenuItemSelected( + const webkit_glue::CustomContextMenuContext& /* ignored */, + unsigned id); // Load the blocked plugin. void LoadPlugin(); diff --git a/chrome/renderer/pepper_plugin_delegate_impl.cc b/chrome/renderer/pepper_plugin_delegate_impl.cc index e6d7124..2d3a23e 100644 --- a/chrome/renderer/pepper_plugin_delegate_impl.cc +++ b/chrome/renderer/pepper_plugin_delegate_impl.cc @@ -35,6 +35,7 @@ #include "grit/locale_settings.h" #include "ipc/ipc_channel_handle.h" #include "ppapi/c/dev/pp_video_dev.h" +#include "ppapi/c/pp_errors.h" #include "ppapi/c/private/ppb_flash.h" #include "ppapi/proxy/host_dispatcher.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFileChooserCompletion.h" @@ -43,6 +44,7 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" #include "ui/base/l10n/l10n_util.h" #include "webkit/fileapi/file_system_callback_dispatcher.h" +#include "webkit/glue/context_menu.h" #include "webkit/plugins/npapi/webplugin.h" #include "webkit/plugins/ppapi/ppb_file_io_impl.h" #include "webkit/plugins/ppapi/plugin_module.h" @@ -376,6 +378,8 @@ bool DispatcherWrapper::Init( PepperPluginDelegateImpl::PepperPluginDelegateImpl(RenderView* render_view) : render_view_(render_view), + has_saved_context_menu_action_(false), + saved_context_menu_action_(0), id_generator_(0) { } @@ -818,8 +822,10 @@ int32_t PepperPluginDelegateImpl::ConnectTcp( request_id, std::string(host), port); - if (!render_view_->Send(msg)) + if (!render_view_->Send(msg)) { + pending_connect_tcps_.Remove(request_id); return PP_ERROR_FAILED; + } return PP_ERROR_WOULDBLOCK; } @@ -833,8 +839,10 @@ int32_t PepperPluginDelegateImpl::ConnectTcpAddress( new PepperMsg_ConnectTcpAddress(render_view_->routing_id(), request_id, *addr); - if (!render_view_->Send(msg)) + if (!render_view_->Send(msg)) { + pending_connect_tcps_.Remove(request_id); return PP_ERROR_FAILED; + } return PP_ERROR_WOULDBLOCK; } @@ -851,6 +859,58 @@ void PepperPluginDelegateImpl::OnConnectTcpACK( connector->CompleteConnectTcp(socket, local_addr, remote_addr); } +int32_t PepperPluginDelegateImpl::ShowContextMenu( + webkit::ppapi::PPB_Flash_Menu_Impl* menu, + const gfx::Point& position) { + int request_id = pending_context_menus_.Add( + new scoped_refptr<webkit::ppapi::PPB_Flash_Menu_Impl>(menu)); + + ContextMenuParams params; + params.x = position.x(); + params.y = position.y(); + params.custom_context.is_pepper_menu = true; + params.custom_context.request_id = request_id; + params.custom_items = menu->menu_data(); + + IPC::Message* msg = new ViewHostMsg_ContextMenu(render_view_->routing_id(), + params); + if (!render_view_->Send(msg)) { + pending_context_menus_.Remove(request_id); + return PP_ERROR_FAILED; + } + + return PP_ERROR_WOULDBLOCK; +} + +void PepperPluginDelegateImpl::OnContextMenuClosed( + const webkit_glue::CustomContextMenuContext& custom_context) { + int request_id = custom_context.request_id; + scoped_refptr<webkit::ppapi::PPB_Flash_Menu_Impl> menu = + *pending_context_menus_.Lookup(request_id); + if (!menu) { + NOTREACHED() << "CompleteShowContextMenu() called twice for the same menu."; + return; + } + pending_context_menus_.Remove(request_id); + + if (has_saved_context_menu_action_) { + menu->CompleteShow(PP_OK, saved_context_menu_action_); + has_saved_context_menu_action_ = false; + saved_context_menu_action_ = 0; + } else { + menu->CompleteShow(PP_ERROR_USERCANCEL, 0); + } +} + +void PepperPluginDelegateImpl::OnCustomContextMenuAction( + const webkit_glue::CustomContextMenuContext& custom_context, + unsigned action) { + // Just save the action. + DCHECK(!has_saved_context_menu_action_); + has_saved_context_menu_action_ = true; + saved_context_menu_action_ = action; +} + webkit::ppapi::FullscreenContainer* PepperPluginDelegateImpl::CreateFullscreenContainer( webkit::ppapi::PluginInstance* instance) { diff --git a/chrome/renderer/pepper_plugin_delegate_impl.h b/chrome/renderer/pepper_plugin_delegate_impl.h index 408163a..f589687 100644 --- a/chrome/renderer/pepper_plugin_delegate_impl.h +++ b/chrome/renderer/pepper_plugin_delegate_impl.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -16,11 +16,13 @@ #include "ppapi/c/pp_errors.h" #include "webkit/plugins/ppapi/plugin_delegate.h" #include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/ppb_flash_menu_impl.h" class FilePath; class RenderView; namespace gfx { +class Point; class Rect; } @@ -38,6 +40,10 @@ class WebFileChooserCompletion; struct WebFileChooserParams; } +namespace webkit_glue { +struct CustomContextMenuContext; +} + class TransportDIB; class PepperPluginDelegateImpl @@ -154,6 +160,17 @@ class PepperPluginDelegateImpl base::PlatformFile socket, const PP_Flash_NetAddress& local_addr, const PP_Flash_NetAddress& remote_addr); + virtual int32_t ShowContextMenu( + webkit::ppapi::PPB_Flash_Menu_Impl* menu, + const gfx::Point& position); + void OnContextMenuClosed( + const webkit_glue::CustomContextMenuContext& custom_context); + void OnCustomContextMenuAction( + const webkit_glue::CustomContextMenuContext& custom_context, + unsigned action); + void CompleteShowContextMenu(int request_id, + bool did_select, + unsigned action); virtual webkit::ppapi::FullscreenContainer* CreateFullscreenContainer( webkit::ppapi::PluginInstance* instance); @@ -171,6 +188,10 @@ class PepperPluginDelegateImpl std::set<webkit::ppapi::PluginInstance*> active_instances_; + // Used to send a single context menu "completion" upon menu close. + bool has_saved_context_menu_action_; + unsigned saved_context_menu_action_; + // TODO(viettrungluu): Get rid of |id_generator_| -- just use |IDMap::Add()|. // Rename |messages_waiting_replies_| (to specify async open file). int id_generator_; @@ -179,6 +200,9 @@ class PepperPluginDelegateImpl IDMap<scoped_refptr<webkit::ppapi::PPB_Flash_NetConnector_Impl>, IDMapOwnPointer> pending_connect_tcps_; + IDMap<scoped_refptr<webkit::ppapi::PPB_Flash_Menu_Impl>, + IDMapOwnPointer> pending_context_menus_; + DISALLOW_COPY_AND_ASSIGN(PepperPluginDelegateImpl); }; diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 2dc7c80..25e3544 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -4716,8 +4716,13 @@ void RenderView::OnSetAltErrorPageURL(const GURL& url) { alternate_error_page_url_ = url; } -void RenderView::OnCustomContextMenuAction(unsigned action) { - webview()->performCustomContextMenuAction(action); +void RenderView::OnCustomContextMenuAction( + const webkit_glue::CustomContextMenuContext& custom_context, + unsigned action) { + if (custom_context.is_pepper_menu) + pepper_delegate_.OnCustomContextMenuAction(custom_context, action); + else + webview()->performCustomContextMenuAction(action); } void RenderView::OnTranslatePage(int page_id, @@ -5774,6 +5779,10 @@ void RenderView::OnJavaScriptStressTestControl(int cmd, int param) { } } -void RenderView::OnContextMenuClosed() { - context_menu_node_.reset(); +void RenderView::OnContextMenuClosed( + const webkit_glue::CustomContextMenuContext& custom_context) { + if (custom_context.is_pepper_menu) + pepper_delegate_.OnContextMenuClosed(custom_context); + else + context_menu_node_.reset(); } diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index 92a3577..314224d 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -114,6 +114,7 @@ class PhishingClassifierDelegate; } namespace webkit_glue { +struct CustomContextMenuContext; class ImageResourceFetcher; struct FileUploadData; struct FormData; @@ -826,7 +827,8 @@ class RenderView : public RenderWidget, const PP_Flash_NetAddress& local_addr, const PP_Flash_NetAddress& remote_addr); #endif - void OnContextMenuClosed(); + void OnContextMenuClosed( + const webkit_glue::CustomContextMenuContext& custom_context); void OnCopy(); void OnCopyImageAt(int x, int y); #if defined(OS_MACOSX) @@ -838,7 +840,9 @@ class RenderView : public RenderWidget, void OnCSSInsertRequest(const std::wstring& frame_xpath, const std::string& css, const std::string& id); - void OnCustomContextMenuAction(unsigned action); + void OnCustomContextMenuAction( + const webkit_glue::CustomContextMenuContext& custom_context, + unsigned action); void OnDelete(); void OnDeterminePageLanguage(); void OnDisableScrollbarsForSmallWindows( diff --git a/ppapi/c/pp_errors.h b/ppapi/c/pp_errors.h index 2d07e90..0138f2f 100644 --- a/ppapi/c/pp_errors.h +++ b/ppapi/c/pp_errors.h @@ -75,7 +75,10 @@ enum { PP_ERROR_FILECHANGED = -23, /** Indicates failure due to a time limit being exceeded. */ - PP_ERROR_TIMEDOUT = -30 + PP_ERROR_TIMEDOUT = -30, + + /** Indicates that the user cancelled rather providing expected input. */ + PP_ERROR_USERCANCEL = -40 }; /** @@ -84,4 +87,3 @@ enum { */ #endif /* PPAPI_C_PP_ERRORS_H_ */ - diff --git a/ppapi/c/private/ppb_flash.h b/ppapi/c/private/ppb_flash.h index a7a5bab..3f8f222 100644 --- a/ppapi/c/private/ppb_flash.h +++ b/ppapi/c/private/ppb_flash.h @@ -19,7 +19,7 @@ // PPB_Flash ------------------------------------------------------------------- -#define PPB_FLASH_INTERFACE "PPB_Flash;4" +#define PPB_FLASH_INTERFACE "PPB_Flash;5" #ifdef _WIN32 typedef HANDLE PP_FileHandle; @@ -116,6 +116,17 @@ struct PPB_Flash { PP_Bool (*NavigateToURL)(PP_Instance instance, const char* url, const char* target); + + // Runs a nested message loop. The plugin will be reentered from this call. + // This function is used in places where Flash would normally enter a nested + // message loop (e.g., when displaying context menus), but Pepper provides + // only an asynchronous call. After performing that asynchronous call, call + // |RunMessageLoop()|. In the callback, call |QuitMessageLoop()|. + void (*RunMessageLoop)(); + + // Posts a quit message for the outermost nested message loop. Use this to + // exit and return back to the caller after you call RunMessageLoop. + void (*QuitMessageLoop)(); }; // PPB_Flash_NetConnector ------------------------------------------------------ diff --git a/ppapi/c/private/ppb_flash_menu.h b/ppapi/c/private/ppb_flash_menu.h new file mode 100644 index 0000000..a183baf --- /dev/null +++ b/ppapi/c/private/ppb_flash_menu.h @@ -0,0 +1,57 @@ +// Copyright (c) 2011 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 PPAPI_C_PRIVATE_PPB_FLASH_MENU_H_ +#define PPAPI_C_PRIVATE_PPB_FLASH_MENU_H_ + +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_point.h" +#include "ppapi/c/pp_resource.h" + +// PPB_Flash ------------------------------------------------------------------- + +#define PPB_FLASH_MENU_INTERFACE "PPB_Flash_Menu;1" + +struct PP_CompletionCallback; + +typedef enum { + // TODO(viettrungluu): Radio items not supported yet. Will also probably want + // special menu items tied to clipboard access. + PP_FLASH_MENUITEM_TYPE_NORMAL = 0, + PP_FLASH_MENUITEM_TYPE_CHECKBOX, + PP_FLASH_MENUITEM_TYPE_SEPARATOR, + PP_FLASH_MENUITEM_TYPE_SUBMENU +} PP_Flash_MenuItem_Type; + +struct PP_Flash_MenuItem { + PP_Flash_MenuItem_Type type; + char* name; + int32_t id; + PP_Bool enabled; + PP_Bool checked; + struct PP_Flash_Menu* submenu; +}; + +struct PP_Flash_Menu { + uint32_t count; + struct PP_Flash_MenuItem* items; +}; + +struct PPB_Flash_Menu { + PP_Resource (*Create)(PP_Instance instance_id, + const struct PP_Flash_Menu* menu_data); + PP_Bool (*IsFlashMenu)(PP_Resource resource_id); + + // Display a context menu at the given location. If the user selects an item, + // |selected_id| will be set to its |id| and the callback called with |PP_OK|. + // If the user dismisses the menu without selecting an item, + // |PP_ERROR_USERCANCEL| will be indicated. + int32_t (*Show)(PP_Resource menu_id, + const struct PP_Point* location, + int32_t* selected_id, + PP_CompletionCallback callback); +}; + +#endif // PPAPI_C_PRIVATE_PPB_FLASH_MENU_H_ diff --git a/ppapi/cpp/private/flash_menu.cc b/ppapi/cpp/private/flash_menu.cc new file mode 100644 index 0000000..8596fc9 --- /dev/null +++ b/ppapi/cpp/private/flash_menu.cc @@ -0,0 +1,48 @@ +// Copyright (c) 2011 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. + +// TODO(viettrungluu): See the comment in corresponding .h file. + +#include "ppapi/cpp/private/flash_menu.h" + +#include "ppapi/c/pp_errors.h" +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/cpp/instance.h" +#include "ppapi/cpp/module.h" +#include "ppapi/cpp/module_impl.h" +#include "ppapi/cpp/point.h" + +namespace pp { + +namespace { + +template <> const char* interface_name<PPB_Flash_Menu>() { + return PPB_FLASH_MENU_INTERFACE; +} + +} // namespace + +namespace flash { + +Menu::Menu(const Instance& instance, const struct PP_Flash_Menu* menu_data) { + if (has_interface<PPB_Flash_Menu>()) { + PassRefFromConstructor(get_interface<PPB_Flash_Menu>()->Create( + instance.pp_instance(), menu_data)); + } +} + +int32_t Menu::Show(const Point& location, + int32_t* selected_id, + const CompletionCallback& cc) { + if (!has_interface<PPB_Flash_Menu>()) + return PP_ERROR_NOINTERFACE; + return get_interface<PPB_Flash_Menu>()->Show( + pp_resource(), + &location.pp_point(), + selected_id, + cc.pp_completion_callback()); +} + +} // namespace flash +} // namespace pp diff --git a/ppapi/cpp/private/flash_menu.h b/ppapi/cpp/private/flash_menu.h new file mode 100644 index 0000000..a5d4408 --- /dev/null +++ b/ppapi/cpp/private/flash_menu.h @@ -0,0 +1,36 @@ +// Copyright (c) 2011 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. + +// TODO(viettrungluu): This (and the .cc file) contain C++ wrappers for some +// things in ppapi/c/private/ppb_flash_menu.h. This is currently not used in (or +// even compiled with) Chromium. + +#ifndef PPAPI_CPP_PRIVATE_FLASH_MENU_H_ +#define PPAPI_CPP_PRIVATE_FLASH_MENU_H_ + +#include "ppapi/c/private/ppb_flash_menu.h" +#include "ppapi/cpp/resource.h" + +namespace pp { + +class CompletionCallback; +class Instance; +class Point; + +namespace flash { + +class Menu : public Resource { + public: + // TODO(viettrungluu): Write a proper C++ wrapper of |PP_Flash_Menu|. + Menu(const Instance& instance, const struct PP_Flash_Menu* menu_data); + + int32_t Show(const Point& location, + int32_t* selected_id, + const CompletionCallback& cc); +}; + +} // namespace flash +} // namespace pp + +#endif // PPAPI_CPP_PRIVATE_FLASH_H_ diff --git a/ppapi/ppapi_cpp.gypi b/ppapi/ppapi_cpp.gypi index 79f5603..112edcd 100644 --- a/ppapi/ppapi_cpp.gypi +++ b/ppapi/ppapi_cpp.gypi @@ -82,6 +82,7 @@ # Private interfaces. 'c/private/ppb_flash.h', + 'c/private/ppb_flash_menu.h', 'c/private/ppb_nacl_private.h', 'c/private/ppb_pdf.h', diff --git a/webkit/glue/context_menu.cc b/webkit/glue/context_menu.cc index bdfe790..6db5c51 100644 --- a/webkit/glue/context_menu.cc +++ b/webkit/glue/context_menu.cc @@ -4,6 +4,15 @@ #include "webkit/glue/context_menu.h" +namespace webkit_glue { + +CustomContextMenuContext::CustomContextMenuContext() + : is_pepper_menu(false), + request_id(0) { +} + +} // namespace webkit_glue + ContextMenuParams::ContextMenuParams() { } @@ -30,6 +39,7 @@ ContextMenuParams::ContextMenuParams(const WebKit::WebContextMenuData& data) edit_flags(data.editFlags), security_info(data.securityInfo), frame_charset(data.frameEncoding.utf8()) { + custom_context.is_pepper_menu = false; for (size_t i = 0; i < data.customItems.size(); ++i) custom_items.push_back(WebMenuItem(data.customItems[i])); } diff --git a/webkit/glue/context_menu.h b/webkit/glue/context_menu.h index e1a88cb..2f38807 100644 --- a/webkit/glue/context_menu.h +++ b/webkit/glue/context_menu.h @@ -14,6 +14,18 @@ #include "third_party/WebKit/Source/WebKit/chromium/public/WebContextMenuData.h" +namespace webkit_glue { + +struct CustomContextMenuContext { + bool is_pepper_menu; + int request_id; + + CustomContextMenuContext(); +}; + +} // namespace webkit_glue + +// TODO(viettrungluu): Put this in the webkit_glue namespace. // Parameters structure for ViewHostMsg_ContextMenu. // FIXME(beng): This would be more useful in the future and more efficient // if the parameters here weren't so literally mapped to what @@ -94,6 +106,7 @@ struct ContextMenuParams { // The character encoding of the frame on which the menu is invoked. std::string frame_charset; + webkit_glue::CustomContextMenuContext custom_context; std::vector<WebMenuItem> custom_items; ContextMenuParams(); diff --git a/webkit/glue/webkit_glue.gypi b/webkit/glue/webkit_glue.gypi index 2de3fbc..31744a0 100644 --- a/webkit/glue/webkit_glue.gypi +++ b/webkit/glue/webkit_glue.gypi @@ -296,6 +296,8 @@ '../plugins/ppapi/ppb_flash_impl.cc', '../plugins/ppapi/ppb_flash_impl.h', '../plugins/ppapi/ppb_flash_impl_linux.cc', + '../plugins/ppapi/ppb_flash_menu_impl.cc', + '../plugins/ppapi/ppb_flash_menu_impl.h', '../plugins/ppapi/ppb_font_impl.cc', '../plugins/ppapi/ppb_font_impl.h', '../plugins/ppapi/ppb_gles_chromium_texture_mapping_impl.cc', diff --git a/webkit/glue/webmenuitem.h b/webkit/glue/webmenuitem.h index f2eb448..c767bea 100644 --- a/webkit/glue/webmenuitem.h +++ b/webkit/glue/webmenuitem.h @@ -1,10 +1,12 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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 WEBMENUITEM_H_ #define WEBMENUITEM_H_ +#include <vector> + #include "base/string16.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebMenuItemInfo.h" @@ -15,7 +17,8 @@ struct WebMenuItem { OPTION = WebKit::WebMenuItemInfo::Option, CHECKABLE_OPTION = WebKit::WebMenuItemInfo::CheckableOption, GROUP = WebKit::WebMenuItemInfo::Group, - SEPARATOR = WebKit::WebMenuItemInfo::Separator + SEPARATOR = WebKit::WebMenuItemInfo::Separator, + SUBMENU // This is currently only used by Pepper, not by WebKit. }; string16 label; @@ -23,6 +26,7 @@ struct WebMenuItem { unsigned action; bool enabled; bool checked; + std::vector<WebMenuItem> submenu; WebMenuItem() : type(OPTION), action(0), enabled(false), checked(false) { } diff --git a/webkit/plugins/ppapi/mock_plugin_delegate.cc b/webkit/plugins/ppapi/mock_plugin_delegate.cc index e072ebb..54e55ee 100644 --- a/webkit/plugins/ppapi/mock_plugin_delegate.cc +++ b/webkit/plugins/ppapi/mock_plugin_delegate.cc @@ -173,6 +173,12 @@ int32_t MockPluginDelegate::ConnectTcpAddress( return PP_ERROR_FAILED; } +int32_t MockPluginDelegate::ShowContextMenu( + webkit::ppapi::PPB_Flash_Menu_Impl* menu, + const gfx::Point& position) { + return PP_ERROR_FAILED; +} + FullscreenContainer* MockPluginDelegate::CreateFullscreenContainer( PluginInstance* instance) { return NULL; diff --git a/webkit/plugins/ppapi/mock_plugin_delegate.h b/webkit/plugins/ppapi/mock_plugin_delegate.h index 5d652dd..75d4637 100644 --- a/webkit/plugins/ppapi/mock_plugin_delegate.h +++ b/webkit/plugins/ppapi/mock_plugin_delegate.h @@ -90,6 +90,9 @@ class MockPluginDelegate : public PluginDelegate { virtual int32_t ConnectTcpAddress( webkit::ppapi::PPB_Flash_NetConnector_Impl* connector, const struct PP_Flash_NetAddress* addr); + virtual int32_t ShowContextMenu( + webkit::ppapi::PPB_Flash_Menu_Impl* menu, + const gfx::Point& position); virtual FullscreenContainer* CreateFullscreenContainer( PluginInstance* instance); virtual std::string GetDefaultEncoding(); diff --git a/webkit/plugins/ppapi/plugin_delegate.h b/webkit/plugins/ppapi/plugin_delegate.h index 94ffa61..8f36c3d 100644 --- a/webkit/plugins/ppapi/plugin_delegate.h +++ b/webkit/plugins/ppapi/plugin_delegate.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -34,6 +34,7 @@ class FileSystemCallbackDispatcher; } namespace gfx { +class Point; class Rect; } @@ -64,6 +65,7 @@ class FileIO; class FullscreenContainer; class PluginInstance; class PluginModule; +class PPB_Flash_Menu_Impl; class PPB_Flash_NetConnector_Impl; // Virtual interface that the browser implements to implement features for @@ -302,6 +304,12 @@ class PluginDelegate { webkit::ppapi::PPB_Flash_NetConnector_Impl* connector, const struct PP_Flash_NetAddress* addr) = 0; + // Show the given context menu at the given position (in the render view's + // coordinates). + virtual int32_t ShowContextMenu( + webkit::ppapi::PPB_Flash_Menu_Impl* menu, + const gfx::Point& position) = 0; + // Create a fullscreen container for a plugin instance. This effectively // switches the plugin to fullscreen. virtual FullscreenContainer* CreateFullscreenContainer( diff --git a/webkit/plugins/ppapi/plugin_module.cc b/webkit/plugins/ppapi/plugin_module.cc index cec7e79..332770ff 100644 --- a/webkit/plugins/ppapi/plugin_module.cc +++ b/webkit/plugins/ppapi/plugin_module.cc @@ -50,6 +50,7 @@ #include "ppapi/c/ppp.h" #include "ppapi/c/ppp_instance.h" #include "ppapi/c/private/ppb_flash.h" +#include "ppapi/c/private/ppb_flash_menu.h" #include "ppapi/c/private/ppb_pdf.h" #include "ppapi/c/private/ppb_nacl_private.h" #include "ppapi/c/trusted/ppb_image_data_trusted.h" @@ -67,6 +68,7 @@ #include "webkit/plugins/ppapi/ppb_file_ref_impl.h" #include "webkit/plugins/ppapi/ppb_file_system_impl.h" #include "webkit/plugins/ppapi/ppb_flash_impl.h" +#include "webkit/plugins/ppapi/ppb_flash_menu_impl.h" #include "webkit/plugins/ppapi/ppb_font_impl.h" #include "webkit/plugins/ppapi/ppb_graphics_2d_impl.h" #include "webkit/plugins/ppapi/ppb_image_data_impl.h" @@ -242,6 +244,8 @@ const void* GetInterface(const char* name) { return PluginInstance::GetFindInterface(); if (strcmp(name, PPB_FLASH_INTERFACE) == 0) return PPB_Flash_Impl::GetInterface(); + if (strcmp(name, PPB_FLASH_MENU_INTERFACE) == 0) + return PPB_Flash_Menu_Impl::GetInterface(); if (strcmp(name, PPB_FONT_DEV_INTERFACE) == 0) return PPB_Font_Impl::GetInterface(); if (strcmp(name, PPB_FULLSCREEN_DEV_INTERFACE) == 0) diff --git a/webkit/plugins/ppapi/ppb_flash_impl.cc b/webkit/plugins/ppapi/ppb_flash_impl.cc index 33e0d11..36ba4ac 100644 --- a/webkit/plugins/ppapi/ppb_flash_impl.cc +++ b/webkit/plugins/ppapi/ppb_flash_impl.cc @@ -7,6 +7,7 @@ #include <string.h> #include "base/file_path.h" +#include "base/message_loop.h" #include "base/stringprintf.h" #include "base/utf_string_conversions.h" #include "googleurl/src/gurl.h" @@ -217,6 +218,17 @@ PP_Bool NavigateToURL(PP_Instance pp_instance, return BoolToPPBool(instance->NavigateToURL(url, target)); } +void RunMessageLoop() { + bool old_state = MessageLoop::current()->NestableTasksAllowed(); + MessageLoop::current()->SetNestableTasksAllowed(true); + MessageLoop::current()->Run(); + MessageLoop::current()->SetNestableTasksAllowed(old_state); +} + +void QuitMessageLoop() { + MessageLoop::current()->QuitNow(); +} + const PPB_Flash ppb_flash = { &SetInstanceAlwaysOnTop, &PPB_Flash_Impl::DrawGlyphs, @@ -229,6 +241,8 @@ const PPB_Flash ppb_flash = { &GetModuleLocalDirContents, &FreeModuleLocalDirContents, &NavigateToURL, + &RunMessageLoop, + &QuitMessageLoop, }; } // namespace diff --git a/webkit/plugins/ppapi/ppb_flash_menu_impl.cc b/webkit/plugins/ppapi/ppb_flash_menu_impl.cc new file mode 100644 index 0000000..67776fe --- /dev/null +++ b/webkit/plugins/ppapi/ppb_flash_menu_impl.cc @@ -0,0 +1,223 @@ +// Copyright (c) 2011 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 "webkit/plugins/ppapi/ppb_flash_menu_impl.h" + +#include "base/utf_string_conversions.h" +#include "gfx/point.h" +#include "ppapi/c/pp_completion_callback.h" +#include "webkit/glue/webmenuitem.h" +#include "webkit/plugins/ppapi/common.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" +#include "webkit/plugins/ppapi/plugin_module.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" + +namespace webkit { +namespace ppapi { + +namespace { + +PP_Resource Create(PP_Instance instance_id, const PP_Flash_Menu* menu_data) { + PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); + if (!instance) + return 0; + + scoped_refptr<PPB_Flash_Menu_Impl> menu(new PPB_Flash_Menu_Impl(instance)); + if (!menu->Init(menu_data)) + return 0; + + return menu->GetReference(); +} + +PP_Bool IsFlashMenu(PP_Resource resource) { + return BoolToPPBool(!!Resource::GetAs<PPB_Flash_Menu_Impl>(resource)); +} + +int32_t Show(PP_Resource menu_id, + const PP_Point* location, + int32_t* selected_id, + PP_CompletionCallback callback) { + scoped_refptr<PPB_Flash_Menu_Impl> menu( + Resource::GetAs<PPB_Flash_Menu_Impl>(menu_id)); + if (!menu.get()) + return PP_ERROR_BADRESOURCE; + + return menu->Show(location, selected_id, callback); +} + +const PPB_Flash_Menu ppb_flash_menu = { + &Create, + &IsFlashMenu, + &Show, +}; + +// Maximum depth of submenus allowed (e.g., 1 indicates that submenus are +// allowed, but not sub-submenus). +const size_t kMaxMenuDepth = 2; + +// Maximum number of entries in any single menu (including separators). +const size_t kMaxMenuEntries = 50; + +// Maximum total number of entries in the |menu_id_map| (see below). +// (Limit to 500 real entries; reserve the 0 action as an invalid entry.) +const size_t kMaxMenuIdMapEntries = 501; + +// Converts menu data from one form to another. +// - |depth| is the current nested depth (call it starting with 0). +// - |menu_id_map| is such that |menu_id_map[output_item.action] == +// input_item.id| (where |action| is what a |WebMenuItem| has, |id| is what a +// |PP_Flash_MenuItem| has). +bool ConvertMenuData(const PP_Flash_Menu* in_menu, + size_t depth, + PPB_Flash_Menu_Impl::MenuData* out_menu, + std::vector<int32_t>* menu_id_map) { + if (depth > kMaxMenuDepth) + return false; + + // Clear the output, just in case. + out_menu->clear(); + + if (!in_menu || !in_menu->count) + return true; // Nothing else to do. + + if (!in_menu->items || in_menu->count > kMaxMenuEntries) + return false; + for (uint32_t i = 0; i < in_menu->count; i++) { + WebMenuItem item; + + PP_Flash_MenuItem_Type type = in_menu->items[i].type; + switch (type) { + case PP_FLASH_MENUITEM_TYPE_NORMAL: + item.type = WebMenuItem::OPTION; + break; + case PP_FLASH_MENUITEM_TYPE_CHECKBOX: + item.type = WebMenuItem::CHECKABLE_OPTION; + break; + case PP_FLASH_MENUITEM_TYPE_SEPARATOR: + item.type = WebMenuItem::SEPARATOR; + break; + case PP_FLASH_MENUITEM_TYPE_SUBMENU: + item.type = WebMenuItem::SUBMENU; + break; + default: + return false; + } + if (in_menu->items[i].name) + item.label = UTF8ToUTF16(in_menu->items[i].name); + if (menu_id_map->size() >= kMaxMenuIdMapEntries) + return false; + item.action = static_cast<unsigned>(menu_id_map->size()); + // This sets |(*menu_id_map)[item.action] = in_menu->items[i].id|. + menu_id_map->push_back(in_menu->items[i].id); + item.enabled = PPBoolToBool(in_menu->items[i].enabled); + item.checked = PPBoolToBool(in_menu->items[i].checked); + if (type == PP_FLASH_MENUITEM_TYPE_SUBMENU) { + if (!ConvertMenuData(in_menu->items[i].submenu, depth + 1, &item.submenu, + menu_id_map)) + return false; + } + + out_menu->push_back(item); + } + + return true; +} + +} // namespace + +PPB_Flash_Menu_Impl::PPB_Flash_Menu_Impl(PluginInstance* instance) + : Resource(instance) { +} + +bool PPB_Flash_Menu_Impl::Init(const PP_Flash_Menu* menu_data) { + menu_id_map_.clear(); + menu_id_map_.push_back(0); // Reserve |menu_id_map_[0]|. + if (!ConvertMenuData(menu_data, 0, &menu_data_, &menu_id_map_)) { + menu_id_map_.clear(); + return false; + } + + return true; +} + +PPB_Flash_Menu_Impl::~PPB_Flash_Menu_Impl() { +} + +// static +const PPB_Flash_Menu* PPB_Flash_Menu_Impl::GetInterface() { + return &ppb_flash_menu; +} + +PPB_Flash_Menu_Impl* PPB_Flash_Menu_Impl::AsPPB_Flash_Menu_Impl() { + return this; +} + +int32_t PPB_Flash_Menu_Impl::Show(const PP_Point* location, + int32_t* selected_id_out, + PP_CompletionCallback callback) { + // |location| is not (currently) optional. + // TODO(viettrungluu): Make it optional and default to the current mouse pos? + if (!location) + return PP_ERROR_BADARGUMENT; + + if (!callback.func) { + NOTIMPLEMENTED(); + return PP_ERROR_BADARGUMENT; + } + + if (callback_.get() && !callback_->completed()) + return PP_ERROR_INPROGRESS; + + PP_Resource resource_id = GetReferenceNoAddRef(); + if (!resource_id) { + NOTREACHED(); + return PP_ERROR_FAILED; + } + + int32_t rv = instance()->delegate()->ShowContextMenu( + this, gfx::Point(instance()->position().x() + location->x, + instance()->position().y() + location->y)); + if (rv == PP_ERROR_WOULDBLOCK) { + // Record callback and output buffers. + callback_ = new TrackedCompletionCallback( + instance()->module()->GetCallbackTracker(), resource_id, callback); + selected_id_out_ = selected_id_out; + } else { + // This should never be completed synchronously successfully. + DCHECK_NE(rv, PP_OK); + } + return rv; + + NOTIMPLEMENTED(); + return PP_ERROR_FAILED; +} + +void PPB_Flash_Menu_Impl::CompleteShow(int32_t result, + unsigned action) { + int32_t rv = PP_ERROR_ABORTED; + if (!callback_->aborted()) { + CHECK(!callback_->completed()); + rv = result; + + // Write output data. + if (selected_id_out_ && result == PP_OK) { + // We reserved action 0 to be invalid. + if (action == 0 || action >= menu_id_map_.size()) { + NOTREACHED() << "Invalid action received."; + rv = PP_ERROR_FAILED; + } else { + *selected_id_out_ = menu_id_map_[action]; + } + } + } + + scoped_refptr<TrackedCompletionCallback> callback; + callback.swap(callback_); + selected_id_out_ = NULL; + + callback->Run(rv); // Will complete abortively if necessary. +} + +} // namespace ppapi +} // namespace webkit diff --git a/webkit/plugins/ppapi/ppb_flash_menu_impl.h b/webkit/plugins/ppapi/ppb_flash_menu_impl.h new file mode 100644 index 0000000..610e46e --- /dev/null +++ b/webkit/plugins/ppapi/ppb_flash_menu_impl.h @@ -0,0 +1,65 @@ +// Copyright (c) 2011 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 WEBKIT_PLUGINS_PPAPI_PPB_FLASH_MENU_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_FLASH_MENU_IMPL_H_ + +#include <vector> + +#include "base/basictypes.h" +#include "base/ref_counted.h" +#include "ppapi/c/pp_point.h" +#include "ppapi/c/private/ppb_flash_menu.h" +#include "webkit/plugins/ppapi/callbacks.h" +#include "webkit/plugins/ppapi/resource.h" + +struct WebMenuItem; + +namespace webkit { +namespace ppapi { + +class PPB_Flash_Menu_Impl : public Resource { + public: + explicit PPB_Flash_Menu_Impl(PluginInstance* instance); + virtual ~PPB_Flash_Menu_Impl(); + + static const PPB_Flash_Menu* GetInterface(); + + bool Init(const PP_Flash_Menu* menu_data); + + // Resource override. + virtual PPB_Flash_Menu_Impl* AsPPB_Flash_Menu_Impl(); + + // PPB_Flash_Menu implementation. + int32_t Show(const PP_Point* location, + int32_t* selected_id_out, + PP_CompletionCallback callback); + + // Called to complete |Show()|. + void CompleteShow(int32_t result, unsigned action); + + typedef std::vector<WebMenuItem> MenuData; + const MenuData& menu_data() const { return menu_data_; } + + private: + MenuData menu_data_; + + // We send |WebMenuItem|s, which have an |unsigned| "action" field instead of + // an |int32_t| ID. (Chrome also limits the range of valid values for + // actions.) This maps actions to IDs. + std::vector<int32_t> menu_id_map_; + + // Any pending callback (for |Show()|). + scoped_refptr<TrackedCompletionCallback> callback_; + + // Output buffers to be filled in when the callback is completed successfully. + int32_t* selected_id_out_; + + DISALLOW_COPY_AND_ASSIGN(PPB_Flash_Menu_Impl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_FLASH_MENU_IMPL_H_ diff --git a/webkit/plugins/ppapi/resource.h b/webkit/plugins/ppapi/resource.h index fb4f2ef..10664f9 100644 --- a/webkit/plugins/ppapi/resource.h +++ b/webkit/plugins/ppapi/resource.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -25,6 +25,7 @@ namespace ppapi { F(PPB_FileIO_Impl) \ F(PPB_FileRef_Impl) \ F(PPB_FileSystem_Impl) \ + F(PPB_Flash_Menu_Impl) \ F(PPB_Flash_NetConnector_Impl) \ F(PPB_Font_Impl) \ F(PPB_Graphics2D_Impl) \ |