瀏覽代碼

LibWeb: Allow infinitely long flex lines when sizing under max-content

If the flex container is being sized under a max-content main size
constraint, there is effectively infinite space available for flex
items. Thus, flex lines should be allowed to be infinitely long.

This is a little awkward, because the spec doesn't mention specifics
about how to resolve flexible lengths during intrninsic sizing.
I've marked the spec deviations with big "AD-HOC" comments.
Andreas Kling 2 年之前
父節點
當前提交
3f9cfa144c

+ 9 - 0
Tests/LibWeb/Layout/expected/flex/flex-container-intrinsic-cross-size-with-max-content-main-size.txt

@@ -0,0 +1,9 @@
+Viewport <#document> at (0,0) content-size 800x600 children: not-inline
+  BlockContainer <html> at (0,0) content-size 800x53.46875 [BFC] children: not-inline
+    BlockContainer <body.outer> at (18,18) content-size 280.84375x17.46875 children: not-inline
+      Box <div.inner> at (18,18) content-size 280.84375x17.46875 flex-container(row) [FFC] children: not-inline
+        BlockContainer <(anonymous)> at (18,18) content-size 280.84375x17.46875 flex-item [BFC] children: inline
+          line 0 width: 280.84375, height: 17.46875, bottom: 17.46875, baseline: 13.53125
+            frag 0 from TextNode start: 0, length: 35, rect: [18,18 280.84375x17.46875]
+              "this text should be all on one line"
+          TextNode <#text>

+ 12 - 0
Tests/LibWeb/Layout/input/flex/flex-container-intrinsic-cross-size-with-max-content-main-size.html

@@ -0,0 +1,12 @@
+<!doctype html><style>
+    html { background: white; }
+    .outer {
+        width: max-content;
+        padding: 10px;
+        background: pink;
+    }
+    .inner {
+        display: flex;
+        background: orange;
+    }
+</style><body class="outer"><div class="inner">this text should be all on one line

+ 24 - 2
Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp

@@ -911,6 +911,18 @@ void FlexFormattingContext::collect_flex_items_into_flex_lines()
 // https://drafts.csswg.org/css-flexbox-1/#resolve-flexible-lengths
 // https://drafts.csswg.org/css-flexbox-1/#resolve-flexible-lengths
 void FlexFormattingContext::resolve_flexible_lengths_for_line(FlexLine& line)
 void FlexFormattingContext::resolve_flexible_lengths_for_line(FlexLine& line)
 {
 {
+    // AD-HOC: The spec tells us to use the "flex container’s inner main size" in this algorithm,
+    //         but that doesn't work when we're sizing under a max-content constraint.
+    //         In that case, there is effectively infinite size available in the main axis,
+    //         but the inner main size has not been assigned yet.
+    //         We solve this by calculating our own "available main size" here, which is essentially
+    //         infinity under max-content, 0 under min-content, and the inner main size otherwise.
+    CSSPixels available_main_size;
+    if (m_available_space_for_items->main.is_intrinsic_sizing_constraint())
+        available_main_size = m_available_space_for_items->main.to_px();
+    else
+        available_main_size = inner_main_size(flex_container());
+
     // 1. Determine the used flex factor.
     // 1. Determine the used flex factor.
 
 
     // Sum the outer hypothetical main sizes of all items on the line.
     // Sum the outer hypothetical main sizes of all items on the line.
@@ -927,7 +939,9 @@ void FlexFormattingContext::resolve_flexible_lengths_for_line(FlexLine& line)
         }
         }
         // CSS-FLEXBOX-2: Account for gap between flex items.
         // CSS-FLEXBOX-2: Account for gap between flex items.
         sum += main_gap() * (line.items.size() - 1);
         sum += main_gap() * (line.items.size() - 1);
-        if (sum < inner_main_size(flex_container()))
+        // AD-HOC: Note that we're using our own "available main size" explained above
+        //         instead of the flex container’s inner main size.
+        if (sum < available_main_size)
             return FlexFactor::FlexGrowFactor;
             return FlexFactor::FlexGrowFactor;
         return FlexFactor::FlexShrinkFactor;
         return FlexFactor::FlexShrinkFactor;
     }();
     }();
@@ -973,7 +987,10 @@ void FlexFormattingContext::resolve_flexible_lengths_for_line(FlexLine& line)
         }
         }
         // CSS-FLEXBOX-2: Account for gap between flex items.
         // CSS-FLEXBOX-2: Account for gap between flex items.
         sum += main_gap() * (line.items.size() - 1);
         sum += main_gap() * (line.items.size() - 1);
-        return inner_main_size(flex_container()) - sum;
+
+        // AD-HOC: Note that we're using our own "available main size" explained above
+        //         instead of the flex container’s inner main size.
+        return available_main_size - sum;
     };
     };
     auto const initial_free_space = calculate_remaining_free_space();
     auto const initial_free_space = calculate_remaining_free_space();
 
 
@@ -1101,6 +1118,11 @@ void FlexFormattingContext::resolve_flexible_lengths_for_line(FlexLine& line)
     // NOTE: Calculate the remaining free space once again here, since it's needed later when aligning items.
     // NOTE: Calculate the remaining free space once again here, since it's needed later when aligning items.
     line.remaining_free_space = calculate_remaining_free_space();
     line.remaining_free_space = calculate_remaining_free_space();
 
 
+    // AD-HOC: Due to the way we calculate the remaining free space, it can be infinite when sizing
+    //         under a max-content constraint. In that case, we can simply set it to zero here.
+    if (!isfinite(line.remaining_free_space.value()))
+        line.remaining_free_space = 0;
+
     // 6. Set each item’s used main size to its target main size.
     // 6. Set each item’s used main size to its target main size.
     for (auto& item : line.items) {
     for (auto& item : line.items) {
         item.main_size = item.target_main_size;
         item.main_size = item.target_main_size;