summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPrestonLTaylor <95388976+PrestonLTaylor@users.noreply.github.com>2023-05-28 18:27:35 +0100
committerAndreas Kling <kling@serenityos.org>2023-06-03 05:58:00 +0200
commit31d536912c86702cc76d5dfe3ca6b20f3eece377 (patch)
tree81298161a1f28ce99c12d49e0bbd38503f864e41
parentfd360ba1715692ce44c49c680ab67bf2a1d2fcc4 (diff)
downloadserenity-31d536912c86702cc76d5dfe3ca6b20f3eece377.zip
LibWeb: Allow SVG painting to escape out of a shadow tree
The spec for the `<use>` element requires a shadow tree for the rendered content, so we need to be able to escape shadow trees when rendering svg content.
-rw-r--r--Userland/Libraries/LibWeb/DOM/Node.h9
-rw-r--r--Userland/Libraries/LibWeb/DOM/ParentNode.h10
-rw-r--r--Userland/Libraries/LibWeb/Layout/SVGGeometryBox.cpp4
-rw-r--r--Userland/Libraries/LibWeb/Painting/SVGGeometryPaintable.cpp2
-rw-r--r--Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp4
5 files changed, 24 insertions, 5 deletions
diff --git a/Userland/Libraries/LibWeb/DOM/Node.h b/Userland/Libraries/LibWeb/DOM/Node.h
index 96392c2d66..8e1818a754 100644
--- a/Userland/Libraries/LibWeb/DOM/Node.h
+++ b/Userland/Libraries/LibWeb/DOM/Node.h
@@ -636,6 +636,15 @@ public:
return nullptr;
}
+ template<typename U>
+ U const* shadow_including_first_ancestor_of_type() const
+ {
+ return const_cast<Node*>(this)->template shadow_including_first_ancestor_of_type<U>();
+ }
+
+ template<typename U>
+ U* shadow_including_first_ancestor_of_type();
+
bool is_parent_of(Node const& other) const
{
for (auto* child = first_child(); child; child = child->next_sibling()) {
diff --git a/Userland/Libraries/LibWeb/DOM/ParentNode.h b/Userland/Libraries/LibWeb/DOM/ParentNode.h
index 4501822bd3..0761d23fb1 100644
--- a/Userland/Libraries/LibWeb/DOM/ParentNode.h
+++ b/Userland/Libraries/LibWeb/DOM/ParentNode.h
@@ -55,6 +55,16 @@ private:
template<>
inline bool Node::fast_is<ParentNode>() const { return is_parent_node(); }
+template<typename U>
+inline U* Node::shadow_including_first_ancestor_of_type()
+{
+ for (auto* ancestor = parent_or_shadow_host(); ancestor; ancestor = ancestor->parent_or_shadow_host()) {
+ if (is<U>(*ancestor))
+ return &verify_cast<U>(*ancestor);
+ }
+ return nullptr;
+}
+
template<typename Callback>
inline void ParentNode::for_each_child(Callback callback) const
{
diff --git a/Userland/Libraries/LibWeb/Layout/SVGGeometryBox.cpp b/Userland/Libraries/LibWeb/Layout/SVGGeometryBox.cpp
index b1497c05e6..134d764642 100644
--- a/Userland/Libraries/LibWeb/Layout/SVGGeometryBox.cpp
+++ b/Userland/Libraries/LibWeb/Layout/SVGGeometryBox.cpp
@@ -19,7 +19,7 @@ SVGGeometryBox::SVGGeometryBox(DOM::Document& document, SVG::SVGGeometryElement&
CSSPixelPoint SVGGeometryBox::viewbox_origin() const
{
- auto* svg_box = dom_node().first_ancestor_of_type<SVG::SVGSVGElement>();
+ auto* svg_box = dom_node().shadow_including_first_ancestor_of_type<SVG::SVGSVGElement>();
if (!svg_box || !svg_box->view_box().has_value())
return { 0, 0 };
return { svg_box->view_box().value().min_x, svg_box->view_box().value().min_y };
@@ -29,7 +29,7 @@ Optional<Gfx::AffineTransform> SVGGeometryBox::layout_transform() const
{
auto& geometry_element = dom_node();
auto transform = geometry_element.get_transform();
- auto* svg_box = geometry_element.first_ancestor_of_type<SVG::SVGSVGElement>();
+ auto* svg_box = geometry_element.shadow_including_first_ancestor_of_type<SVG::SVGSVGElement>();
double scaling = 1;
auto origin = viewbox_origin().to_type<double>().to_type<float>();
Gfx::FloatPoint paint_offset = {};
diff --git a/Userland/Libraries/LibWeb/Painting/SVGGeometryPaintable.cpp b/Userland/Libraries/LibWeb/Painting/SVGGeometryPaintable.cpp
index 979a59fbf3..931b8f6211 100644
--- a/Userland/Libraries/LibWeb/Painting/SVGGeometryPaintable.cpp
+++ b/Userland/Libraries/LibWeb/Painting/SVGGeometryPaintable.cpp
@@ -62,7 +62,7 @@ void SVGGeometryPaintable::paint(PaintContext& context, PaintPhase phase) const
auto offset = context.floored_device_point(svg_context.svg_element_position()).to_type<int>().to_type<float>();
painter.translate(offset);
- auto const* svg_element = geometry_element.first_ancestor_of_type<SVG::SVGSVGElement>();
+ auto const* svg_element = geometry_element.shadow_including_first_ancestor_of_type<SVG::SVGSVGElement>();
auto maybe_view_box = svg_element->view_box();
auto transform = layout_box().layout_transform();
diff --git a/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp
index 3b9ca3419d..54e1528b6e 100644
--- a/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp
+++ b/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp
@@ -97,7 +97,7 @@ Gfx::AffineTransform SVGGraphicsElement::get_transform() const
{
// FIXME: It would be nice to do this using the SVGContext, however, then layout/hit testing knows nothing about the transform.
Gfx::AffineTransform transform = m_transform;
- for (auto* svg_ancestor = first_ancestor_of_type<SVGGraphicsElement>(); svg_ancestor; svg_ancestor = svg_ancestor->first_ancestor_of_type<SVGGraphicsElement>()) {
+ for (auto* svg_ancestor = shadow_including_first_ancestor_of_type<SVGGraphicsElement>(); svg_ancestor; svg_ancestor = svg_ancestor->shadow_including_first_ancestor_of_type<SVGGraphicsElement>()) {
transform = Gfx::AffineTransform { svg_ancestor->m_transform }.multiply(transform);
}
return transform;
@@ -179,7 +179,7 @@ Optional<float> SVGGraphicsElement::stroke_width() const
// FIXME: This isn't right, but it's something.
CSSPixels viewport_width = 0;
CSSPixels viewport_height = 0;
- if (auto* svg_svg_element = first_ancestor_of_type<SVGSVGElement>()) {
+ if (auto* svg_svg_element = shadow_including_first_ancestor_of_type<SVGSVGElement>()) {
if (auto* svg_svg_layout_node = svg_svg_element->layout_node()) {
viewport_width = svg_svg_layout_node->computed_values().width().to_px(*svg_svg_layout_node, 0);
viewport_height = svg_svg_layout_node->computed_values().height().to_px(*svg_svg_layout_node, 0);