Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 13ce6a6997552903710c15201202a8fb7907d5df
      
https://github.com/WebKit/WebKit/commit/13ce6a6997552903710c15201202a8fb7907d5df
  Author: Issac Roy <[email protected]>
  Date:   2026-09-01 (Tue, 01 Sep 2026)

  Changed paths:
    M LayoutTests/TestExpectations
    M 
LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/balance/balance-negative-margin-002-expected.txt
    M Source/WebCore/Headers.cmake
    M Source/WebCore/Sources.txt
    M Source/WebCore/WebCore.xcodeproj/project.pbxproj
    M Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.cpp
    A Source/WebCore/layout/formattingContexts/flex/FlexLineBreaker.cpp
    A Source/WebCore/layout/formattingContexts/flex/FlexLineBreaker.h

  Log Message:
  -----------
  Implement the flex-wrap: balance line breaker
https://bugs.webkit.org/show_bug.cgi?id=323010
rdar://186274279

Reviewed by Alan Baradlay.

css-flexbox-2 9.7 asks `flex-wrap: balance` to divide flex items into lines
that minimize the sum of squared free space, instead of greedily filling each
line.

New FlexLineBreaker.{h,cpp} holds both breakers as free functions over
std::span<const LayoutUnit>, so neither needs a FlexLayoutItem or a formatting
context and both are unit-testable. greedyLineBreaks is the existing loop from
computeFlexLines moved verbatim. computeFlexLines now flattens the outer
hypothetical main sizes once, picks a breaker, and shares one loop to build
ranges and hypotheticalMainSizes.

balancedLineBreaks is a dynamic program over suffixes: minScores[start] is the
best total for items start..n, and bestEndForStart records where that line ends.
The suffix direction is what gets the tie-break right. The spec breaks ties
front-to-back -- most items on the first line, then the second -- so among equal
minima the line starting at `start` must be the longest one, which the `<=`
comparison records as the scan walks `end` upward.

Costs O(n * L) for L items on the fullest line, so quadratic only when one line
can hold most of the items. In the case that we lack performance, a better
solution for such cases is LARSCH, which is O(n) but costs a few hundred lines.

Item sizes are floored at 0 when building the prefix sums, per 9.7's closing
line. greedyLineBreaks deliberately does not floor: CSS Flexbox 1 9.3 sums outer
hypothetical main sizes as-is, and negative margins legitimately shorten a line
there. Squared free space reaches 2^62, so five near-empty lines can overflow a
uint64_t sum; totalScore saturates instead, and a saturated total never compares
better than a real one.

Two bounds keep the search off its worst case. lastFittingEnd[start] is one
two-pointer sweep giving the last item that still fits, so the inner loop runs
over items-per-line rather than n, making the whole thing O(n * L). And a
container that fits everything returns a single line immediately: no line of any
split has a smaller error, and a split sums at least as many of them.

flex-line-count is not implemented, so the 17 balance expectations that remain
are the tests requiring it. They need a second dimension on the DP plus a
measurement pass that divides the available size by the line count, and are
left for a follow-up.

Tests: imported/w3c/web-platform-tests/css/css-flexbox/balance/

* LayoutTests/TestExpectations:
* 
LayoutTests/imported/w3c/web-platform-tests/css/css-flexbox/balance/balance-negative-margin-002-expected.txt:
* Source/WebCore/Headers.cmake:
* Source/WebCore/Sources.txt:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.cpp:
(WebCore::FlexFormattingContext::computeFlexLines):
* Source/WebCore/layout/formattingContexts/flex/FlexLineBreaker.cpp: Added.
(WebCore::greedyLineBreaks):
(WebCore::balancedLineBreaks):
* Source/WebCore/layout/formattingContexts/flex/FlexLineBreaker.h: Added.

Canonical link: https://commits.webkit.org/320259@main



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications

Reply via email to