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/singleton_tabs.h" 6 7 #include "chrome/browser/profiles/profile.h" 8 #include "chrome/browser/search/search.h" 9 #include "chrome/browser/ui/browser.h" 10 #include "chrome/browser/ui/browser_navigator.h" 11 #include "chrome/browser/ui/tabs/tab_strip_model.h" 12 #include "chrome/common/url_constants.h" 13 #include "content/public/browser/browser_url_handler.h" 14 #include "content/public/browser/web_contents.h" 15 16 namespace chrome { 17 namespace { 18 19 // Returns true if two URLs are equal after taking |replacements| into account. 20 bool CompareURLsWithReplacements(const GURL& url, 21 const GURL& other, 22 const url::Replacements<char>& replacements) { 23 if (url == other) 24 return true; 25 26 GURL url_replaced = url.ReplaceComponents(replacements); 27 GURL other_replaced = other.ReplaceComponents(replacements); 28 return url_replaced == other_replaced; 29 } 30 31 } // namespace 32 33 void ShowSingletonTab(Browser* browser, const GURL& url) { 34 NavigateParams params(GetSingletonTabNavigateParams(browser, url)); 35 Navigate(¶ms); 36 } 37 38 void ShowSingletonTabRespectRef(Browser* browser, const GURL& url) { 39 NavigateParams params(GetSingletonTabNavigateParams(browser, url)); 40 params.ref_behavior = NavigateParams::RESPECT_REF; 41 Navigate(¶ms); 42 } 43 44 void ShowSingletonTabOverwritingNTP(Browser* browser, 45 const NavigateParams& params) { 46 DCHECK(browser); 47 NavigateParams local_params(params); 48 content::WebContents* contents = 49 browser->tab_strip_model()->GetActiveWebContents(); 50 if (contents) { 51 const GURL& contents_url = contents->GetURL(); 52 if ((contents_url == GURL(kChromeUINewTabURL) || IsInstantNTP(contents) || 53 contents_url == GURL(url::kAboutBlankURL)) && 54 GetIndexOfSingletonTab(&local_params) < 0) { 55 local_params.disposition = CURRENT_TAB; 56 } 57 } 58 59 Navigate(&local_params); 60 } 61 62 NavigateParams GetSingletonTabNavigateParams(Browser* browser, 63 const GURL& url) { 64 NavigateParams params(browser, url, content::PAGE_TRANSITION_AUTO_BOOKMARK); 65 params.disposition = SINGLETON_TAB; 66 params.window_action = NavigateParams::SHOW_WINDOW; 67 params.user_gesture = true; 68 params.tabstrip_add_types |= TabStripModel::ADD_INHERIT_OPENER; 69 return params; 70 } 71 72 // Returns the index of an existing singleton tab in |params->browser| matching 73 // the URL specified in |params|. 74 int GetIndexOfSingletonTab(NavigateParams* params) { 75 if (params->disposition != SINGLETON_TAB) 76 return -1; 77 78 // In case the URL was rewritten by the BrowserURLHandler we need to ensure 79 // that we do not open another URL that will get redirected to the rewritten 80 // URL. 81 GURL rewritten_url(params->url); 82 bool reverse_on_redirect = false; 83 content::BrowserURLHandler::GetInstance()->RewriteURLIfNecessary( 84 &rewritten_url, 85 params->browser->profile(), 86 &reverse_on_redirect); 87 88 // If there are several matches: prefer the active tab by starting there. 89 int start_index = 90 std::max(0, params->browser->tab_strip_model()->active_index()); 91 int tab_count = params->browser->tab_strip_model()->count(); 92 for (int i = 0; i < tab_count; ++i) { 93 int tab_index = (start_index + i) % tab_count; 94 content::WebContents* tab = 95 params->browser->tab_strip_model()->GetWebContentsAt(tab_index); 96 97 GURL tab_url = tab->GetURL(); 98 99 // Skip view-source tabs. This is needed because RewriteURLIfNecessary 100 // removes the "view-source:" scheme which leads to incorrect matching. 101 if (tab_url.SchemeIs(content::kViewSourceScheme)) 102 continue; 103 104 GURL rewritten_tab_url = tab_url; 105 content::BrowserURLHandler::GetInstance()->RewriteURLIfNecessary( 106 &rewritten_tab_url, 107 params->browser->profile(), 108 &reverse_on_redirect); 109 110 url::Replacements<char> replacements; 111 if (params->ref_behavior == NavigateParams::IGNORE_REF) 112 replacements.ClearRef(); 113 if (params->path_behavior == NavigateParams::IGNORE_AND_NAVIGATE || 114 params->path_behavior == NavigateParams::IGNORE_AND_STAY_PUT) { 115 replacements.ClearPath(); 116 replacements.ClearQuery(); 117 } 118 119 if (CompareURLsWithReplacements(tab_url, params->url, replacements) || 120 CompareURLsWithReplacements(rewritten_tab_url, 121 rewritten_url, 122 replacements)) { 123 params->target_contents = tab; 124 return tab_index; 125 } 126 } 127 128 return -1; 129 } 130 131 } // namespace chrome 132