Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 237 | 237 |
| 238 Extension::TtsVoice::TtsVoice() {} | 238 Extension::TtsVoice::TtsVoice() {} |
| 239 Extension::TtsVoice::~TtsVoice() {} | 239 Extension::TtsVoice::~TtsVoice() {} |
| 240 | 240 |
| 241 Extension::OAuth2Info::OAuth2Info() {} | 241 Extension::OAuth2Info::OAuth2Info() {} |
| 242 Extension::OAuth2Info::~OAuth2Info() {} | 242 Extension::OAuth2Info::~OAuth2Info() {} |
| 243 | 243 |
| 244 Extension::ExtensionKeybinding::ExtensionKeybinding() {} | 244 Extension::ExtensionKeybinding::ExtensionKeybinding() {} |
| 245 Extension::ExtensionKeybinding::~ExtensionKeybinding() {} | 245 Extension::ExtensionKeybinding::~ExtensionKeybinding() {} |
| 246 | 246 |
| 247 bool Extension::ExtensionKeybinding::Parse(DictionaryValue* command, | 247 ui::Accelerator Extension::ExtensionKeybinding::ParseImpl( |
| 248 const std::string& command_name, | 248 const std::string& shortcut, |
| 249 int index, | 249 const std::string& platform_key, |
| 250 string16* error) { | 250 int index, |
| 251 DCHECK(!command_name.empty()); | 251 string16* error) { |
| 252 std::string key_binding; | 252 std::string shortcut_normalized = StringToLowerASCII(shortcut); |
|
Aaron Boodman
2012/03/26 21:44:57
Do we even need to do this part? I kinda prefer we
Finnur
2012/03/29 14:57:27
Need? No.
I changed it everywhere to allow only
Aaron Boodman
2012/03/29 20:57:28
OK, let's try it out this way for awhile and see h
| |
| 253 if (!command->GetString(keys::kKey, &key_binding) || | |
| 254 key_binding.empty()) { | |
| 255 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 256 errors::kInvalidKeyBinding, | |
| 257 base::IntToString(index), | |
| 258 "Missing"); | |
| 259 return false; | |
| 260 } | |
| 261 | |
| 262 std::string original_keybinding = key_binding; | |
| 263 // Normalize '-' to '+'. | |
| 264 ReplaceSubstringsAfterOffset(&key_binding, 0, "-", "+"); | |
| 265 // Remove all spaces. | |
| 266 ReplaceSubstringsAfterOffset(&key_binding, 0, " ", ""); | |
| 267 // And finally, lower-case it. | |
| 268 key_binding = StringToLowerASCII(key_binding); | |
| 269 | 253 |
| 270 std::vector<std::string> tokens; | 254 std::vector<std::string> tokens; |
| 271 base::SplitString(key_binding, '+', &tokens); | 255 base::SplitString(shortcut_normalized, '+', &tokens); |
| 272 if (tokens.size() < 2 || tokens.size() > 3) { | 256 if (tokens.size() < 2 || tokens.size() > 3) { |
| 273 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 257 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 274 errors::kInvalidKeyBinding, | 258 errors::kInvalidKeyBinding, |
| 275 base::IntToString(index), | 259 base::IntToString(index), |
| 276 original_keybinding); | 260 platform_key, |
| 277 return false; | 261 shortcut); |
| 262 return ui::Accelerator(); | |
| 278 } | 263 } |
| 279 | 264 |
| 280 // Now, parse it into an accelerator. | 265 // Now, parse it into an accelerator. |
| 281 bool ctrl = false; | 266 bool ctrl = false; |
| 282 bool alt = false; | 267 bool alt = false; |
| 283 bool shift = false; | 268 bool shift = false; |
| 284 ui::KeyboardCode key = ui::VKEY_UNKNOWN; | 269 ui::KeyboardCode key = ui::VKEY_UNKNOWN; |
| 285 for (size_t i = 0; i < tokens.size(); i++) { | 270 for (size_t i = 0; i < tokens.size(); i++) { |
| 286 if (tokens[i] == "ctrl") { | 271 if (tokens[i] == "ctrl") { |
| 287 ctrl = true; | 272 ctrl = true; |
| 288 } else if (tokens[i] == "alt") { | 273 } else if (tokens[i] == "alt") { |
| 289 alt = true; | 274 alt = true; |
| 290 } else if (tokens[i] == "shift") { | 275 } else if (tokens[i] == "shift") { |
| 291 shift = true; | 276 shift = true; |
| 277 } else if (tokens[i] == "command" && platform_key == "mac") { | |
| 278 // TODO(finnur): Implement for Mac. | |
| 279 } else if (tokens[i] == "option" && platform_key == "mac") { | |
| 280 // TODO(finnur): Implement for Mac. | |
| 292 } else if (tokens[i].size() == 1 && | 281 } else if (tokens[i].size() == 1 && |
| 293 tokens[i][0] >= 'a' && tokens[i][0] <= 'z') { | 282 tokens[i][0] >= 'a' && tokens[i][0] <= 'z') { |
| 294 if (key != ui::VKEY_UNKNOWN) { | 283 if (key != ui::VKEY_UNKNOWN) { |
| 295 // Multiple key assignments. | 284 // Multiple key assignments. |
| 296 key = ui::VKEY_UNKNOWN; | 285 key = ui::VKEY_UNKNOWN; |
| 297 break; | 286 break; |
| 298 } | 287 } |
| 299 | 288 |
| 300 key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'a')); | 289 key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'a')); |
| 301 } else { | 290 } else { |
| 302 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 291 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 303 errors::kInvalidKeyBinding, | 292 errors::kInvalidKeyBinding, |
| 304 base::IntToString(index), | 293 base::IntToString(index), |
| 305 original_keybinding); | 294 platform_key, |
| 306 return false; | 295 shortcut); |
| 296 return ui::Accelerator(); | |
| 307 } | 297 } |
| 308 } | 298 } |
| 309 | 299 |
| 310 // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not | 300 // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not |
| 311 // Ctrl+Alt+foo. For a more detailed reason why we don't support Ctrl+Alt+foo: | 301 // Ctrl+Alt+foo. For a more detailed reason why we don't support Ctrl+Alt+foo: |
|
Aaron Boodman
2012/03/26 21:44:57
What about ctrl+alt+shift+foo ?
Finnur
2012/03/29 14:57:27
That's just a variation of Ctrl+Alt+something, so
Aaron Boodman
2012/03/29 20:57:28
Bummer. OK>
| |
| 312 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx. | 302 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx. |
| 313 if (key == ui::VKEY_UNKNOWN || (ctrl && alt)) { | 303 if (key == ui::VKEY_UNKNOWN || (ctrl && alt)) { |
| 314 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 304 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 315 errors::kInvalidKeyBinding, | 305 errors::kInvalidKeyBinding, |
| 316 base::IntToString(index), | 306 base::IntToString(index), |
| 317 original_keybinding); | 307 platform_key, |
| 318 return false; | 308 shortcut); |
| 309 return ui::Accelerator(); | |
| 319 } | 310 } |
| 320 | 311 |
| 321 accelerator_ = ui::Accelerator(key, shift, ctrl, alt); | 312 return ui::Accelerator(key, shift, ctrl, alt); |
| 313 } | |
| 322 | 314 |
| 323 if (command_name != | 315 bool Extension::ExtensionKeybinding::Parse(DictionaryValue* command, |
| 324 extension_manifest_values::kPageActionKeybindingEvent && | 316 const std::string& command_name, |
| 325 command_name != | 317 int index, |
| 326 extension_manifest_values::kBrowserActionKeybindingEvent) { | 318 string16* error) { |
| 327 if (!command->GetString(keys::kDescription, &description_) || | 319 DCHECK(!command_name.empty()); |
| 328 description_.empty()) { | 320 |
| 321 // We'll build up a map of platform-to-shortcut suggestions. | |
| 322 std::map<const std::string, std::string> suggestions; | |
| 323 | |
| 324 // First try to parse the |commands| section as a dictionary. | |
|
Aaron Boodman
2012/03/26 21:44:57
s/commands/suggested_key/ ?
| |
| 325 DictionaryValue* suggested_key_dict; | |
| 326 if (command->GetDictionary(keys::kSuggestedKey, &suggested_key_dict)) { | |
| 327 DictionaryValue::key_iterator iter = suggested_key_dict->begin_keys(); | |
| 328 for ( ; iter != suggested_key_dict->end_keys(); ++iter) { | |
| 329 // For each item in the dictionary, extract the platforms specified. | |
| 330 std::string suggested_key_string; | |
| 331 if (suggested_key_dict->GetString(*iter, &suggested_key_string) && | |
| 332 !suggested_key_string.empty()) { | |
| 333 // Found a platform, add it to the suggestions list. | |
| 334 suggestions[StringToLowerASCII(*iter)] = suggested_key_string; | |
|
Aaron Boodman
2012/03/26 21:44:57
Again, I would just require the case to be correct
Aaron Boodman
2012/03/26 21:44:57
Do we handle the case where the platform is typo'd
Finnur
2012/03/29 14:57:27
We did not. But we do now.
On 2012/03/26 21:44:57
| |
| 335 } else { | |
| 336 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 337 errors::kInvalidKeyBinding, | |
| 338 base::IntToString(index), | |
| 339 keys::kSuggestedKey, | |
| 340 "Missing"); | |
| 341 return false; | |
| 342 } | |
| 343 } | |
| 344 } else { | |
| 345 // No dictionary was found, fall back to using just a string, so developers | |
| 346 // don't have to specify a dictionary if they just want to use one default | |
| 347 // for all platforms. | |
| 348 std::string suggested_key_string; | |
| 349 if (command->GetString(keys::kSuggestedKey, &suggested_key_string) && | |
| 350 !suggested_key_string.empty()) { | |
| 351 // If only a signle string is provided, it must be default for all. | |
| 352 suggestions["default"] = suggested_key_string; | |
| 353 } else { | |
| 329 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 354 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 330 errors::kInvalidKeyBindingDescription, | 355 errors::kInvalidKeyBinding, |
| 331 base::IntToString(index)); | 356 base::IntToString(index), |
| 332 return false; | 357 keys::kSuggestedKey, |
| 358 "Missing"); | |
| 359 return false; | |
| 333 } | 360 } |
| 334 } | 361 } |
| 335 | 362 |
| 336 command_name_ = command_name; | 363 std::string platform = |
| 364 #if defined(OS_WIN) | |
| 365 values::kKeybindingPlatformWin; | |
| 366 #elif defined(OS_MACOSX) | |
| 367 values::kKeybindingPlatformMac; | |
| 368 #elif defined(OS_CHROMEOS) | |
| 369 values::kKeybindingPlatformChromeOs; | |
| 370 #elif defined(OS_LINUX) | |
| 371 values::kKeybindingPlatformLinux; | |
| 372 #else | |
| 373 ""; | |
| 374 #endif | |
| 375 | |
| 376 std::string key = platform; | |
| 377 if (suggestions.find(key) == suggestions.end()) | |
| 378 key = "default"; | |
| 379 if (suggestions.find(key) == suggestions.end()) { | |
| 380 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 381 errors::kInvalidKeyBindingMissingPlatform, | |
| 382 base::IntToString(index), | |
| 383 keys::kSuggestedKey, | |
| 384 platform); | |
| 385 return false; // No platform specified and no fallback. Bail. | |
| 386 } | |
| 387 | |
| 388 // For developer convenience, we parse all the suggestions (and complain about | |
| 389 // errors for platforms other than the current one) but use only what we need. | |
| 390 std::map<const std::string, std::string>::const_iterator iter = | |
| 391 suggestions.begin(); | |
| 392 for ( ; iter != suggestions.end(); ++iter) { | |
| 393 // Note that we pass iter->first to pretend we are on a platform we're not | |
| 394 // on. | |
| 395 ui::Accelerator accelerator = | |
| 396 ParseImpl(iter->second, iter->first, index, error); | |
| 397 if (accelerator.key_code() == ui::VKEY_UNKNOWN) { | |
| 398 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 399 errors::kInvalidKeyBinding, | |
| 400 base::IntToString(index), | |
| 401 iter->first, | |
| 402 iter->second); | |
| 403 return false; | |
| 404 } | |
| 405 | |
| 406 if (iter->first == key) { | |
| 407 // This platform is our platform, so grab this key. | |
| 408 accelerator_ = accelerator; | |
| 409 command_name_ = command_name; | |
| 410 | |
| 411 if (command_name != | |
| 412 extension_manifest_values::kPageActionKeybindingEvent && | |
| 413 command_name != | |
| 414 extension_manifest_values::kBrowserActionKeybindingEvent) { | |
| 415 if (!command->GetString(keys::kDescription, &description_) || | |
| 416 description_.empty()) { | |
| 417 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
| 418 errors::kInvalidKeyBindingDescription, | |
| 419 base::IntToString(index)); | |
| 420 return false; | |
| 421 } | |
| 422 } | |
| 423 } | |
| 424 } | |
| 337 return true; | 425 return true; |
| 338 } | 426 } |
| 339 | 427 |
| 340 // | 428 // |
| 341 // Extension | 429 // Extension |
| 342 // | 430 // |
| 343 | 431 |
| 344 // static | 432 // static |
| 345 scoped_refptr<Extension> Extension::Create(const FilePath& path, | 433 scoped_refptr<Extension> Extension::Create(const FilePath& path, |
| 346 Location location, | 434 Location location, |
| (...skipping 1165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1512 ++command_index; | 1600 ++command_index; |
| 1513 | 1601 |
| 1514 DictionaryValue* command = NULL; | 1602 DictionaryValue* command = NULL; |
| 1515 if (!commands->GetDictionary(*iter, &command)) { | 1603 if (!commands->GetDictionary(*iter, &command)) { |
| 1516 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1604 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 1517 errors::kInvalidKeyBindingDictionary, | 1605 errors::kInvalidKeyBindingDictionary, |
| 1518 base::IntToString(command_index)); | 1606 base::IntToString(command_index)); |
| 1519 return false; | 1607 return false; |
| 1520 } | 1608 } |
| 1521 | 1609 |
| 1522 ExtensionKeybinding binding; | 1610 scoped_ptr<Extension::ExtensionKeybinding> binding( |
| 1523 if (!binding.Parse(command, *iter, command_index, error)) | 1611 new ExtensionKeybinding()); |
| 1612 if (!binding->Parse(command, *iter, command_index, error)) | |
| 1524 return false; // |error| already set. | 1613 return false; // |error| already set. |
| 1525 | 1614 |
| 1526 commands_.push_back(binding); | 1615 std::string command_name = binding->command_name(); |
| 1616 if (command_name == values::kPageActionKeybindingEvent) | |
| 1617 page_action_command_.reset(binding.release()); | |
| 1618 else if (command_name == values::kBrowserActionKeybindingEvent) | |
| 1619 browser_action_command_.reset(binding.release()); | |
| 1620 else | |
|
Aaron Boodman
2012/03/26 21:44:57
You should skip keys beginning with "_" if they ar
| |
| 1621 named_commands_[command_name] = *binding.release(); | |
| 1527 } | 1622 } |
| 1528 } | 1623 } |
| 1529 return true; | 1624 return true; |
| 1530 } | 1625 } |
| 1531 | 1626 |
| 1532 bool Extension::LoadPlugins(string16* error) { | 1627 bool Extension::LoadPlugins(string16* error) { |
| 1533 if (!manifest_->HasKey(keys::kPlugins)) | 1628 if (!manifest_->HasKey(keys::kPlugins)) |
| 1534 return true; | 1629 return true; |
| 1535 ListValue* list_value = NULL; | 1630 ListValue* list_value = NULL; |
| 1536 if (!manifest_->GetList(keys::kPlugins, &list_value)) { | 1631 if (!manifest_->GetList(keys::kPlugins, &list_value)) { |
| (...skipping 1996 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3533 already_disabled(false), | 3628 already_disabled(false), |
| 3534 extension(extension) {} | 3629 extension(extension) {} |
| 3535 | 3630 |
| 3536 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( | 3631 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( |
| 3537 const Extension* extension, | 3632 const Extension* extension, |
| 3538 const ExtensionPermissionSet* permissions, | 3633 const ExtensionPermissionSet* permissions, |
| 3539 Reason reason) | 3634 Reason reason) |
| 3540 : reason(reason), | 3635 : reason(reason), |
| 3541 extension(extension), | 3636 extension(extension), |
| 3542 permissions(permissions) {} | 3637 permissions(permissions) {} |
| OLD | NEW |