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.
.) Adapt JavaScript Node wrappers (temporary code - see https://bugs.webkit.org/show_bug.cgi?id=58704).
No new tests. (refactoring)
* bindings/js/JSNodeCustom.cpp:
(WebCore::createWrapperInline):
* bindings/v8/custom/V8NodeCustom.cpp:
(WebCore::toV8Slow):
* 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@84394
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2011-04-19 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.
+ .) Adapt JavaScript Node wrappers (temporary code - see https://bugs.webkit.org/show_bug.cgi?id=58704).
+
+ No new tests. (refactoring)
+
+ * bindings/js/JSNodeCustom.cpp:
+ (WebCore::createWrapperInline):
+ * bindings/v8/custom/V8NodeCustom.cpp:
+ (WebCore::toV8Slow):
+ * 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-20 Vsevolod Vlasov <vsevik@chromium.org>
Reviewed by Pavel Feldman.
#include "Notation.h"
#include "ProcessingInstruction.h"
#include "RegisteredEventListener.h"
+#include "ShadowRoot.h"
#include "StyleSheet.h"
#include "StyledElement.h"
#include "Text.h"
wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, Notation, node);
break;
case Node::DOCUMENT_FRAGMENT_NODE:
- wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, DocumentFragment, node);
+ // FIXME: remove 'if' once ShadowRoot gets its own node type (see bug 58704)
+ if (node->isShadowBoundary())
+ wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, Node, node);
+ else
+ wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, DocumentFragment, node);
break;
case Node::ENTITY_REFERENCE_NODE:
wrapper = CREATE_DOM_NODE_WRAPPER(exec, globalObject, EntityReference, node);
#include "Document.h"
#include "EventListener.h"
+#include "ShadowRoot.h"
#include "V8AbstractEventListener.h"
#include "V8Attr.h"
case Node::DOCUMENT_TYPE_NODE:
return toV8(static_cast<DocumentType*>(impl), forceNewObject);
case Node::DOCUMENT_FRAGMENT_NODE:
+ // FIXME: remove 'if' once ShadowRoot gets its own node type (see bug 58704)
+ if (impl->isShadowBoundary())
+ return toV8(static_cast<ShadowRoot*>(impl), forceNewObject);
return toV8(static_cast<DocumentFragment*>(impl), forceNewObject);
case Node::NOTATION_NODE:
return toV8(static_cast<Notation*>(impl), forceNewObject);
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();
}
oldChild->setNextSibling(0);
oldChild->setParent(0);
+ oldChild->setTreeScopeRecursively(document());
+
allowEventDispatch();
}
n->setPreviousSibling(0);
n->setNextSibling(0);
n->setParent(0);
+ n->setTreeScopeRecursively(document());
m_firstChild = next;
if (n == m_lastChild)
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?
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)
ASSERT(m_ranges.isEmpty());
ASSERT(!m_styleRecalcTimer.isActive());
ASSERT(!m_parentTreeScope);
+ ASSERT(!m_guardRefCount);
m_scriptRunner.clear();
ASSERT(!m_docType || !docType);
m_docType = docType;
if (m_docType)
- m_docType->setTreeScope(this);
+ m_docType->setTreeScopeRecursively(this);
}
DOMImplementation* Document::implementation()
class DOMTokenList;
class ElementRareData;
class IntSize;
+class ShadowRoot;
class WebKitAnimationList;
enum SpellcheckAttributeState {
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();
#include "RenderView.h"
#include "ScopedEventQueue.h"
#include "SelectorNodeList.h"
+#include "ShadowRoot.h"
#include "StaticNodeList.h"
#include "TagNodeList.h"
#include "Text.h"
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();
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);
+ }
}
}
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.
#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
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())
#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*);
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)
return adoptRef(new ShadowRoot(document));
}
+inline ShadowRoot* toShadowRoot(Node* node)
+{
+ ASSERT(!node || node->isShadowBoundary());
+ return static_cast<ShadowRoot*>(node);
+}
+
} // namespace
#endif
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()
// 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;
public:
TreeScope* parentTreeScope() const { return m_parentTreeScope; }
+ void setParentTreeScope(TreeScope*);
Element* getElementById(const AtomicString&) const;
bool hasElementWithId(AtomicStringImpl* id) const;
Element* findAnchor(const String& name);
protected:
- TreeScope(Document*, ConstructionType = CreateContainer);
-
+ TreeScope(Document*);
virtual ~TreeScope();
void destroyTreeScopeData();
- void setParentTreeScope(TreeScope*);
-
private:
TreeScope* m_parentTreeScope;
#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>