• 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 "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"
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,
24 // PageActions and SystemIndicators.
25 struct ActionInfoData : public Extension::ManifestData {
26   explicit ActionInfoData(ActionInfo* action_info);
27   virtual ~ActionInfoData();
28 
29   // The action associated with the BrowserAction.
30   scoped_ptr<ActionInfo> action_info;
31 };
32 
ActionInfoData(ActionInfo * info)33 ActionInfoData::ActionInfoData(ActionInfo* info) : action_info(info) {
34 }
35 
~ActionInfoData()36 ActionInfoData::~ActionInfoData() {
37 }
38 
GetActionInfo(const Extension * extension,const std::string & key)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;
44 }
45 
46 }  // namespace
47 
ActionInfo()48 ActionInfo::ActionInfo() {
49 }
50 
~ActionInfo()51 ActionInfo::~ActionInfo() {
52 }
53 
54 // static
Load(const Extension * extension,const base::DictionaryValue * dict,base::string16 * error)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());
59 
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>();
73       }
74       result->default_icon.Add(extension_misc::EXTENSION_ICON_ACTION, path);
75     }
76 
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>();
82       }
83       result->id = id;
84     }
85   }
86 
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       if (!manifest_handler_helpers::LoadIconsFromDictionary(
95               icons_value,
96               extension_misc::kExtensionActionIconSizes,
97               extension_misc::kNumExtensionActionIconSizes,
98               &result->default_icon,
99               error)) {
100         return scoped_ptr<ActionInfo>();
101       }
102     } else if (dict->GetString(keys::kPageActionDefaultIcon, &default_icon) &&
103                manifest_handler_helpers::NormalizeAndValidatePath(
104                    &default_icon)) {
105       result->default_icon.Add(extension_misc::EXTENSION_ICON_ACTION,
106                                default_icon);
107     } else {
108       *error = base::ASCIIToUTF16(errors::kInvalidPageActionIconPath);
109       return scoped_ptr<ActionInfo>();
110     }
111   }
112 
113   // Read the page action title from |default_title| if present, |name| if not
114   // (both optional).
115   if (dict->HasKey(keys::kPageActionDefaultTitle)) {
116     if (!dict->GetString(keys::kPageActionDefaultTitle,
117                          &result->default_title)) {
118       *error = base::ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle);
119       return scoped_ptr<ActionInfo>();
120     }
121   } else if (extension->manifest_version() == 1 && dict->HasKey(keys::kName)) {
122     if (!dict->GetString(keys::kName, &result->default_title)) {
123       *error = base::ASCIIToUTF16(errors::kInvalidPageActionName);
124       return scoped_ptr<ActionInfo>();
125     }
126   }
127 
128   // Read the action's |popup| (optional).
129   const char* popup_key = NULL;
130   if (dict->HasKey(keys::kPageActionDefaultPopup))
131     popup_key = keys::kPageActionDefaultPopup;
132 
133   if (extension->manifest_version() == 1 &&
134       dict->HasKey(keys::kPageActionPopup)) {
135     if (popup_key) {
136       *error = ErrorUtils::FormatErrorMessageUTF16(
137           errors::kInvalidPageActionOldAndNewKeys,
138           keys::kPageActionDefaultPopup,
139           keys::kPageActionPopup);
140       return scoped_ptr<ActionInfo>();
141     }
142     popup_key = keys::kPageActionPopup;
143   }
144 
145   if (popup_key) {
146     const base::DictionaryValue* popup = NULL;
147     std::string url_str;
148 
149     if (dict->GetString(popup_key, &url_str)) {
150       // On success, |url_str| is set.  Nothing else to do.
151     } else if (extension->manifest_version() == 1 &&
152                dict->GetDictionary(popup_key, &popup)) {
153       if (!popup->GetString(keys::kPageActionPopupPath, &url_str)) {
154         *error = ErrorUtils::FormatErrorMessageUTF16(
155             errors::kInvalidPageActionPopupPath, "<missing>");
156         return scoped_ptr<ActionInfo>();
157       }
158     } else {
159       *error = base::ASCIIToUTF16(errors::kInvalidPageActionPopup);
160       return scoped_ptr<ActionInfo>();
161     }
162 
163     if (!url_str.empty()) {
164       // An empty string is treated as having no popup.
165       result->default_popup_url = Extension::GetResourceURL(extension->url(),
166                                                             url_str);
167       if (!result->default_popup_url.is_valid()) {
168         *error = ErrorUtils::FormatErrorMessageUTF16(
169             errors::kInvalidPageActionPopupPath, url_str);
170         return scoped_ptr<ActionInfo>();
171       }
172     } else {
173       DCHECK(result->default_popup_url.is_empty())
174           << "Shouldn't be possible for the popup to be set.";
175     }
176   }
177 
178   return result.Pass();
179 }
180 
181 // static
GetBrowserActionInfo(const Extension * extension)182 const ActionInfo* ActionInfo::GetBrowserActionInfo(const Extension* extension) {
183   return GetActionInfo(extension, keys::kBrowserAction);
184 }
185 
GetPageActionInfo(const Extension * extension)186 const ActionInfo* ActionInfo::GetPageActionInfo(const Extension* extension) {
187   return GetActionInfo(extension, keys::kPageAction);
188 }
189 
190 // static
GetSystemIndicatorInfo(const Extension * extension)191 const ActionInfo* ActionInfo::GetSystemIndicatorInfo(
192     const Extension* extension) {
193   return GetActionInfo(extension, keys::kSystemIndicator);
194 }
195 
196 // static
SetBrowserActionInfo(Extension * extension,ActionInfo * info)197 void ActionInfo::SetBrowserActionInfo(Extension* extension, ActionInfo* info) {
198   extension->SetManifestData(keys::kBrowserAction,
199                              new ActionInfoData(info));
200 }
201 
202 // static
SetPageActionInfo(Extension * extension,ActionInfo * info)203 void ActionInfo::SetPageActionInfo(Extension* extension, ActionInfo* info) {
204   extension->SetManifestData(keys::kPageAction,
205                              new ActionInfoData(info));
206 }
207 
208 // static
SetSystemIndicatorInfo(Extension * extension,ActionInfo * info)209 void ActionInfo::SetSystemIndicatorInfo(Extension* extension,
210                                         ActionInfo* info) {
211   extension->SetManifestData(keys::kSystemIndicator, new ActionInfoData(info));
212 }
213 
214 // static
IsVerboseInstallMessage(const Extension * extension)215 bool ActionInfo::IsVerboseInstallMessage(const Extension* extension) {
216   const ActionInfo* page_action_info = GetPageActionInfo(extension);
217   return page_action_info &&
218       (CommandsInfo::GetPageActionCommand(extension) ||
219        !page_action_info->default_icon.empty());
220 }
221 
222 }  // namespace extensions
223