summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/RenderFlexibleBox.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-05-07 11:21:11 +0200
committerSimon Hausmann <simon.hausmann@nokia.com>2012-05-07 11:21:11 +0200
commit2cf6c8816a73e0132bd8fa3b509d62d7c51b6e47 (patch)
tree988e8c5b116dd0466244ae2fe5af8ee9be926d76 /Source/WebCore/rendering/RenderFlexibleBox.cpp
parentdd91e772430dc294e3bf478c119ef8d43c0a3358 (diff)
downloadqtwebkit-2cf6c8816a73e0132bd8fa3b509d62d7c51b6e47.tar.gz
Imported WebKit commit 7e538425aa020340619e927792f3d895061fb54b (http://svn.webkit.org/repository/webkit/trunk@116286)
Diffstat (limited to 'Source/WebCore/rendering/RenderFlexibleBox.cpp')
-rw-r--r--Source/WebCore/rendering/RenderFlexibleBox.cpp548
1 files changed, 341 insertions, 207 deletions
diff --git a/Source/WebCore/rendering/RenderFlexibleBox.cpp b/Source/WebCore/rendering/RenderFlexibleBox.cpp
index e9dd8381d..efa2eb71d 100644
--- a/Source/WebCore/rendering/RenderFlexibleBox.cpp
+++ b/Source/WebCore/rendering/RenderFlexibleBox.cpp
@@ -102,38 +102,30 @@ private:
Vector<int>::const_iterator m_orderValuesIterator;
};
-struct RenderFlexibleBox::WrapReverseContext {
- explicit WrapReverseContext(EFlexWrap flexWrap)
- : isWrapReverse(flexWrap == FlexWrapReverse)
+struct RenderFlexibleBox::LineContext {
+ LineContext(LayoutUnit crossAxisOffset, LayoutUnit crossAxisExtent, size_t numberOfChildren, LayoutUnit maxAscent)
+ : crossAxisOffset(crossAxisOffset)
+ , crossAxisExtent(crossAxisExtent)
+ , numberOfChildren(numberOfChildren)
+ , maxAscent(maxAscent)
{
}
- void addCrossAxisOffset(LayoutUnit offset)
- {
- if (!isWrapReverse)
- return;
- crossAxisOffsets.append(offset);
- }
-
- void addNumberOfChildrenOnLine(size_t numberOfChildren)
- {
- if (!isWrapReverse)
- return;
- childrenPerLine.append(numberOfChildren);
- }
+ LayoutUnit crossAxisOffset;
+ LayoutUnit crossAxisExtent;
+ size_t numberOfChildren;
+ LayoutUnit maxAscent;
+};
- LayoutUnit lineCrossAxisDelta(size_t line, LayoutUnit crossAxisContentExtent) const
+struct RenderFlexibleBox::Violation {
+ Violation(RenderBox* child, LayoutUnit childSize)
+ : child(child)
+ , childSize(childSize)
{
- ASSERT(line + 1 < crossAxisOffsets.size());
- LayoutUnit lineHeight = crossAxisOffsets[line + 1] - crossAxisOffsets[line];
- LayoutUnit originalOffset = crossAxisOffsets[line] - crossAxisOffsets[0];
- LayoutUnit newOffset = crossAxisContentExtent - originalOffset - lineHeight;
- return newOffset - originalOffset;
}
- WTF::Vector<LayoutUnit> crossAxisOffsets;
- WTF::Vector<size_t> childrenPerLine;
- bool isWrapReverse;
+ RenderBox* child;
+ LayoutUnit childSize;
};
@@ -188,11 +180,19 @@ void RenderFlexibleBox::computePreferredLogicalWidths()
minPreferredLogicalWidth += margin;
maxPreferredLogicalWidth += margin;
if (!isColumnFlow()) {
- m_minPreferredLogicalWidth += minPreferredLogicalWidth;
m_maxPreferredLogicalWidth += maxPreferredLogicalWidth;
+ if (isMultiline()) {
+ // For multiline, the min preferred width is if you put a break between each item.
+ m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, minPreferredLogicalWidth);
+ } else
+ m_minPreferredLogicalWidth += minPreferredLogicalWidth;
} else {
m_minPreferredLogicalWidth = std::max(minPreferredLogicalWidth, m_minPreferredLogicalWidth);
- m_maxPreferredLogicalWidth = std::max(maxPreferredLogicalWidth, m_maxPreferredLogicalWidth);
+ if (isMultiline()) {
+ // For multiline, the max preferred width is if you put a break between each item.
+ m_maxPreferredLogicalWidth += maxPreferredLogicalWidth;
+ } else
+ m_maxPreferredLogicalWidth = std::max(maxPreferredLogicalWidth, m_maxPreferredLogicalWidth);
}
}
@@ -230,7 +230,7 @@ void RenderFlexibleBox::computePreferredLogicalWidths()
setPreferredLogicalWidthsDirty(false);
}
-void RenderFlexibleBox::layoutBlock(bool relayoutChildren, int, BlockLayoutPass)
+void RenderFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
{
ASSERT(needsLayout());
@@ -247,12 +247,10 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren, int, BlockLayoutPass)
}
computeInitialRegionRangeForBlock();
- IntSize previousSize = size();
+ LayoutSize previousSize = size();
setLogicalHeight(0);
- // We need to call both of these because we grab both crossAxisExtent and mainAxisExtent in layoutFlexItems.
computeLogicalWidth();
- computeLogicalHeight();
m_overflow.clear();
@@ -264,10 +262,15 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren, int, BlockLayoutPass)
layer()->setHasVerticalScrollbar(true);
}
- layoutFlexItems(relayoutChildren);
+ WTF::Vector<LineContext> lineContexts;
+ FlexOrderHashSet flexOrderValues;
+ computeMainAxisPreferredSizes(relayoutChildren, flexOrderValues);
+ FlexOrderIterator flexIterator(this, flexOrderValues);
+ layoutFlexItems(flexIterator, lineContexts);
LayoutUnit oldClientAfterEdge = clientLogicalBottom();
computeLogicalHeight();
+ repositionLogicalHeightDependentFlexItems(flexIterator, lineContexts, oldClientAfterEdge);
if (size() != previousSize)
relayoutChildren = true;
@@ -284,13 +287,35 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren, int, BlockLayoutPass)
// Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
// we overflow or not.
- updateScrollInfoAfterLayout();
+ if (hasOverflowClip())
+ layer()->updateScrollInfoAfterLayout();
repainter.repaintAfterLayout();
setNeedsLayout(false);
}
+void RenderFlexibleBox::repositionLogicalHeightDependentFlexItems(FlexOrderIterator& iterator, WTF::Vector<LineContext>& lineContexts, LayoutUnit& oldClientAfterEdge)
+{
+ LayoutUnit crossAxisStartEdge = lineContexts.isEmpty() ? ZERO_LAYOUT_UNIT : lineContexts[0].crossAxisOffset;
+ packFlexLines(iterator, lineContexts);
+
+ // If we have a single line flexbox, the line height is all the available space.
+ // For flex-direction: row, this means we need to use the height, so we do this after calling computeLogicalHeight.
+ if (!isMultiline() && lineContexts.size() == 1)
+ lineContexts[0].crossAxisExtent = crossAxisContentExtent();
+ alignChildren(iterator, lineContexts);
+
+ if (style()->flexWrap() == FlexWrapReverse) {
+ if (isHorizontalFlow())
+ oldClientAfterEdge = clientLogicalBottom();
+ flipForWrapReverse(iterator, lineContexts, crossAxisStartEdge);
+ }
+
+ // direction:rtl + flex-direction:column means the cross-axis direction is flipped.
+ flipForRightToLeftColumn(iterator);
+}
+
bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox* child) const
{
// FIXME: If the child is a flexbox, then we need to check isHorizontalFlow.
@@ -321,9 +346,12 @@ bool RenderFlexibleBox::isMultiline() const
return style()->flexWrap() != FlexWrapNone;
}
-Length RenderFlexibleBox::mainAxisLengthForChild(RenderBox* child) const
+Length RenderFlexibleBox::preferredLengthForChild(RenderBox* child) const
{
- return isHorizontalFlow() ? child->style()->width() : child->style()->height();
+ Length flexLength = child->style()->flexPreferredSize();
+ if (flexLength.isAuto())
+ flexLength = isHorizontalFlow() ? child->style()->width() : child->style()->height();
+ return flexLength;
}
Length RenderFlexibleBox::crossAxisLength() const
@@ -560,62 +588,58 @@ LayoutUnit RenderFlexibleBox::mainAxisScrollbarExtentForChild(RenderBox* child)
LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* child) const
{
- Length mainAxisLength = mainAxisLengthForChild(child);
+ Length mainAxisLength = preferredLengthForChild(child);
if (mainAxisLength.isAuto()) {
LayoutUnit mainAxisExtent = hasOrthogonalFlow(child) ? child->logicalHeight() : child->maxPreferredLogicalWidth();
- return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child) - mainAxisScrollbarExtentForChild(child);
+ return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child);
}
- return mainAxisLength.calcMinValue(mainAxisContentExtent());
+ return minimumValueForLength(mainAxisLength, mainAxisContentExtent(), view());
}
-void RenderFlexibleBox::layoutFlexItems(bool relayoutChildren)
+LayoutUnit RenderFlexibleBox::computeAvailableFreeSpace(LayoutUnit preferredMainAxisExtent)
{
- FlexOrderHashSet flexOrderValues;
- computeMainAxisPreferredSizes(relayoutChildren, flexOrderValues);
+ LayoutUnit contentExtent = 0;
+ if (!isColumnFlow())
+ contentExtent = mainAxisContentExtent();
+ else if (hasOverrideHeight())
+ contentExtent = overrideHeight() - (logicalHeight() - contentLogicalHeight());
+ else {
+ LayoutUnit heightResult = computeContentLogicalHeightUsing(style()->logicalHeight());
+ if (heightResult == -1)
+ heightResult = preferredMainAxisExtent;
+ LayoutUnit minHeight = computeContentLogicalHeightUsing(style()->logicalMinHeight()); // Leave as -1 if unset.
+ LayoutUnit maxHeight = style()->logicalMaxHeight().isUndefined() ? heightResult : computeContentLogicalHeightUsing(style()->logicalMaxHeight());
+ if (maxHeight == -1)
+ maxHeight = heightResult;
+ heightResult = std::min(maxHeight, heightResult);
+ heightResult = std::max(minHeight, heightResult);
+ contentExtent = heightResult;
+ }
+ return contentExtent - preferredMainAxisExtent;
+}
+
+void RenderFlexibleBox::layoutFlexItems(FlexOrderIterator& iterator, WTF::Vector<LineContext>& lineContexts)
+{
OrderedFlexItemList orderedChildren;
LayoutUnit preferredMainAxisExtent;
float totalPositiveFlexibility;
float totalNegativeFlexibility;
- FlexOrderIterator flexIterator(this, flexOrderValues);
-
- // For wrap-reverse, we need to layout as wrap, then reverse the lines. The next two arrays
- // are some extra information so it's possible to reverse the lines.
- WrapReverseContext wrapReverseContext(style()->flexWrap());
+ LayoutUnit minMaxAppliedMainAxisExtent;
LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
- LayoutUnit mainAxisFlexibleSpace = mainAxisContentExtent();
- while (computeNextFlexLine(flexIterator, orderedChildren, preferredMainAxisExtent, totalPositiveFlexibility, totalNegativeFlexibility)) {
- LayoutUnit availableFreeSpace = mainAxisFlexibleSpace - preferredMainAxisExtent;
+ while (computeNextFlexLine(iterator, orderedChildren, preferredMainAxisExtent, totalPositiveFlexibility, totalNegativeFlexibility, minMaxAppliedMainAxisExtent)) {
+ LayoutUnit availableFreeSpace = computeAvailableFreeSpace(preferredMainAxisExtent);
+ FlexSign flexSign = (minMaxAppliedMainAxisExtent < preferredMainAxisExtent + availableFreeSpace) ? PositiveFlexibility : NegativeFlexibility;
InflexibleFlexItemSize inflexibleItems;
WTF::Vector<LayoutUnit> childSizes;
- while (!runFreeSpaceAllocationAlgorithm(orderedChildren, availableFreeSpace, totalPositiveFlexibility, totalNegativeFlexibility, inflexibleItems, childSizes)) {
+ while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalPositiveFlexibility, totalNegativeFlexibility, inflexibleItems, childSizes)) {
ASSERT(totalPositiveFlexibility >= 0 && totalNegativeFlexibility >= 0);
ASSERT(inflexibleItems.size() > 0);
}
- wrapReverseContext.addNumberOfChildrenOnLine(orderedChildren.size());
- wrapReverseContext.addCrossAxisOffset(crossAxisOffset);
- layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace);
- }
-
- if (wrapReverseContext.isWrapReverse) {
- wrapReverseContext.addCrossAxisOffset(crossAxisOffset);
- flipForWrapReverse(flexIterator, wrapReverseContext);
+ layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace, lineContexts);
}
-
- // direction:rtl + flex-direction:column means the cross-axis direction is flipped.
- flipForRightToLeftColumn(flexIterator);
-}
-
-float RenderFlexibleBox::positiveFlexForChild(RenderBox* child) const
-{
- return isHorizontalFlow() ? child->style()->flexboxWidthPositiveFlex() : child->style()->flexboxHeightPositiveFlex();
-}
-
-float RenderFlexibleBox::negativeFlexForChild(RenderBox* child) const
-{
- return isHorizontalFlow() ? child->style()->flexboxWidthNegativeFlex() : child->style()->flexboxHeightNegativeFlex();
}
LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox* child)
@@ -635,6 +659,7 @@ LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(RenderBox* child)
void RenderFlexibleBox::computeMainAxisPreferredSizes(bool relayoutChildren, FlexOrderHashSet& flexOrderValues)
{
LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent();
+ RenderView* renderView = view();
for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
flexOrderValues.add(child->style()->flexOrder());
@@ -642,7 +667,7 @@ void RenderFlexibleBox::computeMainAxisPreferredSizes(bool relayoutChildren, Fle
continue;
child->clearOverrideSize();
- if (mainAxisLengthForChild(child).isAuto()) {
+ if (preferredLengthForChild(child).isAuto()) {
if (!relayoutChildren)
child->setChildNeedsLayout(true);
child->layoutIfNeeded();
@@ -652,52 +677,100 @@ void RenderFlexibleBox::computeMainAxisPreferredSizes(bool relayoutChildren, Fle
// of 0 and because if we're not auto sizing, we don't do a layout that
// computes the start/end margins.
if (isHorizontalFlow()) {
- child->setMarginLeft(child->style()->marginLeft().calcMinValue(flexboxAvailableContentExtent));
- child->setMarginRight(child->style()->marginRight().calcMinValue(flexboxAvailableContentExtent));
+ child->setMarginLeft(minimumValueForLength(child->style()->marginLeft(), flexboxAvailableContentExtent, renderView));
+ child->setMarginRight(minimumValueForLength(child->style()->marginRight(), flexboxAvailableContentExtent, renderView));
} else {
- child->setMarginTop(child->style()->marginTop().calcMinValue(flexboxAvailableContentExtent));
- child->setMarginBottom(child->style()->marginBottom().calcMinValue(flexboxAvailableContentExtent));
+ child->setMarginTop(minimumValueForLength(child->style()->marginTop(), flexboxAvailableContentExtent, renderView));
+ child->setMarginBottom(minimumValueForLength(child->style()->marginBottom(), flexboxAvailableContentExtent, renderView));
}
}
}
-bool RenderFlexibleBox::computeNextFlexLine(FlexOrderIterator& iterator, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalPositiveFlexibility, float& totalNegativeFlexibility)
+LayoutUnit RenderFlexibleBox::lineBreakLength()
+{
+ if (!isColumnFlow())
+ return mainAxisContentExtent();
+
+ LayoutUnit height = computeContentLogicalHeightUsing(style()->logicalHeight());
+ if (height == -1)
+ height = MAX_LAYOUT_UNIT;
+ LayoutUnit maxHeight = computeContentLogicalHeightUsing(style()->logicalMaxHeight());
+ if (maxHeight != -1)
+ height = std::min(height, maxHeight);
+ return height;
+}
+
+LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox* child, LayoutUnit childSize, LayoutUnit flexboxAvailableContentExtent)
+{
+ Length max = isHorizontalFlow() ? child->style()->maxWidth() : child->style()->maxHeight();
+ Length min = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
+ RenderView* renderView = view();
+ // FIXME: valueForLength isn't quite right in quirks mode: percentage heights should check parents until a value is found.
+ // https://bugs.webkit.org/show_bug.cgi?id=81809
+ if (max.isSpecified() && childSize > valueForLength(max, flexboxAvailableContentExtent, renderView))
+ childSize = valueForLength(max, flexboxAvailableContentExtent, renderView);
+ if (min.isSpecified() && childSize < valueForLength(min, flexboxAvailableContentExtent, renderView))
+ childSize = valueForLength(min, flexboxAvailableContentExtent, renderView);
+ return childSize;
+}
+
+bool RenderFlexibleBox::computeNextFlexLine(FlexOrderIterator& iterator, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalPositiveFlexibility, float& totalNegativeFlexibility, LayoutUnit& minMaxAppliedMainAxisExtent)
{
orderedChildren.clear();
preferredMainAxisExtent = 0;
totalPositiveFlexibility = totalNegativeFlexibility = 0;
+ minMaxAppliedMainAxisExtent = 0;
if (!iterator.currentChild())
return false;
+ LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent();
+ LayoutUnit lineBreak = lineBreakLength();
+
for (RenderBox* child = iterator.currentChild(); child; child = iterator.next()) {
if (child->isPositioned()) {
orderedChildren.append(child);
continue;
}
- LayoutUnit childMainAxisExtent = mainAxisBorderAndPaddingExtentForChild(child) + preferredMainAxisContentExtentForChild(child);
- if (isHorizontalFlow())
- childMainAxisExtent += child->marginWidth();
- else
- childMainAxisExtent += child->marginHeight();
+ LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(child);
+ LayoutUnit childMainAxisMarginBoxExtent = mainAxisBorderAndPaddingExtentForChild(child) + childMainAxisExtent;
+ childMainAxisMarginBoxExtent += isHorizontalFlow() ? child->marginWidth() : child->marginHeight();
- if (isMultiline() && preferredMainAxisExtent + childMainAxisExtent > mainAxisContentExtent() && orderedChildren.size() > 0)
+ if (isMultiline() && preferredMainAxisExtent + childMainAxisMarginBoxExtent > lineBreak && orderedChildren.size() > 0)
break;
orderedChildren.append(child);
- preferredMainAxisExtent += childMainAxisExtent;
- totalPositiveFlexibility += positiveFlexForChild(child);
- totalNegativeFlexibility += negativeFlexForChild(child);
+ preferredMainAxisExtent += childMainAxisMarginBoxExtent;
+ totalPositiveFlexibility += child->style()->positiveFlex();
+ totalNegativeFlexibility += child->style()->negativeFlex();
+
+ LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(child, childMainAxisExtent, flexboxAvailableContentExtent);
+ minMaxAppliedMainAxisExtent += childMinMaxAppliedMainAxisExtent - childMainAxisExtent + childMainAxisMarginBoxExtent;
}
return true;
}
+void RenderFlexibleBox::freezeViolations(const WTF::Vector<Violation>& violations, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalNegativeFlexibility, InflexibleFlexItemSize& inflexibleItems)
+{
+ for (size_t i = 0; i < violations.size(); ++i) {
+ RenderBox* child = violations[i].child;
+ LayoutUnit childSize = violations[i].childSize;
+ availableFreeSpace -= childSize - preferredMainAxisContentExtentForChild(child);
+ totalPositiveFlexibility -= child->style()->positiveFlex();
+ totalNegativeFlexibility -= child->style()->negativeFlex();
+ inflexibleItems.set(child, childSize);
+ }
+}
+
// Returns true if we successfully ran the algorithm and sized the flex items.
-bool RenderFlexibleBox::runFreeSpaceAllocationAlgorithm(const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalNegativeFlexibility, InflexibleFlexItemSize& inflexibleItems, WTF::Vector<LayoutUnit>& childSizes)
+bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalNegativeFlexibility, InflexibleFlexItemSize& inflexibleItems, WTF::Vector<LayoutUnit>& childSizes)
{
childSizes.clear();
-
LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent();
+ LayoutUnit totalViolation = 0;
+ LayoutUnit usedFreeSpace = 0;
+ WTF::Vector<Violation> minViolations;
+ WTF::Vector<Violation> maxViolations;
for (size_t i = 0; i < children.size(); ++i) {
RenderBox* child = children[i];
if (child->isPositioned()) {
@@ -705,59 +778,53 @@ bool RenderFlexibleBox::runFreeSpaceAllocationAlgorithm(const OrderedFlexItemLis
continue;
}
- LayoutUnit childPreferredSize;
if (inflexibleItems.contains(child))
- childPreferredSize = inflexibleItems.get(child);
+ childSizes.append(inflexibleItems.get(child));
else {
- childPreferredSize = preferredMainAxisContentExtentForChild(child);
- if (availableFreeSpace > 0 && totalPositiveFlexibility > 0) {
- childPreferredSize += lroundf(availableFreeSpace * positiveFlexForChild(child) / totalPositiveFlexibility);
-
- Length childLogicalMaxWidth = isHorizontalFlow() ? child->style()->maxWidth() : child->style()->maxHeight();
- if (!childLogicalMaxWidth.isUndefined() && childLogicalMaxWidth.isSpecified() && childPreferredSize > childLogicalMaxWidth.calcValue(flexboxAvailableContentExtent)) {
- childPreferredSize = childLogicalMaxWidth.calcValue(flexboxAvailableContentExtent);
- availableFreeSpace -= childPreferredSize - preferredMainAxisContentExtentForChild(child);
- totalPositiveFlexibility -= positiveFlexForChild(child);
-
- inflexibleItems.set(child, childPreferredSize);
- return false;
- }
- } else if (availableFreeSpace < 0 && totalNegativeFlexibility > 0) {
- childPreferredSize += lroundf(availableFreeSpace * negativeFlexForChild(child) / totalNegativeFlexibility);
-
- Length childLogicalMinWidth = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
- if (!childLogicalMinWidth.isUndefined() && childLogicalMinWidth.isSpecified() && childPreferredSize < childLogicalMinWidth.calcValue(flexboxAvailableContentExtent)) {
- childPreferredSize = childLogicalMinWidth.calcValue(flexboxAvailableContentExtent);
- availableFreeSpace += preferredMainAxisContentExtentForChild(child) - childPreferredSize;
- totalNegativeFlexibility -= negativeFlexForChild(child);
-
- inflexibleItems.set(child, childPreferredSize);
- return false;
- }
- }
+ LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child);
+ LayoutUnit childSize = preferredChildSize;
+ if (availableFreeSpace > 0 && totalPositiveFlexibility > 0 && flexSign == PositiveFlexibility)
+ childSize += lroundf(availableFreeSpace * child->style()->positiveFlex() / totalPositiveFlexibility);
+ else if (availableFreeSpace < 0 && totalNegativeFlexibility > 0 && flexSign == NegativeFlexibility)
+ childSize += lroundf(availableFreeSpace * child->style()->negativeFlex() / totalNegativeFlexibility);
+
+ LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(child, childSize, flexboxAvailableContentExtent);
+ childSizes.append(adjustedChildSize);
+ usedFreeSpace += adjustedChildSize - preferredChildSize;
+
+ LayoutUnit violation = adjustedChildSize - childSize;
+ if (violation > 0)
+ minViolations.append(Violation(child, adjustedChildSize));
+ else if (violation < 0)
+ maxViolations.append(Violation(child, adjustedChildSize));
+ totalViolation += violation;
}
- childSizes.append(childPreferredSize);
}
- return true;
+
+ if (totalViolation)
+ freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalPositiveFlexibility, totalNegativeFlexibility, inflexibleItems);
+ else
+ availableFreeSpace -= usedFreeSpace;
+
+ return !totalViolation;
}
-static LayoutUnit initialPackingOffset(LayoutUnit availableFreeSpace, EFlexPack flexPack, size_t numberOfChildren)
+static LayoutUnit initialPackingOffset(LayoutUnit availableFreeSpace, EFlexPack flexPack, unsigned numberOfChildren)
{
- if (availableFreeSpace > 0) {
- if (flexPack == PackEnd)
- return availableFreeSpace;
- if (flexPack == PackCenter)
- return availableFreeSpace / 2;
- if (flexPack == PackDistribute && numberOfChildren)
+ if (flexPack == PackEnd)
+ return availableFreeSpace;
+ if (flexPack == PackCenter)
+ return availableFreeSpace / 2;
+ if (flexPack == PackDistribute) {
+ if (availableFreeSpace > 0 && numberOfChildren)
return availableFreeSpace / (2 * numberOfChildren);
- } else if (availableFreeSpace < 0) {
- if (flexPack == PackCenter || flexPack == PackDistribute)
+ if (availableFreeSpace < 0)
return availableFreeSpace / 2;
}
return 0;
}
-static LayoutUnit packingSpaceBetweenChildren(LayoutUnit availableFreeSpace, EFlexPack flexPack, size_t numberOfChildren)
+static LayoutUnit packingSpaceBetweenChildren(LayoutUnit availableFreeSpace, EFlexPack flexPack, unsigned numberOfChildren)
{
if (availableFreeSpace > 0 && numberOfChildren > 1) {
if (flexPack == PackJustify)
@@ -791,7 +858,7 @@ void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox* child, Layout
if (childLayer->staticBlockPosition() != staticBlockPosition) {
childLayer->setStaticBlockPosition(staticBlockPosition);
if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
- child->setChildNeedsLayout(true, false);
+ child->setChildNeedsLayout(true, MarkOnlyThis);
}
}
@@ -811,8 +878,9 @@ static EFlexAlign flexAlignForChild(RenderBox* child)
return align;
}
-void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace)
+void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace, WTF::Vector<LineContext>& lineContexts)
{
+ ASSERT(childSizes.size() == children.size());
LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart();
mainAxisOffset += initialPackingOffset(availableFreeSpace, style()->flexPack(), childSizes.size());
if (style()->flexDirection() == FlowRowReverse)
@@ -845,8 +913,8 @@ void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, cons
childCrossAxisMarginBoxExtent = maxAscent + maxDescent;
} else
childCrossAxisMarginBoxExtent = crossAxisExtentForChild(child) + crossAxisMarginExtentForChild(child);
- if (crossAxisLength().isAuto())
- setCrossAxisExtent(std::max(crossAxisExtent(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent()));
+ if (!isColumnFlow() && style()->logicalHeight().isAuto())
+ setLogicalHeight(std::max(logicalHeight(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent()));
maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisMarginBoxExtent);
mainAxisOffset += flowAwareMarginStartForChild(child);
@@ -872,10 +940,8 @@ void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, cons
layoutColumnReverse(children, childSizes, crossAxisOffset, availableFreeSpace);
}
- LayoutUnit lineCrossAxisExtent = isMultiline() ? maxChildCrossAxisExtent : crossAxisContentExtent();
- alignChildren(children, lineCrossAxisExtent, maxAscent);
-
- crossAxisOffset += lineCrossAxisExtent;
+ lineContexts.append(LineContext(crossAxisOffset, maxChildCrossAxisExtent, children.size(), maxAscent));
+ crossAxisOffset += maxChildCrossAxisExtent;
}
void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace)
@@ -906,6 +972,55 @@ void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children,
}
}
+static LayoutUnit initialLinePackingOffset(LayoutUnit availableFreeSpace, EFlexLinePack linePack, unsigned numberOfLines)
+{
+ if (linePack == LinePackEnd)
+ return availableFreeSpace;
+ if (linePack == LinePackCenter)
+ return availableFreeSpace / 2;
+ if (linePack == LinePackDistribute) {
+ if (availableFreeSpace > 0 && numberOfLines)
+ return availableFreeSpace / (2 * numberOfLines);
+ if (availableFreeSpace < 0)
+ return availableFreeSpace / 2;
+ }
+ return 0;
+}
+
+static LayoutUnit linePackingSpaceBetweenChildren(LayoutUnit availableFreeSpace, EFlexLinePack linePack, unsigned numberOfLines)
+{
+ if (availableFreeSpace > 0 && numberOfLines > 1) {
+ if (linePack == LinePackJustify)
+ return availableFreeSpace / (numberOfLines - 1);
+ if (linePack == LinePackDistribute || linePack == LinePackStretch)
+ return availableFreeSpace / numberOfLines;
+ }
+ return 0;
+}
+
+void RenderFlexibleBox::packFlexLines(FlexOrderIterator& iterator, WTF::Vector<LineContext>& lineContexts)
+{
+ if (!isMultiline() || style()->flexLinePack() == LinePackStart)
+ return;
+
+ LayoutUnit availableCrossAxisSpace = crossAxisContentExtent();
+ for (size_t i = 0; i < lineContexts.size(); ++i)
+ availableCrossAxisSpace -= lineContexts[i].crossAxisExtent;
+
+ RenderBox* child = iterator.first();
+ LayoutUnit lineOffset = initialLinePackingOffset(availableCrossAxisSpace, style()->flexLinePack(), 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 = iterator.next())
+ adjustAlignmentForChild(child, lineOffset);
+
+ if (style()->flexLinePack() == LinePackStretch && availableCrossAxisSpace > 0)
+ lineContexts[lineNumber].crossAxisExtent += availableCrossAxisSpace / static_cast<unsigned>(lineContexts.size());
+
+ lineOffset += linePackingSpaceBetweenChildren(availableCrossAxisSpace, style()->flexLinePack(), lineContexts.size());
+ }
+}
+
void RenderFlexibleBox::adjustAlignmentForChild(RenderBox* child, LayoutUnit delta)
{
LayoutRect oldRect = child->frameRect();
@@ -919,72 +1034,94 @@ void RenderFlexibleBox::adjustAlignmentForChild(RenderBox* child, LayoutUnit del
child->repaintDuringLayoutIfMoved(oldRect);
}
-void RenderFlexibleBox::alignChildren(const OrderedFlexItemList& children, LayoutUnit lineCrossAxisExtent, LayoutUnit maxAscent)
+void RenderFlexibleBox::alignChildren(FlexOrderIterator& iterator, const WTF::Vector<LineContext>& lineContexts)
{
- LayoutUnit minMarginAfterBaseline = std::numeric_limits<LayoutUnit>::max();
-
- for (size_t i = 0; i < children.size(); ++i) {
- RenderBox* child = children[i];
- switch (flexAlignForChild(child)) {
- case AlignAuto:
- ASSERT_NOT_REACHED();
- break;
- case AlignStretch: {
- if (!isColumnFlow() && child->style()->logicalHeight().isAuto()) {
- LayoutUnit logicalHeightBefore = child->logicalHeight();
- LayoutUnit stretchedLogicalHeight = child->logicalHeight() + availableAlignmentSpaceForChild(lineCrossAxisExtent, child);
- child->setLogicalHeight(stretchedLogicalHeight);
- child->computeLogicalHeight();
-
- if (child->logicalHeight() != logicalHeightBefore) {
- child->setOverrideHeight(child->logicalHeight());
- child->setLogicalHeight(0);
- child->setChildNeedsLayout(true);
- child->layoutIfNeeded();
- }
- } else if (isColumnFlow() && child->style()->logicalWidth().isAuto() && isMultiline()) {
- // FIXME: Handle min-width and max-width.
- LayoutUnit childWidth = lineCrossAxisExtent - crossAxisMarginExtentForChild(child);
- child->setOverrideWidth(std::max(0, childWidth));
- child->setChildNeedsLayout(true);
- child->layoutIfNeeded();
+ // Keep track of the space between the baseline edge and the after edge of the box for each line.
+ WTF::Vector<LayoutUnit> minMarginAfterBaselines;
+
+ RenderBox* child = iterator.first();
+ for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
+ LayoutUnit minMarginAfterBaseline = MAX_LAYOUT_UNIT;
+ LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
+ LayoutUnit maxAscent = lineContexts[lineNumber].maxAscent;
+
+ for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) {
+ ASSERT(child);
+ switch (flexAlignForChild(child)) {
+ case AlignAuto:
+ ASSERT_NOT_REACHED();
+ break;
+ case AlignStretch: {
+ 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;
}
- // Since wrap-reverse flips cross start and cross end, strech children should be aligned with the cross end.
- if (style()->flexWrap() == FlexWrapReverse)
+ case AlignStart:
+ break;
+ case AlignEnd:
adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
- break;
- }
- case AlignStart:
- break;
- case AlignEnd:
- adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
- break;
- case AlignCenter:
- adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) / 2);
- break;
- case AlignBaseline: {
- LayoutUnit ascent = marginBoxAscentForChild(child);
- LayoutUnit startOffset = maxAscent - ascent;
- adjustAlignmentForChild(child, startOffset);
-
- if (style()->flexWrap() == FlexWrapReverse)
- minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) - startOffset);
- break;
- }
+ break;
+ case AlignCenter:
+ adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) / 2);
+ break;
+ case AlignBaseline: {
+ LayoutUnit ascent = marginBoxAscentForChild(child);
+ LayoutUnit startOffset = maxAscent - ascent;
+ adjustAlignmentForChild(child, startOffset);
+
+ if (style()->flexWrap() == FlexWrapReverse)
+ minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) - startOffset);
+ break;
+ }
+ }
}
+ minMarginAfterBaselines.append(minMarginAfterBaseline);
}
+ if (style()->flexWrap() != FlexWrapReverse)
+ return;
+
// wrap-reverse flips the cross axis start and end. For baseline alignment, this means we
// need to align the after edge of baseline elements with the after edge of the flex line.
- if (style()->flexWrap() == FlexWrapReverse && minMarginAfterBaseline) {
- for (size_t i = 0; i < children.size(); ++i) {
- RenderBox* child = children[i];
- if (flexAlignForChild(child) == AlignBaseline)
+ child = iterator.first();
+ for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
+ LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber];
+ for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) {
+ ASSERT(child);
+ if (flexAlignForChild(child) == AlignBaseline && minMarginAfterBaseline)
adjustAlignmentForChild(child, minMarginAfterBaseline);
}
}
}
+void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox* child, LayoutUnit lineCrossAxisExtent)
+{
+ if (!isColumnFlow() && child->style()->logicalHeight().isAuto()) {
+ LayoutUnit logicalHeightBefore = child->logicalHeight();
+ LayoutUnit stretchedLogicalHeight = child->logicalHeight() + availableAlignmentSpaceForChild(lineCrossAxisExtent, child);
+ if (stretchedLogicalHeight < logicalHeightBefore)
+ return;
+
+ child->setLogicalHeight(stretchedLogicalHeight);
+ child->computeLogicalHeight();
+
+ if (child->logicalHeight() != logicalHeightBefore) {
+ child->setOverrideHeight(child->logicalHeight());
+ child->setLogicalHeight(0);
+ child->setChildNeedsLayout(true);
+ child->layoutIfNeeded();
+ }
+ } else if (isColumnFlow() && child->style()->logicalWidth().isAuto() && isMultiline()) {
+ // FIXME: Handle min-width and max-width.
+ LayoutUnit childWidth = lineCrossAxisExtent - crossAxisMarginExtentForChild(child);
+ child->setOverrideWidth(std::max(ZERO_LAYOUT_UNIT, childWidth));
+ child->setChildNeedsLayout(true);
+ child->layoutIfNeeded();
+ }
+}
+
void RenderFlexibleBox::flipForRightToLeftColumn(FlexOrderIterator& iterator)
{
if (style()->isLeftToRightDirection() || !isColumnFlow())
@@ -998,26 +1135,23 @@ void RenderFlexibleBox::flipForRightToLeftColumn(FlexOrderIterator& iterator)
}
}
-void RenderFlexibleBox::flipForWrapReverse(FlexOrderIterator& iterator, const WrapReverseContext& wrapReverseContext)
+void RenderFlexibleBox::flipForWrapReverse(FlexOrderIterator& iterator, const WTF::Vector<LineContext>& lineContexts, LayoutUnit crossAxisStartEdge)
{
- if (!isColumnFlow())
- computeLogicalHeight();
-
- size_t currentChild = 0;
- size_t lineNumber = 0;
LayoutUnit contentExtent = crossAxisContentExtent();
- for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
- LayoutPoint location = flowAwareLocationForChild(child);
- location.setY(location.y() + wrapReverseContext.lineCrossAxisDelta(lineNumber, contentExtent));
-
- LayoutRect oldRect = child->frameRect();
- setFlowAwareLocationForChild(child, location);
- if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
- child->repaintDuringLayoutIfMoved(oldRect);
-
- if (++currentChild == wrapReverseContext.childrenPerLine[lineNumber]) {
- ++lineNumber;
- currentChild = 0;
+ RenderBox* child = iterator.first();
+ for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
+ for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) {
+ ASSERT(child);
+ LayoutPoint location = flowAwareLocationForChild(child);
+ LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
+ LayoutUnit originalOffset = lineContexts[lineNumber].crossAxisOffset - crossAxisStartEdge;
+ LayoutUnit newOffset = contentExtent - originalOffset - lineCrossAxisExtent;
+ location.setY(location.y() + newOffset - originalOffset);
+
+ LayoutRect oldRect = child->frameRect();
+ setFlowAwareLocationForChild(child, location);
+ if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
+ child->repaintDuringLayoutIfMoved(oldRect);
}
}
}