• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "core/rendering/RenderFlexibleBox.h"
33 
34 #include "core/rendering/FastTextAutosizer.h"
35 #include "core/rendering/LayoutRepainter.h"
36 #include "core/rendering/RenderLayer.h"
37 #include "core/rendering/RenderView.h"
38 #include "platform/LengthFunctions.h"
39 #include "wtf/MathExtras.h"
40 #include <limits>
41 
42 namespace WebCore {
43 
44 struct RenderFlexibleBox::LineContext {
LineContextWebCore::RenderFlexibleBox::LineContext45     LineContext(LayoutUnit crossAxisOffset, LayoutUnit crossAxisExtent, size_t numberOfChildren, LayoutUnit maxAscent)
46         : crossAxisOffset(crossAxisOffset)
47         , crossAxisExtent(crossAxisExtent)
48         , numberOfChildren(numberOfChildren)
49         , maxAscent(maxAscent)
50     {
51     }
52 
53     LayoutUnit crossAxisOffset;
54     LayoutUnit crossAxisExtent;
55     size_t numberOfChildren;
56     LayoutUnit maxAscent;
57 };
58 
59 struct RenderFlexibleBox::Violation {
ViolationWebCore::RenderFlexibleBox::Violation60     Violation(RenderBox* child, LayoutUnit childSize)
61         : child(child)
62         , childSize(childSize)
63     {
64     }
65 
66     RenderBox* child;
67     LayoutUnit childSize;
68 };
69 
70 
RenderFlexibleBox(Element * element)71 RenderFlexibleBox::RenderFlexibleBox(Element* element)
72     : RenderBlock(element)
73     , m_orderIterator(this)
74     , m_numberOfInFlowChildrenOnFirstLine(-1)
75 {
76     setChildrenInline(false); // All of our children must be block-level.
77 }
78 
~RenderFlexibleBox()79 RenderFlexibleBox::~RenderFlexibleBox()
80 {
81 }
82 
createAnonymous(Document * document)83 RenderFlexibleBox* RenderFlexibleBox::createAnonymous(Document* document)
84 {
85     RenderFlexibleBox* renderer = new RenderFlexibleBox(0);
86     renderer->setDocumentForAnonymous(document);
87     return renderer;
88 }
89 
renderName() const90 const char* RenderFlexibleBox::renderName() const
91 {
92     return "RenderFlexibleBox";
93 }
94 
computeIntrinsicLogicalWidths(LayoutUnit & minLogicalWidth,LayoutUnit & maxLogicalWidth) const95 void RenderFlexibleBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
96 {
97     // FIXME: We're ignoring flex-basis here and we shouldn't. We can't start honoring it though until
98     // the flex shorthand stops setting it to 0.
99     // See https://bugs.webkit.org/show_bug.cgi?id=116117 and http://crbug.com/240765.
100     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
101         if (child->isOutOfFlowPositioned())
102             continue;
103 
104         LayoutUnit margin = marginIntrinsicLogicalWidthForChild(child);
105         bool hasOrthogonalWritingMode = child->isHorizontalWritingMode() != isHorizontalWritingMode();
106         LayoutUnit minPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->minPreferredLogicalWidth();
107         LayoutUnit maxPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->maxPreferredLogicalWidth();
108         minPreferredLogicalWidth += margin;
109         maxPreferredLogicalWidth += margin;
110         if (!isColumnFlow()) {
111             maxLogicalWidth += maxPreferredLogicalWidth;
112             if (isMultiline()) {
113                 // For multiline, the min preferred width is if you put a break between each item.
114                 minLogicalWidth = std::max(minLogicalWidth, minPreferredLogicalWidth);
115             } else
116                 minLogicalWidth += minPreferredLogicalWidth;
117         } else {
118             minLogicalWidth = std::max(minPreferredLogicalWidth, minLogicalWidth);
119             if (isMultiline()) {
120                 // For multiline, the max preferred width is if you never break between items.
121                 maxLogicalWidth += maxPreferredLogicalWidth;
122             } else
123                 maxLogicalWidth = std::max(maxPreferredLogicalWidth, maxLogicalWidth);
124         }
125     }
126 
127     maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
128 
129     LayoutUnit scrollbarWidth = instrinsicScrollbarLogicalWidth();
130     maxLogicalWidth += scrollbarWidth;
131     minLogicalWidth += scrollbarWidth;
132 }
133 
synthesizedBaselineFromContentBox(const RenderBox * box,LineDirectionMode direction)134 static int synthesizedBaselineFromContentBox(const RenderBox* box, LineDirectionMode direction)
135 {
136     return direction == HorizontalLine ? box->borderTop() + box->paddingTop() + box->contentHeight() : box->borderRight() + box->paddingRight() + box->contentWidth();
137 }
138 
baselinePosition(FontBaseline,bool,LineDirectionMode direction,LinePositionMode mode) const139 int RenderFlexibleBox::baselinePosition(FontBaseline, bool, LineDirectionMode direction, LinePositionMode mode) const
140 {
141     ASSERT(mode == PositionOnContainingLine);
142     int baseline = firstLineBoxBaseline();
143     if (baseline == -1)
144         baseline = synthesizedBaselineFromContentBox(this, direction);
145 
146     return beforeMarginInLineDirection(direction) + baseline;
147 }
148 
firstLineBoxBaseline() const149 int RenderFlexibleBox::firstLineBoxBaseline() const
150 {
151     if (isWritingModeRoot() || m_numberOfInFlowChildrenOnFirstLine <= 0)
152         return -1;
153     RenderBox* baselineChild = 0;
154     int childNumber = 0;
155     for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
156         if (child->isOutOfFlowPositioned())
157             continue;
158         if (alignmentForChild(child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(child)) {
159             baselineChild = child;
160             break;
161         }
162         if (!baselineChild)
163             baselineChild = child;
164 
165         ++childNumber;
166         if (childNumber == m_numberOfInFlowChildrenOnFirstLine)
167             break;
168     }
169 
170     if (!baselineChild)
171         return -1;
172 
173     if (!isColumnFlow() && hasOrthogonalFlow(baselineChild))
174         return crossAxisExtentForChild(baselineChild) + baselineChild->logicalTop();
175     if (isColumnFlow() && !hasOrthogonalFlow(baselineChild))
176         return mainAxisExtentForChild(baselineChild) + baselineChild->logicalTop();
177 
178     int baseline = baselineChild->firstLineBoxBaseline();
179     if (baseline == -1) {
180         // FIXME: We should pass |direction| into firstLineBoxBaseline and stop bailing out if we're a writing mode root.
181         // This would also fix some cases where the flexbox is orthogonal to its container.
182         LineDirectionMode direction = isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
183         return synthesizedBaselineFromContentBox(baselineChild, direction) + baselineChild->logicalTop();
184     }
185 
186     return baseline + baselineChild->logicalTop();
187 }
188 
inlineBlockBaseline(LineDirectionMode direction) const189 int RenderFlexibleBox::inlineBlockBaseline(LineDirectionMode direction) const
190 {
191     int baseline = firstLineBoxBaseline();
192     if (baseline != -1)
193         return baseline;
194 
195     int marginAscent = direction == HorizontalLine ? marginTop() : marginRight();
196     return synthesizedBaselineFromContentBox(this, direction) + marginAscent;
197 }
198 
resolveAlignment(const RenderStyle * parentStyle,const RenderStyle * childStyle)199 static ItemPosition resolveAlignment(const RenderStyle* parentStyle, const RenderStyle* childStyle)
200 {
201     ItemPosition align = childStyle->alignSelf();
202     if (align == ItemPositionAuto)
203         align = parentStyle->alignItems();
204     return align;
205 }
206 
removeChild(RenderObject * child)207 void RenderFlexibleBox::removeChild(RenderObject* child)
208 {
209     RenderBlock::removeChild(child);
210     m_intrinsicSizeAlongMainAxis.remove(child);
211 }
212 
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)213 void RenderFlexibleBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
214 {
215     RenderBlock::styleDidChange(diff, oldStyle);
216 
217     if (oldStyle && oldStyle->alignItems() == ItemPositionStretch && diff.needsFullLayout()) {
218         // Flex items that were previously stretching need to be relayed out so we can compute new available cross axis space.
219         // This is only necessary for stretching since other alignment values don't change the size of the box.
220         for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
221             ItemPosition previousAlignment = resolveAlignment(oldStyle, child->style());
222             if (previousAlignment == ItemPositionStretch && previousAlignment != resolveAlignment(style(), child->style()))
223                 child->setChildNeedsLayout(MarkOnlyThis);
224         }
225     }
226 }
227 
layoutBlock(bool relayoutChildren)228 void RenderFlexibleBox::layoutBlock(bool relayoutChildren)
229 {
230     ASSERT(needsLayout());
231 
232     if (!relayoutChildren && simplifiedLayout())
233         return;
234 
235     LayoutRepainter repainter(*this, checkForPaintInvalidationDuringLayout());
236 
237     if (updateLogicalWidthAndColumnWidth())
238         relayoutChildren = true;
239 
240     LayoutUnit previousHeight = logicalHeight();
241     setLogicalHeight(borderAndPaddingLogicalHeight() + scrollbarLogicalHeight());
242 
243     {
244         FastTextAutosizer::LayoutScope fastTextAutosizerLayoutScope(this);
245         LayoutState state(*this, locationOffset());
246 
247         m_numberOfInFlowChildrenOnFirstLine = -1;
248 
249         RenderBlock::startDelayUpdateScrollInfo();
250 
251         prepareOrderIteratorAndMargins();
252 
253         ChildFrameRects oldChildRects;
254         appendChildFrameRects(oldChildRects);
255 
256         layoutFlexItems(relayoutChildren);
257 
258         RenderBlock::finishDelayUpdateScrollInfo();
259 
260         if (logicalHeight() != previousHeight)
261             relayoutChildren = true;
262 
263         layoutPositionedObjects(relayoutChildren || isDocumentElement());
264 
265         computeRegionRangeForBlock(flowThreadContainingBlock());
266 
267         repaintChildrenDuringLayoutIfMoved(oldChildRects);
268         // FIXME: css3/flexbox/repaint-rtl-column.html seems to repaint more overflow than it needs to.
269         computeOverflow(clientLogicalBottomAfterRepositioning());
270     }
271 
272     updateLayerTransformAfterLayout();
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     clearNeedsLayout();
281 }
282 
appendChildFrameRects(ChildFrameRects & childFrameRects)283 void RenderFlexibleBox::appendChildFrameRects(ChildFrameRects& childFrameRects)
284 {
285     for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
286         if (!child->isOutOfFlowPositioned())
287             childFrameRects.append(child->frameRect());
288     }
289 }
290 
repaintChildrenDuringLayoutIfMoved(const ChildFrameRects & oldChildRects)291 void RenderFlexibleBox::repaintChildrenDuringLayoutIfMoved(const ChildFrameRects& oldChildRects)
292 {
293     size_t childIndex = 0;
294     for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
295         if (child->isOutOfFlowPositioned())
296             continue;
297 
298         // If the child moved, we have to repaint it as well as any floating/positioned
299         // descendants. An exception is if we need a layout. In this case, we know we're going to
300         // repaint ourselves (and the child) anyway.
301         if (!selfNeedsLayout() && child->checkForPaintInvalidationDuringLayout())
302             child->repaintDuringLayoutIfMoved(oldChildRects[childIndex]);
303         ++childIndex;
304     }
305     ASSERT(childIndex == oldChildRects.size());
306 }
307 
paintChildren(PaintInfo & paintInfo,const LayoutPoint & paintOffset)308 void RenderFlexibleBox::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
309 {
310     for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next())
311         paintChildAsInlineBlock(child, paintInfo, paintOffset);
312 }
313 
repositionLogicalHeightDependentFlexItems(Vector<LineContext> & lineContexts)314 void RenderFlexibleBox::repositionLogicalHeightDependentFlexItems(Vector<LineContext>& lineContexts)
315 {
316     LayoutUnit crossAxisStartEdge = lineContexts.isEmpty() ? LayoutUnit() : lineContexts[0].crossAxisOffset;
317     alignFlexLines(lineContexts);
318 
319     alignChildren(lineContexts);
320 
321     if (style()->flexWrap() == FlexWrapReverse)
322         flipForWrapReverse(lineContexts, crossAxisStartEdge);
323 
324     // direction:rtl + flex-direction:column means the cross-axis direction is flipped.
325     flipForRightToLeftColumn();
326 }
327 
clientLogicalBottomAfterRepositioning()328 LayoutUnit RenderFlexibleBox::clientLogicalBottomAfterRepositioning()
329 {
330     LayoutUnit maxChildLogicalBottom = 0;
331     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
332         if (child->isOutOfFlowPositioned())
333             continue;
334         LayoutUnit childLogicalBottom = logicalTopForChild(child) + logicalHeightForChild(child) + marginAfterForChild(child);
335         maxChildLogicalBottom = std::max(maxChildLogicalBottom, childLogicalBottom);
336     }
337     return std::max(clientLogicalBottom(), maxChildLogicalBottom + paddingAfter());
338 }
339 
hasOrthogonalFlow(RenderBox * child) const340 bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox* child) const
341 {
342     // FIXME: If the child is a flexbox, then we need to check isHorizontalFlow.
343     return isHorizontalFlow() != child->isHorizontalWritingMode();
344 }
345 
isColumnFlow() const346 bool RenderFlexibleBox::isColumnFlow() const
347 {
348     return style()->isColumnFlexDirection();
349 }
350 
isHorizontalFlow() const351 bool RenderFlexibleBox::isHorizontalFlow() const
352 {
353     if (isHorizontalWritingMode())
354         return !isColumnFlow();
355     return isColumnFlow();
356 }
357 
isLeftToRightFlow() const358 bool RenderFlexibleBox::isLeftToRightFlow() const
359 {
360     if (isColumnFlow())
361         return style()->writingMode() == TopToBottomWritingMode || style()->writingMode() == LeftToRightWritingMode;
362     return style()->isLeftToRightDirection() ^ (style()->flexDirection() == FlowRowReverse);
363 }
364 
isMultiline() const365 bool RenderFlexibleBox::isMultiline() const
366 {
367     return style()->flexWrap() != FlexNoWrap;
368 }
369 
flexBasisForChild(RenderBox * child) const370 Length RenderFlexibleBox::flexBasisForChild(RenderBox* child) const
371 {
372     Length flexLength = child->style()->flexBasis();
373     if (flexLength.isAuto())
374         flexLength = isHorizontalFlow() ? child->style()->width() : child->style()->height();
375     return flexLength;
376 }
377 
crossAxisExtentForChild(RenderBox * child) const378 LayoutUnit RenderFlexibleBox::crossAxisExtentForChild(RenderBox* child) const
379 {
380     return isHorizontalFlow() ? child->height() : child->width();
381 }
382 
constrainedChildIntrinsicContentLogicalHeight(RenderBox * child)383 static inline LayoutUnit constrainedChildIntrinsicContentLogicalHeight(RenderBox* child)
384 {
385     LayoutUnit childIntrinsicContentLogicalHeight = child->intrinsicContentLogicalHeight();
386     return child->constrainLogicalHeightByMinMax(childIntrinsicContentLogicalHeight + child->borderAndPaddingLogicalHeight(), childIntrinsicContentLogicalHeight);
387 }
388 
childIntrinsicHeight(RenderBox * child) const389 LayoutUnit RenderFlexibleBox::childIntrinsicHeight(RenderBox* child) const
390 {
391     if (child->isHorizontalWritingMode() && needToStretchChildLogicalHeight(child))
392         return constrainedChildIntrinsicContentLogicalHeight(child);
393     return child->height();
394 }
395 
childIntrinsicWidth(RenderBox * child) const396 LayoutUnit RenderFlexibleBox::childIntrinsicWidth(RenderBox* child) const
397 {
398     if (!child->isHorizontalWritingMode() && needToStretchChildLogicalHeight(child))
399         return constrainedChildIntrinsicContentLogicalHeight(child);
400     return child->width();
401 }
402 
crossAxisIntrinsicExtentForChild(RenderBox * child) const403 LayoutUnit RenderFlexibleBox::crossAxisIntrinsicExtentForChild(RenderBox* child) const
404 {
405     return isHorizontalFlow() ? childIntrinsicHeight(child) : childIntrinsicWidth(child);
406 }
407 
mainAxisExtentForChild(RenderBox * child) const408 LayoutUnit RenderFlexibleBox::mainAxisExtentForChild(RenderBox* child) const
409 {
410     return isHorizontalFlow() ? child->width() : child->height();
411 }
412 
crossAxisExtent() const413 LayoutUnit RenderFlexibleBox::crossAxisExtent() const
414 {
415     return isHorizontalFlow() ? height() : width();
416 }
417 
mainAxisExtent() const418 LayoutUnit RenderFlexibleBox::mainAxisExtent() const
419 {
420     return isHorizontalFlow() ? width() : height();
421 }
422 
crossAxisContentExtent() const423 LayoutUnit RenderFlexibleBox::crossAxisContentExtent() const
424 {
425     return isHorizontalFlow() ? contentHeight() : contentWidth();
426 }
427 
mainAxisContentExtent(LayoutUnit contentLogicalHeight)428 LayoutUnit RenderFlexibleBox::mainAxisContentExtent(LayoutUnit contentLogicalHeight)
429 {
430     if (isColumnFlow()) {
431         LogicalExtentComputedValues computedValues;
432         LayoutUnit borderPaddingAndScrollbar = borderAndPaddingLogicalHeight() + scrollbarLogicalHeight();
433         // FIXME: Remove this std:max once we enable saturated layout arithmetic. It's just here to handle overflow.
434         LayoutUnit borderBoxLogicalHeight = std::max(contentLogicalHeight, contentLogicalHeight + borderPaddingAndScrollbar);
435         computeLogicalHeight(borderBoxLogicalHeight, logicalTop(), computedValues);
436         if (computedValues.m_extent == LayoutUnit::max())
437             return computedValues.m_extent;
438         return std::max(LayoutUnit(0), computedValues.m_extent - borderPaddingAndScrollbar);
439     }
440     return contentLogicalWidth();
441 }
442 
computeMainAxisExtentForChild(RenderBox * child,SizeType sizeType,const Length & size)443 LayoutUnit RenderFlexibleBox::computeMainAxisExtentForChild(RenderBox* child, SizeType sizeType, const Length& size)
444 {
445     // FIXME: This is wrong for orthogonal flows. It should use the flexbox's writing-mode, not the child's in order
446     // to figure out the logical height/width.
447     if (isColumnFlow()) {
448         // We don't have to check for "auto" here - computeContentLogicalHeight will just return -1 for that case anyway.
449         if (size.isIntrinsic())
450             child->layoutIfNeeded();
451         return child->computeContentLogicalHeight(size, child->logicalHeight() - child->borderAndPaddingLogicalHeight());
452     }
453     return child->computeLogicalWidthUsing(sizeType, size, contentLogicalWidth(), this) - child->borderAndPaddingLogicalWidth();
454 }
455 
transformedWritingMode() const456 WritingMode RenderFlexibleBox::transformedWritingMode() const
457 {
458     WritingMode mode = style()->writingMode();
459     if (!isColumnFlow())
460         return mode;
461 
462     switch (mode) {
463     case TopToBottomWritingMode:
464     case BottomToTopWritingMode:
465         return style()->isLeftToRightDirection() ? LeftToRightWritingMode : RightToLeftWritingMode;
466     case LeftToRightWritingMode:
467     case RightToLeftWritingMode:
468         return style()->isLeftToRightDirection() ? TopToBottomWritingMode : BottomToTopWritingMode;
469     }
470     ASSERT_NOT_REACHED();
471     return TopToBottomWritingMode;
472 }
473 
flowAwareBorderStart() const474 LayoutUnit RenderFlexibleBox::flowAwareBorderStart() const
475 {
476     if (isHorizontalFlow())
477         return isLeftToRightFlow() ? borderLeft() : borderRight();
478     return isLeftToRightFlow() ? borderTop() : borderBottom();
479 }
480 
flowAwareBorderEnd() const481 LayoutUnit RenderFlexibleBox::flowAwareBorderEnd() const
482 {
483     if (isHorizontalFlow())
484         return isLeftToRightFlow() ? borderRight() : borderLeft();
485     return isLeftToRightFlow() ? borderBottom() : borderTop();
486 }
487 
flowAwareBorderBefore() const488 LayoutUnit RenderFlexibleBox::flowAwareBorderBefore() const
489 {
490     switch (transformedWritingMode()) {
491     case TopToBottomWritingMode:
492         return borderTop();
493     case BottomToTopWritingMode:
494         return borderBottom();
495     case LeftToRightWritingMode:
496         return borderLeft();
497     case RightToLeftWritingMode:
498         return borderRight();
499     }
500     ASSERT_NOT_REACHED();
501     return borderTop();
502 }
503 
flowAwareBorderAfter() const504 LayoutUnit RenderFlexibleBox::flowAwareBorderAfter() const
505 {
506     switch (transformedWritingMode()) {
507     case TopToBottomWritingMode:
508         return borderBottom();
509     case BottomToTopWritingMode:
510         return borderTop();
511     case LeftToRightWritingMode:
512         return borderRight();
513     case RightToLeftWritingMode:
514         return borderLeft();
515     }
516     ASSERT_NOT_REACHED();
517     return borderTop();
518 }
519 
flowAwarePaddingStart() const520 LayoutUnit RenderFlexibleBox::flowAwarePaddingStart() const
521 {
522     if (isHorizontalFlow())
523         return isLeftToRightFlow() ? paddingLeft() : paddingRight();
524     return isLeftToRightFlow() ? paddingTop() : paddingBottom();
525 }
526 
flowAwarePaddingEnd() const527 LayoutUnit RenderFlexibleBox::flowAwarePaddingEnd() const
528 {
529     if (isHorizontalFlow())
530         return isLeftToRightFlow() ? paddingRight() : paddingLeft();
531     return isLeftToRightFlow() ? paddingBottom() : paddingTop();
532 }
533 
flowAwarePaddingBefore() const534 LayoutUnit RenderFlexibleBox::flowAwarePaddingBefore() const
535 {
536     switch (transformedWritingMode()) {
537     case TopToBottomWritingMode:
538         return paddingTop();
539     case BottomToTopWritingMode:
540         return paddingBottom();
541     case LeftToRightWritingMode:
542         return paddingLeft();
543     case RightToLeftWritingMode:
544         return paddingRight();
545     }
546     ASSERT_NOT_REACHED();
547     return paddingTop();
548 }
549 
flowAwarePaddingAfter() const550 LayoutUnit RenderFlexibleBox::flowAwarePaddingAfter() const
551 {
552     switch (transformedWritingMode()) {
553     case TopToBottomWritingMode:
554         return paddingBottom();
555     case BottomToTopWritingMode:
556         return paddingTop();
557     case LeftToRightWritingMode:
558         return paddingRight();
559     case RightToLeftWritingMode:
560         return paddingLeft();
561     }
562     ASSERT_NOT_REACHED();
563     return paddingTop();
564 }
565 
flowAwareMarginStartForChild(RenderBox * child) const566 LayoutUnit RenderFlexibleBox::flowAwareMarginStartForChild(RenderBox* child) const
567 {
568     if (isHorizontalFlow())
569         return isLeftToRightFlow() ? child->marginLeft() : child->marginRight();
570     return isLeftToRightFlow() ? child->marginTop() : child->marginBottom();
571 }
572 
flowAwareMarginEndForChild(RenderBox * child) const573 LayoutUnit RenderFlexibleBox::flowAwareMarginEndForChild(RenderBox* child) const
574 {
575     if (isHorizontalFlow())
576         return isLeftToRightFlow() ? child->marginRight() : child->marginLeft();
577     return isLeftToRightFlow() ? child->marginBottom() : child->marginTop();
578 }
579 
flowAwareMarginBeforeForChild(RenderBox * child) const580 LayoutUnit RenderFlexibleBox::flowAwareMarginBeforeForChild(RenderBox* child) const
581 {
582     switch (transformedWritingMode()) {
583     case TopToBottomWritingMode:
584         return child->marginTop();
585     case BottomToTopWritingMode:
586         return child->marginBottom();
587     case LeftToRightWritingMode:
588         return child->marginLeft();
589     case RightToLeftWritingMode:
590         return child->marginRight();
591     }
592     ASSERT_NOT_REACHED();
593     return marginTop();
594 }
595 
crossAxisMarginExtentForChild(RenderBox * child) const596 LayoutUnit RenderFlexibleBox::crossAxisMarginExtentForChild(RenderBox* child) const
597 {
598     return isHorizontalFlow() ? child->marginHeight() : child->marginWidth();
599 }
600 
crossAxisScrollbarExtent() const601 LayoutUnit RenderFlexibleBox::crossAxisScrollbarExtent() const
602 {
603     return isHorizontalFlow() ? horizontalScrollbarHeight() : verticalScrollbarWidth();
604 }
605 
flowAwareLocationForChild(RenderBox * child) const606 LayoutPoint RenderFlexibleBox::flowAwareLocationForChild(RenderBox* child) const
607 {
608     return isHorizontalFlow() ? child->location() : child->location().transposedPoint();
609 }
610 
setFlowAwareLocationForChild(RenderBox * child,const LayoutPoint & location)611 void RenderFlexibleBox::setFlowAwareLocationForChild(RenderBox* child, const LayoutPoint& location)
612 {
613     if (isHorizontalFlow())
614         child->setLocation(location);
615     else
616         child->setLocation(location.transposedPoint());
617 }
618 
mainAxisBorderAndPaddingExtentForChild(RenderBox * child) const619 LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox* child) const
620 {
621     return isHorizontalFlow() ? child->borderAndPaddingWidth() : child->borderAndPaddingHeight();
622 }
623 
preferredMainAxisExtentDependsOnLayout(const Length & flexBasis,bool hasInfiniteLineLength)624 static inline bool preferredMainAxisExtentDependsOnLayout(const Length& flexBasis, bool hasInfiniteLineLength)
625 {
626     return flexBasis.isAuto() || (flexBasis.isFixed() && !flexBasis.value() && hasInfiniteLineLength);
627 }
628 
childPreferredMainAxisContentExtentRequiresLayout(RenderBox * child,bool hasInfiniteLineLength) const629 bool RenderFlexibleBox::childPreferredMainAxisContentExtentRequiresLayout(RenderBox* child, bool hasInfiniteLineLength) const
630 {
631     return preferredMainAxisExtentDependsOnLayout(flexBasisForChild(child), hasInfiniteLineLength) && hasOrthogonalFlow(child);
632 }
633 
preferredMainAxisContentExtentForChild(RenderBox * child,bool hasInfiniteLineLength,bool relayoutChildren)634 LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* child, bool hasInfiniteLineLength, bool relayoutChildren)
635 {
636     child->clearOverrideSize();
637 
638     Length flexBasis = flexBasisForChild(child);
639     if (preferredMainAxisExtentDependsOnLayout(flexBasis, hasInfiniteLineLength)) {
640         LayoutUnit mainAxisExtent;
641         if (hasOrthogonalFlow(child)) {
642             if (child->needsLayout() || relayoutChildren) {
643                 m_intrinsicSizeAlongMainAxis.remove(child);
644                 child->forceChildLayout();
645                 m_intrinsicSizeAlongMainAxis.set(child, child->logicalHeight());
646             }
647             ASSERT(m_intrinsicSizeAlongMainAxis.contains(child));
648             mainAxisExtent = m_intrinsicSizeAlongMainAxis.get(child);
649         } else {
650             mainAxisExtent = child->maxPreferredLogicalWidth();
651         }
652         ASSERT(mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child) >= 0);
653         return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child);
654     }
655     return std::max(LayoutUnit(0), computeMainAxisExtentForChild(child, MainOrPreferredSize, flexBasis));
656 }
657 
layoutFlexItems(bool relayoutChildren)658 void RenderFlexibleBox::layoutFlexItems(bool relayoutChildren)
659 {
660     Vector<LineContext> lineContexts;
661     OrderedFlexItemList orderedChildren;
662     LayoutUnit sumFlexBaseSize;
663     double totalFlexGrow;
664     double totalWeightedFlexShrink;
665     LayoutUnit sumHypotheticalMainSize;
666 
667     Vector<LayoutUnit, 16> childSizes;
668 
669     m_orderIterator.first();
670     LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
671     bool hasInfiniteLineLength = false;
672     while (computeNextFlexLine(orderedChildren, sumFlexBaseSize, totalFlexGrow, totalWeightedFlexShrink, sumHypotheticalMainSize, hasInfiniteLineLength, relayoutChildren)) {
673         LayoutUnit containerMainInnerSize = mainAxisContentExtent(sumHypotheticalMainSize);
674         LayoutUnit availableFreeSpace = containerMainInnerSize - sumFlexBaseSize;
675         FlexSign flexSign = (sumHypotheticalMainSize < containerMainInnerSize) ? PositiveFlexibility : NegativeFlexibility;
676         InflexibleFlexItemSize inflexibleItems;
677         childSizes.reserveCapacity(orderedChildren.size());
678         while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, childSizes, hasInfiniteLineLength)) {
679             ASSERT(totalFlexGrow >= 0 && totalWeightedFlexShrink >= 0);
680             ASSERT(inflexibleItems.size() > 0);
681         }
682 
683         layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace, relayoutChildren, lineContexts, hasInfiniteLineLength);
684     }
685     if (hasLineIfEmpty()) {
686         // Even if computeNextFlexLine returns true, the flexbox might not have
687         // a line because all our children might be out of flow positioned.
688         // Instead of just checking if we have a line, make sure the flexbox
689         // has at least a line's worth of height to cover this case.
690         LayoutUnit minHeight = borderAndPaddingLogicalHeight()
691             + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes)
692             + scrollbarLogicalHeight();
693         if (height() < minHeight)
694             setLogicalHeight(minHeight);
695     }
696 
697     updateLogicalHeight();
698     repositionLogicalHeightDependentFlexItems(lineContexts);
699 }
700 
autoMarginOffsetInMainAxis(const OrderedFlexItemList & children,LayoutUnit & availableFreeSpace)701 LayoutUnit RenderFlexibleBox::autoMarginOffsetInMainAxis(const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace)
702 {
703     if (availableFreeSpace <= 0)
704         return 0;
705 
706     int numberOfAutoMargins = 0;
707     bool isHorizontal = isHorizontalFlow();
708     for (size_t i = 0; i < children.size(); ++i) {
709         RenderBox* child = children[i];
710         if (child->isOutOfFlowPositioned())
711             continue;
712         if (isHorizontal) {
713             if (child->style()->marginLeft().isAuto())
714                 ++numberOfAutoMargins;
715             if (child->style()->marginRight().isAuto())
716                 ++numberOfAutoMargins;
717         } else {
718             if (child->style()->marginTop().isAuto())
719                 ++numberOfAutoMargins;
720             if (child->style()->marginBottom().isAuto())
721                 ++numberOfAutoMargins;
722         }
723     }
724     if (!numberOfAutoMargins)
725         return 0;
726 
727     LayoutUnit sizeOfAutoMargin = availableFreeSpace / numberOfAutoMargins;
728     availableFreeSpace = 0;
729     return sizeOfAutoMargin;
730 }
731 
updateAutoMarginsInMainAxis(RenderBox * child,LayoutUnit autoMarginOffset)732 void RenderFlexibleBox::updateAutoMarginsInMainAxis(RenderBox* child, LayoutUnit autoMarginOffset)
733 {
734     ASSERT(autoMarginOffset >= 0);
735 
736     if (isHorizontalFlow()) {
737         if (child->style()->marginLeft().isAuto())
738             child->setMarginLeft(autoMarginOffset);
739         if (child->style()->marginRight().isAuto())
740             child->setMarginRight(autoMarginOffset);
741     } else {
742         if (child->style()->marginTop().isAuto())
743             child->setMarginTop(autoMarginOffset);
744         if (child->style()->marginBottom().isAuto())
745             child->setMarginBottom(autoMarginOffset);
746     }
747 }
748 
hasAutoMarginsInCrossAxis(RenderBox * child) const749 bool RenderFlexibleBox::hasAutoMarginsInCrossAxis(RenderBox* child) const
750 {
751     if (isHorizontalFlow())
752         return child->style()->marginTop().isAuto() || child->style()->marginBottom().isAuto();
753     return child->style()->marginLeft().isAuto() || child->style()->marginRight().isAuto();
754 }
755 
availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent,RenderBox * child)756 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox* child)
757 {
758     ASSERT(!child->isOutOfFlowPositioned());
759     LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child);
760     return lineCrossAxisExtent - childCrossExtent;
761 }
762 
availableAlignmentSpaceForChildBeforeStretching(LayoutUnit lineCrossAxisExtent,RenderBox * child)763 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChildBeforeStretching(LayoutUnit lineCrossAxisExtent, RenderBox* child)
764 {
765     ASSERT(!child->isOutOfFlowPositioned());
766     LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisIntrinsicExtentForChild(child);
767     return lineCrossAxisExtent - childCrossExtent;
768 }
769 
updateAutoMarginsInCrossAxis(RenderBox * child,LayoutUnit availableAlignmentSpace)770 bool RenderFlexibleBox::updateAutoMarginsInCrossAxis(RenderBox* child, LayoutUnit availableAlignmentSpace)
771 {
772     ASSERT(!child->isOutOfFlowPositioned());
773     ASSERT(availableAlignmentSpace >= 0);
774 
775     bool isHorizontal = isHorizontalFlow();
776     Length topOrLeft = isHorizontal ? child->style()->marginTop() : child->style()->marginLeft();
777     Length bottomOrRight = isHorizontal ? child->style()->marginBottom() : child->style()->marginRight();
778     if (topOrLeft.isAuto() && bottomOrRight.isAuto()) {
779         adjustAlignmentForChild(child, availableAlignmentSpace / 2);
780         if (isHorizontal) {
781             child->setMarginTop(availableAlignmentSpace / 2);
782             child->setMarginBottom(availableAlignmentSpace / 2);
783         } else {
784             child->setMarginLeft(availableAlignmentSpace / 2);
785             child->setMarginRight(availableAlignmentSpace / 2);
786         }
787         return true;
788     }
789     bool shouldAdjustTopOrLeft = true;
790     if (isColumnFlow() && !child->style()->isLeftToRightDirection()) {
791         // For column flows, only make this adjustment if topOrLeft corresponds to the "before" margin,
792         // so that flipForRightToLeftColumn will do the right thing.
793         shouldAdjustTopOrLeft = false;
794     }
795     if (!isColumnFlow() && child->style()->isFlippedBlocksWritingMode()) {
796         // If we are a flipped writing mode, we need to adjust the opposite side. This is only needed
797         // for row flows because this only affects the block-direction axis.
798         shouldAdjustTopOrLeft = false;
799     }
800 
801     if (topOrLeft.isAuto()) {
802         if (shouldAdjustTopOrLeft)
803             adjustAlignmentForChild(child, availableAlignmentSpace);
804 
805         if (isHorizontal)
806             child->setMarginTop(availableAlignmentSpace);
807         else
808             child->setMarginLeft(availableAlignmentSpace);
809         return true;
810     }
811     if (bottomOrRight.isAuto()) {
812         if (!shouldAdjustTopOrLeft)
813             adjustAlignmentForChild(child, availableAlignmentSpace);
814 
815         if (isHorizontal)
816             child->setMarginBottom(availableAlignmentSpace);
817         else
818             child->setMarginRight(availableAlignmentSpace);
819         return true;
820     }
821     return false;
822 }
823 
marginBoxAscentForChild(RenderBox * child)824 LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(RenderBox* child)
825 {
826     LayoutUnit ascent = child->firstLineBoxBaseline();
827     if (ascent == -1)
828         ascent = crossAxisExtentForChild(child);
829     return ascent + flowAwareMarginBeforeForChild(child);
830 }
831 
computeChildMarginValue(Length margin)832 LayoutUnit RenderFlexibleBox::computeChildMarginValue(Length margin)
833 {
834     // When resolving the margins, we use the content size for resolving percent and calc (for percents in calc expressions) margins.
835     // Fortunately, percent margins are always computed with respect to the block's width, even for margin-top and margin-bottom.
836     LayoutUnit availableSize = contentLogicalWidth();
837     return minimumValueForLength(margin, availableSize);
838 }
839 
prepareOrderIteratorAndMargins()840 void RenderFlexibleBox::prepareOrderIteratorAndMargins()
841 {
842     OrderIteratorPopulator populator(m_orderIterator);
843 
844     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
845         populator.collectChild(child);
846 
847         if (child->isOutOfFlowPositioned())
848             continue;
849 
850         // Before running the flex algorithm, 'auto' has a margin of 0.
851         // Also, if we're not auto sizing, we don't do a layout that computes the start/end margins.
852         if (isHorizontalFlow()) {
853             child->setMarginLeft(computeChildMarginValue(child->style()->marginLeft()));
854             child->setMarginRight(computeChildMarginValue(child->style()->marginRight()));
855         } else {
856             child->setMarginTop(computeChildMarginValue(child->style()->marginTop()));
857             child->setMarginBottom(computeChildMarginValue(child->style()->marginBottom()));
858         }
859     }
860 }
861 
adjustChildSizeForMinAndMax(RenderBox * child,LayoutUnit childSize)862 LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox* child, LayoutUnit childSize)
863 {
864     Length max = isHorizontalFlow() ? child->style()->maxWidth() : child->style()->maxHeight();
865     if (max.isSpecifiedOrIntrinsic()) {
866         LayoutUnit maxExtent = computeMainAxisExtentForChild(child, MaxSize, max);
867         if (maxExtent != -1 && childSize > maxExtent)
868             childSize = maxExtent;
869     }
870 
871     Length min = isHorizontalFlow() ? child->style()->minWidth() : child->style()->minHeight();
872     LayoutUnit minExtent = 0;
873     if (min.isSpecifiedOrIntrinsic())
874         minExtent = computeMainAxisExtentForChild(child, MinSize, min);
875     return std::max(childSize, minExtent);
876 }
877 
computeNextFlexLine(OrderedFlexItemList & orderedChildren,LayoutUnit & sumFlexBaseSize,double & totalFlexGrow,double & totalWeightedFlexShrink,LayoutUnit & sumHypotheticalMainSize,bool & hasInfiniteLineLength,bool relayoutChildren)878 bool RenderFlexibleBox::computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& sumFlexBaseSize, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& sumHypotheticalMainSize, bool& hasInfiniteLineLength, bool relayoutChildren)
879 {
880     orderedChildren.clear();
881     sumFlexBaseSize = 0;
882     totalFlexGrow = totalWeightedFlexShrink = 0;
883     sumHypotheticalMainSize = 0;
884 
885     if (!m_orderIterator.currentChild())
886         return false;
887 
888     LayoutUnit lineBreakLength = mainAxisContentExtent(LayoutUnit::max());
889     hasInfiniteLineLength = lineBreakLength == LayoutUnit::max();
890 
891     bool lineHasInFlowItem = false;
892 
893     for (RenderBox* child = m_orderIterator.currentChild(); child; child = m_orderIterator.next()) {
894         if (child->isOutOfFlowPositioned()) {
895             orderedChildren.append(child);
896             continue;
897         }
898 
899         LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength, relayoutChildren);
900         LayoutUnit childMainAxisMarginBorderPadding = mainAxisBorderAndPaddingExtentForChild(child)
901             + (isHorizontalFlow() ? child->marginWidth() : child->marginHeight());
902         LayoutUnit childFlexBaseSize = childMainAxisExtent + childMainAxisMarginBorderPadding;
903 
904         LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(child, childMainAxisExtent);
905         LayoutUnit childHypotheticalMainSize = childMinMaxAppliedMainAxisExtent + childMainAxisMarginBorderPadding;
906 
907         if (isMultiline() && sumHypotheticalMainSize + childHypotheticalMainSize > lineBreakLength && lineHasInFlowItem)
908             break;
909         orderedChildren.append(child);
910         lineHasInFlowItem  = true;
911         sumFlexBaseSize += childFlexBaseSize;
912         totalFlexGrow += child->style()->flexGrow();
913         totalWeightedFlexShrink += child->style()->flexShrink() * childMainAxisExtent;
914         sumHypotheticalMainSize += childHypotheticalMainSize;
915     }
916     return true;
917 }
918 
freezeViolations(const Vector<Violation> & violations,LayoutUnit & availableFreeSpace,double & totalFlexGrow,double & totalWeightedFlexShrink,InflexibleFlexItemSize & inflexibleItems,bool hasInfiniteLineLength)919 void RenderFlexibleBox::freezeViolations(const Vector<Violation>& violations, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, bool hasInfiniteLineLength)
920 {
921     for (size_t i = 0; i < violations.size(); ++i) {
922         RenderBox* child = violations[i].child;
923         LayoutUnit childSize = violations[i].childSize;
924         LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
925         availableFreeSpace -= childSize - preferredChildSize;
926         totalFlexGrow -= child->style()->flexGrow();
927         totalWeightedFlexShrink -= child->style()->flexShrink() * preferredChildSize;
928         inflexibleItems.set(child, childSize);
929     }
930 }
931 
932 // Returns true if we successfully ran the algorithm and sized the flex items.
resolveFlexibleLengths(FlexSign flexSign,const OrderedFlexItemList & children,LayoutUnit & availableFreeSpace,double & totalFlexGrow,double & totalWeightedFlexShrink,InflexibleFlexItemSize & inflexibleItems,Vector<LayoutUnit,16> & childSizes,bool hasInfiniteLineLength)933 bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, Vector<LayoutUnit, 16>& childSizes, bool hasInfiniteLineLength)
934 {
935     childSizes.resize(0);
936     LayoutUnit totalViolation = 0;
937     LayoutUnit usedFreeSpace = 0;
938     Vector<Violation> minViolations;
939     Vector<Violation> maxViolations;
940     for (size_t i = 0; i < children.size(); ++i) {
941         RenderBox* child = children[i];
942         if (child->isOutOfFlowPositioned()) {
943             childSizes.append(0);
944             continue;
945         }
946 
947         if (inflexibleItems.contains(child))
948             childSizes.append(inflexibleItems.get(child));
949         else {
950             LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child, hasInfiniteLineLength);
951             LayoutUnit childSize = preferredChildSize;
952             double extraSpace = 0;
953             if (availableFreeSpace > 0 && totalFlexGrow > 0 && flexSign == PositiveFlexibility && std::isfinite(totalFlexGrow))
954                 extraSpace = availableFreeSpace * child->style()->flexGrow() / totalFlexGrow;
955             else if (availableFreeSpace < 0 && totalWeightedFlexShrink > 0 && flexSign == NegativeFlexibility && std::isfinite(totalWeightedFlexShrink))
956                 extraSpace = availableFreeSpace * child->style()->flexShrink() * preferredChildSize / totalWeightedFlexShrink;
957             if (std::isfinite(extraSpace))
958                 childSize += LayoutUnit::fromFloatRound(extraSpace);
959 
960             LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(child, childSize);
961             childSizes.append(adjustedChildSize);
962             usedFreeSpace += adjustedChildSize - preferredChildSize;
963 
964             LayoutUnit violation = adjustedChildSize - childSize;
965             if (violation > 0)
966                 minViolations.append(Violation(child, adjustedChildSize));
967             else if (violation < 0)
968                 maxViolations.append(Violation(child, adjustedChildSize));
969             totalViolation += violation;
970         }
971     }
972 
973     if (totalViolation)
974         freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, hasInfiniteLineLength);
975     else
976         availableFreeSpace -= usedFreeSpace;
977 
978     return !totalViolation;
979 }
980 
initialJustifyContentOffset(LayoutUnit availableFreeSpace,EJustifyContent justifyContent,unsigned numberOfChildren)981 static LayoutUnit initialJustifyContentOffset(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
982 {
983     if (justifyContent == JustifyFlexEnd)
984         return availableFreeSpace;
985     if (justifyContent == JustifyCenter)
986         return availableFreeSpace / 2;
987     if (justifyContent == JustifySpaceAround) {
988         if (availableFreeSpace > 0 && numberOfChildren)
989             return availableFreeSpace / (2 * numberOfChildren);
990         else
991             return availableFreeSpace / 2;
992     }
993     return 0;
994 }
995 
justifyContentSpaceBetweenChildren(LayoutUnit availableFreeSpace,EJustifyContent justifyContent,unsigned numberOfChildren)996 static LayoutUnit justifyContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren)
997 {
998     if (availableFreeSpace > 0 && numberOfChildren > 1) {
999         if (justifyContent == JustifySpaceBetween)
1000             return availableFreeSpace / (numberOfChildren - 1);
1001         if (justifyContent == JustifySpaceAround)
1002             return availableFreeSpace / numberOfChildren;
1003     }
1004     return 0;
1005 }
1006 
setLogicalOverrideSize(RenderBox * child,LayoutUnit childPreferredSize)1007 void RenderFlexibleBox::setLogicalOverrideSize(RenderBox* child, LayoutUnit childPreferredSize)
1008 {
1009     if (hasOrthogonalFlow(child))
1010         child->setOverrideLogicalContentHeight(childPreferredSize - child->borderAndPaddingLogicalHeight());
1011     else
1012         child->setOverrideLogicalContentWidth(childPreferredSize - child->borderAndPaddingLogicalWidth());
1013 }
1014 
prepareChildForPositionedLayout(RenderBox * child,LayoutUnit mainAxisOffset,LayoutUnit crossAxisOffset,PositionedLayoutMode layoutMode)1015 void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox* child, LayoutUnit mainAxisOffset, LayoutUnit crossAxisOffset, PositionedLayoutMode layoutMode)
1016 {
1017     ASSERT(child->isOutOfFlowPositioned());
1018     child->containingBlock()->insertPositionedObject(child);
1019     RenderLayer* childLayer = child->layer();
1020     LayoutUnit inlinePosition = isColumnFlow() ? crossAxisOffset : mainAxisOffset;
1021     if (layoutMode == FlipForRowReverse && style()->flexDirection() == FlowRowReverse)
1022         inlinePosition = mainAxisExtent() - mainAxisOffset;
1023     childLayer->setStaticInlinePosition(inlinePosition);
1024 
1025     LayoutUnit staticBlockPosition = isColumnFlow() ? mainAxisOffset : crossAxisOffset;
1026     if (childLayer->staticBlockPosition() != staticBlockPosition) {
1027         childLayer->setStaticBlockPosition(staticBlockPosition);
1028         if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
1029             child->setChildNeedsLayout(MarkOnlyThis);
1030     }
1031 }
1032 
alignmentForChild(RenderBox * child) const1033 ItemPosition RenderFlexibleBox::alignmentForChild(RenderBox* child) const
1034 {
1035     ItemPosition align = resolveAlignment(style(), child->style());
1036 
1037     if (align == ItemPositionBaseline && hasOrthogonalFlow(child))
1038         align = ItemPositionFlexStart;
1039 
1040     if (style()->flexWrap() == FlexWrapReverse) {
1041         if (align == ItemPositionFlexStart)
1042             align = ItemPositionFlexEnd;
1043         else if (align == ItemPositionFlexEnd)
1044             align = ItemPositionFlexStart;
1045     }
1046 
1047     return align;
1048 }
1049 
numberOfInFlowPositionedChildren(const OrderedFlexItemList & children) const1050 size_t RenderFlexibleBox::numberOfInFlowPositionedChildren(const OrderedFlexItemList& children) const
1051 {
1052     size_t count = 0;
1053     for (size_t i = 0; i < children.size(); ++i) {
1054         RenderBox* child = children[i];
1055         if (!child->isOutOfFlowPositioned())
1056             ++count;
1057     }
1058     return count;
1059 }
1060 
resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox * child)1061 void RenderFlexibleBox::resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox* child)
1062 {
1063     if (hasAutoMarginsInCrossAxis(child)) {
1064         child->updateLogicalHeight();
1065         if (isHorizontalFlow()) {
1066             if (child->style()->marginTop().isAuto())
1067                 child->setMarginTop(0);
1068             if (child->style()->marginBottom().isAuto())
1069                 child->setMarginBottom(0);
1070         } else {
1071             if (child->style()->marginLeft().isAuto())
1072                 child->setMarginLeft(0);
1073             if (child->style()->marginRight().isAuto())
1074                 child->setMarginRight(0);
1075         }
1076     }
1077 }
1078 
needToStretchChildLogicalHeight(RenderBox * child) const1079 bool RenderFlexibleBox::needToStretchChildLogicalHeight(RenderBox* child) const
1080 {
1081     if (alignmentForChild(child) != ItemPositionStretch)
1082         return false;
1083 
1084     return isHorizontalFlow() && child->style()->height().isAuto();
1085 }
1086 
layoutAndPlaceChildren(LayoutUnit & crossAxisOffset,const OrderedFlexItemList & children,const Vector<LayoutUnit,16> & childSizes,LayoutUnit availableFreeSpace,bool relayoutChildren,Vector<LineContext> & lineContexts,bool hasInfiniteLineLength)1087 void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const Vector<LayoutUnit, 16>& childSizes, LayoutUnit availableFreeSpace, bool relayoutChildren, Vector<LineContext>& lineContexts, bool hasInfiniteLineLength)
1088 {
1089     ASSERT(childSizes.size() == children.size());
1090 
1091     size_t numberOfChildrenForJustifyContent = numberOfInFlowPositionedChildren(children);
1092     LayoutUnit autoMarginOffset = autoMarginOffsetInMainAxis(children, availableFreeSpace);
1093     LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart();
1094     mainAxisOffset += initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1095     if (style()->flexDirection() == FlowRowReverse)
1096         mainAxisOffset += isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1097 
1098     LayoutUnit totalMainExtent = mainAxisExtent();
1099     LayoutUnit maxAscent = 0, maxDescent = 0; // Used when align-items: baseline.
1100     LayoutUnit maxChildCrossAxisExtent = 0;
1101     size_t seenInFlowPositionedChildren = 0;
1102     bool shouldFlipMainAxis = !isColumnFlow() && !isLeftToRightFlow();
1103     for (size_t i = 0; i < children.size(); ++i) {
1104         RenderBox* child = children[i];
1105 
1106         if (child->isOutOfFlowPositioned()) {
1107             prepareChildForPositionedLayout(child, mainAxisOffset, crossAxisOffset, FlipForRowReverse);
1108             continue;
1109         }
1110 
1111         // FIXME Investigate if this can be removed based on other flags. crbug.com/370010
1112         child->setMayNeedPaintInvalidation(true);
1113 
1114         LayoutUnit childPreferredSize = childSizes[i] + mainAxisBorderAndPaddingExtentForChild(child);
1115         setLogicalOverrideSize(child, childPreferredSize);
1116         if (childPreferredSize != mainAxisExtentForChild(child)) {
1117             child->setChildNeedsLayout(MarkOnlyThis);
1118         } else {
1119             // To avoid double applying margin changes in updateAutoMarginsInCrossAxis, we reset the margins here.
1120             resetAutoMarginsAndLogicalTopInCrossAxis(child);
1121         }
1122         // We may have already forced relayout for orthogonal flowing children in preferredMainAxisContentExtentForChild.
1123         bool forceChildRelayout = relayoutChildren && !childPreferredMainAxisContentExtentRequiresLayout(child, hasInfiniteLineLength);
1124         updateBlockChildDirtyBitsBeforeLayout(forceChildRelayout, child);
1125         child->layoutIfNeeded();
1126 
1127         updateAutoMarginsInMainAxis(child, autoMarginOffset);
1128 
1129         LayoutUnit childCrossAxisMarginBoxExtent;
1130         if (alignmentForChild(child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(child)) {
1131             LayoutUnit ascent = marginBoxAscentForChild(child);
1132             LayoutUnit descent = (crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child)) - ascent;
1133 
1134             maxAscent = std::max(maxAscent, ascent);
1135             maxDescent = std::max(maxDescent, descent);
1136 
1137             childCrossAxisMarginBoxExtent = maxAscent + maxDescent;
1138         } else {
1139             childCrossAxisMarginBoxExtent = crossAxisIntrinsicExtentForChild(child) + crossAxisMarginExtentForChild(child);
1140         }
1141         if (!isColumnFlow())
1142             setLogicalHeight(std::max(logicalHeight(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent()));
1143         maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisMarginBoxExtent);
1144 
1145         mainAxisOffset += flowAwareMarginStartForChild(child);
1146 
1147         LayoutUnit childMainExtent = mainAxisExtentForChild(child);
1148         // In an RTL column situation, this will apply the margin-right/margin-end on the left.
1149         // This will be fixed later in flipForRightToLeftColumn.
1150         LayoutPoint childLocation(shouldFlipMainAxis ? totalMainExtent - mainAxisOffset - childMainExtent : mainAxisOffset,
1151             crossAxisOffset + flowAwareMarginBeforeForChild(child));
1152 
1153         // FIXME: Supporting layout deltas.
1154         setFlowAwareLocationForChild(child, childLocation);
1155         mainAxisOffset += childMainExtent + flowAwareMarginEndForChild(child);
1156 
1157         ++seenInFlowPositionedChildren;
1158         if (seenInFlowPositionedChildren < numberOfChildrenForJustifyContent)
1159             mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1160     }
1161 
1162     if (isColumnFlow())
1163         setLogicalHeight(mainAxisOffset + flowAwareBorderEnd() + flowAwarePaddingEnd() + scrollbarLogicalHeight());
1164 
1165     if (style()->flexDirection() == FlowColumnReverse) {
1166         // We have to do an extra pass for column-reverse to reposition the flex items since the start depends
1167         // on the height of the flexbox, which we only know after we've positioned all the flex items.
1168         updateLogicalHeight();
1169         layoutColumnReverse(children, crossAxisOffset, availableFreeSpace);
1170     }
1171 
1172     if (m_numberOfInFlowChildrenOnFirstLine == -1)
1173         m_numberOfInFlowChildrenOnFirstLine = seenInFlowPositionedChildren;
1174     lineContexts.append(LineContext(crossAxisOffset, maxChildCrossAxisExtent, children.size(), maxAscent));
1175     crossAxisOffset += maxChildCrossAxisExtent;
1176 }
1177 
layoutColumnReverse(const OrderedFlexItemList & children,LayoutUnit crossAxisOffset,LayoutUnit availableFreeSpace)1178 void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace)
1179 {
1180     // This is similar to the logic in layoutAndPlaceChildren, except we place the children
1181     // starting from the end of the flexbox. We also don't need to layout anything since we're
1182     // just moving the children to a new position.
1183     size_t numberOfChildrenForJustifyContent = numberOfInFlowPositionedChildren(children);
1184     LayoutUnit mainAxisOffset = logicalHeight() - flowAwareBorderEnd() - flowAwarePaddingEnd();
1185     mainAxisOffset -= initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1186     mainAxisOffset -= isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1187 
1188     size_t seenInFlowPositionedChildren = 0;
1189     for (size_t i = 0; i < children.size(); ++i) {
1190         RenderBox* child = children[i];
1191 
1192         if (child->isOutOfFlowPositioned()) {
1193             child->layer()->setStaticBlockPosition(mainAxisOffset);
1194             continue;
1195         }
1196         mainAxisOffset -= mainAxisExtentForChild(child) + flowAwareMarginEndForChild(child);
1197 
1198         setFlowAwareLocationForChild(child, LayoutPoint(mainAxisOffset, crossAxisOffset + flowAwareMarginBeforeForChild(child)));
1199 
1200         mainAxisOffset -= flowAwareMarginStartForChild(child);
1201 
1202         ++seenInFlowPositionedChildren;
1203         if (seenInFlowPositionedChildren < numberOfChildrenForJustifyContent)
1204             mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent);
1205     }
1206 }
1207 
initialAlignContentOffset(LayoutUnit availableFreeSpace,EAlignContent alignContent,unsigned numberOfLines)1208 static LayoutUnit initialAlignContentOffset(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1209 {
1210     if (numberOfLines <= 1)
1211         return 0;
1212     if (alignContent == AlignContentFlexEnd)
1213         return availableFreeSpace;
1214     if (alignContent == AlignContentCenter)
1215         return availableFreeSpace / 2;
1216     if (alignContent == AlignContentSpaceAround) {
1217         if (availableFreeSpace > 0 && numberOfLines)
1218             return availableFreeSpace / (2 * numberOfLines);
1219         if (availableFreeSpace < 0)
1220             return availableFreeSpace / 2;
1221     }
1222     return 0;
1223 }
1224 
alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace,EAlignContent alignContent,unsigned numberOfLines)1225 static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines)
1226 {
1227     if (availableFreeSpace > 0 && numberOfLines > 1) {
1228         if (alignContent == AlignContentSpaceBetween)
1229             return availableFreeSpace / (numberOfLines - 1);
1230         if (alignContent == AlignContentSpaceAround || alignContent == AlignContentStretch)
1231             return availableFreeSpace / numberOfLines;
1232     }
1233     return 0;
1234 }
1235 
alignFlexLines(Vector<LineContext> & lineContexts)1236 void RenderFlexibleBox::alignFlexLines(Vector<LineContext>& lineContexts)
1237 {
1238     // If we have a single line flexbox or a multiline line flexbox with only one flex line,
1239     // the line height is all the available space.
1240     // For flex-direction: row, this means we need to use the height, so we do this after calling updateLogicalHeight.
1241     if (lineContexts.size() == 1) {
1242         lineContexts[0].crossAxisExtent = crossAxisContentExtent();
1243         return;
1244     }
1245 
1246     if (style()->alignContent() == AlignContentFlexStart)
1247         return;
1248 
1249     LayoutUnit availableCrossAxisSpace = crossAxisContentExtent();
1250     for (size_t i = 0; i < lineContexts.size(); ++i)
1251         availableCrossAxisSpace -= lineContexts[i].crossAxisExtent;
1252 
1253     RenderBox* child = m_orderIterator.first();
1254     LayoutUnit lineOffset = initialAlignContentOffset(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1255     for (unsigned lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1256         lineContexts[lineNumber].crossAxisOffset += lineOffset;
1257         for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next())
1258             adjustAlignmentForChild(child, lineOffset);
1259 
1260         if (style()->alignContent() == AlignContentStretch && availableCrossAxisSpace > 0)
1261             lineContexts[lineNumber].crossAxisExtent += availableCrossAxisSpace / static_cast<unsigned>(lineContexts.size());
1262 
1263         lineOffset += alignContentSpaceBetweenChildren(availableCrossAxisSpace, style()->alignContent(), lineContexts.size());
1264     }
1265 }
1266 
adjustAlignmentForChild(RenderBox * child,LayoutUnit delta)1267 void RenderFlexibleBox::adjustAlignmentForChild(RenderBox* child, LayoutUnit delta)
1268 {
1269     if (child->isOutOfFlowPositioned()) {
1270         LayoutUnit staticInlinePosition = child->layer()->staticInlinePosition();
1271         LayoutUnit staticBlockPosition = child->layer()->staticBlockPosition();
1272         LayoutUnit mainAxis = isColumnFlow() ? staticBlockPosition : staticInlinePosition;
1273         LayoutUnit crossAxis = isColumnFlow() ? staticInlinePosition : staticBlockPosition;
1274         crossAxis += delta;
1275         prepareChildForPositionedLayout(child, mainAxis, crossAxis, NoFlipForRowReverse);
1276         return;
1277     }
1278 
1279     setFlowAwareLocationForChild(child, flowAwareLocationForChild(child) + LayoutSize(0, delta));
1280 }
1281 
alignChildren(const Vector<LineContext> & lineContexts)1282 void RenderFlexibleBox::alignChildren(const Vector<LineContext>& lineContexts)
1283 {
1284     // Keep track of the space between the baseline edge and the after edge of the box for each line.
1285     Vector<LayoutUnit> minMarginAfterBaselines;
1286 
1287     RenderBox* child = m_orderIterator.first();
1288     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1289         LayoutUnit minMarginAfterBaseline = LayoutUnit::max();
1290         LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1291         LayoutUnit maxAscent = lineContexts[lineNumber].maxAscent;
1292 
1293         for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
1294             ASSERT(child);
1295             if (child->isOutOfFlowPositioned()) {
1296                 if (style()->flexWrap() == FlexWrapReverse)
1297                     adjustAlignmentForChild(child, lineCrossAxisExtent);
1298                 continue;
1299             }
1300 
1301             if (updateAutoMarginsInCrossAxis(child, std::max(LayoutUnit(0), availableAlignmentSpaceForChild(lineCrossAxisExtent, child))))
1302                 continue;
1303 
1304             switch (alignmentForChild(child)) {
1305             case ItemPositionAuto:
1306                 ASSERT_NOT_REACHED();
1307                 break;
1308             case ItemPositionStretch: {
1309                 applyStretchAlignmentToChild(child, lineCrossAxisExtent);
1310                 // Since wrap-reverse flips cross start and cross end, strech children should be aligned with the cross end.
1311                 if (style()->flexWrap() == FlexWrapReverse)
1312                     adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
1313                 break;
1314             }
1315             case ItemPositionFlexStart:
1316                 break;
1317             case ItemPositionFlexEnd:
1318                 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child));
1319                 break;
1320             case ItemPositionCenter:
1321                 adjustAlignmentForChild(child, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) / 2);
1322                 break;
1323             case ItemPositionBaseline: {
1324                 // FIXME: If we get here in columns, we want the use the descent, except we currently can't get the ascent/descent of orthogonal children.
1325                 // https://bugs.webkit.org/show_bug.cgi?id=98076
1326                 LayoutUnit ascent = marginBoxAscentForChild(child);
1327                 LayoutUnit startOffset = maxAscent - ascent;
1328                 adjustAlignmentForChild(child, startOffset);
1329 
1330                 if (style()->flexWrap() == FlexWrapReverse)
1331                     minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, child) - startOffset);
1332                 break;
1333             }
1334             case ItemPositionSelfStart:
1335             case ItemPositionSelfEnd:
1336             case ItemPositionStart:
1337             case ItemPositionEnd:
1338             case ItemPositionLeft:
1339             case ItemPositionRight:
1340                 // FIXME: File a bug about implementing that. The extended grammar
1341                 // is not enabled by default so we shouldn't hit this codepath.
1342                 ASSERT_NOT_REACHED();
1343                 break;
1344             }
1345         }
1346         minMarginAfterBaselines.append(minMarginAfterBaseline);
1347     }
1348 
1349     if (style()->flexWrap() != FlexWrapReverse)
1350         return;
1351 
1352     // wrap-reverse flips the cross axis start and end. For baseline alignment, this means we
1353     // need to align the after edge of baseline elements with the after edge of the flex line.
1354     child = m_orderIterator.first();
1355     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1356         LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber];
1357         for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
1358             ASSERT(child);
1359             if (alignmentForChild(child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(child) && minMarginAfterBaseline)
1360                 adjustAlignmentForChild(child, minMarginAfterBaseline);
1361         }
1362     }
1363 }
1364 
applyStretchAlignmentToChild(RenderBox * child,LayoutUnit lineCrossAxisExtent)1365 void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox* child, LayoutUnit lineCrossAxisExtent)
1366 {
1367     if (!isColumnFlow() && child->style()->logicalHeight().isAuto()) {
1368         // FIXME: If the child has orthogonal flow, then it already has an override height set, so use it.
1369         if (!hasOrthogonalFlow(child)) {
1370             LayoutUnit heightBeforeStretching = needToStretchChildLogicalHeight(child) ? constrainedChildIntrinsicContentLogicalHeight(child) : child->logicalHeight();
1371             LayoutUnit stretchedLogicalHeight = heightBeforeStretching + availableAlignmentSpaceForChildBeforeStretching(lineCrossAxisExtent, child);
1372             ASSERT(!child->needsLayout());
1373             LayoutUnit desiredLogicalHeight = child->constrainLogicalHeightByMinMax(stretchedLogicalHeight, heightBeforeStretching - child->borderAndPaddingLogicalHeight());
1374 
1375             // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
1376             if (desiredLogicalHeight != child->logicalHeight()) {
1377                 child->setOverrideLogicalContentHeight(desiredLogicalHeight - child->borderAndPaddingLogicalHeight());
1378                 child->setLogicalHeight(0);
1379                 child->forceChildLayout();
1380             }
1381         }
1382     } else if (isColumnFlow() && child->style()->logicalWidth().isAuto()) {
1383         // FIXME: If the child doesn't have orthogonal flow, then it already has an override width set, so use it.
1384         if (hasOrthogonalFlow(child)) {
1385             LayoutUnit childWidth = std::max<LayoutUnit>(0, lineCrossAxisExtent - crossAxisMarginExtentForChild(child));
1386             childWidth = child->constrainLogicalWidthByMinMax(childWidth, childWidth, this);
1387 
1388             if (childWidth != child->logicalWidth()) {
1389                 child->setOverrideLogicalContentWidth(childWidth - child->borderAndPaddingLogicalWidth());
1390                 child->forceChildLayout();
1391             }
1392         }
1393     }
1394 }
1395 
flipForRightToLeftColumn()1396 void RenderFlexibleBox::flipForRightToLeftColumn()
1397 {
1398     if (style()->isLeftToRightDirection() || !isColumnFlow())
1399         return;
1400 
1401     LayoutUnit crossExtent = crossAxisExtent();
1402     for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
1403         if (child->isOutOfFlowPositioned())
1404             continue;
1405         LayoutPoint location = flowAwareLocationForChild(child);
1406         // For vertical flows, setFlowAwareLocationForChild will transpose x and y,
1407         // so using the y axis for a column cross axis extent is correct.
1408         location.setY(crossExtent - crossAxisExtentForChild(child) - location.y());
1409         setFlowAwareLocationForChild(child, location);
1410     }
1411 }
1412 
flipForWrapReverse(const Vector<LineContext> & lineContexts,LayoutUnit crossAxisStartEdge)1413 void RenderFlexibleBox::flipForWrapReverse(const Vector<LineContext>& lineContexts, LayoutUnit crossAxisStartEdge)
1414 {
1415     LayoutUnit contentExtent = crossAxisContentExtent();
1416     RenderBox* child = m_orderIterator.first();
1417     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1418         for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) {
1419             ASSERT(child);
1420             LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1421             LayoutUnit originalOffset = lineContexts[lineNumber].crossAxisOffset - crossAxisStartEdge;
1422             LayoutUnit newOffset = contentExtent - originalOffset - lineCrossAxisExtent;
1423             adjustAlignmentForChild(child, newOffset - originalOffset);
1424         }
1425     }
1426 }
1427 
1428 }
1429