From c67d8c9c9ce3181a15db55a8d2458a31db1b4328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 12 Feb 2025 12:14:42 +0000 Subject: [PATCH] Bug 1946764 - Support non-boolean media query prefs via -moz-pref(). r=firefox-style-system-reviewers,desktop-theme-reviewers,settings-reviewers,tabbrowser-reviewers,places-reviewers,sidebar-reviewers,urlbar-reviewers,firefox-ai-ml-reviewers,dao,mconley,dshin,mak Allow querying int and string prefs too via functional syntax: ``` @media -moz-pref("pref-name", ) { ``` No argument means the pref exists and has a non-zero/false/empty value. Unfortunately stylelint is still unhappy with this so we need to keep the annoying comments... Differential Revision: https://phabricator.services.mozilla.com/D237275 --- browser/components/genai/chat.css | 2 +- browser/components/sidebar/sidebar-main.css | 4 +- browser/themes/linux/browser.css | 8 +- browser/themes/osx/browser.css | 4 +- browser/themes/shared/browser-colors.css | 8 +- browser/themes/shared/browser-shared.css | 10 +- .../shared/customizableui/panelUI-shared.css | 2 +- .../shared/identity-block/identity-block.css | 4 +- browser/themes/shared/places/sidebar.css | 2 +- .../themes/shared/preferences/preferences.css | 2 +- .../privatebrowsing/aboutPrivateBrowsing.css | 8 +- browser/themes/shared/sidebar.css | 12 +- .../themes/shared/tabbrowser/content-area.css | 14 +- browser/themes/shared/tabbrowser/tabs.css | 12 +- browser/themes/shared/toolbarbutton-icons.css | 8 +- browser/themes/shared/urlbar-searchbar.css | 12 +- browser/themes/shared/urlbarView.css | 12 +- browser/themes/windows/browser.css | 4 +- layout/mathml/mathml.css | 2 +- layout/reftests/css-parsing/moz-bool-pref.css | 2 +- layout/style/GeckoBindings.cpp | 61 +++++++- layout/style/GeckoBindings.h | 3 +- layout/style/ServoBindings.toml | 1 + layout/style/res/html.css | 2 +- layout/style/res/scrollbars.css | 2 +- layout/style/res/ua.css | 4 +- layout/style/res/viewsource.css | 4 +- .../test_chrome_only_media_queries.html | 34 ++++- .../components/style/gecko/media_features.rs | 17 +-- servo/components/style/queries/condition.rs | 138 ++++++++++++++++-- servo/components/style/queries/feature.rs | 2 - .../style/queries/feature_expression.rs | 12 +- servo/ports/geckolib/cbindgen.toml | 1 + toolkit/themes/shared/aboutNetError.css | 2 +- 34 files changed, 293 insertions(+), 122 deletions(-) diff --git a/browser/components/genai/chat.css b/browser/components/genai/chat.css index 1ec5c3fb95ba..804f28fc85e0 100644 --- a/browser/components/genai/chat.css +++ b/browser/components/genai/chat.css @@ -66,7 +66,7 @@ body { z-index: 1; /* stylelint-disable-next-line media-query-no-invalid */ - @media not (-moz-bool-pref: "sidebar.revamp") { + @media not -moz-pref("sidebar.revamp") { display: none; } } diff --git a/browser/components/sidebar/sidebar-main.css b/browser/components/sidebar/sidebar-main.css index e00b8459f458..68f4bb827f2c 100644 --- a/browser/components/sidebar/sidebar-main.css +++ b/browser/components/sidebar/sidebar-main.css @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "sidebar.verticalTabs") { +@media -moz-pref("sidebar.verticalTabs") { :host { --button-size-icon: var(--tab-min-height); --button-min-height: var(--button-size-icon); @@ -24,7 +24,7 @@ padding-inline: 0; /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "sidebar.verticalTabs") { + @media -moz-pref("sidebar.verticalTabs") { :host([expanded]) & { /* TODO: Should this be some other pixel value between 5/6? Need to be careful of Linux where font size is larger */ --tab-pinned-horizontal-count: 5; diff --git a/browser/themes/linux/browser.css b/browser/themes/linux/browser.css index dc95772553ef..5c9891e5ed4b 100644 --- a/browser/themes/linux/browser.css +++ b/browser/themes/linux/browser.css @@ -49,7 +49,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "widget.gtk.rounded-bottom-corners.enabled") { + @media -moz-pref("widget.gtk.rounded-bottom-corners.enabled") { #navigator-toolbox { /* The body clip below covers this. */ border-radius: 0; @@ -101,7 +101,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "browser.urlbar.experimental.expandTextOnFocus") { +@media -moz-pref("browser.urlbar.experimental.expandTextOnFocus") { #urlbar[breakout-extend] { font-size: 1.14em; } @@ -116,7 +116,7 @@ /* Content area */ /* stylelint-disable-next-line media-query-no-invalid */ -@media not (-moz-bool-pref: "sidebar.revamp") { +@media not -moz-pref("sidebar.revamp") { .sidebar-splitter { appearance: none; width: 6px; @@ -205,7 +205,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "widget.gtk.non-native-titlebar-buttons.enabled") { + @media -moz-pref("widget.gtk.non-native-titlebar-buttons.enabled") { /* When using lightweight themes, use our own buttons since native ones might * assume a native background in order to be visible. */ :root[lwtheme] & { diff --git a/browser/themes/osx/browser.css b/browser/themes/osx/browser.css index bf935d624b33..7fc76bc82bd5 100644 --- a/browser/themes/osx/browser.css +++ b/browser/themes/osx/browser.css @@ -9,7 +9,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "browser.theme.native-theme") { +@media -moz-pref("browser.theme.native-theme") { @media not (prefers-contrast) { :root:not([lwtheme]) { @media (prefers-color-scheme: light) { @@ -125,7 +125,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "browser.urlbar.experimental.expandTextOnFocus") { +@media -moz-pref("browser.urlbar.experimental.expandTextOnFocus") { #urlbar[breakout-extend] { font-size: 1.36em; } diff --git a/browser/themes/shared/browser-colors.css b/browser/themes/shared/browser-colors.css index 717795495b3a..bd8459080e33 100644 --- a/browser/themes/shared/browser-colors.css +++ b/browser/themes/shared/browser-colors.css @@ -41,7 +41,7 @@ --chrome-content-separator-color: light-dark(rgba(0,0,0,.3), rgba(255,255,255,.3)); /* stylelint-disable-next-line media-query-no-invalid */ - @media not (-moz-bool-pref: "sidebar.revamp") { + @media not -moz-pref("sidebar.revamp") { &:not([lwtheme]) { --chrome-content-separator-color: ThreeDShadow; } @@ -77,7 +77,7 @@ * transparencies in order to look more native. */ /* stylelint-disable-next-line media-query-no-invalid */ -@media not ((prefers-contrast) or (-moz-bool-pref: "browser.theme.native-theme")) { +@media not ((prefers-contrast) or -moz-pref("browser.theme.native-theme")) { :root:not([lwtheme]) { --color-accent-primary: light-dark(rgb(0, 97, 224), rgb(0, 221, 255)); --button-text-color-primary: light-dark(rgb(251, 251, 254), rgb(43, 42, 51)); @@ -107,7 +107,7 @@ --tabs-navbar-separator-style: none; /* stylelint-disable-next-line media-query-no-invalid */ - @media not ((-moz-windows-mica) or ((-moz-windows-accent-color-in-titlebar) and (-moz-bool-pref: "browser.theme.windows.accent-color-in-tabs.enabled"))) { + @media not ((-moz-windows-mica) or ((-moz-windows-accent-color-in-titlebar) and -moz-pref("browser.theme.windows.accent-color-in-tabs.enabled"))) { --toolbox-bgcolor: light-dark(rgb(240, 240, 244), rgb(28, 27, 34)); --toolbox-textcolor: light-dark(rgb(21, 20, 26), rgb(251, 251, 254)); --toolbox-bgcolor-inactive: var(--toolbox-bgcolor); @@ -143,7 +143,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ - @media not (-moz-bool-pref: "sidebar.revamp") { + @media not -moz-pref("sidebar.revamp") { --chrome-content-separator-color: light-dark(rgb(204, 204, 204), hsl(240, 5%, 5%)); } diff --git a/browser/themes/shared/browser-shared.css b/browser/themes/shared/browser-shared.css index d697e936198f..e9a452be0133 100644 --- a/browser/themes/shared/browser-shared.css +++ b/browser/themes/shared/browser-shared.css @@ -52,7 +52,7 @@ body { min-height: 120px; /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "sidebar.verticalTabs") { + @media -moz-pref("sidebar.verticalTabs") { min-width: 732px; @media (-moz-platform: macos) { @@ -192,7 +192,7 @@ body { } /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-platform: macos) and (-moz-bool-pref: "browser.theme.native-theme") { + @media (-moz-platform: macos) and -moz-pref("browser.theme.native-theme") { /* Don't make the toolbox vibrant when in full-screen. macOS fullscreen has a * native titlebar outside of the window (revealed on hover) anyways. */ :root[customtitlebar]:not([lwtheme], [macOSNativeFullscreen]) & { @@ -222,7 +222,7 @@ body { color: inherit; /* stylelint-disable-next-line media-query-no-invalid */ - @media not (-moz-bool-pref: "sidebar.verticalTabs") { + @media not -moz-pref("sidebar.verticalTabs") { &:not(.browser-titlebar) { background-color: var(--toolbar-bgcolor); color: var(--toolbar-color); @@ -305,7 +305,7 @@ body { } /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "sidebar.verticalTabs") { + @media -moz-pref("sidebar.verticalTabs") { &[type="pre-tabs"], &[type="post-tabs"] { display: none; } @@ -415,7 +415,7 @@ body { } /* stylelint-disable-next-line media-query-no-invalid */ -@media not (-moz-bool-pref: "sidebar.verticalTabs") { +@media not -moz-pref("sidebar.verticalTabs") { #vertical-spacer { display: none; } diff --git a/browser/themes/shared/customizableui/panelUI-shared.css b/browser/themes/shared/customizableui/panelUI-shared.css index cf82e05042e0..a61bc7369c91 100644 --- a/browser/themes/shared/customizableui/panelUI-shared.css +++ b/browser/themes/shared/customizableui/panelUI-shared.css @@ -909,7 +909,7 @@ toolbarbutton[constrain-size="true"][cui-areatype="panel"] > .toolbarbutton-badg } /* stylelint-disable-next-line media-query-no-invalid */ - @media not (-moz-bool-pref: "identity.fxaccounts.toolbar.defaultVisible") { + @media not -moz-pref("identity.fxaccounts.toolbar.defaultVisible") { /* Hide the FxA toolbar button when its in the nav-bar, until in use */ &[fxastatus="not_configured"] #widget-overflow-list > #fxa-toolbar-menu-button, &[fxastatus="not_configured"] #nav-bar-customization-target > #fxa-toolbar-menu-button { diff --git a/browser/themes/shared/identity-block/identity-block.css b/browser/themes/shared/identity-block/identity-block.css index 13b1659ed5a3..fab73b174f53 100644 --- a/browser/themes/shared/identity-block/identity-block.css +++ b/browser/themes/shared/identity-block/identity-block.css @@ -30,7 +30,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "browser.urlbar.searchModeSwitcher.featureGate") or (-moz-bool-pref: "browser.urlbar.scotchBonnet.enableOverride") { +@media -moz-pref("browser.urlbar.searchModeSwitcher.featureGate") or -moz-pref("browser.urlbar.scotchBonnet.enableOverride") { #identity-box[pageproxystate="invalid"] { display: none; } @@ -74,7 +74,7 @@ #urlbar-label-box { margin-inline-end: 8px; /* stylelint-disable-next-line media-query-no-invalid */ - @media ((-moz-bool-pref: "browser.urlbar.searchModeSwitcher.featureGate") or (-moz-bool-pref: "browser.urlbar.scotchBonnet.enableOverride")) { + @media (-moz-pref("browser.urlbar.searchModeSwitcher.featureGate") or -moz-pref("browser.urlbar.scotchBonnet.enableOverride")) { margin-inline-end: var(--urlbar-searchmodeswitcher-margin-inline-end); } } diff --git a/browser/themes/shared/places/sidebar.css b/browser/themes/shared/places/sidebar.css index e280643e2ef3..34a198286110 100644 --- a/browser/themes/shared/places/sidebar.css +++ b/browser/themes/shared/places/sidebar.css @@ -19,7 +19,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ - @media not (-moz-bool-pref: "sidebar.revamp") { + @media not -moz-pref("sidebar.revamp") { display: none; } } diff --git a/browser/themes/shared/preferences/preferences.css b/browser/themes/shared/preferences/preferences.css index b6025878661d..efa5d4d85272 100644 --- a/browser/themes/shared/preferences/preferences.css +++ b/browser/themes/shared/preferences/preferences.css @@ -257,7 +257,7 @@ radio { } /* stylelint-disable-next-line media-query-no-invalid */ -@media not (-moz-bool-pref: "browser.migrate.preferences-entrypoint.enabled") { +@media not -moz-pref("browser.migrate.preferences-entrypoint.enabled") { #dataMigrationGroup { display: none; } diff --git a/browser/themes/shared/privatebrowsing/aboutPrivateBrowsing.css b/browser/themes/shared/privatebrowsing/aboutPrivateBrowsing.css index a8d153a95c5f..f8b3e2039e74 100644 --- a/browser/themes/shared/privatebrowsing/aboutPrivateBrowsing.css +++ b/browser/themes/shared/privatebrowsing/aboutPrivateBrowsing.css @@ -89,7 +89,7 @@ p { } /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "browser.privatebrowsing.felt-privacy-v1") { +@media -moz-pref("browser.privatebrowsing.felt-privacy-v1") { .search-inner-wrapper { height: 52px; padding: 0; @@ -251,7 +251,7 @@ p { } /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "browser.privatebrowsing.felt-privacy-v1") { +@media -moz-pref("browser.privatebrowsing.felt-privacy-v1") { .search-handoff-button, .search-handoff-button:hover:not(.focused), .search-handoff-button:active, @@ -384,7 +384,7 @@ p { } /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "browser.privatebrowsing.felt-privacy-v1") { +@media -moz-pref("browser.privatebrowsing.felt-privacy-v1") { .info-border { border-radius: 8px; margin-top: 64px; @@ -605,7 +605,7 @@ p { } /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "browser.privatebrowsing.felt-privacy-v1") { +@media -moz-pref("browser.privatebrowsing.felt-privacy-v1") { .promo.below-search.promo-visible { margin-block: 0 25px; diff --git a/browser/themes/shared/sidebar.css b/browser/themes/shared/sidebar.css index 694d3210dbab..4e5986b1b9c2 100644 --- a/browser/themes/shared/sidebar.css +++ b/browser/themes/shared/sidebar.css @@ -15,7 +15,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "sidebar.revamp") { + @media -moz-pref("sidebar.revamp") { min-width: 200px; width: 340px; padding-block-end: var(--space-small); @@ -40,7 +40,7 @@ max-width: 75vw; /* stylelint-disable-next-line media-query-no-invalid */ - @media not (-moz-bool-pref: "sidebar.revamp") { + @media not -moz-pref("sidebar.revamp") { background-color: var(--sidebar-background-color); color: var(--sidebar-text-color); /* Note that with sidebar.revamp we apply the --sidebar-background-color to the @@ -65,7 +65,7 @@ flex: 1; /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "sidebar.revamp") { + @media -moz-pref("sidebar.revamp") { border-radius: var(--border-radius-medium); box-shadow: var(--content-area-shadow); border: 0.5px solid var(--sidebar-border-color); @@ -81,7 +81,7 @@ z-index: var(--browser-area-z-index-sidebar-splitter); /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "sidebar.revamp") or (not (-moz-platform: linux)) { + @media -moz-pref("sidebar.revamp") or (not (-moz-platform: linux)) { /* We don't let the splitter overlap the sidebar on Linux since the sidebar's scrollbar is too narrow on Linux. */ appearance: none; @@ -102,7 +102,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "sidebar.revamp") { + @media -moz-pref("sidebar.revamp") { --splitter-width: 4px; transition: background-color 0.5s ease-in-out; border-style: none; @@ -116,7 +116,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ - @media not (-moz-bool-pref: "sidebar.verticalTabs") { + @media not -moz-pref("sidebar.verticalTabs") { &#sidebar-launcher-splitter { display: none; } diff --git a/browser/themes/shared/tabbrowser/content-area.css b/browser/themes/shared/tabbrowser/content-area.css index 68e57cf187a2..1a2864f8e903 100644 --- a/browser/themes/shared/tabbrowser/content-area.css +++ b/browser/themes/shared/tabbrowser/content-area.css @@ -19,7 +19,7 @@ --tabpanel-background-color: #25003e !important; /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "browser.privatebrowsing.felt-privacy-v1") { + @media -moz-pref("browser.privatebrowsing.felt-privacy-v1") { --tabpanel-background-color: linear-gradient(45deg, #722291 0%, #45278D 50%, #393473 100%) !important; } } @@ -29,13 +29,13 @@ border-bottom: 0.01px solid var(--chrome-content-separator-color); /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "sidebar.revamp") { + @media -moz-pref("sidebar.revamp") { /* This reserves space for the content area outline */ border-bottom-color: var(--toolbar-bgcolor); } /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "sidebar.verticalTabs") { + @media -moz-pref("sidebar.verticalTabs") { border-bottom-style: none; } } @@ -72,18 +72,18 @@ margin: 0; /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "sidebar.revamp") { + @media -moz-pref("sidebar.revamp") { outline: 0.01px solid var(--chrome-content-separator-color); box-shadow: var(--content-area-shadow); /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "sidebar.revamp.round-content-area") { + @media -moz-pref("sidebar.revamp.round-content-area") { :root:not([inDOMFullscreen]) &[sidebar-shown] { overflow: clip; border-start-end-radius: var(--border-radius-medium); /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "sidebar.position_start") { + @media -moz-pref("sidebar.position_start") { border-start-start-radius: var(--border-radius-medium); border-start-end-radius: 0; } @@ -192,7 +192,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "browser.tabs.hideStatusPanel") { + @media -moz-pref("browser.tabs.hideStatusPanel") { visibility: hidden; } } diff --git a/browser/themes/shared/tabbrowser/tabs.css b/browser/themes/shared/tabbrowser/tabs.css index f47fdf95edaa..f02a1e6c945e 100644 --- a/browser/themes/shared/tabbrowser/tabs.css +++ b/browser/themes/shared/tabbrowser/tabs.css @@ -109,7 +109,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "sidebar.verticalTabs") { +@media -moz-pref("sidebar.verticalTabs") { :root { --tab-min-height: max(32px, calc(var(--tab-label-line-height) * 1em)); --tab-block-margin: 2px; @@ -444,7 +444,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "browser.tabs.fadeOutUnloadedTabs") { + @media -moz-pref("browser.tabs.fadeOutUnloadedTabs") { &[pending] { opacity: 0.5; /* Fade the favicon out */ @@ -793,7 +793,7 @@ /* Tab Groups */ /* stylelint-disable-next-line media-query-no-invalid */ -@media not (-moz-bool-pref: "sidebar.verticalTabs") { +@media not -moz-pref("sidebar.verticalTabs") { /* * .tab-group-line needs to span the drop shadows + space between tabs in the * same tab group so that the whole tab group appears to be underlined by an @@ -845,7 +845,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "sidebar.verticalTabs") { +@media -moz-pref("sidebar.verticalTabs") { tab-group { flex-direction: column; position: relative; @@ -883,7 +883,7 @@ transition: var(--tab-dragover-transition); /* stylelint-disable-next-line media-query-no-invalid */ - @media not (-moz-bool-pref: "sidebar.verticalTabs") { + @media not -moz-pref("sidebar.verticalTabs") { position: relative; /* @@ -1405,7 +1405,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "sidebar.expandOnHover") { + @media -moz-pref("sidebar.expandOnHover") { /* Tab close button when the sidebar is collapsed should not be shown when expand on hover is enabled because once you hover over the launcher to use the button, the launcher diff --git a/browser/themes/shared/toolbarbutton-icons.css b/browser/themes/shared/toolbarbutton-icons.css index bc37f47980a8..96fe41f71b18 100644 --- a/browser/themes/shared/toolbarbutton-icons.css +++ b/browser/themes/shared/toolbarbutton-icons.css @@ -190,7 +190,7 @@ #sidebar-button { /* stylelint-disable-next-line media-query-no-invalid */ - @media not (-moz-bool-pref: "sidebar.revamp") { + @media not -moz-pref("sidebar.revamp") { list-style-image: url("chrome://browser/skin/sidebars-right.svg"); &:-moz-locale-dir(ltr):not([positionend]), @@ -200,11 +200,11 @@ } /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "sidebar.revamp") { + @media -moz-pref("sidebar.revamp") { list-style-image: url("chrome://browser/skin/sidebar-collapsed-right.svg"); /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "sidebar.verticalTabs") { + @media -moz-pref("sidebar.verticalTabs") { &:hover { list-style-image: url("chrome://browser/skin/sidebar-expanded-right.svg"); } @@ -223,7 +223,7 @@ list-style-image: url("chrome://browser/skin/sidebar-collapsed.svg"); /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "sidebar.verticalTabs") { + @media -moz-pref("sidebar.verticalTabs") { &:hover { list-style-image: url("chrome://browser/skin/sidebar-expanded.svg"); } diff --git a/browser/themes/shared/urlbar-searchbar.css b/browser/themes/shared/urlbar-searchbar.css index 574f83af7fa4..5724e22b02de 100644 --- a/browser/themes/shared/urlbar-searchbar.css +++ b/browser/themes/shared/urlbar-searchbar.css @@ -29,7 +29,7 @@ /* When rich suggestions are enabled the urlbar identity icon is given extra padding to * align the results and urlbar text */ /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "browser.urlbar.richSuggestions.featureGate") { +@media -moz-pref("browser.urlbar.richSuggestions.featureGate") { #identity-box[pageproxystate="invalid"] > .identity-box-button { padding-inline: calc(6px + var(--urlbar-icon-padding)); } @@ -1146,8 +1146,8 @@ moz-input-box > menupopup .context-menu-add-engine > .menu-iconic-left::after { } /* stylelint-disable media-query-no-invalid */ - @media (not (-moz-bool-pref: "browser.urlbar.searchModeSwitcher.featureGate")) and - (not (-moz-bool-pref: "browser.urlbar.scotchBonnet.enableOverride")) { + @media (not -moz-pref("browser.urlbar.searchModeSwitcher.featureGate")) and + (not -moz-pref("browser.urlbar.scotchBonnet.enableOverride")) { display: none; } /* stylelint-enable media-query-no-invalid */ @@ -1172,7 +1172,7 @@ moz-input-box > menupopup .context-menu-add-engine > .menu-iconic-left::after { display: none; /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "browser.urlbar.searchModeSwitcher.featureGate") or (-moz-bool-pref: "browser.urlbar.scotchBonnet.enableOverride") { + @media -moz-pref("browser.urlbar.searchModeSwitcher.featureGate") or -moz-pref("browser.urlbar.scotchBonnet.enableOverride") { #urlbar[searchmode] & { display: inline-flex; } @@ -1232,13 +1232,13 @@ moz-input-box > menupopup .context-menu-add-engine > .menu-iconic-left::after { } /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "browser.urlbar.searchModeSwitcher.featureGate") or (-moz-bool-pref: "browser.urlbar.scotchBonnet.enableOverride") { +@media -moz-pref("browser.urlbar.searchModeSwitcher.featureGate") or -moz-pref("browser.urlbar.scotchBonnet.enableOverride") { #urlbar[searchmode] > .urlbar-input-container > #urlbar-search-mode-indicator { display: none; } /* stylelint-disable-next-line media-query-no-invalid */ - @media not (-moz-bool-pref: "browser.urlbar.unifiedSearchButton.always") { + @media not -moz-pref("browser.urlbar.unifiedSearchButton.always") { #urlbar-searchmode-switcher { background-color: var(--urlbar-box-bgcolor); #urlbar:not([unifiedsearchbutton-available]) > .urlbar-input-container > & { diff --git a/browser/themes/shared/urlbarView.css b/browser/themes/shared/urlbarView.css index 1c654e053ca8..6ca9bcc38db5 100644 --- a/browser/themes/shared/urlbarView.css +++ b/browser/themes/shared/urlbarView.css @@ -72,7 +72,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "browser.urlbar.richSuggestions.featureGate") { + @media -moz-pref("browser.urlbar.richSuggestions.featureGate") { --urlbarView-favicon-margin-start: calc((var(--urlbarView-rich-suggestion-default-icon-size) - var(--urlbarView-favicon-width)) / 2); --urlbarView-favicon-margin-end: calc(var(--urlbar-icon-padding) + var(--identity-box-margin-inline) + ((var(--urlbarView-rich-suggestion-default-icon-size) - var(--urlbarView-favicon-width)) / 2)); } @@ -120,7 +120,7 @@ /* Align icons that are smaller than the default rich suggestion icon size (28px) with default-size rich suggestion icons. */ /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "browser.urlbar.richSuggestions.featureGate") { + @media -moz-pref("browser.urlbar.richSuggestions.featureGate") { &:not([rich-suggestion]), &[rich-suggestion][icon-size="16"] { --urlbarView-icon-margin-start: var(--urlbarView-favicon-margin-start); @@ -672,7 +672,7 @@ font-size: var(--urlbarView-small-font-size); /* stylelint-disable-next-line media-query-no-invalid */ - @media not (-moz-bool-pref: "browser.urlbar.scotchBonnet.enableOverride") { + @media not -moz-pref("browser.urlbar.scotchBonnet.enableOverride") { /* This targets both rich and non-rich results, so not using the child selector here. */ .urlbarView-row:not(:hover, [selected], [sponsored]) & { color: var(--urlbarView-action-color); @@ -739,7 +739,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ - @media not (-moz-bool-pref: "browser.urlbar.scotchBonnet.enableOverride") { + @media not -moz-pref("browser.urlbar.scotchBonnet.enableOverride") { color: var(--urlbar-box-text-color); background-color: var(--urlbar-box-focus-bgcolor); @@ -749,7 +749,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "browser.urlbar.scotchBonnet.enableOverride") { + @media -moz-pref("browser.urlbar.scotchBonnet.enableOverride") { -moz-context-properties: fill, fill-opacity; padding-inline-start: calc(var(--urlbarView-favicon-width) + 8px); background-image: url("chrome://browser/content/firefoxview/view-opentabs.svg"); @@ -770,7 +770,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ - @media not (-moz-bool-pref: "browser.urlbar.scotchBonnet.enableOverride") { + @media not -moz-pref("browser.urlbar.scotchBonnet.enableOverride") { &:is([selected], :hover) > .urlbarView-row-inner > .urlbarView-no-wrap > .urlbarView-action { color: var(--urlbarView-result-button-selected-color); background-color: var(--urlbarView-result-button-selected-background-color); diff --git a/browser/themes/windows/browser.css b/browser/themes/windows/browser.css index f49604e53780..9af78803f000 100644 --- a/browser/themes/windows/browser.css +++ b/browser/themes/windows/browser.css @@ -34,7 +34,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-windows-mica) or (-moz-bool-pref: "browser.theme.windows.accent-color-in-tabs.enabled") { + @media (-moz-windows-mica) or -moz-pref("browser.theme.windows.accent-color-in-tabs.enabled") { &:not([lwtheme]) #TabsToolbar { /* These colors match the Linux/HCM default button colors. We need to * override these on the tabs toolbar because the accent color is @@ -286,7 +286,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "browser.urlbar.experimental.expandTextOnFocus") { +@media -moz-pref("browser.urlbar.experimental.expandTextOnFocus") { #urlbar[breakout-extend] { font-size: 1.25em; } diff --git a/layout/mathml/mathml.css b/layout/mathml/mathml.css index ec0686d879f1..b8dc1f7fadcb 100644 --- a/layout/mathml/mathml.css +++ b/layout/mathml/mathml.css @@ -304,7 +304,7 @@ semantics > :not(:first-child) { } /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "mathml.legacy_mathvariant_attribute.disabled") { +@media -moz-pref("mathml.legacy_mathvariant_attribute.disabled") { /* Implement MathML Core's automatic italic on mi. https://w3c.github.io/mathml-core/#the-mathvariant-attribute */ mi { diff --git a/layout/reftests/css-parsing/moz-bool-pref.css b/layout/reftests/css-parsing/moz-bool-pref.css index 3827bb3f1790..b8d30f537818 100644 --- a/layout/reftests/css-parsing/moz-bool-pref.css +++ b/layout/reftests/css-parsing/moz-bool-pref.css @@ -11,7 +11,7 @@ background: green; } -@media (-moz-bool-pref: "testing.supports.moz-bool-pref") { +@media -moz-pref("testing.supports.moz-bool-pref") { .enabled { background: green; } diff --git a/layout/style/GeckoBindings.cpp b/layout/style/GeckoBindings.cpp index e7b64485cfdb..2e056e91c873 100644 --- a/layout/style/GeckoBindings.cpp +++ b/layout/style/GeckoBindings.cpp @@ -1572,34 +1572,79 @@ const nsTArray* Gecko_ShadowRoot_GetElementsWithId( return aShadowRoot->GetAllElementsForId(aId); } -bool Gecko_ComputeBoolPrefMediaQuery(nsAtom* aPref) { +static StyleComputedMozPrefFeatureValue GetPrefValue(const nsCString& aPref) { + using Value = StyleComputedMozPrefFeatureValue; + switch (Preferences::GetType(aPref.get())) { + case nsIPrefBranch::PREF_STRING: { + nsAutoString value; + Preferences::GetString(aPref.get(), value); + return Value::String(StyleAtomString{NS_Atomize(value)}); + } + case nsIPrefBranch::PREF_INT: + return Value::Integer(Preferences::GetInt(aPref.get(), 0)); + case nsIPrefBranch::PREF_BOOL: { + auto value = Preferences::GetBool(aPref.get(), false) + ? StyleBoolValue::True + : StyleBoolValue::False; + return Value::Boolean(value); + } + case nsIPrefBranch::PREF_INVALID: + default: + break; + } + + return StyleComputedMozPrefFeatureValue::None(); +} + +bool Gecko_EvalMozPrefFeature(nsAtom* aPref, + const StyleComputedMozPrefFeatureValue* aValue) { MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aValue); + using Value = StyleComputedMozPrefFeatureValue; + using PrefMap = nsTHashMap, Value>; // This map leaks until shutdown, but that's fine, all the values are // controlled by us so it's not expected to be big. - static StaticAutoPtr, bool>> sRegisteredPrefs; + static StaticAutoPtr sRegisteredPrefs; if (!sRegisteredPrefs) { if (PastShutdownPhase(ShutdownPhase::XPCOMShutdownFinal)) { // Styling doesn't really matter much at this point, don't bother. return false; } - sRegisteredPrefs = new nsTHashMap, bool>(); + sRegisteredPrefs = new PrefMap(); ClearOnShutdown(&sRegisteredPrefs); } - return sRegisteredPrefs->LookupOrInsertWith(aPref, [&] { + + const auto& value = sRegisteredPrefs->LookupOrInsertWith(aPref, [&] { nsAutoAtomCString prefName(aPref); Preferences::RegisterCallback( [](const char* aPrefName, void*) { + nsDependentCString name(aPrefName); if (sRegisteredPrefs) { - RefPtr name = NS_Atomize(nsDependentCString(aPrefName)); - sRegisteredPrefs->InsertOrUpdate(name, - Preferences::GetBool(aPrefName)); + RefPtr nameAtom = NS_Atomize(name); + sRegisteredPrefs->InsertOrUpdate(nameAtom, GetPrefValue(name)); } LookAndFeel::NotifyChangedAllWindows( widget::ThemeChangeKind::MediaQueriesOnly); }, prefName); - return Preferences::GetBool(prefName.get()); + return GetPrefValue(prefName); }); + if (aValue->IsNone()) { + // For a non-specified query, we return true if the pref is not false, zero, + // empty or invalid + switch (value.tag) { + case Value::Tag::None: + return false; + case Value::Tag::Boolean: + return value.AsBoolean() == StyleBoolValue::True; + case Value::Tag::Integer: + return value.AsInteger() != 0; + case Value::Tag::String: + return !value.AsString().AsAtom()->IsEmpty(); + } + return false; + } + return value == *aValue; } bool Gecko_IsFontFormatSupported(StyleFontFaceSourceFormatKeyword aFormat) { diff --git a/layout/style/GeckoBindings.h b/layout/style/GeckoBindings.h index a8b7d75911fa..20566d1970fe 100644 --- a/layout/style/GeckoBindings.h +++ b/layout/style/GeckoBindings.h @@ -550,7 +550,8 @@ const nsTArray* Gecko_Document_GetElementsWithId( const nsTArray* Gecko_ShadowRoot_GetElementsWithId( const mozilla::dom::ShadowRoot*, nsAtom* aId); -bool Gecko_ComputeBoolPrefMediaQuery(nsAtom*); +bool Gecko_EvalMozPrefFeature(nsAtom*, + const mozilla::StyleComputedMozPrefFeatureValue*); // Check whether font format/tech is supported. bool Gecko_IsFontFormatSupported( diff --git a/layout/style/ServoBindings.toml b/layout/style/ServoBindings.toml index 105e0c3e0665..b2f759ef008c 100644 --- a/layout/style/ServoBindings.toml +++ b/layout/style/ServoBindings.toml @@ -382,6 +382,7 @@ cbindgen-types = [ { gecko = "StyleOffsetPathFunction", servo = "crate::values::computed::motion::OffsetPathFunction" }, { gecko = "StyleGenericOffsetPath", servo = "crate::values::generics::motion::OffsetPath" }, { gecko = "StyleGenericOffsetPathFunction", servo = "crate::values::generics::motion::OffsetPathFunction" }, + { gecko = "StyleComputedMozPrefFeatureValue", servo = "crate::queries::condition::ComputedMozPrefFeatureValue" }, { gecko = "StyleMozTheme", servo = "crate::values::computed::ui::MozTheme" }, { gecko = "StyleOffsetPosition", servo = "crate::values::computed::motion::OffsetPosition" }, { gecko = "StyleOffsetRotate", servo = "crate::values::computed::motion::OffsetRotate" }, diff --git a/layout/style/res/html.css b/layout/style/res/html.css index 62b4c7b602b9..9ca4548aa1b4 100644 --- a/layout/style/res/html.css +++ b/layout/style/res/html.css @@ -206,7 +206,7 @@ h6 { } /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "layout.css.h1-in-section-ua-styles.enabled") { +@media -moz-pref("layout.css.h1-in-section-ua-styles.enabled") { :is(article, aside, nav, section) h1 { margin-block: 0.83em; diff --git a/layout/style/res/scrollbars.css b/layout/style/res/scrollbars.css index 6fb12b348768..246af751ac3d 100644 --- a/layout/style/res/scrollbars.css +++ b/layout/style/res/scrollbars.css @@ -6,7 +6,7 @@ /* Rules required for style caching of anonymous content scrollbar parts */ /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "layout.css.cached-scrollbar-styles.enabled") { +@media -moz-pref("layout.css.cached-scrollbar-styles.enabled") { :is(scrollcorner, resizer, scrollbar, scrollbarbutton, slider):where(:-moz-native-anonymous) { /* All scrollbar parts must not inherit any properties from the scrollable * element (except for visibility and pointer-events), for the anonymous diff --git a/layout/style/res/ua.css b/layout/style/res/ua.css index c4e644055834..194cc7bfefda 100644 --- a/layout/style/res/ua.css +++ b/layout/style/res/ua.css @@ -170,7 +170,7 @@ } /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "layout.css.always_underline_links") { +@media -moz-pref("layout.css.always_underline_links") { :any-link { text-decoration: underline !important; } @@ -514,7 +514,7 @@ parsererror|sourcetext { /* Avoid exposing these keyframe names when view transitions are disabled */ /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "dom.viewTransitions.enabled") { +@media -moz-pref("dom.viewTransitions.enabled") { /* Default cross-fade transition */ @keyframes -ua-view-transition-fade-out { to { opacity: 0; } diff --git a/layout/style/res/viewsource.css b/layout/style/res/viewsource.css index 29178f2d98f3..2b2f376b6e3d 100644 --- a/layout/style/res/viewsource.css +++ b/layout/style/res/viewsource.css @@ -19,7 +19,7 @@ margin: 0; padding: 8px; /* stylelint-disable-next-line media-query-no-invalid */ - @media (-moz-bool-pref: "view_source.wrap_long_lines") { + @media -moz-pref("view_source.wrap_long_lines") { white-space: pre-wrap; word-wrap: break-word; } @@ -50,7 +50,7 @@ span[id]::before { } /* stylelint-disable-next-line media-query-no-invalid */ -@media (-moz-bool-pref: "view_source.syntax_highlight") { +@media -moz-pref("view_source.syntax_highlight") { .start-tag, .end-tag { color: light-dark(purple, #f55e5e); diff --git a/layout/style/test/chrome/test_chrome_only_media_queries.html b/layout/style/test/chrome/test_chrome_only_media_queries.html index 961f2c4c3dd7..fce8cdd05f42 100644 --- a/layout/style/test/chrome/test_chrome_only_media_queries.html +++ b/layout/style/test/chrome/test_chrome_only_media_queries.html @@ -10,7 +10,7 @@ SimpleTest.waitForExplicitFinish(); function expect(q, shouldBeKnown) { is(matchMedia(q).media, q, "Serialization should roundtrip"); - is(matchMedia(`${q} or (not ${q})`).matches, shouldBeKnown, `Query should${shouldBeKnown ? "" : " not"} be known`); + is(matchMedia(`${q} or (not ${q})`).matches, shouldBeKnown, `${q} should${shouldBeKnown ? "" : " not"} be known`); } function expectKnown(q) { @@ -21,6 +21,28 @@ function expectUnkown(q) { expect(q, false); } +function testMatches(q, shouldMatch = true) { + is(matchMedia(q).matches, shouldMatch, `${q} should match`); +} + +async function testMozPref(q, prefName, value, otherValue) { + expectKnown(q); + await SpecialPowers.pushPrefEnv({ + set:[[prefName, value]], + }); + testMatches(q, true); + let mediaList = matchMedia(q); + let change = new Promise(r => { + mediaList.addEventListener("change", r, { once: true }); + }); + await SpecialPowers.pushPrefEnv({ + set:[[prefName, otherValue]], + }); + testMatches(q, false); + // Should change dynamically successfully. + await change; +} + // Test a toggle that should always match for `1` or `0`. function testToggle(toggle) { expectKnown(`(${toggle})`); @@ -63,5 +85,13 @@ expectKnown("(forced-colors)"); expectUnkown("(-moz-platform: )"); -SimpleTest.finish(); +(async function() { + await testMozPref('-moz-pref("foo.bar.bool", true)', "foo.bar.bool", true, false); + await testMozPref('-moz-pref("foo.bar.bool")', "foo.bar.bool", true, false); + await testMozPref('-moz-pref("foo.bar.str", "foo")', "foo.bar.str", "foo", "bar"); + await testMozPref('-moz-pref("foo.bar.str")', "foo.bar.str", "foo", ""); + await testMozPref('-moz-pref("foo.bar.int", 1)', "foo.bar.int", 1, 2); + await testMozPref('-moz-pref("foo.bar.int")', "foo.bar.int", 1, 0); + SimpleTest.finish(); +}()); diff --git a/servo/components/style/gecko/media_features.rs b/servo/components/style/gecko/media_features.rs index d0f7dad87624..49636286270d 100644 --- a/servo/components/style/gecko/media_features.rs +++ b/servo/components/style/gecko/media_features.rs @@ -11,10 +11,8 @@ use crate::queries::feature::{AllowsRanges, Evaluator, FeatureFlags, QueryFeatur use crate::queries::values::Orientation; use crate::values::computed::{CSSPixelLength, Context, Ratio, Resolution}; use crate::values::specified::color::ForcedColors; -use crate::values::AtomString; use app_units::Au; use euclid::default::Size2D; -use selectors::kleene_value::KleeneValue; fn device_size(device: &Device) -> Size2D { let mut width = 0; @@ -617,13 +615,6 @@ fn eval_moz_overlay_scrollbars(context: &Context) -> bool { unsafe { bindings::Gecko_MediaFeatures_UseOverlayScrollbars(context.device().document()) } } -fn eval_moz_bool_pref(_: &Context, pref: Option<&AtomString>) -> KleeneValue { - let Some(pref) = pref else { - return KleeneValue::False; - }; - KleeneValue::from(unsafe { bindings::Gecko_ComputeBoolPrefMediaQuery(pref.as_ptr()) }) -} - fn get_lnf_int(int_id: i32) -> i32 { unsafe { bindings::Gecko_GetLookAndFeelInt(int_id) } } @@ -671,7 +662,7 @@ macro_rules! lnf_int_feature { /// to support new types in these entries and (2) ensuring that either /// nsPresContext::MediaFeatureValuesChanged is called when the value that /// would be returned by the evaluator function could change. -pub static MEDIA_FEATURES: [QueryFeatureDescription; 61] = [ +pub static MEDIA_FEATURES: [QueryFeatureDescription; 60] = [ feature!( atom!("width"), AllowsRanges::Yes, @@ -936,12 +927,6 @@ pub static MEDIA_FEATURES: [QueryFeatureDescription; 61] = [ Evaluator::BoolInteger(eval_moz_overlay_scrollbars), FeatureFlags::CHROME_AND_UA_ONLY, ), - feature!( - atom!("-moz-bool-pref"), - AllowsRanges::No, - Evaluator::String(eval_moz_bool_pref), - FeatureFlags::CHROME_AND_UA_ONLY, - ), lnf_int_feature!( atom!("-moz-scrollbar-start-backward"), ScrollArrowStyle, diff --git a/servo/components/style/queries/condition.rs b/servo/components/style/queries/condition.rs index 04acc3e6e96f..3cb762b3d67f 100644 --- a/servo/components/style/queries/condition.rs +++ b/servo/components/style/queries/condition.rs @@ -9,7 +9,7 @@ use super::{FeatureFlags, FeatureType, QueryFeatureExpression}; use crate::custom_properties; -use crate::values::computed; +use crate::values::{computed, AtomString}; use crate::{error_reporting::ContextualParseError, parser::ParserContext}; use cssparser::{Parser, SourcePosition, Token}; use selectors::kleene_value::KleeneValue; @@ -107,6 +107,106 @@ impl StyleFeature { } } +/// A boolean value for a pref query. +#[derive( + Clone, + Debug, + MallocSizeOf, + PartialEq, + Eq, + Parse, + SpecifiedValueInfo, + ToComputedValue, + ToCss, + ToShmem, +)] +#[repr(u8)] +#[allow(missing_docs)] +pub enum BoolValue { + False, + True, +} + +/// Simple values we support for -moz-pref(). We don't want to deal with calc() and other +/// shenanigans for now. +#[derive( + Clone, + Debug, + Eq, + MallocSizeOf, + Parse, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToCss, + ToShmem, +)] +#[repr(u8)] +pub enum MozPrefFeatureValue { + /// No pref value, implicitly bool, but also used to represent missing prefs. + #[css(skip)] + None, + /// A bool value. + Boolean(BoolValue), + /// An integer value, useful for int prefs. + Integer(I), + /// A string pref value. + String(crate::values::AtomString), +} + +type SpecifiedMozPrefFeatureValue = MozPrefFeatureValue; +/// The computed -moz-pref() value. +pub type ComputedMozPrefFeatureValue = MozPrefFeatureValue; + +/// A custom -moz-pref(, ) query feature. +#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)] +pub struct MozPrefFeature { + name: crate::values::AtomString, + value: SpecifiedMozPrefFeatureValue, +} + +impl MozPrefFeature { + fn parse<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + feature_type: FeatureType, + ) -> Result> { + use crate::parser::Parse; + if !context.chrome_rules_enabled() || feature_type != FeatureType::Media { + return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); + } + let name = AtomString::parse(context, input)?; + let value = if input.try_parse(|i| i.expect_comma()).is_ok() { + SpecifiedMozPrefFeatureValue::parse(context, input)? + } else { + SpecifiedMozPrefFeatureValue::None + }; + Ok(Self { name, value }) + } + + fn matches(&self, ctx: &computed::Context) -> KleeneValue { + use crate::values::computed::ToComputedValue; + let value = self.value.to_computed_value(ctx); + KleeneValue::from(unsafe { + crate::gecko_bindings::bindings::Gecko_EvalMozPrefFeature(self.name.as_ptr(), &value) + }) + } +} + +impl ToCss for MozPrefFeature { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: fmt::Write, + { + self.name.to_css(dest)?; + if !matches!(self.value, MozPrefFeatureValue::None) { + dest.write_str(", ")?; + self.value.to_css(dest)?; + } + Ok(()) + } +} + /// Represents a condition. #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)] pub enum QueryCondition { @@ -120,6 +220,8 @@ pub enum QueryCondition { InParens(Box), /// A