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_input.h"
27 #include "chrome/browser/autocomplete/autocomplete_match.h"
28 #include "chrome/browser/browser_process.h"
29 #include "chrome/browser/chrome_notification_types.h"
30 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
31 #include "chrome/browser/devtools/devtools_window.h"
32 #include "chrome/browser/download/download_service.h"
33 #include "chrome/browser/download/download_service_factory.h"
34 #include "chrome/browser/download/download_stats.h"
35 #include "chrome/browser/extensions/devtools_util.h"
36 #include "chrome/browser/extensions/extension_host.h"
37 #include "chrome/browser/extensions/extension_service.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_tab_helper.h"
55 #include "chrome/browser/ui/browser.h"
56 #include "chrome/browser/ui/browser_commands.h"
57 #include "chrome/browser/ui/browser_finder.h"
58 #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"
59 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
60 #include "chrome/common/chrome_constants.h"
61 #include "chrome/common/chrome_switches.h"
62 #include "chrome/common/content_restriction.h"
63 #include "chrome/common/net/url_util.h"
64 #include "chrome/common/pref_names.h"
65 #include "chrome/common/render_messages.h"
66 #include "chrome/common/spellcheck_messages.h"
67 #include "chrome/common/url_constants.h"
68 #include "components/translate/core/browser/translate_download_manager.h"
69 #include "components/translate/core/browser/translate_prefs.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_frame_host.h"
78 #include "content/public/browser/render_process_host.h"
79 #include "content/public/browser/render_view_host.h"
80 #include "content/public/browser/render_widget_host_view.h"
81 #include "content/public/browser/user_metrics.h"
82 #include "content/public/browser/web_contents.h"
83 #include "content/public/common/menu_item.h"
84 #include "content/public/common/ssl_status.h"
85 #include "content/public/common/url_utils.h"
86 #include "extensions/browser/extension_system.h"
87 #include "extensions/browser/view_type_utils.h"
88 #include "extensions/common/extension.h"
89 #include "grit/generated_resources.h"
90 #include "net/base/escape.h"
91 #include "third_party/WebKit/public/web/WebContextMenuData.h"
92 #include "third_party/WebKit/public/web/WebMediaPlayerAction.h"
93 #include "third_party/WebKit/public/web/WebPluginAction.h"
94 #include "ui/base/clipboard/clipboard.h"
95 #include "ui/base/l10n/l10n_util.h"
96 #include "ui/gfx/favicon_size.h"
97 #include "ui/gfx/point.h"
98 #include "ui/gfx/size.h"
99 #include "ui/gfx/text_elider.h"
101 #if defined(ENABLE_PRINTING)
102 #include "chrome/common/print_messages.h"
104 #if defined(ENABLE_FULL_PRINTING)
105 #include "chrome/browser/printing/print_preview_context_menu_observer.h"
106 #include "chrome/browser/printing/print_preview_dialog_controller.h"
107 #include "chrome/browser/printing/print_view_manager.h"
109 #include "chrome/browser/printing/print_view_manager_basic.h"
110 #endif // defined(ENABLE_FULL_PRINTING)
111 #endif // defined(ENABLE_PRINTING)
113 using base::UserMetricsAction
;
114 using blink::WebContextMenuData
;
115 using blink::WebMediaPlayerAction
;
116 using blink::WebPluginAction
;
117 using blink::WebString
;
119 using content::BrowserContext
;
120 using content::ChildProcessSecurityPolicy
;
121 using content::DownloadManager
;
122 using content::DownloadUrlParameters
;
123 using content::NavigationController
;
124 using content::NavigationEntry
;
125 using content::OpenURLParams
;
126 using content::RenderFrameHost
;
127 using content::RenderViewHost
;
128 using content::SSLStatus
;
129 using content::WebContents
;
130 using extensions::Extension
;
131 using extensions::MenuItem
;
132 using extensions::MenuManager
;
136 const int kImageSearchThumbnailMinSize
= 300 * 300;
137 const int kImageSearchThumbnailMaxWidth
= 600;
138 const int kImageSearchThumbnailMaxHeight
= 600;
140 // Maps UMA enumeration to IDC. IDC could be changed so we can't use
141 // just them and |UMA_HISTOGRAM_CUSTOM_ENUMERATION|.
142 // Never change mapping or reuse |enum_id|. Always push back new items.
143 // Items that is not used any more by |RenderViewContextMenu.ExecuteCommand|
144 // could be deleted, but don't change the rest of |kUmaEnumToControlId|.
145 const struct UmaEnumCommandIdPair
{
148 } kUmaEnumToControlId
[] = {
149 { 0, IDC_CONTENT_CONTEXT_CUSTOM_FIRST
},
150 { 1, IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST
},
151 { 2, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
},
152 { 3, IDC_CONTENT_CONTEXT_OPENLINKNEWTAB
},
153 { 4, IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW
},
154 { 5, IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD
},
155 { 6, IDC_CONTENT_CONTEXT_SAVELINKAS
},
156 { 7, IDC_CONTENT_CONTEXT_SAVEAVAS
},
157 { 8, IDC_CONTENT_CONTEXT_SAVEIMAGEAS
},
158 { 9, IDC_CONTENT_CONTEXT_COPYLINKLOCATION
},
159 { 10, IDC_CONTENT_CONTEXT_COPYIMAGELOCATION
},
160 { 11, IDC_CONTENT_CONTEXT_COPYAVLOCATION
},
161 { 12, IDC_CONTENT_CONTEXT_COPYIMAGE
},
162 { 13, IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB
},
163 { 14, IDC_CONTENT_CONTEXT_OPENAVNEWTAB
},
164 { 15, IDC_CONTENT_CONTEXT_PLAYPAUSE
},
165 { 16, IDC_CONTENT_CONTEXT_MUTE
},
166 { 17, IDC_CONTENT_CONTEXT_LOOP
},
167 { 18, IDC_CONTENT_CONTEXT_CONTROLS
},
168 { 19, IDC_CONTENT_CONTEXT_ROTATECW
},
169 { 20, IDC_CONTENT_CONTEXT_ROTATECCW
},
172 { 23, IDC_SAVE_PAGE
},
174 { 25, IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP
},
175 { 26, IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP
},
177 { 28, IDC_VIEW_SOURCE
},
178 { 29, IDC_CONTENT_CONTEXT_INSPECTELEMENT
},
179 { 30, IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE
},
180 { 31, IDC_CONTENT_CONTEXT_VIEWPAGEINFO
},
181 { 32, IDC_CONTENT_CONTEXT_TRANSLATE
},
182 { 33, IDC_CONTENT_CONTEXT_RELOADFRAME
},
183 { 34, IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE
},
184 { 35, IDC_CONTENT_CONTEXT_VIEWFRAMEINFO
},
185 { 36, IDC_CONTENT_CONTEXT_UNDO
},
186 { 37, IDC_CONTENT_CONTEXT_REDO
},
187 { 38, IDC_CONTENT_CONTEXT_CUT
},
188 { 39, IDC_CONTENT_CONTEXT_COPY
},
189 { 40, IDC_CONTENT_CONTEXT_PASTE
},
190 { 41, IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE
},
191 { 42, IDC_CONTENT_CONTEXT_DELETE
},
192 { 43, IDC_CONTENT_CONTEXT_SELECTALL
},
193 { 44, IDC_CONTENT_CONTEXT_SEARCHWEBFOR
},
194 { 45, IDC_CONTENT_CONTEXT_GOTOURL
},
195 { 46, IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS
},
196 { 47, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS
},
197 { 48, IDC_CONTENT_CONTEXT_ADDSEARCHENGINE
},
198 { 49, IDC_CONTENT_CONTEXT_SPEECH_INPUT_FILTER_PROFANITIES
},
199 { 50, IDC_CONTENT_CONTEXT_SPEECH_INPUT_ABOUT
},
200 { 51, IDC_SPEECH_INPUT_MENU
},
201 { 52, IDC_CONTENT_CONTEXT_OPENLINKWITH
},
202 { 53, IDC_CHECK_SPELLING_WHILE_TYPING
},
203 { 54, IDC_SPELLCHECK_MENU
},
204 { 55, IDC_CONTENT_CONTEXT_SPELLING_TOGGLE
},
205 { 56, IDC_SPELLCHECK_LANGUAGES_FIRST
},
206 { 57, IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE
},
207 // Add new items here and use |enum_id| from the next line.
208 { 58, 0 }, // Must be the last. Increment |enum_id| when new IDC was added.
211 // Collapses large ranges of ids before looking for UMA enum.
212 int CollapleCommandsForUMA(int id
) {
213 if (id
>= IDC_CONTENT_CONTEXT_CUSTOM_FIRST
&&
214 id
<= IDC_CONTENT_CONTEXT_CUSTOM_LAST
) {
215 return IDC_CONTENT_CONTEXT_CUSTOM_FIRST
;
218 if (id
>= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST
&&
219 id
<= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST
) {
220 return IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST
;
223 if (id
>= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
&&
224 id
<= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST
) {
225 return IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
;
228 if (id
>= IDC_SPELLCHECK_LANGUAGES_FIRST
&&
229 id
<= IDC_SPELLCHECK_LANGUAGES_LAST
) {
230 return IDC_SPELLCHECK_LANGUAGES_FIRST
;
236 // Returns UMA enum value for command specified by |id| or -1 if not found.
237 int FindUMAEnumValueForCommand(int id
) {
238 id
= CollapleCommandsForUMA(id
);
239 const size_t kMappingSize
= arraysize(kUmaEnumToControlId
);
240 for (size_t i
= 0; i
< kMappingSize
; ++i
) {
241 if (kUmaEnumToControlId
[i
].control_id
== id
) {
242 return kUmaEnumToControlId
[i
].enum_id
;
248 // Increments histogram value for used items specified by |id|.
249 void RecordUsedItem(int id
) {
250 int enum_id
= FindUMAEnumValueForCommand(id
);
252 const size_t kMappingSize
= arraysize(kUmaEnumToControlId
);
253 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Used", enum_id
,
254 kUmaEnumToControlId
[kMappingSize
- 1].enum_id
);
256 NOTREACHED() << "Update kUmaEnumToControlId. Unhanded IDC: " << id
;
260 // Increments histogram value for visible context menu item specified by |id|.
261 void RecordShownItem(int id
) {
262 int enum_id
= FindUMAEnumValueForCommand(id
);
264 const size_t kMappingSize
= arraysize(kUmaEnumToControlId
);
265 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Shown", enum_id
,
266 kUmaEnumToControlId
[kMappingSize
- 1].enum_id
);
268 // Just warning here. It's harder to maintain list of all possibly
269 // visible items than executable items.
270 DLOG(ERROR
) << "Update kUmaEnumToControlId. Unhanded IDC: " << id
;
274 // Usually a new tab is expected where this function is used,
275 // however users should be able to open a tab in background
276 // or in a new window.
277 WindowOpenDisposition
ForceNewTabDispositionFromEventFlags(
279 WindowOpenDisposition disposition
=
280 ui::DispositionFromEventFlags(event_flags
);
281 return disposition
== CURRENT_TAB
? NEW_FOREGROUND_TAB
: disposition
;
284 bool IsCustomItemEnabled(const std::vector
<content::MenuItem
>& items
, int id
) {
285 DCHECK(id
>= IDC_CONTENT_CONTEXT_CUSTOM_FIRST
&&
286 id
<= IDC_CONTENT_CONTEXT_CUSTOM_LAST
);
287 for (size_t i
= 0; i
< items
.size(); ++i
) {
288 int action_id
= IDC_CONTENT_CONTEXT_CUSTOM_FIRST
+ items
[i
].action
;
290 return items
[i
].enabled
;
291 if (items
[i
].type
== content::MenuItem::SUBMENU
) {
292 if (IsCustomItemEnabled(items
[i
].submenu
, id
))
299 bool IsCustomItemChecked(const std::vector
<content::MenuItem
>& items
, int id
) {
300 DCHECK(id
>= IDC_CONTENT_CONTEXT_CUSTOM_FIRST
&&
301 id
<= IDC_CONTENT_CONTEXT_CUSTOM_LAST
);
302 for (size_t i
= 0; i
< items
.size(); ++i
) {
303 int action_id
= IDC_CONTENT_CONTEXT_CUSTOM_FIRST
+ items
[i
].action
;
305 return items
[i
].checked
;
306 if (items
[i
].type
== content::MenuItem::SUBMENU
) {
307 if (IsCustomItemChecked(items
[i
].submenu
, id
))
314 const size_t kMaxCustomMenuDepth
= 5;
315 const size_t kMaxCustomMenuTotalItems
= 1000;
317 void AddCustomItemsToMenu(const std::vector
<content::MenuItem
>& items
,
320 ui::SimpleMenuModel::Delegate
* delegate
,
321 ui::SimpleMenuModel
* menu_model
) {
322 if (depth
> kMaxCustomMenuDepth
) {
323 LOG(ERROR
) << "Custom menu too deeply nested.";
326 for (size_t i
= 0; i
< items
.size(); ++i
) {
327 if (IDC_CONTENT_CONTEXT_CUSTOM_FIRST
+ items
[i
].action
>=
328 IDC_CONTENT_CONTEXT_CUSTOM_LAST
) {
329 LOG(ERROR
) << "Custom menu action value too big.";
332 if (*total_items
>= kMaxCustomMenuTotalItems
) {
333 LOG(ERROR
) << "Custom menu too large (too many items).";
337 switch (items
[i
].type
) {
338 case content::MenuItem::OPTION
:
340 items
[i
].action
+ IDC_CONTENT_CONTEXT_CUSTOM_FIRST
,
343 case content::MenuItem::CHECKABLE_OPTION
:
344 menu_model
->AddCheckItem(
345 items
[i
].action
+ IDC_CONTENT_CONTEXT_CUSTOM_FIRST
,
348 case content::MenuItem::GROUP
:
349 // TODO(viettrungluu): I don't know what this is supposed to do.
352 case content::MenuItem::SEPARATOR
:
353 menu_model
->AddSeparator(ui::NORMAL_SEPARATOR
);
355 case content::MenuItem::SUBMENU
: {
356 ui::SimpleMenuModel
* submenu
= new ui::SimpleMenuModel(delegate
);
357 AddCustomItemsToMenu(items
[i
].submenu
, depth
+ 1, total_items
, delegate
,
359 menu_model
->AddSubMenu(
360 items
[i
].action
+ IDC_CONTENT_CONTEXT_CUSTOM_FIRST
,
372 void DevToolsInspectElementAt(RenderViewHost
* rvh
, int x
, int y
) {
373 DevToolsWindow::InspectElement(rvh
, x
, y
);
376 // Helper function to escape "&" as "&&".
377 void EscapeAmpersands(base::string16
* text
) {
378 const base::char16 ampersand
[] = {'&', 0};
379 base::ReplaceChars(*text
, ampersand
, base::ASCIIToUTF16("&&"), text
);
385 const size_t RenderViewContextMenu::kMaxSelectionTextLength
= 50;
388 bool RenderViewContextMenu::IsDevToolsURL(const GURL
& url
) {
389 return url
.SchemeIs(chrome::kChromeDevToolsScheme
);
393 bool RenderViewContextMenu::IsInternalResourcesURL(const GURL
& url
) {
394 if (!url
.SchemeIs(content::kChromeUIScheme
))
396 return url
.host() == chrome::kChromeUISyncResourcesHost
;
399 static const int kSpellcheckRadioGroup
= 1;
401 RenderViewContextMenu::RenderViewContextMenu(
402 content::RenderFrameHost
* render_frame_host
,
403 const content::ContextMenuParams
& params
)
405 source_web_contents_(WebContents::FromRenderFrameHost(render_frame_host
)),
406 render_process_id_(render_frame_host
->GetProcess()->GetID()),
407 render_frame_id_(render_frame_host
->GetRoutingID()),
408 profile_(Profile::FromBrowserContext(
409 source_web_contents_
->GetBrowserContext())),
411 extension_items_(profile_
, this, &menu_model_
,
412 base::Bind(MenuItemMatchesParams
, params_
)),
413 speech_input_submenu_model_(this),
414 protocol_handler_submenu_model_(this),
415 protocol_handler_registry_(
416 ProtocolHandlerRegistryFactory::GetForProfile(profile_
)),
417 command_executed_(false),
419 RenderViewHost
* rvh
= source_web_contents_
->GetRenderViewHost();
420 if (rvh
&& rvh
->GetProcess()->IsGuest())
424 RenderViewContextMenu::~RenderViewContextMenu() {
427 // Menu construction functions -------------------------------------------------
429 void RenderViewContextMenu::Init() {
434 void RenderViewContextMenu::Cancel() {
438 static bool ExtensionPatternMatch(const extensions::URLPatternSet
& patterns
,
440 // No patterns means no restriction, so that implicitly matches.
441 if (patterns
.is_empty())
443 return patterns
.MatchesURL(url
);
447 bool RenderViewContextMenu::ExtensionContextAndPatternMatch(
448 const content::ContextMenuParams
& params
,
449 MenuItem::ContextList contexts
,
450 const extensions::URLPatternSet
& target_url_patterns
) {
451 const bool has_link
= !params
.link_url
.is_empty();
452 const bool has_selection
= !params
.selection_text
.empty();
453 const bool in_frame
= !params
.frame_url
.is_empty();
455 if (contexts
.Contains(MenuItem::ALL
) ||
456 (has_selection
&& contexts
.Contains(MenuItem::SELECTION
)) ||
457 (params
.is_editable
&& contexts
.Contains(MenuItem::EDITABLE
)) ||
458 (in_frame
&& contexts
.Contains(MenuItem::FRAME
)))
461 if (has_link
&& contexts
.Contains(MenuItem::LINK
) &&
462 ExtensionPatternMatch(target_url_patterns
, params
.link_url
))
465 switch (params
.media_type
) {
466 case WebContextMenuData::MediaTypeImage
:
467 if (contexts
.Contains(MenuItem::IMAGE
) &&
468 ExtensionPatternMatch(target_url_patterns
, params
.src_url
))
472 case WebContextMenuData::MediaTypeVideo
:
473 if (contexts
.Contains(MenuItem::VIDEO
) &&
474 ExtensionPatternMatch(target_url_patterns
, params
.src_url
))
478 case WebContextMenuData::MediaTypeAudio
:
479 if (contexts
.Contains(MenuItem::AUDIO
) &&
480 ExtensionPatternMatch(target_url_patterns
, params
.src_url
))
488 // PAGE is the least specific context, so we only examine that if none of the
489 // other contexts apply (except for FRAME, which is included in PAGE for
490 // backwards compatibility).
491 if (!has_link
&& !has_selection
&& !params
.is_editable
&&
492 params
.media_type
== WebContextMenuData::MediaTypeNone
&&
493 contexts
.Contains(MenuItem::PAGE
))
499 static const GURL
& GetDocumentURL(const content::ContextMenuParams
& params
) {
500 return params
.frame_url
.is_empty() ? params
.page_url
: params
.frame_url
;
504 bool RenderViewContextMenu::MenuItemMatchesParams(
505 const content::ContextMenuParams
& params
,
506 const extensions::MenuItem
* item
) {
507 bool match
= ExtensionContextAndPatternMatch(params
, item
->contexts(),
508 item
->target_url_patterns());
512 const GURL
& document_url
= GetDocumentURL(params
);
513 return ExtensionPatternMatch(item
->document_url_patterns(), document_url
);
516 void RenderViewContextMenu::AppendAllExtensionItems() {
517 extension_items_
.Clear();
518 ExtensionService
* service
=
519 extensions::ExtensionSystem::Get(profile_
)->extension_service();
521 return; // In unit-tests, we may not have an ExtensionService.
523 MenuManager
* menu_manager
= MenuManager::Get(profile_
);
527 base::string16 printable_selection_text
= PrintableSelectionText();
528 EscapeAmpersands(&printable_selection_text
);
530 // Get a list of extension id's that have context menu items, and sort by the
531 // top level context menu title of the extension.
532 std::set
<std::string
> ids
= menu_manager
->ExtensionIds();
533 std::vector
<base::string16
> sorted_menu_titles
;
534 std::map
<base::string16
, std::string
> map_ids
;
535 for (std::set
<std::string
>::iterator i
= ids
.begin(); i
!= ids
.end(); ++i
) {
536 const Extension
* extension
= service
->GetExtensionById(*i
, false);
537 // Platform apps have their context menus created directly in
538 // AppendPlatformAppItems.
539 if (extension
&& !extension
->is_platform_app()) {
540 base::string16 menu_title
= extension_items_
.GetTopLevelContextMenuTitle(
541 *i
, printable_selection_text
);
542 map_ids
[menu_title
] = *i
;
543 sorted_menu_titles
.push_back(menu_title
);
546 if (sorted_menu_titles
.empty())
549 const std::string app_locale
= g_browser_process
->GetApplicationLocale();
550 l10n_util::SortStrings16(app_locale
, &sorted_menu_titles
);
553 base::TimeTicks begin
= base::TimeTicks::Now();
554 for (size_t i
= 0; i
< sorted_menu_titles
.size(); ++i
) {
555 const std::string
& id
= map_ids
[sorted_menu_titles
[i
]];
556 extension_items_
.AppendExtensionItems(id
, printable_selection_text
,
560 UMA_HISTOGRAM_TIMES("Extensions.ContextMenus_BuildTime",
561 base::TimeTicks::Now() - begin
);
562 UMA_HISTOGRAM_COUNTS("Extensions.ContextMenus_ItemCount", index
);
565 void RenderViewContextMenu::InitMenu() {
566 if (chrome::IsRunningInForcedAppMode()) {
567 AppendAppModeItems();
571 extensions::ViewType view_type
=
572 extensions::GetViewType(source_web_contents_
);
573 if (view_type
== extensions::VIEW_TYPE_APP_SHELL
) {
574 AppendPlatformAppItems();
576 } else if (view_type
== extensions::VIEW_TYPE_EXTENSION_POPUP
) {
577 AppendPopupExtensionItems();
579 } else if (view_type
== extensions::VIEW_TYPE_PANEL
) {
584 const bool has_link
= !params_
.unfiltered_link_url
.is_empty();
585 const bool has_selection
= !params_
.selection_text
.empty();
587 if (AppendCustomItems()) {
588 // If there's a selection, don't early return when there are custom items,
589 // but fall through to adding the normal ones after the custom ones.
591 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
593 // Don't add items for Pepper menu.
594 if (!params_
.custom_context
.is_pepper_menu
)
595 AppendDeveloperItems();
600 // When no special node or text is selected and selection has no link,
602 if (params_
.media_type
== WebContextMenuData::MediaTypeNone
&&
604 !params_
.is_editable
&&
607 if (!params_
.page_url
.is_empty()) {
608 bool is_devtools
= IsDevToolsURL(params_
.page_url
);
609 if (!is_devtools
&& !IsInternalResourcesURL(params_
.page_url
)) {
611 // Merge in frame items if we clicked within a frame that needs them.
612 if (!params_
.frame_url
.is_empty()) {
613 is_devtools
= IsDevToolsURL(params_
.frame_url
);
614 if (!is_devtools
&& !IsInternalResourcesURL(params_
.frame_url
)) {
615 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
621 DCHECK(params_
.frame_url
.is_empty());
625 // Do not show link related items for guest.
626 if (has_link
&& !is_guest_
) {
628 if (params_
.media_type
!= WebContextMenuData::MediaTypeNone
)
629 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
632 switch (params_
.media_type
) {
633 case WebContextMenuData::MediaTypeNone
:
635 case WebContextMenuData::MediaTypeImage
:
638 case WebContextMenuData::MediaTypeVideo
:
641 case WebContextMenuData::MediaTypeAudio
:
644 case WebContextMenuData::MediaTypePlugin
:
647 #ifdef WEBCONTEXT_MEDIATYPEFILE_DEFINED
648 case WebContextMenuData::MediaTypeFile
:
653 if (params_
.is_editable
)
654 AppendEditableItems();
655 else if (has_selection
)
658 if (!is_guest_
&& has_selection
) {
659 AppendSearchProvider();
660 if (!IsDevToolsURL(params_
.page_url
))
664 if (!IsDevToolsURL(params_
.page_url
) && !is_guest_
)
665 AppendAllExtensionItems();
667 AppendDeveloperItems();
670 #if defined(ENABLE_FULL_PRINTING)
671 if (!print_preview_menu_observer_
.get()) {
672 print_preview_menu_observer_
.reset(
673 new PrintPreviewContextMenuObserver(source_web_contents_
));
676 observers_
.AddObserver(print_preview_menu_observer_
.get());
681 const Extension
* RenderViewContextMenu::GetExtension() const {
682 extensions::ExtensionSystem
* system
=
683 extensions::ExtensionSystem::Get(profile_
);
684 // There is no process manager in some tests.
685 if (!system
->process_manager())
688 return system
->process_manager()->GetExtensionForRenderViewHost(
689 source_web_contents_
->GetRenderViewHost());
692 void RenderViewContextMenu::AppendAppModeItems() {
693 const bool has_selection
= !params_
.selection_text
.empty();
695 if (params_
.is_editable
)
696 AppendEditableItems();
697 else if (has_selection
)
701 void RenderViewContextMenu::AppendPlatformAppItems() {
702 const Extension
* platform_app
= GetExtension();
704 // The RVH might be for a process sandboxed from the extension.
708 DCHECK(platform_app
->is_platform_app());
710 const bool has_selection
= !params_
.selection_text
.empty();
712 // Add undo/redo, cut/copy/paste etc for text fields.
713 if (params_
.is_editable
)
714 AppendEditableItems();
715 else if (has_selection
)
719 extension_items_
.AppendExtensionItems(platform_app
->id(),
720 PrintableSelectionText(), &index
);
722 // Add dev tools for unpacked extensions.
723 if (extensions::Manifest::IsUnpackedLocation(platform_app
->location()) ||
724 CommandLine::ForCurrentProcess()->HasSwitch(
725 switches::kDebugPackedApps
)) {
726 // Add a separator if there are any items already in the menu.
727 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
729 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP
,
730 IDS_CONTENT_CONTEXT_RELOAD_PACKAGED_APP
);
731 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP
,
732 IDS_CONTENT_CONTEXT_RESTART_APP
);
733 AppendDeveloperItems();
734 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE
,
735 IDS_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE
);
739 void RenderViewContextMenu::AppendPopupExtensionItems() {
740 const bool has_selection
= !params_
.selection_text
.empty();
742 if (params_
.is_editable
)
743 AppendEditableItems();
744 else if (has_selection
)
748 AppendSearchProvider();
750 AppendAllExtensionItems();
751 AppendDeveloperItems();
754 void RenderViewContextMenu::AppendPanelItems() {
755 bool has_selection
= !params_
.selection_text
.empty();
757 // Checking link should take precedence before checking selection since on Mac
758 // right-clicking a link will also make it selected.
759 if (params_
.unfiltered_link_url
.is_valid())
762 if (params_
.is_editable
)
763 AppendEditableItems();
764 else if (has_selection
)
767 // Avoid appending extension related items when |extension| is null. This
768 // happens when the panel is navigated to a url outside of the extension's
770 const Extension
* extension
= GetExtension();
772 // Only add extension items from this extension.
774 extension_items_
.AppendExtensionItems(extension
->id(),
775 PrintableSelectionText(), &index
);
779 void RenderViewContextMenu::AddMenuItem(int command_id
,
780 const base::string16
& title
) {
781 menu_model_
.AddItem(command_id
, title
);
784 void RenderViewContextMenu::AddCheckItem(int command_id
,
785 const base::string16
& title
) {
786 menu_model_
.AddCheckItem(command_id
, title
);
789 void RenderViewContextMenu::AddSeparator() {
790 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
793 void RenderViewContextMenu::AddSubMenu(int command_id
,
794 const base::string16
& label
,
795 ui::MenuModel
* model
) {
796 menu_model_
.AddSubMenu(command_id
, label
, model
);
799 void RenderViewContextMenu::UpdateMenuItem(int command_id
,
802 const base::string16
& label
) {
803 // This function needs platform-specific implementation.
807 RenderViewHost
* RenderViewContextMenu::GetRenderViewHost() const {
808 return source_web_contents_
->GetRenderViewHost();
811 WebContents
* RenderViewContextMenu::GetWebContents() const {
812 return source_web_contents_
;
815 Profile
* RenderViewContextMenu::GetProfile() const {
819 bool RenderViewContextMenu::AppendCustomItems() {
820 size_t total_items
= 0;
821 AddCustomItemsToMenu(params_
.custom_items
, 0, &total_items
, this,
823 return total_items
> 0;
826 void RenderViewContextMenu::AppendDeveloperItems() {
827 // Show Inspect Element in DevTools itself only in case of the debug
829 bool show_developer_items
= !IsDevToolsURL(params_
.page_url
);
831 #if defined(DEBUG_DEVTOOLS)
832 show_developer_items
= true;
835 if (!show_developer_items
)
838 // In the DevTools popup menu, "developer items" is normally the only
839 // section, so omit the separator there.
840 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
841 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTELEMENT
,
842 IDS_CONTENT_CONTEXT_INSPECTELEMENT
);
845 void RenderViewContextMenu::AppendLinkItems() {
846 if (!params_
.link_url
.is_empty()) {
847 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB
,
848 IDS_CONTENT_CONTEXT_OPENLINKNEWTAB
);
849 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW
,
850 IDS_CONTENT_CONTEXT_OPENLINKNEWWINDOW
);
851 if (params_
.link_url
.is_valid()) {
852 AppendProtocolHandlerSubMenu();
855 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD
,
856 IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD
);
857 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVELINKAS
,
858 IDS_CONTENT_CONTEXT_SAVELINKAS
);
861 menu_model_
.AddItemWithStringId(
862 IDC_CONTENT_CONTEXT_COPYLINKLOCATION
,
863 params_
.link_url
.SchemeIs(content::kMailToScheme
) ?
864 IDS_CONTENT_CONTEXT_COPYEMAILADDRESS
:
865 IDS_CONTENT_CONTEXT_COPYLINKLOCATION
);
868 void RenderViewContextMenu::AppendImageItems() {
869 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS
,
870 IDS_CONTENT_CONTEXT_SAVEIMAGEAS
);
871 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGELOCATION
,
872 IDS_CONTENT_CONTEXT_COPYIMAGELOCATION
);
873 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE
,
874 IDS_CONTENT_CONTEXT_COPYIMAGE
);
875 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB
,
876 IDS_CONTENT_CONTEXT_OPENIMAGENEWTAB
);
877 const TemplateURL
* const default_provider
=
878 TemplateURLServiceFactory::GetForProfile(profile_
)->
879 GetDefaultSearchProvider();
880 if (!is_guest_
&& params_
.has_image_contents
&& default_provider
&&
881 !default_provider
->image_url().empty() &&
882 default_provider
->image_url_ref().IsValid()) {
884 IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE
,
885 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFORIMAGE
,
886 default_provider
->short_name()));
891 void RenderViewContextMenu::AppendAudioItems() {
893 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
894 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS
,
895 IDS_CONTENT_CONTEXT_SAVEAUDIOAS
);
896 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION
,
897 IDS_CONTENT_CONTEXT_COPYAUDIOLOCATION
);
898 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB
,
899 IDS_CONTENT_CONTEXT_OPENAUDIONEWTAB
);
902 void RenderViewContextMenu::AppendVideoItems() {
904 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
905 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS
,
906 IDS_CONTENT_CONTEXT_SAVEVIDEOAS
);
907 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION
,
908 IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION
);
909 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB
,
910 IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB
);
913 void RenderViewContextMenu::AppendMediaItems() {
914 int media_flags
= params_
.media_flags
;
916 menu_model_
.AddItemWithStringId(
917 IDC_CONTENT_CONTEXT_PLAYPAUSE
,
918 media_flags
& WebContextMenuData::MediaPaused
?
919 IDS_CONTENT_CONTEXT_PLAY
:
920 IDS_CONTENT_CONTEXT_PAUSE
);
922 menu_model_
.AddItemWithStringId(
923 IDC_CONTENT_CONTEXT_MUTE
,
924 media_flags
& WebContextMenuData::MediaMuted
?
925 IDS_CONTENT_CONTEXT_UNMUTE
:
926 IDS_CONTENT_CONTEXT_MUTE
);
928 menu_model_
.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_LOOP
,
929 IDS_CONTENT_CONTEXT_LOOP
);
930 menu_model_
.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_CONTROLS
,
931 IDS_CONTENT_CONTEXT_CONTROLS
);
934 void RenderViewContextMenu::AppendPluginItems() {
935 if (params_
.page_url
== params_
.src_url
) {
936 // Full page plugin, so show page menu items.
937 if (params_
.link_url
.is_empty() && params_
.selection_text
.empty())
940 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS
,
941 IDS_CONTENT_CONTEXT_SAVEPAGEAS
);
942 menu_model_
.AddItemWithStringId(IDC_PRINT
, IDS_CONTENT_CONTEXT_PRINT
);
945 if (params_
.media_flags
& WebContextMenuData::MediaCanRotate
) {
946 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
947 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECW
,
948 IDS_CONTENT_CONTEXT_ROTATECW
);
949 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECCW
,
950 IDS_CONTENT_CONTEXT_ROTATECCW
);
954 void RenderViewContextMenu::AppendPageItems() {
955 menu_model_
.AddItemWithStringId(IDC_BACK
, IDS_CONTENT_CONTEXT_BACK
);
956 menu_model_
.AddItemWithStringId(IDC_FORWARD
, IDS_CONTENT_CONTEXT_FORWARD
);
957 menu_model_
.AddItemWithStringId(IDC_RELOAD
, IDS_CONTENT_CONTEXT_RELOAD
);
958 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
959 menu_model_
.AddItemWithStringId(IDC_SAVE_PAGE
,
960 IDS_CONTENT_CONTEXT_SAVEPAGEAS
);
961 menu_model_
.AddItemWithStringId(IDC_PRINT
, IDS_CONTENT_CONTEXT_PRINT
);
963 if (TranslateManager::IsTranslatableURL(params_
.page_url
)) {
964 std::string locale
= g_browser_process
->GetApplicationLocale();
965 locale
= TranslateDownloadManager::GetLanguageCode(locale
);
966 base::string16 language
=
967 l10n_util::GetDisplayNameForLocale(locale
, locale
, true);
969 IDC_CONTENT_CONTEXT_TRANSLATE
,
970 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_TRANSLATE
, language
));
973 menu_model_
.AddItemWithStringId(IDC_VIEW_SOURCE
,
974 IDS_CONTENT_CONTEXT_VIEWPAGESOURCE
);
975 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWPAGEINFO
,
976 IDS_CONTENT_CONTEXT_VIEWPAGEINFO
);
979 void RenderViewContextMenu::AppendFrameItems() {
980 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOADFRAME
,
981 IDS_CONTENT_CONTEXT_RELOADFRAME
);
982 // These two menu items have yet to be implemented.
983 // http://code.google.com/p/chromium/issues/detail?id=11827
984 // IDS_CONTENT_CONTEXT_SAVEFRAMEAS
985 // IDS_CONTENT_CONTEXT_PRINTFRAME
986 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE
,
987 IDS_CONTENT_CONTEXT_VIEWFRAMESOURCE
);
988 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMEINFO
,
989 IDS_CONTENT_CONTEXT_VIEWFRAMEINFO
);
992 void RenderViewContextMenu::AppendCopyItem() {
993 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY
,
994 IDS_CONTENT_CONTEXT_COPY
);
997 void RenderViewContextMenu::AppendPrintItem() {
998 if (profile_
->GetPrefs()->GetBoolean(prefs::kPrintingEnabled
) &&
999 (params_
.media_type
== WebContextMenuData::MediaTypeNone
||
1000 params_
.media_flags
& WebContextMenuData::MediaCanPrint
)) {
1001 menu_model_
.AddItemWithStringId(IDC_PRINT
, IDS_CONTENT_CONTEXT_PRINT
);
1005 void RenderViewContextMenu::AppendSearchProvider() {
1008 TrimWhitespace(params_
.selection_text
, TRIM_ALL
, ¶ms_
.selection_text
);
1009 if (params_
.selection_text
.empty())
1012 base::ReplaceChars(params_
.selection_text
, AutocompleteMatch::kInvalidChars
,
1013 base::ASCIIToUTF16(" "), ¶ms_
.selection_text
);
1015 AutocompleteMatch match
;
1016 AutocompleteClassifierFactory::GetForProfile(profile_
)->Classify(
1017 params_
.selection_text
, false, false, AutocompleteInput::INVALID_SPEC
,
1019 selection_navigation_url_
= match
.destination_url
;
1020 if (!selection_navigation_url_
.is_valid())
1023 base::string16 printable_selection_text
= PrintableSelectionText();
1024 EscapeAmpersands(&printable_selection_text
);
1026 if (AutocompleteMatch::IsSearchType(match
.type
)) {
1027 const TemplateURL
* const default_provider
=
1028 TemplateURLServiceFactory::GetForProfile(profile_
)->
1029 GetDefaultSearchProvider();
1030 if (!default_provider
)
1032 menu_model_
.AddItem(
1033 IDC_CONTENT_CONTEXT_SEARCHWEBFOR
,
1034 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFOR
,
1035 default_provider
->short_name(),
1036 printable_selection_text
));
1038 if ((selection_navigation_url_
!= params_
.link_url
) &&
1039 ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme(
1040 selection_navigation_url_
.scheme())) {
1041 menu_model_
.AddItem(
1042 IDC_CONTENT_CONTEXT_GOTOURL
,
1043 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_GOTOURL
,
1044 printable_selection_text
));
1049 void RenderViewContextMenu::AppendEditableItems() {
1050 const bool use_spellcheck_and_search
= !chrome::IsRunningInForcedAppMode();
1052 if (use_spellcheck_and_search
)
1053 AppendSpellingSuggestionsSubMenu();
1055 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_UNDO
,
1056 IDS_CONTENT_CONTEXT_UNDO
);
1057 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_REDO
,
1058 IDS_CONTENT_CONTEXT_REDO
);
1059 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
1060 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_CUT
,
1061 IDS_CONTENT_CONTEXT_CUT
);
1062 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY
,
1063 IDS_CONTENT_CONTEXT_COPY
);
1064 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE
,
1065 IDS_CONTENT_CONTEXT_PASTE
);
1066 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE
,
1067 IDS_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE
);
1068 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_DELETE
,
1069 IDS_CONTENT_CONTEXT_DELETE
);
1070 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
1072 if (use_spellcheck_and_search
&& !params_
.keyword_url
.is_empty()) {
1073 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_ADDSEARCHENGINE
,
1074 IDS_CONTENT_CONTEXT_ADDSEARCHENGINE
);
1075 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
1078 if (use_spellcheck_and_search
)
1079 AppendSpellcheckOptionsSubMenu();
1080 AppendSpeechInputOptionsSubMenu();
1081 AppendPlatformEditableItems();
1083 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
1084 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SELECTALL
,
1085 IDS_CONTENT_CONTEXT_SELECTALL
);
1088 void RenderViewContextMenu::AppendSpellingSuggestionsSubMenu() {
1089 if (!spelling_menu_observer_
.get())
1090 spelling_menu_observer_
.reset(new SpellingMenuObserver(this));
1091 observers_
.AddObserver(spelling_menu_observer_
.get());
1092 spelling_menu_observer_
->InitMenu(params_
);
1095 void RenderViewContextMenu::AppendSpellcheckOptionsSubMenu() {
1096 if (!spellchecker_submenu_observer_
.get()) {
1097 spellchecker_submenu_observer_
.reset(new SpellCheckerSubMenuObserver(
1098 this, this, kSpellcheckRadioGroup
));
1100 spellchecker_submenu_observer_
->InitMenu(params_
);
1101 observers_
.AddObserver(spellchecker_submenu_observer_
.get());
1104 void RenderViewContextMenu::AppendSpeechInputOptionsSubMenu() {
1105 if (params_
.speech_input_enabled
) {
1106 speech_input_submenu_model_
.AddCheckItem(
1107 IDC_CONTENT_CONTEXT_SPEECH_INPUT_FILTER_PROFANITIES
,
1108 l10n_util::GetStringUTF16(
1109 IDS_CONTENT_CONTEXT_SPEECH_INPUT_FILTER_PROFANITIES
));
1111 speech_input_submenu_model_
.AddItemWithStringId(
1112 IDC_CONTENT_CONTEXT_SPEECH_INPUT_ABOUT
,
1113 IDS_CONTENT_CONTEXT_SPEECH_INPUT_ABOUT
);
1115 menu_model_
.AddSubMenu(
1116 IDC_SPEECH_INPUT_MENU
,
1117 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_SPEECH_INPUT_MENU
),
1118 &speech_input_submenu_model_
);
1122 void RenderViewContextMenu::AppendProtocolHandlerSubMenu() {
1123 const ProtocolHandlerRegistry::ProtocolHandlerList handlers
=
1124 GetHandlersForLinkUrl();
1125 if (handlers
.empty())
1127 size_t max
= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST
-
1128 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
;
1129 for (size_t i
= 0; i
< handlers
.size() && i
<= max
; i
++) {
1130 protocol_handler_submenu_model_
.AddItem(
1131 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
+ i
,
1132 handlers
[i
].title());
1134 protocol_handler_submenu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
1135 protocol_handler_submenu_model_
.AddItem(
1136 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS
,
1137 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH_CONFIGURE
));
1139 menu_model_
.AddSubMenu(
1140 IDC_CONTENT_CONTEXT_OPENLINKWITH
,
1141 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH
),
1142 &protocol_handler_submenu_model_
);
1145 void RenderViewContextMenu::AppendPlatformEditableItems() {
1148 // Menu delegate functions -----------------------------------------------------
1150 bool RenderViewContextMenu::IsCommandIdEnabled(int id
) const {
1151 // If this command is is added by one of our observers, we dispatch it to the
1153 ObserverListBase
<RenderViewContextMenuObserver
>::Iterator
it(observers_
);
1154 RenderViewContextMenuObserver
* observer
;
1155 while ((observer
= it
.GetNext()) != NULL
) {
1156 if (observer
->IsCommandIdSupported(id
))
1157 return observer
->IsCommandIdEnabled(id
);
1160 CoreTabHelper
* core_tab_helper
=
1161 CoreTabHelper::FromWebContents(source_web_contents_
);
1162 int content_restrictions
= 0;
1163 if (core_tab_helper
)
1164 content_restrictions
= core_tab_helper
->content_restrictions();
1165 if (id
== IDC_PRINT
&& (content_restrictions
& CONTENT_RESTRICTION_PRINT
))
1168 if (id
== IDC_SAVE_PAGE
&&
1169 (content_restrictions
& CONTENT_RESTRICTION_SAVE
)) {
1173 // Allow Spell Check language items on sub menu for text area context menu.
1174 if ((id
>= IDC_SPELLCHECK_LANGUAGES_FIRST
) &&
1175 (id
< IDC_SPELLCHECK_LANGUAGES_LAST
)) {
1176 return profile_
->GetPrefs()->GetBoolean(prefs::kEnableContinuousSpellcheck
);
1180 if (id
>= IDC_CONTENT_CONTEXT_CUSTOM_FIRST
&&
1181 id
<= IDC_CONTENT_CONTEXT_CUSTOM_LAST
) {
1182 return IsCustomItemEnabled(params_
.custom_items
, id
);
1186 if (id
>= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST
&&
1187 id
<= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST
) {
1188 return extension_items_
.IsCommandIdEnabled(id
);
1191 if (id
>= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
&&
1192 id
<= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST
) {
1196 IncognitoModePrefs::Availability incognito_avail
=
1197 IncognitoModePrefs::GetAvailability(profile_
->GetPrefs());
1200 return source_web_contents_
->GetController().CanGoBack();
1203 return source_web_contents_
->GetController().CanGoForward();
1206 CoreTabHelper
* core_tab_helper
=
1207 CoreTabHelper::FromWebContents(source_web_contents_
);
1208 if (!core_tab_helper
)
1211 CoreTabHelperDelegate
* core_delegate
= core_tab_helper
->delegate();
1212 return !core_delegate
||
1213 core_delegate
->CanReloadContents(source_web_contents_
);
1216 case IDC_VIEW_SOURCE
:
1217 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE
:
1218 return source_web_contents_
->GetController().CanViewSource();
1220 case IDC_CONTENT_CONTEXT_INSPECTELEMENT
:
1221 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE
:
1222 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP
:
1223 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP
:
1224 return IsDevCommandEnabled(id
);
1226 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO
:
1227 if (source_web_contents_
->GetController().GetActiveEntry() == NULL
)
1229 // Disabled if no browser is associated (e.g. desktop notifications).
1230 if (chrome::FindBrowserWithWebContents(source_web_contents_
) == NULL
)
1234 case IDC_CONTENT_CONTEXT_TRANSLATE
: {
1235 TranslateTabHelper
* translate_tab_helper
=
1236 TranslateTabHelper::FromWebContents(source_web_contents_
);
1237 if (!translate_tab_helper
)
1239 std::string original_lang
=
1240 translate_tab_helper
->GetLanguageState().original_language();
1241 std::string target_lang
= g_browser_process
->GetApplicationLocale();
1242 target_lang
= TranslateDownloadManager::GetLanguageCode(target_lang
);
1243 // Note that we intentionally enable the menu even if the original and
1244 // target languages are identical. This is to give a way to user to
1245 // translate a page that might contains text fragments in a different
1247 return ((params_
.edit_flags
& WebContextMenuData::CanTranslate
) != 0) &&
1248 !original_lang
.empty() && // Did we receive the page language yet?
1249 !translate_tab_helper
->GetLanguageState().IsPageTranslated() &&
1250 !source_web_contents_
->GetInterstitialPage() &&
1251 // There are some application locales which can't be used as a
1252 // target language for translation.
1253 TranslateDownloadManager::IsSupportedLanguage(target_lang
) &&
1254 // Disable on the Instant Extended NTP.
1255 !chrome::IsInstantNTP(source_web_contents_
);
1258 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB
:
1259 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW
:
1260 return params_
.link_url
.is_valid();
1262 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION
:
1263 return params_
.unfiltered_link_url
.is_valid();
1265 case IDC_CONTENT_CONTEXT_SAVELINKAS
: {
1266 PrefService
* local_state
= g_browser_process
->local_state();
1267 DCHECK(local_state
);
1268 // Test if file-selection dialogs are forbidden by policy.
1269 if (!local_state
->GetBoolean(prefs::kAllowFileSelectionDialogs
))
1272 return params_
.link_url
.is_valid() &&
1273 ProfileIOData::IsHandledProtocol(params_
.link_url
.scheme());
1276 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS
: {
1277 PrefService
* local_state
= g_browser_process
->local_state();
1278 DCHECK(local_state
);
1279 // Test if file-selection dialogs are forbidden by policy.
1280 if (!local_state
->GetBoolean(prefs::kAllowFileSelectionDialogs
))
1283 return params_
.src_url
.is_valid() &&
1284 ProfileIOData::IsHandledProtocol(params_
.src_url
.scheme());
1287 // The images shown in the most visited thumbnails can't be opened or
1288 // searched for conventionally.
1289 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB
:
1290 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE
:
1291 return params_
.src_url
.is_valid() &&
1292 (params_
.src_url
.scheme() != content::kChromeUIScheme
);
1294 case IDC_CONTENT_CONTEXT_COPYIMAGE
:
1295 return params_
.has_image_contents
;
1297 // Media control commands should all be disabled if the player is in an
1299 case IDC_CONTENT_CONTEXT_PLAYPAUSE
:
1300 case IDC_CONTENT_CONTEXT_LOOP
:
1301 return (params_
.media_flags
&
1302 WebContextMenuData::MediaInError
) == 0;
1304 // Mute and unmute should also be disabled if the player has no audio.
1305 case IDC_CONTENT_CONTEXT_MUTE
:
1306 return (params_
.media_flags
&
1307 WebContextMenuData::MediaHasAudio
) != 0 &&
1308 (params_
.media_flags
&
1309 WebContextMenuData::MediaInError
) == 0;
1311 // Media controls can be toggled only for video player. If we toggle
1312 // controls for audio then the player disappears, and there is no way to
1314 case IDC_CONTENT_CONTEXT_CONTROLS
:
1315 return (params_
.media_flags
&
1316 WebContextMenuData::MediaHasVideo
) != 0;
1318 case IDC_CONTENT_CONTEXT_ROTATECW
:
1319 case IDC_CONTENT_CONTEXT_ROTATECCW
:
1321 (params_
.media_flags
& WebContextMenuData::MediaCanRotate
) != 0;
1323 case IDC_CONTENT_CONTEXT_COPYAVLOCATION
:
1324 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION
:
1325 return params_
.src_url
.is_valid();
1327 case IDC_CONTENT_CONTEXT_SAVEAVAS
: {
1328 PrefService
* local_state
= g_browser_process
->local_state();
1329 DCHECK(local_state
);
1330 // Test if file-selection dialogs are forbidden by policy.
1331 if (!local_state
->GetBoolean(prefs::kAllowFileSelectionDialogs
))
1334 const GURL
& url
= params_
.src_url
;
1336 (params_
.media_flags
& WebContextMenuData::MediaCanSave
) &&
1337 url
.is_valid() && ProfileIOData::IsHandledProtocol(url
.scheme());
1338 #if defined(ENABLE_FULL_PRINTING)
1339 // Do not save the preview PDF on the print preview page.
1340 can_save
= can_save
&&
1341 !(printing::PrintPreviewDialogController::IsPrintPreviewURL(url
));
1346 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB
:
1349 case IDC_SAVE_PAGE
: {
1350 CoreTabHelper
* core_tab_helper
=
1351 CoreTabHelper::FromWebContents(source_web_contents_
);
1352 if (!core_tab_helper
)
1355 CoreTabHelperDelegate
* core_delegate
= core_tab_helper
->delegate();
1356 if (core_delegate
&&
1357 !core_delegate
->CanSaveContents(source_web_contents_
))
1360 PrefService
* local_state
= g_browser_process
->local_state();
1361 DCHECK(local_state
);
1362 // Test if file-selection dialogs are forbidden by policy.
1363 if (!local_state
->GetBoolean(prefs::kAllowFileSelectionDialogs
))
1366 // Instead of using GetURL here, we use url() (which is the "real" url of
1367 // the page) from the NavigationEntry because its reflects their origin
1368 // rather than the display one (returned by GetURL) which may be
1369 // different (like having "view-source:" on the front).
1370 // TODO(nasko): Audit all GetActiveEntry calls in this file.
1371 NavigationEntry
* active_entry
=
1372 source_web_contents_
->GetController().GetActiveEntry();
1373 return content::IsSavableURL(
1374 (active_entry
) ? active_entry
->GetURL() : GURL());
1377 case IDC_CONTENT_CONTEXT_RELOADFRAME
:
1378 return params_
.frame_url
.is_valid();
1380 case IDC_CONTENT_CONTEXT_UNDO
:
1381 return !!(params_
.edit_flags
& WebContextMenuData::CanUndo
);
1383 case IDC_CONTENT_CONTEXT_REDO
:
1384 return !!(params_
.edit_flags
& WebContextMenuData::CanRedo
);
1386 case IDC_CONTENT_CONTEXT_CUT
:
1387 return !!(params_
.edit_flags
& WebContextMenuData::CanCut
);
1389 case IDC_CONTENT_CONTEXT_COPY
:
1390 return !!(params_
.edit_flags
& WebContextMenuData::CanCopy
);
1392 case IDC_CONTENT_CONTEXT_PASTE
:
1393 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE
:
1394 return !!(params_
.edit_flags
& WebContextMenuData::CanPaste
);
1396 case IDC_CONTENT_CONTEXT_DELETE
:
1397 return !!(params_
.edit_flags
& WebContextMenuData::CanDelete
);
1399 case IDC_CONTENT_CONTEXT_SELECTALL
:
1400 return !!(params_
.edit_flags
& WebContextMenuData::CanSelectAll
);
1402 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD
:
1403 return !profile_
->IsOffTheRecord() && params_
.link_url
.is_valid() &&
1404 incognito_avail
!= IncognitoModePrefs::DISABLED
;
1407 return profile_
->GetPrefs()->GetBoolean(prefs::kPrintingEnabled
) &&
1408 (params_
.media_type
== WebContextMenuData::MediaTypeNone
||
1409 params_
.media_flags
& WebContextMenuData::MediaCanPrint
);
1411 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR
:
1412 case IDC_CONTENT_CONTEXT_GOTOURL
:
1413 case IDC_SPELLPANEL_TOGGLE
:
1414 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS
:
1416 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO
:
1417 // Disabled if no browser is associated (e.g. desktop notifications).
1418 if (chrome::FindBrowserWithWebContents(source_web_contents_
) == NULL
)
1422 case IDC_CHECK_SPELLING_WHILE_TYPING
:
1423 return profile_
->GetPrefs()->GetBoolean(
1424 prefs::kEnableContinuousSpellcheck
);
1426 #if !defined(OS_MACOSX) && defined(OS_POSIX)
1427 // TODO(suzhe): this should not be enabled for password fields.
1428 case IDC_INPUT_METHODS_MENU
:
1432 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE
:
1433 return !params_
.keyword_url
.is_empty();
1435 case IDC_SPELLCHECK_MENU
:
1438 case IDC_CONTENT_CONTEXT_SPEECH_INPUT_FILTER_PROFANITIES
:
1439 case IDC_CONTENT_CONTEXT_SPEECH_INPUT_ABOUT
:
1440 case IDC_SPEECH_INPUT_MENU
:
1443 case IDC_CONTENT_CONTEXT_OPENLINKWITH
:
1446 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS
:
1455 bool RenderViewContextMenu::IsCommandIdChecked(int id
) const {
1456 // If this command is is added by one of our observers, we dispatch it to the
1458 ObserverListBase
<RenderViewContextMenuObserver
>::Iterator
it(observers_
);
1459 RenderViewContextMenuObserver
* observer
;
1460 while ((observer
= it
.GetNext()) != NULL
) {
1461 if (observer
->IsCommandIdSupported(id
))
1462 return observer
->IsCommandIdChecked(id
);
1465 // See if the video is set to looping.
1466 if (id
== IDC_CONTENT_CONTEXT_LOOP
) {
1467 return (params_
.media_flags
&
1468 WebContextMenuData::MediaLoop
) != 0;
1471 if (id
== IDC_CONTENT_CONTEXT_CONTROLS
) {
1472 return (params_
.media_flags
&
1473 WebContextMenuData::MediaControls
) != 0;
1477 if (id
>= IDC_CONTENT_CONTEXT_CUSTOM_FIRST
&&
1478 id
<= IDC_CONTENT_CONTEXT_CUSTOM_LAST
) {
1479 return IsCustomItemChecked(params_
.custom_items
, id
);
1483 if (id
>= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST
&&
1484 id
<= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST
) {
1485 return extension_items_
.IsCommandIdChecked(id
);
1488 #if defined(ENABLE_INPUT_SPEECH)
1489 // Check box for menu item 'Block offensive words'.
1490 if (id
== IDC_CONTENT_CONTEXT_SPEECH_INPUT_FILTER_PROFANITIES
) {
1491 return profile_
->GetPrefs()->GetBoolean(
1492 prefs::kSpeechRecognitionFilterProfanities
);
1499 void RenderViewContextMenu::ExecuteCommand(int id
, int event_flags
) {
1500 command_executed_
= true;
1501 // If this command is is added by one of our observers, we dispatch it to the
1503 ObserverListBase
<RenderViewContextMenuObserver
>::Iterator
it(observers_
);
1504 RenderViewContextMenuObserver
* observer
;
1505 while ((observer
= it
.GetNext()) != NULL
) {
1506 if (observer
->IsCommandIdSupported(id
))
1507 return observer
->ExecuteCommand(id
);
1512 RenderViewHost
* rvh
= source_web_contents_
->GetRenderViewHost();
1514 // Process custom actions range.
1515 if (id
>= IDC_CONTENT_CONTEXT_CUSTOM_FIRST
&&
1516 id
<= IDC_CONTENT_CONTEXT_CUSTOM_LAST
) {
1517 unsigned action
= id
- IDC_CONTENT_CONTEXT_CUSTOM_FIRST
;
1518 const content::CustomContextMenuContext
& context
= params_
.custom_context
;
1519 #if defined(ENABLE_PLUGINS)
1520 if (context
.request_id
&& !context
.is_pepper_menu
) {
1521 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins(
1522 source_web_contents_
, false, std::string());
1525 RenderFrameHost
* render_frame_host
=
1526 RenderFrameHost::FromID(render_process_id_
, render_frame_id_
);
1527 if (render_frame_host
)
1528 render_frame_host
->ExecuteCustomContextMenuCommand(action
, context
);
1532 // Process extension menu items.
1533 if (id
>= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST
&&
1534 id
<= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST
) {
1535 extension_items_
.ExecuteCommand(id
, source_web_contents_
, params_
);
1539 if (id
>= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
&&
1540 id
<= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST
) {
1541 ProtocolHandlerRegistry::ProtocolHandlerList handlers
=
1542 GetHandlersForLinkUrl();
1543 if (handlers
.empty()) {
1546 content::RecordAction(
1547 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Open"));
1548 int handlerIndex
= id
- IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
;
1549 WindowOpenDisposition disposition
=
1550 ForceNewTabDispositionFromEventFlags(event_flags
);
1552 handlers
[handlerIndex
].TranslateUrl(params_
.link_url
),
1553 params_
.frame_url
.is_empty() ? params_
.page_url
: params_
.frame_url
,
1556 content::PAGE_TRANSITION_LINK
);
1561 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB
: {
1563 chrome::FindBrowserWithWebContents(source_web_contents_
);
1566 params_
.frame_url
.is_empty() ? params_
.page_url
: params_
.frame_url
,
1568 !browser
|| browser
->is_app() ?
1569 NEW_FOREGROUND_TAB
: NEW_BACKGROUND_TAB
,
1570 content::PAGE_TRANSITION_LINK
);
1573 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW
:
1576 params_
.frame_url
.is_empty() ? params_
.page_url
: params_
.frame_url
,
1578 NEW_WINDOW
, content::PAGE_TRANSITION_LINK
);
1581 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD
:
1582 OpenURL(params_
.link_url
,
1586 content::PAGE_TRANSITION_LINK
);
1589 case IDC_CONTENT_CONTEXT_SAVELINKAS
: {
1590 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU
);
1591 const GURL
& referrer
=
1592 params_
.frame_url
.is_empty() ? params_
.page_url
: params_
.frame_url
;
1593 const GURL
& url
= params_
.link_url
;
1594 DownloadManager
* dlm
= BrowserContext::GetDownloadManager(profile_
);
1595 scoped_ptr
<DownloadUrlParameters
> dl_params(
1596 DownloadUrlParameters::FromWebContents(source_web_contents_
, url
));
1597 dl_params
->set_referrer(
1598 content::Referrer(referrer
, params_
.referrer_policy
));
1599 dl_params
->set_referrer_encoding(params_
.frame_charset
);
1600 dl_params
->set_prompt(true);
1601 dlm
->DownloadUrl(dl_params
.Pass());
1605 case IDC_CONTENT_CONTEXT_SAVEAVAS
:
1606 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS
: {
1607 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU
);
1608 const GURL
& referrer
=
1609 params_
.frame_url
.is_empty() ? params_
.page_url
: params_
.frame_url
;
1610 const GURL
& url
= params_
.src_url
;
1612 if (url
== source_web_contents_
->GetURL()) {
1613 const NavigationEntry
* entry
=
1614 source_web_contents_
->GetController().GetActiveEntry();
1616 post_id
= entry
->GetPostID();
1618 DownloadManager
* dlm
= BrowserContext::GetDownloadManager(profile_
);
1619 scoped_ptr
<DownloadUrlParameters
> dl_params(
1620 DownloadUrlParameters::FromWebContents(source_web_contents_
, url
));
1621 dl_params
->set_referrer(
1622 content::Referrer(referrer
, params_
.referrer_policy
));
1623 dl_params
->set_post_id(post_id
);
1624 dl_params
->set_prefer_cache(true);
1626 dl_params
->set_method("POST");
1627 dl_params
->set_prompt(true);
1628 dlm
->DownloadUrl(dl_params
.Pass());
1632 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION
:
1633 WriteURLToClipboard(params_
.unfiltered_link_url
);
1636 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION
:
1637 case IDC_CONTENT_CONTEXT_COPYAVLOCATION
:
1638 WriteURLToClipboard(params_
.src_url
);
1641 case IDC_CONTENT_CONTEXT_COPYIMAGE
:
1642 CopyImageAt(params_
.x
, params_
.y
);
1645 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE
:
1646 GetImageThumbnailForSearch();
1649 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB
:
1650 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB
:
1653 params_
.frame_url
.is_empty() ? params_
.page_url
: params_
.frame_url
,
1655 NEW_BACKGROUND_TAB
, content::PAGE_TRANSITION_LINK
);
1658 case IDC_CONTENT_CONTEXT_PLAYPAUSE
: {
1659 bool play
= !!(params_
.media_flags
& WebContextMenuData::MediaPaused
);
1661 content::RecordAction(UserMetricsAction("MediaContextMenu_Play"));
1663 content::RecordAction(UserMetricsAction("MediaContextMenu_Pause"));
1665 MediaPlayerActionAt(gfx::Point(params_
.x
, params_
.y
),
1666 WebMediaPlayerAction(
1667 WebMediaPlayerAction::Play
, play
));
1671 case IDC_CONTENT_CONTEXT_MUTE
: {
1672 bool mute
= !(params_
.media_flags
& WebContextMenuData::MediaMuted
);
1674 content::RecordAction(UserMetricsAction("MediaContextMenu_Mute"));
1676 content::RecordAction(UserMetricsAction("MediaContextMenu_Unmute"));
1678 MediaPlayerActionAt(gfx::Point(params_
.x
, params_
.y
),
1679 WebMediaPlayerAction(
1680 WebMediaPlayerAction::Mute
, mute
));
1684 case IDC_CONTENT_CONTEXT_LOOP
:
1685 content::RecordAction(UserMetricsAction("MediaContextMenu_Loop"));
1686 MediaPlayerActionAt(gfx::Point(params_
.x
, params_
.y
),
1687 WebMediaPlayerAction(
1688 WebMediaPlayerAction::Loop
,
1689 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_LOOP
)));
1692 case IDC_CONTENT_CONTEXT_CONTROLS
:
1693 content::RecordAction(UserMetricsAction("MediaContextMenu_Controls"));
1694 MediaPlayerActionAt(
1695 gfx::Point(params_
.x
, params_
.y
),
1696 WebMediaPlayerAction(
1697 WebMediaPlayerAction::Controls
,
1698 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_CONTROLS
)));
1701 case IDC_CONTENT_CONTEXT_ROTATECW
:
1702 content::RecordAction(
1703 UserMetricsAction("PluginContextMenu_RotateClockwise"));
1705 gfx::Point(params_
.x
, params_
.y
),
1707 WebPluginAction::Rotate90Clockwise
,
1711 case IDC_CONTENT_CONTEXT_ROTATECCW
:
1712 content::RecordAction(
1713 UserMetricsAction("PluginContextMenu_RotateCounterclockwise"));
1715 gfx::Point(params_
.x
, params_
.y
),
1717 WebPluginAction::Rotate90Counterclockwise
,
1722 source_web_contents_
->GetController().GoBack();
1726 source_web_contents_
->GetController().GoForward();
1730 source_web_contents_
->OnSavePage();
1734 source_web_contents_
->GetController().Reload(true);
1737 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP
: {
1738 const Extension
* platform_app
= GetExtension();
1739 DCHECK(platform_app
);
1740 DCHECK(platform_app
->is_platform_app());
1742 extensions::ExtensionSystem::Get(profile_
)->extension_service()->
1743 ReloadExtension(platform_app
->id());
1747 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP
: {
1748 const Extension
* platform_app
= GetExtension();
1749 DCHECK(platform_app
);
1750 DCHECK(platform_app
->is_platform_app());
1752 apps::AppLoadService::Get(profile_
)->RestartApplication(
1753 platform_app
->id());
1758 #if defined(ENABLE_PRINTING)
1759 if (params_
.media_type
== WebContextMenuData::MediaTypeNone
) {
1760 #if defined(ENABLE_FULL_PRINTING)
1761 printing::PrintViewManager
* print_view_manager
=
1762 printing::PrintViewManager::FromWebContents(source_web_contents_
);
1764 if (!print_view_manager
)
1766 if (profile_
->GetPrefs()->GetBoolean(prefs::kPrintPreviewDisabled
)) {
1767 print_view_manager
->PrintNow();
1769 print_view_manager
->PrintPreviewNow(!params_
.selection_text
.empty());
1772 printing::PrintViewManagerBasic
* print_view_manager
=
1773 printing::PrintViewManagerBasic::FromWebContents(
1774 source_web_contents_
);
1775 if (!print_view_manager
)
1777 print_view_manager
->PrintNow();
1778 #endif // defined(ENABLE_FULL_PRINTING)
1780 rvh
->Send(new PrintMsg_PrintNodeUnderContextMenu(rvh
->GetRoutingID()));
1782 #endif // defined(ENABLE_PRINTING)
1785 case IDC_VIEW_SOURCE
:
1786 source_web_contents_
->ViewSource();
1789 case IDC_CONTENT_CONTEXT_INSPECTELEMENT
:
1790 Inspect(params_
.x
, params_
.y
);
1793 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE
: {
1794 const Extension
* platform_app
= GetExtension();
1795 DCHECK(platform_app
);
1796 DCHECK(platform_app
->is_platform_app());
1798 extensions::devtools_util::InspectBackgroundPage(platform_app
, profile_
);
1802 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO
: {
1803 NavigationController
* controller
= &source_web_contents_
->GetController();
1804 // Important to use GetVisibleEntry to match what's showing in the
1806 NavigationEntry
* nav_entry
= controller
->GetVisibleEntry();
1808 chrome::FindBrowserWithWebContents(source_web_contents_
);
1809 chrome::ShowWebsiteSettings(browser
, source_web_contents_
,
1810 nav_entry
->GetURL(), nav_entry
->GetSSL());
1814 case IDC_CONTENT_CONTEXT_TRANSLATE
: {
1815 // A translation might have been triggered by the time the menu got
1816 // selected, do nothing in that case.
1817 TranslateTabHelper
* translate_tab_helper
=
1818 TranslateTabHelper::FromWebContents(source_web_contents_
);
1819 if (!translate_tab_helper
||
1820 translate_tab_helper
->GetLanguageState().IsPageTranslated() ||
1821 translate_tab_helper
->GetLanguageState().translation_pending()) {
1824 std::string original_lang
=
1825 translate_tab_helper
->GetLanguageState().original_language();
1826 std::string target_lang
= g_browser_process
->GetApplicationLocale();
1827 target_lang
= TranslateDownloadManager::GetLanguageCode(target_lang
);
1828 // Since the user decided to translate for that language and site, clears
1829 // any preferences for not translating them.
1830 scoped_ptr
<TranslatePrefs
> prefs(
1831 TranslateTabHelper::CreateTranslatePrefs(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 base::string16
keyword(
1932 TemplateURLService::GenerateKeyword(params_
.page_url
));
1933 TemplateURLData data
;
1934 data
.short_name
= keyword
;
1935 data
.SetKeyword(keyword
);
1936 data
.SetURL(params_
.keyword_url
.spec());
1938 TemplateURL::GenerateFaviconURL(params_
.page_url
.GetOrigin());
1939 // Takes ownership of the TemplateURL.
1940 search_engine_tab_helper
->delegate()->
1941 ConfirmAddSearchProvider(new TemplateURL(profile_
, data
), profile_
);
1946 #if defined(ENABLE_INPUT_SPEECH)
1947 case IDC_CONTENT_CONTEXT_SPEECH_INPUT_FILTER_PROFANITIES
: {
1948 profile_
->GetPrefs()->SetBoolean(
1949 prefs::kSpeechRecognitionFilterProfanities
,
1950 !profile_
->GetPrefs()->GetBoolean(
1951 prefs::kSpeechRecognitionFilterProfanities
));
1955 case IDC_CONTENT_CONTEXT_SPEECH_INPUT_ABOUT
: {
1956 GURL
url(chrome::kSpeechInputAboutURL
);
1957 GURL localized_url
= google_util::AppendGoogleLocaleParam(url
);
1958 // Open URL with no referrer field (because user clicked on menu item).
1959 OpenURL(localized_url
, GURL(), 0, NEW_FOREGROUND_TAB
,
1960 content::PAGE_TRANSITION_LINK
);
1970 ProtocolHandlerRegistry::ProtocolHandlerList
1971 RenderViewContextMenu::GetHandlersForLinkUrl() {
1972 ProtocolHandlerRegistry::ProtocolHandlerList handlers
=
1973 protocol_handler_registry_
->GetHandlersFor(params_
.link_url
.scheme());
1974 std::sort(handlers
.begin(), handlers
.end());
1978 void RenderViewContextMenu::MenuWillShow(ui::SimpleMenuModel
* source
) {
1979 for (int i
= 0; i
< source
->GetItemCount(); ++i
) {
1980 if (source
->IsVisibleAt(i
) &&
1981 source
->GetTypeAt(i
) != ui::MenuModel::TYPE_SEPARATOR
) {
1982 RecordShownItem(source
->GetCommandIdAt(i
));
1986 // Ignore notifications from submenus.
1987 if (source
!= &menu_model_
)
1990 content::RenderWidgetHostView
* view
=
1991 source_web_contents_
->GetRenderWidgetHostView();
1993 view
->SetShowingContextMenu(true);
1995 content::NotificationService::current()->Notify(
1996 chrome::NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN
,
1997 content::Source
<RenderViewContextMenu
>(this),
1998 content::NotificationService::NoDetails());
2001 void RenderViewContextMenu::MenuClosed(ui::SimpleMenuModel
* source
) {
2002 // Ignore notifications from submenus.
2003 if (source
!= &menu_model_
)
2006 content::RenderWidgetHostView
* view
=
2007 source_web_contents_
->GetRenderWidgetHostView();
2009 view
->SetShowingContextMenu(false);
2010 RenderFrameHost
* render_frame_host
=
2011 RenderFrameHost::FromID(render_process_id_
, render_frame_id_
);
2012 if (render_frame_host
)
2013 render_frame_host
->NotifyContextMenuClosed(params_
.custom_context
);
2015 if (!command_executed_
) {
2016 FOR_EACH_OBSERVER(RenderViewContextMenuObserver
,
2022 bool RenderViewContextMenu::IsDevCommandEnabled(int id
) const {
2023 if (id
== IDC_CONTENT_CONTEXT_INSPECTELEMENT
||
2024 id
== IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE
) {
2025 const CommandLine
* command_line
= CommandLine::ForCurrentProcess();
2026 if (!profile_
->GetPrefs()->GetBoolean(prefs::kWebKitJavascriptEnabled
) ||
2027 command_line
->HasSwitch(switches::kDisableJavaScript
))
2030 // Don't enable the web inspector if the developer tools are disabled via
2031 // the preference dev-tools-disabled.
2032 if (profile_
->GetPrefs()->GetBoolean(prefs::kDevToolsDisabled
))
2039 base::string16
RenderViewContextMenu::PrintableSelectionText() {
2040 return gfx::TruncateString(params_
.selection_text
,
2041 kMaxSelectionTextLength
);
2044 // Controller functions --------------------------------------------------------
2046 void RenderViewContextMenu::OpenURL(
2047 const GURL
& url
, const GURL
& referrer
, int64 frame_id
,
2048 WindowOpenDisposition disposition
,
2049 content::PageTransition transition
) {
2050 // Ensure that URL fragment, username and password fields are not sent
2052 GURL
sanitized_referrer(referrer
);
2053 if (sanitized_referrer
.is_valid() && (sanitized_referrer
.has_ref() ||
2054 sanitized_referrer
.has_username() || sanitized_referrer
.has_password())) {
2055 GURL::Replacements referrer_mods
;
2056 referrer_mods
.ClearRef();
2057 referrer_mods
.ClearUsername();
2058 referrer_mods
.ClearPassword();
2059 sanitized_referrer
= sanitized_referrer
.ReplaceComponents(referrer_mods
);
2062 WebContents
* new_contents
= source_web_contents_
->OpenURL(OpenURLParams(
2063 url
, content::Referrer(sanitized_referrer
, params_
.referrer_policy
),
2064 disposition
, transition
, false));
2068 RetargetingDetails details
;
2069 details
.source_web_contents
= source_web_contents_
;
2070 details
.source_frame_id
= frame_id
;
2071 details
.target_url
= url
;
2072 details
.target_web_contents
= new_contents
;
2073 details
.not_yet_in_tabstrip
= false;
2074 content::NotificationService::current()->Notify(
2075 chrome::NOTIFICATION_RETARGETING
,
2076 content::Source
<Profile
>(Profile::FromBrowserContext(
2077 source_web_contents_
->GetBrowserContext())),
2078 content::Details
<RetargetingDetails
>(&details
));
2081 void RenderViewContextMenu::CopyImageAt(int x
, int y
) {
2082 source_web_contents_
->GetRenderViewHost()->CopyImageAt(x
, y
);
2085 void RenderViewContextMenu::GetImageThumbnailForSearch() {
2086 source_web_contents_
->GetRenderViewHost()->Send(
2087 new ChromeViewMsg_RequestThumbnailForContextNode(
2088 source_web_contents_
->GetRenderViewHost()->GetRoutingID(),
2089 kImageSearchThumbnailMinSize
,
2090 gfx::Size(kImageSearchThumbnailMaxWidth
,
2091 kImageSearchThumbnailMaxHeight
)));
2094 void RenderViewContextMenu::Inspect(int x
, int y
) {
2095 content::RecordAction(UserMetricsAction("DevTools_InspectElement"));
2096 source_web_contents_
->GetRenderViewHostAtPosition(
2097 x
, y
, base::Bind(&DevToolsInspectElementAt
));
2100 void RenderViewContextMenu::WriteURLToClipboard(const GURL
& url
) {
2101 chrome_common_net::WriteURLToClipboard(
2103 profile_
->GetPrefs()->GetString(prefs::kAcceptLanguages
),
2104 ui::Clipboard::GetForCurrentThread());
2107 void RenderViewContextMenu::MediaPlayerActionAt(
2108 const gfx::Point
& location
,
2109 const WebMediaPlayerAction
& action
) {
2110 source_web_contents_
->GetRenderViewHost()->
2111 ExecuteMediaPlayerActionAtLocation(location
, action
);
2114 void RenderViewContextMenu::PluginActionAt(
2115 const gfx::Point
& location
,
2116 const WebPluginAction
& action
) {
2117 source_web_contents_
->GetRenderViewHost()->
2118 ExecutePluginActionAtLocation(location
, action
);