Chromium Code Reviews| Index: Source/core/rendering/RenderMultiColumnFlowThread.cpp |
| diff --git a/Source/core/rendering/RenderMultiColumnFlowThread.cpp b/Source/core/rendering/RenderMultiColumnFlowThread.cpp |
| index 027a721718c1ac30a2d8e0adff3403bd05575fc0..4e5432fdfc837488c5bbab715881feafcc8c555d 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,6 +441,7 @@ LayoutUnit RenderMultiColumnFlowThread::skipColumnSpanner(RenderBox* renderer, L |
| void RenderMultiColumnFlowThread::flowThreadDescendantWasInserted(RenderObject* descendant) |
| { |
| ASSERT(!m_isBeingEvacuated); |
| + RenderObject* nextRenderer = descendant->nextInPreOrderAfterChildren(this); |
| // 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). |
| for (RenderObject* renderer = descendant; renderer; renderer = renderer->nextInPreOrder(descendant)) { |
| @@ -448,13 +449,63 @@ void RenderMultiColumnFlowThread::flowThreadDescendantWasInserted(RenderObject* |
| 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, then. |
| + RenderObject* previousRenderer = renderer->previousInPreOrder(this); |
|
Julien - ping for review
2015/01/23 09:13:56
You're using |this| as the |root| instead of |desc
mstensho (USE GERRIT)
2015/01/23 12:15:49
Yes, |this| is the flow thread, and that's all we
|
| + 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(); |
| + } |
| } |
| } |
| @@ -462,6 +513,7 @@ void RenderMultiColumnFlowThread::flowThreadDescendantWillBeRemoved(RenderObject |
| { |
| 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 +535,41 @@ 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. |
| + } |
|
Julien - ping for review
2015/01/23 09:13:56
Shouldn't you ASSERT that you either have no child
mstensho (USE GERRIT)
2015/01/23 12:15:50
Discussed offline that what we already have is eno
|
| + // 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 && !columnSetToRemove->nextSiblingMultiColumnSet()); |
| + } |
| + ASSERT(columnSetToRemove); |
| + columnSetToRemove->destroy(); |
| } |
|
Julien - ping for review
2015/01/23 09:13:56
Adding a comment to explain the whole strategy wou
mstensho (USE GERRIT)
2015/01/23 12:15:49
Done.
Added some header file documentation, and r
|
| void RenderMultiColumnFlowThread::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const |