/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsINode_h_ #define nsINode_h_ #include #include #include "js/TypeDecls.h" // for Handle, Value, JSObject, JSContext #include "mozilla/DoublyLinkedList.h" #include "mozilla/UniquePtr.h" #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/DOMString.h" #include "mozilla/dom/EventTarget.h" // for base class #include "mozilla/dom/NodeInfo.h" // member (in nsCOMPtr) #include "nsCOMPtr.h" // for member, local #include "nsGkAtoms.h" // for nsGkAtoms::baseURIProperty #include "nsIMutationObserver.h" #include "nsIWeakReference.h" #include "nsNodeInfoManager.h" // for use in NodePrincipal() #include "nsPropertyTable.h" // for typedefs // Including 'windows.h' will #define GetClassInfo to something else. #ifdef XP_WIN # ifdef GetClassInfo # undef GetClassInfo # endif #endif class AttrArray; class nsAttrChildContentList; template class nsCOMArray; class nsDOMAttributeMap; class nsFrameSelection; class nsGenericHTMLElement; class nsIAnimationObserver; class nsIContent; class nsIContentSecurityPolicy; class nsIFrame; class nsIFormControl; class nsMultiMutationObserver; class nsINode; class nsIPolicyContainer; class nsIPrincipal; class nsIURI; class nsNodeSupportsWeakRefTearoff; class nsDOMMutationObserver; class nsRange; class nsWindowSizes; namespace mozilla { class EventListenerManager; struct StyleSelectorList; template class Maybe; template class LinkedList; class ErrorResult; class PresShell; class TextEditor; class WidgetEvent; namespace dom { class NodeList; class HTMLCollection; /** * @return true if aChar is what the WHATWG defines as a 'ascii whitespace'. * https://infra.spec.whatwg.org/#ascii-whitespace */ inline bool IsSpaceCharacter(char16_t aChar) { return aChar == ' ' || aChar == '\t' || aChar == '\n' || aChar == '\r' || aChar == '\f'; } inline bool IsSpaceCharacter(char aChar) { return aChar == ' ' || aChar == '\t' || aChar == '\n' || aChar == '\r' || aChar == '\f'; } class AbstractRange; class AccessibleNode; template class AncestorsOfTypeIterator; struct BoxQuadOptions; struct ConvertCoordinateOptions; class CustomElementRegistry; class DocGroup; class Document; class DocumentFragment; class DocumentOrShadowRoot; class DOMPoint; class DOMQuad; class DOMRectReadOnly; class Element; class EventHandlerNonNull; template class FlatTreeAncestorsOfTypeIterator; class HTMLDialogElement; class HTMLSlotElement; template class InclusiveAncestorsOfTypeIterator; template class InclusiveFlatTreeAncestorsOfTypeIterator; class LinkStyle; class MutationObservers; template class Optional; class OwningNodeOrString; class SelectionNodeCache; template class Sequence; class ShadowRoot; class SVGUseElement; class Text; class TextOrElementOrDocument; struct DOMPointInit; struct GetRootNodeOptions; enum class AllowRangeCrossShadowBoundary : bool; // defined in AbstractRange.h enum class CallerType : uint32_t; struct AriaNotificationOptions; } // namespace dom } // namespace mozilla #define NODE_FLAG_BIT(n_) \ (nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED + (n_))) enum : uint32_t { // This bit will be set if the node has a listener manager. NODE_HAS_LISTENERMANAGER = NODE_FLAG_BIT(0), // Whether this node has had any properties set on it NODE_HAS_PROPERTIES = NODE_FLAG_BIT(1), // Whether the node has some ancestor, possibly itself, that is native // anonymous. This includes ancestors crossing XBL scopes, in cases when an // XBL binding is attached to an element which has a native anonymous // ancestor. This flag is set-once: once a node has it, it must not be // removed. // NOTE: Should only be used on nsIContent nodes NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE = NODE_FLAG_BIT(2), // Whether this node is the root of a native anonymous (from the perspective // of its parent) subtree. This flag is set-once: once a node has it, it // must not be removed. // NOTE: Should only be used on nsIContent nodes NODE_IS_NATIVE_ANONYMOUS_ROOT = NODE_FLAG_BIT(3), NODE_IS_EDITABLE = NODE_FLAG_BIT(4), // Whether the node participates in a shadow tree. NODE_IS_IN_SHADOW_TREE = NODE_FLAG_BIT(5), // This node needs to go through frame construction to get a frame (or // undisplayed entry). NODE_NEEDS_FRAME = NODE_FLAG_BIT(6), // At least one descendant in the flattened tree has NODE_NEEDS_FRAME set. // This should be set on every node on the flattened tree path between the // node(s) with NODE_NEEDS_FRAME and the root content. NODE_DESCENDANTS_NEED_FRAMES = NODE_FLAG_BIT(7), // Set if the node has the accesskey attribute set. NODE_HAS_ACCESSKEY = NODE_FLAG_BIT(8), NODE_HAS_BEEN_IN_UA_WIDGET = NODE_FLAG_BIT(9), // Set if the node has a nonce value and a header delivered CSP. NODE_HAS_NONCE_AND_HEADER_CSP = NODE_FLAG_BIT(10), NODE_KEEPS_DOMARENA = NODE_FLAG_BIT(11), NODE_MAY_HAVE_ELEMENT_CHILDREN = NODE_FLAG_BIT(12), NODE_HAS_SCHEDULED_SELECTION_CHANGE_EVENT = NODE_FLAG_BIT(13), // Remaining bits are node type specific. NODE_TYPE_SPECIFIC_BITS_OFFSET = 14 }; // Flags for selectors that persist to the DOM node. enum class NodeSelectorFlags : uint32_t { // Node has an :empty or :-moz-only-whitespace selector HasEmptySelector = 1 << 0, /// A child of the node has a selector such that any insertion, /// removal, or appending of children requires restyling the parent, if the /// parent is an element. If the parent is the shadow root, the child's /// siblings are restyled. HasSlowSelector = 1 << 1, /// A child of the node has a :first-child, :-moz-first-node, /// :only-child, :last-child or :-moz-last-node selector. HasEdgeChildSelector = 1 << 2, /// A child of the node has a selector such that any insertion or /// removal of children requires restyling later siblings of that /// element. Additionally (in this manner it is stronger than /// NODE_HAS_SLOW_SELECTOR), if a child's style changes due to any /// other content tree changes (e.g., the child changes to or from /// matching :empty due to a grandchild insertion or removal), the /// child's later siblings must also be restyled. HasSlowSelectorLaterSiblings = 1 << 3, /// HasSlowSelector* was set by the presence of :nth (But not of). HasSlowSelectorNth = 1 << 4, /// A child of this node might be matched by :nth-child(.. of ) or /// :nth-last-child(.. of ). If a DOM mutation may have caused the /// selector to either match or no longer match that child, the child's /// siblings are restyled. HasSlowSelectorNthOf = 1 << 5, /// All instances of :nth flags. HasSlowSelectorNthAll = HasSlowSelectorNthOf | HasSlowSelectorNth, /// A child of this node may be using sibling-index() or sibling-count(), /// and must be recascaded if other children are added or removed. MayHaveTreeCountingFunction = 1 << 6, /// Set of selector flags that may trigger a restyle on DOM append, with /// restyle on siblings or a single parent (And perhaps their subtrees). AllSimpleRestyleFlagsForAppend = HasEmptySelector | HasSlowSelector | HasEdgeChildSelector | HasSlowSelectorNthAll | MayHaveTreeCountingFunction, /// Set of selector flags that may trigger a restyle as a result of any /// DOM mutation. AllSimpleRestyleFlags = AllSimpleRestyleFlagsForAppend | HasSlowSelectorLaterSiblings, // This node was evaluated as an anchor for a relative selector. RelativeSelectorAnchor = 1 << 7, // This node was evaluated as an anchor for a relative selector, and that // relative selector was not the subject of the overall selector. RelativeSelectorAnchorNonSubject = 1 << 8, // This node's sibling(s) performed a relative selector search to this node. RelativeSelectorSearchDirectionSibling = 1 << 9, // This node's ancestor(s) performed a relative selector search to this node. RelativeSelectorSearchDirectionAncestor = 1 << 10, // This node's sibling(s) and ancestor(s), and/or this node's ancestor's // sibling(s) performed a relative selector search to this node. RelativeSelectorSearchDirectionAncestorSibling = RelativeSelectorSearchDirectionSibling | RelativeSelectorSearchDirectionAncestor, }; MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(NodeSelectorFlags); enum class BatchRemovalOrder { FrontToBack, BackToFront, }; struct BatchRemovalState { // Whether we're the fist kid getting removed in the batch. Note that that's // different to whether we're the first _child_, if we're removing // back-to-front. bool mIsFirst = true; }; // Make sure we have space for our bits #define ASSERT_NODE_FLAGS_SPACE(n) \ static_assert(WRAPPER_CACHE_FLAGS_BITS_USED + (n) <= \ sizeof(nsWrapperCache::FlagsType) * 8, \ "Not enough space for our bits") ASSERT_NODE_FLAGS_SPACE(NODE_TYPE_SPECIFIC_BITS_OFFSET); /** * Class used to detect unexpected mutations. To use the class create an * nsMutationGuard on the stack before unexpected mutations could occur. * You can then at any time call Mutated to check if any unexpected mutations * have occurred. * * NOTE: There is SelectionChangeGuard which manages the generation of selection * ranges. If you need to fix a bug of this class, you need to touch * SelectionChangeGuard too. */ class nsMutationGuard { public: nsMutationGuard() { mStartingGeneration = sGeneration; } /** * Returns true if any unexpected mutations have occurred. You can pass in * an 8-bit ignore count to ignore a number of expected mutations. * * We don't need to care about overflow because subtraction of uint64_t's is * finding the difference between two elements of the group Z < 2^64. Once * we know the difference between two elements we only need to check that is * less than the given number of mutations to know less than that many * mutations occurred. Assuming constant 1ns mutations it would take 584 * years for sGeneration to fully wrap around so we can ignore a guard living * through a full wrap around. */ bool Mutated(uint8_t aIgnoreCount) const { return (sGeneration - mStartingGeneration) > aIgnoreCount; } // This function should be called whenever a mutation that we want to keep // track of happen. For now this is only done when children are added or // removed, but we might do it for attribute changes too in the future. static void DidMutate() { sGeneration++; } private: // This is the value sGeneration had when the guard was constructed. uint64_t mStartingGeneration; // This value is incremented on every mutation, for the life of the process. static uint64_t sGeneration; }; /** * A class that implements nsIWeakReference */ class nsNodeWeakReference final : public nsIWeakReference { public: explicit nsNodeWeakReference(nsINode* aNode); // nsISupports NS_DECL_ISUPPORTS // nsIWeakReference NS_DECL_NSIWEAKREFERENCE void NoticeNodeDestruction() { mObject = nullptr; } private: ~nsNodeWeakReference(); }; enum class TreeKind : uint8_t { // The simplest DOM, won't get ShadowRoot from the parent. // FYI: This is a good TreeKind for the cases which won't cross Shadow DOM // boundaries. E.g., for the editor. DOM, // Treat attached ShadowRoot as a child before its first child. However, // non-content shadow is ignored because they must have s to use the // direct child of the host, but in this mode, is treated as not having // assigned nodes. // FYI: This is a good TreeKind for comparing the range boundaries of // TreeKind::DOM. // NOTE: When comparing 2 points with nsContentUtils::ComparePoints or its // relatives in the shadow including DOM, the points may be treated as in the // simple DOM tree because a point is in a shadow host is a valid point for // RangeBoundaryBase. Therefore, they can compare points across shadow DOM // boundaries but they also may compare children of a shadow host which are // replaced with the shadow root in the shadow including DOM. ShadowIncludingDOM, // Handle the flattened tree which assigned nodes of are treated as // children of the . // FYI: This is a good TreeKind for the cases which need to work with the // visual order and/or any visible nodes. E.g., for the layout module. Flat, // Handle the flattened tree for Selection. Selection API accepts any nodes in // the DOM as a container of a range boundary. I.e., even if a node is not // part of the flattened tree. On the other hand, shadow for UA shadow DOM for // elements such as
,