diff --git a/components/style/gecko/media_features.rs b/components/style/gecko/media_features.rs index a02ddcfd688..f3b8297439f 100644 --- a/components/style/gecko/media_features.rs +++ b/components/style/gecko/media_features.rs @@ -308,6 +308,53 @@ fn eval_prefers_reduced_motion(device: &Device, query_value: Option) -> bool { + let forced_colors = !device.use_document_colors(); + let contrast_pref = + unsafe { bindings::Gecko_MediaFeatures_PrefersContrast(device.document(), forced_colors) }; + if let Some(query_value) = query_value { + match query_value { + PrefersContrast::Forced => forced_colors, + PrefersContrast::High => contrast_pref == ContrastPref::High, + PrefersContrast::Low => contrast_pref == ContrastPref::Low, + PrefersContrast::NoPreference => contrast_pref == ContrastPref::NoPreference, + } + } else { + // Only prefers-contrast: no-preference evaluates to false. + forced_colors || (contrast_pref != ContrastPref::NoPreference) + } +} + #[derive(Clone, Copy, Debug, FromPrimitive, Parse, ToCss)] #[repr(u8)] enum OverflowBlock { @@ -548,7 +595,7 @@ macro_rules! system_metric_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: [MediaFeatureDescription; 53] = [ +pub static MEDIA_FEATURES: [MediaFeatureDescription; 54] = [ feature!( atom!("width"), AllowsRanges::Yes, @@ -666,6 +713,17 @@ pub static MEDIA_FEATURES: [MediaFeatureDescription; 53] = [ keyword_evaluator!(eval_prefers_reduced_motion, PrefersReducedMotion), ParsingRequirements::empty(), ), + feature!( + atom!("prefers-contrast"), + AllowsRanges::No, + keyword_evaluator!(eval_prefers_contrast, PrefersContrast), + // Note: by default this is only enabled in browser chrome and + // ua. It can be enabled on the web via the + // layout.css.prefers-contrast.enabled preference. See + // disabed_by_pref in media_feature_expression.rs for how that + // is done. + ParsingRequirements::empty(), + ), feature!( atom!("overflow-block"), AllowsRanges::No, diff --git a/components/style/media_queries/media_feature_expression.rs b/components/style/media_queries/media_feature_expression.rs index 61e62f4ab70..0d2262f1def 100644 --- a/components/style/media_queries/media_feature_expression.rs +++ b/components/style/media_queries/media_feature_expression.rs @@ -218,12 +218,18 @@ fn consume_operation_or_colon(input: &mut Parser) -> Result, () } #[allow(unused_variables)] -fn disabled_by_pref(feature: &Atom) -> bool { +fn disabled_by_pref(feature: &Atom, context: &ParserContext) -> bool { #[cfg(feature = "gecko")] { if *feature == atom!("-moz-touch-enabled") { return !static_prefs::pref!("layout.css.moz-touch-enabled.enabled"); } + // prefers-contrast is always enabled in the ua and chrome. On + // the web it is hidden behind a preference. + if *feature == atom!("prefers-contrast") { + return !context.in_ua_or_chrome_sheet() && + !static_prefs::pref!("layout.css.prefers-contrast.enabled"); + } } false } @@ -305,7 +311,7 @@ impl MediaFeatureExpression { }, }; - if disabled_by_pref(&feature.name) || + if disabled_by_pref(&feature.name, context) || !requirements.contains(feature.requirements) || (range.is_some() && !feature.allows_ranges()) { diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 80199caa563..9bb13eb62b0 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -2089,7 +2089,9 @@ pub fn assert_initial_values_match(data: &PerDocumentStyleData) { let data = data.borrow(); let cv = data.stylist.device().default_computed_values(); <% - # Skip properties with initial values that change at computed value time. + # Skip properties with initial values that change at computed + # value time, or whose initial value depends on the document + # / other prefs. SKIPPED = [ "border-top-width", "border-bottom-width", @@ -2098,6 +2100,7 @@ pub fn assert_initial_values_match(data: &PerDocumentStyleData) { "font-family", "font-size", "outline-width", + "color", ] TO_TEST = [p for p in data.longhands if p.enabled_in != "" and not p.logical and not p.name in SKIPPED] %>