summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb/SVG
diff options
context:
space:
mode:
authorMacDue <macdue@dueutil.tech>2023-04-17 01:20:24 +0100
committerAndreas Kling <kling@serenityos.org>2023-04-17 07:32:31 +0200
commit5df4e64eb7e7a2556d282b634d66adf7d8edc5ec (patch)
tree343eb6dca7a90f903fe82ea536a1fc23684bbc08 /Userland/Libraries/LibWeb/SVG
parent5a12e9f22292cd6b6393b5d4b09165ebdee3a8bb (diff)
downloadserenity-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.cpp73
-rw-r--r--Userland/Libraries/LibWeb/SVG/AttributeParser.h22
-rw-r--r--Userland/Libraries/LibWeb/SVG/SVGSVGElement.cpp2
-rw-r--r--Userland/Libraries/LibWeb/SVG/SVGSVGElement.h3
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;
};
}