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 3f9c12f381a38e37c3da6530c8d553774887fc86..92885dac8d79a9247a7cdc442cd2bae88a0e39cc 100644 |
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp |
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp |
@@ -685,27 +685,47 @@ LayoutUnit LayoutBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTop, |
{ |
LayoutBlockFlow* childBlockFlow = child.isLayoutBlockFlow() ? toLayoutBlockFlow(&child) : 0; |
+ // Calculate the pagination strut for this child. A strut may come from three sources: |
+ // 1. The first piece of content inside the child doesn't fit in the current page or column |
+ // 2. A forced break before the child |
+ // 3. The child itself is unsplittable and doesn't fit in the current page or column. |
+ // |
+ // No matter which source, if we need to insert a strut, it should always take us to the exact |
+ // top of the next page or column, or be zero. |
+ |
+ // We're now going to calculate the child's final pagination strut. We may end up propagating |
+ // it to its containing block (|this|), so reset it first. |
+ child.resetPaginationStrut(); |
+ |
+ // The first piece of content inside the child may have set a strut during layout. Currently, |
+ // only block flows support strut propagation, but this may (and should) change in the future. |
+ // See crbug.com/539873 |
+ LayoutUnit strutFromContent = childBlockFlow ? childBlockFlow->paginationStrutPropagatedFromChild() : LayoutUnit(); |
+ LayoutUnit logicalTopWithContentStrut = logicalTop + strutFromContent; |
+ |
// If the object has a page or column break value of "before", then we should shift to the top of the next page. |
- LayoutUnit newLogicalTop = applyBeforeBreak(child, logicalTop); |
+ LayoutUnit logicalTopAfterForcedBreak = applyBeforeBreak(child, logicalTop); |
// For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one. |
- LayoutUnit logicalTopBeforeUnsplittableAdjustment = newLogicalTop; |
- LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, newLogicalTop); |
- |
- LayoutUnit paginationStrut = 0; |
- LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment; |
+ LayoutUnit logicalTopAfterUnsplittable = adjustForUnsplittableChild(child, logicalTop); |
LayoutUnit childLogicalHeight = child.logicalHeight(); |
- if (unsplittableAdjustmentDelta) { |
- setPageBreak(newLogicalTop, childLogicalHeight - unsplittableAdjustmentDelta); |
- paginationStrut = unsplittableAdjustmentDelta; |
- } else if (childBlockFlow && childBlockFlow->paginationStrutPropagatedFromChild()) { |
- paginationStrut = childBlockFlow->paginationStrutPropagatedFromChild(); |
- } |
- |
- if (paginationStrut) { |
+ bool neededBreakForUnsplittable = logicalTopAfterUnsplittable != logicalTop; |
+ if (neededBreakForUnsplittable) |
+ setPageBreak(logicalTop, childLogicalHeight - (logicalTopAfterUnsplittable - logicalTop)); |
+ |
+ // Some sanity checks: No matter what the reason is for pushing the child to the next page or |
+ // column, the amount should be the same. |
+ ASSERT(!strutFromContent || logicalTopAfterForcedBreak == logicalTop || logicalTopAfterForcedBreak == logicalTopWithContentStrut); |
+ ASSERT(!strutFromContent || logicalTopAfterUnsplittable == logicalTop || logicalTopAfterUnsplittable == logicalTopWithContentStrut); |
+ ASSERT(logicalTopAfterUnsplittable == logicalTop || logicalTopAfterForcedBreak == logicalTop || logicalTopAfterUnsplittable == logicalTopAfterForcedBreak); |
+ |
+ LayoutUnit logicalTopAfterPagination = std::max(logicalTopWithContentStrut, std::max(logicalTopAfterForcedBreak, logicalTopAfterUnsplittable)); |
+ 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 && logicalTop == newLogicalTop && allowsPaginationStrut()) { |
+ if (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. |
@@ -716,11 +736,12 @@ LayoutUnit LayoutBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTop, |
if (childBlockFlow) |
childBlockFlow->setPaginationStrutPropagatedFromChild(LayoutUnit()); |
} else { |
+ child.setPaginationStrut(paginationStrut); |
newLogicalTop += paginationStrut; |
} |
} |
- if (!unsplittableAdjustmentDelta) { |
+ if (!neededBreakForUnsplittable) { |
if (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(newLogicalTop)) { |
LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(newLogicalTop, AssociateWithLatterPage); |
LayoutUnit spaceShortage = childLogicalHeight - remainingLogicalHeight; |
@@ -2409,24 +2430,19 @@ bool LayoutBlockFlow::positionNewFloats(LineWidth* width) |
childBox->layoutIfNeeded(); |
if (isPaginated) { |
- LayoutUnit newLogicalTop = floatLogicalLocation.y(); |
- |
- LayoutBlockFlow* childBlockFlow = childBox->isLayoutBlockFlow() ? toLayoutBlockFlow(childBox) : 0; |
- if (childBlockFlow && childBlockFlow->paginationStrutPropagatedFromChild()) { |
- // Some content inside this float has determined that we need to move to the next |
- // page or column. |
- newLogicalTop += childBlockFlow->paginationStrutPropagatedFromChild(); |
- } else { |
- // Now that we know the final height, check if we are unsplittable, and if we don't |
- // fit at the current position, but would fit at the top of the next page or |
- // column, move there. |
- newLogicalTop = adjustForUnsplittableChild(*childBox, newLogicalTop); |
+ LayoutBlockFlow* childBlockFlow = childBox->isLayoutBlockFlow() ? toLayoutBlockFlow(childBox) : nullptr; |
+ // The first piece of content inside the child may have set a strut during layout. |
+ LayoutUnit strut = childBlockFlow ? childBlockFlow->paginationStrutPropagatedFromChild() : LayoutUnit(); |
+ if (!strut) { |
+ // Otherwise, if we are unsplittable and don't fit, move to the next page or column |
+ // if that helps the situation. |
+ strut = adjustForUnsplittableChild(*childBox, floatLogicalLocation.y()) - floatLogicalLocation.y(); |
} |
- if (newLogicalTop != floatLogicalLocation.y()) { |
- floatingObject.setPaginationStrut(newLogicalTop - floatLogicalLocation.y()); |
- |
- floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop); |
+ floatingObject.setPaginationStrut(strut); |
+ childBox->setPaginationStrut(strut); |
+ if (strut) { |
+ floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, floatLogicalLocation.y() + strut); |
setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x()); |
setLogicalLeftForChild(*childBox, floatLogicalLocation.x() + childLogicalLeftMargin); |