diff --git a/java/tests/junittests/CefBrowserWindowVisibilityTest.java b/java/tests/junittests/CefBrowserWindowVisibilityTest.java new file mode 100644 index 00000000..4a0030d4 --- /dev/null +++ b/java/tests/junittests/CefBrowserWindowVisibilityTest.java @@ -0,0 +1,53 @@ +// Copyright (c) 2026 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. + +package tests.junittests; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.cef.browser.CefBrowser; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +// Regression coverage for native/CefBrowser_N.cpp's N_SetWindowVisibility: +// previously the whole function body was gated on OS_MACOSX, and even there +// only ran when windowed (the IsWindowRenderingDisabled() check was +// backwards for that branch's intent) -- so on every platform, for every +// OSR (windowless) browser, setWindowVisibility() silently did nothing. +// Fixed by routing windowless browsers to CefBrowserHost::WasHidden() +// instead, CEF's own signal to pause/resume rendering and GPU resource +// usage for a browser with no native window. +// +// This is a smoke test (doesn't throw, browser stays usable) rather than a +// direct assertion on paused/resumed rendering state, since that internal +// state isn't observable from the Java side. +@ExtendWith(TestSetupExtension.class) +class CefBrowserWindowVisibilityTest { + private static final String TEST_URL = "http://test.com/window_visibility_test.html"; + + @Test + void setWindowVisibilityOnOsrBrowserDoesNotThrow() { + TestFrame frame = new TestFrame() { + @Override + protected void setupTest() { + addResource(TEST_URL, "Visibility Test", "text/html"); + createBrowser(TEST_URL, true /* useOSR */); + super.setupTest(); + } + + @Override + public void onLoadingStateChange(CefBrowser browser, boolean isLoading, + boolean canGoBack, boolean canGoForward) { + if (isLoading) return; + terminateTest(); + } + }; + + frame.awaitCompletion(); + + CefBrowser browser = frame.browser_; + assertDoesNotThrow(() -> browser.setWindowVisibility(false)); + assertDoesNotThrow(() -> browser.setWindowVisibility(true)); + } +} diff --git a/native/CefBrowser_N.cpp b/native/CefBrowser_N.cpp index 07f22de6..bb14d265 100644 --- a/native/CefBrowser_N.cpp +++ b/native/CefBrowser_N.cpp @@ -1542,12 +1542,21 @@ Java_org_cef_browser_CefBrowser_1N_N_1SetWindowVisibility(JNIEnv* env, jobject obj, jboolean visible) { CefRefPtr browser = JNI_GET_BROWSER_OR_RETURN(env, obj); + CefRefPtr host = browser->GetHost(); -#if defined(OS_MACOSX) - if (!browser->GetHost()->IsWindowRenderingDisabled()) { - util_mac::SetVisibility(browser->GetHost()->GetWindowHandle(), - visible != JNI_FALSE); + // Windowless (OSR) browsers have no native window for the OS-level + // visibility toggle below -- CefBrowserHost::WasHidden() is CEF's own + // signal for this case (used to pause/resume rendering and GPU resource + // usage). Previously this whole function was a no-op for every OSR browser + // on every platform except this one macOS branch, and even that branch had + // the windowless check backwards (skipped exactly when windowless). + if (host->IsWindowRenderingDisabled()) { + host->WasHidden(visible == JNI_FALSE); + return; } + +#if defined(OS_MACOSX) + util_mac::SetVisibility(host->GetWindowHandle(), visible != JNI_FALSE); #endif } JNIEXPORT jdouble JNICALL