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