RenderTreeUpdaterMultiColumn.cpp [plain text]
#include "config.h"
#include "RenderTreeUpdaterMultiColumn.h"
#include "RenderBlockFlow.h"
#include "RenderChildIterator.h"
#include "RenderMultiColumnFlow.h"
#include "RenderMultiColumnSet.h"
#include "RenderMultiColumnSpannerPlaceholder.h"
namespace WebCore {
void RenderTreeUpdater::MultiColumn::update(RenderBlockFlow& flow)
{
bool needsFragmentedFlow = flow.requiresColumns(flow.style().columnCount());
bool hasFragmentedFlow = flow.multiColumnFlow();
if (!hasFragmentedFlow && needsFragmentedFlow) {
createFragmentedFlow(flow);
return;
}
if (hasFragmentedFlow && !needsFragmentedFlow) {
destroyFragmentedFlow(flow);
return;
}
}
void RenderTreeUpdater::MultiColumn::createFragmentedFlow(RenderBlockFlow& flow)
{
flow.setChildrenInline(false); flow.deleteLines();
auto* enclosingflow = flow.enclosingFragmentedFlow();
if (is<RenderMultiColumnFlow>(enclosingflow)) {
auto& spanners = downcast<RenderMultiColumnFlow>(enclosingflow)->spannerMap();
Vector<RenderMultiColumnSpannerPlaceholder*> placeholdersToDelete;
for (auto& spannerAndPlaceholder : spanners) {
auto& placeholder = *spannerAndPlaceholder.value;
if (!placeholder.isDescendantOf(&flow))
continue;
placeholdersToDelete.append(&placeholder);
}
for (auto* placeholder : placeholdersToDelete) {
auto* spanner = placeholder->spanner();
if (!spanner) {
ASSERT_NOT_REACHED();
continue;
}
auto& spannerOriginalParent = *placeholder->parent();
auto spannerToReInsert = spanner->parent()->takeChild(*spanner);
spannerOriginalParent.addChild(WTFMove(spannerToReInsert));
}
}
auto newFragmentedFlow = WebCore::createRenderer<RenderMultiColumnFlow>(flow.document(), RenderStyle::createAnonymousStyleWithDisplay(flow.style(), BLOCK));
newFragmentedFlow->initializeStyle();
auto& fragmentedFlow = *newFragmentedFlow;
flow.RenderBlock::addChild(WTFMove(newFragmentedFlow));
flow.moveChildrenTo(&fragmentedFlow, flow.firstChild(), &fragmentedFlow, RenderBoxModelObject::NormalizeAfterInsertion::Yes);
if (flow.isFieldset()) {
for (auto& box : childrenOfType<RenderBox>(fragmentedFlow)) {
if (box.isLegend())
fragmentedFlow.moveChildTo(&flow, &box, RenderBoxModelObject::NormalizeAfterInsertion::Yes);
}
}
flow.setMultiColumnFlow(fragmentedFlow);
}
void RenderTreeUpdater::MultiColumn::destroyFragmentedFlow(RenderBlockFlow& flow)
{
auto& multiColumnFlow = *flow.multiColumnFlow();
multiColumnFlow.deleteLines();
auto& spanners = multiColumnFlow.spannerMap();
Vector<RenderMultiColumnSpannerPlaceholder*> placeholdersToDelete;
for (auto& spannerAndPlaceholder : spanners)
placeholdersToDelete.append(spannerAndPlaceholder.value.get());
Vector<std::pair<RenderElement*, RenderPtr<RenderObject>>> parentAndSpannerList;
for (auto* placeholder : placeholdersToDelete) {
auto* spannerOriginalParent = placeholder->parent();
if (spannerOriginalParent == &multiColumnFlow)
spannerOriginalParent = &flow;
auto* spanner = placeholder->spanner();
parentAndSpannerList.append(std::make_pair(spannerOriginalParent, spanner->parent()->takeChild(*spanner)));
}
while (auto* columnSet = multiColumnFlow.firstMultiColumnSet())
columnSet->removeFromParentAndDestroy();
flow.clearMultiColumnFlow();
multiColumnFlow.moveAllChildrenTo(&flow, RenderBoxModelObject::NormalizeAfterInsertion::Yes);
multiColumnFlow.removeFromParentAndDestroy();
for (auto& parentAndSpanner : parentAndSpannerList)
parentAndSpanner.first->addChild(WTFMove(parentAndSpanner.second));
}
}