diff --git a/BUILD.gn b/BUILD.gn index 6cae9b0ad..b3a64badc 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -839,6 +839,7 @@ source_set("libcef_static") { "libcef/common/values_impl.h", "libcef/common/waitable_event_impl.cc", "libcef/common/waitable_event_impl.h", + "libcef/renderer/browser_config.h", "libcef/renderer/browser_impl.cc", "libcef/renderer/browser_impl.h", "libcef/renderer/chrome/chrome_content_renderer_client_cef.cc", diff --git a/include/views/cef_browser_view_delegate.h b/include/views/cef_browser_view_delegate.h index bdf132608..013e8f45f 100644 --- a/include/views/cef_browser_view_delegate.h +++ b/include/views/cef_browser_view_delegate.h @@ -38,6 +38,7 @@ #define CEF_INCLUDE_VIEWS_CEF_BROWSER_VIEW_DELEGATE_H_ #pragma once +#include "include/cef_api_hash.h" #include "include/cef_client.h" #include "include/views/cef_view_delegate.h" @@ -129,6 +130,18 @@ class CefBrowserViewDelegate : public CefViewDelegate { return false; } +#if CEF_API_ADDED(CEF_NEXT) + /// + /// Return true to allow the use of JavaScript moveTo/By() and resizeTo/By() + /// (without user activation) with Document picture-in-picture popups. + /// + /*--cef(added=next)--*/ + virtual bool AllowMoveForPictureInPicture( + CefRefPtr browser_view) { + return false; + } +#endif + /// /// Called when |browser_view| receives a gesture command. Return true to /// handle (or disable) a |gesture_command| or false to propagate the gesture diff --git a/libcef/browser/alloy/alloy_browser_host_impl.cc b/libcef/browser/alloy/alloy_browser_host_impl.cc index 26262835c..2019d0cbf 100644 --- a/libcef/browser/alloy/alloy_browser_host_impl.cc +++ b/libcef/browser/alloy/alloy_browser_host_impl.cc @@ -117,8 +117,7 @@ CefRefPtr AlloyBrowserHostImpl::Create( scoped_refptr info = CefBrowserInfoManager::GetInstance()->CreateBrowserInfo( - /*is_devtools_popup=*/false, platform_delegate->IsWindowless(), - platform_delegate->IsPrintPreviewSupported(), + /*is_devtools_popup=*/false, platform_delegate->GetBrowserConfig(), create_params.extra_info); bool own_web_contents = false; @@ -132,8 +131,7 @@ CefRefPtr AlloyBrowserHostImpl::Create( CefRefPtr browser = CreateInternal(create_params.settings, create_params.client, web_contents, - own_web_contents, info, - /*opener=*/nullptr, /*is_devtools_popup=*/false, + own_web_contents, info, /*opener=*/nullptr, request_context_impl, std::move(platform_delegate)); if (!browser) { return nullptr; @@ -160,7 +158,6 @@ CefRefPtr AlloyBrowserHostImpl::CreateInternal( bool own_web_contents, scoped_refptr browser_info, CefRefPtr opener, - bool is_devtools_popup, CefRefPtr request_context, std::unique_ptr platform_delegate) { CEF_REQUIRE_UIT(); @@ -185,7 +182,7 @@ CefRefPtr AlloyBrowserHostImpl::CreateInternal( // new browser's platform delegate. opener->platform_delegate_->PopupWebContentsCreated( settings, client, web_contents, platform_delegate.get(), - is_devtools_popup); + /*is_devtools=*/false); } // Take ownership of |web_contents| if |own_web_contents| is true. @@ -208,7 +205,7 @@ CefRefPtr AlloyBrowserHostImpl::CreateInternal( // result in a call to CefBrowserViewDelegate::OnPopupBrowserViewCreated(). // Do this first for consistency with Chrome style. opener->platform_delegate_->PopupBrowserCreated( - browser->platform_delegate(), browser.get(), is_devtools_popup); + browser->platform_delegate(), browser.get(), /*is_devtools=*/false); } // 2. Notify the browser's LifeSpanHandler. This must always be the first @@ -1121,8 +1118,7 @@ void AlloyBrowserHostImpl::WebContentsCreated( scoped_refptr info = CefBrowserInfoManager::GetInstance()->CreatePopupBrowserInfo( - new_contents, platform_delegate->IsWindowless(), - platform_delegate->IsPrintPreviewSupported(), extra_info); + new_contents, platform_delegate->GetBrowserConfig(), extra_info); CHECK(info.get()); CHECK(info->is_popup()); @@ -1140,8 +1136,7 @@ void AlloyBrowserHostImpl::WebContentsCreated( // However, we need to install observers/delegates here. CefRefPtr browser = CreateInternal( settings, client, new_contents, /*own_web_contents=*/false, info, opener, - /*is_devtools_popup=*/false, request_context, - std::move(platform_delegate)); + request_context, std::move(platform_delegate)); } void AlloyBrowserHostImpl::RendererUnresponsive( diff --git a/libcef/browser/alloy/alloy_browser_host_impl.h b/libcef/browser/alloy/alloy_browser_host_impl.h index d75cdbc95..04be12c2d 100644 --- a/libcef/browser/alloy/alloy_browser_host_impl.h +++ b/libcef/browser/alloy/alloy_browser_host_impl.h @@ -298,7 +298,6 @@ class AlloyBrowserHostImpl : public CefBrowserHostBase, bool own_web_contents, scoped_refptr browser_info, CefRefPtr opener, - bool is_devtools_popup, CefRefPtr request_context, std::unique_ptr platform_delegate); diff --git a/libcef/browser/browser_info.cc b/libcef/browser/browser_info.cc index f19cc21aa..94bc97db5 100644 --- a/libcef/browser/browser_info.cc +++ b/libcef/browser/browser_info.cc @@ -28,13 +28,11 @@ CefBrowserInfo::FrameInfo::~FrameInfo() { CefBrowserInfo::CefBrowserInfo(int browser_id, bool is_popup, - bool is_windowless, - bool print_preview_enabled, + const cef::BrowserConfig& config, CefRefPtr extra_info) : browser_id_(browser_id), is_popup_(is_popup), - is_windowless_(is_windowless), - print_preview_enabled_(print_preview_enabled), + config_(config), extra_info_(extra_info) { DCHECK_GT(browser_id, 0); diff --git a/libcef/browser/browser_info.h b/libcef/browser/browser_info.h index 50f658e39..8a96baf0a 100644 --- a/libcef/browser/browser_info.h +++ b/libcef/browser/browser_info.h @@ -19,6 +19,7 @@ #include "base/values.h" #include "cef/include/internal/cef_ptr.h" #include "cef/libcef/common/values_impl.h" +#include "cef/libcef/renderer/browser_config.h" #include "content/public/browser/global_routing_id.h" #include "content/public/browser/render_frame_host.h" @@ -36,8 +37,7 @@ class CefBrowserInfo : public base::RefCountedThreadSafe { public: CefBrowserInfo(int browser_id, bool is_popup, - bool is_windowless, - bool print_preview_enabled, + const cef::BrowserConfig& config, CefRefPtr extra_info); CefBrowserInfo(const CefBrowserInfo&) = delete; @@ -45,8 +45,7 @@ class CefBrowserInfo : public base::RefCountedThreadSafe { int browser_id() const { return browser_id_; } bool is_popup() const { return is_popup_; } - bool is_windowless() const { return is_windowless_; } - bool print_preview_enabled() const { return print_preview_enabled_; } + const cef::BrowserConfig& config() const { return config_; } CefRefPtr extra_info() const { return extra_info_; } // May return nullptr if the browser has not yet been created (before @@ -202,8 +201,7 @@ class CefBrowserInfo : public base::RefCountedThreadSafe { const int browser_id_; const bool is_popup_; - const bool is_windowless_; - const bool print_preview_enabled_; + const cef::BrowserConfig config_; CefRefPtr extra_info_; // Navigation will be blocked while |navigation_lock_| exists. diff --git a/libcef/browser/browser_info_manager.cc b/libcef/browser/browser_info_manager.cc index 03edb77d2..06e6a3851 100644 --- a/libcef/browser/browser_info_manager.cc +++ b/libcef/browser/browser_info_manager.cc @@ -69,15 +69,13 @@ CefBrowserInfoManager* CefBrowserInfoManager::GetInstance() { } scoped_refptr CefBrowserInfoManager::CreateBrowserInfo( - bool is_popup, - bool is_windowless, - bool print_preview_enabled, + bool is_devtools_popup, + const cef::BrowserConfig& config, CefRefPtr extra_info) { base::AutoLock lock_scope(browser_info_lock_); - scoped_refptr browser_info = - new CefBrowserInfo(++next_browser_id_, is_popup, is_windowless, - print_preview_enabled, extra_info); + scoped_refptr browser_info = new CefBrowserInfo( + ++next_browser_id_, is_devtools_popup, config, extra_info); browser_info_list_.push_back(browser_info); return browser_info; @@ -85,8 +83,7 @@ scoped_refptr CefBrowserInfoManager::CreateBrowserInfo( scoped_refptr CefBrowserInfoManager::CreatePopupBrowserInfo( content::WebContents* new_contents, - bool is_windowless, - bool print_preview_enabled, + const cef::BrowserConfig& config, CefRefPtr extra_info) { CEF_REQUIRE_UIT(); @@ -95,8 +92,8 @@ scoped_refptr CefBrowserInfoManager::CreatePopupBrowserInfo( scoped_refptr browser_info; { base::AutoLock lock_scope(browser_info_lock_); - browser_info = new CefBrowserInfo(++next_browser_id_, true, is_windowless, - print_preview_enabled, extra_info); + browser_info = + new CefBrowserInfo(++next_browser_id_, true, config, extra_info); browser_info_list_.push_back(browser_info); } @@ -777,9 +774,14 @@ void CefBrowserInfoManager::SendNewBrowserInfoResponse( if (browser_info) { params->browser_id = browser_info->browser_id(); - params->is_windowless = browser_info->is_windowless(); - params->is_popup = browser_info->is_popup(); - params->print_preview_enabled = browser_info->print_preview_enabled(); + + auto config = cef::mojom::NewBrowserConfig::New(); + config->is_popup = browser_info->is_popup(); + config->is_windowless = browser_info->config().is_windowless; + config->print_preview_enabled = + browser_info->config().print_preview_enabled; + config->move_pip_enabled = browser_info->config().move_pip_enabled; + params->config = std::move(config); auto extra_info = browser_info->extra_info(); if (extra_info) { diff --git a/libcef/browser/browser_info_manager.h b/libcef/browser/browser_info_manager.h index 486605e9b..afc4cdf32 100644 --- a/libcef/browser/browser_info_manager.h +++ b/libcef/browser/browser_info_manager.h @@ -53,11 +53,10 @@ class CefBrowserInfoManager : public content::RenderProcessHostObserver { static CefBrowserInfoManager* GetInstance(); // Called immediately before a new CefBrowserHost implementation is created - // directly. In this case |is_popup| will be true only for DevTools browsers. + // directly. scoped_refptr CreateBrowserInfo( - bool is_popup, - bool is_windowless, - bool print_preview_enabled, + bool is_devtools_popup, + const cef::BrowserConfig& config, CefRefPtr extra_info); // Called from WebContentsDelegate::WebContentsCreated when a new browser is @@ -66,8 +65,7 @@ class CefBrowserInfoManager : public content::RenderProcessHostObserver { // response will be sent when this method is called. scoped_refptr CreatePopupBrowserInfo( content::WebContents* new_contents, - bool is_windowless, - bool print_preview_enabled, + const cef::BrowserConfig& config, CefRefPtr extra_info); // Called from ContentBrowserClient::CanCreateWindow. See comments on diff --git a/libcef/browser/browser_platform_delegate.cc b/libcef/browser/browser_platform_delegate.cc index 611ffbd74..3f940c250 100644 --- a/libcef/browser/browser_platform_delegate.cc +++ b/libcef/browser/browser_platform_delegate.cc @@ -567,6 +567,15 @@ bool CefBrowserPlatformDelegate::IsPrintPreviewSupported() const { return true; } +bool CefBrowserPlatformDelegate::IsMovePictureInPictureEnabled() const { + return false; +} + +cef::BrowserConfig CefBrowserPlatformDelegate::GetBrowserConfig() const { + return {IsWindowless(), IsPrintPreviewSupported(), + IsMovePictureInPictureEnabled()}; +} + void CefBrowserPlatformDelegate::Find(const CefString& searchText, bool forward, bool matchCase, diff --git a/libcef/browser/browser_platform_delegate.h b/libcef/browser/browser_platform_delegate.h index 2cb32aa4e..6b3f6cde3 100644 --- a/libcef/browser/browser_platform_delegate.h +++ b/libcef/browser/browser_platform_delegate.h @@ -15,6 +15,7 @@ #include "cef/include/cef_drag_data.h" #include "cef/include/internal/cef_types.h" #include "cef/include/views/cef_browser_view.h" +#include "cef/libcef/renderer/browser_config.h" #include "third_party/blink/public/common/page/drag_operation.h" #include "third_party/blink/public/mojom/drag/drag.mojom-forward.h" #include "third_party/skia/include/core/SkColor.h" @@ -370,6 +371,12 @@ class CefBrowserPlatformDelegate { bool findNext); virtual void StopFinding(bool clearSelection); + virtual bool IsMovePictureInPictureEnabled() const; + + // CefBrowser configuration determined prior to CefBrowserHost creation and + // passed to the renderer process via the GetNewBrowserInfo Mojo request. + cef::BrowserConfig GetBrowserConfig() const; + protected: // Allow deletion via std::unique_ptr only. friend std::default_delete; diff --git a/libcef/browser/chrome/chrome_browser_delegate.cc b/libcef/browser/chrome/chrome_browser_delegate.cc index 12cf9ccda..4ba866483 100644 --- a/libcef/browser/chrome/chrome_browser_delegate.cc +++ b/libcef/browser/chrome/chrome_browser_delegate.cc @@ -260,8 +260,8 @@ void ChromeBrowserDelegate::SetAsDelegate(content::WebContents* web_contents, CHECK(platform_delegate->IsChromeStyle()); auto browser_info = CefBrowserInfoManager::GetInstance()->CreateBrowserInfo( - is_devtools_popup, /*is_windowless=*/false, - platform_delegate->IsPrintPreviewSupported(), create_params_.extra_info); + is_devtools_popup, platform_delegate->GetBrowserConfig(), + create_params_.extra_info); auto request_context_impl = CefRequestContextImpl::GetOrCreateForRequestContext( @@ -759,8 +759,7 @@ ChromeBrowserDelegate::CreateBrowserHostForPopup( auto browser_info = CefBrowserInfoManager::GetInstance()->CreatePopupBrowserInfo( - web_contents, /*is_windowless=*/false, - platform_delegate->IsPrintPreviewSupported(), extra_info); + web_contents, platform_delegate->GetBrowserConfig(), extra_info); CHECK(browser_info->is_popup()); // Popups must share the same RequestContext as the parent. diff --git a/libcef/browser/chrome/chrome_browser_host_impl.cc b/libcef/browser/chrome/chrome_browser_host_impl.cc index 1516a8773..bea3c3fd4 100644 --- a/libcef/browser/chrome/chrome_browser_host_impl.cc +++ b/libcef/browser/chrome/chrome_browser_host_impl.cc @@ -500,8 +500,7 @@ void ChromeBrowserHostImpl::Attach(content::WebContents* web_contents, is_devtools_popup); } - platform_delegate_->WebContentsCreated(web_contents, - /*own_web_contents=*/false); + platform_delegate_->WebContentsCreated(web_contents, /*owned=*/false); contents_delegate_.ObserveWebContents(web_contents); // Associate the platform delegate with this browser. diff --git a/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.cc b/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.cc index c1d635301..2c55f842d 100644 --- a/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.cc +++ b/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.cc @@ -130,6 +130,16 @@ bool CefBrowserPlatformDelegateChromeViews::IsViewsHosted() const { return true; } +bool CefBrowserPlatformDelegateChromeViews::IsMovePictureInPictureEnabled() + const { + if (browser_view_) { + if (auto* delegate = browser_view_->delegate()) { + return delegate->AllowMoveForPictureInPicture(browser_view_.get()); + } + } + return false; +} + CefWindowImpl* CefBrowserPlatformDelegateChromeViews::GetWindowImpl() const { if (auto* widget = GetWindowWidget()) { CefRefPtr window = view_util::GetWindowFor(widget); diff --git a/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h b/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h index ed456ac49..3023620e7 100644 --- a/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h +++ b/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h @@ -34,6 +34,7 @@ class CefBrowserPlatformDelegateChromeViews void SetBrowserView(CefRefPtr browser_view) override; void SetFocus(bool setFocus) override; bool IsViewsHosted() const override; + bool IsMovePictureInPictureEnabled() const override; CefBrowserViewImpl* browser_view() const { return browser_view_.get(); } diff --git a/libcef/common/mojom/cef.mojom b/libcef/common/mojom/cef.mojom index b82d9d397..66935451a 100644 --- a/libcef/common/mojom/cef.mojom +++ b/libcef/common/mojom/cef.mojom @@ -111,12 +111,19 @@ struct NewRenderThreadInfo { array? cross_origin_whitelist_entries; }; +struct NewBrowserConfig { + bool is_popup; + + // Values from cef::BrowserConfig. + bool is_windowless; + bool print_preview_enabled; + bool move_pip_enabled; +}; + struct NewBrowserInfo { int32 browser_id; - bool? is_popup; - bool? is_windowless; - bool? print_preview_enabled; bool is_excluded; + NewBrowserConfig? config; mojo_base.mojom.DictionaryValue? extra_info; }; diff --git a/libcef/renderer/browser_config.h b/libcef/renderer/browser_config.h new file mode 100644 index 000000000..88ba79fd2 --- /dev/null +++ b/libcef/renderer/browser_config.h @@ -0,0 +1,22 @@ +// Copyright 2025 The Chromium Embedded Framework Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can +// be found in the LICENSE file. + +#ifndef CEF_LIBCEF_RENDERER_BROWSER_CONFIG_H_ +#define CEF_LIBCEF_RENDERER_BROWSER_CONFIG_H_ +#pragma once + +namespace cef { + +// CefBrowser configuration determined prior to CefBrowserHost creation (in +// CefBrowserPlatformDelegate::GetBrowserConfig) and passed to the renderer +// process via the GetNewBrowserInfo Mojo request. +struct BrowserConfig { + bool is_windowless; + bool print_preview_enabled; + bool move_pip_enabled; +}; + +} // namespace cef + +#endif // CEF_LIBCEF_RENDERER_BROWSER_CONFIG_H_ diff --git a/libcef/renderer/browser_impl.cc b/libcef/renderer/browser_impl.cc index b488ed365..fb44774b7 100644 --- a/libcef/renderer/browser_impl.cc +++ b/libcef/renderer/browser_impl.cc @@ -276,13 +276,11 @@ void CefBrowserImpl::GetFrameNames(std::vector& names) { CefBrowserImpl::CefBrowserImpl(blink::WebView* web_view, int browser_id, bool is_popup, - bool is_windowless, - bool print_preview_enabled) + const cef::BrowserConfig& config) : blink::WebViewObserver(web_view), browser_id_(browser_id), is_popup_(is_popup), - is_windowless_(is_windowless), - print_preview_enabled_(print_preview_enabled) {} + config_(config) {} CefBrowserImpl::~CefBrowserImpl() = default; diff --git a/libcef/renderer/browser_impl.h b/libcef/renderer/browser_impl.h index 2e12c7fef..b06678e55 100644 --- a/libcef/renderer/browser_impl.h +++ b/libcef/renderer/browser_impl.h @@ -16,6 +16,7 @@ #include "cef/include/cef_browser.h" #include "cef/include/cef_client.h" +#include "cef/libcef/renderer/browser_config.h" #include "cef/libcef/renderer/frame_impl.h" #include "third_party/blink/public/common/tokens/tokens.h" #include "third_party/blink/public/web/web_view_observer.h" @@ -66,8 +67,7 @@ class CefBrowserImpl : public CefBrowser, public blink::WebViewObserver { CefBrowserImpl(blink::WebView* web_view, int browser_id, bool is_popup, - bool is_windowless, - bool print_preview_enabled); + const cef::BrowserConfig& config); CefBrowserImpl(const CefBrowserImpl&) = delete; CefBrowserImpl& operator=(const CefBrowserImpl&) = delete; @@ -80,8 +80,7 @@ class CefBrowserImpl : public CefBrowser, public blink::WebViewObserver { int browser_id() const { return browser_id_; } bool is_popup() const { return is_popup_; } - bool is_windowless() const { return is_windowless_; } - bool print_preview_enabled() const { return print_preview_enabled_; } + const cef::BrowserConfig& config() const { return config_; } // blink::WebViewObserver methods. void OnDestruct() override; @@ -96,8 +95,7 @@ class CefBrowserImpl : public CefBrowser, public blink::WebViewObserver { // same browser ID. const int browser_id_; const bool is_popup_; - const bool is_windowless_; - const bool print_preview_enabled_; + const cef::BrowserConfig config_; // Map of unique frame tokens to CefFrameImpl references. using FrameMap = std::map>; diff --git a/libcef/renderer/chrome/chrome_content_renderer_client_cef.cc b/libcef/renderer/chrome/chrome_content_renderer_client_cef.cc index 01decd6a2..31c4d6f83 100644 --- a/libcef/renderer/chrome/chrome_content_renderer_client_cef.cc +++ b/libcef/renderer/chrome/chrome_content_renderer_client_cef.cc @@ -46,20 +46,19 @@ void ChromeContentRendererClientCef::RenderFrameCreated( new CefRenderFrameObserver(render_frame); bool browser_created; - std::optional is_windowless; - std::optional print_preview_enabled; + std::optional config; render_manager_->RenderFrameCreated(render_frame, render_frame_observer, - browser_created, is_windowless, - print_preview_enabled); + browser_created, config); if (browser_created) { - OnBrowserCreated(render_frame->GetWebView(), is_windowless); + CHECK(config.has_value()); + OnBrowserCreated(render_frame->GetWebView(), *config); } - if (print_preview_enabled.has_value()) { - // This value will be used when the when ChromeContentRendererClient + if (config.has_value()) { + // This value will be used when the ChromeContentRendererClient // creates the new ChromePrintRenderFrameHelperDelegate below. ChromePrintRenderFrameHelperDelegate::SetNextPrintPreviewEnabled( - *print_preview_enabled); + (*config).print_preview_enabled); } ChromeContentRendererClient::RenderFrameCreated(render_frame); @@ -73,12 +72,11 @@ void ChromeContentRendererClientCef::WebViewCreated( outermost_origin); bool browser_created; - std::optional is_windowless; - std::optional print_preview_enabled; - render_manager_->WebViewCreated(web_view, browser_created, is_windowless, - print_preview_enabled); + std::optional config; + render_manager_->WebViewCreated(web_view, browser_created, config); if (browser_created) { - OnBrowserCreated(web_view, is_windowless); + CHECK(config.has_value()); + OnBrowserCreated(web_view, *config); } } @@ -117,14 +115,9 @@ void ChromeContentRendererClientCef::ExposeInterfacesToBrowser( void ChromeContentRendererClientCef::OnBrowserCreated( blink::WebView* web_view, - std::optional is_windowless) { + const cef::BrowserConfig& config) { #if BUILDFLAG(IS_MAC) - const bool windowless = is_windowless.has_value() && *is_windowless; - - // FIXME: It would be better if this API would be a callback from the - // WebKit layer, or if it would be exposed as an WebView instance method; the - // current implementation uses a static variable, and WebKit needs to be - // patched in order to make it work for each WebView instance - web_view->SetUseExternalPopupMenusThisInstance(!windowless); + web_view->SetUseExternalPopupMenusThisInstance(!config.is_windowless); #endif + web_view->SetMovePictureInPictureEnabled(config.move_pip_enabled); } diff --git a/libcef/renderer/chrome/chrome_content_renderer_client_cef.h b/libcef/renderer/chrome/chrome_content_renderer_client_cef.h index 840f64c61..7275eae99 100644 --- a/libcef/renderer/chrome/chrome_content_renderer_client_cef.h +++ b/libcef/renderer/chrome/chrome_content_renderer_client_cef.h @@ -12,6 +12,10 @@ #include "base/task/single_thread_task_runner.h" #include "chrome/renderer/chrome_content_renderer_client.h" +namespace cef { +struct BrowserConfig; +} + class CefRenderManager; // CEF override of ChromeContentRendererClient. @@ -48,7 +52,7 @@ class ChromeContentRendererClientCef : public ChromeContentRendererClient { private: void OnBrowserCreated(blink::WebView* web_view, - std::optional is_windowless); + const cef::BrowserConfig& config); std::unique_ptr render_manager_; diff --git a/libcef/renderer/render_manager.cc b/libcef/renderer/render_manager.cc index 78f9f2179..54f57dbb6 100644 --- a/libcef/renderer/render_manager.cc +++ b/libcef/renderer/render_manager.cc @@ -56,25 +56,17 @@ class CefExcludedView : public blink::WebViewObserver { public: CefExcludedView(CefRenderManager* manager, blink::WebView* web_view, - std::optional is_windowless, - std::optional print_preview_enabled) - : blink::WebViewObserver(web_view), - manager_(manager), - is_windowless_(is_windowless), - print_preview_enabled_(print_preview_enabled) {} + const std::optional& config) + : blink::WebViewObserver(web_view), manager_(manager), config_(config) {} - std::optional is_windowless() const { return is_windowless_; } - std::optional print_preview_enabled() const { - return print_preview_enabled_; - } + const std::optional& config() const { return config_; } private: // RenderViewObserver methods. void OnDestruct() override { manager_->OnExcludedViewDestroyed(this); } CefRenderManager* const manager_; - const std::optional is_windowless_; - const std::optional print_preview_enabled_; + const std::optional config_; }; CefRenderManager::CefRenderManager() { @@ -110,11 +102,9 @@ void CefRenderManager::RenderFrameCreated( content::RenderFrame* render_frame, CefRenderFrameObserver* render_frame_observer, bool& browser_created, - std::optional& is_windowless, - std::optional& print_preview_enabled) { + std::optional& config) { auto browser = MaybeCreateBrowser(render_frame->GetWebView(), render_frame, - &browser_created, &is_windowless, - &print_preview_enabled); + browser_created, config); if (browser) { // Attach the frame to the observer for message routing purposes. render_frame_observer->AttachFrame( @@ -130,16 +120,14 @@ void CefRenderManager::RenderFrameCreated( void CefRenderManager::WebViewCreated( blink::WebView* web_view, bool& browser_created, - std::optional& is_windowless, - std::optional& print_preview_enabled) { + std::optional& config) { content::RenderFrame* render_frame = nullptr; if (web_view->MainFrame()->IsWebLocalFrame()) { render_frame = content::RenderFrame::FromWebFrame( web_view->MainFrame()->ToWebLocalFrame()); } - MaybeCreateBrowser(web_view, render_frame, &browser_created, &is_windowless, - &print_preview_enabled); + MaybeCreateBrowser(web_view, render_frame, browser_created, config); } void CefRenderManager::DevToolsAgentAttached() { @@ -294,12 +282,9 @@ void CefRenderManager::WebKitInitialized() { CefRefPtr CefRenderManager::MaybeCreateBrowser( blink::WebView* web_view, content::RenderFrame* render_frame, - bool* browser_created, - std::optional* is_windowless, - std::optional* print_preview_enabled) { - if (browser_created) { - *browser_created = false; - } + bool& browser_created, + std::optional& config) { + browser_created = false; if (!web_view || !render_frame) { return nullptr; @@ -307,25 +292,13 @@ CefRefPtr CefRenderManager::MaybeCreateBrowser( // Don't create another browser or excluded view object if one already exists // for the view. - auto browser = GetBrowserForView(web_view); - if (browser) { - if (is_windowless) { - *is_windowless = browser->is_windowless(); - } - if (print_preview_enabled) { - *print_preview_enabled = browser->print_preview_enabled(); - } + if (auto browser = GetBrowserForView(web_view)) { + config = browser->config(); return browser; } - auto excluded_view = GetExcludedViewForView(web_view); - if (excluded_view) { - if (is_windowless) { - *is_windowless = excluded_view->is_windowless(); - } - if (print_preview_enabled) { - *print_preview_enabled = excluded_view->print_preview_enabled(); - } + if (auto excluded_view = GetExcludedViewForView(web_view)) { + config = excluded_view->config(); return nullptr; } @@ -338,11 +311,10 @@ CefRefPtr CefRenderManager::MaybeCreateBrowser( return nullptr; } - if (is_windowless) { - *is_windowless = params->is_windowless; - } - if (print_preview_enabled) { - *print_preview_enabled = params->print_preview_enabled; + if (params->config) { + config = cef::BrowserConfig{params->config->is_windowless, + params->config->print_preview_enabled, + params->config->move_pip_enabled}; } if (params->is_excluded || params->browser_id < 0) { @@ -350,15 +322,13 @@ CefRefPtr CefRenderManager::MaybeCreateBrowser( // extension or print preview dialog), or if the new browser info response // has timed out. excluded_views_.insert(std::make_pair( - web_view, - std::make_unique(this, web_view, params->is_windowless, - params->print_preview_enabled))); + web_view, std::make_unique(this, web_view, config))); return nullptr; } - browser = new CefBrowserImpl(web_view, params->browser_id, *params->is_popup, - *params->is_windowless, - *params->print_preview_enabled); + CHECK(params->config); + CefRefPtr browser = new CefBrowserImpl( + web_view, params->browser_id, params->config->is_popup, *config); browsers_.insert(std::make_pair(web_view, browser)); // Notify the render process handler. @@ -377,9 +347,7 @@ CefRefPtr CefRenderManager::MaybeCreateBrowser( } } - if (browser_created) { - *browser_created = true; - } + browser_created = true; return browser; } diff --git a/libcef/renderer/render_manager.h b/libcef/renderer/render_manager.h index 66abb8e29..c6dc124e7 100644 --- a/libcef/renderer/render_manager.h +++ b/libcef/renderer/render_manager.h @@ -12,6 +12,7 @@ #include "cef/include/internal/cef_ptr.h" #include "cef/libcef/common/mojom/cef.mojom.h" +#include "cef/libcef/renderer/browser_config.h" #include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/remote.h" @@ -52,12 +53,10 @@ class CefRenderManager : public cef::mojom::RenderManager { void RenderFrameCreated(content::RenderFrame* render_frame, CefRenderFrameObserver* render_frame_observer, bool& browser_created, - std::optional& is_windowless, - std::optional& print_preview_enabled); + std::optional& config); void WebViewCreated(blink::WebView* web_view, bool& browser_created, - std::optional& is_windowless, - std::optional& print_preview_enabled); + std::optional& config); void DevToolsAgentAttached(); void DevToolsAgentDetached(); void ExposeInterfacesToBrowser(mojo::BinderMap* binders); @@ -94,9 +93,8 @@ class CefRenderManager : public cef::mojom::RenderManager { CefRefPtr MaybeCreateBrowser( blink::WebView* web_view, content::RenderFrame* render_frame, - bool* browser_created, - std::optional* is_windowless, - std::optional* print_preview_enabled); + bool& browser_created, + std::optional& config); // Called from CefBrowserImpl::OnDestruct(). void OnBrowserDestroyed(CefBrowserImpl* browser); diff --git a/patch/patch.cfg b/patch/patch.cfg index 894c254fc..e2a4aca58 100644 --- a/patch/patch.cfg +++ b/patch/patch.cfg @@ -68,6 +68,9 @@ patches = [ }, { # Enable popups in offscreen rendering on MacOS. + # + # Enable moveTo()/moveBy() for Document picture-in-picture popups. + # https://github.com/chromiumembedded/cef/issues/3714 'name': 'webkit_popups', }, { diff --git a/patch/patches/webkit_popups.patch b/patch/patches/webkit_popups.patch index 64e3f0f14..0d243ad89 100644 --- a/patch/patches/webkit_popups.patch +++ b/patch/patches/webkit_popups.patch @@ -1,5 +1,5 @@ diff --git third_party/blink/public/web/web_view.h third_party/blink/public/web/web_view.h -index b1689844282d6..a8f3b3432517d 100644 +index b1689844282d6..a4288bf5d3ba2 100644 --- third_party/blink/public/web/web_view.h +++ third_party/blink/public/web/web_view.h @@ -344,6 +344,7 @@ class BLINK_EXPORT WebView { @@ -10,6 +10,18 @@ index b1689844282d6..a8f3b3432517d 100644 // Cancels and hides the current popup (datetime, select...) if any. virtual void CancelPagePopup() = 0; +@@ -486,6 +487,11 @@ class BLINK_EXPORT WebView { + virtual void SetPageAttributionSupport( + network::mojom::AttributionSupport support) = 0; + ++ // Sets whether to allow the use of JavaScript moveTo/By() and resizeTo/By() ++ // (without user activation) with Document picture-in-picture popups. ++ virtual void SetMovePictureInPictureEnabled(bool enabled) = 0; ++ virtual bool MovePictureInPictureEnabled() const = 0; ++ + protected: + ~WebView() = default; + }; diff --git third_party/blink/renderer/core/exported/web_view_impl.cc third_party/blink/renderer/core/exported/web_view_impl.cc index 1af1fa035b3da..f92d9b70fbd32 100644 --- third_party/blink/renderer/core/exported/web_view_impl.cc @@ -39,7 +51,7 @@ index 1af1fa035b3da..f92d9b70fbd32 100644 fullscreen_controller_(std::make_unique(this)), page_base_background_color_( diff --git third_party/blink/renderer/core/exported/web_view_impl.h third_party/blink/renderer/core/exported/web_view_impl.h -index 06f7cf79b4526..58ad11da45137 100644 +index 06f7cf79b4526..e0d395867f552 100644 --- third_party/blink/renderer/core/exported/web_view_impl.h +++ third_party/blink/renderer/core/exported/web_view_impl.h @@ -140,7 +140,8 @@ class CORE_EXPORT WebViewImpl final : public WebView, @@ -52,7 +64,21 @@ index 06f7cf79b4526..58ad11da45137 100644 // Returns whether frames under this WebView are backed by a compositor. bool does_composite() const { return does_composite_; } -@@ -882,6 +883,8 @@ class CORE_EXPORT WebViewImpl final : public WebView, +@@ -326,6 +327,13 @@ class CORE_EXPORT WebViewImpl final : public WebView, + void UpdateColorProviders( + const ColorProviderColorMaps& color_provider_colors) override; + ++ void SetMovePictureInPictureEnabled(bool enabled) override { ++ move_pip_enabled_ = enabled; ++ } ++ bool MovePictureInPictureEnabled() const override { ++ return move_pip_enabled_; ++ } ++ + void DispatchPersistedPageshow(base::TimeTicks navigation_start); + void DispatchPagehide(mojom::blink::PagehideDispatch pagehide_dispatch); + void HookBackForwardCacheEviction(bool hook); +@@ -882,6 +890,8 @@ class CORE_EXPORT WebViewImpl final : public WebView, float fake_page_scale_animation_page_scale_factor_ = 0.f; bool fake_page_scale_animation_use_anchor_ = false; @@ -61,6 +87,115 @@ index 06f7cf79b4526..58ad11da45137 100644 float compositor_device_scale_factor_override_ = 0.f; gfx::Transform device_emulation_transform_; +@@ -1011,6 +1021,8 @@ class CORE_EXPORT WebViewImpl final : public WebView, + // CSS property. + bool supports_draggable_regions_ = false; + ++ bool move_pip_enabled_ = false; ++ + // All the registered observers. + base::ObserverList observers_; + }; +diff --git third_party/blink/renderer/core/frame/local_dom_window.cc third_party/blink/renderer/core/frame/local_dom_window.cc +index f4a1ed78679c5..711b072977662 100644 +--- third_party/blink/renderer/core/frame/local_dom_window.cc ++++ third_party/blink/renderer/core/frame/local_dom_window.cc +@@ -52,6 +52,7 @@ + #include "third_party/blink/public/platform/task_type.h" + #include "third_party/blink/public/platform/web_string.h" + #include "third_party/blink/public/web/web_picture_in_picture_window_options.h" ++#include "third_party/blink/public/web/web_view.h" + #include "third_party/blink/renderer/bindings/core/v8/binding_security.h" + #include "third_party/blink/renderer/bindings/core/v8/capture_source_location.h" + #include "third_party/blink/renderer/bindings/core/v8/isolated_world_csp.h" +@@ -110,6 +111,7 @@ + #include "third_party/blink/renderer/core/frame/settings.h" + #include "third_party/blink/renderer/core/frame/viewport_data.h" + #include "third_party/blink/renderer/core/frame/visual_viewport.h" ++#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" + #include "third_party/blink/renderer/core/html/custom/custom_element_registry.h" + #include "third_party/blink/renderer/core/html/fenced_frame/fence.h" + #include "third_party/blink/renderer/core/html/forms/form_controller.h" +@@ -1914,8 +1916,9 @@ void LocalDOMWindow::moveBy(int x, int y) const { + return; + } + +- if (IsPictureInPictureWindow()) ++ if (IsPictureInPictureWindow() && !MovePictureInPictureEnabled()) { + return; ++ } + + LocalFrame* frame = GetFrame(); + Page* page = frame->GetPage(); +@@ -1935,8 +1938,9 @@ void LocalDOMWindow::moveTo(int x, int y) const { + return; + } + +- if (IsPictureInPictureWindow()) ++ if (IsPictureInPictureWindow() && !MovePictureInPictureEnabled()) { + return; ++ } + + LocalFrame* frame = GetFrame(); + Page* page = frame->GetPage(); +@@ -1959,7 +1963,8 @@ void LocalDOMWindow::resizeBy(int x, + } + + if (IsPictureInPictureWindow()) { +- if (!LocalFrame::ConsumeTransientUserActivation(GetFrame())) { ++ if (!MovePictureInPictureEnabled() && ++ !LocalFrame::ConsumeTransientUserActivation(GetFrame())) { + exception_state.ThrowDOMException( + DOMExceptionCode::kNotAllowedError, + "resizeBy() requires user activation in document picture-in-picture"); +@@ -1987,7 +1992,8 @@ void LocalDOMWindow::resizeTo(int width, + } + + if (IsPictureInPictureWindow()) { +- if (!LocalFrame::ConsumeTransientUserActivation(GetFrame())) { ++ if (!MovePictureInPictureEnabled() && ++ !LocalFrame::ConsumeTransientUserActivation(GetFrame())) { + exception_state.ThrowDOMException( + DOMExceptionCode::kNotAllowedError, + "resizeTo() requires user activation in document picture-in-picture"); +@@ -2456,6 +2462,12 @@ DOMWindow* LocalDOMWindow::openPictureInPictureWindow( + To(result.frame->DomWindow()); + pip_dom_window->SetIsPictureInPictureWindow(); + ++ if (WebLocalFrameImpl::FromFrame(entered_window->GetFrame()) ++ ->View() ++ ->MovePictureInPictureEnabled()) { ++ pip_dom_window->SetMovePictureInPictureEnabled(true); ++ } ++ + // Ensure that we're using the same compatibility mode as the opener document. + pip_dom_window->document()->SetCompatibilityMode( + entered_window->document()->GetCompatibilityMode()); +diff --git third_party/blink/renderer/core/frame/local_dom_window.h third_party/blink/renderer/core/frame/local_dom_window.h +index 615d1851fa041..a97811623a2e2 100644 +--- third_party/blink/renderer/core/frame/local_dom_window.h ++++ third_party/blink/renderer/core/frame/local_dom_window.h +@@ -566,6 +566,11 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow, + + void SetIsPictureInPictureWindow(); + ++ void SetMovePictureInPictureEnabled(bool enabled) { ++ move_pip_enabled_ = enabled; ++ } ++ bool MovePictureInPictureEnabled() const { return move_pip_enabled_; } ++ + // Return the viewport size including scrollbars. + gfx::Size GetViewportSize() const; + +@@ -668,6 +673,8 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow, + // https://wicg.github.io/document-picture-in-picture/ + bool is_picture_in_picture_window_ = false; + ++ bool move_pip_enabled_ = false; ++ + // The navigation id of a document is to identify navigation of special types + // like bfcache navigation or soft navigation. It changes when navigations + // of these types occur. diff --git third_party/blink/renderer/core/page/chrome_client_impl.cc third_party/blink/renderer/core/page/chrome_client_impl.cc index e3888bb31414a..78dfff2048a67 100644 --- third_party/blink/renderer/core/page/chrome_client_impl.cc diff --git a/tests/cefclient/browser/views_window.cc b/tests/cefclient/browser/views_window.cc index 446e0b8f0..dc2f0d209 100644 --- a/tests/cefclient/browser/views_window.cc +++ b/tests/cefclient/browser/views_window.cc @@ -530,6 +530,13 @@ bool ViewsWindow::UseFramelessWindowForPictureInPicture( return hide_pip_frame_; } +#if CEF_API_ADDED(CEF_NEXT) +bool ViewsWindow::AllowMoveForPictureInPicture( + CefRefPtr browser_view) { + return move_pip_enabled_; +} +#endif + cef_runtime_style_t ViewsWindow::GetBrowserRuntimeStyle() { if (use_alloy_style_) { return CEF_RUNTIME_STYLE_ALLOY; @@ -1160,6 +1167,7 @@ ViewsWindow::ViewsWindow(WindowType type, use_window_modal_dialog_ = command_line->HasSwitch(switches::kUseWindowModalDialog); hide_pip_frame_ = command_line->HasSwitch(switches::kHidePipFrame); + move_pip_enabled_ = command_line->HasSwitch(switches::kMovePipEnabled); } void ViewsWindow::SetBrowserView(CefRefPtr browser_view) { diff --git a/tests/cefclient/browser/views_window.h b/tests/cefclient/browser/views_window.h index 0f39c2890..b74e7eba9 100644 --- a/tests/cefclient/browser/views_window.h +++ b/tests/cefclient/browser/views_window.h @@ -145,6 +145,10 @@ class ViewsWindow : public CefBrowserViewDelegate, CefRefPtr browser_view) override; bool UseFramelessWindowForPictureInPicture( CefRefPtr browser_view) override; +#if CEF_API_ADDED(CEF_NEXT) + bool AllowMoveForPictureInPicture( + CefRefPtr browser_view) override; +#endif cef_runtime_style_t GetBrowserRuntimeStyle() override; // CefButtonDelegate methods: @@ -271,6 +275,7 @@ class ViewsWindow : public CefBrowserViewDelegate, bool use_window_modal_dialog_; bool use_bottom_controls_; bool hide_pip_frame_; + bool move_pip_enabled_; bool accepts_first_mouse_; CefRefPtr window_; diff --git a/tests/shared/common/client_switches.cc b/tests/shared/common/client_switches.cc index 9c43013d5..dcc69e5bb 100644 --- a/tests/shared/common/client_switches.cc +++ b/tests/shared/common/client_switches.cc @@ -53,6 +53,7 @@ const char kShowWindowButtons[] = "show-window-buttons"; const char kUseWindowModalDialog[] = "use-window-modal-dialog"; const char kUseBottomControls[] = "use-bottom-controls"; const char kHidePipFrame[] = "hide-pip-frame"; +const char kMovePipEnabled[] = "move-pip-enabled"; const char kHideChromeBubbles[] = "hide-chrome-bubbles"; const char kHideWindowOnClose[] = "hide-window-on-close"; const char kAcceptsFirstMouse[] = "accepts-first-mouse"; diff --git a/tests/shared/common/client_switches.h b/tests/shared/common/client_switches.h index c1e111cdd..52ad26a6c 100644 --- a/tests/shared/common/client_switches.h +++ b/tests/shared/common/client_switches.h @@ -47,6 +47,7 @@ extern const char kShowWindowButtons[]; extern const char kUseWindowModalDialog[]; extern const char kUseBottomControls[]; extern const char kHidePipFrame[]; +extern const char kMovePipEnabled[]; extern const char kHideChromeBubbles[]; extern const char kHideWindowOnClose[]; extern const char kAcceptsFirstMouse[];