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