REGRESSION: flexbox content-size fails to exclude scrollbar
[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 = computeContentBoxLogicalWidth(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, computeContentBoxLogicalWidth(styleToUse->logicalMinWidth().value()));
221         m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(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, computeContentBoxLogicalWidth(styleToUse->logicalMaxWidth().value()));
227         m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(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     computeLogicalWidth();
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     computeLogicalHeight();
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 computeLogicalHeight.
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 Length RenderFlexibleBox::crossAxisLength() const
364 {
365     return isHorizontalFlow() ? style()->height() : style()->width();
366 }
367
368 void RenderFlexibleBox::setCrossAxisExtent(LayoutUnit extent)
369 {
370     if (isHorizontalFlow())
371         setHeight(extent);
372     else
373         setWidth(extent);
374 }
375
376 LayoutUnit RenderFlexibleBox::crossAxisExtentForChild(RenderBox* child)
377 {
378     return isHorizontalFlow() ? child->height() : child->width();
379 }
380
381 LayoutUnit RenderFlexibleBox::mainAxisExtentForChild(RenderBox* child)
382 {
383     return isHorizontalFlow() ? child->width() : child->height();
384 }
385
386 LayoutUnit RenderFlexibleBox::crossAxisExtent() const
387 {
388     return isHorizontalFlow() ? height() : width();
389 }
390
391 LayoutUnit RenderFlexibleBox::mainAxisExtent() const
392 {
393     return isHorizontalFlow() ? width() : height();
394 }
395
396 LayoutUnit RenderFlexibleBox::crossAxisContentExtent() const
397 {
398     return isHorizontalFlow() ? contentHeight() : contentWidth();
399 }
400
401 LayoutUnit RenderFlexibleBox::mainAxisContentExtent()
402 {
403     if (isColumnFlow())
404         return std::max(LayoutUnit(0), computeLogicalClientHeight(MainOrPreferredSize, style()->logicalHeight()));
405     return contentLogicalWidth();
406 }
407
408 LayoutUnit RenderFlexibleBox::computeLogicalClientHeight(SizeType heightType, const Length& height)
409 {
410     LayoutUnit heightIncludingScrollbar = computeContentLogicalHeightUsing(heightType, height);
411     if (heightIncludingScrollbar == -1)
412         return -1;
413     return std::max(LayoutUnit(0), heightIncludingScrollbar - scrollbarLogicalHeight());
414 }
415
416 WritingMode RenderFlexibleBox::transformedWritingMode() const
417 {
418     WritingMode mode = style()->writingMode();
419     if (!isColumnFlow())
420         return mode;
421
422     switch (mode) {
423     case TopToBottomWritingMode:
424     case BottomToTopWritingMode:
425         return style()->isLeftToRightDirection() ? LeftToRightWritingMode : RightToLeftWritingMode;
426     case LeftToRightWritingMode:
427     case RightToLeftWritingMode:
428         return style()->isLeftToRightDirection() ? TopToBottomWritingMode : BottomToTopWritingMode;
429     }
430     ASSERT_NOT_REACHED();
431     return TopToBottomWritingMode;
432 }
433
434 LayoutUnit RenderFlexibleBox::flowAwareBorderStart() const
435 {
436     if (isHorizontalFlow())
437         return isLeftToRightFlow() ? borderLeft() : borderRight();
438     return isLeftToRightFlow() ? borderTop() : borderBottom();
439 }
440
441 LayoutUnit RenderFlexibleBox::flowAwareBorderEnd() const
442 {
443     if (isHorizontalFlow())
444         return isLeftToRightFlow() ? borderRight() : borderLeft();
445     return isLeftToRightFlow() ? borderBottom() : borderTop();
446 }
447
448 LayoutUnit RenderFlexibleBox::flowAwareBorderBefore() const
449 {
450     switch (transformedWritingMode()) {
451     case TopToBottomWritingMode:
452         return borderTop();
453     case BottomToTopWritingMode:
454         return borderBottom();
455     case LeftToRightWritingMode:
456         return borderLeft();
457     case RightToLeftWritingMode:
458         return borderRight();
459     }
460     ASSERT_NOT_REACHED();
461     return borderTop();
462 }
463
464 LayoutUnit RenderFlexibleBox::flowAwareBorderAfter() const
465 {
466     switch (transformedWritingMode()) {
467     case TopToBottomWritingMode:
468         return borderBottom();
469     case BottomToTopWritingMode:
470         return borderTop();
471     case LeftToRightWritingMode:
472         return borderRight();
473     case RightToLeftWritingMode:
474         return borderLeft();
475     }
476     ASSERT_NOT_REACHED();
477     return borderTop();
478 }
479
480 LayoutUnit RenderFlexibleBox::flowAwarePaddingStart() const
481 {
482     if (isHorizontalFlow())
483         return isLeftToRightFlow() ? paddingLeft() : paddingRight();
484     return isLeftToRightFlow() ? paddingTop() : paddingBottom();
485 }
486
487 LayoutUnit RenderFlexibleBox::flowAwarePaddingEnd() const
488 {
489     if (isHorizontalFlow())
490         return isLeftToRightFlow() ? paddingRight() : paddingLeft();
491     return isLeftToRightFlow() ? paddingBottom() : paddingTop();
492 }
493
494 LayoutUnit RenderFlexibleBox::flowAwarePaddingBefore() const
495 {
496     switch (transformedWritingMode()) {
497     case TopToBottomWritingMode:
498         return paddingTop();
499     case BottomToTopWritingMode:
500         return paddingBottom();
501     case LeftToRightWritingMode:
502         return paddingLeft();
503     case RightToLeftWritingMode:
504         return paddingRight();
505     }
506     ASSERT_NOT_REACHED();
507     return paddingTop();
508 }
509
510 LayoutUnit RenderFlexibleBox::flowAwarePaddingAfter() const
511 {
512     switch (transformedWritingMode()) {
513     case TopToBottomWritingMode:
514         return paddingBottom();
515     case BottomToTopWritingMode:
516         return paddingTop();
517     case LeftToRightWritingMode:
518         return paddingRight();
519     case RightToLeftWritingMode:
520         return paddingLeft();
521     }
522     ASSERT_NOT_REACHED();
523     return paddingTop();
524 }
525
526 LayoutUnit RenderFlexibleBox::flowAwareMarginStartForChild(RenderBox* child) const
527 {
528     if (isHorizontalFlow())
529         return isLeftToRightFlow() ? child->marginLeft() : child->marginRight();
530     return isLeftToRightFlow() ? child->marginTop() : child->marginBottom();
531 }
532
533 LayoutUnit RenderFlexibleBox::flowAwareMarginEndForChild(RenderBox* child) const
534 {
535     if (isHorizontalFlow())
536         return isLeftToRightFlow() ? child->marginRight() : child->marginLeft();
537     return isLeftToRightFlow() ? child->marginBottom() : child->marginTop();
538 }
539
540 LayoutUnit RenderFlexibleBox::flowAwareMarginBeforeForChild(RenderBox* child) const
541 {
542     switch (transformedWritingMode()) {
543     case TopToBottomWritingMode:
544         return child->marginTop();
545     case BottomToTopWritingMode:
546         return child->marginBottom();
547     case LeftToRightWritingMode:
548         return child->marginLeft();
549     case RightToLeftWritingMode:
550         return child->marginRight();
551     }
552     ASSERT_NOT_REACHED();
553     return marginTop();
554 }
555
556 LayoutUnit RenderFlexibleBox::flowAwareMarginAfterForChild(RenderBox* child) const
557 {
558     switch (transformedWritingMode()) {
559     case TopToBottomWritingMode:
560         return child->marginBottom();
561     case BottomToTopWritingMode:
562         return child->marginTop();
563     case LeftToRightWritingMode:
564         return child->marginRight();
565     case RightToLeftWritingMode:
566         return child->marginLeft();
567     }
568     ASSERT_NOT_REACHED();
569     return marginBottom();
570 }
571
572 LayoutUnit RenderFlexibleBox::crossAxisMarginExtentForChild(RenderBox* child) const
573 {
574     return isHorizontalFlow() ? child->marginHeight() : child->marginWidth();
575 }
576
577 LayoutUnit RenderFlexibleBox::crossAxisScrollbarExtent() const
578 {
579     return isHorizontalFlow() ? horizontalScrollbarHeight() : verticalScrollbarWidth();
580 }
581
582 LayoutPoint RenderFlexibleBox::flowAwareLocationForChild(RenderBox* child) const
583 {
584     return isHorizontalFlow() ? child->location() : child->location().transposedPoint();
585 }
586
587 void RenderFlexibleBox::setFlowAwareLocationForChild(RenderBox* child, const LayoutPoint& location)
588 {
589     if (isHorizontalFlow())
590         child->setLocation(location);
591     else
592         child->setLocation(location.transposedPoint());
593 }
594
595 LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox* child) const
596 {
597     return isHorizontalFlow() ? child->borderAndPaddingWidth() : child->borderAndPaddingHeight();
598 }
599
600 LayoutUnit RenderFlexibleBox::mainAxisScrollbarExtentForChild(RenderBox* child) const
601 {
602     return isHorizontalFlow() ? child->verticalScrollbarWidth() : child->horizontalScrollbarHeight();
603 }
604
605 LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* child)
606 {
607     Length flexBasis = flexBasisForChild(child);
608     if (flexBasis.isAuto()) {
609         LayoutUnit mainAxisExtent = hasOrthogonalFlow(child) ? child->logicalHeight() : child->maxPreferredLogicalWidth();
610         return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child);
611     }
612     return std::max(LayoutUnit(0), minimumValueForLength(flexBasis, mainAxisContentExtent(), view()));
613 }
614
615 LayoutUnit RenderFlexibleBox::computeAvailableFreeSpace(LayoutUnit preferredMainAxisExtent)
616 {
617     LayoutUnit contentExtent = 0;
618     if (!isColumnFlow())
619         contentExtent = mainAxisContentExtent();
620     else if (hasOverrideHeight())
621         contentExtent = overrideLogicalContentHeight();
622     else {
623         LayoutUnit heightResult = computeLogicalClientHeight(MainOrPreferredSize, style()->logicalHeight());
624         if (heightResult == -1)
625             heightResult = preferredMainAxisExtent;
626         LayoutUnit minHeight = computeLogicalClientHeight(MinSize, style()->logicalMinHeight()); // Leave as -1 if unset.
627         LayoutUnit maxHeight = style()->logicalMaxHeight().isUndefined() ? heightResult : computeLogicalClientHeight(MaxSize, style()->logicalMaxHeight());
628         if (maxHeight == -1)
629             maxHeight = heightResult;
630         heightResult = std::min(maxHeight, heightResult);
631         heightResult = std::max(minHeight, heightResult);
632         contentExtent = heightResult;
633     }
634
635     return contentExtent - preferredMainAxisExtent;
636 }
637
638 void RenderFlexibleBox::layoutFlexItems(OrderIterator& iterator, WTF::Vector<LineContext>& lineContexts)
639 {
640     OrderedFlexItemList orderedChildren;
641     LayoutUnit preferredMainAxisExtent;
642     float totalFlexGrow;
643     float totalWeightedFlexShrink;
644     LayoutUnit minMaxAppliedMainAxisExtent;
645
646     LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
647     while (computeNextFlexLine(iterator, orderedChildren, preferredMainAxisExtent, totalFlexGrow, totalWeightedFlexShrink, minMaxAppliedMainAxisExtent)) {
648         LayoutUnit availableFreeSpace = computeAvailableFreeSpace(preferredMainAxisExtent);
649         FlexSign flexSign = (minMaxAppliedMainAxisExtent < preferredMainAxisExtent + availableFreeSpace) ? PositiveFlexibility : NegativeFlexibility;
650         InflexibleFlexItemSize inflexibleItems;
651         WTF::Vector<LayoutUnit> childSizes;
652         while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, childSizes)) {
653             ASSERT(totalFlexGrow >= 0 && totalWeightedFlexShrink >= 0);
654             ASSERT(inflexibleItems.size() > 0);
655         }
656
657         layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace, lineContexts);
658     }
659 }
660
661 LayoutUnit RenderFlexibleBox::autoMarginOffsetInMainAxis(const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace)
662 {
663     if (availableFreeSpace <= 0)
664         return 0;
665
666     int numberOfAutoMargins = 0;
667     bool isHorizontal = isHorizontalFlow();
668     for (size_t i = 0; i < children.size(); ++i) {
669         RenderBox* child = children[i];
670         if (child->isOutOfFlowPositioned())
671             continue;
672         if (isHorizontal) {
673             if (child->style()->marginLeft().isAuto())
674                 ++numberOfAutoMargins;
675             if (child->style()->marginRight().isAuto())
676                 ++numberOfAutoMargins;
677         } else {
678             if (child->style()->marginTop().isAuto())
679                 ++numberOfAutoMargins;
680             if (child->style()->marginBottom().isAuto())
681                 ++numberOfAutoMargins;
682         }
683     }
684     if (!numberOfAutoMargins)
685         return 0;
686
687     LayoutUnit sizeOfAutoMargin = availableFreeSpace / numberOfAutoMargins;
688     availableFreeSpace = 0;
689     return sizeOfAutoMargin;
690 }
691
692 void RenderFlexibleBox::updateAutoMarginsInMainAxis(RenderBox* child, LayoutUnit autoMarginOffset)
693 {
694     if (isHorizontalFlow()) {
695         if (child->style()->marginLeft().isAuto())
696             child->setMarginLeft(autoMarginOffset);
697         if (child->style()->marginRight().isAuto())
698             child->setMarginRight(autoMarginOffset);
699     } else {
700         if (child->style()->marginTop().isAuto())
701             child->setMarginTop(autoMarginOffset);
702         if (child->style()->marginBottom().isAuto())
703             child->setMarginBottom(autoMarginOffset);
704     }
705 }
706
707 bool RenderFlexibleBox::hasAutoMarginsInCrossAxis(RenderBox* child)
708 {
709     if (isHorizontalFlow())
710         return child->style()->marginTop().isAuto() || child->style()->marginBottom().isAuto();
711     return child->style()->marginLeft().isAuto() || child->style()->marginRight().isAuto();
712 }
713
714 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox* child)
715 {
716     LayoutUnit childCrossExtent = 0;
717     if (!child->isOutOfFlowPositioned())
718         childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child);
719     return lineCrossAxisExtent - childCrossExtent;
720 }
721
722 bool RenderFlexibleBox::updateAutoMarginsInCrossAxis(RenderBox* child, LayoutUnit availableAlignmentSpace)
723 {
724     bool isHorizontal = isHorizontalFlow();
725     Length start = isHorizontal ? child->style()->marginTop() : child->style()->marginLeft();
726     Length end = isHorizontal ? child->style()->marginBottom() : child->style()->marginRight();
727     if (start.isAuto() && end.isAuto()) {
728         adjustAlignmentForChild(child, availableAlignmentSpace / 2);
729         if (isHorizontal) {
730             child->setMarginTop(availableAlignmentSpace / 2);
731             child->setMarginBottom(availableAlignmentSpace / 2);
732         } else {
733             child->setMarginLeft(availableAlignmentSpace / 2);
734             child->setMarginRight(availableAlignmentSpace / 2);
735         }
736         return true;
737     }
738     if (start.isAuto()) {
739         adjustAlignmentForChild(child, availableAlignmentSpace);
740         if (isHorizontal)
741             child->setMarginTop(availableAlignmentSpace);
742         else
743             child->setMarginLeft(availableAlignmentSpace);
744         return true;
745     }
746     if (end.isAuto()) {
747         if (isHorizontal)
748             child->setMarginBottom(availableAlignmentSpace);
749         else
750             child->setMarginRight(availableAlignmentSpace);
751         return true;
752     }
753     return false;
754 }
755
756 LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(RenderBox* child)
757 {
758     LayoutUnit ascent = child->firstLineBoxBaseline();
759     if (ascent == -1)
760         ascent = crossAxisExtentForChild(child) + flowAwareMarginAfterForChild(child);
761     return ascent + flowAwareMarginBeforeForChild(child);
762 }
763
764 void RenderFlexibleBox::computeMainAxisPreferredSizes(bool relayoutChildren, OrderHashSet& orderValues)
765 {
766     LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent();
767     RenderView* renderView = view();
768     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
769         orderValues.add(child->style()->order());
770
771         if (child->isOutOfFlowPositioned())
772             continue;
773
774         child->clearOverrideSize();
775         // Only need to layout here if we will need to get the logicalHeight of the child in computeNextFlexLine.
776         Length childMainAxisMin = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
777         if (hasOrthogonalFlow(child) && (flexBasisForChild(child).isAuto() || childMainAxisMin.isAuto())) {
778             if (!relayoutChildren)
779                 child->setChildNeedsLayout(true);
780             child->layoutIfNeeded();
781         }
782
783         // Before running the flex algorithm, 'auto' has a margin of 0.
784         // Also, if we're not auto sizing, we don't do a layout that computes the start/end margins.
785         if (isHorizontalFlow()) {
786             child->setMarginLeft(minimumValueForLength(child->style()->marginLeft(), flexboxAvailableContentExtent, renderView));
787             child->setMarginRight(minimumValueForLength(child->style()->marginRight(), flexboxAvailableContentExtent, renderView));
788         } else {
789             child->setMarginTop(minimumValueForLength(child->style()->marginTop(), flexboxAvailableContentExtent, renderView));
790             child->setMarginBottom(minimumValueForLength(child->style()->marginBottom(), flexboxAvailableContentExtent, renderView));
791         }
792     }
793 }
794
795 LayoutUnit RenderFlexibleBox::lineBreakLength()
796 {
797     if (!isColumnFlow())
798         return mainAxisContentExtent();
799
800     LayoutUnit height = computeLogicalClientHeight(MainOrPreferredSize, style()->logicalHeight());
801     if (height == -1)
802         height = MAX_LAYOUT_UNIT;
803     LayoutUnit maxHeight = computeLogicalClientHeight(MaxSize, style()->logicalMaxHeight());
804     if (maxHeight != -1)
805         height = std::min(height, maxHeight);
806     return height;
807 }
808
809 LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox* child, LayoutUnit childSize, LayoutUnit flexboxAvailableContentExtent)
810 {
811     Length max = isHorizontalFlow() ? child->style()->maxWidth() : child->style()->maxHeight();
812     Length min = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
813     RenderView* renderView = view();
814     // FIXME: valueForLength isn't quite right in quirks mode: percentage heights should check parents until a value is found.
815     // https://bugs.webkit.org/show_bug.cgi?id=81809
816     if (max.isSpecified() && childSize > valueForLength(max, flexboxAvailableContentExtent, renderView))
817         childSize = valueForLength(max, flexboxAvailableContentExtent, renderView);
818
819     if (min.isSpecified() && childSize < valueForLength(min, flexboxAvailableContentExtent, renderView))
820         return valueForLength(min, flexboxAvailableContentExtent, renderView);
821
822     // FIXME: Support min/max sizes of fit-content, max-content and fill-available.
823     if (min.isAuto()) {
824         LayoutUnit minContent = hasOrthogonalFlow(child) ? child->logicalHeight() : child->minPreferredLogicalWidth();
825         minContent -= mainAxisBorderAndPaddingExtentForChild(child);
826         return std::max(childSize, minContent);
827     }
828
829     return childSize;
830 }
831
832 bool RenderFlexibleBox::computeNextFlexLine(OrderIterator& iterator, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalFlexGrow, float& totalWeightedFlexShrink, LayoutUnit& minMaxAppliedMainAxisExtent)
833 {
834     orderedChildren.clear();
835     preferredMainAxisExtent = 0;
836     totalFlexGrow = totalWeightedFlexShrink = 0;
837     minMaxAppliedMainAxisExtent = 0;
838
839     if (!iterator.currentChild())
840         return false;
841
842     LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent();
843     LayoutUnit lineBreak = lineBreakLength();
844
845     for (RenderBox* child = iterator.currentChild(); child; child = iterator.next()) {
846         if (child->isOutOfFlowPositioned()) {
847             orderedChildren.append(child);
848             continue;
849         }
850
851         LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(child);
852         LayoutUnit childMainAxisMarginBoxExtent = mainAxisBorderAndPaddingExtentForChild(child) + childMainAxisExtent;
853         childMainAxisMarginBoxExtent += isHorizontalFlow() ? child->marginWidth() : child->marginHeight();
854
855         if (isMultiline() && preferredMainAxisExtent + childMainAxisMarginBoxExtent > lineBreak && orderedChildren.size() > 0)
856             break;
857         orderedChildren.append(child);
858         preferredMainAxisExtent += childMainAxisMarginBoxExtent;
859         totalFlexGrow += child->style()->flexGrow();
860         totalWeightedFlexShrink += child->style()->flexShrink() * childMainAxisExtent;
861
862         LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(child, childMainAxisExtent, flexboxAvailableContentExtent);
863         minMaxAppliedMainAxisExtent += childMinMaxAppliedMainAxisExtent - childMainAxisExtent + childMainAxisMarginBoxExtent;
864     }
865     return true;
866 }
867
868 void RenderFlexibleBox::freezeViolations(const WTF::Vector<Violation>& violations, LayoutUnit& availableFreeSpace, float& totalFlexGrow, float& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems)
869 {
870     for (size_t i = 0; i < violations.size(); ++i) {
871         RenderBox* child = violations[i].child;
872         LayoutUnit childSize = violations[i].childSize;
873         LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child);
874         availableFreeSpace -= childSize - preferredChildSize;
875         totalFlexGrow -= child->style()->flexGrow();
876         totalWeightedFlexShrink -= child->style()->flexShrink() * preferredChildSize;
877         inflexibleItems.set(child, childSize);
878     }
879 }
880
881 // Returns true if we successfully ran the algorithm and sized the flex items.
882 bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, float& totalFlexGrow, float& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, WTF::Vector<LayoutUnit>& childSizes)
883 {
884     childSizes.clear();
885     LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent();
886     LayoutUnit totalViolation = 0;
887     LayoutUnit usedFreeSpace = 0;
888     WTF::Vector<Violation> minViolations;
889     WTF::Vector<Violation> maxViolations;
890     for (size_t i = 0; i < children.size(); ++i) {
891         RenderBox* child = children[i];
892         if (child->isOutOfFlowPositioned()) {
893             childSizes.append(0);
894             continue;
895         }
896
897         if (inflexibleItems.contains(child))
898             childSizes.append(inflexibleItems.get(child));
899         else {
900             LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child);
901             LayoutUnit childSize = preferredChildSize;
902             if (availableFreeSpace > 0 && totalFlexGrow > 0 && flexSign == PositiveFlexibility && isfinite(totalFlexGrow))
903                 childSize += roundedLayoutUnit(availableFreeSpace * child->style()->flexGrow() / totalFlexGrow);
904             else if (availableFreeSpace < 0 && totalWeightedFlexShrink > 0 && flexSign == NegativeFlexibility && isfinite(totalWeightedFlexShrink))
905                 childSize += roundedLayoutUnit(availableFreeSpace * child->style()->flexShrink() * preferredChildSize / totalWeightedFlexShrink);
906
907             LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(child, childSize, flexboxAvailableContentExtent);
908             childSizes.append(adjustedChildSize);
909             usedFreeSpace += adjustedChildSize - preferredChildSize;
910
911             LayoutUnit violation = adjustedChildSize - childSize;
912             if (violation > 0)
913                 minViolations.append(Violation(child, adjustedChildSize));
914             else if (violation < 0)
915                 maxViolations.append(Violation(child, adjustedChildSize));
916             totalViolation += violation;
917         }
918     }
919
920     if (totalViolation)
921         freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems);
922     else
923         availableFreeSpace -= usedFreeSpace;
924
925     return !totalViolation;
926 }
927
928 static LayoutUnit initialJustifyContentOffset(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
929 {
930     if (justifyContent == JustifyFlexEnd)
931         return availableFreeSpace;
932     if (justifyContent == JustifyCenter)
933         return availableFreeSpace / 2;
934     if (justifyContent == JustifySpaceAround) {
935         if (availableFreeSpace > 0 && numberOfChildren)
936             return availableFreeSpace / (2 * numberOfChildren);
937         if (availableFreeSpace < 0)
938             return availableFreeSpace / 2;
939     }
940     return 0;
941 }
942
943 static LayoutUnit justifyContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
944 {
945     if (availableFreeSpace > 0 && numberOfChildren > 1) {
946         if (justifyContent == JustifySpaceBetween)
947             return availableFreeSpace / (numberOfChildren - 1);
948         if (justifyContent == JustifySpaceAround)
949             return availableFreeSpace / numberOfChildren;
950     }
951     return 0;
952 }
953
954 void RenderFlexibleBox::setLogicalOverrideSize(RenderBox* child, LayoutUnit childPreferredSize)
955 {
956     if (hasOrthogonalFlow(child))
957         child->setOverrideLogicalContentHeight(childPreferredSize - child->borderAndPaddingLogicalHeight());
958     else
959         child->setOverrideLogicalContentWidth(childPreferredSize - child->borderAndPaddingLogicalWidth());
960 }
961
962 void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox* child, LayoutUnit mainAxisOffset, LayoutUnit crossAxisOffset, PositionedLayoutMode layoutMode)
963 {
964     ASSERT(child->isOutOfFlowPositioned());
965     child->containingBlock()->insertPositionedObject(child);
966     RenderLayer* childLayer = child->layer();
967     LayoutUnit inlinePosition = isColumnFlow() ? crossAxisOffset : mainAxisOffset;
968     if (layoutMode == FlipForRowReverse && style()->flexDirection() == FlowRowReverse)
969         inlinePosition = mainAxisExtent() - mainAxisOffset;
970     childLayer->setStaticInlinePosition(inlinePosition); // FIXME: Not right for regions.
971
972     LayoutUnit staticBlockPosition = isColumnFlow() ? mainAxisOffset : crossAxisOffset;
973     if (childLayer->staticBlockPosition() != staticBlockPosition) {
974         childLayer->setStaticBlockPosition(staticBlockPosition);
975         if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
976             child->setChildNeedsLayout(true, MarkOnlyThis);
977     }
978 }
979
980 static EAlignItems alignmentForChild(RenderBox* child)
981 {
982     EAlignItems align = child->style()->alignSelf();
983     if (align == AlignAuto)
984         align = child->parent()->style()->alignItems();
985
986     if (child->parent()->style()->flexWrap() == FlexWrapReverse) {
987         if (align == AlignFlexStart)
988             align = AlignFlexEnd;
989         else if (align == AlignFlexEnd)
990             align = AlignFlexStart;
991     }
992
993     return align;
994 }
995
996 void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace, WTF::Vector<LineContext>& lineContexts)
997 {
998     ASSERT(childSizes.size() == children.size());
999
1000     LayoutUnit autoMarginOffset = autoMarginOffsetInMainAxis(children, availableFreeSpace);
1001     LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart();
1002     mainAxisOffset += initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), childSizes.size());
1003     if (style()->flexDirection() == FlowRowReverse)
1004         mainAxisOffset += isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1005
1006     LayoutUnit totalMainExtent = mainAxisExtent();
1007     LayoutUnit maxAscent = 0, maxDescent = 0; // Used when align-items: baseline.
1008     LayoutUnit maxChildCrossAxisExtent = 0;
1009     bool shouldFlipMainAxis = !isColumnFlow() && !isLeftToRightFlow();
1010     for (size_t i = 0; i < children.size(); ++i) {
1011         RenderBox* child = children[i];
1012         if (child->isOutOfFlowPositioned()) {
1013             prepareChildForPositionedLayout(child, mainAxisOffset, crossAxisOffset, FlipForRowReverse);
1014             mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), childSizes.size());
1015             continue;
1016         }
1017         LayoutUnit childPreferredSize = childSizes[i] + mainAxisBorderAndPaddingExtentForChild(child);
1018         setLogicalOverrideSize(child, childPreferredSize);
1019         // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
1020         child->setChildNeedsLayout(true);
1021         child->layoutIfNeeded();
1022
1023         updateAutoMarginsInMainAxis(child, autoMarginOffset);
1024
1025         LayoutUnit childCrossAxisMarginBoxExtent;
1026         if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child)) {
1027             LayoutUnit ascent = marginBoxAscentForChild(child);
1028             LayoutUnit descent = (crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child)) - ascent;
1029
1030             maxAscent = std::max(maxAscent, ascent);
1031             maxDescent = std::max(maxDescent, descent);
1032
1033             childCrossAxisMarginBoxExtent = maxAscent + maxDescent;
1034         } else
1035             childCrossAxisMarginBoxExtent = crossAxisExtentForChild(child) + crossAxisMarginExtentForChild(child);
1036         if (!isColumnFlow() && style()->logicalHeight().isAuto())
1037             setLogicalHeight(std::max(logicalHeight(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent()));
1038         maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisMarginBoxExtent);
1039
1040         mainAxisOffset += flowAwareMarginStartForChild(child);
1041
1042         LayoutUnit childMainExtent = mainAxisExtentForChild(child);
1043         LayoutPoint childLocation(shouldFlipMainAxis ? totalMainExtent - mainAxisOffset - childMainExtent : mainAxisOffset,
1044             crossAxisOffset + flowAwareMarginBeforeForChild(child));
1045
1046         // FIXME: Supporting layout deltas.
1047         setFlowAwareLocationForChild(child, childLocation);
1048         mainAxisOffset += childMainExtent + flowAwareMarginEndForChild(child);
1049
1050         mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), childSizes.size());
1051     }
1052
1053     if (isColumnFlow())
1054         setLogicalHeight(mainAxisOffset + flowAwareBorderEnd() + flowAwarePaddingEnd() + scrollbarLogicalHeight());
1055
1056     if (style()->flexDirection() == FlowColumnReverse) {
1057         // We have to do an extra pass for column-reverse to reposition the flex items since the start depends
1058         // on the height of the flexbox, which we only know after we've positioned all the flex items.
1059         computeLogicalHeight();
1060         layoutColumnReverse(children, childSizes, crossAxisOffset, availableFreeSpace);
1061     }
1062
1063     lineContexts.append(LineContext(crossAxisOffset, maxChildCrossAxisExtent, children.size(), maxAscent));
1064     crossAxisOffset += maxChildCrossAxisExtent;
1065 }
1066
1067 void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace)
1068 {
1069     // This is similar to the logic in layoutAndPlaceChildren, except we place the children
1070     // starting from the end of the flexbox. We also don't need to layout anything since we're
1071     // just moving the children to a new position.
1072     LayoutUnit mainAxisOffset = logicalHeight() - flowAwareBorderEnd() - flowAwarePaddingEnd();
1073     mainAxisOffset -= initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), childSizes.size());
1074     mainAxisOffset -= isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1075
1076     for (size_t i = 0; i < children.size(); ++i) {
1077         RenderBox* child = children[i];
1078         if (child->isOutOfFlowPositioned()) {
1079             child->layer()->setStaticBlockPosition(mainAxisOffset);
1080             mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), childSizes.size());
1081             continue;
1082         }
1083         mainAxisOffset -= mainAxisExtentForChild(child) + flowAwareMarginEndForChild(child);
1084
1085         LayoutRect oldRect = child->frameRect();
1086         setFlowAwareLocationForChild(child, LayoutPoint(mainAxisOffset, crossAxisOffset + flowAwareMarginBeforeForChild(child)));
1087         if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
1088             child->repaintDuringLayoutIfMoved(oldRect);
1089
1090         mainAxisOffset -= flowAwareMarginStartForChild(child);
1091         mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), childSizes.size());
1092     }
1093 }
1094
1095 static LayoutUnit initialAlignContentOffset(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1096 {
1097     if (alignContent == AlignContentFlexEnd)
1098         return availableFreeSpace;
1099     if (alignContent == AlignContentCenter)
1100         return availableFreeSpace / 2;
1101     if (alignContent == AlignContentSpaceAround) {
1102         if (availableFreeSpace > 0 && numberOfLines)
1103             return availableFreeSpace / (2 * numberOfLines);
1104         if (availableFreeSpace < 0)
1105             return availableFreeSpace / 2;
1106     }
1107     return 0;
1108 }
1109
1110 static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1111 {
1112     if (availableFreeSpace > 0 && numberOfLines > 1) {
1113         if (alignContent == AlignContentSpaceBetween)
1114             return availableFreeSpace / (numberOfLines - 1);
1115         if (alignContent == AlignContentSpaceAround || alignContent == AlignContentStretch)
1116             return availableFreeSpace / numberOfLines;
1117     }
1118     return 0;
1119 }
1120
1121 void RenderFlexibleBox::alignFlexLines(OrderIterator& iterator, WTF::Vector<LineContext>& lineContexts)
1122 {
1123     if (!isMultiline() || style()->alignContent() == AlignContentFlexStart)
1124         return;
1125
1126     LayoutUnit availableCrossAxisSpace = crossAxisContentExtent();
1127     for (size_t i = 0; i < lineContexts.size(); ++i)
1128         availableCrossAxisSpace -= lineContexts[i].crossAxisExtent;
1129
1130     RenderBox* child = iterator.first();
1131     LayoutUnit lineOffset = initialAlignContentOffset(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1132     for (unsigned lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1133         lineContexts[lineNumber].crossAxisOffset += lineOffset;
1134         for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next())
1135             adjustAlignmentForChild(child, lineOffset);
1136
1137         if (style()->alignContent() == AlignContentStretch && availableCrossAxisSpace > 0)
1138             lineContexts[lineNumber].crossAxisExtent += availableCrossAxisSpace / static_cast<unsigned>(lineContexts.size());
1139
1140         lineOffset += alignContentSpaceBetweenChildren(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1141     }
1142 }
1143
1144 void RenderFlexibleBox::adjustAlignmentForChild(RenderBox* child, LayoutUnit delta)
1145 {
1146     if (child->isOutOfFlowPositioned()) {
1147         LayoutUnit staticInlinePosition = child->layer()->staticInlinePosition();
1148         LayoutUnit staticBlockPosition = child->layer()->staticBlockPosition();
1149         LayoutUnit mainAxis = isColumnFlow() ? staticBlockPosition : staticInlinePosition;
1150         LayoutUnit crossAxis = isColumnFlow() ? staticInlinePosition : staticBlockPosition;
1151         crossAxis += delta;
1152         prepareChildForPositionedLayout(child, mainAxis, crossAxis, NoFlipForRowReverse);
1153         return;
1154     }
1155
1156     LayoutRect oldRect = child->frameRect();
1157     setFlowAwareLocationForChild(child, flowAwareLocationForChild(child) + LayoutSize(0, delta));
1158
1159     // If the child moved, we have to repaint it as well as any floating/positioned
1160     // descendants. An exception is if we need a layout. In this case, we know we're going to
1161     // repaint ourselves (and the child) anyway.
1162     if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
1163         child->repaintDuringLayoutIfMoved(oldRect);
1164 }
1165
1166 void RenderFlexibleBox::alignChildren(OrderIterator& iterator, const WTF::Vector<LineContext>& lineContexts)
1167 {
1168     // Keep track of the space between the baseline edge and the after edge of the box for each line.
1169     WTF::Vector<LayoutUnit> minMarginAfterBaselines;
1170
1171     RenderBox* child = iterator.first();
1172     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1173         LayoutUnit minMarginAfterBaseline = MAX_LAYOUT_UNIT;
1174         LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1175         LayoutUnit maxAscent = lineContexts[lineNumber].maxAscent;
1176
1177         for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) {
1178             ASSERT(child);
1179             if (updateAutoMarginsInCrossAxis(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child)))
1180                 continue;
1181
1182             switch (alignmentForChild(child)) {
1183             case AlignAuto:
1184                 ASSERT_NOT_REACHED();
1185                 break;
1186             case AlignStretch: {
1187                 applyStretchAlignmentToChild(child, lineCrossAxisExtent);
1188                 // Since wrap-reverse flips cross start and cross end, strech children should be aligned with the cross end.
1189                 if (style()->flexWrap() == FlexWrapReverse)
1190                     adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
1191                 break;
1192             }
1193             case AlignFlexStart:
1194                 break;
1195             case AlignFlexEnd:
1196                 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
1197                 break;
1198             case AlignCenter:
1199                 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) / 2);
1200                 break;
1201             case AlignBaseline: {
1202                 LayoutUnit ascent = marginBoxAscentForChild(child);
1203                 LayoutUnit startOffset = maxAscent - ascent;
1204                 adjustAlignmentForChild(child, startOffset);
1205
1206                 if (style()->flexWrap() == FlexWrapReverse)
1207                     minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) - startOffset);
1208                 break;
1209             }
1210             }
1211         }
1212         minMarginAfterBaselines.append(minMarginAfterBaseline);
1213     }
1214
1215     if (style()->flexWrap() != FlexWrapReverse)
1216         return;
1217
1218     // wrap-reverse flips the cross axis start and end. For baseline alignment, this means we
1219     // need to align the after edge of baseline elements with the after edge of the flex line.
1220     child = iterator.first();
1221     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1222         LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber];
1223         for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) {
1224             ASSERT(child);
1225             if (alignmentForChild(child) == AlignBaseline && !hasAutoMarginsInCrossAxis(child) && minMarginAfterBaseline)
1226                 adjustAlignmentForChild(child, minMarginAfterBaseline);
1227         }
1228     }
1229 }
1230
1231 void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox* child, LayoutUnit lineCrossAxisExtent)
1232 {
1233     if (!isColumnFlow() && child->style()->logicalHeight().isAuto()) {
1234         LayoutUnit logicalHeightBefore = child->logicalHeight();
1235         LayoutUnit stretchedLogicalHeight = child->logicalHeight() + availableAlignmentSpaceForChild(lineCrossAxisExtent, child);
1236
1237         child->setLogicalHeight(stretchedLogicalHeight);
1238         child->computeLogicalHeight();
1239
1240         // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
1241         if (child->logicalHeight() != logicalHeightBefore) {
1242             child->setOverrideLogicalContentHeight(child->logicalHeight() - child->borderAndPaddingLogicalHeight());
1243             child->setLogicalHeight(0);
1244             child->setChildNeedsLayout(true);
1245             child->layoutIfNeeded();
1246         }
1247     } else if (isColumnFlow() && child->style()->logicalWidth().isAuto() && isMultiline()) {
1248         // FIXME: Handle min-width and max-width.
1249         LayoutUnit childWidth = lineCrossAxisExtent - crossAxisMarginExtentForChild(child);
1250         child->setOverrideLogicalContentWidth(std::max(ZERO_LAYOUT_UNIT, childWidth));
1251         child->setChildNeedsLayout(true);
1252         child->layoutIfNeeded();
1253     }
1254 }
1255
1256 void RenderFlexibleBox::flipForRightToLeftColumn(OrderIterator& iterator)
1257 {
1258     if (style()->isLeftToRightDirection() || !isColumnFlow())
1259         return;
1260
1261     LayoutUnit crossExtent = crossAxisExtent();
1262     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
1263         if (child->isOutOfFlowPositioned())
1264             continue;
1265         LayoutPoint location = flowAwareLocationForChild(child);
1266         location.setY(crossExtent - crossAxisExtentForChild(child) - location.y());
1267         setFlowAwareLocationForChild(child, location);
1268     }
1269 }
1270
1271 void RenderFlexibleBox::flipForWrapReverse(OrderIterator& iterator, const WTF::Vector<LineContext>& lineContexts, LayoutUnit crossAxisStartEdge)
1272 {
1273     LayoutUnit contentExtent = crossAxisContentExtent();
1274     RenderBox* child = iterator.first();
1275     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1276         for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = iterator.next()) {
1277             ASSERT(child);
1278             LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1279             LayoutUnit originalOffset = lineContexts[lineNumber].crossAxisOffset - crossAxisStartEdge;
1280             LayoutUnit newOffset = contentExtent - originalOffset - lineCrossAxisExtent;
1281             adjustAlignmentForChild(child, newOffset - originalOffset);
1282         }
1283     }
1284 }
1285
1286 }