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

LibWeb: Refactor GridFormattingContext

For legibility, split up the run() function of the GridFormattingContext
into individual components.
This commit is contained in:
Tom 2022-12-28 10:12:30 +01:00 committed by Andreas Kling
parent 0bbf7a1b54
commit 6e29f693f5
2 changed files with 765 additions and 737 deletions

View file

@ -17,13 +17,8 @@ GridFormattingContext::GridFormattingContext(LayoutState& state, BlockContainer
GridFormattingContext::~GridFormattingContext() = default;
void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const& available_space)
float GridFormattingContext::resolve_definite_track_size(CSS::GridSize const& grid_size, AvailableSpace const& available_space, Box const& box)
{
auto& box_state = m_state.get_mutable(box);
auto grid_template_columns = box.computed_values().grid_template_columns();
auto grid_template_rows = box.computed_values().grid_template_rows();
auto resolve_definite_track_size = [&](CSS::GridSize const& grid_size) -> float {
VERIFY(grid_size.is_definite());
switch (grid_size.type()) {
case CSS::GridSize::Type::Length:
@ -38,27 +33,30 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
VERIFY_NOT_REACHED();
}
return 0;
};
}
auto count_of_gap_columns = [&]() -> size_t {
size_t GridFormattingContext::count_of_gap_columns()
{
size_t count = 0;
for (auto& grid_column : m_grid_columns) {
if (grid_column.is_gap)
count++;
}
return count;
};
}
auto count_of_gap_rows = [&]() -> size_t {
size_t GridFormattingContext::count_of_gap_rows()
{
size_t count = 0;
for (auto& grid_row : m_grid_rows) {
if (grid_row.is_gap)
count++;
}
return count;
};
}
auto resolve_size = [&](CSS::Size const& size, AvailableSize const& available_size) -> float {
float GridFormattingContext::resolve_size(CSS::Size const& size, AvailableSize const& available_size, Box const& box)
{
if (size.is_length() && size.length().is_calculated()) {
if (size.length().calculated_style_value()->contains_percentage()) {
if (!available_size.is_definite())
@ -77,44 +75,29 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
return available_size.to_px() * size.percentage().as_fraction();
}
return 0;
};
}
// https://drafts.csswg.org/css-grid/#overview-placement
// 2.2. Placing Items
// The contents of the grid container are organized into individual grid items (analogous to
// flex items), which are then assigned to predefined areas in the grid. They can be explicitly
// placed using coordinates through the grid-placement properties or implicitly placed into
// empty areas using auto-placement.
struct PositionedBox {
Box const& box;
int row { 0 };
int row_span { 1 };
int column { 0 };
int column_span { 1 };
};
Vector<PositionedBox> positioned_boxes;
Vector<Box const&> boxes_to_place;
box.for_each_child_of_type<Box>([&](Box& child_box) {
if (can_skip_is_anonymous_text_run(child_box))
return IterationDecision::Continue;
boxes_to_place.append(child_box);
return IterationDecision::Continue;
});
auto column_count = 0;
for (auto const& explicit_grid_track : grid_template_columns.track_list()) {
int GridFormattingContext::get_count_of_tracks(Vector<CSS::ExplicitGridTrack> const& track_list, AvailableSpace const& available_space, Box const& box)
{
auto track_count = 0;
for (auto const& explicit_grid_track : track_list) {
if (explicit_grid_track.is_repeat() && explicit_grid_track.repeat().is_default())
column_count += explicit_grid_track.repeat().repeat_count() * explicit_grid_track.repeat().grid_track_size_list().track_list().size();
track_count += explicit_grid_track.repeat().repeat_count() * explicit_grid_track.repeat().grid_track_size_list().track_list().size();
else
column_count += 1;
}
auto row_count = 0;
for (auto const& explicit_grid_track : grid_template_rows.track_list()) {
if (explicit_grid_track.is_repeat() && explicit_grid_track.repeat().is_default())
row_count += explicit_grid_track.repeat().repeat_count() * explicit_grid_track.repeat().grid_track_size_list().track_list().size();
else
row_count += 1;
track_count += 1;
}
if (track_list.size() == 1
&& track_list.first().is_repeat()
&& (track_list.first().repeat().is_auto_fill() || track_list.first().repeat().is_auto_fit())) {
track_count = count_of_repeated_auto_fill_or_fit_tracks(track_list, available_space, box);
}
return track_count;
}
int GridFormattingContext::count_of_repeated_auto_fill_or_fit_tracks(Vector<CSS::ExplicitGridTrack> const& track_list, AvailableSpace const& available_space, Box const& box)
{
// https://www.w3.org/TR/css-grid-2/#auto-repeat
// 7.2.3.2. Repeat-to-fill: auto-fill and auto-fit repetitions
// On a subgridded axis, the auto-fill keyword is only valid once per <line-name-list>, and repeats
@ -122,9 +105,6 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
// the span is already fulfilled).
// Otherwise on a standalone axis, when auto-fill is given as the repetition number
if (grid_template_columns.track_list().size() == 1
&& grid_template_columns.track_list().first().is_repeat()
&& (grid_template_columns.track_list().first().repeat().is_auto_fill() || grid_template_columns.track_list().first().repeat().is_auto_fit())) {
// If the grid container has a definite size or max size in the relevant axis, then the number of
// repetitions is the largest possible positive integer that does not cause the grid to overflow the
// content box of its grid container
@ -134,77 +114,28 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
// function otherwise, flooring the max track sizing function by the min track sizing function if both
// are definite, and taking gap into account)
// FIXME: take gap into account
for (auto& explicit_grid_track : grid_template_columns.track_list().first().repeat().grid_track_size_list().track_list()) {
for (auto& explicit_grid_track : track_list.first().repeat().grid_track_size_list().track_list()) {
auto track_sizing_function = explicit_grid_track;
if (track_sizing_function.is_minmax()) {
if (track_sizing_function.minmax().max_grid_size().is_definite() && !track_sizing_function.minmax().min_grid_size().is_definite())
sum_of_grid_track_sizes += resolve_definite_track_size(track_sizing_function.minmax().max_grid_size());
sum_of_grid_track_sizes += resolve_definite_track_size(track_sizing_function.minmax().max_grid_size(), available_space, box);
else if (track_sizing_function.minmax().min_grid_size().is_definite() && !track_sizing_function.minmax().max_grid_size().is_definite())
sum_of_grid_track_sizes += resolve_definite_track_size(track_sizing_function.minmax().min_grid_size());
sum_of_grid_track_sizes += resolve_definite_track_size(track_sizing_function.minmax().min_grid_size(), available_space, box);
else if (track_sizing_function.minmax().min_grid_size().is_definite() && track_sizing_function.minmax().max_grid_size().is_definite())
sum_of_grid_track_sizes += min(resolve_definite_track_size(track_sizing_function.minmax().min_grid_size()), resolve_definite_track_size(track_sizing_function.minmax().max_grid_size()));
sum_of_grid_track_sizes += min(resolve_definite_track_size(track_sizing_function.minmax().min_grid_size(), available_space, box), resolve_definite_track_size(track_sizing_function.minmax().max_grid_size(), available_space, box));
} else {
sum_of_grid_track_sizes += min(resolve_definite_track_size(track_sizing_function.grid_size()), resolve_definite_track_size(track_sizing_function.grid_size()));
sum_of_grid_track_sizes += min(resolve_definite_track_size(track_sizing_function.grid_size(), available_space, box), resolve_definite_track_size(track_sizing_function.grid_size(), available_space, box));
}
}
column_count = max(1, static_cast<int>(get_free_space_x(available_space) / sum_of_grid_track_sizes));
return max(1, static_cast<int>(get_free_space_x(available_space) / sum_of_grid_track_sizes));
// For the purpose of finding the number of auto-repeated tracks in a standalone axis, the UA must
// floor the track size to a UA-specified value to avoid division by zero. It is suggested that this
// floor be 1px.
}
if (grid_template_rows.track_list().size() == 1
&& grid_template_rows.track_list().first().is_repeat()
&& (grid_template_rows.track_list().first().repeat().is_auto_fill() || grid_template_rows.track_list().first().repeat().is_auto_fit())) {
// If the grid container has a definite size or max size in the relevant axis, then the number of
// repetitions is the largest possible positive integer that does not cause the grid to overflow the
// content box of its grid container
auto sum_of_grid_track_sizes = 0;
// (treating each track as its max track sizing function if that is definite or its minimum track sizing
// function otherwise, flooring the max track sizing function by the min track sizing function if both
// are definite, and taking gap into account)
// FIXME: take gap into account
for (auto& explicit_grid_track : grid_template_rows.track_list().first().repeat().grid_track_size_list().track_list()) {
auto track_sizing_function = explicit_grid_track;
if (track_sizing_function.is_minmax()) {
if (track_sizing_function.minmax().max_grid_size().is_definite() && !track_sizing_function.minmax().min_grid_size().is_definite())
sum_of_grid_track_sizes += resolve_definite_track_size(track_sizing_function.minmax().max_grid_size());
else if (track_sizing_function.minmax().min_grid_size().is_definite() && !track_sizing_function.minmax().max_grid_size().is_definite())
sum_of_grid_track_sizes += resolve_definite_track_size(track_sizing_function.minmax().min_grid_size());
else if (track_sizing_function.minmax().min_grid_size().is_definite() && track_sizing_function.minmax().max_grid_size().is_definite())
sum_of_grid_track_sizes += min(resolve_definite_track_size(track_sizing_function.minmax().min_grid_size()), resolve_definite_track_size(track_sizing_function.minmax().max_grid_size()));
} else {
sum_of_grid_track_sizes += min(resolve_definite_track_size(track_sizing_function.grid_size()), resolve_definite_track_size(track_sizing_function.grid_size()));
}
}
row_count = max(1, static_cast<int>(get_free_space_y(box) / sum_of_grid_track_sizes));
// The auto-fit keyword behaves the same as auto-fill, except that after grid item placement any
// empty repeated tracks are collapsed. An empty track is one with no in-flow grid items placed into
// or spanning across it. (This can result in all tracks being collapsed, if theyre all empty.)
// A collapsed track is treated as having a fixed track sizing function of 0px, and the gutters on
// either side of it—including any space allotted through distributed alignment—collapse.
// For the purpose of finding the number of auto-repeated tracks in a standalone axis, the UA must
// floor the track size to a UA-specified value to avoid division by zero. It is suggested that this
// floor be 1px.
}
auto occupation_grid = OccupationGrid(column_count, row_count);
// https://drafts.csswg.org/css-grid/#auto-placement-algo
// 8.5. Grid Item Placement Algorithm
// FIXME: 0. Generate anonymous grid items
// 1. Position anything that's not auto-positioned.
for (size_t i = 0; i < boxes_to_place.size(); i++) {
auto const& child_box = boxes_to_place[i];
if (is_auto_positioned_row(child_box.computed_values().grid_row_start(), child_box.computed_values().grid_row_end())
|| is_auto_positioned_column(child_box.computed_values().grid_column_start(), child_box.computed_values().grid_column_end()))
continue;
}
void GridFormattingContext::place_item_with_row_and_column_position(Box const& box, Box const& child_box)
{
int row_start = child_box.computed_values().grid_row_start().raw_value();
int row_end = child_box.computed_values().grid_row_end().raw_value();
int column_start = child_box.computed_values().grid_column_start().raw_value();
@ -224,9 +155,9 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
// 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 = occupation_grid.row_count() + row_end + 2;
row_end = m_occupation_grid.row_count() + row_end + 2;
if (column_end < 0)
column_end = occupation_grid.column_count() + column_end + 2;
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
@ -266,14 +197,14 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
// 8.1.3. Named Lines and Spans
// Instead of counting lines by number, lines can be referenced by their line name:
if (child_box.computed_values().grid_column_start().has_line_name()) {
auto found_flag_and_index = get_line_index_by_line_name(child_box.computed_values().grid_column_start().line_name(), grid_template_columns);
auto found_flag_and_index = get_line_index_by_line_name(child_box.computed_values().grid_column_start().line_name(), box.computed_values().grid_template_columns());
if (found_flag_and_index > -1)
column_start = 1 + found_flag_and_index;
else
column_start = 1; // FIXME
}
if (child_box.computed_values().grid_column_end().has_line_name()) {
auto found_flag_and_index = get_line_index_by_line_name(child_box.computed_values().grid_column_end().line_name(), grid_template_columns);
auto found_flag_and_index = get_line_index_by_line_name(child_box.computed_values().grid_column_end().line_name(), box.computed_values().grid_template_columns());
if (found_flag_and_index > -1) {
column_end = 1 + found_flag_and_index;
if (!child_box.computed_values().grid_column_start().is_position())
@ -284,14 +215,14 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
}
}
if (child_box.computed_values().grid_row_start().has_line_name()) {
auto found_flag_and_index = get_line_index_by_line_name(child_box.computed_values().grid_row_start().line_name(), grid_template_rows);
auto found_flag_and_index = get_line_index_by_line_name(child_box.computed_values().grid_row_start().line_name(), box.computed_values().grid_template_rows());
if (found_flag_and_index > -1)
row_start = 1 + found_flag_and_index;
else
row_start = 1; // FIXME
}
if (child_box.computed_values().grid_row_end().has_line_name()) {
auto found_flag_and_index = get_line_index_by_line_name(child_box.computed_values().grid_row_end().line_name(), grid_template_rows);
auto found_flag_and_index = get_line_index_by_line_name(child_box.computed_values().grid_row_end().line_name(), box.computed_values().grid_template_rows());
if (found_flag_and_index > -1) {
row_end = 1 + found_flag_and_index;
if (!child_box.computed_values().grid_row_start().is_position())
@ -334,22 +265,15 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
row_start -= 1;
column_start -= 1;
positioned_boxes.append({ child_box, row_start, row_span, column_start, column_span });
m_positioned_boxes.append({ child_box, row_start, row_span, column_start, column_span });
occupation_grid.maybe_add_row(row_start + row_span);
occupation_grid.maybe_add_column(column_start + column_span);
occupation_grid.set_occupied(column_start, column_start + column_span, row_start, row_start + row_span);
boxes_to_place.remove(i);
i--;
}
// 2. Process the items locked to a given row.
// FIXME: Do "dense" packing
for (size_t i = 0; i < boxes_to_place.size(); i++) {
auto const& child_box = boxes_to_place[i];
if (is_auto_positioned_row(child_box.computed_values().grid_row_start(), child_box.computed_values().grid_row_end()))
continue;
m_occupation_grid.maybe_add_row(row_start + row_span);
m_occupation_grid.maybe_add_column(column_start + column_span);
m_occupation_grid.set_occupied(column_start, column_start + column_span, row_start, row_start + row_span);
}
void GridFormattingContext::place_item_with_row_position(Box const& box, Box const& child_box)
{
int row_start = child_box.computed_values().grid_row_start().raw_value();
int row_end = child_box.computed_values().grid_row_end().raw_value();
@ -367,7 +291,7 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
// 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 = occupation_grid.row_count() + row_end + 2;
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
@ -403,14 +327,14 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
// 8.1.3. Named Lines and Spans
// Instead of counting lines by number, lines can be referenced by their line name:
if (child_box.computed_values().grid_row_start().has_line_name()) {
auto found_flag_and_index = get_line_index_by_line_name(child_box.computed_values().grid_row_start().line_name(), grid_template_rows);
auto found_flag_and_index = get_line_index_by_line_name(child_box.computed_values().grid_row_start().line_name(), box.computed_values().grid_template_rows());
if (found_flag_and_index > -1)
row_start = 1 + found_flag_and_index;
else
row_start = 1; // FIXME
}
if (child_box.computed_values().grid_row_end().has_line_name()) {
auto found_flag_and_index = get_line_index_by_line_name(child_box.computed_values().grid_row_end().line_name(), grid_template_rows);
auto found_flag_and_index = get_line_index_by_line_name(child_box.computed_values().grid_row_end().line_name(), box.computed_values().grid_template_rows());
if (found_flag_and_index > -1) {
row_end = 1 + found_flag_and_index;
if (!child_box.computed_values().grid_row_start().is_position())
@ -447,7 +371,7 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
// FIXME: If the placement contains only a span for a named line, replace it with a span of 1.
row_start -= 1;
occupation_grid.maybe_add_row(row_start + row_span);
m_occupation_grid.maybe_add_row(row_start + row_span);
int column_start = 0;
auto column_span = child_box.computed_values().grid_column_start().is_span() ? child_box.computed_values().grid_column_start().raw_value() : 1;
@ -456,51 +380,26 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
// 3.3. If the largest column span among all the items without a definite column position is larger
// than the width of the implicit grid, add columns to the end of the implicit grid to accommodate
// that column span.
occupation_grid.maybe_add_column(column_span);
m_occupation_grid.maybe_add_column(column_span);
bool found_available_column = false;
for (int column_index = column_start; column_index < occupation_grid.column_count(); column_index++) {
if (!occupation_grid.is_occupied(column_index, row_start)) {
for (int column_index = column_start; column_index < m_occupation_grid.column_count(); column_index++) {
if (!m_occupation_grid.is_occupied(column_index, row_start)) {
found_available_column = true;
column_start = column_index;
break;
}
}
if (!found_available_column) {
column_start = occupation_grid.column_count();
occupation_grid.maybe_add_column(column_start + column_span);
column_start = m_occupation_grid.column_count();
m_occupation_grid.maybe_add_column(column_start + column_span);
}
occupation_grid.set_occupied(column_start, column_start + column_span, row_start, row_start + row_span);
m_occupation_grid.set_occupied(column_start, column_start + column_span, row_start, row_start + row_span);
positioned_boxes.append({ child_box, row_start, row_span, column_start, column_span });
boxes_to_place.remove(i);
i--;
}
m_positioned_boxes.append({ child_box, row_start, row_span, column_start, column_span });
}
// 3. Determine the columns in the implicit grid.
// NOTE: "implicit grid" here is the same as the occupation_grid
// 3.1. Start with the columns from the explicit grid.
// NOTE: Done in step 1.
// 3.2. Among all the items with a definite column position (explicitly positioned items, items
// positioned in the previous step, and items not yet positioned but with a definite column) add
// columns to the beginning and end of the implicit grid as necessary to accommodate those items.
// NOTE: "Explicitly positioned items" and "items positioned in the previous step" done in step 1
// and 2, respectively. Adding columns for "items not yet positioned but with a definite column"
// will be done in step 4.
// 4. Position the remaining grid items.
// For each grid item that hasn't been positioned by the previous steps, in order-modified document
// order:
auto auto_placement_cursor_x = 0;
auto auto_placement_cursor_y = 0;
for (size_t i = 0; i < boxes_to_place.size(); i++) {
auto const& child_box = boxes_to_place[i];
// 4.1. For sparse packing:
// FIXME: no distinction made. See #4.2
// 4.1.1. If the item has a definite column position:
if (!is_auto_positioned_column(child_box.computed_values().grid_column_start(), child_box.computed_values().grid_column_end())) {
void GridFormattingContext::place_item_with_column_position(Box const& box, Box const& child_box, int& auto_placement_cursor_x, int& auto_placement_cursor_y)
{
int column_start = child_box.computed_values().grid_column_start().raw_value();
int column_end = child_box.computed_values().grid_column_end().raw_value();
@ -518,7 +417,7 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
// 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 = occupation_grid.column_count() + column_end + 2;
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
@ -558,14 +457,14 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
// 8.1.3. Named Lines and Spans
// Instead of counting lines by number, lines can be referenced by their line name:
if (child_box.computed_values().grid_column_start().has_line_name()) {
auto found_flag_and_index = get_line_index_by_line_name(child_box.computed_values().grid_column_start().line_name(), grid_template_columns);
auto found_flag_and_index = get_line_index_by_line_name(child_box.computed_values().grid_column_start().line_name(), box.computed_values().grid_template_columns());
if (found_flag_and_index > -1)
column_start = 1 + found_flag_and_index;
else
column_start = 1; // FIXME
}
if (child_box.computed_values().grid_column_end().has_line_name()) {
auto found_flag_and_index = get_line_index_by_line_name(child_box.computed_values().grid_column_end().line_name(), grid_template_columns);
auto found_flag_and_index = get_line_index_by_line_name(child_box.computed_values().grid_column_end().line_name(), box.computed_values().grid_template_columns());
if (found_flag_and_index > -1) {
column_end = 1 + found_flag_and_index;
if (!child_box.computed_values().grid_column_start().is_position())
@ -606,26 +505,27 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
auto_placement_cursor_y++;
auto_placement_cursor_x = column_start;
occupation_grid.maybe_add_column(auto_placement_cursor_x + column_span);
occupation_grid.maybe_add_row(auto_placement_cursor_y + row_span);
m_occupation_grid.maybe_add_column(auto_placement_cursor_x + column_span);
m_occupation_grid.maybe_add_row(auto_placement_cursor_y + row_span);
// 4.1.1.2. Increment the cursor's row position until a value is found where the grid item does not
// overlap any occupied grid cells (creating new rows in the implicit grid as necessary).
while (true) {
if (!occupation_grid.is_occupied(column_start, auto_placement_cursor_y)) {
if (!m_occupation_grid.is_occupied(column_start, auto_placement_cursor_y)) {
break;
}
auto_placement_cursor_y++;
occupation_grid.maybe_add_row(auto_placement_cursor_y + row_span);
m_occupation_grid.maybe_add_row(auto_placement_cursor_y + row_span);
}
// 4.1.1.3. Set the item's row-start line to the cursor's row position, and set the item's row-end
// line according to its span from that position.
occupation_grid.set_occupied(column_start, column_start + column_span, auto_placement_cursor_y, auto_placement_cursor_y + row_span);
m_occupation_grid.set_occupied(column_start, column_start + column_span, auto_placement_cursor_y, auto_placement_cursor_y + row_span);
positioned_boxes.append({ child_box, auto_placement_cursor_y, row_span, column_start, column_span });
}
// 4.1.2. If the item has an automatic grid position in both axes:
else {
m_positioned_boxes.append({ child_box, auto_placement_cursor_y, row_span, column_start, column_span });
}
void GridFormattingContext::place_item_with_no_declared_position(Box const& child_box, int& auto_placement_cursor_x, int& auto_placement_cursor_y)
{
// 4.1.2.1. Increment the column position of the auto-placement cursor until either this item's grid
// area does not overlap any occupied grid cells, or the cursor's column position, plus the item's
// column span, overflow the number of columns in the implicit grid, as determined earlier in this
@ -641,7 +541,7 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
// 3.3. If the largest column span among all the items without a definite column position is larger
// than the width of the implicit grid, add columns to the end of the implicit grid to accommodate
// that column span.
occupation_grid.maybe_add_column(column_span);
m_occupation_grid.maybe_add_column(column_span);
auto row_start = 0;
auto row_span = 1;
if (child_box.computed_values().grid_row_start().is_span())
@ -649,12 +549,12 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
else if (child_box.computed_values().grid_row_end().is_span())
row_span = child_box.computed_values().grid_row_end().raw_value();
auto found_unoccupied_area = false;
for (int row_index = auto_placement_cursor_y; row_index < occupation_grid.row_count(); row_index++) {
for (int column_index = auto_placement_cursor_x; column_index < occupation_grid.column_count(); column_index++) {
if (column_span + column_index <= occupation_grid.column_count()) {
for (int row_index = auto_placement_cursor_y; row_index < m_occupation_grid.row_count(); row_index++) {
for (int column_index = auto_placement_cursor_x; column_index < m_occupation_grid.column_count(); column_index++) {
if (column_span + column_index <= m_occupation_grid.column_count()) {
auto found_all_available = true;
for (int span_index = 0; span_index < column_span; span_index++) {
if (occupation_grid.is_occupied(column_index + span_index, row_index))
if (m_occupation_grid.is_occupied(column_index + span_index, row_index))
found_all_available = false;
}
if (found_all_available) {
@ -668,46 +568,24 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
auto_placement_cursor_x = 0;
auto_placement_cursor_y++;
}
finish:
finish:
// 4.1.2.2. If a non-overlapping position was found in the previous step, set the item's row-start
// and column-start lines to the cursor's position. Otherwise, increment the auto-placement cursor's
// row position (creating new rows in the implicit grid as necessary), set its column position to the
// start-most column line in the implicit grid, and return to the previous step.
if (!found_unoccupied_area) {
row_start = occupation_grid.row_count();
occupation_grid.maybe_add_row(occupation_grid.row_count() + 1);
row_start = m_occupation_grid.row_count();
m_occupation_grid.maybe_add_row(m_occupation_grid.row_count() + 1);
}
occupation_grid.set_occupied(column_start, column_start + column_span, row_start, row_start + row_span);
positioned_boxes.append({ child_box, row_start, row_span, column_start, column_span });
}
boxes_to_place.remove(i);
i--;
m_occupation_grid.set_occupied(column_start, column_start + column_span, row_start, row_start + row_span);
m_positioned_boxes.append({ child_box, row_start, row_span, column_start, column_span });
}
// FIXME: 4.2. For dense packing:
}
// https://drafts.csswg.org/css-grid/#overview-sizing
// 2.3. Sizing the Grid
// Once the grid items have been placed, the sizes of the grid tracks (rows and columns) are
// calculated, accounting for the sizes of their contents and/or available space as specified in
// the grid definition.
// https://www.w3.org/TR/css-grid-2/#layout-algorithm
// 12. Grid Sizing
// This section defines the grid sizing algorithm, which determines the size of all grid tracks and,
// by extension, the entire grid.
// Each track has specified minimum and maximum sizing functions (which may be the same). Each
// sizing function is either:
// - A fixed sizing function (<length> or resolvable <percentage>).
// - An intrinsic sizing function (min-content, max-content, auto, fit-content()).
// - A flexible sizing function (<flex>).
// The grid sizing algorithm defines how to resolve these sizing constraints into used track sizes.
for (auto const& track_in_list : grid_template_columns.track_list()) {
void GridFormattingContext::initialize_grid_tracks(Box const& box, AvailableSpace const& available_space, int column_count, int row_count)
{
for (auto const& track_in_list : box.computed_values().grid_template_columns().track_list()) {
auto repeat_count = (track_in_list.is_repeat() && track_in_list.repeat().is_default()) ? track_in_list.repeat().repeat_count() : 1;
if (track_in_list.is_repeat()) {
if (track_in_list.repeat().is_auto_fill() || track_in_list.repeat().is_auto_fit())
@ -735,7 +613,7 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
}
}
}
for (auto const& track_in_list : grid_template_rows.track_list()) {
for (auto const& track_in_list : box.computed_values().grid_template_rows().track_list()) {
auto repeat_count = (track_in_list.is_repeat() && track_in_list.repeat().is_default()) ? track_in_list.repeat().repeat_count() : 1;
if (track_in_list.is_repeat()) {
if (track_in_list.repeat().is_auto_fill() || track_in_list.repeat().is_auto_fit())
@ -764,9 +642,9 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
}
}
for (int column_index = m_grid_columns.size(); column_index < occupation_grid.column_count(); column_index++)
for (int column_index = m_grid_columns.size(); column_index < m_occupation_grid.column_count(); column_index++)
m_grid_columns.append(TemporaryTrack());
for (int row_index = m_grid_rows.size(); row_index < occupation_grid.row_count(); row_index++)
for (int row_index = m_grid_rows.size(); row_index < m_occupation_grid.row_count(); row_index++)
m_grid_rows.append(TemporaryTrack());
// https://www.w3.org/TR/css-grid-2/#gutters
@ -775,50 +653,19 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
// the specified size, which is spanned by any grid items that span across its corresponding grid
// line.
if (!box.computed_values().column_gap().is_auto()) {
for (int column_index = 1; column_index < (occupation_grid.column_count() * 2) - 1; column_index += 2)
m_grid_columns.insert(column_index, TemporaryTrack(resolve_size(box.computed_values().column_gap(), available_space.width), true));
for (int column_index = 1; column_index < (m_occupation_grid.column_count() * 2) - 1; column_index += 2)
m_grid_columns.insert(column_index, TemporaryTrack(resolve_size(box.computed_values().column_gap(), available_space.width, box), true));
}
if (!box.computed_values().row_gap().is_auto()) {
for (int row_index = 1; row_index < (occupation_grid.row_count() * 2) - 1; row_index += 2)
m_grid_rows.insert(row_index, TemporaryTrack(resolve_size(box.computed_values().row_gap(), available_space.height), true));
for (int row_index = 1; row_index < (m_occupation_grid.row_count() * 2) - 1; row_index += 2)
m_grid_rows.insert(row_index, TemporaryTrack(resolve_size(box.computed_values().row_gap(), available_space.height, box), true));
}
}
// https://www.w3.org/TR/css-grid-2/#algo-overview
// 12.1. Grid Sizing Algorithm
// 1. First, the track sizing algorithm is used to resolve the sizes of the grid columns.
// In this process, any grid item which is subgridded in the grid containers inline axis is treated
// as empty and its grid items (the grandchildren) are treated as direct children of the grid
// container (their grandparent). This introspection is recursive.
// Items which are subgridded only in the block axis, and whose grid container size in the inline
// axis depends on the size of its contents are also introspected: since the size of the item in
// this dimension can be dependent on the sizing of its subgridded tracks in the other, the size
// contribution of any such item to this grids column sizing (see Resolve Intrinsic Track Sizes) is
// taken under the provision of having determined its track sizing only up to the same point in the
// Grid Sizing Algorithm as this itself. E.g. for the first pass through this step, the item will
// have its tracks sized only through this first step; if a second pass of this step is triggered
// then the item will have completed a first pass through steps 1-3 as well as the second pass of
// this step prior to returning its size for consideration in this grids column sizing. Again, this
// introspection is recursive.
// https://www.w3.org/TR/css-grid-2/#algo-track-sizing
// 12.3. Track Sizing Algorithm
// The remainder of this section is the track sizing algorithm, which calculates from the min and
// max track sizing functions the used track size. Each track has a base size, a <length> which
// grows throughout the algorithm and which will eventually be the tracks final size, and a growth
// limit, a <length> which provides a desired maximum size for the base size. There are 5 steps:
// 1. Initialize Track Sizes
// 2. Resolve Intrinsic Track Sizes
// 3. Maximize Tracks
// 4. Expand Flexible Tracks
// 5. Expand Stretched auto Tracks
void GridFormattingContext::calculate_sizes_of_columns(Box const& box, AvailableSpace const& available_space)
{
// https://www.w3.org/TR/css-grid-2/#algo-init
// 12.4. Initialize Track Sizes
// Initialize each tracks base size and growth limit.
for (auto& grid_column : m_grid_columns) {
if (grid_column.is_gap)
@ -902,7 +749,7 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
}
Vector<Box const&> boxes_of_column;
for (auto& positioned_box : positioned_boxes) {
for (auto& positioned_box : m_positioned_boxes) {
if (positioned_box.column == index && positioned_box.column_span == 1)
boxes_of_column.append(positioned_box.box);
}
@ -962,12 +809,12 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
// The auto-fit keyword behaves the same as auto-fill, except that after grid item placement any
// empty repeated tracks are collapsed. An empty track is one with no in-flow grid items placed into
// or spanning across it. (This can result in all tracks being collapsed, if theyre all empty.)
if (grid_template_columns.track_list().size() == 1
&& grid_template_columns.track_list().first().is_repeat()
&& grid_template_columns.track_list().first().repeat().is_auto_fit()) {
if (box.computed_values().grid_template_columns().track_list().size() == 1
&& box.computed_values().grid_template_columns().track_list().first().is_repeat()
&& box.computed_values().grid_template_columns().track_list().first().repeat().is_auto_fit()) {
for (size_t idx = 0; idx < m_grid_columns.size(); idx++) {
auto column_to_check = box.computed_values().column_gap().is_auto() ? idx : idx / 2;
if (occupation_grid.is_occupied(column_to_check, 0))
if (m_occupation_grid.is_occupied(column_to_check, 0))
continue;
if (!box.computed_values().column_gap().is_auto() && idx % 2 != 0)
continue;
@ -1272,42 +1119,14 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
// function had that size and all other rows were infinite. If both the grid container and all
// tracks have definite sizes, also apply align-content to find the final effective size of any gaps
// spanned by such items; otherwise ignore the effects of track alignment in this estimation.
}
// https://www.w3.org/TR/css-grid-2/#algo-overview
// 12.1. Grid Sizing Algorithm
// 2. Next, the track sizing algorithm resolves the sizes of the grid rows.
// In this process, any grid item which is subgridded in the grid containers block axis is treated
// as empty and its grid items (the grandchildren) are treated as direct children of the grid
// container (their grandparent). This introspection is recursive.
// As with sizing columns, items which are subgridded only in the inline axis, and whose grid
// container size in the block axis depends on the size of its contents are also introspected. (As
// with sizing columns, the size contribution to this grids row sizing is taken under the provision
// of having determined its track sizing only up to this corresponding point in the algorithm; and
// again, this introspection is recursive.)
// To find the inline-axis available space for any items whose block-axis size contributions require
// it, use the grid column sizes calculated in the previous step. If the grid containers inline
// size is definite, also apply justify-content to account for the effective column gap sizes.
// https://www.w3.org/TR/css-grid-2/#algo-track-sizing
// 12.3. Track Sizing Algorithm
// The remainder of this section is the track sizing algorithm, which calculates from the min and
// max track sizing functions the used track size. Each track has a base size, a <length> which
// grows throughout the algorithm and which will eventually be the tracks final size, and a growth
// limit, a <length> which provides a desired maximum size for the base size. There are 5 steps:
// 1. Initialize Track Sizes
// 2. Resolve Intrinsic Track Sizes
// 3. Maximize Tracks
// 4. Expand Flexible Tracks
// 5. Expand Stretched auto Tracks
void GridFormattingContext::calculate_sizes_of_rows(Box const& box)
{
// https://www.w3.org/TR/css-grid-2/#algo-init
// 12.4. Initialize Track Sizes
// Initialize each tracks base size and growth limit.
auto& box_state = m_state.get_mutable(box);
for (auto& grid_row : m_grid_rows) {
if (grid_row.is_gap)
continue;
@ -1378,7 +1197,7 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
// 2. Size tracks to fit non-spanning items: For each track with an intrinsic track sizing function and
// not a flexible sizing function, consider the items in it with a span of 1:
index = 0;
auto index = 0;
for (auto& grid_row : m_grid_rows) {
if (grid_row.is_gap)
continue;
@ -1388,7 +1207,7 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
}
Vector<PositionedBox&> positioned_boxes_of_row;
for (auto& positioned_box : positioned_boxes) {
for (auto& positioned_box : m_positioned_boxes) {
if (positioned_box.row == index && positioned_box.row_span == 1)
positioned_boxes_of_row.append(positioned_box);
}
@ -1560,7 +1379,7 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
// If the free space is positive, distribute it equally to the base sizes of all tracks, freezing
// tracks as they reach their growth limits (and continuing to grow the unfrozen tracks as needed).
free_space = get_free_space_y(box);
auto free_space = get_free_space_y(box);
while (free_space > 0) {
auto free_space_to_distribute_per_track = free_space / (m_grid_rows.size() - count_of_gap_rows());
for (auto& grid_row : m_grid_rows) {
@ -1695,6 +1514,183 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
if (grid_row.max_track_sizing_function.is_length() && grid_row.max_track_sizing_function.length().is_auto())
grid_row.base_size = max(grid_row.base_size, remaining_vertical_space / count_of_auto_max_row_tracks);
}
}
void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const& available_space)
{
auto grid_template_columns = box.computed_values().grid_template_columns();
auto grid_template_rows = box.computed_values().grid_template_rows();
// https://drafts.csswg.org/css-grid/#overview-placement
// 2.2. Placing Items
// The contents of the grid container are organized into individual grid items (analogous to
// flex items), which are then assigned to predefined areas in the grid. They can be explicitly
// placed using coordinates through the grid-placement properties or implicitly placed into
// empty areas using auto-placement.
box.for_each_child_of_type<Box>([&](Box& child_box) {
if (can_skip_is_anonymous_text_run(child_box))
return IterationDecision::Continue;
m_boxes_to_place.append(child_box);
return IterationDecision::Continue;
});
auto column_count = get_count_of_tracks(grid_template_columns.track_list(), available_space, box);
auto row_count = get_count_of_tracks(grid_template_rows.track_list(), available_space, box);
m_occupation_grid = OccupationGrid(column_count, row_count);
// https://drafts.csswg.org/css-grid/#auto-placement-algo
// 8.5. Grid Item Placement Algorithm
// FIXME: 0. Generate anonymous grid items
// 1. Position anything that's not auto-positioned.
for (size_t i = 0; i < m_boxes_to_place.size(); i++) {
auto const& child_box = m_boxes_to_place[i];
if (is_auto_positioned_row(child_box.computed_values().grid_row_start(), child_box.computed_values().grid_row_end())
|| is_auto_positioned_column(child_box.computed_values().grid_column_start(), child_box.computed_values().grid_column_end()))
continue;
place_item_with_row_and_column_position(box, child_box);
m_boxes_to_place.remove(i);
i--;
}
// 2. Process the items locked to a given row.
// FIXME: Do "dense" packing
for (size_t i = 0; i < m_boxes_to_place.size(); i++) {
auto const& child_box = m_boxes_to_place[i];
if (is_auto_positioned_row(child_box.computed_values().grid_row_start(), child_box.computed_values().grid_row_end()))
continue;
place_item_with_row_position(box, child_box);
m_boxes_to_place.remove(i);
i--;
}
// 3. Determine the columns in the implicit grid.
// NOTE: "implicit grid" here is the same as the m_occupation_grid
// 3.1. Start with the columns from the explicit grid.
// NOTE: Done in step 1.
// 3.2. Among all the items with a definite column position (explicitly positioned items, items
// positioned in the previous step, and items not yet positioned but with a definite column) add
// columns to the beginning and end of the implicit grid as necessary to accommodate those items.
// NOTE: "Explicitly positioned items" and "items positioned in the previous step" done in step 1
// and 2, respectively. Adding columns for "items not yet positioned but with a definite column"
// will be done in step 4.
// 4. Position the remaining grid items.
// For each grid item that hasn't been positioned by the previous steps, in order-modified document
// order:
auto auto_placement_cursor_x = 0;
auto auto_placement_cursor_y = 0;
for (size_t i = 0; i < m_boxes_to_place.size(); i++) {
auto const& child_box = m_boxes_to_place[i];
// 4.1. For sparse packing:
// FIXME: no distinction made. See #4.2
// 4.1.1. If the item has a definite column position:
if (!is_auto_positioned_column(child_box.computed_values().grid_column_start(), child_box.computed_values().grid_column_end()))
place_item_with_column_position(box, child_box, auto_placement_cursor_x, auto_placement_cursor_y);
// 4.1.2. If the item has an automatic grid position in both axes:
else
place_item_with_no_declared_position(child_box, auto_placement_cursor_x, auto_placement_cursor_y);
m_boxes_to_place.remove(i);
i--;
// FIXME: 4.2. For dense packing:
}
// https://drafts.csswg.org/css-grid/#overview-sizing
// 2.3. Sizing the Grid
// Once the grid items have been placed, the sizes of the grid tracks (rows and columns) are
// calculated, accounting for the sizes of their contents and/or available space as specified in
// the grid definition.
// https://www.w3.org/TR/css-grid-2/#layout-algorithm
// 12. Grid Sizing
// This section defines the grid sizing algorithm, which determines the size of all grid tracks and,
// by extension, the entire grid.
// Each track has specified minimum and maximum sizing functions (which may be the same). Each
// sizing function is either:
// - A fixed sizing function (<length> or resolvable <percentage>).
// - An intrinsic sizing function (min-content, max-content, auto, fit-content()).
// - A flexible sizing function (<flex>).
// The grid sizing algorithm defines how to resolve these sizing constraints into used track sizes.
initialize_grid_tracks(box, available_space, column_count, row_count);
// https://www.w3.org/TR/css-grid-2/#algo-overview
// 12.1. Grid Sizing Algorithm
// 1. First, the track sizing algorithm is used to resolve the sizes of the grid columns.
// In this process, any grid item which is subgridded in the grid containers inline axis is treated
// as empty and its grid items (the grandchildren) are treated as direct children of the grid
// container (their grandparent). This introspection is recursive.
// Items which are subgridded only in the block axis, and whose grid container size in the inline
// axis depends on the size of its contents are also introspected: since the size of the item in
// this dimension can be dependent on the sizing of its subgridded tracks in the other, the size
// contribution of any such item to this grids column sizing (see Resolve Intrinsic Track Sizes) is
// taken under the provision of having determined its track sizing only up to the same point in the
// Grid Sizing Algorithm as this itself. E.g. for the first pass through this step, the item will
// have its tracks sized only through this first step; if a second pass of this step is triggered
// then the item will have completed a first pass through steps 1-3 as well as the second pass of
// this step prior to returning its size for consideration in this grids column sizing. Again, this
// introspection is recursive.
// https://www.w3.org/TR/css-grid-2/#algo-track-sizing
// 12.3. Track Sizing Algorithm
// The remainder of this section is the track sizing algorithm, which calculates from the min and
// max track sizing functions the used track size. Each track has a base size, a <length> which
// grows throughout the algorithm and which will eventually be the tracks final size, and a growth
// limit, a <length> which provides a desired maximum size for the base size. There are 5 steps:
// 1. Initialize Track Sizes
// 2. Resolve Intrinsic Track Sizes
// 3. Maximize Tracks
// 4. Expand Flexible Tracks
// 5. Expand Stretched auto Tracks
calculate_sizes_of_columns(box, available_space);
// https://www.w3.org/TR/css-grid-2/#algo-overview
// 12.1. Grid Sizing Algorithm
// 2. Next, the track sizing algorithm resolves the sizes of the grid rows.
// In this process, any grid item which is subgridded in the grid containers block axis is treated
// as empty and its grid items (the grandchildren) are treated as direct children of the grid
// container (their grandparent). This introspection is recursive.
// As with sizing columns, items which are subgridded only in the inline axis, and whose grid
// container size in the block axis depends on the size of its contents are also introspected. (As
// with sizing columns, the size contribution to this grids row sizing is taken under the provision
// of having determined its track sizing only up to this corresponding point in the algorithm; and
// again, this introspection is recursive.)
// To find the inline-axis available space for any items whose block-axis size contributions require
// it, use the grid column sizes calculated in the previous step. If the grid containers inline
// size is definite, also apply justify-content to account for the effective column gap sizes.
// https://www.w3.org/TR/css-grid-2/#algo-track-sizing
// 12.3. Track Sizing Algorithm
// The remainder of this section is the track sizing algorithm, which calculates from the min and
// max track sizing functions the used track size. Each track has a base size, a <length> which
// grows throughout the algorithm and which will eventually be the tracks final size, and a growth
// limit, a <length> which provides a desired maximum size for the base size. There are 5 steps:
// 1. Initialize Track Sizes
// 2. Resolve Intrinsic Track Sizes
// 3. Maximize Tracks
// 4. Expand Flexible Tracks
// 5. Expand Stretched auto Tracks
calculate_sizes_of_rows(box);
// https://www.w3.org/TR/css-grid-2/#algo-overview
// 12.1. Grid Sizing Algorithm
@ -1745,7 +1741,7 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const
independent_formatting_context->parent_context_did_dimension_child_root_box();
};
for (auto& positioned_box : positioned_boxes) {
for (auto& positioned_box : m_positioned_boxes) {
auto resolved_row_start = box.computed_values().row_gap().is_auto() ? positioned_box.row : positioned_box.row * 2;
auto resolved_row_span = box.computed_values().row_gap().is_auto() ? positioned_box.row_span : positioned_box.row_span * 2;
if (!box.computed_values().row_gap().is_auto() && resolved_row_start == 0)
@ -1866,6 +1862,10 @@ OccupationGrid::OccupationGrid(int column_count, int row_count)
m_occupation_grid.append(occupation_grid_row);
}
OccupationGrid::OccupationGrid()
{
}
void OccupationGrid::maybe_add_column(int needed_number_of_columns)
{
if (needed_number_of_columns <= column_count())

View file

@ -13,6 +13,24 @@
namespace Web::Layout {
class OccupationGrid {
public:
OccupationGrid(int column_count, int row_count);
OccupationGrid();
void maybe_add_column(int needed_number_of_columns);
void maybe_add_row(int needed_number_of_rows);
void set_occupied(int column_start, int column_end, int row_start, int row_end);
void set_occupied(int column_index, int row_index);
int column_count() { return static_cast<int>(m_occupation_grid[0].size()); }
int row_count() { return static_cast<int>(m_occupation_grid.size()); }
bool is_occupied(int column_index, int row_index);
private:
Vector<Vector<bool>> m_occupation_grid;
};
class GridFormattingContext final : public BlockFormattingContext {
public:
explicit GridFormattingContext(LayoutState&, BlockContainer const&, FormattingContext* parent);
@ -27,6 +45,14 @@ private:
bool is_auto_positioned_column(CSS::GridTrackPlacement const&, CSS::GridTrackPlacement const&) const;
bool is_auto_positioned_track(CSS::GridTrackPlacement const&, CSS::GridTrackPlacement const&) const;
struct PositionedBox {
Box const& box;
int row { 0 };
int row_span { 1 };
int column { 0 };
int column_span { 1 };
};
struct TemporaryTrack {
CSS::GridSize min_track_sizing_function;
CSS::GridSize max_track_sizing_function;
@ -66,27 +92,29 @@ private:
Vector<TemporaryTrack> m_grid_rows;
Vector<TemporaryTrack> m_grid_columns;
OccupationGrid m_occupation_grid;
Vector<PositionedBox> m_positioned_boxes;
Vector<Box const&> m_boxes_to_place;
float get_free_space_x(AvailableSpace const& available_space);
float get_free_space_y(Box const&);
int get_line_index_by_line_name(DeprecatedString const& line_name, CSS::GridTrackSizeList);
};
float resolve_definite_track_size(CSS::GridSize const&, AvailableSpace const&, Box const&);
size_t count_of_gap_columns();
size_t count_of_gap_rows();
float resolve_size(CSS::Size const&, AvailableSize const&, Box const&);
int count_of_repeated_auto_fill_or_fit_tracks(Vector<CSS::ExplicitGridTrack> const& track_list, AvailableSpace const&, Box const&);
int get_count_of_tracks(Vector<CSS::ExplicitGridTrack> const&, AvailableSpace const&, Box const&);
class OccupationGrid {
public:
OccupationGrid(int column_count, int row_count);
void place_item_with_row_and_column_position(Box const& box, Box const& child_box);
void place_item_with_row_position(Box const& box, Box const& child_box);
void place_item_with_column_position(Box const& box, Box const& child_box, int& auto_placement_cursor_x, int& auto_placement_cursor_y);
void place_item_with_no_declared_position(Box const& child_box, int& auto_placement_cursor_x, int& auto_placement_cursor_y);
void maybe_add_column(int needed_number_of_columns);
void maybe_add_row(int needed_number_of_rows);
void set_occupied(int column_start, int column_end, int row_start, int row_end);
void set_occupied(int column_index, int row_index);
int column_count() { return static_cast<int>(m_occupation_grid[0].size()); }
int row_count() { return static_cast<int>(m_occupation_grid.size()); }
bool is_occupied(int column_index, int row_index);
private:
Vector<Vector<bool>> m_occupation_grid;
void initialize_grid_tracks(Box const&, AvailableSpace const&, int column_count, int row_count);
void calculate_sizes_of_columns(Box const&, AvailableSpace const&);
void calculate_sizes_of_rows(Box const&);
};
}