From 944bbded135a0a6586d9e1dfe6ed6d9ac42e6e32 Mon Sep 17 00:00:00 2001 From: Chad Nelson Date: Thu, 29 Jan 2026 14:30:08 -0600 Subject: [PATCH] Support transparent window in Views framework (follow up issue #2315) --- include/internal/cef_types.h | 8 +-- libcef/browser/browser_host_base.cc | 3 +- .../browser_platform_delegate_create.cc | 8 ++- libcef/browser/context.cc | 20 +++--- libcef/browser/context.h | 11 ++-- libcef/browser/views/window_view.cc | 13 ++++ tests/cefclient/browser/main_context_impl.cc | 11 ++++ tests/cefclient/browser/resource.h | 13 ++-- .../browser/resource_util_win_idmap.cc | 1 + .../resources/transparent_views.html | 64 +++++++++++++++++++ tests/cefclient/win/cefclient.rc | 1 + tests/cefsimple/simple_app.cc | 6 ++ tests/ceftests/views/window_unittest.cc | 14 ++++ 13 files changed, 144 insertions(+), 29 deletions(-) create mode 100644 tests/cefclient/resources/transparent_views.html diff --git a/include/internal/cef_types.h b/include/internal/cef_types.h index 3ec2b6a9a4..c7f72f420c 100644 --- a/include/internal/cef_types.h +++ b/include/internal/cef_types.h @@ -443,8 +443,8 @@ typedef struct _cef_settings_t { /// opaque then the RGB components will be used as the background color. If /// the alpha component is fully transparent for a windowed browser then the /// default value of opaque white be used. If the alpha component is fully - /// transparent for a windowless (off-screen) browser then transparent - /// painting will be enabled. + /// transparent for a windowless (off-screen) browser or a frameless window + /// using Views framework then transparent painting will be enabled. /// cef_color_t background_color; @@ -704,8 +704,8 @@ typedef struct _cef_browser_settings_t { /// opaque then the RGB components will be used as the background color. If /// the alpha component is fully transparent for a windowed browser then the /// CefSettings.background_color value will be used. If the alpha component is - /// fully transparent for a windowless (off-screen) browser then transparent - /// painting will be enabled. + /// fully transparent for a windowless (off-screen) browser or a frameless window + /// using Views framework then transparent painting will be enabled. /// cef_color_t background_color; diff --git a/libcef/browser/browser_host_base.cc b/libcef/browser/browser_host_base.cc index d8f6b040de..262cb08171 100644 --- a/libcef/browser/browser_host_base.cc +++ b/libcef/browser/browser_host_base.cc @@ -1521,7 +1521,8 @@ int CefBrowserHostBase::browser_id() const { SkColor CefBrowserHostBase::GetBackgroundColor() const { // Don't use |platform_delegate_| because it's not thread-safe. return CefContext::Get()->GetBackgroundColor( - &settings_, IsWindowless() ? STATE_ENABLED : STATE_DISABLED); + &settings_, + IsWindowless() || is_views_hosted() ? STATE_ENABLED : STATE_DISABLED); } content::WebContents* CefBrowserHostBase::GetWebContents() const { diff --git a/libcef/browser/browser_platform_delegate_create.cc b/libcef/browser/browser_platform_delegate_create.cc index b2f30ae0a0..8fcfd40db1 100644 --- a/libcef/browser/browser_platform_delegate_create.cc +++ b/libcef/browser/browser_platform_delegate_create.cc @@ -67,8 +67,11 @@ std::unique_ptr CreateOSRDelegate( std::unique_ptr CefBrowserPlatformDelegate::Create( const CefBrowserCreateParams& create_params) { const bool is_windowless = create_params.IsWindowless(); + const bool is_views_hosted = create_params.browser_view || + create_params.popup_with_views_hosted_opener; const SkColor background_color = CefContext::Get()->GetBackgroundColor( - &create_params.settings, is_windowless ? STATE_ENABLED : STATE_DISABLED); + &create_params.settings, + is_windowless || is_views_hosted ? STATE_ENABLED : STATE_DISABLED); if (create_params.IsChromeStyle()) { CefWindowInfo window_info; @@ -97,8 +100,7 @@ std::unique_ptr CefBrowserPlatformDelegate::Create( std::move(native_delegate)); } - if (create_params.browser_view || - create_params.popup_with_views_hosted_opener) { + if (is_views_hosted) { // CefWindowInfo is not used in this case. std::unique_ptr native_delegate = CreateNativeDelegate(CefWindowInfo(), background_color); diff --git a/libcef/browser/context.cc b/libcef/browser/context.cc index 53abc8dba7..9512a21273 100644 --- a/libcef/browser/context.cc +++ b/libcef/browser/context.cc @@ -74,14 +74,14 @@ void InitCrashReporter() { #endif // BUILDFLAG(IS_WIN) -bool GetColor(const cef_color_t cef_in, bool is_windowless, SkColor* sk_out) { - // Windowed browser colors must be fully opaque. - if (!is_windowless && CefColorGetA(cef_in) != SK_AlphaOPAQUE) { +bool GetColor(const cef_color_t cef_in, bool is_transparent, SkColor* sk_out) { + // transparent unsupported browser colors must be fully opaque. + if (!is_transparent && CefColorGetA(cef_in) != SK_AlphaOPAQUE) { return false; } - // Windowless browser colors may be fully transparent. - if (is_windowless && CefColorGetA(cef_in) == SK_AlphaTRANSPARENT) { + // transparent supported browser colors may be fully transparent. + if (is_transparent && CefColorGetA(cef_in) == SK_AlphaTRANSPARENT) { *sk_out = SK_ColorTRANSPARENT; return true; } @@ -444,10 +444,10 @@ bool CefContext::OnInitThread() { SkColor CefContext::GetBackgroundColor( const CefBrowserSettings* browser_settings, - cef_state_t windowless_state) const { - bool is_windowless = windowless_state == STATE_ENABLED + cef_state_t transparent_state) const { + bool is_transparent = transparent_state == STATE_ENABLED ? true - : (windowless_state == STATE_DISABLED + : (transparent_state == STATE_DISABLED ? false : !!settings_.windowless_rendering_enabled); @@ -455,8 +455,8 @@ SkColor CefContext::GetBackgroundColor( SkColor sk_color = SK_ColorWHITE; if (!browser_settings || - !GetColor(browser_settings->background_color, is_windowless, &sk_color)) { - GetColor(settings_.background_color, is_windowless, &sk_color); + !GetColor(browser_settings->background_color, is_transparent, &sk_color)) { + GetColor(settings_.background_color, is_transparent, &sk_color); } return sk_color; } diff --git a/libcef/browser/context.h b/libcef/browser/context.h index b73fc32f52..fab29fb47f 100644 --- a/libcef/browser/context.h +++ b/libcef/browser/context.h @@ -70,13 +70,14 @@ class CefContext { // Returns the background color for the browser. If |browser_settings| is // nullptr or does not specify a color then the global settings will be used. // The alpha component will be either SK_AlphaTRANSPARENT or SK_AlphaOPAQUE - // (e.g. fully transparent or fully opaque). If |is_windowless| is + // (e.g. fully transparent or fully opaque). If |transparent_state| is // STATE_DISABLED then SK_AlphaTRANSPARENT will always be returned. If - // |is_windowless| is STATE_ENABLED then SK_ColorTRANSPARENT may be returned - // to enable transparency for windowless browsers. See additional comments on - // CefSettings.background_color and CefBrowserSettings.background_color. + // |transparent_state| is STATE_ENABLED then SK_ColorTRANSPARENT may be returned + // to enable transparency for windowless browsers or a frameless + // window in Views. See additional comments on CefSettings.background_color + // and CefBrowserSettings.background_color. SkColor GetBackgroundColor(const CefBrowserSettings* browser_settings, - cef_state_t windowless_state) const; + cef_state_t transparent_state) const; CefTraceSubscriber* GetTraceSubscriber(); pref_helper::Registrar* GetPrefRegistrar(); diff --git a/libcef/browser/views/window_view.cc b/libcef/browser/views/window_view.cc index f1d3d9019b..f4f34981fa 100644 --- a/libcef/browser/views/window_view.cc +++ b/libcef/browser/views/window_view.cc @@ -17,10 +17,13 @@ #endif #endif +#include "cef/libcef/browser/chrome/views/chrome_browser_frame.h" +#include "cef/libcef/browser/context.h" #include "cef/libcef/browser/geometry_util.h" #include "cef/libcef/browser/image_impl.h" #include "cef/libcef/browser/views/widget.h" #include "cef/libcef/browser/views/window_impl.h" +#include "cef/libcef/features/runtime.h" #include "ui/base/hit_test.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/base/mojom/ui_base_types.mojom-shared.h" @@ -521,6 +524,9 @@ void CefWindowView::CreateWidget(gfx::AcceleratedWidget parent_widget) { bool can_activate = true; bool can_resize = true; + auto color = CefContext::Get()->GetBackgroundColor(nullptr, STATE_ENABLED); + bool is_translucent = color == SK_ColorTRANSPARENT; + const bool has_native_parent = parent_widget != gfx::kNullAcceleratedWidget; if (has_native_parent) { params.parent_widget = parent_widget; @@ -539,6 +545,9 @@ void CefWindowView::CreateWidget(gfx::AcceleratedWidget parent_widget) { params.opacity = views::Widget::InitParams::WindowOpacity::kOpaque; } else { params.type = views::Widget::InitParams::TYPE_WINDOW; + if (is_translucent) { + params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent; + } } if (cef_delegate()) { @@ -727,6 +736,10 @@ void CefWindowView::CreateWidget(gfx::AcceleratedWidget parent_widget) { // |widget|. host_widget_destruction_observer_ = std::make_unique(host_widget); + + if (is_translucent) { + GetCefWindow()->SetBackgroundColor(SK_ColorTRANSPARENT); + } } } diff --git a/tests/cefclient/browser/main_context_impl.cc b/tests/cefclient/browser/main_context_impl.cc index 74bfc7d787..780ea6db14 100644 --- a/tests/cefclient/browser/main_context_impl.cc +++ b/tests/cefclient/browser/main_context_impl.cc @@ -110,6 +110,17 @@ MainContextImpl::MainContextImpl(CefRefPtr command_line, use_views_ = true; } + // Whether transparent painting is used with windowless rendering. + const bool use_transparent_painting = + (use_windowless_rendering_ || use_views_) && + command_line_->HasSwitch(switches::kTransparentPaintingEnabled); + if (use_views_ && use_transparent_painting && + command_line->HasSwitch(switches::kHideFrame) && + !command_line_->HasSwitch(switches::kUrl)) { + // Use the draggable regions test as the default URL for frameless windows. + main_url_ = "http://tests/transparent_views"; + } + if (command_line_->HasSwitch(switches::kBackgroundColor)) { // Parse the background color value. background_color_ = diff --git a/tests/cefclient/browser/resource.h b/tests/cefclient/browser/resource.h index 9cf60e0809..fd1fd59544 100644 --- a/tests/cefclient/browser/resource.h +++ b/tests/cefclient/browser/resource.h @@ -68,12 +68,13 @@ #define IDS_SERVER_HTML 1021 #define IDS_TASK_MANAGER_HTML 1022 #define IDS_TRANSPARENCY_HTML 1023 -#define IDS_URLREQUEST_HTML 1024 -#define IDS_WEBSOCKET_HTML 1025 -#define IDS_WINDOW_HTML 1026 -#define IDS_WINDOW_ICON_1X_PNG 1027 -#define IDS_WINDOW_ICON_2X_PNG 1028 -#define IDS_XMLHTTPREQUEST_HTML 1029 +#define IDS_TRANSPARENCT_VIEWS_HTML 1024 +#define IDS_URLREQUEST_HTML 1025 +#define IDS_WEBSOCKET_HTML 1026 +#define IDS_WINDOW_HTML 1027 +#define IDS_WINDOW_ICON_1X_PNG 1028 +#define IDS_WINDOW_ICON_2X_PNG 1029 +#define IDS_XMLHTTPREQUEST_HTML 1030 // Next default values for new objects // diff --git a/tests/cefclient/browser/resource_util_win_idmap.cc b/tests/cefclient/browser/resource_util_win_idmap.cc index dfe6550920..dfd3a221ca 100644 --- a/tests/cefclient/browser/resource_util_win_idmap.cc +++ b/tests/cefclient/browser/resource_util_win_idmap.cc @@ -37,6 +37,7 @@ int GetResourceId(const char* resource_name) { {"server.html", IDS_SERVER_HTML}, {"task_manager.html", IDS_TASK_MANAGER_HTML}, {"transparency.html", IDS_TRANSPARENCY_HTML}, + {"transparent_views.html", IDS_TRANSPARENT_VIEWS_HTML}, {"urlrequest.html", IDS_URLREQUEST_HTML}, {"websocket.html", IDS_WEBSOCKET_HTML}, {"window.html", IDS_WINDOW_HTML}, diff --git a/tests/cefclient/resources/transparent_views.html b/tests/cefclient/resources/transparent_views.html new file mode 100644 index 0000000000..e9f75bdc1f --- /dev/null +++ b/tests/cefclient/resources/transparent_views.html @@ -0,0 +1,64 @@ + + Translucent Window Test + + + + +
+
+
+
X
+
+ Transparent window using Views framework can be enabled by setting the + alpha component of the CefSettings.background_color to fully transparent + (0x00) and returning true from IsFrameless() in CefWindowDelegate(). + The transparent effect will propagate to + popped up window. +
Window can be closed using JavaScript window.close(). +

+ Click: decrease alpha component of the background.
+ Shift-Click: increase alpha component of the background. +
+ + \ No newline at end of file diff --git a/tests/cefclient/win/cefclient.rc b/tests/cefclient/win/cefclient.rc index 686c354609..375bf90afb 100644 --- a/tests/cefclient/win/cefclient.rc +++ b/tests/cefclient/win/cefclient.rc @@ -53,6 +53,7 @@ IDS_RESPONSE_FILTER_HTML BINARY "tests\\cefclient\\resources\\response_filter.ht IDS_SERVER_HTML BINARY "tests\\cefclient\\resources\\server.html" IDS_TASK_MANAGER_HTML BINARY "tests\\cefclient\\resources\\task_manager.html" IDS_TRANSPARENCY_HTML BINARY "tests\\cefclient\\resources\\transparency.html" +IDS_TRANSPARENT_VIEWS_HTML BINARY "tests\\cefclient\\resources\\transparent_views.html" IDS_URLREQUEST_HTML BINARY "tests\\cefclient\\resources\\urlrequest.html" IDS_WEBSOCKET_HTML BINARY "tests\\cefclient\\resources\\websocket.html" IDS_WINDOW_HTML BINARY "tests\\cefclient\\resources\\window.html" diff --git a/tests/cefsimple/simple_app.cc b/tests/cefsimple/simple_app.cc index 302d00ec3e..76272ea4a6 100644 --- a/tests/cefsimple/simple_app.cc +++ b/tests/cefsimple/simple_app.cc @@ -42,6 +42,12 @@ class SimpleWindowDelegate : public CefWindowDelegate { browser_view_ = nullptr; } + bool IsFrameless(CefRefPtr window) override { + CefRefPtr command_line = + CefCommandLine::GetGlobalCommandLine(); + return command_line->HasSwitch("hide-frame"); + } + bool CanClose(CefRefPtr window) override { // Allow the window to close if the browser says it's OK. CefRefPtr browser = browser_view_->GetBrowser(); diff --git a/tests/ceftests/views/window_unittest.cc b/tests/ceftests/views/window_unittest.cc index 5c769647db..2fa030cf90 100644 --- a/tests/ceftests/views/window_unittest.cc +++ b/tests/ceftests/views/window_unittest.cc @@ -567,6 +567,19 @@ void WindowAcceleratorImpl(CefRefPtr event) { TestWindowDelegate::RunTest(event, std::move(config)); } +void VerifyWindowTransparentBackground(CefRefPtr window) { + // The transparent background color value from CefSettings.background_color + // by set in CefTestSuite::GetSettings() to enable transparent window + // in Views framework. + EXPECT_EQ(window->GetBackgroundColor(), 0u); +} + +void WindowCreateTranslucentImpl(CefRefPtr event) { + auto config = std::make_unique(); + config->on_window_created = base::BindOnce(VerifyWindowTransparentBackground); + TestWindowDelegate::RunTest(event, std::move(config)); +} + } // namespace // Test window functionality. This is primarily to exercise exposed CEF APIs @@ -591,6 +604,7 @@ WINDOW_TEST_ASYNC(WindowFullscreenFrameless) WINDOW_TEST_ASYNC(WindowIcon) WINDOW_TEST_ASYNC(WindowIconFrameless) WINDOW_TEST_ASYNC(WindowAccelerator) +WINDOW_TEST_ASYNC(WindowCreateTranslucent) namespace {