| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | /*
 | 
					
						
							|  |  |  |  |  * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-04-22 01:24:48 -07:00
										 |  |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  |  */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include <LibWeb/DOM/Node.h>
 | 
					
						
							| 
									
										
										
										
											2021-11-18 15:01:28 +01:00
										 |  |  |  | #include <LibWeb/HTML/BrowsingContext.h>
 | 
					
						
							| 
									
										
										
										
											2020-11-22 15:53:01 +01:00
										 |  |  |  | #include <LibWeb/Layout/Box.h>
 | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | #include <LibWeb/Layout/InlineFormattingContext.h>
 | 
					
						
							| 
									
										
										
										
											2020-11-22 15:53:01 +01:00
										 |  |  |  | #include <LibWeb/Layout/TableBox.h>
 | 
					
						
							|  |  |  |  | #include <LibWeb/Layout/TableCellBox.h>
 | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | #include <LibWeb/Layout/TableFormattingContext.h>
 | 
					
						
							| 
									
										
										
										
											2020-11-22 15:53:01 +01:00
										 |  |  |  | #include <LibWeb/Layout/TableRowBox.h>
 | 
					
						
							|  |  |  |  | #include <LibWeb/Layout/TableRowGroupBox.h>
 | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  | struct GridPosition { | 
					
						
							|  |  |  |  |     size_t x; | 
					
						
							|  |  |  |  |     size_t y; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | inline bool operator==(GridPosition const& a, GridPosition const& b) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     return a.x == b.x && a.y == b.y; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | namespace AK { | 
					
						
							|  |  |  |  | template<> | 
					
						
							|  |  |  |  | struct Traits<GridPosition> : public GenericTraits<GridPosition> { | 
					
						
							|  |  |  |  |     static unsigned hash(GridPosition const& key) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |         return pair_int_hash(key.x, key.y); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | namespace Web::Layout { | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 21:57:21 +03:00
										 |  |  |  | TableFormattingContext::TableFormattingContext(LayoutState& state, BlockContainer const& root, FormattingContext* parent) | 
					
						
							|  |  |  |  |     : FormattingContext(Type::Table, state, root, parent) | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | { | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-14 13:21:51 -06:00
										 |  |  |  | TableFormattingContext::~TableFormattingContext() = default; | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  | void TableFormattingContext::calculate_row_column_grid(Box const& box) | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |     // Implements https://html.spec.whatwg.org/multipage/tables.html#forming-a-table
 | 
					
						
							|  |  |  |  |     HashMap<GridPosition, bool> grid; | 
					
						
							| 
									
										
										
										
											2022-02-20 15:51:24 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |     size_t x_width = 0, y_height = 0; | 
					
						
							|  |  |  |  |     size_t x_current = 0, y_current = 0; | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |     auto process_row = [&](auto& row) { | 
					
						
							|  |  |  |  |         if (y_height == y_current) | 
					
						
							|  |  |  |  |             y_height++; | 
					
						
							| 
									
										
										
										
											2020-11-29 22:37:15 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |         x_current = 0; | 
					
						
							|  |  |  |  |         while (x_current < x_width && grid.contains(GridPosition { x_current, y_current })) | 
					
						
							|  |  |  |  |             x_current++; | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |         for (auto* child = row.first_child(); child; child = child->next_sibling()) { | 
					
						
							|  |  |  |  |             if (is<TableCellBox>(*child)) { | 
					
						
							|  |  |  |  |                 Box* box = static_cast<Box*>(child); | 
					
						
							|  |  |  |  |                 if (x_current == x_width) | 
					
						
							|  |  |  |  |                     x_width++; | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |                 const size_t colspan = static_cast<TableCellBox*>(child)->colspan(); | 
					
						
							| 
									
										
										
										
											2022-12-04 22:44:19 +03:00
										 |  |  |  |                 const size_t rowspan = static_cast<TableCellBox*>(child)->rowspan(); | 
					
						
							| 
									
										
										
										
											2022-03-29 00:10:59 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |                 if (x_width < x_current + colspan) | 
					
						
							|  |  |  |  |                     x_width = x_current + colspan; | 
					
						
							|  |  |  |  |                 if (y_height < y_current + rowspan) | 
					
						
							|  |  |  |  |                     y_height = y_current + rowspan; | 
					
						
							| 
									
										
										
										
											2022-03-29 00:10:59 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |                 for (size_t y = y_current; y < y_current + rowspan; y++) | 
					
						
							|  |  |  |  |                     for (size_t x = x_current; x < x_current + colspan; x++) | 
					
						
							|  |  |  |  |                         grid.set(GridPosition { x, y }, true); | 
					
						
							|  |  |  |  |                 m_cells.append(Cell { *box, x_current, y_current, colspan, rowspan }); | 
					
						
							| 
									
										
										
										
											2022-03-29 00:10:59 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |                 x_current += colspan; | 
					
						
							| 
									
										
										
										
											2022-03-29 00:10:59 +02:00
										 |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-03-28 14:35:10 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |         m_rows.append(Row { row }); | 
					
						
							|  |  |  |  |         y_current++; | 
					
						
							|  |  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |     box.template for_each_child_of_type<TableRowGroupBox>([&](auto& row_group_box) { | 
					
						
							| 
									
										
										
										
											2020-12-06 19:48:02 +01:00
										 |  |  |  |         row_group_box.template for_each_child_of_type<TableRowBox>([&](auto& row) { | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |             process_row(row); | 
					
						
							|  |  |  |  |             return IterationDecision::Continue; | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  |         }); | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-09 12:44:38 +03:00
										 |  |  |  |     box.template for_each_child_of_type<TableRowBox>([&](auto& row) { | 
					
						
							|  |  |  |  |         process_row(row); | 
					
						
							|  |  |  |  |         return IterationDecision::Continue; | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |     m_columns.resize(x_width); | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-10-28 14:41:01 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  | void TableFormattingContext::compute_table_measures() | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     for (auto& cell : m_cells) { | 
					
						
							|  |  |  |  |         auto width_of_containing_block = m_state.get(*cell.box.containing_block()).content_width(); | 
					
						
							|  |  |  |  |         auto width_of_containing_block_as_length = CSS::Length::make_px(width_of_containing_block); | 
					
						
							| 
									
										
										
										
											2022-12-09 13:44:41 +03:00
										 |  |  |  |         auto& computed_values = cell.box.computed_values(); | 
					
						
							|  |  |  |  |         float padding_left = computed_values.padding().left().resolved(cell.box, width_of_containing_block_as_length).to_px(cell.box); | 
					
						
							|  |  |  |  |         float padding_right = computed_values.padding().right().resolved(cell.box, width_of_containing_block_as_length).to_px(cell.box); | 
					
						
							| 
									
										
										
										
											2023-01-02 23:06:55 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         auto is_left_most_cell = cell.column_index == 0; | 
					
						
							|  |  |  |  |         auto is_right_most_cell = cell.column_index == m_columns.size() - 1; | 
					
						
							|  |  |  |  |         auto should_hide_borders = cell.box.computed_values().border_collapse() == CSS::BorderCollapse::Collapse; | 
					
						
							|  |  |  |  |         float border_left = should_hide_borders && !is_left_most_cell ? 0 : computed_values.border_left().width; | 
					
						
							|  |  |  |  |         float border_right = should_hide_borders && !is_right_most_cell ? 0 : computed_values.border_right().width; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-09 13:44:41 +03:00
										 |  |  |  |         float width = computed_values.width().resolved(cell.box, width_of_containing_block_as_length).to_px(cell.box); | 
					
						
							|  |  |  |  |         auto cell_intrinsic_offsets = padding_left + padding_right + border_left + border_right; | 
					
						
							|  |  |  |  |         auto min_content_width = calculate_min_content_width(cell.box); | 
					
						
							|  |  |  |  |         auto max_content_width = calculate_max_content_width(cell.box); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-23 17:46:10 +00:00
										 |  |  |  |         float min_width = min_content_width.value(); | 
					
						
							| 
									
										
										
										
											2022-12-09 13:44:41 +03:00
										 |  |  |  |         if (!computed_values.min_width().is_auto()) | 
					
						
							|  |  |  |  |             min_width = max(min_width, computed_values.min_width().resolved(cell.box, width_of_containing_block_as_length).to_px(cell.box)); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-23 17:46:10 +00:00
										 |  |  |  |         float max_width = computed_values.width().is_auto() ? max_content_width.value() : width; | 
					
						
							| 
									
										
										
										
											2022-12-09 13:44:41 +03:00
										 |  |  |  |         if (!computed_values.max_width().is_none()) | 
					
						
							|  |  |  |  |             max_width = min(max_width, computed_values.max_width().resolved(cell.box, width_of_containing_block_as_length).to_px(cell.box)); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         auto cell_outer_min_content_width = min_width + cell_intrinsic_offsets; | 
					
						
							|  |  |  |  |         auto cell_outer_max_content_width = max(max(width, min_width), max_width) + cell_intrinsic_offsets; | 
					
						
							|  |  |  |  |         m_columns[cell.column_index].min_width = max(m_columns[cell.column_index].min_width, cell_outer_min_content_width); | 
					
						
							|  |  |  |  |         m_columns[cell.column_index].max_width = max(m_columns[cell.column_index].max_width, cell_outer_max_content_width); | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     for (auto& column : m_columns) { | 
					
						
							|  |  |  |  |         column.used_width = column.min_width; | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  | void TableFormattingContext::compute_table_width(float& extra_width) | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |     auto const& table_box = context_box(); | 
					
						
							|  |  |  |  |     auto& table_box_state = m_state.get_mutable(table_box); | 
					
						
							| 
									
										
										
										
											2022-07-09 15:17:47 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |     auto& computed_values = table_box.computed_values(); | 
					
						
							| 
									
										
										
										
											2022-03-29 00:10:59 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |     float width_of_table_containing_block = m_state.get(*table_box.containing_block()).content_width(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // The row/column-grid width minimum (GRIDMIN) width is the sum of the min-content width
 | 
					
						
							|  |  |  |  |     // of all the columns plus cell spacing or borders.
 | 
					
						
							|  |  |  |  |     float grid_min = 0.0f; | 
					
						
							|  |  |  |  |     for (auto& column : m_columns) { | 
					
						
							|  |  |  |  |         grid_min += column.min_width; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // The row/column-grid width maximum (GRIDMAX) width is the sum of the max-content width
 | 
					
						
							|  |  |  |  |     // of all the columns plus cell spacing or borders.
 | 
					
						
							|  |  |  |  |     float grid_max = 0.0f; | 
					
						
							|  |  |  |  |     for (auto& column : m_columns) { | 
					
						
							|  |  |  |  |         grid_max += column.max_width; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // The used min-width of a table is the greater of the resolved min-width, CAPMIN, and GRIDMIN.
 | 
					
						
							|  |  |  |  |     float used_min_width = grid_min; | 
					
						
							|  |  |  |  |     if (!computed_values.min_width().is_auto()) { | 
					
						
							|  |  |  |  |         used_min_width = max(used_min_width, computed_values.min_width().resolved(table_box, CSS::Length::make_px(width_of_table_containing_block)).to_px(table_box)); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     float used_width; | 
					
						
							|  |  |  |  |     if (computed_values.width().is_auto()) { | 
					
						
							|  |  |  |  |         // If the table-root has 'width: auto', the used width is the greater of
 | 
					
						
							|  |  |  |  |         // min(GRIDMAX, the table’s containing block width), the used min-width of the table.
 | 
					
						
							|  |  |  |  |         used_width = max(min(grid_max, width_of_table_containing_block), used_min_width); | 
					
						
							|  |  |  |  |         table_box_state.set_content_width(used_width); | 
					
						
							|  |  |  |  |     } else { | 
					
						
							|  |  |  |  |         // If the table-root’s width property has a computed value (resolving to
 | 
					
						
							|  |  |  |  |         // resolved-table-width) other than auto, the used width is the greater
 | 
					
						
							|  |  |  |  |         // of resolved-table-width, and the used min-width of the table.
 | 
					
						
							|  |  |  |  |         float resolved_table_width = computed_values.width().resolved(table_box, CSS::Length::make_px(width_of_table_containing_block)).to_px(table_box); | 
					
						
							|  |  |  |  |         used_width = max(resolved_table_width, used_min_width); | 
					
						
							|  |  |  |  |         table_box_state.set_content_width(used_width); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (used_width > grid_min) { | 
					
						
							|  |  |  |  |         extra_width = used_width - grid_min; | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  | void TableFormattingContext::distribute_width_to_columns(float extra_width) | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |     float grid_max = 0.0f; | 
					
						
							|  |  |  |  |     for (auto& column : m_columns) | 
					
						
							|  |  |  |  |         grid_max += column.max_width - column.min_width; | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-02 22:53:19 +01:00
										 |  |  |  |     if (grid_max == 0) | 
					
						
							|  |  |  |  |         return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |     for (auto& column : m_columns) | 
					
						
							|  |  |  |  |         column.used_width += ((column.max_width - column.min_width) / grid_max) * extra_width; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:47:45 +03:00
										 |  |  |  | void TableFormattingContext::determine_intrisic_size_of_table_container(AvailableSpace const& available_space) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     auto const& table_box = context_box(); | 
					
						
							|  |  |  |  |     auto& table_box_state = m_state.get_mutable(table_box); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (available_space.width.is_min_content()) { | 
					
						
							|  |  |  |  |         // The min-content width of a table is the width required to fit all of its columns min-content widths and its undistributable spaces.
 | 
					
						
							|  |  |  |  |         float grid_min = 0.0f; | 
					
						
							|  |  |  |  |         for (auto& column : m_columns) | 
					
						
							|  |  |  |  |             grid_min += column.min_width; | 
					
						
							|  |  |  |  |         table_box_state.set_content_width(grid_min); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (available_space.width.is_max_content()) { | 
					
						
							|  |  |  |  |         // The max-content width of a table is the width required to fit all of its columns max-content widths and its undistributable spaces.
 | 
					
						
							|  |  |  |  |         float grid_max = 0.0f; | 
					
						
							|  |  |  |  |         for (auto& column : m_columns) | 
					
						
							|  |  |  |  |             grid_max += column.max_width; | 
					
						
							|  |  |  |  |         table_box_state.set_content_width(grid_max); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  | void TableFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const& available_space) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |     float total_content_height = 0; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // Determine the number of rows/columns the table requires.
 | 
					
						
							|  |  |  |  |     calculate_row_column_grid(box); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // Compute the minimum width of each column.
 | 
					
						
							|  |  |  |  |     compute_table_measures(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:47:45 +03:00
										 |  |  |  |     if (available_space.width.is_intrinsic_sizing_constraint()) { | 
					
						
							|  |  |  |  |         determine_intrisic_size_of_table_container(available_space); | 
					
						
							|  |  |  |  |         return; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |     // Compute the width of the table.
 | 
					
						
							|  |  |  |  |     float extra_width = 0; | 
					
						
							|  |  |  |  |     compute_table_width(extra_width); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // Distribute the width of the table among columns.
 | 
					
						
							|  |  |  |  |     distribute_width_to_columns(extra_width); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     float left_column_offset = 0; | 
					
						
							|  |  |  |  |     for (auto& column : m_columns) { | 
					
						
							|  |  |  |  |         column.left_offset = left_column_offset; | 
					
						
							|  |  |  |  |         left_column_offset += column.used_width; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     for (auto& cell : m_cells) { | 
					
						
							|  |  |  |  |         auto& cell_state = m_state.get_mutable(cell.box); | 
					
						
							| 
									
										
										
										
											2022-03-21 20:39:19 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-28 14:48:08 +02:00
										 |  |  |  |         float span_width = 0; | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |         for (size_t i = 0; i < cell.column_span; ++i) | 
					
						
							|  |  |  |  |             span_width += m_columns[cell.column_index + i].used_width; | 
					
						
							| 
									
										
										
										
											2022-03-28 14:48:08 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |         auto width_of_containing_block = m_state.get(*cell.box.containing_block()).content_width(); | 
					
						
							|  |  |  |  |         auto width_of_containing_block_as_length = CSS::Length::make_px(width_of_containing_block); | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |         cell_state.padding_top = cell.box.computed_values().padding().top().resolved(cell.box, width_of_containing_block_as_length).to_px(cell.box); | 
					
						
							|  |  |  |  |         cell_state.padding_bottom = cell.box.computed_values().padding().bottom().resolved(cell.box, width_of_containing_block_as_length).to_px(cell.box); | 
					
						
							|  |  |  |  |         cell_state.padding_left = cell.box.computed_values().padding().left().resolved(cell.box, width_of_containing_block_as_length).to_px(cell.box); | 
					
						
							|  |  |  |  |         cell_state.padding_right = cell.box.computed_values().padding().right().resolved(cell.box, width_of_containing_block_as_length).to_px(cell.box); | 
					
						
							| 
									
										
										
										
											2023-01-02 23:06:55 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         auto is_top_most_cell = cell.row_index == 0; | 
					
						
							|  |  |  |  |         auto is_left_most_cell = cell.column_index == 0; | 
					
						
							|  |  |  |  |         auto is_right_most_cell = cell.column_index == m_columns.size() - 1; | 
					
						
							|  |  |  |  |         auto is_bottom_most_cell = cell.row_index == m_rows.size() - 1; | 
					
						
							|  |  |  |  |         auto should_hide_borders = cell.box.computed_values().border_collapse() == CSS::BorderCollapse::Collapse; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         cell_state.border_top = (should_hide_borders && is_top_most_cell) ? 0 : cell.box.computed_values().border_top().width; | 
					
						
							|  |  |  |  |         cell_state.border_bottom = (should_hide_borders && is_bottom_most_cell) ? 0 : cell.box.computed_values().border_bottom().width; | 
					
						
							|  |  |  |  |         cell_state.border_left = (should_hide_borders && is_left_most_cell) ? 0 : cell.box.computed_values().border_left().width; | 
					
						
							|  |  |  |  |         cell_state.border_right = (should_hide_borders && is_right_most_cell) ? 0 : cell.box.computed_values().border_right().width; | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         cell_state.set_content_width(span_width - cell_state.border_box_left() - cell_state.border_box_right()); | 
					
						
							| 
									
										
										
										
											2022-12-04 21:57:21 +03:00
										 |  |  |  |         auto independent_formatting_context = layout_inside(cell.box, LayoutMode::Normal, cell_state.available_inner_space_or_constraints_from(available_space)); | 
					
						
							|  |  |  |  |         VERIFY(independent_formatting_context); | 
					
						
							| 
									
										
										
										
											2022-11-23 17:46:10 +00:00
										 |  |  |  |         cell_state.set_content_height(independent_formatting_context->automatic_content_height().value()); | 
					
						
							| 
									
										
										
										
											2022-12-04 21:57:21 +03:00
										 |  |  |  |         independent_formatting_context->parent_context_did_dimension_child_root_box(); | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 20:02:28 +03:00
										 |  |  |  |         cell.baseline = box_baseline(m_state, cell.box); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         auto& row = m_rows[cell.row_index]; | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |         row.used_width = max(row.used_width, cell_state.border_box_height()); | 
					
						
							| 
									
										
										
										
											2022-12-04 20:02:28 +03:00
										 |  |  |  |         row.baseline = max(row.baseline, cell.baseline); | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-31 14:32:15 +01:00
										 |  |  |  |     float row_top_offset = 0.0f; | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |     for (size_t y = 0; y < m_rows.size(); y++) { | 
					
						
							|  |  |  |  |         auto& row = m_rows[y]; | 
					
						
							|  |  |  |  |         auto& row_state = m_state.get_mutable(row.box); | 
					
						
							|  |  |  |  |         float row_width = 0.0f; | 
					
						
							|  |  |  |  |         for (auto& column : m_columns) { | 
					
						
							|  |  |  |  |             row_width += column.used_width; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         row_state.set_content_height(row.used_width); | 
					
						
							|  |  |  |  |         row_state.set_content_width(row_width); | 
					
						
							| 
									
										
										
										
											2022-12-31 14:32:15 +01:00
										 |  |  |  |         row_state.set_content_y(row_top_offset); | 
					
						
							|  |  |  |  |         row_top_offset += row_state.content_height(); | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     float row_group_top_offset = 0.0f; | 
					
						
							|  |  |  |  |     box.for_each_child_of_type<TableRowGroupBox>([&](auto& row_group_box) { | 
					
						
							|  |  |  |  |         float row_group_height = 0.0f; | 
					
						
							|  |  |  |  |         float row_group_width = 0.0f; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         auto& row_group_box_state = m_state.get_mutable(row_group_box); | 
					
						
							|  |  |  |  |         row_group_box_state.set_content_y(row_group_top_offset); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         float row_top_offset = 0.0f; | 
					
						
							|  |  |  |  |         row_group_box.template for_each_child_of_type<TableRowBox>([&](auto& row) { | 
					
						
							|  |  |  |  |             auto& row_state = m_state.get_mutable(row); | 
					
						
							|  |  |  |  |             row_state.set_content_y(row_top_offset); | 
					
						
							|  |  |  |  |             row_group_height += row_state.border_box_height(); | 
					
						
							|  |  |  |  |             row_group_width = max(row_group_width, row_state.border_box_width()); | 
					
						
							|  |  |  |  |             row_top_offset += row_state.border_box_height(); | 
					
						
							|  |  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |         row_group_top_offset += row_top_offset; | 
					
						
							| 
									
										
										
										
											2022-03-28 14:32:21 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |         row_group_box_state.set_content_height(row_group_height); | 
					
						
							|  |  |  |  |         row_group_box_state.set_content_width(row_group_width); | 
					
						
							| 
									
										
										
										
											2022-03-28 14:32:21 +02:00
										 |  |  |  |     }); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |     for (auto& cell : m_cells) { | 
					
						
							|  |  |  |  |         auto& cell_state = m_state.get_mutable(cell.box); | 
					
						
							|  |  |  |  |         auto& row_state = m_state.get(m_rows[cell.row_index].box); | 
					
						
							| 
									
										
										
										
											2022-12-04 20:02:28 +03:00
										 |  |  |  |         float const cell_border_box_height = cell_state.content_height() + cell_state.border_box_top() + cell_state.border_box_bottom(); | 
					
						
							|  |  |  |  |         float const row_content_height = row_state.content_height(); | 
					
						
							|  |  |  |  |         auto const& vertical_align = cell.box.computed_values().vertical_align(); | 
					
						
							|  |  |  |  |         if (vertical_align.has<CSS::VerticalAlign>()) { | 
					
						
							|  |  |  |  |             switch (vertical_align.get<CSS::VerticalAlign>()) { | 
					
						
							|  |  |  |  |             case CSS::VerticalAlign::Middle: { | 
					
						
							|  |  |  |  |                 cell_state.padding_top += (row_content_height - cell_border_box_height) / 2; | 
					
						
							|  |  |  |  |                 cell_state.padding_bottom += (row_content_height - cell_border_box_height) / 2; | 
					
						
							|  |  |  |  |                 break; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             // FIXME: implement actual 'top' and 'bottom' support instead of fall back to 'baseline'
 | 
					
						
							|  |  |  |  |             case CSS::VerticalAlign::Top: | 
					
						
							|  |  |  |  |             case CSS::VerticalAlign::Bottom: | 
					
						
							|  |  |  |  |             case CSS::VerticalAlign::Baseline: { | 
					
						
							|  |  |  |  |                 cell_state.padding_top += m_rows[cell.row_index].baseline - cell.baseline; | 
					
						
							|  |  |  |  |                 cell_state.padding_bottom += row_content_height - cell_border_box_height; | 
					
						
							|  |  |  |  |                 break; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |             default: | 
					
						
							|  |  |  |  |                 VERIFY_NOT_REACHED(); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  |         cell_state.offset = row_state.offset.translated(cell_state.border_box_left() + m_columns[cell.column_index].left_offset, cell_state.border_box_top()); | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-12-04 22:39:38 +03:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     m_state.get_mutable(context_box()).set_content_height(total_content_height); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // FIXME: This is a total hack, we should respect the 'height' property.
 | 
					
						
							|  |  |  |  |     m_automatic_content_height = total_content_height; | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-23 17:46:10 +00:00
										 |  |  |  | CSSPixels TableFormattingContext::automatic_content_height() const | 
					
						
							| 
									
										
										
										
											2022-09-24 13:39:43 +02:00
										 |  |  |  | { | 
					
						
							|  |  |  |  |     return m_automatic_content_height; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-22 13:38:18 +01:00
										 |  |  |  | } |