diff options
Diffstat (limited to 'Source/WebCore/dom/ContainerNode.h')
-rw-r--r-- | Source/WebCore/dom/ContainerNode.h | 256 |
1 files changed, 107 insertions, 149 deletions
diff --git a/Source/WebCore/dom/ContainerNode.h b/Source/WebCore/dom/ContainerNode.h index 163753026..8a8e0a2d7 100644 --- a/Source/WebCore/dom/ContainerNode.h +++ b/Source/WebCore/dom/ContainerNode.h @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2004-2015 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -21,222 +21,177 @@ * */ -#ifndef ContainerNode_h -#define ContainerNode_h +#pragma once -#include "ExceptionCodePlaceholder.h" +#include "CollectionType.h" #include "Node.h" -#include <wtf/OwnPtr.h> -#include <wtf/Vector.h> - namespace WebCore { -class FloatPoint; +class HTMLCollection; +class RadioNodeList; class RenderElement; -typedef void (*NodeCallback)(Node&, unsigned); - -namespace Private { - template<class GenericNode, class GenericNodeContainer> - void addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer&); -}; - -class NoEventDispatchAssertion { -public: - NoEventDispatchAssertion() - { -#ifndef NDEBUG - if (!isMainThread()) - return; - s_count++; -#endif - } - - ~NoEventDispatchAssertion() - { -#ifndef NDEBUG - if (!isMainThread()) - return; - ASSERT(s_count); - s_count--; -#endif - } - -#ifndef NDEBUG - static bool isEventDispatchForbidden() - { - if (!isMainThread()) - return false; - return s_count; - } -#endif - -private: -#ifndef NDEBUG - static unsigned s_count; -#endif -}; - class ContainerNode : public Node { - friend class PostAttachCallbackDisabler; public: virtual ~ContainerNode(); Node* firstChild() const { return m_firstChild; } + static ptrdiff_t firstChildMemoryOffset() { return OBJECT_OFFSETOF(ContainerNode, m_firstChild); } Node* lastChild() const { return m_lastChild; } + static ptrdiff_t lastChildMemoryOffset() { return OBJECT_OFFSETOF(ContainerNode, m_lastChild); } bool hasChildNodes() const { return m_firstChild; } + bool hasOneChild() const { return m_firstChild && !m_firstChild->nextSibling(); } + + bool directChildNeedsStyleRecalc() const { return getFlag(DirectChildNeedsStyleRecalcFlag); } + void setDirectChildNeedsStyleRecalc() { setFlag(DirectChildNeedsStyleRecalcFlag); } - unsigned childNodeCount() const; - Node* childNode(unsigned index) const; + WEBCORE_EXPORT unsigned countChildNodes() const; + WEBCORE_EXPORT Node* traverseToChildAt(unsigned) const; - bool insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& = ASSERT_NO_EXCEPTION); - bool replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& = ASSERT_NO_EXCEPTION); - bool removeChild(Node* child, ExceptionCode& = ASSERT_NO_EXCEPTION); - bool appendChild(PassRefPtr<Node> newChild, ExceptionCode& = ASSERT_NO_EXCEPTION); + ExceptionOr<void> insertBefore(Node& newChild, Node* refChild); + ExceptionOr<void> replaceChild(Node& newChild, Node& oldChild); + WEBCORE_EXPORT ExceptionOr<void> removeChild(Node& child); + WEBCORE_EXPORT ExceptionOr<void> appendChild(Node& newChild); + void replaceAllChildren(Ref<Node>&&); + void replaceAllChildren(std::nullptr_t); // These methods are only used during parsing. // They don't send DOM mutation events or handle reparenting. // However, arbitrary code may be run by beforeload handlers. - void parserAppendChild(PassRefPtr<Node>); + void parserAppendChild(Node&); void parserRemoveChild(Node&); - void parserInsertBefore(PassRefPtr<Node> newChild, Node* refChild); + void parserInsertBefore(Node& newChild, Node& refChild); void removeChildren(); - void takeAllChildrenFrom(ContainerNode*); - void cloneChildNodes(ContainerNode* clone); + void takeAllChildrenFrom(ContainerNode*); - virtual LayoutRect boundingBox() const override; + void cloneChildNodes(ContainerNode& clone); - enum ChildChangeType { ElementInserted, ElementRemoved, TextInserted, TextRemoved, TextChanged, AllChildrenRemoved, NonContentsChildChanged }; + enum ChildChangeType { ElementInserted, ElementRemoved, TextInserted, TextRemoved, TextChanged, AllChildrenRemoved, NonContentsChildRemoved, NonContentsChildInserted, AllChildrenReplaced }; enum ChildChangeSource { ChildChangeSourceParser, ChildChangeSourceAPI }; struct ChildChange { ChildChangeType type; Element* previousSiblingElement; Element* nextSiblingElement; ChildChangeSource source; + + bool isInsertion() const + { + switch (type) { + case ElementInserted: + case TextInserted: + case NonContentsChildInserted: + case AllChildrenReplaced: + return true; + case ElementRemoved: + case TextRemoved: + case TextChanged: + case AllChildrenRemoved: + case NonContentsChildRemoved: + return false; + } + ASSERT_NOT_REACHED(); + return false; + } }; virtual void childrenChanged(const ChildChange&); void disconnectDescendantFrames(); - virtual bool childShouldCreateRenderer(const Node&) const { return true; } - - using Node::setAttributeEventListener; - void setAttributeEventListener(const AtomicString& eventType, const QualifiedName& attributeName, const AtomicString& value); - RenderElement* renderer() const; - Element* querySelector(const AtomicString& selectors, ExceptionCode&); - RefPtr<NodeList> querySelectorAll(const AtomicString& selectors, ExceptionCode&); + // Return a bounding box in absolute coordinates enclosing this node and all its descendants. + // This gives the area within which events may get handled by a hander registered on this node. + virtual LayoutRect absoluteEventHandlerBounds(bool& /* includesFixedPositionElements */) { return LayoutRect(); } - PassRefPtr<NodeList> getElementsByTagName(const AtomicString&); - PassRefPtr<NodeList> getElementsByTagNameNS(const AtomicString& namespaceURI, const AtomicString& localName); - PassRefPtr<NodeList> getElementsByName(const String& elementName); - PassRefPtr<NodeList> getElementsByClassName(const String& classNames); - PassRefPtr<RadioNodeList> radioNodeList(const AtomicString&); + WEBCORE_EXPORT ExceptionOr<Element*> querySelector(const String& selectors); + WEBCORE_EXPORT ExceptionOr<Ref<NodeList>> querySelectorAll(const String& selectors); -protected: - explicit ContainerNode(Document*, ConstructionType = CreateContainer); + WEBCORE_EXPORT Ref<HTMLCollection> getElementsByTagName(const AtomicString&); + WEBCORE_EXPORT Ref<HTMLCollection> getElementsByTagNameNS(const AtomicString& namespaceURI, const AtomicString& localName); + WEBCORE_EXPORT Ref<NodeList> getElementsByName(const String& elementName); + WEBCORE_EXPORT Ref<HTMLCollection> getElementsByClassName(const AtomicString& classNames); + Ref<RadioNodeList> radioNodeList(const AtomicString&); - static void queuePostAttachCallback(NodeCallback, Node&, unsigned = 0); - static bool postAttachCallbacksAreSuspended(); + // From the ParentNode interface - https://dom.spec.whatwg.org/#interface-parentnode + WEBCORE_EXPORT Ref<HTMLCollection> children(); + WEBCORE_EXPORT Element* firstElementChild() const; + WEBCORE_EXPORT Element* lastElementChild() const; + WEBCORE_EXPORT unsigned childElementCount() const; + ExceptionOr<void> append(Vector<NodeOrString>&&); + ExceptionOr<void> prepend(Vector<NodeOrString>&&); - template<class GenericNode, class GenericNodeContainer> - friend void appendChildToContainer(GenericNode* child, GenericNodeContainer&); + ExceptionOr<void> ensurePreInsertionValidity(Node& newChild, Node* refChild); - template<class GenericNode, class GenericNodeContainer> - friend void Private::addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer&); +protected: + explicit ContainerNode(Document&, ConstructionType = CreateContainer); + + friend void addChildNodesToDeletionQueue(Node*& head, Node*& tail, ContainerNode&); void removeDetachedChildren(); void setFirstChild(Node* child) { m_firstChild = child; } void setLastChild(Node* child) { m_lastChild = child; } + HTMLCollection* cachedHTMLCollection(CollectionType); + private: void removeBetween(Node* previousChild, Node* nextChild, Node& oldChild); + ExceptionOr<void> appendChildWithoutPreInsertionValidityCheck(Node&); void insertBeforeCommon(Node& nextChild, Node& oldChild); + void appendChildCommon(Node&); - static void dispatchPostAttachCallbacks(); - static void suspendPostAttachCallbacks(Document&); - static void resumePostAttachCallbacks(Document&); - - bool getUpperLeftCorner(FloatPoint&) const; - bool getLowerRightCorner(FloatPoint&) const; - - void notifyChildInserted(Node& child, ChildChangeSource); + void notifyChildInserted(Node& child, const ChildChange&); void notifyChildRemoved(Node& child, Node* previousSibling, Node* nextSibling, ChildChangeSource); - void updateTreeAfterInsertion(Node& child); + enum class ReplacedAllChildren { No, Yes }; + void updateTreeAfterInsertion(Node& child, ReplacedAllChildren = ReplacedAllChildren::No); + static ChildChange changeForChildInsertion(Node& child, ChildChangeSource, ReplacedAllChildren = ReplacedAllChildren::No); + void rebuildSVGExtensionsElementsIfNecessary(); bool isContainerNode() const = delete; - void willRemoveChild(Node& child); - - Node* m_firstChild; - Node* m_lastChild; + Node* m_firstChild { nullptr }; + Node* m_lastChild { nullptr }; }; -inline bool isContainerNode(const Node& node) { return node.isContainerNode(); } -void isContainerNode(const ContainerNode&); // Catch unnecessary runtime check of type known at compile time. - -NODE_TYPE_CASTS(ContainerNode) - -inline ContainerNode::ContainerNode(Document* document, ConstructionType type) +inline ContainerNode::ContainerNode(Document& document, ConstructionType type) : Node(document, type) - , m_firstChild(0) - , m_lastChild(0) { } -inline unsigned Node::childNodeCount() const +inline unsigned Node::countChildNodes() const { - if (!isContainerNode()) + if (!is<ContainerNode>(*this)) return 0; - return toContainerNode(this)->childNodeCount(); + return downcast<ContainerNode>(*this).countChildNodes(); } -inline Node* Node::childNode(unsigned index) const +inline Node* Node::traverseToChildAt(unsigned index) const { - if (!isContainerNode()) - return 0; - return toContainerNode(this)->childNode(index); + if (!is<ContainerNode>(*this)) + return nullptr; + return downcast<ContainerNode>(*this).traverseToChildAt(index); } inline Node* Node::firstChild() const { - if (!isContainerNode()) - return 0; - return toContainerNode(this)->firstChild(); + if (!is<ContainerNode>(*this)) + return nullptr; + return downcast<ContainerNode>(*this).firstChild(); } inline Node* Node::lastChild() const { - if (!isContainerNode()) - return 0; - return toContainerNode(this)->lastChild(); -} - -inline Node* Node::highestAncestor() const -{ - Node* node = const_cast<Node*>(this); - Node* highest = node; - for (; node; node = node->parentNode()) - highest = node; - return highest; -} - -inline bool Node::needsNodeRenderingTraversalSlowPath() const -{ - if (getFlag(NeedsNodeRenderingTraversalSlowPathFlag)) - return true; - ContainerNode* parent = parentOrShadowHostNode(); - return parent && parent->getFlag(NeedsNodeRenderingTraversalSlowPathFlag); + if (!is<ContainerNode>(*this)) + return nullptr; + return downcast<ContainerNode>(*this).lastChild(); } inline bool Node::isTreeScope() const { - return treeScope().rootNode() == this; + return &treeScope().rootNode() == this; } // This constant controls how much buffer is initially allocated @@ -259,45 +214,45 @@ public: explicit ChildNodesLazySnapshot(Node& parentNode) : m_currentNode(parentNode.firstChild()) , m_currentIndex(0) + , m_hasSnapshot(false) { m_nextSnapshot = latestSnapshot; latestSnapshot = this; } - ~ChildNodesLazySnapshot() + ALWAYS_INLINE ~ChildNodesLazySnapshot() { latestSnapshot = m_nextSnapshot; } // Returns 0 if there is no next Node. - PassRefPtr<Node> nextNode() + RefPtr<Node> nextNode() { if (LIKELY(!hasSnapshot())) { - RefPtr<Node> node = m_currentNode; + RefPtr<Node> node = WTFMove(m_currentNode); if (node) m_currentNode = node->nextSibling(); - return node.release(); + return node; } - Vector<RefPtr<Node>>& nodeVector = *m_childNodes; - if (m_currentIndex >= nodeVector.size()) - return 0; - return nodeVector[m_currentIndex++]; + if (m_currentIndex >= m_snapshot.size()) + return nullptr; + return m_snapshot[m_currentIndex++]; } void takeSnapshot() { if (hasSnapshot()) return; - m_childNodes = adoptPtr(new Vector<RefPtr<Node>>()); + m_hasSnapshot = true; Node* node = m_currentNode.get(); while (node) { - m_childNodes->append(node); + m_snapshot.append(node); node = node->nextSibling(); } } ChildNodesLazySnapshot* nextSnapshot() { return m_nextSnapshot; } - bool hasSnapshot() { return !!m_childNodes.get(); } + bool hasSnapshot() { return m_hasSnapshot; } static void takeChildNodesLazySnapshot() { @@ -313,10 +268,13 @@ private: RefPtr<Node> m_currentNode; unsigned m_currentIndex; - OwnPtr<Vector<RefPtr<Node>>> m_childNodes; // Lazily instantiated. + bool m_hasSnapshot; + Vector<RefPtr<Node>> m_snapshot; // Lazily instantiated. ChildNodesLazySnapshot* m_nextSnapshot; }; } // namespace WebCore -#endif // ContainerNode_h +SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ContainerNode) + static bool isType(const WebCore::Node& node) { return node.isContainerNode(); } +SPECIALIZE_TYPE_TRAITS_END() |