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