| Index: Source/core/rendering/RenderMultiColumnFlowThread.cpp
|
| diff --git a/Source/core/rendering/RenderMultiColumnFlowThread.cpp b/Source/core/rendering/RenderMultiColumnFlowThread.cpp
|
| index a6bd077631340a6ab76f66050846204bb21e013f..6eaed6f174181af1b3308840f9bf3bb3b990256a 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()
|
| @@ -227,6 +229,64 @@ 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 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::descendantIsValidColumnSpanner(RenderObject* descendant) const
|
| +{
|
| + // We assume that we're inside the flow thread. This function is not to be called otherwise.
|
| + ASSERT(descendant->isDescendantOf(this));
|
| +
|
| + // The spec says that column-span only applies to in-flow block-level elements.
|
| + if (descendant->style()->columnSpan() != ColumnSpanAll || !descendant->isBox() || descendant->isInline() || descendant->isFloatingOrOutOfFlowPositioned())
|
| + return false;
|
| +
|
| + if (!descendant->containingBlock()->isRenderBlockFlow()) {
|
| + // Needs to be in a block-flow container, and not e.g. a table.
|
| + return false;
|
| + }
|
| +
|
| + // This looks like a spanner, but if we're inside something unbreakable, it's not to be treated as one.
|
| + for (RenderBlock* ancestor = descendant->containingBlock(); ancestor && ancestor->flowThreadContainingBlock() == this; ancestor = ancestor->containingBlock()) {
|
| + if (ancestor->isRenderFlowThread()) {
|
| + ASSERT(ancestor == this);
|
| + return true;
|
| + }
|
| + 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";
|
| @@ -246,6 +306,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.
|
| @@ -255,6 +316,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 (descendantIsValidColumnSpanner(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.
|
|
|