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/net/url_util.h"
60 #include "chrome/common/pref_names.h"
61 #include "chrome/common/render_messages.h"
62 #include "chrome/common/spellcheck_common.h"
63 #include "chrome/common/url_constants.h"
64 #include "chrome/grit/generated_resources.h"
65 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
66 #include "components/google/core/browser/google_util.h"
67 #include "components/metrics/proto/omnibox_input_type.pb.h"
68 #include "components/omnibox/browser/autocomplete_classifier.h"
69 #include "components/omnibox/browser/autocomplete_match.h"
70 #include "components/password_manager/core/common/experiments.h"
71 #include "components/search_engines/template_url.h"
72 #include "components/search_engines/template_url_service.h"
73 #include "components/translate/core/browser/translate_download_manager.h"
74 #include "components/translate/core/browser/translate_manager.h"
75 #include "components/translate/core/browser/translate_prefs.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/l10n/l10n_util.h"
104 #include "ui/gfx/favicon_size.h"
105 #include "ui/gfx/geometry/point.h"
106 #include "ui/gfx/geometry/size.h"
107 #include "ui/gfx/text_elider.h"
109 #if defined(ENABLE_EXTENSIONS)
110 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
113 #if defined(ENABLE_PRINTING)
114 #include "chrome/browser/printing/print_view_manager_common.h"
115 #include "components/printing/common/print_messages.h"
117 #if defined(ENABLE_PRINT_PREVIEW)
118 #include "chrome/browser/printing/print_preview_context_menu_observer.h"
119 #include "chrome/browser/printing/print_preview_dialog_controller.h"
120 #endif // defined(ENABLE_PRINT_PREVIEW)
121 #endif // defined(ENABLE_PRINTING)
123 using base::UserMetricsAction
;
124 using blink::WebContextMenuData
;
125 using blink::WebMediaPlayerAction
;
126 using blink::WebPluginAction
;
127 using blink::WebString
;
129 using content::BrowserContext
;
130 using content::ChildProcessSecurityPolicy
;
131 using content::DownloadManager
;
132 using content::DownloadUrlParameters
;
133 using content::NavigationController
;
134 using content::NavigationEntry
;
135 using content::OpenURLParams
;
136 using content::RenderFrameHost
;
137 using content::RenderViewHost
;
138 using content::SSLStatus
;
139 using content::WebContents
;
140 using extensions::ContextMenuMatcher
;
141 using extensions::Extension
;
142 using extensions::MenuItem
;
143 using extensions::MenuManager
;
147 const int kImageSearchThumbnailMinSize
= 300 * 300;
148 const int kImageSearchThumbnailMaxWidth
= 600;
149 const int kImageSearchThumbnailMaxHeight
= 600;
151 // Maps UMA enumeration to IDC. IDC could be changed so we can't use
152 // just them and |UMA_HISTOGRAM_CUSTOM_ENUMERATION|.
153 // Never change mapping or reuse |enum_id|. Always push back new items.
154 // Items that is not used any more by |RenderViewContextMenu.ExecuteCommand|
155 // could be deleted, but don't change the rest of |kUmaEnumToControlId|.
156 const struct UmaEnumCommandIdPair
{
159 } kUmaEnumToControlId
[] = {
161 enum id for 0, 1 are detected using
162 RenderViewContextMenu::IsContentCustomCommandId and
163 ContextMenuMatcher::IsExtensionsCustomCommandId
165 {2, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
},
166 {3, IDC_CONTENT_CONTEXT_OPENLINKNEWTAB
},
167 {4, IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW
},
168 {5, IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD
},
169 {6, IDC_CONTENT_CONTEXT_SAVELINKAS
},
170 {7, IDC_CONTENT_CONTEXT_SAVEAVAS
},
171 {8, IDC_CONTENT_CONTEXT_SAVEIMAGEAS
},
172 {9, IDC_CONTENT_CONTEXT_COPYLINKLOCATION
},
173 {10, IDC_CONTENT_CONTEXT_COPYIMAGELOCATION
},
174 {11, IDC_CONTENT_CONTEXT_COPYAVLOCATION
},
175 {12, IDC_CONTENT_CONTEXT_COPYIMAGE
},
176 {13, IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB
},
177 {14, IDC_CONTENT_CONTEXT_OPENAVNEWTAB
},
178 {15, IDC_CONTENT_CONTEXT_PLAYPAUSE
},
179 {16, IDC_CONTENT_CONTEXT_MUTE
},
180 {17, IDC_CONTENT_CONTEXT_LOOP
},
181 {18, IDC_CONTENT_CONTEXT_CONTROLS
},
182 {19, IDC_CONTENT_CONTEXT_ROTATECW
},
183 {20, IDC_CONTENT_CONTEXT_ROTATECCW
},
188 {25, IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP
},
189 {26, IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP
},
191 {28, IDC_VIEW_SOURCE
},
192 {29, IDC_CONTENT_CONTEXT_INSPECTELEMENT
},
193 {30, IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE
},
194 {31, IDC_CONTENT_CONTEXT_VIEWPAGEINFO
},
195 {32, IDC_CONTENT_CONTEXT_TRANSLATE
},
196 {33, IDC_CONTENT_CONTEXT_RELOADFRAME
},
197 {34, IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE
},
198 {35, IDC_CONTENT_CONTEXT_VIEWFRAMEINFO
},
199 {36, IDC_CONTENT_CONTEXT_UNDO
},
200 {37, IDC_CONTENT_CONTEXT_REDO
},
201 {38, IDC_CONTENT_CONTEXT_CUT
},
202 {39, IDC_CONTENT_CONTEXT_COPY
},
203 {40, IDC_CONTENT_CONTEXT_PASTE
},
204 {41, IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE
},
205 {42, IDC_CONTENT_CONTEXT_DELETE
},
206 {43, IDC_CONTENT_CONTEXT_SELECTALL
},
207 {44, IDC_CONTENT_CONTEXT_SEARCHWEBFOR
},
208 {45, IDC_CONTENT_CONTEXT_GOTOURL
},
209 {46, IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS
},
210 {47, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS
},
211 {48, IDC_CONTENT_CONTEXT_ADDSEARCHENGINE
},
212 {52, IDC_CONTENT_CONTEXT_OPENLINKWITH
},
213 {53, IDC_CHECK_SPELLING_WHILE_TYPING
},
214 {54, IDC_SPELLCHECK_MENU
},
215 {55, IDC_CONTENT_CONTEXT_SPELLING_TOGGLE
},
216 {56, IDC_SPELLCHECK_LANGUAGES_FIRST
},
217 {57, IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE
},
218 {58, IDC_SPELLCHECK_SUGGESTION_0
},
219 {59, IDC_SPELLCHECK_ADD_TO_DICTIONARY
},
220 {60, IDC_SPELLPANEL_TOGGLE
},
221 {61, IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB
},
222 {62, IDC_WRITING_DIRECTION_MENU
},
223 {63, IDC_WRITING_DIRECTION_DEFAULT
},
224 {64, IDC_WRITING_DIRECTION_LTR
},
225 {65, IDC_WRITING_DIRECTION_RTL
},
226 {66, IDC_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE
},
227 {67, IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD
},
228 // Add new items here and use |enum_id| from the next line.
229 // Also, add new items to RenderViewContextMenuItem enum in histograms.xml.
230 {68, 0}, // Must be the last. Increment |enum_id| when new IDC was added.
233 // Collapses large ranges of ids before looking for UMA enum.
234 int CollapseCommandsForUMA(int id
) {
235 DCHECK(!RenderViewContextMenu::IsContentCustomCommandId(id
));
236 DCHECK(!ContextMenuMatcher::IsExtensionsCustomCommandId(id
));
238 if (id
>= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
&&
239 id
<= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST
) {
240 return IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
;
243 if (id
>= IDC_SPELLCHECK_LANGUAGES_FIRST
&&
244 id
<= IDC_SPELLCHECK_LANGUAGES_LAST
) {
245 return IDC_SPELLCHECK_LANGUAGES_FIRST
;
248 if (id
>= IDC_SPELLCHECK_SUGGESTION_0
&&
249 id
<= IDC_SPELLCHECK_SUGGESTION_LAST
) {
250 return IDC_SPELLCHECK_SUGGESTION_0
;
256 // Returns UMA enum value for command specified by |id| or -1 if not found.
257 int FindUMAEnumValueForCommand(int id
) {
258 if (RenderViewContextMenu::IsContentCustomCommandId(id
))
261 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id
))
264 id
= CollapseCommandsForUMA(id
);
265 const size_t kMappingSize
= arraysize(kUmaEnumToControlId
);
266 for (size_t i
= 0; i
< kMappingSize
; ++i
) {
267 if (kUmaEnumToControlId
[i
].control_id
== id
) {
268 return kUmaEnumToControlId
[i
].enum_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 // Returns the preference of the profile represented by the |context|.
285 PrefService
* GetPrefs(content::BrowserContext
* context
) {
286 return user_prefs::UserPrefs::Get(context
);
289 bool ExtensionPatternMatch(const extensions::URLPatternSet
& patterns
,
291 // No patterns means no restriction, so that implicitly matches.
292 if (patterns
.is_empty())
294 return patterns
.MatchesURL(url
);
297 const GURL
& GetDocumentURL(const content::ContextMenuParams
& params
) {
298 return params
.frame_url
.is_empty() ? params
.page_url
: params
.frame_url
;
301 content::Referrer
CreateSaveAsReferrer(
303 const content::ContextMenuParams
& params
) {
304 const GURL
& referring_url
= GetDocumentURL(params
);
305 return content::Referrer::SanitizeForRequest(
307 content::Referrer(referring_url
.GetAsReferrer(), params
.referrer_policy
));
310 content::WebContents
* GetWebContentsToUse(content::WebContents
* web_contents
) {
311 #if defined(ENABLE_EXTENSIONS)
312 // If we're viewing in a MimeHandlerViewGuest, use its embedder WebContents.
313 if (extensions::MimeHandlerViewGuest::FromWebContents(web_contents
)) {
314 WebContents
* top_level_web_contents
=
315 guest_view::GuestViewBase::GetTopLevelWebContents(web_contents
);
316 if (top_level_web_contents
)
317 return top_level_web_contents
;
323 bool g_custom_id_ranges_initialized
= false;
325 const int kSpellcheckRadioGroup
= 1;
330 gfx::Vector2d
RenderViewContextMenu::GetOffset(
331 RenderFrameHost
* render_frame_host
) {
332 gfx::Vector2d offset
;
333 #if defined(ENABLE_EXTENSIONS)
334 WebContents
* web_contents
=
335 WebContents::FromRenderFrameHost(render_frame_host
);
336 WebContents
* top_level_web_contents
=
337 guest_view::GuestViewBase::GetTopLevelWebContents(web_contents
);
338 if (web_contents
&& top_level_web_contents
&&
339 web_contents
!= top_level_web_contents
) {
340 gfx::Rect bounds
= web_contents
->GetContainerBounds();
341 gfx::Rect top_level_bounds
= top_level_web_contents
->GetContainerBounds();
342 offset
= bounds
.origin() - top_level_bounds
.origin();
344 #endif // defined(ENABLE_EXTENSIONS)
349 bool RenderViewContextMenu::IsDevToolsURL(const GURL
& url
) {
350 return url
.SchemeIs(content::kChromeDevToolsScheme
);
354 bool RenderViewContextMenu::IsInternalResourcesURL(const GURL
& url
) {
355 if (!url
.SchemeIs(content::kChromeUIScheme
))
357 return url
.host() == chrome::kChromeUISyncResourcesHost
;
360 RenderViewContextMenu::RenderViewContextMenu(
361 content::RenderFrameHost
* render_frame_host
,
362 const content::ContextMenuParams
& params
)
363 : RenderViewContextMenuBase(render_frame_host
, params
),
364 extension_items_(browser_context_
,
367 base::Bind(MenuItemMatchesParams
, params_
)),
368 protocol_handler_submenu_model_(this),
369 protocol_handler_registry_(
370 ProtocolHandlerRegistryFactory::GetForBrowserContext(GetProfile())),
371 embedder_web_contents_(GetWebContentsToUse(source_web_contents_
)) {
372 if (!g_custom_id_ranges_initialized
) {
373 g_custom_id_ranges_initialized
= true;
374 SetContentCustomCommandIdRange(IDC_CONTENT_CONTEXT_CUSTOM_FIRST
,
375 IDC_CONTENT_CONTEXT_CUSTOM_LAST
);
377 set_content_type(ContextMenuContentTypeFactory::Create(
378 source_web_contents_
, params
));
381 RenderViewContextMenu::~RenderViewContextMenu() {
384 // Menu construction functions -------------------------------------------------
386 #if defined(ENABLE_EXTENSIONS)
388 bool RenderViewContextMenu::ExtensionContextAndPatternMatch(
389 const content::ContextMenuParams
& params
,
390 const MenuItem::ContextList
& contexts
,
391 const extensions::URLPatternSet
& target_url_patterns
) {
392 const bool has_link
= !params
.link_url
.is_empty();
393 const bool has_selection
= !params
.selection_text
.empty();
394 const bool in_frame
= !params
.frame_url
.is_empty();
396 if (contexts
.Contains(MenuItem::ALL
) ||
397 (has_selection
&& contexts
.Contains(MenuItem::SELECTION
)) ||
398 (params
.is_editable
&& contexts
.Contains(MenuItem::EDITABLE
)) ||
399 (in_frame
&& contexts
.Contains(MenuItem::FRAME
)))
402 if (has_link
&& contexts
.Contains(MenuItem::LINK
) &&
403 ExtensionPatternMatch(target_url_patterns
, params
.link_url
))
406 switch (params
.media_type
) {
407 case WebContextMenuData::MediaTypeImage
:
408 if (contexts
.Contains(MenuItem::IMAGE
) &&
409 ExtensionPatternMatch(target_url_patterns
, params
.src_url
))
413 case WebContextMenuData::MediaTypeVideo
:
414 if (contexts
.Contains(MenuItem::VIDEO
) &&
415 ExtensionPatternMatch(target_url_patterns
, params
.src_url
))
419 case WebContextMenuData::MediaTypeAudio
:
420 if (contexts
.Contains(MenuItem::AUDIO
) &&
421 ExtensionPatternMatch(target_url_patterns
, params
.src_url
))
429 // PAGE is the least specific context, so we only examine that if none of the
430 // other contexts apply (except for FRAME, which is included in PAGE for
431 // backwards compatibility).
432 if (!has_link
&& !has_selection
&& !params
.is_editable
&&
433 params
.media_type
== WebContextMenuData::MediaTypeNone
&&
434 contexts
.Contains(MenuItem::PAGE
))
441 bool RenderViewContextMenu::MenuItemMatchesParams(
442 const content::ContextMenuParams
& params
,
443 const extensions::MenuItem
* item
) {
444 bool match
= ExtensionContextAndPatternMatch(params
, item
->contexts(),
445 item
->target_url_patterns());
449 const GURL
& document_url
= GetDocumentURL(params
);
450 return ExtensionPatternMatch(item
->document_url_patterns(), document_url
);
453 void RenderViewContextMenu::AppendAllExtensionItems() {
454 extension_items_
.Clear();
455 ExtensionService
* service
=
456 extensions::ExtensionSystem::Get(browser_context_
)->extension_service();
458 return; // In unit-tests, we may not have an ExtensionService.
460 MenuManager
* menu_manager
= MenuManager::Get(browser_context_
);
464 base::string16 printable_selection_text
= PrintableSelectionText();
465 EscapeAmpersands(&printable_selection_text
);
467 // Get a list of extension id's that have context menu items, and sort by the
468 // top level context menu title of the extension.
469 std::set
<MenuItem::ExtensionKey
> ids
= menu_manager
->ExtensionIds();
470 std::vector
<base::string16
> sorted_menu_titles
;
471 std::map
<base::string16
, std::vector
<const Extension
*>>
472 title_to_extensions_map
;
473 for (std::set
<MenuItem::ExtensionKey
>::iterator iter
= ids
.begin();
476 const Extension
* extension
=
477 service
->GetExtensionById(iter
->extension_id
, false);
478 // Platform apps have their context menus created directly in
479 // AppendPlatformAppItems.
480 if (extension
&& !extension
->is_platform_app()) {
481 base::string16 menu_title
= extension_items_
.GetTopLevelContextMenuTitle(
482 *iter
, printable_selection_text
);
483 title_to_extensions_map
[menu_title
].push_back(extension
);
484 sorted_menu_titles
.push_back(menu_title
);
487 if (sorted_menu_titles
.empty())
490 const std::string app_locale
= g_browser_process
->GetApplicationLocale();
491 l10n_util::SortStrings16(app_locale
, &sorted_menu_titles
);
492 sorted_menu_titles
.erase(
493 std::unique(sorted_menu_titles
.begin(), sorted_menu_titles
.end()),
494 sorted_menu_titles
.end());
497 for (size_t i
= 0; i
< sorted_menu_titles
.size(); ++i
) {
498 std::vector
<const Extension
*>& extensions
=
499 title_to_extensions_map
[sorted_menu_titles
[i
]];
500 for (const auto& extension
: extensions
) {
501 MenuItem::ExtensionKey
extension_key(extension
->id());
502 extension_items_
.AppendExtensionItems(extension_key
,
503 printable_selection_text
, &index
,
504 false); // is_action_menu
509 void RenderViewContextMenu::AppendCurrentExtensionItems() {
510 // Avoid appending extension related items when |extension| is null.
511 // For Panel, this happens when the panel is navigated to a url outside of the
512 // extension's package.
513 const Extension
* extension
= GetExtension();
517 extensions::WebViewGuest
* web_view_guest
=
518 extensions::WebViewGuest::FromWebContents(source_web_contents_
);
519 MenuItem::ExtensionKey key
;
520 if (web_view_guest
) {
521 key
= MenuItem::ExtensionKey(
523 web_view_guest
->owner_web_contents()->GetRenderProcessHost()->GetID(),
524 web_view_guest
->view_instance_id());
526 key
= MenuItem::ExtensionKey(extension
->id());
529 // Only add extension items from this extension.
531 extension_items_
.AppendExtensionItems(key
, PrintableSelectionText(), &index
,
532 false /* is_action_menu */);
534 #endif // defined(ENABLE_EXTENSIONS)
536 void RenderViewContextMenu::InitMenu() {
537 RenderViewContextMenuBase::InitMenu();
539 if (content_type_
->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PAGE
))
542 if (content_type_
->SupportsGroup(ContextMenuContentType::ITEM_GROUP_FRAME
)) {
543 // Merge in frame items with page items if we clicked within a frame that
545 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
549 if (content_type_
->SupportsGroup(ContextMenuContentType::ITEM_GROUP_LINK
)) {
551 if (params_
.media_type
!= WebContextMenuData::MediaTypeNone
)
552 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
555 if (content_type_
->SupportsGroup(
556 ContextMenuContentType::ITEM_GROUP_MEDIA_IMAGE
)) {
560 if (content_type_
->SupportsGroup(
561 ContextMenuContentType::ITEM_GROUP_SEARCHWEBFORIMAGE
)) {
562 AppendSearchWebForImageItems();
565 if (content_type_
->SupportsGroup(
566 ContextMenuContentType::ITEM_GROUP_MEDIA_VIDEO
)) {
570 if (content_type_
->SupportsGroup(
571 ContextMenuContentType::ITEM_GROUP_MEDIA_AUDIO
)) {
575 if (content_type_
->SupportsGroup(
576 ContextMenuContentType::ITEM_GROUP_MEDIA_CANVAS
)) {
580 if (content_type_
->SupportsGroup(
581 ContextMenuContentType::ITEM_GROUP_MEDIA_PLUGIN
)) {
585 // ITEM_GROUP_MEDIA_FILE has no specific items.
587 if (content_type_
->SupportsGroup(ContextMenuContentType::ITEM_GROUP_EDITABLE
))
588 AppendEditableItems();
590 if (content_type_
->SupportsGroup(ContextMenuContentType::ITEM_GROUP_COPY
)) {
591 DCHECK(!content_type_
->SupportsGroup(
592 ContextMenuContentType::ITEM_GROUP_EDITABLE
));
596 if (content_type_
->SupportsGroup(
597 ContextMenuContentType::ITEM_GROUP_SEARCH_PROVIDER
)) {
598 AppendSearchProvider();
601 if (content_type_
->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT
))
604 if (content_type_
->SupportsGroup(
605 ContextMenuContentType::ITEM_GROUP_MEDIA_PLUGIN
)) {
606 AppendRotationItems();
609 if (content_type_
->SupportsGroup(
610 ContextMenuContentType::ITEM_GROUP_ALL_EXTENSION
)) {
611 DCHECK(!content_type_
->SupportsGroup(
612 ContextMenuContentType::ITEM_GROUP_CURRENT_EXTENSION
));
613 AppendAllExtensionItems();
616 if (content_type_
->SupportsGroup(
617 ContextMenuContentType::ITEM_GROUP_CURRENT_EXTENSION
)) {
618 DCHECK(!content_type_
->SupportsGroup(
619 ContextMenuContentType::ITEM_GROUP_ALL_EXTENSION
));
620 AppendCurrentExtensionItems();
623 if (content_type_
->SupportsGroup(
624 ContextMenuContentType::ITEM_GROUP_DEVELOPER
)) {
625 AppendDeveloperItems();
628 if (content_type_
->SupportsGroup(
629 ContextMenuContentType::ITEM_GROUP_DEVTOOLS_UNPACKED_EXT
)) {
630 AppendDevtoolsForUnpackedExtensions();
633 if (content_type_
->SupportsGroup(
634 ContextMenuContentType::ITEM_GROUP_PRINT_PREVIEW
)) {
635 AppendPrintPreviewItems();
638 if (content_type_
->SupportsGroup(
639 ContextMenuContentType::ITEM_GROUP_PASSWORD
)) {
640 AppendPasswordItems();
644 Profile
* RenderViewContextMenu::GetProfile() {
645 return Profile::FromBrowserContext(browser_context_
);
648 void RenderViewContextMenu::RecordUsedItem(int id
) {
649 int enum_id
= FindUMAEnumValueForCommand(id
);
651 const size_t kMappingSize
= arraysize(kUmaEnumToControlId
);
652 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Used", enum_id
,
653 kUmaEnumToControlId
[kMappingSize
- 1].enum_id
);
655 NOTREACHED() << "Update kUmaEnumToControlId. Unhanded IDC: " << id
;
659 void RenderViewContextMenu::RecordShownItem(int id
) {
660 int enum_id
= FindUMAEnumValueForCommand(id
);
662 const size_t kMappingSize
= arraysize(kUmaEnumToControlId
);
663 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Shown", enum_id
,
664 kUmaEnumToControlId
[kMappingSize
- 1].enum_id
);
666 // Just warning here. It's harder to maintain list of all possibly
667 // visible items than executable items.
668 DLOG(ERROR
) << "Update kUmaEnumToControlId. Unhanded IDC: " << id
;
672 #if defined(ENABLE_PLUGINS)
673 void RenderViewContextMenu::HandleAuthorizeAllPlugins() {
674 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins(
675 source_web_contents_
, false, std::string());
679 void RenderViewContextMenu::AppendPrintPreviewItems() {
680 #if defined(ENABLE_PRINT_PREVIEW)
681 if (!print_preview_menu_observer_
.get()) {
682 print_preview_menu_observer_
.reset(
683 new PrintPreviewContextMenuObserver(source_web_contents_
));
686 observers_
.AddObserver(print_preview_menu_observer_
.get());
690 const Extension
* RenderViewContextMenu::GetExtension() const {
691 return extensions::ProcessManager::Get(browser_context_
)
692 ->GetExtensionForWebContents(source_web_contents_
);
695 void RenderViewContextMenu::AppendDeveloperItems() {
696 // Show Inspect Element in DevTools itself only in case of the debug
698 bool show_developer_items
= !IsDevToolsURL(params_
.page_url
);
700 #if defined(DEBUG_DEVTOOLS)
701 show_developer_items
= true;
704 if (!show_developer_items
)
707 // In the DevTools popup menu, "developer items" is normally the only
708 // section, so omit the separator there.
709 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
710 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTELEMENT
,
711 IDS_CONTENT_CONTEXT_INSPECTELEMENT
);
714 void RenderViewContextMenu::AppendDevtoolsForUnpackedExtensions() {
715 // Add a separator if there are any items already in the menu.
716 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
718 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP
,
719 IDS_CONTENT_CONTEXT_RELOAD_PACKAGED_APP
);
720 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP
,
721 IDS_CONTENT_CONTEXT_RESTART_APP
);
722 AppendDeveloperItems();
723 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE
,
724 IDS_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE
);
727 void RenderViewContextMenu::AppendLinkItems() {
728 if (!params_
.link_url
.is_empty()) {
729 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB
,
730 IDS_CONTENT_CONTEXT_OPENLINKNEWTAB
);
731 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW
,
732 IDS_CONTENT_CONTEXT_OPENLINKNEWWINDOW
);
733 if (params_
.link_url
.is_valid()) {
734 AppendProtocolHandlerSubMenu();
737 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD
,
738 IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD
);
739 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVELINKAS
,
740 IDS_CONTENT_CONTEXT_SAVELINKAS
);
743 menu_model_
.AddItemWithStringId(
744 IDC_CONTENT_CONTEXT_COPYLINKLOCATION
,
745 params_
.link_url
.SchemeIs(url::kMailToScheme
) ?
746 IDS_CONTENT_CONTEXT_COPYEMAILADDRESS
:
747 IDS_CONTENT_CONTEXT_COPYLINKLOCATION
);
750 void RenderViewContextMenu::AppendImageItems() {
751 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS
,
752 IDS_CONTENT_CONTEXT_SAVEIMAGEAS
);
753 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGELOCATION
,
754 IDS_CONTENT_CONTEXT_COPYIMAGELOCATION
);
755 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE
,
756 IDS_CONTENT_CONTEXT_COPYIMAGE
);
757 std::map
<std::string
, std::string
>::const_iterator it
=
758 params_
.properties
.find(data_reduction_proxy::chrome_proxy_header());
759 if (it
!= params_
.properties
.end() && it
->second
==
760 data_reduction_proxy::chrome_proxy_lo_fi_directive()) {
761 menu_model_
.AddItemWithStringId(
762 IDC_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE
,
763 IDS_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE
);
765 DataReductionProxyChromeSettings
* settings
=
766 DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
768 if (settings
&& settings
->CanUseDataReductionProxy(params_
.src_url
)) {
769 menu_model_
.AddItemWithStringId(
770 IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB
,
771 IDS_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB
);
773 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB
,
774 IDS_CONTENT_CONTEXT_OPENIMAGENEWTAB
);
778 void RenderViewContextMenu::AppendSearchWebForImageItems() {
779 TemplateURLService
* service
=
780 TemplateURLServiceFactory::GetForProfile(GetProfile());
781 const TemplateURL
* const default_provider
=
782 service
->GetDefaultSearchProvider();
783 if (params_
.has_image_contents
&& default_provider
&&
784 !default_provider
->image_url().empty() &&
785 default_provider
->image_url_ref().IsValid(service
->search_terms_data())) {
787 IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE
,
788 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFORIMAGE
,
789 default_provider
->short_name()));
793 void RenderViewContextMenu::AppendAudioItems() {
795 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
796 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS
,
797 IDS_CONTENT_CONTEXT_SAVEAUDIOAS
);
798 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION
,
799 IDS_CONTENT_CONTEXT_COPYAUDIOLOCATION
);
800 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB
,
801 IDS_CONTENT_CONTEXT_OPENAUDIONEWTAB
);
804 void RenderViewContextMenu::AppendCanvasItems() {
805 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS
,
806 IDS_CONTENT_CONTEXT_SAVEIMAGEAS
);
807 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE
,
808 IDS_CONTENT_CONTEXT_COPYIMAGE
);
811 void RenderViewContextMenu::AppendVideoItems() {
813 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
814 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS
,
815 IDS_CONTENT_CONTEXT_SAVEVIDEOAS
);
816 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION
,
817 IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION
);
818 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB
,
819 IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB
);
822 void RenderViewContextMenu::AppendMediaItems() {
823 int media_flags
= params_
.media_flags
;
825 menu_model_
.AddItemWithStringId(
826 IDC_CONTENT_CONTEXT_PLAYPAUSE
,
827 media_flags
& WebContextMenuData::MediaPaused
?
828 IDS_CONTENT_CONTEXT_PLAY
:
829 IDS_CONTENT_CONTEXT_PAUSE
);
831 menu_model_
.AddItemWithStringId(
832 IDC_CONTENT_CONTEXT_MUTE
,
833 media_flags
& WebContextMenuData::MediaMuted
?
834 IDS_CONTENT_CONTEXT_UNMUTE
:
835 IDS_CONTENT_CONTEXT_MUTE
);
837 menu_model_
.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_LOOP
,
838 IDS_CONTENT_CONTEXT_LOOP
);
839 menu_model_
.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_CONTROLS
,
840 IDS_CONTENT_CONTEXT_CONTROLS
);
843 void RenderViewContextMenu::AppendPluginItems() {
844 if (params_
.page_url
== params_
.src_url
||
845 guest_view::GuestViewBase::IsGuest(source_web_contents_
)) {
846 // Full page plugin, so show page menu items.
847 if (params_
.link_url
.is_empty() && params_
.selection_text
.empty())
850 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS
,
851 IDS_CONTENT_CONTEXT_SAVEPAGEAS
);
852 // The "Print" menu item should always be included for plugins. If
853 // content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT)
854 // is true the item will be added inside AppendPrintItem(). Otherwise we
856 if (!content_type_
->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT
))
857 menu_model_
.AddItemWithStringId(IDC_PRINT
, IDS_CONTENT_CONTEXT_PRINT
);
861 void RenderViewContextMenu::AppendPageItems() {
862 menu_model_
.AddItemWithStringId(IDC_BACK
, IDS_CONTENT_CONTEXT_BACK
);
863 menu_model_
.AddItemWithStringId(IDC_FORWARD
, IDS_CONTENT_CONTEXT_FORWARD
);
864 menu_model_
.AddItemWithStringId(IDC_RELOAD
, IDS_CONTENT_CONTEXT_RELOAD
);
865 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
866 menu_model_
.AddItemWithStringId(IDC_SAVE_PAGE
,
867 IDS_CONTENT_CONTEXT_SAVEPAGEAS
);
868 menu_model_
.AddItemWithStringId(IDC_PRINT
, IDS_CONTENT_CONTEXT_PRINT
);
870 if (TranslateService::IsTranslatableURL(params_
.page_url
)) {
871 std::string locale
= g_browser_process
->GetApplicationLocale();
872 locale
= translate::TranslateDownloadManager::GetLanguageCode(locale
);
873 base::string16 language
=
874 l10n_util::GetDisplayNameForLocale(locale
, locale
, true);
876 IDC_CONTENT_CONTEXT_TRANSLATE
,
877 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_TRANSLATE
, language
));
880 menu_model_
.AddItemWithStringId(IDC_VIEW_SOURCE
,
881 IDS_CONTENT_CONTEXT_VIEWPAGESOURCE
);
882 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWPAGEINFO
,
883 IDS_CONTENT_CONTEXT_VIEWPAGEINFO
);
886 void RenderViewContextMenu::AppendFrameItems() {
887 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOADFRAME
,
888 IDS_CONTENT_CONTEXT_RELOADFRAME
);
889 // These two menu items have yet to be implemented.
890 // http://code.google.com/p/chromium/issues/detail?id=11827
891 // IDS_CONTENT_CONTEXT_SAVEFRAMEAS
892 // IDS_CONTENT_CONTEXT_PRINTFRAME
893 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE
,
894 IDS_CONTENT_CONTEXT_VIEWFRAMESOURCE
);
895 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMEINFO
,
896 IDS_CONTENT_CONTEXT_VIEWFRAMEINFO
);
899 void RenderViewContextMenu::AppendCopyItem() {
900 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY
,
901 IDS_CONTENT_CONTEXT_COPY
);
904 void RenderViewContextMenu::AppendPrintItem() {
905 if (GetPrefs(browser_context_
)->GetBoolean(prefs::kPrintingEnabled
) &&
906 (params_
.media_type
== WebContextMenuData::MediaTypeNone
||
907 params_
.media_flags
& WebContextMenuData::MediaCanPrint
)) {
908 menu_model_
.AddItemWithStringId(IDC_PRINT
, IDS_CONTENT_CONTEXT_PRINT
);
912 void RenderViewContextMenu::AppendRotationItems() {
913 if (params_
.media_flags
& WebContextMenuData::MediaCanRotate
) {
914 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
915 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECW
,
916 IDS_CONTENT_CONTEXT_ROTATECW
);
917 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECCW
,
918 IDS_CONTENT_CONTEXT_ROTATECCW
);
922 void RenderViewContextMenu::AppendSearchProvider() {
923 DCHECK(browser_context_
);
925 base::TrimWhitespace(params_
.selection_text
, base::TRIM_ALL
,
926 ¶ms_
.selection_text
);
927 if (params_
.selection_text
.empty())
930 base::ReplaceChars(params_
.selection_text
, AutocompleteMatch::kInvalidChars
,
931 base::ASCIIToUTF16(" "), ¶ms_
.selection_text
);
933 AutocompleteMatch match
;
934 AutocompleteClassifierFactory::GetForProfile(GetProfile())->Classify(
935 params_
.selection_text
,
938 metrics::OmniboxEventProto::INVALID_SPEC
,
941 selection_navigation_url_
= match
.destination_url
;
942 if (!selection_navigation_url_
.is_valid())
945 base::string16 printable_selection_text
= PrintableSelectionText();
946 EscapeAmpersands(&printable_selection_text
);
948 if (AutocompleteMatch::IsSearchType(match
.type
)) {
949 const TemplateURL
* const default_provider
=
950 TemplateURLServiceFactory::GetForProfile(GetProfile())
951 ->GetDefaultSearchProvider();
952 if (!default_provider
)
955 IDC_CONTENT_CONTEXT_SEARCHWEBFOR
,
956 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFOR
,
957 default_provider
->short_name(),
958 printable_selection_text
));
960 if ((selection_navigation_url_
!= params_
.link_url
) &&
961 ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme(
962 selection_navigation_url_
.scheme())) {
964 IDC_CONTENT_CONTEXT_GOTOURL
,
965 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_GOTOURL
,
966 printable_selection_text
));
971 void RenderViewContextMenu::AppendEditableItems() {
972 const bool use_spellcheck_and_search
= !chrome::IsRunningInForcedAppMode();
974 if (use_spellcheck_and_search
)
975 AppendSpellingSuggestionsSubMenu();
977 if (!IsDevToolsURL(params_
.page_url
)) {
978 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_UNDO
,
979 IDS_CONTENT_CONTEXT_UNDO
);
980 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_REDO
,
981 IDS_CONTENT_CONTEXT_REDO
);
982 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
985 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_CUT
,
986 IDS_CONTENT_CONTEXT_CUT
);
987 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY
,
988 IDS_CONTENT_CONTEXT_COPY
);
989 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE
,
990 IDS_CONTENT_CONTEXT_PASTE
);
991 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE
,
992 IDS_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE
);
993 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_DELETE
,
994 IDS_CONTENT_CONTEXT_DELETE
);
995 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
997 if (use_spellcheck_and_search
&& !params_
.keyword_url
.is_empty()) {
998 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_ADDSEARCHENGINE
,
999 IDS_CONTENT_CONTEXT_ADDSEARCHENGINE
);
1000 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
1003 #if defined(OS_MACOSX)
1004 if (use_spellcheck_and_search
)
1005 AppendSpellcheckOptionsSubMenu();
1007 if (chrome::spellcheck_common::IsMultilingualSpellcheckEnabled()) {
1008 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS
,
1009 IDS_CONTENT_CONTEXT_LANGUAGE_SETTINGS
);
1010 } else if (use_spellcheck_and_search
) {
1011 AppendSpellcheckOptionsSubMenu();
1013 #endif // defined(OS_MACOSX)
1015 AppendPlatformEditableItems();
1017 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
1018 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_SELECTALL
,
1019 IDS_CONTENT_CONTEXT_SELECTALL
);
1022 void RenderViewContextMenu::AppendSpellingSuggestionsSubMenu() {
1023 if (!spelling_menu_observer_
.get())
1024 spelling_menu_observer_
.reset(new SpellingMenuObserver(this));
1025 observers_
.AddObserver(spelling_menu_observer_
.get());
1026 spelling_menu_observer_
->InitMenu(params_
);
1029 void RenderViewContextMenu::AppendSpellcheckOptionsSubMenu() {
1030 if (!spellchecker_submenu_observer_
.get()) {
1031 spellchecker_submenu_observer_
.reset(new SpellCheckerSubMenuObserver(
1032 this, this, kSpellcheckRadioGroup
));
1034 spellchecker_submenu_observer_
->InitMenu(params_
);
1035 observers_
.AddObserver(spellchecker_submenu_observer_
.get());
1038 void RenderViewContextMenu::AppendProtocolHandlerSubMenu() {
1039 const ProtocolHandlerRegistry::ProtocolHandlerList handlers
=
1040 GetHandlersForLinkUrl();
1041 if (handlers
.empty())
1043 size_t max
= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST
-
1044 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
;
1045 for (size_t i
= 0; i
< handlers
.size() && i
<= max
; i
++) {
1046 protocol_handler_submenu_model_
.AddItem(
1047 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
+ i
,
1048 base::UTF8ToUTF16(handlers
[i
].url().host()));
1050 protocol_handler_submenu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
1051 protocol_handler_submenu_model_
.AddItem(
1052 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS
,
1053 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH_CONFIGURE
));
1055 menu_model_
.AddSubMenu(
1056 IDC_CONTENT_CONTEXT_OPENLINKWITH
,
1057 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH
),
1058 &protocol_handler_submenu_model_
);
1061 void RenderViewContextMenu::AppendPasswordItems() {
1062 if (!password_manager::ForceSavingExperimentEnabled())
1065 menu_model_
.AddSeparator(ui::NORMAL_SEPARATOR
);
1066 menu_model_
.AddItemWithStringId(IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD
,
1067 IDS_CONTENT_CONTEXT_FORCESAVEPASSWORD
);
1070 // Menu delegate functions -----------------------------------------------------
1072 bool RenderViewContextMenu::IsCommandIdEnabled(int id
) const {
1074 bool enabled
= false;
1075 if (RenderViewContextMenuBase::IsCommandIdKnown(id
, &enabled
))
1079 CoreTabHelper
* core_tab_helper
=
1080 CoreTabHelper::FromWebContents(source_web_contents_
);
1081 int content_restrictions
= 0;
1082 if (core_tab_helper
)
1083 content_restrictions
= core_tab_helper
->content_restrictions();
1084 if (id
== IDC_PRINT
&& (content_restrictions
& CONTENT_RESTRICTION_PRINT
))
1087 if (id
== IDC_SAVE_PAGE
&&
1088 (content_restrictions
& CONTENT_RESTRICTION_SAVE
)) {
1092 PrefService
* prefs
= GetPrefs(browser_context_
);
1094 // Allow Spell Check language items on sub menu for text area context menu.
1095 if ((id
>= IDC_SPELLCHECK_LANGUAGES_FIRST
) &&
1096 (id
< IDC_SPELLCHECK_LANGUAGES_LAST
)) {
1097 return prefs
->GetBoolean(prefs::kEnableContinuousSpellcheck
);
1101 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id
))
1102 return extension_items_
.IsCommandIdEnabled(id
);
1104 if (id
>= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
&&
1105 id
<= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST
) {
1109 IncognitoModePrefs::Availability incognito_avail
=
1110 IncognitoModePrefs::GetAvailability(prefs
);
1113 return embedder_web_contents_
->GetController().CanGoBack();
1116 return embedder_web_contents_
->GetController().CanGoForward();
1119 CoreTabHelper
* core_tab_helper
=
1120 CoreTabHelper::FromWebContents(embedder_web_contents_
);
1121 if (!core_tab_helper
)
1124 CoreTabHelperDelegate
* core_delegate
= core_tab_helper
->delegate();
1125 return !core_delegate
||
1126 core_delegate
->CanReloadContents(embedder_web_contents_
);
1129 case IDC_VIEW_SOURCE
:
1130 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE
:
1131 return embedder_web_contents_
->GetController().CanViewSource();
1133 case IDC_CONTENT_CONTEXT_INSPECTELEMENT
:
1134 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE
:
1135 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP
:
1136 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP
:
1137 return IsDevCommandEnabled(id
);
1139 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO
:
1140 if (embedder_web_contents_
->GetController().GetVisibleEntry() == NULL
)
1142 // Disabled if no browser is associated (e.g. desktop notifications).
1143 if (chrome::FindBrowserWithWebContents(embedder_web_contents_
) == NULL
)
1147 case IDC_CONTENT_CONTEXT_TRANSLATE
: {
1148 ChromeTranslateClient
* chrome_translate_client
=
1149 ChromeTranslateClient::FromWebContents(embedder_web_contents_
);
1150 if (!chrome_translate_client
)
1152 std::string original_lang
=
1153 chrome_translate_client
->GetLanguageState().original_language();
1154 std::string target_lang
= g_browser_process
->GetApplicationLocale();
1156 translate::TranslateDownloadManager::GetLanguageCode(target_lang
);
1157 // Note that we intentionally enable the menu even if the original and
1158 // target languages are identical. This is to give a way to user to
1159 // translate a page that might contains text fragments in a different
1161 return ((params_
.edit_flags
& WebContextMenuData::CanTranslate
) != 0) &&
1162 !original_lang
.empty() && // Did we receive the page language yet?
1163 !chrome_translate_client
->GetLanguageState().IsPageTranslated() &&
1164 !embedder_web_contents_
->GetInterstitialPage() &&
1165 // There are some application locales which can't be used as a
1166 // target language for translation.
1167 translate::TranslateDownloadManager::IsSupportedLanguage(
1169 // Disable on the Instant Extended NTP.
1170 !search::IsInstantNTP(embedder_web_contents_
);
1173 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB
:
1174 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW
:
1175 return params_
.link_url
.is_valid();
1177 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION
:
1178 return params_
.unfiltered_link_url
.is_valid();
1180 case IDC_CONTENT_CONTEXT_SAVELINKAS
: {
1181 PrefService
* local_state
= g_browser_process
->local_state();
1182 DCHECK(local_state
);
1183 // Test if file-selection dialogs are forbidden by policy.
1184 if (!local_state
->GetBoolean(prefs::kAllowFileSelectionDialogs
))
1187 return params_
.link_url
.is_valid() &&
1188 ProfileIOData::IsHandledProtocol(params_
.link_url
.scheme());
1191 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS
: {
1192 PrefService
* local_state
= g_browser_process
->local_state();
1193 DCHECK(local_state
);
1194 // Test if file-selection dialogs are forbidden by policy.
1195 if (!local_state
->GetBoolean(prefs::kAllowFileSelectionDialogs
))
1198 return params_
.has_image_contents
;
1201 // The images shown in the most visited thumbnails can't be opened or
1202 // searched for conventionally.
1203 case IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB
:
1204 case IDC_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE
:
1205 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB
:
1206 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE
:
1207 return params_
.src_url
.is_valid() &&
1208 (params_
.src_url
.scheme() != content::kChromeUIScheme
);
1210 case IDC_CONTENT_CONTEXT_COPYIMAGE
:
1211 return params_
.has_image_contents
;
1213 // Media control commands should all be disabled if the player is in an
1215 case IDC_CONTENT_CONTEXT_PLAYPAUSE
:
1216 case IDC_CONTENT_CONTEXT_LOOP
:
1217 return (params_
.media_flags
&
1218 WebContextMenuData::MediaInError
) == 0;
1220 // Mute and unmute should also be disabled if the player has no audio.
1221 case IDC_CONTENT_CONTEXT_MUTE
:
1222 return (params_
.media_flags
&
1223 WebContextMenuData::MediaHasAudio
) != 0 &&
1224 (params_
.media_flags
&
1225 WebContextMenuData::MediaInError
) == 0;
1227 case IDC_CONTENT_CONTEXT_CONTROLS
:
1228 return (params_
.media_flags
&
1229 WebContextMenuData::MediaCanToggleControls
) != 0;
1231 case IDC_CONTENT_CONTEXT_ROTATECW
:
1232 case IDC_CONTENT_CONTEXT_ROTATECCW
:
1234 (params_
.media_flags
& WebContextMenuData::MediaCanRotate
) != 0;
1236 case IDC_CONTENT_CONTEXT_COPYAVLOCATION
:
1237 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION
:
1238 return params_
.src_url
.is_valid();
1240 case IDC_CONTENT_CONTEXT_SAVEAVAS
: {
1241 PrefService
* local_state
= g_browser_process
->local_state();
1242 DCHECK(local_state
);
1243 // Test if file-selection dialogs are forbidden by policy.
1244 if (!local_state
->GetBoolean(prefs::kAllowFileSelectionDialogs
))
1247 const GURL
& url
= params_
.src_url
;
1249 (params_
.media_flags
& WebContextMenuData::MediaCanSave
) &&
1250 url
.is_valid() && ProfileIOData::IsHandledProtocol(url
.scheme());
1251 #if defined(ENABLE_PRINT_PREVIEW)
1252 // Do not save the preview PDF on the print preview page.
1253 can_save
= can_save
&&
1254 !(printing::PrintPreviewDialogController::IsPrintPreviewURL(url
));
1259 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB
:
1260 // Currently, a media element can be opened in a new tab iff it can
1261 // be saved. So rather than duplicating the MediaCanSave flag, we rely
1263 return !!(params_
.media_flags
& WebContextMenuData::MediaCanSave
);
1265 case IDC_SAVE_PAGE
: {
1266 CoreTabHelper
* core_tab_helper
=
1267 CoreTabHelper::FromWebContents(embedder_web_contents_
);
1268 if (!core_tab_helper
)
1271 CoreTabHelperDelegate
* core_delegate
= core_tab_helper
->delegate();
1272 if (core_delegate
&&
1273 !core_delegate
->CanSaveContents(embedder_web_contents_
))
1276 PrefService
* local_state
= g_browser_process
->local_state();
1277 DCHECK(local_state
);
1278 // Test if file-selection dialogs are forbidden by policy.
1279 if (!local_state
->GetBoolean(prefs::kAllowFileSelectionDialogs
))
1282 // We save the last committed entry (which the user is looking at), as
1283 // opposed to any pending URL that hasn't committed yet.
1284 NavigationEntry
* entry
=
1285 embedder_web_contents_
->GetController().GetLastCommittedEntry();
1286 return content::IsSavableURL(entry
? entry
->GetURL() : GURL());
1289 case IDC_CONTENT_CONTEXT_RELOADFRAME
:
1290 return params_
.frame_url
.is_valid();
1292 case IDC_CONTENT_CONTEXT_UNDO
:
1293 return !!(params_
.edit_flags
& WebContextMenuData::CanUndo
);
1295 case IDC_CONTENT_CONTEXT_REDO
:
1296 return !!(params_
.edit_flags
& WebContextMenuData::CanRedo
);
1298 case IDC_CONTENT_CONTEXT_CUT
:
1299 return !!(params_
.edit_flags
& WebContextMenuData::CanCut
);
1301 case IDC_CONTENT_CONTEXT_COPY
:
1302 return !!(params_
.edit_flags
& WebContextMenuData::CanCopy
);
1304 case IDC_CONTENT_CONTEXT_PASTE
: {
1305 if (!(params_
.edit_flags
& WebContextMenuData::CanPaste
))
1308 std::vector
<base::string16
> types
;
1310 ui::Clipboard::GetForCurrentThread()->ReadAvailableTypes(
1311 ui::CLIPBOARD_TYPE_COPY_PASTE
, &types
, &ignore
);
1312 return !types
.empty();
1315 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE
: {
1316 if (!(params_
.edit_flags
& WebContextMenuData::CanPaste
))
1319 return ui::Clipboard::GetForCurrentThread()->IsFormatAvailable(
1320 ui::Clipboard::GetPlainTextFormatType(),
1321 ui::CLIPBOARD_TYPE_COPY_PASTE
);
1324 case IDC_CONTENT_CONTEXT_DELETE
:
1325 return !!(params_
.edit_flags
& WebContextMenuData::CanDelete
);
1327 case IDC_CONTENT_CONTEXT_SELECTALL
:
1328 return !!(params_
.edit_flags
& WebContextMenuData::CanSelectAll
);
1330 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD
:
1331 return !browser_context_
->IsOffTheRecord() &&
1332 params_
.link_url
.is_valid() &&
1333 incognito_avail
!= IncognitoModePrefs::DISABLED
;
1336 return prefs
->GetBoolean(prefs::kPrintingEnabled
) &&
1337 (params_
.media_type
== WebContextMenuData::MediaTypeNone
||
1338 params_
.media_flags
& WebContextMenuData::MediaCanPrint
);
1340 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR
:
1341 case IDC_CONTENT_CONTEXT_GOTOURL
:
1342 case IDC_SPELLPANEL_TOGGLE
:
1343 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS
:
1345 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO
:
1346 // Disabled if no browser is associated (e.g. desktop notifications).
1347 if (chrome::FindBrowserWithWebContents(source_web_contents_
) == NULL
)
1351 case IDC_CHECK_SPELLING_WHILE_TYPING
:
1352 return prefs
->GetBoolean(prefs::kEnableContinuousSpellcheck
);
1354 #if !defined(OS_MACOSX) && defined(OS_POSIX)
1355 // TODO(suzhe): this should not be enabled for password fields.
1356 case IDC_INPUT_METHODS_MENU
:
1360 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE
:
1361 return !params_
.keyword_url
.is_empty();
1363 case IDC_SPELLCHECK_MENU
:
1366 case IDC_CONTENT_CONTEXT_OPENLINKWITH
:
1369 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS
:
1372 case IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD
:
1381 bool RenderViewContextMenu::IsCommandIdChecked(int id
) const {
1382 if (RenderViewContextMenuBase::IsCommandIdChecked(id
))
1385 // See if the video is set to looping.
1386 if (id
== IDC_CONTENT_CONTEXT_LOOP
)
1387 return (params_
.media_flags
& WebContextMenuData::MediaLoop
) != 0;
1389 if (id
== IDC_CONTENT_CONTEXT_CONTROLS
)
1390 return (params_
.media_flags
& WebContextMenuData::MediaControls
) != 0;
1393 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id
))
1394 return extension_items_
.IsCommandIdChecked(id
);
1399 void RenderViewContextMenu::ExecuteCommand(int id
, int event_flags
) {
1400 RenderViewContextMenuBase::ExecuteCommand(id
, event_flags
);
1401 if (command_executed_
)
1403 command_executed_
= true;
1405 RenderFrameHost
* render_frame_host
= GetRenderFrameHost();
1407 // Process extension menu items.
1408 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id
)) {
1409 extension_items_
.ExecuteCommand(id
, source_web_contents_
, params_
);
1413 if (id
>= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
&&
1414 id
<= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST
) {
1415 ProtocolHandlerRegistry::ProtocolHandlerList handlers
=
1416 GetHandlersForLinkUrl();
1417 if (handlers
.empty())
1420 content::RecordAction(
1421 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Open"));
1422 int handlerIndex
= id
- IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST
;
1423 WindowOpenDisposition disposition
=
1424 ForceNewTabDispositionFromEventFlags(event_flags
);
1425 OpenURL(handlers
[handlerIndex
].TranslateUrl(params_
.link_url
),
1426 GetDocumentURL(params_
),
1428 ui::PAGE_TRANSITION_LINK
);
1433 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB
: {
1435 chrome::FindBrowserWithWebContents(source_web_contents_
);
1436 OpenURL(params_
.link_url
,
1437 GetDocumentURL(params_
),
1438 !browser
|| browser
->is_app() ?
1439 NEW_FOREGROUND_TAB
: NEW_BACKGROUND_TAB
,
1440 ui::PAGE_TRANSITION_LINK
);
1443 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW
:
1444 OpenURL(params_
.link_url
,
1445 GetDocumentURL(params_
),
1447 ui::PAGE_TRANSITION_LINK
);
1450 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD
:
1451 OpenURL(params_
.link_url
, GURL(), OFF_THE_RECORD
,
1452 ui::PAGE_TRANSITION_LINK
);
1455 case IDC_CONTENT_CONTEXT_SAVELINKAS
: {
1456 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU
);
1457 const GURL
& url
= params_
.link_url
;
1458 content::Referrer referrer
= CreateSaveAsReferrer(url
, params_
);
1459 DownloadManager
* dlm
=
1460 BrowserContext::GetDownloadManager(browser_context_
);
1461 scoped_ptr
<DownloadUrlParameters
> dl_params(
1462 DownloadUrlParameters::FromWebContents(source_web_contents_
, url
));
1463 dl_params
->set_referrer(referrer
);
1464 dl_params
->set_referrer_encoding(params_
.frame_charset
);
1465 dl_params
->set_suggested_name(params_
.suggested_filename
);
1466 dl_params
->set_prompt(true);
1467 dlm
->DownloadUrl(dl_params
.Pass());
1471 case IDC_CONTENT_CONTEXT_SAVEAVAS
:
1472 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS
: {
1473 bool is_large_data_url
= params_
.has_image_contents
&&
1474 params_
.src_url
.is_empty();
1475 if (params_
.media_type
== WebContextMenuData::MediaTypeCanvas
||
1476 (params_
.media_type
== WebContextMenuData::MediaTypeImage
&&
1477 is_large_data_url
)) {
1478 source_web_contents_
->GetRenderViewHost()->SaveImageAt(
1479 params_
.x
, params_
.y
);
1481 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU
);
1482 const GURL
& url
= params_
.src_url
;
1483 content::Referrer referrer
= CreateSaveAsReferrer(url
, params_
);
1485 std::string headers
;
1486 DataReductionProxyChromeSettings
* settings
=
1487 DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
1489 if (params_
.media_type
== WebContextMenuData::MediaTypeImage
&&
1490 settings
&& settings
->CanUseDataReductionProxy(params_
.src_url
)) {
1491 headers
= data_reduction_proxy::kDataReductionPassThroughHeader
;
1494 source_web_contents_
->SaveFrameWithHeaders(url
, referrer
, headers
);
1499 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION
:
1500 WriteURLToClipboard(params_
.unfiltered_link_url
);
1503 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION
:
1504 case IDC_CONTENT_CONTEXT_COPYAVLOCATION
:
1505 WriteURLToClipboard(params_
.src_url
);
1508 case IDC_CONTENT_CONTEXT_COPYIMAGE
:
1509 CopyImageAt(params_
.x
, params_
.y
);
1512 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE
:
1513 GetImageThumbnailForSearch();
1516 case IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB
:
1517 OpenURLWithExtraHeaders(
1518 params_
.src_url
, GetDocumentURL(params_
), NEW_BACKGROUND_TAB
,
1519 ui::PAGE_TRANSITION_LINK
,
1520 data_reduction_proxy::kDataReductionPassThroughHeader
);
1523 case IDC_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE
:
1524 LoadOriginalImage();
1527 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB
:
1528 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB
:
1529 OpenURL(params_
.src_url
,
1530 GetDocumentURL(params_
),
1532 ui::PAGE_TRANSITION_LINK
);
1535 case IDC_CONTENT_CONTEXT_PLAYPAUSE
: {
1536 bool play
= !!(params_
.media_flags
& WebContextMenuData::MediaPaused
);
1538 content::RecordAction(UserMetricsAction("MediaContextMenu_Play"));
1540 content::RecordAction(UserMetricsAction("MediaContextMenu_Pause"));
1542 MediaPlayerActionAt(gfx::Point(params_
.x
, params_
.y
),
1543 WebMediaPlayerAction(
1544 WebMediaPlayerAction::Play
, play
));
1548 case IDC_CONTENT_CONTEXT_MUTE
: {
1549 bool mute
= !(params_
.media_flags
& WebContextMenuData::MediaMuted
);
1551 content::RecordAction(UserMetricsAction("MediaContextMenu_Mute"));
1553 content::RecordAction(UserMetricsAction("MediaContextMenu_Unmute"));
1555 MediaPlayerActionAt(gfx::Point(params_
.x
, params_
.y
),
1556 WebMediaPlayerAction(
1557 WebMediaPlayerAction::Mute
, mute
));
1561 case IDC_CONTENT_CONTEXT_LOOP
:
1562 content::RecordAction(UserMetricsAction("MediaContextMenu_Loop"));
1563 MediaPlayerActionAt(gfx::Point(params_
.x
, params_
.y
),
1564 WebMediaPlayerAction(
1565 WebMediaPlayerAction::Loop
,
1566 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_LOOP
)));
1569 case IDC_CONTENT_CONTEXT_CONTROLS
:
1570 content::RecordAction(UserMetricsAction("MediaContextMenu_Controls"));
1571 MediaPlayerActionAt(
1572 gfx::Point(params_
.x
, params_
.y
),
1573 WebMediaPlayerAction(
1574 WebMediaPlayerAction::Controls
,
1575 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_CONTROLS
)));
1578 case IDC_CONTENT_CONTEXT_ROTATECW
:
1579 content::RecordAction(
1580 UserMetricsAction("PluginContextMenu_RotateClockwise"));
1582 gfx::Point(params_
.x
, params_
.y
),
1583 WebPluginAction(WebPluginAction::Rotate90Clockwise
, true));
1586 case IDC_CONTENT_CONTEXT_ROTATECCW
:
1587 content::RecordAction(
1588 UserMetricsAction("PluginContextMenu_RotateCounterclockwise"));
1590 gfx::Point(params_
.x
, params_
.y
),
1591 WebPluginAction(WebPluginAction::Rotate90Counterclockwise
, true));
1595 embedder_web_contents_
->GetController().GoBack();
1599 embedder_web_contents_
->GetController().GoForward();
1603 embedder_web_contents_
->OnSavePage();
1607 embedder_web_contents_
->GetController().Reload(true);
1610 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP
: {
1611 const Extension
* platform_app
= GetExtension();
1612 DCHECK(platform_app
);
1613 DCHECK(platform_app
->is_platform_app());
1615 extensions::ExtensionSystem::Get(browser_context_
)
1616 ->extension_service()
1617 ->ReloadExtension(platform_app
->id());
1621 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP
: {
1622 const Extension
* platform_app
= GetExtension();
1623 DCHECK(platform_app
);
1624 DCHECK(platform_app
->is_platform_app());
1626 apps::AppLoadService::Get(GetProfile())
1627 ->RestartApplication(platform_app
->id());
1632 #if defined(ENABLE_PRINTING)
1633 if (params_
.media_type
!= WebContextMenuData::MediaTypeNone
) {
1634 if (render_frame_host
) {
1635 render_frame_host
->Send(new PrintMsg_PrintNodeUnderContextMenu(
1636 render_frame_host
->GetRoutingID()));
1641 printing::StartPrint(
1642 source_web_contents_
,
1643 GetPrefs(browser_context_
)->GetBoolean(prefs::kPrintPreviewDisabled
),
1644 !params_
.selection_text
.empty());
1645 #endif // ENABLE_PRINTING
1649 case IDC_VIEW_SOURCE
:
1650 embedder_web_contents_
->ViewSource();
1653 case IDC_CONTENT_CONTEXT_INSPECTELEMENT
:
1654 Inspect(params_
.x
, params_
.y
);
1657 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE
: {
1658 const Extension
* platform_app
= GetExtension();
1659 DCHECK(platform_app
);
1660 DCHECK(platform_app
->is_platform_app());
1662 extensions::devtools_util::InspectBackgroundPage(platform_app
,
1667 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO
: {
1668 NavigationController
* controller
=
1669 &embedder_web_contents_
->GetController();
1670 // Important to use GetVisibleEntry to match what's showing in the
1671 // omnibox. This may return null.
1672 NavigationEntry
* nav_entry
= controller
->GetVisibleEntry();
1676 chrome::FindBrowserWithWebContents(embedder_web_contents_
);
1677 chrome::ShowWebsiteSettings(browser
, embedder_web_contents_
,
1678 nav_entry
->GetURL(), nav_entry
->GetSSL());
1682 case IDC_CONTENT_CONTEXT_TRANSLATE
: {
1683 // A translation might have been triggered by the time the menu got
1684 // selected, do nothing in that case.
1685 ChromeTranslateClient
* chrome_translate_client
=
1686 ChromeTranslateClient::FromWebContents(embedder_web_contents_
);
1687 if (!chrome_translate_client
||
1688 chrome_translate_client
->GetLanguageState().IsPageTranslated() ||
1689 chrome_translate_client
->GetLanguageState().translation_pending()) {
1692 std::string original_lang
=
1693 chrome_translate_client
->GetLanguageState().original_language();
1694 std::string target_lang
= g_browser_process
->GetApplicationLocale();
1696 translate::TranslateDownloadManager::GetLanguageCode(target_lang
);
1697 // Since the user decided to translate for that language and site, clears
1698 // any preferences for not translating them.
1699 scoped_ptr
<translate::TranslatePrefs
> prefs(
1700 ChromeTranslateClient::CreateTranslatePrefs(
1701 GetPrefs(browser_context_
)));
1702 prefs
->UnblockLanguage(original_lang
);
1703 prefs
->RemoveSiteFromBlacklist(params_
.page_url
.HostNoBrackets());
1704 translate::TranslateManager
* manager
=
1705 chrome_translate_client
->GetTranslateManager();
1707 manager
->TranslatePage(original_lang
, target_lang
, true);
1711 case IDC_CONTENT_CONTEXT_RELOADFRAME
:
1712 // We always obey the cache here.
1713 // TODO(evanm): Perhaps we could allow shift-clicking the menu item to do
1714 // a cache-ignoring reload of the frame.
1715 source_web_contents_
->ReloadFocusedFrame(false);
1718 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE
:
1719 source_web_contents_
->ViewFrameSource(params_
.frame_url
,
1720 params_
.frame_page_state
);
1723 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO
: {
1724 Browser
* browser
= chrome::FindBrowserWithWebContents(
1725 source_web_contents_
);
1726 chrome::ShowWebsiteSettings(browser
, source_web_contents_
,
1727 params_
.frame_url
, params_
.security_info
);
1731 case IDC_CONTENT_CONTEXT_UNDO
:
1732 source_web_contents_
->Undo();
1735 case IDC_CONTENT_CONTEXT_REDO
:
1736 source_web_contents_
->Redo();
1739 case IDC_CONTENT_CONTEXT_CUT
:
1740 source_web_contents_
->Cut();
1743 case IDC_CONTENT_CONTEXT_COPY
:
1744 source_web_contents_
->Copy();
1747 case IDC_CONTENT_CONTEXT_PASTE
:
1748 source_web_contents_
->Paste();
1751 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE
:
1752 source_web_contents_
->PasteAndMatchStyle();
1755 case IDC_CONTENT_CONTEXT_DELETE
:
1756 source_web_contents_
->Delete();
1759 case IDC_CONTENT_CONTEXT_SELECTALL
:
1760 source_web_contents_
->SelectAll();
1763 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR
:
1764 case IDC_CONTENT_CONTEXT_GOTOURL
: {
1765 WindowOpenDisposition disposition
=
1766 ForceNewTabDispositionFromEventFlags(event_flags
);
1767 OpenURL(selection_navigation_url_
, GURL(), disposition
,
1768 ui::PAGE_TRANSITION_LINK
);
1771 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS
: {
1772 WindowOpenDisposition disposition
=
1773 ForceNewTabDispositionFromEventFlags(event_flags
);
1774 GURL url
= chrome::GetSettingsUrl(chrome::kLanguageOptionsSubPage
);
1775 OpenURL(url
, GURL(), disposition
, ui::PAGE_TRANSITION_LINK
);
1779 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS
: {
1780 content::RecordAction(
1781 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Settings"));
1782 WindowOpenDisposition disposition
=
1783 ForceNewTabDispositionFromEventFlags(event_flags
);
1784 GURL url
= chrome::GetSettingsUrl(chrome::kHandlerSettingsSubPage
);
1785 OpenURL(url
, GURL(), disposition
, ui::PAGE_TRANSITION_LINK
);
1789 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE
: {
1790 // Make sure the model is loaded.
1791 TemplateURLService
* model
=
1792 TemplateURLServiceFactory::GetForProfile(GetProfile());
1797 SearchEngineTabHelper
* search_engine_tab_helper
=
1798 SearchEngineTabHelper::FromWebContents(source_web_contents_
);
1799 if (search_engine_tab_helper
&&
1800 search_engine_tab_helper
->delegate()) {
1801 base::string16
keyword(TemplateURL::GenerateKeyword(
1803 GetProfile()->GetPrefs()->GetString(prefs::kAcceptLanguages
)));
1804 TemplateURLData data
;
1805 data
.SetShortName(keyword
);
1806 data
.SetKeyword(keyword
);
1807 data
.SetURL(params_
.keyword_url
.spec());
1809 TemplateURL::GenerateFaviconURL(params_
.page_url
.GetOrigin());
1810 // Takes ownership of the TemplateURL.
1811 search_engine_tab_helper
->delegate()->ConfirmAddSearchProvider(
1812 new TemplateURL(data
), GetProfile());
1817 case IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD
:
1818 ChromePasswordManagerClient::FromWebContents(source_web_contents_
)->
1819 ForceSavePassword();
1828 ProtocolHandlerRegistry::ProtocolHandlerList
1829 RenderViewContextMenu::GetHandlersForLinkUrl() {
1830 ProtocolHandlerRegistry::ProtocolHandlerList handlers
=
1831 protocol_handler_registry_
->GetHandlersFor(params_
.link_url
.scheme());
1832 std::sort(handlers
.begin(), handlers
.end());
1836 void RenderViewContextMenu::NotifyMenuShown() {
1837 content::NotificationService::current()->Notify(
1838 chrome::NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN
,
1839 content::Source
<RenderViewContextMenu
>(this),
1840 content::NotificationService::NoDetails());
1843 void RenderViewContextMenu::NotifyURLOpened(
1845 content::WebContents
* new_contents
) {
1846 RetargetingDetails details
;
1847 details
.source_web_contents
= source_web_contents_
;
1848 // Don't use GetRenderFrameHost() as it may be NULL. crbug.com/399789
1849 details
.source_render_frame_id
= render_frame_id_
;
1850 details
.target_url
= url
;
1851 details
.target_web_contents
= new_contents
;
1852 details
.not_yet_in_tabstrip
= false;
1854 content::NotificationService::current()->Notify(
1855 chrome::NOTIFICATION_RETARGETING
,
1856 content::Source
<Profile
>(GetProfile()),
1857 content::Details
<RetargetingDetails
>(&details
));
1860 bool RenderViewContextMenu::IsDevCommandEnabled(int id
) const {
1861 if (id
== IDC_CONTENT_CONTEXT_INSPECTELEMENT
||
1862 id
== IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE
) {
1863 if (!GetPrefs(browser_context_
)
1864 ->GetBoolean(prefs::kWebKitJavascriptEnabled
))
1867 // Don't enable the web inspector if the developer tools are disabled via
1868 // the preference dev-tools-disabled.
1869 if (GetPrefs(browser_context_
)->GetBoolean(prefs::kDevToolsDisabled
))
1876 base::string16
RenderViewContextMenu::PrintableSelectionText() {
1877 return gfx::TruncateString(params_
.selection_text
,
1878 kMaxSelectionTextLength
,
1882 void RenderViewContextMenu::EscapeAmpersands(base::string16
* text
) {
1883 base::ReplaceChars(*text
, base::ASCIIToUTF16("&"), base::ASCIIToUTF16("&&"),
1887 // Controller functions --------------------------------------------------------
1889 void RenderViewContextMenu::CopyImageAt(int x
, int y
) {
1890 source_web_contents_
->GetRenderViewHost()->CopyImageAt(x
, y
);
1893 void RenderViewContextMenu::LoadOriginalImage() {
1894 RenderFrameHost
* render_frame_host
= GetRenderFrameHost();
1895 if (!render_frame_host
)
1897 render_frame_host
->Send(new ChromeViewMsg_RequestReloadImageForContextNode(
1898 render_frame_host
->GetRoutingID()));
1901 void RenderViewContextMenu::GetImageThumbnailForSearch() {
1902 RenderFrameHost
* render_frame_host
= GetRenderFrameHost();
1903 if (!render_frame_host
)
1905 render_frame_host
->Send(new ChromeViewMsg_RequestThumbnailForContextNode(
1906 render_frame_host
->GetRoutingID(),
1907 kImageSearchThumbnailMinSize
,
1908 gfx::Size(kImageSearchThumbnailMaxWidth
,
1909 kImageSearchThumbnailMaxHeight
)));
1912 void RenderViewContextMenu::Inspect(int x
, int y
) {
1913 content::RecordAction(UserMetricsAction("DevTools_InspectElement"));
1914 RenderFrameHost
* render_frame_host
= GetRenderFrameHost();
1915 if (!render_frame_host
)
1917 DevToolsWindow::InspectElement(
1918 WebContents::FromRenderFrameHost(render_frame_host
), x
, y
);
1921 void RenderViewContextMenu::WriteURLToClipboard(const GURL
& url
) {
1922 chrome_common_net::WriteURLToClipboard(
1923 url
, GetPrefs(browser_context_
)->GetString(prefs::kAcceptLanguages
));
1926 void RenderViewContextMenu::MediaPlayerActionAt(
1927 const gfx::Point
& location
,
1928 const WebMediaPlayerAction
& action
) {
1929 source_web_contents_
->GetRenderViewHost()->
1930 ExecuteMediaPlayerActionAtLocation(location
, action
);
1933 void RenderViewContextMenu::PluginActionAt(
1934 const gfx::Point
& location
,
1935 const WebPluginAction
& action
) {
1936 source_web_contents_
->GetRenderViewHost()->
1937 ExecutePluginActionAtLocation(location
, action
);