Skip to content

Commit 6ca69d9

Browse files
AtkinsSJawesomekling
authored andcommitted
LibWeb/Layout: Spec-comment Table "algorithm for processing rows"
Some of this is rearranged for clarity, but it's mostly the exact same code. Steps 3, 10, 11, and 15 are new, but don't have any effect until we implement downward-growing cells.
1 parent 2af6314 commit 6ca69d9

File tree

2 files changed

+93
-38
lines changed

2 files changed

+93
-38
lines changed

Libraries/LibWeb/HTML/HTMLTableCellElement.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,21 +129,22 @@ void HTMLTableCellElement::apply_presentational_hints(GC::Ref<CSS::CascadedPrope
129129
// https://html.spec.whatwg.org/multipage/tables.html#algorithm-for-processing-rows
130130
WebIDL::UnsignedLong HTMLTableCellElement::col_span() const
131131
{
132+
// If the current cell has a colspan attribute, then parse that attribute's value, and let colspan be the result.
133+
// If parsing that value failed, or returned zero, or if the attribute is absent, then let colspan be 1, instead.
132134
auto col_span_attribute = get_attribute(HTML::AttributeNames::colspan);
133135
if (!col_span_attribute.has_value())
134136
return 1;
135137

136138
auto optional_value_digits = Web::HTML::parse_non_negative_integer_digits(*col_span_attribute);
137139

138-
// If parsing that value failed, or returned zero, or if the attribute is absent, then let colspan be 1, instead.
139140
if (!optional_value_digits.has_value())
140141
return 1;
141142

142143
auto optional_value = optional_value_digits->to_number<i64>(TrimWhitespace::No);
143144
if (optional_value == 0)
144145
return 1;
145146

146-
// NOTE: If there is no value at this point the value must be larger than NumericLimits<i64>::max(), so return the maximum value of 1000.
147+
// NB: If there is no value at this point the value must be larger than NumericLimits<i64>::max(), so return the maximum value of 1000.
147148
if (!optional_value.has_value())
148149
return 1000;
149150

@@ -168,19 +169,20 @@ void HTMLTableCellElement::set_col_span(WebIDL::UnsignedLong value)
168169
// https://html.spec.whatwg.org/multipage/tables.html#algorithm-for-processing-rows
169170
WebIDL::UnsignedLong HTMLTableCellElement::row_span() const
170171
{
172+
// If the current cell has a rowspan attribute, then parse that attribute's value, and let rowspan be the result.
173+
// If parsing that value failed or if the attribute is absent, then let rowspan be 1, instead.
171174
auto row_span_attribute = get_attribute(HTML::AttributeNames::rowspan);
172175
if (!row_span_attribute.has_value())
173176
return 1;
174177

175-
// If parsing that value failed or if the attribute is absent, then let rowspan be 1, instead.
176178
auto optional_value_digits = Web::HTML::parse_non_negative_integer_digits(*row_span_attribute);
177179
if (!optional_value_digits.has_value())
178180
return 1;
179181

180182
auto optional_value = optional_value_digits->to_number<i64>(TrimWhitespace::No);
181183

182184
// If rowspan is greater than 65534, let it be 65534 instead.
183-
// NOTE: If there is no value at this point the value must be larger than NumericLimits<i64>::max(), so return the maximum value of 65534.
185+
// NB: If there is no value at this point the value must be larger than NumericLimits<i64>::max(), so return the maximum value of 65534.
184186
if (!optional_value.has_value() || *optional_value > 65534)
185187
return 65534;
186188

Libraries/LibWeb/Layout/TableGrid.cpp

Lines changed: 87 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,50 +15,103 @@ TableGrid TableGrid::calculate_row_column_grid(Box const& box, Vector<Cell>& cel
1515
// Implements https://html.spec.whatwg.org/multipage/tables.html#forming-a-table
1616
TableGrid table_grid;
1717

18-
size_t x_width = 0, y_height = 0;
19-
size_t x_current = 0, y_current = 0;
20-
size_t max_cell_x = 0, max_cell_y = 0;
18+
size_t x_width = 0;
19+
size_t y_height = 0;
20+
size_t y_current = 0;
21+
size_t max_cell_x = 0;
22+
size_t max_cell_y = 0;
2123

2224
// Implements https://html.spec.whatwg.org/multipage/tables.html#algorithm-for-processing-rows
23-
auto process_row = [&](auto& row, Optional<Box&> row_group = {}) {
25+
auto process_row = [&table_grid, &cells, &rows, &x_width, &y_height, &y_current, &max_cell_x, &max_cell_y](Box const& row, Optional<Box&> row_group = {}) {
26+
// 1. If yheight is equal to ycurrent, then increase yheight by 1. (ycurrent is never greater than yheight.)
2427
if (y_height == y_current)
2528
y_height++;
2629

27-
x_current = 0;
30+
// 2. Let xcurrent be 0.
31+
size_t x_current = 0;
2832

33+
// FIXME: 3. Run the algorithm for growing downward-growing cells.
34+
35+
// 4. If the tr element being processed has no td or th element children, then increase ycurrent by 1, abort
36+
// this set of steps, and return to the algorithm above.
37+
// NB: The remaining steps already accomplish the same thing in this case.
38+
39+
// 5. Let current cell be the first td or th element child in the tr element being processed.
2940
for (auto* child = row.first_child(); child; child = child->next_sibling()) {
30-
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-
while (x_current < x_width && table_grid.m_occupancy_grid.contains(GridPosition { x_current, y_current }))
33-
x_current++;
34-
35-
Box const* box = static_cast<Box const*>(child);
36-
if (x_current == x_width)
37-
x_width++;
38-
39-
size_t colspan = 1, rowspan = 1;
40-
if (box->dom_node() && is<HTML::HTMLTableCellElement>(*box->dom_node())) {
41-
auto const& node = static_cast<HTML::HTMLTableCellElement const&>(*box->dom_node());
42-
colspan = node.col_span();
43-
rowspan = node.row_span();
44-
}
45-
46-
if (x_width < x_current + colspan)
47-
x_width = x_current + colspan;
48-
if (y_height < y_current + rowspan)
49-
y_height = y_current + rowspan;
50-
51-
for (size_t y = y_current; y < y_current + rowspan; y++)
52-
for (size_t x = x_current; x < x_current + colspan; x++)
53-
table_grid.m_occupancy_grid.set(GridPosition { x, y }, true);
54-
cells.append(Cell { *box, x_current, y_current, colspan, rowspan });
55-
max_cell_x = max(x_current, max_cell_x);
56-
max_cell_y = max(y_current, max_cell_y);
57-
58-
x_current += colspan;
41+
// NB: This actually applies to children with `display: table-cell`, not just td/th elements.
42+
if (!child->display().is_table_cell())
43+
continue;
44+
45+
auto& current_cell = as<Box>(*child);
46+
47+
// 6. Cells: While x_current is less than x_width and the slot with coordinate (x_current, y_current)
48+
// already has a cell assigned to it, increase x_current by 1.
49+
while (x_current < x_width && table_grid.m_occupancy_grid.contains(GridPosition { x_current, y_current }))
50+
x_current++;
51+
52+
// 7. If xcurrent is equal to xwidth, increase xwidth by 1. (xcurrent is never greater than xwidth.)
53+
if (x_current == x_width)
54+
x_width++;
55+
56+
// NB: Steps 8 and 9 are implemented in HTMLTableCellElement.col_span() and HTMLTableCellElement.row_spam() respectively.
57+
size_t colspan = 1;
58+
size_t rowspan = 1;
59+
if (auto* table_cell = as_if<HTML::HTMLTableCellElement>(current_cell.dom_node())) {
60+
colspan = table_cell->col_span();
61+
rowspan = table_cell->row_span();
62+
}
63+
64+
// 10. Let cell grows downward be false.
65+
auto cell_grows_downward = false;
66+
67+
// 11. If rowspan is zero, then set cell grows downward to true and set rowspan to 1.
68+
if (rowspan == 0) {
69+
cell_grows_downward = true;
70+
rowspan = 1;
5971
}
72+
73+
// 12. If xwidth < xcurrent+colspan, then let xwidth be xcurrent+colspan.
74+
if (x_width < x_current + colspan)
75+
x_width = x_current + colspan;
76+
77+
// 13. If yheight < ycurrent+rowspan, then let yheight be ycurrent+rowspan.
78+
if (y_height < y_current + rowspan)
79+
y_height = y_current + rowspan;
80+
81+
// 14. Let the slots with coordinates (x, y) such that xcurrent ≤ x < xcurrent+colspan and
82+
// ycurrent ≤ y < ycurrent+rowspan be covered by a new cell c, anchored at (xcurrent, ycurrent),
83+
// which has width colspan and height rowspan, corresponding to the current cell element.
84+
// If the current cell element is a th element, let this new cell c be a header cell;
85+
// otherwise, let it be a data cell.
86+
// To establish which header cells apply to the current cell element, use the algorithm for
87+
// assigning header cells described in the next section.
88+
// If any of the slots involved already had a cell covering them, then this is a table model error.
89+
// Those slots now have two cells overlapping.
90+
// NB: We don't distinguish between header and data cells here.
91+
for (size_t y = y_current; y < y_current + rowspan; y++)
92+
for (size_t x = x_current; x < x_current + colspan; x++)
93+
table_grid.m_occupancy_grid.set(GridPosition { x, y }, true);
94+
cells.append(Cell { current_cell, x_current, y_current, colspan, rowspan });
95+
max_cell_x = max(x_current, max_cell_x);
96+
max_cell_y = max(y_current, max_cell_y);
97+
98+
// 15. If cell grows downward is true, then add the tuple {c, xcurrent, colspan} to the list of downward-growing cells.
99+
if (cell_grows_downward) {
100+
// FIXME: Add the tuple.
101+
}
102+
103+
// 16. Increase xcurrent by colspan.
104+
x_current += colspan;
105+
106+
// NB: Step 17 is handled below, outside of this loop.
107+
108+
// 18. Let current cell be the next td or th element child in the tr element being processed.
109+
// 19. Return to the step labeled cells.
110+
// NB: Handled by the loop.
60111
}
61112

113+
// 17. If current cell is the last td or th element child in the tr element being processed, then increase
114+
// ycurrent by 1, abort this set of steps, and return to the algorithm above.
62115
rows.append(Row {
63116
.box = row,
64117
.is_collapsed = row.computed_values().visibility() == CSS::Visibility::Collapse

0 commit comments

Comments
 (0)