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