| Index: Source/core/rendering/RenderMultiColumnFlowThread.cpp
|
| diff --git a/Source/core/rendering/RenderMultiColumnFlowThread.cpp b/Source/core/rendering/RenderMultiColumnFlowThread.cpp
|
| index 6eaed6f174181af1b3308840f9bf3bb3b990256a..1a847a502deb6d974b9eb5f0053e3af95dbacf48 100644
|
| --- a/Source/core/rendering/RenderMultiColumnFlowThread.cpp
|
| +++ b/Source/core/rendering/RenderMultiColumnFlowThread.cpp
|
| @@ -32,11 +32,13 @@
|
| namespace blink {
|
|
|
| RenderMultiColumnFlowThread::RenderMultiColumnFlowThread()
|
| - : m_columnCount(1)
|
| + : m_lastSetWorkedOn(0)
|
| + , m_columnCount(1)
|
| , m_columnHeightAvailable(0)
|
| , m_inBalancingPass(false)
|
| , m_needsColumnHeightsRecalculation(false)
|
| , m_progressionIsInline(true)
|
| + , m_isBeingEvacuated(false)
|
| {
|
| setFlowThreadState(InsideInFlowThread);
|
| }
|
| @@ -102,6 +104,7 @@ void RenderMultiColumnFlowThread::populate()
|
| void RenderMultiColumnFlowThread::evacuateAndDestroy()
|
| {
|
| RenderBlockFlow* multicolContainer = multiColumnBlockFlow();
|
| + m_isBeingEvacuated = true;
|
|
|
| // Remove all sets.
|
| while (RenderMultiColumnSet* columnSet = firstMultiColumnSet())
|
| @@ -146,11 +149,33 @@ bool RenderMultiColumnFlowThread::needsNewWidth() const
|
| return newWidth != logicalWidth();
|
| }
|
|
|
| +RenderMultiColumnSet* RenderMultiColumnFlowThread::columnSetAtBlockOffset(LayoutUnit offset) const
|
| +{
|
| + if (m_lastSetWorkedOn) {
|
| + // Layout in progress. We are calculating the set heights as we speak, so the column set range
|
| + // information is not up-to-date.
|
| + return m_lastSetWorkedOn;
|
| + }
|
| +
|
| + ASSERT(!m_regionsInvalidated);
|
| + if (offset <= 0)
|
| + return m_multiColumnSetList.isEmpty() ? 0 : m_multiColumnSetList.first();
|
| +
|
| + MultiColumnSetSearchAdapter adapter(offset);
|
| + m_multiColumnSetIntervalTree.allOverlapsWithAdapter<MultiColumnSetSearchAdapter>(adapter);
|
| +
|
| + // If no set was found, the offset is in the flow thread overflow.
|
| + if (!adapter.result() && !m_multiColumnSetList.isEmpty())
|
| + return m_multiColumnSetList.last();
|
| + return adapter.result();
|
| +}
|
| +
|
| void RenderMultiColumnFlowThread::layoutColumns(bool relayoutChildren, SubtreeLayoutScope& layoutScope)
|
| {
|
| if (relayoutChildren)
|
| layoutScope.setChildNeedsLayout(this);
|
|
|
| + m_needsColumnHeightsRecalculation = false;
|
| if (!needsLayout()) {
|
| // Just before the multicol container (our parent RenderBlockFlow) finishes laying out, it
|
| // will call recalculateColumnHeights() on us unconditionally, but we only want that method
|
| @@ -158,7 +183,6 @@ void RenderMultiColumnFlowThread::layoutColumns(bool relayoutChildren, SubtreeLa
|
| // machinery would kick in needlessly, and trigger additional layout passes. Furthermore, we
|
| // actually depend on a proper flowthread layout pass in order to do balancing, since it's
|
| // flowthread layout that sets up content runs.
|
| - m_needsColumnHeightsRecalculation = false;
|
| return;
|
| }
|
|
|
| @@ -168,10 +192,11 @@ void RenderMultiColumnFlowThread::layoutColumns(bool relayoutChildren, SubtreeLa
|
| // typically have changed.
|
| columnSet->resetColumnHeight();
|
| }
|
| + if (!m_needsColumnHeightsRecalculation)
|
| + m_needsColumnHeightsRecalculation = columnSet->isRenderMultiColumnSpannerSet() || columnSet->heightIsAuto();
|
| }
|
|
|
| invalidateRegions();
|
| - m_needsColumnHeightsRecalculation = heightIsAuto();
|
| layout();
|
| }
|
|
|
| @@ -316,8 +341,71 @@ void RenderMultiColumnFlowThread::willBeRemovedFromTree()
|
| RenderFlowThread::willBeRemovedFromTree();
|
| }
|
|
|
| +bool RenderMultiColumnFlowThread::isColumnSpanner(const RenderObject* descendant) const
|
| +{
|
| + ASSERT(descendant->isDescendantOf(this));
|
| + return m_spannerMap.get(descendant);
|
| +}
|
| +
|
| +bool RenderMultiColumnFlowThread::isInsideColumnSpanner(const RenderObject* descendant) const
|
| +{
|
| + ASSERT(descendant->isDescendantOf(this));
|
| + return containingColumnSpannerSet(descendant);
|
| +}
|
| +
|
| +LayoutUnit RenderMultiColumnFlowThread::enterColumnSpannerBeforeLayout(RenderBox* renderer, LayoutUnit logicalTop, SubtreeLayoutScope& layoutScope)
|
| +{
|
| + ASSERT(isColumnSpanner(renderer));
|
| + RenderMultiColumnSpannerSet* spannerSet = m_spannerMap.get(renderer);
|
| +
|
| + // FIXME: it's really only necessary to mark the spanner set for layout when the height of
|
| + // |renderer| changes.
|
| + spannerSet->setChildNeedsLayout(MarkOnlyThis, &layoutScope);
|
| +
|
| + RenderMultiColumnSet* previousSet = spannerSet->previousSiblingMultiColumnSet();
|
| + if (!previousSet) {
|
| + // The first set is entered at the beginning of flow thread layout. If the first set happens
|
| + // to be a spanner, we have nothing more to do here.
|
| + return LayoutUnit();
|
| + }
|
| +
|
| + LayoutUnit logicalTopInFlowThread = renderer->parentBlock()->offsetFromLogicalTopOfFirstPage() + logicalTop;
|
| + LayoutUnit adjustment;
|
| + if (!previousSet->isRenderMultiColumnSpannerSet() && previousSet->pageLogicalHeight()) {
|
| + // Pad flow thread offset to a column boundary, so that any content that's supposed to come
|
| + // after the spanner (or the spanner itself) doesn't bleed into the column preceding the
|
| + // spanner.
|
| + LayoutUnit columnLogicalTopInFlowThread = previousSet->pageLogicalTopForOffset(logicalTopInFlowThread);
|
| + if (columnLogicalTopInFlowThread != logicalTopInFlowThread) {
|
| + adjustment = columnLogicalTopInFlowThread + previousSet->pageLogicalHeight() - logicalTopInFlowThread;
|
| + logicalTopInFlowThread += adjustment;
|
| + }
|
| + }
|
| +
|
| + if (!previousSet->isRenderMultiColumnSpannerSet())
|
| + previousSet->endFlow(logicalTopInFlowThread);
|
| + spannerSet->beginFlow(logicalTopInFlowThread);
|
| +
|
| + m_lastSetWorkedOn = spannerSet;
|
| + return adjustment;
|
| +}
|
| +
|
| +void RenderMultiColumnFlowThread::exitColumnSpannerAfterLayout(RenderBox* renderer, LayoutUnit logicalBottom)
|
| +{
|
| + ASSERT(m_lastSetWorkedOn == m_spannerMap.get(renderer));
|
| +
|
| + LayoutUnit logicalBottomInFlowThread = renderer->parentBlock()->offsetFromLogicalTopOfFirstPage() + logicalBottom;
|
| + m_lastSetWorkedOn->endFlow(logicalBottomInFlowThread);
|
| + if (RenderMultiColumnSet* nextSet = m_lastSetWorkedOn->nextSiblingMultiColumnSet()) {
|
| + m_lastSetWorkedOn = nextSet;
|
| + if (!m_lastSetWorkedOn->isRenderMultiColumnSpannerSet())
|
| + m_lastSetWorkedOn->beginFlow(logicalBottomInFlowThread);
|
| + }
|
| +}
|
| +
|
| void RenderMultiColumnFlowThread::flowThreadDescendantWasInserted(RenderObject* descendant)
|
| {
|
| + ASSERT(!m_isBeingEvacuated);
|
| // Go through the subtree that was just inserted and create column sets (needed by regular
|
| // column content) and spanner sets (one needed by each spanner).
|
| for (RenderObject* renderer = descendant; renderer; renderer = renderer->nextInPreOrder(descendant)) {
|
| @@ -335,6 +423,34 @@ void RenderMultiColumnFlowThread::flowThreadDescendantWasInserted(RenderObject*
|
| }
|
| }
|
|
|
| +void RenderMultiColumnFlowThread::flowThreadDescendantWillBeRemoved(RenderObject* descendant)
|
| +{
|
| + if (m_isBeingEvacuated)
|
| + return;
|
| + RenderObject* next;
|
| + // Remove spanner sets that are no longer needed, and merge column sets around them.
|
| + for (RenderObject* renderer = descendant; renderer; renderer = next) {
|
| + RenderMultiColumnSpannerSet* spanner = m_spannerMap.get(renderer);
|
| + if (!spanner) {
|
| + next = renderer->nextInPreOrder(descendant);
|
| + continue;
|
| + }
|
| + next = renderer->nextInPreOrderAfterChildren(descendant); // It's a spanner. Its children are of no interest to us.
|
| + if (RenderMultiColumnSet* nextSet = spanner->nextSiblingMultiColumnSet()) {
|
| + RenderMultiColumnSet* previousSet = spanner->previousSiblingMultiColumnSet();
|
| + if (nextSet && !nextSet->isRenderMultiColumnSpannerSet()
|
| + && previousSet && !previousSet->isRenderMultiColumnSpannerSet()) {
|
| + // Need to merge two column sets.
|
| + nextSet->destroy();
|
| + previousSet->setNeedsLayout();
|
| + invalidateRegions();
|
| + }
|
| + }
|
| + m_spannerMap.remove(renderer);
|
| + spanner->destroy();
|
| + }
|
| +}
|
| +
|
| void RenderMultiColumnFlowThread::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
|
| {
|
| // We simply remain at our intrinsic height.
|
| @@ -351,9 +467,17 @@ void RenderMultiColumnFlowThread::updateLogicalWidth()
|
|
|
| void RenderMultiColumnFlowThread::layout()
|
| {
|
| + ASSERT(!m_lastSetWorkedOn);
|
| + m_lastSetWorkedOn = firstMultiColumnSet();
|
| + if (m_lastSetWorkedOn)
|
| + m_lastSetWorkedOn->beginFlow(LayoutUnit());
|
| RenderFlowThread::layout();
|
| - if (RenderMultiColumnSet* lastSet = lastMultiColumnSet())
|
| + if (RenderMultiColumnSet* lastSet = lastMultiColumnSet()) {
|
| + ASSERT(lastSet == m_lastSetWorkedOn);
|
| + lastSet->endFlow(logicalHeight());
|
| lastSet->expandToEncompassFlowThreadContentsIfNeeded();
|
| + }
|
| + m_lastSetWorkedOn = 0;
|
| }
|
|
|
| void RenderMultiColumnFlowThread::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
|
| @@ -375,12 +499,6 @@ void RenderMultiColumnFlowThread::updateMinimumPageHeight(LayoutUnit offset, Lay
|
| multicolSet->updateMinimumColumnHeight(minHeight);
|
| }
|
|
|
| -RenderMultiColumnSet* RenderMultiColumnFlowThread::columnSetAtBlockOffset(LayoutUnit /*offset*/) const
|
| -{
|
| - // For now there's only one column set, so this is easy:
|
| - return firstMultiColumnSet();
|
| -}
|
| -
|
| bool RenderMultiColumnFlowThread::addForcedRegionBreak(LayoutUnit offset, RenderObject* /*breakChild*/, bool /*isBefore*/, LayoutUnit* offsetBreakAdjustment)
|
| {
|
| if (RenderMultiColumnSet* multicolSet = columnSetAtBlockOffset(offset)) {
|
| @@ -394,8 +512,10 @@ bool RenderMultiColumnFlowThread::addForcedRegionBreak(LayoutUnit offset, Render
|
|
|
| bool RenderMultiColumnFlowThread::isPageLogicalHeightKnown() const
|
| {
|
| - if (RenderMultiColumnSet* columnSet = lastMultiColumnSet())
|
| - return columnSet->pageLogicalHeight();
|
| + for (RenderMultiColumnSet* columnSet = lastMultiColumnSet(); columnSet; columnSet = columnSet->previousSiblingMultiColumnSet()) {
|
| + if (!columnSet->isRenderMultiColumnSpannerSet())
|
| + return columnSet->pageLogicalHeight();
|
| + }
|
| return false;
|
| }
|
|
|
|
|