• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/common/extensions/api/extension_action/action_info.h"
6 
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 "chrome/common/extensions/extension_constants.h"
11 #include "chrome/common/extensions/manifest_handler_helpers.h"
12 #include "extensions/common/error_utils.h"
13 #include "extensions/common/extension.h"
14 #include "extensions/common/manifest_constants.h"
15 
16 namespace extensions {
17 
18 namespace errors = manifest_errors;
19 namespace keys = manifest_keys;
20 
21 namespace {
22 
23 // The manifest data container for the ActionInfos for BrowserActions and
24 // ScriptBadges.
25 struct ActionInfoData : public Extension::ManifestData {
26   explicit ActionInfoData(ActionInfo* action_info);
27   virtual ~ActionInfoData();
28 
29   // The action associated with the BrowserAction or ScriptBadge.
30   // This is never NULL for ScriptBadge.
31   scoped_ptr<ActionInfo> action_info;
32 };
33 
ActionInfoData(ActionInfo * info)34 ActionInfoData::ActionInfoData(ActionInfo* info) : action_info(info) {
35 }
36 
~ActionInfoData()37 ActionInfoData::~ActionInfoData() {
38 }
39 
GetActionInfo(const Extension * extension,const std::string & key)40 static const ActionInfo* GetActionInfo(const Extension* extension,
41                                        const std::string& key) {
42   ActionInfoData* data = static_cast<ActionInfoData*>(
43       extension->GetManifestData(key));
44   return data ? data->action_info.get() : NULL;
45 }
46 
47 }  // namespace
48 
ActionInfo()49 ActionInfo::ActionInfo() {
50 }
51 
~ActionInfo()52 ActionInfo::~ActionInfo() {
53 }
54 
55 // static
Load(const Extension * extension,const base::DictionaryValue * dict,base::string16 * error)56 scoped_ptr<ActionInfo> ActionInfo::Load(const Extension* extension,
57                                         const base::DictionaryValue* dict,
58                                         base::string16* error) {
59   scoped_ptr<ActionInfo> result(new ActionInfo());
60 
61   if (extension->manifest_version() == 1) {
62     // kPageActionIcons is obsolete, and used by very few extensions. Continue
63     // loading it, but only take the first icon as the default_icon path.
64     const base::ListValue* icons = NULL;
65     if (dict->HasKey(keys::kPageActionIcons) &&
66         dict->GetList(keys::kPageActionIcons, &icons)) {
67       base::ListValue::const_iterator iter = icons->begin();
68       std::string path;
69       if (iter == icons->end() ||
70           !(*iter)->GetAsString(&path) ||
71           !manifest_handler_helpers::NormalizeAndValidatePath(&path)) {
72         *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath);
73         return scoped_ptr<ActionInfo>();
74       }
75       result->default_icon.Add(extension_misc::EXTENSION_ICON_ACTION, path);
76     }
77 
78     std::string id;
79     if (dict->HasKey(keys::kPageActionId)) {
80       if (!dict->GetString(keys::kPageActionId, &id)) {
81         *error = ASCIIToUTF16(errors::kInvalidPageActionId);
82         return scoped_ptr<ActionInfo>();
83       }
84       result->id = id;
85     }
86   }
87 
88   // Read the page action |default_icon| (optional).
89   // The |default_icon| value can be either dictionary {icon size -> icon path}
90   // or non empty string value.
91   if (dict->HasKey(keys::kPageActionDefaultIcon)) {
92     const DictionaryValue* icons_value = NULL;
93     std::string default_icon;
94     if (dict->GetDictionary(keys::kPageActionDefaultIcon, &icons_value)) {
95       if (!manifest_handler_helpers::LoadIconsFromDictionary(
96               icons_value,
97               extension_misc::kExtensionActionIconSizes,
98               extension_misc::kNumExtensionActionIconSizes,
99               &result->default_icon,
100               error)) {
101         return scoped_ptr<ActionInfo>();
102       }
103     } else if (dict->GetString(keys::kPageActionDefaultIcon, &default_icon) &&
104                manifest_handler_helpers::NormalizeAndValidatePath(
105                    &default_icon)) {
106       result->default_icon.Add(extension_misc::EXTENSION_ICON_ACTION,
107                                default_icon);
108     } else {
109       *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath);
110       return scoped_ptr<ActionInfo>();
111     }
112   }
113 
114   // Read the page action title from |default_title| if present, |name| if not
115   // (both optional).
116   if (dict->HasKey(keys::kPageActionDefaultTitle)) {
117     if (!dict->GetString(keys::kPageActionDefaultTitle,
118                          &result->default_title)) {
119       *error = ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle);
120       return scoped_ptr<ActionInfo>();
121     }
122   } else if (extension->manifest_version() == 1 && dict->HasKey(keys::kName)) {
123     if (!dict->GetString(keys::kName, &result->default_title)) {
124       *error = ASCIIToUTF16(errors::kInvalidPageActionName);
125       return scoped_ptr<ActionInfo>();
126     }
127   }
128 
129   // Read the action's |popup| (optional).
130   const char* popup_key = NULL;
131   if (dict->HasKey(keys::kPageActionDefaultPopup))
132     popup_key = keys::kPageActionDefaultPopup;
133 
134   if (extension->manifest_version() == 1 &&
135       dict->HasKey(keys::kPageActionPopup)) {
136     if (popup_key) {
137       *error = ErrorUtils::FormatErrorMessageUTF16(
138           errors::kInvalidPageActionOldAndNewKeys,
139           keys::kPageActionDefaultPopup,
140           keys::kPageActionPopup);
141       return scoped_ptr<ActionInfo>();
142     }
143     popup_key = keys::kPageActionPopup;
144   }
145 
146   if (popup_key) {
147     const DictionaryValue* popup = NULL;
148     std::string url_str;
149 
150     if (dict->GetString(popup_key, &url_str)) {
151       // On success, |url_str| is set.  Nothing else to do.
152     } else if (extension->manifest_version() == 1 &&
153                dict->GetDictionary(popup_key, &popup)) {
154       if (!popup->GetString(keys::kPageActionPopupPath, &url_str)) {
155         *error = ErrorUtils::FormatErrorMessageUTF16(
156             errors::kInvalidPageActionPopupPath, "<missing>");
157         return scoped_ptr<ActionInfo>();
158       }
159     } else {
160       *error = ASCIIToUTF16(errors::kInvalidPageActionPopup);
161       return scoped_ptr<ActionInfo>();
162     }
163 
164     if (!url_str.empty()) {
165       // An empty string is treated as having no popup.
166       result->default_popup_url = Extension::GetResourceURL(extension->url(),
167                                                             url_str);
168       if (!result->default_popup_url.is_valid()) {
169         *error = ErrorUtils::FormatErrorMessageUTF16(
170             errors::kInvalidPageActionPopupPath, url_str);
171         return scoped_ptr<ActionInfo>();
172       }
173     } else {
174       DCHECK(result->default_popup_url.is_empty())
175           << "Shouldn't be possible for the popup to be set.";
176     }
177   }
178 
179   return result.Pass();
180 }
181 
182 // static
GetBrowserActionInfo(const Extension * extension)183 const ActionInfo* ActionInfo::GetBrowserActionInfo(const Extension* extension) {
184   return GetActionInfo(extension, keys::kBrowserAction);
185 }
186 
GetPageActionInfo(const Extension * extension)187 const ActionInfo* ActionInfo::GetPageActionInfo(const Extension* extension) {
188   return GetActionInfo(extension, keys::kPageAction);
189 }
190 
191 // static
GetScriptBadgeInfo(const Extension * extension)192 const ActionInfo* ActionInfo::GetScriptBadgeInfo(const Extension* extension) {
193   return GetActionInfo(extension, keys::kScriptBadge);
194 }
195 
196 // static
GetSystemIndicatorInfo(const Extension * extension)197 const ActionInfo* ActionInfo::GetSystemIndicatorInfo(
198     const Extension* extension) {
199   return GetActionInfo(extension, keys::kSystemIndicator);
200 }
201 
202 // static
SetBrowserActionInfo(Extension * extension,ActionInfo * info)203 void ActionInfo::SetBrowserActionInfo(Extension* extension, ActionInfo* info) {
204   extension->SetManifestData(keys::kBrowserAction,
205                              new ActionInfoData(info));
206 }
207 
208 // static
SetPageActionInfo(Extension * extension,ActionInfo * info)209 void ActionInfo::SetPageActionInfo(Extension* extension, ActionInfo* info) {
210   extension->SetManifestData(keys::kPageAction,
211                              new ActionInfoData(info));
212 }
213 
214 // static
SetScriptBadgeInfo(Extension * extension,ActionInfo * info)215 void ActionInfo::SetScriptBadgeInfo(Extension* extension, ActionInfo* info) {
216   extension->SetManifestData(keys::kScriptBadge,
217                              new ActionInfoData(info));
218 }
219 
220 // static
SetSystemIndicatorInfo(Extension * extension,ActionInfo * info)221 void ActionInfo::SetSystemIndicatorInfo(Extension* extension,
222                                         ActionInfo* info) {
223   extension->SetManifestData(keys::kSystemIndicator, new ActionInfoData(info));
224 }
225 
226 // static
IsVerboseInstallMessage(const Extension * extension)227 bool ActionInfo::IsVerboseInstallMessage(const Extension* extension) {
228   const ActionInfo* page_action_info = GetPageActionInfo(extension);
229   return page_action_info &&
230       (CommandsInfo::GetPageActionCommand(extension) ||
231        !page_action_info->default_icon.empty());
232 }
233 
234 }  // namespace extensions
235