diff options
author | Tobias Christiansen <tobi@tobyase.de> | 2021-07-22 23:02:40 +0200 |
---|---|---|
committer | Ali Mohammad Pur <Ali.mpfard@gmail.com> | 2021-07-24 03:02:07 +0430 |
commit | 7a4c8e0b76ad01508c6a86d8337ab01769684972 (patch) | |
tree | 457b8f2ba56d120e7ffa58f0701daa4407a2895a /Userland/Libraries/LibWeb/CSS/Parser | |
parent | f8bf6ae9119896426a536824ef0224f3d3bf18af (diff) | |
download | serenity-7a4c8e0b76ad01508c6a86d8337ab01769684972.zip |
LibWeb: Add tokenization of calc expression
Here the first step in understanding a calc() expression is taken:
Finding the start of an expression and tokenizong it.
Diffstat (limited to 'Userland/Libraries/LibWeb/CSS/Parser')
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp index 2fd9ed2b5a..9dd35bfffd 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp @@ -1,9 +1,11 @@ /* * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> + * Copyright (c) 2021, Tobias Christiansen <tobi@tobyase.de> * * SPDX-License-Identifier: BSD-2-Clause */ +#include <AK/GenericLexer.h> #include <AK/HashMap.h> #include <AK/SourceLocation.h> #include <LibWeb/CSS/CSSImportRule.h> @@ -229,6 +231,104 @@ static StringView parse_custom_property_name(const StringView& value) return value.substring_view(4, substring_length); } +static StringView isolate_calc_expression(const StringView& value) +{ + if (!value.starts_with("calc(") || !value.ends_with(")")) + return {}; + auto substring_length = value.length() - 5 - 1; + return value.substring_view(5, substring_length); +} + +static Optional<NonnullOwnPtr<CSS::CalculatedStyleValue::CalcSum>> parse_calc_expression(const StringView& expression_string) +{ + // First, tokenize + + struct CalcToken { + enum class Type { + Undefined, + Number, + Unit, + Whitespace, + Plus, + Minus, + Asterisk, + Slash, + OpenBracket, + CloseBracket, + } type { Type::Undefined }; + String value {}; + }; + + Vector<CalcToken> tokens; + + GenericLexer lexer(expression_string); + while (!lexer.is_eof()) { + // Number + if (((lexer.next_is('+') || lexer.next_is('-')) && !isspace(lexer.peek(1))) + || lexer.next_is('.') + || lexer.next_is(isdigit)) { + + auto number = lexer.consume_while(is_any_of("+-.0123456789")); + tokens.append(CalcToken { CalcToken::Type ::Number, number.to_string() }); + continue; + } + + auto ch = lexer.consume(); + + if (isspace(ch)) { + tokens.append(CalcToken { CalcToken::Type::Whitespace }); + continue; + } + + if (ch == '%') { + tokens.append(CalcToken { CalcToken::Type::Unit, "%" }); + continue; + } + + if (ch == '+') { + tokens.append(CalcToken { CalcToken::Type::Plus }); + continue; + } + + if (ch == '-') { + tokens.append(CalcToken { CalcToken::Type::Minus }); + continue; + } + + if (ch == '*') { + tokens.append(CalcToken { CalcToken::Type::Asterisk }); + continue; + } + + if (ch == '/') { + tokens.append(CalcToken { CalcToken::Type::Slash }); + continue; + } + + if (ch == '(') { + tokens.append(CalcToken { CalcToken::Type::OpenBracket }); + continue; + } + + if (ch == ')') { + tokens.append(CalcToken { CalcToken::Type::CloseBracket }); + continue; + } + + // Unit + if (isalpha(ch)) { + lexer.retreat(); + auto unit = lexer.consume_while(isalpha); + tokens.append(CalcToken { CalcToken::Type::Unit, unit.to_string() }); + continue; + } + + VERIFY_NOT_REACHED(); + } + + return {}; +} + RefPtr<CSS::StyleValue> parse_css_value(const CSS::DeprecatedParsingContext& context, const StringView& string, CSS::PropertyID property_id) { bool is_bad_length = false; @@ -257,6 +357,12 @@ RefPtr<CSS::StyleValue> parse_css_value(const CSS::DeprecatedParsingContext& con return CSS::LengthStyleValue::create(CSS::Length::make_auto()); if (string.starts_with("var(")) return CSS::CustomStyleValue::create(parse_custom_property_name(string)); + if (string.starts_with("calc(")) { + auto calc_expression_string = isolate_calc_expression(string); + auto calc_expression = parse_calc_expression(calc_expression_string); + if (calc_expression.has_value()) + return CSS::CalculatedStyleValue::create(calc_expression_string, calc_expression.release_value()); + } auto value_id = CSS::value_id_from_string(string); if (value_id != CSS::ValueID::Invalid) |