[email protected] | 327640a | 2012-01-24 21:57:59 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 5 | #include "chrome/browser/extensions/extension_tab_util.h" |
[email protected] | 41d9faf | 2012-02-28 23:46:02 | [diff] [blame] | 6 | |
[email protected] | dbb03fb | 2014-02-15 05:36:33 | [diff] [blame] | 7 | #include "apps/app_window.h" |
| 8 | #include "apps/app_window_registry.h" |
[email protected] | 9852830 | 2014-05-02 00:34:08 | [diff] [blame^] | 9 | #include "base/strings/string_number_conversions.h" |
[email protected] | b19451b | 2012-06-08 17:36:19 | [diff] [blame] | 10 | #include "chrome/browser/extensions/api/tabs/tabs_constants.h" |
[email protected] | 9852830 | 2014-05-02 00:34:08 | [diff] [blame^] | 11 | #include "chrome/browser/extensions/chrome_extension_function.h" |
[email protected] | e9570fdf | 2012-07-18 20:01:21 | [diff] [blame] | 12 | #include "chrome/browser/extensions/tab_helper.h" |
| 13 | #include "chrome/browser/extensions/window_controller.h" |
[email protected] | f1c102b | 2013-02-15 07:44:12 | [diff] [blame] | 14 | #include "chrome/browser/extensions/window_controller_list.h" |
[email protected] | b56e2e3 | 2012-05-11 21:18:04 | [diff] [blame] | 15 | #include "chrome/browser/profiles/profile.h" |
[email protected] | 1034cb4 | 2012-07-17 08:37:54 | [diff] [blame] | 16 | #include "chrome/browser/sessions/session_id.h" |
[email protected] | b56e2e3 | 2012-05-11 21:18:04 | [diff] [blame] | 17 | #include "chrome/browser/ui/browser.h" |
[email protected] | 73c1a684 | 2012-07-13 17:39:04 | [diff] [blame] | 18 | #include "chrome/browser/ui/browser_finder.h" |
[email protected] | 3539929f | 2013-02-01 05:59:14 | [diff] [blame] | 19 | #include "chrome/browser/ui/browser_iterator.h" |
[email protected] | b56e2e3 | 2012-05-11 21:18:04 | [diff] [blame] | 20 | #include "chrome/browser/ui/browser_window.h" |
[email protected] | 0edcdec | 2013-10-31 06:43:08 | [diff] [blame] | 21 | #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" |
[email protected] | 44e329a | 2012-07-14 01:13:06 | [diff] [blame] | 22 | #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" |
[email protected] | b56e2e3 | 2012-05-11 21:18:04 | [diff] [blame] | 23 | #include "chrome/browser/ui/tabs/tab_strip_model.h" |
[email protected] | 69508978 | 2013-04-09 16:03:17 | [diff] [blame] | 24 | #include "chrome/common/extensions/manifest_url_handler.h" |
[email protected] | 4f3b446 | 2013-07-27 19:20:18 | [diff] [blame] | 25 | #include "chrome/common/net/url_fixer_upper.h" |
[email protected] | 45c75e6 | 2012-03-21 19:56:35 | [diff] [blame] | 26 | #include "chrome/common/url_constants.h" |
[email protected] | ad23a09 | 2011-12-28 07:02:04 | [diff] [blame] | 27 | #include "content/public/browser/favicon_status.h" |
| 28 | #include "content/public/browser/navigation_entry.h" |
[email protected] | 6acde635 | 2012-01-04 16:52:20 | [diff] [blame] | 29 | #include "content/public/browser/web_contents.h" |
[email protected] | a16a5a5 | 2013-08-16 17:23:35 | [diff] [blame] | 30 | #include "content/public/browser/web_contents_view.h" |
[email protected] | 9852830 | 2014-05-02 00:34:08 | [diff] [blame^] | 31 | #include "extensions/common/constants.h" |
| 32 | #include "extensions/common/error_utils.h" |
[email protected] | e4452d3 | 2013-11-15 23:07:41 | [diff] [blame] | 33 | #include "extensions/common/extension.h" |
[email protected] | 0c3c973 | 2013-09-16 08:53:41 | [diff] [blame] | 34 | #include "extensions/common/manifest_constants.h" |
[email protected] | 9852830 | 2014-05-02 00:34:08 | [diff] [blame^] | 35 | #include "extensions/common/manifest_handlers/incognito_info.h" |
[email protected] | 793964a | 2013-10-08 00:47:19 | [diff] [blame] | 36 | #include "extensions/common/permissions/api_permission.h" |
[email protected] | e4452d3 | 2013-11-15 23:07:41 | [diff] [blame] | 37 | #include "extensions/common/permissions/permissions_data.h" |
[email protected] | a6483d2 | 2013-07-03 22:11:00 | [diff] [blame] | 38 | #include "url/gurl.h" |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 39 | |
[email protected] | dbb03fb | 2014-02-15 05:36:33 | [diff] [blame] | 40 | using apps::AppWindow; |
[email protected] | 10f417c5 | 2011-12-28 21:04:23 | [diff] [blame] | 41 | using content::NavigationEntry; |
[email protected] | 26b5e32 | 2011-12-23 01:36:47 | [diff] [blame] | 42 | using content::WebContents; |
[email protected] | 1c4fbc0 | 2013-11-13 02:52:42 | [diff] [blame] | 43 | |
| 44 | namespace extensions { |
[email protected] | 26b5e32 | 2011-12-23 01:36:47 | [diff] [blame] | 45 | |
[email protected] | f1c102b | 2013-02-15 07:44:12 | [diff] [blame] | 46 | namespace { |
| 47 | |
[email protected] | 1c4fbc0 | 2013-11-13 02:52:42 | [diff] [blame] | 48 | namespace keys = tabs_constants; |
| 49 | |
[email protected] | dbb03fb | 2014-02-15 05:36:33 | [diff] [blame] | 50 | WindowController* GetAppWindowController(const WebContents* contents) { |
[email protected] | f1c102b | 2013-02-15 07:44:12 | [diff] [blame] | 51 | Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); |
[email protected] | dbb03fb | 2014-02-15 05:36:33 | [diff] [blame] | 52 | apps::AppWindowRegistry* registry = apps::AppWindowRegistry::Get(profile); |
[email protected] | f1c102b | 2013-02-15 07:44:12 | [diff] [blame] | 53 | if (!registry) |
| 54 | return NULL; |
[email protected] | dbb03fb | 2014-02-15 05:36:33 | [diff] [blame] | 55 | AppWindow* app_window = |
| 56 | registry->GetAppWindowForRenderViewHost(contents->GetRenderViewHost()); |
| 57 | if (!app_window) |
[email protected] | f1c102b | 2013-02-15 07:44:12 | [diff] [blame] | 58 | return NULL; |
[email protected] | 4442454 | 2014-01-29 12:10:31 | [diff] [blame] | 59 | return WindowControllerList::GetInstance()->FindWindowById( |
[email protected] | dbb03fb | 2014-02-15 05:36:33 | [diff] [blame] | 60 | app_window->session_id().id()); |
[email protected] | f1c102b | 2013-02-15 07:44:12 | [diff] [blame] | 61 | } |
| 62 | |
[email protected] | 9852830 | 2014-05-02 00:34:08 | [diff] [blame^] | 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. |
| 65 | Browser* 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 | |
| 90 | Browser* 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] | f1c102b | 2013-02-15 07:44:12 | [diff] [blame] | 109 | } // namespace |
| 110 | |
[email protected] | 9852830 | 2014-05-02 00:34:08 | [diff] [blame^] | 111 | ExtensionTabUtil::OpenTabParams::OpenTabParams() |
| 112 | : create_browser_if_needed(false) { |
| 113 | } |
| 114 | |
| 115 | ExtensionTabUtil::OpenTabParams::~OpenTabParams() { |
| 116 | } |
| 117 | |
| 118 | // Opens a new tab for a given extension. Returns NULL and sets |error| if an |
| 119 | // error occurs. |
| 120 | base::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 | |
| 259 | Browser* 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] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 279 | int ExtensionTabUtil::GetWindowId(const Browser* browser) { |
| 280 | return browser->session_id().id(); |
| 281 | } |
| 282 | |
[email protected] | 8c3495c | 2011-09-28 03:32:30 | [diff] [blame] | 283 | int ExtensionTabUtil::GetWindowIdOfTabStripModel( |
| 284 | const TabStripModel* tab_strip_model) { |
[email protected] | 3539929f | 2013-02-01 05:59:14 | [diff] [blame] | 285 | for (chrome::BrowserIterator it; !it.done(); it.Next()) { |
| 286 | if (it->tab_strip_model() == tab_strip_model) |
[email protected] | 8c3495c | 2011-09-28 03:32:30 | [diff] [blame] | 287 | return GetWindowId(*it); |
| 288 | } |
| 289 | return -1; |
| 290 | } |
| 291 | |
[email protected] | 26b5e32 | 2011-12-23 01:36:47 | [diff] [blame] | 292 | int ExtensionTabUtil::GetTabId(const WebContents* web_contents) { |
[email protected] | 554e41e | 2012-09-10 20:21:42 | [diff] [blame] | 293 | return SessionID::IdForTab(web_contents); |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 294 | } |
| 295 | |
| 296 | std::string ExtensionTabUtil::GetTabStatusText(bool is_loading) { |
| 297 | return is_loading ? keys::kStatusValueLoading : keys::kStatusValueComplete; |
| 298 | } |
| 299 | |
[email protected] | ea049a0 | 2011-12-25 21:37:09 | [diff] [blame] | 300 | int ExtensionTabUtil::GetWindowIdOfTab(const WebContents* web_contents) { |
[email protected] | 554e41e | 2012-09-10 20:21:42 | [diff] [blame] | 301 | return SessionID::IdForWindowContainingTab(web_contents); |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 302 | } |
| 303 | |
[email protected] | 023b3d1 | 2013-12-23 18:46:49 | [diff] [blame] | 304 | base::DictionaryValue* ExtensionTabUtil::CreateTabValue( |
[email protected] | f34706be | 2012-09-04 07:32:09 | [diff] [blame] | 305 | const WebContents* contents, |
[email protected] | 0c9f326 | 2012-09-17 05:59:06 | [diff] [blame] | 306 | TabStripModel* tab_strip, |
| 307 | int tab_index, |
[email protected] | f34706be | 2012-09-04 07:32:09 | [diff] [blame] | 308 | const Extension* extension) { |
[email protected] | dbb03fb | 2014-02-15 05:36:33 | [diff] [blame] | 309 | // If we have a matching AppWindow with a controller, get the tab value |
[email protected] | f1c102b | 2013-02-15 07:44:12 | [diff] [blame] | 310 | // from its controller instead. |
[email protected] | dbb03fb | 2014-02-15 05:36:33 | [diff] [blame] | 311 | WindowController* controller = GetAppWindowController(contents); |
[email protected] | f1c102b | 2013-02-15 07:44:12 | [diff] [blame] | 312 | if (controller && |
| 313 | (!extension || controller->IsVisibleToExtension(extension))) { |
| 314 | return controller->CreateTabValue(extension, tab_index); |
| 315 | } |
[email protected] | 4442454 | 2014-01-29 12:10:31 | [diff] [blame] | 316 | base::DictionaryValue* result = |
[email protected] | 023b3d1 | 2013-12-23 18:46:49 | [diff] [blame] | 317 | CreateTabValue(contents, tab_strip, tab_index); |
[email protected] | 304fd15 | 2013-01-12 16:54:44 | [diff] [blame] | 318 | ScrubTabValueForExtension(contents, extension, result); |
| 319 | return result; |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 320 | } |
| 321 | |
[email protected] | aeca23f | 2013-06-21 22:34:41 | [diff] [blame] | 322 | base::ListValue* ExtensionTabUtil::CreateTabList( |
[email protected] | f34706be | 2012-09-04 07:32:09 | [diff] [blame] | 323 | const Browser* browser, |
| 324 | const Extension* extension) { |
[email protected] | aeca23f | 2013-06-21 22:34:41 | [diff] [blame] | 325 | base::ListValue* tab_list = new base::ListValue(); |
[email protected] | c084925 | 2012-05-12 13:51:27 | [diff] [blame] | 326 | TabStripModel* tab_strip = browser->tab_strip_model(); |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 327 | for (int i = 0; i < tab_strip->count(); ++i) { |
[email protected] | 72f6797 | 2012-10-30 18:53:28 | [diff] [blame] | 328 | tab_list->Append(CreateTabValue(tab_strip->GetWebContentsAt(i), |
| 329 | tab_strip, |
| 330 | i, |
| 331 | extension)); |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 332 | } |
| 333 | |
| 334 | return tab_list; |
| 335 | } |
| 336 | |
[email protected] | 023b3d1 | 2013-12-23 18:46:49 | [diff] [blame] | 337 | base::DictionaryValue* ExtensionTabUtil::CreateTabValue( |
[email protected] | f34706be | 2012-09-04 07:32:09 | [diff] [blame] | 338 | const WebContents* contents, |
| 339 | TabStripModel* tab_strip, |
[email protected] | 304fd15 | 2013-01-12 16:54:44 | [diff] [blame] | 340 | int tab_index) { |
[email protected] | dbb03fb | 2014-02-15 05:36:33 | [diff] [blame] | 341 | // If we have a matching AppWindow with a controller, get the tab value |
[email protected] | f1c102b | 2013-02-15 07:44:12 | [diff] [blame] | 342 | // from its controller instead. |
[email protected] | dbb03fb | 2014-02-15 05:36:33 | [diff] [blame] | 343 | WindowController* controller = GetAppWindowController(contents); |
[email protected] | f1c102b | 2013-02-15 07:44:12 | [diff] [blame] | 344 | if (controller) |
| 345 | return controller->CreateTabValue(NULL, tab_index); |
| 346 | |
[email protected] | 0c9f326 | 2012-09-17 05:59:06 | [diff] [blame] | 347 | if (!tab_strip) |
| 348 | ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index); |
| 349 | |
[email protected] | 023b3d1 | 2013-12-23 18:46:49 | [diff] [blame] | 350 | base::DictionaryValue* result = new base::DictionaryValue(); |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 351 | bool is_loading = contents->IsLoading(); |
[email protected] | f34706be | 2012-09-04 07:32:09 | [diff] [blame] | 352 | result->SetInteger(keys::kIdKey, GetTabId(contents)); |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 353 | result->SetInteger(keys::kIndexKey, tab_index); |
[email protected] | f34706be | 2012-09-04 07:32:09 | [diff] [blame] | 354 | result->SetInteger(keys::kWindowIdKey, GetWindowIdOfTab(contents)); |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 355 | result->SetString(keys::kStatusKey, GetTabStatusText(is_loading)); |
[email protected] | 8c3495c | 2011-09-28 03:32:30 | [diff] [blame] | 356 | result->SetBoolean(keys::kActiveKey, |
| 357 | tab_strip && tab_index == tab_strip->active_index()); |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 358 | result->SetBoolean(keys::kSelectedKey, |
| 359 | tab_strip && tab_index == tab_strip->active_index()); |
[email protected] | 8c3495c | 2011-09-28 03:32:30 | [diff] [blame] | 360 | result->SetBoolean(keys::kHighlightedKey, |
| 361 | tab_strip && tab_strip->IsTabSelected(tab_index)); |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 362 | result->SetBoolean(keys::kPinnedKey, |
| 363 | tab_strip && tab_strip->IsTabPinned(tab_index)); |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 364 | result->SetBoolean(keys::kIncognitoKey, |
[email protected] | 627e051 | 2011-12-21 22:55:30 | [diff] [blame] | 365 | contents->GetBrowserContext()->IsOffTheRecord()); |
[email protected] | a16a5a5 | 2013-08-16 17:23:35 | [diff] [blame] | 366 | result->SetInteger(keys::kWidthKey, |
| 367 | contents->GetView()->GetContainerSize().width()); |
| 368 | result->SetInteger(keys::kHeightKey, |
| 369 | contents->GetView()->GetContainerSize().height()); |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 370 | |
[email protected] | 304fd15 | 2013-01-12 16:54:44 | [diff] [blame] | 371 | // 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] | afe9aba | 2013-08-16 20:31:34 | [diff] [blame] | 376 | NavigationEntry* entry = contents->GetController().GetVisibleEntry(); |
[email protected] | 304fd15 | 2013-01-12 16:54:44 | [diff] [blame] | 377 | if (entry && entry->GetFavicon().valid) |
| 378 | result->SetString(keys::kFaviconUrlKey, entry->GetFavicon().url.spec()); |
[email protected] | f34706be | 2012-09-04 07:32:09 | [diff] [blame] | 379 | } |
| 380 | |
[email protected] | 327640a | 2012-01-24 21:57:59 | [diff] [blame] | 381 | if (tab_strip) { |
[email protected] | 6707540 | 2012-10-26 08:26:25 | [diff] [blame] | 382 | WebContents* opener = tab_strip->GetOpenerOfWebContentsAt(tab_index); |
| 383 | if (opener) |
| 384 | result->SetInteger(keys::kOpenerTabIdKey, GetTabId(opener)); |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 385 | } |
| 386 | |
| 387 | return result; |
| 388 | } |
| 389 | |
[email protected] | 023b3d1 | 2013-12-23 18:46:49 | [diff] [blame] | 390 | void ExtensionTabUtil::ScrubTabValueForExtension( |
| 391 | const WebContents* contents, |
| 392 | const Extension* extension, |
| 393 | base::DictionaryValue* tab_info) { |
[email protected] | 13c68b6 | 2013-05-17 11:29:05 | [diff] [blame] | 394 | bool has_permission = |
| 395 | extension && |
[email protected] | 1c4fbc0 | 2013-11-13 02:52:42 | [diff] [blame] | 396 | PermissionsData::HasAPIPermissionForTab( |
[email protected] | 13c68b6 | 2013-05-17 11:29:05 | [diff] [blame] | 397 | extension, GetTabId(contents), APIPermission::kTab); |
[email protected] | 304fd15 | 2013-01-12 16:54:44 | [diff] [blame] | 398 | |
| 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] | ab3f6141 | 2013-01-29 21:55:07 | [diff] [blame] | 406 | void ExtensionTabUtil::ScrubTabForExtension(const Extension* extension, |
[email protected] | 1c4fbc0 | 2013-11-13 02:52:42 | [diff] [blame] | 407 | api::tabs::Tab* tab) { |
[email protected] | ab3f6141 | 2013-01-29 21:55:07 | [diff] [blame] | 408 | 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] | ea049a0 | 2011-12-25 21:37:09 | [diff] [blame] | 418 | bool ExtensionTabUtil::GetTabStripModel(const WebContents* web_contents, |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 419 | TabStripModel** tab_strip_model, |
| 420 | int* tab_index) { |
[email protected] | ea049a0 | 2011-12-25 21:37:09 | [diff] [blame] | 421 | DCHECK(web_contents); |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 422 | DCHECK(tab_strip_model); |
| 423 | DCHECK(tab_index); |
| 424 | |
[email protected] | 3539929f | 2013-02-01 05:59:14 | [diff] [blame] | 425 | for (chrome::BrowserIterator it; !it.done(); it.Next()) { |
| 426 | TabStripModel* tab_strip = it->tab_strip_model(); |
[email protected] | e52d0a4 | 2012-06-08 22:44:16 | [diff] [blame] | 427 | int index = tab_strip->GetIndexOfWebContents(web_contents); |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 428 | if (index != -1) { |
| 429 | *tab_strip_model = tab_strip; |
| 430 | *tab_index = index; |
| 431 | return true; |
| 432 | } |
| 433 | } |
| 434 | |
| 435 | return false; |
| 436 | } |
| 437 | |
| 438 | bool ExtensionTabUtil::GetDefaultTab(Browser* browser, |
[email protected] | 72f6797 | 2012-10-30 18:53:28 | [diff] [blame] | 439 | WebContents** contents, |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 440 | int* tab_id) { |
| 441 | DCHECK(browser); |
| 442 | DCHECK(contents); |
| 443 | |
[email protected] | 617ee96 | 2013-01-29 20:49:12 | [diff] [blame] | 444 | *contents = browser->tab_strip_model()->GetActiveWebContents(); |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 445 | if (*contents) { |
| 446 | if (tab_id) |
[email protected] | 72f6797 | 2012-10-30 18:53:28 | [diff] [blame] | 447 | *tab_id = GetTabId(*contents); |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 448 | return true; |
| 449 | } |
| 450 | |
| 451 | return false; |
| 452 | } |
| 453 | |
| 454 | bool ExtensionTabUtil::GetTabById(int tab_id, |
| 455 | Profile* profile, |
| 456 | bool include_incognito, |
| 457 | Browser** browser, |
| 458 | TabStripModel** tab_strip, |
[email protected] | 72f6797 | 2012-10-30 18:53:28 | [diff] [blame] | 459 | WebContents** contents, |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 460 | int* tab_index) { |
| 461 | Profile* incognito_profile = |
| 462 | include_incognito && profile->HasOffTheRecordProfile() ? |
| 463 | profile->GetOffTheRecordProfile() : NULL; |
[email protected] | 3539929f | 2013-02-01 05:59:14 | [diff] [blame] | 464 | for (chrome::BrowserIterator it; !it.done(); it.Next()) { |
| 465 | Browser* target_browser = *it; |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 466 | if (target_browser->profile() == profile || |
| 467 | target_browser->profile() == incognito_profile) { |
[email protected] | c084925 | 2012-05-12 13:51:27 | [diff] [blame] | 468 | TabStripModel* target_tab_strip = target_browser->tab_strip_model(); |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 469 | for (int i = 0; i < target_tab_strip->count(); ++i) { |
[email protected] | 72f6797 | 2012-10-30 18:53:28 | [diff] [blame] | 470 | WebContents* target_contents = target_tab_strip->GetWebContentsAt(i); |
| 471 | if (SessionID::IdForTab(target_contents) == tab_id) { |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 472 | 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] | 45c75e6 | 2012-03-21 19:56:35 | [diff] [blame] | 487 | |
| 488 | GURL ExtensionTabUtil::ResolvePossiblyRelativeURL(const std::string& url_string, |
[email protected] | 1c4fbc0 | 2013-11-13 02:52:42 | [diff] [blame] | 489 | const Extension* extension) { |
[email protected] | 45c75e6 | 2012-03-21 19:56:35 | [diff] [blame] | 490 | GURL url = GURL(url_string); |
| 491 | if (!url.is_valid()) |
| 492 | url = extension->GetResourceURL(url_string); |
| 493 | |
| 494 | return url; |
| 495 | } |
| 496 | |
| 497 | bool 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] | 2d9748b2 | 2014-02-11 00:17:29 | [diff] [blame] | 501 | return (fixed_url.SchemeIs(content::kChromeUIScheme) && |
[email protected] | 46ed086 | 2013-04-14 02:47:56 | [diff] [blame] | 502 | (fixed_url.host() == content::kChromeUIBrowserCrashHost || |
[email protected] | 45c75e6 | 2012-03-21 19:56:35 | [diff] [blame] | 503 | fixed_url.host() == chrome::kChromeUICrashHost)); |
| 504 | } |
[email protected] | 73c1a684 | 2012-07-13 17:39:04 | [diff] [blame] | 505 | |
| 506 | void 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] | 73c1a684 | 2012-07-13 17:39:04 | [diff] [blame] | 511 | Profile* profile = |
| 512 | Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
[email protected] | 435d43e0 | 2012-12-09 09:13:55 | [diff] [blame] | 513 | chrome::HostDesktopType active_desktop = chrome::GetActiveDesktop(); |
[email protected] | 7507273 | 2013-01-09 13:39:25 | [diff] [blame] | 514 | Browser* browser = chrome::FindTabbedBrowser(profile, false, active_desktop); |
[email protected] | 2764cab7 | 2012-07-19 17:02:10 | [diff] [blame] | 515 | const bool browser_created = !browser; |
| 516 | if (!browser) |
[email protected] | 435d43e0 | 2012-12-09 09:13:55 | [diff] [blame] | 517 | browser = new Browser(Browser::CreateParams(profile, active_desktop)); |
[email protected] | e232c99 | 2012-12-06 12:43:20 | [diff] [blame] | 518 | chrome::NavigateParams params(browser, web_contents); |
[email protected] | 73c1a684 | 2012-07-13 17:39:04 | [diff] [blame] | 519 | |
| 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] | 73c1a684 | 2012-07-13 17:39:04 | [diff] [blame] | 528 | 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(¶ms); |
[email protected] | 2764cab7 | 2012-07-19 17:02:10 | [diff] [blame] | 533 | |
| 534 | // Close the browser if chrome::Navigate created a new one. |
| 535 | if (browser_created && (browser != params.browser)) |
| 536 | browser->window()->Close(); |
[email protected] | 73c1a684 | 2012-07-13 17:39:04 | [diff] [blame] | 537 | } |
[email protected] | 44e329a | 2012-07-14 01:13:06 | [diff] [blame] | 538 | |
| 539 | // static |
| 540 | void ExtensionTabUtil::ForEachTab( |
| 541 | const base::Callback<void(WebContents*)>& callback) { |
[email protected] | b031ff8 | 2013-01-29 22:53:16 | [diff] [blame] | 542 | for (TabContentsIterator iterator; !iterator.done(); iterator.Next()) |
[email protected] | f807356 | 2012-12-06 12:43:53 | [diff] [blame] | 543 | callback.Run(*iterator); |
[email protected] | 44e329a | 2012-07-14 01:13:06 | [diff] [blame] | 544 | } |
[email protected] | e9570fdf | 2012-07-18 20:01:21 | [diff] [blame] | 545 | |
| 546 | // static |
[email protected] | 1c4fbc0 | 2013-11-13 02:52:42 | [diff] [blame] | 547 | WindowController* ExtensionTabUtil::GetWindowControllerOfTab( |
[email protected] | e9570fdf | 2012-07-18 20:01:21 | [diff] [blame] | 548 | const WebContents* web_contents) { |
[email protected] | f7b4b9e | 2012-12-02 07:43:17 | [diff] [blame] | 549 | Browser* browser = chrome::FindBrowserWithWebContents(web_contents); |
[email protected] | e9570fdf | 2012-07-18 20:01:21 | [diff] [blame] | 550 | if (browser != NULL) |
| 551 | return browser->extension_window_controller(); |
| 552 | |
| 553 | return NULL; |
| 554 | } |
[email protected] | 69508978 | 2013-04-09 16:03:17 | [diff] [blame] | 555 | |
| 556 | void ExtensionTabUtil::OpenOptionsPage(const Extension* extension, |
| 557 | Browser* browser) { |
[email protected] | 1c4fbc0 | 2013-11-13 02:52:42 | [diff] [blame] | 558 | DCHECK(!ManifestURL::GetOptionsPage(extension).is_empty()); |
[email protected] | 69508978 | 2013-04-09 16:03:17 | [diff] [blame] | 559 | |
| 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] | 0edcdec | 2013-10-31 06:43:08 | [diff] [blame] | 562 | scoped_ptr<chrome::ScopedTabbedBrowserDisplayer> displayer; |
[email protected] | 69508978 | 2013-04-09 16:03:17 | [diff] [blame] | 563 | if (browser->profile()->IsOffTheRecord()) { |
[email protected] | 0edcdec | 2013-10-31 06:43:08 | [diff] [blame] | 564 | displayer.reset(new chrome::ScopedTabbedBrowserDisplayer( |
| 565 | browser->profile()->GetOriginalProfile(), |
| 566 | browser->host_desktop_type())); |
| 567 | browser = displayer->browser(); |
[email protected] | 69508978 | 2013-04-09 16:03:17 | [diff] [blame] | 568 | } |
| 569 | |
[email protected] | 1c4fbc0 | 2013-11-13 02:52:42 | [diff] [blame] | 570 | content::OpenURLParams params(ManifestURL::GetOptionsPage(extension), |
| 571 | content::Referrer(), |
| 572 | SINGLETON_TAB, |
| 573 | content::PAGE_TRANSITION_LINK, |
| 574 | false); |
[email protected] | 69508978 | 2013-04-09 16:03:17 | [diff] [blame] | 575 | 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] | 1c4fbc0 | 2013-11-13 02:52:42 | [diff] [blame] | 581 | |
| 582 | } // namespace extensions |