Coverage Report

Created: 2026-06-07 07:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}