1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 15:38:10 +00:00

LibWeb: Added simple parsing for (at)import rules

For now, the parsing is very crude, and parses only the document url.
The meta queries for the import are ignored.
This commit is contained in:
Sviatoslav Peleshko 2021-02-21 18:36:34 +02:00 committed by Andreas Kling
parent 04d67d0239
commit 54617e1a91
8 changed files with 248 additions and 24 deletions

View file

@ -25,6 +25,7 @@
*/
#include <AK/HashMap.h>
#include <LibWeb/CSS/CSSImportRule.h>
#include <LibWeb/CSS/CSSRule.h>
#include <LibWeb/CSS/Parser/CSSParser.h>
#include <LibWeb/CSS/PropertyID.h>
@ -70,6 +71,11 @@ bool ParsingContext::in_quirks_mode() const
return m_document ? m_document->in_quirks_mode() : false;
}
URL ParsingContext::complete_url(const String& addr) const
{
return m_document ? m_document->url().complete_url(addr) : URL::create_with_url_or_path(addr);
}
}
static Optional<Color> parse_css_color(const CSS::ParsingContext&, const StringView& view)
@ -664,6 +670,11 @@ public:
return ch && ch != '!' && ch != ';' && ch != '}';
}
bool is_valid_string_quotes_char(char ch) const
{
return ch == '\'' || ch == '\"';
}
struct ValueAndImportant {
String value;
bool important { false };
@ -785,31 +796,8 @@ public:
}
}
void parse_rule()
void parse_style_rule()
{
consume_whitespace_or_comments();
if (!peek())
return;
// FIXME: We ignore @-rules for now.
if (peek() == '@') {
while (peek() != '{')
consume_one();
int level = 0;
for (;;) {
auto ch = consume_one();
if (ch == '{') {
++level;
} else if (ch == '}') {
--level;
if (level == 0)
break;
}
}
consume_whitespace_or_comments();
return;
}
parse_selector_list();
if (!consume_specific('{')) {
PARSE_ERROR();
@ -820,7 +808,129 @@ public:
PARSE_ERROR();
return;
}
rules.append(CSS::StyleRule::create(move(current_rule.selectors), CSS::StyleDeclaration::create(move(current_rule.properties))));
}
Optional<String> parse_string()
{
if (!is_valid_string_quotes_char(peek())) {
PARSE_ERROR();
return {};
}
char end_char = consume_one();
buffer.clear();
while (peek() && peek() != end_char) {
if (peek() == '\\') {
consume_specific('\\');
if (peek() == 0)
break;
}
buffer.append(consume_one());
}
String string_value(String::copy(buffer));
buffer.clear();
if (consume_specific(end_char)) {
return { string_value };
}
return {};
}
Optional<String> parse_url()
{
if (is_valid_string_quotes_char(peek()))
return parse_string();
buffer.clear();
while (peek() && peek() != ')')
buffer.append(consume_one());
String url_value(String::copy(buffer));
buffer.clear();
if (peek() == ')')
return { url_value };
return {};
}
void parse_at_import_rule()
{
consume_whitespace_or_comments();
Optional<String> imported_address;
if (is_valid_string_quotes_char(peek())) {
imported_address = parse_string();
} else if (next_is("url")) {
consume_specific('u');
consume_specific('r');
consume_specific('l');
consume_whitespace_or_comments();
if (!consume_specific('('))
return;
imported_address = parse_url();
if (!consume_specific(')'))
return;
} else {
PARSE_ERROR();
return;
}
if (imported_address.has_value())
rules.append(CSS::CSSImportRule::create(m_context.complete_url(imported_address.value())));
// FIXME: We ignore possilbe media query list
while (peek() && peek() != ';')
consume_one();
consume_specific(';');
}
void parse_at_rule()
{
HashMap<String, void (CSSParser::*)()> at_rules_parsers({ { "@import", &CSSParser::parse_at_import_rule } });
for (const auto& rule_parser_pair : at_rules_parsers) {
if (next_is(rule_parser_pair.key.characters())) {
for (char c : rule_parser_pair.key) {
consume_specific(c);
}
(this->*(rule_parser_pair.value))();
return;
}
}
// FIXME: We ignore other @-rules completely for now.
while (peek() != 0 && peek() != '{')
consume_one();
int level = 0;
for (;;) {
auto ch = consume_one();
if (ch == '{') {
++level;
} else if (ch == '}') {
--level;
if (level == 0)
break;
}
}
}
void parse_rule()
{
consume_whitespace_or_comments();
if (!peek())
return;
if (peek() == '@') {
parse_at_rule();
} else {
parse_style_rule();
}
consume_whitespace_or_comments();
}