changing -webkit-order should change the paint order of flex items
[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 class RenderFlexibleBox::OrderIterator {
43 public:
44     OrderIterator(RenderFlexibleBox* flexibleBox, const OrderHashSet& orderValues)
45         : m_flexibleBox(flexibleBox)
46         , m_currentChild(0)
47         , m_orderValuesIterator(0)
48     {
49         copyToVector(orderValues, m_orderValues);
50         std::sort(m_orderValues.begin(), m_orderValues.end());
51         first();
52     }
53
54     RenderBox* currentChild() { return m_currentChild; }
55
56     RenderBox* first()
57     {
58         reset();
59         return next();
60     }
61
62     RenderBox* next()
63     {
64         do {
65             if (!m_currentChild) {
66                 if (m_orderValuesIterator == m_orderValues.end())
67                     return 0;
68                 if (m_orderValuesIterator) {
69                     ++m_orderValuesIterator;
70                     if (m_orderValuesIterator == m_orderValues.end())
71                         return 0;
72                 } else
73                     m_orderValuesIterator = m_orderValues.begin();
74
75                 m_currentChild = m_flexibleBox->firstChildBox();
76             } else
77                 m_currentChild = m_currentChild->nextSiblingBox();
78         } while (!m_currentChild || m_currentChild->style()->order() != *m_orderValuesIterator);
79
80         return m_currentChild;
81     }
82
83     void reset()
84     {
85         m_currentChild = 0;
86         m_orderValuesIterator = 0;
87     }
88
89 private:
90     RenderFlexibleBox* m_flexibleBox;
91     RenderBox* m_currentChild;
92     Vector<float> m_orderValues;
93     Vector<float>::const_iterator m_orderValuesIterator;
94 };
95
96 struct RenderFlexibleBox::LineContext {
97     LineContext(LayoutUnit crossAxisOffset, LayoutUnit crossAxisExtent, size_t numberOfChildren, LayoutUnit maxAscent)
98         : crossAxisOffset(crossAxisOffset)
99         , crossAxisExtent(crossAxisExtent)
100         , numberOfChildren(numberOfChildren)
101         , maxAscent(maxAscent)
102     {
103     }
104
105     LayoutUnit crossAxisOffset;
106     LayoutUnit crossAxisExtent;
107     size_t numberOfChildren;
108     LayoutUnit maxAscent;
109 };
110
111 struct RenderFlexibleBox::Violation {
112     Violation(RenderBox* child, LayoutUnit childSize)
113         : child(child)
114         , childSize(childSize)
115     {
116     }
117
118     RenderBox* child;
119     LayoutUnit childSize;
120 };
121
122
123 RenderFlexibleBox::RenderFlexibleBox(Node* node)
124     : RenderBlock(node)
125 {
126     setChildrenInline(false); // All of our children must be block-level.
127 }
128
129 RenderFlexibleBox::~RenderFlexibleBox()
130 {
131 }
132
133 const char* RenderFlexibleBox::renderName() const
134 {
135     return "RenderFlexibleBox";
136 }
137
138 static LayoutUnit marginLogicalWidthForChild(RenderBox* child, RenderStyle* parentStyle)
139 {
140     // A margin has three types: fixed, percentage, and auto (variable).
141     // Auto and percentage margins become 0 when computing min/max width.
142     // Fixed margins can be added in as is.
143     Length marginLeft = child->style()->marginStartUsing(parentStyle);
144     Length marginRight = child->style()->marginEndUsing(parentStyle);
145     LayoutUnit margin = 0;
146     if (marginLeft.isFixed())
147         margin += marginLeft.value();
148     if (marginRight.isFixed())
149         margin += marginRight.value();
150     return margin;
151 }
152
153 void RenderFlexibleBox::computePreferredLogicalWidths()
154 {
155     ASSERT(preferredLogicalWidthsDirty());
156
157     RenderStyle* styleToUse = style();
158     // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for width.
159     if (styleToUse->logicalWidth().isFixed() && styleToUse->logicalWidth().value() > 0)
160         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeContentBoxLogicalWidth(styleToUse->logicalWidth().value());
161     else {
162         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
163
164         for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
165             if (child->isOutOfFlowPositioned())
166                 continue;
167
168             LayoutUnit margin = marginLogicalWidthForChild(child, style());
169             bool hasOrthogonalWritingMode = child->isHorizontalWritingMode() != isHorizontalWritingMode();
170             LayoutUnit minPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->minPreferredLogicalWidth();
171             LayoutUnit maxPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->maxPreferredLogicalWidth();
172             minPreferredLogicalWidth += margin;
173             maxPreferredLogicalWidth += margin;
174             if (!isColumnFlow()) {
175                 m_maxPreferredLogicalWidth += maxPreferredLogicalWidth;
176                 if (isMultiline()) {
177                     // For multiline, the min preferred width is if you put a break between each item.
178                     m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, minPreferredLogicalWidth);
179                 } else
180                     m_minPreferredLogicalWidth += minPreferredLogicalWidth;
181             } else {
182                 m_minPreferredLogicalWidth = std::max(minPreferredLogicalWidth, m_minPreferredLogicalWidth);
183                 if (isMultiline()) {
184                     // For multiline, the max preferred width is if you put a break between each item.
185                     m_maxPreferredLogicalWidth += maxPreferredLogicalWidth;
186                 } else
187                     m_maxPreferredLogicalWidth = std::max(maxPreferredLogicalWidth, m_maxPreferredLogicalWidth);
188             }
189         }
190
191         m_maxPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
192     }
193
194     LayoutUnit scrollbarWidth = 0;
195     if (hasOverflowClip()) {
196         if (isHorizontalWritingMode() && styleToUse->overflowY() == OSCROLL) {
197             layer()->setHasVerticalScrollbar(true);
198             scrollbarWidth = verticalScrollbarWidth();
199         } else if (!isHorizontalWritingMode() && styleToUse->overflowX() == OSCROLL) {
200             layer()->setHasHorizontalScrollbar(true);
201             scrollbarWidth = horizontalScrollbarHeight();
202         }
203     }
204
205     m_maxPreferredLogicalWidth += scrollbarWidth;
206     m_minPreferredLogicalWidth += scrollbarWidth;
207
208     // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for min-width.
209     if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
210         m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(styleToUse->logicalMinWidth().value()));
211         m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(styleToUse->logicalMinWidth().value()));
212     }
213
214     // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for maxWidth.
215     if (styleToUse->logicalMaxWidth().isFixed()) {
216         m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(styleToUse->logicalMaxWidth().value()));
217         m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(styleToUse->logicalMaxWidth().value()));
218     }
219
220     LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
221     m_minPreferredLogicalWidth += borderAndPadding;
222     m_maxPreferredLogicalWidth += borderAndPadding;
223
224     setPreferredLogicalWidthsDirty(false);
225 }
226
227 void RenderFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
228 {
229     ASSERT(needsLayout());
230
231     if (!relayoutChildren && simplifiedLayout())
232         return;
233
234     LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
235     LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
236
237     if (inRenderFlowThread()) {
238         // Regions changing widths can force us to relayout our children.
239         if (logicalWidthChangedInRegions())
240             relayoutChildren = true;
241     }
242     computeInitialRegionRangeForBlock();
243
244     LayoutSize previousSize = size();
245
246     setLogicalHeight(0);
247     computeLogicalWidth();
248
249     m_overflow.clear();
250
251     // For overflow:scroll blocks, ensure we have both scrollbars in place always.
252     if (scrollsOverflow()) {
253         if (style()->overflowX() == OSCROLL)
254             layer()->setHasHorizontalScrollbar(true);
255         if (style()->overflowY() == OSCROLL)
256             layer()->setHasVerticalScrollbar(true);
257     }
258
259     WTF::Vector<LineContext> lineContexts;
260     OrderHashSet orderValues;
261     computeMainAxisPreferredSizes(relayoutChildren, orderValues);
262     m_orderIterator = adoptPtr(new OrderIterator(this, orderValues));
263     layoutFlexItems(*m_orderIterator, lineContexts);
264
265     LayoutUnit oldClientAfterEdge = clientLogicalBottom();
266     computeLogicalHeight();
267     repositionLogicalHeightDependentFlexItems(*m_orderIterator, lineContexts, oldClientAfterEdge);
268
269     if (size() != previousSize)
270         relayoutChildren = true;
271
272     layoutPositionedObjects(relayoutChildren || isRoot());
273
274     computeRegionRangeForBlock();
275
276     // FIXME: css3/flexbox/repaint-rtl-column.html seems to repaint more overflow than it needs to.
277     computeOverflow(oldClientAfterEdge);
278     statePusher.pop();
279
280     updateLayerTransform();
281
282     // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
283     // we overflow or not.
284     if (hasOverflowClip())
285         layer()->updateScrollInfoAfterLayout();
286
287     repainter.repaintAfterLayout();
288
289     setNeedsLayout(false);
290 }
291
292 void RenderFlexibleBox::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset, PaintInfo& paintInfoForChild, bool usePrintRect)
293 {
294     ASSERT(m_orderIterator);
295
296     for (RenderBox* child = m_orderIterator->first(); child; child = m_orderIterator->next()) {
297         if (!paintChild(child, paintInfo, paintOffset, paintInfoForChild, usePrintRect))
298             return;
299     }
300 }
301
302 void RenderFlexibleBox::repositionLogicalHeightDependentFlexItems(OrderIterator& iterator, WTF::Vector<LineContext>& lineContexts, LayoutUnit& oldClientAfterEdge)
303 {
304     LayoutUnit crossAxisStartEdge = lineContexts.isEmpty() ? ZERO_LAYOUT_UNIT : lineContexts[0].crossAxisOffset;
305     alignFlexLines(iterator, lineContexts);
306
307     // If we have a single line flexbox, the line height is all the available space.
308     // For flex-direction: row, this means we need to use the height, so we do this after calling computeLogicalHeight.
309     if (!isMultiline() && lineContexts.size() == 1)
310         lineContexts[0].crossAxisExtent = crossAxisContentExtent();
311     alignChildren(iterator, lineContexts);
312
313     if (style()->flexWrap() == FlexWrapReverse) {
314         if (isHorizontalFlow())
315             oldClientAfterEdge = clientLogicalBottom();
316         flipForWrapReverse(iterator, lineContexts, crossAxisStartEdge);
317     }
318
319     // direction:rtl + flex-direction:column means the cross-axis direction is flipped.
320     flipForRightToLeftColumn(iterator);
321 }
322
323 bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox* child) const
324 {
325     // FIXME: If the child is a flexbox, then we need to check isHorizontalFlow.
326     return isHorizontalFlow() != child->isHorizontalWritingMode();
327 }
328
329 bool RenderFlexibleBox::isColumnFlow() const
330 {
331     return style()->isColumnFlexDirection();
332 }
333
334 bool RenderFlexibleBox::isHorizontalFlow() const
335 {
336     if (isHorizontalWritingMode())
337         return !isColumnFlow();
338     return isColumnFlow();
339 }
340
341 bool RenderFlexibleBox::isLeftToRightFlow() const
342 {
343     if (isColumnFlow())
344         return style()->writingMode() == TopToBottomWritingMode || style()->writingMode() == LeftToRightWritingMode;
345     return style()->isLeftToRightDirection() ^ (style()->flexDirection() == FlowRowReverse);
346 }
347
348 bool RenderFlexibleBox::isMultiline() const
349 {
350     return style()->flexWrap() != FlexWrapNone;
351 }
352
353 Length RenderFlexibleBox::flexBasisForChild(RenderBox* child) const
354 {
355     Length flexLength = child->style()->flexBasis();
356     if (flexLength.isAuto())
357         flexLength = isHorizontalFlow() ? child->style()->width() : child->style()->height();
358     return flexLength;
359 }
360
361 Length RenderFlexibleBox::crossAxisLength() const
362 {
363     return isHorizontalFlow() ? style()->height() : style()->width();
364 }
365
366 void RenderFlexibleBox::setCrossAxisExtent(LayoutUnit extent)
367 {
368     if (isHorizontalFlow())
369         setHeight(extent);
370     else
371         setWidth(extent);
372 }
373
374 LayoutUnit RenderFlexibleBox::crossAxisExtentForChild(RenderBox* child)
375 {
376     return isHorizontalFlow() ? child->height() : child->width();
377 }
378
379 LayoutUnit RenderFlexibleBox::mainAxisExtentForChild(RenderBox* child)
380 {
381     return isHorizontalFlow() ? child->width() : child->height();
382 }
383
384 LayoutUnit RenderFlexibleBox::crossAxisExtent() const
385 {
386     return isHorizontalFlow() ? height() : width();
387 }
388
389 LayoutUnit RenderFlexibleBox::mainAxisExtent() const
390 {
391     return isHorizontalFlow() ? width() : height();
392 }
393
394 LayoutUnit RenderFlexibleBox::crossAxisContentExtent() const
395 {
396     return isHorizontalFlow() ? contentHeight() : contentWidth();
397 }
398
399 LayoutUnit RenderFlexibleBox::mainAxisContentExtent() const
400 {
401     return isHorizontalFlow() ? contentWidth() : contentHeight();
402 }
403
404 WritingMode RenderFlexibleBox::transformedWritingMode() const
405 {
406     WritingMode mode = style()->writingMode();
407     if (!isColumnFlow())
408         return mode;
409
410     switch (mode) {
411     case TopToBottomWritingMode:
412     case BottomToTopWritingMode:
413         return style()->isLeftToRightDirection() ? LeftToRightWritingMode : RightToLeftWritingMode;
414     case LeftToRightWritingMode:
415     case RightToLeftWritingMode:
416         return style()->isLeftToRightDirection() ? TopToBottomWritingMode : BottomToTopWritingMode;
417     }
418     ASSERT_NOT_REACHED();
419     return TopToBottomWritingMode;
420 }
421
422 LayoutUnit RenderFlexibleBox::flowAwareBorderStart() const
423 {
424     if (isHorizontalFlow())
425         return isLeftToRightFlow() ? borderLeft() : borderRight();
426     return isLeftToRightFlow() ? borderTop() : borderBottom();
427 }
428
429 LayoutUnit RenderFlexibleBox::flowAwareBorderEnd() const
430 {
431     if (isHorizontalFlow())
432         return isLeftToRightFlow() ? borderRight() : borderLeft();
433     return isLeftToRightFlow() ? borderBottom() : borderTop();
434 }
435
436 LayoutUnit RenderFlexibleBox::flowAwareBorderBefore() const
437 {
438     switch (transformedWritingMode()) {
439     case TopToBottomWritingMode:
440         return borderTop();
441     case BottomToTopWritingMode:
442         return borderBottom();
443     case LeftToRightWritingMode:
444         return borderLeft();
445     case RightToLeftWritingMode:
446         return borderRight();
447     }
448     ASSERT_NOT_REACHED();
449     return borderTop();
450 }
451
452 LayoutUnit RenderFlexibleBox::flowAwareBorderAfter() const
453 {
454     switch (transformedWritingMode()) {
455     case TopToBottomWritingMode:
456         return borderBottom();
457     case BottomToTopWritingMode:
458         return borderTop();
459     case LeftToRightWritingMode:
460         return borderRight();
461     case RightToLeftWritingMode:
462         return borderLeft();
463     }
464     ASSERT_NOT_REACHED();
465     return borderTop();
466 }
467
468 LayoutUnit RenderFlexibleBox::flowAwarePaddingStart() const
469 {
470     if (isHorizontalFlow())
471         return isLeftToRightFlow() ? paddingLeft() : paddingRight();
472     return isLeftToRightFlow() ? paddingTop() : paddingBottom();
473 }
474
475 LayoutUnit RenderFlexibleBox::flowAwarePaddingEnd() const
476 {
477     if (isHorizontalFlow())
478         return isLeftToRightFlow() ? paddingRight() : paddingLeft();
479     return isLeftToRightFlow() ? paddingBottom() : paddingTop();
480 }
481
482 LayoutUnit RenderFlexibleBox::flowAwarePaddingBefore() const
483 {
484     switch (transformedWritingMode()) {
485     case TopToBottomWritingMode:
486         return paddingTop();
487     case BottomToTopWritingMode:
488         return paddingBottom();
489     case LeftToRightWritingMode:
490         return paddingLeft();
491     case RightToLeftWritingMode:
492         return paddingRight();
493     }
494     ASSERT_NOT_REACHED();
495     return paddingTop();
496 }
497
498 LayoutUnit RenderFlexibleBox::flowAwarePaddingAfter() const
499 {
500     switch (transformedWritingMode()) {
501     case TopToBottomWritingMode:
502         return paddingBottom();
503     case BottomToTopWritingMode:
504         return paddingTop();
505     case LeftToRightWritingMode:
506         return paddingRight();
507     case RightToLeftWritingMode:
508         return paddingLeft();
509     }
510     ASSERT_NOT_REACHED();
511     return paddingTop();
512 }
513
514 LayoutUnit RenderFlexibleBox::flowAwareMarginStartForChild(RenderBox* child) const
515 {
516     if (isHorizontalFlow())
517         return isLeftToRightFlow() ? child->marginLeft() : child->marginRight();
518     return isLeftToRightFlow() ? child->marginTop() : child->marginBottom();
519 }
520
521 LayoutUnit RenderFlexibleBox::flowAwareMarginEndForChild(RenderBox* child) const
522 {
523     if (isHorizontalFlow())
524         return isLeftToRightFlow() ? child->marginRight() : child->marginLeft();
525     return isLeftToRightFlow() ? child->marginBottom() : child->marginTop();
526 }
527
528 LayoutUnit RenderFlexibleBox::flowAwareMarginBeforeForChild(RenderBox* child) const
529 {
530     switch (transformedWritingMode()) {
531     case TopToBottomWritingMode:
532         return child->marginTop();
533     case BottomToTopWritingMode:
534         return child->marginBottom();
535     case LeftToRightWritingMode:
536         return child->marginLeft();
537     case RightToLeftWritingMode:
538         return child->marginRight();
539     }
540     ASSERT_NOT_REACHED();
541     return marginTop();
542 }
543
544 LayoutUnit RenderFlexibleBox::flowAwareMarginAfterForChild(RenderBox* child) const
545 {
546     switch (transformedWritingMode()) {
547     case TopToBottomWritingMode:
548         return child->marginBottom();
549     case BottomToTopWritingMode:
550         return child->marginTop();
551     case LeftToRightWritingMode:
552         return child->marginRight();
553     case RightToLeftWritingMode:
554         return child->marginLeft();
555     }
556     ASSERT_NOT_REACHED();
557     return marginBottom();
558 }
559
560 LayoutUnit RenderFlexibleBox::crossAxisMarginExtentForChild(RenderBox* child) const
561 {
562     return isHorizontalFlow() ? child->marginHeight() : child->marginWidth();
563 }
564
565 LayoutUnit RenderFlexibleBox::crossAxisScrollbarExtent() const
566 {
567     return isHorizontalFlow() ? horizontalScrollbarHeight() : verticalScrollbarWidth();
568 }
569
570 LayoutPoint RenderFlexibleBox::flowAwareLocationForChild(RenderBox* child) const
571 {
572     return isHorizontalFlow() ? child->location() : child->location().transposedPoint();
573 }
574
575 void RenderFlexibleBox::setFlowAwareLocationForChild(RenderBox* child, const LayoutPoint& location)
576 {
577     if (isHorizontalFlow())
578         child->setLocation(location);
579     else
580         child->setLocation(location.transposedPoint());
581 }
582
583 LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox* child) const
584 {
585     return isHorizontalFlow() ? child->borderAndPaddingWidth() : child->borderAndPaddingHeight();
586 }
587
588 LayoutUnit RenderFlexibleBox::mainAxisScrollbarExtentForChild(RenderBox* child) const
589 {
590     return isHorizontalFlow() ? child->verticalScrollbarWidth() : child->horizontalScrollbarHeight();
591 }
592
593 LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* child) const
594 {
595     Length flexBasis = flexBasisForChild(child);
596     if (flexBasis.isAuto()) {
597         LayoutUnit mainAxisExtent = hasOrthogonalFlow(child) ? child->logicalHeight() : child->maxPreferredLogicalWidth();
598         return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child);
599     }
600     return std::max(LayoutUnit(0), minimumValueForLength(flexBasis, mainAxisContentExtent(), view()));
601 }
602
603 LayoutUnit RenderFlexibleBox::computeAvailableFreeSpace(LayoutUnit preferredMainAxisExtent)
604 {
605     LayoutUnit contentExtent = 0;
606     if (!isColumnFlow())
607         contentExtent = mainAxisContentExtent();
608     else if (hasOverrideHeight())
609         contentExtent = overrideLogicalContentHeight();
610     else {
611         LayoutUnit heightResult = computeContentLogicalHeightUsing(MainOrPreferredSize, style()->logicalHeight());
612         if (heightResult == -1)
613             heightResult = preferredMainAxisExtent;
614         LayoutUnit minHeight = computeContentLogicalHeightUsing(MinSize, style()->logicalMinHeight()); // Leave as -1 if unset.
615         LayoutUnit maxHeight = style()->logicalMaxHeight().isUndefined() ? heightResult : computeContentLogicalHeightUsing(MaxSize, style()->logicalMaxHeight());
616         if (maxHeight == -1)
617             maxHeight = heightResult;
618         heightResult = std::min(maxHeight, heightResult);
619         heightResult = std::max(minHeight, heightResult);
620         contentExtent = heightResult;
621     }
622
623     return contentExtent - preferredMainAxisExtent;
624 }
625
626 void RenderFlexibleBox::layoutFlexItems(OrderIterator& iterator, WTF::Vector<LineContext>& lineContexts)
627 {
628     OrderedFlexItemList orderedChildren;
629     LayoutUnit preferredMainAxisExtent;
630     float totalFlexGrow;
631     float totalWeightedFlexShrink;
632     LayoutUnit minMaxAppliedMainAxisExtent;
633
634     LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
635     while (computeNextFlexLine(iterator, orderedChildren, preferredMainAxisExtent, totalFlexGrow, totalWeightedFlexShrink, minMaxAppliedMainAxisExtent)) {
636         LayoutUnit availableFreeSpace = computeAvailableFreeSpace(preferredMainAxisExtent);
637         FlexSign flexSign = (minMaxAppliedMainAxisExtent < preferredMainAxisExtent + availableFreeSpace) ? PositiveFlexibility : NegativeFlexibility;
638         InflexibleFlexItemSize inflexibleItems;
639         WTF::Vector<LayoutUnit> childSizes;
640         while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, childSizes)) {
641             ASSERT(totalFlexGrow >= 0 && totalWeightedFlexShrink >= 0);
642             ASSERT(inflexibleItems.size() > 0);
643         }
644
645         layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace, lineContexts);
646     }
647 }
648
649 LayoutUnit RenderFlexibleBox::autoMarginOffsetInMainAxis(const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace)
650 {
651     if (availableFreeSpace <= 0)
652         return 0;
653
654     int numberOfAutoMargins = 0;
655     bool isHorizontal = isHorizontalFlow();
656     for (size_t i = 0; i < children.size(); ++i) {
657         RenderBox* child = children[i];
658         if (child->isOutOfFlowPositioned())
659             continue;
660         if (isHorizontal) {
661             if (child->style()->marginLeft().isAuto())
662                 ++numberOfAutoMargins;
663             if (child->style()->marginRight().isAuto())
664                 ++numberOfAutoMargins;
665         } else {
666             if (child->style()->marginTop().isAuto())
667                 ++numberOfAutoMargins;
668             if (child->style()->marginBottom().isAuto())
669                 ++numberOfAutoMargins;
670         }
671     }
672     if (!numberOfAutoMargins)
673         return 0;
674
675     LayoutUnit sizeOfAutoMargin = availableFreeSpace / numberOfAutoMargins;
676     availableFreeSpace = 0;
677     return sizeOfAutoMargin;
678 }
679
680 void RenderFlexibleBox::updateAutoMarginsInMainAxis(RenderBox* child, LayoutUnit autoMarginOffset)
681 {
682     if (isHorizontalFlow()) {
683         if (child->style()->marginLeft().isAuto())
684             child->setMarginLeft(autoMarginOffset);
685         if (child->style()->marginRight().isAuto())
686             child->setMarginRight(autoMarginOffset);
687     } else {
688         if (child->style()->marginTop().isAuto())
689             child->setMarginTop(autoMarginOffset);
690         if (child->style()->marginBottom().isAuto())
691             child->setMarginBottom(autoMarginOffset);
692     }
693 }
694
695 bool RenderFlexibleBox::hasAutoMarginsInCrossAxis(RenderBox* child)
696 {
697     if (isHorizontalFlow())
698         return child->style()->marginTop().isAuto() || child->style()->marginBottom().isAuto();
699     return child->style()->marginLeft().isAuto() || child->style()->marginRight().isAuto();
700 }
701
702 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox* child)
703 {
704     LayoutUnit childCrossExtent = 0;
705     if (!child->isOutOfFlowPositioned())
706         childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child);
707     return lineCrossAxisExtent - childCrossExtent;
708 }
709
710 bool RenderFlexibleBox::updateAutoMarginsInCrossAxis(RenderBox* child, LayoutUnit availableAlignmentSpace)
711 {
712     bool isHorizontal = isHorizontalFlow();
713     Length start = isHorizontal ? child->style()->marginTop() : child->style()->marginLeft();
714     Length end = isHorizontal ? child->style()->marginBottom() : child->style()->marginRight();
715     if (start.isAuto() && end.isAuto()) {
716         adjustAlignmentForChild(child, availableAlignmentSpace / 2);
717         if (isHorizontal) {
718             child->setMarginTop(availableAlignmentSpace / 2);
719             child->setMarginBottom(availableAlignmentSpace / 2);
720         } else {
721             child->setMarginLeft(availableAlignmentSpace / 2);
722             child->setMarginRight(availableAlignmentSpace / 2);
723         }
724         return true;
725     }
726     if (start.isAuto()) {
727         adjustAlignmentForChild(child, availableAlignmentSpace);
728         if (isHorizontal)
729             child->setMarginTop(availableAlignmentSpace);
730         else
731             child->setMarginLeft(availableAlignmentSpace);
732         return true;
733     }
734     if (end.isAuto()) {
735         if (isHorizontal)
736             child->setMarginBottom(availableAlignmentSpace);
737         else
738             child->setMarginRight(availableAlignmentSpace);
739         return true;
740     }
741     return false;
742 }
743
744 LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(RenderBox* child)
745 {
746     LayoutUnit ascent = child->firstLineBoxBaseline();
747     if (ascent == -1)
748         ascent = crossAxisExtentForChild(child) + flowAwareMarginAfterForChild(child);
749     return ascent + flowAwareMarginBeforeForChild(child);
750 }
751
752 void RenderFlexibleBox::computeMainAxisPreferredSizes(bool relayoutChildren, OrderHashSet& orderValues)
753 {
754     LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent();
755     RenderView* renderView = view();
756     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
757         orderValues.add(child->style()->order());
758
759         if (child->isOutOfFlowPositioned())
760             continue;
761
762         child->clearOverrideSize();
763         // Only need to layout here if we will need to get the logicalHeight of the child in computeNextFlexLine.
764         Length childMainAxisMin = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
765         if (hasOrthogonalFlow(child) && (flexBasisForChild(child).isAuto() || childMainAxisMin.isAuto())) {
766             if (!relayoutChildren)
767                 child->setChildNeedsLayout(true);
768             child->layoutIfNeeded();
769         }
770
771         // Before running the flex algorithm, 'auto' has a margin of 0.
772         // Also, if we're not auto sizing, we don't do a layout that computes the start/end margins.
773         if (isHorizontalFlow()) {
774             child->setMarginLeft(minimumValueForLength(child->style()->marginLeft(), flexboxAvailableContentExtent, renderView));
775             child->setMarginRight(minimumValueForLength(child->style()->marginRight(), flexboxAvailableContentExtent, renderView));
776         } else {
777             child->setMarginTop(minimumValueForLength(child->style()->marginTop(), flexboxAvailableContentExtent, renderView));
778             child->setMarginBottom(minimumValueForLength(child->style()->marginBottom(), flexboxAvailableContentExtent, renderView));
779         }
780     }
781 }
782
783 LayoutUnit RenderFlexibleBox::lineBreakLength()
784 {
785     if (!isColumnFlow())
786         return mainAxisContentExtent();
787
788     LayoutUnit height = computeContentLogicalHeightUsing(MainOrPreferredSize, style()->logicalHeight());
789     if (height == -1)
790         height = MAX_LAYOUT_UNIT;
791     LayoutUnit maxHeight = computeContentLogicalHeightUsing(MaxSize, style()->logicalMaxHeight());
792     if (maxHeight != -1)
793         height = std::min(height, maxHeight);
794     return height;
795 }
796
797 LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox* child, LayoutUnit childSize, LayoutUnit flexboxAvailableContentExtent)
798 {
799     Length max = isHorizontalFlow() ? child->style()->maxWidth() : child->style()->maxHeight();
800     Length min = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
801     RenderView* renderView = view();
802     // FIXME: valueForLength isn't quite right in quirks mode: percentage heights should check parents until a value is found.
803     // https://bugs.webkit.org/show_bug.cgi?id=81809
804     if (max.isSpecified() && childSize > valueForLength(max, flexboxAvailableContentExtent, renderView))
805         childSize = valueForLength(max, flexboxAvailableContentExtent, renderView);
806
807     if (min.isSpecified() && childSize < valueForLength(min, flexboxAvailableContentExtent, renderView))
808         return valueForLength(min, flexboxAvailableContentExtent, renderView);
809
810     // FIXME: Support min/max sizes of fit-content, max-content and fill-available.
811     if (min.isAuto()) {
812         LayoutUnit minContent = hasOrthogonalFlow(child) ? child->logicalHeight() : child->minPreferredLogicalWidth();
813         minContent -= mainAxisBorderAndPaddingExtentForChild(child);
814         return std::max(childSize, minContent);
815     }
816
817     return childSize;
818 }
819
820 bool RenderFlexibleBox::computeNextFlexLine(OrderIterator& iterator, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalFlexGrow, float& totalWeightedFlexShrink, LayoutUnit& minMaxAppliedMainAxisExtent)
821 {
822     orderedChildren.clear();
823     preferredMainAxisExtent = 0;
824     totalFlexGrow = totalWeightedFlexShrink = 0;
825     minMaxAppliedMainAxisExtent = 0;
826
827     if (!iterator.currentChild())
828         return false;
829
830     LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent();
831     LayoutUnit lineBreak = lineBreakLength();
832
833     for (RenderBox* child = iterator.currentChild(); child; child = iterator.next()) {
834         if (child->isOutOfFlowPositioned()) {
835             orderedChildren.append(child);
836             continue;
837         }
838
839         LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(child);
840         LayoutUnit childMainAxisMarginBoxExtent = mainAxisBorderAndPaddingExtentForChild(child) + childMainAxisExtent;
841         childMainAxisMarginBoxExtent += isHorizontalFlow() ? child->marginWidth() : child->marginHeight();
842
843         if (isMultiline() && preferredMainAxisExtent + childMainAxisMarginBoxExtent > lineBreak && orderedChildren.size() > 0)
844             break;
845         orderedChildren.append(child);
846         preferredMainAxisExtent += childMainAxisMarginBoxExtent;
847         totalFlexGrow += child->style()->flexGrow();
848         totalWeightedFlexShrink += child->style()->flexShrink() * childMainAxisExtent;
849
850         LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(child, childMainAxisExtent, flexboxAvailableContentExtent);
851         minMaxAppliedMainAxisExtent += childMinMaxAppliedMainAxisExtent - childMainAxisExtent + childMainAxisMarginBoxExtent;
852     }
853     return true;
854 }
855
856 void RenderFlexibleBox::freezeViolations(const WTF::Vector<Violation>& violations, LayoutUnit& availableFreeSpace, float& totalFlexGrow, float& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems)
857 {
858     for (size_t i = 0; i < violations.size(); ++i) {
859         RenderBox* child = violations[i].child;
860         LayoutUnit childSize = violations[i].childSize;
861         LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child);
862         availableFreeSpace -= childSize - preferredChildSize;
863         totalFlexGrow -= child->style()->flexGrow();
864         totalWeightedFlexShrink -= child->style()->flexShrink() * preferredChildSize;
865         inflexibleItems.set(child, childSize);
866     }
867 }
868
869 // Returns true if we successfully ran the algorithm and sized the flex items.
870 bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, float& totalFlexGrow, float& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, WTF::Vector<LayoutUnit>& childSizes)
871 {
872     childSizes.clear();
873     LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent();
874     LayoutUnit totalViolation = 0;
875     LayoutUnit usedFreeSpace = 0;
876     WTF::Vector<Violation> minViolations;
877     WTF::Vector<Violation> maxViolations;
878     for (size_t i = 0; i < children.size(); ++i) {
879         RenderBox* child = children[i];
880         if (child->isOutOfFlowPositioned()) {
881             childSizes.append(0);
882             continue;
883         }
884
885         if (inflexibleItems.contains(child))
886             childSizes.append(inflexibleItems.get(child));
887         else {
888             LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child);
889             LayoutUnit childSize = preferredChildSize;
890             if (availableFreeSpace > 0 && totalFlexGrow > 0 && flexSign == PositiveFlexibility && isfinite(totalFlexGrow))
891                 childSize += roundedLayoutUnit(availableFreeSpace * child->style()->flexGrow() / totalFlexGrow);
892             else if (availableFreeSpace < 0 && totalWeightedFlexShrink > 0 && flexSign == NegativeFlexibility && isfinite(totalWeightedFlexShrink))
893                 childSize += roundedLayoutUnit(availableFreeSpace * child->style()->flexShrink() * preferredChildSize / totalWeightedFlexShrink);
894
895             LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(child, childSize, flexboxAvailableContentExtent);
896             childSizes.append(adjustedChildSize);
897             usedFreeSpace += adjustedChildSize - preferredChildSize;
898
899             LayoutUnit violation = adjustedChildSize - childSize;
900             if (violation > 0)
901                 minViolations.append(Violation(child, adjustedChildSize));
902             else if (violation < 0)
903                 maxViolations.append(Violation(child, adjustedChildSize));
904             totalViolation += violation;
905         }
906     }
907
908     if (totalViolation)
909         freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems);
910     else
911         availableFreeSpace -= usedFreeSpace;
912
913     return !totalViolation;
914 }
915
916 static LayoutUnit initialJustifyContentOffset(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
917 {
918     if (justifyContent == JustifyFlexEnd)
919         return availableFreeSpace;
920     if (justifyContent == JustifyCenter)
921         return availableFreeSpace / 2;
922     if (justifyContent == JustifySpaceAround) {
923         if (availableFreeSpace > 0 && numberOfChildren)
924             return availableFreeSpace / (2 * numberOfChildren);
925         if (availableFreeSpace < 0)
926             return availableFreeSpace / 2;
927     }
928     return 0;
929 }
930
931 static LayoutUnit justifyContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
932 {
933     if (availableFreeSpace > 0 && numberOfChildren > 1) {
934         if (justifyContent == JustifySpaceBetween)
935             return availableFreeSpace / (numberOfChildren - 1);
936         if (justifyContent == JustifySpaceAround)
937             return availableFreeSpace / numberOfChildren;
938     }
939     return 0;
940 }
941
942 void RenderFlexibleBox::setLogicalOverrideSize(RenderBox* child, LayoutUnit childPreferredSize)
943 {
944     if (hasOrthogonalFlow(child))
945         child->setOverrideLogicalContentHeight(childPreferredSize - child->borderAndPaddingLogicalHeight());
946     else
947         child->setOverrideLogicalContentWidth(childPreferredSize - child->borderAndPaddingLogicalWidth());
948 }
949
950 void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox* child, LayoutUnit mainAxisOffset, LayoutUnit crossAxisOffset, PositionedLayoutMode layoutMode)
951 {
952     ASSERT(child->isOutOfFlowPositioned());
953     child->containingBlock()->insertPositionedObject(child);
954     RenderLayer* childLayer = child->layer();
955     LayoutUnit inlinePosition = isColumnFlow() ? crossAxisOffset : mainAxisOffset;
956     if (layoutMode == FlipForRowReverse && style()->flexDirection() == FlowRowReverse)
957         inlinePosition = mainAxisExtent() - mainAxisOffset;
958     childLayer->setStaticInlinePosition(inlinePosition); // FIXME: Not right for regions.
959
960     LayoutUnit staticBlockPosition = isColumnFlow() ? mainAxisOffset : crossAxisOffset;
961     if (childLayer->staticBlockPosition() != staticBlockPosition) {
962         childLayer->setStaticBlockPosition(staticBlockPosition);
963         if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
964             child->setChildNeedsLayout(true, MarkOnlyThis);
965     }
966 }
967
968 static EAlignItems alignmentForChild(RenderBox* child)
969 {
970     EAlignItems align = child->style()->alignSelf();
971     if (align == AlignAuto)
972         align = child->parent()->style()->alignItems();
973
974     if (child->parent()->style()->flexWrap() == FlexWrapReverse) {
975         if (align == AlignFlexStart)
976             align = AlignFlexEnd;
977         else if (align == AlignFlexEnd)
978             align = AlignFlexStart;
979     }
980
981     return align;
982 }
983
984 void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace, WTF::Vector<LineContext>& lineContexts)
985 {
986     ASSERT(childSizes.size() == children.size());
987
988     LayoutUnit autoMarginOffset = autoMarginOffsetInMainAxis(children, availableFreeSpace);
989     LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart();
990     mainAxisOffset += initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), childSizes.size());
991     if (style()->flexDirection() == FlowRowReverse)
992         mainAxisOffset += isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
993
994     LayoutUnit totalMainExtent = mainAxisExtent();
995     LayoutUnit maxAscent = 0, maxDescent = 0; // Used when align-items: baseline.
996     LayoutUnit maxChildCrossAxisExtent = 0;
997     bool shouldFlipMainAxis = !isColumnFlow() && !isLeftToRightFlow();
998     for (size_t i = 0; i < children.size(); ++i) {
999         RenderBox* child = children[i];
1000         if (child->isOutOfFlowPositioned()) {
1001             prepareChildForPositionedLayout(child, mainAxisOffset, crossAxisOffset, FlipForRowReverse);
1002             mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), childSizes.size());
1003             continue;
1004         }
1005         LayoutUnit childPreferredSize = childSizes[i] + mainAxisBorderAndPaddingExtentForChild(child);
1006         setLogicalOverrideSize(child, childPreferredSize);
1007         // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
1008         child->setChildNeedsLayout(true);
1009         child->layoutIfNeeded();
1010
1011         updateAutoMarginsInMainAxis(child, autoMarginOffset);
1012
1013         LayoutUnit childCrossAxisMarginBoxExtent;
1014         if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child)) {
1015             LayoutUnit ascent = marginBoxAscentForChild(child);
1016             LayoutUnit descent = (crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child)) - ascent;
1017
1018             maxAscent = std::max(maxAscent, ascent);
1019             maxDescent = std::max(maxDescent, descent);
1020
1021             childCrossAxisMarginBoxExtent = maxAscent + maxDescent;
1022         } else
1023             childCrossAxisMarginBoxExtent = crossAxisExtentForChild(child) + crossAxisMarginExtentForChild(child);
1024         if (!isColumnFlow() && style()->logicalHeight().isAuto())
1025             setLogicalHeight(std::max(logicalHeight(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent()));
1026         maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisMarginBoxExtent);
1027
1028         mainAxisOffset += flowAwareMarginStartForChild(child);
1029
1030         LayoutUnit childMainExtent = mainAxisExtentForChild(child);
1031         LayoutPoint childLocation(shouldFlipMainAxis ? totalMainExtent - mainAxisOffset - childMainExtent : mainAxisOffset,
1032             crossAxisOffset + flowAwareMarginBeforeForChild(child));
1033
1034         // FIXME: Supporting layout deltas.
1035         setFlowAwareLocationForChild(child, childLocation);
1036         mainAxisOffset += childMainExtent + flowAwareMarginEndForChild(child);
1037
1038         mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), childSizes.size());
1039     }
1040
1041     if (isColumnFlow())
1042         setLogicalHeight(mainAxisOffset + flowAwareBorderEnd() + flowAwarePaddingEnd() + scrollbarLogicalHeight());
1043
1044     if (style()->flexDirection() == FlowColumnReverse) {
1045         // We have to do an extra pass for column-reverse to reposition the flex items since the start depends
1046         // on the height of the flexbox, which we only know after we've positioned all the flex items.
1047         computeLogicalHeight();
1048         layoutColumnReverse(children, childSizes, crossAxisOffset, availableFreeSpace);
1049     }
1050
1051     lineContexts.append(LineContext(crossAxisOffset, maxChildCrossAxisExtent, children.size(), maxAscent));
1052     crossAxisOffset += maxChildCrossAxisExtent;
1053 }
1054
1055 void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace)
1056 {
1057     // This is similar to the logic in layoutAndPlaceChildren, except we place the children
1058     // starting from the end of the flexbox. We also don't need to layout anything since we're
1059     // just moving the children to a new position.
1060     LayoutUnit mainAxisOffset = logicalHeight() - flowAwareBorderEnd() - flowAwarePaddingEnd();
1061     mainAxisOffset -= initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), childSizes.size());
1062     mainAxisOffset -= isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1063
1064     for (size_t i = 0; i < children.size(); ++i) {
1065         RenderBox* child = children[i];
1066         if (child->isOutOfFlowPositioned()) {
1067             child->layer()->setStaticBlockPosition(mainAxisOffset);
1068             mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), childSizes.size());
1069             continue;
1070         }
1071         mainAxisOffset -= mainAxisExtentForChild(child) + flowAwareMarginEndForChild(child);
1072
1073         LayoutRect oldRect = child->frameRect();
1074         setFlowAwareLocationForChild(child, LayoutPoint(mainAxisOffset, crossAxisOffset + flowAwareMarginBeforeForChild(child)));
1075         if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
1076             child->repaintDuringLayoutIfMoved(oldRect);
1077
1078         mainAxisOffset -= flowAwareMarginStartForChild(child);
1079         mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), childSizes.size());
1080     }
1081 }
1082
1083 static LayoutUnit initialAlignContentOffset(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1084 {
1085     if (alignContent == AlignContentFlexEnd)
1086         return availableFreeSpace;
1087     if (alignContent == AlignContentCenter)
1088         return availableFreeSpace / 2;
1089     if (alignContent == AlignContentSpaceAround) {
1090         if (availableFreeSpace > 0 && numberOfLines)
1091             return availableFreeSpace / (2 * numberOfLines);
1092         if (availableFreeSpace < 0)
1093             return availableFreeSpace / 2;
1094     }
1095     return 0;
1096 }
1097
1098 static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1099 {
1100     if (availableFreeSpace > 0 && numberOfLines > 1) {
1101         if (alignContent == AlignContentSpaceBetween)
1102             return availableFreeSpace / (numberOfLines - 1);
1103         if (alignContent == AlignContentSpaceAround || alignContent == AlignContentStretch)
1104             return availableFreeSpace / numberOfLines;
1105     }
1106     return 0;
1107 }
1108
1109 void RenderFlexibleBox::alignFlexLines(OrderIterator& iterator, WTF::Vector<LineContext>& lineContexts)
1110 {
1111     if (!isMultiline() || style()->alignContent() == AlignContentFlexStart)
1112         return;
1113
1114     LayoutUnit availableCrossAxisSpace = crossAxisContentExtent();
1115     for (size_t i = 0; i < lineContexts.size(); ++i)
1116         availableCrossAxisSpace -= lineContexts[i].crossAxisExtent;
1117
1118     RenderBox* child = iterator.first();
1119     LayoutUnit lineOffset = initialAlignContentOffset(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1120     for (unsigned lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1121         lineContexts[lineNumber].crossAxisOffset += lineOffset;
1122         for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next())
1123             adjustAlignmentForChild(child, lineOffset);
1124
1125         if (style()->alignContent() == AlignContentStretch && availableCrossAxisSpace > 0)
1126             lineContexts[lineNumber].crossAxisExtent += availableCrossAxisSpace / static_cast<unsigned>(lineContexts.size());
1127
1128         lineOffset += alignContentSpaceBetweenChildren(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1129     }
1130 }
1131
1132 void RenderFlexibleBox::adjustAlignmentForChild(RenderBox* child, LayoutUnit delta)
1133 {
1134     if (child->isOutOfFlowPositioned()) {
1135         LayoutUnit staticInlinePosition = child->layer()->staticInlinePosition();
1136         LayoutUnit staticBlockPosition = child->layer()->staticBlockPosition();
1137         LayoutUnit mainAxis = isColumnFlow() ? staticBlockPosition : staticInlinePosition;
1138         LayoutUnit crossAxis = isColumnFlow() ? staticInlinePosition : staticBlockPosition;
1139         crossAxis += delta;
1140         prepareChildForPositionedLayout(child, mainAxis, crossAxis, NoFlipForRowReverse);
1141         return;
1142     }
1143
1144     LayoutRect oldRect = child->frameRect();
1145     setFlowAwareLocationForChild(child, flowAwareLocationForChild(child) + LayoutSize(0, delta));
1146
1147     // If the child moved, we have to repaint it as well as any floating/positioned
1148     // descendants. An exception is if we need a layout. In this case, we know we're going to
1149     // repaint ourselves (and the child) anyway.
1150     if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
1151         child->repaintDuringLayoutIfMoved(oldRect);
1152 }
1153
1154 void RenderFlexibleBox::alignChildren(OrderIterator& iterator, const WTF::Vector<LineContext>& lineContexts)
1155 {
1156     // Keep track of the space between the baseline edge and the after edge of the box for each line.
1157     WTF::Vector<LayoutUnit> minMarginAfterBaselines;
1158
1159     RenderBox* child = iterator.first();
1160     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1161         LayoutUnit minMarginAfterBaseline = MAX_LAYOUT_UNIT;
1162         LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1163         LayoutUnit maxAscent = lineContexts[lineNumber].maxAscent;
1164
1165         for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) {
1166             ASSERT(child);
1167             if (updateAutoMarginsInCrossAxis(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child)))
1168                 continue;
1169
1170             switch (alignmentForChild(child)) {
1171             case AlignAuto:
1172                 ASSERT_NOT_REACHED();
1173                 break;
1174             case AlignStretch: {
1175                 applyStretchAlignmentToChild(child, lineCrossAxisExtent);
1176                 // Since wrap-reverse flips cross start and cross end, strech children should be aligned with the cross end.
1177                 if (style()->flexWrap() == FlexWrapReverse)
1178                     adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
1179                 break;
1180             }
1181             case AlignFlexStart:
1182                 break;
1183             case AlignFlexEnd:
1184                 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
1185                 break;
1186             case AlignCenter:
1187                 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) / 2);
1188                 break;
1189             case AlignBaseline: {
1190                 LayoutUnit ascent = marginBoxAscentForChild(child);
1191                 LayoutUnit startOffset = maxAscent - ascent;
1192                 adjustAlignmentForChild(child, startOffset);
1193
1194                 if (style()->flexWrap() == FlexWrapReverse)
1195                     minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) - startOffset);
1196                 break;
1197             }
1198             }
1199         }
1200         minMarginAfterBaselines.append(minMarginAfterBaseline);
1201     }
1202
1203     if (style()->flexWrap() != FlexWrapReverse)
1204         return;
1205
1206     // wrap-reverse flips the cross axis start and end. For baseline alignment, this means we
1207     // need to align the after edge of baseline elements with the after edge of the flex line.
1208     child = iterator.first();
1209     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1210         LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber];
1211         for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) {
1212             ASSERT(child);
1213             if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child) && minMarginAfterBaseline)
1214                 adjustAlignmentForChild(child, minMarginAfterBaseline);
1215         }
1216     }
1217 }
1218
1219 void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox* child, LayoutUnit lineCrossAxisExtent)
1220 {
1221     if (!isColumnFlow() && child->style()->logicalHeight().isAuto()) {
1222         LayoutUnit logicalHeightBefore = child->logicalHeight();
1223         LayoutUnit stretchedLogicalHeight = child->logicalHeight() + availableAlignmentSpaceForChild(lineCrossAxisExtent, child);
1224
1225         child->setLogicalHeight(stretchedLogicalHeight);
1226         child->computeLogicalHeight();
1227
1228         // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
1229         if (child->logicalHeight() != logicalHeightBefore) {
1230             child->setOverrideLogicalContentHeight(child->logicalHeight() - child->borderAndPaddingLogicalHeight());
1231             child->setLogicalHeight(0);
1232             child->setChildNeedsLayout(true);
1233             child->layoutIfNeeded();
1234         }
1235     } else if (isColumnFlow() && child->style()->logicalWidth().isAuto() && isMultiline()) {
1236         // FIXME: Handle min-width and max-width.
1237         LayoutUnit childWidth = lineCrossAxisExtent - crossAxisMarginExtentForChild(child);
1238         child->setOverrideLogicalContentWidth(std::max(ZERO_LAYOUT_UNIT, childWidth));
1239         child->setChildNeedsLayout(true);
1240         child->layoutIfNeeded();
1241     }
1242 }
1243
1244 void RenderFlexibleBox::flipForRightToLeftColumn(OrderIterator& iterator)
1245 {
1246     if (style()->isLeftToRightDirection() || !isColumnFlow())
1247         return;
1248
1249     LayoutUnit crossExtent = crossAxisExtent();
1250     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
1251         if (child->isOutOfFlowPositioned())
1252             continue;
1253         LayoutPoint location = flowAwareLocationForChild(child);
1254         location.setY(crossExtent - crossAxisExtentForChild(child) - location.y());
1255         setFlowAwareLocationForChild(child, location);
1256     }
1257 }
1258
1259 void RenderFlexibleBox::flipForWrapReverse(OrderIterator& iterator, const WTF::Vector<LineContext>& lineContexts, LayoutUnit crossAxisStartEdge)
1260 {
1261     LayoutUnit contentExtent = crossAxisContentExtent();
1262     RenderBox* child = iterator.first();
1263     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1264         for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) {
1265             ASSERT(child);
1266             LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1267             LayoutUnit originalOffset = lineContexts[lineNumber].crossAxisOffset - crossAxisStartEdge;
1268             LayoutUnit newOffset = contentExtent - originalOffset - lineCrossAxisExtent;
1269             adjustAlignmentForChild(child, newOffset - originalOffset);
1270         }
1271     }
1272 }
1273
1274 }