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