diff --git a/Tests/LibWeb/Layout/expected/grid/borders.txt b/Tests/LibWeb/Layout/expected/grid/borders.txt index f4061be61c..ac82923265 100644 --- a/Tests/LibWeb/Layout/expected/grid/borders.txt +++ b/Tests/LibWeb/Layout/expected/grid/borders.txt @@ -1,6 +1,6 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline BlockContainer at (0,0) content-size 800x600 [BFC] children: not-inline - BlockContainer at (8,8) content-size 784x428.28125 children: not-inline + BlockContainer at (8,8) content-size 784x448.28125 children: not-inline Box at (8,8) content-size 784x74.9375 [GFC] children: not-inline BlockContainer <(anonymous)> at (8,8) content-size 0x0 [BFC] children: inline TextNode <#text> @@ -122,40 +122,40 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline Box at (8,366.28125) content-size 784x50 [GFC] children: not-inline BlockContainer <(anonymous)> at (8,366.28125) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer at (18,376.28125) content-size 280x5 [BFC] children: inline + BlockContainer at (18,376.28125) content-size 280x25 [BFC] children: inline line 0 width: 6.34375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 frag 0 from TextNode start: 0, length: 1, rect: [18,376.28125 6.34375x17.46875] "1" TextNode <#text> BlockContainer <(anonymous)> at (8,366.28125) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer at (318,376.28125) content-size 280x5 [BFC] children: inline + BlockContainer at (318,376.28125) content-size 280x25 [BFC] children: inline line 0 width: 8.8125, height: 17.46875, bottom: 17.46875, baseline: 13.53125 frag 0 from TextNode start: 0, length: 1, rect: [318,376.28125 8.8125x17.46875] "2" TextNode <#text> BlockContainer <(anonymous)> at (8,366.28125) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer at (18,401.28125) content-size 280x5 [BFC] children: inline + BlockContainer at (18,421.28125) content-size 280x25 [BFC] children: inline line 0 width: 8.8125, height: 17.46875, bottom: 17.46875, baseline: 13.53125 - frag 0 from TextNode start: 0, length: 1, rect: [18,401.28125 8.8125x17.46875] + frag 0 from TextNode start: 0, length: 1, rect: [18,421.28125 8.8125x17.46875] "2" TextNode <#text> BlockContainer <(anonymous)> at (8,366.28125) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer at (318,401.28125) content-size 280x5 [BFC] children: inline + BlockContainer at (318,421.28125) content-size 280x25 [BFC] children: inline line 0 width: 8.8125, height: 17.46875, bottom: 17.46875, baseline: 13.53125 - frag 0 from TextNode start: 0, length: 1, rect: [318,401.28125 8.8125x17.46875] + frag 0 from TextNode start: 0, length: 1, rect: [318,421.28125 8.8125x17.46875] "2" TextNode <#text> BlockContainer <(anonymous)> at (8,366.28125) content-size 0x0 [BFC] children: inline TextNode <#text> BlockContainer <(anonymous)> at (8,416.28125) content-size 784x0 children: inline TextNode <#text> - Box at (8,416.28125) content-size 784x20 [GFC] children: not-inline + Box at (8,416.28125) content-size 784x40 [GFC] children: not-inline BlockContainer <(anonymous)> at (8,416.28125) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer at (18,426.28125) content-size 764x0 [BFC] children: inline + BlockContainer at (18,426.28125) content-size 764x20 [BFC] children: inline line 0 width: 6.34375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 frag 0 from TextNode start: 0, length: 1, rect: [18,426.28125 6.34375x17.46875] "1" diff --git a/Tests/LibWeb/Layout/expected/grid/minmax.txt b/Tests/LibWeb/Layout/expected/grid/minmax.txt index 1150a2f3c7..25afce72a9 100644 --- a/Tests/LibWeb/Layout/expected/grid/minmax.txt +++ b/Tests/LibWeb/Layout/expected/grid/minmax.txt @@ -1,6 +1,6 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline BlockContainer at (0,0) content-size 800x600 [BFC] children: not-inline - BlockContainer at (8,8) content-size 784x272.28125 children: not-inline + BlockContainer at (8,8) content-size 784x222.28125 children: not-inline Box at (8,8) content-size 784x17.46875 [GFC] children: not-inline BlockContainer <(anonymous)> at (8,8) content-size 0x0 [BFC] children: inline TextNode <#text> @@ -21,148 +21,148 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline BlockContainer <(anonymous)> at (8,25.46875) content-size 784x0 children: inline TextNode <#text> TextNode <#text> - Box at (8,25.46875) content-size 784x100 [GFC] children: not-inline + Box at (8,25.46875) content-size 784x50 [GFC] children: not-inline BlockContainer <(anonymous)> at (8,25.46875) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer at (8,25.46875) content-size 300x50 [BFC] children: inline + BlockContainer at (8,25.46875) content-size 300x25 [BFC] children: inline line 0 width: 6.34375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 frag 0 from TextNode start: 0, length: 1, rect: [8,25.46875 6.34375x17.46875] "1" TextNode <#text> BlockContainer <(anonymous)> at (8,25.46875) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer at (308,25.46875) content-size 300x50 [BFC] children: inline + BlockContainer at (308,25.46875) content-size 300x25 [BFC] children: inline line 0 width: 8.8125, height: 17.46875, bottom: 17.46875, baseline: 13.53125 frag 0 from TextNode start: 0, length: 1, rect: [308,25.46875 8.8125x17.46875] "2" TextNode <#text> BlockContainer <(anonymous)> at (8,25.46875) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer <(anonymous)> at (8,125.46875) content-size 784x0 children: inline + BlockContainer <(anonymous)> at (8,75.46875) content-size 784x0 children: inline TextNode <#text> TextNode <#text> - Box at (8,125.46875) content-size 784x34.9375 [GFC] children: not-inline - BlockContainer <(anonymous)> at (8,125.46875) content-size 0x0 [BFC] children: inline + Box at (8,75.46875) content-size 784x34.9375 [GFC] children: not-inline + BlockContainer <(anonymous)> at (8,75.46875) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer at (8,125.46875) content-size 784x17.46875 [BFC] children: inline + BlockContainer at (8,75.46875) content-size 784x17.46875 [BFC] children: inline line 0 width: 6.34375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 - frag 0 from TextNode start: 0, length: 1, rect: [8,125.46875 6.34375x17.46875] + frag 0 from TextNode start: 0, length: 1, rect: [8,75.46875 6.34375x17.46875] "1" TextNode <#text> - BlockContainer <(anonymous)> at (8,125.46875) content-size 0x0 [BFC] children: inline + BlockContainer <(anonymous)> at (8,75.46875) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer at (8,142.9375) content-size 784x17.46875 [BFC] children: inline + BlockContainer at (8,92.9375) content-size 784x17.46875 [BFC] children: inline line 0 width: 8.8125, height: 17.46875, bottom: 17.46875, baseline: 13.53125 - frag 0 from TextNode start: 0, length: 1, rect: [8,142.9375 8.8125x17.46875] + frag 0 from TextNode start: 0, length: 1, rect: [8,92.9375 8.8125x17.46875] "2" TextNode <#text> - BlockContainer <(anonymous)> at (8,125.46875) content-size 0x0 [BFC] children: inline + BlockContainer <(anonymous)> at (8,75.46875) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer <(anonymous)> at (8,160.40625) content-size 784x0 children: inline + BlockContainer <(anonymous)> at (8,110.40625) content-size 784x0 children: inline TextNode <#text> TextNode <#text> - Box at (8,160.40625) content-size 784x34.9375 [GFC] children: not-inline - BlockContainer <(anonymous)> at (8,160.40625) content-size 0x0 [BFC] children: inline + Box at (8,110.40625) content-size 784x34.9375 [GFC] children: not-inline + BlockContainer <(anonymous)> at (8,110.40625) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer at (8,160.40625) content-size 784x17.46875 [BFC] children: inline + BlockContainer at (8,110.40625) content-size 784x17.46875 [BFC] children: inline line 0 width: 6.34375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 - frag 0 from TextNode start: 0, length: 1, rect: [8,160.40625 6.34375x17.46875] + frag 0 from TextNode start: 0, length: 1, rect: [8,110.40625 6.34375x17.46875] "1" TextNode <#text> - BlockContainer <(anonymous)> at (8,160.40625) content-size 0x0 [BFC] children: inline + BlockContainer <(anonymous)> at (8,110.40625) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer at (8,177.875) content-size 784x17.46875 [BFC] children: inline + BlockContainer at (8,127.875) content-size 784x17.46875 [BFC] children: inline line 0 width: 8.8125, height: 17.46875, bottom: 17.46875, baseline: 13.53125 - frag 0 from TextNode start: 0, length: 1, rect: [8,177.875 8.8125x17.46875] + frag 0 from TextNode start: 0, length: 1, rect: [8,127.875 8.8125x17.46875] "2" TextNode <#text> - BlockContainer <(anonymous)> at (8,160.40625) content-size 0x0 [BFC] children: inline + BlockContainer <(anonymous)> at (8,110.40625) content-size 0x0 [BFC] children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (8,145.34375) content-size 784x0 children: inline + TextNode <#text> + TextNode <#text> + Box at (8,145.34375) content-size 784x50 [GFC] children: not-inline + BlockContainer <(anonymous)> at (8,145.34375) content-size 0x0 [BFC] children: inline + TextNode <#text> + BlockContainer at (8,145.34375) content-size 300x25 [BFC] children: inline + line 0 width: 6.34375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 1, rect: [8,145.34375 6.34375x17.46875] + "1" + TextNode <#text> + BlockContainer <(anonymous)> at (8,145.34375) content-size 0x0 [BFC] children: inline + TextNode <#text> + BlockContainer at (308,145.34375) content-size 300x25 [BFC] children: inline + line 0 width: 8.8125, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 1, rect: [308,145.34375 8.8125x17.46875] + "2" + TextNode <#text> + BlockContainer <(anonymous)> at (8,145.34375) content-size 0x0 [BFC] children: inline + TextNode <#text> + BlockContainer at (8,170.34375) content-size 300x25 [BFC] children: inline + line 0 width: 9.09375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 1, rect: [8,170.34375 9.09375x17.46875] + "3" + TextNode <#text> + BlockContainer <(anonymous)> at (8,145.34375) content-size 0x0 [BFC] children: inline + TextNode <#text> + BlockContainer at (308,170.34375) content-size 300x25 [BFC] children: inline + line 0 width: 7.75, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 1, rect: [308,170.34375 7.75x17.46875] + "4" + TextNode <#text> + BlockContainer <(anonymous)> at (8,145.34375) content-size 0x0 [BFC] children: inline TextNode <#text> BlockContainer <(anonymous)> at (8,195.34375) content-size 784x0 children: inline TextNode <#text> TextNode <#text> - Box at (8,195.34375) content-size 784x50 [GFC] children: not-inline + Box at (8,195.34375) content-size 784x17.46875 [GFC] children: not-inline BlockContainer <(anonymous)> at (8,195.34375) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer at (8,195.34375) content-size 300x25 [BFC] children: inline + BlockContainer at (8,195.34375) content-size 261.333343x17.46875 [BFC] children: inline line 0 width: 6.34375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 frag 0 from TextNode start: 0, length: 1, rect: [8,195.34375 6.34375x17.46875] "1" TextNode <#text> BlockContainer <(anonymous)> at (8,195.34375) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer at (308,195.34375) content-size 300x25 [BFC] children: inline + BlockContainer at (269.333343,195.34375) content-size 261.333343x17.46875 [BFC] children: inline line 0 width: 8.8125, height: 17.46875, bottom: 17.46875, baseline: 13.53125 - frag 0 from TextNode start: 0, length: 1, rect: [308,195.34375 8.8125x17.46875] + frag 0 from TextNode start: 0, length: 1, rect: [269.333343,195.34375 8.8125x17.46875] "2" TextNode <#text> BlockContainer <(anonymous)> at (8,195.34375) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer at (8,220.34375) content-size 300x25 [BFC] children: inline + BlockContainer at (530.666687,195.34375) content-size 261.333312x17.46875 [BFC] children: inline line 0 width: 9.09375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 - frag 0 from TextNode start: 0, length: 1, rect: [8,220.34375 9.09375x17.46875] + frag 0 from TextNode start: 0, length: 1, rect: [530.666687,195.34375 9.09375x17.46875] "3" TextNode <#text> BlockContainer <(anonymous)> at (8,195.34375) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer at (308,220.34375) content-size 300x25 [BFC] children: inline - line 0 width: 7.75, height: 17.46875, bottom: 17.46875, baseline: 13.53125 - frag 0 from TextNode start: 0, length: 1, rect: [308,220.34375 7.75x17.46875] - "4" - TextNode <#text> - BlockContainer <(anonymous)> at (8,195.34375) content-size 0x0 [BFC] children: inline - TextNode <#text> - BlockContainer <(anonymous)> at (8,245.34375) content-size 784x0 children: inline + BlockContainer <(anonymous)> at (8,212.8125) content-size 784x0 children: inline TextNode <#text> TextNode <#text> - Box at (8,245.34375) content-size 784x17.46875 [GFC] children: not-inline - BlockContainer <(anonymous)> at (8,245.34375) content-size 0x0 [BFC] children: inline + Box at (8,212.8125) content-size 784x17.46875 [GFC] children: not-inline + BlockContainer <(anonymous)> at (8,212.8125) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer at (8,245.34375) content-size 261.333343x17.46875 [BFC] children: inline + BlockContainer at (8,212.8125) content-size 56.218711x17.46875 [BFC] children: inline line 0 width: 6.34375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 - frag 0 from TextNode start: 0, length: 1, rect: [8,245.34375 6.34375x17.46875] + frag 0 from TextNode start: 0, length: 1, rect: [8,212.8125 6.34375x17.46875] "1" TextNode <#text> - BlockContainer <(anonymous)> at (8,245.34375) content-size 0x0 [BFC] children: inline + BlockContainer <(anonymous)> at (8,212.8125) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer at (269.333343,245.34375) content-size 261.333343x17.46875 [BFC] children: inline - line 0 width: 8.8125, height: 17.46875, bottom: 17.46875, baseline: 13.53125 - frag 0 from TextNode start: 0, length: 1, rect: [269.333343,245.34375 8.8125x17.46875] - "2" - TextNode <#text> - BlockContainer <(anonymous)> at (8,245.34375) content-size 0x0 [BFC] children: inline - TextNode <#text> - BlockContainer at (530.666687,245.34375) content-size 261.333312x17.46875 [BFC] children: inline - line 0 width: 9.09375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 - frag 0 from TextNode start: 0, length: 1, rect: [530.666687,245.34375 9.09375x17.46875] - "3" - TextNode <#text> - BlockContainer <(anonymous)> at (8,245.34375) content-size 0x0 [BFC] children: inline - TextNode <#text> - BlockContainer <(anonymous)> at (8,262.8125) content-size 784x0 children: inline - TextNode <#text> - TextNode <#text> - Box at (8,262.8125) content-size 784x17.46875 [GFC] children: not-inline - BlockContainer <(anonymous)> at (8,262.8125) content-size 0x0 [BFC] children: inline - TextNode <#text> - BlockContainer at (8,262.8125) content-size 56.218711x17.46875 [BFC] children: inline - line 0 width: 6.34375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 - frag 0 from TextNode start: 0, length: 1, rect: [8,262.8125 6.34375x17.46875] - "1" - TextNode <#text> - BlockContainer <(anonymous)> at (8,262.8125) content-size 0x0 [BFC] children: inline - TextNode <#text> - BlockContainer at (64.218711,262.8125) content-size 671.5625x17.46875 [BFC] children: inline + BlockContainer at (64.218711,212.8125) content-size 671.5625x17.46875 [BFC] children: inline line 0 width: 125.265625, height: 17.46875, bottom: 17.46875, baseline: 13.53125 - frag 0 from TextNode start: 0, length: 15, rect: [64.218711,262.8125 125.265625x17.46875] + frag 0 from TextNode start: 0, length: 15, rect: [64.218711,212.8125 125.265625x17.46875] "Article content" TextNode <#text> - BlockContainer <(anonymous)> at (8,262.8125) content-size 0x0 [BFC] children: inline + BlockContainer <(anonymous)> at (8,212.8125) content-size 0x0 [BFC] children: inline TextNode <#text> - BlockContainer at (735.781188,262.8125) content-size 56.218688x17.46875 [BFC] children: inline + BlockContainer at (735.781188,212.8125) content-size 56.218688x17.46875 [BFC] children: inline line 0 width: 9.09375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 - frag 0 from TextNode start: 0, length: 1, rect: [735.781188,262.8125 9.09375x17.46875] + frag 0 from TextNode start: 0, length: 1, rect: [735.781188,212.8125 9.09375x17.46875] "3" TextNode <#text> - BlockContainer <(anonymous)> at (8,262.8125) content-size 0x0 [BFC] children: inline + BlockContainer <(anonymous)> at (8,212.8125) content-size 0x0 [BFC] children: inline TextNode <#text> diff --git a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp index b7716a2b92..83c4e1a384 100644 --- a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp @@ -35,21 +35,11 @@ CSSPixels GridFormattingContext::resolve_definite_track_size(CSS::GridSize const return 0; } -size_t GridFormattingContext::count_of_gap_columns() +size_t GridFormattingContext::count_of_gap_tracks(Vector const& tracks) const { 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_rows() -{ - size_t count = 0; - for (auto& grid_row : m_grid_rows) { - if (grid_row.is_gap) + for (auto& track : tracks) { + if (track.is_gap) count++; } return count; @@ -126,7 +116,7 @@ int GridFormattingContext::count_of_repeated_auto_fill_or_fit_tracks(Vector((get_free_space_x(available_space) / sum_of_grid_track_sizes).value())); + return max(1, static_cast((get_free_space(available_space.width, m_grid_columns) / sum_of_grid_track_sizes).value())); // 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 @@ -652,25 +642,27 @@ void GridFormattingContext::initialize_grid_tracks(Box const& box, AvailableSpac } } -void GridFormattingContext::calculate_sizes_of_columns(Box const& box, AvailableSpace const& available_space) +void GridFormattingContext::run_track_sizing(GridDimension const dimension, AvailableSpace const& available_space, Vector& tracks) { + auto track_available_size = dimension == GridDimension::Column ? available_space.width : available_space.height; + // 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) + for (auto& track : tracks) { + if (track.is_gap) continue; // For each track, if the track’s min track sizing function is: - switch (grid_column.min_track_sizing_function.type()) { + switch (track.min_track_sizing_function.type()) { // - A fixed sizing function // Resolve to an absolute length and use that size as the track’s initial base size. case CSS::GridSize::Type::Length: - if (!grid_column.min_track_sizing_function.length().is_auto()) - grid_column.base_size = grid_column.min_track_sizing_function.length().to_px(box); + if (!track.min_track_sizing_function.length().is_auto()) + track.base_size = track.min_track_sizing_function.length().to_px(grid_container()); break; case CSS::GridSize::Type::Percentage: - if (available_space.width.is_definite()) - grid_column.base_size = grid_column.min_track_sizing_function.percentage().as_fraction() * available_space.width.to_px().value(); + if (track_available_size.is_definite()) + track.base_size = track.min_track_sizing_function.percentage().as_fraction() * track_available_size.to_px().value(); break; // - An intrinsic sizing function // Use an initial base size of zero. @@ -683,31 +675,31 @@ void GridFormattingContext::calculate_sizes_of_columns(Box const& box, Available } // For each track, if the track’s max track sizing function is: - switch (grid_column.max_track_sizing_function.type()) { + switch (track.max_track_sizing_function.type()) { // - A fixed sizing function // Resolve to an absolute length and use that size as the track’s initial growth limit. case CSS::GridSize::Type::Length: - if (!grid_column.max_track_sizing_function.length().is_auto()) - grid_column.growth_limit = grid_column.max_track_sizing_function.length().to_px(box); + if (!track.max_track_sizing_function.length().is_auto()) + track.growth_limit = track.max_track_sizing_function.length().to_px(grid_container()); else // - An intrinsic sizing function // Use an initial growth limit of infinity. - grid_column.growth_limit = -1; + track.growth_limit = -1; break; case CSS::GridSize::Type::Percentage: - if (available_space.width.is_definite()) - grid_column.growth_limit = grid_column.max_track_sizing_function.percentage().as_fraction() * available_space.width.to_px().value(); + if (track_available_size.is_definite()) + track.growth_limit = track.max_track_sizing_function.percentage().as_fraction() * track_available_size.to_px().value(); break; // - A flexible sizing function // Use an initial growth limit of infinity. case CSS::GridSize::Type::FlexibleLength: - grid_column.growth_limit = -1; + track.growth_limit = -1; break; // - An intrinsic sizing function // Use an initial growth limit of infinity. case CSS::GridSize::Type::MaxContent: case CSS::GridSize::Type::MinContent: - grid_column.growth_limit = -1; + track.growth_limit = -1; break; default: VERIFY_NOT_REACHED(); @@ -715,8 +707,8 @@ void GridFormattingContext::calculate_sizes_of_columns(Box const& box, Available // In all cases, if the growth limit is less than the base size, increase the growth limit to match // the base size. - if (grid_column.growth_limit != -1 && grid_column.growth_limit < grid_column.base_size) - grid_column.growth_limit = grid_column.base_size; + if (track.growth_limit != -1 && track.growth_limit < track.base_size) + track.growth_limit = track.base_size; } // https://www.w3.org/TR/css-grid-2/#algo-content @@ -737,45 +729,66 @@ void GridFormattingContext::calculate_sizes_of_columns(Box const& box, Available // 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: + + auto calculate_item_min_content_contribution = [&](GridItem const& item) { + if (dimension == GridDimension::Column) { + return calculate_min_content_width(item.box()); + } else { + return content_based_minimum_height(item); + } + }; + int index = 0; - for (auto& grid_column : m_grid_columns) { - if (grid_column.is_gap) { + for (auto& track : tracks) { + if (track.is_gap) { ++index; continue; } - Vector boxes_of_column; + Vector grid_items_of_track; for (auto& grid_item : m_grid_items) { - if (grid_item.gap_adjusted_column(box) == index && grid_item.raw_column_span() == 1) { - boxes_of_column.append(grid_item.box()); - grid_column.border_left = max(grid_column.border_left, grid_item.box().computed_values().border_left().width); - grid_column.border_right = max(grid_column.border_right, grid_item.box().computed_values().border_right().width); + if (dimension == GridDimension::Column) { + if (grid_item.gap_adjusted_column(grid_container()) == index && grid_item.raw_column_span() == 1) { + grid_items_of_track.append(grid_item); + + track.border_left = max(track.border_left, grid_item.box().computed_values().border_left().width); + track.border_right = max(track.border_right, grid_item.box().computed_values().border_right().width); + } + } else { + if (grid_item.gap_adjusted_row(grid_container()) == index && grid_item.raw_row_span() == 1) { + grid_items_of_track.append(grid_item); + + track.border_top = max(track.border_top, grid_item.box().computed_values().border_top().width); + track.border_bottom = max(track.border_bottom, grid_item.box().computed_values().border_bottom().width); + } } } - if (!grid_column.min_track_sizing_function.is_intrinsic_track_sizing() && !grid_column.max_track_sizing_function.is_intrinsic_track_sizing()) { + if (!track.min_track_sizing_function.is_intrinsic_track_sizing() && !track.max_track_sizing_function.is_intrinsic_track_sizing()) { ++index; continue; } - switch (grid_column.min_track_sizing_function.type()) { + switch (track.min_track_sizing_function.type()) { // - For min-content minimums: // If the track has a min-content min track sizing function, set its base size to the maximum of the // items’ min-content contributions, floored at zero. case CSS::GridSize::Type::MinContent: { - CSSPixels column_width = 0; - for (auto& box_of_column : boxes_of_column) - column_width = max(column_width, calculate_min_content_width(box_of_column)); - grid_column.base_size = column_width; + CSSPixels base_size = 0; + for (auto& item : grid_items_of_track) { + base_size = max(base_size, calculate_item_min_content_contribution(item)); + } + track.base_size = base_size; } break; // - For max-content minimums: // If the track has a max-content min track sizing function, set its base size to the maximum of the // items’ max-content contributions, floored at zero. case CSS::GridSize::Type::MaxContent: { - CSSPixels column_width = 0; - for (auto& box_of_column : boxes_of_column) - column_width = max(column_width, calculate_max_content_width(box_of_column)); - grid_column.base_size = column_width; + CSSPixels base_size = 0; + for (auto& item : grid_items_of_track) { + base_size = max(base_size, calculate_item_min_content_contribution(item)); + } + track.base_size = base_size; } break; // - For auto minimums: // If the track has an auto min track sizing function and the grid container is being sized under a @@ -796,34 +809,37 @@ void GridFormattingContext::calculate_sizes_of_columns(Box const& box, Available // the size of the item’s content, it is considered a type of intrinsic size contribution. case CSS::GridSize::Type::Percentage: case CSS::GridSize::Type::FlexibleLength: { - CSSPixels grid_column_width = 0; - for (auto& box_of_column : boxes_of_column) - grid_column_width = max(grid_column_width, calculate_min_content_width(box_of_column).value()); - grid_column.base_size = grid_column_width; + CSSPixels base_size = 0; + for (auto& item : grid_items_of_track) { + base_size = max(base_size, calculate_item_min_content_contribution(item)); + } + track.base_size = base_size; } break; default: VERIFY_NOT_REACHED(); } - switch (grid_column.max_track_sizing_function.type()) { + switch (track.max_track_sizing_function.type()) { // - For min-content maximums: // If the track has a min-content max track sizing function, set its growth limit to the maximum of // the items’ min-content contributions. case CSS::GridSize::Type::MinContent: { - CSSPixels column_width = 0; - for (auto& box_of_column : boxes_of_column) - column_width = max(column_width, calculate_min_content_width(box_of_column)); - grid_column.growth_limit = column_width; + CSSPixels growth_limit = 0; + for (auto& item : grid_items_of_track) { + growth_limit = max(growth_limit, calculate_item_min_content_contribution(item)); + } + track.growth_limit = growth_limit; } break; // - For max-content maximums: // If the track has a max-content max track sizing function, set its growth limit to the maximum of // the items’ max-content contributions. For fit-content() maximums, furthermore clamp this growth // limit by the fit-content() argument. case CSS::GridSize::Type::MaxContent: { - CSSPixels column_width = 0; - for (auto& box_of_column : boxes_of_column) - column_width = max(column_width, calculate_max_content_width(box_of_column)); - grid_column.growth_limit = column_width; + CSSPixels growth_limit = 0; + for (auto& item : grid_items_of_track) { + growth_limit = max(growth_limit, calculate_item_min_content_contribution(item)); + } + track.growth_limit = growth_limit; } break; case CSS::GridSize::Type::Length: case CSS::GridSize::Type::Percentage: @@ -835,8 +851,8 @@ void GridFormattingContext::calculate_sizes_of_columns(Box const& box, Available // In all cases, if a track’s growth limit is now less than its base size, increase the growth limit // to match the base size. - if (grid_column.growth_limit != -1 && grid_column.growth_limit < grid_column.base_size) - grid_column.growth_limit = grid_column.base_size; + if (track.growth_limit != -1 && track.growth_limit < track.base_size) + track.growth_limit = track.base_size; ++index; } @@ -845,14 +861,15 @@ void GridFormattingContext::calculate_sizes_of_columns(Box const& box, Available // 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 (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()) { + if (dimension == GridDimension::Column // FIXME: Handle for columns + && grid_container().computed_values().grid_template_columns().track_list().size() == 1 + && grid_container().computed_values().grid_template_columns().track_list().first().is_repeat() + && grid_container().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; + auto column_to_check = grid_container().computed_values().column_gap().is_auto() ? idx : idx / 2; if (m_occupation_grid.is_occupied(column_to_check, 0)) continue; - if (!box.computed_values().column_gap().is_auto() && idx % 2 != 0) + if (!grid_container().computed_values().column_gap().is_auto() && idx % 2 != 0) continue; // A collapsed track is treated as having a fixed track sizing function of 0px @@ -924,7 +941,7 @@ void GridFormattingContext::calculate_sizes_of_columns(Box const& box, Available // To distribute extra space by increasing the affected sizes of a set of tracks as required by a // set of intrinsic size contributions, CSSPixels sum_of_track_sizes = 0; - for (auto& it : m_grid_columns) + for (auto& it : tracks) sum_of_track_sizes += it.base_size; // 1. Maintain separately for each affected base size or growth limit a planned increase, initially @@ -942,20 +959,21 @@ void GridFormattingContext::calculate_sizes_of_columns(Box const& box, Available // a growth limit and the track is not marked infinitely growable, then each item-incurred increase // will be zero. // extra-space = max(0, size-contribution - ∑track-sizes) - for (auto& grid_column : m_grid_columns) { - if (grid_column.is_gap) + for (auto& track : tracks) { + if (track.is_gap) continue; - grid_column.space_to_distribute = max(CSSPixels(0), (grid_column.growth_limit == -1 ? grid_column.base_size : grid_column.growth_limit) - grid_column.base_size); + track.space_to_distribute = max(CSSPixels(0), (track.growth_limit == -1 ? track.base_size : track.growth_limit) - track.base_size); } - auto remaining_free_space = available_space.width.is_definite() ? available_space.width.to_px() - sum_of_track_sizes : 0; + auto remaining_free_space = track_available_size.is_definite() ? track_available_size.to_px() - sum_of_track_sizes : 0; + // 2.2. Distribute space up to limits: Find the item-incurred increase for each spanned track with an // affected size by: distributing the space equally among such tracks, freezing a track’s // item-incurred increase as its affected size + item-incurred increase reaches its limit (and // continuing to grow the unfrozen tracks as needed). auto count_of_unfrozen_tracks = 0; - for (auto& grid_column : m_grid_columns) { - if (grid_column.space_to_distribute > 0) + for (auto& track : tracks) { + if (track.space_to_distribute > 0) count_of_unfrozen_tracks++; } while (remaining_free_space > 0) { @@ -963,25 +981,25 @@ void GridFormattingContext::calculate_sizes_of_columns(Box const& box, Available break; auto free_space_to_distribute_per_track = remaining_free_space / count_of_unfrozen_tracks; - for (auto& grid_column : m_grid_columns) { - if (grid_column.space_to_distribute == 0) + for (auto& track : tracks) { + if (track.space_to_distribute == 0) continue; // 2.4. For each affected track, if the track’s item-incurred increase is larger than the track’s planned // increase set the track’s planned increase to that value. - if (grid_column.space_to_distribute <= free_space_to_distribute_per_track) { - grid_column.planned_increase += grid_column.space_to_distribute; - remaining_free_space -= grid_column.space_to_distribute; - grid_column.space_to_distribute = 0; + if (track.space_to_distribute <= free_space_to_distribute_per_track) { + track.planned_increase += track.space_to_distribute; + remaining_free_space -= track.space_to_distribute; + track.space_to_distribute = 0; } else { - grid_column.space_to_distribute -= free_space_to_distribute_per_track; - grid_column.planned_increase += free_space_to_distribute_per_track; + track.space_to_distribute -= free_space_to_distribute_per_track; + track.planned_increase += free_space_to_distribute_per_track; remaining_free_space -= free_space_to_distribute_per_track; } } count_of_unfrozen_tracks = 0; - for (auto& grid_column : m_grid_columns) { - if (grid_column.space_to_distribute > 0) + for (auto& track : tracks) { + if (track.space_to_distribute > 0) count_of_unfrozen_tracks++; } if (remaining_free_space == 0) @@ -1011,28 +1029,28 @@ void GridFormattingContext::calculate_sizes_of_columns(Box const& box, Available // 3. Update the tracks' affected sizes by adding in the planned increase so that the next round of // space distribution will account for the increase. (If the affected size is an infinite growth // limit, set it to the track’s base size plus the planned increase.) - for (auto& grid_column : m_grid_columns) - grid_column.base_size += grid_column.planned_increase; + for (auto& track : tracks) + track.base_size += track.planned_increase; // https://www.w3.org/TR/css-grid-2/#algo-grow-tracks // 12.6. Maximize Tracks // 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). - auto free_space = get_free_space_x(available_space); + auto free_space = get_free_space(track_available_size, tracks); while (free_space > 0) { - auto free_space_to_distribute_per_track = free_space / (m_grid_columns.size() - count_of_gap_columns()); - for (auto& grid_column : m_grid_columns) { - if (grid_column.is_gap) + auto free_space_to_distribute_per_track = free_space / (tracks.size() - count_of_gap_tracks(tracks)); + for (auto& track : tracks) { + if (track.is_gap) continue; - if (grid_column.growth_limit != -1) - grid_column.base_size = min(grid_column.growth_limit, grid_column.base_size + free_space_to_distribute_per_track); + if (track.growth_limit != -1) + track.base_size = min(track.growth_limit, track.base_size + free_space_to_distribute_per_track); else - grid_column.base_size = grid_column.base_size + free_space_to_distribute_per_track; + track.base_size = track.base_size + free_space_to_distribute_per_track; } - if (get_free_space_x(available_space) == free_space) + if (get_free_space(track_available_size, tracks) == free_space) break; - free_space = get_free_space_x(available_space); + free_space = get_free_space(track_available_size, tracks); } // For the purpose of this step: if sizing the grid container under a max-content constraint, the @@ -1048,25 +1066,25 @@ void GridFormattingContext::calculate_sizes_of_columns(Box const& box, Available // the available space. // First, find the grid’s used flex fraction: - auto column_flex_factor_sum = 0; - for (auto& grid_column : m_grid_columns) { - if (grid_column.min_track_sizing_function.is_flexible_length()) - column_flex_factor_sum++; + auto flex_factor_sum = 0; + for (auto& track : tracks) { + if (track.min_track_sizing_function.is_flexible_length()) + flex_factor_sum++; } // See 12.7.1. // Let flex factor sum be the sum of the flex factors of the flexible tracks. If this value is less // than 1, set it to 1 instead. - if (column_flex_factor_sum < 1) - column_flex_factor_sum = 1; + if (flex_factor_sum < 1) + flex_factor_sum = 1; // See 12.7.1. CSSPixels sized_column_widths = 0; - for (auto& grid_column : m_grid_columns) { - if (!grid_column.min_track_sizing_function.is_flexible_length()) - sized_column_widths += grid_column.base_size; + for (auto& track : tracks) { + if (!track.min_track_sizing_function.is_flexible_length()) + sized_column_widths += track.base_size; } // Let leftover space be the space to fill minus the base sizes of the non-flexible grid tracks. - CSSPixels free_horizontal_space = available_space.width.is_definite() ? available_space.width.to_px() - sized_column_widths : 0; + CSSPixels leftover_space = track_available_size.is_definite() ? track_available_size.to_px() - sized_column_widths : 0; // If the free space is zero or if sizing the grid container under a min-content constraint: // The used flex fraction is zero. @@ -1075,15 +1093,15 @@ void GridFormattingContext::calculate_sizes_of_columns(Box const& box, Available // Otherwise, if the free space is a definite length: // The used flex fraction is the result of finding the size of an fr using all of the grid tracks // and a space to fill of the available grid space. - if (free_horizontal_space > 0) { - for (auto& grid_column : m_grid_columns) { - if (grid_column.min_track_sizing_function.is_flexible_length()) { + if (leftover_space > 0) { + for (auto& track : tracks) { + if (track.min_track_sizing_function.is_flexible_length()) { // See 12.7.1. // Let the hypothetical fr size be the leftover space divided by the flex factor sum. - auto hypothetical_fr_size = free_horizontal_space / column_flex_factor_sum; + auto hypothetical_fr_size = leftover_space / flex_factor_sum; // For each flexible track, if the product of the used flex fraction and the track’s flex factor is // greater than the track’s base size, set its base size to that product. - grid_column.base_size = max(grid_column.base_size, hypothetical_fr_size); + track.base_size = max(track.base_size, hypothetical_fr_size); } } } @@ -1133,21 +1151,22 @@ void GridFormattingContext::calculate_sizes_of_columns(Box const& box, Available // positive, definite free space equally amongst them. If the free space is indefinite, but the grid // container has a definite min-width/height, use that size to calculate the free space for this // step instead. - CSSPixels used_horizontal_space = 0; - for (auto& grid_column : m_grid_columns) { - if (!(grid_column.max_track_sizing_function.is_length() && grid_column.max_track_sizing_function.length().is_auto())) - used_horizontal_space += grid_column.base_size; + CSSPixels used_space = 0; + for (auto& track : tracks) { + if (!(track.max_track_sizing_function.is_length() && track.max_track_sizing_function.length().is_auto())) + used_space += track.base_size; } - CSSPixels remaining_horizontal_space = available_space.width.is_definite() ? available_space.width.to_px() - used_horizontal_space : 0; - auto count_of_auto_max_column_tracks = 0; - for (auto& grid_column : m_grid_columns) { - if (grid_column.max_track_sizing_function.is_length() && grid_column.max_track_sizing_function.length().is_auto()) - count_of_auto_max_column_tracks++; + CSSPixels remaining_space = track_available_size.is_definite() ? track_available_size.to_px() - used_space : 0; + auto count_of_auto_max_sizing_tracks = 0; + for (auto& track : tracks) { + if (track.max_track_sizing_function.is_length() && track.max_track_sizing_function.length().is_auto()) + count_of_auto_max_sizing_tracks++; } - for (auto& grid_column : m_grid_columns) { - if (grid_column.max_track_sizing_function.is_length() && grid_column.max_track_sizing_function.length().is_auto()) - grid_column.base_size = max(grid_column.base_size, remaining_horizontal_space / count_of_auto_max_column_tracks); + + for (auto& track : tracks) { + if (track.max_track_sizing_function.is_length() && track.max_track_sizing_function.length().is_auto()) + track.base_size = max(track.base_size, remaining_space / count_of_auto_max_sizing_tracks); } // If calculating the layout of a grid item in this step depends on the available space in the block @@ -1157,453 +1176,6 @@ void GridFormattingContext::calculate_sizes_of_columns(Box const& box, Available // spanned by such items; otherwise ignore the effects of track alignment in this estimation. } -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; - // For each track, if the track’s min track sizing function is: - switch (grid_row.min_track_sizing_function.type()) { - // - A fixed sizing function - // Resolve to an absolute length and use that size as the track’s initial base size. - case CSS::GridSize::Type::Length: - if (!grid_row.min_track_sizing_function.length().is_auto()) - grid_row.base_size = grid_row.min_track_sizing_function.length().to_px(box); - break; - case CSS::GridSize::Type::Percentage: - grid_row.base_size = grid_row.min_track_sizing_function.percentage().as_fraction() * box_state.content_height(); - break; - // - An intrinsic sizing function - // Use an initial base size of zero. - case CSS::GridSize::Type::FlexibleLength: - case CSS::GridSize::Type::MaxContent: - case CSS::GridSize::Type::MinContent: - break; - default: - VERIFY_NOT_REACHED(); - } - - // For each track, if the track’s max track sizing function is: - switch (grid_row.max_track_sizing_function.type()) { - // - A fixed sizing function - // Resolve to an absolute length and use that size as the track’s initial growth limit. - case CSS::GridSize::Type::Length: - if (!grid_row.max_track_sizing_function.length().is_auto()) - grid_row.growth_limit = grid_row.max_track_sizing_function.length().to_px(box); - else - // - An intrinsic sizing function - // Use an initial growth limit of infinity. - grid_row.growth_limit = -1; - break; - case CSS::GridSize::Type::Percentage: - grid_row.growth_limit = grid_row.max_track_sizing_function.percentage().as_fraction() * box_state.content_height(); - break; - // - A flexible sizing function - // Use an initial growth limit of infinity. - case CSS::GridSize::Type::FlexibleLength: - grid_row.growth_limit = -1; - break; - // - An intrinsic sizing function - // Use an initial growth limit of infinity. - case CSS::GridSize::Type::MaxContent: - case CSS::GridSize::Type::MinContent: - grid_row.growth_limit = -1; - break; - default: - VERIFY_NOT_REACHED(); - } - - // In all cases, if the growth limit is less than the base size, increase the growth limit to match - // the base size. - if (grid_row.growth_limit != -1 && grid_row.growth_limit < grid_row.base_size) - grid_row.growth_limit = grid_row.base_size; - } - - // https://www.w3.org/TR/css-grid-2/#algo-content - // 12.5. Resolve Intrinsic Track Sizes - // This step resolves intrinsic track sizing functions to absolute lengths. First it resolves those - // sizes based on items that are contained wholly within a single track. Then it gradually adds in - // the space requirements of items that span multiple tracks, evenly distributing the extra space - // across those tracks insofar as possible. - - // FIXME: 1. Shim baseline-aligned items so their intrinsic size contributions reflect their baseline - // alignment. For the items in each baseline-sharing group, add a “shim” (effectively, additional - // margin) on the start/end side (for first/last-baseline alignment) of each item so that, when - // start/end-aligned together their baselines align as specified. - - // Consider these “shims” as part of the items’ intrinsic size contribution for the purpose of track - // sizing, below. If an item uses multiple intrinsic size contributions, it can have different shims - // for each one. - - // 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: - auto index = 0; - for (auto& grid_row : m_grid_rows) { - if (grid_row.is_gap) { - ++index; - continue; - } - - Vector grid_items_of_row; - for (auto& grid_item : m_grid_items) { - if (grid_item.gap_adjusted_row(box) == index && grid_item.raw_row_span() == 1) { - grid_items_of_row.append(grid_item); - grid_row.border_top = max(grid_row.border_top, grid_item.box().computed_values().border_top().width); - grid_row.border_bottom = max(grid_row.border_bottom, grid_item.box().computed_values().border_bottom().width); - } - } - - if (!grid_row.min_track_sizing_function.is_intrinsic_track_sizing() && !grid_row.max_track_sizing_function.is_intrinsic_track_sizing()) { - ++index; - continue; - } - - switch (grid_row.min_track_sizing_function.type()) { - // - For min-content minimums: - // If the track has a min-content min track sizing function, set its base size to the maximum of the - // items’ min-content contributions, floored at zero. - case CSS::GridSize::Type::MinContent: { - CSSPixels row_height = 0; - for (auto& grid_item : grid_items_of_row) - row_height = max(row_height, content_based_minimum_height(grid_item, box)); - grid_row.base_size = row_height; - } break; - // - For max-content minimums: - // If the track has a max-content min track sizing function, set its base size to the maximum of the - // items’ max-content contributions, floored at zero. - case CSS::GridSize::Type::MaxContent: { - CSSPixels row_height = 0; - for (auto& grid_item : grid_items_of_row) - row_height = max(row_height, content_based_minimum_height(grid_item, box)); - grid_row.base_size = row_height; - } break; - // - For auto minimums: - // If the track has an auto min track sizing function and the grid container is being sized under a - // min-/max-content constraint, set the track’s base size to the maximum of its items’ limited - // min-/max-content contributions (respectively), floored at zero. The limited min-/max-content - // contribution of an item is (for this purpose) its min-/max-content contribution (accordingly), - // limited by the max track sizing function (which could be the argument to a fit-content() track - // sizing function) if that is fixed and ultimately floored by its minimum contribution (defined - // below). - // FIXME: Container min/max-content - case CSS::GridSize::Type::Length: - // Otherwise, set the track’s base size to the maximum of its items’ minimum contributions, floored - // at zero. The minimum contribution of an item is the smallest outer size it can have. - // Specifically, if the item’s computed preferred size behaves as auto or depends on the size of its - // containing block in the relevant axis, its minimum contribution is the outer size that would - // result from assuming the item’s used minimum size as its preferred size; else the item’s minimum - // contribution is its min-content contribution. Because the minimum contribution often depends on - // the size of the item’s content, it is considered a type of intrinsic size contribution. - case CSS::GridSize::Type::Percentage: - case CSS::GridSize::Type::FlexibleLength: { - CSSPixels grid_row_height = 0; - for (auto& grid_item : grid_items_of_row) - grid_row_height = max(grid_row_height, content_based_minimum_height(grid_item, box)); - grid_row.base_size = grid_row_height; - } break; - default: - VERIFY_NOT_REACHED(); - } - - switch (grid_row.max_track_sizing_function.type()) { - // - For min-content maximums: - // If the track has a min-content max track sizing function, set its growth limit to the maximum of - // the items’ min-content contributions. - case CSS::GridSize::Type::MinContent: { - CSSPixels row_height = 0; - for (auto& grid_item : grid_items_of_row) - row_height = max(row_height, content_based_minimum_height(grid_item, box)); - grid_row.base_size = row_height; - } break; - // - For max-content maximums: - // If the track has a max-content max track sizing function, set its growth limit to the maximum of - // the items’ max-content contributions. For fit-content() maximums, furthermore clamp this growth - // limit by the fit-content() argument. - case CSS::GridSize::Type::MaxContent: { - CSSPixels row_height = 0; - for (auto& grid_item : grid_items_of_row) - row_height = max(row_height, content_based_minimum_height(grid_item, box)); - grid_row.base_size = row_height; - } break; - case CSS::GridSize::Type::Length: - case CSS::GridSize::Type::Percentage: - case CSS::GridSize::Type::FlexibleLength: - break; - default: - VERIFY_NOT_REACHED(); - } - - // In all cases, if a track’s growth limit is now less than its base size, increase the growth limit - // to match the base size. - if (grid_row.growth_limit != -1 && grid_row.growth_limit < grid_row.base_size) - grid_row.growth_limit = grid_row.base_size; - ++index; - } - - // https://www.w3.org/TR/css-grid-2/#auto-repeat - // 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.) - - // 3. Increase sizes to accommodate spanning items crossing content-sized tracks: Next, consider the - // items with a span of 2 that do not span a track with a flexible sizing function. - // FIXME: Content-sized tracks not implemented (min-content, etc.) - - // 3.1. For intrinsic minimums: First increase the base size of tracks with an intrinsic min track sizing - // function by distributing extra space as needed to accommodate these items’ minimum contributions. - - // If the grid container is being sized under a min- or max-content constraint, use the items’ - // limited min-content contributions in place of their minimum contributions here. (For an item - // spanning multiple tracks, the upper limit used to calculate its limited min-/max-content - // contribution is the sum of the fixed max track sizing functions of any tracks it spans, and is - // applied if it only spans such tracks.) - - // 3.2. For content-based minimums: Next continue to increase the base size of tracks with a min track - // sizing function of min-content or max-content by distributing extra space as needed to account - // for these items' min-content contributions. - - // 3.3. For max-content minimums: Next, if the grid container is being sized under a max-content - // constraint, continue to increase the base size of tracks with a min track sizing function of auto - // or max-content by distributing extra space as needed to account for these items' limited - // max-content contributions. - - // In all cases, continue to increase the base size of tracks with a min track sizing function of - // max-content by distributing extra space as needed to account for these items' max-content - // contributions. - - // 3.4. If at this point any track’s growth limit is now less than its base size, increase its growth - // limit to match its base size. - - // 3.5. For intrinsic maximums: Next increase the growth limit of tracks with an intrinsic max track - // sizing function by distributing extra space as needed to account for these items' min-content - // contributions. Mark any tracks whose growth limit changed from infinite to finite in this step as - // infinitely growable for the next step. - - // 3.6. For max-content maximums: Lastly continue to increase the growth limit of tracks with a max track - // sizing function of max-content by distributing extra space as needed to account for these items' - // max-content contributions. However, limit the growth of any fit-content() tracks by their - // fit-content() argument. - - // Repeat incrementally for items with greater spans until all items have been considered. - - // FIXME: 4. Increase sizes to accommodate spanning items crossing flexible tracks: Next, repeat the previous - // step instead considering (together, rather than grouped by span size) all items that do span a - // track with a flexible sizing function while - - // - distributing space only to flexible tracks (i.e. treating all other tracks as having a fixed - // sizing function) - - // - if the sum of the flexible sizing functions of all flexible tracks spanned by the item is greater - // than zero, distributing space to such tracks according to the ratios of their flexible sizing - // functions rather than distributing space equally - - // FIXME: 5. If any track still has an infinite growth limit (because, for example, it had no items placed in - // it or it is a flexible track), set its growth limit to its base size. - - // https://www.w3.org/TR/css-grid-2/#extra-space - // 12.5.1. Distributing Extra Space Across Spanned Tracks - // To distribute extra space by increasing the affected sizes of a set of tracks as required by a - // set of intrinsic size contributions, - - // 1. Maintain separately for each affected base size or growth limit a planned increase, initially - // set to 0. (This prevents the size increases from becoming order-dependent.) - - // 2. For each considered item, - - // 2.1. Find the space to distribute: Subtract the corresponding size (base size or growth limit) of - // every spanned track from the item’s size contribution to find the item’s remaining size - // contribution. (For infinite growth limits, substitute the track’s base size.) This is the space - // to distribute. Floor it at zero. - - // For base sizes, the limit is its growth limit. For growth limits, the limit is infinity if it is - // marked as infinitely growable, and equal to the growth limit otherwise. If the affected size was - // a growth limit and the track is not marked infinitely growable, then each item-incurred increase - // will be zero. - // extra-space = max(0, size-contribution - ∑track-sizes) - - // 2.2. Distribute space up to limits: Find the item-incurred increase for each spanned track with an - // affected size by: distributing the space equally among such tracks, freezing a track’s - // item-incurred increase as its affected size + item-incurred increase reaches its limit (and - // continuing to grow the unfrozen tracks as needed). - - // 2.3. Distribute space beyond limits: If space remains after all tracks are frozen, unfreeze and - // continue to distribute space to the item-incurred increase of… - - // - when accommodating minimum contributions or accommodating min-content contributions: any affected - // track that happens to also have an intrinsic max track sizing function; if there are no such - // tracks, then all affected tracks. - - // - when accommodating max-content contributions: any affected track that happens to also have a - // max-content max track sizing function; if there are no such tracks, then all affected tracks. - - // - when handling any intrinsic growth limit: all affected tracks. - - // For this purpose, the max track sizing function of a fit-content() track is treated as - // max-content until it reaches the limit specified as the fit-content() argument, after which it is - // treated as having a fixed sizing function of that argument. - - // This step prioritizes the distribution of space for accommodating space required by the - // tracks’ min track sizing functions beyond their current growth limits based on the types of their - // max track sizing functions. - - // 3. Update the tracks' affected sizes by adding in the planned increase so that the next round of - // space distribution will account for the increase. (If the affected size is an infinite growth - // limit, set it to the track’s base size plus the planned increase.) - // FIXME: Do for rows. - - // https://www.w3.org/TR/css-grid-2/#algo-grow-tracks - // 12.6. Maximize Tracks - - // 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). - - 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) { - if (grid_row.is_gap) - continue; - grid_row.base_size = min(grid_row.growth_limit, grid_row.base_size + free_space_to_distribute_per_track); - } - if (get_free_space_y(box) == free_space) - break; - free_space = get_free_space_y(box); - } - if (free_space == -1) { - for (auto& grid_row : m_grid_rows) { - if (grid_row.is_gap) - continue; - if (grid_row.growth_limit != -1) - grid_row.base_size = grid_row.growth_limit; - } - } - - // For the purpose of this step: if sizing the grid container under a max-content constraint, the - // free space is infinite; if sizing under a min-content constraint, the free space is zero. - - // If this would cause the grid to be larger than the grid container’s inner size as limited by its - // max-width/height, then redo this step, treating the available grid space as equal to the grid - // container’s inner size when it’s sized to its max-width/height. - - // https://drafts.csswg.org/css-grid/#algo-flex-tracks - // 12.7. Expand Flexible Tracks - // This step sizes flexible tracks using the largest value it can assign to an fr without exceeding - // the available space. - - // First, find the grid’s used flex fraction: - auto row_flex_factor_sum = 0; - for (auto& grid_row : m_grid_rows) { - if (grid_row.min_track_sizing_function.is_flexible_length()) - row_flex_factor_sum++; - } - // See 12.7.1. - // Let flex factor sum be the sum of the flex factors of the flexible tracks. If this value is less - // than 1, set it to 1 instead. - if (row_flex_factor_sum < 1) - row_flex_factor_sum = 1; - - // See 12.7.1. - CSSPixels sized_row_heights = 0; - for (auto& grid_row : m_grid_rows) { - if (!grid_row.min_track_sizing_function.is_flexible_length()) - sized_row_heights += grid_row.base_size; - } - // Let leftover space be the space to fill minus the base sizes of the non-flexible grid tracks. - CSSPixels free_vertical_space = CSSPixels(box_state.content_height()) - sized_row_heights; - - // If the free space is zero or if sizing the grid container under a min-content constraint: - // The used flex fraction is zero. - // FIXME: Add min-content constraint check. - - // Otherwise, if the free space is a definite length: - // The used flex fraction is the result of finding the size of an fr using all of the grid tracks - // and a space to fill of the available grid space. - if (free_vertical_space > 0) { - for (auto& grid_row : m_grid_rows) { - if (grid_row.min_track_sizing_function.is_flexible_length()) { - // See 12.7.1. - // Let the hypothetical fr size be the leftover space divided by the flex factor sum. - auto hypothetical_fr_size = free_vertical_space / row_flex_factor_sum; - // For each flexible track, if the product of the used flex fraction and the track’s flex factor is - // greater than the track’s base size, set its base size to that product. - grid_row.base_size = max(grid_row.base_size, hypothetical_fr_size); - } - } - } - - // Otherwise, if the free space is an indefinite length: - // FIXME: No tracks will have indefinite length as per current implementation. - - // The used flex fraction is the maximum of: - // For each flexible track, if the flexible track’s flex factor is greater than one, the result of - // dividing the track’s base size by its flex factor; otherwise, the track’s base size. - - // For each grid item that crosses a flexible track, the result of finding the size of an fr using - // all the grid tracks that the item crosses and a space to fill of the item’s max-content - // contribution. - - // If using this flex fraction would cause the grid to be smaller than the grid container’s - // min-width/height (or larger than the grid container’s max-width/height), then redo this step, - // treating the free space as definite and the available grid space as equal to the grid container’s - // inner size when it’s sized to its min-width/height (max-width/height). - - // For each flexible track, if the product of the used flex fraction and the track’s flex factor is - // greater than the track’s base size, set its base size to that product. - - // https://drafts.csswg.org/css-grid/#algo-find-fr-size - // 12.7.1. Find the Size of an fr - - // This algorithm finds the largest size that an fr unit can be without exceeding the target size. - // It must be called with a set of grid tracks and some quantity of space to fill. - - // 1. Let leftover space be the space to fill minus the base sizes of the non-flexible grid tracks. - - // 2. Let flex factor sum be the sum of the flex factors of the flexible tracks. If this value is less - // than 1, set it to 1 instead. - - // 3. Let the hypothetical fr size be the leftover space divided by the flex factor sum. - - // FIXME: 4. If the product of the hypothetical fr size and a flexible track’s flex factor is less than the - // track’s base size, restart this algorithm treating all such tracks as inflexible. - - // 5. Return the hypothetical fr size. - - // https://drafts.csswg.org/css-grid/#algo-stretch - // 12.8. Stretch auto Tracks - - // When the content-distribution property of the grid container is normal or stretch in this axis, - // this step expands tracks that have an auto max track sizing function by dividing any remaining - // positive, definite free space equally amongst them. If the free space is indefinite, but the grid - // container has a definite min-width/height, use that size to calculate the free space for this - // step instead. - CSSPixels used_vertical_space = 0; - for (auto& grid_row : m_grid_rows) { - if (!(grid_row.max_track_sizing_function.is_length() && grid_row.max_track_sizing_function.length().is_auto())) - used_vertical_space += grid_row.base_size; - } - - CSSPixels remaining_vertical_space = CSSPixels(box_state.content_height()) - used_vertical_space; - auto count_of_auto_max_row_tracks = 0; - for (auto& grid_row : m_grid_rows) { - if (grid_row.max_track_sizing_function.is_length() && grid_row.max_track_sizing_function.length().is_auto()) - count_of_auto_max_row_tracks++; - } - for (auto& grid_row : m_grid_rows) { - if (grid_row.is_gap) - continue; - 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); - if (grid_row.full_vertical_size() > grid_row.growth_limit && grid_row.growth_limit != -1) - grid_row.base_size = max(CSSPixels(0), grid_row.base_size + (grid_row.growth_limit - grid_row.full_vertical_size())); - if (grid_row.min_track_sizing_function.is_length() && !grid_row.min_track_sizing_function.length().is_auto() && grid_row.full_vertical_size() > grid_row.min_track_sizing_function.length().to_px(box) && free_space != -1) - grid_row.base_size = max(CSSPixels(0), grid_row.base_size + (grid_row.min_track_sizing_function.length().to_px(box) - grid_row.full_vertical_size())); - } -} - void GridFormattingContext::build_valid_grid_areas(Box const& box) { Vector found_grid_areas; @@ -1803,7 +1375,7 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const // 4. Expand Flexible Tracks // 5. Expand Stretched auto Tracks - calculate_sizes_of_columns(box, available_space); + run_track_sizing(GridDimension::Column, available_space, m_grid_columns); // https://www.w3.org/TR/css-grid-2/#algo-overview // 12.1. Grid Sizing Algorithm @@ -1836,7 +1408,7 @@ void GridFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const // 4. Expand Flexible Tracks // 5. Expand Stretched auto Tracks - calculate_sizes_of_rows(box); + run_track_sizing(GridDimension::Row, available_space, m_grid_rows); // https://www.w3.org/TR/css-grid-2/#algo-overview // 12.1. Grid Sizing Algorithm @@ -1950,34 +1522,19 @@ bool GridFormattingContext::is_auto_positioned_track(CSS::GridTrackPlacement con return grid_track_start.is_auto_positioned() && grid_track_end.is_auto_positioned(); } -CSSPixels GridFormattingContext::get_free_space_x(AvailableSpace const& available_space) +CSSPixels GridFormattingContext::get_free_space(AvailableSize const& available_size, Vector const& tracks) const { // https://www.w3.org/TR/css-grid-2/#algo-terms // free space: Equal to the available grid space minus the sum of the base sizes of all the grid // tracks (including gutters), floored at zero. If available grid space is indefinite, the free // space is indefinite as well. // FIXME: do indefinite space - if (!available_space.width.is_definite()) + if (!available_size.is_definite()) return 0; CSSPixels sum_base_sizes = 0; - for (auto& grid_column : m_grid_columns) - sum_base_sizes += grid_column.base_size; - return max(CSSPixels(0), available_space.width.to_px() - sum_base_sizes); -} - -CSSPixels GridFormattingContext::get_free_space_y(Box const& box) -{ - // https://www.w3.org/TR/css-grid-2/#algo-terms - // free space: Equal to the available grid space minus the sum of the base sizes of all the grid - // tracks (including gutters), floored at zero. If available grid space is indefinite, the free - // space is indefinite as well. - CSSPixels sum_base_sizes = 0; - for (auto& grid_row : m_grid_rows) - sum_base_sizes += grid_row.base_size; - auto& box_state = m_state.get_mutable(box); - if (box_state.has_definite_height()) - return max(CSSPixels(0), CSSPixels(absolute_content_rect(box, m_state).height()) - sum_base_sizes); - return -1; + for (auto& track : tracks) + sum_base_sizes += track.base_size; + return max(CSSPixels(0), available_size.to_px() - sum_base_sizes); } int GridFormattingContext::get_line_index_by_line_name(String const& needle, CSS::GridTrackSizeList grid_track_size_list) @@ -2071,18 +1628,18 @@ bool OccupationGrid::is_occupied(int column_index, int row_index) return m_occupation_grid[row_index][column_index]; } -int GridItem::gap_adjusted_row(Box const& parent_box) const +int GridItem::gap_adjusted_row(Box const& grid_box) const { - return parent_box.computed_values().row_gap().is_auto() ? m_row : m_row * 2; + return grid_box.computed_values().row_gap().is_auto() ? m_row : m_row * 2; } -int GridItem::gap_adjusted_column(Box const& parent_box) const +int GridItem::gap_adjusted_column(Box const& grid_box) const { - return parent_box.computed_values().column_gap().is_auto() ? m_column : m_column * 2; + return grid_box.computed_values().column_gap().is_auto() ? m_column : m_column * 2; } // https://www.w3.org/TR/css-grid-2/#min-size-auto -CSSPixels GridFormattingContext::content_based_minimum_height(GridItem const& item, Box const& parent_box) +CSSPixels GridFormattingContext::content_based_minimum_height(GridItem const& item) { // The content-based minimum size for a grid item in a given dimension is its specified size suggestion if it exists if (!item.box().computed_values().height().is_auto()) { @@ -2091,7 +1648,7 @@ CSSPixels GridFormattingContext::content_based_minimum_height(GridItem const& it } // FIXME: otherwise its transferred size suggestion if that exists // else its content size suggestion - return calculate_min_content_height(item.box(), AvailableSize::make_definite(m_grid_columns[item.gap_adjusted_column(parent_box)].base_size)); + return calculate_min_content_height(item.box(), AvailableSize::make_definite(m_grid_columns[item.gap_adjusted_column(grid_container())].base_size)); } } diff --git a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h index e34b2599ea..f04ee26e15 100644 --- a/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/GridFormattingContext.h @@ -11,6 +11,11 @@ namespace Web::Layout { +enum class GridDimension { + Row, + Column +}; + class OccupationGrid { public: OccupationGrid(int column_count, int row_count); @@ -45,8 +50,8 @@ public: int raw_row_span() { return m_row_span; } int raw_column_span() { return m_column_span; } - int gap_adjusted_row(Box const& parent_box) const; - int gap_adjusted_column(Box const& parent_box) const; + int gap_adjusted_row(Box const& grid_box) const; + int gap_adjusted_column(Box const& grid_box) const; private: JS::NonnullGCPtr m_box; @@ -65,6 +70,8 @@ public: virtual CSSPixels automatic_content_width() const override; virtual CSSPixels automatic_content_height() const override; + Box const& grid_container() const { return context_box(); } + private: CSSPixels m_automatic_content_height { 0 }; bool is_auto_positioned_row(CSS::GridTrackPlacement const&, CSS::GridTrackPlacement const&) const; @@ -138,13 +145,11 @@ private: Vector m_grid_items; Vector> m_boxes_to_place; - CSSPixels get_free_space_x(AvailableSpace const& available_space); - CSSPixels get_free_space_y(Box const&); + CSSPixels get_free_space(AvailableSize const& available_size, Vector const& tracks) const; int get_line_index_by_line_name(String const& line_name, CSS::GridTrackSizeList); CSSPixels resolve_definite_track_size(CSS::GridSize const&, AvailableSpace const&, Box const&); - size_t count_of_gap_columns(); - size_t count_of_gap_rows(); + size_t count_of_gap_tracks(Vector const& tracks) const; CSSPixels resolve_size(CSS::Size const&, AvailableSize const&, Box const&); int count_of_repeated_auto_fill_or_fit_tracks(Vector const& track_list, AvailableSpace const&, Box const&); int get_count_of_tracks(Vector const&, AvailableSpace const&, Box const&); @@ -158,10 +163,9 @@ private: 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&); + void run_track_sizing(GridDimension const dimension, AvailableSpace const& available_space, Vector& tracks); - CSSPixels content_based_minimum_height(GridItem const&, Box const& parent_box); + CSSPixels content_based_minimum_height(GridItem const&); }; }