Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(363)

Unified Diff: Source/core/rendering/RenderMultiColumnFlowThread.cpp

Issue 869583002: [New Multicolumn] Support dynamic insertion and removal of multicol content. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698