summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2022-07-11 12:25:01 +0200
committerAndreas Kling <kling@serenityos.org>2022-07-11 18:57:45 +0200
commit17a6fcfde339bede45ef61913c28d41dbc77da09 (patch)
tree68e22f5836ebb3fc4cd9c2071df3a7ac3eb00a28 /Userland
parent7dfd5afd37932d54b0513865d911d816785e1aa6 (diff)
downloadserenity-17a6fcfde339bede45ef61913c28d41dbc77da09.zip
LibWeb: Try to work out the intrinsic size of <svg> elements
If the `width` and `height` attributes are provided, we derive the intrinsic size and ratio from them. Otherwise, we trace a rectangle around the geometry elements inside the SVG and use the size of that as the intrinsic size. This is definitely far from correct, but is still a much better guess at the intrinsic size than nothing.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibWeb/Layout/SVGSVGBox.cpp71
-rw-r--r--Userland/Libraries/LibWeb/Layout/SVGSVGBox.h2
2 files changed, 73 insertions, 0 deletions
diff --git a/Userland/Libraries/LibWeb/Layout/SVGSVGBox.cpp b/Userland/Libraries/LibWeb/Layout/SVGSVGBox.cpp
index f521e0da39..5b7398892b 100644
--- a/Userland/Libraries/LibWeb/Layout/SVGSVGBox.cpp
+++ b/Userland/Libraries/LibWeb/Layout/SVGSVGBox.cpp
@@ -1,10 +1,13 @@
/*
* Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
+ * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
+#include <LibWeb/HTML/Parser/HTMLParser.h>
#include <LibWeb/Layout/ReplacedBox.h>
+#include <LibWeb/Layout/SVGGeometryBox.h>
#include <LibWeb/Painting/SVGSVGPaintable.h>
namespace Web::Layout {
@@ -19,4 +22,72 @@ RefPtr<Painting::Paintable> SVGSVGBox::create_paintable() const
return Painting::SVGSVGPaintable::create(*this);
}
+void SVGSVGBox::prepare_for_replaced_layout()
+{
+ if (dom_node().has_attribute(HTML::AttributeNames::width) && dom_node().has_attribute(HTML::AttributeNames::height)) {
+ Optional<float> w;
+ Optional<float> h;
+ if (auto width = HTML::parse_dimension_value(dom_node().attribute(HTML::AttributeNames::width))) {
+ if (width->has_length())
+ w = width->to_length().to_px(*this);
+ }
+ if (auto height = HTML::parse_dimension_value(dom_node().attribute(HTML::AttributeNames::height))) {
+ if (height->has_length())
+ h = height->to_length().to_px(*this);
+ }
+ if (w.has_value() && h.has_value()) {
+ set_intrinsic_width(*w);
+ set_intrinsic_height(*h);
+ set_intrinsic_aspect_ratio(*w / *h);
+ return;
+ }
+ }
+
+ Optional<Gfx::FloatRect> united_rect;
+
+ auto add_to_united_rect = [&](Gfx::FloatRect const& rect) {
+ if (united_rect.has_value())
+ united_rect = united_rect->united(rect);
+ else
+ united_rect = rect;
+ };
+
+ for_each_in_subtree_of_type<SVGGeometryBox>([&](SVGGeometryBox const& geometry_box) {
+ auto& dom_node = const_cast<SVG::SVGGeometryElement&>(geometry_box.dom_node());
+ if (dom_node.has_attribute(HTML::AttributeNames::width) && dom_node.has_attribute(HTML::AttributeNames::height)) {
+ Gfx::FloatRect rect;
+ // FIXME: Allow for relative lengths here
+ rect.set_width(computed_values().width().resolved(*this, CSS::Length::make_px(0)).to_px(*this));
+ rect.set_height(computed_values().height().resolved(*this, CSS::Length::make_px(0)).to_px(*this));
+ add_to_united_rect(rect);
+ return IterationDecision::Continue;
+ }
+
+ auto& path = dom_node.get_path();
+ auto path_bounding_box = path.bounding_box();
+
+ // Stroke increases the path's size by stroke_width/2 per side.
+ auto stroke_width = geometry_box.dom_node().stroke_width().value_or(0);
+ path_bounding_box.inflate(stroke_width, stroke_width);
+
+ auto& maybe_view_box = this->dom_node().view_box();
+
+ if (maybe_view_box.has_value()) {
+ auto view_box = maybe_view_box.value();
+ Gfx::FloatRect rect(view_box.min_x, view_box.min_y, view_box.width, view_box.height);
+ add_to_united_rect(rect);
+ return IterationDecision::Continue;
+ }
+
+ add_to_united_rect(path_bounding_box);
+ return IterationDecision::Continue;
+ });
+
+ if (united_rect.has_value()) {
+ set_intrinsic_width(united_rect->width());
+ set_intrinsic_height(united_rect->height());
+ set_intrinsic_aspect_ratio(united_rect->width() / united_rect->height());
+ }
+}
+
}
diff --git a/Userland/Libraries/LibWeb/Layout/SVGSVGBox.h b/Userland/Libraries/LibWeb/Layout/SVGSVGBox.h
index 530fa27856..55d4967c41 100644
--- a/Userland/Libraries/LibWeb/Layout/SVGSVGBox.h
+++ b/Userland/Libraries/LibWeb/Layout/SVGSVGBox.h
@@ -21,6 +21,8 @@ public:
virtual bool can_have_children() const override { return true; }
virtual RefPtr<Painting::Paintable> create_paintable() const override;
+
+ virtual void prepare_for_replaced_layout() override;
};
}