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"; |