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