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
16namespace chrome {
17namespace {
18
19// Returns true if two URLs are equal after taking |replacements| into account.
20bool 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
33void ShowSingletonTab(Browser* browser, const GURL& url) {
34  NavigateParams params(GetSingletonTabNavigateParams(browser, url));
35  Navigate(&params);
36}
37
38void ShowSingletonTabRespectRef(Browser* browser, const GURL& url) {
39  NavigateParams params(GetSingletonTabNavigateParams(browser, url));
40  params.ref_behavior = NavigateParams::RESPECT_REF;
41  Navigate(&params);
42}
43
44void 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
62NavigateParams GetSingletonTabNavigateParams(Browser* browser,
63                                             const GURL& url) {
64  NavigateParams params(browser, url, ui::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|.
74int 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