2011-04-15 Roland Steiner <rolandsteiner@chromium.org>
authorrolandsteiner@chromium.org <rolandsteiner@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 15 Apr 2011 23:47:24 +0000 (23:47 +0000)
committerrolandsteiner@chromium.org <rolandsteiner@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 15 Apr 2011 23:47:24 +0000 (23:47 +0000)
        Reviewed by Dimitri Glazkov.

        Bug 52963 - Enable O(1) access to root from any node in shadow DOM subtree
        https://bugs.webkit.org/show_bug.cgi?id=52963

        .) Change base class of ShadowRoot from DocumentFragment to TreeScope.
        .) Re-enable tree scope handling in Node (had ASSERT_NOT_REACHED, etc.).
        .) Merged setTreeScope() with setTreeScopeRecursively()
        .) Call setTreeScopeRecursively in DOM manipulation functions where applicable.

        No new tests. (refactoring)

        * dom/ContainerNode.cpp:
        (WebCore::ContainerNode::takeAllChildrenFrom):
        (WebCore::ContainerNode::removeBetween):
        (WebCore::ContainerNode::removeChildren):
        (WebCore::ContainerNode::parserAddChild):
        * dom/Document.cpp:
        (WebCore::Document::Document):
        (WebCore::Document::~Document):
        (WebCore::Document::setDocType):
        * dom/Element.h:
        * dom/Node.cpp:
        (WebCore::Node::treeScope):
        (WebCore::Node::setTreeScopeRecursively):
        * dom/Node.h:
        (WebCore::Node::document):
        * dom/ShadowRoot.cpp:
        (WebCore::ShadowRoot::ShadowRoot):
        (WebCore::ShadowRoot::~ShadowRoot):
        (WebCore::ShadowRoot::nodeType):
        (WebCore::ShadowRoot::cloneNode):
        (WebCore::ShadowRoot::childTypeAllowed):
        * dom/ShadowRoot.h:
        (WebCore::toShadowRoot):
        * dom/TreeScope.cpp:
        (WebCore::TreeScope::TreeScope):
        (WebCore::TreeScope::setParentTreeScope):
        * dom/TreeScope.h:
        * rendering/RenderSlider.cpp:

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

Source/WebCore/ChangeLog
Source/WebCore/dom/ContainerNode.cpp
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Element.h
Source/WebCore/dom/Node.cpp
Source/WebCore/dom/Node.h
Source/WebCore/dom/ShadowRoot.cpp
Source/WebCore/dom/ShadowRoot.h
Source/WebCore/dom/TreeScope.cpp
Source/WebCore/dom/TreeScope.h
Source/WebCore/rendering/RenderSlider.cpp

index a59d569..0d09180 100644 (file)
@@ -1,3 +1,46 @@
+2011-04-15  Roland Steiner  <rolandsteiner@chromium.org>
+
+        Reviewed by Dimitri Glazkov.
+
+        Bug 52963 - Enable O(1) access to root from any node in shadow DOM subtree
+        https://bugs.webkit.org/show_bug.cgi?id=52963
+
+        .) Change base class of ShadowRoot from DocumentFragment to TreeScope.
+        .) Re-enable tree scope handling in Node (had ASSERT_NOT_REACHED, etc.).
+        .) Merged setTreeScope() with setTreeScopeRecursively()
+        .) Call setTreeScopeRecursively in DOM manipulation functions where applicable.
+
+        No new tests. (refactoring)
+
+        * dom/ContainerNode.cpp:
+        (WebCore::ContainerNode::takeAllChildrenFrom):
+        (WebCore::ContainerNode::removeBetween):
+        (WebCore::ContainerNode::removeChildren):
+        (WebCore::ContainerNode::parserAddChild):
+        * dom/Document.cpp:
+        (WebCore::Document::Document):
+        (WebCore::Document::~Document):
+        (WebCore::Document::setDocType):
+        * dom/Element.h:
+        * dom/Node.cpp:
+        (WebCore::Node::treeScope):
+        (WebCore::Node::setTreeScopeRecursively):
+        * dom/Node.h:
+        (WebCore::Node::document):
+        * dom/ShadowRoot.cpp:
+        (WebCore::ShadowRoot::ShadowRoot):
+        (WebCore::ShadowRoot::~ShadowRoot):
+        (WebCore::ShadowRoot::nodeType):
+        (WebCore::ShadowRoot::cloneNode):
+        (WebCore::ShadowRoot::childTypeAllowed):
+        * dom/ShadowRoot.h:
+        (WebCore::toShadowRoot):
+        * dom/TreeScope.cpp:
+        (WebCore::TreeScope::TreeScope):
+        (WebCore::TreeScope::setParentTreeScope):
+        * dom/TreeScope.h:
+        * rendering/RenderSlider.cpp:
+
 2011-04-15  Geoffrey Garen  <ggaren@apple.com>
 
         Reviewed by Oliver Hunt.
index 9efc838..e47cf3f 100644 (file)
@@ -90,6 +90,10 @@ void ContainerNode::takeAllChildrenFrom(ContainerNode* oldParent)
         RefPtr<Node> child = document()->adoptNode(children[i].release(), ec);
         ASSERT(!ec);
         parserAddChild(child.get());
+        // FIXME: Together with adoptNode above, the tree scope might get updated recursively twice
+        // (if the document changed or oldParent was in a shadow tree, AND *this is in a shadow tree).
+        // Can we do better?
+        child->setTreeScopeRecursively(treeScope());
         if (attached() && !child->attached())
             child->attach();
     }
@@ -481,6 +485,8 @@ void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node* ol
     oldChild->setNextSibling(0);
     oldChild->setParent(0);
 
+    oldChild->setTreeScopeRecursively(document());
+
     allowEventDispatch();
 }
 
@@ -530,6 +536,7 @@ void ContainerNode::removeChildren()
         n->setPreviousSibling(0);
         n->setNextSibling(0);
         n->setParent(0);
+        n->setTreeScopeRecursively(document());
 
         m_firstChild = next;
         if (n == m_lastChild)
@@ -648,6 +655,8 @@ void ContainerNode::parserAddChild(PassRefPtr<Node> newChild)
     Node* last = m_lastChild;
     // FIXME: This method should take a PassRefPtr.
     appendChildToContainer<Node, ContainerNode>(newChild.get(), this);
+    newChild->setTreeScopeRecursively(treeScope());
+    
     allowEventDispatch();
 
     // FIXME: Why doesn't this use notifyChildInserted(newChild) instead?
index 64082e3..b3f230f 100644 (file)
@@ -377,7 +377,7 @@ private:
 uint64_t Document::s_globalTreeVersion = 0;
 
 Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
-    : TreeScope(this)
+    : TreeScope(0)
     , m_guardRefCount(0)
     , m_compatibilityMode(NoQuirksMode)
     , m_compatibilityModeLocked(false)
@@ -434,6 +434,7 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
     , m_writeRecursionIsTooDeep(false)
     , m_writeRecursionDepth(0)
 {
+
     m_document = this;
 
     m_pageGroupUserSheetCacheValid = false;
@@ -514,6 +515,7 @@ Document::~Document()
     ASSERT(m_ranges.isEmpty());
     ASSERT(!m_styleRecalcTimer.isActive());
     ASSERT(!m_parentTreeScope);
+    ASSERT(!m_guardRefCount);
 
     m_scriptRunner.clear();
 
@@ -665,7 +667,7 @@ void Document::setDocType(PassRefPtr<DocumentType> docType)
     ASSERT(!m_docType || !docType);
     m_docType = docType;
     if (m_docType)
-        m_docType->setTreeScope(this);
+        m_docType->setTreeScopeRecursively(this);
 }
 
 DOMImplementation* Document::implementation()
index d269dbe..0af6d97 100644 (file)
@@ -39,6 +39,7 @@ class DOMStringMap;
 class DOMTokenList;
 class ElementRareData;
 class IntSize;
+class ShadowRoot;
 class WebKitAnimationList;
 
 enum SpellcheckAttributeState {
@@ -229,6 +230,7 @@ public:
     virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
     virtual void recalcStyle(StyleChange = NoChange);
 
+    // FIXME: Make these return a proper ShadowRoot* (bug 58703).
     ContainerNode* shadowRoot() const;
     ContainerNode* ensureShadowRoot();
     void removeShadowRoot();
index 8ac2adc..8ca18cb 100644 (file)
@@ -77,6 +77,7 @@
 #include "ScopedEventQueue.h"
 #include "ScriptController.h"
 #include "SelectorNodeList.h"
+#include "ShadowRoot.h"
 #include "StaticNodeList.h"
 #include "TagNodeList.h"
 #include "Text.h"
@@ -468,39 +469,22 @@ void Node::setDocument(Document* document)
 
 TreeScope* Node::treeScope() const
 {
+    // FIXME: Using m_document directly is not good -> see comment with document() in the header file.
     if (!hasRareData())
-        return document();
+        return m_document;
     TreeScope* scope = rareData()->treeScope();
-    // FIXME: Until we land shadow scopes, there should be no non-document scopes.
-    ASSERT(!scope);
-    return scope ? scope : document();
+    return scope ? scope : m_document;
 }
 
-void Node::setTreeScope(TreeScope* newTreeScope)
+void Node::setTreeScopeRecursively(TreeScope* newTreeScope, bool includeRoot)
 {
-    ASSERT(!isDocumentNode());
+    ASSERT(this);
+    ASSERT(!includeRoot || !isDocumentNode());
     ASSERT(newTreeScope);
-    ASSERT(!inDocument() || treeScope() == newTreeScope);
+    ASSERT(!m_deletionHasBegun);
 
-    if (newTreeScope->isDocumentNode()) {
-        if (hasRareData())
-            rareData()->setTreeScope(0);
-        // Setting the new document scope will be handled implicitly
-        // by setDocument() below.
-    } else {
-        // FIXME: Until we land shadow scopes, this branch should be inert.
-        ASSERT_NOT_REACHED();
-        ensureRareData()->setTreeScope(newTreeScope);
-    }
-
-    setDocument(newTreeScope->document());
-}
-
-void Node::setTreeScopeRecursively(TreeScope* newTreeScope)
-{
-    ASSERT(!isDocumentNode());
-    ASSERT(newTreeScope);
-    if (treeScope() == newTreeScope)
+    TreeScope* currentTreeScope = treeScope();
+    if (currentTreeScope == newTreeScope)
         return;
 
     Document* currentDocument = document();
@@ -512,9 +496,25 @@ void Node::setTreeScopeRecursively(TreeScope* newTreeScope)
     if (currentDocument && currentDocument != newDocument)
         currentDocument->incDOMTreeVersion();
 
-    for (Node* node = this; node; node = node->traverseNextNode(this)) {
-        node->setTreeScope(newTreeScope);
-        // FIXME: Once shadow scopes are landed, update parent scope, etc.
+    for (Node* node = includeRoot ? this : traverseNextNode(this); node; node = node->traverseNextNode(this)) {
+        if (newTreeScope == newDocument) {
+            if (node->hasRareData())
+                node->rareData()->setTreeScope(0);
+            // Setting the new document tree scope will be handled implicitly
+            // by setDocument() below.
+        } else
+            node->ensureRareData()->setTreeScope(newTreeScope);
+
+        node->setDocument(newDocument);
+
+        if (!node->isElementNode())
+            continue;
+        // FIXME: Remove toShadowRoot() once shadowRoot() returns a proper ShadowRoot* (bug 58703).
+        if (ShadowRoot* shadowRoot = toShadowRoot(toElement(node)->shadowRoot())) {
+            shadowRoot->setParentTreeScope(newTreeScope);
+            if (currentDocument != newDocument)
+                shadowRoot->setDocumentRecursively(newDocument);
+        }
     }
 }
 
index c3b9203..f33681e 100644 (file)
@@ -352,18 +352,16 @@ public:
     Document* document() const
     {
         ASSERT(this);
+        // FIXME: below ASSERT is useful, but prevents the use of document() in the constructor or destructor
+        // due to the virtual function call to nodeType().
         ASSERT(m_document || (nodeType() == DOCUMENT_TYPE_NODE && !inDocument()));
         return m_document;
     }
 
     TreeScope* treeScope() const;
 
-    // Do not use this method to change the scope of a node until after the node has been
-    // removed from its previous scope. Do not use to change documents.
-    void setTreeScope(TreeScope*);
-
     // Used by the basic DOM methods (e.g., appendChild()).
-    void setTreeScopeRecursively(TreeScope*);
+    void setTreeScopeRecursively(TreeScope*, bool includeRoot = true);
 
     // Returns true if this node is associated with a document and is in its associated document's
     // node tree, false otherwise.
index 8fe56b5..e54767e 100644 (file)
 #include "config.h"
 #include "ShadowRoot.h"
 
+#include "Document.h"
+#include "NodeRareData.h"
+
 namespace WebCore {
 
 ShadowRoot::ShadowRoot(Document* document)
-    : DocumentFragment(document)
+    : TreeScope(document)
 {
     ASSERT(document);
+    
+    // Assume document as parent scope.
+    setParentTreeScope(document);
+    // Shadow tree scopes have the scope pointer point to themselves.
+    // This way, direct children will receive the correct scope pointer.
+    ensureRareData()->setTreeScope(this);
+}
+
+ShadowRoot::~ShadowRoot()
+{
 }
 
 String ShadowRoot::nodeName() const
@@ -40,6 +53,33 @@ String ShadowRoot::nodeName() const
     return "#shadow-root";
 }
 
+Node::NodeType ShadowRoot::nodeType() const
+{
+    // FIXME: Decide correct node type (bug 58704).
+    return DOCUMENT_FRAGMENT_NODE;
+}
+
+PassRefPtr<Node> ShadowRoot::cloneNode(bool)
+{
+    // ShadowRoot should not be arbitrarily cloned.
+    return 0;
+}
+
+bool ShadowRoot::childTypeAllowed(NodeType type) const
+{
+    switch (type) {
+    case ELEMENT_NODE:
+    case PROCESSING_INSTRUCTION_NODE:
+    case COMMENT_NODE:
+    case TEXT_NODE:
+    case CDATA_SECTION_NODE:
+    case ENTITY_REFERENCE_NODE:
+        return true;
+    default:
+        return false;
+    }
+}
+
 void ShadowRoot::recalcStyle(StyleChange change)
 {
     for (Node* n = firstChild(); n; n = n->nextSibling())
index aeccd8a..db51b2b 100644 (file)
 #ifndef ShadowRoot_h
 #define ShadowRoot_h
 
-#include "DocumentFragment.h"
+#include "TreeScope.h"
 
 namespace WebCore {
 
 class Document;
 
-class ShadowRoot : public DocumentFragment {
+class ShadowRoot : public TreeScope {
 public:
     static PassRefPtr<ShadowRoot> create(Document*);
 
@@ -42,7 +42,12 @@ public:
 
 private:
     ShadowRoot(Document*);
+    virtual ~ShadowRoot();
+
     virtual String nodeName() const;
+    virtual NodeType nodeType() const;
+    virtual PassRefPtr<Node> cloneNode(bool deep);
+    virtual bool childTypeAllowed(NodeType) const;
 };
 
 inline PassRefPtr<ShadowRoot> ShadowRoot::create(Document* document)
@@ -50,6 +55,12 @@ inline PassRefPtr<ShadowRoot> ShadowRoot::create(Document* document)
     return adoptRef(new ShadowRoot(document));
 }
 
+inline ShadowRoot* toShadowRoot(Node* node)
+{
+    ASSERT(!node || node->isShadowBoundary());
+    return static_cast<ShadowRoot*>(node);
+}
+
 } // namespace
 
 #endif
index a995a2d..c8dc07e 100644 (file)
@@ -36,19 +36,12 @@ namespace WebCore {
 
 using namespace HTMLNames;
 
-TreeScope::TreeScope(Document* document, ConstructionType constructionType)
-    : ContainerNode(0, constructionType)
+TreeScope::TreeScope(Document* document)
+    : ContainerNode(document)
     , m_parentTreeScope(0)
     , m_accessKeyMapValid(false)
     , m_numNodeListCaches(0)
 {
-    m_document = document;
-    if (document != this) {
-        // Assume document as parent scope
-        m_parentTreeScope = document;
-        // FIXME: This branch should be inert until shadow scopes are landed.
-        ASSERT_NOT_REACHED();
-    }
 }
 
 TreeScope::~TreeScope()
@@ -69,7 +62,6 @@ void TreeScope::setParentTreeScope(TreeScope* newParentScope)
     // A document node cannot be re-parented.
     ASSERT(!isDocumentNode());
     // Every scope other than document needs a parent scope.
-    ASSERT(m_parentTreeScope);
     ASSERT(newParentScope);
 
     m_parentTreeScope = newParentScope;
index 6271541..1f90a09 100644 (file)
@@ -39,6 +39,7 @@ class TreeScope : public ContainerNode {
 
 public:
     TreeScope* parentTreeScope() const { return m_parentTreeScope; }
+    void setParentTreeScope(TreeScope*);
 
     Element* getElementById(const AtomicString&) const;
     bool hasElementWithId(AtomicStringImpl* id) const;
@@ -65,14 +66,11 @@ public:
     Element* findAnchor(const String& name);
 
 protected:
-    TreeScope(Document*, ConstructionType = CreateContainer);
-
+    TreeScope(Document*);
     virtual ~TreeScope();
 
     void destroyTreeScopeData();
 
-    void setParentTreeScope(TreeScope*);
-
 private:
     TreeScope* m_parentTreeScope;
 
index ad5ab1a..07d325e 100644 (file)
@@ -37,7 +37,7 @@
 #include "RenderLayer.h"
 #include "RenderTheme.h"
 #include "RenderView.h"
-#include "ShadowElement.h"
+#include "ShadowRoot.h"
 #include "SliderThumbElement.h"
 #include "StepRange.h"
 #include <wtf/MathExtras.h>