Home | History | Annotate | Download | only in ui
      1 // Copyright (c) 2012 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/ui/browser_navigator.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/command_line.h"
     10 #include "base/prefs/pref_service.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "chrome/browser/browser_about_handler.h"
     14 #include "chrome/browser/chrome_notification_types.h"
     15 #include "chrome/browser/extensions/extension_service.h"
     16 #include "chrome/browser/extensions/tab_helper.h"
     17 #include "chrome/browser/google/google_url_tracker.h"
     18 #include "chrome/browser/prefs/incognito_mode_prefs.h"
     19 #include "chrome/browser/prerender/prerender_manager.h"
     20 #include "chrome/browser/prerender/prerender_manager_factory.h"
     21 #include "chrome/browser/prerender/prerender_util.h"
     22 #include "chrome/browser/profiles/profile.h"
     23 #include "chrome/browser/tab_contents/tab_util.h"
     24 #include "chrome/browser/ui/browser.h"
     25 #include "chrome/browser/ui/browser_finder.h"
     26 #include "chrome/browser/ui/browser_instant_controller.h"
     27 #include "chrome/browser/ui/browser_tab_contents.h"
     28 #include "chrome/browser/ui/browser_window.h"
     29 #include "chrome/browser/ui/host_desktop.h"
     30 #include "chrome/browser/ui/omnibox/location_bar.h"
     31 #include "chrome/browser/ui/search/instant_search_prerenderer.h"
     32 #include "chrome/browser/ui/singleton_tabs.h"
     33 #include "chrome/browser/ui/status_bubble.h"
     34 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     35 #include "chrome/browser/web_applications/web_app.h"
     36 #include "chrome/common/pref_names.h"
     37 #include "chrome/common/url_constants.h"
     38 #include "content/public/browser/browser_url_handler.h"
     39 #include "content/public/browser/navigation_entry.h"
     40 #include "content/public/browser/notification_service.h"
     41 #include "content/public/browser/render_view_host.h"
     42 #include "content/public/browser/web_contents.h"
     43 #include "content/public/browser/web_contents_view.h"
     44 #include "extensions/common/extension.h"
     45 
     46 #if defined(USE_ASH)
     47 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
     48 #endif
     49 #if defined(USE_AURA)
     50 #include "ui/aura/window.h"
     51 #endif
     52 
     53 using content::GlobalRequestID;
     54 using content::NavigationController;
     55 using content::WebContents;
     56 
     57 class BrowserNavigatorWebContentsAdoption {
     58  public:
     59   static void AttachTabHelpers(content::WebContents* contents) {
     60     BrowserTabContents::AttachTabHelpers(contents);
     61   }
     62 };
     63 
     64 namespace {
     65 
     66 // Returns true if the specified Browser can open tabs. Not all Browsers support
     67 // multiple tabs, such as app frames and popups. This function returns false for
     68 // those types of Browser.
     69 bool WindowCanOpenTabs(Browser* browser) {
     70   return browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP) ||
     71       browser->tab_strip_model()->empty();
     72 }
     73 
     74 // Finds an existing Browser compatible with |profile|, making a new one if no
     75 // such Browser is located.
     76 Browser* GetOrCreateBrowser(Profile* profile,
     77                             chrome::HostDesktopType host_desktop_type) {
     78   Browser* browser = chrome::FindTabbedBrowser(profile, false,
     79                                                host_desktop_type);
     80   return browser ? browser : new Browser(
     81       Browser::CreateParams(profile, host_desktop_type));
     82 }
     83 
     84 // Change some of the navigation parameters based on the particular URL.
     85 // Currently this applies to some chrome:// pages which we always want to open
     86 // in a non-incognito window. Note that even though a ChromeOS guest session is
     87 // technically an incognito window, these URLs are allowed.
     88 // Returns true on success. Otherwise, if changing params leads the browser into
     89 // an erroneous state, returns false.
     90 bool AdjustNavigateParamsForURL(chrome::NavigateParams* params) {
     91   if (params->target_contents != NULL ||
     92       chrome::IsURLAllowedInIncognito(params->url,
     93                                       params->initiating_profile) ||
     94       params->initiating_profile->IsGuestSession()) {
     95     return true;
     96   }
     97 
     98   Profile* profile = params->initiating_profile;
     99 
    100   if (profile->IsOffTheRecord() || params->disposition == OFF_THE_RECORD) {
    101     profile = profile->GetOriginalProfile();
    102 
    103     // If incognito is forced, we punt.
    104     PrefService* prefs = profile->GetPrefs();
    105     if (prefs && IncognitoModePrefs::GetAvailability(prefs) ==
    106             IncognitoModePrefs::FORCED) {
    107       return false;
    108     }
    109 
    110     params->disposition = SINGLETON_TAB;
    111     params->browser = GetOrCreateBrowser(profile, params->host_desktop_type);
    112     params->window_action = chrome::NavigateParams::SHOW_WINDOW;
    113   }
    114 
    115   return true;
    116 }
    117 
    118 // Returns a Browser that can host the navigation or tab addition specified in
    119 // |params|. This might just return the same Browser specified in |params|, or
    120 // some other if that Browser is deemed incompatible.
    121 Browser* GetBrowserForDisposition(chrome::NavigateParams* params) {
    122   // If no source WebContents was specified, we use the selected one from
    123   // the target browser. This must happen first, before
    124   // GetBrowserForDisposition() has a chance to replace |params->browser| with
    125   // another one.
    126   if (!params->source_contents && params->browser) {
    127     params->source_contents =
    128         params->browser->tab_strip_model()->GetActiveWebContents();
    129   }
    130 
    131   Profile* profile = params->initiating_profile;
    132 
    133   switch (params->disposition) {
    134     case CURRENT_TAB:
    135       if (params->browser)
    136         return params->browser;
    137       // Find a compatible window and re-execute this command in it. Otherwise
    138       // re-run with NEW_WINDOW.
    139       return GetOrCreateBrowser(profile, params->host_desktop_type);
    140     case SINGLETON_TAB:
    141     case NEW_FOREGROUND_TAB:
    142     case NEW_BACKGROUND_TAB:
    143       // See if we can open the tab in the window this navigator is bound to.
    144       if (params->browser && WindowCanOpenTabs(params->browser))
    145         return params->browser;
    146       // Find a compatible window and re-execute this command in it. Otherwise
    147       // re-run with NEW_WINDOW.
    148       return GetOrCreateBrowser(profile, params->host_desktop_type);
    149     case NEW_POPUP: {
    150       // Make a new popup window.
    151       // Coerce app-style if |source| represents an app.
    152       std::string app_name;
    153       if (!params->extension_app_id.empty()) {
    154         app_name = web_app::GenerateApplicationNameFromExtensionId(
    155             params->extension_app_id);
    156       } else if (params->browser && !params->browser->app_name().empty()) {
    157         app_name = params->browser->app_name();
    158       } else if (params->source_contents) {
    159         extensions::TabHelper* extensions_tab_helper =
    160             extensions::TabHelper::FromWebContents(params->source_contents);
    161         if (extensions_tab_helper && extensions_tab_helper->is_app()) {
    162           app_name = web_app::GenerateApplicationNameFromExtensionId(
    163               extensions_tab_helper->extension_app()->id());
    164         }
    165       }
    166       if (app_name.empty()) {
    167         Browser::CreateParams browser_params(
    168             Browser::TYPE_POPUP, profile, params->host_desktop_type);
    169         browser_params.initial_bounds = params->window_bounds;
    170         return new Browser(browser_params);
    171       }
    172 
    173       return new Browser(Browser::CreateParams::CreateForApp(
    174           Browser::TYPE_POPUP, app_name, params->window_bounds, profile,
    175           params->host_desktop_type));
    176     }
    177     case NEW_WINDOW: {
    178       // Make a new normal browser window.
    179       return new Browser(Browser::CreateParams(profile,
    180                                                params->host_desktop_type));
    181     }
    182     case OFF_THE_RECORD:
    183       // Make or find an incognito window.
    184       return GetOrCreateBrowser(profile->GetOffTheRecordProfile(),
    185                                 params->host_desktop_type);
    186     // The following types all result in no navigation.
    187     case SUPPRESS_OPEN:
    188     case SAVE_TO_DISK:
    189     case IGNORE_ACTION:
    190       return NULL;
    191     default:
    192       NOTREACHED();
    193   }
    194   return NULL;
    195 }
    196 
    197 // Fix disposition and other parameter values depending on prevailing
    198 // conditions.
    199 void NormalizeDisposition(chrome::NavigateParams* params) {
    200   // Calculate the WindowOpenDisposition if necessary.
    201   if (params->browser->tab_strip_model()->empty() &&
    202       (params->disposition == NEW_BACKGROUND_TAB ||
    203        params->disposition == CURRENT_TAB ||
    204        params->disposition == SINGLETON_TAB)) {
    205     params->disposition = NEW_FOREGROUND_TAB;
    206   }
    207   if (params->browser->profile()->IsOffTheRecord() &&
    208       params->disposition == OFF_THE_RECORD) {
    209     params->disposition = NEW_FOREGROUND_TAB;
    210   }
    211   if (!params->source_contents && params->disposition == CURRENT_TAB)
    212     params->disposition = NEW_FOREGROUND_TAB;
    213 
    214   switch (params->disposition) {
    215     case NEW_BACKGROUND_TAB:
    216       // Disposition trumps add types. ADD_ACTIVE is a default, so we need to
    217       // remove it if disposition implies the tab is going to open in the
    218       // background.
    219       params->tabstrip_add_types &= ~TabStripModel::ADD_ACTIVE;
    220       break;
    221 
    222     case NEW_WINDOW:
    223     case NEW_POPUP:
    224       // Code that wants to open a new window typically expects it to be shown
    225       // automatically.
    226       if (params->window_action == chrome::NavigateParams::NO_ACTION)
    227         params->window_action = chrome::NavigateParams::SHOW_WINDOW;
    228       // Fall-through.
    229     case NEW_FOREGROUND_TAB:
    230     case SINGLETON_TAB:
    231       params->tabstrip_add_types |= TabStripModel::ADD_ACTIVE;
    232       break;
    233 
    234     default:
    235       break;
    236   }
    237 }
    238 
    239 // Obtain the profile used by the code that originated the Navigate() request.
    240 Profile* GetSourceProfile(chrome::NavigateParams* params) {
    241   if (params->source_contents) {
    242     return Profile::FromBrowserContext(
    243         params->source_contents->GetBrowserContext());
    244   }
    245 
    246   return params->initiating_profile;
    247 }
    248 
    249 void LoadURLInContents(WebContents* target_contents,
    250                        const GURL& url,
    251                        chrome::NavigateParams* params) {
    252   NavigationController::LoadURLParams load_url_params(url);
    253   load_url_params.referrer = params->referrer;
    254   load_url_params.frame_tree_node_id = params->frame_tree_node_id;
    255   load_url_params.redirect_chain = params->redirect_chain;
    256   load_url_params.transition_type = params->transition;
    257   load_url_params.extra_headers = params->extra_headers;
    258   load_url_params.should_replace_current_entry =
    259       params->should_replace_current_entry;
    260 
    261   if (params->transferred_global_request_id != GlobalRequestID()) {
    262     load_url_params.is_renderer_initiated = params->is_renderer_initiated;
    263     load_url_params.transferred_global_request_id =
    264         params->transferred_global_request_id;
    265   } else if (params->is_renderer_initiated) {
    266     load_url_params.is_renderer_initiated = true;
    267   }
    268 
    269   // Only allows the browser-initiated navigation to use POST.
    270   if (params->uses_post && !params->is_renderer_initiated) {
    271     load_url_params.load_type =
    272         NavigationController::LOAD_TYPE_BROWSER_INITIATED_HTTP_POST;
    273     load_url_params.browser_initiated_post_data =
    274         params->browser_initiated_post_data;
    275   }
    276   target_contents->GetController().LoadURLWithParams(load_url_params);
    277 }
    278 
    279 // This class makes sure the Browser object held in |params| is made visible
    280 // by the time it goes out of scope, provided |params| wants it to be shown.
    281 class ScopedBrowserShower {
    282  public:
    283   explicit ScopedBrowserShower(chrome::NavigateParams* params)
    284       : params_(params) {
    285   }
    286   ~ScopedBrowserShower() {
    287     if (params_->window_action == chrome::NavigateParams::SHOW_WINDOW_INACTIVE)
    288       params_->browser->window()->ShowInactive();
    289     else if (params_->window_action == chrome::NavigateParams::SHOW_WINDOW)
    290       params_->browser->window()->Show();
    291   }
    292  private:
    293   chrome::NavigateParams* params_;
    294   DISALLOW_COPY_AND_ASSIGN(ScopedBrowserShower);
    295 };
    296 
    297 // This class manages the lifetime of a WebContents created by the
    298 // Navigate() function. When Navigate() creates a WebContents for a URL,
    299 // an instance of this class takes ownership of it via TakeOwnership() until the
    300 // WebContents is added to a tab strip at which time ownership is
    301 // relinquished via ReleaseOwnership(). If this object goes out of scope without
    302 // being added to a tab strip, the created WebContents is deleted to
    303 // avoid a leak and the params->target_contents field is set to NULL.
    304 class ScopedTargetContentsOwner {
    305  public:
    306   explicit ScopedTargetContentsOwner(chrome::NavigateParams* params)
    307       : params_(params) {
    308   }
    309   ~ScopedTargetContentsOwner() {
    310     if (target_contents_owner_.get())
    311       params_->target_contents = NULL;
    312   }
    313 
    314   // Assumes ownership of |params_|' target_contents until ReleaseOwnership
    315   // is called.
    316   void TakeOwnership() {
    317     target_contents_owner_.reset(params_->target_contents);
    318   }
    319 
    320   // Relinquishes ownership of |params_|' target_contents.
    321   WebContents* ReleaseOwnership() {
    322     return target_contents_owner_.release();
    323   }
    324 
    325  private:
    326   chrome::NavigateParams* params_;
    327   scoped_ptr<WebContents> target_contents_owner_;
    328   DISALLOW_COPY_AND_ASSIGN(ScopedTargetContentsOwner);
    329 };
    330 
    331 content::WebContents* CreateTargetContents(const chrome::NavigateParams& params,
    332                                            const GURL& url) {
    333   WebContents::CreateParams create_params(
    334       params.browser->profile(),
    335       tab_util::GetSiteInstanceForNewTab(params.browser->profile(), url));
    336   if (params.source_contents) {
    337     create_params.initial_size =
    338         params.source_contents->GetView()->GetContainerSize();
    339     if (params.should_set_opener)
    340       create_params.opener = params.source_contents;
    341   }
    342   if (params.disposition == NEW_BACKGROUND_TAB)
    343     create_params.initially_hidden = true;
    344 
    345 #if defined(USE_AURA)
    346   if (params.browser->window() &&
    347       params.browser->window()->GetNativeWindow()) {
    348     create_params.context =
    349         params.browser->window()->GetNativeWindow();
    350   }
    351 #endif
    352 
    353   WebContents* target_contents = WebContents::Create(create_params);
    354 
    355   // New tabs can have WebUI URLs that will make calls back to arbitrary
    356   // tab helpers, so the entire set of tab helpers needs to be set up
    357   // immediately.
    358   BrowserNavigatorWebContentsAdoption::AttachTabHelpers(target_contents);
    359   extensions::TabHelper::FromWebContents(target_contents)->
    360       SetExtensionAppById(params.extension_app_id);
    361   return target_contents;
    362 }
    363 
    364 // If a prerendered page exists for |url|, replace the page at
    365 // |params->target_contents| with it and update to point to the swapped-in
    366 // WebContents.
    367 bool SwapInPrerender(const GURL& url, chrome::NavigateParams* params) {
    368   Profile* profile =
    369       Profile::FromBrowserContext(params->target_contents->GetBrowserContext());
    370   InstantSearchPrerenderer* prerenderer =
    371       InstantSearchPrerenderer::GetForProfile(profile);
    372   if (prerenderer && prerenderer->UsePrerenderedPage(url, params))
    373     return true;
    374 
    375   prerender::PrerenderManager* prerender_manager =
    376       prerender::PrerenderManagerFactory::GetForProfile(profile);
    377   return prerender_manager &&
    378       prerender_manager->MaybeUsePrerenderedPage(url, params);
    379 }
    380 
    381 bool SwapInInstantNTP(chrome::NavigateParams* params,
    382                       const GURL& url,
    383                       content::WebContents* source_contents) {
    384   BrowserInstantController* instant = params->browser->instant_controller();
    385   return instant && instant->MaybeSwapInInstantNTPContents(
    386       url, source_contents, &params->target_contents);
    387 }
    388 
    389 chrome::HostDesktopType GetHostDesktop(Browser* browser) {
    390   if (browser)
    391     return browser->host_desktop_type();
    392   return chrome::GetActiveDesktop();
    393 }
    394 
    395 }  // namespace
    396 
    397 namespace chrome {
    398 
    399 NavigateParams::NavigateParams(Browser* a_browser,
    400                                const GURL& a_url,
    401                                content::PageTransition a_transition)
    402     : url(a_url),
    403       frame_tree_node_id(-1),
    404       uses_post(false),
    405       target_contents(NULL),
    406       source_contents(NULL),
    407       disposition(CURRENT_TAB),
    408       transition(a_transition),
    409       is_renderer_initiated(false),
    410       tabstrip_index(-1),
    411       tabstrip_add_types(TabStripModel::ADD_ACTIVE),
    412       window_action(NO_ACTION),
    413       user_gesture(true),
    414       path_behavior(RESPECT),
    415       ref_behavior(IGNORE_REF),
    416       browser(a_browser),
    417       initiating_profile(NULL),
    418       host_desktop_type(GetHostDesktop(a_browser)),
    419       should_replace_current_entry(false),
    420       should_set_opener(false) {
    421 }
    422 
    423 NavigateParams::NavigateParams(Browser* a_browser,
    424                                WebContents* a_target_contents)
    425     : frame_tree_node_id(-1),
    426       uses_post(false),
    427       target_contents(a_target_contents),
    428       source_contents(NULL),
    429       disposition(CURRENT_TAB),
    430       transition(content::PAGE_TRANSITION_LINK),
    431       is_renderer_initiated(false),
    432       tabstrip_index(-1),
    433       tabstrip_add_types(TabStripModel::ADD_ACTIVE),
    434       window_action(NO_ACTION),
    435       user_gesture(true),
    436       path_behavior(RESPECT),
    437       ref_behavior(IGNORE_REF),
    438       browser(a_browser),
    439       initiating_profile(NULL),
    440       host_desktop_type(GetHostDesktop(a_browser)),
    441       should_replace_current_entry(false),
    442       should_set_opener(false) {
    443 }
    444 
    445 NavigateParams::NavigateParams(Profile* a_profile,
    446                                const GURL& a_url,
    447                                content::PageTransition a_transition)
    448     : url(a_url),
    449       frame_tree_node_id(-1),
    450       uses_post(false),
    451       target_contents(NULL),
    452       source_contents(NULL),
    453       disposition(NEW_FOREGROUND_TAB),
    454       transition(a_transition),
    455       is_renderer_initiated(false),
    456       tabstrip_index(-1),
    457       tabstrip_add_types(TabStripModel::ADD_ACTIVE),
    458       window_action(SHOW_WINDOW),
    459       user_gesture(true),
    460       path_behavior(RESPECT),
    461       ref_behavior(IGNORE_REF),
    462       browser(NULL),
    463       initiating_profile(a_profile),
    464       host_desktop_type(chrome::GetActiveDesktop()),
    465       should_replace_current_entry(false),
    466       should_set_opener(false) {
    467 }
    468 
    469 NavigateParams::~NavigateParams() {}
    470 
    471 void FillNavigateParamsFromOpenURLParams(chrome::NavigateParams* nav_params,
    472                                          const content::OpenURLParams& params) {
    473   nav_params->referrer = params.referrer;
    474   nav_params->frame_tree_node_id = params.frame_tree_node_id;
    475   nav_params->redirect_chain = params.redirect_chain;
    476   nav_params->extra_headers = params.extra_headers;
    477   nav_params->disposition = params.disposition;
    478   nav_params->is_renderer_initiated = params.is_renderer_initiated;
    479   nav_params->transferred_global_request_id =
    480       params.transferred_global_request_id;
    481   nav_params->should_replace_current_entry =
    482       params.should_replace_current_entry;
    483   nav_params->uses_post = params.uses_post;
    484   nav_params->browser_initiated_post_data = params.browser_initiated_post_data;
    485 }
    486 
    487 void Navigate(NavigateParams* params) {
    488   Browser* source_browser = params->browser;
    489   if (source_browser)
    490     params->initiating_profile = source_browser->profile();
    491   DCHECK(params->initiating_profile);
    492 
    493   if (!AdjustNavigateParamsForURL(params))
    494     return;
    495 
    496   ExtensionService* service = params->initiating_profile->GetExtensionService();
    497   if (service)
    498     service->ShouldBlockUrlInBrowserTab(&params->url);
    499 
    500   // The browser window may want to adjust the disposition.
    501   if (params->disposition == NEW_POPUP &&
    502       source_browser &&
    503       source_browser->window()) {
    504     params->disposition =
    505         source_browser->window()->GetDispositionForPopupBounds(
    506             params->window_bounds);
    507   }
    508 
    509   params->browser = GetBrowserForDisposition(params);
    510   if (!params->browser)
    511     return;
    512 
    513 #if defined(USE_ASH)
    514   if (source_browser && source_browser != params->browser) {
    515     // When the newly created browser was spawned by a browser which visits
    516     // another user's desktop, it should be shown on the same desktop as the
    517     // originating one. (This is part of the desktop separation per profile).
    518     MultiUserWindowManager* manager = MultiUserWindowManager::GetInstance();
    519     // Some unit tests have no manager instantiated.
    520     if (manager) {
    521       aura::Window* src_window = source_browser->window()->GetNativeWindow();
    522       aura::Window* new_window = params->browser->window()->GetNativeWindow();
    523       const std::string& src_user =
    524           manager->GetUserPresentingWindow(src_window);
    525       if (src_user != manager->GetUserPresentingWindow(new_window)) {
    526         // Once the window gets presented, it should be shown on the same
    527         // desktop as the desktop of the creating browser. Note that this
    528         // command will not show the window if it wasn't shown yet by the
    529         // browser creation.
    530         manager->ShowWindowForUser(new_window, src_user);
    531       }
    532     }
    533   }
    534 #endif
    535 
    536   // Navigate() must not return early after this point.
    537 
    538   if (GetSourceProfile(params) != params->browser->profile()) {
    539     // A tab is being opened from a link from a different profile, we must reset
    540     // source information that may cause state to be shared.
    541     params->source_contents = NULL;
    542     params->referrer = content::Referrer();
    543   }
    544 
    545   // Make sure the Browser is shown if params call for it.
    546   ScopedBrowserShower shower(params);
    547 
    548   // Makes sure any WebContents created by this function is destroyed if
    549   // not properly added to a tab strip.
    550   ScopedTargetContentsOwner target_contents_owner(params);
    551 
    552   // Some dispositions need coercion to base types.
    553   NormalizeDisposition(params);
    554 
    555   // If a new window has been created, it needs to be shown.
    556   if (params->window_action == NavigateParams::NO_ACTION &&
    557       source_browser != params->browser &&
    558       params->browser->tab_strip_model()->empty()) {
    559     params->window_action = NavigateParams::SHOW_WINDOW;
    560   }
    561 
    562   // If we create a popup window from a non user-gesture, don't activate it.
    563   if (params->window_action == NavigateParams::SHOW_WINDOW &&
    564       params->disposition == NEW_POPUP &&
    565       params->user_gesture == false) {
    566     params->window_action = NavigateParams::SHOW_WINDOW_INACTIVE;
    567   }
    568 
    569   // Determine if the navigation was user initiated. If it was, we need to
    570   // inform the target WebContents, and we may need to update the UI.
    571   content::PageTransition base_transition =
    572       content::PageTransitionStripQualifier(params->transition);
    573   bool user_initiated =
    574       params->transition & content::PAGE_TRANSITION_FROM_ADDRESS_BAR ||
    575       base_transition == content::PAGE_TRANSITION_TYPED ||
    576       base_transition == content::PAGE_TRANSITION_AUTO_BOOKMARK ||
    577       base_transition == content::PAGE_TRANSITION_GENERATED ||
    578       base_transition == content::PAGE_TRANSITION_AUTO_TOPLEVEL ||
    579       base_transition == content::PAGE_TRANSITION_RELOAD ||
    580       base_transition == content::PAGE_TRANSITION_KEYWORD;
    581 
    582   // Check if this is a singleton tab that already exists
    583   int singleton_index = chrome::GetIndexOfSingletonTab(params);
    584 
    585   // Did we use Instant's NTP contents or a prerender?
    586   bool swapped_in = false;
    587 
    588   // If no target WebContents was specified, we need to construct one if
    589   // we are supposed to target a new tab; unless it's a singleton that already
    590   // exists.
    591   if (!params->target_contents && singleton_index < 0) {
    592     GURL url;
    593     if (params->url.is_empty()) {
    594       url = params->browser->profile()->GetHomePage();
    595       params->transition = content::PageTransitionFromInt(
    596           params->transition | content::PAGE_TRANSITION_HOME_PAGE);
    597     } else {
    598       url = params->url;
    599     }
    600 
    601     if (params->disposition != CURRENT_TAB) {
    602       swapped_in = SwapInInstantNTP(params, url, NULL);
    603       if (!swapped_in)
    604         params->target_contents = CreateTargetContents(*params, url);
    605 
    606       // This function takes ownership of |params->target_contents| until it
    607       // is added to a TabStripModel.
    608       target_contents_owner.TakeOwnership();
    609     } else {
    610       // ... otherwise if we're loading in the current tab, the target is the
    611       // same as the source.
    612       DCHECK(params->source_contents);
    613       swapped_in = SwapInInstantNTP(params, url, params->source_contents);
    614       if (!swapped_in)
    615         params->target_contents = params->source_contents;
    616       DCHECK(params->target_contents);
    617       // Prerender expects |params->target_contents| to be attached to a browser
    618       // window, so only call for CURRENT_TAB navigations. (Others are currently
    619       // unsupported because of session storage namespaces anyway.)
    620       // Notice that this includes middle-clicking, since middle clicking
    621       // translates into a chrome::Navigate call with no URL followed by a
    622       // CURRENT_TAB navigation.
    623       // TODO(tburkard): We can actually swap in in non-CURRENT_TAB cases, as
    624       // long as the WebContents we swap into is part of a TabStrip model.
    625       // Therefore, we should swap in regardless of CURRENT_TAB, and instead,
    626       // check in the swapin function whether the WebContents is not in a
    627       // TabStrip model, in which case we must not swap in.
    628       if (!swapped_in)
    629         swapped_in = SwapInPrerender(url, params);
    630     }
    631 
    632     if (user_initiated)
    633       params->target_contents->UserGestureDone();
    634 
    635     if (!swapped_in) {
    636       // Try to handle non-navigational URLs that popup dialogs and such, these
    637       // should not actually navigate.
    638       if (!HandleNonNavigationAboutURL(url)) {
    639         // Perform the actual navigation, tracking whether it came from the
    640         // renderer.
    641 
    642         LoadURLInContents(params->target_contents, url, params);
    643         // For prerender bookkeeping purposes, record that this pending navigate
    644         // originated from chrome::Navigate.
    645         content::NavigationEntry* entry =
    646             params->target_contents->GetController().GetPendingEntry();
    647         if (entry)
    648           entry->SetExtraData(prerender::kChromeNavigateExtraDataKey,
    649                               base::string16());
    650       }
    651     }
    652   } else {
    653     // |target_contents| was specified non-NULL, and so we assume it has already
    654     // been navigated appropriately. We need to do nothing more other than
    655     // add it to the appropriate tabstrip.
    656   }
    657 
    658   // If the user navigated from the omnibox, and the selected tab is going to
    659   // lose focus, then make sure the focus for the source tab goes away from the
    660   // omnibox.
    661   if (params->source_contents &&
    662       (params->disposition == NEW_FOREGROUND_TAB ||
    663        params->disposition == NEW_WINDOW) &&
    664       (params->tabstrip_add_types & TabStripModel::ADD_INHERIT_OPENER))
    665     params->source_contents->GetView()->Focus();
    666 
    667   if (params->source_contents == params->target_contents ||
    668       (swapped_in && params->disposition == CURRENT_TAB)) {
    669     // The navigation occurred in the source tab.
    670     params->browser->UpdateUIForNavigationInTab(params->target_contents,
    671                                                 params->transition,
    672                                                 user_initiated);
    673   } else if (singleton_index == -1) {
    674     // If some non-default value is set for the index, we should tell the
    675     // TabStripModel to respect it.
    676     if (params->tabstrip_index != -1)
    677       params->tabstrip_add_types |= TabStripModel::ADD_FORCE_INDEX;
    678 
    679     // The navigation should insert a new tab into the target Browser.
    680     params->browser->tab_strip_model()->AddWebContents(
    681         params->target_contents,
    682         params->tabstrip_index,
    683         params->transition,
    684         params->tabstrip_add_types);
    685     // Now that the |params->target_contents| is safely owned by the target
    686     // Browser's TabStripModel, we can release ownership.
    687     target_contents_owner.ReleaseOwnership();
    688   }
    689 
    690   if (singleton_index >= 0) {
    691     WebContents* target =
    692         params->browser->tab_strip_model()->GetWebContentsAt(singleton_index);
    693 
    694     if (target->IsCrashed()) {
    695       target->GetController().Reload(true);
    696     } else if (params->path_behavior == NavigateParams::IGNORE_AND_NAVIGATE &&
    697         target->GetURL() != params->url) {
    698       LoadURLInContents(target, params->url, params);
    699       // For prerender bookkeeping purposes, record that this pending navigate
    700       // originated from chrome::Navigate.
    701       content::NavigationEntry* entry =
    702           target->GetController().GetPendingEntry();
    703       if (entry)
    704         entry->SetExtraData(prerender::kChromeNavigateExtraDataKey,
    705                             base::string16());
    706     }
    707 
    708     // If the singleton tab isn't already selected, select it.
    709     if (params->source_contents != params->target_contents) {
    710       params->browser->tab_strip_model()->ActivateTabAt(singleton_index,
    711                                                         user_initiated);
    712     }
    713   }
    714 
    715   if (params->disposition != CURRENT_TAB) {
    716     content::NotificationService::current()->Notify(
    717         chrome::NOTIFICATION_TAB_ADDED,
    718         content::Source<content::WebContentsDelegate>(params->browser),
    719         content::Details<WebContents>(params->target_contents));
    720   }
    721 }
    722 
    723 bool IsURLAllowedInIncognito(const GURL& url,
    724                              content::BrowserContext* browser_context) {
    725   if (url.scheme() == content::kViewSourceScheme) {
    726     // A view-source URL is allowed in incognito mode only if the URL itself
    727     // is allowed in incognito mode. Remove the "view-source:" from the start
    728     // of the URL and validate the rest.
    729     std::string stripped_spec = url.spec();
    730     DCHECK_GT(stripped_spec.size(), strlen(content::kViewSourceScheme));
    731     stripped_spec.erase(0, strlen(content::kViewSourceScheme) + 1);
    732     GURL stripped_url(stripped_spec);
    733     return stripped_url.is_valid() &&
    734         IsURLAllowedInIncognito(stripped_url, browser_context);
    735   }
    736   // Most URLs are allowed in incognito; the following are exceptions.
    737   // chrome://extensions is on the list because it redirects to
    738   // chrome://settings.
    739   if (url.scheme() == chrome::kChromeUIScheme &&
    740       (url.host() == chrome::kChromeUISettingsHost ||
    741        url.host() == chrome::kChromeUISettingsFrameHost ||
    742        url.host() == chrome::kChromeUIExtensionsHost ||
    743        url.host() == chrome::kChromeUIBookmarksHost ||
    744 #if defined(ENABLE_ENHANCED_BOOKMARKS)
    745        url.host() == chrome::kChromeUIEnhancedBookmarksHost ||
    746 #endif
    747        url.host() == chrome::kChromeUIUberHost ||
    748        url.host() == chrome::kChromeUIThumbnailHost ||
    749        url.host() == chrome::kChromeUIThumbnailHost2 ||
    750        url.host() == chrome::kChromeUIThumbnailListHost)) {
    751     return false;
    752   }
    753 
    754   if (url.scheme() == chrome::kChromeSearchScheme &&
    755       (url.host() == chrome::kChromeUIThumbnailHost ||
    756        url.host() == chrome::kChromeUIThumbnailHost2 ||
    757        url.host() == chrome::kChromeUIThumbnailListHost)) {
    758     return false;
    759   }
    760 
    761   GURL rewritten_url = url;
    762   bool reverse_on_redirect = false;
    763   content::BrowserURLHandler::GetInstance()->RewriteURLIfNecessary(
    764       &rewritten_url, browser_context, &reverse_on_redirect);
    765 
    766   // Some URLs are mapped to uber subpages. Do not allow them in incognito.
    767   return !(rewritten_url.scheme() == chrome::kChromeUIScheme &&
    768            rewritten_url.host() == chrome::kChromeUIUberHost);
    769 }
    770 
    771 }  // namespace chrome
    772