Move more multicolumn render tree mutation code to RenderTreeUpdater::MultiColumn
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 5 Oct 2017 17:59:49 +0000 (17:59 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 5 Oct 2017 17:59:49 +0000 (17:59 +0000)
https://bugs.webkit.org/show_bug.cgi?id=177942

Reviewed by Zalan Bujtas.

* rendering/RenderMultiColumnFlow.cpp:
(WebCore::RenderMultiColumnFlow::RenderMultiColumnFlow):

    Use std::unique_ptr for the spanner map for safe owenership transfer.

(WebCore::RenderMultiColumnFlow::fragmentedFlowDescendantInserted):
(WebCore::RenderMultiColumnFlow::handleSpannerRemoval):
(WebCore::RenderMultiColumnFlow::fragmentedFlowRelativeWillBeRemoved):
(WebCore::RenderMultiColumnFlow::populate): Deleted.
(WebCore::RenderMultiColumnFlow::evacuateAndDestroy): Deleted.

    This code moves to RenderTreeUpdater::MultiColumn.

* rendering/RenderMultiColumnFlow.h:
* style/RenderTreeUpdaterMultiColumn.cpp:
(WebCore::RenderTreeUpdater::MultiColumn::update):
(WebCore::RenderTreeUpdater::MultiColumn::createFragmentedFlow):
(WebCore::RenderTreeUpdater::MultiColumn::destroyFragmentedFlow):

    Use Hyatt's preferred 'fragmented flow' terminology.

* style/RenderTreeUpdaterMultiColumn.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@222920 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderMultiColumnFlow.cpp
Source/WebCore/rendering/RenderMultiColumnFlow.h
Source/WebCore/style/RenderTreeUpdaterMultiColumn.cpp
Source/WebCore/style/RenderTreeUpdaterMultiColumn.h

index c551887..c189e09 100644 (file)
@@ -1,3 +1,33 @@
+2017-10-05  Antti Koivisto  <antti@apple.com>
+
+        Move more multicolumn render tree mutation code to RenderTreeUpdater::MultiColumn
+        https://bugs.webkit.org/show_bug.cgi?id=177942
+
+        Reviewed by Zalan Bujtas.
+
+        * rendering/RenderMultiColumnFlow.cpp:
+        (WebCore::RenderMultiColumnFlow::RenderMultiColumnFlow):
+
+            Use std::unique_ptr for the spanner map for safe owenership transfer.
+
+        (WebCore::RenderMultiColumnFlow::fragmentedFlowDescendantInserted):
+        (WebCore::RenderMultiColumnFlow::handleSpannerRemoval):
+        (WebCore::RenderMultiColumnFlow::fragmentedFlowRelativeWillBeRemoved):
+        (WebCore::RenderMultiColumnFlow::populate): Deleted.
+        (WebCore::RenderMultiColumnFlow::evacuateAndDestroy): Deleted.
+
+            This code moves to RenderTreeUpdater::MultiColumn.
+
+        * rendering/RenderMultiColumnFlow.h:
+        * style/RenderTreeUpdaterMultiColumn.cpp:
+        (WebCore::RenderTreeUpdater::MultiColumn::update):
+        (WebCore::RenderTreeUpdater::MultiColumn::createFragmentedFlow):
+        (WebCore::RenderTreeUpdater::MultiColumn::destroyFragmentedFlow):
+
+            Use Hyatt's preferred 'fragmented flow' terminology.
+
+        * style/RenderTreeUpdaterMultiColumn.h:
+
 2017-10-05  Darin Adler  <darin@apple.com>
 
         Remove additional WebKitSystemInterface remnants
index 3ce7284..e07bf02 100644 (file)
@@ -40,6 +40,7 @@ bool RenderMultiColumnFlow::gShiftingSpanner = false;
 
 RenderMultiColumnFlow::RenderMultiColumnFlow(Document& document, RenderStyle&& style)
     : RenderFragmentedFlow(document, WTFMove(style))
+    , m_spannerMap(std::make_unique<SpannerMap>())
     , m_lastSetWorkedOn(nullptr)
     , m_columnCount(1)
     , m_columnWidth(0)
@@ -142,51 +143,6 @@ static RenderMultiColumnSet* findSetRendering(const RenderMultiColumnFlow& fragm
     return nullptr;
 }
 
-void RenderMultiColumnFlow::populate()
-{
-    RenderBlockFlow* 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 renderers (column
-    // sets and spanners) will be inserted there as we insert elements into the flow thread.
-    multicolContainer->moveChildrenTo(this, multicolContainer->firstChild(), this, true);
-    
-    if (multicolContainer->isFieldset()) {
-        // Keep legends out of the flow thread.
-        for (auto& box : childrenOfType<RenderBox>(*this)) {
-            if (box.isLegend())
-                moveChildTo(multicolContainer, &box, true);
-        }
-    }
-}
-
-void RenderMultiColumnFlow::evacuateAndDestroy()
-{
-    RenderBlockFlow* multicolContainer = multiColumnBlockFlow();
-    // Delete the line box tree.
-    deleteLines();
-    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;
-        auto takenSpanner = multicolContainer->takeChild(*spanner);
-        ASSERT(it->value.get());
-        if (RenderMultiColumnSpannerPlaceholder* placeholder = it->value.get()) {
-            RenderBlockFlow& originalContainer = downcast<RenderBlockFlow>(*placeholder->parent());
-            originalContainer.addChild(WTFMove(takenSpanner), placeholder);
-            placeholder->removeFromParentAndDestroy();
-        }
-        m_spannerMap.remove(it);
-    }
-
-    // Remove all sets.
-    while (RenderMultiColumnSet* columnSet = firstMultiColumnSet())
-        columnSet->removeFromParentAndDestroy();
-    
-    removeFromParentAndDestroy();
-}
-
 void RenderMultiColumnFlow::addFragmentToThread(RenderFragmentContainer* RenderFragmentContainer)
 {
     auto* columnSet = downcast<RenderMultiColumnSet>(RenderFragmentContainer);
@@ -416,7 +372,7 @@ void RenderMultiColumnFlow::fragmentedFlowDescendantInserted(RenderObject& newDe
                 
                 // 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.
-                placeholder.fragmentedFlow()->m_spannerMap.remove(spanner);
+                placeholder.fragmentedFlow()->spannerMap().remove(spanner);
 
                 spannersToDelete.append(placeholder.parent()->takeChild(placeholder));
 
@@ -427,8 +383,8 @@ void RenderMultiColumnFlow::fragmentedFlowDescendantInserted(RenderObject& newDe
                 continue;
             }
             
-            ASSERT(!m_spannerMap.get(placeholder.spanner()));
-            m_spannerMap.add(placeholder.spanner(), makeWeakPtr(placeholder));
+            ASSERT(!spannerMap().get(placeholder.spanner()));
+            spannerMap().add(placeholder.spanner(), makeWeakPtr(placeholder));
             ASSERT(!placeholder.firstChild()); // There should be no children here, but if there are, we ought to skip them.
             continue;
         }
@@ -439,7 +395,7 @@ void RenderMultiColumnFlow::fragmentedFlowDescendantInserted(RenderObject& newDe
 void RenderMultiColumnFlow::handleSpannerRemoval(RenderObject& spanner)
 {
     // The placeholder may already have been removed, but if it hasn't, do so now.
-    if (auto placeholder = m_spannerMap.take(&downcast<RenderBox>(spanner)))
+    if (auto placeholder = spannerMap().take(&downcast<RenderBox>(spanner)))
         placeholder->removeFromParentAndDestroy();
 
     if (RenderObject* next = spanner.nextSibling()) {
@@ -461,7 +417,7 @@ void RenderMultiColumnFlow::fragmentedFlowRelativeWillBeRemoved(RenderObject& re
         // keep the reference to the spanner, since the placeholder may be about to be re-inserted
         // in the tree.
         ASSERT(relative.isDescendantOf(this));
-        m_spannerMap.remove(downcast<RenderMultiColumnSpannerPlaceholder>(relative).spanner());
+        spannerMap().remove(downcast<RenderMultiColumnSpannerPlaceholder>(relative).spanner());
         return;
     }
     if (relative.style().columnSpan() == ColumnSpanAll) {
index a05c3c4..309afee 100644 (file)
@@ -43,23 +43,14 @@ public:
     RenderMultiColumnSet* firstMultiColumnSet() const;
     RenderMultiColumnSet* lastMultiColumnSet() const;
     RenderBox* firstColumnSetOrSpanner() const;
-    bool hasColumnSpanner() const { return !m_spannerMap.isEmpty(); }
+    bool hasColumnSpanner() const { return !m_spannerMap->isEmpty(); }
     static RenderBox* nextColumnSetOrSpannerSiblingOf(const RenderBox*);
     static RenderBox* previousColumnSetOrSpannerSiblingOf(const RenderBox*);
 
-    RenderMultiColumnSpannerPlaceholder* findColumnSpannerPlaceholder(RenderBox* spanner) const { return m_spannerMap.get(spanner).get(); }
+    RenderMultiColumnSpannerPlaceholder* findColumnSpannerPlaceholder(RenderBox* spanner) const { return m_spannerMap->get(spanner).get(); }
 
     void layout() override;
 
-    // Populate the flow thread with what's currently its siblings. Called when a regular block
-    // becomes a multicol container.
-    void populate();
-
-    // Empty the flow thread by moving everything to the parent. Remove all multicol specific
-    // renderers. Then destroy the flow thread. Called when a multicol container becomes a regular
-    // block.
-    void evacuateAndDestroy();
-
     unsigned columnCount() const { return m_columnCount; }
     LayoutUnit columnWidth() const { return m_columnWidth; }
     LayoutUnit columnHeightAvailable() const { return m_columnHeightAvailable; }
@@ -105,6 +96,9 @@ public:
     // FIXME: Eventually as column and fragment flow threads start nesting, this will end up changing.
     bool shouldCheckColumnBreaks() const override;
 
+    typedef HashMap<RenderBox*, WeakPtr<RenderMultiColumnSpannerPlaceholder>> SpannerMap;
+    std::unique_ptr<SpannerMap> takeSpannerMap() { return WTFMove(m_spannerMap); }
+
 private:
     bool isRenderMultiColumnFlow() const override { return true; }
     const char* renderName() const override;
@@ -125,10 +119,11 @@ private:
 
     void handleSpannerRemoval(RenderObject& spanner);
     RenderObject* processPossibleSpannerDescendant(RenderObject*& subtreeRoot, RenderObject& descendant);
+
+    SpannerMap& spannerMap() { return *m_spannerMap; }
     
 private:
-    typedef HashMap<RenderBox*, WeakPtr<RenderMultiColumnSpannerPlaceholder>> SpannerMap;
-    SpannerMap m_spannerMap;
+    std::unique_ptr<SpannerMap> m_spannerMap;
 
     // The last set we worked on. It's not to be used as the "current set". The concept of a
     // "current set" is difficult, since layout may jump back and forth in the tree, due to wrong
index 644e8f9..677ab1e 100644 (file)
 #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());
-    auto* multiColumnFlow = flow.multiColumnFlow();
-    if (!needsFragmentedFlow) {
-        if (multiColumnFlow) {
-            flow.clearMultiColumnFlow();
-            multiColumnFlow->evacuateAndDestroy();
-            ASSERT(!flow.multiColumnFlow());
-        }
+    bool hasFragmentedFlow = flow.multiColumnFlow();
+
+    if (!hasFragmentedFlow && needsFragmentedFlow) {
+        createFragmentedFlow(flow);
+        return;
+    }
+    if (hasFragmentedFlow && !needsFragmentedFlow) {
+        destroyFragmentedFlow(flow);
         return;
     }
-    if (!multiColumnFlow)
-        createFragmentedFlow(flow);
 }
 
 void RenderTreeUpdater::MultiColumn::createFragmentedFlow(RenderBlockFlow& flow)
@@ -53,9 +55,42 @@ void RenderTreeUpdater::MultiColumn::createFragmentedFlow(RenderBlockFlow& flow)
     flow.deleteLines();
     auto& fragmentedFlow = *newFragmentedFlow;
     flow.RenderBlock::addChild(WTFMove(newFragmentedFlow));
-    fragmentedFlow.populate(); // Called after the flow thread is inserted so that we are reachable by the flow thread.
+
+    // Reparent children preceding the fragmented flow into the fragmented flow.
+    flow.moveChildrenTo(&fragmentedFlow, flow.firstChild(), &fragmentedFlow, true);
+    if (flow.isFieldset()) {
+        // Keep legends out of the flow thread.
+        for (auto& box : childrenOfType<RenderBox>(fragmentedFlow)) {
+            if (box.isLegend())
+                fragmentedFlow.moveChildTo(&flow, &box, true);
+        }
+    }
+
     flow.setMultiColumnFlow(fragmentedFlow);
 }
 
+void RenderTreeUpdater::MultiColumn::destroyFragmentedFlow(RenderBlockFlow& flow)
+{
+    auto& fragmentedFlow = *flow.multiColumnFlow();
+    flow.clearMultiColumnFlow();
+
+    fragmentedFlow.deleteLines();
+    fragmentedFlow.moveAllChildrenTo(&flow, true);
+
+    // Move spanners back to their original DOM position in the tree, and destroy the placeholders.
+    auto spannerMap = fragmentedFlow.takeSpannerMap();
+    for (auto& spannerAndPlaceholder : *spannerMap) {
+        RenderBox& spanner = *spannerAndPlaceholder.key;
+        auto& placeholder = *spannerAndPlaceholder.value;
+        auto takenSpanner = flow.takeChild(spanner);
+        placeholder.parent()->addChild(WTFMove(takenSpanner), &placeholder);
+        placeholder.removeFromParentAndDestroy();
+    }
+
+    while (auto* columnSet = fragmentedFlow.firstMultiColumnSet())
+        columnSet->removeFromParentAndDestroy();
+
+    fragmentedFlow.removeFromParentAndDestroy();
+}
 
 }
index 5cad599..69716a3 100644 (file)
@@ -37,6 +37,7 @@ public:
 
 private:
     static void createFragmentedFlow(RenderBlockFlow&);
+    static void destroyFragmentedFlow(RenderBlockFlow&);
 };
 
 }