LibWeb: Consider percent and fixed widths in table column distribution

Change column distribution to take in account is_length() and
is_percentage() width values instead of treating all cells like
they have auto width by implementing it in the way described
in CSS Tables 3 spec:
https://www.w3.org/TR/css-tables-3/#width-distribution-algorithm

distribute_width_to_column() is structured to follow schema:
w3.org/TR/css-tables-3/images/CSS-Tables-Column-Width-Assignment.svg
This commit is contained in:
Aliaksandr Kalenik 2023-01-05 18:56:34 +03:00 committed by Andreas Kling
parent 21d89a2153
commit b2a04ff48a
Notes: sideshowbarker 2024-07-17 07:31:31 +09:00
2 changed files with 110 additions and 21 deletions

View File

@ -129,18 +129,22 @@ void TableFormattingContext::compute_table_measures()
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 computed_width = computed_values.width();
if (computed_width.is_percentage()) {
m_columns[cell.column_index].type = ColumnType::Percent;
m_columns[cell.column_index].percentage_width = max(m_columns[cell.column_index].percentage_width, computed_width.percentage().value());
} else if (computed_width.is_length()) {
m_columns[cell.column_index].type = ColumnType::Pixel;
}
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);
}
for (auto& column : m_columns) {
column.used_width = column.min_width;
}
}
void TableFormattingContext::compute_table_width(CSSPixels& extra_width)
void TableFormattingContext::compute_table_width()
{
auto const& table_box = context_box();
auto& table_box_state = m_state.get_mutable(table_box);
@ -183,23 +187,101 @@ void TableFormattingContext::compute_table_width(CSSPixels& extra_width)
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;
}
}
void TableFormattingContext::distribute_width_to_columns(CSSPixels extra_width)
void TableFormattingContext::distribute_width_to_columns()
{
CSSPixels grid_max = 0.0f;
for (auto& column : m_columns)
grid_max += column.max_width - column.min_width;
// Implements https://www.w3.org/TR/css-tables-3/#width-distribution-algorithm
if (grid_max == 0)
CSSPixels available_width = m_state.get(context_box()).content_width();
auto columns_total_used_width = [&]() {
CSSPixels total_used_width = 0;
for (auto& column : m_columns) {
total_used_width += column.used_width;
}
return total_used_width;
};
auto column_preferred_width = [&](Column& column) {
switch (column.type) {
case ColumnType::Percent: {
return max(column.min_width, column.percentage_width / 100 * available_width);
}
case ColumnType::Pixel:
case ColumnType::Auto: {
return column.max_width;
}
default: {
VERIFY_NOT_REACHED();
}
}
};
auto expand_columns_to_fill_available_width = [&](ColumnType column_type) {
CSSPixels remaining_available_width = available_width;
CSSPixels total_preferred_width_increment = 0;
for (auto& column : m_columns) {
remaining_available_width -= column.used_width;
if (column.type == column_type) {
total_preferred_width_increment += column_preferred_width(column) - column.min_width;
}
}
for (auto& column : m_columns) {
if (column.type == column_type) {
CSSPixels preferred_width_increment = column_preferred_width(column) - column.min_width;
column.used_width += preferred_width_increment * remaining_available_width / total_preferred_width_increment;
}
}
};
auto shrink_columns_to_fit_available_width = [&](ColumnType column_type) {
for (auto& column : m_columns) {
if (column.type == column_type)
column.used_width = column.min_width;
}
expand_columns_to_fill_available_width(column_type);
};
for (auto& column : m_columns) {
column.used_width = column.min_width;
}
for (auto& column : m_columns) {
if (column.type == ColumnType::Percent) {
column.used_width = max(column.min_width, column.percentage_width / 100 * available_width);
}
}
if (columns_total_used_width() > available_width) {
shrink_columns_to_fit_available_width(ColumnType::Percent);
return;
}
for (auto& column : m_columns)
column.used_width += ((column.max_width - column.min_width) / grid_max) * extra_width;
for (auto& column : m_columns) {
if (column.type == ColumnType::Pixel) {
column.used_width = column.max_width;
}
}
if (columns_total_used_width() > available_width) {
shrink_columns_to_fit_available_width(ColumnType::Pixel);
return;
}
if (columns_total_used_width() < available_width) {
expand_columns_to_fill_available_width(ColumnType::Auto);
}
if (columns_total_used_width() < available_width) {
expand_columns_to_fill_available_width(ColumnType::Pixel);
}
if (columns_total_used_width() < available_width) {
expand_columns_to_fill_available_width(ColumnType::Percent);
}
}
void TableFormattingContext::determine_intrisic_size_of_table_container(AvailableSpace const& available_space)
@ -242,11 +324,10 @@ void TableFormattingContext::run(Box const& box, LayoutMode, AvailableSpace cons
}
// Compute the width of the table.
CSSPixels extra_width = 0;
compute_table_width(extra_width);
compute_table_width();
// Distribute the width of the table among columns.
distribute_width_to_columns(extra_width);
distribute_width_to_columns();
CSSPixels left_column_offset = 0;
for (auto& column : m_columns) {

View File

@ -22,19 +22,27 @@ public:
private:
void calculate_row_column_grid(Box const&);
void compute_table_measures();
void compute_table_width(CSSPixels&);
void distribute_width_to_columns(CSSPixels extra_width);
void compute_table_width();
void distribute_width_to_columns();
void determine_intrisic_size_of_table_container(AvailableSpace const& available_space);
CSSPixels m_automatic_content_height { 0 };
Optional<AvailableSpace> m_available_space;
enum class ColumnType {
Percent,
Pixel,
Auto
};
struct Column {
ColumnType type { ColumnType::Auto };
CSSPixels left_offset { 0 };
CSSPixels min_width { 0 };
CSSPixels max_width { 0 };
CSSPixels used_width { 0 };
float percentage_width { 0 };
};
struct Row {