diff options
author | Sam Atkins <atkinssj@serenityos.org> | 2022-02-11 13:08:27 +0000 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-02-11 21:38:27 +0100 |
commit | 82308fb71a5ec3748a46c09d167bf29cfa187fe4 (patch) | |
tree | 6f85031e0fa465f47784eacf039be74153f3fc12 /Userland/Libraries/LibWeb | |
parent | 784c3183f734f45672ec7ebc43d285f81a40e1a0 (diff) | |
download | serenity-82308fb71a5ec3748a46c09d167bf29cfa187fe4.zip |
LibWeb: Move SVG::PathDataParser into its own file and rename it
I've chosen the name `AttributeParser` since it parses data from
attributes. Rather than duplicate the parsing of numbers and other
basic types, let's make use of this existing parsing code for parsing
the data for `<line>`, `<polyline>`, etc.
Diffstat (limited to 'Userland/Libraries/LibWeb')
-rw-r--r-- | Userland/Libraries/LibWeb/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/SVG/AttributeParser.cpp | 367 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/SVG/AttributeParser.h | 85 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/SVG/SVGPathElement.cpp | 357 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/SVG/SVGPathElement.h | 71 |
5 files changed, 455 insertions, 426 deletions
diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 8c87504305..0090210ed1 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -265,6 +265,7 @@ set(SOURCES RequestIdleCallback/IdleDeadline.cpp ResizeObserver/ResizeObserver.cpp SVG/AttributeNames.cpp + SVG/AttributeParser.cpp SVG/SVGElement.cpp SVG/SVGGElement.cpp SVG/SVGGeometryElement.cpp diff --git a/Userland/Libraries/LibWeb/SVG/AttributeParser.cpp b/Userland/Libraries/LibWeb/SVG/AttributeParser.cpp new file mode 100644 index 0000000000..cc68f80345 --- /dev/null +++ b/Userland/Libraries/LibWeb/SVG/AttributeParser.cpp @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org> + * Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "AttributeParser.h" +#include <AK/StringBuilder.h> +#include <ctype.h> + +namespace Web::SVG { + +AttributeParser::AttributeParser(String source) + : m_source(move(source)) +{ +} + +Vector<PathInstruction> AttributeParser::parse_path_data() +{ + parse_whitespace(); + while (!done()) + parse_drawto(); + if (!m_instructions.is_empty() && m_instructions[0].type != PathInstructionType::Move) + VERIFY_NOT_REACHED(); + return m_instructions; +} + +void AttributeParser::parse_drawto() +{ + if (match('M') || match('m')) { + parse_moveto(); + } else if (match('Z') || match('z')) { + parse_closepath(); + } else if (match('L') || match('l')) { + parse_lineto(); + } else if (match('H') || match('h')) { + parse_horizontal_lineto(); + } else if (match('V') || match('v')) { + parse_vertical_lineto(); + } else if (match('C') || match('c')) { + parse_curveto(); + } else if (match('S') || match('s')) { + parse_smooth_curveto(); + } else if (match('Q') || match('q')) { + parse_quadratic_bezier_curveto(); + } else if (match('T') || match('t')) { + parse_smooth_quadratic_bezier_curveto(); + } else if (match('A') || match('a')) { + parse_elliptical_arc(); + } else { + dbgln("AttributeParser::parse_drawto failed to match: '{}'", ch()); + TODO(); + } +} + +void AttributeParser::parse_moveto() +{ + bool absolute = consume() == 'M'; + parse_whitespace(); + for (auto& pair : parse_coordinate_pair_sequence()) + m_instructions.append({ PathInstructionType::Move, absolute, pair }); +} + +void AttributeParser::parse_closepath() +{ + bool absolute = consume() == 'Z'; + parse_whitespace(); + m_instructions.append({ PathInstructionType::ClosePath, absolute, {} }); +} + +void AttributeParser::parse_lineto() +{ + bool absolute = consume() == 'L'; + parse_whitespace(); + for (auto& pair : parse_coordinate_pair_sequence()) + m_instructions.append({ PathInstructionType::Line, absolute, pair }); +} + +void AttributeParser::parse_horizontal_lineto() +{ + bool absolute = consume() == 'H'; + parse_whitespace(); + m_instructions.append({ PathInstructionType::HorizontalLine, absolute, parse_coordinate_sequence() }); +} + +void AttributeParser::parse_vertical_lineto() +{ + bool absolute = consume() == 'V'; + parse_whitespace(); + m_instructions.append({ PathInstructionType::VerticalLine, absolute, parse_coordinate_sequence() }); +} + +void AttributeParser::parse_curveto() +{ + bool absolute = consume() == 'C'; + parse_whitespace(); + + while (true) { + m_instructions.append({ PathInstructionType::Curve, absolute, parse_coordinate_pair_triplet() }); + if (match_comma_whitespace()) + parse_comma_whitespace(); + if (!match_coordinate()) + break; + } +} + +void AttributeParser::parse_smooth_curveto() +{ + bool absolute = consume() == 'S'; + parse_whitespace(); + + while (true) { + m_instructions.append({ PathInstructionType::SmoothCurve, absolute, parse_coordinate_pair_double() }); + if (match_comma_whitespace()) + parse_comma_whitespace(); + if (!match_coordinate()) + break; + } +} + +void AttributeParser::parse_quadratic_bezier_curveto() +{ + bool absolute = consume() == 'Q'; + parse_whitespace(); + + while (true) { + m_instructions.append({ PathInstructionType::QuadraticBezierCurve, absolute, parse_coordinate_pair_double() }); + if (match_comma_whitespace()) + parse_comma_whitespace(); + if (!match_coordinate()) + break; + } +} + +void AttributeParser::parse_smooth_quadratic_bezier_curveto() +{ + bool absolute = consume() == 'T'; + parse_whitespace(); + + while (true) { + m_instructions.append({ PathInstructionType::SmoothQuadraticBezierCurve, absolute, parse_coordinate_pair() }); + if (match_comma_whitespace()) + parse_comma_whitespace(); + if (!match_coordinate()) + break; + } +} + +void AttributeParser::parse_elliptical_arc() +{ + bool absolute = consume() == 'A'; + parse_whitespace(); + + while (true) { + m_instructions.append({ PathInstructionType::EllipticalArc, absolute, parse_elliptical_arg_argument() }); + if (match_comma_whitespace()) + parse_comma_whitespace(); + if (!match_coordinate()) + break; + } +} + +float AttributeParser::parse_coordinate() +{ + return parse_sign() * parse_number(); +} + +Vector<float> AttributeParser::parse_coordinate_pair() +{ + Vector<float> coordinates; + coordinates.append(parse_coordinate()); + if (match_comma_whitespace()) + parse_comma_whitespace(); + coordinates.append(parse_coordinate()); + return coordinates; +} + +Vector<float> AttributeParser::parse_coordinate_sequence() +{ + Vector<float> sequence; + while (true) { + sequence.append(parse_coordinate()); + if (match_comma_whitespace()) + parse_comma_whitespace(); + if (!match_comma_whitespace() && !match_coordinate()) + break; + } + return sequence; +} + +Vector<Vector<float>> AttributeParser::parse_coordinate_pair_sequence() +{ + Vector<Vector<float>> sequence; + while (true) { + sequence.append(parse_coordinate_pair()); + if (match_comma_whitespace()) + parse_comma_whitespace(); + if (!match_comma_whitespace() && !match_coordinate()) + break; + } + return sequence; +} + +Vector<float> AttributeParser::parse_coordinate_pair_double() +{ + Vector<float> coordinates; + coordinates.extend(parse_coordinate_pair()); + if (match_comma_whitespace()) + parse_comma_whitespace(); + coordinates.extend(parse_coordinate_pair()); + return coordinates; +} + +Vector<float> AttributeParser::parse_coordinate_pair_triplet() +{ + Vector<float> coordinates; + coordinates.extend(parse_coordinate_pair()); + if (match_comma_whitespace()) + parse_comma_whitespace(); + coordinates.extend(parse_coordinate_pair()); + if (match_comma_whitespace()) + parse_comma_whitespace(); + coordinates.extend(parse_coordinate_pair()); + return coordinates; +} + +Vector<float> AttributeParser::parse_elliptical_arg_argument() +{ + Vector<float> numbers; + numbers.append(parse_number()); + if (match_comma_whitespace()) + parse_comma_whitespace(); + numbers.append(parse_number()); + if (match_comma_whitespace()) + parse_comma_whitespace(); + numbers.append(parse_number()); + parse_comma_whitespace(); + numbers.append(parse_flag()); + if (match_comma_whitespace()) + parse_comma_whitespace(); + numbers.append(parse_flag()); + if (match_comma_whitespace()) + parse_comma_whitespace(); + numbers.extend(parse_coordinate_pair()); + + return numbers; +} + +void AttributeParser::parse_whitespace(bool must_match_once) +{ + bool matched = false; + while (!done() && match_whitespace()) { + consume(); + matched = true; + } + + VERIFY(!must_match_once || matched); +} + +void AttributeParser::parse_comma_whitespace() +{ + if (match(',')) { + consume(); + parse_whitespace(); + } else { + parse_whitespace(1); + if (match(',')) + consume(); + parse_whitespace(); + } +} + +float AttributeParser::parse_fractional_constant() +{ + StringBuilder builder; + bool floating_point = false; + + while (!done() && isdigit(ch())) + builder.append(consume()); + + if (match('.')) { + floating_point = true; + builder.append('.'); + consume(); + while (!done() && isdigit(ch())) + builder.append(consume()); + } else { + VERIFY(builder.length() > 0); + } + + if (floating_point) + return strtof(builder.to_string().characters(), nullptr); + return builder.to_string().to_int().value(); +} + +float AttributeParser::parse_number() +{ + auto number = parse_fractional_constant(); + + if (!match('e') && !match('E')) + return number; + consume(); + + auto exponent_sign = parse_sign(); + + StringBuilder exponent_builder; + while (!done() && isdigit(ch())) + exponent_builder.append(consume()); + VERIFY(exponent_builder.length() > 0); + + auto exponent = exponent_builder.to_string().to_int().value(); + + // Fast path: If the number is 0, there's no point in computing the exponentiation. + if (number == 0) + return number; + + if (exponent_sign < 0) { + for (int i = 0; i < exponent; ++i) { + number /= 10; + } + } else if (exponent_sign > 0) { + for (int i = 0; i < exponent; ++i) { + number *= 10; + } + } + + return number; +} + +float AttributeParser::parse_flag() +{ + if (!match('0') && !match('1')) + VERIFY_NOT_REACHED(); + return consume() - '0'; +} + +int AttributeParser::parse_sign() +{ + if (match('-')) { + consume(); + return -1; + } + if (match('+')) + consume(); + return 1; +} + +bool AttributeParser::match_whitespace() const +{ + if (done()) + return false; + char c = ch(); + return c == 0x9 || c == 0x20 || c == 0xa || c == 0xc || c == 0xd; +} + +bool AttributeParser::match_comma_whitespace() const +{ + return match_whitespace() || match(','); +} + +bool AttributeParser::match_coordinate() const +{ + return !done() && (isdigit(ch()) || ch() == '-' || ch() == '+' || ch() == '.'); +} + +} diff --git a/Userland/Libraries/LibWeb/SVG/AttributeParser.h b/Userland/Libraries/LibWeb/SVG/AttributeParser.h new file mode 100644 index 0000000000..61a2ca690d --- /dev/null +++ b/Userland/Libraries/LibWeb/SVG/AttributeParser.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org> + * Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/String.h> +#include <AK/Vector.h> + +namespace Web::SVG { + +enum class PathInstructionType { + Move, + ClosePath, + Line, + HorizontalLine, + VerticalLine, + Curve, + SmoothCurve, + QuadraticBezierCurve, + SmoothQuadraticBezierCurve, + EllipticalArc, + Invalid, +}; + +struct PathInstruction { + PathInstructionType type; + bool absolute; + Vector<float> data; +}; + +class AttributeParser final { +public: + AttributeParser(String source); + ~AttributeParser() = default; + + Vector<PathInstruction> parse_path_data(); + +private: + void parse_drawto(); + + void parse_moveto(); + void parse_closepath(); + void parse_lineto(); + void parse_horizontal_lineto(); + void parse_vertical_lineto(); + void parse_curveto(); + void parse_smooth_curveto(); + void parse_quadratic_bezier_curveto(); + void parse_smooth_quadratic_bezier_curveto(); + void parse_elliptical_arc(); + + float parse_coordinate(); + Vector<float> parse_coordinate_pair(); + Vector<float> parse_coordinate_sequence(); + Vector<Vector<float>> parse_coordinate_pair_sequence(); + Vector<float> parse_coordinate_pair_double(); + Vector<float> parse_coordinate_pair_triplet(); + Vector<float> parse_elliptical_arg_argument(); + void parse_whitespace(bool must_match_once = false); + void parse_comma_whitespace(); + float parse_fractional_constant(); + float parse_number(); + float parse_flag(); + // -1 if negative, +1 otherwise + int parse_sign(); + + bool match_whitespace() const; + bool match_comma_whitespace() const; + bool match_coordinate() const; + bool match(char c) const { return !done() && ch() == c; } + + bool done() const { return m_cursor >= m_source.length(); } + char ch() const { return m_source[m_cursor]; } + char consume() { return m_source[m_cursor++]; } + + String m_source; + size_t m_cursor { 0 }; + Vector<PathInstruction> m_instructions; +}; + +} diff --git a/Userland/Libraries/LibWeb/SVG/SVGPathElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGPathElement.cpp index f11852a3a6..bf64a60271 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGPathElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGPathElement.cpp @@ -6,14 +6,12 @@ #include <AK/Debug.h> #include <AK/ExtraMathConstants.h> -#include <AK/StringBuilder.h> #include <LibGfx/Painter.h> #include <LibGfx/Path.h> #include <LibWeb/DOM/Document.h> #include <LibWeb/DOM/Event.h> #include <LibWeb/Layout/SVGGeometryBox.h> #include <LibWeb/SVG/SVGPathElement.h> -#include <ctype.h> namespace Web::SVG { @@ -85,359 +83,6 @@ namespace Web::SVG { } } -PathDataParser::PathDataParser(const String& source) - : m_source(source) -{ -} - -Vector<PathInstruction> PathDataParser::parse() -{ - parse_whitespace(); - while (!done()) - parse_drawto(); - if (!m_instructions.is_empty() && m_instructions[0].type != PathInstructionType::Move) - VERIFY_NOT_REACHED(); - return m_instructions; -} - -void PathDataParser::parse_drawto() -{ - if (match('M') || match('m')) { - parse_moveto(); - } else if (match('Z') || match('z')) { - parse_closepath(); - } else if (match('L') || match('l')) { - parse_lineto(); - } else if (match('H') || match('h')) { - parse_horizontal_lineto(); - } else if (match('V') || match('v')) { - parse_vertical_lineto(); - } else if (match('C') || match('c')) { - parse_curveto(); - } else if (match('S') || match('s')) { - parse_smooth_curveto(); - } else if (match('Q') || match('q')) { - parse_quadratic_bezier_curveto(); - } else if (match('T') || match('t')) { - parse_smooth_quadratic_bezier_curveto(); - } else if (match('A') || match('a')) { - parse_elliptical_arc(); - } else { - dbgln("PathDataParser::parse_drawto failed to match: '{}'", ch()); - TODO(); - } -} - -void PathDataParser::parse_moveto() -{ - bool absolute = consume() == 'M'; - parse_whitespace(); - for (auto& pair : parse_coordinate_pair_sequence()) - m_instructions.append({ PathInstructionType::Move, absolute, pair }); -} - -void PathDataParser::parse_closepath() -{ - bool absolute = consume() == 'Z'; - parse_whitespace(); - m_instructions.append({ PathInstructionType::ClosePath, absolute, {} }); -} - -void PathDataParser::parse_lineto() -{ - bool absolute = consume() == 'L'; - parse_whitespace(); - for (auto& pair : parse_coordinate_pair_sequence()) - m_instructions.append({ PathInstructionType::Line, absolute, pair }); -} - -void PathDataParser::parse_horizontal_lineto() -{ - bool absolute = consume() == 'H'; - parse_whitespace(); - m_instructions.append({ PathInstructionType::HorizontalLine, absolute, parse_coordinate_sequence() }); -} - -void PathDataParser::parse_vertical_lineto() -{ - bool absolute = consume() == 'V'; - parse_whitespace(); - m_instructions.append({ PathInstructionType::VerticalLine, absolute, parse_coordinate_sequence() }); -} - -void PathDataParser::parse_curveto() -{ - bool absolute = consume() == 'C'; - parse_whitespace(); - - while (true) { - m_instructions.append({ PathInstructionType::Curve, absolute, parse_coordinate_pair_triplet() }); - if (match_comma_whitespace()) - parse_comma_whitespace(); - if (!match_coordinate()) - break; - } -} - -void PathDataParser::parse_smooth_curveto() -{ - bool absolute = consume() == 'S'; - parse_whitespace(); - - while (true) { - m_instructions.append({ PathInstructionType::SmoothCurve, absolute, parse_coordinate_pair_double() }); - if (match_comma_whitespace()) - parse_comma_whitespace(); - if (!match_coordinate()) - break; - } -} - -void PathDataParser::parse_quadratic_bezier_curveto() -{ - bool absolute = consume() == 'Q'; - parse_whitespace(); - - while (true) { - m_instructions.append({ PathInstructionType::QuadraticBezierCurve, absolute, parse_coordinate_pair_double() }); - if (match_comma_whitespace()) - parse_comma_whitespace(); - if (!match_coordinate()) - break; - } -} - -void PathDataParser::parse_smooth_quadratic_bezier_curveto() -{ - bool absolute = consume() == 'T'; - parse_whitespace(); - - while (true) { - m_instructions.append({ PathInstructionType::SmoothQuadraticBezierCurve, absolute, parse_coordinate_pair() }); - if (match_comma_whitespace()) - parse_comma_whitespace(); - if (!match_coordinate()) - break; - } -} - -void PathDataParser::parse_elliptical_arc() -{ - bool absolute = consume() == 'A'; - parse_whitespace(); - - while (true) { - m_instructions.append({ PathInstructionType::EllipticalArc, absolute, parse_elliptical_arg_argument() }); - if (match_comma_whitespace()) - parse_comma_whitespace(); - if (!match_coordinate()) - break; - } -} - -float PathDataParser::parse_coordinate() -{ - return parse_sign() * parse_number(); -} - -Vector<float> PathDataParser::parse_coordinate_pair() -{ - Vector<float> coordinates; - coordinates.append(parse_coordinate()); - if (match_comma_whitespace()) - parse_comma_whitespace(); - coordinates.append(parse_coordinate()); - return coordinates; -} - -Vector<float> PathDataParser::parse_coordinate_sequence() -{ - Vector<float> sequence; - while (true) { - sequence.append(parse_coordinate()); - if (match_comma_whitespace()) - parse_comma_whitespace(); - if (!match_comma_whitespace() && !match_coordinate()) - break; - } - return sequence; -} - -Vector<Vector<float>> PathDataParser::parse_coordinate_pair_sequence() -{ - Vector<Vector<float>> sequence; - while (true) { - sequence.append(parse_coordinate_pair()); - if (match_comma_whitespace()) - parse_comma_whitespace(); - if (!match_comma_whitespace() && !match_coordinate()) - break; - } - return sequence; -} - -Vector<float> PathDataParser::parse_coordinate_pair_double() -{ - Vector<float> coordinates; - coordinates.extend(parse_coordinate_pair()); - if (match_comma_whitespace()) - parse_comma_whitespace(); - coordinates.extend(parse_coordinate_pair()); - return coordinates; -} - -Vector<float> PathDataParser::parse_coordinate_pair_triplet() -{ - Vector<float> coordinates; - coordinates.extend(parse_coordinate_pair()); - if (match_comma_whitespace()) - parse_comma_whitespace(); - coordinates.extend(parse_coordinate_pair()); - if (match_comma_whitespace()) - parse_comma_whitespace(); - coordinates.extend(parse_coordinate_pair()); - return coordinates; -} - -Vector<float> PathDataParser::parse_elliptical_arg_argument() -{ - Vector<float> numbers; - numbers.append(parse_number()); - if (match_comma_whitespace()) - parse_comma_whitespace(); - numbers.append(parse_number()); - if (match_comma_whitespace()) - parse_comma_whitespace(); - numbers.append(parse_number()); - parse_comma_whitespace(); - numbers.append(parse_flag()); - if (match_comma_whitespace()) - parse_comma_whitespace(); - numbers.append(parse_flag()); - if (match_comma_whitespace()) - parse_comma_whitespace(); - numbers.extend(parse_coordinate_pair()); - - return numbers; -} - -void PathDataParser::parse_whitespace(bool must_match_once) -{ - bool matched = false; - while (!done() && match_whitespace()) { - consume(); - matched = true; - } - - VERIFY(!must_match_once || matched); -} - -void PathDataParser::parse_comma_whitespace() -{ - if (match(',')) { - consume(); - parse_whitespace(); - } else { - parse_whitespace(1); - if (match(',')) - consume(); - parse_whitespace(); - } -} - -float PathDataParser::parse_fractional_constant() -{ - StringBuilder builder; - bool floating_point = false; - - while (!done() && isdigit(ch())) - builder.append(consume()); - - if (match('.')) { - floating_point = true; - builder.append('.'); - consume(); - while (!done() && isdigit(ch())) - builder.append(consume()); - } else { - VERIFY(builder.length() > 0); - } - - if (floating_point) - return strtof(builder.to_string().characters(), nullptr); - return builder.to_string().to_int().value(); -} - -float PathDataParser::parse_number() -{ - auto number = parse_fractional_constant(); - - if (!match('e') && !match('E')) - return number; - consume(); - - auto exponent_sign = parse_sign(); - - StringBuilder exponent_builder; - while (!done() && isdigit(ch())) - exponent_builder.append(consume()); - VERIFY(exponent_builder.length() > 0); - - auto exponent = exponent_builder.to_string().to_int().value(); - - // Fast path: If the number is 0, there's no point in computing the exponentiation. - if (number == 0) - return number; - - if (exponent_sign < 0) { - for (int i = 0; i < exponent; ++i) { - number /= 10; - } - } else if (exponent_sign > 0) { - for (int i = 0; i < exponent; ++i) { - number *= 10; - } - } - - return number; -} - -float PathDataParser::parse_flag() -{ - if (!match('0') && !match('1')) - VERIFY_NOT_REACHED(); - return consume() - '0'; -} - -int PathDataParser::parse_sign() -{ - if (match('-')) { - consume(); - return -1; - } - if (match('+')) - consume(); - return 1; -} - -bool PathDataParser::match_whitespace() const -{ - if (done()) - return false; - char c = ch(); - return c == 0x9 || c == 0x20 || c == 0xa || c == 0xc || c == 0xd; -} - -bool PathDataParser::match_comma_whitespace() const -{ - return match_whitespace() || match(','); -} - -bool PathDataParser::match_coordinate() const -{ - return !done() && (isdigit(ch()) || ch() == '-' || ch() == '+' || ch() == '.'); -} - SVGPathElement::SVGPathElement(DOM::Document& document, QualifiedName qualified_name) : SVGGeometryElement(document, move(qualified_name)) { @@ -448,7 +93,7 @@ void SVGPathElement::parse_attribute(const FlyString& name, const String& value) SVGGeometryElement::parse_attribute(name, value); if (name == "d") - m_instructions = PathDataParser(value).parse(); + m_instructions = AttributeParser(value).parse_path_data(); } Gfx::Path& SVGPathElement::get_path() diff --git a/Userland/Libraries/LibWeb/SVG/SVGPathElement.h b/Userland/Libraries/LibWeb/SVG/SVGPathElement.h index 8fb31d51f0..45f0406e8a 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGPathElement.h +++ b/Userland/Libraries/LibWeb/SVG/SVGPathElement.h @@ -8,80 +8,11 @@ #include <LibGfx/Bitmap.h> #include <LibWeb/HTML/HTMLElement.h> +#include <LibWeb/SVG/AttributeParser.h> #include <LibWeb/SVG/SVGGeometryElement.h> namespace Web::SVG { -enum class PathInstructionType { - Move, - ClosePath, - Line, - HorizontalLine, - VerticalLine, - Curve, - SmoothCurve, - QuadraticBezierCurve, - SmoothQuadraticBezierCurve, - EllipticalArc, - Invalid, -}; - -struct PathInstruction { - PathInstructionType type; - bool absolute; - Vector<float> data; -}; - -class PathDataParser final { -public: - PathDataParser(const String& source); - ~PathDataParser() = default; - - Vector<PathInstruction> parse(); - -private: - void parse_drawto(); - - void parse_moveto(); - void parse_closepath(); - void parse_lineto(); - void parse_horizontal_lineto(); - void parse_vertical_lineto(); - void parse_curveto(); - void parse_smooth_curveto(); - void parse_quadratic_bezier_curveto(); - void parse_smooth_quadratic_bezier_curveto(); - void parse_elliptical_arc(); - - float parse_coordinate(); - Vector<float> parse_coordinate_pair(); - Vector<float> parse_coordinate_sequence(); - Vector<Vector<float>> parse_coordinate_pair_sequence(); - Vector<float> parse_coordinate_pair_double(); - Vector<float> parse_coordinate_pair_triplet(); - Vector<float> parse_elliptical_arg_argument(); - void parse_whitespace(bool must_match_once = false); - void parse_comma_whitespace(); - float parse_fractional_constant(); - float parse_number(); - float parse_flag(); - // -1 if negative, +1 otherwise - int parse_sign(); - - bool match_whitespace() const; - bool match_comma_whitespace() const; - bool match_coordinate() const; - bool match(char c) const { return !done() && ch() == c; } - - bool done() const { return m_cursor >= m_source.length(); } - char ch() const { return m_source[m_cursor]; } - char consume() { return m_source[m_cursor++]; } - - String m_source; - size_t m_cursor { 0 }; - Vector<PathInstruction> m_instructions; -}; - class SVGPathElement final : public SVGGeometryElement { public: using WrapperType = Bindings::SVGPathElementWrapper; |