Jelajahi Sumber

LibWeb: Implement missing step in GFC fr size calculation

Implements:
"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."

Fixes https://github.com/LadybirdBrowser/ladybird/issues/1211
Aliaksandr Kalenik 10 bulan lalu
induk
melakukan
7b2042571b

+ 17 - 0
Tests/LibWeb/Layout/expected/grid/restart-fr-algorithm-if-less-than-base-size.txt

@@ -0,0 +1,17 @@
+Viewport <#document> at (0,0) content-size 800x600 children: not-inline
+  BlockContainer <html> at (0,0) content-size 800x33 [BFC] children: not-inline
+    Box <body> at (8,8) content-size 200x17 [GFC] children: not-inline
+      BlockContainer <div> at (8,8) content-size 0x17 [BFC] children: not-inline
+      BlockContainer <div.nowrap> at (8,8) content-size 202.5x17 [BFC] children: inline
+        frag 0 from TextNode start: 0, length: 24, rect: [8,8 202.5x17] baseline: 13.296875
+            "HelloFriendsHelloFriends"
+        TextNode <#text>
+      BlockContainer <div> at (210.5,8) content-size 0x17 [BFC] children: not-inline
+
+ViewportPaintable (Viewport<#document>) [0,0 800x600]
+  PaintableWithLines (BlockContainer<HTML>) [0,0 800x33]
+    PaintableBox (Box<BODY>) [8,8 200x17] overflow: [8,8 202.5x17]
+      PaintableWithLines (BlockContainer<DIV>) [8,8 0x17]
+      PaintableWithLines (BlockContainer<DIV>.nowrap) [8,8 202.5x17]
+        TextPaintable (TextNode<#text>)
+      PaintableWithLines (BlockContainer<DIV>) [210.5,8 0x17]

+ 20 - 0
Tests/LibWeb/Layout/input/grid/restart-fr-algorithm-if-less-than-base-size.html

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<style>
+  * {
+    outline: 1px solid black;
+  }
+  html {
+    background: white;
+  }
+  body {
+    background: pink;
+    display: grid;
+    grid-template-columns: 1fr 1fr 1fr;
+    width: 200px;
+  }
+  .nowrap {
+    background: orange;
+    white-space: nowrap;
+  }
+</style>
+<body><div></div><div class="nowrap">HelloFriendsHelloFriends</div><div></div></body>

+ 40 - 23
Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp

@@ -1012,33 +1012,50 @@ void GridFormattingContext::expand_flexible_tracks(GridDimension const dimension
     // FIXME: This should idealy take a Span, as that is more idomatic, but Span does not yet support holding references
     auto find_the_size_of_an_fr = [&](Vector<GridTrack&> const& tracks, CSSPixels space_to_fill) -> CSSPixelFraction {
         // https://www.w3.org/TR/css-grid-2/#algo-find-fr-size
-
-        // 1. Let leftover space be the space to fill minus the base sizes of the non-flexible grid tracks.
-        auto leftover_space = space_to_fill;
-        for (auto& track : tracks) {
-            if (!track.max_track_sizing_function.is_flexible_length()) {
-                leftover_space -= track.base_size;
+        auto treat_track_as_inflexiable = MUST(AK::Bitmap::create(tracks.size(), false));
+        do {
+            // 1. Let leftover space be the space to fill minus the base sizes of the non-flexible grid tracks.
+            auto leftover_space = space_to_fill;
+            for (auto track_index = 0u; track_index < tracks.size(); track_index++) {
+                if (treat_track_as_inflexiable.view().get(track_index) || !tracks[track_index].max_track_sizing_function.is_flexible_length()) {
+                    leftover_space -= tracks[track_index].base_size;
+                }
             }
-        }
-
-        // 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.
-        CSSPixels flex_factor_sum = 0;
-        for (auto& track : tracks) {
-            if (track.max_track_sizing_function.is_flexible_length())
-                flex_factor_sum += CSSPixels::nearest_value_for(track.max_track_sizing_function.flex_factor());
-        }
-        if (flex_factor_sum < 1)
-            flex_factor_sum = 1;
 
-        // 3. Let the hypothetical fr size be the leftover space divided by the flex factor sum.
-        auto hypothetical_fr_size = leftover_space / flex_factor_sum;
+            // 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.
+            CSSPixels flex_factor_sum = 0;
+            for (auto track_index = 0u; track_index < tracks.size(); track_index++) {
+                if (treat_track_as_inflexiable.view().get(track_index) || !tracks[track_index].max_track_sizing_function.is_flexible_length())
+                    continue;
+                flex_factor_sum += CSSPixels::nearest_value_for(tracks[track_index].max_track_sizing_function.flex_factor());
+            }
+            if (flex_factor_sum < 1)
+                flex_factor_sum = 1;
+
+            // 3. Let the hypothetical fr size be the leftover space divided by the flex factor sum.
+            auto hypothetical_fr_size = leftover_space / flex_factor_sum;
+
+            // 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.
+            bool need_to_restart = false;
+            for (auto track_index = 0u; track_index < tracks.size(); track_index++) {
+                if (treat_track_as_inflexiable.view().get(track_index) || !tracks[track_index].max_track_sizing_function.is_flexible_length())
+                    continue;
+                auto scaled_fraction = CSSPixels::nearest_value_for(tracks[track_index].max_track_sizing_function.flex_factor()) * hypothetical_fr_size;
+                if (scaled_fraction < tracks[track_index].base_size) {
+                    treat_track_as_inflexiable.set(track_index, true);
+                    need_to_restart = true;
+                }
+            }
+            if (need_to_restart)
+                continue;
 
-        // 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.
+            return hypothetical_fr_size;
+        } while (true);
 
-        // 5. Return the hypothetical fr size.
-        return hypothetical_fr_size;
+        VERIFY_NOT_REACHED();
     };
 
     // First, find the grid’s used flex fraction: