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 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 } | 234 } |
235 | 235 |
236 Extension::InputComponentInfo::~InputComponentInfo() {} | 236 Extension::InputComponentInfo::~InputComponentInfo() {} |
237 | 237 |
238 Extension::TtsVoice::TtsVoice() {} | 238 Extension::TtsVoice::TtsVoice() {} |
239 Extension::TtsVoice::~TtsVoice() {} | 239 Extension::TtsVoice::~TtsVoice() {} |
240 | 240 |
241 Extension::ExtensionKeybinding::ExtensionKeybinding() {} | 241 Extension::ExtensionKeybinding::ExtensionKeybinding() {} |
242 Extension::ExtensionKeybinding::~ExtensionKeybinding() {} | 242 Extension::ExtensionKeybinding::~ExtensionKeybinding() {} |
243 | 243 |
244 bool Extension::ExtensionKeybinding::Parse(DictionaryValue* command, | 244 ui::Accelerator Extension::ExtensionKeybinding::ParseImpl( |
245 const std::string& command_name, | 245 const std::string& shortcut, |
246 int index, | 246 const std::string& platform_key, |
247 string16* error) { | 247 int index, |
248 DCHECK(!command_name.empty()); | 248 string16* error) { |
249 std::string key_binding; | 249 std::string shortcut_normalized = StringToLowerASCII(shortcut); |
250 if (!command->GetString(keys::kKey, &key_binding) || | |
251 key_binding.empty()) { | |
252 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | |
253 errors::kInvalidKeyBinding, | |
254 base::IntToString(index), | |
255 "Missing"); | |
256 return false; | |
257 } | |
258 | |
259 std::string original_keybinding = key_binding; | |
260 // Normalize '-' to '+'. | |
261 ReplaceSubstringsAfterOffset(&key_binding, 0, "-", "+"); | |
262 // Remove all spaces. | |
263 ReplaceSubstringsAfterOffset(&key_binding, 0, " ", ""); | |
264 // And finally, lower-case it. | |
265 key_binding = StringToLowerASCII(key_binding); | |
266 | 250 |
267 std::vector<std::string> tokens; | 251 std::vector<std::string> tokens; |
268 base::SplitString(key_binding, '+', &tokens); | 252 base::SplitString(shortcut_normalized, '+', &tokens); |
269 if (tokens.size() < 2 || tokens.size() > 3) { | 253 if (tokens.size() < 2 || tokens.size() > 3) { |
270 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 254 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
271 errors::kInvalidKeyBinding, | 255 errors::kInvalidKeyBinding, |
272 base::IntToString(index), | 256 base::IntToString(index), |
273 original_keybinding); | 257 platform_key, |
274 return false; | 258 shortcut); |
| 259 return ui::Accelerator(); |
275 } | 260 } |
276 | 261 |
277 // Now, parse it into an accelerator. | 262 // Now, parse it into an accelerator. |
278 bool ctrl = false; | 263 bool ctrl = false; |
279 bool alt = false; | 264 bool alt = false; |
280 bool shift = false; | 265 bool shift = false; |
| 266 bool command = false; |
| 267 bool option = false; |
281 ui::KeyboardCode key = ui::VKEY_UNKNOWN; | 268 ui::KeyboardCode key = ui::VKEY_UNKNOWN; |
282 for (size_t i = 0; i < tokens.size(); i++) { | 269 for (size_t i = 0; i < tokens.size(); i++) { |
283 if (tokens[i] == "ctrl") { | 270 if (tokens[i] == "ctrl") { |
284 ctrl = true; | 271 ctrl = true; |
285 } else if (tokens[i] == "alt") { | 272 } else if (tokens[i] == "alt") { |
286 alt = true; | 273 alt = true; |
287 } else if (tokens[i] == "shift") { | 274 } else if (tokens[i] == "shift") { |
288 shift = true; | 275 shift = true; |
| 276 } else if (tokens[i] == "command" && platform_key == "mac") { |
| 277 command = true; |
| 278 } else if (tokens[i] == "option" && platform_key == "mac") { |
| 279 option = true; |
289 } else if (tokens[i].size() == 1 && | 280 } else if (tokens[i].size() == 1 && |
290 tokens[i][0] >= 'a' && tokens[i][0] <= 'z') { | 281 tokens[i][0] >= 'a' && tokens[i][0] <= 'z') { |
291 if (key != ui::VKEY_UNKNOWN) { | 282 if (key != ui::VKEY_UNKNOWN) { |
292 // Multiple key assignments. | 283 // Multiple key assignments. |
293 key = ui::VKEY_UNKNOWN; | 284 key = ui::VKEY_UNKNOWN; |
294 break; | 285 break; |
295 } | 286 } |
296 | 287 |
297 key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'a')); | 288 key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'a')); |
298 } else { | 289 } else { |
299 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 290 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
300 errors::kInvalidKeyBinding, | 291 errors::kInvalidKeyBinding, |
301 base::IntToString(index), | 292 base::IntToString(index), |
302 original_keybinding); | 293 platform_key, |
303 return false; | 294 shortcut); |
| 295 return ui::Accelerator(); |
304 } | 296 } |
305 } | 297 } |
306 | 298 |
307 // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not | 299 // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not |
308 // Ctrl+Alt+foo. For a more detailed reason why we don't support Ctrl+Alt+foo: | 300 // Ctrl+Alt+foo. For a more detailed reason why we don't support Ctrl+Alt+foo: |
309 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx. | 301 // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx. |
310 if (key == ui::VKEY_UNKNOWN || (ctrl && alt)) { | 302 if (key == ui::VKEY_UNKNOWN || (ctrl && alt)) { |
311 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 303 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
312 errors::kInvalidKeyBinding, | 304 errors::kInvalidKeyBinding, |
313 base::IntToString(index), | 305 base::IntToString(index), |
314 original_keybinding); | 306 platform_key, |
315 return false; | 307 shortcut); |
| 308 return ui::Accelerator(); |
316 } | 309 } |
317 | 310 |
318 accelerator_ = ui::Accelerator(key, shift, ctrl, alt); | 311 return ui::Accelerator(key, shift, ctrl, alt); |
| 312 } |
319 | 313 |
320 if (command_name != | 314 bool Extension::ExtensionKeybinding::Parse(DictionaryValue* command, |
321 extension_manifest_values::kPageActionKeybindingEvent && | 315 const std::string& command_name, |
322 command_name != | 316 int index, |
323 extension_manifest_values::kBrowserActionKeybindingEvent) { | 317 string16* error) { |
324 if (!command->GetString(keys::kDescription, &description_) || | 318 DCHECK(!command_name.empty()); |
325 description_.empty()) { | 319 |
| 320 // We'll build up a map of platform-to-shortcut suggestions. |
| 321 std::map<const std::string, std::string> suggestions; |
| 322 |
| 323 // First try to parse the |commands| section as a dictionary. |
| 324 DictionaryValue* suggested_key_dict; |
| 325 if (command->GetDictionary(keys::kSuggestedKey, &suggested_key_dict)) { |
| 326 DictionaryValue::key_iterator iter = suggested_key_dict->begin_keys(); |
| 327 for ( ; iter != suggested_key_dict->end_keys(); ++iter) { |
| 328 // For each item in the dictionary, extract the platforms specified. |
| 329 std::string suggested_key_string; |
| 330 if (suggested_key_dict->GetString(*iter, &suggested_key_string) && |
| 331 !suggested_key_string.empty()) { |
| 332 // Found a platform, add it to the suggestions list. |
| 333 suggestions[StringToLowerASCII(*iter)] = suggested_key_string; |
| 334 } else { |
| 335 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 336 errors::kInvalidKeyBinding, |
| 337 base::IntToString(index), |
| 338 keys::kSuggestedKey, |
| 339 "Missing"); |
| 340 return false; |
| 341 } |
| 342 } |
| 343 } else { |
| 344 // No dictionary was found, fall back to using just a string, so developers |
| 345 // don't have to specify a dictionary if they just want to use one default |
| 346 // for all platforms. |
| 347 std::string suggested_key_string; |
| 348 if (command->GetString(keys::kSuggestedKey, &suggested_key_string) && |
| 349 !suggested_key_string.empty()) { |
| 350 // If only a signle string is provided, it must be default for all. |
| 351 suggestions["default"] = suggested_key_string; |
| 352 } else { |
326 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 353 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
327 errors::kInvalidKeyBindingDescription, | 354 errors::kInvalidKeyBinding, |
328 base::IntToString(index)); | 355 base::IntToString(index), |
329 return false; | 356 keys::kSuggestedKey, |
| 357 "Missing"); |
| 358 return false; |
330 } | 359 } |
331 } | 360 } |
332 | 361 |
333 command_name_ = command_name; | 362 std::string platform = |
| 363 #if defined(OS_WIN) |
| 364 values::kKeybindingPlatformWin; |
| 365 #elif defined(OS_MACOSX) |
| 366 values::kKeybindingPlatformMac; |
| 367 #elif defined(OS_CHROMEOS) |
| 368 values::kKeybindingPlatformChromeOs; |
| 369 #elif defined(OS_LINUX) |
| 370 values::kKeybindingPlatformLinux; |
| 371 #else |
| 372 ""; |
| 373 #endif |
| 374 |
| 375 std::string key = platform; |
| 376 if (suggestions.find(key) == suggestions.end()) |
| 377 key = "default"; |
| 378 if (suggestions.find(key) == suggestions.end()) { |
| 379 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 380 errors::kInvalidKeyBindingMissingPlatform, |
| 381 base::IntToString(index), |
| 382 keys::kSuggestedKey, |
| 383 platform); |
| 384 return false; // No platform specified and no fallback. Bail. |
| 385 } |
| 386 |
| 387 // For developer convenience, we parse all the suggestions (and complain about |
| 388 // errors for platforms other than the current one) but use only what we need. |
| 389 std::map<const std::string, std::string>::const_iterator iter = |
| 390 suggestions.begin(); |
| 391 for ( ; iter != suggestions.end(); ++iter) { |
| 392 // Note that we pass iter->first to pretend we are on a platform we're not |
| 393 // on. |
| 394 ui::Accelerator accelerator = |
| 395 ParseImpl(iter->second, iter->first, index, error); |
| 396 if (accelerator.key_code() == ui::VKEY_UNKNOWN) { |
| 397 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 398 errors::kInvalidKeyBinding, |
| 399 base::IntToString(index), |
| 400 iter->first, |
| 401 iter->second); |
| 402 return false; |
| 403 } |
| 404 |
| 405 if (iter->first == key) { |
| 406 // This platform is our platform, so grab this key. |
| 407 accelerator_ = accelerator; |
| 408 command_name_ = command_name; |
| 409 |
| 410 if (command_name != |
| 411 extension_manifest_values::kPageActionKeybindingEvent && |
| 412 command_name != |
| 413 extension_manifest_values::kBrowserActionKeybindingEvent) { |
| 414 if (!command->GetString(keys::kDescription, &description_) || |
| 415 description_.empty()) { |
| 416 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
| 417 errors::kInvalidKeyBindingDescription, |
| 418 base::IntToString(index)); |
| 419 return false; |
| 420 } |
| 421 } |
| 422 } |
| 423 } |
334 return true; | 424 return true; |
335 } | 425 } |
336 | 426 |
337 // | 427 // |
338 // Extension | 428 // Extension |
339 // | 429 // |
340 | 430 |
341 // static | 431 // static |
342 scoped_refptr<Extension> Extension::Create(const FilePath& path, | 432 scoped_refptr<Extension> Extension::Create(const FilePath& path, |
343 Location location, | 433 Location location, |
(...skipping 1137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1481 ++command_index; | 1571 ++command_index; |
1482 | 1572 |
1483 DictionaryValue* command = NULL; | 1573 DictionaryValue* command = NULL; |
1484 if (!commands->GetDictionary(*iter, &command)) { | 1574 if (!commands->GetDictionary(*iter, &command)) { |
1485 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( | 1575 *error = ExtensionErrorUtils::FormatErrorMessageUTF16( |
1486 errors::kInvalidKeyBindingDictionary, | 1576 errors::kInvalidKeyBindingDictionary, |
1487 base::IntToString(command_index)); | 1577 base::IntToString(command_index)); |
1488 return false; | 1578 return false; |
1489 } | 1579 } |
1490 | 1580 |
1491 ExtensionKeybinding binding; | 1581 scoped_ptr<Extension::ExtensionKeybinding> binding( |
1492 if (!binding.Parse(command, *iter, command_index, error)) | 1582 new ExtensionKeybinding()); |
| 1583 if (!binding->Parse(command, *iter, command_index, error)) |
1493 return false; // |error| already set. | 1584 return false; // |error| already set. |
1494 | 1585 |
1495 commands_.push_back(binding); | 1586 std::string command_name = binding->command_name(); |
| 1587 if (command_name == values::kPageActionKeybindingEvent) |
| 1588 page_action_command_.reset(binding.release()); |
| 1589 else if (command_name == values::kBrowserActionKeybindingEvent) |
| 1590 browser_action_command_.reset(binding.release()); |
| 1591 else |
| 1592 named_commands_[command_name] = *binding.release(); |
1496 } | 1593 } |
1497 } | 1594 } |
1498 return true; | 1595 return true; |
1499 } | 1596 } |
1500 | 1597 |
1501 bool Extension::LoadPlugins(string16* error) { | 1598 bool Extension::LoadPlugins(string16* error) { |
1502 if (!manifest_->HasKey(keys::kPlugins)) | 1599 if (!manifest_->HasKey(keys::kPlugins)) |
1503 return true; | 1600 return true; |
1504 ListValue* list_value = NULL; | 1601 ListValue* list_value = NULL; |
1505 if (!manifest_->GetList(keys::kPlugins, &list_value)) { | 1602 if (!manifest_->GetList(keys::kPlugins, &list_value)) { |
(...skipping 1992 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3498 already_disabled(false), | 3595 already_disabled(false), |
3499 extension(extension) {} | 3596 extension(extension) {} |
3500 | 3597 |
3501 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( | 3598 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( |
3502 const Extension* extension, | 3599 const Extension* extension, |
3503 const ExtensionPermissionSet* permissions, | 3600 const ExtensionPermissionSet* permissions, |
3504 Reason reason) | 3601 Reason reason) |
3505 : reason(reason), | 3602 : reason(reason), |
3506 extension(extension), | 3603 extension(extension), |
3507 permissions(permissions) {} | 3604 permissions(permissions) {} |
OLD | NEW |