| 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)
|
|
|