630 lines
20 KiB
C++
630 lines
20 KiB
C++
// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "cef/libcef/browser/chrome/chrome_browser_host_impl.h"
|
|
|
|
#include "base/logging.h"
|
|
#include "base/notreached.h"
|
|
#include "cef/libcef/browser/browser_platform_delegate.h"
|
|
#include "cef/libcef/browser/chrome/browser_platform_delegate_chrome.h"
|
|
#include "cef/libcef/browser/chrome/views/chrome_browser_frame.h"
|
|
#include "cef/libcef/browser/chrome/views/chrome_browser_view.h"
|
|
#include "cef/libcef/browser/thread_util.h"
|
|
#include "cef/libcef/browser/views/browser_view_impl.h"
|
|
#include "cef/libcef/common/net/url_util.h"
|
|
#include "chrome/browser/profiles/profile.h"
|
|
#include "chrome/browser/ui/browser_commands.h"
|
|
#include "chrome/browser/ui/browser_navigator.h"
|
|
#include "chrome/browser/ui/browser_tabstrip.h"
|
|
#include "chrome/browser/ui/browser_window.h"
|
|
#include "chrome/browser/ui/tabs/tab_strip_model.h"
|
|
#include "chrome/browser/ui/views/frame/contents_web_view.h"
|
|
#include "chrome/common/pref_names.h"
|
|
|
|
// static
|
|
CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::Create(
|
|
const CefBrowserCreateParams& params) {
|
|
auto browser = CreateBrowser(params, std::nullopt);
|
|
|
|
GURL url = url_util::MakeGURL(params.url, /*fixup=*/true);
|
|
const bool url_is_empty = url.is_empty();
|
|
if (url_is_empty) {
|
|
// Chrome will navigate to kChromeUINewTabURL by default. We want to keep
|
|
// the current CEF behavior of not navigating at all. Use a special URL that
|
|
// will be recognized in HandleNonNavigationAboutURL.
|
|
url = GURL("chrome://ignore/");
|
|
}
|
|
|
|
// Add a new tab. This will indirectly create a new tab WebContents and
|
|
// call ChromeBrowserDelegate::OnWebContentsCreated to create the associated
|
|
// ChromeBrowserHostImpl.
|
|
chrome::AddTabAt(browser, url, /*index=*/TabStripModel::kNoTab,
|
|
/*foreground=*/true);
|
|
|
|
// The new tab WebContents.
|
|
auto web_contents = browser->tab_strip_model()->GetActiveWebContents();
|
|
CHECK(web_contents);
|
|
|
|
// The associated ChromeBrowserHostImpl.
|
|
auto browser_host =
|
|
ChromeBrowserHostImpl::GetBrowserForContents(web_contents);
|
|
CHECK(browser_host);
|
|
|
|
if (!url_is_empty) {
|
|
// Match Alloy-style behavior of requesting focus after initial navigation.
|
|
browser_host->OnSetFocus(FOCUS_SOURCE_NAVIGATION);
|
|
}
|
|
|
|
return browser_host;
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::FromBaseChecked(
|
|
CefRefPtr<CefBrowserHostBase> host_base) {
|
|
if (!host_base) {
|
|
return nullptr;
|
|
}
|
|
CHECK(host_base->IsChromeStyle());
|
|
return static_cast<ChromeBrowserHostImpl*>(host_base.get());
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForHost(
|
|
const content::RenderViewHost* host) {
|
|
return FromBaseChecked(CefBrowserHostBase::GetBrowserForHost(host));
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForHost(
|
|
const content::RenderFrameHost* host) {
|
|
return FromBaseChecked(CefBrowserHostBase::GetBrowserForHost(host));
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForContents(
|
|
const content::WebContents* contents) {
|
|
return FromBaseChecked(CefBrowserHostBase::GetBrowserForContents(contents));
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForGlobalId(
|
|
const content::GlobalRenderFrameHostId& global_id) {
|
|
return FromBaseChecked(CefBrowserHostBase::GetBrowserForGlobalId(global_id));
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForBrowser(
|
|
const Browser* browser) {
|
|
// Return the ChromeBrowserHostImpl that is currently active.
|
|
// Views-hosted Browsers will contain a single ChromeBrowserHostImpl.
|
|
// Otherwise, there will be a ChromeBrowserHostImpl per Tab/WebContents.
|
|
// |contents| may be nullptr during Browser initialization or destruction.
|
|
auto contents = browser->tab_strip_model()->GetActiveWebContents();
|
|
if (!contents) {
|
|
return nullptr;
|
|
}
|
|
return GetBrowserForContents(contents);
|
|
}
|
|
|
|
ChromeBrowserHostImpl::~ChromeBrowserHostImpl() = default;
|
|
|
|
void ChromeBrowserHostImpl::AddNewContents(
|
|
std::unique_ptr<content::WebContents> contents,
|
|
std::optional<Browser::CreateParams> browser_create_params) {
|
|
DCHECK(contents);
|
|
DCHECK(!browser_);
|
|
|
|
// We should already be associated with the WebContents.
|
|
DCHECK_EQ(GetWebContents(), contents.get());
|
|
|
|
CefBrowserCreateParams params;
|
|
params.request_context = request_context();
|
|
params.browser_view = GetBrowserView();
|
|
|
|
// Create the new Browser representation.
|
|
auto browser = CreateBrowser(params, std::move(browser_create_params));
|
|
|
|
// Add the WebContents to the Browser.
|
|
browser->tab_strip_model()->AddWebContents(
|
|
std::move(contents), /*index=*/TabStripModel::kNoTab,
|
|
ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
|
|
AddTabTypes::ADD_ACTIVE);
|
|
|
|
SetBrowser(browser);
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::OnWebContentsDestroyed(
|
|
content::WebContents* web_contents) {
|
|
DestroyWebContents(web_contents);
|
|
|
|
if (!is_destroying_browser_) {
|
|
// Destroy the browser asynchronously to allow the current call stack
|
|
// to unwind (we may have been called via the TabStripModel owned by the
|
|
// Browser).
|
|
CEF_POST_TASK(CEF_UIT,
|
|
base::BindOnce(&ChromeBrowserHostImpl::DestroyBrowser, this));
|
|
}
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::OnSetFocus(cef_focus_source_t source) {
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(CEF_UIT, base::BindOnce(&ChromeBrowserHostImpl::OnSetFocus,
|
|
this, source));
|
|
return;
|
|
}
|
|
|
|
if (contents_delegate_.OnSetFocus(source)) {
|
|
return;
|
|
}
|
|
|
|
if (platform_delegate_) {
|
|
platform_delegate_->SetFocus(true);
|
|
}
|
|
|
|
if (browser_) {
|
|
const int tab_index = GetCurrentTabIndex();
|
|
if (tab_index != TabStripModel::kNoTab) {
|
|
chrome::SelectNumberedTab(browser_, tab_index);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::CloseBrowser(bool force_close) {
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(CEF_UIT, base::BindOnce(&ChromeBrowserHostImpl::CloseBrowser,
|
|
this, force_close));
|
|
return;
|
|
}
|
|
|
|
if (!force_close) {
|
|
TryCloseBrowser();
|
|
return;
|
|
}
|
|
|
|
// Always do this asynchronously because TabStripModel is not re-entrant.
|
|
CEF_POST_TASK(CEF_UIT,
|
|
base::BindOnce(&ChromeBrowserHostImpl::DoCloseBrowser, this));
|
|
}
|
|
|
|
bool ChromeBrowserHostImpl::TryCloseBrowser() {
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
DCHECK(false) << "called on invalid thread";
|
|
return false;
|
|
}
|
|
|
|
if (auto* web_contents = GetWebContents()) {
|
|
// This check works as follows:
|
|
// 1. Returns false if the main frame is ready to close
|
|
// (IsPageReadyToBeClosed returns true).
|
|
// 2. Otherwise returns true if any frame in the frame tree needs to run
|
|
// beforeunload or unload-time event handlers.
|
|
// 3. Otherwise returns false.
|
|
if (web_contents->NeedToFireBeforeUnloadOrUnloadEvents()) {
|
|
// Will result in a call to Browser::BeforeUnloadFired and, if the close
|
|
// isn't canceled, Browser::CloseContents which indirectly calls
|
|
// TabStripModel::CloseWebContentsAt (similar to DoCloseBrowser but
|
|
// without CLOSE_USER_GESTURE). Additional calls to DispatchBeforeUnload
|
|
// while the unload is pending will be ignored.
|
|
web_contents->DispatchBeforeUnload(/*auto_cancel=*/false);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
CloseBrowser(/*force_close=*/true);
|
|
return true;
|
|
}
|
|
|
|
CefWindowHandle ChromeBrowserHostImpl::GetWindowHandle() {
|
|
if (CEF_CURRENTLY_ON_UIT()) {
|
|
// Always return the most up-to-date window handle for a views-hosted
|
|
// browser since it may change if the view is re-parented.
|
|
if (platform_delegate_) {
|
|
return platform_delegate_->GetHostWindowHandle();
|
|
}
|
|
}
|
|
return host_window_handle_;
|
|
}
|
|
|
|
CefWindowHandle ChromeBrowserHostImpl::GetOpenerWindowHandle() {
|
|
NOTIMPLEMENTED();
|
|
return kNullWindowHandle;
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::Find(const CefString& searchText,
|
|
bool forward,
|
|
bool matchCase,
|
|
bool findNext) {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::StopFinding(bool clearSelection) {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::WasResized() {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::WasHidden(bool hidden) {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::NotifyScreenInfoChanged() {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::Invalidate(PaintElementType type) {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::SendExternalBeginFrame() {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::SendTouchEvent(const CefTouchEvent& event) {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::SendCaptureLostEvent() {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
int ChromeBrowserHostImpl::GetWindowlessFrameRate() {
|
|
return 0;
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::SetWindowlessFrameRate(int frame_rate) {}
|
|
|
|
void ChromeBrowserHostImpl::ImeSetComposition(
|
|
const CefString& text,
|
|
const std::vector<CefCompositionUnderline>& underlines,
|
|
const CefRange& replacement_range,
|
|
const CefRange& selection_range) {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::ImeCommitText(const CefString& text,
|
|
const CefRange& replacement_range,
|
|
int relative_cursor_pos) {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
void ChromeBrowserHostImpl::ImeFinishComposingText(bool keep_selection) {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::ImeCancelComposition() {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::DragTargetDragEnter(
|
|
CefRefPtr<CefDragData> drag_data,
|
|
const CefMouseEvent& event,
|
|
DragOperationsMask allowed_ops) {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::DragTargetDragOver(const CefMouseEvent& event,
|
|
DragOperationsMask allowed_ops) {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::DragTargetDragLeave() {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::DragTargetDrop(const CefMouseEvent& event) {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::DragSourceSystemDragEnded() {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::DragSourceEndedAt(int x,
|
|
int y,
|
|
DragOperationsMask op) {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::SetAudioMuted(bool mute) {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
bool ChromeBrowserHostImpl::IsAudioMuted() {
|
|
NOTIMPLEMENTED();
|
|
return false;
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::SetAutoResizeEnabled(bool enabled,
|
|
const CefSize& min_size,
|
|
const CefSize& max_size) {
|
|
NOTIMPLEMENTED();
|
|
}
|
|
|
|
bool ChromeBrowserHostImpl::CanExecuteChromeCommand(int command_id) {
|
|
// Verify that this method is being called on the UI thread.
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
DCHECK(false) << "called on invalid thread";
|
|
return false;
|
|
}
|
|
|
|
if (browser_) {
|
|
return chrome::SupportsCommand(browser_, command_id) &&
|
|
chrome::IsCommandEnabled(browser_, command_id);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::ExecuteChromeCommand(
|
|
int command_id,
|
|
cef_window_open_disposition_t disposition) {
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(CEF_UIT,
|
|
base::BindOnce(&ChromeBrowserHostImpl::ExecuteChromeCommand,
|
|
this, command_id, disposition));
|
|
return;
|
|
}
|
|
|
|
if (browser_) {
|
|
chrome::ExecuteCommandWithDisposition(
|
|
browser_, command_id, static_cast<WindowOpenDisposition>(disposition));
|
|
}
|
|
}
|
|
|
|
ChromeBrowserView* ChromeBrowserHostImpl::chrome_browser_view() const {
|
|
if (browser_ && is_views_hosted_) {
|
|
return static_cast<ChromeBrowserView*>(browser_->window());
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool ChromeBrowserHostImpl::Navigate(const content::OpenURLParams& params) {
|
|
CEF_REQUIRE_UIT();
|
|
if (GetCurrentTabIndex() == TabStripModel::kNoTab) {
|
|
// We can't navigate via the Browser because we don't have a current tab.
|
|
return CefBrowserHostBase::Navigate(params);
|
|
}
|
|
|
|
if (browser_) {
|
|
GURL gurl = params.url;
|
|
if (!url_util::FixupGURL(gurl)) {
|
|
return false;
|
|
}
|
|
|
|
// This is generally equivalent to calling Browser::OpenURL, except:
|
|
// 1. It doesn't trigger a call to CefRequestHandler::OnOpenURLFromTab, and
|
|
// 2. It navigates in this CefBrowserHost's WebContents instead of
|
|
// (a) creating a new WebContents, or (b) using the Browser's active
|
|
// WebContents (which may not be the same), and
|
|
// 3. There is no risk of triggering chrome's popup blocker.
|
|
NavigateParams nav_params(browser_, gurl, params.transition);
|
|
nav_params.FillNavigateParamsFromOpenURLParams(params);
|
|
|
|
// Always navigate in the current tab.
|
|
nav_params.disposition = WindowOpenDisposition::CURRENT_TAB;
|
|
nav_params.source_contents = GetWebContents();
|
|
|
|
nav_params.tabstrip_add_types = AddTabTypes::ADD_NONE;
|
|
if (params.user_gesture) {
|
|
nav_params.window_action = NavigateParams::SHOW_WINDOW;
|
|
}
|
|
::Navigate(&nav_params);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
ChromeBrowserHostImpl::ChromeBrowserHostImpl(
|
|
const CefBrowserSettings& settings,
|
|
CefRefPtr<CefClient> client,
|
|
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
|
|
scoped_refptr<CefBrowserInfo> browser_info,
|
|
CefRefPtr<CefRequestContextImpl> request_context)
|
|
: CefBrowserHostBase(settings,
|
|
client,
|
|
std::move(platform_delegate),
|
|
browser_info,
|
|
request_context) {}
|
|
|
|
// static
|
|
Browser* ChromeBrowserHostImpl::CreateBrowser(
|
|
const CefBrowserCreateParams& params,
|
|
std::optional<Browser::CreateParams> browser_create_params) {
|
|
Browser::CreateParams chrome_params = [¶ms, &browser_create_params]() {
|
|
if (!browser_create_params.has_value()) {
|
|
auto* profile = CefRequestContextImpl::GetProfile(params.request_context);
|
|
return Browser::CreateParams(profile, /*user_gesture=*/false);
|
|
} else {
|
|
return std::move(*browser_create_params);
|
|
}
|
|
}();
|
|
|
|
// Pass |params| to cef::BrowserDelegate::Create from the Browser constructor.
|
|
chrome_params.cef_params = base::MakeRefCounted<DelegateCreateParams>(params);
|
|
|
|
// Configure Browser creation to use the existing Views-based
|
|
// Widget/BrowserFrame (ChromeBrowserFrame) and BrowserView/BrowserWindow
|
|
// (ChromeBrowserView). See views/chrome_browser_frame.h for related
|
|
// documentation.
|
|
ChromeBrowserView* chrome_browser_view = nullptr;
|
|
if (params.browser_view) {
|
|
if (chrome_params.type == Browser::TYPE_NORMAL) {
|
|
// Don't show most controls.
|
|
chrome_params.type = Browser::TYPE_POPUP;
|
|
// Don't show title bar or address.
|
|
chrome_params.trusted_source = true;
|
|
}
|
|
|
|
auto view_impl =
|
|
static_cast<CefBrowserViewImpl*>(params.browser_view.get());
|
|
|
|
chrome_browser_view = view_impl->chrome_browser_view();
|
|
chrome_params.window = chrome_browser_view;
|
|
|
|
auto chrome_widget =
|
|
static_cast<ChromeBrowserFrame*>(chrome_browser_view->GetWidget());
|
|
chrome_browser_view->set_frame(chrome_widget);
|
|
}
|
|
|
|
// Create the Browser. This will indirectly create the ChomeBrowserDelegate.
|
|
// The same params will be used to create a new Browser if the tab is dragged
|
|
// out of the existing Browser. The returned Browser is owned by the
|
|
// associated BrowserView.
|
|
auto browser = Browser::Create(chrome_params);
|
|
|
|
bool show_browser = true;
|
|
|
|
if (chrome_browser_view) {
|
|
// Initialize the BrowserFrame and BrowserView and create the controls that
|
|
// require access to the Browser.
|
|
chrome_browser_view->InitBrowser(base::WrapUnique(browser));
|
|
|
|
// Don't set theme colors in ContentsWebView::UpdateBackgroundColor.
|
|
chrome_browser_view->contents_web_view()->SetBackgroundVisible(false);
|
|
|
|
// Don't show the browser by default.
|
|
show_browser = false;
|
|
}
|
|
|
|
if (show_browser) {
|
|
browser->window()->Show();
|
|
}
|
|
|
|
return browser;
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::Attach(content::WebContents* web_contents,
|
|
bool is_devtools_popup,
|
|
CefRefPtr<CefBrowserHostBase> opener) {
|
|
DCHECK(web_contents);
|
|
|
|
if (opener) {
|
|
opener_id_ = opener->GetIdentifier();
|
|
|
|
// Give the opener browser's platform delegate an opportunity to modify the
|
|
// new browser's platform delegate.
|
|
opener->platform_delegate()->PopupWebContentsCreated(
|
|
settings_, client_, web_contents, platform_delegate_.get(),
|
|
is_devtools_popup);
|
|
}
|
|
|
|
platform_delegate_->WebContentsCreated(web_contents,
|
|
/*own_web_contents=*/false);
|
|
contents_delegate_.ObserveWebContents(web_contents);
|
|
|
|
// Associate the platform delegate with this browser.
|
|
platform_delegate_->BrowserCreated(this);
|
|
|
|
// Associate the base class with the WebContents.
|
|
InitializeBrowser();
|
|
|
|
// Notify that the browser has been created. These must be delivered in the
|
|
// expected order.
|
|
|
|
if (opener) {
|
|
// 1. Notify the opener browser's platform delegate. With Views this will
|
|
// result in a call to CefBrowserViewDelegate::OnPopupBrowserViewCreated().
|
|
// We want to call this method first because the implementation will often
|
|
// create the Widget for the new popup browser. Without that Widget
|
|
// CefBrowserHost::GetWindowHandle() will return kNullWindowHandle in
|
|
// OnAfterCreated(), which breaks client expectations (e.g. clients expect
|
|
// everything about the browser to be valid at that time).
|
|
opener->platform_delegate()->PopupBrowserCreated(platform_delegate_.get(),
|
|
this, is_devtools_popup);
|
|
}
|
|
|
|
// 2. Notify the browser's LifeSpanHandler. This must always be the first
|
|
// notification for the browser.
|
|
{
|
|
// The WebContents won't be added to the Browser's TabStripModel until later
|
|
// in the current call stack. Block navigation until that time.
|
|
auto navigation_lock = browser_info_->CreateNavigationLock();
|
|
OnAfterCreated();
|
|
}
|
|
|
|
// 3. Notify the platform delegate. With Views this will result in a call to
|
|
// CefBrowserViewDelegate::OnBrowserCreated().
|
|
platform_delegate_->NotifyBrowserCreated();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::SetBrowser(Browser* browser) {
|
|
CEF_REQUIRE_UIT();
|
|
if (browser == browser_) {
|
|
return;
|
|
}
|
|
|
|
browser_ = browser;
|
|
static_cast<CefBrowserPlatformDelegateChrome*>(platform_delegate_.get())
|
|
->set_chrome_browser(browser);
|
|
if (browser_) {
|
|
// We expect the Browser and CefRequestContext to have the same Profile.
|
|
CHECK_EQ(browser_->profile(),
|
|
request_context()->GetBrowserContext()->AsProfile());
|
|
|
|
host_window_handle_ = platform_delegate_->GetHostWindowHandle();
|
|
} else {
|
|
host_window_handle_ = kNullWindowHandle;
|
|
}
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::WindowDestroyed() {
|
|
CEF_REQUIRE_UIT();
|
|
if (auto view = chrome_browser_view()) {
|
|
view->Destroyed();
|
|
}
|
|
|
|
platform_delegate_->CloseHostWindow();
|
|
}
|
|
|
|
bool ChromeBrowserHostImpl::WillBeDestroyed() const {
|
|
CEF_REQUIRE_UIT();
|
|
// TODO(chrome): Modify this to support DoClose(), see issue #3294.
|
|
return !!browser_;
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::DestroyBrowser() {
|
|
CEF_REQUIRE_UIT();
|
|
|
|
is_destroying_browser_ = true;
|
|
|
|
// If the WebContents still exists at this point, close the Browser and
|
|
// WebContents first. See comments on CefBrowserHostBase::DestroyBrowser.
|
|
if (GetWebContents()) {
|
|
// Triggers a call to OnWebContentsDestroyed.
|
|
DoCloseBrowser();
|
|
DCHECK(!GetWebContents());
|
|
}
|
|
|
|
// Disassociate the platform delegate from this browser.
|
|
platform_delegate_->BrowserDestroyed(this);
|
|
|
|
// Clean up UI thread state.
|
|
browser_ = nullptr;
|
|
weak_ptr_factory_.InvalidateWeakPtrs();
|
|
|
|
CefBrowserHostBase::DestroyBrowser();
|
|
}
|
|
|
|
void ChromeBrowserHostImpl::DoCloseBrowser() {
|
|
CEF_REQUIRE_UIT();
|
|
if (browser_) {
|
|
// Like chrome::CloseTab() but specifying the WebContents.
|
|
const int tab_index = GetCurrentTabIndex();
|
|
if (tab_index != TabStripModel::kNoTab) {
|
|
// This will trigger destruction of the Browser and WebContents.
|
|
browser_->tab_strip_model()->CloseWebContentsAt(
|
|
tab_index, TabCloseTypes::CLOSE_CREATE_HISTORICAL_TAB |
|
|
TabCloseTypes::CLOSE_USER_GESTURE);
|
|
}
|
|
}
|
|
}
|
|
|
|
int ChromeBrowserHostImpl::GetCurrentTabIndex() const {
|
|
CEF_REQUIRE_UIT();
|
|
if (browser_) {
|
|
return browser_->tab_strip_model()->GetIndexOfWebContents(GetWebContents());
|
|
}
|
|
return TabStripModel::kNoTab;
|
|
}
|