/src/serenity/Userland/Libraries/LibWeb/Layout/TableGrid.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2023, the SerenityOS developers. |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <LibWeb/HTML/HTMLTableCellElement.h> |
8 | | #include <LibWeb/HTML/HTMLTableColElement.h> |
9 | | #include <LibWeb/Layout/TableGrid.h> |
10 | | |
11 | | namespace Web::Layout { |
12 | | |
13 | | TableGrid TableGrid::calculate_row_column_grid(Box const& box, Vector<Cell>& cells, Vector<Row>& rows) |
14 | 0 | { |
15 | | // Implements https://html.spec.whatwg.org/multipage/tables.html#forming-a-table |
16 | 0 | TableGrid table_grid; |
17 | |
|
18 | 0 | size_t x_width = 0, y_height = 0; |
19 | 0 | size_t x_current = 0, y_current = 0; |
20 | 0 | size_t max_cell_x = 0, max_cell_y = 0; |
21 | | |
22 | | // Implements https://html.spec.whatwg.org/multipage/tables.html#algorithm-for-processing-rows |
23 | 0 | auto process_row = [&](auto& row) { |
24 | 0 | if (y_height == y_current) |
25 | 0 | y_height++; |
26 | |
|
27 | 0 | x_current = 0; |
28 | |
|
29 | 0 | for (auto* child = row.first_child(); child; child = child->next_sibling()) { |
30 | 0 | if (child->display().is_table_cell()) { |
31 | | // Cells: While x_current is less than x_width and the slot with coordinate (x_current, y_current) already has a cell assigned to it, increase x_current by 1. |
32 | 0 | while (x_current < x_width && table_grid.m_occupancy_grid.contains(GridPosition { x_current, y_current })) |
33 | 0 | x_current++; |
34 | |
|
35 | 0 | Box const* box = static_cast<Box const*>(child); |
36 | 0 | if (x_current == x_width) |
37 | 0 | x_width++; |
38 | |
|
39 | 0 | size_t colspan = 1, rowspan = 1; |
40 | 0 | if (box->dom_node() && is<HTML::HTMLTableCellElement>(*box->dom_node())) { |
41 | 0 | auto const& node = static_cast<HTML::HTMLTableCellElement const&>(*box->dom_node()); |
42 | 0 | colspan = node.col_span(); |
43 | 0 | rowspan = node.row_span(); |
44 | 0 | } |
45 | |
|
46 | 0 | if (x_width < x_current + colspan && y_current == 0) |
47 | 0 | x_width = x_current + colspan; |
48 | 0 | if (y_height < y_current + rowspan) |
49 | 0 | y_height = y_current + rowspan; |
50 | |
|
51 | 0 | for (size_t y = y_current; y < y_current + rowspan; y++) |
52 | 0 | for (size_t x = x_current; x < x_current + colspan; x++) |
53 | 0 | table_grid.m_occupancy_grid.set(GridPosition { x, y }, true); |
54 | 0 | cells.append(Cell { *box, x_current, y_current, colspan, rowspan }); |
55 | 0 | max_cell_x = max(x_current, max_cell_x); |
56 | 0 | max_cell_y = max(y_current, max_cell_y); |
57 | |
|
58 | 0 | x_current += colspan; |
59 | 0 | } |
60 | 0 | } |
61 | |
|
62 | 0 | rows.append(Row { row }); |
63 | 0 | y_current++; |
64 | 0 | }; |
65 | |
|
66 | 0 | auto process_col_group = [&](auto& col_group) { |
67 | 0 | auto dom_node = col_group.dom_node(); |
68 | 0 | dom_node->template for_each_in_subtree_of_type<HTML::HTMLTableColElement>([&](auto&) { |
69 | 0 | x_width += 1; |
70 | 0 | return TraversalDecision::Continue; |
71 | 0 | }); |
72 | 0 | }; |
73 | |
|
74 | 0 | for_each_child_box_matching(box, is_table_column_group, [&](auto& column_group_box) { |
75 | 0 | process_col_group(column_group_box); |
76 | 0 | }); |
77 | |
|
78 | 0 | for_each_child_box_matching(box, is_table_row_group, [&](auto& row_group_box) { |
79 | 0 | for_each_child_box_matching(row_group_box, is_table_row, [&](auto& row_box) { |
80 | 0 | process_row(row_box); |
81 | 0 | return IterationDecision::Continue; |
82 | 0 | }); |
83 | 0 | }); |
84 | |
|
85 | 0 | for_each_child_box_matching(box, is_table_row, [&](auto& row_box) { |
86 | 0 | process_row(row_box); |
87 | 0 | return IterationDecision::Continue; |
88 | 0 | }); |
89 | |
|
90 | 0 | table_grid.m_column_count = x_width; |
91 | |
|
92 | 0 | for (auto& cell : cells) { |
93 | | // Clip spans to the end of the table. |
94 | 0 | cell.row_span = min(cell.row_span, rows.size() - cell.row_index); |
95 | 0 | cell.column_span = min(cell.column_span, table_grid.m_column_count - cell.column_index); |
96 | 0 | } |
97 | |
|
98 | 0 | return table_grid; |
99 | 0 | } |
100 | | |
101 | | TableGrid TableGrid::calculate_row_column_grid(Box const& box) |
102 | 0 | { |
103 | 0 | Vector<Cell> cells; |
104 | 0 | Vector<Row> rows; |
105 | 0 | return calculate_row_column_grid(box, cells, rows); |
106 | 0 | } |
107 | | |
108 | | } |