6692eac7b1130fc8e69a55e5ec9eff7a31bbd008
[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(LayoutUnit(), minLogicalWidth);
124     maxLogicalWidth = std::max(LayoutUnit(), 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().value_or(synthesizedBaselineFromContentBox(*this, direction));
176
177     int marginAscent = direction == HorizontalLine ? marginTop() : marginRight();
178     return baseline + marginAscent;
179 }
180
181 std::optional<int> RenderFlexibleBox::firstLineBaseline() const
182 {
183     if (isWritingModeRoot() || m_numberOfInFlowChildrenOnFirstLine <= 0)
184         return std::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 std::optional<int>();
204
205     if (!isColumnFlow() && hasOrthogonalFlow(*baselineChild))
206         return std::optional<int>(crossAxisExtentForChild(*baselineChild) + baselineChild->logicalTop());
207     if (isColumnFlow() && !hasOrthogonalFlow(*baselineChild))
208         return std::optional<int>(mainAxisExtentForChild(*baselineChild) + baselineChild->logicalTop());
209
210     std::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 std::optional<int>(synthesizedBaselineFromContentBox(*baselineChild, direction) + baselineChild->logicalTop());
216     }
217
218     return std::optional<int>(baseline.value() + baselineChild->logicalTop());
219 }
220
221 std::optional<int> RenderFlexibleBox::inlineBlockBaseline(LineDirectionMode direction) const
222 {
223     if (std::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() ? LayoutUnit() : 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(LayoutUnit(), computedValues.m_extent - borderPaddingAndScrollbar);
516     }
517     return contentLogicalWidth();
518 }
519
520 std::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         std::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     std::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 LayoutUnit();
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) != std::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(LayoutUnit(), 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 <= LayoutUnit())
922         return LayoutUnit();
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 LayoutUnit();
943     
944     LayoutUnit sizeOfAutoMargin = availableFreeSpace / numberOfAutoMargins;
945     availableFreeSpace = LayoutUnit();
946     return sizeOfAutoMargin;
947 }
948
949 void RenderFlexibleBox::updateAutoMarginsInMainAxis(RenderBox& child, LayoutUnit autoMarginOffset)
950 {
951     ASSERT(autoMarginOffset >= LayoutUnit());
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 >= LayoutUnit());
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().value_or(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     std::optional<LayoutUnit> maxExtent = std::nullopt;
1075     if (max.isSpecifiedOrIntrinsic()) {
1076         maxExtent = computeMainAxisExtentForChild(child, MaxSize, max);
1077         childSize = std::min(childSize, maxExtent.value_or(childSize));
1078     }
1079
1080     Length min = isHorizontalFlow() ? child.style().minWidth() : child.style().minHeight();
1081     if (min.isSpecifiedOrIntrinsic())
1082         return std::max(childSize, std::max(LayoutUnit(), computeMainAxisExtentForChild(child, MinSize, min).value_or(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         LayoutUnit contentSize = computeMainAxisExtentForChild(child, MinSize, Length(MinContent)).value();
1091         ASSERT(contentSize >= 0);
1092         if (child.hasAspectRatio() && child.intrinsicSize().height() > 0)
1093             contentSize = adjustChildSizeForAspectRatioCrossAxisMinAndMax(child, contentSize);
1094         contentSize = std::min(contentSize, maxExtent.value_or(contentSize));
1095         
1096         Length mainSize = isHorizontalFlow() ? child.style().width() : child.style().height();
1097         if (mainAxisLengthIsDefinite(child, mainSize)) {
1098             LayoutUnit resolvedMainSize = computeMainAxisExtentForChild(child, MainOrPreferredSize, mainSize).value();
1099             ASSERT(resolvedMainSize >= 0);
1100             LayoutUnit specifiedSize = std::min(resolvedMainSize, maxExtent.value_or(resolvedMainSize));
1101             return std::max(childSize, std::min(specifiedSize, contentSize));
1102         }
1103
1104         if (useChildAspectRatio(child)) {
1105             Length crossSizeLength = isHorizontalFlow() ? child.style().height() : child.style().width();
1106             std::optional<LayoutUnit> transferredSize = computeMainSizeFromAspectRatioUsing(child, crossSizeLength);
1107             if (transferredSize) {
1108                 transferredSize = adjustChildSizeForAspectRatioCrossAxisMinAndMax(child, transferredSize.value());
1109                 return std::max(childSize, std::min(transferredSize.value(), contentSize));
1110             }
1111         }
1112         
1113         return std::max(childSize, contentSize);
1114     }
1115
1116     return std::max(LayoutUnit(), childSize);
1117 }
1118     
1119 std::optional<LayoutUnit> RenderFlexibleBox::crossSizeForPercentageResolution(const RenderBox& child)
1120 {
1121     if (alignmentForChild(child) != ItemPosition::Stretch)
1122         return std::nullopt;
1123
1124     // Here we implement https://drafts.csswg.org/css-flexbox/#algo-stretch
1125     if (hasOrthogonalFlow(child) && child.hasOverrideContentLogicalWidth())
1126         return child.overrideContentLogicalWidth();
1127     if (!hasOrthogonalFlow(child) && child.hasOverrideContentLogicalHeight())
1128         return child.overrideContentLogicalHeight();
1129     
1130     // We don't currently implement the optimization from
1131     // https://drafts.csswg.org/css-flexbox/#definite-sizes case 1. While that
1132     // could speed up a specialized case, it requires determining if we have a
1133     // definite size, which itself is not cheap. We can consider implementing it
1134     // at a later time. (The correctness is ensured by redoing layout in
1135     // applyStretchAlignmentToChild)
1136     return std::nullopt;
1137 }
1138
1139 std::optional<LayoutUnit> RenderFlexibleBox::mainSizeForPercentageResolution(const RenderBox& child)
1140 {
1141     // This function implements section 9.8. Definite and Indefinite Sizes, case
1142     // 2) of the flexbox spec.
1143     // We need to check for the flexbox to have a definite main size, and for the
1144     // flex item to have a definite flex basis.
1145     const Length& flexBasis = flexBasisForChild(child);
1146     if (!mainAxisLengthIsDefinite(child, flexBasis))
1147         return std::nullopt;
1148     if (!flexBasis.isPercentOrCalculated()) {
1149         // If flex basis had a percentage, our size is guaranteed to be definite or
1150         // the flex item's size could not be definite. Otherwise, we make up a
1151         // percentage to check whether we have a definite size.
1152         if (!mainAxisLengthIsDefinite(child, Length(0, Percent)))
1153             return std::nullopt;
1154     }
1155     
1156     if (hasOrthogonalFlow(child))
1157         return child.hasOverrideContentLogicalHeight() ? std::optional<LayoutUnit>(child.overrideContentLogicalHeight()) : std::nullopt;
1158     return child.hasOverrideContentLogicalWidth() ? std::optional<LayoutUnit>(child.overrideContentLogicalWidth()) : std::nullopt;
1159 }
1160
1161 std::optional<LayoutUnit> RenderFlexibleBox::childLogicalHeightForPercentageResolution(const RenderBox& child)
1162 {
1163     if (!hasOrthogonalFlow(child))
1164         return crossSizeForPercentageResolution(child);
1165     return mainSizeForPercentageResolution(child);
1166 }
1167
1168 LayoutUnit RenderFlexibleBox::adjustChildSizeForAspectRatioCrossAxisMinAndMax(const RenderBox& child, LayoutUnit childSize)
1169 {
1170     Length crossMin = isHorizontalFlow() ? child.style().minHeight() : child.style().minWidth();
1171     Length crossMax = isHorizontalFlow() ? child.style().maxHeight() : child.style().maxWidth();
1172     
1173     if (crossAxisLengthIsDefinite(child, crossMax)) {
1174         LayoutUnit maxValue = computeMainSizeFromAspectRatioUsing(child, crossMax);
1175         childSize = std::min(maxValue, childSize);
1176     }
1177     
1178     if (crossAxisLengthIsDefinite(child, crossMin)) {
1179         LayoutUnit minValue = computeMainSizeFromAspectRatioUsing(child, crossMin);
1180         childSize = std::max(minValue, childSize);
1181     }
1182     
1183     return childSize;
1184 }
1185
1186 FlexItem RenderFlexibleBox::constructFlexItem(RenderBox& child, bool relayoutChildren)
1187 {
1188     // If this condition is true, then computeMainAxisExtentForChild will call
1189     // child.intrinsicContentLogicalHeight() and
1190     // child.scrollbarLogicalHeight(), so if the child has intrinsic
1191     // min/max/preferred size, run layout on it now to make sure its logical
1192     // height and scroll bars are up to date.
1193     if (childHasIntrinsicMainAxisSize(child) && child.needsLayout()) {
1194         child.clearOverrideContentSize();
1195         child.setChildNeedsLayout(MarkOnlyThis);
1196         child.layoutIfNeeded();
1197         cacheChildMainSize(child);
1198         relayoutChildren = false;
1199     }
1200     
1201     LayoutUnit borderAndPadding = isHorizontalFlow() ? child.horizontalBorderAndPaddingExtent() : child.verticalBorderAndPaddingExtent();
1202     LayoutUnit childInnerFlexBaseSize = computeInnerFlexBaseSizeForChild(child, borderAndPadding, relayoutChildren);
1203     LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(child, childInnerFlexBaseSize);
1204     LayoutUnit margin = isHorizontalFlow() ? child.horizontalMarginExtent() : child.verticalMarginExtent();
1205     return FlexItem(child, childInnerFlexBaseSize, childMinMaxAppliedMainAxisExtent, borderAndPadding, margin);
1206 }
1207     
1208 void RenderFlexibleBox::freezeViolations(Vector<FlexItem*>& violations, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalFlexShrink, double& totalWeightedFlexShrink)
1209 {
1210     for (size_t i = 0; i < violations.size(); ++i) {
1211         ASSERT(!violations[i]->frozen);
1212         const auto& child = violations[i]->box;
1213         LayoutUnit childSize = violations[i]->flexedContentSize;
1214         availableFreeSpace -= childSize - violations[i]->flexBaseContentSize;
1215         totalFlexGrow -= child.style().flexGrow();
1216         totalFlexShrink -= child.style().flexShrink();
1217         totalWeightedFlexShrink -= child.style().flexShrink() * violations[i]->flexBaseContentSize;
1218         // totalWeightedFlexShrink can be negative when we exceed the precision of
1219         // a double when we initially calcuate totalWeightedFlexShrink. We then
1220         // subtract each child's weighted flex shrink with full precision, now
1221         // leading to a negative result. See
1222         // css3/flexbox/large-flex-shrink-assert.html
1223         totalWeightedFlexShrink = std::max(totalWeightedFlexShrink, 0.0);
1224         violations[i]->frozen = true;
1225     }
1226 }
1227     
1228 void RenderFlexibleBox::freezeInflexibleItems(FlexSign flexSign, Vector<FlexItem>& children, LayoutUnit& remainingFreeSpace, double& totalFlexGrow, double& totalFlexShrink, double& totalWeightedFlexShrink)
1229 {
1230     // Per https://drafts.csswg.org/css-flexbox/#resolve-flexible-lengths step 2,
1231     // we freeze all items with a flex factor of 0 as well as those with a min/max
1232     // size violation.
1233     Vector<FlexItem*> newInflexibleItems;
1234     for (size_t i = 0; i < children.size(); ++i) {
1235         FlexItem& flexItem = children[i];
1236         const auto& child = flexItem.box;
1237         ASSERT(!flexItem.box.isOutOfFlowPositioned());
1238         ASSERT(!flexItem.frozen);
1239         float flexFactor = (flexSign == PositiveFlexibility) ? child.style().flexGrow() : child.style().flexShrink();
1240         if (!flexFactor || (flexSign == PositiveFlexibility && flexItem.flexBaseContentSize > flexItem.hypotheticalMainContentSize) || (flexSign == NegativeFlexibility && flexItem.flexBaseContentSize < flexItem.hypotheticalMainContentSize)) {
1241             flexItem.flexedContentSize = flexItem.hypotheticalMainContentSize;
1242             newInflexibleItems.append(&flexItem);
1243         }
1244     }
1245     freezeViolations(newInflexibleItems, remainingFreeSpace, totalFlexGrow, totalFlexShrink, totalWeightedFlexShrink);
1246 }
1247
1248 // Returns true if we successfully ran the algorithm and sized the flex items.
1249 bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, Vector<FlexItem>& children, LayoutUnit initialFreeSpace, LayoutUnit& remainingFreeSpace, double& totalFlexGrow, double& totalFlexShrink, double& totalWeightedFlexShrink)
1250 {
1251     LayoutUnit totalViolation;
1252     LayoutUnit usedFreeSpace;
1253     Vector<FlexItem*> minViolations;
1254     Vector<FlexItem*> maxViolations;
1255
1256     double sumFlexFactors = (flexSign == PositiveFlexibility) ? totalFlexGrow : totalFlexShrink;
1257     if (sumFlexFactors > 0 && sumFlexFactors < 1) {
1258         LayoutUnit fractional(initialFreeSpace * sumFlexFactors);
1259         if (fractional.abs() < remainingFreeSpace.abs())
1260             remainingFreeSpace = fractional;
1261     }
1262
1263     for (size_t i = 0; i < children.size(); ++i) {
1264         FlexItem& flexItem = children[i];
1265         const auto& child = flexItem.box;
1266         
1267         // This check also covers out-of-flow children.
1268         if (flexItem.frozen)
1269             continue;
1270         
1271         LayoutUnit childSize = flexItem.flexBaseContentSize;
1272         double extraSpace = 0;
1273         if (remainingFreeSpace > 0 && totalFlexGrow > 0 && flexSign == PositiveFlexibility && std::isfinite(totalFlexGrow))
1274             extraSpace = remainingFreeSpace * child.style().flexGrow() / totalFlexGrow;
1275         else if (remainingFreeSpace < 0 && totalWeightedFlexShrink > 0 && flexSign == NegativeFlexibility && std::isfinite(totalWeightedFlexShrink) && child.style().flexShrink())
1276             extraSpace = remainingFreeSpace * child.style().flexShrink() * flexItem.flexBaseContentSize / totalWeightedFlexShrink;
1277         if (std::isfinite(extraSpace))
1278             childSize += LayoutUnit::fromFloatRound(extraSpace);
1279         
1280         LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(child, childSize);
1281         ASSERT(adjustedChildSize >= 0);
1282         flexItem.flexedContentSize = adjustedChildSize;
1283         usedFreeSpace += adjustedChildSize - flexItem.flexBaseContentSize;
1284         
1285         LayoutUnit violation = adjustedChildSize - childSize;
1286         if (violation > 0)
1287             minViolations.append(&flexItem);
1288         else if (violation < 0)
1289             maxViolations.append(&flexItem);
1290         totalViolation += violation;
1291     }
1292     
1293     if (totalViolation)
1294         freezeViolations(totalViolation < 0 ? maxViolations : minViolations, remainingFreeSpace, totalFlexGrow, totalFlexShrink, totalWeightedFlexShrink);
1295     else
1296         remainingFreeSpace -= usedFreeSpace;
1297     
1298     return !totalViolation;
1299 }
1300
1301 static LayoutUnit initialJustifyContentOffset(LayoutUnit availableFreeSpace, ContentPosition justifyContent, ContentDistribution justifyContentDistribution, unsigned numberOfChildren)
1302 {
1303     if (justifyContent == ContentPosition::FlexEnd)
1304         return availableFreeSpace;
1305     if (justifyContent == ContentPosition::Center)
1306         return availableFreeSpace / 2;
1307     if (justifyContentDistribution == ContentDistribution::SpaceAround) {
1308         if (availableFreeSpace > 0 && numberOfChildren)
1309             return availableFreeSpace / (2 * numberOfChildren);
1310         else
1311             return availableFreeSpace / 2;
1312     }
1313     if (justifyContentDistribution == ContentDistribution::SpaceEvenly) {
1314         if (availableFreeSpace > 0 && numberOfChildren)
1315             return availableFreeSpace / (numberOfChildren + 1);
1316         // Fallback to 'center'
1317         return availableFreeSpace / 2;
1318     }
1319     return 0;
1320 }
1321
1322 static LayoutUnit justifyContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, ContentDistribution justifyContentDistribution, unsigned numberOfChildren)
1323 {
1324     if (availableFreeSpace > 0 && numberOfChildren > 1) {
1325         if (justifyContentDistribution == ContentDistribution::SpaceBetween)
1326             return availableFreeSpace / (numberOfChildren - 1);
1327         if (justifyContentDistribution == ContentDistribution::SpaceAround)
1328             return availableFreeSpace / numberOfChildren;
1329         if (justifyContentDistribution == ContentDistribution::SpaceEvenly)
1330             return availableFreeSpace / (numberOfChildren + 1);
1331     }
1332     return 0;
1333 }
1334
1335
1336 static LayoutUnit alignmentOffset(LayoutUnit availableFreeSpace, ItemPosition position, LayoutUnit ascent, LayoutUnit maxAscent, bool isWrapReverse)
1337 {
1338     switch (position) {
1339     case ItemPosition::Legacy:
1340     case ItemPosition::Auto:
1341     case ItemPosition::Normal:
1342         ASSERT_NOT_REACHED();
1343         break;
1344     case ItemPosition::Stretch:
1345         // Actual stretching must be handled by the caller. Since wrap-reverse
1346         // flips cross start and cross end, stretch children should be aligned
1347         // with the cross end. This matters because applyStretchAlignment
1348         // doesn't always stretch or stretch fully (explicit cross size given, or
1349         // stretching constrained by max-height/max-width). For flex-start and
1350         // flex-end this is handled by alignmentForChild().
1351         if (isWrapReverse)
1352             return availableFreeSpace;
1353         break;
1354     case ItemPosition::FlexStart:
1355         break;
1356     case ItemPosition::FlexEnd:
1357         return availableFreeSpace;
1358     case ItemPosition::Center:
1359         return availableFreeSpace / 2;
1360     case ItemPosition::Baseline:
1361         // FIXME: If we get here in columns, we want the use the descent, except
1362         // we currently can't get the ascent/descent of orthogonal children.
1363         // https://bugs.webkit.org/show_bug.cgi?id=98076
1364         return maxAscent - ascent;
1365     case ItemPosition::LastBaseline:
1366     case ItemPosition::SelfStart:
1367     case ItemPosition::SelfEnd:
1368     case ItemPosition::Start:
1369     case ItemPosition::End:
1370     case ItemPosition::Left:
1371     case ItemPosition::Right:
1372         // FIXME: Implement the extended grammar, enabled when the Grid Layout
1373         // feature was enabled by default.
1374         break;
1375     }
1376     return 0;
1377 }
1378
1379 void RenderFlexibleBox::setOverrideMainAxisContentSizeForChild(RenderBox& child, LayoutUnit childPreferredSize)
1380 {
1381     if (hasOrthogonalFlow(child))
1382         child.setOverrideContentLogicalHeight(childPreferredSize);
1383     else
1384         child.setOverrideContentLogicalWidth(childPreferredSize);
1385 }
1386
1387 LayoutUnit RenderFlexibleBox::staticMainAxisPositionForPositionedChild(const RenderBox& child)
1388 {
1389     const LayoutUnit availableSpace = mainAxisContentExtent(contentLogicalHeight()) - mainAxisExtentForChild(child);
1390
1391     ContentPosition position = style().resolvedJustifyContentPosition(contentAlignmentNormalBehavior());
1392     ContentDistribution distribution = style().resolvedJustifyContentDistribution(contentAlignmentNormalBehavior());
1393     LayoutUnit offset = initialJustifyContentOffset(availableSpace, position, distribution, 1);
1394     if (style().flexDirection() == FlexDirection::RowReverse || style().flexDirection() == FlexDirection::ColumnReverse)
1395         offset = availableSpace - offset;
1396     return offset;
1397 }
1398
1399 LayoutUnit RenderFlexibleBox::staticCrossAxisPositionForPositionedChild(const RenderBox& child)
1400 {
1401     LayoutUnit availableSpace = crossAxisContentExtent() - crossAxisExtentForChild(child);
1402     return alignmentOffset(availableSpace, alignmentForChild(child), LayoutUnit(), LayoutUnit(), style().flexWrap() == FlexWrap::Reverse);
1403 }
1404
1405 LayoutUnit RenderFlexibleBox::staticInlinePositionForPositionedChild(const RenderBox& child)
1406 {
1407     return startOffsetForContent() + (isColumnFlow() ? staticCrossAxisPositionForPositionedChild(child) : staticMainAxisPositionForPositionedChild(child));
1408 }
1409
1410 LayoutUnit RenderFlexibleBox::staticBlockPositionForPositionedChild(const RenderBox& child)
1411 {
1412     return borderAndPaddingBefore() + (isColumnFlow() ? staticMainAxisPositionForPositionedChild(child) : staticCrossAxisPositionForPositionedChild(child));
1413 }
1414
1415 bool RenderFlexibleBox::setStaticPositionForPositionedLayout(const RenderBox& child)
1416 {
1417     bool positionChanged = false;
1418     auto* childLayer = child.layer();
1419     if (child.style().hasStaticInlinePosition(style().isHorizontalWritingMode())) {
1420         LayoutUnit inlinePosition = staticInlinePositionForPositionedChild(child);
1421         if (childLayer->staticInlinePosition() != inlinePosition) {
1422             childLayer->setStaticInlinePosition(inlinePosition);
1423             positionChanged = true;
1424         }
1425     }
1426     if (child.style().hasStaticBlockPosition(style().isHorizontalWritingMode())) {
1427         LayoutUnit blockPosition = staticBlockPositionForPositionedChild(child);
1428         if (childLayer->staticBlockPosition() != blockPosition) {
1429             childLayer->setStaticBlockPosition(blockPosition);
1430             positionChanged = true;
1431         }
1432     }
1433     return positionChanged;
1434 }
1435
1436 void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox& child)
1437 {
1438     ASSERT(child.isOutOfFlowPositioned());
1439     child.containingBlock()->insertPositionedObject(child);
1440     auto* childLayer = child.layer();
1441     LayoutUnit staticInlinePosition = flowAwareBorderStart() + flowAwarePaddingStart();
1442     if (childLayer->staticInlinePosition() != staticInlinePosition) {
1443         childLayer->setStaticInlinePosition(staticInlinePosition);
1444         if (child.style().hasStaticInlinePosition(style().isHorizontalWritingMode()))
1445             child.setChildNeedsLayout(MarkOnlyThis);
1446     }
1447
1448     LayoutUnit staticBlockPosition = flowAwareBorderBefore() + flowAwarePaddingBefore();
1449     if (childLayer->staticBlockPosition() != staticBlockPosition) {
1450         childLayer->setStaticBlockPosition(staticBlockPosition);
1451         if (child.style().hasStaticBlockPosition(style().isHorizontalWritingMode()))
1452             child.setChildNeedsLayout(MarkOnlyThis);
1453     }
1454 }
1455
1456 ItemPosition RenderFlexibleBox::alignmentForChild(const RenderBox& child) const
1457 {
1458     ItemPosition align = child.style().resolvedAlignSelf(&style(), selfAlignmentNormalBehavior()).position();
1459     ASSERT(align != ItemPosition::Auto && align != ItemPosition::Normal);
1460
1461     if (align == ItemPosition::Baseline && hasOrthogonalFlow(child))
1462         align = ItemPosition::FlexStart;
1463
1464     if (style().flexWrap() == FlexWrap::Reverse) {
1465         if (align == ItemPosition::FlexStart)
1466             align = ItemPosition::FlexEnd;
1467         else if (align == ItemPosition::FlexEnd)
1468             align = ItemPosition::FlexStart;
1469     }
1470
1471     return align;
1472 }
1473
1474 void RenderFlexibleBox::resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox& child)
1475 {
1476     if (hasAutoMarginsInCrossAxis(child)) {
1477         child.updateLogicalHeight();
1478         if (isHorizontalFlow()) {
1479             if (child.style().marginTop().isAuto())
1480                 child.setMarginTop(LayoutUnit());
1481             if (child.style().marginBottom().isAuto())
1482                 child.setMarginBottom(LayoutUnit());
1483         } else {
1484             if (child.style().marginLeft().isAuto())
1485                 child.setMarginLeft(LayoutUnit());
1486             if (child.style().marginRight().isAuto())
1487                 child.setMarginRight(LayoutUnit());
1488         }
1489     }
1490 }
1491
1492 bool RenderFlexibleBox::needToStretchChildLogicalHeight(const RenderBox& child) const
1493 {
1494     // This function is a little bit magical. It relies on the fact that blocks
1495     // intrinsically "stretch" themselves in their inline axis, i.e. a <div> has
1496     // an implicit width: 100%. So the child will automatically stretch if our
1497     // cross axis is the child's inline axis. That's the case if:
1498     // - We are horizontal and the child is in vertical writing mode
1499     // - We are vertical and the child is in horizontal writing mode
1500     // Otherwise, we need to stretch if the cross axis size is auto.
1501     if (alignmentForChild(child) != ItemPosition::Stretch)
1502         return false;
1503
1504     if (isHorizontalFlow() != child.style().isHorizontalWritingMode())
1505         return false;
1506
1507     return child.style().logicalHeight().isAuto();
1508 }
1509
1510 bool RenderFlexibleBox::childHasIntrinsicMainAxisSize(const RenderBox& child) const
1511 {
1512     bool result = false;
1513     if (isHorizontalFlow() != child.style().isHorizontalWritingMode()) {
1514         Length childFlexBasis = flexBasisForChild(child);
1515         Length childMinSize = isHorizontalFlow() ? child.style().minWidth() : child.style().minHeight();
1516         Length childMaxSize = isHorizontalFlow() ? child.style().maxWidth() : child.style().maxHeight();
1517         if (childFlexBasis.isIntrinsic() || childMinSize.isIntrinsicOrAuto() || childMaxSize.isIntrinsic())
1518             result = true;
1519     }
1520     return result;
1521 }
1522
1523 Overflow RenderFlexibleBox::mainAxisOverflowForChild(const RenderBox& child) const
1524 {
1525     if (isHorizontalFlow())
1526         return child.style().overflowX();
1527     return child.style().overflowY();
1528 }
1529
1530 Overflow RenderFlexibleBox::crossAxisOverflowForChild(const RenderBox& child) const
1531 {
1532     if (isHorizontalFlow())
1533         return child.style().overflowY();
1534     return child.style().overflowX();
1535 }
1536
1537 void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, Vector<FlexItem>& children, LayoutUnit availableFreeSpace, bool relayoutChildren, Vector<LineContext>& lineContexts)
1538 {
1539     ContentPosition position = style().resolvedJustifyContentPosition(contentAlignmentNormalBehavior());
1540     ContentDistribution distribution = style().resolvedJustifyContentDistribution(contentAlignmentNormalBehavior());
1541
1542     LayoutUnit autoMarginOffset = autoMarginOffsetInMainAxis(children, availableFreeSpace);
1543     LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart();
1544     mainAxisOffset += initialJustifyContentOffset(availableFreeSpace, position, distribution, children.size());
1545     if (style().flexDirection() == FlexDirection::RowReverse)
1546         mainAxisOffset += isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1547
1548     LayoutUnit totalMainExtent = mainAxisExtent();
1549     LayoutUnit maxAscent, maxDescent; // Used when align-items: baseline.
1550     LayoutUnit maxChildCrossAxisExtent;
1551     bool shouldFlipMainAxis = !isColumnFlow() && !isLeftToRightFlow();
1552     for (size_t i = 0; i < children.size(); ++i) {
1553         const auto& flexItem = children[i];
1554         auto& child = flexItem.box;
1555         bool childHadLayout = child.everHadLayout();
1556
1557         ASSERT(!flexItem.box.isOutOfFlowPositioned());
1558
1559         setOverrideMainAxisContentSizeForChild(child, flexItem.flexedContentSize);
1560         // The flexed content size and the override size include the scrollbar
1561         // width, so we need to compare to the size including the scrollbar.
1562         // TODO(cbiesinger): Should it include the scrollbar?
1563         if (flexItem.flexedContentSize != mainAxisContentExtentForChildIncludingScrollbar(child))
1564             child.setChildNeedsLayout(MarkOnlyThis);
1565         else {
1566             // To avoid double applying margin changes in
1567             // updateAutoMarginsInCrossAxis, we reset the margins here.
1568             resetAutoMarginsAndLogicalTopInCrossAxis(child);
1569         }
1570         // We may have already forced relayout for orthogonal flowing children in
1571         // computeInnerFlexBaseSizeForChild.
1572         bool forceChildRelayout = relayoutChildren && !m_relaidOutChildren.contains(&child);
1573         if (child.isRenderBlock() && downcast<RenderBlock>(child).hasPercentHeightDescendants()) {
1574             // Have to force another relayout even though the child is sized
1575             // correctly, because its descendants are not sized correctly yet. Our
1576             // previous layout of the child was done without an override height set.
1577             // So, redo it here.
1578             forceChildRelayout = true;
1579         }
1580         updateBlockChildDirtyBitsBeforeLayout(forceChildRelayout, child);
1581         if (!child.needsLayout())
1582             child.markForPaginationRelayoutIfNeeded();
1583         if (child.needsLayout())
1584             m_relaidOutChildren.add(&child);
1585         child.layoutIfNeeded();
1586         if (!childHadLayout && child.checkForRepaintDuringLayout()) {
1587             child.repaint();
1588             child.repaintOverhangingFloats(true);
1589         }
1590
1591         updateAutoMarginsInMainAxis(child, autoMarginOffset);
1592
1593         LayoutUnit childCrossAxisMarginBoxExtent;
1594         if (alignmentForChild(child) == ItemPosition::Baseline && !hasAutoMarginsInCrossAxis(child)) {
1595             LayoutUnit ascent = marginBoxAscentForChild(child);
1596             LayoutUnit descent = (crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child)) - ascent;
1597
1598             maxAscent = std::max(maxAscent, ascent);
1599             maxDescent = std::max(maxDescent, descent);
1600
1601             // FIXME: Take scrollbar into account
1602             childCrossAxisMarginBoxExtent = maxAscent + maxDescent;
1603         } else
1604             childCrossAxisMarginBoxExtent = crossAxisIntrinsicExtentForChild(child) + crossAxisMarginExtentForChild(child);
1605
1606         if (!isColumnFlow())
1607             setLogicalHeight(std::max(logicalHeight(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent()));
1608         maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisMarginBoxExtent);
1609
1610         mainAxisOffset += flowAwareMarginStartForChild(child);
1611
1612         LayoutUnit childMainExtent = mainAxisExtentForChild(child);
1613         // In an RTL column situation, this will apply the margin-right/margin-end
1614         // on the left. This will be fixed later in flipForRightToLeftColumn.
1615         LayoutPoint childLocation(shouldFlipMainAxis ? totalMainExtent - mainAxisOffset - childMainExtent : mainAxisOffset, crossAxisOffset + flowAwareMarginBeforeForChild(child));
1616         setFlowAwareLocationForChild(child, childLocation);
1617         mainAxisOffset += childMainExtent + flowAwareMarginEndForChild(child);
1618
1619         if (i != children.size() - 1) {
1620             // The last item does not get extra space added.
1621             mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, distribution, children.size());
1622         }
1623
1624         // FIXME: Deal with pagination.
1625     }
1626
1627     if (isColumnFlow())
1628         setLogicalHeight(std::max(logicalHeight(), mainAxisOffset + flowAwareBorderEnd() + flowAwarePaddingEnd() + scrollbarLogicalHeight()));
1629
1630     if (style().flexDirection() == FlexDirection::ColumnReverse) {
1631         // We have to do an extra pass for column-reverse to reposition the flex
1632         // items since the start depends on the height of the flexbox, which we
1633         // only know after we've positioned all the flex items.
1634         updateLogicalHeight();
1635         layoutColumnReverse(children, crossAxisOffset, availableFreeSpace);
1636     }
1637
1638     if (m_numberOfInFlowChildrenOnFirstLine == -1)
1639         m_numberOfInFlowChildrenOnFirstLine = children.size();
1640     lineContexts.append(LineContext(crossAxisOffset, maxChildCrossAxisExtent, maxAscent, WTFMove(children)));
1641     crossAxisOffset += maxChildCrossAxisExtent;
1642 }
1643
1644 void RenderFlexibleBox::layoutColumnReverse(const Vector<FlexItem>& children, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace)
1645 {
1646     ContentPosition position = style().resolvedJustifyContentPosition(contentAlignmentNormalBehavior());
1647     ContentDistribution distribution = style().resolvedJustifyContentDistribution(contentAlignmentNormalBehavior());
1648     
1649     // This is similar to the logic in layoutAndPlaceChildren, except we place
1650     // the children starting from the end of the flexbox. We also don't need to
1651     // layout anything since we're just moving the children to a new position.
1652     LayoutUnit mainAxisOffset = logicalHeight() - flowAwareBorderEnd() - flowAwarePaddingEnd();
1653     mainAxisOffset -= initialJustifyContentOffset(availableFreeSpace, position, distribution, children.size());
1654     mainAxisOffset -= isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight();
1655     
1656     for (size_t i = 0; i < children.size(); ++i) {
1657         auto& child = children[i].box;
1658         ASSERT(!child.isOutOfFlowPositioned());
1659         mainAxisOffset -= mainAxisExtentForChild(child) + flowAwareMarginEndForChild(child);
1660         setFlowAwareLocationForChild(child, LayoutPoint(mainAxisOffset, crossAxisOffset + flowAwareMarginBeforeForChild(child)));
1661         mainAxisOffset -= flowAwareMarginStartForChild(child);
1662         mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, distribution, children.size());
1663     }
1664 }
1665     
1666 static LayoutUnit initialAlignContentOffset(LayoutUnit availableFreeSpace, ContentPosition alignContent, ContentDistribution alignContentDistribution, unsigned numberOfLines)
1667 {
1668     if (numberOfLines <= 1)
1669         return LayoutUnit();
1670     if (alignContent == ContentPosition::FlexEnd)
1671         return availableFreeSpace;
1672     if (alignContent == ContentPosition::Center)
1673         return availableFreeSpace / 2;
1674     if (alignContentDistribution == ContentDistribution::SpaceAround) {
1675         if (availableFreeSpace > 0 && numberOfLines)
1676             return availableFreeSpace / (2 * numberOfLines);
1677         if (availableFreeSpace < 0)
1678             return availableFreeSpace / 2;
1679     }
1680     if (alignContentDistribution == ContentDistribution::SpaceEvenly) {
1681         if (availableFreeSpace > 0)
1682             return availableFreeSpace / (numberOfLines + 1);
1683         // Fallback to 'center'
1684         return availableFreeSpace / 2;
1685     }
1686     return LayoutUnit();
1687 }
1688
1689 static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, ContentDistribution alignContentDistribution, unsigned numberOfLines)
1690 {
1691     if (availableFreeSpace > 0 && numberOfLines > 1) {
1692         if (alignContentDistribution == ContentDistribution::SpaceBetween)
1693             return availableFreeSpace / (numberOfLines - 1);
1694         if (alignContentDistribution == ContentDistribution::SpaceAround || alignContentDistribution == ContentDistribution::Stretch)
1695             return availableFreeSpace / numberOfLines;
1696         if (alignContentDistribution == ContentDistribution::SpaceEvenly)
1697             return availableFreeSpace / (numberOfLines + 1);
1698     }
1699     return LayoutUnit();
1700 }
1701     
1702 void RenderFlexibleBox::alignFlexLines(Vector<LineContext>& lineContexts)
1703 {
1704     ContentPosition position = style().resolvedAlignContentPosition(contentAlignmentNormalBehavior());
1705     ContentDistribution distribution = style().resolvedAlignContentDistribution(contentAlignmentNormalBehavior());
1706     
1707     // If we have a single line flexbox or a multiline line flexbox with only one
1708     // flex line, the line height is all the available space. For
1709     // flex-direction: row, this means we need to use the height, so we do this
1710     // after calling updateLogicalHeight.
1711     if (lineContexts.size() == 1) {
1712         lineContexts[0].crossAxisExtent = crossAxisContentExtent();
1713         return;
1714     }
1715     
1716     if (position == ContentPosition::FlexStart)
1717         return;
1718     
1719     LayoutUnit availableCrossAxisSpace = crossAxisContentExtent();
1720     for (size_t i = 0; i < lineContexts.size(); ++i)
1721         availableCrossAxisSpace -= lineContexts[i].crossAxisExtent;
1722     
1723     LayoutUnit lineOffset = initialAlignContentOffset(availableCrossAxisSpace, position, distribution, lineContexts.size());
1724     for (unsigned lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1725         LineContext& lineContext = lineContexts[lineNumber];
1726         lineContext.crossAxisOffset += lineOffset;
1727         for (size_t childNumber = 0; childNumber < lineContext.flexItems.size(); ++childNumber) {
1728             FlexItem& flexItem = lineContext.flexItems[childNumber];
1729             adjustAlignmentForChild(flexItem.box, lineOffset);
1730         }
1731         
1732         if (distribution == ContentDistribution::Stretch && availableCrossAxisSpace > 0)
1733             lineContexts[lineNumber].crossAxisExtent += availableCrossAxisSpace / static_cast<unsigned>(lineContexts.size());
1734         
1735         lineOffset += alignContentSpaceBetweenChildren(availableCrossAxisSpace, distribution, lineContexts.size());
1736     }
1737 }
1738     
1739 void RenderFlexibleBox::adjustAlignmentForChild(RenderBox& child, LayoutUnit delta)
1740 {
1741     ASSERT(!child.isOutOfFlowPositioned());
1742     setFlowAwareLocationForChild(child, flowAwareLocationForChild(child) + LayoutSize(LayoutUnit(), delta));
1743 }
1744     
1745 void RenderFlexibleBox::alignChildren(const Vector<LineContext>& lineContexts)
1746 {
1747     // Keep track of the space between the baseline edge and the after edge of
1748     // the box for each line.
1749     Vector<LayoutUnit> minMarginAfterBaselines;
1750     
1751     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1752         const LineContext& lineContext = lineContexts[lineNumber];
1753         
1754         LayoutUnit minMarginAfterBaseline = LayoutUnit::max();
1755         LayoutUnit lineCrossAxisExtent = lineContext.crossAxisExtent;
1756         LayoutUnit maxAscent = lineContext.maxAscent;
1757         
1758         for (size_t childNumber = 0; childNumber < lineContext.flexItems.size(); ++childNumber) {
1759             const auto& flexItem = lineContext.flexItems[childNumber];
1760             ASSERT(!flexItem.box.isOutOfFlowPositioned());
1761             
1762             if (updateAutoMarginsInCrossAxis(flexItem.box, std::max(LayoutUnit(), availableAlignmentSpaceForChild(lineCrossAxisExtent, flexItem.box))))
1763                 continue;
1764             
1765             ItemPosition position = alignmentForChild(flexItem.box);
1766             if (position == ItemPosition::Stretch)
1767                 applyStretchAlignmentToChild(flexItem.box, lineCrossAxisExtent);
1768             LayoutUnit availableSpace =
1769             availableAlignmentSpaceForChild(lineCrossAxisExtent, flexItem.box);
1770             LayoutUnit offset = alignmentOffset(availableSpace, position, marginBoxAscentForChild(flexItem.box), maxAscent, style().flexWrap() == FlexWrap::Reverse);
1771             adjustAlignmentForChild(flexItem.box, offset);
1772             if (position == ItemPosition::Baseline && style().flexWrap() == FlexWrap::Reverse)
1773                 minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, flexItem.box) - offset);
1774         }
1775
1776         minMarginAfterBaselines.append(minMarginAfterBaseline);
1777     }
1778     
1779     if (style().flexWrap() != FlexWrap::Reverse)
1780         return;
1781     
1782     // wrap-reverse flips the cross axis start and end. For baseline alignment,
1783     // this means we need to align the after edge of baseline elements with the
1784     // after edge of the flex line.
1785     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1786         const LineContext& lineContext = lineContexts[lineNumber];
1787         LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber];
1788         for (size_t childNumber = 0; childNumber < lineContext.flexItems.size(); ++childNumber) {
1789             const auto& flexItem = lineContext.flexItems[childNumber];
1790             if (alignmentForChild(flexItem.box) == ItemPosition::Baseline && !hasAutoMarginsInCrossAxis(flexItem.box) && minMarginAfterBaseline)
1791                 adjustAlignmentForChild(flexItem.box, minMarginAfterBaseline);
1792         }
1793     }
1794 }
1795
1796 void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox& child, LayoutUnit lineCrossAxisExtent)
1797 {
1798     if (!hasOrthogonalFlow(child) && child.style().logicalHeight().isAuto()) {
1799         LayoutUnit stretchedLogicalHeight = std::max(child.borderAndPaddingLogicalHeight(),
1800         lineCrossAxisExtent - crossAxisMarginExtentForChild(child));
1801         ASSERT(!child.needsLayout());
1802         LayoutUnit desiredLogicalHeight = child.constrainLogicalHeightByMinMax(stretchedLogicalHeight, cachedChildIntrinsicContentLogicalHeight(child));
1803         
1804         // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905.
1805         bool childNeedsRelayout = desiredLogicalHeight != child.logicalHeight();
1806         if (child.isRenderBlock() && downcast<RenderBlock>(child).hasPercentHeightDescendants() && m_relaidOutChildren.contains(&child)) {
1807             // Have to force another relayout even though the child is sized
1808             // correctly, because its descendants are not sized correctly yet. Our
1809             // previous layout of the child was done without an override height set.
1810             // So, redo it here.
1811             childNeedsRelayout = true;
1812         }
1813         if (childNeedsRelayout || !child.hasOverrideContentLogicalHeight())
1814             child.setOverrideContentLogicalHeight(desiredLogicalHeight - child.borderAndPaddingLogicalHeight());
1815         if (childNeedsRelayout) {
1816             child.setLogicalHeight(LayoutUnit());
1817             // We cache the child's intrinsic content logical height to avoid it being
1818             // reset to the stretched height.
1819             // FIXME: This is fragile. RendertBoxes should be smart enough to
1820             // determine their intrinsic content logical height correctly even when
1821             // there's an overrideHeight.
1822             LayoutUnit childIntrinsicContentLogicalHeight = cachedChildIntrinsicContentLogicalHeight(child);
1823             child.setChildNeedsLayout(MarkOnlyThis);
1824             
1825             // Don't use layoutChildIfNeeded to avoid setting cross axis cached size twice.
1826             child.layoutIfNeeded();
1827
1828             setCachedChildIntrinsicContentLogicalHeight(child, childIntrinsicContentLogicalHeight);
1829         }
1830     } else if (hasOrthogonalFlow(child) && child.style().logicalWidth().isAuto()) {
1831         LayoutUnit childWidth = std::max(LayoutUnit(), lineCrossAxisExtent - crossAxisMarginExtentForChild(child));
1832         childWidth = child.constrainLogicalWidthInFragmentByMinMax(childWidth, crossAxisContentExtent(), *this, nullptr);
1833         
1834         if (childWidth != child.logicalWidth()) {
1835             child.setOverrideContentLogicalWidth(childWidth - child.borderAndPaddingLogicalWidth());
1836             child.setChildNeedsLayout(MarkOnlyThis);
1837             child.layoutIfNeeded();
1838         }
1839     }
1840 }
1841
1842 void RenderFlexibleBox::flipForRightToLeftColumn(const Vector<LineContext>& lineContexts)
1843 {
1844     if (style().isLeftToRightDirection() || !isColumnFlow())
1845         return;
1846     
1847     LayoutUnit crossExtent = crossAxisExtent();
1848     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1849         const LineContext& lineContext = lineContexts[lineNumber];
1850         for (size_t childNumber = 0; childNumber < lineContext.flexItems.size(); ++childNumber) {
1851             const auto& flexItem = lineContext.flexItems[childNumber];
1852             ASSERT(!flexItem.box.isOutOfFlowPositioned());
1853             
1854             LayoutPoint location = flowAwareLocationForChild(flexItem.box);
1855             // For vertical flows, setFlowAwareLocationForChild will transpose x and
1856             // y, so using the y axis for a column cross axis extent is correct.
1857             location.setY(crossExtent - crossAxisExtentForChild(flexItem.box) - location.y());
1858             if (!isHorizontalWritingMode())
1859                 location.move(LayoutSize(0, -horizontalScrollbarHeight()));
1860             setFlowAwareLocationForChild(flexItem.box, location);
1861         }
1862     }
1863 }
1864
1865 void RenderFlexibleBox::flipForWrapReverse(const Vector<LineContext>& lineContexts, LayoutUnit crossAxisStartEdge)
1866 {
1867     LayoutUnit contentExtent = crossAxisContentExtent();
1868     for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) {
1869         const LineContext& lineContext = lineContexts[lineNumber];
1870         for (size_t childNumber = 0; childNumber < lineContext.flexItems.size(); ++childNumber) {
1871             const auto& flexItem = lineContext.flexItems[childNumber];
1872             LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent;
1873             LayoutUnit originalOffset = lineContexts[lineNumber].crossAxisOffset - crossAxisStartEdge;
1874             LayoutUnit newOffset = contentExtent - originalOffset - lineCrossAxisExtent;
1875             adjustAlignmentForChild(flexItem.box, newOffset - originalOffset);
1876         }
1877     }
1878 }
1879
1880 bool RenderFlexibleBox::isTopLayoutOverflowAllowed() const
1881 {
1882     bool hasTopOverflow = RenderBlock::isTopLayoutOverflowAllowed();
1883     if (hasTopOverflow || !style().isReverseFlexDirection())
1884         return hasTopOverflow;
1885     
1886     return !isHorizontalFlow();
1887 }
1888
1889 bool RenderFlexibleBox::isLeftLayoutOverflowAllowed() const
1890 {
1891     bool hasLeftOverflow = RenderBlock::isLeftLayoutOverflowAllowed();
1892     if (hasLeftOverflow || !style().isReverseFlexDirection())
1893         return hasLeftOverflow;
1894     
1895     return isHorizontalFlow();
1896 }
1897
1898 }