TableGrid.cpp 3.8 KB

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