LibWeb: Save more details about ASF presence in UnresolvedStyleValue

In the upcoming changes we would have to know specifically whether
`var()`, `attr()` or both are included in UnresolvedStyleValue.
This commit is contained in:
Aliaksandr Kalenik 2025-07-27 19:40:17 +02:00 committed by Andreas Kling
commit b1efd62ce6
Notes: github-actions[bot] 2025-07-30 09:07:37 +00:00
5 changed files with 44 additions and 41 deletions

View file

@ -393,7 +393,7 @@ Parser::ParseErrorOr<NonnullRefPtr<CSSStyleValue const>> Parser::parse_css_value
// FIXME: Stop removing whitespace here. It's less helpful than it seems. // FIXME: Stop removing whitespace here. It's less helpful than it seems.
Vector<ComponentValue> component_values; Vector<ComponentValue> component_values;
bool contains_arbitrary_substitution_function = false; SubstitutionFunctionsPresence substitution_presence;
bool const property_accepts_custom_ident = property_accepts_type(property_id, ValueType::CustomIdent); bool const property_accepts_custom_ident = property_accepts_type(property_id, ValueType::CustomIdent);
while (unprocessed_tokens.has_next_token()) { while (unprocessed_tokens.has_next_token()) {
@ -412,12 +412,10 @@ Parser::ParseErrorOr<NonnullRefPtr<CSSStyleValue const>> Parser::parse_css_value
return ParseError::IncludesIgnoredVendorPrefix; return ParseError::IncludesIgnoredVendorPrefix;
} }
if (!contains_arbitrary_substitution_function) { if (token.is_function())
if (token.is_function() && token.function().contains_arbitrary_substitution_function()) token.function().contains_arbitrary_substitution_function(substitution_presence);
contains_arbitrary_substitution_function = true; else if (token.is_block())
else if (token.is_block() && token.block().contains_arbitrary_substitution_function()) token.block().contains_arbitrary_substitution_function(substitution_presence);
contains_arbitrary_substitution_function = true;
}
component_values.append(token); component_values.append(token);
} }
@ -428,8 +426,8 @@ Parser::ParseErrorOr<NonnullRefPtr<CSSStyleValue const>> Parser::parse_css_value
return parsed_value.release_nonnull(); return parsed_value.release_nonnull();
} }
if (property_id == PropertyID::Custom || contains_arbitrary_substitution_function) if (property_id == PropertyID::Custom || substitution_presence.has_any())
return UnresolvedStyleValue::create(move(component_values), contains_arbitrary_substitution_function, original_source_text); return UnresolvedStyleValue::create(move(component_values), substitution_presence, original_source_text);
if (component_values.is_empty()) if (component_values.is_empty())
return ParseError::SyntaxError; return ParseError::SyntaxError;

View file

@ -51,15 +51,14 @@ String SimpleBlock::original_source_text() const
return builder.to_string_without_validation(); return builder.to_string_without_validation();
} }
bool SimpleBlock::contains_arbitrary_substitution_function() const void SimpleBlock::contains_arbitrary_substitution_function(SubstitutionFunctionsPresence& presence) const
{ {
for (auto const& component_value : value) { for (auto const& component_value : value) {
if (component_value.is_function() && component_value.function().contains_arbitrary_substitution_function()) if (component_value.is_function())
return true; component_value.function().contains_arbitrary_substitution_function(presence);
if (component_value.is_block() && component_value.block().contains_arbitrary_substitution_function()) if (component_value.is_block())
return true; component_value.block().contains_arbitrary_substitution_function(presence);
} }
return false;
} }
String Function::to_string() const String Function::to_string() const
@ -86,17 +85,18 @@ String Function::original_source_text() const
return builder.to_string_without_validation(); return builder.to_string_without_validation();
} }
bool Function::contains_arbitrary_substitution_function() const void Function::contains_arbitrary_substitution_function(SubstitutionFunctionsPresence& presence) const
{ {
if (name.equals_ignoring_ascii_case("var"sv) || name.equals_ignoring_ascii_case("attr"sv)) if (name.equals_ignoring_ascii_case("var"sv))
return true; presence.var = true;
else if (name.equals_ignoring_ascii_case("attr"sv))
presence.attr = true;
for (auto const& component_value : value) { for (auto const& component_value : value) {
if (component_value.is_function() && component_value.function().contains_arbitrary_substitution_function()) if (component_value.is_function())
return true; component_value.function().contains_arbitrary_substitution_function(presence);
if (component_value.is_block() && component_value.block().contains_arbitrary_substitution_function()) if (component_value.is_block())
return true; component_value.block().contains_arbitrary_substitution_function(presence);
} }
return false;
} }
void AtRule::for_each(AtRuleVisitor&& visit_at_rule, QualifiedRuleVisitor&& visit_qualified_rule, DeclarationVisitor&& visit_declaration) const void AtRule::for_each(AtRuleVisitor&& visit_at_rule, QualifiedRuleVisitor&& visit_qualified_rule, DeclarationVisitor&& visit_declaration) const

View file

@ -61,6 +61,13 @@ struct Declaration {
String to_string() const; String to_string() const;
}; };
struct SubstitutionFunctionsPresence {
bool attr { false };
bool var { false };
bool has_any() const { return attr || var; }
};
// https://drafts.csswg.org/css-syntax/#simple-block // https://drafts.csswg.org/css-syntax/#simple-block
struct SimpleBlock { struct SimpleBlock {
Token token; Token token;
@ -73,7 +80,7 @@ struct SimpleBlock {
String to_string() const; String to_string() const;
String original_source_text() const; String original_source_text() const;
bool contains_arbitrary_substitution_function() const; void contains_arbitrary_substitution_function(SubstitutionFunctionsPresence&) const;
}; };
// https://drafts.csswg.org/css-syntax/#function // https://drafts.csswg.org/css-syntax/#function
@ -85,7 +92,7 @@ struct Function {
String to_string() const; String to_string() const;
String original_source_text() const; String original_source_text() const;
bool contains_arbitrary_substitution_function() const; void contains_arbitrary_substitution_function(SubstitutionFunctionsPresence&) const;
}; };
// https://drafts.csswg.org/css-variables/#guaranteed-invalid-value // https://drafts.csswg.org/css-variables/#guaranteed-invalid-value

View file

@ -13,27 +13,25 @@
namespace Web::CSS { namespace Web::CSS {
ValueComparingNonnullRefPtr<UnresolvedStyleValue const> UnresolvedStyleValue::create(Vector<Parser::ComponentValue>&& values, Optional<bool> contains_arbitrary_substitution_function, Optional<String> original_source_text) ValueComparingNonnullRefPtr<UnresolvedStyleValue const> UnresolvedStyleValue::create(Vector<Parser::ComponentValue>&& values, Optional<Parser::SubstitutionFunctionsPresence> substitution_presence, Optional<String> original_source_text)
{ {
if (!contains_arbitrary_substitution_function.has_value()) { if (!substitution_presence.has_value()) {
bool found_asf = false; substitution_presence = Parser::SubstitutionFunctionsPresence {};
for (auto const& value : values) { for (auto const& value : values) {
if ((value.is_function() && value.function().contains_arbitrary_substitution_function()) if (value.is_function())
|| (value.is_block() && value.block().contains_arbitrary_substitution_function())) { value.function().contains_arbitrary_substitution_function(*substitution_presence);
found_asf = true; if (value.is_block())
break; value.block().contains_arbitrary_substitution_function(*substitution_presence);
}
} }
contains_arbitrary_substitution_function = found_asf;
} }
return adopt_ref(*new (nothrow) UnresolvedStyleValue(move(values), contains_arbitrary_substitution_function.value(), move(original_source_text))); return adopt_ref(*new (nothrow) UnresolvedStyleValue(move(values), *substitution_presence, move(original_source_text)));
} }
UnresolvedStyleValue::UnresolvedStyleValue(Vector<Parser::ComponentValue>&& values, bool contains_arbitrary_substitution_function, Optional<String> original_source_text) UnresolvedStyleValue::UnresolvedStyleValue(Vector<Parser::ComponentValue>&& values, Parser::SubstitutionFunctionsPresence substitution_presence, Optional<String> original_source_text)
: CSSStyleValue(Type::Unresolved) : CSSStyleValue(Type::Unresolved)
, m_values(move(values)) , m_values(move(values))
, m_contains_arbitrary_substitution_function(contains_arbitrary_substitution_function) , m_substitution_functions_presence(substitution_presence)
, m_original_source_text(move(original_source_text)) , m_original_source_text(move(original_source_text))
{ {
} }

View file

@ -17,22 +17,22 @@ namespace Web::CSS {
class UnresolvedStyleValue final : public CSSStyleValue { class UnresolvedStyleValue final : public CSSStyleValue {
public: public:
static ValueComparingNonnullRefPtr<UnresolvedStyleValue const> create(Vector<Parser::ComponentValue>&& values, Optional<bool> contains_arbitrary_substitution_function = {}, Optional<String> original_source_text = {}); static ValueComparingNonnullRefPtr<UnresolvedStyleValue const> create(Vector<Parser::ComponentValue>&& values, Optional<Parser::SubstitutionFunctionsPresence> = {}, Optional<String> original_source_text = {});
virtual ~UnresolvedStyleValue() override = default; virtual ~UnresolvedStyleValue() override = default;
virtual String to_string(SerializationMode) const override; virtual String to_string(SerializationMode) const override;
virtual Vector<Parser::ComponentValue> tokenize() const override { return m_values; } virtual Vector<Parser::ComponentValue> tokenize() const override { return m_values; }
Vector<Parser::ComponentValue> const& values() const { return m_values; } Vector<Parser::ComponentValue> const& values() const { return m_values; }
bool contains_arbitrary_substitution_function() const { return m_contains_arbitrary_substitution_function; } bool contains_arbitrary_substitution_function() const { return m_substitution_functions_presence.has_any(); }
virtual bool equals(CSSStyleValue const& other) const override; virtual bool equals(CSSStyleValue const& other) const override;
private: private:
UnresolvedStyleValue(Vector<Parser::ComponentValue>&& values, bool contains_arbitrary_substitution_function, Optional<String> original_source_text); UnresolvedStyleValue(Vector<Parser::ComponentValue>&& values, Parser::SubstitutionFunctionsPresence, Optional<String> original_source_text);
Vector<Parser::ComponentValue> m_values; Vector<Parser::ComponentValue> m_values;
bool m_contains_arbitrary_substitution_function { false }; Parser::SubstitutionFunctionsPresence m_substitution_functions_presence {};
Optional<String> m_original_source_text; Optional<String> m_original_source_text;
}; };