Skip to content

Commit

Permalink
Add notification for aborted popups (fixes #3776)
Browse files Browse the repository at this point in the history
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`.
  • Loading branch information
magreenblatt committed Nov 13, 2024
1 parent b91be9f commit 1a99a3a
Show file tree
Hide file tree
Showing 45 changed files with 773 additions and 109 deletions.
14 changes: 13 additions & 1 deletion include/capi/cef_browser_capi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_
Expand Down Expand Up @@ -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.
///
Expand Down Expand Up @@ -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
Expand Down
70 changes: 49 additions & 21 deletions include/capi/cef_life_span_handler_capi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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.
///
Expand Down
8 changes: 4 additions & 4 deletions include/cef_api_hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions include/cef_browser.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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.
///
Expand Down
55 changes: 41 additions & 14 deletions include/cef_life_span_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
15 changes: 9 additions & 6 deletions libcef/browser/alloy/alloy_browser_host_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ CefWindowHandle AlloyBrowserHostImpl::GetWindowHandle() {
}

CefWindowHandle AlloyBrowserHostImpl::GetOpenerWindowHandle() {
return opener_;
return opener_window_handle_;
}

void AlloyBrowserHostImpl::Find(const CefString& searchText,
Expand Down Expand Up @@ -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.
Expand Down
5 changes: 3 additions & 2 deletions libcef/browser/alloy/alloy_browser_host_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down
9 changes: 9 additions & 0 deletions libcef/browser/browser_host_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,10 @@ void CefBrowserHostBase::SetFocus(bool focus) {
}
}

int CefBrowserHostBase::GetOpenerIdentifier() {
return opener_id_;
}

void CefBrowserHostBase::RunFileDialog(
FileDialogMode mode,
const CefString& title,
Expand Down Expand Up @@ -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()) {
Expand Down
8 changes: 8 additions & 0 deletions libcef/browser/browser_host_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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(
Expand All @@ -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_;
Expand Down Expand Up @@ -473,6 +479,8 @@ class CefBrowserHostBase : public CefBrowserHost,

std::unique_ptr<CefMediaStreamRegistrar> media_stream_registrar_;

int next_popup_id_ = 1;

private:
IMPLEMENT_REFCOUNTING(CefBrowserHostBase);
};
Expand Down
Loading

0 comments on commit 1a99a3a

Please sign in to comment.