at (9,87.9375) content-size 98x39.46875 table-row children: not-inline
+ BlockContainer at (20,98.9375) content-size 30.5625x17.46875 table-cell [BFC] children: inline
+ line 0 width: 14.265625, height: 17.46875, bottom: 17.46875, baseline: 13.53125
+ frag 0 from TextNode start: 0, length: 1, rect: [20,98.9375 14.265625x17.46875]
+ "A"
+ TextNode <#text>
+ BlockContainer <(anonymous)> at (62.5625,107.171875) content-size 21.71875x0 table-cell [BFC] children: not-inline
+ BlockContainer <(anonymous)> at (84.28125,107.171875) content-size 21.71875x0 table-cell [BFC] children: not-inline
+
+ViewportPaintable (Viewport<#document>) [0,0 800x600]
+ PaintableWithLines (BlockContainer) [0,0 800x600]
+ PaintableWithLines (BlockContainer) [8,8 784x120.40625]
+ PaintableBox (Box) [8,8 784x120.40625]
+ PaintableWithLines (TableWrapper(anonymous)) [8,8 100x120.40625]
+ PaintableBox (Box ) [8,8 100x120.40625]
+ PaintableBox (Box) [9,9 98x118.40625]
+ PaintableBox (Box) [9,9 98x39.46875]
+ PaintableWithLines (BlockContainer) [9,9 52.5625x39.46875]
+ TextPaintable (TextNode<#text>)
+ PaintableWithLines (BlockContainer | ) [61.5625,9 45.4375x39.46875]
+ TextPaintable (TextNode<#text>)
+ PaintableBox (Box | ) [9,48.46875 98x39.46875]
+ PaintableWithLines (BlockContainer) [9,48.46875 52.5625x39.46875]
+ TextPaintable (TextNode<#text>)
+ PaintableWithLines (BlockContainer(anonymous)) [61.5625,48.46875 22.71875x39.46875]
+ PaintableWithLines (BlockContainer(anonymous)) [84.28125,48.46875 22.71875x39.46875]
+ PaintableBox (Box | ) [9,87.9375 98x39.46875]
+ PaintableWithLines (BlockContainer) [9,87.9375 52.5625x39.46875]
+ TextPaintable (TextNode<#text>)
+ PaintableWithLines (BlockContainer(anonymous)) [61.5625,87.9375 22.71875x39.46875]
+ PaintableWithLines (BlockContainer(anonymous)) [84.28125,87.9375 22.71875x39.46875]
diff --git a/Tests/LibWeb/Layout/expected/table/missing-cells.txt b/Tests/LibWeb/Layout/expected/table/missing-cells.txt
new file mode 100644
index 0000000000..15e66f9750
--- /dev/null
+++ b/Tests/LibWeb/Layout/expected/table/missing-cells.txt
@@ -0,0 +1,53 @@
+Viewport <#document> at (0,0) content-size 800x600 children: not-inline
+ BlockContainer at (0,0) content-size 800x600 [BFC] children: not-inline
+ BlockContainer at (8,8) content-size 784x120.40625 children: not-inline
+ Box at (8,8) content-size 784x120.40625 [GFC] children: not-inline
+ TableWrapper <(anonymous)> at (8,8) content-size 100x120.40625 [BFC] children: not-inline
+ Box at (9,9) content-size 98x118.40625 table-box [TFC] children: not-inline
+ Box at (9,9) content-size 98x118.40625 table-row-group children: not-inline
+ Box at (9,9) content-size 98x39.46875 table-row children: not-inline
+ BlockContainer at (20,20) content-size 30.5625x17.46875 table-cell [BFC] children: inline
+ line 0 width: 14.265625, height: 17.46875, bottom: 17.46875, baseline: 13.53125
+ frag 0 from TextNode start: 0, length: 1, rect: [20,20 14.265625x17.46875]
+ "A"
+ TextNode <#text>
+ BlockContainer | at (72.5625,20) content-size 23.4375x17.46875 table-cell [BFC] children: inline
+ line 0 width: 9.34375, height: 17.46875, bottom: 17.46875, baseline: 13.53125
+ frag 0 from TextNode start: 0, length: 1, rect: [72.5625,20 9.34375x17.46875]
+ "B"
+ TextNode <#text>
+ Box | at (9,48.46875) content-size 98x39.46875 table-row children: not-inline
+ BlockContainer at (20,59.46875) content-size 30.5625x17.46875 table-cell [BFC] children: inline
+ line 0 width: 14.265625, height: 17.46875, bottom: 17.46875, baseline: 13.53125
+ frag 0 from TextNode start: 0, length: 1, rect: [20,59.46875 14.265625x17.46875]
+ "A"
+ TextNode <#text>
+ BlockContainer <(anonymous)> at (62.5625,68.703125) content-size 43.4375x0 table-cell [BFC] children: not-inline
+ Box | at (9,87.9375) content-size 98x39.46875 table-row children: not-inline
+ BlockContainer at (20,98.9375) content-size 30.5625x17.46875 table-cell [BFC] children: inline
+ line 0 width: 14.265625, height: 17.46875, bottom: 17.46875, baseline: 13.53125
+ frag 0 from TextNode start: 0, length: 1, rect: [20,98.9375 14.265625x17.46875]
+ "A"
+ TextNode <#text>
+ BlockContainer <(anonymous)> at (62.5625,107.171875) content-size 43.4375x0 table-cell [BFC] children: not-inline
+
+ViewportPaintable (Viewport<#document>) [0,0 800x600]
+ PaintableWithLines (BlockContainer) [0,0 800x600]
+ PaintableWithLines (BlockContainer) [8,8 784x120.40625]
+ PaintableBox (Box) [8,8 784x120.40625]
+ PaintableWithLines (TableWrapper(anonymous)) [8,8 100x120.40625]
+ PaintableBox (Box ) [8,8 100x120.40625]
+ PaintableBox (Box) [9,9 98x118.40625]
+ PaintableBox (Box) [9,9 98x39.46875]
+ PaintableWithLines (BlockContainer) [9,9 52.5625x39.46875]
+ TextPaintable (TextNode<#text>)
+ PaintableWithLines (BlockContainer | ) [61.5625,9 45.4375x39.46875]
+ TextPaintable (TextNode<#text>)
+ PaintableBox (Box | ) [9,48.46875 98x39.46875]
+ PaintableWithLines (BlockContainer) [9,48.46875 52.5625x39.46875]
+ TextPaintable (TextNode<#text>)
+ PaintableWithLines (BlockContainer(anonymous)) [61.5625,48.46875 45.4375x39.46875]
+ PaintableBox (Box | ) [9,87.9375 98x39.46875]
+ PaintableWithLines (BlockContainer) [9,87.9375 52.5625x39.46875]
+ TextPaintable (TextNode<#text>)
+ PaintableWithLines (BlockContainer(anonymous)) [61.5625,87.9375 45.4375x39.46875]
diff --git a/Tests/LibWeb/Layout/input/table/missing-cells-with-span.html b/Tests/LibWeb/Layout/input/table/missing-cells-with-span.html
new file mode 100644
index 0000000000..08def4751b
--- /dev/null
+++ b/Tests/LibWeb/Layout/input/table/missing-cells-with-span.html
@@ -0,0 +1,16 @@
+
\ No newline at end of file
diff --git a/Tests/LibWeb/Layout/input/table/missing-cells.html b/Tests/LibWeb/Layout/input/table/missing-cells.html
new file mode 100644
index 0000000000..11c76298a6
--- /dev/null
+++ b/Tests/LibWeb/Layout/input/table/missing-cells.html
@@ -0,0 +1,16 @@
+
\ No newline at end of file
diff --git a/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp
index 472bf94784..3721933887 100644
--- a/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp
+++ b/Userland/Libraries/LibWeb/Layout/TableFormattingContext.cpp
@@ -12,26 +12,6 @@
#include
#include
-struct GridPosition {
- size_t x;
- size_t y;
-};
-
-inline bool operator==(GridPosition const& a, GridPosition const& b)
-{
- return a.x == b.x && a.y == b.y;
-}
-
-namespace AK {
-template<>
-struct Traits : public GenericTraits {
- static unsigned hash(GridPosition const& key)
- {
- return pair_int_hash(key.x, key.y);
- }
-};
-}
-
namespace Web::Layout {
TableFormattingContext::TableFormattingContext(LayoutState& state, Box const& root, FormattingContext* parent)
diff --git a/Userland/Libraries/LibWeb/Layout/TableFormattingContext.h b/Userland/Libraries/LibWeb/Layout/TableFormattingContext.h
index 0512799217..7c4c04584b 100644
--- a/Userland/Libraries/LibWeb/Layout/TableFormattingContext.h
+++ b/Userland/Libraries/LibWeb/Layout/TableFormattingContext.h
@@ -38,7 +38,6 @@ public:
private:
CSSPixels run_caption_layout(LayoutMode, CSS::CaptionSide);
CSSPixels compute_capmin();
- void calculate_row_column_grid(Box const&);
void compute_constrainedness();
void compute_cell_measures();
void compute_outer_content_sizes();
diff --git a/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp b/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp
index 43b707cc4b..aca6b2caa3 100644
--- a/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp
+++ b/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -451,7 +452,8 @@ void TreeBuilder::fixup_tables(NodeWithStyle& root)
{
remove_irrelevant_boxes(root);
generate_missing_child_wrappers(root);
- generate_missing_parents(root);
+ auto table_root_boxes = generate_missing_parents(root);
+ missing_cells_fixup(table_root_boxes);
}
void TreeBuilder::remove_irrelevant_boxes(NodeWithStyle& root)
@@ -621,7 +623,7 @@ void TreeBuilder::generate_missing_child_wrappers(NodeWithStyle& root)
});
}
-void TreeBuilder::generate_missing_parents(NodeWithStyle& root)
+Vector> TreeBuilder::generate_missing_parents(NodeWithStyle& root)
{
Vector> table_roots_to_wrap;
root.for_each_in_inclusive_subtree_of_type([&](auto& parent) {
@@ -671,6 +673,57 @@ void TreeBuilder::generate_missing_parents(NodeWithStyle& root)
else
parent.append_child(*wrapper);
}
+
+ return table_roots_to_wrap;
}
+template
+static void for_each_child_box_matching(Box& parent, Matcher matcher, Callback callback)
+{
+ parent.for_each_child_of_type([&](Box& child_box) {
+ if (matcher(child_box))
+ callback(child_box);
+ });
+}
+
+static void fixup_row(Box& row_box, TableGrid const& table_grid, size_t row_index)
+{
+ bool missing_cells_run_has_started = false;
+ for (size_t column_index = 0; column_index < table_grid.column_count(); ++column_index) {
+ if (table_grid.occupancy_grid().contains({ column_index, row_index })) {
+ VERIFY(!missing_cells_run_has_started);
+ continue;
+ }
+ missing_cells_run_has_started = true;
+ auto row_computed_values = row_box.computed_values().clone_inherited_values();
+ auto& cell_computed_values = static_cast(row_computed_values);
+ cell_computed_values.set_display(Web::CSS::Display { CSS::Display::Internal::TableCell });
+ // Ensure that the cell (with zero content height) will have the same height as the row by setting vertical-align to middle.
+ cell_computed_values.set_vertical_align(CSS::VerticalAlign::Middle);
+ auto cell_box = row_box.heap().template allocate_without_realm(row_box.document(), nullptr, cell_computed_values);
+ row_box.append_child(cell_box);
+ }
+}
+
+void TreeBuilder::missing_cells_fixup(Vector> const& table_root_boxes)
+{
+ // Implements https://www.w3.org/TR/css-tables-3/#missing-cells-fixup.
+ for (auto& table_box : table_root_boxes) {
+ auto table_grid = TableGrid::calculate_row_column_grid(*table_box);
+ size_t row_index = 0;
+ for_each_child_box_matching(*table_box, TableGrid::is_table_row_group, [&](auto& row_group_box) {
+ for_each_child_box_matching(row_group_box, is_table_row, [&](auto& row_box) {
+ fixup_row(row_box, table_grid, row_index);
+ ++row_index;
+ return IterationDecision::Continue;
+ });
+ });
+
+ for_each_child_box_matching(*table_box, is_table_row, [&](auto& row_box) {
+ fixup_row(row_box, table_grid, row_index);
+ ++row_index;
+ return IterationDecision::Continue;
+ });
+ }
+}
}
diff --git a/Userland/Libraries/LibWeb/Layout/TreeBuilder.h b/Userland/Libraries/LibWeb/Layout/TreeBuilder.h
index e68a4e692b..0c40bf5d5d 100644
--- a/Userland/Libraries/LibWeb/Layout/TreeBuilder.h
+++ b/Userland/Libraries/LibWeb/Layout/TreeBuilder.h
@@ -39,7 +39,8 @@ private:
void fixup_tables(NodeWithStyle& root);
void remove_irrelevant_boxes(NodeWithStyle& root);
void generate_missing_child_wrappers(NodeWithStyle& root);
- void generate_missing_parents(NodeWithStyle& root);
+ Vector> generate_missing_parents(NodeWithStyle& root);
+ void missing_cells_fixup(Vector> const&);
enum class AppendOrPrepend {
Append,
| | | |