1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 07:37:44 +00:00

LibWeb: Extract common path in definite row/column placement in GFC

Moves the code that identifies (start, end, span) for a grid item into
a separate function. By doing so, we can eliminate the duplicated code
between the placement of grid items with definite columns and those
with definite rows.

This change omits some of the comments that reference the spec, as they
were largely irrelevant and unhelpful for making changes or diagnosing
issues.
This commit is contained in:
Aliaksandr Kalenik 2024-03-06 15:49:04 +01:00 committed by Andreas Kling
parent 0243278587
commit 8695a82c56
2 changed files with 90 additions and 211 deletions

View file

@ -139,6 +139,80 @@ int GridFormattingContext::count_of_repeated_auto_fill_or_fit_tracks(GridDimensi
// floor be 1px.
}
GridFormattingContext::PlacementPosition GridFormattingContext::resolve_grid_position(Box const& child_box, GridDimension const dimension)
{
auto const& computed_values = child_box.computed_values();
auto const& placement_start = dimension == GridDimension::Row ? computed_values.grid_row_start() : computed_values.grid_column_start();
auto const& placement_end = dimension == GridDimension::Row ? computed_values.grid_row_end() : computed_values.grid_column_end();
PlacementPosition result;
if (placement_start.has_line_number() && placement_start.line_number() > 0)
result.start = placement_start.line_number() - 1;
else if (placement_start.has_line_number()) {
auto explicit_line_count = dimension == GridDimension::Row ? m_explicit_rows_line_count : m_explicit_columns_line_count;
result.start = explicit_line_count + placement_start.line_number();
}
if (placement_end.has_line_number())
result.end = placement_end.line_number() - 1;
if (result.end < 0) {
if (dimension == GridDimension::Row)
result.end = m_occupation_grid.row_count() + result.end + 2;
else
result.end = m_occupation_grid.column_count() + result.end + 2;
}
if (placement_start.has_line_number() && placement_end.is_span())
result.span = placement_end.span();
if (placement_end.has_line_number() && placement_start.is_span()) {
result.span = placement_start.span();
result.start = result.end - result.span;
// FIXME: Remove me once have implemented spans overflowing into negative indexes, e.g., grid-row: span 2 / 1
if (result.start < 0)
result.start = 0;
}
if (placement_end.has_identifier()) {
if (auto maybe_grid_area = m_grid_areas.get(placement_end.identifier()); maybe_grid_area.has_value()) {
result.end = dimension == GridDimension::Row ? maybe_grid_area->row_end : maybe_grid_area->column_end;
} else if (auto line_name_index = get_line_index_by_line_name(dimension, placement_end.identifier()); line_name_index.has_value()) {
result.end = line_name_index.value();
} else {
result.end = 1;
}
result.start = result.end - 1;
}
if (placement_start.has_identifier()) {
if (auto maybe_grid_area = m_grid_areas.get(placement_start.identifier()); maybe_grid_area.has_value()) {
result.start = dimension == GridDimension::Row ? maybe_grid_area->row_start : maybe_grid_area->column_start;
} else if (auto line_name_index = get_line_index_by_line_name(dimension, placement_start.identifier()); line_name_index.has_value()) {
result.start = line_name_index.value();
} else {
result.start = 0;
}
}
if (placement_start.is_positioned() && placement_end.is_positioned()) {
if (result.start > result.end)
swap(result.start, result.end);
if (result.start != result.end)
result.span = result.end - result.start;
}
// FIXME: Have yet to find the spec for this.
if (!placement_start.is_positioned() && placement_end.is_positioned() && result.end == 0)
result.start = 0;
// If the placement contains two spans, remove the one contributed by the end grid-placement
// property.
if (placement_start.is_span() && placement_end.is_span())
result.span = placement_start.span();
return result;
}
void GridFormattingContext::place_item_with_row_and_column_position(Box const& child_box)
{
auto const& grid_row_start = child_box.computed_values().grid_row_start();
@ -292,112 +366,14 @@ void GridFormattingContext::place_item_with_row_and_column_position(Box const& c
void GridFormattingContext::place_item_with_row_position(Box const& child_box)
{
auto const& grid_row_start = child_box.computed_values().grid_row_start();
auto const& grid_row_end = child_box.computed_values().grid_row_end();
auto placement_position = resolve_grid_position(child_box, GridDimension::Row);
auto row_start = placement_position.start;
size_t row_span = placement_position.span;
auto const& grid_column_start = child_box.computed_values().grid_column_start();
int row_start = 0, row_end = 0;
if (grid_row_start.has_line_number())
row_start = grid_row_start.line_number() - 1;
if (grid_row_end.has_line_number())
row_end = grid_row_end.line_number() - 1;
// https://www.w3.org/TR/css-grid-2/#line-placement
// 8.3. Line-based Placement: the grid-row-start, grid-column-start, grid-row-end, and grid-column-end properties
// https://www.w3.org/TR/css-grid-2/#grid-placement-slot
// First attempt to match the grid areas edge to a named grid area: if there is a grid line whose
// line name is <custom-ident>-start (for grid-*-start) / <custom-ident>-end (for grid-*-end),
// contributes the first such line to the grid items placement.
// Otherwise, treat this as if the integer 1 had been specified along with the <custom-ident>.
// https://www.w3.org/TR/css-grid-2/#grid-placement-int
// Contributes the Nth grid line to the grid items placement. If a negative integer is given, it
// instead counts in reverse, starting from the end edge of the explicit grid.
if (row_end < 0)
row_end = m_occupation_grid.row_count() + row_end + 2;
// If a name is given as a <custom-ident>, only lines with that name are counted. If not enough
// lines with that name exist, all implicit grid lines are assumed to have that name for the purpose
// of finding this position.
// https://www.w3.org/TR/css-grid-2/#grid-placement-span-int
// Contributes a grid span to the grid items placement such that the corresponding edge of the grid
// items grid area is N lines from its opposite edge in the corresponding direction. For example,
// grid-column-end: span 2 indicates the second grid line in the endward direction from the
// grid-column-start line.
size_t row_span = 1;
if (grid_row_start.has_line_number() && grid_row_end.is_span())
row_span = grid_row_end.span();
if (grid_row_end.has_line_number() && grid_row_start.is_span()) {
row_span = grid_row_start.span();
row_start = row_end - row_span;
// FIXME: Remove me once have implemented spans overflowing into negative indexes, e.g., grid-row: span 2 / 1
if (row_start < 0)
row_start = 0;
}
// If a name is given as a <custom-ident>, only lines with that name are counted. If not enough
// lines with that name exist, all implicit grid lines on the side of the explicit grid
// corresponding to the search direction are assumed to have that name for the purpose of counting
// this span.
// https://drafts.csswg.org/css-grid/#grid-placement-auto
// auto
// The property contributes nothing to the grid items placement, indicating auto-placement or a
// default span of one. (See §8 Placing Grid Items, above.)
// https://www.w3.org/TR/css-grid-2/#common-uses-named-lines
// 8.1.3. Named Lines and Spans
// Instead of counting lines by number, lines can be referenced by their line name:
if (grid_row_end.has_identifier()) {
if (auto maybe_grid_area = m_grid_areas.get(grid_row_end.identifier()); maybe_grid_area.has_value())
row_end = maybe_grid_area->row_end;
else if (auto line_name_index = get_line_index_by_line_name(GridDimension::Row, grid_row_end.identifier()); line_name_index.has_value())
row_end = line_name_index.value() - 1;
else
row_end = 1;
row_start = row_end - 1;
}
if (grid_row_start.has_identifier()) {
if (auto maybe_grid_area = m_grid_areas.get(grid_row_start.identifier()); maybe_grid_area.has_value())
row_start = maybe_grid_area->row_start;
else if (auto line_name_index = get_line_index_by_line_name(GridDimension::Row, grid_row_start.identifier()); line_name_index.has_value())
row_start = line_name_index.value();
else
row_start = 0;
}
// If there are multiple lines of the same name, they effectively establish a named set of grid
// lines, which can be exclusively indexed by filtering the placement by name:
// https://drafts.csswg.org/css-grid/#grid-placement-errors
// 8.3.1. Grid Placement Conflict Handling
// If the placement for a grid item contains two lines, and the start line is further end-ward than
// the end line, swap the two lines. If the start line is equal to the end line, remove the end
// line.
if (grid_row_start.is_positioned() && grid_row_end.is_positioned()) {
if (row_start > row_end)
swap(row_start, row_end);
if (row_start != row_end)
row_span = row_end - row_start;
}
// FIXME: Have yet to find the spec for this.
if (!grid_row_start.is_positioned() && grid_row_end.is_positioned() && row_end == 0)
row_start = 0;
// If the placement contains two spans, remove the one contributed by the end grid-placement
// property.
if (grid_row_start.is_span() && grid_row_end.is_span())
row_span = grid_row_start.span();
// FIXME: If the placement contains only a span for a named line, replace it with a span of 1.
int column_start = 0;
size_t column_span = grid_column_start.is_span() ? grid_column_start.span() : 1;
bool found_available_column = false;
for (size_t column_index = column_start; column_index < m_occupation_grid.column_count(); column_index++) {
if (!m_occupation_grid.is_occupied(column_index, row_start)) {
@ -421,116 +397,12 @@ void GridFormattingContext::place_item_with_row_position(Box const& child_box)
void GridFormattingContext::place_item_with_column_position(Box const& child_box, int& auto_placement_cursor_x, int& auto_placement_cursor_y)
{
auto placement_position = resolve_grid_position(child_box, GridDimension::Column);
auto column_start = placement_position.start;
size_t column_span = placement_position.span;
auto const& grid_row_start = child_box.computed_values().grid_row_start();
auto const& grid_column_start = child_box.computed_values().grid_column_start();
auto const& grid_column_end = child_box.computed_values().grid_column_end();
int column_start = 0;
if (grid_column_start.has_line_number() && grid_column_start.line_number() > 0) {
column_start = grid_column_start.line_number() - 1;
} else if (grid_column_start.has_line_number()) {
// NOTE: Negative indexes count from the end side of the explicit grid
column_start = m_explicit_columns_line_count + grid_column_start.line_number();
}
int column_end = 0;
if (grid_column_end.has_line_number())
column_end = grid_column_end.line_number() - 1;
// https://www.w3.org/TR/css-grid-2/#line-placement
// 8.3. Line-based Placement: the grid-row-start, grid-column-start, grid-row-end, and grid-column-end properties
// https://www.w3.org/TR/css-grid-2/#grid-placement-slot
// First attempt to match the grid areas edge to a named grid area: if there is a grid line whose
// line name is <custom-ident>-start (for grid-*-start) / <custom-ident>-end (for grid-*-end),
// contributes the first such line to the grid items placement.
// Otherwise, treat this as if the integer 1 had been specified along with the <custom-ident>.
// https://www.w3.org/TR/css-grid-2/#grid-placement-int
// Contributes the Nth grid line to the grid items placement. If a negative integer is given, it
// instead counts in reverse, starting from the end edge of the explicit grid.
if (column_end < 0)
column_end = m_occupation_grid.column_count() + column_end + 2;
// If a name is given as a <custom-ident>, only lines with that name are counted. If not enough
// lines with that name exist, all implicit grid lines are assumed to have that name for the purpose
// of finding this position.
// https://www.w3.org/TR/css-grid-2/#grid-placement-span-int
// Contributes a grid span to the grid items placement such that the corresponding edge of the grid
// items grid area is N lines from its opposite edge in the corresponding direction. For example,
// grid-column-end: span 2 indicates the second grid line in the endward direction from the
// grid-column-start line.
size_t column_span = 1;
size_t row_span = grid_row_start.is_span() ? grid_row_start.span() : 1;
if (grid_column_start.has_line_number() && grid_column_end.is_span())
column_span = grid_column_end.span();
if (grid_column_end.has_line_number() && grid_column_start.is_span()) {
column_span = grid_column_start.span();
column_start = column_end - column_span;
// FIXME: Remove me once have implemented spans overflowing into negative indexes, e.g., grid-column: span 2 / 1
if (column_start < 0)
column_start = 0;
}
// FIXME: Have yet to find the spec for this.
if (!grid_column_start.is_positioned() && grid_column_end.is_positioned() && column_end == 0)
column_start = 0;
// If a name is given as a <custom-ident>, only lines with that name are counted. If not enough
// lines with that name exist, all implicit grid lines on the side of the explicit grid
// corresponding to the search direction are assumed to have that name for the purpose of counting
// this span.
// https://drafts.csswg.org/css-grid/#grid-placement-auto
// auto
// The property contributes nothing to the grid items placement, indicating auto-placement or a
// default span of one. (See §8 Placing Grid Items, above.)
// https://www.w3.org/TR/css-grid-2/#common-uses-named-lines
// 8.1.3. Named Lines and Spans
// Instead of counting lines by number, lines can be referenced by their line name:
if (grid_column_end.has_identifier()) {
if (auto maybe_grid_area = m_grid_areas.get(grid_column_end.identifier()); maybe_grid_area.has_value())
column_end = maybe_grid_area->column_end;
else if (auto line_name_index = get_line_index_by_line_name(GridDimension::Column, grid_column_end.identifier()); line_name_index.has_value()) {
column_end = line_name_index.value();
} else
column_end = 1;
column_start = column_end - 1;
}
if (grid_column_start.has_identifier()) {
if (auto maybe_grid_area = m_grid_areas.get(grid_column_start.identifier()); maybe_grid_area.has_value())
column_start = maybe_grid_area->column_start;
else if (auto line_name_index = get_line_index_by_line_name(GridDimension::Column, grid_column_start.identifier()); line_name_index.has_value()) {
column_start = line_name_index.value();
} else {
column_start = 0;
}
}
// If there are multiple lines of the same name, they effectively establish a named set of grid
// lines, which can be exclusively indexed by filtering the placement by name:
// https://drafts.csswg.org/css-grid/#grid-placement-errors
// 8.3.1. Grid Placement Conflict Handling
// If the placement for a grid item contains two lines, and the start line is further end-ward than
// the end line, swap the two lines. If the start line is equal to the end line, remove the end
// line.
if (grid_column_start.is_positioned() && grid_column_end.is_positioned()) {
if (column_start > column_end)
swap(column_start, column_end);
if (column_start != column_end)
column_span = column_end - column_start;
}
// If the placement contains two spans, remove the one contributed by the end grid-placement
// property.
if (grid_column_start.is_span() && grid_column_end.is_span())
column_span = grid_column_start.span();
// FIXME: If the placement contains only a span for a named line, replace it with a span of 1.
// 4.1.1.1. Set the column position of the cursor to the grid item's column-start line. If this is
// less than the previous column position of the cursor, increment the row position by 1.