Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(463)

Unified Diff: components/renderer_context_menu/render_view_context_menu_base.cc

Issue 432003007: Separate chrome independent part from RVContextMenu (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/renderer_context_menu/render_view_context_menu_base.cc
diff --git a/components/renderer_context_menu/render_view_context_menu_base.cc b/components/renderer_context_menu/render_view_context_menu_base.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4c2596c393cae653c5b5eb3ea92643728710f577
--- /dev/null
+++ b/components/renderer_context_menu/render_view_context_menu_base.cc
@@ -0,0 +1,385 @@
+// Copyright 2014 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 "components/renderer_context_menu/render_view_context_menu_base.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/menu_item.h"
+#include "extensions/browser/extension_host.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/browser/view_type_utils.h"
+#include "extensions/common/extension.h"
+#include "third_party/WebKit/public/web/WebContextMenuData.h"
+
+using blink::WebContextMenuData;
+using blink::WebString;
+using blink::WebURL;
+using content::BrowserContext;
+using content::OpenURLParams;
+using content::RenderFrameHost;
+using content::RenderViewHost;
+using content::WebContents;
+
+namespace {
+
+// The range of command IDs reserved for content's custom menus.
lazyboy 2014/08/01 07:59:34 The (inclusive) range of ...
+// TODO(oshima): These values will be injected by embedders.
lazyboy 2014/08/01 07:59:34 This TODO has been taken care of?
oshima 2014/08/01 10:38:45 Done. Thanks
+int content_context_custom_first = -1;
lazyboy 2014/08/01 07:59:34 These should also have g_ prefix as they are globa
oshima 2014/08/01 10:38:44 same here. they're file scoped, not global.
+int content_context_custom_last = -1;
+
+bool IsCustomItemEnabledInternal(const std::vector<content::MenuItem>& items,
+ int id) {
+ DCHECK(RenderViewContextMenuBase::IsContentCustomCommandId(id));
+ for (size_t i = 0; i < items.size(); ++i) {
+ int action_id = RenderViewContextMenuBase::ConvertToContentCustomCommandId(
+ items[i].action);
+ if (action_id == id)
+ return items[i].enabled;
+ if (items[i].type == content::MenuItem::SUBMENU) {
+ if (IsCustomItemEnabledInternal(items[i].submenu, id))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool IsCustomItemCheckedInternal(const std::vector<content::MenuItem>& items,
+ int id) {
+ DCHECK(RenderViewContextMenuBase::IsContentCustomCommandId(id));
+ for (size_t i = 0; i < items.size(); ++i) {
+ int action_id = RenderViewContextMenuBase::ConvertToContentCustomCommandId(
+ items[i].action);
+ if (action_id == id)
+ return items[i].checked;
+ if (items[i].type == content::MenuItem::SUBMENU) {
+ if (IsCustomItemCheckedInternal(items[i].submenu, id))
+ return true;
+ }
+ }
+ return false;
+}
+
+const size_t kMaxCustomMenuDepth = 5;
+const size_t kMaxCustomMenuTotalItems = 1000;
+
+void AddCustomItemsToMenu(const std::vector<content::MenuItem>& 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) {
+ int command_id = RenderViewContextMenuBase::ConvertToContentCustomCommandId(
+ items[i].action);
+ if (!RenderViewContextMenuBase::IsContentCustomCommandId(command_id)) {
+ LOG(ERROR) << "Custom menu action value out of range.";
+ return;
+ }
+ if (*total_items >= kMaxCustomMenuTotalItems) {
+ LOG(ERROR) << "Custom menu too large (too many items).";
+ return;
+ }
+ (*total_items)++;
+ switch (items[i].type) {
+ case content::MenuItem::OPTION:
+ menu_model->AddItem(
+ RenderViewContextMenuBase::ConvertToContentCustomCommandId(
+ items[i].action),
+ items[i].label);
+ break;
+ case content::MenuItem::CHECKABLE_OPTION:
+ menu_model->AddCheckItem(
+ RenderViewContextMenuBase::ConvertToContentCustomCommandId(
+ items[i].action),
+ items[i].label);
+ break;
+ case content::MenuItem::GROUP:
+ // TODO(viettrungluu): I don't know what this is supposed to do.
+ NOTREACHED();
+ break;
+ case content::MenuItem::SEPARATOR:
+ menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
+ break;
+ case content::MenuItem::SUBMENU: {
+ ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate);
+ AddCustomItemsToMenu(items[i].submenu, depth + 1, total_items, delegate,
+ submenu);
+ menu_model->AddSubMenu(
+ RenderViewContextMenuBase::ConvertToContentCustomCommandId(
+ items[i].action),
+ items[i].label,
+ submenu);
+ break;
+ }
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+}
+
+} // namespace
+
+// static
+void RenderViewContextMenuBase::SetContentCustomCommandIdRange(
lazyboy 2014/08/01 07:59:34 Add a note that this range is inclusive.
oshima 2014/08/01 10:38:44 Done.
+ int first, int last) {
+ content_context_custom_first = first;
+ content_context_custom_last = last;
+}
+
+// static
+const size_t RenderViewContextMenuBase::kMaxSelectionTextLength = 50;
+
+// static
+int RenderViewContextMenuBase::ConvertToContentCustomCommandId(int id) {
+ return content_context_custom_first + id;
+}
+
+// static
+bool RenderViewContextMenuBase::IsContentCustomCommandId(int id) {
+ return id >= content_context_custom_first &&
+ id <= content_context_custom_last;
+}
+
+RenderViewContextMenuBase::RenderViewContextMenuBase(
+ content::RenderFrameHost* render_frame_host,
+ const content::ContextMenuParams& params)
+ : params_(params),
+ source_web_contents_(WebContents::FromRenderFrameHost(render_frame_host)),
+ browser_context_(source_web_contents_->GetBrowserContext()),
+ menu_model_(this),
+ command_executed_(false),
+ render_process_id_(render_frame_host->GetProcess()->GetID()),
+ render_frame_id_(render_frame_host->GetRoutingID()) {
+}
+
+RenderViewContextMenuBase::~RenderViewContextMenuBase() {
+}
+
+// Menu construction functions -------------------------------------------------
+
+void RenderViewContextMenuBase::Init() {
+ // Command id range must have been already initializerd.
+ DCHECK_NE(-1, content_context_custom_first);
+ DCHECK_NE(-1, content_context_custom_last);
+
+ InitMenu();
+ if (toolkit_delegate_)
+ toolkit_delegate_->Init(&menu_model_);
+}
+
+void RenderViewContextMenuBase::Cancel() {
+ if (toolkit_delegate_)
+ toolkit_delegate_->Cancel();
+}
+
+void RenderViewContextMenuBase::InitMenu() {
+ if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_CUSTOM)) {
+ AppendCustomItems();
+
+ const bool has_selection = !params_.selection_text.empty();
+ if (has_selection) {
+ // We will add more items if there's a selection, so add a separator.
+ // TODO(lazyboy): Clean up separator logic.
+ menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
+ }
+ }
+}
+
+void RenderViewContextMenuBase::AddMenuItem(int command_id,
+ const base::string16& title) {
+ menu_model_.AddItem(command_id, title);
+}
+
+void RenderViewContextMenuBase::AddCheckItem(int command_id,
+ const base::string16& title) {
+ menu_model_.AddCheckItem(command_id, title);
+}
+
+void RenderViewContextMenuBase::AddSeparator() {
+ menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
+}
+
+void RenderViewContextMenuBase::AddSubMenu(int command_id,
+ const base::string16& label,
+ ui::MenuModel* model) {
+ menu_model_.AddSubMenu(command_id, label, model);
+}
+
+void RenderViewContextMenuBase::UpdateMenuItem(int command_id,
+ bool enabled,
+ bool hidden,
+ const base::string16& label) {
+ if (toolkit_delegate_) {
+ toolkit_delegate_->UpdateMenuItem(command_id,
+ enabled,
+ hidden,
+ label);
+ }
+}
+
+RenderViewHost* RenderViewContextMenuBase::GetRenderViewHost() const {
+ return source_web_contents_->GetRenderViewHost();
+}
+
+WebContents* RenderViewContextMenuBase::GetWebContents() const {
+ return source_web_contents_;
+}
+
+BrowserContext* RenderViewContextMenuBase::GetBrowserContext() const {
+ return browser_context_;
+}
+
+bool RenderViewContextMenuBase::AppendCustomItems() {
+ size_t total_items = 0;
+ AddCustomItemsToMenu(params_.custom_items, 0, &total_items, this,
+ &menu_model_);
+ return total_items > 0;
+}
+
+// Menu delegate functions -----------------------------------------------------
+
+bool RenderViewContextMenuBase::IsCommandIdEnabled(int id) const {
+ // If this command is is added by one of our observers, we dispatch
+ // it to the observer.
+ ObserverListBase<RenderViewContextMenuObserver>::Iterator it(observers_);
+ RenderViewContextMenuObserver* observer;
+ while ((observer = it.GetNext()) != NULL) {
+ if (observer->IsCommandIdSupported(id))
+ return observer->IsCommandIdEnabled(id);
+ }
+
+ // Custom items.
+ if (IsContentCustomCommandId(id))
+ return IsCustomItemEnabled(id);
+
+ return false;
+}
+
+bool RenderViewContextMenuBase::IsCommandIdChecked(int id) const {
+ // If this command is is added by one of our observers, we dispatch it to the
+ // observer.
+ ObserverListBase<RenderViewContextMenuObserver>::Iterator it(observers_);
+ RenderViewContextMenuObserver* observer;
+ while ((observer = it.GetNext()) != NULL) {
+ if (observer->IsCommandIdSupported(id))
+ return observer->IsCommandIdChecked(id);
+ }
+
+ // Custom items.
+ if (IsContentCustomCommandId(id))
+ return IsCustomItemChecked(id);
+
+ return false;
+}
+
+void RenderViewContextMenuBase::ExecuteCommand(int id, int event_flags) {
+ command_executed_ = true;
+ RecordUsedItem(id);
+
+ // If this command is is added by one of our observers, we dispatch
+ // it to the observer.
+ ObserverListBase<RenderViewContextMenuObserver>::Iterator it(observers_);
+ RenderViewContextMenuObserver* observer;
+ while ((observer = it.GetNext()) != NULL) {
+ if (observer->IsCommandIdSupported(id))
+ return observer->ExecuteCommand(id);
+ }
+
+ // Process custom actions range.
+ if (IsContentCustomCommandId(id)) {
+ unsigned action = id - content_context_custom_first;
+ const content::CustomContextMenuContext& context = params_.custom_context;
+#if defined(ENABLE_PLUGINS)
+ if (context.request_id && !context.is_pepper_menu)
+ HandleAuthorizeAllPlugins();
+#endif
+ source_web_contents_->ExecuteCustomContextMenuCommand(action, context);
+ return;
+ }
+ command_executed_ = false;
+}
+
+void RenderViewContextMenuBase::MenuWillShow(ui::SimpleMenuModel* source) {
+ for (int i = 0; i < source->GetItemCount(); ++i) {
+ if (source->IsVisibleAt(i) &&
+ source->GetTypeAt(i) != ui::MenuModel::TYPE_SEPARATOR) {
+ RecordShownItem(source->GetCommandIdAt(i));
+ }
+ }
+
+ // Ignore notifications from submenus.
+ if (source != &menu_model_)
+ return;
+
+ content::RenderWidgetHostView* view =
+ source_web_contents_->GetRenderWidgetHostView();
+ if (view)
+ view->SetShowingContextMenu(true);
+
+ NotifyMenuShown();
+}
+
+void RenderViewContextMenuBase::MenuClosed(ui::SimpleMenuModel* source) {
+ // Ignore notifications from submenus.
+ if (source != &menu_model_)
+ return;
+
+ content::RenderWidgetHostView* view =
+ source_web_contents_->GetRenderWidgetHostView();
+ if (view)
+ view->SetShowingContextMenu(false);
+ source_web_contents_->NotifyContextMenuClosed(params_.custom_context);
+
+ if (!command_executed_) {
+ FOR_EACH_OBSERVER(RenderViewContextMenuObserver,
+ observers_,
+ OnMenuCancel());
+ }
+}
+
+RenderFrameHost* RenderViewContextMenuBase::GetRenderFrameHost() {
+ return RenderFrameHost::FromID(render_process_id_, render_frame_id_);
+}
+
+// Controller functions --------------------------------------------------------
+
+void RenderViewContextMenuBase::OpenURL(
+ const GURL& url, const GURL& referring_url,
+ WindowOpenDisposition disposition,
+ content::PageTransition transition) {
+ content::Referrer referrer(referring_url.GetAsReferrer(),
+ params_.referrer_policy);
+
+ if (params_.link_url == url && disposition != OFF_THE_RECORD)
+ params_.custom_context.link_followed = url;
+
+ WebContents* new_contents = source_web_contents_->OpenURL(OpenURLParams(
+ url, referrer, disposition, transition, false));
+ if (!new_contents)
+ return;
+
+ NotifyURLOpened(url, new_contents);
+}
+
+bool RenderViewContextMenuBase::IsCustomItemChecked(int id) const {
+ return IsCustomItemCheckedInternal(params_.custom_items, id);
+}
+
+bool RenderViewContextMenuBase::IsCustomItemEnabled(int id) const {
+ return IsCustomItemEnabledInternal(params_.custom_items, id);
+}
+

Powered by Google App Engine
This is Rietveld 408576698