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

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