Changeset 294804 in webkit


Ignore:
Timestamp:
May 25, 2022 10:29:16 AM (2 years ago)
Author:
Alan Bujtas
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

Location:
trunk/Source/WebCore/layout/formattingContexts/flex
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.cpp

    r294755 r294804  
    205205}
    206206
     207void FlexFormattingContext::computeLogicalWidthForFlexItems(LogicalFlexItems& logicalFlexItemList, const ConstraintsForFlexContent& flexConstraints)
     208{
     209    auto& formattingState = this->formattingState();
     210
     211    auto flexDirection = root().style().flexDirection();
     212    auto flexDirectionIsInlineAxis = flexDirection == FlexDirection::Row || flexDirection == FlexDirection::RowReverse;
     213    auto availableSpace = std::optional<LayoutUnit> { flexDirectionIsInlineAxis ? std::make_optional(flexConstraints.horizontal().logicalWidth) : flexConstraints.availableVerticalSpace() };
     214
     215    auto totalGrowth = 0.f;
     216    auto totalFlexibleSpace = *availableSpace;
     217    auto flexGrowBase = 0.f;
     218    Vector<size_t> flexingItems;
     219
     220    auto computeTotalGrowthAndFlexibleSpace = [&] {
     221        // Collect flex items with non-zero flex-grow value. flex-grow: 0 (initial) flex items
     222        // don't participate in available space distribution.
     223        for (size_t index = 0; index < logicalFlexItemList.size(); ++index) {
     224            auto& logicalFlexItem = logicalFlexItemList[index];
     225            if (auto flexGrow = logicalFlexItem.layoutBox->style().flexGrow()) {
     226                flexingItems.append(index);
     227                totalGrowth += flexGrow;
     228            } else
     229                totalFlexibleSpace -= logicalFlexItem.rect.width();
     230        }
     231        if (totalGrowth)
     232            flexGrowBase = totalFlexibleSpace / totalGrowth;
     233    };
     234    computeTotalGrowthAndFlexibleSpace();
     235
     236    auto totalLogicalWidth = [&] {
     237        // This is where we compute how much space the flexing boxes take up if we just
     238        // let them flex by their flex-grow value. Note that we can't size them below their minimum content width.
     239        // Such flex items are removed from the final overflow distribution.
     240        auto accumulatedWidth = LayoutUnit { };
     241        for (auto flexItemIndex : flexingItems) {
     242            auto& flexItem = logicalFlexItemList[flexItemIndex];
     243
     244            auto flexGrow = flexItem.layoutBox->style().flexGrow();
     245            auto flexedSize = flexGrow * flexGrowBase;
     246            auto minimumSize = formattingState.intrinsicWidthConstraintsForBox(*flexItem.layoutBox)->minimum;
     247            if (minimumSize >= flexedSize) {
     248                accumulatedWidth += minimumSize;
     249                totalGrowth -= flexGrow;
     250            } else
     251                accumulatedWidth += flexedSize;
     252        }
     253        return accumulatedWidth;
     254    }();
     255    auto overflowWidth = totalLogicalWidth - totalFlexibleSpace;
     256    ASSERT(overflowWidth >= 0);
     257
     258    auto computeLogicalWidth = [&] {
     259        // Adjust the total grow width by the overflow value (shrink) except when min content with disagrees.
     260        for (auto flexItemIndex : flexingItems) {
     261            auto& flexItem = logicalFlexItemList[flexItemIndex];
     262
     263            auto flexGrow = flexItem.layoutBox->style().flexGrow();
     264            auto flexedSize = flexGrow * flexGrowBase;
     265            auto minimumSize = formattingState.intrinsicWidthConstraintsForBox(*flexItem.layoutBox)->minimum;
     266            if (minimumSize >= flexedSize)
     267                flexItem.rect.setWidth(minimumSize);
     268            else {
     269                auto distributedOverflow = overflowWidth / totalGrowth * flexGrow;
     270                flexItem.rect.setWidth(std::max(minimumSize, LayoutUnit { flexedSize - distributedOverflow }));
     271            }
     272        }
     273    };
     274    computeLogicalWidth();
     275}
     276
    207277void FlexFormattingContext::layoutInFlowContentForIntegration(const ConstraintsForInFlowContent& constraints)
    208278{
    209     auto& formattingState = this->formattingState();
    210279    auto logicalFlexItemList = convertFlexItemsToLogicalSpace();
    211 
    212     auto totalGrowth = 0.f;
    213     auto totalFixedSpace = LayoutUnit { };
    214 
    215     for (auto& logicalFlexItem : logicalFlexItemList) {
    216         totalGrowth += logicalFlexItem.layoutBox->style().flexGrow();
    217         totalFixedSpace += formattingState.intrinsicWidthConstraintsForBox(*logicalFlexItem.layoutBox)->minimum;
    218     }
    219280
    220281    auto flexConstraints = downcast<ConstraintsForFlexContent>(constraints);
    221282    auto logicalLeft = LayoutUnit { };
    222283    auto logicalTop = LayoutUnit { };
    223     auto flexDirection = root().style().flexDirection();
    224     auto flexDirectionIsInlineAxis = flexDirection == FlexDirection::Row || flexDirection == FlexDirection::RowReverse;
    225     auto availableSpace = std::optional<LayoutUnit> { flexDirectionIsInlineAxis ? std::make_optional(flexConstraints.horizontal().logicalWidth) : flexConstraints.availableVerticalSpace() };
    226     auto flexibleSpace = availableSpace.value_or(0_lu) - totalFixedSpace;
     284
     285    computeLogicalWidthForFlexItems(logicalFlexItemList, flexConstraints);
    227286
    228287    for (auto& logicalFlexItem : logicalFlexItemList) {
    229288        logicalFlexItem.rect.setTopLeft({ logicalLeft, logicalTop });
    230289        logicalLeft = logicalFlexItem.rect.right();
    231         auto growFlexItemIfApplicable = [&] {
    232             if (flexibleSpace <= 0)
    233                 return;
    234             auto grow = logicalFlexItem.layoutBox->style().flexGrow();
    235             if (!grow)
    236                 return;
    237             // This value specifies the flex grow factor, which determines how much the flex item will grow relative to the
    238             // rest of the flex items in the flex container when positive free space is distributed.
    239             ASSERT(availableSpace.has_value());
    240             // FIXME: This is still slighly incorrect.
    241             logicalFlexItem.rect.setWidth(LayoutUnit { formattingState.intrinsicWidthConstraintsForBox(*logicalFlexItem.layoutBox)->minimum + (flexibleSpace * grow / totalGrowth) });
    242             // FIXME: constrain logical width on min width.
    243         };
    244         growFlexItemIfApplicable();
    245290    }
    246291    setFlexItemsGeometry(logicalFlexItemList, flexConstraints);
  • trunk/Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.h

    r294623 r294804  
    6666    LogicalFlexItems convertFlexItemsToLogicalSpace();
    6767    void setFlexItemsGeometry(const LogicalFlexItems&, const ConstraintsForFlexContent&);
     68    void computeLogicalWidthForFlexItems(LogicalFlexItems&, const ConstraintsForFlexContent&);
    6869
    6970    const FlexFormattingState& formattingState() const { return downcast<FlexFormattingState>(FormattingContext::formattingState()); }
Note: See TracChangeset for help on using the changeset viewer.