LibWeb: Fix grid placement with named lines

This commit is contained in:
Lukas Scheller 2025-03-11 23:03:06 +01:00 committed by Alexander Kalenik
commit 852e8ff12f
Notes: github-actions[bot] 2025-04-05 19:31:34 +00:00
8 changed files with 277 additions and 12 deletions

View file

@ -316,9 +316,9 @@ GridFormattingContext::PlacementPosition GridFormattingContext::resolve_grid_pos
result.end = m_occupation_grid.column_count() + result.end + 2; 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(); 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.span = placement_start.span();
result.start = result.end - result.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 // 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()) { if (placement_end.has_identifier()) {
auto area_end_line_name = MUST(String::formatted("{}-end", placement_end.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(); 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(); result.end = line_name_index.value();
} else { } else {
result.end = 1; result.end = 1;
@ -340,9 +341,10 @@ GridFormattingContext::PlacementPosition GridFormattingContext::resolve_grid_pos
if (placement_start.has_identifier()) { if (placement_start.has_identifier()) {
auto area_start_line_name = MUST(String::formatted("{}-start", placement_start.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(); 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(); result.start = line_name_index.value();
} else { } else {
result.start = 0; result.start = 0;
@ -2266,13 +2268,23 @@ AvailableSize GridFormattingContext::get_free_space(AvailableSpace const& availa
return available_size; return available_size;
} }
Optional<int> GridFormattingContext::get_line_index_by_line_name(GridDimension dimension, String const& line_name) Optional<int> 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; auto const& lines = dimension == GridDimension::Column ? m_column_lines : m_row_lines;
for (size_t line_index = 0; line_index < lines.size(); line_index++) { size_t line_index = nth_line < 0 ? lines.size() + nth_line : nth_line - 1;
for (auto const& name : lines[line_index].names) { // FIXME: If not enough lines with the name exist, all implicit grid lines on the side
if (name == line_name) // of the explicit grid corresponding to the search direction are assumed to have that name for the purpose of counting this span.
return static_cast<int>(line_index); // 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 items placement.
if (line_index == 0)
return static_cast<int>(actual_line_index);
else
line_index--;
}
} }
} }
return {}; return {};

View file

@ -328,7 +328,7 @@ private:
AvailableSize get_free_space(AvailableSpace const&, GridDimension) const; AvailableSize get_free_space(AvailableSpace const&, GridDimension) const;
Optional<int> get_line_index_by_line_name(GridDimension dimension, String const&); Optional<int> get_nth_line_index_by_line_name(GridDimension dimension, String const&, int line_number);
CSSPixels resolve_definite_track_size(CSS::GridSize const&, AvailableSpace const&); 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); int count_of_repeated_auto_fill_or_fit_tracks(GridDimension, CSS::ExplicitGridTrack const& repeated_track);

View file

@ -0,0 +1,30 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x168 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x152 children: not-inline
BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline
TextNode <#text>
Box <div.wrapper> at (8,8) content-size 784x152 [GFC] children: not-inline
BlockContainer <(anonymous)> (not painted) [BFC] children: inline
TextNode <#text>
BlockContainer <div.box.a> 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 <div.box.b> 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<HTML>) [0,0 800x168]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x152]
PaintableWithLines (BlockContainer(anonymous)) [8,8 784x0]
PaintableBox (Box<DIV>.wrapper) [8,8 784x152]
PaintableWithLines (BlockContainer<DIV>.box.a) [8,18 100x66]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<DIV>.box.b) [8,94 100x66]
TextPaintable (TextNode<#text>)

View file

@ -0,0 +1,54 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x234 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x218 children: not-inline
BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline
TextNode <#text>
Box <div.wrapper> at (8,8) content-size 784x218 [GFC] children: not-inline
BlockContainer <(anonymous)> (not painted) [BFC] children: inline
TextNode <#text>
BlockContainer <div.box.a> 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 <div.box.b> 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 <div.box.c> 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 <div.box.d> 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 <div.box.e> 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<HTML>) [0,0 800x234]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x218]
PaintableWithLines (BlockContainer(anonymous)) [8,8 784x0]
PaintableBox (Box<DIV>.wrapper) [8,8 784x218]
PaintableWithLines (BlockContainer<DIV>.box.a) [8,8 210x66]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<DIV>.box.b) [228,8 210x66]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<DIV>.box.c) [8,84 100x66]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<DIV>.box.d) [118,84 320x66]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<DIV>.box.e) [8,160 430x66]
TextPaintable (TextNode<#text>)

View file

@ -0,0 +1,54 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x234 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x218 children: not-inline
BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline
TextNode <#text>
Box <div.wrapper> at (8,8) content-size 784x218 [GFC] children: not-inline
BlockContainer <(anonymous)> (not painted) [BFC] children: inline
TextNode <#text>
BlockContainer <div.box.a> 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 <div.box.b> 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 <div.box.c> 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 <div.box.d> 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 <div.box.e> 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<HTML>) [0,0 800x234]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x218]
PaintableWithLines (BlockContainer(anonymous)) [8,8 784x0]
PaintableBox (Box<DIV>.wrapper) [8,8 784x218]
PaintableWithLines (BlockContainer<DIV>.box.a) [8,8 210x66]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<DIV>.box.b) [228,8 210x66]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<DIV>.box.c) [8,84 100x66]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<DIV>.box.d) [118,84 320x66]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<DIV>.box.e) [8,160 430x66]
TextPaintable (TextNode<#text>)

View file

@ -0,0 +1,27 @@
<!DOCTYPE html><style>
.wrapper {
display: grid;
grid-gap: 10px;
grid-template-columns: [col] 100px [col] 100px [col] 100px [col] 100px;
grid-template-rows: [row] auto [row] auto [row];
background-color: #fff;
color: #444;
}
.box {
background-color: #444;
color: #fff;
border-radius: 5px;
padding: 20px;
font-size: 150%;
}
.a {
grid-row: row -2 ;
}
.b {
grid-row: row -1 ;
}
</style>
<body>
<div class="wrapper">
<div class="box a">A</div>
<div class="box b">B</div>

View file

@ -0,0 +1,44 @@
<!DOCTYPE html><style>
.wrapper {
display: grid;
grid-gap: 10px;
grid-template-columns: [col] 100px [col] 100px [col] 100px [col] 100px;
grid-template-rows: [row] auto [row] auto [row];
background-color: #fff;
color: #444;
}
.box {
background-color: #444;
color: #fff;
border-radius: 5px;
padding: 20px;
font-size: 150%;
}
.a {
grid-column: col / span 2;
grid-row: row ;
}
.b {
grid-column: col 3 / span 2 ;
grid-row: row ;
}
.c {
grid-column: col ;
grid-row: row 2 ;
}
.d {
grid-column: col 2 / span 3 ;
grid-row: row 2 ;
}
.e {
grid-column: col / span 4;
grid-row: row 3;
}
</style>
<body>
<div class="wrapper">
<div class="box a">A</div>
<div class="box b">B</div>
<div class="box c">C</div>
<div class="box d">D</div>
<div class="box e">E</div>

View file

@ -0,0 +1,44 @@
<!DOCTYPE html><style>
.wrapper {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(4, [col] 100px) ;
grid-template-rows: repeat(3, [row] auto);
background-color: #fff;
color: #444;
}
.box {
background-color: #444;
color: #fff;
border-radius: 5px;
padding: 20px;
font-size: 150%;
}
.a {
grid-column: col / span 2;
grid-row: row ;
}
.b {
grid-column: col 3 / span 2 ;
grid-row: row ;
}
.c {
grid-column: col ;
grid-row: row 2 ;
}
.d {
grid-column: col 2 / span 3 ;
grid-row: row 2 ;
}
.e {
grid-column: col / span 4;
grid-row: row 3;
}
</style>
<body>
<div class="wrapper">
<div class="box a">A</div>
<div class="box b">B</div>
<div class="box c">C</div>
<div class="box d">D</div>
<div class="box e">E</div>