Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / context_menu_matcher.cc
index 0e7adbd..18a0058 100644 (file)
@@ -2,38 +2,74 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/extensions/context_menu_matcher.h"
+
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
-#include "chrome/browser/extensions/context_menu_matcher.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_util.h"
-#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/common/context_menu_params.h"
 #include "extensions/browser/extension_system.h"
 #include "ui/gfx/favicon_size.h"
 #include "ui/gfx/image/image.h"
 
+#if defined(ENABLE_EXTENSIONS)
+#include "chrome/common/extensions/api/context_menus.h"
+#endif
+
 namespace extensions {
 
+namespace {
+
+int GetActionMenuTopLevelLimit() {
+#if defined(ENABLE_EXTENSIONS)
+  return api::context_menus::ACTION_MENU_TOP_LEVEL_LIMIT;
+#else
+  return 0;
+#endif
+}
+
+// The range of command IDs reserved for extension's custom menus.
+// TODO(oshima): These values will be injected by embedders.
+int extensions_context_custom_first = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
+int extensions_context_custom_last = IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST;
+
+}  // namespace
+
 // static
 const size_t ContextMenuMatcher::kMaxExtensionItemTitleLength = 75;
 
+// static
+int ContextMenuMatcher::ConvertToExtensionsCustomCommandId(int id) {
+  return extensions_context_custom_first + id;
+}
+
+// static
+bool ContextMenuMatcher::IsExtensionsCustomCommandId(int id) {
+  return id >= extensions_context_custom_first &&
+         id <= extensions_context_custom_last;
+}
+
 ContextMenuMatcher::ContextMenuMatcher(
-    Profile* profile,
+    content::BrowserContext* browser_context,
     ui::SimpleMenuModel::Delegate* delegate,
     ui::SimpleMenuModel* menu_model,
     const base::Callback<bool(const MenuItem*)>& filter)
-    : profile_(profile), menu_model_(menu_model), delegate_(delegate),
+    : browser_context_(browser_context),
+      menu_model_(menu_model),
+      delegate_(delegate),
       filter_(filter) {
 }
 
 void ContextMenuMatcher::AppendExtensionItems(
     const MenuItem::ExtensionKey& extension_key,
     const base::string16& selection_text,
-    int* index) {
+    int* index,
+    bool is_action_menu) {
   DCHECK_GE(*index, 0);
   int max_index =
-      IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST - IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
+      extensions_context_custom_last - extensions_context_custom_first;
   if (*index >= max_index)
     return;
 
@@ -54,13 +90,21 @@ void ContextMenuMatcher::AppendExtensionItems(
 
   // Extensions (other than platform apps) are only allowed one top-level slot
   // (and it can't be a radio or checkbox item because we are going to put the
-  // extension icon next to it).
-  // If they have more than that, we automatically push them into a submenu.
-  if (extension->is_platform_app()) {
-    RecursivelyAppendExtensionItems(items, can_cross_incognito, selection_text,
-                                    menu_model_, index);
+  // extension icon next to it), unless the context menu is an an action menu.
+  // Action menus do not include the extension action, and they only include
+  // items from one extension, so they are not placed within a submenu.
+  // Otherwise, we automatically push them into a submenu if there is more than
+  // one top-level item.
+  if (extension->is_platform_app() || is_action_menu) {
+    RecursivelyAppendExtensionItems(items,
+                                    can_cross_incognito,
+                                    selection_text,
+                                    menu_model_,
+                                    index,
+                                    is_action_menu);
   } else {
-    int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++;
+    int menu_id = ConvertToExtensionsCustomCommandId(*index);
+    (*index)++;
     base::string16 title;
     MenuItem::List submenu_items;
 
@@ -83,10 +127,15 @@ void ContextMenuMatcher::AppendExtensionItems(
       ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate_);
       extension_menu_models_.push_back(submenu);
       menu_model_->AddSubMenu(menu_id, title, submenu);
-      RecursivelyAppendExtensionItems(submenu_items, can_cross_incognito,
-                                      selection_text, submenu, index);
+      RecursivelyAppendExtensionItems(submenu_items,
+                                      can_cross_incognito,
+                                      selection_text,
+                                      submenu,
+                                      index,
+                                      false);  // is_action_menu_top_level
     }
-    SetExtensionIcon(extension_key.extension_id);
+    if (!is_action_menu)
+      SetExtensionIcon(extension_key.extension_id);
   }
 }
 
@@ -139,8 +188,8 @@ void ContextMenuMatcher::ExecuteCommand(int command_id,
   if (!item)
     return;
 
-  MenuManager* manager = MenuManager::Get(profile_);
-  manager->ExecuteCommand(profile_, web_contents, params, item->id());
+  MenuManager* manager = MenuManager::Get(browser_context_);
+  manager->ExecuteCommand(browser_context_, web_contents, params, item->id());
 }
 
 bool ContextMenuMatcher::GetRelevantExtensionTopLevelItems(
@@ -149,19 +198,19 @@ bool ContextMenuMatcher::GetRelevantExtensionTopLevelItems(
     bool* can_cross_incognito,
     MenuItem::List& items) {
   ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile_)->extension_service();
+      extensions::ExtensionSystem::Get(browser_context_)->extension_service();
   *extension = service->GetExtensionById(extension_key.extension_id, false);
 
   if (!*extension)
     return false;
 
   // Find matching items.
-  MenuManager* manager = MenuManager::Get(profile_);
+  MenuManager* manager = MenuManager::Get(browser_context_);
   const MenuItem::List* all_items = manager->MenuItems(extension_key);
   if (!all_items || all_items->empty())
     return false;
 
-  *can_cross_incognito = util::CanCrossIncognito(*extension, profile_);
+  *can_cross_incognito = util::CanCrossIncognito(*extension, browser_context_);
   items = GetRelevantExtensionItems(*all_items,
                                     *can_cross_incognito);
 
@@ -179,7 +228,7 @@ MenuItem::List ContextMenuMatcher::GetRelevantExtensionItems(
     if (!filter_.Run(item))
       continue;
 
-    if (item->id().incognito == profile_->IsOffTheRecord() ||
+    if (item->id().incognito == browser_context_->IsOffTheRecord() ||
         can_cross_incognito)
       result.push_back(*i);
   }
@@ -191,10 +240,11 @@ void ContextMenuMatcher::RecursivelyAppendExtensionItems(
     bool can_cross_incognito,
     const base::string16& selection_text,
     ui::SimpleMenuModel* menu_model,
-    int* index)
-{
+    int* index,
+    bool is_action_menu_top_level) {
   MenuItem::Type last_type = MenuItem::NORMAL;
   int radio_group_id = 1;
+  int num_items = 0;
 
   for (MenuItem::List::const_iterator i = items.begin();
        i != items.end(); ++i) {
@@ -208,9 +258,16 @@ void ContextMenuMatcher::RecursivelyAppendExtensionItems(
       last_type = MenuItem::SEPARATOR;
     }
 
-    int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++;
-    if (menu_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST)
+    int menu_id = ConvertToExtensionsCustomCommandId(*index);
+    ++(*index);
+    ++num_items;
+    // Action context menus have a limit for top level extension items to
+    // prevent control items from being pushed off the screen, since extension
+    // items will not be placed in a submenu.
+    if (menu_id >= extensions_context_custom_last ||
+        (is_action_menu_top_level && num_items >= GetActionMenuTopLevelLimit()))
       return;
+
     extension_item_map_[menu_id] = item->id();
     base::string16 title = item->TitleWithReplacement(selection_text,
                                                 kMaxExtensionItemTitleLength);
@@ -223,8 +280,12 @@ void ContextMenuMatcher::RecursivelyAppendExtensionItems(
         ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate_);
         extension_menu_models_.push_back(submenu);
         menu_model->AddSubMenu(menu_id, title, submenu);
-        RecursivelyAppendExtensionItems(children, can_cross_incognito,
-                                        selection_text, submenu, index);
+        RecursivelyAppendExtensionItems(children,
+                                        can_cross_incognito,
+                                        selection_text,
+                                        submenu,
+                                        index,
+                                        false);  // is_action_menu_top_level
       }
     } else if (item->type() == MenuItem::CHECKBOX) {
       menu_model->AddCheckItem(menu_id, title);
@@ -246,7 +307,7 @@ void ContextMenuMatcher::RecursivelyAppendExtensionItems(
 }
 
 MenuItem* ContextMenuMatcher::GetExtensionMenuItem(int id) const {
-  MenuManager* manager = MenuManager::Get(profile_);
+  MenuManager* manager = MenuManager::Get(browser_context_);
   std::map<int, MenuItem::Id>::const_iterator i =
       extension_item_map_.find(id);
   if (i != extension_item_map_.end()) {
@@ -258,7 +319,7 @@ MenuItem* ContextMenuMatcher::GetExtensionMenuItem(int id) const {
 }
 
 void ContextMenuMatcher::SetExtensionIcon(const std::string& extension_id) {
-  MenuManager* menu_manager = MenuManager::Get(profile_);
+  MenuManager* menu_manager = MenuManager::Get(browser_context_);
 
   int index = menu_model_->GetItemCount() - 1;
   DCHECK_GE(index, 0);