tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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___ */