LibWeb: Implement distributing space to tracks beyond limits in GFC

Implements "Distribute space beyond limits" step from:
https://www.w3.org/TR/css-grid-2/#distribute-extra-space
This commit is contained in:
Aliaksandr Kalenik 2023-06-22 00:48:46 +03:00 committed by Andreas Kling
parent e3ade95d24
commit 20edbb70f8
Notes: sideshowbarker 2024-07-16 22:17:03 +09:00
4 changed files with 63 additions and 9 deletions

View file

@ -0,0 +1,9 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x33.46875 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x17.46875 children: not-inline
Box <div.container> at (8,8) content-size 784x17.46875 [GFC] children: not-inline
BlockContainer <div.item> at (8,8) content-size 28.6875x17.46875 [BFC] children: inline
line 0 width: 28.6875, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 3, rect: [8,8 28.6875x17.46875]
"one"
TextNode <#text>

View file

@ -0,0 +1,10 @@
<!DOCTYPE html><style>
.container {
display: grid;
grid-template-columns: minmax(min-content, 0px);
}
.item {
background-color: aquamarine;
}
</style><div class="container"><div class="item">one</div></div>

View file

@ -783,8 +783,10 @@ void GridFormattingContext::resolve_intrinsic_track_sizes(AvailableSpace const&
}
template<typename Match>
void GridFormattingContext::distribute_extra_space_across_spanned_tracks_base_size(CSSPixels item_size_contribution, Vector<GridTrack&>& spanned_tracks, Match matcher)
void GridFormattingContext::distribute_extra_space_across_spanned_tracks_base_size(GridDimension dimension, CSSPixels item_size_contribution, SpaceDistributionPhase phase, Vector<GridTrack&>& spanned_tracks, Match matcher)
{
auto& available_size = dimension == GridDimension::Column ? m_available_space->width : m_available_space->height;
Vector<GridTrack&> affected_tracks;
for (auto& track : spanned_tracks) {
if (matcher(track))
@ -830,7 +832,31 @@ void GridFormattingContext::distribute_extra_space_across_spanned_tracks_base_si
}
}
// FIXME: 3. Distribute space beyond limits
// 3. Distribute space beyond limits
if (extra_space > 0) {
Vector<GridTrack&> tracks_to_grow_beyond_limits;
// If space remains after all tracks are frozen, unfreeze and continue to
// distribute space to the item-incurred increase of...
if (phase == SpaceDistributionPhase::AccommodateMinimumContribution || phase == SpaceDistributionPhase::AccommodateMinContentContribution) {
// when accommodating minimum contributions or accommodating min-content contributions: any affected track
// that happens to also have an intrinsic max track sizing function
for (auto& track : affected_tracks) {
if (track.max_track_sizing_function.is_intrinsic(available_size))
tracks_to_grow_beyond_limits.append(track);
}
// if there are no such tracks, then all affected tracks.
if (tracks_to_grow_beyond_limits.size() == 0)
tracks_to_grow_beyond_limits = affected_tracks;
}
// FIXME: 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.
CSSPixels increase_per_track = extra_space / affected_tracks.size();
for (auto& track : affected_tracks)
track.item_incurred_increase += increase_per_track;
}
// 4. For each affected track, if the tracks item-incurred increase is larger than the tracks planned increase
// set the tracks planned increase to that value.
@ -935,7 +961,7 @@ void GridFormattingContext::increase_sizes_to_accommodate_spanning_items_crossin
return calculate_limited_min_content_contribution(item, dimension);
return calculate_minimum_contribution(item, dimension);
}();
distribute_extra_space_across_spanned_tracks_base_size(item_size_contribution, spanned_tracks, [&](GridTrack const& track) {
distribute_extra_space_across_spanned_tracks_base_size(dimension, item_size_contribution, SpaceDistributionPhase::AccommodateMinimumContribution, spanned_tracks, [&](GridTrack const& track) {
return track.min_track_sizing_function.is_intrinsic(available_size);
});
for (auto& track : spanned_tracks) {
@ -947,7 +973,7 @@ void GridFormattingContext::increase_sizes_to_accommodate_spanning_items_crossin
// sizing function of min-content or max-content by distributing extra space as needed to account for
// these items' min-content contributions.
auto item_min_content_contribution = calculate_min_content_contribution(item, dimension);
distribute_extra_space_across_spanned_tracks_base_size(item_min_content_contribution, spanned_tracks, [&](GridTrack const& track) {
distribute_extra_space_across_spanned_tracks_base_size(dimension, item_min_content_contribution, SpaceDistributionPhase::AccommodateMinContentContribution, spanned_tracks, [&](GridTrack const& track) {
return track.min_track_sizing_function.is_min_content() || track.min_track_sizing_function.is_max_content();
});
for (auto& track : spanned_tracks) {
@ -960,7 +986,7 @@ void GridFormattingContext::increase_sizes_to_accommodate_spanning_items_crossin
// distributing extra space as needed to account for these items' limited max-content contributions.
if (available_size.is_max_content()) {
auto item_limited_max_content_contribution = calculate_limited_max_content_contribution(item, dimension);
distribute_extra_space_across_spanned_tracks_base_size(item_limited_max_content_contribution, spanned_tracks, [&](GridTrack const& track) {
distribute_extra_space_across_spanned_tracks_base_size(dimension, item_limited_max_content_contribution, SpaceDistributionPhase::AccommodateMaxContentContribution, spanned_tracks, [&](GridTrack const& track) {
return track.min_track_sizing_function.is_auto(available_size) || track.min_track_sizing_function.is_max_content();
});
for (auto& track : spanned_tracks) {
@ -1030,9 +1056,10 @@ void GridFormattingContext::increase_sizes_to_accommodate_spanning_items_crossin
// 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.
auto item_minimum_contribution = automatic_minimum_size(item, dimension);
distribute_extra_space_across_spanned_tracks_base_size(item_minimum_contribution, spanned_tracks, [&](GridTrack const& track) {
return track.min_track_sizing_function.is_flexible_length();
});
distribute_extra_space_across_spanned_tracks_base_size(dimension,
item_minimum_contribution, SpaceDistributionPhase::AccommodateMinimumContribution, spanned_tracks, [&](GridTrack const& track) {
return track.min_track_sizing_function.is_flexible_length();
});
for (auto& track : spanned_tracks) {
track.base_size += track.planned_increase;
@ -1074,6 +1101,8 @@ void GridFormattingContext::maximize_tracks(AvailableSpace const& available_spac
while (free_space_px > 0) {
auto free_space_to_distribute_per_track = free_space_px / tracks.size();
for (auto& track : tracks) {
if (track.base_size_frozen)
continue;
VERIFY(isfinite(track.growth_limit.to_double()));
track.base_size = min(track.growth_limit, track.base_size + free_space_to_distribute_per_track);
}

View file

@ -242,8 +242,14 @@ private:
void collapse_auto_fit_tracks_if_needed(GridDimension const);
enum class SpaceDistributionPhase {
AccommodateMinimumContribution,
AccommodateMinContentContribution,
AccommodateMaxContentContribution
};
template<typename Match>
void distribute_extra_space_across_spanned_tracks_base_size(CSSPixels item_size_contribution, Vector<GridTrack&>& spanned_tracks, Match matcher);
void distribute_extra_space_across_spanned_tracks_base_size(GridDimension dimension, CSSPixels item_size_contribution, SpaceDistributionPhase phase, Vector<GridTrack&>& spanned_tracks, Match matcher);
template<typename Match>
void distribute_extra_space_across_spanned_tracks_growth_limit(CSSPixels item_size_contribution, Vector<GridTrack&>& spanned_tracks, Match matcher);