Chromium Code Reviews| Index: Source/core/rendering/RenderMultiColumnFlowThread.cpp |
| diff --git a/Source/core/rendering/RenderMultiColumnFlowThread.cpp b/Source/core/rendering/RenderMultiColumnFlowThread.cpp |
| index 3bacd490d4ec1a851be613a0f9ec31f375ca95dc..e82b05837811e9f1c7d1e23d26b00b880bf64db1 100644 |
| --- a/Source/core/rendering/RenderMultiColumnFlowThread.cpp |
| +++ b/Source/core/rendering/RenderMultiColumnFlowThread.cpp |
| @@ -27,6 +27,7 @@ |
| #include "core/rendering/RenderMultiColumnFlowThread.h" |
| #include "core/rendering/RenderMultiColumnSet.h" |
| +#include "core/rendering/RenderMultiColumnSpannerSet.h" |
| namespace blink { |
| @@ -70,21 +71,22 @@ RenderMultiColumnSet* RenderMultiColumnFlowThread::lastMultiColumnSet() const |
| return 0; |
| } |
| -void RenderMultiColumnFlowThread::addChild(RenderObject* newChild, RenderObject* beforeChild) |
| +RenderMultiColumnSpannerSet* RenderMultiColumnFlowThread::containingColumnSpannerSet(const RenderObject* descendant) const |
| { |
| - RenderBlockFlow::addChild(newChild, beforeChild); |
| - if (firstMultiColumnSet()) |
| - return; |
| - |
| - // For now we only create one column set. It's created as soon as the multicol container gets |
| - // any content at all. |
| - RenderMultiColumnSet* newSet = RenderMultiColumnSet::createAnonymous(this, multiColumnBlockFlow()->style()); |
| - |
| - // Need to skip RenderBlockFlow's implementation of addChild(), or we'd get redirected right |
| - // back here. |
| - multiColumnBlockFlow()->RenderBlock::addChild(newSet); |
| - |
| - invalidateRegions(); |
| + ASSERT(descendant->isDescendantOf(this)); |
| + |
| + // Before we spend time on searching the ancestry, see if there's a quick way to determine |
| + // whether there might be any spanners at all. |
| + RenderMultiColumnSet* firstSet = firstMultiColumnSet(); |
| + if (!firstSet || (firstSet == lastMultiColumnSet() && !firstSet->isRenderMultiColumnSpannerSet())) |
| + return 0; |
| + |
| + // We have spanners. See if the renderer in question is one or inside of one then. |
| + for (const RenderObject* ancestor = descendant; ancestor && ancestor != this; ancestor = ancestor->parent()) { |
| + if (RenderMultiColumnSpannerSet* spanner = m_spannerMap.get(ancestor)) |
| + return spanner; |
| + } |
| + return 0; |
| } |
| void RenderMultiColumnFlowThread::populate() |
| @@ -228,6 +230,67 @@ void RenderMultiColumnFlowThread::calculateColumnCountAndWidth(LayoutUnit& width |
| } |
| } |
| +void RenderMultiColumnFlowThread::createAndInsertMultiColumnSet() |
| +{ |
| + RenderBlockFlow* multicolContainer = multiColumnBlockFlow(); |
| + RenderMultiColumnSet* newSet = RenderMultiColumnSet::createAnonymous(this, multicolContainer->style()); |
| + multicolContainer->RenderBlock::addChild(newSet); |
| + invalidateRegions(); |
| + |
| + // We cannot handle immediate column set siblings (and there's no need for it, either). There |
|
Julien - ping for review
2014/11/05 16:52:38
Nit: Let's move 'There' to the next line so that w
mstensho (USE GERRIT)
2014/11/05 21:43:06
Done.
|
| + // has to be at least one spanner separating them. |
| + ASSERT(!newSet->previousSiblingMultiColumnSet() || newSet->previousSiblingMultiColumnSet()->isRenderMultiColumnSpannerSet()); |
| + ASSERT(!newSet->nextSiblingMultiColumnSet() || newSet->nextSiblingMultiColumnSet()->isRenderMultiColumnSpannerSet()); |
| +} |
| + |
| +void RenderMultiColumnFlowThread::createAndInsertSpannerSet(RenderBox* spanner) |
| +{ |
| + RenderBlockFlow* multicolContainer = multiColumnBlockFlow(); |
| + RenderMultiColumnSpannerSet* newSpannerSet = RenderMultiColumnSpannerSet::createAnonymous(this, multicolContainer->style(), spanner); |
| + multicolContainer->RenderBlock::addChild(newSpannerSet); |
| + m_spannerMap.add(spanner, newSpannerSet); |
| + invalidateRegions(); |
| +} |
| + |
| +bool RenderMultiColumnFlowThread::isDescendantValidColumnSpanner(RenderObject* descendant) const |
| +{ |
| + // We assume that we're inside the flow thread. This function is not to be called otherwise. |
| + ASSERT(descendant->isDescendantOf(this)); |
| + |
| + // First make sure that the renderer itself has the right properties and characteristics for |
| + // becoming a spanner. |
|
Julien - ping for review
2014/11/05 16:52:38
I would be good to quote from the specification as
mstensho (USE GERRIT)
2014/11/05 21:43:06
Done.
|
| + if (descendant->style()->columnSpan() != ColumnSpanAll || !descendant->isBox() || descendant->isInline() || descendant->isFloatingOrOutOfFlowPositioned()) |
| + return false; |
| + |
| + if (!descendant->containingBlock()->isRenderBlockFlow()) { |
| + // Needs to be in a block container, and not e.g. a table. |
|
Julien - ping for review
2014/11/05 16:52:38
It should be: block-flow container
mstensho (USE GERRIT)
2014/11/05 21:43:06
Done.
The spec calls those things "block containe
|
| + return false; |
| + } |
| + |
| + // This looks like a spanner, but if we're inside something unbreakable, it's not to be treated as one. |
| + for (RenderBox* ancestor = toRenderBox(descendant)->parentBox(); ancestor; ancestor = ancestor->parentBox()) { |
|
Julien - ping for review
2014/11/05 16:52:38
I don't think you should not use parentBox as it d
mstensho (USE GERRIT)
2014/11/05 21:43:06
The spec doesn't have much to offer regarding this
|
| + if (ancestor->isRenderFlowThread()) { |
|
Julien - ping for review
2014/11/05 16:52:38
Shouldn't we just check flowThreadState()? If that
mstensho (USE GERRIT)
2014/11/05 21:43:06
flowThreadState() just tells you if you're a flow
|
| + // Don't allow any intervening non-multicol fragmentation contexts. The spec doesn't say |
|
Julien - ping for review
2014/11/05 16:52:38
We don't allow non-multicol fragmentation contexts
mstensho (USE GERRIT)
2014/11/05 21:43:06
There's paged containers (overflow:-webkit-paged-[
mstensho (USE GERRIT)
2014/11/05 23:16:22
Nonono! Wrong! Well, yes, there may be paged conta
|
| + // anything about disallowing this, but it's just going to be too complicated to |
| + // implement (not to mention specify behavior). |
| + return ancestor == this; |
| + } |
| + if (m_spannerMap.get(ancestor)) { |
| + // FIXME: do we want to support nested spanners in a different way? The outer spanner |
| + // has already broken out from the columns to become sized by the multicol container, |
| + // which may be good enough for the inner spanner. But margins, borders, padding and |
| + // explicit widths on the outer spanner, or on any children between the outer and inner |
| + // spanner, will affect the width of the inner spanner this way, which might be |
| + // undesirable. The spec has nothing to say on the matter. |
| + return false; // Ignore nested spanners. |
| + } |
| + if (ancestor->isUnsplittableForPagination()) |
| + return false; |
| + } |
| + ASSERT_NOT_REACHED(); |
| + return false; |
| +} |
| + |
| const char* RenderMultiColumnFlowThread::renderName() const |
| { |
| return "RenderMultiColumnFlowThread"; |
| @@ -247,6 +310,7 @@ void RenderMultiColumnFlowThread::addRegionToThread(RenderMultiColumnSet* column |
| void RenderMultiColumnFlowThread::willBeRemovedFromTree() |
| { |
| + m_spannerMap.clear(); |
| // Detach all column sets from the flow thread. Cannot destroy them at this point, since they |
| // are siblings of this object, and there may be pointers to this object's sibling somewhere |
| // further up on the call stack. |
| @@ -256,6 +320,25 @@ void RenderMultiColumnFlowThread::willBeRemovedFromTree() |
| RenderFlowThread::willBeRemovedFromTree(); |
| } |
| +void RenderMultiColumnFlowThread::flowThreadDescendantWasInserted(RenderObject* descendant) |
| +{ |
| + // 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)) { |
| + if (containingColumnSpannerSet(renderer)) |
| + continue; // Inside a column spanner set. Nothing to do, then. |
| + if (isDescendantValidColumnSpanner(renderer)) { |
| + // This renderer is a spanner, so it needs to establish a spanner set. |
| + createAndInsertSpannerSet(toRenderBox(renderer)); |
| + continue; |
| + } |
| + // This renderer is regular column content (i.e. not a spanner). Create a set if necessary. |
| + RenderMultiColumnSet* lastSet = lastMultiColumnSet(); |
| + if (!lastSet || lastSet->isRenderMultiColumnSpannerSet()) |
| + createAndInsertMultiColumnSet(); |
| + } |
| +} |
| + |
| void RenderMultiColumnFlowThread::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const |
| { |
| // We simply remain at our intrinsic height. |