| Index: Source/core/rendering/RenderMultiColumnFlowThread.cpp
|
| diff --git a/Source/core/rendering/RenderMultiColumnFlowThread.cpp b/Source/core/rendering/RenderMultiColumnFlowThread.cpp
|
| index 027a721718c1ac30a2d8e0adff3403bd05575fc0..0af35bb74c94ec0857dcca363d101b7b783835b1 100644
|
| --- a/Source/core/rendering/RenderMultiColumnFlowThread.cpp
|
| +++ b/Source/core/rendering/RenderMultiColumnFlowThread.cpp
|
| @@ -321,11 +321,11 @@ void RenderMultiColumnFlowThread::calculateColumnCountAndWidth(LayoutUnit& width
|
| }
|
| }
|
|
|
| -void RenderMultiColumnFlowThread::createAndInsertMultiColumnSet()
|
| +void RenderMultiColumnFlowThread::createAndInsertMultiColumnSet(RenderBox* insertBefore)
|
| {
|
| RenderBlockFlow* multicolContainer = multiColumnBlockFlow();
|
| RenderMultiColumnSet* newSet = RenderMultiColumnSet::createAnonymous(this, multicolContainer->style());
|
| - multicolContainer->RenderBlock::addChild(newSet);
|
| + multicolContainer->RenderBlock::addChild(newSet, insertBefore);
|
| invalidateRegions();
|
|
|
| // We cannot handle immediate column set siblings (and there's no need for it, either).
|
| @@ -334,11 +334,11 @@ void RenderMultiColumnFlowThread::createAndInsertMultiColumnSet()
|
| ASSERT(!newSet->nextSiblingMultiColumnBox() || !newSet->nextSiblingMultiColumnBox()->isRenderMultiColumnSet());
|
| }
|
|
|
| -void RenderMultiColumnFlowThread::createAndInsertSpannerPlaceholder(RenderBox* spanner)
|
| +void RenderMultiColumnFlowThread::createAndInsertSpannerPlaceholder(RenderBox* spanner, RenderBox* insertBefore)
|
| {
|
| RenderBlockFlow* multicolContainer = multiColumnBlockFlow();
|
| RenderMultiColumnSpannerPlaceholder* newPlaceholder = RenderMultiColumnSpannerPlaceholder::createAnonymous(multicolContainer->style(), spanner);
|
| - multicolContainer->RenderBlock::addChild(newPlaceholder);
|
| + multicolContainer->RenderBlock::addChild(newPlaceholder, insertBefore);
|
| spanner->setSpannerPlaceholder(*newPlaceholder);
|
| }
|
|
|
| @@ -441,27 +441,86 @@ LayoutUnit RenderMultiColumnFlowThread::skipColumnSpanner(RenderBox* renderer, L
|
| 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 placeholders (one needed by each spanner).
|
| + RenderObject* nextRenderer = descendant->nextInPreOrderAfterChildren(this);
|
| + // This method ensures that the list of column sets and spanner placeholders reflects the
|
| + // multicol content after having inserted a descendant (or descendant subtree). See the header
|
| + // file for more information. Go through the subtree that was just inserted and create column
|
| + // sets (needed by regular column content) and spanner placeholders (one needed by each spanner)
|
| + // where needed.
|
| for (RenderObject* renderer = descendant; renderer; renderer = renderer->nextInPreOrder(descendant)) {
|
| if (containingColumnSpannerPlaceholder(renderer))
|
| continue; // Inside a column spanner. Nothing to do, then.
|
| if (descendantIsValidColumnSpanner(renderer)) {
|
| // This renderer is a spanner, so it needs to establish a spanner placeholder.
|
| - createAndInsertSpannerPlaceholder(toRenderBox(renderer));
|
| + RenderBox* insertBefore = 0;
|
| + RenderMultiColumnSet* setToSplit = 0;
|
| + if (nextRenderer) {
|
| + // The spanner is inserted before something. Figure out what this entails. If the
|
| + // next renderer is a spanner too, it means that we can simply insert a new spanner
|
| + // placeholder in front of its placeholder.
|
| + insertBefore = nextRenderer->spannerPlaceholder();
|
| + if (!insertBefore) {
|
| + // The next renderer isn't a spanner; it's regular column content. Examine what
|
| + // comes right before us in the flow thread, then.
|
| + RenderObject* previousRenderer = renderer->previousInPreOrder(this);
|
| + if (!previousRenderer || previousRenderer == this) {
|
| + // The spanner is inserted as the first child of the multicol container,
|
| + // which means that we simply insert a new spanner placeholder at the
|
| + // beginning.
|
| + insertBefore = firstMultiColumnBox();
|
| + } else if (RenderMultiColumnSpannerPlaceholder* previousPlaceholder = containingColumnSpannerPlaceholder(previousRenderer)) {
|
| + // Before us is another spanner. We belong right after it then.
|
| + insertBefore = previousPlaceholder->nextSiblingMultiColumnBox();
|
| + } else {
|
| + // We're inside regular column content with both feet. Find out which column
|
| + // set this is. It needs to be split it into two sets, so that we can insert
|
| + // a new spanner placeholder between them.
|
| + setToSplit = findSetRendering(previousRenderer);
|
| + ASSERT(setToSplit == findSetRendering(nextRenderer));
|
| + setToSplit->setNeedsLayoutAndFullPaintInvalidation();
|
| + insertBefore = setToSplit->nextSiblingMultiColumnBox();
|
| + // We've found out which set that needs to be split. Now proceed to
|
| + // inserting the spanner placeholder, and then insert a second column set.
|
| + }
|
| + }
|
| + ASSERT(setToSplit || insertBefore);
|
| + }
|
| + createAndInsertSpannerPlaceholder(toRenderBox(renderer), insertBefore);
|
| + if (setToSplit)
|
| + createAndInsertMultiColumnSet(insertBefore);
|
| continue;
|
| }
|
| // This renderer is regular column content (i.e. not a spanner). Create a set if necessary.
|
| - RenderBox* lastColumnBox = lastMultiColumnBox();
|
| - if (!lastColumnBox || !lastColumnBox->isRenderMultiColumnSet())
|
| - createAndInsertMultiColumnSet();
|
| + if (nextRenderer) {
|
| + if (RenderMultiColumnSpannerPlaceholder* placeholder = nextRenderer->spannerPlaceholder()) {
|
| + // If inserted right before a spanner, we need to make sure that there's a set for us there.
|
| + RenderBox* previous = placeholder->previousSiblingMultiColumnBox();
|
| + if (!previous || !previous->isRenderMultiColumnSet())
|
| + createAndInsertMultiColumnSet(placeholder);
|
| + } else {
|
| + // Otherwise, since |nextRenderer| isn't a spanner, it has to mean that there's
|
| + // already a set for that content. We can use it for this renderer too.
|
| + ASSERT(findSetRendering(nextRenderer));
|
| + ASSERT(findSetRendering(renderer) == findSetRendering(nextRenderer));
|
| + }
|
| + } else {
|
| + // Inserting at the end. Then we just need to make sure that there's a column set at the end.
|
| + RenderBox* lastColumnBox = lastMultiColumnBox();
|
| + if (!lastColumnBox || !lastColumnBox->isRenderMultiColumnSet())
|
| + createAndInsertMultiColumnSet();
|
| + }
|
| }
|
| }
|
|
|
| void RenderMultiColumnFlowThread::flowThreadDescendantWillBeRemoved(RenderObject* descendant)
|
| {
|
| + // This method ensures that the list of column sets and spanner placeholders reflects the
|
| + // multicol content that we'll be left with after removal of a descendant (or descendant
|
| + // subtree). See the header file for more information. Removing content may mean that we need to
|
| + // remove column sets and/or spanner placeholders.
|
| if (m_isBeingEvacuated)
|
| return;
|
| + bool hadContainingPlaceholder = containingColumnSpannerPlaceholder(descendant);
|
| RenderObject* next;
|
| // Remove spanner placeholders that are no longer needed, and merge column sets around them.
|
| for (RenderObject* renderer = descendant; renderer; renderer = next) {
|
| @@ -483,6 +542,42 @@ void RenderMultiColumnFlowThread::flowThreadDescendantWillBeRemoved(RenderObject
|
| }
|
| placeholder->destroy();
|
| }
|
| + if (hadContainingPlaceholder)
|
| + return; // We're only removing a spanner (or something inside one), which means that no column content will be removed.
|
| +
|
| + // Column content will be removed. Does this mean that we should destroy a column set?
|
| + RenderMultiColumnSpannerPlaceholder* adjacentPreviousSpannerPlaceholder = 0;
|
| + RenderObject* previousRenderer = descendant->previousInPreOrder(this);
|
| + if (previousRenderer && previousRenderer != this) {
|
| + adjacentPreviousSpannerPlaceholder = containingColumnSpannerPlaceholder(previousRenderer);
|
| + if (!adjacentPreviousSpannerPlaceholder)
|
| + return; // Preceded by column content. Set still needed.
|
| + }
|
| + RenderMultiColumnSpannerPlaceholder* adjacentNextSpannerPlaceholder = 0;
|
| + RenderObject* nextRenderer = descendant->nextInPreOrderAfterChildren(this);
|
| + if (nextRenderer) {
|
| + adjacentNextSpannerPlaceholder = containingColumnSpannerPlaceholder(nextRenderer);
|
| + if (!adjacentNextSpannerPlaceholder)
|
| + return; // Followed by column content. Set still needed.
|
| + }
|
| + // We have now determined that, with the removal of |descendant|, we should remove a column
|
| + // set. Locate it and remove it. Do it without involving findSetRendering(), as that might be
|
| + // very slow. Deduce the right set from the spanner placeholders that we've already found.
|
| + RenderMultiColumnSet* columnSetToRemove;
|
| + if (adjacentNextSpannerPlaceholder) {
|
| + columnSetToRemove = toRenderMultiColumnSet(adjacentNextSpannerPlaceholder->previousSiblingMultiColumnBox());
|
| + ASSERT(!adjacentPreviousSpannerPlaceholder || columnSetToRemove == adjacentPreviousSpannerPlaceholder->nextSiblingMultiColumnBox());
|
| + } else if (adjacentPreviousSpannerPlaceholder) {
|
| + columnSetToRemove = toRenderMultiColumnSet(adjacentPreviousSpannerPlaceholder->nextSiblingMultiColumnBox());
|
| + } else {
|
| + // If there were no adjacent spanners, it has to mean that there's only one column set,
|
| + // since it's only spanners that may cause creation of multiple sets.
|
| + columnSetToRemove = firstMultiColumnSet();
|
| + ASSERT(columnSetToRemove);
|
| + ASSERT(!columnSetToRemove->nextSiblingMultiColumnSet());
|
| + }
|
| + ASSERT(columnSetToRemove);
|
| + columnSetToRemove->destroy();
|
| }
|
|
|
| void RenderMultiColumnFlowThread::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
|
|
|