#include "chrome/browser/ui/browser_navigator.h"
#include "base/memory/raw_ptr.h"
#include "base/notimplemented.h"
#include "base/task/single_thread_task_runner.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/browser/ui/browser_navigator_params_utils.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "chrome/browser/ui/browser_window/public/create_browser_window.h"
#include "chrome/browser/ui/tabs/tab_list_interface.h"
#include "components/tabs/public/tab_interface.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/window_open_disposition.h"
namespace {
bool ValidNavigateParams(NavigateParams* params) {
DCHECK(params->browser);
DCHECK(!params->contents_to_insert);
DCHECK(!params->switch_to_singleton_tab);
if (!params->initiating_profile) {
params->initiating_profile = params->browser->GetProfile();
}
DCHECK(params->initiating_profile);
if (params->initiating_profile->ShutdownStarted()) {
return false;
}
if (params->disposition == WindowOpenDisposition::OFF_THE_RECORD &&
params->initiating_profile->IsOffTheRecord()) {
params->disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
}
return true;
}
void GetOrCreateBrowserWindowForDisposition(
NavigateParams* params,
base::OnceCallback<void(BrowserWindowInterface*)> callback) {
raw_ptr<Profile> profile = params->initiating_profile;
switch (params->disposition) {
case WindowOpenDisposition::OFF_THE_RECORD:
profile = profile->GetPrimaryOTRProfile(true);
[[fallthrough]];
case WindowOpenDisposition::NEW_WINDOW: {
BrowserWindowCreateParams create_params(*profile, params->user_gesture);
CreateBrowserWindow(std::move(create_params), std::move(callback));
break;
}
case WindowOpenDisposition::NEW_POPUP: {
BrowserWindowCreateParams create_params(
BrowserWindowInterface::Type::TYPE_POPUP, *profile,
params->user_gesture);
CreateBrowserWindow(std::move(create_params), std::move(callback));
break;
}
case WindowOpenDisposition::NEW_BACKGROUND_TAB:
[[fallthrough]];
case WindowOpenDisposition::NEW_FOREGROUND_TAB:
[[fallthrough]];
case WindowOpenDisposition::CURRENT_TAB: {
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), params->browser));
break;
}
default:
NOTIMPLEMENTED();
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), nullptr));
}
}
raw_ptr<tabs::TabInterface> GetOrCreateTabForDisposition(
BrowserWindowInterface* bwi,
NavigateParams* params) {
TabListInterface* tab_list = TabListInterface::From(bwi);
if (!tab_list) {
return nullptr;
}
switch (params->disposition) {
case WindowOpenDisposition::NEW_BACKGROUND_TAB:
[[fallthrough]];
case WindowOpenDisposition::NEW_FOREGROUND_TAB: {
int active_index = tab_list->GetActiveIndex();
int insertion_index =
active_index == -1 ? 0
: params->disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB
? -1
: active_index + 1;
raw_ptr<tabs::TabInterface> new_tab =
tab_list->OpenTab(params->url, insertion_index);
if (!new_tab || !new_tab->GetContents()) {
return nullptr;
}
if (params->disposition != WindowOpenDisposition::NEW_BACKGROUND_TAB) {
tabs::TabHandle new_tab_handle = new_tab->GetHandle();
tab_list->HighlightTabs(new_tab_handle, {new_tab_handle});
}
params->source_contents = new_tab->GetContents();
return new_tab;
}
case WindowOpenDisposition::CURRENT_TAB:
if (params->source_contents) {
return tabs::TabInterface::GetFromContents(params->source_contents);
}
[[fallthrough]];
case WindowOpenDisposition::OFF_THE_RECORD:
[[fallthrough]];
case WindowOpenDisposition::NEW_POPUP:
[[fallthrough]];
case WindowOpenDisposition::NEW_WINDOW: {
raw_ptr<tabs::TabInterface> active_tab = tab_list->GetActiveTab();
params->source_contents = active_tab->GetContents();
return active_tab;
}
default:
NOTIMPLEMENTED();
return nullptr;
}
}
base::WeakPtr<content::NavigationHandle> PerformNavigation(
raw_ptr<tabs::TabInterface> tab,
NavigateParams* params) {
if (!tab || !params->source_contents) {
return nullptr;
}
content::WebContents* contents = tab->GetContents();
params->navigated_or_inserted_contents = contents;
content::NavigationController::LoadURLParams load_url_params =
LoadURLParamsFromNavigateParams(params);
return contents->GetController().LoadURLWithParams(load_url_params);
}
void GetTabAndPerformNavigation(
NavigateParams* params,
base::OnceCallback<void(base::WeakPtr<content::NavigationHandle>)> callback,
BrowserWindowInterface* bwi) {
if (!bwi) {
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), nullptr));
return;
}
tabs::TabInterface* tab = GetOrCreateTabForDisposition(bwi, params);
base::WeakPtr<content::NavigationHandle> handle =
PerformNavigation(tab, params);
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), handle));
}
}
base::WeakPtr<content::NavigationHandle> Navigate(NavigateParams* params) {
if (!ValidNavigateParams(params)) {
return nullptr;
}
if (params->disposition != WindowOpenDisposition::CURRENT_TAB &&
params->disposition != WindowOpenDisposition::NEW_BACKGROUND_TAB &&
params->disposition != WindowOpenDisposition::NEW_FOREGROUND_TAB) {
return nullptr;
}
auto tab = GetOrCreateTabForDisposition(params->browser, params);
return PerformNavigation(tab, params);
}
void Navigate(NavigateParams* params,
base::OnceCallback<void(base::WeakPtr<content::NavigationHandle>)>
callback) {
if (!ValidNavigateParams(params)) {
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), nullptr));
return;
}
GetOrCreateBrowserWindowForDisposition(
params,
base::BindOnce(&GetTabAndPerformNavigation, params, std::move(callback)));
}