| /* |
| * Copyright (C) 1999 Lars Knoll ([email protected]) |
| * (C) 1999 Antti Koivisto ([email protected]) |
| * (C) 2001 Dirk Mueller ([email protected]) |
| * Copyright (C) 2004-2018 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 |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public License |
| * along with this library; see the file COPYING.LIB. If not, write to |
| * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| * |
| */ |
| |
| #pragma once |
| |
| #include "Node.h" |
| |
| namespace WebCore { |
| |
| class HTMLCollection; |
| class RadioNodeList; |
| class RenderElement; |
| struct SerializedNode; |
| |
| enum class CollectionType : uint8_t; |
| |
| class ContainerNode : public Node { |
| WTF_MAKE_TZONE_OR_ISO_ALLOCATED(ContainerNode); |
| WTF_OVERRIDE_DELETE_FOR_CHECKED_PTR(ContainerNode); |
| public: |
| virtual ~ContainerNode(); |
| |
| Node* firstChild() const { return m_firstChild.get(); } |
| RefPtr<Node> protectedFirstChild() const { return m_firstChild.get(); } |
| static constexpr ptrdiff_t firstChildMemoryOffset() { return OBJECT_OFFSETOF(ContainerNode, m_firstChild); } |
| Node* lastChild() const { return m_lastChild.get(); } |
| RefPtr<Node> protectedLastChild() const { return m_lastChild.get(); } |
| static constexpr ptrdiff_t lastChildMemoryOffset() { return OBJECT_OFFSETOF(ContainerNode, m_lastChild); } |
| bool hasChildNodes() const { return m_firstChild.get(); } |
| bool hasOneChild() const { return m_firstChild && m_firstChild == m_lastChild; } |
| |
| bool directChildNeedsStyleRecalc() const { return hasStyleFlag(NodeStyleFlag::DirectChildNeedsStyleResolution); } |
| void setDirectChildNeedsStyleRecalc() { setStyleFlag(NodeStyleFlag::DirectChildNeedsStyleResolution); } |
| |
| WEBCORE_EXPORT unsigned countChildNodes() const; |
| WEBCORE_EXPORT Node* traverseToChildAt(unsigned) const; |
| |
| ExceptionOr<void> insertBefore(Node& newChild, RefPtr<Node>&& refChild); |
| ExceptionOr<void> replaceChild(Node& newChild, Node& oldChild); |
| WEBCORE_EXPORT ExceptionOr<void> removeChild(Node& child); |
| WEBCORE_EXPORT ExceptionOr<void> appendChild(Node& newChild); |
| void stringReplaceAll(String&&); |
| void replaceAll(Node*); |
| |
| inline ContainerNode& rootNode() const; // Defined in ContainerNodeInlines.h |
| inline Ref<ContainerNode> protectedRootNode() const; // Defined in ContainerNodeInlines.h |
| ContainerNode& traverseToRootNode() const; |
| |
| // 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(Node&); |
| void parserAppendChildIntoIsolatedTree(Node&); |
| void parserNotifyChildrenChanged(); |
| void parserRemoveChild(Node&); |
| void parserInsertBefore(Node& newChild, Node& refChild); |
| |
| WEBCORE_EXPORT void removeChildren(); |
| |
| void takeAllChildrenFrom(ContainerNode*); |
| |
| void cloneChildNodes(Document&, CustomElementRegistry*, ContainerNode& clone, size_t currentDepth = 0) const; |
| Vector<SerializedNode> serializeChildNodes(size_t currentDepth = 0) const; |
| |
| enum class CanDelayNodeDeletion : uint8_t { No, Yes, Unknown }; |
| struct ChildChange { |
| enum class Type : uint8_t { ElementInserted, ElementRemoved, TextInserted, TextRemoved, TextChanged, AllChildrenRemoved, NonContentsChildRemoved, NonContentsChildInserted, AllChildrenReplaced }; |
| enum class Source : uint8_t { Parser, API, Clone }; |
| enum class AffectsElements : uint8_t { Unknown, No, Yes }; |
| |
| ChildChange::Type type; |
| // Making these raw pointers RefPtr leads to a Speedometer 3 regression. |
| SUPPRESS_UNCOUNTED_MEMBER Element* siblingChanged; |
| SUPPRESS_UNCOUNTED_MEMBER Element* previousSiblingElement; |
| SUPPRESS_UNCOUNTED_MEMBER Element* nextSiblingElement; |
| ChildChange::Source source; |
| AffectsElements affectsElements; |
| |
| bool isInsertion() const |
| { |
| switch (type) { |
| case ChildChange::Type::ElementInserted: |
| case ChildChange::Type::TextInserted: |
| case ChildChange::Type::NonContentsChildInserted: |
| case ChildChange::Type::AllChildrenReplaced: |
| return true; |
| case ChildChange::Type::ElementRemoved: |
| case ChildChange::Type::TextRemoved: |
| case ChildChange::Type::TextChanged: |
| case ChildChange::Type::AllChildrenRemoved: |
| case ChildChange::Type::NonContentsChildRemoved: |
| return false; |
| } |
| ASSERT_NOT_REACHED(); |
| return false; |
| } |
| }; |
| virtual void childrenChanged(const ChildChange&); |
| |
| ExceptionOr<void> appendChild(ChildChange::Source, Node& newChild); |
| |
| void disconnectDescendantFrames(); |
| |
| inline RenderElement* renderer() const; // Defined in ContainerNodeInlines.h. |
| inline CheckedPtr<RenderElement> checkedRenderer() const; // Defined in ContainerNodeInlines.h. |
| |
| // 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 */); |
| |
| WEBCORE_EXPORT ExceptionOr<Element*> querySelector(const String& selectors); |
| WEBCORE_EXPORT ExceptionOr<Ref<NodeList>> querySelectorAll(const String& selectors); |
| |
| WEBCORE_EXPORT Ref<HTMLCollection> getElementsByTagName(const AtomString&); |
| WEBCORE_EXPORT Ref<HTMLCollection> getElementsByTagNameNS(const AtomString& namespaceURI, const AtomString& localName); |
| WEBCORE_EXPORT Ref<HTMLCollection> getElementsByClassName(const AtomString& classNames); |
| Ref<RadioNodeList> radioNodeList(const AtomString&); |
| |
| // 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(FixedVector<NodeOrString>&&); |
| ExceptionOr<void> prepend(FixedVector<NodeOrString>&&); |
| |
| ExceptionOr<void> replaceChildren(FixedVector<NodeOrString>&&); |
| |
| ExceptionOr<void> ensurePreInsertionValidity(Node& newChild, Node* refChild); |
| ExceptionOr<void> ensurePreInsertionValidityForPhantomDocumentFragment(NodeVector& newChildren, Node* refChild = nullptr); |
| ExceptionOr<void> insertChildrenBeforeWithoutPreInsertionValidityCheck(NodeVector&&, Node* nextChild = nullptr); |
| |
| protected: |
| explicit ContainerNode(Document&, NodeType, OptionSet<TypeFlag> = { }); |
| |
| friend void removeDetachedChildrenInContainer(ContainerNode&); |
| |
| void removeDetachedChildren(); |
| void setFirstChild(Node* child) { m_firstChild = child; } |
| void setLastChild(Node* child) { m_lastChild = child; } |
| |
| HTMLCollection* cachedHTMLCollection(CollectionType); |
| |
| private: |
| friend struct SerializedNode; |
| void executePreparedChildrenRemoval(); |
| enum class DeferChildrenChanged : bool { No, Yes }; |
| enum class DidRemoveElements : bool { No, Yes }; |
| struct RemoveAllChildrenResult { |
| unsigned subTreeSize; |
| DidRemoveElements didRemoveElements; |
| CanDelayNodeDeletion canBeDelayed; |
| }; |
| RemoveAllChildrenResult removeAllChildrenWithScriptAssertionMaybeAsync(ChildChange::Source, NodeVector& children, DeferChildrenChanged = DeferChildrenChanged::No); |
| RemoveAllChildrenResult removeAllChildrenWithScriptAssertion(ChildChange::Source, NodeVector& children, DeferChildrenChanged = DeferChildrenChanged::No); |
| bool removeNodeWithScriptAssertion(Node&, ChildChange::Source); |
| ExceptionOr<void> removeSelfOrChildNodesForInsertion(Node&, NodeVector&); |
| |
| void removeBetween(Node* previousChild, Node* nextChild, Node& oldChild); |
| ExceptionOr<void> appendChildWithoutPreInsertionValidityCheck(Node&); |
| |
| void insertBeforeCommon(Node& nextChild, Node& oldChild); |
| void appendChildCommon(Node&); |
| |
| void rebuildSVGExtensionsElementsIfNecessary(); |
| |
| bool isContainerNode() const = delete; |
| |
| CheckedPtr<Node> m_firstChild; |
| CheckedPtr<Node> m_lastChild; |
| }; |
| |
| inline ContainerNode::ContainerNode(Document& document, NodeType type, OptionSet<TypeFlag> typeFlags) |
| : Node(document, type, typeFlags | TypeFlag::IsContainerNode) |
| { |
| ASSERT(!isCharacterDataNode()); |
| } |
| |
| } // namespace WebCore |
| |
| SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ContainerNode) |
| static bool isType(const WebCore::Node& node) { return node.isContainerNode(); } |
| SPECIALIZE_TYPE_TRAITS_END() |