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