summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWeb
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/Libraries/LibWeb')
-rw-r--r--Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp1422
-rw-r--r--Userland/Libraries/LibWeb/Layout/GridFormattingContext.h62
2 files changed, 756 insertions, 728 deletions
diff --git a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp
index e103f66d2c..80a6a18a9c 100644
--- a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp
+++ b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp
@@ -17,104 +17,87 @@ 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:
- if (grid_size.length().is_auto())
- break;
- return grid_size.length().to_px(box);
- case CSS::GridSize::Type::Percentage:
- if (available_space.width.is_definite())
- return grid_size.percentage().as_fraction() * available_space.width.to_px();
+ VERIFY(grid_size.is_definite());
+ switch (grid_size.type()) {
+ case CSS::GridSize::Type::Length:
+ if (grid_size.length().is_auto())
break;
- default:
- VERIFY_NOT_REACHED();
- }
- return 0;
- };
+ return grid_size.length().to_px(box);
+ case CSS::GridSize::Type::Percentage:
+ if (available_space.width.is_definite())
+ return grid_size.percentage().as_fraction() * available_space.width.to_px();
+ break;
+ default:
+ VERIFY_NOT_REACHED();
+ }
+ return 0;
+}
- auto count_of_gap_columns = [&]() -> size_t {
- size_t count = 0;
- for (auto& grid_column : m_grid_columns) {
- if (grid_column.is_gap)
- count++;
- }
- return count;
- };
+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 count = 0;
- for (auto& grid_row : m_grid_rows) {
- if (grid_row.is_gap)
- count++;
- }
- return count;
- };
+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 {
- if (size.is_length() && size.length().is_calculated()) {
- if (size.length().calculated_style_value()->contains_percentage()) {
- if (!available_size.is_definite())
- return 0;
- auto& calc_value = *size.length().calculated_style_value();
- return calc_value.resolve_length_percentage(box, CSS::Length::make_px(available_size.to_px())).value_or(CSS::Length::make_auto()).to_px(box);
- }
- return size.length().to_px(box);
- }
- if (size.is_length()) {
- return size.length().to_px(box);
- }
- if (size.is_percentage()) {
+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())
return 0;
- return available_size.to_px() * size.percentage().as_fraction();
+ auto& calc_value = *size.length().calculated_style_value();
+ return calc_value.resolve_length_percentage(box, CSS::Length::make_px(available_size.to_px())).value_or(CSS::Length::make_auto()).to_px(box);
}
- return 0;
- };
+ return size.length().to_px(box);
+ }
+ if (size.is_length()) {
+ return size.length().to_px(box);
+ }
+ if (size.is_percentage()) {
+ if (!available_size.is_definite())
+ return 0;
+ 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;
+ track_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;
+
+ 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,592 +105,487 @@ 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
-
- 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_columns.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()));
- }
- }
- column_count = 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()));
- }
+ // 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 : 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(), 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(), 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(), 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(), available_space, box), resolve_definite_track_size(track_sizing_function.grid_size(), available_space, box));
}
- row_count = max(1, static_cast<int>(get_free_space_y(box) / sum_of_grid_track_sizes));
+ }
+ return max(1, static_cast<int>(get_free_space_x(available_space) / 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 they’re all empty.)
+ // 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.
+}
- // 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.
+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();
+ int column_end = child_box.computed_values().grid_column_end().raw_value();
+
+ // 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 area’s 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 item’s 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 item’s 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 (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 item’s placement such that the corresponding edge of the grid
+ // item’s 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.
+ int row_span = 1;
+ int column_span = 1;
+ if (child_box.computed_values().grid_row_start().is_position() && child_box.computed_values().grid_row_end().is_span())
+ row_span = child_box.computed_values().grid_row_end().raw_value();
+ if (child_box.computed_values().grid_column_start().is_position() && child_box.computed_values().grid_column_end().is_span())
+ column_span = child_box.computed_values().grid_column_end().raw_value();
+ if (child_box.computed_values().grid_row_end().is_position() && child_box.computed_values().grid_row_start().is_span()) {
+ row_span = child_box.computed_values().grid_row_start().raw_value();
+ row_start = row_end - row_span;
+ }
+ if (child_box.computed_values().grid_column_end().is_position() && child_box.computed_values().grid_column_start().is_span()) {
+ column_span = child_box.computed_values().grid_column_start().raw_value();
+ column_start = column_end - column_span;
+ }
- // 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 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 item’s 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 (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(), 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(), 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())
+ column_start = column_end - column_span;
+ } else {
+ column_end = 2; // FIXME
+ column_start = 1; // FIXME
+ }
+ }
+ 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(), 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(), 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())
+ row_start = row_end - row_span;
+ } else {
+ row_end = 2; // FIXME
+ row_start = 1; // FIXME
+ }
}
- auto occupation_grid = OccupationGrid(column_count, row_count);
- // https://drafts.csswg.org/css-grid/#auto-placement-algo
- // 8.5. Grid Item Placement Algorithm
+ // 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:
- // FIXME: 0. Generate anonymous grid items
+ // 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 (child_box.computed_values().grid_row_start().is_position() && child_box.computed_values().grid_row_end().is_position()) {
+ if (row_start > row_end)
+ swap(row_start, row_end);
+ if (row_start != row_end)
+ row_span = row_end - row_start;
+ }
+ if (child_box.computed_values().grid_column_start().is_position() && child_box.computed_values().grid_column_end().is_position()) {
+ if (column_start > column_end)
+ swap(column_start, column_end);
+ if (column_start != column_end)
+ column_span = column_end - column_start;
+ }
- // 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;
+ // If the placement contains two spans, remove the one contributed by the end grid-placement
+ // property.
+ if (child_box.computed_values().grid_row_start().is_span() && child_box.computed_values().grid_row_end().is_span())
+ row_span = child_box.computed_values().grid_row_start().raw_value();
+ if (child_box.computed_values().grid_column_start().is_span() && child_box.computed_values().grid_column_end().is_span())
+ column_span = child_box.computed_values().grid_column_start().raw_value();
- 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();
- int column_end = child_box.computed_values().grid_column_end().raw_value();
-
- // 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 area’s 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 item’s 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 item’s 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;
- if (column_end < 0)
- column_end = 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 item’s placement such that the corresponding edge of the grid
- // item’s 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.
- int row_span = 1;
- int column_span = 1;
- if (child_box.computed_values().grid_row_start().is_position() && child_box.computed_values().grid_row_end().is_span())
- row_span = child_box.computed_values().grid_row_end().raw_value();
- if (child_box.computed_values().grid_column_start().is_position() && child_box.computed_values().grid_column_end().is_span())
- column_span = child_box.computed_values().grid_column_end().raw_value();
- if (child_box.computed_values().grid_row_end().is_position() && child_box.computed_values().grid_row_start().is_span()) {
- row_span = child_box.computed_values().grid_row_start().raw_value();
- row_start = row_end - row_span;
- }
- if (child_box.computed_values().grid_column_end().is_position() && child_box.computed_values().grid_column_start().is_span()) {
- column_span = child_box.computed_values().grid_column_start().raw_value();
- column_start = column_end - column_span;
- }
+ // FIXME: If the placement contains only a span for a named line, replace it with a span of 1.
- // 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 item’s 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 (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);
- 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);
- if (found_flag_and_index > -1) {
- column_end = 1 + found_flag_and_index;
- if (!child_box.computed_values().grid_column_start().is_position())
- column_start = column_end - column_span;
- } else {
- column_end = 2; // FIXME
- column_start = 1; // FIXME
- }
- }
- 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);
- 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);
- if (found_flag_and_index > -1) {
- row_end = 1 + found_flag_and_index;
- if (!child_box.computed_values().grid_row_start().is_position())
- row_start = row_end - row_span;
- } else {
- row_end = 2; // FIXME
- row_start = 1; // FIXME
- }
- }
+ row_start -= 1;
+ column_start -= 1;
+ m_positioned_boxes.append({ child_box, row_start, row_span, column_start, column_span });
- // 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 (child_box.computed_values().grid_row_start().is_position() && child_box.computed_values().grid_row_end().is_position()) {
- if (row_start > row_end)
- swap(row_start, row_end);
- if (row_start != row_end)
- row_span = row_end - row_start;
- }
- if (child_box.computed_values().grid_column_start().is_position() && child_box.computed_values().grid_column_end().is_position()) {
- if (column_start > column_end)
- swap(column_start, column_end);
- if (column_start != column_end)
- column_span = column_end - column_start;
- }
+ 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);
+}
- // If the placement contains two spans, remove the one contributed by the end grid-placement
- // property.
- if (child_box.computed_values().grid_row_start().is_span() && child_box.computed_values().grid_row_end().is_span())
- row_span = child_box.computed_values().grid_row_start().raw_value();
- if (child_box.computed_values().grid_column_start().is_span() && child_box.computed_values().grid_column_end().is_span())
- column_span = child_box.computed_values().grid_column_start().raw_value();
+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();
+
+ // 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 area’s 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 item’s 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 item’s 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 item’s placement such that the corresponding edge of the grid
+ // item’s 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.
+ int row_span = 1;
+ if (child_box.computed_values().grid_row_start().is_position() && child_box.computed_values().grid_row_end().is_span())
+ row_span = child_box.computed_values().grid_row_end().raw_value();
+ if (child_box.computed_values().grid_row_end().is_position() && child_box.computed_values().grid_row_start().is_span()) {
+ row_span = child_box.computed_values().grid_row_start().raw_value();
+ 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 = 1;
+ }
- // FIXME: If the placement contains only a span for a named line, replace it with a span of 1.
+ // 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 item’s 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 (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(), 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(), 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())
+ row_start = row_end - row_span;
+ } else {
+ row_start = 1; // FIXME
+ row_end = 2; // FIXME
+ }
+ }
- row_start -= 1;
- column_start -= 1;
- positioned_boxes.append({ child_box, row_start, row_span, column_start, column_span });
+ // 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:
- 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--;
+ // 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 (child_box.computed_values().grid_row_start().is_position() && child_box.computed_values().grid_row_end().is_position()) {
+ 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 (!child_box.computed_values().grid_row_start().is_position() && child_box.computed_values().grid_row_end().is_position() && row_end == 1)
+ row_start = 1;
- // 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;
-
- int row_start = child_box.computed_values().grid_row_start().raw_value();
- int row_end = child_box.computed_values().grid_row_end().raw_value();
-
- // 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 area’s 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 item’s 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 item’s 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;
-
- // 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 item’s placement such that the corresponding edge of the grid
- // item’s 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.
- int row_span = 1;
- if (child_box.computed_values().grid_row_start().is_position() && child_box.computed_values().grid_row_end().is_span())
- row_span = child_box.computed_values().grid_row_end().raw_value();
- if (child_box.computed_values().grid_row_end().is_position() && child_box.computed_values().grid_row_start().is_span()) {
- row_span = child_box.computed_values().grid_row_start().raw_value();
- 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 = 1;
- }
+ // If the placement contains two spans, remove the one contributed by the end grid-placement
+ // property.
+ if (child_box.computed_values().grid_row_start().is_span() && child_box.computed_values().grid_row_end().is_span())
+ row_span = child_box.computed_values().grid_row_start().raw_value();
- // 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 item’s 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 (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);
- 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);
- if (found_flag_and_index > -1) {
- row_end = 1 + found_flag_and_index;
- if (!child_box.computed_values().grid_row_start().is_position())
- row_start = row_end - row_span;
- } else {
- row_start = 1; // FIXME
- row_end = 2; // FIXME
- }
- }
+ // FIXME: If the placement contains only a span for a named line, replace it with a span of 1.
- // 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 (child_box.computed_values().grid_row_start().is_position() && child_box.computed_values().grid_row_end().is_position()) {
- 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 (!child_box.computed_values().grid_row_start().is_position() && child_box.computed_values().grid_row_end().is_position() && row_end == 1)
- row_start = 1;
+ row_start -= 1;
+ m_occupation_grid.maybe_add_row(row_start + row_span);
- // If the placement contains two spans, remove the one contributed by the end grid-placement
- // property.
- if (child_box.computed_values().grid_row_start().is_span() && child_box.computed_values().grid_row_end().is_span())
- row_span = child_box.computed_values().grid_row_start().raw_value();
-
- // 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);
-
- 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;
- // https://drafts.csswg.org/css-grid/#auto-placement-algo
- // 8.5. Grid Item Placement Algorithm
- // 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);
- 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)) {
- 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);
+ 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;
+ // https://drafts.csswg.org/css-grid/#auto-placement-algo
+ // 8.5. Grid Item Placement Algorithm
+ // 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.
+ m_occupation_grid.maybe_add_column(column_span);
+ bool found_available_column = false;
+ 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;
}
- 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--;
}
+ if (!found_available_column) {
+ column_start = m_occupation_grid.column_count();
+ 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);
- // 3. Determine the columns in the implicit grid.
- // NOTE: "implicit grid" here is the same as the occupation_grid
+ m_positioned_boxes.append({ child_box, row_start, row_span, column_start, column_span });
+}
- // 3.1. Start with the columns from the explicit grid.
- // NOTE: Done in step 1.
+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();
+
+ // 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 area’s 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 item’s 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 item’s 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 item’s placement such that the corresponding edge of the grid
+ // item’s 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.
+ int column_span = 1;
+ auto row_span = child_box.computed_values().grid_row_start().is_span() ? child_box.computed_values().grid_row_start().raw_value() : 1;
+ if (child_box.computed_values().grid_column_start().is_position() && child_box.computed_values().grid_column_end().is_span())
+ column_span = child_box.computed_values().grid_column_end().raw_value();
+ if (child_box.computed_values().grid_column_end().is_position() && child_box.computed_values().grid_column_start().is_span()) {
+ column_span = child_box.computed_values().grid_column_start().raw_value();
+ 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 = 1;
+ }
+ // FIXME: Have yet to find the spec for this.
+ if (!child_box.computed_values().grid_column_start().is_position() && child_box.computed_values().grid_column_end().is_position() && column_end == 1)
+ column_start = 1;
+
+ // 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 item’s 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 (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(), 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(), 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())
+ column_start = column_end - column_span;
+ } else {
+ column_end = 2; // FIXME
+ column_start = 1; // FIXME
+ }
+ }
- // 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.
+ // 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:
- // 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
+ // 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 (child_box.computed_values().grid_column_start().is_position() && child_box.computed_values().grid_column_end().is_position()) {
+ if (column_start > column_end)
+ swap(column_start, column_end);
+ if (column_start != column_end)
+ column_span = column_end - column_start;
+ }
- // 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())) {
- int column_start = child_box.computed_values().grid_column_start().raw_value();
- int column_end = child_box.computed_values().grid_column_end().raw_value();
-
- // 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 area’s 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 item’s 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 item’s 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;
-
- // 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 item’s placement such that the corresponding edge of the grid
- // item’s 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.
- int column_span = 1;
- auto row_span = child_box.computed_values().grid_row_start().is_span() ? child_box.computed_values().grid_row_start().raw_value() : 1;
- if (child_box.computed_values().grid_column_start().is_position() && child_box.computed_values().grid_column_end().is_span())
- column_span = child_box.computed_values().grid_column_end().raw_value();
- if (child_box.computed_values().grid_column_end().is_position() && child_box.computed_values().grid_column_start().is_span()) {
- column_span = child_box.computed_values().grid_column_start().raw_value();
- 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 = 1;
- }
- // FIXME: Have yet to find the spec for this.
- if (!child_box.computed_values().grid_column_start().is_position() && child_box.computed_values().grid_column_end().is_position() && column_end == 1)
- column_start = 1;
-
- // 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 item’s 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 (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);
- 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);
- if (found_flag_and_index > -1) {
- column_end = 1 + found_flag_and_index;
- if (!child_box.computed_values().grid_column_start().is_position())
- column_start = column_end - column_span;
- } else {
- column_end = 2; // FIXME
- column_start = 1; // FIXME
- }
- }
+ // If the placement contains two spans, remove the one contributed by the end grid-placement
+ // property.
+ if (child_box.computed_values().grid_column_start().is_span() && child_box.computed_values().grid_column_end().is_span())
+ column_span = child_box.computed_values().grid_column_start().raw_value();
- // 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 (child_box.computed_values().grid_column_start().is_position() && child_box.computed_values().grid_column_end().is_position()) {
- if (column_start > column_end)
- swap(column_start, column_end);
- if (column_start != column_end)
- column_span = column_end - column_start;
- }
+ // FIXME: If the placement contains only a span for a named line, replace it with a span of 1.
- // If the placement contains two spans, remove the one contributed by the end grid-placement
- // property.
- if (child_box.computed_values().grid_column_start().is_span() && child_box.computed_values().grid_column_end().is_span())
- column_span = child_box.computed_values().grid_column_start().raw_value();
+ column_start -= 1;
- // 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.
+ if (column_start < auto_placement_cursor_x)
+ auto_placement_cursor_y++;
+ auto_placement_cursor_x = column_start;
- column_start -= 1;
+ 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.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.
- if (column_start < auto_placement_cursor_x)
- auto_placement_cursor_y++;
- auto_placement_cursor_x = column_start;
+ // 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 (!m_occupation_grid.is_occupied(column_start, auto_placement_cursor_y)) {
+ break;
+ }
+ auto_placement_cursor_y++;
+ 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.
+ m_occupation_grid.set_occupied(column_start, column_start + column_span, auto_placement_cursor_y, auto_placement_cursor_y + row_span);
- occupation_grid.maybe_add_column(auto_placement_cursor_x + column_span);
- occupation_grid.maybe_add_row(auto_placement_cursor_y + row_span);
+ m_positioned_boxes.append({ child_box, auto_placement_cursor_y, row_span, column_start, column_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)) {
- break;
+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
+ // algorithm.
+ auto column_start = 0;
+ auto column_span = 1;
+ if (child_box.computed_values().grid_column_start().is_span())
+ column_span = child_box.computed_values().grid_column_start().raw_value();
+ else if (child_box.computed_values().grid_column_end().is_span())
+ column_span = child_box.computed_values().grid_column_end().raw_value();
+ // https://drafts.csswg.org/css-grid/#auto-placement-algo
+ // 8.5. Grid Item Placement Algorithm
+ // 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.
+ 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())
+ row_span = child_box.computed_values().grid_row_start().raw_value();
+ 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 < 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 (m_occupation_grid.is_occupied(column_index + span_index, row_index))
+ found_all_available = false;
}
- auto_placement_cursor_y++;
- 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);
-
- 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 {
- // 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
- // algorithm.
- auto column_start = 0;
- auto column_span = 1;
- if (child_box.computed_values().grid_column_start().is_span())
- column_span = child_box.computed_values().grid_column_start().raw_value();
- else if (child_box.computed_values().grid_column_end().is_span())
- column_span = child_box.computed_values().grid_column_end().raw_value();
- // https://drafts.csswg.org/css-grid/#auto-placement-algo
- // 8.5. Grid Item Placement Algorithm
- // 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);
- auto row_start = 0;
- auto row_span = 1;
- if (child_box.computed_values().grid_row_start().is_span())
- row_span = child_box.computed_values().grid_row_start().raw_value();
- 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()) {
- 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))
- found_all_available = false;
- }
- if (found_all_available) {
- found_unoccupied_area = true;
- column_start = column_index;
- row_start = row_index;
- goto finish;
- }
- }
+ if (found_all_available) {
+ found_unoccupied_area = true;
+ column_start = column_index;
+ row_start = row_index;
+ goto finish;
}
- auto_placement_cursor_x = 0;
- auto_placement_cursor_y++;
- }
- 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);
}
-
- 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--;
-
- // FIXME: 4.2. For dense packing:
+ auto_placement_cursor_x = 0;
+ auto_placement_cursor_y++;
+ }
+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 = m_occupation_grid.row_count();
+ m_occupation_grid.maybe_add_row(m_occupation_grid.row_count() + 1);
}
- // 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>).
+ 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 });
+}
- // 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 container’s 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 grid’s 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 grid’s 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 track’s 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 track’s 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 they’re 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 container’s 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 grid’s 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 container’s 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 track’s 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 track’s 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 container’s 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 grid’s 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 grid’s 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 track’s 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 container’s 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 grid’s 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 container’s 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 track’s 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())
diff --git a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h
index ca6539e77b..b70b819adc 100644
--- a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h
+++ b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h
@@ -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);
-};
-
-class OccupationGrid {
-public:
- OccupationGrid(int column_count, int row_count);
-
- 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;
+ 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&);
+
+ 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 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&);
};
}