mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
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]`
220 lines
7.2 KiB
C++
220 lines
7.2 KiB
C++
// Copyright 2022 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/views/chrome_child_window.h"
|
|
|
|
#include "libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h"
|
|
#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"
|
|
#endif
|
|
|
|
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;
|
|
ChildWindowDelegate& operator=(const ChildWindowDelegate&) = delete;
|
|
|
|
static void Create(CefRefPtr<CefBrowserView> browser_view,
|
|
const CefWindowInfo& window_info,
|
|
gfx::AcceleratedWidget parent_handle) {
|
|
DCHECK(parent_handle != gfx::kNullAcceleratedWidget);
|
|
|
|
// Create the Window. It will show itself after creation.
|
|
CefWindowImpl::Create(new ChildWindowDelegate(browser_view, window_info),
|
|
parent_handle);
|
|
}
|
|
|
|
void OnWindowCreated(CefRefPtr<CefWindow> window) override {
|
|
DCHECK(!window_);
|
|
window_ = window;
|
|
|
|
// Add the browser view. It will now have an associated Widget.
|
|
window_->AddChildView(browser_view_);
|
|
|
|
ShowWindow();
|
|
}
|
|
|
|
void OnWindowDestroyed(CefRefPtr<CefWindow> window) override {
|
|
browser_view_ = nullptr;
|
|
window_ = nullptr;
|
|
}
|
|
|
|
CefRect GetInitialBounds(CefRefPtr<CefWindow> window) override {
|
|
CefRect initial_bounds(window_info_.bounds);
|
|
if (initial_bounds.IsEmpty()) {
|
|
return CefRect(0, 0, 800, 600);
|
|
}
|
|
return initial_bounds;
|
|
}
|
|
|
|
void ShowWindow() {
|
|
#if BUILDFLAG(IS_WIN)
|
|
auto widget = static_cast<CefWindowImpl*>(window_.get())->widget();
|
|
DCHECK(widget);
|
|
const HWND widget_hwnd = HWNDForWidget(widget);
|
|
DCHECK(widget_hwnd);
|
|
|
|
// The native delegate needs state to perform some actions.
|
|
auto browser = CefBrowserHostBase::FromBrowser(browser_view_->GetBrowser());
|
|
auto platform_delegate = browser->platform_delegate();
|
|
DCHECK(platform_delegate->IsViewsHosted());
|
|
auto chrome_delegate =
|
|
static_cast<CefBrowserPlatformDelegateChromeViews*>(platform_delegate);
|
|
auto native_delegate = static_cast<CefBrowserPlatformDelegateNativeWin*>(
|
|
chrome_delegate->native_delegate());
|
|
native_delegate->set_widget(widget, widget_hwnd);
|
|
|
|
if (window_info_.ex_style & WS_EX_NOACTIVATE) {
|
|
const DWORD widget_ex_styles = GetWindowLongPtr(widget_hwnd, GWL_EXSTYLE);
|
|
|
|
// Add the WS_EX_NOACTIVATE style on the DesktopWindowTreeHostWin HWND
|
|
// so that HWNDMessageHandler::Show() called via Widget::Show() does not
|
|
// activate the window.
|
|
SetWindowLongPtr(widget_hwnd, GWL_EXSTYLE,
|
|
widget_ex_styles | WS_EX_NOACTIVATE);
|
|
|
|
window_->Show();
|
|
|
|
// Remove the WS_EX_NOACTIVATE style so that future mouse clicks inside
|
|
// the browser correctly activate and focus the window.
|
|
SetWindowLongPtr(widget_hwnd, GWL_EXSTYLE, widget_ex_styles);
|
|
return;
|
|
}
|
|
#endif // BUILDFLAG(IS_WIN)
|
|
|
|
window_->Show();
|
|
|
|
// Give keyboard focus to the browser view.
|
|
browser_view_->RequestFocus();
|
|
}
|
|
|
|
private:
|
|
ChildWindowDelegate(CefRefPtr<CefBrowserView> browser_view,
|
|
const CefWindowInfo& window_info)
|
|
: browser_view_(browser_view), window_info_(window_info) {}
|
|
|
|
CefRefPtr<CefBrowserView> browser_view_;
|
|
const CefWindowInfo window_info_;
|
|
|
|
CefRefPtr<CefWindow> window_;
|
|
|
|
IMPLEMENT_REFCOUNTING(ChildWindowDelegate);
|
|
};
|
|
|
|
class ChildBrowserViewDelegate : public CefBrowserViewDelegate {
|
|
public:
|
|
ChildBrowserViewDelegate() = default;
|
|
|
|
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,
|
|
CefRefPtr<CefClient> client,
|
|
bool is_devtools) override {
|
|
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 =
|
|
CefBrowserHostBase::FromBrowser(popup_browser_view->GetBrowser());
|
|
auto new_platform_delegate = new_browser->platform_delegate();
|
|
DCHECK(new_platform_delegate->IsViewsHosted());
|
|
auto new_platform_delegate_impl =
|
|
static_cast<CefBrowserPlatformDelegateChromeViews*>(
|
|
new_platform_delegate);
|
|
|
|
const auto& window_info =
|
|
new_platform_delegate_impl->native_delegate()->window_info();
|
|
const auto parent_handle = GetParentWidget(window_info);
|
|
if (parent_handle != gfx::kNullAcceleratedWidget) {
|
|
ChildWindowDelegate::Create(popup_browser_view, window_info,
|
|
parent_handle);
|
|
return true;
|
|
}
|
|
|
|
// Use the default implementation that creates a new Views-hosted top-level
|
|
// window.
|
|
return false;
|
|
}
|
|
|
|
private:
|
|
IMPLEMENT_REFCOUNTING(ChildBrowserViewDelegate);
|
|
};
|
|
|
|
} // namespace
|
|
|
|
namespace chrome_child_window {
|
|
|
|
bool HasParentHandle(const CefWindowInfo& window_info) {
|
|
return GetParentHandle(window_info) != kNullWindowHandle;
|
|
}
|
|
|
|
CefRefPtr<CefBrowserHostBase> MaybeCreateChildBrowser(
|
|
const CefBrowserCreateParams& create_params) {
|
|
// If the BrowserView already exists it means that we're dealing with a popup
|
|
// and we'll instead create the Window in OnPopupBrowserViewCreated.
|
|
if (create_params.browser_view) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (!create_params.window_info) {
|
|
return nullptr;
|
|
}
|
|
|
|
const auto parent_handle = GetParentWidget(*create_params.window_info);
|
|
if (parent_handle == gfx::kNullAcceleratedWidget) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Create the BrowserView.
|
|
auto browser_view = CefBrowserViewImpl::Create(
|
|
*create_params.window_info, create_params.client, create_params.url,
|
|
create_params.settings, create_params.extra_info,
|
|
create_params.request_context, new ChildBrowserViewDelegate());
|
|
|
|
ChildWindowDelegate::Create(browser_view, *create_params.window_info,
|
|
parent_handle);
|
|
|
|
return CefBrowserHostBase::FromBrowser(browser_view->GetBrowser());
|
|
}
|
|
|
|
CefRefPtr<CefBrowserViewDelegate>
|
|
GetDefaultBrowserViewDelegateForPopupOpener() {
|
|
return new ChildBrowserViewDelegate();
|
|
}
|
|
|
|
} // namespace chrome_child_window
|