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