Add a basic functionality to the force-saving menu item.
[chromium-blink-merge.git] / chrome / browser / renderer_context_menu / render_view_context_menu.cc
blob8af019df57b9f36a23c1a2a2b10f6461053833fb
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.h"
24 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
25 #include "chrome/browser/browser_process.h"
26 #include "chrome/browser/chrome_notification_types.h"
27 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
28 #include "chrome/browser/devtools/devtools_window.h"
29 #include "chrome/browser/download/download_service.h"
30 #include "chrome/browser/download/download_service_factory.h"
31 #include "chrome/browser/download/download_stats.h"
32 #include "chrome/browser/extensions/devtools_util.h"
33 #include "chrome/browser/extensions/extension_service.h"
34 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h"
35 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings_factory.h"
36 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
37 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
38 #include "chrome/browser/prefs/incognito_mode_prefs.h"
39 #include "chrome/browser/profiles/profile.h"
40 #include "chrome/browser/profiles/profile_io_data.h"
41 #include "chrome/browser/renderer_context_menu/context_menu_content_type_factory.h"
42 #include "chrome/browser/renderer_context_menu/spellchecker_submenu_observer.h"
43 #include "chrome/browser/renderer_context_menu/spelling_menu_observer.h"
44 #include "chrome/browser/search/search.h"
45 #include "chrome/browser/search_engines/template_url_service_factory.h"
46 #include "chrome/browser/spellchecker/spellcheck_host_metrics.h"
47 #include "chrome/browser/spellchecker/spellcheck_service.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/net/url_util.h"
61 #include "chrome/common/pref_names.h"
62 #include "chrome/common/render_messages.h"
63 #include "chrome/common/spellcheck_messages.h"
64 #include "chrome/common/url_constants.h"
65 #include "chrome/grit/generated_resources.h"
66 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
67 #include "components/google/core/browser/google_util.h"
68 #include "components/metrics/proto/omnibox_input_type.pb.h"
69 #include "components/omnibox/autocomplete_match.h"
70 #include "components/password_manager/core/common/experiments.h"
71 #include "components/search_engines/template_url.h"
72 #include "components/search_engines/template_url_service.h"
73 #include "components/translate/core/browser/translate_download_manager.h"
74 #include "components/translate/core/browser/translate_manager.h"
75 #include "components/translate/core/browser/translate_prefs.h"
76 #include "components/user_prefs/user_prefs.h"
77 #include "content/public/browser/child_process_security_policy.h"
78 #include "content/public/browser/download_manager.h"
79 #include "content/public/browser/download_save_info.h"
80 #include "content/public/browser/download_url_parameters.h"
81 #include "content/public/browser/navigation_details.h"
82 #include "content/public/browser/navigation_entry.h"
83 #include "content/public/browser/notification_service.h"
84 #include "content/public/browser/render_frame_host.h"
85 #include "content/public/browser/render_process_host.h"
86 #include "content/public/browser/render_view_host.h"
87 #include "content/public/browser/render_widget_host_view.h"
88 #include "content/public/browser/user_metrics.h"
89 #include "content/public/browser/web_contents.h"
90 #include "content/public/common/menu_item.h"
91 #include "content/public/common/ssl_status.h"
92 #include "content/public/common/url_utils.h"
93 #include "extensions/browser/extension_host.h"
94 #include "extensions/browser/extension_system.h"
95 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
96 #include "extensions/browser/view_type_utils.h"
97 #include "extensions/common/extension.h"
98 #include "net/base/escape.h"
99 #include "third_party/WebKit/public/web/WebContextMenuData.h"
100 #include "third_party/WebKit/public/web/WebMediaPlayerAction.h"
101 #include "third_party/WebKit/public/web/WebPluginAction.h"
102 #include "ui/base/clipboard/clipboard.h"
103 #include "ui/base/l10n/l10n_util.h"
104 #include "ui/gfx/favicon_size.h"
105 #include "ui/gfx/geometry/point.h"
106 #include "ui/gfx/geometry/size.h"
107 #include "ui/gfx/text_elider.h"
109 #if defined(ENABLE_EXTENSIONS)
110 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
111 #endif
113 #if defined(ENABLE_PRINTING)
114 #include "chrome/browser/printing/print_view_manager_common.h"
115 #include "components/printing/common/print_messages.h"
117 #if defined(ENABLE_PRINT_PREVIEW)
118 #include "chrome/browser/printing/print_preview_context_menu_observer.h"
119 #include "chrome/browser/printing/print_preview_dialog_controller.h"
120 #endif // defined(ENABLE_PRINT_PREVIEW)
121 #endif // defined(ENABLE_PRINTING)
123 using base::UserMetricsAction;
124 using blink::WebContextMenuData;
125 using blink::WebMediaPlayerAction;
126 using blink::WebPluginAction;
127 using blink::WebString;
128 using blink::WebURL;
129 using content::BrowserContext;
130 using content::ChildProcessSecurityPolicy;
131 using content::DownloadManager;
132 using content::DownloadUrlParameters;
133 using content::NavigationController;
134 using content::NavigationEntry;
135 using content::OpenURLParams;
136 using content::RenderFrameHost;
137 using content::RenderViewHost;
138 using content::SSLStatus;
139 using content::WebContents;
140 using extensions::ContextMenuMatcher;
141 using extensions::Extension;
142 using extensions::MenuItem;
143 using extensions::MenuManager;
145 namespace {
147 const int kImageSearchThumbnailMinSize = 300 * 300;
148 const int kImageSearchThumbnailMaxWidth = 600;
149 const int kImageSearchThumbnailMaxHeight = 600;
151 // Maps UMA enumeration to IDC. IDC could be changed so we can't use
152 // just them and |UMA_HISTOGRAM_CUSTOM_ENUMERATION|.
153 // Never change mapping or reuse |enum_id|. Always push back new items.
154 // Items that is not used any more by |RenderViewContextMenu.ExecuteCommand|
155 // could be deleted, but don't change the rest of |kUmaEnumToControlId|.
156 const struct UmaEnumCommandIdPair {
157 int enum_id;
158 int control_id;
159 } kUmaEnumToControlId[] = {
161 enum id for 0, 1 are detected using
162 RenderViewContextMenu::IsContentCustomCommandId and
163 ContextMenuMatcher::IsExtensionsCustomCommandId
165 {2, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST},
166 {3, IDC_CONTENT_CONTEXT_OPENLINKNEWTAB},
167 {4, IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW},
168 {5, IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD},
169 {6, IDC_CONTENT_CONTEXT_SAVELINKAS},
170 {7, IDC_CONTENT_CONTEXT_SAVEAVAS},
171 {8, IDC_CONTENT_CONTEXT_SAVEIMAGEAS},
172 {9, IDC_CONTENT_CONTEXT_COPYLINKLOCATION},
173 {10, IDC_CONTENT_CONTEXT_COPYIMAGELOCATION},
174 {11, IDC_CONTENT_CONTEXT_COPYAVLOCATION},
175 {12, IDC_CONTENT_CONTEXT_COPYIMAGE},
176 {13, IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB},
177 {14, IDC_CONTENT_CONTEXT_OPENAVNEWTAB},
178 {15, IDC_CONTENT_CONTEXT_PLAYPAUSE},
179 {16, IDC_CONTENT_CONTEXT_MUTE},
180 {17, IDC_CONTENT_CONTEXT_LOOP},
181 {18, IDC_CONTENT_CONTEXT_CONTROLS},
182 {19, IDC_CONTENT_CONTEXT_ROTATECW},
183 {20, IDC_CONTENT_CONTEXT_ROTATECCW},
184 {21, IDC_BACK},
185 {22, IDC_FORWARD},
186 {23, IDC_SAVE_PAGE},
187 {24, IDC_RELOAD},
188 {25, IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP},
189 {26, IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP},
190 {27, IDC_PRINT},
191 {28, IDC_VIEW_SOURCE},
192 {29, IDC_CONTENT_CONTEXT_INSPECTELEMENT},
193 {30, IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE},
194 {31, IDC_CONTENT_CONTEXT_VIEWPAGEINFO},
195 {32, IDC_CONTENT_CONTEXT_TRANSLATE},
196 {33, IDC_CONTENT_CONTEXT_RELOADFRAME},
197 {34, IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE},
198 {35, IDC_CONTENT_CONTEXT_VIEWFRAMEINFO},
199 {36, IDC_CONTENT_CONTEXT_UNDO},
200 {37, IDC_CONTENT_CONTEXT_REDO},
201 {38, IDC_CONTENT_CONTEXT_CUT},
202 {39, IDC_CONTENT_CONTEXT_COPY},
203 {40, IDC_CONTENT_CONTEXT_PASTE},
204 {41, IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE},
205 {42, IDC_CONTENT_CONTEXT_DELETE},
206 {43, IDC_CONTENT_CONTEXT_SELECTALL},
207 {44, IDC_CONTENT_CONTEXT_SEARCHWEBFOR},
208 {45, IDC_CONTENT_CONTEXT_GOTOURL},
209 {46, IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS},
210 {47, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS},
211 {48, IDC_CONTENT_CONTEXT_ADDSEARCHENGINE},
212 {52, IDC_CONTENT_CONTEXT_OPENLINKWITH},
213 {53, IDC_CHECK_SPELLING_WHILE_TYPING},
214 {54, IDC_SPELLCHECK_MENU},
215 {55, IDC_CONTENT_CONTEXT_SPELLING_TOGGLE},
216 {56, IDC_SPELLCHECK_LANGUAGES_FIRST},
217 {57, IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE},
218 {58, IDC_SPELLCHECK_SUGGESTION_0},
219 {59, IDC_SPELLCHECK_ADD_TO_DICTIONARY},
220 {60, IDC_SPELLPANEL_TOGGLE},
221 {61, IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB},
222 {62, IDC_WRITING_DIRECTION_MENU},
223 {63, IDC_WRITING_DIRECTION_DEFAULT},
224 {64, IDC_WRITING_DIRECTION_LTR},
225 {65, IDC_WRITING_DIRECTION_RTL},
226 {66, IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE},
227 {67, IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD},
228 // Add new items here and use |enum_id| from the next line.
229 // Also, add new items to RenderViewContextMenuItem enum in histograms.xml.
230 {68, 0}, // Must be the last. Increment |enum_id| when new IDC was added.
233 // Collapses large ranges of ids before looking for UMA enum.
234 int CollapseCommandsForUMA(int id) {
235 DCHECK(!RenderViewContextMenu::IsContentCustomCommandId(id));
236 DCHECK(!ContextMenuMatcher::IsExtensionsCustomCommandId(id));
238 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
239 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
240 return IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
243 if (id >= IDC_SPELLCHECK_LANGUAGES_FIRST &&
244 id <= IDC_SPELLCHECK_LANGUAGES_LAST) {
245 return IDC_SPELLCHECK_LANGUAGES_FIRST;
248 if (id >= IDC_SPELLCHECK_SUGGESTION_0 &&
249 id <= IDC_SPELLCHECK_SUGGESTION_LAST) {
250 return IDC_SPELLCHECK_SUGGESTION_0;
253 return id;
256 // Returns UMA enum value for command specified by |id| or -1 if not found.
257 int FindUMAEnumValueForCommand(int id) {
258 if (RenderViewContextMenu::IsContentCustomCommandId(id))
259 return 0;
261 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
262 return 1;
264 id = CollapseCommandsForUMA(id);
265 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
266 for (size_t i = 0; i < kMappingSize; ++i) {
267 if (kUmaEnumToControlId[i].control_id == id) {
268 return kUmaEnumToControlId[i].enum_id;
271 return -1;
274 // Usually a new tab is expected where this function is used,
275 // however users should be able to open a tab in background
276 // or in a new window.
277 WindowOpenDisposition ForceNewTabDispositionFromEventFlags(
278 int event_flags) {
279 WindowOpenDisposition disposition =
280 ui::DispositionFromEventFlags(event_flags);
281 return disposition == CURRENT_TAB ? NEW_FOREGROUND_TAB : disposition;
284 // Helper function to escape "&" as "&&".
285 void EscapeAmpersands(base::string16* text) {
286 base::ReplaceChars(*text, base::ASCIIToUTF16("&"), base::ASCIIToUTF16("&&"),
287 text);
290 // Returns the preference of the profile represented by the |context|.
291 PrefService* GetPrefs(content::BrowserContext* context) {
292 return user_prefs::UserPrefs::Get(context);
295 bool ExtensionPatternMatch(const extensions::URLPatternSet& patterns,
296 const GURL& url) {
297 // No patterns means no restriction, so that implicitly matches.
298 if (patterns.is_empty())
299 return true;
300 return patterns.MatchesURL(url);
303 const GURL& GetDocumentURL(const content::ContextMenuParams& params) {
304 return params.frame_url.is_empty() ? params.page_url : params.frame_url;
307 content::Referrer CreateSaveAsReferrer(
308 const GURL& url,
309 const content::ContextMenuParams& params) {
310 const GURL& referring_url = GetDocumentURL(params);
311 return content::Referrer::SanitizeForRequest(
312 url,
313 content::Referrer(referring_url.GetAsReferrer(), params.referrer_policy));
316 content::WebContents* GetWebContentsToUse(content::WebContents* web_contents) {
317 #if defined(ENABLE_EXTENSIONS)
318 // If we're viewing in a MimeHandlerViewGuest, use its embedder WebContents.
319 if (extensions::MimeHandlerViewGuest::FromWebContents(web_contents)) {
320 WebContents* top_level_web_contents =
321 guest_view::GuestViewBase::GetTopLevelWebContents(web_contents);
322 if (top_level_web_contents)
323 return top_level_web_contents;
325 #endif
326 return web_contents;
329 bool g_custom_id_ranges_initialized = false;
331 const int kSpellcheckRadioGroup = 1;
333 } // namespace
335 // static
336 gfx::Vector2d RenderViewContextMenu::GetOffset(
337 RenderFrameHost* render_frame_host) {
338 gfx::Vector2d offset;
339 #if defined(ENABLE_EXTENSIONS)
340 WebContents* web_contents =
341 WebContents::FromRenderFrameHost(render_frame_host);
342 WebContents* top_level_web_contents =
343 guest_view::GuestViewBase::GetTopLevelWebContents(web_contents);
344 if (web_contents && top_level_web_contents &&
345 web_contents != top_level_web_contents) {
346 gfx::Rect bounds = web_contents->GetContainerBounds();
347 gfx::Rect top_level_bounds = top_level_web_contents->GetContainerBounds();
348 offset = bounds.origin() - top_level_bounds.origin();
350 #endif // defined(ENABLE_EXTENSIONS)
351 return offset;
354 // static
355 bool RenderViewContextMenu::IsDevToolsURL(const GURL& url) {
356 return url.SchemeIs(content::kChromeDevToolsScheme);
359 // static
360 bool RenderViewContextMenu::IsInternalResourcesURL(const GURL& url) {
361 if (!url.SchemeIs(content::kChromeUIScheme))
362 return false;
363 return url.host() == chrome::kChromeUISyncResourcesHost;
366 RenderViewContextMenu::RenderViewContextMenu(
367 content::RenderFrameHost* render_frame_host,
368 const content::ContextMenuParams& params)
369 : RenderViewContextMenuBase(render_frame_host, params),
370 extension_items_(browser_context_,
371 this,
372 &menu_model_,
373 base::Bind(MenuItemMatchesParams, params_)),
374 protocol_handler_submenu_model_(this),
375 protocol_handler_registry_(
376 ProtocolHandlerRegistryFactory::GetForBrowserContext(GetProfile())),
377 embedder_web_contents_(GetWebContentsToUse(source_web_contents_)) {
378 if (!g_custom_id_ranges_initialized) {
379 g_custom_id_ranges_initialized = true;
380 SetContentCustomCommandIdRange(IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
381 IDC_CONTENT_CONTEXT_CUSTOM_LAST);
383 set_content_type(ContextMenuContentTypeFactory::Create(
384 source_web_contents_, params));
387 RenderViewContextMenu::~RenderViewContextMenu() {
390 // Menu construction functions -------------------------------------------------
392 #if defined(ENABLE_EXTENSIONS)
393 // static
394 bool RenderViewContextMenu::ExtensionContextAndPatternMatch(
395 const content::ContextMenuParams& params,
396 const MenuItem::ContextList& contexts,
397 const extensions::URLPatternSet& target_url_patterns) {
398 const bool has_link = !params.link_url.is_empty();
399 const bool has_selection = !params.selection_text.empty();
400 const bool in_frame = !params.frame_url.is_empty();
402 if (contexts.Contains(MenuItem::ALL) ||
403 (has_selection && contexts.Contains(MenuItem::SELECTION)) ||
404 (params.is_editable && contexts.Contains(MenuItem::EDITABLE)) ||
405 (in_frame && contexts.Contains(MenuItem::FRAME)))
406 return true;
408 if (has_link && contexts.Contains(MenuItem::LINK) &&
409 ExtensionPatternMatch(target_url_patterns, params.link_url))
410 return true;
412 switch (params.media_type) {
413 case WebContextMenuData::MediaTypeImage:
414 if (contexts.Contains(MenuItem::IMAGE) &&
415 ExtensionPatternMatch(target_url_patterns, params.src_url))
416 return true;
417 break;
419 case WebContextMenuData::MediaTypeVideo:
420 if (contexts.Contains(MenuItem::VIDEO) &&
421 ExtensionPatternMatch(target_url_patterns, params.src_url))
422 return true;
423 break;
425 case WebContextMenuData::MediaTypeAudio:
426 if (contexts.Contains(MenuItem::AUDIO) &&
427 ExtensionPatternMatch(target_url_patterns, params.src_url))
428 return true;
429 break;
431 default:
432 break;
435 // PAGE is the least specific context, so we only examine that if none of the
436 // other contexts apply (except for FRAME, which is included in PAGE for
437 // backwards compatibility).
438 if (!has_link && !has_selection && !params.is_editable &&
439 params.media_type == WebContextMenuData::MediaTypeNone &&
440 contexts.Contains(MenuItem::PAGE))
441 return true;
443 return false;
446 // static
447 bool RenderViewContextMenu::MenuItemMatchesParams(
448 const content::ContextMenuParams& params,
449 const extensions::MenuItem* item) {
450 bool match = ExtensionContextAndPatternMatch(params, item->contexts(),
451 item->target_url_patterns());
452 if (!match)
453 return false;
455 const GURL& document_url = GetDocumentURL(params);
456 return ExtensionPatternMatch(item->document_url_patterns(), document_url);
459 void RenderViewContextMenu::AppendAllExtensionItems() {
460 extension_items_.Clear();
461 ExtensionService* service =
462 extensions::ExtensionSystem::Get(browser_context_)->extension_service();
463 if (!service)
464 return; // In unit-tests, we may not have an ExtensionService.
466 MenuManager* menu_manager = MenuManager::Get(browser_context_);
467 if (!menu_manager)
468 return;
470 base::string16 printable_selection_text = PrintableSelectionText();
471 EscapeAmpersands(&printable_selection_text);
473 // Get a list of extension id's that have context menu items, and sort by the
474 // top level context menu title of the extension.
475 std::set<MenuItem::ExtensionKey> ids = menu_manager->ExtensionIds();
476 std::vector<base::string16> sorted_menu_titles;
477 std::map<base::string16, std::vector<const Extension*>>
478 title_to_extensions_map;
479 for (std::set<MenuItem::ExtensionKey>::iterator iter = ids.begin();
480 iter != ids.end();
481 ++iter) {
482 const Extension* extension =
483 service->GetExtensionById(iter->extension_id, false);
484 // Platform apps have their context menus created directly in
485 // AppendPlatformAppItems.
486 if (extension && !extension->is_platform_app()) {
487 base::string16 menu_title = extension_items_.GetTopLevelContextMenuTitle(
488 *iter, printable_selection_text);
489 title_to_extensions_map[menu_title].push_back(extension);
490 sorted_menu_titles.push_back(menu_title);
493 if (sorted_menu_titles.empty())
494 return;
496 const std::string app_locale = g_browser_process->GetApplicationLocale();
497 l10n_util::SortStrings16(app_locale, &sorted_menu_titles);
498 sorted_menu_titles.erase(
499 std::unique(sorted_menu_titles.begin(), sorted_menu_titles.end()),
500 sorted_menu_titles.end());
502 int index = 0;
503 for (size_t i = 0; i < sorted_menu_titles.size(); ++i) {
504 std::vector<const Extension*>& extensions =
505 title_to_extensions_map[sorted_menu_titles[i]];
506 for (const auto& extension : extensions) {
507 MenuItem::ExtensionKey extension_key(extension->id());
508 extension_items_.AppendExtensionItems(extension_key,
509 printable_selection_text, &index,
510 false); // is_action_menu
515 void RenderViewContextMenu::AppendCurrentExtensionItems() {
516 // Avoid appending extension related items when |extension| is null.
517 // For Panel, this happens when the panel is navigated to a url outside of the
518 // extension's package.
519 const Extension* extension = GetExtension();
520 if (extension) {
521 // Only add extension items from this extension.
522 int index = 0;
523 MenuItem::ExtensionKey key(
524 extension->id(),
525 extensions::WebViewGuest::GetViewInstanceId(source_web_contents_));
526 extension_items_.AppendExtensionItems(key,
527 PrintableSelectionText(),
528 &index,
529 false); // is_action_menu
532 #endif // defined(ENABLE_EXTENSIONS)
534 void RenderViewContextMenu::InitMenu() {
535 RenderViewContextMenuBase::InitMenu();
537 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PAGE))
538 AppendPageItems();
540 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_FRAME)) {
541 // Merge in frame items with page items if we clicked within a frame that
542 // needs them.
543 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
544 AppendFrameItems();
547 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_LINK)) {
548 AppendLinkItems();
549 if (params_.media_type != WebContextMenuData::MediaTypeNone)
550 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
553 if (content_type_->SupportsGroup(
554 ContextMenuContentType::ITEM_GROUP_MEDIA_IMAGE)) {
555 AppendImageItems();
558 if (content_type_->SupportsGroup(
559 ContextMenuContentType::ITEM_GROUP_SEARCHWEBFORIMAGE)) {
560 AppendSearchWebForImageItems();
563 if (content_type_->SupportsGroup(
564 ContextMenuContentType::ITEM_GROUP_MEDIA_VIDEO)) {
565 AppendVideoItems();
568 if (content_type_->SupportsGroup(
569 ContextMenuContentType::ITEM_GROUP_MEDIA_AUDIO)) {
570 AppendAudioItems();
573 if (content_type_->SupportsGroup(
574 ContextMenuContentType::ITEM_GROUP_MEDIA_CANVAS)) {
575 AppendCanvasItems();
578 if (content_type_->SupportsGroup(
579 ContextMenuContentType::ITEM_GROUP_MEDIA_PLUGIN)) {
580 AppendPluginItems();
583 // ITEM_GROUP_MEDIA_FILE has no specific items.
585 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_EDITABLE))
586 AppendEditableItems();
588 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_COPY)) {
589 DCHECK(!content_type_->SupportsGroup(
590 ContextMenuContentType::ITEM_GROUP_EDITABLE));
591 AppendCopyItem();
594 if (content_type_->SupportsGroup(
595 ContextMenuContentType::ITEM_GROUP_SEARCH_PROVIDER)) {
596 AppendSearchProvider();
599 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT))
600 AppendPrintItem();
602 if (content_type_->SupportsGroup(
603 ContextMenuContentType::ITEM_GROUP_MEDIA_PLUGIN)) {
604 AppendRotationItems();
607 if (content_type_->SupportsGroup(
608 ContextMenuContentType::ITEM_GROUP_ALL_EXTENSION)) {
609 DCHECK(!content_type_->SupportsGroup(
610 ContextMenuContentType::ITEM_GROUP_CURRENT_EXTENSION));
611 AppendAllExtensionItems();
614 if (content_type_->SupportsGroup(
615 ContextMenuContentType::ITEM_GROUP_CURRENT_EXTENSION)) {
616 DCHECK(!content_type_->SupportsGroup(
617 ContextMenuContentType::ITEM_GROUP_ALL_EXTENSION));
618 AppendCurrentExtensionItems();
621 if (content_type_->SupportsGroup(
622 ContextMenuContentType::ITEM_GROUP_DEVELOPER)) {
623 AppendDeveloperItems();
626 if (content_type_->SupportsGroup(
627 ContextMenuContentType::ITEM_GROUP_DEVTOOLS_UNPACKED_EXT)) {
628 AppendDevtoolsForUnpackedExtensions();
631 if (content_type_->SupportsGroup(
632 ContextMenuContentType::ITEM_GROUP_PRINT_PREVIEW)) {
633 AppendPrintPreviewItems();
636 if (content_type_->SupportsGroup(
637 ContextMenuContentType::ITEM_GROUP_PASSWORD)) {
638 AppendPasswordItems();
642 Profile* RenderViewContextMenu::GetProfile() {
643 return Profile::FromBrowserContext(browser_context_);
646 void RenderViewContextMenu::RecordUsedItem(int id) {
647 int enum_id = FindUMAEnumValueForCommand(id);
648 if (enum_id != -1) {
649 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
650 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Used", enum_id,
651 kUmaEnumToControlId[kMappingSize - 1].enum_id);
652 } else {
653 NOTREACHED() << "Update kUmaEnumToControlId. Unhanded IDC: " << id;
657 void RenderViewContextMenu::RecordShownItem(int id) {
658 int enum_id = FindUMAEnumValueForCommand(id);
659 if (enum_id != -1) {
660 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
661 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Shown", enum_id,
662 kUmaEnumToControlId[kMappingSize - 1].enum_id);
663 } else {
664 // Just warning here. It's harder to maintain list of all possibly
665 // visible items than executable items.
666 DLOG(ERROR) << "Update kUmaEnumToControlId. Unhanded IDC: " << id;
670 #if defined(ENABLE_PLUGINS)
671 void RenderViewContextMenu::HandleAuthorizeAllPlugins() {
672 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins(
673 source_web_contents_, false, std::string());
675 #endif
677 void RenderViewContextMenu::AppendPrintPreviewItems() {
678 #if defined(ENABLE_PRINT_PREVIEW)
679 if (!print_preview_menu_observer_.get()) {
680 print_preview_menu_observer_.reset(
681 new PrintPreviewContextMenuObserver(source_web_contents_));
684 observers_.AddObserver(print_preview_menu_observer_.get());
685 #endif
688 const Extension* RenderViewContextMenu::GetExtension() const {
689 return extensions::ProcessManager::Get(browser_context_)
690 ->GetExtensionForWebContents(source_web_contents_);
693 void RenderViewContextMenu::AppendDeveloperItems() {
694 // Show Inspect Element in DevTools itself only in case of the debug
695 // devtools build.
696 bool show_developer_items = !IsDevToolsURL(params_.page_url);
698 #if defined(DEBUG_DEVTOOLS)
699 show_developer_items = true;
700 #endif
702 if (!show_developer_items)
703 return;
705 // In the DevTools popup menu, "developer items" is normally the only
706 // section, so omit the separator there.
707 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
708 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTELEMENT,
709 IDS_CONTENT_CONTEXT_INSPECTELEMENT);
712 void RenderViewContextMenu::AppendDevtoolsForUnpackedExtensions() {
713 // Add a separator if there are any items already in the menu.
714 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
716 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP,
717 IDS_CONTENT_CONTEXT_RELOAD_PACKAGED_APP);
718 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP,
719 IDS_CONTENT_CONTEXT_RESTART_APP);
720 AppendDeveloperItems();
721 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE,
722 IDS_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE);
725 void RenderViewContextMenu::AppendLinkItems() {
726 if (!params_.link_url.is_empty()) {
727 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB,
728 IDS_CONTENT_CONTEXT_OPENLINKNEWTAB);
729 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW,
730 IDS_CONTENT_CONTEXT_OPENLINKNEWWINDOW);
731 if (params_.link_url.is_valid()) {
732 AppendProtocolHandlerSubMenu();
735 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD,
736 IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD);
737 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVELINKAS,
738 IDS_CONTENT_CONTEXT_SAVELINKAS);
741 menu_model_.AddItemWithStringId(
742 IDC_CONTENT_CONTEXT_COPYLINKLOCATION,
743 params_.link_url.SchemeIs(url::kMailToScheme) ?
744 IDS_CONTENT_CONTEXT_COPYEMAILADDRESS :
745 IDS_CONTENT_CONTEXT_COPYLINKLOCATION);
748 void RenderViewContextMenu::AppendImageItems() {
749 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS,
750 IDS_CONTENT_CONTEXT_SAVEIMAGEAS);
751 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGELOCATION,
752 IDS_CONTENT_CONTEXT_COPYIMAGELOCATION);
753 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
754 IDS_CONTENT_CONTEXT_COPYIMAGE);
755 std::map<std::string, std::string>::const_iterator it =
756 params_.properties.find(data_reduction_proxy::chrome_proxy_header());
757 if (it != params_.properties.end() && it->second ==
758 data_reduction_proxy::chrome_proxy_lo_fi_directive()) {
759 menu_model_.AddItemWithStringId(
760 IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE,
761 IDS_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE);
763 DataReductionProxyChromeSettings* settings =
764 DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
765 browser_context_);
766 if (settings && settings->CanUseDataReductionProxy(params_.src_url)) {
767 menu_model_.AddItemWithStringId(
768 IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB,
769 IDS_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB);
770 } else {
771 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB,
772 IDS_CONTENT_CONTEXT_OPENIMAGENEWTAB);
776 void RenderViewContextMenu::AppendSearchWebForImageItems() {
777 TemplateURLService* service =
778 TemplateURLServiceFactory::GetForProfile(GetProfile());
779 const TemplateURL* const default_provider =
780 service->GetDefaultSearchProvider();
781 if (params_.has_image_contents && default_provider &&
782 !default_provider->image_url().empty() &&
783 default_provider->image_url_ref().IsValid(service->search_terms_data())) {
784 menu_model_.AddItem(
785 IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE,
786 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFORIMAGE,
787 default_provider->short_name()));
791 void RenderViewContextMenu::AppendAudioItems() {
792 AppendMediaItems();
793 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
794 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
795 IDS_CONTENT_CONTEXT_SAVEAUDIOAS);
796 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
797 IDS_CONTENT_CONTEXT_COPYAUDIOLOCATION);
798 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
799 IDS_CONTENT_CONTEXT_OPENAUDIONEWTAB);
802 void RenderViewContextMenu::AppendCanvasItems() {
803 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS,
804 IDS_CONTENT_CONTEXT_SAVEIMAGEAS);
805 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
806 IDS_CONTENT_CONTEXT_COPYIMAGE);
809 void RenderViewContextMenu::AppendVideoItems() {
810 AppendMediaItems();
811 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
812 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
813 IDS_CONTENT_CONTEXT_SAVEVIDEOAS);
814 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
815 IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION);
816 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
817 IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB);
820 void RenderViewContextMenu::AppendMediaItems() {
821 int media_flags = params_.media_flags;
823 menu_model_.AddItemWithStringId(
824 IDC_CONTENT_CONTEXT_PLAYPAUSE,
825 media_flags & WebContextMenuData::MediaPaused ?
826 IDS_CONTENT_CONTEXT_PLAY :
827 IDS_CONTENT_CONTEXT_PAUSE);
829 menu_model_.AddItemWithStringId(
830 IDC_CONTENT_CONTEXT_MUTE,
831 media_flags & WebContextMenuData::MediaMuted ?
832 IDS_CONTENT_CONTEXT_UNMUTE :
833 IDS_CONTENT_CONTEXT_MUTE);
835 menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_LOOP,
836 IDS_CONTENT_CONTEXT_LOOP);
837 menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_CONTROLS,
838 IDS_CONTENT_CONTEXT_CONTROLS);
841 void RenderViewContextMenu::AppendPluginItems() {
842 if (params_.page_url == params_.src_url ||
843 guest_view::GuestViewBase::IsGuest(source_web_contents_)) {
844 // Full page plugin, so show page menu items.
845 if (params_.link_url.is_empty() && params_.selection_text.empty())
846 AppendPageItems();
847 } else {
848 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
849 IDS_CONTENT_CONTEXT_SAVEPAGEAS);
850 // The "Print" menu item should always be included for plugins. If
851 // content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT)
852 // is true the item will be added inside AppendPrintItem(). Otherwise we
853 // add "Print" here.
854 if (!content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT))
855 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
859 void RenderViewContextMenu::AppendPageItems() {
860 menu_model_.AddItemWithStringId(IDC_BACK, IDS_CONTENT_CONTEXT_BACK);
861 menu_model_.AddItemWithStringId(IDC_FORWARD, IDS_CONTENT_CONTEXT_FORWARD);
862 menu_model_.AddItemWithStringId(IDC_RELOAD, IDS_CONTENT_CONTEXT_RELOAD);
863 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
864 menu_model_.AddItemWithStringId(IDC_SAVE_PAGE,
865 IDS_CONTENT_CONTEXT_SAVEPAGEAS);
866 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
868 if (TranslateService::IsTranslatableURL(params_.page_url)) {
869 std::string locale = g_browser_process->GetApplicationLocale();
870 locale = translate::TranslateDownloadManager::GetLanguageCode(locale);
871 base::string16 language =
872 l10n_util::GetDisplayNameForLocale(locale, locale, true);
873 menu_model_.AddItem(
874 IDC_CONTENT_CONTEXT_TRANSLATE,
875 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_TRANSLATE, language));
878 menu_model_.AddItemWithStringId(IDC_VIEW_SOURCE,
879 IDS_CONTENT_CONTEXT_VIEWPAGESOURCE);
880 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWPAGEINFO,
881 IDS_CONTENT_CONTEXT_VIEWPAGEINFO);
884 void RenderViewContextMenu::AppendFrameItems() {
885 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOADFRAME,
886 IDS_CONTENT_CONTEXT_RELOADFRAME);
887 // These two menu items have yet to be implemented.
888 // http://code.google.com/p/chromium/issues/detail?id=11827
889 // IDS_CONTENT_CONTEXT_SAVEFRAMEAS
890 // IDS_CONTENT_CONTEXT_PRINTFRAME
891 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE,
892 IDS_CONTENT_CONTEXT_VIEWFRAMESOURCE);
893 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMEINFO,
894 IDS_CONTENT_CONTEXT_VIEWFRAMEINFO);
897 void RenderViewContextMenu::AppendCopyItem() {
898 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
899 IDS_CONTENT_CONTEXT_COPY);
902 void RenderViewContextMenu::AppendPrintItem() {
903 if (GetPrefs(browser_context_)->GetBoolean(prefs::kPrintingEnabled) &&
904 (params_.media_type == WebContextMenuData::MediaTypeNone ||
905 params_.media_flags & WebContextMenuData::MediaCanPrint)) {
906 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
910 void RenderViewContextMenu::AppendRotationItems() {
911 if (params_.media_flags & WebContextMenuData::MediaCanRotate) {
912 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
913 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECW,
914 IDS_CONTENT_CONTEXT_ROTATECW);
915 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECCW,
916 IDS_CONTENT_CONTEXT_ROTATECCW);
920 void RenderViewContextMenu::AppendSearchProvider() {
921 DCHECK(browser_context_);
923 base::TrimWhitespace(params_.selection_text, base::TRIM_ALL,
924 &params_.selection_text);
925 if (params_.selection_text.empty())
926 return;
928 base::ReplaceChars(params_.selection_text, AutocompleteMatch::kInvalidChars,
929 base::ASCIIToUTF16(" "), &params_.selection_text);
931 AutocompleteMatch match;
932 AutocompleteClassifierFactory::GetForProfile(GetProfile())->Classify(
933 params_.selection_text,
934 false,
935 false,
936 metrics::OmniboxEventProto::INVALID_SPEC,
937 &match,
938 NULL);
939 selection_navigation_url_ = match.destination_url;
940 if (!selection_navigation_url_.is_valid())
941 return;
943 base::string16 printable_selection_text = PrintableSelectionText();
944 EscapeAmpersands(&printable_selection_text);
946 if (AutocompleteMatch::IsSearchType(match.type)) {
947 const TemplateURL* const default_provider =
948 TemplateURLServiceFactory::GetForProfile(GetProfile())
949 ->GetDefaultSearchProvider();
950 if (!default_provider)
951 return;
952 menu_model_.AddItem(
953 IDC_CONTENT_CONTEXT_SEARCHWEBFOR,
954 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFOR,
955 default_provider->short_name(),
956 printable_selection_text));
957 } else {
958 if ((selection_navigation_url_ != params_.link_url) &&
959 ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme(
960 selection_navigation_url_.scheme())) {
961 menu_model_.AddItem(
962 IDC_CONTENT_CONTEXT_GOTOURL,
963 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_GOTOURL,
964 printable_selection_text));
969 void RenderViewContextMenu::AppendEditableItems() {
970 const bool use_spellcheck_and_search = !chrome::IsRunningInForcedAppMode();
972 if (use_spellcheck_and_search)
973 AppendSpellingSuggestionsSubMenu();
975 if (!IsDevToolsURL(params_.page_url)) {
976 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_UNDO,
977 IDS_CONTENT_CONTEXT_UNDO);
978 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_REDO,
979 IDS_CONTENT_CONTEXT_REDO);
980 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
983 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_CUT,
984 IDS_CONTENT_CONTEXT_CUT);
985 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
986 IDS_CONTENT_CONTEXT_COPY);
987 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE,
988 IDS_CONTENT_CONTEXT_PASTE);
989 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE,
990 IDS_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE);
991 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_DELETE,
992 IDS_CONTENT_CONTEXT_DELETE);
993 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
995 if (use_spellcheck_and_search && !params_.keyword_url.is_empty()) {
996 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ADDSEARCHENGINE,
997 IDS_CONTENT_CONTEXT_ADDSEARCHENGINE);
998 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1001 if (use_spellcheck_and_search)
1002 AppendSpellcheckOptionsSubMenu();
1003 AppendPlatformEditableItems();
1005 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1006 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SELECTALL,
1007 IDS_CONTENT_CONTEXT_SELECTALL);
1010 void RenderViewContextMenu::AppendSpellingSuggestionsSubMenu() {
1011 if (!spelling_menu_observer_.get())
1012 spelling_menu_observer_.reset(new SpellingMenuObserver(this));
1013 observers_.AddObserver(spelling_menu_observer_.get());
1014 spelling_menu_observer_->InitMenu(params_);
1017 void RenderViewContextMenu::AppendSpellcheckOptionsSubMenu() {
1018 if (!spellchecker_submenu_observer_.get()) {
1019 spellchecker_submenu_observer_.reset(new SpellCheckerSubMenuObserver(
1020 this, this, kSpellcheckRadioGroup));
1022 spellchecker_submenu_observer_->InitMenu(params_);
1023 observers_.AddObserver(spellchecker_submenu_observer_.get());
1026 void RenderViewContextMenu::AppendProtocolHandlerSubMenu() {
1027 const ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1028 GetHandlersForLinkUrl();
1029 if (handlers.empty())
1030 return;
1031 size_t max = IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST -
1032 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
1033 for (size_t i = 0; i < handlers.size() && i <= max; i++) {
1034 protocol_handler_submenu_model_.AddItem(
1035 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST + i,
1036 base::UTF8ToUTF16(handlers[i].url().host()));
1038 protocol_handler_submenu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1039 protocol_handler_submenu_model_.AddItem(
1040 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS,
1041 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH_CONFIGURE));
1043 menu_model_.AddSubMenu(
1044 IDC_CONTENT_CONTEXT_OPENLINKWITH,
1045 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH),
1046 &protocol_handler_submenu_model_);
1049 void RenderViewContextMenu::AppendPasswordItems() {
1050 if (!password_manager::ForceSavingExperimentEnabled())
1051 return;
1053 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1054 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD,
1055 IDS_CONTENT_CONTEXT_FORCESAVEPASSWORD);
1058 // Menu delegate functions -----------------------------------------------------
1060 bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
1062 bool enabled = false;
1063 if (RenderViewContextMenuBase::IsCommandIdKnown(id, &enabled))
1064 return enabled;
1067 CoreTabHelper* core_tab_helper =
1068 CoreTabHelper::FromWebContents(source_web_contents_);
1069 int content_restrictions = 0;
1070 if (core_tab_helper)
1071 content_restrictions = core_tab_helper->content_restrictions();
1072 if (id == IDC_PRINT && (content_restrictions & CONTENT_RESTRICTION_PRINT))
1073 return false;
1075 if (id == IDC_SAVE_PAGE &&
1076 (content_restrictions & CONTENT_RESTRICTION_SAVE)) {
1077 return false;
1080 PrefService* prefs = GetPrefs(browser_context_);
1082 // Allow Spell Check language items on sub menu for text area context menu.
1083 if ((id >= IDC_SPELLCHECK_LANGUAGES_FIRST) &&
1084 (id < IDC_SPELLCHECK_LANGUAGES_LAST)) {
1085 return prefs->GetBoolean(prefs::kEnableContinuousSpellcheck);
1088 // Extension items.
1089 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
1090 return extension_items_.IsCommandIdEnabled(id);
1092 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
1093 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
1094 return true;
1097 IncognitoModePrefs::Availability incognito_avail =
1098 IncognitoModePrefs::GetAvailability(prefs);
1099 switch (id) {
1100 case IDC_BACK:
1101 return embedder_web_contents_->GetController().CanGoBack();
1103 case IDC_FORWARD:
1104 return embedder_web_contents_->GetController().CanGoForward();
1106 case IDC_RELOAD: {
1107 CoreTabHelper* core_tab_helper =
1108 CoreTabHelper::FromWebContents(embedder_web_contents_);
1109 if (!core_tab_helper)
1110 return false;
1112 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
1113 return !core_delegate ||
1114 core_delegate->CanReloadContents(embedder_web_contents_);
1117 case IDC_VIEW_SOURCE:
1118 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
1119 return embedder_web_contents_->GetController().CanViewSource();
1121 case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
1122 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE:
1123 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP:
1124 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP:
1125 return IsDevCommandEnabled(id);
1127 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO:
1128 if (embedder_web_contents_->GetController().GetVisibleEntry() == NULL)
1129 return false;
1130 // Disabled if no browser is associated (e.g. desktop notifications).
1131 if (chrome::FindBrowserWithWebContents(embedder_web_contents_) == NULL)
1132 return false;
1133 return true;
1135 case IDC_CONTENT_CONTEXT_TRANSLATE: {
1136 ChromeTranslateClient* chrome_translate_client =
1137 ChromeTranslateClient::FromWebContents(embedder_web_contents_);
1138 if (!chrome_translate_client)
1139 return false;
1140 std::string original_lang =
1141 chrome_translate_client->GetLanguageState().original_language();
1142 std::string target_lang = g_browser_process->GetApplicationLocale();
1143 target_lang =
1144 translate::TranslateDownloadManager::GetLanguageCode(target_lang);
1145 // Note that we intentionally enable the menu even if the original and
1146 // target languages are identical. This is to give a way to user to
1147 // translate a page that might contains text fragments in a different
1148 // language.
1149 return ((params_.edit_flags & WebContextMenuData::CanTranslate) != 0) &&
1150 !original_lang.empty() && // Did we receive the page language yet?
1151 !chrome_translate_client->GetLanguageState().IsPageTranslated() &&
1152 !embedder_web_contents_->GetInterstitialPage() &&
1153 // There are some application locales which can't be used as a
1154 // target language for translation.
1155 translate::TranslateDownloadManager::IsSupportedLanguage(
1156 target_lang) &&
1157 // Disable on the Instant Extended NTP.
1158 !chrome::IsInstantNTP(embedder_web_contents_);
1161 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB:
1162 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
1163 return params_.link_url.is_valid();
1165 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
1166 return params_.unfiltered_link_url.is_valid();
1168 case IDC_CONTENT_CONTEXT_SAVELINKAS: {
1169 PrefService* local_state = g_browser_process->local_state();
1170 DCHECK(local_state);
1171 // Test if file-selection dialogs are forbidden by policy.
1172 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1173 return false;
1175 return params_.link_url.is_valid() &&
1176 ProfileIOData::IsHandledProtocol(params_.link_url.scheme());
1179 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: {
1180 PrefService* local_state = g_browser_process->local_state();
1181 DCHECK(local_state);
1182 // Test if file-selection dialogs are forbidden by policy.
1183 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1184 return false;
1186 return params_.has_image_contents;
1189 // The images shown in the most visited thumbnails can't be opened or
1190 // searched for conventionally.
1191 case IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB:
1192 case IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE:
1193 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
1194 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
1195 return params_.src_url.is_valid() &&
1196 (params_.src_url.scheme() != content::kChromeUIScheme);
1198 case IDC_CONTENT_CONTEXT_COPYIMAGE:
1199 return params_.has_image_contents;
1201 // Media control commands should all be disabled if the player is in an
1202 // error state.
1203 case IDC_CONTENT_CONTEXT_PLAYPAUSE:
1204 case IDC_CONTENT_CONTEXT_LOOP:
1205 return (params_.media_flags &
1206 WebContextMenuData::MediaInError) == 0;
1208 // Mute and unmute should also be disabled if the player has no audio.
1209 case IDC_CONTENT_CONTEXT_MUTE:
1210 return (params_.media_flags &
1211 WebContextMenuData::MediaHasAudio) != 0 &&
1212 (params_.media_flags &
1213 WebContextMenuData::MediaInError) == 0;
1215 case IDC_CONTENT_CONTEXT_CONTROLS:
1216 return (params_.media_flags &
1217 WebContextMenuData::MediaCanToggleControls) != 0;
1219 case IDC_CONTENT_CONTEXT_ROTATECW:
1220 case IDC_CONTENT_CONTEXT_ROTATECCW:
1221 return
1222 (params_.media_flags & WebContextMenuData::MediaCanRotate) != 0;
1224 case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
1225 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
1226 return params_.src_url.is_valid();
1228 case IDC_CONTENT_CONTEXT_SAVEAVAS: {
1229 PrefService* local_state = g_browser_process->local_state();
1230 DCHECK(local_state);
1231 // Test if file-selection dialogs are forbidden by policy.
1232 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1233 return false;
1235 const GURL& url = params_.src_url;
1236 bool can_save =
1237 (params_.media_flags & WebContextMenuData::MediaCanSave) &&
1238 url.is_valid() && ProfileIOData::IsHandledProtocol(url.scheme());
1239 #if defined(ENABLE_PRINT_PREVIEW)
1240 // Do not save the preview PDF on the print preview page.
1241 can_save = can_save &&
1242 !(printing::PrintPreviewDialogController::IsPrintPreviewURL(url));
1243 #endif
1244 return can_save;
1247 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
1248 // Currently, a media element can be opened in a new tab iff it can
1249 // be saved. So rather than duplicating the MediaCanSave flag, we rely
1250 // on that here.
1251 return !!(params_.media_flags & WebContextMenuData::MediaCanSave);
1253 case IDC_SAVE_PAGE: {
1254 CoreTabHelper* core_tab_helper =
1255 CoreTabHelper::FromWebContents(embedder_web_contents_);
1256 if (!core_tab_helper)
1257 return false;
1259 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
1260 if (core_delegate &&
1261 !core_delegate->CanSaveContents(embedder_web_contents_))
1262 return false;
1264 PrefService* local_state = g_browser_process->local_state();
1265 DCHECK(local_state);
1266 // Test if file-selection dialogs are forbidden by policy.
1267 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1268 return false;
1270 // We save the last committed entry (which the user is looking at), as
1271 // opposed to any pending URL that hasn't committed yet.
1272 NavigationEntry* entry =
1273 embedder_web_contents_->GetController().GetLastCommittedEntry();
1274 return content::IsSavableURL(entry ? entry->GetURL() : GURL());
1277 case IDC_CONTENT_CONTEXT_RELOADFRAME:
1278 return params_.frame_url.is_valid();
1280 case IDC_CONTENT_CONTEXT_UNDO:
1281 return !!(params_.edit_flags & WebContextMenuData::CanUndo);
1283 case IDC_CONTENT_CONTEXT_REDO:
1284 return !!(params_.edit_flags & WebContextMenuData::CanRedo);
1286 case IDC_CONTENT_CONTEXT_CUT:
1287 return !!(params_.edit_flags & WebContextMenuData::CanCut);
1289 case IDC_CONTENT_CONTEXT_COPY:
1290 return !!(params_.edit_flags & WebContextMenuData::CanCopy);
1292 case IDC_CONTENT_CONTEXT_PASTE: {
1293 if (!(params_.edit_flags & WebContextMenuData::CanPaste))
1294 return false;
1296 std::vector<base::string16> types;
1297 bool ignore;
1298 ui::Clipboard::GetForCurrentThread()->ReadAvailableTypes(
1299 ui::CLIPBOARD_TYPE_COPY_PASTE, &types, &ignore);
1300 return !types.empty();
1303 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE: {
1304 if (!(params_.edit_flags & WebContextMenuData::CanPaste))
1305 return false;
1307 return ui::Clipboard::GetForCurrentThread()->IsFormatAvailable(
1308 ui::Clipboard::GetPlainTextFormatType(),
1309 ui::CLIPBOARD_TYPE_COPY_PASTE);
1312 case IDC_CONTENT_CONTEXT_DELETE:
1313 return !!(params_.edit_flags & WebContextMenuData::CanDelete);
1315 case IDC_CONTENT_CONTEXT_SELECTALL:
1316 return !!(params_.edit_flags & WebContextMenuData::CanSelectAll);
1318 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
1319 return !browser_context_->IsOffTheRecord() &&
1320 params_.link_url.is_valid() &&
1321 incognito_avail != IncognitoModePrefs::DISABLED;
1323 case IDC_PRINT:
1324 return prefs->GetBoolean(prefs::kPrintingEnabled) &&
1325 (params_.media_type == WebContextMenuData::MediaTypeNone ||
1326 params_.media_flags & WebContextMenuData::MediaCanPrint);
1328 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
1329 case IDC_CONTENT_CONTEXT_GOTOURL:
1330 case IDC_SPELLPANEL_TOGGLE:
1331 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS:
1332 return true;
1333 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO:
1334 // Disabled if no browser is associated (e.g. desktop notifications).
1335 if (chrome::FindBrowserWithWebContents(source_web_contents_) == NULL)
1336 return false;
1337 return true;
1339 case IDC_CHECK_SPELLING_WHILE_TYPING:
1340 return prefs->GetBoolean(prefs::kEnableContinuousSpellcheck);
1342 #if !defined(OS_MACOSX) && defined(OS_POSIX)
1343 // TODO(suzhe): this should not be enabled for password fields.
1344 case IDC_INPUT_METHODS_MENU:
1345 return true;
1346 #endif
1348 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE:
1349 return !params_.keyword_url.is_empty();
1351 case IDC_SPELLCHECK_MENU:
1352 return true;
1354 case IDC_CONTENT_CONTEXT_OPENLINKWITH:
1355 return true;
1357 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS:
1358 return true;
1360 case IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD:
1361 return true;
1363 default:
1364 NOTREACHED();
1365 return false;
1369 bool RenderViewContextMenu::IsCommandIdChecked(int id) const {
1370 if (RenderViewContextMenuBase::IsCommandIdChecked(id))
1371 return true;
1373 // See if the video is set to looping.
1374 if (id == IDC_CONTENT_CONTEXT_LOOP)
1375 return (params_.media_flags & WebContextMenuData::MediaLoop) != 0;
1377 if (id == IDC_CONTENT_CONTEXT_CONTROLS)
1378 return (params_.media_flags & WebContextMenuData::MediaControls) != 0;
1380 // Extension items.
1381 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
1382 return extension_items_.IsCommandIdChecked(id);
1384 return false;
1387 void RenderViewContextMenu::ExecuteCommand(int id, int event_flags) {
1388 RenderViewContextMenuBase::ExecuteCommand(id, event_flags);
1389 if (command_executed_)
1390 return;
1391 command_executed_ = true;
1393 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1395 // Process extension menu items.
1396 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id)) {
1397 extension_items_.ExecuteCommand(id, source_web_contents_, params_);
1398 return;
1401 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
1402 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
1403 ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1404 GetHandlersForLinkUrl();
1405 if (handlers.empty())
1406 return;
1408 content::RecordAction(
1409 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Open"));
1410 int handlerIndex = id - IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
1411 WindowOpenDisposition disposition =
1412 ForceNewTabDispositionFromEventFlags(event_flags);
1413 OpenURL(handlers[handlerIndex].TranslateUrl(params_.link_url),
1414 GetDocumentURL(params_),
1415 disposition,
1416 ui::PAGE_TRANSITION_LINK);
1417 return;
1420 switch (id) {
1421 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB: {
1422 Browser* browser =
1423 chrome::FindBrowserWithWebContents(source_web_contents_);
1424 OpenURL(params_.link_url,
1425 GetDocumentURL(params_),
1426 !browser || browser->is_app() ?
1427 NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB,
1428 ui::PAGE_TRANSITION_LINK);
1429 break;
1431 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
1432 OpenURL(params_.link_url,
1433 GetDocumentURL(params_),
1434 NEW_WINDOW,
1435 ui::PAGE_TRANSITION_LINK);
1436 break;
1438 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
1439 OpenURL(params_.link_url, GURL(), OFF_THE_RECORD,
1440 ui::PAGE_TRANSITION_LINK);
1441 break;
1443 case IDC_CONTENT_CONTEXT_SAVELINKAS: {
1444 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
1445 const GURL& url = params_.link_url;
1446 content::Referrer referrer = CreateSaveAsReferrer(url, params_);
1447 DownloadManager* dlm =
1448 BrowserContext::GetDownloadManager(browser_context_);
1449 scoped_ptr<DownloadUrlParameters> dl_params(
1450 DownloadUrlParameters::FromWebContents(source_web_contents_, url));
1451 dl_params->set_referrer(referrer);
1452 dl_params->set_referrer_encoding(params_.frame_charset);
1453 dl_params->set_suggested_name(params_.suggested_filename);
1454 dl_params->set_prompt(true);
1455 dlm->DownloadUrl(dl_params.Pass());
1456 break;
1459 case IDC_CONTENT_CONTEXT_SAVEAVAS:
1460 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: {
1461 bool is_large_data_url = params_.has_image_contents &&
1462 params_.src_url.is_empty();
1463 if (params_.media_type == WebContextMenuData::MediaTypeCanvas ||
1464 (params_.media_type == WebContextMenuData::MediaTypeImage &&
1465 is_large_data_url)) {
1466 source_web_contents_->GetRenderViewHost()->SaveImageAt(
1467 params_.x, params_.y);
1468 } else {
1469 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
1470 const GURL& url = params_.src_url;
1471 content::Referrer referrer = CreateSaveAsReferrer(url, params_);
1473 std::string headers;
1474 DataReductionProxyChromeSettings* settings =
1475 DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
1476 browser_context_);
1477 if (params_.media_type == WebContextMenuData::MediaTypeImage &&
1478 settings && settings->CanUseDataReductionProxy(params_.src_url)) {
1479 headers = data_reduction_proxy::kDataReductionPassThroughHeader;
1482 source_web_contents_->SaveFrameWithHeaders(url, referrer, headers);
1484 break;
1487 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
1488 WriteURLToClipboard(params_.unfiltered_link_url);
1489 break;
1491 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
1492 case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
1493 WriteURLToClipboard(params_.src_url);
1494 break;
1496 case IDC_CONTENT_CONTEXT_COPYIMAGE:
1497 CopyImageAt(params_.x, params_.y);
1498 break;
1500 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
1501 GetImageThumbnailForSearch();
1502 break;
1504 case IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB:
1505 OpenURLWithExtraHeaders(
1506 params_.src_url, GetDocumentURL(params_), NEW_BACKGROUND_TAB,
1507 ui::PAGE_TRANSITION_LINK,
1508 data_reduction_proxy::kDataReductionPassThroughHeader);
1509 break;
1511 case IDC_CONTENT_CONTEXT_SHOW_ORIGINAL_IMAGE:
1512 ShowOriginalImage();
1513 break;
1515 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
1516 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
1517 OpenURL(params_.src_url,
1518 GetDocumentURL(params_),
1519 NEW_BACKGROUND_TAB,
1520 ui::PAGE_TRANSITION_LINK);
1521 break;
1523 case IDC_CONTENT_CONTEXT_PLAYPAUSE: {
1524 bool play = !!(params_.media_flags & WebContextMenuData::MediaPaused);
1525 if (play) {
1526 content::RecordAction(UserMetricsAction("MediaContextMenu_Play"));
1527 } else {
1528 content::RecordAction(UserMetricsAction("MediaContextMenu_Pause"));
1530 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1531 WebMediaPlayerAction(
1532 WebMediaPlayerAction::Play, play));
1533 break;
1536 case IDC_CONTENT_CONTEXT_MUTE: {
1537 bool mute = !(params_.media_flags & WebContextMenuData::MediaMuted);
1538 if (mute) {
1539 content::RecordAction(UserMetricsAction("MediaContextMenu_Mute"));
1540 } else {
1541 content::RecordAction(UserMetricsAction("MediaContextMenu_Unmute"));
1543 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1544 WebMediaPlayerAction(
1545 WebMediaPlayerAction::Mute, mute));
1546 break;
1549 case IDC_CONTENT_CONTEXT_LOOP:
1550 content::RecordAction(UserMetricsAction("MediaContextMenu_Loop"));
1551 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1552 WebMediaPlayerAction(
1553 WebMediaPlayerAction::Loop,
1554 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_LOOP)));
1555 break;
1557 case IDC_CONTENT_CONTEXT_CONTROLS:
1558 content::RecordAction(UserMetricsAction("MediaContextMenu_Controls"));
1559 MediaPlayerActionAt(
1560 gfx::Point(params_.x, params_.y),
1561 WebMediaPlayerAction(
1562 WebMediaPlayerAction::Controls,
1563 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_CONTROLS)));
1564 break;
1566 case IDC_CONTENT_CONTEXT_ROTATECW:
1567 content::RecordAction(
1568 UserMetricsAction("PluginContextMenu_RotateClockwise"));
1569 PluginActionAt(
1570 gfx::Point(params_.x, params_.y),
1571 WebPluginAction(WebPluginAction::Rotate90Clockwise, true));
1572 break;
1574 case IDC_CONTENT_CONTEXT_ROTATECCW:
1575 content::RecordAction(
1576 UserMetricsAction("PluginContextMenu_RotateCounterclockwise"));
1577 PluginActionAt(
1578 gfx::Point(params_.x, params_.y),
1579 WebPluginAction(WebPluginAction::Rotate90Counterclockwise, true));
1580 break;
1582 case IDC_BACK:
1583 embedder_web_contents_->GetController().GoBack();
1584 break;
1586 case IDC_FORWARD:
1587 embedder_web_contents_->GetController().GoForward();
1588 break;
1590 case IDC_SAVE_PAGE:
1591 embedder_web_contents_->OnSavePage();
1592 break;
1594 case IDC_RELOAD:
1595 embedder_web_contents_->GetController().Reload(true);
1596 break;
1598 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP: {
1599 const Extension* platform_app = GetExtension();
1600 DCHECK(platform_app);
1601 DCHECK(platform_app->is_platform_app());
1603 extensions::ExtensionSystem::Get(browser_context_)
1604 ->extension_service()
1605 ->ReloadExtension(platform_app->id());
1606 break;
1609 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP: {
1610 const Extension* platform_app = GetExtension();
1611 DCHECK(platform_app);
1612 DCHECK(platform_app->is_platform_app());
1614 apps::AppLoadService::Get(GetProfile())
1615 ->RestartApplication(platform_app->id());
1616 break;
1619 case IDC_PRINT: {
1620 #if defined(ENABLE_PRINTING)
1621 if (params_.media_type != WebContextMenuData::MediaTypeNone) {
1622 if (render_frame_host) {
1623 render_frame_host->Send(new PrintMsg_PrintNodeUnderContextMenu(
1624 render_frame_host->GetRoutingID()));
1626 break;
1629 printing::StartPrint(
1630 source_web_contents_,
1631 GetPrefs(browser_context_)->GetBoolean(prefs::kPrintPreviewDisabled),
1632 !params_.selection_text.empty());
1633 #endif // ENABLE_PRINTING
1634 break;
1637 case IDC_VIEW_SOURCE:
1638 embedder_web_contents_->ViewSource();
1639 break;
1641 case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
1642 Inspect(params_.x, params_.y);
1643 break;
1645 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE: {
1646 const Extension* platform_app = GetExtension();
1647 DCHECK(platform_app);
1648 DCHECK(platform_app->is_platform_app());
1650 extensions::devtools_util::InspectBackgroundPage(platform_app,
1651 GetProfile());
1652 break;
1655 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO: {
1656 NavigationController* controller =
1657 &embedder_web_contents_->GetController();
1658 // Important to use GetVisibleEntry to match what's showing in the
1659 // omnibox. This may return null.
1660 NavigationEntry* nav_entry = controller->GetVisibleEntry();
1661 if (!nav_entry)
1662 return;
1663 Browser* browser =
1664 chrome::FindBrowserWithWebContents(embedder_web_contents_);
1665 chrome::ShowWebsiteSettings(browser, embedder_web_contents_,
1666 nav_entry->GetURL(), nav_entry->GetSSL());
1667 break;
1670 case IDC_CONTENT_CONTEXT_TRANSLATE: {
1671 // A translation might have been triggered by the time the menu got
1672 // selected, do nothing in that case.
1673 ChromeTranslateClient* chrome_translate_client =
1674 ChromeTranslateClient::FromWebContents(embedder_web_contents_);
1675 if (!chrome_translate_client ||
1676 chrome_translate_client->GetLanguageState().IsPageTranslated() ||
1677 chrome_translate_client->GetLanguageState().translation_pending()) {
1678 return;
1680 std::string original_lang =
1681 chrome_translate_client->GetLanguageState().original_language();
1682 std::string target_lang = g_browser_process->GetApplicationLocale();
1683 target_lang =
1684 translate::TranslateDownloadManager::GetLanguageCode(target_lang);
1685 // Since the user decided to translate for that language and site, clears
1686 // any preferences for not translating them.
1687 scoped_ptr<translate::TranslatePrefs> prefs(
1688 ChromeTranslateClient::CreateTranslatePrefs(
1689 GetPrefs(browser_context_)));
1690 prefs->UnblockLanguage(original_lang);
1691 prefs->RemoveSiteFromBlacklist(params_.page_url.HostNoBrackets());
1692 translate::TranslateManager* manager =
1693 chrome_translate_client->GetTranslateManager();
1694 DCHECK(manager);
1695 manager->TranslatePage(original_lang, target_lang, true);
1696 break;
1699 case IDC_CONTENT_CONTEXT_RELOADFRAME:
1700 // We always obey the cache here.
1701 // TODO(evanm): Perhaps we could allow shift-clicking the menu item to do
1702 // a cache-ignoring reload of the frame.
1703 source_web_contents_->ReloadFocusedFrame(false);
1704 break;
1706 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
1707 source_web_contents_->ViewFrameSource(params_.frame_url,
1708 params_.frame_page_state);
1709 break;
1711 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO: {
1712 Browser* browser = chrome::FindBrowserWithWebContents(
1713 source_web_contents_);
1714 chrome::ShowWebsiteSettings(browser, source_web_contents_,
1715 params_.frame_url, params_.security_info);
1716 break;
1719 case IDC_CONTENT_CONTEXT_UNDO:
1720 source_web_contents_->Undo();
1721 break;
1723 case IDC_CONTENT_CONTEXT_REDO:
1724 source_web_contents_->Redo();
1725 break;
1727 case IDC_CONTENT_CONTEXT_CUT:
1728 source_web_contents_->Cut();
1729 break;
1731 case IDC_CONTENT_CONTEXT_COPY:
1732 source_web_contents_->Copy();
1733 break;
1735 case IDC_CONTENT_CONTEXT_PASTE:
1736 source_web_contents_->Paste();
1737 break;
1739 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE:
1740 source_web_contents_->PasteAndMatchStyle();
1741 break;
1743 case IDC_CONTENT_CONTEXT_DELETE:
1744 source_web_contents_->Delete();
1745 break;
1747 case IDC_CONTENT_CONTEXT_SELECTALL:
1748 source_web_contents_->SelectAll();
1749 break;
1751 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
1752 case IDC_CONTENT_CONTEXT_GOTOURL: {
1753 WindowOpenDisposition disposition =
1754 ForceNewTabDispositionFromEventFlags(event_flags);
1755 OpenURL(selection_navigation_url_, GURL(), disposition,
1756 ui::PAGE_TRANSITION_LINK);
1757 break;
1759 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS: {
1760 WindowOpenDisposition disposition =
1761 ForceNewTabDispositionFromEventFlags(event_flags);
1762 GURL url = chrome::GetSettingsUrl(chrome::kLanguageOptionsSubPage);
1763 OpenURL(url, GURL(), disposition, ui::PAGE_TRANSITION_LINK);
1764 break;
1767 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS: {
1768 content::RecordAction(
1769 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Settings"));
1770 WindowOpenDisposition disposition =
1771 ForceNewTabDispositionFromEventFlags(event_flags);
1772 GURL url = chrome::GetSettingsUrl(chrome::kHandlerSettingsSubPage);
1773 OpenURL(url, GURL(), disposition, ui::PAGE_TRANSITION_LINK);
1774 break;
1777 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE: {
1778 // Make sure the model is loaded.
1779 TemplateURLService* model =
1780 TemplateURLServiceFactory::GetForProfile(GetProfile());
1781 if (!model)
1782 return;
1783 model->Load();
1785 SearchEngineTabHelper* search_engine_tab_helper =
1786 SearchEngineTabHelper::FromWebContents(source_web_contents_);
1787 if (search_engine_tab_helper &&
1788 search_engine_tab_helper->delegate()) {
1789 base::string16 keyword(TemplateURL::GenerateKeyword(params_.page_url));
1790 TemplateURLData data;
1791 data.SetShortName(keyword);
1792 data.SetKeyword(keyword);
1793 data.SetURL(params_.keyword_url.spec());
1794 data.favicon_url =
1795 TemplateURL::GenerateFaviconURL(params_.page_url.GetOrigin());
1796 // Takes ownership of the TemplateURL.
1797 search_engine_tab_helper->delegate()->ConfirmAddSearchProvider(
1798 new TemplateURL(data), GetProfile());
1800 break;
1803 case IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD:
1804 ChromePasswordManagerClient::FromWebContents(source_web_contents_)->
1805 ForceSavePassword();
1806 break;
1808 default:
1809 NOTREACHED();
1810 break;
1814 ProtocolHandlerRegistry::ProtocolHandlerList
1815 RenderViewContextMenu::GetHandlersForLinkUrl() {
1816 ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1817 protocol_handler_registry_->GetHandlersFor(params_.link_url.scheme());
1818 std::sort(handlers.begin(), handlers.end());
1819 return handlers;
1822 void RenderViewContextMenu::NotifyMenuShown() {
1823 content::NotificationService::current()->Notify(
1824 chrome::NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN,
1825 content::Source<RenderViewContextMenu>(this),
1826 content::NotificationService::NoDetails());
1829 void RenderViewContextMenu::NotifyURLOpened(
1830 const GURL& url,
1831 content::WebContents* new_contents) {
1832 RetargetingDetails details;
1833 details.source_web_contents = source_web_contents_;
1834 // Don't use GetRenderFrameHost() as it may be NULL. crbug.com/399789
1835 details.source_render_frame_id = render_frame_id_;
1836 details.target_url = url;
1837 details.target_web_contents = new_contents;
1838 details.not_yet_in_tabstrip = false;
1840 content::NotificationService::current()->Notify(
1841 chrome::NOTIFICATION_RETARGETING,
1842 content::Source<Profile>(GetProfile()),
1843 content::Details<RetargetingDetails>(&details));
1846 bool RenderViewContextMenu::IsDevCommandEnabled(int id) const {
1847 if (id == IDC_CONTENT_CONTEXT_INSPECTELEMENT ||
1848 id == IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE) {
1849 if (!GetPrefs(browser_context_)
1850 ->GetBoolean(prefs::kWebKitJavascriptEnabled))
1851 return false;
1853 // Don't enable the web inspector if the developer tools are disabled via
1854 // the preference dev-tools-disabled.
1855 if (GetPrefs(browser_context_)->GetBoolean(prefs::kDevToolsDisabled))
1856 return false;
1859 return true;
1862 base::string16 RenderViewContextMenu::PrintableSelectionText() {
1863 return gfx::TruncateString(params_.selection_text,
1864 kMaxSelectionTextLength,
1865 gfx::WORD_BREAK);
1868 // Controller functions --------------------------------------------------------
1870 void RenderViewContextMenu::CopyImageAt(int x, int y) {
1871 source_web_contents_->GetRenderViewHost()->CopyImageAt(x, y);
1874 void RenderViewContextMenu::ShowOriginalImage() {
1875 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1876 if (!render_frame_host)
1877 return;
1878 render_frame_host->Send(new ChromeViewMsg_RequestReloadImageForContextNode(
1879 render_frame_host->GetRoutingID()));
1882 void RenderViewContextMenu::GetImageThumbnailForSearch() {
1883 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1884 if (!render_frame_host)
1885 return;
1886 render_frame_host->Send(new ChromeViewMsg_RequestThumbnailForContextNode(
1887 render_frame_host->GetRoutingID(),
1888 kImageSearchThumbnailMinSize,
1889 gfx::Size(kImageSearchThumbnailMaxWidth,
1890 kImageSearchThumbnailMaxHeight)));
1893 void RenderViewContextMenu::Inspect(int x, int y) {
1894 content::RecordAction(UserMetricsAction("DevTools_InspectElement"));
1895 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1896 if (!render_frame_host)
1897 return;
1898 DevToolsWindow::InspectElement(
1899 WebContents::FromRenderFrameHost(render_frame_host), x, y);
1902 void RenderViewContextMenu::WriteURLToClipboard(const GURL& url) {
1903 chrome_common_net::WriteURLToClipboard(
1904 url, GetPrefs(browser_context_)->GetString(prefs::kAcceptLanguages));
1907 void RenderViewContextMenu::MediaPlayerActionAt(
1908 const gfx::Point& location,
1909 const WebMediaPlayerAction& action) {
1910 source_web_contents_->GetRenderViewHost()->
1911 ExecuteMediaPlayerActionAtLocation(location, action);
1914 void RenderViewContextMenu::PluginActionAt(
1915 const gfx::Point& location,
1916 const WebPluginAction& action) {
1917 source_web_contents_->GetRenderViewHost()->
1918 ExecutePluginActionAtLocation(location, action);