Need to implement flex-flow: row-reverse
[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()->isColumnFlexFlow();
207 }
208
209 bool RenderFlexibleBox::isReverseFlow() const
210 {
211     return style()->flexFlow() == FlowColumnReverse || style()->flexFlow() == FlowRowReverse;
212 }
213
214 bool RenderFlexibleBox::isHorizontalFlow() const
215 {
216     if (isHorizontalWritingMode())
217         return !isColumnFlow();
218     return isColumnFlow();
219 }
220
221 bool RenderFlexibleBox::isLeftToRightFlow() const
222 {
223     if (isColumnFlow())
224         return style()->writingMode() == TopToBottomWritingMode || style()->writingMode() == LeftToRightWritingMode;
225     return style()->isLeftToRightDirection() ^ isReverseFlow();
226 }
227
228 Length RenderFlexibleBox::mainAxisLengthForChild(RenderBox* child) const
229 {
230     return isHorizontalFlow() ? child->style()->width() : child->style()->height();
231 }
232
233 Length RenderFlexibleBox::crossAxisLength() const
234 {
235     return isHorizontalFlow() ? style()->height() : style()->width();
236 }
237
238 void RenderFlexibleBox::setCrossAxisExtent(LayoutUnit extent)
239 {
240     if (isHorizontalFlow())
241         setHeight(extent);
242     else
243         setWidth(extent);
244 }
245
246 LayoutUnit RenderFlexibleBox::crossAxisExtentForChild(RenderBox* child)
247 {
248     return isHorizontalFlow() ? child->height() : child->width();
249 }
250
251 LayoutUnit RenderFlexibleBox::mainAxisExtentForChild(RenderBox* child)
252 {
253     return isHorizontalFlow() ? child->width() : child->height();
254 }
255
256 LayoutUnit RenderFlexibleBox::crossAxisExtent() const
257 {
258     return isHorizontalFlow() ? height() : width();
259 }
260
261 LayoutUnit RenderFlexibleBox::mainAxisExtent() const
262 {
263     return isHorizontalFlow() ? width() : height();
264 }
265
266 LayoutUnit RenderFlexibleBox::crossAxisContentExtent() const
267 {
268     return isHorizontalFlow() ? contentHeight() : contentWidth();
269 }
270
271 LayoutUnit RenderFlexibleBox::mainAxisContentExtent() const
272 {
273     return isHorizontalFlow() ? contentWidth() : contentHeight();
274 }
275
276 WritingMode RenderFlexibleBox::transformedWritingMode() const
277 {
278     WritingMode mode = style()->writingMode();
279     if (!isColumnFlow())
280         return mode;
281
282     switch (mode) {
283     case TopToBottomWritingMode:
284     case BottomToTopWritingMode:
285         return style()->isLeftToRightDirection() ? LeftToRightWritingMode : RightToLeftWritingMode;
286     case LeftToRightWritingMode:
287     case RightToLeftWritingMode:
288         return style()->isLeftToRightDirection() ? TopToBottomWritingMode : BottomToTopWritingMode;
289     }
290     ASSERT_NOT_REACHED();
291     return TopToBottomWritingMode;
292 }
293
294 LayoutUnit RenderFlexibleBox::flowAwareBorderStart() const
295 {
296     if (isHorizontalFlow())
297         return isLeftToRightFlow() ? borderLeft() : borderRight();
298     return isLeftToRightFlow() ? borderTop() : borderBottom();
299 }
300
301 LayoutUnit RenderFlexibleBox::flowAwareBorderBefore() const
302 {
303     switch (transformedWritingMode()) {
304     case TopToBottomWritingMode:
305         return borderTop();
306     case BottomToTopWritingMode:
307         return borderBottom();
308     case LeftToRightWritingMode:
309         return borderLeft();
310     case RightToLeftWritingMode:
311         return borderRight();
312     }
313     ASSERT_NOT_REACHED();
314     return borderTop();
315 }
316
317 LayoutUnit RenderFlexibleBox::crossAxisBorderAndPaddingExtent() const
318 {
319     return isHorizontalFlow() ? borderAndPaddingHeight() : borderAndPaddingWidth();
320 }
321
322 LayoutUnit RenderFlexibleBox::flowAwarePaddingStart() const
323 {
324     if (isHorizontalFlow())
325         return isLeftToRightFlow() ? paddingLeft() : paddingRight();
326     return isLeftToRightFlow() ? paddingTop() : paddingBottom();
327 }
328
329 LayoutUnit RenderFlexibleBox::flowAwarePaddingBefore() const
330 {
331     switch (transformedWritingMode()) {
332     case TopToBottomWritingMode:
333         return paddingTop();
334     case BottomToTopWritingMode:
335         return paddingBottom();
336     case LeftToRightWritingMode:
337         return paddingLeft();
338     case RightToLeftWritingMode:
339         return paddingRight();
340     }
341     ASSERT_NOT_REACHED();
342     return paddingTop();
343 }
344
345 LayoutUnit RenderFlexibleBox::flowAwareMarginStartForChild(RenderBox* child) const
346 {
347     if (isHorizontalFlow())
348         return isLeftToRightFlow() ? child->marginLeft() : child->marginRight();
349     return isLeftToRightFlow() ? child->marginTop() : child->marginBottom();
350 }
351
352 LayoutUnit RenderFlexibleBox::flowAwareMarginEndForChild(RenderBox* child) const
353 {
354     if (isHorizontalFlow())
355         return isLeftToRightFlow() ? child->marginRight() : child->marginLeft();
356     return isLeftToRightFlow() ? child->marginBottom() : child->marginTop();
357 }
358
359 LayoutUnit RenderFlexibleBox::flowAwareMarginBeforeForChild(RenderBox* child) const
360 {
361     switch (transformedWritingMode()) {
362     case TopToBottomWritingMode:
363         return child->marginTop();
364     case BottomToTopWritingMode:
365         return child->marginBottom();
366     case LeftToRightWritingMode:
367         return child->marginLeft();
368     case RightToLeftWritingMode:
369         return child->marginRight();
370     }
371     ASSERT_NOT_REACHED();
372     return marginTop();
373 }
374
375 LayoutUnit RenderFlexibleBox::flowAwareMarginAfterForChild(RenderBox* child) const
376 {
377     switch (transformedWritingMode()) {
378     case TopToBottomWritingMode:
379         return child->marginBottom();
380     case BottomToTopWritingMode:
381         return child->marginTop();
382     case LeftToRightWritingMode:
383         return child->marginRight();
384     case RightToLeftWritingMode:
385         return child->marginLeft();
386     }
387     ASSERT_NOT_REACHED();
388     return marginBottom();
389 }
390
391 LayoutUnit RenderFlexibleBox::crossAxisMarginExtentForChild(RenderBox* child) const
392 {
393     return isHorizontalFlow() ? child->marginTop() + child->marginBottom() : child->marginLeft() + child->marginRight();
394 }
395
396 LayoutPoint RenderFlexibleBox::flowAwareLocationForChild(RenderBox* child) const
397 {
398     return isHorizontalFlow() ? child->location() : child->location().transposedPoint();
399 }
400
401 void RenderFlexibleBox::setFlowAwareLocationForChild(RenderBox* child, const LayoutPoint& location)
402 {
403     if (isHorizontalFlow())
404         child->setLocation(location);
405     else
406         child->setLocation(location.transposedPoint());
407 }
408
409 LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox* child) const
410 {
411     return isHorizontalFlow() ? child->borderAndPaddingWidth() : child->borderAndPaddingHeight();
412 }
413
414 LayoutUnit RenderFlexibleBox::mainAxisScrollbarExtentForChild(RenderBox* child) const
415 {
416     return isHorizontalFlow() ? child->verticalScrollbarWidth() : child->horizontalScrollbarHeight();
417 }
418
419 LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForFlexItem(RenderBox* child) const
420 {
421     Length mainAxisLength = mainAxisLengthForChild(child);
422     if (mainAxisLength.isAuto()) {
423         LayoutUnit mainAxisExtent = hasOrthogonalFlow(child) ? child->logicalHeight() : child->maxPreferredLogicalWidth();
424         return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child) - mainAxisScrollbarExtentForChild(child);
425     }
426     return mainAxisLength.calcMinValue(mainAxisContentExtent());
427 }
428
429 void RenderFlexibleBox::layoutFlexItems(bool relayoutChildren)
430 {
431     LayoutUnit preferredMainAxisExtent;
432     float totalPositiveFlexibility;
433     float totalNegativeFlexibility;
434     TreeOrderIterator treeIterator(this);
435
436     computePreferredMainAxisExtent(relayoutChildren, treeIterator, preferredMainAxisExtent, totalPositiveFlexibility, totalNegativeFlexibility);
437     LayoutUnit availableFreeSpace = mainAxisContentExtent() - preferredMainAxisExtent;
438
439     FlexOrderIterator flexIterator(this, treeIterator.flexOrderValues());
440     InflexibleFlexItemSize inflexibleItems;
441     WTF::Vector<LayoutUnit> childSizes;
442     while (!runFreeSpaceAllocationAlgorithm(flexIterator, availableFreeSpace, totalPositiveFlexibility, totalNegativeFlexibility, inflexibleItems, childSizes)) {
443         ASSERT(totalPositiveFlexibility >= 0 && totalNegativeFlexibility >= 0);
444         ASSERT(inflexibleItems.size() > 0);
445     }
446
447     layoutAndPlaceChildren(flexIterator, childSizes, availableFreeSpace, totalPositiveFlexibility);
448 }
449
450 float RenderFlexibleBox::positiveFlexForChild(RenderBox* child) const
451 {
452     return isHorizontalFlow() ? child->style()->flexboxWidthPositiveFlex() : child->style()->flexboxHeightPositiveFlex();
453 }
454
455 float RenderFlexibleBox::negativeFlexForChild(RenderBox* child) const
456 {
457     return isHorizontalFlow() ? child->style()->flexboxWidthNegativeFlex() : child->style()->flexboxHeightNegativeFlex();
458 }
459
460 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(RenderBox* child)
461 {
462     LayoutUnit crossContentExtent = crossAxisContentExtent();
463     LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child);
464     return crossContentExtent - childCrossExtent;
465 }
466
467 LayoutUnit RenderFlexibleBox::marginBoxAscent(RenderBox* child)
468 {
469     LayoutUnit ascent = child->firstLineBoxBaseline();
470     if (ascent == -1)
471         ascent = crossAxisExtentForChild(child) + flowAwareMarginAfterForChild(child);
472     return ascent + flowAwareMarginBeforeForChild(child);
473 }
474
475 void RenderFlexibleBox::computePreferredMainAxisExtent(bool relayoutChildren, TreeOrderIterator& iterator, LayoutUnit& preferredMainAxisExtent, float& totalPositiveFlexibility, float& totalNegativeFlexibility)
476 {
477     preferredMainAxisExtent = 0;
478     totalPositiveFlexibility = totalNegativeFlexibility = 0;
479
480     LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent();
481     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
482         if (mainAxisLengthForChild(child).isAuto()) {
483             child->clearOverrideSize();
484             if (!relayoutChildren)
485                 child->setChildNeedsLayout(true);
486             child->layoutIfNeeded();
487         }
488
489         // We set the margins because we want to make sure 'auto' has a margin
490         // of 0 and because if we're not auto sizing, we don't do a layout that
491         // computes the start/end margins.
492         if (isHorizontalFlow()) {
493             child->setMarginLeft(child->style()->marginLeft().calcMinValue(flexboxAvailableContentExtent));
494             child->setMarginRight(child->style()->marginRight().calcMinValue(flexboxAvailableContentExtent));
495             preferredMainAxisExtent += child->marginLeft() + child->marginRight();
496         } else {
497             child->setMarginTop(child->style()->marginTop().calcMinValue(flexboxAvailableContentExtent));
498             child->setMarginBottom(child->style()->marginBottom().calcMinValue(flexboxAvailableContentExtent));
499             preferredMainAxisExtent += child->marginTop() + child->marginBottom();
500         }
501
502         preferredMainAxisExtent += mainAxisBorderAndPaddingExtentForChild(child);
503         preferredMainAxisExtent += preferredMainAxisContentExtentForFlexItem(child);
504
505         totalPositiveFlexibility += positiveFlexForChild(child);
506         totalNegativeFlexibility += negativeFlexForChild(child);
507     }
508 }
509
510 // Returns true if we successfully ran the algorithm and sized the flex items.
511 bool RenderFlexibleBox::runFreeSpaceAllocationAlgorithm(FlexOrderIterator& iterator, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalNegativeFlexibility, InflexibleFlexItemSize& inflexibleItems, WTF::Vector<LayoutUnit>& childSizes)
512 {
513     childSizes.clear();
514
515     LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent();
516     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
517         LayoutUnit childPreferredSize;
518         if (inflexibleItems.contains(child))
519             childPreferredSize = inflexibleItems.get(child);
520         else {
521             childPreferredSize = preferredMainAxisContentExtentForFlexItem(child);
522             if (availableFreeSpace > 0 && totalPositiveFlexibility > 0) {
523                 childPreferredSize += lroundf(availableFreeSpace * positiveFlexForChild(child) / totalPositiveFlexibility);
524
525                 Length childLogicalMaxWidth = isHorizontalFlow() ? child->style()->maxWidth() : child->style()->maxHeight();
526                 if (!childLogicalMaxWidth.isUndefined() && childLogicalMaxWidth.isSpecified() && childPreferredSize > childLogicalMaxWidth.calcValue(flexboxAvailableContentExtent)) {
527                     childPreferredSize = childLogicalMaxWidth.calcValue(flexboxAvailableContentExtent);
528                     availableFreeSpace -= childPreferredSize - preferredMainAxisContentExtentForFlexItem(child);
529                     totalPositiveFlexibility -= positiveFlexForChild(child);
530
531                     inflexibleItems.set(child, childPreferredSize);
532                     return false;
533                 }
534             } else if (availableFreeSpace < 0 && totalNegativeFlexibility > 0) {
535                 childPreferredSize += lroundf(availableFreeSpace * negativeFlexForChild(child) / totalNegativeFlexibility);
536
537                 Length childLogicalMinWidth = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
538                 if (!childLogicalMinWidth.isUndefined() && childLogicalMinWidth.isSpecified() && childPreferredSize < childLogicalMinWidth.calcValue(flexboxAvailableContentExtent)) {
539                     childPreferredSize = childLogicalMinWidth.calcValue(flexboxAvailableContentExtent);
540                     availableFreeSpace += preferredMainAxisContentExtentForFlexItem(child) - childPreferredSize;
541                     totalNegativeFlexibility -= negativeFlexForChild(child);
542
543                     inflexibleItems.set(child, childPreferredSize);
544                     return false;
545                 }
546             }
547         }
548         childSizes.append(childPreferredSize);
549     }
550     return true;
551 }
552
553 static bool hasPackingSpace(LayoutUnit availableFreeSpace, float totalPositiveFlexibility)
554 {
555     return availableFreeSpace > 0 && !totalPositiveFlexibility;
556 }
557
558 void RenderFlexibleBox::setLogicalOverrideSize(RenderBox* child, LayoutUnit childPreferredSize)
559 {
560     // FIXME: Rename setOverrideWidth/setOverrideHeight to setOverrideLogicalWidth/setOverrideLogicalHeight.
561     if (hasOrthogonalFlow(child))
562         child->setOverrideHeight(childPreferredSize);
563     else
564         child->setOverrideWidth(childPreferredSize);
565 }
566
567 void RenderFlexibleBox::layoutAndPlaceChildren(FlexOrderIterator& iterator, const WTF::Vector<LayoutUnit>& childSizes, LayoutUnit availableFreeSpace, float totalPositiveFlexibility)
568 {
569     LayoutUnit startEdge = flowAwareBorderStart() + flowAwarePaddingStart();
570
571     if (hasPackingSpace(availableFreeSpace, totalPositiveFlexibility)) {
572         if (style()->flexPack() == PackEnd)
573             startEdge += availableFreeSpace;
574         else if (style()->flexPack() == PackCenter)
575             startEdge += availableFreeSpace / 2;
576     }
577
578     LayoutUnit logicalTop = flowAwareBorderBefore() + flowAwarePaddingBefore();
579     LayoutUnit totalMainExtent = mainAxisExtent();
580     LayoutUnit maxAscent = 0, maxDescent = 0; // Used when flex-align: baseline.
581     size_t i = 0;
582     for (RenderBox* child = iterator.first(); child; child = iterator.next(), ++i) {
583         LayoutUnit childPreferredSize = childSizes[i] + mainAxisBorderAndPaddingExtentForChild(child);
584         setLogicalOverrideSize(child, childPreferredSize);
585         child->setChildNeedsLayout(true);
586         child->layoutIfNeeded();
587
588         if (child->style()->flexAlign() == AlignBaseline) {
589             LayoutUnit ascent = marginBoxAscent(child);
590             LayoutUnit descent = (crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child)) - ascent;
591
592             maxAscent = std::max(maxAscent, ascent);
593             maxDescent = std::max(maxDescent, descent);
594
595             // FIXME: add flowAwareScrollbarLogicalHeight.
596             if (crossAxisLength().isAuto())
597                 setCrossAxisExtent(std::max(crossAxisExtent(), crossAxisBorderAndPaddingExtent() + crossAxisMarginExtentForChild(child) + maxAscent + maxDescent + scrollbarLogicalHeight()));
598         } else if (crossAxisLength().isAuto())
599             setCrossAxisExtent(std::max(crossAxisExtent(), crossAxisBorderAndPaddingExtent() + crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child) + scrollbarLogicalHeight()));
600
601         startEdge += flowAwareMarginStartForChild(child);
602
603         LayoutUnit childMainExtent = mainAxisExtentForChild(child);
604         bool shouldFlipMainAxis = !isColumnFlow() && !isLeftToRightFlow();
605         LayoutUnit logicalLeft = shouldFlipMainAxis ? totalMainExtent - startEdge - childMainExtent : startEdge;
606
607         // FIXME: Supporting layout deltas.
608         setFlowAwareLocationForChild(child, IntPoint(logicalLeft, logicalTop + flowAwareMarginBeforeForChild(child)));
609         startEdge += childMainExtent + flowAwareMarginEndForChild(child);
610
611         if (hasPackingSpace(availableFreeSpace, totalPositiveFlexibility) && style()->flexPack() == PackJustify && childSizes.size() > 1)
612             startEdge += availableFreeSpace / (childSizes.size() - 1);
613
614         if (isColumnFlow())
615             setLogicalHeight(startEdge);
616     }
617     alignChildren(iterator, maxAscent);
618 }
619
620 void RenderFlexibleBox::adjustAlignmentForChild(RenderBox* child, LayoutUnit delta)
621 {
622     LayoutRect oldRect = child->frameRect();
623
624     setFlowAwareLocationForChild(child, flowAwareLocationForChild(child) + LayoutSize(0, delta));
625
626     // If the child moved, we have to repaint it as well as any floating/positioned
627     // descendants. An exception is if we need a layout. In this case, we know we're going to
628     // repaint ourselves (and the child) anyway.
629     if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
630         child->repaintDuringLayoutIfMoved(oldRect);
631 }
632
633 void RenderFlexibleBox::alignChildren(FlexOrderIterator& iterator, LayoutUnit maxAscent)
634 {
635     LayoutUnit crossExtent = crossAxisExtent();
636
637     for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
638         // direction:rtl + flex-flow:column means the cross-axis direction is flipped.
639         if (!style()->isLeftToRightDirection() && isColumnFlow()) {
640             LayoutPoint location = flowAwareLocationForChild(child);
641             location.setY(crossExtent - crossAxisExtentForChild(child) - location.y());
642             setFlowAwareLocationForChild(child, location);
643         }
644
645         // FIXME: Make sure this does the right thing with column flows.
646         switch (child->style()->flexAlign()) {
647         case AlignStretch: {
648             if (!isColumnFlow() && child->style()->logicalHeight().isAuto()) {
649                 LayoutUnit stretchedLogicalHeight = child->logicalHeight() + RenderFlexibleBox::availableAlignmentSpaceForChild(child);
650                 child->setLogicalHeight(stretchedLogicalHeight);
651                 child->computeLogicalHeight();
652                 // FIXME: We need to relayout if the height changed.
653             }
654             break;
655         }
656         case AlignStart:
657             break;
658         case AlignEnd:
659             adjustAlignmentForChild(child, RenderFlexibleBox::availableAlignmentSpaceForChild(child));
660             break;
661         case AlignCenter:
662             adjustAlignmentForChild(child, RenderFlexibleBox::availableAlignmentSpaceForChild(child) / 2);
663             break;
664         case AlignBaseline: {
665             LayoutUnit ascent = marginBoxAscent(child);
666             adjustAlignmentForChild(child, maxAscent - ascent);
667             break;
668         }
669         }
670     }
671 }
672
673 }