diff options
Diffstat (limited to 'Source/WebCore/dom/Node.h')
-rw-r--r-- | Source/WebCore/dom/Node.h | 554 |
1 files changed, 309 insertions, 245 deletions
diff --git a/Source/WebCore/dom/Node.h b/Source/WebCore/dom/Node.h index dff49ff96..37a7f5dff 100644 --- a/Source/WebCore/dom/Node.h +++ b/Source/WebCore/dom/Node.h @@ -22,84 +22,47 @@ * */ -#ifndef Node_h -#define Node_h +#pragma once -#include "EditingBoundary.h" #include "EventTarget.h" -#include "URLHash.h" +#include "ExceptionOr.h" #include "LayoutRect.h" #include "MutationObserver.h" #include "RenderStyleConstants.h" -#include "ScriptWrappable.h" -#include "SimulatedClickOptions.h" +#include "StyleValidity.h" #include "TreeScope.h" -#include "TreeShared.h" +#include "URLHash.h" #include <wtf/Forward.h> #include <wtf/ListHashSet.h> -#include <wtf/text/AtomicString.h> - -namespace JSC { - class VM; - class SlotVisitor; -} +#include <wtf/MainThread.h> +#include <wtf/TypeCasts.h> // This needs to be here because Document.h also depends on it. #define DUMP_NODE_STATISTICS 0 namespace WebCore { -class Attribute; -class ClassNodeList; class ContainerNode; -class DOMSettableTokenList; class Document; class Element; -class Event; -class EventListener; class FloatPoint; -class Frame; -class HTMLInputElement; -class IntRect; -class KeyboardEvent; -class NSResolver; +class HTMLQualifiedName; +class HTMLSlotElement; +class MathMLQualifiedName; class NamedNodeMap; -class NameNodeList; class NodeList; class NodeListsNodeData; class NodeRareData; class QualifiedName; -class RadioNodeList; -class RegisteredEventListener; class RenderBox; class RenderBoxModelObject; class RenderObject; class RenderStyle; +class SVGQualifiedName; class ShadowRoot; -class TagNodeList; - -#if ENABLE(INDIE_UI) -class UIRequestEvent; -#endif - -#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS) class TouchEvent; -#endif - -typedef int ExceptionCode; -const int nodeStyleChangeShift = 14; - -// SyntheticStyleChange means that we need to go through the entire style change logic even though -// no style property has actually changed. It is used to restructure the tree when, for instance, -// RenderLayers are created or destroyed due to animation changes. -enum StyleChangeType { - NoStyleChange = 0, - InlineStyleChange = 1 << nodeStyleChangeShift, - FullStyleChange = 2 << nodeStyleChangeShift, - SyntheticStyleChange = 3 << nodeStyleChangeShift, - ReconstructRenderTree = 4 << nodeStyleChangeShift, -}; +using NodeOrString = Variant<RefPtr<Node>, String>; class NodeRareDataBase { public: @@ -115,26 +78,28 @@ private: RenderObject* m_renderer; }; -class Node : public EventTarget, public ScriptWrappable, public TreeShared<Node> { +class Node : public EventTarget { + WTF_MAKE_FAST_ALLOCATED; + friend class Document; friend class TreeScope; friend class TreeScopeAdopter; - public: enum NodeType { ELEMENT_NODE = 1, ATTRIBUTE_NODE = 2, TEXT_NODE = 3, CDATA_SECTION_NODE = 4, - ENTITY_REFERENCE_NODE = 5, - ENTITY_NODE = 6, PROCESSING_INSTRUCTION_NODE = 7, COMMENT_NODE = 8, DOCUMENT_NODE = 9, DOCUMENT_TYPE_NODE = 10, DOCUMENT_FRAGMENT_NODE = 11, + }; + enum DeprecatedNodeType { + ENTITY_REFERENCE_NODE = 5, + ENTITY_NODE = 6, NOTATION_NODE = 12, - XPATH_NAMESPACE_NODE = 13, }; enum DocumentPosition { DOCUMENT_POSITION_EQUIVALENT = 0x00, @@ -146,31 +111,32 @@ public: DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20, }; - static bool isSupported(const String& feature, const String& version); - - static void startIgnoringLeaks(); - static void stopIgnoringLeaks(); + WEBCORE_EXPORT static void startIgnoringLeaks(); + WEBCORE_EXPORT static void stopIgnoringLeaks(); static void dumpStatistics(); virtual ~Node(); - void willBeDeletedFrom(Document*); + void willBeDeletedFrom(Document&); // DOM methods & attributes for Node - bool hasTagName(const QualifiedName&) const; - bool hasLocalName(const AtomicString&) const; + bool hasTagName(const HTMLQualifiedName&) const; + bool hasTagName(const MathMLQualifiedName&) const; + bool hasTagName(const SVGQualifiedName&) const; virtual String nodeName() const = 0; virtual String nodeValue() const; - virtual void setNodeValue(const String&, ExceptionCode&); + virtual ExceptionOr<void> setNodeValue(const String&); virtual NodeType nodeType() const = 0; + virtual size_t approximateMemoryCost() const { return sizeof(*this); } ContainerNode* parentNode() const; static ptrdiff_t parentNodeMemoryOffset() { return OBJECT_OFFSETOF(Node, m_parentNode); } Element* parentElement() const; Node* previousSibling() const { return m_previous; } static ptrdiff_t previousSiblingMemoryOffset() { return OBJECT_OFFSETOF(Node, m_previous); } Node* nextSibling() const { return m_next; } - PassRefPtr<NodeList> childNodes(); + static ptrdiff_t nextSiblingMemoryOffset() { return OBJECT_OFFSETOF(Node, m_next); } + WEBCORE_EXPORT RefPtr<NodeList> childNodes(); Node* firstChild() const; Node* lastChild() const; bool hasAttributes() const; @@ -180,40 +146,54 @@ public: Node* pseudoAwareFirstChild() const; Node* pseudoAwareLastChild() const; - virtual URL baseURI() const; + WEBCORE_EXPORT const URL& baseURI() const; void getSubresourceURLs(ListHashSet<URL>&) const; - // These should all actually return a node, but this is only important for language bindings, - // which will already know and hold a ref on the right node to return. Returning bool allows - // these methods to be more efficient since they don't need to return a ref - bool insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode&); - bool replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode&); - bool removeChild(Node* child, ExceptionCode&); - bool appendChild(PassRefPtr<Node> newChild, ExceptionCode&); + WEBCORE_EXPORT ExceptionOr<void> insertBefore(Node& newChild, Node* refChild); + WEBCORE_EXPORT ExceptionOr<void> replaceChild(Node& newChild, Node& oldChild); + WEBCORE_EXPORT ExceptionOr<void> removeChild(Node& child); + WEBCORE_EXPORT ExceptionOr<void> appendChild(Node& newChild); - void remove(ExceptionCode&); bool hasChildNodes() const { return firstChild(); } - virtual PassRefPtr<Node> cloneNode(bool deep) = 0; + + enum class CloningOperation { + OnlySelf, + SelfWithTemplateContent, + Everything, + }; + virtual Ref<Node> cloneNodeInternal(Document&, CloningOperation) = 0; + Ref<Node> cloneNode(bool deep) { return cloneNodeInternal(document(), deep ? CloningOperation::Everything : CloningOperation::OnlySelf); } + WEBCORE_EXPORT ExceptionOr<Ref<Node>> cloneNodeForBindings(bool deep); + virtual const AtomicString& localName() const; virtual const AtomicString& namespaceURI() const; virtual const AtomicString& prefix() const; - virtual void setPrefix(const AtomicString&, ExceptionCode&); - void normalize(); + virtual ExceptionOr<void> setPrefix(const AtomicString&); + WEBCORE_EXPORT void normalize(); bool isSameNode(Node* other) const { return this == other; } - bool isEqualNode(Node*) const; - bool isDefaultNamespace(const AtomicString& namespaceURI) const; - String lookupPrefix(const AtomicString& namespaceURI) const; - String lookupNamespaceURI(const String& prefix) const; - String lookupNamespacePrefix(const AtomicString& namespaceURI, const Element* originalElement) const; - - String textContent(bool convertBRsToNewlines = false) const; - void setTextContent(const String&, ExceptionCode&); + WEBCORE_EXPORT bool isEqualNode(Node*) const; + WEBCORE_EXPORT bool isDefaultNamespace(const AtomicString& namespaceURI) const; + WEBCORE_EXPORT const AtomicString& lookupPrefix(const AtomicString& namespaceURI) const; + WEBCORE_EXPORT const AtomicString& lookupNamespaceURI(const AtomicString& prefix) const; + + WEBCORE_EXPORT String textContent(bool convertBRsToNewlines = false) const; + WEBCORE_EXPORT ExceptionOr<void> setTextContent(const String&); Node* lastDescendant() const; Node* firstDescendant() const; + // From the NonDocumentTypeChildNode - https://dom.spec.whatwg.org/#nondocumenttypechildnode + WEBCORE_EXPORT Element* previousElementSibling() const; + WEBCORE_EXPORT Element* nextElementSibling() const; + + // From the ChildNode - https://dom.spec.whatwg.org/#childnode + ExceptionOr<void> before(Vector<NodeOrString>&&); + ExceptionOr<void> after(Vector<NodeOrString>&&); + ExceptionOr<void> replaceWith(Vector<NodeOrString>&&); + WEBCORE_EXPORT ExceptionOr<void> remove(); + // Other methods (not part of DOM) bool isElementNode() const { return getFlag(IsElementFlag); } @@ -238,44 +218,60 @@ public: virtual bool isCharacterDataNode() const { return false; } virtual bool isFrameOwnerElement() const { return false; } virtual bool isPluginElement() const { return false; } - virtual bool isInsertionPointNode() const { return false; } +#if ENABLE(SERVICE_CONTROLS) + virtual bool isImageControlsRootElement() const { return false; } + virtual bool isImageControlsButtonElement() const { return false; } +#endif bool isDocumentNode() const; bool isTreeScope() const; bool isDocumentFragment() const { return getFlag(IsDocumentFragmentFlag); } bool isShadowRoot() const { return isDocumentFragment() && isTreeScope(); } - bool isInsertionPoint() const { return getFlag(NeedsNodeRenderingTraversalSlowPathFlag) && isInsertionPointNode(); } - // Returns Node rather than InsertionPoint. Should be used only for language bindings. - Node* insertionParentForBinding() const; - - bool needsNodeRenderingTraversalSlowPath() const; - bool inNamedFlow() const { return getFlag(InNamedFlowFlag); } bool hasCustomStyleResolveCallbacks() const { return getFlag(HasCustomStyleResolveCallbacksFlag); } bool hasSyntheticAttrChildNodes() const { return getFlag(HasSyntheticAttrChildNodesFlag); } void setHasSyntheticAttrChildNodes(bool flag) { setFlag(flag, HasSyntheticAttrChildNodesFlag); } - // If this node is in a shadow tree, returns its shadow host. Otherwise, returns 0. - Element* shadowHost() const; + // If this node is in a shadow tree, returns its shadow host. Otherwise, returns null. + WEBCORE_EXPORT Element* shadowHost() const; // If this node is in a shadow tree, returns its shadow host. Otherwise, returns this. // Deprecated. Should use shadowHost() and check the return value. - Node* deprecatedShadowAncestorNode() const; + WEBCORE_EXPORT Node* deprecatedShadowAncestorNode() const; ShadowRoot* containingShadowRoot() const; ShadowRoot* shadowRoot() const; + bool isClosedShadowHidden(const Node&) const; - // Returns 0, a child of ShadowRoot, or a legacy shadow root. + HTMLSlotElement* assignedSlot() const; + HTMLSlotElement* assignedSlotForBindings() const; + + bool isUndefinedCustomElement() const { return isElementNode() && getFlag(IsEditingTextOrUndefinedCustomElementFlag); } + bool isCustomElementUpgradeCandidate() const { return getFlag(IsCustomElement) && getFlag(IsEditingTextOrUndefinedCustomElementFlag); } + bool isDefinedCustomElement() const { return getFlag(IsCustomElement) && !getFlag(IsEditingTextOrUndefinedCustomElementFlag); } + bool isFailedCustomElement() const { return isElementNode() && !getFlag(IsCustomElement) && getFlag(IsEditingTextOrUndefinedCustomElementFlag); } + + // Returns null, a child of ShadowRoot, or a legacy shadow root. Node* nonBoundaryShadowTreeRootNode(); // Node's parent or shadow tree host. ContainerNode* parentOrShadowHostNode() const; + ContainerNode* parentInComposedTree() const; + Element* parentElementInComposedTree() const; Element* parentOrShadowHostElement() const; void setParentNode(ContainerNode*); - Node* highestAncestor() const; + Node& rootNode() const; + Node& shadowIncludingRoot() const; - // Use when it's guaranteed to that shadowHost is 0. + struct GetRootNodeOptions { + bool composed; + }; + Node& getRootNode(const GetRootNodeOptions&) const; + + void* opaqueRoot() const; + + // Use when it's guaranteed to that shadowHost is null. ContainerNode* parentNodeGuaranteedHostFree() const; - // Returns the parent node, but 0 if the parent node is a ShadowRoot. + // Returns the parent node, but null if the parent node is a ShadowRoot. ContainerNode* nonShadowBoundaryParentNode() const; bool selfOrAncestorHasDirAutoAttribute() const { return getFlag(SelfOrAncestorHasDirAutoFlag); } @@ -291,8 +287,7 @@ public: virtual bool canContainRangeEndPoint() const { return false; } bool isRootEditableElement() const; - Element* rootEditableElement() const; - Element* rootEditableElement(EditableType) const; + WEBCORE_EXPORT Element* rootEditableElement() const; // Called by the parser when this element's close tag is reached, // signaling that all child tags have been parsed and added. @@ -312,24 +307,20 @@ public: void setUserActionElement(bool flag) { setFlag(flag, IsUserActionElement); } bool inRenderedDocument() const; - bool needsStyleRecalc() const { return styleChangeType() != NoStyleChange; } - StyleChangeType styleChangeType() const { return static_cast<StyleChangeType>(m_nodeFlags & StyleChangeMask); } + bool needsStyleRecalc() const { return styleValidity() != Style::Validity::Valid; } + Style::Validity styleValidity() const; + bool styleResolutionShouldRecompositeLayer() const; bool childNeedsStyleRecalc() const { return getFlag(ChildNeedsStyleRecalcFlag); } - bool isLink() const { return getFlag(IsLinkFlag); } - bool isEditingText() const { return getFlag(IsEditingTextFlag); } + bool styleIsAffectedByPreviousSibling() const { return getFlag(StyleIsAffectedByPreviousSibling); } + bool isEditingText() const { return getFlag(IsTextFlag) && getFlag(IsEditingTextOrUndefinedCustomElementFlag); } void setChildNeedsStyleRecalc() { setFlag(ChildNeedsStyleRecalcFlag); } - void clearChildNeedsStyleRecalc() { clearFlag(ChildNeedsStyleRecalcFlag); } + void clearChildNeedsStyleRecalc() { m_nodeFlags &= ~(ChildNeedsStyleRecalcFlag | DirectChildNeedsStyleRecalcFlag); } - void setNeedsStyleRecalc(StyleChangeType changeType = FullStyleChange); - void clearNeedsStyleRecalc() { m_nodeFlags &= ~StyleChangeMask; } + void setHasValidStyle(); - void setIsLink(bool f) { setFlag(f, IsLinkFlag); } - void setIsLink() { setFlag(IsLinkFlag); } - void clearIsLink() { clearFlag(IsLinkFlag); } - - void setInNamedFlow() { setFlag(InNamedFlowFlag); } - void clearInNamedFlow() { clearFlag(InNamedFlowFlag); } + bool isLink() const { return getFlag(IsLinkFlag); } + void setIsLink(bool flag) { setFlag(flag, IsLinkFlag); } bool hasEventTargetData() const { return getFlag(HasEventTargetDataFlag); } void setHasEventTargetData(bool flag) { setFlag(flag, HasEventTargetDataFlag); } @@ -338,53 +329,39 @@ public: UserSelectAllDoesNotAffectEditability, UserSelectAllIsAlwaysNonEditable }; - bool isContentEditable(UserSelectAllTreatment = UserSelectAllDoesNotAffectEditability); + WEBCORE_EXPORT bool isContentEditable(); bool isContentRichlyEditable(); - void inspect(); + WEBCORE_EXPORT void inspect(); - bool hasEditableStyle(EditableType editableType = ContentIsEditable, UserSelectAllTreatment treatment = UserSelectAllIsAlwaysNonEditable) const + bool hasEditableStyle(UserSelectAllTreatment treatment = UserSelectAllIsAlwaysNonEditable) const { - switch (editableType) { - case ContentIsEditable: - return hasEditableStyle(Editable, treatment); - case HasEditableAXRole: - return isEditableToAccessibility(Editable); - } - ASSERT_NOT_REACHED(); - return false; + return computeEditability(treatment, ShouldUpdateStyle::DoNotUpdate) != Editability::ReadOnly; } - - bool hasRichlyEditableStyle(EditableType editableType = ContentIsEditable) const + // FIXME: Replace every use of this function by helpers in htmlediting.h + bool hasRichlyEditableStyle() const { - switch (editableType) { - case ContentIsEditable: - return hasEditableStyle(RichlyEditable, UserSelectAllIsAlwaysNonEditable); - case HasEditableAXRole: - return isEditableToAccessibility(RichlyEditable); - } - ASSERT_NOT_REACHED(); - return false; + return computeEditability(UserSelectAllIsAlwaysNonEditable, ShouldUpdateStyle::DoNotUpdate) == Editability::CanEditRichly; } - virtual LayoutRect boundingBox() const; - IntRect pixelSnappedBoundingBox() const { return pixelSnappedIntRect(boundingBox()); } - LayoutRect renderRect(bool* isReplaced); - IntRect pixelSnappedRenderRect(bool* isReplaced) { return pixelSnappedIntRect(renderRect(isReplaced)); } + enum class Editability { ReadOnly, CanEditPlainText, CanEditRichly }; + enum class ShouldUpdateStyle { Update, DoNotUpdate }; + WEBCORE_EXPORT Editability computeEditability(UserSelectAllTreatment, ShouldUpdateStyle) const; - unsigned nodeIndex() const; + WEBCORE_EXPORT LayoutRect renderRect(bool* isReplaced); + IntRect pixelSnappedRenderRect(bool* isReplaced) { return snappedIntRect(renderRect(isReplaced)); } - // Returns the DOM ownerDocument attribute. This method never returns 0, except in the case + WEBCORE_EXPORT unsigned computeNodeIndex() const; + + // Returns the DOM ownerDocument attribute. This method never returns null, except in the case // of a Document node. - Document* ownerDocument() const; + WEBCORE_EXPORT Document* ownerDocument() const; - // Returns the document associated with this node. This method never returns 0. + // Returns the document associated with this node. // A Document node returns itself. Document& document() const { - ASSERT(this); - ASSERT(documentInternal()); - return *documentInternal(); + return treeScope().documentScope(); } TreeScope& treeScope() const @@ -392,28 +369,30 @@ public: ASSERT(m_treeScope); return *m_treeScope; } + static ptrdiff_t treeScopeMemoryOffset() { return OBJECT_OFFSETOF(Node, m_treeScope); } // Returns true if this node is associated with a document and is in its associated document's - // node tree, false otherwise. - bool inDocument() const + // node tree, false otherwise (https://dom.spec.whatwg.org/#connected). + bool isConnected() const { - ASSERT(documentInternal() || !getFlag(InDocumentFlag)); - return getFlag(InDocumentFlag); + return getFlag(IsConnectedFlag); } + bool isInUserAgentShadowTree() const; bool isInShadowTree() const { return getFlag(IsInShadowTreeFlag); } - bool isInTreeScope() const { return getFlag(static_cast<NodeFlags>(InDocumentFlag | IsInShadowTreeFlag)); } + bool isInTreeScope() const { return getFlag(static_cast<NodeFlags>(IsConnectedFlag | IsInShadowTreeFlag)); } - bool isReadOnlyNode() const { return nodeType() == ENTITY_REFERENCE_NODE; } bool isDocumentTypeNode() const { return nodeType() == DOCUMENT_TYPE_NODE; } virtual bool childTypeAllowed(NodeType) const { return false; } - unsigned childNodeCount() const; - Node* childNode(unsigned index) const; + unsigned countChildNodes() const; + Node* traverseToChildAt(unsigned) const; + + ExceptionOr<void> checkSetPrefix(const AtomicString& prefix); - void checkSetPrefix(const AtomicString& prefix, ExceptionCode&); + WEBCORE_EXPORT bool isDescendantOf(const Node&) const; + bool isDescendantOf(const Node* other) const { return other && isDescendantOf(*other); } - bool isDescendantOf(const Node*) const; bool isDescendantOrShadowDescendantOf(const Node*) const; - bool contains(const Node*) const; + WEBCORE_EXPORT bool contains(const Node*) const; bool containsIncludingShadowDOM(const Node*) const; bool containsIncludingHostElements(const Node*) const; @@ -426,6 +405,8 @@ public: // Whether or not a selection can be started in this object virtual bool canStartSelection() const; + virtual bool shouldSelectOnMouseDown() { return false; } + // Getting points into and out of screen space FloatPoint convertToPage(const FloatPoint&) const; FloatPoint convertFromPage(const FloatPoint&) const; @@ -444,13 +425,13 @@ public: } // Use these two methods with caution. - RenderBox* renderBox() const; + WEBCORE_EXPORT RenderBox* renderBox() const; RenderBoxModelObject* renderBoxModelObject() const; // Wrapper for nodes that don't have a renderer, but still cache the style (like HTMLOptionElement). - RenderStyle* renderStyle() const; + const RenderStyle* renderStyle() const; - virtual RenderStyle* computedStyle(PseudoId pseudoElementSpecifier = NOPSEUDO); + virtual const RenderStyle* computedStyle(PseudoId pseudoElementSpecifier = NOPSEUDO); // ----------------------------------------------------------------------------- // Notification of document structure changes (see ContainerNode.h for more notification methods) @@ -461,20 +442,20 @@ public: // dispatching. // // WebKit notifies this callback regardless if the subtree of the node is a document tree or a floating subtree. - // Implementation can determine the type of subtree by seeing insertionPoint->inDocument(). + // Implementation can determine the type of subtree by seeing insertionPoint->isConnected(). // For a performance reason, notifications are delivered only to ContainerNode subclasses if the insertionPoint is out of document. // - // There are another callback named didNotifyDescendantInsertions(), which is called after all the descendant is notified. - // Only a few subclasses actually need this. To utilize this, the node should return InsertionShouldCallDidNotifyDescendantInsertions + // There is another callback named finishedInsertingSubtree(), which is called after all descendants are notified. + // Only a few subclasses actually need this. To utilize this, the node should return InsertionShouldCallFinishedInsertingSubtree // from insrtedInto(). // enum InsertionNotificationRequest { InsertionDone, - InsertionShouldCallDidNotifySubtreeInsertions + InsertionShouldCallFinishedInsertingSubtree }; virtual InsertionNotificationRequest insertedInto(ContainerNode& insertionPoint); - virtual void didNotifySubtreeInsertions(ContainerNode*) { } + virtual void finishedInsertingSubtree() { } // Notifies the node that it is no longer part of the tree. // @@ -483,17 +464,17 @@ public: // virtual void removedFrom(ContainerNode& insertionPoint); -#ifndef NDEBUG +#if ENABLE(TREE_DEBUGGING) virtual void formatForDebugger(char* buffer, unsigned length) const; void showNode(const char* prefix = "") const; void showTreeForThis() const; void showNodePathForThis() const; - void showTreeAndMark(const Node* markedNode1, const char* markedLabel1, const Node* markedNode2 = 0, const char* markedLabel2 = 0) const; + void showTreeAndMark(const Node* markedNode1, const char* markedLabel1, const Node* markedNode2 = nullptr, const char* markedLabel2 = nullptr) const; void showTreeForThisAcrossFrame() const; -#endif +#endif // ENABLE(TREE_DEBUGGING) - void invalidateNodeListAndCollectionCachesInAncestors(const QualifiedName* attrName = 0, Element* attributeOwnerElement = 0); + void invalidateNodeListAndCollectionCachesInAncestors(const QualifiedName* attrName = nullptr, Element* attributeOwnerElement = nullptr); NodeListsNodeData* nodeLists(); void clearNodeLists(); @@ -501,55 +482,63 @@ public: virtual bool willRespondToMouseClickEvents(); virtual bool willRespondToMouseWheelEvents(); - unsigned short compareDocumentPosition(Node*); + WEBCORE_EXPORT unsigned short compareDocumentPosition(Node&); - virtual Node* toNode() override; - virtual HTMLInputElement* toInputElement(); + Node* toNode() override; - virtual EventTargetInterface eventTargetInterface() const override; - virtual ScriptExecutionContext* scriptExecutionContext() const override final; // Implemented in Document.h + EventTargetInterface eventTargetInterface() const override; + ScriptExecutionContext* scriptExecutionContext() const final; // Implemented in Document.h - virtual bool addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture) override; - virtual bool removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture) override; + bool addEventListener(const AtomicString& eventType, Ref<EventListener>&&, const AddEventListenerOptions&) override; + bool removeEventListener(const AtomicString& eventType, EventListener&, const ListenerOptions&) override; using EventTarget::dispatchEvent; - virtual bool dispatchEvent(PassRefPtr<Event>) override; + bool dispatchEvent(Event&) override; - void dispatchScopedEvent(PassRefPtr<Event>); + void dispatchScopedEvent(Event&); virtual void handleLocalEvents(Event&); void dispatchSubtreeModifiedEvent(); - bool dispatchDOMActivateEvent(int detail, PassRefPtr<Event> underlyingEvent); + bool dispatchDOMActivateEvent(int detail, Event& underlyingEvent); -#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS) - bool dispatchTouchEvent(PassRefPtr<TouchEvent>); -#endif -#if ENABLE(INDIE_UI) - bool dispatchUIRequestEvent(PassRefPtr<UIRequestEvent>); +#if ENABLE(TOUCH_EVENTS) + virtual bool allowsDoubleTapGesture() const { return true; } #endif +#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS) + bool dispatchTouchEvent(TouchEvent&); +#endif bool dispatchBeforeLoadEvent(const String& sourceURL); - virtual void dispatchInputEvent(); + void dispatchInputEvent(); // Perform the default action for an event. - virtual void defaultEventHandler(Event*); + virtual void defaultEventHandler(Event&); - using TreeShared<Node>::ref; - using TreeShared<Node>::deref; + void ref(); + void deref(); + bool hasOneRef() const; + int refCount() const; + +#ifndef NDEBUG + bool m_deletionHasBegun { false }; + bool m_inRemovedLastRefFunction { false }; + bool m_adoptionIsRequired { true }; +#endif - virtual EventTargetData* eventTargetData() override final; - virtual EventTargetData& ensureEventTargetData() override final; + EventTargetData* eventTargetData() final; + EventTargetData* eventTargetDataConcurrently() final; + EventTargetData& ensureEventTargetData() final; - void getRegisteredMutationObserversOfType(HashMap<MutationObserver*, MutationRecordDeliveryOptions>&, MutationObserver::MutationType, const QualifiedName* attributeName); - void registerMutationObserver(MutationObserver*, MutationObserverOptions, const HashSet<AtomicString>& attributeFilter); - void unregisterMutationObserver(MutationObserverRegistration*); - void registerTransientMutationObserver(MutationObserverRegistration*); - void unregisterTransientMutationObserver(MutationObserverRegistration*); + HashMap<MutationObserver*, MutationRecordDeliveryOptions> registeredMutationObservers(MutationObserver::MutationType, const QualifiedName* attributeName); + void registerMutationObserver(MutationObserver&, MutationObserverOptions, const HashSet<AtomicString>& attributeFilter); + void unregisterMutationObserver(MutationObserverRegistration&); + void registerTransientMutationObserver(MutationObserverRegistration&); + void unregisterTransientMutationObserver(MutationObserverRegistration&); void notifyMutationObserversNodeWillDetach(); - void textRects(Vector<IntRect>&) const; + WEBCORE_EXPORT void textRects(Vector<IntRect>&) const; unsigned connectedSubframeCount() const; void incrementConnectedSubframeCount(unsigned amount = 1); @@ -557,13 +546,23 @@ public: void updateAncestorConnectedSubframeCountForRemoval() const; void updateAncestorConnectedSubframeCountForInsertion() const; - void markAncestorsWithChildNeedsStyleRecalc(); - -#if ENABLE(CSS_SELECTOR_JIT) +#if ENABLE(JIT) static ptrdiff_t nodeFlagsMemoryOffset() { return OBJECT_OFFSETOF(Node, m_nodeFlags); } + static ptrdiff_t rareDataMemoryOffset() { return OBJECT_OFFSETOF(Node, m_data.m_rareData); } + static int32_t flagIsText() { return IsTextFlag; } + static int32_t flagIsContainer() { return IsContainerFlag; } static int32_t flagIsElement() { return IsElementFlag; } + static int32_t flagIsHTML() { return IsHTMLFlag; } static int32_t flagIsLink() { return IsLinkFlag; } -#endif // ENABLE(CSS_SELECTOR_JIT) + static int32_t flagHasFocusWithin() { return HasFocusWithin; } + static int32_t flagHasRareData() { return HasRareDataFlag; } + static int32_t flagIsParsingChildrenFinished() { return IsParsingChildrenFinishedFlag; } + static int32_t flagChildrenAffectedByFirstChildRulesFlag() { return ChildrenAffectedByFirstChildRulesFlag; } + static int32_t flagChildrenAffectedByLastChildRulesFlag() { return ChildrenAffectedByLastChildRulesFlag; } + + static int32_t flagAffectsNextSiblingElementStyle() { return AffectsNextSiblingElementStyle; } + static int32_t flagStyleIsAffectedByPreviousSibling() { return StyleIsAffectedByPreviousSibling; } +#endif // ENABLE(JIT) protected: enum NodeFlags { @@ -574,7 +573,7 @@ protected: IsHTMLFlag = 1 << 4, IsSVGFlag = 1 << 5, ChildNeedsStyleRecalcFlag = 1 << 7, - InDocumentFlag = 1 << 8, + IsConnectedFlag = 1 << 8, IsLinkFlag = 1 << 9, IsUserActionElement = 1 << 10, HasRareDataFlag = 1 << 11, @@ -583,23 +582,27 @@ protected: // These bits are used by derived classes, pulled up here so they can // be stored in the same memory word as the Node bits above. IsParsingChildrenFinishedFlag = 1 << 13, // Element - - StyleChangeMask = 1 << nodeStyleChangeShift | 1 << (nodeStyleChangeShift + 1) | 1 << (nodeStyleChangeShift + 2), - IsEditingTextFlag = 1 << 17, - InNamedFlowFlag = 1 << 18, + StyleValidityShift = 14, + StyleValidityMask = 3 << StyleValidityShift, + StyleResolutionShouldRecompositeLayerFlag = 1 << 16, + IsEditingTextOrUndefinedCustomElementFlag = 1 << 17, + HasFocusWithin = 1 << 18, HasSyntheticAttrChildNodesFlag = 1 << 19, HasCustomStyleResolveCallbacksFlag = 1 << 20, HasEventTargetDataFlag = 1 << 21, - NeedsNodeRenderingTraversalSlowPathFlag = 1 << 22, + IsCustomElement = 1 << 22, IsInShadowTreeFlag = 1 << 23, IsMathMLFlag = 1 << 24, ChildrenAffectedByFirstChildRulesFlag = 1 << 25, ChildrenAffectedByLastChildRulesFlag = 1 << 26, - ChildrenAffectedByDirectAdjacentRulesFlag = 1 << 27, - ChildrenAffectedByHoverRulesFlag = 1 << 28, + ChildrenAffectedByHoverRulesFlag = 1 << 27, + + DirectChildNeedsStyleRecalcFlag = 1 << 28, + AffectsNextSiblingElementStyle = 1 << 29, + StyleIsAffectedByPreviousSibling = 1 << 30, - SelfOrAncestorHasDirAutoFlag = 1 << 29, + SelfOrAncestorHasDirAutoFlag = 1 << 31, DefaultNodeFlags = IsParsingChildrenFinishedFlag }; @@ -614,20 +617,19 @@ protected: CreateText = DefaultNodeFlags | IsTextFlag, CreateContainer = DefaultNodeFlags | IsContainerFlag, CreateElement = CreateContainer | IsElementFlag, - CreatePseudoElement = CreateElement | InDocumentFlag | NeedsNodeRenderingTraversalSlowPathFlag, - CreateShadowRoot = CreateContainer | IsDocumentFragmentFlag | NeedsNodeRenderingTraversalSlowPathFlag | IsInShadowTreeFlag, + CreatePseudoElement = CreateElement | IsConnectedFlag, + CreateShadowRoot = CreateContainer | IsDocumentFragmentFlag | IsInShadowTreeFlag, CreateDocumentFragment = CreateContainer | IsDocumentFragmentFlag, CreateStyledElement = CreateElement | IsStyledElementFlag, CreateHTMLElement = CreateStyledElement | IsHTMLFlag, CreateSVGElement = CreateStyledElement | IsSVGFlag | HasCustomStyleResolveCallbacksFlag, - CreateDocument = CreateContainer | InDocumentFlag, - CreateInsertionPoint = CreateHTMLElement | NeedsNodeRenderingTraversalSlowPathFlag, - CreateEditingText = CreateText | IsEditingTextFlag, - CreateMathMLElement = CreateStyledElement | IsMathMLFlag, + CreateDocument = CreateContainer | IsConnectedFlag, + CreateEditingText = CreateText | IsEditingTextOrUndefinedCustomElementFlag, + CreateMathMLElement = CreateStyledElement | IsMathMLFlag }; - Node(Document*, ConstructionType); + Node(Document&, ConstructionType); - virtual void didMoveToNewDocument(Document* oldDocument); + virtual void didMoveToNewDocument(Document& oldDocument); virtual void addSubresourceAttributeURLs(ListHashSet<URL>&) const { } @@ -641,52 +643,47 @@ protected: void setHasCustomStyleResolveCallbacks() { setFlag(true, HasCustomStyleResolveCallbacksFlag); } - void setNeedsNodeRenderingTraversalSlowPath(bool flag) { setFlag(flag, NeedsNodeRenderingTraversalSlowPathFlag); } - - Document* documentInternal() const { return treeScope().documentScope(); } void setTreeScope(TreeScope& scope) { m_treeScope = &scope; } - void setStyleChange(StyleChangeType changeType) { m_nodeFlags = (m_nodeFlags & ~StyleChangeMask) | changeType; } + void invalidateStyle(Style::Validity, Style::InvalidationMode = Style::InvalidationMode::Normal); + void updateAncestorsForStyleRecalc(); -private: - friend class TreeShared<Node>; + ExceptionOr<RefPtr<Node>> convertNodesOrStringsIntoNode(Vector<NodeOrString>&&); +private: virtual PseudoId customPseudoId() const { ASSERT(hasCustomStyleResolveCallbacks()); return NOPSEUDO; } - void removedLastRef(); - bool hasTreeSharedParent() const { return !!parentNode(); } + WEBCORE_EXPORT void removedLastRef(); - enum EditableLevel { Editable, RichlyEditable }; - bool hasEditableStyle(EditableLevel, UserSelectAllTreatment = UserSelectAllIsAlwaysNonEditable) const; - bool isEditableToAccessibility(EditableLevel) const; - - virtual void refEventTarget() override; - virtual void derefEventTarget() override; - - virtual RenderStyle* nonRendererStyle() const { return 0; } - - Element* ancestorElement() const; + void refEventTarget() override; + void derefEventTarget() override; void trackForDebugging(); + void materializeRareData(); - Vector<OwnPtr<MutationObserverRegistration>>* mutationObserverRegistry(); + Vector<std::unique_ptr<MutationObserverRegistration>>* mutationObserverRegistry(); HashSet<MutationObserverRegistration*>* transientMutationObserverRegistry(); + void adjustStyleValidity(Style::Validity, Style::InvalidationMode); + + void* opaqueRootSlow() const; + + int m_refCount; mutable uint32_t m_nodeFlags; - ContainerNode* m_parentNode; - TreeScope* m_treeScope; - Node* m_previous; - Node* m_next; + + ContainerNode* m_parentNode { nullptr }; + TreeScope* m_treeScope { nullptr }; + Node* m_previous { nullptr }; + Node* m_next { nullptr }; // When a node has rare data we move the renderer into the rare data. union DataUnion { - DataUnion() : m_renderer(0) { } RenderObject* m_renderer; NodeRareDataBase* m_rareData; - } m_data; + } m_data { nullptr }; protected: bool isParsingChildrenFinished() const { return getFlag(IsParsingChildrenFinishedFlag); } @@ -694,6 +691,53 @@ protected: void clearIsParsingChildrenFinished() { clearFlag(IsParsingChildrenFinishedFlag); } }; +#ifndef NDEBUG +inline void adopted(Node* node) +{ + if (!node) + return; + ASSERT(!node->m_deletionHasBegun); + ASSERT(!node->m_inRemovedLastRefFunction); + node->m_adoptionIsRequired = false; +} +#endif + +ALWAYS_INLINE void Node::ref() +{ + ASSERT(isMainThread()); + ASSERT(!m_deletionHasBegun); + ASSERT(!m_inRemovedLastRefFunction); + ASSERT(!m_adoptionIsRequired); + ++m_refCount; +} + +ALWAYS_INLINE void Node::deref() +{ + ASSERT(isMainThread()); + ASSERT(m_refCount >= 0); + ASSERT(!m_deletionHasBegun); + ASSERT(!m_inRemovedLastRefFunction); + ASSERT(!m_adoptionIsRequired); + if (--m_refCount <= 0 && !parentNode()) { +#ifndef NDEBUG + m_inRemovedLastRefFunction = true; +#endif + removedLastRef(); + } +} + +ALWAYS_INLINE bool Node::hasOneRef() const +{ + ASSERT(!m_deletionHasBegun); + ASSERT(!m_inRemovedLastRefFunction); + return m_refCount == 1; +} + +ALWAYS_INLINE int Node::refCount() const +{ + return m_refCount; +} + // Used in Node::addSubresourceAttributeURLs() and in addSubresourceStyleURLs() inline void addSubresourceURL(ListHashSet<URL>& urls, const URL& url) { @@ -713,21 +757,41 @@ inline ContainerNode* Node::parentNode() const return m_parentNode; } +inline void* Node::opaqueRoot() const +{ + // FIXME: Possible race? + // https://bugs.webkit.org/show_bug.cgi?id=165713 + if (isConnected()) + return &document(); + return opaqueRootSlow(); +} + inline ContainerNode* Node::parentNodeGuaranteedHostFree() const { ASSERT(!isShadowRoot()); return parentNode(); } -#define NODE_TYPE_CASTS(ToClassName) \ - TYPE_CASTS_BASE(ToClassName, Node, node, WebCore::is##ToClassName(*node), WebCore::is##ToClassName(node)) +inline Style::Validity Node::styleValidity() const +{ + return static_cast<Style::Validity>((m_nodeFlags & StyleValidityMask) >> StyleValidityShift); +} + +inline bool Node::styleResolutionShouldRecompositeLayer() const +{ + return getFlag(StyleResolutionShouldRecompositeLayerFlag); +} + +inline void Node::setHasValidStyle() +{ + m_nodeFlags &= ~StyleValidityMask; + clearFlag(StyleResolutionShouldRecompositeLayerFlag); +} } // namespace WebCore -#ifndef NDEBUG -// Outside the WebCore namespace for ease of invocation from gdb. +#if ENABLE(TREE_DEBUGGING) +// Outside the WebCore namespace for ease of invocation from the debugger. void showTree(const WebCore::Node*); void showNodePath(const WebCore::Node*); #endif - -#endif |