Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(144)

Side by Side Diff: chrome/common/extensions/extension.cc

Issue 9402018: Experimental Extension Keybinding (first cut). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/common/extensions/extension.h ('k') | chrome/common/extensions/extension_constants.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/common/extensions/extension.h" 5 #include "chrome/common/extensions/extension.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/base64.h" 9 #include "base/base64.h"
10 #include "base/basictypes.h" 10 #include "base/basictypes.h"
11 #include "base/command_line.h" 11 #include "base/command_line.h"
12 #include "base/file_path.h" 12 #include "base/file_path.h"
13 #include "base/file_util.h" 13 #include "base/file_util.h"
14 #include "base/i18n/rtl.h" 14 #include "base/i18n/rtl.h"
15 #include "base/logging.h" 15 #include "base/logging.h"
16 #include "base/memory/singleton.h" 16 #include "base/memory/singleton.h"
17 #include "base/stl_util.h" 17 #include "base/stl_util.h"
18 #include "base/string16.h" 18 #include "base/string16.h"
19 #include "base/string_number_conversions.h" 19 #include "base/string_number_conversions.h"
20 #include "base/string_piece.h" 20 #include "base/string_piece.h"
21 #include "base/string_split.h"
21 #include "base/string_util.h" 22 #include "base/string_util.h"
22 #include "base/utf_string_conversions.h" 23 #include "base/utf_string_conversions.h"
23 #include "base/values.h" 24 #include "base/values.h"
24 #include "base/version.h" 25 #include "base/version.h"
25 #include "crypto/sha2.h" 26 #include "crypto/sha2.h"
26 #include "chrome/common/chrome_constants.h" 27 #include "chrome/common/chrome_constants.h"
27 #include "chrome/common/chrome_switches.h" 28 #include "chrome/common/chrome_switches.h"
28 #include "chrome/common/chrome_version_info.h" 29 #include "chrome/common/chrome_version_info.h"
29 #include "chrome/common/extensions/csp_validator.h" 30 #include "chrome/common/extensions/csp_validator.h"
30 #include "chrome/common/extensions/extension_action.h" 31 #include "chrome/common/extensions/extension_action.h"
31 #include "chrome/common/extensions/extension_constants.h" 32 #include "chrome/common/extensions/extension_constants.h"
32 #include "chrome/common/extensions/extension_error_utils.h" 33 #include "chrome/common/extensions/extension_error_utils.h"
33 #include "chrome/common/extensions/extension_resource.h" 34 #include "chrome/common/extensions/extension_resource.h"
34 #include "chrome/common/extensions/file_browser_handler.h" 35 #include "chrome/common/extensions/file_browser_handler.h"
35 #include "chrome/common/extensions/manifest.h" 36 #include "chrome/common/extensions/manifest.h"
36 #include "chrome/common/extensions/user_script.h" 37 #include "chrome/common/extensions/user_script.h"
37 #include "chrome/common/url_constants.h" 38 #include "chrome/common/url_constants.h"
38 #include "googleurl/src/url_util.h" 39 #include "googleurl/src/url_util.h"
39 #include "grit/chromium_strings.h" 40 #include "grit/chromium_strings.h"
40 #include "grit/generated_resources.h" 41 #include "grit/generated_resources.h"
41 #include "grit/theme_resources.h" 42 #include "grit/theme_resources.h"
42 #include "net/base/registry_controlled_domain.h" 43 #include "net/base/registry_controlled_domain.h"
43 #include "third_party/skia/include/core/SkBitmap.h" 44 #include "third_party/skia/include/core/SkBitmap.h"
45 #include "ui/base/keycodes/keyboard_codes.h"
44 #include "ui/base/l10n/l10n_util.h" 46 #include "ui/base/l10n/l10n_util.h"
45 #include "ui/base/resource/resource_bundle.h" 47 #include "ui/base/resource/resource_bundle.h"
46 #include "webkit/glue/image_decoder.h" 48 #include "webkit/glue/image_decoder.h"
47 #include "webkit/glue/web_intent_service_data.h" 49 #include "webkit/glue/web_intent_service_data.h"
48 50
49 namespace keys = extension_manifest_keys; 51 namespace keys = extension_manifest_keys;
50 namespace values = extension_manifest_values; 52 namespace values = extension_manifest_values;
51 namespace errors = extension_manifest_errors; 53 namespace errors = extension_manifest_errors;
52 54
53 using extensions::csp_validator::ContentSecurityPolicyIsLegal; 55 using extensions::csp_validator::ContentSecurityPolicyIsLegal;
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 shortcut_alt(false), 213 shortcut_alt(false),
212 shortcut_ctrl(false), 214 shortcut_ctrl(false),
213 shortcut_shift(false) { 215 shortcut_shift(false) {
214 } 216 }
215 217
216 Extension::InputComponentInfo::~InputComponentInfo() {} 218 Extension::InputComponentInfo::~InputComponentInfo() {}
217 219
218 Extension::TtsVoice::TtsVoice() {} 220 Extension::TtsVoice::TtsVoice() {}
219 Extension::TtsVoice::~TtsVoice() {} 221 Extension::TtsVoice::~TtsVoice() {}
220 222
223 Extension::ExtensionKeybinding::ExtensionKeybinding() {}
224 Extension::ExtensionKeybinding::~ExtensionKeybinding() {}
225
226 bool Extension::ExtensionKeybinding::Parse(DictionaryValue* command,
227 const std::string& command_name,
228 int index,
229 string16* error) {
230 DCHECK(!command_name.empty());
231 std::string key_binding;
232 if (!command->GetString(keys::kKey, &key_binding) ||
233 key_binding.empty()) {
234 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
235 errors::kInvalidKeyBinding,
236 base::IntToString(index),
237 "Missing");
238 return false;
239 }
240
241 std::string original_keybinding = key_binding;
242 // Normalize '-' to '+'.
243 ReplaceSubstringsAfterOffset(&key_binding, 0, "-", "+");
244 // Remove all spaces.
245 ReplaceSubstringsAfterOffset(&key_binding, 0, " ", "");
246 // And finally, lower-case it.
247 key_binding = StringToLowerASCII(key_binding);
248
249 std::vector<std::string> tokens;
250 base::SplitString(key_binding, '+', &tokens);
251 if (tokens.size() < 2 || tokens.size() > 3) {
252 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
253 errors::kInvalidKeyBinding,
254 base::IntToString(index),
255 original_keybinding);
256 return false;
257 }
258
259 // Now, parse it into an accelerator.
260 bool ctrl = false;
261 bool alt = false;
262 bool shift = false;
263 ui::KeyboardCode key = ui::VKEY_UNKNOWN;
264 for (size_t i = 0; i < tokens.size(); i++) {
265 if (tokens[i] == "ctrl") {
266 ctrl = true;
267 } else if (tokens[i] == "alt") {
268 alt = true;
269 } else if (tokens[i] == "shift") {
270 shift = true;
271 } else if (tokens[i].size() == 1 &&
272 base::ToUpperASCII(tokens[i][0]) >= ui::VKEY_A &&
273 base::ToUpperASCII(tokens[i][0]) <= ui::VKEY_Z) {
274 if (key != ui::VKEY_UNKNOWN) {
275 // Multiple key assignments.
276 key = ui::VKEY_UNKNOWN;
277 break;
278 }
279
280 key = static_cast<ui::KeyboardCode>(
281 ui::VKEY_A + (base::ToUpperASCII(tokens[i][0]) - ui::VKEY_A));
282 } else {
283 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
284 errors::kInvalidKeyBinding,
285 base::IntToString(index),
286 original_keybinding);
287 return false;
288 }
289 }
290
291 // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not
292 // Ctrl+Alt+foo. For a more detailed reason why we don't support Ctrl+Alt+foo:
293 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx.
294 if (key == ui::VKEY_UNKNOWN || (ctrl == true && alt == true)) {
295 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
296 errors::kInvalidKeyBinding,
297 base::IntToString(index),
298 original_keybinding);
299 return false;
300 }
301
302 accelerator_ = ui::Accelerator(key, shift, ctrl, alt);
303
304 if (command_name !=
305 extension_manifest_values::kPageActionKeybindingEvent &&
306 command_name !=
307 extension_manifest_values::kBrowserActionKeybindingEvent) {
308 if (!command->GetString(keys::kDescription, &description_) ||
309 description_.empty()) {
310 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
311 errors::kInvalidKeyBindingDescription,
312 base::IntToString(index));
313 return false;
314 }
315 }
316
317 command_name_ = command_name;
318 return true;
319 }
320
221 // 321 //
222 // Extension 322 // Extension
223 // 323 //
224 324
225 // static 325 // static
226 scoped_refptr<Extension> Extension::Create(const FilePath& path, 326 scoped_refptr<Extension> Extension::Create(const FilePath& path,
227 Location location, 327 Location location,
228 const DictionaryValue& value, 328 const DictionaryValue& value,
229 int flags, 329 int flags,
230 std::string* utf8_error) { 330 std::string* utf8_error) {
(...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after
850 errors::kInvalidURLPatternError, filter); 950 errors::kInvalidURLPatternError, filter);
851 return NULL; 951 return NULL;
852 } 952 }
853 result->AddPattern(pattern); 953 result->AddPattern(pattern);
854 } 954 }
855 955
856 std::string default_icon; 956 std::string default_icon;
857 // Read the file browser action |default_icon| (optional). 957 // Read the file browser action |default_icon| (optional).
858 if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) { 958 if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) {
859 if (!file_browser_handler->GetString( 959 if (!file_browser_handler->GetString(
860 keys::kPageActionDefaultIcon,&default_icon) || 960 keys::kPageActionDefaultIcon, &default_icon) ||
861 default_icon.empty()) { 961 default_icon.empty()) {
862 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath); 962 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath);
863 return NULL; 963 return NULL;
864 } 964 }
865 result->set_icon_path(default_icon); 965 result->set_icon_path(default_icon);
866 } 966 }
867 967
868 return result.release(); 968 return result.release();
869 } 969 }
870 970
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after
1151 *error = ASCIIToUTF16(errors::kInvalidIntent); 1251 *error = ASCIIToUTF16(errors::kInvalidIntent);
1152 return false; 1252 return false;
1153 } 1253 }
1154 service.action = UTF8ToUTF16(*iter); 1254 service.action = UTF8ToUTF16(*iter);
1155 1255
1156 ListValue* mime_types = NULL; 1256 ListValue* mime_types = NULL;
1157 if (!one_service->HasKey(keys::kIntentType) || 1257 if (!one_service->HasKey(keys::kIntentType) ||
1158 !one_service->GetList(keys::kIntentType, &mime_types) || 1258 !one_service->GetList(keys::kIntentType, &mime_types) ||
1159 mime_types->GetSize() == 0) { 1259 mime_types->GetSize() == 0) {
1160 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 1260 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1161 errors::kInvalidIntentType,*iter); 1261 errors::kInvalidIntentType, *iter);
1162 return false; 1262 return false;
1163 } 1263 }
1164 1264
1165 if (one_service->HasKey(keys::kIntentPath)) { 1265 if (one_service->HasKey(keys::kIntentPath)) {
1166 if (!one_service->GetString(keys::kIntentPath, &value)) { 1266 if (!one_service->GetString(keys::kIntentPath, &value)) {
1167 *error = ASCIIToUTF16(errors::kInvalidIntentPath); 1267 *error = ASCIIToUTF16(errors::kInvalidIntentPath);
1168 return false; 1268 return false;
1169 } 1269 }
1170 if (is_hosted_app()) { 1270 if (is_hosted_app()) {
1171 // Hosted apps require an absolute URL for intents. 1271 // Hosted apps require an absolute URL for intents.
1172 GURL service_url(value); 1272 GURL service_url(value);
1173 if (!service_url.is_valid() || 1273 if (!service_url.is_valid() ||
1174 !(web_extent().MatchesURL(service_url))) { 1274 !(web_extent().MatchesURL(service_url))) {
1175 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 1275 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1176 errors::kInvalidIntentPageInHostedApp,*iter); 1276 errors::kInvalidIntentPageInHostedApp, *iter);
1177 return false; 1277 return false;
1178 } 1278 }
1179 service.service_url = service_url; 1279 service.service_url = service_url;
1180 } else { 1280 } else {
1181 // We do not allow absolute intent URLs in non-hosted apps. 1281 // We do not allow absolute intent URLs in non-hosted apps.
1182 if (GURL(value).is_valid()) { 1282 if (GURL(value).is_valid()) {
1183 *error =ExtensionErrorUtils::FormatErrorMessageUTF16( 1283 *error =ExtensionErrorUtils::FormatErrorMessageUTF16(
1184 errors::kCannotAccessPage,value.c_str()); 1284 errors::kCannotAccessPage, value.c_str());
1185 return false; 1285 return false;
1186 } 1286 }
1187 service.service_url = GetResourceURL(value); 1287 service.service_url = GetResourceURL(value);
1188 } 1288 }
1189 } 1289 }
1190 1290
1191 if (one_service->HasKey(keys::kIntentTitle) && 1291 if (one_service->HasKey(keys::kIntentTitle) &&
1192 !one_service->GetString(keys::kIntentTitle, &service.title)) { 1292 !one_service->GetString(keys::kIntentTitle, &service.title)) {
1193 *error = ASCIIToUTF16(errors::kInvalidIntentTitle); 1293 *error = ASCIIToUTF16(errors::kInvalidIntentTitle);
1194 return false; 1294 return false;
(...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after
1708 minimum_version_string); 1808 minimum_version_string);
1709 return false; 1809 return false;
1710 } 1810 }
1711 } 1811 }
1712 1812
1713 // Initialize converted_from_user_script (if present) 1813 // Initialize converted_from_user_script (if present)
1714 if (manifest->HasKey(keys::kConvertedFromUserScript)) 1814 if (manifest->HasKey(keys::kConvertedFromUserScript))
1715 manifest->GetBoolean(keys::kConvertedFromUserScript, 1815 manifest->GetBoolean(keys::kConvertedFromUserScript,
1716 &converted_from_user_script_); 1816 &converted_from_user_script_);
1717 1817
1818 // Initialize commands (if present).
1819 if (manifest->HasKey(keys::kCommands)) {
1820 DictionaryValue* commands = NULL;
1821 if (!manifest->GetDictionary(keys::kCommands, &commands)) {
1822 *error = ASCIIToUTF16(errors::kInvalidCommandsKey);
1823 return false;
1824 }
1825
1826 int command_index = 0;
1827 for (DictionaryValue::key_iterator iter = commands->begin_keys();
1828 iter != commands->end_keys(); ++iter) {
1829 ++command_index;
1830
1831 DictionaryValue* command = NULL;
1832 if (!commands->GetDictionary(*iter, &command)) {
1833 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1834 errors::kInvalidKeyBindingDictionary,
1835 base::IntToString(command_index));
1836 return false;
1837 }
1838
1839 ExtensionKeybinding binding;
1840 if (!binding.Parse(command, *iter, command_index, error))
1841 return false; // |error| already set.
1842
1843 commands_.push_back(binding);
1844 }
1845 }
1846
1718 // Initialize icons (if present). 1847 // Initialize icons (if present).
1719 if (manifest->HasKey(keys::kIcons)) { 1848 if (manifest->HasKey(keys::kIcons)) {
1720 DictionaryValue* icons_value = NULL; 1849 DictionaryValue* icons_value = NULL;
1721 if (!manifest->GetDictionary(keys::kIcons, &icons_value)) { 1850 if (!manifest->GetDictionary(keys::kIcons, &icons_value)) {
1722 *error = ASCIIToUTF16(errors::kInvalidIcons); 1851 *error = ASCIIToUTF16(errors::kInvalidIcons);
1723 return false; 1852 return false;
1724 } 1853 }
1725 1854
1726 for (size_t i = 0; i < arraysize(kIconSizes); ++i) { 1855 for (size_t i = 0; i < arraysize(kIconSizes); ++i) {
1727 std::string key = base::IntToString(kIconSizes[i]); 1856 std::string key = base::IntToString(kIconSizes[i]);
(...skipping 1137 matching lines...) Expand 10 before | Expand all | Expand 10 after
2865 2994
2866 if (permission->id() == ExtensionAPIPermission::kExperimental) { 2995 if (permission->id() == ExtensionAPIPermission::kExperimental) {
2867 if (!CanSpecifyExperimentalPermission()) { 2996 if (!CanSpecifyExperimentalPermission()) {
2868 *error = ASCIIToUTF16(errors::kExperimentalFlagRequired); 2997 *error = ASCIIToUTF16(errors::kExperimentalFlagRequired);
2869 return false; 2998 return false;
2870 } 2999 }
2871 } 3000 }
2872 3001
2873 bool supports_type = false; 3002 bool supports_type = false;
2874 switch (GetType()) { 3003 switch (GetType()) {
2875 case TYPE_USER_SCRIPT: // Pass through. 3004 case TYPE_USER_SCRIPT: // Pass through.
2876 case TYPE_EXTENSION: 3005 case TYPE_EXTENSION:
2877 supports_type = permission->supports_extensions(); 3006 supports_type = permission->supports_extensions();
2878 break; 3007 break;
2879 case TYPE_HOSTED_APP: 3008 case TYPE_HOSTED_APP:
2880 supports_type = permission->supports_hosted_apps(); 3009 supports_type = permission->supports_hosted_apps();
2881 break; 3010 break;
2882 case TYPE_PACKAGED_APP: 3011 case TYPE_PACKAGED_APP:
2883 supports_type = permission->supports_packaged_apps(); 3012 supports_type = permission->supports_packaged_apps();
2884 break; 3013 break;
2885 case TYPE_PLATFORM_APP: 3014 case TYPE_PLATFORM_APP:
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
3021 } 3150 }
3022 } 3151 }
3023 3152
3024 bool Extension::IsSyncable() const { 3153 bool Extension::IsSyncable() const {
3025 // TODO(akalin): Figure out if we need to allow some other types. 3154 // TODO(akalin): Figure out if we need to allow some other types.
3026 3155
3027 // We want to sync any extensions that are shown in the luancher because 3156 // We want to sync any extensions that are shown in the luancher because
3028 // their positions should sync. 3157 // their positions should sync.
3029 return location_ == Extension::INTERNAL || 3158 return location_ == Extension::INTERNAL ||
3030 ShouldDisplayInLauncher(); 3159 ShouldDisplayInLauncher();
3031
3032 } 3160 }
3033 3161
3034 bool Extension::ShouldDisplayInLauncher() const { 3162 bool Extension::ShouldDisplayInLauncher() const {
3035 // All apps should be displayed on the NTP except for the Cloud Print App. 3163 // All apps should be displayed on the NTP except for the Cloud Print App.
3036 return is_app() && id() != extension_misc::kCloudPrintAppId; 3164 return is_app() && id() != extension_misc::kCloudPrintAppId;
3037 } 3165 }
3038 3166
3039 ExtensionInfo::ExtensionInfo(const DictionaryValue* manifest, 3167 ExtensionInfo::ExtensionInfo(const DictionaryValue* manifest,
3040 const std::string& id, 3168 const std::string& id,
3041 const FilePath& path, 3169 const FilePath& path,
(...skipping 29 matching lines...) Expand all
3071 already_disabled(false), 3199 already_disabled(false),
3072 extension(extension) {} 3200 extension(extension) {}
3073 3201
3074 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( 3202 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo(
3075 const Extension* extension, 3203 const Extension* extension,
3076 const ExtensionPermissionSet* permissions, 3204 const ExtensionPermissionSet* permissions,
3077 Reason reason) 3205 Reason reason)
3078 : reason(reason), 3206 : reason(reason),
3079 extension(extension), 3207 extension(extension),
3080 permissions(permissions) {} 3208 permissions(permissions) {}
OLDNEW
« no previous file with comments | « chrome/common/extensions/extension.h ('k') | chrome/common/extensions/extension_constants.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698