blob: 5d4b89b667faac9facefd526cd0de2a974db0499 [file] [log] [blame]
[email protected]327640a2012-01-24 21:57:591// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ac84431b2011-09-27 17:26:112// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]ac84431b2011-09-27 17:26:115#include "chrome/browser/extensions/extension_tab_util.h"
[email protected]41d9faf2012-02-28 23:46:026
[email protected]98528302014-05-02 00:34:087#include "base/strings/string_number_conversions.h"
ericzengf97b7c22014-08-26 03:07:308#include "base/strings/stringprintf.h"
[email protected]b19451b2012-06-08 17:36:199#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
[email protected]98528302014-05-02 00:34:0810#include "chrome/browser/extensions/chrome_extension_function.h"
lfg185333072014-09-09 20:16:1111#include "chrome/browser/extensions/chrome_extension_function_details.h"
[email protected]e9570fdf2012-07-18 20:01:2112#include "chrome/browser/extensions/tab_helper.h"
13#include "chrome/browser/extensions/window_controller.h"
[email protected]f1c102b2013-02-15 07:44:1214#include "chrome/browser/extensions/window_controller_list.h"
[email protected]b56e2e32012-05-11 21:18:0415#include "chrome/browser/profiles/profile.h"
[email protected]e3f90c602014-08-18 12:41:5916#include "chrome/browser/sessions/session_tab_helper.h"
[email protected]b56e2e32012-05-11 21:18:0417#include "chrome/browser/ui/browser.h"
[email protected]73c1a6842012-07-13 17:39:0418#include "chrome/browser/ui/browser_finder.h"
[email protected]3539929f2013-02-01 05:59:1419#include "chrome/browser/ui/browser_iterator.h"
[email protected]b56e2e32012-05-11 21:18:0420#include "chrome/browser/ui/browser_window.h"
[email protected]0edcdec2013-10-31 06:43:0821#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
ericzengf97b7c22014-08-26 03:07:3022#include "chrome/browser/ui/singleton_tabs.h"
[email protected]44e329a2012-07-14 01:13:0623#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
[email protected]b56e2e32012-05-11 21:18:0424#include "chrome/browser/ui/tabs/tab_strip_model.h"
jared.sohn09a3ccc2015-07-09 03:47:3025#include "chrome/browser/ui/tabs/tab_utils.h"
[email protected]760f6032014-06-30 23:18:1926#include "chrome/common/extensions/api/tabs.h"
[email protected]45c75e62012-03-21 19:56:3527#include "chrome/common/url_constants.h"
[email protected]9b5b1d602014-06-12 14:29:0228#include "components/url_fixer/url_fixer.h"
[email protected]ad23a092011-12-28 07:02:0429#include "content/public/browser/favicon_status.h"
30#include "content/public/browser/navigation_entry.h"
[email protected]6acde6352012-01-04 16:52:2031#include "content/public/browser/web_contents.h"
hashimotoad3c6872014-08-29 09:46:5732#include "extensions/browser/app_window/app_window.h"
33#include "extensions/browser/app_window/app_window_registry.h"
[email protected]98528302014-05-02 00:34:0834#include "extensions/common/constants.h"
35#include "extensions/common/error_utils.h"
[email protected]e4452d32013-11-15 23:07:4136#include "extensions/common/extension.h"
ericzengf97b7c22014-08-26 03:07:3037#include "extensions/common/feature_switch.h"
[email protected]0c3c9732013-09-16 08:53:4138#include "extensions/common/manifest_constants.h"
[email protected]98528302014-05-02 00:34:0839#include "extensions/common/manifest_handlers/incognito_info.h"
ericzeng09a7e002014-09-09 21:43:4740#include "extensions/common/manifest_handlers/options_page_info.h"
[email protected]793964a2013-10-08 00:47:1941#include "extensions/common/permissions/api_permission.h"
[email protected]e4452d32013-11-15 23:07:4142#include "extensions/common/permissions/permissions_data.h"
[email protected]a6483d22013-07-03 22:11:0043#include "url/gurl.h"
[email protected]ac84431b2011-09-27 17:26:1144
[email protected]10f417c52011-12-28 21:04:2345using content::NavigationEntry;
[email protected]26b5e322011-12-23 01:36:4746using content::WebContents;
[email protected]1c4fbc02013-11-13 02:52:4247
48namespace extensions {
[email protected]26b5e322011-12-23 01:36:4749
[email protected]f1c102b2013-02-15 07:44:1250namespace {
51
[email protected]1c4fbc02013-11-13 02:52:4252namespace keys = tabs_constants;
53
[email protected]dbb03fb2014-02-15 05:36:3354WindowController* GetAppWindowController(const WebContents* contents) {
[email protected]f1c102b2013-02-15 07:44:1255 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
hashimotoad3c6872014-08-29 09:46:5756 AppWindowRegistry* registry = AppWindowRegistry::Get(profile);
[email protected]f1c102b2013-02-15 07:44:1257 if (!registry)
58 return NULL;
rdevlin.croninc3d6ba1b12015-07-09 17:36:5959 AppWindow* app_window = registry->GetAppWindowForWebContents(contents);
[email protected]dbb03fb2014-02-15 05:36:3360 if (!app_window)
[email protected]f1c102b2013-02-15 07:44:1261 return NULL;
[email protected]44424542014-01-29 12:10:3162 return WindowControllerList::GetInstance()->FindWindowById(
[email protected]dbb03fb2014-02-15 05:36:3363 app_window->session_id().id());
[email protected]f1c102b2013-02-15 07:44:1264}
65
[email protected]98528302014-05-02 00:34:0866// |error_message| can optionally be passed in and will be set with an
67// appropriate message if the window cannot be found by id.
68Browser* GetBrowserInProfileWithId(Profile* profile,
69 const int window_id,
70 bool include_incognito,
71 std::string* error_message) {
72 Profile* incognito_profile =
73 include_incognito && profile->HasOffTheRecordProfile()
74 ? profile->GetOffTheRecordProfile()
75 : NULL;
76 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
77 Browser* browser = *it;
78 if ((browser->profile() == profile ||
79 browser->profile() == incognito_profile) &&
80 ExtensionTabUtil::GetWindowId(browser) == window_id &&
81 browser->window()) {
82 return browser;
83 }
84 }
85
86 if (error_message)
87 *error_message = ErrorUtils::FormatErrorMessage(
88 keys::kWindowNotFoundError, base::IntToString(window_id));
89
90 return NULL;
91}
92
[email protected]a0c91a9f2014-05-03 03:41:4393Browser* CreateBrowser(ChromeUIThreadExtensionFunction* function,
[email protected]98528302014-05-02 00:34:0894 int window_id,
95 std::string* error) {
96 content::WebContents* web_contents = function->GetAssociatedWebContents();
[email protected]98528302014-05-02 00:34:0897 chrome::HostDesktopType desktop_type =
rpaquayf2ed43c2014-11-05 18:50:5198 web_contents && web_contents->GetNativeView()
99 ? chrome::GetHostDesktopTypeForNativeView(
100 web_contents->GetNativeView())
101 : chrome::GetHostDesktopTypeForNativeView(NULL);
[email protected]98528302014-05-02 00:34:08102 Browser::CreateParams params(
103 Browser::TYPE_TABBED, function->GetProfile(), desktop_type);
104 Browser* browser = new Browser(params);
105 browser->window()->Show();
106 return browser;
107}
108
[email protected]f1c102b2013-02-15 07:44:12109} // namespace
110
[email protected]98528302014-05-02 00:34:08111ExtensionTabUtil::OpenTabParams::OpenTabParams()
112 : create_browser_if_needed(false) {
113}
114
115ExtensionTabUtil::OpenTabParams::~OpenTabParams() {
116}
117
118// Opens a new tab for a given extension. Returns NULL and sets |error| if an
119// error occurs.
120base::DictionaryValue* ExtensionTabUtil::OpenTab(
[email protected]a0c91a9f2014-05-03 03:41:43121 ChromeUIThreadExtensionFunction* function,
[email protected]98528302014-05-02 00:34:08122 const OpenTabParams& params,
123 std::string* error) {
124 // windowId defaults to "current" window.
125 int window_id = extension_misc::kCurrentWindowId;
126 if (params.window_id.get())
127 window_id = *params.window_id;
128
129 Browser* browser = GetBrowserFromWindowID(function, window_id, error);
130 if (!browser) {
131 if (!params.create_browser_if_needed) {
132 return NULL;
133 }
134 browser = CreateBrowser(function, window_id, error);
135 if (!browser)
136 return NULL;
137 }
138
139 // Ensure the selected browser is tabbed.
140 if (!browser->is_type_tabbed() && browser->IsAttemptingToCloseBrowser())
141 browser = chrome::FindTabbedBrowser(function->GetProfile(),
142 function->include_incognito(),
143 browser->host_desktop_type());
144
145 if (!browser || !browser->window()) {
deepak.m121895c012015-05-11 08:11:19146 if (error)
147 *error = keys::kNoCurrentWindowError;
[email protected]98528302014-05-02 00:34:08148 return NULL;
149 }
150
151 // TODO(jstritar): Add a constant, chrome.tabs.TAB_ID_ACTIVE, that
152 // represents the active tab.
153 WebContents* opener = NULL;
154 if (params.opener_tab_id.get()) {
155 int opener_id = *params.opener_tab_id;
156
157 if (!ExtensionTabUtil::GetTabById(opener_id,
158 function->GetProfile(),
159 function->include_incognito(),
160 NULL,
161 NULL,
162 &opener,
163 NULL)) {
deepak.m121895c012015-05-11 08:11:19164 if (error) {
165 *error = ErrorUtils::FormatErrorMessage(keys::kTabNotFoundError,
166 base::IntToString(opener_id));
167 }
[email protected]98528302014-05-02 00:34:08168 return NULL;
169 }
170 }
171
172 // TODO(rafaelw): handle setting remaining tab properties:
173 // -title
174 // -favIconUrl
175
[email protected]98528302014-05-02 00:34:08176 GURL url;
177 if (params.url.get()) {
bokan107a47f2015-02-03 23:23:39178 std::string url_string = *params.url;
[email protected]eba8f7d2014-07-28 22:09:23179 url = ExtensionTabUtil::ResolvePossiblyRelativeURL(url_string,
180 function->extension());
[email protected]98528302014-05-02 00:34:08181 if (!url.is_valid()) {
182 *error =
183 ErrorUtils::FormatErrorMessage(keys::kInvalidUrlError, url_string);
184 return NULL;
185 }
[email protected]f5ec3c922014-05-22 15:04:03186 } else {
187 url = GURL(chrome::kChromeUINewTabURL);
[email protected]98528302014-05-02 00:34:08188 }
189
190 // Don't let extensions crash the browser or renderers.
kalmandfefe1a2015-07-13 22:27:54191 if (ExtensionTabUtil::IsKillURL(url)) {
[email protected]98528302014-05-02 00:34:08192 *error = keys::kNoCrashBrowserError;
193 return NULL;
194 }
195
196 // Default to foreground for the new tab. The presence of 'active' property
197 // will override this default.
198 bool active = true;
199 if (params.active.get())
200 active = *params.active;
201
202 // Default to not pinning the tab. Setting the 'pinned' property to true
203 // will override this default.
204 bool pinned = false;
205 if (params.pinned.get())
206 pinned = *params.pinned;
207
208 // We can't load extension URLs into incognito windows unless the extension
209 // uses split mode. Special case to fall back to a tabbed window.
210 if (url.SchemeIs(kExtensionScheme) &&
[email protected]eba8f7d2014-07-28 22:09:23211 !IncognitoInfo::IsSplitMode(function->extension()) &&
[email protected]98528302014-05-02 00:34:08212 browser->profile()->IsOffTheRecord()) {
213 Profile* profile = browser->profile()->GetOriginalProfile();
214 chrome::HostDesktopType desktop_type = browser->host_desktop_type();
215
216 browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
217 if (!browser) {
218 browser = new Browser(
219 Browser::CreateParams(Browser::TYPE_TABBED, profile, desktop_type));
220 browser->window()->Show();
221 }
222 }
223
224 // If index is specified, honor the value, but keep it bound to
225 // -1 <= index <= tab_strip->count() where -1 invokes the default behavior.
226 int index = -1;
227 if (params.index.get())
228 index = *params.index;
229
230 TabStripModel* tab_strip = browser->tab_strip_model();
231
232 index = std::min(std::max(index, -1), tab_strip->count());
233
234 int add_types = active ? TabStripModel::ADD_ACTIVE : TabStripModel::ADD_NONE;
235 add_types |= TabStripModel::ADD_FORCE_INDEX;
236 if (pinned)
237 add_types |= TabStripModel::ADD_PINNED;
238 chrome::NavigateParams navigate_params(
Sylvain Defresnec6ccc77d2014-09-19 10:19:35239 browser, url, ui::PAGE_TRANSITION_LINK);
[email protected]98528302014-05-02 00:34:08240 navigate_params.disposition =
241 active ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
242 navigate_params.tabstrip_index = index;
243 navigate_params.tabstrip_add_types = add_types;
244 chrome::Navigate(&navigate_params);
245
246 // The tab may have been created in a different window, so make sure we look
247 // at the right tab strip.
248 tab_strip = navigate_params.browser->tab_strip_model();
249 int new_index =
250 tab_strip->GetIndexOfWebContents(navigate_params.target_contents);
251 if (opener)
252 tab_strip->SetOpenerOfWebContentsAt(new_index, opener);
253
254 if (active)
[email protected]fc2b46b2014-05-03 16:33:45255 navigate_params.target_contents->SetInitialFocus();
[email protected]98528302014-05-02 00:34:08256
257 // Return data about the newly created tab.
258 return ExtensionTabUtil::CreateTabValue(navigate_params.target_contents,
259 tab_strip,
260 new_index,
[email protected]eba8f7d2014-07-28 22:09:23261 function->extension());
[email protected]98528302014-05-02 00:34:08262}
263
264Browser* ExtensionTabUtil::GetBrowserFromWindowID(
[email protected]a0c91a9f2014-05-03 03:41:43265 ChromeUIThreadExtensionFunction* function,
[email protected]98528302014-05-02 00:34:08266 int window_id,
267 std::string* error) {
268 if (window_id == extension_misc::kCurrentWindowId) {
269 Browser* result = function->GetCurrentBrowser();
270 if (!result || !result->window()) {
271 if (error)
272 *error = keys::kNoCurrentWindowError;
273 return NULL;
274 }
275 return result;
276 } else {
277 return GetBrowserInProfileWithId(function->GetProfile(),
278 window_id,
279 function->include_incognito(),
280 error);
281 }
282}
283
lfg185333072014-09-09 20:16:11284Browser* ExtensionTabUtil::GetBrowserFromWindowID(
285 const ChromeExtensionFunctionDetails& details,
286 int window_id,
287 std::string* error) {
288 if (window_id == extension_misc::kCurrentWindowId) {
289 Browser* result = details.GetCurrentBrowser();
290 if (!result || !result->window()) {
291 if (error)
292 *error = keys::kNoCurrentWindowError;
293 return NULL;
294 }
295 return result;
296 } else {
297 return GetBrowserInProfileWithId(details.GetProfile(),
298 window_id,
299 details.function()->include_incognito(),
300 error);
301 }
302}
303
[email protected]ac84431b2011-09-27 17:26:11304int ExtensionTabUtil::GetWindowId(const Browser* browser) {
305 return browser->session_id().id();
306}
307
[email protected]8c3495c2011-09-28 03:32:30308int ExtensionTabUtil::GetWindowIdOfTabStripModel(
309 const TabStripModel* tab_strip_model) {
[email protected]3539929f2013-02-01 05:59:14310 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
311 if (it->tab_strip_model() == tab_strip_model)
[email protected]8c3495c2011-09-28 03:32:30312 return GetWindowId(*it);
313 }
314 return -1;
315}
316
[email protected]d2bd5fde2014-05-29 02:24:31317int ExtensionTabUtil::GetTabId(const WebContents* web_contents) {
[email protected]e3f90c602014-08-18 12:41:59318 return SessionTabHelper::IdForTab(web_contents);
[email protected]ac84431b2011-09-27 17:26:11319}
320
321std::string ExtensionTabUtil::GetTabStatusText(bool is_loading) {
322 return is_loading ? keys::kStatusValueLoading : keys::kStatusValueComplete;
323}
324
[email protected]ea049a02011-12-25 21:37:09325int ExtensionTabUtil::GetWindowIdOfTab(const WebContents* web_contents) {
[email protected]e3f90c602014-08-18 12:41:59326 return SessionTabHelper::IdForWindowContainingTab(web_contents);
[email protected]ac84431b2011-09-27 17:26:11327}
328
[email protected]023b3d12013-12-23 18:46:49329base::DictionaryValue* ExtensionTabUtil::CreateTabValue(
[email protected]fc2b46b2014-05-03 16:33:45330 WebContents* contents,
[email protected]0c9f3262012-09-17 05:59:06331 TabStripModel* tab_strip,
332 int tab_index,
[email protected]f34706be2012-09-04 07:32:09333 const Extension* extension) {
[email protected]dbb03fb2014-02-15 05:36:33334 // If we have a matching AppWindow with a controller, get the tab value
[email protected]f1c102b2013-02-15 07:44:12335 // from its controller instead.
[email protected]dbb03fb2014-02-15 05:36:33336 WindowController* controller = GetAppWindowController(contents);
[email protected]f1c102b2013-02-15 07:44:12337 if (controller &&
338 (!extension || controller->IsVisibleToExtension(extension))) {
339 return controller->CreateTabValue(extension, tab_index);
340 }
[email protected]44424542014-01-29 12:10:31341 base::DictionaryValue* result =
[email protected]023b3d12013-12-23 18:46:49342 CreateTabValue(contents, tab_strip, tab_index);
[email protected]304fd152013-01-12 16:54:44343 ScrubTabValueForExtension(contents, extension, result);
344 return result;
[email protected]ac84431b2011-09-27 17:26:11345}
346
[email protected]aeca23f2013-06-21 22:34:41347base::ListValue* ExtensionTabUtil::CreateTabList(
[email protected]f34706be2012-09-04 07:32:09348 const Browser* browser,
349 const Extension* extension) {
[email protected]aeca23f2013-06-21 22:34:41350 base::ListValue* tab_list = new base::ListValue();
[email protected]c0849252012-05-12 13:51:27351 TabStripModel* tab_strip = browser->tab_strip_model();
[email protected]ac84431b2011-09-27 17:26:11352 for (int i = 0; i < tab_strip->count(); ++i) {
[email protected]72f67972012-10-30 18:53:28353 tab_list->Append(CreateTabValue(tab_strip->GetWebContentsAt(i),
354 tab_strip,
355 i,
356 extension));
[email protected]ac84431b2011-09-27 17:26:11357 }
358
359 return tab_list;
360}
361
[email protected]023b3d12013-12-23 18:46:49362base::DictionaryValue* ExtensionTabUtil::CreateTabValue(
[email protected]fc2b46b2014-05-03 16:33:45363 WebContents* contents,
[email protected]f34706be2012-09-04 07:32:09364 TabStripModel* tab_strip,
[email protected]304fd152013-01-12 16:54:44365 int tab_index) {
[email protected]dbb03fb2014-02-15 05:36:33366 // If we have a matching AppWindow with a controller, get the tab value
[email protected]f1c102b2013-02-15 07:44:12367 // from its controller instead.
[email protected]dbb03fb2014-02-15 05:36:33368 WindowController* controller = GetAppWindowController(contents);
[email protected]f1c102b2013-02-15 07:44:12369 if (controller)
370 return controller->CreateTabValue(NULL, tab_index);
371
[email protected]0c9f3262012-09-17 05:59:06372 if (!tab_strip)
373 ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index);
374
[email protected]023b3d12013-12-23 18:46:49375 base::DictionaryValue* result = new base::DictionaryValue();
[email protected]ac84431b2011-09-27 17:26:11376 bool is_loading = contents->IsLoading();
[email protected]f34706be2012-09-04 07:32:09377 result->SetInteger(keys::kIdKey, GetTabId(contents));
[email protected]ac84431b2011-09-27 17:26:11378 result->SetInteger(keys::kIndexKey, tab_index);
[email protected]f34706be2012-09-04 07:32:09379 result->SetInteger(keys::kWindowIdKey, GetWindowIdOfTab(contents));
[email protected]ac84431b2011-09-27 17:26:11380 result->SetString(keys::kStatusKey, GetTabStatusText(is_loading));
[email protected]8c3495c2011-09-28 03:32:30381 result->SetBoolean(keys::kActiveKey,
382 tab_strip && tab_index == tab_strip->active_index());
[email protected]ac84431b2011-09-27 17:26:11383 result->SetBoolean(keys::kSelectedKey,
384 tab_strip && tab_index == tab_strip->active_index());
[email protected]8c3495c2011-09-28 03:32:30385 result->SetBoolean(keys::kHighlightedKey,
386 tab_strip && tab_strip->IsTabSelected(tab_index));
[email protected]ac84431b2011-09-27 17:26:11387 result->SetBoolean(keys::kPinnedKey,
388 tab_strip && tab_strip->IsTabPinned(tab_index));
jared.sohn09a3ccc2015-07-09 03:47:30389 result->SetBoolean(keys::kAudibleKey,
390 tab_strip && chrome::IsPlayingAudio(contents));
391 result->SetBoolean(keys::kMutedKey,
392 tab_strip && chrome::IsTabAudioMuted(contents));
393 result->SetString(keys::kMutedCauseKey,
394 chrome::GetTabAudioMutedCause(contents));
[email protected]ac84431b2011-09-27 17:26:11395 result->SetBoolean(keys::kIncognitoKey,
[email protected]627e0512011-12-21 22:55:30396 contents->GetBrowserContext()->IsOffTheRecord());
[email protected]a16a5a52013-08-16 17:23:35397 result->SetInteger(keys::kWidthKey,
[email protected]fc2b46b2014-05-03 16:33:45398 contents->GetContainerBounds().size().width());
[email protected]a16a5a52013-08-16 17:23:35399 result->SetInteger(keys::kHeightKey,
[email protected]fc2b46b2014-05-03 16:33:45400 contents->GetContainerBounds().size().height());
[email protected]ac84431b2011-09-27 17:26:11401
[email protected]304fd152013-01-12 16:54:44402 // Privacy-sensitive fields: these should be stripped off by
403 // ScrubTabValueForExtension if the extension should not see them.
404 result->SetString(keys::kUrlKey, contents->GetURL().spec());
405 result->SetString(keys::kTitleKey, contents->GetTitle());
406 if (!is_loading) {
[email protected]afe9aba2013-08-16 20:31:34407 NavigationEntry* entry = contents->GetController().GetVisibleEntry();
[email protected]304fd152013-01-12 16:54:44408 if (entry && entry->GetFavicon().valid)
409 result->SetString(keys::kFaviconUrlKey, entry->GetFavicon().url.spec());
[email protected]f34706be2012-09-04 07:32:09410 }
411
[email protected]327640a2012-01-24 21:57:59412 if (tab_strip) {
[email protected]67075402012-10-26 08:26:25413 WebContents* opener = tab_strip->GetOpenerOfWebContentsAt(tab_index);
414 if (opener)
415 result->SetInteger(keys::kOpenerTabIdKey, GetTabId(opener));
[email protected]ac84431b2011-09-27 17:26:11416 }
417
418 return result;
419}
420
[email protected]023b3d12013-12-23 18:46:49421void ExtensionTabUtil::ScrubTabValueForExtension(
[email protected]fc2b46b2014-05-03 16:33:45422 WebContents* contents,
[email protected]023b3d12013-12-23 18:46:49423 const Extension* extension,
424 base::DictionaryValue* tab_info) {
[email protected]a6910e72014-06-06 05:04:36425 bool has_permission = extension &&
426 extension->permissions_data()->HasAPIPermissionForTab(
427 GetTabId(contents), APIPermission::kTab);
[email protected]304fd152013-01-12 16:54:44428
429 if (!has_permission) {
430 tab_info->Remove(keys::kUrlKey, NULL);
431 tab_info->Remove(keys::kTitleKey, NULL);
432 tab_info->Remove(keys::kFaviconUrlKey, NULL);
433 }
434}
435
[email protected]ab3f61412013-01-29 21:55:07436void ExtensionTabUtil::ScrubTabForExtension(const Extension* extension,
[email protected]1c4fbc02013-11-13 02:52:42437 api::tabs::Tab* tab) {
[email protected]076ebeda2014-06-06 21:47:26438 bool has_permission =
439 extension &&
440 extension->permissions_data()->HasAPIPermission(APIPermission::kTab);
[email protected]ab3f61412013-01-29 21:55:07441
442 if (!has_permission) {
443 tab->url.reset();
444 tab->title.reset();
445 tab->fav_icon_url.reset();
446 }
447}
448
[email protected]ea049a02011-12-25 21:37:09449bool ExtensionTabUtil::GetTabStripModel(const WebContents* web_contents,
[email protected]ac84431b2011-09-27 17:26:11450 TabStripModel** tab_strip_model,
451 int* tab_index) {
[email protected]ea049a02011-12-25 21:37:09452 DCHECK(web_contents);
[email protected]ac84431b2011-09-27 17:26:11453 DCHECK(tab_strip_model);
454 DCHECK(tab_index);
455
[email protected]3539929f2013-02-01 05:59:14456 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
457 TabStripModel* tab_strip = it->tab_strip_model();
[email protected]e52d0a42012-06-08 22:44:16458 int index = tab_strip->GetIndexOfWebContents(web_contents);
[email protected]ac84431b2011-09-27 17:26:11459 if (index != -1) {
460 *tab_strip_model = tab_strip;
461 *tab_index = index;
462 return true;
463 }
464 }
465
466 return false;
467}
468
469bool ExtensionTabUtil::GetDefaultTab(Browser* browser,
[email protected]72f67972012-10-30 18:53:28470 WebContents** contents,
[email protected]ac84431b2011-09-27 17:26:11471 int* tab_id) {
472 DCHECK(browser);
473 DCHECK(contents);
474
[email protected]617ee962013-01-29 20:49:12475 *contents = browser->tab_strip_model()->GetActiveWebContents();
[email protected]ac84431b2011-09-27 17:26:11476 if (*contents) {
477 if (tab_id)
[email protected]72f67972012-10-30 18:53:28478 *tab_id = GetTabId(*contents);
[email protected]ac84431b2011-09-27 17:26:11479 return true;
480 }
481
482 return false;
483}
484
485bool ExtensionTabUtil::GetTabById(int tab_id,
wjmaclean5b11eee2014-09-05 00:55:14486 content::BrowserContext* browser_context,
[email protected]ac84431b2011-09-27 17:26:11487 bool include_incognito,
488 Browser** browser,
489 TabStripModel** tab_strip,
[email protected]72f67972012-10-30 18:53:28490 WebContents** contents,
[email protected]ac84431b2011-09-27 17:26:11491 int* tab_index) {
wjmaclean5b11eee2014-09-05 00:55:14492 Profile* profile = Profile::FromBrowserContext(browser_context);
[email protected]ac84431b2011-09-27 17:26:11493 Profile* incognito_profile =
494 include_incognito && profile->HasOffTheRecordProfile() ?
495 profile->GetOffTheRecordProfile() : NULL;
[email protected]3539929f2013-02-01 05:59:14496 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
497 Browser* target_browser = *it;
[email protected]ac84431b2011-09-27 17:26:11498 if (target_browser->profile() == profile ||
499 target_browser->profile() == incognito_profile) {
[email protected]c0849252012-05-12 13:51:27500 TabStripModel* target_tab_strip = target_browser->tab_strip_model();
[email protected]ac84431b2011-09-27 17:26:11501 for (int i = 0; i < target_tab_strip->count(); ++i) {
[email protected]72f67972012-10-30 18:53:28502 WebContents* target_contents = target_tab_strip->GetWebContentsAt(i);
[email protected]e3f90c602014-08-18 12:41:59503 if (SessionTabHelper::IdForTab(target_contents) == tab_id) {
[email protected]ac84431b2011-09-27 17:26:11504 if (browser)
505 *browser = target_browser;
506 if (tab_strip)
507 *tab_strip = target_tab_strip;
508 if (contents)
509 *contents = target_contents;
510 if (tab_index)
511 *tab_index = i;
512 return true;
513 }
514 }
515 }
516 }
517 return false;
518}
[email protected]45c75e62012-03-21 19:56:35519
520GURL ExtensionTabUtil::ResolvePossiblyRelativeURL(const std::string& url_string,
[email protected]1c4fbc02013-11-13 02:52:42521 const Extension* extension) {
[email protected]45c75e62012-03-21 19:56:35522 GURL url = GURL(url_string);
523 if (!url.is_valid())
524 url = extension->GetResourceURL(url_string);
525
526 return url;
527}
528
kalmandfefe1a2015-07-13 22:27:54529bool ExtensionTabUtil::IsKillURL(const GURL& url) {
530 static const char* kill_hosts[] = {
531 chrome::kChromeUICrashHost,
532 chrome::kChromeUIHangUIHost,
533 chrome::kChromeUIKillHost,
534 chrome::kChromeUIQuitHost,
535 chrome::kChromeUIRestartHost,
536 content::kChromeUIBrowserCrashHost,
537 };
538
[email protected]45c75e62012-03-21 19:56:35539 // Check a fixed-up URL, to normalize the scheme and parse hosts correctly.
540 GURL fixed_url =
[email protected]9b5b1d602014-06-12 14:29:02541 url_fixer::FixupURL(url.possibly_invalid_spec(), std::string());
kalmandfefe1a2015-07-13 22:27:54542 if (!fixed_url.SchemeIs(content::kChromeUIScheme))
543 return false;
544
545 for (size_t i = 0; i < arraysize(kill_hosts); ++i) {
546 if (fixed_url.host() == kill_hosts[i])
547 return true;
548 }
549
550 return false;
[email protected]45c75e62012-03-21 19:56:35551}
[email protected]73c1a6842012-07-13 17:39:04552
553void ExtensionTabUtil::CreateTab(WebContents* web_contents,
554 const std::string& extension_id,
555 WindowOpenDisposition disposition,
bokan107a47f2015-02-03 23:23:39556 const gfx::Rect& initial_rect,
[email protected]73c1a6842012-07-13 17:39:04557 bool user_gesture) {
[email protected]73c1a6842012-07-13 17:39:04558 Profile* profile =
559 Profile::FromBrowserContext(web_contents->GetBrowserContext());
[email protected]435d43e02012-12-09 09:13:55560 chrome::HostDesktopType active_desktop = chrome::GetActiveDesktop();
[email protected]75072732013-01-09 13:39:25561 Browser* browser = chrome::FindTabbedBrowser(profile, false, active_desktop);
[email protected]2764cab72012-07-19 17:02:10562 const bool browser_created = !browser;
563 if (!browser)
[email protected]435d43e02012-12-09 09:13:55564 browser = new Browser(Browser::CreateParams(profile, active_desktop));
[email protected]e232c992012-12-06 12:43:20565 chrome::NavigateParams params(browser, web_contents);
[email protected]73c1a6842012-07-13 17:39:04566
567 // The extension_app_id parameter ends up as app_name in the Browser
568 // which causes the Browser to return true for is_app(). This affects
569 // among other things, whether the location bar gets displayed.
570 // TODO(mpcomplete): This seems wrong. What if the extension content is hosted
571 // in a tab?
572 if (disposition == NEW_POPUP)
573 params.extension_app_id = extension_id;
574
[email protected]73c1a6842012-07-13 17:39:04575 params.disposition = disposition;
bokan107a47f2015-02-03 23:23:39576 params.window_bounds = initial_rect;
[email protected]73c1a6842012-07-13 17:39:04577 params.window_action = chrome::NavigateParams::SHOW_WINDOW;
578 params.user_gesture = user_gesture;
579 chrome::Navigate(&params);
[email protected]2764cab72012-07-19 17:02:10580
581 // Close the browser if chrome::Navigate created a new one.
582 if (browser_created && (browser != params.browser))
583 browser->window()->Close();
[email protected]73c1a6842012-07-13 17:39:04584}
[email protected]44e329a2012-07-14 01:13:06585
586// static
587void ExtensionTabUtil::ForEachTab(
588 const base::Callback<void(WebContents*)>& callback) {
[email protected]b031ff82013-01-29 22:53:16589 for (TabContentsIterator iterator; !iterator.done(); iterator.Next())
[email protected]f8073562012-12-06 12:43:53590 callback.Run(*iterator);
[email protected]44e329a2012-07-14 01:13:06591}
[email protected]e9570fdf2012-07-18 20:01:21592
593// static
[email protected]1c4fbc02013-11-13 02:52:42594WindowController* ExtensionTabUtil::GetWindowControllerOfTab(
[email protected]e9570fdf2012-07-18 20:01:21595 const WebContents* web_contents) {
[email protected]f7b4b9e2012-12-02 07:43:17596 Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
[email protected]e9570fdf2012-07-18 20:01:21597 if (browser != NULL)
598 return browser->extension_window_controller();
599
600 return NULL;
601}
[email protected]695089782013-04-09 16:03:17602
kalmance22c472015-02-19 02:31:43603bool ExtensionTabUtil::OpenOptionsPage(const Extension* extension,
[email protected]695089782013-04-09 16:03:17604 Browser* browser) {
kalmance22c472015-02-19 02:31:43605 if (!OptionsPageInfo::HasOptionsPage(extension))
606 return false;
[email protected]695089782013-04-09 16:03:17607
608 // Force the options page to open in non-OTR window, because it won't be
609 // able to save settings from OTR.
[email protected]0edcdec2013-10-31 06:43:08610 scoped_ptr<chrome::ScopedTabbedBrowserDisplayer> displayer;
[email protected]695089782013-04-09 16:03:17611 if (browser->profile()->IsOffTheRecord()) {
[email protected]0edcdec2013-10-31 06:43:08612 displayer.reset(new chrome::ScopedTabbedBrowserDisplayer(
613 browser->profile()->GetOriginalProfile(),
614 browser->host_desktop_type()));
615 browser = displayer->browser();
[email protected]695089782013-04-09 16:03:17616 }
617
kalman4427c252015-03-13 01:55:48618 GURL url_to_navigate;
619 if (OptionsPageInfo::ShouldOpenInTab(extension)) {
620 // Options page tab is simply e.g. chrome-extension://.../options.html.
621 url_to_navigate = OptionsPageInfo::GetOptionsPage(extension);
622 } else {
623 // Options page tab is Extension settings pointed at that Extension's ID,
624 // e.g. chrome://extensions?options=...
625 url_to_navigate = GURL(chrome::kChromeUIExtensionsURL);
ericzengf97b7c22014-08-26 03:07:30626 GURL::Replacements replacements;
627 std::string query =
628 base::StringPrintf("options=%s", extension->id().c_str());
629 replacements.SetQueryStr(query);
kalman4427c252015-03-13 01:55:48630 url_to_navigate = url_to_navigate.ReplaceComponents(replacements);
ericzengf97b7c22014-08-26 03:07:30631 }
kalmance22c472015-02-19 02:31:43632
kalman4427c252015-03-13 01:55:48633 chrome::NavigateParams params(
634 chrome::GetSingletonTabNavigateParams(browser, url_to_navigate));
635 params.path_behavior = chrome::NavigateParams::IGNORE_AND_NAVIGATE;
636 params.url = url_to_navigate;
637 chrome::ShowSingletonTabOverwritingNTP(browser, params);
kalmance22c472015-02-19 02:31:43638 return true;
[email protected]695089782013-04-09 16:03:17639}
[email protected]1c4fbc02013-11-13 02:52:42640
641} // namespace extensions