Home | History | Annotate | Download | only in tab_contents
      1 // Copyright 2013 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/tab_contents/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 "base/time/time.h"
     22 #include "chrome/app/chrome_command_ids.h"
     23 #include "chrome/browser/app_mode/app_mode_utils.h"
     24 #include "chrome/browser/autocomplete/autocomplete_classifier.h"
     25 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
     26 #include "chrome/browser/autocomplete/autocomplete_match.h"
     27 #include "chrome/browser/browser_process.h"
     28 #include "chrome/browser/chrome_notification_types.h"
     29 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
     30 #include "chrome/browser/devtools/devtools_window.h"
     31 #include "chrome/browser/download/download_service.h"
     32 #include "chrome/browser/download/download_service_factory.h"
     33 #include "chrome/browser/download/download_stats.h"
     34 #include "chrome/browser/extensions/devtools_util.h"
     35 #include "chrome/browser/extensions/extension_host.h"
     36 #include "chrome/browser/extensions/extension_service.h"
     37 #include "chrome/browser/extensions/extension_system.h"
     38 #include "chrome/browser/google/google_util.h"
     39 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
     40 #include "chrome/browser/prefs/incognito_mode_prefs.h"
     41 #include "chrome/browser/profiles/profile.h"
     42 #include "chrome/browser/profiles/profile_io_data.h"
     43 #include "chrome/browser/search/search.h"
     44 #include "chrome/browser/search_engines/search_terms_data.h"
     45 #include "chrome/browser/search_engines/template_url.h"
     46 #include "chrome/browser/search_engines/template_url_service.h"
     47 #include "chrome/browser/search_engines/template_url_service_factory.h"
     48 #include "chrome/browser/spellchecker/spellcheck_host_metrics.h"
     49 #include "chrome/browser/spellchecker/spellcheck_service.h"
     50 #include "chrome/browser/tab_contents/retargeting_details.h"
     51 #include "chrome/browser/tab_contents/spellchecker_submenu_observer.h"
     52 #include "chrome/browser/tab_contents/spelling_menu_observer.h"
     53 #include "chrome/browser/translate/translate_manager.h"
     54 #include "chrome/browser/translate/translate_prefs.h"
     55 #include "chrome/browser/translate/translate_tab_helper.h"
     56 #include "chrome/browser/ui/browser.h"
     57 #include "chrome/browser/ui/browser_commands.h"
     58 #include "chrome/browser/ui/browser_finder.h"
     59 #include "chrome/browser/ui/search_engines/search_engine_tab_helper.h"
     60 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
     61 #include "chrome/common/chrome_constants.h"
     62 #include "chrome/common/chrome_switches.h"
     63 #include "chrome/common/content_restriction.h"
     64 #include "chrome/common/net/url_util.h"
     65 #include "chrome/common/pref_names.h"
     66 #include "chrome/common/render_messages.h"
     67 #include "chrome/common/spellcheck_messages.h"
     68 #include "chrome/common/url_constants.h"
     69 #include "content/public/browser/child_process_security_policy.h"
     70 #include "content/public/browser/download_manager.h"
     71 #include "content/public/browser/download_save_info.h"
     72 #include "content/public/browser/download_url_parameters.h"
     73 #include "content/public/browser/navigation_details.h"
     74 #include "content/public/browser/navigation_entry.h"
     75 #include "content/public/browser/notification_service.h"
     76 #include "content/public/browser/render_process_host.h"
     77 #include "content/public/browser/render_view_host.h"
     78 #include "content/public/browser/render_widget_host_view.h"
     79 #include "content/public/browser/user_metrics.h"
     80 #include "content/public/browser/web_contents.h"
     81 #include "content/public/common/menu_item.h"
     82 #include "content/public/common/ssl_status.h"
     83 #include "content/public/common/url_utils.h"
     84 #include "extensions/browser/view_type_utils.h"
     85 #include "extensions/common/extension.h"
     86 #include "grit/generated_resources.h"
     87 #include "net/base/escape.h"
     88 #include "third_party/WebKit/public/web/WebContextMenuData.h"
     89 #include "third_party/WebKit/public/web/WebMediaPlayerAction.h"
     90 #include "third_party/WebKit/public/web/WebPluginAction.h"
     91 #include "ui/base/clipboard/clipboard.h"
     92 #include "ui/base/l10n/l10n_util.h"
     93 #include "ui/gfx/favicon_size.h"
     94 #include "ui/gfx/point.h"
     95 #include "ui/gfx/size.h"
     96 #include "ui/gfx/text_elider.h"
     97 
     98 #if defined(ENABLE_PRINTING)
     99 #include "chrome/common/print_messages.h"
    100 
    101 #if defined(ENABLE_FULL_PRINTING)
    102 #include "chrome/browser/printing/print_preview_context_menu_observer.h"
    103 #include "chrome/browser/printing/print_preview_dialog_controller.h"
    104 #include "chrome/browser/printing/print_view_manager.h"
    105 #else
    106 #include "chrome/browser/printing/print_view_manager_basic.h"
    107 #endif  // defined(ENABLE_FULL_PRINTING)
    108 #endif  // defined(ENABLE_PRINTING)
    109 
    110 using blink::WebContextMenuData;
    111 using blink::WebMediaPlayerAction;
    112 using blink::WebPluginAction;
    113 using blink::WebString;
    114 using blink::WebURL;
    115 using content::BrowserContext;
    116 using content::ChildProcessSecurityPolicy;
    117 using content::DownloadManager;
    118 using content::DownloadUrlParameters;
    119 using content::NavigationController;
    120 using content::NavigationEntry;
    121 using content::OpenURLParams;
    122 using content::RenderViewHost;
    123 using content::SSLStatus;
    124 using content::UserMetricsAction;
    125 using content::WebContents;
    126 using extensions::Extension;
    127 using extensions::MenuItem;
    128 using extensions::MenuManager;
    129 
    130 namespace {
    131 
    132 const int kImageSearchThumbnailMinSize = 300 * 300;
    133 const int kImageSearchThumbnailMaxWidth = 600;
    134 const int kImageSearchThumbnailMaxHeight = 600;
    135 
    136 // Maps UMA enumeration to IDC. IDC could be changed so we can't use
    137 // just them and |UMA_HISTOGRAM_CUSTOM_ENUMERATION|.
    138 // Never change mapping or reuse |enum_id|. Always push back new items.
    139 // Items that is not used any more by |RenderViewContextMenu.ExecuteCommand|
    140 // could be deleted, but don't change the rest of |kUmaEnumToControlId|.
    141 const struct UmaEnumCommandIdPair {
    142   int enum_id;
    143   int control_id;
    144 } kUmaEnumToControlId[] = {
    145   {  0, IDC_CONTENT_CONTEXT_CUSTOM_FIRST },
    146   {  1, IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST },
    147   {  2, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST },
    148   {  3, IDC_CONTENT_CONTEXT_OPENLINKNEWTAB },
    149   {  4, IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW },
    150   {  5, IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD },
    151   {  6, IDC_CONTENT_CONTEXT_SAVELINKAS },
    152   {  7, IDC_CONTENT_CONTEXT_SAVEAVAS },
    153   {  8, IDC_CONTENT_CONTEXT_SAVEIMAGEAS },
    154   {  9, IDC_CONTENT_CONTEXT_COPYLINKLOCATION },
    155   { 10, IDC_CONTENT_CONTEXT_COPYIMAGELOCATION },
    156   { 11, IDC_CONTENT_CONTEXT_COPYAVLOCATION },
    157   { 12, IDC_CONTENT_CONTEXT_COPYIMAGE },
    158   { 13, IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB },
    159   { 14, IDC_CONTENT_CONTEXT_OPENAVNEWTAB },
    160   { 15, IDC_CONTENT_CONTEXT_PLAYPAUSE },
    161   { 16, IDC_CONTENT_CONTEXT_MUTE },
    162   { 17, IDC_CONTENT_CONTEXT_LOOP },
    163   { 18, IDC_CONTENT_CONTEXT_CONTROLS },
    164   { 19, IDC_CONTENT_CONTEXT_ROTATECW },
    165   { 20, IDC_CONTENT_CONTEXT_ROTATECCW },
    166   { 21, IDC_BACK },
    167   { 22, IDC_FORWARD },
    168   { 23, IDC_SAVE_PAGE },
    169   { 24, IDC_RELOAD },
    170   { 25, IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP },
    171   { 26, IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP },
    172   { 27, IDC_PRINT },
    173   { 28, IDC_VIEW_SOURCE },
    174   { 29, IDC_CONTENT_CONTEXT_INSPECTELEMENT },
    175   { 30, IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE },
    176   { 31, IDC_CONTENT_CONTEXT_VIEWPAGEINFO },
    177   { 32, IDC_CONTENT_CONTEXT_TRANSLATE },
    178   { 33, IDC_CONTENT_CONTEXT_RELOADFRAME },
    179   { 34, IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE },
    180   { 35, IDC_CONTENT_CONTEXT_VIEWFRAMEINFO },
    181   { 36, IDC_CONTENT_CONTEXT_UNDO },
    182   { 37, IDC_CONTENT_CONTEXT_REDO },
    183   { 38, IDC_CONTENT_CONTEXT_CUT },
    184   { 39, IDC_CONTENT_CONTEXT_COPY },
    185   { 40, IDC_CONTENT_CONTEXT_PASTE },
    186   { 41, IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE },
    187   { 42, IDC_CONTENT_CONTEXT_DELETE },
    188   { 43, IDC_CONTENT_CONTEXT_SELECTALL },
    189   { 44, IDC_CONTENT_CONTEXT_SEARCHWEBFOR },
    190   { 45, IDC_CONTENT_CONTEXT_GOTOURL },
    191   { 46, IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS },
    192   { 47, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS },
    193   { 48, IDC_CONTENT_CONTEXT_ADDSEARCHENGINE },
    194   { 49, IDC_CONTENT_CONTEXT_SPEECH_INPUT_FILTER_PROFANITIES },
    195   { 50, IDC_CONTENT_CONTEXT_SPEECH_INPUT_ABOUT },
    196   { 51, IDC_SPEECH_INPUT_MENU },
    197   { 52, IDC_CONTENT_CONTEXT_OPENLINKWITH },
    198   { 53, IDC_CHECK_SPELLING_WHILE_TYPING },
    199   { 54, IDC_SPELLCHECK_MENU },
    200   { 55, IDC_CONTENT_CONTEXT_SPELLING_TOGGLE },
    201   { 56, IDC_SPELLCHECK_LANGUAGES_FIRST },
    202   { 57, IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE },
    203   // Add new items here and use |enum_id| from the next line.
    204   { 58, 0 },  // Must be the last. Increment |enum_id| when new IDC was added.
    205 };
    206 
    207 // Collapses large ranges of ids before looking for UMA enum.
    208 int CollapleCommandsForUMA(int id) {
    209   if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
    210       id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) {
    211     return IDC_CONTENT_CONTEXT_CUSTOM_FIRST;
    212   }
    213 
    214   if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
    215       id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
    216     return IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
    217   }
    218 
    219   if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
    220       id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
    221     return IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
    222   }
    223 
    224   if (id >= IDC_SPELLCHECK_LANGUAGES_FIRST &&
    225       id <= IDC_SPELLCHECK_LANGUAGES_LAST) {
    226     return IDC_SPELLCHECK_LANGUAGES_FIRST;
    227   }
    228 
    229   return id;
    230 }
    231 
    232 // Returns UMA enum value for command specified by |id| or -1 if not found.
    233 int FindUMAEnumValueForCommand(int id) {
    234   id = CollapleCommandsForUMA(id);
    235   const size_t kMappingSize = arraysize(kUmaEnumToControlId);
    236   for (size_t i = 0; i < kMappingSize; ++i) {
    237     if (kUmaEnumToControlId[i].control_id == id) {
    238       return kUmaEnumToControlId[i].enum_id;
    239     }
    240   }
    241   return -1;
    242 }
    243 
    244 // Increments histogram value for used items specified by |id|.
    245 void RecordUsedItem(int id) {
    246   int enum_id = FindUMAEnumValueForCommand(id);
    247   if (enum_id != -1) {
    248     const size_t kMappingSize = arraysize(kUmaEnumToControlId);
    249     UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Used", enum_id,
    250                               kUmaEnumToControlId[kMappingSize - 1].enum_id);
    251   } else {
    252     NOTREACHED() << "Update kUmaEnumToControlId. Unhanded IDC: " << id;
    253   }
    254 }
    255 
    256 // Increments histogram value for visible context menu item specified by |id|.
    257 void RecordShownItem(int id) {
    258   int enum_id = FindUMAEnumValueForCommand(id);
    259   if (enum_id != -1) {
    260     const size_t kMappingSize = arraysize(kUmaEnumToControlId);
    261     UMA_HISTOGRAM_ENUMERATION("RenderViewContextMenu.Shown", enum_id,
    262                               kUmaEnumToControlId[kMappingSize - 1].enum_id);
    263   } else {
    264     // Just warning here. It's harder to maintain list of all possibly
    265     // visible items than executable items.
    266     DLOG(ERROR) << "Update kUmaEnumToControlId. Unhanded IDC: " << id;
    267   }
    268 }
    269 
    270 // Usually a new tab is expected where this function is used,
    271 // however users should be able to open a tab in background
    272 // or in a new window.
    273 WindowOpenDisposition ForceNewTabDispositionFromEventFlags(
    274     int event_flags) {
    275   WindowOpenDisposition disposition =
    276       ui::DispositionFromEventFlags(event_flags);
    277   return disposition == CURRENT_TAB ? NEW_FOREGROUND_TAB : disposition;
    278 }
    279 
    280 bool IsCustomItemEnabled(const std::vector<content::MenuItem>& items, int id) {
    281   DCHECK(id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
    282          id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST);
    283   for (size_t i = 0; i < items.size(); ++i) {
    284     int action_id = IDC_CONTENT_CONTEXT_CUSTOM_FIRST + items[i].action;
    285     if (action_id == id)
    286       return items[i].enabled;
    287     if (items[i].type == content::MenuItem::SUBMENU) {
    288       if (IsCustomItemEnabled(items[i].submenu, id))
    289         return true;
    290     }
    291   }
    292   return false;
    293 }
    294 
    295 bool IsCustomItemChecked(const std::vector<content::MenuItem>& items, int id) {
    296   DCHECK(id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
    297          id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST);
    298   for (size_t i = 0; i < items.size(); ++i) {
    299     int action_id = IDC_CONTENT_CONTEXT_CUSTOM_FIRST + items[i].action;
    300     if (action_id == id)
    301       return items[i].checked;
    302     if (items[i].type == content::MenuItem::SUBMENU) {
    303       if (IsCustomItemChecked(items[i].submenu, id))
    304         return true;
    305     }
    306   }
    307   return false;
    308 }
    309 
    310 const size_t kMaxCustomMenuDepth = 5;
    311 const size_t kMaxCustomMenuTotalItems = 1000;
    312 
    313 void AddCustomItemsToMenu(const std::vector<content::MenuItem>& items,
    314                           size_t depth,
    315                           size_t* total_items,
    316                           ui::SimpleMenuModel::Delegate* delegate,
    317                           ui::SimpleMenuModel* menu_model) {
    318   if (depth > kMaxCustomMenuDepth) {
    319     LOG(ERROR) << "Custom menu too deeply nested.";
    320     return;
    321   }
    322   for (size_t i = 0; i < items.size(); ++i) {
    323     if (IDC_CONTENT_CONTEXT_CUSTOM_FIRST + items[i].action >=
    324         IDC_CONTENT_CONTEXT_CUSTOM_LAST) {
    325       LOG(ERROR) << "Custom menu action value too big.";
    326       return;
    327     }
    328     if (*total_items >= kMaxCustomMenuTotalItems) {
    329       LOG(ERROR) << "Custom menu too large (too many items).";
    330       return;
    331     }
    332     (*total_items)++;
    333     switch (items[i].type) {
    334       case content::MenuItem::OPTION:
    335         menu_model->AddItem(
    336             items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
    337             items[i].label);
    338         break;
    339       case content::MenuItem::CHECKABLE_OPTION:
    340         menu_model->AddCheckItem(
    341             items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
    342             items[i].label);
    343         break;
    344       case content::MenuItem::GROUP:
    345         // TODO(viettrungluu): I don't know what this is supposed to do.
    346         NOTREACHED();
    347         break;
    348       case content::MenuItem::SEPARATOR:
    349         menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
    350         break;
    351       case content::MenuItem::SUBMENU: {
    352         ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate);
    353         AddCustomItemsToMenu(items[i].submenu, depth + 1, total_items, delegate,
    354                              submenu);
    355         menu_model->AddSubMenu(
    356             items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
    357             items[i].label,
    358             submenu);
    359         break;
    360       }
    361       default:
    362         NOTREACHED();
    363         break;
    364     }
    365   }
    366 }
    367 
    368 void DevToolsInspectElementAt(RenderViewHost* rvh, int x, int y) {
    369   DevToolsWindow::InspectElement(rvh, x, y);
    370 }
    371 
    372 // Helper function to escape "&" as "&&".
    373 void EscapeAmpersands(base::string16* text) {
    374   const char16 ampersand[] = {'&', 0};
    375   base::ReplaceChars(*text, ampersand, ASCIIToUTF16("&&"), text);
    376 }
    377 
    378 }  // namespace
    379 
    380 // static
    381 const size_t RenderViewContextMenu::kMaxSelectionTextLength = 50;
    382 
    383 // static
    384 bool RenderViewContextMenu::IsDevToolsURL(const GURL& url) {
    385   return url.SchemeIs(chrome::kChromeDevToolsScheme);
    386 }
    387 
    388 // static
    389 bool RenderViewContextMenu::IsInternalResourcesURL(const GURL& url) {
    390   if (!url.SchemeIs(chrome::kChromeUIScheme))
    391     return false;
    392   return url.host() == chrome::kChromeUISyncResourcesHost;
    393 }
    394 
    395 static const int kSpellcheckRadioGroup = 1;
    396 
    397 RenderViewContextMenu::RenderViewContextMenu(
    398     WebContents* web_contents,
    399     const content::ContextMenuParams& params)
    400     : params_(params),
    401       source_web_contents_(web_contents),
    402       profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
    403       menu_model_(this),
    404       extension_items_(profile_, this, &menu_model_,
    405                     base::Bind(MenuItemMatchesParams, params_)),
    406       external_(false),
    407       speech_input_submenu_model_(this),
    408       protocol_handler_submenu_model_(this),
    409       protocol_handler_registry_(
    410           ProtocolHandlerRegistryFactory::GetForProfile(profile_)),
    411       command_executed_(false),
    412       is_guest_(false) {
    413   RenderViewHost* rvh = source_web_contents_->GetRenderViewHost();
    414   if (rvh && rvh->GetProcess()->IsGuest())
    415     is_guest_ = true;
    416 }
    417 
    418 RenderViewContextMenu::~RenderViewContextMenu() {
    419 }
    420 
    421 // Menu construction functions -------------------------------------------------
    422 
    423 void RenderViewContextMenu::Init() {
    424   InitMenu();
    425   PlatformInit();
    426 }
    427 
    428 void RenderViewContextMenu::Cancel() {
    429   PlatformCancel();
    430 }
    431 
    432 static bool ExtensionPatternMatch(const extensions::URLPatternSet& patterns,
    433                                   const GURL& url) {
    434   // No patterns means no restriction, so that implicitly matches.
    435   if (patterns.is_empty())
    436     return true;
    437   return patterns.MatchesURL(url);
    438 }
    439 
    440 // static
    441 bool RenderViewContextMenu::ExtensionContextAndPatternMatch(
    442     const content::ContextMenuParams& params,
    443     MenuItem::ContextList contexts,
    444     const extensions::URLPatternSet& target_url_patterns) {
    445   const bool has_link = !params.link_url.is_empty();
    446   const bool has_selection = !params.selection_text.empty();
    447   const bool in_frame = !params.frame_url.is_empty();
    448 
    449   if (contexts.Contains(MenuItem::ALL) ||
    450       (has_selection && contexts.Contains(MenuItem::SELECTION)) ||
    451       (params.is_editable && contexts.Contains(MenuItem::EDITABLE)) ||
    452       (in_frame && contexts.Contains(MenuItem::FRAME)))
    453     return true;
    454 
    455   if (has_link && contexts.Contains(MenuItem::LINK) &&
    456       ExtensionPatternMatch(target_url_patterns, params.link_url))
    457     return true;
    458 
    459   switch (params.media_type) {
    460     case WebContextMenuData::MediaTypeImage:
    461       if (contexts.Contains(MenuItem::IMAGE) &&
    462           ExtensionPatternMatch(target_url_patterns, params.src_url))
    463         return true;
    464       break;
    465 
    466     case WebContextMenuData::MediaTypeVideo:
    467       if (contexts.Contains(MenuItem::VIDEO) &&
    468           ExtensionPatternMatch(target_url_patterns, params.src_url))
    469         return true;
    470       break;
    471 
    472     case WebContextMenuData::MediaTypeAudio:
    473       if (contexts.Contains(MenuItem::AUDIO) &&
    474           ExtensionPatternMatch(target_url_patterns, params.src_url))
    475         return true;
    476       break;
    477 
    478     default:
    479       break;
    480   }
    481 
    482   // PAGE is the least specific context, so we only examine that if none of the
    483   // other contexts apply (except for FRAME, which is included in PAGE for
    484   // backwards compatibility).
    485   if (!has_link && !has_selection && !params.is_editable &&
    486       params.media_type == WebContextMenuData::MediaTypeNone &&
    487       contexts.Contains(MenuItem::PAGE))
    488     return true;
    489 
    490   return false;
    491 }
    492 
    493 static const GURL& GetDocumentURL(const content::ContextMenuParams& params) {
    494   return params.frame_url.is_empty() ? params.page_url : params.frame_url;
    495 }
    496 
    497 // static
    498 bool RenderViewContextMenu::MenuItemMatchesParams(
    499     const content::ContextMenuParams& params,
    500     const extensions::MenuItem* item) {
    501   bool match = ExtensionContextAndPatternMatch(params, item->contexts(),
    502                                                item->target_url_patterns());
    503   if (!match)
    504     return false;
    505 
    506   const GURL& document_url = GetDocumentURL(params);
    507   return ExtensionPatternMatch(item->document_url_patterns(), document_url);
    508 }
    509 
    510 void RenderViewContextMenu::AppendAllExtensionItems() {
    511   extension_items_.Clear();
    512   ExtensionService* service =
    513       extensions::ExtensionSystem::Get(profile_)->extension_service();
    514   if (!service)
    515     return;  // In unit-tests, we may not have an ExtensionService.
    516 
    517   MenuManager* menu_manager = MenuManager::Get(profile_);
    518   if (!menu_manager)
    519     return;
    520 
    521   base::string16 printable_selection_text = PrintableSelectionText();
    522   EscapeAmpersands(&printable_selection_text);
    523 
    524   // Get a list of extension id's that have context menu items, and sort by the
    525   // top level context menu title of the extension.
    526   std::set<std::string> ids = menu_manager->ExtensionIds();
    527   std::vector<base::string16> sorted_menu_titles;
    528   std::map<base::string16, std::string> map_ids;
    529   for (std::set<std::string>::iterator i = ids.begin(); i != ids.end(); ++i) {
    530     const Extension* extension = service->GetExtensionById(*i, false);
    531     // Platform apps have their context menus created directly in
    532     // AppendPlatformAppItems.
    533     if (extension && !extension->is_platform_app()) {
    534       base::string16 menu_title = extension_items_.GetTopLevelContextMenuTitle(
    535           *i, printable_selection_text);
    536       map_ids[menu_title] = *i;
    537       sorted_menu_titles.push_back(menu_title);
    538     }
    539   }
    540   if (sorted_menu_titles.empty())
    541     return;
    542 
    543   const std::string app_locale = g_browser_process->GetApplicationLocale();
    544   l10n_util::SortStrings16(app_locale, &sorted_menu_titles);
    545 
    546   int index = 0;
    547   base::TimeTicks begin = base::TimeTicks::Now();
    548   for (size_t i = 0; i < sorted_menu_titles.size(); ++i) {
    549     const std::string& id = map_ids[sorted_menu_titles[i]];
    550     extension_items_.AppendExtensionItems(id, printable_selection_text,
    551                                           &index);
    552   }
    553 
    554   UMA_HISTOGRAM_TIMES("Extensions.ContextMenus_BuildTime",
    555                       base::TimeTicks::Now() - begin);
    556   UMA_HISTOGRAM_COUNTS("Extensions.ContextMenus_ItemCount", index);
    557 }
    558 
    559 void RenderViewContextMenu::InitMenu() {
    560   if (chrome::IsRunningInForcedAppMode()) {
    561     AppendAppModeItems();
    562     return;
    563   }
    564 
    565   extensions::ViewType view_type =
    566       extensions::GetViewType(source_web_contents_);
    567   if (view_type == extensions::VIEW_TYPE_APP_SHELL) {
    568     AppendPlatformAppItems();
    569     return;
    570   } else if (view_type == extensions::VIEW_TYPE_EXTENSION_POPUP) {
    571     AppendPopupExtensionItems();
    572     return;
    573   } else if (view_type == extensions::VIEW_TYPE_PANEL) {
    574     AppendPanelItems();
    575     return;
    576   }
    577 
    578   const bool has_link = !params_.unfiltered_link_url.is_empty();
    579   const bool has_selection = !params_.selection_text.empty();
    580 
    581   if (AppendCustomItems()) {
    582     // If there's a selection, don't early return when there are custom items,
    583     // but fall through to adding the normal ones after the custom ones.
    584     if (has_selection) {
    585       menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
    586     } else {
    587       // Don't add items for Pepper menu.
    588       if (!params_.custom_context.is_pepper_menu)
    589         AppendDeveloperItems();
    590       return;
    591     }
    592   }
    593 
    594   // When no special node or text is selected and selection has no link,
    595   // show page items.
    596   if (params_.media_type == WebContextMenuData::MediaTypeNone &&
    597       !has_link &&
    598       !params_.is_editable &&
    599       !is_guest_ &&
    600       !has_selection) {
    601     if (!params_.page_url.is_empty()) {
    602       bool is_devtools = IsDevToolsURL(params_.page_url);
    603       if (!is_devtools && !IsInternalResourcesURL(params_.page_url)) {
    604         AppendPageItems();
    605         // Merge in frame items if we clicked within a frame that needs them.
    606         if (!params_.frame_url.is_empty()) {
    607           is_devtools = IsDevToolsURL(params_.frame_url);
    608           if (!is_devtools && !IsInternalResourcesURL(params_.frame_url)) {
    609             menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
    610             AppendFrameItems();
    611           }
    612         }
    613       }
    614     } else {
    615       DCHECK(params_.frame_url.is_empty());
    616     }
    617   }
    618 
    619   // Do not show link related items for guest.
    620   if (has_link && !is_guest_) {
    621     AppendLinkItems();
    622     if (params_.media_type != WebContextMenuData::MediaTypeNone)
    623       menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
    624   }
    625 
    626   switch (params_.media_type) {
    627     case WebContextMenuData::MediaTypeNone:
    628       break;
    629     case WebContextMenuData::MediaTypeImage:
    630       AppendImageItems();
    631       break;
    632     case WebContextMenuData::MediaTypeVideo:
    633       AppendVideoItems();
    634       break;
    635     case WebContextMenuData::MediaTypeAudio:
    636       AppendAudioItems();
    637       break;
    638     case WebContextMenuData::MediaTypePlugin:
    639       AppendPluginItems();
    640       break;
    641 #ifdef WEBCONTEXT_MEDIATYPEFILE_DEFINED
    642     case WebContextMenuData::MediaTypeFile:
    643       break;
    644 #endif
    645   }
    646 
    647   if (params_.is_editable)
    648     AppendEditableItems();
    649   else if (has_selection)
    650     AppendCopyItem();
    651 
    652   if (!is_guest_ && has_selection) {
    653     AppendSearchProvider();
    654     if (!IsDevToolsURL(params_.page_url))
    655       AppendPrintItem();
    656   }
    657 
    658   if (!IsDevToolsURL(params_.page_url) && !is_guest_)
    659     AppendAllExtensionItems();
    660 
    661   AppendDeveloperItems();
    662 
    663   if (!is_guest_) {
    664 #if defined(ENABLE_FULL_PRINTING)
    665     if (!print_preview_menu_observer_.get()) {
    666       print_preview_menu_observer_.reset(
    667           new PrintPreviewContextMenuObserver(source_web_contents_));
    668     }
    669 
    670     observers_.AddObserver(print_preview_menu_observer_.get());
    671 #endif
    672   }
    673 }
    674 
    675 const Extension* RenderViewContextMenu::GetExtension() const {
    676   extensions::ExtensionSystem* system =
    677       extensions::ExtensionSystem::Get(profile_);
    678   // There is no process manager in some tests.
    679   if (!system->process_manager())
    680     return NULL;
    681 
    682   return system->process_manager()->GetExtensionForRenderViewHost(
    683       source_web_contents_->GetRenderViewHost());
    684 }
    685 
    686 void RenderViewContextMenu::AppendAppModeItems() {
    687   const bool has_selection = !params_.selection_text.empty();
    688 
    689   if (params_.is_editable)
    690     AppendEditableItems();
    691   else if (has_selection)
    692     AppendCopyItem();
    693 }
    694 
    695 void RenderViewContextMenu::AppendPlatformAppItems() {
    696   const Extension* platform_app = GetExtension();
    697 
    698   // The RVH might be for a process sandboxed from the extension.
    699   if (!platform_app)
    700     return;
    701 
    702   DCHECK(platform_app->is_platform_app());
    703 
    704   const bool has_selection = !params_.selection_text.empty();
    705 
    706   // Add undo/redo, cut/copy/paste etc for text fields.
    707   if (params_.is_editable)
    708     AppendEditableItems();
    709   else if (has_selection)
    710     AppendCopyItem();
    711 
    712   int index = 0;
    713   extension_items_.AppendExtensionItems(platform_app->id(),
    714                                         PrintableSelectionText(), &index);
    715 
    716   // Add dev tools for unpacked extensions.
    717   if (extensions::Manifest::IsUnpackedLocation(platform_app->location()) ||
    718       CommandLine::ForCurrentProcess()->HasSwitch(
    719           switches::kDebugPackedApps)) {
    720     // Add a separator if there are any items already in the menu.
    721     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
    722 
    723     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP,
    724                                     IDS_CONTENT_CONTEXT_RELOAD_PACKAGED_APP);
    725     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP,
    726                                     IDS_CONTENT_CONTEXT_RESTART_APP);
    727     AppendDeveloperItems();
    728     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE,
    729                                     IDS_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE);
    730   }
    731 }
    732 
    733 void RenderViewContextMenu::AppendPopupExtensionItems() {
    734   const bool has_selection = !params_.selection_text.empty();
    735 
    736   if (params_.is_editable)
    737     AppendEditableItems();
    738   else if (has_selection)
    739     AppendCopyItem();
    740 
    741   if (has_selection)
    742     AppendSearchProvider();
    743 
    744   AppendAllExtensionItems();
    745   AppendDeveloperItems();
    746 }
    747 
    748 void RenderViewContextMenu::AppendPanelItems() {
    749   bool has_selection = !params_.selection_text.empty();
    750 
    751   // Checking link should take precedence before checking selection since on Mac
    752   // right-clicking a link will also make it selected.
    753   if (params_.unfiltered_link_url.is_valid())
    754     AppendLinkItems();
    755 
    756   if (params_.is_editable)
    757     AppendEditableItems();
    758   else if (has_selection)
    759     AppendCopyItem();
    760 
    761   // Avoid appending extension related items when |extension| is null. This
    762   // happens when the panel is navigated to a url outside of the extension's
    763   // package.
    764   const Extension* extension = GetExtension();
    765   if (extension) {
    766     // Only add extension items from this extension.
    767     int index = 0;
    768     extension_items_.AppendExtensionItems(extension->id(),
    769                                           PrintableSelectionText(), &index);
    770   }
    771 }
    772 
    773 void RenderViewContextMenu::AddMenuItem(int command_id,
    774                                         const base::string16& title) {
    775   menu_model_.AddItem(command_id, title);
    776 }
    777 
    778 void RenderViewContextMenu::AddCheckItem(int command_id,
    779                                          const base::string16& title) {
    780   menu_model_.AddCheckItem(command_id, title);
    781 }
    782 
    783 void RenderViewContextMenu::AddSeparator() {
    784   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
    785 }
    786 
    787 void RenderViewContextMenu::AddSubMenu(int command_id,
    788                                        const base::string16& label,
    789                                        ui::MenuModel* model) {
    790   menu_model_.AddSubMenu(command_id, label, model);
    791 }
    792 
    793 void RenderViewContextMenu::UpdateMenuItem(int command_id,
    794                                            bool enabled,
    795                                            bool hidden,
    796                                            const base::string16& label) {
    797   // This function needs platform-specific implementation.
    798   NOTIMPLEMENTED();
    799 }
    800 
    801 RenderViewHost* RenderViewContextMenu::GetRenderViewHost() const {
    802   return source_web_contents_->GetRenderViewHost();
    803 }
    804 
    805 WebContents* RenderViewContextMenu::GetWebContents() const {
    806   return source_web_contents_;
    807 }
    808 
    809 Profile* RenderViewContextMenu::GetProfile() const {
    810   return profile_;
    811 }
    812 
    813 bool RenderViewContextMenu::AppendCustomItems() {
    814   size_t total_items = 0;
    815   AddCustomItemsToMenu(params_.custom_items, 0, &total_items, this,
    816                        &menu_model_);
    817   return total_items > 0;
    818 }
    819 
    820 void RenderViewContextMenu::AppendDeveloperItems() {
    821   // Show Inspect Element in DevTools itself only in case of the debug
    822   // devtools build.
    823   bool show_developer_items = !IsDevToolsURL(params_.page_url);
    824 
    825 #if defined(DEBUG_DEVTOOLS)
    826   show_developer_items = true;
    827 #endif
    828 
    829   if (!show_developer_items)
    830     return;
    831 
    832   // In the DevTools popup menu, "developer items" is normally the only
    833   // section, so omit the separator there.
    834   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
    835   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTELEMENT,
    836                                   IDS_CONTENT_CONTEXT_INSPECTELEMENT);
    837 }
    838 
    839 void RenderViewContextMenu::AppendLinkItems() {
    840   if (!params_.link_url.is_empty()) {
    841     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB,
    842                                     IDS_CONTENT_CONTEXT_OPENLINKNEWTAB);
    843     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW,
    844                                     IDS_CONTENT_CONTEXT_OPENLINKNEWWINDOW);
    845     if (params_.link_url.is_valid()) {
    846       AppendProtocolHandlerSubMenu();
    847     }
    848 
    849     if (!external_) {
    850       menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD,
    851                                       IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD);
    852     }
    853     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVELINKAS,
    854                                     IDS_CONTENT_CONTEXT_SAVELINKAS);
    855   }
    856 
    857   menu_model_.AddItemWithStringId(
    858       IDC_CONTENT_CONTEXT_COPYLINKLOCATION,
    859       params_.link_url.SchemeIs(content::kMailToScheme) ?
    860           IDS_CONTENT_CONTEXT_COPYEMAILADDRESS :
    861           IDS_CONTENT_CONTEXT_COPYLINKLOCATION);
    862 }
    863 
    864 void RenderViewContextMenu::AppendImageItems() {
    865   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS,
    866                                   IDS_CONTENT_CONTEXT_SAVEIMAGEAS);
    867   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGELOCATION,
    868                                   IDS_CONTENT_CONTEXT_COPYIMAGELOCATION);
    869   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
    870                                   IDS_CONTENT_CONTEXT_COPYIMAGE);
    871   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB,
    872                                   IDS_CONTENT_CONTEXT_OPENIMAGENEWTAB);
    873   const TemplateURL* const default_provider =
    874       TemplateURLServiceFactory::GetForProfile(profile_)->
    875           GetDefaultSearchProvider();
    876   if (params_.has_image_contents && default_provider &&
    877       !default_provider->image_url().empty() &&
    878       default_provider->image_url_ref().IsValid()) {
    879     menu_model_.AddItem(
    880         IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE,
    881         l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFORIMAGE,
    882                                    default_provider->short_name()));
    883   }
    884   AppendPrintItem();
    885 }
    886 
    887 void RenderViewContextMenu::AppendAudioItems() {
    888   AppendMediaItems();
    889   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
    890   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
    891                                   IDS_CONTENT_CONTEXT_SAVEAUDIOAS);
    892   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
    893                                   IDS_CONTENT_CONTEXT_COPYAUDIOLOCATION);
    894   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
    895                                   IDS_CONTENT_CONTEXT_OPENAUDIONEWTAB);
    896 }
    897 
    898 void RenderViewContextMenu::AppendVideoItems() {
    899   AppendMediaItems();
    900   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
    901   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
    902                                   IDS_CONTENT_CONTEXT_SAVEVIDEOAS);
    903   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
    904                                   IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION);
    905   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
    906                                   IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB);
    907 }
    908 
    909 void RenderViewContextMenu::AppendMediaItems() {
    910   int media_flags = params_.media_flags;
    911 
    912   menu_model_.AddItemWithStringId(
    913       IDC_CONTENT_CONTEXT_PLAYPAUSE,
    914       media_flags & WebContextMenuData::MediaPaused ?
    915           IDS_CONTENT_CONTEXT_PLAY :
    916           IDS_CONTENT_CONTEXT_PAUSE);
    917 
    918   menu_model_.AddItemWithStringId(
    919       IDC_CONTENT_CONTEXT_MUTE,
    920       media_flags & WebContextMenuData::MediaMuted ?
    921           IDS_CONTENT_CONTEXT_UNMUTE :
    922           IDS_CONTENT_CONTEXT_MUTE);
    923 
    924   menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_LOOP,
    925                                        IDS_CONTENT_CONTEXT_LOOP);
    926   menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_CONTROLS,
    927                                        IDS_CONTENT_CONTEXT_CONTROLS);
    928 }
    929 
    930 void RenderViewContextMenu::AppendPluginItems() {
    931   if (params_.page_url == params_.src_url) {
    932     // Full page plugin, so show page menu items.
    933     if (params_.link_url.is_empty() && params_.selection_text.empty())
    934       AppendPageItems();
    935   } else {
    936     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
    937                                     IDS_CONTENT_CONTEXT_SAVEPAGEAS);
    938     menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
    939   }
    940 
    941   if (params_.media_flags & WebContextMenuData::MediaCanRotate) {
    942     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
    943     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECW,
    944                                     IDS_CONTENT_CONTEXT_ROTATECW);
    945     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ROTATECCW,
    946                                     IDS_CONTENT_CONTEXT_ROTATECCW);
    947   }
    948 }
    949 
    950 void RenderViewContextMenu::AppendPageItems() {
    951   menu_model_.AddItemWithStringId(IDC_BACK, IDS_CONTENT_CONTEXT_BACK);
    952   menu_model_.AddItemWithStringId(IDC_FORWARD, IDS_CONTENT_CONTEXT_FORWARD);
    953   menu_model_.AddItemWithStringId(IDC_RELOAD, IDS_CONTENT_CONTEXT_RELOAD);
    954   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
    955   menu_model_.AddItemWithStringId(IDC_SAVE_PAGE,
    956                                   IDS_CONTENT_CONTEXT_SAVEPAGEAS);
    957   menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
    958 
    959   if (TranslateManager::IsTranslatableURL(params_.page_url)) {
    960     std::string locale = g_browser_process->GetApplicationLocale();
    961     locale = TranslateManager::GetLanguageCode(locale);
    962     base::string16 language =
    963         l10n_util::GetDisplayNameForLocale(locale, locale, true);
    964     menu_model_.AddItem(
    965         IDC_CONTENT_CONTEXT_TRANSLATE,
    966         l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_TRANSLATE, language));
    967   }
    968 
    969   menu_model_.AddItemWithStringId(IDC_VIEW_SOURCE,
    970                                   IDS_CONTENT_CONTEXT_VIEWPAGESOURCE);
    971   // Only add View Page Info if there's a browser.  This is a temporary thing
    972   // while View Page Info crashes Chrome Frame; see http://crbug.com/120901.
    973   // TODO(grt) Remove this once page info is back for Chrome Frame.
    974   if (!external_) {
    975     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWPAGEINFO,
    976                                     IDS_CONTENT_CONTEXT_VIEWPAGEINFO);
    977   }
    978 }
    979 
    980 void RenderViewContextMenu::AppendFrameItems() {
    981   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOADFRAME,
    982                                   IDS_CONTENT_CONTEXT_RELOADFRAME);
    983   // These two menu items have yet to be implemented.
    984   // http://code.google.com/p/chromium/issues/detail?id=11827
    985   //   IDS_CONTENT_CONTEXT_SAVEFRAMEAS
    986   //   IDS_CONTENT_CONTEXT_PRINTFRAME
    987   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE,
    988                                   IDS_CONTENT_CONTEXT_VIEWFRAMESOURCE);
    989   // Only add View Frame Info if there's a browser.  This is a temporary thing
    990   // while View Frame Info crashes Chrome Frame; see http://crbug.com/120901.
    991   // TODO(grt) Remove this once frame info is back for Chrome Frame.
    992   if (!external_) {
    993     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMEINFO,
    994                                     IDS_CONTENT_CONTEXT_VIEWFRAMEINFO);
    995   }
    996 }
    997 
    998 void RenderViewContextMenu::AppendCopyItem() {
    999   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
   1000                                   IDS_CONTENT_CONTEXT_COPY);
   1001 }
   1002 
   1003 void RenderViewContextMenu::AppendPrintItem() {
   1004   if (profile_->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) &&
   1005       (params_.media_type == WebContextMenuData::MediaTypeNone ||
   1006        params_.media_flags & WebContextMenuData::MediaCanPrint)) {
   1007     menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
   1008   }
   1009 }
   1010 
   1011 void RenderViewContextMenu::AppendSearchProvider() {
   1012   DCHECK(profile_);
   1013 
   1014   TrimWhitespace(params_.selection_text, TRIM_ALL, &params_.selection_text);
   1015   if (params_.selection_text.empty())
   1016     return;
   1017 
   1018   base::ReplaceChars(params_.selection_text, AutocompleteMatch::kInvalidChars,
   1019                      ASCIIToUTF16(" "), &params_.selection_text);
   1020 
   1021   AutocompleteMatch match;
   1022   AutocompleteClassifierFactory::GetForProfile(profile_)->Classify(
   1023       params_.selection_text, false, false, &match, NULL);
   1024   selection_navigation_url_ = match.destination_url;
   1025   if (!selection_navigation_url_.is_valid())
   1026     return;
   1027 
   1028   base::string16 printable_selection_text = PrintableSelectionText();
   1029   EscapeAmpersands(&printable_selection_text);
   1030 
   1031   if (AutocompleteMatch::IsSearchType(match.type)) {
   1032     const TemplateURL* const default_provider =
   1033         TemplateURLServiceFactory::GetForProfile(profile_)->
   1034         GetDefaultSearchProvider();
   1035     if (!default_provider)
   1036       return;
   1037     menu_model_.AddItem(
   1038         IDC_CONTENT_CONTEXT_SEARCHWEBFOR,
   1039         l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFOR,
   1040                                    default_provider->short_name(),
   1041                                    printable_selection_text));
   1042   } else {
   1043     if ((selection_navigation_url_ != params_.link_url) &&
   1044         ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme(
   1045             selection_navigation_url_.scheme())) {
   1046       menu_model_.AddItem(
   1047           IDC_CONTENT_CONTEXT_GOTOURL,
   1048           l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_GOTOURL,
   1049                                      printable_selection_text));
   1050     }
   1051   }
   1052 }
   1053 
   1054 void RenderViewContextMenu::AppendEditableItems() {
   1055   const bool use_spellcheck_and_search = !chrome::IsRunningInForcedAppMode();
   1056 
   1057   if (use_spellcheck_and_search)
   1058     AppendSpellingSuggestionsSubMenu();
   1059 
   1060   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_UNDO,
   1061                                   IDS_CONTENT_CONTEXT_UNDO);
   1062   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_REDO,
   1063                                   IDS_CONTENT_CONTEXT_REDO);
   1064   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
   1065   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_CUT,
   1066                                   IDS_CONTENT_CONTEXT_CUT);
   1067   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
   1068                                   IDS_CONTENT_CONTEXT_COPY);
   1069   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE,
   1070                                   IDS_CONTENT_CONTEXT_PASTE);
   1071   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE,
   1072                                   IDS_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE);
   1073   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_DELETE,
   1074                                   IDS_CONTENT_CONTEXT_DELETE);
   1075   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
   1076 
   1077   if (use_spellcheck_and_search && !params_.keyword_url.is_empty()) {
   1078     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_ADDSEARCHENGINE,
   1079                                     IDS_CONTENT_CONTEXT_ADDSEARCHENGINE);
   1080     menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
   1081   }
   1082 
   1083   if (use_spellcheck_and_search)
   1084     AppendSpellcheckOptionsSubMenu();
   1085   AppendSpeechInputOptionsSubMenu();
   1086   AppendPlatformEditableItems();
   1087 
   1088   menu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
   1089   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SELECTALL,
   1090                                   IDS_CONTENT_CONTEXT_SELECTALL);
   1091 }
   1092 
   1093 void RenderViewContextMenu::AppendSpellingSuggestionsSubMenu() {
   1094   if (!spelling_menu_observer_.get())
   1095     spelling_menu_observer_.reset(new SpellingMenuObserver(this));
   1096   observers_.AddObserver(spelling_menu_observer_.get());
   1097   spelling_menu_observer_->InitMenu(params_);
   1098 }
   1099 
   1100 void RenderViewContextMenu::AppendSpellcheckOptionsSubMenu() {
   1101   if (!spellchecker_submenu_observer_.get()) {
   1102     spellchecker_submenu_observer_.reset(new SpellCheckerSubMenuObserver(
   1103         this, this, kSpellcheckRadioGroup));
   1104   }
   1105   spellchecker_submenu_observer_->InitMenu(params_);
   1106   observers_.AddObserver(spellchecker_submenu_observer_.get());
   1107 }
   1108 
   1109 void RenderViewContextMenu::AppendSpeechInputOptionsSubMenu() {
   1110   if (params_.speech_input_enabled) {
   1111     speech_input_submenu_model_.AddCheckItem(
   1112         IDC_CONTENT_CONTEXT_SPEECH_INPUT_FILTER_PROFANITIES,
   1113         l10n_util::GetStringUTF16(
   1114             IDS_CONTENT_CONTEXT_SPEECH_INPUT_FILTER_PROFANITIES));
   1115 
   1116     speech_input_submenu_model_.AddItemWithStringId(
   1117         IDC_CONTENT_CONTEXT_SPEECH_INPUT_ABOUT,
   1118         IDS_CONTENT_CONTEXT_SPEECH_INPUT_ABOUT);
   1119 
   1120     menu_model_.AddSubMenu(
   1121         IDC_SPEECH_INPUT_MENU,
   1122         l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_SPEECH_INPUT_MENU),
   1123         &speech_input_submenu_model_);
   1124   }
   1125 }
   1126 
   1127 void RenderViewContextMenu::AppendProtocolHandlerSubMenu() {
   1128   const ProtocolHandlerRegistry::ProtocolHandlerList handlers =
   1129       GetHandlersForLinkUrl();
   1130   if (handlers.empty())
   1131     return;
   1132   size_t max = IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST -
   1133       IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
   1134   for (size_t i = 0; i < handlers.size() && i <= max; i++) {
   1135     protocol_handler_submenu_model_.AddItem(
   1136         IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST + i,
   1137         handlers[i].title());
   1138   }
   1139   protocol_handler_submenu_model_.AddSeparator(ui::NORMAL_SEPARATOR);
   1140   protocol_handler_submenu_model_.AddItem(
   1141       IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS,
   1142       l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH_CONFIGURE));
   1143 
   1144   menu_model_.AddSubMenu(
   1145       IDC_CONTENT_CONTEXT_OPENLINKWITH,
   1146       l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_OPENLINKWITH),
   1147       &protocol_handler_submenu_model_);
   1148 }
   1149 
   1150 void RenderViewContextMenu::AppendPlatformEditableItems() {
   1151 }
   1152 
   1153 // Menu delegate functions -----------------------------------------------------
   1154 
   1155 bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
   1156   // If this command is is added by one of our observers, we dispatch it to the
   1157   // observer.
   1158   ObserverListBase<RenderViewContextMenuObserver>::Iterator it(observers_);
   1159   RenderViewContextMenuObserver* observer;
   1160   while ((observer = it.GetNext()) != NULL) {
   1161     if (observer->IsCommandIdSupported(id))
   1162       return observer->IsCommandIdEnabled(id);
   1163   }
   1164 
   1165   CoreTabHelper* core_tab_helper =
   1166       CoreTabHelper::FromWebContents(source_web_contents_);
   1167   int content_restrictions = 0;
   1168   if (core_tab_helper)
   1169     content_restrictions = core_tab_helper->content_restrictions();
   1170   if (id == IDC_PRINT && (content_restrictions & CONTENT_RESTRICTION_PRINT))
   1171     return false;
   1172 
   1173   if (id == IDC_SAVE_PAGE &&
   1174       (content_restrictions & CONTENT_RESTRICTION_SAVE)) {
   1175     return false;
   1176   }
   1177 
   1178   // Allow Spell Check language items on sub menu for text area context menu.
   1179   if ((id >= IDC_SPELLCHECK_LANGUAGES_FIRST) &&
   1180       (id < IDC_SPELLCHECK_LANGUAGES_LAST)) {
   1181     return profile_->GetPrefs()->GetBoolean(prefs::kEnableContinuousSpellcheck);
   1182   }
   1183 
   1184   // Custom items.
   1185   if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
   1186       id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) {
   1187     return IsCustomItemEnabled(params_.custom_items, id);
   1188   }
   1189 
   1190   // Extension items.
   1191   if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
   1192       id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
   1193     return extension_items_.IsCommandIdEnabled(id);
   1194   }
   1195 
   1196   if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
   1197       id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
   1198     return true;
   1199   }
   1200 
   1201   IncognitoModePrefs::Availability incognito_avail =
   1202       IncognitoModePrefs::GetAvailability(profile_->GetPrefs());
   1203   switch (id) {
   1204     case IDC_BACK:
   1205       return source_web_contents_->GetController().CanGoBack();
   1206 
   1207     case IDC_FORWARD:
   1208       return source_web_contents_->GetController().CanGoForward();
   1209 
   1210     case IDC_RELOAD: {
   1211       CoreTabHelper* core_tab_helper =
   1212           CoreTabHelper::FromWebContents(source_web_contents_);
   1213       if (!core_tab_helper)
   1214         return false;
   1215 
   1216       CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
   1217       return !core_delegate ||
   1218              core_delegate->CanReloadContents(source_web_contents_);
   1219     }
   1220 
   1221     case IDC_VIEW_SOURCE:
   1222     case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
   1223       return source_web_contents_->GetController().CanViewSource();
   1224 
   1225     case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
   1226     case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE:
   1227     case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP:
   1228     case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP:
   1229       return IsDevCommandEnabled(id);
   1230 
   1231     case IDC_CONTENT_CONTEXT_VIEWPAGEINFO:
   1232       if (source_web_contents_->GetController().GetActiveEntry() == NULL)
   1233         return false;
   1234       // Disabled if no browser is associated (e.g. desktop notifications).
   1235       if (chrome::FindBrowserWithWebContents(source_web_contents_) == NULL)
   1236         return false;
   1237       return true;
   1238 
   1239     case IDC_CONTENT_CONTEXT_TRANSLATE: {
   1240       TranslateTabHelper* translate_tab_helper =
   1241           TranslateTabHelper::FromWebContents(source_web_contents_);
   1242       if (!translate_tab_helper)
   1243         return false;
   1244       std::string original_lang =
   1245           translate_tab_helper->language_state().original_language();
   1246       std::string target_lang = g_browser_process->GetApplicationLocale();
   1247       target_lang = TranslateManager::GetLanguageCode(target_lang);
   1248       // Note that we intentionally enable the menu even if the original and
   1249       // target languages are identical.  This is to give a way to user to
   1250       // translate a page that might contains text fragments in a different
   1251       // language.
   1252       return ((params_.edit_flags & WebContextMenuData::CanTranslate) != 0) &&
   1253              !original_lang.empty() &&  // Did we receive the page language yet?
   1254              !translate_tab_helper->language_state().IsPageTranslated() &&
   1255              !source_web_contents_->GetInterstitialPage() &&
   1256              // There are some application locales which can't be used as a
   1257              // target language for translation.
   1258              TranslateManager::IsSupportedLanguage(target_lang) &&
   1259              // Disable on the Instant Extended NTP.
   1260              !chrome::IsInstantNTP(source_web_contents_);
   1261     }
   1262 
   1263     case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB:
   1264     case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
   1265       return params_.link_url.is_valid();
   1266 
   1267     case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
   1268       return params_.unfiltered_link_url.is_valid();
   1269 
   1270     case IDC_CONTENT_CONTEXT_SAVELINKAS: {
   1271       PrefService* local_state = g_browser_process->local_state();
   1272       DCHECK(local_state);
   1273       // Test if file-selection dialogs are forbidden by policy.
   1274       if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
   1275         return false;
   1276 
   1277       return params_.link_url.is_valid() &&
   1278           ProfileIOData::IsHandledProtocol(params_.link_url.scheme());
   1279     }
   1280 
   1281     case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: {
   1282       PrefService* local_state = g_browser_process->local_state();
   1283       DCHECK(local_state);
   1284       // Test if file-selection dialogs are forbidden by policy.
   1285       if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
   1286         return false;
   1287 
   1288       return params_.src_url.is_valid() &&
   1289           ProfileIOData::IsHandledProtocol(params_.src_url.scheme());
   1290     }
   1291 
   1292     // The images shown in the most visited thumbnails can't be opened or
   1293     // searched for conventionally.
   1294     case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
   1295     case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
   1296       return params_.src_url.is_valid() &&
   1297           (params_.src_url.scheme() != chrome::kChromeUIScheme);
   1298 
   1299     case IDC_CONTENT_CONTEXT_COPYIMAGE:
   1300       return params_.has_image_contents;
   1301 
   1302     // Media control commands should all be disabled if the player is in an
   1303     // error state.
   1304     case IDC_CONTENT_CONTEXT_PLAYPAUSE:
   1305     case IDC_CONTENT_CONTEXT_LOOP:
   1306       return (params_.media_flags &
   1307               WebContextMenuData::MediaInError) == 0;
   1308 
   1309     // Mute and unmute should also be disabled if the player has no audio.
   1310     case IDC_CONTENT_CONTEXT_MUTE:
   1311       return (params_.media_flags &
   1312               WebContextMenuData::MediaHasAudio) != 0 &&
   1313              (params_.media_flags &
   1314               WebContextMenuData::MediaInError) == 0;
   1315 
   1316     // Media controls can be toggled only for video player. If we toggle
   1317     // controls for audio then the player disappears, and there is no way to
   1318     // return it back.
   1319     case IDC_CONTENT_CONTEXT_CONTROLS:
   1320       return (params_.media_flags &
   1321               WebContextMenuData::MediaHasVideo) != 0;
   1322 
   1323     case IDC_CONTENT_CONTEXT_ROTATECW:
   1324     case IDC_CONTENT_CONTEXT_ROTATECCW:
   1325       return
   1326           (params_.media_flags & WebContextMenuData::MediaCanRotate) != 0;
   1327 
   1328     case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
   1329     case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
   1330       return params_.src_url.is_valid();
   1331 
   1332     case IDC_CONTENT_CONTEXT_SAVEAVAS: {
   1333       PrefService* local_state = g_browser_process->local_state();
   1334       DCHECK(local_state);
   1335       // Test if file-selection dialogs are forbidden by policy.
   1336       if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
   1337         return false;
   1338 
   1339       const GURL& url = params_.src_url;
   1340       bool can_save =
   1341           (params_.media_flags & WebContextMenuData::MediaCanSave) &&
   1342           url.is_valid() && ProfileIOData::IsHandledProtocol(url.scheme());
   1343 #if defined(ENABLE_FULL_PRINTING)
   1344           // Do not save the preview PDF on the print preview page.
   1345       can_save = can_save &&
   1346           !(printing::PrintPreviewDialogController::IsPrintPreviewURL(url));
   1347 #endif
   1348       return can_save;
   1349     }
   1350 
   1351     case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
   1352       return true;
   1353 
   1354     case IDC_SAVE_PAGE: {
   1355       CoreTabHelper* core_tab_helper =
   1356           CoreTabHelper::FromWebContents(source_web_contents_);
   1357       if (!core_tab_helper)
   1358         return false;
   1359 
   1360       CoreTabHelperDelegate* core_delegate = core_tab_helper->delegate();
   1361       if (core_delegate &&
   1362           !core_delegate->CanSaveContents(source_web_contents_))
   1363         return false;
   1364 
   1365       PrefService* local_state = g_browser_process->local_state();
   1366       DCHECK(local_state);
   1367       // Test if file-selection dialogs are forbidden by policy.
   1368       if (!local_state->GetBoolean(prefs::kAllowFileSelectionDialogs))
   1369         return false;
   1370 
   1371       // Instead of using GetURL here, we use url() (which is the "real" url of
   1372       // the page) from the NavigationEntry because its reflects their origin
   1373       // rather than the display one (returned by GetURL) which may be
   1374       // different (like having "view-source:" on the front).
   1375       // TODO(nasko): Audit all GetActiveEntry calls in this file.
   1376       NavigationEntry* active_entry =
   1377           source_web_contents_->GetController().GetActiveEntry();
   1378       return content::IsSavableURL(
   1379           (active_entry) ? active_entry->GetURL() : GURL());
   1380     }
   1381 
   1382     case IDC_CONTENT_CONTEXT_RELOADFRAME:
   1383       return params_.frame_url.is_valid();
   1384 
   1385     case IDC_CONTENT_CONTEXT_UNDO:
   1386       return !!(params_.edit_flags & WebContextMenuData::CanUndo);
   1387 
   1388     case IDC_CONTENT_CONTEXT_REDO:
   1389       return !!(params_.edit_flags & WebContextMenuData::CanRedo);
   1390 
   1391     case IDC_CONTENT_CONTEXT_CUT:
   1392       return !!(params_.edit_flags & WebContextMenuData::CanCut);
   1393 
   1394     case IDC_CONTENT_CONTEXT_COPY:
   1395       return !!(params_.edit_flags & WebContextMenuData::CanCopy);
   1396 
   1397     case IDC_CONTENT_CONTEXT_PASTE:
   1398     case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE:
   1399       return !!(params_.edit_flags & WebContextMenuData::CanPaste);
   1400 
   1401     case IDC_CONTENT_CONTEXT_DELETE:
   1402       return !!(params_.edit_flags & WebContextMenuData::CanDelete);
   1403 
   1404     case IDC_CONTENT_CONTEXT_SELECTALL:
   1405       return !!(params_.edit_flags & WebContextMenuData::CanSelectAll);
   1406 
   1407     case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
   1408       return !profile_->IsOffTheRecord() && params_.link_url.is_valid() &&
   1409              incognito_avail != IncognitoModePrefs::DISABLED;
   1410 
   1411     case IDC_PRINT:
   1412       return profile_->GetPrefs()->GetBoolean(prefs::kPrintingEnabled) &&
   1413           (params_.media_type == WebContextMenuData::MediaTypeNone ||
   1414            params_.media_flags & WebContextMenuData::MediaCanPrint);
   1415 
   1416     case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
   1417     case IDC_CONTENT_CONTEXT_GOTOURL:
   1418     case IDC_SPELLPANEL_TOGGLE:
   1419     case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS:
   1420       return true;
   1421     case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO:
   1422       // Disabled if no browser is associated (e.g. desktop notifications).
   1423       if (chrome::FindBrowserWithWebContents(source_web_contents_) == NULL)
   1424         return false;
   1425       return true;
   1426 
   1427     case IDC_CHECK_SPELLING_WHILE_TYPING:
   1428       return profile_->GetPrefs()->GetBoolean(
   1429           prefs::kEnableContinuousSpellcheck);
   1430 
   1431 #if !defined(OS_MACOSX) && defined(OS_POSIX)
   1432     // TODO(suzhe): this should not be enabled for password fields.
   1433     case IDC_INPUT_METHODS_MENU:
   1434       return true;
   1435 #endif
   1436 
   1437     case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE:
   1438       return !params_.keyword_url.is_empty();
   1439 
   1440     case IDC_SPELLCHECK_MENU:
   1441       return true;
   1442 
   1443     case IDC_CONTENT_CONTEXT_SPEECH_INPUT_FILTER_PROFANITIES:
   1444     case IDC_CONTENT_CONTEXT_SPEECH_INPUT_ABOUT:
   1445     case IDC_SPEECH_INPUT_MENU:
   1446       return true;
   1447 
   1448     case IDC_CONTENT_CONTEXT_OPENLINKWITH:
   1449       return true;
   1450 
   1451     case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS:
   1452       return true;
   1453 
   1454     default:
   1455       NOTREACHED();
   1456       return false;
   1457   }
   1458 }
   1459 
   1460 bool RenderViewContextMenu::IsCommandIdChecked(int id) const {
   1461   // If this command is is added by one of our observers, we dispatch it to the
   1462   // observer.
   1463   ObserverListBase<RenderViewContextMenuObserver>::Iterator it(observers_);
   1464   RenderViewContextMenuObserver* observer;
   1465   while ((observer = it.GetNext()) != NULL) {
   1466     if (observer->IsCommandIdSupported(id))
   1467       return observer->IsCommandIdChecked(id);
   1468   }
   1469 
   1470   // See if the video is set to looping.
   1471   if (id == IDC_CONTENT_CONTEXT_LOOP) {
   1472     return (params_.media_flags &
   1473             WebContextMenuData::MediaLoop) != 0;
   1474   }
   1475 
   1476   if (id == IDC_CONTENT_CONTEXT_CONTROLS) {
   1477     return (params_.media_flags &
   1478             WebContextMenuData::MediaControls) != 0;
   1479   }
   1480 
   1481   // Custom items.
   1482   if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
   1483       id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) {
   1484     return IsCustomItemChecked(params_.custom_items, id);
   1485   }
   1486 
   1487   // Extension items.
   1488   if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
   1489       id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
   1490     return extension_items_.IsCommandIdChecked(id);
   1491   }
   1492 
   1493 #if defined(ENABLE_INPUT_SPEECH)
   1494   // Check box for menu item 'Block offensive words'.
   1495   if (id == IDC_CONTENT_CONTEXT_SPEECH_INPUT_FILTER_PROFANITIES) {
   1496     return profile_->GetPrefs()->GetBoolean(
   1497         prefs::kSpeechRecognitionFilterProfanities);
   1498   }
   1499 #endif
   1500 
   1501   return false;
   1502 }
   1503 
   1504 void RenderViewContextMenu::ExecuteCommand(int id, int event_flags) {
   1505   command_executed_ = true;
   1506   // If this command is is added by one of our observers, we dispatch it to the
   1507   // observer.
   1508   ObserverListBase<RenderViewContextMenuObserver>::Iterator it(observers_);
   1509   RenderViewContextMenuObserver* observer;
   1510   while ((observer = it.GetNext()) != NULL) {
   1511     if (observer->IsCommandIdSupported(id))
   1512       return observer->ExecuteCommand(id);
   1513   }
   1514 
   1515   RecordUsedItem(id);
   1516 
   1517   RenderViewHost* rvh = source_web_contents_->GetRenderViewHost();
   1518 
   1519   // Process custom actions range.
   1520   if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
   1521       id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) {
   1522     unsigned action = id - IDC_CONTENT_CONTEXT_CUSTOM_FIRST;
   1523     const content::CustomContextMenuContext& context = params_.custom_context;
   1524 #if defined(ENABLE_PLUGINS)
   1525     if (context.request_id && !context.is_pepper_menu) {
   1526       ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins(
   1527         rvh->GetProcess()->GetID());
   1528     }
   1529 #endif
   1530     rvh->ExecuteCustomContextMenuCommand(action, context);
   1531     return;
   1532   }
   1533 
   1534   // Process extension menu items.
   1535   if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
   1536       id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
   1537     extension_items_.ExecuteCommand(id, source_web_contents_, params_);
   1538     return;
   1539   }
   1540 
   1541   if (id >= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST &&
   1542       id <= IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_LAST) {
   1543     ProtocolHandlerRegistry::ProtocolHandlerList handlers =
   1544         GetHandlersForLinkUrl();
   1545     if (handlers.empty()) {
   1546       return;
   1547     }
   1548     content::RecordAction(
   1549         UserMetricsAction("RegisterProtocolHandler.ContextMenu_Open"));
   1550     int handlerIndex = id - IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST;
   1551     WindowOpenDisposition disposition =
   1552         ForceNewTabDispositionFromEventFlags(event_flags);
   1553     OpenURL(
   1554         handlers[handlerIndex].TranslateUrl(params_.link_url),
   1555         params_.frame_url.is_empty() ? params_.page_url : params_.frame_url,
   1556         params_.frame_id,
   1557         disposition,
   1558         content::PAGE_TRANSITION_LINK);
   1559     return;
   1560   }
   1561 
   1562   switch (id) {
   1563     case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB: {
   1564       Browser* browser =
   1565           chrome::FindBrowserWithWebContents(source_web_contents_);
   1566       OpenURL(
   1567           params_.link_url,
   1568           params_.frame_url.is_empty() ? params_.page_url : params_.frame_url,
   1569           params_.frame_id,
   1570           !browser || browser->is_app() ?
   1571                   NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB,
   1572           content::PAGE_TRANSITION_LINK);
   1573       break;
   1574     }
   1575     case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
   1576       OpenURL(
   1577           params_.link_url,
   1578           params_.frame_url.is_empty() ? params_.page_url : params_.frame_url,
   1579           params_.frame_id,
   1580           NEW_WINDOW, content::PAGE_TRANSITION_LINK);
   1581       break;
   1582 
   1583     case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
   1584       OpenURL(params_.link_url,
   1585               GURL(),
   1586               params_.frame_id,
   1587               OFF_THE_RECORD,
   1588               content::PAGE_TRANSITION_LINK);
   1589       break;
   1590 
   1591     case IDC_CONTENT_CONTEXT_SAVELINKAS: {
   1592       RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
   1593       const GURL& referrer =
   1594           params_.frame_url.is_empty() ? params_.page_url : params_.frame_url;
   1595       const GURL& url = params_.link_url;
   1596       DownloadManager* dlm = BrowserContext::GetDownloadManager(profile_);
   1597       scoped_ptr<DownloadUrlParameters> dl_params(
   1598           DownloadUrlParameters::FromWebContents(source_web_contents_, url));
   1599       dl_params->set_referrer(
   1600           content::Referrer(referrer, params_.referrer_policy));
   1601       dl_params->set_referrer_encoding(params_.frame_charset);
   1602       dl_params->set_prompt(true);
   1603       dlm->DownloadUrl(dl_params.Pass());
   1604       break;
   1605     }
   1606 
   1607     case IDC_CONTENT_CONTEXT_SAVEAVAS:
   1608     case IDC_CONTENT_CONTEXT_SAVEIMAGEAS: {
   1609       RecordDownloadSource(DOWNLOAD_INITIATED_BY_CONTEXT_MENU);
   1610       const GURL& referrer =
   1611           params_.frame_url.is_empty() ? params_.page_url : params_.frame_url;
   1612       const GURL& url = params_.src_url;
   1613       int64 post_id = -1;
   1614       if (url == source_web_contents_->GetURL()) {
   1615         const NavigationEntry* entry =
   1616             source_web_contents_->GetController().GetActiveEntry();
   1617         if (entry)
   1618           post_id = entry->GetPostID();
   1619       }
   1620       DownloadManager* dlm = BrowserContext::GetDownloadManager(profile_);
   1621       scoped_ptr<DownloadUrlParameters> dl_params(
   1622           DownloadUrlParameters::FromWebContents(source_web_contents_, url));
   1623       dl_params->set_referrer(
   1624           content::Referrer(referrer, params_.referrer_policy));
   1625       dl_params->set_post_id(post_id);
   1626       dl_params->set_prefer_cache(true);
   1627       if (post_id >= 0)
   1628         dl_params->set_method("POST");
   1629       dl_params->set_prompt(true);
   1630       dlm->DownloadUrl(dl_params.Pass());
   1631       break;
   1632     }
   1633 
   1634     case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
   1635       WriteURLToClipboard(params_.unfiltered_link_url);
   1636       break;
   1637 
   1638     case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
   1639     case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
   1640       WriteURLToClipboard(params_.src_url);
   1641       break;
   1642 
   1643     case IDC_CONTENT_CONTEXT_COPYIMAGE:
   1644       CopyImageAt(params_.x, params_.y);
   1645       break;
   1646 
   1647     case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
   1648       GetImageThumbnailForSearch();
   1649       break;
   1650 
   1651     case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
   1652     case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
   1653       OpenURL(
   1654           params_.src_url,
   1655           params_.frame_url.is_empty() ? params_.page_url : params_.frame_url,
   1656           params_.frame_id,
   1657           NEW_BACKGROUND_TAB, content::PAGE_TRANSITION_LINK);
   1658       break;
   1659 
   1660     case IDC_CONTENT_CONTEXT_PLAYPAUSE: {
   1661       bool play = !!(params_.media_flags & WebContextMenuData::MediaPaused);
   1662       if (play) {
   1663         content::RecordAction(UserMetricsAction("MediaContextMenu_Play"));
   1664       } else {
   1665         content::RecordAction(UserMetricsAction("MediaContextMenu_Pause"));
   1666       }
   1667       MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
   1668                           WebMediaPlayerAction(
   1669                               WebMediaPlayerAction::Play, play));
   1670       break;
   1671     }
   1672 
   1673     case IDC_CONTENT_CONTEXT_MUTE: {
   1674       bool mute = !(params_.media_flags & WebContextMenuData::MediaMuted);
   1675       if (mute) {
   1676         content::RecordAction(UserMetricsAction("MediaContextMenu_Mute"));
   1677       } else {
   1678         content::RecordAction(UserMetricsAction("MediaContextMenu_Unmute"));
   1679       }
   1680       MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
   1681                           WebMediaPlayerAction(
   1682                               WebMediaPlayerAction::Mute, mute));
   1683       break;
   1684     }
   1685 
   1686     case IDC_CONTENT_CONTEXT_LOOP:
   1687       content::RecordAction(UserMetricsAction("MediaContextMenu_Loop"));
   1688       MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
   1689                           WebMediaPlayerAction(
   1690                               WebMediaPlayerAction::Loop,
   1691                               !IsCommandIdChecked(IDC_CONTENT_CONTEXT_LOOP)));
   1692       break;
   1693 
   1694     case IDC_CONTENT_CONTEXT_CONTROLS:
   1695       content::RecordAction(UserMetricsAction("MediaContextMenu_Controls"));
   1696       MediaPlayerActionAt(
   1697           gfx::Point(params_.x, params_.y),
   1698           WebMediaPlayerAction(
   1699               WebMediaPlayerAction::Controls,
   1700               !IsCommandIdChecked(IDC_CONTENT_CONTEXT_CONTROLS)));
   1701       break;
   1702 
   1703     case IDC_CONTENT_CONTEXT_ROTATECW:
   1704       content::RecordAction(
   1705       UserMetricsAction("PluginContextMenu_RotateClockwise"));
   1706       PluginActionAt(
   1707           gfx::Point(params_.x, params_.y),
   1708           WebPluginAction(
   1709               WebPluginAction::Rotate90Clockwise,
   1710               true));
   1711       break;
   1712 
   1713     case IDC_CONTENT_CONTEXT_ROTATECCW:
   1714       content::RecordAction(
   1715       UserMetricsAction("PluginContextMenu_RotateCounterclockwise"));
   1716       PluginActionAt(
   1717           gfx::Point(params_.x, params_.y),
   1718           WebPluginAction(
   1719               WebPluginAction::Rotate90Counterclockwise,
   1720               true));
   1721       break;
   1722 
   1723     case IDC_BACK:
   1724       source_web_contents_->GetController().GoBack();
   1725       break;
   1726 
   1727     case IDC_FORWARD:
   1728       source_web_contents_->GetController().GoForward();
   1729       break;
   1730 
   1731     case IDC_SAVE_PAGE:
   1732       source_web_contents_->OnSavePage();
   1733       break;
   1734 
   1735     case IDC_RELOAD:
   1736       // Prevent the modal "Resubmit form post" dialog from appearing in the
   1737       // context of an external context menu.
   1738       source_web_contents_->GetController().Reload(!external_);
   1739       break;
   1740 
   1741     case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP: {
   1742       const Extension* platform_app = GetExtension();
   1743       DCHECK(platform_app);
   1744       DCHECK(platform_app->is_platform_app());
   1745 
   1746       extensions::ExtensionSystem::Get(profile_)->extension_service()->
   1747           ReloadExtension(platform_app->id());
   1748       break;
   1749     }
   1750 
   1751     case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP: {
   1752       const Extension* platform_app = GetExtension();
   1753       DCHECK(platform_app);
   1754       DCHECK(platform_app->is_platform_app());
   1755 
   1756       apps::AppLoadService::Get(profile_)->RestartApplication(
   1757           platform_app->id());
   1758       break;
   1759     }
   1760 
   1761     case IDC_PRINT:
   1762 #if defined(ENABLE_PRINTING)
   1763       if (params_.media_type == WebContextMenuData::MediaTypeNone) {
   1764 #if defined(ENABLE_FULL_PRINTING)
   1765         printing::PrintViewManager* print_view_manager =
   1766             printing::PrintViewManager::FromWebContents(source_web_contents_);
   1767 
   1768         if (!print_view_manager)
   1769           break;
   1770         if (profile_->GetPrefs()->GetBoolean(prefs::kPrintPreviewDisabled)) {
   1771           print_view_manager->PrintNow();
   1772         } else {
   1773           print_view_manager->PrintPreviewNow(!params_.selection_text.empty());
   1774         }
   1775 #else
   1776         printing::PrintViewManagerBasic* print_view_manager =
   1777             printing::PrintViewManagerBasic::FromWebContents(
   1778                 source_web_contents_);
   1779         if (!print_view_manager)
   1780           break;
   1781         print_view_manager->PrintNow();
   1782 #endif  // defined(ENABLE_FULL_PRINTING)
   1783       } else {
   1784         rvh->Send(new PrintMsg_PrintNodeUnderContextMenu(rvh->GetRoutingID()));
   1785       }
   1786 #endif  // defined(ENABLE_PRINTING)
   1787       break;
   1788 
   1789     case IDC_VIEW_SOURCE:
   1790       source_web_contents_->ViewSource();
   1791       break;
   1792 
   1793     case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
   1794       Inspect(params_.x, params_.y);
   1795       break;
   1796 
   1797     case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE: {
   1798       const Extension* platform_app = GetExtension();
   1799       DCHECK(platform_app);
   1800       DCHECK(platform_app->is_platform_app());
   1801 
   1802       extensions::devtools_util::InspectBackgroundPage(platform_app, profile_);
   1803       break;
   1804     }
   1805 
   1806     case IDC_CONTENT_CONTEXT_VIEWPAGEINFO: {
   1807       NavigationController* controller = &source_web_contents_->GetController();
   1808       // Important to use GetVisibleEntry to match what's showing in the
   1809       // omnibox.
   1810       NavigationEntry* nav_entry = controller->GetVisibleEntry();
   1811       Browser* browser =
   1812           chrome::FindBrowserWithWebContents(source_web_contents_);
   1813       chrome::ShowWebsiteSettings(browser, source_web_contents_,
   1814                                   nav_entry->GetURL(), nav_entry->GetSSL());
   1815       break;
   1816     }
   1817 
   1818     case IDC_CONTENT_CONTEXT_TRANSLATE: {
   1819       // A translation might have been triggered by the time the menu got
   1820       // selected, do nothing in that case.
   1821       TranslateTabHelper* translate_tab_helper =
   1822           TranslateTabHelper::FromWebContents(source_web_contents_);
   1823       if (!translate_tab_helper ||
   1824           translate_tab_helper->language_state().IsPageTranslated() ||
   1825           translate_tab_helper->language_state().translation_pending()) {
   1826         return;
   1827       }
   1828       std::string original_lang =
   1829           translate_tab_helper->language_state().original_language();
   1830       std::string target_lang = g_browser_process->GetApplicationLocale();
   1831       target_lang = TranslateManager::GetLanguageCode(target_lang);
   1832       // Since the user decided to translate for that language and site, clears
   1833       // any preferences for not translating them.
   1834       TranslatePrefs prefs(profile_->GetPrefs());
   1835       prefs.UnblockLanguage(original_lang);
   1836       prefs.RemoveSiteFromBlacklist(params_.page_url.HostNoBrackets());
   1837       TranslateManager::GetInstance()->TranslatePage(
   1838           source_web_contents_, original_lang, target_lang);
   1839       break;
   1840     }
   1841 
   1842     case IDC_CONTENT_CONTEXT_RELOADFRAME:
   1843       rvh->ReloadFrame();
   1844       break;
   1845 
   1846     case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
   1847       source_web_contents_->ViewFrameSource(params_.frame_url,
   1848                                             params_.frame_page_state);
   1849       break;
   1850 
   1851     case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO: {
   1852       Browser* browser = chrome::FindBrowserWithWebContents(
   1853           source_web_contents_);
   1854       chrome::ShowWebsiteSettings(browser, source_web_contents_,
   1855                                   params_.frame_url, params_.security_info);
   1856       break;
   1857     }
   1858 
   1859     case IDC_CONTENT_CONTEXT_UNDO:
   1860       rvh->Undo();
   1861       break;
   1862 
   1863     case IDC_CONTENT_CONTEXT_REDO:
   1864       rvh->Redo();
   1865       break;
   1866 
   1867     case IDC_CONTENT_CONTEXT_CUT:
   1868       rvh->Cut();
   1869       break;
   1870 
   1871     case IDC_CONTENT_CONTEXT_COPY:
   1872       rvh->Copy();
   1873       break;
   1874 
   1875     case IDC_CONTENT_CONTEXT_PASTE:
   1876       rvh->Paste();
   1877       break;
   1878 
   1879     case IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE:
   1880       rvh->PasteAndMatchStyle();
   1881       break;
   1882 
   1883     case IDC_CONTENT_CONTEXT_DELETE:
   1884       rvh->Delete();
   1885       break;
   1886 
   1887     case IDC_CONTENT_CONTEXT_SELECTALL:
   1888       rvh->SelectAll();
   1889       break;
   1890 
   1891     case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
   1892     case IDC_CONTENT_CONTEXT_GOTOURL: {
   1893       WindowOpenDisposition disposition =
   1894           ForceNewTabDispositionFromEventFlags(event_flags);
   1895       OpenURL(selection_navigation_url_,
   1896               GURL(),
   1897               params_.frame_id,
   1898               disposition,
   1899               content::PAGE_TRANSITION_LINK);
   1900       break;
   1901     }
   1902     case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS: {
   1903       WindowOpenDisposition disposition =
   1904           ForceNewTabDispositionFromEventFlags(event_flags);
   1905       std::string url = std::string(chrome::kChromeUISettingsURL) +
   1906           chrome::kLanguageOptionsSubPage;
   1907       OpenURL(GURL(url), GURL(), 0, disposition, content::PAGE_TRANSITION_LINK);
   1908       break;
   1909     }
   1910 
   1911     case IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS: {
   1912       content::RecordAction(
   1913           UserMetricsAction("RegisterProtocolHandler.ContextMenu_Settings"));
   1914       WindowOpenDisposition disposition =
   1915           ForceNewTabDispositionFromEventFlags(event_flags);
   1916       std::string url = std::string(chrome::kChromeUISettingsURL) +
   1917           chrome::kHandlerSettingsSubPage;
   1918       OpenURL(GURL(url), GURL(), 0, disposition, content::PAGE_TRANSITION_LINK);
   1919       break;
   1920     }
   1921 
   1922     case IDC_CONTENT_CONTEXT_ADDSEARCHENGINE: {
   1923       // Make sure the model is loaded.
   1924       TemplateURLService* model =
   1925           TemplateURLServiceFactory::GetForProfile(profile_);
   1926       if (!model)
   1927         return;
   1928       model->Load();
   1929 
   1930       SearchEngineTabHelper* search_engine_tab_helper =
   1931           SearchEngineTabHelper::FromWebContents(source_web_contents_);
   1932       if (search_engine_tab_helper &&
   1933           search_engine_tab_helper->delegate()) {
   1934         base::string16 keyword(
   1935             TemplateURLService::GenerateKeyword(params_.page_url));
   1936         TemplateURLData data;
   1937         data.short_name = keyword;
   1938         data.SetKeyword(keyword);
   1939         data.SetURL(params_.keyword_url.spec());
   1940         data.favicon_url =
   1941             TemplateURL::GenerateFaviconURL(params_.page_url.GetOrigin());
   1942         // Takes ownership of the TemplateURL.
   1943         search_engine_tab_helper->delegate()->
   1944             ConfirmAddSearchProvider(new TemplateURL(profile_, data), profile_);
   1945       }
   1946       break;
   1947     }
   1948 
   1949 #if defined(ENABLE_INPUT_SPEECH)
   1950     case IDC_CONTENT_CONTEXT_SPEECH_INPUT_FILTER_PROFANITIES: {
   1951       profile_->GetPrefs()->SetBoolean(
   1952           prefs::kSpeechRecognitionFilterProfanities,
   1953           !profile_->GetPrefs()->GetBoolean(
   1954               prefs::kSpeechRecognitionFilterProfanities));
   1955       break;
   1956     }
   1957 #endif
   1958     case IDC_CONTENT_CONTEXT_SPEECH_INPUT_ABOUT: {
   1959       GURL url(chrome::kSpeechInputAboutURL);
   1960       GURL localized_url = google_util::AppendGoogleLocaleParam(url);
   1961       // Open URL with no referrer field (because user clicked on menu item).
   1962       OpenURL(localized_url, GURL(), 0, NEW_FOREGROUND_TAB,
   1963           content::PAGE_TRANSITION_LINK);
   1964       break;
   1965     }
   1966 
   1967     default:
   1968       NOTREACHED();
   1969       break;
   1970   }
   1971 }
   1972 
   1973 ProtocolHandlerRegistry::ProtocolHandlerList
   1974     RenderViewContextMenu::GetHandlersForLinkUrl() {
   1975   ProtocolHandlerRegistry::ProtocolHandlerList handlers =
   1976       protocol_handler_registry_->GetHandlersFor(params_.link_url.scheme());
   1977   std::sort(handlers.begin(), handlers.end());
   1978   return handlers;
   1979 }
   1980 
   1981 void RenderViewContextMenu::MenuWillShow(ui::SimpleMenuModel* source) {
   1982   for (int i = 0; i < source->GetItemCount(); ++i) {
   1983     if (source->IsVisibleAt(i) &&
   1984         source->GetTypeAt(i) != ui::MenuModel::TYPE_SEPARATOR) {
   1985       RecordShownItem(source->GetCommandIdAt(i));
   1986     }
   1987   }
   1988 
   1989   // Ignore notifications from submenus.
   1990   if (source != &menu_model_)
   1991     return;
   1992 
   1993   content::RenderWidgetHostView* view =
   1994       source_web_contents_->GetRenderWidgetHostView();
   1995   if (view)
   1996     view->SetShowingContextMenu(true);
   1997 
   1998   content::NotificationService::current()->Notify(
   1999       chrome::NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN,
   2000       content::Source<RenderViewContextMenu>(this),
   2001       content::NotificationService::NoDetails());
   2002 }
   2003 
   2004 void RenderViewContextMenu::MenuClosed(ui::SimpleMenuModel* source) {
   2005   // Ignore notifications from submenus.
   2006   if (source != &menu_model_)
   2007     return;
   2008 
   2009   content::RenderWidgetHostView* view =
   2010       source_web_contents_->GetRenderWidgetHostView();
   2011   if (view)
   2012     view->SetShowingContextMenu(false);
   2013   RenderViewHost* rvh = source_web_contents_->GetRenderViewHost();
   2014   if (rvh) {
   2015     rvh->NotifyContextMenuClosed(params_.custom_context);
   2016   }
   2017 
   2018   if (!command_executed_) {
   2019     FOR_EACH_OBSERVER(RenderViewContextMenuObserver,
   2020                       observers_,
   2021                       OnMenuCancel());
   2022   }
   2023 }
   2024 
   2025 bool RenderViewContextMenu::IsDevCommandEnabled(int id) const {
   2026   if (id == IDC_CONTENT_CONTEXT_INSPECTELEMENT ||
   2027       id == IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE) {
   2028     const CommandLine* command_line = CommandLine::ForCurrentProcess();
   2029     if (!profile_->GetPrefs()->GetBoolean(prefs::kWebKitJavascriptEnabled) ||
   2030         command_line->HasSwitch(switches::kDisableJavaScript))
   2031       return false;
   2032 
   2033     // Don't enable the web inspector if the developer tools are disabled via
   2034     // the preference dev-tools-disabled.
   2035     if (profile_->GetPrefs()->GetBoolean(prefs::kDevToolsDisabled))
   2036       return false;
   2037   }
   2038 
   2039   return true;
   2040 }
   2041 
   2042 base::string16 RenderViewContextMenu::PrintableSelectionText() {
   2043   return gfx::TruncateString(params_.selection_text,
   2044                             kMaxSelectionTextLength);
   2045 }
   2046 
   2047 // Controller functions --------------------------------------------------------
   2048 
   2049 void RenderViewContextMenu::OpenURL(
   2050     const GURL& url, const GURL& referrer, int64 frame_id,
   2051     WindowOpenDisposition disposition,
   2052     content::PageTransition transition) {
   2053   // Ensure that URL fragment, username and password fields are not sent
   2054   // in the referrer.
   2055   GURL sanitized_referrer(referrer);
   2056   if (sanitized_referrer.is_valid() && (sanitized_referrer.has_ref() ||
   2057       sanitized_referrer.has_username() || sanitized_referrer.has_password())) {
   2058     GURL::Replacements referrer_mods;
   2059     referrer_mods.ClearRef();
   2060     referrer_mods.ClearUsername();
   2061     referrer_mods.ClearPassword();
   2062     sanitized_referrer = sanitized_referrer.ReplaceComponents(referrer_mods);
   2063   }
   2064 
   2065   WebContents* new_contents = source_web_contents_->OpenURL(OpenURLParams(
   2066       url, content::Referrer(sanitized_referrer, params_.referrer_policy),
   2067       disposition, transition, false));
   2068   if (!new_contents)
   2069     return;
   2070 
   2071   RetargetingDetails details;
   2072   details.source_web_contents = source_web_contents_;
   2073   details.source_frame_id = frame_id;
   2074   details.target_url = url;
   2075   details.target_web_contents = new_contents;
   2076   details.not_yet_in_tabstrip = false;
   2077   content::NotificationService::current()->Notify(
   2078       chrome::NOTIFICATION_RETARGETING,
   2079       content::Source<Profile>(Profile::FromBrowserContext(
   2080           source_web_contents_->GetBrowserContext())),
   2081       content::Details<RetargetingDetails>(&details));
   2082 }
   2083 
   2084 void RenderViewContextMenu::CopyImageAt(int x, int y) {
   2085   source_web_contents_->GetRenderViewHost()->CopyImageAt(x, y);
   2086 }
   2087 
   2088 void RenderViewContextMenu::GetImageThumbnailForSearch() {
   2089   source_web_contents_->GetRenderViewHost()->Send(
   2090        new ChromeViewMsg_RequestThumbnailForContextNode(
   2091            source_web_contents_->GetRenderViewHost()->GetRoutingID(),
   2092            kImageSearchThumbnailMinSize,
   2093            gfx::Size(kImageSearchThumbnailMaxWidth,
   2094                      kImageSearchThumbnailMaxHeight)));
   2095 }
   2096 
   2097 void RenderViewContextMenu::Inspect(int x, int y) {
   2098   content::RecordAction(UserMetricsAction("DevTools_InspectElement"));
   2099   source_web_contents_->GetRenderViewHostAtPosition(
   2100       x, y, base::Bind(&DevToolsInspectElementAt));
   2101 }
   2102 
   2103 void RenderViewContextMenu::WriteURLToClipboard(const GURL& url) {
   2104   chrome_common_net::WriteURLToClipboard(
   2105       url,
   2106       profile_->GetPrefs()->GetString(prefs::kAcceptLanguages),
   2107       ui::Clipboard::GetForCurrentThread());
   2108 }
   2109 
   2110 void RenderViewContextMenu::MediaPlayerActionAt(
   2111     const gfx::Point& location,
   2112     const WebMediaPlayerAction& action) {
   2113   source_web_contents_->GetRenderViewHost()->
   2114       ExecuteMediaPlayerActionAtLocation(location, action);
   2115 }
   2116 
   2117 void RenderViewContextMenu::PluginActionAt(
   2118     const gfx::Point& location,
   2119     const WebPluginAction& action) {
   2120   source_web_contents_->GetRenderViewHost()->
   2121       ExecutePluginActionAtLocation(location, action);
   2122 }
   2123