mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-07 21:59:54 +00:00
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.
This commit is contained in:
parent
2af63149ec
commit
6ca69d9e26
Notes:
github-actions[bot]
2025-11-30 10:49:07 +00:00
Author: https://github.com/AtkinsSJ
Commit: 6ca69d9e26
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6959
2 changed files with 89 additions and 34 deletions
|
|
@ -129,13 +129,14 @@ void HTMLTableCellElement::apply_presentational_hints(GC::Ref<CSS::CascadedPrope
|
|||
// https://html.spec.whatwg.org/multipage/tables.html#algorithm-for-processing-rows
|
||||
WebIDL::UnsignedLong HTMLTableCellElement::col_span() const
|
||||
{
|
||||
// If the current cell has a colspan attribute, then parse that attribute's value, and let colspan be the result.
|
||||
// If parsing that value failed, or returned zero, or if the attribute is absent, then let colspan be 1, instead.
|
||||
auto col_span_attribute = get_attribute(HTML::AttributeNames::colspan);
|
||||
if (!col_span_attribute.has_value())
|
||||
return 1;
|
||||
|
||||
auto optional_value_digits = Web::HTML::parse_non_negative_integer_digits(*col_span_attribute);
|
||||
|
||||
// If parsing that value failed, or returned zero, or if the attribute is absent, then let colspan be 1, instead.
|
||||
if (!optional_value_digits.has_value())
|
||||
return 1;
|
||||
|
||||
|
|
@ -143,7 +144,7 @@ WebIDL::UnsignedLong HTMLTableCellElement::col_span() const
|
|||
if (optional_value == 0)
|
||||
return 1;
|
||||
|
||||
// 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.
|
||||
// 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.
|
||||
if (!optional_value.has_value())
|
||||
return 1000;
|
||||
|
||||
|
|
@ -168,11 +169,12 @@ void HTMLTableCellElement::set_col_span(WebIDL::UnsignedLong value)
|
|||
// https://html.spec.whatwg.org/multipage/tables.html#algorithm-for-processing-rows
|
||||
WebIDL::UnsignedLong HTMLTableCellElement::row_span() const
|
||||
{
|
||||
// If the current cell has a rowspan attribute, then parse that attribute's value, and let rowspan be the result.
|
||||
// If parsing that value failed or if the attribute is absent, then let rowspan be 1, instead.
|
||||
auto row_span_attribute = get_attribute(HTML::AttributeNames::rowspan);
|
||||
if (!row_span_attribute.has_value())
|
||||
return 1;
|
||||
|
||||
// If parsing that value failed or if the attribute is absent, then let rowspan be 1, instead.
|
||||
auto optional_value_digits = Web::HTML::parse_non_negative_integer_digits(*row_span_attribute);
|
||||
if (!optional_value_digits.has_value())
|
||||
return 1;
|
||||
|
|
@ -180,7 +182,7 @@ WebIDL::UnsignedLong HTMLTableCellElement::row_span() const
|
|||
auto optional_value = optional_value_digits->to_number<i64>(TrimWhitespace::No);
|
||||
|
||||
// If rowspan is greater than 65534, let it be 65534 instead.
|
||||
// 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.
|
||||
// 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.
|
||||
if (!optional_value.has_value() || *optional_value > 65534)
|
||||
return 65534;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,50 +15,103 @@ TableGrid TableGrid::calculate_row_column_grid(Box const& box, Vector<Cell>& cel
|
|||
// Implements https://html.spec.whatwg.org/multipage/tables.html#forming-a-table
|
||||
TableGrid table_grid;
|
||||
|
||||
size_t x_width = 0, y_height = 0;
|
||||
size_t x_current = 0, y_current = 0;
|
||||
size_t max_cell_x = 0, max_cell_y = 0;
|
||||
size_t x_width = 0;
|
||||
size_t y_height = 0;
|
||||
size_t y_current = 0;
|
||||
size_t max_cell_x = 0;
|
||||
size_t max_cell_y = 0;
|
||||
|
||||
// Implements https://html.spec.whatwg.org/multipage/tables.html#algorithm-for-processing-rows
|
||||
auto process_row = [&](auto& row, Optional<Box&> row_group = {}) {
|
||||
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 = {}) {
|
||||
// 1. If yheight is equal to ycurrent, then increase yheight by 1. (ycurrent is never greater than yheight.)
|
||||
if (y_height == y_current)
|
||||
y_height++;
|
||||
|
||||
x_current = 0;
|
||||
// 2. Let xcurrent be 0.
|
||||
size_t x_current = 0;
|
||||
|
||||
// FIXME: 3. Run the algorithm for growing downward-growing cells.
|
||||
|
||||
// 4. If the tr element being processed has no td or th element children, then increase ycurrent by 1, abort
|
||||
// this set of steps, and return to the algorithm above.
|
||||
// NB: The remaining steps already accomplish the same thing in this case.
|
||||
|
||||
// 5. Let current cell be the first td or th element child in the tr element being processed.
|
||||
for (auto* child = row.first_child(); child; child = child->next_sibling()) {
|
||||
if (child->display().is_table_cell()) {
|
||||
// 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.
|
||||
while (x_current < x_width && table_grid.m_occupancy_grid.contains(GridPosition { x_current, y_current }))
|
||||
x_current++;
|
||||
// NB: This actually applies to children with `display: table-cell`, not just td/th elements.
|
||||
if (!child->display().is_table_cell())
|
||||
continue;
|
||||
|
||||
Box const* box = static_cast<Box const*>(child);
|
||||
if (x_current == x_width)
|
||||
x_width++;
|
||||
auto& current_cell = as<Box>(*child);
|
||||
|
||||
size_t colspan = 1, rowspan = 1;
|
||||
if (box->dom_node() && is<HTML::HTMLTableCellElement>(*box->dom_node())) {
|
||||
auto const& node = static_cast<HTML::HTMLTableCellElement const&>(*box->dom_node());
|
||||
colspan = node.col_span();
|
||||
rowspan = node.row_span();
|
||||
}
|
||||
// 6. 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.
|
||||
while (x_current < x_width && table_grid.m_occupancy_grid.contains(GridPosition { x_current, y_current }))
|
||||
x_current++;
|
||||
|
||||
if (x_width < x_current + colspan)
|
||||
x_width = x_current + colspan;
|
||||
if (y_height < y_current + rowspan)
|
||||
y_height = y_current + rowspan;
|
||||
// 7. If xcurrent is equal to xwidth, increase xwidth by 1. (xcurrent is never greater than xwidth.)
|
||||
if (x_current == x_width)
|
||||
x_width++;
|
||||
|
||||
for (size_t y = y_current; y < y_current + rowspan; y++)
|
||||
for (size_t x = x_current; x < x_current + colspan; x++)
|
||||
table_grid.m_occupancy_grid.set(GridPosition { x, y }, true);
|
||||
cells.append(Cell { *box, x_current, y_current, colspan, rowspan });
|
||||
max_cell_x = max(x_current, max_cell_x);
|
||||
max_cell_y = max(y_current, max_cell_y);
|
||||
|
||||
x_current += colspan;
|
||||
// NB: Steps 8 and 9 are implemented in HTMLTableCellElement.col_span() and HTMLTableCellElement.row_spam() respectively.
|
||||
size_t colspan = 1;
|
||||
size_t rowspan = 1;
|
||||
if (auto* table_cell = as_if<HTML::HTMLTableCellElement>(current_cell.dom_node())) {
|
||||
colspan = table_cell->col_span();
|
||||
rowspan = table_cell->row_span();
|
||||
}
|
||||
|
||||
// 10. Let cell grows downward be false.
|
||||
auto cell_grows_downward = false;
|
||||
|
||||
// 11. If rowspan is zero, then set cell grows downward to true and set rowspan to 1.
|
||||
if (rowspan == 0) {
|
||||
cell_grows_downward = true;
|
||||
rowspan = 1;
|
||||
}
|
||||
|
||||
// 12. If xwidth < xcurrent+colspan, then let xwidth be xcurrent+colspan.
|
||||
if (x_width < x_current + colspan)
|
||||
x_width = x_current + colspan;
|
||||
|
||||
// 13. If yheight < ycurrent+rowspan, then let yheight be ycurrent+rowspan.
|
||||
if (y_height < y_current + rowspan)
|
||||
y_height = y_current + rowspan;
|
||||
|
||||
// 14. Let the slots with coordinates (x, y) such that xcurrent ≤ x < xcurrent+colspan and
|
||||
// ycurrent ≤ y < ycurrent+rowspan be covered by a new cell c, anchored at (xcurrent, ycurrent),
|
||||
// which has width colspan and height rowspan, corresponding to the current cell element.
|
||||
// If the current cell element is a th element, let this new cell c be a header cell;
|
||||
// otherwise, let it be a data cell.
|
||||
// To establish which header cells apply to the current cell element, use the algorithm for
|
||||
// assigning header cells described in the next section.
|
||||
// If any of the slots involved already had a cell covering them, then this is a table model error.
|
||||
// Those slots now have two cells overlapping.
|
||||
// NB: We don't distinguish between header and data cells here.
|
||||
for (size_t y = y_current; y < y_current + rowspan; y++)
|
||||
for (size_t x = x_current; x < x_current + colspan; x++)
|
||||
table_grid.m_occupancy_grid.set(GridPosition { x, y }, true);
|
||||
cells.append(Cell { current_cell, x_current, y_current, colspan, rowspan });
|
||||
max_cell_x = max(x_current, max_cell_x);
|
||||
max_cell_y = max(y_current, max_cell_y);
|
||||
|
||||
// 15. If cell grows downward is true, then add the tuple {c, xcurrent, colspan} to the list of downward-growing cells.
|
||||
if (cell_grows_downward) {
|
||||
// FIXME: Add the tuple.
|
||||
}
|
||||
|
||||
// 16. Increase xcurrent by colspan.
|
||||
x_current += colspan;
|
||||
|
||||
// NB: Step 17 is handled below, outside of this loop.
|
||||
|
||||
// 18. Let current cell be the next td or th element child in the tr element being processed.
|
||||
// 19. Return to the step labeled cells.
|
||||
// NB: Handled by the loop.
|
||||
}
|
||||
|
||||
// 17. If current cell is the last td or th element child in the tr element being processed, then increase
|
||||
// ycurrent by 1, abort this set of steps, and return to the algorithm above.
|
||||
rows.append(Row {
|
||||
.box = row,
|
||||
.is_collapsed = row.computed_values().visibility() == CSS::Visibility::Collapse
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue