style/substitution/
var.rs1use super::{
9 ArbitraryDeclarationValue, ParsedArgument, Substitution, SubstitutionArgument,
10 SubstitutionParserContext, SubstitutionReplacementContext, parse_optional_fallback,
11};
12use crate::custom_properties::{Name, VariableValue, parse_name};
13use crate::parser::Parse;
14use crate::{Atom, derives::*};
15use cssparser::{Delimiter, Parser};
16use style_traits::{ParseError, StyleParseErrorKind};
17
18#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
20pub struct CustomPropertyName(pub Name);
21
22impl Parse for CustomPropertyName {
23 fn parse(_: &crate::parser::ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
24 parse_name(input.expect_ident()?.as_ref())
25 .map(Atom::from)
26 .map(CustomPropertyName)
27 .map_err(|_| ParseError::custom(StyleParseErrorKind::UnexpectedIdent))
28 }
29}
30
31#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
33pub struct VarFunction {
34 pub name: SubstitutionArgument<CustomPropertyName>,
36 pub fallback: Option<ArbitraryDeclarationValue>,
38}
39
40impl VarFunction {
41 pub fn parse(
45 input: &mut Parser,
46 context: &mut SubstitutionParserContext,
47 ) -> Result<Self, ParseError> {
48 let name = SubstitutionArgument::try_parse(input, context, Delimiter::Comma)?;
49 let fallback = parse_optional_fallback(input, context)?;
50 Ok(Self { name, fallback })
51 }
52
53 pub fn replace<'a>(
56 &'a self,
57 source: &'a VariableValue,
58 context: &mut SubstitutionReplacementContext<'a, '_, '_, '_>,
59 ) -> Result<Substitution<'a>, ()> {
60 let name = self.replace_name(source, context);
61 let mut substitution = name
62 .value
63 .and_then(|name| Self::resolve_custom_property(&name.0, context))
64 .ok_or(())
65 .or_else(|_| {
66 context.substitute_declaration_value(self.fallback.as_ref().ok_or(())?, source)
67 })?;
68 substitution.attr_tainted |= name.attr_tainted;
69 Ok(substitution)
70 }
71
72 fn resolve_custom_property<'a>(
73 name: &Name,
74 context: &mut SubstitutionReplacementContext<'a, '_, '_, '_>,
75 ) -> Option<Substitution<'a>> {
76 let registration = context.stylist.get_custom_property_registration(name);
77 match context.substitution_functions.get_var(registration, name) {
78 None => None,
79 Some(v) => match v.as_universal() {
85 Some(u) if u.has_references() => {
86 if context.seen.contains(name) {
87 None
90 } else {
91 context.seen.push(name.clone());
92 let result =
93 context.substitute_variable_value(u, None);
94 context.seen.pop();
95 match result {
96 Ok(mut substitution) => {
97 substitution.attr_tainted |= v.attr_tainted;
98 Some(substitution)
99 },
100 Err(()) => None,
102 }
103 }
104 },
105 _ => Some(Substitution::from_value(
106 v.to_variable_value(),
107 v.attr_tainted,
108 )),
109 },
110 }
111 }
112
113 pub fn replace_name<'a>(
115 &'a self,
116 source: &'a VariableValue,
117 context: &mut SubstitutionReplacementContext<'a, '_, '_, '_>,
118 ) -> ParsedArgument<'a, CustomPropertyName> {
119 self.name.substitute_and_parse(source, context)
120 }
121
122 pub fn for_each_unparsed_value<F>(&self, mut f: F)
124 where
125 F: FnMut(&ArbitraryDeclarationValue),
126 {
127 if let SubstitutionArgument::Unparsed(arg) = &self.name {
128 f(arg);
129 }
130 if let Some(ref fallback) = self.fallback {
131 f(fallback);
132 }
133 }
134}