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 // Normally, -1 and 0 are not valid in a HashSet, but these are relatively likely order: values. Instead,
43 // we make the two smallest int values invalid order: values (in the css parser code we clamp them to
45 struct RenderFlexibleBox::OrderHashTraits : WTF::GenericHashTraits<int> {
46 static const bool emptyValueIsZero = false;
47 static int emptyValue() { return std::numeric_limits<int>::min(); }
48 static void constructDeletedValue(int& slot) { slot = std::numeric_limits<int>::min() + 1; }
49 static bool isDeletedValue(int value) { return value == std::numeric_limits<int>::min() + 1; }
52 class RenderFlexibleBox::OrderIterator {
54 OrderIterator(RenderFlexibleBox* flexibleBox, const OrderHashSet& orderValues)
55 : m_flexibleBox(flexibleBox)
57 , m_orderValuesIterator(0)
59 copyToVector(orderValues, m_orderValues);
60 std::sort(m_orderValues.begin(), m_orderValues.end());
64 RenderBox* currentChild() { return m_currentChild; }
75 if (!m_currentChild) {
76 if (m_orderValuesIterator == m_orderValues.end())
78 if (m_orderValuesIterator) {
79 ++m_orderValuesIterator;
80 if (m_orderValuesIterator == m_orderValues.end())
83 m_orderValuesIterator = m_orderValues.begin();
85 m_currentChild = m_flexibleBox->firstChildBox();
87 m_currentChild = m_currentChild->nextSiblingBox();
88 } while (!m_currentChild || m_currentChild->style()->order() != *m_orderValuesIterator);
90 return m_currentChild;
96 m_orderValuesIterator = 0;
100 RenderFlexibleBox* m_flexibleBox;
101 RenderBox* m_currentChild;
102 Vector<int> m_orderValues;
103 Vector<int>::const_iterator m_orderValuesIterator;
106 struct RenderFlexibleBox::LineContext {
107 LineContext(LayoutUnit crossAxisOffset, LayoutUnit crossAxisExtent, size_t numberOfChildren, LayoutUnit maxAscent)
108 : crossAxisOffset(crossAxisOffset)
109 , crossAxisExtent(crossAxisExtent)
110 , numberOfChildren(numberOfChildren)
111 , maxAscent(maxAscent)
115 LayoutUnit crossAxisOffset;
116 LayoutUnit crossAxisExtent;
117 size_t numberOfChildren;
118 LayoutUnit maxAscent;
121 struct RenderFlexibleBox::Violation {
122 Violation(RenderBox* child, LayoutUnit childSize)
124 , childSize(childSize)
129 LayoutUnit childSize;
133 RenderFlexibleBox::RenderFlexibleBox(Node* node)
136 setChildrenInline(false); // All of our children must be block-level.
139 RenderFlexibleBox::~RenderFlexibleBox()
143 const char* RenderFlexibleBox::renderName() const
145 return "RenderFlexibleBox";
148 static LayoutUnit marginLogicalWidthForChild(RenderBox* child, RenderStyle* parentStyle)
150 // A margin has three types: fixed, percentage, and auto (variable).
151 // Auto and percentage margins become 0 when computing min/max width.
152 // Fixed margins can be added in as is.
153 Length marginLeft = child->style()->marginStartUsing(parentStyle);
154 Length marginRight = child->style()->marginEndUsing(parentStyle);
155 LayoutUnit margin = 0;
156 if (marginLeft.isFixed())
157 margin += marginLeft.value();
158 if (marginRight.isFixed())
159 margin += marginRight.value();
163 void RenderFlexibleBox::computePreferredLogicalWidths()
165 ASSERT(preferredLogicalWidthsDirty());
167 RenderStyle* styleToUse = style();
168 // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for width.
169 if (styleToUse->logicalWidth().isFixed() && styleToUse->logicalWidth().value() > 0)
170 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalWidth().value());
172 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
174 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
175 if (child->isOutOfFlowPositioned())
178 LayoutUnit margin = marginLogicalWidthForChild(child, style());
179 bool hasOrthogonalWritingMode = child->isHorizontalWritingMode() != isHorizontalWritingMode();
180 LayoutUnit minPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->minPreferredLogicalWidth();
181 LayoutUnit maxPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->maxPreferredLogicalWidth();
182 minPreferredLogicalWidth += margin;
183 maxPreferredLogicalWidth += margin;
184 if (!isColumnFlow()) {
185 m_maxPreferredLogicalWidth += maxPreferredLogicalWidth;
187 // For multiline, the min preferred width is if you put a break between each item.
188 m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, minPreferredLogicalWidth);
190 m_minPreferredLogicalWidth += minPreferredLogicalWidth;
192 m_minPreferredLogicalWidth = std::max(minPreferredLogicalWidth, m_minPreferredLogicalWidth);
194 // For multiline, the max preferred width is if you put a break between each item.
195 m_maxPreferredLogicalWidth += maxPreferredLogicalWidth;
197 m_maxPreferredLogicalWidth = std::max(maxPreferredLogicalWidth, m_maxPreferredLogicalWidth);
201 m_maxPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
204 LayoutUnit scrollbarWidth = 0;
205 if (hasOverflowClip()) {
206 if (isHorizontalWritingMode() && styleToUse->overflowY() == OSCROLL) {
207 ASSERT(layer()->hasVerticalScrollbar());
208 scrollbarWidth = verticalScrollbarWidth();
209 } else if (!isHorizontalWritingMode() && styleToUse->overflowX() == OSCROLL) {
210 ASSERT(layer()->hasHorizontalScrollbar());
211 scrollbarWidth = horizontalScrollbarHeight();
215 m_maxPreferredLogicalWidth += scrollbarWidth;
216 m_minPreferredLogicalWidth += scrollbarWidth;
218 // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for min-width.
219 if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
220 m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
221 m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
224 // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for maxWidth.
225 if (styleToUse->logicalMaxWidth().isFixed()) {
226 m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
227 m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
230 LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
231 m_minPreferredLogicalWidth += borderAndPadding;
232 m_maxPreferredLogicalWidth += borderAndPadding;
234 setPreferredLogicalWidthsDirty(false);
237 void RenderFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
239 ASSERT(needsLayout());
241 if (!relayoutChildren && simplifiedLayout())
244 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
245 LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
247 if (inRenderFlowThread()) {
248 // Regions changing widths can force us to relayout our children.
249 if (logicalWidthChangedInRegions())
250 relayoutChildren = true;
252 computeInitialRegionRangeForBlock();
254 LayoutSize previousSize = size();
257 updateLogicalWidth();
261 WTF::Vector<LineContext> lineContexts;
262 OrderHashSet orderValues;
263 computeMainAxisPreferredSizes(relayoutChildren, orderValues);
264 m_orderIterator = adoptPtr(new OrderIterator(this, orderValues));
265 layoutFlexItems(*m_orderIterator, lineContexts);
267 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
268 updateLogicalHeight();
269 repositionLogicalHeightDependentFlexItems(*m_orderIterator, lineContexts, oldClientAfterEdge);
271 if (size() != previousSize)
272 relayoutChildren = true;
274 layoutPositionedObjects(relayoutChildren || isRoot());
276 computeRegionRangeForBlock();
278 // FIXME: css3/flexbox/repaint-rtl-column.html seems to repaint more overflow than it needs to.
279 computeOverflow(oldClientAfterEdge);
282 updateLayerTransform();
284 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
285 // we overflow or not.
286 if (hasOverflowClip())
287 layer()->updateScrollInfoAfterLayout();
289 repainter.repaintAfterLayout();
291 setNeedsLayout(false);
294 void RenderFlexibleBox::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset, PaintInfo& paintInfoForChild, bool usePrintRect)
296 ASSERT(m_orderIterator);
298 for (RenderBox* child = m_orderIterator->first(); child; child = m_orderIterator->next()) {
299 if (!paintChild(child, paintInfo, paintOffset, paintInfoForChild, usePrintRect))
304 void RenderFlexibleBox::repositionLogicalHeightDependentFlexItems(OrderIterator& iterator, WTF::Vector<LineContext>& lineContexts, LayoutUnit& oldClientAfterEdge)
306 LayoutUnit crossAxisStartEdge = lineContexts.isEmpty() ? ZERO_LAYOUT_UNIT : lineContexts[0].crossAxisOffset;
307 alignFlexLines(iterator, lineContexts);
309 // If we have a single line flexbox, the line height is all the available space.
310 // For flex-direction: row, this means we need to use the height, so we do this after calling updateLogicalHeight.
311 if (!isMultiline() && lineContexts.size() == 1)
312 lineContexts[0].crossAxisExtent = crossAxisContentExtent();
313 alignChildren(iterator, lineContexts);
315 if (style()->flexWrap() == FlexWrapReverse) {
316 if (isHorizontalFlow())
317 oldClientAfterEdge = clientLogicalBottom();
318 flipForWrapReverse(iterator, lineContexts, crossAxisStartEdge);
321 // direction:rtl + flex-direction:column means the cross-axis direction is flipped.
322 flipForRightToLeftColumn(iterator);
325 bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox* child) const
327 // FIXME: If the child is a flexbox, then we need to check isHorizontalFlow.
328 return isHorizontalFlow() != child->isHorizontalWritingMode();
331 bool RenderFlexibleBox::isColumnFlow() const
333 return style()->isColumnFlexDirection();
336 bool RenderFlexibleBox::isHorizontalFlow() const
338 if (isHorizontalWritingMode())
339 return !isColumnFlow();
340 return isColumnFlow();
343 bool RenderFlexibleBox::isLeftToRightFlow() const
346 return style()->writingMode() == TopToBottomWritingMode || style()->writingMode() == LeftToRightWritingMode;
347 return style()->isLeftToRightDirection() ^ (style()->flexDirection() == FlowRowReverse);
350 bool RenderFlexibleBox::isMultiline() const
352 return style()->flexWrap() != FlexWrapNone;
355 Length RenderFlexibleBox::flexBasisForChild(RenderBox* child) const
357 Length flexLength = child->style()->flexBasis();
358 if (flexLength.isAuto())
359 flexLength = isHorizontalFlow() ? child->style()->width() : child->style()->height();
363 void RenderFlexibleBox::setCrossAxisExtent(LayoutUnit extent)
365 if (isHorizontalFlow())
371 LayoutUnit RenderFlexibleBox::crossAxisExtentForChild(RenderBox* child)
373 return isHorizontalFlow() ? child->height() : child->width();
376 LayoutUnit RenderFlexibleBox::mainAxisExtentForChild(RenderBox* child)
378 return isHorizontalFlow() ? child->width() : child->height();
381 LayoutUnit RenderFlexibleBox::crossAxisExtent() const
383 return isHorizontalFlow() ? height() : width();
386 LayoutUnit RenderFlexibleBox::mainAxisExtent() const
388 return isHorizontalFlow() ? width() : height();
391 LayoutUnit RenderFlexibleBox::crossAxisContentExtent() const
393 return isHorizontalFlow() ? contentHeight() : contentWidth();
396 LayoutUnit RenderFlexibleBox::mainAxisContentExtent(LayoutUnit contentLogicalHeight)
398 if (isColumnFlow()) {
399 LogicalExtentComputedValues computedValues;
400 computeLogicalHeight(contentLogicalHeight, logicalTop(), computedValues);
401 return std::max(LayoutUnit(0), computedValues.m_extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight());
403 return contentLogicalWidth();
406 LayoutUnit RenderFlexibleBox::computeMainAxisExtentForChild(RenderBox* child, SizeType sizeType, const Length& size)
408 // FIXME: This is wrong for orthogonal flows. It should use the flexbox's writing-mode, not the child's in order
409 // to figure out the logical height/width.
411 return child->computeContentLogicalHeight(sizeType, size);
412 return child->adjustContentBoxLogicalWidthForBoxSizing(valueForLength(size, contentLogicalWidth(), view()));
415 WritingMode RenderFlexibleBox::transformedWritingMode() const
417 WritingMode mode = style()->writingMode();
422 case TopToBottomWritingMode:
423 case BottomToTopWritingMode:
424 return style()->isLeftToRightDirection() ? LeftToRightWritingMode : RightToLeftWritingMode;
425 case LeftToRightWritingMode:
426 case RightToLeftWritingMode:
427 return style()->isLeftToRightDirection() ? TopToBottomWritingMode : BottomToTopWritingMode;
429 ASSERT_NOT_REACHED();
430 return TopToBottomWritingMode;
433 LayoutUnit RenderFlexibleBox::flowAwareBorderStart() const
435 if (isHorizontalFlow())
436 return isLeftToRightFlow() ? borderLeft() : borderRight();
437 return isLeftToRightFlow() ? borderTop() : borderBottom();
440 LayoutUnit RenderFlexibleBox::flowAwareBorderEnd() const
442 if (isHorizontalFlow())
443 return isLeftToRightFlow() ? borderRight() : borderLeft();
444 return isLeftToRightFlow() ? borderBottom() : borderTop();
447 LayoutUnit RenderFlexibleBox::flowAwareBorderBefore() const
449 switch (transformedWritingMode()) {
450 case TopToBottomWritingMode:
452 case BottomToTopWritingMode:
453 return borderBottom();
454 case LeftToRightWritingMode:
456 case RightToLeftWritingMode:
457 return borderRight();
459 ASSERT_NOT_REACHED();
463 LayoutUnit RenderFlexibleBox::flowAwareBorderAfter() const
465 switch (transformedWritingMode()) {
466 case TopToBottomWritingMode:
467 return borderBottom();
468 case BottomToTopWritingMode:
470 case LeftToRightWritingMode:
471 return borderRight();
472 case RightToLeftWritingMode:
475 ASSERT_NOT_REACHED();
479 LayoutUnit RenderFlexibleBox::flowAwarePaddingStart() const
481 if (isHorizontalFlow())
482 return isLeftToRightFlow() ? paddingLeft() : paddingRight();
483 return isLeftToRightFlow() ? paddingTop() : paddingBottom();
486 LayoutUnit RenderFlexibleBox::flowAwarePaddingEnd() const
488 if (isHorizontalFlow())
489 return isLeftToRightFlow() ? paddingRight() : paddingLeft();
490 return isLeftToRightFlow() ? paddingBottom() : paddingTop();
493 LayoutUnit RenderFlexibleBox::flowAwarePaddingBefore() const
495 switch (transformedWritingMode()) {
496 case TopToBottomWritingMode:
498 case BottomToTopWritingMode:
499 return paddingBottom();
500 case LeftToRightWritingMode:
501 return paddingLeft();
502 case RightToLeftWritingMode:
503 return paddingRight();
505 ASSERT_NOT_REACHED();
509 LayoutUnit RenderFlexibleBox::flowAwarePaddingAfter() const
511 switch (transformedWritingMode()) {
512 case TopToBottomWritingMode:
513 return paddingBottom();
514 case BottomToTopWritingMode:
516 case LeftToRightWritingMode:
517 return paddingRight();
518 case RightToLeftWritingMode:
519 return paddingLeft();
521 ASSERT_NOT_REACHED();
525 LayoutUnit RenderFlexibleBox::flowAwareMarginStartForChild(RenderBox* child) const
527 if (isHorizontalFlow())
528 return isLeftToRightFlow() ? child->marginLeft() : child->marginRight();
529 return isLeftToRightFlow() ? child->marginTop() : child->marginBottom();
532 LayoutUnit RenderFlexibleBox::flowAwareMarginEndForChild(RenderBox* child) const
534 if (isHorizontalFlow())
535 return isLeftToRightFlow() ? child->marginRight() : child->marginLeft();
536 return isLeftToRightFlow() ? child->marginBottom() : child->marginTop();
539 LayoutUnit RenderFlexibleBox::flowAwareMarginBeforeForChild(RenderBox* child) const
541 switch (transformedWritingMode()) {
542 case TopToBottomWritingMode:
543 return child->marginTop();
544 case BottomToTopWritingMode:
545 return child->marginBottom();
546 case LeftToRightWritingMode:
547 return child->marginLeft();
548 case RightToLeftWritingMode:
549 return child->marginRight();
551 ASSERT_NOT_REACHED();
555 LayoutUnit RenderFlexibleBox::flowAwareMarginAfterForChild(RenderBox* child) const
557 switch (transformedWritingMode()) {
558 case TopToBottomWritingMode:
559 return child->marginBottom();
560 case BottomToTopWritingMode:
561 return child->marginTop();
562 case LeftToRightWritingMode:
563 return child->marginRight();
564 case RightToLeftWritingMode:
565 return child->marginLeft();
567 ASSERT_NOT_REACHED();
568 return marginBottom();
571 LayoutUnit RenderFlexibleBox::crossAxisMarginExtentForChild(RenderBox* child) const
573 return isHorizontalFlow() ? child->marginHeight() : child->marginWidth();
576 LayoutUnit RenderFlexibleBox::crossAxisScrollbarExtent() const
578 return isHorizontalFlow() ? horizontalScrollbarHeight() : verticalScrollbarWidth();
581 LayoutPoint RenderFlexibleBox::flowAwareLocationForChild(RenderBox* child) const
583 return isHorizontalFlow() ? child->location() : child->location().transposedPoint();
586 void RenderFlexibleBox::setFlowAwareLocationForChild(RenderBox* child, const LayoutPoint& location)
588 if (isHorizontalFlow())
589 child->setLocation(location);
591 child->setLocation(location.transposedPoint());
594 LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox* child) const
596 return isHorizontalFlow() ? child->borderAndPaddingWidth() : child->borderAndPaddingHeight();
599 LayoutUnit RenderFlexibleBox::mainAxisScrollbarExtentForChild(RenderBox* child) const
601 return isHorizontalFlow() ? child->verticalScrollbarWidth() : child->horizontalScrollbarHeight();
604 LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* child)
606 Length flexBasis = flexBasisForChild(child);
607 if (flexBasis.isAuto()) {
608 LayoutUnit mainAxisExtent = hasOrthogonalFlow(child) ? child->logicalHeight() : child->maxPreferredLogicalWidth();
609 return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child);
611 return std::max(LayoutUnit(0), computeMainAxisExtentForChild(child, MainOrPreferredSize, flexBasis));
614 void RenderFlexibleBox::layoutFlexItems(OrderIterator& iterator, WTF::Vector<LineContext>& lineContexts)
616 OrderedFlexItemList orderedChildren;
617 LayoutUnit preferredMainAxisExtent;
619 float totalWeightedFlexShrink;
620 LayoutUnit minMaxAppliedMainAxisExtent;
622 LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
623 while (computeNextFlexLine(iterator, orderedChildren, preferredMainAxisExtent, totalFlexGrow, totalWeightedFlexShrink, minMaxAppliedMainAxisExtent)) {
624 LayoutUnit availableFreeSpace = mainAxisContentExtent(preferredMainAxisExtent) - preferredMainAxisExtent;
625 FlexSign flexSign = (minMaxAppliedMainAxisExtent < preferredMainAxisExtent + availableFreeSpace) ? PositiveFlexibility : NegativeFlexibility;
626 InflexibleFlexItemSize inflexibleItems;
627 WTF::Vector<LayoutUnit> childSizes;
628 while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, childSizes)) {
629 ASSERT(totalFlexGrow >= 0 && totalWeightedFlexShrink >= 0);
630 ASSERT(inflexibleItems.size() > 0);
633 layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace, lineContexts);
637 LayoutUnit RenderFlexibleBox::autoMarginOffsetInMainAxis(const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace)
639 if (availableFreeSpace <= 0)
642 int numberOfAutoMargins = 0;
643 bool isHorizontal = isHorizontalFlow();
644 for (size_t i = 0; i < children.size(); ++i) {
645 RenderBox* child = children[i];
646 if (child->isOutOfFlowPositioned())
649 if (child->style()->marginLeft().isAuto())
650 ++numberOfAutoMargins;
651 if (child->style()->marginRight().isAuto())
652 ++numberOfAutoMargins;
654 if (child->style()->marginTop().isAuto())
655 ++numberOfAutoMargins;
656 if (child->style()->marginBottom().isAuto())
657 ++numberOfAutoMargins;
660 if (!numberOfAutoMargins)
663 LayoutUnit sizeOfAutoMargin = availableFreeSpace / numberOfAutoMargins;
664 availableFreeSpace = 0;
665 return sizeOfAutoMargin;
668 void RenderFlexibleBox::updateAutoMarginsInMainAxis(RenderBox* child, LayoutUnit autoMarginOffset)
670 if (isHorizontalFlow()) {
671 if (child->style()->marginLeft().isAuto())
672 child->setMarginLeft(autoMarginOffset);
673 if (child->style()->marginRight().isAuto())
674 child->setMarginRight(autoMarginOffset);
676 if (child->style()->marginTop().isAuto())
677 child->setMarginTop(autoMarginOffset);
678 if (child->style()->marginBottom().isAuto())
679 child->setMarginBottom(autoMarginOffset);
683 bool RenderFlexibleBox::hasAutoMarginsInCrossAxis(RenderBox* child)
685 if (isHorizontalFlow())
686 return child->style()->marginTop().isAuto() || child->style()->marginBottom().isAuto();
687 return child->style()->marginLeft().isAuto() || child->style()->marginRight().isAuto();
690 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox* child)
692 LayoutUnit childCrossExtent = 0;
693 if (!child->isOutOfFlowPositioned())
694 childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child);
695 return lineCrossAxisExtent - childCrossExtent;
698 bool RenderFlexibleBox::updateAutoMarginsInCrossAxis(RenderBox* child, LayoutUnit availableAlignmentSpace)
700 bool isHorizontal = isHorizontalFlow();
701 Length start = isHorizontal ? child->style()->marginTop() : child->style()->marginLeft();
702 Length end = isHorizontal ? child->style()->marginBottom() : child->style()->marginRight();
703 if (start.isAuto() && end.isAuto()) {
704 adjustAlignmentForChild(child, availableAlignmentSpace / 2);
706 child->setMarginTop(availableAlignmentSpace / 2);
707 child->setMarginBottom(availableAlignmentSpace / 2);
709 child->setMarginLeft(availableAlignmentSpace / 2);
710 child->setMarginRight(availableAlignmentSpace / 2);
714 if (start.isAuto()) {
715 adjustAlignmentForChild(child, availableAlignmentSpace);
717 child->setMarginTop(availableAlignmentSpace);
719 child->setMarginLeft(availableAlignmentSpace);
724 child->setMarginBottom(availableAlignmentSpace);
726 child->setMarginRight(availableAlignmentSpace);
732 LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(RenderBox* child)
734 LayoutUnit ascent = child->firstLineBoxBaseline();
736 ascent = crossAxisExtentForChild(child) + flowAwareMarginAfterForChild(child);
737 return ascent + flowAwareMarginBeforeForChild(child);
740 LayoutUnit RenderFlexibleBox::computeChildMarginValue(Length margin, RenderView* view)
742 // When resolving the margins, we use the content size for resolving percent and calc (for percents in calc expressions) margins.
743 // Fortunately, percent margins are always computed with respect to the block's width, even for margin-top and margin-bottom.
744 LayoutUnit availableSize = contentLogicalWidth();
745 return minimumValueForLength(margin, availableSize, view);
748 void RenderFlexibleBox::computeMainAxisPreferredSizes(bool relayoutChildren, OrderHashSet& orderValues)
750 RenderView* renderView = view();
751 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
752 orderValues.add(child->style()->order());
754 if (child->isOutOfFlowPositioned())
757 child->clearOverrideSize();
758 // Only need to layout here if we will need to get the logicalHeight of the child in computeNextFlexLine.
759 Length childMainAxisMin = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
760 if (hasOrthogonalFlow(child) && (flexBasisForChild(child).isAuto() || childMainAxisMin.isAuto())) {
761 if (!relayoutChildren)
762 child->setChildNeedsLayout(true, MarkOnlyThis);
763 child->layoutIfNeeded();
766 // Before running the flex algorithm, 'auto' has a margin of 0.
767 // Also, if we're not auto sizing, we don't do a layout that computes the start/end margins.
768 if (isHorizontalFlow()) {
769 child->setMarginLeft(computeChildMarginValue(child->style()->marginLeft(), renderView));
770 child->setMarginRight(computeChildMarginValue(child->style()->marginRight(), renderView));
772 child->setMarginTop(computeChildMarginValue(child->style()->marginTop(), renderView));
773 child->setMarginBottom(computeChildMarginValue(child->style()->marginBottom(), renderView));
778 LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox* child, LayoutUnit childSize)
780 // FIXME: Support intrinsic min/max lengths.
781 Length max = isHorizontalFlow() ? child->style()->maxWidth() : child->style()->maxHeight();
782 if (max.isSpecified()) {
783 LayoutUnit maxExtent = computeMainAxisExtentForChild(child, MaxSize, max);
784 if (maxExtent != -1 && childSize > maxExtent)
785 childSize = maxExtent;
788 Length min = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
789 LayoutUnit minExtent = 0;
790 if (min.isSpecified())
791 minExtent = computeMainAxisExtentForChild(child, MinSize, min);
792 else if (min.isAuto()) {
793 minExtent = hasOrthogonalFlow(child) ? child->logicalHeight() : child->minPreferredLogicalWidth();
794 minExtent -= mainAxisBorderAndPaddingExtentForChild(child);
796 return std::max(childSize, minExtent);
799 bool RenderFlexibleBox::computeNextFlexLine(OrderIterator& iterator, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalFlexGrow, float& totalWeightedFlexShrink, LayoutUnit& minMaxAppliedMainAxisExtent)
801 orderedChildren.clear();
802 preferredMainAxisExtent = 0;
803 totalFlexGrow = totalWeightedFlexShrink = 0;
804 minMaxAppliedMainAxisExtent = 0;
806 if (!iterator.currentChild())
809 LayoutUnit lineBreakLength = mainAxisContentExtent(MAX_LAYOUT_UNIT);
811 for (RenderBox* child = iterator.currentChild(); child; child = iterator.next()) {
812 if (child->isOutOfFlowPositioned()) {
813 orderedChildren.append(child);
817 LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(child);
818 LayoutUnit childMainAxisMarginBoxExtent = mainAxisBorderAndPaddingExtentForChild(child) + childMainAxisExtent;
819 childMainAxisMarginBoxExtent += isHorizontalFlow() ? child->marginWidth() : child->marginHeight();
821 if (isMultiline() && preferredMainAxisExtent + childMainAxisMarginBoxExtent > lineBreakLength && orderedChildren.size() > 0)
823 orderedChildren.append(child);
824 preferredMainAxisExtent += childMainAxisMarginBoxExtent;
825 totalFlexGrow += child->style()->flexGrow();
826 totalWeightedFlexShrink += child->style()->flexShrink() * childMainAxisExtent;
828 LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(child, childMainAxisExtent);
829 minMaxAppliedMainAxisExtent += childMinMaxAppliedMainAxisExtent - childMainAxisExtent + childMainAxisMarginBoxExtent;
834 void RenderFlexibleBox::freezeViolations(const WTF::Vector<Violation>& violations, LayoutUnit& availableFreeSpace, float& totalFlexGrow, float& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems)
836 for (size_t i = 0; i < violations.size(); ++i) {
837 RenderBox* child = violations[i].child;
838 LayoutUnit childSize = violations[i].childSize;
839 LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child);
840 availableFreeSpace -= childSize - preferredChildSize;
841 totalFlexGrow -= child->style()->flexGrow();
842 totalWeightedFlexShrink -= child->style()->flexShrink() * preferredChildSize;
843 inflexibleItems.set(child, childSize);
847 // Returns true if we successfully ran the algorithm and sized the flex items.
848 bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, float& totalFlexGrow, float& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, WTF::Vector<LayoutUnit>& childSizes)
851 LayoutUnit totalViolation = 0;
852 LayoutUnit usedFreeSpace = 0;
853 WTF::Vector<Violation> minViolations;
854 WTF::Vector<Violation> maxViolations;
855 for (size_t i = 0; i < children.size(); ++i) {
856 RenderBox* child = children[i];
857 if (child->isOutOfFlowPositioned()) {
858 childSizes.append(0);
862 if (inflexibleItems.contains(child))
863 childSizes.append(inflexibleItems.get(child));
865 LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child);
866 LayoutUnit childSize = preferredChildSize;
867 if (availableFreeSpace > 0 && totalFlexGrow > 0 && flexSign == PositiveFlexibility && isfinite(totalFlexGrow))
868 childSize += roundedLayoutUnit(availableFreeSpace * child->style()->flexGrow() / totalFlexGrow);
869 else if (availableFreeSpace < 0 && totalWeightedFlexShrink > 0 && flexSign == NegativeFlexibility && isfinite(totalWeightedFlexShrink))
870 childSize += roundedLayoutUnit(availableFreeSpace * child->style()->flexShrink() * preferredChildSize / totalWeightedFlexShrink);
872 LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(child, childSize);
873 childSizes.append(adjustedChildSize);
874 usedFreeSpace += adjustedChildSize - preferredChildSize;
876 LayoutUnit violation = adjustedChildSize - childSize;
878 minViolations.append(Violation(child, adjustedChildSize));
879 else if (violation < 0)
880 maxViolations.append(Violation(child, adjustedChildSize));
881 totalViolation += violation;
886 freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems);
888 availableFreeSpace -= usedFreeSpace;
890 return !totalViolation;
893 static LayoutUnit initialJustifyContentOffset(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
895 if (justifyContent == JustifyFlexEnd)
896 return availableFreeSpace;
897 if (justifyContent == JustifyCenter)
898 return availableFreeSpace / 2;
899 if (justifyContent == JustifySpaceAround) {
900 if (availableFreeSpace > 0 && numberOfChildren)
901 return availableFreeSpace / (2 * numberOfChildren);
902 if (availableFreeSpace < 0)
903 return availableFreeSpace / 2;
908 static LayoutUnit justifyContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
910 if (availableFreeSpace > 0 && numberOfChildren > 1) {
911 if (justifyContent == JustifySpaceBetween)
912 return availableFreeSpace / (numberOfChildren - 1);
913 if (justifyContent == JustifySpaceAround)
914 return availableFreeSpace / numberOfChildren;
919 void RenderFlexibleBox::setLogicalOverrideSize(RenderBox* child, LayoutUnit childPreferredSize)
921 if (hasOrthogonalFlow(child))
922 child->setOverrideLogicalContentHeight(childPreferredSize - child->borderAndPaddingLogicalHeight());
924 child->setOverrideLogicalContentWidth(childPreferredSize - child->borderAndPaddingLogicalWidth());
927 void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox* child, LayoutUnit mainAxisOffset, LayoutUnit crossAxisOffset, PositionedLayoutMode layoutMode)
929 ASSERT(child->isOutOfFlowPositioned());
930 child->containingBlock()->insertPositionedObject(child);
931 RenderLayer* childLayer = child->layer();
932 LayoutUnit inlinePosition = isColumnFlow() ? crossAxisOffset : mainAxisOffset;
933 if (layoutMode == FlipForRowReverse && style()->flexDirection() == FlowRowReverse)
934 inlinePosition = mainAxisExtent() - mainAxisOffset;
935 childLayer->setStaticInlinePosition(inlinePosition); // FIXME: Not right for regions.
937 LayoutUnit staticBlockPosition = isColumnFlow() ? mainAxisOffset : crossAxisOffset;
938 if (childLayer->staticBlockPosition() != staticBlockPosition) {
939 childLayer->setStaticBlockPosition(staticBlockPosition);
940 if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
941 child->setChildNeedsLayout(true, MarkOnlyThis);
945 static EAlignItems alignmentForChild(RenderBox* child)
947 EAlignItems align = child->style()->alignSelf();
948 if (align == AlignAuto)
949 align = child->parent()->style()->alignItems();
951 if (child->parent()->style()->flexWrap() == FlexWrapReverse) {
952 if (align == AlignFlexStart)
953 align = AlignFlexEnd;
954 else if (align == AlignFlexEnd)
955 align = AlignFlexStart;
961 void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace, WTF::Vector<LineContext>& lineContexts)
963 ASSERT(childSizes.size() == children.size());
965 LayoutUnit autoMarginOffset = autoMarginOffsetInMainAxis(children, availableFreeSpace);
966 LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart();
967 mainAxisOffset += initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), childSizes.size());
968 if (style()->flexDirection() == FlowRowReverse)
969 mainAxisOffset += isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
971 LayoutUnit totalMainExtent = mainAxisExtent();
972 LayoutUnit maxAscent = 0, maxDescent = 0; // Used when align-items: baseline.
973 LayoutUnit maxChildCrossAxisExtent = 0;
974 bool shouldFlipMainAxis = !isColumnFlow() && !isLeftToRightFlow();
975 for (size_t i = 0; i < children.size(); ++i) {
976 RenderBox* child = children[i];
977 if (child->isOutOfFlowPositioned()) {
978 prepareChildForPositionedLayout(child, mainAxisOffset, crossAxisOffset, FlipForRowReverse);
979 mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), childSizes.size());
982 LayoutUnit childPreferredSize = childSizes[i] + mainAxisBorderAndPaddingExtentForChild(child);
983 setLogicalOverrideSize(child, childPreferredSize);
984 // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
985 child->setChildNeedsLayout(true, MarkOnlyThis);
986 child->layoutIfNeeded();
988 updateAutoMarginsInMainAxis(child, autoMarginOffset);
990 LayoutUnit childCrossAxisMarginBoxExtent;
991 if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child)) {
992 LayoutUnit ascent = marginBoxAscentForChild(child);
993 LayoutUnit descent = (crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child)) - ascent;
995 maxAscent = std::max(maxAscent, ascent);
996 maxDescent = std::max(maxDescent, descent);
998 childCrossAxisMarginBoxExtent = maxAscent + maxDescent;
1000 childCrossAxisMarginBoxExtent = crossAxisExtentForChild(child) + crossAxisMarginExtentForChild(child);
1001 if (!isColumnFlow() && style()->logicalHeight().isAuto())
1002 setLogicalHeight(std::max(logicalHeight(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent()));
1003 maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisMarginBoxExtent);
1005 mainAxisOffset += flowAwareMarginStartForChild(child);
1007 LayoutUnit childMainExtent = mainAxisExtentForChild(child);
1008 LayoutPoint childLocation(shouldFlipMainAxis ? totalMainExtent - mainAxisOffset - childMainExtent : mainAxisOffset,
1009 crossAxisOffset + flowAwareMarginBeforeForChild(child));
1011 // FIXME: Supporting layout deltas.
1012 setFlowAwareLocationForChild(child, childLocation);
1013 mainAxisOffset += childMainExtent + flowAwareMarginEndForChild(child);
1015 mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), childSizes.size());
1019 setLogicalHeight(mainAxisOffset + flowAwareBorderEnd() + flowAwarePaddingEnd() + scrollbarLogicalHeight());
1021 if (style()->flexDirection() == FlowColumnReverse) {
1022 // We have to do an extra pass for column-reverse to reposition the flex items since the start depends
1023 // on the height of the flexbox, which we only know after we've positioned all the flex items.
1024 updateLogicalHeight();
1025 layoutColumnReverse(children, childSizes, crossAxisOffset, availableFreeSpace);
1028 lineContexts.append(LineContext(crossAxisOffset, maxChildCrossAxisExtent, children.size(), maxAscent));
1029 crossAxisOffset += maxChildCrossAxisExtent;
1032 void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace)
1034 // This is similar to the logic in layoutAndPlaceChildren, except we place the children
1035 // starting from the end of the flexbox. We also don't need to layout anything since we're
1036 // just moving the children to a new position.
1037 LayoutUnit mainAxisOffset = logicalHeight() - flowAwareBorderEnd() - flowAwarePaddingEnd();
1038 mainAxisOffset -= initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), childSizes.size());
1039 mainAxisOffset -= isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1041 for (size_t i = 0; i < children.size(); ++i) {
1042 RenderBox* child = children[i];
1043 if (child->isOutOfFlowPositioned()) {
1044 child->layer()->setStaticBlockPosition(mainAxisOffset);
1045 mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), childSizes.size());
1048 mainAxisOffset -= mainAxisExtentForChild(child) + flowAwareMarginEndForChild(child);
1050 LayoutRect oldRect = child->frameRect();
1051 setFlowAwareLocationForChild(child, LayoutPoint(mainAxisOffset, crossAxisOffset + flowAwareMarginBeforeForChild(child)));
1052 if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
1053 child->repaintDuringLayoutIfMoved(oldRect);
1055 mainAxisOffset -= flowAwareMarginStartForChild(child);
1056 mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), childSizes.size());
1060 static LayoutUnit initialAlignContentOffset(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1062 if (alignContent == AlignContentFlexEnd)
1063 return availableFreeSpace;
1064 if (alignContent == AlignContentCenter)
1065 return availableFreeSpace / 2;
1066 if (alignContent == AlignContentSpaceAround) {
1067 if (availableFreeSpace > 0 && numberOfLines)
1068 return availableFreeSpace / (2 * numberOfLines);
1069 if (availableFreeSpace < 0)
1070 return availableFreeSpace / 2;
1075 static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1077 if (availableFreeSpace > 0 && numberOfLines > 1) {
1078 if (alignContent == AlignContentSpaceBetween)
1079 return availableFreeSpace / (numberOfLines - 1);
1080 if (alignContent == AlignContentSpaceAround || alignContent == AlignContentStretch)
1081 return availableFreeSpace / numberOfLines;
1086 void RenderFlexibleBox::alignFlexLines(OrderIterator& iterator, WTF::Vector<LineContext>& lineContexts)
1088 if (!isMultiline() || style()->alignContent() == AlignContentFlexStart)
1091 LayoutUnit availableCrossAxisSpace = crossAxisContentExtent();
1092 for (size_t i = 0; i < lineContexts.size(); ++i)
1093 availableCrossAxisSpace -= lineContexts[i].crossAxisExtent;
1095 RenderBox* child = iterator.first();
1096 LayoutUnit lineOffset = initialAlignContentOffset(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1097 for (unsigned lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1098 lineContexts[lineNumber].crossAxisOffset += lineOffset;
1099 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next())
1100 adjustAlignmentForChild(child, lineOffset);
1102 if (style()->alignContent() == AlignContentStretch && availableCrossAxisSpace > 0)
1103 lineContexts[lineNumber].crossAxisExtent += availableCrossAxisSpace / static_cast<unsigned>(lineContexts.size());
1105 lineOffset += alignContentSpaceBetweenChildren(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1109 void RenderFlexibleBox::adjustAlignmentForChild(RenderBox* child, LayoutUnit delta)
1111 if (child->isOutOfFlowPositioned()) {
1112 LayoutUnit staticInlinePosition = child->layer()->staticInlinePosition();
1113 LayoutUnit staticBlockPosition = child->layer()->staticBlockPosition();
1114 LayoutUnit mainAxis = isColumnFlow() ? staticBlockPosition : staticInlinePosition;
1115 LayoutUnit crossAxis = isColumnFlow() ? staticInlinePosition : staticBlockPosition;
1117 prepareChildForPositionedLayout(child, mainAxis, crossAxis, NoFlipForRowReverse);
1121 LayoutRect oldRect = child->frameRect();
1122 setFlowAwareLocationForChild(child, flowAwareLocationForChild(child) + LayoutSize(0, delta));
1124 // If the child moved, we have to repaint it as well as any floating/positioned
1125 // descendants. An exception is if we need a layout. In this case, we know we're going to
1126 // repaint ourselves (and the child) anyway.
1127 if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
1128 child->repaintDuringLayoutIfMoved(oldRect);
1131 void RenderFlexibleBox::alignChildren(OrderIterator& iterator, const WTF::Vector<LineContext>& lineContexts)
1133 // Keep track of the space between the baseline edge and the after edge of the box for each line.
1134 WTF::Vector<LayoutUnit> minMarginAfterBaselines;
1136 RenderBox* child = iterator.first();
1137 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1138 LayoutUnit minMarginAfterBaseline = MAX_LAYOUT_UNIT;
1139 LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1140 LayoutUnit maxAscent = lineContexts[lineNumber].maxAscent;
1142 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) {
1144 if (updateAutoMarginsInCrossAxis(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child)))
1147 switch (alignmentForChild(child)) {
1149 ASSERT_NOT_REACHED();
1151 case AlignStretch: {
1152 applyStretchAlignmentToChild(child, lineCrossAxisExtent);
1153 // Since wrap-reverse flips cross start and cross end, strech children should be aligned with the cross end.
1154 if (style()->flexWrap() == FlexWrapReverse)
1155 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
1158 case AlignFlexStart:
1161 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
1164 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) / 2);
1166 case AlignBaseline: {
1167 LayoutUnit ascent = marginBoxAscentForChild(child);
1168 LayoutUnit startOffset = maxAscent - ascent;
1169 adjustAlignmentForChild(child, startOffset);
1171 if (style()->flexWrap() == FlexWrapReverse)
1172 minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) - startOffset);
1177 minMarginAfterBaselines.append(minMarginAfterBaseline);
1180 if (style()->flexWrap() != FlexWrapReverse)
1183 // wrap-reverse flips the cross axis start and end. For baseline alignment, this means we
1184 // need to align the after edge of baseline elements with the after edge of the flex line.
1185 child = iterator.first();
1186 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1187 LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber];
1188 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) {
1190 if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child) && minMarginAfterBaseline)
1191 adjustAlignmentForChild(child, minMarginAfterBaseline);
1196 void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox* child, LayoutUnit lineCrossAxisExtent)
1198 if (!isColumnFlow() && child->style()->logicalHeight().isAuto()) {
1199 // FIXME: If the child has orthogonal flow, then it already has an override height set, so use it.
1200 if (!hasOrthogonalFlow(child)) {
1201 LayoutUnit stretchedLogicalHeight = child->logicalHeight() + availableAlignmentSpaceForChild(lineCrossAxisExtent, child);
1202 LayoutUnit desiredLogicalHeight = child->constrainLogicalHeightByMinMax(stretchedLogicalHeight);
1204 // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
1205 if (desiredLogicalHeight != child->logicalHeight()) {
1206 child->setOverrideLogicalContentHeight(desiredLogicalHeight - child->borderAndPaddingLogicalHeight());
1207 child->setLogicalHeight(0);
1208 child->setChildNeedsLayout(true, MarkOnlyThis);
1209 child->layoutIfNeeded();
1212 } else if (isColumnFlow() && child->style()->logicalWidth().isAuto()) {
1213 // FIXME: If the child doesn't have orthogonal flow, then it already has an override width set, so use it.
1214 if (hasOrthogonalFlow(child)) {
1215 LayoutUnit childWidth = std::max(ZERO_LAYOUT_UNIT, lineCrossAxisExtent - crossAxisMarginExtentForChild(child));
1216 childWidth = child->constrainLogicalWidthInRegionByMinMax(childWidth, childWidth, this);
1218 if (childWidth != child->logicalWidth()) {
1219 child->setOverrideLogicalContentWidth(childWidth);
1220 child->setChildNeedsLayout(true, MarkOnlyThis);
1221 child->layoutIfNeeded();
1227 void RenderFlexibleBox::flipForRightToLeftColumn(OrderIterator& iterator)
1229 if (style()->isLeftToRightDirection() || !isColumnFlow())
1232 LayoutUnit crossExtent = crossAxisExtent();
1233 for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
1234 if (child->isOutOfFlowPositioned())
1236 LayoutPoint location = flowAwareLocationForChild(child);
1237 location.setY(crossExtent - crossAxisExtentForChild(child) - location.y());
1238 setFlowAwareLocationForChild(child, location);
1242 void RenderFlexibleBox::flipForWrapReverse(OrderIterator& iterator, const WTF::Vector<LineContext>& lineContexts, LayoutUnit crossAxisStartEdge)
1244 LayoutUnit contentExtent = crossAxisContentExtent();
1245 RenderBox* child = iterator.first();
1246 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1247 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) {
1249 LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1250 LayoutUnit originalOffset = lineContexts[lineNumber].crossAxisOffset - crossAxisStartEdge;
1251 LayoutUnit newOffset = contentExtent - originalOffset - lineCrossAxisExtent;
1252 adjustAlignmentForChild(child, newOffset - originalOffset);