Change class hierarycy so that ShadowRoot can inherit DocumentFragment.
authorhayato@chromium.org <hayato@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 2 Feb 2012 04:21:29 +0000 (04:21 +0000)
committerhayato@chromium.org <hayato@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 2 Feb 2012 04:21:29 +0000 (04:21 +0000)
https://bugs.webkit.org/show_bug.cgi?id=76693

Reviewed by Darin Adler.

Make ShadowRoot inherit DocumentFragment so that it matches the class hierarchy of IDL in the spec.
TreeScope becomes a separated class, which is now inherited by Document and ShadowRoot using multiple-inheritance.
This patch is pre-requirement for coming IDL change.

No tests. No change in behavior.

* dom/Document.cpp:
(WebCore::Document::Document):
(WebCore::Document::~Document):
(WebCore::Document::buildAccessKeyMap):
(WebCore::Document::childrenChanged):
(WebCore::Document::attach):
(WebCore::Document::detach):
* dom/Document.h:
(Document):
* dom/DocumentFragment.cpp:
(WebCore::DocumentFragment::DocumentFragment):
* dom/DocumentFragment.h:
(DocumentFragment):
* dom/DocumentOrderedMap.cpp:
(WebCore::DocumentOrderedMap::get):
* dom/ShadowRoot.cpp:
(WebCore::ShadowRoot::ShadowRoot):
(WebCore::ShadowRoot::~ShadowRoot):
(WebCore::ShadowRoot::attach):
* dom/ShadowRoot.h:
* dom/TreeScope.cpp:
(WebCore::TreeScope::TreeScope):
(WebCore::TreeScope::~TreeScope):
(WebCore::TreeScope::setParentTreeScope):
(WebCore::TreeScope::getImageMap):
(WebCore::TreeScope::findAnchor):
* dom/TreeScope.h:
(WebCore):
(WebCore::TreeScope::rootNode):
(TreeScope):
* dom/TreeScopeAdopter.cpp:
(WebCore::TreeScopeAdopter::moveTreeToNewScope):
* page/DragController.cpp:
(WebCore::asFileInput):
* page/FocusController.cpp:
(WebCore::ownerOfTreeScope):
(WebCore::FocusController::nextFocusableNode):
(WebCore::FocusController::previousFocusableNode):

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

13 files changed:
Source/WebCore/ChangeLog
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/DocumentFragment.cpp
Source/WebCore/dom/DocumentFragment.h
Source/WebCore/dom/DocumentOrderedMap.cpp
Source/WebCore/dom/ShadowRoot.cpp
Source/WebCore/dom/ShadowRoot.h
Source/WebCore/dom/TreeScope.cpp
Source/WebCore/dom/TreeScope.h
Source/WebCore/dom/TreeScopeAdopter.cpp
Source/WebCore/page/DragController.cpp
Source/WebCore/page/FocusController.cpp

index ac4ac8b..1a4116c 100644 (file)
@@ -1,3 +1,55 @@
+2012-02-01  Hayato Ito  <hayato@chromium.org>
+
+        Change class hierarycy so that ShadowRoot can inherit DocumentFragment.
+        https://bugs.webkit.org/show_bug.cgi?id=76693
+
+        Reviewed by Darin Adler.
+
+        Make ShadowRoot inherit DocumentFragment so that it matches the class hierarchy of IDL in the spec.
+        TreeScope becomes a separated class, which is now inherited by Document and ShadowRoot using multiple-inheritance.
+        This patch is pre-requirement for coming IDL change.
+
+        No tests. No change in behavior.
+
+        * dom/Document.cpp:
+        (WebCore::Document::Document):
+        (WebCore::Document::~Document):
+        (WebCore::Document::buildAccessKeyMap):
+        (WebCore::Document::childrenChanged):
+        (WebCore::Document::attach):
+        (WebCore::Document::detach):
+        * dom/Document.h:
+        (Document):
+        * dom/DocumentFragment.cpp:
+        (WebCore::DocumentFragment::DocumentFragment):
+        * dom/DocumentFragment.h:
+        (DocumentFragment):
+        * dom/DocumentOrderedMap.cpp:
+        (WebCore::DocumentOrderedMap::get):
+        * dom/ShadowRoot.cpp:
+        (WebCore::ShadowRoot::ShadowRoot):
+        (WebCore::ShadowRoot::~ShadowRoot):
+        (WebCore::ShadowRoot::attach):
+        * dom/ShadowRoot.h:
+        * dom/TreeScope.cpp:
+        (WebCore::TreeScope::TreeScope):
+        (WebCore::TreeScope::~TreeScope):
+        (WebCore::TreeScope::setParentTreeScope):
+        (WebCore::TreeScope::getImageMap):
+        (WebCore::TreeScope::findAnchor):
+        * dom/TreeScope.h:
+        (WebCore):
+        (WebCore::TreeScope::rootNode):
+        (TreeScope):
+        * dom/TreeScopeAdopter.cpp:
+        (WebCore::TreeScopeAdopter::moveTreeToNewScope):
+        * page/DragController.cpp:
+        (WebCore::asFileInput):
+        * page/FocusController.cpp:
+        (WebCore::ownerOfTreeScope):
+        (WebCore::FocusController::nextFocusableNode):
+        (WebCore::FocusController::previousFocusableNode):
+
 2012-02-01  Benjamin Poulain  <bpoulain@apple.com>
 
         WorkerScriptController::evaluate() should not return anything
index 13d4501..3101e04 100644 (file)
@@ -373,7 +373,8 @@ private:
 uint64_t Document::s_globalTreeVersion = 0;
 
 Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
-    : TreeScope(0)
+    : ContainerNode(0)
+    , TreeScope(this)
     , m_guardRefCount(0)
     , m_compatibilityMode(NoQuirksMode)
     , m_compatibilityModeLocked(false)
@@ -571,6 +572,11 @@ Document::~Document()
 
     if (m_mediaQueryMatcher)
         m_mediaQueryMatcher->documentDestroyed();
+
+    // We must call clearRareData() here since a Document class inherits TreeScope
+    // as well as Node. See a comment on TreeScope.h for the reason.
+    if (hasRareData())
+        clearRareData();
 }
 
 void Document::removedLastRef()
@@ -642,16 +648,19 @@ Element* Document::getElementByAccessKey(const String& key)
     return m_elementsByAccessKey.get(key.impl());
 }
 
-void Document::buildAccessKeyMap(TreeScope* root)
+void Document::buildAccessKeyMap(TreeScope* scope)
 {
-     for (Node* n = root; n; n = n->traverseNextNode(root)) {
-        if (!n->isElementNode())
+    ASSERT(scope);
+    Node* rootNode = scope->rootNode();
+    for (Node* node = rootNode; node; node = node->traverseNextNode(rootNode)) {
+        if (!node->isElementNode())
             continue;
-        Element* element = static_cast<Element*>(n);
+        Element* element = static_cast<Element*>(node);
         const AtomicString& accessKey = element->getAttribute(accesskeyAttr);
         if (!accessKey.isEmpty())
             m_elementsByAccessKey.set(accessKey.impl(), element);
-        buildAccessKeyMap(element->shadowRoot());
+        if (ShadowRoot* shadowRoot = element->shadowRoot())
+            buildAccessKeyMap(shadowRoot);
     }
 }
 
@@ -722,7 +731,7 @@ DOMImplementation* Document::implementation()
 
 void Document::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
 {
-    TreeScope::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+    ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
     
     Element* newDocumentElement = firstElementChild(this);
     if (newDocumentElement == m_documentElement)
@@ -1840,7 +1849,7 @@ void Document::attach()
     RenderObject* render = renderer();
     setRenderer(0);
 
-    TreeScope::attach();
+    ContainerNode::attach();
 
     setRenderer(render);
 }
@@ -1894,7 +1903,7 @@ void Document::detach()
     m_focusedNode = 0;
     m_activeNode = 0;
 
-    TreeScope::detach();
+    ContainerNode::detach();
 
     unscheduleStyleRecalc();
 
index f9b0c71..2d160f1 100644 (file)
@@ -31,6 +31,7 @@
 #include "CheckedRadioButtons.h"
 #include "CollectionType.h"
 #include "Color.h"
+#include "ContainerNode.h"
 #include "DOMTimeStamp.h"
 #include "DocumentEventQueue.h"
 #include "DocumentTiming.h"
@@ -213,7 +214,7 @@ enum PageshowEventPersistence {
 
 enum StyleSelectorUpdateFlag { RecalcStyleImmediately, DeferRecalcStyle, RecalcStyleIfNeeded };
 
-class Document : public TreeScope, public ScriptExecutionContext {
+class Document : public ContainerNode, public TreeScope, public ScriptExecutionContext {
 public:
     static PassRefPtr<Document> create(Frame* frame, const KURL& url)
     {
@@ -227,8 +228,8 @@ public:
 
     MediaQueryMatcher* mediaQueryMatcher();
 
-    using TreeScope::ref;
-    using TreeScope::deref;
+    using ContainerNode::ref;
+    using ContainerNode::deref;
 
     // Nodes belonging to this document hold guard references -
     // these are enough to keep the document from being destroyed, but
index 23d8c20..f7cfadf 100644 (file)
@@ -32,8 +32,8 @@
 
 namespace WebCore {
 
-DocumentFragment::DocumentFragment(Document* document)
-    : ContainerNode(document)
+DocumentFragment::DocumentFragment(Document* document, ConstructionType constructionType)
+    : ContainerNode(document, constructionType)
 {
     ASSERT(document);
 }
index 6bf52f1..1ea4dcb 100644 (file)
@@ -39,7 +39,7 @@ public:
     virtual bool canContainRangeEndPoint() const { return true; }
 
 protected:
-    DocumentFragment(Document*);
+    DocumentFragment(Document*, ConstructionType = CreateContainer);
     virtual String nodeName() const;
 
 private:
index 47268c4..886b8bf 100644 (file)
@@ -108,6 +108,7 @@ template<bool keyMatches(AtomicStringImpl*, Element*)>
 inline Element* DocumentOrderedMap::get(AtomicStringImpl* key, const TreeScope* scope) const
 {
     ASSERT(key);
+    ASSERT(scope);
 
     m_map.checkConsistency();
 
@@ -117,7 +118,7 @@ inline Element* DocumentOrderedMap::get(AtomicStringImpl* key, const TreeScope*
 
     if (m_duplicateCounts.contains(key)) {
         // We know there's at least one node that matches; iterate to find the first one.
-        for (Node* node = scope->firstChild(); node; node = node->traverseNextNode()) {
+        for (Node* node = scope->rootNode()->firstChild(); node; node = node->traverseNextNode()) {
             if (!node->isElementNode())
                 continue;
             element = static_cast<Element*>(node);
index 23235a3..052c51d 100644 (file)
@@ -37,7 +37,8 @@
 namespace WebCore {
 
 ShadowRoot::ShadowRoot(Document* document)
-    : TreeScope(document, CreateShadowRoot)
+    : DocumentFragment(document, CreateShadowRoot)
+    , TreeScope(this)
     , m_applyAuthorSheets(false)
     , m_needsRecalculateContent(false)
 {
@@ -52,6 +53,10 @@ ShadowRoot::ShadowRoot(Document* document)
 
 ShadowRoot::~ShadowRoot()
 {
+    // We must call clearRareData() here since a ShadowRoot class inherits TreeScope
+    // as well as Node. See a comment on TreeScope.h for the reason.
+    if (hasRareData())
+        clearRareData();
 }
 
 PassRefPtr<ShadowRoot> ShadowRoot::create(Element* element, ExceptionCode& ec)
@@ -172,7 +177,7 @@ void ShadowRoot::attach()
     // ensureInclusions(), and here we just ensure that
     // it is in clean state.
     ASSERT(!m_inclusions || !m_inclusions->hasCandidates());
-    TreeScope::attach();
+    DocumentFragment::attach();
     if (m_inclusions)
         m_inclusions->didSelect();
 }
index bb5734c..d0b1894 100644 (file)
@@ -27,6 +27,7 @@
 #ifndef ShadowRoot_h
 #define ShadowRoot_h
 
+#include "DocumentFragment.h"
 #include "ExceptionCode.h"
 #include "TreeScope.h"
 
@@ -36,7 +37,7 @@ class ContentInclusionSelector;
 class Document;
 class HTMLContentElement;
 
-class ShadowRoot : public TreeScope {
+class ShadowRoot : public DocumentFragment, public TreeScope {
 public:
     static PassRefPtr<ShadowRoot> create(Document*);
     static PassRefPtr<ShadowRoot> create(Element*, ExceptionCode&);
index 91f3c29..7138446 100644 (file)
 #include "config.h"
 #include "TreeScope.h"
 
+#include "ContainerNode.h"
+#include "Document.h"
 #include "Element.h"
 #include "HTMLAnchorElement.h"
 #include "HTMLMapElement.h"
 #include "HTMLNames.h"
-#include "NodeRareData.h"
 #include "TreeScopeAdopter.h"
+#include <wtf/text/AtomicString.h>
+#include <wtf/text/CString.h>
 
 namespace WebCore {
 
 using namespace HTMLNames;
 
-TreeScope::TreeScope(Document* document, ConstructionType constructionType)
-    : ContainerNode(document, constructionType)
+TreeScope::TreeScope(ContainerNode* rootNode)
+    : m_rootNode(rootNode)
     , m_parentTreeScope(0)
     , m_numNodeListCaches(0)
 {
+    ASSERT(rootNode);
 }
 
 TreeScope::~TreeScope()
 {
-    if (hasRareData())
-        clearRareData();
 }
 
 void TreeScope::destroyTreeScopeData()
@@ -59,7 +61,7 @@ void TreeScope::destroyTreeScopeData()
 void TreeScope::setParentTreeScope(TreeScope* newParentScope)
 {
     // A document node cannot be re-parented.
-    ASSERT(!isDocumentNode());
+    ASSERT(!rootNode()->isDocumentNode());
     // Every scope other than document needs a parent scope.
     ASSERT(newParentScope);
 
@@ -105,7 +107,7 @@ HTMLMapElement* TreeScope::getImageMap(const String& url) const
         return 0;
     size_t hashPos = url.find('#');
     String name = (hashPos == notFound ? url : url.substring(hashPos + 1)).impl();
-    if (document()->isHTMLDocument())
+    if (rootNode()->document()->isHTMLDocument())
         return static_cast<HTMLMapElement*>(m_imageMapsByName.getElementByLowercasedMapName(AtomicString(name.lower()).impl(), this));
     return static_cast<HTMLMapElement*>(m_imageMapsByName.getElementByMapName(AtomicString(name).impl(), this));
 }
@@ -116,10 +118,10 @@ Element* TreeScope::findAnchor(const String& name)
         return 0;
     if (Element* element = getElementById(name))
         return element;
-    for (Node* node = this; node; node = node->traverseNextNode()) {
+    for (Node* node = rootNode(); node; node = node->traverseNextNode()) {
         if (node->hasTagName(aTag)) {
             HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(node);
-            if (document()->inQuirksMode()) {
+            if (rootNode()->document()->inQuirksMode()) {
                 // Quirks mode, case insensitive comparison of names.
                 if (equalIgnoringCase(anchor->name(), name))
                     return anchor;
index fd6c3cb..b58bbdc 100644 (file)
 #ifndef TreeScope_h
 #define TreeScope_h
 
-#include "ContainerNode.h"
 #include "DocumentOrderedMap.h"
+#include <wtf/Forward.h>
+#include <wtf/text/AtomicString.h>
 
 namespace WebCore {
 
+class ContainerNode;
 class Element;
 class HTMLMapElement;
+class Node;
 
-class TreeScope : public ContainerNode {
+// A class which inherits both Node and TreeScope must call clearRareData() in its destructor
+// so that the Node destructor no longer does problematic NodeList cache manipulation in
+// the destructor.
+class TreeScope {
     friend class Document;
 
 public:
@@ -67,13 +73,16 @@ public:
     // Used by the basic DOM mutation methods (e.g., appendChild()).
     void adoptIfNeeded(Node*);
 
+    ContainerNode* rootNode() const { return m_rootNode; }
+
 protected:
-    TreeScope(Document*, ConstructionType = CreateContainer);
+    TreeScope(ContainerNode*);
     virtual ~TreeScope();
 
     void destroyTreeScopeData();
 
 private:
+    ContainerNode* m_rootNode;
     TreeScope* m_parentTreeScope;
 
     DocumentOrderedMap m_elementsById;
index ab11792..727df2f 100644 (file)
@@ -44,8 +44,8 @@ void TreeScopeAdopter::moveTreeToNewScope(Node* root) const
     // that element may contain stale data as changes made to it will have updated the DOMTreeVersion
     // of the document it was moved to. By increasing the DOMTreeVersion of the donating document here
     // we ensure that the collection cache will be invalidated as needed when the element is moved back.
-    Document* oldDocument = m_oldScope ? m_oldScope->document() : 0;
-    Document* newDocument = m_newScope->document();
+    Document* oldDocument = m_oldScope ? m_oldScope->rootNode()->document() : 0;
+    Document* newDocument = m_newScope->rootNode()->document();
     bool willMoveToNewDocument = oldDocument != newDocument;
     if (oldDocument && willMoveToNewDocument)
         oldDocument->incDOMTreeVersion();
index bc45dbe..a47b6a4 100644 (file)
@@ -270,8 +270,8 @@ static HTMLInputElement* asFileInput(Node* node)
     HTMLInputElement* inputElement = node->toInputElement();
 
     // If this is a button inside of the a file input, move up to the file input.
-    if (inputElement && inputElement->isTextButton() && inputElement->treeScope()->isShadowRoot())
-        inputElement = inputElement->treeScope()->shadowHost()->toInputElement();
+    if (inputElement && inputElement->isTextButton() && inputElement->treeScope()->rootNode()->isShadowRoot())
+        inputElement = inputElement->treeScope()->rootNode()->shadowHost()->toInputElement();
 
     return inputElement && inputElement->isFileUpload() ? inputElement : 0;
 }
index b18d4d1..b0ef211 100644 (file)
@@ -319,10 +319,10 @@ bool FocusController::advanceFocusInDocumentOrder(FocusDirection direction, Keyb
 static inline Node* ownerOfTreeScope(TreeScope* scope)
 {
     ASSERT(scope);
-    if (scope->isShadowRoot())
-        return scope->shadowHost();
-    if (scope->document()->frame())
-        return scope->document()->frame()->ownerElement();
+    if (scope->rootNode()->isShadowRoot())
+        return scope->rootNode()->shadowHost();
+    if (scope->rootNode()->document()->frame())
+        return scope->rootNode()->document()->frame()->ownerElement();
     return 0;
 }
 
@@ -419,18 +419,18 @@ Node* FocusController::nextFocusableNode(TreeScope* scope, Node* start, Keyboard
     // Look for the first node in the scope that:
     // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and
     // 2) comes first in the scope, if there's a tie.
-    if (Node* winner = nextNodeWithGreaterTabIndex(scope, start ? start->tabIndex() : 0, event))
+    if (Node* winner = nextNodeWithGreaterTabIndex(scope->rootNode(), start ? start->tabIndex() : 0, event))
         return winner;
 
     // There are no nodes with a tabindex greater than start's tabindex,
     // so find the first node with a tabindex of 0.
-    return nextNodeWithExactTabIndex(scope, 0, event);
+    return nextNodeWithExactTabIndex(scope->rootNode(), 0, event);
 }
 
 Node* FocusController::previousFocusableNode(TreeScope* scope, Node* start, KeyboardEvent* event)
 {
     Node* last;
-    for (last = scope; last->lastChild(); last = last->lastChild()) { }
+    for (last = scope->rootNode(); last->lastChild(); last = last->lastChild()) { }
 
     // First try to find the last node in the scope that comes before start and has the same tabindex as start.
     // If start is null, find the last node in the scope with a tabindex of 0.