diff options
-rw-r--r-- | chrome/browser/extensions/api/context_menu/context_menu_api.cc | 86 | ||||
-rw-r--r-- | chrome/browser/extensions/api/context_menu/context_menu_api.h | 11 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_menu_manager.cc | 189 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_menu_manager.h | 43 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_prefs.cc | 65 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_prefs.h | 6 | ||||
-rw-r--r-- | chrome/common/extensions/url_pattern_set.cc | 45 | ||||
-rw-r--r-- | chrome/common/extensions/url_pattern_set.h | 13 |
8 files changed, 342 insertions, 116 deletions
diff --git a/chrome/browser/extensions/api/context_menu/context_menu_api.cc b/chrome/browser/extensions/api/context_menu/context_menu_api.cc index 588b382..2976b06 100644 --- a/chrome/browser/extensions/api/context_menu/context_menu_api.cc +++ b/chrome/browser/extensions/api/context_menu/context_menu_api.cc @@ -13,6 +13,8 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/extension_error_utils.h" +namespace { + const char kCheckedKey[] = "checked"; const char kContextsKey[] = "contexts"; const char kDocumentUrlPatternsKey[] = "documentUrlPatterns"; @@ -31,7 +33,6 @@ const char kDuplicateIDError[] = "Cannot create item with duplicate id *"; const char kIdRequiredError[] = "Extensions using event pages must pass an " "id parameter to chrome.contextMenus.create"; -const char kInvalidURLPatternError[] = "Invalid url pattern '*'"; const char kInvalidValueError[] = "Invalid value for *"; const char kInvalidTypeStringError[] = "Invalid type string '*'"; const char kParentsMustBeNormalError[] = @@ -39,10 +40,6 @@ const char kParentsMustBeNormalError[] = const char kTitleNeededError[] = "All menu items except for separators must have a title"; -namespace extensions { - -namespace { - std::string GetIDString(const ExtensionMenuItem::Id& id) { if (id.uid == 0) return id.string_uid; @@ -52,6 +49,8 @@ std::string GetIDString(const ExtensionMenuItem::Id& id) { } // namespace +namespace extensions { + bool ExtensionContextMenuFunction::ParseContexts( const DictionaryValue& properties, const char* key, @@ -143,68 +142,11 @@ bool ExtensionContextMenuFunction::ParseChecked( return true; } -bool ExtensionContextMenuFunction::ParseURLPatterns( - const DictionaryValue& properties, - const char* key, - URLPatternSet* result) { - if (!properties.HasKey(key)) - return true; - ListValue* list = NULL; - if (!properties.GetList(key, &list)) - return false; - for (ListValue::iterator i = list->begin(); i != list->end(); ++i) { - std::string tmp; - if (!(*i)->GetAsString(&tmp)) - return false; - - URLPattern pattern(URLPattern::SCHEME_ALL); - // TODO(skerner): Consider enabling strict pattern parsing - // if this extension's location indicates that it is under development. - if (URLPattern::PARSE_SUCCESS != pattern.Parse(tmp)) { - error_ = ExtensionErrorUtils::FormatErrorMessage(kInvalidURLPatternError, - tmp); - return false; - } - result->AddPattern(pattern); - } - return true; -} - -bool ExtensionContextMenuFunction::SetURLPatterns( - const DictionaryValue& properties, - ExtensionMenuItem* item) { - // Process the documentUrlPattern value. - URLPatternSet document_url_patterns; - if (!ParseURLPatterns(properties, kDocumentUrlPatternsKey, - &document_url_patterns)) - return false; - - if (!document_url_patterns.is_empty()) { - item->set_document_url_patterns(document_url_patterns); - } - - // Process the targetUrlPattern value. - URLPatternSet target_url_patterns; - if (!ParseURLPatterns(properties, kTargetUrlPatternsKey, - &target_url_patterns)) - return false; - - if (!target_url_patterns.is_empty()) { - item->set_target_url_patterns(target_url_patterns); - } - - return true; -} - bool ExtensionContextMenuFunction::ParseID( const Value* value, ExtensionMenuItem::Id* result) { - if (value->GetAsInteger(&result->uid) || - value->GetAsString(&result->string_uid)) { - return true; - } else { - return false; - } + return (value->GetAsInteger(&result->uid) || + value->GetAsString(&result->string_uid)); } bool ExtensionContextMenuFunction::GetParent( @@ -289,7 +231,8 @@ bool CreateContextMenuFunction::RunImpl() { scoped_ptr<ExtensionMenuItem> item( new ExtensionMenuItem(id, title, checked, enabled, type, contexts)); - if (!SetURLPatterns(*properties, item.get())) + if (!item->PopulateURLPatterns( + *properties, kDocumentUrlPatternsKey, kTargetUrlPatternsKey, &error_)) return false; bool success = true; @@ -305,6 +248,7 @@ bool CreateContextMenuFunction::RunImpl() { if (!success) return false; + menu_manager->WriteToPrefs(GetExtension()); return true; } @@ -382,7 +326,8 @@ bool UpdateContextMenuFunction::RunImpl() { if (parent && !manager->ChangeParent(item->id(), &parent->id())) return false; - if (!SetURLPatterns(*properties, item)) + if (!item->PopulateURLPatterns( + *properties, kDocumentUrlPatternsKey, kTargetUrlPatternsKey, &error_)) return false; // There is no need to call ItemUpdated if ChangeParent is called because @@ -390,6 +335,7 @@ bool UpdateContextMenuFunction::RunImpl() { if (!parent && radioItemUpdated && !manager->ItemUpdated(item->id())) return false; + manager->WriteToPrefs(GetExtension()); return true; } @@ -409,13 +355,17 @@ bool RemoveContextMenuFunction::RunImpl() { return false; } - return manager->RemoveContextMenuItem(id); + if (!manager->RemoveContextMenuItem(id)) + return false; + manager->WriteToPrefs(GetExtension()); + return true; } bool RemoveAllContextMenusFunction::RunImpl() { ExtensionService* service = profile()->GetExtensionService(); ExtensionMenuManager* manager = service->menu_manager(); - manager->RemoveAllContextItems(extension_id()); + manager->RemoveAllContextItems(GetExtension()->id()); + manager->WriteToPrefs(GetExtension()); return true; } diff --git a/chrome/browser/extensions/api/context_menu/context_menu_api.h b/chrome/browser/extensions/api/context_menu/context_menu_api.h index 6117e3e..fe09370 100644 --- a/chrome/browser/extensions/api/context_menu/context_menu_api.h +++ b/chrome/browser/extensions/api/context_menu/context_menu_api.h @@ -41,17 +41,6 @@ class ExtensionContextMenuFunction : public SyncExtensionFunction { bool default_value, bool* checked); - // Helper to read in a set of url patterns from a property with the given key - // name. - bool ParseURLPatterns(const base::DictionaryValue& properties, - const char* key, - URLPatternSet* result); - - // Reads in any document and targetUrl patterns from |properties| and sets - // them on |item|. - bool SetURLPatterns(const base::DictionaryValue& properties, - ExtensionMenuItem* item); - // Helper to read an ID from the Value*. The ID can be either a string or // integer. bool ParseID(const Value* value, diff --git a/chrome/browser/extensions/extension_menu_manager.cc b/chrome/browser/extensions/extension_menu_manager.cc index 500efcf..99d6fc4 100644 --- a/chrome/browser/extensions/extension_menu_manager.cc +++ b/chrome/browser/extensions/extension_menu_manager.cc @@ -13,6 +13,9 @@ #include "base/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/extensions/extension_event_router.h" +#include "chrome/browser/extensions/extension_prefs.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_system.h" #include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_notification_types.h" @@ -27,6 +30,18 @@ using content::WebContents; namespace { +// Keys for serialization to and from Value to store in the preferences. +const char kCheckedKey[] = "checked"; +const char kContextsKey[] = "contexts"; +const char kDocumentURLPatternsKey[] = "document_url_patterns"; +const char kEnabledKey[] = "enabled"; +const char kIncognitoKey[] = "incognito"; +const char kParentUIDKey[] = "parent_uid"; +const char kStringUIDKey[] = "string_uid"; +const char kTargetURLPatternsKey[] = "target_url_patterns"; +const char kTitleKey[] = "title"; +const char kTypeKey[] = "type"; + void SetIdKeyValue(base::DictionaryValue* properties, const char* key, const ExtensionMenuItem::Id& id) { @@ -74,6 +89,12 @@ ExtensionMenuItem* ExtensionMenuItem::ReleaseChild(const Id& child_id, return NULL; } +void ExtensionMenuItem::GetFlattenedSubtree(ExtensionMenuItem::List* list) { + list->push_back(this); + for (List::iterator i = children_.begin(); i != children_.end(); ++i) + (*i)->GetFlattenedSubtree(list); +} + std::set<ExtensionMenuItem::Id> ExtensionMenuItem::RemoveAllDescendants() { std::set<Id> result; for (List::iterator i = children_.begin(); i != children_.end(); ++i) { @@ -110,7 +131,111 @@ void ExtensionMenuItem::AddChild(ExtensionMenuItem* item) { children_.push_back(item); } -ExtensionMenuManager::ExtensionMenuManager(Profile* profile) { +scoped_ptr<DictionaryValue> ExtensionMenuItem::ToValue() const { + scoped_ptr<DictionaryValue> value(new DictionaryValue); + // Should only be called for extensions with event pages, which only have + // string IDs for items. + DCHECK_EQ(0, id_.uid); + value->SetString(kStringUIDKey, id_.string_uid); + value->SetBoolean(kIncognitoKey, id_.incognito); + value->SetInteger(kTypeKey, type_); + if (type_ != SEPARATOR) + value->SetString(kTitleKey, title_); + if (type_ == CHECKBOX || type_ == RADIO) + value->SetBoolean(kCheckedKey, checked_); + value->SetBoolean(kEnabledKey, enabled_); + value->Set(kContextsKey, contexts_.ToValue().release()); + if (parent_id_.get()) { + DCHECK_EQ(0, parent_id_->uid); + value->SetString(kParentUIDKey, parent_id_->string_uid); + } + value->Set(kDocumentURLPatternsKey, + document_url_patterns_.ToValue().release()); + value->Set(kTargetURLPatternsKey, target_url_patterns_.ToValue().release()); + return value.Pass(); +} + +// static +ExtensionMenuItem* ExtensionMenuItem::Populate(const std::string& extension_id, + const DictionaryValue& value, + std::string* error) { + bool incognito = false; + if (!value.GetBoolean(kIncognitoKey, &incognito)) + return NULL; + Id id(incognito, extension_id); + if (!value.GetString(kStringUIDKey, &id.string_uid)) + return NULL; + int type_int; + Type type; + if (!value.GetInteger(kTypeKey, &type_int)) + return NULL; + type = static_cast<Type>(type_int); + std::string title; + if (type != SEPARATOR && !value.GetString(kTitleKey, &title)) + return NULL; + bool checked; + if ((type == CHECKBOX || type == RADIO) && + !value.GetBoolean(kCheckedKey, &checked)) { + return NULL; + } + bool enabled = true; + if (!value.GetBoolean(kEnabledKey, &enabled)) + return NULL; + ContextList contexts; + Value* contexts_value = NULL; + if (!value.Get(kContextsKey, &contexts_value)) + return NULL; + if (!contexts.Populate(*contexts_value)) + return NULL; + + scoped_ptr<ExtensionMenuItem> result(new ExtensionMenuItem( + id, title, checked, enabled, type, contexts)); + + if (!result->PopulateURLPatterns( + value, kDocumentURLPatternsKey, kTargetURLPatternsKey, error)) + return NULL; + + // 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)); + if (value.HasKey(kParentUIDKey)) { + if (!value.GetString(kParentUIDKey, &parent_id->string_uid)) + return NULL; + result->parent_id_.swap(parent_id); + } + return result.release(); +} + +bool ExtensionMenuItem::PopulateURLPatterns( + const DictionaryValue& properties, + const char* document_url_patterns_key, + const char* target_url_patterns_key, + std::string* error) { + if (properties.HasKey(document_url_patterns_key)) { + ListValue* list = NULL; + if (!properties.GetList(document_url_patterns_key, &list)) + return false; + if (!document_url_patterns_.Populate( + *list, URLPattern::SCHEME_ALL, true, error)) { + return false; + } + } + if (properties.HasKey(target_url_patterns_key)) { + ListValue* list = NULL; + if (!properties.GetList(target_url_patterns_key, &list)) + return false; + if (!target_url_patterns_.Populate( + *list, URLPattern::SCHEME_ALL, true, error)) { + return false; + } + } + return true; +} + +ExtensionMenuManager::ExtensionMenuManager(Profile* profile) + : profile_(profile) { + registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, + content::Source<Profile>(profile)); registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, content::Source<Profile>(profile)); } @@ -182,7 +307,6 @@ bool ExtensionMenuManager::AddChildItem(const ExtensionMenuItem::Id& parent_id, if (child->type() == ExtensionMenuItem::RADIO) SanitizeRadioList(parent->children()); - return true; } @@ -314,7 +438,6 @@ bool ExtensionMenuManager::RemoveContextMenuItem( context_items_.erase(extension_id); icon_manager_.RemoveIcon(extension_id); } - return result; } @@ -472,6 +595,10 @@ void ExtensionMenuManager::ExecuteCommand( item->SetChecked(checked); properties->SetBoolean("checked", item->checked()); + + const extensions::Extension* extension = ExtensionSystem::Get(profile_)-> + extension_service()->GetExtensionById(menuItemId.extension_id, false); + WriteToPrefs(extension); } std::string json_args; @@ -540,17 +667,59 @@ bool ExtensionMenuManager::ItemUpdated(const ExtensionMenuItem::Id& id) { return true; } +void ExtensionMenuManager::WriteToPrefs( + const extensions::Extension* extension) { + if (!extension->has_lazy_background_page()) + return; + const ExtensionMenuItem::List* top_items = MenuItems(extension->id()); + ExtensionMenuItem::List all_items; + if (top_items) { + for (ExtensionMenuItem::List::const_iterator i = top_items->begin(); + i != top_items->end(); ++i) { + (*i)->GetFlattenedSubtree(&all_items); + } + } + ExtensionSystem::Get(profile_)->extension_service()->extension_prefs()-> + SetContextMenuItems(extension->id(), all_items); +} + +void ExtensionMenuManager::ReadFromPrefs( + const extensions::Extension* extension) { + if (!extension->has_lazy_background_page()) + return; + ExtensionMenuItem::List items = + ExtensionSystem::Get(profile_)->extension_service()->extension_prefs()-> + GetContextMenuItems(extension->id()); + for (size_t i = 0; i < items.size(); ++i) { + if (items[i]->parent_id()) { + // Parent IDs are stored in the parent_id field for convenience, but + // they have not yet been validated. Separate them out here. + // Because of the order in which we store items in the prefs, parents will + // precede children, so we should already know about any parent items. + scoped_ptr<ExtensionMenuItem::Id> parent_id; + parent_id.swap(items[i]->parent_id_); + AddChildItem(*parent_id, items[i]); + } else { + AddContextItem(extension, items[i]); + } + } +} + void ExtensionMenuManager::Observe( int type, const content::NotificationSource& source, const content::NotificationDetails& details) { - DCHECK(type == chrome::NOTIFICATION_EXTENSION_UNLOADED); - - // Remove menu items for disabled/uninstalled extensions. - const extensions::Extension* extension = - content::Details<extensions::UnloadedExtensionInfo>(details)->extension; - if (ContainsKey(context_items_, extension->id())) { - RemoveAllContextItems(extension->id()); + if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) { + // Remove menu items for disabled/uninstalled extensions. + const extensions::Extension* extension = + content::Details<extensions::UnloadedExtensionInfo>(details)->extension; + if (ContainsKey(context_items_, extension->id())) { + RemoveAllContextItems(extension->id()); + } + } else if (type == chrome::NOTIFICATION_EXTENSION_LOADED) { + const extensions::Extension* extension = + content::Details<const extensions::Extension>(details).ptr(); + ReadFromPrefs(extension); } } diff --git a/chrome/browser/extensions/extension_menu_manager.h b/chrome/browser/extensions/extension_menu_manager.h index d55ebca..1197c27 100644 --- a/chrome/browser/extensions/extension_menu_manager.h +++ b/chrome/browser/extensions/extension_menu_manager.h @@ -16,6 +16,7 @@ #include "base/gtest_prod_util.h" #include "base/memory/scoped_ptr.h" #include "base/string16.h" +#include "base/values.h" #include "chrome/browser/extensions/extension_icon_manager.h" #include "chrome/common/extensions/url_pattern_set.h" #include "content/public/browser/notification_observer.h" @@ -108,6 +109,18 @@ class ExtensionMenuItem { value_ |= context; } + scoped_ptr<Value> ToValue() const { + return scoped_ptr<Value>(Value::CreateIntegerValue(value_)); + } + + bool Populate(const Value& value) { + int int_value; + if (!value.GetAsInteger(&int_value) || int_value < 0) + return false; + value_ = int_value; + return true; + } + private: uint32 value_; // A bitmask of Context values. }; @@ -156,9 +169,24 @@ class ExtensionMenuItem { string16 TitleWithReplacement(const string16& selection, size_t max_length) const; - // Set the checked state to |checked|. Returns true if successful. + // Sets the checked state to |checked|. Returns true if successful. bool SetChecked(bool checked); + // Converts to Value for serialization to preferences. + scoped_ptr<base::DictionaryValue> ToValue() const; + + // Returns a new ExtensionMenuItem created from |value|, or NULL if there is + // an error. The caller takes ownership of the ExtensionMenuItem. + static ExtensionMenuItem* Populate(const std::string& extension_id, + const DictionaryValue& value, + std::string* error); + + // Sets any document and target URL patterns from |properties|. + bool PopulateURLPatterns(const base::DictionaryValue& properties, + const char* document_url_patterns_key, + const char* target_url_patterns_key, + std::string* error); + protected: friend class ExtensionMenuManager; @@ -169,6 +197,10 @@ class ExtensionMenuItem { // then owns the pointer. ExtensionMenuItem* ReleaseChild(const Id& child_id, bool recursive); + // Recursively appends all descendant items (children, grandchildren, etc.) + // to the output |list|. + void GetFlattenedSubtree(ExtensionMenuItem::List* list); + // Recursively removes all descendant items (children, grandchildren, etc.), // returning the ids of the removed items. std::set<Id> RemoveAllDescendants(); @@ -275,6 +307,13 @@ class ExtensionMenuManager : public content::NotificationObserver { virtual void Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) OVERRIDE; + // Stores the menu items for the extension in the preferences. + void WriteToPrefs(const extensions::Extension* extension); + + // Reads menu items for the extension from the preferences. Any invalid + // items are ignored. + void ReadFromPrefs(const extensions::Extension* extension); + private: FRIEND_TEST_ALL_PREFIXES(ExtensionMenuManagerTest, DeleteParent); FRIEND_TEST_ALL_PREFIXES(ExtensionMenuManagerTest, RemoveOneByOne); @@ -306,6 +345,8 @@ class ExtensionMenuManager : public content::NotificationObserver { ExtensionIconManager icon_manager_; + Profile* profile_; + DISALLOW_COPY_AND_ASSIGN(ExtensionMenuManager); }; diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc index faf3bd5..52af11b 100644 --- a/chrome/browser/extensions/extension_prefs.cc +++ b/chrome/browser/extensions/extension_prefs.cc @@ -9,6 +9,7 @@ #include "base/utf_string_conversions.h" #include "chrome/browser/extensions/api/alarms/alarm_manager.h" #include "chrome/browser/extensions/api/omnibox/omnibox_api.h" +#include "chrome/browser/extensions/extension_menu_manager.h" #include "chrome/browser/extensions/extension_pref_store.h" #include "chrome/browser/extensions/extension_sorting.h" #include "chrome/browser/prefs/pref_notifier.h" @@ -174,6 +175,9 @@ const char kAlarmScheduledRunTime[] = "scheduled_run_time"; // Persisted value for omnibox.setDefaultSuggestion. const char kOmniboxDefaultSuggestion[] = "omnibox_default_suggestion"; +// A preference containing context menu items, persisted for event pages. +const char kPrefContextMenus[] = "context_menus"; + // Provider of write access to a dictionary storing extension prefs. class ScopedExtensionPrefUpdate : public DictionaryPrefUpdate { public: @@ -440,38 +444,15 @@ bool ExtensionPrefs::ReadExtensionPrefURLPatternSet( if (!ReadExtensionPrefList(extension_id, pref_key, &value)) return false; - result->ClearPatterns(); bool allow_file_access = AllowFileAccess(extension_id); - - for (size_t i = 0; i < value->GetSize(); ++i) { - std::string item; - if (!value->GetString(i, &item)) - return false; - URLPattern pattern(valid_schemes); - if (pattern.Parse(item) != URLPattern::PARSE_SUCCESS) { - LOG(ERROR) << "Invaid permission pattern: " << item; - return false; - } - if (!allow_file_access && pattern.MatchesScheme(chrome::kFileScheme)) { - pattern.SetValidSchemes( - pattern.valid_schemes() & ~URLPattern::SCHEME_FILE); - } - result->AddPattern(pattern); - } - - return true; + return result->Populate(*value, valid_schemes, allow_file_access, NULL); } void ExtensionPrefs::SetExtensionPrefURLPatternSet( const std::string& extension_id, const std::string& pref_key, const URLPatternSet& new_value) { - ListValue* value = new ListValue(); - for (URLPatternSet::const_iterator i = new_value.begin(); - i != new_value.end(); ++i) - value->AppendIfNotPresent(Value::CreateStringValue(i->GetAsString())); - - UpdateExtensionPref(extension_id, pref_key, value); + UpdateExtensionPref(extension_id, pref_key, new_value.ToValue().release()); } ExtensionPermissionSet* ExtensionPrefs::ReadExtensionPrefPermissionSet( @@ -1032,6 +1013,37 @@ void ExtensionPrefs::SetOmniboxDefaultSuggestion( UpdateExtensionPref(extension_id, kOmniboxDefaultSuggestion, dict.release()); } +ExtensionMenuItem::List ExtensionPrefs::GetContextMenuItems( + const std::string& extension_id) { + ExtensionMenuItem::List items; + const base::ListValue* list = NULL; + if (!ReadExtensionPrefList(extension_id, kPrefContextMenus, &list)) + return items; + for (size_t i = 0; i < list->GetSize(); ++i) { + base::DictionaryValue* dict = NULL; + if (!list->GetDictionary(i, &dict)) + continue; + ExtensionMenuItem* item = ExtensionMenuItem::Populate( + extension_id, *dict, NULL); + if (!item) + continue; + items.push_back(item); + } + return items; +} + +void ExtensionPrefs::SetContextMenuItems( + const std::string& extension_id, + const ExtensionMenuItem::List& items) { + base::ListValue* list = NULL; + if (items.size() > 0) { + list = new base::ListValue; + for (size_t i = 0; i < items.size(); ++i) + list->Append(items[i]->ToValue().release()); + } + UpdateExtensionPref(extension_id, kPrefContextMenus, list); +} + bool ExtensionPrefs::IsIncognitoEnabled(const std::string& extension_id) { return ReadExtensionPrefBoolean(extension_id, kPrefIncognitoEnabled); } @@ -1227,9 +1239,10 @@ void ExtensionPrefs::OnExtensionInstalled( extension->manifest()->value()->DeepCopy()); } - // Clear any events and alarms that may be registered from a previous install. + // Clear state that may be registered from a previous install. extension_dict->Remove(kRegisteredEvents, NULL); extension_dict->Remove(kRegisteredAlarms, NULL); + extension_dict->Remove(kPrefContextMenus, NULL); if (extension->is_app()) { StringOrdinal new_page_ordinal = page_ordinal.IsValid() ? diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h index adfb45f..bef7f2a 100644 --- a/chrome/browser/extensions/extension_prefs.h +++ b/chrome/browser/extensions/extension_prefs.h @@ -14,6 +14,7 @@ #include "base/time.h" #include "base/values.h" #include "chrome/browser/extensions/api/content_settings/content_settings_store.h" +#include "chrome/browser/extensions/extension_menu_manager.h" #include "chrome/browser/extensions/extension_prefs_scope.h" #include "chrome/browser/extensions/extension_scoped_prefs.h" #include "chrome/common/extensions/extension.h" @@ -283,6 +284,11 @@ class ExtensionPrefs : public extensions::ContentSettingsStore::Observer, const std::string& extension_id, const extensions::ExtensionOmniboxSuggestion& suggestion); + // Controls the context menu items for this extension. + ExtensionMenuItem::List GetContextMenuItems(const std::string& extension_id); + void SetContextMenuItems(const std::string& extension_id, + const ExtensionMenuItem::List& items); + // Returns true if the user enabled this extension to be loaded in incognito // mode. bool IsIncognitoEnabled(const std::string& extension_id); diff --git a/chrome/common/extensions/url_pattern_set.cc b/chrome/common/extensions/url_pattern_set.cc index b2f5f25..c84df14 100644 --- a/chrome/common/extensions/url_pattern_set.cc +++ b/chrome/common/extensions/url_pattern_set.cc @@ -7,9 +7,18 @@ #include <algorithm> #include <iterator> +#include "base/logging.h" +#include "base/values.h" +#include "chrome/common/extensions/extension_error_utils.h" #include "chrome/common/extensions/url_pattern.h" +#include "content/public/common/url_constants.h" #include "googleurl/src/gurl.h" +namespace { + +const char kInvalidURLPatternError[] = "Invalid url pattern '*'"; + +} // namespace // static void URLPatternSet::CreateDifference(const URLPatternSet& set1, @@ -114,3 +123,39 @@ bool URLPatternSet::OverlapsWith(const URLPatternSet& other) const { return false; } + +scoped_ptr<base::ListValue> URLPatternSet::ToValue() const { + scoped_ptr<ListValue> value(new ListValue); + for (URLPatternSet::const_iterator i = patterns_.begin(); + i != patterns_.end(); ++i) + value->AppendIfNotPresent(Value::CreateStringValue(i->GetAsString())); + return value.Pass(); +} + +bool URLPatternSet::Populate(const base::ListValue& value, + int valid_schemes, + bool allow_file_access, + std::string* error) { + ClearPatterns(); + for (size_t i = 0; i < value.GetSize(); ++i) { + std::string item; + if (!value.GetString(i, &item)) + return false; + URLPattern pattern(valid_schemes); + if (pattern.Parse(item) != URLPattern::PARSE_SUCCESS) { + if (error) { + *error = ExtensionErrorUtils::FormatErrorMessage( + kInvalidURLPatternError, item); + } else { + LOG(ERROR) << "Invalid url pattern: " << item; + } + return false; + } + if (!allow_file_access && pattern.MatchesScheme(chrome::kFileScheme)) { + pattern.SetValidSchemes( + pattern.valid_schemes() & ~URLPattern::SCHEME_FILE); + } + AddPattern(pattern); + } + return true; +} diff --git a/chrome/common/extensions/url_pattern_set.h b/chrome/common/extensions/url_pattern_set.h index 3629f0b..c912558 100644 --- a/chrome/common/extensions/url_pattern_set.h +++ b/chrome/common/extensions/url_pattern_set.h @@ -8,10 +8,16 @@ #include <set> +#include "base/memory/scoped_ptr.h" #include "chrome/common/extensions/url_pattern.h" class GURL; +namespace base { +class ListValue; +class Value; +} + // Represents the set of URLs an extension uses for web content. class URLPatternSet { public: @@ -61,6 +67,13 @@ class URLPatternSet { // Returns true if there is a single URL that would be in two extents. bool OverlapsWith(const URLPatternSet& other) const; + // Converts to and from Value for serialization to preferences. + scoped_ptr<base::ListValue> ToValue() const; + bool Populate(const base::ListValue& value, + int valid_schemes, + bool allow_file_access, + std::string* error); + private: // The list of URL patterns that comprise the extent. std::set<URLPattern> patterns_; |