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