1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-13 21:57:36 +00:00

LibWeb: Convert style declarations and at rules into CSSRules

This commit is contained in:
Sam Atkins 2021-07-08 21:53:22 +01:00 committed by Andreas Kling
parent 2c84379846
commit 28e8bb9b1d
2 changed files with 118 additions and 33 deletions

View file

@ -158,12 +158,14 @@ NonnullRefPtr<CSSStyleSheet> Parser::parse_as_stylesheet(TokenStream<T>& tokens)
NonnullRefPtrVector<CSSRule> rules; NonnullRefPtrVector<CSSRule> rules;
for (auto& raw_rule : parser_rules) { for (auto& raw_rule : parser_rules) {
auto rule = convert_rule(raw_rule); auto rule = convert_to_rule(raw_rule);
if (rule) if (rule)
rules.append(*rule); rules.append(*rule);
} }
return CSSStyleSheet::create(rules); auto stylesheet = CSSStyleSheet::create(rules);
dump_sheet(stylesheet);
return stylesheet;
} }
Vector<Selector> Parser::parse_a_selector() Vector<Selector> Parser::parse_a_selector()
@ -574,10 +576,11 @@ NonnullRefPtr<StyleRule> Parser::consume_an_at_rule()
template<typename T> template<typename T>
NonnullRefPtr<StyleRule> Parser::consume_an_at_rule(TokenStream<T>& tokens) NonnullRefPtr<StyleRule> Parser::consume_an_at_rule(TokenStream<T>& tokens)
{ {
auto initial = tokens.next_token(); auto name_ident = tokens.next_token();
VERIFY(name_ident.is(Token::Type::Ident));
NonnullRefPtr<StyleRule> rule = create<StyleRule>(StyleRule::Type::At); NonnullRefPtr<StyleRule> rule = create<StyleRule>(StyleRule::Type::At);
rule->m_name = initial.m_value.to_string(); rule->m_name = ((Token)name_ident).ident();
for (;;) { for (;;) {
auto token = tokens.next_token(); auto token = tokens.next_token();
@ -636,9 +639,10 @@ RefPtr<StyleRule> Parser::consume_a_qualified_rule(TokenStream<T>& tokens)
return rule; return rule;
} }
StyleComponentValueRule Parser::consume_a_component_value() template<>
StyleComponentValueRule Parser::consume_a_component_value(TokenStream<StyleComponentValueRule>& tokens)
{ {
return consume_a_component_value(m_token_stream); return tokens.next_token();
} }
template<typename T> template<typename T>
@ -655,6 +659,11 @@ StyleComponentValueRule Parser::consume_a_component_value(TokenStream<T>& tokens
return StyleComponentValueRule(token); return StyleComponentValueRule(token);
} }
StyleComponentValueRule Parser::consume_a_component_value()
{
return consume_a_component_value(m_token_stream);
}
NonnullRefPtr<StyleBlockRule> Parser::consume_a_simple_block() NonnullRefPtr<StyleBlockRule> Parser::consume_a_simple_block()
{ {
return consume_a_simple_block(m_token_stream); return consume_a_simple_block(m_token_stream);
@ -740,7 +749,6 @@ Optional<StyleDeclarationRule> Parser::consume_a_declaration(TokenStream<T>& tok
tokens.skip_whitespace(); tokens.skip_whitespace();
auto colon = tokens.next_token(); auto colon = tokens.next_token();
if (!colon.is(Token::Type::Colon)) { if (!colon.is(Token::Type::Colon)) {
log_parse_error(); log_parse_error();
return {}; return {};
@ -755,18 +763,20 @@ Optional<StyleDeclarationRule> Parser::consume_a_declaration(TokenStream<T>& tok
declaration.m_values.append(consume_a_component_value(tokens)); declaration.m_values.append(consume_a_component_value(tokens));
} }
auto second_last = declaration.m_values.at(declaration.m_values.size() - 2); if (declaration.m_values.size() >= 2) {
auto last = declaration.m_values.at(declaration.m_values.size() - 1); auto second_last = declaration.m_values.at(declaration.m_values.size() - 2);
auto last = declaration.m_values.at(declaration.m_values.size() - 1);
if (second_last.m_type == StyleComponentValueRule::ComponentType::Token && last.m_type == StyleComponentValueRule::ComponentType::Token) { if (second_last.m_type == StyleComponentValueRule::ComponentType::Token && last.m_type == StyleComponentValueRule::ComponentType::Token) {
auto last_token = last.m_token; auto last_token = last.m_token;
auto second_last_token = second_last.m_token; auto second_last_token = second_last.m_token;
if (second_last_token.is(Token::Type::Delim) && second_last_token.m_value.to_string().equals_ignoring_case("!")) { if (second_last_token.is(Token::Type::Delim) && second_last_token.m_value.to_string().equals_ignoring_case("!")) {
if (last_token.is(Token::Type::Ident) && last_token.m_value.to_string().equals_ignoring_case("important")) { if (last_token.is(Token::Type::Ident) && last_token.m_value.to_string().equals_ignoring_case("important")) {
declaration.m_values.remove(declaration.m_values.size() - 2); declaration.m_values.remove(declaration.m_values.size() - 2);
declaration.m_values.remove(declaration.m_values.size() - 1); declaration.m_values.remove(declaration.m_values.size() - 1);
declaration.m_important = true; declaration.m_important = true;
}
} }
} }
} }
@ -810,7 +820,7 @@ Vector<DeclarationOrAtRule> Parser::consume_a_list_of_declarations(TokenStream<T
if (token.is(Token::Type::Ident)) { if (token.is(Token::Type::Ident)) {
Vector<StyleComponentValueRule> temp; Vector<StyleComponentValueRule> temp;
temp.append(StyleComponentValueRule(token)); temp.append(token);
for (;;) { for (;;) {
auto peek = tokens.peek_token(); auto peek = tokens.peek_token();
@ -825,13 +835,14 @@ Vector<DeclarationOrAtRule> Parser::consume_a_list_of_declarations(TokenStream<T
if (maybe_declaration.has_value()) { if (maybe_declaration.has_value()) {
list.append(DeclarationOrAtRule(maybe_declaration.value())); list.append(DeclarationOrAtRule(maybe_declaration.value()));
} }
continue;
} }
log_parse_error(); log_parse_error();
tokens.reconsume_current_input_token(); tokens.reconsume_current_input_token();
auto peek = tokens.peek_token(); auto peek = tokens.peek_token();
if (!(peek.is(Token::Type::Semicolon) || peek.is(Token::Type::EndOfFile))) { if (!(peek.is(Token::Type::Semicolon) || peek.is(Token::Type::EndOfFile))) {
consume_a_component_value(tokens); (void)consume_a_component_value(tokens);
} }
} }
@ -855,14 +866,14 @@ RefPtr<CSSRule> Parser::parse_as_rule(TokenStream<T>& tokens)
if (token.is(Token::Type::EndOfFile)) { if (token.is(Token::Type::EndOfFile)) {
return {}; return {};
} else if (token.is(Token::Type::AtKeyword)) { } else if (token.is(Token::Type::AtKeyword)) {
auto at_rule = consume_an_at_rule(tokens); auto at_rule = consume_an_at_rule();
rule = convert_rule(at_rule); rule = convert_to_rule(at_rule);
} else { } else {
auto qualified_rule = consume_a_qualified_rule(tokens); auto qualified_rule = consume_a_qualified_rule(tokens);
if (!qualified_rule) if (!qualified_rule)
return {}; return {};
rule = convert_rule(*qualified_rule); rule = convert_to_rule(*qualified_rule);
} }
tokens.skip_whitespace(); tokens.skip_whitespace();
@ -887,7 +898,7 @@ NonnullRefPtrVector<CSSRule> Parser::parse_as_list_of_rules(TokenStream<T>& toke
NonnullRefPtrVector<CSSRule> rules; NonnullRefPtrVector<CSSRule> rules;
for (auto& rule : parsed_rules) { for (auto& rule : parsed_rules) {
auto converted_rule = convert_rule(rule); auto converted_rule = convert_to_rule(rule);
if (converted_rule) if (converted_rule)
rules.append(*converted_rule); rules.append(*converted_rule);
} }
@ -1007,9 +1018,77 @@ Vector<Vector<StyleComponentValueRule>> Parser::parse_as_comma_separated_list_of
return lists; return lists;
} }
RefPtr<CSSRule> Parser::convert_rule(NonnullRefPtr<StyleRule>) RefPtr<CSSRule> Parser::convert_to_rule(NonnullRefPtr<StyleRule> rule)
{ {
dbgln("Converting a rule: {}", rule->to_string());
if (rule->m_type == StyleRule::Type::At) {
dbgln("... It's an at rule");
} else {
dbgln("... It's a style rule");
auto prelude_stream = TokenStream(rule->m_prelude);
Vector<Selector> selectors = parse_a_selector(prelude_stream);
auto declaration = convert_to_declaration(*rule->m_block);
if (declaration && !selectors.is_empty())
return CSSStyleRule::create(move(selectors), move(*declaration));
}
dbgln("... discarding because it's invalid or unsupported.");
return {}; return {};
} }
RefPtr<CSSStyleDeclaration> Parser::convert_to_declaration(NonnullRefPtr<StyleBlockRule> block)
{
if (!block->is_curly())
return {};
Vector<StyleProperty> properties;
HashMap<String, StyleProperty> custom_properties;
auto stream = TokenStream(block->m_values);
auto declarations_and_at_rules = consume_a_list_of_declarations(stream);
for (auto& declaration_or_at_rule : declarations_and_at_rules) {
if (declaration_or_at_rule.is_at_rule()) {
dbgln("CSS::Parser::convert_to_declaration(): Skipping @ rule.");
continue;
}
auto& declaration = declaration_or_at_rule.m_declaration;
auto& property_name = declaration.m_name;
auto property_id = property_id_from_string(property_name);
if (property_id == CSS::PropertyID::Invalid && property_name.starts_with("--"))
property_id = CSS::PropertyID::Custom;
if (property_id == CSS::PropertyID::Invalid && !property_name.starts_with("-")) {
dbgln("CSS::Parser::convert_to_declaration(): Unrecognized property '{}'", property_name);
continue;
}
auto value_token_stream = TokenStream(declaration.m_values);
auto value = parse_css_value(property_id, value_token_stream);
if (!value) {
dbgln("CSS::Parser::convert_to_declaration(): Property '{}' has no value.", property_name);
continue;
}
if (property_id == CSS::PropertyID::Custom) {
custom_properties.set(property_name, CSS::StyleProperty { property_id, value.release_nonnull(), declaration.m_name, declaration.m_important });
} else {
properties.append(CSS::StyleProperty { property_id, value.release_nonnull(), {}, declaration.m_important });
}
}
return CSSStyleDeclaration::create(move(properties), move(custom_properties));
}
template<typename T>
RefPtr<StyleValue> Parser::parse_css_value(PropertyID, TokenStream<T>&)
{
// FIXME: This is mostly copied from the old, deprecated parser. It may or may not be to spec.
return {};
}
} }

View file

@ -24,6 +24,8 @@ class CSSStyleSheet;
class CSSRule; class CSSRule;
class CSSStyleRule; class CSSStyleRule;
struct StyleProperty; struct StyleProperty;
class StyleValue;
enum class PropertyID;
class ParsingContext { class ParsingContext {
public: public:
@ -120,6 +122,9 @@ public:
template<typename T> template<typename T>
Vector<Selector> parse_a_relative_selector(TokenStream<T>&); Vector<Selector> parse_a_relative_selector(TokenStream<T>&);
template<typename T>
RefPtr<StyleValue> parse_css_value(PropertyID, TokenStream<T>&);
// FIXME: https://drafts.csswg.org/css-backgrounds-3/ // FIXME: https://drafts.csswg.org/css-backgrounds-3/
static Optional<String> as_valid_background_repeat(String input) { return input; } static Optional<String> as_valid_background_repeat(String input) { return input; }
static Optional<String> as_valid_background_attachment(String input) { return input; } static Optional<String> as_valid_background_attachment(String input) { return input; }
@ -147,23 +152,24 @@ private:
template<typename T> template<typename T>
[[nodiscard]] Vector<DeclarationOrAtRule> consume_a_list_of_declarations(TokenStream<T>&); [[nodiscard]] Vector<DeclarationOrAtRule> consume_a_list_of_declarations(TokenStream<T>&);
Optional<StyleDeclarationRule> consume_a_declaration(); [[nodiscard]] Optional<StyleDeclarationRule> consume_a_declaration();
template<typename T> template<typename T>
Optional<StyleDeclarationRule> consume_a_declaration(TokenStream<T>&); [[nodiscard]] Optional<StyleDeclarationRule> consume_a_declaration(TokenStream<T>&);
StyleComponentValueRule consume_a_component_value(); [[nodiscard]] StyleComponentValueRule consume_a_component_value();
template<typename T> template<typename T>
StyleComponentValueRule consume_a_component_value(TokenStream<T>&); [[nodiscard]] StyleComponentValueRule consume_a_component_value(TokenStream<T>&);
NonnullRefPtr<StyleBlockRule> consume_a_simple_block(); [[nodiscard]] NonnullRefPtr<StyleBlockRule> consume_a_simple_block();
template<typename T> template<typename T>
NonnullRefPtr<StyleBlockRule> consume_a_simple_block(TokenStream<T>&); [[nodiscard]] NonnullRefPtr<StyleBlockRule> consume_a_simple_block(TokenStream<T>&);
NonnullRefPtr<StyleFunctionRule> consume_a_function(); [[nodiscard]] NonnullRefPtr<StyleFunctionRule> consume_a_function();
template<typename T> template<typename T>
NonnullRefPtr<StyleFunctionRule> consume_a_function(TokenStream<T>&); [[nodiscard]] NonnullRefPtr<StyleFunctionRule> consume_a_function(TokenStream<T>&);
RefPtr<CSSRule> convert_rule(NonnullRefPtr<StyleRule>); [[nodiscard]] RefPtr<CSSRule> convert_to_rule(NonnullRefPtr<StyleRule>);
[[nodiscard]] RefPtr<CSSStyleDeclaration> convert_to_declaration(NonnullRefPtr<StyleBlockRule>);
ParsingContext m_context; ParsingContext m_context;