Title: [294804] trunk/Source/WebCore/layout/formattingContexts/flex
Revision
294804
Author
za...@apple.com
Date
2022-05-25 10:29:16 -0700 (Wed, 25 May 2022)

Log Message

Expand flex-grow support
https://bugs.webkit.org/show_bug.cgi?id=240898

Reviewed by Antti Koivisto.

This patch add support for flex-grow. This property defines how flex items take over the available space.

* Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.cpp:
(WebCore::Layout::FlexFormattingContext::computeLogicalWidthForFlexItems):
(WebCore::Layout::FlexFormattingContext::layoutInFlowContentForIntegration):
* Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.h:

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

Modified Paths

Diff

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


--- trunk/Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.cpp	2022-05-25 17:22:59 UTC (rev 294803)
+++ trunk/Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.cpp	2022-05-25 17:29:16 UTC (rev 294804)
@@ -204,44 +204,89 @@
     }
 }
 
-void FlexFormattingContext::layoutInFlowContentForIntegration(const ConstraintsForInFlowContent& constraints)
+void FlexFormattingContext::computeLogicalWidthForFlexItems(LogicalFlexItems& logicalFlexItemList, const ConstraintsForFlexContent& flexConstraints)
 {
     auto& formattingState = this->formattingState();
-    auto logicalFlexItemList = convertFlexItemsToLogicalSpace();
 
+    auto flexDirection = root().style().flexDirection();
+    auto flexDirectionIsInlineAxis = flexDirection == FlexDirection::Row || flexDirection == FlexDirection::RowReverse;
+    auto availableSpace = std::optional<LayoutUnit> { flexDirectionIsInlineAxis ? std::make_optional(flexConstraints.horizontal().logicalWidth) : flexConstraints.availableVerticalSpace() };
+
     auto totalGrowth = 0.f;
-    auto totalFixedSpace = LayoutUnit { };
+    auto totalFlexibleSpace = *availableSpace;
+    auto flexGrowBase = 0.f;
+    Vector<size_t> flexingItems;
 
-    for (auto& logicalFlexItem : logicalFlexItemList) {
-        totalGrowth += logicalFlexItem.layoutBox->style().flexGrow();
-        totalFixedSpace += formattingState.intrinsicWidthConstraintsForBox(*logicalFlexItem.layoutBox)->minimum;
-    }
+    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 (size_t index = 0; index < logicalFlexItemList.size(); ++index) {
+            auto& logicalFlexItem = logicalFlexItemList[index];
+            if (auto flexGrow = logicalFlexItem.layoutBox->style().flexGrow()) {
+                flexingItems.append(index);
+                totalGrowth += flexGrow;
+            } else
+                totalFlexibleSpace -= logicalFlexItem.rect.width();
+        }
+        if (totalGrowth)
+            flexGrowBase = totalFlexibleSpace / totalGrowth;
+    };
+    computeTotalGrowthAndFlexibleSpace();
 
+    auto totalLogicalWidth = [&] {
+        // 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 { };
+        for (auto flexItemIndex : flexingItems) {
+            auto& flexItem = logicalFlexItemList[flexItemIndex];
+
+            auto flexGrow = flexItem.layoutBox->style().flexGrow();
+            auto flexedSize = flexGrow * flexGrowBase;
+            auto minimumSize = formattingState.intrinsicWidthConstraintsForBox(*flexItem.layoutBox)->minimum;
+            if (minimumSize >= flexedSize) {
+                accumulatedWidth += minimumSize;
+                totalGrowth -= flexGrow;
+            } else
+                accumulatedWidth += flexedSize;
+        }
+        return accumulatedWidth;
+    }();
+    auto overflowWidth = totalLogicalWidth - totalFlexibleSpace;
+    ASSERT(overflowWidth >= 0);
+
+    auto computeLogicalWidth = [&] {
+        // Adjust the total grow width by the overflow value (shrink) except when min content with disagrees.
+        for (auto flexItemIndex : flexingItems) {
+            auto& flexItem = logicalFlexItemList[flexItemIndex];
+
+            auto flexGrow = flexItem.layoutBox->style().flexGrow();
+            auto flexedSize = flexGrow * flexGrowBase;
+            auto minimumSize = formattingState.intrinsicWidthConstraintsForBox(*flexItem.layoutBox)->minimum;
+            if (minimumSize >= flexedSize)
+                flexItem.rect.setWidth(minimumSize);
+            else {
+                auto distributedOverflow = overflowWidth / totalGrowth * flexGrow;
+                flexItem.rect.setWidth(std::max(minimumSize, LayoutUnit { flexedSize - distributedOverflow }));
+            }
+        }
+    };
+    computeLogicalWidth();
+}
+
+void FlexFormattingContext::layoutInFlowContentForIntegration(const ConstraintsForInFlowContent& constraints)
+{
+    auto logicalFlexItemList = convertFlexItemsToLogicalSpace();
+
     auto flexConstraints = downcast<ConstraintsForFlexContent>(constraints);
     auto logicalLeft = LayoutUnit { };
     auto logicalTop = LayoutUnit { };
-    auto flexDirection = root().style().flexDirection();
-    auto flexDirectionIsInlineAxis = flexDirection == FlexDirection::Row || flexDirection == FlexDirection::RowReverse;
-    auto availableSpace = std::optional<LayoutUnit> { flexDirectionIsInlineAxis ? std::make_optional(flexConstraints.horizontal().logicalWidth) : flexConstraints.availableVerticalSpace() };
-    auto flexibleSpace = availableSpace.value_or(0_lu) - totalFixedSpace;
 
+    computeLogicalWidthForFlexItems(logicalFlexItemList, flexConstraints);
+
     for (auto& logicalFlexItem : logicalFlexItemList) {
         logicalFlexItem.rect.setTopLeft({ logicalLeft, logicalTop });
         logicalLeft = logicalFlexItem.rect.right();
-        auto growFlexItemIfApplicable = [&] {
-            if (flexibleSpace <= 0)
-                return;
-            auto grow = logicalFlexItem.layoutBox->style().flexGrow();
-            if (!grow)
-                return;
-            // This value specifies the flex grow factor, which determines how much the flex item will grow relative to the
-            // rest of the flex items in the flex container when positive free space is distributed.
-            ASSERT(availableSpace.has_value());
-            // FIXME: This is still slighly incorrect.
-            logicalFlexItem.rect.setWidth(LayoutUnit { formattingState.intrinsicWidthConstraintsForBox(*logicalFlexItem.layoutBox)->minimum + (flexibleSpace * grow / totalGrowth) });
-            // FIXME: constrain logical width on min width.
-        };
-        growFlexItemIfApplicable();
     }
     setFlexItemsGeometry(logicalFlexItemList, flexConstraints);
 }

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


--- trunk/Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.h	2022-05-25 17:22:59 UTC (rev 294803)
+++ trunk/Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.h	2022-05-25 17:29:16 UTC (rev 294804)
@@ -65,6 +65,7 @@
     using LogicalFlexItems = Vector<LogicalFlexItem>;
     LogicalFlexItems convertFlexItemsToLogicalSpace();
     void setFlexItemsGeometry(const LogicalFlexItems&, const ConstraintsForFlexContent&);
+    void computeLogicalWidthForFlexItems(LogicalFlexItems&, const ConstraintsForFlexContent&);
 
     const FlexFormattingState& formattingState() const { return downcast<FlexFormattingState>(FormattingContext::formattingState()); }
     FlexFormattingState& formattingState() { return downcast<FlexFormattingState>(FormattingContext::formattingState()); }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to