LayoutMultiColumnFlowThread* LayoutMultiColumnFlowThread::enclosingFlowThread() const
{
    if (isLayoutPagedFlowThread()) {
        // Paged overflow containers should never be fragmented by enclosing fragmentation
        // contexts. They are to be treated as unbreakable content.
        return nullptr;
    }
    if (multiColumnBlockFlow()->isInsideFlowThread())
        return toLayoutMultiColumnFlowThread(locateFlowThreadContainingBlockOf(*multiColumnBlockFlow()));
    return nullptr;
}
LayoutUnit LayoutMultiColumnSet::columnGap() const
{
    LayoutBlockFlow* parentBlock = multiColumnBlockFlow();
    if (parentBlock->style()->hasNormalColumnGap())
        return parentBlock->style()->fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
    return parentBlock->style()->columnGap();
}
void RenderMultiColumnFlowThread::evacuateAndDestroy()
{
    RenderBlockFlow* multicolContainer = multiColumnBlockFlow();
    m_beingEvacuated = true;

    // Delete the line box tree.
    deleteLines();

    LayoutStateDisabler layoutStateDisabler(&view());

    // First promote all children of the flow thread. Before we move them to the flow thread's
    // container, we need to unregister the flow thread, so that they aren't just re-added again to
    // the flow thread that we're trying to empty.
    multicolContainer->setMultiColumnFlowThread(nullptr);
    moveAllChildrenTo(multicolContainer, true);

    // Move spanners back to their original DOM position in the tree, and destroy the placeholders.
    SpannerMap::iterator it;
    while ((it = m_spannerMap.begin()) != m_spannerMap.end()) {
        RenderBox* spanner = it->key;
        RenderMultiColumnSpannerPlaceholder* placeholder = it->value;
        RenderBlockFlow* originalContainer = toRenderBlockFlow(placeholder->parent());
        multicolContainer->removeChild(*spanner);
        originalContainer->addChild(spanner, placeholder);
        placeholder->destroy();
        m_spannerMap.remove(it);
    }

    // Remove all sets.
    while (RenderMultiColumnSet* columnSet = firstMultiColumnSet())
        columnSet->destroy();

    destroy();
}
void LayoutMultiColumnFlowThread::layoutColumns(SubtreeLayoutScope& layoutScope)
{
    // Since we ended up here, it means that the multicol container (our parent) needed
    // layout. Since contents of the multicol container are diverted to the flow thread, the flow
    // thread needs layout as well.
    layoutScope.setChildNeedsLayout(this);

    m_blockOffsetInEnclosingFragmentationContext = enclosingFragmentationContext() ? multiColumnBlockFlow()->offsetFromLogicalTopOfFirstPage() : LayoutUnit();

    for (LayoutBox* columnBox = firstMultiColumnBox(); columnBox; columnBox = columnBox->nextSiblingMultiColumnBox()) {
        if (!columnBox->isLayoutMultiColumnSet()) {
            ASSERT(columnBox->isLayoutMultiColumnSpannerPlaceholder()); // no other type is expected.
            continue;
        }
        LayoutMultiColumnSet* columnSet = toLayoutMultiColumnSet(columnBox);
        layoutScope.setChildNeedsLayout(columnSet);
        if (!m_columnHeightsChanged) {
            // This is the initial layout pass. We need to reset the column height, because contents
            // typically have changed.
            columnSet->resetColumnHeight();
        }
        // Since column sets are regular block flow objects, and their position is changed in
        // regular block layout code (with no means for the multicol code to notice unless we add
        // hooks there), store the previous position now. If it changes in the imminent layout
        // pass, we may have to rebalance its columns.
        columnSet->storeOldPosition();
    }

    m_columnHeightsChanged = false;
    invalidateColumnSets();
    layout();
    validateColumnSets();
}
void LayoutMultiColumnFlowThread::computePreferredLogicalWidths()
{
    LayoutFlowThread::computePreferredLogicalWidths();

    // The min/max intrinsic widths calculated really tell how much space elements need when
    // laid out inside the columns. In order to eventually end up with the desired column width,
    // we need to convert them to values pertaining to the multicol container.
    const LayoutBlockFlow* multicolContainer = multiColumnBlockFlow();
    const ComputedStyle* multicolStyle = multicolContainer->style();
    int columnCount = multicolStyle->hasAutoColumnCount() ? 1 : multicolStyle->columnCount();
    LayoutUnit columnWidth;
    LayoutUnit gapExtra = (columnCount - 1) * multicolContainer->columnGap();
    if (multicolStyle->hasAutoColumnWidth()) {
        m_minPreferredLogicalWidth = m_minPreferredLogicalWidth * columnCount + gapExtra;
    } else {
        columnWidth = multicolStyle->columnWidth();
        m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, columnWidth);
    }
    // Note that if column-count is auto here, we should resolve it to calculate the maximum
    // intrinsic width, instead of pretending that it's 1. The only way to do that is by performing
    // a layout pass, but this is not an appropriate time or place for layout. The good news is that
    // if height is unconstrained and there are no explicit breaks, the resolved column-count really
    // should be 1.
    m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, columnWidth) * columnCount + gapExtra;
}
void LayoutMultiColumnFlowThread::evacuateAndDestroy()
{
    LayoutBlockFlow* multicolContainer = multiColumnBlockFlow();
    m_isBeingEvacuated = true;

    // Remove all sets and spanners.
    while (LayoutBox* columnBox = firstMultiColumnBox()) {
        ASSERT(columnBox->isAnonymous());
        columnBox->destroy();
    }

    ASSERT(!previousSibling());
    ASSERT(!nextSibling());

    // Finally we can promote all flow thread's children. Before we move them to the flow thread's
    // container, we need to unregister the flow thread, so that they aren't just re-added again to
    // the flow thread that we're trying to empty.
    multicolContainer->resetMultiColumnFlowThread();
    moveAllChildrenTo(multicolContainer, true);

    // We used to manually nuke the line box tree here, but that should happen automatically when
    // moving children around (the code above).
    ASSERT(!firstLineBox());

    destroy();
}
Exemplo n.º 7
0
LayoutUnit RenderMultiColumnSet::heightAdjustedForSetOffset(LayoutUnit height) const
{
    RenderBlockFlow* multicolBlock = multiColumnBlockFlow();
    LayoutUnit contentLogicalTop = logicalTop() - multicolBlock->borderBefore() - multicolBlock->paddingBefore();

    height -= contentLogicalTop;
    return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would probably cause an infinite amount of columns to be created.
}
LayoutMultiColumnSet* LayoutMultiColumnFlowThread::lastMultiColumnSet() const
{
    for (LayoutObject* sibling = multiColumnBlockFlow()->lastChild(); sibling; sibling = sibling->previousSibling()) {
        if (sibling->isLayoutMultiColumnSet())
            return toLayoutMultiColumnSet(sibling);
    }
    return nullptr;
}
void LayoutMultiColumnFlowThread::populate()
{
    LayoutBlockFlow* multicolContainer = multiColumnBlockFlow();
    ASSERT(!nextSibling());
    // Reparent children preceding the flow thread into the flow thread. It's multicol content
    // now. At this point there's obviously nothing after the flow thread, but layoutObjects (column
    // sets and spanners) will be inserted there as we insert elements into the flow thread.
    multicolContainer->moveChildrenTo(this, multicolContainer->firstChild(), this, true);
}
void LayoutMultiColumnFlowThread::willBeRemovedFromTree()
{
    // 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.
    for (LayoutMultiColumnSet* columnSet = firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet())
        columnSet->detachFromFlowThread();
    multiColumnBlockFlow()->resetMultiColumnFlowThread();
    LayoutFlowThread::willBeRemovedFromTree();
}
void LayoutMultiColumnFlowThread::createAndInsertMultiColumnSet(LayoutBox* insertBefore)
{
    LayoutBlockFlow* multicolContainer = multiColumnBlockFlow();
    LayoutMultiColumnSet* newSet = LayoutMultiColumnSet::createAnonymous(*this, multicolContainer->styleRef());
    multicolContainer->LayoutBlock::addChild(newSet, insertBefore);
    invalidateColumnSets();

    // 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->previousSiblingMultiColumnBox() || !newSet->previousSiblingMultiColumnBox()->isLayoutMultiColumnSet());
    ASSERT(!newSet->nextSiblingMultiColumnBox() || !newSet->nextSiblingMultiColumnBox()->isLayoutMultiColumnSet());
}
Exemplo n.º 12
0
void RenderMultiColumnSet::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
{
    if (paintInfo.context->paintingDisabled())
        return;

    RenderStyle* blockStyle = multiColumnBlockFlow()->style();
    const Color& ruleColor = resolveColor(blockStyle, CSSPropertyWebkitColumnRuleColor);
    bool ruleTransparent = blockStyle->columnRuleIsTransparent();
    EBorderStyle ruleStyle = blockStyle->columnRuleStyle();
    LayoutUnit ruleThickness = blockStyle->columnRuleWidth();
    LayoutUnit colGap = columnGap();
    bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent;
    if (!renderRule)
        return;

    unsigned colCount = columnCount();
    if (colCount <= 1)
        return;

    bool antialias = shouldAntialiasLines(paintInfo.context);

    bool leftToRight = style()->isLeftToRightDirection();
    LayoutUnit currLogicalLeftOffset = leftToRight ? LayoutUnit() : contentLogicalWidth();
    LayoutUnit ruleAdd = borderAndPaddingLogicalLeft();
    LayoutUnit ruleLogicalLeft = leftToRight ? LayoutUnit() : contentLogicalWidth();
    LayoutUnit inlineDirectionSize = computedColumnWidth();
    BoxSide boxSide = isHorizontalWritingMode()
        ? leftToRight ? BSLeft : BSRight
        : leftToRight ? BSTop : BSBottom;

    for (unsigned i = 0; i < colCount; i++) {
        // Move to the next position.
        if (leftToRight) {
            ruleLogicalLeft += inlineDirectionSize + colGap / 2;
            currLogicalLeftOffset += inlineDirectionSize + colGap;
        } else {
            ruleLogicalLeft -= (inlineDirectionSize + colGap / 2);
            currLogicalLeftOffset -= (inlineDirectionSize + colGap);
        }

        // Now paint the column rule.
        if (i < colCount - 1) {
            LayoutUnit ruleLeft = isHorizontalWritingMode() ? paintOffset.x() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd : paintOffset.x() + borderLeft() + paddingLeft();
            LayoutUnit ruleRight = isHorizontalWritingMode() ? ruleLeft + ruleThickness : ruleLeft + contentWidth();
            LayoutUnit ruleTop = isHorizontalWritingMode() ? paintOffset.y() + borderTop() + paddingTop() : paintOffset.y() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd;
            LayoutUnit ruleBottom = isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleThickness;
            IntRect pixelSnappedRuleRect = pixelSnappedIntRectFromEdges(ruleLeft, ruleTop, ruleRight, ruleBottom);
            drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
        }

        ruleLogicalLeft = currLogicalLeftOffset;
    }
}
Exemplo n.º 13
0
LayoutUnit RenderMultiColumnSet::calculateMaxColumnHeight() const
{
    RenderBlockFlow* multicolBlock = multiColumnBlockFlow();
    RenderStyle* multicolStyle = multicolBlock->style();
    LayoutUnit availableHeight = multiColumnFlowThread()->columnHeightAvailable();
    LayoutUnit maxColumnHeight = availableHeight ? availableHeight : RenderFlowThread::maxLogicalHeight();
    if (!multicolStyle->logicalMaxHeight().isUndefined()) {
        LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight(multicolStyle->logicalMaxHeight(), -1);
        if (logicalMaxHeight != -1 && maxColumnHeight > logicalMaxHeight)
            maxColumnHeight = logicalMaxHeight;
    }
    return heightAdjustedForSetOffset(maxColumnHeight);
}
LayoutUnit LayoutMultiColumnSet::logicalTopFromMulticolContentEdge() const
{
    // We subtract the position of the first column set or spanner placeholder, rather than the
    // "before" border+padding of the multicol container. This distinction doesn't matter after
    // layout, but during layout it does: The flow thread (i.e. the multicol contents) is laid out
    // before the column sets and spanner placeholders, which means that compesating for a top
    // border+padding that hasn't yet been baked into the offset will produce the wrong results in
    // the first layout pass, and we'd end up performing a wasted layout pass in many cases.
    const LayoutBox& firstColumnBox = *multiColumnFlowThread()->firstMultiColumnBox();
    // The top margin edge of the first column set or spanner placeholder is flush with the top
    // content edge of the multicol container. The margin here never collapses with other margins,
    // so we can just subtract it. Column sets never have margins, but spanner placeholders may.
    LayoutUnit firstColumnBoxMarginEdge = firstColumnBox.logicalTop() - multiColumnBlockFlow()->marginBeforeForChild(firstColumnBox);
    return logicalTop() - firstColumnBoxMarginEdge;
}
Exemplo n.º 15
0
LayoutUnit RenderMultiColumnSet::heightAdjustedForSetOffset(LayoutUnit height) const
{
    // Adjust for the top offset within the content box of the multicol container (containing
    // block), unless this is the first set. We know that the top offset for the first set will be
    // zero, but if the multicol container has non-zero top border or padding, the set's top offset
    // (initially being 0 and relative to the border box) will be negative until it has been laid
    // out. Had we used this bogus offset, we would calculate the wrong height, and risk performing
    // a wasted layout iteration. Of course all other sets (if any) have this problem in the first
    // layout pass too, but there's really nothing we can do there until the flow thread has been
    // laid out anyway.
    if (previousSiblingMultiColumnSet()) {
        RenderBlockFlow* multicolBlock = multiColumnBlockFlow();
        LayoutUnit contentLogicalTop = logicalTop() - multicolBlock->borderAndPaddingBefore();
        height -= contentLogicalTop;
    }
    return max(height, LayoutUnit(1)); // Let's avoid zero height, as that would probably cause an infinite amount of columns to be created.
}
void LayoutMultiColumnFlowThread::contentWasLaidOut(LayoutUnit logicalTopInFlowThreadAfterPagination)
{
    // Check if we need another fragmentainer group. If we've run out of columns in the last
    // fragmentainer group (column row), we need to insert another fragmentainer group to hold more
    // columns.

    // First figure out if there's any chance that we're nested at all. If we can be sure that
    // we're not, bail early. This code is run very often, and since locating a containing flow
    // thread has some cost (depending on tree depth), avoid calling
    // enclosingFragmentationContext() right away. This test may give some false positives (hence
    // the "mayBe"), if we're in an out-of-flow subtree and have an outer multicol container that
    // doesn't affect us, but that's okay. We'll discover that further down the road when trying to
    // locate our enclosing flow thread for real.
    bool mayBeNested = multiColumnBlockFlow()->isInsideFlowThread() || view()->fragmentationContext();
    if (!mayBeNested)
        return;
    appendNewFragmentainerGroupIfNeeded(logicalTopInFlowThreadAfterPagination);
}
void LayoutMultiColumnFlowThread::createAndInsertSpannerPlaceholder(LayoutBox* spannerObjectInFlowThread, LayoutObject* insertedBeforeInFlowThread)
{
    LayoutBox* insertBeforeColumnBox = nullptr;
    LayoutMultiColumnSet* setToSplit = nullptr;
    if (insertedBeforeInFlowThread) {
        // The spanner is inserted before something. Figure out what this entails. If the
        // next object is a spanner too, it means that we can simply insert a new spanner
        // placeholder in front of its placeholder.
        insertBeforeColumnBox = insertedBeforeInFlowThread->spannerPlaceholder();
        if (!insertBeforeColumnBox) {
            // The next object isn't a spanner; it's regular column content. Examine what
            // comes right before us in the flow thread, then.
            LayoutObject* previousLayoutObject = previousInPreOrderSkippingOutOfFlow(this, spannerObjectInFlowThread);
            if (!previousLayoutObject || previousLayoutObject == 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.
                insertBeforeColumnBox = firstMultiColumnBox();
            } else if (LayoutMultiColumnSpannerPlaceholder* previousPlaceholder = containingColumnSpannerPlaceholder(previousLayoutObject)) {
                // Before us is another spanner. We belong right after it then.
                insertBeforeColumnBox = 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 = mapDescendantToColumnSet(previousLayoutObject);
                ASSERT(setToSplit == mapDescendantToColumnSet(insertedBeforeInFlowThread));
                insertBeforeColumnBox = 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 || insertBeforeColumnBox);
    }

    LayoutBlockFlow* multicolContainer = multiColumnBlockFlow();
    LayoutMultiColumnSpannerPlaceholder* newPlaceholder = LayoutMultiColumnSpannerPlaceholder::createAnonymous(multicolContainer->styleRef(), *spannerObjectInFlowThread);
    ASSERT(!insertBeforeColumnBox || insertBeforeColumnBox->parent() == multicolContainer);
    multicolContainer->LayoutBlock::addChild(newPlaceholder, insertBeforeColumnBox);
    spannerObjectInFlowThread->setSpannerPlaceholder(*newPlaceholder);

    if (setToSplit)
        createAndInsertMultiColumnSet(insertBeforeColumnBox);
}
bool LayoutMultiColumnSet::heightIsAuto() const
{
    LayoutMultiColumnFlowThread* flowThread = multiColumnFlowThread();
    if (!flowThread->isLayoutPagedFlowThread()) {
        // If support for the column-fill property isn't enabled, we want to behave as if
        // column-fill were auto, so that multicol containers with specified height don't get their
        // columns balanced (auto-height multicol containers will still get their columns balanced,
        // even if column-fill isn't 'balance' - in accordance with the spec). Pretending that
        // column-fill is auto also matches the old multicol implementation, which has no support
        // for this property.
        if (multiColumnBlockFlow()->style()->getColumnFill() == ColumnFillBalance)
            return true;
        if (LayoutBox* next = nextSiblingBox()) {
            if (next->isLayoutMultiColumnSpannerPlaceholder()) {
                // If we're followed by a spanner, we need to balance.
                return true;
            }
        }
    }
    return !flowThread->columnHeightAvailable();
}
void LayoutMultiColumnFlowThread::calculateColumnCountAndWidth(LayoutUnit& width, unsigned& count) const
{
    LayoutBlock* columnBlock = multiColumnBlockFlow();
    const ComputedStyle* columnStyle = columnBlock->style();
    LayoutUnit availableWidth = columnBlock->contentLogicalWidth();
    LayoutUnit columnGap = columnBlock->columnGap();
    LayoutUnit computedColumnWidth = max<LayoutUnit>(1, LayoutUnit(columnStyle->columnWidth()));
    unsigned computedColumnCount = max<int>(1, columnStyle->columnCount());

    ASSERT(!columnStyle->hasAutoColumnCount() || !columnStyle->hasAutoColumnWidth());
    if (columnStyle->hasAutoColumnWidth() && !columnStyle->hasAutoColumnCount()) {
        count = computedColumnCount;
        width = std::max<LayoutUnit>(0, (availableWidth - ((count - 1) * columnGap)) / count);
    } else if (!columnStyle->hasAutoColumnWidth() && columnStyle->hasAutoColumnCount()) {
        count = std::max<LayoutUnit>(1, (availableWidth + columnGap) / (computedColumnWidth + columnGap));
        width = ((availableWidth + columnGap) / count) - columnGap;
    } else {
        count = std::max<LayoutUnit>(std::min<LayoutUnit>(computedColumnCount, (availableWidth + columnGap) / (computedColumnWidth + columnGap)), 1);
        width = ((availableWidth + columnGap) / count) - columnGap;
    }
}
Exemplo n.º 20
0
void RenderMultiColumnSet::prepareForLayout()
{
    RenderBlockFlow* multicolBlock = multiColumnBlockFlow();
    RenderStyle* multicolStyle = multicolBlock->style();

    // Set box logical top.
    ASSERT(!previousSiblingBox() || !previousSiblingBox()->isRenderMultiColumnSet()); // FIXME: multiple set not implemented; need to examine previous set to calculate the correct logical top.
    setLogicalTop(multicolBlock->borderBefore() + multicolBlock->paddingBefore());

    // Set box width.
    updateLogicalWidth();

    if (multicolBlock->multiColumnFlowThread()->requiresBalancing()) {
        // Set maximum column height. We will not stretch beyond this.
        m_maxColumnHeight = RenderFlowThread::maxLogicalHeight();
        if (!multicolStyle->logicalHeight().isAuto()) {
            m_maxColumnHeight = multicolBlock->computeContentLogicalHeight(multicolStyle->logicalHeight(), -1);
            if (m_maxColumnHeight == -1)
                m_maxColumnHeight = RenderFlowThread::maxLogicalHeight();
        }
        if (!multicolStyle->logicalMaxHeight().isUndefined()) {
            LayoutUnit logicalMaxHeight = multicolBlock->computeContentLogicalHeight(multicolStyle->logicalMaxHeight(), -1);
            if (logicalMaxHeight != -1 && m_maxColumnHeight > logicalMaxHeight)
                m_maxColumnHeight = logicalMaxHeight;
        }
        m_maxColumnHeight = heightAdjustedForSetOffset(m_maxColumnHeight);
        m_computedColumnHeight = 0; // Restart balancing.
    } else {
        setAndConstrainColumnHeight(heightAdjustedForSetOffset(multicolBlock->multiColumnFlowThread()->columnHeightAvailable()));
    }

    clearForcedBreaks();

    // Nuke previously stored minimum column height. Contents may have changed for all we know.
    m_minimumColumnHeight = 0;
}
void RenderMultiColumnFlowThread::flowThreadDescendantInserted(RenderObject* descendant)
{
    if (gShiftingSpanner || m_beingEvacuated || descendant->isInFlowRenderFlowThread())
        return;
    RenderObject* subtreeRoot = descendant;
    for (; descendant; descendant = (descendant ? descendant->nextInPreOrder(subtreeRoot) : nullptr)) {
        if (descendant->isRenderMultiColumnSpannerPlaceholder()) {
            // A spanner's placeholder has been inserted. The actual spanner renderer is moved from
            // where it would otherwise occur (if it weren't a spanner) to becoming a sibling of the
            // column sets.
            RenderMultiColumnSpannerPlaceholder* placeholder = toRenderMultiColumnSpannerPlaceholder(descendant);
            if (placeholder->flowThread() != this) {
                // This isn't our spanner! It shifted here from an ancestor multicolumn block. It's going to end up
                // becoming our spanner instead, but for it to do that we first have to nuke the original spanner,
                // and get the spanner content back into this flow thread.
                RenderBox* spanner = placeholder->spanner();

                // Get info for the move of the original content back into our flow thread.
                RenderBoxModelObject* placeholderParent = toRenderBoxModelObject(placeholder->parent());

                // We have to nuke the placeholder, since the ancestor already lost the mapping to it when
                // we shifted the placeholder down into this flow thread.
                RenderObject* placeholderNextSibling = placeholderParent->removeChild(*placeholder);

                // Get the ancestor multicolumn flow thread to clean up its mess.
                RenderBlockFlow* ancestorBlock = toRenderBlockFlow(spanner->parent());
                ancestorBlock->multiColumnFlowThread()->flowThreadRelativeWillBeRemoved(spanner);

                // Now move the original content into our flow thread. It will end up calling flowThreadDescendantInserted
                // on the new content only, and everything will get set up properly.
                ancestorBlock->moveChildTo(placeholderParent, spanner, placeholderNextSibling, true);

                // Advance descendant.
                descendant = placeholderNextSibling;

                // If the spanner was the subtree root, then we're done, since there is nothing else left to insert.
                if (!descendant)
                    return;

                // Now that we have done this, we can continue past the spanning content, since we advanced
                // descendant already.
                if (descendant)
                    descendant = descendant->previousInPreOrder(subtreeRoot);

                continue;
            }

            ASSERT(!m_spannerMap.get(placeholder->spanner()));
            m_spannerMap.add(placeholder->spanner(), placeholder);
            ASSERT(!placeholder->firstChild()); // There should be no children here, but if there are, we ought to skip them.
            continue;
        }
        RenderBlockFlow* multicolContainer = multiColumnBlockFlow();
        RenderObject* nextRendererInFlowThread = descendant->nextInPreOrderAfterChildren(this);
        RenderObject* insertBeforeMulticolChild = nullptr;
        if (isValidColumnSpanner(this, descendant)) {
            // This is a spanner (column-span:all). Such renderers are moved from where they would
            // otherwise occur in the render tree to becoming a direct child of the multicol container,
            // so that they live among the column sets. This simplifies the layout implementation, and
            // basically just relies on regular block layout done by the RenderBlockFlow that
            // establishes the multicol container.
            RenderBlockFlow* container = toRenderBlockFlow(descendant->parent());
            RenderMultiColumnSet* setToSplit = nullptr;
            if (nextRendererInFlowThread) {
                setToSplit = findSetRendering(descendant);
                if (setToSplit) {
                    setToSplit->setNeedsLayout();
                    insertBeforeMulticolChild = setToSplit->nextSibling();
                }
            }
            // Moving a spanner's renderer so that it becomes a sibling of the column sets requires us
            // to insert an anonymous placeholder in the tree where the spanner's renderer otherwise
            // would have been. This is needed for a two reasons: We need a way of separating inline
            // content before and after the spanner, so that it becomes separate line boxes. Secondly,
            // this placeholder serves as a break point for column sets, so that, when encountered, we
            // end flowing one column set and move to the next one.
            RenderMultiColumnSpannerPlaceholder* placeholder = RenderMultiColumnSpannerPlaceholder::createAnonymous(this, toRenderBox(descendant), &container->style());
            container->addChild(placeholder, descendant->nextSibling());
            container->removeChild(*descendant);

            // This is a guard to stop an ancestor flow thread from processing the spanner.
            gShiftingSpanner = true;
            multicolContainer->RenderBlock::addChild(descendant, insertBeforeMulticolChild);
            gShiftingSpanner = false;

            // The spanner has now been moved out from the flow thread, but we don't want to
            // examine its children anyway. They are all part of the spanner and shouldn't trigger
            // creation of column sets or anything like that. Continue at its original position in
            // the tree, i.e. where the placeholder was just put.
            if (subtreeRoot == descendant)
                subtreeRoot = placeholder;
            descendant = placeholder;
        } else {
            // This is regular multicol content, i.e. not part of a spanner.
            if (nextRendererInFlowThread && nextRendererInFlowThread->isRenderMultiColumnSpannerPlaceholder()) {
                // Inserted right before a spanner. Is there a set for us there?
                RenderMultiColumnSpannerPlaceholder* placeholder = toRenderMultiColumnSpannerPlaceholder(nextRendererInFlowThread);
                if (RenderObject* previous = placeholder->spanner()->previousSibling()) {
                    if (previous->isRenderMultiColumnSet())
                        continue; // There's already a set there. Nothing to do.
                }
                insertBeforeMulticolChild = placeholder->spanner();
            } else if (RenderMultiColumnSet* lastSet = lastMultiColumnSet()) {
                // This child is not an immediate predecessor of a spanner, which means that if this
                // child precedes a spanner at all, there has to be a column set created for us there
                // already. If it doesn't precede any spanner at all, on the other hand, we need a
                // column set at the end of the multicol container. We don't really check here if the
                // child inserted precedes any spanner or not (as that's an expensive operation). Just
                // make sure we have a column set at the end. It's no big deal if it remains unused.
                if (!lastSet->nextSibling())
                    continue;
            }
        }
        // Need to create a new column set when there's no set already created. We also always insert
        // another column set after a spanner. Even if it turns out that there are no renderers
        // following the spanner, there may be bottom margins there, which take up space.
        RenderMultiColumnSet* newSet = new RenderMultiColumnSet(*this, RenderStyle::createAnonymousStyleWithDisplay(&multicolContainer->style(), BLOCK));
        newSet->initializeStyle();
        multicolContainer->RenderBlock::addChild(newSet, insertBeforeMulticolChild);
        invalidateRegions();

        // We cannot handle immediate column set siblings at the moment (and there's no need for
        // it, either). There has to be at least one spanner separating them.
        ASSERT(!previousColumnSetOrSpannerSiblingOf(newSet) || !previousColumnSetOrSpannerSiblingOf(newSet)->isRenderMultiColumnSet());
        ASSERT(!nextColumnSetOrSpannerSiblingOf(newSet) || !nextColumnSetOrSpannerSiblingOf(newSet)->isRenderMultiColumnSet());
    }
}