2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "core/rendering/RenderFlexibleBox.h"
34 #include "core/frame/UseCounter.h"
35 #include "core/paint/BlockPainter.h"
36 #include "core/rendering/RenderLayer.h"
37 #include "core/rendering/RenderView.h"
38 #include "core/rendering/TextAutosizer.h"
39 #include "core/rendering/style/RenderStyle.h"
40 #include "platform/LengthFunctions.h"
41 #include "wtf/MathExtras.h"
46 struct RenderFlexibleBox::LineContext {
47 LineContext(LayoutUnit crossAxisOffset, LayoutUnit crossAxisExtent, size_t numberOfChildren, LayoutUnit maxAscent)
48 : crossAxisOffset(crossAxisOffset)
49 , crossAxisExtent(crossAxisExtent)
50 , numberOfChildren(numberOfChildren)
51 , maxAscent(maxAscent)
55 LayoutUnit crossAxisOffset;
56 LayoutUnit crossAxisExtent;
57 size_t numberOfChildren;
61 struct RenderFlexibleBox::Violation {
62 Violation(RenderBox* child, LayoutUnit childSize)
64 , childSize(childSize)
73 RenderFlexibleBox::RenderFlexibleBox(Element* element)
74 : RenderBlock(element)
75 , m_orderIterator(this)
76 , m_numberOfInFlowChildrenOnFirstLine(-1)
78 ASSERT(!childrenInline());
81 RenderFlexibleBox::~RenderFlexibleBox()
85 RenderFlexibleBox* RenderFlexibleBox::createAnonymous(Document* document)
87 RenderFlexibleBox* renderer = new RenderFlexibleBox(0);
88 renderer->setDocumentForAnonymous(document);
92 const char* RenderFlexibleBox::renderName() const
94 return "RenderFlexibleBox";
97 void RenderFlexibleBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
99 // FIXME: We're ignoring flex-basis here and we shouldn't. We can't start honoring it though until
100 // the flex shorthand stops setting it to 0.
101 // See https://bugs.webkit.org/show_bug.cgi?id=116117 and http://crbug.com/240765.
102 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
103 if (child->isOutOfFlowPositioned())
106 LayoutUnit margin = marginIntrinsicLogicalWidthForChild(child);
107 bool hasOrthogonalWritingMode = child->isHorizontalWritingMode() != isHorizontalWritingMode();
108 LayoutUnit minPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->minPreferredLogicalWidth();
109 LayoutUnit maxPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->maxPreferredLogicalWidth();
110 minPreferredLogicalWidth += margin;
111 maxPreferredLogicalWidth += margin;
112 if (!isColumnFlow()) {
113 maxLogicalWidth += maxPreferredLogicalWidth;
115 // For multiline, the min preferred width is if you put a break between each item.
116 minLogicalWidth = std::max(minLogicalWidth, minPreferredLogicalWidth);
118 minLogicalWidth += minPreferredLogicalWidth;
120 minLogicalWidth = std::max(minPreferredLogicalWidth, minLogicalWidth);
121 maxLogicalWidth = std::max(maxPreferredLogicalWidth, maxLogicalWidth);
125 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
127 LayoutUnit scrollbarWidth = instrinsicScrollbarLogicalWidth();
128 maxLogicalWidth += scrollbarWidth;
129 minLogicalWidth += scrollbarWidth;
132 static int synthesizedBaselineFromContentBox(const RenderBox& box, LineDirectionMode direction)
134 return direction == HorizontalLine ? box.borderTop() + box.paddingTop() + box.contentHeight() : box.borderRight() + box.paddingRight() + box.contentWidth();
137 int RenderFlexibleBox::baselinePosition(FontBaseline, bool, LineDirectionMode direction, LinePositionMode mode) const
139 ASSERT(mode == PositionOnContainingLine);
140 int baseline = firstLineBoxBaseline();
142 baseline = synthesizedBaselineFromContentBox(*this, direction);
144 return beforeMarginInLineDirection(direction) + baseline;
147 int RenderFlexibleBox::firstLineBoxBaseline() const
149 if (isWritingModeRoot() || m_numberOfInFlowChildrenOnFirstLine <= 0)
151 RenderBox* baselineChild = 0;
153 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
154 if (child->isOutOfFlowPositioned())
156 if (alignmentForChild(*child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(*child)) {
157 baselineChild = child;
161 baselineChild = child;
164 if (childNumber == m_numberOfInFlowChildrenOnFirstLine)
171 if (!isColumnFlow() && hasOrthogonalFlow(*baselineChild))
172 return crossAxisExtentForChild(*baselineChild) + baselineChild->logicalTop();
173 if (isColumnFlow() && !hasOrthogonalFlow(*baselineChild))
174 return mainAxisExtentForChild(*baselineChild) + baselineChild->logicalTop();
176 int baseline = baselineChild->firstLineBoxBaseline();
177 if (baseline == -1) {
178 // FIXME: We should pass |direction| into firstLineBoxBaseline and stop bailing out if we're a writing mode root.
179 // This would also fix some cases where the flexbox is orthogonal to its container.
180 LineDirectionMode direction = isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
181 return synthesizedBaselineFromContentBox(*baselineChild, direction) + baselineChild->logicalTop();
184 return baseline + baselineChild->logicalTop();
187 int RenderFlexibleBox::inlineBlockBaseline(LineDirectionMode direction) const
189 int baseline = firstLineBoxBaseline();
193 int marginAscent = direction == HorizontalLine ? marginTop() : marginRight();
194 return synthesizedBaselineFromContentBox(*this, direction) + marginAscent;
197 void RenderFlexibleBox::removeChild(RenderObject* child)
199 RenderBlock::removeChild(child);
200 m_intrinsicSizeAlongMainAxis.remove(child);
203 void RenderFlexibleBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
205 RenderBlock::styleDidChange(diff, oldStyle);
207 if (oldStyle && oldStyle->alignItems() == ItemPositionStretch && diff.needsFullLayout()) {
208 // Flex items that were previously stretching need to be relayed out so we can compute new available cross axis space.
209 // This is only necessary for stretching since other alignment values don't change the size of the box.
210 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
211 ItemPosition previousAlignment = RenderStyle::resolveAlignment(oldStyle, child->style(), ItemPositionStretch);
212 if (previousAlignment == ItemPositionStretch && previousAlignment != RenderStyle::resolveAlignment(style(), child->style(), ItemPositionStretch))
213 child->setChildNeedsLayout(MarkOnlyThis);
218 void RenderFlexibleBox::layoutBlock(bool relayoutChildren)
220 ASSERT(needsLayout());
222 if (!relayoutChildren && simplifiedLayout())
225 if (updateLogicalWidthAndColumnWidth())
226 relayoutChildren = true;
228 LayoutUnit previousHeight = logicalHeight();
229 setLogicalHeight(borderAndPaddingLogicalHeight() + scrollbarLogicalHeight());
232 TextAutosizer::LayoutScope textAutosizerLayoutScope(this);
233 LayoutState state(*this, locationOffset());
235 m_numberOfInFlowChildrenOnFirstLine = -1;
237 RenderBlock::startDelayUpdateScrollInfo();
239 prepareOrderIteratorAndMargins();
241 ChildFrameRects oldChildRects;
242 appendChildFrameRects(oldChildRects);
244 layoutFlexItems(relayoutChildren);
246 RenderBlock::finishDelayUpdateScrollInfo();
248 if (logicalHeight() != previousHeight)
249 relayoutChildren = true;
251 layoutPositionedObjects(relayoutChildren || isDocumentElement());
253 // FIXME: css3/flexbox/repaint-rtl-column.html seems to issue paint invalidations for more overflow than it needs to.
254 computeOverflow(clientLogicalBottomAfterRepositioning());
257 updateLayerTransformAfterLayout();
259 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
260 // we overflow or not.
261 updateScrollInfoAfterLayout();
266 void RenderFlexibleBox::appendChildFrameRects(ChildFrameRects& childFrameRects)
268 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
269 if (!child->isOutOfFlowPositioned())
270 childFrameRects.append(child->frameRect());
274 void RenderFlexibleBox::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
276 BlockPainter::paintChildrenOfFlexibleBox(*this, paintInfo, paintOffset);
279 void RenderFlexibleBox::repositionLogicalHeightDependentFlexItems(Vector<LineContext>& lineContexts)
281 LayoutUnit crossAxisStartEdge = lineContexts.isEmpty() ? LayoutUnit() : lineContexts[0].crossAxisOffset;
282 alignFlexLines(lineContexts);
284 alignChildren(lineContexts);
286 if (style()->flexWrap() == FlexWrapReverse)
287 flipForWrapReverse(lineContexts, crossAxisStartEdge);
289 // direction:rtl + flex-direction:column means the cross-axis direction is flipped.
290 flipForRightToLeftColumn();
293 LayoutUnit RenderFlexibleBox::clientLogicalBottomAfterRepositioning()
295 LayoutUnit maxChildLogicalBottom = 0;
296 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
297 if (child->isOutOfFlowPositioned())
299 LayoutUnit childLogicalBottom = logicalTopForChild(child) + logicalHeightForChild(child) + marginAfterForChild(child);
300 maxChildLogicalBottom = std::max(maxChildLogicalBottom, childLogicalBottom);
302 return std::max(clientLogicalBottom(), maxChildLogicalBottom + paddingAfter());
305 bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox& child) const
307 // FIXME: If the child is a flexbox, then we need to check isHorizontalFlow.
308 return isHorizontalFlow() != child.isHorizontalWritingMode();
311 bool RenderFlexibleBox::isColumnFlow() const
313 return style()->isColumnFlexDirection();
316 bool RenderFlexibleBox::isHorizontalFlow() const
318 if (isHorizontalWritingMode())
319 return !isColumnFlow();
320 return isColumnFlow();
323 bool RenderFlexibleBox::isLeftToRightFlow() const
326 return style()->writingMode() == TopToBottomWritingMode || style()->writingMode() == LeftToRightWritingMode;
327 return style()->isLeftToRightDirection() ^ (style()->flexDirection() == FlowRowReverse);
330 bool RenderFlexibleBox::isMultiline() const
332 return style()->flexWrap() != FlexNoWrap;
335 Length RenderFlexibleBox::flexBasisForChild(RenderBox& child) const
337 Length flexLength = child.style()->flexBasis();
338 if (flexLength.isAuto())
339 flexLength = isHorizontalFlow() ? child.style()->width() : child.style()->height();
343 LayoutUnit RenderFlexibleBox::crossAxisExtentForChild(RenderBox& child) const
345 return isHorizontalFlow() ? child.height() : child.width();
348 static inline LayoutUnit constrainedChildIntrinsicContentLogicalHeight(RenderBox& child)
350 LayoutUnit childIntrinsicContentLogicalHeight = child.intrinsicContentLogicalHeight();
351 return child.constrainLogicalHeightByMinMax(childIntrinsicContentLogicalHeight + child.borderAndPaddingLogicalHeight(), childIntrinsicContentLogicalHeight);
354 LayoutUnit RenderFlexibleBox::childIntrinsicHeight(RenderBox& child) const
356 if (child.isHorizontalWritingMode() && needToStretchChildLogicalHeight(child))
357 return constrainedChildIntrinsicContentLogicalHeight(child);
358 return child.height();
361 LayoutUnit RenderFlexibleBox::childIntrinsicWidth(RenderBox& child) const
363 if (!child.isHorizontalWritingMode() && needToStretchChildLogicalHeight(child))
364 return constrainedChildIntrinsicContentLogicalHeight(child);
365 return child.width();
368 LayoutUnit RenderFlexibleBox::crossAxisIntrinsicExtentForChild(RenderBox& child) const
370 return isHorizontalFlow() ? childIntrinsicHeight(child) : childIntrinsicWidth(child);
373 LayoutUnit RenderFlexibleBox::mainAxisExtentForChild(RenderBox& child) const
375 return isHorizontalFlow() ? child.width() : child.height();
378 LayoutUnit RenderFlexibleBox::crossAxisExtent() const
380 return isHorizontalFlow() ? height() : width();
383 LayoutUnit RenderFlexibleBox::mainAxisExtent() const
385 return isHorizontalFlow() ? width() : height();
388 LayoutUnit RenderFlexibleBox::crossAxisContentExtent() const
390 return isHorizontalFlow() ? contentHeight() : contentWidth();
393 LayoutUnit RenderFlexibleBox::mainAxisContentExtent(LayoutUnit contentLogicalHeight)
395 if (isColumnFlow()) {
396 LogicalExtentComputedValues computedValues;
397 LayoutUnit borderPaddingAndScrollbar = borderAndPaddingLogicalHeight() + scrollbarLogicalHeight();
398 LayoutUnit borderBoxLogicalHeight = contentLogicalHeight + borderPaddingAndScrollbar;
399 computeLogicalHeight(borderBoxLogicalHeight, logicalTop(), computedValues);
400 if (computedValues.m_extent == LayoutUnit::max())
401 return computedValues.m_extent;
402 return std::max(LayoutUnit(0), computedValues.m_extent - borderPaddingAndScrollbar);
404 return contentLogicalWidth();
407 LayoutUnit RenderFlexibleBox::computeMainAxisExtentForChild(RenderBox& child, SizeType sizeType, const Length& size)
409 // FIXME: This is wrong for orthogonal flows. It should use the flexbox's writing-mode, not the child's in order
410 // to figure out the logical height/width.
411 if (isColumnFlow()) {
412 // We don't have to check for "auto" here - computeContentLogicalHeight will just return -1 for that case anyway.
413 if (size.isIntrinsic())
414 child.layoutIfNeeded();
415 return child.computeContentLogicalHeight(size, child.logicalHeight() - child.borderAndPaddingLogicalHeight()) + child.scrollbarLogicalHeight();
417 return child.computeLogicalWidthUsing(sizeType, size, contentLogicalWidth(), this) - child.borderAndPaddingLogicalWidth();
420 WritingMode RenderFlexibleBox::transformedWritingMode() const
422 WritingMode mode = style()->writingMode();
427 case TopToBottomWritingMode:
428 case BottomToTopWritingMode:
429 return style()->isLeftToRightDirection() ? LeftToRightWritingMode : RightToLeftWritingMode;
430 case LeftToRightWritingMode:
431 case RightToLeftWritingMode:
432 return style()->isLeftToRightDirection() ? TopToBottomWritingMode : BottomToTopWritingMode;
434 ASSERT_NOT_REACHED();
435 return TopToBottomWritingMode;
438 LayoutUnit RenderFlexibleBox::flowAwareBorderStart() const
440 if (isHorizontalFlow())
441 return isLeftToRightFlow() ? borderLeft() : borderRight();
442 return isLeftToRightFlow() ? borderTop() : borderBottom();
445 LayoutUnit RenderFlexibleBox::flowAwareBorderEnd() const
447 if (isHorizontalFlow())
448 return isLeftToRightFlow() ? borderRight() : borderLeft();
449 return isLeftToRightFlow() ? borderBottom() : borderTop();
452 LayoutUnit RenderFlexibleBox::flowAwareBorderBefore() const
454 switch (transformedWritingMode()) {
455 case TopToBottomWritingMode:
457 case BottomToTopWritingMode:
458 return borderBottom();
459 case LeftToRightWritingMode:
461 case RightToLeftWritingMode:
462 return borderRight();
464 ASSERT_NOT_REACHED();
468 LayoutUnit RenderFlexibleBox::flowAwareBorderAfter() const
470 switch (transformedWritingMode()) {
471 case TopToBottomWritingMode:
472 return borderBottom();
473 case BottomToTopWritingMode:
475 case LeftToRightWritingMode:
476 return borderRight();
477 case RightToLeftWritingMode:
480 ASSERT_NOT_REACHED();
484 LayoutUnit RenderFlexibleBox::flowAwarePaddingStart() const
486 if (isHorizontalFlow())
487 return isLeftToRightFlow() ? paddingLeft() : paddingRight();
488 return isLeftToRightFlow() ? paddingTop() : paddingBottom();
491 LayoutUnit RenderFlexibleBox::flowAwarePaddingEnd() const
493 if (isHorizontalFlow())
494 return isLeftToRightFlow() ? paddingRight() : paddingLeft();
495 return isLeftToRightFlow() ? paddingBottom() : paddingTop();
498 LayoutUnit RenderFlexibleBox::flowAwarePaddingBefore() const
500 switch (transformedWritingMode()) {
501 case TopToBottomWritingMode:
503 case BottomToTopWritingMode:
504 return paddingBottom();
505 case LeftToRightWritingMode:
506 return paddingLeft();
507 case RightToLeftWritingMode:
508 return paddingRight();
510 ASSERT_NOT_REACHED();
514 LayoutUnit RenderFlexibleBox::flowAwarePaddingAfter() const
516 switch (transformedWritingMode()) {
517 case TopToBottomWritingMode:
518 return paddingBottom();
519 case BottomToTopWritingMode:
521 case LeftToRightWritingMode:
522 return paddingRight();
523 case RightToLeftWritingMode:
524 return paddingLeft();
526 ASSERT_NOT_REACHED();
530 LayoutUnit RenderFlexibleBox::flowAwareMarginStartForChild(RenderBox& child) const
532 if (isHorizontalFlow())
533 return isLeftToRightFlow() ? child.marginLeft() : child.marginRight();
534 return isLeftToRightFlow() ? child.marginTop() : child.marginBottom();
537 LayoutUnit RenderFlexibleBox::flowAwareMarginEndForChild(RenderBox& child) const
539 if (isHorizontalFlow())
540 return isLeftToRightFlow() ? child.marginRight() : child.marginLeft();
541 return isLeftToRightFlow() ? child.marginBottom() : child.marginTop();
544 LayoutUnit RenderFlexibleBox::flowAwareMarginBeforeForChild(RenderBox& child) const
546 switch (transformedWritingMode()) {
547 case TopToBottomWritingMode:
548 return child.marginTop();
549 case BottomToTopWritingMode:
550 return child.marginBottom();
551 case LeftToRightWritingMode:
552 return child.marginLeft();
553 case RightToLeftWritingMode:
554 return child.marginRight();
556 ASSERT_NOT_REACHED();
560 LayoutUnit RenderFlexibleBox::crossAxisMarginExtentForChild(RenderBox& child) const
562 return isHorizontalFlow() ? child.marginHeight() : child.marginWidth();
565 LayoutUnit RenderFlexibleBox::crossAxisScrollbarExtent() const
567 return isHorizontalFlow() ? horizontalScrollbarHeight() : verticalScrollbarWidth();
570 LayoutUnit RenderFlexibleBox::crossAxisScrollbarExtentForChild(RenderBox& child) const
572 return isHorizontalFlow() ? child.horizontalScrollbarHeight() : child.verticalScrollbarWidth();
575 LayoutPoint RenderFlexibleBox::flowAwareLocationForChild(RenderBox& child) const
577 return isHorizontalFlow() ? child.location() : child.location().transposedPoint();
580 void RenderFlexibleBox::setFlowAwareLocationForChild(RenderBox& child, const LayoutPoint& location)
582 if (isHorizontalFlow())
583 child.setLocation(location);
585 child.setLocation(location.transposedPoint());
588 LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox& child) const
590 return isHorizontalFlow() ? child.borderAndPaddingWidth() : child.borderAndPaddingHeight();
593 static inline bool preferredMainAxisExtentDependsOnLayout(const Length& flexBasis, bool hasInfiniteLineLength)
595 return flexBasis.isAuto() || (flexBasis.isPercent() && hasInfiniteLineLength);
598 bool RenderFlexibleBox::childPreferredMainAxisContentExtentRequiresLayout(RenderBox& child, bool hasInfiniteLineLength) const
600 return preferredMainAxisExtentDependsOnLayout(flexBasisForChild(child), hasInfiniteLineLength) && hasOrthogonalFlow(child);
603 LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox& child, bool hasInfiniteLineLength, bool relayoutChildren)
605 child.clearOverrideSize();
607 if (child.isImage() || child.isVideo() || child.isCanvas())
608 UseCounter::count(document(), UseCounter::AspectRatioFlexItem);
610 Length flexBasis = flexBasisForChild(child);
611 if (preferredMainAxisExtentDependsOnLayout(flexBasis, hasInfiniteLineLength)) {
612 LayoutUnit mainAxisExtent;
613 if (hasOrthogonalFlow(child)) {
614 if (child.needsLayout() || relayoutChildren || !m_intrinsicSizeAlongMainAxis.contains(&child)) {
615 m_intrinsicSizeAlongMainAxis.remove(&child);
616 child.forceChildLayout();
617 m_intrinsicSizeAlongMainAxis.set(&child, child.logicalHeight());
619 mainAxisExtent = m_intrinsicSizeAlongMainAxis.get(&child);
621 mainAxisExtent = child.maxPreferredLogicalWidth();
623 ASSERT(mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child) >= 0);
624 return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child);
626 return std::max(LayoutUnit(0), computeMainAxisExtentForChild(child, MainOrPreferredSize, flexBasis));
629 void RenderFlexibleBox::layoutFlexItems(bool relayoutChildren)
631 Vector<LineContext> lineContexts;
632 OrderedFlexItemList orderedChildren;
633 LayoutUnit sumFlexBaseSize;
634 double totalFlexGrow;
635 double totalWeightedFlexShrink;
636 LayoutUnit sumHypotheticalMainSize;
638 Vector<LayoutUnit, 16> childSizes;
640 m_orderIterator.first();
641 LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
642 bool hasInfiniteLineLength = false;
643 while (computeNextFlexLine(orderedChildren, sumFlexBaseSize, totalFlexGrow, totalWeightedFlexShrink, sumHypotheticalMainSize, hasInfiniteLineLength, relayoutChildren)) {
644 LayoutUnit containerMainInnerSize = mainAxisContentExtent(sumHypotheticalMainSize);
645 LayoutUnit availableFreeSpace = containerMainInnerSize - sumFlexBaseSize;
646 FlexSign flexSign = (sumHypotheticalMainSize < containerMainInnerSize) ? PositiveFlexibility : NegativeFlexibility;
647 InflexibleFlexItemSize inflexibleItems;
648 childSizes.reserveCapacity(orderedChildren.size());
649 while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, childSizes, hasInfiniteLineLength)) {
650 ASSERT(totalFlexGrow >= 0 && totalWeightedFlexShrink >= 0);
651 ASSERT(inflexibleItems.size() > 0);
654 layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace, relayoutChildren, lineContexts, hasInfiniteLineLength);
656 if (hasLineIfEmpty()) {
657 // Even if computeNextFlexLine returns true, the flexbox might not have
658 // a line because all our children might be out of flow positioned.
659 // Instead of just checking if we have a line, make sure the flexbox
660 // has at least a line's worth of height to cover this case.
661 LayoutUnit minHeight = borderAndPaddingLogicalHeight()
662 + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes)
663 + scrollbarLogicalHeight();
664 if (height() < minHeight)
665 setLogicalHeight(minHeight);
668 updateLogicalHeight();
669 repositionLogicalHeightDependentFlexItems(lineContexts);
672 LayoutUnit RenderFlexibleBox::autoMarginOffsetInMainAxis(const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace)
674 if (availableFreeSpace <= 0)
677 int numberOfAutoMargins = 0;
678 bool isHorizontal = isHorizontalFlow();
679 for (size_t i = 0; i < children.size(); ++i) {
680 RenderBox* child = children[i];
681 if (child->isOutOfFlowPositioned())
684 if (child->style()->marginLeft().isAuto())
685 ++numberOfAutoMargins;
686 if (child->style()->marginRight().isAuto())
687 ++numberOfAutoMargins;
689 if (child->style()->marginTop().isAuto())
690 ++numberOfAutoMargins;
691 if (child->style()->marginBottom().isAuto())
692 ++numberOfAutoMargins;
695 if (!numberOfAutoMargins)
698 LayoutUnit sizeOfAutoMargin = availableFreeSpace / numberOfAutoMargins;
699 availableFreeSpace = 0;
700 return sizeOfAutoMargin;
703 void RenderFlexibleBox::updateAutoMarginsInMainAxis(RenderBox& child, LayoutUnit autoMarginOffset)
705 ASSERT(autoMarginOffset >= 0);
707 if (isHorizontalFlow()) {
708 if (child.style()->marginLeft().isAuto())
709 child.setMarginLeft(autoMarginOffset);
710 if (child.style()->marginRight().isAuto())
711 child.setMarginRight(autoMarginOffset);
713 if (child.style()->marginTop().isAuto())
714 child.setMarginTop(autoMarginOffset);
715 if (child.style()->marginBottom().isAuto())
716 child.setMarginBottom(autoMarginOffset);
720 bool RenderFlexibleBox::hasAutoMarginsInCrossAxis(RenderBox& child) const
722 if (isHorizontalFlow())
723 return child.style()->marginTop().isAuto() || child.style()->marginBottom().isAuto();
724 return child.style()->marginLeft().isAuto() || child.style()->marginRight().isAuto();
727 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox& child)
729 ASSERT(!child.isOutOfFlowPositioned());
730 LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child);
731 return lineCrossAxisExtent - childCrossExtent;
734 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChildBeforeStretching(LayoutUnit lineCrossAxisExtent, RenderBox& child)
736 ASSERT(!child.isOutOfFlowPositioned());
737 LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisIntrinsicExtentForChild(child);
738 return lineCrossAxisExtent - childCrossExtent;
741 bool RenderFlexibleBox::updateAutoMarginsInCrossAxis(RenderBox& child, LayoutUnit availableAlignmentSpace)
743 ASSERT(!child.isOutOfFlowPositioned());
744 ASSERT(availableAlignmentSpace >= 0);
746 bool isHorizontal = isHorizontalFlow();
747 Length topOrLeft = isHorizontal ? child.style()->marginTop() : child.style()->marginLeft();
748 Length bottomOrRight = isHorizontal ? child.style()->marginBottom() : child.style()->marginRight();
749 if (topOrLeft.isAuto() && bottomOrRight.isAuto()) {
750 adjustAlignmentForChild(child, availableAlignmentSpace / 2);
752 child.setMarginTop(availableAlignmentSpace / 2);
753 child.setMarginBottom(availableAlignmentSpace / 2);
755 child.setMarginLeft(availableAlignmentSpace / 2);
756 child.setMarginRight(availableAlignmentSpace / 2);
760 bool shouldAdjustTopOrLeft = true;
761 if (isColumnFlow() && !child.style()->isLeftToRightDirection()) {
762 // For column flows, only make this adjustment if topOrLeft corresponds to the "before" margin,
763 // so that flipForRightToLeftColumn will do the right thing.
764 shouldAdjustTopOrLeft = false;
766 if (!isColumnFlow() && child.style()->slowIsFlippedBlocksWritingMode()) {
767 // If we are a flipped writing mode, we need to adjust the opposite side. This is only needed
768 // for row flows because this only affects the block-direction axis.
769 shouldAdjustTopOrLeft = false;
772 if (topOrLeft.isAuto()) {
773 if (shouldAdjustTopOrLeft)
774 adjustAlignmentForChild(child, availableAlignmentSpace);
777 child.setMarginTop(availableAlignmentSpace);
779 child.setMarginLeft(availableAlignmentSpace);
782 if (bottomOrRight.isAuto()) {
783 if (!shouldAdjustTopOrLeft)
784 adjustAlignmentForChild(child, availableAlignmentSpace);
787 child.setMarginBottom(availableAlignmentSpace);
789 child.setMarginRight(availableAlignmentSpace);
795 LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(RenderBox& child)
797 LayoutUnit ascent = child.firstLineBoxBaseline();
799 ascent = crossAxisExtentForChild(child);
800 return ascent + flowAwareMarginBeforeForChild(child);
803 LayoutUnit RenderFlexibleBox::computeChildMarginValue(Length margin)
805 // When resolving the margins, we use the content size for resolving percent and calc (for percents in calc expressions) margins.
806 // Fortunately, percent margins are always computed with respect to the block's width, even for margin-top and margin-bottom.
807 LayoutUnit availableSize = contentLogicalWidth();
808 return minimumValueForLength(margin, availableSize);
811 void RenderFlexibleBox::prepareOrderIteratorAndMargins()
813 OrderIteratorPopulator populator(m_orderIterator);
815 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
816 populator.collectChild(child);
818 if (child->isOutOfFlowPositioned())
821 // Before running the flex algorithm, 'auto' has a margin of 0.
822 // Also, if we're not auto sizing, we don't do a layout that computes the start/end margins.
823 if (isHorizontalFlow()) {
824 child->setMarginLeft(computeChildMarginValue(child->style()->marginLeft()));
825 child->setMarginRight(computeChildMarginValue(child->style()->marginRight()));
827 child->setMarginTop(computeChildMarginValue(child->style()->marginTop()));
828 child->setMarginBottom(computeChildMarginValue(child->style()->marginBottom()));
833 LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox& child, LayoutUnit childSize)
835 Length max = isHorizontalFlow() ? child.style()->maxWidth() : child.style()->maxHeight();
836 if (max.isSpecifiedOrIntrinsic()) {
837 LayoutUnit maxExtent = computeMainAxisExtentForChild(child, MaxSize, max);
838 if (maxExtent != -1 && childSize > maxExtent)
839 childSize = maxExtent;
842 Length min = isHorizontalFlow() ? child.style()->minWidth() : child.style()->minHeight();
843 LayoutUnit minExtent = 0;
844 if (min.isSpecifiedOrIntrinsic())
845 minExtent = computeMainAxisExtentForChild(child, MinSize, min);
846 return std::max(childSize, minExtent);
849 bool RenderFlexibleBox::computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& sumFlexBaseSize, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& sumHypotheticalMainSize, bool& hasInfiniteLineLength, bool relayoutChildren)
851 orderedChildren.clear();
853 totalFlexGrow = totalWeightedFlexShrink = 0;
854 sumHypotheticalMainSize = 0;
856 if (!m_orderIterator.currentChild())
859 LayoutUnit lineBreakLength = mainAxisContentExtent(LayoutUnit::max());
860 hasInfiniteLineLength = lineBreakLength == LayoutUnit::max();
862 bool lineHasInFlowItem = false;
864 for (RenderBox* child = m_orderIterator.currentChild(); child; child = m_orderIterator.next()) {
865 if (child->isOutOfFlowPositioned()) {
866 orderedChildren.append(child);
870 LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(*child, hasInfiniteLineLength, relayoutChildren);
871 LayoutUnit childMainAxisMarginBorderPadding = mainAxisBorderAndPaddingExtentForChild(*child)
872 + (isHorizontalFlow() ? child->marginWidth() : child->marginHeight());
873 LayoutUnit childFlexBaseSize = childMainAxisExtent + childMainAxisMarginBorderPadding;
875 LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(*child, childMainAxisExtent);
876 LayoutUnit childHypotheticalMainSize = childMinMaxAppliedMainAxisExtent + childMainAxisMarginBorderPadding;
878 if (isMultiline() && sumHypotheticalMainSize + childHypotheticalMainSize > lineBreakLength && lineHasInFlowItem)
880 orderedChildren.append(child);
881 lineHasInFlowItem = true;
882 sumFlexBaseSize += childFlexBaseSize;
883 totalFlexGrow += child->style()->flexGrow();
884 totalWeightedFlexShrink += child->style()->flexShrink() * childMainAxisExtent;
885 sumHypotheticalMainSize += childHypotheticalMainSize;
890 void RenderFlexibleBox::freezeViolations(const Vector<Violation>& violations, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, bool hasInfiniteLineLength)
892 for (size_t i = 0; i < violations.size(); ++i) {
893 RenderBox* child = violations[i].child;
894 LayoutUnit childSize = violations[i].childSize;
895 LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(*child, hasInfiniteLineLength);
896 availableFreeSpace -= childSize - preferredChildSize;
897 totalFlexGrow -= child->style()->flexGrow();
898 totalWeightedFlexShrink -= child->style()->flexShrink() * preferredChildSize;
899 inflexibleItems.set(child, childSize);
903 // Returns true if we successfully ran the algorithm and sized the flex items.
904 bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, Vector<LayoutUnit, 16>& childSizes, bool hasInfiniteLineLength)
906 childSizes.resize(0);
907 LayoutUnit totalViolation = 0;
908 LayoutUnit usedFreeSpace = 0;
909 Vector<Violation> minViolations;
910 Vector<Violation> maxViolations;
911 for (size_t i = 0; i < children.size(); ++i) {
912 RenderBox* child = children[i];
913 if (child->isOutOfFlowPositioned()) {
914 childSizes.append(0);
918 if (inflexibleItems.contains(child))
919 childSizes.append(inflexibleItems.get(child));
921 LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(*child, hasInfiniteLineLength);
922 LayoutUnit childSize = preferredChildSize;
923 double extraSpace = 0;
924 if (availableFreeSpace > 0 && totalFlexGrow > 0 && flexSign == PositiveFlexibility && std::isfinite(totalFlexGrow))
925 extraSpace = availableFreeSpace * child->style()->flexGrow() / totalFlexGrow;
926 else if (availableFreeSpace < 0 && totalWeightedFlexShrink > 0 && flexSign == NegativeFlexibility && std::isfinite(totalWeightedFlexShrink))
927 extraSpace = availableFreeSpace * child->style()->flexShrink() * preferredChildSize / totalWeightedFlexShrink;
928 if (std::isfinite(extraSpace))
929 childSize += LayoutUnit::fromFloatRound(extraSpace);
931 LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(*child, childSize);
932 childSizes.append(adjustedChildSize);
933 usedFreeSpace += adjustedChildSize - preferredChildSize;
935 LayoutUnit violation = adjustedChildSize - childSize;
937 minViolations.append(Violation(child, adjustedChildSize));
938 else if (violation < 0)
939 maxViolations.append(Violation(child, adjustedChildSize));
940 totalViolation += violation;
945 freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, hasInfiniteLineLength);
947 availableFreeSpace -= usedFreeSpace;
949 return !totalViolation;
952 static LayoutUnit initialJustifyContentOffset(LayoutUnit availableFreeSpace, ContentPosition justifyContent, ContentDistributionType justifyContentDistribution, unsigned numberOfChildren)
954 if (justifyContent == ContentPositionFlexEnd)
955 return availableFreeSpace;
956 if (justifyContent == ContentPositionCenter)
957 return availableFreeSpace / 2;
958 if (justifyContentDistribution == ContentDistributionSpaceAround) {
959 if (availableFreeSpace > 0 && numberOfChildren)
960 return availableFreeSpace / (2 * numberOfChildren);
962 return availableFreeSpace / 2;
967 static LayoutUnit justifyContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, ContentDistributionType justifyContentDistribution, unsigned numberOfChildren)
969 if (availableFreeSpace > 0 && numberOfChildren > 1) {
970 if (justifyContentDistribution == ContentDistributionSpaceBetween)
971 return availableFreeSpace / (numberOfChildren - 1);
972 if (justifyContentDistribution == ContentDistributionSpaceAround)
973 return availableFreeSpace / numberOfChildren;
978 void RenderFlexibleBox::setLogicalOverrideSize(RenderBox& child, LayoutUnit childPreferredSize)
980 if (hasOrthogonalFlow(child))
981 child.setOverrideLogicalContentHeight(childPreferredSize - child.borderAndPaddingLogicalHeight());
983 child.setOverrideLogicalContentWidth(childPreferredSize - child.borderAndPaddingLogicalWidth());
986 void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox& child, LayoutUnit mainAxisOffset, LayoutUnit crossAxisOffset, PositionedLayoutMode layoutMode)
988 ASSERT(child.isOutOfFlowPositioned());
989 child.containingBlock()->insertPositionedObject(&child);
990 RenderLayer* childLayer = child.layer();
991 LayoutUnit inlinePosition = isColumnFlow() ? crossAxisOffset : mainAxisOffset;
992 if (layoutMode == FlipForRowReverse && style()->flexDirection() == FlowRowReverse)
993 inlinePosition = mainAxisExtent() - mainAxisOffset;
994 childLayer->setStaticInlinePosition(inlinePosition);
996 LayoutUnit staticBlockPosition = isColumnFlow() ? mainAxisOffset : crossAxisOffset;
997 if (childLayer->staticBlockPosition() != staticBlockPosition) {
998 childLayer->setStaticBlockPosition(staticBlockPosition);
999 if (child.style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
1000 child.setChildNeedsLayout(MarkOnlyThis);
1004 ItemPosition RenderFlexibleBox::alignmentForChild(RenderBox& child) const
1006 ItemPosition align = RenderStyle::resolveAlignment(style(), child.style(), ItemPositionStretch);
1008 if (align == ItemPositionBaseline && hasOrthogonalFlow(child))
1009 align = ItemPositionFlexStart;
1011 if (style()->flexWrap() == FlexWrapReverse) {
1012 if (align == ItemPositionFlexStart)
1013 align = ItemPositionFlexEnd;
1014 else if (align == ItemPositionFlexEnd)
1015 align = ItemPositionFlexStart;
1021 size_t RenderFlexibleBox::numberOfInFlowPositionedChildren(const OrderedFlexItemList& children) const
1024 for (size_t i = 0; i < children.size(); ++i) {
1025 RenderBox* child = children[i];
1026 if (!child->isOutOfFlowPositioned())
1032 void RenderFlexibleBox::resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox& child)
1034 if (hasAutoMarginsInCrossAxis(child)) {
1035 child.updateLogicalHeight();
1036 if (isHorizontalFlow()) {
1037 if (child.style()->marginTop().isAuto())
1038 child.setMarginTop(0);
1039 if (child.style()->marginBottom().isAuto())
1040 child.setMarginBottom(0);
1042 if (child.style()->marginLeft().isAuto())
1043 child.setMarginLeft(0);
1044 if (child.style()->marginRight().isAuto())
1045 child.setMarginRight(0);
1050 bool RenderFlexibleBox::needToStretchChildLogicalHeight(RenderBox& child) const
1052 if (alignmentForChild(child) != ItemPositionStretch)
1055 return isHorizontalFlow() && child.style()->height().isAuto();
1058 void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const Vector<LayoutUnit, 16>& childSizes, LayoutUnit availableFreeSpace, bool relayoutChildren, Vector<LineContext>& lineContexts, bool hasInfiniteLineLength)
1060 ASSERT(childSizes.size() == children.size());
1062 size_t numberOfChildrenForJustifyContent = numberOfInFlowPositionedChildren(children);
1063 LayoutUnit autoMarginOffset = autoMarginOffsetInMainAxis(children, availableFreeSpace);
1064 LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart();
1065 mainAxisOffset += initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), style()->justifyContentDistribution(), numberOfChildrenForJustifyContent);
1066 if (style()->flexDirection() == FlowRowReverse)
1067 mainAxisOffset += isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1069 LayoutUnit totalMainExtent = mainAxisExtent();
1070 LayoutUnit maxAscent = 0, maxDescent = 0; // Used when align-items: baseline.
1071 LayoutUnit maxChildCrossAxisExtent = 0;
1072 size_t seenInFlowPositionedChildren = 0;
1073 bool shouldFlipMainAxis = !isColumnFlow() && !isLeftToRightFlow();
1074 for (size_t i = 0; i < children.size(); ++i) {
1075 RenderBox* child = children[i];
1077 if (child->isOutOfFlowPositioned()) {
1078 prepareChildForPositionedLayout(*child, mainAxisOffset, crossAxisOffset, FlipForRowReverse);
1082 // FIXME Investigate if this can be removed based on other flags. crbug.com/370010
1083 child->setMayNeedPaintInvalidation(true);
1085 LayoutUnit childPreferredSize = childSizes[i] + mainAxisBorderAndPaddingExtentForChild(*child);
1086 setLogicalOverrideSize(*child, childPreferredSize);
1087 if (childPreferredSize != mainAxisExtentForChild(*child)) {
1088 child->setChildNeedsLayout(MarkOnlyThis);
1090 // To avoid double applying margin changes in updateAutoMarginsInCrossAxis, we reset the margins here.
1091 resetAutoMarginsAndLogicalTopInCrossAxis(*child);
1093 // We may have already forced relayout for orthogonal flowing children in preferredMainAxisContentExtentForChild.
1094 bool forceChildRelayout = relayoutChildren && !childPreferredMainAxisContentExtentRequiresLayout(*child, hasInfiniteLineLength);
1095 updateBlockChildDirtyBitsBeforeLayout(forceChildRelayout, child);
1096 child->layoutIfNeeded();
1098 updateAutoMarginsInMainAxis(*child, autoMarginOffset);
1100 LayoutUnit childCrossAxisMarginBoxExtent;
1101 if (alignmentForChild(*child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(*child)) {
1102 LayoutUnit ascent = marginBoxAscentForChild(*child);
1103 LayoutUnit descent = (crossAxisMarginExtentForChild(*child) + crossAxisExtentForChild(*child)) - ascent;
1105 maxAscent = std::max(maxAscent, ascent);
1106 maxDescent = std::max(maxDescent, descent);
1108 childCrossAxisMarginBoxExtent = maxAscent + maxDescent;
1110 childCrossAxisMarginBoxExtent = crossAxisIntrinsicExtentForChild(*child) + crossAxisMarginExtentForChild(*child) + crossAxisScrollbarExtentForChild(*child);
1112 if (!isColumnFlow())
1113 setLogicalHeight(std::max(logicalHeight(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent()));
1114 maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisMarginBoxExtent);
1116 mainAxisOffset += flowAwareMarginStartForChild(*child);
1118 LayoutUnit childMainExtent = mainAxisExtentForChild(*child);
1119 // In an RTL column situation, this will apply the margin-right/margin-end on the left.
1120 // This will be fixed later in flipForRightToLeftColumn.
1121 LayoutPoint childLocation(shouldFlipMainAxis ? totalMainExtent - mainAxisOffset - childMainExtent : mainAxisOffset,
1122 crossAxisOffset + flowAwareMarginBeforeForChild(*child));
1124 // FIXME: Supporting layout deltas.
1125 setFlowAwareLocationForChild(*child, childLocation);
1126 mainAxisOffset += childMainExtent + flowAwareMarginEndForChild(*child);
1128 ++seenInFlowPositionedChildren;
1129 if (seenInFlowPositionedChildren < numberOfChildrenForJustifyContent)
1130 mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContentDistribution(), numberOfChildrenForJustifyContent);
1134 setLogicalHeight(mainAxisOffset + flowAwareBorderEnd() + flowAwarePaddingEnd() + scrollbarLogicalHeight());
1136 if (style()->flexDirection() == FlowColumnReverse) {
1137 // We have to do an extra pass for column-reverse to reposition the flex items since the start depends
1138 // on the height of the flexbox, which we only know after we've positioned all the flex items.
1139 updateLogicalHeight();
1140 layoutColumnReverse(children, crossAxisOffset, availableFreeSpace);
1143 if (m_numberOfInFlowChildrenOnFirstLine == -1)
1144 m_numberOfInFlowChildrenOnFirstLine = seenInFlowPositionedChildren;
1145 lineContexts.append(LineContext(crossAxisOffset, maxChildCrossAxisExtent, children.size(), maxAscent));
1146 crossAxisOffset += maxChildCrossAxisExtent;
1149 void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace)
1151 // This is similar to the logic in layoutAndPlaceChildren, except we place the children
1152 // starting from the end of the flexbox. We also don't need to layout anything since we're
1153 // just moving the children to a new position.
1154 size_t numberOfChildrenForJustifyContent = numberOfInFlowPositionedChildren(children);
1155 LayoutUnit mainAxisOffset = logicalHeight() - flowAwareBorderEnd() - flowAwarePaddingEnd();
1156 mainAxisOffset -= initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), style()->justifyContentDistribution(), numberOfChildrenForJustifyContent);
1157 mainAxisOffset -= isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1159 size_t seenInFlowPositionedChildren = 0;
1160 for (size_t i = 0; i < children.size(); ++i) {
1161 RenderBox* child = children[i];
1163 if (child->isOutOfFlowPositioned()) {
1164 child->layer()->setStaticBlockPosition(mainAxisOffset);
1167 mainAxisOffset -= mainAxisExtentForChild(*child) + flowAwareMarginEndForChild(*child);
1169 setFlowAwareLocationForChild(*child, LayoutPoint(mainAxisOffset, crossAxisOffset + flowAwareMarginBeforeForChild(*child)));
1171 mainAxisOffset -= flowAwareMarginStartForChild(*child);
1173 ++seenInFlowPositionedChildren;
1174 if (seenInFlowPositionedChildren < numberOfChildrenForJustifyContent)
1175 mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContentDistribution(), numberOfChildrenForJustifyContent);
1179 static LayoutUnit initialAlignContentOffset(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1181 if (numberOfLines <= 1)
1183 if (alignContent == AlignContentFlexEnd)
1184 return availableFreeSpace;
1185 if (alignContent == AlignContentCenter)
1186 return availableFreeSpace / 2;
1187 if (alignContent == AlignContentSpaceAround) {
1188 if (availableFreeSpace > 0 && numberOfLines)
1189 return availableFreeSpace / (2 * numberOfLines);
1190 if (availableFreeSpace < 0)
1191 return availableFreeSpace / 2;
1196 static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1198 if (availableFreeSpace > 0 && numberOfLines > 1) {
1199 if (alignContent == AlignContentSpaceBetween)
1200 return availableFreeSpace / (numberOfLines - 1);
1201 if (alignContent == AlignContentSpaceAround || alignContent == AlignContentStretch)
1202 return availableFreeSpace / numberOfLines;
1207 void RenderFlexibleBox::alignFlexLines(Vector<LineContext>& lineContexts)
1209 // If we have a single line flexbox or a multiline line flexbox with only one flex line,
1210 // the line height is all the available space.
1211 // For flex-direction: row, this means we need to use the height, so we do this after calling updateLogicalHeight.
1212 if (lineContexts.size() == 1) {
1213 lineContexts[0].crossAxisExtent = crossAxisContentExtent();
1217 if (style()->alignContent() == AlignContentFlexStart)
1220 LayoutUnit availableCrossAxisSpace = crossAxisContentExtent();
1221 for (size_t i = 0; i < lineContexts.size(); ++i)
1222 availableCrossAxisSpace -= lineContexts[i].crossAxisExtent;
1224 RenderBox* child = m_orderIterator.first();
1225 LayoutUnit lineOffset = initialAlignContentOffset(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1226 for (unsigned lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1227 lineContexts[lineNumber].crossAxisOffset += lineOffset;
1228 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next())
1229 adjustAlignmentForChild(*child, lineOffset);
1231 if (style()->alignContent() == AlignContentStretch && availableCrossAxisSpace > 0)
1232 lineContexts[lineNumber].crossAxisExtent += availableCrossAxisSpace / static_cast<unsigned>(lineContexts.size());
1234 lineOffset += alignContentSpaceBetweenChildren(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1238 void RenderFlexibleBox::adjustAlignmentForChild(RenderBox& child, LayoutUnit delta)
1240 if (child.isOutOfFlowPositioned()) {
1241 LayoutUnit staticInlinePosition = child.layer()->staticInlinePosition();
1242 LayoutUnit staticBlockPosition = child.layer()->staticBlockPosition();
1243 LayoutUnit mainAxis = isColumnFlow() ? staticBlockPosition : staticInlinePosition;
1244 LayoutUnit crossAxis = isColumnFlow() ? staticInlinePosition : staticBlockPosition;
1246 prepareChildForPositionedLayout(child, mainAxis, crossAxis, NoFlipForRowReverse);
1250 setFlowAwareLocationForChild(child, flowAwareLocationForChild(child) + LayoutSize(0, delta));
1253 void RenderFlexibleBox::alignChildren(const Vector<LineContext>& lineContexts)
1255 // Keep track of the space between the baseline edge and the after edge of the box for each line.
1256 Vector<LayoutUnit> minMarginAfterBaselines;
1258 RenderBox* child = m_orderIterator.first();
1259 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1260 LayoutUnit minMarginAfterBaseline = LayoutUnit::max();
1261 LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1262 LayoutUnit maxAscent = lineContexts[lineNumber].maxAscent;
1264 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
1266 if (child->isOutOfFlowPositioned()) {
1267 if (style()->flexWrap() == FlexWrapReverse)
1268 adjustAlignmentForChild(*child, lineCrossAxisExtent);
1272 if (updateAutoMarginsInCrossAxis(*child, std::max(LayoutUnit(0), availableAlignmentSpaceForChild(lineCrossAxisExtent, *child))))
1275 switch (alignmentForChild(*child)) {
1276 case ItemPositionAuto:
1277 ASSERT_NOT_REACHED();
1279 case ItemPositionStretch: {
1280 applyStretchAlignmentToChild(*child, lineCrossAxisExtent);
1281 // Since wrap-reverse flips cross start and cross end, strech children should be aligned with the cross end.
1282 if (style()->flexWrap() == FlexWrapReverse)
1283 adjustAlignmentForChild(*child, availableAlignmentSpaceForChild(lineCrossAxisExtent, *child));
1286 case ItemPositionFlexStart:
1288 case ItemPositionFlexEnd:
1289 adjustAlignmentForChild(*child, availableAlignmentSpaceForChild(lineCrossAxisExtent, *child));
1291 case ItemPositionCenter:
1292 adjustAlignmentForChild(*child, availableAlignmentSpaceForChild(lineCrossAxisExtent, *child) / 2);
1294 case ItemPositionBaseline: {
1295 // 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.
1296 // https://bugs.webkit.org/show_bug.cgi?id=98076
1297 LayoutUnit ascent = marginBoxAscentForChild(*child);
1298 LayoutUnit startOffset = maxAscent - ascent;
1299 adjustAlignmentForChild(*child, startOffset);
1301 if (style()->flexWrap() == FlexWrapReverse)
1302 minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, *child) - startOffset);
1305 case ItemPositionLastBaseline:
1306 case ItemPositionSelfStart:
1307 case ItemPositionSelfEnd:
1308 case ItemPositionStart:
1309 case ItemPositionEnd:
1310 case ItemPositionLeft:
1311 case ItemPositionRight:
1312 // FIXME: File a bug about implementing that. The extended grammar
1313 // is not enabled by default so we shouldn't hit this codepath.
1314 ASSERT_NOT_REACHED();
1318 minMarginAfterBaselines.append(minMarginAfterBaseline);
1321 if (style()->flexWrap() != FlexWrapReverse)
1324 // wrap-reverse flips the cross axis start and end. For baseline alignment, this means we
1325 // need to align the after edge of baseline elements with the after edge of the flex line.
1326 child = m_orderIterator.first();
1327 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1328 LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber];
1329 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
1331 if (alignmentForChild(*child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(*child) && minMarginAfterBaseline)
1332 adjustAlignmentForChild(*child, minMarginAfterBaseline);
1337 void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox& child, LayoutUnit lineCrossAxisExtent)
1339 if (!isColumnFlow() && child.style()->logicalHeight().isAuto()) {
1340 // FIXME: If the child has orthogonal flow, then it already has an override height set, so use it.
1341 if (!hasOrthogonalFlow(child)) {
1342 LayoutUnit heightBeforeStretching = needToStretchChildLogicalHeight(child) ? constrainedChildIntrinsicContentLogicalHeight(child) : child.logicalHeight();
1343 LayoutUnit stretchedLogicalHeight = heightBeforeStretching + availableAlignmentSpaceForChildBeforeStretching(lineCrossAxisExtent, child);
1344 ASSERT(!child.needsLayout());
1345 LayoutUnit desiredLogicalHeight = child.constrainLogicalHeightByMinMax(stretchedLogicalHeight, heightBeforeStretching - child.borderAndPaddingLogicalHeight());
1347 // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
1348 bool childNeedsRelayout = desiredLogicalHeight != child.logicalHeight();
1349 if (childNeedsRelayout || !child.hasOverrideHeight())
1350 child.setOverrideLogicalContentHeight(desiredLogicalHeight - child.borderAndPaddingLogicalHeight());
1351 if (childNeedsRelayout) {
1352 child.setLogicalHeight(0);
1353 // We cache the child's intrinsic content logical height to avoid it being reset to the stretched height.
1354 // FIXME: This is fragile. RenderBoxes should be smart enough to determine their intrinsic content logical
1355 // height correctly even when there's an overrideHeight.
1356 LayoutUnit childIntrinsicContentLogicalHeight = child.intrinsicContentLogicalHeight();
1357 child.forceChildLayout();
1358 child.updateIntrinsicContentLogicalHeight(childIntrinsicContentLogicalHeight);
1361 } else if (isColumnFlow() && child.style()->logicalWidth().isAuto()) {
1362 // FIXME: If the child doesn't have orthogonal flow, then it already has an override width set, so use it.
1363 if (hasOrthogonalFlow(child)) {
1364 LayoutUnit childWidth = std::max<LayoutUnit>(0, lineCrossAxisExtent - crossAxisMarginExtentForChild(child));
1365 childWidth = child.constrainLogicalWidthByMinMax(childWidth, childWidth, this);
1367 if (childWidth != child.logicalWidth()) {
1368 child.setOverrideLogicalContentWidth(childWidth - child.borderAndPaddingLogicalWidth());
1369 child.forceChildLayout();
1375 void RenderFlexibleBox::flipForRightToLeftColumn()
1377 if (style()->isLeftToRightDirection() || !isColumnFlow())
1380 LayoutUnit crossExtent = crossAxisExtent();
1381 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
1382 if (child->isOutOfFlowPositioned())
1384 LayoutPoint location = flowAwareLocationForChild(*child);
1385 // For vertical flows, setFlowAwareLocationForChild will transpose x and y,
1386 // so using the y axis for a column cross axis extent is correct.
1387 location.setY(crossExtent - crossAxisExtentForChild(*child) - location.y());
1388 setFlowAwareLocationForChild(*child, location);
1392 void RenderFlexibleBox::flipForWrapReverse(const Vector<LineContext>& lineContexts, LayoutUnit crossAxisStartEdge)
1394 LayoutUnit contentExtent = crossAxisContentExtent();
1395 RenderBox* child = m_orderIterator.first();
1396 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1397 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
1399 LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1400 LayoutUnit originalOffset = lineContexts[lineNumber].crossAxisOffset - crossAxisStartEdge;
1401 LayoutUnit newOffset = contentExtent - originalOffset - lineCrossAxisExtent;
1402 adjustAlignmentForChild(*child, newOffset - originalOffset);