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:
Marshall Greenblatt
2024-11-08 19:05:04 -05:00
parent b660522983
commit e513077eac
45 changed files with 773 additions and 109 deletions

View File

@@ -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());
}
}

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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) {

View File

@@ -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_;

View File

@@ -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) {

View File

@@ -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());

View File

@@ -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_;

View File

@@ -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) {

View File

@@ -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_;

View File

@@ -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() {

View File

@@ -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;

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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_;