/src/serenity/Userland/Libraries/LibWeb/Layout/TableFormattingContext.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #pragma once |
8 | | |
9 | | #include <AK/Forward.h> |
10 | | #include <LibWeb/Layout/FormattingContext.h> |
11 | | #include <LibWeb/Layout/TableGrid.h> |
12 | | #include <LibWeb/Layout/TableWrapper.h> |
13 | | |
14 | | namespace Web::Layout { |
15 | | |
16 | | enum class TableDimension { |
17 | | Row, |
18 | | Column |
19 | | }; |
20 | | |
21 | | class TableFormattingContext final : public FormattingContext { |
22 | | public: |
23 | | explicit TableFormattingContext(LayoutState&, LayoutMode, Box const&, FormattingContext* parent); |
24 | | ~TableFormattingContext(); |
25 | | |
26 | | void run_until_width_calculation(AvailableSpace const& available_space); |
27 | | |
28 | | virtual void run(AvailableSpace const&) override; |
29 | | virtual CSSPixels automatic_content_width() const override; |
30 | | virtual CSSPixels automatic_content_height() const override; |
31 | | |
32 | 0 | Box const& table_box() const { return context_box(); } |
33 | | TableWrapper const& table_wrapper() const |
34 | 0 | { |
35 | 0 | return verify_cast<TableWrapper>(*table_box().containing_block()); |
36 | 0 | } |
37 | | |
38 | | static bool border_is_less_specific(const CSS::BorderData& a, const CSS::BorderData& b); |
39 | | |
40 | | private: |
41 | | CSSPixels run_caption_layout(CSS::CaptionSide); |
42 | | CSSPixels compute_capmin(); |
43 | | void compute_constrainedness(); |
44 | | void compute_cell_measures(); |
45 | | void compute_outer_content_sizes(); |
46 | | template<class RowOrColumn> |
47 | | void initialize_table_measures(); |
48 | | template<class RowOrColumn> |
49 | | void compute_table_measures(); |
50 | | template<class RowOrColumn> |
51 | | void compute_intrinsic_percentage(size_t max_cell_span); |
52 | | void compute_table_width(); |
53 | | void distribute_width_to_columns(); |
54 | | void distribute_excess_width_to_columns(CSSPixels available_width); |
55 | | void distribute_excess_width_to_columns_fixed_mode(CSSPixels excess_width); |
56 | | void compute_table_height(); |
57 | | void distribute_height_to_rows(); |
58 | | void position_row_boxes(); |
59 | | void position_cell_boxes(); |
60 | | void border_conflict_resolution(); |
61 | | CSSPixels border_spacing_horizontal() const; |
62 | | CSSPixels border_spacing_vertical() const; |
63 | | void finish_grid_initialization(TableGrid const&); |
64 | | |
65 | | CSSPixels compute_columns_total_used_width() const; |
66 | | void commit_candidate_column_widths(Vector<CSSPixels> const& candidate_widths); |
67 | | void assign_columns_width_linear_combination(Vector<CSSPixels> const& candidate_widths, CSSPixels available_width); |
68 | | |
69 | | template<class ColumnFilter, class BaseWidthGetter> |
70 | | bool distribute_excess_width_proportionally_to_base_width(CSSPixels excess_width, ColumnFilter column_filter, BaseWidthGetter base_width_getter); |
71 | | template<class ColumnFilter> |
72 | | bool distribute_excess_width_equally(CSSPixels excess_width, ColumnFilter column_filter); |
73 | | template<class ColumnFilter> |
74 | | bool distribute_excess_width_by_intrinsic_percentage(CSSPixels excess_width, ColumnFilter column_filter); |
75 | | |
76 | | bool use_fixed_mode_layout() const; |
77 | | |
78 | | CSSPixels m_table_height { 0 }; |
79 | | CSSPixels m_automatic_content_height { 0 }; |
80 | | |
81 | | Optional<AvailableSpace> m_available_space; |
82 | | |
83 | | struct Column { |
84 | | CSSPixels left_offset { 0 }; |
85 | | CSSPixels min_size { 0 }; |
86 | | CSSPixels max_size { 0 }; |
87 | | CSSPixels used_width { 0 }; |
88 | | bool has_intrinsic_percentage { false }; |
89 | | double intrinsic_percentage { 0 }; |
90 | | // Store whether the column is constrained: https://www.w3.org/TR/css-tables-3/#constrainedness |
91 | | bool is_constrained { false }; |
92 | | // Store whether the column has originating cells, defined in https://www.w3.org/TR/css-tables-3/#terminology. |
93 | | bool has_originating_cells { false }; |
94 | | }; |
95 | | |
96 | | using Cell = TableGrid::Cell; |
97 | | using Row = TableGrid::Row; |
98 | | |
99 | | // Accessors to enable direction-agnostic table measurement. |
100 | | |
101 | | template<class RowOrColumn> |
102 | | static size_t cell_span(Cell const& cell); |
103 | | |
104 | | template<class RowOrColumn> |
105 | | static size_t cell_index(Cell const& cell); |
106 | | |
107 | | template<class RowOrColumn> |
108 | | static CSSPixels cell_min_size(Cell const& cell); |
109 | | |
110 | | template<class RowOrColumn> |
111 | | static CSSPixels cell_max_size(Cell const& cell); |
112 | | |
113 | | template<class RowOrColumn> |
114 | | static double cell_percentage_contribution(Cell const& cell); |
115 | | |
116 | | template<class RowOrColumn> |
117 | | static bool cell_has_intrinsic_percentage(Cell const& cell); |
118 | | |
119 | | template<class RowOrColumn> |
120 | | void initialize_intrinsic_percentages_from_rows_or_columns(); |
121 | | |
122 | | template<class RowOrColumn> |
123 | | void initialize_intrinsic_percentages_from_cells(); |
124 | | |
125 | | template<class RowOrColumn> |
126 | | CSSPixels border_spacing(); |
127 | | |
128 | | template<class RowOrColumn> |
129 | | Vector<RowOrColumn>& table_rows_or_columns(); |
130 | | |
131 | | CSSPixels compute_row_content_height(Cell const& cell) const; |
132 | | |
133 | | enum class ConflictingSide { |
134 | | Top, |
135 | | Bottom, |
136 | | Left, |
137 | | Right, |
138 | | }; |
139 | | |
140 | | struct ConflictingEdge { |
141 | | JS::GCPtr<Node const> element; |
142 | | Painting::PaintableBox::ConflictingElementKind element_kind; |
143 | | ConflictingSide side; |
144 | | Optional<size_t> row; |
145 | | Optional<size_t> column; |
146 | | }; |
147 | | |
148 | | static TableFormattingContext::ConflictingEdge const& winning_conflicting_edge(TableFormattingContext::ConflictingEdge const& a, TableFormattingContext::ConflictingEdge const& b); |
149 | | |
150 | | static const CSS::BorderData& border_data_conflicting_edge(ConflictingEdge const& conflicting_edge); |
151 | | static Painting::PaintableBox::BorderDataWithElementKind const border_data_with_element_kind_from_conflicting_edge(ConflictingEdge const& conflicting_edge); |
152 | | |
153 | | class BorderConflictFinder { |
154 | | public: |
155 | | BorderConflictFinder(TableFormattingContext const* context); |
156 | | Vector<ConflictingEdge> conflicting_edges(Cell const&, ConflictingSide) const; |
157 | | |
158 | | private: |
159 | | void collect_conflicting_col_elements(); |
160 | | void collect_conflicting_row_group_elements(); |
161 | | |
162 | | void collect_cell_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const; |
163 | | void collect_row_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const; |
164 | | void collect_row_group_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const; |
165 | | void collect_column_group_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const; |
166 | | void collect_table_box_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const; |
167 | | |
168 | | struct RowGroupInfo { |
169 | | JS::GCPtr<Node const> row_group; |
170 | | size_t start_index; |
171 | | size_t row_count; |
172 | | }; |
173 | | |
174 | | Vector<JS::GCPtr<Node const>> m_col_elements_by_index; |
175 | | Vector<Optional<RowGroupInfo>> m_row_group_elements_by_index; |
176 | | TableFormattingContext const* m_context; |
177 | | }; |
178 | | |
179 | | Vector<Cell> m_cells; |
180 | | Vector<Vector<Optional<Cell const&>>> m_cells_by_coordinate; |
181 | | Vector<Column> m_columns; |
182 | | Vector<Row> m_rows; |
183 | | }; |
184 | | |
185 | | } |