1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/tab_contents/render_view_context_menu.h"
11 #include "apps/app_load_service.h"
12 #include "base/command_line.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram.h"
15 #include "base/prefs/pref_member.h"
16 #include "base/prefs/pref_service.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/time/time.h"
22 #include "chrome/app/chrome_command_ids.h"
23 #include "chrome/browser/app_mode/app_mode_utils.h"
24 #include "chrome/browser/autocomplete/autocomplete_classifier.h"
25 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
26 #include "chrome/browser/autocomplete/autocomplete_match.h"
27 #include "chrome/browser/browser_process.h"
28 #include "chrome/browser/chrome_notification_types.h"
29 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
30 #include "chrome/browser/devtools/devtools_window.h"
31 #include "chrome/browser/download/download_service.h"
32 #include "chrome/browser/download/download_service_factory.h"
33 #include "chrome/browser/download/download_stats.h"
34 #include "chrome/browser/extensions/devtools_util.h"
35 #include "chrome/browser/extensions/extension_host.h"
36 #include "chrome/browser/extensions/extension_service.h"
37 #include "chrome/browser/extensions/extension_system.h"
38 #include "chrome/browser/google/google_util.h"
39 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
40 #include "chrome/browser/prefs/incognito_mode_prefs.h"
41 #include "chrome/browser/profiles/profile.h"
42 #include "chrome/browser/profiles/profile_io_data.h"
43 #include "chrome/browser/search/search.h"
44 #include "chrome/browser/search_engines/search_terms_data.h"
45 #include "chrome/browser/search_engines/template_url.h"
46 #include "chrome/browser/search_engines/template_url_service.h"
47 #include "chrome/browser/search_engines/template_url_service_factory.h"
48 #include "chrome/browser/spellchecker/spellcheck_host_metrics.h"
49 #include "chrome/browser/spellchecker/spellcheck_service.h"
50 #include "chrome/browser/tab_contents/retargeting_details.h"
51 #include "chrome/browser/tab_contents/spellchecker_submenu_observer.h"
52 #include "chrome/browser/tab_contents/spelling_menu_observer.h"
53 #include "chrome/browser/translate/translate_manager.h"
54 #include "chrome/browser/translate/translate_prefs.h"
55 #include "chrome/browser/translate/translate_tab_helper.h"
56 #include "chrome/browser/ui/browser.h"
57 #include "chrome/browser/ui/browser_commands.h"
58 #include "chrome/browser/ui/browser_finder.h"
59 #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"
60 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
61 #include "chrome/common/chrome_constants.h"
62 #include "chrome/common/chrome_switches.h"
63 #include "chrome/common/content_restriction.h"
64 #include "chrome/common/extensions/extension.h"
65 #include "chrome/common/net/url_util.h"
66 #include "chrome/common/pref_names.h"
67 #include "chrome/common/render_messages.h"
68 #include "chrome/common/spellcheck_messages.h"
69 #include "chrome/common/url_constants.h"
70 #include "content/public/browser/child_process_security_policy.h"
71 #include "content/public/browser/download_manager.h"
72 #include "content/public/browser/download_save_info.h"
73 #include "content/public/browser/download_url_parameters.h"
74 #include "content/public/browser/navigation_details.h"
75 #include "content/public/browser/navigation_entry.h"
76 #include "content/public/browser/notification_service.h"
77 #include "content/public/browser/render_process_host.h"
78 #include "content/public/browser/render_view_host.h"
79 #include "content/public/browser/render_widget_host_view.h"
80 #include "content/public/browser/user_metrics.h"
81 #include "content/public/browser/web_contents.h"
82 #include "content/public/common/menu_item.h"
83 #include "content/public/common/ssl_status.h"
84 #include "content/public/common/url_utils.h"
85 #include "extensions/browser/view_type_utils.h"
86 #include "grit/generated_resources.h"
87 #include "net/base/escape.h"
88 #include "third_party/WebKit/public/web/WebContextMenuData.h"
89 #include "third_party/WebKit/public/web/WebMediaPlayerAction.h"
90 #include "third_party/WebKit/public/web/WebPluginAction.h"
91 #include "ui/base/clipboard/clipboard.h"
92 #include "ui/base/l10n/l10n_util.h"
93 #include "ui/gfx/favicon_size.h"
94 #include "ui/gfx/point.h"
95 #include "ui/gfx/size.h"
96 #include "ui/gfx/text_elider.h"
98 #if defined(ENABLE_PRINTING)
99 #include "chrome/common/print_messages.h"
101 #if defined(ENABLE_FULL_PRINTING)
102 #include "chrome/browser/printing/print_preview_context_menu_observer.h"
103 #include "chrome/browser/printing/print_preview_dialog_controller.h"
104 #include "chrome/browser/printing/print_view_manager.h"
106 #include "chrome/browser/printing/print_view_manager_basic.h"
107 #endif // defined(ENABLE_FULL_PRINTING)
108 #endif // defined(ENABLE_PRINTING)
110 using WebKit::WebContextMenuData;
111 using WebKit::WebMediaPlayerAction;
112 using WebKit::WebPluginAction;
113 using WebKit::WebString;
114 using WebKit::WebURL;
115 using content::BrowserContext;
116 using content::ChildProcessSecurityPolicy;
117 using content::DownloadManager;
118 using content::DownloadUrlParameters;
119 using content::NavigationController;
120 using content::NavigationEntry;
121 using content::OpenURLParams;
122 using content::RenderViewHost;
123 using content::SSLStatus;
124 using content::UserMetricsAction;
125 using content::WebContents;
126 using extensions::Extension;
127 using extensions::MenuItem;
128 using extensions::MenuManager;
132 const int kImageSearchThumbnailMinSize = 300 * 300;
133 const int kImageSearchThumbnailMaxWidth = 600;
134 const int kImageSearchThumbnailMaxHeight = 600;
136 // Maps UMA enumeration to IDC. IDC could be changed so we can't use
137 // just them and |UMA_HISTOGRAM_CUSTOM_ENUMERATION|.
138 // Never change mapping or reuse |enum_id|. Always push back new items.
139 // Items that is not used any more by |RenderViewContextMenu.ExecuteCommand|
140 // could be deleted, but don't change the rest of |kUmaEnumToControlId|.
141 const struct UmaEnumCommandIdPair {
144 } kUmaEnumToControlId[] = {
145 { 0, IDC_CONTENT_CONTEXT_CUSTOM_FIRST },
146 { 1, IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST },
147 { 2, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST },
148 { 3, IDC_CONTENT_CONTEXT_OPENLINKNEWTAB },
149 { 4, IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW },
150 { 5, IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD },
151 { 6, IDC_CONTENT_CONTEXT_SAVELINKAS },
152 { 7, IDC_CONTENT_CONTEXT_SAVEAVAS },
153 { 8, IDC_CONTENT_CONTEXT_SAVEIMAGEAS },
154 { 9, IDC_CONTENT_CONTEXT_COPYLINKLOCATION },
155 { 10, IDC_CONTENT_CONTEXT_COPYIMAGELOCATION },
156 { 11, IDC_CONTENT_CONTEXT_COPYAVLOCATION },
157 { 12, IDC_CONTENT_CONTEXT_COPYIMAGE },
158 { 13, IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB },
159 { 14, IDC_CONTENT_CONTEXT_OPENAVNEWTAB },
160 { 15, IDC_CONTENT_CONTEXT_PLAYPAUSE },
161 { 16, IDC_CONTENT_CONTEXT_MUTE },
162 { 17, IDC_CONTENT_CONTEXT_LOOP },
163 { 18, IDC_CONTENT_CONTEXT_CONTROLS },
164 { 19, IDC_CONTENT_CONTEXT_ROTATECW },
165 { 20, IDC_CONTENT_CONTEXT_ROTATECCW },
168 { 23, IDC_SAVE_PAGE },
170 { 25, IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP },
171 { 26, IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP },
173 { 28, IDC_VIEW_SOURCE },
174 { 29, IDC_CONTENT_CONTEXT_INSPECTELEMENT },
175 { 30, IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE },
176 { 31, IDC_CONTENT_CONTEXT_VIEWPAGEINFO },
177 { 32, IDC_CONTENT_CONTEXT_TRANSLATE },
178 { 33, IDC_CONTENT_CONTEXT_RELOADFRAME },
179 { 34, IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE },
180 { 35, IDC_CONTENT_CONTEXT_VIEWFRAMEINFO },
181 { 36, IDC_CONTENT_CONTEXT_UNDO },
182 { 37, IDC_CONTENT_CONTEXT_REDO },
183 { 38, IDC_CONTENT_CONTEXT_CUT },
184 { 39, IDC_CONTENT_CONTEXT_COPY },
185 { 40, IDC_CONTENT_CONTEXT_PASTE },
186 { 41, IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE },
187 { 42, IDC_CONTENT_CONTEXT_DELETE },
188 { 43, IDC_CONTENT_CONTEXT_SELECTALL },
189 { 44, IDC_CONTENT_CONTEXT_SEARCHWEBFOR },
190 { 45, IDC_CONTENT_CONTEXT_GOTOURL },
191 { 46, IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS },
192 { 47, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS },
193 { 48, IDC_CONTENT_CONTEXT_ADDSEARCHENGINE },
194 { 49, IDC_CONTENT_CONTEXT_SPEECH_INPUT_FILTER_PROFANITIES },
195 { 50, IDC_CONTENT_CONTEXT_SPEECH_INPUT_ABOUT },
196 { 51, IDC_SPEECH_INPUT_MENU },
197 { 52, IDC_CONTENT_CONTEXT_OPENLINKWITH },
198 { 53, IDC_CHECK_SPELLING_WHILE_TYPING },
199 { 54, IDC_SPELLCHECK_MENU },
200 { 55, IDC_CONTENT_CONTEXT_SPELLING_TOGGLE },
201 { 56, IDC_SPELLCHECK_LANGUAGES_FIRST },
202 { 57, IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE },
203 // Add new items here and use |enum_id| from the next line.
204 { 58, 0 }, // Must be the last. Increment |enum_id| when new IDC was added.
207 // Collapses large ranges of ids before looking for UMA enum.
208 int CollapleCommandsForUMA(int id) {
209 if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
210 id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) {
211 return IDC_CONTENT_CONTEXT_CUSTOM_FIRST;
214 if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
215 id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
216 return IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
219 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
220 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
221 return IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
224 if (id >= IDC_SPELLCHECK_LANGUAGES_FIRST &&
225 id <= IDC_SPELLCHECK_LANGUAGES_LAST) {
226 return IDC_SPELLCHECK_LANGUAGES_FIRST;
232 // Returns UMA enum value for command specified by |id| or -1 if not found.
233 int FindUMAEnumValueForCommand(int id) {
234 id = CollapleCommandsForUMA(id);
235 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
236 for (size_t i = 0; i < kMappingSize; ++i) {
237 if (kUmaEnumToControlId[i].control_id == id) {
238 return kUmaEnumToControlId[i].enum_id;
244 // Increments histogram value for used items specified by |id|.
245 void RecordUsedItem(int id) {
246 int enum_id = FindUMAEnumValueForCommand(id);
248 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
249 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Used", enum_id,
250 kUmaEnumToControlId[kMappingSize - 1].enum_id);
252 NOTREACHED() << "Update kUmaEnumToControlId. Unhanded IDC: " << id;
256 // Increments histogram value for visible context menu item specified by |id|.
257 void RecordShownItem(int id) {
258 int enum_id = FindUMAEnumValueForCommand(id);
260 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
261 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Shown", enum_id,
262 kUmaEnumToControlId[kMappingSize - 1].enum_id);
264 // Just warning here. It's harder to maintain list of all possibly
265 // visible items than executable items.
266 DLOG(ERROR) << "Update kUmaEnumToControlId. Unhanded IDC: " << id;
270 // Usually a new tab is expected where this function is used,
271 // however users should be able to open a tab in background
272 // or in a new window.
273 WindowOpenDisposition ForceNewTabDispositionFromEventFlags(
275 WindowOpenDisposition disposition =
276 ui::DispositionFromEventFlags(event_flags);
277 return disposition == CURRENT_TAB ? NEW_FOREGROUND_TAB : disposition;
280 bool IsCustomItemEnabled(const std::vector<content::MenuItem>& items, int id) {
281 DCHECK(id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
282 id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST);
283 for (size_t i = 0; i < items.size(); ++i) {
284 int action_id = IDC_CONTENT_CONTEXT_CUSTOM_FIRST + items[i].action;
286 return items[i].enabled;
287 if (items[i].type == content::MenuItem::SUBMENU) {
288 if (IsCustomItemEnabled(items[i].submenu, id))
295 bool IsCustomItemChecked(const std::vector<content::MenuItem>& items, int id) {
296 DCHECK(id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
297 id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST);
298 for (size_t i = 0; i < items.size(); ++i) {
299 int action_id = IDC_CONTENT_CONTEXT_CUSTOM_FIRST + items[i].action;
301 return items[i].checked;
302 if (items[i].type == content::MenuItem::SUBMENU) {
303 if (IsCustomItemChecked(items[i].submenu, id))
310 const size_t kMaxCustomMenuDepth = 5;
311 const size_t kMaxCustomMenuTotalItems = 1000;
313 void AddCustomItemsToMenu(const std::vector<content::MenuItem>& items,
316 ui::SimpleMenuModel::Delegate* delegate,
317 ui::SimpleMenuModel* menu_model) {
318 if (depth > kMaxCustomMenuDepth) {
319 LOG(ERROR) << "Custom menu too deeply nested.";
322 for (size_t i = 0; i < items.size(); ++i) {
323 if (IDC_CONTENT_CONTEXT_CUSTOM_FIRST + items[i].action >=
324 IDC_CONTENT_CONTEXT_CUSTOM_LAST) {
325 LOG(ERROR) << "Custom menu action value too big.";
328 if (*total_items >= kMaxCustomMenuTotalItems) {
329 LOG(ERROR) << "Custom menu too large (too many items).";
333 switch (items[i].type) {
334 case content::MenuItem::OPTION:
336 items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
339 case content::MenuItem::CHECKABLE_OPTION:
340 menu_model->AddCheckItem(
341 items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
344 case content::MenuItem::GROUP:
345 // TODO(viettrungluu): I don't know what this is supposed to do.
348 case content::MenuItem::SEPARATOR:
349 menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
351 case content::MenuItem::SUBMENU: {
352 ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate);
353 AddCustomItemsToMenu(items[i].submenu, depth + 1, total_items, delegate,
355 menu_model->AddSubMenu(
356 items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
368 void DevToolsInspectElementAt(RenderViewHost* rvh, int x, int y) {
369 DevToolsWindow::InspectElement(rvh, x, y);
372 // Helper function to escape "&" as "&&".
373 void EscapeAmpersands(string16* text) {
374 const char16 ampersand[] = {'&', 0};
375 ReplaceChars(*text, ampersand, ASCIIToUTF16("&&"), text);
381 const size_t RenderViewContextMenu::kMaxSelectionTextLength = 50;
384 bool RenderViewContextMenu::IsDevToolsURL(const GURL& url) {
385 return url.SchemeIs(chrome::kChromeDevToolsScheme);
389 bool RenderViewContextMenu::IsInternalResourcesURL(const GURL& url) {
390 if (!url.SchemeIs(chrome::kChromeUIScheme))
392 return url.host() == chrome::kChromeUISyncResourcesHost;
395 static const int kSpellcheckRadioGroup = 1;
397 RenderViewContextMenu::RenderViewContextMenu(
398 WebContents* web_contents,
399 const content::ContextMenuParams& params)
401 source_web_contents_(web_contents),
402 profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
404 extension_items_(profile_, this, &menu_model_,
405 base::Bind(MenuItemMatchesParams, params_)),
407 speech_input_submenu_model_(this),
408 protocol_handler_submenu_model_(this),
409 protocol_handler_registry_(
410 ProtocolHandlerRegistryFactory::GetForProfile(profile_)),
411 command_executed_(false),
413 RenderViewHost* rvh = source_web_contents_->GetRenderViewHost();
414 if (rvh && rvh->GetProcess()->IsGuest())
418 RenderViewContextMenu::~RenderViewContextMenu() {
421 // Menu construction functions -------------------------------------------------
423 void RenderViewContextMenu::Init() {
428 void RenderViewContextMenu::Cancel() {
432 static bool ExtensionPatternMatch(const extensions::URLPatternSet& patterns,
434 // No patterns means no restriction, so that implicitly matches.
435 if (patterns.is_empty())
437 return patterns.MatchesURL(url);
441 bool RenderViewContextMenu::ExtensionContextAndPatternMatch(
442 const content::ContextMenuParams& params,
443 MenuItem::ContextList contexts,
444 const extensions::URLPatternSet& target_url_patterns) {
445 const bool has_link = !params.link_url.is_empty();
446 const bool has_selection = !params.selection_text.empty();
447 const bool in_frame = !params.frame_url.is_empty();
449 if (contexts.Contains(MenuItem::ALL) ||
450 (has_selection && contexts.Contains(MenuItem::SELECTION)) ||
451 (params.is_editable && contexts.Contains(MenuItem::EDITABLE)) ||
452 (in_frame && contexts.Contains(MenuItem::FRAME)))
455 if (has_link && contexts.Contains(MenuItem::LINK) &&
456 ExtensionPatternMatch(target_url_patterns, params.link_url))
459 switch (params.media_type) {
460 case WebContextMenuData::MediaTypeImage:
461 if (contexts.Contains(MenuItem::IMAGE) &&
462 ExtensionPatternMatch(target_url_patterns, params.src_url))
466 case WebContextMenuData::MediaTypeVideo:
467 if (contexts.Contains(MenuItem::VIDEO) &&
468 ExtensionPatternMatch(target_url_patterns, params.src_url))
472 case WebContextMenuData::MediaTypeAudio:
473 if (contexts.Contains(MenuItem::AUDIO) &&
474 ExtensionPatternMatch(target_url_patterns, params.src_url))
482 // PAGE is the least specific context, so we only examine that if none of the
483 // other contexts apply (except for FRAME, which is included in PAGE for
484 // backwards compatibility).
485 if (!has_link && !has_selection && !params.is_editable &&
486 params.media_type == WebContextMenuData::MediaTypeNone &&
487 contexts.Contains(MenuItem::PAGE))
493 static const GURL& GetDocumentURL(const content::ContextMenuParams& params) {
494 return params.frame_url.is_empty() ? params.page_url : params.frame_url;
498 bool RenderViewContextMenu::MenuItemMatchesParams(
499 const content::ContextMenuParams& params,
500 const extensions::MenuItem* item) {
501 bool match = ExtensionContextAndPatternMatch(params, item->contexts(),
502 item->target_url_patterns());
506 const GURL& document_url = GetDocumentURL(params);
507 return ExtensionPatternMatch(item->document_url_patterns(), document_url);
510 void RenderViewContextMenu::AppendAllExtensionItems() {
511 extension_items_.Clear();
512 ExtensionService* service =
513 extensions::ExtensionSystem::Get(profile_)->extension_service();
515 return; // In unit-tests, we may not have an ExtensionService.
516 MenuManager* menu_manager = service->menu_manager();
518 string16 printable_selection_text = PrintableSelectionText();
519 EscapeAmpersands(&printable_selection_text);
521 // Get a list of extension id's that have context menu items, and sort by the
522 // top level context menu title of the extension.
523 std::set<std::string> ids = menu_manager->ExtensionIds();
524 std::vector<base::string16> sorted_menu_titles;
525 std::map<base::string16, std::string> map_ids;
526 for (std::set<std::string>::iterator i = ids.begin(); i != ids.end(); ++i) {
527 const Extension* extension = service->GetExtensionById(*i, false);
528 // Platform apps have their context menus created directly in
529 // AppendPlatformAppItems.
530 if (extension && !extension->is_platform_app()) {
531 base::string16 menu_title = extension_items_.GetTopLevelContextMenuTitle(
532 *i, printable_selection_text);
533 map_ids[menu_title] = *i;
534 sorted_menu_titles.push_back(menu_title);
537 if (sorted_menu_titles.empty())
540 const std::string app_locale = g_browser_process->GetApplicationLocale();
541 l10n_util::SortStrings16(app_locale, &sorted_menu_titles);
544 base::TimeTicks begin = base::TimeTicks::Now();
545 for (size_t i = 0; i < sorted_menu_titles.size(); ++i) {
546 const std::string& id = map_ids[sorted_menu_titles[i]];
547 extension_items_.AppendExtensionItems(id, printable_selection_text,
551 UMA_HISTOGRAM_TIMES("Extensions.ContextMenus_BuildTime",
552 base::TimeTicks::Now() - begin);
553 UMA_HISTOGRAM_COUNTS("Extensions.ContextMenus_ItemCount", index);
556 void RenderViewContextMenu::InitMenu() {
557 if (chrome::IsRunningInForcedAppMode()) {
558 AppendAppModeItems();
562 extensions::ViewType view_type =
563 extensions::GetViewType(source_web_contents_);
564 if (view_type == extensions::VIEW_TYPE_APP_SHELL) {
565 AppendPlatformAppItems();
567 } else if (view_type == extensions::VIEW_TYPE_EXTENSION_POPUP) {
568 AppendPopupExtensionItems();
570 } else if (view_type == extensions::VIEW_TYPE_PANEL) {
575 const bool has_link = !params_.unfiltered_link_url.is_empty();
576 const bool has_selection = !params_.selection_text.empty();
578 if (AppendCustomItems()) {
579 // If there's a selection, don't early return when there are custom items,
580 // but fall through to adding the normal ones after the custom ones.
582 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
584 // Don't add items for Pepper menu.
585 if (!params_.custom_context.is_pepper_menu)
586 AppendDeveloperItems();
591 // When no special node or text is selected and selection has no link,
593 if (params_.media_type == WebContextMenuData::MediaTypeNone &&
595 !params_.is_editable &&
598 if (!params_.page_url.is_empty()) {
599 bool is_devtools = IsDevToolsURL(params_.page_url);
600 if (!is_devtools && !IsInternalResourcesURL(params_.page_url)) {
602 // Merge in frame items if we clicked within a frame that needs them.
603 if (!params_.frame_url.is_empty()) {
604 is_devtools = IsDevToolsURL(params_.frame_url);
605 if (!is_devtools && !IsInternalResourcesURL(params_.frame_url)) {
606 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
612 DCHECK(params_.frame_url.is_empty());
616 // Do not show link related items for guest.
617 if (has_link && !is_guest_) {
619 if (params_.media_type != WebContextMenuData::MediaTypeNone)
620 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
623 switch (params_.media_type) {
624 case WebContextMenuData::MediaTypeNone:
626 case WebContextMenuData::MediaTypeImage:
629 case WebContextMenuData::MediaTypeVideo:
632 case WebContextMenuData::MediaTypeAudio:
635 case WebContextMenuData::MediaTypePlugin:
638 #ifdef WEBCONTEXT_MEDIATYPEFILE_DEFINED
639 case WebContextMenuData::MediaTypeFile:
644 if (params_.is_editable)
645 AppendEditableItems();
646 else if (has_selection)
649 if (!is_guest_ && has_selection) {
650 AppendSearchProvider();
651 if (!IsDevToolsURL(params_.page_url))
655 if (!IsDevToolsURL(params_.page_url) && !is_guest_)
656 AppendAllExtensionItems();
658 AppendDeveloperItems();
661 #if defined(ENABLE_FULL_PRINTING)
662 if (!print_preview_menu_observer_.get()) {
663 print_preview_menu_observer_.reset(
664 new PrintPreviewContextMenuObserver(source_web_contents_));
667 observers_.AddObserver(print_preview_menu_observer_.get());
672 const Extension* RenderViewContextMenu::GetExtension() const {
673 extensions::ExtensionSystem* system =
674 extensions::ExtensionSystem::Get(profile_);
675 // There is no process manager in some tests.
676 if (!system->process_manager())
679 return system->process_manager()->GetExtensionForRenderViewHost(
680 source_web_contents_->GetRenderViewHost());
683 void RenderViewContextMenu::AppendAppModeItems() {
684 const bool has_selection = !params_.selection_text.empty();
686 if (params_.is_editable)
687 AppendEditableItems();
688 else if (has_selection)
692 void RenderViewContextMenu::AppendPlatformAppItems() {
693 const Extension* platform_app = GetExtension();
695 // The RVH might be for a process sandboxed from the extension.
699 DCHECK(platform_app->is_platform_app());
701 const bool has_selection = !params_.selection_text.empty();
703 // Add undo/redo, cut/copy/paste etc for text fields.
704 if (params_.is_editable)
705 AppendEditableItems();
706 else if (has_selection)
710 extension_items_.AppendExtensionItems(platform_app->id(),
711 PrintableSelectionText(), &index);
713 // Add dev tools for unpacked extensions.
714 if (extensions::Manifest::IsUnpackedLocation(platform_app->location()) ||
715 CommandLine::ForCurrentProcess()->HasSwitch(
716 switches::kDebugPackedApps)) {
717 // Add a separator if there are any items already in the menu.
718 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
720 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP,
721 IDS_CONTENT_CONTEXT_RELOAD_PACKAGED_APP);
722 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP,
723 IDS_CONTENT_CONTEXT_RESTART_APP);
724 AppendDeveloperItems();
725 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE,
726 IDS_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE);
730 void RenderViewContextMenu::AppendPopupExtensionItems() {
731 const bool has_selection = !params_.selection_text.empty();
733 if (params_.is_editable)
734 AppendEditableItems();
735 else if (has_selection)
739 AppendSearchProvider();
741 AppendAllExtensionItems();
742 AppendDeveloperItems();
745 void RenderViewContextMenu::AppendPanelItems() {
746 bool has_selection = !params_.selection_text.empty();
748 // Checking link should take precedence before checking selection since on Mac
749 // right-clicking a link will also make it selected.
750 if (params_.unfiltered_link_url.is_valid())
753 if (params_.is_editable)
754 AppendEditableItems();
755 else if (has_selection)
758 // Avoid appending extension related items when |extension| is null. This
759 // happens when the panel is navigated to a url outside of the extension's
761 const Extension* extension = GetExtension();
763 // Only add extension items from this extension.
765 extension_items_.AppendExtensionItems(extension->id(),
766 PrintableSelectionText(), &index);
770 void RenderViewContextMenu::AddMenuItem(int command_id,
771 const string16& title) {
772 menu_model_.AddItem(command_id, title);
775 void RenderViewContextMenu::AddCheckItem(int command_id,
776 const string16& title) {
777 menu_model_.AddCheckItem(command_id, title);
780 void RenderViewContextMenu::AddSeparator() {
781 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
784 void RenderViewContextMenu::AddSubMenu(int command_id,
785 const string16& label,
786 ui::MenuModel* model) {
787 menu_model_.AddSubMenu(command_id, label, model);
790 void RenderViewContextMenu::UpdateMenuItem(int command_id,
793 const string16& label) {
794 // This function needs platform-specific implementation.
798 RenderViewHost* RenderViewContextMenu::GetRenderViewHost() const {
799 return source_web_contents_->GetRenderViewHost();
802 WebContents* RenderViewContextMenu::GetWebContents() const {
803 return source_web_contents_;
806 Profile* RenderViewContextMenu::GetProfile() const {
810 bool RenderViewContextMenu::AppendCustomItems() {
811 size_t total_items = 0;
812 AddCustomItemsToMenu(params_.custom_items, 0, &total_items, this,
814 return total_items > 0;
817 void RenderViewContextMenu::AppendDeveloperItems() {
818 // Show Inspect Element in DevTools itself only in case of the debug
820 bool show_developer_items = !IsDevToolsURL(params_.page_url);
822 #if defined(DEBUG_DEVTOOLS)
823 show_developer_items = true;
826 if (!show_developer_items)
829 // In the DevTools popup menu, "developer items" is normally the only
830 // section, so omit the separator there.
831 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
832 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTELEMENT,
833 IDS_CONTENT_CONTEXT_INSPECTELEMENT);
836 void RenderViewContextMenu::AppendLinkItems() {
837 if (!params_.link_url.is_empty()) {
838 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB,
839 IDS_CONTENT_CONTEXT_OPENLINKNEWTAB);
840 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW,
841 IDS_CONTENT_CONTEXT_OPENLINKNEWWINDOW);
842 if (params_.link_url.is_valid()) {
843 AppendProtocolHandlerSubMenu();
847 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD,
848 IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD);
850 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVELINKAS,
851 IDS_CONTENT_CONTEXT_SAVELINKAS);
854 menu_model_.AddItemWithStringId(
855 IDC_CONTENT_CONTEXT_COPYLINKLOCATION,
856 params_.link_url.SchemeIs(content::kMailToScheme) ?
857 IDS_CONTENT_CONTEXT_COPYEMAILADDRESS :
858 IDS_CONTENT_CONTEXT_COPYLINKLOCATION);
861 void RenderViewContextMenu::AppendImageItems() {
862 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS,
863 IDS_CONTENT_CONTEXT_SAVEIMAGEAS);
864 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGELOCATION,
865 IDS_CONTENT_CONTEXT_COPYIMAGELOCATION);
866 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
867 IDS_CONTENT_CONTEXT_COPYIMAGE);
868 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB,
869 IDS_CONTENT_CONTEXT_OPENIMAGENEWTAB);
870 const TemplateURL* const default_provider =
871 TemplateURLServiceFactory::GetForProfile(profile_)->
872 GetDefaultSearchProvider();
873 if (params_.has_image_contents && default_provider &&
874 !default_provider->image_url().empty() &&
875 default_provider->image_url_ref().IsValid()) {
877 IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE,
878 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFORIMAGE,
879 default_provider->short_name()));
884 void RenderViewContextMenu::AppendAudioItems() {
886 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
887 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
888 IDS_CONTENT_CONTEXT_SAVEAUDIOAS);
889 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
890 IDS_CONTENT_CONTEXT_COPYAUDIOLOCATION);
891 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
892 IDS_CONTENT_CONTEXT_OPENAUDIONEWTAB);
895 void RenderViewContextMenu::AppendVideoItems() {
897 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
898 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
899 IDS_CONTENT_CONTEXT_SAVEVIDEOAS);
900 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
901 IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION);
902 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
903 IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB);
906 void RenderViewContextMenu::AppendMediaItems() {
907 int media_flags = params_.media_flags;
909 menu_model_.AddItemWithStringId(
910 IDC_CONTENT_CONTEXT_PLAYPAUSE,
911 media_flags & WebContextMenuData::MediaPaused ?
912 IDS_CONTENT_CONTEXT_PLAY :
913 IDS_CONTENT_CONTEXT_PAUSE);
915 menu_model_.AddItemWithStringId(
916 IDC_CONTENT_CONTEXT_MUTE,
917 media_flags & WebContextMenuData::MediaMuted ?
918 IDS_CONTENT_CONTEXT_UNMUTE :
919 IDS_CONTENT_CONTEXT_MUTE);
921 menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_LOOP,
922 IDS_CONTENT_CONTEXT_LOOP);
923 menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_CONTROLS,
924 IDS_CONTENT_CONTEXT_CONTROLS);
927 void RenderViewContextMenu::AppendPluginItems() {
928 if (params_.page_url == params_.src_url) {
929 // Full page plugin, so show page menu items.
930 if (params_.link_url.is_empty() && params_.selection_text.empty())
933 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
934 IDS_CONTENT_CONTEXT_SAVEPAGEAS);
935 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
938 if (params_.media_flags & WebContextMenuData::MediaCanRotate) {
939 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
940 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECW,
941 IDS_CONTENT_CONTEXT_ROTATECW);
942 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECCW,
943 IDS_CONTENT_CONTEXT_ROTATECCW);
947 void RenderViewContextMenu::AppendPageItems() {
948 menu_model_.AddItemWithStringId(IDC_BACK, IDS_CONTENT_CONTEXT_BACK);
949 menu_model_.AddItemWithStringId(IDC_FORWARD, IDS_CONTENT_CONTEXT_FORWARD);
950 menu_model_.AddItemWithStringId(IDC_RELOAD, IDS_CONTENT_CONTEXT_RELOAD);
951 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
952 menu_model_.AddItemWithStringId(IDC_SAVE_PAGE,
953 IDS_CONTENT_CONTEXT_SAVEPAGEAS);
954 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
956 if (TranslateManager::IsTranslatableURL(params_.page_url)) {
957 std::string locale = g_browser_process->GetApplicationLocale();
958 locale = TranslateManager::GetLanguageCode(locale);
959 string16 language = l10n_util::GetDisplayNameForLocale(locale, locale,
962 IDC_CONTENT_CONTEXT_TRANSLATE,
963 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_TRANSLATE, language));
966 menu_model_.AddItemWithStringId(IDC_VIEW_SOURCE,
967 IDS_CONTENT_CONTEXT_VIEWPAGESOURCE);
968 // Only add View Page Info if there's a browser. This is a temporary thing
969 // while View Page Info crashes Chrome Frame; see http://crbug.com/120901.
970 // TODO(grt) Remove this once page info is back for Chrome Frame.
972 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWPAGEINFO,
973 IDS_CONTENT_CONTEXT_VIEWPAGEINFO);
977 void RenderViewContextMenu::AppendFrameItems() {
978 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOADFRAME,
979 IDS_CONTENT_CONTEXT_RELOADFRAME);
980 // These two menu items have yet to be implemented.
981 // http://code.google.com/p/chromium/issues/detail?id=11827
982 // IDS_CONTENT_CONTEXT_SAVEFRAMEAS
983 // IDS_CONTENT_CONTEXT_PRINTFRAME
984 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE,
985 IDS_CONTENT_CONTEXT_VIEWFRAMESOURCE);
986 // Only add View Frame Info if there's a browser. This is a temporary thing
987 // while View Frame Info crashes Chrome Frame; see http://crbug.com/120901.
988 // TODO(grt) Remove this once frame info is back for Chrome Frame.
990 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMEINFO,
991 IDS_CONTENT_CONTEXT_VIEWFRAMEINFO);
995 void RenderViewContextMenu::AppendCopyItem() {
996 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
997 IDS_CONTENT_CONTEXT_COPY);
1000 void RenderViewContextMenu::AppendPrintItem() {
1001 if (profile_->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) &&
1002 (params_.media_type == WebContextMenuData::MediaTypeNone ||
1003 params_.media_flags & WebContextMenuData::MediaCanPrint)) {
1004 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
1008 void RenderViewContextMenu::AppendSearchProvider() {
1011 TrimWhitespace(params_.selection_text, TRIM_ALL, ¶ms_.selection_text);
1012 if (params_.selection_text.empty())
1015 ReplaceChars(params_.selection_text, AutocompleteMatch::kInvalidChars,
1016 ASCIIToUTF16(" "), ¶ms_.selection_text);
1018 AutocompleteMatch match;
1019 AutocompleteClassifierFactory::GetForProfile(profile_)->Classify(
1020 params_.selection_text, false, false, &match, NULL);
1021 selection_navigation_url_ = match.destination_url;
1022 if (!selection_navigation_url_.is_valid())
1025 string16 printable_selection_text = PrintableSelectionText();
1026 EscapeAmpersands(&printable_selection_text);
1028 if (AutocompleteMatch::IsSearchType(match.type)) {
1029 const TemplateURL* const default_provider =
1030 TemplateURLServiceFactory::GetForProfile(profile_)->
1031 GetDefaultSearchProvider();
1032 if (!default_provider)
1034 menu_model_.AddItem(
1035 IDC_CONTENT_CONTEXT_SEARCHWEBFOR,
1036 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFOR,
1037 default_provider->short_name(),
1038 printable_selection_text));
1040 if ((selection_navigation_url_ != params_.link_url) &&
1041 ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme(
1042 selection_navigation_url_.scheme())) {
1043 menu_model_.AddItem(
1044 IDC_CONTENT_CONTEXT_GOTOURL,
1045 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_GOTOURL,
1046 printable_selection_text));
1051 void RenderViewContextMenu::AppendEditableItems() {
1052 const bool use_spellcheck_and_search = !chrome::IsRunningInForcedAppMode();
1054 if (use_spellcheck_and_search)
1055 AppendSpellingSuggestionsSubMenu();
1057 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_UNDO,
1058 IDS_CONTENT_CONTEXT_UNDO);
1059 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_REDO,
1060 IDS_CONTENT_CONTEXT_REDO);
1061 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1062 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_CUT,
1063 IDS_CONTENT_CONTEXT_CUT);
1064 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
1065 IDS_CONTENT_CONTEXT_COPY);
1066 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE,
1067 IDS_CONTENT_CONTEXT_PASTE);
1068 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE,
1069 IDS_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE);
1070 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_DELETE,
1071 IDS_CONTENT_CONTEXT_DELETE);
1072 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1074 if (use_spellcheck_and_search && !params_.keyword_url.is_empty()) {
1075 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ADDSEARCHENGINE,
1076 IDS_CONTENT_CONTEXT_ADDSEARCHENGINE);
1077 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1080 if (use_spellcheck_and_search)
1081 AppendSpellcheckOptionsSubMenu();
1082 AppendSpeechInputOptionsSubMenu();
1083 AppendPlatformEditableItems();
1085 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1086 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SELECTALL,
1087 IDS_CONTENT_CONTEXT_SELECTALL);
1090 void RenderViewContextMenu::AppendSpellingSuggestionsSubMenu() {
1091 if (!spelling_menu_observer_.get())
1092 spelling_menu_observer_.reset(new SpellingMenuObserver(this));
1093 observers_.AddObserver(spelling_menu_observer_.get());
1094 spelling_menu_observer_->InitMenu(params_);
1097 void RenderViewContextMenu::AppendSpellcheckOptionsSubMenu() {
1098 if (!spellchecker_submenu_observer_.get()) {
1099 spellchecker_submenu_observer_.reset(new SpellCheckerSubMenuObserver(
1100 this, this, kSpellcheckRadioGroup));
1102 spellchecker_submenu_observer_->InitMenu(params_);
1103 observers_.AddObserver(spellchecker_submenu_observer_.get());
1106 void RenderViewContextMenu::AppendSpeechInputOptionsSubMenu() {
1107 if (params_.speech_input_enabled) {
1108 speech_input_submenu_model_.AddCheckItem(
1109 IDC_CONTENT_CONTEXT_SPEECH_INPUT_FILTER_PROFANITIES,
1110 l10n_util::GetStringUTF16(
1111 IDS_CONTENT_CONTEXT_SPEECH_INPUT_FILTER_PROFANITIES));
1113 speech_input_submenu_model_.AddItemWithStringId(
1114 IDC_CONTENT_CONTEXT_SPEECH_INPUT_ABOUT,
1115 IDS_CONTENT_CONTEXT_SPEECH_INPUT_ABOUT);
1117 menu_model_.AddSubMenu(
1118 IDC_SPEECH_INPUT_MENU,
1119 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_SPEECH_INPUT_MENU),
1120 &speech_input_submenu_model_);
1124 void RenderViewContextMenu::AppendProtocolHandlerSubMenu() {
1125 const ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1126 GetHandlersForLinkUrl();
1127 if (handlers.empty())
1129 size_t max = IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST -
1130 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
1131 for (size_t i = 0; i < handlers.size() && i <= max; i++) {
1132 protocol_handler_submenu_model_.AddItem(
1133 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST + i,
1134 handlers[i].title());
1136 protocol_handler_submenu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1137 protocol_handler_submenu_model_.AddItem(
1138 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS,
1139 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH_CONFIGURE));
1141 menu_model_.AddSubMenu(
1142 IDC_CONTENT_CONTEXT_OPENLINKWITH,
1143 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH),
1144 &protocol_handler_submenu_model_);
1147 void RenderViewContextMenu::AppendPlatformEditableItems() {
1150 // Menu delegate functions -----------------------------------------------------
1152 bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
1153 // If this command is is added by one of our observers, we dispatch it to the
1155 ObserverListBase<RenderViewContextMenuObserver>::Iterator it(observers_);
1156 RenderViewContextMenuObserver* observer;
1157 while ((observer = it.GetNext()) != NULL) {
1158 if (observer->IsCommandIdSupported(id))
1159 return observer->IsCommandIdEnabled(id);
1162 CoreTabHelper* core_tab_helper =
1163 CoreTabHelper::FromWebContents(source_web_contents_);
1164 int content_restrictions = 0;
1165 if (core_tab_helper)
1166 content_restrictions = core_tab_helper->content_restrictions();
1167 if (id == IDC_PRINT && (content_restrictions & CONTENT_RESTRICTION_PRINT))
1170 if (id == IDC_SAVE_PAGE &&
1171 (content_restrictions & CONTENT_RESTRICTION_SAVE)) {
1175 // Allow Spell Check language items on sub menu for text area context menu.
1176 if ((id >= IDC_SPELLCHECK_LANGUAGES_FIRST) &&
1177 (id < IDC_SPELLCHECK_LANGUAGES_LAST)) {
1178 return profile_->GetPrefs()->GetBoolean(prefs::kEnableContinuousSpellcheck);
1182 if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
1183 id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) {
1184 return IsCustomItemEnabled(params_.custom_items, id);
1188 if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
1189 id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
1190 return extension_items_.IsCommandIdEnabled(id);
1193 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
1194 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
1198 IncognitoModePrefs::Availability incognito_avail =
1199 IncognitoModePrefs::GetAvailability(profile_->GetPrefs());
1202 return source_web_contents_->GetController().CanGoBack();
1205 return source_web_contents_->GetController().CanGoForward();
1208 CoreTabHelper* core_tab_helper =
1209 CoreTabHelper::FromWebContents(source_web_contents_);
1210 if (!core_tab_helper)
1213 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
1214 return !core_delegate ||
1215 core_delegate->CanReloadContents(source_web_contents_);
1218 case IDC_VIEW_SOURCE:
1219 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
1220 return source_web_contents_->GetController().CanViewSource();
1222 case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
1223 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE:
1224 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP:
1225 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP:
1226 return IsDevCommandEnabled(id);
1228 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO:
1229 if (source_web_contents_->GetController().GetActiveEntry() == NULL)
1231 // Disabled if no browser is associated (e.g. desktop notifications).
1232 if (chrome::FindBrowserWithWebContents(source_web_contents_) == NULL)
1236 case IDC_CONTENT_CONTEXT_TRANSLATE: {
1237 TranslateTabHelper* translate_tab_helper =
1238 TranslateTabHelper::FromWebContents(source_web_contents_);
1239 if (!translate_tab_helper)
1241 std::string original_lang =
1242 translate_tab_helper->language_state().original_language();
1243 std::string target_lang = g_browser_process->GetApplicationLocale();
1244 target_lang = TranslateManager::GetLanguageCode(target_lang);
1245 // Note that we intentionally enable the menu even if the original and
1246 // target languages are identical. This is to give a way to user to
1247 // translate a page that might contains text fragments in a different
1249 return ((params_.edit_flags & WebContextMenuData::CanTranslate) != 0) &&
1250 !original_lang.empty() && // Did we receive the page language yet?
1251 !translate_tab_helper->language_state().IsPageTranslated() &&
1252 !source_web_contents_->GetInterstitialPage() &&
1253 // There are some application locales which can't be used as a
1254 // target language for translation.
1255 TranslateManager::IsSupportedLanguage(target_lang) &&
1256 // Disable on the Instant Extended NTP.
1257 !chrome::IsInstantNTP(source_web_contents_);
1260 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB:
1261 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
1262 return params_.link_url.is_valid();
1264 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
1265 return params_.unfiltered_link_url.is_valid();
1267 case IDC_CONTENT_CONTEXT_SAVELINKAS: {
1268 PrefService* local_state = g_browser_process->local_state();
1269 DCHECK(local_state);
1270 // Test if file-selection dialogs are forbidden by policy.
1271 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1274 return params_.link_url.is_valid() &&
1275 ProfileIOData::IsHandledProtocol(params_.link_url.scheme());
1278 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: {
1279 PrefService* local_state = g_browser_process->local_state();
1280 DCHECK(local_state);
1281 // Test if file-selection dialogs are forbidden by policy.
1282 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1285 return params_.src_url.is_valid() &&
1286 ProfileIOData::IsHandledProtocol(params_.src_url.scheme());
1289 // The images shown in the most visited thumbnails can't be opened or
1290 // searched for conventionally.
1291 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
1292 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
1293 return params_.src_url.is_valid() &&
1294 (params_.src_url.scheme() != chrome::kChromeUIScheme);
1296 case IDC_CONTENT_CONTEXT_COPYIMAGE:
1297 return params_.has_image_contents;
1299 // Media control commands should all be disabled if the player is in an
1301 case IDC_CONTENT_CONTEXT_PLAYPAUSE:
1302 case IDC_CONTENT_CONTEXT_LOOP:
1303 return (params_.media_flags &
1304 WebContextMenuData::MediaInError) == 0;
1306 // Mute and unmute should also be disabled if the player has no audio.
1307 case IDC_CONTENT_CONTEXT_MUTE:
1308 return (params_.media_flags &
1309 WebContextMenuData::MediaHasAudio) != 0 &&
1310 (params_.media_flags &
1311 WebContextMenuData::MediaInError) == 0;
1313 // Media controls can be toggled only for video player. If we toggle
1314 // controls for audio then the player disappears, and there is no way to
1316 case IDC_CONTENT_CONTEXT_CONTROLS:
1317 return (params_.media_flags &
1318 WebContextMenuData::MediaHasVideo) != 0;
1320 case IDC_CONTENT_CONTEXT_ROTATECW:
1321 case IDC_CONTENT_CONTEXT_ROTATECCW:
1323 (params_.media_flags & WebContextMenuData::MediaCanRotate) != 0;
1325 case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
1326 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
1327 return params_.src_url.is_valid();
1329 case IDC_CONTENT_CONTEXT_SAVEAVAS: {
1330 PrefService* local_state = g_browser_process->local_state();
1331 DCHECK(local_state);
1332 // Test if file-selection dialogs are forbidden by policy.
1333 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1336 const GURL& url = params_.src_url;
1338 (params_.media_flags & WebContextMenuData::MediaCanSave) &&
1339 url.is_valid() && ProfileIOData::IsHandledProtocol(url.scheme());
1340 #if defined(ENABLE_FULL_PRINTING)
1341 // Do not save the preview PDF on the print preview page.
1342 can_save = can_save &&
1343 !(printing::PrintPreviewDialogController::IsPrintPreviewURL(url));
1348 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
1351 case IDC_SAVE_PAGE: {
1352 CoreTabHelper* core_tab_helper =
1353 CoreTabHelper::FromWebContents(source_web_contents_);
1354 if (!core_tab_helper)
1357 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
1358 if (core_delegate &&
1359 !core_delegate->CanSaveContents(source_web_contents_))
1362 PrefService* local_state = g_browser_process->local_state();
1363 DCHECK(local_state);
1364 // Test if file-selection dialogs are forbidden by policy.
1365 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1368 // Instead of using GetURL here, we use url() (which is the "real" url of
1369 // the page) from the NavigationEntry because its reflects their origin
1370 // rather than the display one (returned by GetURL) which may be
1371 // different (like having "view-source:" on the front).
1372 // TODO(nasko): Audit all GetActiveEntry calls in this file.
1373 NavigationEntry* active_entry =
1374 source_web_contents_->GetController().GetActiveEntry();
1375 return content::IsSavableURL(
1376 (active_entry) ? active_entry->GetURL() : GURL());
1379 case IDC_CONTENT_CONTEXT_RELOADFRAME:
1380 return params_.frame_url.is_valid();
1382 case IDC_CONTENT_CONTEXT_UNDO:
1383 return !!(params_.edit_flags & WebContextMenuData::CanUndo);
1385 case IDC_CONTENT_CONTEXT_REDO:
1386 return !!(params_.edit_flags & WebContextMenuData::CanRedo);
1388 case IDC_CONTENT_CONTEXT_CUT:
1389 return !!(params_.edit_flags & WebContextMenuData::CanCut);
1391 case IDC_CONTENT_CONTEXT_COPY:
1392 return !!(params_.edit_flags & WebContextMenuData::CanCopy);
1394 case IDC_CONTENT_CONTEXT_PASTE:
1395 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE:
1396 return !!(params_.edit_flags & WebContextMenuData::CanPaste);
1398 case IDC_CONTENT_CONTEXT_DELETE:
1399 return !!(params_.edit_flags & WebContextMenuData::CanDelete);
1401 case IDC_CONTENT_CONTEXT_SELECTALL:
1402 return !!(params_.edit_flags & WebContextMenuData::CanSelectAll);
1404 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
1405 return !profile_->IsOffTheRecord() && params_.link_url.is_valid() &&
1406 incognito_avail != IncognitoModePrefs::DISABLED;
1409 return profile_->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) &&
1410 (params_.media_type == WebContextMenuData::MediaTypeNone ||
1411 params_.media_flags & WebContextMenuData::MediaCanPrint);
1413 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
1414 case IDC_CONTENT_CONTEXT_GOTOURL:
1415 case IDC_SPELLPANEL_TOGGLE:
1416 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS:
1418 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO:
1419 // Disabled if no browser is associated (e.g. desktop notifications).
1420 if (chrome::FindBrowserWithWebContents(source_web_contents_) == NULL)
1424 case IDC_CHECK_SPELLING_WHILE_TYPING:
1425 return profile_->GetPrefs()->GetBoolean(
1426 prefs::kEnableContinuousSpellcheck);
1428 #if !defined(OS_MACOSX) && defined(OS_POSIX)
1429 // TODO(suzhe): this should not be enabled for password fields.
1430 case IDC_INPUT_METHODS_MENU:
1434 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE:
1435 return !params_.keyword_url.is_empty();
1437 case IDC_SPELLCHECK_MENU:
1440 case IDC_CONTENT_CONTEXT_SPEECH_INPUT_FILTER_PROFANITIES:
1441 case IDC_CONTENT_CONTEXT_SPEECH_INPUT_ABOUT:
1442 case IDC_SPEECH_INPUT_MENU:
1445 case IDC_CONTENT_CONTEXT_OPENLINKWITH:
1448 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS:
1457 bool RenderViewContextMenu::IsCommandIdChecked(int id) const {
1458 // If this command is is added by one of our observers, we dispatch it to the
1460 ObserverListBase<RenderViewContextMenuObserver>::Iterator it(observers_);
1461 RenderViewContextMenuObserver* observer;
1462 while ((observer = it.GetNext()) != NULL) {
1463 if (observer->IsCommandIdSupported(id))
1464 return observer->IsCommandIdChecked(id);
1467 // See if the video is set to looping.
1468 if (id == IDC_CONTENT_CONTEXT_LOOP) {
1469 return (params_.media_flags &
1470 WebContextMenuData::MediaLoop) != 0;
1473 if (id == IDC_CONTENT_CONTEXT_CONTROLS) {
1474 return (params_.media_flags &
1475 WebContextMenuData::MediaControls) != 0;
1479 if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
1480 id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) {
1481 return IsCustomItemChecked(params_.custom_items, id);
1485 if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
1486 id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
1487 return extension_items_.IsCommandIdChecked(id);
1490 #if defined(ENABLE_INPUT_SPEECH)
1491 // Check box for menu item 'Block offensive words'.
1492 if (id == IDC_CONTENT_CONTEXT_SPEECH_INPUT_FILTER_PROFANITIES) {
1493 return profile_->GetPrefs()->GetBoolean(
1494 prefs::kSpeechRecognitionFilterProfanities);
1501 void RenderViewContextMenu::ExecuteCommand(int id, int event_flags) {
1502 command_executed_ = true;
1503 // If this command is is added by one of our observers, we dispatch it to the
1505 ObserverListBase<RenderViewContextMenuObserver>::Iterator it(observers_);
1506 RenderViewContextMenuObserver* observer;
1507 while ((observer = it.GetNext()) != NULL) {
1508 if (observer->IsCommandIdSupported(id))
1509 return observer->ExecuteCommand(id);
1514 RenderViewHost* rvh = source_web_contents_->GetRenderViewHost();
1516 // Process custom actions range.
1517 if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
1518 id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) {
1519 unsigned action = id - IDC_CONTENT_CONTEXT_CUSTOM_FIRST;
1520 const content::CustomContextMenuContext& context = params_.custom_context;
1521 #if defined(ENABLE_PLUGINS)
1522 if (context.request_id && !context.is_pepper_menu) {
1523 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins(
1524 rvh->GetProcess()->GetID());
1527 rvh->ExecuteCustomContextMenuCommand(action, context);
1531 // Process extension menu items.
1532 if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
1533 id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
1534 extension_items_.ExecuteCommand(id, source_web_contents_, params_);
1538 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
1539 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
1540 ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1541 GetHandlersForLinkUrl();
1542 if (handlers.empty()) {
1545 content::RecordAction(
1546 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Open"));
1547 int handlerIndex = id - IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
1548 WindowOpenDisposition disposition =
1549 ForceNewTabDispositionFromEventFlags(event_flags);
1551 handlers[handlerIndex].TranslateUrl(params_.link_url),
1552 params_.frame_url.is_empty() ? params_.page_url : params_.frame_url,
1555 content::PAGE_TRANSITION_LINK);
1560 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB: {
1562 chrome::FindBrowserWithWebContents(source_web_contents_);
1565 params_.frame_url.is_empty() ? params_.page_url : params_.frame_url,
1567 !browser || browser->is_app() ?
1568 NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB,
1569 content::PAGE_TRANSITION_LINK);
1572 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
1575 params_.frame_url.is_empty() ? params_.page_url : params_.frame_url,
1577 NEW_WINDOW, content::PAGE_TRANSITION_LINK);
1580 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
1581 OpenURL(params_.link_url,
1585 content::PAGE_TRANSITION_LINK);
1588 case IDC_CONTENT_CONTEXT_SAVELINKAS: {
1589 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
1590 const GURL& referrer =
1591 params_.frame_url.is_empty() ? params_.page_url : params_.frame_url;
1592 const GURL& url = params_.link_url;
1593 DownloadManager* dlm = BrowserContext::GetDownloadManager(profile_);
1594 scoped_ptr<DownloadUrlParameters> dl_params(
1595 DownloadUrlParameters::FromWebContents(source_web_contents_, url));
1596 dl_params->set_referrer(
1597 content::Referrer(referrer, params_.referrer_policy));
1598 dl_params->set_referrer_encoding(params_.frame_charset);
1599 dl_params->set_prompt(true);
1600 dlm->DownloadUrl(dl_params.Pass());
1604 case IDC_CONTENT_CONTEXT_SAVEAVAS:
1605 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: {
1606 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
1607 const GURL& referrer =
1608 params_.frame_url.is_empty() ? params_.page_url : params_.frame_url;
1609 const GURL& url = params_.src_url;
1611 if (url == source_web_contents_->GetURL()) {
1612 const NavigationEntry* entry =
1613 source_web_contents_->GetController().GetActiveEntry();
1615 post_id = entry->GetPostID();
1617 DownloadManager* dlm = BrowserContext::GetDownloadManager(profile_);
1618 scoped_ptr<DownloadUrlParameters> dl_params(
1619 DownloadUrlParameters::FromWebContents(source_web_contents_, url));
1620 dl_params->set_referrer(
1621 content::Referrer(referrer, params_.referrer_policy));
1622 dl_params->set_post_id(post_id);
1623 dl_params->set_prefer_cache(true);
1625 dl_params->set_method("POST");
1626 dl_params->set_prompt(true);
1627 dlm->DownloadUrl(dl_params.Pass());
1631 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
1632 WriteURLToClipboard(params_.unfiltered_link_url);
1635 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
1636 case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
1637 WriteURLToClipboard(params_.src_url);
1640 case IDC_CONTENT_CONTEXT_COPYIMAGE:
1641 CopyImageAt(params_.x, params_.y);
1644 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
1645 GetImageThumbnailForSearch();
1648 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
1649 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
1652 params_.frame_url.is_empty() ? params_.page_url : params_.frame_url,
1654 NEW_BACKGROUND_TAB, content::PAGE_TRANSITION_LINK);
1657 case IDC_CONTENT_CONTEXT_PLAYPAUSE: {
1658 bool play = !!(params_.media_flags & WebContextMenuData::MediaPaused);
1660 content::RecordAction(UserMetricsAction("MediaContextMenu_Play"));
1662 content::RecordAction(UserMetricsAction("MediaContextMenu_Pause"));
1664 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1665 WebMediaPlayerAction(
1666 WebMediaPlayerAction::Play, play));
1670 case IDC_CONTENT_CONTEXT_MUTE: {
1671 bool mute = !(params_.media_flags & WebContextMenuData::MediaMuted);
1673 content::RecordAction(UserMetricsAction("MediaContextMenu_Mute"));
1675 content::RecordAction(UserMetricsAction("MediaContextMenu_Unmute"));
1677 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1678 WebMediaPlayerAction(
1679 WebMediaPlayerAction::Mute, mute));
1683 case IDC_CONTENT_CONTEXT_LOOP:
1684 content::RecordAction(UserMetricsAction("MediaContextMenu_Loop"));
1685 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1686 WebMediaPlayerAction(
1687 WebMediaPlayerAction::Loop,
1688 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_LOOP)));
1691 case IDC_CONTENT_CONTEXT_CONTROLS:
1692 content::RecordAction(UserMetricsAction("MediaContextMenu_Controls"));
1693 MediaPlayerActionAt(
1694 gfx::Point(params_.x, params_.y),
1695 WebMediaPlayerAction(
1696 WebMediaPlayerAction::Controls,
1697 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_CONTROLS)));
1700 case IDC_CONTENT_CONTEXT_ROTATECW:
1701 content::RecordAction(
1702 UserMetricsAction("PluginContextMenu_RotateClockwise"));
1704 gfx::Point(params_.x, params_.y),
1706 WebPluginAction::Rotate90Clockwise,
1710 case IDC_CONTENT_CONTEXT_ROTATECCW:
1711 content::RecordAction(
1712 UserMetricsAction("PluginContextMenu_RotateCounterclockwise"));
1714 gfx::Point(params_.x, params_.y),
1716 WebPluginAction::Rotate90Counterclockwise,
1721 source_web_contents_->GetController().GoBack();
1725 source_web_contents_->GetController().GoForward();
1729 source_web_contents_->OnSavePage();
1733 // Prevent the modal "Resubmit form post" dialog from appearing in the
1734 // context of an external context menu.
1735 source_web_contents_->GetController().Reload(!external_);
1738 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP: {
1739 const Extension* platform_app = GetExtension();
1740 DCHECK(platform_app);
1741 DCHECK(platform_app->is_platform_app());
1743 extensions::ExtensionSystem::Get(profile_)->extension_service()->
1744 ReloadExtension(platform_app->id());
1748 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP: {
1749 const Extension* platform_app = GetExtension();
1750 DCHECK(platform_app);
1751 DCHECK(platform_app->is_platform_app());
1753 apps::AppLoadService::Get(profile_)->RestartApplication(
1754 platform_app->id());
1759 #if defined(ENABLE_PRINTING)
1760 if (params_.media_type == WebContextMenuData::MediaTypeNone) {
1761 #if defined(ENABLE_FULL_PRINTING)
1762 printing::PrintViewManager* print_view_manager =
1763 printing::PrintViewManager::FromWebContents(source_web_contents_);
1765 if (!print_view_manager)
1767 if (profile_->GetPrefs()->GetBoolean(prefs::kPrintPreviewDisabled)) {
1768 print_view_manager->PrintNow();
1770 print_view_manager->PrintPreviewNow(!params_.selection_text.empty());
1773 printing::PrintViewManagerBasic* print_view_manager =
1774 printing::PrintViewManagerBasic::FromWebContents(
1775 source_web_contents_);
1776 if (!print_view_manager)
1778 print_view_manager->PrintNow();
1779 #endif // defined(ENABLE_FULL_PRINTING)
1781 rvh->Send(new PrintMsg_PrintNodeUnderContextMenu(rvh->GetRoutingID()));
1783 #endif // defined(ENABLE_PRINTING)
1786 case IDC_VIEW_SOURCE:
1787 source_web_contents_->ViewSource();
1790 case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
1791 Inspect(params_.x, params_.y);
1794 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE: {
1795 const Extension* platform_app = GetExtension();
1796 DCHECK(platform_app);
1797 DCHECK(platform_app->is_platform_app());
1799 extensions::devtools_util::InspectBackgroundPage(platform_app, profile_);
1803 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO: {
1804 NavigationController* controller = &source_web_contents_->GetController();
1805 // Important to use GetVisibleEntry to match what's showing in the
1807 NavigationEntry* nav_entry = controller->GetVisibleEntry();
1809 chrome::FindBrowserWithWebContents(source_web_contents_);
1810 chrome::ShowWebsiteSettings(browser, source_web_contents_,
1811 nav_entry->GetURL(), nav_entry->GetSSL());
1815 case IDC_CONTENT_CONTEXT_TRANSLATE: {
1816 // A translation might have been triggered by the time the menu got
1817 // selected, do nothing in that case.
1818 TranslateTabHelper* translate_tab_helper =
1819 TranslateTabHelper::FromWebContents(source_web_contents_);
1820 if (!translate_tab_helper ||
1821 translate_tab_helper->language_state().IsPageTranslated() ||
1822 translate_tab_helper->language_state().translation_pending()) {
1825 std::string original_lang =
1826 translate_tab_helper->language_state().original_language();
1827 std::string target_lang = g_browser_process->GetApplicationLocale();
1828 target_lang = TranslateManager::GetLanguageCode(target_lang);
1829 // Since the user decided to translate for that language and site, clears
1830 // any preferences for not translating them.
1831 TranslatePrefs prefs(profile_->GetPrefs());
1832 prefs.UnblockLanguage(original_lang);
1833 prefs.RemoveSiteFromBlacklist(params_.page_url.HostNoBrackets());
1834 TranslateManager::GetInstance()->TranslatePage(
1835 source_web_contents_, original_lang, target_lang);
1839 case IDC_CONTENT_CONTEXT_RELOADFRAME:
1843 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
1844 source_web_contents_->ViewFrameSource(params_.frame_url,
1845 params_.frame_page_state);
1848 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO: {
1849 Browser* browser = chrome::FindBrowserWithWebContents(
1850 source_web_contents_);
1851 chrome::ShowWebsiteSettings(browser, source_web_contents_,
1852 params_.frame_url, params_.security_info);
1856 case IDC_CONTENT_CONTEXT_UNDO:
1860 case IDC_CONTENT_CONTEXT_REDO:
1864 case IDC_CONTENT_CONTEXT_CUT:
1868 case IDC_CONTENT_CONTEXT_COPY:
1872 case IDC_CONTENT_CONTEXT_PASTE:
1876 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE:
1877 rvh->PasteAndMatchStyle();
1880 case IDC_CONTENT_CONTEXT_DELETE:
1884 case IDC_CONTENT_CONTEXT_SELECTALL:
1888 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
1889 case IDC_CONTENT_CONTEXT_GOTOURL: {
1890 WindowOpenDisposition disposition =
1891 ForceNewTabDispositionFromEventFlags(event_flags);
1892 OpenURL(selection_navigation_url_,
1896 content::PAGE_TRANSITION_LINK);
1899 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS: {
1900 WindowOpenDisposition disposition =
1901 ForceNewTabDispositionFromEventFlags(event_flags);
1902 std::string url = std::string(chrome::kChromeUISettingsURL) +
1903 chrome::kLanguageOptionsSubPage;
1904 OpenURL(GURL(url), GURL(), 0, disposition, content::PAGE_TRANSITION_LINK);
1908 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS: {
1909 content::RecordAction(
1910 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Settings"));
1911 WindowOpenDisposition disposition =
1912 ForceNewTabDispositionFromEventFlags(event_flags);
1913 std::string url = std::string(chrome::kChromeUISettingsURL) +
1914 chrome::kHandlerSettingsSubPage;
1915 OpenURL(GURL(url), GURL(), 0, disposition, content::PAGE_TRANSITION_LINK);
1919 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE: {
1920 // Make sure the model is loaded.
1921 TemplateURLService* model =
1922 TemplateURLServiceFactory::GetForProfile(profile_);
1927 SearchEngineTabHelper* search_engine_tab_helper =
1928 SearchEngineTabHelper::FromWebContents(source_web_contents_);
1929 if (search_engine_tab_helper &&
1930 search_engine_tab_helper->delegate()) {
1931 string16 keyword(TemplateURLService::GenerateKeyword(params_.page_url));
1932 TemplateURLData data;
1933 data.short_name = keyword;
1934 data.SetKeyword(keyword);
1935 data.SetURL(params_.keyword_url.spec());
1937 TemplateURL::GenerateFaviconURL(params_.page_url.GetOrigin());
1938 // Takes ownership of the TemplateURL.
1939 search_engine_tab_helper->delegate()->
1940 ConfirmAddSearchProvider(new TemplateURL(profile_, data), profile_);
1945 #if defined(ENABLE_INPUT_SPEECH)
1946 case IDC_CONTENT_CONTEXT_SPEECH_INPUT_FILTER_PROFANITIES: {
1947 profile_->GetPrefs()->SetBoolean(
1948 prefs::kSpeechRecognitionFilterProfanities,
1949 !profile_->GetPrefs()->GetBoolean(
1950 prefs::kSpeechRecognitionFilterProfanities));
1954 case IDC_CONTENT_CONTEXT_SPEECH_INPUT_ABOUT: {
1955 GURL url(chrome::kSpeechInputAboutURL);
1956 GURL localized_url = google_util::AppendGoogleLocaleParam(url);
1957 // Open URL with no referrer field (because user clicked on menu item).
1958 OpenURL(localized_url, GURL(), 0, NEW_FOREGROUND_TAB,
1959 content::PAGE_TRANSITION_LINK);
1969 ProtocolHandlerRegistry::ProtocolHandlerList
1970 RenderViewContextMenu::GetHandlersForLinkUrl() {
1971 ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1972 protocol_handler_registry_->GetHandlersFor(params_.link_url.scheme());
1973 std::sort(handlers.begin(), handlers.end());
1977 void RenderViewContextMenu::MenuWillShow(ui::SimpleMenuModel* source) {
1978 for (int i = 0; i < source->GetItemCount(); ++i) {
1979 if (source->IsVisibleAt(i) &&
1980 source->GetTypeAt(i) != ui::MenuModel::TYPE_SEPARATOR) {
1981 RecordShownItem(source->GetCommandIdAt(i));
1985 // Ignore notifications from submenus.
1986 if (source != &menu_model_)
1989 content::RenderWidgetHostView* view =
1990 source_web_contents_->GetRenderWidgetHostView();
1992 view->SetShowingContextMenu(true);
1994 content::NotificationService::current()->Notify(
1995 chrome::NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN,
1996 content::Source<RenderViewContextMenu>(this),
1997 content::NotificationService::NoDetails());
2000 void RenderViewContextMenu::MenuClosed(ui::SimpleMenuModel* source) {
2001 // Ignore notifications from submenus.
2002 if (source != &menu_model_)
2005 content::RenderWidgetHostView* view =
2006 source_web_contents_->GetRenderWidgetHostView();
2008 view->SetShowingContextMenu(false);
2009 RenderViewHost* rvh = source_web_contents_->GetRenderViewHost();
2011 rvh->NotifyContextMenuClosed(params_.custom_context);
2014 if (!command_executed_) {
2015 FOR_EACH_OBSERVER(RenderViewContextMenuObserver,
2021 bool RenderViewContextMenu::IsDevCommandEnabled(int id) const {
2022 if (id == IDC_CONTENT_CONTEXT_INSPECTELEMENT ||
2023 id == IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE) {
2024 const CommandLine* command_line = CommandLine::ForCurrentProcess();
2025 if (!profile_->GetPrefs()->GetBoolean(prefs::kWebKitJavascriptEnabled) ||
2026 command_line->HasSwitch(switches::kDisableJavaScript))
2029 // Don't enable the web inspector if the developer tools are disabled via
2030 // the preference dev-tools-disabled.
2031 if (profile_->GetPrefs()->GetBoolean(prefs::kDevToolsDisabled))
2038 string16 RenderViewContextMenu::PrintableSelectionText() {
2039 return gfx::TruncateString(params_.selection_text,
2040 kMaxSelectionTextLength);
2043 // Controller functions --------------------------------------------------------
2045 void RenderViewContextMenu::OpenURL(
2046 const GURL& url, const GURL& referrer, int64 frame_id,
2047 WindowOpenDisposition disposition,
2048 content::PageTransition transition) {
2049 // Ensure that URL fragment, username and password fields are not sent
2051 GURL sanitized_referrer(referrer);
2052 if (sanitized_referrer.is_valid() && (sanitized_referrer.has_ref() ||
2053 sanitized_referrer.has_username() || sanitized_referrer.has_password())) {
2054 GURL::Replacements referrer_mods;
2055 referrer_mods.ClearRef();
2056 referrer_mods.ClearUsername();
2057 referrer_mods.ClearPassword();
2058 sanitized_referrer = sanitized_referrer.ReplaceComponents(referrer_mods);
2061 WebContents* new_contents = source_web_contents_->OpenURL(OpenURLParams(
2062 url, content::Referrer(sanitized_referrer, params_.referrer_policy),
2063 disposition, transition, false));
2067 RetargetingDetails details;
2068 details.source_web_contents = source_web_contents_;
2069 details.source_frame_id = frame_id;
2070 details.target_url = url;
2071 details.target_web_contents = new_contents;
2072 details.not_yet_in_tabstrip = false;
2073 content::NotificationService::current()->Notify(
2074 chrome::NOTIFICATION_RETARGETING,
2075 content::Source<Profile>(Profile::FromBrowserContext(
2076 source_web_contents_->GetBrowserContext())),
2077 content::Details<RetargetingDetails>(&details));
2080 void RenderViewContextMenu::CopyImageAt(int x, int y) {
2081 source_web_contents_->GetRenderViewHost()->CopyImageAt(x, y);
2084 void RenderViewContextMenu::GetImageThumbnailForSearch() {
2085 source_web_contents_->GetRenderViewHost()->Send(
2086 new ChromeViewMsg_RequestThumbnailForContextNode(
2087 source_web_contents_->GetRenderViewHost()->GetRoutingID(),
2088 kImageSearchThumbnailMinSize,
2089 gfx::Size(kImageSearchThumbnailMaxWidth,
2090 kImageSearchThumbnailMaxHeight)));
2093 void RenderViewContextMenu::Inspect(int x, int y) {
2094 content::RecordAction(UserMetricsAction("DevTools_InspectElement"));
2095 source_web_contents_->GetRenderViewHostAtPosition(
2096 x, y, base::Bind(&DevToolsInspectElementAt));
2099 void RenderViewContextMenu::WriteURLToClipboard(const GURL& url) {
2100 chrome_common_net::WriteURLToClipboard(
2102 profile_->GetPrefs()->GetString(prefs::kAcceptLanguages),
2103 ui::Clipboard::GetForCurrentThread());
2106 void RenderViewContextMenu::MediaPlayerActionAt(
2107 const gfx::Point& location,
2108 const WebMediaPlayerAction& action) {
2109 source_web_contents_->GetRenderViewHost()->
2110 ExecuteMediaPlayerActionAtLocation(location, action);
2113 void RenderViewContextMenu::PluginActionAt(
2114 const gfx::Point& location,
2115 const WebPluginAction& action) {
2116 source_web_contents_->GetRenderViewHost()->
2117 ExecutePluginActionAtLocation(location, action);