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