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