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/LayoutRepainter.h"
35 #include "core/rendering/RenderLayer.h"
36 #include "core/rendering/RenderView.h"
37 #include "platform/LengthFunctions.h"
38 #include "wtf/MathExtras.h"
43 struct RenderFlexibleBox::LineContext {
44 LineContext(LayoutUnit crossAxisOffset, LayoutUnit crossAxisExtent, size_t numberOfChildren, LayoutUnit maxAscent)
45 : crossAxisOffset(crossAxisOffset)
46 , crossAxisExtent(crossAxisExtent)
47 , numberOfChildren(numberOfChildren)
48 , maxAscent(maxAscent)
52 LayoutUnit crossAxisOffset;
53 LayoutUnit crossAxisExtent;
54 size_t numberOfChildren;
58 struct RenderFlexibleBox::Violation {
59 Violation(RenderBox* child, LayoutUnit childSize)
61 , childSize(childSize)
70 RenderFlexibleBox::RenderFlexibleBox(Element* element)
71 : RenderBlock(element)
72 , m_orderIterator(this)
73 , m_numberOfInFlowChildrenOnFirstLine(-1)
75 setChildrenInline(false); // All of our children must be block-level.
78 RenderFlexibleBox::~RenderFlexibleBox()
82 RenderFlexibleBox* RenderFlexibleBox::createAnonymous(Document* document)
84 RenderFlexibleBox* renderer = new RenderFlexibleBox(0);
85 renderer->setDocumentForAnonymous(document);
89 const char* RenderFlexibleBox::renderName() const
91 return "RenderFlexibleBox";
94 void RenderFlexibleBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
96 // FIXME: We're ignoring flex-basis here and we shouldn't. We can't start honoring it though until
97 // the flex shorthand stops setting it to 0.
98 // See https://bugs.webkit.org/show_bug.cgi?id=116117 and http://crbug.com/240765.
99 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
100 if (child->isOutOfFlowPositioned())
103 LayoutUnit margin = marginIntrinsicLogicalWidthForChild(child);
104 bool hasOrthogonalWritingMode = child->isHorizontalWritingMode() != isHorizontalWritingMode();
105 LayoutUnit minPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->minPreferredLogicalWidth();
106 LayoutUnit maxPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->maxPreferredLogicalWidth();
107 minPreferredLogicalWidth += margin;
108 maxPreferredLogicalWidth += margin;
109 if (!isColumnFlow()) {
110 maxLogicalWidth += maxPreferredLogicalWidth;
112 // For multiline, the min preferred width is if you put a break between each item.
113 minLogicalWidth = std::max(minLogicalWidth, minPreferredLogicalWidth);
115 minLogicalWidth += minPreferredLogicalWidth;
117 minLogicalWidth = std::max(minPreferredLogicalWidth, minLogicalWidth);
119 // For multiline, the max preferred width is if you never break between items.
120 maxLogicalWidth += maxPreferredLogicalWidth;
122 maxLogicalWidth = std::max(maxPreferredLogicalWidth, maxLogicalWidth);
126 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
128 LayoutUnit scrollbarWidth = instrinsicScrollbarLogicalWidth();
129 maxLogicalWidth += scrollbarWidth;
130 minLogicalWidth += scrollbarWidth;
133 static int synthesizedBaselineFromContentBox(const RenderBox* box, LineDirectionMode direction)
135 return direction == HorizontalLine ? box->borderTop() + box->paddingTop() + box->contentHeight() : box->borderRight() + box->paddingRight() + box->contentWidth();
138 int RenderFlexibleBox::baselinePosition(FontBaseline, bool, LineDirectionMode direction, LinePositionMode mode) const
140 ASSERT(mode == PositionOnContainingLine);
141 int baseline = firstLineBoxBaseline();
143 baseline = synthesizedBaselineFromContentBox(this, direction);
145 return beforeMarginInLineDirection(direction) + baseline;
148 int RenderFlexibleBox::firstLineBoxBaseline() const
150 if (isWritingModeRoot() || m_numberOfInFlowChildrenOnFirstLine <= 0)
152 RenderBox* baselineChild = 0;
154 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
155 if (child->isOutOfFlowPositioned())
157 if (alignmentForChild(child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(child)) {
158 baselineChild = child;
162 baselineChild = child;
165 if (childNumber == m_numberOfInFlowChildrenOnFirstLine)
172 if (!isColumnFlow() && hasOrthogonalFlow(baselineChild))
173 return crossAxisExtentForChild(baselineChild) + baselineChild->logicalTop();
174 if (isColumnFlow() && !hasOrthogonalFlow(baselineChild))
175 return mainAxisExtentForChild(baselineChild) + baselineChild->logicalTop();
177 int baseline = baselineChild->firstLineBoxBaseline();
178 if (baseline == -1) {
179 // FIXME: We should pass |direction| into firstLineBoxBaseline and stop bailing out if we're a writing mode root.
180 // This would also fix some cases where the flexbox is orthogonal to its container.
181 LineDirectionMode direction = isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
182 return synthesizedBaselineFromContentBox(baselineChild, direction) + baselineChild->logicalTop();
185 return baseline + baselineChild->logicalTop();
188 int RenderFlexibleBox::inlineBlockBaseline(LineDirectionMode direction) const
190 int baseline = firstLineBoxBaseline();
194 int marginAscent = direction == HorizontalLine ? marginTop() : marginRight();
195 return synthesizedBaselineFromContentBox(this, direction) + marginAscent;
198 static ItemPosition resolveAlignment(const RenderStyle* parentStyle, const RenderStyle* childStyle)
200 ItemPosition align = childStyle->alignSelf();
201 if (align == ItemPositionAuto)
202 align = parentStyle->alignItems();
206 void RenderFlexibleBox::removeChild(RenderObject* child)
208 RenderBlock::removeChild(child);
209 m_intrinsicSizeAlongMainAxis.remove(child);
212 void RenderFlexibleBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
214 RenderBlock::styleDidChange(diff, oldStyle);
216 if (oldStyle && oldStyle->alignItems() == ItemPositionStretch && diff.needsFullLayout()) {
217 // Flex items that were previously stretching need to be relayed out so we can compute new available cross axis space.
218 // This is only necessary for stretching since other alignment values don't change the size of the box.
219 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
220 ItemPosition previousAlignment = resolveAlignment(oldStyle, child->style());
221 if (previousAlignment == ItemPositionStretch && previousAlignment != resolveAlignment(style(), child->style()))
222 child->setChildNeedsLayout(MarkOnlyThis);
227 void RenderFlexibleBox::layoutBlock(bool relayoutChildren)
229 ASSERT(needsLayout());
231 if (!relayoutChildren && simplifiedLayout())
234 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
236 if (updateLogicalWidthAndColumnWidth())
237 relayoutChildren = true;
239 LayoutUnit previousHeight = logicalHeight();
240 setLogicalHeight(borderAndPaddingLogicalHeight() + scrollbarLogicalHeight());
243 LayoutStateMaintainer statePusher(*this, locationOffset());
245 m_numberOfInFlowChildrenOnFirstLine = -1;
247 RenderBlock::startDelayUpdateScrollInfo();
249 prepareOrderIteratorAndMargins();
251 ChildFrameRects oldChildRects;
252 appendChildFrameRects(oldChildRects);
254 layoutFlexItems(relayoutChildren);
256 RenderBlock::finishDelayUpdateScrollInfo();
258 if (logicalHeight() != previousHeight)
259 relayoutChildren = true;
261 layoutPositionedObjects(relayoutChildren || isDocumentElement());
263 computeRegionRangeForBlock(flowThreadContainingBlock());
265 repaintChildrenDuringLayoutIfMoved(oldChildRects);
266 // FIXME: css3/flexbox/repaint-rtl-column.html seems to repaint more overflow than it needs to.
267 computeOverflow(clientLogicalBottomAfterRepositioning());
270 updateLayerTransform();
272 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
273 // we overflow or not.
274 updateScrollInfoAfterLayout();
276 repainter.repaintAfterLayout();
281 void RenderFlexibleBox::appendChildFrameRects(ChildFrameRects& childFrameRects)
283 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
284 if (!child->isOutOfFlowPositioned())
285 childFrameRects.append(child->frameRect());
289 void RenderFlexibleBox::repaintChildrenDuringLayoutIfMoved(const ChildFrameRects& oldChildRects)
291 size_t childIndex = 0;
292 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
293 if (child->isOutOfFlowPositioned())
296 // If the child moved, we have to repaint it as well as any floating/positioned
297 // descendants. An exception is if we need a layout. In this case, we know we're going to
298 // repaint ourselves (and the child) anyway.
299 if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
300 child->repaintDuringLayoutIfMoved(oldChildRects[childIndex]);
303 ASSERT(childIndex == oldChildRects.size());
306 void RenderFlexibleBox::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
308 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next())
309 paintChildAsInlineBlock(child, paintInfo, paintOffset);
312 void RenderFlexibleBox::repositionLogicalHeightDependentFlexItems(Vector<LineContext>& lineContexts)
314 LayoutUnit crossAxisStartEdge = lineContexts.isEmpty() ? LayoutUnit() : lineContexts[0].crossAxisOffset;
315 alignFlexLines(lineContexts);
317 // If we have a single line flexbox, the line height is all the available space.
318 // For flex-direction: row, this means we need to use the height, so we do this after calling updateLogicalHeight.
319 if (!isMultiline() && lineContexts.size() == 1)
320 lineContexts[0].crossAxisExtent = crossAxisContentExtent();
321 alignChildren(lineContexts);
323 if (style()->flexWrap() == FlexWrapReverse)
324 flipForWrapReverse(lineContexts, crossAxisStartEdge);
326 // direction:rtl + flex-direction:column means the cross-axis direction is flipped.
327 flipForRightToLeftColumn();
330 LayoutUnit RenderFlexibleBox::clientLogicalBottomAfterRepositioning()
332 LayoutUnit maxChildLogicalBottom = 0;
333 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
334 if (child->isOutOfFlowPositioned())
336 LayoutUnit childLogicalBottom = logicalTopForChild(child) + logicalHeightForChild(child) + marginAfterForChild(child);
337 maxChildLogicalBottom = std::max(maxChildLogicalBottom, childLogicalBottom);
339 return std::max(clientLogicalBottom(), maxChildLogicalBottom + paddingAfter());
342 bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox* child) const
344 // FIXME: If the child is a flexbox, then we need to check isHorizontalFlow.
345 return isHorizontalFlow() != child->isHorizontalWritingMode();
348 bool RenderFlexibleBox::isColumnFlow() const
350 return style()->isColumnFlexDirection();
353 bool RenderFlexibleBox::isHorizontalFlow() const
355 if (isHorizontalWritingMode())
356 return !isColumnFlow();
357 return isColumnFlow();
360 bool RenderFlexibleBox::isLeftToRightFlow() const
363 return style()->writingMode() == TopToBottomWritingMode || style()->writingMode() == LeftToRightWritingMode;
364 return style()->isLeftToRightDirection() ^ (style()->flexDirection() == FlowRowReverse);
367 bool RenderFlexibleBox::isMultiline() const
369 return style()->flexWrap() != FlexNoWrap;
372 Length RenderFlexibleBox::flexBasisForChild(RenderBox* child) const
374 Length flexLength = child->style()->flexBasis();
375 if (flexLength.isAuto())
376 flexLength = isHorizontalFlow() ? child->style()->width() : child->style()->height();
380 LayoutUnit RenderFlexibleBox::crossAxisExtentForChild(RenderBox* child) const
382 return isHorizontalFlow() ? child->height() : child->width();
385 static inline LayoutUnit constrainedChildIntrinsicContentLogicalHeight(RenderBox* child)
387 LayoutUnit childIntrinsicContentLogicalHeight = child->intrinsicContentLogicalHeight();
388 return child->constrainLogicalHeightByMinMax(childIntrinsicContentLogicalHeight + child->borderAndPaddingLogicalHeight(), childIntrinsicContentLogicalHeight);
391 LayoutUnit RenderFlexibleBox::childIntrinsicHeight(RenderBox* child) const
393 if (child->isHorizontalWritingMode() && needToStretchChildLogicalHeight(child))
394 return constrainedChildIntrinsicContentLogicalHeight(child);
395 return child->height();
398 LayoutUnit RenderFlexibleBox::childIntrinsicWidth(RenderBox* child) const
400 if (!child->isHorizontalWritingMode() && needToStretchChildLogicalHeight(child))
401 return constrainedChildIntrinsicContentLogicalHeight(child);
402 return child->width();
405 LayoutUnit RenderFlexibleBox::crossAxisIntrinsicExtentForChild(RenderBox* child) const
407 return isHorizontalFlow() ? childIntrinsicHeight(child) : childIntrinsicWidth(child);
410 LayoutUnit RenderFlexibleBox::mainAxisExtentForChild(RenderBox* child) const
412 return isHorizontalFlow() ? child->width() : child->height();
415 LayoutUnit RenderFlexibleBox::crossAxisExtent() const
417 return isHorizontalFlow() ? height() : width();
420 LayoutUnit RenderFlexibleBox::mainAxisExtent() const
422 return isHorizontalFlow() ? width() : height();
425 LayoutUnit RenderFlexibleBox::crossAxisContentExtent() const
427 return isHorizontalFlow() ? contentHeight() : contentWidth();
430 LayoutUnit RenderFlexibleBox::mainAxisContentExtent(LayoutUnit contentLogicalHeight)
432 if (isColumnFlow()) {
433 LogicalExtentComputedValues computedValues;
434 LayoutUnit borderPaddingAndScrollbar = borderAndPaddingLogicalHeight() + scrollbarLogicalHeight();
435 // FIXME: Remove this std:max once we enable saturated layout arithmetic. It's just here to handle overflow.
436 LayoutUnit borderBoxLogicalHeight = std::max(contentLogicalHeight, contentLogicalHeight + borderPaddingAndScrollbar);
437 computeLogicalHeight(borderBoxLogicalHeight, logicalTop(), computedValues);
438 if (computedValues.m_extent == LayoutUnit::max())
439 return computedValues.m_extent;
440 return std::max(LayoutUnit(0), computedValues.m_extent - borderPaddingAndScrollbar);
442 return contentLogicalWidth();
445 LayoutUnit RenderFlexibleBox::computeMainAxisExtentForChild(RenderBox* child, SizeType sizeType, const Length& size)
447 // FIXME: This is wrong for orthogonal flows. It should use the flexbox's writing-mode, not the child's in order
448 // to figure out the logical height/width.
449 if (isColumnFlow()) {
450 // We don't have to check for "auto" here - computeContentLogicalHeight will just return -1 for that case anyway.
451 if (size.isIntrinsic())
452 child->layoutIfNeeded();
453 return child->computeContentLogicalHeight(size, child->logicalHeight() - child->borderAndPaddingLogicalHeight());
455 return child->computeLogicalWidthUsing(sizeType, size, contentLogicalWidth(), this) - child->borderAndPaddingLogicalWidth();
458 WritingMode RenderFlexibleBox::transformedWritingMode() const
460 WritingMode mode = style()->writingMode();
465 case TopToBottomWritingMode:
466 case BottomToTopWritingMode:
467 return style()->isLeftToRightDirection() ? LeftToRightWritingMode : RightToLeftWritingMode;
468 case LeftToRightWritingMode:
469 case RightToLeftWritingMode:
470 return style()->isLeftToRightDirection() ? TopToBottomWritingMode : BottomToTopWritingMode;
472 ASSERT_NOT_REACHED();
473 return TopToBottomWritingMode;
476 LayoutUnit RenderFlexibleBox::flowAwareBorderStart() const
478 if (isHorizontalFlow())
479 return isLeftToRightFlow() ? borderLeft() : borderRight();
480 return isLeftToRightFlow() ? borderTop() : borderBottom();
483 LayoutUnit RenderFlexibleBox::flowAwareBorderEnd() const
485 if (isHorizontalFlow())
486 return isLeftToRightFlow() ? borderRight() : borderLeft();
487 return isLeftToRightFlow() ? borderBottom() : borderTop();
490 LayoutUnit RenderFlexibleBox::flowAwareBorderBefore() const
492 switch (transformedWritingMode()) {
493 case TopToBottomWritingMode:
495 case BottomToTopWritingMode:
496 return borderBottom();
497 case LeftToRightWritingMode:
499 case RightToLeftWritingMode:
500 return borderRight();
502 ASSERT_NOT_REACHED();
506 LayoutUnit RenderFlexibleBox::flowAwareBorderAfter() const
508 switch (transformedWritingMode()) {
509 case TopToBottomWritingMode:
510 return borderBottom();
511 case BottomToTopWritingMode:
513 case LeftToRightWritingMode:
514 return borderRight();
515 case RightToLeftWritingMode:
518 ASSERT_NOT_REACHED();
522 LayoutUnit RenderFlexibleBox::flowAwarePaddingStart() const
524 if (isHorizontalFlow())
525 return isLeftToRightFlow() ? paddingLeft() : paddingRight();
526 return isLeftToRightFlow() ? paddingTop() : paddingBottom();
529 LayoutUnit RenderFlexibleBox::flowAwarePaddingEnd() const
531 if (isHorizontalFlow())
532 return isLeftToRightFlow() ? paddingRight() : paddingLeft();
533 return isLeftToRightFlow() ? paddingBottom() : paddingTop();
536 LayoutUnit RenderFlexibleBox::flowAwarePaddingBefore() const
538 switch (transformedWritingMode()) {
539 case TopToBottomWritingMode:
541 case BottomToTopWritingMode:
542 return paddingBottom();
543 case LeftToRightWritingMode:
544 return paddingLeft();
545 case RightToLeftWritingMode:
546 return paddingRight();
548 ASSERT_NOT_REACHED();
552 LayoutUnit RenderFlexibleBox::flowAwarePaddingAfter() const
554 switch (transformedWritingMode()) {
555 case TopToBottomWritingMode:
556 return paddingBottom();
557 case BottomToTopWritingMode:
559 case LeftToRightWritingMode:
560 return paddingRight();
561 case RightToLeftWritingMode:
562 return paddingLeft();
564 ASSERT_NOT_REACHED();
568 LayoutUnit RenderFlexibleBox::flowAwareMarginStartForChild(RenderBox* child) const
570 if (isHorizontalFlow())
571 return isLeftToRightFlow() ? child->marginLeft() : child->marginRight();
572 return isLeftToRightFlow() ? child->marginTop() : child->marginBottom();
575 LayoutUnit RenderFlexibleBox::flowAwareMarginEndForChild(RenderBox* child) const
577 if (isHorizontalFlow())
578 return isLeftToRightFlow() ? child->marginRight() : child->marginLeft();
579 return isLeftToRightFlow() ? child->marginBottom() : child->marginTop();
582 LayoutUnit RenderFlexibleBox::flowAwareMarginBeforeForChild(RenderBox* child) const
584 switch (transformedWritingMode()) {
585 case TopToBottomWritingMode:
586 return child->marginTop();
587 case BottomToTopWritingMode:
588 return child->marginBottom();
589 case LeftToRightWritingMode:
590 return child->marginLeft();
591 case RightToLeftWritingMode:
592 return child->marginRight();
594 ASSERT_NOT_REACHED();
598 LayoutUnit RenderFlexibleBox::crossAxisMarginExtentForChild(RenderBox* child) const
600 return isHorizontalFlow() ? child->marginHeight() : child->marginWidth();
603 LayoutUnit RenderFlexibleBox::crossAxisScrollbarExtent() const
605 return isHorizontalFlow() ? horizontalScrollbarHeight() : verticalScrollbarWidth();
608 LayoutPoint RenderFlexibleBox::flowAwareLocationForChild(RenderBox* child) const
610 return isHorizontalFlow() ? child->location() : child->location().transposedPoint();
613 void RenderFlexibleBox::setFlowAwareLocationForChild(RenderBox* child, const LayoutPoint& location)
615 if (isHorizontalFlow())
616 child->setLocation(location);
618 child->setLocation(location.transposedPoint());
621 LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox* child) const
623 return isHorizontalFlow() ? child->borderAndPaddingWidth() : child->borderAndPaddingHeight();
626 static inline bool preferredMainAxisExtentDependsOnLayout(const Length& flexBasis, bool hasInfiniteLineLength)
628 return flexBasis.isAuto() || (flexBasis.isFixed() && !flexBasis.value() && hasInfiniteLineLength);
631 bool RenderFlexibleBox::childPreferredMainAxisContentExtentRequiresLayout(RenderBox* child, bool hasInfiniteLineLength) const
633 return preferredMainAxisExtentDependsOnLayout(flexBasisForChild(child), hasInfiniteLineLength) && hasOrthogonalFlow(child);
636 LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* child, bool hasInfiniteLineLength, bool relayoutChildren)
638 child->clearOverrideSize();
640 Length flexBasis = flexBasisForChild(child);
641 if (preferredMainAxisExtentDependsOnLayout(flexBasis, hasInfiniteLineLength)) {
642 LayoutUnit mainAxisExtent;
643 if (hasOrthogonalFlow(child)) {
644 if (child->needsLayout() || relayoutChildren) {
645 m_intrinsicSizeAlongMainAxis.remove(child);
646 child->forceChildLayout();
647 m_intrinsicSizeAlongMainAxis.set(child, child->logicalHeight());
649 ASSERT(m_intrinsicSizeAlongMainAxis.contains(child));
650 mainAxisExtent = m_intrinsicSizeAlongMainAxis.get(child);
652 mainAxisExtent = child->maxPreferredLogicalWidth();
654 ASSERT(mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child) >= 0);
655 return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child);
657 return std::max(LayoutUnit(0), computeMainAxisExtentForChild(child, MainOrPreferredSize, flexBasis));
660 void RenderFlexibleBox::layoutFlexItems(bool relayoutChildren)
662 Vector<LineContext> lineContexts;
663 OrderedFlexItemList orderedChildren;
664 LayoutUnit sumFlexBaseSize;
665 double totalFlexGrow;
666 double totalWeightedFlexShrink;
667 LayoutUnit sumHypotheticalMainSize;
669 Vector<LayoutUnit, 16> childSizes;
671 m_orderIterator.first();
672 LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
673 bool hasInfiniteLineLength = false;
674 while (computeNextFlexLine(orderedChildren, sumFlexBaseSize, totalFlexGrow, totalWeightedFlexShrink, sumHypotheticalMainSize, hasInfiniteLineLength, relayoutChildren)) {
675 LayoutUnit containerMainInnerSize = mainAxisContentExtent(sumHypotheticalMainSize);
676 LayoutUnit availableFreeSpace = containerMainInnerSize - sumFlexBaseSize;
677 FlexSign flexSign = (sumHypotheticalMainSize < containerMainInnerSize) ? PositiveFlexibility : NegativeFlexibility;
678 InflexibleFlexItemSize inflexibleItems;
679 childSizes.reserveCapacity(orderedChildren.size());
680 while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, childSizes, hasInfiniteLineLength)) {
681 ASSERT(totalFlexGrow >= 0 && totalWeightedFlexShrink >= 0);
682 ASSERT(inflexibleItems.size() > 0);
685 layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace, relayoutChildren, lineContexts, hasInfiniteLineLength);
687 if (hasLineIfEmpty()) {
688 // Even if computeNextFlexLine returns true, the flexbox might not have
689 // a line because all our children might be out of flow positioned.
690 // Instead of just checking if we have a line, make sure the flexbox
691 // has at least a line's worth of height to cover this case.
692 LayoutUnit minHeight = borderAndPaddingLogicalHeight()
693 + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes)
694 + scrollbarLogicalHeight();
695 if (height() < minHeight)
696 setLogicalHeight(minHeight);
699 updateLogicalHeight();
700 repositionLogicalHeightDependentFlexItems(lineContexts);
703 LayoutUnit RenderFlexibleBox::autoMarginOffsetInMainAxis(const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace)
705 if (availableFreeSpace <= 0)
708 int numberOfAutoMargins = 0;
709 bool isHorizontal = isHorizontalFlow();
710 for (size_t i = 0; i < children.size(); ++i) {
711 RenderBox* child = children[i];
712 if (child->isOutOfFlowPositioned())
715 if (child->style()->marginLeft().isAuto())
716 ++numberOfAutoMargins;
717 if (child->style()->marginRight().isAuto())
718 ++numberOfAutoMargins;
720 if (child->style()->marginTop().isAuto())
721 ++numberOfAutoMargins;
722 if (child->style()->marginBottom().isAuto())
723 ++numberOfAutoMargins;
726 if (!numberOfAutoMargins)
729 LayoutUnit sizeOfAutoMargin = availableFreeSpace / numberOfAutoMargins;
730 availableFreeSpace = 0;
731 return sizeOfAutoMargin;
734 void RenderFlexibleBox::updateAutoMarginsInMainAxis(RenderBox* child, LayoutUnit autoMarginOffset)
736 ASSERT(autoMarginOffset >= 0);
738 if (isHorizontalFlow()) {
739 if (child->style()->marginLeft().isAuto())
740 child->setMarginLeft(autoMarginOffset);
741 if (child->style()->marginRight().isAuto())
742 child->setMarginRight(autoMarginOffset);
744 if (child->style()->marginTop().isAuto())
745 child->setMarginTop(autoMarginOffset);
746 if (child->style()->marginBottom().isAuto())
747 child->setMarginBottom(autoMarginOffset);
751 bool RenderFlexibleBox::hasAutoMarginsInCrossAxis(RenderBox* child) const
753 if (isHorizontalFlow())
754 return child->style()->marginTop().isAuto() || child->style()->marginBottom().isAuto();
755 return child->style()->marginLeft().isAuto() || child->style()->marginRight().isAuto();
758 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox* child)
760 ASSERT(!child->isOutOfFlowPositioned());
761 LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child);
762 return lineCrossAxisExtent - childCrossExtent;
765 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChildBeforeStretching(LayoutUnit lineCrossAxisExtent, RenderBox* child)
767 ASSERT(!child->isOutOfFlowPositioned());
768 LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisIntrinsicExtentForChild(child);
769 return lineCrossAxisExtent - childCrossExtent;
772 bool RenderFlexibleBox::updateAutoMarginsInCrossAxis(RenderBox* child, LayoutUnit availableAlignmentSpace)
774 ASSERT(!child->isOutOfFlowPositioned());
775 ASSERT(availableAlignmentSpace >= 0);
777 bool isHorizontal = isHorizontalFlow();
778 Length topOrLeft = isHorizontal ? child->style()->marginTop() : child->style()->marginLeft();
779 Length bottomOrRight = isHorizontal ? child->style()->marginBottom() : child->style()->marginRight();
780 if (topOrLeft.isAuto() && bottomOrRight.isAuto()) {
781 adjustAlignmentForChild(child, availableAlignmentSpace / 2);
783 child->setMarginTop(availableAlignmentSpace / 2);
784 child->setMarginBottom(availableAlignmentSpace / 2);
786 child->setMarginLeft(availableAlignmentSpace / 2);
787 child->setMarginRight(availableAlignmentSpace / 2);
791 bool shouldAdjustTopOrLeft = true;
792 if (isColumnFlow() && !child->style()->isLeftToRightDirection()) {
793 // For column flows, only make this adjustment if topOrLeft corresponds to the "before" margin,
794 // so that flipForRightToLeftColumn will do the right thing.
795 shouldAdjustTopOrLeft = false;
797 if (!isColumnFlow() && child->style()->isFlippedBlocksWritingMode()) {
798 // If we are a flipped writing mode, we need to adjust the opposite side. This is only needed
799 // for row flows because this only affects the block-direction axis.
800 shouldAdjustTopOrLeft = false;
803 if (topOrLeft.isAuto()) {
804 if (shouldAdjustTopOrLeft)
805 adjustAlignmentForChild(child, availableAlignmentSpace);
808 child->setMarginTop(availableAlignmentSpace);
810 child->setMarginLeft(availableAlignmentSpace);
813 if (bottomOrRight.isAuto()) {
814 if (!shouldAdjustTopOrLeft)
815 adjustAlignmentForChild(child, availableAlignmentSpace);
818 child->setMarginBottom(availableAlignmentSpace);
820 child->setMarginRight(availableAlignmentSpace);
826 LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(RenderBox* child)
828 LayoutUnit ascent = child->firstLineBoxBaseline();
830 ascent = crossAxisExtentForChild(child);
831 return ascent + flowAwareMarginBeforeForChild(child);
834 LayoutUnit RenderFlexibleBox::computeChildMarginValue(Length margin)
836 // When resolving the margins, we use the content size for resolving percent and calc (for percents in calc expressions) margins.
837 // Fortunately, percent margins are always computed with respect to the block's width, even for margin-top and margin-bottom.
838 LayoutUnit availableSize = contentLogicalWidth();
839 return minimumValueForLength(margin, availableSize);
842 void RenderFlexibleBox::prepareOrderIteratorAndMargins()
844 OrderIteratorPopulator populator(m_orderIterator);
846 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
847 populator.collectChild(child);
849 if (child->isOutOfFlowPositioned())
852 // Before running the flex algorithm, 'auto' has a margin of 0.
853 // Also, if we're not auto sizing, we don't do a layout that computes the start/end margins.
854 if (isHorizontalFlow()) {
855 child->setMarginLeft(computeChildMarginValue(child->style()->marginLeft()));
856 child->setMarginRight(computeChildMarginValue(child->style()->marginRight()));
858 child->setMarginTop(computeChildMarginValue(child->style()->marginTop()));
859 child->setMarginBottom(computeChildMarginValue(child->style()->marginBottom()));
864 LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox* child, LayoutUnit childSize)
866 Length max = isHorizontalFlow() ? child->style()->maxWidth() : child->style()->maxHeight();
867 if (max.isSpecifiedOrIntrinsic()) {
868 LayoutUnit maxExtent = computeMainAxisExtentForChild(child, MaxSize, max);
869 if (maxExtent != -1 && childSize > maxExtent)
870 childSize = maxExtent;
873 Length min = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
874 LayoutUnit minExtent = 0;
875 if (min.isSpecifiedOrIntrinsic())
876 minExtent = computeMainAxisExtentForChild(child, MinSize, min);
877 return std::max(childSize, minExtent);
880 bool RenderFlexibleBox::computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& sumFlexBaseSize, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& sumHypotheticalMainSize, bool& hasInfiniteLineLength, bool relayoutChildren)
882 orderedChildren.clear();
884 totalFlexGrow = totalWeightedFlexShrink = 0;
885 sumHypotheticalMainSize = 0;
887 if (!m_orderIterator.currentChild())
890 LayoutUnit lineBreakLength = mainAxisContentExtent(LayoutUnit::max());
891 hasInfiniteLineLength = lineBreakLength == LayoutUnit::max();
893 bool lineHasInFlowItem = false;
895 for (RenderBox* child = m_orderIterator.currentChild(); child; child = m_orderIterator.next()) {
896 if (child->isOutOfFlowPositioned()) {
897 orderedChildren.append(child);
901 LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength, relayoutChildren);
902 LayoutUnit childMainAxisMarginBorderPadding = mainAxisBorderAndPaddingExtentForChild(child)
903 + (isHorizontalFlow() ? child->marginWidth() : child->marginHeight());
904 LayoutUnit childFlexBaseSize = childMainAxisExtent + childMainAxisMarginBorderPadding;
906 LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(child, childMainAxisExtent);
907 LayoutUnit childHypotheticalMainSize = childMinMaxAppliedMainAxisExtent + childMainAxisMarginBorderPadding;
909 if (isMultiline() && sumHypotheticalMainSize + childHypotheticalMainSize > lineBreakLength && lineHasInFlowItem)
911 orderedChildren.append(child);
912 lineHasInFlowItem = true;
913 sumFlexBaseSize += childFlexBaseSize;
914 totalFlexGrow += child->style()->flexGrow();
915 totalWeightedFlexShrink += child->style()->flexShrink() * childMainAxisExtent;
916 sumHypotheticalMainSize += childHypotheticalMainSize;
921 void RenderFlexibleBox::freezeViolations(const Vector<Violation>& violations, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, bool hasInfiniteLineLength)
923 for (size_t i = 0; i < violations.size(); ++i) {
924 RenderBox* child = violations[i].child;
925 LayoutUnit childSize = violations[i].childSize;
926 LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
927 availableFreeSpace -= childSize - preferredChildSize;
928 totalFlexGrow -= child->style()->flexGrow();
929 totalWeightedFlexShrink -= child->style()->flexShrink() * preferredChildSize;
930 inflexibleItems.set(child, childSize);
934 // Returns true if we successfully ran the algorithm and sized the flex items.
935 bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, Vector<LayoutUnit, 16>& childSizes, bool hasInfiniteLineLength)
937 childSizes.resize(0);
938 LayoutUnit totalViolation = 0;
939 LayoutUnit usedFreeSpace = 0;
940 Vector<Violation> minViolations;
941 Vector<Violation> maxViolations;
942 for (size_t i = 0; i < children.size(); ++i) {
943 RenderBox* child = children[i];
944 if (child->isOutOfFlowPositioned()) {
945 childSizes.append(0);
949 if (inflexibleItems.contains(child))
950 childSizes.append(inflexibleItems.get(child));
952 LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
953 LayoutUnit childSize = preferredChildSize;
954 double extraSpace = 0;
955 if (availableFreeSpace > 0 && totalFlexGrow > 0 && flexSign == PositiveFlexibility && std::isfinite(totalFlexGrow))
956 extraSpace = availableFreeSpace * child->style()->flexGrow() / totalFlexGrow;
957 else if (availableFreeSpace < 0 && totalWeightedFlexShrink > 0 && flexSign == NegativeFlexibility && std::isfinite(totalWeightedFlexShrink))
958 extraSpace = availableFreeSpace * child->style()->flexShrink() * preferredChildSize / totalWeightedFlexShrink;
959 if (std::isfinite(extraSpace))
960 childSize += LayoutUnit::fromFloatRound(extraSpace);
962 LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(child, childSize);
963 childSizes.append(adjustedChildSize);
964 usedFreeSpace += adjustedChildSize - preferredChildSize;
966 LayoutUnit violation = adjustedChildSize - childSize;
968 minViolations.append(Violation(child, adjustedChildSize));
969 else if (violation < 0)
970 maxViolations.append(Violation(child, adjustedChildSize));
971 totalViolation += violation;
976 freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, hasInfiniteLineLength);
978 availableFreeSpace -= usedFreeSpace;
980 return !totalViolation;
983 static LayoutUnit initialJustifyContentOffset(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
985 if (justifyContent == JustifyFlexEnd)
986 return availableFreeSpace;
987 if (justifyContent == JustifyCenter)
988 return availableFreeSpace / 2;
989 if (justifyContent == JustifySpaceAround) {
990 if (availableFreeSpace > 0 && numberOfChildren)
991 return availableFreeSpace / (2 * numberOfChildren);
993 return availableFreeSpace / 2;
998 static LayoutUnit justifyContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
1000 if (availableFreeSpace > 0 && numberOfChildren > 1) {
1001 if (justifyContent == JustifySpaceBetween)
1002 return availableFreeSpace / (numberOfChildren - 1);
1003 if (justifyContent == JustifySpaceAround)
1004 return availableFreeSpace / numberOfChildren;
1009 void RenderFlexibleBox::setLogicalOverrideSize(RenderBox* child, LayoutUnit childPreferredSize)
1011 if (hasOrthogonalFlow(child))
1012 child->setOverrideLogicalContentHeight(childPreferredSize - child->borderAndPaddingLogicalHeight());
1014 child->setOverrideLogicalContentWidth(childPreferredSize - child->borderAndPaddingLogicalWidth());
1017 void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox* child, LayoutUnit mainAxisOffset, LayoutUnit crossAxisOffset, PositionedLayoutMode layoutMode)
1019 ASSERT(child->isOutOfFlowPositioned());
1020 child->containingBlock()->insertPositionedObject(child);
1021 RenderLayer* childLayer = child->layer();
1022 LayoutUnit inlinePosition = isColumnFlow() ? crossAxisOffset : mainAxisOffset;
1023 if (layoutMode == FlipForRowReverse && style()->flexDirection() == FlowRowReverse)
1024 inlinePosition = mainAxisExtent() - mainAxisOffset;
1025 childLayer->setStaticInlinePosition(inlinePosition);
1027 LayoutUnit staticBlockPosition = isColumnFlow() ? mainAxisOffset : crossAxisOffset;
1028 if (childLayer->staticBlockPosition() != staticBlockPosition) {
1029 childLayer->setStaticBlockPosition(staticBlockPosition);
1030 if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
1031 child->setChildNeedsLayout(MarkOnlyThis);
1035 ItemPosition RenderFlexibleBox::alignmentForChild(RenderBox* child) const
1037 ItemPosition align = resolveAlignment(style(), child->style());
1039 if (align == ItemPositionBaseline && hasOrthogonalFlow(child))
1040 align = ItemPositionFlexStart;
1042 if (style()->flexWrap() == FlexWrapReverse) {
1043 if (align == ItemPositionFlexStart)
1044 align = ItemPositionFlexEnd;
1045 else if (align == ItemPositionFlexEnd)
1046 align = ItemPositionFlexStart;
1052 size_t RenderFlexibleBox::numberOfInFlowPositionedChildren(const OrderedFlexItemList& children) const
1055 for (size_t i = 0; i < children.size(); ++i) {
1056 RenderBox* child = children[i];
1057 if (!child->isOutOfFlowPositioned())
1063 void RenderFlexibleBox::resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox* child)
1065 if (hasAutoMarginsInCrossAxis(child)) {
1066 child->updateLogicalHeight();
1067 if (isHorizontalFlow()) {
1068 if (child->style()->marginTop().isAuto())
1069 child->setMarginTop(0);
1070 if (child->style()->marginBottom().isAuto())
1071 child->setMarginBottom(0);
1073 if (child->style()->marginLeft().isAuto())
1074 child->setMarginLeft(0);
1075 if (child->style()->marginRight().isAuto())
1076 child->setMarginRight(0);
1081 bool RenderFlexibleBox::needToStretchChildLogicalHeight(RenderBox* child) const
1083 if (alignmentForChild(child) != ItemPositionStretch)
1086 return isHorizontalFlow() && child->style()->height().isAuto();
1089 void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const Vector<LayoutUnit, 16>& childSizes, LayoutUnit availableFreeSpace, bool relayoutChildren, Vector<LineContext>& lineContexts, bool hasInfiniteLineLength)
1091 ASSERT(childSizes.size() == children.size());
1093 size_t numberOfChildrenForJustifyContent = numberOfInFlowPositionedChildren(children);
1094 LayoutUnit autoMarginOffset = autoMarginOffsetInMainAxis(children, availableFreeSpace);
1095 LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart();
1096 mainAxisOffset += initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1097 if (style()->flexDirection() == FlowRowReverse)
1098 mainAxisOffset += isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1100 LayoutUnit totalMainExtent = mainAxisExtent();
1101 LayoutUnit maxAscent = 0, maxDescent = 0; // Used when align-items: baseline.
1102 LayoutUnit maxChildCrossAxisExtent = 0;
1103 size_t seenInFlowPositionedChildren = 0;
1104 bool shouldFlipMainAxis = !isColumnFlow() && !isLeftToRightFlow();
1105 for (size_t i = 0; i < children.size(); ++i) {
1106 RenderBox* child = children[i];
1108 if (child->isOutOfFlowPositioned()) {
1109 prepareChildForPositionedLayout(child, mainAxisOffset, crossAxisOffset, FlipForRowReverse);
1113 // FIXME Investigate if this can be removed based on other flags. crbug.com/370010
1114 child->setMayNeedInvalidation(true);
1116 LayoutUnit childPreferredSize = childSizes[i] + mainAxisBorderAndPaddingExtentForChild(child);
1117 setLogicalOverrideSize(child, childPreferredSize);
1118 if (childPreferredSize != mainAxisExtentForChild(child)) {
1119 child->setChildNeedsLayout(MarkOnlyThis);
1121 // To avoid double applying margin changes in updateAutoMarginsInCrossAxis, we reset the margins here.
1122 resetAutoMarginsAndLogicalTopInCrossAxis(child);
1124 // We may have already forced relayout for orthogonal flowing children in preferredMainAxisContentExtentForChild.
1125 bool forceChildRelayout = relayoutChildren && !childPreferredMainAxisContentExtentRequiresLayout(child, hasInfiniteLineLength);
1126 updateBlockChildDirtyBitsBeforeLayout(forceChildRelayout, child);
1127 child->layoutIfNeeded();
1129 updateAutoMarginsInMainAxis(child, autoMarginOffset);
1131 LayoutUnit childCrossAxisMarginBoxExtent;
1132 if (alignmentForChild(child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(child)) {
1133 LayoutUnit ascent = marginBoxAscentForChild(child);
1134 LayoutUnit descent = (crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child)) - ascent;
1136 maxAscent = std::max(maxAscent, ascent);
1137 maxDescent = std::max(maxDescent, descent);
1139 childCrossAxisMarginBoxExtent = maxAscent + maxDescent;
1141 childCrossAxisMarginBoxExtent = crossAxisIntrinsicExtentForChild(child) + crossAxisMarginExtentForChild(child);
1143 if (!isColumnFlow())
1144 setLogicalHeight(std::max(logicalHeight(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent()));
1145 maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisMarginBoxExtent);
1147 mainAxisOffset += flowAwareMarginStartForChild(child);
1149 LayoutUnit childMainExtent = mainAxisExtentForChild(child);
1150 // In an RTL column situation, this will apply the margin-right/margin-end on the left.
1151 // This will be fixed later in flipForRightToLeftColumn.
1152 LayoutPoint childLocation(shouldFlipMainAxis ? totalMainExtent - mainAxisOffset - childMainExtent : mainAxisOffset,
1153 crossAxisOffset + flowAwareMarginBeforeForChild(child));
1155 // FIXME: Supporting layout deltas.
1156 setFlowAwareLocationForChild(child, childLocation);
1157 mainAxisOffset += childMainExtent + flowAwareMarginEndForChild(child);
1159 ++seenInFlowPositionedChildren;
1160 if (seenInFlowPositionedChildren < numberOfChildrenForJustifyContent)
1161 mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1165 setLogicalHeight(mainAxisOffset + flowAwareBorderEnd() + flowAwarePaddingEnd() + scrollbarLogicalHeight());
1167 if (style()->flexDirection() == FlowColumnReverse) {
1168 // We have to do an extra pass for column-reverse to reposition the flex items since the start depends
1169 // on the height of the flexbox, which we only know after we've positioned all the flex items.
1170 updateLogicalHeight();
1171 layoutColumnReverse(children, crossAxisOffset, availableFreeSpace);
1174 if (m_numberOfInFlowChildrenOnFirstLine == -1)
1175 m_numberOfInFlowChildrenOnFirstLine = seenInFlowPositionedChildren;
1176 lineContexts.append(LineContext(crossAxisOffset, maxChildCrossAxisExtent, children.size(), maxAscent));
1177 crossAxisOffset += maxChildCrossAxisExtent;
1180 void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace)
1182 // This is similar to the logic in layoutAndPlaceChildren, except we place the children
1183 // starting from the end of the flexbox. We also don't need to layout anything since we're
1184 // just moving the children to a new position.
1185 size_t numberOfChildrenForJustifyContent = numberOfInFlowPositionedChildren(children);
1186 LayoutUnit mainAxisOffset = logicalHeight() - flowAwareBorderEnd() - flowAwarePaddingEnd();
1187 mainAxisOffset -= initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1188 mainAxisOffset -= isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1190 size_t seenInFlowPositionedChildren = 0;
1191 for (size_t i = 0; i < children.size(); ++i) {
1192 RenderBox* child = children[i];
1194 if (child->isOutOfFlowPositioned()) {
1195 child->layer()->setStaticBlockPosition(mainAxisOffset);
1198 mainAxisOffset -= mainAxisExtentForChild(child) + flowAwareMarginEndForChild(child);
1200 setFlowAwareLocationForChild(child, LayoutPoint(mainAxisOffset, crossAxisOffset + flowAwareMarginBeforeForChild(child)));
1202 mainAxisOffset -= flowAwareMarginStartForChild(child);
1204 ++seenInFlowPositionedChildren;
1205 if (seenInFlowPositionedChildren < numberOfChildrenForJustifyContent)
1206 mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1210 static LayoutUnit initialAlignContentOffset(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1212 if (alignContent == AlignContentFlexEnd)
1213 return availableFreeSpace;
1214 if (alignContent == AlignContentCenter)
1215 return availableFreeSpace / 2;
1216 if (alignContent == AlignContentSpaceAround) {
1217 if (availableFreeSpace > 0 && numberOfLines)
1218 return availableFreeSpace / (2 * numberOfLines);
1219 if (availableFreeSpace < 0)
1220 return availableFreeSpace / 2;
1225 static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1227 if (availableFreeSpace > 0 && numberOfLines > 1) {
1228 if (alignContent == AlignContentSpaceBetween)
1229 return availableFreeSpace / (numberOfLines - 1);
1230 if (alignContent == AlignContentSpaceAround || alignContent == AlignContentStretch)
1231 return availableFreeSpace / numberOfLines;
1236 void RenderFlexibleBox::alignFlexLines(Vector<LineContext>& lineContexts)
1238 if (!isMultiline() || style()->alignContent() == AlignContentFlexStart)
1241 LayoutUnit availableCrossAxisSpace = crossAxisContentExtent();
1242 for (size_t i = 0; i < lineContexts.size(); ++i)
1243 availableCrossAxisSpace -= lineContexts[i].crossAxisExtent;
1245 RenderBox* child = m_orderIterator.first();
1246 LayoutUnit lineOffset = initialAlignContentOffset(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1247 for (unsigned lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1248 lineContexts[lineNumber].crossAxisOffset += lineOffset;
1249 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next())
1250 adjustAlignmentForChild(child, lineOffset);
1252 if (style()->alignContent() == AlignContentStretch && availableCrossAxisSpace > 0)
1253 lineContexts[lineNumber].crossAxisExtent += availableCrossAxisSpace / static_cast<unsigned>(lineContexts.size());
1255 lineOffset += alignContentSpaceBetweenChildren(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1259 void RenderFlexibleBox::adjustAlignmentForChild(RenderBox* child, LayoutUnit delta)
1261 if (child->isOutOfFlowPositioned()) {
1262 LayoutUnit staticInlinePosition = child->layer()->staticInlinePosition();
1263 LayoutUnit staticBlockPosition = child->layer()->staticBlockPosition();
1264 LayoutUnit mainAxis = isColumnFlow() ? staticBlockPosition : staticInlinePosition;
1265 LayoutUnit crossAxis = isColumnFlow() ? staticInlinePosition : staticBlockPosition;
1267 prepareChildForPositionedLayout(child, mainAxis, crossAxis, NoFlipForRowReverse);
1271 setFlowAwareLocationForChild(child, flowAwareLocationForChild(child) + LayoutSize(0, delta));
1274 void RenderFlexibleBox::alignChildren(const Vector<LineContext>& lineContexts)
1276 // Keep track of the space between the baseline edge and the after edge of the box for each line.
1277 Vector<LayoutUnit> minMarginAfterBaselines;
1279 RenderBox* child = m_orderIterator.first();
1280 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1281 LayoutUnit minMarginAfterBaseline = LayoutUnit::max();
1282 LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1283 LayoutUnit maxAscent = lineContexts[lineNumber].maxAscent;
1285 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
1287 if (child->isOutOfFlowPositioned()) {
1288 if (style()->flexWrap() == FlexWrapReverse)
1289 adjustAlignmentForChild(child, lineCrossAxisExtent);
1293 if (updateAutoMarginsInCrossAxis(child, std::max(LayoutUnit(0), availableAlignmentSpaceForChild(lineCrossAxisExtent, child))))
1296 switch (alignmentForChild(child)) {
1297 case ItemPositionAuto:
1298 ASSERT_NOT_REACHED();
1300 case ItemPositionStretch: {
1301 applyStretchAlignmentToChild(child, lineCrossAxisExtent);
1302 // Since wrap-reverse flips cross start and cross end, strech children should be aligned with the cross end.
1303 if (style()->flexWrap() == FlexWrapReverse)
1304 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
1307 case ItemPositionFlexStart:
1309 case ItemPositionFlexEnd:
1310 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
1312 case ItemPositionCenter:
1313 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) / 2);
1315 case ItemPositionBaseline: {
1316 // 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.
1317 // https://bugs.webkit.org/show_bug.cgi?id=98076
1318 LayoutUnit ascent = marginBoxAscentForChild(child);
1319 LayoutUnit startOffset = maxAscent - ascent;
1320 adjustAlignmentForChild(child, startOffset);
1322 if (style()->flexWrap() == FlexWrapReverse)
1323 minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) - startOffset);
1326 case ItemPositionSelfStart:
1327 case ItemPositionSelfEnd:
1328 case ItemPositionStart:
1329 case ItemPositionEnd:
1330 case ItemPositionLeft:
1331 case ItemPositionRight:
1332 // FIXME: File a bug about implementing that. The extended grammar
1333 // is not enabled by default so we shouldn't hit this codepath.
1334 ASSERT_NOT_REACHED();
1338 minMarginAfterBaselines.append(minMarginAfterBaseline);
1341 if (style()->flexWrap() != FlexWrapReverse)
1344 // wrap-reverse flips the cross axis start and end. For baseline alignment, this means we
1345 // need to align the after edge of baseline elements with the after edge of the flex line.
1346 child = m_orderIterator.first();
1347 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1348 LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber];
1349 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
1351 if (alignmentForChild(child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(child) && minMarginAfterBaseline)
1352 adjustAlignmentForChild(child, minMarginAfterBaseline);
1357 void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox* child, LayoutUnit lineCrossAxisExtent)
1359 if (!isColumnFlow() && child->style()->logicalHeight().isAuto()) {
1360 // FIXME: If the child has orthogonal flow, then it already has an override height set, so use it.
1361 if (!hasOrthogonalFlow(child)) {
1362 LayoutUnit heightBeforeStretching = needToStretchChildLogicalHeight(child) ? constrainedChildIntrinsicContentLogicalHeight(child) : child->logicalHeight();
1363 LayoutUnit stretchedLogicalHeight = heightBeforeStretching + availableAlignmentSpaceForChildBeforeStretching(lineCrossAxisExtent, child);
1364 ASSERT(!child->needsLayout());
1365 LayoutUnit desiredLogicalHeight = child->constrainLogicalHeightByMinMax(stretchedLogicalHeight, heightBeforeStretching - child->borderAndPaddingLogicalHeight());
1367 // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
1368 if (desiredLogicalHeight != child->logicalHeight()) {
1369 child->setOverrideLogicalContentHeight(desiredLogicalHeight - child->borderAndPaddingLogicalHeight());
1370 child->setLogicalHeight(0);
1371 child->forceChildLayout();
1374 } else if (isColumnFlow() && child->style()->logicalWidth().isAuto()) {
1375 // FIXME: If the child doesn't have orthogonal flow, then it already has an override width set, so use it.
1376 if (hasOrthogonalFlow(child)) {
1377 LayoutUnit childWidth = std::max<LayoutUnit>(0, lineCrossAxisExtent - crossAxisMarginExtentForChild(child));
1378 childWidth = child->constrainLogicalWidthByMinMax(childWidth, childWidth, this);
1380 if (childWidth != child->logicalWidth()) {
1381 child->setOverrideLogicalContentWidth(childWidth - child->borderAndPaddingLogicalWidth());
1382 child->forceChildLayout();
1388 void RenderFlexibleBox::flipForRightToLeftColumn()
1390 if (style()->isLeftToRightDirection() || !isColumnFlow())
1393 LayoutUnit crossExtent = crossAxisExtent();
1394 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
1395 if (child->isOutOfFlowPositioned())
1397 LayoutPoint location = flowAwareLocationForChild(child);
1398 // For vertical flows, setFlowAwareLocationForChild will transpose x and y,
1399 // so using the y axis for a column cross axis extent is correct.
1400 location.setY(crossExtent - crossAxisExtentForChild(child) - location.y());
1401 setFlowAwareLocationForChild(child, location);
1405 void RenderFlexibleBox::flipForWrapReverse(const Vector<LineContext>& lineContexts, LayoutUnit crossAxisStartEdge)
1407 LayoutUnit contentExtent = crossAxisContentExtent();
1408 RenderBox* child = m_orderIterator.first();
1409 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1410 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
1412 LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1413 LayoutUnit originalOffset = lineContexts[lineNumber].crossAxisOffset - crossAxisStartEdge;
1414 LayoutUnit newOffset = contentExtent - originalOffset - lineCrossAxisExtent;
1415 adjustAlignmentForChild(child, newOffset - originalOffset);