Only grant permissions to new extensions from sync if they have the expected version
[chromium-blink-merge.git] / chrome / browser / renderer_context_menu / render_view_context_menu.cc
blobfc5ae9c571c60da9c4bac490f75a0c234bddfb36
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
7 #include <algorithm>
8 #include <set>
9 #include <utility>
11 #include "apps/app_load_service.h"
12 #include "base/command_line.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram.h"
15 #include "base/prefs/pref_member.h"
16 #include "base/prefs/pref_service.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "chrome/app/chrome_command_ids.h"
22 #include "chrome/browser/app_mode/app_mode_utils.h"
23 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
24 #include "chrome/browser/browser_process.h"
25 #include "chrome/browser/chrome_notification_types.h"
26 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
27 #include "chrome/browser/devtools/devtools_window.h"
28 #include "chrome/browser/download/download_service.h"
29 #include "chrome/browser/download/download_service_factory.h"
30 #include "chrome/browser/download/download_stats.h"
31 #include "chrome/browser/extensions/devtools_util.h"
32 #include "chrome/browser/extensions/extension_service.h"
33 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h"
34 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings_factory.h"
35 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
36 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
37 #include "chrome/browser/prefs/incognito_mode_prefs.h"
38 #include "chrome/browser/profiles/profile.h"
39 #include "chrome/browser/profiles/profile_io_data.h"
40 #include "chrome/browser/renderer_context_menu/context_menu_content_type_factory.h"
41 #include "chrome/browser/renderer_context_menu/spellchecker_submenu_observer.h"
42 #include "chrome/browser/renderer_context_menu/spelling_menu_observer.h"
43 #include "chrome/browser/search/search.h"
44 #include "chrome/browser/search_engines/template_url_service_factory.h"
45 #include "chrome/browser/spellchecker/spellcheck_host_metrics.h"
46 #include "chrome/browser/spellchecker/spellcheck_service.h"
47 #include "chrome/browser/tab_contents/retargeting_details.h"
48 #include "chrome/browser/translate/chrome_translate_client.h"
49 #include "chrome/browser/translate/translate_service.h"
50 #include "chrome/browser/ui/browser.h"
51 #include "chrome/browser/ui/browser_commands.h"
52 #include "chrome/browser/ui/browser_finder.h"
53 #include "chrome/browser/ui/chrome_pages.h"
54 #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"
55 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
56 #include "chrome/common/chrome_constants.h"
57 #include "chrome/common/chrome_switches.h"
58 #include "chrome/common/content_restriction.h"
59 #include "chrome/common/pref_names.h"
60 #include "chrome/common/render_messages.h"
61 #include "chrome/common/spellcheck_common.h"
62 #include "chrome/common/url_constants.h"
63 #include "chrome/grit/generated_resources.h"
64 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
65 #include "components/google/core/browser/google_util.h"
66 #include "components/metrics/proto/omnibox_input_type.pb.h"
67 #include "components/omnibox/browser/autocomplete_classifier.h"
68 #include "components/omnibox/browser/autocomplete_match.h"
69 #include "components/password_manager/core/common/experiments.h"
70 #include "components/search_engines/template_url.h"
71 #include "components/search_engines/template_url_service.h"
72 #include "components/translate/core/browser/translate_download_manager.h"
73 #include "components/translate/core/browser/translate_manager.h"
74 #include "components/translate/core/browser/translate_prefs.h"
75 #include "components/url_formatter/url_formatter.h"
76 #include "components/user_prefs/user_prefs.h"
77 #include "content/public/browser/child_process_security_policy.h"
78 #include "content/public/browser/download_manager.h"
79 #include "content/public/browser/download_save_info.h"
80 #include "content/public/browser/download_url_parameters.h"
81 #include "content/public/browser/navigation_details.h"
82 #include "content/public/browser/navigation_entry.h"
83 #include "content/public/browser/notification_service.h"
84 #include "content/public/browser/render_frame_host.h"
85 #include "content/public/browser/render_process_host.h"
86 #include "content/public/browser/render_view_host.h"
87 #include "content/public/browser/render_widget_host_view.h"
88 #include "content/public/browser/user_metrics.h"
89 #include "content/public/browser/web_contents.h"
90 #include "content/public/common/menu_item.h"
91 #include "content/public/common/ssl_status.h"
92 #include "content/public/common/url_utils.h"
93 #include "extensions/browser/extension_host.h"
94 #include "extensions/browser/extension_system.h"
95 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
96 #include "extensions/browser/view_type_utils.h"
97 #include "extensions/common/extension.h"
98 #include "net/base/escape.h"
99 #include "third_party/WebKit/public/web/WebContextMenuData.h"
100 #include "third_party/WebKit/public/web/WebMediaPlayerAction.h"
101 #include "third_party/WebKit/public/web/WebPluginAction.h"
102 #include "ui/base/clipboard/clipboard.h"
103 #include "ui/base/clipboard/scoped_clipboard_writer.h"
104 #include "ui/base/l10n/l10n_util.h"
105 #include "ui/gfx/favicon_size.h"
106 #include "ui/gfx/geometry/point.h"
107 #include "ui/gfx/geometry/size.h"
108 #include "ui/gfx/text_elider.h"
110 #if defined(ENABLE_EXTENSIONS)
111 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
112 #endif
114 #if defined(ENABLE_PRINTING)
115 #include "chrome/browser/printing/print_view_manager_common.h"
116 #include "components/printing/common/print_messages.h"
118 #if defined(ENABLE_PRINT_PREVIEW)
119 #include "chrome/browser/printing/print_preview_context_menu_observer.h"
120 #include "chrome/browser/printing/print_preview_dialog_controller.h"
121 #endif // defined(ENABLE_PRINT_PREVIEW)
122 #endif // defined(ENABLE_PRINTING)
124 using base::UserMetricsAction;
125 using blink::WebContextMenuData;
126 using blink::WebMediaPlayerAction;
127 using blink::WebPluginAction;
128 using blink::WebString;
129 using blink::WebURL;
130 using content::BrowserContext;
131 using content::ChildProcessSecurityPolicy;
132 using content::DownloadManager;
133 using content::DownloadUrlParameters;
134 using content::NavigationController;
135 using content::NavigationEntry;
136 using content::OpenURLParams;
137 using content::RenderFrameHost;
138 using content::RenderViewHost;
139 using content::SSLStatus;
140 using content::WebContents;
141 using extensions::ContextMenuMatcher;
142 using extensions::Extension;
143 using extensions::MenuItem;
144 using extensions::MenuManager;
146 namespace {
148 const int kImageSearchThumbnailMinSize = 300 * 300;
149 const int kImageSearchThumbnailMaxWidth = 600;
150 const int kImageSearchThumbnailMaxHeight = 600;
152 // Maps UMA enumeration to IDC. IDC could be changed so we can't use
153 // just them and |UMA_HISTOGRAM_CUSTOM_ENUMERATION|.
154 // Never change mapping or reuse |enum_id|. Always push back new items.
155 // Items that is not used any more by |RenderViewContextMenu.ExecuteCommand|
156 // could be deleted, but don't change the rest of |kUmaEnumToControlId|.
157 const struct UmaEnumCommandIdPair {
158 int enum_id;
159 int control_id;
160 } kUmaEnumToControlId[] = {
162 enum id for 0, 1 are detected using
163 RenderViewContextMenu::IsContentCustomCommandId and
164 ContextMenuMatcher::IsExtensionsCustomCommandId
166 {2, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST},
167 {3, IDC_CONTENT_CONTEXT_OPENLINKNEWTAB},
168 {4, IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW},
169 {5, IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD},
170 {6, IDC_CONTENT_CONTEXT_SAVELINKAS},
171 {7, IDC_CONTENT_CONTEXT_SAVEAVAS},
172 {8, IDC_CONTENT_CONTEXT_SAVEIMAGEAS},
173 {9, IDC_CONTENT_CONTEXT_COPYLINKLOCATION},
174 {10, IDC_CONTENT_CONTEXT_COPYIMAGELOCATION},
175 {11, IDC_CONTENT_CONTEXT_COPYAVLOCATION},
176 {12, IDC_CONTENT_CONTEXT_COPYIMAGE},
177 {13, IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB},
178 {14, IDC_CONTENT_CONTEXT_OPENAVNEWTAB},
179 {15, IDC_CONTENT_CONTEXT_PLAYPAUSE},
180 {16, IDC_CONTENT_CONTEXT_MUTE},
181 {17, IDC_CONTENT_CONTEXT_LOOP},
182 {18, IDC_CONTENT_CONTEXT_CONTROLS},
183 {19, IDC_CONTENT_CONTEXT_ROTATECW},
184 {20, IDC_CONTENT_CONTEXT_ROTATECCW},
185 {21, IDC_BACK},
186 {22, IDC_FORWARD},
187 {23, IDC_SAVE_PAGE},
188 {24, IDC_RELOAD},
189 {25, IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP},
190 {26, IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP},
191 {27, IDC_PRINT},
192 {28, IDC_VIEW_SOURCE},
193 {29, IDC_CONTENT_CONTEXT_INSPECTELEMENT},
194 {30, IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE},
195 {31, IDC_CONTENT_CONTEXT_VIEWPAGEINFO},
196 {32, IDC_CONTENT_CONTEXT_TRANSLATE},
197 {33, IDC_CONTENT_CONTEXT_RELOADFRAME},
198 {34, IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE},
199 {35, IDC_CONTENT_CONTEXT_VIEWFRAMEINFO},
200 {36, IDC_CONTENT_CONTEXT_UNDO},
201 {37, IDC_CONTENT_CONTEXT_REDO},
202 {38, IDC_CONTENT_CONTEXT_CUT},
203 {39, IDC_CONTENT_CONTEXT_COPY},
204 {40, IDC_CONTENT_CONTEXT_PASTE},
205 {41, IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE},
206 {42, IDC_CONTENT_CONTEXT_DELETE},
207 {43, IDC_CONTENT_CONTEXT_SELECTALL},
208 {44, IDC_CONTENT_CONTEXT_SEARCHWEBFOR},
209 {45, IDC_CONTENT_CONTEXT_GOTOURL},
210 {46, IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS},
211 {47, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS},
212 {48, IDC_CONTENT_CONTEXT_ADDSEARCHENGINE},
213 {52, IDC_CONTENT_CONTEXT_OPENLINKWITH},
214 {53, IDC_CHECK_SPELLING_WHILE_TYPING},
215 {54, IDC_SPELLCHECK_MENU},
216 {55, IDC_CONTENT_CONTEXT_SPELLING_TOGGLE},
217 {56, IDC_SPELLCHECK_LANGUAGES_FIRST},
218 {57, IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE},
219 {58, IDC_SPELLCHECK_SUGGESTION_0},
220 {59, IDC_SPELLCHECK_ADD_TO_DICTIONARY},
221 {60, IDC_SPELLPANEL_TOGGLE},
222 {61, IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB},
223 {62, IDC_WRITING_DIRECTION_MENU},
224 {63, IDC_WRITING_DIRECTION_DEFAULT},
225 {64, IDC_WRITING_DIRECTION_LTR},
226 {65, IDC_WRITING_DIRECTION_RTL},
227 {66, IDC_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE},
228 {67, IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD},
229 // Add new items here and use |enum_id| from the next line.
230 // Also, add new items to RenderViewContextMenuItem enum in histograms.xml.
231 {68, 0}, // Must be the last. Increment |enum_id| when new IDC was added.
234 // Collapses large ranges of ids before looking for UMA enum.
235 int CollapseCommandsForUMA(int id) {
236 DCHECK(!RenderViewContextMenu::IsContentCustomCommandId(id));
237 DCHECK(!ContextMenuMatcher::IsExtensionsCustomCommandId(id));
239 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
240 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
241 return IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
244 if (id >= IDC_SPELLCHECK_LANGUAGES_FIRST &&
245 id <= IDC_SPELLCHECK_LANGUAGES_LAST) {
246 return IDC_SPELLCHECK_LANGUAGES_FIRST;
249 if (id >= IDC_SPELLCHECK_SUGGESTION_0 &&
250 id <= IDC_SPELLCHECK_SUGGESTION_LAST) {
251 return IDC_SPELLCHECK_SUGGESTION_0;
254 return id;
257 // Returns UMA enum value for command specified by |id| or -1 if not found.
258 int FindUMAEnumValueForCommand(int id) {
259 if (RenderViewContextMenu::IsContentCustomCommandId(id))
260 return 0;
262 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
263 return 1;
265 id = CollapseCommandsForUMA(id);
266 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
267 for (size_t i = 0; i < kMappingSize; ++i) {
268 if (kUmaEnumToControlId[i].control_id == id) {
269 return kUmaEnumToControlId[i].enum_id;
272 return -1;
275 // Usually a new tab is expected where this function is used,
276 // however users should be able to open a tab in background
277 // or in a new window.
278 WindowOpenDisposition ForceNewTabDispositionFromEventFlags(
279 int event_flags) {
280 WindowOpenDisposition disposition =
281 ui::DispositionFromEventFlags(event_flags);
282 return disposition == CURRENT_TAB ? NEW_FOREGROUND_TAB : disposition;
285 // Returns the preference of the profile represented by the |context|.
286 PrefService* GetPrefs(content::BrowserContext* context) {
287 return user_prefs::UserPrefs::Get(context);
290 bool ExtensionPatternMatch(const extensions::URLPatternSet& patterns,
291 const GURL& url) {
292 // No patterns means no restriction, so that implicitly matches.
293 if (patterns.is_empty())
294 return true;
295 return patterns.MatchesURL(url);
298 const GURL& GetDocumentURL(const content::ContextMenuParams& params) {
299 return params.frame_url.is_empty() ? params.page_url : params.frame_url;
302 content::Referrer CreateSaveAsReferrer(
303 const GURL& url,
304 const content::ContextMenuParams& params) {
305 const GURL& referring_url = GetDocumentURL(params);
306 return content::Referrer::SanitizeForRequest(
307 url,
308 content::Referrer(referring_url.GetAsReferrer(), params.referrer_policy));
311 content::WebContents* GetWebContentsToUse(content::WebContents* web_contents) {
312 #if defined(ENABLE_EXTENSIONS)
313 // If we're viewing in a MimeHandlerViewGuest, use its embedder WebContents.
314 if (extensions::MimeHandlerViewGuest::FromWebContents(web_contents)) {
315 WebContents* top_level_web_contents =
316 guest_view::GuestViewBase::GetTopLevelWebContents(web_contents);
317 if (top_level_web_contents)
318 return top_level_web_contents;
320 #endif
321 return web_contents;
324 void WriteURLToClipboard(const GURL& url, const std::string& languages) {
325 if (url.is_empty() || !url.is_valid())
326 return;
328 // Unescaping path and query is not a good idea because other applications
329 // may not encode non-ASCII characters in UTF-8. See crbug.com/2820.
330 base::string16 text =
331 url.SchemeIs(url::kMailToScheme)
332 ? base::ASCIIToUTF16(url.path())
333 : url_formatter::FormatUrl(
334 url, languages, url_formatter::kFormatUrlOmitNothing,
335 net::UnescapeRule::NONE, nullptr, nullptr, nullptr);
337 ui::ScopedClipboardWriter scw(ui::CLIPBOARD_TYPE_COPY_PASTE);
338 scw.WriteURL(text);
341 bool g_custom_id_ranges_initialized = false;
343 const int kSpellcheckRadioGroup = 1;
345 } // namespace
347 // static
348 gfx::Vector2d RenderViewContextMenu::GetOffset(
349 RenderFrameHost* render_frame_host) {
350 gfx::Vector2d offset;
351 #if defined(ENABLE_EXTENSIONS)
352 WebContents* web_contents =
353 WebContents::FromRenderFrameHost(render_frame_host);
354 WebContents* top_level_web_contents =
355 guest_view::GuestViewBase::GetTopLevelWebContents(web_contents);
356 if (web_contents && top_level_web_contents &&
357 web_contents != top_level_web_contents) {
358 gfx::Rect bounds = web_contents->GetContainerBounds();
359 gfx::Rect top_level_bounds = top_level_web_contents->GetContainerBounds();
360 offset = bounds.origin() - top_level_bounds.origin();
362 #endif // defined(ENABLE_EXTENSIONS)
363 return offset;
366 // static
367 bool RenderViewContextMenu::IsDevToolsURL(const GURL& url) {
368 return url.SchemeIs(content::kChromeDevToolsScheme);
371 // static
372 bool RenderViewContextMenu::IsInternalResourcesURL(const GURL& url) {
373 if (!url.SchemeIs(content::kChromeUIScheme))
374 return false;
375 return url.host() == chrome::kChromeUISyncResourcesHost;
378 RenderViewContextMenu::RenderViewContextMenu(
379 content::RenderFrameHost* render_frame_host,
380 const content::ContextMenuParams& params)
381 : RenderViewContextMenuBase(render_frame_host, params),
382 extension_items_(browser_context_,
383 this,
384 &menu_model_,
385 base::Bind(MenuItemMatchesParams, params_)),
386 protocol_handler_submenu_model_(this),
387 protocol_handler_registry_(
388 ProtocolHandlerRegistryFactory::GetForBrowserContext(GetProfile())),
389 embedder_web_contents_(GetWebContentsToUse(source_web_contents_)) {
390 if (!g_custom_id_ranges_initialized) {
391 g_custom_id_ranges_initialized = true;
392 SetContentCustomCommandIdRange(IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
393 IDC_CONTENT_CONTEXT_CUSTOM_LAST);
395 set_content_type(ContextMenuContentTypeFactory::Create(
396 source_web_contents_, params));
399 RenderViewContextMenu::~RenderViewContextMenu() {
402 // Menu construction functions -------------------------------------------------
404 #if defined(ENABLE_EXTENSIONS)
405 // static
406 bool RenderViewContextMenu::ExtensionContextAndPatternMatch(
407 const content::ContextMenuParams& params,
408 const MenuItem::ContextList& contexts,
409 const extensions::URLPatternSet& target_url_patterns) {
410 const bool has_link = !params.link_url.is_empty();
411 const bool has_selection = !params.selection_text.empty();
412 const bool in_frame = !params.frame_url.is_empty();
414 if (contexts.Contains(MenuItem::ALL) ||
415 (has_selection && contexts.Contains(MenuItem::SELECTION)) ||
416 (params.is_editable && contexts.Contains(MenuItem::EDITABLE)) ||
417 (in_frame && contexts.Contains(MenuItem::FRAME)))
418 return true;
420 if (has_link && contexts.Contains(MenuItem::LINK) &&
421 ExtensionPatternMatch(target_url_patterns, params.link_url))
422 return true;
424 switch (params.media_type) {
425 case WebContextMenuData::MediaTypeImage:
426 if (contexts.Contains(MenuItem::IMAGE) &&
427 ExtensionPatternMatch(target_url_patterns, params.src_url))
428 return true;
429 break;
431 case WebContextMenuData::MediaTypeVideo:
432 if (contexts.Contains(MenuItem::VIDEO) &&
433 ExtensionPatternMatch(target_url_patterns, params.src_url))
434 return true;
435 break;
437 case WebContextMenuData::MediaTypeAudio:
438 if (contexts.Contains(MenuItem::AUDIO) &&
439 ExtensionPatternMatch(target_url_patterns, params.src_url))
440 return true;
441 break;
443 default:
444 break;
447 // PAGE is the least specific context, so we only examine that if none of the
448 // other contexts apply (except for FRAME, which is included in PAGE for
449 // backwards compatibility).
450 if (!has_link && !has_selection && !params.is_editable &&
451 params.media_type == WebContextMenuData::MediaTypeNone &&
452 contexts.Contains(MenuItem::PAGE))
453 return true;
455 return false;
458 // static
459 bool RenderViewContextMenu::MenuItemMatchesParams(
460 const content::ContextMenuParams& params,
461 const extensions::MenuItem* item) {
462 bool match = ExtensionContextAndPatternMatch(params, item->contexts(),
463 item->target_url_patterns());
464 if (!match)
465 return false;
467 const GURL& document_url = GetDocumentURL(params);
468 return ExtensionPatternMatch(item->document_url_patterns(), document_url);
471 void RenderViewContextMenu::AppendAllExtensionItems() {
472 extension_items_.Clear();
473 ExtensionService* service =
474 extensions::ExtensionSystem::Get(browser_context_)->extension_service();
475 if (!service)
476 return; // In unit-tests, we may not have an ExtensionService.
478 MenuManager* menu_manager = MenuManager::Get(browser_context_);
479 if (!menu_manager)
480 return;
482 base::string16 printable_selection_text = PrintableSelectionText();
483 EscapeAmpersands(&printable_selection_text);
485 // Get a list of extension id's that have context menu items, and sort by the
486 // top level context menu title of the extension.
487 std::set<MenuItem::ExtensionKey> ids = menu_manager->ExtensionIds();
488 std::vector<base::string16> sorted_menu_titles;
489 std::map<base::string16, std::vector<const Extension*>>
490 title_to_extensions_map;
491 for (std::set<MenuItem::ExtensionKey>::iterator iter = ids.begin();
492 iter != ids.end();
493 ++iter) {
494 const Extension* extension =
495 service->GetExtensionById(iter->extension_id, false);
496 // Platform apps have their context menus created directly in
497 // AppendPlatformAppItems.
498 if (extension && !extension->is_platform_app()) {
499 base::string16 menu_title = extension_items_.GetTopLevelContextMenuTitle(
500 *iter, printable_selection_text);
501 title_to_extensions_map[menu_title].push_back(extension);
502 sorted_menu_titles.push_back(menu_title);
505 if (sorted_menu_titles.empty())
506 return;
508 const std::string app_locale = g_browser_process->GetApplicationLocale();
509 l10n_util::SortStrings16(app_locale, &sorted_menu_titles);
510 sorted_menu_titles.erase(
511 std::unique(sorted_menu_titles.begin(), sorted_menu_titles.end()),
512 sorted_menu_titles.end());
514 int index = 0;
515 for (size_t i = 0; i < sorted_menu_titles.size(); ++i) {
516 std::vector<const Extension*>& extensions =
517 title_to_extensions_map[sorted_menu_titles[i]];
518 for (const auto& extension : extensions) {
519 MenuItem::ExtensionKey extension_key(extension->id());
520 extension_items_.AppendExtensionItems(extension_key,
521 printable_selection_text, &index,
522 false); // is_action_menu
527 void RenderViewContextMenu::AppendCurrentExtensionItems() {
528 // Avoid appending extension related items when |extension| is null.
529 // For Panel, this happens when the panel is navigated to a url outside of the
530 // extension's package.
531 const Extension* extension = GetExtension();
532 if (!extension)
533 return;
535 extensions::WebViewGuest* web_view_guest =
536 extensions::WebViewGuest::FromWebContents(source_web_contents_);
537 MenuItem::ExtensionKey key;
538 if (web_view_guest) {
539 key = MenuItem::ExtensionKey(
540 extension->id(),
541 web_view_guest->owner_web_contents()->GetRenderProcessHost()->GetID(),
542 web_view_guest->view_instance_id());
543 } else {
544 key = MenuItem::ExtensionKey(extension->id());
547 // Only add extension items from this extension.
548 int index = 0;
549 extension_items_.AppendExtensionItems(key, PrintableSelectionText(), &index,
550 false /* is_action_menu */);
552 #endif // defined(ENABLE_EXTENSIONS)
554 void RenderViewContextMenu::InitMenu() {
555 RenderViewContextMenuBase::InitMenu();
557 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PAGE))
558 AppendPageItems();
560 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_FRAME)) {
561 // Merge in frame items with page items if we clicked within a frame that
562 // needs them.
563 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
564 AppendFrameItems();
567 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_LINK)) {
568 AppendLinkItems();
569 if (params_.media_type != WebContextMenuData::MediaTypeNone)
570 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
573 if (content_type_->SupportsGroup(
574 ContextMenuContentType::ITEM_GROUP_MEDIA_IMAGE)) {
575 AppendImageItems();
578 if (content_type_->SupportsGroup(
579 ContextMenuContentType::ITEM_GROUP_SEARCHWEBFORIMAGE)) {
580 AppendSearchWebForImageItems();
583 if (content_type_->SupportsGroup(
584 ContextMenuContentType::ITEM_GROUP_MEDIA_VIDEO)) {
585 AppendVideoItems();
588 if (content_type_->SupportsGroup(
589 ContextMenuContentType::ITEM_GROUP_MEDIA_AUDIO)) {
590 AppendAudioItems();
593 if (content_type_->SupportsGroup(
594 ContextMenuContentType::ITEM_GROUP_MEDIA_CANVAS)) {
595 AppendCanvasItems();
598 if (content_type_->SupportsGroup(
599 ContextMenuContentType::ITEM_GROUP_MEDIA_PLUGIN)) {
600 AppendPluginItems();
603 // ITEM_GROUP_MEDIA_FILE has no specific items.
605 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_EDITABLE))
606 AppendEditableItems();
608 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_COPY)) {
609 DCHECK(!content_type_->SupportsGroup(
610 ContextMenuContentType::ITEM_GROUP_EDITABLE));
611 AppendCopyItem();
614 if (content_type_->SupportsGroup(
615 ContextMenuContentType::ITEM_GROUP_SEARCH_PROVIDER)) {
616 AppendSearchProvider();
619 if (content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT))
620 AppendPrintItem();
622 if (content_type_->SupportsGroup(
623 ContextMenuContentType::ITEM_GROUP_MEDIA_PLUGIN)) {
624 AppendRotationItems();
627 if (content_type_->SupportsGroup(
628 ContextMenuContentType::ITEM_GROUP_ALL_EXTENSION)) {
629 DCHECK(!content_type_->SupportsGroup(
630 ContextMenuContentType::ITEM_GROUP_CURRENT_EXTENSION));
631 AppendAllExtensionItems();
634 if (content_type_->SupportsGroup(
635 ContextMenuContentType::ITEM_GROUP_CURRENT_EXTENSION)) {
636 DCHECK(!content_type_->SupportsGroup(
637 ContextMenuContentType::ITEM_GROUP_ALL_EXTENSION));
638 AppendCurrentExtensionItems();
641 if (content_type_->SupportsGroup(
642 ContextMenuContentType::ITEM_GROUP_DEVELOPER)) {
643 AppendDeveloperItems();
646 if (content_type_->SupportsGroup(
647 ContextMenuContentType::ITEM_GROUP_DEVTOOLS_UNPACKED_EXT)) {
648 AppendDevtoolsForUnpackedExtensions();
651 if (content_type_->SupportsGroup(
652 ContextMenuContentType::ITEM_GROUP_PRINT_PREVIEW)) {
653 AppendPrintPreviewItems();
656 if (content_type_->SupportsGroup(
657 ContextMenuContentType::ITEM_GROUP_PASSWORD)) {
658 AppendPasswordItems();
662 Profile* RenderViewContextMenu::GetProfile() {
663 return Profile::FromBrowserContext(browser_context_);
666 void RenderViewContextMenu::RecordUsedItem(int id) {
667 int enum_id = FindUMAEnumValueForCommand(id);
668 if (enum_id != -1) {
669 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
670 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Used", enum_id,
671 kUmaEnumToControlId[kMappingSize - 1].enum_id);
672 } else {
673 NOTREACHED() << "Update kUmaEnumToControlId. Unhanded IDC: " << id;
677 void RenderViewContextMenu::RecordShownItem(int id) {
678 int enum_id = FindUMAEnumValueForCommand(id);
679 if (enum_id != -1) {
680 const size_t kMappingSize = arraysize(kUmaEnumToControlId);
681 UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Shown", enum_id,
682 kUmaEnumToControlId[kMappingSize - 1].enum_id);
683 } else {
684 // Just warning here. It's harder to maintain list of all possibly
685 // visible items than executable items.
686 DLOG(ERROR) << "Update kUmaEnumToControlId. Unhanded IDC: " << id;
690 #if defined(ENABLE_PLUGINS)
691 void RenderViewContextMenu::HandleAuthorizeAllPlugins() {
692 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins(
693 source_web_contents_, false, std::string());
695 #endif
697 void RenderViewContextMenu::AppendPrintPreviewItems() {
698 #if defined(ENABLE_PRINT_PREVIEW)
699 if (!print_preview_menu_observer_.get()) {
700 print_preview_menu_observer_.reset(
701 new PrintPreviewContextMenuObserver(source_web_contents_));
704 observers_.AddObserver(print_preview_menu_observer_.get());
705 #endif
708 const Extension* RenderViewContextMenu::GetExtension() const {
709 return extensions::ProcessManager::Get(browser_context_)
710 ->GetExtensionForWebContents(source_web_contents_);
713 void RenderViewContextMenu::AppendDeveloperItems() {
714 // Show Inspect Element in DevTools itself only in case of the debug
715 // devtools build.
716 bool show_developer_items = !IsDevToolsURL(params_.page_url);
718 #if defined(DEBUG_DEVTOOLS)
719 show_developer_items = true;
720 #endif
722 if (!show_developer_items)
723 return;
725 // In the DevTools popup menu, "developer items" is normally the only
726 // section, so omit the separator there.
727 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
728 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTELEMENT,
729 IDS_CONTENT_CONTEXT_INSPECTELEMENT);
732 void RenderViewContextMenu::AppendDevtoolsForUnpackedExtensions() {
733 // Add a separator if there are any items already in the menu.
734 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
736 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP,
737 IDS_CONTENT_CONTEXT_RELOAD_PACKAGED_APP);
738 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP,
739 IDS_CONTENT_CONTEXT_RESTART_APP);
740 AppendDeveloperItems();
741 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE,
742 IDS_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE);
745 void RenderViewContextMenu::AppendLinkItems() {
746 if (!params_.link_url.is_empty()) {
747 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB,
748 IDS_CONTENT_CONTEXT_OPENLINKNEWTAB);
749 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW,
750 IDS_CONTENT_CONTEXT_OPENLINKNEWWINDOW);
751 if (params_.link_url.is_valid()) {
752 AppendProtocolHandlerSubMenu();
755 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD,
756 IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD);
757 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVELINKAS,
758 IDS_CONTENT_CONTEXT_SAVELINKAS);
761 menu_model_.AddItemWithStringId(
762 IDC_CONTENT_CONTEXT_COPYLINKLOCATION,
763 params_.link_url.SchemeIs(url::kMailToScheme) ?
764 IDS_CONTENT_CONTEXT_COPYEMAILADDRESS :
765 IDS_CONTENT_CONTEXT_COPYLINKLOCATION);
768 void RenderViewContextMenu::AppendImageItems() {
769 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS,
770 IDS_CONTENT_CONTEXT_SAVEIMAGEAS);
771 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGELOCATION,
772 IDS_CONTENT_CONTEXT_COPYIMAGELOCATION);
773 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
774 IDS_CONTENT_CONTEXT_COPYIMAGE);
775 std::map<std::string, std::string>::const_iterator it =
776 params_.properties.find(data_reduction_proxy::chrome_proxy_header());
777 if (it != params_.properties.end() && it->second ==
778 data_reduction_proxy::chrome_proxy_lo_fi_directive()) {
779 menu_model_.AddItemWithStringId(
780 IDC_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE,
781 IDS_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE);
783 DataReductionProxyChromeSettings* settings =
784 DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
785 browser_context_);
786 if (settings && settings->CanUseDataReductionProxy(params_.src_url)) {
787 menu_model_.AddItemWithStringId(
788 IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB,
789 IDS_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB);
790 } else {
791 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB,
792 IDS_CONTENT_CONTEXT_OPENIMAGENEWTAB);
796 void RenderViewContextMenu::AppendSearchWebForImageItems() {
797 TemplateURLService* service =
798 TemplateURLServiceFactory::GetForProfile(GetProfile());
799 const TemplateURL* const default_provider =
800 service->GetDefaultSearchProvider();
801 if (params_.has_image_contents && default_provider &&
802 !default_provider->image_url().empty() &&
803 default_provider->image_url_ref().IsValid(service->search_terms_data())) {
804 menu_model_.AddItem(
805 IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE,
806 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFORIMAGE,
807 default_provider->short_name()));
811 void RenderViewContextMenu::AppendAudioItems() {
812 AppendMediaItems();
813 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
814 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
815 IDS_CONTENT_CONTEXT_SAVEAUDIOAS);
816 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
817 IDS_CONTENT_CONTEXT_COPYAUDIOLOCATION);
818 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
819 IDS_CONTENT_CONTEXT_OPENAUDIONEWTAB);
822 void RenderViewContextMenu::AppendCanvasItems() {
823 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS,
824 IDS_CONTENT_CONTEXT_SAVEIMAGEAS);
825 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
826 IDS_CONTENT_CONTEXT_COPYIMAGE);
829 void RenderViewContextMenu::AppendVideoItems() {
830 AppendMediaItems();
831 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
832 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
833 IDS_CONTENT_CONTEXT_SAVEVIDEOAS);
834 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
835 IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION);
836 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
837 IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB);
840 void RenderViewContextMenu::AppendMediaItems() {
841 int media_flags = params_.media_flags;
843 menu_model_.AddItemWithStringId(
844 IDC_CONTENT_CONTEXT_PLAYPAUSE,
845 media_flags & WebContextMenuData::MediaPaused ?
846 IDS_CONTENT_CONTEXT_PLAY :
847 IDS_CONTENT_CONTEXT_PAUSE);
849 menu_model_.AddItemWithStringId(
850 IDC_CONTENT_CONTEXT_MUTE,
851 media_flags & WebContextMenuData::MediaMuted ?
852 IDS_CONTENT_CONTEXT_UNMUTE :
853 IDS_CONTENT_CONTEXT_MUTE);
855 menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_LOOP,
856 IDS_CONTENT_CONTEXT_LOOP);
857 menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_CONTROLS,
858 IDS_CONTENT_CONTEXT_CONTROLS);
861 void RenderViewContextMenu::AppendPluginItems() {
862 if (params_.page_url == params_.src_url ||
863 guest_view::GuestViewBase::IsGuest(source_web_contents_)) {
864 // Full page plugin, so show page menu items.
865 if (params_.link_url.is_empty() && params_.selection_text.empty())
866 AppendPageItems();
867 } else {
868 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
869 IDS_CONTENT_CONTEXT_SAVEPAGEAS);
870 // The "Print" menu item should always be included for plugins. If
871 // content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT)
872 // is true the item will be added inside AppendPrintItem(). Otherwise we
873 // add "Print" here.
874 if (!content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_PRINT))
875 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
879 void RenderViewContextMenu::AppendPageItems() {
880 menu_model_.AddItemWithStringId(IDC_BACK, IDS_CONTENT_CONTEXT_BACK);
881 menu_model_.AddItemWithStringId(IDC_FORWARD, IDS_CONTENT_CONTEXT_FORWARD);
882 menu_model_.AddItemWithStringId(IDC_RELOAD, IDS_CONTENT_CONTEXT_RELOAD);
883 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
884 menu_model_.AddItemWithStringId(IDC_SAVE_PAGE,
885 IDS_CONTENT_CONTEXT_SAVEPAGEAS);
886 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
888 if (TranslateService::IsTranslatableURL(params_.page_url)) {
889 std::string locale = g_browser_process->GetApplicationLocale();
890 locale = translate::TranslateDownloadManager::GetLanguageCode(locale);
891 base::string16 language =
892 l10n_util::GetDisplayNameForLocale(locale, locale, true);
893 menu_model_.AddItem(
894 IDC_CONTENT_CONTEXT_TRANSLATE,
895 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_TRANSLATE, language));
898 menu_model_.AddItemWithStringId(IDC_VIEW_SOURCE,
899 IDS_CONTENT_CONTEXT_VIEWPAGESOURCE);
900 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWPAGEINFO,
901 IDS_CONTENT_CONTEXT_VIEWPAGEINFO);
904 void RenderViewContextMenu::AppendFrameItems() {
905 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOADFRAME,
906 IDS_CONTENT_CONTEXT_RELOADFRAME);
907 // These two menu items have yet to be implemented.
908 // http://code.google.com/p/chromium/issues/detail?id=11827
909 // IDS_CONTENT_CONTEXT_SAVEFRAMEAS
910 // IDS_CONTENT_CONTEXT_PRINTFRAME
911 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE,
912 IDS_CONTENT_CONTEXT_VIEWFRAMESOURCE);
913 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMEINFO,
914 IDS_CONTENT_CONTEXT_VIEWFRAMEINFO);
917 void RenderViewContextMenu::AppendCopyItem() {
918 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
919 IDS_CONTENT_CONTEXT_COPY);
922 void RenderViewContextMenu::AppendPrintItem() {
923 if (GetPrefs(browser_context_)->GetBoolean(prefs::kPrintingEnabled) &&
924 (params_.media_type == WebContextMenuData::MediaTypeNone ||
925 params_.media_flags & WebContextMenuData::MediaCanPrint)) {
926 menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
930 void RenderViewContextMenu::AppendRotationItems() {
931 if (params_.media_flags & WebContextMenuData::MediaCanRotate) {
932 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
933 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECW,
934 IDS_CONTENT_CONTEXT_ROTATECW);
935 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECCW,
936 IDS_CONTENT_CONTEXT_ROTATECCW);
940 void RenderViewContextMenu::AppendSearchProvider() {
941 DCHECK(browser_context_);
943 base::TrimWhitespace(params_.selection_text, base::TRIM_ALL,
944 &params_.selection_text);
945 if (params_.selection_text.empty())
946 return;
948 base::ReplaceChars(params_.selection_text, AutocompleteMatch::kInvalidChars,
949 base::ASCIIToUTF16(" "), &params_.selection_text);
951 AutocompleteMatch match;
952 AutocompleteClassifierFactory::GetForProfile(GetProfile())->Classify(
953 params_.selection_text,
954 false,
955 false,
956 metrics::OmniboxEventProto::INVALID_SPEC,
957 &match,
958 NULL);
959 selection_navigation_url_ = match.destination_url;
960 if (!selection_navigation_url_.is_valid())
961 return;
963 base::string16 printable_selection_text = PrintableSelectionText();
964 EscapeAmpersands(&printable_selection_text);
966 if (AutocompleteMatch::IsSearchType(match.type)) {
967 const TemplateURL* const default_provider =
968 TemplateURLServiceFactory::GetForProfile(GetProfile())
969 ->GetDefaultSearchProvider();
970 if (!default_provider)
971 return;
972 menu_model_.AddItem(
973 IDC_CONTENT_CONTEXT_SEARCHWEBFOR,
974 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFOR,
975 default_provider->short_name(),
976 printable_selection_text));
977 } else {
978 if ((selection_navigation_url_ != params_.link_url) &&
979 ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme(
980 selection_navigation_url_.scheme())) {
981 menu_model_.AddItem(
982 IDC_CONTENT_CONTEXT_GOTOURL,
983 l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_GOTOURL,
984 printable_selection_text));
989 void RenderViewContextMenu::AppendEditableItems() {
990 const bool use_spellcheck_and_search = !chrome::IsRunningInForcedAppMode();
992 if (use_spellcheck_and_search)
993 AppendSpellingSuggestionsSubMenu();
995 if (!IsDevToolsURL(params_.page_url)) {
996 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_UNDO,
997 IDS_CONTENT_CONTEXT_UNDO);
998 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_REDO,
999 IDS_CONTENT_CONTEXT_REDO);
1000 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1003 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_CUT,
1004 IDS_CONTENT_CONTEXT_CUT);
1005 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
1006 IDS_CONTENT_CONTEXT_COPY);
1007 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE,
1008 IDS_CONTENT_CONTEXT_PASTE);
1009 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE,
1010 IDS_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE);
1011 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_DELETE,
1012 IDS_CONTENT_CONTEXT_DELETE);
1013 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1015 if (use_spellcheck_and_search && !params_.keyword_url.is_empty()) {
1016 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ADDSEARCHENGINE,
1017 IDS_CONTENT_CONTEXT_ADDSEARCHENGINE);
1018 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1021 #if defined(OS_MACOSX)
1022 if (use_spellcheck_and_search)
1023 AppendSpellcheckOptionsSubMenu();
1024 #else
1025 if (chrome::spellcheck_common::IsMultilingualSpellcheckEnabled()) {
1026 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS,
1027 IDS_CONTENT_CONTEXT_LANGUAGE_SETTINGS);
1028 } else if (use_spellcheck_and_search) {
1029 AppendSpellcheckOptionsSubMenu();
1031 #endif // defined(OS_MACOSX)
1033 AppendPlatformEditableItems();
1035 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1036 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SELECTALL,
1037 IDS_CONTENT_CONTEXT_SELECTALL);
1040 void RenderViewContextMenu::AppendSpellingSuggestionsSubMenu() {
1041 if (!spelling_menu_observer_.get())
1042 spelling_menu_observer_.reset(new SpellingMenuObserver(this));
1043 observers_.AddObserver(spelling_menu_observer_.get());
1044 spelling_menu_observer_->InitMenu(params_);
1047 void RenderViewContextMenu::AppendSpellcheckOptionsSubMenu() {
1048 if (!spellchecker_submenu_observer_.get()) {
1049 spellchecker_submenu_observer_.reset(new SpellCheckerSubMenuObserver(
1050 this, this, kSpellcheckRadioGroup));
1052 spellchecker_submenu_observer_->InitMenu(params_);
1053 observers_.AddObserver(spellchecker_submenu_observer_.get());
1056 void RenderViewContextMenu::AppendProtocolHandlerSubMenu() {
1057 const ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1058 GetHandlersForLinkUrl();
1059 if (handlers.empty())
1060 return;
1061 size_t max = IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST -
1062 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
1063 for (size_t i = 0; i < handlers.size() && i <= max; i++) {
1064 protocol_handler_submenu_model_.AddItem(
1065 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST + i,
1066 base::UTF8ToUTF16(handlers[i].url().host()));
1068 protocol_handler_submenu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1069 protocol_handler_submenu_model_.AddItem(
1070 IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS,
1071 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH_CONFIGURE));
1073 menu_model_.AddSubMenu(
1074 IDC_CONTENT_CONTEXT_OPENLINKWITH,
1075 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH),
1076 &protocol_handler_submenu_model_);
1079 void RenderViewContextMenu::AppendPasswordItems() {
1080 if (!password_manager::ForceSavingExperimentEnabled())
1081 return;
1083 menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
1084 menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD,
1085 IDS_CONTENT_CONTEXT_FORCESAVEPASSWORD);
1088 // Menu delegate functions -----------------------------------------------------
1090 bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
1092 bool enabled = false;
1093 if (RenderViewContextMenuBase::IsCommandIdKnown(id, &enabled))
1094 return enabled;
1097 CoreTabHelper* core_tab_helper =
1098 CoreTabHelper::FromWebContents(source_web_contents_);
1099 int content_restrictions = 0;
1100 if (core_tab_helper)
1101 content_restrictions = core_tab_helper->content_restrictions();
1102 if (id == IDC_PRINT && (content_restrictions & CONTENT_RESTRICTION_PRINT))
1103 return false;
1105 if (id == IDC_SAVE_PAGE &&
1106 (content_restrictions & CONTENT_RESTRICTION_SAVE)) {
1107 return false;
1110 PrefService* prefs = GetPrefs(browser_context_);
1112 // Allow Spell Check language items on sub menu for text area context menu.
1113 if ((id >= IDC_SPELLCHECK_LANGUAGES_FIRST) &&
1114 (id < IDC_SPELLCHECK_LANGUAGES_LAST)) {
1115 return prefs->GetBoolean(prefs::kEnableContinuousSpellcheck);
1118 // Extension items.
1119 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
1120 return extension_items_.IsCommandIdEnabled(id);
1122 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
1123 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
1124 return true;
1127 IncognitoModePrefs::Availability incognito_avail =
1128 IncognitoModePrefs::GetAvailability(prefs);
1129 switch (id) {
1130 case IDC_BACK:
1131 return embedder_web_contents_->GetController().CanGoBack();
1133 case IDC_FORWARD:
1134 return embedder_web_contents_->GetController().CanGoForward();
1136 case IDC_RELOAD: {
1137 CoreTabHelper* core_tab_helper =
1138 CoreTabHelper::FromWebContents(embedder_web_contents_);
1139 if (!core_tab_helper)
1140 return false;
1142 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
1143 return !core_delegate ||
1144 core_delegate->CanReloadContents(embedder_web_contents_);
1147 case IDC_VIEW_SOURCE:
1148 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
1149 return (params_.media_type != WebContextMenuData::MediaTypePlugin) &&
1150 embedder_web_contents_->GetController().CanViewSource();
1152 case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
1153 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE:
1154 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP:
1155 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP:
1156 return IsDevCommandEnabled(id);
1158 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO:
1159 if (embedder_web_contents_->GetController().GetVisibleEntry() == NULL)
1160 return false;
1161 // Disabled if no browser is associated (e.g. desktop notifications).
1162 if (chrome::FindBrowserWithWebContents(embedder_web_contents_) == NULL)
1163 return false;
1164 return true;
1166 case IDC_CONTENT_CONTEXT_TRANSLATE: {
1167 ChromeTranslateClient* chrome_translate_client =
1168 ChromeTranslateClient::FromWebContents(embedder_web_contents_);
1169 if (!chrome_translate_client)
1170 return false;
1171 std::string original_lang =
1172 chrome_translate_client->GetLanguageState().original_language();
1173 std::string target_lang = g_browser_process->GetApplicationLocale();
1174 target_lang =
1175 translate::TranslateDownloadManager::GetLanguageCode(target_lang);
1176 // Note that we intentionally enable the menu even if the original and
1177 // target languages are identical. This is to give a way to user to
1178 // translate a page that might contains text fragments in a different
1179 // language.
1180 return ((params_.edit_flags & WebContextMenuData::CanTranslate) != 0) &&
1181 !original_lang.empty() && // Did we receive the page language yet?
1182 !chrome_translate_client->GetLanguageState().IsPageTranslated() &&
1183 !embedder_web_contents_->GetInterstitialPage() &&
1184 // There are some application locales which can't be used as a
1185 // target language for translation.
1186 translate::TranslateDownloadManager::IsSupportedLanguage(
1187 target_lang) &&
1188 // Disable on the Instant Extended NTP.
1189 !search::IsInstantNTP(embedder_web_contents_);
1192 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB:
1193 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
1194 return params_.link_url.is_valid();
1196 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
1197 return params_.unfiltered_link_url.is_valid();
1199 case IDC_CONTENT_CONTEXT_SAVELINKAS: {
1200 PrefService* local_state = g_browser_process->local_state();
1201 DCHECK(local_state);
1202 // Test if file-selection dialogs are forbidden by policy.
1203 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1204 return false;
1206 return params_.link_url.is_valid() &&
1207 ProfileIOData::IsHandledProtocol(params_.link_url.scheme());
1210 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: {
1211 PrefService* local_state = g_browser_process->local_state();
1212 DCHECK(local_state);
1213 // Test if file-selection dialogs are forbidden by policy.
1214 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1215 return false;
1217 return params_.has_image_contents;
1220 // The images shown in the most visited thumbnails can't be opened or
1221 // searched for conventionally.
1222 case IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB:
1223 case IDC_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE:
1224 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
1225 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
1226 return params_.src_url.is_valid() &&
1227 (params_.src_url.scheme() != content::kChromeUIScheme);
1229 case IDC_CONTENT_CONTEXT_COPYIMAGE:
1230 return params_.has_image_contents;
1232 // Media control commands should all be disabled if the player is in an
1233 // error state.
1234 case IDC_CONTENT_CONTEXT_PLAYPAUSE:
1235 case IDC_CONTENT_CONTEXT_LOOP:
1236 return (params_.media_flags &
1237 WebContextMenuData::MediaInError) == 0;
1239 // Mute and unmute should also be disabled if the player has no audio.
1240 case IDC_CONTENT_CONTEXT_MUTE:
1241 return (params_.media_flags &
1242 WebContextMenuData::MediaHasAudio) != 0 &&
1243 (params_.media_flags &
1244 WebContextMenuData::MediaInError) == 0;
1246 case IDC_CONTENT_CONTEXT_CONTROLS:
1247 return (params_.media_flags &
1248 WebContextMenuData::MediaCanToggleControls) != 0;
1250 case IDC_CONTENT_CONTEXT_ROTATECW:
1251 case IDC_CONTENT_CONTEXT_ROTATECCW:
1252 return
1253 (params_.media_flags & WebContextMenuData::MediaCanRotate) != 0;
1255 case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
1256 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
1257 return params_.src_url.is_valid();
1259 case IDC_CONTENT_CONTEXT_SAVEAVAS: {
1260 PrefService* local_state = g_browser_process->local_state();
1261 DCHECK(local_state);
1262 // Test if file-selection dialogs are forbidden by policy.
1263 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1264 return false;
1266 const GURL& url = params_.src_url;
1267 bool can_save =
1268 (params_.media_flags & WebContextMenuData::MediaCanSave) &&
1269 url.is_valid() && ProfileIOData::IsHandledProtocol(url.scheme());
1270 #if defined(ENABLE_PRINT_PREVIEW)
1271 // Do not save the preview PDF on the print preview page.
1272 can_save = can_save &&
1273 !(printing::PrintPreviewDialogController::IsPrintPreviewURL(url));
1274 #endif
1275 return can_save;
1278 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
1279 // Currently, a media element can be opened in a new tab iff it can
1280 // be saved. So rather than duplicating the MediaCanSave flag, we rely
1281 // on that here.
1282 return !!(params_.media_flags & WebContextMenuData::MediaCanSave);
1284 case IDC_SAVE_PAGE: {
1285 CoreTabHelper* core_tab_helper =
1286 CoreTabHelper::FromWebContents(embedder_web_contents_);
1287 if (!core_tab_helper)
1288 return false;
1290 CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
1291 if (core_delegate &&
1292 !core_delegate->CanSaveContents(embedder_web_contents_))
1293 return false;
1295 PrefService* local_state = g_browser_process->local_state();
1296 DCHECK(local_state);
1297 // Test if file-selection dialogs are forbidden by policy.
1298 if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
1299 return false;
1301 // We save the last committed entry (which the user is looking at), as
1302 // opposed to any pending URL that hasn't committed yet.
1303 NavigationEntry* entry =
1304 embedder_web_contents_->GetController().GetLastCommittedEntry();
1305 return content::IsSavableURL(entry ? entry->GetURL() : GURL());
1308 case IDC_CONTENT_CONTEXT_RELOADFRAME:
1309 return params_.frame_url.is_valid();
1311 case IDC_CONTENT_CONTEXT_UNDO:
1312 return !!(params_.edit_flags & WebContextMenuData::CanUndo);
1314 case IDC_CONTENT_CONTEXT_REDO:
1315 return !!(params_.edit_flags & WebContextMenuData::CanRedo);
1317 case IDC_CONTENT_CONTEXT_CUT:
1318 return !!(params_.edit_flags & WebContextMenuData::CanCut);
1320 case IDC_CONTENT_CONTEXT_COPY:
1321 return !!(params_.edit_flags & WebContextMenuData::CanCopy);
1323 case IDC_CONTENT_CONTEXT_PASTE: {
1324 if (!(params_.edit_flags & WebContextMenuData::CanPaste))
1325 return false;
1327 std::vector<base::string16> types;
1328 bool ignore;
1329 ui::Clipboard::GetForCurrentThread()->ReadAvailableTypes(
1330 ui::CLIPBOARD_TYPE_COPY_PASTE, &types, &ignore);
1331 return !types.empty();
1334 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE: {
1335 if (!(params_.edit_flags & WebContextMenuData::CanPaste))
1336 return false;
1338 return ui::Clipboard::GetForCurrentThread()->IsFormatAvailable(
1339 ui::Clipboard::GetPlainTextFormatType(),
1340 ui::CLIPBOARD_TYPE_COPY_PASTE);
1343 case IDC_CONTENT_CONTEXT_DELETE:
1344 return !!(params_.edit_flags & WebContextMenuData::CanDelete);
1346 case IDC_CONTENT_CONTEXT_SELECTALL:
1347 return !!(params_.edit_flags & WebContextMenuData::CanSelectAll);
1349 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
1350 return !browser_context_->IsOffTheRecord() &&
1351 params_.link_url.is_valid() &&
1352 incognito_avail != IncognitoModePrefs::DISABLED;
1354 case IDC_PRINT:
1355 return prefs->GetBoolean(prefs::kPrintingEnabled) &&
1356 (params_.media_type == WebContextMenuData::MediaTypeNone ||
1357 params_.media_flags & WebContextMenuData::MediaCanPrint);
1359 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
1360 case IDC_CONTENT_CONTEXT_GOTOURL:
1361 case IDC_SPELLPANEL_TOGGLE:
1362 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS:
1363 return true;
1364 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO:
1365 // Disabled if no browser is associated (e.g. desktop notifications).
1366 if (chrome::FindBrowserWithWebContents(source_web_contents_) == NULL)
1367 return false;
1368 return true;
1370 case IDC_CHECK_SPELLING_WHILE_TYPING:
1371 return prefs->GetBoolean(prefs::kEnableContinuousSpellcheck);
1373 #if !defined(OS_MACOSX) && defined(OS_POSIX)
1374 // TODO(suzhe): this should not be enabled for password fields.
1375 case IDC_INPUT_METHODS_MENU:
1376 return true;
1377 #endif
1379 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE:
1380 return !params_.keyword_url.is_empty();
1382 case IDC_SPELLCHECK_MENU:
1383 return true;
1385 case IDC_CONTENT_CONTEXT_OPENLINKWITH:
1386 return true;
1388 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS:
1389 return true;
1391 case IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD:
1392 return true;
1394 default:
1395 NOTREACHED();
1396 return false;
1400 bool RenderViewContextMenu::IsCommandIdChecked(int id) const {
1401 if (RenderViewContextMenuBase::IsCommandIdChecked(id))
1402 return true;
1404 // See if the video is set to looping.
1405 if (id == IDC_CONTENT_CONTEXT_LOOP)
1406 return (params_.media_flags & WebContextMenuData::MediaLoop) != 0;
1408 if (id == IDC_CONTENT_CONTEXT_CONTROLS)
1409 return (params_.media_flags & WebContextMenuData::MediaControls) != 0;
1411 // Extension items.
1412 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
1413 return extension_items_.IsCommandIdChecked(id);
1415 return false;
1418 void RenderViewContextMenu::ExecuteCommand(int id, int event_flags) {
1419 RenderViewContextMenuBase::ExecuteCommand(id, event_flags);
1420 if (command_executed_)
1421 return;
1422 command_executed_ = true;
1424 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1426 // Process extension menu items.
1427 if (ContextMenuMatcher::IsExtensionsCustomCommandId(id)) {
1428 extension_items_.ExecuteCommand(id, source_web_contents_, params_);
1429 return;
1432 if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
1433 id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
1434 ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1435 GetHandlersForLinkUrl();
1436 if (handlers.empty())
1437 return;
1439 content::RecordAction(
1440 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Open"));
1441 int handlerIndex = id - IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
1442 WindowOpenDisposition disposition =
1443 ForceNewTabDispositionFromEventFlags(event_flags);
1444 OpenURL(handlers[handlerIndex].TranslateUrl(params_.link_url),
1445 GetDocumentURL(params_),
1446 disposition,
1447 ui::PAGE_TRANSITION_LINK);
1448 return;
1451 switch (id) {
1452 case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB: {
1453 Browser* browser =
1454 chrome::FindBrowserWithWebContents(source_web_contents_);
1455 OpenURL(params_.link_url,
1456 GetDocumentURL(params_),
1457 !browser || browser->is_app() ?
1458 NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB,
1459 ui::PAGE_TRANSITION_LINK);
1460 break;
1462 case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
1463 OpenURL(params_.link_url,
1464 GetDocumentURL(params_),
1465 NEW_WINDOW,
1466 ui::PAGE_TRANSITION_LINK);
1467 break;
1469 case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
1470 OpenURL(params_.link_url, GURL(), OFF_THE_RECORD,
1471 ui::PAGE_TRANSITION_LINK);
1472 break;
1474 case IDC_CONTENT_CONTEXT_SAVELINKAS: {
1475 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
1476 const GURL& url = params_.link_url;
1477 content::Referrer referrer = CreateSaveAsReferrer(url, params_);
1478 DownloadManager* dlm =
1479 BrowserContext::GetDownloadManager(browser_context_);
1480 scoped_ptr<DownloadUrlParameters> dl_params(
1481 DownloadUrlParameters::FromWebContents(source_web_contents_, url));
1482 dl_params->set_referrer(referrer);
1483 dl_params->set_referrer_encoding(params_.frame_charset);
1484 dl_params->set_suggested_name(params_.suggested_filename);
1485 dl_params->set_prompt(true);
1486 dlm->DownloadUrl(dl_params.Pass());
1487 break;
1490 case IDC_CONTENT_CONTEXT_SAVEAVAS:
1491 case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: {
1492 bool is_large_data_url = params_.has_image_contents &&
1493 params_.src_url.is_empty();
1494 if (params_.media_type == WebContextMenuData::MediaTypeCanvas ||
1495 (params_.media_type == WebContextMenuData::MediaTypeImage &&
1496 is_large_data_url)) {
1497 source_web_contents_->GetRenderViewHost()->SaveImageAt(
1498 params_.x, params_.y);
1499 } else {
1500 RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
1501 const GURL& url = params_.src_url;
1502 content::Referrer referrer = CreateSaveAsReferrer(url, params_);
1504 std::string headers;
1505 DataReductionProxyChromeSettings* settings =
1506 DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
1507 browser_context_);
1508 if (params_.media_type == WebContextMenuData::MediaTypeImage &&
1509 settings && settings->CanUseDataReductionProxy(params_.src_url)) {
1510 headers = data_reduction_proxy::kDataReductionPassThroughHeader;
1513 source_web_contents_->SaveFrameWithHeaders(url, referrer, headers);
1515 break;
1518 case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
1519 WriteURLToClipboard(params_.unfiltered_link_url);
1520 break;
1522 case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
1523 case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
1524 WriteURLToClipboard(params_.src_url);
1525 break;
1527 case IDC_CONTENT_CONTEXT_COPYIMAGE:
1528 CopyImageAt(params_.x, params_.y);
1529 break;
1531 case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
1532 GetImageThumbnailForSearch();
1533 break;
1535 case IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB:
1536 OpenURLWithExtraHeaders(
1537 params_.src_url, GetDocumentURL(params_), NEW_BACKGROUND_TAB,
1538 ui::PAGE_TRANSITION_LINK,
1539 data_reduction_proxy::kDataReductionPassThroughHeader);
1540 break;
1542 case IDC_CONTENT_CONTEXT_LOAD_ORIGINAL_IMAGE:
1543 LoadOriginalImage();
1544 break;
1546 case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
1547 case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
1548 OpenURL(params_.src_url,
1549 GetDocumentURL(params_),
1550 NEW_BACKGROUND_TAB,
1551 ui::PAGE_TRANSITION_LINK);
1552 break;
1554 case IDC_CONTENT_CONTEXT_PLAYPAUSE: {
1555 bool play = !!(params_.media_flags & WebContextMenuData::MediaPaused);
1556 if (play) {
1557 content::RecordAction(UserMetricsAction("MediaContextMenu_Play"));
1558 } else {
1559 content::RecordAction(UserMetricsAction("MediaContextMenu_Pause"));
1561 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1562 WebMediaPlayerAction(
1563 WebMediaPlayerAction::Play, play));
1564 break;
1567 case IDC_CONTENT_CONTEXT_MUTE: {
1568 bool mute = !(params_.media_flags & WebContextMenuData::MediaMuted);
1569 if (mute) {
1570 content::RecordAction(UserMetricsAction("MediaContextMenu_Mute"));
1571 } else {
1572 content::RecordAction(UserMetricsAction("MediaContextMenu_Unmute"));
1574 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1575 WebMediaPlayerAction(
1576 WebMediaPlayerAction::Mute, mute));
1577 break;
1580 case IDC_CONTENT_CONTEXT_LOOP:
1581 content::RecordAction(UserMetricsAction("MediaContextMenu_Loop"));
1582 MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
1583 WebMediaPlayerAction(
1584 WebMediaPlayerAction::Loop,
1585 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_LOOP)));
1586 break;
1588 case IDC_CONTENT_CONTEXT_CONTROLS:
1589 content::RecordAction(UserMetricsAction("MediaContextMenu_Controls"));
1590 MediaPlayerActionAt(
1591 gfx::Point(params_.x, params_.y),
1592 WebMediaPlayerAction(
1593 WebMediaPlayerAction::Controls,
1594 !IsCommandIdChecked(IDC_CONTENT_CONTEXT_CONTROLS)));
1595 break;
1597 case IDC_CONTENT_CONTEXT_ROTATECW:
1598 content::RecordAction(
1599 UserMetricsAction("PluginContextMenu_RotateClockwise"));
1600 PluginActionAt(
1601 gfx::Point(params_.x, params_.y),
1602 WebPluginAction(WebPluginAction::Rotate90Clockwise, true));
1603 break;
1605 case IDC_CONTENT_CONTEXT_ROTATECCW:
1606 content::RecordAction(
1607 UserMetricsAction("PluginContextMenu_RotateCounterclockwise"));
1608 PluginActionAt(
1609 gfx::Point(params_.x, params_.y),
1610 WebPluginAction(WebPluginAction::Rotate90Counterclockwise, true));
1611 break;
1613 case IDC_BACK:
1614 embedder_web_contents_->GetController().GoBack();
1615 break;
1617 case IDC_FORWARD:
1618 embedder_web_contents_->GetController().GoForward();
1619 break;
1621 case IDC_SAVE_PAGE:
1622 embedder_web_contents_->OnSavePage();
1623 break;
1625 case IDC_RELOAD:
1626 embedder_web_contents_->GetController().Reload(true);
1627 break;
1629 case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP: {
1630 const Extension* platform_app = GetExtension();
1631 DCHECK(platform_app);
1632 DCHECK(platform_app->is_platform_app());
1634 extensions::ExtensionSystem::Get(browser_context_)
1635 ->extension_service()
1636 ->ReloadExtension(platform_app->id());
1637 break;
1640 case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP: {
1641 const Extension* platform_app = GetExtension();
1642 DCHECK(platform_app);
1643 DCHECK(platform_app->is_platform_app());
1645 apps::AppLoadService::Get(GetProfile())
1646 ->RestartApplication(platform_app->id());
1647 break;
1650 case IDC_PRINT: {
1651 #if defined(ENABLE_PRINTING)
1652 if (params_.media_type != WebContextMenuData::MediaTypeNone) {
1653 if (render_frame_host) {
1654 render_frame_host->Send(new PrintMsg_PrintNodeUnderContextMenu(
1655 render_frame_host->GetRoutingID()));
1657 break;
1660 printing::StartPrint(
1661 source_web_contents_,
1662 GetPrefs(browser_context_)->GetBoolean(prefs::kPrintPreviewDisabled),
1663 !params_.selection_text.empty());
1664 #endif // ENABLE_PRINTING
1665 break;
1668 case IDC_VIEW_SOURCE:
1669 embedder_web_contents_->ViewSource();
1670 break;
1672 case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
1673 Inspect(params_.x, params_.y);
1674 break;
1676 case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE: {
1677 const Extension* platform_app = GetExtension();
1678 DCHECK(platform_app);
1679 DCHECK(platform_app->is_platform_app());
1681 extensions::devtools_util::InspectBackgroundPage(platform_app,
1682 GetProfile());
1683 break;
1686 case IDC_CONTENT_CONTEXT_VIEWPAGEINFO: {
1687 NavigationController* controller =
1688 &embedder_web_contents_->GetController();
1689 // Important to use GetVisibleEntry to match what's showing in the
1690 // omnibox. This may return null.
1691 NavigationEntry* nav_entry = controller->GetVisibleEntry();
1692 if (!nav_entry)
1693 return;
1694 Browser* browser =
1695 chrome::FindBrowserWithWebContents(embedder_web_contents_);
1696 chrome::ShowWebsiteSettings(browser, embedder_web_contents_,
1697 nav_entry->GetURL(), nav_entry->GetSSL());
1698 break;
1701 case IDC_CONTENT_CONTEXT_TRANSLATE: {
1702 // A translation might have been triggered by the time the menu got
1703 // selected, do nothing in that case.
1704 ChromeTranslateClient* chrome_translate_client =
1705 ChromeTranslateClient::FromWebContents(embedder_web_contents_);
1706 if (!chrome_translate_client ||
1707 chrome_translate_client->GetLanguageState().IsPageTranslated() ||
1708 chrome_translate_client->GetLanguageState().translation_pending()) {
1709 return;
1711 std::string original_lang =
1712 chrome_translate_client->GetLanguageState().original_language();
1713 std::string target_lang = g_browser_process->GetApplicationLocale();
1714 target_lang =
1715 translate::TranslateDownloadManager::GetLanguageCode(target_lang);
1716 // Since the user decided to translate for that language and site, clears
1717 // any preferences for not translating them.
1718 scoped_ptr<translate::TranslatePrefs> prefs(
1719 ChromeTranslateClient::CreateTranslatePrefs(
1720 GetPrefs(browser_context_)));
1721 prefs->UnblockLanguage(original_lang);
1722 prefs->RemoveSiteFromBlacklist(params_.page_url.HostNoBrackets());
1723 translate::TranslateManager* manager =
1724 chrome_translate_client->GetTranslateManager();
1725 DCHECK(manager);
1726 manager->TranslatePage(original_lang, target_lang, true);
1727 break;
1730 case IDC_CONTENT_CONTEXT_RELOADFRAME:
1731 // We always obey the cache here.
1732 // TODO(evanm): Perhaps we could allow shift-clicking the menu item to do
1733 // a cache-ignoring reload of the frame.
1734 source_web_contents_->ReloadFocusedFrame(false);
1735 break;
1737 case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
1738 source_web_contents_->ViewFrameSource(params_.frame_url,
1739 params_.frame_page_state);
1740 break;
1742 case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO: {
1743 Browser* browser = chrome::FindBrowserWithWebContents(
1744 source_web_contents_);
1745 chrome::ShowWebsiteSettings(browser, source_web_contents_,
1746 params_.frame_url, params_.security_info);
1747 break;
1750 case IDC_CONTENT_CONTEXT_UNDO:
1751 source_web_contents_->Undo();
1752 break;
1754 case IDC_CONTENT_CONTEXT_REDO:
1755 source_web_contents_->Redo();
1756 break;
1758 case IDC_CONTENT_CONTEXT_CUT:
1759 source_web_contents_->Cut();
1760 break;
1762 case IDC_CONTENT_CONTEXT_COPY:
1763 source_web_contents_->Copy();
1764 break;
1766 case IDC_CONTENT_CONTEXT_PASTE:
1767 source_web_contents_->Paste();
1768 break;
1770 case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE:
1771 source_web_contents_->PasteAndMatchStyle();
1772 break;
1774 case IDC_CONTENT_CONTEXT_DELETE:
1775 source_web_contents_->Delete();
1776 break;
1778 case IDC_CONTENT_CONTEXT_SELECTALL:
1779 source_web_contents_->SelectAll();
1780 break;
1782 case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
1783 case IDC_CONTENT_CONTEXT_GOTOURL: {
1784 WindowOpenDisposition disposition =
1785 ForceNewTabDispositionFromEventFlags(event_flags);
1786 OpenURL(selection_navigation_url_, GURL(), disposition,
1787 ui::PAGE_TRANSITION_LINK);
1788 break;
1790 case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS: {
1791 WindowOpenDisposition disposition =
1792 ForceNewTabDispositionFromEventFlags(event_flags);
1793 GURL url = chrome::GetSettingsUrl(chrome::kLanguageOptionsSubPage);
1794 OpenURL(url, GURL(), disposition, ui::PAGE_TRANSITION_LINK);
1795 break;
1798 case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS: {
1799 content::RecordAction(
1800 UserMetricsAction("RegisterProtocolHandler.ContextMenu_Settings"));
1801 WindowOpenDisposition disposition =
1802 ForceNewTabDispositionFromEventFlags(event_flags);
1803 GURL url = chrome::GetSettingsUrl(chrome::kHandlerSettingsSubPage);
1804 OpenURL(url, GURL(), disposition, ui::PAGE_TRANSITION_LINK);
1805 break;
1808 case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE: {
1809 // Make sure the model is loaded.
1810 TemplateURLService* model =
1811 TemplateURLServiceFactory::GetForProfile(GetProfile());
1812 if (!model)
1813 return;
1814 model->Load();
1816 SearchEngineTabHelper* search_engine_tab_helper =
1817 SearchEngineTabHelper::FromWebContents(source_web_contents_);
1818 if (search_engine_tab_helper &&
1819 search_engine_tab_helper->delegate()) {
1820 base::string16 keyword(TemplateURL::GenerateKeyword(
1821 params_.page_url,
1822 GetProfile()->GetPrefs()->GetString(prefs::kAcceptLanguages)));
1823 TemplateURLData data;
1824 data.SetShortName(keyword);
1825 data.SetKeyword(keyword);
1826 data.SetURL(params_.keyword_url.spec());
1827 data.favicon_url =
1828 TemplateURL::GenerateFaviconURL(params_.page_url.GetOrigin());
1829 // Takes ownership of the TemplateURL.
1830 search_engine_tab_helper->delegate()->ConfirmAddSearchProvider(
1831 new TemplateURL(data), GetProfile());
1833 break;
1836 case IDC_CONTENT_CONTEXT_FORCESAVEPASSWORD:
1837 ChromePasswordManagerClient::FromWebContents(source_web_contents_)->
1838 ForceSavePassword();
1839 break;
1841 default:
1842 NOTREACHED();
1843 break;
1847 ProtocolHandlerRegistry::ProtocolHandlerList
1848 RenderViewContextMenu::GetHandlersForLinkUrl() {
1849 ProtocolHandlerRegistry::ProtocolHandlerList handlers =
1850 protocol_handler_registry_->GetHandlersFor(params_.link_url.scheme());
1851 std::sort(handlers.begin(), handlers.end());
1852 return handlers;
1855 void RenderViewContextMenu::NotifyMenuShown() {
1856 content::NotificationService::current()->Notify(
1857 chrome::NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN,
1858 content::Source<RenderViewContextMenu>(this),
1859 content::NotificationService::NoDetails());
1862 void RenderViewContextMenu::NotifyURLOpened(
1863 const GURL& url,
1864 content::WebContents* new_contents) {
1865 RetargetingDetails details;
1866 details.source_web_contents = source_web_contents_;
1867 // Don't use GetRenderFrameHost() as it may be NULL. crbug.com/399789
1868 details.source_render_frame_id = render_frame_id_;
1869 details.target_url = url;
1870 details.target_web_contents = new_contents;
1871 details.not_yet_in_tabstrip = false;
1873 content::NotificationService::current()->Notify(
1874 chrome::NOTIFICATION_RETARGETING,
1875 content::Source<Profile>(GetProfile()),
1876 content::Details<RetargetingDetails>(&details));
1879 bool RenderViewContextMenu::IsDevCommandEnabled(int id) const {
1880 if (id == IDC_CONTENT_CONTEXT_INSPECTELEMENT ||
1881 id == IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE) {
1882 if (!GetPrefs(browser_context_)
1883 ->GetBoolean(prefs::kWebKitJavascriptEnabled))
1884 return false;
1886 // Don't enable the web inspector if the developer tools are disabled via
1887 // the preference dev-tools-disabled.
1888 if (GetPrefs(browser_context_)->GetBoolean(prefs::kDevToolsDisabled))
1889 return false;
1892 return true;
1895 base::string16 RenderViewContextMenu::PrintableSelectionText() {
1896 return gfx::TruncateString(params_.selection_text,
1897 kMaxSelectionTextLength,
1898 gfx::WORD_BREAK);
1901 void RenderViewContextMenu::EscapeAmpersands(base::string16* text) {
1902 base::ReplaceChars(*text, base::ASCIIToUTF16("&"), base::ASCIIToUTF16("&&"),
1903 text);
1906 // Controller functions --------------------------------------------------------
1908 void RenderViewContextMenu::CopyImageAt(int x, int y) {
1909 source_web_contents_->GetRenderViewHost()->CopyImageAt(x, y);
1912 void RenderViewContextMenu::LoadOriginalImage() {
1913 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1914 if (!render_frame_host)
1915 return;
1916 render_frame_host->Send(new ChromeViewMsg_RequestReloadImageForContextNode(
1917 render_frame_host->GetRoutingID()));
1920 void RenderViewContextMenu::GetImageThumbnailForSearch() {
1921 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1922 if (!render_frame_host)
1923 return;
1924 render_frame_host->Send(new ChromeViewMsg_RequestThumbnailForContextNode(
1925 render_frame_host->GetRoutingID(),
1926 kImageSearchThumbnailMinSize,
1927 gfx::Size(kImageSearchThumbnailMaxWidth,
1928 kImageSearchThumbnailMaxHeight)));
1931 void RenderViewContextMenu::Inspect(int x, int y) {
1932 content::RecordAction(UserMetricsAction("DevTools_InspectElement"));
1933 RenderFrameHost* render_frame_host = GetRenderFrameHost();
1934 if (!render_frame_host)
1935 return;
1936 DevToolsWindow::InspectElement(
1937 WebContents::FromRenderFrameHost(render_frame_host), x, y);
1940 void RenderViewContextMenu::WriteURLToClipboard(const GURL& url) {
1941 ::WriteURLToClipboard(
1942 url, GetPrefs(browser_context_)->GetString(prefs::kAcceptLanguages));
1945 void RenderViewContextMenu::MediaPlayerActionAt(
1946 const gfx::Point& location,
1947 const WebMediaPlayerAction& action) {
1948 source_web_contents_->GetRenderViewHost()->
1949 ExecuteMediaPlayerActionAtLocation(location, action);
1952 void RenderViewContextMenu::PluginActionAt(
1953 const gfx::Point& location,
1954 const WebPluginAction& action) {
1955 source_web_contents_->GetRenderViewHost()->
1956 ExecutePluginActionAtLocation(location, action);