Title: [295039] trunk/Source/WebCore
Revision
295039
Author
za...@apple.com
Date
2022-05-30 18:26:39 -0700 (Mon, 30 May 2022)

Log Message

Move core flex layout to FlexLayout
https://bugs.webkit.org/show_bug.cgi?id=241106

Reviewed by Antti Koivisto.

* Source/WebCore/Headers.cmake:
* Source/WebCore/Sources.txt:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.cpp:
(WebCore::Layout::FlexFormattingContext::convertFlexItemsToLogicalSpace):
(WebCore::Layout::FlexFormattingContext::setFlexItemsGeometry):
(WebCore::Layout::FlexFormattingContext::layoutInFlowContentForIntegration):
(WebCore::Layout::FlexFormattingContext::computeAvailableLogicalVerticalSpace const): Deleted.
(WebCore::Layout::FlexFormattingContext::computeAvailableLogicalHorizontalSpace const): Deleted.
(WebCore::Layout::FlexFormattingContext::computeLogicalWidthForShrinkingFlexItems): Deleted.
(WebCore::Layout::FlexFormattingContext::computeLogicalWidthForStretchingFlexItems): Deleted.
(WebCore::Layout::FlexFormattingContext::computeLogicalWidthForFlexItems): Deleted.
(WebCore::Layout::FlexFormattingContext::computeLogicalHeightForFlexItems): Deleted.
(WebCore::Layout::FlexFormattingContext::alignFlexItems): Deleted.
(WebCore::Layout::FlexFormattingContext::justifyFlexItems): Deleted.
* Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.h:
* Source/WebCore/layout/formattingContexts/flex/FlexLayout.cpp: Added.
(WebCore::Layout::FlexLayout::FlexLayout):
(WebCore::Layout::FlexLayout::computeAvailableLogicalVerticalSpace const):
(WebCore::Layout::FlexLayout::computeAvailableLogicalHorizontalSpace const):
(WebCore::Layout::FlexLayout::computeLogicalWidthForShrinkingFlexItems):
(WebCore::Layout::FlexLayout::computeLogicalWidthForStretchingFlexItems):
(WebCore::Layout::FlexLayout::computeLogicalWidthForFlexItems):
(WebCore::Layout::FlexLayout::computeLogicalHeightForFlexItems):
(WebCore::Layout::FlexLayout::alignFlexItems):
(WebCore::Layout::FlexLayout::justifyFlexItems):
(WebCore::Layout::FlexLayout::layout):
* Source/WebCore/layout/formattingContexts/flex/FlexLayout.h: Copied from Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.h.
(WebCore::Layout::FlexLayout::formattingState const):
(WebCore::Layout::FlexLayout::flexBoxStyle const):

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

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/Headers.cmake (295038 => 295039)


--- trunk/Source/WebCore/Headers.cmake	2022-05-30 23:59:45 UTC (rev 295038)
+++ trunk/Source/WebCore/Headers.cmake	2022-05-31 01:26:39 UTC (rev 295039)
@@ -982,6 +982,7 @@
 
     layout/formattingContexts/flex/FlexFormattingConstraints.h
     layout/formattingContexts/flex/FlexFormattingState.h
+    layout/formattingContexts/flex/FlexLayout.h
 
     layout/formattingContexts/inline/display/InlineDisplayBox.h
     layout/formattingContexts/inline/InlineRect.h

Modified: trunk/Source/WebCore/Sources.txt (295038 => 295039)


--- trunk/Source/WebCore/Sources.txt	2022-05-30 23:59:45 UTC (rev 295038)
+++ trunk/Source/WebCore/Sources.txt	2022-05-31 01:26:39 UTC (rev 295039)
@@ -1567,6 +1567,7 @@
 layout/formattingContexts/block/tablewrapper/TableWrapperBlockFormattingQuirks.cpp
 layout/formattingContexts/flex/FlexFormattingContext.cpp
 layout/formattingContexts/flex/FlexFormattingGeometry.cpp
+layout/formattingContexts/flex/FlexLayout.cpp
 layout/formattingContexts/flex/FlexFormattingState.cpp
 layout/floats/FloatAvoider.cpp
 layout/floats/FloatingContext.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (295038 => 295039)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2022-05-30 23:59:45 UTC (rev 295038)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2022-05-31 01:26:39 UTC (rev 295039)
@@ -2220,6 +2220,7 @@
 		6ED878C5147493F4004C3597 /* RenderTableCaption.h in Headers */ = {isa = PBXBuildFile; fileRef = 6ED878C3147493F4004C3597 /* RenderTableCaption.h */; };
 		6ED8C37A183BFF8C009E53BD /* BoxShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 6ED8C378183BFF8C009E53BD /* BoxShape.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		6EE8A77310F803F3005A4A24 /* JSWebGLContextAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = 6EE8A77110F803F3005A4A24 /* JSWebGLContextAttributes.h */; };
+		6F047A9228453EDB00C25EE7 /* FlexLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F047A9128453EDB00C25EE7 /* FlexLayout.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		6F0B98B523F268EC00EEC2F2 /* LayoutInlineTextBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F0B98B323F268EB00EEC2F2 /* LayoutInlineTextBox.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		6F0CD695229ED32700C5994E /* InlineLine.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F0CD694229ED32700C5994E /* InlineLine.h */; };
 		6F15522126476B5C00E353C6 /* TableWrapperBlockFormattingQuirks.h in Headers */ = {isa = PBXBuildFile; fileRef = 6F15522026476B5B00E353C6 /* TableWrapperBlockFormattingQuirks.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -11020,6 +11021,8 @@
 		6ED8C378183BFF8C009E53BD /* BoxShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BoxShape.h; sourceTree = "<group>"; };
 		6EE8A77010F803F3005A4A24 /* JSWebGLContextAttributes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebGLContextAttributes.cpp; sourceTree = "<group>"; };
 		6EE8A77110F803F3005A4A24 /* JSWebGLContextAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWebGLContextAttributes.h; sourceTree = "<group>"; };
+		6F047A9028453ED200C25EE7 /* FlexLayout.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FlexLayout.cpp; sourceTree = "<group>"; };
+		6F047A9128453EDB00C25EE7 /* FlexLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FlexLayout.h; sourceTree = "<group>"; };
 		6F0830DF20B46951008A945B /* BlockFormattingGeometry.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = BlockFormattingGeometry.cpp; sourceTree = "<group>"; };
 		6F0B98B323F268EB00EEC2F2 /* LayoutInlineTextBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LayoutInlineTextBox.h; sourceTree = "<group>"; };
 		6F0B98B623F2690600EEC2F2 /* LayoutInlineTextBox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LayoutInlineTextBox.cpp; sourceTree = "<group>"; };
@@ -24693,6 +24696,8 @@
 		6FB7D2D5250FD7B5000207AA /* flex */ = {
 			isa = PBXGroup;
 			children = (
+				6F047A9128453EDB00C25EE7 /* FlexLayout.h */,
+				6F047A9028453ED200C25EE7 /* FlexLayout.cpp */,
 				6FB17475283A8FF40067D8CA /* FlexFormattingConstraints.h */,
 				6FB7D2D7250FD7E5000207AA /* FlexFormattingContext.cpp */,
 				6FB7D2D9250FD7FC000207AA /* FlexFormattingContext.h */,
@@ -35279,6 +35284,7 @@
 				BC7F44A80B9E324E00A9D081 /* ImageObserver.h in Headers */,
 				2D5A5931152525D00036EE51 /* ImageOrientation.h in Headers */,
 				F46D5386273D7E460009FA80 /* ImageOverlay.h in Headers */,
+				6F047A9228453EDB00C25EE7 /* FlexLayout.h in Headers */,
 				F482434B260C33060022497C /* ImageOverlayController.h in Headers */,
 				F446EDE1265DB1E50031DA8F /* ImageOverlayDataDetectionResultIdentifier.h in Headers */,
 				72283F0E230B268C00F5D828 /* ImagePaintingOptions.h in Headers */,

Modified: trunk/Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.cpp (295038 => 295039)


--- trunk/Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.cpp	2022-05-30 23:59:45 UTC (rev 295038)
+++ trunk/Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.cpp	2022-05-31 01:26:39 UTC (rev 295039)
@@ -119,48 +119,15 @@
     }
 }
 
-LayoutUnit FlexFormattingContext::computeAvailableLogicalVerticalSpace(LogicalFlexItems& logicalFlexItemList, const ConstraintsForFlexContent& flexConstraints) const
+FlexLayout::LogicalFlexItems FlexFormattingContext::convertFlexItemsToLogicalSpace()
 {
-    auto availableLogicalVerticalSpaceFromConstraint = [&] {
-        auto flexDirection = root().style().flexDirection();
-        auto flexDirectionIsInlineAxis = flexDirection == FlexDirection::Row || flexDirection == FlexDirection::RowReverse;
-        if (flexDirectionIsInlineAxis)
-            return flexConstraints.availableVerticalSpace();
-        return std::optional<LayoutUnit> { flexConstraints.horizontal().logicalWidth };
+    struct FlexItem {
+        FlexRect marginRect;
+        int logicalOrder { 0 };
     };
 
-    if (auto availableSpace = availableLogicalVerticalSpaceFromConstraint())
-        return *availableSpace;
-
-    auto availableSpace = LayoutUnit { };
-    for (auto& logicalFlexItem : logicalFlexItemList)
-        availableSpace = std::max(availableSpace, logicalFlexItem.rect.height());
-    return availableSpace;
-}
-
-LayoutUnit FlexFormattingContext::computeAvailableLogicalHorizontalSpace(LogicalFlexItems& logicalFlexItemList, const ConstraintsForFlexContent& flexConstraints) const
-{
-    auto availableLogicalHorizontalSpaceFromConstraint = [&] {
-        auto flexDirection = root().style().flexDirection();
-        auto flexDirectionIsInlineAxis = flexDirection == FlexDirection::Row || flexDirection == FlexDirection::RowReverse;
-        if (flexDirectionIsInlineAxis)
-            return std::optional<LayoutUnit> { flexConstraints.horizontal().logicalWidth }; 
-        return flexConstraints.availableVerticalSpace();
-    };
-
-    if (auto availableSpace = availableLogicalHorizontalSpaceFromConstraint())
-        return *availableSpace;
-
-    auto availableSpace = LayoutUnit { };
-    for (auto& logicalFlexItem : logicalFlexItemList)
-        availableSpace += logicalFlexItem.rect.width();
-    return availableSpace;
-}
-
-FlexFormattingContext::LogicalFlexItems FlexFormattingContext::convertFlexItemsToLogicalSpace()
-{
     auto& formattingState = this->formattingState();
-    LogicalFlexItems logicalFlexItemList;
+    Vector<FlexItem> flexItemList;
     auto flexItemsNeedReordering = false;
 
     auto convertVisualToLogical = [&] {
@@ -167,8 +134,8 @@
         auto direction = root().style().flexDirection();
         auto previousLogicalOrder = std::optional<int> { };
 
-        for (auto& flexItem : childrenOfType<ContainerBox>(root())) {
-            auto& flexItemGeometry = formattingState.boxGeometry(flexItem);
+        for (auto* flexItem = root().firstInFlowChild(); flexItem; flexItem = flexItem->nextInFlowSibling()) {
+            auto& flexItemGeometry = formattingState.boxGeometry(*flexItem);
             auto logicalSize = LayoutSize { };
 
             switch (direction) {
@@ -184,11 +151,11 @@
                 ASSERT_NOT_REACHED();
                 break;
             }
-            auto flexItemOrder = flexItem.style().order();
+            auto flexItemOrder = flexItem->style().order();
             flexItemsNeedReordering = flexItemsNeedReordering || flexItemOrder != previousLogicalOrder.value_or(0);
             previousLogicalOrder = flexItemOrder;
 
-            logicalFlexItemList.append({ { logicalSize }, flexItemOrder, &flexItem });
+            flexItemList.append({ { logicalSize }, flexItemOrder });
         }
     };
     convertVisualToLogical();
@@ -197,19 +164,25 @@
         if (!flexItemsNeedReordering)
             return;
 
-        std::stable_sort(logicalFlexItemList.begin(), logicalFlexItemList.end(), [&] (auto& a, auto& b) {
+        std::stable_sort(flexItemList.begin(), flexItemList.end(), [&] (auto& a, auto& b) {
             return a.logicalOrder < b.logicalOrder;
         });
     };
     reorderFlexItemsIfApplicable();
 
+    auto logicalFlexItemList = FlexLayout::LogicalFlexItems(flexItemList.size());
+    auto* layoutBox = root().firstInFlowChild();
+    for (size_t index = 0; index < flexItemList.size(); ++index) {
+        logicalFlexItemList[index] = { flexItemList[index].marginRect, downcast<ContainerBox>(layoutBox) };
+        layoutBox = layoutBox->nextInFlowSibling();
+    }
     return logicalFlexItemList;
 }
 
-void FlexFormattingContext::setFlexItemsGeometry(const LogicalFlexItems& logicalFlexItemList, const ConstraintsForFlexContent& constraints)
+void FlexFormattingContext::setFlexItemsGeometry(const FlexLayout::LogicalFlexItems& logicalFlexItemList, const ConstraintsForFlexContent& constraints)
 {
     auto& formattingState = this->formattingState();
-    auto logicalWidth = logicalFlexItemList.last().rect.right() - logicalFlexItemList.first().rect.left();
+    auto logicalWidth = logicalFlexItemList.last().marginRect.right() - logicalFlexItemList.first().marginRect.left();
     auto direction = root().style().flexDirection();
     for (auto& logicalFlexItem : logicalFlexItemList) {
         auto& flexItemGeometry = formattingState.boxGeometry(*logicalFlexItem.layoutBox);
@@ -217,18 +190,18 @@
 
         switch (direction) {
         case FlexDirection::Row:
-            topLeft = { constraints.horizontal().logicalLeft + logicalFlexItem.rect.left(), constraints.logicalTop() + logicalFlexItem.rect.top() };
+            topLeft = { constraints.horizontal().logicalLeft + logicalFlexItem.marginRect.left(), constraints.logicalTop() + logicalFlexItem.marginRect.top() };
             break;
         case FlexDirection::RowReverse:
-            topLeft = { constraints.horizontal().logicalRight() - logicalFlexItem.rect.right(), constraints.logicalTop() + logicalFlexItem.rect.top() };
+            topLeft = { constraints.horizontal().logicalRight() - logicalFlexItem.marginRect.right(), constraints.logicalTop() + logicalFlexItem.marginRect.top() };
             break;
         case FlexDirection::Column: {
-            auto flippedTopLeft = logicalFlexItem.rect.topLeft().transposedPoint();
+            auto flippedTopLeft = logicalFlexItem.marginRect.topLeft().transposedPoint();
             topLeft = { constraints.horizontal().logicalLeft + flippedTopLeft.x(), constraints.logicalTop() + flippedTopLeft.y() };
             break;
         }
         case FlexDirection::ColumnReverse:
-            topLeft = { constraints.horizontal().logicalLeft + logicalFlexItem.rect.top(), constraints.logicalTop() + logicalWidth - logicalFlexItem.rect.right() };
+            topLeft = { constraints.horizontal().logicalLeft + logicalFlexItem.marginRect.top(), constraints.logicalTop() + logicalWidth - logicalFlexItem.marginRect.right() };
             break;
         default:
             ASSERT_NOT_REACHED();
@@ -236,315 +209,22 @@
         }
         flexItemGeometry.setLogicalTopLeft(topLeft);
         if (direction == FlexDirection::Row || direction == FlexDirection::RowReverse) {
-            flexItemGeometry.setContentBoxWidth(logicalFlexItem.rect.width() - flexItemGeometry.horizontalMarginBorderAndPadding());
-            flexItemGeometry.setContentBoxHeight(logicalFlexItem.rect.height() - flexItemGeometry.verticalMarginBorderAndPadding());
+            flexItemGeometry.setContentBoxWidth(logicalFlexItem.marginRect.width() - flexItemGeometry.horizontalMarginBorderAndPadding());
+            flexItemGeometry.setContentBoxHeight(logicalFlexItem.marginRect.height() - flexItemGeometry.verticalMarginBorderAndPadding());
         } else {
-            flexItemGeometry.setContentBoxWidth(logicalFlexItem.rect.height() - flexItemGeometry.horizontalMarginBorderAndPadding());
-            flexItemGeometry.setContentBoxHeight(logicalFlexItem.rect.width() - flexItemGeometry.verticalMarginBorderAndPadding());
+            flexItemGeometry.setContentBoxWidth(logicalFlexItem.marginRect.height() - flexItemGeometry.horizontalMarginBorderAndPadding());
+            flexItemGeometry.setContentBoxHeight(logicalFlexItem.marginRect.width() - flexItemGeometry.verticalMarginBorderAndPadding());
         }
     }
 }
 
-void FlexFormattingContext::computeLogicalWidthForShrinkingFlexItems(LogicalFlexItems& logicalFlexItemList, LayoutUnit availableSpace)
-{
-    auto& formattingState = this->formattingState();
-
-    auto totalShrink = 0.f;
-    auto totalFlexibleSpace = LayoutUnit { };
-    auto flexShrinkBase = 0.f;
-
-    struct ShrinkingFlexItem {
-        float flexShrink { 0 };
-        LayoutUnit minimumSize;
-        LayoutUnit flexBasis;
-        LogicalFlexItem& flexItem;
-        bool isFrozen { false };
-    };
-    Vector<ShrinkingFlexItem> shrinkingItems;
-
-    auto computeTotalShrinkAndOverflowingSpace = [&] {
-        // Collect flex items with non-zero flex-shrink value. flex-shrink: 0 flex items
-        // don't participate in content flexing.
-        for (auto& flexItem : logicalFlexItemList) {
-            auto& style = flexItem.layoutBox->style();
-            auto baseSize = style.flexBasis().isFixed() ? LayoutUnit { style.flexBasis().value() } : flexItem.rect.width();
-            if (auto shrinkValue = style.flexShrink()) {
-                auto flexShrink = shrinkValue * baseSize;
-                shrinkingItems.append({ flexShrink, formattingState.intrinsicWidthConstraintsForBox(*flexItem.layoutBox)->minimum, baseSize, flexItem, { } });
-                totalShrink += flexShrink;
-                totalFlexibleSpace += baseSize;
-            } else
-                availableSpace -= baseSize;
-        }
-        if (totalShrink)
-            flexShrinkBase = (totalFlexibleSpace - availableSpace) / totalShrink;
-    };
-    computeTotalShrinkAndOverflowingSpace();
-
-    auto adjustShrinkBase = [&] {
-        // Now that we know how much each flex item needs to be shrunk, let's check
-        // if they hit their minimum content width (i.e. whether they can be sized that small).
-        while (true) {
-            auto didFreeze = false;
-            for (auto& shirinkingFlex : shrinkingItems) {
-                auto flexedSize = shirinkingFlex.flexBasis - (shirinkingFlex.flexShrink * flexShrinkBase);
-                if (!shirinkingFlex.isFrozen && shirinkingFlex.minimumSize > flexedSize) {
-                    shirinkingFlex.isFrozen = true;
-                    didFreeze = true;
-                    totalShrink -= shirinkingFlex.flexShrink;
-                    totalFlexibleSpace -= shirinkingFlex.flexBasis;
-                    availableSpace -= shirinkingFlex.minimumSize;
-                }
-            }
-            if (!didFreeze)
-                break;
-            flexShrinkBase = totalShrink ? (totalFlexibleSpace - availableSpace) / totalShrink : 0.f;
-        }
-    };
-    adjustShrinkBase();
-
-    auto computeLogicalWidth = [&] {
-        // Adjust the total grow width by the overflow value (shrink) except when min content with disagrees.
-        for (auto& shirinkingFlex : shrinkingItems) {
-            auto flexedSize = LayoutUnit { shirinkingFlex.flexBasis - (shirinkingFlex.flexShrink * flexShrinkBase) };
-            shirinkingFlex.flexItem.rect.setWidth(std::max(shirinkingFlex.minimumSize, flexedSize));
-        }
-    };
-    computeLogicalWidth();
-}
-
-void FlexFormattingContext::computeLogicalWidthForStretchingFlexItems(LogicalFlexItems& logicalFlexItemList, LayoutUnit availableSpace)
-{
-    auto& formattingState = this->formattingState();
-
-    auto totalFlexibleSpace = LayoutUnit { };
-    auto totalGrowth = 0.f;
-    auto flexGrowBase = 0.f;
-    struct StrechingFlexItem {
-        float flexGrow { 0 };
-        LayoutUnit minimumSize;
-        LayoutUnit flexBasis;
-        LogicalFlexItem& flexItem;
-        bool isFrozen { false };
-    };
-    Vector<StrechingFlexItem> stretchingItems;
-
-    auto computeTotalGrowthAndFlexibleSpace = [&] {
-        // Collect flex items with non-zero flex-grow value. flex-grow: 0 (initial) flex items
-        // don't participate in available space distribution.
-        for (auto& flexItem : logicalFlexItemList) {
-            auto& style = flexItem.layoutBox->style();
-            auto baseSize = style.flexBasis().isFixed() ? LayoutUnit { style.flexBasis().value() } : flexItem.rect.width();
-            if (auto growValue = style.flexGrow()) {
-                auto flexGrow = growValue * baseSize;
-                stretchingItems.append({ flexGrow, formattingState.intrinsicWidthConstraintsForBox(*flexItem.layoutBox)->minimum, baseSize, flexItem, { } });
-                totalGrowth += flexGrow;
-                totalFlexibleSpace += baseSize;
-            } else
-                availableSpace -= baseSize;
-        }
-        if (totalGrowth)
-            flexGrowBase = (availableSpace - totalFlexibleSpace) / totalGrowth;
-    };
-    computeTotalGrowthAndFlexibleSpace();
-    if (!totalGrowth)
-        return;
-
-    auto adjustGrowthBase = [&] {
-        // This is where we compute how much space the flexing boxes take up if we just
-        // let them flex by their flex-grow value. Note that we can't size them below their minimum content width.
-        // Such flex items are removed from the final overflow distribution.
-        auto accumulatedWidth = LayoutUnit { };
-        while (true) {
-            auto didFreeze = false;
-            for (auto& stretchingFlex : stretchingItems) {
-                auto flexedSize = stretchingFlex.flexBasis + stretchingFlex.flexGrow * flexGrowBase;
-                if (stretchingFlex.minimumSize >= flexedSize) {
-                    stretchingFlex.isFrozen = true;
-                    didFreeze = true;
-                    totalGrowth -= stretchingFlex.flexGrow;
-                    totalFlexibleSpace -= stretchingFlex.flexBasis;
-                    availableSpace -= stretchingFlex.minimumSize;
-                }
-            }
-            if (!didFreeze)
-                break;
-            flexGrowBase = totalGrowth ? (totalFlexibleSpace - availableSpace) / totalGrowth : 0.f;
-        }
-    };
-    adjustGrowthBase();
-
-    auto computeLogicalWidth = [&] {
-        // Adjust the total grow width by the overflow value (shrink) except when min content with disagrees.
-        for (auto& stretchingFlex : stretchingItems) {
-            auto flexedSize = LayoutUnit { stretchingFlex.flexBasis + (stretchingFlex.flexGrow * flexGrowBase) };
-            stretchingFlex.flexItem.rect.setWidth(std::max(stretchingFlex.minimumSize, flexedSize));
-        }
-    };
-    computeLogicalWidth();
-}
-
-void FlexFormattingContext::computeLogicalWidthForFlexItems(LogicalFlexItems& logicalFlexItemList, LayoutUnit availableSpace)
-{
-    auto contentLogicalWidth = [&] {
-        auto logicalWidth = LayoutUnit { };
-        for (auto& logicalFlexItem : logicalFlexItemList)
-            logicalWidth += logicalFlexItem.rect.width();
-        return logicalWidth;
-    }();
-
-    if (availableSpace > contentLogicalWidth)
-        computeLogicalWidthForStretchingFlexItems(logicalFlexItemList, availableSpace);
-    else if (availableSpace < contentLogicalWidth)
-        computeLogicalWidthForShrinkingFlexItems(logicalFlexItemList, availableSpace);
-}
-
-void FlexFormattingContext::computeLogicalHeightForFlexItems(LogicalFlexItems& logicalFlexItemList, LayoutUnit availableSpace)
-{
-    auto alignItems = root().style().alignItems();
-
-    for (auto& logicalFlexItem : logicalFlexItemList) {
-        auto& height = logicalFlexItem.layoutBox->style().height();
-        if (!height.isAuto())
-            continue;
-        switch (alignItems.position()) {
-        case ItemPosition::Normal:
-        case ItemPosition::Stretch:
-            logicalFlexItem.rect.setHeight(availableSpace);
-            break;
-        case ItemPosition::Center:
-        case ItemPosition::Start:
-        case ItemPosition::FlexStart:
-        case ItemPosition::End:
-        case ItemPosition::FlexEnd:
-            break;
-        default:
-            ASSERT_NOT_IMPLEMENTED_YET();
-            break;
-        }
-    }
-}
-
-void FlexFormattingContext::alignFlexItems(LogicalFlexItems& logicalFlexItemList, LayoutUnit availableSpace)
-{
-    // FIXME: Check if height computation and vertical alignment should merge.
-    auto flexBoxAlignItems = root().style().alignItems();
-
-    for (auto& logicalFlexItem : logicalFlexItemList) {
-        auto& flexItemAlignSelf = logicalFlexItem.layoutBox->style().alignSelf();
-        auto alignValue = flexItemAlignSelf.position() != ItemPosition::Auto ? flexItemAlignSelf : flexBoxAlignItems;
-        switch (alignValue.position()) {
-        case ItemPosition::Normal:
-        case ItemPosition::Stretch:
-            logicalFlexItem.rect.setTop({ });
-            break;
-        case ItemPosition::Center:
-            logicalFlexItem.rect.setTop({ availableSpace / 2 -  logicalFlexItem.rect.height() / 2 });
-            break;
-        case ItemPosition::Start:
-        case ItemPosition::FlexStart:
-            logicalFlexItem.rect.setTop({ });
-            break;
-        case ItemPosition::End:
-        case ItemPosition::FlexEnd:
-            logicalFlexItem.rect.setTop({ availableSpace - logicalFlexItem.rect.height() });
-            break;
-        default:
-            ASSERT_NOT_IMPLEMENTED_YET();
-            break;
-        }
-    }
-}
-
-void FlexFormattingContext::justifyFlexItems(LogicalFlexItems& logicalFlexItemList, LayoutUnit availableSpace)
-{
-    auto justifyContent = root().style().justifyContent();
-    // FIXME: Make this optional.
-    auto contentLogicalWidth = [&] {
-        auto logicalWidth = LayoutUnit { };
-        for (auto& logicalFlexItem : logicalFlexItemList)
-            logicalWidth += logicalFlexItem.rect.width();
-        return logicalWidth;
-    }();
-
-    auto initialOffset = [&] {
-        switch (justifyContent.distribution()) {
-        case ContentDistribution::Default:
-            // Fall back to justifyContent.position() 
-            break;
-        case ContentDistribution::SpaceBetween:
-            return LayoutUnit { };
-        case ContentDistribution::SpaceAround:
-            return (availableSpace - contentLogicalWidth) / logicalFlexItemList.size() / 2; 
-        case ContentDistribution::SpaceEvenly:
-            return (availableSpace - contentLogicalWidth) / (logicalFlexItemList.size() + 1);
-        default:
-            ASSERT_NOT_IMPLEMENTED_YET();
-            break;
-        }
-
-        switch (justifyContent.position()) {
-        case ContentPosition::Normal:
-        case ContentPosition::Start:
-        case ContentPosition::FlexStart:
-        case ContentPosition::Left:
-            return LayoutUnit { };
-        case ContentPosition::End:
-        case ContentPosition::FlexEnd:
-        case ContentPosition::Right:
-            return availableSpace - contentLogicalWidth;
-        case ContentPosition::Center:
-            return availableSpace / 2 - contentLogicalWidth / 2;
-        default:
-            ASSERT_NOT_IMPLEMENTED_YET();
-            break;
-        }
-        ASSERT_NOT_REACHED();
-        return LayoutUnit { };
-    };
-
-    auto gapBetweenItems = [&] {
-        switch (justifyContent.distribution()) {
-        case ContentDistribution::Default:
-            return LayoutUnit { };
-        case ContentDistribution::SpaceBetween:
-            if (logicalFlexItemList.size() == 1)
-                return LayoutUnit { };
-            return (availableSpace - contentLogicalWidth) / (logicalFlexItemList.size() - 1); 
-        case ContentDistribution::SpaceAround:
-            return (availableSpace - contentLogicalWidth) / logicalFlexItemList.size(); 
-        case ContentDistribution::SpaceEvenly:
-            return (availableSpace - contentLogicalWidth) / (logicalFlexItemList.size() + 1);
-        default:
-            ASSERT_NOT_IMPLEMENTED_YET();
-            break;
-        }
-        ASSERT_NOT_REACHED();
-        return LayoutUnit { };
-    };
-
-    auto logicalLeft = initialOffset();
-    auto gap = gapBetweenItems();
-    for (auto& logicalFlexItem : logicalFlexItemList) {
-        logicalFlexItem.rect.setLeft(logicalLeft);
-        logicalLeft = logicalFlexItem.rect.right() + gap;
-    }
-}
-
 void FlexFormattingContext::layoutInFlowContentForIntegration(const ConstraintsForInFlowContent& constraints)
 {
-    auto logicalFlexItemList = convertFlexItemsToLogicalSpace();
     auto flexConstraints = downcast<ConstraintsForFlexContent>(constraints);
-
-    auto availableLogicalHorizontalSpace = computeAvailableLogicalHorizontalSpace(logicalFlexItemList, flexConstraints);
-    computeLogicalWidthForFlexItems(logicalFlexItemList, availableLogicalHorizontalSpace);
-
-    auto availableLogicalVerticalSpace = computeAvailableLogicalVerticalSpace(logicalFlexItemList, flexConstraints);
-    computeLogicalHeightForFlexItems(logicalFlexItemList, availableLogicalVerticalSpace);
-    alignFlexItems(logicalFlexItemList, availableLogicalVerticalSpace);
-    justifyFlexItems(logicalFlexItemList, availableLogicalHorizontalSpace);
-
-    setFlexItemsGeometry(logicalFlexItemList, flexConstraints);
+    auto logicalFlexItems = convertFlexItemsToLogicalSpace();
+    auto flexLayout = FlexLayout { formattingState(), root().style() };
+    flexLayout.layout(flexConstraints, logicalFlexItems);
+    setFlexItemsGeometry(logicalFlexItems, flexConstraints);
 }
 
 IntrinsicWidthConstraints FlexFormattingContext::computedIntrinsicWidthConstraintsForIntegration()

Modified: trunk/Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.h (295038 => 295039)


--- trunk/Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.h	2022-05-30 23:59:45 UTC (rev 295038)
+++ trunk/Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.h	2022-05-31 01:26:39 UTC (rev 295039)
@@ -30,6 +30,7 @@
 #include "FlexFormattingConstraints.h"
 #include "FlexFormattingGeometry.h"
 #include "FlexFormattingState.h"
+#include "FlexLayout.h"
 #include "FlexRect.h"
 #include "FormattingQuirks.h"
 #include <wtf/IsoMalloc.h>
@@ -57,22 +58,8 @@
     void sizeAndPlaceFlexItems(const ConstraintsForFlexContent&);
     void computeIntrinsicWidthConstraintsForFlexItems();
 
-    struct LogicalFlexItem {
-        FlexRect rect;
-        int logicalOrder { 0 };
-        CheckedPtr<const ContainerBox> layoutBox;
-    };
-    using LogicalFlexItems = Vector<LogicalFlexItem>;
-    LogicalFlexItems convertFlexItemsToLogicalSpace();
-    void setFlexItemsGeometry(const LogicalFlexItems&, const ConstraintsForFlexContent&);
-    void computeLogicalWidthForFlexItems(LogicalFlexItems&, LayoutUnit availableSpace);
-    void computeLogicalWidthForStretchingFlexItems(LogicalFlexItems&, LayoutUnit availableSpace);
-    void computeLogicalWidthForShrinkingFlexItems(LogicalFlexItems&, LayoutUnit availableSpace);
-    void computeLogicalHeightForFlexItems(LogicalFlexItems&, LayoutUnit availableSpace);
-    void alignFlexItems(LogicalFlexItems&, LayoutUnit availableSpace);
-    void justifyFlexItems(LogicalFlexItems&, LayoutUnit availableSpace);
-    LayoutUnit computeAvailableLogicalVerticalSpace(LogicalFlexItems&, const ConstraintsForFlexContent&) const;
-    LayoutUnit computeAvailableLogicalHorizontalSpace(LogicalFlexItems&, const ConstraintsForFlexContent&) const;
+    FlexLayout::LogicalFlexItems convertFlexItemsToLogicalSpace();
+    void setFlexItemsGeometry(const FlexLayout::LogicalFlexItems&, const ConstraintsForFlexContent&);
 
     const FlexFormattingState& formattingState() const { return downcast<FlexFormattingState>(FormattingContext::formattingState()); }
     FlexFormattingState& formattingState() { return downcast<FlexFormattingState>(FormattingContext::formattingState()); }

Added: trunk/Source/WebCore/layout/formattingContexts/flex/FlexLayout.cpp (0 => 295039)


--- trunk/Source/WebCore/layout/formattingContexts/flex/FlexLayout.cpp	                        (rev 0)
+++ trunk/Source/WebCore/layout/formattingContexts/flex/FlexLayout.cpp	2022-05-31 01:26:39 UTC (rev 295039)
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FlexLayout.h"
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "FlexRect.h"
+#include "LayoutContext.h"
+
+namespace WebCore {
+namespace Layout {
+
+FlexLayout::FlexLayout(const FlexFormattingState& formattingState, const RenderStyle& flexBoxStyle)
+    : m_formattingState(formattingState)
+    , m_flexBoxStyle(flexBoxStyle)
+{
+}
+
+LayoutUnit FlexLayout::computeAvailableLogicalVerticalSpace(LogicalFlexItems& flexItems, const ConstraintsForFlexContent& flexConstraints) const
+{
+    auto availableLogicalVerticalSpaceFromConstraint = [&] {
+        auto flexDirection = flexBoxStyle().flexDirection();
+        auto flexDirectionIsInlineAxis = flexDirection == FlexDirection::Row || flexDirection == FlexDirection::RowReverse;
+        if (flexDirectionIsInlineAxis)
+            return flexConstraints.availableVerticalSpace();
+        return std::optional<LayoutUnit> { flexConstraints.horizontal().logicalWidth };
+    };
+
+    if (auto availableSpace = availableLogicalVerticalSpaceFromConstraint())
+        return *availableSpace;
+
+    auto availableSpace = LayoutUnit { };
+    for (auto& flexItem : flexItems)
+        availableSpace = std::max(availableSpace, flexItem.marginRect.height());
+    return availableSpace;
+}
+
+LayoutUnit FlexLayout::computeAvailableLogicalHorizontalSpace(LogicalFlexItems& flexItems, const ConstraintsForFlexContent& flexConstraints) const
+{
+    auto availableLogicalHorizontalSpaceFromConstraint = [&] {
+        auto flexDirection = flexBoxStyle().flexDirection();
+        auto flexDirectionIsInlineAxis = flexDirection == FlexDirection::Row || flexDirection == FlexDirection::RowReverse;
+        if (flexDirectionIsInlineAxis)
+            return std::optional<LayoutUnit> { flexConstraints.horizontal().logicalWidth }; 
+        return flexConstraints.availableVerticalSpace();
+    };
+
+    if (auto availableSpace = availableLogicalHorizontalSpaceFromConstraint())
+        return *availableSpace;
+
+    auto availableSpace = LayoutUnit { };
+    for (auto& flexItem : flexItems)
+        availableSpace += flexItem.marginRect.width();
+    return availableSpace;
+}
+
+void FlexLayout::computeLogicalWidthForShrinkingFlexItems(LogicalFlexItems& flexItems, LayoutUnit availableSpace)
+{
+    auto& formattingState = this->formattingState();
+
+    auto totalShrink = 0.f;
+    auto totalFlexibleSpace = LayoutUnit { };
+    auto flexShrinkBase = 0.f;
+
+    struct ShrinkingFlexItem {
+        float flexShrink { 0 };
+        LayoutUnit minimumSize;
+        LayoutUnit flexBasis;
+        LogicalFlexItem& flexItem;
+        bool isFrozen { false };
+    };
+    Vector<ShrinkingFlexItem> shrinkingItems;
+
+    auto computeTotalShrinkAndOverflowingSpace = [&] {
+        // Collect flex items with non-zero flex-shrink value. flex-shrink: 0 flex items
+        // don't participate in content flexing.
+        for (auto& flexItem : flexItems) {
+            auto& style = flexItem.layoutBox->style();
+            auto baseSize = style.flexBasis().isFixed() ? LayoutUnit { style.flexBasis().value() } : flexItem.marginRect.width();
+            if (auto shrinkValue = style.flexShrink()) {
+                auto flexShrink = shrinkValue * baseSize;
+                shrinkingItems.append({ flexShrink, formattingState.intrinsicWidthConstraintsForBox(*flexItem.layoutBox)->minimum, baseSize, flexItem, { } });
+                totalShrink += flexShrink;
+                totalFlexibleSpace += baseSize;
+            } else
+                availableSpace -= baseSize;
+        }
+        if (totalShrink)
+            flexShrinkBase = (totalFlexibleSpace - availableSpace) / totalShrink;
+    };
+    computeTotalShrinkAndOverflowingSpace();
+
+    auto adjustShrinkBase = [&] {
+        // Now that we know how much each flex item needs to be shrunk, let's check
+        // if they hit their minimum content width (i.e. whether they can be sized that small).
+        while (true) {
+            auto didFreeze = false;
+            for (auto& shirinkingFlex : shrinkingItems) {
+                auto flexedSize = shirinkingFlex.flexBasis - (shirinkingFlex.flexShrink * flexShrinkBase);
+                if (!shirinkingFlex.isFrozen && shirinkingFlex.minimumSize > flexedSize) {
+                    shirinkingFlex.isFrozen = true;
+                    didFreeze = true;
+                    totalShrink -= shirinkingFlex.flexShrink;
+                    totalFlexibleSpace -= shirinkingFlex.flexBasis;
+                    availableSpace -= shirinkingFlex.minimumSize;
+                }
+            }
+            if (!didFreeze)
+                break;
+            flexShrinkBase = totalShrink ? (totalFlexibleSpace - availableSpace) / totalShrink : 0.f;
+        }
+    };
+    adjustShrinkBase();
+
+    auto computeLogicalWidth = [&] {
+        // Adjust the total grow width by the overflow value (shrink) except when min content with disagrees.
+        for (auto& shirinkingFlex : shrinkingItems) {
+            auto flexedSize = LayoutUnit { shirinkingFlex.flexBasis - (shirinkingFlex.flexShrink * flexShrinkBase) };
+            shirinkingFlex.flexItem.marginRect.setWidth(std::max(shirinkingFlex.minimumSize, flexedSize));
+        }
+    };
+    computeLogicalWidth();
+}
+
+void FlexLayout::computeLogicalWidthForStretchingFlexItems(LogicalFlexItems& flexItems, LayoutUnit availableSpace)
+{
+    auto& formattingState = this->formattingState();
+
+    auto totalFlexibleSpace = LayoutUnit { };
+    auto totalGrowth = 0.f;
+    auto flexGrowBase = 0.f;
+    struct StrechingFlexItem {
+        float flexGrow { 0 };
+        LayoutUnit minimumSize;
+        LayoutUnit flexBasis;
+        LogicalFlexItem& flexItem;
+        bool isFrozen { false };
+    };
+    Vector<StrechingFlexItem> stretchingItems;
+
+    auto computeTotalGrowthAndFlexibleSpace = [&] {
+        // Collect flex items with non-zero flex-grow value. flex-grow: 0 (initial) flex items
+        // don't participate in available space distribution.
+        for (auto& flexItem : flexItems) {
+            auto& style = flexItem.layoutBox->style();
+            auto baseSize = style.flexBasis().isFixed() ? LayoutUnit { style.flexBasis().value() } : flexItem.marginRect.width();
+            if (auto growValue = style.flexGrow()) {
+                auto flexGrow = growValue * baseSize;
+                stretchingItems.append({ flexGrow, formattingState.intrinsicWidthConstraintsForBox(*flexItem.layoutBox)->minimum, baseSize, flexItem, { } });
+                totalGrowth += flexGrow;
+                totalFlexibleSpace += baseSize;
+            } else
+                availableSpace -= baseSize;
+        }
+        if (totalGrowth)
+            flexGrowBase = (availableSpace - totalFlexibleSpace) / totalGrowth;
+    };
+    computeTotalGrowthAndFlexibleSpace();
+    if (!totalGrowth)
+        return;
+
+    auto adjustGrowthBase = [&] {
+        // This is where we compute how much space the flexing boxes take up if we just
+        // let them flex by their flex-grow value. Note that we can't size them below their minimum content width.
+        // Such flex items are removed from the final overflow distribution.
+        auto accumulatedWidth = LayoutUnit { };
+        while (true) {
+            auto didFreeze = false;
+            for (auto& stretchingFlex : stretchingItems) {
+                auto flexedSize = stretchingFlex.flexBasis + stretchingFlex.flexGrow * flexGrowBase;
+                if (stretchingFlex.minimumSize >= flexedSize) {
+                    stretchingFlex.isFrozen = true;
+                    didFreeze = true;
+                    totalGrowth -= stretchingFlex.flexGrow;
+                    totalFlexibleSpace -= stretchingFlex.flexBasis;
+                    availableSpace -= stretchingFlex.minimumSize;
+                }
+            }
+            if (!didFreeze)
+                break;
+            flexGrowBase = totalGrowth ? (totalFlexibleSpace - availableSpace) / totalGrowth : 0.f;
+        }
+    };
+    adjustGrowthBase();
+
+    auto computeLogicalWidth = [&] {
+        // Adjust the total grow width by the overflow value (shrink) except when min content with disagrees.
+        for (auto& stretchingFlex : stretchingItems) {
+            auto flexedSize = LayoutUnit { stretchingFlex.flexBasis + (stretchingFlex.flexGrow * flexGrowBase) };
+            stretchingFlex.flexItem.marginRect.setWidth(std::max(stretchingFlex.minimumSize, flexedSize));
+        }
+    };
+    computeLogicalWidth();
+}
+
+void FlexLayout::computeLogicalWidthForFlexItems(LogicalFlexItems& flexItems, LayoutUnit availableSpace)
+{
+    auto contentLogicalWidth = [&] {
+        auto logicalWidth = LayoutUnit { };
+        for (auto& flexItem : flexItems)
+            logicalWidth += flexItem.marginRect.width();
+        return logicalWidth;
+    }();
+
+    if (availableSpace > contentLogicalWidth)
+        computeLogicalWidthForStretchingFlexItems(flexItems, availableSpace);
+    else if (availableSpace < contentLogicalWidth)
+        computeLogicalWidthForShrinkingFlexItems(flexItems, availableSpace);
+}
+
+void FlexLayout::computeLogicalHeightForFlexItems(LogicalFlexItems& flexItems, LayoutUnit availableSpace)
+{
+    auto alignItems = flexBoxStyle().alignItems();
+
+    for (auto& flexItem : flexItems) {
+        auto& height = flexItem.layoutBox->style().height();
+        if (!height.isAuto())
+            continue;
+        switch (alignItems.position()) {
+        case ItemPosition::Normal:
+        case ItemPosition::Stretch:
+            flexItem.marginRect.setHeight(availableSpace);
+            break;
+        case ItemPosition::Center:
+        case ItemPosition::Start:
+        case ItemPosition::FlexStart:
+        case ItemPosition::End:
+        case ItemPosition::FlexEnd:
+            break;
+        default:
+            ASSERT_NOT_IMPLEMENTED_YET();
+            break;
+        }
+    }
+}
+
+void FlexLayout::alignFlexItems(LogicalFlexItems& flexItems, LayoutUnit availableSpace)
+{
+    // FIXME: Check if height computation and vertical alignment should merge.
+    auto flexBoxAlignItems = flexBoxStyle().alignItems();
+
+    for (auto& flexItem : flexItems) {
+        auto& flexItemAlignSelf = flexItem.layoutBox->style().alignSelf();
+        auto alignValue = flexItemAlignSelf.position() != ItemPosition::Auto ? flexItemAlignSelf : flexBoxAlignItems;
+        switch (alignValue.position()) {
+        case ItemPosition::Normal:
+        case ItemPosition::Stretch:
+            flexItem.marginRect.setTop({ });
+            break;
+        case ItemPosition::Center:
+            flexItem.marginRect.setTop({ availableSpace / 2 -  flexItem.marginRect.height() / 2 });
+            break;
+        case ItemPosition::Start:
+        case ItemPosition::FlexStart:
+            flexItem.marginRect.setTop({ });
+            break;
+        case ItemPosition::End:
+        case ItemPosition::FlexEnd:
+            flexItem.marginRect.setTop({ availableSpace - flexItem.marginRect.height() });
+            break;
+        default:
+            ASSERT_NOT_IMPLEMENTED_YET();
+            break;
+        }
+    }
+}
+
+void FlexLayout::justifyFlexItems(LogicalFlexItems& flexItems, LayoutUnit availableSpace)
+{
+    auto justifyContent = flexBoxStyle().justifyContent();
+    // FIXME: Make this optional.
+    auto contentLogicalWidth = [&] {
+        auto logicalWidth = LayoutUnit { };
+        for (auto& flexItem : flexItems)
+            logicalWidth += flexItem.marginRect.width();
+        return logicalWidth;
+    }();
+
+    auto initialOffset = [&] {
+        switch (justifyContent.distribution()) {
+        case ContentDistribution::Default:
+            // Fall back to justifyContent.position() 
+            break;
+        case ContentDistribution::SpaceBetween:
+            return LayoutUnit { };
+        case ContentDistribution::SpaceAround:
+            return (availableSpace - contentLogicalWidth) / flexItems.size() / 2; 
+        case ContentDistribution::SpaceEvenly:
+            return (availableSpace - contentLogicalWidth) / (flexItems.size() + 1);
+        default:
+            ASSERT_NOT_IMPLEMENTED_YET();
+            break;
+        }
+
+        switch (justifyContent.position()) {
+        case ContentPosition::Normal:
+        case ContentPosition::Start:
+        case ContentPosition::FlexStart:
+        case ContentPosition::Left:
+            return LayoutUnit { };
+        case ContentPosition::End:
+        case ContentPosition::FlexEnd:
+        case ContentPosition::Right:
+            return availableSpace - contentLogicalWidth;
+        case ContentPosition::Center:
+            return availableSpace / 2 - contentLogicalWidth / 2;
+        default:
+            ASSERT_NOT_IMPLEMENTED_YET();
+            break;
+        }
+        ASSERT_NOT_REACHED();
+        return LayoutUnit { };
+    };
+
+    auto gapBetweenItems = [&] {
+        switch (justifyContent.distribution()) {
+        case ContentDistribution::Default:
+            return LayoutUnit { };
+        case ContentDistribution::SpaceBetween:
+            if (flexItems.size() == 1)
+                return LayoutUnit { };
+            return (availableSpace - contentLogicalWidth) / (flexItems.size() - 1); 
+        case ContentDistribution::SpaceAround:
+            return (availableSpace - contentLogicalWidth) / flexItems.size(); 
+        case ContentDistribution::SpaceEvenly:
+            return (availableSpace - contentLogicalWidth) / (flexItems.size() + 1);
+        default:
+            ASSERT_NOT_IMPLEMENTED_YET();
+            break;
+        }
+        ASSERT_NOT_REACHED();
+        return LayoutUnit { };
+    };
+
+    auto logicalLeft = initialOffset();
+    auto gap = gapBetweenItems();
+    for (auto& flexItem : flexItems) {
+        flexItem.marginRect.setLeft(logicalLeft);
+        logicalLeft = flexItem.marginRect.right() + gap;
+    }
+}
+
+void FlexLayout::layout(const ConstraintsForFlexContent& constraints, LogicalFlexItems& flexItems)
+{
+    auto availableLogicalHorizontalSpace = computeAvailableLogicalHorizontalSpace(flexItems, constraints);
+    computeLogicalWidthForFlexItems(flexItems, availableLogicalHorizontalSpace);
+
+    auto availableLogicalVerticalSpace = computeAvailableLogicalVerticalSpace(flexItems, constraints);
+    computeLogicalHeightForFlexItems(flexItems, availableLogicalVerticalSpace);
+    alignFlexItems(flexItems, availableLogicalVerticalSpace);
+    justifyFlexItems(flexItems, availableLogicalHorizontalSpace);
+}
+
+}
+}
+
+#endif

Copied: trunk/Source/WebCore/layout/formattingContexts/flex/FlexLayout.h (from rev 295038, trunk/Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.h) (0 => 295039)


--- trunk/Source/WebCore/layout/formattingContexts/flex/FlexLayout.h	                        (rev 0)
+++ trunk/Source/WebCore/layout/formattingContexts/flex/FlexLayout.h	2022-05-31 01:26:39 UTC (rev 295039)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "FlexFormattingConstraints.h"
+#include "FlexFormattingState.h"
+#include "FlexRect.h"
+
+namespace WebCore {
+namespace Layout {
+
+// This class implements the layout logic for flex formatting contexts.
+// https://www.w3.org/TR/css-flexbox-1/
+class FlexLayout {
+public:
+    FlexLayout(const FlexFormattingState&, const RenderStyle& flexBoxStyle);
+
+    struct LogicalFlexItem {
+        FlexRect marginRect;
+        CheckedPtr<const ContainerBox> layoutBox;        
+    };
+    using LogicalFlexItems = Vector<LogicalFlexItem>;    
+    void layout(const ConstraintsForFlexContent&, LogicalFlexItems&);
+
+private:
+    void computeLogicalWidthForFlexItems(LogicalFlexItems&, LayoutUnit availableSpace);
+    void computeLogicalWidthForStretchingFlexItems(LogicalFlexItems&, LayoutUnit availableSpace);
+    void computeLogicalWidthForShrinkingFlexItems(LogicalFlexItems&, LayoutUnit availableSpace);
+    void computeLogicalHeightForFlexItems(LogicalFlexItems&, LayoutUnit availableSpace);
+    void alignFlexItems(LogicalFlexItems&, LayoutUnit availableSpace);
+    void justifyFlexItems(LogicalFlexItems&, LayoutUnit availableSpace);
+    LayoutUnit computeAvailableLogicalVerticalSpace(LogicalFlexItems&, const ConstraintsForFlexContent&) const;
+    LayoutUnit computeAvailableLogicalHorizontalSpace(LogicalFlexItems&, const ConstraintsForFlexContent&) const;
+
+    const FlexFormattingState& formattingState() const { return m_formattingState; }
+    const RenderStyle& flexBoxStyle() const { return m_flexBoxStyle; }
+
+    const FlexFormattingState& m_formattingState;
+    const RenderStyle& m_flexBoxStyle;
+};
+
+}
+}
+
+#endif
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to