|
8 | 8 | use super::feature::{Evaluator, QueryFeatureDescription}; |
9 | 9 | use super::feature::{FeatureFlags, KeywordDiscriminant}; |
10 | 10 | use crate::context::QuirksMode; |
| 11 | +use crate::custom_properties::VariableValue as CustomVariableValue; |
11 | 12 | use crate::derives::*; |
12 | 13 | use crate::parser::{Parse, ParserContext}; |
13 | 14 | use crate::properties::CSSWideKeyword; |
@@ -679,8 +680,12 @@ pub enum QueryExpressionValue { |
679 | 680 | /// A custom property name. |
680 | 681 | Custom(DashedIdent), |
681 | 682 | /// A simple var(...) reference without a default (equivalent to a bare Custom ident, |
682 | | - /// but will serialize with the `var()` wrapper) |
| 683 | + /// but will serialize with the `var()` wrapper). |
683 | 684 | Var(DashedIdent), |
| 685 | + /// An arbitrary substitution function (var(), attr(), env()), stored as a string |
| 686 | + /// for later evaluation. We store this as a custom-property value to make it easy |
| 687 | + /// to resolve later. |
| 688 | + Function(Box<CustomVariableValue>), |
684 | 689 | } |
685 | 690 |
|
686 | 691 | impl QueryExpressionValue { |
@@ -709,6 +714,7 @@ impl QueryExpressionValue { |
709 | 714 | v.to_css(dest)?; |
710 | 715 | dest.write_char(')') |
711 | 716 | }, |
| 717 | + QueryExpressionValue::Function(ref f) => f.to_css(dest), |
712 | 718 | QueryExpressionValue::Enumerated(value) => match for_expr |
713 | 719 | .expect("caller should have passed for_expr") |
714 | 720 | .feature() |
@@ -793,17 +799,38 @@ impl QueryExpressionValue { |
793 | 799 | if let Ok(keyword) = input.try_parse(|i| CSSWideKeyword::parse(i)) { |
794 | 800 | return Ok(Self::Keyword(keyword)); |
795 | 801 | } |
| 802 | + input.skip_whitespace(); |
| 803 | + let start = input.position(); |
796 | 804 | if let Ok(Token::Function(ref name)) = input.next() { |
797 | | - // Here, we only handle simple `var(--foo)` references when used as individual |
798 | | - // query expression values. More complex usages such as `var(...)` with default, |
799 | | - // or `var(...)` used within `calc(...)` expressions, will be substituted and |
800 | | - // resolved at query evaluation time. |
| 805 | + // Helper to parse the function arg and store the complete expression (function |
| 806 | + // name and parenthesized argument) into a CustomVariableValue. |
| 807 | + let parse_func = |
| 808 | + |input: &mut Parser<'i, 't>| -> Result<CustomVariableValue, ParseError<'i>> { |
| 809 | + input.parse_nested_block(|i| i.expect_no_error_token().map_err(Into::into))?; |
| 810 | + let mut input = ParserInput::new(input.slice_from(start)); |
| 811 | + CustomVariableValue::parse( |
| 812 | + &mut Parser::new(&mut input), |
| 813 | + Some(&context.namespaces.prefixes), |
| 814 | + context.url_data, |
| 815 | + ) |
| 816 | + }; |
| 817 | + |
801 | 818 | if name.eq_ignore_ascii_case("var") { |
| 819 | + // For simple `var(--foo)` references used as individual query-expression values, |
| 820 | + // we can store as the Var() variant and just look up the custom property at |
| 821 | + // evaluation time. |
802 | 822 | if let Ok(ident) = |
803 | 823 | input.try_parse(|i| i.parse_nested_block(|i| DashedIdent::parse(context, i))) |
804 | 824 | { |
805 | 825 | return Ok(Self::Var(ident)); |
806 | 826 | } |
| 827 | + // Otherwise, we store the entire function to be resolved later via |
| 828 | + // custom_properties::substitute(), which will also handle fallbacks |
| 829 | + // if necessary. |
| 830 | + return Ok(Self::Function(Box::new(parse_func(input)?))); |
| 831 | + } |
| 832 | + if static_prefs::pref!("layout.css.attr.enabled") && name.eq_ignore_ascii_case("attr") { |
| 833 | + return Ok(Self::Function(Box::new(parse_func(input)?))); |
807 | 834 | } |
808 | 835 | } |
809 | 836 | Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) |
|
0 commit comments