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.
CompareURLsWithReplacements(const GURL & url,const GURL & other,const url::Replacements<char> & replacements)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
ShowSingletonTab(Browser * browser,const GURL & url)33 void ShowSingletonTab(Browser* browser, const GURL& url) {
34 NavigateParams params(GetSingletonTabNavigateParams(browser, url));
35 Navigate(¶ms);
36 }
37
ShowSingletonTabRespectRef(Browser * browser,const GURL & url)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
ShowSingletonTabOverwritingNTP(Browser * browser,const NavigateParams & params)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
GetSingletonTabNavigateParams(Browser * browser,const GURL & url)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|.
GetIndexOfSingletonTab(NavigateParams * 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