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