extension_tab_util.cc revision 116680a4aac90f2aa7413d9095a592090648e557
15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// found in the LICENSE file. 45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/extensions/extension_tab_util.h" 65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "apps/app_window.h" 85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "apps/app_window_registry.h" 95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/extensions/api/tabs/tabs_constants.h" 115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/extensions/chrome_extension_function.h" 125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/extensions/tab_helper.h" 135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/extensions/window_controller.h" 145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/extensions/window_controller_list.h" 155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/profiles/profile.h" 165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/sessions/session_id.h" 175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/ui/browser.h" 185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/ui/browser_finder.h" 195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/ui/browser_iterator.h" 205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/ui/browser_window.h" 215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" 225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" 235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h" 245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/common/extensions/api/tabs.h" 255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/common/extensions/manifest_url_handler.h" 265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/common/url_constants.h" 275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "components/url_fixer/url_fixer.h" 285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "content/public/browser/favicon_status.h" 295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "content/public/browser/navigation_entry.h" 305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "content/public/browser/web_contents.h" 315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "extensions/common/constants.h" 325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "extensions/common/error_utils.h" 335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "extensions/common/extension.h" 3409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)#include "extensions/common/manifest_constants.h" 355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "extensions/common/manifest_handlers/incognito_info.h" 36c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)#include "extensions/common/permissions/api_permission.h" 37591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch#include "extensions/common/permissions/permissions_data.h" 385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "url/gurl.h" 397757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch 40591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdochusing apps::AppWindow; 4109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)using content::NavigationEntry; 425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)using content::WebContents; 43e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 44e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)namespace extensions { 455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)namespace { 475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 48c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace keys = tabs_constants; 495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WindowController* GetAppWindowController(const WebContents* contents) { 515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); 525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) apps::AppWindowRegistry* registry = apps::AppWindowRegistry::Get(profile); 53 if (!registry) 54 return NULL; 55 AppWindow* app_window = 56 registry->GetAppWindowForRenderViewHost(contents->GetRenderViewHost()); 57 if (!app_window) 58 return NULL; 59 return WindowControllerList::GetInstance()->FindWindowById( 60 app_window->session_id().id()); 61} 62 63// |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(ChromeUIThreadExtensionFunction* function, 91 int window_id, 92 std::string* error) { 93 content::WebContents* web_contents = function->GetAssociatedWebContents(); 94 DCHECK(web_contents); 95 DCHECK(web_contents->GetNativeView()); 96 DCHECK(!chrome::FindBrowserWithWebContents(web_contents)); 97 98 chrome::HostDesktopType desktop_type = 99 chrome::GetHostDesktopTypeForNativeView(web_contents->GetNativeView()); 100 Browser::CreateParams params( 101 Browser::TYPE_TABBED, function->GetProfile(), desktop_type); 102 Browser* browser = new Browser(params); 103 browser->window()->Show(); 104 return browser; 105} 106 107} // namespace 108 109ExtensionTabUtil::OpenTabParams::OpenTabParams() 110 : create_browser_if_needed(false) { 111} 112 113ExtensionTabUtil::OpenTabParams::~OpenTabParams() { 114} 115 116// Opens a new tab for a given extension. Returns NULL and sets |error| if an 117// error occurs. 118base::DictionaryValue* ExtensionTabUtil::OpenTab( 119 ChromeUIThreadExtensionFunction* function, 120 const OpenTabParams& params, 121 std::string* error) { 122 // windowId defaults to "current" window. 123 int window_id = extension_misc::kCurrentWindowId; 124 if (params.window_id.get()) 125 window_id = *params.window_id; 126 127 Browser* browser = GetBrowserFromWindowID(function, window_id, error); 128 if (!browser) { 129 if (!params.create_browser_if_needed) { 130 return NULL; 131 } 132 browser = CreateBrowser(function, window_id, error); 133 if (!browser) 134 return NULL; 135 } 136 137 // Ensure the selected browser is tabbed. 138 if (!browser->is_type_tabbed() && browser->IsAttemptingToCloseBrowser()) 139 browser = chrome::FindTabbedBrowser(function->GetProfile(), 140 function->include_incognito(), 141 browser->host_desktop_type()); 142 143 if (!browser || !browser->window()) { 144 // TODO(rpaquay): Error message? 145 return NULL; 146 } 147 148 // TODO(jstritar): Add a constant, chrome.tabs.TAB_ID_ACTIVE, that 149 // represents the active tab. 150 WebContents* opener = NULL; 151 if (params.opener_tab_id.get()) { 152 int opener_id = *params.opener_tab_id; 153 154 if (!ExtensionTabUtil::GetTabById(opener_id, 155 function->GetProfile(), 156 function->include_incognito(), 157 NULL, 158 NULL, 159 &opener, 160 NULL)) { 161 // TODO(rpaquay): Error message? 162 return NULL; 163 } 164 } 165 166 // TODO(rafaelw): handle setting remaining tab properties: 167 // -title 168 // -favIconUrl 169 170 GURL url; 171 if (params.url.get()) { 172 std::string url_string= *params.url; 173 url = ExtensionTabUtil::ResolvePossiblyRelativeURL( 174 url_string, function->GetExtension()); 175 if (!url.is_valid()) { 176 *error = 177 ErrorUtils::FormatErrorMessage(keys::kInvalidUrlError, url_string); 178 return NULL; 179 } 180 } else { 181 url = GURL(chrome::kChromeUINewTabURL); 182 } 183 184 // Don't let extensions crash the browser or renderers. 185 if (ExtensionTabUtil::IsCrashURL(url)) { 186 *error = keys::kNoCrashBrowserError; 187 return NULL; 188 } 189 190 // Default to foreground for the new tab. The presence of 'active' property 191 // will override this default. 192 bool active = true; 193 if (params.active.get()) 194 active = *params.active; 195 196 // Default to not pinning the tab. Setting the 'pinned' property to true 197 // will override this default. 198 bool pinned = false; 199 if (params.pinned.get()) 200 pinned = *params.pinned; 201 202 // We can't load extension URLs into incognito windows unless the extension 203 // uses split mode. Special case to fall back to a tabbed window. 204 if (url.SchemeIs(kExtensionScheme) && 205 !IncognitoInfo::IsSplitMode(function->GetExtension()) && 206 browser->profile()->IsOffTheRecord()) { 207 Profile* profile = browser->profile()->GetOriginalProfile(); 208 chrome::HostDesktopType desktop_type = browser->host_desktop_type(); 209 210 browser = chrome::FindTabbedBrowser(profile, false, desktop_type); 211 if (!browser) { 212 browser = new Browser( 213 Browser::CreateParams(Browser::TYPE_TABBED, profile, desktop_type)); 214 browser->window()->Show(); 215 } 216 } 217 218 // If index is specified, honor the value, but keep it bound to 219 // -1 <= index <= tab_strip->count() where -1 invokes the default behavior. 220 int index = -1; 221 if (params.index.get()) 222 index = *params.index; 223 224 TabStripModel* tab_strip = browser->tab_strip_model(); 225 226 index = std::min(std::max(index, -1), tab_strip->count()); 227 228 int add_types = active ? TabStripModel::ADD_ACTIVE : TabStripModel::ADD_NONE; 229 add_types |= TabStripModel::ADD_FORCE_INDEX; 230 if (pinned) 231 add_types |= TabStripModel::ADD_PINNED; 232 chrome::NavigateParams navigate_params( 233 browser, url, content::PAGE_TRANSITION_LINK); 234 navigate_params.disposition = 235 active ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB; 236 navigate_params.tabstrip_index = index; 237 navigate_params.tabstrip_add_types = add_types; 238 chrome::Navigate(&navigate_params); 239 240 // The tab may have been created in a different window, so make sure we look 241 // at the right tab strip. 242 tab_strip = navigate_params.browser->tab_strip_model(); 243 int new_index = 244 tab_strip->GetIndexOfWebContents(navigate_params.target_contents); 245 if (opener) 246 tab_strip->SetOpenerOfWebContentsAt(new_index, opener); 247 248 if (active) 249 navigate_params.target_contents->SetInitialFocus(); 250 251 // Return data about the newly created tab. 252 return ExtensionTabUtil::CreateTabValue(navigate_params.target_contents, 253 tab_strip, 254 new_index, 255 function->GetExtension()); 256} 257 258Browser* ExtensionTabUtil::GetBrowserFromWindowID( 259 ChromeUIThreadExtensionFunction* function, 260 int window_id, 261 std::string* error) { 262 if (window_id == extension_misc::kCurrentWindowId) { 263 Browser* result = function->GetCurrentBrowser(); 264 if (!result || !result->window()) { 265 if (error) 266 *error = keys::kNoCurrentWindowError; 267 return NULL; 268 } 269 return result; 270 } else { 271 return GetBrowserInProfileWithId(function->GetProfile(), 272 window_id, 273 function->include_incognito(), 274 error); 275 } 276} 277 278int ExtensionTabUtil::GetWindowId(const Browser* browser) { 279 return browser->session_id().id(); 280} 281 282int ExtensionTabUtil::GetWindowIdOfTabStripModel( 283 const TabStripModel* tab_strip_model) { 284 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 285 if (it->tab_strip_model() == tab_strip_model) 286 return GetWindowId(*it); 287 } 288 return -1; 289} 290 291int ExtensionTabUtil::GetTabId(const WebContents* web_contents) { 292 return SessionID::IdForTab(web_contents); 293} 294 295std::string ExtensionTabUtil::GetTabStatusText(bool is_loading) { 296 return is_loading ? keys::kStatusValueLoading : keys::kStatusValueComplete; 297} 298 299int ExtensionTabUtil::GetWindowIdOfTab(const WebContents* web_contents) { 300 return SessionID::IdForWindowContainingTab(web_contents); 301} 302 303base::DictionaryValue* ExtensionTabUtil::CreateTabValue( 304 WebContents* contents, 305 TabStripModel* tab_strip, 306 int tab_index, 307 const Extension* extension) { 308 // If we have a matching AppWindow with a controller, get the tab value 309 // from its controller instead. 310 WindowController* controller = GetAppWindowController(contents); 311 if (controller && 312 (!extension || controller->IsVisibleToExtension(extension))) { 313 return controller->CreateTabValue(extension, tab_index); 314 } 315 base::DictionaryValue* result = 316 CreateTabValue(contents, tab_strip, tab_index); 317 ScrubTabValueForExtension(contents, extension, result); 318 return result; 319} 320 321base::ListValue* ExtensionTabUtil::CreateTabList( 322 const Browser* browser, 323 const Extension* extension) { 324 base::ListValue* tab_list = new base::ListValue(); 325 TabStripModel* tab_strip = browser->tab_strip_model(); 326 for (int i = 0; i < tab_strip->count(); ++i) { 327 tab_list->Append(CreateTabValue(tab_strip->GetWebContentsAt(i), 328 tab_strip, 329 i, 330 extension)); 331 } 332 333 return tab_list; 334} 335 336base::DictionaryValue* ExtensionTabUtil::CreateTabValue( 337 WebContents* contents, 338 TabStripModel* tab_strip, 339 int tab_index) { 340 // If we have a matching AppWindow with a controller, get the tab value 341 // from its controller instead. 342 WindowController* controller = GetAppWindowController(contents); 343 if (controller) 344 return controller->CreateTabValue(NULL, tab_index); 345 346 if (!tab_strip) 347 ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index); 348 349 base::DictionaryValue* result = new base::DictionaryValue(); 350 bool is_loading = contents->IsLoading(); 351 result->SetInteger(keys::kIdKey, GetTabId(contents)); 352 result->SetInteger(keys::kIndexKey, tab_index); 353 result->SetInteger(keys::kWindowIdKey, GetWindowIdOfTab(contents)); 354 result->SetString(keys::kStatusKey, GetTabStatusText(is_loading)); 355 result->SetBoolean(keys::kActiveKey, 356 tab_strip && tab_index == tab_strip->active_index()); 357 result->SetBoolean(keys::kSelectedKey, 358 tab_strip && tab_index == tab_strip->active_index()); 359 result->SetBoolean(keys::kHighlightedKey, 360 tab_strip && tab_strip->IsTabSelected(tab_index)); 361 result->SetBoolean(keys::kPinnedKey, 362 tab_strip && tab_strip->IsTabPinned(tab_index)); 363 result->SetBoolean(keys::kIncognitoKey, 364 contents->GetBrowserContext()->IsOffTheRecord()); 365 result->SetInteger(keys::kWidthKey, 366 contents->GetContainerBounds().size().width()); 367 result->SetInteger(keys::kHeightKey, 368 contents->GetContainerBounds().size().height()); 369 370 // Privacy-sensitive fields: these should be stripped off by 371 // ScrubTabValueForExtension if the extension should not see them. 372 result->SetString(keys::kUrlKey, contents->GetURL().spec()); 373 result->SetString(keys::kTitleKey, contents->GetTitle()); 374 if (!is_loading) { 375 NavigationEntry* entry = contents->GetController().GetVisibleEntry(); 376 if (entry && entry->GetFavicon().valid) 377 result->SetString(keys::kFaviconUrlKey, entry->GetFavicon().url.spec()); 378 } 379 380 if (tab_strip) { 381 WebContents* opener = tab_strip->GetOpenerOfWebContentsAt(tab_index); 382 if (opener) 383 result->SetInteger(keys::kOpenerTabIdKey, GetTabId(opener)); 384 } 385 386 return result; 387} 388 389void ExtensionTabUtil::ScrubTabValueForExtension( 390 WebContents* contents, 391 const Extension* extension, 392 base::DictionaryValue* tab_info) { 393 bool has_permission = extension && 394 extension->permissions_data()->HasAPIPermissionForTab( 395 GetTabId(contents), APIPermission::kTab); 396 397 if (!has_permission) { 398 tab_info->Remove(keys::kUrlKey, NULL); 399 tab_info->Remove(keys::kTitleKey, NULL); 400 tab_info->Remove(keys::kFaviconUrlKey, NULL); 401 } 402} 403 404void ExtensionTabUtil::ScrubTabForExtension(const Extension* extension, 405 api::tabs::Tab* tab) { 406 bool has_permission = 407 extension && 408 extension->permissions_data()->HasAPIPermission(APIPermission::kTab); 409 410 if (!has_permission) { 411 tab->url.reset(); 412 tab->title.reset(); 413 tab->fav_icon_url.reset(); 414 } 415} 416 417bool ExtensionTabUtil::GetTabStripModel(const WebContents* web_contents, 418 TabStripModel** tab_strip_model, 419 int* tab_index) { 420 DCHECK(web_contents); 421 DCHECK(tab_strip_model); 422 DCHECK(tab_index); 423 424 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 425 TabStripModel* tab_strip = it->tab_strip_model(); 426 int index = tab_strip->GetIndexOfWebContents(web_contents); 427 if (index != -1) { 428 *tab_strip_model = tab_strip; 429 *tab_index = index; 430 return true; 431 } 432 } 433 434 return false; 435} 436 437bool ExtensionTabUtil::GetDefaultTab(Browser* browser, 438 WebContents** contents, 439 int* tab_id) { 440 DCHECK(browser); 441 DCHECK(contents); 442 443 *contents = browser->tab_strip_model()->GetActiveWebContents(); 444 if (*contents) { 445 if (tab_id) 446 *tab_id = GetTabId(*contents); 447 return true; 448 } 449 450 return false; 451} 452 453bool ExtensionTabUtil::GetTabById(int tab_id, 454 Profile* profile, 455 bool include_incognito, 456 Browser** browser, 457 TabStripModel** tab_strip, 458 WebContents** contents, 459 int* tab_index) { 460 Profile* incognito_profile = 461 include_incognito && profile->HasOffTheRecordProfile() ? 462 profile->GetOffTheRecordProfile() : NULL; 463 for (chrome::BrowserIterator it; !it.done(); it.Next()) { 464 Browser* target_browser = *it; 465 if (target_browser->profile() == profile || 466 target_browser->profile() == incognito_profile) { 467 TabStripModel* target_tab_strip = target_browser->tab_strip_model(); 468 for (int i = 0; i < target_tab_strip->count(); ++i) { 469 WebContents* target_contents = target_tab_strip->GetWebContentsAt(i); 470 if (SessionID::IdForTab(target_contents) == tab_id) { 471 if (browser) 472 *browser = target_browser; 473 if (tab_strip) 474 *tab_strip = target_tab_strip; 475 if (contents) 476 *contents = target_contents; 477 if (tab_index) 478 *tab_index = i; 479 return true; 480 } 481 } 482 } 483 } 484 return false; 485} 486 487GURL ExtensionTabUtil::ResolvePossiblyRelativeURL(const std::string& url_string, 488 const Extension* extension) { 489 GURL url = GURL(url_string); 490 if (!url.is_valid()) 491 url = extension->GetResourceURL(url_string); 492 493 return url; 494} 495 496bool ExtensionTabUtil::IsCrashURL(const GURL& url) { 497 // Check a fixed-up URL, to normalize the scheme and parse hosts correctly. 498 GURL fixed_url = 499 url_fixer::FixupURL(url.possibly_invalid_spec(), std::string()); 500 return (fixed_url.SchemeIs(content::kChromeUIScheme) && 501 (fixed_url.host() == content::kChromeUIBrowserCrashHost || 502 fixed_url.host() == chrome::kChromeUICrashHost)); 503} 504 505void ExtensionTabUtil::CreateTab(WebContents* web_contents, 506 const std::string& extension_id, 507 WindowOpenDisposition disposition, 508 const gfx::Rect& initial_pos, 509 bool user_gesture) { 510 Profile* profile = 511 Profile::FromBrowserContext(web_contents->GetBrowserContext()); 512 chrome::HostDesktopType active_desktop = chrome::GetActiveDesktop(); 513 Browser* browser = chrome::FindTabbedBrowser(profile, false, active_desktop); 514 const bool browser_created = !browser; 515 if (!browser) 516 browser = new Browser(Browser::CreateParams(profile, active_desktop)); 517 chrome::NavigateParams params(browser, web_contents); 518 519 // The extension_app_id parameter ends up as app_name in the Browser 520 // which causes the Browser to return true for is_app(). This affects 521 // among other things, whether the location bar gets displayed. 522 // TODO(mpcomplete): This seems wrong. What if the extension content is hosted 523 // in a tab? 524 if (disposition == NEW_POPUP) 525 params.extension_app_id = extension_id; 526 527 params.disposition = disposition; 528 params.window_bounds = initial_pos; 529 params.window_action = chrome::NavigateParams::SHOW_WINDOW; 530 params.user_gesture = user_gesture; 531 chrome::Navigate(¶ms); 532 533 // Close the browser if chrome::Navigate created a new one. 534 if (browser_created && (browser != params.browser)) 535 browser->window()->Close(); 536} 537 538// static 539void ExtensionTabUtil::ForEachTab( 540 const base::Callback<void(WebContents*)>& callback) { 541 for (TabContentsIterator iterator; !iterator.done(); iterator.Next()) 542 callback.Run(*iterator); 543} 544 545// static 546WindowController* ExtensionTabUtil::GetWindowControllerOfTab( 547 const WebContents* web_contents) { 548 Browser* browser = chrome::FindBrowserWithWebContents(web_contents); 549 if (browser != NULL) 550 return browser->extension_window_controller(); 551 552 return NULL; 553} 554 555void ExtensionTabUtil::OpenOptionsPage(const Extension* extension, 556 Browser* browser) { 557 DCHECK(!ManifestURL::GetOptionsPage(extension).is_empty()); 558 559 // Force the options page to open in non-OTR window, because it won't be 560 // able to save settings from OTR. 561 scoped_ptr<chrome::ScopedTabbedBrowserDisplayer> displayer; 562 if (browser->profile()->IsOffTheRecord()) { 563 displayer.reset(new chrome::ScopedTabbedBrowserDisplayer( 564 browser->profile()->GetOriginalProfile(), 565 browser->host_desktop_type())); 566 browser = displayer->browser(); 567 } 568 569 content::OpenURLParams params(ManifestURL::GetOptionsPage(extension), 570 content::Referrer(), 571 SINGLETON_TAB, 572 content::PAGE_TRANSITION_LINK, 573 false); 574 browser->OpenURL(params); 575 browser->window()->Show(); 576 WebContents* web_contents = 577 browser->tab_strip_model()->GetActiveWebContents(); 578 web_contents->GetDelegate()->ActivateContents(web_contents); 579} 580 581} // namespace extensions 582