diff options
author | Sam Atkins <atkinssj@gmail.com> | 2021-07-08 21:53:22 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-07-11 23:19:56 +0200 |
commit | 28e8bb9b1d3dfd0cbdf88c46924094cfc55b7e0c (patch) | |
tree | e48177d292203e33b26589e7725f2f44f5d12da1 /Userland/Libraries/LibWeb | |
parent | 2c843798462931277770b41f5624feba738234d5 (diff) | |
download | serenity-28e8bb9b1d3dfd0cbdf88c46924094cfc55b7e0c.zip |
LibWeb: Convert style declarations and at rules into CSSRules
Diffstat (limited to 'Userland/Libraries/LibWeb')
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp | 127 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Parser/Parser.h | 24 |
2 files changed, 118 insertions, 33 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index 88c11f91aa..6db27f766a 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -158,12 +158,14 @@ NonnullRefPtr<CSSStyleSheet> Parser::parse_as_stylesheet(TokenStream<T>& tokens) NonnullRefPtrVector<CSSRule> rules; for (auto& raw_rule : parser_rules) { - auto rule = convert_rule(raw_rule); + auto rule = convert_to_rule(raw_rule); if (rule) rules.append(*rule); } - return CSSStyleSheet::create(rules); + auto stylesheet = CSSStyleSheet::create(rules); + dump_sheet(stylesheet); + return stylesheet; } Vector<Selector> Parser::parse_a_selector() @@ -574,10 +576,11 @@ NonnullRefPtr<StyleRule> Parser::consume_an_at_rule() template<typename T> 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); - rule->m_name = initial.m_value.to_string(); + rule->m_name = ((Token)name_ident).ident(); for (;;) { auto token = tokens.next_token(); @@ -636,9 +639,10 @@ RefPtr<StyleRule> Parser::consume_a_qualified_rule(TokenStream<T>& tokens) 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> @@ -655,6 +659,11 @@ StyleComponentValueRule Parser::consume_a_component_value(TokenStream<T>& tokens return StyleComponentValueRule(token); } +StyleComponentValueRule Parser::consume_a_component_value() +{ + return consume_a_component_value(m_token_stream); +} + NonnullRefPtr<StyleBlockRule> Parser::consume_a_simple_block() { return consume_a_simple_block(m_token_stream); @@ -740,7 +749,6 @@ Optional<StyleDeclarationRule> Parser::consume_a_declaration(TokenStream<T>& tok tokens.skip_whitespace(); auto colon = tokens.next_token(); - if (!colon.is(Token::Type::Colon)) { log_parse_error(); return {}; @@ -755,18 +763,20 @@ Optional<StyleDeclarationRule> Parser::consume_a_declaration(TokenStream<T>& tok declaration.m_values.append(consume_a_component_value(tokens)); } - auto second_last = declaration.m_values.at(declaration.m_values.size() - 2); - auto last = declaration.m_values.at(declaration.m_values.size() - 1); + if (declaration.m_values.size() >= 2) { + 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) { - auto last_token = last.m_token; - auto second_last_token = second_last.m_token; + if (second_last.m_type == StyleComponentValueRule::ComponentType::Token && last.m_type == StyleComponentValueRule::ComponentType::Token) { + auto last_token = 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 (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() - 1); - declaration.m_important = true; + 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")) { + declaration.m_values.remove(declaration.m_values.size() - 2); + declaration.m_values.remove(declaration.m_values.size() - 1); + declaration.m_important = true; + } } } } @@ -810,7 +820,7 @@ Vector<DeclarationOrAtRule> Parser::consume_a_list_of_declarations(TokenStream<T if (token.is(Token::Type::Ident)) { Vector<StyleComponentValueRule> temp; - temp.append(StyleComponentValueRule(token)); + temp.append(token); for (;;) { auto peek = tokens.peek_token(); @@ -825,13 +835,14 @@ Vector<DeclarationOrAtRule> Parser::consume_a_list_of_declarations(TokenStream<T if (maybe_declaration.has_value()) { list.append(DeclarationOrAtRule(maybe_declaration.value())); } + continue; } log_parse_error(); tokens.reconsume_current_input_token(); auto peek = tokens.peek_token(); 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)) { return {}; } else if (token.is(Token::Type::AtKeyword)) { - auto at_rule = consume_an_at_rule(tokens); - rule = convert_rule(at_rule); + auto at_rule = consume_an_at_rule(); + rule = convert_to_rule(at_rule); } else { auto qualified_rule = consume_a_qualified_rule(tokens); if (!qualified_rule) return {}; - rule = convert_rule(*qualified_rule); + rule = convert_to_rule(*qualified_rule); } tokens.skip_whitespace(); @@ -887,7 +898,7 @@ NonnullRefPtrVector<CSSRule> Parser::parse_as_list_of_rules(TokenStream<T>& toke NonnullRefPtrVector<CSSRule> rules; for (auto& rule : parsed_rules) { - auto converted_rule = convert_rule(rule); + auto converted_rule = convert_to_rule(rule); if (converted_rule) rules.append(*converted_rule); } @@ -1007,9 +1018,77 @@ Vector<Vector<StyleComponentValueRule>> Parser::parse_as_comma_separated_list_of 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 {}; } +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 {}; +} } diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h index 09f694e513..4727f2cea4 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -24,6 +24,8 @@ class CSSStyleSheet; class CSSRule; class CSSStyleRule; struct StyleProperty; +class StyleValue; +enum class PropertyID; class ParsingContext { public: @@ -120,6 +122,9 @@ public: template<typename 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/ static Optional<String> as_valid_background_repeat(String input) { return input; } static Optional<String> as_valid_background_attachment(String input) { return input; } @@ -147,23 +152,24 @@ private: template<typename 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> - 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> - 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> - 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> - 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; |