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