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