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/rendering/LayoutRectRecorder.h"
35 #include "core/rendering/LayoutRepainter.h"
36 #include "core/rendering/RenderLayer.h"
37 #include "core/rendering/RenderView.h"
38 #include "platform/LengthFunctions.h"
39 #include "wtf/MathExtras.h"
44 struct RenderFlexibleBox::LineContext {
45 LineContext(LayoutUnit crossAxisOffset, LayoutUnit crossAxisExtent, size_t numberOfChildren, LayoutUnit maxAscent)
46 : crossAxisOffset(crossAxisOffset)
47 , crossAxisExtent(crossAxisExtent)
48 , numberOfChildren(numberOfChildren)
49 , maxAscent(maxAscent)
53 LayoutUnit crossAxisOffset;
54 LayoutUnit crossAxisExtent;
55 size_t numberOfChildren;
59 struct RenderFlexibleBox::Violation {
60 Violation(RenderBox* child, LayoutUnit childSize)
62 , childSize(childSize)
71 RenderFlexibleBox::RenderFlexibleBox(Element* element)
72 : RenderBlock(element)
73 , m_orderIterator(this)
74 , m_numberOfInFlowChildrenOnFirstLine(-1)
76 setChildrenInline(false); // All of our children must be block-level.
79 RenderFlexibleBox::~RenderFlexibleBox()
83 RenderFlexibleBox* RenderFlexibleBox::createAnonymous(Document* document)
85 RenderFlexibleBox* renderer = new RenderFlexibleBox(0);
86 renderer->setDocumentForAnonymous(document);
90 const char* RenderFlexibleBox::renderName() const
92 return "RenderFlexibleBox";
95 void RenderFlexibleBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
97 // FIXME: We're ignoring flex-basis here and we shouldn't. We can't start honoring it though until
98 // the flex shorthand stops setting it to 0.
99 // See https://bugs.webkit.org/show_bug.cgi?id=116117 and http://crbug.com/240765.
100 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
101 if (child->isOutOfFlowPositioned())
104 LayoutUnit margin = marginIntrinsicLogicalWidthForChild(child);
105 bool hasOrthogonalWritingMode = child->isHorizontalWritingMode() != isHorizontalWritingMode();
106 LayoutUnit minPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->minPreferredLogicalWidth();
107 LayoutUnit maxPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->maxPreferredLogicalWidth();
108 minPreferredLogicalWidth += margin;
109 maxPreferredLogicalWidth += margin;
110 if (!isColumnFlow()) {
111 maxLogicalWidth += maxPreferredLogicalWidth;
113 // For multiline, the min preferred width is if you put a break between each item.
114 minLogicalWidth = std::max(minLogicalWidth, minPreferredLogicalWidth);
116 minLogicalWidth += minPreferredLogicalWidth;
118 minLogicalWidth = std::max(minPreferredLogicalWidth, minLogicalWidth);
120 // For multiline, the max preferred width is if you never break between items.
121 maxLogicalWidth += maxPreferredLogicalWidth;
123 maxLogicalWidth = std::max(maxPreferredLogicalWidth, maxLogicalWidth);
127 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
129 LayoutUnit scrollbarWidth = instrinsicScrollbarLogicalWidth();
130 maxLogicalWidth += scrollbarWidth;
131 minLogicalWidth += scrollbarWidth;
134 static int synthesizedBaselineFromContentBox(const RenderBox* box, LineDirectionMode direction)
136 return direction == HorizontalLine ? box->borderTop() + box->paddingTop() + box->contentHeight() : box->borderRight() + box->paddingRight() + box->contentWidth();
139 int RenderFlexibleBox::baselinePosition(FontBaseline, bool, LineDirectionMode direction, LinePositionMode mode) const
141 ASSERT(mode == PositionOnContainingLine);
142 int baseline = firstLineBoxBaseline();
144 baseline = synthesizedBaselineFromContentBox(this, direction);
146 return beforeMarginInLineDirection(direction) + baseline;
149 int RenderFlexibleBox::firstLineBoxBaseline() const
151 if (isWritingModeRoot() || m_numberOfInFlowChildrenOnFirstLine <= 0)
153 RenderBox* baselineChild = 0;
155 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
156 if (child->isOutOfFlowPositioned())
158 if (alignmentForChild(child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(child)) {
159 baselineChild = child;
163 baselineChild = child;
166 if (childNumber == m_numberOfInFlowChildrenOnFirstLine)
173 if (!isColumnFlow() && hasOrthogonalFlow(baselineChild))
174 return crossAxisExtentForChild(baselineChild) + baselineChild->logicalTop();
175 if (isColumnFlow() && !hasOrthogonalFlow(baselineChild))
176 return mainAxisExtentForChild(baselineChild) + baselineChild->logicalTop();
178 int baseline = baselineChild->firstLineBoxBaseline();
179 if (baseline == -1) {
180 // FIXME: We should pass |direction| into firstLineBoxBaseline and stop bailing out if we're a writing mode root.
181 // This would also fix some cases where the flexbox is orthogonal to its container.
182 LineDirectionMode direction = isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
183 return synthesizedBaselineFromContentBox(baselineChild, direction) + baselineChild->logicalTop();
186 return baseline + baselineChild->logicalTop();
189 int RenderFlexibleBox::inlineBlockBaseline(LineDirectionMode direction) const
191 int baseline = firstLineBoxBaseline();
195 int marginAscent = direction == HorizontalLine ? marginTop() : marginRight();
196 return synthesizedBaselineFromContentBox(this, direction) + marginAscent;
199 static ItemPosition resolveAlignment(const RenderStyle* parentStyle, const RenderStyle* childStyle)
201 ItemPosition align = childStyle->alignSelf();
202 if (align == ItemPositionAuto)
203 align = parentStyle->alignItems();
207 void RenderFlexibleBox::removeChild(RenderObject* child)
209 RenderBlock::removeChild(child);
210 m_intrinsicSizeAlongMainAxis.remove(child);
213 void RenderFlexibleBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
215 RenderBlock::styleDidChange(diff, oldStyle);
217 if (oldStyle && oldStyle->alignItems() == ItemPositionStretch && diff == StyleDifferenceLayout) {
218 // Flex items that were previously stretching need to be relayed out so we can compute new available cross axis space.
219 // This is only necessary for stretching since other alignment values don't change the size of the box.
220 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
221 ItemPosition previousAlignment = resolveAlignment(oldStyle, child->style());
222 if (previousAlignment == ItemPositionStretch && previousAlignment != resolveAlignment(style(), child->style()))
223 child->setChildNeedsLayout(MarkOnlyThis);
228 void RenderFlexibleBox::layoutBlock(bool relayoutChildren)
230 ASSERT(needsLayout());
232 if (!relayoutChildren && simplifiedLayout())
235 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
236 LayoutRectRecorder recorder(*this);
238 if (updateLogicalWidthAndColumnWidth())
239 relayoutChildren = true;
241 LayoutUnit previousHeight = logicalHeight();
242 setLogicalHeight(borderAndPaddingLogicalHeight() + scrollbarLogicalHeight());
245 LayoutStateMaintainer statePusher(*this, locationOffset());
247 m_numberOfInFlowChildrenOnFirstLine = -1;
249 RenderBlock::startDelayUpdateScrollInfo();
251 prepareOrderIteratorAndMargins();
253 ChildFrameRects oldChildRects;
254 appendChildFrameRects(oldChildRects);
256 layoutFlexItems(relayoutChildren);
258 RenderBlock::finishDelayUpdateScrollInfo();
260 if (logicalHeight() != previousHeight)
261 relayoutChildren = true;
263 layoutPositionedObjects(relayoutChildren || isRoot());
265 computeRegionRangeForBlock(flowThreadContainingBlock());
267 repaintChildrenDuringLayoutIfMoved(oldChildRects);
268 // FIXME: css3/flexbox/repaint-rtl-column.html seems to repaint more overflow than it needs to.
269 computeOverflow(clientLogicalBottomAfterRepositioning());
272 updateLayerTransform();
274 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
275 // we overflow or not.
276 updateScrollInfoAfterLayout();
278 repainter.repaintAfterLayout();
283 void RenderFlexibleBox::appendChildFrameRects(ChildFrameRects& childFrameRects)
285 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
286 if (!child->isOutOfFlowPositioned())
287 childFrameRects.append(child->frameRect());
291 void RenderFlexibleBox::repaintChildrenDuringLayoutIfMoved(const ChildFrameRects& oldChildRects)
293 size_t childIndex = 0;
294 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
295 if (child->isOutOfFlowPositioned())
298 // If the child moved, we have to repaint it as well as any floating/positioned
299 // descendants. An exception is if we need a layout. In this case, we know we're going to
300 // repaint ourselves (and the child) anyway.
301 if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
302 child->repaintDuringLayoutIfMoved(oldChildRects[childIndex]);
305 ASSERT(childIndex == oldChildRects.size());
308 void RenderFlexibleBox::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
310 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next())
311 paintChildAsInlineBlock(child, paintInfo, paintOffset);
314 void RenderFlexibleBox::repositionLogicalHeightDependentFlexItems(Vector<LineContext>& lineContexts)
316 LayoutUnit crossAxisStartEdge = lineContexts.isEmpty() ? LayoutUnit() : lineContexts[0].crossAxisOffset;
317 alignFlexLines(lineContexts);
319 // If we have a single line flexbox, the line height is all the available space.
320 // For flex-direction: row, this means we need to use the height, so we do this after calling updateLogicalHeight.
321 if (!isMultiline() && lineContexts.size() == 1)
322 lineContexts[0].crossAxisExtent = crossAxisContentExtent();
323 alignChildren(lineContexts);
325 if (style()->flexWrap() == FlexWrapReverse)
326 flipForWrapReverse(lineContexts, crossAxisStartEdge);
328 // direction:rtl + flex-direction:column means the cross-axis direction is flipped.
329 flipForRightToLeftColumn();
332 LayoutUnit RenderFlexibleBox::clientLogicalBottomAfterRepositioning()
334 LayoutUnit maxChildLogicalBottom = 0;
335 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
336 if (child->isOutOfFlowPositioned())
338 LayoutUnit childLogicalBottom = logicalTopForChild(child) + logicalHeightForChild(child) + marginAfterForChild(child);
339 maxChildLogicalBottom = std::max(maxChildLogicalBottom, childLogicalBottom);
341 return std::max(clientLogicalBottom(), maxChildLogicalBottom + paddingAfter());
344 bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox* child) const
346 // FIXME: If the child is a flexbox, then we need to check isHorizontalFlow.
347 return isHorizontalFlow() != child->isHorizontalWritingMode();
350 bool RenderFlexibleBox::isColumnFlow() const
352 return style()->isColumnFlexDirection();
355 bool RenderFlexibleBox::isHorizontalFlow() const
357 if (isHorizontalWritingMode())
358 return !isColumnFlow();
359 return isColumnFlow();
362 bool RenderFlexibleBox::isLeftToRightFlow() const
365 return style()->writingMode() == TopToBottomWritingMode || style()->writingMode() == LeftToRightWritingMode;
366 return style()->isLeftToRightDirection() ^ (style()->flexDirection() == FlowRowReverse);
369 bool RenderFlexibleBox::isMultiline() const
371 return style()->flexWrap() != FlexNoWrap;
374 Length RenderFlexibleBox::flexBasisForChild(RenderBox* child) const
376 Length flexLength = child->style()->flexBasis();
377 if (flexLength.isAuto())
378 flexLength = isHorizontalFlow() ? child->style()->width() : child->style()->height();
382 void RenderFlexibleBox::setCrossAxisExtent(LayoutUnit extent)
384 if (isHorizontalFlow())
390 LayoutUnit RenderFlexibleBox::crossAxisExtentForChild(RenderBox* child) const
392 return isHorizontalFlow() ? child->height() : child->width();
395 static inline LayoutUnit constrainedChildIntrinsicContentLogicalHeight(RenderBox* child)
397 LayoutUnit childIntrinsicContentLogicalHeight = child->intrinsicContentLogicalHeight();
398 return child->constrainLogicalHeightByMinMax(childIntrinsicContentLogicalHeight + child->borderAndPaddingLogicalHeight(), childIntrinsicContentLogicalHeight);
401 LayoutUnit RenderFlexibleBox::childIntrinsicHeight(RenderBox* child) const
403 if (child->isHorizontalWritingMode() && needToStretchChildLogicalHeight(child))
404 return constrainedChildIntrinsicContentLogicalHeight(child);
405 return child->height();
408 LayoutUnit RenderFlexibleBox::childIntrinsicWidth(RenderBox* child) const
410 if (!child->isHorizontalWritingMode() && needToStretchChildLogicalHeight(child))
411 return constrainedChildIntrinsicContentLogicalHeight(child);
412 return child->width();
415 LayoutUnit RenderFlexibleBox::crossAxisIntrinsicExtentForChild(RenderBox* child) const
417 return isHorizontalFlow() ? childIntrinsicHeight(child) : childIntrinsicWidth(child);
420 LayoutUnit RenderFlexibleBox::mainAxisExtentForChild(RenderBox* child) const
422 return isHorizontalFlow() ? child->width() : child->height();
425 LayoutUnit RenderFlexibleBox::crossAxisExtent() const
427 return isHorizontalFlow() ? height() : width();
430 LayoutUnit RenderFlexibleBox::mainAxisExtent() const
432 return isHorizontalFlow() ? width() : height();
435 LayoutUnit RenderFlexibleBox::crossAxisContentExtent() const
437 return isHorizontalFlow() ? contentHeight() : contentWidth();
440 LayoutUnit RenderFlexibleBox::mainAxisContentExtent(LayoutUnit contentLogicalHeight)
442 if (isColumnFlow()) {
443 LogicalExtentComputedValues computedValues;
444 LayoutUnit borderPaddingAndScrollbar = borderAndPaddingLogicalHeight() + scrollbarLogicalHeight();
445 // FIXME: Remove this std:max once we enable saturated layout arithmetic. It's just here to handle overflow.
446 LayoutUnit borderBoxLogicalHeight = std::max(contentLogicalHeight, contentLogicalHeight + borderPaddingAndScrollbar);
447 computeLogicalHeight(borderBoxLogicalHeight, logicalTop(), computedValues);
448 if (computedValues.m_extent == LayoutUnit::max())
449 return computedValues.m_extent;
450 return std::max(LayoutUnit(0), computedValues.m_extent - borderPaddingAndScrollbar);
452 return contentLogicalWidth();
455 LayoutUnit RenderFlexibleBox::computeMainAxisExtentForChild(RenderBox* child, SizeType sizeType, const Length& size)
457 // FIXME: This is wrong for orthogonal flows. It should use the flexbox's writing-mode, not the child's in order
458 // to figure out the logical height/width.
459 if (isColumnFlow()) {
460 // We don't have to check for "auto" here - computeContentLogicalHeight will just return -1 for that case anyway.
461 if (size.isIntrinsic())
462 child->layoutIfNeeded();
463 return child->computeContentLogicalHeight(size, child->logicalHeight() - child->borderAndPaddingLogicalHeight());
465 return child->computeLogicalWidthUsing(sizeType, size, contentLogicalWidth(), this) - child->borderAndPaddingLogicalWidth();
468 WritingMode RenderFlexibleBox::transformedWritingMode() const
470 WritingMode mode = style()->writingMode();
475 case TopToBottomWritingMode:
476 case BottomToTopWritingMode:
477 return style()->isLeftToRightDirection() ? LeftToRightWritingMode : RightToLeftWritingMode;
478 case LeftToRightWritingMode:
479 case RightToLeftWritingMode:
480 return style()->isLeftToRightDirection() ? TopToBottomWritingMode : BottomToTopWritingMode;
482 ASSERT_NOT_REACHED();
483 return TopToBottomWritingMode;
486 LayoutUnit RenderFlexibleBox::flowAwareBorderStart() const
488 if (isHorizontalFlow())
489 return isLeftToRightFlow() ? borderLeft() : borderRight();
490 return isLeftToRightFlow() ? borderTop() : borderBottom();
493 LayoutUnit RenderFlexibleBox::flowAwareBorderEnd() const
495 if (isHorizontalFlow())
496 return isLeftToRightFlow() ? borderRight() : borderLeft();
497 return isLeftToRightFlow() ? borderBottom() : borderTop();
500 LayoutUnit RenderFlexibleBox::flowAwareBorderBefore() const
502 switch (transformedWritingMode()) {
503 case TopToBottomWritingMode:
505 case BottomToTopWritingMode:
506 return borderBottom();
507 case LeftToRightWritingMode:
509 case RightToLeftWritingMode:
510 return borderRight();
512 ASSERT_NOT_REACHED();
516 LayoutUnit RenderFlexibleBox::flowAwareBorderAfter() const
518 switch (transformedWritingMode()) {
519 case TopToBottomWritingMode:
520 return borderBottom();
521 case BottomToTopWritingMode:
523 case LeftToRightWritingMode:
524 return borderRight();
525 case RightToLeftWritingMode:
528 ASSERT_NOT_REACHED();
532 LayoutUnit RenderFlexibleBox::flowAwarePaddingStart() const
534 if (isHorizontalFlow())
535 return isLeftToRightFlow() ? paddingLeft() : paddingRight();
536 return isLeftToRightFlow() ? paddingTop() : paddingBottom();
539 LayoutUnit RenderFlexibleBox::flowAwarePaddingEnd() const
541 if (isHorizontalFlow())
542 return isLeftToRightFlow() ? paddingRight() : paddingLeft();
543 return isLeftToRightFlow() ? paddingBottom() : paddingTop();
546 LayoutUnit RenderFlexibleBox::flowAwarePaddingBefore() const
548 switch (transformedWritingMode()) {
549 case TopToBottomWritingMode:
551 case BottomToTopWritingMode:
552 return paddingBottom();
553 case LeftToRightWritingMode:
554 return paddingLeft();
555 case RightToLeftWritingMode:
556 return paddingRight();
558 ASSERT_NOT_REACHED();
562 LayoutUnit RenderFlexibleBox::flowAwarePaddingAfter() const
564 switch (transformedWritingMode()) {
565 case TopToBottomWritingMode:
566 return paddingBottom();
567 case BottomToTopWritingMode:
569 case LeftToRightWritingMode:
570 return paddingRight();
571 case RightToLeftWritingMode:
572 return paddingLeft();
574 ASSERT_NOT_REACHED();
578 LayoutUnit RenderFlexibleBox::flowAwareMarginStartForChild(RenderBox* child) const
580 if (isHorizontalFlow())
581 return isLeftToRightFlow() ? child->marginLeft() : child->marginRight();
582 return isLeftToRightFlow() ? child->marginTop() : child->marginBottom();
585 LayoutUnit RenderFlexibleBox::flowAwareMarginEndForChild(RenderBox* child) const
587 if (isHorizontalFlow())
588 return isLeftToRightFlow() ? child->marginRight() : child->marginLeft();
589 return isLeftToRightFlow() ? child->marginBottom() : child->marginTop();
592 LayoutUnit RenderFlexibleBox::flowAwareMarginBeforeForChild(RenderBox* child) const
594 switch (transformedWritingMode()) {
595 case TopToBottomWritingMode:
596 return child->marginTop();
597 case BottomToTopWritingMode:
598 return child->marginBottom();
599 case LeftToRightWritingMode:
600 return child->marginLeft();
601 case RightToLeftWritingMode:
602 return child->marginRight();
604 ASSERT_NOT_REACHED();
608 LayoutUnit RenderFlexibleBox::flowAwareMarginAfterForChild(RenderBox* child) const
610 switch (transformedWritingMode()) {
611 case TopToBottomWritingMode:
612 return child->marginBottom();
613 case BottomToTopWritingMode:
614 return child->marginTop();
615 case LeftToRightWritingMode:
616 return child->marginRight();
617 case RightToLeftWritingMode:
618 return child->marginLeft();
620 ASSERT_NOT_REACHED();
621 return marginBottom();
624 LayoutUnit RenderFlexibleBox::crossAxisMarginExtentForChild(RenderBox* child) const
626 return isHorizontalFlow() ? child->marginHeight() : child->marginWidth();
629 LayoutUnit RenderFlexibleBox::crossAxisScrollbarExtent() const
631 return isHorizontalFlow() ? horizontalScrollbarHeight() : verticalScrollbarWidth();
634 LayoutPoint RenderFlexibleBox::flowAwareLocationForChild(RenderBox* child) const
636 return isHorizontalFlow() ? child->location() : child->location().transposedPoint();
639 void RenderFlexibleBox::setFlowAwareLocationForChild(RenderBox* child, const LayoutPoint& location)
641 if (isHorizontalFlow())
642 child->setLocation(location);
644 child->setLocation(location.transposedPoint());
647 LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox* child) const
649 return isHorizontalFlow() ? child->borderAndPaddingWidth() : child->borderAndPaddingHeight();
652 LayoutUnit RenderFlexibleBox::mainAxisScrollbarExtentForChild(RenderBox* child) const
654 return isHorizontalFlow() ? child->verticalScrollbarWidth() : child->horizontalScrollbarHeight();
657 static inline bool preferredMainAxisExtentDependsOnLayout(const Length& flexBasis, bool hasInfiniteLineLength)
659 return flexBasis.isAuto() || (flexBasis.isFixed() && !flexBasis.value() && hasInfiniteLineLength);
662 bool RenderFlexibleBox::childPreferredMainAxisContentExtentRequiresLayout(RenderBox* child, bool hasInfiniteLineLength) const
664 return preferredMainAxisExtentDependsOnLayout(flexBasisForChild(child), hasInfiniteLineLength) && hasOrthogonalFlow(child);
667 LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* child, bool hasInfiniteLineLength, bool relayoutChildren)
669 child->clearOverrideSize();
671 Length flexBasis = flexBasisForChild(child);
672 if (preferredMainAxisExtentDependsOnLayout(flexBasis, hasInfiniteLineLength)) {
673 LayoutUnit mainAxisExtent;
674 if (hasOrthogonalFlow(child)) {
675 if (child->needsLayout() || relayoutChildren) {
676 m_intrinsicSizeAlongMainAxis.remove(child);
677 child->forceChildLayout();
678 m_intrinsicSizeAlongMainAxis.set(child, child->logicalHeight());
680 ASSERT(m_intrinsicSizeAlongMainAxis.contains(child));
681 mainAxisExtent = m_intrinsicSizeAlongMainAxis.get(child);
683 mainAxisExtent = child->maxPreferredLogicalWidth();
685 ASSERT(mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child) >= 0);
686 return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child);
688 return std::max(LayoutUnit(0), computeMainAxisExtentForChild(child, MainOrPreferredSize, flexBasis));
691 void RenderFlexibleBox::layoutFlexItems(bool relayoutChildren)
693 Vector<LineContext> lineContexts;
694 OrderedFlexItemList orderedChildren;
695 LayoutUnit sumFlexBaseSize;
696 double totalFlexGrow;
697 double totalWeightedFlexShrink;
698 LayoutUnit sumHypotheticalMainSize;
700 Vector<LayoutUnit, 16> childSizes;
702 m_orderIterator.first();
703 LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
704 bool hasInfiniteLineLength = false;
705 while (computeNextFlexLine(orderedChildren, sumFlexBaseSize, totalFlexGrow, totalWeightedFlexShrink, sumHypotheticalMainSize, hasInfiniteLineLength, relayoutChildren)) {
706 LayoutUnit containerMainInnerSize = mainAxisContentExtent(sumHypotheticalMainSize);
707 LayoutUnit availableFreeSpace = containerMainInnerSize - sumFlexBaseSize;
708 FlexSign flexSign = (sumHypotheticalMainSize < containerMainInnerSize) ? PositiveFlexibility : NegativeFlexibility;
709 InflexibleFlexItemSize inflexibleItems;
710 childSizes.reserveCapacity(orderedChildren.size());
711 while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, childSizes, hasInfiniteLineLength)) {
712 ASSERT(totalFlexGrow >= 0 && totalWeightedFlexShrink >= 0);
713 ASSERT(inflexibleItems.size() > 0);
716 layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace, relayoutChildren, lineContexts, hasInfiniteLineLength);
718 if (hasLineIfEmpty()) {
719 // Even if computeNextFlexLine returns true, the flexbox might not have
720 // a line because all our children might be out of flow positioned.
721 // Instead of just checking if we have a line, make sure the flexbox
722 // has at least a line's worth of height to cover this case.
723 LayoutUnit minHeight = borderAndPaddingLogicalHeight()
724 + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes)
725 + scrollbarLogicalHeight();
726 if (height() < minHeight)
727 setLogicalHeight(minHeight);
730 updateLogicalHeight();
731 repositionLogicalHeightDependentFlexItems(lineContexts);
734 LayoutUnit RenderFlexibleBox::autoMarginOffsetInMainAxis(const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace)
736 if (availableFreeSpace <= 0)
739 int numberOfAutoMargins = 0;
740 bool isHorizontal = isHorizontalFlow();
741 for (size_t i = 0; i < children.size(); ++i) {
742 RenderBox* child = children[i];
743 if (child->isOutOfFlowPositioned())
746 if (child->style()->marginLeft().isAuto())
747 ++numberOfAutoMargins;
748 if (child->style()->marginRight().isAuto())
749 ++numberOfAutoMargins;
751 if (child->style()->marginTop().isAuto())
752 ++numberOfAutoMargins;
753 if (child->style()->marginBottom().isAuto())
754 ++numberOfAutoMargins;
757 if (!numberOfAutoMargins)
760 LayoutUnit sizeOfAutoMargin = availableFreeSpace / numberOfAutoMargins;
761 availableFreeSpace = 0;
762 return sizeOfAutoMargin;
765 void RenderFlexibleBox::updateAutoMarginsInMainAxis(RenderBox* child, LayoutUnit autoMarginOffset)
767 ASSERT(autoMarginOffset >= 0);
769 if (isHorizontalFlow()) {
770 if (child->style()->marginLeft().isAuto())
771 child->setMarginLeft(autoMarginOffset);
772 if (child->style()->marginRight().isAuto())
773 child->setMarginRight(autoMarginOffset);
775 if (child->style()->marginTop().isAuto())
776 child->setMarginTop(autoMarginOffset);
777 if (child->style()->marginBottom().isAuto())
778 child->setMarginBottom(autoMarginOffset);
782 bool RenderFlexibleBox::hasAutoMarginsInCrossAxis(RenderBox* child) const
784 if (isHorizontalFlow())
785 return child->style()->marginTop().isAuto() || child->style()->marginBottom().isAuto();
786 return child->style()->marginLeft().isAuto() || child->style()->marginRight().isAuto();
789 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox* child)
791 ASSERT(!child->isOutOfFlowPositioned());
792 LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child);
793 return lineCrossAxisExtent - childCrossExtent;
796 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChildBeforeStretching(LayoutUnit lineCrossAxisExtent, RenderBox* child)
798 ASSERT(!child->isOutOfFlowPositioned());
799 LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisIntrinsicExtentForChild(child);
800 return lineCrossAxisExtent - childCrossExtent;
803 bool RenderFlexibleBox::updateAutoMarginsInCrossAxis(RenderBox* child, LayoutUnit availableAlignmentSpace)
805 ASSERT(!child->isOutOfFlowPositioned());
806 ASSERT(availableAlignmentSpace >= 0);
808 bool isHorizontal = isHorizontalFlow();
809 Length topOrLeft = isHorizontal ? child->style()->marginTop() : child->style()->marginLeft();
810 Length bottomOrRight = isHorizontal ? child->style()->marginBottom() : child->style()->marginRight();
811 if (topOrLeft.isAuto() && bottomOrRight.isAuto()) {
812 adjustAlignmentForChild(child, availableAlignmentSpace / 2);
814 child->setMarginTop(availableAlignmentSpace / 2);
815 child->setMarginBottom(availableAlignmentSpace / 2);
817 child->setMarginLeft(availableAlignmentSpace / 2);
818 child->setMarginRight(availableAlignmentSpace / 2);
822 bool shouldAdjustTopOrLeft = true;
823 if (isColumnFlow() && !child->style()->isLeftToRightDirection()) {
824 // For column flows, only make this adjustment if topOrLeft corresponds to the "before" margin,
825 // so that flipForRightToLeftColumn will do the right thing.
826 shouldAdjustTopOrLeft = false;
828 if (!isColumnFlow() && child->style()->isFlippedBlocksWritingMode()) {
829 // If we are a flipped writing mode, we need to adjust the opposite side. This is only needed
830 // for row flows because this only affects the block-direction axis.
831 shouldAdjustTopOrLeft = false;
834 if (topOrLeft.isAuto()) {
835 if (shouldAdjustTopOrLeft)
836 adjustAlignmentForChild(child, availableAlignmentSpace);
839 child->setMarginTop(availableAlignmentSpace);
841 child->setMarginLeft(availableAlignmentSpace);
844 if (bottomOrRight.isAuto()) {
845 if (!shouldAdjustTopOrLeft)
846 adjustAlignmentForChild(child, availableAlignmentSpace);
849 child->setMarginBottom(availableAlignmentSpace);
851 child->setMarginRight(availableAlignmentSpace);
857 LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(RenderBox* child)
859 LayoutUnit ascent = child->firstLineBoxBaseline();
861 ascent = crossAxisExtentForChild(child);
862 return ascent + flowAwareMarginBeforeForChild(child);
865 LayoutUnit RenderFlexibleBox::computeChildMarginValue(Length margin)
867 // When resolving the margins, we use the content size for resolving percent and calc (for percents in calc expressions) margins.
868 // Fortunately, percent margins are always computed with respect to the block's width, even for margin-top and margin-bottom.
869 LayoutUnit availableSize = contentLogicalWidth();
870 return minimumValueForLength(margin, availableSize);
873 void RenderFlexibleBox::prepareOrderIteratorAndMargins()
875 OrderIteratorPopulator populator(m_orderIterator);
877 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
878 populator.collectChild(child);
880 if (child->isOutOfFlowPositioned())
883 // Before running the flex algorithm, 'auto' has a margin of 0.
884 // Also, if we're not auto sizing, we don't do a layout that computes the start/end margins.
885 if (isHorizontalFlow()) {
886 child->setMarginLeft(computeChildMarginValue(child->style()->marginLeft()));
887 child->setMarginRight(computeChildMarginValue(child->style()->marginRight()));
889 child->setMarginTop(computeChildMarginValue(child->style()->marginTop()));
890 child->setMarginBottom(computeChildMarginValue(child->style()->marginBottom()));
895 LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox* child, LayoutUnit childSize)
897 Length max = isHorizontalFlow() ? child->style()->maxWidth() : child->style()->maxHeight();
898 if (max.isSpecifiedOrIntrinsic()) {
899 LayoutUnit maxExtent = computeMainAxisExtentForChild(child, MaxSize, max);
900 if (maxExtent != -1 && childSize > maxExtent)
901 childSize = maxExtent;
904 Length min = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
905 LayoutUnit minExtent = 0;
906 if (min.isSpecifiedOrIntrinsic())
907 minExtent = computeMainAxisExtentForChild(child, MinSize, min);
908 return std::max(childSize, minExtent);
911 bool RenderFlexibleBox::computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& sumFlexBaseSize, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& sumHypotheticalMainSize, bool& hasInfiniteLineLength, bool relayoutChildren)
913 orderedChildren.clear();
915 totalFlexGrow = totalWeightedFlexShrink = 0;
916 sumHypotheticalMainSize = 0;
918 if (!m_orderIterator.currentChild())
921 LayoutUnit lineBreakLength = mainAxisContentExtent(LayoutUnit::max());
922 hasInfiniteLineLength = lineBreakLength == LayoutUnit::max();
924 bool lineHasInFlowItem = false;
926 for (RenderBox* child = m_orderIterator.currentChild(); child; child = m_orderIterator.next()) {
927 if (child->isOutOfFlowPositioned()) {
928 orderedChildren.append(child);
932 LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength, relayoutChildren);
933 LayoutUnit childMainAxisMarginBorderPadding = mainAxisBorderAndPaddingExtentForChild(child)
934 + (isHorizontalFlow() ? child->marginWidth() : child->marginHeight());
935 LayoutUnit childFlexBaseSize = childMainAxisExtent + childMainAxisMarginBorderPadding;
937 LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(child, childMainAxisExtent);
938 LayoutUnit childHypotheticalMainSize = childMinMaxAppliedMainAxisExtent + childMainAxisMarginBorderPadding;
940 if (isMultiline() && sumHypotheticalMainSize + childHypotheticalMainSize > lineBreakLength && lineHasInFlowItem)
942 orderedChildren.append(child);
943 lineHasInFlowItem = true;
944 sumFlexBaseSize += childFlexBaseSize;
945 totalFlexGrow += child->style()->flexGrow();
946 totalWeightedFlexShrink += child->style()->flexShrink() * childMainAxisExtent;
947 sumHypotheticalMainSize += childHypotheticalMainSize;
952 void RenderFlexibleBox::freezeViolations(const Vector<Violation>& violations, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, bool hasInfiniteLineLength)
954 for (size_t i = 0; i < violations.size(); ++i) {
955 RenderBox* child = violations[i].child;
956 LayoutUnit childSize = violations[i].childSize;
957 LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
958 availableFreeSpace -= childSize - preferredChildSize;
959 totalFlexGrow -= child->style()->flexGrow();
960 totalWeightedFlexShrink -= child->style()->flexShrink() * preferredChildSize;
961 inflexibleItems.set(child, childSize);
965 // Returns true if we successfully ran the algorithm and sized the flex items.
966 bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, Vector<LayoutUnit, 16>& childSizes, bool hasInfiniteLineLength)
968 childSizes.resize(0);
969 LayoutUnit totalViolation = 0;
970 LayoutUnit usedFreeSpace = 0;
971 Vector<Violation> minViolations;
972 Vector<Violation> maxViolations;
973 for (size_t i = 0; i < children.size(); ++i) {
974 RenderBox* child = children[i];
975 if (child->isOutOfFlowPositioned()) {
976 childSizes.append(0);
980 if (inflexibleItems.contains(child))
981 childSizes.append(inflexibleItems.get(child));
983 LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
984 LayoutUnit childSize = preferredChildSize;
985 double extraSpace = 0;
986 if (availableFreeSpace > 0 && totalFlexGrow > 0 && flexSign == PositiveFlexibility && std::isfinite(totalFlexGrow))
987 extraSpace = availableFreeSpace * child->style()->flexGrow() / totalFlexGrow;
988 else if (availableFreeSpace < 0 && totalWeightedFlexShrink > 0 && flexSign == NegativeFlexibility && std::isfinite(totalWeightedFlexShrink))
989 extraSpace = availableFreeSpace * child->style()->flexShrink() * preferredChildSize / totalWeightedFlexShrink;
990 if (std::isfinite(extraSpace))
991 childSize += LayoutUnit::fromFloatRound(extraSpace);
993 LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(child, childSize);
994 childSizes.append(adjustedChildSize);
995 usedFreeSpace += adjustedChildSize - preferredChildSize;
997 LayoutUnit violation = adjustedChildSize - childSize;
999 minViolations.append(Violation(child, adjustedChildSize));
1000 else if (violation < 0)
1001 maxViolations.append(Violation(child, adjustedChildSize));
1002 totalViolation += violation;
1007 freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, hasInfiniteLineLength);
1009 availableFreeSpace -= usedFreeSpace;
1011 return !totalViolation;
1014 static LayoutUnit initialJustifyContentOffset(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
1016 if (justifyContent == JustifyFlexEnd)
1017 return availableFreeSpace;
1018 if (justifyContent == JustifyCenter)
1019 return availableFreeSpace / 2;
1020 if (justifyContent == JustifySpaceAround) {
1021 if (availableFreeSpace > 0 && numberOfChildren)
1022 return availableFreeSpace / (2 * numberOfChildren);
1024 return availableFreeSpace / 2;
1029 static LayoutUnit justifyContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
1031 if (availableFreeSpace > 0 && numberOfChildren > 1) {
1032 if (justifyContent == JustifySpaceBetween)
1033 return availableFreeSpace / (numberOfChildren - 1);
1034 if (justifyContent == JustifySpaceAround)
1035 return availableFreeSpace / numberOfChildren;
1040 void RenderFlexibleBox::setLogicalOverrideSize(RenderBox* child, LayoutUnit childPreferredSize)
1042 if (hasOrthogonalFlow(child))
1043 child->setOverrideLogicalContentHeight(childPreferredSize - child->borderAndPaddingLogicalHeight());
1045 child->setOverrideLogicalContentWidth(childPreferredSize - child->borderAndPaddingLogicalWidth());
1048 void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox* child, LayoutUnit mainAxisOffset, LayoutUnit crossAxisOffset, PositionedLayoutMode layoutMode)
1050 ASSERT(child->isOutOfFlowPositioned());
1051 child->containingBlock()->insertPositionedObject(child);
1052 RenderLayer* childLayer = child->layer();
1053 LayoutUnit inlinePosition = isColumnFlow() ? crossAxisOffset : mainAxisOffset;
1054 if (layoutMode == FlipForRowReverse && style()->flexDirection() == FlowRowReverse)
1055 inlinePosition = mainAxisExtent() - mainAxisOffset;
1056 childLayer->setStaticInlinePosition(inlinePosition);
1058 LayoutUnit staticBlockPosition = isColumnFlow() ? mainAxisOffset : crossAxisOffset;
1059 if (childLayer->staticBlockPosition() != staticBlockPosition) {
1060 childLayer->setStaticBlockPosition(staticBlockPosition);
1061 if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
1062 child->setChildNeedsLayout(MarkOnlyThis);
1066 ItemPosition RenderFlexibleBox::alignmentForChild(RenderBox* child) const
1068 ItemPosition align = resolveAlignment(style(), child->style());
1070 if (align == ItemPositionBaseline && hasOrthogonalFlow(child))
1071 align = ItemPositionFlexStart;
1073 if (style()->flexWrap() == FlexWrapReverse) {
1074 if (align == ItemPositionFlexStart)
1075 align = ItemPositionFlexEnd;
1076 else if (align == ItemPositionFlexEnd)
1077 align = ItemPositionFlexStart;
1083 size_t RenderFlexibleBox::numberOfInFlowPositionedChildren(const OrderedFlexItemList& children) const
1086 for (size_t i = 0; i < children.size(); ++i) {
1087 RenderBox* child = children[i];
1088 if (!child->isOutOfFlowPositioned())
1094 void RenderFlexibleBox::resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox* child)
1096 if (hasAutoMarginsInCrossAxis(child)) {
1097 child->updateLogicalHeight();
1098 if (isHorizontalFlow()) {
1099 if (child->style()->marginTop().isAuto())
1100 child->setMarginTop(0);
1101 if (child->style()->marginBottom().isAuto())
1102 child->setMarginBottom(0);
1104 if (child->style()->marginLeft().isAuto())
1105 child->setMarginLeft(0);
1106 if (child->style()->marginRight().isAuto())
1107 child->setMarginRight(0);
1112 bool RenderFlexibleBox::needToStretchChildLogicalHeight(RenderBox* child) const
1114 if (alignmentForChild(child) != ItemPositionStretch)
1117 return isHorizontalFlow() && child->style()->height().isAuto();
1120 void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const Vector<LayoutUnit, 16>& childSizes, LayoutUnit availableFreeSpace, bool relayoutChildren, Vector<LineContext>& lineContexts, bool hasInfiniteLineLength)
1122 ASSERT(childSizes.size() == children.size());
1124 size_t numberOfChildrenForJustifyContent = numberOfInFlowPositionedChildren(children);
1125 LayoutUnit autoMarginOffset = autoMarginOffsetInMainAxis(children, availableFreeSpace);
1126 LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart();
1127 mainAxisOffset += initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1128 if (style()->flexDirection() == FlowRowReverse)
1129 mainAxisOffset += isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1131 LayoutUnit totalMainExtent = mainAxisExtent();
1132 LayoutUnit maxAscent = 0, maxDescent = 0; // Used when align-items: baseline.
1133 LayoutUnit maxChildCrossAxisExtent = 0;
1134 size_t seenInFlowPositionedChildren = 0;
1135 bool shouldFlipMainAxis = !isColumnFlow() && !isLeftToRightFlow();
1136 for (size_t i = 0; i < children.size(); ++i) {
1137 RenderBox* child = children[i];
1138 LayoutRectRecorder recorder(*child);
1140 if (child->isOutOfFlowPositioned()) {
1141 prepareChildForPositionedLayout(child, mainAxisOffset, crossAxisOffset, FlipForRowReverse);
1145 LayoutUnit childPreferredSize = childSizes[i] + mainAxisBorderAndPaddingExtentForChild(child);
1146 setLogicalOverrideSize(child, childPreferredSize);
1147 if (childPreferredSize != mainAxisExtentForChild(child)) {
1148 child->setChildNeedsLayout(MarkOnlyThis);
1150 // To avoid double applying margin changes in updateAutoMarginsInCrossAxis, we reset the margins here.
1151 resetAutoMarginsAndLogicalTopInCrossAxis(child);
1153 // We may have already forced relayout for orthogonal flowing children in preferredMainAxisContentExtentForChild.
1154 bool forceChildRelayout = relayoutChildren && !childPreferredMainAxisContentExtentRequiresLayout(child, hasInfiniteLineLength);
1155 updateBlockChildDirtyBitsBeforeLayout(forceChildRelayout, child);
1156 child->layoutIfNeeded();
1158 updateAutoMarginsInMainAxis(child, autoMarginOffset);
1160 LayoutUnit childCrossAxisMarginBoxExtent;
1161 if (alignmentForChild(child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(child)) {
1162 LayoutUnit ascent = marginBoxAscentForChild(child);
1163 LayoutUnit descent = (crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child)) - ascent;
1165 maxAscent = std::max(maxAscent, ascent);
1166 maxDescent = std::max(maxDescent, descent);
1168 childCrossAxisMarginBoxExtent = maxAscent + maxDescent;
1170 childCrossAxisMarginBoxExtent = crossAxisIntrinsicExtentForChild(child) + crossAxisMarginExtentForChild(child);
1172 if (!isColumnFlow())
1173 setLogicalHeight(std::max(logicalHeight(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent()));
1174 maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisMarginBoxExtent);
1176 mainAxisOffset += flowAwareMarginStartForChild(child);
1178 LayoutUnit childMainExtent = mainAxisExtentForChild(child);
1179 // In an RTL column situation, this will apply the margin-right/margin-end on the left.
1180 // This will be fixed later in flipForRightToLeftColumn.
1181 LayoutPoint childLocation(shouldFlipMainAxis ? totalMainExtent - mainAxisOffset - childMainExtent : mainAxisOffset,
1182 crossAxisOffset + flowAwareMarginBeforeForChild(child));
1184 // FIXME: Supporting layout deltas.
1185 setFlowAwareLocationForChild(child, childLocation);
1186 mainAxisOffset += childMainExtent + flowAwareMarginEndForChild(child);
1188 ++seenInFlowPositionedChildren;
1189 if (seenInFlowPositionedChildren < numberOfChildrenForJustifyContent)
1190 mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1194 setLogicalHeight(mainAxisOffset + flowAwareBorderEnd() + flowAwarePaddingEnd() + scrollbarLogicalHeight());
1196 if (style()->flexDirection() == FlowColumnReverse) {
1197 // We have to do an extra pass for column-reverse to reposition the flex items since the start depends
1198 // on the height of the flexbox, which we only know after we've positioned all the flex items.
1199 updateLogicalHeight();
1200 layoutColumnReverse(children, crossAxisOffset, availableFreeSpace);
1203 if (m_numberOfInFlowChildrenOnFirstLine == -1)
1204 m_numberOfInFlowChildrenOnFirstLine = seenInFlowPositionedChildren;
1205 lineContexts.append(LineContext(crossAxisOffset, maxChildCrossAxisExtent, children.size(), maxAscent));
1206 crossAxisOffset += maxChildCrossAxisExtent;
1209 void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace)
1211 // This is similar to the logic in layoutAndPlaceChildren, except we place the children
1212 // starting from the end of the flexbox. We also don't need to layout anything since we're
1213 // just moving the children to a new position.
1214 size_t numberOfChildrenForJustifyContent = numberOfInFlowPositionedChildren(children);
1215 LayoutUnit mainAxisOffset = logicalHeight() - flowAwareBorderEnd() - flowAwarePaddingEnd();
1216 mainAxisOffset -= initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1217 mainAxisOffset -= isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1219 size_t seenInFlowPositionedChildren = 0;
1220 for (size_t i = 0; i < children.size(); ++i) {
1221 RenderBox* child = children[i];
1222 LayoutRectRecorder recorder(*child);
1224 if (child->isOutOfFlowPositioned()) {
1225 child->layer()->setStaticBlockPosition(mainAxisOffset);
1228 mainAxisOffset -= mainAxisExtentForChild(child) + flowAwareMarginEndForChild(child);
1230 setFlowAwareLocationForChild(child, LayoutPoint(mainAxisOffset, crossAxisOffset + flowAwareMarginBeforeForChild(child)));
1232 mainAxisOffset -= flowAwareMarginStartForChild(child);
1234 ++seenInFlowPositionedChildren;
1235 if (seenInFlowPositionedChildren < numberOfChildrenForJustifyContent)
1236 mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1240 static LayoutUnit initialAlignContentOffset(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1242 if (alignContent == AlignContentFlexEnd)
1243 return availableFreeSpace;
1244 if (alignContent == AlignContentCenter)
1245 return availableFreeSpace / 2;
1246 if (alignContent == AlignContentSpaceAround) {
1247 if (availableFreeSpace > 0 && numberOfLines)
1248 return availableFreeSpace / (2 * numberOfLines);
1249 if (availableFreeSpace < 0)
1250 return availableFreeSpace / 2;
1255 static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1257 if (availableFreeSpace > 0 && numberOfLines > 1) {
1258 if (alignContent == AlignContentSpaceBetween)
1259 return availableFreeSpace / (numberOfLines - 1);
1260 if (alignContent == AlignContentSpaceAround || alignContent == AlignContentStretch)
1261 return availableFreeSpace / numberOfLines;
1266 void RenderFlexibleBox::alignFlexLines(Vector<LineContext>& lineContexts)
1268 if (!isMultiline() || style()->alignContent() == AlignContentFlexStart)
1271 LayoutUnit availableCrossAxisSpace = crossAxisContentExtent();
1272 for (size_t i = 0; i < lineContexts.size(); ++i)
1273 availableCrossAxisSpace -= lineContexts[i].crossAxisExtent;
1275 RenderBox* child = m_orderIterator.first();
1276 LayoutUnit lineOffset = initialAlignContentOffset(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1277 for (unsigned lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1278 lineContexts[lineNumber].crossAxisOffset += lineOffset;
1279 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next())
1280 adjustAlignmentForChild(child, lineOffset);
1282 if (style()->alignContent() == AlignContentStretch && availableCrossAxisSpace > 0)
1283 lineContexts[lineNumber].crossAxisExtent += availableCrossAxisSpace / static_cast<unsigned>(lineContexts.size());
1285 lineOffset += alignContentSpaceBetweenChildren(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1289 void RenderFlexibleBox::adjustAlignmentForChild(RenderBox* child, LayoutUnit delta)
1291 if (child->isOutOfFlowPositioned()) {
1292 LayoutUnit staticInlinePosition = child->layer()->staticInlinePosition();
1293 LayoutUnit staticBlockPosition = child->layer()->staticBlockPosition();
1294 LayoutUnit mainAxis = isColumnFlow() ? staticBlockPosition : staticInlinePosition;
1295 LayoutUnit crossAxis = isColumnFlow() ? staticInlinePosition : staticBlockPosition;
1297 prepareChildForPositionedLayout(child, mainAxis, crossAxis, NoFlipForRowReverse);
1301 setFlowAwareLocationForChild(child, flowAwareLocationForChild(child) + LayoutSize(0, delta));
1304 void RenderFlexibleBox::alignChildren(const Vector<LineContext>& lineContexts)
1306 // Keep track of the space between the baseline edge and the after edge of the box for each line.
1307 Vector<LayoutUnit> minMarginAfterBaselines;
1309 RenderBox* child = m_orderIterator.first();
1310 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1311 LayoutUnit minMarginAfterBaseline = LayoutUnit::max();
1312 LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1313 LayoutUnit maxAscent = lineContexts[lineNumber].maxAscent;
1315 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
1317 if (child->isOutOfFlowPositioned()) {
1318 if (style()->flexWrap() == FlexWrapReverse)
1319 adjustAlignmentForChild(child, lineCrossAxisExtent);
1323 if (updateAutoMarginsInCrossAxis(child, std::max(LayoutUnit(0), availableAlignmentSpaceForChild(lineCrossAxisExtent, child))))
1326 switch (alignmentForChild(child)) {
1327 case ItemPositionAuto:
1328 ASSERT_NOT_REACHED();
1330 case ItemPositionStretch: {
1331 applyStretchAlignmentToChild(child, lineCrossAxisExtent);
1332 // Since wrap-reverse flips cross start and cross end, strech children should be aligned with the cross end.
1333 if (style()->flexWrap() == FlexWrapReverse)
1334 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
1337 case ItemPositionFlexStart:
1339 case ItemPositionFlexEnd:
1340 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
1342 case ItemPositionCenter:
1343 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) / 2);
1345 case ItemPositionBaseline: {
1346 // 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.
1347 // https://bugs.webkit.org/show_bug.cgi?id=98076
1348 LayoutUnit ascent = marginBoxAscentForChild(child);
1349 LayoutUnit startOffset = maxAscent - ascent;
1350 adjustAlignmentForChild(child, startOffset);
1352 if (style()->flexWrap() == FlexWrapReverse)
1353 minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) - startOffset);
1356 case ItemPositionSelfStart:
1357 case ItemPositionSelfEnd:
1358 case ItemPositionStart:
1359 case ItemPositionEnd:
1360 case ItemPositionLeft:
1361 case ItemPositionRight:
1362 // FIXME: File a bug about implementing that. The extended grammar
1363 // is not enabled by default so we shouldn't hit this codepath.
1364 ASSERT_NOT_REACHED();
1368 minMarginAfterBaselines.append(minMarginAfterBaseline);
1371 if (style()->flexWrap() != FlexWrapReverse)
1374 // wrap-reverse flips the cross axis start and end. For baseline alignment, this means we
1375 // need to align the after edge of baseline elements with the after edge of the flex line.
1376 child = m_orderIterator.first();
1377 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1378 LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber];
1379 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
1381 if (alignmentForChild(child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(child) && minMarginAfterBaseline)
1382 adjustAlignmentForChild(child, minMarginAfterBaseline);
1387 void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox* child, LayoutUnit lineCrossAxisExtent)
1389 if (!isColumnFlow() && child->style()->logicalHeight().isAuto()) {
1390 // FIXME: If the child has orthogonal flow, then it already has an override height set, so use it.
1391 if (!hasOrthogonalFlow(child)) {
1392 LayoutUnit heightBeforeStretching = needToStretchChildLogicalHeight(child) ? constrainedChildIntrinsicContentLogicalHeight(child) : child->logicalHeight();
1393 LayoutUnit stretchedLogicalHeight = heightBeforeStretching + availableAlignmentSpaceForChildBeforeStretching(lineCrossAxisExtent, child);
1394 ASSERT(!child->needsLayout());
1395 LayoutUnit desiredLogicalHeight = child->constrainLogicalHeightByMinMax(stretchedLogicalHeight, heightBeforeStretching - child->borderAndPaddingLogicalHeight());
1397 // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
1398 if (desiredLogicalHeight != child->logicalHeight()) {
1399 child->setOverrideLogicalContentHeight(desiredLogicalHeight - child->borderAndPaddingLogicalHeight());
1400 child->setLogicalHeight(0);
1401 child->forceChildLayout();
1404 } else if (isColumnFlow() && child->style()->logicalWidth().isAuto()) {
1405 // FIXME: If the child doesn't have orthogonal flow, then it already has an override width set, so use it.
1406 if (hasOrthogonalFlow(child)) {
1407 LayoutUnit childWidth = std::max<LayoutUnit>(0, lineCrossAxisExtent - crossAxisMarginExtentForChild(child));
1408 childWidth = child->constrainLogicalWidthByMinMax(childWidth, childWidth, this);
1410 if (childWidth != child->logicalWidth()) {
1411 child->setOverrideLogicalContentWidth(childWidth - child->borderAndPaddingLogicalWidth());
1412 child->forceChildLayout();
1418 void RenderFlexibleBox::flipForRightToLeftColumn()
1420 if (style()->isLeftToRightDirection() || !isColumnFlow())
1423 LayoutUnit crossExtent = crossAxisExtent();
1424 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
1425 if (child->isOutOfFlowPositioned())
1427 LayoutPoint location = flowAwareLocationForChild(child);
1428 // For vertical flows, setFlowAwareLocationForChild will transpose x and y,
1429 // so using the y axis for a column cross axis extent is correct.
1430 location.setY(crossExtent - crossAxisExtentForChild(child) - location.y());
1431 setFlowAwareLocationForChild(child, location);
1435 void RenderFlexibleBox::flipForWrapReverse(const Vector<LineContext>& lineContexts, LayoutUnit crossAxisStartEdge)
1437 LayoutUnit contentExtent = crossAxisContentExtent();
1438 RenderBox* child = m_orderIterator.first();
1439 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1440 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
1442 LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1443 LayoutUnit originalOffset = lineContexts[lineNumber].crossAxisOffset - crossAxisStartEdge;
1444 LayoutUnit newOffset = contentExtent - originalOffset - lineCrossAxisExtent;
1445 adjustAlignmentForChild(child, newOffset - originalOffset);