OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 <algorithm> | 5 #include <algorithm> |
6 #include <set> | 6 #include <set> |
7 | 7 |
8 #include "chrome/browser/tab_contents/render_view_context_menu.h" | 8 #include "chrome/browser/tab_contents/render_view_context_menu.h" |
9 | 9 |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 #include "net/url_request/url_request.h" | 53 #include "net/url_request/url_request.h" |
54 #include "third_party/WebKit/Source/WebKit/chromium/public/WebContextMenuData.h" | 54 #include "third_party/WebKit/Source/WebKit/chromium/public/WebContextMenuData.h" |
55 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerAction.
h" | 55 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerAction.
h" |
56 #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextDirection.h" | 56 #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextDirection.h" |
57 #include "ui/base/l10n/l10n_util.h" | 57 #include "ui/base/l10n/l10n_util.h" |
58 #include "webkit/glue/webmenuitem.h" | 58 #include "webkit/glue/webmenuitem.h" |
59 | 59 |
60 using WebKit::WebContextMenuData; | 60 using WebKit::WebContextMenuData; |
61 using WebKit::WebMediaPlayerAction; | 61 using WebKit::WebMediaPlayerAction; |
62 | 62 |
| 63 namespace { |
| 64 |
| 65 bool IsCustomItemEnabled(const std::vector<WebMenuItem>& items, int id) { |
| 66 DCHECK(id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST && |
| 67 id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST); |
| 68 for (size_t i = 0; i < items.size(); ++i) { |
| 69 int action_id = IDC_CONTENT_CONTEXT_CUSTOM_FIRST + items[i].action; |
| 70 if (action_id == id) |
| 71 return items[i].enabled; |
| 72 if (items[i].type == WebMenuItem::SUBMENU) { |
| 73 if (IsCustomItemEnabled(items[i].submenu, id)) |
| 74 return true; |
| 75 } |
| 76 } |
| 77 return false; |
| 78 } |
| 79 |
| 80 bool IsCustomItemChecked(const std::vector<WebMenuItem>& items, int id) { |
| 81 DCHECK(id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST && |
| 82 id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST); |
| 83 for (size_t i = 0; i < items.size(); ++i) { |
| 84 int action_id = IDC_CONTENT_CONTEXT_CUSTOM_FIRST + items[i].action; |
| 85 if (action_id == id) |
| 86 return items[i].checked; |
| 87 if (items[i].type == WebMenuItem::SUBMENU) { |
| 88 if (IsCustomItemChecked(items[i].submenu, id)) |
| 89 return true; |
| 90 } |
| 91 } |
| 92 return false; |
| 93 } |
| 94 |
| 95 const size_t kMaxCustomMenuDepth = 5; |
| 96 const size_t kMaxCustomMenuTotalItems = 1000; |
| 97 |
| 98 void AddCustomItemsToMenu(const std::vector<WebMenuItem>& items, |
| 99 size_t depth, |
| 100 size_t* total_items, |
| 101 ui::SimpleMenuModel::Delegate* delegate, |
| 102 ui::SimpleMenuModel* menu_model) { |
| 103 if (depth > kMaxCustomMenuDepth) { |
| 104 LOG(ERROR) << "Custom menu too deeply nested."; |
| 105 return; |
| 106 } |
| 107 for (size_t i = 0; i < items.size(); ++i) { |
| 108 if (IDC_CONTENT_CONTEXT_CUSTOM_FIRST + items[i].action >= |
| 109 IDC_CONTENT_CONTEXT_CUSTOM_LAST) { |
| 110 LOG(ERROR) << "Custom menu action value too big."; |
| 111 return; |
| 112 } |
| 113 if (*total_items >= kMaxCustomMenuTotalItems) { |
| 114 LOG(ERROR) << "Custom menu too large (too many items)."; |
| 115 return; |
| 116 } |
| 117 (*total_items)++; |
| 118 switch (items[i].type) { |
| 119 case WebMenuItem::OPTION: |
| 120 menu_model->AddItem( |
| 121 items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST, |
| 122 items[i].label); |
| 123 break; |
| 124 case WebMenuItem::CHECKABLE_OPTION: |
| 125 menu_model->AddCheckItem( |
| 126 items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST, |
| 127 items[i].label); |
| 128 break; |
| 129 case WebMenuItem::GROUP: |
| 130 // TODO(viettrungluu): I don't know what this is supposed to do. |
| 131 NOTREACHED(); |
| 132 break; |
| 133 case WebMenuItem::SEPARATOR: |
| 134 menu_model->AddSeparator(); |
| 135 break; |
| 136 case WebMenuItem::SUBMENU: { |
| 137 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate); |
| 138 AddCustomItemsToMenu(items[i].submenu, depth + 1, total_items, delegate, |
| 139 submenu); |
| 140 menu_model->AddSubMenu( |
| 141 items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST, |
| 142 items[i].label, |
| 143 submenu); |
| 144 break; |
| 145 } |
| 146 default: |
| 147 NOTREACHED(); |
| 148 break; |
| 149 } |
| 150 } |
| 151 } |
| 152 |
| 153 } // namespace |
| 154 |
63 // static | 155 // static |
64 const size_t RenderViewContextMenu::kMaxExtensionItemTitleLength = 75; | 156 const size_t RenderViewContextMenu::kMaxExtensionItemTitleLength = 75; |
65 // static | 157 // static |
66 const size_t RenderViewContextMenu::kMaxSelectionTextLength = 50; | 158 const size_t RenderViewContextMenu::kMaxSelectionTextLength = 50; |
67 | 159 |
68 // static | 160 // static |
69 bool RenderViewContextMenu::IsDevToolsURL(const GURL& url) { | 161 bool RenderViewContextMenu::IsDevToolsURL(const GURL& url) { |
70 return url.SchemeIs(chrome::kChromeDevToolsScheme) && | 162 return url.SchemeIs(chrome::kChromeDevToolsScheme) && |
71 url.host() == chrome::kChromeUIDevToolsHost; | 163 url.host() == chrome::kChromeUIDevToolsHost; |
72 } | 164 } |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 UMA_HISTOGRAM_TIMES("Extensions.ContextMenus_BuildTime", | 443 UMA_HISTOGRAM_TIMES("Extensions.ContextMenus_BuildTime", |
352 base::TimeTicks::Now() - begin); | 444 base::TimeTicks::Now() - begin); |
353 UMA_HISTOGRAM_COUNTS("Extensions.ContextMenus_ItemCount", index); | 445 UMA_HISTOGRAM_COUNTS("Extensions.ContextMenus_ItemCount", index); |
354 } | 446 } |
355 | 447 |
356 void RenderViewContextMenu::InitMenu() { | 448 void RenderViewContextMenu::InitMenu() { |
357 bool has_link = !params_.link_url.is_empty(); | 449 bool has_link = !params_.link_url.is_empty(); |
358 bool has_selection = !params_.selection_text.empty(); | 450 bool has_selection = !params_.selection_text.empty(); |
359 | 451 |
360 if (AppendCustomItems()) { | 452 if (AppendCustomItems()) { |
361 AppendDeveloperItems(); | 453 // Don't add items for Pepper menu. |
| 454 if (!params_.custom_context.is_pepper_menu) |
| 455 AppendDeveloperItems(); |
362 return; | 456 return; |
363 } | 457 } |
364 | 458 |
365 // When no special node or text is selected and selection has no link, | 459 // When no special node or text is selected and selection has no link, |
366 // show page items. | 460 // show page items. |
367 bool is_devtools = false; | 461 bool is_devtools = false; |
368 if (params_.media_type == WebContextMenuData::MediaTypeNone && | 462 if (params_.media_type == WebContextMenuData::MediaTypeNone && |
369 !has_link && | 463 !has_link && |
370 !params_.is_editable && | 464 !params_.is_editable && |
371 !has_selection) { | 465 !has_selection) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
417 | 511 |
418 AppendDeveloperItems(); | 512 AppendDeveloperItems(); |
419 } | 513 } |
420 | 514 |
421 void RenderViewContextMenu::LookUpInDictionary() { | 515 void RenderViewContextMenu::LookUpInDictionary() { |
422 // Used only in the Mac port. | 516 // Used only in the Mac port. |
423 NOTREACHED(); | 517 NOTREACHED(); |
424 } | 518 } |
425 | 519 |
426 bool RenderViewContextMenu::AppendCustomItems() { | 520 bool RenderViewContextMenu::AppendCustomItems() { |
427 std::vector<WebMenuItem>& custom_items = params_.custom_items; | 521 size_t total_items = 0; |
428 for (size_t i = 0; i < custom_items.size(); ++i) { | 522 AddCustomItemsToMenu(params_.custom_items, 0, &total_items, this, |
429 DCHECK(IDC_CONTENT_CONTEXT_CUSTOM_FIRST + custom_items[i].action < | 523 &menu_model_); |
430 IDC_CONTENT_CONTEXT_CUSTOM_LAST); | 524 return total_items > 0; |
431 if (custom_items[i].type == WebMenuItem::SEPARATOR) { | |
432 menu_model_.AddSeparator(); | |
433 } else if (custom_items[i].type == WebMenuItem::CHECKABLE_OPTION) { | |
434 menu_model_.AddCheckItem( | |
435 custom_items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST, | |
436 custom_items[i].label); | |
437 } else { | |
438 menu_model_.AddItem( | |
439 custom_items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST, | |
440 custom_items[i].label); | |
441 } | |
442 } | |
443 return custom_items.size() > 0; | |
444 } | 525 } |
445 | 526 |
446 void RenderViewContextMenu::AppendDeveloperItems() { | 527 void RenderViewContextMenu::AppendDeveloperItems() { |
447 if (g_browser_process->have_inspector_files()) { | 528 if (g_browser_process->have_inspector_files()) { |
448 // In the DevTools popup menu, "developer items" is normally the only | 529 // In the DevTools popup menu, "developer items" is normally the only |
449 // section, so omit the separator there. | 530 // section, so omit the separator there. |
450 if (menu_model_.GetItemCount() > 0) | 531 if (menu_model_.GetItemCount() > 0) |
451 menu_model_.AddSeparator(); | 532 menu_model_.AddSeparator(); |
452 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTELEMENT, | 533 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTELEMENT, |
453 IDS_CONTENT_CONTEXT_INSPECTELEMENT); | 534 IDS_CONTENT_CONTEXT_INSPECTELEMENT); |
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
766 CONTENT_RESTRICTION_SAVE)) { | 847 CONTENT_RESTRICTION_SAVE)) { |
767 return false; | 848 return false; |
768 } | 849 } |
769 | 850 |
770 // Allow Spell Check language items on sub menu for text area context menu. | 851 // Allow Spell Check language items on sub menu for text area context menu. |
771 if ((id >= IDC_SPELLCHECK_LANGUAGES_FIRST) && | 852 if ((id >= IDC_SPELLCHECK_LANGUAGES_FIRST) && |
772 (id < IDC_SPELLCHECK_LANGUAGES_LAST)) { | 853 (id < IDC_SPELLCHECK_LANGUAGES_LAST)) { |
773 return profile_->GetPrefs()->GetBoolean(prefs::kEnableSpellCheck); | 854 return profile_->GetPrefs()->GetBoolean(prefs::kEnableSpellCheck); |
774 } | 855 } |
775 | 856 |
776 // Process custom actions range. | 857 // Custom items. |
777 if ((id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST) && | |
778 (id < IDC_CONTENT_CONTEXT_CUSTOM_LAST)) { | |
779 unsigned action = id - IDC_CONTENT_CONTEXT_CUSTOM_FIRST; | |
780 for (size_t i = 0; i < params_.custom_items.size(); ++i) { | |
781 if (params_.custom_items[i].action == action) | |
782 return params_.custom_items[i].enabled; | |
783 } | |
784 NOTREACHED(); | |
785 return false; | |
786 } | |
787 | |
788 // Custom WebKit items. | |
789 if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST && | 858 if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST && |
790 id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) { | 859 id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) { |
791 const std::vector<WebMenuItem>& custom_items = params_.custom_items; | 860 return IsCustomItemEnabled(params_.custom_items, id); |
792 for (size_t i = 0; i < custom_items.size(); ++i) { | |
793 int action_id = IDC_CONTENT_CONTEXT_CUSTOM_FIRST + custom_items[i].action; | |
794 if (action_id == id) | |
795 return custom_items[i].enabled; | |
796 } | |
797 return true; | |
798 } | 861 } |
799 | 862 |
800 // Extension items. | 863 // Extension items. |
801 if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST && | 864 if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST && |
802 id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) { | 865 id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) { |
803 // In the future we may add APIs for extensions to disable items, but for | 866 // In the future we may add APIs for extensions to disable items, but for |
804 // now all items are implicitly enabled. | 867 // now all items are implicitly enabled. |
805 return true; | 868 return true; |
806 } | 869 } |
807 | 870 |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1013 if (id == IDC_CONTENT_CONTEXT_LOOP) { | 1076 if (id == IDC_CONTENT_CONTEXT_LOOP) { |
1014 return (params_.media_flags & | 1077 return (params_.media_flags & |
1015 WebContextMenuData::MediaLoop) != 0; | 1078 WebContextMenuData::MediaLoop) != 0; |
1016 } | 1079 } |
1017 | 1080 |
1018 if (id == IDC_CONTENT_CONTEXT_CONTROLS) { | 1081 if (id == IDC_CONTENT_CONTEXT_CONTROLS) { |
1019 return (params_.media_flags & | 1082 return (params_.media_flags & |
1020 WebContextMenuData::MediaControls) != 0; | 1083 WebContextMenuData::MediaControls) != 0; |
1021 } | 1084 } |
1022 | 1085 |
1023 // Custom WebKit items. | 1086 // Custom items. |
1024 if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST && | 1087 if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST && |
1025 id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) { | 1088 id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) { |
1026 const std::vector<WebMenuItem>& custom_items = params_.custom_items; | 1089 return IsCustomItemChecked(params_.custom_items, id); |
1027 for (size_t i = 0; i < custom_items.size(); ++i) { | |
1028 int action_id = IDC_CONTENT_CONTEXT_CUSTOM_FIRST + custom_items[i].action; | |
1029 if (action_id == id) | |
1030 return custom_items[i].checked; | |
1031 } | |
1032 return false; | |
1033 } | 1090 } |
1034 | 1091 |
1035 // Extension items. | 1092 // Extension items. |
1036 if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST && | 1093 if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST && |
1037 id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) { | 1094 id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) { |
1038 ExtensionMenuItem* item = GetExtensionMenuItem(id); | 1095 ExtensionMenuItem* item = GetExtensionMenuItem(id); |
1039 if (item) | 1096 if (item) |
1040 return item->checked(); | 1097 return item->checked(); |
1041 else | 1098 else |
1042 return false; | 1099 return false; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1083 if (language_number < languages.size()) { | 1140 if (language_number < languages.size()) { |
1084 StringPrefMember dictionary_language; | 1141 StringPrefMember dictionary_language; |
1085 dictionary_language.Init(prefs::kSpellCheckDictionary, | 1142 dictionary_language.Init(prefs::kSpellCheckDictionary, |
1086 profile_->GetPrefs(), NULL); | 1143 profile_->GetPrefs(), NULL); |
1087 dictionary_language.SetValue(languages[language_number]); | 1144 dictionary_language.SetValue(languages[language_number]); |
1088 } | 1145 } |
1089 return; | 1146 return; |
1090 } | 1147 } |
1091 | 1148 |
1092 // Process custom actions range. | 1149 // Process custom actions range. |
1093 if ((id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST) && | 1150 if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST && |
1094 (id < IDC_CONTENT_CONTEXT_CUSTOM_LAST)) { | 1151 id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) { |
1095 unsigned action = id - IDC_CONTENT_CONTEXT_CUSTOM_FIRST; | 1152 unsigned action = id - IDC_CONTENT_CONTEXT_CUSTOM_FIRST; |
1096 source_tab_contents_->render_view_host()-> | 1153 source_tab_contents_->render_view_host()->PerformCustomContextMenuAction( |
1097 PerformCustomContextMenuAction(action); | 1154 params_.custom_context, action); |
1098 return; | 1155 return; |
1099 } | 1156 } |
1100 | 1157 |
1101 // Process extension menu items. | 1158 // Process extension menu items. |
1102 if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST && | 1159 if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST && |
1103 id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) { | 1160 id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) { |
1104 ExtensionMenuManager* manager = | 1161 ExtensionMenuManager* manager = |
1105 profile_->GetExtensionService()->menu_manager(); | 1162 profile_->GetExtensionService()->menu_manager(); |
1106 std::map<int, ExtensionMenuItem::Id>::const_iterator i = | 1163 std::map<int, ExtensionMenuItem::Id>::const_iterator i = |
1107 extension_item_map_.find(id); | 1164 extension_item_map_.find(id); |
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1392 break; | 1449 break; |
1393 #endif // OS_MACOSX | 1450 #endif // OS_MACOSX |
1394 | 1451 |
1395 default: | 1452 default: |
1396 NOTREACHED(); | 1453 NOTREACHED(); |
1397 break; | 1454 break; |
1398 } | 1455 } |
1399 } | 1456 } |
1400 | 1457 |
1401 void RenderViewContextMenu::MenuClosed() { | 1458 void RenderViewContextMenu::MenuClosed() { |
1402 source_tab_contents_->render_view_host()->ContextMenuClosed(); | 1459 source_tab_contents_->render_view_host()->ContextMenuClosed( |
| 1460 params_.custom_context); |
1403 } | 1461 } |
1404 | 1462 |
1405 bool RenderViewContextMenu::IsDevCommandEnabled(int id) const { | 1463 bool RenderViewContextMenu::IsDevCommandEnabled(int id) const { |
1406 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | 1464 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
1407 if (command_line.HasSwitch(switches::kAlwaysEnableDevTools)) | 1465 if (command_line.HasSwitch(switches::kAlwaysEnableDevTools)) |
1408 return true; | 1466 return true; |
1409 | 1467 |
1410 NavigationEntry *active_entry = | 1468 NavigationEntry *active_entry = |
1411 source_tab_contents_->controller().GetActiveEntry(); | 1469 source_tab_contents_->controller().GetActiveEntry(); |
1412 if (!active_entry) | 1470 if (!active_entry) |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1472 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages), | 1530 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages), |
1473 g_browser_process->clipboard()); | 1531 g_browser_process->clipboard()); |
1474 } | 1532 } |
1475 | 1533 |
1476 void RenderViewContextMenu::MediaPlayerActionAt( | 1534 void RenderViewContextMenu::MediaPlayerActionAt( |
1477 const gfx::Point& location, | 1535 const gfx::Point& location, |
1478 const WebMediaPlayerAction& action) { | 1536 const WebMediaPlayerAction& action) { |
1479 source_tab_contents_->render_view_host()->MediaPlayerActionAt( | 1537 source_tab_contents_->render_view_host()->MediaPlayerActionAt( |
1480 location, action); | 1538 location, action); |
1481 } | 1539 } |
OLD | NEW |