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