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