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