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 if (platform_key != values::kKeybindingPlatformWin && |
253 if (!command->GetString(keys::kKey, &key_binding) || | 253 platform_key != values::kKeybindingPlatformMac && |
254 key_binding.empty()) { | 254 platform_key != values::kKeybindingPlatformChromeOs && |
| 255 platform_key != values::kKeybindingPlatformLinux && |
| 256 platform_key != values::kKeybindingPlatformDefault) { |
255 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 257 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
256 errors::kInvalidKeyBinding, | 258 errors::kInvalidKeyBindingUnknownPlatform, |
257 base::IntToString(index), | 259 base::IntToString(index), |
258 "Missing"); | 260 platform_key); |
259 return false; | 261 return ui::Accelerator(); |
260 } | 262 } |
261 | 263 |
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 | |
270 std::vector<std::string> tokens; | 264 std::vector<std::string> tokens; |
271 base::SplitString(key_binding, '+', &tokens); | 265 base::SplitString(shortcut, '+', &tokens); |
272 if (tokens.size() < 2 || tokens.size() > 3) { | 266 if (tokens.size() < 2 || tokens.size() > 3) { |
273 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 267 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
274 errors::kInvalidKeyBinding, | 268 errors::kInvalidKeyBinding, |
275 base::IntToString(index), | 269 base::IntToString(index), |
276 original_keybinding); | 270 platform_key, |
277 return false; | 271 shortcut); |
| 272 return ui::Accelerator(); |
278 } | 273 } |
279 | 274 |
280 // Now, parse it into an accelerator. | 275 // Now, parse it into an accelerator. |
281 bool ctrl = false; | 276 bool ctrl = false; |
282 bool alt = false; | 277 bool alt = false; |
283 bool shift = false; | 278 bool shift = false; |
284 ui::KeyboardCode key = ui::VKEY_UNKNOWN; | 279 ui::KeyboardCode key = ui::VKEY_UNKNOWN; |
285 for (size_t i = 0; i < tokens.size(); i++) { | 280 for (size_t i = 0; i < tokens.size(); i++) { |
286 if (tokens[i] == "ctrl") { | 281 if (tokens[i] == "Ctrl") { |
287 ctrl = true; | 282 ctrl = true; |
288 } else if (tokens[i] == "alt") { | 283 } else if (tokens[i] == "Alt") { |
289 alt = true; | 284 alt = true; |
290 } else if (tokens[i] == "shift") { | 285 } else if (tokens[i] == "Shift") { |
291 shift = true; | 286 shift = true; |
| 287 } else if (tokens[i] == "Command" && platform_key == "mac") { |
| 288 // TODO(finnur): Implement for Mac. |
| 289 } else if (tokens[i] == "Option" && platform_key == "mac") { |
| 290 // TODO(finnur): Implement for Mac. |
292 } else if (tokens[i].size() == 1 && | 291 } else if (tokens[i].size() == 1 && |
293 tokens[i][0] >= 'a' && tokens[i][0] <= 'z') { | 292 tokens[i][0] >= 'A' && tokens[i][0] <= 'Z') { |
294 if (key != ui::VKEY_UNKNOWN) { | 293 if (key != ui::VKEY_UNKNOWN) { |
295 // Multiple key assignments. | 294 // Multiple key assignments. |
296 key = ui::VKEY_UNKNOWN; | 295 key = ui::VKEY_UNKNOWN; |
297 break; | 296 break; |
298 } | 297 } |
299 | 298 |
300 key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'a')); | 299 key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'A')); |
301 } else { | 300 } else { |
302 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 301 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
303 errors::kInvalidKeyBinding, | 302 errors::kInvalidKeyBinding, |
304 base::IntToString(index), | 303 base::IntToString(index), |
305 original_keybinding); | 304 platform_key, |
306 return false; | 305 shortcut); |
| 306 return ui::Accelerator(); |
307 } | 307 } |
308 } | 308 } |
309 | 309 |
310 // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not | 310 // 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: | 311 // Ctrl+Alt+foo. For a more detailed reason why we don't support Ctrl+Alt+foo: |
312 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx. | 312 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx. |
313 if (key == ui::VKEY_UNKNOWN || (ctrl && alt)) { | 313 if (key == ui::VKEY_UNKNOWN || (ctrl && alt)) { |
314 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 314 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
315 errors::kInvalidKeyBinding, | 315 errors::kInvalidKeyBinding, |
316 base::IntToString(index), | 316 base::IntToString(index), |
317 original_keybinding); | 317 platform_key, |
318 return false; | 318 shortcut); |
| 319 return ui::Accelerator(); |
319 } | 320 } |
320 | 321 |
321 accelerator_ = ui::Accelerator(key, shift, ctrl, alt); | 322 return ui::Accelerator(key, shift, ctrl, alt); |
| 323 } |
322 | 324 |
323 if (command_name != | 325 bool Extension::ExtensionKeybinding::Parse(DictionaryValue* command, |
324 extension_manifest_values::kPageActionKeybindingEvent && | 326 const std::string& command_name, |
325 command_name != | 327 int index, |
326 extension_manifest_values::kBrowserActionKeybindingEvent) { | 328 string16* error) { |
327 if (!command->GetString(keys::kDescription, &description_) || | 329 DCHECK(!command_name.empty()); |
328 description_.empty()) { | 330 |
| 331 // We'll build up a map of platform-to-shortcut suggestions. |
| 332 std::map<const std::string, std::string> suggestions; |
| 333 |
| 334 // First try to parse the |suggested_key| as a dictionary. |
| 335 DictionaryValue* suggested_key_dict; |
| 336 if (command->GetDictionary(keys::kSuggestedKey, &suggested_key_dict)) { |
| 337 DictionaryValue::key_iterator iter = suggested_key_dict->begin_keys(); |
| 338 for ( ; iter != suggested_key_dict->end_keys(); ++iter) { |
| 339 // For each item in the dictionary, extract the platforms specified. |
| 340 std::string suggested_key_string; |
| 341 if (suggested_key_dict->GetString(*iter, &suggested_key_string) && |
| 342 !suggested_key_string.empty()) { |
| 343 // Found a platform, add it to the suggestions list. |
| 344 suggestions[*iter] = suggested_key_string; |
| 345 } else { |
| 346 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 347 errors::kInvalidKeyBinding, |
| 348 base::IntToString(index), |
| 349 keys::kSuggestedKey, |
| 350 "Missing"); |
| 351 return false; |
| 352 } |
| 353 } |
| 354 } else { |
| 355 // No dictionary was found, fall back to using just a string, so developers |
| 356 // don't have to specify a dictionary if they just want to use one default |
| 357 // for all platforms. |
| 358 std::string suggested_key_string; |
| 359 if (command->GetString(keys::kSuggestedKey, &suggested_key_string) && |
| 360 !suggested_key_string.empty()) { |
| 361 // If only a signle string is provided, it must be default for all. |
| 362 suggestions["default"] = suggested_key_string; |
| 363 } else { |
329 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 364 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
330 errors::kInvalidKeyBindingDescription, | 365 errors::kInvalidKeyBinding, |
331 base::IntToString(index)); | 366 base::IntToString(index), |
332 return false; | 367 keys::kSuggestedKey, |
| 368 "Missing"); |
| 369 return false; |
333 } | 370 } |
334 } | 371 } |
335 | 372 |
336 command_name_ = command_name; | 373 std::string platform = |
| 374 #if defined(OS_WIN) |
| 375 values::kKeybindingPlatformWin; |
| 376 #elif defined(OS_MACOSX) |
| 377 values::kKeybindingPlatformMac; |
| 378 #elif defined(OS_CHROMEOS) |
| 379 values::kKeybindingPlatformChromeOs; |
| 380 #elif defined(OS_LINUX) |
| 381 values::kKeybindingPlatformLinux; |
| 382 #else |
| 383 ""; |
| 384 #endif |
| 385 |
| 386 std::string key = platform; |
| 387 if (suggestions.find(key) == suggestions.end()) |
| 388 key = values::kKeybindingPlatformDefault; |
| 389 if (suggestions.find(key) == suggestions.end()) { |
| 390 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 391 errors::kInvalidKeyBindingMissingPlatform, |
| 392 base::IntToString(index), |
| 393 keys::kSuggestedKey, |
| 394 platform); |
| 395 return false; // No platform specified and no fallback. Bail. |
| 396 } |
| 397 |
| 398 // For developer convenience, we parse all the suggestions (and complain about |
| 399 // errors for platforms other than the current one) but use only what we need. |
| 400 std::map<const std::string, std::string>::const_iterator iter = |
| 401 suggestions.begin(); |
| 402 for ( ; iter != suggestions.end(); ++iter) { |
| 403 // Note that we pass iter->first to pretend we are on a platform we're not |
| 404 // on. |
| 405 ui::Accelerator accelerator = |
| 406 ParseImpl(iter->second, iter->first, index, error); |
| 407 if (accelerator.key_code() == ui::VKEY_UNKNOWN) { |
| 408 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 409 errors::kInvalidKeyBinding, |
| 410 base::IntToString(index), |
| 411 iter->first, |
| 412 iter->second); |
| 413 return false; |
| 414 } |
| 415 |
| 416 if (iter->first == key) { |
| 417 // This platform is our platform, so grab this key. |
| 418 accelerator_ = accelerator; |
| 419 command_name_ = command_name; |
| 420 |
| 421 if (command_name != |
| 422 extension_manifest_values::kPageActionKeybindingEvent && |
| 423 command_name != |
| 424 extension_manifest_values::kBrowserActionKeybindingEvent) { |
| 425 if (!command->GetString(keys::kDescription, &description_) || |
| 426 description_.empty()) { |
| 427 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 428 errors::kInvalidKeyBindingDescription, |
| 429 base::IntToString(index)); |
| 430 return false; |
| 431 } |
| 432 } |
| 433 } |
| 434 } |
337 return true; | 435 return true; |
338 } | 436 } |
339 | 437 |
340 // | 438 // |
341 // Extension | 439 // Extension |
342 // | 440 // |
343 | 441 |
344 // static | 442 // static |
345 scoped_refptr<Extension> Extension::Create(const FilePath& path, | 443 scoped_refptr<Extension> Extension::Create(const FilePath& path, |
346 Location location, | 444 Location location, |
(...skipping 1172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1519 ++command_index; | 1617 ++command_index; |
1520 | 1618 |
1521 DictionaryValue* command = NULL; | 1619 DictionaryValue* command = NULL; |
1522 if (!commands->GetDictionary(*iter, &command)) { | 1620 if (!commands->GetDictionary(*iter, &command)) { |
1523 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1621 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
1524 errors::kInvalidKeyBindingDictionary, | 1622 errors::kInvalidKeyBindingDictionary, |
1525 base::IntToString(command_index)); | 1623 base::IntToString(command_index)); |
1526 return false; | 1624 return false; |
1527 } | 1625 } |
1528 | 1626 |
1529 ExtensionKeybinding binding; | 1627 scoped_ptr<Extension::ExtensionKeybinding> binding( |
1530 if (!binding.Parse(command, *iter, command_index, error)) | 1628 new ExtensionKeybinding()); |
| 1629 if (!binding->Parse(command, *iter, command_index, error)) |
1531 return false; // |error| already set. | 1630 return false; // |error| already set. |
1532 | 1631 |
1533 commands_.push_back(binding); | 1632 std::string command_name = binding->command_name(); |
| 1633 if (command_name == values::kPageActionKeybindingEvent) { |
| 1634 page_action_command_.reset(binding.release()); |
| 1635 } else if (command_name == values::kBrowserActionKeybindingEvent) { |
| 1636 browser_action_command_.reset(binding.release()); |
| 1637 } else { |
| 1638 if (command_name[0] != '_') // All commands w/underscore are reserved. |
| 1639 named_commands_[command_name] = *binding.release(); |
| 1640 } |
1534 } | 1641 } |
1535 } | 1642 } |
1536 return true; | 1643 return true; |
1537 } | 1644 } |
1538 | 1645 |
1539 bool Extension::LoadPlugins(string16* error) { | 1646 bool Extension::LoadPlugins(string16* error) { |
1540 if (!manifest_->HasKey(keys::kPlugins)) | 1647 if (!manifest_->HasKey(keys::kPlugins)) |
1541 return true; | 1648 return true; |
1542 ListValue* list_value = NULL; | 1649 ListValue* list_value = NULL; |
1543 if (!manifest_->GetList(keys::kPlugins, &list_value)) { | 1650 if (!manifest_->GetList(keys::kPlugins, &list_value)) { |
(...skipping 2018 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3562 already_disabled(false), | 3669 already_disabled(false), |
3563 extension(extension) {} | 3670 extension(extension) {} |
3564 | 3671 |
3565 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( | 3672 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( |
3566 const Extension* extension, | 3673 const Extension* extension, |
3567 const ExtensionPermissionSet* permissions, | 3674 const ExtensionPermissionSet* permissions, |
3568 Reason reason) | 3675 Reason reason) |
3569 : reason(reason), | 3676 : reason(reason), |
3570 extension(extension), | 3677 extension(extension), |
3571 permissions(permissions) {} | 3678 permissions(permissions) {} |
OLD | NEW |