|  | /* | 
|  | * Copyright (C) 2011 Google Inc. All rights reserved. | 
|  | * | 
|  | * Redistribution and use in source and binary forms, with or without | 
|  | * modification, are permitted provided that the following conditions are | 
|  | * met: | 
|  | * | 
|  | *     * Redistributions of source code must retain the above copyright | 
|  | * notice, this list of conditions and the following disclaimer. | 
|  | *     * Redistributions in binary form must reproduce the above | 
|  | * copyright notice, this list of conditions and the following disclaimer | 
|  | * in the documentation and/or other materials provided with the | 
|  | * distribution. | 
|  | *     * Neither the name of Google Inc. nor the names of its | 
|  | * contributors may be used to endorse or promote products derived from | 
|  | * this software without specific prior written permission. | 
|  | * | 
|  | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
|  | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|  | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|  | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
|  | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
|  | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
|  | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "core/rendering/RenderFlexibleBox.h" | 
|  |  | 
|  | #include "core/frame/UseCounter.h" | 
|  | #include "core/paint/BlockPainter.h" | 
|  | #include "core/rendering/RenderLayer.h" | 
|  | #include "core/rendering/RenderView.h" | 
|  | #include "core/rendering/TextAutosizer.h" | 
|  | #include "core/rendering/style/RenderStyle.h" | 
|  | #include "platform/LengthFunctions.h" | 
|  | #include "wtf/MathExtras.h" | 
|  | #include <limits> | 
|  |  | 
|  | namespace blink { | 
|  |  | 
|  | struct RenderFlexibleBox::LineContext { | 
|  | LineContext(LayoutUnit crossAxisOffset, LayoutUnit crossAxisExtent, size_t numberOfChildren, LayoutUnit maxAscent) | 
|  | : crossAxisOffset(crossAxisOffset) | 
|  | , crossAxisExtent(crossAxisExtent) | 
|  | , numberOfChildren(numberOfChildren) | 
|  | , maxAscent(maxAscent) | 
|  | { | 
|  | } | 
|  |  | 
|  | LayoutUnit crossAxisOffset; | 
|  | LayoutUnit crossAxisExtent; | 
|  | size_t numberOfChildren; | 
|  | LayoutUnit maxAscent; | 
|  | }; | 
|  |  | 
|  | struct RenderFlexibleBox::Violation { | 
|  | Violation(RenderBox* child, LayoutUnit childSize) | 
|  | : child(child) | 
|  | , childSize(childSize) | 
|  | { | 
|  | } | 
|  |  | 
|  | RenderBox* child; | 
|  | LayoutUnit childSize; | 
|  | }; | 
|  |  | 
|  |  | 
|  | RenderFlexibleBox::RenderFlexibleBox(Element* element) | 
|  | : RenderBlock(element) | 
|  | , m_orderIterator(this) | 
|  | , m_numberOfInFlowChildrenOnFirstLine(-1) | 
|  | { | 
|  | ASSERT(!childrenInline()); | 
|  | } | 
|  |  | 
|  | RenderFlexibleBox::~RenderFlexibleBox() | 
|  | { | 
|  | } | 
|  |  | 
|  | RenderFlexibleBox* RenderFlexibleBox::createAnonymous(Document* document) | 
|  | { | 
|  | RenderFlexibleBox* renderer = new RenderFlexibleBox(0); | 
|  | renderer->setDocumentForAnonymous(document); | 
|  | return renderer; | 
|  | } | 
|  |  | 
|  | const char* RenderFlexibleBox::renderName() const | 
|  | { | 
|  | return "RenderFlexibleBox"; | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const | 
|  | { | 
|  | // FIXME: We're ignoring flex-basis here and we shouldn't. We can't start honoring it though until | 
|  | // the flex shorthand stops setting it to 0. | 
|  | // See https://bugs.webkit.org/show_bug.cgi?id=116117 and http://crbug.com/240765. | 
|  | for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { | 
|  | if (child->isOutOfFlowPositioned()) | 
|  | continue; | 
|  |  | 
|  | LayoutUnit margin = marginIntrinsicLogicalWidthForChild(child); | 
|  | bool hasOrthogonalWritingMode = child->isHorizontalWritingMode() != isHorizontalWritingMode(); | 
|  | LayoutUnit minPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->minPreferredLogicalWidth(); | 
|  | LayoutUnit maxPreferredLogicalWidth = hasOrthogonalWritingMode ? child->logicalHeight() : child->maxPreferredLogicalWidth(); | 
|  | minPreferredLogicalWidth += margin; | 
|  | maxPreferredLogicalWidth += margin; | 
|  | if (!isColumnFlow()) { | 
|  | maxLogicalWidth += maxPreferredLogicalWidth; | 
|  | if (isMultiline()) { | 
|  | // For multiline, the min preferred width is if you put a break between each item. | 
|  | minLogicalWidth = std::max(minLogicalWidth, minPreferredLogicalWidth); | 
|  | } else | 
|  | minLogicalWidth += minPreferredLogicalWidth; | 
|  | } else { | 
|  | minLogicalWidth = std::max(minPreferredLogicalWidth, minLogicalWidth); | 
|  | maxLogicalWidth = std::max(maxPreferredLogicalWidth, maxLogicalWidth); | 
|  | } | 
|  | } | 
|  |  | 
|  | maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth); | 
|  |  | 
|  | LayoutUnit scrollbarWidth = instrinsicScrollbarLogicalWidth(); | 
|  | maxLogicalWidth += scrollbarWidth; | 
|  | minLogicalWidth += scrollbarWidth; | 
|  | } | 
|  |  | 
|  | static int synthesizedBaselineFromContentBox(const RenderBox& box, LineDirectionMode direction) | 
|  | { | 
|  | return direction == HorizontalLine ? box.borderTop() + box.paddingTop() + box.contentHeight() : box.borderRight() + box.paddingRight() + box.contentWidth(); | 
|  | } | 
|  |  | 
|  | int RenderFlexibleBox::baselinePosition(FontBaseline, bool, LineDirectionMode direction, LinePositionMode mode) const | 
|  | { | 
|  | ASSERT(mode == PositionOnContainingLine); | 
|  | int baseline = firstLineBoxBaseline(); | 
|  | if (baseline == -1) | 
|  | baseline = synthesizedBaselineFromContentBox(*this, direction); | 
|  |  | 
|  | return beforeMarginInLineDirection(direction) + baseline; | 
|  | } | 
|  |  | 
|  | int RenderFlexibleBox::firstLineBoxBaseline() const | 
|  | { | 
|  | if (isWritingModeRoot() || m_numberOfInFlowChildrenOnFirstLine <= 0) | 
|  | return -1; | 
|  | RenderBox* baselineChild = 0; | 
|  | int childNumber = 0; | 
|  | for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) { | 
|  | if (child->isOutOfFlowPositioned()) | 
|  | continue; | 
|  | if (alignmentForChild(*child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(*child)) { | 
|  | baselineChild = child; | 
|  | break; | 
|  | } | 
|  | if (!baselineChild) | 
|  | baselineChild = child; | 
|  |  | 
|  | ++childNumber; | 
|  | if (childNumber == m_numberOfInFlowChildrenOnFirstLine) | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (!baselineChild) | 
|  | return -1; | 
|  |  | 
|  | if (!isColumnFlow() && hasOrthogonalFlow(*baselineChild)) | 
|  | return crossAxisExtentForChild(*baselineChild) + baselineChild->logicalTop(); | 
|  | if (isColumnFlow() && !hasOrthogonalFlow(*baselineChild)) | 
|  | return mainAxisExtentForChild(*baselineChild) + baselineChild->logicalTop(); | 
|  |  | 
|  | int baseline = baselineChild->firstLineBoxBaseline(); | 
|  | if (baseline == -1) { | 
|  | // FIXME: We should pass |direction| into firstLineBoxBaseline and stop bailing out if we're a writing mode root. | 
|  | // This would also fix some cases where the flexbox is orthogonal to its container. | 
|  | LineDirectionMode direction = isHorizontalWritingMode() ? HorizontalLine : VerticalLine; | 
|  | return synthesizedBaselineFromContentBox(*baselineChild, direction) + baselineChild->logicalTop(); | 
|  | } | 
|  |  | 
|  | return baseline + baselineChild->logicalTop(); | 
|  | } | 
|  |  | 
|  | int RenderFlexibleBox::inlineBlockBaseline(LineDirectionMode direction) const | 
|  | { | 
|  | int baseline = firstLineBoxBaseline(); | 
|  | if (baseline != -1) | 
|  | return baseline; | 
|  |  | 
|  | int marginAscent = direction == HorizontalLine ? marginTop() : marginRight(); | 
|  | return synthesizedBaselineFromContentBox(*this, direction) + marginAscent; | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::removeChild(RenderObject* child) | 
|  | { | 
|  | RenderBlock::removeChild(child); | 
|  | m_intrinsicSizeAlongMainAxis.remove(child); | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) | 
|  | { | 
|  | RenderBlock::styleDidChange(diff, oldStyle); | 
|  |  | 
|  | if (oldStyle && oldStyle->alignItems() == ItemPositionStretch && diff.needsFullLayout()) { | 
|  | // Flex items that were previously stretching need to be relayed out so we can compute new available cross axis space. | 
|  | // This is only necessary for stretching since other alignment values don't change the size of the box. | 
|  | for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { | 
|  | ItemPosition previousAlignment = RenderStyle::resolveAlignment(oldStyle, child->style()); | 
|  | if (previousAlignment == ItemPositionStretch && previousAlignment != RenderStyle::resolveAlignment(style(), child->style())) | 
|  | child->setChildNeedsLayout(MarkOnlyThis); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::layoutBlock(bool relayoutChildren) | 
|  | { | 
|  | ASSERT(needsLayout()); | 
|  |  | 
|  | if (!relayoutChildren && simplifiedLayout()) | 
|  | return; | 
|  |  | 
|  | if (updateLogicalWidthAndColumnWidth()) | 
|  | relayoutChildren = true; | 
|  |  | 
|  | LayoutUnit previousHeight = logicalHeight(); | 
|  | setLogicalHeight(borderAndPaddingLogicalHeight() + scrollbarLogicalHeight()); | 
|  |  | 
|  | { | 
|  | TextAutosizer::LayoutScope textAutosizerLayoutScope(this); | 
|  | LayoutState state(*this, locationOffset()); | 
|  |  | 
|  | m_numberOfInFlowChildrenOnFirstLine = -1; | 
|  |  | 
|  | RenderBlock::startDelayUpdateScrollInfo(); | 
|  |  | 
|  | prepareOrderIteratorAndMargins(); | 
|  |  | 
|  | ChildFrameRects oldChildRects; | 
|  | appendChildFrameRects(oldChildRects); | 
|  |  | 
|  | layoutFlexItems(relayoutChildren); | 
|  |  | 
|  | RenderBlock::finishDelayUpdateScrollInfo(); | 
|  |  | 
|  | if (logicalHeight() != previousHeight) | 
|  | relayoutChildren = true; | 
|  |  | 
|  | layoutPositionedObjects(relayoutChildren || isDocumentElement()); | 
|  |  | 
|  | // FIXME: css3/flexbox/repaint-rtl-column.html seems to issue paint invalidations for more overflow than it needs to. | 
|  | computeOverflow(clientLogicalBottomAfterRepositioning()); | 
|  | } | 
|  |  | 
|  | updateLayerTransformAfterLayout(); | 
|  |  | 
|  | // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if | 
|  | // we overflow or not. | 
|  | updateScrollInfoAfterLayout(); | 
|  |  | 
|  | clearNeedsLayout(); | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::appendChildFrameRects(ChildFrameRects& childFrameRects) | 
|  | { | 
|  | for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) { | 
|  | if (!child->isOutOfFlowPositioned()) | 
|  | childFrameRects.append(child->frameRect()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset) | 
|  | { | 
|  | BlockPainter::paintChildrenOfFlexibleBox(*this, paintInfo, paintOffset); | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::repositionLogicalHeightDependentFlexItems(Vector<LineContext>& lineContexts) | 
|  | { | 
|  | LayoutUnit crossAxisStartEdge = lineContexts.isEmpty() ? LayoutUnit() : lineContexts[0].crossAxisOffset; | 
|  | alignFlexLines(lineContexts); | 
|  |  | 
|  | alignChildren(lineContexts); | 
|  |  | 
|  | if (style()->flexWrap() == FlexWrapReverse) | 
|  | flipForWrapReverse(lineContexts, crossAxisStartEdge); | 
|  |  | 
|  | // direction:rtl + flex-direction:column means the cross-axis direction is flipped. | 
|  | flipForRightToLeftColumn(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::clientLogicalBottomAfterRepositioning() | 
|  | { | 
|  | LayoutUnit maxChildLogicalBottom = 0; | 
|  | for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { | 
|  | if (child->isOutOfFlowPositioned()) | 
|  | continue; | 
|  | LayoutUnit childLogicalBottom = logicalTopForChild(child) + logicalHeightForChild(child) + marginAfterForChild(child); | 
|  | maxChildLogicalBottom = std::max(maxChildLogicalBottom, childLogicalBottom); | 
|  | } | 
|  | return std::max(clientLogicalBottom(), maxChildLogicalBottom + paddingAfter()); | 
|  | } | 
|  |  | 
|  | bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox& child) const | 
|  | { | 
|  | // FIXME: If the child is a flexbox, then we need to check isHorizontalFlow. | 
|  | return isHorizontalFlow() != child.isHorizontalWritingMode(); | 
|  | } | 
|  |  | 
|  | bool RenderFlexibleBox::isColumnFlow() const | 
|  | { | 
|  | return style()->isColumnFlexDirection(); | 
|  | } | 
|  |  | 
|  | bool RenderFlexibleBox::isHorizontalFlow() const | 
|  | { | 
|  | if (isHorizontalWritingMode()) | 
|  | return !isColumnFlow(); | 
|  | return isColumnFlow(); | 
|  | } | 
|  |  | 
|  | bool RenderFlexibleBox::isLeftToRightFlow() const | 
|  | { | 
|  | if (isColumnFlow()) | 
|  | return style()->writingMode() == TopToBottomWritingMode || style()->writingMode() == LeftToRightWritingMode; | 
|  | return style()->isLeftToRightDirection() ^ (style()->flexDirection() == FlowRowReverse); | 
|  | } | 
|  |  | 
|  | bool RenderFlexibleBox::isMultiline() const | 
|  | { | 
|  | return style()->flexWrap() != FlexNoWrap; | 
|  | } | 
|  |  | 
|  | Length RenderFlexibleBox::flexBasisForChild(RenderBox& child) const | 
|  | { | 
|  | Length flexLength = child.style()->flexBasis(); | 
|  | if (flexLength.isAuto()) | 
|  | flexLength = isHorizontalFlow() ? child.style()->width() : child.style()->height(); | 
|  | return flexLength; | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::crossAxisExtentForChild(RenderBox& child) const | 
|  | { | 
|  | return isHorizontalFlow() ? child.height() : child.width(); | 
|  | } | 
|  |  | 
|  | static inline LayoutUnit constrainedChildIntrinsicContentLogicalHeight(RenderBox& child) | 
|  | { | 
|  | LayoutUnit childIntrinsicContentLogicalHeight = child.intrinsicContentLogicalHeight(); | 
|  | return child.constrainLogicalHeightByMinMax(childIntrinsicContentLogicalHeight + child.borderAndPaddingLogicalHeight(), childIntrinsicContentLogicalHeight); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::childIntrinsicHeight(RenderBox& child) const | 
|  | { | 
|  | if (child.isHorizontalWritingMode() && needToStretchChildLogicalHeight(child)) | 
|  | return constrainedChildIntrinsicContentLogicalHeight(child); | 
|  | return child.height(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::childIntrinsicWidth(RenderBox& child) const | 
|  | { | 
|  | if (!child.isHorizontalWritingMode() && needToStretchChildLogicalHeight(child)) | 
|  | return constrainedChildIntrinsicContentLogicalHeight(child); | 
|  | return child.width(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::crossAxisIntrinsicExtentForChild(RenderBox& child) const | 
|  | { | 
|  | return isHorizontalFlow() ? childIntrinsicHeight(child) : childIntrinsicWidth(child); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::mainAxisExtentForChild(RenderBox& child) const | 
|  | { | 
|  | return isHorizontalFlow() ? child.width() : child.height(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::crossAxisExtent() const | 
|  | { | 
|  | return isHorizontalFlow() ? height() : width(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::mainAxisExtent() const | 
|  | { | 
|  | return isHorizontalFlow() ? width() : height(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::crossAxisContentExtent() const | 
|  | { | 
|  | return isHorizontalFlow() ? contentHeight() : contentWidth(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::mainAxisContentExtent(LayoutUnit contentLogicalHeight) | 
|  | { | 
|  | if (isColumnFlow()) { | 
|  | LogicalExtentComputedValues computedValues; | 
|  | LayoutUnit borderPaddingAndScrollbar = borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(); | 
|  | LayoutUnit borderBoxLogicalHeight = contentLogicalHeight + borderPaddingAndScrollbar; | 
|  | computeLogicalHeight(borderBoxLogicalHeight, logicalTop(), computedValues); | 
|  | if (computedValues.m_extent == LayoutUnit::max()) | 
|  | return computedValues.m_extent; | 
|  | return std::max(LayoutUnit(0), computedValues.m_extent - borderPaddingAndScrollbar); | 
|  | } | 
|  | return contentLogicalWidth(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::computeMainAxisExtentForChild(RenderBox& child, SizeType sizeType, const Length& size) | 
|  | { | 
|  | // FIXME: This is wrong for orthogonal flows. It should use the flexbox's writing-mode, not the child's in order | 
|  | // to figure out the logical height/width. | 
|  | if (isColumnFlow()) { | 
|  | // We don't have to check for "auto" here - computeContentLogicalHeight will just return -1 for that case anyway. | 
|  | if (size.isIntrinsic()) | 
|  | child.layoutIfNeeded(); | 
|  | return child.computeContentLogicalHeight(size, child.logicalHeight() - child.borderAndPaddingLogicalHeight()) + child.scrollbarLogicalHeight(); | 
|  | } | 
|  | return child.computeLogicalWidthUsing(sizeType, size, contentLogicalWidth(), this) - child.borderAndPaddingLogicalWidth(); | 
|  | } | 
|  |  | 
|  | WritingMode RenderFlexibleBox::transformedWritingMode() const | 
|  | { | 
|  | WritingMode mode = style()->writingMode(); | 
|  | if (!isColumnFlow()) | 
|  | return mode; | 
|  |  | 
|  | switch (mode) { | 
|  | case TopToBottomWritingMode: | 
|  | case BottomToTopWritingMode: | 
|  | return style()->isLeftToRightDirection() ? LeftToRightWritingMode : RightToLeftWritingMode; | 
|  | case LeftToRightWritingMode: | 
|  | case RightToLeftWritingMode: | 
|  | return style()->isLeftToRightDirection() ? TopToBottomWritingMode : BottomToTopWritingMode; | 
|  | } | 
|  | ASSERT_NOT_REACHED(); | 
|  | return TopToBottomWritingMode; | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::flowAwareBorderStart() const | 
|  | { | 
|  | if (isHorizontalFlow()) | 
|  | return isLeftToRightFlow() ? borderLeft() : borderRight(); | 
|  | return isLeftToRightFlow() ? borderTop() : borderBottom(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::flowAwareBorderEnd() const | 
|  | { | 
|  | if (isHorizontalFlow()) | 
|  | return isLeftToRightFlow() ? borderRight() : borderLeft(); | 
|  | return isLeftToRightFlow() ? borderBottom() : borderTop(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::flowAwareBorderBefore() const | 
|  | { | 
|  | switch (transformedWritingMode()) { | 
|  | case TopToBottomWritingMode: | 
|  | return borderTop(); | 
|  | case BottomToTopWritingMode: | 
|  | return borderBottom(); | 
|  | case LeftToRightWritingMode: | 
|  | return borderLeft(); | 
|  | case RightToLeftWritingMode: | 
|  | return borderRight(); | 
|  | } | 
|  | ASSERT_NOT_REACHED(); | 
|  | return borderTop(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::flowAwareBorderAfter() const | 
|  | { | 
|  | switch (transformedWritingMode()) { | 
|  | case TopToBottomWritingMode: | 
|  | return borderBottom(); | 
|  | case BottomToTopWritingMode: | 
|  | return borderTop(); | 
|  | case LeftToRightWritingMode: | 
|  | return borderRight(); | 
|  | case RightToLeftWritingMode: | 
|  | return borderLeft(); | 
|  | } | 
|  | ASSERT_NOT_REACHED(); | 
|  | return borderTop(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::flowAwarePaddingStart() const | 
|  | { | 
|  | if (isHorizontalFlow()) | 
|  | return isLeftToRightFlow() ? paddingLeft() : paddingRight(); | 
|  | return isLeftToRightFlow() ? paddingTop() : paddingBottom(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::flowAwarePaddingEnd() const | 
|  | { | 
|  | if (isHorizontalFlow()) | 
|  | return isLeftToRightFlow() ? paddingRight() : paddingLeft(); | 
|  | return isLeftToRightFlow() ? paddingBottom() : paddingTop(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::flowAwarePaddingBefore() const | 
|  | { | 
|  | switch (transformedWritingMode()) { | 
|  | case TopToBottomWritingMode: | 
|  | return paddingTop(); | 
|  | case BottomToTopWritingMode: | 
|  | return paddingBottom(); | 
|  | case LeftToRightWritingMode: | 
|  | return paddingLeft(); | 
|  | case RightToLeftWritingMode: | 
|  | return paddingRight(); | 
|  | } | 
|  | ASSERT_NOT_REACHED(); | 
|  | return paddingTop(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::flowAwarePaddingAfter() const | 
|  | { | 
|  | switch (transformedWritingMode()) { | 
|  | case TopToBottomWritingMode: | 
|  | return paddingBottom(); | 
|  | case BottomToTopWritingMode: | 
|  | return paddingTop(); | 
|  | case LeftToRightWritingMode: | 
|  | return paddingRight(); | 
|  | case RightToLeftWritingMode: | 
|  | return paddingLeft(); | 
|  | } | 
|  | ASSERT_NOT_REACHED(); | 
|  | return paddingTop(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::flowAwareMarginStartForChild(RenderBox& child) const | 
|  | { | 
|  | if (isHorizontalFlow()) | 
|  | return isLeftToRightFlow() ? child.marginLeft() : child.marginRight(); | 
|  | return isLeftToRightFlow() ? child.marginTop() : child.marginBottom(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::flowAwareMarginEndForChild(RenderBox& child) const | 
|  | { | 
|  | if (isHorizontalFlow()) | 
|  | return isLeftToRightFlow() ? child.marginRight() : child.marginLeft(); | 
|  | return isLeftToRightFlow() ? child.marginBottom() : child.marginTop(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::flowAwareMarginBeforeForChild(RenderBox& child) const | 
|  | { | 
|  | switch (transformedWritingMode()) { | 
|  | case TopToBottomWritingMode: | 
|  | return child.marginTop(); | 
|  | case BottomToTopWritingMode: | 
|  | return child.marginBottom(); | 
|  | case LeftToRightWritingMode: | 
|  | return child.marginLeft(); | 
|  | case RightToLeftWritingMode: | 
|  | return child.marginRight(); | 
|  | } | 
|  | ASSERT_NOT_REACHED(); | 
|  | return marginTop(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::crossAxisMarginExtentForChild(RenderBox& child) const | 
|  | { | 
|  | return isHorizontalFlow() ? child.marginHeight() : child.marginWidth(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::crossAxisScrollbarExtent() const | 
|  | { | 
|  | return isHorizontalFlow() ? horizontalScrollbarHeight() : verticalScrollbarWidth(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::crossAxisScrollbarExtentForChild(RenderBox& child) const | 
|  | { | 
|  | return isHorizontalFlow() ? child.horizontalScrollbarHeight() : child.verticalScrollbarWidth(); | 
|  | } | 
|  |  | 
|  | LayoutPoint RenderFlexibleBox::flowAwareLocationForChild(RenderBox& child) const | 
|  | { | 
|  | return isHorizontalFlow() ? child.location() : child.location().transposedPoint(); | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::setFlowAwareLocationForChild(RenderBox& child, const LayoutPoint& location) | 
|  | { | 
|  | if (isHorizontalFlow()) | 
|  | child.setLocation(location); | 
|  | else | 
|  | child.setLocation(location.transposedPoint()); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox& child) const | 
|  | { | 
|  | return isHorizontalFlow() ? child.borderAndPaddingWidth() : child.borderAndPaddingHeight(); | 
|  | } | 
|  |  | 
|  | static inline bool preferredMainAxisExtentDependsOnLayout(const Length& flexBasis, bool hasInfiniteLineLength) | 
|  | { | 
|  | return flexBasis.isAuto() || (flexBasis.isPercent() && hasInfiniteLineLength); | 
|  | } | 
|  |  | 
|  | bool RenderFlexibleBox::childPreferredMainAxisContentExtentRequiresLayout(RenderBox& child, bool hasInfiniteLineLength) const | 
|  | { | 
|  | return preferredMainAxisExtentDependsOnLayout(flexBasisForChild(child), hasInfiniteLineLength) && hasOrthogonalFlow(child); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox& child, bool hasInfiniteLineLength, bool relayoutChildren) | 
|  | { | 
|  | child.clearOverrideSize(); | 
|  |  | 
|  | if (child.isImage() || child.isVideo() || child.isCanvas()) | 
|  | UseCounter::count(document(), UseCounter::AspectRatioFlexItem); | 
|  |  | 
|  | Length flexBasis = flexBasisForChild(child); | 
|  | if (preferredMainAxisExtentDependsOnLayout(flexBasis, hasInfiniteLineLength)) { | 
|  | LayoutUnit mainAxisExtent; | 
|  | if (hasOrthogonalFlow(child)) { | 
|  | if (child.needsLayout() || relayoutChildren || !m_intrinsicSizeAlongMainAxis.contains(&child)) { | 
|  | m_intrinsicSizeAlongMainAxis.remove(&child); | 
|  | child.forceChildLayout(); | 
|  | m_intrinsicSizeAlongMainAxis.set(&child, child.logicalHeight()); | 
|  | } | 
|  | mainAxisExtent = m_intrinsicSizeAlongMainAxis.get(&child); | 
|  | } else { | 
|  | mainAxisExtent = child.maxPreferredLogicalWidth(); | 
|  | } | 
|  | ASSERT(mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child) >= 0); | 
|  | return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child); | 
|  | } | 
|  | return std::max(LayoutUnit(0), computeMainAxisExtentForChild(child, MainOrPreferredSize, flexBasis)); | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::layoutFlexItems(bool relayoutChildren) | 
|  | { | 
|  | Vector<LineContext> lineContexts; | 
|  | OrderedFlexItemList orderedChildren; | 
|  | LayoutUnit sumFlexBaseSize; | 
|  | double totalFlexGrow; | 
|  | double totalWeightedFlexShrink; | 
|  | LayoutUnit sumHypotheticalMainSize; | 
|  |  | 
|  | Vector<LayoutUnit, 16> childSizes; | 
|  |  | 
|  | m_orderIterator.first(); | 
|  | LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore(); | 
|  | bool hasInfiniteLineLength = false; | 
|  | while (computeNextFlexLine(orderedChildren, sumFlexBaseSize, totalFlexGrow, totalWeightedFlexShrink, sumHypotheticalMainSize, hasInfiniteLineLength, relayoutChildren)) { | 
|  | LayoutUnit containerMainInnerSize = mainAxisContentExtent(sumHypotheticalMainSize); | 
|  | LayoutUnit availableFreeSpace = containerMainInnerSize - sumFlexBaseSize; | 
|  | FlexSign flexSign = (sumHypotheticalMainSize < containerMainInnerSize) ? PositiveFlexibility : NegativeFlexibility; | 
|  | InflexibleFlexItemSize inflexibleItems; | 
|  | childSizes.reserveCapacity(orderedChildren.size()); | 
|  | while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, childSizes, hasInfiniteLineLength)) { | 
|  | ASSERT(totalFlexGrow >= 0 && totalWeightedFlexShrink >= 0); | 
|  | ASSERT(inflexibleItems.size() > 0); | 
|  | } | 
|  |  | 
|  | layoutAndPlaceChildren(crossAxisOffset, orderedChildren, childSizes, availableFreeSpace, relayoutChildren, lineContexts, hasInfiniteLineLength); | 
|  | } | 
|  | if (hasLineIfEmpty()) { | 
|  | // Even if computeNextFlexLine returns true, the flexbox might not have | 
|  | // a line because all our children might be out of flow positioned. | 
|  | // Instead of just checking if we have a line, make sure the flexbox | 
|  | // has at least a line's worth of height to cover this case. | 
|  | LayoutUnit minHeight = borderAndPaddingLogicalHeight() | 
|  | + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes) | 
|  | + scrollbarLogicalHeight(); | 
|  | if (height() < minHeight) | 
|  | setLogicalHeight(minHeight); | 
|  | } | 
|  |  | 
|  | updateLogicalHeight(); | 
|  | repositionLogicalHeightDependentFlexItems(lineContexts); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::autoMarginOffsetInMainAxis(const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace) | 
|  | { | 
|  | if (availableFreeSpace <= 0) | 
|  | return 0; | 
|  |  | 
|  | int numberOfAutoMargins = 0; | 
|  | bool isHorizontal = isHorizontalFlow(); | 
|  | for (size_t i = 0; i < children.size(); ++i) { | 
|  | RenderBox* child = children[i]; | 
|  | if (child->isOutOfFlowPositioned()) | 
|  | continue; | 
|  | if (isHorizontal) { | 
|  | if (child->style()->marginLeft().isAuto()) | 
|  | ++numberOfAutoMargins; | 
|  | if (child->style()->marginRight().isAuto()) | 
|  | ++numberOfAutoMargins; | 
|  | } else { | 
|  | if (child->style()->marginTop().isAuto()) | 
|  | ++numberOfAutoMargins; | 
|  | if (child->style()->marginBottom().isAuto()) | 
|  | ++numberOfAutoMargins; | 
|  | } | 
|  | } | 
|  | if (!numberOfAutoMargins) | 
|  | return 0; | 
|  |  | 
|  | LayoutUnit sizeOfAutoMargin = availableFreeSpace / numberOfAutoMargins; | 
|  | availableFreeSpace = 0; | 
|  | return sizeOfAutoMargin; | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::updateAutoMarginsInMainAxis(RenderBox& child, LayoutUnit autoMarginOffset) | 
|  | { | 
|  | ASSERT(autoMarginOffset >= 0); | 
|  |  | 
|  | if (isHorizontalFlow()) { | 
|  | if (child.style()->marginLeft().isAuto()) | 
|  | child.setMarginLeft(autoMarginOffset); | 
|  | if (child.style()->marginRight().isAuto()) | 
|  | child.setMarginRight(autoMarginOffset); | 
|  | } else { | 
|  | if (child.style()->marginTop().isAuto()) | 
|  | child.setMarginTop(autoMarginOffset); | 
|  | if (child.style()->marginBottom().isAuto()) | 
|  | child.setMarginBottom(autoMarginOffset); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool RenderFlexibleBox::hasAutoMarginsInCrossAxis(RenderBox& child) const | 
|  | { | 
|  | if (isHorizontalFlow()) | 
|  | return child.style()->marginTop().isAuto() || child.style()->marginBottom().isAuto(); | 
|  | return child.style()->marginLeft().isAuto() || child.style()->marginRight().isAuto(); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChild(LayoutUnit lineCrossAxisExtent, RenderBox& child) | 
|  | { | 
|  | ASSERT(!child.isOutOfFlowPositioned()); | 
|  | LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisExtentForChild(child); | 
|  | return lineCrossAxisExtent - childCrossExtent; | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::availableAlignmentSpaceForChildBeforeStretching(LayoutUnit lineCrossAxisExtent, RenderBox& child) | 
|  | { | 
|  | ASSERT(!child.isOutOfFlowPositioned()); | 
|  | LayoutUnit childCrossExtent = crossAxisMarginExtentForChild(child) + crossAxisIntrinsicExtentForChild(child); | 
|  | return lineCrossAxisExtent - childCrossExtent; | 
|  | } | 
|  |  | 
|  | bool RenderFlexibleBox::updateAutoMarginsInCrossAxis(RenderBox& child, LayoutUnit availableAlignmentSpace) | 
|  | { | 
|  | ASSERT(!child.isOutOfFlowPositioned()); | 
|  | ASSERT(availableAlignmentSpace >= 0); | 
|  |  | 
|  | bool isHorizontal = isHorizontalFlow(); | 
|  | Length topOrLeft = isHorizontal ? child.style()->marginTop() : child.style()->marginLeft(); | 
|  | Length bottomOrRight = isHorizontal ? child.style()->marginBottom() : child.style()->marginRight(); | 
|  | if (topOrLeft.isAuto() && bottomOrRight.isAuto()) { | 
|  | adjustAlignmentForChild(child, availableAlignmentSpace / 2); | 
|  | if (isHorizontal) { | 
|  | child.setMarginTop(availableAlignmentSpace / 2); | 
|  | child.setMarginBottom(availableAlignmentSpace / 2); | 
|  | } else { | 
|  | child.setMarginLeft(availableAlignmentSpace / 2); | 
|  | child.setMarginRight(availableAlignmentSpace / 2); | 
|  | } | 
|  | return true; | 
|  | } | 
|  | bool shouldAdjustTopOrLeft = true; | 
|  | if (isColumnFlow() && !child.style()->isLeftToRightDirection()) { | 
|  | // For column flows, only make this adjustment if topOrLeft corresponds to the "before" margin, | 
|  | // so that flipForRightToLeftColumn will do the right thing. | 
|  | shouldAdjustTopOrLeft = false; | 
|  | } | 
|  | if (!isColumnFlow() && child.style()->isFlippedBlocksWritingMode()) { | 
|  | // If we are a flipped writing mode, we need to adjust the opposite side. This is only needed | 
|  | // for row flows because this only affects the block-direction axis. | 
|  | shouldAdjustTopOrLeft = false; | 
|  | } | 
|  |  | 
|  | if (topOrLeft.isAuto()) { | 
|  | if (shouldAdjustTopOrLeft) | 
|  | adjustAlignmentForChild(child, availableAlignmentSpace); | 
|  |  | 
|  | if (isHorizontal) | 
|  | child.setMarginTop(availableAlignmentSpace); | 
|  | else | 
|  | child.setMarginLeft(availableAlignmentSpace); | 
|  | return true; | 
|  | } | 
|  | if (bottomOrRight.isAuto()) { | 
|  | if (!shouldAdjustTopOrLeft) | 
|  | adjustAlignmentForChild(child, availableAlignmentSpace); | 
|  |  | 
|  | if (isHorizontal) | 
|  | child.setMarginBottom(availableAlignmentSpace); | 
|  | else | 
|  | child.setMarginRight(availableAlignmentSpace); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::marginBoxAscentForChild(RenderBox& child) | 
|  | { | 
|  | LayoutUnit ascent = child.firstLineBoxBaseline(); | 
|  | if (ascent == -1) | 
|  | ascent = crossAxisExtentForChild(child); | 
|  | return ascent + flowAwareMarginBeforeForChild(child); | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::computeChildMarginValue(Length margin) | 
|  | { | 
|  | // When resolving the margins, we use the content size for resolving percent and calc (for percents in calc expressions) margins. | 
|  | // Fortunately, percent margins are always computed with respect to the block's width, even for margin-top and margin-bottom. | 
|  | LayoutUnit availableSize = contentLogicalWidth(); | 
|  | return minimumValueForLength(margin, availableSize); | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::prepareOrderIteratorAndMargins() | 
|  | { | 
|  | OrderIteratorPopulator populator(m_orderIterator); | 
|  |  | 
|  | for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { | 
|  | populator.collectChild(child); | 
|  |  | 
|  | if (child->isOutOfFlowPositioned()) | 
|  | continue; | 
|  |  | 
|  | // Before running the flex algorithm, 'auto' has a margin of 0. | 
|  | // Also, if we're not auto sizing, we don't do a layout that computes the start/end margins. | 
|  | if (isHorizontalFlow()) { | 
|  | child->setMarginLeft(computeChildMarginValue(child->style()->marginLeft())); | 
|  | child->setMarginRight(computeChildMarginValue(child->style()->marginRight())); | 
|  | } else { | 
|  | child->setMarginTop(computeChildMarginValue(child->style()->marginTop())); | 
|  | child->setMarginBottom(computeChildMarginValue(child->style()->marginBottom())); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox& child, LayoutUnit childSize) | 
|  | { | 
|  | Length max = isHorizontalFlow() ? child.style()->maxWidth() : child.style()->maxHeight(); | 
|  | if (max.isSpecifiedOrIntrinsic()) { | 
|  | LayoutUnit maxExtent = computeMainAxisExtentForChild(child, MaxSize, max); | 
|  | if (maxExtent != -1 && childSize > maxExtent) | 
|  | childSize = maxExtent; | 
|  | } | 
|  |  | 
|  | Length min = isHorizontalFlow() ? child.style()->minWidth() : child.style()->minHeight(); | 
|  | LayoutUnit minExtent = 0; | 
|  | if (min.isSpecifiedOrIntrinsic()) | 
|  | minExtent = computeMainAxisExtentForChild(child, MinSize, min); | 
|  | return std::max(childSize, minExtent); | 
|  | } | 
|  |  | 
|  | bool RenderFlexibleBox::computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& sumFlexBaseSize, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& sumHypotheticalMainSize, bool& hasInfiniteLineLength, bool relayoutChildren) | 
|  | { | 
|  | orderedChildren.clear(); | 
|  | sumFlexBaseSize = 0; | 
|  | totalFlexGrow = totalWeightedFlexShrink = 0; | 
|  | sumHypotheticalMainSize = 0; | 
|  |  | 
|  | if (!m_orderIterator.currentChild()) | 
|  | return false; | 
|  |  | 
|  | LayoutUnit lineBreakLength = mainAxisContentExtent(LayoutUnit::max()); | 
|  | hasInfiniteLineLength = lineBreakLength == LayoutUnit::max(); | 
|  |  | 
|  | bool lineHasInFlowItem = false; | 
|  |  | 
|  | for (RenderBox* child = m_orderIterator.currentChild(); child; child = m_orderIterator.next()) { | 
|  | if (child->isOutOfFlowPositioned()) { | 
|  | orderedChildren.append(child); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | LayoutUnit childMainAxisExtent = preferredMainAxisContentExtentForChild(*child, hasInfiniteLineLength, relayoutChildren); | 
|  | LayoutUnit childMainAxisMarginBorderPadding = mainAxisBorderAndPaddingExtentForChild(*child) | 
|  | + (isHorizontalFlow() ? child->marginWidth() : child->marginHeight()); | 
|  | LayoutUnit childFlexBaseSize = childMainAxisExtent + childMainAxisMarginBorderPadding; | 
|  |  | 
|  | LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(*child, childMainAxisExtent); | 
|  | LayoutUnit childHypotheticalMainSize = childMinMaxAppliedMainAxisExtent + childMainAxisMarginBorderPadding; | 
|  |  | 
|  | if (isMultiline() && sumHypotheticalMainSize + childHypotheticalMainSize > lineBreakLength && lineHasInFlowItem) | 
|  | break; | 
|  | orderedChildren.append(child); | 
|  | lineHasInFlowItem  = true; | 
|  | sumFlexBaseSize += childFlexBaseSize; | 
|  | totalFlexGrow += child->style()->flexGrow(); | 
|  | totalWeightedFlexShrink += child->style()->flexShrink() * childMainAxisExtent; | 
|  | sumHypotheticalMainSize += childHypotheticalMainSize; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::freezeViolations(const Vector<Violation>& violations, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, bool hasInfiniteLineLength) | 
|  | { | 
|  | for (size_t i = 0; i < violations.size(); ++i) { | 
|  | RenderBox* child = violations[i].child; | 
|  | LayoutUnit childSize = violations[i].childSize; | 
|  | LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(*child, hasInfiniteLineLength); | 
|  | availableFreeSpace -= childSize - preferredChildSize; | 
|  | totalFlexGrow -= child->style()->flexGrow(); | 
|  | totalWeightedFlexShrink -= child->style()->flexShrink() * preferredChildSize; | 
|  | inflexibleItems.set(child, childSize); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Returns true if we successfully ran the algorithm and sized the flex items. | 
|  | bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize& inflexibleItems, Vector<LayoutUnit, 16>& childSizes, bool hasInfiniteLineLength) | 
|  | { | 
|  | childSizes.resize(0); | 
|  | LayoutUnit totalViolation = 0; | 
|  | LayoutUnit usedFreeSpace = 0; | 
|  | Vector<Violation> minViolations; | 
|  | Vector<Violation> maxViolations; | 
|  | for (size_t i = 0; i < children.size(); ++i) { | 
|  | RenderBox* child = children[i]; | 
|  | if (child->isOutOfFlowPositioned()) { | 
|  | childSizes.append(0); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (inflexibleItems.contains(child)) | 
|  | childSizes.append(inflexibleItems.get(child)); | 
|  | else { | 
|  | LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(*child, hasInfiniteLineLength); | 
|  | LayoutUnit childSize = preferredChildSize; | 
|  | double extraSpace = 0; | 
|  | if (availableFreeSpace > 0 && totalFlexGrow > 0 && flexSign == PositiveFlexibility && std::isfinite(totalFlexGrow)) | 
|  | extraSpace = availableFreeSpace * child->style()->flexGrow() / totalFlexGrow; | 
|  | else if (availableFreeSpace < 0 && totalWeightedFlexShrink > 0 && flexSign == NegativeFlexibility && std::isfinite(totalWeightedFlexShrink)) | 
|  | extraSpace = availableFreeSpace * child->style()->flexShrink() * preferredChildSize / totalWeightedFlexShrink; | 
|  | if (std::isfinite(extraSpace)) | 
|  | childSize += LayoutUnit::fromFloatRound(extraSpace); | 
|  |  | 
|  | LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(*child, childSize); | 
|  | childSizes.append(adjustedChildSize); | 
|  | usedFreeSpace += adjustedChildSize - preferredChildSize; | 
|  |  | 
|  | LayoutUnit violation = adjustedChildSize - childSize; | 
|  | if (violation > 0) | 
|  | minViolations.append(Violation(child, adjustedChildSize)); | 
|  | else if (violation < 0) | 
|  | maxViolations.append(Violation(child, adjustedChildSize)); | 
|  | totalViolation += violation; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (totalViolation) | 
|  | freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalFlexGrow, totalWeightedFlexShrink, inflexibleItems, hasInfiniteLineLength); | 
|  | else | 
|  | availableFreeSpace -= usedFreeSpace; | 
|  |  | 
|  | return !totalViolation; | 
|  | } | 
|  |  | 
|  | static LayoutUnit initialJustifyContentOffset(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren) | 
|  | { | 
|  | if (justifyContent == JustifyFlexEnd) | 
|  | return availableFreeSpace; | 
|  | if (justifyContent == JustifyCenter) | 
|  | return availableFreeSpace / 2; | 
|  | if (justifyContent == JustifySpaceAround) { | 
|  | if (availableFreeSpace > 0 && numberOfChildren) | 
|  | return availableFreeSpace / (2 * numberOfChildren); | 
|  | else | 
|  | return availableFreeSpace / 2; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static LayoutUnit justifyContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EJustifyContent justifyContent, unsigned numberOfChildren) | 
|  | { | 
|  | if (availableFreeSpace > 0 && numberOfChildren > 1) { | 
|  | if (justifyContent == JustifySpaceBetween) | 
|  | return availableFreeSpace / (numberOfChildren - 1); | 
|  | if (justifyContent == JustifySpaceAround) | 
|  | return availableFreeSpace / numberOfChildren; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::setLogicalOverrideSize(RenderBox& child, LayoutUnit childPreferredSize) | 
|  | { | 
|  | if (hasOrthogonalFlow(child)) | 
|  | child.setOverrideLogicalContentHeight(childPreferredSize - child.borderAndPaddingLogicalHeight()); | 
|  | else | 
|  | child.setOverrideLogicalContentWidth(childPreferredSize - child.borderAndPaddingLogicalWidth()); | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::prepareChildForPositionedLayout(RenderBox& child, LayoutUnit mainAxisOffset, LayoutUnit crossAxisOffset, PositionedLayoutMode layoutMode) | 
|  | { | 
|  | ASSERT(child.isOutOfFlowPositioned()); | 
|  | child.containingBlock()->insertPositionedObject(&child); | 
|  | RenderLayer* childLayer = child.layer(); | 
|  | LayoutUnit inlinePosition = isColumnFlow() ? crossAxisOffset : mainAxisOffset; | 
|  | if (layoutMode == FlipForRowReverse && style()->flexDirection() == FlowRowReverse) | 
|  | inlinePosition = mainAxisExtent() - mainAxisOffset; | 
|  | childLayer->setStaticInlinePosition(inlinePosition); | 
|  |  | 
|  | LayoutUnit staticBlockPosition = isColumnFlow() ? mainAxisOffset : crossAxisOffset; | 
|  | if (childLayer->staticBlockPosition() != staticBlockPosition) { | 
|  | childLayer->setStaticBlockPosition(staticBlockPosition); | 
|  | if (child.style()->hasStaticBlockPosition(style()->isHorizontalWritingMode())) | 
|  | child.setChildNeedsLayout(MarkOnlyThis); | 
|  | } | 
|  | } | 
|  |  | 
|  | ItemPosition RenderFlexibleBox::alignmentForChild(RenderBox& child) const | 
|  | { | 
|  | ItemPosition align = RenderStyle::resolveAlignment(style(), child.style()); | 
|  |  | 
|  | if (align == ItemPositionBaseline && hasOrthogonalFlow(child)) | 
|  | align = ItemPositionFlexStart; | 
|  |  | 
|  | if (style()->flexWrap() == FlexWrapReverse) { | 
|  | if (align == ItemPositionFlexStart) | 
|  | align = ItemPositionFlexEnd; | 
|  | else if (align == ItemPositionFlexEnd) | 
|  | align = ItemPositionFlexStart; | 
|  | } | 
|  |  | 
|  | return align; | 
|  | } | 
|  |  | 
|  | size_t RenderFlexibleBox::numberOfInFlowPositionedChildren(const OrderedFlexItemList& children) const | 
|  | { | 
|  | size_t count = 0; | 
|  | for (size_t i = 0; i < children.size(); ++i) { | 
|  | RenderBox* child = children[i]; | 
|  | if (!child->isOutOfFlowPositioned()) | 
|  | ++count; | 
|  | } | 
|  | return count; | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox& child) | 
|  | { | 
|  | if (hasAutoMarginsInCrossAxis(child)) { | 
|  | child.updateLogicalHeight(); | 
|  | if (isHorizontalFlow()) { | 
|  | if (child.style()->marginTop().isAuto()) | 
|  | child.setMarginTop(0); | 
|  | if (child.style()->marginBottom().isAuto()) | 
|  | child.setMarginBottom(0); | 
|  | } else { | 
|  | if (child.style()->marginLeft().isAuto()) | 
|  | child.setMarginLeft(0); | 
|  | if (child.style()->marginRight().isAuto()) | 
|  | child.setMarginRight(0); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | bool RenderFlexibleBox::needToStretchChildLogicalHeight(RenderBox& child) const | 
|  | { | 
|  | if (alignmentForChild(child) != ItemPositionStretch) | 
|  | return false; | 
|  |  | 
|  | return isHorizontalFlow() && child.style()->height().isAuto(); | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const Vector<LayoutUnit, 16>& childSizes, LayoutUnit availableFreeSpace, bool relayoutChildren, Vector<LineContext>& lineContexts, bool hasInfiniteLineLength) | 
|  | { | 
|  | ASSERT(childSizes.size() == children.size()); | 
|  |  | 
|  | size_t numberOfChildrenForJustifyContent = numberOfInFlowPositionedChildren(children); | 
|  | LayoutUnit autoMarginOffset = autoMarginOffsetInMainAxis(children, availableFreeSpace); | 
|  | LayoutUnit mainAxisOffset = flowAwareBorderStart() + flowAwarePaddingStart(); | 
|  | mainAxisOffset += initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent); | 
|  | if (style()->flexDirection() == FlowRowReverse) | 
|  | mainAxisOffset += isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight(); | 
|  |  | 
|  | LayoutUnit totalMainExtent = mainAxisExtent(); | 
|  | LayoutUnit maxAscent = 0, maxDescent = 0; // Used when align-items: baseline. | 
|  | LayoutUnit maxChildCrossAxisExtent = 0; | 
|  | size_t seenInFlowPositionedChildren = 0; | 
|  | bool shouldFlipMainAxis = !isColumnFlow() && !isLeftToRightFlow(); | 
|  | for (size_t i = 0; i < children.size(); ++i) { | 
|  | RenderBox* child = children[i]; | 
|  |  | 
|  | if (child->isOutOfFlowPositioned()) { | 
|  | prepareChildForPositionedLayout(*child, mainAxisOffset, crossAxisOffset, FlipForRowReverse); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // FIXME Investigate if this can be removed based on other flags. crbug.com/370010 | 
|  | child->setMayNeedPaintInvalidation(true); | 
|  |  | 
|  | LayoutUnit childPreferredSize = childSizes[i] + mainAxisBorderAndPaddingExtentForChild(*child); | 
|  | setLogicalOverrideSize(*child, childPreferredSize); | 
|  | if (childPreferredSize != mainAxisExtentForChild(*child)) { | 
|  | child->setChildNeedsLayout(MarkOnlyThis); | 
|  | } else { | 
|  | // To avoid double applying margin changes in updateAutoMarginsInCrossAxis, we reset the margins here. | 
|  | resetAutoMarginsAndLogicalTopInCrossAxis(*child); | 
|  | } | 
|  | // We may have already forced relayout for orthogonal flowing children in preferredMainAxisContentExtentForChild. | 
|  | bool forceChildRelayout = relayoutChildren && !childPreferredMainAxisContentExtentRequiresLayout(*child, hasInfiniteLineLength); | 
|  | updateBlockChildDirtyBitsBeforeLayout(forceChildRelayout, child); | 
|  | child->layoutIfNeeded(); | 
|  |  | 
|  | updateAutoMarginsInMainAxis(*child, autoMarginOffset); | 
|  |  | 
|  | LayoutUnit childCrossAxisMarginBoxExtent; | 
|  | if (alignmentForChild(*child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(*child)) { | 
|  | LayoutUnit ascent = marginBoxAscentForChild(*child); | 
|  | LayoutUnit descent = (crossAxisMarginExtentForChild(*child) + crossAxisExtentForChild(*child)) - ascent; | 
|  |  | 
|  | maxAscent = std::max(maxAscent, ascent); | 
|  | maxDescent = std::max(maxDescent, descent); | 
|  |  | 
|  | childCrossAxisMarginBoxExtent = maxAscent + maxDescent; | 
|  | } else { | 
|  | childCrossAxisMarginBoxExtent = crossAxisIntrinsicExtentForChild(*child) + crossAxisMarginExtentForChild(*child) + crossAxisScrollbarExtentForChild(*child); | 
|  | } | 
|  | if (!isColumnFlow()) | 
|  | setLogicalHeight(std::max(logicalHeight(), crossAxisOffset + flowAwareBorderAfter() + flowAwarePaddingAfter() + childCrossAxisMarginBoxExtent + crossAxisScrollbarExtent())); | 
|  | maxChildCrossAxisExtent = std::max(maxChildCrossAxisExtent, childCrossAxisMarginBoxExtent); | 
|  |  | 
|  | mainAxisOffset += flowAwareMarginStartForChild(*child); | 
|  |  | 
|  | LayoutUnit childMainExtent = mainAxisExtentForChild(*child); | 
|  | // In an RTL column situation, this will apply the margin-right/margin-end on the left. | 
|  | // This will be fixed later in flipForRightToLeftColumn. | 
|  | LayoutPoint childLocation(shouldFlipMainAxis ? totalMainExtent - mainAxisOffset - childMainExtent : mainAxisOffset, | 
|  | crossAxisOffset + flowAwareMarginBeforeForChild(*child)); | 
|  |  | 
|  | // FIXME: Supporting layout deltas. | 
|  | setFlowAwareLocationForChild(*child, childLocation); | 
|  | mainAxisOffset += childMainExtent + flowAwareMarginEndForChild(*child); | 
|  |  | 
|  | ++seenInFlowPositionedChildren; | 
|  | if (seenInFlowPositionedChildren < numberOfChildrenForJustifyContent) | 
|  | mainAxisOffset += justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent); | 
|  | } | 
|  |  | 
|  | if (isColumnFlow()) | 
|  | setLogicalHeight(mainAxisOffset + flowAwareBorderEnd() + flowAwarePaddingEnd() + scrollbarLogicalHeight()); | 
|  |  | 
|  | if (style()->flexDirection() == FlowColumnReverse) { | 
|  | // We have to do an extra pass for column-reverse to reposition the flex items since the start depends | 
|  | // on the height of the flexbox, which we only know after we've positioned all the flex items. | 
|  | updateLogicalHeight(); | 
|  | layoutColumnReverse(children, crossAxisOffset, availableFreeSpace); | 
|  | } | 
|  |  | 
|  | if (m_numberOfInFlowChildrenOnFirstLine == -1) | 
|  | m_numberOfInFlowChildrenOnFirstLine = seenInFlowPositionedChildren; | 
|  | lineContexts.append(LineContext(crossAxisOffset, maxChildCrossAxisExtent, children.size(), maxAscent)); | 
|  | crossAxisOffset += maxChildCrossAxisExtent; | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::layoutColumnReverse(const OrderedFlexItemList& children, LayoutUnit crossAxisOffset, LayoutUnit availableFreeSpace) | 
|  | { | 
|  | // This is similar to the logic in layoutAndPlaceChildren, except we place the children | 
|  | // starting from the end of the flexbox. We also don't need to layout anything since we're | 
|  | // just moving the children to a new position. | 
|  | size_t numberOfChildrenForJustifyContent = numberOfInFlowPositionedChildren(children); | 
|  | LayoutUnit mainAxisOffset = logicalHeight() - flowAwareBorderEnd() - flowAwarePaddingEnd(); | 
|  | mainAxisOffset -= initialJustifyContentOffset(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent); | 
|  | mainAxisOffset -= isHorizontalFlow() ? verticalScrollbarWidth() : horizontalScrollbarHeight(); | 
|  |  | 
|  | size_t seenInFlowPositionedChildren = 0; | 
|  | for (size_t i = 0; i < children.size(); ++i) { | 
|  | RenderBox* child = children[i]; | 
|  |  | 
|  | if (child->isOutOfFlowPositioned()) { | 
|  | child->layer()->setStaticBlockPosition(mainAxisOffset); | 
|  | continue; | 
|  | } | 
|  | mainAxisOffset -= mainAxisExtentForChild(*child) + flowAwareMarginEndForChild(*child); | 
|  |  | 
|  | setFlowAwareLocationForChild(*child, LayoutPoint(mainAxisOffset, crossAxisOffset + flowAwareMarginBeforeForChild(*child))); | 
|  |  | 
|  | mainAxisOffset -= flowAwareMarginStartForChild(*child); | 
|  |  | 
|  | ++seenInFlowPositionedChildren; | 
|  | if (seenInFlowPositionedChildren < numberOfChildrenForJustifyContent) | 
|  | mainAxisOffset -= justifyContentSpaceBetweenChildren(availableFreeSpace, style()->justifyContent(), numberOfChildrenForJustifyContent); | 
|  | } | 
|  | } | 
|  |  | 
|  | static LayoutUnit initialAlignContentOffset(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines) | 
|  | { | 
|  | if (numberOfLines <= 1) | 
|  | return 0; | 
|  | if (alignContent == AlignContentFlexEnd) | 
|  | return availableFreeSpace; | 
|  | if (alignContent == AlignContentCenter) | 
|  | return availableFreeSpace / 2; | 
|  | if (alignContent == AlignContentSpaceAround) { | 
|  | if (availableFreeSpace > 0 && numberOfLines) | 
|  | return availableFreeSpace / (2 * numberOfLines); | 
|  | if (availableFreeSpace < 0) | 
|  | return availableFreeSpace / 2; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static LayoutUnit alignContentSpaceBetweenChildren(LayoutUnit availableFreeSpace, EAlignContent alignContent, unsigned numberOfLines) | 
|  | { | 
|  | if (availableFreeSpace > 0 && numberOfLines > 1) { | 
|  | if (alignContent == AlignContentSpaceBetween) | 
|  | return availableFreeSpace / (numberOfLines - 1); | 
|  | if (alignContent == AlignContentSpaceAround || alignContent == AlignContentStretch) | 
|  | return availableFreeSpace / numberOfLines; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::alignFlexLines(Vector<LineContext>& lineContexts) | 
|  | { | 
|  | // If we have a single line flexbox or a multiline line flexbox with only one flex line, | 
|  | // the line height is all the available space. | 
|  | // For flex-direction: row, this means we need to use the height, so we do this after calling updateLogicalHeight. | 
|  | if (lineContexts.size() == 1) { | 
|  | lineContexts[0].crossAxisExtent = crossAxisContentExtent(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (style()->alignContent() == AlignContentFlexStart) | 
|  | return; | 
|  |  | 
|  | LayoutUnit availableCrossAxisSpace = crossAxisContentExtent(); | 
|  | for (size_t i = 0; i < lineContexts.size(); ++i) | 
|  | availableCrossAxisSpace -= lineContexts[i].crossAxisExtent; | 
|  |  | 
|  | RenderBox* child = m_orderIterator.first(); | 
|  | LayoutUnit lineOffset = initialAlignContentOffset(availableCrossAxisSpace, style()->alignContent(), lineContexts.size()); | 
|  | for (unsigned lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) { | 
|  | lineContexts[lineNumber].crossAxisOffset += lineOffset; | 
|  | for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) | 
|  | adjustAlignmentForChild(*child, lineOffset); | 
|  |  | 
|  | if (style()->alignContent() == AlignContentStretch && availableCrossAxisSpace > 0) | 
|  | lineContexts[lineNumber].crossAxisExtent += availableCrossAxisSpace / static_cast<unsigned>(lineContexts.size()); | 
|  |  | 
|  | lineOffset += alignContentSpaceBetweenChildren(availableCrossAxisSpace, style()->alignContent(), lineContexts.size()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::adjustAlignmentForChild(RenderBox& child, LayoutUnit delta) | 
|  | { | 
|  | if (child.isOutOfFlowPositioned()) { | 
|  | LayoutUnit staticInlinePosition = child.layer()->staticInlinePosition(); | 
|  | LayoutUnit staticBlockPosition = child.layer()->staticBlockPosition(); | 
|  | LayoutUnit mainAxis = isColumnFlow() ? staticBlockPosition : staticInlinePosition; | 
|  | LayoutUnit crossAxis = isColumnFlow() ? staticInlinePosition : staticBlockPosition; | 
|  | crossAxis += delta; | 
|  | prepareChildForPositionedLayout(child, mainAxis, crossAxis, NoFlipForRowReverse); | 
|  | return; | 
|  | } | 
|  |  | 
|  | setFlowAwareLocationForChild(child, flowAwareLocationForChild(child) + LayoutSize(0, delta)); | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::alignChildren(const Vector<LineContext>& lineContexts) | 
|  | { | 
|  | // Keep track of the space between the baseline edge and the after edge of the box for each line. | 
|  | Vector<LayoutUnit> minMarginAfterBaselines; | 
|  |  | 
|  | RenderBox* child = m_orderIterator.first(); | 
|  | for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) { | 
|  | LayoutUnit minMarginAfterBaseline = LayoutUnit::max(); | 
|  | LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent; | 
|  | LayoutUnit maxAscent = lineContexts[lineNumber].maxAscent; | 
|  |  | 
|  | for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) { | 
|  | ASSERT(child); | 
|  | if (child->isOutOfFlowPositioned()) { | 
|  | if (style()->flexWrap() == FlexWrapReverse) | 
|  | adjustAlignmentForChild(*child, lineCrossAxisExtent); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (updateAutoMarginsInCrossAxis(*child, std::max(LayoutUnit(0), availableAlignmentSpaceForChild(lineCrossAxisExtent, *child)))) | 
|  | continue; | 
|  |  | 
|  | switch (alignmentForChild(*child)) { | 
|  | case ItemPositionAuto: | 
|  | ASSERT_NOT_REACHED(); | 
|  | break; | 
|  | case ItemPositionStretch: { | 
|  | applyStretchAlignmentToChild(*child, lineCrossAxisExtent); | 
|  | // Since wrap-reverse flips cross start and cross end, strech children should be aligned with the cross end. | 
|  | if (style()->flexWrap() == FlexWrapReverse) | 
|  | adjustAlignmentForChild(*child, availableAlignmentSpaceForChild(lineCrossAxisExtent, *child)); | 
|  | break; | 
|  | } | 
|  | case ItemPositionFlexStart: | 
|  | break; | 
|  | case ItemPositionFlexEnd: | 
|  | adjustAlignmentForChild(*child, availableAlignmentSpaceForChild(lineCrossAxisExtent, *child)); | 
|  | break; | 
|  | case ItemPositionCenter: | 
|  | adjustAlignmentForChild(*child, availableAlignmentSpaceForChild(lineCrossAxisExtent, *child) / 2); | 
|  | break; | 
|  | case ItemPositionBaseline: { | 
|  | // FIXME: If we get here in columns, we want the use the descent, except we currently can't get the ascent/descent of orthogonal children. | 
|  | // https://bugs.webkit.org/show_bug.cgi?id=98076 | 
|  | LayoutUnit ascent = marginBoxAscentForChild(*child); | 
|  | LayoutUnit startOffset = maxAscent - ascent; | 
|  | adjustAlignmentForChild(*child, startOffset); | 
|  |  | 
|  | if (style()->flexWrap() == FlexWrapReverse) | 
|  | minMarginAfterBaseline = std::min(minMarginAfterBaseline, availableAlignmentSpaceForChild(lineCrossAxisExtent, *child) - startOffset); | 
|  | break; | 
|  | } | 
|  | case ItemPositionLastBaseline: | 
|  | case ItemPositionSelfStart: | 
|  | case ItemPositionSelfEnd: | 
|  | case ItemPositionStart: | 
|  | case ItemPositionEnd: | 
|  | case ItemPositionLeft: | 
|  | case ItemPositionRight: | 
|  | // FIXME: File a bug about implementing that. The extended grammar | 
|  | // is not enabled by default so we shouldn't hit this codepath. | 
|  | ASSERT_NOT_REACHED(); | 
|  | break; | 
|  | } | 
|  | } | 
|  | minMarginAfterBaselines.append(minMarginAfterBaseline); | 
|  | } | 
|  |  | 
|  | if (style()->flexWrap() != FlexWrapReverse) | 
|  | return; | 
|  |  | 
|  | // wrap-reverse flips the cross axis start and end. For baseline alignment, this means we | 
|  | // need to align the after edge of baseline elements with the after edge of the flex line. | 
|  | child = m_orderIterator.first(); | 
|  | for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) { | 
|  | LayoutUnit minMarginAfterBaseline = minMarginAfterBaselines[lineNumber]; | 
|  | for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) { | 
|  | ASSERT(child); | 
|  | if (alignmentForChild(*child) == ItemPositionBaseline && !hasAutoMarginsInCrossAxis(*child) && minMarginAfterBaseline) | 
|  | adjustAlignmentForChild(*child, minMarginAfterBaseline); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::applyStretchAlignmentToChild(RenderBox& child, LayoutUnit lineCrossAxisExtent) | 
|  | { | 
|  | if (!isColumnFlow() && child.style()->logicalHeight().isAuto()) { | 
|  | // FIXME: If the child has orthogonal flow, then it already has an override height set, so use it. | 
|  | if (!hasOrthogonalFlow(child)) { | 
|  | LayoutUnit heightBeforeStretching = needToStretchChildLogicalHeight(child) ? constrainedChildIntrinsicContentLogicalHeight(child) : child.logicalHeight(); | 
|  | LayoutUnit stretchedLogicalHeight = heightBeforeStretching + availableAlignmentSpaceForChildBeforeStretching(lineCrossAxisExtent, child); | 
|  | ASSERT(!child.needsLayout()); | 
|  | LayoutUnit desiredLogicalHeight = child.constrainLogicalHeightByMinMax(stretchedLogicalHeight, heightBeforeStretching - child.borderAndPaddingLogicalHeight()); | 
|  |  | 
|  | // FIXME: Can avoid laying out here in some cases. See https://webkit.org/b/87905. | 
|  | bool childNeedsRelayout = desiredLogicalHeight != child.logicalHeight(); | 
|  | if (childNeedsRelayout || !child.hasOverrideHeight()) | 
|  | child.setOverrideLogicalContentHeight(desiredLogicalHeight - child.borderAndPaddingLogicalHeight()); | 
|  | if (childNeedsRelayout) { | 
|  | child.setLogicalHeight(0); | 
|  | child.forceChildLayout(); | 
|  | } | 
|  | } | 
|  | } else if (isColumnFlow() && child.style()->logicalWidth().isAuto()) { | 
|  | // FIXME: If the child doesn't have orthogonal flow, then it already has an override width set, so use it. | 
|  | if (hasOrthogonalFlow(child)) { | 
|  | LayoutUnit childWidth = std::max<LayoutUnit>(0, lineCrossAxisExtent - crossAxisMarginExtentForChild(child)); | 
|  | childWidth = child.constrainLogicalWidthByMinMax(childWidth, childWidth, this); | 
|  |  | 
|  | if (childWidth != child.logicalWidth()) { | 
|  | child.setOverrideLogicalContentWidth(childWidth - child.borderAndPaddingLogicalWidth()); | 
|  | child.forceChildLayout(); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::flipForRightToLeftColumn() | 
|  | { | 
|  | if (style()->isLeftToRightDirection() || !isColumnFlow()) | 
|  | return; | 
|  |  | 
|  | LayoutUnit crossExtent = crossAxisExtent(); | 
|  | for (RenderBox* child = m_orderIterator.first(); child; child = m_orderIterator.next()) { | 
|  | if (child->isOutOfFlowPositioned()) | 
|  | continue; | 
|  | LayoutPoint location = flowAwareLocationForChild(*child); | 
|  | // For vertical flows, setFlowAwareLocationForChild will transpose x and y, | 
|  | // so using the y axis for a column cross axis extent is correct. | 
|  | location.setY(crossExtent - crossAxisExtentForChild(*child) - location.y()); | 
|  | setFlowAwareLocationForChild(*child, location); | 
|  | } | 
|  | } | 
|  |  | 
|  | void RenderFlexibleBox::flipForWrapReverse(const Vector<LineContext>& lineContexts, LayoutUnit crossAxisStartEdge) | 
|  | { | 
|  | LayoutUnit contentExtent = crossAxisContentExtent(); | 
|  | RenderBox* child = m_orderIterator.first(); | 
|  | for (size_t lineNumber = 0; lineNumber < lineContexts.size(); ++lineNumber) { | 
|  | for (size_t childNumber = 0; childNumber < lineContexts[lineNumber].numberOfChildren; ++childNumber, child = m_orderIterator.next()) { | 
|  | ASSERT(child); | 
|  | LayoutUnit lineCrossAxisExtent = lineContexts[lineNumber].crossAxisExtent; | 
|  | LayoutUnit originalOffset = lineContexts[lineNumber].crossAxisOffset - crossAxisStartEdge; | 
|  | LayoutUnit newOffset = contentExtent - originalOffset - lineCrossAxisExtent; | 
|  | adjustAlignmentForChild(*child, newOffset - originalOffset); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | } |