Rename GetIconID to GetIconId
[chromium-blink-merge.git] / chrome / browser / extensions / extension_tab_util.cc
blob2e85087485fba163af07211c6f0b66e1c0ccb9f7
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/extension_tab_util.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "base/strings/stringprintf.h"
9 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
10 #include "chrome/browser/extensions/chrome_extension_function.h"
11 #include "chrome/browser/extensions/chrome_extension_function_details.h"
12 #include "chrome/browser/extensions/tab_helper.h"
13 #include "chrome/browser/extensions/window_controller.h"
14 #include "chrome/browser/extensions/window_controller_list.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/sessions/session_tab_helper.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/browser_finder.h"
19 #include "chrome/browser/ui/browser_iterator.h"
20 #include "chrome/browser/ui/browser_window.h"
21 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
22 #include "chrome/browser/ui/singleton_tabs.h"
23 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
24 #include "chrome/browser/ui/tabs/tab_strip_model.h"
25 #include "chrome/browser/ui/tabs/tab_utils.h"
26 #include "chrome/common/extensions/api/tabs.h"
27 #include "chrome/common/url_constants.h"
28 #include "components/url_formatter/url_fixer.h"
29 #include "content/public/browser/favicon_status.h"
30 #include "content/public/browser/navigation_entry.h"
31 #include "content/public/browser/web_contents.h"
32 #include "extensions/browser/app_window/app_window.h"
33 #include "extensions/browser/app_window/app_window_registry.h"
34 #include "extensions/common/constants.h"
35 #include "extensions/common/error_utils.h"
36 #include "extensions/common/extension.h"
37 #include "extensions/common/feature_switch.h"
38 #include "extensions/common/manifest_constants.h"
39 #include "extensions/common/manifest_handlers/incognito_info.h"
40 #include "extensions/common/manifest_handlers/options_page_info.h"
41 #include "extensions/common/permissions/api_permission.h"
42 #include "extensions/common/permissions/permissions_data.h"
43 #include "url/gurl.h"
45 using content::NavigationEntry;
46 using content::WebContents;
48 namespace extensions {
50 namespace {
52 namespace keys = tabs_constants;
54 WindowController* GetAppWindowController(const WebContents* contents) {
55 Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
56 AppWindowRegistry* registry = AppWindowRegistry::Get(profile);
57 if (!registry)
58 return NULL;
59 AppWindow* app_window = registry->GetAppWindowForWebContents(contents);
60 if (!app_window)
61 return NULL;
62 return WindowControllerList::GetInstance()->FindWindowById(
63 app_window->session_id().id());
66 // |error_message| can optionally be passed in and will be set with an
67 // appropriate message if the window cannot be found by id.
68 Browser* 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;
86 if (error_message)
87 *error_message = ErrorUtils::FormatErrorMessage(
88 keys::kWindowNotFoundError, base::IntToString(window_id));
90 return NULL;
93 Browser* CreateBrowser(ChromeUIThreadExtensionFunction* function,
94 int window_id,
95 std::string* error) {
96 content::WebContents* web_contents = function->GetAssociatedWebContents();
97 chrome::HostDesktopType desktop_type =
98 web_contents && web_contents->GetNativeView()
99 ? chrome::GetHostDesktopTypeForNativeView(
100 web_contents->GetNativeView())
101 : chrome::GetHostDesktopTypeForNativeView(NULL);
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;
109 // Use this function for reporting a tab id to an extension. It will
110 // take care of setting the id to TAB_ID_NONE if necessary (for
111 // example with devtools).
112 int GetTabIdForExtensions(const WebContents* web_contents) {
113 Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
114 if (browser && !ExtensionTabUtil::BrowserSupportsTabs(browser))
115 return -1;
116 return SessionTabHelper::IdForTab(web_contents);
119 } // namespace
121 ExtensionTabUtil::OpenTabParams::OpenTabParams()
122 : create_browser_if_needed(false) {
125 ExtensionTabUtil::OpenTabParams::~OpenTabParams() {
128 // Opens a new tab for a given extension. Returns NULL and sets |error| if an
129 // error occurs.
130 base::DictionaryValue* ExtensionTabUtil::OpenTab(
131 ChromeUIThreadExtensionFunction* function,
132 const OpenTabParams& params,
133 std::string* error) {
134 // windowId defaults to "current" window.
135 int window_id = extension_misc::kCurrentWindowId;
136 if (params.window_id.get())
137 window_id = *params.window_id;
139 Browser* browser = GetBrowserFromWindowID(function, window_id, error);
140 if (!browser) {
141 if (!params.create_browser_if_needed) {
142 return NULL;
144 browser = CreateBrowser(function, window_id, error);
145 if (!browser)
146 return NULL;
149 // Ensure the selected browser is tabbed.
150 if (!browser->is_type_tabbed() && browser->IsAttemptingToCloseBrowser())
151 browser = chrome::FindTabbedBrowser(function->GetProfile(),
152 function->include_incognito(),
153 browser->host_desktop_type());
155 if (!browser || !browser->window()) {
156 if (error)
157 *error = keys::kNoCurrentWindowError;
158 return NULL;
161 // TODO(jstritar): Add a constant, chrome.tabs.TAB_ID_ACTIVE, that
162 // represents the active tab.
163 WebContents* opener = NULL;
164 if (params.opener_tab_id.get()) {
165 int opener_id = *params.opener_tab_id;
167 if (!ExtensionTabUtil::GetTabById(opener_id,
168 function->GetProfile(),
169 function->include_incognito(),
170 NULL,
171 NULL,
172 &opener,
173 NULL)) {
174 if (error) {
175 *error = ErrorUtils::FormatErrorMessage(keys::kTabNotFoundError,
176 base::IntToString(opener_id));
178 return NULL;
182 // TODO(rafaelw): handle setting remaining tab properties:
183 // -title
184 // -favIconUrl
186 GURL url;
187 if (params.url.get()) {
188 std::string url_string = *params.url;
189 url = ExtensionTabUtil::ResolvePossiblyRelativeURL(url_string,
190 function->extension());
191 if (!url.is_valid()) {
192 *error =
193 ErrorUtils::FormatErrorMessage(keys::kInvalidUrlError, url_string);
194 return NULL;
196 } else {
197 url = GURL(chrome::kChromeUINewTabURL);
200 // Don't let extensions crash the browser or renderers.
201 if (ExtensionTabUtil::IsKillURL(url)) {
202 *error = keys::kNoCrashBrowserError;
203 return NULL;
206 // Default to foreground for the new tab. The presence of 'active' property
207 // will override this default.
208 bool active = true;
209 if (params.active.get())
210 active = *params.active;
212 // Default to not pinning the tab. Setting the 'pinned' property to true
213 // will override this default.
214 bool pinned = false;
215 if (params.pinned.get())
216 pinned = *params.pinned;
218 // We can't load extension URLs into incognito windows unless the extension
219 // uses split mode. Special case to fall back to a tabbed window.
220 if (url.SchemeIs(kExtensionScheme) &&
221 !IncognitoInfo::IsSplitMode(function->extension()) &&
222 browser->profile()->IsOffTheRecord()) {
223 Profile* profile = browser->profile()->GetOriginalProfile();
224 chrome::HostDesktopType desktop_type = browser->host_desktop_type();
226 browser = chrome::FindTabbedBrowser(profile, false, desktop_type);
227 if (!browser) {
228 browser = new Browser(
229 Browser::CreateParams(Browser::TYPE_TABBED, profile, desktop_type));
230 browser->window()->Show();
234 // If index is specified, honor the value, but keep it bound to
235 // -1 <= index <= tab_strip->count() where -1 invokes the default behavior.
236 int index = -1;
237 if (params.index.get())
238 index = *params.index;
240 TabStripModel* tab_strip = browser->tab_strip_model();
242 index = std::min(std::max(index, -1), tab_strip->count());
244 int add_types = active ? TabStripModel::ADD_ACTIVE : TabStripModel::ADD_NONE;
245 add_types |= TabStripModel::ADD_FORCE_INDEX;
246 if (pinned)
247 add_types |= TabStripModel::ADD_PINNED;
248 chrome::NavigateParams navigate_params(
249 browser, url, ui::PAGE_TRANSITION_LINK);
250 navigate_params.disposition =
251 active ? NEW_FOREGROUND_TAB : NEW_BACKGROUND_TAB;
252 navigate_params.tabstrip_index = index;
253 navigate_params.tabstrip_add_types = add_types;
254 chrome::Navigate(&navigate_params);
256 // The tab may have been created in a different window, so make sure we look
257 // at the right tab strip.
258 tab_strip = navigate_params.browser->tab_strip_model();
259 int new_index =
260 tab_strip->GetIndexOfWebContents(navigate_params.target_contents);
261 if (opener)
262 tab_strip->SetOpenerOfWebContentsAt(new_index, opener);
264 if (active)
265 navigate_params.target_contents->SetInitialFocus();
267 // Return data about the newly created tab.
268 return ExtensionTabUtil::CreateTabValue(navigate_params.target_contents,
269 tab_strip,
270 new_index,
271 function->extension());
274 Browser* ExtensionTabUtil::GetBrowserFromWindowID(
275 ChromeUIThreadExtensionFunction* function,
276 int window_id,
277 std::string* error) {
278 if (window_id == extension_misc::kCurrentWindowId) {
279 Browser* result = function->GetCurrentBrowser();
280 if (!result || !result->window()) {
281 if (error)
282 *error = keys::kNoCurrentWindowError;
283 return NULL;
285 return result;
286 } else {
287 return GetBrowserInProfileWithId(function->GetProfile(),
288 window_id,
289 function->include_incognito(),
290 error);
294 Browser* ExtensionTabUtil::GetBrowserFromWindowID(
295 const ChromeExtensionFunctionDetails& details,
296 int window_id,
297 std::string* error) {
298 if (window_id == extension_misc::kCurrentWindowId) {
299 Browser* result = details.GetCurrentBrowser();
300 if (!result || !result->window()) {
301 if (error)
302 *error = keys::kNoCurrentWindowError;
303 return NULL;
305 return result;
306 } else {
307 return GetBrowserInProfileWithId(details.GetProfile(),
308 window_id,
309 details.function()->include_incognito(),
310 error);
314 int ExtensionTabUtil::GetWindowId(const Browser* browser) {
315 return browser->session_id().id();
318 int ExtensionTabUtil::GetWindowIdOfTabStripModel(
319 const TabStripModel* tab_strip_model) {
320 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
321 if (it->tab_strip_model() == tab_strip_model)
322 return GetWindowId(*it);
324 return -1;
327 int ExtensionTabUtil::GetTabId(const WebContents* web_contents) {
328 return SessionTabHelper::IdForTab(web_contents);
331 std::string ExtensionTabUtil::GetTabStatusText(bool is_loading) {
332 return is_loading ? keys::kStatusValueLoading : keys::kStatusValueComplete;
335 int ExtensionTabUtil::GetWindowIdOfTab(const WebContents* web_contents) {
336 return SessionTabHelper::IdForWindowContainingTab(web_contents);
339 base::DictionaryValue* ExtensionTabUtil::CreateTabValue(
340 WebContents* contents,
341 TabStripModel* tab_strip,
342 int tab_index,
343 const Extension* extension) {
344 // If we have a matching AppWindow with a controller, get the tab value
345 // from its controller instead.
346 WindowController* controller = GetAppWindowController(contents);
347 if (controller &&
348 (!extension || controller->IsVisibleToExtension(extension))) {
349 return controller->CreateTabValue(extension, tab_index);
351 base::DictionaryValue* result =
352 CreateTabValue(contents, tab_strip, tab_index);
353 ScrubTabValueForExtension(contents, extension, result);
354 return result;
357 base::ListValue* ExtensionTabUtil::CreateTabList(
358 const Browser* browser,
359 const Extension* extension) {
360 base::ListValue* tab_list = new base::ListValue();
361 TabStripModel* tab_strip = browser->tab_strip_model();
362 for (int i = 0; i < tab_strip->count(); ++i) {
363 tab_list->Append(CreateTabValue(tab_strip->GetWebContentsAt(i),
364 tab_strip,
366 extension));
369 return tab_list;
372 base::DictionaryValue* ExtensionTabUtil::CreateTabValue(
373 WebContents* contents,
374 TabStripModel* tab_strip,
375 int tab_index) {
376 // If we have a matching AppWindow with a controller, get the tab value
377 // from its controller instead.
378 WindowController* controller = GetAppWindowController(contents);
379 if (controller)
380 return controller->CreateTabValue(NULL, tab_index);
382 if (!tab_strip)
383 ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index);
385 base::DictionaryValue* result = new base::DictionaryValue();
386 bool is_loading = contents->IsLoading();
387 result->SetInteger(keys::kIdKey, GetTabIdForExtensions(contents));
388 result->SetInteger(keys::kIndexKey, tab_index);
389 result->SetInteger(keys::kWindowIdKey, GetWindowIdOfTab(contents));
390 result->SetString(keys::kStatusKey, GetTabStatusText(is_loading));
391 result->SetBoolean(keys::kActiveKey,
392 tab_strip && tab_index == tab_strip->active_index());
393 result->SetBoolean(keys::kSelectedKey,
394 tab_strip && tab_index == tab_strip->active_index());
395 result->SetBoolean(keys::kHighlightedKey,
396 tab_strip && tab_strip->IsTabSelected(tab_index));
397 result->SetBoolean(keys::kPinnedKey,
398 tab_strip && tab_strip->IsTabPinned(tab_index));
399 result->SetBoolean(keys::kAudibleKey, contents->WasRecentlyAudible());
400 result->Set(keys::kMutedInfoKey, CreateMutedInfo(contents).Pass());
401 result->SetBoolean(keys::kIncognitoKey,
402 contents->GetBrowserContext()->IsOffTheRecord());
403 result->SetInteger(keys::kWidthKey,
404 contents->GetContainerBounds().size().width());
405 result->SetInteger(keys::kHeightKey,
406 contents->GetContainerBounds().size().height());
408 // Privacy-sensitive fields: these should be stripped off by
409 // ScrubTabValueForExtension if the extension should not see them.
410 result->SetString(keys::kUrlKey, contents->GetURL().spec());
411 result->SetString(keys::kTitleKey, contents->GetTitle());
412 if (!is_loading) {
413 NavigationEntry* entry = contents->GetController().GetVisibleEntry();
414 if (entry && entry->GetFavicon().valid)
415 result->SetString(keys::kFaviconUrlKey, entry->GetFavicon().url.spec());
418 if (tab_strip) {
419 WebContents* opener = tab_strip->GetOpenerOfWebContentsAt(tab_index);
420 if (opener)
421 result->SetInteger(keys::kOpenerTabIdKey, GetTabIdForExtensions(opener));
424 return result;
427 // static
428 scoped_ptr<base::DictionaryValue> ExtensionTabUtil::CreateMutedInfo(
429 content::WebContents* contents) {
430 DCHECK(contents);
431 api::tabs::MutedInfo info;
432 info.muted = contents->IsAudioMuted();
433 switch (chrome::GetTabAudioMutedReason(contents)) {
434 case TAB_MUTED_REASON_NONE:
435 break;
436 case TAB_MUTED_REASON_CONTEXT_MENU:
437 case TAB_MUTED_REASON_AUDIO_INDICATOR:
438 info.reason = api::tabs::MUTED_INFO_REASON_USER;
439 break;
440 case TAB_MUTED_REASON_MEDIA_CAPTURE:
441 info.reason = api::tabs::MUTED_INFO_REASON_CAPTURE;
442 break;
443 case TAB_MUTED_REASON_EXTENSION:
444 info.reason = api::tabs::MUTED_INFO_REASON_EXTENSION;
445 info.extension_id.reset(
446 new std::string(chrome::GetExtensionIdForMutedTab(contents)));
447 break;
449 return info.ToValue();
452 void ExtensionTabUtil::ScrubTabValueForExtension(
453 WebContents* contents,
454 const Extension* extension,
455 base::DictionaryValue* tab_info) {
456 int tab_id = GetTabId(contents);
457 bool has_permission = tab_id >= 0 && extension &&
458 extension->permissions_data()->HasAPIPermissionForTab(
459 tab_id, APIPermission::kTab);
461 if (!has_permission) {
462 tab_info->Remove(keys::kUrlKey, NULL);
463 tab_info->Remove(keys::kTitleKey, NULL);
464 tab_info->Remove(keys::kFaviconUrlKey, NULL);
468 void ExtensionTabUtil::ScrubTabForExtension(const Extension* extension,
469 api::tabs::Tab* tab) {
470 bool has_permission =
471 extension &&
472 extension->permissions_data()->HasAPIPermission(APIPermission::kTab);
474 if (!has_permission) {
475 tab->url.reset();
476 tab->title.reset();
477 tab->fav_icon_url.reset();
481 bool ExtensionTabUtil::GetTabStripModel(const WebContents* web_contents,
482 TabStripModel** tab_strip_model,
483 int* tab_index) {
484 DCHECK(web_contents);
485 DCHECK(tab_strip_model);
486 DCHECK(tab_index);
488 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
489 TabStripModel* tab_strip = it->tab_strip_model();
490 int index = tab_strip->GetIndexOfWebContents(web_contents);
491 if (index != -1) {
492 *tab_strip_model = tab_strip;
493 *tab_index = index;
494 return true;
498 return false;
501 bool ExtensionTabUtil::GetDefaultTab(Browser* browser,
502 WebContents** contents,
503 int* tab_id) {
504 DCHECK(browser);
505 DCHECK(contents);
507 *contents = browser->tab_strip_model()->GetActiveWebContents();
508 if (*contents) {
509 if (tab_id)
510 *tab_id = GetTabId(*contents);
511 return true;
514 return false;
517 bool ExtensionTabUtil::GetTabById(int tab_id,
518 content::BrowserContext* browser_context,
519 bool include_incognito,
520 Browser** browser,
521 TabStripModel** tab_strip,
522 WebContents** contents,
523 int* tab_index) {
524 if (tab_id == api::tabs::TAB_ID_NONE)
525 return false;
526 Profile* profile = Profile::FromBrowserContext(browser_context);
527 Profile* incognito_profile =
528 include_incognito && profile->HasOffTheRecordProfile() ?
529 profile->GetOffTheRecordProfile() : NULL;
530 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
531 Browser* target_browser = *it;
532 if (target_browser->profile() == profile ||
533 target_browser->profile() == incognito_profile) {
534 TabStripModel* target_tab_strip = target_browser->tab_strip_model();
535 for (int i = 0; i < target_tab_strip->count(); ++i) {
536 WebContents* target_contents = target_tab_strip->GetWebContentsAt(i);
537 if (SessionTabHelper::IdForTab(target_contents) == tab_id) {
538 if (browser)
539 *browser = target_browser;
540 if (tab_strip)
541 *tab_strip = target_tab_strip;
542 if (contents)
543 *contents = target_contents;
544 if (tab_index)
545 *tab_index = i;
546 return true;
551 return false;
554 GURL ExtensionTabUtil::ResolvePossiblyRelativeURL(const std::string& url_string,
555 const Extension* extension) {
556 GURL url = GURL(url_string);
557 if (!url.is_valid())
558 url = extension->GetResourceURL(url_string);
560 return url;
563 bool ExtensionTabUtil::IsKillURL(const GURL& url) {
564 static const char* kill_hosts[] = {
565 chrome::kChromeUICrashHost,
566 chrome::kChromeUIHangUIHost,
567 chrome::kChromeUIKillHost,
568 chrome::kChromeUIQuitHost,
569 chrome::kChromeUIRestartHost,
570 content::kChromeUIBrowserCrashHost,
573 // Check a fixed-up URL, to normalize the scheme and parse hosts correctly.
574 GURL fixed_url =
575 url_formatter::FixupURL(url.possibly_invalid_spec(), std::string());
576 if (!fixed_url.SchemeIs(content::kChromeUIScheme))
577 return false;
579 for (size_t i = 0; i < arraysize(kill_hosts); ++i) {
580 if (fixed_url.host() == kill_hosts[i])
581 return true;
584 return false;
587 void ExtensionTabUtil::CreateTab(WebContents* web_contents,
588 const std::string& extension_id,
589 WindowOpenDisposition disposition,
590 const gfx::Rect& initial_rect,
591 bool user_gesture) {
592 Profile* profile =
593 Profile::FromBrowserContext(web_contents->GetBrowserContext());
594 chrome::HostDesktopType active_desktop = chrome::GetActiveDesktop();
595 Browser* browser = chrome::FindTabbedBrowser(profile, false, active_desktop);
596 const bool browser_created = !browser;
597 if (!browser)
598 browser = new Browser(Browser::CreateParams(profile, active_desktop));
599 chrome::NavigateParams params(browser, web_contents);
601 // The extension_app_id parameter ends up as app_name in the Browser
602 // which causes the Browser to return true for is_app(). This affects
603 // among other things, whether the location bar gets displayed.
604 // TODO(mpcomplete): This seems wrong. What if the extension content is hosted
605 // in a tab?
606 if (disposition == NEW_POPUP)
607 params.extension_app_id = extension_id;
609 params.disposition = disposition;
610 params.window_bounds = initial_rect;
611 params.window_action = chrome::NavigateParams::SHOW_WINDOW;
612 params.user_gesture = user_gesture;
613 chrome::Navigate(&params);
615 // Close the browser if chrome::Navigate created a new one.
616 if (browser_created && (browser != params.browser))
617 browser->window()->Close();
620 // static
621 void ExtensionTabUtil::ForEachTab(
622 const base::Callback<void(WebContents*)>& callback) {
623 for (TabContentsIterator iterator; !iterator.done(); iterator.Next())
624 callback.Run(*iterator);
627 // static
628 WindowController* ExtensionTabUtil::GetWindowControllerOfTab(
629 const WebContents* web_contents) {
630 Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
631 if (browser != NULL)
632 return browser->extension_window_controller();
634 return NULL;
637 bool ExtensionTabUtil::OpenOptionsPage(const Extension* extension,
638 Browser* browser) {
639 if (!OptionsPageInfo::HasOptionsPage(extension))
640 return false;
642 // Force the options page to open in non-OTR window, because it won't be
643 // able to save settings from OTR.
644 scoped_ptr<chrome::ScopedTabbedBrowserDisplayer> displayer;
645 if (browser->profile()->IsOffTheRecord()) {
646 displayer.reset(new chrome::ScopedTabbedBrowserDisplayer(
647 browser->profile()->GetOriginalProfile(),
648 browser->host_desktop_type()));
649 browser = displayer->browser();
652 GURL url_to_navigate;
653 if (OptionsPageInfo::ShouldOpenInTab(extension)) {
654 // Options page tab is simply e.g. chrome-extension://.../options.html.
655 url_to_navigate = OptionsPageInfo::GetOptionsPage(extension);
656 } else {
657 // Options page tab is Extension settings pointed at that Extension's ID,
658 // e.g. chrome://extensions?options=...
659 url_to_navigate = GURL(chrome::kChromeUIExtensionsURL);
660 GURL::Replacements replacements;
661 std::string query =
662 base::StringPrintf("options=%s", extension->id().c_str());
663 replacements.SetQueryStr(query);
664 url_to_navigate = url_to_navigate.ReplaceComponents(replacements);
667 chrome::NavigateParams params(
668 chrome::GetSingletonTabNavigateParams(browser, url_to_navigate));
669 params.path_behavior = chrome::NavigateParams::IGNORE_AND_NAVIGATE;
670 params.url = url_to_navigate;
671 chrome::ShowSingletonTabOverwritingNTP(browser, params);
672 return true;
675 // static
676 bool ExtensionTabUtil::BrowserSupportsTabs(Browser* browser) {
677 return browser && browser->tab_strip_model() && !browser->is_devtools();
680 } // namespace extensions