| Index: third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
|
| diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
|
| index 150aa1552105867a01155737122445e8b3598b3f..ce2fe9ff2625cfe6510230ca2161299f1cf04aee 100644
|
| --- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
|
| +++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
|
| @@ -69,6 +69,7 @@ struct SameSizeAsMarginInfo {
|
|
|
| static_assert(sizeof(LayoutBlockFlow::MarginValues) == sizeof(LayoutUnit[4]), "MarginValues should stay small");
|
|
|
| +// Caches all our current margin collapsing state.
|
| class MarginInfo {
|
| // Collapsing flags for whether we can collapse our margins with our children's margins.
|
| bool m_canCollapseWithChildren : 1;
|
| @@ -154,6 +155,28 @@ public:
|
| bool lastChildIsSelfCollapsingBlockWithClearance() const { return m_lastChildIsSelfCollapsingBlockWithClearance; }
|
| };
|
|
|
| +// Some features, such as floats, margin collapsing and fragmentation, require some knowledge about
|
| +// things that happened when laying out previous block child siblings. Only looking at the object
|
| +// currently being laid out isn't always enough.
|
| +class BlockChildrenLayoutInfo {
|
| +public:
|
| + BlockChildrenLayoutInfo(LayoutBlockFlow* blockFlow, LayoutUnit beforeEdge, LayoutUnit afterEdge)
|
| + : m_marginInfo(blockFlow, beforeEdge, afterEdge)
|
| + , m_isAtFirstInFlowChild(true) { }
|
| +
|
| + const MarginInfo& marginInfo() const { return m_marginInfo; }
|
| + MarginInfo& marginInfo() { return m_marginInfo; }
|
| + LayoutUnit& previousFloatLogicalBottom() { return m_previousFloatLogicalBottom; }
|
| +
|
| + bool isAtFirstInFlowChild() const { return m_isAtFirstInFlowChild; }
|
| + void clearIsAtFirstInFlowChild() { m_isAtFirstInFlowChild = false; }
|
| +
|
| +private:
|
| + MarginInfo m_marginInfo;
|
| + LayoutUnit m_previousFloatLogicalBottom;
|
| + bool m_isAtFirstInFlowChild;
|
| +};
|
| +
|
| LayoutBlockFlow::LayoutBlockFlow(ContainerNode* node)
|
| : LayoutBlock(node)
|
| {
|
| @@ -523,9 +546,10 @@ void LayoutBlockFlow::markDescendantsWithFloatsForLayoutIfNeeded(LayoutBlockFlow
|
| child.markAllDescendantsWithFloatsForLayout();
|
| }
|
|
|
| -bool LayoutBlockFlow::positionAndLayoutOnceIfNeeded(LayoutBox& child, LayoutUnit newLogicalTop, LayoutUnit& previousFloatLogicalBottom)
|
| +bool LayoutBlockFlow::positionAndLayoutOnceIfNeeded(LayoutBox& child, LayoutUnit newLogicalTop, BlockChildrenLayoutInfo& layoutInfo)
|
| {
|
| if (child.isLayoutBlockFlow()) {
|
| + LayoutUnit& previousFloatLogicalBottom = layoutInfo.previousFloatLogicalBottom();
|
| LayoutBlockFlow& childBlockFlow = toLayoutBlockFlow(child);
|
| if (childBlockFlow.containsFloats() || containsFloats())
|
| markDescendantsWithFloatsForLayoutIfNeeded(childBlockFlow, newLogicalTop, previousFloatLogicalBottom);
|
| @@ -556,8 +580,9 @@ bool LayoutBlockFlow::positionAndLayoutOnceIfNeeded(LayoutBox& child, LayoutUnit
|
| return true;
|
| }
|
|
|
| -void LayoutBlockFlow::layoutBlockChild(LayoutBox& child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom)
|
| +void LayoutBlockFlow::layoutBlockChild(LayoutBox& child, BlockChildrenLayoutInfo& layoutInfo)
|
| {
|
| + MarginInfo& marginInfo = layoutInfo.marginInfo();
|
| LayoutBlockFlow* childLayoutBlockFlow = child.isLayoutBlockFlow() ? toLayoutBlockFlow(&child) : nullptr;
|
| LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
|
| LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
|
| @@ -577,7 +602,7 @@ void LayoutBlockFlow::layoutBlockChild(LayoutBox& child, MarginInfo& marginInfo,
|
| // Use the estimated block position and lay out the child if needed. After child layout, when
|
| // we have enough information to perform proper margin collapsing, float clearing and
|
| // pagination, we may have to reposition and lay out again if the estimate was wrong.
|
| - bool childNeededLayout = positionAndLayoutOnceIfNeeded(child, logicalTopEstimate, previousFloatLogicalBottom);
|
| + bool childNeededLayout = positionAndLayoutOnceIfNeeded(child, logicalTopEstimate, layoutInfo);
|
|
|
| // Cache if we are at the top of the block right now.
|
| bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
|
| @@ -600,10 +625,10 @@ void LayoutBlockFlow::layoutBlockChild(LayoutBox& child, MarginInfo& marginInfo,
|
| // We got a new position due to clearance or margin collapsing. Before we attempt to
|
| // paginate (which may result in the position changing again), let's try again at the
|
| // new position (since a new position may result in a new logical height).
|
| - positionAndLayoutOnceIfNeeded(child, newLogicalTop, previousFloatLogicalBottom);
|
| + positionAndLayoutOnceIfNeeded(child, newLogicalTop, layoutInfo);
|
| }
|
|
|
| - newLogicalTop = adjustBlockChildForPagination(newLogicalTop, child, atBeforeSideOfBlock && logicalTopBeforeClear == newLogicalTop);
|
| + newLogicalTop = adjustBlockChildForPagination(newLogicalTop, child, layoutInfo, atBeforeSideOfBlock && logicalTopBeforeClear == newLogicalTop);
|
| }
|
|
|
| // Clearance, margin collapsing or pagination may have given us a new logical top, in which
|
| @@ -612,7 +637,7 @@ void LayoutBlockFlow::layoutBlockChild(LayoutBox& child, MarginInfo& marginInfo,
|
| if (newLogicalTop != logicalTopEstimate
|
| || child.needsLayout()
|
| || (paginated && childLayoutBlockFlow && childLayoutBlockFlow->shouldBreakAtLineToAvoidWidow())) {
|
| - positionAndLayoutOnceIfNeeded(child, newLogicalTop, previousFloatLogicalBottom);
|
| + positionAndLayoutOnceIfNeeded(child, newLogicalTop, layoutInfo);
|
| }
|
|
|
| // If we previously encountered a self-collapsing sibling of this child that had clearance then
|
| @@ -662,7 +687,7 @@ void LayoutBlockFlow::layoutBlockChild(LayoutBox& child, MarginInfo& marginInfo,
|
| }
|
| }
|
|
|
| -LayoutUnit LayoutBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTop, LayoutBox& child, bool atBeforeSideOfBlock)
|
| +LayoutUnit LayoutBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTop, LayoutBox& child, BlockChildrenLayoutInfo& layoutInfo, bool atBeforeSideOfBlock)
|
| {
|
| LayoutBlockFlow* childBlockFlow = child.isLayoutBlockFlow() ? toLayoutBlockFlow(&child) : 0;
|
|
|
| @@ -696,9 +721,11 @@ LayoutUnit LayoutBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTop,
|
| LayoutUnit newLogicalTop = logicalTop;
|
| if (LayoutUnit paginationStrut = logicalTopAfterPagination - logicalTop) {
|
| ASSERT(paginationStrut > 0);
|
| - // We are willing to propagate out to our parent block as long as we were at the top of the block prior
|
| - // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
|
| - if (atBeforeSideOfBlock && logicalTopAfterForcedBreak == logicalTop && allowsPaginationStrut()) {
|
| + // If we're not at the first in-flow child, there's a class A break point before the child. If we *are* at the
|
| + // first in-flow child, but the child isn't flush with the content edge of its container, due to e.g. clearance,
|
| + // there's a class C break point before the child. Otherwise we should propagate the strut to our parent block,
|
| + // and attempt to break there instead. See https://drafts.csswg.org/css-break/#possible-breaks
|
| + if (layoutInfo.isAtFirstInFlowChild() && atBeforeSideOfBlock && logicalTopAfterForcedBreak == logicalTop && allowsPaginationStrut()) {
|
| // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
|
| // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
|
| // and pushes to the next page anyway, so not too concerned about it.
|
| @@ -998,16 +1025,14 @@ void LayoutBlockFlow::layoutBlockChildren(bool relayoutChildren, SubtreeLayoutSc
|
| {
|
| dirtyForLayoutFromPercentageHeightDescendants(layoutScope);
|
|
|
| - // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts,
|
| - MarginInfo marginInfo(this, beforeEdge, afterEdge);
|
| + BlockChildrenLayoutInfo layoutInfo(this, beforeEdge, afterEdge);
|
| + MarginInfo& marginInfo = layoutInfo.marginInfo();
|
|
|
| // Fieldsets need to find their legend and position it inside the border of the object.
|
| // The legend then gets skipped during normal layout. The same is true for ruby text.
|
| // It doesn't get included in the normal layout process but is instead skipped.
|
| LayoutObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren, layoutScope);
|
|
|
| - LayoutUnit previousFloatLogicalBottom;
|
| -
|
| LayoutBox* next = firstChildBox();
|
| LayoutBox* lastNormalFlowChild = nullptr;
|
|
|
| @@ -1046,7 +1071,8 @@ void LayoutBlockFlow::layoutBlockChildren(bool relayoutChildren, SubtreeLayoutSc
|
| }
|
|
|
| // Lay out the child.
|
| - layoutBlockChild(*child, marginInfo, previousFloatLogicalBottom);
|
| + layoutBlockChild(*child, layoutInfo);
|
| + layoutInfo.clearIsAtFirstInFlowChild();
|
| lastNormalFlowChild = child;
|
| }
|
|
|
|
|