commit b49c6ab85ff5ec5d6fd49b8aa6c5643edec554e0
parent bb70a75a721c6e6ed662c190f7ecf408a5e418b7
Author: Emilio Cobos Álvarez <emilio@crisal.io>
Date: Tue, 23 Dec 2025 19:08:08 +0000
Bug 2007558 - Make transparent attribute work dynamically. r=Gijs
Differential Revision: https://phabricator.services.mozilla.com/D277444
Diffstat:
8 files changed, 75 insertions(+), 8 deletions(-)
diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp
@@ -3653,6 +3653,13 @@ mozilla::ipc::IPCResult BrowserChild::RecvUIResolutionChanged(
return IPC_OK();
}
+mozilla::ipc::IPCResult BrowserChild::RecvTransparencyChanged(
+ const bool& aIsTransparent) {
+ mIsTransparent = aIsTransparent;
+ SchedulePaint();
+ return IPC_OK();
+}
+
mozilla::ipc::IPCResult BrowserChild::RecvSafeAreaInsetsChanged(
const mozilla::LayoutDeviceIntMargin& aSafeAreaInsets) {
mPuppetWidget->UpdateSafeAreaInsets(aSafeAreaInsets);
diff --git a/dom/ipc/BrowserChild.h b/dom/ipc/BrowserChild.h
@@ -525,6 +525,8 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
const int32_t& aRounding,
const double& aScale);
+ mozilla::ipc::IPCResult RecvTransparencyChanged(const bool& aIsTransparent);
+
mozilla::ipc::IPCResult RecvHandleAccessKey(const WidgetKeyboardEvent& aEvent,
nsTArray<uint32_t>&& aCharCodes);
MOZ_CAN_RUN_SCRIPT_BOUNDARY
diff --git a/dom/ipc/BrowserParent.cpp b/dom/ipc/BrowserParent.cpp
@@ -572,19 +572,18 @@ BrowserBridgeParent* BrowserParent::GetBrowserBridgeParent() const {
BrowserHost* BrowserParent::GetBrowserHost() const { return mBrowserHost; }
+bool BrowserParent::IsTransparent() const {
+ return mFrameElement && mFrameElement->HasAttr(nsGkAtoms::transparent) &&
+ nsContentUtils::IsChromeDoc(mFrameElement->OwnerDoc());
+}
+
ParentShowInfo BrowserParent::GetShowInfo() {
TryCacheDPIAndScale();
+ nsAutoString name;
if (mFrameElement) {
- nsAutoString name;
mFrameElement->GetAttr(nsGkAtoms::name, name);
- bool isTransparent =
- nsContentUtils::IsChromeDoc(mFrameElement->OwnerDoc()) &&
- mFrameElement->HasAttr(nsGkAtoms::transparent);
- return ParentShowInfo(name, false, isTransparent, mDPI, mRounding,
- mDefaultScale.scale);
}
-
- return ParentShowInfo(u""_ns, false, false, mDPI, mRounding,
+ return ParentShowInfo(name, false, IsTransparent(), mDPI, mRounding,
mDefaultScale.scale);
}
@@ -3717,6 +3716,12 @@ void BrowserParent::NotifyResolutionChanged() {
mDPI < 0 ? -1.0 : mDefaultScale.scale);
}
+void BrowserParent::NotifyTransparencyChanged() {
+ if (!mIsDestroyed) {
+ (void)SendTransparencyChanged(IsTransparent());
+ }
+}
+
bool BrowserParent::CanCancelContentJS(
nsIRemoteTab::NavigationType aNavigationType, int32_t aNavigationIndex,
nsIURI* aNavigationURI) const {
diff --git a/dom/ipc/BrowserParent.h b/dom/ipc/BrowserParent.h
@@ -204,6 +204,9 @@ class BrowserParent final : public PBrowserParent,
*/
bool CreatingWindow() const { return mCreatingWindow; }
+ // Whether our embedder can render transparent.
+ bool IsTransparent() const;
+
/*
* Visit each BrowserParent in the tree formed by PBrowser and
* PBrowserBridge, including `this`.
@@ -707,6 +710,7 @@ class BrowserParent final : public PBrowserParent,
void SetPriorityHint(bool aPriorityHint);
void PreserveLayers(bool aPreserveLayers);
void NotifyResolutionChanged();
+ void NotifyTransparencyChanged();
bool CanCancelContentJS(nsIRemoteTab::NavigationType aNavigationType,
int32_t aNavigationIndex,
diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl
@@ -939,6 +939,12 @@ child:
async UIResolutionChanged(float dpi, int32_t rounding, double scale);
/**
+ * Tell the child that whether it's allowed to render transparent has
+ * changed. See also ParentShowInfo::isTransparent.
+ */
+ async TransparencyChanged(bool transparent);
+
+ /**
* Tell the child that the safe area of widget has changed.
*
*/
diff --git a/dom/ipc/tests/browser.toml b/dom/ipc/tests/browser.toml
@@ -83,6 +83,8 @@ skip-if = [
["browser_subframesPreferUsed.js"]
+["browser_transparent.js"]
+
["browser_very_fission.js"]
support-files = ["file_dummy.html"]
run-if = [
diff --git a/dom/ipc/tests/browser_transparent.js b/dom/ipc/tests/browser_transparent.js
@@ -0,0 +1,35 @@
+/* Any copyright is dedicated to the Public Domain.
+ https://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+function getContentCanvasBg(browser) {
+ return SpecialPowers.spawn(browser, [], () => {
+ return content.windowUtils.canvasBackgroundColor;
+ });
+}
+
+add_task(async function test_transparent_dynamic() {
+ await BrowserTestUtils.withNewTab(
+ `data:text/html,hello`,
+ async function (browser) {
+ is(
+ await getContentCanvasBg(browser),
+ "rgb(255, 255, 255)",
+ "Content bg should be white"
+ );
+ browser.toggleAttribute("transparent", true);
+ is(
+ await getContentCanvasBg(browser),
+ "rgba(0, 0, 0, 0)",
+ "Content bg should be transparent"
+ );
+ browser.toggleAttribute("transparent", false);
+ is(
+ await getContentCanvasBg(browser),
+ "rgb(255, 255, 255)",
+ "Content bg should be white again"
+ );
+ }
+ );
+});
diff --git a/dom/xul/XULFrameElement.cpp b/dom/xul/XULFrameElement.cpp
@@ -7,6 +7,7 @@
#include "mozilla/dom/XULFrameElement.h"
#include "mozilla/AsyncEventDispatcher.h"
+#include "mozilla/dom/BrowserParent.h"
#include "mozilla/dom/HTMLIFrameElement.h"
#include "mozilla/dom/WindowProxyHolder.h"
#include "mozilla/dom/XULFrameElementBinding.h"
@@ -191,6 +192,11 @@ void XULFrameElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
if (auto* bc = mFrameLoader->GetExtantBrowsingContext()) {
MOZ_ALWAYS_SUCCEEDS(bc->SetFullscreenAllowedByOwner(!aValue));
}
+ } else if (aName == nsGkAtoms::transparent && mFrameLoader &&
+ (!!aValue != !!aOldValue)) {
+ if (auto* bp = mFrameLoader->GetBrowserParent()) {
+ bp->NotifyTransparencyChanged();
+ }
}
}