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