mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
Add notification for aborted popups (fixes #3776)
Pass a new |popup_id| parameter to OnBeforePopup and call a new OnBeforePopupAborted callback if the popup is aborted before OnAfterCreated is called for the popup browser. Add new CefBrowserHost::GetBrowserByIdentifier and GetOpenerIdentifier methods to assist with retrieval of associated browsers. In cefclient, clean up state when a popup is aborted and close any associated popup browsers when the opener browser is closed. This also works when running with `--use-default-popup`.
This commit is contained in:
@@ -61,7 +61,8 @@ void BaseClientHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
|
||||
}
|
||||
|
||||
if (track_as_other_browser_) {
|
||||
MainContext::Get()->GetRootWindowManager()->OtherBrowserCreated();
|
||||
MainContext::Get()->GetRootWindowManager()->OtherBrowserCreated(
|
||||
browser->GetIdentifier(), browser->GetHost()->GetOpenerIdentifier());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +80,8 @@ void BaseClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
||||
}
|
||||
|
||||
if (track_as_other_browser_) {
|
||||
MainContext::Get()->GetRootWindowManager()->OtherBrowserClosed();
|
||||
MainContext::Get()->GetRootWindowManager()->OtherBrowserClosed(
|
||||
browser->GetIdentifier(), browser->GetHost()->GetOpenerIdentifier());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -924,6 +924,7 @@ bool ClientHandler::OnPreKeyEvent(CefRefPtr<CefBrowser> browser,
|
||||
bool ClientHandler::OnBeforePopup(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int popup_id,
|
||||
const CefString& target_url,
|
||||
const CefString& target_frame_name,
|
||||
CefLifeSpanHandler::WindowOpenDisposition target_disposition,
|
||||
@@ -944,13 +945,20 @@ bool ClientHandler::OnBeforePopup(
|
||||
|
||||
// Potentially create a new RootWindow for the popup browser that will be
|
||||
// created asynchronously.
|
||||
CreatePopupWindow(browser, /*is_devtools=*/false, popupFeatures, windowInfo,
|
||||
client, settings);
|
||||
CreatePopupWindow(browser, popup_id, /*is_devtools=*/false, popupFeatures,
|
||||
windowInfo, client, settings);
|
||||
|
||||
// Allow popup creation.
|
||||
return false;
|
||||
}
|
||||
|
||||
void ClientHandler::OnBeforePopupAborted(CefRefPtr<CefBrowser> browser,
|
||||
int popup_id) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
MainContext::Get()->GetRootWindowManager()->AbortOrClosePopup(
|
||||
browser->GetIdentifier(), popup_id);
|
||||
}
|
||||
|
||||
void ClientHandler::OnBeforeDevToolsPopup(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefWindowInfo& windowInfo,
|
||||
@@ -962,8 +970,8 @@ void ClientHandler::OnBeforeDevToolsPopup(
|
||||
|
||||
// Potentially create a new RootWindow for the DevTools popup browser that
|
||||
// will be created immediately after this method returns.
|
||||
if (!CreatePopupWindow(browser, /*is_devtools=*/true, CefPopupFeatures(),
|
||||
windowInfo, client, settings)) {
|
||||
if (!CreatePopupWindow(browser, /*popup_id=*/-1, /*is_devtools=*/true,
|
||||
CefPopupFeatures(), windowInfo, client, settings)) {
|
||||
*use_default_window = true;
|
||||
}
|
||||
}
|
||||
@@ -998,6 +1006,10 @@ bool ClientHandler::DoClose(CefRefPtr<CefBrowser> browser) {
|
||||
|
||||
void ClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
// Close all popups that have this browser as the opener.
|
||||
OnBeforePopupAborted(browser, /*popup_id=*/-1);
|
||||
|
||||
BaseClientHandler::OnBeforeClose(browser);
|
||||
NotifyBrowserClosed(browser);
|
||||
}
|
||||
@@ -1308,6 +1320,7 @@ void ClientHandler::ShowSSLInformation(CefRefPtr<CefBrowser> browser) {
|
||||
}
|
||||
|
||||
bool ClientHandler::CreatePopupWindow(CefRefPtr<CefBrowser> browser,
|
||||
int popup_id,
|
||||
bool is_devtools,
|
||||
const CefPopupFeatures& popupFeatures,
|
||||
CefWindowInfo& windowInfo,
|
||||
@@ -1320,7 +1333,8 @@ bool ClientHandler::CreatePopupWindow(CefRefPtr<CefBrowser> browser,
|
||||
// May return nullptr if UseDefaultPopup() returns true.
|
||||
return !!MainContext::Get()->GetRootWindowManager()->CreateRootWindowAsPopup(
|
||||
use_views_, use_alloy_style_, with_controls_ && !is_devtools, is_osr_,
|
||||
is_devtools, popupFeatures, windowInfo, client, settings);
|
||||
browser->GetIdentifier(), popup_id, is_devtools, popupFeatures,
|
||||
windowInfo, client, settings);
|
||||
}
|
||||
|
||||
void ClientHandler::NotifyBrowserCreated(CefRefPtr<CefBrowser> browser) {
|
||||
|
@@ -212,6 +212,7 @@ class ClientHandler : public BaseClientHandler,
|
||||
bool OnBeforePopup(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int popup_id,
|
||||
const CefString& target_url,
|
||||
const CefString& target_frame_name,
|
||||
CefLifeSpanHandler::WindowOpenDisposition target_disposition,
|
||||
@@ -222,6 +223,8 @@ class ClientHandler : public BaseClientHandler,
|
||||
CefBrowserSettings& settings,
|
||||
CefRefPtr<CefDictionaryValue>& extra_info,
|
||||
bool* no_javascript_access) override;
|
||||
void OnBeforePopupAborted(CefRefPtr<CefBrowser> browser,
|
||||
int popup_id) override;
|
||||
void OnBeforeDevToolsPopup(CefRefPtr<CefBrowser> browser,
|
||||
CefWindowInfo& windowInfo,
|
||||
CefRefPtr<CefClient>& client,
|
||||
@@ -331,6 +334,7 @@ class ClientHandler : public BaseClientHandler,
|
||||
// will be true if the window will be used for DevTools. Returns true if a
|
||||
// RootWindow was created for the popup.
|
||||
bool CreatePopupWindow(CefRefPtr<CefBrowser> browser,
|
||||
int popup_id,
|
||||
bool is_devtools,
|
||||
const CefPopupFeatures& popupFeatures,
|
||||
CefWindowInfo& windowInfo,
|
||||
|
@@ -27,6 +27,7 @@ CefRefPtr<DefaultClientHandler> DefaultClientHandler::GetForClient(
|
||||
bool DefaultClientHandler::OnBeforePopup(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int popup_id,
|
||||
const CefString& target_url,
|
||||
const CefString& target_frame_name,
|
||||
CefLifeSpanHandler::WindowOpenDisposition target_disposition,
|
||||
@@ -52,11 +53,27 @@ bool DefaultClientHandler::OnBeforePopup(
|
||||
// created asynchronously.
|
||||
MainContext::Get()->GetRootWindowManager()->CreateRootWindowAsPopup(
|
||||
config.use_views, use_alloy_style_, config.with_controls,
|
||||
/*is_osr=*/false, /*is_devtools=*/false, popupFeatures, windowInfo,
|
||||
client, settings);
|
||||
/*is_osr=*/false, browser->GetIdentifier(), popup_id,
|
||||
/*is_devtools=*/false, popupFeatures, windowInfo, client, settings);
|
||||
|
||||
// Allow popup creation.
|
||||
return false;
|
||||
}
|
||||
|
||||
void DefaultClientHandler::OnBeforePopupAborted(CefRefPtr<CefBrowser> browser,
|
||||
int popup_id) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
MainContext::Get()->GetRootWindowManager()->AbortOrClosePopup(
|
||||
browser->GetIdentifier(), popup_id);
|
||||
}
|
||||
|
||||
void DefaultClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
// Close all popups that have this browser as the opener.
|
||||
OnBeforePopupAborted(browser, /*popup_id=*/-1);
|
||||
|
||||
BaseClientHandler::OnBeforeClose(browser);
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
@@ -29,6 +29,7 @@ class DefaultClientHandler : public BaseClientHandler {
|
||||
bool OnBeforePopup(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int popup_id,
|
||||
const CefString& target_url,
|
||||
const CefString& target_frame_name,
|
||||
CefLifeSpanHandler::WindowOpenDisposition target_disposition,
|
||||
@@ -39,6 +40,9 @@ class DefaultClientHandler : public BaseClientHandler {
|
||||
CefBrowserSettings& settings,
|
||||
CefRefPtr<CefDictionaryValue>& extra_info,
|
||||
bool* no_javascript_access) override;
|
||||
void OnBeforePopupAborted(CefRefPtr<CefBrowser> browser,
|
||||
int popup_id) override;
|
||||
void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
|
||||
|
||||
private:
|
||||
// Used to determine the object type.
|
||||
|
@@ -29,4 +29,28 @@ scoped_refptr<RootWindow> RootWindow::GetForBrowser(int browser_id) {
|
||||
browser_id);
|
||||
}
|
||||
|
||||
bool RootWindow::IsWindowCreated() const {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
return window_created_;
|
||||
}
|
||||
|
||||
void RootWindow::SetPopupId(int opener_browser_id, int popup_id) {
|
||||
DCHECK_GT(opener_browser_id, 0);
|
||||
DCHECK_GT(popup_id, 0);
|
||||
opener_browser_id_ = opener_browser_id;
|
||||
popup_id_ = popup_id;
|
||||
}
|
||||
|
||||
bool RootWindow::IsPopupIdMatch(int opener_browser_id, int popup_id) const {
|
||||
if (opener_browser_id_ == 0 || popup_id_ == 0) {
|
||||
// Not a popup.
|
||||
return false;
|
||||
}
|
||||
if (popup_id < 0) {
|
||||
// Only checking the opener.
|
||||
return opener_browser_id == opener_browser_id_;
|
||||
}
|
||||
return opener_browser_id == opener_browser_id_ && popup_id == popup_id_;
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
@@ -209,6 +209,19 @@ class RootWindow
|
||||
// Returns true if this window is using windowless rendering (osr).
|
||||
virtual bool WithWindowlessRendering() const = 0;
|
||||
|
||||
// Returns true if this object has been initialized.
|
||||
bool IsInitialized() const { return initialized_; }
|
||||
|
||||
// Returns true if the platform window has been created.
|
||||
bool IsWindowCreated() const;
|
||||
|
||||
// Used to uniquely identify popup windows.
|
||||
void SetPopupId(int opener_browser_id, int popup_id);
|
||||
// If |popup_id| is -1 only match |opener_browser_id|.
|
||||
bool IsPopupIdMatch(int opener_browser_id, int popup_id) const;
|
||||
int opener_browser_id() const { return opener_browser_id_; }
|
||||
int popup_id() const { return popup_id_; }
|
||||
|
||||
protected:
|
||||
// Allow deletion via scoped_refptr only.
|
||||
friend struct DeleteOnMainThread;
|
||||
@@ -217,10 +230,19 @@ class RootWindow
|
||||
explicit RootWindow(bool use_alloy_style);
|
||||
virtual ~RootWindow();
|
||||
|
||||
// Members set during initialization. Safe to access from any thread.
|
||||
Delegate* delegate_ = nullptr;
|
||||
bool initialized_ = false;
|
||||
|
||||
// Only accessed on the main thread.
|
||||
bool window_created_ = false;
|
||||
|
||||
private:
|
||||
const bool use_alloy_style_;
|
||||
|
||||
// Members set during initialization. Safe to access from any thread.
|
||||
int opener_browser_id_ = 0;
|
||||
int popup_id_ = 0;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
@@ -86,7 +86,6 @@ RootWindowGtk::RootWindowGtk(bool use_alloy_style)
|
||||
always_on_top_(false),
|
||||
with_osr_(false),
|
||||
is_popup_(false),
|
||||
initialized_(false),
|
||||
window_(nullptr),
|
||||
back_button_(nullptr),
|
||||
forward_button_(nullptr),
|
||||
@@ -443,6 +442,8 @@ void RootWindowGtk::CreateRootWindow(const CefBrowserSettings& settings,
|
||||
browser_window_->ShowPopup(parent, browser_bounds_.x, browser_bounds_.y,
|
||||
browser_bounds_.width, browser_bounds_.height);
|
||||
}
|
||||
|
||||
window_created_ = true;
|
||||
}
|
||||
|
||||
void RootWindowGtk::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
|
||||
|
@@ -131,7 +131,6 @@ class RootWindowGtk : public RootWindow, public BrowserWindow::Delegate {
|
||||
bool is_popup_;
|
||||
CefRect start_rect_;
|
||||
std::unique_ptr<BrowserWindow> browser_window_;
|
||||
bool initialized_;
|
||||
|
||||
// Main window.
|
||||
GtkWidget* window_;
|
||||
|
@@ -240,7 +240,6 @@ class RootWindowMacImpl
|
||||
CefRect initial_bounds_;
|
||||
cef_show_state_t initial_show_state_ = CEF_SHOW_STATE_NORMAL;
|
||||
std::unique_ptr<BrowserWindow> browser_window_;
|
||||
bool initialized_ = false;
|
||||
|
||||
// Main window.
|
||||
NSWindow* window_ = nil;
|
||||
@@ -273,7 +272,7 @@ RootWindowMacImpl::~RootWindowMacImpl() {
|
||||
void RootWindowMacImpl::Init(RootWindow::Delegate* delegate,
|
||||
std::unique_ptr<RootWindowConfig> config,
|
||||
const CefBrowserSettings& settings) {
|
||||
DCHECK(!initialized_);
|
||||
DCHECK(!root_window_.initialized_);
|
||||
|
||||
with_controls_ = config->with_controls;
|
||||
with_osr_ = config->with_osr;
|
||||
@@ -294,7 +293,7 @@ void RootWindowMacImpl::Init(RootWindow::Delegate* delegate,
|
||||
|
||||
CreateBrowserWindow(config->url);
|
||||
|
||||
initialized_ = true;
|
||||
root_window_.initialized_ = true;
|
||||
|
||||
CreateRootWindow(settings, config->initially_hidden);
|
||||
}
|
||||
@@ -307,7 +306,7 @@ void RootWindowMacImpl::InitAsPopup(RootWindow::Delegate* delegate,
|
||||
CefRefPtr<CefClient>& client,
|
||||
CefBrowserSettings& settings) {
|
||||
DCHECK(delegate);
|
||||
DCHECK(!initialized_);
|
||||
DCHECK(!root_window_.initialized_);
|
||||
|
||||
with_controls_ = with_controls;
|
||||
with_osr_ = with_osr;
|
||||
@@ -328,7 +327,7 @@ void RootWindowMacImpl::InitAsPopup(RootWindow::Delegate* delegate,
|
||||
|
||||
CreateBrowserWindow(std::string());
|
||||
|
||||
initialized_ = true;
|
||||
root_window_.initialized_ = true;
|
||||
|
||||
// The new popup is initially parented to a temporary window. The native root
|
||||
// window will be created after the browser is created and the popup window
|
||||
@@ -632,6 +631,8 @@ void RootWindowMacImpl::CreateRootWindow(const CefBrowserSettings& settings,
|
||||
// Show the window.
|
||||
Show(mode);
|
||||
}
|
||||
|
||||
root_window_.window_created_ = true;
|
||||
}
|
||||
|
||||
void RootWindowMacImpl::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
|
||||
|
@@ -125,6 +125,8 @@ scoped_refptr<RootWindow> RootWindowManager::CreateRootWindowAsPopup(
|
||||
bool use_alloy_style,
|
||||
bool with_controls,
|
||||
bool with_osr,
|
||||
int opener_browser_id,
|
||||
int popup_id,
|
||||
bool is_devtools,
|
||||
const CefPopupFeatures& popupFeatures,
|
||||
CefWindowInfo& windowInfo,
|
||||
@@ -142,6 +144,9 @@ scoped_refptr<RootWindow> RootWindowManager::CreateRootWindowAsPopup(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CHECK_GT(opener_browser_id, 0);
|
||||
CHECK(popup_id > 0 || is_devtools);
|
||||
|
||||
SanityCheckWindowConfig(is_devtools, use_views, use_alloy_style, with_osr);
|
||||
|
||||
if (!temp_window_ && !use_views) {
|
||||
@@ -154,6 +159,9 @@ scoped_refptr<RootWindow> RootWindowManager::CreateRootWindowAsPopup(
|
||||
|
||||
scoped_refptr<RootWindow> root_window =
|
||||
RootWindow::Create(use_views, use_alloy_style);
|
||||
if (!is_devtools) {
|
||||
root_window->SetPopupId(opener_browser_id, popup_id);
|
||||
}
|
||||
root_window->InitAsPopup(this, with_controls, with_osr, popupFeatures,
|
||||
windowInfo, client, settings);
|
||||
|
||||
@@ -163,6 +171,12 @@ scoped_refptr<RootWindow> RootWindowManager::CreateRootWindowAsPopup(
|
||||
return root_window;
|
||||
}
|
||||
|
||||
void RootWindowManager::AbortOrClosePopup(int opener_browser_id, int popup_id) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
// Continue on the main thread.
|
||||
OnAbortOrClosePopup(opener_browser_id, popup_id);
|
||||
}
|
||||
|
||||
scoped_refptr<RootWindow> RootWindowManager::GetWindowForBrowser(
|
||||
int browser_id) const {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
@@ -202,28 +216,48 @@ void RootWindowManager::CloseAllWindows(bool force) {
|
||||
}
|
||||
}
|
||||
|
||||
void RootWindowManager::OtherBrowserCreated() {
|
||||
void RootWindowManager::OtherBrowserCreated(int browser_id,
|
||||
int opener_browser_id) {
|
||||
if (!CURRENTLY_ON_MAIN_THREAD()) {
|
||||
// Execute this method on the main thread.
|
||||
MAIN_POST_CLOSURE(base::BindOnce(&RootWindowManager::OtherBrowserCreated,
|
||||
base::Unretained(this)));
|
||||
base::Unretained(this), browser_id,
|
||||
opener_browser_id));
|
||||
return;
|
||||
}
|
||||
|
||||
other_browser_ct_++;
|
||||
|
||||
// Track ownership of popup browsers that don't have a RootWindow.
|
||||
if (opener_browser_id > 0) {
|
||||
other_browser_owners_[opener_browser_id].insert(browser_id);
|
||||
}
|
||||
}
|
||||
|
||||
void RootWindowManager::OtherBrowserClosed() {
|
||||
void RootWindowManager::OtherBrowserClosed(int browser_id,
|
||||
int opener_browser_id) {
|
||||
if (!CURRENTLY_ON_MAIN_THREAD()) {
|
||||
// Execute this method on the main thread.
|
||||
MAIN_POST_CLOSURE(base::BindOnce(&RootWindowManager::OtherBrowserClosed,
|
||||
base::Unretained(this)));
|
||||
base::Unretained(this), browser_id,
|
||||
opener_browser_id));
|
||||
return;
|
||||
}
|
||||
|
||||
DCHECK_GT(other_browser_ct_, 0);
|
||||
other_browser_ct_--;
|
||||
|
||||
// Track ownership of popup browsers that don't have a RootWindow.
|
||||
if (opener_browser_id > 0) {
|
||||
DCHECK(other_browser_owners_.contains(opener_browser_id));
|
||||
auto& child_set = other_browser_owners_[opener_browser_id];
|
||||
DCHECK(child_set.contains(browser_id));
|
||||
child_set.erase(browser_id);
|
||||
if (child_set.empty()) {
|
||||
other_browser_owners_.erase(opener_browser_id);
|
||||
}
|
||||
}
|
||||
|
||||
MaybeCleanup();
|
||||
}
|
||||
|
||||
@@ -244,6 +278,55 @@ void RootWindowManager::OnRootWindowCreated(
|
||||
}
|
||||
}
|
||||
|
||||
void RootWindowManager::OnAbortOrClosePopup(int opener_browser_id,
|
||||
int popup_id) {
|
||||
if (!CURRENTLY_ON_MAIN_THREAD()) {
|
||||
// Execute this method on the main thread.
|
||||
MAIN_POST_CLOSURE(base::BindOnce(&RootWindowManager::OnAbortOrClosePopup,
|
||||
base::Unretained(this), opener_browser_id,
|
||||
popup_id));
|
||||
return;
|
||||
}
|
||||
|
||||
// Use a copy of |root_windows_| because the original set may be modified
|
||||
// in OnRootWindowDestroyed while iterating.
|
||||
RootWindowSet root_windows = root_windows_;
|
||||
|
||||
// Close or destroy the associated RootWindow(s). This may be a specific popup
|
||||
// (|popup_id| > 0), or all popups if the opener is closing (|popup_id| < 0).
|
||||
for (auto root_window : root_windows) {
|
||||
if (root_window->IsPopupIdMatch(opener_browser_id, popup_id)) {
|
||||
const bool window_created = root_window->IsWindowCreated();
|
||||
LOG(INFO) << (window_created ? "Closing" : "Aborting") << " popup "
|
||||
<< root_window->popup_id() << " of browser "
|
||||
<< opener_browser_id;
|
||||
if (window_created) {
|
||||
// Close the window in the usual way. Will result in a call to
|
||||
// OnRootWindowDestroyed.
|
||||
root_window->Close(/*force=*/false);
|
||||
} else {
|
||||
// The window was not created, so destroy directly.
|
||||
OnRootWindowDestroyed(root_window.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close all other associated popups if the opener is closing. These popups
|
||||
// don't have a RootWindow (e.g. when running with `--use-default-popup`).
|
||||
if (popup_id < 0 && other_browser_owners_.contains(opener_browser_id)) {
|
||||
// Use a copy as the original set may be modified in OtherBrowserClosed
|
||||
// while iterating.
|
||||
auto set = other_browser_owners_[opener_browser_id];
|
||||
for (auto browser_id : set) {
|
||||
if (auto browser = CefBrowserHost::GetBrowserByIdentifier(browser_id)) {
|
||||
LOG(INFO) << "Closing popup browser " << browser_id << " of browser "
|
||||
<< opener_browser_id;
|
||||
browser->GetHost()->CloseBrowser(/*force=*/false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CefRefPtr<CefRequestContext> RootWindowManager::GetRequestContext() {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
return CreateRequestContext(RequestContextCallback());
|
||||
|
@@ -6,6 +6,7 @@
|
||||
#define CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_MANAGER_H_
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
@@ -40,12 +41,18 @@ class RootWindowManager : public RootWindow::Delegate {
|
||||
bool use_alloy_style,
|
||||
bool with_controls,
|
||||
bool with_osr,
|
||||
int opener_browser_id,
|
||||
int popup_id,
|
||||
bool is_devtools,
|
||||
const CefPopupFeatures& popupFeatures,
|
||||
CefWindowInfo& windowInfo,
|
||||
CefRefPtr<CefClient>& client,
|
||||
CefBrowserSettings& settings);
|
||||
|
||||
// Abort or close the popup matching the specified identifiers. If |popup_id|
|
||||
// is -1 then all popups for |opener_browser_id| will be impacted.
|
||||
void AbortOrClosePopup(int opener_browser_id, int popup_id);
|
||||
|
||||
// Returns the RootWindow associated with the specified browser ID. Must be
|
||||
// called on the main thread.
|
||||
scoped_refptr<RootWindow> GetWindowForBrowser(int browser_id) const;
|
||||
@@ -63,8 +70,11 @@ class RootWindowManager : public RootWindow::Delegate {
|
||||
}
|
||||
|
||||
// Track other browsers that are not directly associated with a RootWindow.
|
||||
void OtherBrowserCreated();
|
||||
void OtherBrowserClosed();
|
||||
// This may be an overlay browser, a popup created with `--use-default-popup`,
|
||||
// or a browser using default Chrome UI. |opener_browser_id| will be > 0 for
|
||||
// popup browsers.
|
||||
void OtherBrowserCreated(int browser_id, int opener_browser_id);
|
||||
void OtherBrowserClosed(int browser_id, int opener_browser_id);
|
||||
|
||||
private:
|
||||
// Allow deletion via std::unique_ptr only.
|
||||
@@ -73,6 +83,7 @@ class RootWindowManager : public RootWindow::Delegate {
|
||||
~RootWindowManager() override;
|
||||
|
||||
void OnRootWindowCreated(scoped_refptr<RootWindow> root_window);
|
||||
void OnAbortOrClosePopup(int opener_browser_id, int popup_id);
|
||||
|
||||
// RootWindow::Delegate methods.
|
||||
CefRefPtr<CefRequestContext> GetRequestContext() override;
|
||||
@@ -95,12 +106,19 @@ class RootWindowManager : public RootWindow::Delegate {
|
||||
bool request_context_shared_cache_;
|
||||
|
||||
// Existing root windows. Only accessed on the main thread.
|
||||
typedef std::set<scoped_refptr<RootWindow>> RootWindowSet;
|
||||
using RootWindowSet = std::set<scoped_refptr<RootWindow>>;
|
||||
RootWindowSet root_windows_;
|
||||
|
||||
// Count of other browsers. Only accessed on the main thread.
|
||||
// Count of browsers that are not directly associated with a RootWindow. Only
|
||||
// accessed on the main thread.
|
||||
int other_browser_ct_ = 0;
|
||||
|
||||
// Map of owner browser ID to popup browser IDs for popups that don't have a
|
||||
// RootWindow. Only accessed on the main thread.
|
||||
using BrowserIdSet = std::set<int>;
|
||||
using BrowserOwnerMap = std::map<int, BrowserIdSet>;
|
||||
BrowserOwnerMap other_browser_owners_;
|
||||
|
||||
// The currently active/foreground RootWindow. Only accessed on the main
|
||||
// thread.
|
||||
scoped_refptr<RootWindow> active_root_window_;
|
||||
|
@@ -235,6 +235,17 @@ void RootWindowViews::OnViewsWindowCreated(CefRefPtr<ViewsWindow> window) {
|
||||
DCHECK(!window_);
|
||||
window_ = window;
|
||||
window_->SetAlwaysOnTop(config_->always_on_top);
|
||||
|
||||
if (CURRENTLY_ON_MAIN_THREAD()) {
|
||||
window_created_ = true;
|
||||
} else {
|
||||
// Execute on the main thread.
|
||||
MAIN_POST_CLOSURE(base::BindOnce(
|
||||
[](scoped_refptr<RootWindowViews> self) {
|
||||
self->window_created_ = true;
|
||||
},
|
||||
scoped_refptr<RootWindowViews>(this)));
|
||||
}
|
||||
}
|
||||
|
||||
void RootWindowViews::OnViewsWindowClosing(CefRefPtr<ViewsWindow> window) {
|
||||
|
@@ -105,7 +105,6 @@ class RootWindowViews : public RootWindow,
|
||||
// Members set during initialization. Safe to access from any thread.
|
||||
std::unique_ptr<RootWindowConfig> config_;
|
||||
CefRefPtr<ClientHandler> client_handler_;
|
||||
bool initialized_ = false;
|
||||
|
||||
// Only accessed on the main thread.
|
||||
CefRefPtr<CefBrowser> browser_;
|
||||
|
@@ -1017,6 +1017,8 @@ void RootWindowWin::OnCreate(LPCREATESTRUCT lpCreateStruct) {
|
||||
browser_window_->ShowPopup(hwnd_, rect.left, rect.top,
|
||||
rect.right - rect.left, rect.bottom - rect.top);
|
||||
}
|
||||
|
||||
window_created_ = true;
|
||||
}
|
||||
|
||||
bool RootWindowWin::OnClose() {
|
||||
|
@@ -126,7 +126,6 @@ class RootWindowWin : public RootWindow, public BrowserWindow::Delegate {
|
||||
cef_show_state_t initial_show_state_ = CEF_SHOW_STATE_NORMAL;
|
||||
std::unique_ptr<BrowserWindow> browser_window_;
|
||||
CefBrowserSettings browser_settings_;
|
||||
bool initialized_ = false;
|
||||
|
||||
// Main window.
|
||||
HWND hwnd_ = nullptr;
|
||||
|
@@ -412,6 +412,11 @@ struct FrameStatus {
|
||||
EXPECT_FALSE(browser->IsValid()) << func;
|
||||
}
|
||||
|
||||
const auto browser_id = browser->GetIdentifier();
|
||||
EXPECT_GT(browser_id, 0) << func;
|
||||
auto get_browser = CefBrowserHost::GetBrowserByIdentifier(browser_id);
|
||||
EXPECT_TRUE(get_browser && get_browser->IsSame(browser)) << func;
|
||||
|
||||
// Note that this might not be the same main frame as us when navigating
|
||||
// cross-origin, because the new main frame object is assigned to the
|
||||
// browser before the CefFrameHandler callbacks related to main frame change
|
||||
@@ -1641,6 +1646,7 @@ class ParentOrderMainTestHandler : public OrderMainTestHandler {
|
||||
bool OnBeforePopup(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int popup_id,
|
||||
const CefString& target_url,
|
||||
const CefString& target_frame_name,
|
||||
CefLifeSpanHandler::WindowOpenDisposition target_disposition,
|
||||
|
@@ -1480,6 +1480,7 @@ class OrderNavTestHandler : public TestHandler {
|
||||
bool OnBeforePopup(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int popup_id,
|
||||
const CefString& target_url,
|
||||
const CefString& target_frame_name,
|
||||
CefLifeSpanHandler::WindowOpenDisposition target_disposition,
|
||||
@@ -2270,6 +2271,7 @@ class PopupSimultaneousTestHandler : public TestHandler {
|
||||
|
||||
bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int popup_id,
|
||||
const CefString& target_url,
|
||||
const CefString& target_frame_name,
|
||||
cef_window_open_disposition_t target_disposition,
|
||||
@@ -2429,6 +2431,7 @@ class PopupJSWindowOpenTestHandler : public TestHandler {
|
||||
|
||||
bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int popup_id,
|
||||
const CefString& target_url,
|
||||
const CefString& target_frame_name,
|
||||
cef_window_open_disposition_t target_disposition,
|
||||
@@ -2576,6 +2579,7 @@ class PopupJSWindowEmptyTestHandler : public TestHandler {
|
||||
|
||||
bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int popup_id,
|
||||
const CefString& target_url,
|
||||
const CefString& target_frame_name,
|
||||
cef_window_open_disposition_t target_disposition,
|
||||
@@ -3602,6 +3606,7 @@ class ExtraInfoNavTestHandler : public TestHandler {
|
||||
|
||||
bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int popup_id,
|
||||
const CefString& target_url,
|
||||
const CefString& target_frame_name,
|
||||
cef_window_open_disposition_t target_disposition,
|
||||
|
@@ -213,6 +213,7 @@ class OsrPopupJSOtherClientTestHandler : public TestHandler,
|
||||
|
||||
bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int popup_id,
|
||||
const CefString& target_url,
|
||||
const CefString& target_frame_name,
|
||||
cef_window_open_disposition_t target_disposition,
|
||||
@@ -346,6 +347,7 @@ class OsrPopupJSOtherCefClient : public CefClient,
|
||||
|
||||
bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int popup_id,
|
||||
const CefString& target_url,
|
||||
const CefString& target_frame_name,
|
||||
cef_window_open_disposition_t target_disposition,
|
||||
|
@@ -203,6 +203,8 @@ class PopupTestHandler : public TestHandler {
|
||||
enum Mode {
|
||||
MODE_WINDOW_OPEN,
|
||||
MODE_TARGETED_LINK,
|
||||
// The no-referrer popup won't have an opener from the renderer's
|
||||
// perspective, but we still track it from the browser's perspective.
|
||||
MODE_NOREFERRER_LINK,
|
||||
};
|
||||
|
||||
@@ -284,6 +286,7 @@ class PopupTestHandler : public TestHandler {
|
||||
|
||||
bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int popup_id,
|
||||
const CefString& target_url,
|
||||
const CefString& target_frame_name,
|
||||
cef_window_open_disposition_t target_disposition,
|
||||
@@ -294,8 +297,14 @@ class PopupTestHandler : public TestHandler {
|
||||
CefBrowserSettings& settings,
|
||||
CefRefPtr<CefDictionaryValue>& extra_info,
|
||||
bool* no_javascript_access) override {
|
||||
EXPECT_FALSE(got_on_before_popup_);
|
||||
EXPECT_FALSE(got_on_before_popup_aborted_);
|
||||
EXPECT_FALSE(got_on_after_created_popup_);
|
||||
got_on_before_popup_.yes();
|
||||
|
||||
// Only ever a single popup with this test.
|
||||
EXPECT_EQ(1, popup_id);
|
||||
|
||||
const std::string& url = target_url;
|
||||
EXPECT_STREQ(url.c_str(), popup_url_.c_str());
|
||||
|
||||
@@ -310,6 +319,30 @@ class PopupTestHandler : public TestHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
void OnBeforePopupAborted(CefRefPtr<CefBrowser> browser,
|
||||
int popup_id) override {
|
||||
EXPECT_TRUE(got_on_before_popup_);
|
||||
EXPECT_FALSE(got_on_before_popup_aborted_);
|
||||
EXPECT_FALSE(got_on_after_created_popup_);
|
||||
got_on_before_popup_aborted_.yes();
|
||||
|
||||
// Only ever a single popup with this test.
|
||||
EXPECT_EQ(1, popup_id);
|
||||
}
|
||||
|
||||
void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
|
||||
if (browser->IsPopup()) {
|
||||
EXPECT_TRUE(got_on_before_popup_);
|
||||
EXPECT_FALSE(got_on_before_popup_aborted_);
|
||||
got_on_after_created_popup_.yes();
|
||||
// Opener is the main browser.
|
||||
EXPECT_EQ(GetBrowserId(), browser->GetHost()->GetOpenerIdentifier());
|
||||
} else {
|
||||
EXPECT_EQ(0, browser->GetHost()->GetOpenerIdentifier());
|
||||
}
|
||||
TestHandler::OnAfterCreated(browser);
|
||||
}
|
||||
|
||||
void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
|
||||
TestHandler::OnBeforeClose(browser);
|
||||
|
||||
@@ -372,6 +405,8 @@ class PopupTestHandler : public TestHandler {
|
||||
// Verify test expectations.
|
||||
EXPECT_TRUE(got_load_end1_);
|
||||
EXPECT_TRUE(got_on_before_popup_);
|
||||
EXPECT_FALSE(got_on_before_popup_aborted_);
|
||||
EXPECT_TRUE(got_on_after_created_popup_);
|
||||
EXPECT_TRUE(got_load_end2_);
|
||||
EXPECT_TRUE(got_cookie1_);
|
||||
EXPECT_TRUE(got_cookie2_);
|
||||
@@ -389,6 +424,8 @@ class PopupTestHandler : public TestHandler {
|
||||
|
||||
TrackCallback got_load_end1_;
|
||||
TrackCallback got_on_before_popup_;
|
||||
TrackCallback got_on_before_popup_aborted_;
|
||||
TrackCallback got_on_after_created_popup_;
|
||||
TrackCallback got_load_end2_;
|
||||
TrackCallback got_cookie1_;
|
||||
TrackCallback got_cookie2_;
|
||||
@@ -516,6 +553,7 @@ class PopupNavTestHandler : public TestHandler {
|
||||
|
||||
bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int popup_id,
|
||||
const CefString& target_url,
|
||||
const CefString& target_frame_name,
|
||||
cef_window_open_disposition_t target_disposition,
|
||||
@@ -527,10 +565,16 @@ class PopupNavTestHandler : public TestHandler {
|
||||
CefRefPtr<CefDictionaryValue>& extra_info,
|
||||
bool* no_javascript_access) override {
|
||||
EXPECT_FALSE(got_on_before_popup_);
|
||||
EXPECT_FALSE(got_on_before_popup_aborted_);
|
||||
got_on_before_popup_.yes();
|
||||
|
||||
EXPECT_TRUE(CefCurrentlyOn(TID_UI));
|
||||
EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
|
||||
|
||||
// Only ever a single popup with this test.
|
||||
EXPECT_EQ(1, popup_id);
|
||||
opener_browser_id_ = browser->GetIdentifier();
|
||||
EXPECT_EQ(GetBrowserId(), opener_browser_id_);
|
||||
|
||||
EXPECT_STREQ(kPopupNavPageUrl, frame->GetURL().ToString().c_str());
|
||||
EXPECT_STREQ(kPopupNavPopupUrl, target_url.ToString().c_str());
|
||||
EXPECT_STREQ(kPopupNavPopupName, target_frame_name.ToString().c_str());
|
||||
@@ -547,8 +591,32 @@ class PopupNavTestHandler : public TestHandler {
|
||||
return (mode_ == DENY); // Return true to cancel the popup.
|
||||
}
|
||||
|
||||
void OnBeforePopupAborted(CefRefPtr<CefBrowser> browser,
|
||||
int popup_id) override {
|
||||
EXPECT_TRUE(got_on_before_popup_);
|
||||
EXPECT_FALSE(got_on_before_popup_aborted_);
|
||||
got_on_before_popup_aborted_.yes();
|
||||
|
||||
EXPECT_TRUE(CefCurrentlyOn(TID_UI));
|
||||
|
||||
// Can't use GetBrowserId() here because the opener is already closing.
|
||||
EXPECT_EQ(opener_browser_id_, browser->GetIdentifier());
|
||||
EXPECT_FALSE(browser->IsValid());
|
||||
|
||||
// Only ever a single popup with this test.
|
||||
EXPECT_EQ(1, popup_id);
|
||||
}
|
||||
|
||||
void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
|
||||
TestHandler::OnAfterCreated(browser);
|
||||
if (browser->IsPopup()) {
|
||||
EXPECT_TRUE(got_on_before_popup_);
|
||||
EXPECT_EQ(opener_browser_id_, browser->GetHost()->GetOpenerIdentifier());
|
||||
} else {
|
||||
EXPECT_FALSE(got_on_before_popup_);
|
||||
EXPECT_EQ(0, browser->GetHost()->GetOpenerIdentifier());
|
||||
}
|
||||
EXPECT_FALSE(got_on_before_popup_aborted_);
|
||||
|
||||
if (browser->IsPopup() && (mode_ == DESTROY_PARENT_AFTER_CREATION ||
|
||||
mode_ == DESTROY_PARENT_AFTER_CREATION_FORCE)) {
|
||||
@@ -684,10 +752,24 @@ class PopupNavTestHandler : public TestHandler {
|
||||
EXPECT_TRUE(got_load_end_);
|
||||
|
||||
// OnBeforePopup may come before or after browser destruction with the
|
||||
// DESTROY_PARENT_BEFORE_CREATION* tests.
|
||||
// DESTROY_PARENT_BEFORE_CREATION* tests and Alloy style browsers.
|
||||
if (mode_ != DESTROY_PARENT_BEFORE_CREATION &&
|
||||
mode_ != DESTROY_PARENT_BEFORE_CREATION_FORCE) {
|
||||
EXPECT_TRUE(got_on_before_popup_);
|
||||
} else if (!use_alloy_style_browser()) {
|
||||
EXPECT_FALSE(got_on_before_popup_);
|
||||
}
|
||||
|
||||
if (mode_ == DESTROY_PARENT_DURING_CREATION ||
|
||||
mode_ == DESTROY_PARENT_DURING_CREATION_FORCE ||
|
||||
mode_ == DESTROY_PARENT_AFTER_CREATION ||
|
||||
mode_ == DESTROY_PARENT_AFTER_CREATION_FORCE) {
|
||||
// Timing of Alloy style browsers may not result in abort.
|
||||
if (!use_alloy_style_browser()) {
|
||||
EXPECT_TRUE(got_on_before_popup_aborted_);
|
||||
}
|
||||
} else {
|
||||
EXPECT_FALSE(got_on_before_popup_aborted_);
|
||||
}
|
||||
|
||||
if (mode_ == ALLOW_CLOSE_POPUP_FIRST || mode_ == ALLOW_CLOSE_POPUP_LAST) {
|
||||
@@ -737,6 +819,8 @@ class PopupNavTestHandler : public TestHandler {
|
||||
const std::string rc_cache_path_;
|
||||
|
||||
TrackCallback got_on_before_popup_;
|
||||
int opener_browser_id_ = 0;
|
||||
TrackCallback got_on_before_popup_aborted_;
|
||||
TrackCallback got_load_start_;
|
||||
TrackCallback got_load_error_;
|
||||
TrackCallback got_load_end_;
|
||||
|
Reference in New Issue
Block a user