TableGrid.cpp 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. /*
  2. * Copyright (c) 2023, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibWeb/HTML/HTMLTableCellElement.h>
  7. #include <LibWeb/Layout/TableGrid.h>
  8. namespace Web::Layout {
  9. TableGrid TableGrid::calculate_row_column_grid(Box const& box, Vector<Cell>& cells, Vector<Row>& rows)
  10. {
  11. // Implements https://html.spec.whatwg.org/multipage/tables.html#forming-a-table
  12. TableGrid table_grid;
  13. size_t x_width = 0, y_height = 0;
  14. size_t x_current = 0, y_current = 0;
  15. size_t max_cell_x = 0, max_cell_y = 0;
  16. // Implements https://html.spec.whatwg.org/multipage/tables.html#algorithm-for-processing-rows
  17. auto process_row = [&](auto& row) {
  18. if (y_height == y_current)
  19. y_height++;
  20. x_current = 0;
  21. for (auto* child = row.first_child(); child; child = child->next_sibling()) {
  22. if (child->display().is_table_cell()) {
  23. // 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.
  24. while (x_current < x_width && table_grid.m_occupancy_grid.contains(GridPosition { x_current, y_current }))
  25. x_current++;
  26. Box const* box = static_cast<Box const*>(child);
  27. if (x_current == x_width)
  28. x_width++;
  29. size_t colspan = 1, rowspan = 1;
  30. if (box->dom_node() && is<HTML::HTMLTableCellElement>(*box->dom_node())) {
  31. auto const& node = static_cast<HTML::HTMLTableCellElement const&>(*box->dom_node());
  32. colspan = node.col_span();
  33. rowspan = node.row_span();
  34. }
  35. if (x_width < x_current + colspan && y_current == 0)
  36. x_width = x_current + colspan;
  37. if (y_height < y_current + rowspan)
  38. y_height = y_current + rowspan;
  39. for (size_t y = y_current; y < y_current + rowspan; y++)
  40. for (size_t x = x_current; x < x_current + colspan; x++)
  41. table_grid.m_occupancy_grid.set(GridPosition { x, y }, true);
  42. cells.append(Cell { *box, x_current, y_current, colspan, rowspan });
  43. max_cell_x = max(x_current, max_cell_x);
  44. max_cell_y = max(y_current, max_cell_y);
  45. x_current += colspan;
  46. }
  47. }
  48. rows.append(Row { row });
  49. y_current++;
  50. };
  51. for_each_child_box_matching(box, is_table_row_group, [&](auto& row_group_box) {
  52. for_each_child_box_matching(row_group_box, is_table_row, [&](auto& row_box) {
  53. process_row(row_box);
  54. return IterationDecision::Continue;
  55. });
  56. });
  57. for_each_child_box_matching(box, is_table_row, [&](auto& row_box) {
  58. process_row(row_box);
  59. return IterationDecision::Continue;
  60. });
  61. table_grid.m_column_count = x_width;
  62. for (auto& cell : cells) {
  63. // Clip spans to the end of the table.
  64. cell.row_span = min(cell.row_span, rows.size() - cell.row_index);
  65. cell.column_span = min(cell.column_span, table_grid.m_column_count - cell.column_index);
  66. }
  67. return table_grid;
  68. }
  69. TableGrid TableGrid::calculate_row_column_grid(Box const& box)
  70. {
  71. Vector<Cell> cells;
  72. Vector<Row> rows;
  73. return calculate_row_column_grid(box, cells, rows);
  74. }
  75. }