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