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