Elim cr-checkbox
[chromium-blink-merge.git] / chrome / browser / renderer_context_menu / render_view_context_menu.cc
blob5a4ab40131b9e7646e31a3ba46e0a045871eb86b
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"
7 #include <algorithm>
8 #include <set>
9 #include <utility>
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/ssl/security_state_model.h"
48 #include "chrome/browser/tab_contents/retargeting_details.h"
49 #include "chrome/browser/translate/chrome_translate_client.h"
50 #include "chrome/browser/translate/translate_service.h"
51 #include "chrome/browser/ui/browser.h"
52 #include "chrome/browser/ui/browser_commands.h"
53 #include "chrome/browser/ui/browser_finder.h"
54 #include "chrome/browser/ui/chrome_pages.h"
55 #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"
56 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
57 #include "chrome/common/chrome_constants.h"
58 #include "chrome/common/chrome_switches.h"
59 #include "chrome/common/content_restriction.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/url_formatter/url_formatter.h"
77 #include "components/user_prefs/user_prefs.h"
78 #include "content/public/browser/child_process_security_policy.h"
79 #include "content/public/browser/download_manager.h"
80 #include "content/public/browser/download_save_info.h"
81 #include "content/public/browser/download_url_parameters.h"
82 #include "content/public/browser/navigation_details.h"
83 #include "content/public/browser/navigation_entry.h"
84 #include "content/public/browser/notification_service.h"
85 #include "content/public/browser/render_frame_host.h"
86 #include "content/public/browser/render_process_host.h"
87 #include "content/public/browser/render_view_host.h"
88 #include "content/public/browser/render_widget_host_view.h"
89 #include "content/public/browser/user_metrics.h"
90 #include "content/public/browser/web_contents.h"
91 #include "content/public/common/menu_item.h"
92 #include "content/public/common/ssl_status.h"
93 #include "content/public/common/url_utils.h"
94 #include "extensions/browser/extension_host.h"
95 #include "extensions/browser/extension_system.h"
96 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
97 #include "extensions/browser/view_type_utils.h"
98 #include "extensions/common/extension.h"
99 #include "net/base/escape.h"
100 #include "third_party/WebKit/public/web/WebContextMenuData.h"
101 #include "third_party/WebKit/public/web/WebMediaPlayerAction.h"
102 #include "third_party/WebKit/public/web/WebPluginAction.h"
103 #include "ui/base/clipboard/clipboard.h"
104 #include "ui/base/clipboard/scoped_clipboard_writer.h"
105 #include "ui/base/l10n/l10n_util.h"
106 #include "ui/gfx/favicon_size.h"
107 #include "ui/gfx/geometry/point.h"
108 #include "ui/gfx/geometry/size.h"
109 #include "ui/gfx/text_elider.h"
111 #if defined(ENABLE_EXTENSIONS)
112 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
113 #endif
115 #if defined(ENABLE_PRINTING)
116 #include "chrome/browser/printing/print_view_manager_common.h"
117 #include "components/printing/common/print_messages.h"
119 #if defined(ENABLE_PRINT_PREVIEW)
120 #include "chrome/browser/printing/print_preview_context_menu_observer.h"
121 #include "chrome/browser/printing/print_preview_dialog_controller.h"
122 #endif // defined(ENABLE_PRINT_PREVIEW)
123 #endif // defined(ENABLE_PRINTING)
125 using base::UserMetricsAction;
126 using blink::WebContextMenuData;
127 using blink::WebMediaPlayerAction;
128 using blink::WebPluginAction;
129 using blink::WebString;
130 using blink::WebURL;
131 using content::BrowserContext;
132 using content::ChildProcessSecurityPolicy;
133 using content::DownloadManager;
134 using content::DownloadUrlParameters;
135 using content::NavigationController;
136 using content::NavigationEntry;
137 using content::OpenURLParams;
138 using content::RenderFrameHost;
139 using content::RenderViewHost;
140 using content::SSLStatus;
141 using content::WebContents;
142 using extensions::ContextMenuMatcher;
143 using extensions::Extension;
144 using extensions::MenuItem;
145 using extensions::MenuManager;
147 namespace {
149 const int kImageSearchThumbnailMinSize = 300 * 300;
150 const int kImageSearchThumbnailMaxWidth = 600;
151 const int kImageSearchThumbnailMaxHeight = 600;
153 // Maps UMA enumeration to IDC. IDC could be changed so we can't use
154 // just them and |UMA_HISTOGRAM_CUSTOM_ENUMERATION|.
155 // Never change mapping or reuse |enum_id|. Always push back new items.
156 // Items that is not used any more by |RenderViewContextMenu.ExecuteCommand|
157 // could be deleted, but don't change the rest of |kUmaEnumToControlId|.
158 const struct UmaEnumCommandIdPair {
159 int enum_id;
160 int control_id;
161 } kUmaEnumToControlId[] = {
163 enum id for 0, 1 are detected using
164 RenderViewContextMenu::IsContentCustomCommandId and
165 ContextMenuMatcher::IsExtensionsCustomCommandId
167 {2, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST},
168 {3, IDC_CONTENT_CONTEXT_OPENLINKNEWTAB},
169 {4, IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW},
170 {5, IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD},
171 {6, IDC_CONTENT_CONTEXT_SAVELINKAS},
172 {7, IDC_CONTENT_CONTEXT_SAVEAVAS},
173 {8, IDC_CONTENT_CONTEXT_SAVEIMAGEAS},
174 {9, IDC_CONTENT_CONTEXT_COPYLINKLOCATION},
175 {10, IDC_CONTENT_CONTEXT_COPYIMAGELOCATION},
176 {11, IDC_CONTENT_CONTEXT_COPYAVLOCATION},
177 {12, IDC_CONTENT_CONTEXT_COPYIMAGE},
178 {13, IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB},
179 {14, IDC_CONTENT_CONTEXT_OPENAVNEWTAB},
180 {15, IDC_CONTENT_CONTEXT_PLAYPAUSE},
181 {16, IDC_CONTENT_CONTEXT_MUTE},
182 {17, IDC_CONTENT_CONTEXT_LOOP},
183 {18, IDC_CONTENT_CONTEXT_CONTROLS},
184 {19, IDC_CONTENT_CONTEXT_ROTATECW},
185 {20, IDC_CONTENT_CONTEXT_ROTATECCW},
186 {21, IDC_BACK},
187 {22, IDC_FORWARD},
188 {23, IDC_SAVE_PAGE},
189 {24, IDC_RELOAD},
190 {25, IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP},
191 {26, IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP},
192 {27, IDC_PRINT},
193 {28, IDC_VIEW_SOURCE},
194 {29, IDC_CONTENT_CONTEXT_INSPECTELEMENT},
195 {30, IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE},
196 {31, IDC_CONTENT_CONTEXT_VIEWPAGEINFO},
197 {32, IDC_CONTENT_CONTEXT_TRANSLATE},
198 {33, IDC_CONTENT_CONTEXT_RELOADFRAME},
199 {34, IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE},
200 {35, IDC_CONTENT_CONTEXT_VIEWFRAMEINFO},
201 {36, IDC_CONTENT_CONTEXT_UNDO},
202 {37, IDC_CONTENT_CONTEXT_REDO},
203 {38, IDC_CONTENT_CONTEXT_CUT},
204 {39, IDC_CONTENT_CONTEXT_COPY},
205 {40, IDC_CONTENT_CONTEXT_PASTE},
206 {41, IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE},
207 {42, IDC_CONTENT_CONTEXT_DELETE},
208 {43, IDC_CONTENT_CONTEXT_SELECTALL},
209 {44, IDC_CONTENT_CONTEXT_SEARCHWEBFOR},
210 {45, IDC_CONTENT_CONTEXT_GOTOURL},
211 {46, IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS},
212 {47, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS},
213 {48, IDC_CONTENT_CONTEXT_ADDSEARCHENGINE},
214 {52, IDC_CONTENT_CONTEXT_OPENLINKWITH},
215 {53, IDC_CHECK_SPELLING_WHILE_TYPING},
216 {54, IDC_SPELLCHECK_MENU},
217 {55, IDC_CONTENT_CONTEXT_SPELLING_TOGGLE},
218 {56, IDC_SPELLCHECK_LANGUAGES_FIRST},
219 {57, IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE},
220 {58, IDC_SPELLCHECK_SUGGESTION_0},
221 {59, IDC_SPELLCHECK_ADD_TO_DICTIONARY},
222 {60, IDC_SPELLPANEL_TOGGLE},
223 {61, IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB},
224 {62, IDC_WRITING_DIRECTION_MENU},
225 {63, IDC_WRITING_DIRECTION_DEFAULT},
226 {64, IDC_WRITING_DIRECTION_LTR},
227 {65, IDC_WRITING_DIRECTION_RTL},
228 {66, IDC_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE},
229 {67, IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD},
230 // Add new items here and use |enum_id| from the next line.
231 // Also, add new items to RenderViewContextMenuItem enum in histograms.xml.
232 {68, 0}, // Must be the last. Increment |enum_id| when new IDC was added.
235 // Collapses large ranges of ids before looking for UMA enum.
236 int CollapseCommandsForUMA(int id) {
237 DCHECK(!RenderViewContextMenu::IsContentCustomCommandId(id));
238 DCHECK(!ContextMenuMatcher::IsExtensionsCustomCommandId(id));
240 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
241 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
242 return IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
245 if (id >= IDC_SPELLCHECK_LANGUAGES_FIRST &&
246 id <= IDC_SPELLCHECK_LANGUAGES_LAST) {
247 return IDC_SPELLCHECK_LANGUAGES_FIRST;
250 if (id >= IDC_SPELLCHECK_SUGGESTION_0 &&
251 id <= IDC_SPELLCHECK_SUGGESTION_LAST) {
252 return IDC_SPELLCHECK_SUGGESTION_0;
255 return id;
258 // Returns UMA enum value for command specified by |id| or -1 if not found.
259 int FindUMAEnumValueForCommand(int id) {
260 if (RenderViewContextMenu::IsContentCustomCommandId(id))
261 return 0;
263 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
264 return 1;
266 id = CollapseCommandsForUMA(id);
267 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
268 for (size_t i = 0; i < kMappingSize; ++i) {
269 if (kUmaEnumToControlId[i].control_id == id) {
270 return kUmaEnumToControlId[i].enum_id;
273 return -1;
276 // Usually a new tab is expected where this function is used,
277 // however users should be able to open a tab in background
278 // or in a new window.
279 WindowOpenDisposition ForceNewTabDispositionFromEventFlags(
280 int event_flags) {
281 WindowOpenDisposition disposition =
282 ui::DispositionFromEventFlags(event_flags);
283 return disposition == CURRENT_TAB ? NEW_FOREGROUND_TAB : disposition;
286 // Returns the preference of the profile represented by the |context|.
287 PrefService* GetPrefs(content::BrowserContext* context) {
288 return user_prefs::UserPrefs::Get(context);
291 bool ExtensionPatternMatch(const extensions::URLPatternSet& patterns,
292 const GURL& url) {
293 // No patterns means no restriction, so that implicitly matches.
294 if (patterns.is_empty())
295 return true;
296 return patterns.MatchesURL(url);
299 const GURL& GetDocumentURL(const content::ContextMenuParams& params) {
300 return params.frame_url.is_empty() ? params.page_url : params.frame_url;
303 content::Referrer CreateSaveAsReferrer(
304 const GURL& url,
305 const content::ContextMenuParams& params) {
306 const GURL& referring_url = GetDocumentURL(params);
307 return content::Referrer::SanitizeForRequest(
308 url,
309 content::Referrer(referring_url.GetAsReferrer(), params.referrer_policy));
312 content::WebContents* GetWebContentsToUse(content::WebContents* web_contents) {
313 #if defined(ENABLE_EXTENSIONS)
314 // If we're viewing in a MimeHandlerViewGuest, use its embedder WebContents.
315 if (extensions::MimeHandlerViewGuest::FromWebContents(web_contents)) {
316 WebContents* top_level_web_contents =
317 guest_view::GuestViewBase::GetTopLevelWebContents(web_contents);
318 if (top_level_web_contents)
319 return top_level_web_contents;
321 #endif
322 return web_contents;
325 void WriteURLToClipboard(const GURL& url, const std::string& languages) {
326 if (url.is_empty() || !url.is_valid())
327 return;
329 // Unescaping path and query is not a good idea because other applications
330 // may not encode non-ASCII characters in UTF-8. See crbug.com/2820.
331 base::string16 text =
332 url.SchemeIs(url::kMailToScheme)
333 ? base::ASCIIToUTF16(url.path())
334 : url_formatter::FormatUrl(
335 url, languages, url_formatter::kFormatUrlOmitNothing,
336 net::UnescapeRule::NONE, nullptr, nullptr, nullptr);
338 ui::ScopedClipboardWriter scw(ui::CLIPBOARD_TYPE_COPY_PASTE);
339 scw.WriteURL(text);
342 bool g_custom_id_ranges_initialized = false;
344 const int kSpellcheckRadioGroup = 1;
346 } // namespace
348 // static
349 gfx::Vector2d RenderViewContextMenu::GetOffset(
350 RenderFrameHost* render_frame_host) {
351 gfx::Vector2d offset;
352 #if defined(ENABLE_EXTENSIONS)
353 WebContents* web_contents =
354 WebContents::FromRenderFrameHost(render_frame_host);
355 WebContents* top_level_web_contents =
356 guest_view::GuestViewBase::GetTopLevelWebContents(web_contents);
357 if (web_contents && top_level_web_contents &&
358 web_contents != top_level_web_contents) {
359 gfx::Rect bounds = web_contents->GetContainerBounds();
360 gfx::Rect top_level_bounds = top_level_web_contents->GetContainerBounds();
361 offset = bounds.origin() - top_level_bounds.origin();
363 #endif // defined(ENABLE_EXTENSIONS)
364 return offset;
367 // static
368 bool RenderViewContextMenu::IsDevToolsURL(const GURL& url) {
369 return url.SchemeIs(content::kChromeDevToolsScheme);
372 // static
373 bool RenderViewContextMenu::IsInternalResourcesURL(const GURL& url) {
374 if (!url.SchemeIs(content::kChromeUIScheme))
375 return false;
376 return url.host() == chrome::kChromeUISyncResourcesHost;
379 RenderViewContextMenu::RenderViewContextMenu(
380 content::RenderFrameHost* render_frame_host,
381 const content::ContextMenuParams& params)
382 : RenderViewContextMenuBase(render_frame_host, params),
383 extension_items_(browser_context_,
384 this,
385 &menu_model_,
386 base::Bind(MenuItemMatchesParams, params_)),
387 protocol_handler_submenu_model_(this),
388 protocol_handler_registry_(
389 ProtocolHandlerRegistryFactory::GetForBrowserContext(GetProfile())),
390 embedder_web_contents_(GetWebContentsToUse(source_web_contents_)) {
391 if (!g_custom_id_ranges_initialized) {
392 g_custom_id_ranges_initialized = true;
393 SetContentCustomCommandIdRange(IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
394 IDC_CONTENT_CONTEXT_CUSTOM_LAST);
396 set_content_type(ContextMenuContentTypeFactory::Create(
397 source_web_contents_, params));
400 RenderViewContextMenu::~RenderViewContextMenu() {
403 // Menu construction functions -------------------------------------------------
405 #if defined(ENABLE_EXTENSIONS)
406 // static
407 bool RenderViewContextMenu::ExtensionContextAndPatternMatch(
408 const content::ContextMenuParams& params,
409 const MenuItem::ContextList& contexts,
410 const extensions::URLPatternSet& target_url_patterns) {
411 const bool has_link = !params.link_url.is_empty();
412 const bool has_selection = !params.selection_text.empty();
413 const bool in_frame = !params.frame_url.is_empty();
415 if (contexts.Contains(MenuItem::ALL) ||
416 (has_selection && contexts.Contains(MenuItem::SELECTION)) ||
417 (params.is_editable && contexts.Contains(MenuItem::EDITABLE)) ||
418 (in_frame && contexts.Contains(MenuItem::FRAME)))
419 return true;
421 if (has_link && contexts.Contains(MenuItem::LINK) &&
422 ExtensionPatternMatch(target_url_patterns, params.link_url))
423 return true;
425 switch (params.media_type) {
426 case WebContextMenuData::MediaTypeImage:
427 if (contexts.Contains(MenuItem::IMAGE) &&
428 ExtensionPatternMatch(target_url_patterns, params.src_url))
429 return true;
430 break;
432 case WebContextMenuData::MediaTypeVideo:
433 if (contexts.Contains(MenuItem::VIDEO) &&
434 ExtensionPatternMatch(target_url_patterns, params.src_url))
435 return true;
436 break;
438 case WebContextMenuData::MediaTypeAudio:
439 if (contexts.Contains(MenuItem::AUDIO) &&
440 ExtensionPatternMatch(target_url_patterns, params.src_url))
441 return true;
442 break;
444 default:
445 break;
448 // PAGE is the least specific context, so we only examine that if none of the
449 // other contexts apply (except for FRAME, which is included in PAGE for
450 // backwards compatibility).
451 if (!has_link && !has_selection && !params.is_editable &&
452 params.media_type == WebContextMenuData::MediaTypeNone &&
453 contexts.Contains(MenuItem::PAGE))
454 return true;
456 return false;
459 // static
460 bool RenderViewContextMenu::MenuItemMatchesParams(
461 const content::ContextMenuParams& params,
462 const extensions::MenuItem* item) {
463 bool match = ExtensionContextAndPatternMatch(params, item->contexts(),
464 item->target_url_patterns());
465 if (!match)
466 return false;
468 const GURL& document_url = GetDocumentURL(params);
469 return ExtensionPatternMatch(item->document_url_patterns(), document_url);
472 void RenderViewContextMenu::AppendAllExtensionItems() {
473 extension_items_.Clear();
474 ExtensionService* service =
475 extensions::ExtensionSystem::Get(browser_context_)->extension_service();
476 if (!service)
477 return; // In unit-tests, we may not have an ExtensionService.
479 MenuManager* menu_manager = MenuManager::Get(browser_context_);
480 if (!menu_manager)
481 return;
483 base::string16 printable_selection_text = PrintableSelectionText();
484 EscapeAmpersands(&printable_selection_text);
486 // Get a list of extension id's that have context menu items, and sort by the
487 // top level context menu title of the extension.
488 std::set<MenuItem::ExtensionKey> ids = menu_manager->ExtensionIds();
489 std::vector<base::string16> sorted_menu_titles;
490 std::map<base::string16, std::vector<const Extension*>>
491 title_to_extensions_map;
492 for (std::set<MenuItem::ExtensionKey>::iterator iter = ids.begin();
493 iter != ids.end();
494 ++iter) {
495 const Extension* extension =
496 service->GetExtensionById(iter->extension_id, false);
497 // Platform apps have their context menus created directly in
498 // AppendPlatformAppItems.
499 if (extension && !extension->is_platform_app()) {
500 base::string16 menu_title = extension_items_.GetTopLevelContextMenuTitle(
501 *iter, printable_selection_text);
502 title_to_extensions_map[menu_title].push_back(extension);
503 sorted_menu_titles.push_back(menu_title);
506 if (sorted_menu_titles.empty())
507 return;
509 const std::string app_locale = g_browser_process->GetApplicationLocale();
510 l10n_util::SortStrings16(app_locale, &sorted_menu_titles);
511 sorted_menu_titles.erase(
512 std::unique(sorted_menu_titles.begin(), sorted_menu_titles.end()),
513 sorted_menu_titles.end());
515 int index = 0;
516 for (size_t i = 0; i < sorted_menu_titles.size(); ++i) {
517 std::vector<const Extension*>& extensions =
518 title_to_extensions_map[sorted_menu_titles[i]];
519 for (const auto& extension : extensions) {
520 MenuItem::ExtensionKey extension_key(extension->id());
521 extension_items_.AppendExtensionItems(extension_key,
522 printable_selection_text, &index,
523 false); // is_action_menu
528 void RenderViewContextMenu::AppendCurrentExtensionItems() {
529 // Avoid appending extension related items when |extension| is null.
530 // For Panel, this happens when the panel is navigated to a url outside of the
531 // extension's package.
532 const Extension* extension = GetExtension();
533 if (!extension)
534 return;
536 extensions::WebViewGuest* web_view_guest =
537 extensions::WebViewGuest::FromWebContents(source_web_contents_);
538 MenuItem::ExtensionKey key;
539 if (web_view_guest) {
540 key = MenuItem::ExtensionKey(
541 extension->id(),
542 web_view_guest->owner_web_contents()->GetRenderProcessHost()->GetID(),
543 web_view_guest->view_instance_id());
544 } else {
545 key = MenuItem::ExtensionKey(extension->id());
548 // Only add extension items from this extension.
549 int index = 0;
550 extension_items_.AppendExtensionItems(key, PrintableSelectionText(), &index,
551 false /* is_action_menu */);
553 #endif // defined(ENABLE_EXTENSIONS)
555 void RenderViewContextMenu::InitMenu() {
556 RenderViewContextMenuBase::InitMenu();
558 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PAGE))
559 AppendPageItems();
561 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_FRAME)) {
562 // Merge in frame items with page items if we clicked within a frame that
563 // needs them.
564 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
565 AppendFrameItems();
568 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_LINK)) {
569 AppendLinkItems();
570 if (params_.media_type != WebContextMenuData::MediaTypeNone)
571 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
574 if (content_type_->SupportsGroup(
575 ContextMenuContentType::ITEM_GROUP_MEDIA_IMAGE)) {
576 AppendImageItems();
579 if (content_type_->SupportsGroup(
580 ContextMenuContentType::ITEM_GROUP_SEARCHWEBFORIMAGE)) {
581 AppendSearchWebForImageItems();
584 if (content_type_->SupportsGroup(
585 ContextMenuContentType::ITEM_GROUP_MEDIA_VIDEO)) {
586 AppendVideoItems();
589 if (content_type_->SupportsGroup(
590 ContextMenuContentType::ITEM_GROUP_MEDIA_AUDIO)) {
591 AppendAudioItems();
594 if (content_type_->SupportsGroup(
595 ContextMenuContentType::ITEM_GROUP_MEDIA_CANVAS)) {
596 AppendCanvasItems();
599 if (content_type_->SupportsGroup(
600 ContextMenuContentType::ITEM_GROUP_MEDIA_PLUGIN)) {
601 AppendPluginItems();
604 // ITEM_GROUP_MEDIA_FILE has no specific items.
606 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_EDITABLE))
607 AppendEditableItems();
609 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_COPY)) {
610 DCHECK(!content_type_->SupportsGroup(
611 ContextMenuContentType::ITEM_GROUP_EDITABLE));
612 AppendCopyItem();
615 if (content_type_->SupportsGroup(
616 ContextMenuContentType::ITEM_GROUP_SEARCH_PROVIDER)) {
617 AppendSearchProvider();
620 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT))
621 AppendPrintItem();
623 if (content_type_->SupportsGroup(
624 ContextMenuContentType::ITEM_GROUP_MEDIA_PLUGIN)) {
625 AppendRotationItems();
628 if (content_type_->SupportsGroup(
629 ContextMenuContentType::ITEM_GROUP_ALL_EXTENSION)) {
630 DCHECK(!content_type_->SupportsGroup(
631 ContextMenuContentType::ITEM_GROUP_CURRENT_EXTENSION));
632 AppendAllExtensionItems();
635 if (content_type_->SupportsGroup(
636 ContextMenuContentType::ITEM_GROUP_CURRENT_EXTENSION)) {
637 DCHECK(!content_type_->SupportsGroup(
638 ContextMenuContentType::ITEM_GROUP_ALL_EXTENSION));
639 AppendCurrentExtensionItems();
642 if (content_type_->SupportsGroup(
643 ContextMenuContentType::ITEM_GROUP_DEVELOPER)) {
644 AppendDeveloperItems();
647 if (content_type_->SupportsGroup(
648 ContextMenuContentType::ITEM_GROUP_DEVTOOLS_UNPACKED_EXT)) {
649 AppendDevtoolsForUnpackedExtensions();
652 if (content_type_->SupportsGroup(
653 ContextMenuContentType::ITEM_GROUP_PRINT_PREVIEW)) {
654 AppendPrintPreviewItems();
657 if (content_type_->SupportsGroup(
658 ContextMenuContentType::ITEM_GROUP_PASSWORD)) {
659 AppendPasswordItems();
663 Profile* RenderViewContextMenu::GetProfile() {
664 return Profile::FromBrowserContext(browser_context_);
667 void RenderViewContextMenu::RecordUsedItem(int id) {
668 int enum_id = FindUMAEnumValueForCommand(id);
669 if (enum_id != -1) {
670 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
671 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Used", enum_id,
672 kUmaEnumToControlId[kMappingSize - 1].enum_id);
673 } else {
674 NOTREACHED() << "Update kUmaEnumToControlId. Unhanded IDC: " << id;
678 void RenderViewContextMenu::RecordShownItem(int id) {
679 int enum_id = FindUMAEnumValueForCommand(id);
680 if (enum_id != -1) {
681 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
682 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Shown", enum_id,
683 kUmaEnumToControlId[kMappingSize - 1].enum_id);
684 } else {
685 // Just warning here. It's harder to maintain list of all possibly
686 // visible items than executable items.
687 DLOG(ERROR) << "Update kUmaEnumToControlId. Unhanded IDC: " << id;
691 #if defined(ENABLE_PLUGINS)
692 void RenderViewContextMenu::HandleAuthorizeAllPlugins() {
693 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins(
694 source_web_contents_, false, std::string());
696 #endif
698 void RenderViewContextMenu::AppendPrintPreviewItems() {
699 #if defined(ENABLE_PRINT_PREVIEW)
700 if (!print_preview_menu_observer_.get()) {
701 print_preview_menu_observer_.reset(
702 new PrintPreviewContextMenuObserver(source_web_contents_));
705 observers_.AddObserver(print_preview_menu_observer_.get());
706 #endif
709 const Extension* RenderViewContextMenu::GetExtension() const {
710 return extensions::ProcessManager::Get(browser_context_)
711 ->GetExtensionForWebContents(source_web_contents_);
714 void RenderViewContextMenu::AppendDeveloperItems() {
715 // Show Inspect Element in DevTools itself only in case of the debug
716 // devtools build.
717 bool show_developer_items = !IsDevToolsURL(params_.page_url);
719 #if defined(DEBUG_DEVTOOLS)
720 show_developer_items = true;
721 #endif
723 if (!show_developer_items)
724 return;
726 // In the DevTools popup menu, "developer items" is normally the only
727 // section, so omit the separator there.
728 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
729 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTELEMENT,
730 IDS_CONTENT_CONTEXT_INSPECTELEMENT);
733 void RenderViewContextMenu::AppendDevtoolsForUnpackedExtensions() {
734 // Add a separator if there are any items already in the menu.
735 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
737 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP,
738 IDS_CONTENT_CONTEXT_RELOAD_PACKAGED_APP);
739 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP,
740 IDS_CONTENT_CONTEXT_RESTART_APP);
741 AppendDeveloperItems();
742 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE,
743 IDS_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE);
746 void RenderViewContextMenu::AppendLinkItems() {
747 if (!params_.link_url.is_empty()) {
748 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB,
749 IDS_CONTENT_CONTEXT_OPENLINKNEWTAB);
750 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW,
751 IDS_CONTENT_CONTEXT_OPENLINKNEWWINDOW);
752 if (params_.link_url.is_valid()) {
753 AppendProtocolHandlerSubMenu();
756 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD,
757 IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD);
758 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVELINKAS,
759 IDS_CONTENT_CONTEXT_SAVELINKAS);
762 menu_model_.AddItemWithStringId(
763 IDC_CONTENT_CONTEXT_COPYLINKLOCATION,
764 params_.link_url.SchemeIs(url::kMailToScheme) ?
765 IDS_CONTENT_CONTEXT_COPYEMAILADDRESS :
766 IDS_CONTENT_CONTEXT_COPYLINKLOCATION);
769 void RenderViewContextMenu::AppendImageItems() {
770 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS,
771 IDS_CONTENT_CONTEXT_SAVEIMAGEAS);
772 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGELOCATION,
773 IDS_CONTENT_CONTEXT_COPYIMAGELOCATION);
774 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
775 IDS_CONTENT_CONTEXT_COPYIMAGE);
776 std::map<std::string, std::string>::const_iterator it =
777 params_.properties.find(data_reduction_proxy::chrome_proxy_header());
778 if (it != params_.properties.end() && it->second ==
779 data_reduction_proxy::chrome_proxy_lo_fi_directive()) {
780 menu_model_.AddItemWithStringId(
781 IDC_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE,
782 IDS_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE);
784 DataReductionProxyChromeSettings* settings =
785 DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
786 browser_context_);
787 if (settings && settings->CanUseDataReductionProxy(params_.src_url)) {
788 menu_model_.AddItemWithStringId(
789 IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB,
790 IDS_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB);
791 } else {
792 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB,
793 IDS_CONTENT_CONTEXT_OPENIMAGENEWTAB);
797 void RenderViewContextMenu::AppendSearchWebForImageItems() {
798 TemplateURLService* service =
799 TemplateURLServiceFactory::GetForProfile(GetProfile());
800 const TemplateURL* const default_provider =
801 service->GetDefaultSearchProvider();
802 if (params_.has_image_contents && default_provider &&
803 !default_provider->image_url().empty() &&
804 default_provider->image_url_ref().IsValid(service->search_terms_data())) {
805 menu_model_.AddItem(
806 IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE,
807 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFORIMAGE,
808 default_provider->short_name()));
812 void RenderViewContextMenu::AppendAudioItems() {
813 AppendMediaItems();
814 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
815 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
816 IDS_CONTENT_CONTEXT_SAVEAUDIOAS);
817 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
818 IDS_CONTENT_CONTEXT_COPYAUDIOLOCATION);
819 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
820 IDS_CONTENT_CONTEXT_OPENAUDIONEWTAB);
823 void RenderViewContextMenu::AppendCanvasItems() {
824 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS,
825 IDS_CONTENT_CONTEXT_SAVEIMAGEAS);
826 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
827 IDS_CONTENT_CONTEXT_COPYIMAGE);
830 void RenderViewContextMenu::AppendVideoItems() {
831 AppendMediaItems();
832 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
833 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
834 IDS_CONTENT_CONTEXT_SAVEVIDEOAS);
835 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
836 IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION);
837 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
838 IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB);
841 void RenderViewContextMenu::AppendMediaItems() {
842 int media_flags = params_.media_flags;
844 menu_model_.AddItemWithStringId(
845 IDC_CONTENT_CONTEXT_PLAYPAUSE,
846 media_flags & WebContextMenuData::MediaPaused ?
847 IDS_CONTENT_CONTEXT_PLAY :
848 IDS_CONTENT_CONTEXT_PAUSE);
850 menu_model_.AddItemWithStringId(
851 IDC_CONTENT_CONTEXT_MUTE,
852 media_flags & WebContextMenuData::MediaMuted ?
853 IDS_CONTENT_CONTEXT_UNMUTE :
854 IDS_CONTENT_CONTEXT_MUTE);
856 menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_LOOP,
857 IDS_CONTENT_CONTEXT_LOOP);
858 menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_CONTROLS,
859 IDS_CONTENT_CONTEXT_CONTROLS);
862 void RenderViewContextMenu::AppendPluginItems() {
863 if (params_.page_url == params_.src_url ||
864 guest_view::GuestViewBase::IsGuest(source_web_contents_)) {
865 // Full page plugin, so show page menu items.
866 if (params_.link_url.is_empty() && params_.selection_text.empty())
867 AppendPageItems();
868 } else {
869 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
870 IDS_CONTENT_CONTEXT_SAVEPAGEAS);
871 // The "Print" menu item should always be included for plugins. If
872 // content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT)
873 // is true the item will be added inside AppendPrintItem(). Otherwise we
874 // add "Print" here.
875 if (!content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT))
876 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
880 void RenderViewContextMenu::AppendPageItems() {
881 menu_model_.AddItemWithStringId(IDC_BACK, IDS_CONTENT_CONTEXT_BACK);
882 menu_model_.AddItemWithStringId(IDC_FORWARD, IDS_CONTENT_CONTEXT_FORWARD);
883 menu_model_.AddItemWithStringId(IDC_RELOAD, IDS_CONTENT_CONTEXT_RELOAD);
884 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
885 menu_model_.AddItemWithStringId(IDC_SAVE_PAGE,
886 IDS_CONTENT_CONTEXT_SAVEPAGEAS);
887 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
889 if (TranslateService::IsTranslatableURL(params_.page_url)) {
890 std::string locale = g_browser_process->GetApplicationLocale();
891 locale = translate::TranslateDownloadManager::GetLanguageCode(locale);
892 base::string16 language =
893 l10n_util::GetDisplayNameForLocale(locale, locale, true);
894 menu_model_.AddItem(
895 IDC_CONTENT_CONTEXT_TRANSLATE,
896 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_TRANSLATE, language));
899 menu_model_.AddItemWithStringId(IDC_VIEW_SOURCE,
900 IDS_CONTENT_CONTEXT_VIEWPAGESOURCE);
901 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWPAGEINFO,
902 IDS_CONTENT_CONTEXT_VIEWPAGEINFO);
905 void RenderViewContextMenu::AppendFrameItems() {
906 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOADFRAME,
907 IDS_CONTENT_CONTEXT_RELOADFRAME);
908 // These two menu items have yet to be implemented.
909 // http://code.google.com/p/chromium/issues/detail?id=11827
910 // IDS_CONTENT_CONTEXT_SAVEFRAMEAS
911 // IDS_CONTENT_CONTEXT_PRINTFRAME
912 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE,
913 IDS_CONTENT_CONTEXT_VIEWFRAMESOURCE);
914 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMEINFO,
915 IDS_CONTENT_CONTEXT_VIEWFRAMEINFO);
918 void RenderViewContextMenu::AppendCopyItem() {
919 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
920 IDS_CONTENT_CONTEXT_COPY);
923 void RenderViewContextMenu::AppendPrintItem() {
924 if (GetPrefs(browser_context_)->GetBoolean(prefs::kPrintingEnabled) &&
925 (params_.media_type == WebContextMenuData::MediaTypeNone ||
926 params_.media_flags & WebContextMenuData::MediaCanPrint)) {
927 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
931 void RenderViewContextMenu::AppendRotationItems() {
932 if (params_.media_flags & WebContextMenuData::MediaCanRotate) {
933 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
934 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECW,
935 IDS_CONTENT_CONTEXT_ROTATECW);
936 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECCW,
937 IDS_CONTENT_CONTEXT_ROTATECCW);
941 void RenderViewContextMenu::AppendSearchProvider() {
942 DCHECK(browser_context_);
944 base::TrimWhitespace(params_.selection_text, base::TRIM_ALL,
945 &params_.selection_text);
946 if (params_.selection_text.empty())
947 return;
949 base::ReplaceChars(params_.selection_text, AutocompleteMatch::kInvalidChars,
950 base::ASCIIToUTF16(" "), &params_.selection_text);
952 AutocompleteMatch match;
953 AutocompleteClassifierFactory::GetForProfile(GetProfile())->Classify(
954 params_.selection_text,
955 false,
956 false,
957 metrics::OmniboxEventProto::INVALID_SPEC,
958 &match,
959 NULL);
960 selection_navigation_url_ = match.destination_url;
961 if (!selection_navigation_url_.is_valid())
962 return;
964 base::string16 printable_selection_text = PrintableSelectionText();
965 EscapeAmpersands(&printable_selection_text);
967 if (AutocompleteMatch::IsSearchType(match.type)) {
968 const TemplateURL* const default_provider =
969 TemplateURLServiceFactory::GetForProfile(GetProfile())
970 ->GetDefaultSearchProvider();
971 if (!default_provider)
972 return;
973 menu_model_.AddItem(
974 IDC_CONTENT_CONTEXT_SEARCHWEBFOR,
975 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFOR,
976 default_provider->short_name(),
977 printable_selection_text));
978 } else {
979 if ((selection_navigation_url_ != params_.link_url) &&
980 ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme(
981 selection_navigation_url_.scheme())) {
982 menu_model_.AddItem(
983 IDC_CONTENT_CONTEXT_GOTOURL,
984 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_GOTOURL,
985 printable_selection_text));
990 void RenderViewContextMenu::AppendEditableItems() {
991 const bool use_spellcheck_and_search = !chrome::IsRunningInForcedAppMode();
993 if (use_spellcheck_and_search)
994 AppendSpellingSuggestionsSubMenu();
996 if (!IsDevToolsURL(params_.page_url)) {
997 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_UNDO,
998 IDS_CONTENT_CONTEXT_UNDO);
999 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_REDO,
1000 IDS_CONTENT_CONTEXT_REDO);
1001 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1004 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_CUT,
1005 IDS_CONTENT_CONTEXT_CUT);
1006 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
1007 IDS_CONTENT_CONTEXT_COPY);
1008 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE,
1009 IDS_CONTENT_CONTEXT_PASTE);
1010 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE,
1011 IDS_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE);
1012 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_DELETE,
1013 IDS_CONTENT_CONTEXT_DELETE);
1014 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1016 if (use_spellcheck_and_search && !params_.keyword_url.is_empty()) {
1017 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ADDSEARCHENGINE,
1018 IDS_CONTENT_CONTEXT_ADDSEARCHENGINE);
1019 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1022 #if defined(OS_MACOSX)
1023 if (use_spellcheck_and_search)
1024 AppendSpellcheckOptionsSubMenu();
1025 #else
1026 if (chrome::spellcheck_common::IsMultilingualSpellcheckEnabled()) {
1027 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS,
1028 IDS_CONTENT_CONTEXT_LANGUAGE_SETTINGS);
1029 } else if (use_spellcheck_and_search) {
1030 AppendSpellcheckOptionsSubMenu();
1032 #endif // defined(OS_MACOSX)
1034 AppendPlatformEditableItems();
1036 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1037 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SELECTALL,
1038 IDS_CONTENT_CONTEXT_SELECTALL);
1041 void RenderViewContextMenu::AppendSpellingSuggestionsSubMenu() {
1042 if (!spelling_menu_observer_.get())
1043 spelling_menu_observer_.reset(new SpellingMenuObserver(this));
1044 observers_.AddObserver(spelling_menu_observer_.get());
1045 spelling_menu_observer_->InitMenu(params_);
1048 void RenderViewContextMenu::AppendSpellcheckOptionsSubMenu() {
1049 if (!spellchecker_submenu_observer_.get()) {
1050 spellchecker_submenu_observer_.reset(new SpellCheckerSubMenuObserver(
1051 this, this, kSpellcheckRadioGroup));
1053 spellchecker_submenu_observer_->InitMenu(params_);
1054 observers_.AddObserver(spellchecker_submenu_observer_.get());
1057 void RenderViewContextMenu::AppendProtocolHandlerSubMenu() {
1058 const ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1059 GetHandlersForLinkUrl();
1060 if (handlers.empty())
1061 return;
1062 size_t max = IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST -
1063 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
1064 for (size_t i = 0; i < handlers.size() && i <= max; i++) {
1065 protocol_handler_submenu_model_.AddItem(
1066 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST + i,
1067 base::UTF8ToUTF16(handlers[i].url().host()));
1069 protocol_handler_submenu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1070 protocol_handler_submenu_model_.AddItem(
1071 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS,
1072 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH_CONFIGURE));
1074 menu_model_.AddSubMenu(
1075 IDC_CONTENT_CONTEXT_OPENLINKWITH,
1076 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH),
1077 &protocol_handler_submenu_model_);
1080 void RenderViewContextMenu::AppendPasswordItems() {
1081 if (!password_manager::ForceSavingExperimentEnabled())
1082 return;
1084 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1085 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD,
1086 IDS_CONTENT_CONTEXT_FORCESAVEPASSWORD);
1089 // Menu delegate functions -----------------------------------------------------
1091 bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
1093 bool enabled = false;
1094 if (RenderViewContextMenuBase::IsCommandIdKnown(id, &enabled))
1095 return enabled;
1098 CoreTabHelper* core_tab_helper =
1099 CoreTabHelper::FromWebContents(source_web_contents_);
1100 int content_restrictions = 0;
1101 if (core_tab_helper)
1102 content_restrictions = core_tab_helper->content_restrictions();
1103 if (id == IDC_PRINT && (content_restrictions & CONTENT_RESTRICTION_PRINT))
1104 return false;
1106 if (id == IDC_SAVE_PAGE &&
1107 (content_restrictions & CONTENT_RESTRICTION_SAVE)) {
1108 return false;
1111 PrefService* prefs = GetPrefs(browser_context_);
1113 // Allow Spell Check language items on sub menu for text area context menu.
1114 if ((id >= IDC_SPELLCHECK_LANGUAGES_FIRST) &&
1115 (id < IDC_SPELLCHECK_LANGUAGES_LAST)) {
1116 return prefs->GetBoolean(prefs::kEnableContinuousSpellcheck);
1119 // Extension items.
1120 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
1121 return extension_items_.IsCommandIdEnabled(id);
1123 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
1124 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
1125 return true;
1128 IncognitoModePrefs::Availability incognito_avail =
1129 IncognitoModePrefs::GetAvailability(prefs);
1130 switch (id) {
1131 case IDC_BACK:
1132 return embedder_web_contents_->GetController().CanGoBack();
1134 case IDC_FORWARD:
1135 return embedder_web_contents_->GetController().CanGoForward();
1137 case IDC_RELOAD: {
1138 CoreTabHelper* core_tab_helper =
1139 CoreTabHelper::FromWebContents(embedder_web_contents_);
1140 if (!core_tab_helper)
1141 return false;
1143 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
1144 return !core_delegate ||
1145 core_delegate->CanReloadContents(embedder_web_contents_);
1148 case IDC_VIEW_SOURCE:
1149 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
1150 return (params_.media_type != WebContextMenuData::MediaTypePlugin) &&
1151 embedder_web_contents_->GetController().CanViewSource();
1153 case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
1154 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE:
1155 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP:
1156 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP:
1157 return IsDevCommandEnabled(id);
1159 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO:
1160 if (embedder_web_contents_->GetController().GetVisibleEntry() == NULL)
1161 return false;
1162 // Disabled if no browser is associated (e.g. desktop notifications).
1163 if (chrome::FindBrowserWithWebContents(embedder_web_contents_) == NULL)
1164 return false;
1165 return true;
1167 case IDC_CONTENT_CONTEXT_TRANSLATE: {
1168 ChromeTranslateClient* chrome_translate_client =
1169 ChromeTranslateClient::FromWebContents(embedder_web_contents_);
1170 if (!chrome_translate_client)
1171 return false;
1172 std::string original_lang =
1173 chrome_translate_client->GetLanguageState().original_language();
1174 std::string target_lang = g_browser_process->GetApplicationLocale();
1175 target_lang =
1176 translate::TranslateDownloadManager::GetLanguageCode(target_lang);
1177 // Note that we intentionally enable the menu even if the original and
1178 // target languages are identical. This is to give a way to user to
1179 // translate a page that might contains text fragments in a different
1180 // language.
1181 return ((params_.edit_flags & WebContextMenuData::CanTranslate) != 0) &&
1182 !original_lang.empty() && // Did we receive the page language yet?
1183 !chrome_translate_client->GetLanguageState().IsPageTranslated() &&
1184 !embedder_web_contents_->GetInterstitialPage() &&
1185 // There are some application locales which can't be used as a
1186 // target language for translation.
1187 translate::TranslateDownloadManager::IsSupportedLanguage(
1188 target_lang) &&
1189 // Disable on the Instant Extended NTP.
1190 !search::IsInstantNTP(embedder_web_contents_);
1193 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB:
1194 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
1195 return params_.link_url.is_valid();
1197 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
1198 return params_.unfiltered_link_url.is_valid();
1200 case IDC_CONTENT_CONTEXT_SAVELINKAS: {
1201 PrefService* local_state = g_browser_process->local_state();
1202 DCHECK(local_state);
1203 // Test if file-selection dialogs are forbidden by policy.
1204 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1205 return false;
1207 return params_.link_url.is_valid() &&
1208 ProfileIOData::IsHandledProtocol(params_.link_url.scheme());
1211 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: {
1212 PrefService* local_state = g_browser_process->local_state();
1213 DCHECK(local_state);
1214 // Test if file-selection dialogs are forbidden by policy.
1215 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1216 return false;
1218 return params_.has_image_contents;
1221 // The images shown in the most visited thumbnails can't be opened or
1222 // searched for conventionally.
1223 case IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB:
1224 case IDC_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE:
1225 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
1226 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
1227 return params_.src_url.is_valid() &&
1228 (params_.src_url.scheme() != content::kChromeUIScheme);
1230 case IDC_CONTENT_CONTEXT_COPYIMAGE:
1231 return params_.has_image_contents;
1233 // Media control commands should all be disabled if the player is in an
1234 // error state.
1235 case IDC_CONTENT_CONTEXT_PLAYPAUSE:
1236 case IDC_CONTENT_CONTEXT_LOOP:
1237 return (params_.media_flags &
1238 WebContextMenuData::MediaInError) == 0;
1240 // Mute and unmute should also be disabled if the player has no audio.
1241 case IDC_CONTENT_CONTEXT_MUTE:
1242 return (params_.media_flags &
1243 WebContextMenuData::MediaHasAudio) != 0 &&
1244 (params_.media_flags &
1245 WebContextMenuData::MediaInError) == 0;
1247 case IDC_CONTENT_CONTEXT_CONTROLS:
1248 return (params_.media_flags &
1249 WebContextMenuData::MediaCanToggleControls) != 0;
1251 case IDC_CONTENT_CONTEXT_ROTATECW:
1252 case IDC_CONTENT_CONTEXT_ROTATECCW:
1253 return
1254 (params_.media_flags & WebContextMenuData::MediaCanRotate) != 0;
1256 case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
1257 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
1258 return params_.src_url.is_valid();
1260 case IDC_CONTENT_CONTEXT_SAVEAVAS: {
1261 PrefService* local_state = g_browser_process->local_state();
1262 DCHECK(local_state);
1263 // Test if file-selection dialogs are forbidden by policy.
1264 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1265 return false;
1267 const GURL& url = params_.src_url;
1268 bool can_save =
1269 (params_.media_flags & WebContextMenuData::MediaCanSave) &&
1270 url.is_valid() && ProfileIOData::IsHandledProtocol(url.scheme());
1271 #if defined(ENABLE_PRINT_PREVIEW)
1272 // Do not save the preview PDF on the print preview page.
1273 can_save = can_save &&
1274 !(printing::PrintPreviewDialogController::IsPrintPreviewURL(url));
1275 #endif
1276 return can_save;
1279 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
1280 // Currently, a media element can be opened in a new tab iff it can
1281 // be saved. So rather than duplicating the MediaCanSave flag, we rely
1282 // on that here.
1283 return !!(params_.media_flags & WebContextMenuData::MediaCanSave);
1285 case IDC_SAVE_PAGE: {
1286 CoreTabHelper* core_tab_helper =
1287 CoreTabHelper::FromWebContents(embedder_web_contents_);
1288 if (!core_tab_helper)
1289 return false;
1291 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
1292 if (core_delegate &&
1293 !core_delegate->CanSaveContents(embedder_web_contents_))
1294 return false;
1296 PrefService* local_state = g_browser_process->local_state();
1297 DCHECK(local_state);
1298 // Test if file-selection dialogs are forbidden by policy.
1299 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1300 return false;
1302 // We save the last committed entry (which the user is looking at), as
1303 // opposed to any pending URL that hasn't committed yet.
1304 NavigationEntry* entry =
1305 embedder_web_contents_->GetController().GetLastCommittedEntry();
1306 return content::IsSavableURL(entry ? entry->GetURL() : GURL());
1309 case IDC_CONTENT_CONTEXT_RELOADFRAME:
1310 return params_.frame_url.is_valid();
1312 case IDC_CONTENT_CONTEXT_UNDO:
1313 return !!(params_.edit_flags & WebContextMenuData::CanUndo);
1315 case IDC_CONTENT_CONTEXT_REDO:
1316 return !!(params_.edit_flags & WebContextMenuData::CanRedo);
1318 case IDC_CONTENT_CONTEXT_CUT:
1319 return !!(params_.edit_flags & WebContextMenuData::CanCut);
1321 case IDC_CONTENT_CONTEXT_COPY:
1322 return !!(params_.edit_flags & WebContextMenuData::CanCopy);
1324 case IDC_CONTENT_CONTEXT_PASTE: {
1325 if (!(params_.edit_flags & WebContextMenuData::CanPaste))
1326 return false;
1328 std::vector<base::string16> types;
1329 bool ignore;
1330 ui::Clipboard::GetForCurrentThread()->ReadAvailableTypes(
1331 ui::CLIPBOARD_TYPE_COPY_PASTE, &types, &ignore);
1332 return !types.empty();
1335 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE: {
1336 if (!(params_.edit_flags & WebContextMenuData::CanPaste))
1337 return false;
1339 return ui::Clipboard::GetForCurrentThread()->IsFormatAvailable(
1340 ui::Clipboard::GetPlainTextFormatType(),
1341 ui::CLIPBOARD_TYPE_COPY_PASTE);
1344 case IDC_CONTENT_CONTEXT_DELETE:
1345 return !!(params_.edit_flags & WebContextMenuData::CanDelete);
1347 case IDC_CONTENT_CONTEXT_SELECTALL:
1348 return !!(params_.edit_flags & WebContextMenuData::CanSelectAll);
1350 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
1351 return !browser_context_->IsOffTheRecord() &&
1352 params_.link_url.is_valid() &&
1353 incognito_avail != IncognitoModePrefs::DISABLED;
1355 case IDC_PRINT:
1356 return prefs->GetBoolean(prefs::kPrintingEnabled) &&
1357 (params_.media_type == WebContextMenuData::MediaTypeNone ||
1358 params_.media_flags & WebContextMenuData::MediaCanPrint);
1360 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
1361 case IDC_CONTENT_CONTEXT_GOTOURL:
1362 case IDC_SPELLPANEL_TOGGLE:
1363 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS:
1364 return true;
1365 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO:
1366 // Disabled if no browser is associated (e.g. desktop notifications).
1367 if (chrome::FindBrowserWithWebContents(source_web_contents_) == NULL)
1368 return false;
1369 return true;
1371 case IDC_CHECK_SPELLING_WHILE_TYPING:
1372 return prefs->GetBoolean(prefs::kEnableContinuousSpellcheck);
1374 #if !defined(OS_MACOSX) && defined(OS_POSIX)
1375 // TODO(suzhe): this should not be enabled for password fields.
1376 case IDC_INPUT_METHODS_MENU:
1377 return true;
1378 #endif
1380 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE:
1381 return !params_.keyword_url.is_empty();
1383 case IDC_SPELLCHECK_MENU:
1384 return true;
1386 case IDC_CONTENT_CONTEXT_OPENLINKWITH:
1387 return true;
1389 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS:
1390 return true;
1392 case IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD:
1393 return true;
1395 default:
1396 NOTREACHED();
1397 return false;
1401 bool RenderViewContextMenu::IsCommandIdChecked(int id) const {
1402 if (RenderViewContextMenuBase::IsCommandIdChecked(id))
1403 return true;
1405 // See if the video is set to looping.
1406 if (id == IDC_CONTENT_CONTEXT_LOOP)
1407 return (params_.media_flags & WebContextMenuData::MediaLoop) != 0;
1409 if (id == IDC_CONTENT_CONTEXT_CONTROLS)
1410 return (params_.media_flags & WebContextMenuData::MediaControls) != 0;
1412 // Extension items.
1413 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
1414 return extension_items_.IsCommandIdChecked(id);
1416 return false;
1419 void RenderViewContextMenu::ExecuteCommand(int id, int event_flags) {
1420 RenderViewContextMenuBase::ExecuteCommand(id, event_flags);
1421 if (command_executed_)
1422 return;
1423 command_executed_ = true;
1425 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1427 // Process extension menu items.
1428 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id)) {
1429 extension_items_.ExecuteCommand(id, source_web_contents_, params_);
1430 return;
1433 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
1434 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
1435 ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1436 GetHandlersForLinkUrl();
1437 if (handlers.empty())
1438 return;
1440 content::RecordAction(
1441 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Open"));
1442 int handlerIndex = id - IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
1443 WindowOpenDisposition disposition =
1444 ForceNewTabDispositionFromEventFlags(event_flags);
1445 OpenURL(handlers[handlerIndex].TranslateUrl(params_.link_url),
1446 GetDocumentURL(params_),
1447 disposition,
1448 ui::PAGE_TRANSITION_LINK);
1449 return;
1452 switch (id) {
1453 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB: {
1454 Browser* browser =
1455 chrome::FindBrowserWithWebContents(source_web_contents_);
1456 OpenURL(params_.link_url,
1457 GetDocumentURL(params_),
1458 !browser || browser->is_app() ?
1459 NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB,
1460 ui::PAGE_TRANSITION_LINK);
1461 break;
1463 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
1464 OpenURL(params_.link_url,
1465 GetDocumentURL(params_),
1466 NEW_WINDOW,
1467 ui::PAGE_TRANSITION_LINK);
1468 break;
1470 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
1471 OpenURL(params_.link_url, GURL(), OFF_THE_RECORD,
1472 ui::PAGE_TRANSITION_LINK);
1473 break;
1475 case IDC_CONTENT_CONTEXT_SAVELINKAS: {
1476 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
1477 const GURL& url = params_.link_url;
1478 content::Referrer referrer = CreateSaveAsReferrer(url, params_);
1479 DownloadManager* dlm =
1480 BrowserContext::GetDownloadManager(browser_context_);
1481 scoped_ptr<DownloadUrlParameters> dl_params(
1482 DownloadUrlParameters::FromWebContents(source_web_contents_, url));
1483 dl_params->set_referrer(referrer);
1484 dl_params->set_referrer_encoding(params_.frame_charset);
1485 dl_params->set_suggested_name(params_.suggested_filename);
1486 dl_params->set_prompt(true);
1487 dlm->DownloadUrl(dl_params.Pass());
1488 break;
1491 case IDC_CONTENT_CONTEXT_SAVEAVAS:
1492 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: {
1493 bool is_large_data_url = params_.has_image_contents &&
1494 params_.src_url.is_empty();
1495 if (params_.media_type == WebContextMenuData::MediaTypeCanvas ||
1496 (params_.media_type == WebContextMenuData::MediaTypeImage &&
1497 is_large_data_url)) {
1498 source_web_contents_->GetRenderViewHost()->SaveImageAt(
1499 params_.x, params_.y);
1500 } else {
1501 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
1502 const GURL& url = params_.src_url;
1503 content::Referrer referrer = CreateSaveAsReferrer(url, params_);
1505 std::string headers;
1506 DataReductionProxyChromeSettings* settings =
1507 DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
1508 browser_context_);
1509 if (params_.media_type == WebContextMenuData::MediaTypeImage &&
1510 settings && settings->CanUseDataReductionProxy(params_.src_url)) {
1511 headers = data_reduction_proxy::kDataReductionPassThroughHeader;
1514 source_web_contents_->SaveFrameWithHeaders(url, referrer, headers);
1516 break;
1519 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
1520 WriteURLToClipboard(params_.unfiltered_link_url);
1521 break;
1523 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
1524 case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
1525 WriteURLToClipboard(params_.src_url);
1526 break;
1528 case IDC_CONTENT_CONTEXT_COPYIMAGE:
1529 CopyImageAt(params_.x, params_.y);
1530 break;
1532 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
1533 GetImageThumbnailForSearch();
1534 break;
1536 case IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB:
1537 OpenURLWithExtraHeaders(
1538 params_.src_url, GetDocumentURL(params_), NEW_BACKGROUND_TAB,
1539 ui::PAGE_TRANSITION_LINK,
1540 data_reduction_proxy::kDataReductionPassThroughHeader);
1541 break;
1543 case IDC_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE:
1544 LoadOriginalImage();
1545 break;
1547 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
1548 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
1549 OpenURL(params_.src_url,
1550 GetDocumentURL(params_),
1551 NEW_BACKGROUND_TAB,
1552 ui::PAGE_TRANSITION_LINK);
1553 break;
1555 case IDC_CONTENT_CONTEXT_PLAYPAUSE: {
1556 bool play = !!(params_.media_flags & WebContextMenuData::MediaPaused);
1557 if (play) {
1558 content::RecordAction(UserMetricsAction("MediaContextMenu_Play"));
1559 } else {
1560 content::RecordAction(UserMetricsAction("MediaContextMenu_Pause"));
1562 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1563 WebMediaPlayerAction(
1564 WebMediaPlayerAction::Play, play));
1565 break;
1568 case IDC_CONTENT_CONTEXT_MUTE: {
1569 bool mute = !(params_.media_flags & WebContextMenuData::MediaMuted);
1570 if (mute) {
1571 content::RecordAction(UserMetricsAction("MediaContextMenu_Mute"));
1572 } else {
1573 content::RecordAction(UserMetricsAction("MediaContextMenu_Unmute"));
1575 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1576 WebMediaPlayerAction(
1577 WebMediaPlayerAction::Mute, mute));
1578 break;
1581 case IDC_CONTENT_CONTEXT_LOOP:
1582 content::RecordAction(UserMetricsAction("MediaContextMenu_Loop"));
1583 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1584 WebMediaPlayerAction(
1585 WebMediaPlayerAction::Loop,
1586 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_LOOP)));
1587 break;
1589 case IDC_CONTENT_CONTEXT_CONTROLS:
1590 content::RecordAction(UserMetricsAction("MediaContextMenu_Controls"));
1591 MediaPlayerActionAt(
1592 gfx::Point(params_.x, params_.y),
1593 WebMediaPlayerAction(
1594 WebMediaPlayerAction::Controls,
1595 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_CONTROLS)));
1596 break;
1598 case IDC_CONTENT_CONTEXT_ROTATECW:
1599 content::RecordAction(
1600 UserMetricsAction("PluginContextMenu_RotateClockwise"));
1601 PluginActionAt(
1602 gfx::Point(params_.x, params_.y),
1603 WebPluginAction(WebPluginAction::Rotate90Clockwise, true));
1604 break;
1606 case IDC_CONTENT_CONTEXT_ROTATECCW:
1607 content::RecordAction(
1608 UserMetricsAction("PluginContextMenu_RotateCounterclockwise"));
1609 PluginActionAt(
1610 gfx::Point(params_.x, params_.y),
1611 WebPluginAction(WebPluginAction::Rotate90Counterclockwise, true));
1612 break;
1614 case IDC_BACK:
1615 embedder_web_contents_->GetController().GoBack();
1616 break;
1618 case IDC_FORWARD:
1619 embedder_web_contents_->GetController().GoForward();
1620 break;
1622 case IDC_SAVE_PAGE:
1623 embedder_web_contents_->OnSavePage();
1624 break;
1626 case IDC_RELOAD:
1627 embedder_web_contents_->GetController().Reload(true);
1628 break;
1630 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP: {
1631 const Extension* platform_app = GetExtension();
1632 DCHECK(platform_app);
1633 DCHECK(platform_app->is_platform_app());
1635 extensions::ExtensionSystem::Get(browser_context_)
1636 ->extension_service()
1637 ->ReloadExtension(platform_app->id());
1638 break;
1641 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP: {
1642 const Extension* platform_app = GetExtension();
1643 DCHECK(platform_app);
1644 DCHECK(platform_app->is_platform_app());
1646 apps::AppLoadService::Get(GetProfile())
1647 ->RestartApplication(platform_app->id());
1648 break;
1651 case IDC_PRINT: {
1652 #if defined(ENABLE_PRINTING)
1653 if (params_.media_type != WebContextMenuData::MediaTypeNone) {
1654 if (render_frame_host) {
1655 render_frame_host->Send(new PrintMsg_PrintNodeUnderContextMenu(
1656 render_frame_host->GetRoutingID()));
1658 break;
1661 printing::StartPrint(
1662 source_web_contents_,
1663 GetPrefs(browser_context_)->GetBoolean(prefs::kPrintPreviewDisabled),
1664 !params_.selection_text.empty());
1665 #endif // ENABLE_PRINTING
1666 break;
1669 case IDC_VIEW_SOURCE:
1670 embedder_web_contents_->ViewSource();
1671 break;
1673 case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
1674 Inspect(params_.x, params_.y);
1675 break;
1677 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE: {
1678 const Extension* platform_app = GetExtension();
1679 DCHECK(platform_app);
1680 DCHECK(platform_app->is_platform_app());
1682 extensions::devtools_util::InspectBackgroundPage(platform_app,
1683 GetProfile());
1684 break;
1687 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO: {
1688 NavigationController* controller =
1689 &embedder_web_contents_->GetController();
1690 // Important to use GetVisibleEntry to match what's showing in the
1691 // omnibox. This may return null.
1692 NavigationEntry* nav_entry = controller->GetVisibleEntry();
1693 if (!nav_entry)
1694 return;
1695 Browser* browser =
1696 chrome::FindBrowserWithWebContents(embedder_web_contents_);
1697 SecurityStateModel* security_model =
1698 SecurityStateModel::FromWebContents(embedder_web_contents_);
1699 DCHECK(security_model);
1700 chrome::ShowWebsiteSettings(browser, embedder_web_contents_,
1701 nav_entry->GetURL(),
1702 security_model->GetSecurityInfo());
1703 break;
1706 case IDC_CONTENT_CONTEXT_TRANSLATE: {
1707 // A translation might have been triggered by the time the menu got
1708 // selected, do nothing in that case.
1709 ChromeTranslateClient* chrome_translate_client =
1710 ChromeTranslateClient::FromWebContents(embedder_web_contents_);
1711 if (!chrome_translate_client ||
1712 chrome_translate_client->GetLanguageState().IsPageTranslated() ||
1713 chrome_translate_client->GetLanguageState().translation_pending()) {
1714 return;
1716 std::string original_lang =
1717 chrome_translate_client->GetLanguageState().original_language();
1718 std::string target_lang = g_browser_process->GetApplicationLocale();
1719 target_lang =
1720 translate::TranslateDownloadManager::GetLanguageCode(target_lang);
1721 // Since the user decided to translate for that language and site, clears
1722 // any preferences for not translating them.
1723 scoped_ptr<translate::TranslatePrefs> prefs(
1724 ChromeTranslateClient::CreateTranslatePrefs(
1725 GetPrefs(browser_context_)));
1726 prefs->UnblockLanguage(original_lang);
1727 prefs->RemoveSiteFromBlacklist(params_.page_url.HostNoBrackets());
1728 translate::TranslateManager* manager =
1729 chrome_translate_client->GetTranslateManager();
1730 DCHECK(manager);
1731 manager->TranslatePage(original_lang, target_lang, true);
1732 break;
1735 case IDC_CONTENT_CONTEXT_RELOADFRAME:
1736 // We always obey the cache here.
1737 // TODO(evanm): Perhaps we could allow shift-clicking the menu item to do
1738 // a cache-ignoring reload of the frame.
1739 source_web_contents_->ReloadFocusedFrame(false);
1740 break;
1742 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
1743 source_web_contents_->ViewFrameSource(params_.frame_url,
1744 params_.frame_page_state);
1745 break;
1747 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO: {
1748 Browser* browser = chrome::FindBrowserWithWebContents(
1749 source_web_contents_);
1750 SecurityStateModel::SecurityInfo security_info;
1751 SecurityStateModel::SecurityInfoForRequest(
1752 params_.frame_url, params_.security_info,
1753 Profile::FromBrowserContext(
1754 source_web_contents_->GetBrowserContext()),
1755 &security_info);
1756 chrome::ShowWebsiteSettings(browser, source_web_contents_,
1757 params_.frame_url, security_info);
1758 break;
1761 case IDC_CONTENT_CONTEXT_UNDO:
1762 source_web_contents_->Undo();
1763 break;
1765 case IDC_CONTENT_CONTEXT_REDO:
1766 source_web_contents_->Redo();
1767 break;
1769 case IDC_CONTENT_CONTEXT_CUT:
1770 source_web_contents_->Cut();
1771 break;
1773 case IDC_CONTENT_CONTEXT_COPY:
1774 source_web_contents_->Copy();
1775 break;
1777 case IDC_CONTENT_CONTEXT_PASTE:
1778 source_web_contents_->Paste();
1779 break;
1781 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE:
1782 source_web_contents_->PasteAndMatchStyle();
1783 break;
1785 case IDC_CONTENT_CONTEXT_DELETE:
1786 source_web_contents_->Delete();
1787 break;
1789 case IDC_CONTENT_CONTEXT_SELECTALL:
1790 source_web_contents_->SelectAll();
1791 break;
1793 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
1794 case IDC_CONTENT_CONTEXT_GOTOURL: {
1795 WindowOpenDisposition disposition =
1796 ForceNewTabDispositionFromEventFlags(event_flags);
1797 OpenURL(selection_navigation_url_, GURL(), disposition,
1798 ui::PAGE_TRANSITION_LINK);
1799 break;
1801 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS: {
1802 WindowOpenDisposition disposition =
1803 ForceNewTabDispositionFromEventFlags(event_flags);
1804 GURL url = chrome::GetSettingsUrl(chrome::kLanguageOptionsSubPage);
1805 OpenURL(url, GURL(), disposition, ui::PAGE_TRANSITION_LINK);
1806 break;
1809 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS: {
1810 content::RecordAction(
1811 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Settings"));
1812 WindowOpenDisposition disposition =
1813 ForceNewTabDispositionFromEventFlags(event_flags);
1814 GURL url = chrome::GetSettingsUrl(chrome::kHandlerSettingsSubPage);
1815 OpenURL(url, GURL(), disposition, ui::PAGE_TRANSITION_LINK);
1816 break;
1819 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE: {
1820 // Make sure the model is loaded.
1821 TemplateURLService* model =
1822 TemplateURLServiceFactory::GetForProfile(GetProfile());
1823 if (!model)
1824 return;
1825 model->Load();
1827 SearchEngineTabHelper* search_engine_tab_helper =
1828 SearchEngineTabHelper::FromWebContents(source_web_contents_);
1829 if (search_engine_tab_helper &&
1830 search_engine_tab_helper->delegate()) {
1831 base::string16 keyword(TemplateURL::GenerateKeyword(
1832 params_.page_url,
1833 GetProfile()->GetPrefs()->GetString(prefs::kAcceptLanguages)));
1834 TemplateURLData data;
1835 data.SetShortName(keyword);
1836 data.SetKeyword(keyword);
1837 data.SetURL(params_.keyword_url.spec());
1838 data.favicon_url =
1839 TemplateURL::GenerateFaviconURL(params_.page_url.GetOrigin());
1840 // Takes ownership of the TemplateURL.
1841 search_engine_tab_helper->delegate()->ConfirmAddSearchProvider(
1842 new TemplateURL(data), GetProfile());
1844 break;
1847 case IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD:
1848 ChromePasswordManagerClient::FromWebContents(source_web_contents_)->
1849 ForceSavePassword();
1850 break;
1852 default:
1853 NOTREACHED();
1854 break;
1858 ProtocolHandlerRegistry::ProtocolHandlerList
1859 RenderViewContextMenu::GetHandlersForLinkUrl() {
1860 ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1861 protocol_handler_registry_->GetHandlersFor(params_.link_url.scheme());
1862 std::sort(handlers.begin(), handlers.end());
1863 return handlers;
1866 void RenderViewContextMenu::NotifyMenuShown() {
1867 content::NotificationService::current()->Notify(
1868 chrome::NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN,
1869 content::Source<RenderViewContextMenu>(this),
1870 content::NotificationService::NoDetails());
1873 void RenderViewContextMenu::NotifyURLOpened(
1874 const GURL& url,
1875 content::WebContents* new_contents) {
1876 RetargetingDetails details;
1877 details.source_web_contents = source_web_contents_;
1878 // Don't use GetRenderFrameHost() as it may be NULL. crbug.com/399789
1879 details.source_render_frame_id = render_frame_id_;
1880 details.target_url = url;
1881 details.target_web_contents = new_contents;
1882 details.not_yet_in_tabstrip = false;
1884 content::NotificationService::current()->Notify(
1885 chrome::NOTIFICATION_RETARGETING,
1886 content::Source<Profile>(GetProfile()),
1887 content::Details<RetargetingDetails>(&details));
1890 bool RenderViewContextMenu::IsDevCommandEnabled(int id) const {
1891 if (id == IDC_CONTENT_CONTEXT_INSPECTELEMENT ||
1892 id == IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE) {
1893 if (!GetPrefs(browser_context_)
1894 ->GetBoolean(prefs::kWebKitJavascriptEnabled))
1895 return false;
1897 // Don't enable the web inspector if the developer tools are disabled via
1898 // the preference dev-tools-disabled.
1899 if (GetPrefs(browser_context_)->GetBoolean(prefs::kDevToolsDisabled))
1900 return false;
1903 return true;
1906 base::string16 RenderViewContextMenu::PrintableSelectionText() {
1907 return gfx::TruncateString(params_.selection_text,
1908 kMaxSelectionTextLength,
1909 gfx::WORD_BREAK);
1912 void RenderViewContextMenu::EscapeAmpersands(base::string16* text) {
1913 base::ReplaceChars(*text, base::ASCIIToUTF16("&"), base::ASCIIToUTF16("&&"),
1914 text);
1917 // Controller functions --------------------------------------------------------
1919 void RenderViewContextMenu::CopyImageAt(int x, int y) {
1920 source_web_contents_->GetRenderViewHost()->CopyImageAt(x, y);
1923 void RenderViewContextMenu::LoadOriginalImage() {
1924 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1925 if (!render_frame_host)
1926 return;
1927 render_frame_host->Send(new ChromeViewMsg_RequestReloadImageForContextNode(
1928 render_frame_host->GetRoutingID()));
1931 void RenderViewContextMenu::GetImageThumbnailForSearch() {
1932 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1933 if (!render_frame_host)
1934 return;
1935 render_frame_host->Send(new ChromeViewMsg_RequestThumbnailForContextNode(
1936 render_frame_host->GetRoutingID(),
1937 kImageSearchThumbnailMinSize,
1938 gfx::Size(kImageSearchThumbnailMaxWidth,
1939 kImageSearchThumbnailMaxHeight)));
1942 void RenderViewContextMenu::Inspect(int x, int y) {
1943 content::RecordAction(UserMetricsAction("DevTools_InspectElement"));
1944 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1945 if (!render_frame_host)
1946 return;
1947 DevToolsWindow::InspectElement(
1948 WebContents::FromRenderFrameHost(render_frame_host), x, y);
1951 void RenderViewContextMenu::WriteURLToClipboard(const GURL& url) {
1952 ::WriteURLToClipboard(
1953 url, GetPrefs(browser_context_)->GetString(prefs::kAcceptLanguages));
1956 void RenderViewContextMenu::MediaPlayerActionAt(
1957 const gfx::Point& location,
1958 const WebMediaPlayerAction& action) {
1959 source_web_contents_->GetRenderViewHost()->
1960 ExecuteMediaPlayerActionAtLocation(location, action);
1963 void RenderViewContextMenu::PluginActionAt(
1964 const gfx::Point& location,
1965 const WebPluginAction& action) {
1966 source_web_contents_->GetRenderViewHost()->
1967 ExecutePluginActionAtLocation(location, action);