Home | History | Annotate | Download | only in tab_contents
      1 // Copyright (c) 2011 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 <algorithm>
      6 #include <set>
      7 
      8 #include "chrome/browser/tab_contents/render_view_context_menu.h"
      9 
     10 #include "base/command_line.h"
     11 #include "base/logging.h"
     12 #include "base/metrics/histogram.h"
     13 #include "base/stl_util-inl.h"
     14 #include "base/string_util.h"
     15 #include "base/time.h"
     16 #include "base/utf_string_conversions.h"
     17 #include "chrome/app/chrome_command_ids.h"
     18 #include "chrome/browser/autocomplete/autocomplete_classifier.h"
     19 #include "chrome/browser/autocomplete/autocomplete_edit.h"
     20 #include "chrome/browser/autocomplete/autocomplete_match.h"
     21 #include "chrome/browser/browser_process.h"
     22 #include "chrome/browser/debugger/devtools_manager.h"
     23 #include "chrome/browser/debugger/devtools_window.h"
     24 #include "chrome/browser/download/download_manager.h"
     25 #include "chrome/browser/download/download_util.h"
     26 #include "chrome/browser/download/save_package.h"
     27 #include "chrome/browser/extensions/extension_event_router.h"
     28 #include "chrome/browser/extensions/extension_service.h"
     29 #include "chrome/browser/metrics/user_metrics.h"
     30 #include "chrome/browser/net/browser_url_util.h"
     31 #include "chrome/browser/page_info_window.h"
     32 #include "chrome/browser/platform_util.h"
     33 #include "chrome/browser/prefs/pref_member.h"
     34 #include "chrome/browser/prefs/pref_service.h"
     35 #include "chrome/browser/printing/print_preview_tab_controller.h"
     36 #include "chrome/browser/profiles/profile.h"
     37 #include "chrome/browser/search_engines/template_url.h"
     38 #include "chrome/browser/search_engines/template_url_model.h"
     39 #include "chrome/browser/spellcheck_host.h"
     40 #include "chrome/browser/spellchecker_platform_engine.h"
     41 #include "chrome/browser/translate/translate_manager.h"
     42 #include "chrome/browser/translate/translate_prefs.h"
     43 #include "chrome/browser/translate/translate_tab_helper.h"
     44 #include "chrome/browser/ui/download/download_tab_helper.h"
     45 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
     46 #include "chrome/common/chrome_constants.h"
     47 #include "chrome/common/chrome_switches.h"
     48 #include "chrome/common/content_restriction.h"
     49 #include "chrome/common/pref_names.h"
     50 #include "chrome/common/print_messages.h"
     51 #include "chrome/common/url_constants.h"
     52 #include "content/browser/child_process_security_policy.h"
     53 #include "content/browser/renderer_host/render_view_host.h"
     54 #include "content/browser/renderer_host/render_widget_host_view.h"
     55 #include "content/browser/tab_contents/navigation_entry.h"
     56 #include "content/browser/tab_contents/tab_contents.h"
     57 #include "grit/generated_resources.h"
     58 #include "net/base/escape.h"
     59 #include "net/url_request/url_request.h"
     60 #include "third_party/WebKit/Source/WebKit/chromium/public/WebContextMenuData.h"
     61 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerAction.h"
     62 #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextDirection.h"
     63 #include "ui/base/l10n/l10n_util.h"
     64 #include "ui/gfx/favicon_size.h"
     65 #include "webkit/glue/webmenuitem.h"
     66 
     67 using WebKit::WebContextMenuData;
     68 using WebKit::WebMediaPlayerAction;
     69 
     70 namespace {
     71 
     72 bool IsCustomItemEnabled(const std::vector<WebMenuItem>& items, int id) {
     73   DCHECK(id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
     74          id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST);
     75   for (size_t i = 0; i < items.size(); ++i) {
     76     int action_id = IDC_CONTENT_CONTEXT_CUSTOM_FIRST + items[i].action;
     77     if (action_id == id)
     78       return items[i].enabled;
     79     if (items[i].type == WebMenuItem::SUBMENU) {
     80       if (IsCustomItemEnabled(items[i].submenu, id))
     81         return true;
     82     }
     83   }
     84   return false;
     85 }
     86 
     87 bool IsCustomItemChecked(const std::vector<WebMenuItem>& items, int id) {
     88   DCHECK(id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
     89          id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST);
     90   for (size_t i = 0; i < items.size(); ++i) {
     91     int action_id = IDC_CONTENT_CONTEXT_CUSTOM_FIRST + items[i].action;
     92     if (action_id == id)
     93       return items[i].checked;
     94     if (items[i].type == WebMenuItem::SUBMENU) {
     95       if (IsCustomItemChecked(items[i].submenu, id))
     96         return true;
     97     }
     98   }
     99   return false;
    100 }
    101 
    102 const size_t kMaxCustomMenuDepth = 5;
    103 const size_t kMaxCustomMenuTotalItems = 1000;
    104 
    105 void AddCustomItemsToMenu(const std::vector<WebMenuItem>& items,
    106                           size_t depth,
    107                           size_t* total_items,
    108                           ui::SimpleMenuModel::Delegate* delegate,
    109                           ui::SimpleMenuModel* menu_model) {
    110   if (depth > kMaxCustomMenuDepth) {
    111     LOG(ERROR) << "Custom menu too deeply nested.";
    112     return;
    113   }
    114   for (size_t i = 0; i < items.size(); ++i) {
    115     if (IDC_CONTENT_CONTEXT_CUSTOM_FIRST + items[i].action >=
    116         IDC_CONTENT_CONTEXT_CUSTOM_LAST) {
    117       LOG(ERROR) << "Custom menu action value too big.";
    118       return;
    119     }
    120     if (*total_items >= kMaxCustomMenuTotalItems) {
    121       LOG(ERROR) << "Custom menu too large (too many items).";
    122       return;
    123     }
    124     (*total_items)++;
    125     switch (items[i].type) {
    126       case WebMenuItem::OPTION:
    127         menu_model->AddItem(
    128             items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
    129             items[i].label);
    130         break;
    131       case WebMenuItem::CHECKABLE_OPTION:
    132         menu_model->AddCheckItem(
    133             items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
    134             items[i].label);
    135         break;
    136       case WebMenuItem::GROUP:
    137         // TODO(viettrungluu): I don't know what this is supposed to do.
    138         NOTREACHED();
    139         break;
    140       case WebMenuItem::SEPARATOR:
    141         menu_model->AddSeparator();
    142         break;
    143       case WebMenuItem::SUBMENU: {
    144         ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(delegate);
    145         AddCustomItemsToMenu(items[i].submenu, depth + 1, total_items, delegate,
    146                              submenu);
    147         menu_model->AddSubMenu(
    148             items[i].action + IDC_CONTENT_CONTEXT_CUSTOM_FIRST,
    149             items[i].label,
    150             submenu);
    151         break;
    152       }
    153       default:
    154         NOTREACHED();
    155         break;
    156     }
    157   }
    158 }
    159 
    160 }  // namespace
    161 
    162 // static
    163 const size_t RenderViewContextMenu::kMaxExtensionItemTitleLength = 75;
    164 // static
    165 const size_t RenderViewContextMenu::kMaxSelectionTextLength = 50;
    166 
    167 // static
    168 bool RenderViewContextMenu::IsDevToolsURL(const GURL& url) {
    169   return url.SchemeIs(chrome::kChromeDevToolsScheme) &&
    170       url.host() == chrome::kChromeUIDevToolsHost;
    171 }
    172 
    173 // static
    174 bool RenderViewContextMenu::IsInternalResourcesURL(const GURL& url) {
    175   if (!url.SchemeIs(chrome::kChromeUIScheme))
    176     return false;
    177   return url.host() == chrome::kChromeUISyncResourcesHost ||
    178       url.host() == chrome::kChromeUIRemotingResourcesHost;
    179 }
    180 
    181 static const int kSpellcheckRadioGroup = 1;
    182 
    183 RenderViewContextMenu::RenderViewContextMenu(
    184     TabContents* tab_contents,
    185     const ContextMenuParams& params)
    186     : params_(params),
    187       source_tab_contents_(tab_contents),
    188       profile_(tab_contents->profile()),
    189       ALLOW_THIS_IN_INITIALIZER_LIST(menu_model_(this)),
    190       external_(false),
    191       ALLOW_THIS_IN_INITIALIZER_LIST(spellcheck_submenu_model_(this)),
    192       ALLOW_THIS_IN_INITIALIZER_LIST(bidi_submenu_model_(this)) {
    193 }
    194 
    195 RenderViewContextMenu::~RenderViewContextMenu() {
    196 }
    197 
    198 // Menu construction functions -------------------------------------------------
    199 
    200 void RenderViewContextMenu::Init() {
    201   InitMenu();
    202   PlatformInit();
    203 }
    204 
    205 static bool ExtensionContextMatch(const ContextMenuParams& params,
    206                                   ExtensionMenuItem::ContextList contexts) {
    207   bool has_link = !params.link_url.is_empty();
    208   bool has_selection = !params.selection_text.empty();
    209   bool in_frame = !params.frame_url.is_empty();
    210 
    211   if (contexts.Contains(ExtensionMenuItem::ALL) ||
    212       (has_selection && contexts.Contains(ExtensionMenuItem::SELECTION)) ||
    213       (has_link && contexts.Contains(ExtensionMenuItem::LINK)) ||
    214       (params.is_editable && contexts.Contains(ExtensionMenuItem::EDITABLE)) ||
    215       (in_frame && contexts.Contains(ExtensionMenuItem::FRAME))) {
    216     return true;
    217   }
    218 
    219   switch (params.media_type) {
    220     case WebContextMenuData::MediaTypeImage:
    221       return contexts.Contains(ExtensionMenuItem::IMAGE);
    222 
    223     case WebContextMenuData::MediaTypeVideo:
    224       return contexts.Contains(ExtensionMenuItem::VIDEO);
    225 
    226     case WebContextMenuData::MediaTypeAudio:
    227       return contexts.Contains(ExtensionMenuItem::AUDIO);
    228 
    229     default:
    230       break;
    231   }
    232 
    233   // PAGE is the least specific context, so we only examine that if none of the
    234   // other contexts apply (except for FRAME, which is included in PAGE for
    235   // backwards compatibility).
    236   if (!has_link && !has_selection && !params.is_editable &&
    237       params.media_type == WebContextMenuData::MediaTypeNone &&
    238       contexts.Contains(ExtensionMenuItem::PAGE))
    239     return true;
    240 
    241   return false;
    242 }
    243 
    244 static bool ExtensionPatternMatch(const ExtensionExtent& patterns,
    245                                   const GURL& url) {
    246   // No patterns means no restriction, so that implicitly matches.
    247   if (patterns.is_empty())
    248     return true;
    249   return patterns.ContainsURL(url);
    250 }
    251 
    252 static const GURL& GetDocumentURL(const ContextMenuParams& params) {
    253   return params.frame_url.is_empty() ? params.page_url : params.frame_url;
    254 }
    255 
    256 // Given a list of items, returns the ones that match given the contents
    257 // of |params| and the profile.
    258 static ExtensionMenuItem::List GetRelevantExtensionItems(
    259     const ExtensionMenuItem::List& items,
    260     const ContextMenuParams& params,
    261     Profile* profile,
    262     bool can_cross_incognito) {
    263   ExtensionMenuItem::List result;
    264   for (ExtensionMenuItem::List::const_iterator i = items.begin();
    265        i != items.end(); ++i) {
    266     const ExtensionMenuItem* item = *i;
    267 
    268     if (!ExtensionContextMatch(params, item->contexts()))
    269       continue;
    270 
    271     const GURL& document_url = GetDocumentURL(params);
    272     if (!ExtensionPatternMatch(item->document_url_patterns(), document_url))
    273       continue;
    274 
    275     const GURL& target_url =
    276         params.src_url.is_empty() ? params.link_url : params.src_url;
    277     if (!ExtensionPatternMatch(item->target_url_patterns(), target_url))
    278       continue;
    279 
    280     if (item->id().profile == profile || can_cross_incognito)
    281       result.push_back(*i);
    282   }
    283   return result;
    284 }
    285 
    286 void RenderViewContextMenu::AppendExtensionItems(
    287     const std::string& extension_id, int* index) {
    288   ExtensionService* service = profile_->GetExtensionService();
    289   ExtensionMenuManager* manager = service->menu_manager();
    290   const Extension* extension = service->GetExtensionById(extension_id, false);
    291   DCHECK_GE(*index, 0);
    292   int max_index =
    293       IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST - IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST;
    294   if (!extension || *index >= max_index)
    295     return;
    296 
    297   // Find matching items.
    298   const ExtensionMenuItem::List* all_items = manager->MenuItems(extension_id);
    299   if (!all_items || all_items->empty())
    300     return;
    301   bool can_cross_incognito = service->CanCrossIncognito(extension);
    302   ExtensionMenuItem::List items =
    303       GetRelevantExtensionItems(*all_items, params_, profile_,
    304                                 can_cross_incognito);
    305   if (items.empty())
    306     return;
    307 
    308   // If this is the first extension-provided menu item, add a separator.
    309   if (*index == 0)
    310     menu_model_.AddSeparator();
    311 
    312   int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++;
    313 
    314   // Extensions are only allowed one top-level slot (and it can't be a radio or
    315   // checkbox item because we are going to put the extension icon next to it).
    316   // If they have more than that, we automatically push them into a submenu.
    317   string16 title;
    318   ExtensionMenuItem::List submenu_items;
    319   if (items.size() > 1 || items[0]->type() != ExtensionMenuItem::NORMAL) {
    320     title = UTF8ToUTF16(extension->name());
    321     submenu_items = items;
    322   } else {
    323     ExtensionMenuItem* item = items[0];
    324     extension_item_map_[menu_id] = item->id();
    325     title = item->TitleWithReplacement(PrintableSelectionText(),
    326                                        kMaxExtensionItemTitleLength);
    327     submenu_items = GetRelevantExtensionItems(item->children(), params_,
    328                                               profile_, can_cross_incognito);
    329   }
    330 
    331   // Now add our item(s) to the menu_model_.
    332   if (submenu_items.empty()) {
    333     menu_model_.AddItem(menu_id, title);
    334   } else {
    335     ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(this);
    336     extension_menu_models_.push_back(submenu);
    337     menu_model_.AddSubMenu(menu_id, title, submenu);
    338     RecursivelyAppendExtensionItems(submenu_items, can_cross_incognito, submenu,
    339                                     index);
    340   }
    341   SetExtensionIcon(extension_id);
    342 }
    343 
    344 void RenderViewContextMenu::RecursivelyAppendExtensionItems(
    345     const ExtensionMenuItem::List& items,
    346     bool can_cross_incognito,
    347     ui::SimpleMenuModel* menu_model,
    348     int *index) {
    349   string16 selection_text = PrintableSelectionText();
    350   ExtensionMenuItem::Type last_type = ExtensionMenuItem::NORMAL;
    351   int radio_group_id = 1;
    352 
    353   for (ExtensionMenuItem::List::const_iterator i = items.begin();
    354        i != items.end(); ++i) {
    355     ExtensionMenuItem* item = *i;
    356 
    357     // If last item was of type radio but the current one isn't, auto-insert
    358     // a separator.  The converse case is handled below.
    359     if (last_type == ExtensionMenuItem::RADIO &&
    360         item->type() != ExtensionMenuItem::RADIO) {
    361       menu_model->AddSeparator();
    362       last_type = ExtensionMenuItem::SEPARATOR;
    363     }
    364 
    365     int menu_id = IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + (*index)++;
    366     if (menu_id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST)
    367       return;
    368     extension_item_map_[menu_id] = item->id();
    369     string16 title = item->TitleWithReplacement(selection_text,
    370                                                 kMaxExtensionItemTitleLength);
    371     if (item->type() == ExtensionMenuItem::NORMAL) {
    372       ExtensionMenuItem::List children =
    373           GetRelevantExtensionItems(item->children(), params_,
    374                                     profile_, can_cross_incognito);
    375       if (children.empty()) {
    376         menu_model->AddItem(menu_id, title);
    377       } else {
    378         ui::SimpleMenuModel* submenu = new ui::SimpleMenuModel(this);
    379         extension_menu_models_.push_back(submenu);
    380         menu_model->AddSubMenu(menu_id, title, submenu);
    381         RecursivelyAppendExtensionItems(children, can_cross_incognito,
    382                                         submenu, index);
    383       }
    384     } else if (item->type() == ExtensionMenuItem::CHECKBOX) {
    385       menu_model->AddCheckItem(menu_id, title);
    386     } else if (item->type() == ExtensionMenuItem::RADIO) {
    387       if (i != items.begin() &&
    388           last_type != ExtensionMenuItem::RADIO) {
    389         radio_group_id++;
    390 
    391         // Auto-append a separator if needed.
    392         if (last_type != ExtensionMenuItem::SEPARATOR)
    393           menu_model->AddSeparator();
    394       }
    395 
    396       menu_model->AddRadioItem(menu_id, title, radio_group_id);
    397     } else if (item->type() == ExtensionMenuItem::SEPARATOR) {
    398       if (i != items.begin() && last_type != ExtensionMenuItem::SEPARATOR) {
    399         menu_model->AddSeparator();
    400       }
    401     }
    402     last_type = item->type();
    403   }
    404 }
    405 
    406 void RenderViewContextMenu::SetExtensionIcon(const std::string& extension_id) {
    407   ExtensionService* service = profile_->GetExtensionService();
    408   ExtensionMenuManager* menu_manager = service->menu_manager();
    409 
    410   int index = menu_model_.GetItemCount() - 1;
    411   DCHECK_GE(index, 0);
    412 
    413   const SkBitmap& icon = menu_manager->GetIconForExtension(extension_id);
    414   DCHECK(icon.width() == kFaviconSize);
    415   DCHECK(icon.height() == kFaviconSize);
    416 
    417   menu_model_.SetIcon(index, icon);
    418 }
    419 
    420 void RenderViewContextMenu::AppendAllExtensionItems() {
    421   extension_item_map_.clear();
    422   ExtensionService* service = profile_->GetExtensionService();
    423   if (!service)
    424     return;  // In unit-tests, we may not have an ExtensionService.
    425   ExtensionMenuManager* menu_manager = service->menu_manager();
    426   const GURL& document_url = GetDocumentURL(params_);
    427   if (!menu_manager->HasAllowedScheme(document_url))
    428     return;
    429 
    430   // Get a list of extension id's that have context menu items, and sort it by
    431   // the extension's name.
    432   std::set<std::string> ids = menu_manager->ExtensionIds();
    433   std::vector<std::pair<std::string, std::string> > sorted_ids;
    434   for (std::set<std::string>::iterator i = ids.begin(); i != ids.end(); ++i) {
    435     const Extension* extension = service->GetExtensionById(*i, false);
    436     if (extension)
    437       sorted_ids.push_back(
    438           std::pair<std::string, std::string>(extension->name(), *i));
    439   }
    440   // TODO(asargent) - See if this works properly for i18n names (bug 32363).
    441   std::sort(sorted_ids.begin(), sorted_ids.end());
    442 
    443   if (sorted_ids.empty())
    444     return;
    445 
    446   int index = 0;
    447   base::TimeTicks begin = base::TimeTicks::Now();
    448   std::vector<std::pair<std::string, std::string> >::const_iterator i;
    449   for (i = sorted_ids.begin();
    450        i != sorted_ids.end(); ++i) {
    451     AppendExtensionItems(i->second, &index);
    452   }
    453   UMA_HISTOGRAM_TIMES("Extensions.ContextMenus_BuildTime",
    454                       base::TimeTicks::Now() - begin);
    455   UMA_HISTOGRAM_COUNTS("Extensions.ContextMenus_ItemCount", index);
    456 }
    457 
    458 void RenderViewContextMenu::InitMenu() {
    459   bool has_link = !params_.link_url.is_empty();
    460   bool has_selection = !params_.selection_text.empty();
    461 
    462   if (AppendCustomItems()) {
    463     // Don't add items for Pepper menu.
    464     if (!params_.custom_context.is_pepper_menu)
    465       AppendDeveloperItems();
    466     return;
    467   }
    468 
    469   // When no special node or text is selected and selection has no link,
    470   // show page items.
    471   bool is_devtools = false;
    472   if (params_.media_type == WebContextMenuData::MediaTypeNone &&
    473       !has_link &&
    474       !params_.is_editable &&
    475       !has_selection) {
    476     if (!params_.page_url.is_empty()) {
    477       is_devtools = IsDevToolsURL(params_.page_url);
    478       if (!is_devtools && !IsInternalResourcesURL(params_.page_url)) {
    479         AppendPageItems();
    480         // Merge in frame items if we clicked within a frame that needs them.
    481         if (!params_.frame_url.is_empty()) {
    482           is_devtools = IsDevToolsURL(params_.frame_url);
    483           if (!is_devtools && !IsInternalResourcesURL(params_.frame_url)) {
    484             menu_model_.AddSeparator();
    485             AppendFrameItems();
    486           }
    487         }
    488       }
    489     } else {
    490       DCHECK(params_.frame_url.is_empty());
    491     }
    492   }
    493 
    494   if (has_link) {
    495     AppendLinkItems();
    496     if (params_.media_type != WebContextMenuData::MediaTypeNone)
    497       menu_model_.AddSeparator();
    498   }
    499 
    500   switch (params_.media_type) {
    501     case WebContextMenuData::MediaTypeNone:
    502       break;
    503     case WebContextMenuData::MediaTypeImage:
    504       AppendImageItems();
    505       break;
    506     case WebContextMenuData::MediaTypeVideo:
    507       AppendVideoItems();
    508       break;
    509     case WebContextMenuData::MediaTypeAudio:
    510       AppendAudioItems();
    511       break;
    512     case WebContextMenuData::MediaTypePlugin:
    513       AppendPluginItems();
    514       break;
    515 #ifdef WEBCONTEXT_MEDIATYPEFILE_DEFINED
    516     case WebContextMenuData::MediaTypeFile:
    517       break;
    518 #endif
    519   }
    520 
    521   if (params_.is_editable)
    522     AppendEditableItems();
    523   else if (has_selection)
    524     AppendCopyItem();
    525 
    526   if (has_selection)
    527     AppendSearchProvider();
    528 
    529   if (!is_devtools)
    530     AppendAllExtensionItems();
    531 
    532   AppendDeveloperItems();
    533 }
    534 
    535 void RenderViewContextMenu::LookUpInDictionary() {
    536   // Used only in the Mac port.
    537   NOTREACHED();
    538 }
    539 
    540 bool RenderViewContextMenu::AppendCustomItems() {
    541   size_t total_items = 0;
    542   AddCustomItemsToMenu(params_.custom_items, 0, &total_items, this,
    543                        &menu_model_);
    544   return total_items > 0;
    545 }
    546 
    547 void RenderViewContextMenu::AppendDeveloperItems() {
    548   // In the DevTools popup menu, "developer items" is normally the only
    549   // section, so omit the separator there.
    550   if (menu_model_.GetItemCount() > 0)
    551     menu_model_.AddSeparator();
    552   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTELEMENT,
    553                                   IDS_CONTENT_CONTEXT_INSPECTELEMENT);
    554 }
    555 
    556 void RenderViewContextMenu::AppendLinkItems() {
    557   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB,
    558                                   IDS_CONTENT_CONTEXT_OPENLINKNEWTAB);
    559   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW,
    560                                   IDS_CONTENT_CONTEXT_OPENLINKNEWWINDOW);
    561   if (!external_) {
    562     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD,
    563                                     IDS_CONTENT_CONTEXT_OPENLINKOFFTHERECORD);
    564   }
    565   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVELINKAS,
    566                                   IDS_CONTENT_CONTEXT_SAVELINKAS);
    567 
    568   menu_model_.AddItemWithStringId(
    569       IDC_CONTENT_CONTEXT_COPYLINKLOCATION,
    570       params_.link_url.SchemeIs(chrome::kMailToScheme) ?
    571           IDS_CONTENT_CONTEXT_COPYEMAILADDRESS :
    572           IDS_CONTENT_CONTEXT_COPYLINKLOCATION);
    573 }
    574 
    575 void RenderViewContextMenu::AppendImageItems() {
    576   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEIMAGEAS,
    577                                   IDS_CONTENT_CONTEXT_SAVEIMAGEAS);
    578   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGELOCATION,
    579                                   IDS_CONTENT_CONTEXT_COPYIMAGELOCATION);
    580   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
    581                                   IDS_CONTENT_CONTEXT_COPYIMAGE);
    582   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB,
    583                                   IDS_CONTENT_CONTEXT_OPENIMAGENEWTAB);
    584 }
    585 
    586 void RenderViewContextMenu::AppendAudioItems() {
    587   AppendMediaItems();
    588   menu_model_.AddSeparator();
    589   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
    590                                   IDS_CONTENT_CONTEXT_SAVEAUDIOAS);
    591   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
    592                                   IDS_CONTENT_CONTEXT_COPYAUDIOLOCATION);
    593   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
    594                                   IDS_CONTENT_CONTEXT_OPENAUDIONEWTAB);
    595 }
    596 
    597 void RenderViewContextMenu::AppendVideoItems() {
    598   AppendMediaItems();
    599   menu_model_.AddSeparator();
    600   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
    601                                   IDS_CONTENT_CONTEXT_SAVEVIDEOAS);
    602   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYAVLOCATION,
    603                                   IDS_CONTENT_CONTEXT_COPYVIDEOLOCATION);
    604   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENAVNEWTAB,
    605                                   IDS_CONTENT_CONTEXT_OPENVIDEONEWTAB);
    606 }
    607 
    608 void RenderViewContextMenu::AppendMediaItems() {
    609   int media_flags = params_.media_flags;
    610 
    611   menu_model_.AddItemWithStringId(
    612       IDC_CONTENT_CONTEXT_PLAYPAUSE,
    613       media_flags & WebContextMenuData::MediaPaused ?
    614           IDS_CONTENT_CONTEXT_PLAY :
    615           IDS_CONTENT_CONTEXT_PAUSE);
    616 
    617   menu_model_.AddItemWithStringId(
    618       IDC_CONTENT_CONTEXT_MUTE,
    619       media_flags & WebContextMenuData::MediaMuted ?
    620           IDS_CONTENT_CONTEXT_UNMUTE :
    621           IDS_CONTENT_CONTEXT_MUTE);
    622 
    623   menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_LOOP,
    624                                        IDS_CONTENT_CONTEXT_LOOP);
    625   menu_model_.AddCheckItemWithStringId(IDC_CONTENT_CONTEXT_CONTROLS,
    626                                        IDS_CONTENT_CONTEXT_CONTROLS);
    627 }
    628 
    629 void RenderViewContextMenu::AppendPluginItems() {
    630   if (params_.page_url == params_.src_url) {
    631     // Full page plugin, so show page menu items.
    632     if (params_.link_url.is_empty() && params_.selection_text.empty())
    633       AppendPageItems();
    634   } else {
    635     menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SAVEAVAS,
    636                                     IDS_CONTENT_CONTEXT_SAVEPAGEAS);
    637     menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
    638   }
    639 }
    640 
    641 void RenderViewContextMenu::AppendPageItems() {
    642   menu_model_.AddItemWithStringId(IDC_BACK, IDS_CONTENT_CONTEXT_BACK);
    643   menu_model_.AddItemWithStringId(IDC_FORWARD, IDS_CONTENT_CONTEXT_FORWARD);
    644   menu_model_.AddItemWithStringId(IDC_RELOAD, IDS_CONTENT_CONTEXT_RELOAD);
    645   menu_model_.AddSeparator();
    646   menu_model_.AddItemWithStringId(IDC_SAVE_PAGE,
    647                                   IDS_CONTENT_CONTEXT_SAVEPAGEAS);
    648   menu_model_.AddItemWithStringId(IDC_PRINT, IDS_CONTENT_CONTEXT_PRINT);
    649 
    650   std::string locale = g_browser_process->GetApplicationLocale();
    651   locale = TranslateManager::GetLanguageCode(locale);
    652   string16 language = l10n_util::GetDisplayNameForLocale(locale, locale, true);
    653   menu_model_.AddItem(
    654       IDC_CONTENT_CONTEXT_TRANSLATE,
    655       l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_TRANSLATE, language));
    656 
    657   menu_model_.AddItemWithStringId(IDC_VIEW_SOURCE,
    658                                   IDS_CONTENT_CONTEXT_VIEWPAGESOURCE);
    659   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWPAGEINFO,
    660                                   IDS_CONTENT_CONTEXT_VIEWPAGEINFO);
    661 }
    662 
    663 void RenderViewContextMenu::AppendFrameItems() {
    664   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOADFRAME,
    665                                   IDS_CONTENT_CONTEXT_RELOADFRAME);
    666   // These two menu items have yet to be implemented.
    667   // http://code.google.com/p/chromium/issues/detail?id=11827
    668   //   IDS_CONTENT_CONTEXT_SAVEFRAMEAS
    669   //   IDS_CONTENT_CONTEXT_PRINTFRAME
    670   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE,
    671                                   IDS_CONTENT_CONTEXT_VIEWFRAMESOURCE);
    672   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_VIEWFRAMEINFO,
    673                                   IDS_CONTENT_CONTEXT_VIEWFRAMEINFO);
    674 }
    675 
    676 void RenderViewContextMenu::AppendCopyItem() {
    677   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
    678                                   IDS_CONTENT_CONTEXT_COPY);
    679 }
    680 
    681 void RenderViewContextMenu::AppendSearchProvider() {
    682   DCHECK(profile_);
    683 
    684   TrimWhitespace(params_.selection_text, TRIM_ALL, &params_.selection_text);
    685   if (params_.selection_text.empty())
    686     return;
    687 
    688   AutocompleteMatch match;
    689   profile_->GetAutocompleteClassifier()->Classify(
    690       params_.selection_text, string16(), false, &match, NULL);
    691   selection_navigation_url_ = match.destination_url;
    692   if (!selection_navigation_url_.is_valid())
    693     return;
    694 
    695   string16 printable_selection_text = PrintableSelectionText();
    696   // Escape "&" as "&&".
    697   for (size_t i = printable_selection_text.find('&'); i != string16::npos;
    698        i = printable_selection_text.find('&', i + 2))
    699     printable_selection_text.insert(i, 1, '&');
    700 
    701   if (match.transition == PageTransition::TYPED) {
    702     if (ChildProcessSecurityPolicy::GetInstance()->IsWebSafeScheme(
    703         selection_navigation_url_.scheme())) {
    704       menu_model_.AddItem(
    705           IDC_CONTENT_CONTEXT_GOTOURL,
    706           l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_GOTOURL,
    707                                      printable_selection_text));
    708     }
    709   } else {
    710     const TemplateURL* const default_provider =
    711         profile_->GetTemplateURLModel()->GetDefaultSearchProvider();
    712     if (!default_provider)
    713       return;
    714     menu_model_.AddItem(
    715         IDC_CONTENT_CONTEXT_SEARCHWEBFOR,
    716         l10n_util::GetStringFUTF16(IDS_CONTENT_CONTEXT_SEARCHWEBFOR,
    717                                    default_provider->short_name(),
    718                                    printable_selection_text));
    719   }
    720 }
    721 
    722 void RenderViewContextMenu::AppendEditableItems() {
    723   // Append Dictionary spell check suggestions.
    724   for (size_t i = 0; i < params_.dictionary_suggestions.size() &&
    725        IDC_SPELLCHECK_SUGGESTION_0 + i <= IDC_SPELLCHECK_SUGGESTION_LAST;
    726        ++i) {
    727     menu_model_.AddItem(IDC_SPELLCHECK_SUGGESTION_0 + static_cast<int>(i),
    728                         params_.dictionary_suggestions[i]);
    729   }
    730   if (!params_.dictionary_suggestions.empty())
    731     menu_model_.AddSeparator();
    732 
    733   // If word is misspelled, give option for "Add to dictionary"
    734   if (!params_.misspelled_word.empty()) {
    735     if (params_.dictionary_suggestions.empty()) {
    736       menu_model_.AddItem(0,
    737           l10n_util::GetStringUTF16(
    738               IDS_CONTENT_CONTEXT_NO_SPELLING_SUGGESTIONS));
    739     }
    740     menu_model_.AddItemWithStringId(IDC_SPELLCHECK_ADD_TO_DICTIONARY,
    741                                     IDS_CONTENT_CONTEXT_ADD_TO_DICTIONARY);
    742     menu_model_.AddSeparator();
    743   }
    744 
    745   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_UNDO,
    746                                   IDS_CONTENT_CONTEXT_UNDO);
    747   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_REDO,
    748                                   IDS_CONTENT_CONTEXT_REDO);
    749   menu_model_.AddSeparator();
    750   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_CUT,
    751                                   IDS_CONTENT_CONTEXT_CUT);
    752   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPY,
    753                                   IDS_CONTENT_CONTEXT_COPY);
    754   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_PASTE,
    755                                   IDS_CONTENT_CONTEXT_PASTE);
    756   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_DELETE,
    757                                   IDS_CONTENT_CONTEXT_DELETE);
    758   menu_model_.AddSeparator();
    759 
    760   AppendSpellcheckOptionsSubMenu();
    761 
    762 #if defined(OS_MACOSX)
    763   // OS X provides a contextual menu to set writing direction for BiDi
    764   // languages.
    765   // This functionality is exposed as a keyboard shortcut on Windows & Linux.
    766   AppendBidiSubMenu();
    767 #endif  // OS_MACOSX
    768 
    769   menu_model_.AddSeparator();
    770   menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_SELECTALL,
    771                                   IDS_CONTENT_CONTEXT_SELECTALL);
    772 }
    773 
    774 void RenderViewContextMenu::AppendSpellcheckOptionsSubMenu() {
    775   // Add Spell Check languages to sub menu.
    776   std::vector<std::string> spellcheck_languages;
    777   SpellCheckHost::GetSpellCheckLanguages(profile_,
    778       &spellcheck_languages);
    779   DCHECK(spellcheck_languages.size() <
    780          IDC_SPELLCHECK_LANGUAGES_LAST - IDC_SPELLCHECK_LANGUAGES_FIRST);
    781   const std::string app_locale = g_browser_process->GetApplicationLocale();
    782   for (size_t i = 0; i < spellcheck_languages.size(); ++i) {
    783     string16 display_name(l10n_util::GetDisplayNameForLocale(
    784         spellcheck_languages[i], app_locale, true));
    785     spellcheck_submenu_model_.AddRadioItem(
    786         IDC_SPELLCHECK_LANGUAGES_FIRST + i,
    787         display_name,
    788         kSpellcheckRadioGroup);
    789   }
    790 
    791   // Add item in the sub menu to pop up the fonts and languages options menu.
    792   spellcheck_submenu_model_.AddSeparator();
    793   spellcheck_submenu_model_.AddItemWithStringId(
    794       IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS,
    795       IDS_CONTENT_CONTEXT_LANGUAGE_SETTINGS);
    796 
    797   // Add 'Check the spelling of this field' item in the sub menu.
    798   spellcheck_submenu_model_.AddCheckItem(
    799       IDC_CHECK_SPELLING_OF_THIS_FIELD,
    800       l10n_util::GetStringUTF16(
    801           IDS_CONTENT_CONTEXT_CHECK_SPELLING_OF_THIS_FIELD));
    802 
    803   // Add option for showing the spelling panel if the platform spellchecker
    804   // supports it.
    805   if (SpellCheckerPlatform::SpellCheckerAvailable() &&
    806       SpellCheckerPlatform::SpellCheckerProvidesPanel()) {
    807     spellcheck_submenu_model_.AddCheckItem(
    808         IDC_SPELLPANEL_TOGGLE,
    809         l10n_util::GetStringUTF16(
    810             SpellCheckerPlatform::SpellingPanelVisible() ?
    811                 IDS_CONTENT_CONTEXT_HIDE_SPELLING_PANEL :
    812                 IDS_CONTENT_CONTEXT_SHOW_SPELLING_PANEL));
    813   }
    814 
    815   menu_model_.AddSubMenu(
    816       IDC_SPELLCHECK_MENU,
    817       l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_SPELLCHECK_MENU),
    818       &spellcheck_submenu_model_);
    819 }
    820 
    821 #if defined(OS_MACOSX)
    822 void RenderViewContextMenu::AppendBidiSubMenu() {
    823   bidi_submenu_model_.AddCheckItem(IDC_WRITING_DIRECTION_DEFAULT,
    824       l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_DEFAULT));
    825   bidi_submenu_model_.AddCheckItem(IDC_WRITING_DIRECTION_LTR,
    826       l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_LTR));
    827   bidi_submenu_model_.AddCheckItem(IDC_WRITING_DIRECTION_RTL,
    828       l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_RTL));
    829 
    830   menu_model_.AddSubMenu(
    831       IDC_WRITING_DIRECTION_MENU,
    832       l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_WRITING_DIRECTION_MENU),
    833       &bidi_submenu_model_);
    834 }
    835 #endif  // OS_MACOSX
    836 
    837 ExtensionMenuItem* RenderViewContextMenu::GetExtensionMenuItem(int id) const {
    838   ExtensionMenuManager* manager =
    839       profile_->GetExtensionService()->menu_manager();
    840   std::map<int, ExtensionMenuItem::Id>::const_iterator i =
    841       extension_item_map_.find(id);
    842   if (i != extension_item_map_.end()) {
    843     ExtensionMenuItem* item = manager->GetItemById(i->second);
    844     if (item)
    845       return item;
    846   }
    847   return NULL;
    848 }
    849 
    850 // Menu delegate functions -----------------------------------------------------
    851 
    852 bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
    853   if (id == IDC_PRINT &&
    854       (source_tab_contents_->content_restrictions() &
    855           CONTENT_RESTRICTION_PRINT)) {
    856     return false;
    857   }
    858 
    859   if (id == IDC_SAVE_PAGE &&
    860       (source_tab_contents_->content_restrictions() &
    861           CONTENT_RESTRICTION_SAVE)) {
    862     return false;
    863   }
    864 
    865   // Allow Spell Check language items on sub menu for text area context menu.
    866   if ((id >= IDC_SPELLCHECK_LANGUAGES_FIRST) &&
    867       (id < IDC_SPELLCHECK_LANGUAGES_LAST)) {
    868     return profile_->GetPrefs()->GetBoolean(prefs::kEnableSpellCheck);
    869   }
    870 
    871   // Custom items.
    872   if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
    873       id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) {
    874     return IsCustomItemEnabled(params_.custom_items, id);
    875   }
    876 
    877   // Extension items.
    878   if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
    879       id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
    880     // In the future we may add APIs for extensions to disable items, but for
    881     // now all items are implicitly enabled.
    882     return true;
    883   }
    884 
    885   switch (id) {
    886     case IDC_BACK:
    887       return source_tab_contents_->controller().CanGoBack();
    888 
    889     case IDC_FORWARD:
    890       return source_tab_contents_->controller().CanGoForward();
    891 
    892     case IDC_RELOAD:
    893       return source_tab_contents_->delegate() &&
    894           source_tab_contents_->delegate()->CanReloadContents(
    895               source_tab_contents_);
    896 
    897     case IDC_VIEW_SOURCE:
    898     case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
    899       return source_tab_contents_->controller().CanViewSource();
    900 
    901     case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
    902     // Viewing page info is not a developer command but is meaningful for the
    903     // same set of pages which developer commands are meaningful for.
    904     case IDC_CONTENT_CONTEXT_VIEWPAGEINFO:
    905       return IsDevCommandEnabled(id);
    906 
    907     case IDC_CONTENT_CONTEXT_TRANSLATE: {
    908       TranslateTabHelper* helper =
    909           TabContentsWrapper::GetCurrentWrapperForContents(
    910               source_tab_contents_)->translate_tab_helper();
    911       std::string original_lang =
    912           helper->language_state().original_language();
    913       std::string target_lang = g_browser_process->GetApplicationLocale();
    914       target_lang = TranslateManager::GetLanguageCode(target_lang);
    915       // Note that we intentionally enable the menu even if the original and
    916       // target languages are identical.  This is to give a way to user to
    917       // translate a page that might contains text fragments in a different
    918       // language.
    919       return !!(params_.edit_flags & WebContextMenuData::CanTranslate) &&
    920              helper->language_state().page_translatable() &&
    921              !original_lang.empty() &&  // Did we receive the page language yet?
    922              // Only allow translating languages we explitly support and the
    923              // unknown language (in which case the page language is detected on
    924              // the server side).
    925              (original_lang == chrome::kUnknownLanguageCode ||
    926                  TranslateManager::IsSupportedLanguage(original_lang)) &&
    927              !helper->language_state().IsPageTranslated() &&
    928              !source_tab_contents_->interstitial_page() &&
    929              TranslateManager::IsTranslatableURL(params_.page_url);
    930     }
    931 
    932     case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB:
    933     case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
    934       return params_.link_url.is_valid();
    935 
    936     case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
    937       return params_.unfiltered_link_url.is_valid();
    938 
    939     case IDC_CONTENT_CONTEXT_SAVELINKAS:
    940       return params_.link_url.is_valid() &&
    941              net::URLRequest::IsHandledURL(params_.link_url);
    942 
    943     case IDC_CONTENT_CONTEXT_SAVEIMAGEAS:
    944       return params_.src_url.is_valid() &&
    945              net::URLRequest::IsHandledURL(params_.src_url);
    946 
    947     case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
    948       // The images shown in the most visited thumbnails do not currently open
    949       // in a new tab as they should. Disabling this context menu option for
    950       // now, as a quick hack, before we resolve this issue (Issue = 2608).
    951       // TODO(sidchat): Enable this option once this issue is resolved.
    952       if (params_.src_url.scheme() == chrome::kChromeUIScheme ||
    953           !params_.src_url.is_valid())
    954         return false;
    955       return true;
    956 
    957     case IDC_CONTENT_CONTEXT_COPYIMAGE:
    958       return !params_.is_image_blocked;
    959 
    960     // Media control commands should all be disabled if the player is in an
    961     // error state.
    962     case IDC_CONTENT_CONTEXT_PLAYPAUSE:
    963     case IDC_CONTENT_CONTEXT_LOOP:
    964       return (params_.media_flags &
    965               WebContextMenuData::MediaInError) == 0;
    966 
    967     // Mute and unmute should also be disabled if the player has no audio.
    968     case IDC_CONTENT_CONTEXT_MUTE:
    969       return (params_.media_flags &
    970               WebContextMenuData::MediaHasAudio) != 0 &&
    971              (params_.media_flags &
    972               WebContextMenuData::MediaInError) == 0;
    973 
    974     // Media controls can be toggled only for video player. If we toggle
    975     // controls for audio then the player disappears, and there is no way to
    976     // return it back.
    977     case IDC_CONTENT_CONTEXT_CONTROLS:
    978       return (params_.media_flags &
    979               WebContextMenuData::MediaHasVideo) != 0;
    980 
    981     case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
    982     case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
    983       return params_.src_url.is_valid();
    984 
    985     case IDC_CONTENT_CONTEXT_SAVEAVAS:
    986       return (params_.media_flags &
    987               WebContextMenuData::MediaCanSave) &&
    988              params_.src_url.is_valid() &&
    989              net::URLRequest::IsHandledURL(params_.src_url);
    990 
    991     case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
    992       return true;
    993 
    994     case IDC_SAVE_PAGE: {
    995       // Instead of using GetURL here, we use url() (which is the "real" url of
    996       // the page) from the NavigationEntry because its reflects their origin
    997       // rather than the display one (returned by GetURL) which may be
    998       // different (like having "view-source:" on the front).
    999       NavigationEntry* active_entry =
   1000           source_tab_contents_->controller().GetActiveEntry();
   1001       return SavePackage::IsSavableURL(
   1002           (active_entry) ? active_entry->url() : GURL());
   1003     }
   1004 
   1005     case IDC_CONTENT_CONTEXT_RELOADFRAME:
   1006       return params_.frame_url.is_valid();
   1007 
   1008     case IDC_CONTENT_CONTEXT_UNDO:
   1009       return !!(params_.edit_flags & WebContextMenuData::CanUndo);
   1010 
   1011     case IDC_CONTENT_CONTEXT_REDO:
   1012       return !!(params_.edit_flags & WebContextMenuData::CanRedo);
   1013 
   1014     case IDC_CONTENT_CONTEXT_CUT:
   1015       return !!(params_.edit_flags & WebContextMenuData::CanCut);
   1016 
   1017     case IDC_CONTENT_CONTEXT_COPY:
   1018       return !!(params_.edit_flags & WebContextMenuData::CanCopy);
   1019 
   1020     case IDC_CONTENT_CONTEXT_PASTE:
   1021       return !!(params_.edit_flags & WebContextMenuData::CanPaste);
   1022 
   1023     case IDC_CONTENT_CONTEXT_DELETE:
   1024       return !!(params_.edit_flags & WebContextMenuData::CanDelete);
   1025 
   1026     case IDC_CONTENT_CONTEXT_SELECTALL:
   1027       return !!(params_.edit_flags & WebContextMenuData::CanSelectAll);
   1028 
   1029     case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
   1030       return !profile_->IsOffTheRecord() && params_.link_url.is_valid() &&
   1031              profile_->GetPrefs()->GetBoolean(prefs::kIncognitoEnabled);
   1032 
   1033     case IDC_SPELLCHECK_ADD_TO_DICTIONARY:
   1034       return !params_.misspelled_word.empty();
   1035 
   1036     case IDC_PRINT:
   1037       if (g_browser_process->local_state() &&
   1038           !g_browser_process->local_state()->GetBoolean(
   1039               prefs::kPrintingEnabled)) {
   1040         return false;
   1041       }
   1042       return params_.media_type == WebContextMenuData::MediaTypeNone ||
   1043              params_.media_flags & WebContextMenuData::MediaCanPrint;
   1044 
   1045     case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
   1046     case IDC_CONTENT_CONTEXT_GOTOURL:
   1047     case IDC_SPELLCHECK_SUGGESTION_0:
   1048     case IDC_SPELLCHECK_SUGGESTION_1:
   1049     case IDC_SPELLCHECK_SUGGESTION_2:
   1050     case IDC_SPELLCHECK_SUGGESTION_3:
   1051     case IDC_SPELLCHECK_SUGGESTION_4:
   1052     case IDC_SPELLPANEL_TOGGLE:
   1053 #if !defined(OS_MACOSX)
   1054     // TODO(jeremy): re-enable - http://crbug.com/34512 .
   1055     case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS:
   1056 #endif
   1057     case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO:
   1058       return true;
   1059 
   1060     case IDC_CHECK_SPELLING_OF_THIS_FIELD:
   1061       return profile_->GetPrefs()->GetBoolean(prefs::kEnableSpellCheck);
   1062 
   1063 #if defined(OS_MACOSX)
   1064     // TODO(jeremy): re-enable - http://crbug.com/34512 .
   1065     case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS:
   1066       return false;
   1067 #endif
   1068 
   1069 #if defined(OS_MACOSX)
   1070     case IDC_WRITING_DIRECTION_DEFAULT:  // Provided to match OS defaults.
   1071       return params_.writing_direction_default &
   1072           WebContextMenuData::CheckableMenuItemEnabled;
   1073     case IDC_WRITING_DIRECTION_RTL:
   1074       return params_.writing_direction_right_to_left &
   1075           WebContextMenuData::CheckableMenuItemEnabled;
   1076     case IDC_WRITING_DIRECTION_LTR:
   1077       return params_.writing_direction_left_to_right &
   1078           WebContextMenuData::CheckableMenuItemEnabled;
   1079     case IDC_WRITING_DIRECTION_MENU:
   1080       return true;
   1081     case IDC_CONTENT_CONTEXT_LOOK_UP_IN_DICTIONARY:
   1082       // This is OK because the menu is not shown when it isn't
   1083       // appropriate.
   1084       return true;
   1085 #elif defined(OS_POSIX)
   1086     // TODO(suzhe): this should not be enabled for password fields.
   1087     case IDC_INPUT_METHODS_MENU:
   1088       return true;
   1089 #endif
   1090 
   1091     case IDC_SPELLCHECK_MENU:
   1092       return true;
   1093 
   1094     default:
   1095       NOTREACHED();
   1096       return false;
   1097   }
   1098 }
   1099 
   1100 bool RenderViewContextMenu::IsCommandIdChecked(int id) const {
   1101   // See if the video is set to looping.
   1102   if (id == IDC_CONTENT_CONTEXT_LOOP) {
   1103     return (params_.media_flags &
   1104             WebContextMenuData::MediaLoop) != 0;
   1105   }
   1106 
   1107   if (id == IDC_CONTENT_CONTEXT_CONTROLS) {
   1108     return (params_.media_flags &
   1109             WebContextMenuData::MediaControlRootElement) != 0;
   1110   }
   1111 
   1112   // Custom items.
   1113   if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
   1114       id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) {
   1115     return IsCustomItemChecked(params_.custom_items, id);
   1116   }
   1117 
   1118   // Extension items.
   1119   if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
   1120       id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
   1121     ExtensionMenuItem* item = GetExtensionMenuItem(id);
   1122     if (item)
   1123       return item->checked();
   1124     else
   1125       return false;
   1126   }
   1127 
   1128 #if defined(OS_MACOSX)
   1129     if (id == IDC_WRITING_DIRECTION_DEFAULT)
   1130       return params_.writing_direction_default &
   1131           WebContextMenuData::CheckableMenuItemChecked;
   1132     if (id == IDC_WRITING_DIRECTION_RTL)
   1133       return params_.writing_direction_right_to_left &
   1134           WebContextMenuData::CheckableMenuItemChecked;
   1135     if (id == IDC_WRITING_DIRECTION_LTR)
   1136       return params_.writing_direction_left_to_right &
   1137           WebContextMenuData::CheckableMenuItemChecked;
   1138     if (id == IDC_CONTENT_CONTEXT_LOOK_UP_IN_DICTIONARY)
   1139       return false;
   1140 #endif  // OS_MACOSX
   1141 
   1142   // Check box for 'Check the Spelling of this field'.
   1143   if (id == IDC_CHECK_SPELLING_OF_THIS_FIELD) {
   1144     return (params_.spellcheck_enabled &&
   1145             profile_->GetPrefs()->GetBoolean(prefs::kEnableSpellCheck));
   1146   }
   1147 
   1148   // Don't bother getting the display language vector if this isn't a spellcheck
   1149   // language.
   1150   if ((id < IDC_SPELLCHECK_LANGUAGES_FIRST) ||
   1151       (id >= IDC_SPELLCHECK_LANGUAGES_LAST))
   1152     return false;
   1153 
   1154   std::vector<std::string> languages;
   1155   return SpellCheckHost::GetSpellCheckLanguages(profile_, &languages) ==
   1156       (id - IDC_SPELLCHECK_LANGUAGES_FIRST);
   1157 }
   1158 
   1159 void RenderViewContextMenu::ExecuteCommand(int id) {
   1160   // Check to see if one of the spell check language ids have been clicked.
   1161   if (id >= IDC_SPELLCHECK_LANGUAGES_FIRST &&
   1162       id < IDC_SPELLCHECK_LANGUAGES_LAST) {
   1163     const size_t language_number = id - IDC_SPELLCHECK_LANGUAGES_FIRST;
   1164     std::vector<std::string> languages;
   1165     SpellCheckHost::GetSpellCheckLanguages(profile_, &languages);
   1166     if (language_number < languages.size()) {
   1167       StringPrefMember dictionary_language;
   1168       dictionary_language.Init(prefs::kSpellCheckDictionary,
   1169           profile_->GetPrefs(), NULL);
   1170       dictionary_language.SetValue(languages[language_number]);
   1171     }
   1172     return;
   1173   }
   1174 
   1175   // Process custom actions range.
   1176   if (id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
   1177       id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) {
   1178     unsigned action = id - IDC_CONTENT_CONTEXT_CUSTOM_FIRST;
   1179     source_tab_contents_->render_view_host()->PerformCustomContextMenuAction(
   1180         params_.custom_context, action);
   1181     return;
   1182   }
   1183 
   1184   // Process extension menu items.
   1185   if (id >= IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST &&
   1186       id <= IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST) {
   1187     ExtensionMenuManager* manager =
   1188         profile_->GetExtensionService()->menu_manager();
   1189     std::map<int, ExtensionMenuItem::Id>::const_iterator i =
   1190         extension_item_map_.find(id);
   1191     if (i != extension_item_map_.end()) {
   1192       manager->ExecuteCommand(profile_, source_tab_contents_, params_,
   1193                               i->second);
   1194     }
   1195     return;
   1196   }
   1197 
   1198 
   1199   switch (id) {
   1200     case IDC_CONTENT_CONTEXT_OPENLINKNEWTAB:
   1201       OpenURL(params_.link_url,
   1202               source_tab_contents_->delegate() &&
   1203               source_tab_contents_->delegate()->IsApplication() ?
   1204                   NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB,
   1205               PageTransition::LINK);
   1206       break;
   1207 
   1208     case IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW:
   1209       OpenURL(params_.link_url, NEW_WINDOW, PageTransition::LINK);
   1210       break;
   1211 
   1212     case IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD:
   1213       OpenURL(params_.link_url, OFF_THE_RECORD, PageTransition::LINK);
   1214       break;
   1215 
   1216     case IDC_CONTENT_CONTEXT_SAVEAVAS:
   1217     case IDC_CONTENT_CONTEXT_SAVEIMAGEAS:
   1218     case IDC_CONTENT_CONTEXT_SAVELINKAS: {
   1219       download_util::RecordDownloadCount(
   1220           download_util::INITIATED_BY_CONTEXT_MENU_COUNT);
   1221       const GURL& referrer =
   1222           params_.frame_url.is_empty() ? params_.page_url : params_.frame_url;
   1223       const GURL& url =
   1224           (id == IDC_CONTENT_CONTEXT_SAVELINKAS ? params_.link_url :
   1225                                                   params_.src_url);
   1226       DownloadManager* dlm = profile_->GetDownloadManager();
   1227       dlm->DownloadUrl(url, referrer, params_.frame_charset,
   1228                        source_tab_contents_);
   1229       break;
   1230     }
   1231 
   1232     case IDC_CONTENT_CONTEXT_COPYLINKLOCATION:
   1233       WriteURLToClipboard(params_.unfiltered_link_url);
   1234       break;
   1235 
   1236     case IDC_CONTENT_CONTEXT_COPYIMAGELOCATION:
   1237     case IDC_CONTENT_CONTEXT_COPYAVLOCATION:
   1238       WriteURLToClipboard(params_.src_url);
   1239       break;
   1240 
   1241     case IDC_CONTENT_CONTEXT_COPYIMAGE:
   1242       CopyImageAt(params_.x, params_.y);
   1243       break;
   1244 
   1245     case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
   1246     case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
   1247       OpenURL(params_.src_url, NEW_BACKGROUND_TAB, PageTransition::LINK);
   1248       break;
   1249 
   1250     case IDC_CONTENT_CONTEXT_PLAYPAUSE: {
   1251       bool play = !!(params_.media_flags & WebContextMenuData::MediaPaused);
   1252       if (play) {
   1253         UserMetrics::RecordAction(UserMetricsAction("MediaContextMenu_Play"),
   1254                                   profile_);
   1255       } else {
   1256         UserMetrics::RecordAction(UserMetricsAction("MediaContextMenu_Pause"),
   1257                                   profile_);
   1258       }
   1259       MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
   1260                           WebMediaPlayerAction(
   1261                               WebMediaPlayerAction::Play, play));
   1262       break;
   1263     }
   1264 
   1265     case IDC_CONTENT_CONTEXT_MUTE: {
   1266       bool mute = !(params_.media_flags & WebContextMenuData::MediaMuted);
   1267       if (mute) {
   1268         UserMetrics::RecordAction(UserMetricsAction("MediaContextMenu_Mute"),
   1269                                   profile_);
   1270       } else {
   1271         UserMetrics::RecordAction(UserMetricsAction("MediaContextMenu_Unmute"),
   1272                                   profile_);
   1273       }
   1274       MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
   1275                           WebMediaPlayerAction(
   1276                               WebMediaPlayerAction::Mute, mute));
   1277       break;
   1278     }
   1279 
   1280     case IDC_CONTENT_CONTEXT_LOOP:
   1281       UserMetrics::RecordAction(UserMetricsAction("MediaContextMenu_Loop"),
   1282                                 profile_);
   1283       MediaPlayerActionAt(gfx::Point(params_.x, params_.y),
   1284                           WebMediaPlayerAction(
   1285                               WebMediaPlayerAction::Loop,
   1286                               !IsCommandIdChecked(IDC_CONTENT_CONTEXT_LOOP)));
   1287       break;
   1288 
   1289     case IDC_CONTENT_CONTEXT_CONTROLS:
   1290       UserMetrics::RecordAction(UserMetricsAction("MediaContextMenu_Controls"),
   1291                                 profile_);
   1292       MediaPlayerActionAt(
   1293           gfx::Point(params_.x, params_.y),
   1294           WebMediaPlayerAction(
   1295               WebMediaPlayerAction::Controls,
   1296               !IsCommandIdChecked(IDC_CONTENT_CONTEXT_CONTROLS)));
   1297       break;
   1298 
   1299     case IDC_BACK:
   1300       source_tab_contents_->controller().GoBack();
   1301       break;
   1302 
   1303     case IDC_FORWARD:
   1304       source_tab_contents_->controller().GoForward();
   1305       break;
   1306 
   1307     case IDC_SAVE_PAGE: {
   1308       TabContentsWrapper* wrapper =
   1309           TabContentsWrapper::GetCurrentWrapperForContents(
   1310               source_tab_contents_);
   1311       wrapper->download_tab_helper()->OnSavePage();
   1312       break;
   1313     }
   1314 
   1315     case IDC_RELOAD:
   1316       // Prevent the modal "Resubmit form post" dialog from appearing in the
   1317       // context of an external context menu.
   1318       source_tab_contents_->controller().Reload(!external_);
   1319       break;
   1320 
   1321     case IDC_PRINT:
   1322       if (params_.media_type == WebContextMenuData::MediaTypeNone) {
   1323         if (CommandLine::ForCurrentProcess()->HasSwitch(
   1324             switches::kEnablePrintPreview)) {
   1325           printing::PrintPreviewTabController::PrintPreview(
   1326               source_tab_contents_);
   1327         } else {
   1328           TabContentsWrapper* wrapper =
   1329               TabContentsWrapper::GetCurrentWrapperForContents(
   1330                   source_tab_contents_);
   1331           wrapper->print_view_manager()->PrintNow();
   1332         }
   1333       } else {
   1334         RenderViewHost* rvh = source_tab_contents_->render_view_host();
   1335         rvh->Send(new PrintMsg_PrintNodeUnderContextMenu(rvh->routing_id()));
   1336       }
   1337       break;
   1338 
   1339     case IDC_VIEW_SOURCE:
   1340       source_tab_contents_->ViewSource();
   1341       break;
   1342 
   1343     case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
   1344       Inspect(params_.x, params_.y);
   1345       break;
   1346 
   1347     case IDC_CONTENT_CONTEXT_VIEWPAGEINFO: {
   1348       NavigationEntry* nav_entry =
   1349           source_tab_contents_->controller().GetActiveEntry();
   1350       source_tab_contents_->ShowPageInfo(nav_entry->url(), nav_entry->ssl(),
   1351                                          true);
   1352       break;
   1353     }
   1354 
   1355     case IDC_CONTENT_CONTEXT_TRANSLATE: {
   1356       // A translation might have been triggered by the time the menu got
   1357       // selected, do nothing in that case.
   1358       TranslateTabHelper* helper =
   1359           TabContentsWrapper::GetCurrentWrapperForContents(
   1360               source_tab_contents_)->translate_tab_helper();
   1361       if (helper->language_state().IsPageTranslated() ||
   1362           helper->language_state().translation_pending()) {
   1363         return;
   1364       }
   1365       std::string original_lang = helper->language_state().original_language();
   1366       std::string target_lang = g_browser_process->GetApplicationLocale();
   1367       target_lang = TranslateManager::GetLanguageCode(target_lang);
   1368       // Since the user decided to translate for that language and site, clears
   1369       // any preferences for not translating them.
   1370       TranslatePrefs prefs(profile_->GetPrefs());
   1371       prefs.RemoveLanguageFromBlacklist(original_lang);
   1372       prefs.RemoveSiteFromBlacklist(params_.page_url.HostNoBrackets());
   1373       TranslateManager::GetInstance()->TranslatePage(
   1374           source_tab_contents_, original_lang, target_lang);
   1375       break;
   1376     }
   1377 
   1378     case IDC_CONTENT_CONTEXT_RELOADFRAME:
   1379       source_tab_contents_->render_view_host()->ReloadFrame();
   1380       break;
   1381 
   1382     case IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE:
   1383       source_tab_contents_->ViewFrameSource(params_.frame_url,
   1384                                             params_.frame_content_state);
   1385       break;
   1386 
   1387     case IDC_CONTENT_CONTEXT_VIEWFRAMEINFO: {
   1388       // Deserialize the SSL info.
   1389       NavigationEntry::SSLStatus ssl;
   1390       if (!params_.security_info.empty()) {
   1391         int cert_id, cert_status, security_bits, connection_status;
   1392         SSLManager::DeserializeSecurityInfo(params_.security_info,
   1393                                             &cert_id,
   1394                                             &cert_status,
   1395                                             &security_bits,
   1396                                             &connection_status);
   1397         ssl.set_cert_id(cert_id);
   1398         ssl.set_cert_status(cert_status);
   1399         ssl.set_security_bits(security_bits);
   1400         ssl.set_connection_status(connection_status);
   1401       }
   1402       source_tab_contents_->ShowPageInfo(params_.frame_url, ssl,
   1403                                          false);  // Don't show the history.
   1404       break;
   1405     }
   1406 
   1407     case IDC_CONTENT_CONTEXT_UNDO:
   1408       source_tab_contents_->render_view_host()->Undo();
   1409       break;
   1410 
   1411     case IDC_CONTENT_CONTEXT_REDO:
   1412       source_tab_contents_->render_view_host()->Redo();
   1413       break;
   1414 
   1415     case IDC_CONTENT_CONTEXT_CUT:
   1416       source_tab_contents_->render_view_host()->Cut();
   1417       break;
   1418 
   1419     case IDC_CONTENT_CONTEXT_COPY:
   1420       source_tab_contents_->render_view_host()->Copy();
   1421       break;
   1422 
   1423     case IDC_CONTENT_CONTEXT_PASTE:
   1424       source_tab_contents_->render_view_host()->Paste();
   1425       break;
   1426 
   1427     case IDC_CONTENT_CONTEXT_DELETE:
   1428       source_tab_contents_->render_view_host()->Delete();
   1429       break;
   1430 
   1431     case IDC_CONTENT_CONTEXT_SELECTALL:
   1432       source_tab_contents_->render_view_host()->SelectAll();
   1433       break;
   1434 
   1435     case IDC_CONTENT_CONTEXT_SEARCHWEBFOR:
   1436     case IDC_CONTENT_CONTEXT_GOTOURL: {
   1437       OpenURL(selection_navigation_url_, NEW_FOREGROUND_TAB,
   1438               PageTransition::LINK);
   1439       break;
   1440     }
   1441 
   1442     case IDC_SPELLCHECK_SUGGESTION_0:
   1443     case IDC_SPELLCHECK_SUGGESTION_1:
   1444     case IDC_SPELLCHECK_SUGGESTION_2:
   1445     case IDC_SPELLCHECK_SUGGESTION_3:
   1446     case IDC_SPELLCHECK_SUGGESTION_4:
   1447       source_tab_contents_->render_view_host()->Replace(
   1448           params_.dictionary_suggestions[id - IDC_SPELLCHECK_SUGGESTION_0]);
   1449       break;
   1450 
   1451     case IDC_CHECK_SPELLING_OF_THIS_FIELD:
   1452       source_tab_contents_->render_view_host()->ToggleSpellCheck();
   1453       break;
   1454     case IDC_SPELLCHECK_ADD_TO_DICTIONARY: {
   1455       SpellCheckHost* spellcheck_host = profile_->GetSpellCheckHost();
   1456       if (!spellcheck_host) {
   1457         NOTREACHED();
   1458         break;
   1459       }
   1460       spellcheck_host->AddWord(UTF16ToUTF8(params_.misspelled_word));
   1461       SpellCheckerPlatform::AddWord(params_.misspelled_word);
   1462       break;
   1463     }
   1464 
   1465     case IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS: {
   1466       std::string url = std::string(chrome::kChromeUISettingsURL) +
   1467           chrome::kLanguageOptionsSubPage;
   1468       OpenURL(GURL(url), NEW_FOREGROUND_TAB, PageTransition::LINK);
   1469       break;
   1470     }
   1471 
   1472     case IDC_SPELLPANEL_TOGGLE:
   1473       source_tab_contents_->render_view_host()->ToggleSpellPanel(
   1474           SpellCheckerPlatform::SpellingPanelVisible());
   1475       break;
   1476 
   1477 #if defined(OS_MACOSX)
   1478     case IDC_WRITING_DIRECTION_DEFAULT:
   1479       // WebKit's current behavior is for this menu item to always be disabled.
   1480       NOTREACHED();
   1481       break;
   1482     case IDC_WRITING_DIRECTION_RTL:
   1483     case IDC_WRITING_DIRECTION_LTR: {
   1484       WebKit::WebTextDirection dir = WebKit::WebTextDirectionLeftToRight;
   1485       if (id == IDC_WRITING_DIRECTION_RTL)
   1486         dir = WebKit::WebTextDirectionRightToLeft;
   1487       source_tab_contents_->render_view_host()->UpdateTextDirection(dir);
   1488       source_tab_contents_->render_view_host()->NotifyTextDirection();
   1489       break;
   1490     }
   1491     case IDC_CONTENT_CONTEXT_LOOK_UP_IN_DICTIONARY:
   1492       LookUpInDictionary();
   1493       break;
   1494 #endif  // OS_MACOSX
   1495 
   1496     default:
   1497       NOTREACHED();
   1498       break;
   1499   }
   1500 }
   1501 
   1502 void RenderViewContextMenu::MenuWillShow() {
   1503   RenderWidgetHostView* view = source_tab_contents_->GetRenderWidgetHostView();
   1504   if (view)
   1505     view->ShowingContextMenu(true);
   1506 }
   1507 
   1508 void RenderViewContextMenu::MenuClosed() {
   1509   RenderWidgetHostView* view = source_tab_contents_->GetRenderWidgetHostView();
   1510   if (view)
   1511     view->ShowingContextMenu(false);
   1512   if (source_tab_contents_->render_view_host()) {
   1513     source_tab_contents_->render_view_host()->ContextMenuClosed(
   1514         params_.custom_context);
   1515   }
   1516 }
   1517 
   1518 bool RenderViewContextMenu::IsDevCommandEnabled(int id) const {
   1519   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
   1520   if (command_line.HasSwitch(switches::kAlwaysEnableDevTools))
   1521     return true;
   1522 
   1523   NavigationEntry *active_entry =
   1524       source_tab_contents_->controller().GetActiveEntry();
   1525   if (!active_entry)
   1526     return false;
   1527 
   1528   // Don't inspect view source.
   1529   if (active_entry->IsViewSourceMode())
   1530     return false;
   1531 
   1532   // Don't inspect about:network, about:memory, etc.
   1533   // However, we do want to inspect about:blank, which is often
   1534   // used by ordinary web pages.
   1535   if (active_entry->virtual_url().SchemeIs(chrome::kAboutScheme) &&
   1536       !LowerCaseEqualsASCII(active_entry->virtual_url().path(), "blank"))
   1537     return false;
   1538 
   1539   if (id == IDC_CONTENT_CONTEXT_INSPECTELEMENT) {
   1540     // Don't enable the web inspector if JavaScript is disabled.
   1541     if (!profile_->GetPrefs()->GetBoolean(prefs::kWebKitJavascriptEnabled) ||
   1542         command_line.HasSwitch(switches::kDisableJavaScript))
   1543       return false;
   1544     // Don't enable the web inspector if the developer tools are disabled via
   1545     // the preference dev-tools-disabled.
   1546     if (profile_->GetPrefs()->GetBoolean(prefs::kDevToolsDisabled))
   1547       return false;
   1548   }
   1549 
   1550   return true;
   1551 }
   1552 
   1553 string16 RenderViewContextMenu::PrintableSelectionText() {
   1554   return l10n_util::TruncateString(params_.selection_text,
   1555                                    kMaxSelectionTextLength);
   1556 }
   1557 
   1558 // Controller functions --------------------------------------------------------
   1559 
   1560 void RenderViewContextMenu::OpenURL(
   1561     const GURL& url,
   1562     WindowOpenDisposition disposition,
   1563     PageTransition::Type transition) {
   1564   source_tab_contents_->OpenURL(url, GURL(), disposition, transition);
   1565 }
   1566 
   1567 void RenderViewContextMenu::CopyImageAt(int x, int y) {
   1568   source_tab_contents_->render_view_host()->CopyImageAt(x, y);
   1569 }
   1570 
   1571 void RenderViewContextMenu::Inspect(int x, int y) {
   1572   UserMetrics::RecordAction(UserMetricsAction("DevTools_InspectElement"),
   1573                             profile_);
   1574   DevToolsManager::GetInstance()->InspectElement(
   1575       source_tab_contents_->render_view_host(), x, y);
   1576 }
   1577 
   1578 void RenderViewContextMenu::WriteURLToClipboard(const GURL& url) {
   1579   chrome_browser_net::WriteURLToClipboard(
   1580       url,
   1581       profile_->GetPrefs()->GetString(prefs::kAcceptLanguages),
   1582       g_browser_process->clipboard());
   1583 }
   1584 
   1585 void RenderViewContextMenu::MediaPlayerActionAt(
   1586     const gfx::Point& location,
   1587     const WebMediaPlayerAction& action) {
   1588   source_tab_contents_->render_view_host()->MediaPlayerActionAt(
   1589       location, action);
   1590 }
   1591