blob: 1537a33e8ed4d0b4f06d9a57fcd96724029f4ca0 [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]dbb03fb2014-02-15 05:36:337#include "apps/app_window.h"
8#include "apps/app_window_registry.h"
[email protected]98528302014-05-02 00:34:089#include "base/strings/string_number_conversions.h"
[email protected]b19451b2012-06-08 17:36:1910#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
[email protected]98528302014-05-02 00:34:0811#include "chrome/browser/extensions/chrome_extension_function.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]1034cb42012-07-17 08:37:5416#include "chrome/browser/sessions/session_id.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"
[email protected]44e329a2012-07-14 01:13:0622#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
[email protected]b56e2e32012-05-11 21:18:0423#include "chrome/browser/ui/tabs/tab_strip_model.h"
[email protected]695089782013-04-09 16:03:1724#include "chrome/common/extensions/manifest_url_handler.h"
[email protected]4f3b4462013-07-27 19:20:1825#include "chrome/common/net/url_fixer_upper.h"
[email protected]45c75e62012-03-21 19:56:3526#include "chrome/common/url_constants.h"
[email protected]ad23a092011-12-28 07:02:0427#include "content/public/browser/favicon_status.h"
28#include "content/public/browser/navigation_entry.h"
[email protected]6acde6352012-01-04 16:52:2029#include "content/public/browser/web_contents.h"
[email protected]a16a5a52013-08-16 17:23:3530#include "content/public/browser/web_contents_view.h"
[email protected]98528302014-05-02 00:34:0831#include "extensions/common/constants.h"
32#include "extensions/common/error_utils.h"
[email protected]e4452d32013-11-15 23:07:4133#include "extensions/common/extension.h"
[email protected]0c3c9732013-09-16 08:53:4134#include "extensions/common/manifest_constants.h"
[email protected]98528302014-05-02 00:34:0835#include "extensions/common/manifest_handlers/incognito_info.h"
[email protected]793964a2013-10-08 00:47:1936#include "extensions/common/permissions/api_permission.h"
[email protected]e4452d32013-11-15 23:07:4137#include "extensions/common/permissions/permissions_data.h"
[email protected]a6483d22013-07-03 22:11:0038#include "url/gurl.h"
[email protected]ac84431b2011-09-27 17:26:1139
[email protected]dbb03fb2014-02-15 05:36:3340using apps::AppWindow;
[email protected]10f417c52011-12-28 21:04:2341using content::NavigationEntry;
[email protected]26b5e322011-12-23 01:36:4742using content::WebContents;
[email protected]1c4fbc02013-11-13 02:52:4243
44namespace extensions {
[email protected]26b5e322011-12-23 01:36:4745
[email protected]f1c102b2013-02-15 07:44:1246namespace {
47
[email protected]1c4fbc02013-11-13 02:52:4248namespace keys = tabs_constants;
49
[email protected]dbb03fb2014-02-15 05:36:3350WindowController* GetAppWindowController(const WebContents* contents) {
[email protected]f1c102b2013-02-15 07:44:1251 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
[email protected]dbb03fb2014-02-15 05:36:3352 apps::AppWindowRegistry* registry = apps::AppWindowRegistry::Get(profile);
[email protected]f1c102b2013-02-15 07:44:1253 if (!registry)
54 return NULL;
[email protected]dbb03fb2014-02-15 05:36:3355 AppWindow* app_window =
56 registry->GetAppWindowForRenderViewHost(contents->GetRenderViewHost());
57 if (!app_window)
[email protected]f1c102b2013-02-15 07:44:1258 return NULL;
[email protected]44424542014-01-29 12:10:3159 return WindowControllerList::GetInstance()->FindWindowById(
[email protected]dbb03fb2014-02-15 05:36:3360 app_window->session_id().id());
[email protected]f1c102b2013-02-15 07:44:1261}
62
[email protected]98528302014-05-02 00:34:0863// |error_message| can optionally be passed in and will be set with an
64// appropriate message if the window cannot be found by id.
65Browser* GetBrowserInProfileWithId(Profile* profile,
66 const int window_id,
67 bool include_incognito,
68 std::string* error_message) {
69 Profile* incognito_profile =
70 include_incognito && profile->HasOffTheRecordProfile()
71 ? profile->GetOffTheRecordProfile()
72 : NULL;
73 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
74 Browser* browser = *it;
75 if ((browser->profile() == profile ||
76 browser->profile() == incognito_profile) &&
77 ExtensionTabUtil::GetWindowId(browser) == window_id &&
78 browser->window()) {
79 return browser;
80 }
81 }
82
83 if (error_message)
84 *error_message = ErrorUtils::FormatErrorMessage(
85 keys::kWindowNotFoundError, base::IntToString(window_id));
86
87 return NULL;
88}
89
90Browser* CreateBrowser(ChromeAsyncExtensionFunction* function,
91 int window_id,
92 std::string* error) {
93 content::WebContents* web_contents = function->GetAssociatedWebContents();
94 DCHECK(web_contents);
95 DCHECK(web_contents->GetView());
96 DCHECK(web_contents->GetView()->GetNativeView());
97 DCHECK(!chrome::FindBrowserWithWebContents(web_contents));
98
99 chrome::HostDesktopType desktop_type =
100 chrome::GetHostDesktopTypeForNativeView(
101 web_contents->GetView()->GetNativeView());
102 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(
121 ChromeAsyncExtensionFunction* function,
122 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()) {
146 // TODO(rpaquay): Error message?
147 return NULL;
148 }
149
150 // TODO(jstritar): Add a constant, chrome.tabs.TAB_ID_ACTIVE, that
151 // represents the active tab.
152 WebContents* opener = NULL;
153 if (params.opener_tab_id.get()) {
154 int opener_id = *params.opener_tab_id;
155
156 if (!ExtensionTabUtil::GetTabById(opener_id,
157 function->GetProfile(),
158 function->include_incognito(),
159 NULL,
160 NULL,
161 &opener,
162 NULL)) {
163 // TODO(rpaquay): Error message?
164 return NULL;
165 }
166 }
167
168 // TODO(rafaelw): handle setting remaining tab properties:
169 // -title
170 // -favIconUrl
171
172 std::string url_string;
173 GURL url;
174 if (params.url.get()) {
175 url_string = *params.url;
176 url = ExtensionTabUtil::ResolvePossiblyRelativeURL(
177 url_string, function->GetExtension());
178 if (!url.is_valid()) {
179 *error =
180 ErrorUtils::FormatErrorMessage(keys::kInvalidUrlError, url_string);
181 return NULL;
182 }
183 }
184
185 // Don't let extensions crash the browser or renderers.
186 if (ExtensionTabUtil::IsCrashURL(url)) {
187 *error = keys::kNoCrashBrowserError;
188 return NULL;
189 }
190
191 // Default to foreground for the new tab. The presence of 'active' property
192 // will override this default.
193 bool active = true;
194 if (params.active.get())
195 active = *params.active;
196
197 // Default to not pinning the tab. Setting the 'pinned' property to true
198 // will override this default.
199 bool pinned = false;
200 if (params.pinned.get())
201 pinned = *params.pinned;
202
203 // We can't load extension URLs into incognito windows unless the extension
204 // uses split mode. Special case to fall back to a tabbed window.
205 if (url.SchemeIs(kExtensionScheme) &&
206 !IncognitoInfo::IsSplitMode(function->GetExtension()) &&
207 browser->profile()->IsOffTheRecord()) {
208 Profile* profile = browser->profile()->GetOriginalProfile();
209 chrome::HostDesktopType desktop_type = browser->host_desktop_type();
210
211 browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
212 if (!browser) {
213 browser = new Browser(
214 Browser::CreateParams(Browser::TYPE_TABBED, profile, desktop_type));
215 browser->window()->Show();
216 }
217 }
218
219 // If index is specified, honor the value, but keep it bound to
220 // -1 <= index <= tab_strip->count() where -1 invokes the default behavior.
221 int index = -1;
222 if (params.index.get())
223 index = *params.index;
224
225 TabStripModel* tab_strip = browser->tab_strip_model();
226
227 index = std::min(std::max(index, -1), tab_strip->count());
228
229 int add_types = active ? TabStripModel::ADD_ACTIVE : TabStripModel::ADD_NONE;
230 add_types |= TabStripModel::ADD_FORCE_INDEX;
231 if (pinned)
232 add_types |= TabStripModel::ADD_PINNED;
233 chrome::NavigateParams navigate_params(
234 browser, url, content::PAGE_TRANSITION_LINK);
235 navigate_params.disposition =
236 active ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
237 navigate_params.tabstrip_index = index;
238 navigate_params.tabstrip_add_types = add_types;
239 chrome::Navigate(&navigate_params);
240
241 // The tab may have been created in a different window, so make sure we look
242 // at the right tab strip.
243 tab_strip = navigate_params.browser->tab_strip_model();
244 int new_index =
245 tab_strip->GetIndexOfWebContents(navigate_params.target_contents);
246 if (opener)
247 tab_strip->SetOpenerOfWebContentsAt(new_index, opener);
248
249 if (active)
250 navigate_params.target_contents->GetView()->SetInitialFocus();
251
252 // Return data about the newly created tab.
253 return ExtensionTabUtil::CreateTabValue(navigate_params.target_contents,
254 tab_strip,
255 new_index,
256 function->GetExtension());
257}
258
259Browser* ExtensionTabUtil::GetBrowserFromWindowID(
260 ChromeAsyncExtensionFunction* function,
261 int window_id,
262 std::string* error) {
263 if (window_id == extension_misc::kCurrentWindowId) {
264 Browser* result = function->GetCurrentBrowser();
265 if (!result || !result->window()) {
266 if (error)
267 *error = keys::kNoCurrentWindowError;
268 return NULL;
269 }
270 return result;
271 } else {
272 return GetBrowserInProfileWithId(function->GetProfile(),
273 window_id,
274 function->include_incognito(),
275 error);
276 }
277}
278
[email protected]ac84431b2011-09-27 17:26:11279int ExtensionTabUtil::GetWindowId(const Browser* browser) {
280 return browser->session_id().id();
281}
282
[email protected]8c3495c2011-09-28 03:32:30283int ExtensionTabUtil::GetWindowIdOfTabStripModel(
284 const TabStripModel* tab_strip_model) {
[email protected]3539929f2013-02-01 05:59:14285 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
286 if (it->tab_strip_model() == tab_strip_model)
[email protected]8c3495c2011-09-28 03:32:30287 return GetWindowId(*it);
288 }
289 return -1;
290}
291
[email protected]26b5e322011-12-23 01:36:47292int ExtensionTabUtil::GetTabId(const WebContents* web_contents) {
[email protected]554e41e2012-09-10 20:21:42293 return SessionID::IdForTab(web_contents);
[email protected]ac84431b2011-09-27 17:26:11294}
295
296std::string ExtensionTabUtil::GetTabStatusText(bool is_loading) {
297 return is_loading ? keys::kStatusValueLoading : keys::kStatusValueComplete;
298}
299
[email protected]ea049a02011-12-25 21:37:09300int ExtensionTabUtil::GetWindowIdOfTab(const WebContents* web_contents) {
[email protected]554e41e2012-09-10 20:21:42301 return SessionID::IdForWindowContainingTab(web_contents);
[email protected]ac84431b2011-09-27 17:26:11302}
303
[email protected]023b3d12013-12-23 18:46:49304base::DictionaryValue* ExtensionTabUtil::CreateTabValue(
[email protected]f34706be2012-09-04 07:32:09305 const WebContents* contents,
[email protected]0c9f3262012-09-17 05:59:06306 TabStripModel* tab_strip,
307 int tab_index,
[email protected]f34706be2012-09-04 07:32:09308 const Extension* extension) {
[email protected]dbb03fb2014-02-15 05:36:33309 // If we have a matching AppWindow with a controller, get the tab value
[email protected]f1c102b2013-02-15 07:44:12310 // from its controller instead.
[email protected]dbb03fb2014-02-15 05:36:33311 WindowController* controller = GetAppWindowController(contents);
[email protected]f1c102b2013-02-15 07:44:12312 if (controller &&
313 (!extension || controller->IsVisibleToExtension(extension))) {
314 return controller->CreateTabValue(extension, tab_index);
315 }
[email protected]44424542014-01-29 12:10:31316 base::DictionaryValue* result =
[email protected]023b3d12013-12-23 18:46:49317 CreateTabValue(contents, tab_strip, tab_index);
[email protected]304fd152013-01-12 16:54:44318 ScrubTabValueForExtension(contents, extension, result);
319 return result;
[email protected]ac84431b2011-09-27 17:26:11320}
321
[email protected]aeca23f2013-06-21 22:34:41322base::ListValue* ExtensionTabUtil::CreateTabList(
[email protected]f34706be2012-09-04 07:32:09323 const Browser* browser,
324 const Extension* extension) {
[email protected]aeca23f2013-06-21 22:34:41325 base::ListValue* tab_list = new base::ListValue();
[email protected]c0849252012-05-12 13:51:27326 TabStripModel* tab_strip = browser->tab_strip_model();
[email protected]ac84431b2011-09-27 17:26:11327 for (int i = 0; i < tab_strip->count(); ++i) {
[email protected]72f67972012-10-30 18:53:28328 tab_list->Append(CreateTabValue(tab_strip->GetWebContentsAt(i),
329 tab_strip,
330 i,
331 extension));
[email protected]ac84431b2011-09-27 17:26:11332 }
333
334 return tab_list;
335}
336
[email protected]023b3d12013-12-23 18:46:49337base::DictionaryValue* ExtensionTabUtil::CreateTabValue(
[email protected]f34706be2012-09-04 07:32:09338 const WebContents* contents,
339 TabStripModel* tab_strip,
[email protected]304fd152013-01-12 16:54:44340 int tab_index) {
[email protected]dbb03fb2014-02-15 05:36:33341 // If we have a matching AppWindow with a controller, get the tab value
[email protected]f1c102b2013-02-15 07:44:12342 // from its controller instead.
[email protected]dbb03fb2014-02-15 05:36:33343 WindowController* controller = GetAppWindowController(contents);
[email protected]f1c102b2013-02-15 07:44:12344 if (controller)
345 return controller->CreateTabValue(NULL, tab_index);
346
[email protected]0c9f3262012-09-17 05:59:06347 if (!tab_strip)
348 ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index);
349
[email protected]023b3d12013-12-23 18:46:49350 base::DictionaryValue* result = new base::DictionaryValue();
[email protected]ac84431b2011-09-27 17:26:11351 bool is_loading = contents->IsLoading();
[email protected]f34706be2012-09-04 07:32:09352 result->SetInteger(keys::kIdKey, GetTabId(contents));
[email protected]ac84431b2011-09-27 17:26:11353 result->SetInteger(keys::kIndexKey, tab_index);
[email protected]f34706be2012-09-04 07:32:09354 result->SetInteger(keys::kWindowIdKey, GetWindowIdOfTab(contents));
[email protected]ac84431b2011-09-27 17:26:11355 result->SetString(keys::kStatusKey, GetTabStatusText(is_loading));
[email protected]8c3495c2011-09-28 03:32:30356 result->SetBoolean(keys::kActiveKey,
357 tab_strip && tab_index == tab_strip->active_index());
[email protected]ac84431b2011-09-27 17:26:11358 result->SetBoolean(keys::kSelectedKey,
359 tab_strip && tab_index == tab_strip->active_index());
[email protected]8c3495c2011-09-28 03:32:30360 result->SetBoolean(keys::kHighlightedKey,
361 tab_strip && tab_strip->IsTabSelected(tab_index));
[email protected]ac84431b2011-09-27 17:26:11362 result->SetBoolean(keys::kPinnedKey,
363 tab_strip && tab_strip->IsTabPinned(tab_index));
[email protected]ac84431b2011-09-27 17:26:11364 result->SetBoolean(keys::kIncognitoKey,
[email protected]627e0512011-12-21 22:55:30365 contents->GetBrowserContext()->IsOffTheRecord());
[email protected]a16a5a52013-08-16 17:23:35366 result->SetInteger(keys::kWidthKey,
367 contents->GetView()->GetContainerSize().width());
368 result->SetInteger(keys::kHeightKey,
369 contents->GetView()->GetContainerSize().height());
[email protected]ac84431b2011-09-27 17:26:11370
[email protected]304fd152013-01-12 16:54:44371 // Privacy-sensitive fields: these should be stripped off by
372 // ScrubTabValueForExtension if the extension should not see them.
373 result->SetString(keys::kUrlKey, contents->GetURL().spec());
374 result->SetString(keys::kTitleKey, contents->GetTitle());
375 if (!is_loading) {
[email protected]afe9aba2013-08-16 20:31:34376 NavigationEntry* entry = contents->GetController().GetVisibleEntry();
[email protected]304fd152013-01-12 16:54:44377 if (entry && entry->GetFavicon().valid)
378 result->SetString(keys::kFaviconUrlKey, entry->GetFavicon().url.spec());
[email protected]f34706be2012-09-04 07:32:09379 }
380
[email protected]327640a2012-01-24 21:57:59381 if (tab_strip) {
[email protected]67075402012-10-26 08:26:25382 WebContents* opener = tab_strip->GetOpenerOfWebContentsAt(tab_index);
383 if (opener)
384 result->SetInteger(keys::kOpenerTabIdKey, GetTabId(opener));
[email protected]ac84431b2011-09-27 17:26:11385 }
386
387 return result;
388}
389
[email protected]023b3d12013-12-23 18:46:49390void ExtensionTabUtil::ScrubTabValueForExtension(
391 const WebContents* contents,
392 const Extension* extension,
393 base::DictionaryValue* tab_info) {
[email protected]13c68b62013-05-17 11:29:05394 bool has_permission =
395 extension &&
[email protected]1c4fbc02013-11-13 02:52:42396 PermissionsData::HasAPIPermissionForTab(
[email protected]13c68b62013-05-17 11:29:05397 extension, GetTabId(contents), APIPermission::kTab);
[email protected]304fd152013-01-12 16:54:44398
399 if (!has_permission) {
400 tab_info->Remove(keys::kUrlKey, NULL);
401 tab_info->Remove(keys::kTitleKey, NULL);
402 tab_info->Remove(keys::kFaviconUrlKey, NULL);
403 }
404}
405
[email protected]ab3f61412013-01-29 21:55:07406void ExtensionTabUtil::ScrubTabForExtension(const Extension* extension,
[email protected]1c4fbc02013-11-13 02:52:42407 api::tabs::Tab* tab) {
[email protected]ab3f61412013-01-29 21:55:07408 bool has_permission = extension && extension->HasAPIPermission(
409 APIPermission::kTab);
410
411 if (!has_permission) {
412 tab->url.reset();
413 tab->title.reset();
414 tab->fav_icon_url.reset();
415 }
416}
417
[email protected]ea049a02011-12-25 21:37:09418bool ExtensionTabUtil::GetTabStripModel(const WebContents* web_contents,
[email protected]ac84431b2011-09-27 17:26:11419 TabStripModel** tab_strip_model,
420 int* tab_index) {
[email protected]ea049a02011-12-25 21:37:09421 DCHECK(web_contents);
[email protected]ac84431b2011-09-27 17:26:11422 DCHECK(tab_strip_model);
423 DCHECK(tab_index);
424
[email protected]3539929f2013-02-01 05:59:14425 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
426 TabStripModel* tab_strip = it->tab_strip_model();
[email protected]e52d0a42012-06-08 22:44:16427 int index = tab_strip->GetIndexOfWebContents(web_contents);
[email protected]ac84431b2011-09-27 17:26:11428 if (index != -1) {
429 *tab_strip_model = tab_strip;
430 *tab_index = index;
431 return true;
432 }
433 }
434
435 return false;
436}
437
438bool ExtensionTabUtil::GetDefaultTab(Browser* browser,
[email protected]72f67972012-10-30 18:53:28439 WebContents** contents,
[email protected]ac84431b2011-09-27 17:26:11440 int* tab_id) {
441 DCHECK(browser);
442 DCHECK(contents);
443
[email protected]617ee962013-01-29 20:49:12444 *contents = browser->tab_strip_model()->GetActiveWebContents();
[email protected]ac84431b2011-09-27 17:26:11445 if (*contents) {
446 if (tab_id)
[email protected]72f67972012-10-30 18:53:28447 *tab_id = GetTabId(*contents);
[email protected]ac84431b2011-09-27 17:26:11448 return true;
449 }
450
451 return false;
452}
453
454bool ExtensionTabUtil::GetTabById(int tab_id,
455 Profile* profile,
456 bool include_incognito,
457 Browser** browser,
458 TabStripModel** tab_strip,
[email protected]72f67972012-10-30 18:53:28459 WebContents** contents,
[email protected]ac84431b2011-09-27 17:26:11460 int* tab_index) {
461 Profile* incognito_profile =
462 include_incognito && profile->HasOffTheRecordProfile() ?
463 profile->GetOffTheRecordProfile() : NULL;
[email protected]3539929f2013-02-01 05:59:14464 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
465 Browser* target_browser = *it;
[email protected]ac84431b2011-09-27 17:26:11466 if (target_browser->profile() == profile ||
467 target_browser->profile() == incognito_profile) {
[email protected]c0849252012-05-12 13:51:27468 TabStripModel* target_tab_strip = target_browser->tab_strip_model();
[email protected]ac84431b2011-09-27 17:26:11469 for (int i = 0; i < target_tab_strip->count(); ++i) {
[email protected]72f67972012-10-30 18:53:28470 WebContents* target_contents = target_tab_strip->GetWebContentsAt(i);
471 if (SessionID::IdForTab(target_contents) == tab_id) {
[email protected]ac84431b2011-09-27 17:26:11472 if (browser)
473 *browser = target_browser;
474 if (tab_strip)
475 *tab_strip = target_tab_strip;
476 if (contents)
477 *contents = target_contents;
478 if (tab_index)
479 *tab_index = i;
480 return true;
481 }
482 }
483 }
484 }
485 return false;
486}
[email protected]45c75e62012-03-21 19:56:35487
488GURL ExtensionTabUtil::ResolvePossiblyRelativeURL(const std::string& url_string,
[email protected]1c4fbc02013-11-13 02:52:42489 const Extension* extension) {
[email protected]45c75e62012-03-21 19:56:35490 GURL url = GURL(url_string);
491 if (!url.is_valid())
492 url = extension->GetResourceURL(url_string);
493
494 return url;
495}
496
497bool ExtensionTabUtil::IsCrashURL(const GURL& url) {
498 // Check a fixed-up URL, to normalize the scheme and parse hosts correctly.
499 GURL fixed_url =
500 URLFixerUpper::FixupURL(url.possibly_invalid_spec(), std::string());
[email protected]2d9748b22014-02-11 00:17:29501 return (fixed_url.SchemeIs(content::kChromeUIScheme) &&
[email protected]46ed0862013-04-14 02:47:56502 (fixed_url.host() == content::kChromeUIBrowserCrashHost ||
[email protected]45c75e62012-03-21 19:56:35503 fixed_url.host() == chrome::kChromeUICrashHost));
504}
[email protected]73c1a6842012-07-13 17:39:04505
506void ExtensionTabUtil::CreateTab(WebContents* web_contents,
507 const std::string& extension_id,
508 WindowOpenDisposition disposition,
509 const gfx::Rect& initial_pos,
510 bool user_gesture) {
[email protected]73c1a6842012-07-13 17:39:04511 Profile* profile =
512 Profile::FromBrowserContext(web_contents->GetBrowserContext());
[email protected]435d43e02012-12-09 09:13:55513 chrome::HostDesktopType active_desktop = chrome::GetActiveDesktop();
[email protected]75072732013-01-09 13:39:25514 Browser* browser = chrome::FindTabbedBrowser(profile, false, active_desktop);
[email protected]2764cab72012-07-19 17:02:10515 const bool browser_created = !browser;
516 if (!browser)
[email protected]435d43e02012-12-09 09:13:55517 browser = new Browser(Browser::CreateParams(profile, active_desktop));
[email protected]e232c992012-12-06 12:43:20518 chrome::NavigateParams params(browser, web_contents);
[email protected]73c1a6842012-07-13 17:39:04519
520 // The extension_app_id parameter ends up as app_name in the Browser
521 // which causes the Browser to return true for is_app(). This affects
522 // among other things, whether the location bar gets displayed.
523 // TODO(mpcomplete): This seems wrong. What if the extension content is hosted
524 // in a tab?
525 if (disposition == NEW_POPUP)
526 params.extension_app_id = extension_id;
527
[email protected]73c1a6842012-07-13 17:39:04528 params.disposition = disposition;
529 params.window_bounds = initial_pos;
530 params.window_action = chrome::NavigateParams::SHOW_WINDOW;
531 params.user_gesture = user_gesture;
532 chrome::Navigate(&params);
[email protected]2764cab72012-07-19 17:02:10533
534 // Close the browser if chrome::Navigate created a new one.
535 if (browser_created && (browser != params.browser))
536 browser->window()->Close();
[email protected]73c1a6842012-07-13 17:39:04537}
[email protected]44e329a2012-07-14 01:13:06538
539// static
540void ExtensionTabUtil::ForEachTab(
541 const base::Callback<void(WebContents*)>& callback) {
[email protected]b031ff82013-01-29 22:53:16542 for (TabContentsIterator iterator; !iterator.done(); iterator.Next())
[email protected]f8073562012-12-06 12:43:53543 callback.Run(*iterator);
[email protected]44e329a2012-07-14 01:13:06544}
[email protected]e9570fdf2012-07-18 20:01:21545
546// static
[email protected]1c4fbc02013-11-13 02:52:42547WindowController* ExtensionTabUtil::GetWindowControllerOfTab(
[email protected]e9570fdf2012-07-18 20:01:21548 const WebContents* web_contents) {
[email protected]f7b4b9e2012-12-02 07:43:17549 Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
[email protected]e9570fdf2012-07-18 20:01:21550 if (browser != NULL)
551 return browser->extension_window_controller();
552
553 return NULL;
554}
[email protected]695089782013-04-09 16:03:17555
556void ExtensionTabUtil::OpenOptionsPage(const Extension* extension,
557 Browser* browser) {
[email protected]1c4fbc02013-11-13 02:52:42558 DCHECK(!ManifestURL::GetOptionsPage(extension).is_empty());
[email protected]695089782013-04-09 16:03:17559
560 // Force the options page to open in non-OTR window, because it won't be
561 // able to save settings from OTR.
[email protected]0edcdec2013-10-31 06:43:08562 scoped_ptr<chrome::ScopedTabbedBrowserDisplayer> displayer;
[email protected]695089782013-04-09 16:03:17563 if (browser->profile()->IsOffTheRecord()) {
[email protected]0edcdec2013-10-31 06:43:08564 displayer.reset(new chrome::ScopedTabbedBrowserDisplayer(
565 browser->profile()->GetOriginalProfile(),
566 browser->host_desktop_type()));
567 browser = displayer->browser();
[email protected]695089782013-04-09 16:03:17568 }
569
[email protected]1c4fbc02013-11-13 02:52:42570 content::OpenURLParams params(ManifestURL::GetOptionsPage(extension),
571 content::Referrer(),
572 SINGLETON_TAB,
573 content::PAGE_TRANSITION_LINK,
574 false);
[email protected]695089782013-04-09 16:03:17575 browser->OpenURL(params);
576 browser->window()->Show();
577 WebContents* web_contents =
578 browser->tab_strip_model()->GetActiveWebContents();
579 web_contents->GetDelegate()->ActivateContents(web_contents);
580}
[email protected]1c4fbc02013-11-13 02:52:42581
582} // namespace extensions