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_finder.h"
6 
7 #include <stdint.h>
8 
9 #include <algorithm>
10 
11 #include "build/build_config.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/ui/browser_list.h"
14 #include "chrome/browser/ui/browser_window.h"
15 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
16 #include "chrome/browser/ui/tabs/tab_group_model.h"
17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
18 #include "components/tab_groups/tab_group_id.h"
19 #include "content/public/browser/navigation_controller.h"
20 #include "ui/display/display.h"
21 #include "ui/display/screen.h"
22 
23 #if defined(OS_CHROMEOS)
24 #include "ash/public/cpp/multi_user_window_manager.h"
25 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
26 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_helper.h"
27 #include "components/account_id/account_id.h"
28 #endif
29 
30 using content::WebContents;
31 
32 namespace {
33 
34 // Type used to indicate to match anything.
35 const uint32_t kMatchAny = 0;
36 
37 // See BrowserMatches for details.
38 const uint32_t kMatchOriginalProfile = 1 << 0;
39 const uint32_t kMatchCanSupportWindowFeature = 1 << 1;
40 const uint32_t kMatchNormal = 1 << 2;
41 const uint32_t kMatchDisplayId = 1 << 3;
42 #if defined(OS_WIN) || defined(OS_CHROMEOS)
43 const uint32_t kMatchCurrentWorkspace = 1 << 4;
44 #endif
45 
46 // Returns true if the specified |browser| matches the specified arguments.
47 // |match_types| is a bitmask dictating what parameters to match:
48 // . If it contains kMatchOriginalProfile then the original profile of the
49 //   browser must match |profile->GetOriginalProfile()|. This is used to match
50 //   incognito windows.
51 // . If it contains kMatchCanSupportWindowFeature
52 //   |CanSupportWindowFeature(window_feature)| must return true.
53 // . If it contains kMatchNormal, the browser must be a normal tabbed browser.
BrowserMatches(Browser * browser,Profile * profile,Browser::WindowFeature window_feature,uint32_t match_types,int64_t display_id)54 bool BrowserMatches(Browser* browser,
55                     Profile* profile,
56                     Browser::WindowFeature window_feature,
57                     uint32_t match_types,
58                     int64_t display_id) {
59   if ((match_types & kMatchCanSupportWindowFeature) &&
60       !browser->CanSupportWindowFeature(window_feature)) {
61     return false;
62   }
63 
64 #if defined(OS_CHROMEOS)
65   // Get the profile on which the window is currently shown.
66   // MultiUserWindowManagerHelper might be NULL under test scenario.
67   ash::MultiUserWindowManager* const multi_user_window_manager =
68       MultiUserWindowManagerHelper::GetWindowManager();
69   Profile* shown_profile = nullptr;
70   if (multi_user_window_manager) {
71     const AccountId& shown_account_id =
72         multi_user_window_manager->GetUserPresentingWindow(
73             browser->window()->GetNativeWindow());
74     shown_profile =
75         shown_account_id.is_valid()
76             ? multi_user_util::GetProfileFromAccountId(shown_account_id)
77             : nullptr;
78   }
79 #endif
80 
81   if (match_types & kMatchOriginalProfile) {
82     if (browser->profile()->GetOriginalProfile() !=
83         profile->GetOriginalProfile())
84       return false;
85 #if defined(OS_CHROMEOS)
86     if (shown_profile &&
87         shown_profile->GetOriginalProfile() != profile->GetOriginalProfile()) {
88       return false;
89     }
90 #endif
91   } else {
92     if (browser->profile() != profile)
93       return false;
94 #if defined(OS_CHROMEOS)
95     if (shown_profile && shown_profile != profile)
96       return false;
97 #endif
98   }
99 
100   if ((match_types & kMatchNormal) && !browser->is_type_normal())
101     return false;
102 
103 #if defined(OS_WIN) || defined(OS_CHROMEOS)
104   // Note that |browser->window()| might be nullptr in tests.
105   if ((match_types & kMatchCurrentWorkspace) &&
106       (!browser->window() || !browser->window()->IsOnCurrentWorkspace())) {
107     return false;
108   }
109 #endif  // OS_WIN
110 
111   if (match_types & kMatchDisplayId) {
112     return display::Screen::GetScreen()
113                ->GetDisplayNearestWindow(browser->window()->GetNativeWindow())
114                .id() == display_id;
115   }
116 
117   return true;
118 }
119 
120 // Returns the first browser in the specified iterator that returns true from
121 // |BrowserMatches|, or null if no browsers match the arguments. See
122 // |BrowserMatches| for details on the arguments.
123 template <class T>
FindBrowserMatching(const T & begin,const T & end,Profile * profile,Browser::WindowFeature window_feature,uint32_t match_types,int64_t display_id=display::kInvalidDisplayId)124 Browser* FindBrowserMatching(const T& begin,
125                              const T& end,
126                              Profile* profile,
127                              Browser::WindowFeature window_feature,
128                              uint32_t match_types,
129                              int64_t display_id = display::kInvalidDisplayId) {
130   for (T i = begin; i != end; ++i) {
131     if (BrowserMatches(*i, profile, window_feature, match_types, display_id))
132       return *i;
133   }
134   return NULL;
135 }
136 
FindBrowserWithTabbedOrAnyType(Profile * profile,bool match_tabbed,bool match_original_profiles,bool match_current_workspace,int64_t display_id=display::kInvalidDisplayId)137 Browser* FindBrowserWithTabbedOrAnyType(
138     Profile* profile,
139     bool match_tabbed,
140     bool match_original_profiles,
141     bool match_current_workspace,
142     int64_t display_id = display::kInvalidDisplayId) {
143   BrowserList* browser_list_impl = BrowserList::GetInstance();
144   if (!browser_list_impl)
145     return NULL;
146   uint32_t match_types = kMatchAny;
147   if (match_tabbed)
148     match_types |= kMatchNormal;
149   if (match_original_profiles)
150     match_types |= kMatchOriginalProfile;
151   if (display_id != display::kInvalidDisplayId)
152     match_types |= kMatchDisplayId;
153 #if defined(OS_WIN) || defined(OS_CHROMEOS)
154   if (match_current_workspace)
155     match_types |= kMatchCurrentWorkspace;
156 #endif
157   Browser* browser =
158       FindBrowserMatching(browser_list_impl->begin_last_active(),
159                           browser_list_impl->end_last_active(), profile,
160                           Browser::FEATURE_NONE, match_types, display_id);
161   // Fall back to a forward scan of all Browsers if no active one was found.
162   return browser ? browser
163                  : FindBrowserMatching(
164                        browser_list_impl->begin(), browser_list_impl->end(),
165                        profile, Browser::FEATURE_NONE, match_types, display_id);
166 }
167 
GetBrowserCountImpl(Profile * profile,uint32_t match_types,int64_t display_id=display::kInvalidDisplayId)168 size_t GetBrowserCountImpl(Profile* profile,
169                            uint32_t match_types,
170                            int64_t display_id = display::kInvalidDisplayId) {
171   BrowserList* browser_list_impl = BrowserList::GetInstance();
172   size_t count = 0;
173   if (browser_list_impl) {
174     for (auto i = browser_list_impl->begin(); i != browser_list_impl->end();
175          ++i) {
176       if (BrowserMatches(*i, profile, Browser::FEATURE_NONE, match_types,
177                          display_id))
178         count++;
179     }
180   }
181   return count;
182 }
183 
184 }  // namespace
185 
186 namespace chrome {
187 
FindTabbedBrowser(Profile * profile,bool match_original_profiles,int64_t display_id)188 Browser* FindTabbedBrowser(Profile* profile,
189                            bool match_original_profiles,
190                            int64_t display_id) {
191   return FindBrowserWithTabbedOrAnyType(profile, true, match_original_profiles,
192                                         /*match_current_workspace=*/true,
193                                         display_id);
194 }
195 
FindAnyBrowser(Profile * profile,bool match_original_profiles)196 Browser* FindAnyBrowser(Profile* profile, bool match_original_profiles) {
197   return FindBrowserWithTabbedOrAnyType(profile, false, match_original_profiles,
198                                         /*match_current_workspace=*/false);
199 }
200 
FindBrowserWithProfile(Profile * profile)201 Browser* FindBrowserWithProfile(Profile* profile) {
202   return FindBrowserWithTabbedOrAnyType(profile, false, false,
203                                         /*match_current_workspace=*/false);
204 }
205 
FindBrowserWithID(SessionID desired_id)206 Browser* FindBrowserWithID(SessionID desired_id) {
207   for (auto* browser : *BrowserList::GetInstance()) {
208     if (browser->session_id() == desired_id)
209       return browser;
210   }
211   return NULL;
212 }
213 
FindBrowserWithWindow(gfx::NativeWindow window)214 Browser* FindBrowserWithWindow(gfx::NativeWindow window) {
215   if (!window)
216     return NULL;
217   for (auto* browser : *BrowserList::GetInstance()) {
218     if (browser->window() && browser->window()->GetNativeWindow() == window)
219       return browser;
220   }
221   return NULL;
222 }
223 
FindBrowserWithActiveWindow()224 Browser* FindBrowserWithActiveWindow() {
225   Browser* browser = BrowserList::GetInstance()->GetLastActive();
226   return browser && browser->window()->IsActive() ? browser : nullptr;
227 }
228 
FindBrowserWithWebContents(const WebContents * web_contents)229 Browser* FindBrowserWithWebContents(const WebContents* web_contents) {
230   DCHECK(web_contents);
231   auto& all_tabs = AllTabContentses();
232   auto it = std::find(all_tabs.begin(), all_tabs.end(), web_contents);
233 
234   return (it == all_tabs.end()) ? nullptr : it.browser();
235 }
236 
FindBrowserWithGroup(tab_groups::TabGroupId group,Profile * profile)237 Browser* FindBrowserWithGroup(tab_groups::TabGroupId group, Profile* profile) {
238   for (auto* browser : *BrowserList::GetInstance()) {
239     if ((!profile || browser->profile() == profile) &&
240         browser->tab_strip_model() &&
241         browser->tab_strip_model()->group_model()->ContainsTabGroup(group)) {
242       return browser;
243     }
244   }
245   return nullptr;
246 }
247 
FindLastActiveWithProfile(Profile * profile)248 Browser* FindLastActiveWithProfile(Profile* profile) {
249   BrowserList* list = BrowserList::GetInstance();
250   // We are only interested in last active browsers, so we don't fall back to
251   // all browsers like FindBrowserWith* do.
252   return FindBrowserMatching(list->begin_last_active(), list->end_last_active(),
253                              profile, Browser::FEATURE_NONE, kMatchAny);
254 }
255 
FindLastActive()256 Browser* FindLastActive() {
257   BrowserList* browser_list_impl = BrowserList::GetInstance();
258   if (browser_list_impl)
259     return browser_list_impl->GetLastActive();
260   return NULL;
261 }
262 
GetTotalBrowserCount()263 size_t GetTotalBrowserCount() {
264   return BrowserList::GetInstance()->size();
265 }
266 
GetBrowserCount(Profile * profile)267 size_t GetBrowserCount(Profile* profile) {
268   return GetBrowserCountImpl(profile, kMatchAny);
269 }
270 
GetTabbedBrowserCount(Profile * profile)271 size_t GetTabbedBrowserCount(Profile* profile) {
272   return GetBrowserCountImpl(profile, kMatchNormal);
273 }
274 
275 }  // namespace chrome
276