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