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 |