summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb
diff options
context:
space:
mode:
authorSam Atkins <atkinssj@gmail.com>2021-07-22 17:51:07 +0100
committerAndreas Kling <kling@serenityos.org>2021-07-31 00:18:11 +0200
commit7439fbd896627f1546bb4123a25e777de2de35c8 (patch)
treea76b820f10673d197eca5197fd1d02964550ebd1 /Userland/Libraries/LibWeb
parent8b2e76b838757a7528ddb64de47ef10efe042f98 (diff)
downloadserenity-7439fbd896627f1546bb4123a25e777de2de35c8.zip
LibWeb: Get CSS @import rules working in new parser
Also added css-import.html, which tests the 3 syntax variations on `@import` statements. Note that the optional media-query parameter to `@import` is not handled yet.
Diffstat (limited to 'Userland/Libraries/LibWeb')
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp90
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/Parser.h1
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/Token.h6
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/Tokenizer.cpp2
4 files changed, 61 insertions, 38 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
index dff94a6b87..a304fb239b 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
+++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp
@@ -131,8 +131,13 @@ template<typename T>
void TokenStream<T>::dump_all_tokens()
{
dbgln("Dumping all tokens:");
- for (auto& token : m_tokens)
- dbgln("{}", token.to_debug_string());
+ for (size_t i = 0; i < m_tokens.size(); ++i) {
+ auto& token = m_tokens[i];
+ if ((i - 1) == (size_t)m_iterator_offset)
+ dbgln("-> {}", token.to_debug_string());
+ else
+ dbgln(" {}", token.to_debug_string());
+ }
}
Parser::Parser(ParsingContext const& context, StringView const& input, String const& encoding)
@@ -623,10 +628,10 @@ NonnullRefPtr<StyleRule> Parser::consume_an_at_rule(TokenStream<T>& tokens)
dbgln_if(CSS_PARSER_TRACE, "Parser::consume_an_at_rule");
auto name_ident = tokens.next_token();
- VERIFY(name_ident.is(Token::Type::Ident));
+ VERIFY(name_ident.is(Token::Type::AtKeyword));
NonnullRefPtr<StyleRule> rule = create<StyleRule>(StyleRule::Type::At);
- rule->m_name = ((Token)name_ident).ident();
+ rule->m_name = ((Token)name_ident).at_keyword();
for (;;) {
auto token = tokens.next_token();
@@ -1112,6 +1117,31 @@ Vector<Vector<StyleComponentValueRule>> Parser::parse_as_comma_separated_list_of
return lists;
}
+Optional<URL> Parser::parse_url_function(ParsingContext const& context, StyleComponentValueRule const& component_value)
+{
+ // FIXME: Handle list of media queries. https://www.w3.org/TR/css-cascade-3/#conditional-import
+
+ if (component_value.is(Token::Type::Url))
+ return context.complete_url(component_value.token().url());
+ if (component_value.is_function() && component_value.function().name().equals_ignoring_case("url")) {
+ auto& function_values = component_value.function().values();
+ // FIXME: Handle url-modifiers. https://www.w3.org/TR/css-values-4/#url-modifiers
+ for (size_t i = 0; i < function_values.size(); ++i) {
+ auto& value = function_values[i];
+ if (value.is(Token::Type::Whitespace))
+ continue;
+ if (value.is(Token::Type::String)) {
+ // FIXME: RFC2397
+ if (value.token().string().starts_with("data:"))
+ break;
+ return context.complete_url(value.token().string());
+ }
+ }
+ }
+
+ return {};
+}
+
RefPtr<CSSRule> Parser::convert_to_rule(NonnullRefPtr<StyleRule> rule)
{
dbgln_if(CSS_PARSER_TRACE, "Parser::convert_to_rule");
@@ -1119,25 +1149,26 @@ RefPtr<CSSRule> Parser::convert_to_rule(NonnullRefPtr<StyleRule> rule)
if (rule->m_type == StyleRule::Type::At) {
if (rule->m_name.equals_ignoring_case("import"sv) && !rule->prelude().is_empty()) {
- Optional<String> url;
- auto url_token = rule->prelude().first();
- if (url_token.is_function()) {
- auto& function = url_token.function();
- if (function.name().equals_ignoring_case("url"sv) && !function.values().is_empty()) {
- auto& argument_token = url_token.function().values().first();
- if (argument_token.is(Token::Type::String))
- url = argument_token.token().string();
- else
- dbgln("First argument to url() was not a string: '{}'", argument_token.to_debug_string());
+ Optional<URL> url;
+ for (auto& token : rule->prelude()) {
+ if (token.is(Token::Type::Whitespace))
+ continue;
+
+ if (token.is(Token::Type::String)) {
+ url = m_context.complete_url(token.token().string());
+ } else {
+ url = parse_url_function(m_context, token);
}
- }
- if (url_token.is(Token::Type::String))
- url = url_token.token().string();
+ // FIXME: Handle list of media queries. https://www.w3.org/TR/css-cascade-3/#conditional-import
+ if (url.has_value())
+ break;
+ }
- // FIXME: Handle list of media queries. https://www.w3.org/TR/css-cascade-3/#conditional-import
if (url.has_value())
- return CSSImportRule::create(m_context.complete_url(url.value()));
+ return CSSImportRule::create(url.value());
+ else
+ dbgln("Unable to parse url from @import rule");
} else {
dbgln("Unrecognized CSS at-rule: {}", rule->m_name);
}
@@ -1591,24 +1622,9 @@ RefPtr<StyleValue> Parser::parse_string_value(ParsingContext const&, StyleCompon
RefPtr<StyleValue> Parser::parse_image_value(ParsingContext const& context, StyleComponentValueRule const& component_value)
{
- if (component_value.is(Token::Type::Url))
- return ImageStyleValue::create(context.complete_url(component_value.token().url()), *context.document());
- if (component_value.is_function() && component_value.function().name().equals_ignoring_case("url")) {
- auto& function_values = component_value.function().values();
- // FIXME: Handle url-modifiers. https://www.w3.org/TR/css-values-4/#url-modifiers
- for (size_t i = 0; i < function_values.size(); ++i) {
- auto& value = function_values[i];
- if (value.is(Token::Type::Whitespace))
- continue;
- if (value.is(Token::Type::String)) {
- // FIXME: RFC2397
- if (value.token().string().starts_with("data:"))
- continue;
-
- return ImageStyleValue::create(context.complete_url(value.token().string()), *context.document());
- }
- }
- }
+ auto url = parse_url_function(context, component_value);
+ if (url.has_value())
+ return ImageStyleValue::create(url.value(), *context.document());
// FIXME: Handle gradients.
return {};
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h
index efa823f3ff..76be69bab9 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h
+++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h
@@ -167,6 +167,7 @@ private:
[[nodiscard]] Optional<StyleProperty> convert_to_style_property(StyleDeclarationRule&);
static Optional<float> try_parse_float(StringView string);
+ static Optional<URL> parse_url_function(ParsingContext const&, StyleComponentValueRule const&);
static RefPtr<StyleValue> parse_keyword_or_custom_value(ParsingContext const&, StyleComponentValueRule const&);
static RefPtr<StyleValue> parse_length_value(ParsingContext const&, StyleComponentValueRule const&);
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Token.h b/Userland/Libraries/LibWeb/CSS/Parser/Token.h
index ec6146114f..e244025973 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/Token.h
+++ b/Userland/Libraries/LibWeb/CSS/Parser/Token.h
@@ -82,6 +82,12 @@ public:
return m_value.string_view();
}
+ StringView at_keyword() const
+ {
+ VERIFY(m_type == Type::AtKeyword);
+ return m_value.string_view();
+ }
+
bool is(NumberType number_type) const { return is(Token::Type::Number) && m_number_type == number_type; }
int integer() const
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Tokenizer.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Tokenizer.cpp
index 5746278890..4e7d53cdc6 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/Tokenizer.cpp
+++ b/Userland/Libraries/LibWeb/CSS/Parser/Tokenizer.cpp
@@ -846,7 +846,7 @@ Token Tokenizer::consume_a_token()
if (would_start_an_identifier()) {
auto name = consume_a_name();
- return create_value_token(Token::Type::AtKeyword, input);
+ return create_value_token(Token::Type::AtKeyword, name);
}
return create_value_token(Token::Type::Delim, input);