summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/RenderFlexibleBox.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/rendering/RenderFlexibleBox.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/rendering/RenderFlexibleBox.cpp')
-rw-r--r--Source/WebCore/rendering/RenderFlexibleBox.cpp395
1 files changed, 270 insertions, 125 deletions
diff --git a/Source/WebCore/rendering/RenderFlexibleBox.cpp b/Source/WebCore/rendering/RenderFlexibleBox.cpp
index 9fbfbebad..95b26c330 100644
--- a/Source/WebCore/rendering/RenderFlexibleBox.cpp
+++ b/Source/WebCore/rendering/RenderFlexibleBox.cpp
@@ -34,11 +34,14 @@
#include "LayoutRepainter.h"
#include "RenderLayer.h"
#include "RenderView.h"
+#include "RuntimeEnabledFeatures.h"
#include <limits>
#include <wtf/MathExtras.h>
namespace WebCore {
+static constexpr ItemPosition selfAlignmentNormalBehaviorFlexibleBox = ItemPositionStretch;
+
struct RenderFlexibleBox::LineContext {
LineContext(LayoutUnit crossAxisOffset, LayoutUnit crossAxisExtent, size_t numberOfChildren, LayoutUnit maxAscent)
: crossAxisOffset(crossAxisOffset)
@@ -66,16 +69,16 @@ struct RenderFlexibleBox::Violation {
};
-RenderFlexibleBox::RenderFlexibleBox(Element& element, PassRef<RenderStyle> style)
- : RenderBlock(element, std::move(style), 0)
+RenderFlexibleBox::RenderFlexibleBox(Element& element, RenderStyle&& style)
+ : RenderBlock(element, WTFMove(style), 0)
, m_orderIterator(*this)
, m_numberOfInFlowChildrenOnFirstLine(-1)
{
setChildrenInline(false); // All of our children must be block-level.
}
-RenderFlexibleBox::RenderFlexibleBox(Document& document, PassRef<RenderStyle> style)
- : RenderBlock(document, std::move(style), 0)
+RenderFlexibleBox::RenderFlexibleBox(Document& document, RenderStyle&& style)
+ : RenderBlock(document, WTFMove(style), 0)
, m_orderIterator(*this)
, m_numberOfInFlowChildrenOnFirstLine(-1)
{
@@ -123,9 +126,12 @@ void RenderFlexibleBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidt
}
}
+ // Due to negative margins, it is possible that we calculated a negative intrinsic width.
+ // Make sure that we never return a negative width.
+ minLogicalWidth = std::max(LayoutUnit(), minLogicalWidth);
maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
- LayoutUnit scrollbarWidth = instrinsicScrollbarLogicalWidth();
+ LayoutUnit scrollbarWidth = intrinsicScrollbarLogicalWidth();
maxLogicalWidth += scrollbarWidth;
minLogicalWidth += scrollbarWidth;
}
@@ -169,24 +175,22 @@ static int synthesizedBaselineFromContentBox(const RenderBox& box, LineDirection
int RenderFlexibleBox::baselinePosition(FontBaseline, bool, LineDirectionMode direction, LinePositionMode) const
{
- int baseline = firstLineBaseline();
- if (baseline == -1)
- baseline = synthesizedBaselineFromContentBox(*this, direction);
+ int baseline = firstLineBaseline().value_or(synthesizedBaselineFromContentBox(*this, direction));
int marginAscent = direction == HorizontalLine ? marginTop() : marginRight();
return baseline + marginAscent;
}
-int RenderFlexibleBox::firstLineBaseline() const
+std::optional<int> RenderFlexibleBox::firstLineBaseline() const
{
if (isWritingModeRoot() || m_numberOfInFlowChildrenOnFirstLine <= 0)
- return -1;
- RenderBox* baselineChild = 0;
+ return std::optional<int>();
+ RenderBox* baselineChild = nullptr;
int childNumber = 0;
for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
if (child->isOutOfFlowPositioned())
continue;
- if (alignmentForChild(*child) == AlignBaseline && !hasAutoMarginsInCrossAxis(*child)) {
+ if (alignmentForChild(*child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(*child)) {
baselineChild = child;
break;
}
@@ -199,52 +203,45 @@ int RenderFlexibleBox::firstLineBaseline() const
}
if (!baselineChild)
- return -1;
+ return std::optional<int>();
if (!isColumnFlow() && hasOrthogonalFlow(*baselineChild))
- return crossAxisExtentForChild(*baselineChild) + baselineChild->logicalTop();
+ return std::optional<int>(crossAxisExtentForChild(*baselineChild) + baselineChild->logicalTop());
if (isColumnFlow() && !hasOrthogonalFlow(*baselineChild))
- return mainAxisExtentForChild(*baselineChild) + baselineChild->logicalTop();
+ return std::optional<int>(mainAxisExtentForChild(*baselineChild) + baselineChild->logicalTop());
- int baseline = baselineChild->firstLineBaseline();
- if (baseline == -1) {
+ std::optional<int> baseline = baselineChild->firstLineBaseline();
+ if (!baseline) {
// FIXME: We should pass |direction| into firstLineBoxBaseline and stop bailing out if we're a writing mode root.
// This would also fix some cases where the flexbox is orthogonal to its container.
LineDirectionMode direction = isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
- return synthesizedBaselineFromContentBox(*baselineChild, direction) + baselineChild->logicalTop();
+ return std::optional<int>(synthesizedBaselineFromContentBox(*baselineChild, direction) + baselineChild->logicalTop());
}
- return baseline + baselineChild->logicalTop();
+ return std::optional<int>(baseline.value() + baselineChild->logicalTop());
}
-int RenderFlexibleBox::inlineBlockBaseline(LineDirectionMode direction) const
+std::optional<int> RenderFlexibleBox::inlineBlockBaseline(LineDirectionMode direction) const
{
- int baseline = firstLineBaseline();
- if (baseline != -1)
+ if (std::optional<int> baseline = firstLineBaseline())
return baseline;
int marginAscent = direction == HorizontalLine ? marginTop() : marginRight();
return synthesizedBaselineFromContentBox(*this, direction) + marginAscent;
}
-static EAlignItems resolveAlignment(const RenderStyle* parentStyle, const RenderStyle* childStyle)
-{
- EAlignItems align = childStyle->alignSelf();
- if (align == AlignAuto)
- align = parentStyle->alignItems();
- return align;
-}
-
void RenderFlexibleBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
RenderBlock::styleDidChange(diff, oldStyle);
- if (oldStyle && oldStyle->alignItems() == AlignStretch && diff == StyleDifferenceLayout) {
+ if (oldStyle && oldStyle->resolvedAlignItems(selfAlignmentNormalBehaviorFlexibleBox).position() == ItemPositionStretch && diff == StyleDifferenceLayout) {
// Flex items that were previously stretching need to be relayed out so we can compute new available cross axis space.
// This is only necessary for stretching since other alignment values don't change the size of the box.
+ auto& newStyle = style();
for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
- EAlignItems previousAlignment = resolveAlignment(oldStyle, &child->style());
- if (previousAlignment == AlignStretch && previousAlignment != resolveAlignment(&style(), &child->style()))
+ auto& childStyle = child->style();
+ auto previousAlignment = childStyle.resolvedAlignSelf(*oldStyle, selfAlignmentNormalBehaviorFlexibleBox).position();
+ if (previousAlignment == ItemPositionStretch && previousAlignment != childStyle.resolvedAlignSelf(newStyle, selfAlignmentNormalBehaviorFlexibleBox).position())
child->setChildNeedsLayout(MarkOnlyThis);
}
}
@@ -259,7 +256,7 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
- if (updateLogicalWidthAndColumnWidth())
+ if (recomputeLogicalWidth())
relayoutChildren = true;
LayoutUnit previousHeight = logicalHeight();
@@ -267,34 +264,30 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
LayoutStateMaintainer statePusher(view(), *this, locationOffset(), hasTransform() || hasReflection() || style().isFlippedBlocksWritingMode());
- prepareShapesAndPaginationBeforeBlockLayout(relayoutChildren);
+ preparePaginationBeforeBlockLayout(relayoutChildren);
m_numberOfInFlowChildrenOnFirstLine = -1;
- RenderBlock::startDelayUpdateScrollInfo();
+ beginUpdateScrollInfoAfterLayoutTransaction();
dirtyForLayoutFromPercentageHeightDescendants();
- Vector<LineContext> lineContexts;
- OrderIterator::OrderValues orderValues;
- computeMainAxisPreferredSizes(orderValues);
- m_orderIterator.setOrderValues(std::move(orderValues));
+ prepareOrderIteratorAndMargins();
ChildFrameRects oldChildRects;
appendChildFrameRects(oldChildRects);
+ Vector<LineContext> lineContexts;
layoutFlexItems(relayoutChildren, lineContexts);
updateLogicalHeight();
repositionLogicalHeightDependentFlexItems(lineContexts);
- RenderBlock::finishDelayUpdateScrollInfo();
+ endAndCommitUpdateScrollInfoAfterLayoutTransaction();
if (logicalHeight() != previousHeight)
relayoutChildren = true;
- layoutPositionedObjects(relayoutChildren || isRoot());
-
- updateShapesAfterBlockLayout();
+ layoutPositionedObjects(relayoutChildren || isDocumentElementRenderer());
repaintChildrenDuringLayoutIfMoved(oldChildRects);
// FIXME: css3/flexbox/repaint-rtl-column.html seems to repaint more overflow than it needs to.
@@ -340,7 +333,7 @@ void RenderFlexibleBox::repaintChildrenDuringLayoutIfMoved(const ChildFrameRects
void RenderFlexibleBox::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset, PaintInfo& paintInfoForChild, bool usePrintRect)
{
for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
- if (!paintChild(*child, paintInfo, paintOffset, paintInfoForChild, usePrintRect))
+ if (!paintChild(*child, paintInfo, paintOffset, paintInfoForChild, usePrintRect, PaintAsInlineBlock))
return;
}
}
@@ -375,7 +368,7 @@ LayoutUnit RenderFlexibleBox::clientLogicalBottomAfterRepositioning()
return std::max(clientLogicalBottom(), maxChildLogicalBottom);
}
-bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox& child) const
+bool RenderFlexibleBox::hasOrthogonalFlow(const RenderBox& child) const
{
// FIXME: If the child is a flexbox, then we need to check isHorizontalFlow.
return isHorizontalFlow() != child.isHorizontalWritingMode();
@@ -449,12 +442,11 @@ LayoutUnit RenderFlexibleBox::crossAxisContentExtent() const
LayoutUnit RenderFlexibleBox::mainAxisContentExtent(LayoutUnit contentLogicalHeight)
{
if (isColumnFlow()) {
- LogicalExtentComputedValues computedValues;
LayoutUnit borderPaddingAndScrollbar = borderAndPaddingLogicalHeight() + scrollbarLogicalHeight();
if (contentLogicalHeight > LayoutUnit::max() - borderPaddingAndScrollbar)
contentLogicalHeight -= borderPaddingAndScrollbar;
LayoutUnit borderBoxLogicalHeight = contentLogicalHeight + borderPaddingAndScrollbar;
- computeLogicalHeight(borderBoxLogicalHeight, logicalTop(), computedValues);
+ auto computedValues = computeLogicalHeight(borderBoxLogicalHeight, logicalTop());
if (computedValues.m_extent == LayoutUnit::max())
return computedValues.m_extent;
return std::max(LayoutUnit::fromPixel(0), computedValues.m_extent - borderPaddingAndScrollbar);
@@ -462,18 +454,19 @@ LayoutUnit RenderFlexibleBox::mainAxisContentExtent(LayoutUnit contentLogicalHei
return contentLogicalWidth();
}
-LayoutUnit RenderFlexibleBox::computeMainAxisExtentForChild(RenderBox& child, SizeType sizeType, const Length& size)
+std::optional<LayoutUnit> RenderFlexibleBox::computeMainAxisExtentForChild(const RenderBox& child, SizeType sizeType, const Length& size)
{
// FIXME: This is wrong for orthogonal flows. It should use the flexbox's writing-mode, not the child's in order
// to figure out the logical height/width.
- // FIXME: This is wrong if the height is set to an intrinsic keyword value. computeContentLogicalHeight will return -1.
- // Instead, we need to layout the child an get the appropriate height value.
- // https://bugs.webkit.org/show_bug.cgi?id=113610
- if (isColumnFlow())
- return child.computeContentLogicalHeight(size);
+ if (isColumnFlow()) {
+ // We don't have to check for "auto" here - computeContentLogicalHeight will just return std::nullopt for that case anyway.
+ if (size.isIntrinsic())
+ const_cast<RenderBox&>(child).layoutIfNeeded(); // FIXME: Should not need to do a layout here.
+ return child.computeContentLogicalHeight(sizeType, size, child.logicalHeight() - child.borderAndPaddingLogicalHeight());
+ }
// FIXME: Figure out how this should work for regions and pass in the appropriate values.
- RenderRegion* region = 0;
- return child.computeLogicalWidthInRegionUsing(sizeType, size, contentLogicalWidth(), this, region) - child.borderAndPaddingLogicalWidth();
+ RenderRegion* region = nullptr;
+ return child.computeLogicalWidthInRegionUsing(sizeType, size, contentLogicalWidth(), *this, region) - child.borderAndPaddingLogicalWidth();
}
WritingMode RenderFlexibleBox::transformedWritingMode() const
@@ -634,7 +627,7 @@ LayoutUnit RenderFlexibleBox::flowAwareMarginAfterForChild(RenderBox& child) con
LayoutUnit RenderFlexibleBox::crossAxisMarginExtentForChild(RenderBox& child) const
{
- return isHorizontalFlow() ? child.marginHeight() : child.marginWidth();
+ return isHorizontalFlow() ? child.verticalMarginExtent() : child.horizontalMarginExtent();
}
LayoutUnit RenderFlexibleBox::crossAxisScrollbarExtent() const
@@ -657,7 +650,16 @@ void RenderFlexibleBox::setFlowAwareLocationForChild(RenderBox& child, const Lay
LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox& child) const
{
- return isHorizontalFlow() ? child.borderAndPaddingWidth() : child.borderAndPaddingHeight();
+ return isHorizontalFlow() ? child.horizontalBorderAndPaddingExtent() : child.verticalBorderAndPaddingExtent();
+}
+
+bool RenderFlexibleBox::mainAxisLengthIsDefinite(const RenderBox& child, const Length& flexBasis) const
+{
+ if (flexBasis.isAuto())
+ return false;
+ if (flexBasis.isPercentOrCalculated())
+ return isColumnFlow() ? bool(child.computePercentageLogicalHeight(flexBasis)) : hasDefiniteLogicalWidth();
+ return true;
}
LayoutUnit RenderFlexibleBox::mainAxisScrollbarExtentForChild(RenderBox& child) const
@@ -667,7 +669,7 @@ LayoutUnit RenderFlexibleBox::mainAxisScrollbarExtentForChild(RenderBox& child)
LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox& child, bool hasInfiniteLineLength)
{
- bool hasOverrideSize = child.hasOverrideWidth() || child.hasOverrideHeight();
+ bool hasOverrideSize = child.hasOverrideLogicalContentWidth() || child.hasOverrideLogicalContentHeight();
if (hasOverrideSize)
child.clearOverrideSize();
@@ -682,7 +684,7 @@ LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox&
ASSERT(mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child) >= 0);
return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child);
}
- return std::max(LayoutUnit::fromPixel(0), computeMainAxisExtentForChild(child, MainOrPreferredSize, flexBasis));
+ return computeMainAxisExtentForChild(child, MainOrPreferredSize, flexBasis).value_or(0);
}
void RenderFlexibleBox::layoutFlexItems(bool relayoutChildren, Vector<LineContext>& lineContexts)
@@ -822,9 +824,7 @@ bool RenderFlexibleBox::updateAutoMarginsInCrossAxis(RenderBox& child, LayoutUni
LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(RenderBox& child)
{
- LayoutUnit ascent = child.firstLineBaseline();
- if (ascent == -1)
- ascent = crossAxisExtentForChild(child);
+ LayoutUnit ascent = child.firstLineBaseline().value_or(crossAxisExtentForChild(child));
return ascent + flowAwareMarginBeforeForChild(child);
}
@@ -836,16 +836,12 @@ LayoutUnit RenderFlexibleBox::computeChildMarginValue(const Length& margin)
return minimumValueForLength(margin, availableSize);
}
-void RenderFlexibleBox::computeMainAxisPreferredSizes(OrderIterator::OrderValues& orderValues)
+void RenderFlexibleBox::prepareOrderIteratorAndMargins()
{
- ASSERT(orderValues.isEmpty());
+ OrderIteratorPopulator populator(m_orderIterator);
for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
- // Avoid growing the vector for the common-case default value of 0. This optimizes the most common case which is
- // one or a few values with the default order 0
- int order = child->style().order();
- if (orderValues.isEmpty() || orderValues.last() != order)
- orderValues.append(order);
+ populator.collectChild(*child);
if (child->isOutOfFlowPositioned())
continue;
@@ -862,20 +858,113 @@ void RenderFlexibleBox::computeMainAxisPreferredSizes(OrderIterator::OrderValues
}
}
-LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox& child, LayoutUnit childSize)
+bool RenderFlexibleBox::crossAxisLengthIsDefinite(const RenderBox& child, const Length& length) const
+{
+ if (length.isAuto())
+ return false;
+ if (length.isPercentOrCalculated())
+ return hasOrthogonalFlow(child) ? hasDefiniteLogicalWidth() : bool(child.computePercentageLogicalHeight(length));
+ return length.isFixed();
+}
+
+
+std::optional<LayoutUnit> RenderFlexibleBox::computeMainSizeFromAspectRatioUsing(const RenderBox& child, Length crossSizeLength) const
+{
+ ASSERT(child.hasAspectRatio());
+ ASSERT(child.intrinsicSize().height() > 0);
+
+ std::optional<LayoutUnit> crossSize;
+ if (crossSizeLength.isFixed())
+ crossSize = LayoutUnit(crossSizeLength.value());
+ else {
+ ASSERT(crossSizeLength.isPercentOrCalculated());
+ crossSize = hasOrthogonalFlow(child) ?
+ adjustBorderBoxLogicalWidthForBoxSizing(valueForLength(crossSizeLength, contentWidth())) :
+ child.computePercentageLogicalHeight(crossSizeLength);
+ }
+
+ if (!crossSize)
+ return crossSize;
+
+ const LayoutSize& childIntrinsicSize = child.intrinsicSize();
+ double ratio = childIntrinsicSize.width().toFloat() / childIntrinsicSize.height().toFloat();
+ if (isHorizontalFlow())
+ return LayoutUnit(crossSize.value() * ratio);
+ return LayoutUnit(crossSize.value() / ratio);
+}
+
+LayoutUnit RenderFlexibleBox::adjustChildSizeForAspectRatioCrossAxisMinAndMax(const RenderBox& child, LayoutUnit childSize)
+{
+ Length crossMin = isHorizontalFlow() ? child.style().minHeight() : child.style().minWidth();
+ Length crossMax = isHorizontalFlow() ? child.style().maxHeight() : child.style().maxWidth();
+
+ if (crossAxisLengthIsDefinite(child, crossMax)) {
+ std::optional<LayoutUnit> maxValue = computeMainSizeFromAspectRatioUsing(child, crossMax);
+ if (maxValue)
+ childSize = std::min(maxValue.value(), childSize);
+ }
+
+ if (crossAxisLengthIsDefinite(child, crossMin)) {
+ std::optional<LayoutUnit> minValue = computeMainSizeFromAspectRatioUsing(child, crossMin);
+ if (minValue)
+ childSize = std::max(minValue.value(), childSize);
+ }
+
+ return childSize;
+}
+
+bool RenderFlexibleBox::useChildAspectRatio(const RenderBox& child) const
+{
+ if (!child.hasAspectRatio())
+ return false;
+ if (!child.intrinsicSize().height())
+ return false;
+ Length crossSize = isHorizontalFlow() ? child.style().height() : child.style().width();
+ return crossAxisLengthIsDefinite(child, crossSize);
+}
+
+LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(const RenderBox& child, LayoutUnit childSize)
{
Length max = isHorizontalFlow() ? child.style().maxWidth() : child.style().maxHeight();
+ std::optional<LayoutUnit> maxExtent = std::nullopt;
if (max.isSpecifiedOrIntrinsic()) {
- LayoutUnit maxExtent = computeMainAxisExtentForChild(child, MaxSize, max);
- if (maxExtent != -1 && childSize > maxExtent)
- childSize = maxExtent;
+ maxExtent = computeMainAxisExtentForChild(child, MaxSize, max);
+ childSize = std::min(childSize, maxExtent.value_or(childSize));
}
-
+
Length min = isHorizontalFlow() ? child.style().minWidth() : child.style().minHeight();
- LayoutUnit minExtent = 0;
if (min.isSpecifiedOrIntrinsic())
- minExtent = computeMainAxisExtentForChild(child, MinSize, min);
- return std::max(childSize, minExtent);
+ return std::max(childSize, computeMainAxisExtentForChild(child, MinSize, min).value_or(childSize));
+
+ if (!isFlexibleBoxImpl() && min.isAuto() && mainAxisOverflowForChild(child) == OVISIBLE && !(isColumnFlow() && is<RenderFlexibleBox>(child))) {
+ // This is the implementation of CSS flexbox section 4.5 which defines the minimum size of "pure" flex
+ // items. For any other item the value should be 0, this also includes RenderFlexibleBox's derived clases
+ // (RenderButton, RenderFullScreen...) because that's just an implementation detail.
+ // FIXME: For now we don't handle nested column flexboxes. Need to implement better intrinsic
+ // size handling from the flex box spec first (4.5).
+ LayoutUnit contentSize = computeMainAxisExtentForChild(child, MinSize, Length(MinContent)).value();
+ ASSERT(contentSize >= 0);
+ if (child.hasAspectRatio() && child.intrinsicSize().height() > 0)
+ contentSize = adjustChildSizeForAspectRatioCrossAxisMinAndMax(child, contentSize);
+ contentSize = std::min(contentSize, maxExtent.value_or(contentSize));
+
+ Length mainSize = isHorizontalFlow() ? child.style().width() : child.style().height();
+ if (mainAxisLengthIsDefinite(child, mainSize)) {
+ LayoutUnit resolvedMainSize = computeMainAxisExtentForChild(child, MainOrPreferredSize, mainSize).value();
+ ASSERT(resolvedMainSize >= 0);
+ LayoutUnit specifiedSize = std::min(resolvedMainSize, maxExtent.value_or(resolvedMainSize));
+ return std::max(childSize, std::min(specifiedSize, contentSize));
+ } else if (useChildAspectRatio(child)) {
+ Length crossSizeLength = isHorizontalFlow() ? child.style().height() : child.style().width();
+ std::optional<LayoutUnit> transferredSize = computeMainSizeFromAspectRatioUsing(child, crossSizeLength);
+ if (transferredSize) {
+ transferredSize = adjustChildSizeForAspectRatioCrossAxisMinAndMax(child, transferredSize.value());
+ return std::max(childSize, std::min(transferredSize.value(), contentSize));
+ }
+ }
+ return std::max(childSize, contentSize);
+ }
+ return childSize;
}
bool RenderFlexibleBox::computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& minMaxAppliedMainAxisExtent, bool& hasInfiniteLineLength)
@@ -893,6 +982,7 @@ bool RenderFlexibleBox::computeNextFlexLine(OrderedFlexItemList& orderedChildren
bool lineHasInFlowItem = false;
+ LayoutUnit preferredMainAxisExtentWithMinWidthConstraint;
for (RenderBox* child = m_orderIterator.currentChild(); child; child = m_orderIterator.next()) {
if (child->isOutOfFlowPositioned()) {
orderedChildren.append(child);
@@ -900,19 +990,26 @@ bool RenderFlexibleBox::computeNextFlexLine(OrderedFlexItemList& orderedChildren
}
LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(*child, hasInfiniteLineLength);
- LayoutUnit childMainAxisMarginBoxExtent = mainAxisBorderAndPaddingExtentForChild(*child) + childMainAxisExtent;
- childMainAxisMarginBoxExtent += isHorizontalFlow() ? child->marginWidth() : child->marginHeight();
+ LayoutUnit borderMarginAndPaddingSpace = mainAxisBorderAndPaddingExtentForChild(*child) + (isHorizontalFlow() ? child->horizontalMarginExtent() : child->verticalMarginExtent());
- if (isMultiline() && preferredMainAxisExtent + childMainAxisMarginBoxExtent > lineBreakLength && lineHasInFlowItem)
+ LayoutUnit childMainAxisExtentWithMinWidthConstraint = childMainAxisExtent;
+ if (child->style().logicalMinWidth().isSpecifiedOrIntrinsic()) {
+ if (auto minWidthForChild = computeMainAxisExtentForChild(*child, MinSize, child->style().logicalMinWidth()))
+ childMainAxisExtentWithMinWidthConstraint = std::max(childMainAxisExtent, minWidthForChild.value());
+ }
+ preferredMainAxisExtentWithMinWidthConstraint += childMainAxisExtentWithMinWidthConstraint + borderMarginAndPaddingSpace;
+
+ if (isMultiline() && preferredMainAxisExtentWithMinWidthConstraint > lineBreakLength && lineHasInFlowItem)
break;
orderedChildren.append(child);
lineHasInFlowItem = true;
- preferredMainAxisExtent += childMainAxisMarginBoxExtent;
+
+ preferredMainAxisExtent += childMainAxisExtent + borderMarginAndPaddingSpace;
totalFlexGrow += child->style().flexGrow();
totalWeightedFlexShrink += child->style().flexShrink() * childMainAxisExtent;
LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(*child, childMainAxisExtent);
- minMaxAppliedMainAxisExtent += childMinMaxAppliedMainAxisExtent - childMainAxisExtent + childMainAxisMarginBoxExtent;
+ minMaxAppliedMainAxisExtent += childMinMaxAppliedMainAxisExtent + borderMarginAndPaddingSpace;
}
return true;
}
@@ -956,7 +1053,7 @@ bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedF
else if (availableFreeSpace < 0 && totalWeightedFlexShrink > 0 && flexSign == NegativeFlexibility && std::isfinite(totalWeightedFlexShrink))
extraSpace = availableFreeSpace * child.style().flexShrink() * preferredChildSize / totalWeightedFlexShrink;
if (std::isfinite(extraSpace))
- childSize += roundedLayoutUnit(extraSpace);
+ childSize += LayoutUnit::fromFloatRound(extraSpace);
LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(child, childSize);
childSizes.append(adjustedChildSize);
@@ -979,13 +1076,13 @@ bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedF
return !totalViolation;
}
-static LayoutUnit initialJustifyContentOffset(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
+static LayoutUnit initialJustifyContentOffset(LayoutUnit availableFreeSpace, ContentPosition justifyContent, ContentDistributionType justifyContentDistribution, unsigned numberOfChildren)
{
- if (justifyContent == JustifyFlexEnd)
+ if (justifyContent == ContentPositionFlexEnd)
return availableFreeSpace;
- if (justifyContent == JustifyCenter)
+ if (justifyContent == ContentPositionCenter)
return availableFreeSpace / 2;
- if (justifyContent == JustifySpaceAround) {
+ if (justifyContentDistribution == ContentDistributionSpaceAround) {
if (availableFreeSpace > 0 && numberOfChildren)
return availableFreeSpace / (2 * numberOfChildren);
else
@@ -994,12 +1091,12 @@ static LayoutUnit initialJustifyContentOffset(LayoutUnit availableFreeSpace, EJu
return 0;
}
-static LayoutUnit justifyContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
+static LayoutUnit justifyContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, ContentDistributionType justifyContentDistribution, unsigned numberOfChildren)
{
if (availableFreeSpace > 0 && numberOfChildren > 1) {
- if (justifyContent == JustifySpaceBetween)
+ if (justifyContentDistribution == ContentDistributionSpaceBetween)
return availableFreeSpace / (numberOfChildren - 1);
- if (justifyContent == JustifySpaceAround)
+ if (justifyContentDistribution == ContentDistributionSpaceAround)
return availableFreeSpace / numberOfChildren;
}
return 0;
@@ -1031,18 +1128,18 @@ void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox& child, Layout
}
}
-EAlignItems RenderFlexibleBox::alignmentForChild(RenderBox& child) const
+ItemPosition RenderFlexibleBox::alignmentForChild(RenderBox& child) const
{
- EAlignItems align = resolveAlignment(&style(), &child.style());
+ ItemPosition align = child.style().resolvedAlignSelf(style(), selfAlignmentNormalBehaviorFlexibleBox).position();
- if (align == AlignBaseline && hasOrthogonalFlow(child))
- align = AlignFlexStart;
+ if (align == ItemPositionBaseline && hasOrthogonalFlow(child))
+ align = ItemPositionFlexStart;
if (style().flexWrap() == FlexWrapReverse) {
- if (align == AlignFlexStart)
- align = AlignFlexEnd;
- else if (align == AlignFlexEnd)
- align = AlignFlexStart;
+ if (align == ItemPositionFlexStart)
+ align = ItemPositionFlexEnd;
+ else if (align == ItemPositionFlexEnd)
+ align = ItemPositionFlexStart;
}
return align;
@@ -1061,7 +1158,7 @@ size_t RenderFlexibleBox::numberOfInFlowPositionedChildren(const OrderedFlexItem
bool RenderFlexibleBox::needToStretchChild(RenderBox& child)
{
- if (alignmentForChild(child) != AlignStretch)
+ if (alignmentForChild(child) != ItemPositionStretch)
return false;
Length crossAxisLength = isHorizontalFlow() ? child.style().height() : child.style().width();
@@ -1074,14 +1171,34 @@ void RenderFlexibleBox::resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox& chil
child.updateLogicalHeight();
}
+EOverflow RenderFlexibleBox::mainAxisOverflowForChild(const RenderBox& child) const
+{
+ if (isHorizontalFlow())
+ return child.style().overflowX();
+ return child.style().overflowY();
+}
+
+static const StyleContentAlignmentData& contentAlignmentNormalBehaviorFlexibleBox()
+{
+ // The justify-content property applies along the main axis, but since flexing
+ // in the main axis is controlled by flex, stretch behaves as flex-start (ignoring
+ // the specified fallback alignment, if any).
+ // https://drafts.csswg.org/css-align/#distribution-flex
+ static const StyleContentAlignmentData normalBehavior = {ContentPositionNormal, ContentDistributionStretch};
+ return normalBehavior;
+}
+
void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace, bool relayoutChildren, Vector<LineContext>& lineContexts)
{
ASSERT(childSizes.size() == children.size());
+ auto position = style().resolvedJustifyContentPosition(contentAlignmentNormalBehaviorFlexibleBox());
+ auto distribution = style().resolvedJustifyContentDistribution(contentAlignmentNormalBehaviorFlexibleBox());
+
size_t numberOfChildrenForJustifyContent = numberOfInFlowPositionedChildren(children);
LayoutUnit autoMarginOffset = autoMarginOffsetInMainAxis(children, availableFreeSpace);
LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart();
- mainAxisOffset += initialJustifyContentOffset(availableFreeSpace, style().justifyContent(), numberOfChildrenForJustifyContent);
+ mainAxisOffset += initialJustifyContentOffset(availableFreeSpace, position, distribution, numberOfChildrenForJustifyContent);
if (style().flexDirection() == FlowRowReverse)
mainAxisOffset += isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
@@ -1112,7 +1229,7 @@ void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, cons
updateAutoMarginsInMainAxis(child, autoMarginOffset);
LayoutUnit childCrossAxisMarginBoxExtent;
- if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child)) {
+ if (alignmentForChild(child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(child)) {
LayoutUnit ascent = marginBoxAscentForChild(child);
LayoutUnit descent = (crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child)) - ascent;
@@ -1138,7 +1255,7 @@ void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, cons
++seenInFlowPositionedChildren;
if (seenInFlowPositionedChildren < numberOfChildrenForJustifyContent)
- mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, style().justifyContent(), numberOfChildrenForJustifyContent);
+ mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, distribution, numberOfChildrenForJustifyContent);
}
if (isColumnFlow())
@@ -1159,12 +1276,15 @@ void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, cons
void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace)
{
+ auto position = style().resolvedJustifyContentPosition(contentAlignmentNormalBehaviorFlexibleBox());
+ auto distribution = style().resolvedJustifyContentDistribution(contentAlignmentNormalBehaviorFlexibleBox());
+
// This is similar to the logic in layoutAndPlaceChildren, except we place the children
// starting from the end of the flexbox. We also don't need to layout anything since we're
// just moving the children to a new position.
size_t numberOfChildrenForJustifyContent = numberOfInFlowPositionedChildren(children);
LayoutUnit mainAxisOffset = logicalHeight() - flowAwareBorderEnd() - flowAwarePaddingEnd();
- mainAxisOffset -= initialJustifyContentOffset(availableFreeSpace, style().justifyContent(), numberOfChildrenForJustifyContent);
+ mainAxisOffset -= initialJustifyContentOffset(availableFreeSpace, position, distribution, numberOfChildrenForJustifyContent);
mainAxisOffset -= isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
size_t seenInFlowPositionedChildren = 0;
@@ -1182,17 +1302,17 @@ void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children,
++seenInFlowPositionedChildren;
if (seenInFlowPositionedChildren < numberOfChildrenForJustifyContent)
- mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, style().justifyContent(), numberOfChildrenForJustifyContent);
+ mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, distribution, numberOfChildrenForJustifyContent);
}
}
-static LayoutUnit initialAlignContentOffset(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
+static LayoutUnit initialAlignContentOffset(LayoutUnit availableFreeSpace, ContentPosition alignContent, ContentDistributionType alignContentDistribution, unsigned numberOfLines)
{
- if (alignContent == AlignContentFlexEnd)
+ if (alignContent == ContentPositionFlexEnd)
return availableFreeSpace;
- if (alignContent == AlignContentCenter)
+ if (alignContent == ContentPositionCenter)
return availableFreeSpace / 2;
- if (alignContent == AlignContentSpaceAround) {
+ if (alignContentDistribution == ContentDistributionSpaceAround) {
if (availableFreeSpace > 0 && numberOfLines)
return availableFreeSpace / (2 * numberOfLines);
if (availableFreeSpace < 0)
@@ -1201,12 +1321,12 @@ static LayoutUnit initialAlignContentOffset(LayoutUnit availableFreeSpace, EAlig
return 0;
}
-static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
+static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, ContentDistributionType alignContentDistribution, unsigned numberOfLines)
{
if (availableFreeSpace > 0 && numberOfLines > 1) {
- if (alignContent == AlignContentSpaceBetween)
+ if (alignContentDistribution == ContentDistributionSpaceBetween)
return availableFreeSpace / (numberOfLines - 1);
- if (alignContent == AlignContentSpaceAround || alignContent == AlignContentStretch)
+ if (alignContentDistribution == ContentDistributionSpaceAround || alignContentDistribution == ContentDistributionStretch)
return availableFreeSpace / numberOfLines;
}
return 0;
@@ -1214,7 +1334,10 @@ static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace
void RenderFlexibleBox::alignFlexLines(Vector<LineContext>& lineContexts)
{
- if (!isMultiline() || style().alignContent() == AlignContentFlexStart)
+ ContentPosition position = style().resolvedAlignContentPosition(contentAlignmentNormalBehaviorFlexibleBox());
+ ContentDistributionType distribution = style().resolvedAlignContentDistribution(contentAlignmentNormalBehaviorFlexibleBox());
+
+ if (!isMultiline() || position == ContentPositionFlexStart)
return;
LayoutUnit availableCrossAxisSpace = crossAxisContentExtent();
@@ -1222,16 +1345,16 @@ void RenderFlexibleBox::alignFlexLines(Vector<LineContext>& lineContexts)
availableCrossAxisSpace -= lineContexts[i].crossAxisExtent;
RenderBox* child = m_orderIterator.first();
- LayoutUnit lineOffset = initialAlignContentOffset(availableCrossAxisSpace, style().alignContent(), lineContexts.size());
+ LayoutUnit lineOffset = initialAlignContentOffset(availableCrossAxisSpace, position, distribution, lineContexts.size());
for (unsigned lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
lineContexts[lineNumber].crossAxisOffset += lineOffset;
for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next())
adjustAlignmentForChild(*child, lineOffset);
- if (style().alignContent() == AlignContentStretch && availableCrossAxisSpace > 0)
+ if (distribution == ContentDistributionStretch && availableCrossAxisSpace > 0)
lineContexts[lineNumber].crossAxisExtent += availableCrossAxisSpace / static_cast<unsigned>(lineContexts.size());
- lineOffset += alignContentSpaceBetweenChildren(availableCrossAxisSpace, style().alignContent(), lineContexts.size());
+ lineOffset += alignContentSpaceBetweenChildren(availableCrossAxisSpace, distribution, lineContexts.size());
}
}
@@ -1273,25 +1396,33 @@ void RenderFlexibleBox::alignChildren(const Vector<LineContext>& lineContexts)
continue;
switch (alignmentForChild(*child)) {
- case AlignAuto:
+ case ItemPositionAuto:
+ case ItemPositionNormal:
ASSERT_NOT_REACHED();
break;
- case AlignStretch: {
+ case ItemPositionStart:
+ // FIXME: https://webkit.org/b/135460 - The extended grammar is not supported
+ // yet for FlexibleBox.
+ // Defaulting to Stretch for now, as it what most of FlexBox based renders
+ // expect as default.
+ ASSERT(RuntimeEnabledFeatures::sharedFeatures().isCSSGridLayoutEnabled());
+ FALLTHROUGH;
+ case ItemPositionStretch: {
applyStretchAlignmentToChild(*child, lineCrossAxisExtent);
// Since wrap-reverse flips cross start and cross end, strech children should be aligned with the cross end.
if (style().flexWrap() == FlexWrapReverse)
adjustAlignmentForChild(*child, availableAlignmentSpaceForChild(lineCrossAxisExtent, *child));
break;
}
- case AlignFlexStart:
+ case ItemPositionFlexStart:
break;
- case AlignFlexEnd:
+ case ItemPositionFlexEnd:
adjustAlignmentForChild(*child, availableAlignmentSpaceForChild(lineCrossAxisExtent, *child));
break;
- case AlignCenter:
+ case ItemPositionCenter:
adjustAlignmentForChild(*child, availableAlignmentSpaceForChild(lineCrossAxisExtent, *child) / 2);
break;
- case AlignBaseline: {
+ case ItemPositionBaseline: {
// FIXME: If we get here in columns, we want the use the descent, except we currently can't get the ascent/descent of orthogonal children.
// https://bugs.webkit.org/show_bug.cgi?id=98076
LayoutUnit ascent = marginBoxAscentForChild(*child);
@@ -1302,6 +1433,19 @@ void RenderFlexibleBox::alignChildren(const Vector<LineContext>& lineContexts)
minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, *child) - startOffset);
break;
}
+ case ItemPositionLastBaseline:
+ case ItemPositionSelfStart:
+ case ItemPositionSelfEnd:
+ case ItemPositionEnd:
+ case ItemPositionLeft:
+ case ItemPositionRight:
+ // FIXME: https://webkit.org/b/135460 - The extended grammar is not supported
+ // yet for FlexibleBox.
+ ASSERT(RuntimeEnabledFeatures::sharedFeatures().isCSSGridLayoutEnabled());
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
}
}
minMarginAfterBaselines.append(minMarginAfterBaseline);
@@ -1317,7 +1461,7 @@ void RenderFlexibleBox::alignChildren(const Vector<LineContext>& lineContexts)
LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber];
for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
ASSERT(child);
- if (alignmentForChild(*child) == AlignBaseline && !hasAutoMarginsInCrossAxis(*child) && minMarginAfterBaseline)
+ if (alignmentForChild(*child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(*child) && minMarginAfterBaseline)
adjustAlignmentForChild(*child, minMarginAfterBaseline);
}
}
@@ -1329,7 +1473,8 @@ void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox& child, LayoutUni
// FIXME: If the child has orthogonal flow, then it already has an override height set, so use it.
if (!hasOrthogonalFlow(child)) {
LayoutUnit stretchedLogicalHeight = child.logicalHeight() + availableAlignmentSpaceForChild(lineCrossAxisExtent, child);
- LayoutUnit desiredLogicalHeight = child.constrainLogicalHeightByMinMax(stretchedLogicalHeight);
+ ASSERT(!child.needsLayout());
+ LayoutUnit desiredLogicalHeight = child.constrainLogicalHeightByMinMax(stretchedLogicalHeight, child.logicalHeight() - child.borderAndPaddingLogicalHeight());
// FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
if (desiredLogicalHeight != child.logicalHeight()) {
@@ -1343,7 +1488,7 @@ void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox& child, LayoutUni
// FIXME: If the child doesn't have orthogonal flow, then it already has an override width set, so use it.
if (hasOrthogonalFlow(child)) {
LayoutUnit childWidth = std::max<LayoutUnit>(0, lineCrossAxisExtent - crossAxisMarginExtentForChild(child));
- childWidth = child.constrainLogicalWidthInRegionByMinMax(childWidth, childWidth, this);
+ childWidth = child.constrainLogicalWidthInRegionByMinMax(childWidth, childWidth, *this);
if (childWidth != child.logicalWidth()) {
child.setOverrideLogicalContentWidth(childWidth - child.borderAndPaddingLogicalWidth());