diff options
author | MacDue <macdue@dueutil.tech> | 2023-04-17 01:20:24 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2023-04-17 07:32:31 +0200 |
commit | 5df4e64eb7e7a2556d282b634d66adf7d8edc5ec (patch) | |
tree | 343eb6dca7a90f903fe82ea536a1fc23684bbc08 /Userland/Libraries/LibWeb/SVG | |
parent | 5a12e9f22292cd6b6393b5d4b09165ebdee3a8bb (diff) | |
download | serenity-5df4e64eb7e7a2556d282b634d66adf7d8edc5ec.zip |
LibWeb: Implement SVG `preserveAspectRatio` attribute
This attribute is used to define how the viewBox should be scaled.
Previously the behaviour implemented was that of "xMidYMid meet", now
all of them work (expect none :P).
With this the Discord login backend is now correctly scaled/positioned.
This also brings our SVG code a little closer to the spec! With spec
comments and all :^)
(Minor non-visible update to layout tests)
Diffstat (limited to 'Userland/Libraries/LibWeb/SVG')
-rw-r--r-- | Userland/Libraries/LibWeb/SVG/AttributeParser.cpp | 73 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/SVG/AttributeParser.h | 22 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/SVG/SVGSVGElement.cpp | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/SVG/SVGSVGElement.h | 3 |
4 files changed, 94 insertions, 6 deletions
diff --git a/Userland/Libraries/LibWeb/SVG/AttributeParser.cpp b/Userland/Libraries/LibWeb/SVG/AttributeParser.cpp index 05ca7537f4..644f2843a5 100644 --- a/Userland/Libraries/LibWeb/SVG/AttributeParser.cpp +++ b/Userland/Libraries/LibWeb/SVG/AttributeParser.cpp @@ -397,16 +397,77 @@ int AttributeParser::parse_sign() return 1; } -// https://drafts.csswg.org/css-transforms/#svg-syntax -Optional<Vector<Transform>> AttributeParser::parse_transform() +static bool whitespace(char c) { // wsp: // Either a U+000A LINE FEED, U+000D CARRIAGE RETURN, U+0009 CHARACTER TABULATION, or U+0020 SPACE. - auto wsp = [](char c) { - return AK::first_is_one_of(c, '\n', '\r', '\t', '\f', ' '); - }; + return AK::first_is_one_of(c, '\n', '\r', '\t', '\f', ' '); +} + +// https://svgwg.org/svg2-draft/coords.html#PreserveAspectRatioAttribute +Optional<PreserveAspectRatio> AttributeParser::parse_preserve_aspect_ratio(StringView input) +{ + // <align> <meetOrSlice>? + GenericLexer lexer { input }; + lexer.ignore_while(whitespace); + auto align_string = lexer.consume_until(whitespace); + if (align_string.is_empty()) + return {}; + lexer.ignore_while(whitespace); + auto meet_or_slice_string = lexer.consume_until(whitespace); + + // <align> = + // none + // | xMinYMin | xMidYMin | xMaxYMin + // | xMinYMid | xMidYMid | xMaxYMid + // | xMinYMax | xMidYMax | xMaxYMax + auto align = [&]() -> Optional<PreserveAspectRatio::Align> { + if (align_string == "none"sv) + return PreserveAspectRatio::Align::None; + if (align_string == "xMinYMin"sv) + return PreserveAspectRatio::Align::xMinYMin; + if (align_string == "xMidYMin"sv) + return PreserveAspectRatio::Align::xMidYMin; + if (align_string == "xMaxYMin"sv) + return PreserveAspectRatio::Align::xMaxYMin; + if (align_string == "xMinYMid"sv) + return PreserveAspectRatio::Align::xMinYMid; + if (align_string == "xMidYMid"sv) + return PreserveAspectRatio::Align::xMidYMid; + if (align_string == "xMaxYMid"sv) + return PreserveAspectRatio::Align::xMaxYMid; + if (align_string == "xMinYMax"sv) + return PreserveAspectRatio::Align::xMinYMax; + if (align_string == "xMidYMax"sv) + return PreserveAspectRatio::Align::xMidYMax; + if (align_string == "xMaxYMax"sv) + return PreserveAspectRatio::Align::xMaxYMax; + return {}; + }(); + + if (!align.has_value()) + return {}; + + // <meetOrSlice> = meet | slice + auto meet_or_slice = [&]() -> Optional<PreserveAspectRatio::MeetOrSlice> { + if (meet_or_slice_string.is_empty() || meet_or_slice_string == "meet"sv) + return PreserveAspectRatio::MeetOrSlice::Meet; + if (meet_or_slice_string == "slice"sv) + return PreserveAspectRatio::MeetOrSlice::Slice; + return {}; + }(); + + if (!meet_or_slice.has_value()) + return {}; + + return PreserveAspectRatio { *align, *meet_or_slice }; +} + +// https://drafts.csswg.org/css-transforms/#svg-syntax +Optional<Vector<Transform>> AttributeParser::parse_transform() +{ auto consume_whitespace = [&] { - m_lexer.consume_while(wsp); + m_lexer.ignore_while(whitespace); }; auto consume_comma_whitespace = [&] { diff --git a/Userland/Libraries/LibWeb/SVG/AttributeParser.h b/Userland/Libraries/LibWeb/SVG/AttributeParser.h index e7b5e075c5..164b184a9a 100644 --- a/Userland/Libraries/LibWeb/SVG/AttributeParser.h +++ b/Userland/Libraries/LibWeb/SVG/AttributeParser.h @@ -67,6 +67,27 @@ struct Transform { Operation operation; }; +struct PreserveAspectRatio { + enum class Align { + None, + xMinYMin, + xMidYMin, + xMaxYMin, + xMinYMid, + xMidYMid, + xMaxYMid, + xMinYMax, + xMidYMax, + xMaxYMax + }; + enum class MeetOrSlice { + Meet, + Slice + }; + Align align { Align::xMidYMid }; + MeetOrSlice meet_or_slice { MeetOrSlice::Meet }; +}; + class AttributeParser final { public: ~AttributeParser() = default; @@ -77,6 +98,7 @@ public: static Vector<Gfx::FloatPoint> parse_points(StringView input); static Vector<PathInstruction> parse_path_data(StringView input); static Optional<Vector<Transform>> parse_transform(StringView input); + static Optional<PreserveAspectRatio> parse_preserve_aspect_ratio(StringView input); private: AttributeParser(StringView source); diff --git a/Userland/Libraries/LibWeb/SVG/SVGSVGElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGSVGElement.cpp index abfab45dbf..69b89bdfbc 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGSVGElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGSVGElement.cpp @@ -73,6 +73,8 @@ void SVGSVGElement::parse_attribute(DeprecatedFlyString const& name, DeprecatedS if (name.equals_ignoring_ascii_case(SVG::AttributeNames::viewBox)) m_view_box = try_parse_view_box(value); + if (name.equals_ignoring_ascii_case(SVG::AttributeNames::preserveAspectRatio)) + m_preserve_aspect_ratio = AttributeParser::parse_preserve_aspect_ratio(value); } } diff --git a/Userland/Libraries/LibWeb/SVG/SVGSVGElement.h b/Userland/Libraries/LibWeb/SVG/SVGSVGElement.h index 7f03fda104..a214843f8f 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGSVGElement.h +++ b/Userland/Libraries/LibWeb/SVG/SVGSVGElement.h @@ -7,6 +7,7 @@ #pragma once #include <LibGfx/Bitmap.h> +#include <LibWeb/SVG/AttributeParser.h> #include <LibWeb/SVG/SVGGraphicsElement.h> #include <LibWeb/SVG/ViewBox.h> @@ -24,6 +25,7 @@ public: virtual bool is_svg_container() const override { return true; } Optional<ViewBox> const& view_box() const { return m_view_box; } + Optional<PreserveAspectRatio> const& preserve_aspect_ratio() const { return m_preserve_aspect_ratio; } private: SVGSVGElement(DOM::Document&, DOM::QualifiedName); @@ -35,6 +37,7 @@ private: virtual void parse_attribute(DeprecatedFlyString const& name, DeprecatedString const& value) override; Optional<ViewBox> m_view_box; + Optional<PreserveAspectRatio> m_preserve_aspect_ratio; }; } |