05f70db11ae5f3b2aa84c352c9efb28da2d67ba6
[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
38 namespace WebCore {
39
40 // Normally, -1 and 0 are not valid in a HashSet, but these are relatively likely flex-order values. Instead,
41 // we make the two smallest int values invalid flex-order values (in the css parser code we clamp them to
42 // int min + 2).
43 struct RenderFlexibleBox::FlexOrderHashTraits : WTF::GenericHashTraits<int> {
44     static const bool emptyValueIsZero = false;
45     static int emptyValue() { return std::numeric_limits<int>::min(); }
46     static void constructDeletedValue(int& slot) { slot = std::numeric_limits<int>::min() + 1; }
47     static bool isDeletedValue(int value) { return value == std::numeric_limits<int>::min() + 1; }
48 };
49
50 class RenderFlexibleBox::FlexOrderIterator {
51 public:
52     FlexOrderIterator(RenderFlexibleBox* flexibleBox, const FlexOrderHashSet& flexOrderValues)
53         : m_flexibleBox(flexibleBox)
54         , m_currentChild(0)
55         , m_orderValuesIterator(0)
56     {
57         copyToVector(flexOrderValues, m_orderValues);
58         std::sort(m_orderValues.begin(), m_orderValues.end());
59         first();
60     }
61
62     RenderBox* currentChild() { return m_currentChild; }
63
64     RenderBox* first()
65     {
66         reset();
67         return next();
68     }
69
70     RenderBox* next()
71     {
72         do {
73             if (!m_currentChild) {
74                 if (m_orderValuesIterator == m_orderValues.end())
75                     return 0;
76                 if (m_orderValuesIterator) {
77                     ++m_orderValuesIterator;
78                     if (m_orderValuesIterator == m_orderValues.end())
79                         return 0;
80                 } else
81                     m_orderValuesIterator = m_orderValues.begin();
82
83                 m_currentChild = m_flexibleBox->firstChildBox();
84             } else
85                 m_currentChild = m_currentChild->nextSiblingBox();
86         } while (!m_currentChild || m_currentChild->style()->flexOrder() != *m_orderValuesIterator);
87
88         return m_currentChild;
89     }
90
91     void reset()
92     {
93         m_currentChild = 0;
94         m_orderValuesIterator = 0;
95     }
96
97 private:
98     RenderFlexibleBox* m_flexibleBox;
99     RenderBox* m_currentChild;
100     Vector<int> m_orderValues;
101     Vector<int>::const_iterator m_orderValuesIterator;
102 };
103
104
105 RenderFlexibleBox::RenderFlexibleBox(Node* node)
106     : RenderBlock(node)
107 {
108     setChildrenInline(false); // All of our children must be block-level.
109 }
110
111 RenderFlexibleBox::~RenderFlexibleBox()
112 {
113 }
114
115 const char* RenderFlexibleBox::renderName() const
116 {
117     return "RenderFlexibleBox";
118 }
119
120 static LayoutUnit marginLogicalWidthForChild(RenderBox* child, RenderStyle* parentStyle)
121 {
122     // A margin has three types: fixed, percentage, and auto (variable).
123     // Auto and percentage margins become 0 when computing min/max width.
124     // Fixed margins can be added in as is.
125     Length marginLeft = child->style()->marginStartUsing(parentStyle);
126     Length marginRight = child->style()->marginEndUsing(parentStyle);
127     LayoutUnit margin = 0;
128     if (marginLeft.isFixed())
129         margin += marginLeft.value();
130     if (marginRight.isFixed())
131         margin += marginRight.value();
132     return margin;
133 }
134
135 void RenderFlexibleBox::computePreferredLogicalWidths()
136 {
137     ASSERT(preferredLogicalWidthsDirty());
138
139     RenderStyle* styleToUse = style();
140     if (styleToUse->logicalWidth().isFixed() && styleToUse->logicalWidth().value() > 0)
141         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeContentBoxLogicalWidth(styleToUse->logicalWidth().value());
142     else {
143         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
144
145         for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
146             if (child->isPositioned())
147                 continue;
148
149             LayoutUnit margin = marginLogicalWidthForChild(child, style());
150             bool hasOrthogonalWritingMode = child->isHorizontalWritingMode() != isHorizontalWritingMode();
151             LayoutUnit minPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->minPreferredLogicalWidth();
152             LayoutUnit maxPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->maxPreferredLogicalWidth();
153             minPreferredLogicalWidth += margin;
154             maxPreferredLogicalWidth += margin;
155             if (!isColumnFlow()) {
156                 m_minPreferredLogicalWidth += minPreferredLogicalWidth;
157                 m_maxPreferredLogicalWidth += maxPreferredLogicalWidth;
158             } else {
159                 m_minPreferredLogicalWidth = std::max(minPreferredLogicalWidth, m_minPreferredLogicalWidth);
160                 m_maxPreferredLogicalWidth = std::max(maxPreferredLogicalWidth, m_maxPreferredLogicalWidth);
161             }
162         }
163
164         m_maxPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
165     }
166
167     LayoutUnit scrollbarWidth = 0;
168     if (hasOverflowClip()) {
169         if (isHorizontalWritingMode() && styleToUse->overflowY() == OSCROLL) {
170             layer()->setHasVerticalScrollbar(true);
171             scrollbarWidth = verticalScrollbarWidth();
172         } else if (!isHorizontalWritingMode() && styleToUse->overflowX() == OSCROLL) {
173             layer()->setHasHorizontalScrollbar(true);
174             scrollbarWidth = horizontalScrollbarHeight();
175         }
176     }
177
178     m_maxPreferredLogicalWidth += scrollbarWidth;
179     m_minPreferredLogicalWidth += scrollbarWidth;
180
181     if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
182         m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(styleToUse->logicalMinWidth().value()));
183         m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(styleToUse->logicalMinWidth().value()));
184     }
185
186     if (styleToUse->logicalMaxWidth().isFixed()) {
187         m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(styleToUse->logicalMaxWidth().value()));
188         m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(styleToUse->logicalMaxWidth().value()));
189     }
190
191     LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
192     m_minPreferredLogicalWidth += borderAndPadding;
193     m_maxPreferredLogicalWidth += borderAndPadding;
194
195     setPreferredLogicalWidthsDirty(false);
196 }
197
198 void RenderFlexibleBox::layoutBlock(bool relayoutChildren, int, BlockLayoutPass)
199 {
200     ASSERT(needsLayout());
201
202     if (!relayoutChildren && simplifiedLayout())
203         return;
204
205     LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
206     LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
207
208     if (inRenderFlowThread()) {
209         // Regions changing widths can force us to relayout our children.
210         if (logicalWidthChangedInRegions())
211             relayoutChildren = true;
212     }
213     computeInitialRegionRangeForBlock();
214
215     IntSize previousSize = size();
216
217     setLogicalHeight(0);
218     // We need to call both of these because we grab both crossAxisExtent and mainAxisExtent in layoutFlexItems.
219     computeLogicalWidth();
220     computeLogicalHeight();
221
222     m_overflow.clear();
223
224     // For overflow:scroll blocks, ensure we have both scrollbars in place always.
225     if (scrollsOverflow()) {
226         if (style()->overflowX() == OSCROLL)
227             layer()->setHasHorizontalScrollbar(true);
228         if (style()->overflowY() == OSCROLL)
229             layer()->setHasVerticalScrollbar(true);
230     }
231
232     layoutFlexItems(relayoutChildren);
233
234     LayoutUnit oldClientAfterEdge = clientLogicalBottom();
235     computeLogicalHeight();
236
237     if (size() != previousSize)
238         relayoutChildren = true;
239
240     layoutPositionedObjects(relayoutChildren || isRoot());
241
242     computeRegionRangeForBlock();
243
244     // FIXME: css3/flexbox/repaint-rtl-column.html seems to repaint more overflow than it needs to.
245     computeOverflow(oldClientAfterEdge);
246     statePusher.pop();
247
248     updateLayerTransform();
249
250     // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
251     // we overflow or not.
252     updateScrollInfoAfterLayout();
253
254     repainter.repaintAfterLayout();
255
256     setNeedsLayout(false);
257 }
258
259 bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox* child) const
260 {
261     // FIXME: If the child is a flexbox, then we need to check isHorizontalFlow.
262     return isHorizontalFlow() != child->isHorizontalWritingMode();
263 }
264
265 bool RenderFlexibleBox::isColumnFlow() const
266 {
267     return style()->isColumnFlexDirection();
268 }
269
270 bool RenderFlexibleBox::isHorizontalFlow() const
271 {
272     if (isHorizontalWritingMode())
273         return !isColumnFlow();
274     return isColumnFlow();
275 }
276
277 bool RenderFlexibleBox::isLeftToRightFlow() const
278 {
279     if (isColumnFlow())
280         return style()->writingMode() == TopToBottomWritingMode || style()->writingMode() == LeftToRightWritingMode;
281     return style()->isLeftToRightDirection() ^ (style()->flexDirection() == FlowRowReverse);
282 }
283
284 bool RenderFlexibleBox::isMultiline() const
285 {
286     return style()->flexWrap() != FlexWrapNone;
287 }
288
289 Length RenderFlexibleBox::mainAxisLengthForChild(RenderBox* child) const
290 {
291     return isHorizontalFlow() ? child->style()->width() : child->style()->height();
292 }
293
294 Length RenderFlexibleBox::crossAxisLength() const
295 {
296     return isHorizontalFlow() ? style()->height() : style()->width();
297 }
298
299 void RenderFlexibleBox::setCrossAxisExtent(LayoutUnit extent)
300 {
301     if (isHorizontalFlow())
302         setHeight(extent);
303     else
304         setWidth(extent);
305 }
306
307 LayoutUnit RenderFlexibleBox::crossAxisExtentForChild(RenderBox* child)
308 {
309     return isHorizontalFlow() ? child->height() : child->width();
310 }
311
312 LayoutUnit RenderFlexibleBox::mainAxisExtentForChild(RenderBox* child)
313 {
314     return isHorizontalFlow() ? child->width() : child->height();
315 }
316
317 LayoutUnit RenderFlexibleBox::crossAxisExtent() const
318 {
319     return isHorizontalFlow() ? height() : width();
320 }
321
322 LayoutUnit RenderFlexibleBox::mainAxisExtent() const
323 {
324     return isHorizontalFlow() ? width() : height();
325 }
326
327 LayoutUnit RenderFlexibleBox::crossAxisContentExtent() const
328 {
329     return isHorizontalFlow() ? contentHeight() : contentWidth();
330 }
331
332 LayoutUnit RenderFlexibleBox::mainAxisContentExtent() const
333 {
334     return isHorizontalFlow() ? contentWidth() : contentHeight();
335 }
336
337 WritingMode RenderFlexibleBox::transformedWritingMode() const
338 {
339     WritingMode mode = style()->writingMode();
340     if (!isColumnFlow())
341         return mode;
342
343     switch (mode) {
344     case TopToBottomWritingMode:
345     case BottomToTopWritingMode:
346         return style()->isLeftToRightDirection() ? LeftToRightWritingMode : RightToLeftWritingMode;
347     case LeftToRightWritingMode:
348     case RightToLeftWritingMode:
349         return style()->isLeftToRightDirection() ? TopToBottomWritingMode : BottomToTopWritingMode;
350     }
351     ASSERT_NOT_REACHED();
352     return TopToBottomWritingMode;
353 }
354
355 LayoutUnit RenderFlexibleBox::flowAwareBorderStart() const
356 {
357     if (isHorizontalFlow())
358         return isLeftToRightFlow() ? borderLeft() : borderRight();
359     return isLeftToRightFlow() ? borderTop() : borderBottom();
360 }
361
362 LayoutUnit RenderFlexibleBox::flowAwareBorderEnd() const
363 {
364     if (isHorizontalFlow())
365         return isLeftToRightFlow() ? borderRight() : borderLeft();
366     return isLeftToRightFlow() ? borderBottom() : borderTop();
367 }
368
369 LayoutUnit RenderFlexibleBox::flowAwareBorderBefore() const
370 {
371     switch (transformedWritingMode()) {
372     case TopToBottomWritingMode:
373         return borderTop();
374     case BottomToTopWritingMode:
375         return borderBottom();
376     case LeftToRightWritingMode:
377         return borderLeft();
378     case RightToLeftWritingMode:
379         return borderRight();
380     }
381     ASSERT_NOT_REACHED();
382     return borderTop();
383 }
384
385 LayoutUnit RenderFlexibleBox::flowAwareBorderAfter() const
386 {
387     switch (transformedWritingMode()) {
388     case TopToBottomWritingMode:
389         return borderBottom();
390     case BottomToTopWritingMode:
391         return borderTop();
392     case LeftToRightWritingMode:
393         return borderRight();
394     case RightToLeftWritingMode:
395         return borderLeft();
396     }
397     ASSERT_NOT_REACHED();
398     return borderTop();
399 }
400
401 LayoutUnit RenderFlexibleBox::flowAwarePaddingStart() const
402 {
403     if (isHorizontalFlow())
404         return isLeftToRightFlow() ? paddingLeft() : paddingRight();
405     return isLeftToRightFlow() ? paddingTop() : paddingBottom();
406 }
407
408 LayoutUnit RenderFlexibleBox::flowAwarePaddingEnd() const
409 {
410     if (isHorizontalFlow())
411         return isLeftToRightFlow() ? paddingRight() : paddingLeft();
412     return isLeftToRightFlow() ? paddingBottom() : paddingTop();
413 }
414
415 LayoutUnit RenderFlexibleBox::flowAwarePaddingBefore() const
416 {
417     switch (transformedWritingMode()) {
418     case TopToBottomWritingMode:
419         return paddingTop();
420     case BottomToTopWritingMode:
421         return paddingBottom();
422     case LeftToRightWritingMode:
423         return paddingLeft();
424     case RightToLeftWritingMode:
425         return paddingRight();
426     }
427     ASSERT_NOT_REACHED();
428     return paddingTop();
429 }
430
431 LayoutUnit RenderFlexibleBox::flowAwarePaddingAfter() const
432 {
433     switch (transformedWritingMode()) {
434     case TopToBottomWritingMode:
435         return paddingBottom();
436     case BottomToTopWritingMode:
437         return paddingTop();
438     case LeftToRightWritingMode:
439         return paddingRight();
440     case RightToLeftWritingMode:
441         return paddingLeft();
442     }
443     ASSERT_NOT_REACHED();
444     return paddingTop();
445 }
446
447 LayoutUnit RenderFlexibleBox::flowAwareMarginStartForChild(RenderBox* child) const
448 {
449     if (isHorizontalFlow())
450         return isLeftToRightFlow() ? child->marginLeft() : child->marginRight();
451     return isLeftToRightFlow() ? child->marginTop() : child->marginBottom();
452 }
453
454 LayoutUnit RenderFlexibleBox::flowAwareMarginEndForChild(RenderBox* child) const
455 {
456     if (isHorizontalFlow())
457         return isLeftToRightFlow() ? child->marginRight() : child->marginLeft();
458     return isLeftToRightFlow() ? child->marginBottom() : child->marginTop();
459 }
460
461 LayoutUnit RenderFlexibleBox::flowAwareMarginBeforeForChild(RenderBox* child) const
462 {
463     switch (transformedWritingMode()) {
464     case TopToBottomWritingMode:
465         return child->marginTop();
466     case BottomToTopWritingMode:
467         return child->marginBottom();
468     case LeftToRightWritingMode:
469         return child->marginLeft();
470     case RightToLeftWritingMode:
471         return child->marginRight();
472     }
473     ASSERT_NOT_REACHED();
474     return marginTop();
475 }
476
477 LayoutUnit RenderFlexibleBox::flowAwareMarginAfterForChild(RenderBox* child) const
478 {
479     switch (transformedWritingMode()) {
480     case TopToBottomWritingMode:
481         return child->marginBottom();
482     case BottomToTopWritingMode:
483         return child->marginTop();
484     case LeftToRightWritingMode:
485         return child->marginRight();
486     case RightToLeftWritingMode:
487         return child->marginLeft();
488     }
489     ASSERT_NOT_REACHED();
490     return marginBottom();
491 }
492
493 LayoutUnit RenderFlexibleBox::crossAxisMarginExtentForChild(RenderBox* child) const
494 {
495     return isHorizontalFlow() ? child->marginHeight() : child->marginWidth();
496 }
497
498 LayoutUnit RenderFlexibleBox::crossAxisScrollbarExtent() const
499 {
500     return isHorizontalFlow() ? horizontalScrollbarHeight() : verticalScrollbarWidth();
501 }
502
503 LayoutPoint RenderFlexibleBox::flowAwareLocationForChild(RenderBox* child) const
504 {
505     return isHorizontalFlow() ? child->location() : child->location().transposedPoint();
506 }
507
508 void RenderFlexibleBox::setFlowAwareLocationForChild(RenderBox* child, const LayoutPoint& location)
509 {
510     if (isHorizontalFlow())
511         child->setLocation(location);
512     else
513         child->setLocation(location.transposedPoint());
514 }
515
516 LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox* child) const
517 {
518     return isHorizontalFlow() ? child->borderAndPaddingWidth() : child->borderAndPaddingHeight();
519 }
520
521 LayoutUnit RenderFlexibleBox::mainAxisScrollbarExtentForChild(RenderBox* child) const
522 {
523     return isHorizontalFlow() ? child->verticalScrollbarWidth() : child->horizontalScrollbarHeight();
524 }
525
526 LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* child) const
527 {
528     Length mainAxisLength = mainAxisLengthForChild(child);
529     if (mainAxisLength.isAuto()) {
530         LayoutUnit mainAxisExtent = hasOrthogonalFlow(child) ? child->logicalHeight() : child->maxPreferredLogicalWidth();
531         return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child) - mainAxisScrollbarExtentForChild(child);
532     }
533     return mainAxisLength.calcMinValue(mainAxisContentExtent());
534 }
535
536 void RenderFlexibleBox::layoutFlexItems(bool relayoutChildren)
537 {
538     FlexOrderHashSet flexOrderValues;
539     computeMainAxisPreferredSizes(relayoutChildren, flexOrderValues);
540
541     OrderedFlexItemList orderedChildren;
542     LayoutUnit preferredMainAxisExtent;
543     float totalPositiveFlexibility;
544     float totalNegativeFlexibility;
545     FlexOrderIterator flexIterator(this, flexOrderValues);
546
547     LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
548     LayoutUnit mainAxisFlexibleSpace = mainAxisContentExtent();
549     while (computeNextFlexLine(flexIterator, orderedChildren, preferredMainAxisExtent, totalPositiveFlexibility, totalNegativeFlexibility)) {
550         LayoutUnit availableFreeSpace = mainAxisFlexibleSpace - preferredMainAxisExtent;
551         InflexibleFlexItemSize inflexibleItems;
552         WTF::Vector<LayoutUnit> childSizes;
553         while (!runFreeSpaceAllocationAlgorithm(orderedChildren, availableFreeSpace, totalPositiveFlexibility, totalNegativeFlexibility, inflexibleItems, childSizes)) {
554             ASSERT(totalPositiveFlexibility >= 0 && totalNegativeFlexibility >= 0);
555             ASSERT(inflexibleItems.size() > 0);
556         }
557
558         layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace);
559     }
560
561     // direction:rtl + flex-direction:column means the cross-axis direction is flipped.
562     flipForRightToLeftColumn(flexIterator);
563 }
564
565 float RenderFlexibleBox::positiveFlexForChild(RenderBox* child) const
566 {
567     return isHorizontalFlow() ? child->style()->flexboxWidthPositiveFlex() : child->style()->flexboxHeightPositiveFlex();
568 }
569
570 float RenderFlexibleBox::negativeFlexForChild(RenderBox* child) const
571 {
572     return isHorizontalFlow() ? child->style()->flexboxWidthNegativeFlex() : child->style()->flexboxHeightNegativeFlex();
573 }
574
575 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox* child)
576 {
577     LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child);
578     return lineCrossAxisExtent - childCrossExtent;
579 }
580
581 LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(RenderBox* child)
582 {
583     LayoutUnit ascent = child->firstLineBoxBaseline();
584     if (ascent == -1)
585         ascent = crossAxisExtentForChild(child) + flowAwareMarginAfterForChild(child);
586     return ascent + flowAwareMarginBeforeForChild(child);
587 }
588
589 void RenderFlexibleBox::computeMainAxisPreferredSizes(bool relayoutChildren, FlexOrderHashSet& flexOrderValues)
590 {
591     LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent();
592     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
593         flexOrderValues.add(child->style()->flexOrder());
594
595         if (child->isPositioned())
596             continue;
597
598         child->clearOverrideSize();
599         if (mainAxisLengthForChild(child).isAuto()) {
600             if (!relayoutChildren)
601                 child->setChildNeedsLayout(true);
602             child->layoutIfNeeded();
603         }
604
605         // We set the margins because we want to make sure 'auto' has a margin
606         // of 0 and because if we're not auto sizing, we don't do a layout that
607         // computes the start/end margins.
608         if (isHorizontalFlow()) {
609             child->setMarginLeft(child->style()->marginLeft().calcMinValue(flexboxAvailableContentExtent));
610             child->setMarginRight(child->style()->marginRight().calcMinValue(flexboxAvailableContentExtent));
611         } else {
612             child->setMarginTop(child->style()->marginTop().calcMinValue(flexboxAvailableContentExtent));
613             child->setMarginBottom(child->style()->marginBottom().calcMinValue(flexboxAvailableContentExtent));
614         }
615     }
616 }
617
618 bool RenderFlexibleBox::computeNextFlexLine(FlexOrderIterator& iterator, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalPositiveFlexibility, float& totalNegativeFlexibility)
619 {
620     orderedChildren.clear();
621     preferredMainAxisExtent = 0;
622     totalPositiveFlexibility = totalNegativeFlexibility = 0;
623
624     if (!iterator.currentChild())
625         return false;
626
627     for (RenderBox* child = iterator.currentChild(); child; child = iterator.next()) {
628         if (child->isPositioned()) {
629             orderedChildren.append(child);
630             continue;
631         }
632
633         LayoutUnit childMainAxisExtent = mainAxisBorderAndPaddingExtentForChild(child) + preferredMainAxisContentExtentForChild(child);
634         if (isHorizontalFlow())
635             childMainAxisExtent += child->marginWidth();
636         else
637             childMainAxisExtent += child->marginHeight();
638
639         if (isMultiline() && preferredMainAxisExtent + childMainAxisExtent > mainAxisContentExtent() && orderedChildren.size() > 0)
640             break;
641         orderedChildren.append(child);
642         preferredMainAxisExtent += childMainAxisExtent;
643         totalPositiveFlexibility += positiveFlexForChild(child);
644         totalNegativeFlexibility += negativeFlexForChild(child);
645     }
646     return true;
647 }
648
649 // Returns true if we successfully ran the algorithm and sized the flex items.
650 bool RenderFlexibleBox::runFreeSpaceAllocationAlgorithm(const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalNegativeFlexibility, InflexibleFlexItemSize& inflexibleItems, WTF::Vector<LayoutUnit>& childSizes)
651 {
652     childSizes.clear();
653
654     LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent();
655     for (size_t i = 0; i < children.size(); ++i) {
656         RenderBox* child = children[i];
657         if (child->isPositioned()) {
658             childSizes.append(0);
659             continue;
660         }
661
662         LayoutUnit childPreferredSize;
663         if (inflexibleItems.contains(child))
664             childPreferredSize = inflexibleItems.get(child);
665         else {
666             childPreferredSize = preferredMainAxisContentExtentForChild(child);
667             if (availableFreeSpace > 0 && totalPositiveFlexibility > 0) {
668                 childPreferredSize += lroundf(availableFreeSpace * positiveFlexForChild(child) / totalPositiveFlexibility);
669
670                 Length childLogicalMaxWidth = isHorizontalFlow() ? child->style()->maxWidth() : child->style()->maxHeight();
671                 if (!childLogicalMaxWidth.isUndefined() && childLogicalMaxWidth.isSpecified() && childPreferredSize > childLogicalMaxWidth.calcValue(flexboxAvailableContentExtent)) {
672                     childPreferredSize = childLogicalMaxWidth.calcValue(flexboxAvailableContentExtent);
673                     availableFreeSpace -= childPreferredSize - preferredMainAxisContentExtentForChild(child);
674                     totalPositiveFlexibility -= positiveFlexForChild(child);
675
676                     inflexibleItems.set(child, childPreferredSize);
677                     return false;
678                 }
679             } else if (availableFreeSpace < 0 && totalNegativeFlexibility > 0) {
680                 childPreferredSize += lroundf(availableFreeSpace * negativeFlexForChild(child) / totalNegativeFlexibility);
681
682                 Length childLogicalMinWidth = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
683                 if (!childLogicalMinWidth.isUndefined() && childLogicalMinWidth.isSpecified() && childPreferredSize < childLogicalMinWidth.calcValue(flexboxAvailableContentExtent)) {
684                     childPreferredSize = childLogicalMinWidth.calcValue(flexboxAvailableContentExtent);
685                     availableFreeSpace += preferredMainAxisContentExtentForChild(child) - childPreferredSize;
686                     totalNegativeFlexibility -= negativeFlexForChild(child);
687
688                     inflexibleItems.set(child, childPreferredSize);
689                     return false;
690                 }
691             }
692         }
693         childSizes.append(childPreferredSize);
694     }
695     return true;
696 }
697
698 static LayoutUnit initialPackingOffset(LayoutUnit availableFreeSpace, EFlexPack flexPack, size_t numberOfChildren)
699 {
700     if (availableFreeSpace > 0) {
701         if (flexPack == PackEnd)
702             return availableFreeSpace;
703         if (flexPack == PackCenter)
704             return availableFreeSpace / 2;
705         if (flexPack == PackDistribute && numberOfChildren)
706             return availableFreeSpace / (2 * numberOfChildren);
707     } else if (availableFreeSpace < 0) {
708         if (flexPack == PackCenter || flexPack == PackDistribute)
709             return availableFreeSpace / 2;
710     }
711     return 0;
712 }
713
714 static LayoutUnit packingSpaceBetweenChildren(LayoutUnit availableFreeSpace, EFlexPack flexPack, size_t numberOfChildren)
715 {
716     if (availableFreeSpace > 0 && numberOfChildren > 1) {
717         if (flexPack == PackJustify)
718             return availableFreeSpace / (numberOfChildren - 1);
719         if (flexPack == PackDistribute)
720             return availableFreeSpace / numberOfChildren;
721     }
722     return 0;
723 }
724
725 void RenderFlexibleBox::setLogicalOverrideSize(RenderBox* child, LayoutUnit childPreferredSize)
726 {
727     // FIXME: Rename setOverrideWidth/setOverrideHeight to setOverrideLogicalWidth/setOverrideLogicalHeight.
728     if (hasOrthogonalFlow(child))
729         child->setOverrideHeight(childPreferredSize);
730     else
731         child->setOverrideWidth(childPreferredSize);
732 }
733
734 void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox* child, LayoutUnit mainAxisOffset, LayoutUnit crossAxisOffset)
735 {
736     ASSERT(child->isPositioned());
737     child->containingBlock()->insertPositionedObject(child);
738     RenderLayer* childLayer = child->layer();
739     LayoutUnit inlinePosition = isColumnFlow() ? crossAxisOffset : mainAxisOffset;
740     if (style()->flexDirection() == FlowRowReverse)
741         inlinePosition = mainAxisExtent() - mainAxisOffset;
742     childLayer->setStaticInlinePosition(inlinePosition); // FIXME: Not right for regions.
743
744     LayoutUnit staticBlockPosition = isColumnFlow() ? mainAxisOffset : crossAxisOffset;
745     if (childLayer->staticBlockPosition() != staticBlockPosition) {
746         childLayer->setStaticBlockPosition(staticBlockPosition);
747         if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
748             child->setChildNeedsLayout(true, false);
749     }
750 }
751
752 static EFlexAlign flexAlignForChild(RenderBox* child)
753 {
754     EFlexAlign align = child->style()->flexItemAlign();
755     if (align == AlignAuto)
756         return child->parent()->style()->flexAlign();
757     return align;
758 }
759
760 void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace)
761 {
762     LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart();
763     mainAxisOffset += initialPackingOffset(availableFreeSpace, style()->flexPack(), childSizes.size());
764     if (style()->flexDirection() == FlowRowReverse)
765         mainAxisOffset += isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
766
767     LayoutUnit totalMainExtent = mainAxisExtent();
768     LayoutUnit maxAscent = 0, maxDescent = 0; // Used when flex-align: baseline.
769     LayoutUnit maxChildCrossAxisExtent = 0;
770     bool shouldFlipMainAxis = !isColumnFlow() && !isLeftToRightFlow();
771     for (size_t i = 0; i < children.size(); ++i) {
772         RenderBox* child = children[i];
773         if (child->isPositioned()) {
774             prepareChildForPositionedLayout(child, mainAxisOffset, crossAxisOffset);
775             mainAxisOffset += packingSpaceBetweenChildren(availableFreeSpace, style()->flexPack(), childSizes.size());
776             continue;
777         }
778         LayoutUnit childPreferredSize = childSizes[i] + mainAxisBorderAndPaddingExtentForChild(child);
779         setLogicalOverrideSize(child, childPreferredSize);
780         child->setChildNeedsLayout(true);
781         child->layoutIfNeeded();
782
783         LayoutUnit childCrossAxisExtent;
784         if (flexAlignForChild(child) == AlignBaseline) {
785             LayoutUnit ascent = marginBoxAscentForChild(child);
786             LayoutUnit descent = (crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child)) - ascent;
787
788             maxAscent = std::max(maxAscent, ascent);
789             maxDescent = std::max(maxDescent, descent);
790
791             childCrossAxisExtent = maxAscent + maxDescent;
792         } else
793             childCrossAxisExtent =  crossAxisExtentForChild(child);
794         if (crossAxisLength().isAuto())
795             setCrossAxisExtent(std::max(crossAxisExtent(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + crossAxisMarginExtentForChild(child) + childCrossAxisExtent + crossAxisScrollbarExtent()));
796         maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisExtent + crossAxisMarginExtentForChild(child));
797
798         mainAxisOffset += flowAwareMarginStartForChild(child);
799
800         LayoutUnit childMainExtent = mainAxisExtentForChild(child);
801         IntPoint childLocation(shouldFlipMainAxis ? totalMainExtent - mainAxisOffset - childMainExtent : mainAxisOffset,
802             crossAxisOffset + flowAwareMarginBeforeForChild(child));
803
804         // FIXME: Supporting layout deltas.
805         setFlowAwareLocationForChild(child, childLocation);
806         mainAxisOffset += childMainExtent + flowAwareMarginEndForChild(child);
807
808         mainAxisOffset += packingSpaceBetweenChildren(availableFreeSpace, style()->flexPack(), childSizes.size());
809     }
810
811     if (isColumnFlow())
812         setLogicalHeight(mainAxisOffset + flowAwareBorderEnd() + flowAwarePaddingEnd() + scrollbarLogicalHeight());
813
814     if (style()->flexDirection() == FlowColumnReverse) {
815         // We have to do an extra pass for column-reverse to reposition the flex items since the start depends
816         // on the height of the flexbox, which we only know after we've positioned all the flex items.
817         computeLogicalHeight();
818         layoutColumnReverse(children, childSizes, crossAxisOffset, availableFreeSpace);
819     }
820
821     LayoutUnit lineCrossAxisExtent = isMultiline() ? maxChildCrossAxisExtent : crossAxisContentExtent();
822     alignChildren(children, lineCrossAxisExtent, maxAscent);
823
824     crossAxisOffset += lineCrossAxisExtent;
825 }
826
827 void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace)
828 {
829     // This is similar to the logic in layoutAndPlaceChildren, except we place the children
830     // starting from the end of the flexbox. We also don't need to layout anything since we're
831     // just moving the children to a new position.
832     LayoutUnit mainAxisOffset = logicalHeight() - flowAwareBorderEnd() - flowAwarePaddingEnd();
833     mainAxisOffset -= initialPackingOffset(availableFreeSpace, style()->flexPack(), childSizes.size());
834     mainAxisOffset -= isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
835
836     for (size_t i = 0; i < children.size(); ++i) {
837         RenderBox* child = children[i];
838         if (child->isPositioned()) {
839             child->layer()->setStaticBlockPosition(mainAxisOffset);
840             mainAxisOffset -= packingSpaceBetweenChildren(availableFreeSpace, style()->flexPack(), childSizes.size());
841             continue;
842         }
843         mainAxisOffset -= mainAxisExtentForChild(child) + flowAwareMarginEndForChild(child);
844
845         LayoutRect oldRect = child->frameRect();
846         setFlowAwareLocationForChild(child, IntPoint(mainAxisOffset, crossAxisOffset + flowAwareMarginBeforeForChild(child)));
847         if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
848             child->repaintDuringLayoutIfMoved(oldRect);
849
850         mainAxisOffset -= flowAwareMarginStartForChild(child);
851         mainAxisOffset -= packingSpaceBetweenChildren(availableFreeSpace, style()->flexPack(), childSizes.size());
852     }
853 }
854
855 void RenderFlexibleBox::adjustAlignmentForChild(RenderBox* child, LayoutUnit delta)
856 {
857     LayoutRect oldRect = child->frameRect();
858
859     setFlowAwareLocationForChild(child, flowAwareLocationForChild(child) + LayoutSize(0, delta));
860
861     // If the child moved, we have to repaint it as well as any floating/positioned
862     // descendants. An exception is if we need a layout. In this case, we know we're going to
863     // repaint ourselves (and the child) anyway.
864     if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
865         child->repaintDuringLayoutIfMoved(oldRect);
866 }
867
868 void RenderFlexibleBox::alignChildren(const OrderedFlexItemList& children, LayoutUnit lineCrossAxisExtent, LayoutUnit maxAscent)
869 {
870     for (size_t i = 0; i < children.size(); ++i) {
871         RenderBox* child = children[i];
872         switch (flexAlignForChild(child)) {
873         case AlignAuto:
874             ASSERT_NOT_REACHED();
875             break;
876         case AlignStretch: {
877             if (!isColumnFlow() && child->style()->logicalHeight().isAuto()) {
878                 LayoutUnit logicalHeightBefore = child->logicalHeight();
879                 LayoutUnit stretchedLogicalHeight = child->logicalHeight() + availableAlignmentSpaceForChild(lineCrossAxisExtent, child);
880                 child->setLogicalHeight(stretchedLogicalHeight);
881                 child->computeLogicalHeight();
882
883                 if (child->logicalHeight() != logicalHeightBefore) {
884                     child->setOverrideHeight(child->logicalHeight());
885                     child->setLogicalHeight(0);
886                     child->setChildNeedsLayout(true);
887                     child->layoutIfNeeded();
888                 }
889             } else if (isColumnFlow() && child->style()->logicalWidth().isAuto() && isMultiline()) {
890                 // FIXME: Handle min-width and max-width.
891                 LayoutUnit childWidth = lineCrossAxisExtent - crossAxisMarginExtentForChild(child);
892                 child->setOverrideWidth(std::max(0, childWidth));
893                 child->setChildNeedsLayout(true);
894                 child->layoutIfNeeded();
895             }
896             break;
897         }
898         case AlignStart:
899             break;
900         case AlignEnd:
901             adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
902             break;
903         case AlignCenter:
904             adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) / 2);
905             break;
906         case AlignBaseline: {
907             LayoutUnit ascent = marginBoxAscentForChild(child);
908             adjustAlignmentForChild(child, maxAscent - ascent);
909             break;
910         }
911         }
912     }
913 }
914
915 void RenderFlexibleBox::flipForRightToLeftColumn(FlexOrderIterator& iterator)
916 {
917     if (style()->isLeftToRightDirection() || !isColumnFlow())
918         return;
919
920     LayoutUnit crossExtent = crossAxisExtent();
921     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
922         LayoutPoint location = flowAwareLocationForChild(child);
923         location.setY(crossExtent - crossAxisExtentForChild(child) - location.y());
924         setFlowAwareLocationForChild(child, location);
925     }
926 }
927
928 }