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

Side by Side Diff: chrome/browser/extensions/context_menu_matcher.cc

Issue 359493005: Extend contextMenus API to support browser/page actions (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix android compile error Created 6 years, 4 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/context_menu_matcher.h" 5 #include "chrome/browser/extensions/context_menu_matcher.h"
6 6
7 #include "base/strings/utf_string_conversions.h" 7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/app/chrome_command_ids.h" 8 #include "chrome/app/chrome_command_ids.h"
9 #include "chrome/browser/extensions/extension_service.h" 9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/extensions/extension_util.h" 10 #include "chrome/browser/extensions/extension_util.h"
11 #include "content/public/browser/browser_context.h" 11 #include "content/public/browser/browser_context.h"
12 #include "content/public/common/context_menu_params.h" 12 #include "content/public/common/context_menu_params.h"
13 #include "extensions/browser/extension_system.h" 13 #include "extensions/browser/extension_system.h"
14 #include "ui/gfx/favicon_size.h" 14 #include "ui/gfx/favicon_size.h"
15 #include "ui/gfx/image/image.h" 15 #include "ui/gfx/image/image.h"
16 16
17 #if defined(ENABLE_EXTENSIONS)
18 #include "chrome/common/extensions/api/context_menus.h"
19 #endif
20
17 namespace extensions { 21 namespace extensions {
18 22
19 namespace { 23 namespace {
20 24
25 #if defined(ENABLE_EXTENSIONS)
26 int action_menu_top_level_limit =
27 api::context_menus::ACTION_MENU_TOP_LEVEL_LIMIT;
gpdavis 2014/08/08 21:01:53 Is this the problematic static initializer that's
28 #else
29 int action_menu_top_level_limit = 0;
30 #endif
31
21 // The range of command IDs reserved for extension's custom menus. 32 // The range of command IDs reserved for extension's custom menus.
22 // TODO(oshima): These values will be injected by embedders. 33 // TODO(oshima): These values will be injected by embedders.
23 int extensions_context_custom_first = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST; 34 int extensions_context_custom_first = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
24 int extensions_context_custom_last = IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST; 35 int extensions_context_custom_last = IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST;
25 36
26 } // namespace 37 } // namespace
27 38
28 // static 39 // static
29 const size_t ContextMenuMatcher::kMaxExtensionItemTitleLength = 75; 40 const size_t ContextMenuMatcher::kMaxExtensionItemTitleLength = 75;
30 41
(...skipping 15 matching lines...) Expand all
46 const base::Callback<bool(const MenuItem*)>& filter) 57 const base::Callback<bool(const MenuItem*)>& filter)
47 : browser_context_(browser_context), 58 : browser_context_(browser_context),
48 menu_model_(menu_model), 59 menu_model_(menu_model),
49 delegate_(delegate), 60 delegate_(delegate),
50 filter_(filter) { 61 filter_(filter) {
51 } 62 }
52 63
53 void ContextMenuMatcher::AppendExtensionItems( 64 void ContextMenuMatcher::AppendExtensionItems(
54 const MenuItem::ExtensionKey& extension_key, 65 const MenuItem::ExtensionKey& extension_key,
55 const base::string16& selection_text, 66 const base::string16& selection_text,
56 int* index) { 67 int* index,
68 bool is_action_menu) {
57 DCHECK_GE(*index, 0); 69 DCHECK_GE(*index, 0);
58 int max_index = 70 int max_index =
59 extensions_context_custom_last - extensions_context_custom_first; 71 extensions_context_custom_last - extensions_context_custom_first;
60 if (*index >= max_index) 72 if (*index >= max_index)
61 return; 73 return;
62 74
63 const Extension* extension = NULL; 75 const Extension* extension = NULL;
64 MenuItem::List items; 76 MenuItem::List items;
65 bool can_cross_incognito; 77 bool can_cross_incognito;
66 if (!GetRelevantExtensionTopLevelItems( 78 if (!GetRelevantExtensionTopLevelItems(
67 extension_key, &extension, &can_cross_incognito, items)) 79 extension_key, &extension, &can_cross_incognito, items))
68 return; 80 return;
69 81
70 if (items.empty()) 82 if (items.empty())
71 return; 83 return;
72 84
73 // If this is the first extension-provided menu item, and there are other 85 // If this is the first extension-provided menu item, and there are other
74 // items in the menu, and the last item is not a separator add a separator. 86 // items in the menu, and the last item is not a separator add a separator.
75 if (*index == 0 && menu_model_->GetItemCount()) 87 if (*index == 0 && menu_model_->GetItemCount())
76 menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); 88 menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);
77 89
78 // Extensions (other than platform apps) are only allowed one top-level slot 90 // Extensions (other than platform apps) are only allowed one top-level slot
79 // (and it can't be a radio or checkbox item because we are going to put the 91 // (and it can't be a radio or checkbox item because we are going to put the
80 // extension icon next to it). 92 // extension icon next to it), unless the context menu is an an action menu.
81 // If they have more than that, we automatically push them into a submenu. 93 // Action menus do not include the extension action, and they only include
82 if (extension->is_platform_app()) { 94 // items from one extension, so they are not placed within a submenu.
83 RecursivelyAppendExtensionItems(items, can_cross_incognito, selection_text, 95 // Otherwise, we automatically push them into a submenu if there is more than
84 menu_model_, index); 96 // one top-level item.
97 if (extension->is_platform_app() || is_action_menu) {
98 RecursivelyAppendExtensionItems(items,
99 can_cross_incognito,
100 selection_text,
101 menu_model_,
102 index,
103 is_action_menu);
85 } else { 104 } else {
86 int menu_id = ConvertToExtensionsCustomCommandId(*index); 105 int menu_id = ConvertToExtensionsCustomCommandId(*index);
87 (*index)++; 106 (*index)++;
88 base::string16 title; 107 base::string16 title;
89 MenuItem::List submenu_items; 108 MenuItem::List submenu_items;
90 109
91 if (items.size() > 1 || items[0]->type() != MenuItem::NORMAL) { 110 if (items.size() > 1 || items[0]->type() != MenuItem::NORMAL) {
92 title = base::UTF8ToUTF16(extension->name()); 111 title = base::UTF8ToUTF16(extension->name());
93 submenu_items = items; 112 submenu_items = items;
94 } else { 113 } else {
95 MenuItem* item = items[0]; 114 MenuItem* item = items[0];
96 extension_item_map_[menu_id] = item->id(); 115 extension_item_map_[menu_id] = item->id();
97 title = item->TitleWithReplacement(selection_text, 116 title = item->TitleWithReplacement(selection_text,
98 kMaxExtensionItemTitleLength); 117 kMaxExtensionItemTitleLength);
99 submenu_items = GetRelevantExtensionItems(item->children(), 118 submenu_items = GetRelevantExtensionItems(item->children(),
100 can_cross_incognito); 119 can_cross_incognito);
101 } 120 }
102 121
103 // Now add our item(s) to the menu_model_. 122 // Now add our item(s) to the menu_model_.
104 if (submenu_items.empty()) { 123 if (submenu_items.empty()) {
105 menu_model_->AddItem(menu_id, title); 124 menu_model_->AddItem(menu_id, title);
106 } else { 125 } else {
107 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate_); 126 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate_);
108 extension_menu_models_.push_back(submenu); 127 extension_menu_models_.push_back(submenu);
109 menu_model_->AddSubMenu(menu_id, title, submenu); 128 menu_model_->AddSubMenu(menu_id, title, submenu);
110 RecursivelyAppendExtensionItems(submenu_items, can_cross_incognito, 129 RecursivelyAppendExtensionItems(submenu_items,
111 selection_text, submenu, index); 130 can_cross_incognito,
131 selection_text,
132 submenu,
133 index,
134 false); // is_action_menu_top_level
112 } 135 }
113 SetExtensionIcon(extension_key.extension_id); 136 if (!is_action_menu)
137 SetExtensionIcon(extension_key.extension_id);
114 } 138 }
115 } 139 }
116 140
117 void ContextMenuMatcher::Clear() { 141 void ContextMenuMatcher::Clear() {
118 extension_item_map_.clear(); 142 extension_item_map_.clear();
119 extension_menu_models_.clear(); 143 extension_menu_models_.clear();
120 } 144 }
121 145
122 base::string16 ContextMenuMatcher::GetTopLevelContextMenuTitle( 146 base::string16 ContextMenuMatcher::GetTopLevelContextMenuTitle(
123 const MenuItem::ExtensionKey& extension_key, 147 const MenuItem::ExtensionKey& extension_key,
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 result.push_back(*i); 232 result.push_back(*i);
209 } 233 }
210 return result; 234 return result;
211 } 235 }
212 236
213 void ContextMenuMatcher::RecursivelyAppendExtensionItems( 237 void ContextMenuMatcher::RecursivelyAppendExtensionItems(
214 const MenuItem::List& items, 238 const MenuItem::List& items,
215 bool can_cross_incognito, 239 bool can_cross_incognito,
216 const base::string16& selection_text, 240 const base::string16& selection_text,
217 ui::SimpleMenuModel* menu_model, 241 ui::SimpleMenuModel* menu_model,
218 int* index) 242 int* index,
219 { 243 bool is_action_menu_top_level) {
220 MenuItem::Type last_type = MenuItem::NORMAL; 244 MenuItem::Type last_type = MenuItem::NORMAL;
221 int radio_group_id = 1; 245 int radio_group_id = 1;
246 int num_items = 0;
222 247
223 for (MenuItem::List::const_iterator i = items.begin(); 248 for (MenuItem::List::const_iterator i = items.begin();
224 i != items.end(); ++i) { 249 i != items.end(); ++i) {
225 MenuItem* item = *i; 250 MenuItem* item = *i;
226 251
227 // If last item was of type radio but the current one isn't, auto-insert 252 // If last item was of type radio but the current one isn't, auto-insert
228 // a separator. The converse case is handled below. 253 // a separator. The converse case is handled below.
229 if (last_type == MenuItem::RADIO && 254 if (last_type == MenuItem::RADIO &&
230 item->type() != MenuItem::RADIO) { 255 item->type() != MenuItem::RADIO) {
231 menu_model->AddSeparator(ui::NORMAL_SEPARATOR); 256 menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
232 last_type = MenuItem::SEPARATOR; 257 last_type = MenuItem::SEPARATOR;
233 } 258 }
234 259
235 int menu_id = ConvertToExtensionsCustomCommandId(*index); 260 int menu_id = ConvertToExtensionsCustomCommandId(*index);
236 (*index)++; 261 ++(*index);
237 if (menu_id >= extensions_context_custom_last) 262 ++num_items;
263 // Action context menus have a limit for top level extension items to
264 // prevent control items from being pushed off the screen, since extension
265 // items will not be placed in a submenu.
266 if (menu_id >= extensions_context_custom_last ||
267 (is_action_menu_top_level && num_items >= action_menu_top_level_limit))
238 return; 268 return;
269
239 extension_item_map_[menu_id] = item->id(); 270 extension_item_map_[menu_id] = item->id();
240 base::string16 title = item->TitleWithReplacement(selection_text, 271 base::string16 title = item->TitleWithReplacement(selection_text,
241 kMaxExtensionItemTitleLength); 272 kMaxExtensionItemTitleLength);
242 if (item->type() == MenuItem::NORMAL) { 273 if (item->type() == MenuItem::NORMAL) {
243 MenuItem::List children = 274 MenuItem::List children =
244 GetRelevantExtensionItems(item->children(), can_cross_incognito); 275 GetRelevantExtensionItems(item->children(), can_cross_incognito);
245 if (children.empty()) { 276 if (children.empty()) {
246 menu_model->AddItem(menu_id, title); 277 menu_model->AddItem(menu_id, title);
247 } else { 278 } else {
248 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate_); 279 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate_);
249 extension_menu_models_.push_back(submenu); 280 extension_menu_models_.push_back(submenu);
250 menu_model->AddSubMenu(menu_id, title, submenu); 281 menu_model->AddSubMenu(menu_id, title, submenu);
251 RecursivelyAppendExtensionItems(children, can_cross_incognito, 282 RecursivelyAppendExtensionItems(children,
252 selection_text, submenu, index); 283 can_cross_incognito,
284 selection_text,
285 submenu,
286 index,
287 false); // is_action_menu_top_level
253 } 288 }
254 } else if (item->type() == MenuItem::CHECKBOX) { 289 } else if (item->type() == MenuItem::CHECKBOX) {
255 menu_model->AddCheckItem(menu_id, title); 290 menu_model->AddCheckItem(menu_id, title);
256 } else if (item->type() == MenuItem::RADIO) { 291 } else if (item->type() == MenuItem::RADIO) {
257 if (i != items.begin() && 292 if (i != items.begin() &&
258 last_type != MenuItem::RADIO) { 293 last_type != MenuItem::RADIO) {
259 radio_group_id++; 294 radio_group_id++;
260 295
261 // Auto-append a separator if needed. 296 // Auto-append a separator if needed.
262 menu_model->AddSeparator(ui::NORMAL_SEPARATOR); 297 menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
(...skipping 26 matching lines...) Expand all
289 DCHECK_GE(index, 0); 324 DCHECK_GE(index, 0);
290 325
291 const SkBitmap& icon = menu_manager->GetIconForExtension(extension_id); 326 const SkBitmap& icon = menu_manager->GetIconForExtension(extension_id);
292 DCHECK(icon.width() == gfx::kFaviconSize); 327 DCHECK(icon.width() == gfx::kFaviconSize);
293 DCHECK(icon.height() == gfx::kFaviconSize); 328 DCHECK(icon.height() == gfx::kFaviconSize);
294 329
295 menu_model_->SetIcon(index, gfx::Image::CreateFrom1xBitmap(icon)); 330 menu_model_->SetIcon(index, gfx::Image::CreateFrom1xBitmap(icon));
296 } 331 }
297 332
298 } // namespace extensions 333 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/browser/extensions/context_menu_matcher.h ('k') | chrome/browser/extensions/extension_context_menu_model.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698