Add a was-inserted-into-tree notification to RenderObject
authorjchaffraix@webkit.org <jchaffraix@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 16 Aug 2012 02:35:29 +0000 (02:35 +0000)
committerjchaffraix@webkit.org <jchaffraix@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 16 Aug 2012 02:35:29 +0000 (02:35 +0000)
https://bugs.webkit.org/show_bug.cgi?id=93874

Reviewed by Eric Seidel.

This change adds insertedIntoTree to RenderObject so that renderers
can now do their post-insertion task inside this function.

Our current architecture has 2 ways of doing post-insertion tasks:
- overriding RenderObject::addChild
- RenderObjectChildList::insertChildNode / appendChildNode

Because the former is not guaranteed to be called for each insertion
(on top of being called on the parent and not the inserted child), the
2 latter functions are the one that have been mostly used recently. This
led to code duplication between the functions but also doesn't scale as
other renderers need to hop on this notification and currently don't (for
example, table parts). The other renderer's migration will be done in
follow-up patches.

Refactoring covered by existing tests.

* rendering/RenderObjectChildList.cpp:
(WebCore::RenderObjectChildList::removeChildNode):
* rendering/RenderObject.cpp:
(WebCore::RenderObject::enclosingRenderNamedFlowThread):
Moved the code from renderNamedFlowThreadContainer to RenderObject::enclosingRenderNamedFlowThread.
This is needed as now 2 classes need to access the function.

* rendering/RenderObjectChildList.cpp:
(WebCore::RenderObjectChildList::appendChildNode):
(WebCore::RenderObjectChildList::insertChildNode):
Moved the code duplicated from those 2 functions into
the instances of insertedIntoTree below.

* rendering/RenderObject.cpp:
(WebCore::RenderObject::insertedIntoTree):
Base function that needs to be called from all the other
specialized functions below.

* rendering/RenderListItem.cpp:
(WebCore::RenderListItem::insertedIntoTree):
* rendering/RenderListItem.h:
* rendering/RenderObject.h:
* rendering/RenderObjectChildList.h:
* rendering/RenderRegion.cpp:
(WebCore::RenderRegion::insertedIntoTree):
* rendering/RenderRegion.h:
Added the overriden insertedIntoTree function.

* rendering/RenderQuote.h:
Moved the comment from RenderObjectChildList about RenderQuote here.

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

Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderListItem.cpp
Source/WebCore/rendering/RenderListItem.h
Source/WebCore/rendering/RenderObject.cpp
Source/WebCore/rendering/RenderObject.h
Source/WebCore/rendering/RenderObjectChildList.cpp
Source/WebCore/rendering/RenderObjectChildList.h
Source/WebCore/rendering/RenderQuote.h
Source/WebCore/rendering/RenderRegion.cpp
Source/WebCore/rendering/RenderRegion.h

index cb1852c..55ab6f8 100644 (file)
@@ -1,3 +1,58 @@
+2012-08-15  Julien Chaffraix  <jchaffraix@webkit.org>
+
+        Add a was-inserted-into-tree notification to RenderObject
+        https://bugs.webkit.org/show_bug.cgi?id=93874
+
+        Reviewed by Eric Seidel.
+
+        This change adds insertedIntoTree to RenderObject so that renderers
+        can now do their post-insertion task inside this function.
+
+        Our current architecture has 2 ways of doing post-insertion tasks:
+        - overriding RenderObject::addChild
+        - RenderObjectChildList::insertChildNode / appendChildNode
+
+        Because the former is not guaranteed to be called for each insertion
+        (on top of being called on the parent and not the inserted child), the
+        2 latter functions are the one that have been mostly used recently. This
+        led to code duplication between the functions but also doesn't scale as
+        other renderers need to hop on this notification and currently don't (for
+        example, table parts). The other renderer's migration will be done in
+        follow-up patches.
+
+        Refactoring covered by existing tests.
+
+        * rendering/RenderObjectChildList.cpp:
+        (WebCore::RenderObjectChildList::removeChildNode):
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::enclosingRenderNamedFlowThread):
+        Moved the code from renderNamedFlowThreadContainer to RenderObject::enclosingRenderNamedFlowThread.
+        This is needed as now 2 classes need to access the function.
+
+        * rendering/RenderObjectChildList.cpp:
+        (WebCore::RenderObjectChildList::appendChildNode):
+        (WebCore::RenderObjectChildList::insertChildNode):
+        Moved the code duplicated from those 2 functions into
+        the instances of insertedIntoTree below.
+
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::insertedIntoTree):
+        Base function that needs to be called from all the other
+        specialized functions below.
+
+        * rendering/RenderListItem.cpp:
+        (WebCore::RenderListItem::insertedIntoTree):
+        * rendering/RenderListItem.h:
+        * rendering/RenderObject.h:
+        * rendering/RenderObjectChildList.h:
+        * rendering/RenderRegion.cpp:
+        (WebCore::RenderRegion::insertedIntoTree):
+        * rendering/RenderRegion.h:
+        Added the overriden insertedIntoTree function.
+
+        * rendering/RenderQuote.h:
+        Moved the comment from RenderObjectChildList about RenderQuote here.
+
 2012-08-14  Jeffrey Pfau  <jpfau@apple.com>
 
         Allow blocking of Web SQL databases in third-party documents
index 2f7ff6e..f68d081 100644 (file)
@@ -76,6 +76,13 @@ void RenderListItem::willBeDestroyed()
     RenderBlock::willBeDestroyed();
 }
 
+void RenderListItem::insertedIntoTree()
+{
+    RenderBlock::insertedIntoTree();
+
+    updateListMarkerNumbers();
+}
+
 static bool isList(Node* node)
 {
     return (node->hasTagName(ulTag) || node->hasTagName(olTag));
index 3c0af2f..a1eda21 100644 (file)
@@ -58,6 +58,8 @@ private:
     
     virtual void willBeDestroyed();
 
+    virtual void insertedIntoTree() OVERRIDE;
+
     virtual bool isEmpty() const;
     virtual void paint(PaintInfo&, const LayoutPoint&);
 
index b5f6957..2e1ef38 100755 (executable)
@@ -586,6 +586,15 @@ RenderFlowThread* RenderObject::enclosingRenderFlowThread() const
     return 0;
 }
 
+RenderNamedFlowThread* RenderObject::enclosingRenderNamedFlowThread() const
+{
+    RenderObject* object = const_cast<RenderObject*>(this);
+    while (object && object->isAnonymousBlock() && !object->isRenderNamedFlowThread())
+        object = object->parent();
+
+    return object && object->isRenderNamedFlowThread() ? toRenderNamedFlowThread(object) : 0;
+}
+
 RenderBlock* RenderObject::firstLineBlock() const
 {
     return 0;
@@ -2354,6 +2363,34 @@ void RenderObject::willBeDestroyed()
     clearLayoutRootIfNeeded();
 }
 
+void RenderObject::insertedIntoTree()
+{
+    // FIXME: We should ASSERT(isRooted()) here but generated content makes some out-of-order insertion.
+
+    // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children
+    // and don't have a layer attached to ourselves.
+    RenderLayer* layer = 0;
+    if (firstChild() || hasLayer()) {
+        layer = parent()->enclosingLayer();
+        addLayers(layer);
+    }
+
+    // If |this| is visible but this object was not, tell the layer it has some visible content
+    // that needs to be drawn and layer visibility optimization can't be used
+    if (parent()->style()->visibility() != VISIBLE && style()->visibility() == VISIBLE && !hasLayer()) {
+        if (!layer)
+            layer = parent()->enclosingLayer();
+        if (layer)
+            layer->setHasVisibleContent();
+    }
+
+    if (!isFloating() && parent()->childrenInline())
+        parent()->dirtyLinesFromChangedChild(this);
+
+    if (RenderNamedFlowThread* containerFlowThread = parent()->enclosingRenderNamedFlowThread())
+        containerFlowThread->addFlowChild(this);
+}
+
 void RenderObject::destroyAndCleanupAnonymousWrappers()
 {
     RenderObject* parent = this->parent();
index 5ef90fc..cdadecb 100644 (file)
@@ -59,6 +59,7 @@ class RenderBlock;
 class RenderFlowThread;
 class RenderGeometryMap;
 class RenderLayer;
+class RenderNamedFlowThread;
 class RenderTable;
 class RenderTheme;
 class TransformState;
@@ -226,6 +227,8 @@ public:
     // Function to return our enclosing flow thread if we are contained inside one.
     RenderFlowThread* enclosingRenderFlowThread() const;
 
+    RenderNamedFlowThread* enclosingRenderNamedFlowThread() const;
+
     virtual bool isEmpty() const { return firstChild() == 0; }
 
 #ifndef NDEBUG
@@ -934,6 +937,8 @@ protected:
 
     virtual bool canBeReplacedWithInlineRunIn() const;
 
+    virtual void insertedIntoTree();
+
 private:
     RenderStyle* firstLineStyleSlowCase() const;
     StyleDifference adjustStyleDifference(StyleDifference, unsigned contextSensitiveProperties) const;
index 3158fbf..c4662f9 100644 (file)
@@ -63,14 +63,6 @@ void RenderObjectChildList::destroyLeftoverChildren()
     }
 }
 
-static RenderNamedFlowThread* renderNamedFlowThreadContainer(RenderObject* object)
-{
-    while (object && object->isAnonymousBlock() && !object->isRenderNamedFlowThread())
-        object = object->parent();
-
-    return object && object->isRenderNamedFlowThread() ? toRenderNamedFlowThread(object) : 0;
-}
-
 RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool fullRemove)
 {
     ASSERT(oldChild->parent() == owner);
@@ -126,7 +118,7 @@ RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, Render
             oldChild->enclosingRenderFlowThread()->clearRenderObjectCustomStyle(oldChild);
         }
 
-        if (RenderNamedFlowThread* containerFlowThread = renderNamedFlowThreadContainer(owner))
+        if (RenderNamedFlowThread* containerFlowThread = owner->enclosingRenderNamedFlowThread())
             containerFlowThread->removeFlowChild(oldChild);
 
 #if ENABLE(SVG)
@@ -169,7 +161,7 @@ RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, Render
     return oldChild;
 }
 
-void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* newChild, bool fullAppend)
+void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* newChild, bool notifyRenderer)
 {
     ASSERT(newChild->parent() == 0);
     ASSERT(!owner->isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));
@@ -185,40 +177,8 @@ void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* n
 
     setLastChild(newChild);
     
-    if (fullAppend) {
-        // Keep our layer hierarchy updated.  Optimize for the common case where we don't have any children
-        // and don't have a layer attached to ourselves.
-        RenderLayer* layer = 0;
-        if (newChild->firstChild() || newChild->hasLayer()) {
-            layer = owner->enclosingLayer();
-            newChild->addLayers(layer);
-        }
-
-        // if the new child is visible but this object was not, tell the layer it has some visible content
-        // that needs to be drawn and layer visibility optimization can't be used
-        if (owner->style()->visibility() != VISIBLE && newChild->style()->visibility() == VISIBLE && !newChild->hasLayer()) {
-            if (!layer)
-                layer = owner->enclosingLayer();
-            if (layer)
-                layer->setHasVisibleContent();
-        }
-
-        if (newChild->isListItem())
-            toRenderListItem(newChild)->updateListMarkerNumbers();
-
-        if (!newChild->isFloating() && owner->childrenInline())
-            owner->dirtyLinesFromChangedChild(newChild);
-
-        if (newChild->isRenderRegion())
-            toRenderRegion(newChild)->attachRegion();
-
-        // You can't attachQuote() otherwise the quote would be attached too early
-        // and get the wrong depth since generated content is inserted into anonymous
-        // renderers before going into the main render tree.
-
-        if (RenderNamedFlowThread* containerFlowThread = renderNamedFlowThreadContainer(owner))
-            containerFlowThread->addFlowChild(newChild);
-    }
+    if (notifyRenderer)
+        newChild->insertedIntoTree();
 
     if (!owner->documentBeingDestroyed()) {
         RenderCounter::rendererSubtreeAttached(newChild);
@@ -231,10 +191,10 @@ void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* n
         owner->document()->axObjectCache()->childrenChanged(owner);
 }
 
-void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* beforeChild, bool fullInsert)
+void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* beforeChild, bool notifyRenderer)
 {
     if (!beforeChild) {
-        appendChildNode(owner, child, fullInsert);
+        appendChildNode(owner, child, notifyRenderer);
         return;
     }
 
@@ -257,39 +217,8 @@ void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* c
 
     child->setParent(owner);
     
-    if (fullInsert) {
-        // Keep our layer hierarchy updated.  Optimize for the common case where we don't have any children
-        // and don't have a layer attached to ourselves.
-        RenderLayer* layer = 0;
-        if (child->firstChild() || child->hasLayer()) {
-            layer = owner->enclosingLayer();
-            child->addLayers(layer);
-        }
-
-        // if the new child is visible but this object was not, tell the layer it has some visible content
-        // that needs to be drawn and layer visibility optimization can't be used
-        if (owner->style()->visibility() != VISIBLE && child->style()->visibility() == VISIBLE && !child->hasLayer()) {
-            if (!layer)
-                layer = owner->enclosingLayer();
-            if (layer)
-                layer->setHasVisibleContent();
-        }
-
-        if (child->isListItem())
-            toRenderListItem(child)->updateListMarkerNumbers();
-
-        if (!child->isFloating() && owner->childrenInline())
-            owner->dirtyLinesFromChangedChild(child);
-
-        if (child->isRenderRegion())
-            toRenderRegion(child)->attachRegion();
-
-        // Calling attachQuote() here would be too early (before anonymous renderers are inserted)
-        // see appendChild() for more explanation.
-
-        if (RenderNamedFlowThread* containerFlowThread = renderNamedFlowThreadContainer(owner))
-            containerFlowThread->addFlowChild(child, beforeChild);
-    }
+    if (notifyRenderer)
+        child->insertedIntoTree();
 
     if (!owner->documentBeingDestroyed()) {
         RenderCounter::rendererSubtreeAttached(child);
index cfe9026..6583d51 100644 (file)
@@ -53,8 +53,8 @@ public:
     void destroyLeftoverChildren();
 
     RenderObject* removeChildNode(RenderObject* owner, RenderObject*, bool fullRemove = true);
-    void appendChildNode(RenderObject* owner, RenderObject*, bool fullAppend = true);
-    void insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* before, bool fullInsert = true);
+    void appendChildNode(RenderObject* owner, RenderObject*, bool notifyRenderer = true);
+    void insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* before, bool notifyRenderer = true);
 
     void updateBeforeAfterContent(RenderObject* owner, PseudoId type, const RenderObject* styledObject = 0);
     RenderObject* beforePseudoElementRenderer(const RenderObject* owner) const;
index 008b534..786f831 100644 (file)
@@ -44,6 +44,11 @@ private:
     virtual PassRefPtr<StringImpl> originalText() const OVERRIDE;
     virtual void computePreferredLogicalWidths(float leadWidth) OVERRIDE;
 
+    // We don't override insertedIntoTree to call attachQuote() as it would be attached
+    // too early and get the wrong depth since generated content is inserted into anonymous
+    // renderers before going into the main render tree. Once we can ensure that insertIntoTree,
+    // is called on an attached tree, we should override it here.
+
     const QuotesData* quotesData() const;
     void updateDepth();
     bool isAttached() { return m_attached; }
index 0682ac9..c2b50cb 100644 (file)
@@ -357,6 +357,13 @@ void RenderRegion::restoreRegionObjectsOriginalStyle()
     m_renderObjectRegionStyle.swap(temp);
 }
 
+void RenderRegion::insertedIntoTree()
+{
+    RenderReplaced::insertedIntoTree();
+
+    attachRegion();
+}
+
 PassRefPtr<RenderStyle> RenderRegion::computeStyleInRegion(const RenderObject* object)
 {
     ASSERT(object);
index 6093a9c..0817d48 100644 (file)
@@ -100,6 +100,8 @@ public:
 private:
     virtual const char* renderName() const { return "RenderRegion"; }
 
+    virtual void insertedIntoTree() OVERRIDE;
+
     PassRefPtr<RenderStyle> computeStyleInRegion(const RenderObject*);
     void computeChildrenStyleInRegion(const RenderObject*);
     void setRegionObjectsRegionStyle();