From 3f9cfa144c4a5739c68ac61b6520ee759ae44f88 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 1 Jun 2023 14:20:11 +0200 Subject: [PATCH] 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. --- ...-cross-size-with-max-content-main-size.txt | 9 +++++++ ...cross-size-with-max-content-main-size.html | 12 +++++++++ .../LibWeb/Layout/FlexFormattingContext.cpp | 26 +++++++++++++++++-- 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 Tests/LibWeb/Layout/expected/flex/flex-container-intrinsic-cross-size-with-max-content-main-size.txt create mode 100644 Tests/LibWeb/Layout/input/flex/flex-container-intrinsic-cross-size-with-max-content-main-size.html diff --git a/Tests/LibWeb/Layout/expected/flex/flex-container-intrinsic-cross-size-with-max-content-main-size.txt b/Tests/LibWeb/Layout/expected/flex/flex-container-intrinsic-cross-size-with-max-content-main-size.txt new file mode 100644 index 00000000000..3d7eda797ff --- /dev/null +++ b/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 at (0,0) content-size 800x53.46875 [BFC] children: not-inline + BlockContainer at (18,18) content-size 280.84375x17.46875 children: not-inline + Box 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> diff --git a/Tests/LibWeb/Layout/input/flex/flex-container-intrinsic-cross-size-with-max-content-main-size.html b/Tests/LibWeb/Layout/input/flex/flex-container-intrinsic-cross-size-with-max-content-main-size.html new file mode 100644 index 00000000000..9ff4ad9d24a --- /dev/null +++ b/Tests/LibWeb/Layout/input/flex/flex-container-intrinsic-cross-size-with-max-content-main-size.html @@ -0,0 +1,12 @@ +
this text should be all on one line \ No newline at end of file diff --git a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp index f8d589a70b2..7f238a9db29 100644 --- a/Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp +++ b/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 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. // 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. 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::FlexShrinkFactor; }(); @@ -973,7 +987,10 @@ void FlexFormattingContext::resolve_flexible_lengths_for_line(FlexLine& line) } // CSS-FLEXBOX-2: Account for gap between flex items. 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(); @@ -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. 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. for (auto& item : line.items) { item.main_size = item.target_main_size;