Title: [295051] trunk/Source/WebCore/layout
Revision
295051
Author
za...@apple.com
Date
2022-05-31 06:41:03 -0700 (Tue, 31 May 2022)

Log Message

Add support for margin: auto
https://bugs.webkit.org/show_bug.cgi?id=241111

Reviewed by Antti Koivisto.

Auto margins take up all of the space that they can in their axis.
1. compute the space 'margin: auto' can take
2. distribute it among flex items with 'margin: auto'
3. adjust final top/left with the computed margin

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

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

Modified Paths

Diff

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


--- trunk/Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.cpp	2022-05-31 13:39:54 UTC (rev 295050)
+++ trunk/Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.cpp	2022-05-31 13:41:03 UTC (rev 295051)
@@ -119,8 +119,36 @@
     }
 }
 
-FlexLayout::LogicalFlexItems FlexFormattingContext::convertFlexItemsToLogicalSpace()
+std::optional<LayoutUnit> FlexFormattingContext::computedAutoMarginValueForFlexItems(const ConstraintsForFlexContent& constraints)
 {
+    auto flexDirection = root().style().flexDirection();
+    auto flexDirectionIsInlineAxis = flexDirection == FlexDirection::Row || flexDirection == FlexDirection::RowReverse;
+    auto availableSpace = flexDirectionIsInlineAxis ? std::make_optional(constraints.horizontal().logicalWidth) : constraints.availableVerticalSpace();
+    if (!availableSpace)
+        return { };
+
+    size_t autoMarginCount = 0;
+    auto logicalWidth = LayoutUnit { };
+
+    for (auto* flexItem = root().firstInFlowChild(); flexItem; flexItem = flexItem->nextInFlowSibling()) {
+        auto& flexItemStyle = flexItem->style();
+        auto hasAutoMarginStart = flexDirectionIsInlineAxis ? flexItemStyle.marginStart().isAuto() : flexItemStyle.marginBefore().isAuto();
+        auto hasAutoMarginEnd = flexDirectionIsInlineAxis ? flexItemStyle.marginEnd().isAuto() : flexItemStyle.marginAfter().isAuto();
+        if (hasAutoMarginStart)
+            ++autoMarginCount;
+        if (hasAutoMarginEnd)
+            ++autoMarginCount;
+
+        auto& flexItemGeometry = formattingState().boxGeometry(*flexItem);
+        logicalWidth += flexDirectionIsInlineAxis ? flexItemGeometry.marginBoxWidth() : flexItemGeometry.marginBoxHeight();
+    }
+    if (autoMarginCount)
+        return std::max(0_lu, *availableSpace - logicalWidth) / autoMarginCount;
+    return { };
+}
+
+FlexLayout::LogicalFlexItems FlexFormattingContext::convertFlexItemsToLogicalSpace(const ConstraintsForFlexContent& constraints)
+{
     struct FlexItem {
         FlexRect marginRect;
         int logicalOrder { 0 };
@@ -129,6 +157,7 @@
     auto& formattingState = this->formattingState();
     Vector<FlexItem> flexItemList;
     auto flexItemsNeedReordering = false;
+    auto autoMarginValue = computedAutoMarginValueForFlexItems(constraints);
 
     auto convertVisualToLogical = [&] {
         auto direction = root().style().flexDirection();
@@ -136,22 +165,39 @@
 
         for (auto* flexItem = root().firstInFlowChild(); flexItem; flexItem = flexItem->nextInFlowSibling()) {
             auto& flexItemGeometry = formattingState.boxGeometry(*flexItem);
+            auto& flexItemStyle = flexItem->style();
             auto logicalSize = LayoutSize { };
 
             switch (direction) {
             case FlexDirection::Row:
-            case FlexDirection::RowReverse:
+            case FlexDirection::RowReverse: {
+                auto hasAutoMarginStart = flexItemStyle.marginStart().isAuto();
+                auto hasAutoMarginEnd = flexItemStyle.marginEnd().isAuto();
+                if (autoMarginValue && (hasAutoMarginStart || hasAutoMarginEnd)) {
+                    auto horizontalMargin = flexItemGeometry.horizontalMargin();
+                    horizontalMargin = { hasAutoMarginStart ? *autoMarginValue : horizontalMargin.start, hasAutoMarginEnd ? *autoMarginValue : horizontalMargin.end };
+                    flexItemGeometry.setHorizontalMargin(horizontalMargin);
+                }
                 logicalSize = { flexItemGeometry.marginBoxWidth(), flexItemGeometry.marginBoxHeight() };
                 break;
+            }
             case FlexDirection::Column:
-            case FlexDirection::ColumnReverse:
+            case FlexDirection::ColumnReverse: {
+                auto hasAutoMarginBefore = flexItemStyle.marginBefore().isAuto();
+                auto hasAutoMarginAfter = flexItemStyle.marginAfter().isAuto();
+                if (autoMarginValue && (hasAutoMarginBefore || hasAutoMarginAfter)) {
+                    auto verticalMargin = flexItemGeometry.verticalMargin();
+                    verticalMargin = { hasAutoMarginBefore ? *autoMarginValue : verticalMargin.before, hasAutoMarginAfter ? *autoMarginValue : verticalMargin.after };
+                    flexItemGeometry.setVerticalMargin(verticalMargin);
+                }
                 logicalSize = { flexItemGeometry.marginBoxHeight(), flexItemGeometry.marginBoxWidth() };
                 break;
+            }
             default:
                 ASSERT_NOT_REACHED();
                 break;
             }
-            auto flexItemOrder = flexItem->style().order();
+            auto flexItemOrder = flexItemStyle.order();
             flexItemsNeedReordering = flexItemsNeedReordering || flexItemOrder != previousLogicalOrder.value_or(0);
             previousLogicalOrder = flexItemOrder;
 
@@ -186,28 +232,40 @@
     auto direction = root().style().flexDirection();
     for (auto& logicalFlexItem : logicalFlexItemList) {
         auto& flexItemGeometry = formattingState.boxGeometry(*logicalFlexItem.layoutBox);
-        auto topLeft = LayoutPoint { };
+        auto borderBoxTopLeft = LayoutPoint { };
 
         switch (direction) {
         case FlexDirection::Row:
-            topLeft = { constraints.horizontal().logicalLeft + logicalFlexItem.marginRect.left(), constraints.logicalTop() + logicalFlexItem.marginRect.top() };
+            borderBoxTopLeft = {
+                constraints.horizontal().logicalLeft + logicalFlexItem.marginRect.left() + flexItemGeometry.marginStart(),
+                constraints.logicalTop() + logicalFlexItem.marginRect.top()
+            };
             break;
         case FlexDirection::RowReverse:
-            topLeft = { constraints.horizontal().logicalRight() - logicalFlexItem.marginRect.right(), constraints.logicalTop() + logicalFlexItem.marginRect.top() };
+            borderBoxTopLeft = {
+                constraints.horizontal().logicalRight() - logicalFlexItem.marginRect.right() + flexItemGeometry.marginStart(),
+                constraints.logicalTop() + logicalFlexItem.marginRect.top()
+            };
             break;
         case FlexDirection::Column: {
             auto flippedTopLeft = logicalFlexItem.marginRect.topLeft().transposedPoint();
-            topLeft = { constraints.horizontal().logicalLeft + flippedTopLeft.x(), constraints.logicalTop() + flippedTopLeft.y() };
+            borderBoxTopLeft = {
+                constraints.horizontal().logicalLeft + flippedTopLeft.x(),
+                constraints.logicalTop() + flippedTopLeft.y() + flexItemGeometry.marginBefore()
+            };
             break;
         }
         case FlexDirection::ColumnReverse:
-            topLeft = { constraints.horizontal().logicalLeft + logicalFlexItem.marginRect.top(), constraints.logicalTop() + logicalWidth - logicalFlexItem.marginRect.right() };
+            borderBoxTopLeft = {
+                constraints.horizontal().logicalLeft + logicalFlexItem.marginRect.top(),
+                constraints.logicalTop() + logicalWidth - logicalFlexItem.marginRect.right() + flexItemGeometry.marginBefore()
+            };
             break;
         default:
             ASSERT_NOT_REACHED();
             break;
         }
-        flexItemGeometry.setLogicalTopLeft(topLeft);
+        flexItemGeometry.setLogicalTopLeft(borderBoxTopLeft);
         if (direction == FlexDirection::Row || direction == FlexDirection::RowReverse) {
             flexItemGeometry.setContentBoxWidth(logicalFlexItem.marginRect.width() - flexItemGeometry.horizontalMarginBorderAndPadding());
             flexItemGeometry.setContentBoxHeight(logicalFlexItem.marginRect.height() - flexItemGeometry.verticalMarginBorderAndPadding());
@@ -221,7 +279,7 @@
 void FlexFormattingContext::layoutInFlowContentForIntegration(const ConstraintsForInFlowContent& constraints)
 {
     auto flexConstraints = downcast<ConstraintsForFlexContent>(constraints);
-    auto logicalFlexItems = convertFlexItemsToLogicalSpace();
+    auto logicalFlexItems = convertFlexItemsToLogicalSpace(flexConstraints);
     auto flexLayout = FlexLayout { formattingState(), root().style() };
     flexLayout.layout(flexConstraints, logicalFlexItems);
     setFlexItemsGeometry(logicalFlexItems, flexConstraints);

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


--- trunk/Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.h	2022-05-31 13:39:54 UTC (rev 295050)
+++ trunk/Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.h	2022-05-31 13:41:03 UTC (rev 295051)
@@ -58,9 +58,11 @@
     void sizeAndPlaceFlexItems(const ConstraintsForFlexContent&);
     void computeIntrinsicWidthConstraintsForFlexItems();
 
-    FlexLayout::LogicalFlexItems convertFlexItemsToLogicalSpace();
+    FlexLayout::LogicalFlexItems convertFlexItemsToLogicalSpace(const ConstraintsForFlexContent&);
     void setFlexItemsGeometry(const FlexLayout::LogicalFlexItems&, const ConstraintsForFlexContent&);
 
+    std::optional<LayoutUnit> computedAutoMarginValueForFlexItems(const ConstraintsForFlexContent&);
+
     const FlexFormattingState& formattingState() const { return downcast<FlexFormattingState>(FormattingContext::formattingState()); }
     FlexFormattingState& formattingState() { return downcast<FlexFormattingState>(FormattingContext::formattingState()); }
 

Modified: trunk/Source/WebCore/layout/integration/flex/LayoutIntegrationFlexLayout.cpp (295050 => 295051)


--- trunk/Source/WebCore/layout/integration/flex/LayoutIntegrationFlexLayout.cpp	2022-05-31 13:39:54 UTC (rev 295050)
+++ trunk/Source/WebCore/layout/integration/flex/LayoutIntegrationFlexLayout.cpp	2022-05-31 13:41:03 UTC (rev 295051)
@@ -148,6 +148,11 @@
         renderer.setLocation(borderBox.topLeft());
         renderer.setWidth(borderBox.width());
         renderer.setHeight(borderBox.height());
+
+        renderer.setMarginStart(flexItemGeometry.marginStart());
+        renderer.setMarginEnd(flexItemGeometry.marginEnd());
+        renderer.setMarginBefore(flexItemGeometry.marginBefore());
+        renderer.setMarginAfter(flexItemGeometry.marginAfter());
     }
 }
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to