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