nsINode.h (107682B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef nsINode_h___ 8 #define nsINode_h___ 9 10 #include <iosfwd> 11 12 #include "js/TypeDecls.h" // for Handle, Value, JSObject, JSContext 13 #include "mozilla/DoublyLinkedList.h" 14 #include "mozilla/ErrorResult.h" 15 #include "mozilla/Likely.h" 16 #include "mozilla/LinkedList.h" 17 #include "mozilla/UniquePtr.h" 18 #include "mozilla/dom/BindingDeclarations.h" 19 #include "mozilla/dom/DOMString.h" 20 #include "mozilla/dom/EventTarget.h" // for base class 21 #include "mozilla/dom/NodeBinding.h" 22 #include "mozilla/dom/NodeInfo.h" // member (in nsCOMPtr) 23 #include "nsCOMPtr.h" // for member, local 24 #include "nsGkAtoms.h" // for nsGkAtoms::baseURIProperty 25 #include "nsIMutationObserver.h" 26 #include "nsIWeakReference.h" 27 #include "nsNodeInfoManager.h" // for use in NodePrincipal() 28 #include "nsPropertyTable.h" // for typedefs 29 #include "nsTHashtable.h" 30 31 // Including 'windows.h' will #define GetClassInfo to something else. 32 #ifdef XP_WIN 33 # ifdef GetClassInfo 34 # undef GetClassInfo 35 # endif 36 #endif 37 38 class AttrArray; 39 class nsAttrChildContentList; 40 template <typename T> 41 class nsCOMArray; 42 class nsDOMAttributeMap; 43 class nsFrameSelection; 44 class nsGenericHTMLElement; 45 class nsIAnimationObserver; 46 class nsIContent; 47 class nsIContentSecurityPolicy; 48 class nsIFrame; 49 class nsIFormControl; 50 class nsIHTMLCollection; 51 class nsMultiMutationObserver; 52 class nsINode; 53 class nsINodeList; 54 class nsIPolicyContainer; 55 class nsIPrincipal; 56 class nsIURI; 57 class nsNodeSupportsWeakRefTearoff; 58 class nsDOMMutationObserver; 59 class nsRange; 60 class nsWindowSizes; 61 62 namespace mozilla { 63 class EventListenerManager; 64 struct StyleSelectorList; 65 template <typename T> 66 class Maybe; 67 class PresShell; 68 class TextEditor; 69 class WidgetEvent; 70 namespace dom { 71 /** 72 * @return true if aChar is what the WHATWG defines as a 'ascii whitespace'. 73 * https://infra.spec.whatwg.org/#ascii-whitespace 74 */ 75 inline bool IsSpaceCharacter(char16_t aChar) { 76 return aChar == ' ' || aChar == '\t' || aChar == '\n' || aChar == '\r' || 77 aChar == '\f'; 78 } 79 inline bool IsSpaceCharacter(char aChar) { 80 return aChar == ' ' || aChar == '\t' || aChar == '\n' || aChar == '\r' || 81 aChar == '\f'; 82 } 83 class AbstractRange; 84 class AccessibleNode; 85 template <typename T> 86 class AncestorsOfTypeIterator; 87 struct BoxQuadOptions; 88 struct ConvertCoordinateOptions; 89 class DocGroup; 90 class Document; 91 class DocumentFragment; 92 class DocumentOrShadowRoot; 93 class DOMPoint; 94 class DOMQuad; 95 class DOMRectReadOnly; 96 class Element; 97 class EventHandlerNonNull; 98 template <typename T> 99 class FlatTreeAncestorsOfTypeIterator; 100 class HTMLDialogElement; 101 template <typename T> 102 class InclusiveAncestorsOfTypeIterator; 103 template <typename T> 104 class InclusiveFlatTreeAncestorsOfTypeIterator; 105 class LinkStyle; 106 class MutationObservers; 107 template <typename T> 108 class Optional; 109 class OwningNodeOrString; 110 class SelectionNodeCache; 111 template <typename> 112 class Sequence; 113 class ShadowRoot; 114 class SVGUseElement; 115 class Text; 116 class TextOrElementOrDocument; 117 struct DOMPointInit; 118 struct GetRootNodeOptions; 119 enum class AllowRangeCrossShadowBoundary : bool; // defined in AbstractRange.h 120 enum class CallerType : uint32_t; 121 } // namespace dom 122 } // namespace mozilla 123 124 #define NODE_FLAG_BIT(n_) \ 125 (nsWrapperCache::FlagsType(1U) << (WRAPPER_CACHE_FLAGS_BITS_USED + (n_))) 126 127 enum : uint32_t { 128 // This bit will be set if the node has a listener manager. 129 NODE_HAS_LISTENERMANAGER = NODE_FLAG_BIT(0), 130 131 // Whether this node has had any properties set on it 132 NODE_HAS_PROPERTIES = NODE_FLAG_BIT(1), 133 134 // Whether the node has some ancestor, possibly itself, that is native 135 // anonymous. This includes ancestors crossing XBL scopes, in cases when an 136 // XBL binding is attached to an element which has a native anonymous 137 // ancestor. This flag is set-once: once a node has it, it must not be 138 // removed. 139 // NOTE: Should only be used on nsIContent nodes 140 NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE = NODE_FLAG_BIT(2), 141 142 // Whether this node is the root of a native anonymous (from the perspective 143 // of its parent) subtree. This flag is set-once: once a node has it, it 144 // must not be removed. 145 // NOTE: Should only be used on nsIContent nodes 146 NODE_IS_NATIVE_ANONYMOUS_ROOT = NODE_FLAG_BIT(3), 147 148 NODE_IS_EDITABLE = NODE_FLAG_BIT(4), 149 150 // Whether the node participates in a shadow tree. 151 NODE_IS_IN_SHADOW_TREE = NODE_FLAG_BIT(5), 152 153 // This node needs to go through frame construction to get a frame (or 154 // undisplayed entry). 155 NODE_NEEDS_FRAME = NODE_FLAG_BIT(6), 156 157 // At least one descendant in the flattened tree has NODE_NEEDS_FRAME set. 158 // This should be set on every node on the flattened tree path between the 159 // node(s) with NODE_NEEDS_FRAME and the root content. 160 NODE_DESCENDANTS_NEED_FRAMES = NODE_FLAG_BIT(7), 161 162 // Set if the node has the accesskey attribute set. 163 NODE_HAS_ACCESSKEY = NODE_FLAG_BIT(8), 164 165 NODE_HAS_BEEN_IN_UA_WIDGET = NODE_FLAG_BIT(9), 166 167 // Set if the node has a nonce value and a header delivered CSP. 168 NODE_HAS_NONCE_AND_HEADER_CSP = NODE_FLAG_BIT(10), 169 170 NODE_KEEPS_DOMARENA = NODE_FLAG_BIT(11), 171 172 NODE_MAY_HAVE_ELEMENT_CHILDREN = NODE_FLAG_BIT(12), 173 174 NODE_HAS_SCHEDULED_SELECTION_CHANGE_EVENT = NODE_FLAG_BIT(13), 175 176 // Remaining bits are node type specific. 177 NODE_TYPE_SPECIFIC_BITS_OFFSET = 14 178 }; 179 180 // Flags for selectors that persist to the DOM node. 181 enum class NodeSelectorFlags : uint32_t { 182 // Node has an :empty or :-moz-only-whitespace selector 183 HasEmptySelector = 1 << 0, 184 185 /// A child of the node has a selector such that any insertion, 186 /// removal, or appending of children requires restyling the parent, if the 187 /// parent is an element. If the parent is the shadow root, the child's 188 /// siblings are restyled. 189 HasSlowSelector = 1 << 1, 190 191 /// A child of the node has a :first-child, :-moz-first-node, 192 /// :only-child, :last-child or :-moz-last-node selector. 193 HasEdgeChildSelector = 1 << 2, 194 195 /// A child of the node has a selector such that any insertion or 196 /// removal of children requires restyling later siblings of that 197 /// element. Additionally (in this manner it is stronger than 198 /// NODE_HAS_SLOW_SELECTOR), if a child's style changes due to any 199 /// other content tree changes (e.g., the child changes to or from 200 /// matching :empty due to a grandchild insertion or removal), the 201 /// child's later siblings must also be restyled. 202 HasSlowSelectorLaterSiblings = 1 << 3, 203 204 /// HasSlowSelector* was set by the presence of :nth (But not of). 205 HasSlowSelectorNth = 1 << 4, 206 207 /// A child of this node might be matched by :nth-child(.. of <selector>) or 208 /// :nth-last-child(.. of <selector>). If a DOM mutation may have caused the 209 /// selector to either match or no longer match that child, the child's 210 /// siblings are restyled. 211 HasSlowSelectorNthOf = 1 << 5, 212 213 /// All instances of :nth flags. 214 HasSlowSelectorNthAll = HasSlowSelectorNthOf | HasSlowSelectorNth, 215 216 /// Set of selector flags that may trigger a restyle on DOM append, with 217 /// restyle on siblings or a single parent (And perhaps their subtrees). 218 AllSimpleRestyleFlagsForAppend = HasEmptySelector | HasSlowSelector | 219 HasEdgeChildSelector | HasSlowSelectorNthAll, 220 221 /// Set of selector flags that may trigger a restyle as a result of any 222 /// DOM mutation. 223 AllSimpleRestyleFlags = 224 AllSimpleRestyleFlagsForAppend | HasSlowSelectorLaterSiblings, 225 226 // This node was evaluated as an anchor for a relative selector. 227 RelativeSelectorAnchor = 1 << 6, 228 229 // This node was evaluated as an anchor for a relative selector, and that 230 // relative selector was not the subject of the overall selector. 231 RelativeSelectorAnchorNonSubject = 1 << 7, 232 233 // This node's sibling(s) performed a relative selector search to this node. 234 RelativeSelectorSearchDirectionSibling = 1 << 8, 235 236 // This node's ancestor(s) performed a relative selector search to this node. 237 RelativeSelectorSearchDirectionAncestor = 1 << 9, 238 239 // This node's sibling(s) and ancestor(s), and/or this node's ancestor's 240 // sibling(s) performed a relative selector search to this node. 241 RelativeSelectorSearchDirectionAncestorSibling = 242 RelativeSelectorSearchDirectionSibling | 243 RelativeSelectorSearchDirectionAncestor, 244 }; 245 246 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(NodeSelectorFlags); 247 248 enum class BatchRemovalOrder { 249 FrontToBack, 250 BackToFront, 251 }; 252 253 struct BatchRemovalState { 254 // Whether we're the fist kid getting removed in the batch. Note that that's 255 // different to whether we're the first _child_, if we're removing 256 // back-to-front. 257 bool mIsFirst = true; 258 }; 259 260 // Make sure we have space for our bits 261 #define ASSERT_NODE_FLAGS_SPACE(n) \ 262 static_assert(WRAPPER_CACHE_FLAGS_BITS_USED + (n) <= \ 263 sizeof(nsWrapperCache::FlagsType) * 8, \ 264 "Not enough space for our bits") 265 ASSERT_NODE_FLAGS_SPACE(NODE_TYPE_SPECIFIC_BITS_OFFSET); 266 267 /** 268 * Class used to detect unexpected mutations. To use the class create an 269 * nsMutationGuard on the stack before unexpected mutations could occur. 270 * You can then at any time call Mutated to check if any unexpected mutations 271 * have occurred. 272 */ 273 class nsMutationGuard { 274 public: 275 nsMutationGuard() { mStartingGeneration = sGeneration; } 276 277 /** 278 * Returns true if any unexpected mutations have occurred. You can pass in 279 * an 8-bit ignore count to ignore a number of expected mutations. 280 * 281 * We don't need to care about overflow because subtraction of uint64_t's is 282 * finding the difference between two elements of the group Z < 2^64. Once 283 * we know the difference between two elements we only need to check that is 284 * less than the given number of mutations to know less than that many 285 * mutations occured. Assuming constant 1ns mutations it would take 584 286 * years for sGeneration to fully wrap around so we can ignore a guard living 287 * through a full wrap around. 288 */ 289 bool Mutated(uint8_t aIgnoreCount) const { 290 return (sGeneration - mStartingGeneration) > aIgnoreCount; 291 } 292 293 // This function should be called whenever a mutation that we want to keep 294 // track of happen. For now this is only done when children are added or 295 // removed, but we might do it for attribute changes too in the future. 296 static void DidMutate() { sGeneration++; } 297 298 private: 299 // This is the value sGeneration had when the guard was constructed. 300 uint64_t mStartingGeneration; 301 302 // This value is incremented on every mutation, for the life of the process. 303 static uint64_t sGeneration; 304 }; 305 306 /** 307 * A class that implements nsIWeakReference 308 */ 309 class nsNodeWeakReference final : public nsIWeakReference { 310 public: 311 explicit nsNodeWeakReference(nsINode* aNode); 312 313 // nsISupports 314 NS_DECL_ISUPPORTS 315 316 // nsIWeakReference 317 NS_DECL_NSIWEAKREFERENCE 318 319 void NoticeNodeDestruction() { mObject = nullptr; } 320 321 private: 322 ~nsNodeWeakReference(); 323 }; 324 325 // This should be used for any nsINode sub-class that has fields of its own 326 // that it needs to measure; any sub-class that doesn't use it will inherit 327 // AddSizeOfExcludingThis from its super-class. AddSizeOfIncludingThis() need 328 // not be defined, it is inherited from nsINode. 329 #define NS_DECL_ADDSIZEOFEXCLUDINGTHIS \ 330 virtual void AddSizeOfExcludingThis(nsWindowSizes& aSizes, \ 331 size_t* aNodeSize) const override; 332 333 // IID for the nsINode interface 334 // Must be kept in sync with xpcom/rust/xpcom/src/interfaces/nonidl.rs 335 #define NS_INODE_IID \ 336 {0x70ba4547, 0x7699, 0x44fc, {0xb3, 0x20, 0x52, 0xdb, 0xe3, 0xd1, 0xf9, 0x0a}} 337 338 /** 339 * An internal interface that abstracts some DOMNode-related parts that both 340 * nsIContent and Document share. An instance of this interface has a list 341 * of nsIContent children and provides access to them. 342 */ 343 class nsINode : public mozilla::dom::EventTarget { 344 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 345 void AssertInvariantsOnNodeInfoChange(); 346 #endif 347 public: 348 using BoxQuadOptions = mozilla::dom::BoxQuadOptions; 349 using ConvertCoordinateOptions = mozilla::dom::ConvertCoordinateOptions; 350 using DocGroup = mozilla::dom::DocGroup; 351 using Document = mozilla::dom::Document; 352 using DOMPoint = mozilla::dom::DOMPoint; 353 using DOMPointInit = mozilla::dom::DOMPointInit; 354 using DOMQuad = mozilla::dom::DOMQuad; 355 using DOMRectReadOnly = mozilla::dom::DOMRectReadOnly; 356 using OwningNodeOrString = mozilla::dom::OwningNodeOrString; 357 using TextOrElementOrDocument = mozilla::dom::TextOrElementOrDocument; 358 using CallerType = mozilla::dom::CallerType; 359 using ErrorResult = mozilla::ErrorResult; 360 361 // XXXbz Maybe we should codegen a class holding these constants and 362 // inherit from it... 363 static const auto ELEMENT_NODE = mozilla::dom::Node_Binding::ELEMENT_NODE; 364 static const auto ATTRIBUTE_NODE = mozilla::dom::Node_Binding::ATTRIBUTE_NODE; 365 static const auto TEXT_NODE = mozilla::dom::Node_Binding::TEXT_NODE; 366 static const auto CDATA_SECTION_NODE = 367 mozilla::dom::Node_Binding::CDATA_SECTION_NODE; 368 static const auto ENTITY_REFERENCE_NODE = 369 mozilla::dom::Node_Binding::ENTITY_REFERENCE_NODE; 370 static const auto ENTITY_NODE = mozilla::dom::Node_Binding::ENTITY_NODE; 371 static const auto PROCESSING_INSTRUCTION_NODE = 372 mozilla::dom::Node_Binding::PROCESSING_INSTRUCTION_NODE; 373 static const auto COMMENT_NODE = mozilla::dom::Node_Binding::COMMENT_NODE; 374 static const auto DOCUMENT_NODE = mozilla::dom::Node_Binding::DOCUMENT_NODE; 375 static const auto DOCUMENT_TYPE_NODE = 376 mozilla::dom::Node_Binding::DOCUMENT_TYPE_NODE; 377 static const auto DOCUMENT_FRAGMENT_NODE = 378 mozilla::dom::Node_Binding::DOCUMENT_FRAGMENT_NODE; 379 static const auto NOTATION_NODE = mozilla::dom::Node_Binding::NOTATION_NODE; 380 static const auto MAX_NODE_TYPE = NOTATION_NODE; 381 382 void* operator new(size_t aSize, nsNodeInfoManager* aManager); 383 void* operator new(size_t aSize) = delete; 384 void operator delete(void* aPtr); 385 386 template <class T> 387 using Sequence = mozilla::dom::Sequence<T>; 388 389 NS_INLINE_DECL_STATIC_IID(NS_INODE_IID) 390 391 // The |aNodeSize| outparam on this function is where the actual node size 392 // value is put. It gets added to the appropriate value within |aSizes| by 393 // AddSizeOfNodeTree(). 394 // 395 // Among the sub-classes that inherit (directly or indirectly) from nsINode, 396 // measurement of the following members may be added later if DMD finds it is 397 // worthwhile: 398 // - nsGenericHTMLElement: mForm, mFieldSet 399 // - nsGenericHTMLFrameElement: mFrameLoader (bug 672539) 400 // - HTMLBodyElement: mContentStyleRule 401 // - HTMLDataListElement: mOptions 402 // - HTMLFieldSetElement: mElements, mDependentElements, mFirstLegend 403 // - HTMLFormElement: many! 404 // - HTMLFrameSetElement: mRowSpecs, mColSpecs 405 // - HTMLInputElement: mInputData, mFiles, mFileList, mStaticDocfileList 406 // - nsHTMLMapElement: mAreas 407 // - HTMLMediaElement: many! 408 // - nsHTMLOutputElement: mDefaultValue, mTokenList 409 // - nsHTMLRowElement: mCells 410 // - nsHTMLSelectElement: mOptions, mRestoreState 411 // - nsHTMLTableElement: mTBodies, mRows, mTableInheritedAttributes 412 // - nsHTMLTableSectionElement: mRows 413 // - nsHTMLTextAreaElement: mControllers, mState 414 // 415 // The following members don't need to be measured: 416 // - nsIContent: mPrimaryFrame, because it's non-owning and measured elsewhere 417 // 418 virtual void AddSizeOfExcludingThis(nsWindowSizes& aSizes, 419 size_t* aNodeSize) const; 420 421 // SizeOfIncludingThis doesn't need to be overridden by sub-classes because 422 // sub-classes of nsINode are guaranteed to be laid out in memory in such a 423 // way that |this| points to the start of the allocated object, even in 424 // methods of nsINode's sub-classes, so aSizes.mState.mMallocSizeOf(this) is 425 // always safe to call no matter which object it was invoked on. 426 void AddSizeOfIncludingThis(nsWindowSizes& aSizes, size_t* aNodeSize) const; 427 428 friend class nsNodeWeakReference; 429 friend class nsNodeSupportsWeakRefTearoff; 430 friend class AttrArray; 431 432 #ifdef MOZILLA_INTERNAL_API 433 explicit nsINode(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo); 434 #endif 435 436 virtual ~nsINode(); 437 438 bool IsContainerNode() const { 439 return IsElement() || IsDocument() || IsDocumentFragment(); 440 } 441 442 /** 443 * Returns true if the node is a HTMLTemplate element. 444 */ 445 bool IsTemplateElement() const { return IsHTMLElement(nsGkAtoms::_template); } 446 447 bool IsSlotable() const { return IsElement() || IsText(); } 448 449 /** 450 * Returns true if this is a document node. 451 */ 452 bool IsDocument() const { 453 // One less pointer-chase than checking NodeType(). 454 return !GetParentNode() && IsInUncomposedDoc(); 455 } 456 457 /** 458 * Return this node as a document. Asserts IsDocument(). 459 * 460 * This is defined inline in Document.h. 461 */ 462 inline Document* AsDocument(); 463 inline const Document* AsDocument() const; 464 465 /** 466 * Returns true if this is a document fragment node. 467 */ 468 bool IsDocumentFragment() const { 469 return NodeType() == DOCUMENT_FRAGMENT_NODE; 470 } 471 472 virtual bool IsHTMLFormControlElement() const { return false; } 473 474 /** 475 * https://dom.spec.whatwg.org/#concept-tree-inclusive-descendant 476 * 477 * @param aNode must not be nullptr. 478 */ 479 bool IsInclusiveDescendantOf(const nsINode* aNode) const; 480 481 /** 482 * https://dom.spec.whatwg.org/#concept-shadow-including-descendant 483 * 484 * @param aNode must not be nullptr. 485 */ 486 bool IsShadowIncludingDescendantOf(const nsINode* aNode) const; 487 488 /** 489 * https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-descendant 490 * 491 * @param aNode must not be nullptr. 492 */ 493 bool IsShadowIncludingInclusiveDescendantOf(const nsINode* aNode) const; 494 495 /** 496 * Returns true if the given node is this node or one of its descendants 497 * in the "flat tree." 498 * 499 * @param aNode must not be nullptr. 500 */ 501 bool IsInclusiveFlatTreeDescendantOf(const nsINode* aNode) const; 502 503 /** 504 * Return this node as a document fragment. Asserts IsDocumentFragment(). 505 * 506 * This is defined inline in DocumentFragment.h. 507 */ 508 inline mozilla::dom::DocumentFragment* AsDocumentFragment(); 509 inline const mozilla::dom::DocumentFragment* AsDocumentFragment() const; 510 511 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*> aGivenProto) final; 512 513 /** 514 * Hook for constructing JS::ubi::Concrete specializations for memory 515 * reporting. Specializations are defined in NodeUbiReporting.h. 516 */ 517 virtual void ConstructUbiNode(void* storage) = 0; 518 519 /** 520 * returns true if we are in priviliged code or 521 * layout.css.getBoxQuads.enabled == true. 522 */ 523 static bool HasBoxQuadsSupport(JSContext* aCx, JSObject* /* unused */); 524 525 protected: 526 /** 527 * WrapNode is called from WrapObject to actually wrap this node, WrapObject 528 * does some additional checks and fix-up that's common to all nodes. WrapNode 529 * should just call the DOM binding's Wrap function. 530 * 531 * aGivenProto is the prototype to use (or null if the default one should be 532 * used) and should just be passed directly on to the DOM binding's Wrap 533 * function. 534 */ 535 virtual JSObject* WrapNode(JSContext* aCx, 536 JS::Handle<JSObject*> aGivenProto) = 0; 537 538 public: 539 mozilla::dom::ParentObject GetParentObject() 540 const; // Implemented in Document.h 541 542 /** 543 * Returns the first child of a node or the first child of 544 * a template element's content if the provided node is a 545 * template element. 546 */ 547 nsIContent* GetFirstChildOfTemplateOrNode(); 548 549 /** 550 * Return the scope chain parent for this node, for use in things 551 * like event handler compilation. Returning null means to use the 552 * global object as the scope chain parent. 553 */ 554 virtual nsINode* GetScopeChainParent() const; 555 556 MOZ_CAN_RUN_SCRIPT mozilla::dom::Element* GetParentFlexElement(); 557 558 /** 559 * Returns the nearest inclusive open popover for a given node, see 560 * https://html.spec.whatwg.org/multipage/popover.html#nearest-inclusive-open-popover 561 */ 562 mozilla::dom::Element* GetNearestInclusiveOpenPopover() const; 563 564 /** 565 * https://html.spec.whatwg.org/multipage/popover.html#nearest-inclusive-target-popover-for-invoker 566 */ 567 mozilla::dom::Element* GetNearestInclusiveTargetPopoverForInvoker() const; 568 569 nsGenericHTMLElement* GetEffectiveCommandForElement() const; 570 571 /** 572 * https://html.spec.whatwg.org/multipage/popover.html#popover-target-element 573 */ 574 nsGenericHTMLElement* GetEffectivePopoverTargetElement() const; 575 576 /** 577 * https://html.spec.whatwg.org/multipage/popover.html#topmost-clicked-popover 578 */ 579 mozilla::dom::Element* GetTopmostClickedPopover() const; 580 581 /** 582 * https://html.spec.whatwg.org/multipage/interactive-elements.html#nearest-clicked-dialog 583 */ 584 mozilla::dom::HTMLDialogElement* NearestClickedDialog(mozilla::WidgetEvent*); 585 586 bool IsNode() const final { return true; } 587 588 NS_IMPL_FROMEVENTTARGET_HELPER(nsINode, IsNode()) 589 590 /** 591 * Return whether the node is an Element node. Faster than using `NodeType()`. 592 */ 593 bool IsElement() const { return GetBoolFlag(NodeIsElement); } 594 595 virtual bool IsTextControlElement() const { return false; } 596 virtual bool IsGenericHTMLFormControlElementWithState() const { 597 return false; 598 } 599 600 // Returns non-null if this element subclasses `LinkStyle`. 601 virtual const mozilla::dom::LinkStyle* AsLinkStyle() const { return nullptr; } 602 mozilla::dom::LinkStyle* AsLinkStyle() { 603 return const_cast<mozilla::dom::LinkStyle*>( 604 static_cast<const nsINode*>(this)->AsLinkStyle()); 605 } 606 607 /** 608 * Return this node as an Element. Should only be used for nodes 609 * for which IsElement() is true. This is defined inline in Element.h. 610 */ 611 inline mozilla::dom::Element* AsElement(); 612 inline const mozilla::dom::Element* AsElement() const; 613 614 /** 615 * Return whether the node is an nsStyledElement instance or not. 616 */ 617 virtual bool IsStyledElement() const { return false; } 618 619 /** 620 * Return this node as nsIContent. Should only be used for nodes for which 621 * IsContent() is true. 622 * 623 * The assertion in nsIContent's constructor makes this safe. 624 */ 625 nsIContent* AsContent() { 626 MOZ_ASSERT(IsContent()); 627 return reinterpret_cast<nsIContent*>(this); 628 } 629 const nsIContent* AsContent() const { 630 MOZ_ASSERT(IsContent()); 631 return reinterpret_cast<const nsIContent*>(this); 632 } 633 634 /* 635 * Return whether the node is a Text node (which might be an actual 636 * textnode, or might be a CDATA section). 637 */ 638 bool IsText() const { 639 uint32_t nodeType = NodeType(); 640 return nodeType == TEXT_NODE || nodeType == CDATA_SECTION_NODE; 641 } 642 643 /** 644 * Return this node as Text if it is one, otherwise null. This is defined 645 * inline in Text.h. 646 */ 647 inline mozilla::dom::Text* GetAsText(); 648 inline const mozilla::dom::Text* GetAsText() const; 649 650 /** 651 * Return this node as Text. Asserts IsText(). This is defined inline in 652 * Text.h. 653 */ 654 inline mozilla::dom::Text* AsText(); 655 inline const mozilla::dom::Text* AsText() const; 656 657 /** 658 * Return this node if the instance type inherits nsIFormControl, or an 659 * nsIFormControl instance which ia associated with this node. Otherwise, 660 * returns nullptr. 661 */ 662 [[nodiscard]] virtual nsIFormControl* GetAsFormControl() { return nullptr; } 663 [[nodiscard]] virtual const nsIFormControl* GetAsFormControl() const { 664 return nullptr; 665 } 666 667 /* 668 * Return whether the node is a ProcessingInstruction node. 669 */ 670 bool IsProcessingInstruction() const { 671 return NodeType() == PROCESSING_INSTRUCTION_NODE; 672 } 673 674 /* 675 * Return whether the node is a CharacterData node (text, cdata, 676 * comment, processing instruction) 677 */ 678 bool IsCharacterData() const { 679 uint32_t nodeType = NodeType(); 680 return nodeType == TEXT_NODE || nodeType == CDATA_SECTION_NODE || 681 nodeType == PROCESSING_INSTRUCTION_NODE || nodeType == COMMENT_NODE; 682 } 683 684 /** 685 * Return whether the node is a Comment node. 686 */ 687 bool IsComment() const { return NodeType() == COMMENT_NODE; } 688 689 /** 690 * Return whether the node is an Attr node. 691 */ 692 bool IsAttr() const { return NodeType() == ATTRIBUTE_NODE; } 693 694 /** 695 * Return if this node has any children. 696 */ 697 bool HasChildren() const { return !!mFirstChild; } 698 699 /** 700 * Get the number of children 701 * @return the number of children 702 */ 703 uint32_t GetChildCount() const { return mChildCount; } 704 705 /** Get the number of flat tree children */ 706 uint32_t GetFlatTreeChildCount() const; 707 708 /** 709 * NOTE: this function is going to be removed soon (hopefully!) Don't use it 710 * in new code. 711 * 712 * Get a child by index 713 * @param aIndex the index of the child to get 714 * @return the child, or null if index out of bounds 715 */ 716 nsIContent* GetChildAt_Deprecated(uint32_t aIndex) const; 717 718 /** Get the child at aIndex in flat tree **/ 719 nsINode* GetChildAtInFlatTree(uint32_t aIndex) const; 720 721 /** 722 * Get the index of a child within this content. 723 * 724 * @param aPossibleChild the child to get the index of. 725 * @return the index of the child, or Nothing if not a child. Be aware that 726 * anonymous children (e.g. a <div> child of an <input> element) will 727 * result in Nothing. 728 * 729 * If the return value is Some, then calling GetChildAt_Deprecated() with 730 * that value will return aPossibleChild. 731 */ 732 mozilla::Maybe<uint32_t> ComputeIndexOf(const nsINode* aPossibleChild) const; 733 734 /** 735 * Return true if ComputeIndexOf() may cache the computed index for further 736 * calls. 737 */ 738 [[nodiscard]] bool MaybeCachesComputedIndex() const; 739 740 /** 741 * Get the index of a child within this content's flat tree children. 742 * 743 * @param aPossibleChild the child to get the index of. 744 * @return the index of the child, or Nothing if not a child. Be aware that 745 * anonymous children (e.g. a <div> child of an <input> element) will 746 * result in Nothing. 747 */ 748 mozilla::Maybe<uint32_t> ComputeFlatTreeIndexOf( 749 const nsINode* aPossibleChild) const; 750 751 /** 752 * Get the index of this within parent node (ComputeIndexInParentNode) or 753 * parent content (nsIContent) node (ComputeIndexInParentContent). 754 * 755 * @return the index of this node in the parent, or Nothing there is no 756 * parent (content) node or the parent does not have this node anymore 757 * (e.g., being removed from the parent). Be aware that anonymous 758 * children (e.g. a <div> child of an <input> element) will result in 759 * Nothing. 760 * 761 * If the return value is Some, then calling GetChildAt_Deprecated() with 762 * that value will return this. 763 */ 764 mozilla::Maybe<uint32_t> ComputeIndexInParentNode() const; 765 mozilla::Maybe<uint32_t> ComputeIndexInParentContent() const; 766 767 /** 768 * Return true if the parent node may cache the computed index for further 769 * calls. 770 */ 771 [[nodiscard]] bool MaybeParentCachesComputedIndex() const; 772 773 /** 774 * Get the index of a child within this content. 775 * 776 * @param aPossibleChild the child to get the index of. 777 * @return the index of the child, or -1 if not a child. Be aware that 778 * anonymous children (e.g. a <div> child of an <input> element) will 779 * result in -1. 780 * 781 * If the return value is not -1, then calling GetChildAt_Deprecated() with 782 * that value will return aPossibleChild. 783 */ 784 int32_t ComputeIndexOf_Deprecated(const nsINode* aPossibleChild) const; 785 786 /** 787 * Returns the "node document" of this node. 788 * 789 * https://dom.spec.whatwg.org/#concept-node-document 790 * 791 * Note that in the case that this node is a document node this method 792 * will return |this|. That is different to the Node.ownerDocument DOM 793 * attribute (implemented by nsINode::GetOwnerDocument) which is specified to 794 * be null in that case: 795 * 796 * https://dom.spec.whatwg.org/#dom-node-ownerdocument 797 * 798 * For all other cases OwnerDoc and GetOwnerDocument behave identically. 799 */ 800 Document* OwnerDoc() const MOZ_NONNULL_RETURN { 801 return mNodeInfo->GetDocument(); 802 } 803 804 /** 805 * Return the "owner document" of this node as an nsINode*. Implemented 806 * in Document.h. 807 */ 808 inline nsINode* OwnerDocAsNode() const MOZ_NONNULL_RETURN; 809 810 /** 811 * Returns true if the content has an ancestor that is a document. 812 * 813 * @return whether this content is in a document tree 814 */ 815 bool IsInUncomposedDoc() const { return GetBoolFlag(IsInDocument); } 816 817 /** 818 * Get the document that this content is currently in, if any. This will be 819 * null if the content has no ancestor that is a document. 820 * 821 * @return the current document 822 */ 823 824 Document* GetUncomposedDoc() const { 825 return IsInUncomposedDoc() ? OwnerDoc() : nullptr; 826 } 827 828 /** 829 * Returns true if we're connected, and thus GetComposedDoc() would return a 830 * non-null value. 831 */ 832 bool IsInComposedDoc() const { return GetBoolFlag(IsConnected); } 833 834 /** 835 * This method returns the owner document if the node is connected to it 836 * (as defined in the DOM spec), otherwise it returns null. 837 * In other words, returns non-null even in the case the node is in 838 * Shadow DOM, if there is a possibly shadow boundary crossing path from 839 * the node to its owner document. 840 */ 841 Document* GetComposedDoc() const { 842 return IsInComposedDoc() ? OwnerDoc() : nullptr; 843 } 844 845 /** 846 * Returns OwnerDoc() if the node is in uncomposed document and ShadowRoot if 847 * the node is in Shadow DOM. 848 */ 849 mozilla::dom::DocumentOrShadowRoot* GetContainingDocumentOrShadowRoot() const; 850 851 /** 852 * Returns OwnerDoc() if the node is in uncomposed document and ShadowRoot if 853 * the node is in Shadow DOM and is in composed document. 854 */ 855 mozilla::dom::DocumentOrShadowRoot* GetUncomposedDocOrConnectedShadowRoot() 856 const; 857 858 /** 859 * To be called when reference count of the node drops to zero. 860 */ 861 void LastRelease(); 862 863 /** 864 * The values returned by this function are the ones defined for 865 * Node.nodeType 866 */ 867 uint16_t NodeType() const { return mNodeInfo->NodeType(); } 868 const nsString& NodeName() const { return mNodeInfo->NodeName(); } 869 const nsString& LocalName() const { return mNodeInfo->LocalName(); } 870 871 /** 872 * Get the NodeInfo for this element 873 * @return the nodes node info 874 */ 875 inline mozilla::dom::NodeInfo* NodeInfo() const { return mNodeInfo; } 876 877 /** 878 * Called when we have been adopted, and the information of the 879 * node has been changed. 880 * 881 * The new document can be reached via OwnerDoc(). 882 * 883 * If you override this method, 884 * please call up to the parent NodeInfoChanged. 885 * 886 * If you change this, change also the similar method in Link. 887 */ 888 virtual void NodeInfoChanged(Document* aOldDoc) { 889 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 890 AssertInvariantsOnNodeInfoChange(); 891 #endif 892 } 893 894 inline bool IsInNamespace(int32_t aNamespace) const { 895 return mNodeInfo->NamespaceID() == aNamespace; 896 } 897 898 /** 899 * Returns the DocGroup of the "node document" of this node. 900 */ 901 DocGroup* GetDocGroup() const; 902 903 /** 904 * Print a debugger friendly descriptor of this element. This will describe 905 * the position of this element in the document. 906 */ 907 friend std::ostream& operator<<(std::ostream& aStream, const nsINode& aNode); 908 909 protected: 910 // These 2 methods are useful for the recursive templates IsHTMLElement, 911 // IsSVGElement, etc. 912 inline bool IsNodeInternal() const { return false; } 913 914 template <typename First, typename... Args> 915 inline bool IsNodeInternal(First aFirst, Args... aArgs) const { 916 return mNodeInfo->Equals(aFirst) || IsNodeInternal(aArgs...); 917 } 918 919 public: 920 inline bool IsHTMLElement() const { 921 return IsElement() && IsInNamespace(kNameSpaceID_XHTML); 922 } 923 924 inline bool IsHTMLElement(const nsAtom* aTag) const { 925 return IsElement() && mNodeInfo->Equals(aTag, kNameSpaceID_XHTML); 926 } 927 928 template <typename First, typename... Args> 929 inline bool IsAnyOfHTMLElements(First aFirst, Args... aArgs) const { 930 return IsHTMLElement() && IsNodeInternal(aFirst, aArgs...); 931 } 932 933 inline bool IsSVGElement() const { 934 return IsElement() && IsInNamespace(kNameSpaceID_SVG); 935 } 936 937 inline bool IsSVGElement(const nsAtom* aTag) const { 938 return IsElement() && mNodeInfo->Equals(aTag, kNameSpaceID_SVG); 939 } 940 941 template <typename First, typename... Args> 942 inline bool IsAnyOfSVGElements(First aFirst, Args... aArgs) const { 943 return IsSVGElement() && IsNodeInternal(aFirst, aArgs...); 944 } 945 946 virtual bool IsSVGAnimationElement() const { return false; } 947 virtual bool IsSVGComponentTransferFunctionElement() const { return false; } 948 virtual bool IsSVGFilterPrimitiveElement() const { return false; } 949 virtual bool IsSVGFilterPrimitiveChildElement() const { return false; } 950 virtual bool IsSVGGeometryElement() const { return false; } 951 virtual bool IsSVGGraphicsElement() const { return false; } 952 953 inline bool IsXULElement() const { 954 return IsElement() && IsInNamespace(kNameSpaceID_XUL); 955 } 956 957 inline bool IsXULElement(const nsAtom* aTag) const { 958 return IsElement() && mNodeInfo->Equals(aTag, kNameSpaceID_XUL); 959 } 960 961 template <typename First, typename... Args> 962 inline bool IsAnyOfXULElements(First aFirst, Args... aArgs) const { 963 return IsXULElement() && IsNodeInternal(aFirst, aArgs...); 964 } 965 966 inline bool IsMathMLElement() const { 967 return IsElement() && IsInNamespace(kNameSpaceID_MathML); 968 } 969 970 inline bool IsMathMLElement(const nsAtom* aTag) const { 971 return IsElement() && mNodeInfo->Equals(aTag, kNameSpaceID_MathML); 972 } 973 974 template <typename First, typename... Args> 975 inline bool IsAnyOfMathMLElements(First aFirst, Args... aArgs) const { 976 return IsMathMLElement() && IsNodeInternal(aFirst, aArgs...); 977 } 978 979 bool IsShadowRoot() const { 980 const bool isShadowRoot = IsInShadowTree() && !GetParentNode(); 981 MOZ_ASSERT_IF(isShadowRoot, IsDocumentFragment()); 982 return isShadowRoot; 983 } 984 985 bool IsHTMLHeadingElement() const { 986 return IsAnyOfHTMLElements(nsGkAtoms::h1, nsGkAtoms::h2, nsGkAtoms::h3, 987 nsGkAtoms::h4, nsGkAtoms::h5, nsGkAtoms::h6); 988 } 989 990 /** 991 * Check whether the conditional processing attributes other than 992 * systemLanguage "return true" if they apply to and are specified 993 * on the given SVG element. Returns true if this element should be 994 * rendered, false if it should not. 995 */ 996 virtual bool PassesConditionalProcessingTests() const { return true; } 997 998 /** 999 * Insert a content node before another or at the end. 1000 * This method handles calling BindToTree on the child appropriately. 1001 * 1002 * @param aKid the content to insert 1003 * @param aBeforeThis an existing node. Use nullptr if you want to 1004 * add aKid at the end. 1005 * @param aNotify whether to notify the document (current document for 1006 * nsIContent, and |this| for Document) that the insert has occurred 1007 * @param aRv The error, if any. 1008 * Throw NS_ERROR_DOM_HIERARCHY_REQUEST_ERR if one attempts to have 1009 * more than one element node as a child of a document. Doing this 1010 * will also assert -- you shouldn't be doing it! Check with 1011 * Document::GetRootElement() first if you're not sure. Apart from 1012 * this one constraint, this doesn't do any checking on whether aKid is 1013 * a valid child of |this|. 1014 * Throw NS_ERROR_OUT_OF_MEMORY in some cases (from BindToTree). 1015 * @param aOldParent In case the method is called as part of moveBefore, 1016 * the argument tells which node used to be the parent of aKid. 1017 * @param aMutationEffectOnScript Indicate how this change after 1018 * trustworthiness of parent script. 1019 */ 1020 virtual void InsertChildBefore( 1021 nsIContent* aKid, nsIContent* aBeforeThis, bool aNotify, 1022 mozilla::ErrorResult& aRv, nsINode* aOldParent = nullptr, 1023 MutationEffectOnScript aMutationEffectOnScript = 1024 MutationEffectOnScript::DropTrustWorthiness); 1025 1026 /** 1027 * Append a content node to the end of the child list. This method handles 1028 * calling BindToTree on the child appropriately. 1029 * 1030 * @param aKid the content to append 1031 * @param aNotify whether to notify the document (current document for 1032 * nsIContent, and |this| for Document) that the append has occurred 1033 * @param aRv The error, if any. 1034 * Throw NS_ERROR_DOM_HIERARCHY_REQUEST_ERR if one attempts to have 1035 * more than one element node as a child of a document. Doing this 1036 * will also assert -- you shouldn't be doing it! Check with 1037 * Document::GetRootElement() first if you're not sure. Apart from 1038 * this one constraint, this doesn't do any checking on whether aKid is 1039 * a valid child of |this|. 1040 * Throw NS_ERROR_OUT_OF_MEMORY in some cases (from BindToTree). 1041 * @param aMutationEffectOnScript Indicate how this change after 1042 * trustworthiness of parent script. 1043 */ 1044 void AppendChildTo(nsIContent* aKid, bool aNotify, mozilla::ErrorResult& aRv, 1045 MutationEffectOnScript aMutationEffectOnScript = 1046 MutationEffectOnScript::DropTrustWorthiness) { 1047 InsertChildBefore(aKid, nullptr, aNotify, aRv, nullptr, 1048 aMutationEffectOnScript); 1049 } 1050 1051 template <BatchRemovalOrder aOrder = BatchRemovalOrder::FrontToBack> 1052 void RemoveAllChildren(bool aNotify) { 1053 BatchRemovalState state{}; 1054 while (HasChildren()) { 1055 nsIContent* nodeToRemove = aOrder == BatchRemovalOrder::FrontToBack 1056 ? GetFirstChild() 1057 : GetLastChild(); 1058 RemoveChildNode(nodeToRemove, aNotify, &state, nullptr, 1059 MutationEffectOnScript::KeepTrustWorthiness); 1060 state.mIsFirst = false; 1061 } 1062 } 1063 1064 /** 1065 * Remove a child from this node. This method handles calling UnbindFromTree 1066 * on the child appropriately. 1067 * 1068 * @param aKid the content to remove 1069 * @param aNotify whether to notify the document (current document for 1070 * nsIContent, and |this| for Document) that the remove has occurred 1071 * @param BatchRemovalState The current state of our batch removal. 1072 * @param aNewParent In case the method is called as part of moveBefore, 1073 * the argument tells which node will be aKid's new parent. 1074 * @param aMutationEffectOnScript Indicate how this change after 1075 * trustworthiness of parent script. 1076 */ 1077 virtual void RemoveChildNode(nsIContent* aKid, bool aNotify, 1078 const BatchRemovalState* = nullptr, 1079 nsINode* aNewParent = nullptr, 1080 MutationEffectOnScript aMutationEffectOnScript = 1081 MutationEffectOnScript::DropTrustWorthiness); 1082 1083 /** 1084 * Get a property associated with this node. 1085 * 1086 * @param aPropertyName name of property to get. 1087 * @param aStatus out parameter for storing resulting status. 1088 * Set to NS_PROPTABLE_PROP_NOT_THERE if the property 1089 * is not set. 1090 * @return the property. Null if the property is not set 1091 * (though a null return value does not imply the 1092 * property was not set, i.e. it can be set to null). 1093 */ 1094 void* GetProperty(const nsAtom* aPropertyName, 1095 nsresult* aStatus = nullptr) const; 1096 1097 /** 1098 * Set a property to be associated with this node. This will overwrite an 1099 * existing value if one exists. The existing value is destroyed using the 1100 * destructor function given when that value was set. 1101 * 1102 * @param aPropertyName name of property to set. 1103 * @param aValue new value of property. 1104 * @param aDtor destructor function to be used when this property 1105 * is destroyed. 1106 * @param aTransfer if true the property will not be deleted when the 1107 * ownerDocument of the node changes, if false it 1108 * will be deleted. 1109 * 1110 * @return NS_PROPTABLE_PROP_OVERWRITTEN (success value) if the property 1111 * was already set 1112 * @throws NS_ERROR_OUT_OF_MEMORY if that occurs 1113 */ 1114 nsresult SetProperty(nsAtom* aPropertyName, void* aValue, 1115 NSPropertyDtorFunc aDtor = nullptr, 1116 bool aTransfer = false); 1117 1118 /** 1119 * A generic destructor for property values allocated with new. 1120 */ 1121 template <class T> 1122 static void DeleteProperty(void*, nsAtom*, void* aPropertyValue, void*) { 1123 delete static_cast<T*>(aPropertyValue); 1124 } 1125 1126 /** 1127 * Removes a property associated with this node. The value is destroyed using 1128 * the destruction function given when that value was set. 1129 * 1130 * @param aPropertyName name of property to destroy. 1131 */ 1132 void RemoveProperty(const nsAtom* aPropertyName); 1133 1134 /** 1135 * Take a property associated with this node. The value will not be destroyed 1136 * but rather returned. It is the caller's responsibility to destroy the value 1137 * after that point. 1138 * 1139 * @param aPropertyName name of property to unset. 1140 * @param aStatus out parameter for storing resulting status. 1141 * Set to NS_PROPTABLE_PROP_NOT_THERE if the property 1142 * is not set. 1143 * @return the property. Null if the property is not set 1144 * (though a null return value does not imply the 1145 * property was not set, i.e. it can be set to null). 1146 */ 1147 void* TakeProperty(const nsAtom* aPropertyName, nsresult* aStatus = nullptr); 1148 1149 bool HasProperties() const { return HasFlag(NODE_HAS_PROPERTIES); } 1150 1151 /** 1152 * Return the principal of this node. This is guaranteed to never be a null 1153 * pointer. 1154 */ 1155 nsIPrincipal* NodePrincipal() const { 1156 return mNodeInfo->NodeInfoManager()->DocumentPrincipal(); 1157 } 1158 1159 /** 1160 * Return the Policy Container of this node's document, if any. 1161 */ 1162 nsIPolicyContainer* GetPolicyContainer() const; 1163 1164 /** 1165 * Get the parent nsIContent for this node. 1166 * @return the parent, or null if no parent or the parent is not an nsIContent 1167 */ 1168 nsIContent* GetParent() const { 1169 return MOZ_LIKELY(GetBoolFlag(ParentIsContent)) ? mParent->AsContent() 1170 : nullptr; 1171 } 1172 1173 /** 1174 * Get the parent nsINode for this node. This can be either an nsIContent, a 1175 * Document or an Attr. 1176 * @return the parent node 1177 */ 1178 nsINode* GetParentNode() const { return mParent; } 1179 1180 private: 1181 nsIContent* DoGetShadowHost() const; 1182 1183 public: 1184 nsINode* GetParentOrShadowHostNode() const { 1185 if (MOZ_LIKELY(mParent)) { 1186 return mParent; 1187 } 1188 // We could put this in nsIContentInlines.h or such to avoid this 1189 // reinterpret_cast, but it doesn't seem worth it. 1190 return IsInShadowTree() ? reinterpret_cast<nsINode*>(DoGetShadowHost()) 1191 : nullptr; 1192 } 1193 1194 enum FlattenedParentType { eNormal, eForStyle, eForSelection }; 1195 1196 /** 1197 * Returns the node that is the parent of this node in the flattened 1198 * tree. This differs from the normal parent if the node is filtered 1199 * into an insertion point, or if the node is a direct child of a 1200 * shadow root. 1201 * 1202 * @return the flattened tree parent 1203 */ 1204 inline nsINode* GetFlattenedTreeParentNode() const; 1205 1206 nsINode* GetFlattenedTreeParentNodeNonInline() const; 1207 1208 /** 1209 * Like GetFlattenedTreeParentNode, but returns the document for any native 1210 * anonymous content that was generated for ancestor frames of the document 1211 * element's primary frame, such as scrollbar elements created by the root 1212 * scroll frame. 1213 */ 1214 inline nsINode* GetFlattenedTreeParentNodeForStyle() const; 1215 1216 /** 1217 * Similar to GetFlattenedTreeParentNode, it does two things differently 1218 * 1. For contents that are not in the flattened tree, use its 1219 * parent rather than nullptr. 1220 * 2. For contents that are slotted into a UA shadow tree, use its 1221 * parent rather than the slot element. 1222 */ 1223 inline nsINode* GetFlattenedTreeParentNodeForSelection() const; 1224 1225 inline mozilla::dom::Element* GetFlattenedTreeParentElement() const; 1226 inline mozilla::dom::Element* GetFlattenedTreeParentElementForStyle() const; 1227 1228 /** 1229 * Get the parent nsINode for this node if it is an Element. 1230 * 1231 * Defined inline in Element.h 1232 * 1233 * @return the parent node 1234 */ 1235 inline mozilla::dom::Element* GetParentElement() const; 1236 1237 /** 1238 * Get the parent Element of this node, traversing over a ShadowRoot 1239 * to its host if necessary. 1240 */ 1241 mozilla::dom::Element* GetParentElementCrossingShadowRoot() const; 1242 1243 /** 1244 * Get closest element node for the node. Meaning that if the node is an 1245 * element node, returns itself. Otherwise, returns parent element or null. 1246 * Note that if the node is a non-element node and it's root of a shadow DOM, 1247 * this returns nullptr. If you want to get inclusive flattened tree ancestor 1248 * in this case, use GetInclusiveFlattenedTreeAncestorElement(). 1249 */ 1250 inline mozilla::dom::Element* GetAsElementOrParentElement() const; 1251 1252 /** 1253 * Get inclusive ancestor element in the flattened tree. 1254 */ 1255 inline mozilla::dom::Element* GetInclusiveFlattenedTreeAncestorElement() 1256 const; 1257 1258 /** 1259 * Get the root of the subtree this node belongs to. This never returns 1260 * null. It may return 'this' (e.g. for document nodes, and nodes that 1261 * are the roots of disconnected subtrees). 1262 */ 1263 nsINode* SubtreeRoot() const; 1264 1265 /* 1266 * Get context object's shadow-including root if options's composed is true, 1267 * and context object's root otherwise. 1268 */ 1269 nsINode* GetRootNode(const mozilla::dom::GetRootNodeOptions& aOptions); 1270 1271 virtual mozilla::EventListenerManager* GetExistingListenerManager() 1272 const override; 1273 virtual mozilla::EventListenerManager* GetOrCreateListenerManager() override; 1274 1275 mozilla::Maybe<mozilla::dom::EventCallbackDebuggerNotificationType> 1276 GetDebuggerNotificationType() const override; 1277 1278 bool ComputeDefaultWantsUntrusted(mozilla::ErrorResult& aRv) final; 1279 1280 virtual bool IsApzAware() const override; 1281 1282 virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindingsInternal() override; 1283 virtual nsIGlobalObject* GetOwnerGlobal() const override; 1284 1285 using mozilla::dom::EventTarget::DispatchEvent; 1286 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230) 1287 MOZ_CAN_RUN_SCRIPT_BOUNDARY bool DispatchEvent( 1288 mozilla::dom::Event& aEvent, mozilla::dom::CallerType aCallerType, 1289 mozilla::ErrorResult& aRv) override; 1290 1291 MOZ_CAN_RUN_SCRIPT 1292 nsresult PostHandleEvent(mozilla::EventChainPostVisitor& aVisitor) override; 1293 1294 /** 1295 * Adds a mutation observer to be notified when this node, or any of its 1296 * descendants, are modified. The node will hold a weak reference to the 1297 * observer, which means that it is the responsibility of the observer to 1298 * remove itself in case it dies before the node. If an observer is added 1299 * while observers are being notified, it may also be notified. In general, 1300 * adding observers while inside a notification is not a good idea. An 1301 * observer that is already observing the node must not be added without 1302 * being removed first. 1303 * 1304 * For mutation observers that implement nsIAnimationObserver, use 1305 * AddAnimationObserver instead. 1306 */ 1307 void AddMutationObserver(nsIMutationObserver* aMutationObserver) { 1308 nsSlots* s = Slots(); 1309 if (aMutationObserver) { 1310 NS_ASSERTION(!s->mMutationObservers.contains(aMutationObserver), 1311 "Observer already in the list"); 1312 1313 s->mMutationObservers.pushBack(aMutationObserver); 1314 } 1315 } 1316 1317 void AddMutationObserver(nsMultiMutationObserver* aMultiMutationObserver); 1318 1319 /** 1320 * Same as above, but only adds the observer if its not observing 1321 * the node already. 1322 * 1323 * For mutation observers that implement nsIAnimationObserver, use 1324 * AddAnimationObserverUnlessExists instead. 1325 */ 1326 void AddMutationObserverUnlessExists(nsIMutationObserver* aMutationObserver) { 1327 nsSlots* s = Slots(); 1328 if (aMutationObserver && 1329 !s->mMutationObservers.contains(aMutationObserver)) { 1330 s->mMutationObservers.pushBack(aMutationObserver); 1331 } 1332 } 1333 1334 void AddMutationObserverUnlessExists( 1335 nsMultiMutationObserver* aMultiMutationObserver); 1336 /** 1337 * Same as AddMutationObserver, but for nsIAnimationObservers. This 1338 * additionally records on the document that animation observers have 1339 * been registered, which is used to determine whether notifications 1340 * must be fired when animations are added, removed or changed. 1341 */ 1342 void AddAnimationObserver(nsIAnimationObserver* aAnimationObserver); 1343 1344 /** 1345 * Same as above, but only adds the observer if its not observing 1346 * the node already. 1347 */ 1348 void AddAnimationObserverUnlessExists( 1349 nsIAnimationObserver* aAnimationObserver); 1350 1351 /** 1352 * Removes a mutation observer. 1353 */ 1354 void RemoveMutationObserver(nsIMutationObserver* aMutationObserver) { 1355 nsSlots* s = GetExistingSlots(); 1356 if (s) { 1357 s->mMutationObservers.remove(aMutationObserver); 1358 } 1359 } 1360 1361 void RemoveMutationObserver(nsMultiMutationObserver* aMultiMutationObserver); 1362 1363 mozilla::SafeDoublyLinkedList<nsIMutationObserver>* GetMutationObservers(); 1364 1365 /** 1366 * Helper methods to access ancestor node(s) of type T. 1367 * The implementations of the methods are in mozilla/dom/AncestorIterator.h. 1368 */ 1369 template <typename T> 1370 inline mozilla::dom::AncestorsOfTypeIterator<T> AncestorsOfType() const; 1371 1372 template <typename T> 1373 inline mozilla::dom::InclusiveAncestorsOfTypeIterator<T> 1374 InclusiveAncestorsOfType() const; 1375 1376 template <typename T> 1377 inline mozilla::dom::FlatTreeAncestorsOfTypeIterator<T> 1378 FlatTreeAncestorsOfType() const; 1379 1380 template <typename T> 1381 inline mozilla::dom::InclusiveFlatTreeAncestorsOfTypeIterator<T> 1382 InclusiveFlatTreeAncestorsOfType() const; 1383 1384 template <typename T> 1385 T* FirstAncestorOfType() const; 1386 1387 private: 1388 /** 1389 * Walks aNode, its attributes and, if aDeep is true, its descendant nodes. 1390 * If aClone is true the nodes will be cloned. If aNewNodeInfoManager is 1391 * not null, it is used to create new nodeinfos for the nodes. Also reparents 1392 * the XPConnect wrappers for the nodes into aReparentScope if non-null. 1393 * 1394 * @param aNode Node to adopt/clone. 1395 * @param aClone If true the node will be cloned and the cloned node will 1396 * be returned. 1397 * @param aDeep If true the function will be called recursively on 1398 * descendants of the node 1399 * @param aNewNodeInfoManager The nodeinfo manager to use to create new 1400 * nodeinfos for aNode and its attributes and 1401 * descendants. May be null if the nodeinfos 1402 * shouldn't be changed. 1403 * @param aReparentScope Scope into which wrappers should be reparented, or 1404 * null if no reparenting should be done. 1405 * @param aParent If aClone is true the cloned node will be appended to 1406 * aParent's children. May be null. If not null then aNode 1407 * must be an nsIContent. 1408 * @param aError The error, if any. 1409 * 1410 * @return If aClone is true then the cloned node will be returned, 1411 * unless an error occurred. In error conditions, null 1412 * will be returned. 1413 */ 1414 static already_AddRefed<nsINode> CloneAndAdopt( 1415 nsINode* aNode, bool aClone, bool aDeep, 1416 nsNodeInfoManager* aNewNodeInfoManager, 1417 JS::Handle<JSObject*> aReparentScope, nsINode* aParent, 1418 mozilla::ErrorResult& aError); 1419 1420 public: 1421 /** 1422 * Walks the node, its attributes and descendant nodes. If aNewNodeInfoManager 1423 * is not null, it is used to create new nodeinfos for the nodes. Also 1424 * reparents the XPConnect wrappers for the nodes into aReparentScope if 1425 * non-null. 1426 * 1427 * @param aNewNodeInfoManager The nodeinfo manager to use to create new 1428 * nodeinfos for the node and its attributes and 1429 * descendants. May be null if the nodeinfos 1430 * shouldn't be changed. 1431 * @param aReparentScope New scope for the wrappers, or null if no reparenting 1432 * should be done. 1433 * @param aError The error, if any. 1434 */ 1435 void Adopt(nsNodeInfoManager* aNewNodeInfoManager, 1436 JS::Handle<JSObject*> aReparentScope, 1437 mozilla::ErrorResult& aError); 1438 1439 /** 1440 * Clones the node, its attributes and, if aDeep is true, its descendant nodes 1441 * If aNewNodeInfoManager is not null, it is used to create new nodeinfos for 1442 * the clones. 1443 * 1444 * @param aDeep If true the function will be called recursively on 1445 * descendants of the node 1446 * @param aNewNodeInfoManager The nodeinfo manager to use to create new 1447 * nodeinfos for the node and its attributes and 1448 * descendants. May be null if the nodeinfos 1449 * shouldn't be changed. 1450 * @param aError The error, if any. 1451 * 1452 * @return The newly created node. Null in error conditions. 1453 */ 1454 already_AddRefed<nsINode> Clone(bool aDeep, 1455 nsNodeInfoManager* aNewNodeInfoManager, 1456 mozilla::ErrorResult& aError); 1457 1458 /** 1459 * Clones this node. This needs to be overriden by all node classes. aNodeInfo 1460 * should be identical to this node's nodeInfo, except for the document which 1461 * may be different. When cloning an element, all attributes of the element 1462 * will be cloned. The children of the node will not be cloned. 1463 * 1464 * @param aNodeInfo the nodeinfo to use for the clone 1465 * @param aResult the clone 1466 */ 1467 virtual nsresult Clone(mozilla::dom::NodeInfo*, nsINode** aResult) const = 0; 1468 1469 // A callback that gets called when we are forcefully unbound from a node (due 1470 // to the node going away). You shouldn't take a strong ref to the node from 1471 // the callback. 1472 using UnbindCallback = void (*)(nsISupports*, nsINode*); 1473 // We should keep alive these objects. 1474 struct BoundObject { 1475 nsCOMPtr<nsISupports> mObject; 1476 UnbindCallback mDtor = nullptr; 1477 1478 BoundObject(nsISupports* aObject, UnbindCallback aDtor) 1479 : mObject(aObject), mDtor(aDtor) {} 1480 1481 bool operator==(nsISupports* aOther) const { 1482 return mObject.get() == aOther; 1483 } 1484 }; 1485 1486 // This class can be extended by subclasses that wish to store more 1487 // information in the slots. 1488 class nsSlots { 1489 public: 1490 nsSlots(); 1491 1492 // If needed we could remove the vtable pointer this dtor causes by 1493 // putting a DestroySlots function on nsINode 1494 virtual ~nsSlots(); 1495 1496 virtual void Traverse(nsCycleCollectionTraversalCallback&); 1497 virtual void Unlink(nsINode&); 1498 1499 /** 1500 * A list of mutation observers 1501 */ 1502 mozilla::SafeDoublyLinkedList<nsIMutationObserver> mMutationObservers; 1503 1504 /** 1505 * An object implementing NodeList for this content (childNodes) 1506 * @see NodeList 1507 * @see nsGenericHTMLElement::GetChildNodes 1508 */ 1509 RefPtr<nsAttrChildContentList> mChildNodes; 1510 1511 /** 1512 * Weak reference to this node. This is cleared by the destructor of 1513 * nsNodeWeakReference. 1514 */ 1515 nsNodeWeakReference* MOZ_NON_OWNING_REF mWeakReference; 1516 1517 /** A list of objects that we should keep alive. See Bind/UnbindObject. */ 1518 nsTArray<BoundObject> mBoundObjects; 1519 1520 /** 1521 * A set of ranges which are in the selection and which have this node as 1522 * their endpoints' closest common inclusive ancestor 1523 * (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor). This is 1524 * a UniquePtr instead of just a LinkedList, because that prevents us from 1525 * pushing DOMSlots up to the next allocation bucket size, at the cost of 1526 * some complexity. 1527 */ 1528 mozilla::UniquePtr<mozilla::LinkedList<mozilla::dom::AbstractRange>> 1529 mClosestCommonInclusiveAncestorRanges; 1530 }; 1531 1532 /** 1533 * Functions for managing flags and slots 1534 */ 1535 #ifdef DEBUG 1536 nsSlots* DebugGetSlots() { return Slots(); } 1537 #endif 1538 1539 void SetFlags(FlagsType aFlagsToSet) { 1540 NS_ASSERTION( 1541 !(aFlagsToSet & 1542 (NODE_IS_NATIVE_ANONYMOUS_ROOT | NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | 1543 NODE_DESCENDANTS_NEED_FRAMES | NODE_NEEDS_FRAME | 1544 NODE_HAS_BEEN_IN_UA_WIDGET)) || 1545 IsContent(), 1546 "Flag only permitted on nsIContent nodes"); 1547 nsWrapperCache::SetFlags(aFlagsToSet); 1548 } 1549 1550 void UnsetFlags(FlagsType aFlagsToUnset) { 1551 NS_ASSERTION(!(aFlagsToUnset & (NODE_HAS_BEEN_IN_UA_WIDGET | 1552 NODE_IS_NATIVE_ANONYMOUS_ROOT)), 1553 "Trying to unset write-only flags"); 1554 nsWrapperCache::UnsetFlags(aFlagsToUnset); 1555 } 1556 1557 void SetEditableFlag(bool aEditable) { 1558 if (aEditable) { 1559 SetFlags(NODE_IS_EDITABLE); 1560 } else { 1561 UnsetFlags(NODE_IS_EDITABLE); 1562 } 1563 } 1564 1565 inline bool IsEditable() const; 1566 1567 /** 1568 * Check if this node is an editing host. For avoiding confusion, this always 1569 * returns false if the node is in the design mode document. 1570 */ 1571 inline bool IsEditingHost() const; 1572 1573 /** 1574 * Check if this node is in design mode or not. When this returns true and: 1575 * - if this is a Document node, it's the design mode root. 1576 * - if this is a content node, it's connected, it's not in a shadow tree 1577 * (except shadow tree for UI widget and native anonymous subtree) and its 1578 * uncomposed document is in design mode. 1579 * Note that returning true does NOT mean the node or its children is 1580 * editable. E.g., when this node is in a shadow tree of a UA widget and its 1581 * host is in design mode. 1582 */ 1583 inline bool IsInDesignMode() const; 1584 1585 /** 1586 * Returns true if |this| or any of its ancestors is native anonymous. 1587 */ 1588 bool IsInNativeAnonymousSubtree() const { 1589 return HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE); 1590 } 1591 1592 /** 1593 * If |this| or any ancestor is native anonymous, return the root of the 1594 * native anonymous subtree. Note that in case of nested native anonymous 1595 * content, this returns the innermost root, not the outermost. 1596 */ 1597 nsIContent* GetClosestNativeAnonymousSubtreeRoot() const { 1598 if (!IsInNativeAnonymousSubtree()) { 1599 MOZ_ASSERT(!HasBeenInUAWidget(), "UA widget implies anonymous"); 1600 return nullptr; 1601 } 1602 MOZ_ASSERT(IsContent(), "How did non-content end up in NAC?"); 1603 if (HasBeenInUAWidget()) { 1604 // reinterpret_cast because in this header we don't know ShadowRoot is an 1605 // nsIContent. ShadowRoot constructor asserts this is correct. 1606 return reinterpret_cast<nsIContent*>(GetContainingShadow()); 1607 } 1608 for (const nsINode* node = this; node; node = node->GetParentNode()) { 1609 if (node->IsRootOfNativeAnonymousSubtree()) { 1610 return const_cast<nsINode*>(node)->AsContent(); 1611 } 1612 } 1613 // FIXME(emilio): This should not happen, usually, but editor removes nodes 1614 // in native anonymous subtrees, and we don't clean nodes from the current 1615 // event content stack from ContentRemoved, so it can actually happen, see 1616 // bug 1510208. 1617 NS_WARNING("GetClosestNativeAnonymousSubtreeRoot on disconnected NAC!"); 1618 return nullptr; 1619 } 1620 1621 /** 1622 * If |this| or any ancestor is native anonymous, return the parent of the 1623 * native anonymous subtree. Note that in case of nested native anonymous 1624 * content, this returns the parent or host of the innermost root, not the 1625 * outermost. 1626 */ 1627 nsIContent* GetClosestNativeAnonymousSubtreeRootParentOrHost() const { 1628 // We could put this in nsIContentInlines.h or such to avoid this 1629 // reinterpret_cast, but it doesn't seem worth it. 1630 const auto* root = reinterpret_cast<const nsINode*>( 1631 GetClosestNativeAnonymousSubtreeRoot()); 1632 if (!root) { 1633 return nullptr; 1634 } 1635 if (nsIContent* parent = root->GetParent()) { 1636 return parent; 1637 } 1638 if (MOZ_UNLIKELY(root->IsInShadowTree())) { 1639 return root->DoGetShadowHost(); 1640 } 1641 return nullptr; 1642 } 1643 1644 /** 1645 * Gets the root of the node tree for this content if it is in a shadow tree. 1646 */ 1647 mozilla::dom::ShadowRoot* GetContainingShadow() const; 1648 /** 1649 * Gets the shadow host if this content is in a shadow tree. That is, the host 1650 * of |GetContainingShadow|, if its not null. 1651 * 1652 * @return The shadow host, if this is in shadow tree, or null. 1653 */ 1654 mozilla::dom::Element* GetContainingShadowHost() const; 1655 1656 bool IsInSVGUseShadowTree() const { 1657 return !!GetContainingSVGUseShadowHost(); 1658 } 1659 1660 mozilla::dom::SVGUseElement* GetContainingSVGUseShadowHost() const { 1661 if (!IsInShadowTree()) { 1662 return nullptr; 1663 } 1664 return DoGetContainingSVGUseShadowHost(); 1665 } 1666 1667 // Whether this node has ever been part of a UA widget shadow tree. 1668 bool HasBeenInUAWidget() const { return HasFlag(NODE_HAS_BEEN_IN_UA_WIDGET); } 1669 1670 // True for native anonymous content and for content in UA widgets. 1671 // Only nsIContent can fulfill this condition. 1672 bool ChromeOnlyAccess() const { return IsInNativeAnonymousSubtree(); } 1673 1674 // Whether we're chrome-only for event targeting. UA widgets can use regular 1675 // shadow DOM retargeting for these. 1676 bool ChromeOnlyAccessForEvents() const { 1677 return ChromeOnlyAccess() && !HasBeenInUAWidget(); 1678 } 1679 1680 bool IsInShadowTree() const { return HasFlag(NODE_IS_IN_SHADOW_TREE); } 1681 1682 /** 1683 * Get whether this node is C++-generated anonymous content 1684 * @see nsIAnonymousContentCreator 1685 * @return whether this content is anonymous 1686 */ 1687 bool IsRootOfNativeAnonymousSubtree() const { 1688 NS_ASSERTION( 1689 !HasFlag(NODE_IS_NATIVE_ANONYMOUS_ROOT) || IsInNativeAnonymousSubtree(), 1690 "Some flags seem to be missing!"); 1691 return HasFlag(NODE_IS_NATIVE_ANONYMOUS_ROOT); 1692 } 1693 1694 // Whether this node is the root of a ChromeOnlyAccess DOM subtree. 1695 bool IsRootOfChromeAccessOnlySubtree() const { 1696 return IsRootOfNativeAnonymousSubtree(); 1697 } 1698 1699 /** Whether this is the container of a ::before pseudo-element. */ 1700 bool IsGeneratedContentContainerForBefore() const { 1701 return IsRootOfNativeAnonymousSubtree() && 1702 mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore; 1703 } 1704 1705 /** Whether this is the container of an ::after pseudo-element. */ 1706 bool IsGeneratedContentContainerForAfter() const { 1707 return IsRootOfNativeAnonymousSubtree() && 1708 mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentafter; 1709 } 1710 1711 /** Whether this is the container of a ::marker pseudo-element. */ 1712 bool IsGeneratedContentContainerForMarker() const { 1713 return IsRootOfNativeAnonymousSubtree() && 1714 mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentmarker; 1715 } 1716 1717 /** Whether this is the container of a ::backdrop pseudo-element. */ 1718 bool IsGeneratedContentContainerForBackdrop() const { 1719 return IsRootOfNativeAnonymousSubtree() && 1720 mNodeInfo->NameAtom() == nsGkAtoms::mozgeneratedcontentbackdrop; 1721 } 1722 1723 /** 1724 * Returns true if |this| node is the closest common inclusive ancestor 1725 * (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor) of the 1726 * start/end nodes of a Range in a Selection or a descendant of such a common 1727 * ancestor. This node is definitely not selected when |false| is returned, 1728 * but it may or may not be selected when |true| is returned. 1729 */ 1730 bool IsMaybeSelected() const { 1731 return IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection() || 1732 IsClosestCommonInclusiveAncestorForRangeInSelection(); 1733 } 1734 1735 /** 1736 * Return true if any part of (this, aStartOffset) .. (this, aEndOffset) 1737 * overlaps any nsRange in 1738 * GetClosestCommonInclusiveAncestorForRangeInSelection ranges (i.e. 1739 * where this is a descendant of a range's common inclusive ancestor node). 1740 * If a nsRange starts in (this, aEndOffset) or if it ends in 1741 * (this, aStartOffset) then it is non-overlapping and the result is false 1742 * for that nsRange. Collapsed ranges always counts as non-overlapping. 1743 * 1744 * @param aStartOffset has to be less or equal to aEndOffset. 1745 * @param aCache A cache which contains all fully selected nodes for each 1746 * selection. If present, this provides a fast path to check if 1747 * a node is fully selected. 1748 */ 1749 bool IsSelected(uint32_t aStartOffset, uint32_t aEndOffset, 1750 mozilla::dom::SelectionNodeCache* aCache = nullptr) const; 1751 1752 #ifdef DEBUG 1753 void AssertIsRootElementSlow(bool) const; 1754 #endif 1755 1756 /** Returns whether we're the root element of our document. */ 1757 bool IsRootElement() const { 1758 // This should be faster than pointer-chasing in the common cases, plus it 1759 // is also correct mid-unbind. 1760 const bool isRoot = !GetParent() && IsInUncomposedDoc() && IsElement(); 1761 #ifdef DEBUG 1762 AssertIsRootElementSlow(isRoot); 1763 #endif 1764 return isRoot; 1765 } 1766 1767 /** 1768 * Get the root element of the text editor associated with this node or the 1769 * root element of the text editor of the ancestor 'TextControlElement' if 1770 * this is in its native anonymous subtree. I.e., this returns anonymous 1771 * `<div>` element of a `TextEditor`. Note that this can be used only for 1772 * getting root content of `<input>` or `<textarea>`. I.e., this method 1773 * doesn't support HTML editors. Note that this may create a `TextEditor` 1774 * instance, and it means that the `TextEditor` may modify its native 1775 * anonymous subtree and may run selection listeners. 1776 */ 1777 MOZ_CAN_RUN_SCRIPT mozilla::dom::Element* GetAnonymousRootElementOfTextEditor( 1778 mozilla::TextEditor** aTextEditor = nullptr); 1779 1780 enum class IgnoreOwnIndependentSelection : bool { No, Yes }; 1781 using AllowCrossShadowBoundary = mozilla::dom::AllowRangeCrossShadowBoundary; 1782 1783 /** 1784 * Get the selection root for this node. 1785 * Note that if this node is not in an editor, the result comes from the 1786 * nsFrameSelection that is related to aPresShell, so the result might not be 1787 * the ancestor of this node. 1788 * Be aware that if this node and the computed selection limiter are not in 1789 * same subtree, this returns the root content of the closest subtree. 1790 * 1791 * @param aIgnoreOwnIndependentSelection 1792 * If "Yes", return selection root for selecting this node. 1793 * If "No", return independent selection root which is 1794 * in a native anonymous subtree hosted by this node. 1795 * For example, when this is a text control element, 1796 * return the document's selection root if "No" or return 1797 * the native anonymous <div> if "Yes". 1798 */ 1799 MOZ_CAN_RUN_SCRIPT nsIContent* GetSelectionRootContent( 1800 mozilla::PresShell* aPresShell, 1801 IgnoreOwnIndependentSelection aIgnoreOwnIndependentSelection, 1802 AllowCrossShadowBoundary aAllowCrossShadowBoundary); 1803 1804 [[nodiscard]] nsFrameSelection* GetFrameSelection() const; 1805 1806 bool HasScheduledSelectionChangeEvent() { 1807 return HasFlag(NODE_HAS_SCHEDULED_SELECTION_CHANGE_EVENT); 1808 } 1809 1810 void SetHasScheduledSelectionChangeEvent() { 1811 SetFlags(NODE_HAS_SCHEDULED_SELECTION_CHANGE_EVENT); 1812 } 1813 1814 void ClearHasScheduledSelectionChangeEvent() { 1815 UnsetFlags(NODE_HAS_SCHEDULED_SELECTION_CHANGE_EVENT); 1816 } 1817 1818 nsINodeList* ChildNodes(); 1819 1820 nsIContent* GetFirstChild() const { return mFirstChild; } 1821 1822 nsIContent* GetLastChild() const; 1823 1824 /** 1825 * Implementation is in Document.h, because it needs to cast from 1826 * Document* to nsINode*. 1827 */ 1828 Document* GetOwnerDocument() const; 1829 1830 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230) 1831 MOZ_CAN_RUN_SCRIPT_BOUNDARY void Normalize(); 1832 1833 /** 1834 * Get the base URI for any relative URIs within this piece of 1835 * content. Generally, this is the document's base URI, but certain 1836 * content carries a local base for backward compatibility. 1837 * 1838 * @return the base URI. May return null. 1839 */ 1840 virtual nsIURI* GetBaseURI(bool aTryUseXHRDocBaseURI = false) const = 0; 1841 nsIURI* GetBaseURIObject() const; 1842 1843 /** 1844 * Return true if the node may be apz aware. There are two cases. One is that 1845 * the node is apz aware (such as HTMLInputElement with number type). The 1846 * other is that the node has apz aware listeners. This is a non-virtual 1847 * function which calls IsNodeApzAwareInternal only when the MayBeApzAware is 1848 * set. We check the details in IsNodeApzAwareInternal which may be overriden 1849 * by child classes 1850 */ 1851 bool IsNodeApzAware() const { 1852 return NodeMayBeApzAware() ? IsNodeApzAwareInternal() : false; 1853 } 1854 1855 /** 1856 * Override this function and set the flag MayBeApzAware in case the node has 1857 * to let APZC be aware of it. It's used when the node may handle the apz 1858 * aware events and may do preventDefault to stop APZC to do default actions. 1859 * 1860 * For example, instead of scrolling page by APZ, we handle mouse wheel event 1861 * in HTMLInputElement with number type as increasing / decreasing its value. 1862 */ 1863 virtual bool IsNodeApzAwareInternal() const; 1864 1865 void GetTextContent(nsAString& aTextContent, mozilla::OOMReporter& aError) { 1866 GetTextContentInternal(aTextContent, aError); 1867 } 1868 MOZ_CAN_RUN_SCRIPT virtual void SetTextContent( 1869 const nsAString& aTextContent, nsIPrincipal* aSubjectPrincipal, 1870 mozilla::ErrorResult& aError) { 1871 SetTextContentInternal(aTextContent, aSubjectPrincipal, aError); 1872 } 1873 void SetTextContent(const nsAString& aTextContent, 1874 mozilla::ErrorResult& aError) { 1875 SetTextContentInternal(aTextContent, nullptr, aError); 1876 } 1877 1878 mozilla::dom::Element* QuerySelector(const nsACString& aSelector, 1879 mozilla::ErrorResult& aResult); 1880 already_AddRefed<nsINodeList> QuerySelectorAll(const nsACString& aSelector, 1881 mozilla::ErrorResult& aResult); 1882 1883 protected: 1884 // Document and ShadowRoot override this with its own (faster) version. 1885 // This should really only be called for elements and document fragments. 1886 mozilla::dom::Element* GetElementById(const nsAString& aId); 1887 1888 void AppendChildToChildList(nsIContent* aKid); 1889 void InsertChildToChildList(nsIContent* aKid, nsIContent* aNextSibling); 1890 void DisconnectChild(nsIContent* aKid); 1891 1892 public: 1893 void LookupPrefix(const nsAString& aNamespace, nsAString& aResult); 1894 bool IsDefaultNamespace(const nsAString& aNamespaceURI) { 1895 nsAutoString defaultNamespace; 1896 LookupNamespaceURI(u""_ns, defaultNamespace); 1897 return aNamespaceURI.Equals(defaultNamespace); 1898 } 1899 void LookupNamespaceURI(const nsAString& aNamespacePrefix, 1900 nsAString& aNamespaceURI); 1901 1902 nsIContent* GetNextSibling() const { return mNextSibling; } 1903 nsIContent* GetPreviousSibling() const; 1904 1905 /** 1906 * Return true if the node is being removed from the parent, it means that 1907 * the node still knows the container which it's disconnected from, but the 1908 * node has already been removed from the child node chain of the container. 1909 * I.e., Return true between a call of DisconnectChild of the parent and 1910 * a call of UnbindFromTree of the node. 1911 */ 1912 bool IsBeingRemoved() const { 1913 return mParent && !mNextSibling && !mPreviousOrLastSibling; 1914 } 1915 1916 /** 1917 * Get the next node in the pre-order tree traversal of the DOM. If 1918 * aRoot is non-null, then it must be an ancestor of |this| 1919 * (possibly equal to |this|) and only nodes that are descendants of 1920 * aRoot, not including aRoot itself, will be returned. Returns 1921 * null if there are no more nodes to traverse. 1922 */ 1923 nsIContent* GetNextNode(const nsINode* aRoot = nullptr) const { 1924 return GetNextNodeImpl(aRoot, false); 1925 } 1926 1927 /** 1928 * Get the next node in the pre-order tree traversal of the DOM but ignoring 1929 * the children of this node. If aRoot is non-null, then it must be an 1930 * ancestor of |this| (possibly equal to |this|) and only nodes that are 1931 * descendants of aRoot, not including aRoot itself, will be returned. 1932 * Returns null if there are no more nodes to traverse. 1933 */ 1934 nsIContent* GetNextNonChildNode(const nsINode* aRoot = nullptr) const { 1935 return GetNextNodeImpl(aRoot, true); 1936 } 1937 1938 /** 1939 * Returns true if 'this' is either document or element or 1940 * document fragment and aOther is a descendant in the same 1941 * anonymous tree. 1942 */ 1943 bool Contains(const nsINode* aOther) const; 1944 1945 bool UnoptimizableCCNode() const; 1946 1947 /** 1948 * Return true if the DevTools is observing the mutations in the owner 1949 * document. 1950 */ 1951 [[nodiscard]] bool MaybeNeedsToNotifyDevToolsOfNodeRemovalsInOwnerDoc() const; 1952 1953 /** 1954 * Return true when the DevTools should be notified of the removal of this 1955 * node. 1956 */ 1957 [[nodiscard]] bool DevToolsShouldBeNotifiedOfThisRemoval() const; 1958 1959 /** 1960 * Notify DevTools of the removals of all children of this node. 1961 * TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230) 1962 */ 1963 MOZ_CAN_RUN_SCRIPT_BOUNDARY void NotifyDevToolsOfRemovalsOfChildren(); 1964 1965 void QueueDevtoolsAnonymousEvent(bool aIsRemove); 1966 1967 private: 1968 mozilla::dom::SVGUseElement* DoGetContainingSVGUseShadowHost() const; 1969 1970 nsIContent* GetNextNodeImpl(const nsINode* aRoot, 1971 const bool aSkipChildren) const { 1972 #ifdef DEBUG 1973 if (aRoot) { 1974 // TODO: perhaps nsINode::IsInclusiveDescendantOf could be used instead. 1975 const nsINode* cur = this; 1976 for (; cur; cur = cur->GetParentNode()) 1977 if (cur == aRoot) break; 1978 NS_ASSERTION(cur, "aRoot not an ancestor of |this|?"); 1979 } 1980 #endif 1981 if (!aSkipChildren) { 1982 nsIContent* kid = GetFirstChild(); 1983 if (kid) { 1984 return kid; 1985 } 1986 } 1987 if (this == aRoot) { 1988 return nullptr; 1989 } 1990 const nsINode* cur = this; 1991 while (1) { 1992 nsIContent* next = cur->GetNextSibling(); 1993 if (next) { 1994 return next; 1995 } 1996 nsINode* parent = cur->GetParentNode(); 1997 if (parent == aRoot) { 1998 return nullptr; 1999 } 2000 cur = parent; 2001 } 2002 MOZ_ASSERT_UNREACHABLE("How did we get here?"); 2003 } 2004 2005 public: 2006 /** 2007 * Get the previous nsIContent in the pre-order tree traversal of the DOM. If 2008 * aRoot is non-null, then it must be an ancestor of |this| 2009 * (possibly equal to |this|) and only nsIContents that are descendants of 2010 * aRoot, including aRoot itself, will be returned. Returns 2011 * null if there are no more nsIContents to traverse. 2012 */ 2013 nsIContent* GetPrevNode(const nsINode* aRoot = nullptr) const { 2014 #ifdef DEBUG 2015 if (aRoot) { 2016 // TODO: perhaps nsINode::IsInclusiveDescendantOf could be used instead. 2017 const nsINode* cur = this; 2018 for (; cur; cur = cur->GetParentNode()) 2019 if (cur == aRoot) break; 2020 NS_ASSERTION(cur, "aRoot not an ancestor of |this|?"); 2021 } 2022 #endif 2023 2024 if (this == aRoot) { 2025 return nullptr; 2026 } 2027 nsIContent* cur = this->GetParent(); 2028 nsIContent* iter = this->GetPreviousSibling(); 2029 while (iter) { 2030 cur = iter; 2031 iter = reinterpret_cast<nsINode*>(iter)->GetLastChild(); 2032 } 2033 return cur; 2034 } 2035 2036 /** 2037 * Boolean flags 2038 */ 2039 private: 2040 enum BooleanFlag { 2041 // Set if we're being used from -moz-element or observed via a mask, 2042 // clipPath, filter or use element. 2043 NodeHasDirectRenderingObservers, 2044 // Set if our parent chain (including this node itself) terminates 2045 // in a document 2046 IsInDocument, 2047 // Set if we're part of the composed doc. 2048 // https://dom.spec.whatwg.org/#connected 2049 IsConnected, 2050 // Set if mParent is an nsIContent 2051 ParentIsContent, 2052 // Set if this node is an Element 2053 NodeIsElement, 2054 // Set if the element has a non-empty id attribute. This can in rare 2055 // cases lie for nsXMLElement, such as when the node has been moved between 2056 // documents with different id mappings. 2057 ElementHasID, 2058 // Set if the element might have a class. 2059 ElementMayHaveClass, 2060 // Set if the element might have inline style. 2061 ElementMayHaveStyle, 2062 // Set if the element has a name attribute set. 2063 ElementHasName, 2064 // Set if the element has a part attribute set. 2065 ElementHasPart, 2066 // Set if the element might have a contenteditable attribute set. 2067 ElementMayHaveContentEditableAttr, 2068 // Set if the element has a contenteditable attribute whose value makes the 2069 // element editable. 2070 ElementHasContentEditableAttrTrueOrPlainTextOnly, 2071 // Set if the node is the closest common inclusive ancestor of the start/end 2072 // nodes of a Range that is in a Selection. 2073 NodeIsClosestCommonInclusiveAncestorForRangeInSelection, 2074 // Set if the node is a descendant of a node with the above bit set. 2075 NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection, 2076 // Set if CanSkipInCC check has been done for this subtree root. 2077 NodeIsCCMarkedRoot, 2078 // Maybe set if this node is in black subtree. 2079 NodeIsCCBlackTree, 2080 // Maybe set if the node is a root of a subtree 2081 // which needs to be kept in the purple buffer. 2082 NodeIsPurpleRoot, 2083 // Set if the element has some style states locked 2084 ElementHasLockedStyleStates, 2085 // Set if element has pointer locked 2086 ElementHasPointerLock, 2087 // Set if the node may have DOMMutationObserver attached to it. 2088 NodeMayHaveDOMMutationObserver, 2089 // Set if node is Content 2090 NodeIsContent, 2091 // Set if the node has animations or transitions 2092 ElementHasAnimations, 2093 // Set if node has a dir attribute with a valid value (ltr, rtl, or auto). 2094 // Note that we cannot compute this from the dir attribute event state 2095 // flags, because we can't use those to distinguish 2096 // <bdi dir="some-invalid-value"> and <bdi dir="auto">. 2097 NodeHasValidDirAttribute, 2098 // Set if a node in the node's parent chain has dir=auto and nothing 2099 // inbetween nor the node itself establishes its own direction. 2100 NodeAncestorHasDirAuto, 2101 // Set if the node or an ancestor is assigned to a dir=auto slot and 2102 // nothing between nor the node itself establishes its own direction. 2103 // Except for when the node assigned to the dir=auto slot establishes 2104 // its own direction, then the flag is still set. 2105 NodeAffectsDirAutoSlot, 2106 // Set if the node is handling a click. 2107 NodeHandlingClick, 2108 // Set if the element has a parser insertion mode other than "in body", 2109 // per the HTML5 "Parse state" section. 2110 ElementHasWeirdParserInsertionMode, 2111 // Parser sets this flag if it has notified about the node. 2112 ParserHasNotified, 2113 // Sets if the node is apz aware or we have apz aware listeners. 2114 MayBeApzAware, 2115 // Set if the element might have any kind of anonymous content children, 2116 // which would not be found through the element's children list. 2117 ElementMayHaveAnonymousChildren, 2118 // Set if element has CustomElementData. 2119 ElementHasCustomElementData, 2120 // Set if the element was created from prototype cache and 2121 // its l10n attributes haven't been changed. 2122 ElementCreatedFromPrototypeAndHasUnmodifiedL10n, 2123 // Guard value 2124 BooleanFlagCount 2125 }; 2126 2127 void SetBoolFlag(BooleanFlag name, bool value) { 2128 static_assert(BooleanFlagCount <= 8 * sizeof(mBoolFlags), 2129 "Too many boolean flags"); 2130 mBoolFlags = (mBoolFlags & ~(1U << name)) | (value << name); 2131 } 2132 2133 void SetBoolFlag(BooleanFlag name) { 2134 static_assert(BooleanFlagCount <= 8 * sizeof(mBoolFlags), 2135 "Too many boolean flags"); 2136 mBoolFlags |= (1U << name); 2137 } 2138 2139 void ClearBoolFlag(BooleanFlag name) { 2140 static_assert(BooleanFlagCount <= 8 * sizeof(mBoolFlags), 2141 "Too many boolean flags"); 2142 mBoolFlags &= ~(1U << name); 2143 } 2144 2145 bool GetBoolFlag(BooleanFlag name) const { 2146 static_assert(BooleanFlagCount <= 8 * sizeof(mBoolFlags), 2147 "Too many boolean flags"); 2148 return mBoolFlags & (1U << name); 2149 } 2150 2151 public: 2152 bool HasDirectRenderingObservers() const { 2153 return GetBoolFlag(NodeHasDirectRenderingObservers); 2154 } 2155 void SetHasDirectRenderingObservers(bool aValue) { 2156 SetBoolFlag(NodeHasDirectRenderingObservers, aValue); 2157 } 2158 bool IsContent() const { return GetBoolFlag(NodeIsContent); } 2159 bool HasID() const { return GetBoolFlag(ElementHasID); } 2160 bool MayHaveClass() const { return GetBoolFlag(ElementMayHaveClass); } 2161 void SetMayHaveClass() { SetBoolFlag(ElementMayHaveClass); } 2162 bool MayHaveStyle() const { return GetBoolFlag(ElementMayHaveStyle); } 2163 bool HasName() const { return GetBoolFlag(ElementHasName); } 2164 bool HasPartAttribute() const { return GetBoolFlag(ElementHasPart); } 2165 bool MayHaveContentEditableAttr() const { 2166 return GetBoolFlag(ElementMayHaveContentEditableAttr); 2167 } 2168 /** 2169 * HasContentEditableAttrTrueOrPlainTextOnly() should not be called between 2170 * nsGenericHTMLElement::BeforeSetAttr and nsGenericHTMLElement::AfterSetAttr 2171 * because this is set and cleared by nsGenericHTMLElement::AfterSetAttr. 2172 */ 2173 bool HasContentEditableAttrTrueOrPlainTextOnly() const { 2174 return GetBoolFlag(ElementHasContentEditableAttrTrueOrPlainTextOnly); 2175 } 2176 /** 2177 * https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor 2178 */ 2179 bool IsClosestCommonInclusiveAncestorForRangeInSelection() const { 2180 return GetBoolFlag(NodeIsClosestCommonInclusiveAncestorForRangeInSelection); 2181 } 2182 /** 2183 * https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor 2184 */ 2185 void SetClosestCommonInclusiveAncestorForRangeInSelection() { 2186 SetBoolFlag(NodeIsClosestCommonInclusiveAncestorForRangeInSelection); 2187 } 2188 /** 2189 * https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor 2190 */ 2191 void ClearClosestCommonInclusiveAncestorForRangeInSelection() { 2192 ClearBoolFlag(NodeIsClosestCommonInclusiveAncestorForRangeInSelection); 2193 } 2194 /** 2195 * https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor 2196 */ 2197 bool IsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection() const { 2198 return GetBoolFlag( 2199 NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection); 2200 } 2201 /** 2202 * https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor 2203 */ 2204 void SetDescendantOfClosestCommonInclusiveAncestorForRangeInSelection() { 2205 SetBoolFlag( 2206 NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection); 2207 } 2208 /** 2209 * https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor 2210 */ 2211 void ClearDescendantOfClosestCommonInclusiveAncestorForRangeInSelection() { 2212 ClearBoolFlag( 2213 NodeIsDescendantOfClosestCommonInclusiveAncestorForRangeInSelection); 2214 } 2215 2216 void SetCCMarkedRoot(bool aValue) { SetBoolFlag(NodeIsCCMarkedRoot, aValue); } 2217 bool CCMarkedRoot() const { return GetBoolFlag(NodeIsCCMarkedRoot); } 2218 void SetInCCBlackTree(bool aValue) { SetBoolFlag(NodeIsCCBlackTree, aValue); } 2219 bool InCCBlackTree() const { return GetBoolFlag(NodeIsCCBlackTree); } 2220 void SetIsPurpleRoot(bool aValue) { SetBoolFlag(NodeIsPurpleRoot, aValue); } 2221 bool IsPurpleRoot() const { return GetBoolFlag(NodeIsPurpleRoot); } 2222 bool MayHaveDOMMutationObserver() { 2223 return GetBoolFlag(NodeMayHaveDOMMutationObserver); 2224 } 2225 void SetMayHaveDOMMutationObserver() { 2226 SetBoolFlag(NodeMayHaveDOMMutationObserver, true); 2227 } 2228 bool HasListenerManager() { return HasFlag(NODE_HAS_LISTENERMANAGER); } 2229 bool HasPointerLock() const { return GetBoolFlag(ElementHasPointerLock); } 2230 void SetPointerLock() { SetBoolFlag(ElementHasPointerLock); } 2231 void ClearPointerLock() { ClearBoolFlag(ElementHasPointerLock); } 2232 bool MayHaveAnimations() const { return GetBoolFlag(ElementHasAnimations); } 2233 void SetMayHaveAnimations() { SetBoolFlag(ElementHasAnimations); } 2234 void ClearMayHaveAnimations() { ClearBoolFlag(ElementHasAnimations); } 2235 void SetHasValidDir() { SetBoolFlag(NodeHasValidDirAttribute); } 2236 void ClearHasValidDir() { ClearBoolFlag(NodeHasValidDirAttribute); } 2237 bool HasValidDir() const { return GetBoolFlag(NodeHasValidDirAttribute); } 2238 void SetAncestorHasDirAuto() { SetBoolFlag(NodeAncestorHasDirAuto); } 2239 void ClearAncestorHasDirAuto() { ClearBoolFlag(NodeAncestorHasDirAuto); } 2240 bool AncestorHasDirAuto() const { 2241 return GetBoolFlag(NodeAncestorHasDirAuto); 2242 } 2243 void SetAffectsDirAutoSlot() { SetBoolFlag(NodeAffectsDirAutoSlot); } 2244 void ClearAffectsDirAutoSlot() { ClearBoolFlag(NodeAffectsDirAutoSlot); } 2245 2246 // Set if the node or an ancestor is assigned to a dir=auto slot. 2247 bool AffectsDirAutoSlot() const { 2248 return GetBoolFlag(NodeAffectsDirAutoSlot); 2249 } 2250 2251 // Implemented in nsIContentInlines.h. 2252 inline bool NodeOrAncestorHasDirAuto() const; 2253 2254 void SetParserHasNotified() { SetBoolFlag(ParserHasNotified); }; 2255 bool HasParserNotified() { return GetBoolFlag(ParserHasNotified); } 2256 2257 void SetMayBeApzAware() { SetBoolFlag(MayBeApzAware); } 2258 bool NodeMayBeApzAware() const { return GetBoolFlag(MayBeApzAware); } 2259 2260 void SetMayHaveAnonymousChildren() { 2261 SetBoolFlag(ElementMayHaveAnonymousChildren); 2262 } 2263 bool MayHaveAnonymousChildren() const { 2264 return GetBoolFlag(ElementMayHaveAnonymousChildren); 2265 } 2266 2267 void SetHasCustomElementData() { SetBoolFlag(ElementHasCustomElementData); } 2268 bool HasCustomElementData() const { 2269 return GetBoolFlag(ElementHasCustomElementData); 2270 } 2271 2272 void SetElementCreatedFromPrototypeAndHasUnmodifiedL10n() { 2273 SetBoolFlag(ElementCreatedFromPrototypeAndHasUnmodifiedL10n); 2274 } 2275 bool HasElementCreatedFromPrototypeAndHasUnmodifiedL10n() { 2276 return GetBoolFlag(ElementCreatedFromPrototypeAndHasUnmodifiedL10n); 2277 } 2278 void ClearElementCreatedFromPrototypeAndHasUnmodifiedL10n() { 2279 ClearBoolFlag(ElementCreatedFromPrototypeAndHasUnmodifiedL10n); 2280 } 2281 2282 inline mozilla::dom::ShadowRoot* GetShadowRoot() const; 2283 2284 // Return the shadow root of the node if it is a shadow host and 2285 // it meets the requirements for being a shadow host of a selection. 2286 // For example, <details>, <video> and <use> elements are not valid 2287 // shadow host for selection. 2288 mozilla::dom::ShadowRoot* GetShadowRootForSelection() const; 2289 2290 protected: 2291 void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); } 2292 void SetIsInDocument() { SetBoolFlag(IsInDocument); } 2293 void ClearInDocument() { ClearBoolFlag(IsInDocument); } 2294 void SetIsConnected(bool aConnected) { SetBoolFlag(IsConnected, aConnected); } 2295 void SetNodeIsContent() { SetBoolFlag(NodeIsContent); } 2296 void SetIsElement() { SetBoolFlag(NodeIsElement); } 2297 void SetHasID() { SetBoolFlag(ElementHasID); } 2298 void ClearHasID() { ClearBoolFlag(ElementHasID); } 2299 void SetMayHaveStyle() { SetBoolFlag(ElementMayHaveStyle); } 2300 void SetHasName() { SetBoolFlag(ElementHasName); } 2301 void ClearHasName() { ClearBoolFlag(ElementHasName); } 2302 void SetHasPartAttribute(bool aPart) { SetBoolFlag(ElementHasPart, aPart); } 2303 void SetMayHaveContentEditableAttr() { 2304 SetBoolFlag(ElementMayHaveContentEditableAttr); 2305 } 2306 void ClearMayHaveContentEditableAttr() { 2307 ClearBoolFlag(ElementMayHaveContentEditableAttr); 2308 } 2309 void SetHasContentEditableAttrTrueOrPlainTextOnly() { 2310 SetBoolFlag(ElementHasContentEditableAttrTrueOrPlainTextOnly); 2311 } 2312 void ClearHasContentEditableAttrTrueOrPlainTextOnly() { 2313 ClearBoolFlag(ElementHasContentEditableAttrTrueOrPlainTextOnly); 2314 } 2315 void SetHasLockedStyleStates() { SetBoolFlag(ElementHasLockedStyleStates); } 2316 void ClearHasLockedStyleStates() { 2317 ClearBoolFlag(ElementHasLockedStyleStates); 2318 } 2319 bool HasLockedStyleStates() const { 2320 return GetBoolFlag(ElementHasLockedStyleStates); 2321 } 2322 void SetHasWeirdParserInsertionMode() { 2323 SetBoolFlag(ElementHasWeirdParserInsertionMode); 2324 } 2325 bool HasWeirdParserInsertionMode() const { 2326 return GetBoolFlag(ElementHasWeirdParserInsertionMode); 2327 } 2328 bool HandlingClick() const { return GetBoolFlag(NodeHandlingClick); } 2329 void SetHandlingClick() { SetBoolFlag(NodeHandlingClick); } 2330 void ClearHandlingClick() { ClearBoolFlag(NodeHandlingClick); } 2331 2332 void SetSubtreeRootPointer(nsINode* aSubtreeRoot) { 2333 NS_ASSERTION(aSubtreeRoot, "aSubtreeRoot can never be null!"); 2334 NS_ASSERTION(!(IsContent() && IsInUncomposedDoc()) && !IsInShadowTree(), 2335 "Shouldn't be here!"); 2336 mSubtreeRoot = aSubtreeRoot; 2337 } 2338 2339 void ClearSubtreeRootPointer() { mSubtreeRoot = nullptr; } 2340 2341 public: 2342 // Makes nsINode object keep aObject alive. If a callback is provided, it's 2343 // called before deleting the node. 2344 void BindObject(nsISupports* aObject, UnbindCallback = nullptr); 2345 // After calling UnbindObject nsINode, object doesn't keep aObject alive 2346 // anymore. 2347 void UnbindObject(nsISupports* aObject); 2348 2349 void GenerateXPath(nsAString& aResult); 2350 2351 already_AddRefed<mozilla::dom::AccessibleNode> GetAccessibleNode(); 2352 2353 /** 2354 * Returns the length of this node, as specified at 2355 * <http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length> 2356 */ 2357 uint32_t Length() const; 2358 2359 void GetNodeName(mozilla::dom::DOMString& aNodeName) { 2360 const nsString& nodeName = NodeName(); 2361 aNodeName.SetKnownLiveString(nodeName); 2362 } 2363 [[nodiscard]] nsresult GetBaseURI(nsAString& aBaseURI) const; 2364 // Return the base URI for the document. 2365 // The returned value may differ if the document is loaded via XHR, and 2366 // when accessed from chrome privileged script and 2367 // from content privileged script for compatibility. 2368 void GetBaseURIFromJS(nsAString& aBaseURI, CallerType aCallerType, 2369 ErrorResult& aRv) const; 2370 bool HasChildNodes() const { return HasChildren(); } 2371 2372 uint16_t CompareDocumentPosition(const nsINode& aOther) const; 2373 void GetNodeValue(nsAString& aNodeValue) { GetNodeValueInternal(aNodeValue); } 2374 MOZ_CAN_RUN_SCRIPT virtual void SetNodeValue(const nsAString& aNodeValue, 2375 mozilla::ErrorResult& aError) { 2376 SetNodeValueInternal(aNodeValue, aError); 2377 } 2378 virtual void GetNodeValueInternal(nsAString& aNodeValue); 2379 virtual void SetNodeValueInternal( 2380 const nsAString& aNodeValue, mozilla::ErrorResult& aError, 2381 MutationEffectOnScript aMutationEffectOnScript = 2382 MutationEffectOnScript::DropTrustWorthiness) { 2383 // The DOM spec says that when nodeValue is defined to be null "setting it 2384 // has no effect", so we don't throw an exception. 2385 } 2386 void EnsurePreInsertionValidity(nsINode& aNewChild, nsINode* aRefChild, 2387 mozilla::ErrorResult& aError); 2388 nsINode* InsertBefore(nsINode& aNode, nsINode* aChild, 2389 mozilla::ErrorResult& aError) { 2390 return InsertBeforeInternal( 2391 aNode, aChild, MutationEffectOnScript::DropTrustWorthiness, aError); 2392 } 2393 nsINode* InsertBeforeInternal(nsINode& aNode, nsINode* aChild, 2394 MutationEffectOnScript aMutationEffectOnScript, 2395 mozilla::ErrorResult& aError) { 2396 return ReplaceOrInsertBefore(false, &aNode, aChild, aMutationEffectOnScript, 2397 aError); 2398 } 2399 2400 /** 2401 * See <https://dom.spec.whatwg.org/#dom-node-appendchild>. 2402 */ 2403 nsINode* AppendChild(nsINode& aNode, mozilla::ErrorResult& aError) { 2404 return AppendChildInternal( 2405 aNode, MutationEffectOnScript::DropTrustWorthiness, aError); 2406 } 2407 nsINode* AppendChildInternal(nsINode& aNode, 2408 MutationEffectOnScript aMutationEffectOnScript, 2409 mozilla::ErrorResult& aError) { 2410 return InsertBeforeInternal(aNode, nullptr, aMutationEffectOnScript, 2411 aError); 2412 } 2413 2414 nsINode* ReplaceChild(nsINode& aNode, nsINode& aChild, 2415 mozilla::ErrorResult& aError) { 2416 return ReplaceChildInternal( 2417 aNode, aChild, MutationEffectOnScript::DropTrustWorthiness, aError); 2418 } 2419 nsINode* ReplaceChildInternal(nsINode& aNode, nsINode& aChild, 2420 MutationEffectOnScript aMutationEffectOnScript, 2421 mozilla::ErrorResult& aError) { 2422 return ReplaceOrInsertBefore(true, &aNode, &aChild, aMutationEffectOnScript, 2423 aError); 2424 } 2425 2426 nsINode* RemoveChild(nsINode& aChild, mozilla::ErrorResult& aError) { 2427 return RemoveChildInternal( 2428 aChild, MutationEffectOnScript::DropTrustWorthiness, aError); 2429 } 2430 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230) 2431 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsINode* RemoveChildInternal( 2432 nsINode& aChild, MutationEffectOnScript aMutationEffectOnScript, 2433 mozilla::ErrorResult& aError); 2434 already_AddRefed<nsINode> CloneNode(bool aDeep, mozilla::ErrorResult& aError); 2435 bool IsSameNode(nsINode* aNode); 2436 bool IsEqualNode(nsINode* aNode); 2437 void GetNamespaceURI(nsAString& aNamespaceURI) const { 2438 mNodeInfo->GetNamespaceURI(aNamespaceURI); 2439 } 2440 #ifdef MOZILLA_INTERNAL_API 2441 void GetPrefix(nsAString& aPrefix) { mNodeInfo->GetPrefix(aPrefix); } 2442 #endif 2443 void GetLocalName(mozilla::dom::DOMString& aLocalName) const { 2444 const nsString& localName = LocalName(); 2445 aLocalName.SetKnownLiveString(localName); 2446 } 2447 2448 nsDOMAttributeMap* GetAttributes(); 2449 2450 // Helper method to remove this node from its parent. This is not exposed 2451 // through WebIDL. 2452 // Only call this if the node has a parent node. 2453 nsresult RemoveFromParent() { 2454 nsINode* parent = GetParentNode(); 2455 mozilla::ErrorResult rv; 2456 parent->RemoveChildInternal( 2457 *this, MutationEffectOnScript::DropTrustWorthiness, rv); 2458 return rv.StealNSResult(); 2459 } 2460 2461 // ChildNode methods 2462 inline mozilla::dom::Element* GetPreviousElementSibling() const; 2463 inline mozilla::dom::Element* GetNextElementSibling() const; 2464 2465 MOZ_CAN_RUN_SCRIPT void Before(const Sequence<OwningNodeOrString>& aNodes, 2466 ErrorResult& aRv); 2467 MOZ_CAN_RUN_SCRIPT void After(const Sequence<OwningNodeOrString>& aNodes, 2468 ErrorResult& aRv); 2469 MOZ_CAN_RUN_SCRIPT void ReplaceWith( 2470 const Sequence<OwningNodeOrString>& aNodes, ErrorResult& aRv); 2471 /** 2472 * Remove this node from its parent, if any. 2473 */ 2474 void Remove(); 2475 2476 // ParentNode methods 2477 mozilla::dom::Element* GetFirstElementChild() const; 2478 mozilla::dom::Element* GetLastElementChild() const; 2479 2480 already_AddRefed<nsIHTMLCollection> GetElementsByAttribute( 2481 const nsAString& aAttribute, const nsAString& aValue); 2482 already_AddRefed<nsIHTMLCollection> GetElementsByAttributeNS( 2483 const nsAString& aNamespaceURI, const nsAString& aAttribute, 2484 const nsAString& aValue, ErrorResult& aRv); 2485 2486 MOZ_CAN_RUN_SCRIPT void Prepend(const Sequence<OwningNodeOrString>& aNodes, 2487 ErrorResult& aRv); 2488 MOZ_CAN_RUN_SCRIPT void Append(const Sequence<OwningNodeOrString>& aNodes, 2489 ErrorResult& aRv); 2490 MOZ_CAN_RUN_SCRIPT void ReplaceChildren( 2491 const Sequence<OwningNodeOrString>& aNodes, ErrorResult& aRv); 2492 MOZ_CAN_RUN_SCRIPT void ReplaceChildren( 2493 nsINode* aNode, ErrorResult& aRv, 2494 MutationEffectOnScript aMutationEffectOnScript = 2495 MutationEffectOnScript::DropTrustWorthiness); 2496 2497 MOZ_CAN_RUN_SCRIPT void MoveBefore(nsINode& aNode, nsINode* aChild, 2498 ErrorResult& aRv); 2499 2500 void GetBoxQuads(const BoxQuadOptions& aOptions, 2501 nsTArray<RefPtr<DOMQuad>>& aResult, CallerType aCallerType, 2502 ErrorResult& aRv); 2503 2504 void GetBoxQuadsFromWindowOrigin(const BoxQuadOptions& aOptions, 2505 nsTArray<RefPtr<DOMQuad>>& aResult, 2506 ErrorResult& aRv); 2507 2508 already_AddRefed<DOMQuad> ConvertQuadFromNode( 2509 DOMQuad& aQuad, const TextOrElementOrDocument& aFrom, 2510 const ConvertCoordinateOptions& aOptions, CallerType aCallerType, 2511 ErrorResult& aRv); 2512 already_AddRefed<DOMQuad> ConvertRectFromNode( 2513 DOMRectReadOnly& aRect, const TextOrElementOrDocument& aFrom, 2514 const ConvertCoordinateOptions& aOptions, CallerType aCallerType, 2515 ErrorResult& aRv); 2516 already_AddRefed<DOMPoint> ConvertPointFromNode( 2517 const DOMPointInit& aPoint, const TextOrElementOrDocument& aFrom, 2518 const ConvertCoordinateOptions& aOptions, CallerType aCallerType, 2519 ErrorResult& aRv); 2520 2521 /** 2522 * See nsSlots::mClosestCommonInclusiveAncestorRanges. 2523 */ 2524 const mozilla::LinkedList<mozilla::dom::AbstractRange>* 2525 GetExistingClosestCommonInclusiveAncestorRanges() const { 2526 if (!HasSlots()) { 2527 return nullptr; 2528 } 2529 return GetExistingSlots()->mClosestCommonInclusiveAncestorRanges.get(); 2530 } 2531 2532 /** 2533 * See nsSlots::mClosestCommonInclusiveAncestorRanges. 2534 */ 2535 mozilla::LinkedList<mozilla::dom::AbstractRange>* 2536 GetExistingClosestCommonInclusiveAncestorRanges() { 2537 if (!HasSlots()) { 2538 return nullptr; 2539 } 2540 return GetExistingSlots()->mClosestCommonInclusiveAncestorRanges.get(); 2541 } 2542 2543 /** 2544 * See nsSlots::mClosestCommonInclusiveAncestorRanges. 2545 */ 2546 mozilla::UniquePtr<mozilla::LinkedList<mozilla::dom::AbstractRange>>& 2547 GetClosestCommonInclusiveAncestorRangesPtr() { 2548 return Slots()->mClosestCommonInclusiveAncestorRanges; 2549 } 2550 2551 nsIWeakReference* GetExistingWeakReference() { 2552 return HasSlots() ? GetExistingSlots()->mWeakReference : nullptr; 2553 } 2554 2555 void QueueAncestorRevealingAlgorithm(); 2556 2557 MOZ_CAN_RUN_SCRIPT void AncestorRevealingAlgorithm(ErrorResult& aRv); 2558 2559 protected: 2560 // Override this function to create a custom slots class. 2561 // Must not return null. 2562 virtual nsINode::nsSlots* CreateSlots(); 2563 2564 bool HasSlots() const { return mSlots != nullptr; } 2565 2566 nsSlots* GetExistingSlots() const { return mSlots; } 2567 2568 nsSlots* Slots() { 2569 if (!HasSlots()) { 2570 mSlots = CreateSlots(); 2571 MOZ_ASSERT(mSlots); 2572 } 2573 return GetExistingSlots(); 2574 } 2575 2576 /** 2577 * Invalidate cached child array inside mChildNodes 2578 * of type nsParentNodeChildContentList. 2579 */ 2580 void InvalidateChildNodes(); 2581 2582 virtual void GetTextContentInternal(nsAString& aTextContent, 2583 mozilla::OOMReporter& aError); 2584 virtual void SetTextContentInternal( 2585 const nsAString& aTextContent, nsIPrincipal* aSubjectPrincipal, 2586 mozilla::ErrorResult& aError, 2587 MutationEffectOnScript aMutationEffectOnScript = 2588 MutationEffectOnScript::DropTrustWorthiness) {} 2589 2590 void EnsurePreInsertionValidity1(mozilla::ErrorResult& aError); 2591 void EnsurePreInsertionValidity2(bool aReplace, nsINode& aNewChild, 2592 nsINode* aRefChild, 2593 mozilla::ErrorResult& aError); 2594 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230) 2595 MOZ_CAN_RUN_SCRIPT_BOUNDARY nsINode* ReplaceOrInsertBefore( 2596 bool aReplace, nsINode* aNewChild, nsINode* aRefChild, 2597 MutationEffectOnScript aMutationEffectOnScript, 2598 mozilla::ErrorResult& aError); 2599 2600 /** 2601 * Returns the Element that should be used for resolving namespaces 2602 * on this node (ie the ownerElement for attributes, the documentElement for 2603 * documents, the node itself for elements and for other nodes the parentNode 2604 * if it is an element). 2605 */ 2606 virtual mozilla::dom::Element* GetNameSpaceElement() = 0; 2607 2608 /** 2609 * Parse the given selector string into a servo SelectorList. 2610 * 2611 * Never returns null if aRv is not failing. 2612 * 2613 * Note that the selector list returned here is owned by the owner doc's 2614 * selector cache. 2615 */ 2616 const mozilla::StyleSelectorList* ParseSelectorList( 2617 const nsACString& aSelectorString, mozilla::ErrorResult&); 2618 2619 public: 2620 /* Event stuff that documents and elements share. 2621 2622 Note that we include DOCUMENT_ONLY_EVENT events here so that we 2623 can forward all the document stuff to this implementation. 2624 */ 2625 #define EVENT(name_, id_, type_, struct_) \ 2626 mozilla::dom::EventHandlerNonNull* GetOn##name_() { \ 2627 return GetEventHandler(nsGkAtoms::on##name_); \ 2628 } \ 2629 void SetOn##name_(mozilla::dom::EventHandlerNonNull* handler) { \ 2630 SetEventHandler(nsGkAtoms::on##name_, handler); \ 2631 } 2632 #define TOUCH_EVENT EVENT 2633 #define DOCUMENT_ONLY_EVENT EVENT 2634 #include "mozilla/EventNameList.h" 2635 #undef DOCUMENT_ONLY_EVENT 2636 #undef TOUCH_EVENT 2637 #undef EVENT 2638 2639 NodeSelectorFlags GetSelectorFlags() const { 2640 return static_cast<NodeSelectorFlags>(mSelectorFlags.Get()); 2641 } 2642 2643 protected: 2644 static bool Traverse(nsINode* tmp, nsCycleCollectionTraversalCallback& cb); 2645 static void Unlink(nsINode* tmp); 2646 2647 RefPtr<mozilla::dom::NodeInfo> mNodeInfo; 2648 2649 // mParent is an owning ref most of the time, except for the case of document 2650 // nodes, so it cannot be represented by nsCOMPtr, so mark is as 2651 // MOZ_OWNING_REF. 2652 nsINode* MOZ_OWNING_REF mParent; 2653 2654 private: 2655 #ifndef BOOL_FLAGS_ON_WRAPPER_CACHE 2656 // Boolean flags. 2657 uint32_t mBoolFlags; 2658 #endif 2659 2660 mozilla::RustCell<uint32_t> mSelectorFlags{0}; 2661 2662 uint32_t mChildCount; 2663 2664 protected: 2665 // mNextSibling and mFirstChild are strong references while 2666 // mPreviousOrLastSibling is a weak ref. |mFirstChild->mPreviousOrLastSibling| 2667 // points to the last child node. 2668 nsCOMPtr<nsIContent> mFirstChild; 2669 nsCOMPtr<nsIContent> mNextSibling; 2670 nsIContent* MOZ_NON_OWNING_REF mPreviousOrLastSibling; 2671 2672 union { 2673 // Pointer to our primary frame. Might be null. 2674 nsIFrame* mPrimaryFrame; 2675 2676 // Pointer to the root of our subtree. Might be null. 2677 // This reference is non-owning and safe, since it either points to the 2678 // object itself, or is reset by ClearSubtreeRootPointer. 2679 nsINode* MOZ_NON_OWNING_REF mSubtreeRoot; 2680 }; 2681 2682 // Storage for more members that are usually not needed; allocated lazily. 2683 nsSlots* mSlots; 2684 }; 2685 2686 NON_VIRTUAL_ADDREF_RELEASE(nsINode) 2687 2688 template <> 2689 struct fmt::formatter<nsINode> : ostream_formatter {}; 2690 2691 inline nsINode* mozilla::dom::EventTarget::GetAsNode() { 2692 return IsNode() ? AsNode() : nullptr; 2693 } 2694 2695 inline const nsINode* mozilla::dom::EventTarget::GetAsNode() const { 2696 return const_cast<mozilla::dom::EventTarget*>(this)->GetAsNode(); 2697 } 2698 2699 inline nsINode* mozilla::dom::EventTarget::AsNode() { 2700 MOZ_DIAGNOSTIC_ASSERT(IsNode()); 2701 return static_cast<nsINode*>(this); 2702 } 2703 2704 inline const nsINode* mozilla::dom::EventTarget::AsNode() const { 2705 MOZ_DIAGNOSTIC_ASSERT(IsNode()); 2706 return static_cast<const nsINode*>(this); 2707 } 2708 2709 // Useful inline function for getting a node given an nsIContent and a Document. 2710 // Returns the first argument cast to nsINode if it is non-null, otherwise 2711 // returns the second (which may be null). We use type variables instead of 2712 // nsIContent* and Document* because the actual types must be 2713 // known for the cast to work. 2714 template <class C, class D> 2715 inline nsINode* NODE_FROM(C& aContent, D& aDocument) { 2716 if (aContent) return static_cast<nsINode*>(aContent); 2717 return static_cast<nsINode*>(aDocument); 2718 } 2719 2720 inline nsISupports* ToSupports(nsINode* aPointer) { return aPointer; } 2721 2722 // Some checks are faster to do on nsIContent or Element than on 2723 // nsINode, so spit out FromNode versions taking those types too. 2724 #define NS_IMPL_FROMNODE_GENERIC(_class, _check, _const) \ 2725 template <typename T> \ 2726 static auto FromNode(_const T& aNode) \ 2727 -> decltype(static_cast<_const _class*>(&aNode)) { \ 2728 return aNode._check ? static_cast<_const _class*>(&aNode) : nullptr; \ 2729 } \ 2730 template <typename T> \ 2731 static _const _class* FromNode(_const T* aNode) { \ 2732 return FromNode(*aNode); \ 2733 } \ 2734 template <typename T> \ 2735 static _const _class* FromNodeOrNull(_const T* aNode) { \ 2736 return aNode ? FromNode(*aNode) : nullptr; \ 2737 } \ 2738 template <typename T> \ 2739 static auto FromEventTarget(_const T& aEventTarget) \ 2740 -> decltype(static_cast<_const _class*>(&aEventTarget)) { \ 2741 return aEventTarget.IsNode() && aEventTarget.AsNode()->_check \ 2742 ? static_cast<_const _class*>(&aEventTarget) \ 2743 : nullptr; \ 2744 } \ 2745 template <typename T> \ 2746 static _const _class* FromEventTarget(_const T* aEventTarget) { \ 2747 return FromEventTarget(*aEventTarget); \ 2748 } \ 2749 template <typename T> \ 2750 static _const _class* FromEventTargetOrNull(_const T* aEventTarget) { \ 2751 return aEventTarget ? FromEventTarget(*aEventTarget) : nullptr; \ 2752 } 2753 2754 #define NS_IMPL_FROMNODE_HELPER(_class, _check) \ 2755 NS_IMPL_FROMNODE_GENERIC(_class, _check, ) \ 2756 NS_IMPL_FROMNODE_GENERIC(_class, _check, const) \ 2757 \ 2758 template <typename T> \ 2759 static _class* FromNode(T&& aNode) { \ 2760 /* We need the double-cast in case aNode is a smartptr. Those */ \ 2761 /* can cast to superclasses of the type they're templated on, */ \ 2762 /* but not directly to subclasses. */ \ 2763 return aNode->_check ? static_cast<_class*>(static_cast<nsINode*>(aNode)) \ 2764 : nullptr; \ 2765 } \ 2766 template <typename T> \ 2767 static _class* FromNodeOrNull(T&& aNode) { \ 2768 return aNode ? FromNode(aNode) : nullptr; \ 2769 } \ 2770 template <typename T> \ 2771 static _class* FromEventTarget(T&& aEventTarget) { \ 2772 /* We need the double-cast in case aEventTarget is a smartptr. Those */ \ 2773 /* can cast to superclasses of the type they're templated on, */ \ 2774 /* but not directly to subclasses. */ \ 2775 return aEventTarget->IsNode() && aEventTarget->AsNode()->_check \ 2776 ? static_cast<_class*>(static_cast<EventTarget*>(aEventTarget)) \ 2777 : nullptr; \ 2778 } \ 2779 template <typename T> \ 2780 static _class* FromEventTargetOrNull(T&& aEventTarget) { \ 2781 return aEventTarget ? FromEventTarget(aEventTarget) : nullptr; \ 2782 } 2783 2784 #define NS_IMPL_FROMNODE(_class, _nsid) \ 2785 NS_IMPL_FROMNODE_HELPER(_class, IsInNamespace(_nsid)) 2786 2787 #define NS_IMPL_FROMNODE_WITH_TAG(_class, _nsid, _tag) \ 2788 NS_IMPL_FROMNODE_HELPER(_class, NodeInfo()->Equals(nsGkAtoms::_tag, _nsid)) 2789 2790 #define NS_IMPL_FROMNODE_HTML_WITH_TAG(_class, _tag) \ 2791 NS_IMPL_FROMNODE_WITH_TAG(_class, kNameSpaceID_XHTML, _tag) 2792 2793 #endif /* nsINode_h___ */