Use Optional::valueOr() instead of Optional::value_or()
[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 "FlexibleBoxAlgorithm.h"
35 #include "LayoutRepainter.h"
36 #include "RenderChildIterator.h"
37 #include "RenderLayer.h"
38 #include "RenderView.h"
39 #include "RuntimeEnabledFeatures.h"
40 #include <limits>
41 #include <wtf/IsoMallocInlines.h>
42 #include <wtf/MathExtras.h>
43
44 namespace WebCore {
45
46 WTF_MAKE_ISO_ALLOCATED_IMPL(RenderFlexibleBox);
47
48 struct RenderFlexibleBox::LineContext {
49     LineContext(LayoutUnit crossAxisOffset, LayoutUnit crossAxisExtent, LayoutUnit maxAscent, Vector<FlexItem>&& flexItems)
50         : crossAxisOffset(crossAxisOffset)
51         , crossAxisExtent(crossAxisExtent)
52         , maxAscent(maxAscent)
53         , flexItems(flexItems)
54     {
55     }
56     
57     LayoutUnit crossAxisOffset;
58     LayoutUnit crossAxisExtent;
59     LayoutUnit maxAscent;
60     Vector<FlexItem> flexItems;
61 };
62
63 RenderFlexibleBox::RenderFlexibleBox(Element& element, RenderStyle&& style)
64     : RenderBlock(element, WTFMove(style), 0)
65 {
66     setChildrenInline(false); // All of our children must be block-level.
67 }
68
69 RenderFlexibleBox::RenderFlexibleBox(Document& document, RenderStyle&& style)
70     : RenderBlock(document, WTFMove(style), 0)
71 {
72     setChildrenInline(false); // All of our children must be block-level.
73 }
74
75 RenderFlexibleBox::~RenderFlexibleBox() = default;
76
77 const char* RenderFlexibleBox::renderName() const
78 {
79     return "RenderFlexibleBox";
80 }
81
82 void RenderFlexibleBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
83 {
84     LayoutUnit childMinWidth;
85     LayoutUnit childMaxWidth;
86     bool hadExcludedChildren = computePreferredWidthsForExcludedChildren(childMinWidth, childMaxWidth);
87
88     // FIXME: We're ignoring flex-basis here and we shouldn't. We can't start
89     // honoring it though until the flex shorthand stops setting it to 0. See
90     // https://bugs.webkit.org/show_bug.cgi?id=116117 and
91     // https://crbug.com/240765.
92     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
93         if (child->isOutOfFlowPositioned() || child->isExcludedFromNormalLayout())
94             continue;
95         
96         LayoutUnit margin = marginIntrinsicLogicalWidthForChild(*child);
97         
98         LayoutUnit minPreferredLogicalWidth;
99         LayoutUnit maxPreferredLogicalWidth;
100         computeChildPreferredLogicalWidths(*child, minPreferredLogicalWidth, maxPreferredLogicalWidth);
101         
102         minPreferredLogicalWidth += margin;
103         maxPreferredLogicalWidth += margin;
104
105         if (!isColumnFlow()) {
106             maxLogicalWidth += maxPreferredLogicalWidth;
107             if (isMultiline()) {
108                 // For multiline, the min preferred width is if you put a break between
109                 // each item.
110                 minLogicalWidth = std::max(minLogicalWidth, minPreferredLogicalWidth);
111             } else
112                 minLogicalWidth += minPreferredLogicalWidth;
113         } else {
114             minLogicalWidth = std::max(minPreferredLogicalWidth, minLogicalWidth);
115             maxLogicalWidth = std::max(maxPreferredLogicalWidth, maxLogicalWidth);
116         }
117     }
118     
119     maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
120     
121     // Due to negative margins, it is possible that we calculated a negative
122     // intrinsic width. Make sure that we never return a negative width.
123     minLogicalWidth = std::max(0_lu, minLogicalWidth);
124     maxLogicalWidth = std::max(0_lu, maxLogicalWidth);
125     
126     if (hadExcludedChildren) {
127         minLogicalWidth = std::max(minLogicalWidth, childMinWidth);
128         maxLogicalWidth = std::max(maxLogicalWidth, childMaxWidth);
129     }
130
131     LayoutUnit scrollbarWidth(scrollbarLogicalWidth());
132     maxLogicalWidth += scrollbarWidth;
133     minLogicalWidth += scrollbarWidth;
134 }
135
136 void RenderFlexibleBox::computePreferredLogicalWidths()
137 {
138     ASSERT(preferredLogicalWidthsDirty());
139
140     m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
141
142     const RenderStyle& styleToUse = style();
143     // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for width.
144     if (styleToUse.logicalWidth().isFixed() && styleToUse.logicalWidth().value() > 0)
145         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalWidth().value());
146     else
147         computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
148
149     // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for min-width.
150     if (styleToUse.logicalMinWidth().isFixed() && styleToUse.logicalMinWidth().value() > 0) {
151         m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMinWidth().value()));
152         m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMinWidth().value()));
153     }
154
155     // FIXME: This should probably be checking for isSpecified since you should be able to use percentage, calc or viewport relative values for maxWidth.
156     if (styleToUse.logicalMaxWidth().isFixed()) {
157         m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMaxWidth().value()));
158         m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMaxWidth().value()));
159     }
160
161     LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
162     m_minPreferredLogicalWidth += borderAndPadding;
163     m_maxPreferredLogicalWidth += borderAndPadding;
164
165     setPreferredLogicalWidthsDirty(false);
166 }
167
168 static int synthesizedBaselineFromContentBox(const RenderBox& box, LineDirectionMode direction)
169 {
170     return direction == HorizontalLine ? box.borderTop() + box.paddingTop() + box.contentHeight() : box.borderRight() + box.paddingRight() + box.contentWidth();
171 }
172
173 int RenderFlexibleBox::baselinePosition(FontBaseline, bool, LineDirectionMode direction, LinePositionMode) const
174 {
175     int baseline = firstLineBaseline().valueOr(synthesizedBaselineFromContentBox(*this, direction));
176
177     int marginAscent = direction == HorizontalLine ? marginTop() : marginRight();
178     return baseline + marginAscent;
179 }
180
181 Optional<int> RenderFlexibleBox::firstLineBaseline() const
182 {
183     if (isWritingModeRoot() || m_numberOfInFlowChildrenOnFirstLine <= 0)
184         return Optional<int>();
185     RenderBox* baselineChild = nullptr;
186     int childNumber = 0;
187     for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
188         if (m_orderIterator.shouldSkipChild(*child))
189             continue;
190         if (alignmentForChild(*child) == ItemPosition::Baseline && !hasAutoMarginsInCrossAxis(*child)) {
191             baselineChild = child;
192             break;
193         }
194         if (!baselineChild)
195             baselineChild = child;
196
197         ++childNumber;
198         if (childNumber == m_numberOfInFlowChildrenOnFirstLine)
199             break;
200     }
201
202     if (!baselineChild)
203         return Optional<int>();
204
205     if (!isColumnFlow() && hasOrthogonalFlow(*baselineChild))
206         return Optional<int>(crossAxisExtentForChild(*baselineChild) + baselineChild->logicalTop());
207     if (isColumnFlow() && !hasOrthogonalFlow(*baselineChild))
208         return Optional<int>(mainAxisExtentForChild(*baselineChild) + baselineChild->logicalTop());
209
210     Optional<int> baseline = baselineChild->firstLineBaseline();
211     if (!baseline) {
212         // FIXME: We should pass |direction| into firstLineBoxBaseline and stop bailing out if we're a writing mode root.
213         // This would also fix some cases where the flexbox is orthogonal to its container.
214         LineDirectionMode direction = isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
215         return Optional<int>(synthesizedBaselineFromContentBox(*baselineChild, direction) + baselineChild->logicalTop());
216     }
217
218     return Optional<int>(baseline.value() + baselineChild->logicalTop());
219 }
220
221 Optional<int> RenderFlexibleBox::inlineBlockBaseline(LineDirectionMode direction) const
222 {
223     if (Optional<int> baseline = firstLineBaseline())
224         return baseline;
225
226     int marginAscent = direction == HorizontalLine ? marginTop() : marginRight();
227     return synthesizedBaselineFromContentBox(*this, direction) + marginAscent;
228 }
229
230 static const StyleContentAlignmentData& contentAlignmentNormalBehavior()
231 {
232     // The justify-content property applies along the main axis, but since
233     // flexing in the main axis is controlled by flex, stretch behaves as
234     // flex-start (ignoring the specified fallback alignment, if any).
235     // https://drafts.csswg.org/css-align/#distribution-flex
236     static const StyleContentAlignmentData normalBehavior = { ContentPosition::Normal, ContentDistribution::Stretch};
237     return normalBehavior;
238 }
239
240 void RenderFlexibleBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
241 {
242     RenderBlock::styleDidChange(diff, oldStyle);
243     if (!oldStyle || diff != StyleDifference::Layout)
244         return;
245
246     if (oldStyle->resolvedAlignItems(selfAlignmentNormalBehavior()).position() == ItemPosition::Stretch) {
247         // Flex items that were previously stretching need to be relayed out so we
248         // can compute new available cross axis space. This is only necessary for
249         // stretching since other alignment values don't change the size of the
250         // box.
251         for (auto& child : childrenOfType<RenderBox>(*this)) {
252             ItemPosition previousAlignment = child.style().resolvedAlignSelf(oldStyle, selfAlignmentNormalBehavior()).position();
253             if (previousAlignment == ItemPosition::Stretch && previousAlignment != child.style().resolvedAlignSelf(&style(), selfAlignmentNormalBehavior()).position())
254                 child.setChildNeedsLayout(MarkOnlyThis);
255         }
256     }
257 }
258
259 void RenderFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
260 {
261     ASSERT(needsLayout());
262
263     if (!relayoutChildren && simplifiedLayout())
264         return;
265
266     LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
267
268     m_relaidOutChildren.clear();
269     
270     bool oldInLayout = m_inLayout;
271     m_inLayout = true;
272     
273     if (recomputeLogicalWidth())
274         relayoutChildren = true;
275
276     LayoutUnit previousHeight = logicalHeight();
277     setLogicalHeight(borderAndPaddingLogicalHeight() + scrollbarLogicalHeight());
278     {
279         LayoutStateMaintainer statePusher(*this, locationOffset(), hasTransform() || hasReflection() || style().isFlippedBlocksWritingMode());
280
281         preparePaginationBeforeBlockLayout(relayoutChildren);
282
283         m_numberOfInFlowChildrenOnFirstLine = -1;
284
285         beginUpdateScrollInfoAfterLayoutTransaction();
286
287         prepareOrderIteratorAndMargins();
288
289         // Fieldsets need to find their legend and position it inside the border of the object.
290         // The legend then gets skipped during normal layout. The same is true for ruby text.
291         // It doesn't get included in the normal layout process but is instead skipped.
292         layoutExcludedChildren(relayoutChildren);
293
294         ChildFrameRects oldChildRects;
295         appendChildFrameRects(oldChildRects);
296
297         layoutFlexItems(relayoutChildren);
298
299         endAndCommitUpdateScrollInfoAfterLayoutTransaction();
300
301         if (logicalHeight() != previousHeight)
302             relayoutChildren = true;
303
304         layoutPositionedObjects(relayoutChildren || isDocumentElementRenderer());
305
306         repaintChildrenDuringLayoutIfMoved(oldChildRects);
307         // FIXME: css3/flexbox/repaint-rtl-column.html seems to repaint more overflow than it needs to.
308         computeOverflow(clientLogicalBottomAfterRepositioning());
309     }
310     updateLayerTransform();
311
312     // We have to reset this, because changes to our ancestors' style can affect
313     // this value. Also, this needs to be before we call updateAfterLayout, as
314     // that function may re-enter this one.
315     m_hasDefiniteHeight = SizeDefiniteness::Unknown;
316
317     // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if we overflow or not.
318     updateScrollInfoAfterLayout();
319
320     repainter.repaintAfterLayout();
321
322     clearNeedsLayout();
323     
324     m_inLayout = oldInLayout;
325 }
326
327 void RenderFlexibleBox::appendChildFrameRects(ChildFrameRects& childFrameRects)
328 {
329     for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
330         if (!child->isOutOfFlowPositioned())
331             childFrameRects.append(child->frameRect());
332     }
333 }
334
335 void RenderFlexibleBox::repaintChildrenDuringLayoutIfMoved(const ChildFrameRects& oldChildRects)
336 {
337     size_t childIndex = 0;
338     for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
339         if (child->isOutOfFlowPositioned())
340             continue;
341
342         // If the child moved, we have to repaint it as well as any floating/positioned
343         // descendants. An exception is if we need a layout. In this case, we know we're going to
344         // repaint ourselves (and the child) anyway.
345         if (!selfNeedsLayout() && child->checkForRepaintDuringLayout())
346             child->repaintDuringLayoutIfMoved(oldChildRects[childIndex]);
347         ++childIndex;
348     }
349     ASSERT(childIndex == oldChildRects.size());
350 }
351
352 void RenderFlexibleBox::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset, PaintInfo& paintInfoForChild, bool usePrintRect)
353 {
354     for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) {
355         if (!paintChild(*child, paintInfo, paintOffset, paintInfoForChild, usePrintRect, PaintAsInlineBlock))
356             return;
357     }
358 }
359
360 void RenderFlexibleBox::repositionLogicalHeightDependentFlexItems(Vector<LineContext>& lineContexts)
361 {
362     LayoutUnit crossAxisStartEdge = lineContexts.isEmpty() ? 0_lu : lineContexts[0].crossAxisOffset;
363     alignFlexLines(lineContexts);
364     
365     alignChildren(lineContexts);
366     
367     if (style().flexWrap() == FlexWrap::Reverse)
368         flipForWrapReverse(lineContexts, crossAxisStartEdge);
369     
370     // direction:rtl + flex-direction:column means the cross-axis direction is
371     // flipped.
372     flipForRightToLeftColumn(lineContexts);
373 }
374
375 LayoutUnit RenderFlexibleBox::clientLogicalBottomAfterRepositioning()
376 {
377     LayoutUnit maxChildLogicalBottom;
378     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
379         if (child->isOutOfFlowPositioned())
380             continue;
381         LayoutUnit childLogicalBottom = logicalTopForChild(*child) + logicalHeightForChild(*child) + marginAfterForChild(*child);
382         maxChildLogicalBottom = std::max(maxChildLogicalBottom, childLogicalBottom);
383     }
384     return std::max(clientLogicalBottom(), maxChildLogicalBottom + paddingAfter());
385 }
386
387 bool RenderFlexibleBox::hasOrthogonalFlow(const RenderBox& child) const
388 {
389     return isHorizontalFlow() != child.isHorizontalWritingMode();
390 }
391
392 bool RenderFlexibleBox::isColumnFlow() const
393 {
394     return style().isColumnFlexDirection();
395 }
396
397 bool RenderFlexibleBox::isHorizontalFlow() const
398 {
399     if (isHorizontalWritingMode())
400         return !isColumnFlow();
401     return isColumnFlow();
402 }
403
404 bool RenderFlexibleBox::isLeftToRightFlow() const
405 {
406     if (isColumnFlow())
407         return style().writingMode() == TopToBottomWritingMode || style().writingMode() == LeftToRightWritingMode;
408     return style().isLeftToRightDirection() ^ (style().flexDirection() == FlexDirection::RowReverse);
409 }
410
411 bool RenderFlexibleBox::isMultiline() const
412 {
413     return style().flexWrap() != FlexWrap::NoWrap;
414 }
415
416 Length RenderFlexibleBox::flexBasisForChild(const RenderBox& child) const
417 {
418     Length flexLength = child.style().flexBasis();
419     if (flexLength.isAuto())
420         flexLength = isHorizontalFlow() ? child.style().width() : child.style().height();
421     return flexLength;
422 }
423
424 LayoutUnit RenderFlexibleBox::crossAxisExtentForChild(const RenderBox& child) const
425 {
426     return isHorizontalFlow() ? child.height() : child.width();
427 }
428
429 LayoutUnit RenderFlexibleBox::cachedChildIntrinsicContentLogicalHeight(const RenderBox& child) const
430 {
431     if (child.isRenderReplaced())
432         return downcast<RenderReplaced>(child).intrinsicLogicalHeight();
433     
434     if (m_intrinsicContentLogicalHeights.contains(&child))
435         return m_intrinsicContentLogicalHeights.get(&child);
436     
437     return child.contentLogicalHeight();
438 }
439
440 void RenderFlexibleBox::setCachedChildIntrinsicContentLogicalHeight(const RenderBox& child, LayoutUnit height)
441 {
442     if (child.isRenderReplaced())
443         return; // Replaced elements know their intrinsic height already, so save space by not caching.
444     m_intrinsicContentLogicalHeights.set(&child, height);
445 }
446
447 void RenderFlexibleBox::clearCachedChildIntrinsicContentLogicalHeight(const RenderBox& child)
448 {
449     if (child.isRenderReplaced())
450         return; // Replaced elements know their intrinsic height already, so nothing to do.
451     m_intrinsicContentLogicalHeights.remove(&child);
452 }
453
454 LayoutUnit RenderFlexibleBox::childIntrinsicLogicalHeight(const RenderBox& child) const
455 {
456     // This should only be called if the logical height is the cross size
457     ASSERT(!hasOrthogonalFlow(child));
458     if (needToStretchChildLogicalHeight(child)) {
459         LayoutUnit childContentHeight = cachedChildIntrinsicContentLogicalHeight(child);
460         LayoutUnit childLogicalHeight = childContentHeight + child.scrollbarLogicalHeight() + child.borderAndPaddingLogicalHeight();
461         return child.constrainLogicalHeightByMinMax(childLogicalHeight, childContentHeight);
462     }
463     return child.logicalHeight();
464 }
465
466 LayoutUnit RenderFlexibleBox::childIntrinsicLogicalWidth(const RenderBox& child) const
467 {
468     // This should only be called if the logical width is the cross size
469     ASSERT(hasOrthogonalFlow(child));
470     // If our height is auto, make sure that our returned height is unaffected by
471     // earlier layouts by returning the max preferred logical width
472     if (!crossAxisLengthIsDefinite(child, child.style().logicalWidth()))
473         return child.maxPreferredLogicalWidth();
474     return child.logicalWidth();
475 }
476
477 LayoutUnit RenderFlexibleBox::crossAxisIntrinsicExtentForChild(const RenderBox& child) const
478 {
479     return hasOrthogonalFlow(child) ? childIntrinsicLogicalWidth(child) : childIntrinsicLogicalHeight(child);
480 }
481
482 LayoutUnit RenderFlexibleBox::mainAxisExtentForChild(const RenderBox& child) const
483 {
484     return isHorizontalFlow() ? child.size().width() : child.size().height();
485 }
486
487 LayoutUnit RenderFlexibleBox::mainAxisContentExtentForChildIncludingScrollbar(const RenderBox& child) const
488 {
489     return isHorizontalFlow() ? child.contentWidth() + child.verticalScrollbarWidth() : child.contentHeight() + child.horizontalScrollbarHeight();
490 }
491
492 LayoutUnit RenderFlexibleBox::crossAxisExtent() const
493 {
494     return isHorizontalFlow() ? size().height() : size().width();
495 }
496
497 LayoutUnit RenderFlexibleBox::mainAxisExtent() const
498 {
499     return isHorizontalFlow() ? size().width() : size().height();
500 }
501
502 LayoutUnit RenderFlexibleBox::crossAxisContentExtent() const
503 {
504     return isHorizontalFlow() ? contentHeight() : contentWidth();
505 }
506
507 LayoutUnit RenderFlexibleBox::mainAxisContentExtent(LayoutUnit contentLogicalHeight)
508 {
509     if (isColumnFlow()) {
510         LayoutUnit borderPaddingAndScrollbar = borderAndPaddingLogicalHeight() + scrollbarLogicalHeight();
511         LayoutUnit borderBoxLogicalHeight = contentLogicalHeight + borderPaddingAndScrollbar;
512         auto computedValues = computeLogicalHeight(borderBoxLogicalHeight, logicalTop());
513         if (computedValues.m_extent == LayoutUnit::max())
514             return computedValues.m_extent;
515         return std::max(0_lu, computedValues.m_extent - borderPaddingAndScrollbar);
516     }
517     return contentLogicalWidth();
518 }
519
520 Optional<LayoutUnit> RenderFlexibleBox::computeMainAxisExtentForChild(const RenderBox& child, SizeType sizeType, const Length& size)
521 {
522     // If we have a horizontal flow, that means the main size is the width.
523     // That's the logical width for horizontal writing modes, and the logical
524     // height in vertical writing modes. For a vertical flow, main size is the
525     // height, so it's the inverse. So we need the logical width if we have a
526     // horizontal flow and horizontal writing mode, or vertical flow and vertical
527     // writing mode. Otherwise we need the logical height.
528     if (isHorizontalFlow() != child.style().isHorizontalWritingMode()) {
529         // We don't have to check for "auto" here - computeContentLogicalHeight
530         // will just return a null Optional for that case anyway. It's safe to access
531         // scrollbarLogicalHeight here because ComputeNextFlexLine will have
532         // already forced layout on the child. We previously did a layout out the child
533         // if necessary (see ComputeNextFlexLine and the call to
534         // childHasIntrinsicMainAxisSize) so we can be sure that the two height
535         // calls here will return up-to-date data.
536         Optional<LayoutUnit> height = child.computeContentLogicalHeight(sizeType, size, cachedChildIntrinsicContentLogicalHeight(child));
537         if (!height)
538             return height;
539         return height.value() + child.scrollbarLogicalHeight();
540     }
541
542     // computeLogicalWidth always re-computes the intrinsic widths. However, when
543     // our logical width is auto, we can just use our cached value. So let's do
544     // that here. (Compare code in LayoutBlock::computePreferredLogicalWidths)
545     LayoutUnit borderAndPadding = child.borderAndPaddingLogicalWidth();
546     if (child.style().logicalWidth().isAuto() && !child.hasAspectRatio()) {
547         if (size.type() == MinContent)
548             return child.minPreferredLogicalWidth() - borderAndPadding;
549         if (size.type() == MaxContent)
550             return child.maxPreferredLogicalWidth() - borderAndPadding;
551     }
552     
553     // FIXME: Figure out how this should work for regions and pass in the appropriate values.
554     RenderFragmentContainer* fragment = nullptr;
555     return child.computeLogicalWidthInFragmentUsing(sizeType, size, contentLogicalWidth(), *this, fragment) - borderAndPadding;
556 }
557
558     
559 WritingMode RenderFlexibleBox::transformedWritingMode() const
560 {
561     WritingMode mode = style().writingMode();
562     if (!isColumnFlow())
563         return mode;
564     
565     switch (mode) {
566     case TopToBottomWritingMode:
567     case BottomToTopWritingMode:
568         return style().isLeftToRightDirection() ? LeftToRightWritingMode : RightToLeftWritingMode;
569     case LeftToRightWritingMode:
570     case RightToLeftWritingMode:
571         return style().isLeftToRightDirection() ? TopToBottomWritingMode : BottomToTopWritingMode;
572     }
573     ASSERT_NOT_REACHED();
574     return TopToBottomWritingMode;
575 }
576
577 LayoutUnit RenderFlexibleBox::flowAwareBorderStart() const
578 {
579     if (isHorizontalFlow())
580         return isLeftToRightFlow() ? borderLeft() : borderRight();
581     return isLeftToRightFlow() ? borderTop() : borderBottom();
582 }
583
584 LayoutUnit RenderFlexibleBox::flowAwareBorderEnd() const
585 {
586     if (isHorizontalFlow())
587         return isLeftToRightFlow() ? borderRight() : borderLeft();
588     return isLeftToRightFlow() ? borderBottom() : borderTop();
589 }
590
591 LayoutUnit RenderFlexibleBox::flowAwareBorderBefore() const
592 {
593     switch (transformedWritingMode()) {
594     case TopToBottomWritingMode:
595         return borderTop();
596     case BottomToTopWritingMode:
597         return borderBottom();
598     case LeftToRightWritingMode:
599         return borderLeft();
600     case RightToLeftWritingMode:
601         return borderRight();
602     }
603     ASSERT_NOT_REACHED();
604     return borderTop();
605 }
606
607 LayoutUnit RenderFlexibleBox::flowAwareBorderAfter() const
608 {
609     switch (transformedWritingMode()) {
610     case TopToBottomWritingMode:
611         return borderBottom();
612     case BottomToTopWritingMode:
613         return borderTop();
614     case LeftToRightWritingMode:
615         return borderRight();
616     case RightToLeftWritingMode:
617         return borderLeft();
618     }
619     ASSERT_NOT_REACHED();
620     return borderTop();
621 }
622
623 LayoutUnit RenderFlexibleBox::flowAwarePaddingStart() const
624 {
625     if (isHorizontalFlow())
626         return isLeftToRightFlow() ? paddingLeft() : paddingRight();
627     return isLeftToRightFlow() ? paddingTop() : paddingBottom();
628 }
629
630 LayoutUnit RenderFlexibleBox::flowAwarePaddingEnd() const
631 {
632     if (isHorizontalFlow())
633         return isLeftToRightFlow() ? paddingRight() : paddingLeft();
634     return isLeftToRightFlow() ? paddingBottom() : paddingTop();
635 }
636
637 LayoutUnit RenderFlexibleBox::flowAwarePaddingBefore() const
638 {
639     switch (transformedWritingMode()) {
640     case TopToBottomWritingMode:
641         return paddingTop();
642     case BottomToTopWritingMode:
643         return paddingBottom();
644     case LeftToRightWritingMode:
645         return paddingLeft();
646     case RightToLeftWritingMode:
647         return paddingRight();
648     }
649     ASSERT_NOT_REACHED();
650     return paddingTop();
651 }
652
653 LayoutUnit RenderFlexibleBox::flowAwarePaddingAfter() const
654 {
655     switch (transformedWritingMode()) {
656     case TopToBottomWritingMode:
657         return paddingBottom();
658     case BottomToTopWritingMode:
659         return paddingTop();
660     case LeftToRightWritingMode:
661         return paddingRight();
662     case RightToLeftWritingMode:
663         return paddingLeft();
664     }
665     ASSERT_NOT_REACHED();
666     return paddingTop();
667 }
668
669 LayoutUnit RenderFlexibleBox::flowAwareMarginStartForChild(const RenderBox& child) const
670 {
671     if (isHorizontalFlow())
672         return isLeftToRightFlow() ? child.marginLeft() : child.marginRight();
673     return isLeftToRightFlow() ? child.marginTop() : child.marginBottom();
674 }
675
676 LayoutUnit RenderFlexibleBox::flowAwareMarginEndForChild(const RenderBox& child) const
677 {
678     if (isHorizontalFlow())
679         return isLeftToRightFlow() ? child.marginRight() : child.marginLeft();
680     return isLeftToRightFlow() ? child.marginBottom() : child.marginTop();
681 }
682
683 LayoutUnit RenderFlexibleBox::flowAwareMarginBeforeForChild(const RenderBox& child) const
684 {
685     switch (transformedWritingMode()) {
686     case TopToBottomWritingMode:
687         return child.marginTop();
688     case BottomToTopWritingMode:
689         return child.marginBottom();
690     case LeftToRightWritingMode:
691         return child.marginLeft();
692     case RightToLeftWritingMode:
693         return child.marginRight();
694     }
695     ASSERT_NOT_REACHED();
696     return marginTop();
697 }
698
699 LayoutUnit RenderFlexibleBox::crossAxisMarginExtentForChild(const RenderBox& child) const
700 {
701     return isHorizontalFlow() ? child.verticalMarginExtent() : child.horizontalMarginExtent();
702 }
703
704 LayoutUnit RenderFlexibleBox::crossAxisScrollbarExtent() const
705 {
706     return isHorizontalFlow() ? horizontalScrollbarHeight() : verticalScrollbarWidth();
707 }
708
709 LayoutPoint RenderFlexibleBox::flowAwareLocationForChild(const RenderBox& child) const
710 {
711     return isHorizontalFlow() ? child.location() : child.location().transposedPoint();
712 }
713
714 bool RenderFlexibleBox::useChildAspectRatio(const RenderBox& child) const
715 {
716     if (!child.hasAspectRatio())
717         return false;
718     if (!child.intrinsicSize().height()) {
719         // We can't compute a ratio in this case.
720         return false;
721     }
722     Length crossSize;
723     if (isHorizontalFlow())
724         crossSize = child.style().height();
725     else
726         crossSize = child.style().width();
727     return crossAxisLengthIsDefinite(child, crossSize);
728 }
729
730     
731 LayoutUnit RenderFlexibleBox::computeMainSizeFromAspectRatioUsing(const RenderBox& child, Length crossSizeLength) const
732 {
733     ASSERT(child.hasAspectRatio());
734     ASSERT(child.intrinsicSize().height());
735     
736     Optional<LayoutUnit> crossSize;
737     if (crossSizeLength.isFixed())
738         crossSize = LayoutUnit(crossSizeLength.value());
739     else {
740         ASSERT(crossSizeLength.isPercentOrCalculated());
741         crossSize = hasOrthogonalFlow(child) ? adjustBorderBoxLogicalWidthForBoxSizing(valueForLength(crossSizeLength, contentWidth())) : child.computePercentageLogicalHeight(crossSizeLength);
742         if (!crossSize)
743             return 0_lu;
744     }
745     
746     const LayoutSize& childIntrinsicSize = child.intrinsicSize();
747     double ratio = childIntrinsicSize.width().toFloat() /
748     childIntrinsicSize.height().toFloat();
749     if (isHorizontalFlow())
750         return LayoutUnit(crossSize.value() * ratio);
751     return LayoutUnit(crossSize.value() / ratio);
752 }
753
754 void RenderFlexibleBox::setFlowAwareLocationForChild(RenderBox& child, const LayoutPoint& location)
755 {
756     if (isHorizontalFlow())
757         child.setLocation(location);
758     else
759         child.setLocation(location.transposedPoint());
760 }
761     
762 bool RenderFlexibleBox::mainAxisLengthIsDefinite(const RenderBox& child, const Length& flexBasis) const
763 {
764     if (flexBasis.isAuto())
765         return false;
766     if (flexBasis.isPercentOrCalculated()) {
767         if (!isColumnFlow() || m_hasDefiniteHeight == SizeDefiniteness::Definite)
768             return true;
769         if (m_hasDefiniteHeight == SizeDefiniteness::Indefinite)
770             return false;
771         bool definite = child.computePercentageLogicalHeight(flexBasis) != WTF::nullopt;
772         if (m_inLayout) {
773             // We can reach this code even while we're not laying ourselves out, such
774             // as from mainSizeForPercentageResolution.
775             m_hasDefiniteHeight = definite ? SizeDefiniteness::Definite : SizeDefiniteness::Indefinite;
776         }
777         return definite;
778     }
779     return true;
780 }
781
782 bool RenderFlexibleBox::crossAxisLengthIsDefinite(const RenderBox& child, const Length& length) const
783 {
784     if (length.isAuto())
785         return false;
786     if (length.isPercentOrCalculated()) {
787         if (hasOrthogonalFlow(child) || m_hasDefiniteHeight == SizeDefiniteness::Definite)
788             return true;
789         if (m_hasDefiniteHeight == SizeDefiniteness::Indefinite)
790             return false;
791         bool definite = bool(child.computePercentageLogicalHeight(length));
792         m_hasDefiniteHeight = definite ? SizeDefiniteness::Definite : SizeDefiniteness::Indefinite;
793         return definite;
794     }
795     // FIXME: Eventually we should support other types of sizes here.
796     // Requires updating computeMainSizeFromAspectRatioUsing.
797     return length.isFixed();
798 }
799
800 void RenderFlexibleBox::cacheChildMainSize(const RenderBox& child)
801 {
802     ASSERT(!child.needsLayout());
803     LayoutUnit mainSize;
804     if (hasOrthogonalFlow(child))
805         mainSize = child.logicalHeight();
806     else
807         mainSize = child.maxPreferredLogicalWidth();
808     m_intrinsicSizeAlongMainAxis.set(&child, mainSize);
809     m_relaidOutChildren.add(&child);
810 }
811
812 void RenderFlexibleBox::clearCachedMainSizeForChild(const RenderBox& child)
813 {
814     m_intrinsicSizeAlongMainAxis.remove(&child);
815 }
816
817     
818 LayoutUnit RenderFlexibleBox::computeInnerFlexBaseSizeForChild(RenderBox& child, LayoutUnit mainAxisBorderAndPadding, bool relayoutChildren)
819 {
820     child.clearOverrideContentSize();
821     
822     Length flexBasis = flexBasisForChild(child);
823     if (mainAxisLengthIsDefinite(child, flexBasis))
824         return std::max(0_lu, computeMainAxisExtentForChild(child, MainOrPreferredSize, flexBasis).value());
825
826     // The flex basis is indefinite (=auto), so we need to compute the actual
827     // width of the child. For the logical width axis we just use the preferred
828     // width; for the height we need to lay out the child.
829     LayoutUnit mainAxisExtent;
830     if (hasOrthogonalFlow(child)) {
831         updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
832         if (child.needsLayout() || relayoutChildren || !m_intrinsicSizeAlongMainAxis.contains(&child)) {
833             if (!child.needsLayout())
834                 child.setChildNeedsLayout(MarkOnlyThis);
835             child.layoutIfNeeded();
836             cacheChildMainSize(child);
837         }
838         mainAxisExtent = m_intrinsicSizeAlongMainAxis.get(&child);
839     } else {
840         // We don't need to add scrollbarLogicalWidth here because the preferred
841         // width includes the scrollbar, even for overflow: auto.
842         mainAxisExtent = child.maxPreferredLogicalWidth();
843     }
844     return mainAxisExtent - mainAxisBorderAndPadding;
845 }
846
847 void RenderFlexibleBox::layoutFlexItems(bool relayoutChildren)
848 {
849     Vector<LineContext> lineContexts;
850     LayoutUnit sumFlexBaseSize;
851     double totalFlexGrow;
852     double totalFlexShrink;
853     double totalWeightedFlexShrink;
854     LayoutUnit sumHypotheticalMainSize;
855     
856     // Set up our master list of flex items. All of the rest of the algorithm
857     // should work off this list of a subset.
858     // TODO(cbiesinger): That second part is not yet true.
859     Vector<FlexItem> allItems;
860     m_orderIterator.first();
861     for (RenderBox* child = m_orderIterator.currentChild(); child; child = m_orderIterator.next()) {
862         if (m_orderIterator.shouldSkipChild(*child)) {
863             // Out-of-flow children are not flex items, so we skip them here.
864             if (child->isOutOfFlowPositioned())
865                 prepareChildForPositionedLayout(*child);
866             continue;
867         }
868         allItems.append(constructFlexItem(*child, relayoutChildren));
869     }
870     
871     const LayoutUnit lineBreakLength = mainAxisContentExtent(LayoutUnit::max());
872     FlexLayoutAlgorithm flexAlgorithm(style(), lineBreakLength, allItems);
873     LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore();
874     Vector<FlexItem> lineItems;
875     size_t nextIndex = 0;
876     while (flexAlgorithm.computeNextFlexLine(nextIndex, lineItems, sumFlexBaseSize, totalFlexGrow, totalFlexShrink, totalWeightedFlexShrink, sumHypotheticalMainSize)) {
877         LayoutUnit containerMainInnerSize = mainAxisContentExtent(sumHypotheticalMainSize);
878         // availableFreeSpace is the initial amount of free space in this flexbox.
879         // remainingFreeSpace starts out at the same value but as we place and lay
880         // out flex items we subtract from it. Note that both values can be
881         // negative.
882         LayoutUnit remainingFreeSpace = containerMainInnerSize - sumFlexBaseSize;
883         FlexSign flexSign = (sumHypotheticalMainSize < containerMainInnerSize) ? PositiveFlexibility : NegativeFlexibility;
884         freezeInflexibleItems(flexSign, lineItems, remainingFreeSpace, totalFlexGrow, totalFlexShrink, totalWeightedFlexShrink);
885         // The initial free space gets calculated after freezing inflexible items.
886         // https://drafts.csswg.org/css-flexbox/#resolve-flexible-lengths step 3
887         const LayoutUnit initialFreeSpace = remainingFreeSpace;
888         while (!resolveFlexibleLengths(flexSign, lineItems, initialFreeSpace, remainingFreeSpace, totalFlexGrow, totalFlexShrink, totalWeightedFlexShrink)) {
889             ASSERT(totalFlexGrow >= 0);
890             ASSERT(totalWeightedFlexShrink >= 0);
891         }
892         
893         // Recalculate the remaining free space. The adjustment for flex factors
894         // between 0..1 means we can't just use remainingFreeSpace here.
895         remainingFreeSpace = containerMainInnerSize;
896         for (size_t i = 0; i < lineItems.size(); ++i) {
897             FlexItem& flexItem = lineItems[i];
898             ASSERT(!flexItem.box.isOutOfFlowPositioned());
899             remainingFreeSpace -= flexItem.flexedMarginBoxSize();
900         }
901         // This will std::move lineItems into a newly-created LineContext.
902         layoutAndPlaceChildren(crossAxisOffset, lineItems, remainingFreeSpace, relayoutChildren, lineContexts);
903     }
904
905     if (hasLineIfEmpty()) {
906         // Even if computeNextFlexLine returns true, the flexbox might not have
907         // a line because all our children might be out of flow positioned.
908         // Instead of just checking if we have a line, make sure the flexbox
909         // has at least a line's worth of height to cover this case.
910         LayoutUnit minHeight = borderAndPaddingLogicalHeight() + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes) + scrollbarLogicalHeight();
911         if (size().height() < minHeight)
912             setLogicalHeight(minHeight);
913     }
914     
915     updateLogicalHeight();
916     repositionLogicalHeightDependentFlexItems(lineContexts);
917 }
918
919 LayoutUnit RenderFlexibleBox::autoMarginOffsetInMainAxis(const Vector<FlexItem>& children, LayoutUnit& availableFreeSpace)
920 {
921     if (availableFreeSpace <= 0_lu)
922         return 0_lu;
923     
924     int numberOfAutoMargins = 0;
925     bool isHorizontal = isHorizontalFlow();
926     for (size_t i = 0; i < children.size(); ++i) {
927         const auto& child = children[i].box;
928         ASSERT(!child.isOutOfFlowPositioned());
929         if (isHorizontal) {
930             if (child.style().marginLeft().isAuto())
931                 ++numberOfAutoMargins;
932             if (child.style().marginRight().isAuto())
933                 ++numberOfAutoMargins;
934         } else {
935             if (child.style().marginTop().isAuto())
936                 ++numberOfAutoMargins;
937             if (child.style().marginBottom().isAuto())
938                 ++numberOfAutoMargins;
939         }
940     }
941     if (!numberOfAutoMargins)
942         return 0_lu;
943     
944     LayoutUnit sizeOfAutoMargin = availableFreeSpace / numberOfAutoMargins;
945     availableFreeSpace = 0_lu;
946     return sizeOfAutoMargin;
947 }
948
949 void RenderFlexibleBox::updateAutoMarginsInMainAxis(RenderBox& child, LayoutUnit autoMarginOffset)
950 {
951     ASSERT(autoMarginOffset >= 0_lu);
952     
953     if (isHorizontalFlow()) {
954         if (child.style().marginLeft().isAuto())
955             child.setMarginLeft(autoMarginOffset);
956         if (child.style().marginRight().isAuto())
957             child.setMarginRight(autoMarginOffset);
958     } else {
959         if (child.style().marginTop().isAuto())
960             child.setMarginTop(autoMarginOffset);
961         if (child.style().marginBottom().isAuto())
962             child.setMarginBottom(autoMarginOffset);
963     }
964 }
965
966 bool RenderFlexibleBox::hasAutoMarginsInCrossAxis(const RenderBox& child) const
967 {
968     if (isHorizontalFlow())
969         return child.style().marginTop().isAuto() || child.style().marginBottom().isAuto();
970     return child.style().marginLeft().isAuto() || child.style().marginRight().isAuto();
971 }
972
973 LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, const RenderBox& child)
974 {
975     ASSERT(!child.isOutOfFlowPositioned());
976     LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child);
977     return lineCrossAxisExtent - childCrossExtent;
978 }
979
980 bool RenderFlexibleBox::updateAutoMarginsInCrossAxis(RenderBox& child, LayoutUnit availableAlignmentSpace)
981 {
982     ASSERT(!child.isOutOfFlowPositioned());
983     ASSERT(availableAlignmentSpace >= 0_lu);
984     
985     bool isHorizontal = isHorizontalFlow();
986     Length topOrLeft = isHorizontal ? child.style().marginTop() : child.style().marginLeft();
987     Length bottomOrRight = isHorizontal ? child.style().marginBottom() : child.style().marginRight();
988     if (topOrLeft.isAuto() && bottomOrRight.isAuto()) {
989         adjustAlignmentForChild(child, availableAlignmentSpace / 2);
990         if (isHorizontal) {
991             child.setMarginTop(availableAlignmentSpace / 2);
992             child.setMarginBottom(availableAlignmentSpace / 2);
993         } else {
994             child.setMarginLeft(availableAlignmentSpace / 2);
995             child.setMarginRight(availableAlignmentSpace / 2);
996         }
997         return true;
998     }
999     bool shouldAdjustTopOrLeft = true;
1000     if (isColumnFlow() && !child.style().isLeftToRightDirection()) {
1001         // For column flows, only make this adjustment if topOrLeft corresponds to
1002         // the "before" margin, so that flipForRightToLeftColumn will do the right
1003         // thing.
1004         shouldAdjustTopOrLeft = false;
1005     }
1006     if (!isColumnFlow() && child.style().isFlippedBlocksWritingMode()) {
1007         // If we are a flipped writing mode, we need to adjust the opposite side.
1008         // This is only needed for row flows because this only affects the
1009         // block-direction axis.
1010         shouldAdjustTopOrLeft = false;
1011     }
1012     
1013     if (topOrLeft.isAuto()) {
1014         if (shouldAdjustTopOrLeft)
1015             adjustAlignmentForChild(child, availableAlignmentSpace);
1016         
1017         if (isHorizontal)
1018             child.setMarginTop(availableAlignmentSpace);
1019         else
1020             child.setMarginLeft(availableAlignmentSpace);
1021         return true;
1022     }
1023
1024     if (bottomOrRight.isAuto()) {
1025         if (!shouldAdjustTopOrLeft)
1026             adjustAlignmentForChild(child, availableAlignmentSpace);
1027         
1028         if (isHorizontal)
1029             child.setMarginBottom(availableAlignmentSpace);
1030         else
1031             child.setMarginRight(availableAlignmentSpace);
1032         return true;
1033     }
1034     return false;
1035 }
1036
1037 LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(const RenderBox& child)
1038 {
1039     LayoutUnit ascent = child.firstLineBaseline().valueOr(crossAxisExtentForChild(child));
1040     return ascent + flowAwareMarginBeforeForChild(child);
1041 }
1042
1043 LayoutUnit RenderFlexibleBox::computeChildMarginValue(Length margin)
1044 {
1045     // When resolving the margins, we use the content size for resolving percent and calc (for percents in calc expressions) margins.
1046     // Fortunately, percent margins are always computed with respect to the block's width, even for margin-top and margin-bottom.
1047     LayoutUnit availableSize = contentLogicalWidth();
1048     return minimumValueForLength(margin, availableSize);
1049 }
1050
1051 void RenderFlexibleBox::prepareOrderIteratorAndMargins()
1052 {
1053     OrderIteratorPopulator populator(m_orderIterator);
1054
1055     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1056         if (!populator.collectChild(*child))
1057             continue;
1058
1059         // Before running the flex algorithm, 'auto' has a margin of 0.
1060         // Also, if we're not auto sizing, we don't do a layout that computes the start/end margins.
1061         if (isHorizontalFlow()) {
1062             child->setMarginLeft(computeChildMarginValue(child->style().marginLeft()));
1063             child->setMarginRight(computeChildMarginValue(child->style().marginRight()));
1064         } else {
1065             child->setMarginTop(computeChildMarginValue(child->style().marginTop()));
1066             child->setMarginBottom(computeChildMarginValue(child->style().marginBottom()));
1067         }
1068     }
1069 }
1070
1071 LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(const RenderBox& child, LayoutUnit childSize)
1072 {
1073     Length max = isHorizontalFlow() ? child.style().maxWidth() : child.style().maxHeight();
1074     Optional<LayoutUnit> maxExtent = WTF::nullopt;
1075     if (max.isSpecifiedOrIntrinsic()) {
1076         maxExtent = computeMainAxisExtentForChild(child, MaxSize, max);
1077         childSize = std::min(childSize, maxExtent.valueOr(childSize));
1078     }
1079
1080     Length min = isHorizontalFlow() ? child.style().minWidth() : child.style().minHeight();
1081     if (min.isSpecifiedOrIntrinsic())
1082         return std::max(childSize, std::max(0_lu, computeMainAxisExtentForChild(child, MinSize, min).valueOr(childSize)));
1083     
1084     if (!isFlexibleBoxImpl() && min.isAuto() && mainAxisOverflowForChild(child) == Overflow::Visible && !(isColumnFlow() && is<RenderFlexibleBox>(child))) {
1085         // FIXME: For now, we do not handle min-height: auto for nested
1086         // column flexboxes. We need to implement
1087         // https://drafts.csswg.org/css-flexbox/#intrinsic-sizes before that
1088         // produces reasonable results. Tracking bug: https://crbug.com/581553
1089         // css-flexbox section 4.5
1090         // FIXME: If the min value is expected to be valid here, we need to come up with a non optional version of computeMainAxisExtentForChild and
1091         // ensure it's valid through the virtual calls of computeIntrinsicLogicalContentHeightUsing.
1092         LayoutUnit contentSize = computeMainAxisExtentForChild(child, MinSize, Length(MinContent)).valueOr(0);
1093         ASSERT(contentSize >= 0);
1094         if (child.hasAspectRatio() && child.intrinsicSize().height() > 0)
1095             contentSize = adjustChildSizeForAspectRatioCrossAxisMinAndMax(child, contentSize);
1096         contentSize = std::min(contentSize, maxExtent.valueOr(contentSize));
1097         
1098         Length mainSize = isHorizontalFlow() ? child.style().width() : child.style().height();
1099         if (mainAxisLengthIsDefinite(child, mainSize)) {
1100             LayoutUnit resolvedMainSize = computeMainAxisExtentForChild(child, MainOrPreferredSize, mainSize).valueOr(0);
1101             ASSERT(resolvedMainSize >= 0);
1102             LayoutUnit specifiedSize = std::min(resolvedMainSize, maxExtent.valueOr(resolvedMainSize));
1103             return std::max(childSize, std::min(specifiedSize, contentSize));
1104         }
1105
1106         if (useChildAspectRatio(child)) {
1107             Length crossSizeLength = isHorizontalFlow() ? child.style().height() : child.style().width();
1108             Optional<LayoutUnit> transferredSize = computeMainSizeFromAspectRatioUsing(child, crossSizeLength);
1109             if (transferredSize) {
1110                 transferredSize = adjustChildSizeForAspectRatioCrossAxisMinAndMax(child, transferredSize.value());
1111                 return std::max(childSize, std::min(transferredSize.value(), contentSize));
1112             }
1113         }
1114         
1115         return std::max(childSize, contentSize);
1116     }
1117
1118     return std::max(0_lu, childSize);
1119 }
1120     
1121 Optional<LayoutUnit> RenderFlexibleBox::crossSizeForPercentageResolution(const RenderBox& child)
1122 {
1123     if (alignmentForChild(child) != ItemPosition::Stretch)
1124         return WTF::nullopt;
1125
1126     // Here we implement https://drafts.csswg.org/css-flexbox/#algo-stretch
1127     if (hasOrthogonalFlow(child) && child.hasOverrideContentLogicalWidth())
1128         return child.overrideContentLogicalWidth();
1129     if (!hasOrthogonalFlow(child) && child.hasOverrideContentLogicalHeight())
1130         return child.overrideContentLogicalHeight();
1131     
1132     // We don't currently implement the optimization from
1133     // https://drafts.csswg.org/css-flexbox/#definite-sizes case 1. While that
1134     // could speed up a specialized case, it requires determining if we have a
1135     // definite size, which itself is not cheap. We can consider implementing it
1136     // at a later time. (The correctness is ensured by redoing layout in
1137     // applyStretchAlignmentToChild)
1138     return WTF::nullopt;
1139 }
1140
1141 Optional<LayoutUnit> RenderFlexibleBox::mainSizeForPercentageResolution(const RenderBox& child)
1142 {
1143     // This function implements section 9.8. Definite and Indefinite Sizes, case
1144     // 2) of the flexbox spec.
1145     // We need to check for the flexbox to have a definite main size, and for the
1146     // flex item to have a definite flex basis.
1147     const Length& flexBasis = flexBasisForChild(child);
1148     if (!mainAxisLengthIsDefinite(child, flexBasis))
1149         return WTF::nullopt;
1150     if (!flexBasis.isPercentOrCalculated()) {
1151         // If flex basis had a percentage, our size is guaranteed to be definite or
1152         // the flex item's size could not be definite. Otherwise, we make up a
1153         // percentage to check whether we have a definite size.
1154         if (!mainAxisLengthIsDefinite(child, Length(0, Percent)))
1155             return WTF::nullopt;
1156     }
1157     
1158     if (hasOrthogonalFlow(child))
1159         return child.hasOverrideContentLogicalHeight() ? Optional<LayoutUnit>(child.overrideContentLogicalHeight()) : WTF::nullopt;
1160     return child.hasOverrideContentLogicalWidth() ? Optional<LayoutUnit>(child.overrideContentLogicalWidth()) : WTF::nullopt;
1161 }
1162
1163 Optional<LayoutUnit> RenderFlexibleBox::childLogicalHeightForPercentageResolution(const RenderBox& child)
1164 {
1165     if (!hasOrthogonalFlow(child))
1166         return crossSizeForPercentageResolution(child);
1167     return mainSizeForPercentageResolution(child);
1168 }
1169
1170 LayoutUnit RenderFlexibleBox::adjustChildSizeForAspectRatioCrossAxisMinAndMax(const RenderBox& child, LayoutUnit childSize)
1171 {
1172     Length crossMin = isHorizontalFlow() ? child.style().minHeight() : child.style().minWidth();
1173     Length crossMax = isHorizontalFlow() ? child.style().maxHeight() : child.style().maxWidth();
1174     
1175     if (crossAxisLengthIsDefinite(child, crossMax)) {
1176         LayoutUnit maxValue = computeMainSizeFromAspectRatioUsing(child, crossMax);
1177         childSize = std::min(maxValue, childSize);
1178     }
1179     
1180     if (crossAxisLengthIsDefinite(child, crossMin)) {
1181         LayoutUnit minValue = computeMainSizeFromAspectRatioUsing(child, crossMin);
1182         childSize = std::max(minValue, childSize);
1183     }
1184     
1185     return childSize;
1186 }
1187
1188 FlexItem RenderFlexibleBox::constructFlexItem(RenderBox& child, bool relayoutChildren)
1189 {
1190     // If this condition is true, then computeMainAxisExtentForChild will call
1191     // child.intrinsicContentLogicalHeight() and
1192     // child.scrollbarLogicalHeight(), so if the child has intrinsic
1193     // min/max/preferred size, run layout on it now to make sure its logical
1194     // height and scroll bars are up to date.
1195     if (childHasIntrinsicMainAxisSize(child) && child.needsLayout()) {
1196         child.clearOverrideContentSize();
1197         child.setChildNeedsLayout(MarkOnlyThis);
1198         child.layoutIfNeeded();
1199         cacheChildMainSize(child);
1200         relayoutChildren = false;
1201     }
1202     
1203     LayoutUnit borderAndPadding = isHorizontalFlow() ? child.horizontalBorderAndPaddingExtent() : child.verticalBorderAndPaddingExtent();
1204     LayoutUnit childInnerFlexBaseSize = computeInnerFlexBaseSizeForChild(child, borderAndPadding, relayoutChildren);
1205     LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(child, childInnerFlexBaseSize);
1206     LayoutUnit margin = isHorizontalFlow() ? child.horizontalMarginExtent() : child.verticalMarginExtent();
1207     return FlexItem(child, childInnerFlexBaseSize, childMinMaxAppliedMainAxisExtent, borderAndPadding, margin);
1208 }
1209     
1210 void RenderFlexibleBox::freezeViolations(Vector<FlexItem*>& violations, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalFlexShrink, double& totalWeightedFlexShrink)
1211 {
1212     for (size_t i = 0; i < violations.size(); ++i) {
1213         ASSERT(!violations[i]->frozen);
1214         const auto& child = violations[i]->box;
1215         LayoutUnit childSize = violations[i]->flexedContentSize;
1216         availableFreeSpace -= childSize - violations[i]->flexBaseContentSize;
1217         totalFlexGrow -= child.style().flexGrow();
1218         totalFlexShrink -= child.style().flexShrink();
1219         totalWeightedFlexShrink -= child.style().flexShrink() * violations[i]->flexBaseContentSize;
1220         // totalWeightedFlexShrink can be negative when we exceed the precision of
1221         // a double when we initially calcuate totalWeightedFlexShrink. We then
1222         // subtract each child's weighted flex shrink with full precision, now
1223         // leading to a negative result. See
1224         // css3/flexbox/large-flex-shrink-assert.html
1225         totalWeightedFlexShrink = std::max(totalWeightedFlexShrink, 0.0);
1226         violations[i]->frozen = true;
1227     }
1228 }
1229     
1230 void RenderFlexibleBox::freezeInflexibleItems(FlexSign flexSign, Vector<FlexItem>& children, LayoutUnit& remainingFreeSpace, double& totalFlexGrow, double& totalFlexShrink, double& totalWeightedFlexShrink)
1231 {
1232     // Per https://drafts.csswg.org/css-flexbox/#resolve-flexible-lengths step 2,
1233     // we freeze all items with a flex factor of 0 as well as those with a min/max
1234     // size violation.
1235     Vector<FlexItem*> newInflexibleItems;
1236     for (size_t i = 0; i < children.size(); ++i) {
1237         FlexItem& flexItem = children[i];
1238         const auto& child = flexItem.box;
1239         ASSERT(!flexItem.box.isOutOfFlowPositioned());
1240         ASSERT(!flexItem.frozen);
1241         float flexFactor = (flexSign == PositiveFlexibility) ? child.style().flexGrow() : child.style().flexShrink();
1242         if (!flexFactor || (flexSign == PositiveFlexibility && flexItem.flexBaseContentSize > flexItem.hypotheticalMainContentSize) || (flexSign == NegativeFlexibility && flexItem.flexBaseContentSize < flexItem.hypotheticalMainContentSize)) {
1243             flexItem.flexedContentSize = flexItem.hypotheticalMainContentSize;
1244             newInflexibleItems.append(&flexItem);
1245         }
1246     }
1247     freezeViolations(newInflexibleItems, remainingFreeSpace, totalFlexGrow, totalFlexShrink, totalWeightedFlexShrink);
1248 }
1249
1250 // Returns true if we successfully ran the algorithm and sized the flex items.
1251 bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, Vector<FlexItem>& children, LayoutUnit initialFreeSpace, LayoutUnit& remainingFreeSpace, double& totalFlexGrow, double& totalFlexShrink, double& totalWeightedFlexShrink)
1252 {
1253     LayoutUnit totalViolation;
1254     LayoutUnit usedFreeSpace;
1255     Vector<FlexItem*> minViolations;
1256     Vector<FlexItem*> maxViolations;
1257
1258     double sumFlexFactors = (flexSign == PositiveFlexibility) ? totalFlexGrow : totalFlexShrink;
1259     if (sumFlexFactors > 0 && sumFlexFactors < 1) {
1260         LayoutUnit fractional(initialFreeSpace * sumFlexFactors);
1261         if (fractional.abs() < remainingFreeSpace.abs())
1262             remainingFreeSpace = fractional;
1263     }
1264
1265     for (size_t i = 0; i < children.size(); ++i) {
1266         FlexItem& flexItem = children[i];
1267         const auto& child = flexItem.box;
1268         
1269         // This check also covers out-of-flow children.
1270         if (flexItem.frozen)
1271             continue;
1272         
1273         LayoutUnit childSize = flexItem.flexBaseContentSize;
1274         double extraSpace = 0;
1275         if (remainingFreeSpace > 0 && totalFlexGrow > 0 && flexSign == PositiveFlexibility && std::isfinite(totalFlexGrow))
1276             extraSpace = remainingFreeSpace * child.style().flexGrow() / totalFlexGrow;
1277         else if (remainingFreeSpace < 0 && totalWeightedFlexShrink > 0 && flexSign == NegativeFlexibility && std::isfinite(totalWeightedFlexShrink) && child.style().flexShrink())
1278             extraSpace = remainingFreeSpace * child.style().flexShrink() * flexItem.flexBaseContentSize / totalWeightedFlexShrink;
1279         if (std::isfinite(extraSpace))
1280             childSize += LayoutUnit::fromFloatRound(extraSpace);
1281         
1282         LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(child, childSize);
1283         ASSERT(adjustedChildSize >= 0);
1284         flexItem.flexedContentSize = adjustedChildSize;
1285         usedFreeSpace += adjustedChildSize - flexItem.flexBaseContentSize;
1286         
1287         LayoutUnit violation = adjustedChildSize - childSize;
1288         if (violation > 0)
1289             minViolations.append(&flexItem);
1290         else if (violation < 0)
1291             maxViolations.append(&flexItem);
1292         totalViolation += violation;
1293     }
1294     
1295     if (totalViolation)
1296         freezeViolations(totalViolation < 0 ? maxViolations : minViolations, remainingFreeSpace, totalFlexGrow, totalFlexShrink, totalWeightedFlexShrink);
1297     else
1298         remainingFreeSpace -= usedFreeSpace;
1299     
1300     return !totalViolation;
1301 }
1302
1303 static LayoutUnit initialJustifyContentOffset(LayoutUnit availableFreeSpace, ContentPosition justifyContent, ContentDistribution justifyContentDistribution, unsigned numberOfChildren)
1304 {
1305     if (justifyContent == ContentPosition::FlexEnd)
1306         return availableFreeSpace;
1307     if (justifyContent == ContentPosition::Center)
1308         return availableFreeSpace / 2;
1309     if (justifyContentDistribution == ContentDistribution::SpaceAround) {
1310         if (availableFreeSpace > 0 && numberOfChildren)
1311             return availableFreeSpace / (2 * numberOfChildren);
1312         else
1313             return availableFreeSpace / 2;
1314     }
1315     if (justifyContentDistribution == ContentDistribution::SpaceEvenly) {
1316         if (availableFreeSpace > 0 && numberOfChildren)
1317             return availableFreeSpace / (numberOfChildren + 1);
1318         // Fallback to 'center'
1319         return availableFreeSpace / 2;
1320     }
1321     return 0;
1322 }
1323
1324 static LayoutUnit justifyContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, ContentDistribution justifyContentDistribution, unsigned numberOfChildren)
1325 {
1326     if (availableFreeSpace > 0 && numberOfChildren > 1) {
1327         if (justifyContentDistribution == ContentDistribution::SpaceBetween)
1328             return availableFreeSpace / (numberOfChildren - 1);
1329         if (justifyContentDistribution == ContentDistribution::SpaceAround)
1330             return availableFreeSpace / numberOfChildren;
1331         if (justifyContentDistribution == ContentDistribution::SpaceEvenly)
1332             return availableFreeSpace / (numberOfChildren + 1);
1333     }
1334     return 0;
1335 }
1336
1337
1338 static LayoutUnit alignmentOffset(LayoutUnit availableFreeSpace, ItemPosition position, LayoutUnit ascent, LayoutUnit maxAscent, bool isWrapReverse)
1339 {
1340     switch (position) {
1341     case ItemPosition::Legacy:
1342     case ItemPosition::Auto:
1343     case ItemPosition::Normal:
1344         ASSERT_NOT_REACHED();
1345         break;
1346     case ItemPosition::Stretch:
1347         // Actual stretching must be handled by the caller. Since wrap-reverse
1348         // flips cross start and cross end, stretch children should be aligned
1349         // with the cross end. This matters because applyStretchAlignment
1350         // doesn't always stretch or stretch fully (explicit cross size given, or
1351         // stretching constrained by max-height/max-width). For flex-start and
1352         // flex-end this is handled by alignmentForChild().
1353         if (isWrapReverse)
1354             return availableFreeSpace;
1355         break;
1356     case ItemPosition::FlexStart:
1357         break;
1358     case ItemPosition::FlexEnd:
1359         return availableFreeSpace;
1360     case ItemPosition::Center:
1361         return availableFreeSpace / 2;
1362     case ItemPosition::Baseline:
1363         // FIXME: If we get here in columns, we want the use the descent, except
1364         // we currently can't get the ascent/descent of orthogonal children.
1365         // https://bugs.webkit.org/show_bug.cgi?id=98076
1366         return maxAscent - ascent;
1367     case ItemPosition::LastBaseline:
1368     case ItemPosition::SelfStart:
1369     case ItemPosition::SelfEnd:
1370     case ItemPosition::Start:
1371     case ItemPosition::End:
1372     case ItemPosition::Left:
1373     case ItemPosition::Right:
1374         // FIXME: Implement the extended grammar, enabled when the Grid Layout
1375         // feature was enabled by default.
1376         break;
1377     }
1378     return 0;
1379 }
1380
1381 void RenderFlexibleBox::setOverrideMainAxisContentSizeForChild(RenderBox& child, LayoutUnit childPreferredSize)
1382 {
1383     if (hasOrthogonalFlow(child))
1384         child.setOverrideContentLogicalHeight(childPreferredSize);
1385     else
1386         child.setOverrideContentLogicalWidth(childPreferredSize);
1387 }
1388
1389 LayoutUnit RenderFlexibleBox::staticMainAxisPositionForPositionedChild(const RenderBox& child)
1390 {
1391     const LayoutUnit availableSpace = mainAxisContentExtent(contentLogicalHeight()) - mainAxisExtentForChild(child);
1392
1393     ContentPosition position = style().resolvedJustifyContentPosition(contentAlignmentNormalBehavior());
1394     ContentDistribution distribution = style().resolvedJustifyContentDistribution(contentAlignmentNormalBehavior());
1395     LayoutUnit offset = initialJustifyContentOffset(availableSpace, position, distribution, 1);
1396     if (style().flexDirection() == FlexDirection::RowReverse || style().flexDirection() == FlexDirection::ColumnReverse)
1397         offset = availableSpace - offset;
1398     return offset;
1399 }
1400
1401 LayoutUnit RenderFlexibleBox::staticCrossAxisPositionForPositionedChild(const RenderBox& child)
1402 {
1403     LayoutUnit availableSpace = crossAxisContentExtent() - crossAxisExtentForChild(child);
1404     return alignmentOffset(availableSpace, alignmentForChild(child), 0_lu, 0_lu, style().flexWrap() == FlexWrap::Reverse);
1405 }
1406
1407 LayoutUnit RenderFlexibleBox::staticInlinePositionForPositionedChild(const RenderBox& child)
1408 {
1409     return startOffsetForContent() + (isColumnFlow() ? staticCrossAxisPositionForPositionedChild(child) : staticMainAxisPositionForPositionedChild(child));
1410 }
1411
1412 LayoutUnit RenderFlexibleBox::staticBlockPositionForPositionedChild(const RenderBox& child)
1413 {
1414     return borderAndPaddingBefore() + (isColumnFlow() ? staticMainAxisPositionForPositionedChild(child) : staticCrossAxisPositionForPositionedChild(child));
1415 }
1416
1417 bool RenderFlexibleBox::setStaticPositionForPositionedLayout(const RenderBox& child)
1418 {
1419     bool positionChanged = false;
1420     auto* childLayer = child.layer();
1421     if (child.style().hasStaticInlinePosition(style().isHorizontalWritingMode())) {
1422         LayoutUnit inlinePosition = staticInlinePositionForPositionedChild(child);
1423         if (childLayer->staticInlinePosition() != inlinePosition) {
1424             childLayer->setStaticInlinePosition(inlinePosition);
1425             positionChanged = true;
1426         }
1427     }
1428     if (child.style().hasStaticBlockPosition(style().isHorizontalWritingMode())) {
1429         LayoutUnit blockPosition = staticBlockPositionForPositionedChild(child);
1430         if (childLayer->staticBlockPosition() != blockPosition) {
1431             childLayer->setStaticBlockPosition(blockPosition);
1432             positionChanged = true;
1433         }
1434     }
1435     return positionChanged;
1436 }
1437
1438 void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox& child)
1439 {
1440     ASSERT(child.isOutOfFlowPositioned());
1441     child.containingBlock()->insertPositionedObject(child);
1442     auto* childLayer = child.layer();
1443     LayoutUnit staticInlinePosition = flowAwareBorderStart() + flowAwarePaddingStart();
1444     if (childLayer->staticInlinePosition() != staticInlinePosition) {
1445         childLayer->setStaticInlinePosition(staticInlinePosition);
1446         if (child.style().hasStaticInlinePosition(style().isHorizontalWritingMode()))
1447             child.setChildNeedsLayout(MarkOnlyThis);
1448     }
1449
1450     LayoutUnit staticBlockPosition = flowAwareBorderBefore() + flowAwarePaddingBefore();
1451     if (childLayer->staticBlockPosition() != staticBlockPosition) {
1452         childLayer->setStaticBlockPosition(staticBlockPosition);
1453         if (child.style().hasStaticBlockPosition(style().isHorizontalWritingMode()))
1454             child.setChildNeedsLayout(MarkOnlyThis);
1455     }
1456 }
1457
1458 ItemPosition RenderFlexibleBox::alignmentForChild(const RenderBox& child) const
1459 {
1460     ItemPosition align = child.style().resolvedAlignSelf(&style(), selfAlignmentNormalBehavior()).position();
1461     ASSERT(align != ItemPosition::Auto && align != ItemPosition::Normal);
1462
1463     if (align == ItemPosition::Baseline && hasOrthogonalFlow(child))
1464         align = ItemPosition::FlexStart;
1465
1466     if (style().flexWrap() == FlexWrap::Reverse) {
1467         if (align == ItemPosition::FlexStart)
1468             align = ItemPosition::FlexEnd;
1469         else if (align == ItemPosition::FlexEnd)
1470             align = ItemPosition::FlexStart;
1471     }
1472
1473     return align;
1474 }
1475
1476 void RenderFlexibleBox::resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox& child)
1477 {
1478     if (hasAutoMarginsInCrossAxis(child)) {
1479         child.updateLogicalHeight();
1480         if (isHorizontalFlow()) {
1481             if (child.style().marginTop().isAuto())
1482                 child.setMarginTop(0_lu);
1483             if (child.style().marginBottom().isAuto())
1484                 child.setMarginBottom(0_lu);
1485         } else {
1486             if (child.style().marginLeft().isAuto())
1487                 child.setMarginLeft(0_lu);
1488             if (child.style().marginRight().isAuto())
1489                 child.setMarginRight(0_lu);
1490         }
1491     }
1492 }
1493
1494 bool RenderFlexibleBox::needToStretchChildLogicalHeight(const RenderBox& child) const
1495 {
1496     // This function is a little bit magical. It relies on the fact that blocks
1497     // intrinsically "stretch" themselves in their inline axis, i.e. a <div> has
1498     // an implicit width: 100%. So the child will automatically stretch if our
1499     // cross axis is the child's inline axis. That's the case if:
1500     // - We are horizontal and the child is in vertical writing mode
1501     // - We are vertical and the child is in horizontal writing mode
1502     // Otherwise, we need to stretch if the cross axis size is auto.
1503     if (alignmentForChild(child) != ItemPosition::Stretch)
1504         return false;
1505
1506     if (isHorizontalFlow() != child.style().isHorizontalWritingMode())
1507         return false;
1508
1509     return child.style().logicalHeight().isAuto();
1510 }
1511
1512 bool RenderFlexibleBox::childHasIntrinsicMainAxisSize(const RenderBox& child) const
1513 {
1514     bool result = false;
1515     if (isHorizontalFlow() != child.style().isHorizontalWritingMode()) {
1516         Length childFlexBasis = flexBasisForChild(child);
1517         Length childMinSize = isHorizontalFlow() ? child.style().minWidth() : child.style().minHeight();
1518         Length childMaxSize = isHorizontalFlow() ? child.style().maxWidth() : child.style().maxHeight();
1519         if (childFlexBasis.isIntrinsic() || childMinSize.isIntrinsicOrAuto() || childMaxSize.isIntrinsic())
1520             result = true;
1521     }
1522     return result;
1523 }
1524
1525 Overflow RenderFlexibleBox::mainAxisOverflowForChild(const RenderBox& child) const
1526 {
1527     if (isHorizontalFlow())
1528         return child.style().overflowX();
1529     return child.style().overflowY();
1530 }
1531
1532 Overflow RenderFlexibleBox::crossAxisOverflowForChild(const RenderBox& child) const
1533 {
1534     if (isHorizontalFlow())
1535         return child.style().overflowY();
1536     return child.style().overflowX();
1537 }
1538
1539 void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, Vector<FlexItem>& children, LayoutUnit availableFreeSpace, bool relayoutChildren, Vector<LineContext>& lineContexts)
1540 {
1541     ContentPosition position = style().resolvedJustifyContentPosition(contentAlignmentNormalBehavior());
1542     ContentDistribution distribution = style().resolvedJustifyContentDistribution(contentAlignmentNormalBehavior());
1543
1544     LayoutUnit autoMarginOffset = autoMarginOffsetInMainAxis(children, availableFreeSpace);
1545     LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart();
1546     mainAxisOffset += initialJustifyContentOffset(availableFreeSpace, position, distribution, children.size());
1547     if (style().flexDirection() == FlexDirection::RowReverse)
1548         mainAxisOffset += isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1549
1550     LayoutUnit totalMainExtent = mainAxisExtent();
1551     LayoutUnit maxAscent, maxDescent; // Used when align-items: baseline.
1552     LayoutUnit maxChildCrossAxisExtent;
1553     bool shouldFlipMainAxis = !isColumnFlow() && !isLeftToRightFlow();
1554     for (size_t i = 0; i < children.size(); ++i) {
1555         const auto& flexItem = children[i];
1556         auto& child = flexItem.box;
1557         bool childHadLayout = child.everHadLayout();
1558
1559         ASSERT(!flexItem.box.isOutOfFlowPositioned());
1560
1561         setOverrideMainAxisContentSizeForChild(child, flexItem.flexedContentSize);
1562         // The flexed content size and the override size include the scrollbar
1563         // width, so we need to compare to the size including the scrollbar.
1564         // TODO(cbiesinger): Should it include the scrollbar?
1565         if (flexItem.flexedContentSize != mainAxisContentExtentForChildIncludingScrollbar(child))
1566             child.setChildNeedsLayout(MarkOnlyThis);
1567         else {
1568             // To avoid double applying margin changes in
1569             // updateAutoMarginsInCrossAxis, we reset the margins here.
1570             resetAutoMarginsAndLogicalTopInCrossAxis(child);
1571         }
1572         // We may have already forced relayout for orthogonal flowing children in
1573         // computeInnerFlexBaseSizeForChild.
1574         bool forceChildRelayout = relayoutChildren && !m_relaidOutChildren.contains(&child);
1575         if (child.isRenderBlock() && downcast<RenderBlock>(child).hasPercentHeightDescendants()) {
1576             // Have to force another relayout even though the child is sized
1577             // correctly, because its descendants are not sized correctly yet. Our
1578             // previous layout of the child was done without an override height set.
1579             // So, redo it here.
1580             forceChildRelayout = true;
1581         }
1582         updateBlockChildDirtyBitsBeforeLayout(forceChildRelayout, child);
1583         if (!child.needsLayout())
1584             child.markForPaginationRelayoutIfNeeded();
1585         if (child.needsLayout())
1586             m_relaidOutChildren.add(&child);
1587         child.layoutIfNeeded();
1588         if (!childHadLayout && child.checkForRepaintDuringLayout()) {
1589             child.repaint();
1590             child.repaintOverhangingFloats(true);
1591         }
1592
1593         updateAutoMarginsInMainAxis(child, autoMarginOffset);
1594
1595         LayoutUnit childCrossAxisMarginBoxExtent;
1596         if (alignmentForChild(child) == ItemPosition::Baseline && !hasAutoMarginsInCrossAxis(child)) {
1597             LayoutUnit ascent = marginBoxAscentForChild(child);
1598             LayoutUnit descent = (crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child)) - ascent;
1599
1600             maxAscent = std::max(maxAscent, ascent);
1601             maxDescent = std::max(maxDescent, descent);
1602
1603             // FIXME: Take scrollbar into account
1604             childCrossAxisMarginBoxExtent = maxAscent + maxDescent;
1605         } else
1606             childCrossAxisMarginBoxExtent = crossAxisIntrinsicExtentForChild(child) + crossAxisMarginExtentForChild(child);
1607
1608         if (!isColumnFlow())
1609             setLogicalHeight(std::max(logicalHeight(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent()));
1610         maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisMarginBoxExtent);
1611
1612         mainAxisOffset += flowAwareMarginStartForChild(child);
1613
1614         LayoutUnit childMainExtent = mainAxisExtentForChild(child);
1615         // In an RTL column situation, this will apply the margin-right/margin-end
1616         // on the left. This will be fixed later in flipForRightToLeftColumn.
1617         LayoutPoint childLocation(shouldFlipMainAxis ? totalMainExtent - mainAxisOffset - childMainExtent : mainAxisOffset, crossAxisOffset + flowAwareMarginBeforeForChild(child));
1618         setFlowAwareLocationForChild(child, childLocation);
1619         mainAxisOffset += childMainExtent + flowAwareMarginEndForChild(child);
1620
1621         if (i != children.size() - 1) {
1622             // The last item does not get extra space added.
1623             mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, distribution, children.size());
1624         }
1625
1626         // FIXME: Deal with pagination.
1627     }
1628
1629     if (isColumnFlow())
1630         setLogicalHeight(std::max(logicalHeight(), mainAxisOffset + flowAwareBorderEnd() + flowAwarePaddingEnd() + scrollbarLogicalHeight()));
1631
1632     if (style().flexDirection() == FlexDirection::ColumnReverse) {
1633         // We have to do an extra pass for column-reverse to reposition the flex
1634         // items since the start depends on the height of the flexbox, which we
1635         // only know after we've positioned all the flex items.
1636         updateLogicalHeight();
1637         layoutColumnReverse(children, crossAxisOffset, availableFreeSpace);
1638     }
1639
1640     if (m_numberOfInFlowChildrenOnFirstLine == -1)
1641         m_numberOfInFlowChildrenOnFirstLine = children.size();
1642     lineContexts.append(LineContext(crossAxisOffset, maxChildCrossAxisExtent, maxAscent, WTFMove(children)));
1643     crossAxisOffset += maxChildCrossAxisExtent;
1644 }
1645
1646 void RenderFlexibleBox::layoutColumnReverse(const Vector<FlexItem>& children, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace)
1647 {
1648     ContentPosition position = style().resolvedJustifyContentPosition(contentAlignmentNormalBehavior());
1649     ContentDistribution distribution = style().resolvedJustifyContentDistribution(contentAlignmentNormalBehavior());
1650     
1651     // This is similar to the logic in layoutAndPlaceChildren, except we place
1652     // the children starting from the end of the flexbox. We also don't need to
1653     // layout anything since we're just moving the children to a new position.
1654     LayoutUnit mainAxisOffset = logicalHeight() - flowAwareBorderEnd() - flowAwarePaddingEnd();
1655     mainAxisOffset -= initialJustifyContentOffset(availableFreeSpace, position, distribution, children.size());
1656     mainAxisOffset -= isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1657     
1658     for (size_t i = 0; i < children.size(); ++i) {
1659         auto& child = children[i].box;
1660         ASSERT(!child.isOutOfFlowPositioned());
1661         mainAxisOffset -= mainAxisExtentForChild(child) + flowAwareMarginEndForChild(child);
1662         setFlowAwareLocationForChild(child, LayoutPoint(mainAxisOffset, crossAxisOffset + flowAwareMarginBeforeForChild(child)));
1663         mainAxisOffset -= flowAwareMarginStartForChild(child);
1664         mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, distribution, children.size());
1665     }
1666 }
1667     
1668 static LayoutUnit initialAlignContentOffset(LayoutUnit availableFreeSpace, ContentPosition alignContent, ContentDistribution alignContentDistribution, unsigned numberOfLines)
1669 {
1670     if (numberOfLines <= 1)
1671         return 0_lu;
1672     if (alignContent == ContentPosition::FlexEnd)
1673         return availableFreeSpace;
1674     if (alignContent == ContentPosition::Center)
1675         return availableFreeSpace / 2;
1676     if (alignContentDistribution == ContentDistribution::SpaceAround) {
1677         if (availableFreeSpace > 0 && numberOfLines)
1678             return availableFreeSpace / (2 * numberOfLines);
1679         if (availableFreeSpace < 0)
1680             return availableFreeSpace / 2;
1681     }
1682     if (alignContentDistribution == ContentDistribution::SpaceEvenly) {
1683         if (availableFreeSpace > 0)
1684             return availableFreeSpace / (numberOfLines + 1);
1685         // Fallback to 'center'
1686         return availableFreeSpace / 2;
1687     }
1688     return 0_lu;
1689 }
1690
1691 static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, ContentDistribution alignContentDistribution, unsigned numberOfLines)
1692 {
1693     if (availableFreeSpace > 0 && numberOfLines > 1) {
1694         if (alignContentDistribution == ContentDistribution::SpaceBetween)
1695             return availableFreeSpace / (numberOfLines - 1);
1696         if (alignContentDistribution == ContentDistribution::SpaceAround || alignContentDistribution == ContentDistribution::Stretch)
1697             return availableFreeSpace / numberOfLines;
1698         if (alignContentDistribution == ContentDistribution::SpaceEvenly)
1699             return availableFreeSpace / (numberOfLines + 1);
1700     }
1701     return 0_lu;
1702 }
1703     
1704 void RenderFlexibleBox::alignFlexLines(Vector<LineContext>& lineContexts)
1705 {
1706     ContentPosition position = style().resolvedAlignContentPosition(contentAlignmentNormalBehavior());
1707     ContentDistribution distribution = style().resolvedAlignContentDistribution(contentAlignmentNormalBehavior());
1708     
1709     // If we have a single line flexbox or a multiline line flexbox with only one
1710     // flex line, the line height is all the available space. For
1711     // flex-direction: row, this means we need to use the height, so we do this
1712     // after calling updateLogicalHeight.
1713     if (lineContexts.size() == 1) {
1714         lineContexts[0].crossAxisExtent = crossAxisContentExtent();
1715         return;
1716     }
1717     
1718     if (position == ContentPosition::FlexStart)
1719         return;
1720     
1721     LayoutUnit availableCrossAxisSpace = crossAxisContentExtent();
1722     for (size_t i = 0; i < lineContexts.size(); ++i)
1723         availableCrossAxisSpace -= lineContexts[i].crossAxisExtent;
1724     
1725     LayoutUnit lineOffset = initialAlignContentOffset(availableCrossAxisSpace, position, distribution, lineContexts.size());
1726     for (unsigned lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1727         LineContext& lineContext = lineContexts[lineNumber];
1728         lineContext.crossAxisOffset += lineOffset;
1729         for (size_t childNumber = 0; childNumber < lineContext.flexItems.size(); ++childNumber) {
1730             FlexItem& flexItem = lineContext.flexItems[childNumber];
1731             adjustAlignmentForChild(flexItem.box, lineOffset);
1732         }
1733         
1734         if (distribution == ContentDistribution::Stretch && availableCrossAxisSpace > 0)
1735             lineContexts[lineNumber].crossAxisExtent += availableCrossAxisSpace / static_cast<unsigned>(lineContexts.size());
1736         
1737         lineOffset += alignContentSpaceBetweenChildren(availableCrossAxisSpace, distribution, lineContexts.size());
1738     }
1739 }
1740     
1741 void RenderFlexibleBox::adjustAlignmentForChild(RenderBox& child, LayoutUnit delta)
1742 {
1743     ASSERT(!child.isOutOfFlowPositioned());
1744     setFlowAwareLocationForChild(child, flowAwareLocationForChild(child) + LayoutSize(0_lu, delta));
1745 }
1746     
1747 void RenderFlexibleBox::alignChildren(const Vector<LineContext>& lineContexts)
1748 {
1749     // Keep track of the space between the baseline edge and the after edge of
1750     // the box for each line.
1751     Vector<LayoutUnit> minMarginAfterBaselines;
1752     
1753     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1754         const LineContext& lineContext = lineContexts[lineNumber];
1755         
1756         LayoutUnit minMarginAfterBaseline = LayoutUnit::max();
1757         LayoutUnit lineCrossAxisExtent = lineContext.crossAxisExtent;
1758         LayoutUnit maxAscent = lineContext.maxAscent;
1759         
1760         for (size_t childNumber = 0; childNumber < lineContext.flexItems.size(); ++childNumber) {
1761             const auto& flexItem = lineContext.flexItems[childNumber];
1762             ASSERT(!flexItem.box.isOutOfFlowPositioned());
1763             
1764             if (updateAutoMarginsInCrossAxis(flexItem.box, std::max(0_lu, availableAlignmentSpaceForChild(lineCrossAxisExtent, flexItem.box))))
1765                 continue;
1766             
1767             ItemPosition position = alignmentForChild(flexItem.box);
1768             if (position == ItemPosition::Stretch)
1769                 applyStretchAlignmentToChild(flexItem.box, lineCrossAxisExtent);
1770             LayoutUnit availableSpace =
1771             availableAlignmentSpaceForChild(lineCrossAxisExtent, flexItem.box);
1772             LayoutUnit offset = alignmentOffset(availableSpace, position, marginBoxAscentForChild(flexItem.box), maxAscent, style().flexWrap() == FlexWrap::Reverse);
1773             adjustAlignmentForChild(flexItem.box, offset);
1774             if (position == ItemPosition::Baseline && style().flexWrap() == FlexWrap::Reverse)
1775                 minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, flexItem.box) - offset);
1776         }
1777
1778         minMarginAfterBaselines.append(minMarginAfterBaseline);
1779     }
1780     
1781     if (style().flexWrap() != FlexWrap::Reverse)
1782         return;
1783     
1784     // wrap-reverse flips the cross axis start and end. For baseline alignment,
1785     // this means we need to align the after edge of baseline elements with the
1786     // after edge of the flex line.
1787     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1788         const LineContext& lineContext = lineContexts[lineNumber];
1789         LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber];
1790         for (size_t childNumber = 0; childNumber < lineContext.flexItems.size(); ++childNumber) {
1791             const auto& flexItem = lineContext.flexItems[childNumber];
1792             if (alignmentForChild(flexItem.box) == ItemPosition::Baseline && !hasAutoMarginsInCrossAxis(flexItem.box) && minMarginAfterBaseline)
1793                 adjustAlignmentForChild(flexItem.box, minMarginAfterBaseline);
1794         }
1795     }
1796 }
1797
1798 void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox& child, LayoutUnit lineCrossAxisExtent)
1799 {
1800     if (!hasOrthogonalFlow(child) && child.style().logicalHeight().isAuto()) {
1801         LayoutUnit stretchedLogicalHeight = std::max(child.borderAndPaddingLogicalHeight(),
1802         lineCrossAxisExtent - crossAxisMarginExtentForChild(child));
1803         ASSERT(!child.needsLayout());
1804         LayoutUnit desiredLogicalHeight = child.constrainLogicalHeightByMinMax(stretchedLogicalHeight, cachedChildIntrinsicContentLogicalHeight(child));
1805         
1806         // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
1807         bool childNeedsRelayout = desiredLogicalHeight != child.logicalHeight();
1808         if (child.isRenderBlock() && downcast<RenderBlock>(child).hasPercentHeightDescendants() && m_relaidOutChildren.contains(&child)) {
1809             // Have to force another relayout even though the child is sized
1810             // correctly, because its descendants are not sized correctly yet. Our
1811             // previous layout of the child was done without an override height set.
1812             // So, redo it here.
1813             childNeedsRelayout = true;
1814         }
1815         if (childNeedsRelayout || !child.hasOverrideContentLogicalHeight())
1816             child.setOverrideContentLogicalHeight(desiredLogicalHeight - child.borderAndPaddingLogicalHeight());
1817         if (childNeedsRelayout) {
1818             child.setLogicalHeight(0_lu);
1819             // We cache the child's intrinsic content logical height to avoid it being
1820             // reset to the stretched height.
1821             // FIXME: This is fragile. RendertBoxes should be smart enough to
1822             // determine their intrinsic content logical height correctly even when
1823             // there's an overrideHeight.
1824             LayoutUnit childIntrinsicContentLogicalHeight = cachedChildIntrinsicContentLogicalHeight(child);
1825             child.setChildNeedsLayout(MarkOnlyThis);
1826             
1827             // Don't use layoutChildIfNeeded to avoid setting cross axis cached size twice.
1828             child.layoutIfNeeded();
1829
1830             setCachedChildIntrinsicContentLogicalHeight(child, childIntrinsicContentLogicalHeight);
1831         }
1832     } else if (hasOrthogonalFlow(child) && child.style().logicalWidth().isAuto()) {
1833         LayoutUnit childWidth = std::max(0_lu, lineCrossAxisExtent - crossAxisMarginExtentForChild(child));
1834         childWidth = child.constrainLogicalWidthInFragmentByMinMax(childWidth, crossAxisContentExtent(), *this, nullptr);
1835         
1836         if (childWidth != child.logicalWidth()) {
1837             child.setOverrideContentLogicalWidth(childWidth - child.borderAndPaddingLogicalWidth());
1838             child.setChildNeedsLayout(MarkOnlyThis);
1839             child.layoutIfNeeded();
1840         }
1841     }
1842 }
1843
1844 void RenderFlexibleBox::flipForRightToLeftColumn(const Vector<LineContext>& lineContexts)
1845 {
1846     if (style().isLeftToRightDirection() || !isColumnFlow())
1847         return;
1848     
1849     LayoutUnit crossExtent = crossAxisExtent();
1850     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1851         const LineContext& lineContext = lineContexts[lineNumber];
1852         for (size_t childNumber = 0; childNumber < lineContext.flexItems.size(); ++childNumber) {
1853             const auto& flexItem = lineContext.flexItems[childNumber];
1854             ASSERT(!flexItem.box.isOutOfFlowPositioned());
1855             
1856             LayoutPoint location = flowAwareLocationForChild(flexItem.box);
1857             // For vertical flows, setFlowAwareLocationForChild will transpose x and
1858             // y, so using the y axis for a column cross axis extent is correct.
1859             location.setY(crossExtent - crossAxisExtentForChild(flexItem.box) - location.y());
1860             if (!isHorizontalWritingMode())
1861                 location.move(LayoutSize(0, -horizontalScrollbarHeight()));
1862             setFlowAwareLocationForChild(flexItem.box, location);
1863         }
1864     }
1865 }
1866
1867 void RenderFlexibleBox::flipForWrapReverse(const Vector<LineContext>& lineContexts, LayoutUnit crossAxisStartEdge)
1868 {
1869     LayoutUnit contentExtent = crossAxisContentExtent();
1870     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1871         const LineContext& lineContext = lineContexts[lineNumber];
1872         for (size_t childNumber = 0; childNumber < lineContext.flexItems.size(); ++childNumber) {
1873             const auto& flexItem = lineContext.flexItems[childNumber];
1874             LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1875             LayoutUnit originalOffset = lineContexts[lineNumber].crossAxisOffset - crossAxisStartEdge;
1876             LayoutUnit newOffset = contentExtent - originalOffset - lineCrossAxisExtent;
1877             adjustAlignmentForChild(flexItem.box, newOffset - originalOffset);
1878         }
1879     }
1880 }
1881
1882 bool RenderFlexibleBox::isTopLayoutOverflowAllowed() const
1883 {
1884     bool hasTopOverflow = RenderBlock::isTopLayoutOverflowAllowed();
1885     if (hasTopOverflow || !style().isReverseFlexDirection())
1886         return hasTopOverflow;
1887     
1888     return !isHorizontalFlow();
1889 }
1890
1891 bool RenderFlexibleBox::isLeftLayoutOverflowAllowed() const
1892 {
1893     bool hasLeftOverflow = RenderBlock::isLeftLayoutOverflowAllowed();
1894     if (hasLeftOverflow || !style().isReverseFlexDirection())
1895         return hasLeftOverflow;
1896     
1897     return isHorizontalFlow();
1898 }
1899
1900 }