Region based multicol: support explicit column breaks

https://bugs.webkit.org/show_bug.cgi?id=123993

Patch by Morten Stenshorne <mstensho@opera.com> on 2014-01-20
Reviewed by David Hyatt.

Source/WebCore:

Merely supporting insertion of explicit (forced) column breaks in
the region based multicol implementation is really simple: just
hook up with what the CSS regions code is already doing.

However, there is one complication: column balancing. In order to
balance columns as nicely as possible when there are explicit
breaks, we need to figure out between which explicit breaks the
implicit breaks will occur (if there's room for any at all).

Tests: fast/multicol/newmulticol/break-after.html
       fast/multicol/newmulticol/break-before.html
       fast/multicol/newmulticol/breaks-2-columns-3-no-balancing.html
       fast/multicol/newmulticol/breaks-2-columns-3.html
       fast/multicol/newmulticol/breaks-3-columns-3.html
       fast/multicol/newmulticol/fixed-height-fill-balance-2.html

* rendering/RenderBlockFlow.cpp:
(WebCore::RenderBlockFlow::applyBeforeBreak):
(WebCore::RenderBlockFlow::applyAfterBreak): Use the already
existing region breaking code when inserting breaks in region
based multicol.
* rendering/RenderFlowThread.h:
* rendering/RenderMultiColumnBlock.cpp:
(WebCore::RenderMultiColumnBlock::RenderMultiColumnBlock):
(WebCore::RenderMultiColumnBlock::relayoutForPagination): Avoid
re-balancing if the multicol's contents were not laid out. Apart
from being good for performance, this is now necessary because of
how explicit breaks are implemented.
(WebCore::RenderMultiColumnBlock::layoutSpecialExcludedChild):
Detect if the contents are going to be laid out, or skipped, so
that we can tell if we need to (re-)balance the columns
afterwards.
* rendering/RenderMultiColumnBlock.h:
* rendering/RenderMultiColumnFlowThread.cpp:
(WebCore::RenderMultiColumnFlowThread::addForcedRegionBreak):
Locate the appropriate multi-column set and call its
addForcedBreak().
* rendering/RenderMultiColumnFlowThread.h:
* rendering/RenderMultiColumnSet.cpp:
(WebCore::RenderMultiColumnSet::RenderMultiColumnSet):
(WebCore::RenderMultiColumnSet::findRunWithTallestColumns):
(WebCore::RenderMultiColumnSet::distributeImplicitBreaks): Figure
out how many implicit breaks each single "content run" should
contain. The taller the content run, the more implicit breaks.
(WebCore::RenderMultiColumnSet::calculateBalancedHeight): This is
now a const method that only does half of what the old
calculateBalancedHeight() did. The rest (such as actually storing
the new column height) is done by recalculateBalancedHeight().
(WebCore::RenderMultiColumnSet::clearForcedBreaks): Needs to be
called between each layout pass, to clear the list of "content
runs".
(WebCore::RenderMultiColumnSet::addForcedBreak): Only useful when
columns are to be balanced. It receives explicit (forced) breaks
and stores them as "content runs". When layout is done, we'll go
through the list of content runs, and see where implicit breaks
should be inserted (if there's room for any). The goal is to
insert implicit breaks in such a way that the final columns become
as short as possible.
(WebCore::RenderMultiColumnSet::recalculateBalancedHeight):
Calculates and sets a new balanced column height. This used to be
done directly in calculateBalancedHeight(), but that method is now
const and it now only calculates the new height and returns it.
(WebCore::RenderMultiColumnSet::prepareForLayout):
* rendering/RenderMultiColumnSet.h: Remove old data members
intended for forced breaks (they were unused), and introduce a
"content run" vector instead. A new content run is triggered by an
explicit break. This is only used when column balancing is
enabled. When not balanced, RenderMultiColumnSet doesn't need to
do anything when explicit breaks are inserted.

LayoutTests:

* fast/multicol/newmulticol/break-after-expected.html: Added.
* fast/multicol/newmulticol/break-after.html: Added.
* fast/multicol/newmulticol/break-before-expected.html: Added.
* fast/multicol/newmulticol/break-before.html: Added.
* fast/multicol/newmulticol/breaks-2-columns-3-expected.html: Added.
* fast/multicol/newmulticol/breaks-2-columns-3-no-balancing-expected.html: Added.
* fast/multicol/newmulticol/breaks-2-columns-3-no-balancing.html: Added.
* fast/multicol/newmulticol/breaks-2-columns-3.html: Added.
* fast/multicol/newmulticol/breaks-3-columns-3-expected.html: Added.
* fast/multicol/newmulticol/breaks-3-columns-3.html: Added.
* fast/multicol/newmulticol/fixed-height-fill-balance-2-expected.html: Added.
* fast/multicol/newmulticol/fixed-height-fill-balance-2.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@162366 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 3303c76d
2014-01-20 Morten Stenshorne <mstensho@opera.com>
Region based multicol: support explicit column breaks
https://bugs.webkit.org/show_bug.cgi?id=123993
Reviewed by David Hyatt.
* fast/multicol/newmulticol/break-after-expected.html: Added.
* fast/multicol/newmulticol/break-after.html: Added.
* fast/multicol/newmulticol/break-before-expected.html: Added.
* fast/multicol/newmulticol/break-before.html: Added.
* fast/multicol/newmulticol/breaks-2-columns-3-expected.html: Added.
* fast/multicol/newmulticol/breaks-2-columns-3-no-balancing-expected.html: Added.
* fast/multicol/newmulticol/breaks-2-columns-3-no-balancing.html: Added.
* fast/multicol/newmulticol/breaks-2-columns-3.html: Added.
* fast/multicol/newmulticol/breaks-3-columns-3-expected.html: Added.
* fast/multicol/newmulticol/breaks-3-columns-3.html: Added.
* fast/multicol/newmulticol/fixed-height-fill-balance-2-expected.html: Added.
* fast/multicol/newmulticol/fixed-height-fill-balance-2.html: Added.
2014-01-20 Eric Carlson <eric.carlson@apple.com>
Allow MediaSessionManager to restrict 'preload' behavior
<!DOCTYPE html>
<html>
<head>
<title>auto-height multicol with break</title>
<script>
if (window.internals)
internals.settings.setRegionBasedColumnsEnabled(true);
</script>
<style>
.mc > div { padding:0 0.5em; }
</style>
</head>
<body style="min-width:40em;">
<div class="mc" style="-webkit-columns:3; -webkit-column-gap:1em; columns:3; column-gap:1em; orphans:1; widows:1; width:32em; background:olive;">
<div>
first column<br>
first column<br>
first column<br>
first column<br>
second column<br>
second column<br>
second column<br>
</div>
<div style="-webkit-column-break-before:always; break-before:column;">
third column<br>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>auto-height multicol with break</title>
<script>
if (window.internals)
internals.settings.setRegionBasedColumnsEnabled(true);
</script>
<style>
.mc > div { padding:0 0.5em; }
</style>
</head>
<body style="min-width:40em;">
<div class="mc" style="-webkit-columns:3; -webkit-column-gap:1em; columns:3; column-gap:1em; orphans:1; widows:1; width:32em; background:olive;">
<div style="-webkit-column-break-after:always; break-after:column;">
first column<br>
first column<br>
first column<br>
first column<br>
second column<br>
second column<br>
second column<br>
</div>
<div>
third column<br>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>auto-height multicol with break</title>
<style>
.mc { float:left; width:9em; padding:0 0.5em; }
.gap { float:left; width:1em; }
</style>
</head>
<body style="min-width:40em;">
<div style="float:left; background:olive;">
<div class="mc">
first column<br>
first column<br>
first column<br>
first column<br>
</div>
<div class="gap">&nbsp;</div>
<div class="mc">
second column<br>
second column<br>
second column<br>
</div>
<div class="gap">&nbsp;</div>
<div class="mc">
third column<br>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>auto-height multicol with break</title>
<script>
if (window.internals)
internals.settings.setRegionBasedColumnsEnabled(true);
</script>
<style>
.mc > div { padding:0 0.5em; }
</style>
</head>
<body style="min-width:40em;">
<div class="mc" style="-webkit-columns:3; -webkit-column-gap:1em; columns:3; column-gap:1em; orphans:1; widows:1; width:32em; background:olive;">
<div>
first column<br>
first column<br>
first column<br>
first column<br>
second column<br>
second column<br>
second column<br>
</div>
<div style="-webkit-column-break-before:always; break-before:column;">
third column<br>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>auto-height multicol with break</title>
<style>
.mc { float:left; width:9em; padding:0 0.5em; }
.gap { float:left; width:1em; }
</style>
</head>
<body style="min-width:40em;">
<div style="float:left; background:olive;">
<div class="mc">
first column<br>
</div>
<div class="gap">&nbsp;</div>
<div class="mc">
second column<br>
second column<br>
second column<br>
second column<br>
second column<br>
second column<br>
</div>
<div class="gap">&nbsp;</div>
<div class="mc">
third column<br>
third column<br>
third column<br>
third column<br>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>multicol with break</title>
<style>
.mc { float:left; width:7em; padding:0 0.5em; }
</style>
</head>
<body style="min-width:40em; line-height:2em;">
<div style="float:left; height:10em; background:olive;">
<div class="mc">
first column<br>
first column<br>
first column<br>
first column<br>
first column<br>
</div>
<div class="mc">
second column<br>
</div>
<div class="mc">
third column<br>
</div>
</div>
<div class="mc">
fourth column<br>
fourth column<br>
fourth column<br>
fourth column<br>
fourth column<br>
</div>
<div class="mc">
fifth column<br>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>multicol with break</title>
<script>
if (window.internals)
internals.settings.setRegionBasedColumnsEnabled(true);
</script>
<style>
.mc > div { padding:0 0.5em; }
</style>
</head>
<body style="min-width:40em;">
<div class="mc" style="-webkit-columns:3; -webkit-column-gap:0; -webkit-column-fill:auto; columns:3; column-gap:0; column-fill:auto; orphans:1; widows:1; width:24em; height:10em; line-height:2em; background:olive;">
<div style="-webkit-column-break-after:always; break-after:column;">
first column<br>
first column<br>
first column<br>
first column<br>
first column<br>
second column<br>
</div>
<div style="-webkit-column-break-after:always; break-after:column;">
third column<br>
</div>
<div>
fourth column<br>
fourth column<br>
fourth column<br>
fourth column<br>
fourth column<br>
fifth column<br>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>auto-height multicol with break</title>
<script>
if (window.internals)
internals.settings.setRegionBasedColumnsEnabled(true);
</script>
<style>
.mc > div { padding:0 0.5em; }
</style>
</head>
<body style="min-width:40em;">
<div class="mc" style="-webkit-columns:3; -webkit-column-gap:1em; columns:3; column-gap:1em; orphans:1; widows:1; width:32em; background:olive;">
<div style="-webkit-column-break-after:always; break-after:column;">
first column<br>
</div>
<div style="-webkit-column-break-after:always; break-after:column;">
second column<br>
second column<br>
second column<br>
second column<br>
second column<br>
second column<br>
</div>
<div>
third column<br>
third column<br>
third column<br>
third column<br>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>auto-height multicol with break</title>
<style>
.mc { float:left; width:6em; padding:0 0.5em; }
.gap { float:left; width:1em; }
</style>
</head>
<body style="min-width:40em;">
<div style="float:left; background:olive;">
<div class="mc">
first column<br>
</div>
<div class="gap">&nbsp;</div>
<div class="mc">
second column<br>
second column<br>
second column<br>
second column<br>
second column<br>
second column<br>
</div>
<div class="gap">&nbsp;</div>
<div class="mc">
third column<br>
third column<br>
third column<br>
third column<br>
</div>
</div>
<div class="gap">&nbsp;</div>
<div class="mc">
fourth column<br>
fourth column<br>
fourth column<br>
fourth column<br>
fourth column<br>
fourth column<br>
</div>
<div class="gap">&nbsp;</div>
<div class="mc">
fifth column<br>
fifth column<br>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>auto-height multicol with break</title>
<script>
if (window.internals)
internals.settings.setRegionBasedColumnsEnabled(true);
</script>
<style>
.mc > div { padding:0 0.5em; }
</style>
</head>
<body style="min-width:40em;">
<div class="mc" style="-webkit-columns:3; -webkit-column-gap:1em; columns:3; column-gap:1em; orphans:1; widows:1; width:23em; background:olive;">
<div style="-webkit-column-break-after:always; break-after:column;">
first column<br>
</div>
<div style="-webkit-column-break-after:always; break-after:column;">
second column<br>
second column<br>
second column<br>
second column<br>
second column<br>
second column<br>
</div>
<div style="-webkit-column-break-after:always; break-after:column;">
third column<br>
third column<br>
third column<br>
third column<br>
</div>
<div>
fourth column<br>
fourth column<br>
fourth column<br>
fourth column<br>
fourth column<br>
fourth column<br>
fifth column<br>
fifth column<br>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>balancing fixed-height multicol</title>
</head>
<body style="overflow:hidden;">
<p>There should be three identical blue rectangles below.</p>
<div style="width:20em;">
<div style="float:left; width:6em; height:2em; background:blue;"></div>
<div style="float:left; width:1em; height:2em;"></div>
<div style="float:left; width:6em; height:2em; background:blue;"></div>
<div style="float:left; width:1em; height:2em;"></div>
<div style="float:left; width:6em; height:2em; background:blue;"></div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>balancing fixed-height multicol</title>
<script>
if (window.internals)
internals.settings.setRegionBasedColumnsEnabled(true);
</script>
</head>
<body style="overflow:hidden;">
<p>There should be three identical blue rectangles below.</p>
<div style="-webkit-columns:3; -webkit-column-gap:1em; columns:3; column-gap:1em; line-height:2em; height:3.9em; width:20em;">
<div style="background:blue;"><br><br><br></div>
</div>
</body>
</html>
2014-01-20 Morten Stenshorne <mstensho@opera.com>
Region based multicol: support explicit column breaks
https://bugs.webkit.org/show_bug.cgi?id=123993
Reviewed by David Hyatt.
Merely supporting insertion of explicit (forced) column breaks in
the region based multicol implementation is really simple: just
hook up with what the CSS regions code is already doing.
However, there is one complication: column balancing. In order to
balance columns as nicely as possible when there are explicit
breaks, we need to figure out between which explicit breaks the
implicit breaks will occur (if there's room for any at all).
Tests: fast/multicol/newmulticol/break-after.html
fast/multicol/newmulticol/break-before.html
fast/multicol/newmulticol/breaks-2-columns-3-no-balancing.html
fast/multicol/newmulticol/breaks-2-columns-3.html
fast/multicol/newmulticol/breaks-3-columns-3.html
fast/multicol/newmulticol/fixed-height-fill-balance-2.html
* rendering/RenderBlockFlow.cpp:
(WebCore::RenderBlockFlow::applyBeforeBreak):
(WebCore::RenderBlockFlow::applyAfterBreak): Use the already
existing region breaking code when inserting breaks in region
based multicol.
* rendering/RenderFlowThread.h:
* rendering/RenderMultiColumnBlock.cpp:
(WebCore::RenderMultiColumnBlock::RenderMultiColumnBlock):
(WebCore::RenderMultiColumnBlock::relayoutForPagination): Avoid
re-balancing if the multicol's contents were not laid out. Apart
from being good for performance, this is now necessary because of
how explicit breaks are implemented.
(WebCore::RenderMultiColumnBlock::layoutSpecialExcludedChild):
Detect if the contents are going to be laid out, or skipped, so
that we can tell if we need to (re-)balance the columns
afterwards.
* rendering/RenderMultiColumnBlock.h:
* rendering/RenderMultiColumnFlowThread.cpp:
(WebCore::RenderMultiColumnFlowThread::addForcedRegionBreak):
Locate the appropriate multi-column set and call its
addForcedBreak().
* rendering/RenderMultiColumnFlowThread.h:
* rendering/RenderMultiColumnSet.cpp:
(WebCore::RenderMultiColumnSet::RenderMultiColumnSet):
(WebCore::RenderMultiColumnSet::findRunWithTallestColumns):
(WebCore::RenderMultiColumnSet::distributeImplicitBreaks): Figure
out how many implicit breaks each single "content run" should
contain. The taller the content run, the more implicit breaks.
(WebCore::RenderMultiColumnSet::calculateBalancedHeight): This is
now a const method that only does half of what the old
calculateBalancedHeight() did. The rest (such as actually storing
the new column height) is done by recalculateBalancedHeight().
(WebCore::RenderMultiColumnSet::clearForcedBreaks): Needs to be
called between each layout pass, to clear the list of "content
runs".
(WebCore::RenderMultiColumnSet::addForcedBreak): Only useful when
columns are to be balanced. It receives explicit (forced) breaks
and stores them as "content runs". When layout is done, we'll go
through the list of content runs, and see where implicit breaks
should be inserted (if there's room for any). The goal is to
insert implicit breaks in such a way that the final columns become
as short as possible.
(WebCore::RenderMultiColumnSet::recalculateBalancedHeight):
Calculates and sets a new balanced column height. This used to be
done directly in calculateBalancedHeight(), but that method is now
const and it now only calculates the new height and returns it.
(WebCore::RenderMultiColumnSet::prepareForLayout):
* rendering/RenderMultiColumnSet.h: Remove old data members
intended for forced breaks (they were unused), and introduce a
"content run" vector instead. A new content run is triggered by an
explicit break. This is only used when column balancing is
enabled. When not balanced, RenderMultiColumnSet doesn't need to
do anything when explicit breaks are inserted.
2014-01-20 Eric Carlson <eric.carlson@apple.com>
Allow MediaSessionManager to restrict 'preload' behavior
......@@ -1348,15 +1348,21 @@ static bool inNormalFlow(RenderBox& child)
LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox& child, LayoutUnit logicalOffset)
{
// FIXME: Add page break checking here when we support printing.
bool checkColumnBreaks = view().layoutState()->isPaginatingColumns();
bool checkPageBreaks = !checkColumnBreaks && view().layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
RenderFlowThread* flowThread = flowThreadContainingBlock();
bool isInsideMulticolFlowThread = flowThread && !flowThread->isRenderNamedFlowThread();
bool checkColumnBreaks = isInsideMulticolFlowThread || view().layoutState()->isPaginatingColumns();
bool checkPageBreaks = !checkColumnBreaks && view().layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
bool checkBeforeAlways = (checkColumnBreaks && child.style().columnBreakBefore() == PBALWAYS) || (checkPageBreaks && child.style().pageBreakBefore() == PBALWAYS)
bool checkBeforeAlways = (checkColumnBreaks && child.style().columnBreakBefore() == PBALWAYS)
|| (checkPageBreaks && child.style().pageBreakBefore() == PBALWAYS)
|| (checkRegionBreaks && child.style().regionBreakBefore() == PBALWAYS);
if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
if (checkColumnBreaks)
view().layoutState()->addForcedColumnBreak(&child, logicalOffset);
if (checkColumnBreaks) {
if (isInsideMulticolFlowThread)
checkRegionBreaks = true;
else
view().layoutState()->addForcedColumnBreak(&child, logicalOffset);
}
if (checkRegionBreaks) {
LayoutUnit offsetBreakAdjustment = 0;
if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset, &child, true, &offsetBreakAdjustment))
......@@ -1370,11 +1376,13 @@ LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox& child, LayoutUnit logica
LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox& child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
{
// FIXME: Add page break checking here when we support printing.
bool checkColumnBreaks = view().layoutState()->isPaginatingColumns();
bool checkPageBreaks = !checkColumnBreaks && view().layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
RenderFlowThread* flowThread = flowThreadContainingBlock();
bool isInsideMulticolFlowThread = flowThread && !flowThread->isRenderNamedFlowThread();
bool checkColumnBreaks = isInsideMulticolFlowThread || view().layoutState()->isPaginatingColumns();
bool checkPageBreaks = !checkColumnBreaks && view().layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
bool checkAfterAlways = (checkColumnBreaks && child.style().columnBreakAfter() == PBALWAYS) || (checkPageBreaks && child.style().pageBreakAfter() == PBALWAYS)
bool checkAfterAlways = (checkColumnBreaks && child.style().columnBreakAfter() == PBALWAYS)
|| (checkPageBreaks && child.style().pageBreakAfter() == PBALWAYS)
|| (checkRegionBreaks && child.style().regionBreakAfter() == PBALWAYS);
if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
......@@ -1382,8 +1390,12 @@ LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox& child, LayoutUnit logical
// So our margin doesn't participate in the next collapsing steps.
marginInfo.clearMargin();
if (checkColumnBreaks)
view().layoutState()->addForcedColumnBreak(&child, logicalOffset);
if (checkColumnBreaks) {
if (isInsideMulticolFlowThread)
checkRegionBreaks = true;
else
view().layoutState()->addForcedColumnBreak(&child, logicalOffset);
}
if (checkRegionBreaks) {
LayoutUnit offsetBreakAdjustment = 0;
if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, &child, false, &offsetBreakAdjustment))
......
......@@ -145,7 +145,7 @@ public:
void markAutoLogicalHeightRegionsForLayout();
void markRegionsForOverflowLayoutIfNeeded();
bool addForcedRegionBreak(const RenderBlock*, LayoutUnit, RenderBox* breakChild, bool isBefore, LayoutUnit* offsetBreakAdjustment = 0);
virtual bool addForcedRegionBreak(const RenderBlock*, LayoutUnit, RenderBox* breakChild, bool isBefore, LayoutUnit* offsetBreakAdjustment = 0);
void applyBreakAfterContent(LayoutUnit);
bool pageLogicalSizeChanged() const { return m_pageLogicalSizeChanged; }
......
......@@ -40,6 +40,7 @@ RenderMultiColumnBlock::RenderMultiColumnBlock(Element& element, PassRef<RenderS
, m_columnWidth(0)
, m_columnHeightAvailable(0)
, m_inBalancingPass(false)
, m_needsRebalancing(false)
{
}
......@@ -96,8 +97,9 @@ void RenderMultiColumnBlock::checkForPaginationLogicalHeightChange(LayoutUnit& /
bool RenderMultiColumnBlock::relayoutForPagination(bool, LayoutUnit, LayoutStateMaintainer& statePusher)
{
if (m_inBalancingPass || !requiresBalancing())
if (m_inBalancingPass || !m_needsRebalancing)
return false;
m_needsRebalancing = false;
m_inBalancingPass = true; // Prevent re-entering this method (and recursion into layout).
bool needsRelayout;
......@@ -113,7 +115,7 @@ bool RenderMultiColumnBlock::relayoutForPagination(bool, LayoutUnit, LayoutState
for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox())
if (childBox != m_flowThread && childBox->isRenderMultiColumnSet()) {
RenderMultiColumnSet* multicolSet = toRenderMultiColumnSet(childBox);
if (multicolSet->calculateBalancedHeight(firstPass)) {
if (multicolSet->recalculateBalancedHeight(firstPass)) {
multicolSet->setChildNeedsLayout(MarkOnlyThis);
needsRelayout = true;
}
......@@ -170,6 +172,18 @@ RenderObject* RenderMultiColumnBlock::layoutSpecialExcludedChild(bool relayoutCh
if (relayoutChildren)
m_flowThread->setChildNeedsLayout(MarkOnlyThis);
if (requiresBalancing()) {
// At the end of multicol layout, relayoutForPagination() is called unconditionally, but if
// no children are to be laid out (e.g. fixed width with layout already being up-to-date),
// we want to prevent it from doing any work, so that the column balancing machinery doesn't
// kick in and trigger additional unnecessary layout passes. Actually, it's not just a good
// idea in general to not waste time on balancing content that hasn't been re-laid out; we
// are actually required to guarantee this. The calculation of implicit breaks needs to be
// preceded by a proper layout pass, since it's layout that sets up content runs, and the
// runs get deleted right after every pass.
m_needsRebalancing = shouldInvalidateRegions || m_flowThread->needsLayout();
}
setLogicalTopForChild(*m_flowThread, borderAndPaddingBefore());
m_flowThread->layoutIfNeeded();
determineLogicalLeftPositionForChild(*m_flowThread);
......
......@@ -71,6 +71,7 @@ private:
// These values will be cached (eventually) for multi-column blocks.
LayoutUnit m_columnHeightAvailable; // Total height available to columns, or 0 if auto.
bool m_inBalancingPass; // Set when relayouting for column balancing.
bool m_needsRebalancing;
};
RENDER_OBJECT_TYPE_CASTS(RenderMultiColumnBlock, isRenderMultiColumnBlock())
......
......@@ -110,4 +110,15 @@ void RenderMultiColumnFlowThread::updateMinimumPageHeight(const RenderBlock* blo
multicolSet->updateMinimumColumnHeight(minHeight);
}
bool RenderMultiColumnFlowThread::addForcedRegionBreak(const RenderBlock* block, LayoutUnit offset, RenderBox* /*breakChild*/, bool /*isBefore*/, LayoutUnit* offsetBreakAdjustment)
{
if (RenderMultiColumnSet* multicolSet = toRenderMultiColumnSet(regionAtBlockOffset(block, offset))) {
multicolSet->addForcedBreak(offset);
if (offsetBreakAdjustment)
*offsetBreakAdjustment = pageLogicalHeightForOffset(offset) ? pageRemainingLogicalHeightForOffset(offset, IncludePageBoundary) : LayoutUnit(0);
return true;
}
return false;
}
}
......@@ -43,6 +43,7 @@ private:
virtual LayoutUnit initialLogicalWidth() const override;
virtual void setPageBreak(const RenderBlock*, LayoutUnit offset, LayoutUnit spaceShortage) override;
virtual void updateMinimumPageHeight(const RenderBlock*, LayoutUnit offset, LayoutUnit minHeight) override;
virtual bool addForcedRegionBreak(const RenderBlock*, LayoutUnit, RenderBox* breakChild, bool isBefore, LayoutUnit* offsetBreakAdjustment = 0) override;
};
} // namespace WebCore
......
......@@ -41,9 +41,6 @@ RenderMultiColumnSet::RenderMultiColumnSet(RenderFlowThread& flowThread, PassRef
, m_maxColumnHeight(LayoutUnit::max())