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