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