diff --git a/Tests/LibWeb/Layout/expected/svg/svg-as-image-implicit-viewbox.txt b/Tests/LibWeb/Layout/expected/svg/svg-as-image-implicit-viewbox.txt new file mode 100644 index 0000000000..dcfe4ecf2f --- /dev/null +++ b/Tests/LibWeb/Layout/expected/svg/svg-as-image-implicit-viewbox.txt @@ -0,0 +1,8 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x116 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x100 children: not-inline + ImageBox at (8,8) content-size 50x100 children: not-inline + (SVG-as-image isolated context) + Viewport <#document> at (0,0) content-size 50x100 children: inline + SVGSVGBox at (0,0) content-size 50x100 [SVG] children: not-inline + SVGGeometryBox at (0,0) content-size 50x100 children: not-inline diff --git a/Tests/LibWeb/Layout/input/svg/svg-as-image-implicit-viewbox.html b/Tests/LibWeb/Layout/input/svg/svg-as-image-implicit-viewbox.html new file mode 100644 index 0000000000..33f3a29c09 --- /dev/null +++ b/Tests/LibWeb/Layout/input/svg/svg-as-image-implicit-viewbox.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Tests/LibWeb/Layout/input/svg/svg-without-viewbox.svg b/Tests/LibWeb/Layout/input/svg/svg-without-viewbox.svg new file mode 100644 index 0000000000..590f332e9c --- /dev/null +++ b/Tests/LibWeb/Layout/input/svg/svg-without-viewbox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Userland/Libraries/LibWeb/Layout/SVGFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/SVGFormattingContext.cpp index 19d9e88294..31ff3ca003 100644 --- a/Userland/Libraries/LibWeb/Layout/SVGFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/SVGFormattingContext.cpp @@ -159,7 +159,7 @@ void SVGFormattingContext::run(Box const& box, LayoutMode layout_mode, Available auto path_transform = dom_node.get_transform(); double viewbox_scale = 1; - auto& maybe_view_box = svg_svg_element.view_box(); + auto maybe_view_box = svg_svg_element.view_box(); if (maybe_view_box.has_value()) { // FIXME: This should allow just one of width or height to be specified. // E.g. We should be able to layout where height is unspecified/auto. diff --git a/Userland/Libraries/LibWeb/SVG/SVGSVGElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGSVGElement.cpp index 2bb3b5a902..873439c917 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGSVGElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGSVGElement.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -77,6 +78,53 @@ void SVGSVGElement::parse_attribute(DeprecatedFlyString const& name, DeprecatedS 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); + if (name.equals_ignoring_ascii_case(SVG::AttributeNames::width) || name.equals_ignoring_ascii_case(SVG::AttributeNames::height)) + update_fallback_view_box_for_svg_as_image(); +} + +void SVGSVGElement::update_fallback_view_box_for_svg_as_image() +{ + // AD-HOC: This creates a fallback viewBox for SVGs used as images. + // If the element has width and height, but no viewBox, + // we fall back to a synthetic viewBox="0 0 width height". + + Optional width; + Optional height; + + auto width_attribute = attribute(SVG::AttributeNames::width); + auto parsing_context = CSS::Parser::ParsingContext { document() }; + if (auto width_value = parse_css_value(parsing_context, attribute(Web::HTML::AttributeNames::width), CSS::PropertyID::Width).release_value_but_fixme_should_propagate_errors()) { + if (width_value->is_length() && width_value->as_length().length().is_absolute()) + width = width_value->as_length().length().absolute_length_to_px().to_double(); + } + + auto height_attribute = attribute(SVG::AttributeNames::height); + if (auto height_value = parse_css_value(parsing_context, attribute(Web::HTML::AttributeNames::height), CSS::PropertyID::Height).release_value_but_fixme_should_propagate_errors()) { + if (height_value->is_length() && height_value->as_length().length().is_absolute()) + height = height_value->as_length().length().absolute_length_to_px().to_double(); + } + + if (width.has_value() && height.has_value()) { + m_fallback_view_box_for_svg_as_image = ViewBox { 0, 0, width.value(), height.value() }; + } else { + m_fallback_view_box_for_svg_as_image = {}; + } +} + +void SVGSVGElement::set_fallback_view_box_for_svg_as_image(Optional view_box) +{ + m_fallback_view_box_for_svg_as_image = view_box; +} + +Optional SVGSVGElement::view_box() const +{ + if (m_view_box.has_value()) + return m_view_box; + + if (m_fallback_view_box_for_svg_as_image.has_value()) + return m_fallback_view_box_for_svg_as_image; + + return {}; } } diff --git a/Userland/Libraries/LibWeb/SVG/SVGSVGElement.h b/Userland/Libraries/LibWeb/SVG/SVGSVGElement.h index a214843f8f..12e96c1929 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGSVGElement.h +++ b/Userland/Libraries/LibWeb/SVG/SVGSVGElement.h @@ -24,9 +24,11 @@ public: virtual bool requires_svg_container() const override { return false; } virtual bool is_svg_container() const override { return true; } - Optional const& view_box() const { return m_view_box; } + [[nodiscard]] Optional view_box() const; Optional const& preserve_aspect_ratio() const { return m_preserve_aspect_ratio; } + void set_fallback_view_box_for_svg_as_image(Optional); + private: SVGSVGElement(DOM::Document&, DOM::QualifiedName); @@ -36,8 +38,12 @@ private: virtual void parse_attribute(DeprecatedFlyString const& name, DeprecatedString const& value) override; + void update_fallback_view_box_for_svg_as_image(); + Optional m_view_box; Optional m_preserve_aspect_ratio; + + Optional m_fallback_view_box_for_svg_as_image; }; }