mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 12:57:35 +00:00
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:
parent
21d89a2153
commit
b2a04ff48a
2 changed files with 110 additions and 21 deletions
|
@ -129,18 +129,22 @@ void TableFormattingContext::compute_table_measures()
|
||||||
if (!computed_values.max_width().is_none())
|
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));
|
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_min_content_width = min_width + cell_intrinsic_offsets;
|
||||||
auto cell_outer_max_content_width = max(max(width, min_width), max_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].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);
|
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 const& table_box = context_box();
|
||||||
auto& table_box_state = m_state.get_mutable(table_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);
|
used_width = max(resolved_table_width, used_min_width);
|
||||||
table_box_state.set_content_width(used_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;
|
// Implements https://www.w3.org/TR/css-tables-3/#width-distribution-algorithm
|
||||||
for (auto& column : m_columns)
|
|
||||||
grid_max += column.max_width - column.min_width;
|
|
||||||
|
|
||||||
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;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& column : m_columns)
|
for (auto& column : m_columns) {
|
||||||
column.used_width += ((column.max_width - column.min_width) / grid_max) * extra_width;
|
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)
|
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.
|
// Compute the width of the table.
|
||||||
CSSPixels extra_width = 0;
|
compute_table_width();
|
||||||
compute_table_width(extra_width);
|
|
||||||
|
|
||||||
// Distribute the width of the table among columns.
|
// Distribute the width of the table among columns.
|
||||||
distribute_width_to_columns(extra_width);
|
distribute_width_to_columns();
|
||||||
|
|
||||||
CSSPixels left_column_offset = 0;
|
CSSPixels left_column_offset = 0;
|
||||||
for (auto& column : m_columns) {
|
for (auto& column : m_columns) {
|
||||||
|
|
|
@ -22,19 +22,27 @@ public:
|
||||||
private:
|
private:
|
||||||
void calculate_row_column_grid(Box const&);
|
void calculate_row_column_grid(Box const&);
|
||||||
void compute_table_measures();
|
void compute_table_measures();
|
||||||
void compute_table_width(CSSPixels&);
|
void compute_table_width();
|
||||||
void distribute_width_to_columns(CSSPixels extra_width);
|
void distribute_width_to_columns();
|
||||||
void determine_intrisic_size_of_table_container(AvailableSpace const& available_space);
|
void determine_intrisic_size_of_table_container(AvailableSpace const& available_space);
|
||||||
|
|
||||||
CSSPixels m_automatic_content_height { 0 };
|
CSSPixels m_automatic_content_height { 0 };
|
||||||
|
|
||||||
Optional<AvailableSpace> m_available_space;
|
Optional<AvailableSpace> m_available_space;
|
||||||
|
|
||||||
|
enum class ColumnType {
|
||||||
|
Percent,
|
||||||
|
Pixel,
|
||||||
|
Auto
|
||||||
|
};
|
||||||
|
|
||||||
struct Column {
|
struct Column {
|
||||||
|
ColumnType type { ColumnType::Auto };
|
||||||
CSSPixels left_offset { 0 };
|
CSSPixels left_offset { 0 };
|
||||||
CSSPixels min_width { 0 };
|
CSSPixels min_width { 0 };
|
||||||
CSSPixels max_width { 0 };
|
CSSPixels max_width { 0 };
|
||||||
CSSPixels used_width { 0 };
|
CSSPixels used_width { 0 };
|
||||||
|
float percentage_width { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Row {
|
struct Row {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue