Commit bbdbf9ff authored by mstensho@opera.com's avatar mstensho@opera.com

Avoid duplicated code in LayoutBlockChild::layoutBlockChild().

Before laying out, we try to estimate and set the logical top of the child, but
it may turn out after one layout pass that the estimate was wrong, due to
margin collapsing, float clearance or pagination.

So sometimes we need to reposition and relayout once or even twice inside
layoutBlockChild(). This was done with slightly poorly duplicated code.
Refactor into positionAndLayoutOnceIfNeeded() (and
markDescendantsWithFloatsForLayoutIfNeeded()). One instance of this duplicated
code used to sit in adjustBlockChildForPagination(). Moved it into
layoutBlockChild(), to make it easier to understand what's going on (and to
give adjustBlockChildForPagination() one less thing to worry about - one
parameter removed). Renamed |result| to |newLogicalTop| in
adjustBlockChildForPagination(), and |logicalTopAfterClear| to |newLogicalTop|
in layoutBlockChild().

No behavioral changes were actually intended, but when unifying
almost-duplicated code, some changes are inevitable. Added some tests for
something that now works, and used to fail. In the subsequent layout passes we
forgot to check if the new position changed how we were affected by floats.

R=jchaffraix@chromium.org,leviw@chromium.org

Review URL: https://codereview.chromium.org/1315353005

git-svn-id: svn://svn.chromium.org/blink/trunk@201866 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent c35dc14d
Given a float followed by a regular block with the same height as the float, then a block B with a negative margin, followed by a block with with overflow:hidden. Check that the overflow:hidden block doesn't overlap with the float, and also that it takes up all available space (but not more) beside the float. There's an empty collapse-through block before B, so that our initial logical top estimate fails and we have to relayout. When laying out again, we have to detect that the float that we first thought didn't affect the overflow:hidden block now affects it.
Below there should be an olive square to the left of a navy square. The navy square should be slightly larger than the olive one, and there should be spacing between them. They should not overlap.
PASS
<!DOCTYPE html>
<script src="../../../resources/check-layout.js"></script>
<style>
body { margin:8px; font-size:16px; }
</style>
<p>Given a float followed by a regular block with the same height as the float, then a block B with
a negative margin, followed by a block with with overflow:hidden. Check that the
overflow:hidden block doesn't overlap with the float, and also that it takes up all available
space (but not more) beside the float. There's an empty collapse-through block before B, so
that our initial logical top estimate fails and we have to relayout. When laying out again, we
have to detect that the float that we first thought didn't affect the overflow:hidden block now
affects it.</p>
<p>Below there should be an olive square to the left of a navy square. The navy square should be
slightly larger than the olive one, and there should be spacing between them. They should not
overlap.</p>
<div style="width:18em;">
<div>
<div style="float:left; width:8em; height:8em; margin-right:1em; background:olive;"></div>
<div style="height:8em;"></div>
<div>
<!-- Here's an empty block that we can just collapse through, but we don't realize that
when calculating our initial top estimate on its parent, so we have to relayout
when it turns out that a negative margin has pulled us upwards (and suddenly we
have something block-level that's affected by the float). -->
<div></div>
<div style="margin-top:-8em;"></div>
<!-- Here's a block-level element that is affected by floats, because it's a table. We
could have used e.g. an overflow:hidden DIV for the same effect. -->
<div id="bfc" style="overflow:hidden; height:9em; background:navy;" data-total-x="152" data-expected-width="144"></div>
</div>
</div>
</div>
<p id="result" style="clear:both;"></p>
<script>
checkLayout("#bfc", document.getElementById("result"));
</script>
Given a float followed by a regular block with the same height as the float, then a block B with a negative margin: Check that a line inside B doesn't overlap with the float. There's an empty collapse-through block before B, so that our initial logical top estimate fails and we have to relayout. When laying out again, we have to detect that the float that we first thought didn't affect the line now affects it.
The word "BINGO" should be seen below, to the right of a blue block.
BINGO
PASS
PASS
<!DOCTYPE html>
<style>
body { margin:8px; font-size:16px; }
</style>
<script src="../../../resources/check-layout.js"></script>
<p>Given a float followed by a regular block with the same height as the float, then a block B with
a negative margin: Check that a line inside B doesn't overlap with the float. There's an empty
collapse-through block before B, so that our initial logical top estimate fails and we have to
relayout. When laying out again, we have to detect that the float that we first thought didn't
affect the line now affects it.</p>
<p>The word "BINGO" should be seen below, to the right of a blue block.</p>
<div style="width:20em; color:blue;">
<div>
<div style="float:left; width:8em; height:8em; margin-right:1em; background:blue;"></div>
<div style="height:8em;"></div>
<div>
<!-- Here's an empty block that we can just collapse through, but we don't realize that
when calculating our initial top estimate on its parent, so we have to relayout
when it turns out that a negative margin has pulled us upwards (and suddenly we
have a line that's affected by the float). -->
<div></div>
<div class="testee" data-total-x="8" style="margin-top:-4em;">
<span class="testee" data-total-x="152">BINGO</span>
</div>
</div>
</div>
</div>
<p id="result" style="clear:both;"></p>
<script>
checkLayout(".testee", document.getElementById("result"));
</script>
Given a float followed by a regular block with the same height as the float, then a block B with a negative margin, followed by a table. Check that the table doesn't overlap with the float. There's an empty collapse-through block before B, so that our initial logical top estimate fails and we have to relayout. When laying out again, we have to detect that the float that we first thought didn't affect the table now affects it.
The word "BINGO" should be seen below, to the right of a blue block.
BINGO
PASS
<!DOCTYPE html>
<style>
body { margin:8px; font-size:16px; }
</style>
<script src="../../../resources/check-layout.js"></script>
<p>Given a float followed by a regular block with the same height as the float, then a block B with
a negative margin, followed by a table. Check that the table doesn't overlap with the
float. There's an empty collapse-through block before B, so that our initial logical top
estimate fails and we have to relayout. When laying out again, we have to detect that the float
that we first thought didn't affect the table now affects it.</p>
<p>The word "BINGO" should be seen below, to the right of a blue block.</p>
<div style="width:20em; color:blue;">
<div>
<div style="float:left; width:8em; height:8em; margin-right:1em; background:blue;"></div>
<div style="height:8em;"></div>
<div>
<!-- Here's an empty block that we can just collapse through, but we don't realize that
when calculating our initial top estimate on its parent, so we have to relayout
when it turns out that a negative margin has pulled us upwards (and suddenly we
have something block-level that's affected by the float). -->
<div></div>
<div style="margin-top:-4em;"></div>
<!-- Here's a block-level element that is affected by floats, because it's a table. We
could have used e.g. an overflow:hidden DIV for the same effect. -->
<div id="table" style="display:table;" data-total-x="152">BINGO</div>
</div>
</div>
</div>
<p id="result" style="clear:both;"></p>
<script>
checkLayout("#table", document.getElementById("result"));
</script>
...@@ -506,8 +506,66 @@ void LayoutBlockFlow::setLogicalTopForChild(LayoutBox& child, LayoutUnit logical ...@@ -506,8 +506,66 @@ void LayoutBlockFlow::setLogicalTopForChild(LayoutBox& child, LayoutUnit logical
} }
} }
void LayoutBlockFlow::markDescendantsWithFloatsForLayoutIfNeeded(LayoutBlockFlow& child, LayoutUnit newLogicalTop, LayoutUnit previousFloatLogicalBottom)
{
// TODO(mstensho): rework the code to return early when there is no need for marking, instead
// of this |markDescendantsWithFloats| flag.
bool markDescendantsWithFloats = false;
if (newLogicalTop != child.logicalTop() && !child.avoidsFloats() && child.containsFloats()) {
markDescendantsWithFloats = true;
} else if (UNLIKELY(newLogicalTop.mightBeSaturated())) {
// The logical top might be saturated for very large elements. Comparing with the old
// logical top might then yield a false negative, as adding and removing margins, borders
// etc. from a saturated number might yield incorrect results. If this is the case, always
// mark for layout.
markDescendantsWithFloats = true;
} else if (!child.avoidsFloats() || child.shrinkToAvoidFloats()) {
// If an element might be affected by the presence of floats, then always mark it for
// layout.
if (std::max(previousFloatLogicalBottom, lowestFloatLogicalBottom()) > newLogicalTop)
markDescendantsWithFloats = true;
}
if (markDescendantsWithFloats)
child.markAllDescendantsWithFloatsForLayout();
}
bool LayoutBlockFlow::positionAndLayoutOnceIfNeeded(LayoutBox& child, LayoutUnit newLogicalTop, LayoutUnit& previousFloatLogicalBottom)
{
if (child.isLayoutBlockFlow()) {
LayoutBlockFlow& childBlockFlow = toLayoutBlockFlow(child);
if (childBlockFlow.containsFloats() || containsFloats())
markDescendantsWithFloatsForLayoutIfNeeded(childBlockFlow, newLogicalTop, previousFloatLogicalBottom);
// TODO(mstensho): A writing mode root is one thing, but we should be able to skip anything
// that establishes a new block formatting context here. Their floats don't affect us.
if (!childBlockFlow.isWritingModeRoot())
previousFloatLogicalBottom = std::max(previousFloatLogicalBottom, childBlockFlow.logicalTop() + childBlockFlow.lowestFloatLogicalBottom());
}
LayoutUnit oldLogicalTop = logicalTopForChild(child);
setLogicalTopForChild(child, newLogicalTop);
SubtreeLayoutScope layoutScope(child);
if (!child.needsLayout()) {
if (newLogicalTop != oldLogicalTop && child.shrinkToAvoidFloats()) {
// The child's width is affected by adjacent floats. When the child shifts to clear an
// item, its width can change (because it has more available width).
layoutScope.setChildNeedsLayout(&child);
} else {
child.markForPaginationRelayoutIfNeeded(layoutScope);
}
}
if (!child.needsLayout())
return false;
child.layout();
return true;
}
void LayoutBlockFlow::layoutBlockChild(LayoutBox& child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom) void LayoutBlockFlow::layoutBlockChild(LayoutBox& child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom)
{ {
LayoutBlockFlow* childLayoutBlockFlow = child.isLayoutBlockFlow() ? toLayoutBlockFlow(&child) : nullptr;
LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore(); LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore(); LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
...@@ -522,43 +580,11 @@ void LayoutBlockFlow::layoutBlockChild(LayoutBox& child, MarginInfo& marginInfo, ...@@ -522,43 +580,11 @@ void LayoutBlockFlow::layoutBlockChild(LayoutBox& child, MarginInfo& marginInfo,
// Cache our old rect so that we can dirty the proper paint invalidation rects if the child moves. // Cache our old rect so that we can dirty the proper paint invalidation rects if the child moves.
LayoutRect oldRect = child.frameRect(); LayoutRect oldRect = child.frameRect();
LayoutUnit oldLogicalTop = logicalTopForChild(child);
// Go ahead and position the child as though it didn't collapse with the top.
setLogicalTopForChild(child, logicalTopEstimate);
LayoutBlockFlow* childLayoutBlockFlow = child.isLayoutBlockFlow() ? toLayoutBlockFlow(&child) : 0;
bool markDescendantsWithFloats = false;
if (logicalTopEstimate != oldLogicalTop && childLayoutBlockFlow && !childLayoutBlockFlow->avoidsFloats() && childLayoutBlockFlow->containsFloats()) {
markDescendantsWithFloats = true;
} else if (UNLIKELY(logicalTopEstimate.mightBeSaturated())) {
// logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
// very large elements. If it does the comparison with oldLogicalTop might yield a
// false negative as adding and removing margins, borders etc from a saturated number
// might yield incorrect results. If this is the case always mark for layout.
markDescendantsWithFloats = true;
} else if (!child.avoidsFloats() || child.shrinkToAvoidFloats()) {
// If an element might be affected by the presence of floats, then always mark it for
// layout.
LayoutUnit fb = std::max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
if (fb > logicalTopEstimate)
markDescendantsWithFloats = true;
}
if (childLayoutBlockFlow) {
if (markDescendantsWithFloats)
childLayoutBlockFlow->markAllDescendantsWithFloatsForLayout();
if (!child.isWritingModeRoot())
previousFloatLogicalBottom = std::max(previousFloatLogicalBottom, oldLogicalTop + childLayoutBlockFlow->lowestFloatLogicalBottom());
}
SubtreeLayoutScope layoutScope(child);
if (!child.needsLayout())
child.markForPaginationRelayoutIfNeeded(layoutScope);
bool childNeededLayout = child.needsLayout(); // Use the estimated block position and lay out the child if needed. After child layout, when
if (childNeededLayout) // we have enough information to perform proper margin collapsing, float clearing and
child.layout(); // pagination, we may have to reposition and lay out again if the estimate was wrong.
bool childNeededLayout = positionAndLayoutOnceIfNeeded(child, logicalTopEstimate, previousFloatLogicalBottom);
// Cache if we are at the top of the block right now. // Cache if we are at the top of the block right now.
bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock(); bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
...@@ -572,37 +598,28 @@ void LayoutBlockFlow::layoutBlockChild(LayoutBox& child, MarginInfo& marginInfo, ...@@ -572,37 +598,28 @@ void LayoutBlockFlow::layoutBlockChild(LayoutBox& child, MarginInfo& marginInfo,
// Now check for clear. // Now check for clear.
bool childDiscardMargin = childDiscardMarginBefore || childDiscardMarginAfter; bool childDiscardMargin = childDiscardMarginBefore || childDiscardMarginAfter;
LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear, childIsSelfCollapsing, childDiscardMargin); LayoutUnit newLogicalTop = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear, childIsSelfCollapsing, childDiscardMargin);
// Now check for pagination.
bool paginated = view()->layoutState()->isPaginated(); bool paginated = view()->layoutState()->isPaginated();
if (paginated) { if (paginated) {
logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child, if (estimateWithoutPagination != newLogicalTop) {
atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear); // 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).
setLogicalTopForChild(child, logicalTopAfterClear); positionAndLayoutOnceIfNeeded(child, newLogicalTop, previousFloatLogicalBottom);
// Now we have a final top position. See if it really does end up being different from our estimate.
// clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
// when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
if (logicalTopAfterClear != logicalTopEstimate || child.needsLayout() || (paginated && childLayoutBlockFlow && childLayoutBlockFlow->shouldBreakAtLineToAvoidWidow())) {
SubtreeLayoutScope layoutScope(child);
if (child.shrinkToAvoidFloats()) {
// The child's width depends on the line width.
// When the child shifts to clear an item, its width can
// change (because it has more available line width).
// So go ahead and mark the item as dirty.
layoutScope.setChildNeedsLayout(&child);
} }
if (childLayoutBlockFlow && !childLayoutBlockFlow->avoidsFloats() && childLayoutBlockFlow->containsFloats()) newLogicalTop = adjustBlockChildForPagination(newLogicalTop, child, atBeforeSideOfBlock && logicalTopBeforeClear == newLogicalTop);
childLayoutBlockFlow->markAllDescendantsWithFloatsForLayout(); }
if (!child.needsLayout())
child.markForPaginationRelayoutIfNeeded(layoutScope);
// Our guess was wrong. Make the child lay itself out again. // Clearance, margin collapsing or pagination may have given us a new logical top, in which
child.layoutIfNeeded(); // case we may have to reposition and possibly relayout as well. If we determined during child
// layout that we need to insert a break to honor widows, we also need to relayout.
if (newLogicalTop != logicalTopEstimate
|| child.needsLayout()
|| (paginated && childLayoutBlockFlow && childLayoutBlockFlow->shouldBreakAtLineToAvoidWidow())) {
positionAndLayoutOnceIfNeeded(child, newLogicalTop, previousFloatLogicalBottom);
} }
// If we previously encountered a self-collapsing sibling of this child that had clearance then // If we previously encountered a self-collapsing sibling of this child that had clearance then
...@@ -652,51 +669,22 @@ void LayoutBlockFlow::layoutBlockChild(LayoutBox& child, MarginInfo& marginInfo, ...@@ -652,51 +669,22 @@ void LayoutBlockFlow::layoutBlockChild(LayoutBox& child, MarginInfo& marginInfo,
} }
} }
LayoutUnit LayoutBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, LayoutBox& child, bool atBeforeSideOfBlock) LayoutUnit LayoutBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTop, LayoutBox& child, bool atBeforeSideOfBlock)
{ {
LayoutBlockFlow* childBlockFlow = child.isLayoutBlockFlow() ? toLayoutBlockFlow(&child) : 0; LayoutBlockFlow* childBlockFlow = child.isLayoutBlockFlow() ? toLayoutBlockFlow(&child) : 0;
if (estimateWithoutPagination != logicalTopAfterClear) {
// Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
// position.
setLogicalHeight(logicalTopAfterClear);
setLogicalTopForChild(child, logicalTopAfterClear);
if (child.shrinkToAvoidFloats()) {
// The child's width depends on the line width.
// When the child shifts to clear an item, its width can
// change (because it has more available line width).
// So go ahead and mark the item as dirty.
child.setChildNeedsLayout(MarkOnlyThis);
}
SubtreeLayoutScope layoutScope(child);
if (childBlockFlow) {
if (!childBlockFlow->avoidsFloats() && childBlockFlow->containsFloats())
childBlockFlow->markAllDescendantsWithFloatsForLayout();
if (!child.needsLayout())
child.markForPaginationRelayoutIfNeeded(layoutScope);
}
// Our guess was wrong. Make the child lay itself out again.
child.layoutIfNeeded();
}
LayoutUnit oldTop = logicalTopAfterClear;
// If the object has a page or column break value of "before", then we should shift to the top of the next page. // If the object has a page or column break value of "before", then we should shift to the top of the next page.
LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear); LayoutUnit newLogicalTop = 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. // 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 = result; LayoutUnit logicalTopBeforeUnsplittableAdjustment = newLogicalTop;
LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result); LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, newLogicalTop);
LayoutUnit paginationStrut = 0; LayoutUnit paginationStrut = 0;
LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment; LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
LayoutUnit childLogicalHeight = child.logicalHeight(); LayoutUnit childLogicalHeight = child.logicalHeight();
if (unsplittableAdjustmentDelta) { if (unsplittableAdjustmentDelta) {
setPageBreak(result, childLogicalHeight - unsplittableAdjustmentDelta); setPageBreak(newLogicalTop, childLogicalHeight - unsplittableAdjustmentDelta);
paginationStrut = unsplittableAdjustmentDelta; paginationStrut = unsplittableAdjustmentDelta;
} else if (childBlockFlow && childBlockFlow->paginationStrut()) { } else if (childBlockFlow && childBlockFlow->paginationStrut()) {
paginationStrut = childBlockFlow->paginationStrut(); paginationStrut = childBlockFlow->paginationStrut();
...@@ -705,21 +693,21 @@ LayoutUnit LayoutBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopA ...@@ -705,21 +693,21 @@ LayoutUnit LayoutBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopA
if (paginationStrut) { if (paginationStrut) {
// We are willing to propagate out to our parent block as long as we were at the top of the block prior // 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. // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) { if (atBeforeSideOfBlock && logicalTop == newLogicalTop && !isOutOfFlowPositioned() && !isTableCell()) {
// FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't // 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 // 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. // and pushes to the next page anyway, so not too concerned about it.
setPaginationStrut(result + paginationStrut); setPaginationStrut(logicalTop + paginationStrut);
if (childBlockFlow) if (childBlockFlow)
childBlockFlow->setPaginationStrut(0); childBlockFlow->setPaginationStrut(0);
} else { } else {
result += paginationStrut; newLogicalTop += paginationStrut;
} }
} }
if (!unsplittableAdjustmentDelta) { if (!unsplittableAdjustmentDelta) {
if (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(result)) { if (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(newLogicalTop)) {
LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, AssociateWithLatterPage); LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(newLogicalTop, AssociateWithLatterPage);
LayoutUnit spaceShortage = childLogicalHeight - remainingLogicalHeight; LayoutUnit spaceShortage = childLogicalHeight - remainingLogicalHeight;
if (spaceShortage > 0) { if (spaceShortage > 0) {
// If the child crosses a column boundary, report a break, in case nothing inside it // If the child crosses a column boundary, report a break, in case nothing inside it
...@@ -728,21 +716,21 @@ LayoutUnit LayoutBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopA ...@@ -728,21 +716,21 @@ LayoutUnit LayoutBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopA
// the balancer will have no clue. Only measure the space after the last column // the balancer will have no clue. Only measure the space after the last column
// boundary, in case it crosses more than one. // boundary, in case it crosses more than one.
LayoutUnit spaceShortageInLastColumn = intMod(spaceShortage, pageLogicalHeight); LayoutUnit spaceShortageInLastColumn = intMod(spaceShortage, pageLogicalHeight);
setPageBreak(result, spaceShortageInLastColumn ? spaceShortageInLastColumn : spaceShortage); setPageBreak(newLogicalTop, spaceShortageInLastColumn ? spaceShortageInLastColumn : spaceShortage);
} else if (remainingLogicalHeight == pageLogicalHeight && offsetFromLogicalTopOfFirstPage() + child.logicalTop()) { } else if (remainingLogicalHeight == pageLogicalHeight && offsetFromLogicalTopOfFirstPage() + child.logicalTop()) {
// We're at the very top of a page or column, and it's not the first one. This child // We're at the very top of a page or column, and it's not the first one. This child
// may turn out to be the smallest piece of content that causes a page break, so we // may turn out to be the smallest piece of content that causes a page break, so we
// need to report it. // need to report it.
setPageBreak(result, childLogicalHeight); setPageBreak(newLogicalTop, childLogicalHeight);
} }
} }
} }
// Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child. // Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child.
setLogicalHeight(logicalHeight() + (result - oldTop)); setLogicalHeight(logicalHeight() + (newLogicalTop - logicalTop));
// Return the final adjusted logical top. // Return the final adjusted logical top.
return result; return newLogicalTop;
} }
static inline LayoutUnit calculateMinimumPageHeight(const ComputedStyle& style, const RootInlineBox& lastLine) static inline LayoutUnit calculateMinimumPageHeight(const ComputedStyle& style, const RootInlineBox& lastLine)
......
...@@ -288,6 +288,8 @@ private: ...@@ -288,6 +288,8 @@ private:
bool layoutBlockFlow(bool relayoutChildren, LayoutUnit& pageLogicalHeight, SubtreeLayoutScope&); bool layoutBlockFlow(bool relayoutChildren, LayoutUnit& pageLogicalHeight, SubtreeLayoutScope&);
void layoutBlockChildren(bool relayoutChildren, SubtreeLayoutScope&, LayoutUnit beforeEdge, LayoutUnit afterEdge); void layoutBlockChildren(bool relayoutChildren, SubtreeLayoutScope&, LayoutUnit beforeEdge, LayoutUnit afterEdge);
void markDescendantsWithFloatsForLayoutIfNeeded(LayoutBlockFlow& child, LayoutUnit newLogicalTop, LayoutUnit previousFloatLogicalBottom);
bool positionAndLayoutOnceIfNeeded(LayoutBox& child, LayoutUnit newLogicalTop, LayoutUnit& previousFloatLogicalBottom);
void layoutBlockChild(LayoutBox& child, MarginInfo&, LayoutUnit& previousFloatLogicalBottom); void layoutBlockChild(LayoutBox& child, MarginInfo&, LayoutUnit& previousFloatLogicalBottom);
void adjustPositionedBlock(LayoutBox& child, const MarginInfo&); void adjustPositionedBlock(LayoutBox& child, const MarginInfo&);
void adjustFloatingBlock(const MarginInfo&); void adjustFloatingBlock(const MarginInfo&);
...@@ -487,7 +489,7 @@ private: ...@@ -487,7 +489,7 @@ private:
LayoutUnit applyBeforeBreak(LayoutBox& child, LayoutUnit logicalOffset); // If the child has a before break, then return a new yPos that shifts to the top of the next page/column. LayoutUnit applyBeforeBreak(LayoutBox& child, LayoutUnit logicalOffset); // If the child has a before break, then return a new yPos that shifts to the top of the next page/column.
LayoutUnit applyAfterBreak(LayoutBox& child, LayoutUnit logicalOffset, MarginInfo&); // If the child has an after break, then return a new offset that shifts to the top of the next page/column. LayoutUnit applyAfterBreak(LayoutBox& child, LayoutUnit logicalOffset, MarginInfo&); // If the child has an after break, then return a new offset that shifts to the top of the next page/column.
LayoutUnit adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, LayoutBox& child, bool atBeforeSideOfBlock); LayoutUnit adjustBlockChildForPagination(LayoutUnit logicalTop, LayoutBox& child, bool atBeforeSideOfBlock);
// Computes a deltaOffset value that put a line at the top of the next page if it doesn't fit on the current page. // Computes a deltaOffset value that put a line at the top of the next page if it doesn't fit on the current page.
void adjustLinePositionForPagination(RootInlineBox&, LayoutUnit& deltaOffset); void adjustLinePositionForPagination(RootInlineBox&, LayoutUnit& deltaOffset);
// If the child is unsplittable and can't fit on the current page, return the top of the next page/column. // If the child is unsplittable and can't fit on the current page, return the top of the next page/column.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment