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