Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / renderer_context_menu / render_view_context_menu.cc
blob2d67cc0436bdaf6bd9be8b9d9b73e176852c9973
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/plugins/chrome_plugin_service_filter.h"
35 #include "chrome/browser/prefs/incognito_mode_prefs.h"
36 #include "chrome/browser/profiles/profile.h"
37 #include "chrome/browser/profiles/profile_io_data.h"
38 #include "chrome/browser/renderer_context_menu/context_menu_content_type_factory.h"
39 #include "chrome/browser/renderer_context_menu/spellchecker_submenu_observer.h"
40 #include "chrome/browser/renderer_context_menu/spelling_menu_observer.h"
41 #include "chrome/browser/search/search.h"
42 #include "chrome/browser/search_engines/template_url_service_factory.h"
43 #include "chrome/browser/spellchecker/spellcheck_host_metrics.h"
44 #include "chrome/browser/spellchecker/spellcheck_service.h"
45 #include "chrome/browser/tab_contents/retargeting_details.h"
46 #include "chrome/browser/translate/chrome_translate_client.h"
47 #include "chrome/browser/translate/translate_service.h"
48 #include "chrome/browser/ui/browser.h"
49 #include "chrome/browser/ui/browser_commands.h"
50 #include "chrome/browser/ui/browser_finder.h"
51 #include "chrome/browser/ui/chrome_pages.h"
52 #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"
53 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
54 #include "chrome/common/chrome_constants.h"
55 #include "chrome/common/chrome_switches.h"
56 #include "chrome/common/content_restriction.h"
57 #include "chrome/common/net/url_util.h"
58 #include "chrome/common/pref_names.h"
59 #include "chrome/common/render_messages.h"
60 #include "chrome/common/spellcheck_messages.h"
61 #include "chrome/common/url_constants.h"
62 #include "chrome/grit/generated_resources.h"
63 #include "components/google/core/browser/google_util.h"
64 #include "components/metrics/proto/omnibox_input_type.pb.h"
65 #include "components/omnibox/autocomplete_match.h"
66 #include "components/search_engines/template_url.h"
67 #include "components/search_engines/template_url_service.h"
68 #include "components/translate/core/browser/translate_download_manager.h"
69 #include "components/translate/core/browser/translate_manager.h"
70 #include "components/translate/core/browser/translate_prefs.h"
71 #include "components/user_prefs/user_prefs.h"
72 #include "content/public/browser/child_process_security_policy.h"
73 #include "content/public/browser/download_manager.h"
74 #include "content/public/browser/download_save_info.h"
75 #include "content/public/browser/download_url_parameters.h"
76 #include "content/public/browser/navigation_details.h"
77 #include "content/public/browser/navigation_entry.h"
78 #include "content/public/browser/notification_service.h"
79 #include "content/public/browser/render_frame_host.h"
80 #include "content/public/browser/render_process_host.h"
81 #include "content/public/browser/render_view_host.h"
82 #include "content/public/browser/render_widget_host_view.h"
83 #include "content/public/browser/user_metrics.h"
84 #include "content/public/browser/web_contents.h"
85 #include "content/public/common/menu_item.h"
86 #include "content/public/common/ssl_status.h"
87 #include "content/public/common/url_utils.h"
88 #include "extensions/browser/extension_host.h"
89 #include "extensions/browser/extension_system.h"
90 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
91 #include "extensions/browser/view_type_utils.h"
92 #include "extensions/common/extension.h"
93 #include "net/base/escape.h"
94 #include "third_party/WebKit/public/web/WebContextMenuData.h"
95 #include "third_party/WebKit/public/web/WebMediaPlayerAction.h"
96 #include "third_party/WebKit/public/web/WebPluginAction.h"
97 #include "ui/base/clipboard/clipboard.h"
98 #include "ui/base/l10n/l10n_util.h"
99 #include "ui/gfx/favicon_size.h"
100 #include "ui/gfx/point.h"
101 #include "ui/gfx/size.h"
102 #include "ui/gfx/text_elider.h"
104 #if defined(ENABLE_PRINTING)
105 #include "chrome/common/print_messages.h"
107 #if defined(ENABLE_FULL_PRINTING)
108 #include "chrome/browser/printing/print_preview_context_menu_observer.h"
109 #include "chrome/browser/printing/print_preview_dialog_controller.h"
110 #include "chrome/browser/printing/print_view_manager.h"
111 #else
112 #include "chrome/browser/printing/print_view_manager_basic.h"
113 #endif // defined(ENABLE_FULL_PRINTING)
114 #endif // defined(ENABLE_PRINTING)
116 using base::UserMetricsAction;
117 using blink::WebContextMenuData;
118 using blink::WebMediaPlayerAction;
119 using blink::WebPluginAction;
120 using blink::WebString;
121 using blink::WebURL;
122 using content::BrowserContext;
123 using content::ChildProcessSecurityPolicy;
124 using content::DownloadManager;
125 using content::DownloadUrlParameters;
126 using content::NavigationController;
127 using content::NavigationEntry;
128 using content::OpenURLParams;
129 using content::RenderFrameHost;
130 using content::RenderViewHost;
131 using content::SSLStatus;
132 using content::WebContents;
133 using extensions::ContextMenuMatcher;
134 using extensions::Extension;
135 using extensions::MenuItem;
136 using extensions::MenuManager;
138 namespace {
140 const int kImageSearchThumbnailMinSize = 300 * 300;
141 const int kImageSearchThumbnailMaxWidth = 600;
142 const int kImageSearchThumbnailMaxHeight = 600;
144 // Maps UMA enumeration to IDC. IDC could be changed so we can't use
145 // just them and |UMA_HISTOGRAM_CUSTOM_ENUMERATION|.
146 // Never change mapping or reuse |enum_id|. Always push back new items.
147 // Items that is not used any more by |RenderViewContextMenu.ExecuteCommand|
148 // could be deleted, but don't change the rest of |kUmaEnumToControlId|.
149 const struct UmaEnumCommandIdPair {
150 int enum_id;
151 int control_id;
152 } kUmaEnumToControlId[] = {
154 enum id for 0, 1 are detected using
155 RenderViewContextMenu::IsContentCustomCommandId and
156 ContextMenuMatcher::IsExtensionsCustomCommandId
158 {2, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST},
159 {3, IDC_CONTENT_CONTEXT_OPENLINKNEWTAB},
160 {4, IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW},
161 {5, IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD},
162 {6, IDC_CONTENT_CONTEXT_SAVELINKAS},
163 {7, IDC_CONTENT_CONTEXT_SAVEAVAS},
164 {8, IDC_CONTENT_CONTEXT_SAVEIMAGEAS},
165 {9, IDC_CONTENT_CONTEXT_COPYLINKLOCATION},
166 {10, IDC_CONTENT_CONTEXT_COPYIMAGELOCATION},
167 {11, IDC_CONTENT_CONTEXT_COPYAVLOCATION},
168 {12, IDC_CONTENT_CONTEXT_COPYIMAGE},
169 {13, IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB},
170 {14, IDC_CONTENT_CONTEXT_OPENAVNEWTAB},
171 {15, IDC_CONTENT_CONTEXT_PLAYPAUSE},
172 {16, IDC_CONTENT_CONTEXT_MUTE},
173 {17, IDC_CONTENT_CONTEXT_LOOP},
174 {18, IDC_CONTENT_CONTEXT_CONTROLS},
175 {19, IDC_CONTENT_CONTEXT_ROTATECW},
176 {20, IDC_CONTENT_CONTEXT_ROTATECCW},
177 {21, IDC_BACK},
178 {22, IDC_FORWARD},
179 {23, IDC_SAVE_PAGE},
180 {24, IDC_RELOAD},
181 {25, IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP},
182 {26, IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP},
183 {27, IDC_PRINT},
184 {28, IDC_VIEW_SOURCE},
185 {29, IDC_CONTENT_CONTEXT_INSPECTELEMENT},
186 {30, IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE},
187 {31, IDC_CONTENT_CONTEXT_VIEWPAGEINFO},
188 {32, IDC_CONTENT_CONTEXT_TRANSLATE},
189 {33, IDC_CONTENT_CONTEXT_RELOADFRAME},
190 {34, IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE},
191 {35, IDC_CONTENT_CONTEXT_VIEWFRAMEINFO},
192 {36, IDC_CONTENT_CONTEXT_UNDO},
193 {37, IDC_CONTENT_CONTEXT_REDO},
194 {38, IDC_CONTENT_CONTEXT_CUT},
195 {39, IDC_CONTENT_CONTEXT_COPY},
196 {40, IDC_CONTENT_CONTEXT_PASTE},
197 {41, IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE},
198 {42, IDC_CONTENT_CONTEXT_DELETE},
199 {43, IDC_CONTENT_CONTEXT_SELECTALL},
200 {44, IDC_CONTENT_CONTEXT_SEARCHWEBFOR},
201 {45, IDC_CONTENT_CONTEXT_GOTOURL},
202 {46, IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS},
203 {47, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS},
204 {48, IDC_CONTENT_CONTEXT_ADDSEARCHENGINE},
205 {52, IDC_CONTENT_CONTEXT_OPENLINKWITH},
206 {53, IDC_CHECK_SPELLING_WHILE_TYPING},
207 {54, IDC_SPELLCHECK_MENU},
208 {55, IDC_CONTENT_CONTEXT_SPELLING_TOGGLE},
209 {56, IDC_SPELLCHECK_LANGUAGES_FIRST},
210 {57, IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE},
211 {58, IDC_SPELLCHECK_SUGGESTION_0},
212 {59, IDC_SPELLCHECK_ADD_TO_DICTIONARY},
213 {60, IDC_SPELLPANEL_TOGGLE},
214 // Add new items here and use |enum_id| from the next line.
215 {61, 0}, // Must be the last. Increment |enum_id| when new IDC was added.
218 // Collapses large ranges of ids before looking for UMA enum.
219 int CollapseCommandsForUMA(int id) {
220 DCHECK(!RenderViewContextMenu::IsContentCustomCommandId(id));
221 DCHECK(!ContextMenuMatcher::IsExtensionsCustomCommandId(id));
223 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
224 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
225 return IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
228 if (id >= IDC_SPELLCHECK_LANGUAGES_FIRST &&
229 id <= IDC_SPELLCHECK_LANGUAGES_LAST) {
230 return IDC_SPELLCHECK_LANGUAGES_FIRST;
233 if (id >= IDC_SPELLCHECK_SUGGESTION_0 &&
234 id <= IDC_SPELLCHECK_SUGGESTION_LAST) {
235 return IDC_SPELLCHECK_SUGGESTION_0;
238 return id;
241 // Returns UMA enum value for command specified by |id| or -1 if not found.
242 int FindUMAEnumValueForCommand(int id) {
243 if (RenderViewContextMenu::IsContentCustomCommandId(id))
244 return 0;
246 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
247 return 1;
249 id = CollapseCommandsForUMA(id);
250 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
251 for (size_t i = 0; i < kMappingSize; ++i) {
252 if (kUmaEnumToControlId[i].control_id == id) {
253 return kUmaEnumToControlId[i].enum_id;
256 return -1;
259 // Usually a new tab is expected where this function is used,
260 // however users should be able to open a tab in background
261 // or in a new window.
262 WindowOpenDisposition ForceNewTabDispositionFromEventFlags(
263 int event_flags) {
264 WindowOpenDisposition disposition =
265 ui::DispositionFromEventFlags(event_flags);
266 return disposition == CURRENT_TAB ? NEW_FOREGROUND_TAB : disposition;
269 // Helper function to escape "&" as "&&".
270 void EscapeAmpersands(base::string16* text) {
271 base::ReplaceChars(*text, base::ASCIIToUTF16("&"), base::ASCIIToUTF16("&&"),
272 text);
275 // Returns the preference of the profile represented by the |context|.
276 PrefService* GetPrefs(content::BrowserContext* context) {
277 return user_prefs::UserPrefs::Get(context);
280 bool ExtensionPatternMatch(const extensions::URLPatternSet& patterns,
281 const GURL& url) {
282 // No patterns means no restriction, so that implicitly matches.
283 if (patterns.is_empty())
284 return true;
285 return patterns.MatchesURL(url);
288 const GURL& GetDocumentURL(const content::ContextMenuParams& params) {
289 return params.frame_url.is_empty() ? params.page_url : params.frame_url;
292 content::Referrer CreateSaveAsReferrer(
293 const GURL& url,
294 const content::ContextMenuParams& params) {
295 const GURL& referring_url = GetDocumentURL(params);
296 return content::Referrer::SanitizeForRequest(
297 url,
298 content::Referrer(referring_url.GetAsReferrer(), params.referrer_policy));
301 bool g_custom_id_ranges_initialized = false;
303 const int kSpellcheckRadioGroup = 1;
305 } // namespace
307 // static
308 bool RenderViewContextMenu::IsDevToolsURL(const GURL& url) {
309 return url.SchemeIs(content::kChromeDevToolsScheme);
312 // static
313 bool RenderViewContextMenu::IsInternalResourcesURL(const GURL& url) {
314 if (!url.SchemeIs(content::kChromeUIScheme))
315 return false;
316 return url.host() == chrome::kChromeUISyncResourcesHost;
319 RenderViewContextMenu::RenderViewContextMenu(
320 content::RenderFrameHost* render_frame_host,
321 const content::ContextMenuParams& params)
322 : RenderViewContextMenuBase(render_frame_host, params),
323 extension_items_(browser_context_,
324 this,
325 &menu_model_,
326 base::Bind(MenuItemMatchesParams, params_)),
327 protocol_handler_submenu_model_(this),
328 protocol_handler_registry_(
329 ProtocolHandlerRegistryFactory::GetForBrowserContext(GetProfile())) {
330 if (!g_custom_id_ranges_initialized) {
331 g_custom_id_ranges_initialized = true;
332 SetContentCustomCommandIdRange(IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
333 IDC_CONTENT_CONTEXT_CUSTOM_LAST);
335 set_content_type(ContextMenuContentTypeFactory::Create(
336 source_web_contents_, params));
339 RenderViewContextMenu::~RenderViewContextMenu() {
342 // Menu construction functions -------------------------------------------------
344 // static
345 bool RenderViewContextMenu::ExtensionContextAndPatternMatch(
346 const content::ContextMenuParams& params,
347 const MenuItem::ContextList& contexts,
348 const extensions::URLPatternSet& target_url_patterns) {
349 const bool has_link = !params.link_url.is_empty();
350 const bool has_selection = !params.selection_text.empty();
351 const bool in_frame = !params.frame_url.is_empty();
353 if (contexts.Contains(MenuItem::ALL) ||
354 (has_selection && contexts.Contains(MenuItem::SELECTION)) ||
355 (params.is_editable && contexts.Contains(MenuItem::EDITABLE)) ||
356 (in_frame && contexts.Contains(MenuItem::FRAME)))
357 return true;
359 if (has_link && contexts.Contains(MenuItem::LINK) &&
360 ExtensionPatternMatch(target_url_patterns, params.link_url))
361 return true;
363 switch (params.media_type) {
364 case WebContextMenuData::MediaTypeImage:
365 if (contexts.Contains(MenuItem::IMAGE) &&
366 ExtensionPatternMatch(target_url_patterns, params.src_url))
367 return true;
368 break;
370 case WebContextMenuData::MediaTypeVideo:
371 if (contexts.Contains(MenuItem::VIDEO) &&
372 ExtensionPatternMatch(target_url_patterns, params.src_url))
373 return true;
374 break;
376 case WebContextMenuData::MediaTypeAudio:
377 if (contexts.Contains(MenuItem::AUDIO) &&
378 ExtensionPatternMatch(target_url_patterns, params.src_url))
379 return true;
380 break;
382 default:
383 break;
386 // PAGE is the least specific context, so we only examine that if none of the
387 // other contexts apply (except for FRAME, which is included in PAGE for
388 // backwards compatibility).
389 if (!has_link && !has_selection && !params.is_editable &&
390 params.media_type == WebContextMenuData::MediaTypeNone &&
391 contexts.Contains(MenuItem::PAGE))
392 return true;
394 return false;
397 // static
398 bool RenderViewContextMenu::MenuItemMatchesParams(
399 const content::ContextMenuParams& params,
400 const extensions::MenuItem* item) {
401 bool match = ExtensionContextAndPatternMatch(params, item->contexts(),
402 item->target_url_patterns());
403 if (!match)
404 return false;
406 const GURL& document_url = GetDocumentURL(params);
407 return ExtensionPatternMatch(item->document_url_patterns(), document_url);
410 void RenderViewContextMenu::AppendAllExtensionItems() {
411 extension_items_.Clear();
412 ExtensionService* service =
413 extensions::ExtensionSystem::Get(browser_context_)->extension_service();
414 if (!service)
415 return; // In unit-tests, we may not have an ExtensionService.
417 MenuManager* menu_manager = MenuManager::Get(browser_context_);
418 if (!menu_manager)
419 return;
421 base::string16 printable_selection_text = PrintableSelectionText();
422 EscapeAmpersands(&printable_selection_text);
424 // Get a list of extension id's that have context menu items, and sort by the
425 // top level context menu title of the extension.
426 std::set<MenuItem::ExtensionKey> ids = menu_manager->ExtensionIds();
427 std::vector<base::string16> sorted_menu_titles;
428 std::map<base::string16, std::string> map_ids;
429 for (std::set<MenuItem::ExtensionKey>::iterator iter = ids.begin();
430 iter != ids.end();
431 ++iter) {
432 const Extension* extension =
433 service->GetExtensionById(iter->extension_id, false);
434 // Platform apps have their context menus created directly in
435 // AppendPlatformAppItems.
436 if (extension && !extension->is_platform_app()) {
437 base::string16 menu_title = extension_items_.GetTopLevelContextMenuTitle(
438 *iter, printable_selection_text);
439 map_ids[menu_title] = iter->extension_id;
440 sorted_menu_titles.push_back(menu_title);
443 if (sorted_menu_titles.empty())
444 return;
446 const std::string app_locale = g_browser_process->GetApplicationLocale();
447 l10n_util::SortStrings16(app_locale, &sorted_menu_titles);
449 int index = 0;
450 for (size_t i = 0; i < sorted_menu_titles.size(); ++i) {
451 const std::string& id = map_ids[sorted_menu_titles[i]];
452 const MenuItem::ExtensionKey extension_key(id);
453 extension_items_.AppendExtensionItems(extension_key,
454 printable_selection_text,
455 &index,
456 false); // is_action_menu
460 void RenderViewContextMenu::AppendCurrentExtensionItems() {
461 // Avoid appending extension related items when |extension| is null.
462 // For Panel, this happens when the panel is navigated to a url outside of the
463 // extension's package.
464 const Extension* extension = GetExtension();
465 if (extension) {
466 // Only add extension items from this extension.
467 int index = 0;
468 const MenuItem::ExtensionKey key(
469 extension->id(),
470 extensions::WebViewGuest::GetViewInstanceId(source_web_contents_));
471 extension_items_.AppendExtensionItems(key,
472 PrintableSelectionText(),
473 &index,
474 false); // is_action_menu
478 void RenderViewContextMenu::InitMenu() {
479 RenderViewContextMenuBase::InitMenu();
481 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PAGE))
482 AppendPageItems();
484 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_FRAME)) {
485 // Merge in frame items with page items if we clicked within a frame that
486 // needs them.
487 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
488 AppendFrameItems();
491 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_LINK)) {
492 AppendLinkItems();
493 if (params_.media_type != WebContextMenuData::MediaTypeNone)
494 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
497 if (content_type_->SupportsGroup(
498 ContextMenuContentType::ITEM_GROUP_MEDIA_IMAGE)) {
499 AppendImageItems();
502 if (content_type_->SupportsGroup(
503 ContextMenuContentType::ITEM_GROUP_SEARCHWEBFORIMAGE)) {
504 AppendSearchWebForImageItems();
507 if (content_type_->SupportsGroup(
508 ContextMenuContentType::ITEM_GROUP_MEDIA_VIDEO)) {
509 AppendVideoItems();
512 if (content_type_->SupportsGroup(
513 ContextMenuContentType::ITEM_GROUP_MEDIA_AUDIO)) {
514 AppendAudioItems();
517 if (content_type_->SupportsGroup(
518 ContextMenuContentType::ITEM_GROUP_MEDIA_CANVAS)) {
519 AppendCanvasItems();
522 if (content_type_->SupportsGroup(
523 ContextMenuContentType::ITEM_GROUP_MEDIA_PLUGIN)) {
524 AppendPluginItems();
527 // ITEM_GROUP_MEDIA_FILE has no specific items.
529 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_EDITABLE))
530 AppendEditableItems();
532 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_COPY)) {
533 DCHECK(!content_type_->SupportsGroup(
534 ContextMenuContentType::ITEM_GROUP_EDITABLE));
535 AppendCopyItem();
538 if (content_type_->SupportsGroup(
539 ContextMenuContentType::ITEM_GROUP_SEARCH_PROVIDER)) {
540 AppendSearchProvider();
543 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT))
544 AppendPrintItem();
546 if (content_type_->SupportsGroup(
547 ContextMenuContentType::ITEM_GROUP_MEDIA_PLUGIN)) {
548 AppendRotationItems();
551 if (content_type_->SupportsGroup(
552 ContextMenuContentType::ITEM_GROUP_ALL_EXTENSION)) {
553 DCHECK(!content_type_->SupportsGroup(
554 ContextMenuContentType::ITEM_GROUP_CURRENT_EXTENSION));
555 AppendAllExtensionItems();
558 if (content_type_->SupportsGroup(
559 ContextMenuContentType::ITEM_GROUP_CURRENT_EXTENSION)) {
560 DCHECK(!content_type_->SupportsGroup(
561 ContextMenuContentType::ITEM_GROUP_ALL_EXTENSION));
562 AppendCurrentExtensionItems();
565 if (content_type_->SupportsGroup(
566 ContextMenuContentType::ITEM_GROUP_DEVELOPER)) {
567 AppendDeveloperItems();
570 if (content_type_->SupportsGroup(
571 ContextMenuContentType::ITEM_GROUP_DEVTOOLS_UNPACKED_EXT)) {
572 AppendDevtoolsForUnpackedExtensions();
575 if (content_type_->SupportsGroup(
576 ContextMenuContentType::ITEM_GROUP_PRINT_PREVIEW)) {
577 AppendPrintPreviewItems();
581 Profile* RenderViewContextMenu::GetProfile() {
582 return Profile::FromBrowserContext(browser_context_);
585 void RenderViewContextMenu::RecordUsedItem(int id) {
586 int enum_id = FindUMAEnumValueForCommand(id);
587 if (enum_id != -1) {
588 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
589 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Used", enum_id,
590 kUmaEnumToControlId[kMappingSize - 1].enum_id);
591 } else {
592 NOTREACHED() << "Update kUmaEnumToControlId. Unhanded IDC: " << id;
596 void RenderViewContextMenu::RecordShownItem(int id) {
597 int enum_id = FindUMAEnumValueForCommand(id);
598 if (enum_id != -1) {
599 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
600 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Shown", enum_id,
601 kUmaEnumToControlId[kMappingSize - 1].enum_id);
602 } else {
603 // Just warning here. It's harder to maintain list of all possibly
604 // visible items than executable items.
605 DLOG(ERROR) << "Update kUmaEnumToControlId. Unhanded IDC: " << id;
609 #if defined(ENABLE_PLUGINS)
610 void RenderViewContextMenu::HandleAuthorizeAllPlugins() {
611 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins(
612 source_web_contents_, false, std::string());
614 #endif
616 void RenderViewContextMenu::AppendPrintPreviewItems() {
617 #if defined(ENABLE_FULL_PRINTING)
618 if (!print_preview_menu_observer_.get()) {
619 print_preview_menu_observer_.reset(
620 new PrintPreviewContextMenuObserver(source_web_contents_));
623 observers_.AddObserver(print_preview_menu_observer_.get());
624 #endif
627 const Extension* RenderViewContextMenu::GetExtension() const {
628 extensions::ExtensionSystem* system =
629 extensions::ExtensionSystem::Get(browser_context_);
630 // There is no process manager in some tests.
631 if (!system->process_manager())
632 return NULL;
634 return system->process_manager()->GetExtensionForRenderViewHost(
635 source_web_contents_->GetRenderViewHost());
638 void RenderViewContextMenu::AppendDeveloperItems() {
639 // Show Inspect Element in DevTools itself only in case of the debug
640 // devtools build.
641 bool show_developer_items = !IsDevToolsURL(params_.page_url);
643 #if defined(DEBUG_DEVTOOLS)
644 show_developer_items = true;
645 #endif
647 if (!show_developer_items)
648 return;
650 // In the DevTools popup menu, "developer items" is normally the only
651 // section, so omit the separator there.
652 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
653 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTELEMENT,
654 IDS_CONTENT_CONTEXT_INSPECTELEMENT);
657 void RenderViewContextMenu::AppendDevtoolsForUnpackedExtensions() {
658 // Add a separator if there are any items already in the menu.
659 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
661 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP,
662 IDS_CONTENT_CONTEXT_RELOAD_PACKAGED_APP);
663 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP,
664 IDS_CONTENT_CONTEXT_RESTART_APP);
665 AppendDeveloperItems();
666 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE,
667 IDS_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE);
670 void RenderViewContextMenu::AppendLinkItems() {
671 if (!params_.link_url.is_empty()) {
672 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB,
673 IDS_CONTENT_CONTEXT_OPENLINKNEWTAB);
674 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW,
675 IDS_CONTENT_CONTEXT_OPENLINKNEWWINDOW);
676 if (params_.link_url.is_valid()) {
677 AppendProtocolHandlerSubMenu();
680 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD,
681 IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD);
682 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVELINKAS,
683 IDS_CONTENT_CONTEXT_SAVELINKAS);
686 menu_model_.AddItemWithStringId(
687 IDC_CONTENT_CONTEXT_COPYLINKLOCATION,
688 params_.link_url.SchemeIs(url::kMailToScheme) ?
689 IDS_CONTENT_CONTEXT_COPYEMAILADDRESS :
690 IDS_CONTENT_CONTEXT_COPYLINKLOCATION);
693 void RenderViewContextMenu::AppendImageItems() {
694 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS,
695 IDS_CONTENT_CONTEXT_SAVEIMAGEAS);
696 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGELOCATION,
697 IDS_CONTENT_CONTEXT_COPYIMAGELOCATION);
698 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
699 IDS_CONTENT_CONTEXT_COPYIMAGE);
700 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB,
701 IDS_CONTENT_CONTEXT_OPENIMAGENEWTAB);
704 void RenderViewContextMenu::AppendSearchWebForImageItems() {
705 TemplateURLService* service =
706 TemplateURLServiceFactory::GetForProfile(GetProfile());
707 const TemplateURL* const default_provider =
708 service->GetDefaultSearchProvider();
709 if (params_.has_image_contents && default_provider &&
710 !default_provider->image_url().empty() &&
711 default_provider->image_url_ref().IsValid(service->search_terms_data())) {
712 menu_model_.AddItem(
713 IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE,
714 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFORIMAGE,
715 default_provider->short_name()));
719 void RenderViewContextMenu::AppendAudioItems() {
720 AppendMediaItems();
721 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
722 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
723 IDS_CONTENT_CONTEXT_SAVEAUDIOAS);
724 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
725 IDS_CONTENT_CONTEXT_COPYAUDIOLOCATION);
726 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
727 IDS_CONTENT_CONTEXT_OPENAUDIONEWTAB);
730 void RenderViewContextMenu::AppendCanvasItems() {
731 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS,
732 IDS_CONTENT_CONTEXT_SAVEIMAGEAS);
733 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
734 IDS_CONTENT_CONTEXT_COPYIMAGE);
737 void RenderViewContextMenu::AppendVideoItems() {
738 AppendMediaItems();
739 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
740 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
741 IDS_CONTENT_CONTEXT_SAVEVIDEOAS);
742 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
743 IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION);
744 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
745 IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB);
748 void RenderViewContextMenu::AppendMediaItems() {
749 int media_flags = params_.media_flags;
751 menu_model_.AddItemWithStringId(
752 IDC_CONTENT_CONTEXT_PLAYPAUSE,
753 media_flags & WebContextMenuData::MediaPaused ?
754 IDS_CONTENT_CONTEXT_PLAY :
755 IDS_CONTENT_CONTEXT_PAUSE);
757 menu_model_.AddItemWithStringId(
758 IDC_CONTENT_CONTEXT_MUTE,
759 media_flags & WebContextMenuData::MediaMuted ?
760 IDS_CONTENT_CONTEXT_UNMUTE :
761 IDS_CONTENT_CONTEXT_MUTE);
763 menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_LOOP,
764 IDS_CONTENT_CONTEXT_LOOP);
765 menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_CONTROLS,
766 IDS_CONTENT_CONTEXT_CONTROLS);
769 void RenderViewContextMenu::AppendPluginItems() {
770 if (params_.page_url == params_.src_url) {
771 // Full page plugin, so show page menu items.
772 if (params_.link_url.is_empty() && params_.selection_text.empty())
773 AppendPageItems();
774 } else {
775 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
776 IDS_CONTENT_CONTEXT_SAVEPAGEAS);
777 // The "Print" menu item should always be included for plugins. If
778 // content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT)
779 // is true the item will be added inside AppendPrintItem(). Otherwise we
780 // add "Print" here.
781 if (!content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT))
782 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
786 void RenderViewContextMenu::AppendPageItems() {
787 menu_model_.AddItemWithStringId(IDC_BACK, IDS_CONTENT_CONTEXT_BACK);
788 menu_model_.AddItemWithStringId(IDC_FORWARD, IDS_CONTENT_CONTEXT_FORWARD);
789 menu_model_.AddItemWithStringId(IDC_RELOAD, IDS_CONTENT_CONTEXT_RELOAD);
790 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
791 menu_model_.AddItemWithStringId(IDC_SAVE_PAGE,
792 IDS_CONTENT_CONTEXT_SAVEPAGEAS);
793 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
795 if (TranslateService::IsTranslatableURL(params_.page_url)) {
796 std::string locale = g_browser_process->GetApplicationLocale();
797 locale = translate::TranslateDownloadManager::GetLanguageCode(locale);
798 base::string16 language =
799 l10n_util::GetDisplayNameForLocale(locale, locale, true);
800 menu_model_.AddItem(
801 IDC_CONTENT_CONTEXT_TRANSLATE,
802 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_TRANSLATE, language));
805 menu_model_.AddItemWithStringId(IDC_VIEW_SOURCE,
806 IDS_CONTENT_CONTEXT_VIEWPAGESOURCE);
807 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWPAGEINFO,
808 IDS_CONTENT_CONTEXT_VIEWPAGEINFO);
811 void RenderViewContextMenu::AppendFrameItems() {
812 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOADFRAME,
813 IDS_CONTENT_CONTEXT_RELOADFRAME);
814 // These two menu items have yet to be implemented.
815 // http://code.google.com/p/chromium/issues/detail?id=11827
816 // IDS_CONTENT_CONTEXT_SAVEFRAMEAS
817 // IDS_CONTENT_CONTEXT_PRINTFRAME
818 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE,
819 IDS_CONTENT_CONTEXT_VIEWFRAMESOURCE);
820 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMEINFO,
821 IDS_CONTENT_CONTEXT_VIEWFRAMEINFO);
824 void RenderViewContextMenu::AppendCopyItem() {
825 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
826 IDS_CONTENT_CONTEXT_COPY);
829 void RenderViewContextMenu::AppendPrintItem() {
830 if (GetPrefs(browser_context_)->GetBoolean(prefs::kPrintingEnabled) &&
831 (params_.media_type == WebContextMenuData::MediaTypeNone ||
832 params_.media_flags & WebContextMenuData::MediaCanPrint)) {
833 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
837 void RenderViewContextMenu::AppendRotationItems() {
838 if (params_.media_flags & WebContextMenuData::MediaCanRotate) {
839 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
840 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECW,
841 IDS_CONTENT_CONTEXT_ROTATECW);
842 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECCW,
843 IDS_CONTENT_CONTEXT_ROTATECCW);
847 void RenderViewContextMenu::AppendSearchProvider() {
848 DCHECK(browser_context_);
850 base::TrimWhitespace(params_.selection_text, base::TRIM_ALL,
851 &params_.selection_text);
852 if (params_.selection_text.empty())
853 return;
855 base::ReplaceChars(params_.selection_text, AutocompleteMatch::kInvalidChars,
856 base::ASCIIToUTF16(" "), &params_.selection_text);
858 AutocompleteMatch match;
859 AutocompleteClassifierFactory::GetForProfile(GetProfile())->Classify(
860 params_.selection_text,
861 false,
862 false,
863 metrics::OmniboxEventProto::INVALID_SPEC,
864 &match,
865 NULL);
866 selection_navigation_url_ = match.destination_url;
867 if (!selection_navigation_url_.is_valid())
868 return;
870 base::string16 printable_selection_text = PrintableSelectionText();
871 EscapeAmpersands(&printable_selection_text);
873 if (AutocompleteMatch::IsSearchType(match.type)) {
874 const TemplateURL* const default_provider =
875 TemplateURLServiceFactory::GetForProfile(GetProfile())
876 ->GetDefaultSearchProvider();
877 if (!default_provider)
878 return;
879 menu_model_.AddItem(
880 IDC_CONTENT_CONTEXT_SEARCHWEBFOR,
881 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFOR,
882 default_provider->short_name(),
883 printable_selection_text));
884 } else {
885 if ((selection_navigation_url_ != params_.link_url) &&
886 ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme(
887 selection_navigation_url_.scheme())) {
888 menu_model_.AddItem(
889 IDC_CONTENT_CONTEXT_GOTOURL,
890 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_GOTOURL,
891 printable_selection_text));
896 void RenderViewContextMenu::AppendEditableItems() {
897 const bool use_spellcheck_and_search = !chrome::IsRunningInForcedAppMode();
899 if (use_spellcheck_and_search)
900 AppendSpellingSuggestionsSubMenu();
902 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_UNDO,
903 IDS_CONTENT_CONTEXT_UNDO);
904 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_REDO,
905 IDS_CONTENT_CONTEXT_REDO);
906 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
907 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_CUT,
908 IDS_CONTENT_CONTEXT_CUT);
909 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
910 IDS_CONTENT_CONTEXT_COPY);
911 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE,
912 IDS_CONTENT_CONTEXT_PASTE);
913 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE,
914 IDS_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE);
915 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_DELETE,
916 IDS_CONTENT_CONTEXT_DELETE);
917 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
919 if (use_spellcheck_and_search && !params_.keyword_url.is_empty()) {
920 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ADDSEARCHENGINE,
921 IDS_CONTENT_CONTEXT_ADDSEARCHENGINE);
922 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
925 if (use_spellcheck_and_search)
926 AppendSpellcheckOptionsSubMenu();
927 AppendPlatformEditableItems();
929 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
930 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SELECTALL,
931 IDS_CONTENT_CONTEXT_SELECTALL);
934 void RenderViewContextMenu::AppendSpellingSuggestionsSubMenu() {
935 if (!spelling_menu_observer_.get())
936 spelling_menu_observer_.reset(new SpellingMenuObserver(this));
937 observers_.AddObserver(spelling_menu_observer_.get());
938 spelling_menu_observer_->InitMenu(params_);
941 void RenderViewContextMenu::AppendSpellcheckOptionsSubMenu() {
942 if (!spellchecker_submenu_observer_.get()) {
943 spellchecker_submenu_observer_.reset(new SpellCheckerSubMenuObserver(
944 this, this, kSpellcheckRadioGroup));
946 spellchecker_submenu_observer_->InitMenu(params_);
947 observers_.AddObserver(spellchecker_submenu_observer_.get());
950 void RenderViewContextMenu::AppendProtocolHandlerSubMenu() {
951 const ProtocolHandlerRegistry::ProtocolHandlerList handlers =
952 GetHandlersForLinkUrl();
953 if (handlers.empty())
954 return;
955 size_t max = IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST -
956 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
957 for (size_t i = 0; i < handlers.size() && i <= max; i++) {
958 protocol_handler_submenu_model_.AddItem(
959 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST + i,
960 base::UTF8ToUTF16(handlers[i].url().host()));
962 protocol_handler_submenu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
963 protocol_handler_submenu_model_.AddItem(
964 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS,
965 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH_CONFIGURE));
967 menu_model_.AddSubMenu(
968 IDC_CONTENT_CONTEXT_OPENLINKWITH,
969 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH),
970 &protocol_handler_submenu_model_);
973 // Menu delegate functions -----------------------------------------------------
975 bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
977 bool enabled = false;
978 if (RenderViewContextMenuBase::IsCommandIdKnown(id, &enabled))
979 return enabled;
982 CoreTabHelper* core_tab_helper =
983 CoreTabHelper::FromWebContents(source_web_contents_);
984 int content_restrictions = 0;
985 if (core_tab_helper)
986 content_restrictions = core_tab_helper->content_restrictions();
987 if (id == IDC_PRINT && (content_restrictions & CONTENT_RESTRICTION_PRINT))
988 return false;
990 if (id == IDC_SAVE_PAGE &&
991 (content_restrictions & CONTENT_RESTRICTION_SAVE)) {
992 return false;
995 PrefService* prefs = GetPrefs(browser_context_);
997 // Allow Spell Check language items on sub menu for text area context menu.
998 if ((id >= IDC_SPELLCHECK_LANGUAGES_FIRST) &&
999 (id < IDC_SPELLCHECK_LANGUAGES_LAST)) {
1000 return prefs->GetBoolean(prefs::kEnableContinuousSpellcheck);
1003 // Extension items.
1004 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
1005 return extension_items_.IsCommandIdEnabled(id);
1007 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
1008 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
1009 return true;
1012 IncognitoModePrefs::Availability incognito_avail =
1013 IncognitoModePrefs::GetAvailability(prefs);
1014 switch (id) {
1015 case IDC_BACK:
1016 return source_web_contents_->GetController().CanGoBack();
1018 case IDC_FORWARD:
1019 return source_web_contents_->GetController().CanGoForward();
1021 case IDC_RELOAD: {
1022 CoreTabHelper* core_tab_helper =
1023 CoreTabHelper::FromWebContents(source_web_contents_);
1024 if (!core_tab_helper)
1025 return false;
1027 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
1028 return !core_delegate ||
1029 core_delegate->CanReloadContents(source_web_contents_);
1032 case IDC_VIEW_SOURCE:
1033 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
1034 return source_web_contents_->GetController().CanViewSource();
1036 case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
1037 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE:
1038 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP:
1039 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP:
1040 return IsDevCommandEnabled(id);
1042 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO:
1043 if (source_web_contents_->GetController().GetVisibleEntry() == NULL)
1044 return false;
1045 // Disabled if no browser is associated (e.g. desktop notifications).
1046 if (chrome::FindBrowserWithWebContents(source_web_contents_) == NULL)
1047 return false;
1048 return true;
1050 case IDC_CONTENT_CONTEXT_TRANSLATE: {
1051 ChromeTranslateClient* chrome_translate_client =
1052 ChromeTranslateClient::FromWebContents(source_web_contents_);
1053 if (!chrome_translate_client)
1054 return false;
1055 std::string original_lang =
1056 chrome_translate_client->GetLanguageState().original_language();
1057 std::string target_lang = g_browser_process->GetApplicationLocale();
1058 target_lang =
1059 translate::TranslateDownloadManager::GetLanguageCode(target_lang);
1060 // Note that we intentionally enable the menu even if the original and
1061 // target languages are identical. This is to give a way to user to
1062 // translate a page that might contains text fragments in a different
1063 // language.
1064 return ((params_.edit_flags & WebContextMenuData::CanTranslate) != 0) &&
1065 !original_lang.empty() && // Did we receive the page language yet?
1066 !chrome_translate_client->GetLanguageState().IsPageTranslated() &&
1067 !source_web_contents_->GetInterstitialPage() &&
1068 // There are some application locales which can't be used as a
1069 // target language for translation.
1070 translate::TranslateDownloadManager::IsSupportedLanguage(
1071 target_lang) &&
1072 // Disable on the Instant Extended NTP.
1073 !chrome::IsInstantNTP(source_web_contents_);
1076 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB:
1077 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
1078 return params_.link_url.is_valid();
1080 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
1081 return params_.unfiltered_link_url.is_valid();
1083 case IDC_CONTENT_CONTEXT_SAVELINKAS: {
1084 PrefService* local_state = g_browser_process->local_state();
1085 DCHECK(local_state);
1086 // Test if file-selection dialogs are forbidden by policy.
1087 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1088 return false;
1090 return params_.link_url.is_valid() &&
1091 ProfileIOData::IsHandledProtocol(params_.link_url.scheme());
1094 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: {
1095 PrefService* local_state = g_browser_process->local_state();
1096 DCHECK(local_state);
1097 // Test if file-selection dialogs are forbidden by policy.
1098 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1099 return false;
1101 return params_.has_image_contents;
1104 // The images shown in the most visited thumbnails can't be opened or
1105 // searched for conventionally.
1106 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
1107 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
1108 return params_.src_url.is_valid() &&
1109 (params_.src_url.scheme() != content::kChromeUIScheme);
1111 case IDC_CONTENT_CONTEXT_COPYIMAGE:
1112 return params_.has_image_contents;
1114 // Media control commands should all be disabled if the player is in an
1115 // error state.
1116 case IDC_CONTENT_CONTEXT_PLAYPAUSE:
1117 case IDC_CONTENT_CONTEXT_LOOP:
1118 return (params_.media_flags &
1119 WebContextMenuData::MediaInError) == 0;
1121 // Mute and unmute should also be disabled if the player has no audio.
1122 case IDC_CONTENT_CONTEXT_MUTE:
1123 return (params_.media_flags &
1124 WebContextMenuData::MediaHasAudio) != 0 &&
1125 (params_.media_flags &
1126 WebContextMenuData::MediaInError) == 0;
1128 case IDC_CONTENT_CONTEXT_CONTROLS:
1129 return (params_.media_flags &
1130 WebContextMenuData::MediaCanToggleControls) != 0;
1132 case IDC_CONTENT_CONTEXT_ROTATECW:
1133 case IDC_CONTENT_CONTEXT_ROTATECCW:
1134 return
1135 (params_.media_flags & WebContextMenuData::MediaCanRotate) != 0;
1137 case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
1138 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
1139 return params_.src_url.is_valid();
1141 case IDC_CONTENT_CONTEXT_SAVEAVAS: {
1142 PrefService* local_state = g_browser_process->local_state();
1143 DCHECK(local_state);
1144 // Test if file-selection dialogs are forbidden by policy.
1145 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1146 return false;
1148 const GURL& url = params_.src_url;
1149 bool can_save =
1150 (params_.media_flags & WebContextMenuData::MediaCanSave) &&
1151 url.is_valid() && ProfileIOData::IsHandledProtocol(url.scheme());
1152 #if defined(ENABLE_FULL_PRINTING)
1153 // Do not save the preview PDF on the print preview page.
1154 can_save = can_save &&
1155 !(printing::PrintPreviewDialogController::IsPrintPreviewURL(url));
1156 #endif
1157 return can_save;
1160 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
1161 return true;
1163 case IDC_SAVE_PAGE: {
1164 CoreTabHelper* core_tab_helper =
1165 CoreTabHelper::FromWebContents(source_web_contents_);
1166 if (!core_tab_helper)
1167 return false;
1169 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
1170 if (core_delegate &&
1171 !core_delegate->CanSaveContents(source_web_contents_))
1172 return false;
1174 PrefService* local_state = g_browser_process->local_state();
1175 DCHECK(local_state);
1176 // Test if file-selection dialogs are forbidden by policy.
1177 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1178 return false;
1180 // We save the last committed entry (which the user is looking at), as
1181 // opposed to any pending URL that hasn't committed yet.
1182 NavigationEntry* entry =
1183 source_web_contents_->GetController().GetLastCommittedEntry();
1184 return content::IsSavableURL(entry ? entry->GetURL() : GURL());
1187 case IDC_CONTENT_CONTEXT_RELOADFRAME:
1188 return params_.frame_url.is_valid();
1190 case IDC_CONTENT_CONTEXT_UNDO:
1191 return !!(params_.edit_flags & WebContextMenuData::CanUndo);
1193 case IDC_CONTENT_CONTEXT_REDO:
1194 return !!(params_.edit_flags & WebContextMenuData::CanRedo);
1196 case IDC_CONTENT_CONTEXT_CUT:
1197 return !!(params_.edit_flags & WebContextMenuData::CanCut);
1199 case IDC_CONTENT_CONTEXT_COPY:
1200 return !!(params_.edit_flags & WebContextMenuData::CanCopy);
1202 case IDC_CONTENT_CONTEXT_PASTE:
1203 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE: {
1204 std::vector<base::string16> types;
1205 bool ignore;
1206 ui::Clipboard::GetForCurrentThread()->ReadAvailableTypes(
1207 ui::CLIPBOARD_TYPE_COPY_PASTE, &types, &ignore);
1208 return !types.empty();
1210 case IDC_CONTENT_CONTEXT_DELETE:
1211 return !!(params_.edit_flags & WebContextMenuData::CanDelete);
1213 case IDC_CONTENT_CONTEXT_SELECTALL:
1214 return !!(params_.edit_flags & WebContextMenuData::CanSelectAll);
1216 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
1217 return !browser_context_->IsOffTheRecord() &&
1218 params_.link_url.is_valid() &&
1219 incognito_avail != IncognitoModePrefs::DISABLED;
1221 case IDC_PRINT:
1222 return prefs->GetBoolean(prefs::kPrintingEnabled) &&
1223 (params_.media_type == WebContextMenuData::MediaTypeNone ||
1224 params_.media_flags & WebContextMenuData::MediaCanPrint);
1226 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
1227 case IDC_CONTENT_CONTEXT_GOTOURL:
1228 case IDC_SPELLPANEL_TOGGLE:
1229 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS:
1230 return true;
1231 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO:
1232 // Disabled if no browser is associated (e.g. desktop notifications).
1233 if (chrome::FindBrowserWithWebContents(source_web_contents_) == NULL)
1234 return false;
1235 return true;
1237 case IDC_CHECK_SPELLING_WHILE_TYPING:
1238 return prefs->GetBoolean(prefs::kEnableContinuousSpellcheck);
1240 #if !defined(OS_MACOSX) && defined(OS_POSIX)
1241 // TODO(suzhe): this should not be enabled for password fields.
1242 case IDC_INPUT_METHODS_MENU:
1243 return true;
1244 #endif
1246 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE:
1247 return !params_.keyword_url.is_empty();
1249 case IDC_SPELLCHECK_MENU:
1250 return true;
1252 case IDC_CONTENT_CONTEXT_OPENLINKWITH:
1253 return true;
1255 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS:
1256 return true;
1258 default:
1259 NOTREACHED();
1260 return false;
1264 bool RenderViewContextMenu::IsCommandIdChecked(int id) const {
1265 if (RenderViewContextMenuBase::IsCommandIdChecked(id))
1266 return true;
1268 // See if the video is set to looping.
1269 if (id == IDC_CONTENT_CONTEXT_LOOP)
1270 return (params_.media_flags & WebContextMenuData::MediaLoop) != 0;
1272 if (id == IDC_CONTENT_CONTEXT_CONTROLS)
1273 return (params_.media_flags & WebContextMenuData::MediaControls) != 0;
1275 // Extension items.
1276 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
1277 return extension_items_.IsCommandIdChecked(id);
1279 return false;
1282 void RenderViewContextMenu::ExecuteCommand(int id, int event_flags) {
1283 RenderViewContextMenuBase::ExecuteCommand(id, event_flags);
1284 if (command_executed_)
1285 return;
1286 command_executed_ = true;
1288 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1290 // Process extension menu items.
1291 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id)) {
1292 extension_items_.ExecuteCommand(id, source_web_contents_, params_);
1293 return;
1296 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
1297 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
1298 ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1299 GetHandlersForLinkUrl();
1300 if (handlers.empty())
1301 return;
1303 content::RecordAction(
1304 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Open"));
1305 int handlerIndex = id - IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
1306 WindowOpenDisposition disposition =
1307 ForceNewTabDispositionFromEventFlags(event_flags);
1308 OpenURL(handlers[handlerIndex].TranslateUrl(params_.link_url),
1309 GetDocumentURL(params_),
1310 disposition,
1311 ui::PAGE_TRANSITION_LINK);
1312 return;
1315 switch (id) {
1316 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB: {
1317 Browser* browser =
1318 chrome::FindBrowserWithWebContents(source_web_contents_);
1319 OpenURL(params_.link_url,
1320 GetDocumentURL(params_),
1321 !browser || browser->is_app() ?
1322 NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB,
1323 ui::PAGE_TRANSITION_LINK);
1324 break;
1326 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
1327 OpenURL(params_.link_url,
1328 GetDocumentURL(params_),
1329 NEW_WINDOW,
1330 ui::PAGE_TRANSITION_LINK);
1331 break;
1333 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
1334 OpenURL(params_.link_url, GURL(), OFF_THE_RECORD,
1335 ui::PAGE_TRANSITION_LINK);
1336 break;
1338 case IDC_CONTENT_CONTEXT_SAVELINKAS: {
1339 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
1340 const GURL& url = params_.link_url;
1341 content::Referrer referrer = CreateSaveAsReferrer(url, params_);
1342 DownloadManager* dlm =
1343 BrowserContext::GetDownloadManager(browser_context_);
1344 scoped_ptr<DownloadUrlParameters> dl_params(
1345 DownloadUrlParameters::FromWebContents(source_web_contents_, url));
1346 dl_params->set_referrer(referrer);
1347 dl_params->set_referrer_encoding(params_.frame_charset);
1348 dl_params->set_suggested_name(params_.suggested_filename);
1349 dl_params->set_prompt(true);
1350 dlm->DownloadUrl(dl_params.Pass());
1351 break;
1354 case IDC_CONTENT_CONTEXT_SAVEAVAS:
1355 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: {
1356 bool is_large_data_url = params_.has_image_contents &&
1357 params_.src_url.is_empty();
1358 if (params_.media_type == WebContextMenuData::MediaTypeCanvas ||
1359 (params_.media_type == WebContextMenuData::MediaTypeImage &&
1360 is_large_data_url)) {
1361 source_web_contents_->GetRenderViewHost()->SaveImageAt(
1362 params_.x, params_.y);
1363 } else {
1364 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
1365 const GURL& url = params_.src_url;
1366 content::Referrer referrer = CreateSaveAsReferrer(url, params_);
1367 source_web_contents_->SaveFrame(url, referrer);
1369 break;
1372 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
1373 WriteURLToClipboard(params_.unfiltered_link_url);
1374 break;
1376 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
1377 case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
1378 WriteURLToClipboard(params_.src_url);
1379 break;
1381 case IDC_CONTENT_CONTEXT_COPYIMAGE:
1382 CopyImageAt(params_.x, params_.y);
1383 break;
1385 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
1386 GetImageThumbnailForSearch();
1387 break;
1389 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
1390 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
1391 OpenURL(params_.src_url,
1392 GetDocumentURL(params_),
1393 NEW_BACKGROUND_TAB,
1394 ui::PAGE_TRANSITION_LINK);
1395 break;
1397 case IDC_CONTENT_CONTEXT_PLAYPAUSE: {
1398 bool play = !!(params_.media_flags & WebContextMenuData::MediaPaused);
1399 if (play) {
1400 content::RecordAction(UserMetricsAction("MediaContextMenu_Play"));
1401 } else {
1402 content::RecordAction(UserMetricsAction("MediaContextMenu_Pause"));
1404 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1405 WebMediaPlayerAction(
1406 WebMediaPlayerAction::Play, play));
1407 break;
1410 case IDC_CONTENT_CONTEXT_MUTE: {
1411 bool mute = !(params_.media_flags & WebContextMenuData::MediaMuted);
1412 if (mute) {
1413 content::RecordAction(UserMetricsAction("MediaContextMenu_Mute"));
1414 } else {
1415 content::RecordAction(UserMetricsAction("MediaContextMenu_Unmute"));
1417 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1418 WebMediaPlayerAction(
1419 WebMediaPlayerAction::Mute, mute));
1420 break;
1423 case IDC_CONTENT_CONTEXT_LOOP:
1424 content::RecordAction(UserMetricsAction("MediaContextMenu_Loop"));
1425 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1426 WebMediaPlayerAction(
1427 WebMediaPlayerAction::Loop,
1428 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_LOOP)));
1429 break;
1431 case IDC_CONTENT_CONTEXT_CONTROLS:
1432 content::RecordAction(UserMetricsAction("MediaContextMenu_Controls"));
1433 MediaPlayerActionAt(
1434 gfx::Point(params_.x, params_.y),
1435 WebMediaPlayerAction(
1436 WebMediaPlayerAction::Controls,
1437 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_CONTROLS)));
1438 break;
1440 case IDC_CONTENT_CONTEXT_ROTATECW:
1441 content::RecordAction(
1442 UserMetricsAction("PluginContextMenu_RotateClockwise"));
1443 PluginActionAt(
1444 gfx::Point(params_.x, params_.y),
1445 WebPluginAction(WebPluginAction::Rotate90Clockwise, true));
1446 break;
1448 case IDC_CONTENT_CONTEXT_ROTATECCW:
1449 content::RecordAction(
1450 UserMetricsAction("PluginContextMenu_RotateCounterclockwise"));
1451 PluginActionAt(
1452 gfx::Point(params_.x, params_.y),
1453 WebPluginAction(WebPluginAction::Rotate90Counterclockwise, true));
1454 break;
1456 case IDC_BACK:
1457 source_web_contents_->GetController().GoBack();
1458 break;
1460 case IDC_FORWARD:
1461 source_web_contents_->GetController().GoForward();
1462 break;
1464 case IDC_SAVE_PAGE:
1465 source_web_contents_->OnSavePage();
1466 break;
1468 case IDC_RELOAD:
1469 source_web_contents_->GetController().Reload(true);
1470 break;
1472 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP: {
1473 const Extension* platform_app = GetExtension();
1474 DCHECK(platform_app);
1475 DCHECK(platform_app->is_platform_app());
1477 extensions::ExtensionSystem::Get(browser_context_)
1478 ->extension_service()
1479 ->ReloadExtension(platform_app->id());
1480 break;
1483 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP: {
1484 const Extension* platform_app = GetExtension();
1485 DCHECK(platform_app);
1486 DCHECK(platform_app->is_platform_app());
1488 apps::AppLoadService::Get(GetProfile())
1489 ->RestartApplication(platform_app->id());
1490 break;
1493 case IDC_PRINT: {
1494 #if defined(ENABLE_PRINTING)
1495 if (params_.media_type != WebContextMenuData::MediaTypeNone) {
1496 if (render_frame_host) {
1497 render_frame_host->Send(new PrintMsg_PrintNodeUnderContextMenu(
1498 render_frame_host->GetRoutingID()));
1500 break;
1503 #if defined(ENABLE_FULL_PRINTING)
1504 printing::PrintViewManager* print_view_manager =
1505 printing::PrintViewManager::FromWebContents(source_web_contents_);
1506 if (!print_view_manager)
1507 break;
1508 if (!GetPrefs(browser_context_)
1509 ->GetBoolean(prefs::kPrintPreviewDisabled)) {
1510 print_view_manager->PrintPreviewNow(!params_.selection_text.empty());
1511 break;
1513 #else // ENABLE_FULL_PRINTING
1514 printing::PrintViewManagerBasic* print_view_manager =
1515 printing::PrintViewManagerBasic::FromWebContents(
1516 source_web_contents_);
1517 if (!print_view_manager)
1518 break;
1519 #endif // ENABLE_FULL_PRINTING
1521 #if !defined(DISABLE_BASIC_PRINTING)
1522 print_view_manager->PrintNow();
1523 #endif // !DISABLE_BASIC_PRINTING
1525 #endif // ENABLE_PRINTING
1526 break;
1529 case IDC_VIEW_SOURCE:
1530 source_web_contents_->ViewSource();
1531 break;
1533 case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
1534 Inspect(params_.x, params_.y);
1535 break;
1537 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE: {
1538 const Extension* platform_app = GetExtension();
1539 DCHECK(platform_app);
1540 DCHECK(platform_app->is_platform_app());
1542 extensions::devtools_util::InspectBackgroundPage(platform_app,
1543 GetProfile());
1544 break;
1547 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO: {
1548 NavigationController* controller = &source_web_contents_->GetController();
1549 // Important to use GetVisibleEntry to match what's showing in the
1550 // omnibox. This may return null.
1551 NavigationEntry* nav_entry = controller->GetVisibleEntry();
1552 if (!nav_entry)
1553 return;
1554 Browser* browser =
1555 chrome::FindBrowserWithWebContents(source_web_contents_);
1556 chrome::ShowWebsiteSettings(browser, source_web_contents_,
1557 nav_entry->GetURL(), nav_entry->GetSSL());
1558 break;
1561 case IDC_CONTENT_CONTEXT_TRANSLATE: {
1562 // A translation might have been triggered by the time the menu got
1563 // selected, do nothing in that case.
1564 ChromeTranslateClient* chrome_translate_client =
1565 ChromeTranslateClient::FromWebContents(source_web_contents_);
1566 if (!chrome_translate_client ||
1567 chrome_translate_client->GetLanguageState().IsPageTranslated() ||
1568 chrome_translate_client->GetLanguageState().translation_pending()) {
1569 return;
1571 std::string original_lang =
1572 chrome_translate_client->GetLanguageState().original_language();
1573 std::string target_lang = g_browser_process->GetApplicationLocale();
1574 target_lang =
1575 translate::TranslateDownloadManager::GetLanguageCode(target_lang);
1576 // Since the user decided to translate for that language and site, clears
1577 // any preferences for not translating them.
1578 scoped_ptr<translate::TranslatePrefs> prefs(
1579 ChromeTranslateClient::CreateTranslatePrefs(
1580 GetPrefs(browser_context_)));
1581 prefs->UnblockLanguage(original_lang);
1582 prefs->RemoveSiteFromBlacklist(params_.page_url.HostNoBrackets());
1583 translate::TranslateManager* manager =
1584 chrome_translate_client->GetTranslateManager();
1585 DCHECK(manager);
1586 manager->TranslatePage(original_lang, target_lang, true);
1587 break;
1590 case IDC_CONTENT_CONTEXT_RELOADFRAME:
1591 // We always obey the cache here.
1592 // TODO(evanm): Perhaps we could allow shift-clicking the menu item to do
1593 // a cache-ignoring reload of the frame.
1594 source_web_contents_->ReloadFocusedFrame(false);
1595 break;
1597 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
1598 source_web_contents_->ViewFrameSource(params_.frame_url,
1599 params_.frame_page_state);
1600 break;
1602 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO: {
1603 Browser* browser = chrome::FindBrowserWithWebContents(
1604 source_web_contents_);
1605 chrome::ShowWebsiteSettings(browser, source_web_contents_,
1606 params_.frame_url, params_.security_info);
1607 break;
1610 case IDC_CONTENT_CONTEXT_UNDO:
1611 source_web_contents_->Undo();
1612 break;
1614 case IDC_CONTENT_CONTEXT_REDO:
1615 source_web_contents_->Redo();
1616 break;
1618 case IDC_CONTENT_CONTEXT_CUT:
1619 source_web_contents_->Cut();
1620 break;
1622 case IDC_CONTENT_CONTEXT_COPY:
1623 source_web_contents_->Copy();
1624 break;
1626 case IDC_CONTENT_CONTEXT_PASTE:
1627 source_web_contents_->Paste();
1628 break;
1630 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE:
1631 source_web_contents_->PasteAndMatchStyle();
1632 break;
1634 case IDC_CONTENT_CONTEXT_DELETE:
1635 source_web_contents_->Delete();
1636 break;
1638 case IDC_CONTENT_CONTEXT_SELECTALL:
1639 source_web_contents_->SelectAll();
1640 break;
1642 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
1643 case IDC_CONTENT_CONTEXT_GOTOURL: {
1644 WindowOpenDisposition disposition =
1645 ForceNewTabDispositionFromEventFlags(event_flags);
1646 OpenURL(selection_navigation_url_, GURL(), disposition,
1647 ui::PAGE_TRANSITION_LINK);
1648 break;
1650 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS: {
1651 WindowOpenDisposition disposition =
1652 ForceNewTabDispositionFromEventFlags(event_flags);
1653 GURL url = chrome::GetSettingsUrl(chrome::kLanguageOptionsSubPage);
1654 OpenURL(url, GURL(), disposition, ui::PAGE_TRANSITION_LINK);
1655 break;
1658 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS: {
1659 content::RecordAction(
1660 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Settings"));
1661 WindowOpenDisposition disposition =
1662 ForceNewTabDispositionFromEventFlags(event_flags);
1663 GURL url = chrome::GetSettingsUrl(chrome::kHandlerSettingsSubPage);
1664 OpenURL(url, GURL(), disposition, ui::PAGE_TRANSITION_LINK);
1665 break;
1668 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE: {
1669 // Make sure the model is loaded.
1670 TemplateURLService* model =
1671 TemplateURLServiceFactory::GetForProfile(GetProfile());
1672 if (!model)
1673 return;
1674 model->Load();
1676 SearchEngineTabHelper* search_engine_tab_helper =
1677 SearchEngineTabHelper::FromWebContents(source_web_contents_);
1678 if (search_engine_tab_helper &&
1679 search_engine_tab_helper->delegate()) {
1680 base::string16 keyword(TemplateURL::GenerateKeyword(params_.page_url));
1681 TemplateURLData data;
1682 data.short_name = keyword;
1683 data.SetKeyword(keyword);
1684 data.SetURL(params_.keyword_url.spec());
1685 data.favicon_url =
1686 TemplateURL::GenerateFaviconURL(params_.page_url.GetOrigin());
1687 // Takes ownership of the TemplateURL.
1688 search_engine_tab_helper->delegate()->ConfirmAddSearchProvider(
1689 new TemplateURL(data), GetProfile());
1691 break;
1694 default:
1695 NOTREACHED();
1696 break;
1700 ProtocolHandlerRegistry::ProtocolHandlerList
1701 RenderViewContextMenu::GetHandlersForLinkUrl() {
1702 ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1703 protocol_handler_registry_->GetHandlersFor(params_.link_url.scheme());
1704 std::sort(handlers.begin(), handlers.end());
1705 return handlers;
1708 void RenderViewContextMenu::NotifyMenuShown() {
1709 content::NotificationService::current()->Notify(
1710 chrome::NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN,
1711 content::Source<RenderViewContextMenu>(this),
1712 content::NotificationService::NoDetails());
1715 void RenderViewContextMenu::NotifyURLOpened(
1716 const GURL& url,
1717 content::WebContents* new_contents) {
1718 RetargetingDetails details;
1719 details.source_web_contents = source_web_contents_;
1720 // Don't use GetRenderFrameHost() as it may be NULL. crbug.com/399789
1721 details.source_render_frame_id = render_frame_id_;
1722 details.target_url = url;
1723 details.target_web_contents = new_contents;
1724 details.not_yet_in_tabstrip = false;
1726 content::NotificationService::current()->Notify(
1727 chrome::NOTIFICATION_RETARGETING,
1728 content::Source<Profile>(GetProfile()),
1729 content::Details<RetargetingDetails>(&details));
1732 bool RenderViewContextMenu::IsDevCommandEnabled(int id) const {
1733 if (id == IDC_CONTENT_CONTEXT_INSPECTELEMENT ||
1734 id == IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE) {
1735 const CommandLine* command_line = CommandLine::ForCurrentProcess();
1736 if (!GetPrefs(browser_context_)
1737 ->GetBoolean(prefs::kWebKitJavascriptEnabled) ||
1738 command_line->HasSwitch(switches::kDisableJavaScript))
1739 return false;
1741 // Don't enable the web inspector if the developer tools are disabled via
1742 // the preference dev-tools-disabled.
1743 if (GetPrefs(browser_context_)->GetBoolean(prefs::kDevToolsDisabled))
1744 return false;
1747 return true;
1750 base::string16 RenderViewContextMenu::PrintableSelectionText() {
1751 return gfx::TruncateString(params_.selection_text,
1752 kMaxSelectionTextLength,
1753 gfx::WORD_BREAK);
1756 // Controller functions --------------------------------------------------------
1758 void RenderViewContextMenu::CopyImageAt(int x, int y) {
1759 source_web_contents_->GetRenderViewHost()->CopyImageAt(x, y);
1762 void RenderViewContextMenu::GetImageThumbnailForSearch() {
1763 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1764 if (!render_frame_host)
1765 return;
1766 render_frame_host->Send(new ChromeViewMsg_RequestThumbnailForContextNode(
1767 render_frame_host->GetRoutingID(),
1768 kImageSearchThumbnailMinSize,
1769 gfx::Size(kImageSearchThumbnailMaxWidth,
1770 kImageSearchThumbnailMaxHeight)));
1773 void RenderViewContextMenu::Inspect(int x, int y) {
1774 content::RecordAction(UserMetricsAction("DevTools_InspectElement"));
1775 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1776 if (!render_frame_host)
1777 return;
1778 DevToolsWindow::InspectElement(
1779 WebContents::FromRenderFrameHost(render_frame_host), x, y);
1782 void RenderViewContextMenu::WriteURLToClipboard(const GURL& url) {
1783 chrome_common_net::WriteURLToClipboard(
1784 url, GetPrefs(browser_context_)->GetString(prefs::kAcceptLanguages));
1787 void RenderViewContextMenu::MediaPlayerActionAt(
1788 const gfx::Point& location,
1789 const WebMediaPlayerAction& action) {
1790 source_web_contents_->GetRenderViewHost()->
1791 ExecuteMediaPlayerActionAtLocation(location, action);
1794 void RenderViewContextMenu::PluginActionAt(
1795 const gfx::Point& location,
1796 const WebPluginAction& action) {
1797 source_web_contents_->GetRenderViewHost()->
1798 ExecutePluginActionAtLocation(location, action);