Index: chrome/browser/extensions/menu_manager.cc |
diff --git a/chrome/browser/extensions/menu_manager.cc b/chrome/browser/extensions/menu_manager.cc |
index 424366390b34035298c5790bd32d417cd7ed67a8..12097669f618e80f9efeffaa06eda9d833e8a7b5 100644 |
--- a/chrome/browser/extensions/menu_manager.cc |
+++ b/chrome/browser/extensions/menu_manager.cc |
@@ -19,6 +19,7 @@ |
#include "chrome/browser/extensions/menu_manager_factory.h" |
#include "chrome/browser/extensions/state_store.h" |
#include "chrome/browser/extensions/tab_helper.h" |
+#include "chrome/browser/guestview/webview/webview_guest.h" |
#include "chrome/browser/profiles/profile.h" |
#include "chrome/common/extensions/api/context_menus.h" |
#include "content/public/browser/notification_details.h" |
@@ -222,7 +223,7 @@ MenuItem* MenuItem::Populate(const std::string& extension_id, |
bool incognito = false; |
if (!value.GetBoolean(kIncognitoKey, &incognito)) |
return NULL; |
- Id id(incognito, extension_id); |
+ Id id(incognito, MenuItem::ExtensionKey(extension_id)); |
if (!value.GetString(kStringUIDKey, &id.string_uid)) |
return NULL; |
int type_int; |
@@ -266,7 +267,8 @@ MenuItem* MenuItem::Populate(const std::string& extension_id, |
// parent_id is filled in from the value, but it might not be valid. It's left |
// to be validated upon being added (via AddChildItem) to the menu manager. |
- scoped_ptr<Id> parent_id(new Id(incognito, extension_id)); |
+ scoped_ptr<Id> parent_id( |
+ new Id(incognito, MenuItem::ExtensionKey(extension_id))); |
if (value.HasKey(kParentUIDKey)) { |
if (!value.GetString(kParentUIDKey, &parent_id->string_uid)) |
return NULL; |
@@ -318,8 +320,8 @@ MenuManager* MenuManager::Get(Profile* profile) { |
return MenuManagerFactory::GetForProfile(profile); |
} |
-std::set<std::string> MenuManager::ExtensionIds() { |
- std::set<std::string> id_set; |
+std::set<MenuItem::ExtensionKey> MenuManager::ExtensionIds() { |
+ std::set<MenuItem::ExtensionKey> id_set; |
for (MenuItemMap::const_iterator i = context_items_.begin(); |
i != context_items_.end(); ++i) { |
id_set.insert(i->first); |
@@ -328,34 +330,32 @@ std::set<std::string> MenuManager::ExtensionIds() { |
} |
const MenuItem::List* MenuManager::MenuItems( |
- const std::string& extension_id) { |
- MenuItemMap::iterator i = context_items_.find(extension_id); |
+ const MenuItem::ExtensionKey& key) { |
+ MenuItemMap::iterator i = context_items_.find(key); |
if (i != context_items_.end()) { |
return &(i->second); |
} |
return NULL; |
} |
-bool MenuManager::AddContextItem( |
- const Extension* extension, |
- MenuItem* item) { |
- const std::string& extension_id = item->extension_id(); |
+bool MenuManager::AddContextItem(const Extension* extension, MenuItem* item) { |
+ const MenuItem::ExtensionKey& key = item->id().extension_key; |
// The item must have a non-empty extension id, and not have already been |
// added. |
- if (extension_id.empty() || ContainsKey(items_by_id_, item->id())) |
+ if (key.empty() || ContainsKey(items_by_id_, item->id())) |
return false; |
- DCHECK_EQ(extension->id(), extension_id); |
+ DCHECK_EQ(extension->id(), key.extension_id); |
- bool first_item = !ContainsKey(context_items_, extension_id); |
- context_items_[extension_id].push_back(item); |
+ bool first_item = !ContainsKey(context_items_, key); |
+ context_items_[key].push_back(item); |
items_by_id_[item->id()] = item; |
if (item->type() == MenuItem::RADIO) { |
if (item->checked()) |
RadioItemSelected(item); |
else |
- SanitizeRadioList(context_items_[extension_id]); |
+ SanitizeRadioList(context_items_[key]); |
} |
// If this is the first item for this extension, start loading its icon. |
@@ -424,14 +424,14 @@ bool MenuManager::ChangeParent(const MenuItem::Id& child_id, |
} else { |
// This is a top-level item, so we need to pull it out of our list of |
// top-level items. |
- MenuItemMap::iterator i = context_items_.find(child->extension_id()); |
+ const MenuItem::ExtensionKey& child_key = child->id().extension_key; |
+ MenuItemMap::iterator i = context_items_.find(child_key); |
if (i == context_items_.end()) { |
NOTREACHED(); |
return false; |
} |
MenuItem::List& list = i->second; |
- MenuItem::List::iterator j = std::find(list.begin(), list.end(), |
- child); |
+ MenuItem::List::iterator j = std::find(list.begin(), list.end(), child); |
if (j == list.end()) { |
NOTREACHED(); |
return false; |
@@ -444,9 +444,10 @@ bool MenuManager::ChangeParent(const MenuItem::Id& child_id, |
new_parent->AddChild(child); |
SanitizeRadioList(new_parent->children()); |
} else { |
- context_items_[child->extension_id()].push_back(child); |
+ const MenuItem::ExtensionKey& child_key = child->id().extension_key; |
+ context_items_[child_key].push_back(child); |
child->parent_id_.reset(NULL); |
- SanitizeRadioList(context_items_[child->extension_id()]); |
+ SanitizeRadioList(context_items_[child_key]); |
} |
return true; |
} |
@@ -457,8 +458,8 @@ bool MenuManager::RemoveContextMenuItem(const MenuItem::Id& id) { |
MenuItem* menu_item = GetItemById(id); |
DCHECK(menu_item); |
- std::string extension_id = menu_item->extension_id(); |
- MenuItemMap::iterator i = context_items_.find(extension_id); |
+ const MenuItem::ExtensionKey extension_key = id.extension_key; |
+ MenuItemMap::iterator i = context_items_.find(extension_key); |
if (i == context_items_.end()) { |
NOTREACHED(); |
return false; |
@@ -503,16 +504,18 @@ bool MenuManager::RemoveContextMenuItem(const MenuItem::Id& id) { |
} |
if (list.empty()) { |
- context_items_.erase(extension_id); |
- icon_manager_.RemoveIcon(extension_id); |
+ context_items_.erase(extension_key); |
+ icon_manager_.RemoveIcon(extension_key.extension_id); |
} |
return result; |
} |
-void MenuManager::RemoveAllContextItems(const std::string& extension_id) { |
+void MenuManager::RemoveAllContextItems( |
+ const MenuItem::ExtensionKey& extension_key) { |
MenuItem::List::iterator i; |
- for (i = context_items_[extension_id].begin(); |
- i != context_items_[extension_id].end(); ++i) { |
+ for (i = context_items_[extension_key].begin(); |
+ i != context_items_[extension_key].end(); |
+ ++i) { |
MenuItem* item = *i; |
items_by_id_.erase(item->id()); |
@@ -523,9 +526,9 @@ void MenuManager::RemoveAllContextItems(const std::string& extension_id) { |
items_by_id_.erase(*j); |
} |
} |
- STLDeleteElements(&context_items_[extension_id]); |
- context_items_.erase(extension_id); |
- icon_manager_.RemoveIcon(extension_id); |
+ STLDeleteElements(&context_items_[extension_key]); |
+ context_items_.erase(extension_key); |
+ icon_manager_.RemoveIcon(extension_key.extension_id); |
} |
MenuItem* MenuManager::GetItemById(const MenuItem::Id& id) const { |
@@ -549,11 +552,12 @@ void MenuManager::RadioItemSelected(MenuItem* item) { |
} |
list = &(parent->children()); |
} else { |
- if (context_items_.find(item->extension_id()) == context_items_.end()) { |
+ const MenuItem::ExtensionKey& key = item->id().extension_key; |
+ if (context_items_.find(key) == context_items_.end()) { |
NOTREACHED(); |
return; |
} |
- list = &context_items_[item->extension_id()]; |
+ list = &context_items_[key]; |
} |
// Find where |item| is in the list. |
@@ -610,8 +614,8 @@ void MenuManager::ExecuteCommand(Profile* profile, |
// ExtensionService/Extension can be NULL in unit tests :( |
ExtensionService* service = |
ExtensionSystem::Get(profile_)->extension_service(); |
- const Extension* extension = service ? |
- service->extensions()->GetByID(menu_item_id.extension_id) : NULL; |
+ const Extension* extension = |
+ service ? service->extensions()->GetByID(item->extension_id()) : NULL; |
if (item->type() == MenuItem::RADIO) |
RadioItemSelected(item); |
@@ -646,6 +650,14 @@ void MenuManager::ExecuteCommand(Profile* profile, |
properties->SetBoolean("editable", params.is_editable); |
+ WebViewGuest* webview_guest = WebViewGuest::FromWebContents(web_contents); |
+ if (webview_guest) { |
+ // This is used in webview_custom_bindings.js. |
+ // The property is not exposed to developer API. |
+ properties->SetInteger("webviewInstanceId", |
+ webview_guest->view_instance_id()); |
+ } |
+ |
args->Append(properties); |
// Add the tab info to the argument list. |
@@ -673,7 +685,7 @@ void MenuManager::ExecuteCommand(Profile* profile, |
properties->SetBoolean("checked", item->checked()); |
if (extension) |
- WriteToStorage(extension); |
+ WriteToStorage(extension, item->id().extension_key); |
} |
// Note: web_contents are NULL in unit tests :( |
@@ -683,6 +695,7 @@ void MenuManager::ExecuteCommand(Profile* profile, |
} |
{ |
+ // Dispatch to menu item's .onclick handler. |
scoped_ptr<Event> event(new Event( |
event_names::kOnContextMenus, |
scoped_ptr<base::ListValue>(args->DeepCopy()))); |
@@ -691,10 +704,15 @@ void MenuManager::ExecuteCommand(Profile* profile, |
event_router->DispatchEventToExtension(item->extension_id(), event.Pass()); |
} |
{ |
- scoped_ptr<Event> event(new Event(context_menus::OnClicked::kEventName, |
- args.Pass())); |
+ // Dispatch to .contextMenus.onClicked handler. |
+ scoped_ptr<Event> event( |
+ new Event(webview_guest ? event_names::kOnWebviewContextMenus |
+ : context_menus::OnClicked::kEventName, |
+ args.Pass())); |
event->restrict_to_browser_context = profile; |
event->user_gesture = EventRouter::USER_GESTURE_ENABLED; |
+ if (webview_guest) |
+ event->filter_info.SetInstanceID(webview_guest->view_instance_id()); |
event_router->DispatchEventToExtension(item->extension_id(), event.Pass()); |
} |
} |
@@ -743,8 +761,8 @@ bool MenuManager::ItemUpdated(const MenuItem::Id& id) { |
if (menu_item->parent_id()) { |
SanitizeRadioList(GetItemById(*menu_item->parent_id())->children()); |
} else { |
- std::string extension_id = menu_item->extension_id(); |
- MenuItemMap::iterator i = context_items_.find(extension_id); |
+ MenuItemMap::iterator i = |
+ context_items_.find(menu_item->id().extension_key); |
if (i == context_items_.end()) { |
NOTREACHED(); |
return false; |
@@ -755,21 +773,27 @@ bool MenuManager::ItemUpdated(const MenuItem::Id& id) { |
return true; |
} |
-void MenuManager::WriteToStorage(const Extension* extension) { |
+void MenuManager::WriteToStorage(const Extension* extension, |
+ const MenuItem::ExtensionKey& extension_key) { |
if (!BackgroundInfo::HasLazyBackgroundPage(extension)) |
return; |
- const MenuItem::List* top_items = MenuItems(extension->id()); |
+ // <webview> menu items are transient and not stored in storage. |
+ if (extension_key.webview_instance_id) |
+ return; |
+ const MenuItem::List* top_items = MenuItems(extension_key); |
MenuItem::List all_items; |
if (top_items) { |
for (MenuItem::List::const_iterator i = top_items->begin(); |
i != top_items->end(); ++i) { |
+ DCHECK(!(*i)->id().extension_key.webview_instance_id); |
(*i)->GetFlattenedSubtree(&all_items); |
} |
} |
- if (store_) |
+ if (store_) { |
store_->SetExtensionValue(extension->id(), kContextMenusKey, |
MenuItemsToValue(all_items)); |
+ } |
} |
void MenuManager::ReadFromStorage(const std::string& extension_id, |
@@ -804,8 +828,9 @@ void MenuManager::Observe(int type, |
// Remove menu items for disabled/uninstalled extensions. |
const Extension* extension = |
content::Details<UnloadedExtensionInfo>(details)->extension; |
- if (ContainsKey(context_items_, extension->id())) { |
- RemoveAllContextItems(extension->id()); |
+ MenuItem::ExtensionKey extension_key(extension->id()); |
+ if (ContainsKey(context_items_, extension_key)) { |
+ RemoveAllContextItems(extension_key); |
} |
break; |
} |
@@ -859,18 +884,46 @@ void MenuManager::RemoveAllIncognitoContextItems() { |
RemoveContextMenuItem(*remove_iter); |
} |
+MenuItem::ExtensionKey::ExtensionKey() : webview_instance_id(0) {} |
+ |
+MenuItem::ExtensionKey::ExtensionKey(const std::string& extension_id, |
+ int webview_instance_id) |
+ : extension_id(extension_id), webview_instance_id(webview_instance_id) {} |
+ |
+MenuItem::ExtensionKey::ExtensionKey(const std::string& extension_id) |
+ : extension_id(extension_id), webview_instance_id(0) {} |
+ |
+bool MenuItem::ExtensionKey::operator==(const ExtensionKey& other) const { |
+ return extension_id == other.extension_id && |
+ webview_instance_id == other.webview_instance_id; |
+} |
+ |
+bool MenuItem::ExtensionKey::operator<(const ExtensionKey& other) const { |
+ if (extension_id != other.extension_id) |
+ return extension_id < other.extension_id; |
+ |
+ return webview_instance_id < other.webview_instance_id; |
+} |
+ |
+bool MenuItem::ExtensionKey::operator!=(const ExtensionKey& other) const { |
+ return !(*this == other); |
+} |
+ |
+bool MenuItem::ExtensionKey::empty() const { |
+ return extension_id.empty() && !webview_instance_id; |
+} |
+ |
MenuItem::Id::Id() : incognito(false), uid(0) {} |
-MenuItem::Id::Id(bool incognito, const std::string& extension_id) |
- : incognito(incognito), extension_id(extension_id), uid(0) {} |
+MenuItem::Id::Id(bool incognito, const MenuItem::ExtensionKey& extension_key) |
+ : incognito(incognito), extension_key(extension_key), uid(0) {} |
MenuItem::Id::~Id() { |
} |
bool MenuItem::Id::operator==(const Id& other) const { |
return (incognito == other.incognito && |
- extension_id == other.extension_id && |
- uid == other.uid && |
+ extension_key == other.extension_key && uid == other.uid && |
string_uid == other.string_uid); |
} |
@@ -882,9 +935,9 @@ bool MenuItem::Id::operator<(const Id& other) const { |
if (incognito < other.incognito) |
return true; |
if (incognito == other.incognito) { |
- if (extension_id < other.extension_id) |
+ if (extension_key < other.extension_key) |
return true; |
- if (extension_id == other.extension_id) { |
+ if (extension_key == other.extension_key) { |
if (uid < other.uid) |
return true; |
if (uid == other.uid) |