1 // Copyright 2014 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/renderer_context_menu/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 "chrome/app/chrome_command_ids.h"
22 #include "chrome/browser/app_mode/app_mode_utils.h"
23 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
24 #include "chrome/browser/browser_process.h"
25 #include "chrome/browser/chrome_notification_types.h"
26 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
27 #include "chrome/browser/devtools/devtools_window.h"
28 #include "chrome/browser/download/download_service.h"
29 #include "chrome/browser/download/download_service_factory.h"
30 #include "chrome/browser/download/download_stats.h"
31 #include "chrome/browser/extensions/devtools_util.h"
32 #include "chrome/browser/extensions/extension_service.h"
33 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h"
34 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings_factory.h"
35 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
36 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
37 #include "chrome/browser/prefs/incognito_mode_prefs.h"
38 #include "chrome/browser/profiles/profile.h"
39 #include "chrome/browser/profiles/profile_io_data.h"
40 #include "chrome/browser/renderer_context_menu/context_menu_content_type_factory.h"
41 #include "chrome/browser/renderer_context_menu/spellchecker_submenu_observer.h"
42 #include "chrome/browser/renderer_context_menu/spelling_menu_observer.h"
43 #include "chrome/browser/search/search.h"
44 #include "chrome/browser/search_engines/template_url_service_factory.h"
45 #include "chrome/browser/spellchecker/spellcheck_host_metrics.h"
46 #include "chrome/browser/spellchecker/spellcheck_service.h"
47 #include "chrome/browser/tab_contents/retargeting_details.h"
48 #include "chrome/browser/translate/chrome_translate_client.h"
49 #include "chrome/browser/translate/translate_service.h"
50 #include "chrome/browser/ui/browser.h"
51 #include "chrome/browser/ui/browser_commands.h"
52 #include "chrome/browser/ui/browser_finder.h"
53 #include "chrome/browser/ui/chrome_pages.h"
54 #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"
55 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
56 #include "chrome/common/chrome_constants.h"
57 #include "chrome/common/chrome_switches.h"
58 #include "chrome/common/content_restriction.h"
59 #include "chrome/common/pref_names.h"
60 #include "chrome/common/render_messages.h"
61 #include "chrome/common/spellcheck_common.h"
62 #include "chrome/common/url_constants.h"
63 #include "chrome/grit/generated_resources.h"
64 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
65 #include "components/google/core/browser/google_util.h"
66 #include "components/metrics/proto/omnibox_input_type.pb.h"
67 #include "components/omnibox/browser/autocomplete_classifier.h"
68 #include "components/omnibox/browser/autocomplete_match.h"
69 #include "components/password_manager/core/common/experiments.h"
70 #include "components/search_engines/template_url.h"
71 #include "components/search_engines/template_url_service.h"
72 #include "components/translate/core/browser/translate_download_manager.h"
73 #include "components/translate/core/browser/translate_manager.h"
74 #include "components/translate/core/browser/translate_prefs.h"
75 #include "components/url_formatter/url_formatter.h"
76 #include "components/user_prefs/user_prefs.h"
77 #include "content/public/browser/child_process_security_policy.h"
78 #include "content/public/browser/download_manager.h"
79 #include "content/public/browser/download_save_info.h"
80 #include "content/public/browser/download_url_parameters.h"
81 #include "content/public/browser/navigation_details.h"
82 #include "content/public/browser/navigation_entry.h"
83 #include "content/public/browser/notification_service.h"
84 #include "content/public/browser/render_frame_host.h"
85 #include "content/public/browser/render_process_host.h"
86 #include "content/public/browser/render_view_host.h"
87 #include "content/public/browser/render_widget_host_view.h"
88 #include "content/public/browser/user_metrics.h"
89 #include "content/public/browser/web_contents.h"
90 #include "content/public/common/menu_item.h"
91 #include "content/public/common/ssl_status.h"
92 #include "content/public/common/url_utils.h"
93 #include "extensions/browser/extension_host.h"
94 #include "extensions/browser/extension_system.h"
95 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
96 #include "extensions/browser/view_type_utils.h"
97 #include "extensions/common/extension.h"
98 #include "net/base/escape.h"
99 #include "third_party/WebKit/public/web/WebContextMenuData.h"
100 #include "third_party/WebKit/public/web/WebMediaPlayerAction.h"
101 #include "third_party/WebKit/public/web/WebPluginAction.h"
102 #include "ui/base/clipboard/clipboard.h"
103 #include "ui/base/clipboard/scoped_clipboard_writer.h"
104 #include "ui/base/l10n/l10n_util.h"
105 #include "ui/gfx/favicon_size.h"
106 #include "ui/gfx/geometry/point.h"
107 #include "ui/gfx/geometry/size.h"
108 #include "ui/gfx/text_elider.h"
110 #if defined(ENABLE_EXTENSIONS)
111 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
114 #if defined(ENABLE_PRINTING)
115 #include "chrome/browser/printing/print_view_manager_common.h"
116 #include "components/printing/common/print_messages.h"
118 #if defined(ENABLE_PRINT_PREVIEW)
119 #include "chrome/browser/printing/print_preview_context_menu_observer.h"
120 #include "chrome/browser/printing/print_preview_dialog_controller.h"
121 #endif // defined(ENABLE_PRINT_PREVIEW)
122 #endif // defined(ENABLE_PRINTING)
124 using base::UserMetricsAction
;
125 using blink::WebContextMenuData
;
126 using blink::WebMediaPlayerAction
;
127 using blink::WebPluginAction
;
128 using blink::WebString
;
130 using content::BrowserContext
;
131 using content::ChildProcessSecurityPolicy
;
132 using content::DownloadManager
;
133 using content::DownloadUrlParameters
;
134 using content::NavigationController
;
135 using content::NavigationEntry
;
136 using content::OpenURLParams
;
137 using content::RenderFrameHost
;
138 using content::RenderViewHost
;
139 using content::SSLStatus
;
140 using content::WebContents
;
141 using extensions::ContextMenuMatcher
;
142 using extensions::Extension
;
143 using extensions::MenuItem
;
144 using extensions::MenuManager
;
148 const int kImageSearchThumbnailMinSize
= 300 * 300;
149 const int kImageSearchThumbnailMaxWidth
= 600;
150 const int kImageSearchThumbnailMaxHeight
= 600;
152 // Maps UMA enumeration to IDC. IDC could be changed so we can't use
153 // just them and |UMA_HISTOGRAM_CUSTOM_ENUMERATION|.
154 // Never change mapping or reuse |enum_id|. Always push back new items.
155 // Items that is not used any more by |RenderViewContextMenu.ExecuteCommand|
156 // could be deleted, but don't change the rest of |kUmaEnumToControlId|.
157 const struct UmaEnumCommandIdPair
{
160 } kUmaEnumToControlId
[] = {
162 enum id for 0, 1 are detected using
163 RenderViewContextMenu::IsContentCustomCommandId and
164 ContextMenuMatcher::IsExtensionsCustomCommandId
166 {2, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
},
167 {3, IDC_CONTENT_CONTEXT_OPENLINKNEWTAB
},
168 {4, IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW
},
169 {5, IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD
},
170 {6, IDC_CONTENT_CONTEXT_SAVELINKAS
},
171 {7, IDC_CONTENT_CONTEXT_SAVEAVAS
},
172 {8, IDC_CONTENT_CONTEXT_SAVEIMAGEAS
},
173 {9, IDC_CONTENT_CONTEXT_COPYLINKLOCATION
},
174 {10, IDC_CONTENT_CONTEXT_COPYIMAGELOCATION
},
175 {11, IDC_CONTENT_CONTEXT_COPYAVLOCATION
},
176 {12, IDC_CONTENT_CONTEXT_COPYIMAGE
},
177 {13, IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB
},
178 {14, IDC_CONTENT_CONTEXT_OPENAVNEWTAB
},
179 {15, IDC_CONTENT_CONTEXT_PLAYPAUSE
},
180 {16, IDC_CONTENT_CONTEXT_MUTE
},
181 {17, IDC_CONTENT_CONTEXT_LOOP
},
182 {18, IDC_CONTENT_CONTEXT_CONTROLS
},
183 {19, IDC_CONTENT_CONTEXT_ROTATECW
},
184 {20, IDC_CONTENT_CONTEXT_ROTATECCW
},
189 {25, IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP
},
190 {26, IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP
},
192 {28, IDC_VIEW_SOURCE
},
193 {29, IDC_CONTENT_CONTEXT_INSPECTELEMENT
},
194 {30, IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE
},
195 {31, IDC_CONTENT_CONTEXT_VIEWPAGEINFO
},
196 {32, IDC_CONTENT_CONTEXT_TRANSLATE
},
197 {33, IDC_CONTENT_CONTEXT_RELOADFRAME
},
198 {34, IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE
},
199 {35, IDC_CONTENT_CONTEXT_VIEWFRAMEINFO
},
200 {36, IDC_CONTENT_CONTEXT_UNDO
},
201 {37, IDC_CONTENT_CONTEXT_REDO
},
202 {38, IDC_CONTENT_CONTEXT_CUT
},
203 {39, IDC_CONTENT_CONTEXT_COPY
},
204 {40, IDC_CONTENT_CONTEXT_PASTE
},
205 {41, IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE
},
206 {42, IDC_CONTENT_CONTEXT_DELETE
},
207 {43, IDC_CONTENT_CONTEXT_SELECTALL
},
208 {44, IDC_CONTENT_CONTEXT_SEARCHWEBFOR
},
209 {45, IDC_CONTENT_CONTEXT_GOTOURL
},
210 {46, IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS
},
211 {47, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS
},
212 {48, IDC_CONTENT_CONTEXT_ADDSEARCHENGINE
},
213 {52, IDC_CONTENT_CONTEXT_OPENLINKWITH
},
214 {53, IDC_CHECK_SPELLING_WHILE_TYPING
},
215 {54, IDC_SPELLCHECK_MENU
},
216 {55, IDC_CONTENT_CONTEXT_SPELLING_TOGGLE
},
217 {56, IDC_SPELLCHECK_LANGUAGES_FIRST
},
218 {57, IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE
},
219 {58, IDC_SPELLCHECK_SUGGESTION_0
},
220 {59, IDC_SPELLCHECK_ADD_TO_DICTIONARY
},
221 {60, IDC_SPELLPANEL_TOGGLE
},
222 {61, IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB
},
223 {62, IDC_WRITING_DIRECTION_MENU
},
224 {63, IDC_WRITING_DIRECTION_DEFAULT
},
225 {64, IDC_WRITING_DIRECTION_LTR
},
226 {65, IDC_WRITING_DIRECTION_RTL
},
227 {66, IDC_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE
},
228 {67, IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD
},
229 // Add new items here and use |enum_id| from the next line.
230 // Also, add new items to RenderViewContextMenuItem enum in histograms.xml.
231 {68, 0}, // Must be the last. Increment |enum_id| when new IDC was added.
234 // Collapses large ranges of ids before looking for UMA enum.
235 int CollapseCommandsForUMA(int id
) {
236 DCHECK(!RenderViewContextMenu::IsContentCustomCommandId(id
));
237 DCHECK(!ContextMenuMatcher::IsExtensionsCustomCommandId(id
));
239 if (id
>= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
&&
240 id
<= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST
) {
241 return IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
;
244 if (id
>= IDC_SPELLCHECK_LANGUAGES_FIRST
&&
245 id
<= IDC_SPELLCHECK_LANGUAGES_LAST
) {
246 return IDC_SPELLCHECK_LANGUAGES_FIRST
;
249 if (id
>= IDC_SPELLCHECK_SUGGESTION_0
&&
250 id
<= IDC_SPELLCHECK_SUGGESTION_LAST
) {
251 return IDC_SPELLCHECK_SUGGESTION_0
;
257 // Returns UMA enum value for command specified by |id| or -1 if not found.
258 int FindUMAEnumValueForCommand(int id
) {
259 if (RenderViewContextMenu::IsContentCustomCommandId(id
))
262 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id
))
265 id
= CollapseCommandsForUMA(id
);
266 const size_t kMappingSize
= arraysize(kUmaEnumToControlId
);
267 for (size_t i
= 0; i
< kMappingSize
; ++i
) {
268 if (kUmaEnumToControlId
[i
].control_id
== id
) {
269 return kUmaEnumToControlId
[i
].enum_id
;
275 // Usually a new tab is expected where this function is used,
276 // however users should be able to open a tab in background
277 // or in a new window.
278 WindowOpenDisposition
ForceNewTabDispositionFromEventFlags(
280 WindowOpenDisposition disposition
=
281 ui::DispositionFromEventFlags(event_flags
);
282 return disposition
== CURRENT_TAB
? NEW_FOREGROUND_TAB
: disposition
;
285 // Returns the preference of the profile represented by the |context|.
286 PrefService
* GetPrefs(content::BrowserContext
* context
) {
287 return user_prefs::UserPrefs::Get(context
);
290 bool ExtensionPatternMatch(const extensions::URLPatternSet
& patterns
,
292 // No patterns means no restriction, so that implicitly matches.
293 if (patterns
.is_empty())
295 return patterns
.MatchesURL(url
);
298 const GURL
& GetDocumentURL(const content::ContextMenuParams
& params
) {
299 return params
.frame_url
.is_empty() ? params
.page_url
: params
.frame_url
;
302 content::Referrer
CreateSaveAsReferrer(
304 const content::ContextMenuParams
& params
) {
305 const GURL
& referring_url
= GetDocumentURL(params
);
306 return content::Referrer::SanitizeForRequest(
308 content::Referrer(referring_url
.GetAsReferrer(), params
.referrer_policy
));
311 content::WebContents
* GetWebContentsToUse(content::WebContents
* web_contents
) {
312 #if defined(ENABLE_EXTENSIONS)
313 // If we're viewing in a MimeHandlerViewGuest, use its embedder WebContents.
314 if (extensions::MimeHandlerViewGuest::FromWebContents(web_contents
)) {
315 WebContents
* top_level_web_contents
=
316 guest_view::GuestViewBase::GetTopLevelWebContents(web_contents
);
317 if (top_level_web_contents
)
318 return top_level_web_contents
;
324 void WriteURLToClipboard(const GURL
& url
, const std::string
& languages
) {
325 if (url
.is_empty() || !url
.is_valid())
328 // Unescaping path and query is not a good idea because other applications
329 // may not encode non-ASCII characters in UTF-8. See crbug.com/2820.
330 base::string16 text
=
331 url
.SchemeIs(url::kMailToScheme
)
332 ? base::ASCIIToUTF16(url
.path())
333 : url_formatter::FormatUrl(
334 url
, languages
, url_formatter::kFormatUrlOmitNothing
,
335 net::UnescapeRule::NONE
, nullptr, nullptr, nullptr);
337 ui::ScopedClipboardWriter
scw(ui::CLIPBOARD_TYPE_COPY_PASTE
);
341 bool g_custom_id_ranges_initialized
= false;
343 const int kSpellcheckRadioGroup
= 1;
348 gfx::Vector2d
RenderViewContextMenu::GetOffset(
349 RenderFrameHost
* render_frame_host
) {
350 gfx::Vector2d offset
;
351 #if defined(ENABLE_EXTENSIONS)
352 WebContents
* web_contents
=
353 WebContents::FromRenderFrameHost(render_frame_host
);
354 WebContents
* top_level_web_contents
=
355 guest_view::GuestViewBase::GetTopLevelWebContents(web_contents
);
356 if (web_contents
&& top_level_web_contents
&&
357 web_contents
!= top_level_web_contents
) {
358 gfx::Rect bounds
= web_contents
->GetContainerBounds();
359 gfx::Rect top_level_bounds
= top_level_web_contents
->GetContainerBounds();
360 offset
= bounds
.origin() - top_level_bounds
.origin();
362 #endif // defined(ENABLE_EXTENSIONS)
367 bool RenderViewContextMenu::IsDevToolsURL(const GURL
& url
) {
368 return url
.SchemeIs(content::kChromeDevToolsScheme
);
372 bool RenderViewContextMenu::IsInternalResourcesURL(const GURL
& url
) {
373 if (!url
.SchemeIs(content::kChromeUIScheme
))
375 return url
.host() == chrome::kChromeUISyncResourcesHost
;
378 RenderViewContextMenu::RenderViewContextMenu(
379 content::RenderFrameHost
* render_frame_host
,
380 const content::ContextMenuParams
& params
)
381 : RenderViewContextMenuBase(render_frame_host
, params
),
382 extension_items_(browser_context_
,
385 base::Bind(MenuItemMatchesParams
, params_
)),
386 protocol_handler_submenu_model_(this),
387 protocol_handler_registry_(
388 ProtocolHandlerRegistryFactory::GetForBrowserContext(GetProfile())),
389 embedder_web_contents_(GetWebContentsToUse(source_web_contents_
)) {
390 if (!g_custom_id_ranges_initialized
) {
391 g_custom_id_ranges_initialized
= true;
392 SetContentCustomCommandIdRange(IDC_CONTENT_CONTEXT_CUSTOM_FIRST
,
393 IDC_CONTENT_CONTEXT_CUSTOM_LAST
);
395 set_content_type(ContextMenuContentTypeFactory::Create(
396 source_web_contents_
, params
));
399 RenderViewContextMenu::~RenderViewContextMenu() {
402 // Menu construction functions -------------------------------------------------
404 #if defined(ENABLE_EXTENSIONS)
406 bool RenderViewContextMenu::ExtensionContextAndPatternMatch(
407 const content::ContextMenuParams
& params
,
408 const MenuItem::ContextList
& contexts
,
409 const extensions::URLPatternSet
& target_url_patterns
) {
410 const bool has_link
= !params
.link_url
.is_empty();
411 const bool has_selection
= !params
.selection_text
.empty();
412 const bool in_frame
= !params
.frame_url
.is_empty();
414 if (contexts
.Contains(MenuItem::ALL
) ||
415 (has_selection
&& contexts
.Contains(MenuItem::SELECTION
)) ||
416 (params
.is_editable
&& contexts
.Contains(MenuItem::EDITABLE
)) ||
417 (in_frame
&& contexts
.Contains(MenuItem::FRAME
)))
420 if (has_link
&& contexts
.Contains(MenuItem::LINK
) &&
421 ExtensionPatternMatch(target_url_patterns
, params
.link_url
))
424 switch (params
.media_type
) {
425 case WebContextMenuData::MediaTypeImage
:
426 if (contexts
.Contains(MenuItem::IMAGE
) &&
427 ExtensionPatternMatch(target_url_patterns
, params
.src_url
))
431 case WebContextMenuData::MediaTypeVideo
:
432 if (contexts
.Contains(MenuItem::VIDEO
) &&
433 ExtensionPatternMatch(target_url_patterns
, params
.src_url
))
437 case WebContextMenuData::MediaTypeAudio
:
438 if (contexts
.Contains(MenuItem::AUDIO
) &&
439 ExtensionPatternMatch(target_url_patterns
, params
.src_url
))
447 // PAGE is the least specific context, so we only examine that if none of the
448 // other contexts apply (except for FRAME, which is included in PAGE for
449 // backwards compatibility).
450 if (!has_link
&& !has_selection
&& !params
.is_editable
&&
451 params
.media_type
== WebContextMenuData::MediaTypeNone
&&
452 contexts
.Contains(MenuItem::PAGE
))
459 bool RenderViewContextMenu::MenuItemMatchesParams(
460 const content::ContextMenuParams
& params
,
461 const extensions::MenuItem
* item
) {
462 bool match
= ExtensionContextAndPatternMatch(params
, item
->contexts(),
463 item
->target_url_patterns());
467 const GURL
& document_url
= GetDocumentURL(params
);
468 return ExtensionPatternMatch(item
->document_url_patterns(), document_url
);
471 void RenderViewContextMenu::AppendAllExtensionItems() {
472 extension_items_
.Clear();
473 ExtensionService
* service
=
474 extensions::ExtensionSystem::Get(browser_context_
)->extension_service();
476 return; // In unit-tests, we may not have an ExtensionService.
478 MenuManager
* menu_manager
= MenuManager::Get(browser_context_
);
482 base::string16 printable_selection_text
= PrintableSelectionText();
483 EscapeAmpersands(&printable_selection_text
);
485 // Get a list of extension id's that have context menu items, and sort by the
486 // top level context menu title of the extension.
487 std::set
<MenuItem::ExtensionKey
> ids
= menu_manager
->ExtensionIds();
488 std::vector
<base::string16
> sorted_menu_titles
;
489 std::map
<base::string16
, std::vector
<const Extension
*>>
490 title_to_extensions_map
;
491 for (std::set
<MenuItem::ExtensionKey
>::iterator iter
= ids
.begin();
494 const Extension
* extension
=
495 service
->GetExtensionById(iter
->extension_id
, false);
496 // Platform apps have their context menus created directly in
497 // AppendPlatformAppItems.
498 if (extension
&& !extension
->is_platform_app()) {
499 base::string16 menu_title
= extension_items_
.GetTopLevelContextMenuTitle(
500 *iter
, printable_selection_text
);
501 title_to_extensions_map
[menu_title
].push_back(extension
);
502 sorted_menu_titles
.push_back(menu_title
);
505 if (sorted_menu_titles
.empty())
508 const std::string app_locale
= g_browser_process
->GetApplicationLocale();
509 l10n_util::SortStrings16(app_locale
, &sorted_menu_titles
);
510 sorted_menu_titles
.erase(
511 std::unique(sorted_menu_titles
.begin(), sorted_menu_titles
.end()),
512 sorted_menu_titles
.end());
515 for (size_t i
= 0; i
< sorted_menu_titles
.size(); ++i
) {
516 std::vector
<const Extension
*>& extensions
=
517 title_to_extensions_map
[sorted_menu_titles
[i
]];
518 for (const auto& extension
: extensions
) {
519 MenuItem::ExtensionKey
extension_key(extension
->id());
520 extension_items_
.AppendExtensionItems(extension_key
,
521 printable_selection_text
, &index
,
522 false); // is_action_menu
527 void RenderViewContextMenu::AppendCurrentExtensionItems() {
528 // Avoid appending extension related items when |extension| is null.
529 // For Panel, this happens when the panel is navigated to a url outside of the
530 // extension's package.
531 const Extension
* extension
= GetExtension();
535 extensions::WebViewGuest
* web_view_guest
=
536 extensions::WebViewGuest::FromWebContents(source_web_contents_
);
537 MenuItem::ExtensionKey key
;
538 if (web_view_guest
) {
539 key
= MenuItem::ExtensionKey(
541 web_view_guest
->owner_web_contents()->GetRenderProcessHost()->GetID(),
542 web_view_guest
->view_instance_id());
544 key
= MenuItem::ExtensionKey(extension
->id());
547 // Only add extension items from this extension.
549 extension_items_
.AppendExtensionItems(key
, PrintableSelectionText(), &index
,
550 false /* is_action_menu */);
552 #endif // defined(ENABLE_EXTENSIONS)
554 void RenderViewContextMenu::InitMenu() {
555 RenderViewContextMenuBase::InitMenu();
557 if (content_type_
->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PAGE
))
560 if (content_type_
->SupportsGroup(ContextMenuContentType::ITEM_GROUP_FRAME
)) {
561 // Merge in frame items with page items if we clicked within a frame that
563 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
567 if (content_type_
->SupportsGroup(ContextMenuContentType::ITEM_GROUP_LINK
)) {
569 if (params_
.media_type
!= WebContextMenuData::MediaTypeNone
)
570 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
573 if (content_type_
->SupportsGroup(
574 ContextMenuContentType::ITEM_GROUP_MEDIA_IMAGE
)) {
578 if (content_type_
->SupportsGroup(
579 ContextMenuContentType::ITEM_GROUP_SEARCHWEBFORIMAGE
)) {
580 AppendSearchWebForImageItems();
583 if (content_type_
->SupportsGroup(
584 ContextMenuContentType::ITEM_GROUP_MEDIA_VIDEO
)) {
588 if (content_type_
->SupportsGroup(
589 ContextMenuContentType::ITEM_GROUP_MEDIA_AUDIO
)) {
593 if (content_type_
->SupportsGroup(
594 ContextMenuContentType::ITEM_GROUP_MEDIA_CANVAS
)) {
598 if (content_type_
->SupportsGroup(
599 ContextMenuContentType::ITEM_GROUP_MEDIA_PLUGIN
)) {
603 // ITEM_GROUP_MEDIA_FILE has no specific items.
605 if (content_type_
->SupportsGroup(ContextMenuContentType::ITEM_GROUP_EDITABLE
))
606 AppendEditableItems();
608 if (content_type_
->SupportsGroup(ContextMenuContentType::ITEM_GROUP_COPY
)) {
609 DCHECK(!content_type_
->SupportsGroup(
610 ContextMenuContentType::ITEM_GROUP_EDITABLE
));
614 if (content_type_
->SupportsGroup(
615 ContextMenuContentType::ITEM_GROUP_SEARCH_PROVIDER
)) {
616 AppendSearchProvider();
619 if (content_type_
->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT
))
622 if (content_type_
->SupportsGroup(
623 ContextMenuContentType::ITEM_GROUP_MEDIA_PLUGIN
)) {
624 AppendRotationItems();
627 if (content_type_
->SupportsGroup(
628 ContextMenuContentType::ITEM_GROUP_ALL_EXTENSION
)) {
629 DCHECK(!content_type_
->SupportsGroup(
630 ContextMenuContentType::ITEM_GROUP_CURRENT_EXTENSION
));
631 AppendAllExtensionItems();
634 if (content_type_
->SupportsGroup(
635 ContextMenuContentType::ITEM_GROUP_CURRENT_EXTENSION
)) {
636 DCHECK(!content_type_
->SupportsGroup(
637 ContextMenuContentType::ITEM_GROUP_ALL_EXTENSION
));
638 AppendCurrentExtensionItems();
641 if (content_type_
->SupportsGroup(
642 ContextMenuContentType::ITEM_GROUP_DEVELOPER
)) {
643 AppendDeveloperItems();
646 if (content_type_
->SupportsGroup(
647 ContextMenuContentType::ITEM_GROUP_DEVTOOLS_UNPACKED_EXT
)) {
648 AppendDevtoolsForUnpackedExtensions();
651 if (content_type_
->SupportsGroup(
652 ContextMenuContentType::ITEM_GROUP_PRINT_PREVIEW
)) {
653 AppendPrintPreviewItems();
656 if (content_type_
->SupportsGroup(
657 ContextMenuContentType::ITEM_GROUP_PASSWORD
)) {
658 AppendPasswordItems();
662 Profile
* RenderViewContextMenu::GetProfile() {
663 return Profile::FromBrowserContext(browser_context_
);
666 void RenderViewContextMenu::RecordUsedItem(int id
) {
667 int enum_id
= FindUMAEnumValueForCommand(id
);
669 const size_t kMappingSize
= arraysize(kUmaEnumToControlId
);
670 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Used", enum_id
,
671 kUmaEnumToControlId
[kMappingSize
- 1].enum_id
);
673 NOTREACHED() << "Update kUmaEnumToControlId. Unhanded IDC: " << id
;
677 void RenderViewContextMenu::RecordShownItem(int id
) {
678 int enum_id
= FindUMAEnumValueForCommand(id
);
680 const size_t kMappingSize
= arraysize(kUmaEnumToControlId
);
681 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Shown", enum_id
,
682 kUmaEnumToControlId
[kMappingSize
- 1].enum_id
);
684 // Just warning here. It's harder to maintain list of all possibly
685 // visible items than executable items.
686 DLOG(ERROR
) << "Update kUmaEnumToControlId. Unhanded IDC: " << id
;
690 #if defined(ENABLE_PLUGINS)
691 void RenderViewContextMenu::HandleAuthorizeAllPlugins() {
692 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins(
693 source_web_contents_
, false, std::string());
697 void RenderViewContextMenu::AppendPrintPreviewItems() {
698 #if defined(ENABLE_PRINT_PREVIEW)
699 if (!print_preview_menu_observer_
.get()) {
700 print_preview_menu_observer_
.reset(
701 new PrintPreviewContextMenuObserver(source_web_contents_
));
704 observers_
.AddObserver(print_preview_menu_observer_
.get());
708 const Extension
* RenderViewContextMenu::GetExtension() const {
709 return extensions::ProcessManager::Get(browser_context_
)
710 ->GetExtensionForWebContents(source_web_contents_
);
713 void RenderViewContextMenu::AppendDeveloperItems() {
714 // Show Inspect Element in DevTools itself only in case of the debug
716 bool show_developer_items
= !IsDevToolsURL(params_
.page_url
);
718 #if defined(DEBUG_DEVTOOLS)
719 show_developer_items
= true;
722 if (!show_developer_items
)
725 // In the DevTools popup menu, "developer items" is normally the only
726 // section, so omit the separator there.
727 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
728 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTELEMENT
,
729 IDS_CONTENT_CONTEXT_INSPECTELEMENT
);
732 void RenderViewContextMenu::AppendDevtoolsForUnpackedExtensions() {
733 // Add a separator if there are any items already in the menu.
734 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
736 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP
,
737 IDS_CONTENT_CONTEXT_RELOAD_PACKAGED_APP
);
738 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP
,
739 IDS_CONTENT_CONTEXT_RESTART_APP
);
740 AppendDeveloperItems();
741 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE
,
742 IDS_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE
);
745 void RenderViewContextMenu::AppendLinkItems() {
746 if (!params_
.link_url
.is_empty()) {
747 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB
,
748 IDS_CONTENT_CONTEXT_OPENLINKNEWTAB
);
749 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW
,
750 IDS_CONTENT_CONTEXT_OPENLINKNEWWINDOW
);
751 if (params_
.link_url
.is_valid()) {
752 AppendProtocolHandlerSubMenu();
755 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD
,
756 IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD
);
757 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVELINKAS
,
758 IDS_CONTENT_CONTEXT_SAVELINKAS
);
761 menu_model_
.AddItemWithStringId(
762 IDC_CONTENT_CONTEXT_COPYLINKLOCATION
,
763 params_
.link_url
.SchemeIs(url::kMailToScheme
) ?
764 IDS_CONTENT_CONTEXT_COPYEMAILADDRESS
:
765 IDS_CONTENT_CONTEXT_COPYLINKLOCATION
);
768 void RenderViewContextMenu::AppendImageItems() {
769 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS
,
770 IDS_CONTENT_CONTEXT_SAVEIMAGEAS
);
771 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGELOCATION
,
772 IDS_CONTENT_CONTEXT_COPYIMAGELOCATION
);
773 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE
,
774 IDS_CONTENT_CONTEXT_COPYIMAGE
);
775 std::map
<std::string
, std::string
>::const_iterator it
=
776 params_
.properties
.find(data_reduction_proxy::chrome_proxy_header());
777 if (it
!= params_
.properties
.end() && it
->second
==
778 data_reduction_proxy::chrome_proxy_lo_fi_directive()) {
779 menu_model_
.AddItemWithStringId(
780 IDC_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE
,
781 IDS_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE
);
783 DataReductionProxyChromeSettings
* settings
=
784 DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
786 if (settings
&& settings
->CanUseDataReductionProxy(params_
.src_url
)) {
787 menu_model_
.AddItemWithStringId(
788 IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB
,
789 IDS_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB
);
791 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB
,
792 IDS_CONTENT_CONTEXT_OPENIMAGENEWTAB
);
796 void RenderViewContextMenu::AppendSearchWebForImageItems() {
797 TemplateURLService
* service
=
798 TemplateURLServiceFactory::GetForProfile(GetProfile());
799 const TemplateURL
* const default_provider
=
800 service
->GetDefaultSearchProvider();
801 if (params_
.has_image_contents
&& default_provider
&&
802 !default_provider
->image_url().empty() &&
803 default_provider
->image_url_ref().IsValid(service
->search_terms_data())) {
805 IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE
,
806 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFORIMAGE
,
807 default_provider
->short_name()));
811 void RenderViewContextMenu::AppendAudioItems() {
813 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
814 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS
,
815 IDS_CONTENT_CONTEXT_SAVEAUDIOAS
);
816 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION
,
817 IDS_CONTENT_CONTEXT_COPYAUDIOLOCATION
);
818 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB
,
819 IDS_CONTENT_CONTEXT_OPENAUDIONEWTAB
);
822 void RenderViewContextMenu::AppendCanvasItems() {
823 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS
,
824 IDS_CONTENT_CONTEXT_SAVEIMAGEAS
);
825 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE
,
826 IDS_CONTENT_CONTEXT_COPYIMAGE
);
829 void RenderViewContextMenu::AppendVideoItems() {
831 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
832 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS
,
833 IDS_CONTENT_CONTEXT_SAVEVIDEOAS
);
834 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION
,
835 IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION
);
836 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB
,
837 IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB
);
840 void RenderViewContextMenu::AppendMediaItems() {
841 int media_flags
= params_
.media_flags
;
843 menu_model_
.AddItemWithStringId(
844 IDC_CONTENT_CONTEXT_PLAYPAUSE
,
845 media_flags
& WebContextMenuData::MediaPaused
?
846 IDS_CONTENT_CONTEXT_PLAY
:
847 IDS_CONTENT_CONTEXT_PAUSE
);
849 menu_model_
.AddItemWithStringId(
850 IDC_CONTENT_CONTEXT_MUTE
,
851 media_flags
& WebContextMenuData::MediaMuted
?
852 IDS_CONTENT_CONTEXT_UNMUTE
:
853 IDS_CONTENT_CONTEXT_MUTE
);
855 menu_model_
.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_LOOP
,
856 IDS_CONTENT_CONTEXT_LOOP
);
857 menu_model_
.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_CONTROLS
,
858 IDS_CONTENT_CONTEXT_CONTROLS
);
861 void RenderViewContextMenu::AppendPluginItems() {
862 if (params_
.page_url
== params_
.src_url
||
863 guest_view::GuestViewBase::IsGuest(source_web_contents_
)) {
864 // Full page plugin, so show page menu items.
865 if (params_
.link_url
.is_empty() && params_
.selection_text
.empty())
868 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS
,
869 IDS_CONTENT_CONTEXT_SAVEPAGEAS
);
870 // The "Print" menu item should always be included for plugins. If
871 // content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT)
872 // is true the item will be added inside AppendPrintItem(). Otherwise we
874 if (!content_type_
->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT
))
875 menu_model_
.AddItemWithStringId(IDC_PRINT
, IDS_CONTENT_CONTEXT_PRINT
);
879 void RenderViewContextMenu::AppendPageItems() {
880 menu_model_
.AddItemWithStringId(IDC_BACK
, IDS_CONTENT_CONTEXT_BACK
);
881 menu_model_
.AddItemWithStringId(IDC_FORWARD
, IDS_CONTENT_CONTEXT_FORWARD
);
882 menu_model_
.AddItemWithStringId(IDC_RELOAD
, IDS_CONTENT_CONTEXT_RELOAD
);
883 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
884 menu_model_
.AddItemWithStringId(IDC_SAVE_PAGE
,
885 IDS_CONTENT_CONTEXT_SAVEPAGEAS
);
886 menu_model_
.AddItemWithStringId(IDC_PRINT
, IDS_CONTENT_CONTEXT_PRINT
);
888 if (TranslateService::IsTranslatableURL(params_
.page_url
)) {
889 std::string locale
= g_browser_process
->GetApplicationLocale();
890 locale
= translate::TranslateDownloadManager::GetLanguageCode(locale
);
891 base::string16 language
=
892 l10n_util::GetDisplayNameForLocale(locale
, locale
, true);
894 IDC_CONTENT_CONTEXT_TRANSLATE
,
895 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_TRANSLATE
, language
));
898 menu_model_
.AddItemWithStringId(IDC_VIEW_SOURCE
,
899 IDS_CONTENT_CONTEXT_VIEWPAGESOURCE
);
900 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWPAGEINFO
,
901 IDS_CONTENT_CONTEXT_VIEWPAGEINFO
);
904 void RenderViewContextMenu::AppendFrameItems() {
905 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOADFRAME
,
906 IDS_CONTENT_CONTEXT_RELOADFRAME
);
907 // These two menu items have yet to be implemented.
908 // http://code.google.com/p/chromium/issues/detail?id=11827
909 // IDS_CONTENT_CONTEXT_SAVEFRAMEAS
910 // IDS_CONTENT_CONTEXT_PRINTFRAME
911 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE
,
912 IDS_CONTENT_CONTEXT_VIEWFRAMESOURCE
);
913 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMEINFO
,
914 IDS_CONTENT_CONTEXT_VIEWFRAMEINFO
);
917 void RenderViewContextMenu::AppendCopyItem() {
918 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY
,
919 IDS_CONTENT_CONTEXT_COPY
);
922 void RenderViewContextMenu::AppendPrintItem() {
923 if (GetPrefs(browser_context_
)->GetBoolean(prefs::kPrintingEnabled
) &&
924 (params_
.media_type
== WebContextMenuData::MediaTypeNone
||
925 params_
.media_flags
& WebContextMenuData::MediaCanPrint
)) {
926 menu_model_
.AddItemWithStringId(IDC_PRINT
, IDS_CONTENT_CONTEXT_PRINT
);
930 void RenderViewContextMenu::AppendRotationItems() {
931 if (params_
.media_flags
& WebContextMenuData::MediaCanRotate
) {
932 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
933 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECW
,
934 IDS_CONTENT_CONTEXT_ROTATECW
);
935 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECCW
,
936 IDS_CONTENT_CONTEXT_ROTATECCW
);
940 void RenderViewContextMenu::AppendSearchProvider() {
941 DCHECK(browser_context_
);
943 base::TrimWhitespace(params_
.selection_text
, base::TRIM_ALL
,
944 ¶ms_
.selection_text
);
945 if (params_
.selection_text
.empty())
948 base::ReplaceChars(params_
.selection_text
, AutocompleteMatch::kInvalidChars
,
949 base::ASCIIToUTF16(" "), ¶ms_
.selection_text
);
951 AutocompleteMatch match
;
952 AutocompleteClassifierFactory::GetForProfile(GetProfile())->Classify(
953 params_
.selection_text
,
956 metrics::OmniboxEventProto::INVALID_SPEC
,
959 selection_navigation_url_
= match
.destination_url
;
960 if (!selection_navigation_url_
.is_valid())
963 base::string16 printable_selection_text
= PrintableSelectionText();
964 EscapeAmpersands(&printable_selection_text
);
966 if (AutocompleteMatch::IsSearchType(match
.type
)) {
967 const TemplateURL
* const default_provider
=
968 TemplateURLServiceFactory::GetForProfile(GetProfile())
969 ->GetDefaultSearchProvider();
970 if (!default_provider
)
973 IDC_CONTENT_CONTEXT_SEARCHWEBFOR
,
974 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFOR
,
975 default_provider
->short_name(),
976 printable_selection_text
));
978 if ((selection_navigation_url_
!= params_
.link_url
) &&
979 ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme(
980 selection_navigation_url_
.scheme())) {
982 IDC_CONTENT_CONTEXT_GOTOURL
,
983 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_GOTOURL
,
984 printable_selection_text
));
989 void RenderViewContextMenu::AppendEditableItems() {
990 const bool use_spellcheck_and_search
= !chrome::IsRunningInForcedAppMode();
992 if (use_spellcheck_and_search
)
993 AppendSpellingSuggestionsSubMenu();
995 if (!IsDevToolsURL(params_
.page_url
)) {
996 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_UNDO
,
997 IDS_CONTENT_CONTEXT_UNDO
);
998 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_REDO
,
999 IDS_CONTENT_CONTEXT_REDO
);
1000 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
1003 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_CUT
,
1004 IDS_CONTENT_CONTEXT_CUT
);
1005 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY
,
1006 IDS_CONTENT_CONTEXT_COPY
);
1007 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE
,
1008 IDS_CONTENT_CONTEXT_PASTE
);
1009 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE
,
1010 IDS_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE
);
1011 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_DELETE
,
1012 IDS_CONTENT_CONTEXT_DELETE
);
1013 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
1015 if (use_spellcheck_and_search
&& !params_
.keyword_url
.is_empty()) {
1016 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_ADDSEARCHENGINE
,
1017 IDS_CONTENT_CONTEXT_ADDSEARCHENGINE
);
1018 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
1021 #if defined(OS_MACOSX)
1022 if (use_spellcheck_and_search
)
1023 AppendSpellcheckOptionsSubMenu();
1025 if (chrome::spellcheck_common::IsMultilingualSpellcheckEnabled()) {
1026 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS
,
1027 IDS_CONTENT_CONTEXT_LANGUAGE_SETTINGS
);
1028 } else if (use_spellcheck_and_search
) {
1029 AppendSpellcheckOptionsSubMenu();
1031 #endif // defined(OS_MACOSX)
1033 AppendPlatformEditableItems();
1035 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
1036 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SELECTALL
,
1037 IDS_CONTENT_CONTEXT_SELECTALL
);
1040 void RenderViewContextMenu::AppendSpellingSuggestionsSubMenu() {
1041 if (!spelling_menu_observer_
.get())
1042 spelling_menu_observer_
.reset(new SpellingMenuObserver(this));
1043 observers_
.AddObserver(spelling_menu_observer_
.get());
1044 spelling_menu_observer_
->InitMenu(params_
);
1047 void RenderViewContextMenu::AppendSpellcheckOptionsSubMenu() {
1048 if (!spellchecker_submenu_observer_
.get()) {
1049 spellchecker_submenu_observer_
.reset(new SpellCheckerSubMenuObserver(
1050 this, this, kSpellcheckRadioGroup
));
1052 spellchecker_submenu_observer_
->InitMenu(params_
);
1053 observers_
.AddObserver(spellchecker_submenu_observer_
.get());
1056 void RenderViewContextMenu::AppendProtocolHandlerSubMenu() {
1057 const ProtocolHandlerRegistry::ProtocolHandlerList handlers
=
1058 GetHandlersForLinkUrl();
1059 if (handlers
.empty())
1061 size_t max
= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST
-
1062 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
;
1063 for (size_t i
= 0; i
< handlers
.size() && i
<= max
; i
++) {
1064 protocol_handler_submenu_model_
.AddItem(
1065 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
+ i
,
1066 base::UTF8ToUTF16(handlers
[i
].url().host()));
1068 protocol_handler_submenu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
1069 protocol_handler_submenu_model_
.AddItem(
1070 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS
,
1071 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH_CONFIGURE
));
1073 menu_model_
.AddSubMenu(
1074 IDC_CONTENT_CONTEXT_OPENLINKWITH
,
1075 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH
),
1076 &protocol_handler_submenu_model_
);
1079 void RenderViewContextMenu::AppendPasswordItems() {
1080 if (!password_manager::ForceSavingExperimentEnabled())
1083 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
1084 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD
,
1085 IDS_CONTENT_CONTEXT_FORCESAVEPASSWORD
);
1088 // Menu delegate functions -----------------------------------------------------
1090 bool RenderViewContextMenu::IsCommandIdEnabled(int id
) const {
1092 bool enabled
= false;
1093 if (RenderViewContextMenuBase::IsCommandIdKnown(id
, &enabled
))
1097 CoreTabHelper
* core_tab_helper
=
1098 CoreTabHelper::FromWebContents(source_web_contents_
);
1099 int content_restrictions
= 0;
1100 if (core_tab_helper
)
1101 content_restrictions
= core_tab_helper
->content_restrictions();
1102 if (id
== IDC_PRINT
&& (content_restrictions
& CONTENT_RESTRICTION_PRINT
))
1105 if (id
== IDC_SAVE_PAGE
&&
1106 (content_restrictions
& CONTENT_RESTRICTION_SAVE
)) {
1110 PrefService
* prefs
= GetPrefs(browser_context_
);
1112 // Allow Spell Check language items on sub menu for text area context menu.
1113 if ((id
>= IDC_SPELLCHECK_LANGUAGES_FIRST
) &&
1114 (id
< IDC_SPELLCHECK_LANGUAGES_LAST
)) {
1115 return prefs
->GetBoolean(prefs::kEnableContinuousSpellcheck
);
1119 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id
))
1120 return extension_items_
.IsCommandIdEnabled(id
);
1122 if (id
>= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
&&
1123 id
<= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST
) {
1127 IncognitoModePrefs::Availability incognito_avail
=
1128 IncognitoModePrefs::GetAvailability(prefs
);
1131 return embedder_web_contents_
->GetController().CanGoBack();
1134 return embedder_web_contents_
->GetController().CanGoForward();
1137 CoreTabHelper
* core_tab_helper
=
1138 CoreTabHelper::FromWebContents(embedder_web_contents_
);
1139 if (!core_tab_helper
)
1142 CoreTabHelperDelegate
* core_delegate
= core_tab_helper
->delegate();
1143 return !core_delegate
||
1144 core_delegate
->CanReloadContents(embedder_web_contents_
);
1147 case IDC_VIEW_SOURCE
:
1148 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE
:
1149 return embedder_web_contents_
->GetController().CanViewSource();
1151 case IDC_CONTENT_CONTEXT_INSPECTELEMENT
:
1152 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE
:
1153 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP
:
1154 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP
:
1155 return IsDevCommandEnabled(id
);
1157 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO
:
1158 if (embedder_web_contents_
->GetController().GetVisibleEntry() == NULL
)
1160 // Disabled if no browser is associated (e.g. desktop notifications).
1161 if (chrome::FindBrowserWithWebContents(embedder_web_contents_
) == NULL
)
1165 case IDC_CONTENT_CONTEXT_TRANSLATE
: {
1166 ChromeTranslateClient
* chrome_translate_client
=
1167 ChromeTranslateClient::FromWebContents(embedder_web_contents_
);
1168 if (!chrome_translate_client
)
1170 std::string original_lang
=
1171 chrome_translate_client
->GetLanguageState().original_language();
1172 std::string target_lang
= g_browser_process
->GetApplicationLocale();
1174 translate::TranslateDownloadManager::GetLanguageCode(target_lang
);
1175 // Note that we intentionally enable the menu even if the original and
1176 // target languages are identical. This is to give a way to user to
1177 // translate a page that might contains text fragments in a different
1179 return ((params_
.edit_flags
& WebContextMenuData::CanTranslate
) != 0) &&
1180 !original_lang
.empty() && // Did we receive the page language yet?
1181 !chrome_translate_client
->GetLanguageState().IsPageTranslated() &&
1182 !embedder_web_contents_
->GetInterstitialPage() &&
1183 // There are some application locales which can't be used as a
1184 // target language for translation.
1185 translate::TranslateDownloadManager::IsSupportedLanguage(
1187 // Disable on the Instant Extended NTP.
1188 !search::IsInstantNTP(embedder_web_contents_
);
1191 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB
:
1192 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW
:
1193 return params_
.link_url
.is_valid();
1195 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION
:
1196 return params_
.unfiltered_link_url
.is_valid();
1198 case IDC_CONTENT_CONTEXT_SAVELINKAS
: {
1199 PrefService
* local_state
= g_browser_process
->local_state();
1200 DCHECK(local_state
);
1201 // Test if file-selection dialogs are forbidden by policy.
1202 if (!local_state
->GetBoolean(prefs::kAllowFileSelectionDialogs
))
1205 return params_
.link_url
.is_valid() &&
1206 ProfileIOData::IsHandledProtocol(params_
.link_url
.scheme());
1209 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS
: {
1210 PrefService
* local_state
= g_browser_process
->local_state();
1211 DCHECK(local_state
);
1212 // Test if file-selection dialogs are forbidden by policy.
1213 if (!local_state
->GetBoolean(prefs::kAllowFileSelectionDialogs
))
1216 return params_
.has_image_contents
;
1219 // The images shown in the most visited thumbnails can't be opened or
1220 // searched for conventionally.
1221 case IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB
:
1222 case IDC_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE
:
1223 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB
:
1224 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE
:
1225 return params_
.src_url
.is_valid() &&
1226 (params_
.src_url
.scheme() != content::kChromeUIScheme
);
1228 case IDC_CONTENT_CONTEXT_COPYIMAGE
:
1229 return params_
.has_image_contents
;
1231 // Media control commands should all be disabled if the player is in an
1233 case IDC_CONTENT_CONTEXT_PLAYPAUSE
:
1234 case IDC_CONTENT_CONTEXT_LOOP
:
1235 return (params_
.media_flags
&
1236 WebContextMenuData::MediaInError
) == 0;
1238 // Mute and unmute should also be disabled if the player has no audio.
1239 case IDC_CONTENT_CONTEXT_MUTE
:
1240 return (params_
.media_flags
&
1241 WebContextMenuData::MediaHasAudio
) != 0 &&
1242 (params_
.media_flags
&
1243 WebContextMenuData::MediaInError
) == 0;
1245 case IDC_CONTENT_CONTEXT_CONTROLS
:
1246 return (params_
.media_flags
&
1247 WebContextMenuData::MediaCanToggleControls
) != 0;
1249 case IDC_CONTENT_CONTEXT_ROTATECW
:
1250 case IDC_CONTENT_CONTEXT_ROTATECCW
:
1252 (params_
.media_flags
& WebContextMenuData::MediaCanRotate
) != 0;
1254 case IDC_CONTENT_CONTEXT_COPYAVLOCATION
:
1255 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION
:
1256 return params_
.src_url
.is_valid();
1258 case IDC_CONTENT_CONTEXT_SAVEAVAS
: {
1259 PrefService
* local_state
= g_browser_process
->local_state();
1260 DCHECK(local_state
);
1261 // Test if file-selection dialogs are forbidden by policy.
1262 if (!local_state
->GetBoolean(prefs::kAllowFileSelectionDialogs
))
1265 const GURL
& url
= params_
.src_url
;
1267 (params_
.media_flags
& WebContextMenuData::MediaCanSave
) &&
1268 url
.is_valid() && ProfileIOData::IsHandledProtocol(url
.scheme());
1269 #if defined(ENABLE_PRINT_PREVIEW)
1270 // Do not save the preview PDF on the print preview page.
1271 can_save
= can_save
&&
1272 !(printing::PrintPreviewDialogController::IsPrintPreviewURL(url
));
1277 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB
:
1278 // Currently, a media element can be opened in a new tab iff it can
1279 // be saved. So rather than duplicating the MediaCanSave flag, we rely
1281 return !!(params_
.media_flags
& WebContextMenuData::MediaCanSave
);
1283 case IDC_SAVE_PAGE
: {
1284 CoreTabHelper
* core_tab_helper
=
1285 CoreTabHelper::FromWebContents(embedder_web_contents_
);
1286 if (!core_tab_helper
)
1289 CoreTabHelperDelegate
* core_delegate
= core_tab_helper
->delegate();
1290 if (core_delegate
&&
1291 !core_delegate
->CanSaveContents(embedder_web_contents_
))
1294 PrefService
* local_state
= g_browser_process
->local_state();
1295 DCHECK(local_state
);
1296 // Test if file-selection dialogs are forbidden by policy.
1297 if (!local_state
->GetBoolean(prefs::kAllowFileSelectionDialogs
))
1300 // We save the last committed entry (which the user is looking at), as
1301 // opposed to any pending URL that hasn't committed yet.
1302 NavigationEntry
* entry
=
1303 embedder_web_contents_
->GetController().GetLastCommittedEntry();
1304 return content::IsSavableURL(entry
? entry
->GetURL() : GURL());
1307 case IDC_CONTENT_CONTEXT_RELOADFRAME
:
1308 return params_
.frame_url
.is_valid();
1310 case IDC_CONTENT_CONTEXT_UNDO
:
1311 return !!(params_
.edit_flags
& WebContextMenuData::CanUndo
);
1313 case IDC_CONTENT_CONTEXT_REDO
:
1314 return !!(params_
.edit_flags
& WebContextMenuData::CanRedo
);
1316 case IDC_CONTENT_CONTEXT_CUT
:
1317 return !!(params_
.edit_flags
& WebContextMenuData::CanCut
);
1319 case IDC_CONTENT_CONTEXT_COPY
:
1320 return !!(params_
.edit_flags
& WebContextMenuData::CanCopy
);
1322 case IDC_CONTENT_CONTEXT_PASTE
: {
1323 if (!(params_
.edit_flags
& WebContextMenuData::CanPaste
))
1326 std::vector
<base::string16
> types
;
1328 ui::Clipboard::GetForCurrentThread()->ReadAvailableTypes(
1329 ui::CLIPBOARD_TYPE_COPY_PASTE
, &types
, &ignore
);
1330 return !types
.empty();
1333 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE
: {
1334 if (!(params_
.edit_flags
& WebContextMenuData::CanPaste
))
1337 return ui::Clipboard::GetForCurrentThread()->IsFormatAvailable(
1338 ui::Clipboard::GetPlainTextFormatType(),
1339 ui::CLIPBOARD_TYPE_COPY_PASTE
);
1342 case IDC_CONTENT_CONTEXT_DELETE
:
1343 return !!(params_
.edit_flags
& WebContextMenuData::CanDelete
);
1345 case IDC_CONTENT_CONTEXT_SELECTALL
:
1346 return !!(params_
.edit_flags
& WebContextMenuData::CanSelectAll
);
1348 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD
:
1349 return !browser_context_
->IsOffTheRecord() &&
1350 params_
.link_url
.is_valid() &&
1351 incognito_avail
!= IncognitoModePrefs::DISABLED
;
1354 return prefs
->GetBoolean(prefs::kPrintingEnabled
) &&
1355 (params_
.media_type
== WebContextMenuData::MediaTypeNone
||
1356 params_
.media_flags
& WebContextMenuData::MediaCanPrint
);
1358 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR
:
1359 case IDC_CONTENT_CONTEXT_GOTOURL
:
1360 case IDC_SPELLPANEL_TOGGLE
:
1361 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS
:
1363 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO
:
1364 // Disabled if no browser is associated (e.g. desktop notifications).
1365 if (chrome::FindBrowserWithWebContents(source_web_contents_
) == NULL
)
1369 case IDC_CHECK_SPELLING_WHILE_TYPING
:
1370 return prefs
->GetBoolean(prefs::kEnableContinuousSpellcheck
);
1372 #if !defined(OS_MACOSX) && defined(OS_POSIX)
1373 // TODO(suzhe): this should not be enabled for password fields.
1374 case IDC_INPUT_METHODS_MENU
:
1378 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE
:
1379 return !params_
.keyword_url
.is_empty();
1381 case IDC_SPELLCHECK_MENU
:
1384 case IDC_CONTENT_CONTEXT_OPENLINKWITH
:
1387 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS
:
1390 case IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD
:
1399 bool RenderViewContextMenu::IsCommandIdChecked(int id
) const {
1400 if (RenderViewContextMenuBase::IsCommandIdChecked(id
))
1403 // See if the video is set to looping.
1404 if (id
== IDC_CONTENT_CONTEXT_LOOP
)
1405 return (params_
.media_flags
& WebContextMenuData::MediaLoop
) != 0;
1407 if (id
== IDC_CONTENT_CONTEXT_CONTROLS
)
1408 return (params_
.media_flags
& WebContextMenuData::MediaControls
) != 0;
1411 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id
))
1412 return extension_items_
.IsCommandIdChecked(id
);
1417 void RenderViewContextMenu::ExecuteCommand(int id
, int event_flags
) {
1418 RenderViewContextMenuBase::ExecuteCommand(id
, event_flags
);
1419 if (command_executed_
)
1421 command_executed_
= true;
1423 RenderFrameHost
* render_frame_host
= GetRenderFrameHost();
1425 // Process extension menu items.
1426 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id
)) {
1427 extension_items_
.ExecuteCommand(id
, source_web_contents_
, params_
);
1431 if (id
>= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
&&
1432 id
<= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST
) {
1433 ProtocolHandlerRegistry::ProtocolHandlerList handlers
=
1434 GetHandlersForLinkUrl();
1435 if (handlers
.empty())
1438 content::RecordAction(
1439 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Open"));
1440 int handlerIndex
= id
- IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
;
1441 WindowOpenDisposition disposition
=
1442 ForceNewTabDispositionFromEventFlags(event_flags
);
1443 OpenURL(handlers
[handlerIndex
].TranslateUrl(params_
.link_url
),
1444 GetDocumentURL(params_
),
1446 ui::PAGE_TRANSITION_LINK
);
1451 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB
: {
1453 chrome::FindBrowserWithWebContents(source_web_contents_
);
1454 OpenURL(params_
.link_url
,
1455 GetDocumentURL(params_
),
1456 !browser
|| browser
->is_app() ?
1457 NEW_FOREGROUND_TAB
: NEW_BACKGROUND_TAB
,
1458 ui::PAGE_TRANSITION_LINK
);
1461 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW
:
1462 OpenURL(params_
.link_url
,
1463 GetDocumentURL(params_
),
1465 ui::PAGE_TRANSITION_LINK
);
1468 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD
:
1469 OpenURL(params_
.link_url
, GURL(), OFF_THE_RECORD
,
1470 ui::PAGE_TRANSITION_LINK
);
1473 case IDC_CONTENT_CONTEXT_SAVELINKAS
: {
1474 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU
);
1475 const GURL
& url
= params_
.link_url
;
1476 content::Referrer referrer
= CreateSaveAsReferrer(url
, params_
);
1477 DownloadManager
* dlm
=
1478 BrowserContext::GetDownloadManager(browser_context_
);
1479 scoped_ptr
<DownloadUrlParameters
> dl_params(
1480 DownloadUrlParameters::FromWebContents(source_web_contents_
, url
));
1481 dl_params
->set_referrer(referrer
);
1482 dl_params
->set_referrer_encoding(params_
.frame_charset
);
1483 dl_params
->set_suggested_name(params_
.suggested_filename
);
1484 dl_params
->set_prompt(true);
1485 dlm
->DownloadUrl(dl_params
.Pass());
1489 case IDC_CONTENT_CONTEXT_SAVEAVAS
:
1490 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS
: {
1491 bool is_large_data_url
= params_
.has_image_contents
&&
1492 params_
.src_url
.is_empty();
1493 if (params_
.media_type
== WebContextMenuData::MediaTypeCanvas
||
1494 (params_
.media_type
== WebContextMenuData::MediaTypeImage
&&
1495 is_large_data_url
)) {
1496 source_web_contents_
->GetRenderViewHost()->SaveImageAt(
1497 params_
.x
, params_
.y
);
1499 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU
);
1500 const GURL
& url
= params_
.src_url
;
1501 content::Referrer referrer
= CreateSaveAsReferrer(url
, params_
);
1503 std::string headers
;
1504 DataReductionProxyChromeSettings
* settings
=
1505 DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
1507 if (params_
.media_type
== WebContextMenuData::MediaTypeImage
&&
1508 settings
&& settings
->CanUseDataReductionProxy(params_
.src_url
)) {
1509 headers
= data_reduction_proxy::kDataReductionPassThroughHeader
;
1512 source_web_contents_
->SaveFrameWithHeaders(url
, referrer
, headers
);
1517 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION
:
1518 WriteURLToClipboard(params_
.unfiltered_link_url
);
1521 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION
:
1522 case IDC_CONTENT_CONTEXT_COPYAVLOCATION
:
1523 WriteURLToClipboard(params_
.src_url
);
1526 case IDC_CONTENT_CONTEXT_COPYIMAGE
:
1527 CopyImageAt(params_
.x
, params_
.y
);
1530 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE
:
1531 GetImageThumbnailForSearch();
1534 case IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB
:
1535 OpenURLWithExtraHeaders(
1536 params_
.src_url
, GetDocumentURL(params_
), NEW_BACKGROUND_TAB
,
1537 ui::PAGE_TRANSITION_LINK
,
1538 data_reduction_proxy::kDataReductionPassThroughHeader
);
1541 case IDC_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE
:
1542 LoadOriginalImage();
1545 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB
:
1546 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB
:
1547 OpenURL(params_
.src_url
,
1548 GetDocumentURL(params_
),
1550 ui::PAGE_TRANSITION_LINK
);
1553 case IDC_CONTENT_CONTEXT_PLAYPAUSE
: {
1554 bool play
= !!(params_
.media_flags
& WebContextMenuData::MediaPaused
);
1556 content::RecordAction(UserMetricsAction("MediaContextMenu_Play"));
1558 content::RecordAction(UserMetricsAction("MediaContextMenu_Pause"));
1560 MediaPlayerActionAt(gfx::Point(params_
.x
, params_
.y
),
1561 WebMediaPlayerAction(
1562 WebMediaPlayerAction::Play
, play
));
1566 case IDC_CONTENT_CONTEXT_MUTE
: {
1567 bool mute
= !(params_
.media_flags
& WebContextMenuData::MediaMuted
);
1569 content::RecordAction(UserMetricsAction("MediaContextMenu_Mute"));
1571 content::RecordAction(UserMetricsAction("MediaContextMenu_Unmute"));
1573 MediaPlayerActionAt(gfx::Point(params_
.x
, params_
.y
),
1574 WebMediaPlayerAction(
1575 WebMediaPlayerAction::Mute
, mute
));
1579 case IDC_CONTENT_CONTEXT_LOOP
:
1580 content::RecordAction(UserMetricsAction("MediaContextMenu_Loop"));
1581 MediaPlayerActionAt(gfx::Point(params_
.x
, params_
.y
),
1582 WebMediaPlayerAction(
1583 WebMediaPlayerAction::Loop
,
1584 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_LOOP
)));
1587 case IDC_CONTENT_CONTEXT_CONTROLS
:
1588 content::RecordAction(UserMetricsAction("MediaContextMenu_Controls"));
1589 MediaPlayerActionAt(
1590 gfx::Point(params_
.x
, params_
.y
),
1591 WebMediaPlayerAction(
1592 WebMediaPlayerAction::Controls
,
1593 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_CONTROLS
)));
1596 case IDC_CONTENT_CONTEXT_ROTATECW
:
1597 content::RecordAction(
1598 UserMetricsAction("PluginContextMenu_RotateClockwise"));
1600 gfx::Point(params_
.x
, params_
.y
),
1601 WebPluginAction(WebPluginAction::Rotate90Clockwise
, true));
1604 case IDC_CONTENT_CONTEXT_ROTATECCW
:
1605 content::RecordAction(
1606 UserMetricsAction("PluginContextMenu_RotateCounterclockwise"));
1608 gfx::Point(params_
.x
, params_
.y
),
1609 WebPluginAction(WebPluginAction::Rotate90Counterclockwise
, true));
1613 embedder_web_contents_
->GetController().GoBack();
1617 embedder_web_contents_
->GetController().GoForward();
1621 embedder_web_contents_
->OnSavePage();
1625 embedder_web_contents_
->GetController().Reload(true);
1628 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP
: {
1629 const Extension
* platform_app
= GetExtension();
1630 DCHECK(platform_app
);
1631 DCHECK(platform_app
->is_platform_app());
1633 extensions::ExtensionSystem::Get(browser_context_
)
1634 ->extension_service()
1635 ->ReloadExtension(platform_app
->id());
1639 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP
: {
1640 const Extension
* platform_app
= GetExtension();
1641 DCHECK(platform_app
);
1642 DCHECK(platform_app
->is_platform_app());
1644 apps::AppLoadService::Get(GetProfile())
1645 ->RestartApplication(platform_app
->id());
1650 #if defined(ENABLE_PRINTING)
1651 if (params_
.media_type
!= WebContextMenuData::MediaTypeNone
) {
1652 if (render_frame_host
) {
1653 render_frame_host
->Send(new PrintMsg_PrintNodeUnderContextMenu(
1654 render_frame_host
->GetRoutingID()));
1659 printing::StartPrint(
1660 source_web_contents_
,
1661 GetPrefs(browser_context_
)->GetBoolean(prefs::kPrintPreviewDisabled
),
1662 !params_
.selection_text
.empty());
1663 #endif // ENABLE_PRINTING
1667 case IDC_VIEW_SOURCE
:
1668 embedder_web_contents_
->ViewSource();
1671 case IDC_CONTENT_CONTEXT_INSPECTELEMENT
:
1672 Inspect(params_
.x
, params_
.y
);
1675 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE
: {
1676 const Extension
* platform_app
= GetExtension();
1677 DCHECK(platform_app
);
1678 DCHECK(platform_app
->is_platform_app());
1680 extensions::devtools_util::InspectBackgroundPage(platform_app
,
1685 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO
: {
1686 NavigationController
* controller
=
1687 &embedder_web_contents_
->GetController();
1688 // Important to use GetVisibleEntry to match what's showing in the
1689 // omnibox. This may return null.
1690 NavigationEntry
* nav_entry
= controller
->GetVisibleEntry();
1694 chrome::FindBrowserWithWebContents(embedder_web_contents_
);
1695 chrome::ShowWebsiteSettings(browser
, embedder_web_contents_
,
1696 nav_entry
->GetURL(), nav_entry
->GetSSL());
1700 case IDC_CONTENT_CONTEXT_TRANSLATE
: {
1701 // A translation might have been triggered by the time the menu got
1702 // selected, do nothing in that case.
1703 ChromeTranslateClient
* chrome_translate_client
=
1704 ChromeTranslateClient::FromWebContents(embedder_web_contents_
);
1705 if (!chrome_translate_client
||
1706 chrome_translate_client
->GetLanguageState().IsPageTranslated() ||
1707 chrome_translate_client
->GetLanguageState().translation_pending()) {
1710 std::string original_lang
=
1711 chrome_translate_client
->GetLanguageState().original_language();
1712 std::string target_lang
= g_browser_process
->GetApplicationLocale();
1714 translate::TranslateDownloadManager::GetLanguageCode(target_lang
);
1715 // Since the user decided to translate for that language and site, clears
1716 // any preferences for not translating them.
1717 scoped_ptr
<translate::TranslatePrefs
> prefs(
1718 ChromeTranslateClient::CreateTranslatePrefs(
1719 GetPrefs(browser_context_
)));
1720 prefs
->UnblockLanguage(original_lang
);
1721 prefs
->RemoveSiteFromBlacklist(params_
.page_url
.HostNoBrackets());
1722 translate::TranslateManager
* manager
=
1723 chrome_translate_client
->GetTranslateManager();
1725 manager
->TranslatePage(original_lang
, target_lang
, true);
1729 case IDC_CONTENT_CONTEXT_RELOADFRAME
:
1730 // We always obey the cache here.
1731 // TODO(evanm): Perhaps we could allow shift-clicking the menu item to do
1732 // a cache-ignoring reload of the frame.
1733 source_web_contents_
->ReloadFocusedFrame(false);
1736 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE
:
1737 source_web_contents_
->ViewFrameSource(params_
.frame_url
,
1738 params_
.frame_page_state
);
1741 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO
: {
1742 Browser
* browser
= chrome::FindBrowserWithWebContents(
1743 source_web_contents_
);
1744 chrome::ShowWebsiteSettings(browser
, source_web_contents_
,
1745 params_
.frame_url
, params_
.security_info
);
1749 case IDC_CONTENT_CONTEXT_UNDO
:
1750 source_web_contents_
->Undo();
1753 case IDC_CONTENT_CONTEXT_REDO
:
1754 source_web_contents_
->Redo();
1757 case IDC_CONTENT_CONTEXT_CUT
:
1758 source_web_contents_
->Cut();
1761 case IDC_CONTENT_CONTEXT_COPY
:
1762 source_web_contents_
->Copy();
1765 case IDC_CONTENT_CONTEXT_PASTE
:
1766 source_web_contents_
->Paste();
1769 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE
:
1770 source_web_contents_
->PasteAndMatchStyle();
1773 case IDC_CONTENT_CONTEXT_DELETE
:
1774 source_web_contents_
->Delete();
1777 case IDC_CONTENT_CONTEXT_SELECTALL
:
1778 source_web_contents_
->SelectAll();
1781 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR
:
1782 case IDC_CONTENT_CONTEXT_GOTOURL
: {
1783 WindowOpenDisposition disposition
=
1784 ForceNewTabDispositionFromEventFlags(event_flags
);
1785 OpenURL(selection_navigation_url_
, GURL(), disposition
,
1786 ui::PAGE_TRANSITION_LINK
);
1789 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS
: {
1790 WindowOpenDisposition disposition
=
1791 ForceNewTabDispositionFromEventFlags(event_flags
);
1792 GURL url
= chrome::GetSettingsUrl(chrome::kLanguageOptionsSubPage
);
1793 OpenURL(url
, GURL(), disposition
, ui::PAGE_TRANSITION_LINK
);
1797 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS
: {
1798 content::RecordAction(
1799 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Settings"));
1800 WindowOpenDisposition disposition
=
1801 ForceNewTabDispositionFromEventFlags(event_flags
);
1802 GURL url
= chrome::GetSettingsUrl(chrome::kHandlerSettingsSubPage
);
1803 OpenURL(url
, GURL(), disposition
, ui::PAGE_TRANSITION_LINK
);
1807 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE
: {
1808 // Make sure the model is loaded.
1809 TemplateURLService
* model
=
1810 TemplateURLServiceFactory::GetForProfile(GetProfile());
1815 SearchEngineTabHelper
* search_engine_tab_helper
=
1816 SearchEngineTabHelper::FromWebContents(source_web_contents_
);
1817 if (search_engine_tab_helper
&&
1818 search_engine_tab_helper
->delegate()) {
1819 base::string16
keyword(TemplateURL::GenerateKeyword(
1821 GetProfile()->GetPrefs()->GetString(prefs::kAcceptLanguages
)));
1822 TemplateURLData data
;
1823 data
.SetShortName(keyword
);
1824 data
.SetKeyword(keyword
);
1825 data
.SetURL(params_
.keyword_url
.spec());
1827 TemplateURL::GenerateFaviconURL(params_
.page_url
.GetOrigin());
1828 // Takes ownership of the TemplateURL.
1829 search_engine_tab_helper
->delegate()->ConfirmAddSearchProvider(
1830 new TemplateURL(data
), GetProfile());
1835 case IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD
:
1836 ChromePasswordManagerClient::FromWebContents(source_web_contents_
)->
1837 ForceSavePassword();
1846 ProtocolHandlerRegistry::ProtocolHandlerList
1847 RenderViewContextMenu::GetHandlersForLinkUrl() {
1848 ProtocolHandlerRegistry::ProtocolHandlerList handlers
=
1849 protocol_handler_registry_
->GetHandlersFor(params_
.link_url
.scheme());
1850 std::sort(handlers
.begin(), handlers
.end());
1854 void RenderViewContextMenu::NotifyMenuShown() {
1855 content::NotificationService::current()->Notify(
1856 chrome::NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN
,
1857 content::Source
<RenderViewContextMenu
>(this),
1858 content::NotificationService::NoDetails());
1861 void RenderViewContextMenu::NotifyURLOpened(
1863 content::WebContents
* new_contents
) {
1864 RetargetingDetails details
;
1865 details
.source_web_contents
= source_web_contents_
;
1866 // Don't use GetRenderFrameHost() as it may be NULL. crbug.com/399789
1867 details
.source_render_frame_id
= render_frame_id_
;
1868 details
.target_url
= url
;
1869 details
.target_web_contents
= new_contents
;
1870 details
.not_yet_in_tabstrip
= false;
1872 content::NotificationService::current()->Notify(
1873 chrome::NOTIFICATION_RETARGETING
,
1874 content::Source
<Profile
>(GetProfile()),
1875 content::Details
<RetargetingDetails
>(&details
));
1878 bool RenderViewContextMenu::IsDevCommandEnabled(int id
) const {
1879 if (id
== IDC_CONTENT_CONTEXT_INSPECTELEMENT
||
1880 id
== IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE
) {
1881 if (!GetPrefs(browser_context_
)
1882 ->GetBoolean(prefs::kWebKitJavascriptEnabled
))
1885 // Don't enable the web inspector if the developer tools are disabled via
1886 // the preference dev-tools-disabled.
1887 if (GetPrefs(browser_context_
)->GetBoolean(prefs::kDevToolsDisabled
))
1894 base::string16
RenderViewContextMenu::PrintableSelectionText() {
1895 return gfx::TruncateString(params_
.selection_text
,
1896 kMaxSelectionTextLength
,
1900 void RenderViewContextMenu::EscapeAmpersands(base::string16
* text
) {
1901 base::ReplaceChars(*text
, base::ASCIIToUTF16("&"), base::ASCIIToUTF16("&&"),
1905 // Controller functions --------------------------------------------------------
1907 void RenderViewContextMenu::CopyImageAt(int x
, int y
) {
1908 source_web_contents_
->GetRenderViewHost()->CopyImageAt(x
, y
);
1911 void RenderViewContextMenu::LoadOriginalImage() {
1912 RenderFrameHost
* render_frame_host
= GetRenderFrameHost();
1913 if (!render_frame_host
)
1915 render_frame_host
->Send(new ChromeViewMsg_RequestReloadImageForContextNode(
1916 render_frame_host
->GetRoutingID()));
1919 void RenderViewContextMenu::GetImageThumbnailForSearch() {
1920 RenderFrameHost
* render_frame_host
= GetRenderFrameHost();
1921 if (!render_frame_host
)
1923 render_frame_host
->Send(new ChromeViewMsg_RequestThumbnailForContextNode(
1924 render_frame_host
->GetRoutingID(),
1925 kImageSearchThumbnailMinSize
,
1926 gfx::Size(kImageSearchThumbnailMaxWidth
,
1927 kImageSearchThumbnailMaxHeight
)));
1930 void RenderViewContextMenu::Inspect(int x
, int y
) {
1931 content::RecordAction(UserMetricsAction("DevTools_InspectElement"));
1932 RenderFrameHost
* render_frame_host
= GetRenderFrameHost();
1933 if (!render_frame_host
)
1935 DevToolsWindow::InspectElement(
1936 WebContents::FromRenderFrameHost(render_frame_host
), x
, y
);
1939 void RenderViewContextMenu::WriteURLToClipboard(const GURL
& url
) {
1940 ::WriteURLToClipboard(
1941 url
, GetPrefs(browser_context_
)->GetString(prefs::kAcceptLanguages
));
1944 void RenderViewContextMenu::MediaPlayerActionAt(
1945 const gfx::Point
& location
,
1946 const WebMediaPlayerAction
& action
) {
1947 source_web_contents_
->GetRenderViewHost()->
1948 ExecuteMediaPlayerActionAtLocation(location
, action
);
1951 void RenderViewContextMenu::PluginActionAt(
1952 const gfx::Point
& location
,
1953 const WebPluginAction
& action
) {
1954 source_web_contents_
->GetRenderViewHost()->
1955 ExecutePluginActionAtLocation(location
, action
);