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

@ -33,7 +33,7 @@
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
// $hash=e9f34d90eb4af614e35cbb29da0639b62acec7fd$
// $hash=7b8b175b96f59916c09ac0dc9f307d07c1ad7e32$
//
#ifndef CEF_INCLUDE_CAPI_CEF_BROWSER_CAPI_H_
@ -380,6 +380,12 @@ typedef struct _cef_browser_host_t {
cef_window_handle_t(CEF_CALLBACK* get_opener_window_handle)(
struct _cef_browser_host_t* self);
///
/// Retrieve the unique identifier of the browser that opened this browser.
/// Will return 0 for non-popup browsers.
///
int(CEF_CALLBACK* get_opener_identifier)(struct _cef_browser_host_t* self);
///
/// Returns true (1) if this browser is wrapped in a cef_browser_view_t.
///
@ -1046,6 +1052,12 @@ CEF_EXPORT cef_browser_t* cef_browser_host_create_browser_sync(
struct _cef_dictionary_value_t* extra_info,
struct _cef_request_context_t* request_context);
///
/// Returns the browser (if any) with the specified identifier.
///
CEF_EXPORT cef_browser_t* cef_browser_host_get_browser_by_identifier(
int browser_id);
#ifdef __cplusplus
}
#endif

View File

@ -33,7 +33,7 @@
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
// $hash=6aad2ccf30a6c519bbeee64d83866e82a41a48d8$
// $hash=5a56a530920ced27e4adf06c8ff758c1a42bc6e7$
//
#ifndef CEF_INCLUDE_CAPI_CEF_LIFE_SPAN_HANDLER_CAPI_H_
@ -62,33 +62,40 @@ typedef struct _cef_life_span_handler_t {
///
/// Called on the UI thread before a new popup browser is created. The
/// |browser| and |frame| values represent the source of the popup request.
/// The |target_url| and |target_frame_name| values indicate where the popup
/// browser should navigate and may be NULL if not specified with the request.
/// The |target_disposition| value indicates where the user intended to open
/// the popup (e.g. current tab, new tab, etc). The |user_gesture| value will
/// be true (1) if the popup was opened via explicit user gesture (e.g.
/// clicking a link) or false (0) if the popup opened automatically (e.g. via
/// the DomContentLoaded event). The |popupFeatures| structure contains
/// additional information about the requested popup window. To allow creation
/// of the popup browser optionally modify |windowInfo|, |client|, |settings|
/// and |no_javascript_access| and return false (0). To cancel creation of the
/// |browser| and |frame| values represent the source of the popup request
/// (opener browser and frame). The |popup_id| value uniquely identifies the
/// popup in the context of the opener browser. The |target_url| and
/// |target_frame_name| values indicate where the popup browser should
/// navigate and may be NULL if not specified with the request. The
/// |target_disposition| value indicates where the user intended to open the
/// popup (e.g. current tab, new tab, etc). The |user_gesture| value will be
/// true (1) if the popup was opened via explicit user gesture (e.g. clicking
/// a link) or false (0) if the popup opened automatically (e.g. via the
/// DomContentLoaded event). The |popupFeatures| structure contains additional
/// information about the requested popup window. To allow creation of the
/// popup browser optionally modify |windowInfo|, |client|, |settings| and
/// |no_javascript_access| and return false (0). To cancel creation of the
/// popup browser return true (1). The |client| and |settings| values will
/// default to the source browser's values. If the |no_javascript_access|
/// value is set to false (0) the new browser will not be scriptable and may
/// not be hosted in the same renderer process as the source browser. Any
/// modifications to |windowInfo| will be ignored if the parent browser is
/// wrapped in a cef_browser_view_t. Popup browser creation will be canceled
/// if the parent browser is destroyed before the popup browser creation
/// completes (indicated by a call to OnAfterCreated for the popup browser).
/// The |extra_info| parameter provides an opportunity to specify extra
/// information specific to the created popup browser that will be passed to
/// wrapped in a cef_browser_view_t. The |extra_info| parameter provides an
/// opportunity to specify extra information specific to the created popup
/// browser that will be passed to
/// cef_render_process_handler_t::on_browser_created() in the render process.
///
/// If popup browser creation succeeds then OnAfterCreated will be called for
/// the new popup browser. If popup browser creation fails, and if the opener
/// browser has not yet been destroyed, then OnBeforePopupAborted will be
/// called for the opener browser. See OnBeforePopupAborted documentation for
/// additional details.
///
int(CEF_CALLBACK* on_before_popup)(
struct _cef_life_span_handler_t* self,
struct _cef_browser_t* browser,
struct _cef_frame_t* frame,
int popup_id,
const cef_string_t* target_url,
const cef_string_t* target_frame_name,
cef_window_open_disposition_t target_disposition,
@ -100,6 +107,26 @@ typedef struct _cef_life_span_handler_t {
struct _cef_dictionary_value_t** extra_info,
int* no_javascript_access);
///
/// Called on the UI thread if a new popup browser is aborted. This only
/// occurs if the popup is allowed in OnBeforePopup and creation fails before
/// OnAfterCreated is called for the new popup browser. The |browser| value is
/// the source of the popup request (opener browser). The |popup_id| value
/// uniquely identifies the popup in the context of the opener browser, and is
/// the same value that was passed to OnBeforePopup.
///
/// Any client state associated with pending popups should be cleared in
/// OnBeforePopupAborted, OnAfterCreated of the popup browser, or
/// OnBeforeClose of the opener browser. OnBeforeClose of the opener browser
/// may be called before this function in cases where the opener is closing
/// during popup creation, in which case cef_browser_host_t::IsValid will
/// return false (0) in this function.
///
void(CEF_CALLBACK* on_before_popup_aborted)(
struct _cef_life_span_handler_t* self,
struct _cef_browser_t* browser,
int popup_id);
///
/// Called on the UI thread before a new DevTools popup browser is created.
/// The |browser| value represents the source of the popup request. Optionally
@ -252,10 +279,11 @@ typedef struct _cef_life_span_handler_t {
/// browser object and do not attempt to execute any functions on the browser
/// object (other than IsValid, GetIdentifier or IsSame) after this callback
/// returns. cef_frame_handler_t callbacks related to final main frame
/// destruction will arrive after this callback and cef_browser_t::IsValid
/// will return false (0) at that time. Any in-progress network requests
/// associated with |browser| will be aborted when the browser is destroyed,
/// and cef_resource_request_handler_t callbacks related to those requests may
/// destruction, and OnBeforePopupAborted callbacks for any pending popups,
/// will arrive after this callback and cef_browser_t::IsValid will return
/// false (0) at that time. Any in-progress network requests associated with
/// |browser| will be aborted when the browser is destroyed, and
/// cef_resource_request_handler_t callbacks related to those requests may
/// still arrive on the IO thread after this callback. See cef_frame_handler_t
/// and do_close() documentation for additional usage information.
///

View File

@ -42,13 +42,13 @@
// way that may cause binary incompatibility with other builds. The universal
// hash value will change if any platform is affected whereas the platform hash
// values will change only if that particular platform is affected.
#define CEF_API_HASH_UNIVERSAL "38565e673fbcfcd9e4494914bcea03609b41ec30"
#define CEF_API_HASH_UNIVERSAL "8d6d53c5732a12b4d663665e3745a93d1cfd742d"
#if defined(OS_WIN)
#define CEF_API_HASH_PLATFORM "df2092177211214092ab77559596adbc37edf68d"
#define CEF_API_HASH_PLATFORM "3593cc6344b391d992421dd985c4ebcc46d8314f"
#elif defined(OS_MAC)
#define CEF_API_HASH_PLATFORM "aaa5bde96ceffff3de2c6fab11142c9264f44a39"
#define CEF_API_HASH_PLATFORM "c045e75415a6abc2c29a3e1e05baea7528e2ec28"
#elif defined(OS_LINUX)
#define CEF_API_HASH_PLATFORM "40de77e9ae3e071eda1f3bed7e900aedcdb354e5"
#define CEF_API_HASH_PLATFORM "b1058e8b167cfaa2f0feaccf4b4f23a813db515a"
#endif
#ifdef __cplusplus

View File

@ -324,6 +324,12 @@ class CefBrowserHost : public virtual CefBaseRefCounted {
CefRefPtr<CefDictionaryValue> extra_info,
CefRefPtr<CefRequestContext> request_context);
///
/// Returns the browser (if any) with the specified identifier.
///
/*--cef()--*/
static CefRefPtr<CefBrowser> GetBrowserByIdentifier(int browser_id);
///
/// Returns the hosted browser object.
///
@ -412,6 +418,13 @@ class CefBrowserHost : public virtual CefBaseRefCounted {
/*--cef()--*/
virtual CefWindowHandle GetOpenerWindowHandle() = 0;
///
/// Retrieve the unique identifier of the browser that opened this browser.
/// Will return 0 for non-popup browsers.
///
/*--cef()--*/
virtual int GetOpenerIdentifier() = 0;
///
/// Returns true if this browser is wrapped in a CefBrowserView.
///

View File

@ -55,13 +55,15 @@ class CefLifeSpanHandler : public virtual CefBaseRefCounted {
///
/// Called on the UI thread before a new popup browser is created. The
/// |browser| and |frame| values represent the source of the popup request.
/// The |target_url| and |target_frame_name| values indicate where the popup
/// browser should navigate and may be empty if not specified with the
/// request. The |target_disposition| value indicates where the user intended
/// to open the popup (e.g. current tab, new tab, etc). The |user_gesture|
/// value will be true if the popup was opened via explicit user gesture (e.g.
/// clicking a link) or false if the popup opened automatically (e.g. via the
/// |browser| and |frame| values represent the source of the popup request
/// (opener browser and frame). The |popup_id| value uniquely identifies the
/// popup in the context of the opener browser. The |target_url| and
/// |target_frame_name| values indicate where the popup browser should
/// navigate and may be empty if not specified with the request. The
/// |target_disposition| value indicates where the user intended to open the
/// popup (e.g. current tab, new tab, etc). The |user_gesture| value will be
/// true if the popup was opened via explicit user gesture (e.g. clicking a
/// link) or false if the popup opened automatically (e.g. via the
/// DomContentLoaded event). The |popupFeatures| structure contains additional
/// information about the requested popup window. To allow creation of the
/// popup browser optionally modify |windowInfo|, |client|, |settings| and
@ -71,16 +73,21 @@ class CefLifeSpanHandler : public virtual CefBaseRefCounted {
/// false the new browser will not be scriptable and may not be hosted in the
/// same renderer process as the source browser. Any modifications to
/// |windowInfo| will be ignored if the parent browser is wrapped in a
/// CefBrowserView. Popup browser creation will be canceled if the parent
/// browser is destroyed before the popup browser creation completes
/// (indicated by a call to OnAfterCreated for the popup browser). The
/// |extra_info| parameter provides an opportunity to specify extra
/// information specific to the created popup browser that will be passed to
/// CefRenderProcessHandler::OnBrowserCreated() in the render process.
/// CefBrowserView. The |extra_info| parameter provides an opportunity to
/// specify extra information specific to the created popup browser that will
/// be passed to CefRenderProcessHandler::OnBrowserCreated() in the render
/// process.
///
/// If popup browser creation succeeds then OnAfterCreated will be called for
/// the new popup browser. If popup browser creation fails, and if the opener
/// browser has not yet been destroyed, then OnBeforePopupAborted will be
/// called for the opener browser. See OnBeforePopupAborted documentation for
/// additional details.
///
/*--cef(optional_param=target_url,optional_param=target_frame_name)--*/
virtual bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int popup_id,
const CefString& target_url,
const CefString& target_frame_name,
WindowOpenDisposition target_disposition,
@ -94,6 +101,25 @@ class CefLifeSpanHandler : public virtual CefBaseRefCounted {
return false;
}
///
/// Called on the UI thread if a new popup browser is aborted. This only
/// occurs if the popup is allowed in OnBeforePopup and creation fails before
/// OnAfterCreated is called for the new popup browser. The |browser| value is
/// the source of the popup request (opener browser). The |popup_id| value
/// uniquely identifies the popup in the context of the opener browser, and is
/// the same value that was passed to OnBeforePopup.
///
/// Any client state associated with pending popups should be cleared in
/// OnBeforePopupAborted, OnAfterCreated of the popup browser, or
/// OnBeforeClose of the opener browser. OnBeforeClose of the opener browser
/// may be called before this method in cases where the opener is closing
/// during popup creation, in which case CefBrowserHost::IsValid will return
/// false in this method.
///
/*--cef()--*/
virtual void OnBeforePopupAborted(CefRefPtr<CefBrowser> browser,
int popup_id) {}
///
/// Called on the UI thread before a new DevTools popup browser is created.
/// The |browser| value represents the source of the popup request. Optionally
@ -242,7 +268,8 @@ class CefLifeSpanHandler : public virtual CefBaseRefCounted {
/// Called just before a browser is destroyed. Release all references to the
/// browser object and do not attempt to execute any methods on the browser
/// object (other than IsValid, GetIdentifier or IsSame) after this callback
/// returns. CefFrameHandler callbacks related to final main frame destruction
/// returns. CefFrameHandler callbacks related to final main frame
/// destruction, and OnBeforePopupAborted callbacks for any pending popups,
/// will arrive after this callback and CefBrowser::IsValid will return false
/// at that time. Any in-progress network requests associated with |browser|
/// will be aborted when the browser is destroyed, and

View File

@ -330,7 +330,7 @@ CefWindowHandle AlloyBrowserHostImpl::GetWindowHandle() {
}
CefWindowHandle AlloyBrowserHostImpl::GetOpenerWindowHandle() {
return opener_;
return opener_window_handle_;
}
void AlloyBrowserHostImpl::Find(const CefString& searchText,
@ -1414,14 +1414,17 @@ AlloyBrowserHostImpl::AlloyBrowserHostImpl(
browser_info,
request_context),
content::WebContentsObserver(web_contents),
opener_(kNullWindowHandle),
is_windowless_(platform_delegate_->IsWindowless()) {
contents_delegate_.ObserveWebContents(web_contents);
if (opener.get() && !is_views_hosted_) {
// GetOpenerWindowHandle() only returns a value for non-views-hosted
// popup browsers.
opener_ = opener->GetWindowHandle();
if (opener.get()) {
opener_id_ = opener->GetIdentifier();
if (!is_views_hosted_) {
// GetOpenerWindowHandle() only returns a value for non-views-hosted
// popup browsers.
opener_window_handle_ = opener->GetWindowHandle();
}
}
// Associate the platform delegate with this browser.

View File

@ -174,7 +174,8 @@ class AlloyBrowserHostImpl : public CefBrowserHostBase,
DestructionState destruction_state() const { return destruction_state_; }
// content::WebContentsDelegate methods.
void PrintCrossProcessSubframe(content::WebContents* web_contents,
void PrintCrossProcessSubframe(
content::WebContents* web_contents,
const gfx::Rect& rect,
int document_cookie,
content::RenderFrameHost* subframe_host) const override;
@ -317,7 +318,7 @@ class AlloyBrowserHostImpl : public CefBrowserHostBase,
void StartAudioCapturer();
void OnRecentlyAudibleTimerFired();
CefWindowHandle opener_;
CefWindowHandle opener_window_handle_ = kNullWindowHandle;
const bool is_windowless_;
CefWindowHandle host_window_handle_ = kNullWindowHandle;

View File

@ -480,6 +480,10 @@ void CefBrowserHostBase::SetFocus(bool focus) {
}
}
int CefBrowserHostBase::GetOpenerIdentifier() {
return opener_id_;
}
void CefBrowserHostBase::RunFileDialog(
FileDialogMode mode,
const CefString& title,
@ -1445,6 +1449,11 @@ bool CefBrowserHostBase::IsVisible() const {
return false;
}
int CefBrowserHostBase::GetNextPopupId() {
CEF_REQUIRE_UIT();
return next_popup_id_++;
}
bool CefBrowserHostBase::EnsureDevToolsProtocolManager() {
CEF_REQUIRE_UIT();
if (!contents_delegate_.web_contents()) {

View File

@ -220,6 +220,7 @@ class CefBrowserHostBase : public CefBrowserHost,
bool HasView() override;
bool IsReadyToBeClosed() override;
void SetFocus(bool focus) override;
int GetOpenerIdentifier() override;
void RunFileDialog(FileDialogMode mode,
const CefString& title,
const CefString& default_file_path,
@ -418,6 +419,10 @@ class CefBrowserHostBase : public CefBrowserHost,
// Returns true if this browser is currently visible.
virtual bool IsVisible() const;
// Returns the next popup ID for use with OnBeforePopup. Must be called on
// the UI thread.
int GetNextPopupId();
protected:
bool EnsureDevToolsProtocolManager();
void InitializeDevToolsRegistrationOnUIThread(
@ -439,6 +444,7 @@ class CefBrowserHostBase : public CefBrowserHost,
scoped_refptr<CefBrowserInfo> browser_info_;
CefRefPtr<CefRequestContextImpl> request_context_;
const bool is_views_hosted_;
int opener_id_ = 0;
// Only accessed on the UI thread.
CefBrowserContentsDelegate contents_delegate_;
@ -473,6 +479,8 @@ class CefBrowserHostBase : public CefBrowserHost,
std::unique_ptr<CefMediaStreamRegistrar> media_stream_registrar_;
int next_popup_id_ = 1;
private:
IMPLEMENT_REFCOUNTING(CefBrowserHostBase);
};

View File

@ -151,6 +151,21 @@ CefRefPtr<CefBrowser> CefBrowserHost::CreateBrowserSync(
return CefBrowserHostBase::Create(create_params);
}
// static
CefRefPtr<CefBrowser> CefBrowserHost::GetBrowserByIdentifier(int browser_id) {
// Verify that the context is in a valid state.
if (!CONTEXT_STATE_VALID()) {
DCHECK(false) << "context not valid";
return nullptr;
}
if (browser_id <= 0) {
return nullptr;
}
return CefBrowserHostBase::GetBrowserForBrowserId(browser_id).get();
}
// static
bool CefBrowserCreateParams::IsChromeStyle(const CefWindowInfo* window_info) {
if (!window_info) {

View File

@ -45,6 +45,14 @@ CefBrowserInfoManager* g_info_manager = nullptr;
} // namespace
CefBrowserInfoManager::PendingPopup::~PendingPopup() {
CEF_REQUIRE_UIT();
if (step != CREATION_COMPLETE && !aborted_callback.is_null()) {
// Notify of pending popup abort.
std::move(aborted_callback).Run();
}
}
CefBrowserInfoManager::CefBrowserInfoManager() {
DCHECK(!g_info_manager);
g_info_manager = this;
@ -167,14 +175,35 @@ bool CefBrowserInfoManager::CanCreateWindow(
window_info.bounds.height = cef_features.height;
}
const int popup_id = browser->GetNextPopupId();
allow = !handler->OnBeforePopup(
browser.get(), opener_frame, pending_popup->target_url.spec(),
pending_popup->target_frame_name,
browser.get(), opener_frame, popup_id,
pending_popup->target_url.spec(), pending_popup->target_frame_name,
static_cast<cef_window_open_disposition_t>(disposition), user_gesture,
cef_features, window_info, pending_popup->client,
pending_popup->settings, pending_popup->extra_info,
no_javascript_access);
handled = true;
if (allow) {
// The parent browser may be destroyed during popup creation, so don't
// bind a direct reference.
pending_popup->aborted_callback = base::BindOnce(
[](int browser_id, int popup_id) {
LOG(WARNING) << "Pending popup " << popup_id
<< " aborted for browser " << browser_id;
if (auto browser =
CefBrowserHostBase::GetBrowserForBrowserId(browser_id)) {
if (auto client = browser->GetClient()) {
if (auto handler = client->GetLifeSpanHandler()) {
handler->OnBeforePopupAborted(browser.get(), popup_id);
}
}
}
},
browser->GetIdentifier(), popup_id);
}
}
}
@ -217,12 +246,41 @@ bool CefBrowserInfoManager::CanCreateWindow(
// otherwise GetCustomWebContentsView will fail to retrieve the PopupInfo.
opener->GetProcess()->FilterURL(false, &pending_popup->target_url);
pending_create_popup_ = pending_popup.get();
// Need to Push here because WebContentsCreated may be called before
// CreateWindowResult.
PushPendingPopup(std::move(pending_popup));
}
return allow;
}
void CefBrowserInfoManager::CreateWindowResult(content::RenderFrameHost* opener,
bool success) {
// This method is called during RenderFrameHostImpl::CreateNewWindow execution
// (if CanCreateWindow returns true) with three possible states:
// 1. Before WebContentsCreated with |success=false|. This is the normal
// failure case where the pending popup will be canceled. For example, if a
// file select dialog is active.
// 2. After WebContentsCreated/AddWebContents with |success=true|. This is the
// normal success case where OnAfterCreated has already been called.
// 3. After WebContentsCreated/AddWebContents with |success=false|. This is
// the failure case where a WebContents won't have an opener from the
// renderer's perspective (for example, with JavaScript access disabled or
// no-referrer links). The WebContents is still valid, will navigate
// normally, and OnAfterCreated has already been called.
if (!success && pending_create_popup_) {
const auto* popup = pending_create_popup_.get();
pending_create_popup_ = nullptr;
// Cancel the pending popup.
std::erase_if(pending_popup_list_, [popup](const auto& popup_ptr) {
return popup_ptr.get() == popup;
});
}
}
void CefBrowserInfoManager::GetCustomWebContentsView(
const GURL& target_url,
const content::GlobalRenderFrameHostId& opener_global_id,
@ -255,6 +313,8 @@ void CefBrowserInfoManager::WebContentsCreated(
content::WebContents* new_contents) {
CEF_REQUIRE_UIT();
pending_create_popup_ = nullptr;
// GET_CUSTOM_WEB_CONTENTS_VIEW is only used with Alloy style.
auto pending_popup = PopPendingPopup(
PendingPopup::GET_CUSTOM_WEB_CONTENTS_VIEW,
@ -272,6 +332,8 @@ void CefBrowserInfoManager::WebContentsCreated(
pending_popup->step = PendingPopup::WEB_CONTENTS_CREATED;
pending_popup->new_contents = new_contents;
PushPendingPopup(std::move(pending_popup));
} else {
pending_popup->step = PendingPopup::CREATION_COMPLETE;
}
}
@ -286,6 +348,7 @@ bool CefBrowserInfoManager::AddWebContents(content::WebContents* new_contents) {
PendingPopup::WEB_CONTENTS_CREATED, new_contents);
if (pending_popup) {
DCHECK(!pending_popup->alloy_style);
pending_popup->step = PendingPopup::CREATION_COMPLETE;
return !pending_popup->use_default_browser_creation;
}
@ -589,17 +652,10 @@ void CefBrowserInfoManager::RenderProcessHostDestroyed(
}
// Remove all pending popups that reference the destroyed host as the opener.
{
PendingPopupList::iterator it = pending_popup_list_.begin();
while (it != pending_popup_list_.end()) {
PendingPopup* popup = it->get();
if (popup->opener_global_id.child_id == render_process_id) {
it = pending_popup_list_.erase(it);
} else {
++it;
}
}
}
std::erase_if(
pending_popup_list_, [render_process_id](const auto& popup_ptr) {
return popup_ptr->opener_global_id.child_id == render_process_id;
});
}
void CefBrowserInfoManager::PushPendingPopup(

View File

@ -82,6 +82,10 @@ class CefBrowserInfoManager : public content::RenderProcessHostObserver {
bool opener_suppressed,
bool* no_javascript_access);
// Called from ContentBrowserClient::CreateWindowResult if CanCreateWindow
// returns true. See comments on PendingPopup for more information.
void CreateWindowResult(content::RenderFrameHost* opener, bool success);
// Called from WebContentsDelegate::GetCustomWebContentsView (Alloy style
// only). See comments on PendingPopup for more information.
void GetCustomWebContentsView(
@ -161,23 +165,33 @@ class CefBrowserInfoManager : public content::RenderProcessHostObserver {
// RenderProcessHostObserver methods:
void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
// Store state information about pending popups. Call order is:
// Store state information about pending popups. The UIT callbacks occur
// synchronously during RenderFrameHostImpl::CreateNewWindow execution. The
// result of CreateNewWindow execution will be passed to CreateWindowResult
// (may call OnBeforePopupAborted; see documentation in that method). Call
// order for successful popup creation is is:
// - CanCreateWindow (UIT):
// Provides an opportunity to cancel the popup (calls OnBeforePopup) and
// creates the new platform delegate for the popup. If the popup owner is
// an extension guest view (PDF viewer) then the popup is canceled and
// WebContentsDelegate::OpenURLFromTab is called via the
// CefBrowserHostBase::MaybeAllowNavigation implementation.
// And then the following calls may occur at the same time:
// And then the following UIT and IOT calls may occur at the same time:
// - GetCustomWebContentsView (UIT) (Alloy style only):
// Creates the OSR views for windowless popups.
// - WebContentsCreated (UIT):
// Creates the CefBrowserHost representation for the popup.
// Creates the CefBrowserHost representation for the popup (calls
// OnAfterCreated).
// - AddWebContents (UIT) (Chrome style only):
// Creates the Browser or tab representation for the popup.
// - CefBrowserManager::GetNewBrowserInfo (IOT)
// Passes information about the popup to the renderer process.
struct PendingPopup {
~PendingPopup();
// Used to notify if popup creation is aborted.
base::OnceClosure aborted_callback;
// Track the last method that modified this PendingPopup instance. There may
// be multiple pending popups with the same identifiers and this allows us
// to differentiate between them at different processing steps.
@ -185,6 +199,7 @@ class CefBrowserInfoManager : public content::RenderProcessHostObserver {
CAN_CREATE_WINDOW,
GET_CUSTOM_WEB_CONTENTS_VIEW,
WEB_CONTENTS_CREATED,
CREATION_COMPLETE,
} step;
// True if this popup is Alloy style, otherwise Chrome style.
@ -286,6 +301,11 @@ class CefBrowserInfoManager : public content::RenderProcessHostObserver {
using PendingPopupList = std::vector<std::unique_ptr<PendingPopup>>;
PendingPopupList pending_popup_list_;
// Current popup pending creation during RenderFrameHostImpl::CreateNewWindow
// execution (valid from CanCreateWindow returning true to WebContentsCreated
// or CreateWindowResult being called). Only accessed on the UI thread.
raw_ptr<PendingPopup> pending_create_popup_ = nullptr;
int next_timeout_id_ = 0;
};

View File

@ -500,6 +500,8 @@ void ChromeBrowserHostImpl::Attach(content::WebContents* web_contents,
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(

View File

@ -369,6 +369,12 @@ bool ChromeContentBrowserClientCef::CanCreateWindow(
user_gesture, opener_suppressed, no_javascript_access);
}
void ChromeContentBrowserClientCef::CreateWindowResult(
content::RenderFrameHost* opener,
bool success) {
CefBrowserInfoManager::GetInstance()->CreateWindowResult(opener, success);
}
void ChromeContentBrowserClientCef::OverrideWebkitPrefs(
content::WebContents* web_contents,
blink::web_pref::WebPreferences* prefs) {

View File

@ -63,6 +63,8 @@ class ChromeContentBrowserClientCef : public ChromeContentBrowserClient {
bool user_gesture,
bool opener_suppressed,
bool* no_javascript_access) override;
void CreateWindowResult(content::RenderFrameHost* opener,
bool success) override;
void OverrideWebkitPrefs(content::WebContents* web_contents,
blink::web_pref::WebPreferences* prefs) override;
void WillCreateURLLoaderFactory(

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=8a2a8a4853c3869876ffad3e6c175945ac1c5021$
// $hash=c7458f64a0d7c8537dbdbcf34d11e62bf781428c$
//
#include "libcef_dll/cpptoc/browser_host_cpptoc.h"
@ -136,6 +136,20 @@ CEF_EXPORT cef_browser_t* cef_browser_host_create_browser_sync(
return CefBrowserCppToC::Wrap(_retval);
}
CEF_EXPORT cef_browser_t* cef_browser_host_get_browser_by_identifier(
int browser_id) {
shutdown_checker::AssertNotShutdown();
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
CefRefPtr<CefBrowser> _retval =
CefBrowserHost::GetBrowserByIdentifier(browser_id);
// Return type: refptr_same
return CefBrowserCppToC::Wrap(_retval);
}
namespace {
// MEMBER FUNCTIONS - Body may be edited by hand.
@ -262,6 +276,24 @@ browser_host_get_opener_window_handle(struct _cef_browser_host_t* self) {
return _retval;
}
int CEF_CALLBACK
browser_host_get_opener_identifier(struct _cef_browser_host_t* self) {
shutdown_checker::AssertNotShutdown();
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self) {
return 0;
}
// Execute
int _retval = CefBrowserHostCppToC::Get(self)->GetOpenerIdentifier();
// Return type: simple
return _retval;
}
int CEF_CALLBACK browser_host_has_view(struct _cef_browser_host_t* self) {
shutdown_checker::AssertNotShutdown();
@ -1536,6 +1568,7 @@ CefBrowserHostCppToC::CefBrowserHostCppToC() {
GetStruct()->set_focus = browser_host_set_focus;
GetStruct()->get_window_handle = browser_host_get_window_handle;
GetStruct()->get_opener_window_handle = browser_host_get_opener_window_handle;
GetStruct()->get_opener_identifier = browser_host_get_opener_identifier;
GetStruct()->has_view = browser_host_has_view;
GetStruct()->get_client = browser_host_get_client;
GetStruct()->get_request_context = browser_host_get_request_context;

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=3883fd2aca10df181da30759fcce351fed62d43d$
// $hash=b3844320e2d708a582a4bc2e3d5f2f143de8f514$
//
#include "libcef_dll/cpptoc/life_span_handler_cpptoc.h"
@ -29,6 +29,7 @@ int CEF_CALLBACK life_span_handler_on_before_popup(
struct _cef_life_span_handler_t* self,
cef_browser_t* browser,
cef_frame_t* frame,
int popup_id,
const cef_string_t* target_url,
const cef_string_t* target_frame_name,
cef_window_open_disposition_t target_disposition,
@ -128,7 +129,7 @@ int CEF_CALLBACK life_span_handler_on_before_popup(
// Execute
bool _retval = CefLifeSpanHandlerCppToC::Get(self)->OnBeforePopup(
CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame), popup_id,
CefString(target_url), CefString(target_frame_name), target_disposition,
user_gesture ? true : false, popupFeaturesVal, windowInfoObj, clientPtr,
settingsObj, extra_infoPtr, &no_javascript_accessBool);
@ -170,6 +171,29 @@ int CEF_CALLBACK life_span_handler_on_before_popup(
return _retval;
}
void CEF_CALLBACK
life_span_handler_on_before_popup_aborted(struct _cef_life_span_handler_t* self,
cef_browser_t* browser,
int popup_id) {
shutdown_checker::AssertNotShutdown();
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self) {
return;
}
// Verify param: browser; type: refptr_diff
DCHECK(browser);
if (!browser) {
return;
}
// Execute
CefLifeSpanHandlerCppToC::Get(self)->OnBeforePopupAborted(
CefBrowserCToCpp::Wrap(browser), popup_id);
}
void CEF_CALLBACK life_span_handler_on_before_dev_tools_popup(
struct _cef_life_span_handler_t* self,
cef_browser_t* browser,
@ -365,6 +389,8 @@ life_span_handler_on_before_close(struct _cef_life_span_handler_t* self,
CefLifeSpanHandlerCppToC::CefLifeSpanHandlerCppToC() {
GetStruct()->on_before_popup = life_span_handler_on_before_popup;
GetStruct()->on_before_popup_aborted =
life_span_handler_on_before_popup_aborted;
GetStruct()->on_before_dev_tools_popup =
life_span_handler_on_before_dev_tools_popup;
GetStruct()->on_after_created = life_span_handler_on_after_created;

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=2319d794dd3a38c448908114d1b4ea37b34f89dd$
// $hash=02fc65eec44894d136e5c5ed139927c675a84c6e$
//
#include "libcef_dll/ctocpp/browser_host_ctocpp.h"
@ -79,6 +79,20 @@ CefRefPtr<CefBrowser> CefBrowserHost::CreateBrowserSync(
return CefBrowserCToCpp::Wrap(_retval);
}
NO_SANITIZE("cfi-icall")
CefRefPtr<CefBrowser> CefBrowserHost::GetBrowserByIdentifier(int browser_id) {
shutdown_checker::AssertNotShutdown();
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
cef_browser_t* _retval =
cef_browser_host_get_browser_by_identifier(browser_id);
// Return type: refptr_same
return CefBrowserCToCpp::Wrap(_retval);
}
// VIRTUAL METHODS - Body may be edited by hand.
NO_SANITIZE("cfi-icall")
@ -198,6 +212,23 @@ CefWindowHandle CefBrowserHostCToCpp::GetOpenerWindowHandle() {
return _retval;
}
NO_SANITIZE("cfi-icall") int CefBrowserHostCToCpp::GetOpenerIdentifier() {
shutdown_checker::AssertNotShutdown();
cef_browser_host_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, get_opener_identifier)) {
return 0;
}
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
int _retval = _struct->get_opener_identifier(_struct);
// Return type: simple
return _retval;
}
NO_SANITIZE("cfi-icall") bool CefBrowserHostCToCpp::HasView() {
shutdown_checker::AssertNotShutdown();

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=73d8659f17a4ae3319b5bf20807d5c69a1759c04$
// $hash=f3902d95b54a26c99f532f6d04ce7e8027c86830$
//
#ifndef CEF_LIBCEF_DLL_CTOCPP_BROWSER_HOST_CTOCPP_H_
@ -45,6 +45,7 @@ class CefBrowserHostCToCpp : public CefCToCppRefCounted<CefBrowserHostCToCpp,
void SetFocus(bool focus) override;
CefWindowHandle GetWindowHandle() override;
CefWindowHandle GetOpenerWindowHandle() override;
int GetOpenerIdentifier() override;
bool HasView() override;
CefRefPtr<CefClient> GetClient() override;
CefRefPtr<CefRequestContext> GetRequestContext() override;

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=f8686b23625810a3c7ceab1097eced10acec16ce$
// $hash=fb1397bef33af6e40385469551b2037eeed8c390$
//
#include "libcef_dll/ctocpp/life_span_handler_ctocpp.h"
@ -26,6 +26,7 @@ NO_SANITIZE("cfi-icall")
bool CefLifeSpanHandlerCToCpp::OnBeforePopup(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int popup_id,
const CefString& target_url,
const CefString& target_frame_name,
WindowOpenDisposition target_disposition,
@ -81,9 +82,9 @@ bool CefLifeSpanHandlerCToCpp::OnBeforePopup(
// Execute
int _retval = _struct->on_before_popup(
_struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
target_url.GetStruct(), target_frame_name.GetStruct(), target_disposition,
user_gesture, &popupFeatures, &windowInfo, &clientStruct, &settings,
&extra_infoStruct, &no_javascript_accessInt);
popup_id, target_url.GetStruct(), target_frame_name.GetStruct(),
target_disposition, user_gesture, &popupFeatures, &windowInfo,
&clientStruct, &settings, &extra_infoStruct, &no_javascript_accessInt);
// Restore param:client; type: refptr_same_byref
if (clientStruct) {
@ -110,6 +111,30 @@ bool CefLifeSpanHandlerCToCpp::OnBeforePopup(
return _retval ? true : false;
}
NO_SANITIZE("cfi-icall")
void CefLifeSpanHandlerCToCpp::OnBeforePopupAborted(
CefRefPtr<CefBrowser> browser,
int popup_id) {
shutdown_checker::AssertNotShutdown();
cef_life_span_handler_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, on_before_popup_aborted)) {
return;
}
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: browser; type: refptr_diff
DCHECK(browser.get());
if (!browser.get()) {
return;
}
// Execute
_struct->on_before_popup_aborted(_struct, CefBrowserCppToC::Wrap(browser),
popup_id);
}
NO_SANITIZE("cfi-icall")
void CefLifeSpanHandlerCToCpp::OnBeforeDevToolsPopup(
CefRefPtr<CefBrowser> browser,

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=787463118d294d6a9b1004b54fb26b05c9f0a47b$
// $hash=2e0ae9e4f7e647e43dc4d28fde904298550349e6$
//
#ifndef CEF_LIBCEF_DLL_CTOCPP_LIFE_SPAN_HANDLER_CTOCPP_H_
@ -39,6 +39,7 @@ class CefLifeSpanHandlerCToCpp
// CefLifeSpanHandler methods.
bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int popup_id,
const CefString& target_url,
const CefString& target_frame_name,
WindowOpenDisposition target_disposition,
@ -49,6 +50,8 @@ class CefLifeSpanHandlerCToCpp
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,

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=85864cf7616899c4d51fbaf995d8e0db55249bd7$
// $hash=c4ecb087f15c4b73a529efc0b0715064ebb7fe2b$
//
#include <dlfcn.h>
@ -152,6 +152,8 @@ struct libcef_pointers {
decltype(&cef_browser_host_create_browser) cef_browser_host_create_browser;
decltype(&cef_browser_host_create_browser_sync)
cef_browser_host_create_browser_sync;
decltype(&cef_browser_host_get_browser_by_identifier)
cef_browser_host_get_browser_by_identifier;
decltype(&cef_command_line_create) cef_command_line_create;
decltype(&cef_command_line_get_global) cef_command_line_get_global;
decltype(&cef_cookie_manager_get_global_manager)
@ -397,6 +399,7 @@ int libcef_init_pointers(const char* path) {
INIT_ENTRY(cef_is_feature_enabled_for_tests);
INIT_ENTRY(cef_browser_host_create_browser);
INIT_ENTRY(cef_browser_host_create_browser_sync);
INIT_ENTRY(cef_browser_host_get_browser_by_identifier);
INIT_ENTRY(cef_command_line_create);
INIT_ENTRY(cef_command_line_get_global);
INIT_ENTRY(cef_cookie_manager_get_global_manager);
@ -901,6 +904,13 @@ struct _cef_browser_t* cef_browser_host_create_browser_sync(
windowInfo, client, url, settings, extra_info, request_context);
}
NO_SANITIZE("cfi-icall")
struct _cef_browser_t* cef_browser_host_get_browser_by_identifier(
int browser_id) {
return g_libcef_pointers.cef_browser_host_get_browser_by_identifier(
browser_id);
}
NO_SANITIZE("cfi-icall") struct _cef_command_line_t* cef_command_line_create() {
return g_libcef_pointers.cef_command_line_create();
}

View File

@ -400,6 +400,9 @@ patches = [
# Change ContentBrowserClient::ConfigureNetworkContextParams return type to
# bool to support cancellation of NetworkContext creation during shutdown.
# https://github.com/chromiumembedded/cef/issues/2985
#
# Add ContentBrowserClient::CreateWindowResult callback.
# https://github.com/chromiumembedded/cef/issues/3776
'name': 'content_2015',
},
{
@ -639,6 +642,9 @@ patches = [
# Partially reverts the below changes.
# https://chromium-review.googlesource.com/c/chromium/src/+/4829483
# https://bugs.chromium.org/p/chromium/issues/detail?id=1470837#c22
#
# Add ContentBrowserClient::CreateWindowResult callback.
# https://github.com/chromiumembedded/cef/issues/3776
'name': 'rfh_navigation_4829483'
},
{

View File

@ -68,10 +68,23 @@ index 21967547790ca..7bdf48b830a21 100644
std::vector<base::FilePath>
diff --git content/public/browser/content_browser_client.h content/public/browser/content_browser_client.h
index 0f6781dc459e1..8d8deaba4e049 100644
index 0f6781dc459e1..3f3095cce2ba6 100644
--- content/public/browser/content_browser_client.h
+++ content/public/browser/content_browser_client.h
@@ -2188,7 +2188,7 @@ class CONTENT_EXPORT ContentBrowserClient {
@@ -1329,6 +1329,12 @@ class CONTENT_EXPORT ContentBrowserClient {
bool opener_suppressed,
bool* no_javascript_access);
+ // Called to report the result of new window creation after CanCreateWindow()
+ // returns true. There are cases where the new window may still be canceled.
+ virtual void CreateWindowResult(
+ RenderFrameHost* opener,
+ bool success) {}
+
// Allows the embedder to return a delegate for the SpeechRecognitionManager.
// The delegate will be owned by the manager. It's valid to return nullptr.
virtual SpeechRecognitionManagerDelegate*
@@ -2188,7 +2194,7 @@ class CONTENT_EXPORT ContentBrowserClient {
//
// If |relative_partition_path| is the empty string, it means this needs to
// create the default NetworkContext for the BrowserContext.
@ -80,7 +93,7 @@ index 0f6781dc459e1..8d8deaba4e049 100644
BrowserContext* context,
bool in_memory,
const base::FilePath& relative_partition_path,
@@ -2412,6 +2412,22 @@ class CONTENT_EXPORT ContentBrowserClient {
@@ -2412,6 +2418,22 @@ class CONTENT_EXPORT ContentBrowserClient {
const net::IsolationInfo& isolation_info,
mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory);
@ -103,7 +116,7 @@ index 0f6781dc459e1..8d8deaba4e049 100644
// Creates an OverlayWindow to be used for video or Picture-in-Picture.
// This window will house the content shown when in Picture-in-Picture mode.
// This will return a new OverlayWindow.
@@ -2472,6 +2488,10 @@ class CONTENT_EXPORT ContentBrowserClient {
@@ -2472,6 +2494,10 @@ class CONTENT_EXPORT ContentBrowserClient {
// Used as part of the user agent string.
virtual std::string GetProduct();

View File

@ -1,8 +1,25 @@
diff --git content/browser/renderer_host/render_frame_host_impl.cc content/browser/renderer_host/render_frame_host_impl.cc
index 98c865765c57d..7694cd4516dc9 100644
index 98c865765c57d..f31210f9c3070 100644
--- content/browser/renderer_host/render_frame_host_impl.cc
+++ content/browser/renderer_host/render_frame_host_impl.cc
@@ -11466,6 +11466,7 @@ void RenderFrameHostImpl::CommitNavigation(
@@ -9125,6 +9125,16 @@ void RenderFrameHostImpl::CreateNewWindow(
return;
}
+ callback = base::BindOnce(
+ [](RenderFrameHostImpl* self,
+ CreateNewWindowCallback callback,
+ mojom::CreateNewWindowStatus status,
+ mojom::CreateNewWindowReplyPtr reply) {
+ GetContentClient()->browser()->CreateWindowResult(
+ self, status == mojom::CreateNewWindowStatus::kSuccess);
+ std::move(callback).Run(status, std::move(reply));
+ }, base::Unretained(this), std::move(callback));
+
// Otherwise, consume user activation before we proceed. In particular, it is
// important to do this before we return from the |opener_suppressed| case
// below.
@@ -11466,6 +11476,7 @@ void RenderFrameHostImpl::CommitNavigation(
auto browser_calc_origin_to_commit =
navigation_request->GetOriginToCommitWithDebugInfo();
if (!process_lock.is_error_page() && !is_mhtml_subframe &&

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