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