From 852e8ff12ff377bbb62e415c0bd7fcafea6ef177 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Tue, 11 Mar 2025 23:03:06 +0100 Subject: [PATCH] LibWeb: Fix grid placement with named lines --- .../LibWeb/Layout/GridFormattingContext.cpp | 34 ++++++++---- .../LibWeb/Layout/GridFormattingContext.h | 2 +- ...acement-named-lines-with-span-negative.txt | 30 +++++++++++ ...-based-placement-named-lines-with-span.txt | 54 +++++++++++++++++++ .../expected/grid/line-based-with-repeat.txt | 54 +++++++++++++++++++ ...cement-named-lines-with-span-negative.html | 27 ++++++++++ ...based-placement-named-lines-with-span.html | 44 +++++++++++++++ .../input/grid/line-based-with-repeat.html | 44 +++++++++++++++ 8 files changed, 277 insertions(+), 12 deletions(-) create mode 100644 Tests/LibWeb/Layout/expected/grid/line-based-placement-named-lines-with-span-negative.txt create mode 100644 Tests/LibWeb/Layout/expected/grid/line-based-placement-named-lines-with-span.txt create mode 100644 Tests/LibWeb/Layout/expected/grid/line-based-with-repeat.txt create mode 100644 Tests/LibWeb/Layout/input/grid/line-based-placement-named-lines-with-span-negative.html create mode 100644 Tests/LibWeb/Layout/input/grid/line-based-placement-named-lines-with-span.html create mode 100644 Tests/LibWeb/Layout/input/grid/line-based-with-repeat.html diff --git a/Libraries/LibWeb/Layout/GridFormattingContext.cpp b/Libraries/LibWeb/Layout/GridFormattingContext.cpp index 6c951ca2940..a1b5aabcbad 100644 --- a/Libraries/LibWeb/Layout/GridFormattingContext.cpp +++ b/Libraries/LibWeb/Layout/GridFormattingContext.cpp @@ -316,9 +316,9 @@ GridFormattingContext::PlacementPosition GridFormattingContext::resolve_grid_pos result.end = m_occupation_grid.column_count() + result.end + 2; } - if (placement_start.has_line_number() && placement_end.is_span()) + if (placement_end.is_span()) result.span = placement_end.span(); - if (placement_end.has_line_number() && placement_start.is_span()) { + if (placement_start.is_span()) { result.span = placement_start.span(); result.start = result.end - result.span; // FIXME: Remove me once have implemented spans overflowing into negative indexes, e.g., grid-row: span 2 / 1 @@ -328,9 +328,10 @@ GridFormattingContext::PlacementPosition GridFormattingContext::resolve_grid_pos if (placement_end.has_identifier()) { auto area_end_line_name = MUST(String::formatted("{}-end", placement_end.identifier())); - if (auto area_end_line_index = get_line_index_by_line_name(dimension, area_end_line_name); area_end_line_index.has_value()) { + auto line_number = placement_end.has_line_number() ? placement_end.line_number() : 1; + if (auto area_end_line_index = get_nth_line_index_by_line_name(dimension, area_end_line_name, line_number); area_end_line_index.has_value()) { result.end = area_end_line_index.value(); - } else if (auto line_name_index = get_line_index_by_line_name(dimension, placement_end.identifier()); line_name_index.has_value()) { + } else if (auto line_name_index = get_nth_line_index_by_line_name(dimension, placement_end.identifier(), line_number); line_name_index.has_value()) { result.end = line_name_index.value(); } else { result.end = 1; @@ -340,9 +341,10 @@ GridFormattingContext::PlacementPosition GridFormattingContext::resolve_grid_pos if (placement_start.has_identifier()) { auto area_start_line_name = MUST(String::formatted("{}-start", placement_start.identifier())); - if (auto area_start_line_index = get_line_index_by_line_name(dimension, area_start_line_name); area_start_line_index.has_value()) { + auto line_number = placement_start.has_line_number() ? placement_start.line_number() : 1; + if (auto area_start_line_index = get_nth_line_index_by_line_name(dimension, area_start_line_name, line_number); area_start_line_index.has_value()) { result.start = area_start_line_index.value(); - } else if (auto line_name_index = get_line_index_by_line_name(dimension, placement_start.identifier()); line_name_index.has_value()) { + } else if (auto line_name_index = get_nth_line_index_by_line_name(dimension, placement_start.identifier(), line_number); line_name_index.has_value()) { result.start = line_name_index.value(); } else { result.start = 0; @@ -2266,13 +2268,23 @@ AvailableSize GridFormattingContext::get_free_space(AvailableSpace const& availa return available_size; } -Optional GridFormattingContext::get_line_index_by_line_name(GridDimension dimension, String const& line_name) +Optional GridFormattingContext::get_nth_line_index_by_line_name(GridDimension dimension, String const& line_name, int nth_line) { auto const& lines = dimension == GridDimension::Column ? m_column_lines : m_row_lines; - for (size_t line_index = 0; line_index < lines.size(); line_index++) { - for (auto const& name : lines[line_index].names) { - if (name == line_name) - return static_cast(line_index); + size_t line_index = nth_line < 0 ? lines.size() + nth_line : nth_line - 1; + // FIXME: If not enough lines with the 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. + // Source: https://drafts.csswg.org/css-grid/#line-placement + for (size_t actual_line_index = 0; actual_line_index < lines.size(); actual_line_index++) { + for (auto const& name : lines[actual_line_index].names) { + if (name == line_name) { + // https://drafts.csswg.org/css-grid/#line-placement + // Contributes the nth grid line to the grid item’s placement. + if (line_index == 0) + return static_cast(actual_line_index); + else + line_index--; + } } } return {}; diff --git a/Libraries/LibWeb/Layout/GridFormattingContext.h b/Libraries/LibWeb/Layout/GridFormattingContext.h index 16f6a2dc486..814c6580f2d 100644 --- a/Libraries/LibWeb/Layout/GridFormattingContext.h +++ b/Libraries/LibWeb/Layout/GridFormattingContext.h @@ -328,7 +328,7 @@ private: AvailableSize get_free_space(AvailableSpace const&, GridDimension) const; - Optional get_line_index_by_line_name(GridDimension dimension, String const&); + Optional get_nth_line_index_by_line_name(GridDimension dimension, String const&, int line_number); CSSPixels resolve_definite_track_size(CSS::GridSize const&, AvailableSpace const&); int count_of_repeated_auto_fill_or_fit_tracks(GridDimension, CSS::ExplicitGridTrack const& repeated_track); diff --git a/Tests/LibWeb/Layout/expected/grid/line-based-placement-named-lines-with-span-negative.txt b/Tests/LibWeb/Layout/expected/grid/line-based-placement-named-lines-with-span-negative.txt new file mode 100644 index 00000000000..9905ae4a61d --- /dev/null +++ b/Tests/LibWeb/Layout/expected/grid/line-based-placement-named-lines-with-span-negative.txt @@ -0,0 +1,30 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x168 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x152 children: not-inline + BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline + TextNode <#text> + Box at (8,8) content-size 784x152 [GFC] children: not-inline + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (28,38) content-size 60x26 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [28,38 21.40625x26] baseline: 20.1875 + "A" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (28,114) content-size 60x26 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [28,114 14.015625x26] baseline: 20.1875 + "B" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x168] + PaintableWithLines (BlockContainer) [8,8 784x152] + PaintableWithLines (BlockContainer(anonymous)) [8,8 784x0] + PaintableBox (Box
.wrapper) [8,8 784x152] + PaintableWithLines (BlockContainer
.box.a) [8,18 100x66] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.box.b) [8,94 100x66] + TextPaintable (TextNode<#text>) diff --git a/Tests/LibWeb/Layout/expected/grid/line-based-placement-named-lines-with-span.txt b/Tests/LibWeb/Layout/expected/grid/line-based-placement-named-lines-with-span.txt new file mode 100644 index 00000000000..4ac9b26dcca --- /dev/null +++ b/Tests/LibWeb/Layout/expected/grid/line-based-placement-named-lines-with-span.txt @@ -0,0 +1,54 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x234 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x218 children: not-inline + BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline + TextNode <#text> + Box at (8,8) content-size 784x218 [GFC] children: not-inline + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (28,28) content-size 170x26 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [28,28 21.40625x26] baseline: 20.1875 + "A" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (248,28) content-size 170x26 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [248,28 14.015625x26] baseline: 20.1875 + "B" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (28,104) content-size 60x26 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [28,104 15.46875x26] baseline: 20.1875 + "C" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (138,104) content-size 280x26 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [138,104 16.71875x26] baseline: 20.1875 + "D" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (28,180) content-size 390x26 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [28,180 17.796875x26] baseline: 20.1875 + "E" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x234] + PaintableWithLines (BlockContainer) [8,8 784x218] + PaintableWithLines (BlockContainer(anonymous)) [8,8 784x0] + PaintableBox (Box
.wrapper) [8,8 784x218] + PaintableWithLines (BlockContainer
.box.a) [8,8 210x66] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.box.b) [228,8 210x66] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.box.c) [8,84 100x66] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.box.d) [118,84 320x66] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.box.e) [8,160 430x66] + TextPaintable (TextNode<#text>) diff --git a/Tests/LibWeb/Layout/expected/grid/line-based-with-repeat.txt b/Tests/LibWeb/Layout/expected/grid/line-based-with-repeat.txt new file mode 100644 index 00000000000..4ac9b26dcca --- /dev/null +++ b/Tests/LibWeb/Layout/expected/grid/line-based-with-repeat.txt @@ -0,0 +1,54 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x234 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x218 children: not-inline + BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline + TextNode <#text> + Box at (8,8) content-size 784x218 [GFC] children: not-inline + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (28,28) content-size 170x26 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [28,28 21.40625x26] baseline: 20.1875 + "A" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (248,28) content-size 170x26 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [248,28 14.015625x26] baseline: 20.1875 + "B" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (28,104) content-size 60x26 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [28,104 15.46875x26] baseline: 20.1875 + "C" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (138,104) content-size 280x26 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [138,104 16.71875x26] baseline: 20.1875 + "D" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + BlockContainer at (28,180) content-size 390x26 [BFC] children: inline + frag 0 from TextNode start: 0, length: 1, rect: [28,180 17.796875x26] baseline: 20.1875 + "E" + TextNode <#text> + BlockContainer <(anonymous)> (not painted) [BFC] children: inline + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x234] + PaintableWithLines (BlockContainer) [8,8 784x218] + PaintableWithLines (BlockContainer(anonymous)) [8,8 784x0] + PaintableBox (Box
.wrapper) [8,8 784x218] + PaintableWithLines (BlockContainer
.box.a) [8,8 210x66] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.box.b) [228,8 210x66] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.box.c) [8,84 100x66] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.box.d) [118,84 320x66] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer
.box.e) [8,160 430x66] + TextPaintable (TextNode<#text>) diff --git a/Tests/LibWeb/Layout/input/grid/line-based-placement-named-lines-with-span-negative.html b/Tests/LibWeb/Layout/input/grid/line-based-placement-named-lines-with-span-negative.html new file mode 100644 index 00000000000..a697b554dbc --- /dev/null +++ b/Tests/LibWeb/Layout/input/grid/line-based-placement-named-lines-with-span-negative.html @@ -0,0 +1,27 @@ + + +
+
A
+
B
diff --git a/Tests/LibWeb/Layout/input/grid/line-based-placement-named-lines-with-span.html b/Tests/LibWeb/Layout/input/grid/line-based-placement-named-lines-with-span.html new file mode 100644 index 00000000000..fdfad15fa0c --- /dev/null +++ b/Tests/LibWeb/Layout/input/grid/line-based-placement-named-lines-with-span.html @@ -0,0 +1,44 @@ + + +
+
A
+
B
+
C
+
D
+
E
diff --git a/Tests/LibWeb/Layout/input/grid/line-based-with-repeat.html b/Tests/LibWeb/Layout/input/grid/line-based-with-repeat.html new file mode 100644 index 00000000000..020d68eb30c --- /dev/null +++ b/Tests/LibWeb/Layout/input/grid/line-based-with-repeat.html @@ -0,0 +1,44 @@ + + +
+
A
+
B
+
C
+
D
+
E