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