chrome: Add support for Alloy style browsers and windows (see #3681)

Split the Alloy runtime into bootstrap and style components. Support
creation of Alloy style browsers and windows with the Chrome runtime.
Chrome runtime (`--enable-chrome-runtime`) + Alloy style
(`--use-alloy-style`) supports Views (`--use-views`), native parent
(`--use-native`) and windowless rendering
(`--off-screen-rendering-enabled`).

Print preview is supported in all cases except with windowless rendering
on all platforms and native parent on MacOS. It is disabled by default
with Alloy style for legacy compatibility. Where supported it can be
enabled or disabled globally using `--[enable|disable]-print-preview` or
configured on a per-RequestContext basis using the
`printing.print_preview_disabled` preference. It also behaves as
expected when triggered via the PDF viewer print button.

Chrome runtime + Alloy style behavior differs from Alloy runtime in the
following significant ways:

- Supports Chrome error pages by default.
- DevTools popups are Chrome style only (cannot be windowless).
- The Alloy extension API will not supported.

Chrome runtime + Alloy style passes all expected Alloy ceftests except
the following:

- `DisplayTest.AutoResize` (Alloy extension API not supported)
- `DownloadTest.*` (Download API not yet supported)
- `ExtensionTest.*` (Alloy extension API not supported)

This change also adds Chrome runtime support for
CefContextMenuHandler::RunContextMenu (see #3293).

This change also explicitly blocks (and doesn't retry) FrameAttached
requests from PDF viewer and print preview excluded frames (see #3664).

Known issues specific to Chrome runtime + Alloy style:
- DevTools popup with windowless rendering doesn't load successfully.
  Use windowed rendering or remote debugging as a workaround.
- Chrome style Window with Alloy style BrowserView (`--use-alloy-style
  --use-chrome-style-window`) does not show Chrome theme changes.

To test:
- Run `ceftests --enable-chrome-runtime --use-alloy-style
       [--use-chrome-style-window] [--use-views|--use-native]
       --gtest_filter=...`
- Run `cefclient --enable-chrome-runtime --use-alloy-style
       [--use-chrome-style-window]
       [--use-views|--use-native|--off-screen-rendering-enabled]`
- Run `cefsimple --enable-chrome-runtime --use-alloy-style [--use-views]`
This commit is contained in:
Marshall Greenblatt
2024-04-17 12:01:26 -04:00
parent 62c93f01f4
commit dca0435d2f
216 changed files with 3388 additions and 1565 deletions

View File

@@ -39,15 +39,16 @@ class BrowserDelegate : public content::WebContentsDelegate {
scoped_refptr<CreateParams> cef_params,
const Browser* opener);
~BrowserDelegate() override = default;
// Optionally override Browser creation in
// DevToolsWindow::CreateDevToolsBrowser. The returned Browser, if any, will
// take ownership of |devtools_contents|.
virtual Browser* CreateDevToolsBrowser(
static Browser* CreateDevToolsBrowser(
Profile* profile,
Browser* opener,
std::unique_ptr<content::WebContents>& devtools_contents) = 0;
content::WebContents* inspected_web_contents,
std::unique_ptr<content::WebContents>& devtools_contents);
~BrowserDelegate() override = default;
// Optionally override chrome::AddWebContents behavior. This is most often
// called via Browser::AddNewContents for new popup browsers and provides an

View File

@@ -119,11 +119,6 @@ CefEventHandle CefBrowserPlatformDelegateChrome::GetEventHandle(
return native_delegate_->GetEventHandle(event);
}
bool CefBrowserPlatformDelegateChrome::IsPrintPreviewSupported() const {
return chrome_browser_ && !chrome_browser_->profile()->GetPrefs()->GetBoolean(
prefs::kPrintPreviewDisabled);
}
CefWindowHandle CefBrowserPlatformDelegateChrome::GetParentWindowHandle()
const {
return GetHostWindowHandle();
@@ -143,6 +138,9 @@ gfx::NativeWindow CefBrowserPlatformDelegateChrome::GetNativeWindow() const {
if (chrome_browser_ && chrome_browser_->window()) {
return chrome_browser_->window()->GetNativeWindow();
}
DCHECK(false);
if (web_contents_) {
return web_contents_->GetTopLevelNativeWindow();
}
NOTIMPLEMENTED();
return gfx::NativeWindow();
}

View File

@@ -42,7 +42,7 @@ class CefBrowserPlatformDelegateChrome
void ViewText(const std::string& text) override;
CefEventHandle GetEventHandle(
const content::NativeWebKeyboardEvent& event) const override;
bool IsPrintPreviewSupported() const override;
bool IsAlloyStyle() const override { return false; }
// CefBrowserPlatformDelegateNative::WindowlessHandler methods:
CefWindowHandle GetParentWindowHandle() const override;

View File

@@ -11,11 +11,13 @@
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h"
#include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
#include "chrome/browser/profiles/off_the_record_profile_impl.h"
#include "chrome/common/pref_names.h"
#include "components/history/core/browser/history_service.h"
namespace {
@@ -139,6 +141,29 @@ void ChromeBrowserContext::Shutdown() {
}
}
void ChromeBrowserContext::AddVisitedURLs(
const GURL& url,
const std::vector<GURL>& redirect_chain,
ui::PageTransition transition) {
auto* profile = AsProfile();
if (profile->IsOffTheRecord()) {
// Don't persist state.
return;
}
// Called from DidFinishNavigation by Alloy style browsers. Chrome style
// browsers will handle this via HistoryTabHelper.
if (auto history_service = HistoryServiceFactory::GetForProfile(
profile, ServiceAccessType::IMPLICIT_ACCESS)) {
history::HistoryAddPageArgs add_page_args;
add_page_args.url = url;
add_page_args.redirects = redirect_chain;
add_page_args.transition = transition;
add_page_args.time = base::Time::Now();
history_service->AddPage(std::move(add_page_args));
}
}
void ChromeBrowserContext::ProfileCreated(CreateStatus status,
Profile* profile) {
Profile* parent_profile = nullptr;

View File

@@ -34,6 +34,9 @@ class ChromeBrowserContext : public CefBrowserContext, public ProfileObserver {
bool IsInitialized() const override;
void StoreOrTriggerInitCallback(base::OnceClosure callback) override;
void Shutdown() override;
void AddVisitedURLs(const GURL& url,
const std::vector<GURL>& redirect_chain,
ui::PageTransition transition) override;
// ProfileObserver overrides.
void OnProfileWillBeDestroyed(Profile* profile) override;

View File

@@ -12,6 +12,7 @@
#include "libcef/browser/browser_platform_delegate.h"
#include "libcef/browser/chrome/chrome_browser_context.h"
#include "libcef/browser/chrome/chrome_browser_host_impl.h"
#include "libcef/browser/chrome/chrome_devtools_window_runner.h"
#include "libcef/browser/chrome/views/chrome_browser_view.h"
#include "libcef/browser/chrome/views/chrome_child_window.h"
#include "libcef/browser/hang_monitor.h"
@@ -53,23 +54,35 @@ ChromeBrowserDelegate::ChromeBrowserDelegate(
ChromeBrowserDelegate::~ChromeBrowserDelegate() = default;
// static
Browser* ChromeBrowserDelegate::CreateDevToolsBrowser(
Profile* profile,
Browser* opener,
content::WebContents* inspected_web_contents,
std::unique_ptr<content::WebContents>& devtools_contents) {
// |opener| is the same value that will be passed to the ChromeBrowserDelegate
// constructor for the new popup Browser. It may be nullptr in certain rare
// constructor for the new popup Browser. It may be nullptr in certain
// situations (e.g. if DevTools is launched for a WebContents that is not a
// Browser Tab). In that case, the popup browser host will instead be created
// via SetAsDelegate.
auto opener_browser_host =
// Browser Tab).
CefRefPtr<CefBrowserHostBase> opener_browser_host =
opener ? ChromeBrowserHostImpl::GetBrowserForBrowser(opener) : nullptr;
if (!opener_browser_host) {
return nullptr;
// |inspected_web_contents| may be an Alloy style browser.
opener_browser_host =
CefBrowserHostBase::GetBrowserForContents(inspected_web_contents);
if (!opener_browser_host) {
// The popup browser host will instead be created via SetAsDelegate.
return nullptr;
}
}
// We expect openers and popups to have the same Profile.
CHECK_EQ(opener->profile(), profile);
CHECK_EQ(
CefRequestContextImpl::GetProfile(opener_browser_host->request_context()),
profile);
if (opener) {
CHECK_EQ(opener->profile(), profile);
}
//
// 1. Get configuration settings from the user and create the new platform
@@ -84,25 +97,26 @@ Browser* ChromeBrowserDelegate::CreateDevToolsBrowser(
CefBrowserCreateParams create_params;
CefWindowInfo window_info;
auto* devtools_window_runner = static_cast<ChromeDevToolsWindowRunner*>(
opener_browser_host->GetDevToolsWindowRunner());
auto pending_show_devtools_params =
devtools_window_runner->TakePendingParams();
// If |client| is empty, or if the user clears |client| in
// OnBeforeDevToolsPopup, we'll use the result of GetDefaultClient() later on
// in CreateBrowserHost().
if (pending_show_devtools_params_) {
if (pending_show_devtools_params) {
// Start with the params passed to CefBrowserHost::ShowDevTools().
create_params.client = pending_show_devtools_params_->client_;
create_params.settings = pending_show_devtools_params_->settings_;
window_info = pending_show_devtools_params_->window_info_;
// Pending params are only used a single time.
pending_show_devtools_params_.reset();
create_params.client = pending_show_devtools_params->client_;
create_params.settings = pending_show_devtools_params->settings_;
window_info = pending_show_devtools_params->window_info_;
} else {
// Start with the same client and settings as the opener.
create_params.client = opener_client;
create_params.settings = opener_browser_host->settings();
#if BUILDFLAG(IS_WIN)
window_info.SetAsPopup(nullptr, CefString());
#endif
CefBrowserCreateParams::InitWindowInfo(&window_info,
opener_browser_host.get());
}
// Start with the same extra info as the opener, for consistency with
@@ -121,10 +135,14 @@ Browser* ChromeBrowserDelegate::CreateDevToolsBrowser(
create_params.settings, create_params.extra_info, &use_default_window);
}
if (opener_browser_host->platform_delegate()->HasExternalParent()) {
if (window_info.windowless_rendering_enabled) {
LOG(ERROR)
<< "Windowless rendering is not supported for this DevTools window";
} else if (opener_browser_host->platform_delegate()->HasExternalParent()) {
// A parent window handle for DevTools creation is only supported if the
// opener also has an external parent.
create_params.MaybeSetWindowInfo(window_info);
create_params.MaybeSetWindowInfo(window_info, /*allow_alloy_style=*/false,
/*allow_chrome_style=*/true);
} else if (chrome_child_window::HasParentHandle(window_info)) {
LOG(ERROR) << "Parent window handle not supported for this DevTools window";
}
@@ -132,20 +150,24 @@ Browser* ChromeBrowserDelegate::CreateDevToolsBrowser(
create_params.popup_with_views_hosted_opener =
CefBrowserInfoManager::ShouldCreateViewsHostedPopup(opener_browser_host,
use_default_window);
create_params.popup_with_alloy_style_opener = false;
auto platform_delegate = CefBrowserPlatformDelegate::Create(create_params);
CHECK(platform_delegate);
// Expect runtime style to match.
CHECK(platform_delegate->IsChromeStyle());
//
// 2. Create the new browser host. Logical equivalent of WebContentsCreated()
// for normal popups.
// 2. Create the new browser host. Logical equivalent of
// WebContentsCreated() for normal popups.
//
// Create a new browser host that remains alive until the associated
// WebContents is destroyed. Associate that browser host with the WebContents
// and execute initial client callbacks. Deliver required information to the
// renderer process.
auto browser_host = CreateBrowserHostForPopup(
// WebContents is destroyed. Associate that browser host with the
// WebContents and execute initial client callbacks. Deliver required
// information to the renderer process.
auto browser_host = ChromeBrowserDelegate::CreateBrowserHostForPopup(
devtools_contents.get(), create_params.settings, create_params.client,
create_params.extra_info, std::move(platform_delegate),
/*is_devtools_popup=*/true, opener_browser_host);
@@ -169,10 +191,10 @@ Browser* ChromeBrowserDelegate::CreateDevToolsBrowser(
std::move(chrome_params));
// Give the opener browser a reference to the new DevTools browser. Do this
// last because don't want the client to attempt access to the DevTools
// browser via opener browser methods (e.g. ShowDevTools, CloseDevTools, etc)
// while creation is still in progress.
opener_browser_host->SetDevToolsBrowserHost(browser_host->GetWeakPtr());
// last because we don't want the client to attempt access to the DevTools
// browser via opener browser methods (e.g. ShowDevTools, CloseDevTools,
// etc) while creation is still in progress.
devtools_window_runner->SetDevToolsBrowserHost(browser_host->GetWeakPtr());
auto browser = browser_host->browser();
CHECK(browser);
@@ -203,7 +225,8 @@ std::unique_ptr<content::WebContents> ChromeBrowserDelegate::AddWebContents(
void ChromeBrowserDelegate::OnWebContentsCreated(
content::WebContents* new_contents) {
// Necessary to receive LoadingStateChanged calls during initial navigation.
// This will be called again in Browser::SetAsDelegate, which should be fine.
// This will be called again in Browser::SetAsDelegate, which should be
// fine.
new_contents->SetDelegate(browser_);
SetAsDelegate(new_contents, /*set_delegate=*/true);
@@ -233,14 +256,18 @@ void ChromeBrowserDelegate::SetAsDelegate(content::WebContents* web_contents,
auto platform_delegate = CefBrowserPlatformDelegate::Create(create_params_);
CHECK(platform_delegate);
// Expect runtime style to match.
CHECK(platform_delegate->IsChromeStyle());
auto browser_info = CefBrowserInfoManager::GetInstance()->CreateBrowserInfo(
is_devtools_popup, /*is_windowless=*/false, create_params_.extra_info);
is_devtools_popup, /*is_windowless=*/false,
platform_delegate->IsPrintPreviewSupported(), create_params_.extra_info);
auto request_context_impl =
CefRequestContextImpl::GetOrCreateForRequestContext(
create_params_.request_context);
CreateBrowserHost(web_contents, create_params_.settings,
CreateBrowserHost(browser_, web_contents, create_params_.settings,
create_params_.client, std::move(platform_delegate),
browser_info, is_devtools_popup, /*opener=*/nullptr,
request_context_impl);
@@ -477,9 +504,9 @@ void ChromeBrowserDelegate::WebContentsCreated(
}
// Create a new browser host that remains alive until the associated
// WebContents is destroyed. Associate that browser host with the WebContents
// and execute initial client callbacks. Deliver required information to the
// renderer process.
// WebContents is destroyed. Associate that browser host with the
// WebContents and execute initial client callbacks. Deliver required
// information to the renderer process.
CreateBrowserHostForPopup(new_contents, settings, client, extra_info,
std::move(platform_delegate),
/*is_devtools_popup=*/false, opener);
@@ -592,20 +619,16 @@ bool ChromeBrowserDelegate::HandleKeyboardEvent(
return false;
}
void ChromeBrowserDelegate::SetPendingShowDevToolsParams(
std::unique_ptr<CefShowDevToolsParams> params) {
DCHECK(!pending_show_devtools_params_);
pending_show_devtools_params_ = std::move(params);
}
// static
CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserDelegate::CreateBrowserHost(
Browser* browser,
content::WebContents* web_contents,
const CefBrowserSettings& settings,
CefRefPtr<CefClient> client,
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
scoped_refptr<CefBrowserInfo> browser_info,
bool is_devtools_popup,
CefRefPtr<ChromeBrowserHostImpl> opener,
CefRefPtr<CefBrowserHostBase> opener,
CefRefPtr<CefRequestContextImpl> request_context_impl) {
CEF_REQUIRE_UIT();
DCHECK(web_contents);
@@ -615,6 +638,7 @@ CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserDelegate::CreateBrowserHost(
// If |opener| is non-nullptr it must be a popup window.
DCHECK(!opener.get() || browser_info->is_popup());
DCHECK(browser || opener);
if (!client) {
if (auto app = CefAppManager::Get()->GetApplication()) {
@@ -628,15 +652,20 @@ CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserDelegate::CreateBrowserHost(
LOG(WARNING) << "Creating a chrome browser without a client";
}
// Get or create a ChromeBrowserContext for the browser Profile. Creation may
// be necessary when selecting a new or incognito Profile for the first time
// via the Chrome UI.
auto chrome_browser_context =
ChromeBrowserContext::GetOrCreateForProfile(browser_->profile());
Profile* profile =
browser ? browser->profile()
: Profile::FromBrowserContext(web_contents->GetBrowserContext());
// If the provided CefRequestContext matches the ChromeBrowserContext then use
// the provided one, as it will have the preferred CefRequestContextHandler.
// Otherwise, get or create a CefRequestContext that matches.
// Get or create a ChromeBrowserContext for the browser Profile. Creation
// may be necessary when selecting a new or incognito Profile for the first
// time via the Chrome UI.
auto* chrome_browser_context =
ChromeBrowserContext::GetOrCreateForProfile(profile);
// If the provided CefRequestContext matches the ChromeBrowserContext then
// use the provided one, as it will have the preferred
// CefRequestContextHandler. Otherwise, get or create a CefRequestContext
// that matches.
if (chrome_browser_context != request_context_impl->GetBrowserContext()) {
CefRefPtr<CefRequestContextHandler> handler;
if (auto app = CefAppManager::Get()->GetApplication()) {
@@ -658,12 +687,13 @@ CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserDelegate::CreateBrowserHost(
// The Chrome browser for a normal popup won't be created until
// AddNewContents().
if (!opener) {
browser_host->SetBrowser(browser_);
browser_host->SetBrowser(browser);
}
return browser_host;
}
// static
CefRefPtr<ChromeBrowserHostImpl>
ChromeBrowserDelegate::CreateBrowserHostForPopup(
content::WebContents* web_contents,
@@ -672,10 +702,13 @@ ChromeBrowserDelegate::CreateBrowserHostForPopup(
CefRefPtr<CefDictionaryValue> extra_info,
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
bool is_devtools_popup,
CefRefPtr<ChromeBrowserHostImpl> opener) {
CefRefPtr<CefBrowserHostBase> opener) {
DCHECK(opener);
auto browser_info =
CefBrowserInfoManager::GetInstance()->CreatePopupBrowserInfo(
web_contents, /*is_windowless=*/false, extra_info);
web_contents, /*is_windowless=*/false,
platform_delegate->IsPrintPreviewSupported(), extra_info);
CHECK(browser_info->is_popup());
// Popups must share the same RequestContext as the parent.
@@ -684,7 +717,7 @@ ChromeBrowserDelegate::CreateBrowserHostForPopup(
// We don't officially own |web_contents| until AddNewContents() is called.
// However, we need to install observers/delegates here.
return CreateBrowserHost(web_contents, settings, client,
return CreateBrowserHost(/*browser=*/nullptr, web_contents, settings, client,
std::move(platform_delegate), browser_info,
is_devtools_popup, opener, request_context_impl);
}
@@ -750,4 +783,14 @@ std::unique_ptr<BrowserDelegate> BrowserDelegate::Create(
opener);
}
// static
Browser* BrowserDelegate::CreateDevToolsBrowser(
Profile* profile,
Browser* opener,
content::WebContents* inspected_web_contents,
std::unique_ptr<content::WebContents>& devtools_contents) {
return ChromeBrowserDelegate::CreateDevToolsBrowser(
profile, opener, inspected_web_contents, devtools_contents);
}
} // namespace cef

View File

@@ -52,11 +52,13 @@ class ChromeBrowserDelegate : public cef::BrowserDelegate {
~ChromeBrowserDelegate() override;
// cef::BrowserDelegate methods:
Browser* CreateDevToolsBrowser(
static Browser* CreateDevToolsBrowser(
Profile* profile,
Browser* opener,
std::unique_ptr<content::WebContents>& devtools_contents) override;
content::WebContents* inspected_web_contents,
std::unique_ptr<content::WebContents>& devtools_contents);
// cef::BrowserDelegate methods:
std::unique_ptr<content::WebContents> AddWebContents(
std::unique_ptr<content::WebContents> new_contents) override;
void OnWebContentsCreated(content::WebContents* new_contents) override;
@@ -121,30 +123,28 @@ class ChromeBrowserDelegate : public cef::BrowserDelegate {
content::WebContents* source,
const content::NativeWebKeyboardEvent& event) override;
void SetPendingShowDevToolsParams(
std::unique_ptr<CefShowDevToolsParams> params);
Browser* browser() const { return browser_; }
private:
CefRefPtr<ChromeBrowserHostImpl> CreateBrowserHost(
static CefRefPtr<ChromeBrowserHostImpl> CreateBrowserHost(
Browser* browser,
content::WebContents* web_contents,
const CefBrowserSettings& settings,
CefRefPtr<CefClient> client,
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
scoped_refptr<CefBrowserInfo> browser_info,
bool is_devtools_popup,
CefRefPtr<ChromeBrowserHostImpl> opener,
CefRefPtr<CefBrowserHostBase> opener,
CefRefPtr<CefRequestContextImpl> request_context_impl);
CefRefPtr<ChromeBrowserHostImpl> CreateBrowserHostForPopup(
static CefRefPtr<ChromeBrowserHostImpl> CreateBrowserHostForPopup(
content::WebContents* web_contents,
const CefBrowserSettings& settings,
CefRefPtr<CefClient> client,
CefRefPtr<CefDictionaryValue> extra_info,
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
bool is_devtools_popup,
CefRefPtr<ChromeBrowserHostImpl> opener);
CefRefPtr<CefBrowserHostBase> opener);
CefBrowserContentsDelegate* GetDelegateForWebContents(
content::WebContents* web_contents) const;
@@ -166,8 +166,6 @@ class ChromeBrowserDelegate : public cef::BrowserDelegate {
std::optional<bool> show_status_bubble_;
std::optional<SkRegion> draggable_region_;
mutable std::optional<bool> frameless_pip_;
std::unique_ptr<CefShowDevToolsParams> pending_show_devtools_params_;
};
#endif // CEF_LIBCEF_BROWSER_CHROME_CHROME_BROWSER_DELEGATE_H_

View File

@@ -6,7 +6,6 @@
#include "libcef/browser/browser_platform_delegate.h"
#include "libcef/browser/chrome/browser_platform_delegate_chrome.h"
#include "libcef/browser/chrome/chrome_browser_delegate.h"
#include "libcef/browser/thread_util.h"
#include "libcef/browser/views/browser_view_impl.h"
#include "libcef/common/net/url_util.h"
@@ -14,7 +13,6 @@
#include "base/logging.h"
#include "base/notreached.h"
#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_navigator.h"
@@ -57,36 +55,42 @@ CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::Create(
return browser_host;
}
// static
CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::FromBaseChecked(
CefRefPtr<CefBrowserHostBase> host_base) {
if (!host_base) {
return nullptr;
}
CHECK(host_base->IsChromeStyle());
return static_cast<ChromeBrowserHostImpl*>(host_base.get());
}
// static
CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForHost(
const content::RenderViewHost* host) {
REQUIRE_CHROME_RUNTIME();
auto browser = CefBrowserHostBase::GetBrowserForHost(host);
return static_cast<ChromeBrowserHostImpl*>(browser.get());
return FromBaseChecked(CefBrowserHostBase::GetBrowserForHost(host));
}
// static
CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForHost(
const content::RenderFrameHost* host) {
REQUIRE_CHROME_RUNTIME();
auto browser = CefBrowserHostBase::GetBrowserForHost(host);
return static_cast<ChromeBrowserHostImpl*>(browser.get());
return FromBaseChecked(CefBrowserHostBase::GetBrowserForHost(host));
}
// static
CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForContents(
const content::WebContents* contents) {
REQUIRE_CHROME_RUNTIME();
auto browser = CefBrowserHostBase::GetBrowserForContents(contents);
return static_cast<ChromeBrowserHostImpl*>(browser.get());
return FromBaseChecked(CefBrowserHostBase::GetBrowserForContents(contents));
}
// static
CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForGlobalId(
const content::GlobalRenderFrameHostId& global_id) {
REQUIRE_CHROME_RUNTIME();
auto browser = CefBrowserHostBase::GetBrowserForGlobalId(global_id);
return static_cast<ChromeBrowserHostImpl*>(browser.get());
return FromBaseChecked(CefBrowserHostBase::GetBrowserForGlobalId(global_id));
}
// static
@@ -208,73 +212,6 @@ void ChromeBrowserHostImpl::StopFinding(bool clearSelection) {
NOTIMPLEMENTED();
}
void ChromeBrowserHostImpl::ShowDevToolsOnUIThread(
std::unique_ptr<CefShowDevToolsParams> params) {
CEF_REQUIRE_UIT();
if (!browser_) {
return;
}
auto* web_contents = GetWebContents();
if (!web_contents) {
return;
}
auto* profile = CefRequestContextImpl::GetProfile(request_context());
if (!DevToolsWindow::AllowDevToolsFor(profile, web_contents)) {
LOG(WARNING) << "DevTools is not allowed for this browser";
return;
}
auto inspect_element_at = params->inspect_element_at_;
if (!devtools_browser_host_) {
// Configure parameters for ChromeBrowserDelegate::CreateDevToolsBrowser
// which will be called indirectly to create the DevTools window.
auto chrome_browser_delegate =
static_cast<ChromeBrowserDelegate*>(browser_->cef_delegate());
chrome_browser_delegate->SetPendingShowDevToolsParams(std::move(params));
}
// Focus the existing DevTools window or create a new one.
if (!inspect_element_at.IsEmpty()) {
DevToolsWindow::InspectElement(web_contents->GetPrimaryMainFrame(),
inspect_element_at.x, inspect_element_at.y);
} else {
DevToolsWindow::OpenDevToolsWindow(web_contents, profile,
DevToolsOpenedByAction::kUnknown);
}
// The DevTools browser host should now exist.
DCHECK(devtools_browser_host_);
}
void ChromeBrowserHostImpl::CloseDevTools() {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT,
base::BindOnce(&ChromeBrowserHostImpl::CloseDevTools, this));
return;
}
if (devtools_browser_host_) {
devtools_browser_host_->TryCloseBrowser();
}
}
bool ChromeBrowserHostImpl::HasDevTools() {
if (!CEF_CURRENTLY_ON_UIT()) {
DCHECK(false) << "called on invalid thread";
return false;
}
return !!devtools_browser_host_;
}
bool ChromeBrowserHostImpl::IsWindowRenderingDisabled() {
return false;
}
void ChromeBrowserHostImpl::WasResized() {
NOTIMPLEMENTED();
}
@@ -537,13 +474,13 @@ Browser* ChromeBrowserHostImpl::CreateBrowser(
void ChromeBrowserHostImpl::Attach(content::WebContents* web_contents,
bool is_devtools_popup,
CefRefPtr<ChromeBrowserHostImpl> opener) {
CefRefPtr<CefBrowserHostBase> opener) {
DCHECK(web_contents);
if (opener) {
// Give the opener browser's platform delegate an opportunity to modify the
// new browser's platform delegate.
opener->platform_delegate_->PopupWebContentsCreated(
opener->platform_delegate()->PopupWebContentsCreated(
settings_, client_, web_contents, platform_delegate_.get(),
is_devtools_popup);
}
@@ -569,7 +506,8 @@ void ChromeBrowserHostImpl::Attach(content::WebContents* web_contents,
// CefBrowserHost::GetWindowHandle() will return kNullWindowHandle in
// OnAfterCreated(), which breaks client expectations (e.g. clients expect
// everything about the browser to be valid at that time).
opener->platform_delegate_->PopupBrowserCreated(this, is_devtools_popup);
opener->platform_delegate()->PopupBrowserCreated(platform_delegate_.get(),
this, is_devtools_popup);
}
// 2. Notify the browser's LifeSpanHandler. This must always be the first
@@ -606,13 +544,6 @@ void ChromeBrowserHostImpl::SetBrowser(Browser* browser) {
}
}
void ChromeBrowserHostImpl::SetDevToolsBrowserHost(
base::WeakPtr<ChromeBrowserHostImpl> devtools_browser_host) {
CEF_REQUIRE_UIT();
DCHECK(!devtools_browser_host_);
devtools_browser_host_ = devtools_browser_host;
}
void ChromeBrowserHostImpl::WindowDestroyed() {
CEF_REQUIRE_UIT();
if (auto view = chrome_browser_view()) {

View File

@@ -38,6 +38,11 @@ class ChromeBrowserHostImpl : public CefBrowserHostBase {
static CefRefPtr<ChromeBrowserHostImpl> Create(
const CefBrowserCreateParams& params);
// Safe (checked) conversion from CefBrowserHostBase to ChromeBrowserHostImpl.
// Use this method instead of static_cast.
static CefRefPtr<ChromeBrowserHostImpl> FromBaseChecked(
CefRefPtr<CefBrowserHostBase> host_base);
// Returns the browser associated with the specified RenderViewHost.
static CefRefPtr<ChromeBrowserHostImpl> GetBrowserForHost(
const content::RenderViewHost* host);
@@ -62,6 +67,10 @@ class ChromeBrowserHostImpl : public CefBrowserHostBase {
// CefBrowserHostBase methods called from CefFrameHostImpl:
void OnSetFocus(cef_focus_source_t source) override;
// CefBrowserHostBase methods:
bool IsWindowless() const override { return false; }
bool IsAlloyStyle() const override { return false; }
// CefBrowserHost methods:
void CloseBrowser(bool force_close) override;
bool TryCloseBrowser() override;
@@ -72,9 +81,7 @@ class ChromeBrowserHostImpl : public CefBrowserHostBase {
bool matchCase,
bool findNext) override;
void StopFinding(bool clearSelection) override;
void CloseDevTools() override;
bool HasDevTools() override;
bool IsWindowRenderingDisabled() override;
bool IsWindowRenderingDisabled() override { return false; }
void WasResized() override;
void WasHidden(bool hidden) override;
void NotifyScreenInfoChanged() override;
@@ -124,8 +131,6 @@ class ChromeBrowserHostImpl : public CefBrowserHostBase {
protected:
bool Navigate(const content::OpenURLParams& params) override;
void ShowDevToolsOnUIThread(
std::unique_ptr<CefShowDevToolsParams> params) override;
private:
friend class ChromeBrowserDelegate;
@@ -147,7 +152,7 @@ class ChromeBrowserHostImpl : public CefBrowserHostBase {
// created. Must be called on the UI thread.
void Attach(content::WebContents* web_contents,
bool is_devtools_popup,
CefRefPtr<ChromeBrowserHostImpl> opener);
CefRefPtr<CefBrowserHostBase> opener);
// Called from ChromeBrowserDelegate::AddNewContents to take ownership of a
// popup WebContents. |browser_create_params| may be empty for default Browser
@@ -161,9 +166,6 @@ class ChromeBrowserHostImpl : public CefBrowserHostBase {
// before the new Browser is added. Must be called on the UI thread.
void SetBrowser(Browser* browser);
void SetDevToolsBrowserHost(
base::WeakPtr<ChromeBrowserHostImpl> devtools_browser_host);
// CefBrowserHostBase methods:
void WindowDestroyed() override;
bool WillBeDestroyed() const override;
@@ -178,8 +180,6 @@ class ChromeBrowserHostImpl : public CefBrowserHostBase {
Browser* browser_ = nullptr;
CefWindowHandle host_window_handle_ = kNullWindowHandle;
base::WeakPtr<ChromeBrowserHostImpl> devtools_browser_host_;
base::WeakPtrFactory<ChromeBrowserHostImpl> weak_ptr_factory_{this};
};

View File

@@ -4,6 +4,7 @@
#include "libcef/browser/chrome/chrome_browser_main_extra_parts_cef.h"
#include "libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.h"
#include "libcef/browser/chrome/chrome_context_menu_handler.h"
#include "libcef/browser/chrome/chrome_startup_browser_creator.h"
#include "libcef/browser/context.h"
@@ -13,6 +14,8 @@
#include "base/task/thread_pool.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/views/chrome_constrained_window_views_client.h"
#include "components/constrained_window/constrained_window_views.h"
#if BUILDFLAG(IS_LINUX)
#include "base/linux_util.h"
@@ -67,7 +70,7 @@ void ChromeBrowserMainExtraPartsCef::PreMainMessageLoopRun() {
base::TaskShutdownBehavior::BLOCK_SHUTDOWN, base::MayBlock()});
scheme::RegisterWebUIControllerFactory();
context_menu::RegisterMenuCreatedCallback();
context_menu::RegisterCallbacks();
file_dialog_runner::RegisterFactory();
permission_prompt::RegisterCreateCallback();
@@ -78,3 +81,9 @@ void ChromeBrowserMainExtraPartsCef::PreMainMessageLoopRun() {
}
#endif
}
void ChromeBrowserMainExtraPartsCef::ToolkitInitialized() {
// Override the default Chrome client.
SetConstrainedWindowViewsClient(CreateAlloyConstrainedWindowViewsClient(
CreateChromeConstrainedWindowViewsClient()));
}

View File

@@ -44,6 +44,7 @@ class ChromeBrowserMainExtraPartsCef : public ChromeBrowserMainExtraParts {
void PostProfileInit(Profile* profile, bool is_initial_profile) override;
void PostBrowserStart() override;
void PreMainMessageLoopRun() override;
void ToolkitInitialized() override;
CefRefPtr<CefRequestContextImpl> global_request_context_;

View File

@@ -8,10 +8,10 @@
#include <tuple>
#include "libcef/browser/browser_frame.h"
#include "libcef/browser/browser_host_base.h"
#include "libcef/browser/browser_info_manager.h"
#include "libcef/browser/browser_manager.h"
#include "libcef/browser/certificate_query.h"
#include "libcef/browser/chrome/chrome_browser_host_impl.h"
#include "libcef/browser/chrome/chrome_browser_main_extra_parts_cef.h"
#include "libcef/browser/context.h"
#include "libcef/browser/net/chrome_scheme_handler.h"
@@ -43,6 +43,10 @@
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
#if !BUILDFLAG(IS_MAC)
#include "libcef/browser/chrome/chrome_web_contents_view_delegate_cef.h"
#endif
namespace {
void HandleExternalProtocolHelper(
@@ -210,7 +214,7 @@ void ChromeContentBrowserClientCef::OverrideWebkitPrefs(
ChromeContentBrowserClient::OverrideWebkitPrefs(web_contents, prefs);
SkColor base_background_color;
auto browser = ChromeBrowserHostImpl::GetBrowserForContents(web_contents);
auto browser = CefBrowserHostBase::GetBrowserForContents(web_contents);
if (browser) {
renderer_prefs::SetCefPrefs(browser->settings(), *prefs);
@@ -471,6 +475,18 @@ void ChromeContentBrowserClientCef::RegisterBrowserInterfaceBindersForFrame(
map);
}
std::unique_ptr<content::WebContentsViewDelegate>
ChromeContentBrowserClientCef::GetWebContentsViewDelegate(
content::WebContents* web_contents) {
// This does more work than just creating the delegate, so we call it even
// though the result gets discarded.
ChromeContentBrowserClient::GetWebContentsViewDelegate(web_contents);
// Used to customize context menu behavior for Alloy style. Called during
// WebContents::Create() so we don't yet have an associated BrowserHost.
return CreateWebContentsViewDelegate(web_contents);
}
CefRefPtr<CefRequestContextImpl>
ChromeContentBrowserClientCef::request_context() const {
return browser_main_parts_->request_context();
@@ -490,3 +506,15 @@ scoped_refptr<base::SingleThreadTaskRunner>
ChromeContentBrowserClientCef::user_blocking_task_runner() const {
return browser_main_parts_->user_blocking_task_runner();
}
#if !BUILDFLAG(IS_MAC)
// Defined in a separate .mm file on MacOS to work around
// ChromeWebContentsViewDelegateViewsMac containing ObjC references.
// static
std::unique_ptr<content::WebContentsViewDelegate>
ChromeContentBrowserClientCef::CreateWebContentsViewDelegate(
content::WebContents* web_contents) {
return std::make_unique<ChromeWebContentsViewDelegateCef>(web_contents);
}
#endif

View File

@@ -11,6 +11,7 @@
#include "libcef/browser/request_context_impl.h"
#include "chrome/browser/chrome_content_browser_client.h"
#include "content/public/browser/web_contents_view_delegate.h"
class ChromeBrowserMainExtraPartsCef;
@@ -126,6 +127,8 @@ class ChromeContentBrowserClientCef : public ChromeContentBrowserClient {
void RegisterBrowserInterfaceBindersForFrame(
content::RenderFrameHost* render_frame_host,
mojo::BinderMapWithContext<content::RenderFrameHost*>* map) override;
std::unique_ptr<content::WebContentsViewDelegate> GetWebContentsViewDelegate(
content::WebContents* web_contents) override;
CefRefPtr<CefRequestContextImpl> request_context() const;
@@ -134,6 +137,9 @@ class ChromeContentBrowserClientCef : public ChromeContentBrowserClient {
scoped_refptr<base::SingleThreadTaskRunner> user_blocking_task_runner() const;
private:
static std::unique_ptr<content::WebContentsViewDelegate>
CreateWebContentsViewDelegate(content::WebContents* web_contents);
ChromeBrowserMainExtraPartsCef* browser_main_parts_ = nullptr;
};

View File

@@ -0,0 +1,14 @@
// Copyright 2024 The Chromium Embedded Framework Authors.
// Portions copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libcef/browser/chrome/chrome_content_browser_client_cef.h"
#include "libcef/browser/chrome/chrome_web_contents_view_delegate_cef.h"
// static
std::unique_ptr<content::WebContentsViewDelegate> ChromeContentBrowserClientCef::CreateWebContentsViewDelegate(content::WebContents* web_contents) {
return std::make_unique<ChromeWebContentsViewDelegateCef>(web_contents);
}

View File

@@ -4,6 +4,9 @@
#include "libcef/browser/chrome/chrome_context_menu_handler.h"
#include "base/memory/weak_ptr.h"
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
#include "libcef/browser/browser_host_base.h"
#include "libcef/browser/context_menu_params_impl.h"
#include "libcef/browser/simple_menu_model_impl.h"
@@ -14,6 +17,64 @@ namespace context_menu {
namespace {
constexpr int kInvalidCommandId = -1;
const cef_event_flags_t kEmptyEventFlags = static_cast<cef_event_flags_t>(0);
class CefRunContextMenuCallbackImpl : public CefRunContextMenuCallback {
public:
using Callback =
base::OnceCallback<void(int /*command_id*/, int /*event_flags*/)>;
explicit CefRunContextMenuCallbackImpl(Callback callback)
: callback_(std::move(callback)) {}
CefRunContextMenuCallbackImpl(const CefRunContextMenuCallbackImpl&) = delete;
CefRunContextMenuCallbackImpl& operator=(
const CefRunContextMenuCallbackImpl&) = delete;
~CefRunContextMenuCallbackImpl() override {
if (!callback_.is_null()) {
// The callback is still pending. Cancel it now.
if (CEF_CURRENTLY_ON_UIT()) {
RunNow(std::move(callback_), kInvalidCommandId, kEmptyEventFlags);
} else {
CEF_POST_TASK(CEF_UIT,
base::BindOnce(&CefRunContextMenuCallbackImpl::RunNow,
std::move(callback_), kInvalidCommandId,
kEmptyEventFlags));
}
}
}
void Continue(int command_id, cef_event_flags_t event_flags) override {
if (CEF_CURRENTLY_ON_UIT()) {
if (!callback_.is_null()) {
RunNow(std::move(callback_), command_id, event_flags);
callback_.Reset();
}
} else {
CEF_POST_TASK(CEF_UIT,
base::BindOnce(&CefRunContextMenuCallbackImpl::Continue,
this, command_id, event_flags));
}
}
void Cancel() override { Continue(kInvalidCommandId, kEmptyEventFlags); }
bool IsDisconnected() const { return callback_.is_null(); }
void Disconnect() { callback_.Reset(); }
private:
static void RunNow(Callback callback, int command_id, int event_flags) {
CEF_REQUIRE_UIT();
std::move(callback).Run(command_id, event_flags);
}
Callback callback_;
IMPLEMENT_REFCOUNTING(CefRunContextMenuCallbackImpl);
};
// Lifespan is controlled by RenderViewContextMenu.
class CefContextMenuObserver : public RenderViewContextMenuObserver,
public CefSimpleMenuModelImpl::StateDelegate {
@@ -21,7 +82,10 @@ class CefContextMenuObserver : public RenderViewContextMenuObserver,
CefContextMenuObserver(RenderViewContextMenu* context_menu,
CefRefPtr<CefBrowserHostBase> browser,
CefRefPtr<CefContextMenuHandler> handler)
: context_menu_(context_menu), browser_(browser), handler_(handler) {}
: context_menu_(context_menu), browser_(browser), handler_(handler) {
// This remains valid until the next time a context menu is created.
browser_->set_context_menu_observer(this);
}
CefContextMenuObserver(const CefContextMenuObserver&) = delete;
CefContextMenuObserver& operator=(const CefContextMenuObserver&) = delete;
@@ -130,6 +194,29 @@ class CefContextMenuObserver : public RenderViewContextMenuObserver,
}
}
bool HandleShow() {
if (model_->GetCount() == 0) {
return false;
}
CefRefPtr<CefRunContextMenuCallbackImpl> callbackImpl(
new CefRunContextMenuCallbackImpl(
base::BindOnce(&CefContextMenuObserver::ExecuteCommandCallback,
weak_ptr_factory_.GetWeakPtr())));
bool handled = handler_->RunContextMenu(browser_, GetFrame(), params_,
model_, callbackImpl.get());
if (!handled && callbackImpl->IsDisconnected()) {
LOG(ERROR) << "Should return true from RunContextMenu when executing the "
"callback";
handled = true;
}
if (!handled) {
callbackImpl->Disconnect();
}
return handled;
}
private:
struct ItemInfo {
ItemInfo() = default;
@@ -169,6 +256,7 @@ class CefContextMenuObserver : public RenderViewContextMenuObserver,
// May return nullptr if the frame is destroyed while the menu is pending.
auto* rfh = context_menu_->GetRenderFrameHost();
if (rfh) {
// May return nullptr for guest views.
frame = browser_->GetFrameForHost(rfh);
}
if (!frame) {
@@ -177,6 +265,14 @@ class CefContextMenuObserver : public RenderViewContextMenuObserver,
return frame;
}
void ExecuteCommandCallback(int command_id, int event_flags) {
if (command_id != kInvalidCommandId) {
context_menu_->ExecuteCommand(command_id, event_flags);
}
context_menu_->Cancel();
OnMenuClosed();
}
RenderViewContextMenu* const context_menu_;
CefRefPtr<CefBrowserHostBase> browser_;
CefRefPtr<CefContextMenuHandler> handler_;
@@ -186,6 +282,8 @@ class CefContextMenuObserver : public RenderViewContextMenuObserver,
// Map of command_id to ItemInfo.
using ItemInfoMap = std::map<int, ItemInfo>;
ItemInfoMap iteminfomap_;
base::WeakPtrFactory<CefContextMenuObserver> weak_ptr_factory_{this};
};
std::unique_ptr<RenderViewContextMenuObserver> MenuCreatedCallback(
@@ -199,16 +297,44 @@ std::unique_ptr<RenderViewContextMenuObserver> MenuCreatedCallback(
handler);
}
}
// Don't leave the old pointer, if any.
browser->set_context_menu_observer(nullptr);
}
return nullptr;
}
bool MenuShowHandlerCallback(RenderViewContextMenu* context_menu) {
auto browser = CefBrowserHostBase::GetBrowserForContents(
context_menu->source_web_contents());
if (browser && browser->context_menu_observer()) {
return static_cast<CefContextMenuObserver*>(
browser->context_menu_observer())
->HandleShow();
}
return false;
}
} // namespace
void RegisterMenuCreatedCallback() {
void RegisterCallbacks() {
RenderViewContextMenu::RegisterMenuCreatedCallback(
base::BindRepeating(&MenuCreatedCallback));
RenderViewContextMenu::RegisterMenuShowHandlerCallback(
base::BindRepeating(&MenuShowHandlerCallback));
}
bool HandleContextMenu(content::WebContents* opener,
const content::ContextMenuParams& params) {
auto browser = CefBrowserHostBase::GetBrowserForContents(opener);
if (browser && browser->IsAlloyStyle()) {
AlloyBrowserHostImpl::FromBaseChecked(browser)->ShowContextMenu(params);
return true;
}
// Continue with creating the RenderViewContextMenu.
return false;
}
} // namespace context_menu

View File

@@ -6,10 +6,20 @@
#define CEF_LIBCEF_BROWSER_CHROME_CHROME_CONTEXT_MENU_HANDLER_H_
#pragma once
#include "content/public/browser/context_menu_params.h"
namespace content {
class WebContents;
}
namespace context_menu {
// Register the context menu created callback.
void RegisterMenuCreatedCallback();
// Register RenderViewContextMenu callbacks.
void RegisterCallbacks();
// Returns true if the menu was handled.
bool HandleContextMenu(content::WebContents* opener,
const content::ContextMenuParams& params);
} // namespace context_menu

View File

@@ -0,0 +1,74 @@
// Copyright 2024 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.
#include "libcef/browser/chrome/chrome_devtools_window_runner.h"
#include "libcef/browser/chrome/chrome_browser_host_impl.h"
#include "libcef/browser/request_context_impl.h"
#include "libcef/browser/thread_util.h"
#include "chrome/browser/devtools/devtools_window.h"
void ChromeDevToolsWindowRunner::ShowDevTools(
CefBrowserHostBase* opener,
std::unique_ptr<CefShowDevToolsParams> params) {
CEF_REQUIRE_UIT();
auto* web_contents = opener->GetWebContents();
if (!web_contents) {
return;
}
auto* profile = CefRequestContextImpl::GetProfile(opener->request_context());
if (!DevToolsWindow::AllowDevToolsFor(profile, web_contents)) {
LOG(WARNING) << "DevTools is not allowed for this browser";
return;
}
auto inspect_element_at = params->inspect_element_at_;
if (!browser_host_) {
// Configure parameters for ChromeBrowserDelegate::CreateDevToolsBrowser
// which will be called indirectly to create the DevTools window.
DCHECK(!pending_params_);
pending_params_ = std::move(params);
}
// Focus the existing DevTools window or create a new one.
if (!inspect_element_at.IsEmpty()) {
DevToolsWindow::InspectElement(web_contents->GetPrimaryMainFrame(),
inspect_element_at.x, inspect_element_at.y);
} else {
DevToolsWindow::OpenDevToolsWindow(web_contents, profile,
DevToolsOpenedByAction::kUnknown);
}
// The DevTools browser host should now exist.
DCHECK(browser_host_);
}
void ChromeDevToolsWindowRunner::CloseDevTools() {
CEF_REQUIRE_UIT();
if (browser_host_) {
browser_host_->TryCloseBrowser();
browser_host_ = nullptr;
}
}
bool ChromeDevToolsWindowRunner::HasDevTools() {
CEF_REQUIRE_UIT();
return !!browser_host_;
}
std::unique_ptr<CefShowDevToolsParams>
ChromeDevToolsWindowRunner::TakePendingParams() {
CEF_REQUIRE_UIT();
return std::move(pending_params_);
}
void ChromeDevToolsWindowRunner::SetDevToolsBrowserHost(
base::WeakPtr<ChromeBrowserHostImpl> browser_host) {
CEF_REQUIRE_UIT();
DCHECK(!browser_host_);
browser_host_ = browser_host;
}

View File

@@ -0,0 +1,41 @@
// Copyright 2024 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_BROWSER_CHROME_CHROME_DEVTOOLS_WINDOW_RUNNER_H_
#define CEF_LIBCEF_BROWSER_CHROME_CHROME_DEVTOOLS_WINDOW_RUNNER_H_
#pragma once
#include "libcef/browser/devtools/devtools_window_runner.h"
#include "base/memory/weak_ptr.h"
class ChromeBrowserHostImpl;
// Creates and runs a DevTools window instance. Only accessed on the UI thread.
class ChromeDevToolsWindowRunner : public CefDevToolsWindowRunner {
public:
ChromeDevToolsWindowRunner() = default;
ChromeDevToolsWindowRunner(const ChromeDevToolsWindowRunner&) = delete;
ChromeDevToolsWindowRunner& operator=(const ChromeDevToolsWindowRunner&) =
delete;
// CefDevToolsWindowRunner methods:
void ShowDevTools(CefBrowserHostBase* opener,
std::unique_ptr<CefShowDevToolsParams> params) override;
void CloseDevTools() override;
bool HasDevTools() override;
std::unique_ptr<CefShowDevToolsParams> TakePendingParams();
void SetDevToolsBrowserHost(
base::WeakPtr<ChromeBrowserHostImpl> browser_host);
private:
std::unique_ptr<CefShowDevToolsParams> pending_params_;
base::WeakPtr<ChromeBrowserHostImpl> browser_host_;
};
#endif // CEF_LIBCEF_BROWSER_CHROME_CHROME_DEVTOOLS_WINDOW_RUNNER_H_

View File

@@ -0,0 +1,22 @@
// Copyright 2024 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.
#include "libcef/browser/chrome/chrome_web_contents_view_delegate_cef.h"
#include "libcef/browser/chrome/chrome_context_menu_handler.h"
ChromeWebContentsViewDelegateCef::ChromeWebContentsViewDelegateCef(
content::WebContents* web_contents)
: ChromeWebContentsViewDelegateBase(web_contents),
web_contents_(web_contents) {}
void ChromeWebContentsViewDelegateCef::ShowContextMenu(
content::RenderFrameHost& render_frame_host,
const content::ContextMenuParams& params) {
if (context_menu::HandleContextMenu(web_contents_, params)) {
return;
}
ChromeWebContentsViewDelegateBase::ShowContextMenu(render_frame_host, params);
}

View File

@@ -0,0 +1,37 @@
// Copyright 2024 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_BROWSER_CHROME_CHROME_WEB_CONTENTS_VIEW_DELEGATE_CEF_H_
#define CEF_LIBCEF_BROWSER_CHROME_CHROME_WEB_CONTENTS_VIEW_DELEGATE_CEF_H_
#pragma once
#include "build/build_config.h"
#if BUILDFLAG(IS_MAC)
#include "chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views_mac.h"
using ChromeWebContentsViewDelegateBase = ChromeWebContentsViewDelegateViewsMac;
#else
#include "chrome/browser/ui/views/tab_contents/chrome_web_contents_view_delegate_views.h"
using ChromeWebContentsViewDelegateBase = ChromeWebContentsViewDelegateViews;
#endif
class ChromeWebContentsViewDelegateCef
: public ChromeWebContentsViewDelegateBase {
public:
explicit ChromeWebContentsViewDelegateCef(content::WebContents* web_contents);
ChromeWebContentsViewDelegateCef(const ChromeWebContentsViewDelegateCef&) =
delete;
ChromeWebContentsViewDelegateCef& operator=(
const ChromeWebContentsViewDelegateCef&) = delete;
// WebContentsViewDelegate methods:
void ShowContextMenu(content::RenderFrameHost& render_frame_host,
const content::ContextMenuParams& params) override;
private:
content::WebContents* const web_contents_;
};
#endif // CEF_LIBCEF_BROWSER_CHROME_CHROME_WEB_CONTENTS_VIEW_DELEGATE_CEF_H_

View File

@@ -0,0 +1,6 @@
// Copyright 2024 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.
// Work around ChromeWebContentsViewDelegateViewsMac containing ObjC references.
#include "libcef/browser/chrome/chrome_web_contents_view_delegate_cef.cc"

View File

@@ -7,6 +7,7 @@
#include "libcef/browser/browser_host_base.h"
#include "libcef/browser/browser_info.h"
#include "libcef/browser/chrome/chrome_context_menu_handler.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
@@ -45,4 +46,15 @@ void ChromeMimeHandlerViewGuestDelegateCef::OnGuestDetached() {
web_contents->GetPrimaryMainFrame());
}
bool ChromeMimeHandlerViewGuestDelegateCef::HandleContextMenu(
content::RenderFrameHost& render_frame_host,
const content::ContextMenuParams& params) {
if (context_menu::HandleContextMenu(owner_web_contents_, params)) {
return true;
}
return ChromeMimeHandlerViewGuestDelegate::HandleContextMenu(
render_frame_host, params);
}
} // namespace extensions

View File

@@ -26,6 +26,8 @@ class ChromeMimeHandlerViewGuestDelegateCef
// MimeHandlerViewGuestDelegate methods.
void OnGuestAttached() override;
void OnGuestDetached() override;
bool HandleContextMenu(content::RenderFrameHost& render_frame_host,
const content::ContextMenuParams& params) override;
private:
MimeHandlerViewGuest* guest_; // Owns us.

View File

@@ -18,6 +18,11 @@ void CefBrowserPlatformDelegateChromeChildWindow::CloseHostWindow() {
native_delegate_->CloseHostWindow();
}
CefRefPtr<CefBrowserViewDelegate> CefBrowserPlatformDelegateChromeChildWindow::
GetDefaultBrowserViewDelegateForPopupOpener() {
return chrome_child_window::GetDefaultBrowserViewDelegateForPopupOpener();
}
void CefBrowserPlatformDelegateChromeChildWindow::SetFocus(bool focus) {
native_delegate_->SetFocus(focus);
}

View File

@@ -17,6 +17,8 @@ class CefBrowserPlatformDelegateChromeChildWindow
// CefBrowserPlatformDelegate overrides.
void CloseHostWindow() override;
CefRefPtr<CefBrowserViewDelegate>
GetDefaultBrowserViewDelegateForPopupOpener() override;
void SetFocus(bool focus) override;
#if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC))

View File

@@ -12,43 +12,6 @@
#include "components/zoom/zoom_controller.h"
#include "ui/views/widget/widget.h"
namespace {
// Default popup window delegate implementation.
class PopupWindowDelegate : public CefWindowDelegate {
public:
explicit PopupWindowDelegate(CefRefPtr<CefBrowserView> browser_view)
: browser_view_(browser_view) {}
PopupWindowDelegate(const PopupWindowDelegate&) = delete;
PopupWindowDelegate& operator=(const PopupWindowDelegate&) = delete;
void OnWindowCreated(CefRefPtr<CefWindow> window) override {
window->AddChildView(browser_view_);
window->Show();
browser_view_->RequestFocus();
}
void OnWindowDestroyed(CefRefPtr<CefWindow> window) override {
browser_view_ = nullptr;
}
bool CanClose(CefRefPtr<CefWindow> window) override {
CefRefPtr<CefBrowser> browser = browser_view_->GetBrowser();
if (browser) {
return browser->GetHost()->TryCloseBrowser();
}
return true;
}
private:
CefRefPtr<CefBrowserView> browser_view_;
IMPLEMENT_REFCOUNTING(PopupWindowDelegate);
};
} // namespace
CefBrowserPlatformDelegateChromeViews::CefBrowserPlatformDelegateChromeViews(
std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
CefRefPtr<CefBrowserViewImpl> browser_view)
@@ -59,10 +22,10 @@ CefBrowserPlatformDelegateChromeViews::CefBrowserPlatformDelegateChromeViews(
}
void CefBrowserPlatformDelegateChromeViews::SetBrowserView(
CefRefPtr<CefBrowserViewImpl> browser_view) {
CefRefPtr<CefBrowserView> browser_view) {
DCHECK(!browser_view_);
DCHECK(browser_view);
browser_view_ = browser_view;
browser_view_ = static_cast<CefBrowserViewImpl*>(browser_view.get());
}
void CefBrowserPlatformDelegateChromeViews::WebContentsCreated(
@@ -148,59 +111,6 @@ CefBrowserPlatformDelegateChromeViews::GetBrowserView() const {
return browser_view_.get();
}
void CefBrowserPlatformDelegateChromeViews::PopupWebContentsCreated(
const CefBrowserSettings& settings,
CefRefPtr<CefClient> client,
content::WebContents* new_web_contents,
CefBrowserPlatformDelegate* new_platform_delegate,
bool is_devtools) {
// Default popup handling may not be Views-hosted.
if (!new_platform_delegate->IsViewsHosted()) {
return;
}
auto* new_platform_delegate_impl =
static_cast<CefBrowserPlatformDelegateChromeViews*>(
new_platform_delegate);
CefRefPtr<CefBrowserViewDelegate> new_delegate;
if (browser_view_->delegate()) {
new_delegate = browser_view_->delegate()->GetDelegateForPopupBrowserView(
browser_view_.get(), settings, client, is_devtools);
}
// Create a new BrowserView for the popup.
CefRefPtr<CefBrowserViewImpl> new_browser_view =
CefBrowserViewImpl::CreateForPopup(settings, new_delegate);
// Associate the PlatformDelegate with the new BrowserView.
new_platform_delegate_impl->SetBrowserView(new_browser_view);
}
void CefBrowserPlatformDelegateChromeViews::PopupBrowserCreated(
CefBrowserHostBase* new_browser,
bool is_devtools) {
// Default popup handling may not be Views-hosted.
if (!new_browser->HasView()) {
return;
}
CefRefPtr<CefBrowserView> new_browser_view =
CefBrowserView::GetForBrowser(new_browser);
DCHECK(new_browser_view);
bool popup_handled = false;
if (browser_view_->delegate()) {
popup_handled = browser_view_->delegate()->OnPopupBrowserViewCreated(
browser_view_.get(), new_browser_view.get(), is_devtools);
}
if (!popup_handled) {
CefWindow::CreateTopLevelWindow(
new PopupWindowDelegate(new_browser_view.get()));
}
}
bool CefBrowserPlatformDelegateChromeViews::IsViewsHosted() const {
return true;
}

View File

@@ -30,21 +30,12 @@ class CefBrowserPlatformDelegateChromeViews
CefWindowHandle GetHostWindowHandle() const override;
views::Widget* GetWindowWidget() const override;
CefRefPtr<CefBrowserView> GetBrowserView() const override;
void PopupWebContentsCreated(
const CefBrowserSettings& settings,
CefRefPtr<CefClient> client,
content::WebContents* new_web_contents,
CefBrowserPlatformDelegate* new_platform_delegate,
bool is_devtools) override;
void PopupBrowserCreated(CefBrowserHostBase* new_browser,
bool is_devtools) override;
void SetBrowserView(CefRefPtr<CefBrowserView> browser_view) override;
bool IsViewsHosted() const override;
CefRefPtr<CefBrowserViewImpl> browser_view() const { return browser_view_; }
private:
void SetBrowserView(CefRefPtr<CefBrowserViewImpl> browser_view);
CefWindowImpl* GetWindowImpl() const;
CefRefPtr<CefBrowserViewImpl> browser_view_;

View File

@@ -107,6 +107,7 @@ class ChromeBrowserFrame : public BrowserFrame,
void Init(BrowserView* browser_view, std::unique_ptr<Browser> browser);
// CefWidget methods:
bool IsAlloyStyle() const override { return false; }
views::Widget* GetWidget() override { return this; }
const views::Widget* GetWidget() const override { return this; }
void Initialized() override;

View File

@@ -54,9 +54,6 @@ void ChromeBrowserView::ViewHierarchyChanged(
void ChromeBrowserView::AddedToWidget() {
// Create the Browser and ChromeBrowserHostImpl.
// Results in a call to InitBrowser which calls ParentClass::AddedToWidget.
cef_browser_view_->OnBrowserViewAdded();
// Call after ChromeBrowserHostImpl creation.
cef_browser_view_->AddedToWidget();
}

View File

@@ -8,6 +8,8 @@
#include "libcef/browser/views/browser_view_impl.h"
#include "libcef/browser/views/window_impl.h"
#include "ui/gfx/native_widget_types.h"
#if BUILDFLAG(IS_WIN)
#include "libcef/browser/native/browser_platform_delegate_native_win.h"
#include "ui/views/win/hwnd_util.h"
@@ -15,6 +17,23 @@
namespace {
gfx::AcceleratedWidget GetParentWidget(const CefWindowInfo& window_info) {
#if !BUILDFLAG(IS_MAC)
return window_info.parent_window;
#else
// Chrome style is not supported with native parent on MacOS. See issue #3294.
return gfx::kNullAcceleratedWidget;
#endif
}
CefWindowHandle GetParentHandle(const CefWindowInfo& window_info) {
#if !BUILDFLAG(IS_MAC)
return window_info.parent_window;
#else
return window_info.parent_view;
#endif
}
class ChildWindowDelegate : public CefWindowDelegate {
public:
ChildWindowDelegate(const ChildWindowDelegate&) = delete;
@@ -61,8 +80,7 @@ class ChildWindowDelegate : public CefWindowDelegate {
DCHECK(widget_hwnd);
// The native delegate needs state to perform some actions.
auto browser =
static_cast<CefBrowserHostBase*>(browser_view_->GetBrowser().get());
auto browser = CefBrowserHostBase::FromBrowser(browser_view_->GetBrowser());
auto platform_delegate = browser->platform_delegate();
DCHECK(platform_delegate->IsViewsHosted());
auto chrome_delegate =
@@ -115,6 +133,8 @@ class ChildBrowserViewDelegate : public CefBrowserViewDelegate {
ChildBrowserViewDelegate(const ChildBrowserViewDelegate&) = delete;
ChildBrowserViewDelegate& operator=(const ChildBrowserViewDelegate&) = delete;
// |browser_view| will be nullptr when called for popups with non-Views-hosted
// opener.
CefRefPtr<CefBrowserViewDelegate> GetDelegateForPopupBrowserView(
CefRefPtr<CefBrowserView> browser_view,
const CefBrowserSettings& settings,
@@ -123,11 +143,13 @@ class ChildBrowserViewDelegate : public CefBrowserViewDelegate {
return new ChildBrowserViewDelegate();
}
// |browser_view| will be nullptr when called for popups with non-Views-hosted
// opener.
bool OnPopupBrowserViewCreated(CefRefPtr<CefBrowserView> browser_view,
CefRefPtr<CefBrowserView> popup_browser_view,
bool is_devtools) override {
auto new_browser = static_cast<CefBrowserHostBase*>(
popup_browser_view->GetBrowser().get());
auto new_browser =
CefBrowserHostBase::FromBrowser(popup_browser_view->GetBrowser());
auto new_platform_delegate = new_browser->platform_delegate();
DCHECK(new_platform_delegate->IsViewsHosted());
auto new_platform_delegate_impl =
@@ -136,8 +158,7 @@ class ChildBrowserViewDelegate : public CefBrowserViewDelegate {
const auto& window_info =
new_platform_delegate_impl->native_delegate()->window_info();
const auto parent_handle =
chrome_child_window::GetParentHandle(window_info);
const auto parent_handle = GetParentWidget(window_info);
if (parent_handle != gfx::kNullAcceleratedWidget) {
ChildWindowDelegate::Create(popup_browser_view, window_info,
parent_handle);
@@ -158,15 +179,7 @@ class ChildBrowserViewDelegate : public CefBrowserViewDelegate {
namespace chrome_child_window {
bool HasParentHandle(const CefWindowInfo& window_info) {
return GetParentHandle(window_info) != gfx::kNullAcceleratedWidget;
}
gfx::AcceleratedWidget GetParentHandle(const CefWindowInfo& window_info) {
#if !BUILDFLAG(IS_MAC)
return window_info.parent_window;
#else
return gfx::kNullAcceleratedWidget;
#endif
return GetParentHandle(window_info) != kNullWindowHandle;
}
CefRefPtr<CefBrowserHostBase> MaybeCreateChildBrowser(
@@ -181,7 +194,7 @@ CefRefPtr<CefBrowserHostBase> MaybeCreateChildBrowser(
return nullptr;
}
const auto parent_handle = GetParentHandle(*create_params.window_info);
const auto parent_handle = GetParentWidget(*create_params.window_info);
if (parent_handle == gfx::kNullAcceleratedWidget) {
return nullptr;
}
@@ -195,7 +208,12 @@ CefRefPtr<CefBrowserHostBase> MaybeCreateChildBrowser(
ChildWindowDelegate::Create(browser_view, *create_params.window_info,
parent_handle);
return static_cast<CefBrowserHostBase*>(browser_view->GetBrowser().get());
return CefBrowserHostBase::FromBrowser(browser_view->GetBrowser());
}
CefRefPtr<CefBrowserViewDelegate>
GetDefaultBrowserViewDelegateForPopupOpener() {
return new ChildBrowserViewDelegate();
}
} // namespace chrome_child_window

View File

@@ -6,19 +6,19 @@
#define CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_CHILD_WINDOW_H_
#pragma once
#include "include/views/cef_browser_view_delegate.h"
#include "libcef/browser/browser_host_base.h"
#include "ui/gfx/native_widget_types.h"
namespace chrome_child_window {
bool HasParentHandle(const CefWindowInfo& window_info);
gfx::AcceleratedWidget GetParentHandle(const CefWindowInfo& window_info);
// Called from CefBrowserHostBase::Create.
CefRefPtr<CefBrowserHostBase> MaybeCreateChildBrowser(
const CefBrowserCreateParams& create_params);
CefRefPtr<CefBrowserViewDelegate> GetDefaultBrowserViewDelegateForPopupOpener();
} // namespace chrome_child_window
#endif // CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_CHILD_WINDOW_H_