Fire an error if a pref used in the UI is missing once all prefs are fetched.
[chromium-blink-merge.git] / chrome / browser / renderer_context_menu / render_view_context_menu.cc
blobe83ab0aab938e39ccd42cb85ca9161f11655f3e5
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
7 #include <algorithm>
8 #include <set>
9 #include <utility>
11 #include "apps/app_load_service.h"
12 #include "base/command_line.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram.h"
15 #include "base/prefs/pref_member.h"
16 #include "base/prefs/pref_service.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "chrome/app/chrome_command_ids.h"
22 #include "chrome/browser/app_mode/app_mode_utils.h"
23 #include "chrome/browser/autocomplete/autocomplete_classifier.h"
24 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
25 #include "chrome/browser/browser_process.h"
26 #include "chrome/browser/chrome_notification_types.h"
27 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
28 #include "chrome/browser/devtools/devtools_window.h"
29 #include "chrome/browser/download/download_service.h"
30 #include "chrome/browser/download/download_service_factory.h"
31 #include "chrome/browser/download/download_stats.h"
32 #include "chrome/browser/extensions/devtools_util.h"
33 #include "chrome/browser/extensions/extension_service.h"
34 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h"
35 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings_factory.h"
36 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
37 #include "chrome/browser/prefs/incognito_mode_prefs.h"
38 #include "chrome/browser/profiles/profile.h"
39 #include "chrome/browser/profiles/profile_io_data.h"
40 #include "chrome/browser/renderer_context_menu/context_menu_content_type_factory.h"
41 #include "chrome/browser/renderer_context_menu/spellchecker_submenu_observer.h"
42 #include "chrome/browser/renderer_context_menu/spelling_menu_observer.h"
43 #include "chrome/browser/search/search.h"
44 #include "chrome/browser/search_engines/template_url_service_factory.h"
45 #include "chrome/browser/spellchecker/spellcheck_host_metrics.h"
46 #include "chrome/browser/spellchecker/spellcheck_service.h"
47 #include "chrome/browser/tab_contents/retargeting_details.h"
48 #include "chrome/browser/translate/chrome_translate_client.h"
49 #include "chrome/browser/translate/translate_service.h"
50 #include "chrome/browser/ui/browser.h"
51 #include "chrome/browser/ui/browser_commands.h"
52 #include "chrome/browser/ui/browser_finder.h"
53 #include "chrome/browser/ui/chrome_pages.h"
54 #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"
55 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
56 #include "chrome/common/chrome_constants.h"
57 #include "chrome/common/chrome_switches.h"
58 #include "chrome/common/content_restriction.h"
59 #include "chrome/common/net/url_util.h"
60 #include "chrome/common/pref_names.h"
61 #include "chrome/common/render_messages.h"
62 #include "chrome/common/spellcheck_messages.h"
63 #include "chrome/common/url_constants.h"
64 #include "chrome/grit/generated_resources.h"
65 #include "components/google/core/browser/google_util.h"
66 #include "components/metrics/proto/omnibox_input_type.pb.h"
67 #include "components/omnibox/autocomplete_match.h"
68 #include "components/search_engines/template_url.h"
69 #include "components/search_engines/template_url_service.h"
70 #include "components/translate/core/browser/translate_download_manager.h"
71 #include "components/translate/core/browser/translate_manager.h"
72 #include "components/translate/core/browser/translate_prefs.h"
73 #include "components/user_prefs/user_prefs.h"
74 #include "content/public/browser/child_process_security_policy.h"
75 #include "content/public/browser/download_manager.h"
76 #include "content/public/browser/download_save_info.h"
77 #include "content/public/browser/download_url_parameters.h"
78 #include "content/public/browser/navigation_details.h"
79 #include "content/public/browser/navigation_entry.h"
80 #include "content/public/browser/notification_service.h"
81 #include "content/public/browser/render_frame_host.h"
82 #include "content/public/browser/render_process_host.h"
83 #include "content/public/browser/render_view_host.h"
84 #include "content/public/browser/render_widget_host_view.h"
85 #include "content/public/browser/user_metrics.h"
86 #include "content/public/browser/web_contents.h"
87 #include "content/public/common/menu_item.h"
88 #include "content/public/common/ssl_status.h"
89 #include "content/public/common/url_utils.h"
90 #include "extensions/browser/extension_host.h"
91 #include "extensions/browser/extension_system.h"
92 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
93 #include "extensions/browser/view_type_utils.h"
94 #include "extensions/common/extension.h"
95 #include "net/base/escape.h"
96 #include "third_party/WebKit/public/web/WebContextMenuData.h"
97 #include "third_party/WebKit/public/web/WebMediaPlayerAction.h"
98 #include "third_party/WebKit/public/web/WebPluginAction.h"
99 #include "ui/base/clipboard/clipboard.h"
100 #include "ui/base/l10n/l10n_util.h"
101 #include "ui/gfx/favicon_size.h"
102 #include "ui/gfx/geometry/point.h"
103 #include "ui/gfx/geometry/size.h"
104 #include "ui/gfx/text_elider.h"
106 #if defined(ENABLE_PRINTING)
107 #include "chrome/browser/printing/print_view_manager_common.h"
108 #include "components/printing/common/print_messages.h"
110 #if defined(ENABLE_PRINT_PREVIEW)
111 #include "chrome/browser/printing/print_preview_context_menu_observer.h"
112 #include "chrome/browser/printing/print_preview_dialog_controller.h"
113 #endif // defined(ENABLE_PRINT_PREVIEW)
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 {61, IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB},
215 // Add new items here and use |enum_id| from the next line.
216 {62, 0}, // Must be the last. Increment |enum_id| when new IDC was added.
219 // Collapses large ranges of ids before looking for UMA enum.
220 int CollapseCommandsForUMA(int id) {
221 DCHECK(!RenderViewContextMenu::IsContentCustomCommandId(id));
222 DCHECK(!ContextMenuMatcher::IsExtensionsCustomCommandId(id));
224 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
225 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
226 return IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
229 if (id >= IDC_SPELLCHECK_LANGUAGES_FIRST &&
230 id <= IDC_SPELLCHECK_LANGUAGES_LAST) {
231 return IDC_SPELLCHECK_LANGUAGES_FIRST;
234 if (id >= IDC_SPELLCHECK_SUGGESTION_0 &&
235 id <= IDC_SPELLCHECK_SUGGESTION_LAST) {
236 return IDC_SPELLCHECK_SUGGESTION_0;
239 return id;
242 // Returns UMA enum value for command specified by |id| or -1 if not found.
243 int FindUMAEnumValueForCommand(int id) {
244 if (RenderViewContextMenu::IsContentCustomCommandId(id))
245 return 0;
247 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
248 return 1;
250 id = CollapseCommandsForUMA(id);
251 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
252 for (size_t i = 0; i < kMappingSize; ++i) {
253 if (kUmaEnumToControlId[i].control_id == id) {
254 return kUmaEnumToControlId[i].enum_id;
257 return -1;
260 // Usually a new tab is expected where this function is used,
261 // however users should be able to open a tab in background
262 // or in a new window.
263 WindowOpenDisposition ForceNewTabDispositionFromEventFlags(
264 int event_flags) {
265 WindowOpenDisposition disposition =
266 ui::DispositionFromEventFlags(event_flags);
267 return disposition == CURRENT_TAB ? NEW_FOREGROUND_TAB : disposition;
270 // Helper function to escape "&" as "&&".
271 void EscapeAmpersands(base::string16* text) {
272 base::ReplaceChars(*text, base::ASCIIToUTF16("&"), base::ASCIIToUTF16("&&"),
273 text);
276 // Returns the preference of the profile represented by the |context|.
277 PrefService* GetPrefs(content::BrowserContext* context) {
278 return user_prefs::UserPrefs::Get(context);
281 bool ExtensionPatternMatch(const extensions::URLPatternSet& patterns,
282 const GURL& url) {
283 // No patterns means no restriction, so that implicitly matches.
284 if (patterns.is_empty())
285 return true;
286 return patterns.MatchesURL(url);
289 const GURL& GetDocumentURL(const content::ContextMenuParams& params) {
290 return params.frame_url.is_empty() ? params.page_url : params.frame_url;
293 content::Referrer CreateSaveAsReferrer(
294 const GURL& url,
295 const content::ContextMenuParams& params) {
296 const GURL& referring_url = GetDocumentURL(params);
297 return content::Referrer::SanitizeForRequest(
298 url,
299 content::Referrer(referring_url.GetAsReferrer(), params.referrer_policy));
302 bool g_custom_id_ranges_initialized = false;
304 const int kSpellcheckRadioGroup = 1;
306 } // namespace
308 // static
309 bool RenderViewContextMenu::IsDevToolsURL(const GURL& url) {
310 return url.SchemeIs(content::kChromeDevToolsScheme);
313 // static
314 bool RenderViewContextMenu::IsInternalResourcesURL(const GURL& url) {
315 if (!url.SchemeIs(content::kChromeUIScheme))
316 return false;
317 return url.host() == chrome::kChromeUISyncResourcesHost;
320 RenderViewContextMenu::RenderViewContextMenu(
321 content::RenderFrameHost* render_frame_host,
322 const content::ContextMenuParams& params)
323 : RenderViewContextMenuBase(render_frame_host, params),
324 extension_items_(browser_context_,
325 this,
326 &menu_model_,
327 base::Bind(MenuItemMatchesParams, params_)),
328 protocol_handler_submenu_model_(this),
329 protocol_handler_registry_(
330 ProtocolHandlerRegistryFactory::GetForBrowserContext(GetProfile())) {
331 if (!g_custom_id_ranges_initialized) {
332 g_custom_id_ranges_initialized = true;
333 SetContentCustomCommandIdRange(IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
334 IDC_CONTENT_CONTEXT_CUSTOM_LAST);
336 set_content_type(ContextMenuContentTypeFactory::Create(
337 source_web_contents_, params));
340 RenderViewContextMenu::~RenderViewContextMenu() {
343 // Menu construction functions -------------------------------------------------
345 #if defined(ENABLE_EXTENSIONS)
346 // static
347 bool RenderViewContextMenu::ExtensionContextAndPatternMatch(
348 const content::ContextMenuParams& params,
349 const MenuItem::ContextList& contexts,
350 const extensions::URLPatternSet& target_url_patterns) {
351 const bool has_link = !params.link_url.is_empty();
352 const bool has_selection = !params.selection_text.empty();
353 const bool in_frame = !params.frame_url.is_empty();
355 if (contexts.Contains(MenuItem::ALL) ||
356 (has_selection && contexts.Contains(MenuItem::SELECTION)) ||
357 (params.is_editable && contexts.Contains(MenuItem::EDITABLE)) ||
358 (in_frame && contexts.Contains(MenuItem::FRAME)))
359 return true;
361 if (has_link && contexts.Contains(MenuItem::LINK) &&
362 ExtensionPatternMatch(target_url_patterns, params.link_url))
363 return true;
365 switch (params.media_type) {
366 case WebContextMenuData::MediaTypeImage:
367 if (contexts.Contains(MenuItem::IMAGE) &&
368 ExtensionPatternMatch(target_url_patterns, params.src_url))
369 return true;
370 break;
372 case WebContextMenuData::MediaTypeVideo:
373 if (contexts.Contains(MenuItem::VIDEO) &&
374 ExtensionPatternMatch(target_url_patterns, params.src_url))
375 return true;
376 break;
378 case WebContextMenuData::MediaTypeAudio:
379 if (contexts.Contains(MenuItem::AUDIO) &&
380 ExtensionPatternMatch(target_url_patterns, params.src_url))
381 return true;
382 break;
384 default:
385 break;
388 // PAGE is the least specific context, so we only examine that if none of the
389 // other contexts apply (except for FRAME, which is included in PAGE for
390 // backwards compatibility).
391 if (!has_link && !has_selection && !params.is_editable &&
392 params.media_type == WebContextMenuData::MediaTypeNone &&
393 contexts.Contains(MenuItem::PAGE))
394 return true;
396 return false;
399 // static
400 bool RenderViewContextMenu::MenuItemMatchesParams(
401 const content::ContextMenuParams& params,
402 const extensions::MenuItem* item) {
403 bool match = ExtensionContextAndPatternMatch(params, item->contexts(),
404 item->target_url_patterns());
405 if (!match)
406 return false;
408 const GURL& document_url = GetDocumentURL(params);
409 return ExtensionPatternMatch(item->document_url_patterns(), document_url);
412 void RenderViewContextMenu::AppendAllExtensionItems() {
413 extension_items_.Clear();
414 ExtensionService* service =
415 extensions::ExtensionSystem::Get(browser_context_)->extension_service();
416 if (!service)
417 return; // In unit-tests, we may not have an ExtensionService.
419 MenuManager* menu_manager = MenuManager::Get(browser_context_);
420 if (!menu_manager)
421 return;
423 base::string16 printable_selection_text = PrintableSelectionText();
424 EscapeAmpersands(&printable_selection_text);
426 // Get a list of extension id's that have context menu items, and sort by the
427 // top level context menu title of the extension.
428 std::set<MenuItem::ExtensionKey> ids = menu_manager->ExtensionIds();
429 std::vector<base::string16> sorted_menu_titles;
430 std::map<base::string16, std::string> map_ids;
431 for (std::set<MenuItem::ExtensionKey>::iterator iter = ids.begin();
432 iter != ids.end();
433 ++iter) {
434 const Extension* extension =
435 service->GetExtensionById(iter->extension_id, false);
436 // Platform apps have their context menus created directly in
437 // AppendPlatformAppItems.
438 if (extension && !extension->is_platform_app()) {
439 base::string16 menu_title = extension_items_.GetTopLevelContextMenuTitle(
440 *iter, printable_selection_text);
441 map_ids[menu_title] = iter->extension_id;
442 sorted_menu_titles.push_back(menu_title);
445 if (sorted_menu_titles.empty())
446 return;
448 const std::string app_locale = g_browser_process->GetApplicationLocale();
449 l10n_util::SortStrings16(app_locale, &sorted_menu_titles);
451 int index = 0;
452 for (size_t i = 0; i < sorted_menu_titles.size(); ++i) {
453 const std::string& id = map_ids[sorted_menu_titles[i]];
454 const MenuItem::ExtensionKey extension_key(id);
455 extension_items_.AppendExtensionItems(extension_key,
456 printable_selection_text,
457 &index,
458 false); // is_action_menu
462 void RenderViewContextMenu::AppendCurrentExtensionItems() {
463 // Avoid appending extension related items when |extension| is null.
464 // For Panel, this happens when the panel is navigated to a url outside of the
465 // extension's package.
466 const Extension* extension = GetExtension();
467 if (extension) {
468 // Only add extension items from this extension.
469 int index = 0;
470 const MenuItem::ExtensionKey key(
471 extension->id(),
472 extensions::WebViewGuest::GetViewInstanceId(source_web_contents_));
473 extension_items_.AppendExtensionItems(key,
474 PrintableSelectionText(),
475 &index,
476 false); // is_action_menu
479 #endif // defined(ENABLE_EXTENSIONS)
481 void RenderViewContextMenu::InitMenu() {
482 RenderViewContextMenuBase::InitMenu();
484 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PAGE))
485 AppendPageItems();
487 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_FRAME)) {
488 // Merge in frame items with page items if we clicked within a frame that
489 // needs them.
490 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
491 AppendFrameItems();
494 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_LINK)) {
495 AppendLinkItems();
496 if (params_.media_type != WebContextMenuData::MediaTypeNone)
497 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
500 if (content_type_->SupportsGroup(
501 ContextMenuContentType::ITEM_GROUP_MEDIA_IMAGE)) {
502 AppendImageItems();
505 if (content_type_->SupportsGroup(
506 ContextMenuContentType::ITEM_GROUP_SEARCHWEBFORIMAGE)) {
507 AppendSearchWebForImageItems();
510 if (content_type_->SupportsGroup(
511 ContextMenuContentType::ITEM_GROUP_MEDIA_VIDEO)) {
512 AppendVideoItems();
515 if (content_type_->SupportsGroup(
516 ContextMenuContentType::ITEM_GROUP_MEDIA_AUDIO)) {
517 AppendAudioItems();
520 if (content_type_->SupportsGroup(
521 ContextMenuContentType::ITEM_GROUP_MEDIA_CANVAS)) {
522 AppendCanvasItems();
525 if (content_type_->SupportsGroup(
526 ContextMenuContentType::ITEM_GROUP_MEDIA_PLUGIN)) {
527 AppendPluginItems();
530 // ITEM_GROUP_MEDIA_FILE has no specific items.
532 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_EDITABLE))
533 AppendEditableItems();
535 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_COPY)) {
536 DCHECK(!content_type_->SupportsGroup(
537 ContextMenuContentType::ITEM_GROUP_EDITABLE));
538 AppendCopyItem();
541 if (content_type_->SupportsGroup(
542 ContextMenuContentType::ITEM_GROUP_SEARCH_PROVIDER)) {
543 AppendSearchProvider();
546 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT))
547 AppendPrintItem();
549 if (content_type_->SupportsGroup(
550 ContextMenuContentType::ITEM_GROUP_MEDIA_PLUGIN)) {
551 AppendRotationItems();
554 if (content_type_->SupportsGroup(
555 ContextMenuContentType::ITEM_GROUP_ALL_EXTENSION)) {
556 DCHECK(!content_type_->SupportsGroup(
557 ContextMenuContentType::ITEM_GROUP_CURRENT_EXTENSION));
558 AppendAllExtensionItems();
561 if (content_type_->SupportsGroup(
562 ContextMenuContentType::ITEM_GROUP_CURRENT_EXTENSION)) {
563 DCHECK(!content_type_->SupportsGroup(
564 ContextMenuContentType::ITEM_GROUP_ALL_EXTENSION));
565 AppendCurrentExtensionItems();
568 if (content_type_->SupportsGroup(
569 ContextMenuContentType::ITEM_GROUP_DEVELOPER)) {
570 AppendDeveloperItems();
573 if (content_type_->SupportsGroup(
574 ContextMenuContentType::ITEM_GROUP_DEVTOOLS_UNPACKED_EXT)) {
575 AppendDevtoolsForUnpackedExtensions();
578 if (content_type_->SupportsGroup(
579 ContextMenuContentType::ITEM_GROUP_PRINT_PREVIEW)) {
580 AppendPrintPreviewItems();
584 Profile* RenderViewContextMenu::GetProfile() {
585 return Profile::FromBrowserContext(browser_context_);
588 void RenderViewContextMenu::RecordUsedItem(int id) {
589 int enum_id = FindUMAEnumValueForCommand(id);
590 if (enum_id != -1) {
591 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
592 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Used", enum_id,
593 kUmaEnumToControlId[kMappingSize - 1].enum_id);
594 } else {
595 NOTREACHED() << "Update kUmaEnumToControlId. Unhanded IDC: " << id;
599 void RenderViewContextMenu::RecordShownItem(int id) {
600 int enum_id = FindUMAEnumValueForCommand(id);
601 if (enum_id != -1) {
602 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
603 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Shown", enum_id,
604 kUmaEnumToControlId[kMappingSize - 1].enum_id);
605 } else {
606 // Just warning here. It's harder to maintain list of all possibly
607 // visible items than executable items.
608 DLOG(ERROR) << "Update kUmaEnumToControlId. Unhanded IDC: " << id;
612 #if defined(ENABLE_PLUGINS)
613 void RenderViewContextMenu::HandleAuthorizeAllPlugins() {
614 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins(
615 source_web_contents_, false, std::string());
617 #endif
619 void RenderViewContextMenu::AppendPrintPreviewItems() {
620 #if defined(ENABLE_PRINT_PREVIEW)
621 if (!print_preview_menu_observer_.get()) {
622 print_preview_menu_observer_.reset(
623 new PrintPreviewContextMenuObserver(source_web_contents_));
626 observers_.AddObserver(print_preview_menu_observer_.get());
627 #endif
630 const Extension* RenderViewContextMenu::GetExtension() const {
631 return extensions::ProcessManager::Get(browser_context_)
632 ->GetExtensionForRenderViewHost(
633 source_web_contents_->GetRenderViewHost());
636 void RenderViewContextMenu::AppendDeveloperItems() {
637 // Show Inspect Element in DevTools itself only in case of the debug
638 // devtools build.
639 bool show_developer_items = !IsDevToolsURL(params_.page_url);
641 #if defined(DEBUG_DEVTOOLS)
642 show_developer_items = true;
643 #endif
645 if (!show_developer_items)
646 return;
648 // In the DevTools popup menu, "developer items" is normally the only
649 // section, so omit the separator there.
650 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
651 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTELEMENT,
652 IDS_CONTENT_CONTEXT_INSPECTELEMENT);
655 void RenderViewContextMenu::AppendDevtoolsForUnpackedExtensions() {
656 // Add a separator if there are any items already in the menu.
657 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
659 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP,
660 IDS_CONTENT_CONTEXT_RELOAD_PACKAGED_APP);
661 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP,
662 IDS_CONTENT_CONTEXT_RESTART_APP);
663 AppendDeveloperItems();
664 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE,
665 IDS_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE);
668 void RenderViewContextMenu::AppendLinkItems() {
669 if (!params_.link_url.is_empty()) {
670 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB,
671 IDS_CONTENT_CONTEXT_OPENLINKNEWTAB);
672 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW,
673 IDS_CONTENT_CONTEXT_OPENLINKNEWWINDOW);
674 if (params_.link_url.is_valid()) {
675 AppendProtocolHandlerSubMenu();
678 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD,
679 IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD);
680 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVELINKAS,
681 IDS_CONTENT_CONTEXT_SAVELINKAS);
684 menu_model_.AddItemWithStringId(
685 IDC_CONTENT_CONTEXT_COPYLINKLOCATION,
686 params_.link_url.SchemeIs(url::kMailToScheme) ?
687 IDS_CONTENT_CONTEXT_COPYEMAILADDRESS :
688 IDS_CONTENT_CONTEXT_COPYLINKLOCATION);
691 void RenderViewContextMenu::AppendImageItems() {
692 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS,
693 IDS_CONTENT_CONTEXT_SAVEIMAGEAS);
694 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGELOCATION,
695 IDS_CONTENT_CONTEXT_COPYIMAGELOCATION);
696 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
697 IDS_CONTENT_CONTEXT_COPYIMAGE);
698 DataReductionProxyChromeSettings* settings =
699 DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
700 browser_context_);
701 if (settings && settings->CanUseDataReductionProxy(params_.src_url)) {
702 menu_model_.AddItemWithStringId(
703 IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB,
704 IDS_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB);
705 } else {
706 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB,
707 IDS_CONTENT_CONTEXT_OPENIMAGENEWTAB);
711 void RenderViewContextMenu::AppendSearchWebForImageItems() {
712 TemplateURLService* service =
713 TemplateURLServiceFactory::GetForProfile(GetProfile());
714 const TemplateURL* const default_provider =
715 service->GetDefaultSearchProvider();
716 if (params_.has_image_contents && default_provider &&
717 !default_provider->image_url().empty() &&
718 default_provider->image_url_ref().IsValid(service->search_terms_data())) {
719 menu_model_.AddItem(
720 IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE,
721 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFORIMAGE,
722 default_provider->short_name()));
726 void RenderViewContextMenu::AppendAudioItems() {
727 AppendMediaItems();
728 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
729 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
730 IDS_CONTENT_CONTEXT_SAVEAUDIOAS);
731 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
732 IDS_CONTENT_CONTEXT_COPYAUDIOLOCATION);
733 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
734 IDS_CONTENT_CONTEXT_OPENAUDIONEWTAB);
737 void RenderViewContextMenu::AppendCanvasItems() {
738 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS,
739 IDS_CONTENT_CONTEXT_SAVEIMAGEAS);
740 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
741 IDS_CONTENT_CONTEXT_COPYIMAGE);
744 void RenderViewContextMenu::AppendVideoItems() {
745 AppendMediaItems();
746 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
747 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
748 IDS_CONTENT_CONTEXT_SAVEVIDEOAS);
749 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
750 IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION);
751 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
752 IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB);
755 void RenderViewContextMenu::AppendMediaItems() {
756 int media_flags = params_.media_flags;
758 menu_model_.AddItemWithStringId(
759 IDC_CONTENT_CONTEXT_PLAYPAUSE,
760 media_flags & WebContextMenuData::MediaPaused ?
761 IDS_CONTENT_CONTEXT_PLAY :
762 IDS_CONTENT_CONTEXT_PAUSE);
764 menu_model_.AddItemWithStringId(
765 IDC_CONTENT_CONTEXT_MUTE,
766 media_flags & WebContextMenuData::MediaMuted ?
767 IDS_CONTENT_CONTEXT_UNMUTE :
768 IDS_CONTENT_CONTEXT_MUTE);
770 menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_LOOP,
771 IDS_CONTENT_CONTEXT_LOOP);
772 menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_CONTROLS,
773 IDS_CONTENT_CONTEXT_CONTROLS);
776 void RenderViewContextMenu::AppendPluginItems() {
777 if (params_.page_url == params_.src_url ||
778 extensions::GuestViewBase::IsGuest(source_web_contents_)) {
779 // Full page plugin, so show page menu items.
780 if (params_.link_url.is_empty() && params_.selection_text.empty())
781 AppendPageItems();
782 } else {
783 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
784 IDS_CONTENT_CONTEXT_SAVEPAGEAS);
785 // The "Print" menu item should always be included for plugins. If
786 // content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT)
787 // is true the item will be added inside AppendPrintItem(). Otherwise we
788 // add "Print" here.
789 if (!content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT))
790 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
794 void RenderViewContextMenu::AppendPageItems() {
795 menu_model_.AddItemWithStringId(IDC_BACK, IDS_CONTENT_CONTEXT_BACK);
796 menu_model_.AddItemWithStringId(IDC_FORWARD, IDS_CONTENT_CONTEXT_FORWARD);
797 menu_model_.AddItemWithStringId(IDC_RELOAD, IDS_CONTENT_CONTEXT_RELOAD);
798 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
799 menu_model_.AddItemWithStringId(IDC_SAVE_PAGE,
800 IDS_CONTENT_CONTEXT_SAVEPAGEAS);
801 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
803 if (TranslateService::IsTranslatableURL(params_.page_url)) {
804 std::string locale = g_browser_process->GetApplicationLocale();
805 locale = translate::TranslateDownloadManager::GetLanguageCode(locale);
806 base::string16 language =
807 l10n_util::GetDisplayNameForLocale(locale, locale, true);
808 menu_model_.AddItem(
809 IDC_CONTENT_CONTEXT_TRANSLATE,
810 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_TRANSLATE, language));
813 menu_model_.AddItemWithStringId(IDC_VIEW_SOURCE,
814 IDS_CONTENT_CONTEXT_VIEWPAGESOURCE);
815 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWPAGEINFO,
816 IDS_CONTENT_CONTEXT_VIEWPAGEINFO);
819 void RenderViewContextMenu::AppendFrameItems() {
820 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOADFRAME,
821 IDS_CONTENT_CONTEXT_RELOADFRAME);
822 // These two menu items have yet to be implemented.
823 // http://code.google.com/p/chromium/issues/detail?id=11827
824 // IDS_CONTENT_CONTEXT_SAVEFRAMEAS
825 // IDS_CONTENT_CONTEXT_PRINTFRAME
826 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE,
827 IDS_CONTENT_CONTEXT_VIEWFRAMESOURCE);
828 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMEINFO,
829 IDS_CONTENT_CONTEXT_VIEWFRAMEINFO);
832 void RenderViewContextMenu::AppendCopyItem() {
833 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
834 IDS_CONTENT_CONTEXT_COPY);
837 void RenderViewContextMenu::AppendPrintItem() {
838 if (GetPrefs(browser_context_)->GetBoolean(prefs::kPrintingEnabled) &&
839 (params_.media_type == WebContextMenuData::MediaTypeNone ||
840 params_.media_flags & WebContextMenuData::MediaCanPrint)) {
841 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
845 void RenderViewContextMenu::AppendRotationItems() {
846 if (params_.media_flags & WebContextMenuData::MediaCanRotate) {
847 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
848 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECW,
849 IDS_CONTENT_CONTEXT_ROTATECW);
850 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECCW,
851 IDS_CONTENT_CONTEXT_ROTATECCW);
855 void RenderViewContextMenu::AppendSearchProvider() {
856 DCHECK(browser_context_);
858 base::TrimWhitespace(params_.selection_text, base::TRIM_ALL,
859 &params_.selection_text);
860 if (params_.selection_text.empty())
861 return;
863 base::ReplaceChars(params_.selection_text, AutocompleteMatch::kInvalidChars,
864 base::ASCIIToUTF16(" "), &params_.selection_text);
866 AutocompleteMatch match;
867 AutocompleteClassifierFactory::GetForProfile(GetProfile())->Classify(
868 params_.selection_text,
869 false,
870 false,
871 metrics::OmniboxEventProto::INVALID_SPEC,
872 &match,
873 NULL);
874 selection_navigation_url_ = match.destination_url;
875 if (!selection_navigation_url_.is_valid())
876 return;
878 base::string16 printable_selection_text = PrintableSelectionText();
879 EscapeAmpersands(&printable_selection_text);
881 if (AutocompleteMatch::IsSearchType(match.type)) {
882 const TemplateURL* const default_provider =
883 TemplateURLServiceFactory::GetForProfile(GetProfile())
884 ->GetDefaultSearchProvider();
885 if (!default_provider)
886 return;
887 menu_model_.AddItem(
888 IDC_CONTENT_CONTEXT_SEARCHWEBFOR,
889 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFOR,
890 default_provider->short_name(),
891 printable_selection_text));
892 } else {
893 if ((selection_navigation_url_ != params_.link_url) &&
894 ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme(
895 selection_navigation_url_.scheme())) {
896 menu_model_.AddItem(
897 IDC_CONTENT_CONTEXT_GOTOURL,
898 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_GOTOURL,
899 printable_selection_text));
904 void RenderViewContextMenu::AppendEditableItems() {
905 const bool use_spellcheck_and_search = !chrome::IsRunningInForcedAppMode();
907 if (use_spellcheck_and_search)
908 AppendSpellingSuggestionsSubMenu();
910 if (!IsDevToolsURL(params_.page_url)) {
911 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_UNDO,
912 IDS_CONTENT_CONTEXT_UNDO);
913 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_REDO,
914 IDS_CONTENT_CONTEXT_REDO);
915 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
918 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_CUT,
919 IDS_CONTENT_CONTEXT_CUT);
920 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
921 IDS_CONTENT_CONTEXT_COPY);
922 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE,
923 IDS_CONTENT_CONTEXT_PASTE);
924 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE,
925 IDS_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE);
926 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_DELETE,
927 IDS_CONTENT_CONTEXT_DELETE);
928 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
930 if (use_spellcheck_and_search && !params_.keyword_url.is_empty()) {
931 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ADDSEARCHENGINE,
932 IDS_CONTENT_CONTEXT_ADDSEARCHENGINE);
933 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
936 if (use_spellcheck_and_search)
937 AppendSpellcheckOptionsSubMenu();
938 AppendPlatformEditableItems();
940 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
941 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SELECTALL,
942 IDS_CONTENT_CONTEXT_SELECTALL);
945 void RenderViewContextMenu::AppendSpellingSuggestionsSubMenu() {
946 if (!spelling_menu_observer_.get())
947 spelling_menu_observer_.reset(new SpellingMenuObserver(this));
948 observers_.AddObserver(spelling_menu_observer_.get());
949 spelling_menu_observer_->InitMenu(params_);
952 void RenderViewContextMenu::AppendSpellcheckOptionsSubMenu() {
953 if (!spellchecker_submenu_observer_.get()) {
954 spellchecker_submenu_observer_.reset(new SpellCheckerSubMenuObserver(
955 this, this, kSpellcheckRadioGroup));
957 spellchecker_submenu_observer_->InitMenu(params_);
958 observers_.AddObserver(spellchecker_submenu_observer_.get());
961 void RenderViewContextMenu::AppendProtocolHandlerSubMenu() {
962 const ProtocolHandlerRegistry::ProtocolHandlerList handlers =
963 GetHandlersForLinkUrl();
964 if (handlers.empty())
965 return;
966 size_t max = IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST -
967 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
968 for (size_t i = 0; i < handlers.size() && i <= max; i++) {
969 protocol_handler_submenu_model_.AddItem(
970 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST + i,
971 base::UTF8ToUTF16(handlers[i].url().host()));
973 protocol_handler_submenu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
974 protocol_handler_submenu_model_.AddItem(
975 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS,
976 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH_CONFIGURE));
978 menu_model_.AddSubMenu(
979 IDC_CONTENT_CONTEXT_OPENLINKWITH,
980 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH),
981 &protocol_handler_submenu_model_);
984 // Menu delegate functions -----------------------------------------------------
986 bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
988 bool enabled = false;
989 if (RenderViewContextMenuBase::IsCommandIdKnown(id, &enabled))
990 return enabled;
993 CoreTabHelper* core_tab_helper =
994 CoreTabHelper::FromWebContents(source_web_contents_);
995 int content_restrictions = 0;
996 if (core_tab_helper)
997 content_restrictions = core_tab_helper->content_restrictions();
998 if (id == IDC_PRINT && (content_restrictions & CONTENT_RESTRICTION_PRINT))
999 return false;
1001 if (id == IDC_SAVE_PAGE &&
1002 (content_restrictions & CONTENT_RESTRICTION_SAVE)) {
1003 return false;
1006 PrefService* prefs = GetPrefs(browser_context_);
1008 // Allow Spell Check language items on sub menu for text area context menu.
1009 if ((id >= IDC_SPELLCHECK_LANGUAGES_FIRST) &&
1010 (id < IDC_SPELLCHECK_LANGUAGES_LAST)) {
1011 return prefs->GetBoolean(prefs::kEnableContinuousSpellcheck);
1014 // Extension items.
1015 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
1016 return extension_items_.IsCommandIdEnabled(id);
1018 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
1019 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
1020 return true;
1023 IncognitoModePrefs::Availability incognito_avail =
1024 IncognitoModePrefs::GetAvailability(prefs);
1025 switch (id) {
1026 case IDC_BACK:
1027 return embedder_web_contents_->GetController().CanGoBack();
1029 case IDC_FORWARD:
1030 return embedder_web_contents_->GetController().CanGoForward();
1032 case IDC_RELOAD: {
1033 CoreTabHelper* core_tab_helper =
1034 CoreTabHelper::FromWebContents(embedder_web_contents_);
1035 if (!core_tab_helper)
1036 return false;
1038 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
1039 return !core_delegate ||
1040 core_delegate->CanReloadContents(embedder_web_contents_);
1043 case IDC_VIEW_SOURCE:
1044 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
1045 return embedder_web_contents_->GetController().CanViewSource();
1047 case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
1048 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE:
1049 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP:
1050 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP:
1051 return IsDevCommandEnabled(id);
1053 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO:
1054 if (embedder_web_contents_->GetController().GetVisibleEntry() == NULL)
1055 return false;
1056 // Disabled if no browser is associated (e.g. desktop notifications).
1057 if (chrome::FindBrowserWithWebContents(embedder_web_contents_) == NULL)
1058 return false;
1059 return true;
1061 case IDC_CONTENT_CONTEXT_TRANSLATE: {
1062 ChromeTranslateClient* chrome_translate_client =
1063 ChromeTranslateClient::FromWebContents(embedder_web_contents_);
1064 if (!chrome_translate_client)
1065 return false;
1066 std::string original_lang =
1067 chrome_translate_client->GetLanguageState().original_language();
1068 std::string target_lang = g_browser_process->GetApplicationLocale();
1069 target_lang =
1070 translate::TranslateDownloadManager::GetLanguageCode(target_lang);
1071 // Note that we intentionally enable the menu even if the original and
1072 // target languages are identical. This is to give a way to user to
1073 // translate a page that might contains text fragments in a different
1074 // language.
1075 return ((params_.edit_flags & WebContextMenuData::CanTranslate) != 0) &&
1076 !original_lang.empty() && // Did we receive the page language yet?
1077 !chrome_translate_client->GetLanguageState().IsPageTranslated() &&
1078 !embedder_web_contents_->GetInterstitialPage() &&
1079 // There are some application locales which can't be used as a
1080 // target language for translation.
1081 translate::TranslateDownloadManager::IsSupportedLanguage(
1082 target_lang) &&
1083 // Disable on the Instant Extended NTP.
1084 !chrome::IsInstantNTP(embedder_web_contents_);
1087 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB:
1088 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
1089 return params_.link_url.is_valid();
1091 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
1092 return params_.unfiltered_link_url.is_valid();
1094 case IDC_CONTENT_CONTEXT_SAVELINKAS: {
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_.link_url.is_valid() &&
1102 ProfileIOData::IsHandledProtocol(params_.link_url.scheme());
1105 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: {
1106 PrefService* local_state = g_browser_process->local_state();
1107 DCHECK(local_state);
1108 // Test if file-selection dialogs are forbidden by policy.
1109 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1110 return false;
1112 return params_.has_image_contents;
1115 // The images shown in the most visited thumbnails can't be opened or
1116 // searched for conventionally.
1117 case IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB:
1118 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
1119 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
1120 return params_.src_url.is_valid() &&
1121 (params_.src_url.scheme() != content::kChromeUIScheme);
1123 case IDC_CONTENT_CONTEXT_COPYIMAGE:
1124 return params_.has_image_contents;
1126 // Media control commands should all be disabled if the player is in an
1127 // error state.
1128 case IDC_CONTENT_CONTEXT_PLAYPAUSE:
1129 case IDC_CONTENT_CONTEXT_LOOP:
1130 return (params_.media_flags &
1131 WebContextMenuData::MediaInError) == 0;
1133 // Mute and unmute should also be disabled if the player has no audio.
1134 case IDC_CONTENT_CONTEXT_MUTE:
1135 return (params_.media_flags &
1136 WebContextMenuData::MediaHasAudio) != 0 &&
1137 (params_.media_flags &
1138 WebContextMenuData::MediaInError) == 0;
1140 case IDC_CONTENT_CONTEXT_CONTROLS:
1141 return (params_.media_flags &
1142 WebContextMenuData::MediaCanToggleControls) != 0;
1144 case IDC_CONTENT_CONTEXT_ROTATECW:
1145 case IDC_CONTENT_CONTEXT_ROTATECCW:
1146 return
1147 (params_.media_flags & WebContextMenuData::MediaCanRotate) != 0;
1149 case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
1150 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
1151 return params_.src_url.is_valid();
1153 case IDC_CONTENT_CONTEXT_SAVEAVAS: {
1154 PrefService* local_state = g_browser_process->local_state();
1155 DCHECK(local_state);
1156 // Test if file-selection dialogs are forbidden by policy.
1157 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1158 return false;
1160 const GURL& url = params_.src_url;
1161 bool can_save =
1162 (params_.media_flags & WebContextMenuData::MediaCanSave) &&
1163 url.is_valid() && ProfileIOData::IsHandledProtocol(url.scheme());
1164 #if defined(ENABLE_PRINT_PREVIEW)
1165 // Do not save the preview PDF on the print preview page.
1166 can_save = can_save &&
1167 !(printing::PrintPreviewDialogController::IsPrintPreviewURL(url));
1168 #endif
1169 return can_save;
1172 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
1173 // Currently, a media element can be opened in a new tab iff it can
1174 // be saved. So rather than duplicating the MediaCanSave flag, we rely
1175 // on that here.
1176 return !!(params_.media_flags & WebContextMenuData::MediaCanSave);
1178 case IDC_SAVE_PAGE: {
1179 CoreTabHelper* core_tab_helper =
1180 CoreTabHelper::FromWebContents(embedder_web_contents_);
1181 if (!core_tab_helper)
1182 return false;
1184 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
1185 if (core_delegate &&
1186 !core_delegate->CanSaveContents(embedder_web_contents_))
1187 return false;
1189 PrefService* local_state = g_browser_process->local_state();
1190 DCHECK(local_state);
1191 // Test if file-selection dialogs are forbidden by policy.
1192 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1193 return false;
1195 // We save the last committed entry (which the user is looking at), as
1196 // opposed to any pending URL that hasn't committed yet.
1197 NavigationEntry* entry =
1198 embedder_web_contents_->GetController().GetLastCommittedEntry();
1199 return content::IsSavableURL(entry ? entry->GetURL() : GURL());
1202 case IDC_CONTENT_CONTEXT_RELOADFRAME:
1203 return params_.frame_url.is_valid();
1205 case IDC_CONTENT_CONTEXT_UNDO:
1206 return !!(params_.edit_flags & WebContextMenuData::CanUndo);
1208 case IDC_CONTENT_CONTEXT_REDO:
1209 return !!(params_.edit_flags & WebContextMenuData::CanRedo);
1211 case IDC_CONTENT_CONTEXT_CUT:
1212 return !!(params_.edit_flags & WebContextMenuData::CanCut);
1214 case IDC_CONTENT_CONTEXT_COPY:
1215 return !!(params_.edit_flags & WebContextMenuData::CanCopy);
1217 case IDC_CONTENT_CONTEXT_PASTE: {
1218 if (!(params_.edit_flags & WebContextMenuData::CanPaste))
1219 return false;
1221 std::vector<base::string16> types;
1222 bool ignore;
1223 ui::Clipboard::GetForCurrentThread()->ReadAvailableTypes(
1224 ui::CLIPBOARD_TYPE_COPY_PASTE, &types, &ignore);
1225 return !types.empty();
1228 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE: {
1229 if (!(params_.edit_flags & WebContextMenuData::CanPaste))
1230 return false;
1232 return ui::Clipboard::GetForCurrentThread()->IsFormatAvailable(
1233 ui::Clipboard::GetPlainTextFormatType(),
1234 ui::CLIPBOARD_TYPE_COPY_PASTE);
1237 case IDC_CONTENT_CONTEXT_DELETE:
1238 return !!(params_.edit_flags & WebContextMenuData::CanDelete);
1240 case IDC_CONTENT_CONTEXT_SELECTALL:
1241 return !!(params_.edit_flags & WebContextMenuData::CanSelectAll);
1243 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
1244 return !browser_context_->IsOffTheRecord() &&
1245 params_.link_url.is_valid() &&
1246 incognito_avail != IncognitoModePrefs::DISABLED;
1248 case IDC_PRINT:
1249 return prefs->GetBoolean(prefs::kPrintingEnabled) &&
1250 (params_.media_type == WebContextMenuData::MediaTypeNone ||
1251 params_.media_flags & WebContextMenuData::MediaCanPrint);
1253 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
1254 case IDC_CONTENT_CONTEXT_GOTOURL:
1255 case IDC_SPELLPANEL_TOGGLE:
1256 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS:
1257 return true;
1258 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO:
1259 // Disabled if no browser is associated (e.g. desktop notifications).
1260 if (chrome::FindBrowserWithWebContents(source_web_contents_) == NULL)
1261 return false;
1262 return true;
1264 case IDC_CHECK_SPELLING_WHILE_TYPING:
1265 return prefs->GetBoolean(prefs::kEnableContinuousSpellcheck);
1267 #if !defined(OS_MACOSX) && defined(OS_POSIX)
1268 // TODO(suzhe): this should not be enabled for password fields.
1269 case IDC_INPUT_METHODS_MENU:
1270 return true;
1271 #endif
1273 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE:
1274 return !params_.keyword_url.is_empty();
1276 case IDC_SPELLCHECK_MENU:
1277 return true;
1279 case IDC_CONTENT_CONTEXT_OPENLINKWITH:
1280 return true;
1282 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS:
1283 return true;
1285 default:
1286 NOTREACHED();
1287 return false;
1291 bool RenderViewContextMenu::IsCommandIdChecked(int id) const {
1292 if (RenderViewContextMenuBase::IsCommandIdChecked(id))
1293 return true;
1295 // See if the video is set to looping.
1296 if (id == IDC_CONTENT_CONTEXT_LOOP)
1297 return (params_.media_flags & WebContextMenuData::MediaLoop) != 0;
1299 if (id == IDC_CONTENT_CONTEXT_CONTROLS)
1300 return (params_.media_flags & WebContextMenuData::MediaControls) != 0;
1302 // Extension items.
1303 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
1304 return extension_items_.IsCommandIdChecked(id);
1306 return false;
1309 void RenderViewContextMenu::ExecuteCommand(int id, int event_flags) {
1310 RenderViewContextMenuBase::ExecuteCommand(id, event_flags);
1311 if (command_executed_)
1312 return;
1313 command_executed_ = true;
1315 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1317 // Process extension menu items.
1318 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id)) {
1319 extension_items_.ExecuteCommand(id, source_web_contents_, params_);
1320 return;
1323 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
1324 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
1325 ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1326 GetHandlersForLinkUrl();
1327 if (handlers.empty())
1328 return;
1330 content::RecordAction(
1331 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Open"));
1332 int handlerIndex = id - IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
1333 WindowOpenDisposition disposition =
1334 ForceNewTabDispositionFromEventFlags(event_flags);
1335 OpenURL(handlers[handlerIndex].TranslateUrl(params_.link_url),
1336 GetDocumentURL(params_),
1337 disposition,
1338 ui::PAGE_TRANSITION_LINK);
1339 return;
1342 switch (id) {
1343 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB: {
1344 Browser* browser =
1345 chrome::FindBrowserWithWebContents(source_web_contents_);
1346 OpenURL(params_.link_url,
1347 GetDocumentURL(params_),
1348 !browser || browser->is_app() ?
1349 NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB,
1350 ui::PAGE_TRANSITION_LINK);
1351 break;
1353 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
1354 OpenURL(params_.link_url,
1355 GetDocumentURL(params_),
1356 NEW_WINDOW,
1357 ui::PAGE_TRANSITION_LINK);
1358 break;
1360 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
1361 OpenURL(params_.link_url, GURL(), OFF_THE_RECORD,
1362 ui::PAGE_TRANSITION_LINK);
1363 break;
1365 case IDC_CONTENT_CONTEXT_SAVELINKAS: {
1366 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
1367 const GURL& url = params_.link_url;
1368 content::Referrer referrer = CreateSaveAsReferrer(url, params_);
1369 DownloadManager* dlm =
1370 BrowserContext::GetDownloadManager(browser_context_);
1371 scoped_ptr<DownloadUrlParameters> dl_params(
1372 DownloadUrlParameters::FromWebContents(source_web_contents_, url));
1373 dl_params->set_referrer(referrer);
1374 dl_params->set_referrer_encoding(params_.frame_charset);
1375 dl_params->set_suggested_name(params_.suggested_filename);
1376 dl_params->set_prompt(true);
1377 dlm->DownloadUrl(dl_params.Pass());
1378 break;
1381 case IDC_CONTENT_CONTEXT_SAVEAVAS:
1382 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: {
1383 bool is_large_data_url = params_.has_image_contents &&
1384 params_.src_url.is_empty();
1385 if (params_.media_type == WebContextMenuData::MediaTypeCanvas ||
1386 (params_.media_type == WebContextMenuData::MediaTypeImage &&
1387 is_large_data_url)) {
1388 source_web_contents_->GetRenderViewHost()->SaveImageAt(
1389 params_.x, params_.y);
1390 } else {
1391 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
1392 const GURL& url = params_.src_url;
1393 content::Referrer referrer = CreateSaveAsReferrer(url, params_);
1395 std::string headers;
1396 DataReductionProxyChromeSettings* settings =
1397 DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
1398 browser_context_);
1399 if (params_.media_type == WebContextMenuData::MediaTypeImage &&
1400 settings && settings->CanUseDataReductionProxy(params_.src_url)) {
1401 headers = data_reduction_proxy::kDataReductionPassThroughHeader;
1404 source_web_contents_->SaveFrameWithHeaders(url, referrer, headers);
1406 break;
1409 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
1410 WriteURLToClipboard(params_.unfiltered_link_url);
1411 break;
1413 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
1414 case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
1415 WriteURLToClipboard(params_.src_url);
1416 break;
1418 case IDC_CONTENT_CONTEXT_COPYIMAGE:
1419 CopyImageAt(params_.x, params_.y);
1420 break;
1422 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
1423 GetImageThumbnailForSearch();
1424 break;
1426 case IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB:
1427 OpenURLWithExtraHeaders(
1428 params_.src_url, GetDocumentURL(params_), NEW_BACKGROUND_TAB,
1429 ui::PAGE_TRANSITION_LINK,
1430 data_reduction_proxy::kDataReductionPassThroughHeader);
1431 break;
1433 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
1434 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
1435 OpenURL(params_.src_url,
1436 GetDocumentURL(params_),
1437 NEW_BACKGROUND_TAB,
1438 ui::PAGE_TRANSITION_LINK);
1439 break;
1441 case IDC_CONTENT_CONTEXT_PLAYPAUSE: {
1442 bool play = !!(params_.media_flags & WebContextMenuData::MediaPaused);
1443 if (play) {
1444 content::RecordAction(UserMetricsAction("MediaContextMenu_Play"));
1445 } else {
1446 content::RecordAction(UserMetricsAction("MediaContextMenu_Pause"));
1448 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1449 WebMediaPlayerAction(
1450 WebMediaPlayerAction::Play, play));
1451 break;
1454 case IDC_CONTENT_CONTEXT_MUTE: {
1455 bool mute = !(params_.media_flags & WebContextMenuData::MediaMuted);
1456 if (mute) {
1457 content::RecordAction(UserMetricsAction("MediaContextMenu_Mute"));
1458 } else {
1459 content::RecordAction(UserMetricsAction("MediaContextMenu_Unmute"));
1461 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1462 WebMediaPlayerAction(
1463 WebMediaPlayerAction::Mute, mute));
1464 break;
1467 case IDC_CONTENT_CONTEXT_LOOP:
1468 content::RecordAction(UserMetricsAction("MediaContextMenu_Loop"));
1469 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1470 WebMediaPlayerAction(
1471 WebMediaPlayerAction::Loop,
1472 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_LOOP)));
1473 break;
1475 case IDC_CONTENT_CONTEXT_CONTROLS:
1476 content::RecordAction(UserMetricsAction("MediaContextMenu_Controls"));
1477 MediaPlayerActionAt(
1478 gfx::Point(params_.x, params_.y),
1479 WebMediaPlayerAction(
1480 WebMediaPlayerAction::Controls,
1481 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_CONTROLS)));
1482 break;
1484 case IDC_CONTENT_CONTEXT_ROTATECW:
1485 content::RecordAction(
1486 UserMetricsAction("PluginContextMenu_RotateClockwise"));
1487 PluginActionAt(
1488 gfx::Point(params_.x, params_.y),
1489 WebPluginAction(WebPluginAction::Rotate90Clockwise, true));
1490 break;
1492 case IDC_CONTENT_CONTEXT_ROTATECCW:
1493 content::RecordAction(
1494 UserMetricsAction("PluginContextMenu_RotateCounterclockwise"));
1495 PluginActionAt(
1496 gfx::Point(params_.x, params_.y),
1497 WebPluginAction(WebPluginAction::Rotate90Counterclockwise, true));
1498 break;
1500 case IDC_BACK:
1501 embedder_web_contents_->GetController().GoBack();
1502 break;
1504 case IDC_FORWARD:
1505 embedder_web_contents_->GetController().GoForward();
1506 break;
1508 case IDC_SAVE_PAGE:
1509 embedder_web_contents_->OnSavePage();
1510 break;
1512 case IDC_RELOAD:
1513 embedder_web_contents_->GetController().Reload(true);
1514 break;
1516 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP: {
1517 const Extension* platform_app = GetExtension();
1518 DCHECK(platform_app);
1519 DCHECK(platform_app->is_platform_app());
1521 extensions::ExtensionSystem::Get(browser_context_)
1522 ->extension_service()
1523 ->ReloadExtension(platform_app->id());
1524 break;
1527 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP: {
1528 const Extension* platform_app = GetExtension();
1529 DCHECK(platform_app);
1530 DCHECK(platform_app->is_platform_app());
1532 apps::AppLoadService::Get(GetProfile())
1533 ->RestartApplication(platform_app->id());
1534 break;
1537 case IDC_PRINT: {
1538 #if defined(ENABLE_PRINTING)
1539 if (params_.media_type != WebContextMenuData::MediaTypeNone) {
1540 if (render_frame_host) {
1541 render_frame_host->Send(new PrintMsg_PrintNodeUnderContextMenu(
1542 render_frame_host->GetRoutingID()));
1544 break;
1547 printing::StartPrint(
1548 source_web_contents_,
1549 GetPrefs(browser_context_)->GetBoolean(prefs::kPrintPreviewDisabled),
1550 !params_.selection_text.empty());
1551 #endif // ENABLE_PRINTING
1552 break;
1555 case IDC_VIEW_SOURCE:
1556 embedder_web_contents_->ViewSource();
1557 break;
1559 case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
1560 Inspect(params_.x, params_.y);
1561 break;
1563 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE: {
1564 const Extension* platform_app = GetExtension();
1565 DCHECK(platform_app);
1566 DCHECK(platform_app->is_platform_app());
1568 extensions::devtools_util::InspectBackgroundPage(platform_app,
1569 GetProfile());
1570 break;
1573 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO: {
1574 NavigationController* controller =
1575 &embedder_web_contents_->GetController();
1576 // Important to use GetVisibleEntry to match what's showing in the
1577 // omnibox. This may return null.
1578 NavigationEntry* nav_entry = controller->GetVisibleEntry();
1579 if (!nav_entry)
1580 return;
1581 Browser* browser =
1582 chrome::FindBrowserWithWebContents(embedder_web_contents_);
1583 chrome::ShowWebsiteSettings(browser, embedder_web_contents_,
1584 nav_entry->GetURL(), nav_entry->GetSSL());
1585 break;
1588 case IDC_CONTENT_CONTEXT_TRANSLATE: {
1589 // A translation might have been triggered by the time the menu got
1590 // selected, do nothing in that case.
1591 ChromeTranslateClient* chrome_translate_client =
1592 ChromeTranslateClient::FromWebContents(embedder_web_contents_);
1593 if (!chrome_translate_client ||
1594 chrome_translate_client->GetLanguageState().IsPageTranslated() ||
1595 chrome_translate_client->GetLanguageState().translation_pending()) {
1596 return;
1598 std::string original_lang =
1599 chrome_translate_client->GetLanguageState().original_language();
1600 std::string target_lang = g_browser_process->GetApplicationLocale();
1601 target_lang =
1602 translate::TranslateDownloadManager::GetLanguageCode(target_lang);
1603 // Since the user decided to translate for that language and site, clears
1604 // any preferences for not translating them.
1605 scoped_ptr<translate::TranslatePrefs> prefs(
1606 ChromeTranslateClient::CreateTranslatePrefs(
1607 GetPrefs(browser_context_)));
1608 prefs->UnblockLanguage(original_lang);
1609 prefs->RemoveSiteFromBlacklist(params_.page_url.HostNoBrackets());
1610 translate::TranslateManager* manager =
1611 chrome_translate_client->GetTranslateManager();
1612 DCHECK(manager);
1613 manager->TranslatePage(original_lang, target_lang, true);
1614 break;
1617 case IDC_CONTENT_CONTEXT_RELOADFRAME:
1618 // We always obey the cache here.
1619 // TODO(evanm): Perhaps we could allow shift-clicking the menu item to do
1620 // a cache-ignoring reload of the frame.
1621 source_web_contents_->ReloadFocusedFrame(false);
1622 break;
1624 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
1625 source_web_contents_->ViewFrameSource(params_.frame_url,
1626 params_.frame_page_state);
1627 break;
1629 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO: {
1630 Browser* browser = chrome::FindBrowserWithWebContents(
1631 source_web_contents_);
1632 chrome::ShowWebsiteSettings(browser, source_web_contents_,
1633 params_.frame_url, params_.security_info);
1634 break;
1637 case IDC_CONTENT_CONTEXT_UNDO:
1638 source_web_contents_->Undo();
1639 break;
1641 case IDC_CONTENT_CONTEXT_REDO:
1642 source_web_contents_->Redo();
1643 break;
1645 case IDC_CONTENT_CONTEXT_CUT:
1646 source_web_contents_->Cut();
1647 break;
1649 case IDC_CONTENT_CONTEXT_COPY:
1650 source_web_contents_->Copy();
1651 break;
1653 case IDC_CONTENT_CONTEXT_PASTE:
1654 source_web_contents_->Paste();
1655 break;
1657 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE:
1658 source_web_contents_->PasteAndMatchStyle();
1659 break;
1661 case IDC_CONTENT_CONTEXT_DELETE:
1662 source_web_contents_->Delete();
1663 break;
1665 case IDC_CONTENT_CONTEXT_SELECTALL:
1666 source_web_contents_->SelectAll();
1667 break;
1669 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
1670 case IDC_CONTENT_CONTEXT_GOTOURL: {
1671 WindowOpenDisposition disposition =
1672 ForceNewTabDispositionFromEventFlags(event_flags);
1673 OpenURL(selection_navigation_url_, GURL(), disposition,
1674 ui::PAGE_TRANSITION_LINK);
1675 break;
1677 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS: {
1678 WindowOpenDisposition disposition =
1679 ForceNewTabDispositionFromEventFlags(event_flags);
1680 GURL url = chrome::GetSettingsUrl(chrome::kLanguageOptionsSubPage);
1681 OpenURL(url, GURL(), disposition, ui::PAGE_TRANSITION_LINK);
1682 break;
1685 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS: {
1686 content::RecordAction(
1687 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Settings"));
1688 WindowOpenDisposition disposition =
1689 ForceNewTabDispositionFromEventFlags(event_flags);
1690 GURL url = chrome::GetSettingsUrl(chrome::kHandlerSettingsSubPage);
1691 OpenURL(url, GURL(), disposition, ui::PAGE_TRANSITION_LINK);
1692 break;
1695 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE: {
1696 // Make sure the model is loaded.
1697 TemplateURLService* model =
1698 TemplateURLServiceFactory::GetForProfile(GetProfile());
1699 if (!model)
1700 return;
1701 model->Load();
1703 SearchEngineTabHelper* search_engine_tab_helper =
1704 SearchEngineTabHelper::FromWebContents(source_web_contents_);
1705 if (search_engine_tab_helper &&
1706 search_engine_tab_helper->delegate()) {
1707 base::string16 keyword(TemplateURL::GenerateKeyword(params_.page_url));
1708 TemplateURLData data;
1709 data.short_name = keyword;
1710 data.SetKeyword(keyword);
1711 data.SetURL(params_.keyword_url.spec());
1712 data.favicon_url =
1713 TemplateURL::GenerateFaviconURL(params_.page_url.GetOrigin());
1714 // Takes ownership of the TemplateURL.
1715 search_engine_tab_helper->delegate()->ConfirmAddSearchProvider(
1716 new TemplateURL(data), GetProfile());
1718 break;
1721 default:
1722 NOTREACHED();
1723 break;
1727 ProtocolHandlerRegistry::ProtocolHandlerList
1728 RenderViewContextMenu::GetHandlersForLinkUrl() {
1729 ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1730 protocol_handler_registry_->GetHandlersFor(params_.link_url.scheme());
1731 std::sort(handlers.begin(), handlers.end());
1732 return handlers;
1735 void RenderViewContextMenu::NotifyMenuShown() {
1736 content::NotificationService::current()->Notify(
1737 chrome::NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN,
1738 content::Source<RenderViewContextMenu>(this),
1739 content::NotificationService::NoDetails());
1742 void RenderViewContextMenu::NotifyURLOpened(
1743 const GURL& url,
1744 content::WebContents* new_contents) {
1745 RetargetingDetails details;
1746 details.source_web_contents = source_web_contents_;
1747 // Don't use GetRenderFrameHost() as it may be NULL. crbug.com/399789
1748 details.source_render_frame_id = render_frame_id_;
1749 details.target_url = url;
1750 details.target_web_contents = new_contents;
1751 details.not_yet_in_tabstrip = false;
1753 content::NotificationService::current()->Notify(
1754 chrome::NOTIFICATION_RETARGETING,
1755 content::Source<Profile>(GetProfile()),
1756 content::Details<RetargetingDetails>(&details));
1759 bool RenderViewContextMenu::IsDevCommandEnabled(int id) const {
1760 if (id == IDC_CONTENT_CONTEXT_INSPECTELEMENT ||
1761 id == IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE) {
1762 if (!GetPrefs(browser_context_)
1763 ->GetBoolean(prefs::kWebKitJavascriptEnabled))
1764 return false;
1766 // Don't enable the web inspector if the developer tools are disabled via
1767 // the preference dev-tools-disabled.
1768 if (GetPrefs(browser_context_)->GetBoolean(prefs::kDevToolsDisabled))
1769 return false;
1772 return true;
1775 base::string16 RenderViewContextMenu::PrintableSelectionText() {
1776 return gfx::TruncateString(params_.selection_text,
1777 kMaxSelectionTextLength,
1778 gfx::WORD_BREAK);
1781 // Controller functions --------------------------------------------------------
1783 void RenderViewContextMenu::CopyImageAt(int x, int y) {
1784 source_web_contents_->GetRenderViewHost()->CopyImageAt(x, y);
1787 void RenderViewContextMenu::GetImageThumbnailForSearch() {
1788 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1789 if (!render_frame_host)
1790 return;
1791 render_frame_host->Send(new ChromeViewMsg_RequestThumbnailForContextNode(
1792 render_frame_host->GetRoutingID(),
1793 kImageSearchThumbnailMinSize,
1794 gfx::Size(kImageSearchThumbnailMaxWidth,
1795 kImageSearchThumbnailMaxHeight)));
1798 void RenderViewContextMenu::Inspect(int x, int y) {
1799 content::RecordAction(UserMetricsAction("DevTools_InspectElement"));
1800 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1801 if (!render_frame_host)
1802 return;
1803 DevToolsWindow::InspectElement(
1804 WebContents::FromRenderFrameHost(render_frame_host), x, y);
1807 void RenderViewContextMenu::WriteURLToClipboard(const GURL& url) {
1808 chrome_common_net::WriteURLToClipboard(
1809 url, GetPrefs(browser_context_)->GetString(prefs::kAcceptLanguages));
1812 void RenderViewContextMenu::MediaPlayerActionAt(
1813 const gfx::Point& location,
1814 const WebMediaPlayerAction& action) {
1815 source_web_contents_->GetRenderViewHost()->
1816 ExecuteMediaPlayerActionAtLocation(location, action);
1819 void RenderViewContextMenu::PluginActionAt(
1820 const gfx::Point& location,
1821 const WebPluginAction& action) {
1822 source_web_contents_->GetRenderViewHost()->
1823 ExecutePluginActionAtLocation(location, action);