base::Time multiplicative operator overloading
[chromium-blink-merge.git] / chrome / browser / renderer_context_menu / render_view_context_menu.cc
blobaf666b7e166ad76b3bfafb93b376d7f3d851c08c
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/geometry/point.h"
101 #include "ui/gfx/geometry/size.h"
102 #include "ui/gfx/text_elider.h"
104 #if defined(ENABLE_PRINTING)
105 #include "chrome/browser/printing/print_view_manager_common.h"
106 #include "components/printing/common/print_messages.h"
108 #if defined(ENABLE_PRINT_PREVIEW)
109 #include "chrome/browser/printing/print_preview_context_menu_observer.h"
110 #include "chrome/browser/printing/print_preview_dialog_controller.h"
111 #endif // defined(ENABLE_PRINT_PREVIEW)
112 #endif // defined(ENABLE_PRINTING)
114 using base::UserMetricsAction;
115 using blink::WebContextMenuData;
116 using blink::WebMediaPlayerAction;
117 using blink::WebPluginAction;
118 using blink::WebString;
119 using blink::WebURL;
120 using content::BrowserContext;
121 using content::ChildProcessSecurityPolicy;
122 using content::DownloadManager;
123 using content::DownloadUrlParameters;
124 using content::NavigationController;
125 using content::NavigationEntry;
126 using content::OpenURLParams;
127 using content::RenderFrameHost;
128 using content::RenderViewHost;
129 using content::SSLStatus;
130 using content::WebContents;
131 using extensions::ContextMenuMatcher;
132 using extensions::Extension;
133 using extensions::MenuItem;
134 using extensions::MenuManager;
136 namespace {
138 const int kImageSearchThumbnailMinSize = 300 * 300;
139 const int kImageSearchThumbnailMaxWidth = 600;
140 const int kImageSearchThumbnailMaxHeight = 600;
142 // Maps UMA enumeration to IDC. IDC could be changed so we can't use
143 // just them and |UMA_HISTOGRAM_CUSTOM_ENUMERATION|.
144 // Never change mapping or reuse |enum_id|. Always push back new items.
145 // Items that is not used any more by |RenderViewContextMenu.ExecuteCommand|
146 // could be deleted, but don't change the rest of |kUmaEnumToControlId|.
147 const struct UmaEnumCommandIdPair {
148 int enum_id;
149 int control_id;
150 } kUmaEnumToControlId[] = {
152 enum id for 0, 1 are detected using
153 RenderViewContextMenu::IsContentCustomCommandId and
154 ContextMenuMatcher::IsExtensionsCustomCommandId
156 {2, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST},
157 {3, IDC_CONTENT_CONTEXT_OPENLINKNEWTAB},
158 {4, IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW},
159 {5, IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD},
160 {6, IDC_CONTENT_CONTEXT_SAVELINKAS},
161 {7, IDC_CONTENT_CONTEXT_SAVEAVAS},
162 {8, IDC_CONTENT_CONTEXT_SAVEIMAGEAS},
163 {9, IDC_CONTENT_CONTEXT_COPYLINKLOCATION},
164 {10, IDC_CONTENT_CONTEXT_COPYIMAGELOCATION},
165 {11, IDC_CONTENT_CONTEXT_COPYAVLOCATION},
166 {12, IDC_CONTENT_CONTEXT_COPYIMAGE},
167 {13, IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB},
168 {14, IDC_CONTENT_CONTEXT_OPENAVNEWTAB},
169 {15, IDC_CONTENT_CONTEXT_PLAYPAUSE},
170 {16, IDC_CONTENT_CONTEXT_MUTE},
171 {17, IDC_CONTENT_CONTEXT_LOOP},
172 {18, IDC_CONTENT_CONTEXT_CONTROLS},
173 {19, IDC_CONTENT_CONTEXT_ROTATECW},
174 {20, IDC_CONTENT_CONTEXT_ROTATECCW},
175 {21, IDC_BACK},
176 {22, IDC_FORWARD},
177 {23, IDC_SAVE_PAGE},
178 {24, IDC_RELOAD},
179 {25, IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP},
180 {26, IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP},
181 {27, IDC_PRINT},
182 {28, IDC_VIEW_SOURCE},
183 {29, IDC_CONTENT_CONTEXT_INSPECTELEMENT},
184 {30, IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE},
185 {31, IDC_CONTENT_CONTEXT_VIEWPAGEINFO},
186 {32, IDC_CONTENT_CONTEXT_TRANSLATE},
187 {33, IDC_CONTENT_CONTEXT_RELOADFRAME},
188 {34, IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE},
189 {35, IDC_CONTENT_CONTEXT_VIEWFRAMEINFO},
190 {36, IDC_CONTENT_CONTEXT_UNDO},
191 {37, IDC_CONTENT_CONTEXT_REDO},
192 {38, IDC_CONTENT_CONTEXT_CUT},
193 {39, IDC_CONTENT_CONTEXT_COPY},
194 {40, IDC_CONTENT_CONTEXT_PASTE},
195 {41, IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE},
196 {42, IDC_CONTENT_CONTEXT_DELETE},
197 {43, IDC_CONTENT_CONTEXT_SELECTALL},
198 {44, IDC_CONTENT_CONTEXT_SEARCHWEBFOR},
199 {45, IDC_CONTENT_CONTEXT_GOTOURL},
200 {46, IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS},
201 {47, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS},
202 {48, IDC_CONTENT_CONTEXT_ADDSEARCHENGINE},
203 {52, IDC_CONTENT_CONTEXT_OPENLINKWITH},
204 {53, IDC_CHECK_SPELLING_WHILE_TYPING},
205 {54, IDC_SPELLCHECK_MENU},
206 {55, IDC_CONTENT_CONTEXT_SPELLING_TOGGLE},
207 {56, IDC_SPELLCHECK_LANGUAGES_FIRST},
208 {57, IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE},
209 {58, IDC_SPELLCHECK_SUGGESTION_0},
210 {59, IDC_SPELLCHECK_ADD_TO_DICTIONARY},
211 {60, IDC_SPELLPANEL_TOGGLE},
212 // Add new items here and use |enum_id| from the next line.
213 {61, 0}, // Must be the last. Increment |enum_id| when new IDC was added.
216 // Collapses large ranges of ids before looking for UMA enum.
217 int CollapseCommandsForUMA(int id) {
218 DCHECK(!RenderViewContextMenu::IsContentCustomCommandId(id));
219 DCHECK(!ContextMenuMatcher::IsExtensionsCustomCommandId(id));
221 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
222 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
223 return IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
226 if (id >= IDC_SPELLCHECK_LANGUAGES_FIRST &&
227 id <= IDC_SPELLCHECK_LANGUAGES_LAST) {
228 return IDC_SPELLCHECK_LANGUAGES_FIRST;
231 if (id >= IDC_SPELLCHECK_SUGGESTION_0 &&
232 id <= IDC_SPELLCHECK_SUGGESTION_LAST) {
233 return IDC_SPELLCHECK_SUGGESTION_0;
236 return id;
239 // Returns UMA enum value for command specified by |id| or -1 if not found.
240 int FindUMAEnumValueForCommand(int id) {
241 if (RenderViewContextMenu::IsContentCustomCommandId(id))
242 return 0;
244 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
245 return 1;
247 id = CollapseCommandsForUMA(id);
248 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
249 for (size_t i = 0; i < kMappingSize; ++i) {
250 if (kUmaEnumToControlId[i].control_id == id) {
251 return kUmaEnumToControlId[i].enum_id;
254 return -1;
257 // Usually a new tab is expected where this function is used,
258 // however users should be able to open a tab in background
259 // or in a new window.
260 WindowOpenDisposition ForceNewTabDispositionFromEventFlags(
261 int event_flags) {
262 WindowOpenDisposition disposition =
263 ui::DispositionFromEventFlags(event_flags);
264 return disposition == CURRENT_TAB ? NEW_FOREGROUND_TAB : disposition;
267 // Helper function to escape "&" as "&&".
268 void EscapeAmpersands(base::string16* text) {
269 base::ReplaceChars(*text, base::ASCIIToUTF16("&"), base::ASCIIToUTF16("&&"),
270 text);
273 // Returns the preference of the profile represented by the |context|.
274 PrefService* GetPrefs(content::BrowserContext* context) {
275 return user_prefs::UserPrefs::Get(context);
278 bool ExtensionPatternMatch(const extensions::URLPatternSet& patterns,
279 const GURL& url) {
280 // No patterns means no restriction, so that implicitly matches.
281 if (patterns.is_empty())
282 return true;
283 return patterns.MatchesURL(url);
286 const GURL& GetDocumentURL(const content::ContextMenuParams& params) {
287 return params.frame_url.is_empty() ? params.page_url : params.frame_url;
290 content::Referrer CreateSaveAsReferrer(
291 const GURL& url,
292 const content::ContextMenuParams& params) {
293 const GURL& referring_url = GetDocumentURL(params);
294 return content::Referrer::SanitizeForRequest(
295 url,
296 content::Referrer(referring_url.GetAsReferrer(), params.referrer_policy));
299 bool g_custom_id_ranges_initialized = false;
301 const int kSpellcheckRadioGroup = 1;
303 } // namespace
305 // static
306 bool RenderViewContextMenu::IsDevToolsURL(const GURL& url) {
307 return url.SchemeIs(content::kChromeDevToolsScheme);
310 // static
311 bool RenderViewContextMenu::IsInternalResourcesURL(const GURL& url) {
312 if (!url.SchemeIs(content::kChromeUIScheme))
313 return false;
314 return url.host() == chrome::kChromeUISyncResourcesHost;
317 RenderViewContextMenu::RenderViewContextMenu(
318 content::RenderFrameHost* render_frame_host,
319 const content::ContextMenuParams& params)
320 : RenderViewContextMenuBase(render_frame_host, params),
321 extension_items_(browser_context_,
322 this,
323 &menu_model_,
324 base::Bind(MenuItemMatchesParams, params_)),
325 protocol_handler_submenu_model_(this),
326 protocol_handler_registry_(
327 ProtocolHandlerRegistryFactory::GetForBrowserContext(GetProfile())) {
328 if (!g_custom_id_ranges_initialized) {
329 g_custom_id_ranges_initialized = true;
330 SetContentCustomCommandIdRange(IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
331 IDC_CONTENT_CONTEXT_CUSTOM_LAST);
333 set_content_type(ContextMenuContentTypeFactory::Create(
334 source_web_contents_, params));
337 RenderViewContextMenu::~RenderViewContextMenu() {
340 // Menu construction functions -------------------------------------------------
342 #if defined(ENABLE_EXTENSIONS)
343 // static
344 bool RenderViewContextMenu::ExtensionContextAndPatternMatch(
345 const content::ContextMenuParams& params,
346 const MenuItem::ContextList& contexts,
347 const extensions::URLPatternSet& target_url_patterns) {
348 const bool has_link = !params.link_url.is_empty();
349 const bool has_selection = !params.selection_text.empty();
350 const bool in_frame = !params.frame_url.is_empty();
352 if (contexts.Contains(MenuItem::ALL) ||
353 (has_selection && contexts.Contains(MenuItem::SELECTION)) ||
354 (params.is_editable && contexts.Contains(MenuItem::EDITABLE)) ||
355 (in_frame && contexts.Contains(MenuItem::FRAME)))
356 return true;
358 if (has_link && contexts.Contains(MenuItem::LINK) &&
359 ExtensionPatternMatch(target_url_patterns, params.link_url))
360 return true;
362 switch (params.media_type) {
363 case WebContextMenuData::MediaTypeImage:
364 if (contexts.Contains(MenuItem::IMAGE) &&
365 ExtensionPatternMatch(target_url_patterns, params.src_url))
366 return true;
367 break;
369 case WebContextMenuData::MediaTypeVideo:
370 if (contexts.Contains(MenuItem::VIDEO) &&
371 ExtensionPatternMatch(target_url_patterns, params.src_url))
372 return true;
373 break;
375 case WebContextMenuData::MediaTypeAudio:
376 if (contexts.Contains(MenuItem::AUDIO) &&
377 ExtensionPatternMatch(target_url_patterns, params.src_url))
378 return true;
379 break;
381 default:
382 break;
385 // PAGE is the least specific context, so we only examine that if none of the
386 // other contexts apply (except for FRAME, which is included in PAGE for
387 // backwards compatibility).
388 if (!has_link && !has_selection && !params.is_editable &&
389 params.media_type == WebContextMenuData::MediaTypeNone &&
390 contexts.Contains(MenuItem::PAGE))
391 return true;
393 return false;
396 // static
397 bool RenderViewContextMenu::MenuItemMatchesParams(
398 const content::ContextMenuParams& params,
399 const extensions::MenuItem* item) {
400 bool match = ExtensionContextAndPatternMatch(params, item->contexts(),
401 item->target_url_patterns());
402 if (!match)
403 return false;
405 const GURL& document_url = GetDocumentURL(params);
406 return ExtensionPatternMatch(item->document_url_patterns(), document_url);
409 void RenderViewContextMenu::AppendAllExtensionItems() {
410 extension_items_.Clear();
411 ExtensionService* service =
412 extensions::ExtensionSystem::Get(browser_context_)->extension_service();
413 if (!service)
414 return; // In unit-tests, we may not have an ExtensionService.
416 MenuManager* menu_manager = MenuManager::Get(browser_context_);
417 if (!menu_manager)
418 return;
420 base::string16 printable_selection_text = PrintableSelectionText();
421 EscapeAmpersands(&printable_selection_text);
423 // Get a list of extension id's that have context menu items, and sort by the
424 // top level context menu title of the extension.
425 std::set<MenuItem::ExtensionKey> ids = menu_manager->ExtensionIds();
426 std::vector<base::string16> sorted_menu_titles;
427 std::map<base::string16, std::string> map_ids;
428 for (std::set<MenuItem::ExtensionKey>::iterator iter = ids.begin();
429 iter != ids.end();
430 ++iter) {
431 const Extension* extension =
432 service->GetExtensionById(iter->extension_id, false);
433 // Platform apps have their context menus created directly in
434 // AppendPlatformAppItems.
435 if (extension && !extension->is_platform_app()) {
436 base::string16 menu_title = extension_items_.GetTopLevelContextMenuTitle(
437 *iter, printable_selection_text);
438 map_ids[menu_title] = iter->extension_id;
439 sorted_menu_titles.push_back(menu_title);
442 if (sorted_menu_titles.empty())
443 return;
445 const std::string app_locale = g_browser_process->GetApplicationLocale();
446 l10n_util::SortStrings16(app_locale, &sorted_menu_titles);
448 int index = 0;
449 for (size_t i = 0; i < sorted_menu_titles.size(); ++i) {
450 const std::string& id = map_ids[sorted_menu_titles[i]];
451 const MenuItem::ExtensionKey extension_key(id);
452 extension_items_.AppendExtensionItems(extension_key,
453 printable_selection_text,
454 &index,
455 false); // is_action_menu
459 void RenderViewContextMenu::AppendCurrentExtensionItems() {
460 // Avoid appending extension related items when |extension| is null.
461 // For Panel, this happens when the panel is navigated to a url outside of the
462 // extension's package.
463 const Extension* extension = GetExtension();
464 if (extension) {
465 // Only add extension items from this extension.
466 int index = 0;
467 const MenuItem::ExtensionKey key(
468 extension->id(),
469 extensions::WebViewGuest::GetViewInstanceId(source_web_contents_));
470 extension_items_.AppendExtensionItems(key,
471 PrintableSelectionText(),
472 &index,
473 false); // is_action_menu
476 #endif // defined(ENABLE_EXTENSIONS)
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_PRINT_PREVIEW)
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 return extensions::ProcessManager::Get(browser_context_)
629 ->GetExtensionForRenderViewHost(
630 source_web_contents_->GetRenderViewHost());
633 void RenderViewContextMenu::AppendDeveloperItems() {
634 // Show Inspect Element in DevTools itself only in case of the debug
635 // devtools build.
636 bool show_developer_items = !IsDevToolsURL(params_.page_url);
638 #if defined(DEBUG_DEVTOOLS)
639 show_developer_items = true;
640 #endif
642 if (!show_developer_items)
643 return;
645 // In the DevTools popup menu, "developer items" is normally the only
646 // section, so omit the separator there.
647 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
648 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTELEMENT,
649 IDS_CONTENT_CONTEXT_INSPECTELEMENT);
652 void RenderViewContextMenu::AppendDevtoolsForUnpackedExtensions() {
653 // Add a separator if there are any items already in the menu.
654 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
656 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP,
657 IDS_CONTENT_CONTEXT_RELOAD_PACKAGED_APP);
658 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP,
659 IDS_CONTENT_CONTEXT_RESTART_APP);
660 AppendDeveloperItems();
661 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE,
662 IDS_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE);
665 void RenderViewContextMenu::AppendLinkItems() {
666 if (!params_.link_url.is_empty()) {
667 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB,
668 IDS_CONTENT_CONTEXT_OPENLINKNEWTAB);
669 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW,
670 IDS_CONTENT_CONTEXT_OPENLINKNEWWINDOW);
671 if (params_.link_url.is_valid()) {
672 AppendProtocolHandlerSubMenu();
675 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD,
676 IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD);
677 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVELINKAS,
678 IDS_CONTENT_CONTEXT_SAVELINKAS);
681 menu_model_.AddItemWithStringId(
682 IDC_CONTENT_CONTEXT_COPYLINKLOCATION,
683 params_.link_url.SchemeIs(url::kMailToScheme) ?
684 IDS_CONTENT_CONTEXT_COPYEMAILADDRESS :
685 IDS_CONTENT_CONTEXT_COPYLINKLOCATION);
688 void RenderViewContextMenu::AppendImageItems() {
689 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS,
690 IDS_CONTENT_CONTEXT_SAVEIMAGEAS);
691 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGELOCATION,
692 IDS_CONTENT_CONTEXT_COPYIMAGELOCATION);
693 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
694 IDS_CONTENT_CONTEXT_COPYIMAGE);
695 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB,
696 IDS_CONTENT_CONTEXT_OPENIMAGENEWTAB);
699 void RenderViewContextMenu::AppendSearchWebForImageItems() {
700 TemplateURLService* service =
701 TemplateURLServiceFactory::GetForProfile(GetProfile());
702 const TemplateURL* const default_provider =
703 service->GetDefaultSearchProvider();
704 if (params_.has_image_contents && default_provider &&
705 !default_provider->image_url().empty() &&
706 default_provider->image_url_ref().IsValid(service->search_terms_data())) {
707 menu_model_.AddItem(
708 IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE,
709 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFORIMAGE,
710 default_provider->short_name()));
714 void RenderViewContextMenu::AppendAudioItems() {
715 AppendMediaItems();
716 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
717 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
718 IDS_CONTENT_CONTEXT_SAVEAUDIOAS);
719 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
720 IDS_CONTENT_CONTEXT_COPYAUDIOLOCATION);
721 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
722 IDS_CONTENT_CONTEXT_OPENAUDIONEWTAB);
725 void RenderViewContextMenu::AppendCanvasItems() {
726 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS,
727 IDS_CONTENT_CONTEXT_SAVEIMAGEAS);
728 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
729 IDS_CONTENT_CONTEXT_COPYIMAGE);
732 void RenderViewContextMenu::AppendVideoItems() {
733 AppendMediaItems();
734 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
735 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
736 IDS_CONTENT_CONTEXT_SAVEVIDEOAS);
737 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
738 IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION);
739 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
740 IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB);
743 void RenderViewContextMenu::AppendMediaItems() {
744 int media_flags = params_.media_flags;
746 menu_model_.AddItemWithStringId(
747 IDC_CONTENT_CONTEXT_PLAYPAUSE,
748 media_flags & WebContextMenuData::MediaPaused ?
749 IDS_CONTENT_CONTEXT_PLAY :
750 IDS_CONTENT_CONTEXT_PAUSE);
752 menu_model_.AddItemWithStringId(
753 IDC_CONTENT_CONTEXT_MUTE,
754 media_flags & WebContextMenuData::MediaMuted ?
755 IDS_CONTENT_CONTEXT_UNMUTE :
756 IDS_CONTENT_CONTEXT_MUTE);
758 menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_LOOP,
759 IDS_CONTENT_CONTEXT_LOOP);
760 menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_CONTROLS,
761 IDS_CONTENT_CONTEXT_CONTROLS);
764 void RenderViewContextMenu::AppendPluginItems() {
765 if (params_.page_url == params_.src_url ||
766 extensions::GuestViewBase::IsGuest(source_web_contents_)) {
767 // Full page plugin, so show page menu items.
768 if (params_.link_url.is_empty() && params_.selection_text.empty())
769 AppendPageItems();
770 } else {
771 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
772 IDS_CONTENT_CONTEXT_SAVEPAGEAS);
773 // The "Print" menu item should always be included for plugins. If
774 // content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT)
775 // is true the item will be added inside AppendPrintItem(). Otherwise we
776 // add "Print" here.
777 if (!content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT))
778 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
782 void RenderViewContextMenu::AppendPageItems() {
783 menu_model_.AddItemWithStringId(IDC_BACK, IDS_CONTENT_CONTEXT_BACK);
784 menu_model_.AddItemWithStringId(IDC_FORWARD, IDS_CONTENT_CONTEXT_FORWARD);
785 menu_model_.AddItemWithStringId(IDC_RELOAD, IDS_CONTENT_CONTEXT_RELOAD);
786 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
787 menu_model_.AddItemWithStringId(IDC_SAVE_PAGE,
788 IDS_CONTENT_CONTEXT_SAVEPAGEAS);
789 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
791 if (TranslateService::IsTranslatableURL(params_.page_url)) {
792 std::string locale = g_browser_process->GetApplicationLocale();
793 locale = translate::TranslateDownloadManager::GetLanguageCode(locale);
794 base::string16 language =
795 l10n_util::GetDisplayNameForLocale(locale, locale, true);
796 menu_model_.AddItem(
797 IDC_CONTENT_CONTEXT_TRANSLATE,
798 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_TRANSLATE, language));
801 menu_model_.AddItemWithStringId(IDC_VIEW_SOURCE,
802 IDS_CONTENT_CONTEXT_VIEWPAGESOURCE);
803 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWPAGEINFO,
804 IDS_CONTENT_CONTEXT_VIEWPAGEINFO);
807 void RenderViewContextMenu::AppendFrameItems() {
808 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOADFRAME,
809 IDS_CONTENT_CONTEXT_RELOADFRAME);
810 // These two menu items have yet to be implemented.
811 // http://code.google.com/p/chromium/issues/detail?id=11827
812 // IDS_CONTENT_CONTEXT_SAVEFRAMEAS
813 // IDS_CONTENT_CONTEXT_PRINTFRAME
814 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE,
815 IDS_CONTENT_CONTEXT_VIEWFRAMESOURCE);
816 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMEINFO,
817 IDS_CONTENT_CONTEXT_VIEWFRAMEINFO);
820 void RenderViewContextMenu::AppendCopyItem() {
821 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
822 IDS_CONTENT_CONTEXT_COPY);
825 void RenderViewContextMenu::AppendPrintItem() {
826 if (GetPrefs(browser_context_)->GetBoolean(prefs::kPrintingEnabled) &&
827 (params_.media_type == WebContextMenuData::MediaTypeNone ||
828 params_.media_flags & WebContextMenuData::MediaCanPrint)) {
829 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
833 void RenderViewContextMenu::AppendRotationItems() {
834 if (params_.media_flags & WebContextMenuData::MediaCanRotate) {
835 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
836 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECW,
837 IDS_CONTENT_CONTEXT_ROTATECW);
838 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECCW,
839 IDS_CONTENT_CONTEXT_ROTATECCW);
843 void RenderViewContextMenu::AppendSearchProvider() {
844 DCHECK(browser_context_);
846 base::TrimWhitespace(params_.selection_text, base::TRIM_ALL,
847 &params_.selection_text);
848 if (params_.selection_text.empty())
849 return;
851 base::ReplaceChars(params_.selection_text, AutocompleteMatch::kInvalidChars,
852 base::ASCIIToUTF16(" "), &params_.selection_text);
854 AutocompleteMatch match;
855 AutocompleteClassifierFactory::GetForProfile(GetProfile())->Classify(
856 params_.selection_text,
857 false,
858 false,
859 metrics::OmniboxEventProto::INVALID_SPEC,
860 &match,
861 NULL);
862 selection_navigation_url_ = match.destination_url;
863 if (!selection_navigation_url_.is_valid())
864 return;
866 base::string16 printable_selection_text = PrintableSelectionText();
867 EscapeAmpersands(&printable_selection_text);
869 if (AutocompleteMatch::IsSearchType(match.type)) {
870 const TemplateURL* const default_provider =
871 TemplateURLServiceFactory::GetForProfile(GetProfile())
872 ->GetDefaultSearchProvider();
873 if (!default_provider)
874 return;
875 menu_model_.AddItem(
876 IDC_CONTENT_CONTEXT_SEARCHWEBFOR,
877 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFOR,
878 default_provider->short_name(),
879 printable_selection_text));
880 } else {
881 if ((selection_navigation_url_ != params_.link_url) &&
882 ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme(
883 selection_navigation_url_.scheme())) {
884 menu_model_.AddItem(
885 IDC_CONTENT_CONTEXT_GOTOURL,
886 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_GOTOURL,
887 printable_selection_text));
892 void RenderViewContextMenu::AppendEditableItems() {
893 const bool use_spellcheck_and_search = !chrome::IsRunningInForcedAppMode();
895 if (use_spellcheck_and_search)
896 AppendSpellingSuggestionsSubMenu();
898 if (!IsDevToolsURL(params_.page_url)) {
899 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_UNDO,
900 IDS_CONTENT_CONTEXT_UNDO);
901 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_REDO,
902 IDS_CONTENT_CONTEXT_REDO);
903 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
906 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_CUT,
907 IDS_CONTENT_CONTEXT_CUT);
908 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
909 IDS_CONTENT_CONTEXT_COPY);
910 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE,
911 IDS_CONTENT_CONTEXT_PASTE);
912 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE,
913 IDS_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE);
914 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_DELETE,
915 IDS_CONTENT_CONTEXT_DELETE);
916 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
918 if (use_spellcheck_and_search && !params_.keyword_url.is_empty()) {
919 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ADDSEARCHENGINE,
920 IDS_CONTENT_CONTEXT_ADDSEARCHENGINE);
921 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
924 if (use_spellcheck_and_search)
925 AppendSpellcheckOptionsSubMenu();
926 AppendPlatformEditableItems();
928 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
929 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SELECTALL,
930 IDS_CONTENT_CONTEXT_SELECTALL);
933 void RenderViewContextMenu::AppendSpellingSuggestionsSubMenu() {
934 if (!spelling_menu_observer_.get())
935 spelling_menu_observer_.reset(new SpellingMenuObserver(this));
936 observers_.AddObserver(spelling_menu_observer_.get());
937 spelling_menu_observer_->InitMenu(params_);
940 void RenderViewContextMenu::AppendSpellcheckOptionsSubMenu() {
941 if (!spellchecker_submenu_observer_.get()) {
942 spellchecker_submenu_observer_.reset(new SpellCheckerSubMenuObserver(
943 this, this, kSpellcheckRadioGroup));
945 spellchecker_submenu_observer_->InitMenu(params_);
946 observers_.AddObserver(spellchecker_submenu_observer_.get());
949 void RenderViewContextMenu::AppendProtocolHandlerSubMenu() {
950 const ProtocolHandlerRegistry::ProtocolHandlerList handlers =
951 GetHandlersForLinkUrl();
952 if (handlers.empty())
953 return;
954 size_t max = IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST -
955 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
956 for (size_t i = 0; i < handlers.size() && i <= max; i++) {
957 protocol_handler_submenu_model_.AddItem(
958 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST + i,
959 base::UTF8ToUTF16(handlers[i].url().host()));
961 protocol_handler_submenu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
962 protocol_handler_submenu_model_.AddItem(
963 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS,
964 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH_CONFIGURE));
966 menu_model_.AddSubMenu(
967 IDC_CONTENT_CONTEXT_OPENLINKWITH,
968 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH),
969 &protocol_handler_submenu_model_);
972 // Menu delegate functions -----------------------------------------------------
974 bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
976 bool enabled = false;
977 if (RenderViewContextMenuBase::IsCommandIdKnown(id, &enabled))
978 return enabled;
981 CoreTabHelper* core_tab_helper =
982 CoreTabHelper::FromWebContents(source_web_contents_);
983 int content_restrictions = 0;
984 if (core_tab_helper)
985 content_restrictions = core_tab_helper->content_restrictions();
986 if (id == IDC_PRINT && (content_restrictions & CONTENT_RESTRICTION_PRINT))
987 return false;
989 if (id == IDC_SAVE_PAGE &&
990 (content_restrictions & CONTENT_RESTRICTION_SAVE)) {
991 return false;
994 PrefService* prefs = GetPrefs(browser_context_);
996 // Allow Spell Check language items on sub menu for text area context menu.
997 if ((id >= IDC_SPELLCHECK_LANGUAGES_FIRST) &&
998 (id < IDC_SPELLCHECK_LANGUAGES_LAST)) {
999 return prefs->GetBoolean(prefs::kEnableContinuousSpellcheck);
1002 // Extension items.
1003 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
1004 return extension_items_.IsCommandIdEnabled(id);
1006 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
1007 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
1008 return true;
1011 IncognitoModePrefs::Availability incognito_avail =
1012 IncognitoModePrefs::GetAvailability(prefs);
1013 switch (id) {
1014 case IDC_BACK:
1015 return embedder_web_contents_->GetController().CanGoBack();
1017 case IDC_FORWARD:
1018 return embedder_web_contents_->GetController().CanGoForward();
1020 case IDC_RELOAD: {
1021 CoreTabHelper* core_tab_helper =
1022 CoreTabHelper::FromWebContents(embedder_web_contents_);
1023 if (!core_tab_helper)
1024 return false;
1026 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
1027 return !core_delegate ||
1028 core_delegate->CanReloadContents(embedder_web_contents_);
1031 case IDC_VIEW_SOURCE:
1032 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
1033 return embedder_web_contents_->GetController().CanViewSource();
1035 case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
1036 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE:
1037 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP:
1038 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP:
1039 return IsDevCommandEnabled(id);
1041 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO:
1042 if (embedder_web_contents_->GetController().GetVisibleEntry() == NULL)
1043 return false;
1044 // Disabled if no browser is associated (e.g. desktop notifications).
1045 if (chrome::FindBrowserWithWebContents(embedder_web_contents_) == NULL)
1046 return false;
1047 return true;
1049 case IDC_CONTENT_CONTEXT_TRANSLATE: {
1050 ChromeTranslateClient* chrome_translate_client =
1051 ChromeTranslateClient::FromWebContents(embedder_web_contents_);
1052 if (!chrome_translate_client)
1053 return false;
1054 std::string original_lang =
1055 chrome_translate_client->GetLanguageState().original_language();
1056 std::string target_lang = g_browser_process->GetApplicationLocale();
1057 target_lang =
1058 translate::TranslateDownloadManager::GetLanguageCode(target_lang);
1059 // Note that we intentionally enable the menu even if the original and
1060 // target languages are identical. This is to give a way to user to
1061 // translate a page that might contains text fragments in a different
1062 // language.
1063 return ((params_.edit_flags & WebContextMenuData::CanTranslate) != 0) &&
1064 !original_lang.empty() && // Did we receive the page language yet?
1065 !chrome_translate_client->GetLanguageState().IsPageTranslated() &&
1066 !embedder_web_contents_->GetInterstitialPage() &&
1067 // There are some application locales which can't be used as a
1068 // target language for translation.
1069 translate::TranslateDownloadManager::IsSupportedLanguage(
1070 target_lang) &&
1071 // Disable on the Instant Extended NTP.
1072 !chrome::IsInstantNTP(embedder_web_contents_);
1075 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB:
1076 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
1077 return params_.link_url.is_valid();
1079 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
1080 return params_.unfiltered_link_url.is_valid();
1082 case IDC_CONTENT_CONTEXT_SAVELINKAS: {
1083 PrefService* local_state = g_browser_process->local_state();
1084 DCHECK(local_state);
1085 // Test if file-selection dialogs are forbidden by policy.
1086 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1087 return false;
1089 return params_.link_url.is_valid() &&
1090 ProfileIOData::IsHandledProtocol(params_.link_url.scheme());
1093 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: {
1094 PrefService* local_state = g_browser_process->local_state();
1095 DCHECK(local_state);
1096 // Test if file-selection dialogs are forbidden by policy.
1097 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1098 return false;
1100 return params_.has_image_contents;
1103 // The images shown in the most visited thumbnails can't be opened or
1104 // searched for conventionally.
1105 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
1106 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
1107 return params_.src_url.is_valid() &&
1108 (params_.src_url.scheme() != content::kChromeUIScheme);
1110 case IDC_CONTENT_CONTEXT_COPYIMAGE:
1111 return params_.has_image_contents;
1113 // Media control commands should all be disabled if the player is in an
1114 // error state.
1115 case IDC_CONTENT_CONTEXT_PLAYPAUSE:
1116 case IDC_CONTENT_CONTEXT_LOOP:
1117 return (params_.media_flags &
1118 WebContextMenuData::MediaInError) == 0;
1120 // Mute and unmute should also be disabled if the player has no audio.
1121 case IDC_CONTENT_CONTEXT_MUTE:
1122 return (params_.media_flags &
1123 WebContextMenuData::MediaHasAudio) != 0 &&
1124 (params_.media_flags &
1125 WebContextMenuData::MediaInError) == 0;
1127 case IDC_CONTENT_CONTEXT_CONTROLS:
1128 return (params_.media_flags &
1129 WebContextMenuData::MediaCanToggleControls) != 0;
1131 case IDC_CONTENT_CONTEXT_ROTATECW:
1132 case IDC_CONTENT_CONTEXT_ROTATECCW:
1133 return
1134 (params_.media_flags & WebContextMenuData::MediaCanRotate) != 0;
1136 case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
1137 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
1138 return params_.src_url.is_valid();
1140 case IDC_CONTENT_CONTEXT_SAVEAVAS: {
1141 PrefService* local_state = g_browser_process->local_state();
1142 DCHECK(local_state);
1143 // Test if file-selection dialogs are forbidden by policy.
1144 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1145 return false;
1147 const GURL& url = params_.src_url;
1148 bool can_save =
1149 (params_.media_flags & WebContextMenuData::MediaCanSave) &&
1150 url.is_valid() && ProfileIOData::IsHandledProtocol(url.scheme());
1151 #if defined(ENABLE_PRINT_PREVIEW)
1152 // Do not save the preview PDF on the print preview page.
1153 can_save = can_save &&
1154 !(printing::PrintPreviewDialogController::IsPrintPreviewURL(url));
1155 #endif
1156 return can_save;
1159 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
1160 // Currently, a media element can be opened in a new tab iff it can
1161 // be saved. So rather than duplicating the MediaCanSave flag, we rely
1162 // on that here.
1163 return !!(params_.media_flags & WebContextMenuData::MediaCanSave);
1165 case IDC_SAVE_PAGE: {
1166 CoreTabHelper* core_tab_helper =
1167 CoreTabHelper::FromWebContents(embedder_web_contents_);
1168 if (!core_tab_helper)
1169 return false;
1171 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
1172 if (core_delegate &&
1173 !core_delegate->CanSaveContents(embedder_web_contents_))
1174 return false;
1176 PrefService* local_state = g_browser_process->local_state();
1177 DCHECK(local_state);
1178 // Test if file-selection dialogs are forbidden by policy.
1179 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1180 return false;
1182 // We save the last committed entry (which the user is looking at), as
1183 // opposed to any pending URL that hasn't committed yet.
1184 NavigationEntry* entry =
1185 embedder_web_contents_->GetController().GetLastCommittedEntry();
1186 return content::IsSavableURL(entry ? entry->GetURL() : GURL());
1189 case IDC_CONTENT_CONTEXT_RELOADFRAME:
1190 return params_.frame_url.is_valid();
1192 case IDC_CONTENT_CONTEXT_UNDO:
1193 return !!(params_.edit_flags & WebContextMenuData::CanUndo);
1195 case IDC_CONTENT_CONTEXT_REDO:
1196 return !!(params_.edit_flags & WebContextMenuData::CanRedo);
1198 case IDC_CONTENT_CONTEXT_CUT:
1199 return !!(params_.edit_flags & WebContextMenuData::CanCut);
1201 case IDC_CONTENT_CONTEXT_COPY:
1202 return !!(params_.edit_flags & WebContextMenuData::CanCopy);
1204 case IDC_CONTENT_CONTEXT_PASTE: {
1205 if (!(params_.edit_flags & WebContextMenuData::CanPaste))
1206 return false;
1208 std::vector<base::string16> types;
1209 bool ignore;
1210 ui::Clipboard::GetForCurrentThread()->ReadAvailableTypes(
1211 ui::CLIPBOARD_TYPE_COPY_PASTE, &types, &ignore);
1212 return !types.empty();
1215 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE: {
1216 if (!(params_.edit_flags & WebContextMenuData::CanPaste))
1217 return false;
1219 return ui::Clipboard::GetForCurrentThread()->IsFormatAvailable(
1220 ui::Clipboard::GetPlainTextFormatType(),
1221 ui::CLIPBOARD_TYPE_COPY_PASTE);
1224 case IDC_CONTENT_CONTEXT_DELETE:
1225 return !!(params_.edit_flags & WebContextMenuData::CanDelete);
1227 case IDC_CONTENT_CONTEXT_SELECTALL:
1228 return !!(params_.edit_flags & WebContextMenuData::CanSelectAll);
1230 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
1231 return !browser_context_->IsOffTheRecord() &&
1232 params_.link_url.is_valid() &&
1233 incognito_avail != IncognitoModePrefs::DISABLED;
1235 case IDC_PRINT:
1236 return prefs->GetBoolean(prefs::kPrintingEnabled) &&
1237 (params_.media_type == WebContextMenuData::MediaTypeNone ||
1238 params_.media_flags & WebContextMenuData::MediaCanPrint);
1240 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
1241 case IDC_CONTENT_CONTEXT_GOTOURL:
1242 case IDC_SPELLPANEL_TOGGLE:
1243 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS:
1244 return true;
1245 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO:
1246 // Disabled if no browser is associated (e.g. desktop notifications).
1247 if (chrome::FindBrowserWithWebContents(source_web_contents_) == NULL)
1248 return false;
1249 return true;
1251 case IDC_CHECK_SPELLING_WHILE_TYPING:
1252 return prefs->GetBoolean(prefs::kEnableContinuousSpellcheck);
1254 #if !defined(OS_MACOSX) && defined(OS_POSIX)
1255 // TODO(suzhe): this should not be enabled for password fields.
1256 case IDC_INPUT_METHODS_MENU:
1257 return true;
1258 #endif
1260 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE:
1261 return !params_.keyword_url.is_empty();
1263 case IDC_SPELLCHECK_MENU:
1264 return true;
1266 case IDC_CONTENT_CONTEXT_OPENLINKWITH:
1267 return true;
1269 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS:
1270 return true;
1272 default:
1273 NOTREACHED();
1274 return false;
1278 bool RenderViewContextMenu::IsCommandIdChecked(int id) const {
1279 if (RenderViewContextMenuBase::IsCommandIdChecked(id))
1280 return true;
1282 // See if the video is set to looping.
1283 if (id == IDC_CONTENT_CONTEXT_LOOP)
1284 return (params_.media_flags & WebContextMenuData::MediaLoop) != 0;
1286 if (id == IDC_CONTENT_CONTEXT_CONTROLS)
1287 return (params_.media_flags & WebContextMenuData::MediaControls) != 0;
1289 // Extension items.
1290 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
1291 return extension_items_.IsCommandIdChecked(id);
1293 return false;
1296 void RenderViewContextMenu::ExecuteCommand(int id, int event_flags) {
1297 RenderViewContextMenuBase::ExecuteCommand(id, event_flags);
1298 if (command_executed_)
1299 return;
1300 command_executed_ = true;
1302 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1304 // Process extension menu items.
1305 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id)) {
1306 extension_items_.ExecuteCommand(id, source_web_contents_, params_);
1307 return;
1310 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
1311 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
1312 ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1313 GetHandlersForLinkUrl();
1314 if (handlers.empty())
1315 return;
1317 content::RecordAction(
1318 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Open"));
1319 int handlerIndex = id - IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
1320 WindowOpenDisposition disposition =
1321 ForceNewTabDispositionFromEventFlags(event_flags);
1322 OpenURL(handlers[handlerIndex].TranslateUrl(params_.link_url),
1323 GetDocumentURL(params_),
1324 disposition,
1325 ui::PAGE_TRANSITION_LINK);
1326 return;
1329 switch (id) {
1330 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB: {
1331 Browser* browser =
1332 chrome::FindBrowserWithWebContents(source_web_contents_);
1333 OpenURL(params_.link_url,
1334 GetDocumentURL(params_),
1335 !browser || browser->is_app() ?
1336 NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB,
1337 ui::PAGE_TRANSITION_LINK);
1338 break;
1340 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
1341 OpenURL(params_.link_url,
1342 GetDocumentURL(params_),
1343 NEW_WINDOW,
1344 ui::PAGE_TRANSITION_LINK);
1345 break;
1347 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
1348 OpenURL(params_.link_url, GURL(), OFF_THE_RECORD,
1349 ui::PAGE_TRANSITION_LINK);
1350 break;
1352 case IDC_CONTENT_CONTEXT_SAVELINKAS: {
1353 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
1354 const GURL& url = params_.link_url;
1355 content::Referrer referrer = CreateSaveAsReferrer(url, params_);
1356 DownloadManager* dlm =
1357 BrowserContext::GetDownloadManager(browser_context_);
1358 scoped_ptr<DownloadUrlParameters> dl_params(
1359 DownloadUrlParameters::FromWebContents(source_web_contents_, url));
1360 dl_params->set_referrer(referrer);
1361 dl_params->set_referrer_encoding(params_.frame_charset);
1362 dl_params->set_suggested_name(params_.suggested_filename);
1363 dl_params->set_prompt(true);
1364 dlm->DownloadUrl(dl_params.Pass());
1365 break;
1368 case IDC_CONTENT_CONTEXT_SAVEAVAS:
1369 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: {
1370 bool is_large_data_url = params_.has_image_contents &&
1371 params_.src_url.is_empty();
1372 if (params_.media_type == WebContextMenuData::MediaTypeCanvas ||
1373 (params_.media_type == WebContextMenuData::MediaTypeImage &&
1374 is_large_data_url)) {
1375 source_web_contents_->GetRenderViewHost()->SaveImageAt(
1376 params_.x, params_.y);
1377 } else {
1378 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
1379 const GURL& url = params_.src_url;
1380 content::Referrer referrer = CreateSaveAsReferrer(url, params_);
1381 source_web_contents_->SaveFrame(url, referrer);
1383 break;
1386 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
1387 WriteURLToClipboard(params_.unfiltered_link_url);
1388 break;
1390 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
1391 case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
1392 WriteURLToClipboard(params_.src_url);
1393 break;
1395 case IDC_CONTENT_CONTEXT_COPYIMAGE:
1396 CopyImageAt(params_.x, params_.y);
1397 break;
1399 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
1400 GetImageThumbnailForSearch();
1401 break;
1403 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
1404 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
1405 OpenURL(params_.src_url,
1406 GetDocumentURL(params_),
1407 NEW_BACKGROUND_TAB,
1408 ui::PAGE_TRANSITION_LINK);
1409 break;
1411 case IDC_CONTENT_CONTEXT_PLAYPAUSE: {
1412 bool play = !!(params_.media_flags & WebContextMenuData::MediaPaused);
1413 if (play) {
1414 content::RecordAction(UserMetricsAction("MediaContextMenu_Play"));
1415 } else {
1416 content::RecordAction(UserMetricsAction("MediaContextMenu_Pause"));
1418 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1419 WebMediaPlayerAction(
1420 WebMediaPlayerAction::Play, play));
1421 break;
1424 case IDC_CONTENT_CONTEXT_MUTE: {
1425 bool mute = !(params_.media_flags & WebContextMenuData::MediaMuted);
1426 if (mute) {
1427 content::RecordAction(UserMetricsAction("MediaContextMenu_Mute"));
1428 } else {
1429 content::RecordAction(UserMetricsAction("MediaContextMenu_Unmute"));
1431 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1432 WebMediaPlayerAction(
1433 WebMediaPlayerAction::Mute, mute));
1434 break;
1437 case IDC_CONTENT_CONTEXT_LOOP:
1438 content::RecordAction(UserMetricsAction("MediaContextMenu_Loop"));
1439 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1440 WebMediaPlayerAction(
1441 WebMediaPlayerAction::Loop,
1442 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_LOOP)));
1443 break;
1445 case IDC_CONTENT_CONTEXT_CONTROLS:
1446 content::RecordAction(UserMetricsAction("MediaContextMenu_Controls"));
1447 MediaPlayerActionAt(
1448 gfx::Point(params_.x, params_.y),
1449 WebMediaPlayerAction(
1450 WebMediaPlayerAction::Controls,
1451 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_CONTROLS)));
1452 break;
1454 case IDC_CONTENT_CONTEXT_ROTATECW:
1455 content::RecordAction(
1456 UserMetricsAction("PluginContextMenu_RotateClockwise"));
1457 PluginActionAt(
1458 gfx::Point(params_.x, params_.y),
1459 WebPluginAction(WebPluginAction::Rotate90Clockwise, true));
1460 break;
1462 case IDC_CONTENT_CONTEXT_ROTATECCW:
1463 content::RecordAction(
1464 UserMetricsAction("PluginContextMenu_RotateCounterclockwise"));
1465 PluginActionAt(
1466 gfx::Point(params_.x, params_.y),
1467 WebPluginAction(WebPluginAction::Rotate90Counterclockwise, true));
1468 break;
1470 case IDC_BACK:
1471 embedder_web_contents_->GetController().GoBack();
1472 break;
1474 case IDC_FORWARD:
1475 embedder_web_contents_->GetController().GoForward();
1476 break;
1478 case IDC_SAVE_PAGE:
1479 embedder_web_contents_->OnSavePage();
1480 break;
1482 case IDC_RELOAD:
1483 embedder_web_contents_->GetController().Reload(true);
1484 break;
1486 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP: {
1487 const Extension* platform_app = GetExtension();
1488 DCHECK(platform_app);
1489 DCHECK(platform_app->is_platform_app());
1491 extensions::ExtensionSystem::Get(browser_context_)
1492 ->extension_service()
1493 ->ReloadExtension(platform_app->id());
1494 break;
1497 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP: {
1498 const Extension* platform_app = GetExtension();
1499 DCHECK(platform_app);
1500 DCHECK(platform_app->is_platform_app());
1502 apps::AppLoadService::Get(GetProfile())
1503 ->RestartApplication(platform_app->id());
1504 break;
1507 case IDC_PRINT: {
1508 #if defined(ENABLE_PRINTING)
1509 if (params_.media_type != WebContextMenuData::MediaTypeNone) {
1510 if (render_frame_host) {
1511 render_frame_host->Send(new PrintMsg_PrintNodeUnderContextMenu(
1512 render_frame_host->GetRoutingID()));
1514 break;
1517 printing::StartPrint(
1518 source_web_contents_,
1519 GetPrefs(browser_context_)->GetBoolean(prefs::kPrintPreviewDisabled),
1520 !params_.selection_text.empty());
1521 #endif // ENABLE_PRINTING
1522 break;
1525 case IDC_VIEW_SOURCE:
1526 embedder_web_contents_->ViewSource();
1527 break;
1529 case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
1530 Inspect(params_.x, params_.y);
1531 break;
1533 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE: {
1534 const Extension* platform_app = GetExtension();
1535 DCHECK(platform_app);
1536 DCHECK(platform_app->is_platform_app());
1538 extensions::devtools_util::InspectBackgroundPage(platform_app,
1539 GetProfile());
1540 break;
1543 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO: {
1544 NavigationController* controller =
1545 &embedder_web_contents_->GetController();
1546 // Important to use GetVisibleEntry to match what's showing in the
1547 // omnibox. This may return null.
1548 NavigationEntry* nav_entry = controller->GetVisibleEntry();
1549 if (!nav_entry)
1550 return;
1551 Browser* browser =
1552 chrome::FindBrowserWithWebContents(embedder_web_contents_);
1553 chrome::ShowWebsiteSettings(browser, embedder_web_contents_,
1554 nav_entry->GetURL(), nav_entry->GetSSL());
1555 break;
1558 case IDC_CONTENT_CONTEXT_TRANSLATE: {
1559 // A translation might have been triggered by the time the menu got
1560 // selected, do nothing in that case.
1561 ChromeTranslateClient* chrome_translate_client =
1562 ChromeTranslateClient::FromWebContents(embedder_web_contents_);
1563 if (!chrome_translate_client ||
1564 chrome_translate_client->GetLanguageState().IsPageTranslated() ||
1565 chrome_translate_client->GetLanguageState().translation_pending()) {
1566 return;
1568 std::string original_lang =
1569 chrome_translate_client->GetLanguageState().original_language();
1570 std::string target_lang = g_browser_process->GetApplicationLocale();
1571 target_lang =
1572 translate::TranslateDownloadManager::GetLanguageCode(target_lang);
1573 // Since the user decided to translate for that language and site, clears
1574 // any preferences for not translating them.
1575 scoped_ptr<translate::TranslatePrefs> prefs(
1576 ChromeTranslateClient::CreateTranslatePrefs(
1577 GetPrefs(browser_context_)));
1578 prefs->UnblockLanguage(original_lang);
1579 prefs->RemoveSiteFromBlacklist(params_.page_url.HostNoBrackets());
1580 translate::TranslateManager* manager =
1581 chrome_translate_client->GetTranslateManager();
1582 DCHECK(manager);
1583 manager->TranslatePage(original_lang, target_lang, true);
1584 break;
1587 case IDC_CONTENT_CONTEXT_RELOADFRAME:
1588 // We always obey the cache here.
1589 // TODO(evanm): Perhaps we could allow shift-clicking the menu item to do
1590 // a cache-ignoring reload of the frame.
1591 source_web_contents_->ReloadFocusedFrame(false);
1592 break;
1594 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
1595 source_web_contents_->ViewFrameSource(params_.frame_url,
1596 params_.frame_page_state);
1597 break;
1599 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO: {
1600 Browser* browser = chrome::FindBrowserWithWebContents(
1601 source_web_contents_);
1602 chrome::ShowWebsiteSettings(browser, source_web_contents_,
1603 params_.frame_url, params_.security_info);
1604 break;
1607 case IDC_CONTENT_CONTEXT_UNDO:
1608 source_web_contents_->Undo();
1609 break;
1611 case IDC_CONTENT_CONTEXT_REDO:
1612 source_web_contents_->Redo();
1613 break;
1615 case IDC_CONTENT_CONTEXT_CUT:
1616 source_web_contents_->Cut();
1617 break;
1619 case IDC_CONTENT_CONTEXT_COPY:
1620 source_web_contents_->Copy();
1621 break;
1623 case IDC_CONTENT_CONTEXT_PASTE:
1624 source_web_contents_->Paste();
1625 break;
1627 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE:
1628 source_web_contents_->PasteAndMatchStyle();
1629 break;
1631 case IDC_CONTENT_CONTEXT_DELETE:
1632 source_web_contents_->Delete();
1633 break;
1635 case IDC_CONTENT_CONTEXT_SELECTALL:
1636 source_web_contents_->SelectAll();
1637 break;
1639 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
1640 case IDC_CONTENT_CONTEXT_GOTOURL: {
1641 WindowOpenDisposition disposition =
1642 ForceNewTabDispositionFromEventFlags(event_flags);
1643 OpenURL(selection_navigation_url_, GURL(), disposition,
1644 ui::PAGE_TRANSITION_LINK);
1645 break;
1647 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS: {
1648 WindowOpenDisposition disposition =
1649 ForceNewTabDispositionFromEventFlags(event_flags);
1650 GURL url = chrome::GetSettingsUrl(chrome::kLanguageOptionsSubPage);
1651 OpenURL(url, GURL(), disposition, ui::PAGE_TRANSITION_LINK);
1652 break;
1655 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS: {
1656 content::RecordAction(
1657 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Settings"));
1658 WindowOpenDisposition disposition =
1659 ForceNewTabDispositionFromEventFlags(event_flags);
1660 GURL url = chrome::GetSettingsUrl(chrome::kHandlerSettingsSubPage);
1661 OpenURL(url, GURL(), disposition, ui::PAGE_TRANSITION_LINK);
1662 break;
1665 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE: {
1666 // Make sure the model is loaded.
1667 TemplateURLService* model =
1668 TemplateURLServiceFactory::GetForProfile(GetProfile());
1669 if (!model)
1670 return;
1671 model->Load();
1673 SearchEngineTabHelper* search_engine_tab_helper =
1674 SearchEngineTabHelper::FromWebContents(source_web_contents_);
1675 if (search_engine_tab_helper &&
1676 search_engine_tab_helper->delegate()) {
1677 base::string16 keyword(TemplateURL::GenerateKeyword(params_.page_url));
1678 TemplateURLData data;
1679 data.short_name = keyword;
1680 data.SetKeyword(keyword);
1681 data.SetURL(params_.keyword_url.spec());
1682 data.favicon_url =
1683 TemplateURL::GenerateFaviconURL(params_.page_url.GetOrigin());
1684 // Takes ownership of the TemplateURL.
1685 search_engine_tab_helper->delegate()->ConfirmAddSearchProvider(
1686 new TemplateURL(data), GetProfile());
1688 break;
1691 default:
1692 NOTREACHED();
1693 break;
1697 ProtocolHandlerRegistry::ProtocolHandlerList
1698 RenderViewContextMenu::GetHandlersForLinkUrl() {
1699 ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1700 protocol_handler_registry_->GetHandlersFor(params_.link_url.scheme());
1701 std::sort(handlers.begin(), handlers.end());
1702 return handlers;
1705 void RenderViewContextMenu::NotifyMenuShown() {
1706 content::NotificationService::current()->Notify(
1707 chrome::NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN,
1708 content::Source<RenderViewContextMenu>(this),
1709 content::NotificationService::NoDetails());
1712 void RenderViewContextMenu::NotifyURLOpened(
1713 const GURL& url,
1714 content::WebContents* new_contents) {
1715 RetargetingDetails details;
1716 details.source_web_contents = source_web_contents_;
1717 // Don't use GetRenderFrameHost() as it may be NULL. crbug.com/399789
1718 details.source_render_frame_id = render_frame_id_;
1719 details.target_url = url;
1720 details.target_web_contents = new_contents;
1721 details.not_yet_in_tabstrip = false;
1723 content::NotificationService::current()->Notify(
1724 chrome::NOTIFICATION_RETARGETING,
1725 content::Source<Profile>(GetProfile()),
1726 content::Details<RetargetingDetails>(&details));
1729 bool RenderViewContextMenu::IsDevCommandEnabled(int id) const {
1730 if (id == IDC_CONTENT_CONTEXT_INSPECTELEMENT ||
1731 id == IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE) {
1732 if (!GetPrefs(browser_context_)
1733 ->GetBoolean(prefs::kWebKitJavascriptEnabled))
1734 return false;
1736 // Don't enable the web inspector if the developer tools are disabled via
1737 // the preference dev-tools-disabled.
1738 if (GetPrefs(browser_context_)->GetBoolean(prefs::kDevToolsDisabled))
1739 return false;
1742 return true;
1745 base::string16 RenderViewContextMenu::PrintableSelectionText() {
1746 return gfx::TruncateString(params_.selection_text,
1747 kMaxSelectionTextLength,
1748 gfx::WORD_BREAK);
1751 // Controller functions --------------------------------------------------------
1753 void RenderViewContextMenu::CopyImageAt(int x, int y) {
1754 source_web_contents_->GetRenderViewHost()->CopyImageAt(x, y);
1757 void RenderViewContextMenu::GetImageThumbnailForSearch() {
1758 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1759 if (!render_frame_host)
1760 return;
1761 render_frame_host->Send(new ChromeViewMsg_RequestThumbnailForContextNode(
1762 render_frame_host->GetRoutingID(),
1763 kImageSearchThumbnailMinSize,
1764 gfx::Size(kImageSearchThumbnailMaxWidth,
1765 kImageSearchThumbnailMaxHeight)));
1768 void RenderViewContextMenu::Inspect(int x, int y) {
1769 content::RecordAction(UserMetricsAction("DevTools_InspectElement"));
1770 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1771 if (!render_frame_host)
1772 return;
1773 DevToolsWindow::InspectElement(
1774 WebContents::FromRenderFrameHost(render_frame_host), x, y);
1777 void RenderViewContextMenu::WriteURLToClipboard(const GURL& url) {
1778 chrome_common_net::WriteURLToClipboard(
1779 url, GetPrefs(browser_context_)->GetString(prefs::kAcceptLanguages));
1782 void RenderViewContextMenu::MediaPlayerActionAt(
1783 const gfx::Point& location,
1784 const WebMediaPlayerAction& action) {
1785 source_web_contents_->GetRenderViewHost()->
1786 ExecuteMediaPlayerActionAtLocation(location, action);
1789 void RenderViewContextMenu::PluginActionAt(
1790 const gfx::Point& location,
1791 const WebPluginAction& action) {
1792 source_web_contents_->GetRenderViewHost()->
1793 ExecutePluginActionAtLocation(location, action);