183 lines
6.6 KiB
C++
183 lines
6.6 KiB
C++
/*
|
|
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/Forward.h>
|
|
#include <LibWeb/Layout/FormattingContext.h>
|
|
#include <LibWeb/Layout/TableGrid.h>
|
|
#include <LibWeb/Layout/TableWrapper.h>
|
|
|
|
namespace Web::Layout {
|
|
|
|
enum class TableDimension {
|
|
Row,
|
|
Column
|
|
};
|
|
|
|
class TableFormattingContext final : public FormattingContext {
|
|
public:
|
|
explicit TableFormattingContext(LayoutState&, Box const&, FormattingContext* parent);
|
|
~TableFormattingContext();
|
|
|
|
virtual void run(Box const&, LayoutMode, AvailableSpace const&) override;
|
|
virtual CSSPixels automatic_content_width() const override;
|
|
virtual CSSPixels automatic_content_height() const override;
|
|
|
|
Box const& table_box() const { return context_box(); }
|
|
TableWrapper const& table_wrapper() const
|
|
{
|
|
return verify_cast<TableWrapper>(*table_box().containing_block());
|
|
}
|
|
|
|
static bool border_is_less_specific(const CSS::BorderData& a, const CSS::BorderData& b);
|
|
|
|
private:
|
|
CSSPixels run_caption_layout(LayoutMode, CSS::CaptionSide);
|
|
CSSPixels compute_capmin();
|
|
void compute_constrainedness();
|
|
void compute_cell_measures();
|
|
void compute_outer_content_sizes();
|
|
template<class RowOrColumn>
|
|
void initialize_table_measures();
|
|
template<class RowOrColumn>
|
|
void compute_table_measures();
|
|
template<class RowOrColumn>
|
|
void compute_intrinsic_percentage(size_t max_cell_span);
|
|
void compute_table_width();
|
|
void distribute_width_to_columns();
|
|
void distribute_excess_width_to_columns(CSSPixels available_width);
|
|
void distribute_excess_width_to_columns_fixed_mode(CSSPixels excess_width);
|
|
void compute_table_height(LayoutMode layout_mode);
|
|
void distribute_height_to_rows();
|
|
void position_row_boxes();
|
|
void position_cell_boxes();
|
|
void border_conflict_resolution();
|
|
CSSPixels border_spacing_horizontal() const;
|
|
CSSPixels border_spacing_vertical() const;
|
|
void finish_grid_initialization(TableGrid const&);
|
|
|
|
CSSPixels compute_columns_total_used_width() const;
|
|
void commit_candidate_column_widths(Vector<CSSPixels> const& candidate_widths);
|
|
void assign_columns_width_linear_combination(Vector<CSSPixels> const& candidate_widths, CSSPixels available_width);
|
|
|
|
template<class ColumnFilter, class BaseWidthGetter>
|
|
bool distribute_excess_width_proportionally_to_base_width(CSSPixels excess_width, ColumnFilter column_filter, BaseWidthGetter base_width_getter);
|
|
template<class ColumnFilter>
|
|
bool distribute_excess_width_equally(CSSPixels excess_width, ColumnFilter column_filter);
|
|
template<class ColumnFilter>
|
|
bool distribute_excess_width_by_intrinsic_percentage(CSSPixels excess_width, ColumnFilter column_filter);
|
|
|
|
bool use_fixed_mode_layout() const;
|
|
|
|
CSSPixels m_table_height { 0 };
|
|
CSSPixels m_automatic_content_height { 0 };
|
|
|
|
Optional<AvailableSpace> m_available_space;
|
|
|
|
struct Column {
|
|
CSSPixels left_offset { 0 };
|
|
CSSPixels min_size { 0 };
|
|
CSSPixels max_size { 0 };
|
|
CSSPixels used_width { 0 };
|
|
bool has_intrinsic_percentage { false };
|
|
double intrinsic_percentage { 0 };
|
|
// Store whether the column is constrained: https://www.w3.org/TR/css-tables-3/#constrainedness
|
|
bool is_constrained { false };
|
|
// Store whether the column has originating cells, defined in https://www.w3.org/TR/css-tables-3/#terminology.
|
|
bool has_originating_cells { false };
|
|
};
|
|
|
|
using Cell = TableGrid::Cell;
|
|
using Row = TableGrid::Row;
|
|
|
|
// Accessors to enable direction-agnostic table measurement.
|
|
|
|
template<class RowOrColumn>
|
|
static size_t cell_span(Cell const& cell);
|
|
|
|
template<class RowOrColumn>
|
|
static size_t cell_index(Cell const& cell);
|
|
|
|
template<class RowOrColumn>
|
|
static CSSPixels cell_min_size(Cell const& cell);
|
|
|
|
template<class RowOrColumn>
|
|
static CSSPixels cell_max_size(Cell const& cell);
|
|
|
|
template<class RowOrColumn>
|
|
static double cell_percentage_contribution(Cell const& cell);
|
|
|
|
template<class RowOrColumn>
|
|
static bool cell_has_intrinsic_percentage(Cell const& cell);
|
|
|
|
template<class RowOrColumn>
|
|
void initialize_intrinsic_percentages_from_rows_or_columns();
|
|
|
|
template<class RowOrColumn>
|
|
void initialize_intrinsic_percentages_from_cells();
|
|
|
|
template<class RowOrColumn>
|
|
CSSPixels border_spacing();
|
|
|
|
template<class RowOrColumn>
|
|
Vector<RowOrColumn>& table_rows_or_columns();
|
|
|
|
CSSPixels compute_row_content_height(Cell const& cell) const;
|
|
|
|
enum class ConflictingSide {
|
|
Top,
|
|
Bottom,
|
|
Left,
|
|
Right,
|
|
};
|
|
|
|
struct ConflictingEdge {
|
|
Node const* element;
|
|
Painting::PaintableBox::ConflictingElementKind element_kind;
|
|
ConflictingSide side;
|
|
Optional<size_t> row;
|
|
Optional<size_t> column;
|
|
};
|
|
|
|
static TableFormattingContext::ConflictingEdge const& winning_conflicting_edge(TableFormattingContext::ConflictingEdge const& a, TableFormattingContext::ConflictingEdge const& b);
|
|
|
|
static const CSS::BorderData& border_data_conflicting_edge(ConflictingEdge const& conflicting_edge);
|
|
static const Painting::PaintableBox::BorderDataWithElementKind border_data_with_element_kind_from_conflicting_edge(ConflictingEdge const& conflicting_edge);
|
|
|
|
class BorderConflictFinder {
|
|
public:
|
|
BorderConflictFinder(TableFormattingContext const* context);
|
|
Vector<ConflictingEdge> conflicting_edges(Cell const&, ConflictingSide) const;
|
|
|
|
private:
|
|
void collect_conflicting_col_elements();
|
|
void collect_conflicting_row_group_elements();
|
|
|
|
void collect_cell_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const;
|
|
void collect_row_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const;
|
|
void collect_row_group_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const;
|
|
void collect_column_group_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const;
|
|
void collect_table_box_conflicting_edges(Vector<ConflictingEdge>&, Cell const&, ConflictingSide) const;
|
|
|
|
struct RowGroupInfo {
|
|
Node const* row_group;
|
|
size_t start_index;
|
|
size_t row_count;
|
|
};
|
|
|
|
Vector<Node const*> m_col_elements_by_index;
|
|
Vector<Optional<RowGroupInfo>> m_row_group_elements_by_index;
|
|
TableFormattingContext const* m_context;
|
|
};
|
|
|
|
Vector<Cell> m_cells;
|
|
Vector<Vector<Optional<Cell const&>>> m_cells_by_coordinate;
|
|
Vector<Column> m_columns;
|
|
Vector<Row> m_rows;
|
|
};
|
|
|
|
}
|