Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1304)

Unified Diff: Source/core/rendering/RenderMultiColumnSet.cpp

Issue 288263002: [New Multicolumn] Rebalance properly when child content changes. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: code review Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/rendering/RenderMultiColumnSet.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/rendering/RenderMultiColumnSet.cpp
diff --git a/Source/core/rendering/RenderMultiColumnSet.cpp b/Source/core/rendering/RenderMultiColumnSet.cpp
index 9e7602d08e78160db94dffe4e6f1532e0207abae..5ca3c9fa070622bb1cd8f3a0c337a43335d98f83 100644
--- a/Source/core/rendering/RenderMultiColumnSet.cpp
+++ b/Source/core/rendering/RenderMultiColumnSet.cpp
@@ -63,6 +63,15 @@ RenderMultiColumnSet* RenderMultiColumnSet::nextSiblingMultiColumnSet() const
return 0;
}
+RenderMultiColumnSet* RenderMultiColumnSet::previousSiblingMultiColumnSet() const
+{
+ for (RenderObject* sibling = previousSibling(); sibling; sibling = sibling->previousSibling()) {
+ if (sibling->isRenderMultiColumnSet())
+ return toRenderMultiColumnSet(sibling);
+ }
+ return 0;
+}
+
LayoutSize RenderMultiColumnSet::flowThreadTranslationAtOffset(LayoutUnit blockOffset) const
{
unsigned columnIndex = columnIndexAtOffset(blockOffset);
@@ -75,18 +84,26 @@ LayoutSize RenderMultiColumnSet::flowThreadTranslationAtOffset(LayoutUnit blockO
LayoutUnit RenderMultiColumnSet::heightAdjustedForSetOffset(LayoutUnit height) const
{
- RenderBlockFlow* multicolBlock = multiColumnBlockFlow();
- LayoutUnit contentLogicalTop = logicalTop() - multicolBlock->borderBefore() - multicolBlock->paddingBefore();
-
- height -= contentLogicalTop;
+ // Adjust for the top offset within the content box of the multicol container (containing
+ // block), unless this is the first set. We know that the top offset for the first set will be
+ // zero, but if the multicol container has non-zero top border or padding, the set's top offset
+ // (initially being 0 and relative to the border box) will be negative until it has been laid
+ // out. Had we used this bogus offset, we would calculate the wrong height, and risk performing
+ // a wasted layout iteration. Of course all other sets (if any) have this problem in the first
+ // layout pass too, but there's really nothing we can do there until the flow thread has been
+ // laid out anyway.
+ if (previousSiblingMultiColumnSet()) {
+ RenderBlockFlow* multicolBlock = multiColumnBlockFlow();
+ LayoutUnit contentLogicalTop = logicalTop() - multicolBlock->borderAndPaddingBefore();
+ height -= contentLogicalTop;
+ }
return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would probably cause an infinite amount of columns to be created.
}
LayoutUnit RenderMultiColumnSet::pageLogicalTopForOffset(LayoutUnit offset) const
{
- LayoutUnit portionLogicalTop = (isHorizontalWritingMode() ? flowThreadPortionRect().y() : flowThreadPortionRect().x());
unsigned columnIndex = columnIndexAtOffset(offset, AssumeNewColumns);
- return portionLogicalTop + columnIndex * computedColumnHeight();
+ return logicalTopInFlowThread() + columnIndex * computedColumnHeight();
}
void RenderMultiColumnSet::setAndConstrainColumnHeight(LayoutUnit newHeight)
@@ -142,13 +159,13 @@ void RenderMultiColumnSet::distributeImplicitBreaks()
}
}
-LayoutUnit RenderMultiColumnSet::calculateColumnHeight(bool initial) const
+LayoutUnit RenderMultiColumnSet::calculateColumnHeight(BalancedHeightCalculation calculationMode) const
{
- if (initial) {
- // Start with the lowest imaginable column height. We use the tallest content run (after
- // having "inserted" implicit breaks), and find its start offset (by looking at the previous
- // run's end offset, or, if there's no previous run, the set's start offset in the flow
- // thread).
+ if (calculationMode == GuessFromFlowThreadPortion) {
+ // Initial balancing. Start with the lowest imaginable column height. We use the tallest
+ // content run (after having "inserted" implicit breaks), and find its start offset (by
+ // looking at the previous run's end offset, or, if there's no previous run, the set's start
+ // offset in the flow thread).
unsigned index = findRunWithTallestColumns();
LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset() : logicalTopInFlowThread();
return std::max<LayoutUnit>(m_contentRuns[index].columnLogicalHeight(startOffset), m_minimumColumnHeight);
@@ -188,16 +205,16 @@ void RenderMultiColumnSet::addContentRun(LayoutUnit endOffsetFromFirstPage)
m_contentRuns.append(ContentRun(endOffsetFromFirstPage));
}
-bool RenderMultiColumnSet::recalculateColumnHeight(bool initial)
+bool RenderMultiColumnSet::recalculateColumnHeight(BalancedHeightCalculation calculationMode)
{
ASSERT(multiColumnFlowThread()->requiresBalancing());
LayoutUnit oldColumnHeight = m_computedColumnHeight;
- if (initial) {
+ if (calculationMode == GuessFromFlowThreadPortion) {
// Post-process the content runs and find out where the implicit breaks will occur.
distributeImplicitBreaks();
}
- LayoutUnit newColumnHeight = calculateColumnHeight(initial);
+ LayoutUnit newColumnHeight = calculateColumnHeight(calculationMode);
setAndConstrainColumnHeight(newColumnHeight);
// After having calculated an initial column height, the multicol container typically needs at
@@ -206,11 +223,15 @@ bool RenderMultiColumnSet::recalculateColumnHeight(bool initial)
// determined that the columns need to be as tall as the specified height of the container, we
// have already laid it out correctly, and there's no need for another pass.
+ // We can get rid of the content runs now, if we haven't already done so. They are only needed
+ // to calculate the initial balanced column height. In fact, we have to get rid of them before
+ // the next layout pass, since each pass will rebuild this.
+ m_contentRuns.clear();
+
if (m_computedColumnHeight == oldColumnHeight)
return false; // No change. We're done.
m_minSpaceShortage = RenderFlowThread::maxLogicalHeight();
- m_contentRuns.clear();
return true; // Need another pass.
}
@@ -226,63 +247,27 @@ void RenderMultiColumnSet::recordSpaceShortage(LayoutUnit spaceShortage)
m_minSpaceShortage = spaceShortage;
}
-void RenderMultiColumnSet::updateLogicalWidth()
+void RenderMultiColumnSet::resetColumnHeight()
{
- RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread();
- setComputedColumnWidthAndCount(flowThread->columnWidth(), flowThread->columnCount());
-
- // FIXME: When we add regions support, we'll start it off at the width of the multi-column
- // block in that particular region.
- setLogicalWidth(parentBox()->contentLogicalWidth());
-
- // If we overflow, increase our logical width.
- unsigned colCount = columnCount();
- LayoutUnit colGap = columnGap();
- LayoutUnit minimumContentLogicalWidth = colCount * computedColumnWidth() + (colCount - 1) * colGap;
- LayoutUnit currentContentLogicalWidth = contentLogicalWidth();
- LayoutUnit delta = max(LayoutUnit(), minimumContentLogicalWidth - currentContentLogicalWidth);
- if (!delta)
- return;
-
- // Increase our logical width by the delta.
- setLogicalWidth(logicalWidth() + delta);
-}
-
-void RenderMultiColumnSet::prepareForLayout()
-{
- RenderBlockFlow* multicolBlock = multiColumnBlockFlow();
- RenderStyle* multicolStyle = multicolBlock->style();
+ // Nuke previously stored minimum column height. Contents may have changed for all we know.
+ m_minimumColumnHeight = 0;
- // Set box logical top.
- ASSERT(!previousSiblingBox() || !previousSiblingBox()->isRenderMultiColumnSet()); // FIXME: multiple set not implemented; need to examine previous set to calculate the correct logical top.
- setLogicalTop(multicolBlock->borderBefore() + multicolBlock->paddingBefore());
+ m_maxColumnHeight = calculateMaxColumnHeight();
- // Set box width.
- updateLogicalWidth();
+ LayoutUnit oldColumnHeight = computedColumnHeight();
- if (multiColumnFlowThread()->requiresBalancing()) {
- // Set maximum column height. We will not stretch beyond this.
- m_maxColumnHeight = RenderFlowThread::maxLogicalHeight();
- if (!multicolStyle->logicalHeight().isAuto()) {
- m_maxColumnHeight = multicolBlock->computeContentLogicalHeight(multicolStyle->logicalHeight(), -1);
- if (m_maxColumnHeight == -1)
- m_maxColumnHeight = RenderFlowThread::maxLogicalHeight();
- }
- if (!multicolStyle->logicalMaxHeight().isUndefined()) {
- LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight(multicolStyle->logicalMaxHeight(), -1);
- if (logicalMaxHeight != -1 && m_maxColumnHeight > logicalMaxHeight)
- m_maxColumnHeight = logicalMaxHeight;
- }
- m_maxColumnHeight = heightAdjustedForSetOffset(m_maxColumnHeight);
- m_computedColumnHeight = 0; // Restart balancing.
- } else {
+ if (multiColumnFlowThread()->requiresBalancing())
+ m_computedColumnHeight = 0;
+ else
setAndConstrainColumnHeight(heightAdjustedForSetOffset(multiColumnFlowThread()->columnHeightAvailable()));
- }
- m_contentRuns.clear();
+ if (computedColumnHeight() != oldColumnHeight)
+ setChildNeedsLayout(MarkOnlyThis);
- // Nuke previously stored minimum column height. Contents may have changed for all we know.
- m_minimumColumnHeight = 0;
+ // Content runs are only needed in the initial layout pass, in order to find an initial column
+ // height, and should have been deleted afterwards. We're about to rebuild the content runs, so
+ // the list needs to be empty.
+ ASSERT(m_contentRuns.isEmpty());
}
void RenderMultiColumnSet::expandToEncompassFlowThreadContentsIfNeeded()
@@ -302,22 +287,26 @@ void RenderMultiColumnSet::expandToEncompassFlowThreadContentsIfNeeded()
setFlowThreadPortionRect(LayoutRect(rect.x(), rect.y(), isHorizontal ? rect.width() : logicalHeightWithOverflow, isHorizontal ? logicalHeightWithOverflow : rect.height()));
}
-void RenderMultiColumnSet::layout()
-{
- RenderRegion::layout();
-
- if (!nextSiblingMultiColumnSet()) {
- // This is the last set, i.e. the last region. Seize the opportunity to validate them.
- multiColumnFlowThread()->validateRegions();
- }
-}
-
void RenderMultiColumnSet::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
{
computedValues.m_extent = m_computedColumnHeight;
computedValues.m_position = logicalTop;
}
+LayoutUnit RenderMultiColumnSet::calculateMaxColumnHeight() const
+{
+ RenderBlockFlow* multicolBlock = multiColumnBlockFlow();
+ RenderStyle* multicolStyle = multicolBlock->style();
+ LayoutUnit availableHeight = multiColumnFlowThread()->columnHeightAvailable();
+ LayoutUnit maxColumnHeight = availableHeight ? availableHeight : RenderFlowThread::maxLogicalHeight();
+ if (!multicolStyle->logicalMaxHeight().isUndefined()) {
+ LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight(multicolStyle->logicalMaxHeight(), -1);
+ if (logicalMaxHeight != -1 && maxColumnHeight > logicalMaxHeight)
+ maxColumnHeight = logicalMaxHeight;
+ }
+ return heightAdjustedForSetOffset(maxColumnHeight);
+}
+
LayoutUnit RenderMultiColumnSet::columnGap() const
{
RenderBlockFlow* parentBlock = multiColumnBlockFlow();
@@ -631,6 +620,18 @@ void RenderMultiColumnSet::collectLayerFragments(LayerFragments& fragments, cons
}
}
+void RenderMultiColumnSet::addOverflowFromChildren()
+{
+ unsigned colCount = columnCount();
+ if (!colCount)
+ return;
+
+ LayoutRect lastRect = columnRectAt(colCount - 1);
+ addLayoutOverflow(lastRect);
+ if (!hasOverflowClip())
+ addVisualOverflow(lastRect);
+}
+
const char* RenderMultiColumnSet::renderName() const
{
return "RenderMultiColumnSet";
« no previous file with comments | « Source/core/rendering/RenderMultiColumnSet.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698