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
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/menu_manager.h"
9 #include "base/json/json_writer.h"
10 #include "base/logging.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/values.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/extensions/event_names.h"
17 #include "chrome/browser/extensions/extension_service.h"
18 #include "chrome/browser/extensions/extension_tab_util.h"
19 #include "chrome/browser/extensions/menu_manager_factory.h"
20 #include "chrome/browser/extensions/state_store.h"
21 #include "chrome/browser/extensions/tab_helper.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/common/extensions/api/context_menus.h"
24 #include "content/public/browser/notification_details.h"
25 #include "content/public/browser/notification_service.h"
26 #include "content/public/browser/notification_source.h"
27 #include "content/public/browser/web_contents.h"
28 #include "content/public/common/context_menu_params.h"
29 #include "extensions/browser/event_router.h"
30 #include "extensions/browser/extension_system.h"
31 #include "extensions/common/extension.h"
32 #include "extensions/common/manifest_handlers/background_info.h"
33 #include "ui/gfx/favicon_size.h"
34 #include "ui/gfx/text_elider.h"
36 using content::WebContents;
37 using extensions::ExtensionSystem;
39 namespace extensions {
41 namespace context_menus = api::context_menus;
45 // Keys for serialization to and from Value to store in the preferences.
46 const char kContextMenusKey[] = "context_menus";
48 const char kCheckedKey[] = "checked";
49 const char kContextsKey[] = "contexts";
50 const char kDocumentURLPatternsKey[] = "document_url_patterns";
51 const char kEnabledKey[] = "enabled";
52 const char kIncognitoKey[] = "incognito";
53 const char kParentUIDKey[] = "parent_uid";
54 const char kStringUIDKey[] = "string_uid";
55 const char kTargetURLPatternsKey[] = "target_url_patterns";
56 const char kTitleKey[] = "title";
57 const char kTypeKey[] = "type";
59 void SetIdKeyValue(base::DictionaryValue* properties,
61 const MenuItem::Id& id) {
63 properties->SetString(key, id.string_uid);
65 properties->SetInteger(key, id.uid);
68 MenuItem::List MenuItemsFromValue(const std::string& extension_id,
72 base::ListValue* list = NULL;
73 if (!value || !value->GetAsList(&list))
76 for (size_t i = 0; i < list->GetSize(); ++i) {
77 base::DictionaryValue* dict = NULL;
78 if (!list->GetDictionary(i, &dict))
80 MenuItem* item = MenuItem::Populate(
81 extension_id, *dict, NULL);
84 items.push_back(item);
89 scoped_ptr<base::Value> MenuItemsToValue(const MenuItem::List& items) {
90 scoped_ptr<base::ListValue> list(new base::ListValue());
91 for (size_t i = 0; i < items.size(); ++i)
92 list->Append(items[i]->ToValue().release());
93 return scoped_ptr<base::Value>(list.release());
96 bool GetStringList(const base::DictionaryValue& dict,
97 const std::string& key,
98 std::vector<std::string>* out) {
99 if (!dict.HasKey(key))
102 const base::ListValue* list = NULL;
103 if (!dict.GetListWithoutPathExpansion(key, &list))
106 for (size_t i = 0; i < list->GetSize(); ++i) {
108 if (!list->GetString(i, &pattern))
110 out->push_back(pattern);
118 MenuItem::MenuItem(const Id& id,
119 const std::string& title,
123 const ContextList& contexts)
129 contexts_(contexts) {}
131 MenuItem::~MenuItem() {
132 STLDeleteElements(&children_);
135 MenuItem* MenuItem::ReleaseChild(const Id& child_id,
137 for (List::iterator i = children_.begin(); i != children_.end(); ++i) {
138 MenuItem* child = NULL;
139 if ((*i)->id() == child_id) {
143 } else if (recursive) {
144 child = (*i)->ReleaseChild(child_id, recursive);
152 void MenuItem::GetFlattenedSubtree(MenuItem::List* list) {
153 list->push_back(this);
154 for (List::iterator i = children_.begin(); i != children_.end(); ++i)
155 (*i)->GetFlattenedSubtree(list);
158 std::set<MenuItem::Id> MenuItem::RemoveAllDescendants() {
160 for (List::iterator i = children_.begin(); i != children_.end(); ++i) {
161 MenuItem* child = *i;
162 result.insert(child->id());
163 std::set<Id> removed = child->RemoveAllDescendants();
164 result.insert(removed.begin(), removed.end());
166 STLDeleteElements(&children_);
170 base::string16 MenuItem::TitleWithReplacement(const base::string16& selection,
171 size_t max_length) const {
172 base::string16 result = base::UTF8ToUTF16(title_);
173 // TODO(asargent) - Change this to properly handle %% escaping so you can
174 // put "%s" in titles that won't get substituted.
175 ReplaceSubstringsAfterOffset(&result, 0, base::ASCIIToUTF16("%s"), selection);
177 if (result.length() > max_length)
178 result = gfx::TruncateString(result, max_length);
182 bool MenuItem::SetChecked(bool checked) {
183 if (type_ != CHECKBOX && type_ != RADIO)
189 void MenuItem::AddChild(MenuItem* item) {
190 item->parent_id_.reset(new Id(id_));
191 children_.push_back(item);
194 scoped_ptr<base::DictionaryValue> MenuItem::ToValue() const {
195 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue);
196 // Should only be called for extensions with event pages, which only have
197 // string IDs for items.
198 DCHECK_EQ(0, id_.uid);
199 value->SetString(kStringUIDKey, id_.string_uid);
200 value->SetBoolean(kIncognitoKey, id_.incognito);
201 value->SetInteger(kTypeKey, type_);
202 if (type_ != SEPARATOR)
203 value->SetString(kTitleKey, title_);
204 if (type_ == CHECKBOX || type_ == RADIO)
205 value->SetBoolean(kCheckedKey, checked_);
206 value->SetBoolean(kEnabledKey, enabled_);
207 value->Set(kContextsKey, contexts_.ToValue().release());
209 DCHECK_EQ(0, parent_id_->uid);
210 value->SetString(kParentUIDKey, parent_id_->string_uid);
212 value->Set(kDocumentURLPatternsKey,
213 document_url_patterns_.ToValue().release());
214 value->Set(kTargetURLPatternsKey, target_url_patterns_.ToValue().release());
219 MenuItem* MenuItem::Populate(const std::string& extension_id,
220 const base::DictionaryValue& value,
221 std::string* error) {
222 bool incognito = false;
223 if (!value.GetBoolean(kIncognitoKey, &incognito))
225 Id id(incognito, extension_id);
226 if (!value.GetString(kStringUIDKey, &id.string_uid))
230 if (!value.GetInteger(kTypeKey, &type_int))
232 type = static_cast<Type>(type_int);
234 if (type != SEPARATOR && !value.GetString(kTitleKey, &title))
236 bool checked = false;
237 if ((type == CHECKBOX || type == RADIO) &&
238 !value.GetBoolean(kCheckedKey, &checked)) {
242 if (!value.GetBoolean(kEnabledKey, &enabled))
244 ContextList contexts;
245 const base::Value* contexts_value = NULL;
246 if (!value.Get(kContextsKey, &contexts_value))
248 if (!contexts.Populate(*contexts_value))
251 scoped_ptr<MenuItem> result(new MenuItem(
252 id, title, checked, enabled, type, contexts));
254 std::vector<std::string> document_url_patterns;
255 if (!GetStringList(value, kDocumentURLPatternsKey, &document_url_patterns))
257 std::vector<std::string> target_url_patterns;
258 if (!GetStringList(value, kTargetURLPatternsKey, &target_url_patterns))
261 if (!result->PopulateURLPatterns(&document_url_patterns,
262 &target_url_patterns,
267 // parent_id is filled in from the value, but it might not be valid. It's left
268 // to be validated upon being added (via AddChildItem) to the menu manager.
269 scoped_ptr<Id> parent_id(new Id(incognito, extension_id));
270 if (value.HasKey(kParentUIDKey)) {
271 if (!value.GetString(kParentUIDKey, &parent_id->string_uid))
273 result->parent_id_.swap(parent_id);
275 return result.release();
278 bool MenuItem::PopulateURLPatterns(
279 std::vector<std::string>* document_url_patterns,
280 std::vector<std::string>* target_url_patterns,
281 std::string* error) {
282 if (document_url_patterns) {
283 if (!document_url_patterns_.Populate(
284 *document_url_patterns, URLPattern::SCHEME_ALL, true, error)) {
288 if (target_url_patterns) {
289 if (!target_url_patterns_.Populate(
290 *target_url_patterns, URLPattern::SCHEME_ALL, true, error)) {
297 MenuManager::MenuManager(Profile* profile, StateStore* store)
298 : profile_(profile), store_(store) {
299 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
300 content::Source<Profile>(profile));
301 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
302 content::Source<Profile>(profile));
303 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
304 content::NotificationService::AllSources());
306 store_->RegisterKey(kContextMenusKey);
309 MenuManager::~MenuManager() {
310 MenuItemMap::iterator i;
311 for (i = context_items_.begin(); i != context_items_.end(); ++i) {
312 STLDeleteElements(&(i->second));
317 MenuManager* MenuManager::Get(Profile* profile) {
318 return MenuManagerFactory::GetForProfile(profile);
321 std::set<std::string> MenuManager::ExtensionIds() {
322 std::set<std::string> id_set;
323 for (MenuItemMap::const_iterator i = context_items_.begin();
324 i != context_items_.end(); ++i) {
325 id_set.insert(i->first);
330 const MenuItem::List* MenuManager::MenuItems(
331 const std::string& extension_id) {
332 MenuItemMap::iterator i = context_items_.find(extension_id);
333 if (i != context_items_.end()) {
339 bool MenuManager::AddContextItem(
340 const Extension* extension,
342 const std::string& extension_id = item->extension_id();
343 // The item must have a non-empty extension id, and not have already been
345 if (extension_id.empty() || ContainsKey(items_by_id_, item->id()))
348 DCHECK_EQ(extension->id(), extension_id);
350 bool first_item = !ContainsKey(context_items_, extension_id);
351 context_items_[extension_id].push_back(item);
352 items_by_id_[item->id()] = item;
354 if (item->type() == MenuItem::RADIO) {
356 RadioItemSelected(item);
358 SanitizeRadioList(context_items_[extension_id]);
361 // If this is the first item for this extension, start loading its icon.
363 icon_manager_.LoadIcon(profile_, extension);
368 bool MenuManager::AddChildItem(const MenuItem::Id& parent_id,
370 MenuItem* parent = GetItemById(parent_id);
371 if (!parent || parent->type() != MenuItem::NORMAL ||
372 parent->incognito() != child->incognito() ||
373 parent->extension_id() != child->extension_id() ||
374 ContainsKey(items_by_id_, child->id()))
376 parent->AddChild(child);
377 items_by_id_[child->id()] = child;
379 if (child->type() == MenuItem::RADIO)
380 SanitizeRadioList(parent->children());
384 bool MenuManager::DescendantOf(MenuItem* item,
385 const MenuItem::Id& ancestor_id) {
386 // Work our way up the tree until we find the ancestor or NULL.
387 MenuItem::Id* id = item->parent_id();
389 DCHECK(*id != item->id()); // Catch circular graphs.
390 if (*id == ancestor_id)
392 MenuItem* next = GetItemById(*id);
397 id = next->parent_id();
402 bool MenuManager::ChangeParent(const MenuItem::Id& child_id,
403 const MenuItem::Id* parent_id) {
404 MenuItem* child = GetItemById(child_id);
405 MenuItem* new_parent = parent_id ? GetItemById(*parent_id) : NULL;
406 if ((parent_id && (child_id == *parent_id)) || !child ||
407 (!new_parent && parent_id != NULL) ||
408 (new_parent && (DescendantOf(new_parent, child_id) ||
409 child->incognito() != new_parent->incognito() ||
410 child->extension_id() != new_parent->extension_id())))
413 MenuItem::Id* old_parent_id = child->parent_id();
414 if (old_parent_id != NULL) {
415 MenuItem* old_parent = GetItemById(*old_parent_id);
421 old_parent->ReleaseChild(child_id, false /* non-recursive search*/);
422 DCHECK(taken == child);
423 SanitizeRadioList(old_parent->children());
425 // This is a top-level item, so we need to pull it out of our list of
427 MenuItemMap::iterator i = context_items_.find(child->extension_id());
428 if (i == context_items_.end()) {
432 MenuItem::List& list = i->second;
433 MenuItem::List::iterator j = std::find(list.begin(), list.end(),
435 if (j == list.end()) {
440 SanitizeRadioList(list);
444 new_parent->AddChild(child);
445 SanitizeRadioList(new_parent->children());
447 context_items_[child->extension_id()].push_back(child);
448 child->parent_id_.reset(NULL);
449 SanitizeRadioList(context_items_[child->extension_id()]);
454 bool MenuManager::RemoveContextMenuItem(const MenuItem::Id& id) {
455 if (!ContainsKey(items_by_id_, id))
458 MenuItem* menu_item = GetItemById(id);
460 std::string extension_id = menu_item->extension_id();
461 MenuItemMap::iterator i = context_items_.find(extension_id);
462 if (i == context_items_.end()) {
468 std::set<MenuItem::Id> items_removed;
469 MenuItem::List& list = i->second;
470 MenuItem::List::iterator j;
471 for (j = list.begin(); j < list.end(); ++j) {
472 // See if the current top-level item is a match.
473 if ((*j)->id() == id) {
474 items_removed = (*j)->RemoveAllDescendants();
475 items_removed.insert(id);
479 SanitizeRadioList(list);
482 // See if the item to remove was found as a descendant of the current
484 MenuItem* child = (*j)->ReleaseChild(id, true /* recursive */);
486 items_removed = child->RemoveAllDescendants();
487 items_removed.insert(id);
488 SanitizeRadioList(GetItemById(*child->parent_id())->children());
495 DCHECK(result); // The check at the very top should have prevented this.
497 // Clear entries from the items_by_id_ map.
498 std::set<MenuItem::Id>::iterator removed_iter;
499 for (removed_iter = items_removed.begin();
500 removed_iter != items_removed.end();
502 items_by_id_.erase(*removed_iter);
506 context_items_.erase(extension_id);
507 icon_manager_.RemoveIcon(extension_id);
512 void MenuManager::RemoveAllContextItems(const std::string& extension_id) {
513 MenuItem::List::iterator i;
514 for (i = context_items_[extension_id].begin();
515 i != context_items_[extension_id].end(); ++i) {
517 items_by_id_.erase(item->id());
519 // Remove descendants from this item and erase them from the lookup cache.
520 std::set<MenuItem::Id> removed_ids = item->RemoveAllDescendants();
521 std::set<MenuItem::Id>::const_iterator j;
522 for (j = removed_ids.begin(); j != removed_ids.end(); ++j) {
523 items_by_id_.erase(*j);
526 STLDeleteElements(&context_items_[extension_id]);
527 context_items_.erase(extension_id);
528 icon_manager_.RemoveIcon(extension_id);
531 MenuItem* MenuManager::GetItemById(const MenuItem::Id& id) const {
532 std::map<MenuItem::Id, MenuItem*>::const_iterator i =
533 items_by_id_.find(id);
534 if (i != items_by_id_.end())
540 void MenuManager::RadioItemSelected(MenuItem* item) {
541 // If this is a child item, we need to get a handle to the list from its
542 // parent. Otherwise get a handle to the top-level list.
543 const MenuItem::List* list = NULL;
544 if (item->parent_id()) {
545 MenuItem* parent = GetItemById(*item->parent_id());
550 list = &(parent->children());
552 if (context_items_.find(item->extension_id()) == context_items_.end()) {
556 list = &context_items_[item->extension_id()];
559 // Find where |item| is in the list.
560 MenuItem::List::const_iterator item_location;
561 for (item_location = list->begin(); item_location != list->end();
563 if (*item_location == item)
566 if (item_location == list->end()) {
567 NOTREACHED(); // We should have found the item.
571 // Iterate backwards from |item| and uncheck any adjacent radio items.
572 MenuItem::List::const_iterator i;
573 if (item_location != list->begin()) {
577 if ((*i)->type() != MenuItem::RADIO)
579 (*i)->SetChecked(false);
580 } while (i != list->begin());
583 // Now iterate forwards from |item| and uncheck any adjacent radio items.
584 for (i = item_location + 1; i != list->end(); ++i) {
585 if ((*i)->type() != MenuItem::RADIO)
587 (*i)->SetChecked(false);
591 static void AddURLProperty(base::DictionaryValue* dictionary,
592 const std::string& key, const GURL& url) {
594 dictionary->SetString(key, url.possibly_invalid_spec());
597 void MenuManager::ExecuteCommand(Profile* profile,
598 WebContents* web_contents,
599 const content::ContextMenuParams& params,
600 const MenuItem::Id& menu_item_id) {
601 EventRouter* event_router = extensions::ExtensionSystem::Get(profile)->
606 MenuItem* item = GetItemById(menu_item_id);
610 // ExtensionService/Extension can be NULL in unit tests :(
611 ExtensionService* service =
612 ExtensionSystem::Get(profile_)->extension_service();
613 const Extension* extension = service ?
614 service->extensions()->GetByID(menu_item_id.extension_id) : NULL;
616 if (item->type() == MenuItem::RADIO)
617 RadioItemSelected(item);
619 scoped_ptr<base::ListValue> args(new base::ListValue());
621 base::DictionaryValue* properties = new base::DictionaryValue();
622 SetIdKeyValue(properties, "menuItemId", item->id());
623 if (item->parent_id())
624 SetIdKeyValue(properties, "parentMenuItemId", *item->parent_id());
626 switch (params.media_type) {
627 case blink::WebContextMenuData::MediaTypeImage:
628 properties->SetString("mediaType", "image");
630 case blink::WebContextMenuData::MediaTypeVideo:
631 properties->SetString("mediaType", "video");
633 case blink::WebContextMenuData::MediaTypeAudio:
634 properties->SetString("mediaType", "audio");
636 default: {} // Do nothing.
639 AddURLProperty(properties, "linkUrl", params.unfiltered_link_url);
640 AddURLProperty(properties, "srcUrl", params.src_url);
641 AddURLProperty(properties, "pageUrl", params.page_url);
642 AddURLProperty(properties, "frameUrl", params.frame_url);
644 if (params.selection_text.length() > 0)
645 properties->SetString("selectionText", params.selection_text);
647 properties->SetBoolean("editable", params.is_editable);
649 args->Append(properties);
651 // Add the tab info to the argument list.
652 // No tab info in a platform app.
653 if (!extension || !extension->is_platform_app()) {
654 // Note: web_contents are NULL in unit tests :(
656 args->Append(ExtensionTabUtil::CreateTabValue(web_contents));
658 args->Append(new base::DictionaryValue());
662 if (item->type() == MenuItem::CHECKBOX ||
663 item->type() == MenuItem::RADIO) {
664 bool was_checked = item->checked();
665 properties->SetBoolean("wasChecked", was_checked);
667 // RADIO items always get set to true when you click on them, but CHECKBOX
668 // items get their state toggled.
670 (item->type() == MenuItem::RADIO) ? true : !was_checked;
672 item->SetChecked(checked);
673 properties->SetBoolean("checked", item->checked());
676 WriteToStorage(extension);
679 // Note: web_contents are NULL in unit tests :(
680 if (web_contents && extensions::TabHelper::FromWebContents(web_contents)) {
681 extensions::TabHelper::FromWebContents(web_contents)->
682 active_tab_permission_granter()->GrantIfRequested(extension);
686 scoped_ptr<Event> event(new Event(
687 event_names::kOnContextMenus,
688 scoped_ptr<base::ListValue>(args->DeepCopy())));
689 event->restrict_to_browser_context = profile;
690 event->user_gesture = EventRouter::USER_GESTURE_ENABLED;
691 event_router->DispatchEventToExtension(item->extension_id(), event.Pass());
694 scoped_ptr<Event> event(new Event(context_menus::OnClicked::kEventName,
696 event->restrict_to_browser_context = profile;
697 event->user_gesture = EventRouter::USER_GESTURE_ENABLED;
698 event_router->DispatchEventToExtension(item->extension_id(), event.Pass());
702 void MenuManager::SanitizeRadioList(const MenuItem::List& item_list) {
703 MenuItem::List::const_iterator i = item_list.begin();
704 while (i != item_list.end()) {
705 if ((*i)->type() != MenuItem::RADIO) {
710 // Uncheck any checked radio items in the run, and at the end reset
711 // the appropriate one to checked. If no check radio items were found,
712 // then check the first radio item in the run.
713 MenuItem::List::const_iterator last_checked = item_list.end();
714 MenuItem::List::const_iterator radio_run_iter;
715 for (radio_run_iter = i; radio_run_iter != item_list.end();
717 if ((*radio_run_iter)->type() != MenuItem::RADIO) {
721 if ((*radio_run_iter)->checked()) {
722 last_checked = radio_run_iter;
723 (*radio_run_iter)->SetChecked(false);
727 if (last_checked != item_list.end())
728 (*last_checked)->SetChecked(true);
730 (*i)->SetChecked(true);
736 bool MenuManager::ItemUpdated(const MenuItem::Id& id) {
737 if (!ContainsKey(items_by_id_, id))
740 MenuItem* menu_item = GetItemById(id);
743 if (menu_item->parent_id()) {
744 SanitizeRadioList(GetItemById(*menu_item->parent_id())->children());
746 std::string extension_id = menu_item->extension_id();
747 MenuItemMap::iterator i = context_items_.find(extension_id);
748 if (i == context_items_.end()) {
752 SanitizeRadioList(i->second);
758 void MenuManager::WriteToStorage(const Extension* extension) {
759 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
761 const MenuItem::List* top_items = MenuItems(extension->id());
762 MenuItem::List all_items;
764 for (MenuItem::List::const_iterator i = top_items->begin();
765 i != top_items->end(); ++i) {
766 (*i)->GetFlattenedSubtree(&all_items);
771 store_->SetExtensionValue(extension->id(), kContextMenusKey,
772 MenuItemsToValue(all_items));
775 void MenuManager::ReadFromStorage(const std::string& extension_id,
776 scoped_ptr<base::Value> value) {
777 const Extension* extension =
778 ExtensionSystem::Get(profile_)->extension_service()->extensions()->
779 GetByID(extension_id);
783 MenuItem::List items = MenuItemsFromValue(extension_id, value.get());
784 for (size_t i = 0; i < items.size(); ++i) {
785 if (items[i]->parent_id()) {
786 // Parent IDs are stored in the parent_id field for convenience, but
787 // they have not yet been validated. Separate them out here.
788 // Because of the order in which we store items in the prefs, parents will
789 // precede children, so we should already know about any parent items.
790 scoped_ptr<MenuItem::Id> parent_id;
791 parent_id.swap(items[i]->parent_id_);
792 AddChildItem(*parent_id, items[i]);
794 AddContextItem(extension, items[i]);
799 void MenuManager::Observe(int type,
800 const content::NotificationSource& source,
801 const content::NotificationDetails& details) {
803 case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
804 // Remove menu items for disabled/uninstalled extensions.
805 const Extension* extension =
806 content::Details<UnloadedExtensionInfo>(details)->extension;
807 if (ContainsKey(context_items_, extension->id())) {
808 RemoveAllContextItems(extension->id());
812 case chrome::NOTIFICATION_EXTENSION_LOADED: {
813 const Extension* extension =
814 content::Details<const Extension>(details).ptr();
815 if (store_ && BackgroundInfo::HasLazyBackgroundPage(extension)) {
816 store_->GetExtensionValue(extension->id(), kContextMenusKey,
817 base::Bind(&MenuManager::ReadFromStorage,
818 AsWeakPtr(), extension->id()));
822 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
823 Profile* profile = content::Source<Profile>(source).ptr();
824 // We cannot use profile_->HasOffTheRecordProfile as it may already be
825 // false at this point, if for example the incognito profile was destroyed
826 // using DestroyOffTheRecordProfile.
827 if (profile->GetOriginalProfile() == profile_ &&
828 profile->GetOriginalProfile() != profile) {
829 RemoveAllIncognitoContextItems();
839 const SkBitmap& MenuManager::GetIconForExtension(
840 const std::string& extension_id) {
841 return icon_manager_.GetIcon(extension_id);
844 void MenuManager::RemoveAllIncognitoContextItems() {
845 // Get all context menu items with "incognito" set to "split".
846 std::set<MenuItem::Id> items_to_remove;
847 std::map<MenuItem::Id, MenuItem*>::const_iterator iter;
848 for (iter = items_by_id_.begin();
849 iter != items_by_id_.end();
851 if (iter->first.incognito)
852 items_to_remove.insert(iter->first);
855 std::set<MenuItem::Id>::iterator remove_iter;
856 for (remove_iter = items_to_remove.begin();
857 remove_iter != items_to_remove.end();
859 RemoveContextMenuItem(*remove_iter);
862 MenuItem::Id::Id() : incognito(false), uid(0) {}
864 MenuItem::Id::Id(bool incognito, const std::string& extension_id)
865 : incognito(incognito), extension_id(extension_id), uid(0) {}
867 MenuItem::Id::~Id() {
870 bool MenuItem::Id::operator==(const Id& other) const {
871 return (incognito == other.incognito &&
872 extension_id == other.extension_id &&
874 string_uid == other.string_uid);
877 bool MenuItem::Id::operator!=(const Id& other) const {
878 return !(*this == other);
881 bool MenuItem::Id::operator<(const Id& other) const {
882 if (incognito < other.incognito)
884 if (incognito == other.incognito) {
885 if (extension_id < other.extension_id)
887 if (extension_id == other.extension_id) {
890 if (uid == other.uid)
891 return string_uid < other.string_uid;
897 } // namespace extensions