summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb
diff options
context:
space:
mode:
authorTobias Christiansen <tobi@tobyase.de>2021-07-22 23:02:40 +0200
committerAli Mohammad Pur <Ali.mpfard@gmail.com>2021-07-24 03:02:07 +0430
commit7a4c8e0b76ad01508c6a86d8337ab01769684972 (patch)
tree457b8f2ba56d120e7ffa58f0701daa4407a2895a /Userland/Libraries/LibWeb
parentf8bf6ae9119896426a536824ef0224f3d3bf18af (diff)
downloadserenity-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')
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp106
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)