From 075bdfdef86d7178ba0ffe8b9974184a10d888fd Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 26 Mar 2022 11:38:51 +0100 Subject: [PATCH] LibWeb: Add a parser for the HTML "dimension value" microsyntax --- .../Libraries/LibWeb/CSS/Parser/Parser.cpp | 89 +++++++++++++++++++ Userland/Libraries/LibWeb/CSS/Parser/Parser.h | 1 + 2 files changed, 90 insertions(+) diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index f44d53a120..5497bda008 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -5153,4 +5153,93 @@ RefPtr parse_html_length(DOM::Document const& document, StringV return parse_css_value(CSS::ParsingContext(document), string); } +// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#current-dimension-value +static RefPtr parse_current_dimension_value(float value, Utf8View input, Utf8View::Iterator position) +{ + // 1. If position is past the end of input, then return value as a length. + if (position == input.end()) + return CSS::LengthStyleValue::create(CSS::Length::make_px(value)); + + // 2. If the code point at position within input is U+0025 (%), then return value as a percentage. + if (*position == '%') + return CSS::PercentageStyleValue::create(CSS::Percentage(value)); + + // 3. Return value as a length. + return CSS::LengthStyleValue::create(CSS::Length::make_px(value)); +} + +// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-dimension-values +RefPtr parse_dimension_value(StringView string) +{ + // 1. Let input be the string being parsed. + auto input = Utf8View(string); + if (!input.validate()) + return nullptr; + + // 2. Let position be a position variable for input, initially pointing at the start of input. + auto position = input.begin(); + + // 3. Skip ASCII whitespace within input given position. + while (position != input.end() && is_ascii_space(*position)) + ++position; + + // 4. If position is past the end of input or the code point at position within input is not an ASCII digit, + // then return failure. + if (position == input.end() || !is_ascii_digit(*position)) + return nullptr; + + // 5. Collect a sequence of code points that are ASCII digits from input given position, + // and interpret the resulting sequence as a base-ten integer. Let value be that number. + StringBuilder number_string; + while (position != input.end() && is_ascii_digit(*position)) { + number_string.append(*position); + ++position; + } + auto integer_value = number_string.string_view().to_int(); + + // 6. If position is past the end of input, then return value as a length. + if (position == input.end()) + return CSS::LengthStyleValue::create(CSS::Length::make_px(*integer_value)); + + float value = *integer_value; + + // 7. If the code point at position within input is U+002E (.), then: + if (*position == '.') { + // 1. Advance position by 1. + ++position; + + // 2. If position is past the end of input or the code point at position within input is not an ASCII digit, + // then return the current dimension value with value, input, and position. + if (position == input.end() || !is_ascii_digit(*position)) + return parse_current_dimension_value(value, input, position); + + // 3. Let divisor have the value 1. + float divisor = 1; + + // 4. While true: + while (true) { + // 1. Multiply divisor by ten. + divisor *= 10; + + // 2. Add the value of the code point at position within input, + // interpreted as a base-ten digit (0..9) and divided by divisor, to value. + value += (*position - '0') / divisor; + + // 3. Advance position by 1. + ++position; + + // 4. If position is past the end of input, then return value as a length. + if (position == input.end()) + return CSS::LengthStyleValue::create(CSS::Length::make_px(value)); + + // 5. If the code point at position within input is not an ASCII digit, then break. + if (!is_ascii_digit(*position)) + break; + } + } + + // 8. Return the current dimension value with value, input, and position. + return parse_current_dimension_value(value, input, position); +} + } diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h index d3d13cb10f..e04c44c430 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.h @@ -359,5 +359,6 @@ NonnullRefPtrVector parse_media_query_list(CSS::ParsingContext RefPtr parse_css_supports(CSS::ParsingContext const&, StringView); RefPtr parse_html_length(DOM::Document const&, StringView); +RefPtr parse_dimension_value(StringView); }