Prechádzať zdrojové kódy

LibWeb: Fix style updates for table box nodes

On style update, we have to preserve the invariant established when we
built the layout tree - some properties are applied to the table wrapper
and the table box values are reset to their initial values.

This also ensures that the containing block of a table box is always a
table wrapper, which isn't the case if we set absolute position on the
box instead of the wrapper.

Fixes #19452.
Andi Gallo 2 rokov pred
rodič
commit
55f1a70577

+ 18 - 0
Tests/LibWeb/Layout/expected/table/propagate-style-update-to-wrapper.txt

@@ -0,0 +1,18 @@
+Viewport <#document> at (0,0) content-size 800x600 children: not-inline
+  BlockContainer <html> at (0,0) content-size 800x600 [BFC] children: not-inline
+    BlockContainer <body> at (8,8) content-size 784x0 children: not-inline
+      TableWrapper <(anonymous)> at (8,8) content-size 6x6 positioned [BFC] children: not-inline
+        Box <table#t> at (8,8) content-size 6x6 table-box [TFC] children: not-inline
+          BlockContainer <(anonymous)> (not painted) children: inline
+            TextNode <#text>
+          Box <tbody> at (8,8) content-size 2x2 table-row-group children: not-inline
+            Box <tr> at (10,10) content-size 2x2 table-row children: not-inline
+              BlockContainer <(anonymous)> (not painted) children: inline
+                TextNode <#text>
+              BlockContainer <td> at (11,11) content-size 0x0 table-cell [BFC] children: not-inline
+              BlockContainer <(anonymous)> (not painted) children: inline
+                TextNode <#text>
+            BlockContainer <(anonymous)> (not painted) children: inline
+              TextNode <#text>
+      BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline
+        TextNode <#text>

+ 12 - 0
Tests/LibWeb/Layout/input/table/propagate-style-update-to-wrapper.html

@@ -0,0 +1,12 @@
+<table id="t">
+    <tr>
+        <td></td>
+    </tr>
+</table>
+
+<script>
+    t = document.querySelector("#t");
+    console.log(t);
+    t.style.position = "absolute";
+    window.getComputedStyle(t);
+</script>

+ 23 - 0
Userland/Libraries/LibWeb/Layout/Node.cpp

@@ -26,6 +26,7 @@
 #include <LibWeb/Layout/BlockContainer.h>
 #include <LibWeb/Layout/FormattingContext.h>
 #include <LibWeb/Layout/Node.h>
+#include <LibWeb/Layout/TableWrapper.h>
 #include <LibWeb/Layout/TextNode.h>
 #include <LibWeb/Layout/Viewport.h>
 #include <LibWeb/Platform/FontPlugin.h>
@@ -734,6 +735,10 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
     } else if (aspect_ratio->is_ratio()) {
         computed_values.set_aspect_ratio({ false, aspect_ratio->as_ratio().ratio() });
     }
+    if (display().is_table_inside() && is<TableWrapper>(parent())) {
+        auto& wrapper_computed_values = static_cast<TableWrapper*>(parent())->m_computed_values;
+        transfer_table_box_computed_values_to_wrapper_computed_values(wrapper_computed_values);
+    }
 }
 
 bool Node::is_root_element() const
@@ -810,6 +815,24 @@ void NodeWithStyle::reset_table_box_computed_values_used_by_wrapper_to_init_valu
     mutable_computed_values.set_margin(CSS::InitialValues::margin());
 }
 
+void NodeWithStyle::transfer_table_box_computed_values_to_wrapper_computed_values(CSS::ComputedValues& wrapper_computed_values)
+{
+    // The computed values of properties 'position', 'float', 'margin-*', 'top', 'right', 'bottom', and 'left' on the table element are used on the table wrapper box and not the table box;
+    // all other values of non-inheritable properties are used on the table box and not the table wrapper box.
+    // (Where the table element's values are not used on the table and table wrapper boxes, the initial values are used instead.)
+    auto& mutable_wrapper_computed_values = static_cast<CSS::MutableComputedValues&>(wrapper_computed_values);
+    if (display().is_inline_outside())
+        mutable_wrapper_computed_values.set_display(CSS::Display::from_short(CSS::Display::Short::InlineBlock));
+    else
+        mutable_wrapper_computed_values.set_display(CSS::Display::from_short(CSS::Display::Short::FlowRoot));
+    mutable_wrapper_computed_values.set_position(computed_values().position());
+    mutable_wrapper_computed_values.set_inset(computed_values().inset());
+    mutable_wrapper_computed_values.set_float(computed_values().float_());
+    mutable_wrapper_computed_values.set_clear(computed_values().clear());
+    mutable_wrapper_computed_values.set_margin(computed_values().margin());
+    reset_table_box_computed_values_used_by_wrapper_to_init_values();
+}
+
 void Node::set_paintable(JS::GCPtr<Painting::Paintable> paintable)
 {
     m_paintable = move(paintable);

+ 3 - 1
Userland/Libraries/LibWeb/Layout/Node.h

@@ -195,13 +195,15 @@ public:
 
     JS::NonnullGCPtr<NodeWithStyle> create_anonymous_wrapper() const;
 
-    void reset_table_box_computed_values_used_by_wrapper_to_init_values();
+    void transfer_table_box_computed_values_to_wrapper_computed_values(CSS::ComputedValues& wrapper_computed_values);
 
 protected:
     NodeWithStyle(DOM::Document&, DOM::Node*, NonnullRefPtr<CSS::StyleProperties>);
     NodeWithStyle(DOM::Document&, DOM::Node*, CSS::ComputedValues);
 
 private:
+    void reset_table_box_computed_values_used_by_wrapper_to_init_values();
+
     CSS::ComputedValues m_computed_values;
     RefPtr<Gfx::Font const> m_font;
     CSSPixels m_line_height { 0 };

+ 1 - 14
Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp

@@ -592,20 +592,7 @@ void TreeBuilder::generate_missing_parents(NodeWithStyle& root)
         auto& parent = *table_box->parent();
 
         CSS::ComputedValues wrapper_computed_values;
-        // The computed values of properties 'position', 'float', 'margin-*', 'top', 'right', 'bottom', and 'left' on the table element are used on the table wrapper box and not the table box;
-        // all other values of non-inheritable properties are used on the table box and not the table wrapper box.
-        // (Where the table element's values are not used on the table and table wrapper boxes, the initial values are used instead.)
-        auto& mutable_wrapper_computed_values = static_cast<CSS::MutableComputedValues&>(wrapper_computed_values);
-        if (table_box->display().is_inline_outside())
-            mutable_wrapper_computed_values.set_display(CSS::Display::from_short(CSS::Display::Short::InlineBlock));
-        else
-            mutable_wrapper_computed_values.set_display(CSS::Display::from_short(CSS::Display::Short::FlowRoot));
-        mutable_wrapper_computed_values.set_position(table_box->computed_values().position());
-        mutable_wrapper_computed_values.set_inset(table_box->computed_values().inset());
-        mutable_wrapper_computed_values.set_float(table_box->computed_values().float_());
-        mutable_wrapper_computed_values.set_clear(table_box->computed_values().clear());
-        mutable_wrapper_computed_values.set_margin(table_box->computed_values().margin());
-        table_box->reset_table_box_computed_values_used_by_wrapper_to_init_values();
+        table_box->transfer_table_box_computed_values_to_wrapper_computed_values(wrapper_computed_values);
 
         auto wrapper = parent.heap().allocate_without_realm<TableWrapper>(parent.document(), nullptr, move(wrapper_computed_values));