diff --git a/Userland/Libraries/LibWeb/SVG/AttributeParser.cpp b/Userland/Libraries/LibWeb/SVG/AttributeParser.cpp index f4149eb2a5..66f8b5124b 100644 --- a/Userland/Libraries/LibWeb/SVG/AttributeParser.cpp +++ b/Userland/Libraries/LibWeb/SVG/AttributeParser.cpp @@ -497,15 +497,17 @@ Optional AttributeParser::parse_preserve_aspect_ratio(Strin } // https://svgwg.org/svg2-draft/pservers.html#LinearGradientElementGradientUnitsAttribute -Optional AttributeParser::parse_gradient_units(StringView input) +// https://drafts.fxtf.org/css-masking/#element-attrdef-mask-maskunits +// https://drafts.fxtf.org/css-masking/#element-attrdef-mask-maskcontentunits +Optional AttributeParser::parse_units(StringView input) { GenericLexer lexer { input }; lexer.ignore_while(whitespace); auto gradient_units_string = lexer.consume_until(whitespace); if (gradient_units_string == "userSpaceOnUse"sv) - return GradientUnits::UserSpaceOnUse; + return SVGUnits::UserSpaceOnUse; if (gradient_units_string == "objectBoundingBox"sv) - return GradientUnits::ObjectBoundingBox; + return SVGUnits::ObjectBoundingBox; return {}; } diff --git a/Userland/Libraries/LibWeb/SVG/AttributeParser.h b/Userland/Libraries/LibWeb/SVG/AttributeParser.h index 773e886970..6de3128704 100644 --- a/Userland/Libraries/LibWeb/SVG/AttributeParser.h +++ b/Userland/Libraries/LibWeb/SVG/AttributeParser.h @@ -88,11 +88,15 @@ struct PreserveAspectRatio { MeetOrSlice meet_or_slice { MeetOrSlice::Meet }; }; -enum class GradientUnits { +enum class SVGUnits { ObjectBoundingBox, UserSpaceOnUse }; +using GradientUnits = SVGUnits; +using MaskUnits = SVGUnits; +using MaskContentUnits = SVGUnits; + enum class SpreadMethod { Pad, Repeat, @@ -149,7 +153,7 @@ public: static Vector parse_path_data(StringView input); static Optional> parse_transform(StringView input); static Optional parse_preserve_aspect_ratio(StringView input); - static Optional parse_gradient_units(StringView input); + static Optional parse_units(StringView input); static Optional parse_spread_method(StringView input); private: diff --git a/Userland/Libraries/LibWeb/SVG/SVGGradientElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGGradientElement.cpp index a4800b5b1e..1939546e1d 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGGradientElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGGradientElement.cpp @@ -21,7 +21,7 @@ void SVGGradientElement::attribute_changed(DeprecatedFlyString const& name, Depr { SVGElement::attribute_changed(name, value); if (name == AttributeNames::gradientUnits) { - m_gradient_units = AttributeParser::parse_gradient_units(value); + m_gradient_units = AttributeParser::parse_units(value); } else if (name == AttributeNames::spreadMethod) { m_spread_method = AttributeParser::parse_spread_method(value); } else if (name == AttributeNames::gradientTransform) { diff --git a/Userland/Libraries/LibWeb/SVG/SVGMaskElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGMaskElement.cpp index 5fdefd6967..b113e1a011 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGMaskElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGMaskElement.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2023, Andreas Kling + * Copyright (c) 2023, MacDue * * SPDX-License-Identifier: BSD-2-Clause */ @@ -7,6 +8,7 @@ #include #include #include +#include #include namespace Web::SVG { @@ -29,4 +31,34 @@ JS::GCPtr SVGMaskElement::create_layout_node(NonnullRefPtr(document(), *this, move(style)); } +void SVGMaskElement::attribute_changed(DeprecatedFlyString const& name, DeprecatedString const& value) +{ + SVGGraphicsElement::attribute_changed(name, value); + if (name == AttributeNames::maskUnits) { + m_mask_units = AttributeParser::parse_units(value); + } else if (name == AttributeNames::maskContentUnits) { + m_mask_content_units = AttributeParser::parse_units(value); + } +} + +MaskContentUnits SVGMaskElement::mask_content_units() const +{ + return m_mask_content_units.value_or(MaskContentUnits::UserSpaceOnUse); +} + +MaskUnits SVGMaskElement::mask_units() const +{ + return m_mask_units.value_or(MaskUnits::ObjectBoundingBox); +} + +CSSPixelRect SVGMaskElement::resolve_masking_area(CSSPixelRect const& mask_target) const +{ + if (mask_units() == SVG::MaskUnits::UserSpaceOnUse) { + dbgln("SVG: maskUnits=userSpaceOnUse is not supported"); + return {}; + } + // TODO: Resolve this based on the x, y, width, and height of the mask. + return mask_target.inflated(mask_target.size().scaled(CSSPixels(2) / 10)); +} + } diff --git a/Userland/Libraries/LibWeb/SVG/SVGMaskElement.h b/Userland/Libraries/LibWeb/SVG/SVGMaskElement.h index b957890716..031284bf2e 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGMaskElement.h +++ b/Userland/Libraries/LibWeb/SVG/SVGMaskElement.h @@ -6,6 +6,7 @@ #pragma once +#include #include namespace Web::SVG { @@ -16,11 +17,21 @@ class SVGMaskElement final : public SVGGraphicsElement { public: virtual ~SVGMaskElement() override; + virtual void attribute_changed(DeprecatedFlyString const& name, DeprecatedString const& value) override; + virtual JS::GCPtr create_layout_node(NonnullRefPtr) override; + CSSPixelRect resolve_masking_area(CSSPixelRect const& mask_target) const; + + MaskContentUnits mask_content_units() const; + MaskUnits mask_units() const; + private: SVGMaskElement(DOM::Document&, DOM::QualifiedName); virtual void initialize(JS::Realm&) override; + + Optional m_mask_content_units = {}; + Optional m_mask_units = {}; }; }