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