A small start: add icons to the extension manifest.

Review URL: http://codereview.chromium.org/155662

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@20941 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index 2dc6519..fc13d3a 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -59,7 +59,6 @@
 // A list of all the keys allowed by themes.
 static const wchar_t* kValidThemeKeys[] = {
   keys::kDescription,
-  keys::kIconPath,
   keys::kName,
   keys::kPublicKey,
   keys::kSignature,
@@ -75,6 +74,8 @@
 // first 16 bytes of SHA256 hashed public key.
 const size_t Extension::kIdSize = 16;
 
+const int Extension::kKnownIconSizes[] = { 128 };
+
 Extension::~Extension() {
   for (PageActionMap::iterator i = page_actions_.begin();
        i != page_actions_.end(); ++i)
@@ -286,8 +287,8 @@
 
   ListValue* icons;
   // Read the page action |icons|.
-  if (!page_action->HasKey(keys::kIconPaths) ||
-      !page_action->GetList(keys::kIconPaths, &icons) ||
+  if (!page_action->HasKey(keys::kPageActionIcons) ||
+      !page_action->GetList(keys::kPageActionIcons, &icons) ||
       icons->GetSize() == 0) {
     *error = ExtensionErrorUtils::FormatErrorMessage(
         errors::kInvalidPageActionIconPaths, IntToString(definition_index));
@@ -542,7 +543,7 @@
     return false;
   }
 
-  // Initialize description (optional).
+  // Initialize description (if present).
   if (source.HasKey(keys::kDescription)) {
     if (!source.GetString(keys::kDescription, &description_)) {
       *error = errors::kInvalidDescription;
@@ -566,7 +567,29 @@
     }
   }
 
-  // Initialize themes.
+  // Initialize icons (if present).
+  if (source.HasKey(keys::kIcons)) {
+    DictionaryValue* icons_value = NULL;
+    if (!source.GetDictionary(keys::kIcons, &icons_value)) {
+      *error = errors::kInvalidIcons;
+      return false;
+    }
+
+    for (size_t i = 0; i < arraysize(kKnownIconSizes); ++i) {
+      std::wstring key = ASCIIToWide(IntToString(kKnownIconSizes[i]));
+      if (icons_value->HasKey(key)) {
+        std::string icon_path;
+        if (!icons_value->GetString(key, &icon_path)) {
+          *error = ExtensionErrorUtils::FormatErrorMessage(
+              errors::kInvalidIconPath, WideToASCII(key));
+          return false;
+        }
+        icons_[kKnownIconSizes[i]] = icon_path;
+      }
+    }
+  }
+
+  // Initialize themes (if present).
   is_theme_ = false;
   if (source.HasKey(keys::kTheme)) {
     // Themes cannot contain extension keys.
@@ -828,6 +851,13 @@
 std::set<FilePath> Extension::GetBrowserImages() {
   std::set<FilePath> image_paths;
 
+  // extension icons
+  for (std::map<int, std::string>::iterator iter = icons_.begin();
+       iter != icons_.end(); ++iter) {
+    image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(iter->second)));
+  }
+
+  // theme images
   DictionaryValue* theme_images = GetThemeImages();
   if (theme_images) {
     for (DictionaryValue::key_iterator it = theme_images->begin_keys();
@@ -839,6 +869,7 @@
     }
   }
 
+  // page action icons
   for (PageActionMap::const_iterator it = page_actions().begin();
        it != page_actions().end(); ++it) {
     const std::vector<FilePath>& icon_paths = it->second->icon_paths();
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index 8add980..32fc403c 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -45,6 +45,9 @@
     NEW_INSTALL
   };
 
+  // Icon sizes used by the extension system.
+  static const int kKnownIconSizes[];
+
   // An NPAPI plugin included in the extension.
   struct PluginInfo {
     FilePath path;  // Path to the plugin.
@@ -147,6 +150,7 @@
   const std::vector<std::string>& toolstrips() const { return toolstrips_; }
   const std::vector<URLPattern>& permissions() const { return permissions_; }
   const GURL& update_url() const { return update_url_; }
+  const std::map<int, std::string>& icons() { return icons_; }
 
   // Retrieves a page action by |id|.
   const PageAction* GetPageAction(std::string id) const;
@@ -258,6 +262,9 @@
   // The sites this extension has permission to talk to (using XHR, etc).
   std::vector<URLPattern> permissions_;
 
+  // The paths to the icons the extension contains mapped by their width.
+  std::map<int, std::string> icons_;
+
   // URL for fetching an update manifest
   GURL update_url_;
 
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 87ac2c73..373e913c 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -10,13 +10,13 @@
 const wchar_t* kContentScripts = L"content_scripts";
 const wchar_t* kCss = L"css";
 const wchar_t* kDescription = L"description";
-const wchar_t* kIconPath = L"icon";
-const wchar_t* kIconPaths = L"icons";
+const wchar_t* kIcons = L"icons";
 const wchar_t* kJs = L"js";
 const wchar_t* kMatches = L"matches";
 const wchar_t* kName = L"name";
 const wchar_t* kPageActionId = L"id";
 const wchar_t* kPageActions = L"page_actions";
+const wchar_t* kPageActionIcons = L"icons";
 const wchar_t* kPermissions = L"permissions";
 const wchar_t* kPlugins = L"plugins";
 const wchar_t* kPluginsPath = L"path";
@@ -58,6 +58,10 @@
     "Required value 'content_scripts[*].css is invalid.";
 const char* kInvalidDescription =
     "Invalid value for 'description'.";
+const char* kInvalidIcons =
+    "Invalid value for 'icons'.";
+const char* kInvalidIconPath =
+    "Invalid value for 'icons[\"*\"]'.";
 const char* kInvalidJs =
     "Invalid value for 'content_scripts[*].js[*]'.";
 const char* kInvalidJsList =
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index f1324df0..28aeecb 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -11,13 +11,13 @@
   extern const wchar_t* kContentScripts;
   extern const wchar_t* kCss;
   extern const wchar_t* kDescription;
-  extern const wchar_t* kIconPath;
-  extern const wchar_t* kIconPaths;
+  extern const wchar_t* kIcons;
   extern const wchar_t* kJs;
   extern const wchar_t* kMatches;
   extern const wchar_t* kName;
   extern const wchar_t* kPageActionId;
   extern const wchar_t* kPageActions;
+  extern const wchar_t* kPageActionIcons;
   extern const wchar_t* kPermissions;
   extern const wchar_t* kPlugins;
   extern const wchar_t* kPluginsPath;
@@ -52,6 +52,8 @@
   extern const char* kInvalidCss;
   extern const char* kInvalidCssList;
   extern const char* kInvalidDescription;
+  extern const char* kInvalidIcons;
+  extern const char* kInvalidIconPath;
   extern const char* kInvalidJs;
   extern const char* kInvalidJsList;
   extern const char* kInvalidKey;
diff --git a/chrome/common/extensions/extension_unittest.cc b/chrome/common/extensions/extension_unittest.cc
index 2b5382c..65ade63 100644
--- a/chrome/common/extensions/extension_unittest.cc
+++ b/chrome/common/extensions/extension_unittest.cc
@@ -75,6 +75,21 @@
   EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
   EXPECT_EQ(errors::kInvalidDescription, error);
 
+  // Test invalid icons
+  input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
+  input_value->SetInteger(keys::kIcons, 42);
+  EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
+  EXPECT_EQ(errors::kInvalidIcons, error);
+
+  // Test invalid icon paths
+  input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
+  DictionaryValue* icons = NULL;
+  input_value->GetDictionary(keys::kIcons, &icons);
+  ASSERT_FALSE(NULL == icons);
+  icons->SetInteger(ASCIIToWide(IntToString(128)), 42);
+  EXPECT_FALSE(extension.InitFromValue(*input_value, true, &error));
+  EXPECT_TRUE(MatchPattern(error, errors::kInvalidIconPath));
+
   // Test invalid user scripts list
   input_value.reset(static_cast<DictionaryValue*>(valid_value->DeepCopy()));
   input_value->SetInteger(keys::kContentScripts, 42);
@@ -271,7 +286,7 @@
   ListValue* icons = new ListValue;
   icons->Set(0, Value::CreateStringValue(img1));
   icons->Set(1, Value::CreateStringValue(img2));
-  input.Set(keys::kIconPaths, icons);
+  input.Set(keys::kPageActionIcons, icons);
 
   // Parse the page action and read back the values from the object.
   page_action.reset(extension.LoadPageActionHelper(&input, 0, &error_msg));
@@ -321,7 +336,7 @@
 
   // Then remove the icon paths key.
   copy.reset(static_cast<DictionaryValue*>(input.DeepCopy()));
-  copy->Remove(keys::kIconPaths, NULL);
+  copy->Remove(keys::kPageActionIcons, NULL);
   page_action.reset(extension.LoadPageActionHelper(copy.get(), 0, &error_msg));
   ASSERT_TRUE(NULL == page_action.get());
   ASSERT_TRUE(MatchPattern(error_msg.c_str(),