Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 2011 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      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
     13  * distribution.
     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.
     17  *
     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.
     29  */
     30 
     31 #include "config.h"
     32 #include "core/rendering/RenderFlexibleBox.h"
     33 
     34 #include <limits>
     35 #include "core/rendering/LayoutRepainter.h"
     36 #include "core/rendering/RenderLayer.h"
     37 #include "core/rendering/RenderView.h"
     38 #include "wtf/MathExtras.h"
     39 
     40 namespace WebCore {
     41 
     42 struct RenderFlexibleBox::LineContext {
     43     LineContext(LayoutUnit crossAxisOffset, LayoutUnit crossAxisExtent, size_t numberOfChildren, LayoutUnit maxAscent)
     44         : crossAxisOffset(crossAxisOffset)
     45         , crossAxisExtent(crossAxisExtent)
     46         , numberOfChildren(numberOfChildren)
     47         , maxAscent(maxAscent)
     48     {
     49     }
     50 
     51     LayoutUnit crossAxisOffset;
     52     LayoutUnit crossAxisExtent;
     53     size_t numberOfChildren;
     54     LayoutUnit maxAscent;
     55 };
     56 
     57 struct RenderFlexibleBox::Violation {
     58     Violation(RenderBox* child, LayoutUnit childSize)
     59         : child(child)
     60         , childSize(childSize)
     61     {
     62     }
     63 
     64     RenderBox* child;
     65     LayoutUnit childSize;
     66 };
     67 
     68 
     69 RenderFlexibleBox::RenderFlexibleBox(Element* element)
     70     : RenderBlock(element)
     71     , m_orderIterator(this)
     72     , m_numberOfInFlowChildrenOnFirstLine(-1)
     73 {
     74     setChildrenInline(false); // All of our children must be block-level.
     75 }
     76 
     77 RenderFlexibleBox::~RenderFlexibleBox()
     78 {
     79 }
     80 
     81 RenderFlexibleBox* RenderFlexibleBox::createAnonymous(Document* document)
     82 {
     83     RenderFlexibleBox* renderer = new RenderFlexibleBox(0);
     84     renderer->setDocumentForAnonymous(document);
     85     return renderer;
     86 }
     87 
     88 const char* RenderFlexibleBox::renderName() const
     89 {
     90     return "RenderFlexibleBox";
     91 }
     92 
     93 void RenderFlexibleBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
     94 {
     95     // FIXME: We're ignoring flex-basis here and we shouldn't. We can't start honoring it though until
     96     // the flex shorthand stops setting it to 0.
     97     // See https://bugs.webkit.org/show_bug.cgi?id=116117 and http://crbug.com/240765.
     98     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
     99         if (child->isOutOfFlowPositioned())
    100             continue;
    101 
    102         LayoutUnit margin = marginIntrinsicLogicalWidthForChild(child);
    103         bool hasOrthogonalWritingMode = child->isHorizontalWritingMode() != isHorizontalWritingMode();
    104         LayoutUnit minPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->minPreferredLogicalWidth();
    105         LayoutUnit maxPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->maxPreferredLogicalWidth();
    106         minPreferredLogicalWidth += margin;
    107         maxPreferredLogicalWidth += margin;
    108         if (!isColumnFlow()) {
    109             maxLogicalWidth += maxPreferredLogicalWidth;
    110             if (isMultiline()) {
    111                 // For multiline, the min preferred width is if you put a break between each item.
    112                 minLogicalWidth = std::max(minLogicalWidth, minPreferredLogicalWidth);
    113             } else
    114                 minLogicalWidth += minPreferredLogicalWidth;
    115         } else {
    116             minLogicalWidth = std::max(minPreferredLogicalWidth, minLogicalWidth);
    117             if (isMultiline()) {
    118                 // For multiline, the max preferred width is if you never break between items.
    119                 maxLogicalWidth += maxPreferredLogicalWidth;
    120             } else
    121                 maxLogicalWidth = std::max(maxPreferredLogicalWidth, maxLogicalWidth);
    122         }
    123     }
    124 
    125     maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
    126 
    127     LayoutUnit scrollbarWidth = instrinsicScrollbarLogicalWidth();
    128     maxLogicalWidth += scrollbarWidth;
    129     minLogicalWidth += scrollbarWidth;
    130 }
    131 
    132 static int synthesizedBaselineFromContentBox(const RenderBox* box, LineDirectionMode direction)
    133 {
    134     return direction == HorizontalLine ? box->borderTop() + box->paddingTop() + box->contentHeight() : box->borderRight() + box->paddingRight() + box->contentWidth();
    135 }
    136 
    137 int RenderFlexibleBox::baselinePosition(FontBaseline, bool, LineDirectionMode direction, LinePositionMode mode) const
    138 {
    139     ASSERT(mode == PositionOnContainingLine);
    140     int baseline = firstLineBoxBaseline();
    141     if (baseline == -1)
    142         baseline = synthesizedBaselineFromContentBox(this, direction);
    143 
    144     int marginAscent = direction == HorizontalLine ? marginTop() : marginRight();
    145     return baseline + marginAscent;
    146 }
    147 
    148 int RenderFlexibleBox::firstLineBoxBaseline() const
    149 {
    150     if (isWritingModeRoot() || m_numberOfInFlowChildrenOnFirstLine <= 0)
    151         return -1;
    152     RenderBox* baselineChild = 0;
    153     int childNumber = 0;
    154     for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
    155         if (child->isOutOfFlowPositioned())
    156             continue;
    157         if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child)) {
    158             baselineChild = child;
    159             break;
    160         }
    161         if (!baselineChild)
    162             baselineChild = child;
    163 
    164         ++childNumber;
    165         if (childNumber == m_numberOfInFlowChildrenOnFirstLine)
    166             break;
    167     }
    168 
    169     if (!baselineChild)
    170         return -1;
    171 
    172     if (!isColumnFlow() && hasOrthogonalFlow(baselineChild))
    173         return crossAxisExtentForChild(baselineChild) + baselineChild->logicalTop();
    174     if (isColumnFlow() && !hasOrthogonalFlow(baselineChild))
    175         return mainAxisExtentForChild(baselineChild) + baselineChild->logicalTop();
    176 
    177     int baseline = baselineChild->firstLineBoxBaseline();
    178     if (baseline == -1) {
    179         // FIXME: We should pass |direction| into firstLineBoxBaseline and stop bailing out if we're a writing mode root.
    180         // This would also fix some cases where the flexbox is orthogonal to its container.
    181         LineDirectionMode direction = isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
    182         return synthesizedBaselineFromContentBox(baselineChild, direction) + baselineChild->logicalTop();
    183     }
    184 
    185     return baseline + baselineChild->logicalTop();
    186 }
    187 
    188 int RenderFlexibleBox::inlineBlockBaseline(LineDirectionMode direction) const
    189 {
    190     int baseline = firstLineBoxBaseline();
    191     if (baseline != -1)
    192         return baseline;
    193 
    194     int marginAscent = direction == HorizontalLine ? marginTop() : marginRight();
    195     return synthesizedBaselineFromContentBox(this, direction) + marginAscent;
    196 }
    197 
    198 static EAlignItems resolveAlignment(const RenderStyle* parentStyle, const RenderStyle* childStyle)
    199 {
    200     EAlignItems align = childStyle->alignSelf();
    201     if (align == AlignAuto)
    202         align = parentStyle->alignItems();
    203     return align;
    204 }
    205 
    206 void RenderFlexibleBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
    207 {
    208     RenderBlock::styleDidChange(diff, oldStyle);
    209 
    210     if (oldStyle && oldStyle->alignItems() == AlignStretch && diff == StyleDifferenceLayout) {
    211         // Flex items that were previously stretching need to be relayed out so we can compute new available cross axis space.
    212         // This is only necessary for stretching since other alignment values don't change the size of the box.
    213         for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
    214             EAlignItems previousAlignment = resolveAlignment(oldStyle, child->style());
    215             if (previousAlignment == AlignStretch && previousAlignment != resolveAlignment(style(), child->style()))
    216                 child->setChildNeedsLayout(MarkOnlyThis);
    217         }
    218     }
    219 }
    220 
    221 void RenderFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
    222 {
    223     ASSERT(needsLayout());
    224 
    225     if (!relayoutChildren && simplifiedLayout())
    226         return;
    227 
    228     LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
    229 
    230     if (updateLogicalWidthAndColumnWidth())
    231         relayoutChildren = true;
    232 
    233     LayoutUnit previousHeight = logicalHeight();
    234     setLogicalHeight(borderAndPaddingLogicalHeight() + scrollbarLogicalHeight());
    235 
    236     LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
    237 
    238     // Regions changing widths can force us to relayout our children.
    239     RenderFlowThread* flowThread = flowThreadContainingBlock();
    240     if (logicalWidthChangedInRegions(flowThread))
    241         relayoutChildren = true;
    242     if (updateRegionsAndShapesLogicalSize(flowThread))
    243         relayoutChildren = true;
    244 
    245     m_numberOfInFlowChildrenOnFirstLine = -1;
    246 
    247     RenderBlock::startDelayUpdateScrollInfo();
    248 
    249     prepareOrderIteratorAndMargins();
    250 
    251     ChildFrameRects oldChildRects;
    252     appendChildFrameRects(oldChildRects);
    253 
    254     Vector<LineContext> lineContexts;
    255     layoutFlexItems(relayoutChildren, lineContexts);
    256 
    257     updateLogicalHeight();
    258     repositionLogicalHeightDependentFlexItems(lineContexts);
    259 
    260     RenderBlock::finishDelayUpdateScrollInfo();
    261 
    262     if (logicalHeight() != previousHeight)
    263         relayoutChildren = true;
    264 
    265     layoutPositionedObjects(relayoutChildren || isRoot());
    266 
    267     computeRegionRangeForBlock(flowThread);
    268 
    269     repaintChildrenDuringLayoutIfMoved(oldChildRects);
    270     // FIXME: css3/flexbox/repaint-rtl-column.html seems to repaint more overflow than it needs to.
    271     computeOverflow(clientLogicalBottomAfterRepositioning());
    272     statePusher.pop();
    273 
    274     updateLayerTransform();
    275 
    276     // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
    277     // we overflow or not.
    278     updateScrollInfoAfterLayout();
    279 
    280     repainter.repaintAfterLayout();
    281 
    282     clearNeedsLayout();
    283 }
    284 
    285 void RenderFlexibleBox::appendChildFrameRects(ChildFrameRects& childFrameRects)
    286 {
    287     for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
    288         if (!child->isOutOfFlowPositioned())
    289             childFrameRects.append(child->frameRect());
    290     }
    291 }
    292 
    293 void RenderFlexibleBox::repaintChildrenDuringLayoutIfMoved(const ChildFrameRects& oldChildRects)
    294 {
    295     size_t childIndex = 0;
    296     for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
    297         if (child->isOutOfFlowPositioned())
    298             continue;
    299 
    300         // If the child moved, we have to repaint it as well as any floating/positioned
    301         // descendants. An exception is if we need a layout. In this case, we know we're going to
    302         // repaint ourselves (and the child) anyway.
    303         if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
    304             child->repaintDuringLayoutIfMoved(oldChildRects[childIndex]);
    305         ++childIndex;
    306     }
    307     ASSERT(childIndex == oldChildRects.size());
    308 }
    309 
    310 void RenderFlexibleBox::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    311 {
    312     for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next())
    313         paintChildAsInlineBlock(child, paintInfo, paintOffset);
    314 }
    315 
    316 void RenderFlexibleBox::repositionLogicalHeightDependentFlexItems(Vector<LineContext>& lineContexts)
    317 {
    318     LayoutUnit crossAxisStartEdge = lineContexts.isEmpty() ? LayoutUnit() : lineContexts[0].crossAxisOffset;
    319     alignFlexLines(lineContexts);
    320 
    321     // If we have a single line flexbox, the line height is all the available space.
    322     // For flex-direction: row, this means we need to use the height, so we do this after calling updateLogicalHeight.
    323     if (!isMultiline() && lineContexts.size() == 1)
    324         lineContexts[0].crossAxisExtent = crossAxisContentExtent();
    325     alignChildren(lineContexts);
    326 
    327     if (style()->flexWrap() == FlexWrapReverse)
    328         flipForWrapReverse(lineContexts, crossAxisStartEdge);
    329 
    330     // direction:rtl + flex-direction:column means the cross-axis direction is flipped.
    331     flipForRightToLeftColumn();
    332 }
    333 
    334 LayoutUnit RenderFlexibleBox::clientLogicalBottomAfterRepositioning()
    335 {
    336     LayoutUnit maxChildLogicalBottom = 0;
    337     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
    338         if (child->isOutOfFlowPositioned())
    339             continue;
    340         LayoutUnit childLogicalBottom = logicalTopForChild(child) + logicalHeightForChild(child) + marginAfterForChild(child);
    341         maxChildLogicalBottom = std::max(maxChildLogicalBottom, childLogicalBottom);
    342     }
    343     return std::max(clientLogicalBottom(), maxChildLogicalBottom);
    344 }
    345 
    346 bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox* child) const
    347 {
    348     // FIXME: If the child is a flexbox, then we need to check isHorizontalFlow.
    349     return isHorizontalFlow() != child->isHorizontalWritingMode();
    350 }
    351 
    352 bool RenderFlexibleBox::isColumnFlow() const
    353 {
    354     return style()->isColumnFlexDirection();
    355 }
    356 
    357 bool RenderFlexibleBox::isHorizontalFlow() const
    358 {
    359     if (isHorizontalWritingMode())
    360         return !isColumnFlow();
    361     return isColumnFlow();
    362 }
    363 
    364 bool RenderFlexibleBox::isLeftToRightFlow() const
    365 {
    366     if (isColumnFlow())
    367         return style()->writingMode() == TopToBottomWritingMode || style()->writingMode() == LeftToRightWritingMode;
    368     return style()->isLeftToRightDirection() ^ (style()->flexDirection() == FlowRowReverse);
    369 }
    370 
    371 bool RenderFlexibleBox::isMultiline() const
    372 {
    373     return style()->flexWrap() != FlexNoWrap;
    374 }
    375 
    376 Length RenderFlexibleBox::flexBasisForChild(RenderBox* child) const
    377 {
    378     Length flexLength = child->style()->flexBasis();
    379     if (flexLength.isAuto())
    380         flexLength = isHorizontalFlow() ? child->style()->width() : child->style()->height();
    381     return flexLength;
    382 }
    383 
    384 void RenderFlexibleBox::setCrossAxisExtent(LayoutUnit extent)
    385 {
    386     if (isHorizontalFlow())
    387         setHeight(extent);
    388     else
    389         setWidth(extent);
    390 }
    391 
    392 LayoutUnit RenderFlexibleBox::crossAxisExtentForChild(RenderBox* child) const
    393 {
    394     return isHorizontalFlow() ? child->height() : child->width();
    395 }
    396 
    397 LayoutUnit RenderFlexibleBox::mainAxisExtentForChild(RenderBox* child) const
    398 {
    399     return isHorizontalFlow() ? child->width() : child->height();
    400 }
    401 
    402 LayoutUnit RenderFlexibleBox::crossAxisExtent() const
    403 {
    404     return isHorizontalFlow() ? height() : width();
    405 }
    406 
    407 LayoutUnit RenderFlexibleBox::mainAxisExtent() const
    408 {
    409     return isHorizontalFlow() ? width() : height();
    410 }
    411 
    412 LayoutUnit RenderFlexibleBox::crossAxisContentExtent() const
    413 {
    414     return isHorizontalFlow() ? contentHeight() : contentWidth();
    415 }
    416 
    417 LayoutUnit RenderFlexibleBox::mainAxisContentExtent(LayoutUnit contentLogicalHeight)
    418 {
    419     if (isColumnFlow()) {
    420         LogicalExtentComputedValues computedValues;
    421         LayoutUnit borderPaddingAndScrollbar = borderAndPaddingLogicalHeight() + scrollbarLogicalHeight();
    422         // FIXME: Remove this std:max once we enable saturated layout arithmetic. It's just here to handle overflow.
    423         LayoutUnit borderBoxLogicalHeight = std::max(contentLogicalHeight, contentLogicalHeight + borderPaddingAndScrollbar);
    424         computeLogicalHeight(borderBoxLogicalHeight, logicalTop(), computedValues);
    425         if (computedValues.m_extent == LayoutUnit::max())
    426             return computedValues.m_extent;
    427         return std::max(LayoutUnit(0), computedValues.m_extent - borderPaddingAndScrollbar);
    428     }
    429     return contentLogicalWidth();
    430 }
    431 
    432 LayoutUnit RenderFlexibleBox::computeMainAxisExtentForChild(RenderBox* child, SizeType sizeType, const Length& size)
    433 {
    434     // FIXME: This is wrong for orthogonal flows. It should use the flexbox's writing-mode, not the child's in order
    435     // to figure out the logical height/width.
    436     if (isColumnFlow()) {
    437         // We don't have to check for "auto" here - computeContentLogicalHeight will just return -1 for that case anyway.
    438         if (size.isIntrinsic())
    439             child->layoutIfNeeded();
    440         return child->computeContentLogicalHeight(size, child->logicalHeight() - child->borderAndPaddingLogicalHeight());
    441     }
    442     // FIXME: Figure out how this should work for regions and pass in the appropriate values.
    443     RenderRegion* region = 0;
    444     return child->computeLogicalWidthInRegionUsing(sizeType, size, contentLogicalWidth(), this, region) - child->borderAndPaddingLogicalWidth();
    445 }
    446 
    447 WritingMode RenderFlexibleBox::transformedWritingMode() const
    448 {
    449     WritingMode mode = style()->writingMode();
    450     if (!isColumnFlow())
    451         return mode;
    452 
    453     switch (mode) {
    454     case TopToBottomWritingMode:
    455     case BottomToTopWritingMode:
    456         return style()->isLeftToRightDirection() ? LeftToRightWritingMode : RightToLeftWritingMode;
    457     case LeftToRightWritingMode:
    458     case RightToLeftWritingMode:
    459         return style()->isLeftToRightDirection() ? TopToBottomWritingMode : BottomToTopWritingMode;
    460     }
    461     ASSERT_NOT_REACHED();
    462     return TopToBottomWritingMode;
    463 }
    464 
    465 LayoutUnit RenderFlexibleBox::flowAwareBorderStart() const
    466 {
    467     if (isHorizontalFlow())
    468         return isLeftToRightFlow() ? borderLeft() : borderRight();
    469     return isLeftToRightFlow() ? borderTop() : borderBottom();
    470 }
    471 
    472 LayoutUnit RenderFlexibleBox::flowAwareBorderEnd() const
    473 {
    474     if (isHorizontalFlow())
    475         return isLeftToRightFlow() ? borderRight() : borderLeft();
    476     return isLeftToRightFlow() ? borderBottom() : borderTop();
    477 }
    478 
    479 LayoutUnit RenderFlexibleBox::flowAwareBorderBefore() const
    480 {
    481     switch (transformedWritingMode()) {
    482     case TopToBottomWritingMode:
    483         return borderTop();
    484     case BottomToTopWritingMode:
    485         return borderBottom();
    486     case LeftToRightWritingMode:
    487         return borderLeft();
    488     case RightToLeftWritingMode:
    489         return borderRight();
    490     }
    491     ASSERT_NOT_REACHED();
    492     return borderTop();
    493 }
    494 
    495 LayoutUnit RenderFlexibleBox::flowAwareBorderAfter() const
    496 {
    497     switch (transformedWritingMode()) {
    498     case TopToBottomWritingMode:
    499         return borderBottom();
    500     case BottomToTopWritingMode:
    501         return borderTop();
    502     case LeftToRightWritingMode:
    503         return borderRight();
    504     case RightToLeftWritingMode:
    505         return borderLeft();
    506     }
    507     ASSERT_NOT_REACHED();
    508     return borderTop();
    509 }
    510 
    511 LayoutUnit RenderFlexibleBox::flowAwarePaddingStart() const
    512 {
    513     if (isHorizontalFlow())
    514         return isLeftToRightFlow() ? paddingLeft() : paddingRight();
    515     return isLeftToRightFlow() ? paddingTop() : paddingBottom();
    516 }
    517 
    518 LayoutUnit RenderFlexibleBox::flowAwarePaddingEnd() const
    519 {
    520     if (isHorizontalFlow())
    521         return isLeftToRightFlow() ? paddingRight() : paddingLeft();
    522     return isLeftToRightFlow() ? paddingBottom() : paddingTop();
    523 }
    524 
    525 LayoutUnit RenderFlexibleBox::flowAwarePaddingBefore() const
    526 {
    527     switch (transformedWritingMode()) {
    528     case TopToBottomWritingMode:
    529         return paddingTop();
    530     case BottomToTopWritingMode:
    531         return paddingBottom();
    532     case LeftToRightWritingMode:
    533         return paddingLeft();
    534     case RightToLeftWritingMode:
    535         return paddingRight();
    536     }
    537     ASSERT_NOT_REACHED();
    538     return paddingTop();
    539 }
    540 
    541 LayoutUnit RenderFlexibleBox::flowAwarePaddingAfter() const
    542 {
    543     switch (transformedWritingMode()) {
    544     case TopToBottomWritingMode:
    545         return paddingBottom();
    546     case BottomToTopWritingMode:
    547         return paddingTop();
    548     case LeftToRightWritingMode:
    549         return paddingRight();
    550     case RightToLeftWritingMode:
    551         return paddingLeft();
    552     }
    553     ASSERT_NOT_REACHED();
    554     return paddingTop();
    555 }
    556 
    557 LayoutUnit RenderFlexibleBox::flowAwareMarginStartForChild(RenderBox* child) const
    558 {
    559     if (isHorizontalFlow())
    560         return isLeftToRightFlow() ? child->marginLeft() : child->marginRight();
    561     return isLeftToRightFlow() ? child->marginTop() : child->marginBottom();
    562 }
    563 
    564 LayoutUnit RenderFlexibleBox::flowAwareMarginEndForChild(RenderBox* child) const
    565 {
    566     if (isHorizontalFlow())
    567         return isLeftToRightFlow() ? child->marginRight() : child->marginLeft();
    568     return isLeftToRightFlow() ? child->marginBottom() : child->marginTop();
    569 }
    570 
    571 LayoutUnit RenderFlexibleBox::flowAwareMarginBeforeForChild(RenderBox* child) const
    572 {
    573     switch (transformedWritingMode()) {
    574     case TopToBottomWritingMode:
    575         return child->marginTop();
    576     case BottomToTopWritingMode:
    577         return child->marginBottom();
    578     case LeftToRightWritingMode:
    579         return child->marginLeft();
    580     case RightToLeftWritingMode:
    581         return child->marginRight();
    582     }
    583     ASSERT_NOT_REACHED();
    584     return marginTop();
    585 }
    586 
    587 LayoutUnit RenderFlexibleBox::flowAwareMarginAfterForChild(RenderBox* child) const
    588 {
    589     switch (transformedWritingMode()) {
    590     case TopToBottomWritingMode:
    591         return child->marginBottom();
    592     case BottomToTopWritingMode:
    593         return child->marginTop();
    594     case LeftToRightWritingMode:
    595         return child->marginRight();
    596     case RightToLeftWritingMode:
    597         return child->marginLeft();
    598     }
    599     ASSERT_NOT_REACHED();
    600     return marginBottom();
    601 }
    602 
    603 LayoutUnit RenderFlexibleBox::crossAxisMarginExtentForChild(RenderBox* child) const
    604 {
    605     return isHorizontalFlow() ? child->marginHeight() : child->marginWidth();
    606 }
    607 
    608 LayoutUnit RenderFlexibleBox::crossAxisScrollbarExtent() const
    609 {
    610     return isHorizontalFlow() ? horizontalScrollbarHeight() : verticalScrollbarWidth();
    611 }
    612 
    613 LayoutPoint RenderFlexibleBox::flowAwareLocationForChild(RenderBox* child) const
    614 {
    615     return isHorizontalFlow() ? child->location() : child->location().transposedPoint();
    616 }
    617 
    618 void RenderFlexibleBox::setFlowAwareLocationForChild(RenderBox* child, const LayoutPoint& location)
    619 {
    620     if (isHorizontalFlow())
    621         child->setLocation(location);
    622     else
    623         child->setLocation(location.transposedPoint());
    624 }
    625 
    626 LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox* child) const
    627 {
    628     return isHorizontalFlow() ? child->borderAndPaddingWidth() : child->borderAndPaddingHeight();
    629 }
    630 
    631 LayoutUnit RenderFlexibleBox::mainAxisScrollbarExtentForChild(RenderBox* child) const
    632 {
    633     return isHorizontalFlow() ? child->verticalScrollbarWidth() : child->horizontalScrollbarHeight();
    634 }
    635 
    636 LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* child, bool hasInfiniteLineLength)
    637 {
    638     bool hasOverrideSize = child->hasOverrideWidth() || child->hasOverrideHeight();
    639     if (hasOverrideSize)
    640         child->clearOverrideSize();
    641 
    642     Length flexBasis = flexBasisForChild(child);
    643     if (flexBasis.isAuto() || (flexBasis.isFixed() && !flexBasis.value() && hasInfiniteLineLength)) {
    644         if (hasOrthogonalFlow(child)) {
    645             if (hasOverrideSize)
    646                 child->setChildNeedsLayout(MarkOnlyThis);
    647             child->layoutIfNeeded();
    648         }
    649         LayoutUnit mainAxisExtent = hasOrthogonalFlow(child) ? child->logicalHeight() : child->maxPreferredLogicalWidth();
    650         ASSERT(mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child) >= 0);
    651         return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child);
    652     }
    653     return std::max(LayoutUnit(0), computeMainAxisExtentForChild(child, MainOrPreferredSize, flexBasis));
    654 }
    655 
    656 void RenderFlexibleBox::layoutFlexItems(bool relayoutChildren, Vector<LineContext>& lineContexts)
    657 {
    658     OrderedFlexItemList orderedChildren;
    659     LayoutUnit sumFlexBaseSize;
    660     double totalFlexGrow;
    661     double totalWeightedFlexShrink;
    662     LayoutUnit sumHypotheticalMainSize;
    663 
    664     m_orderIterator.first();
    665     LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
    666     bool hasInfiniteLineLength = false;
    667     while (computeNextFlexLine(orderedChildren, sumFlexBaseSize, totalFlexGrow, totalWeightedFlexShrink, sumHypotheticalMainSize, hasInfiniteLineLength)) {
    668         LayoutUnit containerMainInnerSize = mainAxisContentExtent(sumHypotheticalMainSize);
    669         LayoutUnit availableFreeSpace = containerMainInnerSize - sumFlexBaseSize;
    670         FlexSign flexSign = (sumHypotheticalMainSize < containerMainInnerSize) ? PositiveFlexibility : NegativeFlexibility;
    671         InflexibleFlexItemSize inflexibleItems;
    672         Vector<LayoutUnit> childSizes;
    673         while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, childSizes, hasInfiniteLineLength)) {
    674             ASSERT(totalFlexGrow >= 0 && totalWeightedFlexShrink >= 0);
    675             ASSERT(inflexibleItems.size() > 0);
    676         }
    677 
    678         layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace, relayoutChildren, lineContexts);
    679     }
    680     if (hasLineIfEmpty()) {
    681         // Even if computeNextFlexLine returns true, the flexbox might not have
    682         // a line because all our children might be out of flow positioned.
    683         // Instead of just checking if we have a line, make sure the flexbox
    684         // has at least a line's worth of height to cover this case.
    685         LayoutUnit minHeight = borderAndPaddingLogicalHeight()
    686             + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes)
    687             + scrollbarLogicalHeight();
    688         if (height() < minHeight)
    689             setLogicalHeight(minHeight);
    690     }
    691 }
    692 
    693 LayoutUnit RenderFlexibleBox::autoMarginOffsetInMainAxis(const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace)
    694 {
    695     if (availableFreeSpace <= 0)
    696         return 0;
    697 
    698     int numberOfAutoMargins = 0;
    699     bool isHorizontal = isHorizontalFlow();
    700     for (size_t i = 0; i < children.size(); ++i) {
    701         RenderBox* child = children[i];
    702         if (child->isOutOfFlowPositioned())
    703             continue;
    704         if (isHorizontal) {
    705             if (child->style()->marginLeft().isAuto())
    706                 ++numberOfAutoMargins;
    707             if (child->style()->marginRight().isAuto())
    708                 ++numberOfAutoMargins;
    709         } else {
    710             if (child->style()->marginTop().isAuto())
    711                 ++numberOfAutoMargins;
    712             if (child->style()->marginBottom().isAuto())
    713                 ++numberOfAutoMargins;
    714         }
    715     }
    716     if (!numberOfAutoMargins)
    717         return 0;
    718 
    719     LayoutUnit sizeOfAutoMargin = availableFreeSpace / numberOfAutoMargins;
    720     availableFreeSpace = 0;
    721     return sizeOfAutoMargin;
    722 }
    723 
    724 void RenderFlexibleBox::updateAutoMarginsInMainAxis(RenderBox* child, LayoutUnit autoMarginOffset)
    725 {
    726     ASSERT(autoMarginOffset >= 0);
    727 
    728     if (isHorizontalFlow()) {
    729         if (child->style()->marginLeft().isAuto())
    730             child->setMarginLeft(autoMarginOffset);
    731         if (child->style()->marginRight().isAuto())
    732             child->setMarginRight(autoMarginOffset);
    733     } else {
    734         if (child->style()->marginTop().isAuto())
    735             child->setMarginTop(autoMarginOffset);
    736         if (child->style()->marginBottom().isAuto())
    737             child->setMarginBottom(autoMarginOffset);
    738     }
    739 }
    740 
    741 bool RenderFlexibleBox::hasAutoMarginsInCrossAxis(RenderBox* child) const
    742 {
    743     if (isHorizontalFlow())
    744         return child->style()->marginTop().isAuto() || child->style()->marginBottom().isAuto();
    745     return child->style()->marginLeft().isAuto() || child->style()->marginRight().isAuto();
    746 }
    747 
    748 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox* child)
    749 {
    750     ASSERT(!child->isOutOfFlowPositioned());
    751     LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child);
    752     return lineCrossAxisExtent - childCrossExtent;
    753 }
    754 
    755 bool RenderFlexibleBox::updateAutoMarginsInCrossAxis(RenderBox* child, LayoutUnit availableAlignmentSpace)
    756 {
    757     ASSERT(!child->isOutOfFlowPositioned());
    758     ASSERT(availableAlignmentSpace >= 0);
    759 
    760     bool isHorizontal = isHorizontalFlow();
    761     Length topOrLeft = isHorizontal ? child->style()->marginTop() : child->style()->marginLeft();
    762     Length bottomOrRight = isHorizontal ? child->style()->marginBottom() : child->style()->marginRight();
    763     if (topOrLeft.isAuto() && bottomOrRight.isAuto()) {
    764         adjustAlignmentForChild(child, availableAlignmentSpace / 2);
    765         if (isHorizontal) {
    766             child->setMarginTop(availableAlignmentSpace / 2);
    767             child->setMarginBottom(availableAlignmentSpace / 2);
    768         } else {
    769             child->setMarginLeft(availableAlignmentSpace / 2);
    770             child->setMarginRight(availableAlignmentSpace / 2);
    771         }
    772         return true;
    773     }
    774     bool shouldAdjustTopOrLeft = true;
    775     if (isColumnFlow() && !child->style()->isLeftToRightDirection()) {
    776         // For column flows, only make this adjustment if topOrLeft corresponds to the "before" margin,
    777         // so that flipForRightToLeftColumn will do the right thing.
    778         shouldAdjustTopOrLeft = false;
    779     }
    780     if (!isColumnFlow() && child->style()->isFlippedBlocksWritingMode()) {
    781         // If we are a flipped writing mode, we need to adjust the opposite side. This is only needed
    782         // for row flows because this only affects the block-direction axis.
    783         shouldAdjustTopOrLeft = false;
    784     }
    785 
    786     if (topOrLeft.isAuto()) {
    787         if (shouldAdjustTopOrLeft)
    788             adjustAlignmentForChild(child, availableAlignmentSpace);
    789 
    790         if (isHorizontal)
    791             child->setMarginTop(availableAlignmentSpace);
    792         else
    793             child->setMarginLeft(availableAlignmentSpace);
    794         return true;
    795     }
    796     if (bottomOrRight.isAuto()) {
    797         if (!shouldAdjustTopOrLeft)
    798             adjustAlignmentForChild(child, availableAlignmentSpace);
    799 
    800         if (isHorizontal)
    801             child->setMarginBottom(availableAlignmentSpace);
    802         else
    803             child->setMarginRight(availableAlignmentSpace);
    804         return true;
    805     }
    806     return false;
    807 }
    808 
    809 LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(RenderBox* child)
    810 {
    811     LayoutUnit ascent = child->firstLineBoxBaseline();
    812     if (ascent == -1)
    813         ascent = crossAxisExtentForChild(child);
    814     return ascent + flowAwareMarginBeforeForChild(child);
    815 }
    816 
    817 LayoutUnit RenderFlexibleBox::computeChildMarginValue(Length margin, RenderView* view)
    818 {
    819     // When resolving the margins, we use the content size for resolving percent and calc (for percents in calc expressions) margins.
    820     // Fortunately, percent margins are always computed with respect to the block's width, even for margin-top and margin-bottom.
    821     LayoutUnit availableSize = contentLogicalWidth();
    822     return minimumValueForLength(margin, availableSize, view);
    823 }
    824 
    825 void RenderFlexibleBox::prepareOrderIteratorAndMargins()
    826 {
    827     RenderView* renderView = view();
    828     OrderIteratorPopulator populator(m_orderIterator);
    829 
    830     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
    831         populator.collectChild(child);
    832 
    833         if (child->isOutOfFlowPositioned())
    834             continue;
    835 
    836         // Before running the flex algorithm, 'auto' has a margin of 0.
    837         // Also, if we're not auto sizing, we don't do a layout that computes the start/end margins.
    838         if (isHorizontalFlow()) {
    839             child->setMarginLeft(computeChildMarginValue(child->style()->marginLeft(), renderView));
    840             child->setMarginRight(computeChildMarginValue(child->style()->marginRight(), renderView));
    841         } else {
    842             child->setMarginTop(computeChildMarginValue(child->style()->marginTop(), renderView));
    843             child->setMarginBottom(computeChildMarginValue(child->style()->marginBottom(), renderView));
    844         }
    845     }
    846 }
    847 
    848 LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox* child, LayoutUnit childSize)
    849 {
    850     Length max = isHorizontalFlow() ? child->style()->maxWidth() : child->style()->maxHeight();
    851     if (max.isSpecifiedOrIntrinsic()) {
    852         LayoutUnit maxExtent = computeMainAxisExtentForChild(child, MaxSize, max);
    853         if (maxExtent != -1 && childSize > maxExtent)
    854             childSize = maxExtent;
    855     }
    856 
    857     Length min = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
    858     LayoutUnit minExtent = 0;
    859     if (min.isSpecifiedOrIntrinsic())
    860         minExtent = computeMainAxisExtentForChild(child, MinSize, min);
    861     return std::max(childSize, minExtent);
    862 }
    863 
    864 bool RenderFlexibleBox::computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& sumFlexBaseSize, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& sumHypotheticalMainSize, bool& hasInfiniteLineLength)
    865 {
    866     orderedChildren.clear();
    867     sumFlexBaseSize = 0;
    868     totalFlexGrow = totalWeightedFlexShrink = 0;
    869     sumHypotheticalMainSize = 0;
    870 
    871     if (!m_orderIterator.currentChild())
    872         return false;
    873 
    874     LayoutUnit lineBreakLength = mainAxisContentExtent(LayoutUnit::max());
    875     hasInfiniteLineLength = lineBreakLength == LayoutUnit::max();
    876 
    877     bool lineHasInFlowItem = false;
    878 
    879     for (RenderBox* child = m_orderIterator.currentChild(); child; child = m_orderIterator.next()) {
    880         if (child->isOutOfFlowPositioned()) {
    881             orderedChildren.append(child);
    882             continue;
    883         }
    884 
    885         LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
    886         LayoutUnit childMainAxisMarginBorderPadding = mainAxisBorderAndPaddingExtentForChild(child)
    887             + (isHorizontalFlow() ? child->marginWidth() : child->marginHeight());
    888         LayoutUnit childFlexBaseSize = childMainAxisExtent + childMainAxisMarginBorderPadding;
    889 
    890         LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(child, childMainAxisExtent);
    891         LayoutUnit childHypotheticalMainSize = childMinMaxAppliedMainAxisExtent + childMainAxisMarginBorderPadding;
    892 
    893         if (isMultiline() && sumHypotheticalMainSize + childHypotheticalMainSize > lineBreakLength && lineHasInFlowItem)
    894             break;
    895         orderedChildren.append(child);
    896         lineHasInFlowItem  = true;
    897         sumFlexBaseSize += childFlexBaseSize;
    898         totalFlexGrow += child->style()->flexGrow();
    899         totalWeightedFlexShrink += child->style()->flexShrink() * childMainAxisExtent;
    900         sumHypotheticalMainSize += childHypotheticalMainSize;
    901     }
    902     return true;
    903 }
    904 
    905 void RenderFlexibleBox::freezeViolations(const Vector<Violation>& violations, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, bool hasInfiniteLineLength)
    906 {
    907     for (size_t i = 0; i < violations.size(); ++i) {
    908         RenderBox* child = violations[i].child;
    909         LayoutUnit childSize = violations[i].childSize;
    910         LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
    911         availableFreeSpace -= childSize - preferredChildSize;
    912         totalFlexGrow -= child->style()->flexGrow();
    913         totalWeightedFlexShrink -= child->style()->flexShrink() * preferredChildSize;
    914         inflexibleItems.set(child, childSize);
    915     }
    916 }
    917 
    918 // Returns true if we successfully ran the algorithm and sized the flex items.
    919 bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, Vector<LayoutUnit>& childSizes, bool hasInfiniteLineLength)
    920 {
    921     childSizes.clear();
    922     LayoutUnit totalViolation = 0;
    923     LayoutUnit usedFreeSpace = 0;
    924     Vector<Violation> minViolations;
    925     Vector<Violation> maxViolations;
    926     for (size_t i = 0; i < children.size(); ++i) {
    927         RenderBox* child = children[i];
    928         if (child->isOutOfFlowPositioned()) {
    929             childSizes.append(0);
    930             continue;
    931         }
    932 
    933         if (inflexibleItems.contains(child))
    934             childSizes.append(inflexibleItems.get(child));
    935         else {
    936             LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
    937             LayoutUnit childSize = preferredChildSize;
    938             double extraSpace = 0;
    939             if (availableFreeSpace > 0 && totalFlexGrow > 0 && flexSign == PositiveFlexibility && std::isfinite(totalFlexGrow))
    940                 extraSpace = availableFreeSpace * child->style()->flexGrow() / totalFlexGrow;
    941             else if (availableFreeSpace < 0 && totalWeightedFlexShrink > 0 && flexSign == NegativeFlexibility && std::isfinite(totalWeightedFlexShrink))
    942                 extraSpace = availableFreeSpace * child->style()->flexShrink() * preferredChildSize / totalWeightedFlexShrink;
    943             if (std::isfinite(extraSpace))
    944                 childSize += LayoutUnit::fromFloatRound(extraSpace);
    945 
    946             LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(child, childSize);
    947             childSizes.append(adjustedChildSize);
    948             usedFreeSpace += adjustedChildSize - preferredChildSize;
    949 
    950             LayoutUnit violation = adjustedChildSize - childSize;
    951             if (violation > 0)
    952                 minViolations.append(Violation(child, adjustedChildSize));
    953             else if (violation < 0)
    954                 maxViolations.append(Violation(child, adjustedChildSize));
    955             totalViolation += violation;
    956         }
    957     }
    958 
    959     if (totalViolation)
    960         freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, hasInfiniteLineLength);
    961     else
    962         availableFreeSpace -= usedFreeSpace;
    963 
    964     return !totalViolation;
    965 }
    966 
    967 static LayoutUnit initialJustifyContentOffset(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
    968 {
    969     if (justifyContent == JustifyFlexEnd)
    970         return availableFreeSpace;
    971     if (justifyContent == JustifyCenter)
    972         return availableFreeSpace / 2;
    973     if (justifyContent == JustifySpaceAround) {
    974         if (availableFreeSpace > 0 && numberOfChildren)
    975             return availableFreeSpace / (2 * numberOfChildren);
    976         else
    977             return availableFreeSpace / 2;
    978     }
    979     return 0;
    980 }
    981 
    982 static LayoutUnit justifyContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
    983 {
    984     if (availableFreeSpace > 0 && numberOfChildren > 1) {
    985         if (justifyContent == JustifySpaceBetween)
    986             return availableFreeSpace / (numberOfChildren - 1);
    987         if (justifyContent == JustifySpaceAround)
    988             return availableFreeSpace / numberOfChildren;
    989     }
    990     return 0;
    991 }
    992 
    993 void RenderFlexibleBox::setLogicalOverrideSize(RenderBox* child, LayoutUnit childPreferredSize)
    994 {
    995     if (hasOrthogonalFlow(child))
    996         child->setOverrideLogicalContentHeight(childPreferredSize - child->borderAndPaddingLogicalHeight());
    997     else
    998         child->setOverrideLogicalContentWidth(childPreferredSize - child->borderAndPaddingLogicalWidth());
    999 }
   1000 
   1001 void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox* child, LayoutUnit mainAxisOffset, LayoutUnit crossAxisOffset, PositionedLayoutMode layoutMode)
   1002 {
   1003     ASSERT(child->isOutOfFlowPositioned());
   1004     child->containingBlock()->insertPositionedObject(child);
   1005     RenderLayer* childLayer = child->layer();
   1006     LayoutUnit inlinePosition = isColumnFlow() ? crossAxisOffset : mainAxisOffset;
   1007     if (layoutMode == FlipForRowReverse && style()->flexDirection() == FlowRowReverse)
   1008         inlinePosition = mainAxisExtent() - mainAxisOffset;
   1009     childLayer->setStaticInlinePosition(inlinePosition); // FIXME: Not right for regions.
   1010 
   1011     LayoutUnit staticBlockPosition = isColumnFlow() ? mainAxisOffset : crossAxisOffset;
   1012     if (childLayer->staticBlockPosition() != staticBlockPosition) {
   1013         childLayer->setStaticBlockPosition(staticBlockPosition);
   1014         if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
   1015             child->setChildNeedsLayout(MarkOnlyThis);
   1016     }
   1017 }
   1018 
   1019 EAlignItems RenderFlexibleBox::alignmentForChild(RenderBox* child) const
   1020 {
   1021     EAlignItems align = resolveAlignment(style(), child->style());
   1022 
   1023     if (align == AlignBaseline && hasOrthogonalFlow(child))
   1024         align = AlignFlexStart;
   1025 
   1026     if (style()->flexWrap() == FlexWrapReverse) {
   1027         if (align == AlignFlexStart)
   1028             align = AlignFlexEnd;
   1029         else if (align == AlignFlexEnd)
   1030             align = AlignFlexStart;
   1031     }
   1032 
   1033     return align;
   1034 }
   1035 
   1036 size_t RenderFlexibleBox::numberOfInFlowPositionedChildren(const OrderedFlexItemList& children) const
   1037 {
   1038     size_t count = 0;
   1039     for (size_t i = 0; i < children.size(); ++i) {
   1040         RenderBox* child = children[i];
   1041         if (!child->isOutOfFlowPositioned())
   1042             ++count;
   1043     }
   1044     return count;
   1045 }
   1046 
   1047 bool RenderFlexibleBox::needToStretchChild(RenderBox* child)
   1048 {
   1049     if (alignmentForChild(child) != AlignStretch)
   1050         return false;
   1051 
   1052     Length crossAxisLength = isHorizontalFlow() ? child->style()->height() : child->style()->width();
   1053     return crossAxisLength.isAuto();
   1054 }
   1055 
   1056 void RenderFlexibleBox::resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox* child)
   1057 {
   1058     if (hasAutoMarginsInCrossAxis(child))
   1059         child->updateLogicalHeight();
   1060 }
   1061 
   1062 void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace, bool relayoutChildren, Vector<LineContext>& lineContexts)
   1063 {
   1064     ASSERT(childSizes.size() == children.size());
   1065 
   1066     size_t numberOfChildrenForJustifyContent = numberOfInFlowPositionedChildren(children);
   1067     LayoutUnit autoMarginOffset = autoMarginOffsetInMainAxis(children, availableFreeSpace);
   1068     LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart();
   1069     mainAxisOffset += initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
   1070     if (style()->flexDirection() == FlowRowReverse)
   1071         mainAxisOffset += isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
   1072 
   1073     LayoutUnit totalMainExtent = mainAxisExtent();
   1074     LayoutUnit maxAscent = 0, maxDescent = 0; // Used when align-items: baseline.
   1075     LayoutUnit maxChildCrossAxisExtent = 0;
   1076     size_t seenInFlowPositionedChildren = 0;
   1077     bool shouldFlipMainAxis = !isColumnFlow() && !isLeftToRightFlow();
   1078     for (size_t i = 0; i < children.size(); ++i) {
   1079         RenderBox* child = children[i];
   1080         if (child->isOutOfFlowPositioned()) {
   1081             prepareChildForPositionedLayout(child, mainAxisOffset, crossAxisOffset, FlipForRowReverse);
   1082             continue;
   1083         }
   1084 
   1085         LayoutUnit childPreferredSize = childSizes[i] + mainAxisBorderAndPaddingExtentForChild(child);
   1086         setLogicalOverrideSize(child, childPreferredSize);
   1087         // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
   1088         if (needToStretchChild(child) || childPreferredSize != mainAxisExtentForChild(child))
   1089             child->setChildNeedsLayout(MarkOnlyThis);
   1090         else {
   1091             // To avoid double applying margin changes in updateAutoMarginsInCrossAxis, we reset the margins here.
   1092             resetAutoMarginsAndLogicalTopInCrossAxis(child);
   1093         }
   1094         updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
   1095         child->layoutIfNeeded();
   1096 
   1097         updateAutoMarginsInMainAxis(child, autoMarginOffset);
   1098 
   1099         LayoutUnit childCrossAxisMarginBoxExtent;
   1100         if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child)) {
   1101             LayoutUnit ascent = marginBoxAscentForChild(child);
   1102             LayoutUnit descent = (crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child)) - ascent;
   1103 
   1104             maxAscent = std::max(maxAscent, ascent);
   1105             maxDescent = std::max(maxDescent, descent);
   1106 
   1107             childCrossAxisMarginBoxExtent = maxAscent + maxDescent;
   1108         } else
   1109             childCrossAxisMarginBoxExtent = crossAxisExtentForChild(child) + crossAxisMarginExtentForChild(child);
   1110         if (!isColumnFlow())
   1111             setLogicalHeight(std::max(logicalHeight(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent()));
   1112         maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisMarginBoxExtent);
   1113 
   1114         mainAxisOffset += flowAwareMarginStartForChild(child);
   1115 
   1116         LayoutUnit childMainExtent = mainAxisExtentForChild(child);
   1117         // In an RTL column situation, this will apply the margin-right/margin-end on the left.
   1118         // This will be fixed later in flipForRightToLeftColumn.
   1119         LayoutPoint childLocation(shouldFlipMainAxis ? totalMainExtent - mainAxisOffset - childMainExtent : mainAxisOffset,
   1120             crossAxisOffset + flowAwareMarginBeforeForChild(child));
   1121 
   1122         // FIXME: Supporting layout deltas.
   1123         setFlowAwareLocationForChild(child, childLocation);
   1124         mainAxisOffset += childMainExtent + flowAwareMarginEndForChild(child);
   1125 
   1126         ++seenInFlowPositionedChildren;
   1127         if (seenInFlowPositionedChildren < numberOfChildrenForJustifyContent)
   1128             mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
   1129     }
   1130 
   1131     if (isColumnFlow())
   1132         setLogicalHeight(mainAxisOffset + flowAwareBorderEnd() + flowAwarePaddingEnd() + scrollbarLogicalHeight());
   1133 
   1134     if (style()->flexDirection() == FlowColumnReverse) {
   1135         // We have to do an extra pass for column-reverse to reposition the flex items since the start depends
   1136         // on the height of the flexbox, which we only know after we've positioned all the flex items.
   1137         updateLogicalHeight();
   1138         layoutColumnReverse(children, crossAxisOffset, availableFreeSpace);
   1139     }
   1140 
   1141     if (m_numberOfInFlowChildrenOnFirstLine == -1)
   1142         m_numberOfInFlowChildrenOnFirstLine = seenInFlowPositionedChildren;
   1143     lineContexts.append(LineContext(crossAxisOffset, maxChildCrossAxisExtent, children.size(), maxAscent));
   1144     crossAxisOffset += maxChildCrossAxisExtent;
   1145 }
   1146 
   1147 void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace)
   1148 {
   1149     // This is similar to the logic in layoutAndPlaceChildren, except we place the children
   1150     // starting from the end of the flexbox. We also don't need to layout anything since we're
   1151     // just moving the children to a new position.
   1152     size_t numberOfChildrenForJustifyContent = numberOfInFlowPositionedChildren(children);
   1153     LayoutUnit mainAxisOffset = logicalHeight() - flowAwareBorderEnd() - flowAwarePaddingEnd();
   1154     mainAxisOffset -= initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
   1155     mainAxisOffset -= isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
   1156 
   1157     size_t seenInFlowPositionedChildren = 0;
   1158     for (size_t i = 0; i < children.size(); ++i) {
   1159         RenderBox* child = children[i];
   1160         if (child->isOutOfFlowPositioned()) {
   1161             child->layer()->setStaticBlockPosition(mainAxisOffset);
   1162             continue;
   1163         }
   1164         mainAxisOffset -= mainAxisExtentForChild(child) + flowAwareMarginEndForChild(child);
   1165 
   1166         setFlowAwareLocationForChild(child, LayoutPoint(mainAxisOffset, crossAxisOffset + flowAwareMarginBeforeForChild(child)));
   1167 
   1168         mainAxisOffset -= flowAwareMarginStartForChild(child);
   1169 
   1170         ++seenInFlowPositionedChildren;
   1171         if (seenInFlowPositionedChildren < numberOfChildrenForJustifyContent)
   1172             mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
   1173     }
   1174 }
   1175 
   1176 static LayoutUnit initialAlignContentOffset(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
   1177 {
   1178     if (alignContent == AlignContentFlexEnd)
   1179         return availableFreeSpace;
   1180     if (alignContent == AlignContentCenter)
   1181         return availableFreeSpace / 2;
   1182     if (alignContent == AlignContentSpaceAround) {
   1183         if (availableFreeSpace > 0 && numberOfLines)
   1184             return availableFreeSpace / (2 * numberOfLines);
   1185         if (availableFreeSpace < 0)
   1186             return availableFreeSpace / 2;
   1187     }
   1188     return 0;
   1189 }
   1190 
   1191 static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
   1192 {
   1193     if (availableFreeSpace > 0 && numberOfLines > 1) {
   1194         if (alignContent == AlignContentSpaceBetween)
   1195             return availableFreeSpace / (numberOfLines - 1);
   1196         if (alignContent == AlignContentSpaceAround || alignContent == AlignContentStretch)
   1197             return availableFreeSpace / numberOfLines;
   1198     }
   1199     return 0;
   1200 }
   1201 
   1202 void RenderFlexibleBox::alignFlexLines(Vector<LineContext>& lineContexts)
   1203 {
   1204     if (!isMultiline() || style()->alignContent() == AlignContentFlexStart)
   1205         return;
   1206 
   1207     LayoutUnit availableCrossAxisSpace = crossAxisContentExtent();
   1208     for (size_t i = 0; i < lineContexts.size(); ++i)
   1209         availableCrossAxisSpace -= lineContexts[i].crossAxisExtent;
   1210 
   1211     RenderBox* child = m_orderIterator.first();
   1212     LayoutUnit lineOffset = initialAlignContentOffset(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
   1213     for (unsigned lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
   1214         lineContexts[lineNumber].crossAxisOffset += lineOffset;
   1215         for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next())
   1216             adjustAlignmentForChild(child, lineOffset);
   1217 
   1218         if (style()->alignContent() == AlignContentStretch && availableCrossAxisSpace > 0)
   1219             lineContexts[lineNumber].crossAxisExtent += availableCrossAxisSpace / static_cast<unsigned>(lineContexts.size());
   1220 
   1221         lineOffset += alignContentSpaceBetweenChildren(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
   1222     }
   1223 }
   1224 
   1225 void RenderFlexibleBox::adjustAlignmentForChild(RenderBox* child, LayoutUnit delta)
   1226 {
   1227     if (child->isOutOfFlowPositioned()) {
   1228         LayoutUnit staticInlinePosition = child->layer()->staticInlinePosition();
   1229         LayoutUnit staticBlockPosition = child->layer()->staticBlockPosition();
   1230         LayoutUnit mainAxis = isColumnFlow() ? staticBlockPosition : staticInlinePosition;
   1231         LayoutUnit crossAxis = isColumnFlow() ? staticInlinePosition : staticBlockPosition;
   1232         crossAxis += delta;
   1233         prepareChildForPositionedLayout(child, mainAxis, crossAxis, NoFlipForRowReverse);
   1234         return;
   1235     }
   1236 
   1237     setFlowAwareLocationForChild(child, flowAwareLocationForChild(child) + LayoutSize(0, delta));
   1238 }
   1239 
   1240 void RenderFlexibleBox::alignChildren(const Vector<LineContext>& lineContexts)
   1241 {
   1242     // Keep track of the space between the baseline edge and the after edge of the box for each line.
   1243     Vector<LayoutUnit> minMarginAfterBaselines;
   1244 
   1245     RenderBox* child = m_orderIterator.first();
   1246     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
   1247         LayoutUnit minMarginAfterBaseline = LayoutUnit::max();
   1248         LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
   1249         LayoutUnit maxAscent = lineContexts[lineNumber].maxAscent;
   1250 
   1251         for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
   1252             ASSERT(child);
   1253             if (child->isOutOfFlowPositioned()) {
   1254                 if (style()->flexWrap() == FlexWrapReverse)
   1255                     adjustAlignmentForChild(child, lineCrossAxisExtent);
   1256                 continue;
   1257             }
   1258 
   1259             if (updateAutoMarginsInCrossAxis(child, std::max(LayoutUnit(0), availableAlignmentSpaceForChild(lineCrossAxisExtent, child))))
   1260                 continue;
   1261 
   1262             switch (alignmentForChild(child)) {
   1263             case AlignAuto:
   1264                 ASSERT_NOT_REACHED();
   1265                 break;
   1266             case AlignStretch: {
   1267                 applyStretchAlignmentToChild(child, lineCrossAxisExtent);
   1268                 // Since wrap-reverse flips cross start and cross end, strech children should be aligned with the cross end.
   1269                 if (style()->flexWrap() == FlexWrapReverse)
   1270                     adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
   1271                 break;
   1272             }
   1273             case AlignFlexStart:
   1274                 break;
   1275             case AlignFlexEnd:
   1276                 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
   1277                 break;
   1278             case AlignCenter:
   1279                 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) / 2);
   1280                 break;
   1281             case AlignBaseline: {
   1282                 // 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.
   1283                 // https://bugs.webkit.org/show_bug.cgi?id=98076
   1284                 LayoutUnit ascent = marginBoxAscentForChild(child);
   1285                 LayoutUnit startOffset = maxAscent - ascent;
   1286                 adjustAlignmentForChild(child, startOffset);
   1287 
   1288                 if (style()->flexWrap() == FlexWrapReverse)
   1289                     minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) - startOffset);
   1290                 break;
   1291             }
   1292             }
   1293         }
   1294         minMarginAfterBaselines.append(minMarginAfterBaseline);
   1295     }
   1296 
   1297     if (style()->flexWrap() != FlexWrapReverse)
   1298         return;
   1299 
   1300     // wrap-reverse flips the cross axis start and end. For baseline alignment, this means we
   1301     // need to align the after edge of baseline elements with the after edge of the flex line.
   1302     child = m_orderIterator.first();
   1303     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
   1304         LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber];
   1305         for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
   1306             ASSERT(child);
   1307             if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child) && minMarginAfterBaseline)
   1308                 adjustAlignmentForChild(child, minMarginAfterBaseline);
   1309         }
   1310     }
   1311 }
   1312 
   1313 void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox* child, LayoutUnit lineCrossAxisExtent)
   1314 {
   1315     if (!isColumnFlow() && child->style()->logicalHeight().isAuto()) {
   1316         // FIXME: If the child has orthogonal flow, then it already has an override height set, so use it.
   1317         if (!hasOrthogonalFlow(child)) {
   1318             LayoutUnit stretchedLogicalHeight = child->logicalHeight() + availableAlignmentSpaceForChild(lineCrossAxisExtent, child);
   1319             ASSERT(!child->needsLayout());
   1320             LayoutUnit desiredLogicalHeight = child->constrainLogicalHeightByMinMax(stretchedLogicalHeight, child->logicalHeight() - child->borderAndPaddingLogicalHeight());
   1321 
   1322             // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
   1323             if (desiredLogicalHeight != child->logicalHeight()) {
   1324                 child->setOverrideLogicalContentHeight(desiredLogicalHeight - child->borderAndPaddingLogicalHeight());
   1325                 child->setLogicalHeight(0);
   1326                 child->forceChildLayout();
   1327             }
   1328         }
   1329     } else if (isColumnFlow() && child->style()->logicalWidth().isAuto()) {
   1330         // FIXME: If the child doesn't have orthogonal flow, then it already has an override width set, so use it.
   1331         if (hasOrthogonalFlow(child)) {
   1332             LayoutUnit childWidth = std::max<LayoutUnit>(0, lineCrossAxisExtent - crossAxisMarginExtentForChild(child));
   1333             childWidth = child->constrainLogicalWidthInRegionByMinMax(childWidth, childWidth, this);
   1334 
   1335             if (childWidth != child->logicalWidth()) {
   1336                 child->setOverrideLogicalContentWidth(childWidth - child->borderAndPaddingLogicalWidth());
   1337                 child->forceChildLayout();
   1338             }
   1339         }
   1340     }
   1341 }
   1342 
   1343 void RenderFlexibleBox::flipForRightToLeftColumn()
   1344 {
   1345     if (style()->isLeftToRightDirection() || !isColumnFlow())
   1346         return;
   1347 
   1348     LayoutUnit crossExtent = crossAxisExtent();
   1349     for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
   1350         if (child->isOutOfFlowPositioned())
   1351             continue;
   1352         LayoutPoint location = flowAwareLocationForChild(child);
   1353         // For vertical flows, setFlowAwareLocationForChild will transpose x and y,
   1354         // so using the y axis for a column cross axis extent is correct.
   1355         location.setY(crossExtent - crossAxisExtentForChild(child) - location.y());
   1356         setFlowAwareLocationForChild(child, location);
   1357     }
   1358 }
   1359 
   1360 void RenderFlexibleBox::flipForWrapReverse(const Vector<LineContext>& lineContexts, LayoutUnit crossAxisStartEdge)
   1361 {
   1362     LayoutUnit contentExtent = crossAxisContentExtent();
   1363     RenderBox* child = m_orderIterator.first();
   1364     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
   1365         for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
   1366             ASSERT(child);
   1367             LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
   1368             LayoutUnit originalOffset = lineContexts[lineNumber].crossAxisOffset - crossAxisStartEdge;
   1369             LayoutUnit newOffset = contentExtent - originalOffset - lineCrossAxisExtent;
   1370             adjustAlignmentForChild(child, newOffset - originalOffset);
   1371         }
   1372     }
   1373 }
   1374 
   1375 }
   1376