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