diff --git a/devtools/client/fronts/walker.js b/devtools/client/fronts/walker.js index 6d364f07a131..0cd063bd6426 100644 --- a/devtools/client/fronts/walker.js +++ b/devtools/client/fronts/walker.js @@ -61,6 +61,9 @@ class WalkerFront extends FrontClassWithSpec(walkerSpec) { // calling watchRootNode, so we keep this assignment as a fallback. this.rootNode = types.getType("domnode").read(json.root, this); + // Bug 1861328: boolean set to true when color scheme can't be changed (happens when `privacy.resistFingerprinting` is set to true) + this.rfpCSSColorScheme = json.rfpCSSColorScheme; + this.traits = json.traits; } diff --git a/devtools/client/inspector/rules/rules.js b/devtools/client/inspector/rules/rules.js index 3743fd57ef86..a72f95062974 100644 --- a/devtools/client/inspector/rules/rules.js +++ b/devtools/client/inspector/rules/rules.js @@ -592,6 +592,12 @@ CssRuleView.prototype = { "click", this._onToggleDarkColorSchemeSimulation ); + const { rfpCSSColorScheme } = this.inspector.walker; + if (rfpCSSColorScheme) { + this.colorSchemeLightSimulationButton.setAttribute("disabled", true); + this.colorSchemeDarkSimulationButton.setAttribute("disabled", true); + console.warn("Color scheme simulation is disabled in RFP mode."); + } }, /** diff --git a/devtools/client/inspector/rules/test/browser_part1.toml b/devtools/client/inspector/rules/test/browser_part1.toml index 2b21832e3cb9..ff1a09e6daae 100644 --- a/devtools/client/inspector/rules/test/browser_part1.toml +++ b/devtools/client/inspector/rules/test/browser_part1.toml @@ -114,6 +114,8 @@ skip-if = ["os == 'win' && !debug"] # Bug 1703465 ["browser_rules_color_scheme_simulation_rdm.js"] +["browser_rules_color_scheme_simulation_rfp.js"] + ["browser_rules_colorpicker-and-image-tooltip_01.js"] ["browser_rules_colorpicker-and-image-tooltip_02.js"] diff --git a/devtools/client/inspector/rules/test/browser_rules_color_scheme_simulation_rfp.js b/devtools/client/inspector/rules/test/browser_rules_color_scheme_simulation_rfp.js new file mode 100644 index 000000000000..b05e46906c8e --- /dev/null +++ b/devtools/client/inspector/rules/test/browser_rules_color_scheme_simulation_rfp.js @@ -0,0 +1,47 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test color scheme simulation buttons' state with RFPTarget::CSSPrefersColorScheme enabled +const TEST_URI = URL_ROOT_SSL + "doc_media_queries.html"; + +async function runTest(enabled) { + const sign = enabled ? "+" : "-"; + await SpecialPowers.pushPrefEnv({ + set: [ + ["privacy.fingerprintingProtection", true], + [ + "privacy.fingerprintingProtection.overrides", + `${sign}CSSPrefersColorScheme`, + ], + ], + }); + + await addTab(TEST_URI); + const { inspector } = await openRuleView(); + + info("Check that the color scheme simulation buttons exist"); + const lightButton = inspector.panelDoc.querySelector( + "#color-scheme-simulation-light-toggle" + ); + const darkButton = inspector.panelDoc.querySelector( + "#color-scheme-simulation-dark-toggle" + ); + ok(lightButton, "The light color scheme simulation button exists"); + ok(darkButton, "The dark color scheme simulation button exists"); + + const expectedState = enabled ? "disabled" : "enabled"; + is(lightButton.disabled, enabled, `Light button is ${expectedState}`); + is(darkButton.disabled, enabled, `Dark button is ${expectedState}`); + + await SpecialPowers.popPrefEnv(); +} + +add_task(async function () { + await runTest(true); +}); + +add_task(async function () { + await runTest(false); +}); diff --git a/devtools/server/actors/inspector/walker.js b/devtools/server/actors/inspector/walker.js index c42c0593057c..51440071d2cb 100644 --- a/devtools/server/actors/inspector/walker.js +++ b/devtools/server/actors/inspector/walker.js @@ -339,6 +339,10 @@ class WalkerActor extends Actor { return { actor: this.actorID, root: this.rootNode.form(), + rfpCSSColorScheme: ChromeUtils.shouldResistFingerprinting( + "CSSPrefersColorScheme", + null + ), traits: {}, }; } diff --git a/dom/base/ChromeUtils.cpp b/dom/base/ChromeUtils.cpp index 7f6632cb15d3..c269a3466c8d 100644 --- a/dom/base/ChromeUtils.cpp +++ b/dom/base/ChromeUtils.cpp @@ -2107,6 +2107,9 @@ bool ChromeUtils::ShouldResistFingerprinting( case JSRFPTarget::SiteSpecificZoom: target = RFPTarget::SiteSpecificZoom; break; + case JSRFPTarget::CSSPrefersColorScheme: + target = RFPTarget::CSSPrefersColorScheme; + break; default: MOZ_CRASH("Unhandled JSRFPTarget enum value"); } diff --git a/dom/chrome-webidl/ChromeUtils.webidl b/dom/chrome-webidl/ChromeUtils.webidl index 557ed8cd03db..96ab64bbb0eb 100644 --- a/dom/chrome-webidl/ChromeUtils.webidl +++ b/dom/chrome-webidl/ChromeUtils.webidl @@ -1119,6 +1119,7 @@ enum PopupBlockerState { enum JSRFPTarget { "RoundWindowSize", "SiteSpecificZoom", + "CSSPrefersColorScheme", }; #ifdef XP_UNIX diff --git a/tools/@types/lib.gecko.dom.d.ts b/tools/@types/lib.gecko.dom.d.ts index 75a7b3792ae3..2a3aef627d09 100644 --- a/tools/@types/lib.gecko.dom.d.ts +++ b/tools/@types/lib.gecko.dom.d.ts @@ -25321,7 +25321,7 @@ type ImageOrientation = "flipY" | "from-image" | "none"; type ImportESModuleTargetGlobal = "contextual" | "current" | "devtools" | "shared"; type InspectorPropertyType = "color" | "gradient" | "timing-function"; type IterationCompositeOperation = "accumulate" | "replace"; -type JSRFPTarget = "RoundWindowSize" | "SiteSpecificZoom"; +type JSRFPTarget = "RoundWindowSize" | "SiteSpecificZoom" | "CSSPrefersColorScheme"; type L10nFileSourceHasFileStatus = "missing" | "present" | "unknown"; type LatencyMode = "quality" | "realtime"; type LineAlignSetting = "center" | "end" | "start";