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

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
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"
(...skipping 24 matching lines...) Expand all
35 #include "chrome/common/extensions/file_browser_handler.h" 35 #include "chrome/common/extensions/file_browser_handler.h"
36 #include "chrome/common/extensions/manifest.h" 36 #include "chrome/common/extensions/manifest.h"
37 #include "chrome/common/extensions/user_script.h" 37 #include "chrome/common/extensions/user_script.h"
38 #include "chrome/common/url_constants.h" 38 #include "chrome/common/url_constants.h"
39 #include "googleurl/src/url_util.h" 39 #include "googleurl/src/url_util.h"
40 #include "grit/chromium_strings.h" 40 #include "grit/chromium_strings.h"
41 #include "grit/generated_resources.h" 41 #include "grit/generated_resources.h"
42 #include "grit/theme_resources.h" 42 #include "grit/theme_resources.h"
43 #include "net/base/registry_controlled_domain.h" 43 #include "net/base/registry_controlled_domain.h"
44 #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"
45 #include "ui/base/l10n/l10n_util.h" 46 #include "ui/base/l10n/l10n_util.h"
46 #include "ui/base/resource/resource_bundle.h" 47 #include "ui/base/resource/resource_bundle.h"
47 #include "webkit/glue/image_decoder.h" 48 #include "webkit/glue/image_decoder.h"
48 #include "webkit/glue/web_intent_service_data.h" 49 #include "webkit/glue/web_intent_service_data.h"
49 50
50 namespace keys = extension_manifest_keys; 51 namespace keys = extension_manifest_keys;
51 namespace values = extension_manifest_values; 52 namespace values = extension_manifest_values;
52 namespace errors = extension_manifest_errors; 53 namespace errors = extension_manifest_errors;
53 54
54 using extensions::csp_validator::ContentSecurityPolicyIsLegal; 55 using extensions::csp_validator::ContentSecurityPolicyIsLegal;
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 shortcut_alt(false), 213 shortcut_alt(false),
213 shortcut_ctrl(false), 214 shortcut_ctrl(false),
214 shortcut_shift(false) { 215 shortcut_shift(false) {
215 } 216 }
216 217
217 Extension::InputComponentInfo::~InputComponentInfo() {} 218 Extension::InputComponentInfo::~InputComponentInfo() {}
218 219
219 Extension::TtsVoice::TtsVoice() {} 220 Extension::TtsVoice::TtsVoice() {}
220 Extension::TtsVoice::~TtsVoice() {} 221 Extension::TtsVoice::~TtsVoice() {}
221 222
223 Extension::ExtensionKeybinding::ExtensionKeybinding() {}
224 Extension::ExtensionKeybinding::~ExtensionKeybinding() {}
225
226 bool Extension::ExtensionKeybinding::Parse(DictionaryValue* command,
227 const std::string& event_name,
228 string16* error,
229 int index) {
Matt Perry 2012/02/21 23:13:39 outparams (error) should go last
230 std::string key_binding;
231 if (!command->GetString(keys::kKey, &key_binding)) {
232 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
233 errors::kInvalidKeyBinding,
234 base::IntToString(index),
235 "Missing");
236 return false;
237 }
238
239 std::string original_keybinding = key_binding;
240 // Normalize '-' to '+'.
241 for (size_t pos = key_binding.find('-');
242 pos != std::string::npos;
243 pos = key_binding.find('-')) {
244 key_binding.replace(pos, 1, "+");
245 }
246 // Remove all spaces.
247 for (size_t pos = key_binding.find(' ');
248 pos != std::string::npos;
249 pos = key_binding.find(' ')) {
250 key_binding.replace(pos, 1, "");
251 }
Matt Perry 2012/02/21 23:13:39 base::ReplaceSubstringsAfterOffset(&key_binding, 0
252 // And finally, lower-case it.
253 key_binding = StringToLowerASCII(key_binding);
254
255 // Now, parse it into an accelerator.
256 bool ctrl = false;
257 bool alt = false;
258 bool shift = false;
259 ui::KeyboardCode key = ui::VKEY_UNKNOWN;
260 // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not
261 // Ctrl+Alt+foo. For a more detailed reason why we don't support Ctrl+Alt+foo:
262 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx.
263 size_t position;
Matt Perry 2012/02/21 23:13:39 Should we support Shift+Alt+foo? If so, it might b
Finnur 2012/02/22 23:45:22 Good idea. On 2012/02/21 23:13:39, Matt Perry wro
264 if ((position = key_binding.find("ctrl+")) != std::string::npos) {
265 ctrl = true;
266 key_binding = key_binding.replace(position, 5, "");
267 } else if ((position = key_binding.find("alt+")) != std::string::npos) {
268 alt = true;
269 key_binding = key_binding.replace(position, 4, "");
270 }
271 if ((position = key_binding.find("shift+")) != std::string::npos) {
272 shift = true;
273 key_binding = key_binding.replace(position, 6, "");
274 }
275 // We've stripped everything from the string but the letter.
276 if (key_binding.size() != 1) {
277 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
278 errors::kInvalidKeyBinding,
279 base::IntToString(index),
280 original_keybinding);
281 return false;
282 }
283
284 if (key_binding.compare("a") == 0) key = ui::VKEY_A;
Matt Perry 2012/02/21 23:13:39 Are we guaranteed for VKEY_A through _Z to be cont
285 else if (key_binding.compare("b") == 0) key = ui::VKEY_B;
286 else if (key_binding.compare("c") == 0) key = ui::VKEY_C;
287 else if (key_binding.compare("d") == 0) key = ui::VKEY_D;
288 else if (key_binding.compare("e") == 0) key = ui::VKEY_E;
289 else if (key_binding.compare("f") == 0) key = ui::VKEY_F;
290 else if (key_binding.compare("g") == 0) key = ui::VKEY_G;
291 else if (key_binding.compare("h") == 0) key = ui::VKEY_H;
292 else if (key_binding.compare("i") == 0) key = ui::VKEY_I;
293 else if (key_binding.compare("j") == 0) key = ui::VKEY_J;
294 else if (key_binding.compare("k") == 0) key = ui::VKEY_K;
295 else if (key_binding.compare("l") == 0) key = ui::VKEY_L;
296 else if (key_binding.compare("m") == 0) key = ui::VKEY_M;
297 else if (key_binding.compare("n") == 0) key = ui::VKEY_N;
298 else if (key_binding.compare("o") == 0) key = ui::VKEY_O;
299 else if (key_binding.compare("p") == 0) key = ui::VKEY_P;
300 else if (key_binding.compare("q") == 0) key = ui::VKEY_Q;
301 else if (key_binding.compare("r") == 0) key = ui::VKEY_R;
302 else if (key_binding.compare("s") == 0) key = ui::VKEY_S;
303 else if (key_binding.compare("t") == 0) key = ui::VKEY_T;
304 else if (key_binding.compare("u") == 0) key = ui::VKEY_U;
305 else if (key_binding.compare("v") == 0) key = ui::VKEY_V;
306 else if (key_binding.compare("x") == 0) key = ui::VKEY_X;
307 else if (key_binding.compare("y") == 0) key = ui::VKEY_Y;
308 else if (key_binding.compare("z") == 0) key = ui::VKEY_Z;
309
310 accelerator_ = ui::Accelerator(key, shift, ctrl, alt);
311 if (!command->GetString(keys::kDescription, &description_)) {
312 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
313 errors::kInvalidKeyBindingDescription,
314 base::IntToString(index));
315 return false;
316 }
317
318 event_name_ = event_name;
319 return true;
320 }
321
222 // 322 //
223 // Extension 323 // Extension
224 // 324 //
225 325
226 // static 326 // static
227 scoped_refptr<Extension> Extension::Create(const FilePath& path, 327 scoped_refptr<Extension> Extension::Create(const FilePath& path,
228 Location location, 328 Location location,
229 const DictionaryValue& value, 329 const DictionaryValue& value,
230 int flags, 330 int flags,
231 std::string* utf8_error) { 331 std::string* utf8_error) {
(...skipping 619 matching lines...) Expand 10 before | Expand all | Expand 10 after
851 errors::kInvalidURLPatternError, filter); 951 errors::kInvalidURLPatternError, filter);
852 return NULL; 952 return NULL;
853 } 953 }
854 result->AddPattern(pattern); 954 result->AddPattern(pattern);
855 } 955 }
856 956
857 std::string default_icon; 957 std::string default_icon;
858 // Read the file browser action |default_icon| (optional). 958 // Read the file browser action |default_icon| (optional).
859 if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) { 959 if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) {
860 if (!file_browser_handler->GetString( 960 if (!file_browser_handler->GetString(
861 keys::kPageActionDefaultIcon,&default_icon) || 961 keys::kPageActionDefaultIcon, &default_icon) ||
862 default_icon.empty()) { 962 default_icon.empty()) {
863 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath); 963 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath);
864 return NULL; 964 return NULL;
865 } 965 }
866 result->set_icon_path(default_icon); 966 result->set_icon_path(default_icon);
867 } 967 }
868 968
869 return result.release(); 969 return result.release();
870 } 970 }
871 971
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after
1155 *error = ASCIIToUTF16(errors::kInvalidIntent); 1255 *error = ASCIIToUTF16(errors::kInvalidIntent);
1156 return false; 1256 return false;
1157 } 1257 }
1158 service.action = UTF8ToUTF16(*iter); 1258 service.action = UTF8ToUTF16(*iter);
1159 1259
1160 ListValue* mime_types = NULL; 1260 ListValue* mime_types = NULL;
1161 if (!one_service->HasKey(keys::kIntentType) || 1261 if (!one_service->HasKey(keys::kIntentType) ||
1162 !one_service->GetList(keys::kIntentType, &mime_types) || 1262 !one_service->GetList(keys::kIntentType, &mime_types) ||
1163 mime_types->GetSize() == 0) { 1263 mime_types->GetSize() == 0) {
1164 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 1264 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1165 errors::kInvalidIntentType,*iter); 1265 errors::kInvalidIntentType, *iter);
1166 return false; 1266 return false;
1167 } 1267 }
1168 1268
1169 if (one_service->HasKey(keys::kIntentPath)) { 1269 if (one_service->HasKey(keys::kIntentPath)) {
1170 if (!one_service->GetString(keys::kIntentPath, &value)) { 1270 if (!one_service->GetString(keys::kIntentPath, &value)) {
1171 *error = ASCIIToUTF16(errors::kInvalidIntentPath); 1271 *error = ASCIIToUTF16(errors::kInvalidIntentPath);
1172 return false; 1272 return false;
1173 } 1273 }
1174 if (is_hosted_app()) { 1274 if (is_hosted_app()) {
1175 // Hosted apps require an absolute URL for intents. 1275 // Hosted apps require an absolute URL for intents.
1176 GURL service_url(value); 1276 GURL service_url(value);
1177 if (!service_url.is_valid() || 1277 if (!service_url.is_valid() ||
1178 !(web_extent().MatchesURL(service_url))) { 1278 !(web_extent().MatchesURL(service_url))) {
1179 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( 1279 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1180 errors::kInvalidIntentPageInHostedApp,*iter); 1280 errors::kInvalidIntentPageInHostedApp, *iter);
1181 return false; 1281 return false;
1182 } 1282 }
1183 service.service_url = service_url; 1283 service.service_url = service_url;
1184 } else { 1284 } else {
1185 // We do not allow absolute intent URLs in non-hosted apps. 1285 // We do not allow absolute intent URLs in non-hosted apps.
1186 if (GURL(value).is_valid()) { 1286 if (GURL(value).is_valid()) {
1187 *error =ExtensionErrorUtils::FormatErrorMessageUTF16( 1287 *error =ExtensionErrorUtils::FormatErrorMessageUTF16(
1188 errors::kCannotAccessPage,value.c_str()); 1288 errors::kCannotAccessPage, value.c_str());
1189 return false; 1289 return false;
1190 } 1290 }
1191 service.service_url = GetResourceURL(value); 1291 service.service_url = GetResourceURL(value);
1192 } 1292 }
1193 } 1293 }
1194 1294
1195 if (one_service->HasKey(keys::kIntentTitle) && 1295 if (one_service->HasKey(keys::kIntentTitle) &&
1196 !one_service->GetString(keys::kIntentTitle, &service.title)) { 1296 !one_service->GetString(keys::kIntentTitle, &service.title)) {
1197 *error = ASCIIToUTF16(errors::kInvalidIntentTitle); 1297 *error = ASCIIToUTF16(errors::kInvalidIntentTitle);
1198 return false; 1298 return false;
(...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after
1712 minimum_version_string); 1812 minimum_version_string);
1713 return false; 1813 return false;
1714 } 1814 }
1715 } 1815 }
1716 1816
1717 // Initialize converted_from_user_script (if present) 1817 // Initialize converted_from_user_script (if present)
1718 if (manifest->HasKey(keys::kConvertedFromUserScript)) 1818 if (manifest->HasKey(keys::kConvertedFromUserScript))
1719 manifest->GetBoolean(keys::kConvertedFromUserScript, 1819 manifest->GetBoolean(keys::kConvertedFromUserScript,
1720 &converted_from_user_script_); 1820 &converted_from_user_script_);
1721 1821
1822 // Initialize commands (if present).
1823 if (manifest->HasKey(keys::kCommands)) {
1824 DictionaryValue* commands = NULL;
1825 if (!manifest->GetDictionary(keys::kCommands, &commands)) {
1826 *error = ASCIIToUTF16(errors::kInvalidCommandsKey);
1827 return false;
1828 }
1829
1830 int command_index = 0;
1831 for (DictionaryValue::key_iterator iter = commands->begin_keys();
1832 iter != commands->end_keys(); ++iter) {
1833 ++command_index;
1834
1835 DictionaryValue* command = NULL;
1836 if (!commands->GetDictionary(*iter, &command)) {
1837 *error = ExtensionErrorUtils::FormatErrorMessageUTF16(
1838 errors::kInvalidKeyBindingDictionary,
1839 base::IntToString(command_index));
1840 return false;
1841 }
1842
1843 ExtensionKeybinding binding;
1844 if (!binding.Parse(command, *iter, error, command_index))
1845 return false; // |error| already set.
1846
1847 commands_.push_back(binding);
1848 }
1849 }
1850
1722 // Initialize icons (if present). 1851 // Initialize icons (if present).
1723 if (manifest->HasKey(keys::kIcons)) { 1852 if (manifest->HasKey(keys::kIcons)) {
1724 DictionaryValue* icons_value = NULL; 1853 DictionaryValue* icons_value = NULL;
1725 if (!manifest->GetDictionary(keys::kIcons, &icons_value)) { 1854 if (!manifest->GetDictionary(keys::kIcons, &icons_value)) {
1726 *error = ASCIIToUTF16(errors::kInvalidIcons); 1855 *error = ASCIIToUTF16(errors::kInvalidIcons);
1727 return false; 1856 return false;
1728 } 1857 }
1729 1858
1730 for (size_t i = 0; i < arraysize(kIconSizes); ++i) { 1859 for (size_t i = 0; i < arraysize(kIconSizes); ++i) {
1731 std::string key = base::IntToString(kIconSizes[i]); 1860 std::string key = base::IntToString(kIconSizes[i]);
(...skipping 1143 matching lines...) Expand 10 before | Expand all | Expand 10 after
2875 3004
2876 if (permission->id() == ExtensionAPIPermission::kExperimental) { 3005 if (permission->id() == ExtensionAPIPermission::kExperimental) {
2877 if (!CanSpecifyExperimentalPermission()) { 3006 if (!CanSpecifyExperimentalPermission()) {
2878 *error = ASCIIToUTF16(errors::kExperimentalFlagRequired); 3007 *error = ASCIIToUTF16(errors::kExperimentalFlagRequired);
2879 return false; 3008 return false;
2880 } 3009 }
2881 } 3010 }
2882 3011
2883 bool supports_type = false; 3012 bool supports_type = false;
2884 switch (GetType()) { 3013 switch (GetType()) {
2885 case TYPE_USER_SCRIPT: // Pass through. 3014 case TYPE_USER_SCRIPT: // Pass through.
2886 case TYPE_EXTENSION: 3015 case TYPE_EXTENSION:
2887 supports_type = permission->supports_extensions(); 3016 supports_type = permission->supports_extensions();
2888 break; 3017 break;
2889 case TYPE_HOSTED_APP: 3018 case TYPE_HOSTED_APP:
2890 supports_type = permission->supports_hosted_apps(); 3019 supports_type = permission->supports_hosted_apps();
2891 break; 3020 break;
2892 case TYPE_PACKAGED_APP: 3021 case TYPE_PACKAGED_APP:
2893 supports_type = permission->supports_packaged_apps(); 3022 supports_type = permission->supports_packaged_apps();
2894 break; 3023 break;
2895 case TYPE_PLATFORM_APP: 3024 case TYPE_PLATFORM_APP:
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
3031 } 3160 }
3032 } 3161 }
3033 3162
3034 bool Extension::IsSyncable() const { 3163 bool Extension::IsSyncable() const {
3035 // TODO(akalin): Figure out if we need to allow some other types. 3164 // TODO(akalin): Figure out if we need to allow some other types.
3036 3165
3037 // We want to sync any extensions that are shown in the luancher because 3166 // We want to sync any extensions that are shown in the luancher because
3038 // their positions should sync. 3167 // their positions should sync.
3039 return location_ == Extension::INTERNAL || 3168 return location_ == Extension::INTERNAL ||
3040 ShouldDisplayInLauncher(); 3169 ShouldDisplayInLauncher();
3041
3042 } 3170 }
3043 3171
3044 bool Extension::ShouldDisplayInLauncher() const { 3172 bool Extension::ShouldDisplayInLauncher() const {
3045 // All apps should be displayed on the NTP except for the Cloud Print App. 3173 // All apps should be displayed on the NTP except for the Cloud Print App.
3046 return is_app() && id() != extension_misc::kCloudPrintAppId; 3174 return is_app() && id() != extension_misc::kCloudPrintAppId;
3047 } 3175 }
3048 3176
3049 ExtensionInfo::ExtensionInfo(const DictionaryValue* manifest, 3177 ExtensionInfo::ExtensionInfo(const DictionaryValue* manifest,
3050 const std::string& id, 3178 const std::string& id,
3051 const FilePath& path, 3179 const FilePath& path,
(...skipping 29 matching lines...) Expand all
3081 already_disabled(false), 3209 already_disabled(false),
3082 extension(extension) {} 3210 extension(extension) {}
3083 3211
3084 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( 3212 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo(
3085 const Extension* extension, 3213 const Extension* extension,
3086 const ExtensionPermissionSet* permissions, 3214 const ExtensionPermissionSet* permissions,
3087 Reason reason) 3215 Reason reason)
3088 : reason(reason), 3216 : reason(reason),
3089 extension(extension), 3217 extension(extension),
3090 permissions(permissions) {} 3218 permissions(permissions) {}
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698