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 "RenderFlexibleBox.h"
34 #include "LayoutRepainter.h"
35 #include "RenderLayer.h"
36 #include "RenderView.h"
38 #include <wtf/MathExtras.h>
42 class RenderFlexibleBox::OrderIterator {
44 OrderIterator(RenderFlexibleBox* flexibleBox, const OrderHashSet& orderValues)
45 : m_flexibleBox(flexibleBox)
47 , m_orderValuesIterator(0)
49 copyToVector(orderValues, m_orderValues);
50 std::sort(m_orderValues.begin(), m_orderValues.end());
54 RenderBox* currentChild() { return m_currentChild; }
65 if (!m_currentChild) {
66 if (m_orderValuesIterator == m_orderValues.end())
68 if (m_orderValuesIterator) {
69 ++m_orderValuesIterator;
70 if (m_orderValuesIterator == m_orderValues.end())
73 m_orderValuesIterator = m_orderValues.begin();
75 m_currentChild = m_flexibleBox->firstChildBox();
77 m_currentChild = m_currentChild->nextSiblingBox();
78 } while (!m_currentChild || m_currentChild->style()->order() != *m_orderValuesIterator);
80 return m_currentChild;
86 m_orderValuesIterator = 0;
90 RenderFlexibleBox* m_flexibleBox;
91 RenderBox* m_currentChild;
92 Vector<float> m_orderValues;
93 Vector<float>::const_iterator m_orderValuesIterator;
96 struct RenderFlexibleBox::LineContext {
97 LineContext(LayoutUnit crossAxisOffset, LayoutUnit crossAxisExtent, size_t numberOfChildren, LayoutUnit maxAscent)
98 : crossAxisOffset(crossAxisOffset)
99 , crossAxisExtent(crossAxisExtent)
100 , numberOfChildren(numberOfChildren)
101 , maxAscent(maxAscent)
105 LayoutUnit crossAxisOffset;
106 LayoutUnit crossAxisExtent;
107 size_t numberOfChildren;
108 LayoutUnit maxAscent;
111 struct RenderFlexibleBox::Violation {
112 Violation(RenderBox* child, LayoutUnit childSize)
114 , childSize(childSize)
119 LayoutUnit childSize;
123 RenderFlexibleBox::RenderFlexibleBox(Node* node)
126 setChildrenInline(false); // All of our children must be block-level.
129 RenderFlexibleBox::~RenderFlexibleBox()
133 const char* RenderFlexibleBox::renderName() const
135 return "RenderFlexibleBox";
138 static LayoutUnit marginLogicalWidthForChild(RenderBox* child, RenderStyle* parentStyle)
140 // A margin has three types: fixed, percentage, and auto (variable).
141 // Auto and percentage margins become 0 when computing min/max width.
142 // Fixed margins can be added in as is.
143 Length marginLeft = child->style()->marginStartUsing(parentStyle);
144 Length marginRight = child->style()->marginEndUsing(parentStyle);
145 LayoutUnit margin = 0;
146 if (marginLeft.isFixed())
147 margin += marginLeft.value();
148 if (marginRight.isFixed())
149 margin += marginRight.value();
153 void RenderFlexibleBox::computePreferredLogicalWidths()
155 ASSERT(preferredLogicalWidthsDirty());
157 RenderStyle* styleToUse = style();
158 // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for width.
159 if (styleToUse->logicalWidth().isFixed() && styleToUse->logicalWidth().value() > 0)
160 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeContentBoxLogicalWidth(styleToUse->logicalWidth().value());
162 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
164 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
165 if (child->isOutOfFlowPositioned())
168 LayoutUnit margin = marginLogicalWidthForChild(child, style());
169 bool hasOrthogonalWritingMode = child->isHorizontalWritingMode() != isHorizontalWritingMode();
170 LayoutUnit minPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->minPreferredLogicalWidth();
171 LayoutUnit maxPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->maxPreferredLogicalWidth();
172 minPreferredLogicalWidth += margin;
173 maxPreferredLogicalWidth += margin;
174 if (!isColumnFlow()) {
175 m_maxPreferredLogicalWidth += maxPreferredLogicalWidth;
177 // For multiline, the min preferred width is if you put a break between each item.
178 m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, minPreferredLogicalWidth);
180 m_minPreferredLogicalWidth += minPreferredLogicalWidth;
182 m_minPreferredLogicalWidth = std::max(minPreferredLogicalWidth, m_minPreferredLogicalWidth);
184 // For multiline, the max preferred width is if you put a break between each item.
185 m_maxPreferredLogicalWidth += maxPreferredLogicalWidth;
187 m_maxPreferredLogicalWidth = std::max(maxPreferredLogicalWidth, m_maxPreferredLogicalWidth);
191 m_maxPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
194 LayoutUnit scrollbarWidth = 0;
195 if (hasOverflowClip()) {
196 if (isHorizontalWritingMode() && styleToUse->overflowY() == OSCROLL) {
197 layer()->setHasVerticalScrollbar(true);
198 scrollbarWidth = verticalScrollbarWidth();
199 } else if (!isHorizontalWritingMode() && styleToUse->overflowX() == OSCROLL) {
200 layer()->setHasHorizontalScrollbar(true);
201 scrollbarWidth = horizontalScrollbarHeight();
205 m_maxPreferredLogicalWidth += scrollbarWidth;
206 m_minPreferredLogicalWidth += scrollbarWidth;
208 // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for min-width.
209 if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
210 m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(styleToUse->logicalMinWidth().value()));
211 m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(styleToUse->logicalMinWidth().value()));
214 // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for maxWidth.
215 if (styleToUse->logicalMaxWidth().isFixed()) {
216 m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(styleToUse->logicalMaxWidth().value()));
217 m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(styleToUse->logicalMaxWidth().value()));
220 LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
221 m_minPreferredLogicalWidth += borderAndPadding;
222 m_maxPreferredLogicalWidth += borderAndPadding;
224 setPreferredLogicalWidthsDirty(false);
227 void RenderFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
229 ASSERT(needsLayout());
231 if (!relayoutChildren && simplifiedLayout())
234 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
235 LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
237 if (inRenderFlowThread()) {
238 // Regions changing widths can force us to relayout our children.
239 if (logicalWidthChangedInRegions())
240 relayoutChildren = true;
242 computeInitialRegionRangeForBlock();
244 LayoutSize previousSize = size();
247 computeLogicalWidth();
251 // For overflow:scroll blocks, ensure we have both scrollbars in place always.
252 if (scrollsOverflow()) {
253 if (style()->overflowX() == OSCROLL)
254 layer()->setHasHorizontalScrollbar(true);
255 if (style()->overflowY() == OSCROLL)
256 layer()->setHasVerticalScrollbar(true);
259 WTF::Vector<LineContext> lineContexts;
260 OrderHashSet orderValues;
261 computeMainAxisPreferredSizes(relayoutChildren, orderValues);
262 m_orderIterator = adoptPtr(new OrderIterator(this, orderValues));
263 layoutFlexItems(*m_orderIterator, lineContexts);
265 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
266 computeLogicalHeight();
267 repositionLogicalHeightDependentFlexItems(*m_orderIterator, lineContexts, oldClientAfterEdge);
269 if (size() != previousSize)
270 relayoutChildren = true;
272 layoutPositionedObjects(relayoutChildren || isRoot());
274 computeRegionRangeForBlock();
276 // FIXME: css3/flexbox/repaint-rtl-column.html seems to repaint more overflow than it needs to.
277 computeOverflow(oldClientAfterEdge);
280 updateLayerTransform();
282 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
283 // we overflow or not.
284 if (hasOverflowClip())
285 layer()->updateScrollInfoAfterLayout();
287 repainter.repaintAfterLayout();
289 setNeedsLayout(false);
292 void RenderFlexibleBox::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset, PaintInfo& paintInfoForChild, bool usePrintRect)
294 ASSERT(m_orderIterator);
296 for (RenderBox* child = m_orderIterator->first(); child; child = m_orderIterator->next()) {
297 if (!paintChild(child, paintInfo, paintOffset, paintInfoForChild, usePrintRect))
302 void RenderFlexibleBox::repositionLogicalHeightDependentFlexItems(OrderIterator& iterator, WTF::Vector<LineContext>& lineContexts, LayoutUnit& oldClientAfterEdge)
304 LayoutUnit crossAxisStartEdge = lineContexts.isEmpty() ? ZERO_LAYOUT_UNIT : lineContexts[0].crossAxisOffset;
305 alignFlexLines(iterator, lineContexts);
307 // If we have a single line flexbox, the line height is all the available space.
308 // For flex-direction: row, this means we need to use the height, so we do this after calling computeLogicalHeight.
309 if (!isMultiline() && lineContexts.size() == 1)
310 lineContexts[0].crossAxisExtent = crossAxisContentExtent();
311 alignChildren(iterator, lineContexts);
313 if (style()->flexWrap() == FlexWrapReverse) {
314 if (isHorizontalFlow())
315 oldClientAfterEdge = clientLogicalBottom();
316 flipForWrapReverse(iterator, lineContexts, crossAxisStartEdge);
319 // direction:rtl + flex-direction:column means the cross-axis direction is flipped.
320 flipForRightToLeftColumn(iterator);
323 bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox* child) const
325 // FIXME: If the child is a flexbox, then we need to check isHorizontalFlow.
326 return isHorizontalFlow() != child->isHorizontalWritingMode();
329 bool RenderFlexibleBox::isColumnFlow() const
331 return style()->isColumnFlexDirection();
334 bool RenderFlexibleBox::isHorizontalFlow() const
336 if (isHorizontalWritingMode())
337 return !isColumnFlow();
338 return isColumnFlow();
341 bool RenderFlexibleBox::isLeftToRightFlow() const
344 return style()->writingMode() == TopToBottomWritingMode || style()->writingMode() == LeftToRightWritingMode;
345 return style()->isLeftToRightDirection() ^ (style()->flexDirection() == FlowRowReverse);
348 bool RenderFlexibleBox::isMultiline() const
350 return style()->flexWrap() != FlexNoWrap;
353 Length RenderFlexibleBox::flexBasisForChild(RenderBox* child) const
355 Length flexLength = child->style()->flexBasis();
356 if (flexLength.isAuto())
357 flexLength = isHorizontalFlow() ? child->style()->width() : child->style()->height();
361 Length RenderFlexibleBox::crossAxisLength() const
363 return isHorizontalFlow() ? style()->height() : style()->width();
366 void RenderFlexibleBox::setCrossAxisExtent(LayoutUnit extent)
368 if (isHorizontalFlow())
374 LayoutUnit RenderFlexibleBox::crossAxisExtentForChild(RenderBox* child)
376 return isHorizontalFlow() ? child->height() : child->width();
379 LayoutUnit RenderFlexibleBox::mainAxisExtentForChild(RenderBox* child)
381 return isHorizontalFlow() ? child->width() : child->height();
384 LayoutUnit RenderFlexibleBox::crossAxisExtent() const
386 return isHorizontalFlow() ? height() : width();
389 LayoutUnit RenderFlexibleBox::mainAxisExtent() const
391 return isHorizontalFlow() ? width() : height();
394 LayoutUnit RenderFlexibleBox::crossAxisContentExtent() const
396 return isHorizontalFlow() ? contentHeight() : contentWidth();
399 LayoutUnit RenderFlexibleBox::mainAxisContentExtent()
402 return std::max(LayoutUnit(0), computeContentLogicalHeightUsing(MainOrPreferredSize, style()->logicalHeight()));
403 return contentLogicalWidth();
406 WritingMode RenderFlexibleBox::transformedWritingMode() const
408 WritingMode mode = style()->writingMode();
413 case TopToBottomWritingMode:
414 case BottomToTopWritingMode:
415 return style()->isLeftToRightDirection() ? LeftToRightWritingMode : RightToLeftWritingMode;
416 case LeftToRightWritingMode:
417 case RightToLeftWritingMode:
418 return style()->isLeftToRightDirection() ? TopToBottomWritingMode : BottomToTopWritingMode;
420 ASSERT_NOT_REACHED();
421 return TopToBottomWritingMode;
424 LayoutUnit RenderFlexibleBox::flowAwareBorderStart() const
426 if (isHorizontalFlow())
427 return isLeftToRightFlow() ? borderLeft() : borderRight();
428 return isLeftToRightFlow() ? borderTop() : borderBottom();
431 LayoutUnit RenderFlexibleBox::flowAwareBorderEnd() const
433 if (isHorizontalFlow())
434 return isLeftToRightFlow() ? borderRight() : borderLeft();
435 return isLeftToRightFlow() ? borderBottom() : borderTop();
438 LayoutUnit RenderFlexibleBox::flowAwareBorderBefore() const
440 switch (transformedWritingMode()) {
441 case TopToBottomWritingMode:
443 case BottomToTopWritingMode:
444 return borderBottom();
445 case LeftToRightWritingMode:
447 case RightToLeftWritingMode:
448 return borderRight();
450 ASSERT_NOT_REACHED();
454 LayoutUnit RenderFlexibleBox::flowAwareBorderAfter() const
456 switch (transformedWritingMode()) {
457 case TopToBottomWritingMode:
458 return borderBottom();
459 case BottomToTopWritingMode:
461 case LeftToRightWritingMode:
462 return borderRight();
463 case RightToLeftWritingMode:
466 ASSERT_NOT_REACHED();
470 LayoutUnit RenderFlexibleBox::flowAwarePaddingStart() const
472 if (isHorizontalFlow())
473 return isLeftToRightFlow() ? paddingLeft() : paddingRight();
474 return isLeftToRightFlow() ? paddingTop() : paddingBottom();
477 LayoutUnit RenderFlexibleBox::flowAwarePaddingEnd() const
479 if (isHorizontalFlow())
480 return isLeftToRightFlow() ? paddingRight() : paddingLeft();
481 return isLeftToRightFlow() ? paddingBottom() : paddingTop();
484 LayoutUnit RenderFlexibleBox::flowAwarePaddingBefore() const
486 switch (transformedWritingMode()) {
487 case TopToBottomWritingMode:
489 case BottomToTopWritingMode:
490 return paddingBottom();
491 case LeftToRightWritingMode:
492 return paddingLeft();
493 case RightToLeftWritingMode:
494 return paddingRight();
496 ASSERT_NOT_REACHED();
500 LayoutUnit RenderFlexibleBox::flowAwarePaddingAfter() const
502 switch (transformedWritingMode()) {
503 case TopToBottomWritingMode:
504 return paddingBottom();
505 case BottomToTopWritingMode:
507 case LeftToRightWritingMode:
508 return paddingRight();
509 case RightToLeftWritingMode:
510 return paddingLeft();
512 ASSERT_NOT_REACHED();
516 LayoutUnit RenderFlexibleBox::flowAwareMarginStartForChild(RenderBox* child) const
518 if (isHorizontalFlow())
519 return isLeftToRightFlow() ? child->marginLeft() : child->marginRight();
520 return isLeftToRightFlow() ? child->marginTop() : child->marginBottom();
523 LayoutUnit RenderFlexibleBox::flowAwareMarginEndForChild(RenderBox* child) const
525 if (isHorizontalFlow())
526 return isLeftToRightFlow() ? child->marginRight() : child->marginLeft();
527 return isLeftToRightFlow() ? child->marginBottom() : child->marginTop();
530 LayoutUnit RenderFlexibleBox::flowAwareMarginBeforeForChild(RenderBox* child) const
532 switch (transformedWritingMode()) {
533 case TopToBottomWritingMode:
534 return child->marginTop();
535 case BottomToTopWritingMode:
536 return child->marginBottom();
537 case LeftToRightWritingMode:
538 return child->marginLeft();
539 case RightToLeftWritingMode:
540 return child->marginRight();
542 ASSERT_NOT_REACHED();
546 LayoutUnit RenderFlexibleBox::flowAwareMarginAfterForChild(RenderBox* child) const
548 switch (transformedWritingMode()) {
549 case TopToBottomWritingMode:
550 return child->marginBottom();
551 case BottomToTopWritingMode:
552 return child->marginTop();
553 case LeftToRightWritingMode:
554 return child->marginRight();
555 case RightToLeftWritingMode:
556 return child->marginLeft();
558 ASSERT_NOT_REACHED();
559 return marginBottom();
562 LayoutUnit RenderFlexibleBox::crossAxisMarginExtentForChild(RenderBox* child) const
564 return isHorizontalFlow() ? child->marginHeight() : child->marginWidth();
567 LayoutUnit RenderFlexibleBox::crossAxisScrollbarExtent() const
569 return isHorizontalFlow() ? horizontalScrollbarHeight() : verticalScrollbarWidth();
572 LayoutPoint RenderFlexibleBox::flowAwareLocationForChild(RenderBox* child) const
574 return isHorizontalFlow() ? child->location() : child->location().transposedPoint();
577 void RenderFlexibleBox::setFlowAwareLocationForChild(RenderBox* child, const LayoutPoint& location)
579 if (isHorizontalFlow())
580 child->setLocation(location);
582 child->setLocation(location.transposedPoint());
585 LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox* child) const
587 return isHorizontalFlow() ? child->borderAndPaddingWidth() : child->borderAndPaddingHeight();
590 LayoutUnit RenderFlexibleBox::mainAxisScrollbarExtentForChild(RenderBox* child) const
592 return isHorizontalFlow() ? child->verticalScrollbarWidth() : child->horizontalScrollbarHeight();
595 LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* child)
597 Length flexBasis = flexBasisForChild(child);
598 if (flexBasis.isAuto()) {
599 LayoutUnit mainAxisExtent = hasOrthogonalFlow(child) ? child->logicalHeight() : child->maxPreferredLogicalWidth();
600 return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child);
602 return std::max(LayoutUnit(0), minimumValueForLength(flexBasis, mainAxisContentExtent(), view()));
605 LayoutUnit RenderFlexibleBox::computeAvailableFreeSpace(LayoutUnit preferredMainAxisExtent)
607 LayoutUnit contentExtent = 0;
609 contentExtent = mainAxisContentExtent();
610 else if (hasOverrideHeight())
611 contentExtent = overrideLogicalContentHeight();
613 LayoutUnit heightResult = computeContentLogicalHeightUsing(MainOrPreferredSize, style()->logicalHeight());
614 if (heightResult == -1)
615 heightResult = preferredMainAxisExtent;
616 LayoutUnit minHeight = computeContentLogicalHeightUsing(MinSize, style()->logicalMinHeight()); // Leave as -1 if unset.
617 LayoutUnit maxHeight = style()->logicalMaxHeight().isUndefined() ? heightResult : computeContentLogicalHeightUsing(MaxSize, style()->logicalMaxHeight());
619 maxHeight = heightResult;
620 heightResult = std::min(maxHeight, heightResult);
621 heightResult = std::max(minHeight, heightResult);
622 contentExtent = heightResult;
625 return contentExtent - preferredMainAxisExtent;
628 void RenderFlexibleBox::layoutFlexItems(OrderIterator& iterator, WTF::Vector<LineContext>& lineContexts)
630 OrderedFlexItemList orderedChildren;
631 LayoutUnit preferredMainAxisExtent;
633 float totalWeightedFlexShrink;
634 LayoutUnit minMaxAppliedMainAxisExtent;
636 LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
637 while (computeNextFlexLine(iterator, orderedChildren, preferredMainAxisExtent, totalFlexGrow, totalWeightedFlexShrink, minMaxAppliedMainAxisExtent)) {
638 LayoutUnit availableFreeSpace = computeAvailableFreeSpace(preferredMainAxisExtent);
639 FlexSign flexSign = (minMaxAppliedMainAxisExtent < preferredMainAxisExtent + availableFreeSpace) ? PositiveFlexibility : NegativeFlexibility;
640 InflexibleFlexItemSize inflexibleItems;
641 WTF::Vector<LayoutUnit> childSizes;
642 while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, childSizes)) {
643 ASSERT(totalFlexGrow >= 0 && totalWeightedFlexShrink >= 0);
644 ASSERT(inflexibleItems.size() > 0);
647 layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace, lineContexts);
651 LayoutUnit RenderFlexibleBox::autoMarginOffsetInMainAxis(const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace)
653 if (availableFreeSpace <= 0)
656 int numberOfAutoMargins = 0;
657 bool isHorizontal = isHorizontalFlow();
658 for (size_t i = 0; i < children.size(); ++i) {
659 RenderBox* child = children[i];
660 if (child->isOutOfFlowPositioned())
663 if (child->style()->marginLeft().isAuto())
664 ++numberOfAutoMargins;
665 if (child->style()->marginRight().isAuto())
666 ++numberOfAutoMargins;
668 if (child->style()->marginTop().isAuto())
669 ++numberOfAutoMargins;
670 if (child->style()->marginBottom().isAuto())
671 ++numberOfAutoMargins;
674 if (!numberOfAutoMargins)
677 LayoutUnit sizeOfAutoMargin = availableFreeSpace / numberOfAutoMargins;
678 availableFreeSpace = 0;
679 return sizeOfAutoMargin;
682 void RenderFlexibleBox::updateAutoMarginsInMainAxis(RenderBox* child, LayoutUnit autoMarginOffset)
684 if (isHorizontalFlow()) {
685 if (child->style()->marginLeft().isAuto())
686 child->setMarginLeft(autoMarginOffset);
687 if (child->style()->marginRight().isAuto())
688 child->setMarginRight(autoMarginOffset);
690 if (child->style()->marginTop().isAuto())
691 child->setMarginTop(autoMarginOffset);
692 if (child->style()->marginBottom().isAuto())
693 child->setMarginBottom(autoMarginOffset);
697 bool RenderFlexibleBox::hasAutoMarginsInCrossAxis(RenderBox* child)
699 if (isHorizontalFlow())
700 return child->style()->marginTop().isAuto() || child->style()->marginBottom().isAuto();
701 return child->style()->marginLeft().isAuto() || child->style()->marginRight().isAuto();
704 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox* child)
706 LayoutUnit childCrossExtent = 0;
707 if (!child->isOutOfFlowPositioned())
708 childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child);
709 return lineCrossAxisExtent - childCrossExtent;
712 bool RenderFlexibleBox::updateAutoMarginsInCrossAxis(RenderBox* child, LayoutUnit availableAlignmentSpace)
714 bool isHorizontal = isHorizontalFlow();
715 Length start = isHorizontal ? child->style()->marginTop() : child->style()->marginLeft();
716 Length end = isHorizontal ? child->style()->marginBottom() : child->style()->marginRight();
717 if (start.isAuto() && end.isAuto()) {
718 adjustAlignmentForChild(child, availableAlignmentSpace / 2);
720 child->setMarginTop(availableAlignmentSpace / 2);
721 child->setMarginBottom(availableAlignmentSpace / 2);
723 child->setMarginLeft(availableAlignmentSpace / 2);
724 child->setMarginRight(availableAlignmentSpace / 2);
728 if (start.isAuto()) {
729 adjustAlignmentForChild(child, availableAlignmentSpace);
731 child->setMarginTop(availableAlignmentSpace);
733 child->setMarginLeft(availableAlignmentSpace);
738 child->setMarginBottom(availableAlignmentSpace);
740 child->setMarginRight(availableAlignmentSpace);
746 LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(RenderBox* child)
748 LayoutUnit ascent = child->firstLineBoxBaseline();
750 ascent = crossAxisExtentForChild(child) + flowAwareMarginAfterForChild(child);
751 return ascent + flowAwareMarginBeforeForChild(child);
754 void RenderFlexibleBox::computeMainAxisPreferredSizes(bool relayoutChildren, OrderHashSet& orderValues)
756 LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent();
757 RenderView* renderView = view();
758 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
759 orderValues.add(child->style()->order());
761 if (child->isOutOfFlowPositioned())
764 child->clearOverrideSize();
765 // Only need to layout here if we will need to get the logicalHeight of the child in computeNextFlexLine.
766 Length childMainAxisMin = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
767 if (hasOrthogonalFlow(child) && (flexBasisForChild(child).isAuto() || childMainAxisMin.isAuto())) {
768 if (!relayoutChildren)
769 child->setChildNeedsLayout(true);
770 child->layoutIfNeeded();
773 // Before running the flex algorithm, 'auto' has a margin of 0.
774 // Also, if we're not auto sizing, we don't do a layout that computes the start/end margins.
775 if (isHorizontalFlow()) {
776 child->setMarginLeft(minimumValueForLength(child->style()->marginLeft(), flexboxAvailableContentExtent, renderView));
777 child->setMarginRight(minimumValueForLength(child->style()->marginRight(), flexboxAvailableContentExtent, renderView));
779 child->setMarginTop(minimumValueForLength(child->style()->marginTop(), flexboxAvailableContentExtent, renderView));
780 child->setMarginBottom(minimumValueForLength(child->style()->marginBottom(), flexboxAvailableContentExtent, renderView));
785 LayoutUnit RenderFlexibleBox::lineBreakLength()
788 return mainAxisContentExtent();
790 LayoutUnit height = computeContentLogicalHeightUsing(MainOrPreferredSize, style()->logicalHeight());
792 height = MAX_LAYOUT_UNIT;
793 LayoutUnit maxHeight = computeContentLogicalHeightUsing(MaxSize, style()->logicalMaxHeight());
795 height = std::min(height, maxHeight);
799 LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox* child, LayoutUnit childSize, LayoutUnit flexboxAvailableContentExtent)
801 Length max = isHorizontalFlow() ? child->style()->maxWidth() : child->style()->maxHeight();
802 Length min = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
803 RenderView* renderView = view();
804 // FIXME: valueForLength isn't quite right in quirks mode: percentage heights should check parents until a value is found.
805 // https://bugs.webkit.org/show_bug.cgi?id=81809
806 if (max.isSpecified() && childSize > valueForLength(max, flexboxAvailableContentExtent, renderView))
807 childSize = valueForLength(max, flexboxAvailableContentExtent, renderView);
809 if (min.isSpecified() && childSize < valueForLength(min, flexboxAvailableContentExtent, renderView))
810 return valueForLength(min, flexboxAvailableContentExtent, renderView);
812 // FIXME: Support min/max sizes of fit-content, max-content and fill-available.
814 LayoutUnit minContent = hasOrthogonalFlow(child) ? child->logicalHeight() : child->minPreferredLogicalWidth();
815 minContent -= mainAxisBorderAndPaddingExtentForChild(child);
816 return std::max(childSize, minContent);
822 bool RenderFlexibleBox::computeNextFlexLine(OrderIterator& iterator, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalFlexGrow, float& totalWeightedFlexShrink, LayoutUnit& minMaxAppliedMainAxisExtent)
824 orderedChildren.clear();
825 preferredMainAxisExtent = 0;
826 totalFlexGrow = totalWeightedFlexShrink = 0;
827 minMaxAppliedMainAxisExtent = 0;
829 if (!iterator.currentChild())
832 LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent();
833 LayoutUnit lineBreak = lineBreakLength();
835 for (RenderBox* child = iterator.currentChild(); child; child = iterator.next()) {
836 if (child->isOutOfFlowPositioned()) {
837 orderedChildren.append(child);
841 LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(child);
842 LayoutUnit childMainAxisMarginBoxExtent = mainAxisBorderAndPaddingExtentForChild(child) + childMainAxisExtent;
843 childMainAxisMarginBoxExtent += isHorizontalFlow() ? child->marginWidth() : child->marginHeight();
845 if (isMultiline() && preferredMainAxisExtent + childMainAxisMarginBoxExtent > lineBreak && orderedChildren.size() > 0)
847 orderedChildren.append(child);
848 preferredMainAxisExtent += childMainAxisMarginBoxExtent;
849 totalFlexGrow += child->style()->flexGrow();
850 totalWeightedFlexShrink += child->style()->flexShrink() * childMainAxisExtent;
852 LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(child, childMainAxisExtent, flexboxAvailableContentExtent);
853 minMaxAppliedMainAxisExtent += childMinMaxAppliedMainAxisExtent - childMainAxisExtent + childMainAxisMarginBoxExtent;
858 void RenderFlexibleBox::freezeViolations(const WTF::Vector<Violation>& violations, LayoutUnit& availableFreeSpace, float& totalFlexGrow, float& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems)
860 for (size_t i = 0; i < violations.size(); ++i) {
861 RenderBox* child = violations[i].child;
862 LayoutUnit childSize = violations[i].childSize;
863 LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child);
864 availableFreeSpace -= childSize - preferredChildSize;
865 totalFlexGrow -= child->style()->flexGrow();
866 totalWeightedFlexShrink -= child->style()->flexShrink() * preferredChildSize;
867 inflexibleItems.set(child, childSize);
871 // Returns true if we successfully ran the algorithm and sized the flex items.
872 bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, float& totalFlexGrow, float& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, WTF::Vector<LayoutUnit>& childSizes)
875 LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent();
876 LayoutUnit totalViolation = 0;
877 LayoutUnit usedFreeSpace = 0;
878 WTF::Vector<Violation> minViolations;
879 WTF::Vector<Violation> maxViolations;
880 for (size_t i = 0; i < children.size(); ++i) {
881 RenderBox* child = children[i];
882 if (child->isOutOfFlowPositioned()) {
883 childSizes.append(0);
887 if (inflexibleItems.contains(child))
888 childSizes.append(inflexibleItems.get(child));
890 LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child);
891 LayoutUnit childSize = preferredChildSize;
892 if (availableFreeSpace > 0 && totalFlexGrow > 0 && flexSign == PositiveFlexibility && isfinite(totalFlexGrow))
893 childSize += roundedLayoutUnit(availableFreeSpace * child->style()->flexGrow() / totalFlexGrow);
894 else if (availableFreeSpace < 0 && totalWeightedFlexShrink > 0 && flexSign == NegativeFlexibility && isfinite(totalWeightedFlexShrink))
895 childSize += roundedLayoutUnit(availableFreeSpace * child->style()->flexShrink() * preferredChildSize / totalWeightedFlexShrink);
897 LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(child, childSize, flexboxAvailableContentExtent);
898 childSizes.append(adjustedChildSize);
899 usedFreeSpace += adjustedChildSize - preferredChildSize;
901 LayoutUnit violation = adjustedChildSize - childSize;
903 minViolations.append(Violation(child, adjustedChildSize));
904 else if (violation < 0)
905 maxViolations.append(Violation(child, adjustedChildSize));
906 totalViolation += violation;
911 freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems);
913 availableFreeSpace -= usedFreeSpace;
915 return !totalViolation;
918 static LayoutUnit initialJustifyContentOffset(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
920 if (justifyContent == JustifyFlexEnd)
921 return availableFreeSpace;
922 if (justifyContent == JustifyCenter)
923 return availableFreeSpace / 2;
924 if (justifyContent == JustifySpaceAround) {
925 if (availableFreeSpace > 0 && numberOfChildren)
926 return availableFreeSpace / (2 * numberOfChildren);
927 if (availableFreeSpace < 0)
928 return availableFreeSpace / 2;
933 static LayoutUnit justifyContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
935 if (availableFreeSpace > 0 && numberOfChildren > 1) {
936 if (justifyContent == JustifySpaceBetween)
937 return availableFreeSpace / (numberOfChildren - 1);
938 if (justifyContent == JustifySpaceAround)
939 return availableFreeSpace / numberOfChildren;
944 void RenderFlexibleBox::setLogicalOverrideSize(RenderBox* child, LayoutUnit childPreferredSize)
946 if (hasOrthogonalFlow(child))
947 child->setOverrideLogicalContentHeight(childPreferredSize - child->borderAndPaddingLogicalHeight());
949 child->setOverrideLogicalContentWidth(childPreferredSize - child->borderAndPaddingLogicalWidth());
952 void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox* child, LayoutUnit mainAxisOffset, LayoutUnit crossAxisOffset, PositionedLayoutMode layoutMode)
954 ASSERT(child->isOutOfFlowPositioned());
955 child->containingBlock()->insertPositionedObject(child);
956 RenderLayer* childLayer = child->layer();
957 LayoutUnit inlinePosition = isColumnFlow() ? crossAxisOffset : mainAxisOffset;
958 if (layoutMode == FlipForRowReverse && style()->flexDirection() == FlowRowReverse)
959 inlinePosition = mainAxisExtent() - mainAxisOffset;
960 childLayer->setStaticInlinePosition(inlinePosition); // FIXME: Not right for regions.
962 LayoutUnit staticBlockPosition = isColumnFlow() ? mainAxisOffset : crossAxisOffset;
963 if (childLayer->staticBlockPosition() != staticBlockPosition) {
964 childLayer->setStaticBlockPosition(staticBlockPosition);
965 if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
966 child->setChildNeedsLayout(true, MarkOnlyThis);
970 static EAlignItems alignmentForChild(RenderBox* child)
972 EAlignItems align = child->style()->alignSelf();
973 if (align == AlignAuto)
974 align = child->parent()->style()->alignItems();
976 if (child->parent()->style()->flexWrap() == FlexWrapReverse) {
977 if (align == AlignFlexStart)
978 align = AlignFlexEnd;
979 else if (align == AlignFlexEnd)
980 align = AlignFlexStart;
986 void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace, WTF::Vector<LineContext>& lineContexts)
988 ASSERT(childSizes.size() == children.size());
990 LayoutUnit autoMarginOffset = autoMarginOffsetInMainAxis(children, availableFreeSpace);
991 LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart();
992 mainAxisOffset += initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), childSizes.size());
993 if (style()->flexDirection() == FlowRowReverse)
994 mainAxisOffset += isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
996 LayoutUnit totalMainExtent = mainAxisExtent();
997 LayoutUnit maxAscent = 0, maxDescent = 0; // Used when align-items: baseline.
998 LayoutUnit maxChildCrossAxisExtent = 0;
999 bool shouldFlipMainAxis = !isColumnFlow() && !isLeftToRightFlow();
1000 for (size_t i = 0; i < children.size(); ++i) {
1001 RenderBox* child = children[i];
1002 if (child->isOutOfFlowPositioned()) {
1003 prepareChildForPositionedLayout(child, mainAxisOffset, crossAxisOffset, FlipForRowReverse);
1004 mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), childSizes.size());
1007 LayoutUnit childPreferredSize = childSizes[i] + mainAxisBorderAndPaddingExtentForChild(child);
1008 setLogicalOverrideSize(child, childPreferredSize);
1009 // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
1010 child->setChildNeedsLayout(true);
1011 child->layoutIfNeeded();
1013 updateAutoMarginsInMainAxis(child, autoMarginOffset);
1015 LayoutUnit childCrossAxisMarginBoxExtent;
1016 if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child)) {
1017 LayoutUnit ascent = marginBoxAscentForChild(child);
1018 LayoutUnit descent = (crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child)) - ascent;
1020 maxAscent = std::max(maxAscent, ascent);
1021 maxDescent = std::max(maxDescent, descent);
1023 childCrossAxisMarginBoxExtent = maxAscent + maxDescent;
1025 childCrossAxisMarginBoxExtent = crossAxisExtentForChild(child) + crossAxisMarginExtentForChild(child);
1026 if (!isColumnFlow() && style()->logicalHeight().isAuto())
1027 setLogicalHeight(std::max(logicalHeight(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent()));
1028 maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisMarginBoxExtent);
1030 mainAxisOffset += flowAwareMarginStartForChild(child);
1032 LayoutUnit childMainExtent = mainAxisExtentForChild(child);
1033 LayoutPoint childLocation(shouldFlipMainAxis ? totalMainExtent - mainAxisOffset - childMainExtent : mainAxisOffset,
1034 crossAxisOffset + flowAwareMarginBeforeForChild(child));
1036 // FIXME: Supporting layout deltas.
1037 setFlowAwareLocationForChild(child, childLocation);
1038 mainAxisOffset += childMainExtent + flowAwareMarginEndForChild(child);
1040 mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), childSizes.size());
1044 setLogicalHeight(mainAxisOffset + flowAwareBorderEnd() + flowAwarePaddingEnd() + scrollbarLogicalHeight());
1046 if (style()->flexDirection() == FlowColumnReverse) {
1047 // We have to do an extra pass for column-reverse to reposition the flex items since the start depends
1048 // on the height of the flexbox, which we only know after we've positioned all the flex items.
1049 computeLogicalHeight();
1050 layoutColumnReverse(children, childSizes, crossAxisOffset, availableFreeSpace);
1053 lineContexts.append(LineContext(crossAxisOffset, maxChildCrossAxisExtent, children.size(), maxAscent));
1054 crossAxisOffset += maxChildCrossAxisExtent;
1057 void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace)
1059 // This is similar to the logic in layoutAndPlaceChildren, except we place the children
1060 // starting from the end of the flexbox. We also don't need to layout anything since we're
1061 // just moving the children to a new position.
1062 LayoutUnit mainAxisOffset = logicalHeight() - flowAwareBorderEnd() - flowAwarePaddingEnd();
1063 mainAxisOffset -= initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), childSizes.size());
1064 mainAxisOffset -= isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1066 for (size_t i = 0; i < children.size(); ++i) {
1067 RenderBox* child = children[i];
1068 if (child->isOutOfFlowPositioned()) {
1069 child->layer()->setStaticBlockPosition(mainAxisOffset);
1070 mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), childSizes.size());
1073 mainAxisOffset -= mainAxisExtentForChild(child) + flowAwareMarginEndForChild(child);
1075 LayoutRect oldRect = child->frameRect();
1076 setFlowAwareLocationForChild(child, LayoutPoint(mainAxisOffset, crossAxisOffset + flowAwareMarginBeforeForChild(child)));
1077 if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
1078 child->repaintDuringLayoutIfMoved(oldRect);
1080 mainAxisOffset -= flowAwareMarginStartForChild(child);
1081 mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), childSizes.size());
1085 static LayoutUnit initialAlignContentOffset(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1087 if (alignContent == AlignContentFlexEnd)
1088 return availableFreeSpace;
1089 if (alignContent == AlignContentCenter)
1090 return availableFreeSpace / 2;
1091 if (alignContent == AlignContentSpaceAround) {
1092 if (availableFreeSpace > 0 && numberOfLines)
1093 return availableFreeSpace / (2 * numberOfLines);
1094 if (availableFreeSpace < 0)
1095 return availableFreeSpace / 2;
1100 static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1102 if (availableFreeSpace > 0 && numberOfLines > 1) {
1103 if (alignContent == AlignContentSpaceBetween)
1104 return availableFreeSpace / (numberOfLines - 1);
1105 if (alignContent == AlignContentSpaceAround || alignContent == AlignContentStretch)
1106 return availableFreeSpace / numberOfLines;
1111 void RenderFlexibleBox::alignFlexLines(OrderIterator& iterator, WTF::Vector<LineContext>& lineContexts)
1113 if (!isMultiline() || style()->alignContent() == AlignContentFlexStart)
1116 LayoutUnit availableCrossAxisSpace = crossAxisContentExtent();
1117 for (size_t i = 0; i < lineContexts.size(); ++i)
1118 availableCrossAxisSpace -= lineContexts[i].crossAxisExtent;
1120 RenderBox* child = iterator.first();
1121 LayoutUnit lineOffset = initialAlignContentOffset(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1122 for (unsigned lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1123 lineContexts[lineNumber].crossAxisOffset += lineOffset;
1124 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next())
1125 adjustAlignmentForChild(child, lineOffset);
1127 if (style()->alignContent() == AlignContentStretch && availableCrossAxisSpace > 0)
1128 lineContexts[lineNumber].crossAxisExtent += availableCrossAxisSpace / static_cast<unsigned>(lineContexts.size());
1130 lineOffset += alignContentSpaceBetweenChildren(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1134 void RenderFlexibleBox::adjustAlignmentForChild(RenderBox* child, LayoutUnit delta)
1136 if (child->isOutOfFlowPositioned()) {
1137 LayoutUnit staticInlinePosition = child->layer()->staticInlinePosition();
1138 LayoutUnit staticBlockPosition = child->layer()->staticBlockPosition();
1139 LayoutUnit mainAxis = isColumnFlow() ? staticBlockPosition : staticInlinePosition;
1140 LayoutUnit crossAxis = isColumnFlow() ? staticInlinePosition : staticBlockPosition;
1142 prepareChildForPositionedLayout(child, mainAxis, crossAxis, NoFlipForRowReverse);
1146 LayoutRect oldRect = child->frameRect();
1147 setFlowAwareLocationForChild(child, flowAwareLocationForChild(child) + LayoutSize(0, delta));
1149 // If the child moved, we have to repaint it as well as any floating/positioned
1150 // descendants. An exception is if we need a layout. In this case, we know we're going to
1151 // repaint ourselves (and the child) anyway.
1152 if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
1153 child->repaintDuringLayoutIfMoved(oldRect);
1156 void RenderFlexibleBox::alignChildren(OrderIterator& iterator, const WTF::Vector<LineContext>& lineContexts)
1158 // Keep track of the space between the baseline edge and the after edge of the box for each line.
1159 WTF::Vector<LayoutUnit> minMarginAfterBaselines;
1161 RenderBox* child = iterator.first();
1162 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1163 LayoutUnit minMarginAfterBaseline = MAX_LAYOUT_UNIT;
1164 LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1165 LayoutUnit maxAscent = lineContexts[lineNumber].maxAscent;
1167 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) {
1169 if (updateAutoMarginsInCrossAxis(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child)))
1172 switch (alignmentForChild(child)) {
1174 ASSERT_NOT_REACHED();
1176 case AlignStretch: {
1177 applyStretchAlignmentToChild(child, lineCrossAxisExtent);
1178 // Since wrap-reverse flips cross start and cross end, strech children should be aligned with the cross end.
1179 if (style()->flexWrap() == FlexWrapReverse)
1180 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
1183 case AlignFlexStart:
1186 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
1189 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) / 2);
1191 case AlignBaseline: {
1192 LayoutUnit ascent = marginBoxAscentForChild(child);
1193 LayoutUnit startOffset = maxAscent - ascent;
1194 adjustAlignmentForChild(child, startOffset);
1196 if (style()->flexWrap() == FlexWrapReverse)
1197 minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) - startOffset);
1202 minMarginAfterBaselines.append(minMarginAfterBaseline);
1205 if (style()->flexWrap() != FlexWrapReverse)
1208 // wrap-reverse flips the cross axis start and end. For baseline alignment, this means we
1209 // need to align the after edge of baseline elements with the after edge of the flex line.
1210 child = iterator.first();
1211 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1212 LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber];
1213 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) {
1215 if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child) && minMarginAfterBaseline)
1216 adjustAlignmentForChild(child, minMarginAfterBaseline);
1221 void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox* child, LayoutUnit lineCrossAxisExtent)
1223 if (!isColumnFlow() && child->style()->logicalHeight().isAuto()) {
1224 LayoutUnit logicalHeightBefore = child->logicalHeight();
1225 LayoutUnit stretchedLogicalHeight = child->logicalHeight() + availableAlignmentSpaceForChild(lineCrossAxisExtent, child);
1227 child->setLogicalHeight(stretchedLogicalHeight);
1228 child->computeLogicalHeight();
1230 // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
1231 if (child->logicalHeight() != logicalHeightBefore) {
1232 child->setOverrideLogicalContentHeight(child->logicalHeight() - child->borderAndPaddingLogicalHeight());
1233 child->setLogicalHeight(0);
1234 child->setChildNeedsLayout(true);
1235 child->layoutIfNeeded();
1237 } else if (isColumnFlow() && child->style()->logicalWidth().isAuto() && isMultiline()) {
1238 // FIXME: Handle min-width and max-width.
1239 LayoutUnit childWidth = lineCrossAxisExtent - crossAxisMarginExtentForChild(child);
1240 child->setOverrideLogicalContentWidth(std::max(ZERO_LAYOUT_UNIT, childWidth));
1241 child->setChildNeedsLayout(true);
1242 child->layoutIfNeeded();
1246 void RenderFlexibleBox::flipForRightToLeftColumn(OrderIterator& iterator)
1248 if (style()->isLeftToRightDirection() || !isColumnFlow())
1251 LayoutUnit crossExtent = crossAxisExtent();
1252 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
1253 if (child->isOutOfFlowPositioned())
1255 LayoutPoint location = flowAwareLocationForChild(child);
1256 location.setY(crossExtent - crossAxisExtentForChild(child) - location.y());
1257 setFlowAwareLocationForChild(child, location);
1261 void RenderFlexibleBox::flipForWrapReverse(OrderIterator& iterator, const WTF::Vector<LineContext>& lineContexts, LayoutUnit crossAxisStartEdge)
1263 LayoutUnit contentExtent = crossAxisContentExtent();
1264 RenderBox* child = iterator.first();
1265 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1266 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) {
1268 LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1269 LayoutUnit originalOffset = lineContexts[lineNumber].crossAxisOffset - crossAxisStartEdge;
1270 LayoutUnit newOffset = contentExtent - originalOffset - lineCrossAxisExtent;
1271 adjustAlignmentForChild(child, newOffset - originalOffset);