소스 검색

LibWeb: Fix infinite spinning while distributing extra space in GFC

Fixes infinite spinning in the cases when CSSPixels does not have
enough precision to represent increase per track which happens when
very small extra_space got divided by affected tracks number.
Aliaksandr Kalenik 1 년 전
부모
커밋
79cbbfc67f

+ 21 - 0
Tests/LibWeb/Layout/expected/grid/should-not-cause-infinite-spinning-in-space-distribution.txt

@@ -0,0 +1,21 @@
+Viewport <#document> at (0,0) content-size 800x600 children: not-inline
+  BlockContainer <html> at (1,1) content-size 798x56.90625 [BFC] children: not-inline
+    Box <body> at (10,10) content-size 780x38.90625 [GFC] children: not-inline
+      BlockContainer <div.foo> at (11,11) content-size 778x17.4375 [BFC] children: inline
+        line 0 width: 27.15625, height: 17.46875, bottom: 17.46875, baseline: 13.53125
+          frag 0 from TextNode start: 0, length: 3, rect: [11,11 27.15625x17.46875]
+            "foo"
+        TextNode <#text>
+      BlockContainer <div.bar> at (11,30.4375) content-size 778x17.46875 [BFC] children: inline
+        line 0 width: 27.640625, height: 17.46875, bottom: 17.46875, baseline: 13.53125
+          frag 0 from TextNode start: 0, length: 3, rect: [11,30.4375 27.640625x17.46875]
+            "bar"
+        TextNode <#text>
+
+PaintableWithLines (Viewport<#document>) [0,0 800x600]
+  PaintableWithLines (BlockContainer<HTML>) [0,0 800x58.90625]
+    PaintableBox (Box<BODY>) [9,9 782x40.90625]
+      PaintableWithLines (BlockContainer<DIV>.foo) [10,10 780x19.4375] overflow: [11,11 778x17.46875]
+        TextPaintable (TextNode<#text>)
+      PaintableWithLines (BlockContainer<DIV>.bar) [10,29.4375 780x19.46875]
+        TextPaintable (TextNode<#text>)

+ 15 - 0
Tests/LibWeb/Layout/input/grid/should-not-cause-infinite-spinning-in-space-distribution.html

@@ -0,0 +1,15 @@
+<!doctype html><style>
+* {
+    border: 1px solid black;
+}
+body {
+    display: grid;
+    grid-template-rows: repeat(10, min-content) 1fr;
+}
+.foo {
+    grid-area: 4 / 1 / 8 / 2;
+}
+.bar {
+    grid-area: 9 / 1 / 10 / 2;
+}
+</style><body><div class="foo">foo</div><div class="bar">bar</div>

+ 6 - 6
Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp

@@ -797,9 +797,7 @@ void GridFormattingContext::distribute_extra_space_across_spanned_tracks_base_si
     auto extra_space = max(CSSPixels(0), item_size_contribution - spanned_tracks_sizes_sum);
 
     // 2. Distribute space up to limits:
-    // FIXME: If a fixed-point type were used to represent CSS pixels, it would be possible to compare with 0
-    //        instead of epsilon.
-    while (extra_space > CSSPixels::epsilon()) {
+    while (true) {
         auto all_frozen = all_of(affected_tracks, [](auto const& track) { return track.base_size_frozen; });
         if (all_frozen)
             break;
@@ -808,6 +806,8 @@ void GridFormattingContext::distribute_extra_space_across_spanned_tracks_base_si
         // 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;
         for (auto& track : affected_tracks) {
             if (track.base_size_frozen)
                 continue;
@@ -887,9 +887,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:
-    // FIXME: If a fixed-point type were used to represent CSS pixels, it would be possible to compare with 0
-    //        instead of epsilon.
-    while (extra_space > CSSPixels::epsilon()) {
+    while (true) {
         auto all_frozen = all_of(affected_tracks, [](auto const& track) { return track.growth_limit_frozen; });
         if (all_frozen)
             break;
@@ -898,6 +896,8 @@ void GridFormattingContext::distribute_extra_space_across_spanned_tracks_growth_
         // 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;
         for (auto& track : affected_tracks) {
             if (track.growth_limit_frozen)
                 continue;