summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb
diff options
context:
space:
mode:
authorTobias Christiansen <tobi@tobyase.de>2021-06-11 23:19:03 +0200
committerAli Mohammad Pur <Ali.mpfard@gmail.com>2021-07-24 03:02:07 +0430
commit328afa32c6ed02c7f62b13af7626b0575ac35745 (patch)
treee8c2ae569cd36205db0d5178ef96041059b83ad4 /Userland/Libraries/LibWeb
parente3b68039bfe38a7e48f32e6d39ed307e22f3146a (diff)
downloadserenity-328afa32c6ed02c7f62b13af7626b0575ac35745.zip
LibWeb: Add the parsing to the calc() handling
This patch adds the parsing of previously tokenized calc() expressions into the CSS-Parser. The tokens are processed into a complete CalculatedStyleValue.
Diffstat (limited to 'Userland/Libraries/LibWeb')
-rw-r--r--Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp301
1 files changed, 281 insertions, 20 deletions
diff --git a/Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp
index 0a5754272f..1b509512e5 100644
--- a/Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp
+++ b/Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp
@@ -7,6 +7,7 @@
#include <AK/GenericLexer.h>
#include <AK/HashMap.h>
+#include <AK/NonnullOwnPtr.h>
#include <AK/SourceLocation.h>
#include <LibWeb/CSS/CSSImportRule.h>
#include <LibWeb/CSS/CSSRule.h>
@@ -280,26 +281,38 @@ static StringView isolate_calc_expression(const StringView& value)
return value.substring_view(5, substring_length);
}
-static Optional<NonnullOwnPtr<CSS::CalculatedStyleValue::CalcSum>> parse_calc_expression(const StringView& expression_string)
+struct CalcToken {
+ enum class Type {
+ Undefined,
+ Number,
+ Unit,
+ Whitespace,
+ Plus,
+ Minus,
+ Asterisk,
+ Slash,
+ OpenBracket,
+ CloseBracket,
+ } type { Type::Undefined };
+ String value {};
+};
+
+static void eat_white_space(Vector<CalcToken>&);
+static Optional<CSS::CalculatedStyleValue::CalcValue> parse_calc_value(Vector<CalcToken>&);
+static OwnPtr<CSS::CalculatedStyleValue::CalcProductPartWithOperator> parse_calc_product_part_with_operator(Vector<CalcToken>&);
+static Optional<CSS::CalculatedStyleValue::CalcNumberValue> parse_calc_number_value(Vector<CalcToken>&);
+static OwnPtr<CSS::CalculatedStyleValue::CalcProduct> parse_calc_product(Vector<CalcToken>&);
+static OwnPtr<CSS::CalculatedStyleValue::CalcSumPartWithOperator> parse_calc_sum_part_with_operator(Vector<CalcToken>&);
+static OwnPtr<CSS::CalculatedStyleValue::CalcSum> parse_calc_sum(Vector<CalcToken>&);
+static OwnPtr<CSS::CalculatedStyleValue::CalcNumberSum> parse_calc_number_sum(Vector<CalcToken>& tokens);
+static OwnPtr<CSS::CalculatedStyleValue::CalcNumberProductPartWithOperator> parse_calc_number_product_part_with_operator(Vector<CalcToken>& tokens);
+static OwnPtr<CSS::CalculatedStyleValue::CalcNumberProduct> parse_calc_number_product(Vector<CalcToken>& tokens);
+static OwnPtr<CSS::CalculatedStyleValue::CalcNumberSumPartWithOperator> parse_calc_number_sum_part_with_operator(Vector<CalcToken>& tokens);
+
+static OwnPtr<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);
@@ -367,7 +380,255 @@ static Optional<NonnullOwnPtr<CSS::CalculatedStyleValue::CalcSum>> parse_calc_ex
VERIFY_NOT_REACHED();
}
- return {};
+ // Then, parse
+
+ return parse_calc_sum(tokens);
+}
+
+static void eat_white_space(Vector<CalcToken>& tokens)
+{
+ while (tokens.size() > 0 && tokens.first().type == CalcToken::Type::Whitespace)
+ tokens.take_first();
+}
+
+static Optional<CSS::CalculatedStyleValue::CalcValue> parse_calc_value(Vector<CalcToken>& tokens)
+{
+ auto current_token = tokens.take_first();
+
+ if (current_token.type == CalcToken::Type::OpenBracket) {
+ auto parsed_calc_sum = parse_calc_sum(tokens);
+ if (!parsed_calc_sum)
+ return {};
+ return (CSS::CalculatedStyleValue::CalcValue) { parsed_calc_sum.release_nonnull() };
+ }
+
+ if (current_token.type != CalcToken::Type::Number)
+ return {};
+
+ auto try_the_number = try_parse_float(current_token.value);
+ if (!try_the_number.has_value())
+ return {};
+
+ float the_number = try_the_number.value();
+
+ if (tokens.first().type != CalcToken::Type::Unit)
+ return (CSS::CalculatedStyleValue::CalcValue) { the_number };
+
+ auto type = length_type_from_unit(tokens.take_first().value);
+
+ if (type == CSS::Length::Type::Undefined)
+ return {};
+
+ return (CSS::CalculatedStyleValue::CalcValue) { CSS::Length(the_number, type) };
+}
+
+static OwnPtr<CSS::CalculatedStyleValue::CalcProductPartWithOperator> parse_calc_product_part_with_operator(Vector<CalcToken>& tokens)
+{
+ auto product_with_operator = make<CSS::CalculatedStyleValue::CalcProductPartWithOperator>();
+
+ eat_white_space(tokens);
+
+ auto op = tokens.first();
+ if (op.type == CalcToken::Type::Asterisk) {
+ tokens.take_first();
+ eat_white_space(tokens);
+ product_with_operator->op = CSS::CalculatedStyleValue::CalcProductPartWithOperator::Multiply;
+ auto parsed_calc_value = parse_calc_value(tokens);
+ if (!parsed_calc_value.has_value())
+ return nullptr;
+ product_with_operator->value = { parsed_calc_value.release_value() };
+
+ } else if (op.type == CalcToken::Type::Slash) {
+ tokens.take_first();
+ eat_white_space(tokens);
+ product_with_operator->op = CSS::CalculatedStyleValue::CalcProductPartWithOperator::Divide;
+ auto parsed_calc_number_value = parse_calc_number_value(tokens);
+ if (!parsed_calc_number_value.has_value())
+ return nullptr;
+ product_with_operator->value = { parsed_calc_number_value.release_value() };
+ } else {
+ return nullptr;
+ }
+
+ return product_with_operator;
+}
+
+static OwnPtr<CSS::CalculatedStyleValue::CalcNumberProductPartWithOperator> parse_calc_number_product_part_with_operator(Vector<CalcToken>& tokens)
+{
+ auto number_product_with_operator = make<CSS::CalculatedStyleValue::CalcNumberProductPartWithOperator>();
+
+ eat_white_space(tokens);
+
+ auto op = tokens.first();
+ if (op.type == CalcToken::Type::Asterisk) {
+ tokens.take_first();
+ eat_white_space(tokens);
+ number_product_with_operator->op = CSS::CalculatedStyleValue::CalcNumberProductPartWithOperator::Multiply;
+ } else if (op.type == CalcToken::Type::Slash) {
+ tokens.take_first();
+ eat_white_space(tokens);
+ number_product_with_operator->op = CSS::CalculatedStyleValue::CalcNumberProductPartWithOperator::Divide;
+ } else {
+ return nullptr;
+ }
+ auto parsed_calc_value = parse_calc_number_value(tokens);
+ if (!parsed_calc_value.has_value())
+ return nullptr;
+ number_product_with_operator->value = parsed_calc_value.release_value();
+
+ return number_product_with_operator;
+}
+
+static OwnPtr<CSS::CalculatedStyleValue::CalcNumberProduct> parse_calc_number_product(Vector<CalcToken>& tokens)
+{
+ auto calc_number_product = make<CSS::CalculatedStyleValue::CalcNumberProduct>();
+
+ auto first_calc_number_value_or_error = parse_calc_number_value(tokens);
+ if (!first_calc_number_value_or_error.has_value())
+ return nullptr;
+ calc_number_product->first_calc_number_value = first_calc_number_value_or_error.release_value();
+
+ while (tokens.size() > 0) {
+ auto number_product_with_operator = parse_calc_number_product_part_with_operator(tokens);
+ if (!number_product_with_operator)
+ break;
+ calc_number_product->zero_or_more_additional_calc_number_values.append(number_product_with_operator.release_nonnull());
+ }
+
+ return calc_number_product;
+}
+
+static OwnPtr<CSS::CalculatedStyleValue::CalcNumberSumPartWithOperator> parse_calc_number_sum_part_with_operator(Vector<CalcToken>& tokens)
+{
+ if (tokens.size() < 3)
+ return nullptr;
+ if (!((tokens[0].type == CalcToken::Type::Plus
+ || tokens[0].type == CalcToken::Type::Minus)
+ && tokens[1].type == CalcToken::Type::Whitespace))
+ return nullptr;
+
+ auto op_token = tokens.take_first().type;
+ tokens.take_first(); // Whitespace;
+
+ CSS::CalculatedStyleValue::CalcNumberSumPartWithOperator::Operation op;
+ if (op_token == CalcToken::Type::Plus)
+ op = CSS::CalculatedStyleValue::CalcNumberSumPartWithOperator::Operation::Add;
+ else if (op_token == CalcToken::Type::Minus)
+ op = CSS::CalculatedStyleValue::CalcNumberSumPartWithOperator::Operation::Subtract;
+ else
+ return nullptr;
+
+ auto calc_number_product = parse_calc_number_product(tokens);
+ if (!calc_number_product)
+ return nullptr;
+ return make<CSS::CalculatedStyleValue::CalcNumberSumPartWithOperator>(op, calc_number_product.release_nonnull());
+}
+
+static OwnPtr<CSS::CalculatedStyleValue::CalcNumberSum> parse_calc_number_sum(Vector<CalcToken>& tokens)
+{
+ if (tokens.take_first().type != CalcToken::Type::OpenBracket)
+ return nullptr;
+
+ auto first_calc_number_product_or_error = parse_calc_number_product(tokens);
+ if (!first_calc_number_product_or_error)
+ return nullptr;
+
+ NonnullOwnPtrVector<CSS::CalculatedStyleValue::CalcNumberSumPartWithOperator> additional {};
+ while (tokens.size() > 0 && tokens.first().type != CalcToken::Type::CloseBracket) {
+ auto calc_sum_part = parse_calc_number_sum_part_with_operator(tokens);
+ if (!calc_sum_part)
+ return nullptr;
+ additional.append(calc_sum_part.release_nonnull());
+ }
+
+ eat_white_space(tokens);
+
+ auto calc_number_sum = make<CSS::CalculatedStyleValue::CalcNumberSum>(first_calc_number_product_or_error.release_nonnull(), move(additional));
+ return calc_number_sum;
+}
+
+static Optional<CSS::CalculatedStyleValue::CalcNumberValue> parse_calc_number_value(Vector<CalcToken>& tokens)
+{
+ if (tokens.first().type == CalcToken::Type::OpenBracket) {
+ auto calc_number_sum = parse_calc_number_sum(tokens);
+ if (calc_number_sum)
+ return { calc_number_sum.release_nonnull() };
+ }
+
+ if (tokens.first().type != CalcToken::Type::Number)
+ return {};
+
+ auto the_number_string = tokens.take_first().value;
+ auto try_the_number = try_parse_float(the_number_string);
+ if (!try_the_number.has_value())
+ return {};
+ return try_the_number.value();
+}
+
+static OwnPtr<CSS::CalculatedStyleValue::CalcProduct> parse_calc_product(Vector<CalcToken>& tokens)
+{
+ auto calc_product = make<CSS::CalculatedStyleValue::CalcProduct>();
+
+ auto first_calc_value_or_error = parse_calc_value(tokens);
+ if (!first_calc_value_or_error.has_value())
+ return nullptr;
+ calc_product->first_calc_value = first_calc_value_or_error.release_value();
+
+ while (tokens.size() > 0) {
+ auto product_with_operator = parse_calc_product_part_with_operator(tokens);
+ if (!product_with_operator)
+ break;
+ calc_product->zero_or_more_additional_calc_values.append(product_with_operator.release_nonnull());
+ }
+
+ return calc_product;
+}
+
+static OwnPtr<CSS::CalculatedStyleValue::CalcSumPartWithOperator> parse_calc_sum_part_with_operator(Vector<CalcToken>& tokens)
+{
+ // The following has to have the shape of <Whitespace><+ or -><Whitespace>
+ // But the first whitespace gets eaten in parse_calc_product_part_with_operator().
+ if (tokens.size() < 3)
+ return {};
+ if (!((tokens[0].type == CalcToken::Type::Plus
+ || tokens[0].type == CalcToken::Type::Minus)
+ && tokens[1].type == CalcToken::Type::Whitespace))
+ return nullptr;
+
+ auto op_token = tokens.take_first().type;
+ tokens.take_first(); // Whitespace;
+
+ CSS::CalculatedStyleValue::CalcSumPartWithOperator::Operation op;
+ if (op_token == CalcToken::Type::Plus)
+ op = CSS::CalculatedStyleValue::CalcSumPartWithOperator::Operation::Add;
+ else if (op_token == CalcToken::Type::Minus)
+ op = CSS::CalculatedStyleValue::CalcSumPartWithOperator::Operation::Subtract;
+ else
+ return nullptr;
+
+ auto calc_product = parse_calc_product(tokens);
+ if (!calc_product)
+ return nullptr;
+ return make<CSS::CalculatedStyleValue::CalcSumPartWithOperator>(op, calc_product.release_nonnull());
+};
+
+static OwnPtr<CSS::CalculatedStyleValue::CalcSum> parse_calc_sum(Vector<CalcToken>& tokens)
+{
+ auto parsed_calc_product = parse_calc_product(tokens);
+ if (!parsed_calc_product)
+ return nullptr;
+
+ NonnullOwnPtrVector<CSS::CalculatedStyleValue::CalcSumPartWithOperator> additional {};
+ while (tokens.size() > 0 && tokens.first().type != CalcToken::Type::CloseBracket) {
+ auto calc_sum_part = parse_calc_sum_part_with_operator(tokens);
+ if (!calc_sum_part)
+ return nullptr;
+ additional.append(calc_sum_part.release_nonnull());
+ }
+
+ eat_white_space(tokens);
+
+ return make<CSS::CalculatedStyleValue::CalcSum>(parsed_calc_product.release_nonnull(), move(additional));
}
RefPtr<CSS::StyleValue> parse_css_value(const CSS::DeprecatedParsingContext& context, const StringView& string, CSS::PropertyID property_id)
@@ -401,8 +662,8 @@ RefPtr<CSS::StyleValue> parse_css_value(const CSS::DeprecatedParsingContext& con
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());
+ if (calc_expression)
+ return CSS::CalculatedStyleValue::create(calc_expression_string, calc_expression.release_nonnull());
}
auto value_id = CSS::value_id_from_string(string);