Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / common / extensions / api / extension_action / action_info.cc
blob8cf0386d3613ed37f4524ca95cfa98975ac805c4
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/common/extensions/api/extension_action/action_info.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/common/extensions/api/commands/commands_handler.h"
10 #include "extensions/common/constants.h"
11 #include "extensions/common/error_utils.h"
12 #include "extensions/common/extension.h"
13 #include "extensions/common/manifest_constants.h"
14 #include "extensions/common/manifest_handler_helpers.h"
16 namespace extensions {
18 namespace errors = manifest_errors;
19 namespace keys = manifest_keys;
21 namespace {
23 // The manifest data container for the ActionInfos for BrowserActions,
24 // PageActions and SystemIndicators.
25 struct ActionInfoData : public Extension::ManifestData {
26 explicit ActionInfoData(ActionInfo* action_info);
27 ~ActionInfoData() override;
29 // The action associated with the BrowserAction.
30 scoped_ptr<ActionInfo> action_info;
33 ActionInfoData::ActionInfoData(ActionInfo* info) : action_info(info) {
36 ActionInfoData::~ActionInfoData() {
39 static const ActionInfo* GetActionInfo(const Extension* extension,
40 const std::string& key) {
41 ActionInfoData* data = static_cast<ActionInfoData*>(
42 extension->GetManifestData(key));
43 return data ? data->action_info.get() : NULL;
46 } // namespace
48 ActionInfo::ActionInfo() {
51 ActionInfo::~ActionInfo() {
54 // static
55 scoped_ptr<ActionInfo> ActionInfo::Load(const Extension* extension,
56 const base::DictionaryValue* dict,
57 base::string16* error) {
58 scoped_ptr<ActionInfo> result(new ActionInfo());
60 if (extension->manifest_version() == 1) {
61 // kPageActionIcons is obsolete, and used by very few extensions. Continue
62 // loading it, but only take the first icon as the default_icon path.
63 const base::ListValue* icons = NULL;
64 if (dict->HasKey(keys::kPageActionIcons) &&
65 dict->GetList(keys::kPageActionIcons, &icons)) {
66 base::ListValue::const_iterator iter = icons->begin();
67 std::string path;
68 if (iter == icons->end() ||
69 !(*iter)->GetAsString(&path) ||
70 !manifest_handler_helpers::NormalizeAndValidatePath(&path)) {
71 *error = base::ASCIIToUTF16(errors::kInvalidPageActionIconPath);
72 return scoped_ptr<ActionInfo>();
74 result->default_icon.Add(extension_misc::EXTENSION_ICON_ACTION, path);
77 std::string id;
78 if (dict->HasKey(keys::kPageActionId)) {
79 if (!dict->GetString(keys::kPageActionId, &id)) {
80 *error = base::ASCIIToUTF16(errors::kInvalidPageActionId);
81 return scoped_ptr<ActionInfo>();
83 result->id = id;
87 // Read the page action |default_icon| (optional).
88 // The |default_icon| value can be either dictionary {icon size -> icon path}
89 // or non empty string value.
90 if (dict->HasKey(keys::kPageActionDefaultIcon)) {
91 const base::DictionaryValue* icons_value = NULL;
92 std::string default_icon;
93 if (dict->GetDictionary(keys::kPageActionDefaultIcon, &icons_value)) {
94 int icon_sizes[extension_misc::kNumExtensionActionIconSizes];
95 for (size_t i = 0u; i < extension_misc::kNumExtensionActionIconSizes; ++i)
96 icon_sizes[i] = extension_misc::kExtensionActionIconSizes[i].size;
97 if (!manifest_handler_helpers::LoadIconsFromDictionary(
98 icons_value,
99 icon_sizes,
100 extension_misc::kNumExtensionActionIconSizes,
101 &result->default_icon,
102 error)) {
103 return scoped_ptr<ActionInfo>();
105 } else if (dict->GetString(keys::kPageActionDefaultIcon, &default_icon) &&
106 manifest_handler_helpers::NormalizeAndValidatePath(
107 &default_icon)) {
108 // Choose the most optimistic (highest) icon density - e.g. 38 not 19 -
109 // regardless of the actual icon resolution, whatever that happens to be.
110 // Code elsewhere knows how to scale 38 down to 19.
111 result->default_icon.Add(extension_misc::EXTENSION_ICON_ACTION *
112 extension_misc::kNumExtensionActionIconSizes,
113 default_icon);
114 } else {
115 *error = base::ASCIIToUTF16(errors::kInvalidPageActionIconPath);
116 return scoped_ptr<ActionInfo>();
120 // Read the page action title from |default_title| if present, |name| if not
121 // (both optional).
122 if (dict->HasKey(keys::kPageActionDefaultTitle)) {
123 if (!dict->GetString(keys::kPageActionDefaultTitle,
124 &result->default_title)) {
125 *error = base::ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle);
126 return scoped_ptr<ActionInfo>();
128 } else if (extension->manifest_version() == 1 && dict->HasKey(keys::kName)) {
129 if (!dict->GetString(keys::kName, &result->default_title)) {
130 *error = base::ASCIIToUTF16(errors::kInvalidPageActionName);
131 return scoped_ptr<ActionInfo>();
135 // Read the action's |popup| (optional).
136 const char* popup_key = NULL;
137 if (dict->HasKey(keys::kPageActionDefaultPopup))
138 popup_key = keys::kPageActionDefaultPopup;
140 if (extension->manifest_version() == 1 &&
141 dict->HasKey(keys::kPageActionPopup)) {
142 if (popup_key) {
143 *error = ErrorUtils::FormatErrorMessageUTF16(
144 errors::kInvalidPageActionOldAndNewKeys,
145 keys::kPageActionDefaultPopup,
146 keys::kPageActionPopup);
147 return scoped_ptr<ActionInfo>();
149 popup_key = keys::kPageActionPopup;
152 if (popup_key) {
153 const base::DictionaryValue* popup = NULL;
154 std::string url_str;
156 if (dict->GetString(popup_key, &url_str)) {
157 // On success, |url_str| is set. Nothing else to do.
158 } else if (extension->manifest_version() == 1 &&
159 dict->GetDictionary(popup_key, &popup)) {
160 if (!popup->GetString(keys::kPageActionPopupPath, &url_str)) {
161 *error = ErrorUtils::FormatErrorMessageUTF16(
162 errors::kInvalidPageActionPopupPath, "<missing>");
163 return scoped_ptr<ActionInfo>();
165 } else {
166 *error = base::ASCIIToUTF16(errors::kInvalidPageActionPopup);
167 return scoped_ptr<ActionInfo>();
170 if (!url_str.empty()) {
171 // An empty string is treated as having no popup.
172 result->default_popup_url = Extension::GetResourceURL(extension->url(),
173 url_str);
174 if (!result->default_popup_url.is_valid()) {
175 *error = ErrorUtils::FormatErrorMessageUTF16(
176 errors::kInvalidPageActionPopupPath, url_str);
177 return scoped_ptr<ActionInfo>();
179 } else {
180 DCHECK(result->default_popup_url.is_empty())
181 << "Shouldn't be possible for the popup to be set.";
185 return result.Pass();
188 // static
189 const ActionInfo* ActionInfo::GetBrowserActionInfo(const Extension* extension) {
190 return GetActionInfo(extension, keys::kBrowserAction);
193 const ActionInfo* ActionInfo::GetPageActionInfo(const Extension* extension) {
194 return GetActionInfo(extension, keys::kPageAction);
197 // static
198 const ActionInfo* ActionInfo::GetSystemIndicatorInfo(
199 const Extension* extension) {
200 return GetActionInfo(extension, keys::kSystemIndicator);
203 // static
204 void ActionInfo::SetBrowserActionInfo(Extension* extension, ActionInfo* info) {
205 extension->SetManifestData(keys::kBrowserAction,
206 new ActionInfoData(info));
209 // static
210 void ActionInfo::SetPageActionInfo(Extension* extension, ActionInfo* info) {
211 extension->SetManifestData(keys::kPageAction,
212 new ActionInfoData(info));
215 // static
216 void ActionInfo::SetSystemIndicatorInfo(Extension* extension,
217 ActionInfo* info) {
218 extension->SetManifestData(keys::kSystemIndicator, new ActionInfoData(info));
221 // static
222 bool ActionInfo::IsVerboseInstallMessage(const Extension* extension) {
223 const ActionInfo* page_action_info = GetPageActionInfo(extension);
224 return page_action_info &&
225 (CommandsInfo::GetPageActionCommand(extension) ||
226 !page_action_info->default_icon.empty());
229 } // namespace extensions