Переглянути джерело

LibWeb: Fix infinite loop in GFC growth limit distribution

This change is bd85e1b30b57e89ec058ef61833f7562514b3c9c ported from
base size to growth limit distribution.

Fixes https://github.com/SerenityOS/serenity/issues/21056
Aliaksandr Kalenik 1 рік тому
батько
коміт
693d602b2f

+ 16 - 0
Tests/LibWeb/Layout/expected/grid/should-not-hang-in-size-distribution.txt

@@ -0,0 +1,16 @@
+Viewport <#document> at (0,0) content-size 800x600 children: not-inline
+  BlockContainer <html> at (0,0) content-size 800x33.46875 [BFC] children: not-inline
+    Box <body> at (8,8) content-size 784x17.46875 [GFC] children: not-inline
+      BlockContainer <div#item> at (8,8) content-size 784x17.46875 [BFC] children: not-inline
+        BlockContainer <div#block> at (8,8) content-size 784x17.46875 children: inline
+          line 0 width: 210.484375, height: 17.46875, bottom: 17.46875, baseline: 13.53125
+            frag 0 from TextNode start: 0, length: 26, rect: [8,8 210.484375x17.46875]
+              "Taika Waititi's Best Roles"
+          TextNode <#text>
+
+ViewportPaintable (Viewport<#document>) [0,0 800x600]
+  PaintableWithLines (BlockContainer<HTML>) [0,0 800x33.46875]
+    PaintableBox (Box<BODY>) [8,8 784x17.46875]
+      PaintableWithLines (BlockContainer<DIV>#item) [8,8 784x17.46875]
+        PaintableWithLines (BlockContainer<DIV>#block) [8,8 784x17.46875]
+          TextPaintable (TextNode<#text>)

+ 17 - 0
Tests/LibWeb/Layout/input/grid/should-not-hang-in-size-distribution.html

@@ -0,0 +1,17 @@
+<!doctype html><style>    
+* {                        
+    outline: 1px solid black;              
+}    
+html {    
+    font: inherit;    
+}    
+body {     
+    display: grid;    
+}    
+#item {     
+    grid-column: span 4 / auto;    
+}    
+#block {    
+    min-width: 0px;    
+}    
+</style><body><div id="item"><div id="block">Taika Waititi's Best Roles  

+ 12 - 11
Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp

@@ -935,7 +935,7 @@ void GridFormattingContext::distribute_extra_space_across_spanned_tracks_growth_
     auto extra_space = max(CSSPixels(0), item_size_contribution - spanned_tracks_sizes_sum);
 
     // 2. Distribute space up to limits:
-    while (true) {
+    while (extra_space > 0) {
         auto all_frozen = all_of(affected_tracks, [](auto const& track) { return track.growth_limit_frozen; });
         if (all_frozen)
             break;
@@ -943,23 +943,24 @@ void GridFormattingContext::distribute_extra_space_across_spanned_tracks_growth_
         // 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
-        CSSPixels increase_per_track = extra_space / affected_tracks.size();
-        if (increase_per_track == 0)
-            break;
+        CSSPixels increase_per_track = max(CSSPixels::smallest_positive_value(), extra_space / affected_tracks.size());
         for (auto& track : affected_tracks) {
             if (track.growth_limit_frozen)
                 continue;
 
+            auto increase = min(increase_per_track, extra_space);
+
             // For growth limits, the limit is infinity if it is marked as infinitely growable, and equal to the
             // growth limit otherwise.
-            if (track.infinitely_growable || !track.growth_limit.has_value()) {
-                track.item_incurred_increase += increase_per_track;
-                extra_space -= increase_per_track;
-            } else if (track.growth_limit.has_value() && increase_per_track >= track.growth_limit.value()) {
-                track.growth_limit_frozen = true;
-                track.item_incurred_increase = track.growth_limit.value();
-                extra_space -= track.growth_limit.value();
+            if (!track.infinitely_growable && track.growth_limit.has_value()) {
+                auto maximum_increase = track.growth_limit.value() - track.base_size;
+                if (track.item_incurred_increase + increase >= maximum_increase) {
+                    track.growth_limit_frozen = true;
+                    increase = maximum_increase - track.item_incurred_increase;
+                }
             }
+            track.item_incurred_increase += increase;
+            extra_space -= increase;
         }
     }