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