瀏覽代碼

LibWeb: Wrap table roots in anonymous block boxes

According to table fixup algorithm:
https://www.w3.org/TR/css-tables-3/#fixup-algorithm
around every table-root should be generated anonymous
box wrapper.

Also this patch implements important part of CSS 2.2
spec that is currently not present in CSS Tables 3
spec draft: https://www.w3.org/TR/CSS22/tables.html#model
that portion of computed properties should be moved
from table-root to table wrapper box. Without having
this part implemented height of absolutely positioned
table with `height: auto` won't be computed correctly.
Aliaksandr Kalenik 2 年之前
父節點
當前提交
57940f4370

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

@@ -13,6 +13,7 @@
 #include <LibWeb/Layout/FormattingContext.h>
 #include <LibWeb/Layout/InitialContainingBlock.h>
 #include <LibWeb/Layout/Node.h>
+#include <LibWeb/Layout/TableBox.h>
 #include <LibWeb/Layout/TextNode.h>
 #include <LibWeb/Platform/FontPlugin.h>
 
@@ -666,6 +667,17 @@ JS::NonnullGCPtr<NodeWithStyle> NodeWithStyle::create_anonymous_wrapper() const
     return *wrapper;
 }
 
+void NodeWithStyle::reset_table_box_computed_values_used_by_wrapper_to_init_values()
+{
+    VERIFY(is<TableBox>(*this));
+
+    CSS::MutableComputedValues& mutable_computed_values = static_cast<CSS::MutableComputedValues&>(m_computed_values);
+    mutable_computed_values.set_position(CSS::Position::Static);
+    mutable_computed_values.set_float(CSS::Float::None);
+    mutable_computed_values.set_inset({ CSS::Length::make_auto(), CSS::Length::make_auto(), CSS::Length::make_auto(), CSS::Length::make_auto() });
+    mutable_computed_values.set_margin({ CSS::Length::make_px(0), CSS::Length::make_px(0), CSS::Length::make_px(0), CSS::Length::make_px(0) });
+}
+
 void Node::set_paintable(RefPtr<Painting::Paintable> paintable)
 {
     m_paintable = move(paintable);

+ 2 - 0
Userland/Libraries/LibWeb/Layout/Node.h

@@ -183,6 +183,8 @@ public:
 
     JS::NonnullGCPtr<NodeWithStyle> create_anonymous_wrapper() const;
 
+    void reset_table_box_computed_values_used_by_wrapper_to_init_values();
+
 protected:
     NodeWithStyle(DOM::Document&, DOM::Node*, NonnullRefPtr<CSS::StyleProperties>);
     NodeWithStyle(DOM::Document&, DOM::Node*, CSS::ComputedValues);

+ 29 - 0
Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp

@@ -550,6 +550,7 @@ void TreeBuilder::generate_missing_child_wrappers(NodeWithStyle& root)
 
 void TreeBuilder::generate_missing_parents(NodeWithStyle& root)
 {
+    Vector<JS::Handle<TableBox>> table_roots_to_wrap;
     root.for_each_in_inclusive_subtree_of_type<Box>([&](auto& parent) {
         // An anonymous table-row box must be generated around each sequence of consecutive table-cell boxes whose parent is not a table-row.
         if (is_not_table_row(parent)) {
@@ -572,8 +573,36 @@ void TreeBuilder::generate_missing_parents(NodeWithStyle& root)
             });
         }
 
+        // An anonymous table-wrapper box must be generated around each table-root.
+        if (parent.display().is_table_inside()) {
+            table_roots_to_wrap.append(static_cast<TableBox&>(parent));
+        }
+
         return IterationDecision::Continue;
     });
+
+    for (auto& table_box : table_roots_to_wrap) {
+        auto* nearest_sibling = table_box->next_sibling();
+        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);
+        mutable_wrapper_computed_values.set_display(CSS::Display(CSS::Display::Outside::Block, CSS::Display::Inside::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_margin(table_box->computed_values().margin());
+        table_box->reset_table_box_computed_values_used_by_wrapper_to_init_values();
+
+        auto wrapper = parent.heap().allocate_without_realm<BlockContainer>(parent.document(), nullptr, move(wrapper_computed_values));
+
+        parent.remove_child(*table_box);
+        wrapper->append_child(*table_box);
+        parent.insert_before(*wrapper, *nearest_sibling);
+    }
 }
 
 }