1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-24 16:17:34 +00:00

LibWeb: Break friendship between CSS Declaration and Parser

This means deviating slightly from the spec in order to construct a
fully-initialized Declaration instead of creating an empty one and then
poking at its internals.

DeclarationOrAtRule should probably use a Variant, but for now, making
its Declaration member optional is quick and easy.
This commit is contained in:
Sam Atkins 2022-04-12 16:16:55 +01:00 committed by Andreas Kling
parent 69496f4afd
commit 269810b954
5 changed files with 27 additions and 21 deletions

View file

@ -10,7 +10,13 @@
namespace Web::CSS::Parser { namespace Web::CSS::Parser {
Declaration::Declaration() = default; Declaration::Declaration(FlyString name, Vector<ComponentValue> values, Important important)
: m_name(move(name))
, m_values(move(values))
, m_important(move(important))
{
}
Declaration::~Declaration() = default; Declaration::~Declaration() = default;
String Declaration::to_string() const String Declaration::to_string() const

View file

@ -14,10 +14,8 @@
namespace Web::CSS::Parser { namespace Web::CSS::Parser {
class Declaration { class Declaration {
friend class Parser;
public: public:
Declaration(); Declaration(FlyString name, Vector<ComponentValue> values, Important);
~Declaration(); ~Declaration();
StringView name() const { return m_name; } StringView name() const { return m_name; }

View file

@ -32,7 +32,7 @@ String DeclarationOrAtRule::to_string() const
builder.append(m_at->to_string()); builder.append(m_at->to_string());
break; break;
case DeclarationType::Declaration: case DeclarationType::Declaration:
builder.append(m_declaration.to_string()); builder.append(m_declaration->to_string());
break; break;
} }

View file

@ -36,7 +36,7 @@ public:
Declaration const& declaration() const Declaration const& declaration() const
{ {
VERIFY(is_declaration()); VERIFY(is_declaration());
return m_declaration; return *m_declaration;
} }
String to_string() const; String to_string() const;
@ -44,7 +44,7 @@ public:
private: private:
DeclarationType m_type; DeclarationType m_type;
RefPtr<StyleRule> m_at; RefPtr<StyleRule> m_at;
Declaration m_declaration; Optional<Declaration> m_declaration;
}; };
} }

View file

@ -1932,8 +1932,10 @@ Optional<Declaration> Parser::consume_a_declaration(TokenStream<T>& tokens)
// Create a new declaration with its name set to the value of the current input token // Create a new declaration with its name set to the value of the current input token
// and its value initially set to the empty list. // and its value initially set to the empty list.
Declaration declaration; // NOTE: We create a fully-initialized Declaration just before returning it instead.
declaration.m_name = ((Token)token).ident(); FlyString declaration_name = ((Token)token).ident();
Vector<ComponentValue> declaration_values;
Important declaration_important = Important::No;
// 1. While the next input token is a <whitespace-token>, consume the next input token. // 1. While the next input token is a <whitespace-token>, consume the next input token.
tokens.skip_whitespace(); tokens.skip_whitespace();
@ -1958,18 +1960,18 @@ Optional<Declaration> Parser::consume_a_declaration(TokenStream<T>& tokens)
if (tokens.peek_token().is(Token::Type::EndOfFile)) { if (tokens.peek_token().is(Token::Type::EndOfFile)) {
break; break;
} }
declaration.m_values.append(consume_a_component_value(tokens)); declaration_values.append(consume_a_component_value(tokens));
} }
// 5. If the last two non-<whitespace-token>s in the declarations value are a <delim-token> // 5. If the last two non-<whitespace-token>s in the declarations value are a <delim-token>
// with the value "!" followed by an <ident-token> with a value that is an ASCII case-insensitive // with the value "!" followed by an <ident-token> with a value that is an ASCII case-insensitive
// match for "important", remove them from the declarations value and set the declarations // match for "important", remove them from the declarations value and set the declarations
// important flag to true. // important flag to true.
if (declaration.m_values.size() >= 2) { if (declaration_values.size() >= 2) {
// Walk backwards from the end until we find "important" // Walk backwards from the end until we find "important"
Optional<size_t> important_index; Optional<size_t> important_index;
for (size_t i = declaration.m_values.size() - 1; i > 0; i--) { for (size_t i = declaration_values.size() - 1; i > 0; i--) {
auto value = declaration.m_values[i]; auto value = declaration_values[i];
if (value.is(Token::Type::Ident) && value.token().ident().equals_ignoring_case("important")) { if (value.is(Token::Type::Ident) && value.token().ident().equals_ignoring_case("important")) {
important_index = i; important_index = i;
break; break;
@ -1983,7 +1985,7 @@ Optional<Declaration> Parser::consume_a_declaration(TokenStream<T>& tokens)
if (important_index.has_value()) { if (important_index.has_value()) {
Optional<size_t> bang_index; Optional<size_t> bang_index;
for (size_t i = important_index.value() - 1; i > 0; i--) { for (size_t i = important_index.value() - 1; i > 0; i--) {
auto value = declaration.m_values[i]; auto value = declaration_values[i];
if (value.is(Token::Type::Delim) && value.token().delim() == '!') { if (value.is(Token::Type::Delim) && value.token().delim() == '!') {
bang_index = i; bang_index = i;
break; break;
@ -1994,24 +1996,24 @@ Optional<Declaration> Parser::consume_a_declaration(TokenStream<T>& tokens)
} }
if (bang_index.has_value()) { if (bang_index.has_value()) {
declaration.m_values.remove(important_index.value()); declaration_values.remove(important_index.value());
declaration.m_values.remove(bang_index.value()); declaration_values.remove(bang_index.value());
declaration.m_important = Important::Yes; declaration_important = Important::Yes;
} }
} }
} }
// 6. While the last token in the declarations value is a <whitespace-token>, remove that token. // 6. While the last token in the declarations value is a <whitespace-token>, remove that token.
while (!declaration.m_values.is_empty()) { while (!declaration_values.is_empty()) {
auto maybe_whitespace = declaration.m_values.last(); auto maybe_whitespace = declaration_values.last();
if (!(maybe_whitespace.is(Token::Type::Whitespace))) { if (!(maybe_whitespace.is(Token::Type::Whitespace))) {
break; break;
} }
declaration.m_values.take_last(); declaration_values.take_last();
} }
// 7. Return the declaration. // 7. Return the declaration.
return declaration; return Declaration { move(declaration_name), move(declaration_values), move(declaration_important) };
} }
// 5.4.5. Consume a list of declarations // 5.4.5. Consume a list of declarations