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