Chromium Code Reviews| Index: Source/core/rendering/RenderMultiColumnSet.cpp |
| diff --git a/Source/core/rendering/RenderMultiColumnSet.cpp b/Source/core/rendering/RenderMultiColumnSet.cpp |
| index 9e7602d08e78160db94dffe4e6f1532e0207abae..30132af4f74f5eb535121f1fe4cb97544ee101d3 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->borderBefore() - multicolBlock->paddingBefore(); |
|
Julien - ping for review
2014/05/23 09:07:54
This can be shortened using borderAndPaddingBefore
mstensho (USE GERRIT)
2014/05/23 11:46:09
Done.
|
| + 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() |
|
Julien - ping for review
2014/05/23 09:07:54
Could you explain why we don't need this override
mstensho (USE GERRIT)
2014/05/23 11:46:09
A column set always has the same width as its cont
|
| +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"; |