Skip to content

Commit

Permalink
[FFC] Add support for [9.2.3.E] use max-content when flex-basis is co…
Browse files Browse the repository at this point in the history
…ntent...

https://bugs.webkit.org/show_bug.cgi?id=258761

Reviewed by Antti Koivisto.

Partially implement https://www.w3.org/TR/css-flexbox-1/#algo-main-item 9.3.3.E when
content should be sized using max-content.

1. IFC type of flex item only
2. Use non-integration codepath to compute max-content for now

* Source/WebCore/layout/formattingContexts/flex/FlexFormattingContext.cpp:
(WebCore::Layout::FlexFormattingContext::layout):
* Source/WebCore/layout/formattingContexts/flex/FlexLayout.cpp:
(WebCore::Layout::FlexLayout::FlexLayout):
(WebCore::Layout::FlexLayout::maxContentForFlexItem const):
(WebCore::Layout::FlexLayout::flexBaseAndHypotheticalMainSizeForFlexItems const):
(WebCore::Layout::FlexLayout::stretchFlexLines const):
(WebCore::Layout::FlexLayout::handleMainAxisAlignment const):
(WebCore::Layout::FlexLayout::handleCrossAxisAlignmentForFlexItems const):
(WebCore::Layout::FlexLayout::handleCrossAxisAlignmentForFlexLines const):
(WebCore::Layout::FlexLayout::flexContainer const):
(WebCore::Layout::FlexLayout::flexFormattingContext const):
* Source/WebCore/layout/formattingContexts/flex/FlexLayout.h:
(WebCore::Layout::FlexLayout::isSingleLineFlexContainer const):
(WebCore::Layout::FlexLayout::flexContainerStyle const):
(WebCore::Layout::FlexLayout::flexContainer const): Deleted.
(WebCore::Layout::FlexLayout::rootStyle const): Deleted.
* Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp:
(WebCore::Layout::InlineFormattingContext::maximumContentSize):
* Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.h:

Canonical link: https://commits.webkit.org/265690@main
  • Loading branch information
alanbaradlay committed Jul 1, 2023
1 parent 689be3c commit 01a8c97
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ FlexFormattingContext::FlexFormattingContext(const ElementBox& formattingContext
void FlexFormattingContext::layout(const ConstraintsForFlexContent& constraints)
{
auto logicalFlexItems = convertFlexItemsToLogicalSpace(constraints);
auto flexLayout = FlexLayout { root() };
auto flexLayout = FlexLayout { *this };

auto logicalFlexConstraints = [&] {
auto flexDirection = root().style().flexDirection();
Expand Down
70 changes: 49 additions & 21 deletions Source/WebCore/layout/formattingContexts/flex/FlexLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "FlexFormattingContext.h"
#include "FlexFormattingGeometry.h"
#include "FlexRect.h"
#include "InlineFormattingContext.h"
#include "RenderStyleSetters.h"
#include "StyleContentAlignmentData.h"
#include "StyleSelfAlignmentData.h"
Expand All @@ -51,8 +52,8 @@ struct PositionAndMargins {
LayoutUnit marginEnd;
};

FlexLayout::FlexLayout(const ElementBox& flexContainer)
: m_flexContainer(flexContainer)
FlexLayout::FlexLayout(const FlexFormattingContext& flexFormattingContext)
: m_flexFormattingContext(flexFormattingContext)
{
}

Expand Down Expand Up @@ -152,23 +153,40 @@ void FlexLayout::computeAvailableMainAndCrossSpace(const LogicalConstraints& log
m_availableCrossSpace = computedFinalSize(logicalConstraints.crossAxis);
}

LayoutUnit FlexLayout::maxContentForFlexItem(const LogicalFlexItem& flexItem) const
{
// 9.2.3 E Otherwise, size the item into the available space using its used flex basis in place of its main size,
// treating a value of content as max-content. If a cross size is needed to determine the main size (e.g. when the flex item’s main size
// is in its block axis) and the flex item’s cross size is auto and not definite, in this calculation use fit-content as the flex item’s cross size.
// The flex base size is the item’s resulting main size.
auto& flexItemBox = flexItem.layoutBox();
if (!flexItemBox.establishesInlineFormattingContext()) {
ASSERT_NOT_IMPLEMENTED_YET();
return { };
}

if (flexItem.isOrhogonal() && !flexItem.crossAxis().definiteSize) {
ASSERT_NOT_IMPLEMENTED_YET();
return { };
}
auto& inlineFormattingState = flexFormattingContext().layoutState().ensureInlineFormattingState(flexItemBox);
return InlineFormattingContext { flexItemBox, inlineFormattingState, { } }.maximumContentSize();
}

FlexLayout::FlexBaseAndHypotheticalMainSizeList FlexLayout::flexBaseAndHypotheticalMainSizeForFlexItems(const LogicalConstraints::AxisGeometry& mainAxis, const LogicalFlexItems& flexItems) const
{
auto flexBaseAndHypotheticalMainSizeList = FlexBaseAndHypotheticalMainSizeList { };
for (auto& flexItem : flexItems) {
auto flexBase = LayoutUnit { };
// 3. Determine the flex base size and hypothetical main size of each item:
auto computeFlexBase = [&] {
auto computedFlexBase = [&]() -> LayoutUnit {
// A. If the item has a definite used flex basis, that's the flex base size.
if (auto definiteFlexBase = flexItem.mainAxis().definiteFlexBasis) {
flexBase = *definiteFlexBase;
return;
}
if (auto definiteFlexBase = flexItem.mainAxis().definiteFlexBasis)
return *definiteFlexBase;
// B. If the flex item has...
if (flexItem.hasAspectRatio() && flexItem.hasContentFlexBasis() && flexItem.crossAxis().definiteSize) {
// The flex base size is calculated from its inner cross size and the flex item's intrinsic aspect ratio.
ASSERT_NOT_IMPLEMENTED_YET();
return;
return { };
}
// C. If the used flex basis is content or depends on its available space, and the flex container is being sized under
// a min-content or max-content constraint, size the item under that constraint
Expand All @@ -177,29 +195,29 @@ FlexLayout::FlexBaseAndHypotheticalMainSizeList FlexLayout::flexBaseAndHypotheti
if (flexBasisContentOrAvailableSpaceDependent && flexContainerHasMinMaxConstraints) {
// Compute flex item's main size.
ASSERT_NOT_IMPLEMENTED_YET();
return;
return { };
}
// D. If the used flex basis is content or depends on its available space, the available main size is infinite,
// and the flex item's inline axis is parallel to the main axis, lay the item out using the rules for a box in an orthogonal flow.
// The flex base size is the item's max-content main size.
if (flexBasisContentOrAvailableSpaceDependent && flexItem.isOrhogonal()) {
// Lay the item out using the rules for a box in an orthogonal flow. The flex base size is the item's max-content main size.
ASSERT_NOT_IMPLEMENTED_YET();
return;
return { };
}
// E. Otherwise, size the item into the available space using its used flex basis in place of its main size, treating a value of content as max-content.
ASSERT_NOT_IMPLEMENTED_YET();
return maxContentForFlexItem(flexItem);
};
computeFlexBase();
auto flexBaseSize = computedFlexBase();

auto hypotheticalMainSize = [&] {
// The hypothetical main size is the item's flex base size clamped according to its used min and max main sizes (and flooring the content box size at zero).
auto hypotheticalValue = flexBase;
auto hypotheticalValue = flexBaseSize;
auto maximum = flexItem.mainAxis().maximumSize.value_or(hypotheticalValue);
auto minimum = flexItem.mainAxis().minimumSize.value_or(hypotheticalValue);
return std::max(maximum, std::min(minimum, hypotheticalValue));
};
flexBaseAndHypotheticalMainSizeList.append({ flexBase, hypotheticalMainSize() });
flexBaseAndHypotheticalMainSizeList.append({ flexBaseSize, hypotheticalMainSize() });
}
return flexBaseAndHypotheticalMainSizeList;
}
Expand Down Expand Up @@ -449,7 +467,7 @@ void FlexLayout::stretchFlexLines(LinesCrossSizeList& flexLinesCrossSizeList, si
// Handle 'align-content: stretch'.
// If the flex container has a definite cross size, align-content is stretch, and the sum of the flex lines' cross sizes is less than the flex container's inner cross size,
// increase the cross size of each flex line by equal amounts such that the sum of their cross sizes exactly equals the flex container's inner cross size.
if (rootStyle().alignContent().distribution() != ContentDistribution::Stretch || !crossAxis.definiteSize)
if (flexContainerStyle().alignContent().distribution() != ContentDistribution::Stretch || !crossAxis.definiteSize)
return;

auto linesCrossSize = [&] {
Expand Down Expand Up @@ -550,7 +568,7 @@ FlexLayout::PositionAndMarginsList FlexLayout::handleMainAxisAlignment(LayoutUni

auto justifyContent = [&] {
// 2. Align the items along the main-axis per justify-content.
auto justifyContentValue = rootStyle().justifyContent();
auto justifyContentValue = flexContainerStyle().justifyContent();
auto initialOffset = [&] {
switch (justifyContentValue.distribution()) {
case ContentDistribution::Default:
Expand Down Expand Up @@ -699,7 +717,7 @@ FlexLayout::PositionAndMarginsList FlexLayout::handleCrossAxisAlignmentForFlexIt
auto flexitemOuterCrossPosition = LayoutUnit { };

auto& flexItemAlignSelf = flexItem.style().alignSelf();
auto alignValue = flexItemAlignSelf.position() != ItemPosition::Auto ? flexItemAlignSelf : rootStyle().alignItems();
auto alignValue = flexItemAlignSelf.position() != ItemPosition::Auto ? flexItemAlignSelf : flexContainerStyle().alignItems();
switch (alignValue.position()) {
case ItemPosition::Stretch:
case ItemPosition::Normal: {
Expand Down Expand Up @@ -752,7 +770,7 @@ FlexLayout::LinesCrossPositionList FlexLayout::handleCrossAxisAlignmentForFlexLi
auto flexContainerUsedCrossSize = crossAxis.definiteSize.value_or(flexLinesCrossSize);
// Align all flex lines per align-content.
auto initialOffset = [&]() -> LayoutUnit {
switch (rootStyle().alignContent().position()) {
switch (flexContainerStyle().alignContent().position()) {
case ContentPosition::Start:
case ContentPosition::Normal:
return { };
Expand All @@ -761,7 +779,7 @@ FlexLayout::LinesCrossPositionList FlexLayout::handleCrossAxisAlignmentForFlexLi
case ContentPosition::End:
return flexContainerUsedCrossSize - flexLinesCrossSize;
default:
switch (rootStyle().alignContent().distribution()) {
switch (flexContainerStyle().alignContent().distribution()) {
case ContentDistribution::SpaceBetween:
case ContentDistribution::Stretch:
return { };
Expand All @@ -782,7 +800,7 @@ FlexLayout::LinesCrossPositionList FlexLayout::handleCrossAxisAlignmentForFlexLi
auto extraCrossSpace = flexContainerUsedCrossSize - flexLinesCrossSize;
if (extraCrossSpace <= 0)
return { };
switch (rootStyle().alignContent().distribution()) {
switch (flexContainerStyle().alignContent().distribution()) {
case ContentDistribution::SpaceBetween:
return extraCrossSpace / (lineRanges.size() - 1);
case ContentDistribution::SpaceAround:
Expand All @@ -809,5 +827,15 @@ FlexLayout::LinesCrossPositionList FlexLayout::handleCrossAxisAlignmentForFlexLi
return linesCrossPositionList;
}

const ElementBox& FlexLayout::flexContainer() const
{
return flexFormattingContext().root();
}

const FlexFormattingContext& FlexLayout::flexFormattingContext() const
{
return m_flexFormattingContext;
}

}
}
13 changes: 8 additions & 5 deletions Source/WebCore/layout/formattingContexts/flex/FlexLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ struct PositionAndMargins;
// https://www.w3.org/TR/css-flexbox-1/
class FlexLayout {
public:
FlexLayout(const ElementBox& flexContainer);
FlexLayout(const FlexFormattingContext&);

using LogicalFlexItems = Vector<LogicalFlexItem>;
struct LogicalConstraints {
Expand Down Expand Up @@ -82,12 +82,15 @@ class FlexLayout {
PositionAndMarginsList handleCrossAxisAlignmentForFlexItems(const LogicalFlexItems&, const LineRanges&, const SizeList& flexItemsCrossSizeList, const LinesCrossSizeList& flexLinesCrossSizeList) const;
LinesCrossPositionList handleCrossAxisAlignmentForFlexLines(const LogicalConstraints::AxisGeometry& crossAxis, const LineRanges&, LinesCrossSizeList& flexLinesCrossSizeList) const;

bool isSingleLineFlexContainer() const { return m_flexContainer.style().flexWrap() == FlexWrap::NoWrap; }
const ElementBox& flexContainer() const { return m_flexContainer; }
const RenderStyle& rootStyle() const { return flexContainer().style(); }
LayoutUnit maxContentForFlexItem(const LogicalFlexItem&) const;

bool isSingleLineFlexContainer() const { return flexContainer().style().flexWrap() == FlexWrap::NoWrap; }
const ElementBox& flexContainer() const;
const FlexFormattingContext& flexFormattingContext() const;
const RenderStyle& flexContainerStyle() const { return flexContainer().style(); }

private:
const ElementBox& m_flexContainer;
const FlexFormattingContext& m_flexFormattingContext;

LayoutUnit m_availableMainSpace;
LayoutUnit m_availableCrossSpace;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,18 @@ IntrinsicWidthConstraints InlineFormattingContext::computedIntrinsicWidthConstra
return constraints;
}

LayoutUnit InlineFormattingContext::maximumContentSize()
{
auto& inlineFormattingState = formattingState();
if (auto intrinsicWidthConstraints = inlineFormattingState.intrinsicWidthConstraints())
return intrinsicWidthConstraints->maximum;

if (inlineFormattingState.inlineItems().isEmpty())
InlineItemsBuilder { root(), inlineFormattingState }.build({ });

return ceiledLayoutUnit(computedIntrinsicWidthForConstraint(IntrinsicWidthMode::Maximum));
}

static InlineItemPosition leadingInlineItemPositionForNextLine(InlineItemPosition lineContentEnd, std::optional<InlineItemPosition> previousLineTrailingInlineItemPosition, InlineItemPosition layoutRangeEnd)
{
if (!previousLineTrailingInlineItemPosition)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class InlineFormattingContext final : public FormattingContext {
InlineLayoutResult layoutInFlowAndFloatContent(const ConstraintsForInlineContent&, InlineLayoutState&);
void layoutOutOfFlowContent(const ConstraintsForInlineContent&, InlineLayoutState&, const InlineDisplay::Content&);
IntrinsicWidthConstraints computedIntrinsicWidthConstraints() override;
LayoutUnit maximumContentSize();

const InlineFormattingGeometry& formattingGeometry() const final { return m_inlineFormattingGeometry; }
const InlineFormattingQuirks& formattingQuirks() const final { return m_inlineFormattingQuirks; }
Expand Down

0 comments on commit 01a8c97

Please sign in to comment.