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 |