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