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 RenderFlexibleBox::OrderIterator::OrderIterator(const RenderFlexibleBox* flexibleBox)
53 : m_flexibleBox(flexibleBox)
55 , m_orderValuesIterator(0)
59 void RenderFlexibleBox::OrderIterator::setOrderValues(const OrderHashSet& orderValues)
62 copyToVector(orderValues, m_orderValues);
63 std::sort(m_orderValues.begin(), m_orderValues.end());
66 RenderBox* RenderFlexibleBox::OrderIterator::first()
72 RenderBox* RenderFlexibleBox::OrderIterator::next()
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;
93 void RenderFlexibleBox::OrderIterator::reset()
96 m_orderValuesIterator = 0;
99 struct RenderFlexibleBox::LineContext {
100 LineContext(LayoutUnit crossAxisOffset, LayoutUnit crossAxisExtent, size_t numberOfChildren, LayoutUnit maxAscent)
101 : crossAxisOffset(crossAxisOffset)
102 , crossAxisExtent(crossAxisExtent)
103 , numberOfChildren(numberOfChildren)
104 , maxAscent(maxAscent)
108 LayoutUnit crossAxisOffset;
109 LayoutUnit crossAxisExtent;
110 size_t numberOfChildren;
111 LayoutUnit maxAscent;
114 struct RenderFlexibleBox::Violation {
115 Violation(RenderBox& child, LayoutUnit childSize)
117 , childSize(childSize)
122 LayoutUnit childSize;
126 RenderFlexibleBox::RenderFlexibleBox(Element& element)
127 : RenderBlock(element, 0)
128 , m_orderIterator(this)
129 , m_numberOfInFlowChildrenOnFirstLine(-1)
131 setChildrenInline(false); // All of our children must be block-level.
134 RenderFlexibleBox::RenderFlexibleBox(Document& document)
135 : RenderBlock(document, 0)
136 , m_orderIterator(this)
137 , m_numberOfInFlowChildrenOnFirstLine(-1)
139 setChildrenInline(false); // All of our children must be block-level.
142 RenderFlexibleBox::~RenderFlexibleBox()
146 const char* RenderFlexibleBox::renderName() const
148 return "RenderFlexibleBox";
151 static LayoutUnit marginLogicalWidthForChild(RenderBox& child, RenderStyle* parentStyle)
153 // A margin has three types: fixed, percentage, and auto (variable).
154 // Auto and percentage margins become 0 when computing min/max width.
155 // Fixed margins can be added in as is.
156 Length marginLeft = child.style()->marginStartUsing(parentStyle);
157 Length marginRight = child.style()->marginEndUsing(parentStyle);
158 LayoutUnit margin = 0;
159 if (marginLeft.isFixed())
160 margin += marginLeft.value();
161 if (marginRight.isFixed())
162 margin += marginRight.value();
166 void RenderFlexibleBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
168 // FIXME: We're ignoring flex-basis here and we shouldn't. We can't start honoring it though until
169 // the flex shorthand stops setting it to 0.
170 // See https://bugs.webkit.org/show_bug.cgi?id=116117,
171 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
172 if (child->isOutOfFlowPositioned())
175 LayoutUnit margin = marginLogicalWidthForChild(*child, style());
176 bool hasOrthogonalWritingMode = child->isHorizontalWritingMode() != isHorizontalWritingMode();
177 LayoutUnit minPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->minPreferredLogicalWidth();
178 LayoutUnit maxPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->maxPreferredLogicalWidth();
179 minPreferredLogicalWidth += margin;
180 maxPreferredLogicalWidth += margin;
181 if (!isColumnFlow()) {
182 maxLogicalWidth += maxPreferredLogicalWidth;
184 // For multiline, the min preferred width is if you put a break between each item.
185 minLogicalWidth = std::max(minLogicalWidth, minPreferredLogicalWidth);
187 minLogicalWidth += minPreferredLogicalWidth;
189 minLogicalWidth = std::max(minPreferredLogicalWidth, minLogicalWidth);
191 // For multiline, the max preferred width is if you never break between items.
192 maxLogicalWidth += maxPreferredLogicalWidth;
194 maxLogicalWidth = std::max(maxPreferredLogicalWidth, maxLogicalWidth);
198 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
200 LayoutUnit scrollbarWidth = instrinsicScrollbarLogicalWidth();
201 maxLogicalWidth += scrollbarWidth;
202 minLogicalWidth += scrollbarWidth;
205 void RenderFlexibleBox::computePreferredLogicalWidths()
207 ASSERT(preferredLogicalWidthsDirty());
209 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
211 RenderStyle* styleToUse = style();
212 // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for width.
213 if (styleToUse->logicalWidth().isFixed() && styleToUse->logicalWidth().value() > 0)
214 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalWidth().value());
216 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
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 static int synthesizedBaselineFromContentBox(const RenderBox& box, LineDirectionMode direction)
239 return direction == HorizontalLine ? box.borderTop() + box.paddingTop() + box.contentHeight() : box.borderRight() + box.paddingRight() + box.contentWidth();
242 int RenderFlexibleBox::baselinePosition(FontBaseline, bool, LineDirectionMode direction, LinePositionMode) const
244 int baseline = firstLineBaseline();
246 baseline = synthesizedBaselineFromContentBox(*this, direction);
248 int marginAscent = direction == HorizontalLine ? marginTop() : marginRight();
249 return baseline + marginAscent;
252 int RenderFlexibleBox::firstLineBaseline() const
254 if (isWritingModeRoot() || m_numberOfInFlowChildrenOnFirstLine <= 0)
256 RenderBox* baselineChild = 0;
258 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
259 if (child->isOutOfFlowPositioned())
261 if (alignmentForChild(*child) == AlignBaseline && !hasAutoMarginsInCrossAxis(*child)) {
262 baselineChild = child;
266 baselineChild = child;
269 if (childNumber == m_numberOfInFlowChildrenOnFirstLine)
276 if (!isColumnFlow() && hasOrthogonalFlow(*baselineChild))
277 return crossAxisExtentForChild(*baselineChild) + baselineChild->logicalTop();
278 if (isColumnFlow() && !hasOrthogonalFlow(*baselineChild))
279 return mainAxisExtentForChild(*baselineChild) + baselineChild->logicalTop();
281 int baseline = baselineChild->firstLineBaseline();
282 if (baseline == -1) {
283 // FIXME: We should pass |direction| into firstLineBoxBaseline and stop bailing out if we're a writing mode root.
284 // This would also fix some cases where the flexbox is orthogonal to its container.
285 LineDirectionMode direction = isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
286 return synthesizedBaselineFromContentBox(*baselineChild, direction) + baselineChild->logicalTop();
289 return baseline + baselineChild->logicalTop();
292 int RenderFlexibleBox::inlineBlockBaseline(LineDirectionMode direction) const
294 int baseline = firstLineBaseline();
298 int marginAscent = direction == HorizontalLine ? marginTop() : marginRight();
299 return synthesizedBaselineFromContentBox(*this, direction) + marginAscent;
302 static EAlignItems resolveAlignment(const RenderStyle* parentStyle, const RenderStyle* childStyle)
304 EAlignItems align = childStyle->alignSelf();
305 if (align == AlignAuto)
306 align = parentStyle->alignItems();
310 void RenderFlexibleBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
312 RenderBlock::styleDidChange(diff, oldStyle);
314 if (oldStyle && oldStyle->alignItems() == AlignStretch && diff == StyleDifferenceLayout) {
315 // Flex items that were previously stretching need to be relayed out so we can compute new available cross axis space.
316 // This is only necessary for stretching since other alignment values don't change the size of the box.
317 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
318 EAlignItems previousAlignment = resolveAlignment(oldStyle, child->style());
319 if (previousAlignment == AlignStretch && previousAlignment != resolveAlignment(style(), child->style()))
320 child->setChildNeedsLayout(MarkOnlyThis);
325 void RenderFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
327 ASSERT(needsLayout());
329 if (!relayoutChildren && simplifiedLayout())
332 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
334 if (updateLogicalWidthAndColumnWidth())
335 relayoutChildren = true;
337 LayoutUnit previousHeight = logicalHeight();
338 setLogicalHeight(borderAndPaddingLogicalHeight() + scrollbarLogicalHeight());
340 LayoutStateMaintainer statePusher(&view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
342 prepareShapesAndPaginationBeforeBlockLayout(relayoutChildren);
344 m_numberOfInFlowChildrenOnFirstLine = -1;
346 RenderBlock::startDelayUpdateScrollInfo();
348 dirtyForLayoutFromPercentageHeightDescendants();
350 Vector<LineContext> lineContexts;
351 OrderHashSet orderValues;
352 computeMainAxisPreferredSizes(orderValues);
353 m_orderIterator.setOrderValues(orderValues);
355 ChildFrameRects oldChildRects;
356 appendChildFrameRects(oldChildRects);
357 layoutFlexItems(relayoutChildren, lineContexts);
359 updateLogicalHeight();
360 repositionLogicalHeightDependentFlexItems(lineContexts);
362 RenderBlock::finishDelayUpdateScrollInfo();
364 if (logicalHeight() != previousHeight)
365 relayoutChildren = true;
367 layoutPositionedObjects(relayoutChildren || isRoot());
369 updateShapesAfterBlockLayout();
371 repaintChildrenDuringLayoutIfMoved(oldChildRects);
372 // FIXME: css3/flexbox/repaint-rtl-column.html seems to repaint more overflow than it needs to.
373 computeOverflow(clientLogicalBottomAfterRepositioning());
376 updateLayerTransform();
378 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
379 // we overflow or not.
380 updateScrollInfoAfterLayout();
382 repainter.repaintAfterLayout();
387 void RenderFlexibleBox::appendChildFrameRects(ChildFrameRects& childFrameRects)
389 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
390 if (!child->isOutOfFlowPositioned())
391 childFrameRects.append(child->frameRect());
395 void RenderFlexibleBox::repaintChildrenDuringLayoutIfMoved(const ChildFrameRects& oldChildRects)
397 size_t childIndex = 0;
398 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
399 if (child->isOutOfFlowPositioned())
402 // If the child moved, we have to repaint it as well as any floating/positioned
403 // descendants. An exception is if we need a layout. In this case, we know we're going to
404 // repaint ourselves (and the child) anyway.
405 if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
406 child->repaintDuringLayoutIfMoved(oldChildRects[childIndex]);
409 ASSERT(childIndex == oldChildRects.size());
412 void RenderFlexibleBox::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset, PaintInfo& paintInfoForChild, bool usePrintRect)
414 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
415 if (!paintChild(*child, paintInfo, paintOffset, paintInfoForChild, usePrintRect))
420 void RenderFlexibleBox::repositionLogicalHeightDependentFlexItems(Vector<LineContext>& lineContexts)
422 LayoutUnit crossAxisStartEdge = lineContexts.isEmpty() ? LayoutUnit() : lineContexts[0].crossAxisOffset;
423 alignFlexLines(lineContexts);
425 // If we have a single line flexbox, the line height is all the available space.
426 // For flex-direction: row, this means we need to use the height, so we do this after calling updateLogicalHeight.
427 if (!isMultiline() && lineContexts.size() == 1)
428 lineContexts[0].crossAxisExtent = crossAxisContentExtent();
429 alignChildren(lineContexts);
431 if (style()->flexWrap() == FlexWrapReverse)
432 flipForWrapReverse(lineContexts, crossAxisStartEdge);
434 // direction:rtl + flex-direction:column means the cross-axis direction is flipped.
435 flipForRightToLeftColumn();
438 LayoutUnit RenderFlexibleBox::clientLogicalBottomAfterRepositioning()
440 LayoutUnit maxChildLogicalBottom = 0;
441 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
442 if (child->isOutOfFlowPositioned())
444 LayoutUnit childLogicalBottom = logicalTopForChild(*child) + logicalHeightForChild(*child) + marginAfterForChild(*child);
445 maxChildLogicalBottom = std::max(maxChildLogicalBottom, childLogicalBottom);
447 return std::max(clientLogicalBottom(), maxChildLogicalBottom);
450 bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox& child) const
452 // FIXME: If the child is a flexbox, then we need to check isHorizontalFlow.
453 return isHorizontalFlow() != child.isHorizontalWritingMode();
456 bool RenderFlexibleBox::isColumnFlow() const
458 return style()->isColumnFlexDirection();
461 bool RenderFlexibleBox::isHorizontalFlow() const
463 if (isHorizontalWritingMode())
464 return !isColumnFlow();
465 return isColumnFlow();
468 bool RenderFlexibleBox::isLeftToRightFlow() const
471 return style()->writingMode() == TopToBottomWritingMode || style()->writingMode() == LeftToRightWritingMode;
472 return style()->isLeftToRightDirection() ^ (style()->flexDirection() == FlowRowReverse);
475 bool RenderFlexibleBox::isMultiline() const
477 return style()->flexWrap() != FlexNoWrap;
480 Length RenderFlexibleBox::flexBasisForChild(RenderBox& child) const
482 Length flexLength = child.style()->flexBasis();
483 if (flexLength.isAuto())
484 flexLength = isHorizontalFlow() ? child.style()->width() : child.style()->height();
488 void RenderFlexibleBox::setCrossAxisExtent(LayoutUnit extent)
490 if (isHorizontalFlow())
496 LayoutUnit RenderFlexibleBox::crossAxisExtentForChild(RenderBox& child) const
498 return isHorizontalFlow() ? child.height() : child.width();
501 LayoutUnit RenderFlexibleBox::mainAxisExtentForChild(RenderBox& child) const
503 return isHorizontalFlow() ? child.width() : child.height();
506 LayoutUnit RenderFlexibleBox::crossAxisExtent() const
508 return isHorizontalFlow() ? height() : width();
511 LayoutUnit RenderFlexibleBox::mainAxisExtent() const
513 return isHorizontalFlow() ? width() : height();
516 LayoutUnit RenderFlexibleBox::crossAxisContentExtent() const
518 return isHorizontalFlow() ? contentHeight() : contentWidth();
521 LayoutUnit RenderFlexibleBox::mainAxisContentExtent(LayoutUnit contentLogicalHeight)
523 if (isColumnFlow()) {
524 LogicalExtentComputedValues computedValues;
525 LayoutUnit borderPaddingAndScrollbar = borderAndPaddingLogicalHeight() + scrollbarLogicalHeight();
526 if (contentLogicalHeight > LayoutUnit::max() - borderPaddingAndScrollbar)
527 contentLogicalHeight -= borderPaddingAndScrollbar;
528 LayoutUnit borderBoxLogicalHeight = contentLogicalHeight + borderPaddingAndScrollbar;
529 computeLogicalHeight(borderBoxLogicalHeight, logicalTop(), computedValues);
530 if (computedValues.m_extent == LayoutUnit::max())
531 return computedValues.m_extent;
532 return std::max(LayoutUnit(0), computedValues.m_extent - borderPaddingAndScrollbar);
534 return contentLogicalWidth();
537 LayoutUnit RenderFlexibleBox::computeMainAxisExtentForChild(RenderBox& child, SizeType sizeType, const Length& size)
539 // FIXME: This is wrong for orthogonal flows. It should use the flexbox's writing-mode, not the child's in order
540 // to figure out the logical height/width.
541 // FIXME: This is wrong if the height is set to an intrinsic keyword value. computeContentLogicalHeight will return -1.
542 // Instead, we need to layout the child an get the appropriate height value.
543 // https://bugs.webkit.org/show_bug.cgi?id=113610
545 return child.computeContentLogicalHeight(size);
546 // FIXME: Figure out how this should work for regions and pass in the appropriate values.
547 RenderRegion* region = 0;
548 return child.computeLogicalWidthInRegionUsing(sizeType, size, contentLogicalWidth(), this, region) - child.borderAndPaddingLogicalWidth();
551 WritingMode RenderFlexibleBox::transformedWritingMode() const
553 WritingMode mode = style()->writingMode();
558 case TopToBottomWritingMode:
559 case BottomToTopWritingMode:
560 return style()->isLeftToRightDirection() ? LeftToRightWritingMode : RightToLeftWritingMode;
561 case LeftToRightWritingMode:
562 case RightToLeftWritingMode:
563 return style()->isLeftToRightDirection() ? TopToBottomWritingMode : BottomToTopWritingMode;
565 ASSERT_NOT_REACHED();
566 return TopToBottomWritingMode;
569 LayoutUnit RenderFlexibleBox::flowAwareBorderStart() const
571 if (isHorizontalFlow())
572 return isLeftToRightFlow() ? borderLeft() : borderRight();
573 return isLeftToRightFlow() ? borderTop() : borderBottom();
576 LayoutUnit RenderFlexibleBox::flowAwareBorderEnd() const
578 if (isHorizontalFlow())
579 return isLeftToRightFlow() ? borderRight() : borderLeft();
580 return isLeftToRightFlow() ? borderBottom() : borderTop();
583 LayoutUnit RenderFlexibleBox::flowAwareBorderBefore() const
585 switch (transformedWritingMode()) {
586 case TopToBottomWritingMode:
588 case BottomToTopWritingMode:
589 return borderBottom();
590 case LeftToRightWritingMode:
592 case RightToLeftWritingMode:
593 return borderRight();
595 ASSERT_NOT_REACHED();
599 LayoutUnit RenderFlexibleBox::flowAwareBorderAfter() const
601 switch (transformedWritingMode()) {
602 case TopToBottomWritingMode:
603 return borderBottom();
604 case BottomToTopWritingMode:
606 case LeftToRightWritingMode:
607 return borderRight();
608 case RightToLeftWritingMode:
611 ASSERT_NOT_REACHED();
615 LayoutUnit RenderFlexibleBox::flowAwarePaddingStart() const
617 if (isHorizontalFlow())
618 return isLeftToRightFlow() ? paddingLeft() : paddingRight();
619 return isLeftToRightFlow() ? paddingTop() : paddingBottom();
622 LayoutUnit RenderFlexibleBox::flowAwarePaddingEnd() const
624 if (isHorizontalFlow())
625 return isLeftToRightFlow() ? paddingRight() : paddingLeft();
626 return isLeftToRightFlow() ? paddingBottom() : paddingTop();
629 LayoutUnit RenderFlexibleBox::flowAwarePaddingBefore() const
631 switch (transformedWritingMode()) {
632 case TopToBottomWritingMode:
634 case BottomToTopWritingMode:
635 return paddingBottom();
636 case LeftToRightWritingMode:
637 return paddingLeft();
638 case RightToLeftWritingMode:
639 return paddingRight();
641 ASSERT_NOT_REACHED();
645 LayoutUnit RenderFlexibleBox::flowAwarePaddingAfter() const
647 switch (transformedWritingMode()) {
648 case TopToBottomWritingMode:
649 return paddingBottom();
650 case BottomToTopWritingMode:
652 case LeftToRightWritingMode:
653 return paddingRight();
654 case RightToLeftWritingMode:
655 return paddingLeft();
657 ASSERT_NOT_REACHED();
661 LayoutUnit RenderFlexibleBox::flowAwareMarginStartForChild(RenderBox& child) const
663 if (isHorizontalFlow())
664 return isLeftToRightFlow() ? child.marginLeft() : child.marginRight();
665 return isLeftToRightFlow() ? child.marginTop() : child.marginBottom();
668 LayoutUnit RenderFlexibleBox::flowAwareMarginEndForChild(RenderBox& child) const
670 if (isHorizontalFlow())
671 return isLeftToRightFlow() ? child.marginRight() : child.marginLeft();
672 return isLeftToRightFlow() ? child.marginBottom() : child.marginTop();
675 LayoutUnit RenderFlexibleBox::flowAwareMarginBeforeForChild(RenderBox& child) const
677 switch (transformedWritingMode()) {
678 case TopToBottomWritingMode:
679 return child.marginTop();
680 case BottomToTopWritingMode:
681 return child.marginBottom();
682 case LeftToRightWritingMode:
683 return child.marginLeft();
684 case RightToLeftWritingMode:
685 return child.marginRight();
687 ASSERT_NOT_REACHED();
691 LayoutUnit RenderFlexibleBox::flowAwareMarginAfterForChild(RenderBox& child) const
693 switch (transformedWritingMode()) {
694 case TopToBottomWritingMode:
695 return child.marginBottom();
696 case BottomToTopWritingMode:
697 return child.marginTop();
698 case LeftToRightWritingMode:
699 return child.marginRight();
700 case RightToLeftWritingMode:
701 return child.marginLeft();
703 ASSERT_NOT_REACHED();
704 return marginBottom();
707 LayoutUnit RenderFlexibleBox::crossAxisMarginExtentForChild(RenderBox& child) const
709 return isHorizontalFlow() ? child.marginHeight() : child.marginWidth();
712 LayoutUnit RenderFlexibleBox::crossAxisScrollbarExtent() const
714 return isHorizontalFlow() ? horizontalScrollbarHeight() : verticalScrollbarWidth();
717 LayoutPoint RenderFlexibleBox::flowAwareLocationForChild(RenderBox& child) const
719 return isHorizontalFlow() ? child.location() : child.location().transposedPoint();
722 void RenderFlexibleBox::setFlowAwareLocationForChild(RenderBox& child, const LayoutPoint& location)
724 if (isHorizontalFlow())
725 child.setLocation(location);
727 child.setLocation(location.transposedPoint());
730 LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox& child) const
732 return isHorizontalFlow() ? child.borderAndPaddingWidth() : child.borderAndPaddingHeight();
735 LayoutUnit RenderFlexibleBox::mainAxisScrollbarExtentForChild(RenderBox& child) const
737 return isHorizontalFlow() ? child.verticalScrollbarWidth() : child.horizontalScrollbarHeight();
740 LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox& child, bool hasInfiniteLineLength)
742 bool hasOverrideSize = child.hasOverrideWidth() || child.hasOverrideHeight();
744 child.clearOverrideSize();
746 Length flexBasis = flexBasisForChild(child);
747 if (flexBasis.isAuto() || (flexBasis.isFixed() && !flexBasis.value() && hasInfiniteLineLength)) {
748 if (hasOrthogonalFlow(child)) {
750 child.setChildNeedsLayout(MarkOnlyThis);
751 child.layoutIfNeeded();
753 LayoutUnit mainAxisExtent = hasOrthogonalFlow(child) ? child.logicalHeight() : child.maxPreferredLogicalWidth();
754 ASSERT(mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child) >= 0);
755 return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child);
757 return std::max(LayoutUnit(0), computeMainAxisExtentForChild(child, MainOrPreferredSize, flexBasis));
760 void RenderFlexibleBox::layoutFlexItems(bool relayoutChildren, Vector<LineContext>& lineContexts)
762 OrderedFlexItemList orderedChildren;
763 LayoutUnit preferredMainAxisExtent;
764 double totalFlexGrow;
765 double totalWeightedFlexShrink;
766 LayoutUnit minMaxAppliedMainAxisExtent;
768 m_orderIterator.first();
769 LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
770 bool hasInfiniteLineLength = false;
771 while (computeNextFlexLine(orderedChildren, preferredMainAxisExtent, totalFlexGrow, totalWeightedFlexShrink, minMaxAppliedMainAxisExtent, hasInfiniteLineLength)) {
772 LayoutUnit availableFreeSpace = mainAxisContentExtent(preferredMainAxisExtent) - preferredMainAxisExtent;
773 FlexSign flexSign = (minMaxAppliedMainAxisExtent < preferredMainAxisExtent + availableFreeSpace) ? PositiveFlexibility : NegativeFlexibility;
774 InflexibleFlexItemSize inflexibleItems;
775 Vector<LayoutUnit> childSizes;
776 while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, childSizes, hasInfiniteLineLength)) {
777 ASSERT(totalFlexGrow >= 0 && totalWeightedFlexShrink >= 0);
778 ASSERT(inflexibleItems.size() > 0);
781 layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace, relayoutChildren, lineContexts);
783 if (hasLineIfEmpty()) {
784 // Even if computeNextFlexLine returns true, the flexbox might not have
785 // a line because all our children might be out of flow positioned.
786 // Instead of just checking if we have a line, make sure the flexbox
787 // has at least a line's worth of height to cover this case.
788 LayoutUnit minHeight = borderAndPaddingLogicalHeight()
789 + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes)
790 + scrollbarLogicalHeight();
791 if (height() < minHeight)
792 setLogicalHeight(minHeight);
796 LayoutUnit RenderFlexibleBox::autoMarginOffsetInMainAxis(const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace)
798 if (availableFreeSpace <= 0)
801 int numberOfAutoMargins = 0;
802 bool isHorizontal = isHorizontalFlow();
803 for (size_t i = 0; i < children.size(); ++i) {
804 RenderBox* child = children[i];
805 if (child->isOutOfFlowPositioned())
808 if (child->style()->marginLeft().isAuto())
809 ++numberOfAutoMargins;
810 if (child->style()->marginRight().isAuto())
811 ++numberOfAutoMargins;
813 if (child->style()->marginTop().isAuto())
814 ++numberOfAutoMargins;
815 if (child->style()->marginBottom().isAuto())
816 ++numberOfAutoMargins;
819 if (!numberOfAutoMargins)
822 LayoutUnit sizeOfAutoMargin = availableFreeSpace / numberOfAutoMargins;
823 availableFreeSpace = 0;
824 return sizeOfAutoMargin;
827 void RenderFlexibleBox::updateAutoMarginsInMainAxis(RenderBox& child, LayoutUnit autoMarginOffset)
829 ASSERT(autoMarginOffset >= 0);
831 if (isHorizontalFlow()) {
832 if (child.style()->marginLeft().isAuto())
833 child.setMarginLeft(autoMarginOffset);
834 if (child.style()->marginRight().isAuto())
835 child.setMarginRight(autoMarginOffset);
837 if (child.style()->marginTop().isAuto())
838 child.setMarginTop(autoMarginOffset);
839 if (child.style()->marginBottom().isAuto())
840 child.setMarginBottom(autoMarginOffset);
844 bool RenderFlexibleBox::hasAutoMarginsInCrossAxis(RenderBox& child) const
846 if (isHorizontalFlow())
847 return child.style()->marginTop().isAuto() || child.style()->marginBottom().isAuto();
848 return child.style()->marginLeft().isAuto() || child.style()->marginRight().isAuto();
851 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox& child)
853 ASSERT(!child.isOutOfFlowPositioned());
854 LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child);
855 return lineCrossAxisExtent - childCrossExtent;
858 bool RenderFlexibleBox::updateAutoMarginsInCrossAxis(RenderBox& child, LayoutUnit availableAlignmentSpace)
860 ASSERT(!child.isOutOfFlowPositioned());
861 ASSERT(availableAlignmentSpace >= 0);
863 bool isHorizontal = isHorizontalFlow();
864 Length start = isHorizontal ? child.style()->marginTop() : child.style()->marginLeft();
865 Length end = isHorizontal ? child.style()->marginBottom() : child.style()->marginRight();
866 if (start.isAuto() && end.isAuto()) {
867 adjustAlignmentForChild(child, availableAlignmentSpace / 2);
869 child.setMarginTop(availableAlignmentSpace / 2);
870 child.setMarginBottom(availableAlignmentSpace / 2);
872 child.setMarginLeft(availableAlignmentSpace / 2);
873 child.setMarginRight(availableAlignmentSpace / 2);
877 if (start.isAuto()) {
878 adjustAlignmentForChild(child, availableAlignmentSpace);
880 child.setMarginTop(availableAlignmentSpace);
882 child.setMarginLeft(availableAlignmentSpace);
887 child.setMarginBottom(availableAlignmentSpace);
889 child.setMarginRight(availableAlignmentSpace);
895 LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(RenderBox& child)
897 LayoutUnit ascent = child.firstLineBaseline();
899 ascent = crossAxisExtentForChild(child);
900 return ascent + flowAwareMarginBeforeForChild(child);
903 LayoutUnit RenderFlexibleBox::computeChildMarginValue(const Length& margin)
905 // When resolving the margins, we use the content size for resolving percent and calc (for percents in calc expressions) margins.
906 // Fortunately, percent margins are always computed with respect to the block's width, even for margin-top and margin-bottom.
907 LayoutUnit availableSize = contentLogicalWidth();
908 return minimumValueForLength(margin, availableSize);
911 void RenderFlexibleBox::computeMainAxisPreferredSizes(OrderHashSet& orderValues)
913 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
914 orderValues.add(child->style()->order());
916 if (child->isOutOfFlowPositioned())
919 // Before running the flex algorithm, 'auto' has a margin of 0.
920 // Also, if we're not auto sizing, we don't do a layout that computes the start/end margins.
921 if (isHorizontalFlow()) {
922 child->setMarginLeft(computeChildMarginValue(child->style()->marginLeft()));
923 child->setMarginRight(computeChildMarginValue(child->style()->marginRight()));
925 child->setMarginTop(computeChildMarginValue(child->style()->marginTop()));
926 child->setMarginBottom(computeChildMarginValue(child->style()->marginBottom()));
931 LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox& child, LayoutUnit childSize)
933 Length max = isHorizontalFlow() ? child.style()->maxWidth() : child.style()->maxHeight();
934 if (max.isSpecifiedOrIntrinsic()) {
935 LayoutUnit maxExtent = computeMainAxisExtentForChild(child, MaxSize, max);
936 if (maxExtent != -1 && childSize > maxExtent)
937 childSize = maxExtent;
940 Length min = isHorizontalFlow() ? child.style()->minWidth() : child.style()->minHeight();
941 LayoutUnit minExtent = 0;
942 if (min.isSpecifiedOrIntrinsic())
943 minExtent = computeMainAxisExtentForChild(child, MinSize, min);
944 return std::max(childSize, minExtent);
947 bool RenderFlexibleBox::computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& minMaxAppliedMainAxisExtent, bool& hasInfiniteLineLength)
949 orderedChildren.clear();
950 preferredMainAxisExtent = 0;
951 totalFlexGrow = totalWeightedFlexShrink = 0;
952 minMaxAppliedMainAxisExtent = 0;
954 if (!m_orderIterator.currentChild())
957 LayoutUnit lineBreakLength = mainAxisContentExtent(LayoutUnit::max());
958 hasInfiniteLineLength = lineBreakLength == LayoutUnit::max();
960 bool lineHasInFlowItem = false;
962 for (RenderBox* child = m_orderIterator.currentChild(); child; child = m_orderIterator.next()) {
963 if (child->isOutOfFlowPositioned()) {
964 orderedChildren.append(child);
968 LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(*child, hasInfiniteLineLength);
969 LayoutUnit childMainAxisMarginBoxExtent = mainAxisBorderAndPaddingExtentForChild(*child) + childMainAxisExtent;
970 childMainAxisMarginBoxExtent += isHorizontalFlow() ? child->marginWidth() : child->marginHeight();
972 if (isMultiline() && preferredMainAxisExtent + childMainAxisMarginBoxExtent > lineBreakLength && lineHasInFlowItem)
974 orderedChildren.append(child);
975 lineHasInFlowItem = true;
976 preferredMainAxisExtent += childMainAxisMarginBoxExtent;
977 totalFlexGrow += child->style()->flexGrow();
978 totalWeightedFlexShrink += child->style()->flexShrink() * childMainAxisExtent;
980 LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(*child, childMainAxisExtent);
981 minMaxAppliedMainAxisExtent += childMinMaxAppliedMainAxisExtent - childMainAxisExtent + childMainAxisMarginBoxExtent;
986 void RenderFlexibleBox::freezeViolations(const Vector<Violation>& violations, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, bool hasInfiniteLineLength)
988 for (size_t i = 0; i < violations.size(); ++i) {
989 RenderBox& child = violations[i].child;
990 LayoutUnit childSize = violations[i].childSize;
991 LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
992 availableFreeSpace -= childSize - preferredChildSize;
993 totalFlexGrow -= child.style()->flexGrow();
994 totalWeightedFlexShrink -= child.style()->flexShrink() * preferredChildSize;
995 inflexibleItems.set(&child, childSize);
999 // Returns true if we successfully ran the algorithm and sized the flex items.
1000 bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, Vector<LayoutUnit>& childSizes, bool hasInfiniteLineLength)
1003 LayoutUnit totalViolation = 0;
1004 LayoutUnit usedFreeSpace = 0;
1005 Vector<Violation> minViolations;
1006 Vector<Violation> maxViolations;
1007 for (size_t i = 0; i < children.size(); ++i) {
1008 RenderBox& child = *children[i];
1009 if (child.isOutOfFlowPositioned()) {
1010 childSizes.append(0);
1014 if (inflexibleItems.contains(&child))
1015 childSizes.append(inflexibleItems.get(&child));
1017 LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
1018 LayoutUnit childSize = preferredChildSize;
1019 double extraSpace = 0;
1020 if (availableFreeSpace > 0 && totalFlexGrow > 0 && flexSign == PositiveFlexibility && std::isfinite(totalFlexGrow))
1021 extraSpace = availableFreeSpace * child.style()->flexGrow() / totalFlexGrow;
1022 else if (availableFreeSpace < 0 && totalWeightedFlexShrink > 0 && flexSign == NegativeFlexibility && std::isfinite(totalWeightedFlexShrink))
1023 extraSpace = availableFreeSpace * child.style()->flexShrink() * preferredChildSize / totalWeightedFlexShrink;
1024 if (std::isfinite(extraSpace))
1025 childSize += roundedLayoutUnit(extraSpace);
1027 LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(child, childSize);
1028 childSizes.append(adjustedChildSize);
1029 usedFreeSpace += adjustedChildSize - preferredChildSize;
1031 LayoutUnit violation = adjustedChildSize - childSize;
1033 minViolations.append(Violation(child, adjustedChildSize));
1034 else if (violation < 0)
1035 maxViolations.append(Violation(child, adjustedChildSize));
1036 totalViolation += violation;
1041 freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, hasInfiniteLineLength);
1043 availableFreeSpace -= usedFreeSpace;
1045 return !totalViolation;
1048 static LayoutUnit initialJustifyContentOffset(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
1050 if (justifyContent == JustifyFlexEnd)
1051 return availableFreeSpace;
1052 if (justifyContent == JustifyCenter)
1053 return availableFreeSpace / 2;
1054 if (justifyContent == JustifySpaceAround) {
1055 if (availableFreeSpace > 0 && numberOfChildren)
1056 return availableFreeSpace / (2 * numberOfChildren);
1058 return availableFreeSpace / 2;
1063 static LayoutUnit justifyContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
1065 if (availableFreeSpace > 0 && numberOfChildren > 1) {
1066 if (justifyContent == JustifySpaceBetween)
1067 return availableFreeSpace / (numberOfChildren - 1);
1068 if (justifyContent == JustifySpaceAround)
1069 return availableFreeSpace / numberOfChildren;
1074 void RenderFlexibleBox::setLogicalOverrideSize(RenderBox& child, LayoutUnit childPreferredSize)
1076 if (hasOrthogonalFlow(child))
1077 child.setOverrideLogicalContentHeight(childPreferredSize - child.borderAndPaddingLogicalHeight());
1079 child.setOverrideLogicalContentWidth(childPreferredSize - child.borderAndPaddingLogicalWidth());
1082 void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox& child, LayoutUnit mainAxisOffset, LayoutUnit crossAxisOffset, PositionedLayoutMode layoutMode)
1084 ASSERT(child.isOutOfFlowPositioned());
1085 child.containingBlock()->insertPositionedObject(child);
1086 RenderLayer* childLayer = child.layer();
1087 LayoutUnit inlinePosition = isColumnFlow() ? crossAxisOffset : mainAxisOffset;
1088 if (layoutMode == FlipForRowReverse && style()->flexDirection() == FlowRowReverse)
1089 inlinePosition = mainAxisExtent() - mainAxisOffset;
1090 childLayer->setStaticInlinePosition(inlinePosition); // FIXME: Not right for regions.
1092 LayoutUnit staticBlockPosition = isColumnFlow() ? mainAxisOffset : crossAxisOffset;
1093 if (childLayer->staticBlockPosition() != staticBlockPosition) {
1094 childLayer->setStaticBlockPosition(staticBlockPosition);
1095 if (child.style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
1096 child.setChildNeedsLayout(MarkOnlyThis);
1100 EAlignItems RenderFlexibleBox::alignmentForChild(RenderBox& child) const
1102 EAlignItems align = resolveAlignment(style(), child.style());
1104 if (align == AlignBaseline && hasOrthogonalFlow(child))
1105 align = AlignFlexStart;
1107 if (style()->flexWrap() == FlexWrapReverse) {
1108 if (align == AlignFlexStart)
1109 align = AlignFlexEnd;
1110 else if (align == AlignFlexEnd)
1111 align = AlignFlexStart;
1117 size_t RenderFlexibleBox::numberOfInFlowPositionedChildren(const OrderedFlexItemList& children) const
1120 for (size_t i = 0; i < children.size(); ++i) {
1121 RenderBox* child = children[i];
1122 if (!child->isOutOfFlowPositioned())
1128 bool RenderFlexibleBox::needToStretchChild(RenderBox& child)
1130 if (alignmentForChild(child) != AlignStretch)
1133 Length crossAxisLength = isHorizontalFlow() ? child.style()->height() : child.style()->width();
1134 return crossAxisLength.isAuto();
1137 void RenderFlexibleBox::resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox& child)
1139 if (hasAutoMarginsInCrossAxis(child))
1140 child.updateLogicalHeight();
1143 void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace, bool relayoutChildren, Vector<LineContext>& lineContexts)
1145 ASSERT(childSizes.size() == children.size());
1147 size_t numberOfChildrenForJustifyContent = numberOfInFlowPositionedChildren(children);
1148 LayoutUnit autoMarginOffset = autoMarginOffsetInMainAxis(children, availableFreeSpace);
1149 LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart();
1150 mainAxisOffset += initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1151 if (style()->flexDirection() == FlowRowReverse)
1152 mainAxisOffset += isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1154 LayoutUnit totalMainExtent = mainAxisExtent();
1155 LayoutUnit maxAscent = 0, maxDescent = 0; // Used when align-items: baseline.
1156 LayoutUnit maxChildCrossAxisExtent = 0;
1157 size_t seenInFlowPositionedChildren = 0;
1158 bool shouldFlipMainAxis = !isColumnFlow() && !isLeftToRightFlow();
1159 for (size_t i = 0; i < children.size(); ++i) {
1160 RenderBox& child = *children[i];
1161 if (child.isOutOfFlowPositioned()) {
1162 prepareChildForPositionedLayout(child, mainAxisOffset, crossAxisOffset, FlipForRowReverse);
1166 LayoutUnit childPreferredSize = childSizes[i] + mainAxisBorderAndPaddingExtentForChild(child);
1167 setLogicalOverrideSize(child, childPreferredSize);
1168 // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
1169 if (needToStretchChild(child) || childPreferredSize != mainAxisExtentForChild(child))
1170 child.setChildNeedsLayout(MarkOnlyThis);
1172 // To avoid double applying margin changes in updateAutoMarginsInCrossAxis, we reset the margins here.
1173 resetAutoMarginsAndLogicalTopInCrossAxis(child);
1175 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
1176 child.layoutIfNeeded();
1178 updateAutoMarginsInMainAxis(child, autoMarginOffset);
1180 LayoutUnit childCrossAxisMarginBoxExtent;
1181 if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child)) {
1182 LayoutUnit ascent = marginBoxAscentForChild(child);
1183 LayoutUnit descent = (crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child)) - ascent;
1185 maxAscent = std::max(maxAscent, ascent);
1186 maxDescent = std::max(maxDescent, descent);
1188 childCrossAxisMarginBoxExtent = maxAscent + maxDescent;
1190 childCrossAxisMarginBoxExtent = crossAxisExtentForChild(child) + crossAxisMarginExtentForChild(child);
1191 if (!isColumnFlow())
1192 setLogicalHeight(std::max(logicalHeight(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent()));
1193 maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisMarginBoxExtent);
1195 mainAxisOffset += flowAwareMarginStartForChild(child);
1197 LayoutUnit childMainExtent = mainAxisExtentForChild(child);
1198 LayoutPoint childLocation(shouldFlipMainAxis ? totalMainExtent - mainAxisOffset - childMainExtent : mainAxisOffset,
1199 crossAxisOffset + flowAwareMarginBeforeForChild(child));
1201 // FIXME: Supporting layout deltas.
1202 setFlowAwareLocationForChild(child, childLocation);
1203 mainAxisOffset += childMainExtent + flowAwareMarginEndForChild(child);
1205 ++seenInFlowPositionedChildren;
1206 if (seenInFlowPositionedChildren < numberOfChildrenForJustifyContent)
1207 mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1211 setLogicalHeight(mainAxisOffset + flowAwareBorderEnd() + flowAwarePaddingEnd() + scrollbarLogicalHeight());
1213 if (style()->flexDirection() == FlowColumnReverse) {
1214 // We have to do an extra pass for column-reverse to reposition the flex items since the start depends
1215 // on the height of the flexbox, which we only know after we've positioned all the flex items.
1216 updateLogicalHeight();
1217 layoutColumnReverse(children, crossAxisOffset, availableFreeSpace);
1220 if (m_numberOfInFlowChildrenOnFirstLine == -1)
1221 m_numberOfInFlowChildrenOnFirstLine = seenInFlowPositionedChildren;
1222 lineContexts.append(LineContext(crossAxisOffset, maxChildCrossAxisExtent, children.size(), maxAscent));
1223 crossAxisOffset += maxChildCrossAxisExtent;
1226 void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace)
1228 // This is similar to the logic in layoutAndPlaceChildren, except we place the children
1229 // starting from the end of the flexbox. We also don't need to layout anything since we're
1230 // just moving the children to a new position.
1231 size_t numberOfChildrenForJustifyContent = numberOfInFlowPositionedChildren(children);
1232 LayoutUnit mainAxisOffset = logicalHeight() - flowAwareBorderEnd() - flowAwarePaddingEnd();
1233 mainAxisOffset -= initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1234 mainAxisOffset -= isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1236 size_t seenInFlowPositionedChildren = 0;
1237 for (size_t i = 0; i < children.size(); ++i) {
1238 RenderBox& child = *children[i];
1239 if (child.isOutOfFlowPositioned()) {
1240 child.layer()->setStaticBlockPosition(mainAxisOffset);
1243 mainAxisOffset -= mainAxisExtentForChild(child) + flowAwareMarginEndForChild(child);
1245 setFlowAwareLocationForChild(child, LayoutPoint(mainAxisOffset, crossAxisOffset + flowAwareMarginBeforeForChild(child)));
1247 mainAxisOffset -= flowAwareMarginStartForChild(child);
1249 ++seenInFlowPositionedChildren;
1250 if (seenInFlowPositionedChildren < numberOfChildrenForJustifyContent)
1251 mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1255 static LayoutUnit initialAlignContentOffset(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1257 if (alignContent == AlignContentFlexEnd)
1258 return availableFreeSpace;
1259 if (alignContent == AlignContentCenter)
1260 return availableFreeSpace / 2;
1261 if (alignContent == AlignContentSpaceAround) {
1262 if (availableFreeSpace > 0 && numberOfLines)
1263 return availableFreeSpace / (2 * numberOfLines);
1264 if (availableFreeSpace < 0)
1265 return availableFreeSpace / 2;
1270 static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1272 if (availableFreeSpace > 0 && numberOfLines > 1) {
1273 if (alignContent == AlignContentSpaceBetween)
1274 return availableFreeSpace / (numberOfLines - 1);
1275 if (alignContent == AlignContentSpaceAround || alignContent == AlignContentStretch)
1276 return availableFreeSpace / numberOfLines;
1281 void RenderFlexibleBox::alignFlexLines(Vector<LineContext>& lineContexts)
1283 if (!isMultiline() || style()->alignContent() == AlignContentFlexStart)
1286 LayoutUnit availableCrossAxisSpace = crossAxisContentExtent();
1287 for (size_t i = 0; i < lineContexts.size(); ++i)
1288 availableCrossAxisSpace -= lineContexts[i].crossAxisExtent;
1290 RenderBox* child = m_orderIterator.first();
1291 LayoutUnit lineOffset = initialAlignContentOffset(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1292 for (unsigned lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1293 lineContexts[lineNumber].crossAxisOffset += lineOffset;
1294 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next())
1295 adjustAlignmentForChild(*child, lineOffset);
1297 if (style()->alignContent() == AlignContentStretch && availableCrossAxisSpace > 0)
1298 lineContexts[lineNumber].crossAxisExtent += availableCrossAxisSpace / static_cast<unsigned>(lineContexts.size());
1300 lineOffset += alignContentSpaceBetweenChildren(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1304 void RenderFlexibleBox::adjustAlignmentForChild(RenderBox& child, LayoutUnit delta)
1306 if (child.isOutOfFlowPositioned()) {
1307 LayoutUnit staticInlinePosition = child.layer()->staticInlinePosition();
1308 LayoutUnit staticBlockPosition = child.layer()->staticBlockPosition();
1309 LayoutUnit mainAxis = isColumnFlow() ? staticBlockPosition : staticInlinePosition;
1310 LayoutUnit crossAxis = isColumnFlow() ? staticInlinePosition : staticBlockPosition;
1312 prepareChildForPositionedLayout(child, mainAxis, crossAxis, NoFlipForRowReverse);
1316 setFlowAwareLocationForChild(child, flowAwareLocationForChild(child) + LayoutSize(0, delta));
1319 void RenderFlexibleBox::alignChildren(const Vector<LineContext>& lineContexts)
1321 // Keep track of the space between the baseline edge and the after edge of the box for each line.
1322 Vector<LayoutUnit> minMarginAfterBaselines;
1324 RenderBox* child = m_orderIterator.first();
1325 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1326 LayoutUnit minMarginAfterBaseline = LayoutUnit::max();
1327 LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1328 LayoutUnit maxAscent = lineContexts[lineNumber].maxAscent;
1330 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
1332 if (child->isOutOfFlowPositioned()) {
1333 if (style()->flexWrap() == FlexWrapReverse)
1334 adjustAlignmentForChild(*child, lineCrossAxisExtent);
1338 if (updateAutoMarginsInCrossAxis(*child, std::max(LayoutUnit(0), availableAlignmentSpaceForChild(lineCrossAxisExtent, *child))))
1341 switch (alignmentForChild(*child)) {
1343 ASSERT_NOT_REACHED();
1345 case AlignStretch: {
1346 applyStretchAlignmentToChild(*child, lineCrossAxisExtent);
1347 // Since wrap-reverse flips cross start and cross end, strech children should be aligned with the cross end.
1348 if (style()->flexWrap() == FlexWrapReverse)
1349 adjustAlignmentForChild(*child, availableAlignmentSpaceForChild(lineCrossAxisExtent, *child));
1352 case AlignFlexStart:
1355 adjustAlignmentForChild(*child, availableAlignmentSpaceForChild(lineCrossAxisExtent, *child));
1358 adjustAlignmentForChild(*child, availableAlignmentSpaceForChild(lineCrossAxisExtent, *child) / 2);
1360 case AlignBaseline: {
1361 // FIXME: If we get here in columns, we want the use the descent, except we currently can't get the ascent/descent of orthogonal children.
1362 // https://bugs.webkit.org/show_bug.cgi?id=98076
1363 LayoutUnit ascent = marginBoxAscentForChild(*child);
1364 LayoutUnit startOffset = maxAscent - ascent;
1365 adjustAlignmentForChild(*child, startOffset);
1367 if (style()->flexWrap() == FlexWrapReverse)
1368 minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, *child) - startOffset);
1373 minMarginAfterBaselines.append(minMarginAfterBaseline);
1376 if (style()->flexWrap() != FlexWrapReverse)
1379 // wrap-reverse flips the cross axis start and end. For baseline alignment, this means we
1380 // need to align the after edge of baseline elements with the after edge of the flex line.
1381 child = m_orderIterator.first();
1382 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1383 LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber];
1384 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
1386 if (alignmentForChild(*child) == AlignBaseline && !hasAutoMarginsInCrossAxis(*child) && minMarginAfterBaseline)
1387 adjustAlignmentForChild(*child, minMarginAfterBaseline);
1392 void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox& child, LayoutUnit lineCrossAxisExtent)
1394 if (!isColumnFlow() && child.style()->logicalHeight().isAuto()) {
1395 // FIXME: If the child has orthogonal flow, then it already has an override height set, so use it.
1396 if (!hasOrthogonalFlow(child)) {
1397 LayoutUnit stretchedLogicalHeight = child.logicalHeight() + availableAlignmentSpaceForChild(lineCrossAxisExtent, child);
1398 LayoutUnit desiredLogicalHeight = child.constrainLogicalHeightByMinMax(stretchedLogicalHeight);
1400 // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
1401 if (desiredLogicalHeight != child.logicalHeight()) {
1402 child.setOverrideLogicalContentHeight(desiredLogicalHeight - child.borderAndPaddingLogicalHeight());
1403 child.setLogicalHeight(0);
1404 child.setChildNeedsLayout(MarkOnlyThis);
1408 } else if (isColumnFlow() && child.style()->logicalWidth().isAuto()) {
1409 // FIXME: If the child doesn't have orthogonal flow, then it already has an override width set, so use it.
1410 if (hasOrthogonalFlow(child)) {
1411 LayoutUnit childWidth = std::max<LayoutUnit>(0, lineCrossAxisExtent - crossAxisMarginExtentForChild(child));
1412 childWidth = child.constrainLogicalWidthInRegionByMinMax(childWidth, childWidth, this);
1414 if (childWidth != child.logicalWidth()) {
1415 child.setOverrideLogicalContentWidth(childWidth - child.borderAndPaddingLogicalWidth());
1416 child.setChildNeedsLayout(MarkOnlyThis);
1423 void RenderFlexibleBox::flipForRightToLeftColumn()
1425 if (style()->isLeftToRightDirection() || !isColumnFlow())
1428 LayoutUnit crossExtent = crossAxisExtent();
1429 for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
1430 if (child->isOutOfFlowPositioned())
1432 LayoutPoint location = flowAwareLocationForChild(*child);
1433 location.setY(crossExtent - crossAxisExtentForChild(*child) - location.y());
1434 setFlowAwareLocationForChild(*child, location);
1438 void RenderFlexibleBox::flipForWrapReverse(const Vector<LineContext>& lineContexts, LayoutUnit crossAxisStartEdge)
1440 LayoutUnit contentExtent = crossAxisContentExtent();
1441 RenderBox* child = m_orderIterator.first();
1442 for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1443 for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
1445 LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1446 LayoutUnit originalOffset = lineContexts[lineNumber].crossAxisOffset - crossAxisStartEdge;
1447 LayoutUnit newOffset = contentExtent - originalOffset - lineCrossAxisExtent;
1448 adjustAlignmentForChild(*child, newOffset - originalOffset);