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