瀏覽代碼

LibWeb: Make sure that SVG use and symbol elements get paintables

I'm about to make StackingContext traverse the paintable tree instead of
actually traversing the layout tree, and it turns out we were not
creating paintables for these SVG elements.

Also switch them to Layout::Box instead of the default InlineNode to
make the trees look a bit less weird. Ultimately, we should do something
specialized for these subtrees, but for now this'll do.
Andreas Kling 1 年之前
父節點
當前提交
1e0ea45fe5

+ 5 - 2
Tests/LibWeb/Layout/expected/svg/svg-symbol-with-viewbox.txt

@@ -10,8 +10,8 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
         TextNode <#text>
         SVGSVGBox <svg> at (8,8) content-size 300x150 [SVG] children: inline
           TextNode <#text>
-          InlineNode <use>
-            InlineNode <symbol#braces>
+          Box <use> at (8,8) content-size 0x0 children: inline
+            Box <symbol#braces> at (8,8) content-size 0x0 children: inline
               TextNode <#text>
               SVGGeometryBox <path> at (92.375,26.75) content-size 131.25x112.15625 children: inline
                 TextNode <#text>
@@ -25,3 +25,6 @@ ViewportPaintable (Viewport<#document>) [0,0 800x600]
       PaintableWithLines (BlockContainer(anonymous)) [8,8 784x0]
       PaintableWithLines (BlockContainer<DIV>) [8,8 784x150]
         SVGSVGPaintable (SVGSVGBox<svg>) [8,8 300x150]
+          PaintableBox (Box<use>) [8,8 0x0]
+            PaintableBox (Box<symbol>#braces) [8,8 0x0]
+              SVGGeometryPaintable (SVGGeometryBox<path>) [92.375,26.75 131.25x112.15625]

+ 24 - 11
Userland/Libraries/LibWeb/Layout/SVGFormattingContext.cpp

@@ -15,6 +15,8 @@
 #include <LibWeb/Layout/SVGTextBox.h>
 #include <LibWeb/SVG/SVGForeignObjectElement.h>
 #include <LibWeb/SVG/SVGSVGElement.h>
+#include <LibWeb/SVG/SVGSymbolElement.h>
+#include <LibWeb/SVG/SVGUseElement.h>
 
 namespace Web::Layout {
 
@@ -131,6 +133,21 @@ static ViewBoxTransform scale_and_align_viewbox_content(SVG::PreserveAspectRatio
     return viewbox_transform;
 }
 
+static bool should_ensure_creation_of_paintable(Node const& node)
+{
+    if (is<SVGTextBox>(node))
+        return true;
+    if (is<SVGGraphicsBox>(node))
+        return true;
+    if (node.dom_node()) {
+        if (is<SVG::SVGUseElement>(*node.dom_node()))
+            return true;
+        if (is<SVG::SVGSymbolElement>(*node.dom_node()))
+            return true;
+    }
+    return false;
+}
+
 void SVGFormattingContext::run(Box const& box, LayoutMode layout_mode, AvailableSpace const& available_space)
 {
     auto& svg_svg_element = verify_cast<SVG::SVGSVGElement>(*box.dom_node());
@@ -149,7 +166,7 @@ void SVGFormattingContext::run(Box const& box, LayoutMode layout_mode, Available
         return IterationDecision::Continue;
     });
 
-    box.for_each_in_subtree_of_type<Box>([&](Box const& descendant) {
+    box.for_each_in_subtree([&](Node const& descendant) {
         if (is<SVGGeometryBox>(descendant)) {
             auto const& geometry_box = static_cast<SVGGeometryBox const&>(descendant);
             auto& geometry_box_state = m_state.get_mutable(geometry_box);
@@ -186,16 +203,12 @@ void SVGFormattingContext::run(Box const& box, LayoutMode layout_mode, Available
             geometry_box_state.set_content_width(path_bounding_box.width());
             geometry_box_state.set_content_height(path_bounding_box.height());
         } else if (is<SVGSVGBox>(descendant)) {
-            SVGFormattingContext nested_context(m_state, descendant, this);
-            nested_context.run(descendant, layout_mode, available_space);
-        } else if (is<SVGTextBox>(descendant)) {
-            auto const& svg_text_box = static_cast<SVGTextBox const&>(descendant);
-            // NOTE: This hack creates a layout state to ensure the existence of a paintable box node in LayoutState::commit(), even when none of the values from UsedValues impact the SVG text.
-            m_state.get_mutable(svg_text_box);
-        } else if (is<SVGGraphicsBox>(descendant)) {
-            // Same hack as above.
-            auto const& svg_graphics_box = static_cast<SVGGraphicsBox const&>(descendant);
-            m_state.get_mutable(svg_graphics_box);
+            SVGFormattingContext nested_context(m_state, static_cast<SVGSVGBox const&>(descendant), this);
+            nested_context.run(static_cast<SVGSVGBox const&>(descendant), layout_mode, available_space);
+        } else if (should_ensure_creation_of_paintable(descendant)) {
+            // NOTE: This hack creates a layout state to ensure the existence of
+            //       a paintable in LayoutState::commit().
+            m_state.get_mutable(static_cast<NodeWithStyleAndBoxModelMetrics const&>(descendant));
         }
 
         return IterationDecision::Continue;

+ 6 - 0
Userland/Libraries/LibWeb/SVG/SVGSymbolElement.cpp

@@ -10,6 +10,7 @@
 #include <LibWeb/CSS/StyleValues/IdentifierStyleValue.h>
 #include <LibWeb/CSS/StyleValues/OverflowStyleValue.h>
 #include <LibWeb/DOM/ShadowRoot.h>
+#include <LibWeb/Layout/Box.h>
 #include <LibWeb/SVG/AttributeNames.h>
 #include <LibWeb/SVG/SVGSymbolElement.h>
 #include <LibWeb/SVG/SVGUseElement.h>
@@ -62,4 +63,9 @@ bool SVGSymbolElement::is_direct_child_of_use_shadow_tree() const
     return is<SVGUseElement>(host);
 }
 
+JS::GCPtr<Layout::Node> SVGSymbolElement::create_layout_node(NonnullRefPtr<CSS::StyleProperties> style)
+{
+    return heap().allocate_without_realm<Layout::Box>(document(), this, move(style));
+}
+
 }

+ 2 - 0
Userland/Libraries/LibWeb/SVG/SVGSymbolElement.h

@@ -25,6 +25,8 @@ private:
 
     virtual void initialize(JS::Realm&) override;
 
+    virtual JS::GCPtr<Layout::Node> create_layout_node(NonnullRefPtr<CSS::StyleProperties>) override;
+
     bool is_direct_child_of_use_shadow_tree() const;
 
     virtual void attribute_changed(DeprecatedFlyString const& name, DeprecatedString const& value) override;

+ 6 - 0
Userland/Libraries/LibWeb/SVG/SVGUseElement.cpp

@@ -9,6 +9,7 @@
 #include <LibWeb/DOM/ElementFactory.h>
 #include <LibWeb/DOM/Event.h>
 #include <LibWeb/DOM/ShadowRoot.h>
+#include <LibWeb/Layout/Box.h>
 #include <LibWeb/Namespace.h>
 #include <LibWeb/SVG/AttributeNames.h>
 #include <LibWeb/SVG/SVGSVGElement.h>
@@ -172,4 +173,9 @@ JS::GCPtr<SVGElement> SVGUseElement::animated_instance_root() const
     return instance_root();
 }
 
+JS::GCPtr<Layout::Node> SVGUseElement::create_layout_node(NonnullRefPtr<CSS::StyleProperties> style)
+{
+    return heap().allocate_without_realm<Layout::Box>(document(), this, move(style));
+}
+
 }

+ 2 - 0
Userland/Libraries/LibWeb/SVG/SVGUseElement.h

@@ -42,6 +42,8 @@ private:
 
     virtual bool is_svg_use_element() const override { return true; }
 
+    virtual JS::GCPtr<Layout::Node> create_layout_node(NonnullRefPtr<CSS::StyleProperties>) override;
+
     Optional<StringView> parse_id_from_href(DeprecatedString const& href);
 
     JS::GCPtr<DOM::Element> referenced_element();