From 0dec2dc21c3866384c9bf7b55cf330bc9f9efbc9 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Thu, 10 Oct 2024 23:35:44 +0200 Subject: [PATCH] LibWeb: Improve grid area calculation for abspos items in GFC - Add support for placement of abspos items into track formed by last line and padding edge of grid container - Correctly handle auto-positioned abspos items by placing them between padding edges of grid container Fixes crashing on https://wpt.live/css/css-grid/abspos/positioned-grid-descendants-001.html --- ...s-placed-into-augmented-row-and-column.txt | 50 +++++ ...th-auto-column-placed-in-augmented-row.txt | 50 +++++ ...-auto-row-and-column-contained-by-grid.txt | 50 +++++ ...th-auto-row-placed-in-augmented-column.txt | 50 +++++ ...-placed-into-augmented-row-and-column.html | 35 +++ ...h-auto-column-placed-in-augmented-row.html | 34 +++ ...auto-row-and-column-contained-by-grid.html | 33 +++ ...h-auto-row-placed-in-augmented-column.html | 34 +++ .../LibWeb/Layout/GridFormattingContext.cpp | 204 +++++++++++------- .../LibWeb/Layout/GridFormattingContext.h | 18 +- 10 files changed, 473 insertions(+), 85 deletions(-) create mode 100644 Tests/LibWeb/Layout/expected/grid/abspos-placed-into-augmented-row-and-column.txt create mode 100644 Tests/LibWeb/Layout/expected/grid/abspos-with-auto-column-placed-in-augmented-row.txt create mode 100644 Tests/LibWeb/Layout/expected/grid/abspos-with-auto-row-and-column-contained-by-grid.txt create mode 100644 Tests/LibWeb/Layout/expected/grid/abspos-with-auto-row-placed-in-augmented-column.txt create mode 100644 Tests/LibWeb/Layout/input/grid/abspos-placed-into-augmented-row-and-column.html create mode 100644 Tests/LibWeb/Layout/input/grid/abspos-with-auto-column-placed-in-augmented-row.html create mode 100644 Tests/LibWeb/Layout/input/grid/abspos-with-auto-row-and-column-contained-by-grid.html create mode 100644 Tests/LibWeb/Layout/input/grid/abspos-with-auto-row-placed-in-augmented-column.html diff --git a/Tests/LibWeb/Layout/expected/grid/abspos-placed-into-augmented-row-and-column.txt b/Tests/LibWeb/Layout/expected/grid/abspos-placed-into-augmented-row-and-column.txt new file mode 100644 index 00000000000..b8e12bec817 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/grid/abspos-placed-into-augmented-row-and-column.txt @@ -0,0 +1,50 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x286 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x270 children: not-inline + Box at (58,58) content-size 170x170 positioned [GFC] children: not-inline + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (58,58) content-size 50x50 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [58,58 6.34375x17] baseline: 13.296875 + "1" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (128,58) content-size 100x50 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [128,58 8.8125x17] baseline: 13.296875 + "2" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (58,128) content-size 50x100 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [58,128 9.09375x17] baseline: 13.296875 + "3" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (128,128) content-size 100x100 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [128,128 7.75x17] baseline: 13.296875 + "4" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (228,228) content-size 50x50 positioned [BFC] children: not-inline + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (8,278) content-size 784x0 children: inline + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x286] + PaintableWithLines (BlockContainer) [8,8 784x270] + PaintableBox (Box
.grid-container) [8,8 270x270] + PaintableWithLines (BlockContainer
.grid-item) [58,58 50x50] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.grid-item) [128,58 100x50] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.grid-item) [58,128 50x100] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.grid-item) [128,128 100x100] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.abspos-box) [228,228 50x50] + PaintableWithLines (BlockContainer(anonymous)) [8,278 784x0] diff --git a/Tests/LibWeb/Layout/expected/grid/abspos-with-auto-column-placed-in-augmented-row.txt b/Tests/LibWeb/Layout/expected/grid/abspos-with-auto-column-placed-in-augmented-row.txt new file mode 100644 index 00000000000..f9f92c86861 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/grid/abspos-with-auto-column-placed-in-augmented-row.txt @@ -0,0 +1,50 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x286 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x270 children: not-inline + Box at (58,58) content-size 170x170 positioned [GFC] children: not-inline + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (58,58) content-size 50x50 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [58,58 6.34375x17] baseline: 13.296875 + "1" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (128,58) content-size 100x50 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [128,58 8.8125x17] baseline: 13.296875 + "2" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (58,128) content-size 50x100 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [58,128 9.09375x17] baseline: 13.296875 + "3" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (128,128) content-size 100x100 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [128,128 7.75x17] baseline: 13.296875 + "4" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (8,228) content-size 270x50 positioned [BFC] children: not-inline + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (8,278) content-size 784x0 children: inline + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x286] + PaintableWithLines (BlockContainer) [8,8 784x270] + PaintableBox (Box
.grid-container) [8,8 270x270] + PaintableWithLines (BlockContainer
.grid-item) [58,58 50x50] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.grid-item) [128,58 100x50] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.grid-item) [58,128 50x100] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.grid-item) [128,128 100x100] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.abspos-box) [8,228 270x50] + PaintableWithLines (BlockContainer(anonymous)) [8,278 784x0] diff --git a/Tests/LibWeb/Layout/expected/grid/abspos-with-auto-row-and-column-contained-by-grid.txt b/Tests/LibWeb/Layout/expected/grid/abspos-with-auto-row-and-column-contained-by-grid.txt new file mode 100644 index 00000000000..7b7aa42316e --- /dev/null +++ b/Tests/LibWeb/Layout/expected/grid/abspos-with-auto-row-and-column-contained-by-grid.txt @@ -0,0 +1,50 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x286 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x270 children: not-inline + Box at (58,58) content-size 170x170 positioned [GFC] children: not-inline + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (58,58) content-size 50x50 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [58,58 6.34375x17] baseline: 13.296875 + "1" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (128,58) content-size 100x50 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [128,58 8.8125x17] baseline: 13.296875 + "2" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (58,128) content-size 50x100 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [58,128 9.09375x17] baseline: 13.296875 + "3" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (128,128) content-size 100x100 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [128,128 7.75x17] baseline: 13.296875 + "4" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (8,8) content-size 270x270 positioned [BFC] children: not-inline + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (8,278) content-size 784x0 children: inline + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x286] + PaintableWithLines (BlockContainer) [8,8 784x270] + PaintableBox (Box
.grid-container) [8,8 270x270] + PaintableWithLines (BlockContainer
.grid-item) [58,58 50x50] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.grid-item) [128,58 100x50] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.grid-item) [58,128 50x100] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.grid-item) [128,128 100x100] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.abspos-box) [8,8 270x270] + PaintableWithLines (BlockContainer(anonymous)) [8,278 784x0] diff --git a/Tests/LibWeb/Layout/expected/grid/abspos-with-auto-row-placed-in-augmented-column.txt b/Tests/LibWeb/Layout/expected/grid/abspos-with-auto-row-placed-in-augmented-column.txt new file mode 100644 index 00000000000..34fbe35b395 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/grid/abspos-with-auto-row-placed-in-augmented-column.txt @@ -0,0 +1,50 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x286 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x270 children: not-inline + Box at (58,58) content-size 170x170 positioned [GFC] children: not-inline + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (58,58) content-size 50x50 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [58,58 6.34375x17] baseline: 13.296875 + "1" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (128,58) content-size 100x50 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [128,58 8.8125x17] baseline: 13.296875 + "2" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (58,128) content-size 50x100 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [58,128 9.09375x17] baseline: 13.296875 + "3" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (128,128) content-size 100x100 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [128,128 7.75x17] baseline: 13.296875 + "4" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (228,8) content-size 50x270 positioned [BFC] children: not-inline + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (8,278) content-size 784x0 children: inline + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x286] + PaintableWithLines (BlockContainer) [8,8 784x270] + PaintableBox (Box
.grid-container) [8,8 270x270] + PaintableWithLines (BlockContainer
.grid-item) [58,58 50x50] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.grid-item) [128,58 100x50] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.grid-item) [58,128 50x100] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.grid-item) [128,128 100x100] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.abspos-box) [228,8 50x270] + PaintableWithLines (BlockContainer(anonymous)) [8,278 784x0] diff --git a/Tests/LibWeb/Layout/input/grid/abspos-placed-into-augmented-row-and-column.html b/Tests/LibWeb/Layout/input/grid/abspos-placed-into-augmented-row-and-column.html new file mode 100644 index 00000000000..6013a58414f --- /dev/null +++ b/Tests/LibWeb/Layout/input/grid/abspos-placed-into-augmented-row-and-column.html @@ -0,0 +1,35 @@ + + +
+
1
+
2
+
3
+
4
+
+
diff --git a/Tests/LibWeb/Layout/input/grid/abspos-with-auto-column-placed-in-augmented-row.html b/Tests/LibWeb/Layout/input/grid/abspos-with-auto-column-placed-in-augmented-row.html new file mode 100644 index 00000000000..d1745936f66 --- /dev/null +++ b/Tests/LibWeb/Layout/input/grid/abspos-with-auto-column-placed-in-augmented-row.html @@ -0,0 +1,34 @@ + + +
+
1
+
2
+
3
+
4
+
+
diff --git a/Tests/LibWeb/Layout/input/grid/abspos-with-auto-row-and-column-contained-by-grid.html b/Tests/LibWeb/Layout/input/grid/abspos-with-auto-row-and-column-contained-by-grid.html new file mode 100644 index 00000000000..b933c343a47 --- /dev/null +++ b/Tests/LibWeb/Layout/input/grid/abspos-with-auto-row-and-column-contained-by-grid.html @@ -0,0 +1,33 @@ + + +
+
1
+
2
+
3
+
4
+
+
diff --git a/Tests/LibWeb/Layout/input/grid/abspos-with-auto-row-placed-in-augmented-column.html b/Tests/LibWeb/Layout/input/grid/abspos-with-auto-row-placed-in-augmented-column.html new file mode 100644 index 00000000000..d85ceff782a --- /dev/null +++ b/Tests/LibWeb/Layout/input/grid/abspos-with-auto-row-placed-in-augmented-column.html @@ -0,0 +1,34 @@ + + +
+
1
+
2
+
3
+
4
+
+
diff --git a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp index 48a173242ad..e2016f0390e 100644 --- a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp @@ -464,7 +464,7 @@ void GridFormattingContext::place_item_with_no_declared_position(Box const& chil void GridFormattingContext::record_grid_placement(GridItem grid_item) { - m_occupation_grid.set_occupied(grid_item.column, grid_item.column + grid_item.column_span, grid_item.row, grid_item.row + grid_item.row_span); + m_occupation_grid.set_occupied(grid_item.column.value(), grid_item.column.value() + grid_item.column_span.value(), grid_item.row.value(), grid_item.row.value() + grid_item.row_span.value()); m_grid_items.append(grid_item); } @@ -1445,8 +1445,8 @@ void GridFormattingContext::place_grid_items() // NOTE: When final implicit grid sizes are known, we can offset their positions so leftmost grid track has 0 index. for (auto& item : m_grid_items) { - item.row = item.row - m_occupation_grid.min_row_index(); - item.column = item.column - m_occupation_grid.min_column_index(); + item.row = item.row.value() - m_occupation_grid.min_row_index(); + item.column = item.column.value() - m_occupation_grid.min_column_index(); } } @@ -1833,73 +1833,121 @@ void GridFormattingContext::collapse_auto_fit_tracks_if_needed(GridDimension con CSSPixelRect GridFormattingContext::get_grid_area_rect(GridItem const& grid_item) const { - auto resolved_row_span = grid_item.row_span * 2; - if (grid_item.gap_adjusted_row() + resolved_row_span > m_grid_rows_and_gaps.size()) - resolved_row_span = m_grid_rows_and_gaps.size() - grid_item.gap_adjusted_row(); + CSSPixelRect area_rect; - auto resolved_column_span = grid_item.column_span * 2; - if (grid_item.gap_adjusted_column() + resolved_column_span > m_grid_columns_and_gaps.size()) - resolved_column_span = m_grid_columns_and_gaps.size() - grid_item.gap_adjusted_column(); + auto place_into_track = [&](GridDimension const dimension) { + auto const& tracks_and_gaps = dimension == GridDimension::Column ? m_grid_columns_and_gaps : m_grid_rows_and_gaps; - int row_start = grid_item.gap_adjusted_row(); - int row_end = row_start + resolved_row_span; - int column_start = grid_item.gap_adjusted_column(); - int column_end = column_start + resolved_column_span; + auto resolved_span = grid_item.span(dimension) * 2; + auto gap_adjusted_position = grid_item.gap_adjusted_position(dimension); + if (gap_adjusted_position + resolved_span > tracks_and_gaps.size()) { + resolved_span = tracks_and_gaps.size() - gap_adjusted_position; + } - auto grid_container_width = m_available_space->width.to_px_or_zero(); - CSSPixels sum_base_size_of_columns_and_gaps = 0; - CSSPixels sum_base_size_of_columns = 0; - for (auto const& col_track : m_grid_columns_and_gaps) { - if (!col_track.is_gap) - sum_base_size_of_columns += col_track.base_size; - sum_base_size_of_columns_and_gaps += col_track.base_size; - } - auto const& justify_content = grid_container().computed_values().justify_content(); + int start = gap_adjusted_position; + int end = start + resolved_span; + VERIFY(start <= end); - CSSPixels x_start = 0; - CSSPixels x_end = 0; - if (justify_content == CSS::JustifyContent::Center || justify_content == CSS::JustifyContent::SpaceAround || justify_content == CSS::JustifyContent::SpaceEvenly) { - auto free_space = grid_container_width - sum_base_size_of_columns_and_gaps; - free_space = max(free_space, 0); - x_start = free_space / 2; - x_end = free_space / 2; - } else if (justify_content == CSS::JustifyContent::End || justify_content == CSS::JustifyContent::Right) { - auto free_space = grid_container_width - sum_base_size_of_columns_and_gaps; - x_start = free_space; - x_end = free_space; + auto grid_container_size = dimension == GridDimension::Column ? m_available_space->width : m_available_space->height; + + CSSPixels sum_of_base_sizes_including_gaps = 0; + for (auto const& track : tracks_and_gaps) { + sum_of_base_sizes_including_gaps += track.base_size; + } + + Alignment alignment; + if (dimension == GridDimension::Column) { + alignment = to_alignment(grid_container().computed_values().justify_content()); + } else { + alignment = to_alignment(grid_container().computed_values().align_content()); + } + CSSPixels start_offset = 0; + CSSPixels end_offset = 0; + if (alignment == Alignment::Center || alignment == Alignment::SpaceAround || alignment == Alignment::SpaceEvenly) { + auto free_space = grid_container_size.to_px_or_zero() - sum_of_base_sizes_including_gaps; + free_space = max(free_space, 0); + start_offset = free_space / 2; + end_offset = free_space / 2; + } else if (alignment == Alignment::End) { + auto free_space = grid_container_size.to_px_or_zero() - sum_of_base_sizes_including_gaps; + start_offset = free_space; + end_offset = free_space; + } + + for (int i = 0; i < min(start, tracks_and_gaps.size()); i++) + start_offset += tracks_and_gaps[i].base_size; + for (int i = 0; i < min(end, tracks_and_gaps.size()); i++) { + end_offset += tracks_and_gaps[i].base_size; + } + + if (dimension == GridDimension::Column) { + area_rect.set_x(start_offset); + area_rect.set_width(end_offset - start_offset); + } else { + area_rect.set_y(start_offset); + area_rect.set_height(end_offset - start_offset); + } + }; + + auto place_into_track_formed_by_last_line_and_grid_container_padding_edge = [&](GridDimension const dimension) { + VERIFY(grid_item.box->is_absolutely_positioned()); + auto const& tracks_and_gaps = dimension == GridDimension::Column ? m_grid_columns_and_gaps : m_grid_rows_and_gaps; + auto const& grid_container_state = m_state.get(grid_container()); + CSSPixels offset = 0; + for (auto const& row_track : tracks_and_gaps) { + offset += row_track.base_size; + } + CSSPixels size = dimension == GridDimension::Column ? grid_container_state.padding_right : grid_container_state.padding_bottom; + if (dimension == GridDimension::Column) { + area_rect.set_x(offset); + area_rect.set_width(size); + } else { + area_rect.set_y(offset); + area_rect.set_height(size); + } + }; + + if (grid_item.row.has_value()) { + if (grid_item.row == (int)m_grid_rows.size()) { + place_into_track_formed_by_last_line_and_grid_container_padding_edge(GridDimension::Row); + } else { + place_into_track(GridDimension::Row); + } + } else { + // https://www.w3.org/TR/css-grid-2/#abspos-items + // Instead of auto-placement, an auto value for a grid-placement property contributes a special line to the placement whose position + // is that of the corresponding padding edge of the grid container (the padding edge of the scrollable area, if the grid container + // overflows). These lines become the first and last lines (0th and -0th) of the augmented grid used for positioning absolutely-positioned items. + CSSPixels height = 0; + for (auto const& row_track : m_grid_rows_and_gaps) { + height += row_track.base_size; + } + auto const& grid_container_state = m_state.get(grid_container()); + height += grid_container_state.padding_top; + height += grid_container_state.padding_bottom; + area_rect.set_height(height); + area_rect.set_y(-grid_container_state.padding_top); } - auto grid_container_height = m_available_space->height.to_px_or_zero(); - CSSPixels sum_base_size_of_rows_and_gaps = 0; - for (auto const& row_track : m_grid_rows_and_gaps) { - sum_base_size_of_rows_and_gaps += row_track.base_size; - } - auto const& align_content = grid_container().computed_values().align_content(); - - CSSPixels y_start = 0; - CSSPixels y_end = 0; - if (align_content == CSS::AlignContent::Center || align_content == CSS::AlignContent::SpaceAround || align_content == CSS::AlignContent::SpaceEvenly) { - auto free_space = grid_container_height - sum_base_size_of_rows_and_gaps; - free_space = max(free_space, 0); - y_start = free_space / 2; - y_end = free_space / 2; - } else if (align_content == CSS::AlignContent::End || align_content == CSS::AlignContent::FlexEnd) { - auto free_space = grid_container_height - sum_base_size_of_rows_and_gaps; - y_start = free_space; - y_end = free_space; + if (grid_item.column.has_value()) { + if (grid_item.column == (int)m_grid_columns.size()) { + place_into_track_formed_by_last_line_and_grid_container_padding_edge(GridDimension::Column); + } else { + place_into_track(GridDimension::Column); + } + } else { + CSSPixels width = 0; + for (auto const& col_track : m_grid_columns_and_gaps) { + width += col_track.base_size; + } + auto const& grid_container_state = m_state.get(grid_container()); + width += grid_container_state.padding_left; + width += grid_container_state.padding_right; + area_rect.set_width(width); + area_rect.set_x(-grid_container_state.padding_left); } - for (int i = 0; i < column_start; i++) - x_start += m_grid_columns_and_gaps[i].base_size; - for (int i = 0; i < column_end; i++) - x_end += m_grid_columns_and_gaps[i].base_size; - for (int i = 0; i < row_start; i++) - y_start += m_grid_rows_and_gaps[i].base_size; - for (int i = 0; i < row_end; i++) { - y_end += m_grid_rows_and_gaps[i].base_size; - } - - return { x_start, y_start, x_end - x_start, y_end - y_start }; + return area_rect; } void GridFormattingContext::run(AvailableSpace const& available_space) @@ -2037,17 +2085,21 @@ void GridFormattingContext::layout_absolutely_positioned_element(Box const& box) auto& box_state = m_state.get_mutable(box); auto const& computed_values = box.computed_values(); - auto is_auto_positioned = is_auto_positioned_track(computed_values.grid_row_start(), computed_values.grid_row_end()) || is_auto_positioned_track(computed_values.grid_column_start(), computed_values.grid_column_end()); + auto is_auto_row = is_auto_positioned_track(computed_values.grid_row_start(), computed_values.grid_row_end()); + auto is_auto_column = is_auto_positioned_track(computed_values.grid_column_start(), computed_values.grid_column_end()); - auto row_placement_position = resolve_grid_position(box, GridDimension::Row); - auto column_placement_position = resolve_grid_position(box, GridDimension::Column); + GridItem item { box, {}, {}, {}, {} }; + if (!is_auto_row) { + auto row_placement_position = resolve_grid_position(box, GridDimension::Row); + item.row = row_placement_position.start; + item.row_span = row_placement_position.span; + } + if (!is_auto_column) { + auto column_placement_position = resolve_grid_position(box, GridDimension::Column); + item.column = column_placement_position.start; + item.column_span = column_placement_position.span; + } - auto row_start = row_placement_position.start; - auto row_span = row_placement_position.span; - auto column_start = column_placement_position.start; - auto column_span = column_placement_position.span; - - GridItem item { box, row_start, row_span, column_start, column_span }; auto grid_area_rect = get_grid_area_rect(item); auto available_width = AvailableSize::make_definite(grid_area_rect.width()); auto available_height = AvailableSize::make_definite(grid_area_rect.height()); @@ -2136,12 +2188,6 @@ void GridFormattingContext::layout_absolutely_positioned_element(Box const& box) used_offset.set_x(grid_area_rect.x() + box_state.inset_left + box_state.margin_box_left()); used_offset.set_y(grid_area_rect.y() + box_state.inset_top + box_state.margin_box_top()); - // NOTE: Absolutely positioned boxes with auto-placement are relative to the *padding edge* of the containing block. - if (is_auto_positioned) { - auto const& containing_block_state = m_state.get_mutable(*box.containing_block()); - used_offset.translate_by(-containing_block_state.padding_left, -containing_block_state.padding_top); - } - box_state.set_content_offset(used_offset); if (independent_formatting_context) @@ -2291,12 +2337,12 @@ bool OccupationGrid::is_occupied(int column_index, int row_index) const int GridItem::gap_adjusted_row() const { - return row * 2; + return row.value() * 2; } int GridItem::gap_adjusted_column() const { - return column * 2; + return column.value() * 2; } CSSPixels GridFormattingContext::calculate_grid_container_maximum_size(GridDimension const dimension) const diff --git a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h index 3c4643f8405..8e876974d9f 100644 --- a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h @@ -37,19 +37,20 @@ struct GridPosition { struct GridItem { JS::NonnullGCPtr box; - int row; - size_t row_span; - int column; - size_t column_span; + // Position and span are empty if the item is auto-placed which could only be the case for abspos items + Optional row; + Optional row_span; + Optional column; + Optional column_span; [[nodiscard]] size_t span(GridDimension const dimension) const { - return dimension == GridDimension::Column ? column_span : row_span; + return dimension == GridDimension::Column ? column_span.value() : row_span.value(); } [[nodiscard]] int raw_position(GridDimension const dimension) const { - return dimension == GridDimension::Column ? column : row; + return dimension == GridDimension::Column ? column.value() : row.value(); } [[nodiscard]] CSSPixels add_margin_box_sizes(CSSPixels content_size, GridDimension dimension, LayoutState const& state) const @@ -60,6 +61,11 @@ struct GridItem { return box_state.margin_box_top() + content_size + box_state.margin_box_bottom(); } + [[nodiscard]] int gap_adjusted_position(GridDimension const dimension) const + { + return dimension == GridDimension::Column ? gap_adjusted_column() : gap_adjusted_row(); + } + [[nodiscard]] int gap_adjusted_row() const; [[nodiscard]] int gap_adjusted_column() const; };