content/base/public/nsINode.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #ifndef nsINode_h___
     7 #define nsINode_h___
     9 #include "mozilla/Likely.h"
    10 #include "nsCOMPtr.h"               // for member, local
    11 #include "nsGkAtoms.h"              // for nsGkAtoms::baseURIProperty
    12 #include "nsIDOMNode.h"
    13 #include "nsINodeInfo.h"            // member (in nsCOMPtr)
    14 #include "nsIVariant.h"             // for use in GetUserData()
    15 #include "nsNodeInfoManager.h"      // for use in NodePrincipal()
    16 #include "nsPropertyTable.h"        // for typedefs
    17 #include "nsTObserverArray.h"       // for member
    18 #include "mozilla/ErrorResult.h"
    19 #include "mozilla/MemoryReporting.h"
    20 #include "mozilla/dom/EventTarget.h" // for base class
    21 #include "js/TypeDecls.h"     // for Handle, Value, JSObject, JSContext
    22 #include "mozilla/dom/DOMString.h"
    23 #include "mozilla/dom/BindingDeclarations.h"
    25 // Including 'windows.h' will #define GetClassInfo to something else.
    26 #ifdef XP_WIN
    27 #ifdef GetClassInfo
    28 #undef GetClassInfo
    29 #endif
    30 #endif
    32 class nsAttrAndChildArray;
    33 class nsChildContentList;
    34 class nsCSSSelectorList;
    35 class nsDOMAttributeMap;
    36 class nsIContent;
    37 class nsIDocument;
    38 class nsIDOMElement;
    39 class nsIDOMNodeList;
    40 class nsIDOMUserDataHandler;
    41 class nsIEditor;
    42 class nsIFrame;
    43 class nsIMutationObserver;
    44 class nsINodeList;
    45 class nsIPresShell;
    46 class nsIPrincipal;
    47 class nsIURI;
    48 class nsNodeSupportsWeakRefTearoff;
    49 class nsNodeWeakReference;
    50 class nsXPCClassInfo;
    51 class nsDOMMutationObserver;
    53 namespace mozilla {
    54 class EventListenerManager;
    55 namespace dom {
    56 /**
    57  * @return true if aChar is what the DOM spec defines as 'space character'.
    58  * http://dom.spec.whatwg.org/#space-character
    59  */
    60 inline bool IsSpaceCharacter(char16_t aChar) {
    61   return aChar == ' ' || aChar == '\t' || aChar == '\n' || aChar == '\r' ||
    62          aChar == '\f';
    63 }
    64 inline bool IsSpaceCharacter(char aChar) {
    65   return aChar == ' ' || aChar == '\t' || aChar == '\n' || aChar == '\r' ||
    66          aChar == '\f';
    67 }
    68 struct BoxQuadOptions;
    69 struct ConvertCoordinateOptions;
    70 class DOMPoint;
    71 class DOMQuad;
    72 class DOMRectReadOnly;
    73 class Element;
    74 class EventHandlerNonNull;
    75 class OnErrorEventHandlerNonNull;
    76 template<typename T> class Optional;
    77 class TextOrElementOrDocument;
    78 struct DOMPointInit;
    79 } // namespace dom
    80 } // namespace mozilla
    82 #define NODE_FLAG_BIT(n_) (1U << (WRAPPER_CACHE_FLAGS_BITS_USED + (n_)))
    84 enum {
    85   // This bit will be set if the node has a listener manager.
    86   NODE_HAS_LISTENERMANAGER =              NODE_FLAG_BIT(0),
    88   // Whether this node has had any properties set on it
    89   NODE_HAS_PROPERTIES =                   NODE_FLAG_BIT(1),
    91   // Whether this node is the root of an anonymous subtree.  Note that this
    92   // need not be a native anonymous subtree.  Any anonymous subtree, including
    93   // XBL-generated ones, will do.  This flag is set-once: once a node has it,
    94   // it must not be removed.
    95   // NOTE: Should only be used on nsIContent nodes
    96   NODE_IS_ANONYMOUS_ROOT =                NODE_FLAG_BIT(2),
    98   // Whether the node has some ancestor, possibly itself, that is native
    99   // anonymous.  This includes ancestors crossing XBL scopes, in cases when an
   100   // XBL binding is attached to an element which has a native anonymous
   101   // ancestor.  This flag is set-once: once a node has it, it must not be
   102   // removed.
   103   // NOTE: Should only be used on nsIContent nodes
   104   NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE =          NODE_FLAG_BIT(3),
   106   // Whether this node is the root of a native anonymous (from the perspective
   107   // of its parent) subtree.  This flag is set-once: once a node has it, it
   108   // must not be removed.
   109   // NOTE: Should only be used on nsIContent nodes
   110   NODE_IS_NATIVE_ANONYMOUS_ROOT =         NODE_FLAG_BIT(4),
   112   // Forces the XBL code to treat this node as if it were
   113   // in the document and therefore should get bindings attached.
   114   NODE_FORCE_XBL_BINDINGS =               NODE_FLAG_BIT(5),
   116   // Whether a binding manager may have a pointer to this
   117   NODE_MAY_BE_IN_BINDING_MNGR =           NODE_FLAG_BIT(6),
   119   NODE_IS_EDITABLE =                      NODE_FLAG_BIT(7),
   121   // For all Element nodes, NODE_MAY_HAVE_CLASS is guaranteed to be set if the
   122   // node in fact has a class, but may be set even if it doesn't.
   123   NODE_MAY_HAVE_CLASS =                   NODE_FLAG_BIT(8),
   125   // Whether the node participates in a shadow tree.
   126   NODE_IS_IN_SHADOW_TREE =                NODE_FLAG_BIT(9),
   128   // Node has an :empty or :-moz-only-whitespace selector
   129   NODE_HAS_EMPTY_SELECTOR =               NODE_FLAG_BIT(10),
   131   // A child of the node has a selector such that any insertion,
   132   // removal, or appending of children requires restyling the parent.
   133   NODE_HAS_SLOW_SELECTOR =                NODE_FLAG_BIT(11),
   135   // A child of the node has a :first-child, :-moz-first-node,
   136   // :only-child, :last-child or :-moz-last-node selector.
   137   NODE_HAS_EDGE_CHILD_SELECTOR =          NODE_FLAG_BIT(12),
   139   // A child of the node has a selector such that any insertion or
   140   // removal of children requires restyling later siblings of that
   141   // element.  Additionally (in this manner it is stronger than
   142   // NODE_HAS_SLOW_SELECTOR), if a child's style changes due to any
   143   // other content tree changes (e.g., the child changes to or from
   144   // matching :empty due to a grandchild insertion or removal), the
   145   // child's later siblings must also be restyled.
   146   NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS = NODE_FLAG_BIT(13),
   148   NODE_ALL_SELECTOR_FLAGS =               NODE_HAS_EMPTY_SELECTOR |
   149                                           NODE_HAS_SLOW_SELECTOR |
   150                                           NODE_HAS_EDGE_CHILD_SELECTOR |
   151                                           NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS,
   153   NODE_ATTACH_BINDING_ON_POSTCREATE =     NODE_FLAG_BIT(14),
   155   // This node needs to go through frame construction to get a frame (or
   156   // undisplayed entry).
   157   NODE_NEEDS_FRAME =                      NODE_FLAG_BIT(15),
   159   // At least one descendant in the flattened tree has NODE_NEEDS_FRAME set.
   160   // This should be set on every node on the flattened tree path between the
   161   // node(s) with NODE_NEEDS_FRAME and the root content.
   162   NODE_DESCENDANTS_NEED_FRAMES =          NODE_FLAG_BIT(16),
   164   // Set if the node has the accesskey attribute set.
   165   NODE_HAS_ACCESSKEY =                    NODE_FLAG_BIT(17),
   167   // Set if the node has right-to-left directionality
   168   NODE_HAS_DIRECTION_RTL =                NODE_FLAG_BIT(18),
   170   // Set if the node has left-to-right directionality
   171   NODE_HAS_DIRECTION_LTR =                NODE_FLAG_BIT(19),
   173   NODE_ALL_DIRECTION_FLAGS =              NODE_HAS_DIRECTION_LTR |
   174                                           NODE_HAS_DIRECTION_RTL,
   176   NODE_CHROME_ONLY_ACCESS =               NODE_FLAG_BIT(20),
   178   NODE_IS_ROOT_OF_CHROME_ONLY_ACCESS =    NODE_FLAG_BIT(21),
   180   // Remaining bits are node type specific.
   181   NODE_TYPE_SPECIFIC_BITS_OFFSET =        22
   182 };
   184 // Make sure we have space for our bits
   185 #define ASSERT_NODE_FLAGS_SPACE(n) \
   186   static_assert(WRAPPER_CACHE_FLAGS_BITS_USED + (n) <= 32, \
   187                 "Not enough space for our bits")
   188 ASSERT_NODE_FLAGS_SPACE(NODE_TYPE_SPECIFIC_BITS_OFFSET);
   190 /**
   191  * Class used to detect unexpected mutations. To use the class create an
   192  * nsMutationGuard on the stack before unexpected mutations could occur.
   193  * You can then at any time call Mutated to check if any unexpected mutations
   194  * have occurred.
   195  *
   196  * When a guard is instantiated sMutationCount is set to 300. It is then
   197  * decremented by every mutation (capped at 0). This means that we can only
   198  * detect 300 mutations during the lifetime of a single guard, however that
   199  * should be more then we ever care about as we usually only care if more then
   200  * one mutation has occurred.
   201  *
   202  * When the guard goes out of scope it will adjust sMutationCount so that over
   203  * the lifetime of the guard the guard itself has not affected sMutationCount,
   204  * while mutations that happened while the guard was alive still will. This
   205  * allows a guard to be instantiated even if there is another guard higher up
   206  * on the callstack watching for mutations.
   207  *
   208  * The only thing that has to be avoided is for an outer guard to be used
   209  * while an inner guard is alive. This can be avoided by only ever
   210  * instantiating a single guard per scope and only using the guard in the
   211  * current scope.
   212  */
   213 class nsMutationGuard {
   214 public:
   215   nsMutationGuard()
   216   {
   217     mDelta = eMaxMutations - sMutationCount;
   218     sMutationCount = eMaxMutations;
   219   }
   220   ~nsMutationGuard()
   221   {
   222     sMutationCount =
   223       mDelta > sMutationCount ? 0 : sMutationCount - mDelta;
   224   }
   226   /**
   227    * Returns true if any unexpected mutations have occurred. You can pass in
   228    * an 8-bit ignore count to ignore a number of expected mutations.
   229    */
   230   bool Mutated(uint8_t aIgnoreCount)
   231   {
   232     return sMutationCount < static_cast<uint32_t>(eMaxMutations - aIgnoreCount);
   233   }
   235   // This function should be called whenever a mutation that we want to keep
   236   // track of happen. For now this is only done when children are added or
   237   // removed, but we might do it for attribute changes too in the future.
   238   static void DidMutate()
   239   {
   240     if (sMutationCount) {
   241       --sMutationCount;
   242     }
   243   }
   245 private:
   246   // mDelta is the amount sMutationCount was adjusted when the guard was
   247   // initialized. It is needed so that we can undo that adjustment once
   248   // the guard dies.
   249   uint32_t mDelta;
   251   // The value 300 is not important, as long as it is bigger then anything
   252   // ever passed to Mutated().
   253   enum { eMaxMutations = 300 };
   256   // sMutationCount is a global mutation counter which is decreased by one at
   257   // every mutation. It is capped at 0 to avoid wrapping.
   258   // Its value is always between 0 and 300, inclusive.
   259   static uint32_t sMutationCount;
   260 };
   262 // This should be used for any nsINode sub-class that has fields of its own
   263 // that it needs to measure;  any sub-class that doesn't use it will inherit
   264 // SizeOfExcludingThis from its super-class.  SizeOfIncludingThis() need not be
   265 // defined, it is inherited from nsINode.
   266 // This macro isn't actually specific to nodes, and bug 956400 will move it into MFBT.
   267 #define NS_DECL_SIZEOF_EXCLUDING_THIS \
   268   virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
   270 // Categories of node properties
   271 // 0 is global.
   272 #define DOM_USER_DATA         1
   273 #define DOM_USER_DATA_HANDLER 2
   274 #define SMIL_MAPPED_ATTR_ANIMVAL 3
   276 // IID for the nsINode interface
   277 #define NS_INODE_IID \
   278 { 0x77a62cd0, 0xb34f, 0x42cb, \
   279   { 0x94, 0x52, 0xae, 0xb2, 0x4d, 0x93, 0x2c, 0xb4 } }
   281 /**
   282  * An internal interface that abstracts some DOMNode-related parts that both
   283  * nsIContent and nsIDocument share.  An instance of this interface has a list
   284  * of nsIContent children and provides access to them.
   285  */
   286 class nsINode : public mozilla::dom::EventTarget
   287 {
   288 public:
   289   typedef mozilla::dom::BoxQuadOptions BoxQuadOptions;
   290   typedef mozilla::dom::ConvertCoordinateOptions ConvertCoordinateOptions;
   291   typedef mozilla::dom::DOMPoint DOMPoint;
   292   typedef mozilla::dom::DOMPointInit DOMPointInit;
   293   typedef mozilla::dom::DOMQuad DOMQuad;
   294   typedef mozilla::dom::DOMRectReadOnly DOMRectReadOnly;
   295   typedef mozilla::dom::TextOrElementOrDocument TextOrElementOrDocument;
   296   typedef mozilla::ErrorResult ErrorResult;
   298   NS_DECLARE_STATIC_IID_ACCESSOR(NS_INODE_IID)
   300   // Among the sub-classes that inherit (directly or indirectly) from nsINode,
   301   // measurement of the following members may be added later if DMD finds it is
   302   // worthwhile:
   303   // - nsGenericHTMLElement:  mForm, mFieldSet
   304   // - nsGenericHTMLFrameElement: mFrameLoader (bug 672539)
   305   // - HTMLBodyElement:       mContentStyleRule
   306   // - HTMLDataListElement:   mOptions
   307   // - HTMLFieldSetElement:   mElements, mDependentElements, mFirstLegend
   308   // - HTMLFormElement:       many!
   309   // - HTMLFrameSetElement:   mRowSpecs, mColSpecs
   310   // - HTMLInputElement:      mInputData, mFiles, mFileList, mStaticDocfileList
   311   // - nsHTMLMapElement:      mAreas
   312   // - HTMLMediaElement:      many!
   313   // - nsHTMLOutputElement:   mDefaultValue, mTokenList
   314   // - nsHTMLRowElement:      mCells
   315   // - nsHTMLSelectElement:   mOptions, mRestoreState
   316   // - nsHTMLTableElement:    mTBodies, mRows, mTableInheritedAttributes
   317   // - nsHTMLTableSectionElement: mRows
   318   // - nsHTMLTextAreaElement: mControllers, mState
   319   //
   320   // The following members don't need to be measured:
   321   // - nsIContent: mPrimaryFrame, because it's non-owning and measured elsewhere
   322   //
   323   NS_DECL_SIZEOF_EXCLUDING_THIS
   325   // SizeOfIncludingThis doesn't need to be overridden by sub-classes because
   326   // sub-classes of nsINode are guaranteed to be laid out in memory in such a
   327   // way that |this| points to the start of the allocated object, even in
   328   // methods of nsINode's sub-classes, and so |aMallocSizeOf(this)| is always
   329   // safe to call no matter which object it was invoked on.
   330   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
   331     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   332   }
   334   friend class nsNodeUtils;
   335   friend class nsNodeWeakReference;
   336   friend class nsNodeSupportsWeakRefTearoff;
   337   friend class nsAttrAndChildArray;
   339 #ifdef MOZILLA_INTERNAL_API
   340   nsINode(already_AddRefed<nsINodeInfo>& aNodeInfo)
   341   : mNodeInfo(aNodeInfo),
   342     mParent(nullptr),
   343     mBoolFlags(0),
   344     mNextSibling(nullptr),
   345     mPreviousSibling(nullptr),
   346     mFirstChild(nullptr),
   347     mSubtreeRoot(MOZ_THIS_IN_INITIALIZER_LIST()),
   348     mSlots(nullptr)
   349   {
   350     SetIsDOMBinding();
   351   }
   352 #endif
   354   virtual ~nsINode();
   356   /**
   357    * Bit-flags to pass (or'ed together) to IsNodeOfType()
   358    */
   359   enum {
   360     /** nsIContent nodes */
   361     eCONTENT             = 1 << 0,
   362     /** nsIDocument nodes */
   363     eDOCUMENT            = 1 << 1,
   364     /** nsIAttribute nodes */
   365     eATTRIBUTE           = 1 << 2,
   366     /** text nodes */
   367     eTEXT                = 1 << 3,
   368     /** xml processing instructions */
   369     ePROCESSING_INSTRUCTION = 1 << 4,
   370     /** comment nodes */
   371     eCOMMENT             = 1 << 5,
   372     /** form control elements */
   373     eHTML_FORM_CONTROL   = 1 << 6,
   374     /** document fragments */
   375     eDOCUMENT_FRAGMENT   = 1 << 7,
   376     /** data nodes (comments, PIs, text). Nodes of this type always
   377      returns a non-null value for nsIContent::GetText() */
   378     eDATA_NODE           = 1 << 8,
   379     /** HTMLMediaElement */
   380     eMEDIA               = 1 << 9,
   381     /** animation elements */
   382     eANIMATION           = 1 << 10,
   383     /** filter elements that implement SVGFilterPrimitiveStandardAttributes */
   384     eFILTER              = 1 << 11
   385   };
   387   /**
   388    * API for doing a quick check if a content is of a given
   389    * type, such as Text, Document, Comment ...  Use this when you can instead of
   390    * checking the tag.
   391    *
   392    * @param aFlags what types you want to test for (see above)
   393    * @return whether the content matches ALL flags passed in
   394    */
   395   virtual bool IsNodeOfType(uint32_t aFlags) const = 0;
   397   virtual JSObject* WrapObject(JSContext *aCx) MOZ_OVERRIDE;
   399 protected:
   400   /**
   401    * WrapNode is called from WrapObject to actually wrap this node, WrapObject
   402    * does some additional checks and fix-up that's common to all nodes. WrapNode
   403    * should just call the DOM binding's Wrap function.
   404    */
   405   virtual JSObject* WrapNode(JSContext *aCx)
   406   {
   407     MOZ_ASSERT(!IsDOMBinding(), "Someone forgot to override WrapNode");
   408     return nullptr;
   409   }
   411   // Subclasses that wish to override the parent behavior should return the
   412   // result of GetParentObjectIntenral, which handles the XBL scope stuff.
   413   //
   414   mozilla::dom::ParentObject GetParentObjectInternal(nsINode* aNativeParent) const {
   415     mozilla::dom::ParentObject p(aNativeParent);
   416     // Note that mUseXBLScope is a no-op for chrome, and other places where we
   417     // don't use XBL scopes.
   418     p.mUseXBLScope = IsInAnonymousSubtree() && !IsAnonymousContentInSVGUseSubtree();
   419     return p;
   420   }
   422 public:
   423   mozilla::dom::ParentObject GetParentObject() const; // Implemented in nsIDocument.h
   425   /**
   426    * Return whether the node is an Element node
   427    */
   428   bool IsElement() const {
   429     return GetBoolFlag(NodeIsElement);
   430   }
   432   /**
   433    * Return this node as an Element.  Should only be used for nodes
   434    * for which IsElement() is true.  This is defined inline in Element.h.
   435    */
   436   mozilla::dom::Element* AsElement();
   437   const mozilla::dom::Element* AsElement() const;
   439   /**
   440    * Return this node as nsIContent.  Should only be used for nodes for which
   441    * IsContent() is true.  This is defined inline in nsIContent.h.
   442    */
   443   nsIContent* AsContent();
   444   const nsIContent* AsContent() const
   445   {
   446     return const_cast<nsINode*>(this)->AsContent();
   447   }
   449   virtual nsIDOMNode* AsDOMNode() = 0;
   451   /**
   452    * Return if this node has any children.
   453    */
   454   bool HasChildren() const { return !!mFirstChild; }
   456   /**
   457    * Get the number of children
   458    * @return the number of children
   459    */
   460   virtual uint32_t GetChildCount() const = 0;
   462   /**
   463    * Get a child by index
   464    * @param aIndex the index of the child to get
   465    * @return the child, or null if index out of bounds
   466    */
   467   virtual nsIContent* GetChildAt(uint32_t aIndex) const = 0;
   469   /**
   470    * Get a raw pointer to the child array.  This should only be used if you
   471    * plan to walk a bunch of the kids, promise to make sure that nothing ever
   472    * mutates (no attribute changes, not DOM tree changes, no script execution,
   473    * NOTHING), and will never ever peform an out-of-bounds access here.  This
   474    * method may return null if there are no children, or it may return a
   475    * garbage pointer.  In all cases the out param will be set to the number of
   476    * children.
   477    */
   478   virtual nsIContent * const * GetChildArray(uint32_t* aChildCount) const = 0;
   480   /**
   481    * Get the index of a child within this content
   482    * @param aPossibleChild the child to get the index of.
   483    * @return the index of the child, or -1 if not a child
   484    *
   485    * If the return value is not -1, then calling GetChildAt() with that value
   486    * will return aPossibleChild.
   487    */
   488   virtual int32_t IndexOf(const nsINode* aPossibleChild) const = 0;
   490   /**
   491    * Return the "owner document" of this node.  Note that this is not the same
   492    * as the DOM ownerDocument -- that's null for Document nodes, whereas for a
   493    * nsIDocument GetOwnerDocument returns the document itself.  For nsIContent
   494    * implementations the two are the same.
   495    */
   496   nsIDocument *OwnerDoc() const
   497   {
   498     return mNodeInfo->GetDocument();
   499   }
   501   /**
   502    * Return the "owner document" of this node as an nsINode*.  Implemented
   503    * in nsIDocument.h.
   504    */
   505   nsINode *OwnerDocAsNode() const;
   507   /**
   508    * Returns true if the content has an ancestor that is a document.
   509    *
   510    * @return whether this content is in a document tree
   511    */
   512   bool IsInDoc() const
   513   {
   514     return GetBoolFlag(IsInDocument);
   515   }
   517   /**
   518    * Get the document that this content is currently in, if any. This will be
   519    * null if the content has no ancestor that is a document.
   520    *
   521    * @return the current document
   522    */
   523   nsIDocument *GetCurrentDoc() const
   524   {
   525     return IsInDoc() ? OwnerDoc() : nullptr;
   526   }
   528   /**
   529    * The values returned by this function are the ones defined for
   530    * nsIDOMNode.nodeType
   531    */
   532   uint16_t NodeType() const
   533   {
   534     return mNodeInfo->NodeType();
   535   }
   536   const nsString& NodeName() const
   537   {
   538     return mNodeInfo->NodeName();
   539   }
   540   const nsString& LocalName() const
   541   {
   542     return mNodeInfo->LocalName();
   543   }
   545   /**
   546    * Get the tag for this element. This will always return a non-null atom
   547    * pointer (as implied by the naming of the method).  For elements this is
   548    * the non-namespaced tag, and for other nodes it's something like "#text",
   549    * "#comment", "#document", etc.
   550    */
   551   nsIAtom* Tag() const
   552   {
   553     return mNodeInfo->NameAtom();
   554   }
   556   /**
   557    * Insert a content node at a particular index.  This method handles calling
   558    * BindToTree on the child appropriately.
   559    *
   560    * @param aKid the content to insert
   561    * @param aIndex the index it is being inserted at (the index it will have
   562    *        after it is inserted)
   563    * @param aNotify whether to notify the document (current document for
   564    *        nsIContent, and |this| for nsIDocument) that the insert has
   565    *        occurred
   566    *
   567    * @throws NS_ERROR_DOM_HIERARCHY_REQUEST_ERR if one attempts to have more
   568    * than one element node as a child of a document.  Doing this will also
   569    * assert -- you shouldn't be doing it!  Check with
   570    * nsIDocument::GetRootElement() first if you're not sure.  Apart from this
   571    * one constraint, this doesn't do any checking on whether aKid is a valid
   572    * child of |this|.
   573    *
   574    * @throws NS_ERROR_OUT_OF_MEMORY in some cases (from BindToTree).
   575    */
   576   virtual nsresult InsertChildAt(nsIContent* aKid, uint32_t aIndex,
   577                                  bool aNotify) = 0;
   579   /**
   580    * Append a content node to the end of the child list.  This method handles
   581    * calling BindToTree on the child appropriately.
   582    *
   583    * @param aKid the content to append
   584    * @param aNotify whether to notify the document (current document for
   585    *        nsIContent, and |this| for nsIDocument) that the append has
   586    *        occurred
   587    *
   588    * @throws NS_ERROR_DOM_HIERARCHY_REQUEST_ERR if one attempts to have more
   589    * than one element node as a child of a document.  Doing this will also
   590    * assert -- you shouldn't be doing it!  Check with
   591    * nsIDocument::GetRootElement() first if you're not sure.  Apart from this
   592    * one constraint, this doesn't do any checking on whether aKid is a valid
   593    * child of |this|.
   594    *
   595    * @throws NS_ERROR_OUT_OF_MEMORY in some cases (from BindToTree).
   596    */
   597   nsresult AppendChildTo(nsIContent* aKid, bool aNotify)
   598   {
   599     return InsertChildAt(aKid, GetChildCount(), aNotify);
   600   }
   602   /**
   603    * Remove a child from this node.  This method handles calling UnbindFromTree
   604    * on the child appropriately.
   605    *
   606    * @param aIndex the index of the child to remove
   607    * @param aNotify whether to notify the document (current document for
   608    *        nsIContent, and |this| for nsIDocument) that the remove has
   609    *        occurred
   610    *
   611    * Note: If there is no child at aIndex, this method will simply do nothing.
   612    */
   613   virtual void RemoveChildAt(uint32_t aIndex, bool aNotify) = 0;
   615   /**
   616    * Get a property associated with this node.
   617    *
   618    * @param aPropertyName  name of property to get.
   619    * @param aStatus        out parameter for storing resulting status.
   620    *                       Set to NS_PROPTABLE_PROP_NOT_THERE if the property
   621    *                       is not set.
   622    * @return               the property. Null if the property is not set
   623    *                       (though a null return value does not imply the
   624    *                       property was not set, i.e. it can be set to null).
   625    */
   626   void* GetProperty(nsIAtom *aPropertyName,
   627                     nsresult *aStatus = nullptr) const
   628   {
   629     return GetProperty(0, aPropertyName, aStatus);
   630   }
   632   /**
   633    * Get a property associated with this node.
   634    *
   635    * @param aCategory      category of property to get.
   636    * @param aPropertyName  name of property to get.
   637    * @param aStatus        out parameter for storing resulting status.
   638    *                       Set to NS_PROPTABLE_PROP_NOT_THERE if the property
   639    *                       is not set.
   640    * @return               the property. Null if the property is not set
   641    *                       (though a null return value does not imply the
   642    *                       property was not set, i.e. it can be set to null).
   643    */
   644   virtual void* GetProperty(uint16_t aCategory,
   645                             nsIAtom *aPropertyName,
   646                             nsresult *aStatus = nullptr) const;
   648   /**
   649    * Set a property to be associated with this node. This will overwrite an
   650    * existing value if one exists. The existing value is destroyed using the
   651    * destructor function given when that value was set.
   652    *
   653    * @param aPropertyName  name of property to set.
   654    * @param aValue         new value of property.
   655    * @param aDtor          destructor function to be used when this property
   656    *                       is destroyed.
   657    * @param aTransfer      if true the property will not be deleted when the
   658    *                       ownerDocument of the node changes, if false it
   659    *                       will be deleted.
   660    *
   661    * @return NS_PROPTABLE_PROP_OVERWRITTEN (success value) if the property
   662    *                                       was already set
   663    * @throws NS_ERROR_OUT_OF_MEMORY if that occurs
   664    */
   665   nsresult SetProperty(nsIAtom *aPropertyName,
   666                        void *aValue,
   667                        NSPropertyDtorFunc aDtor = nullptr,
   668                        bool aTransfer = false)
   669   {
   670     return SetProperty(0, aPropertyName, aValue, aDtor, aTransfer);
   671   }
   673   /**
   674    * Set a property to be associated with this node. This will overwrite an
   675    * existing value if one exists. The existing value is destroyed using the
   676    * destructor function given when that value was set.
   677    *
   678    * @param aCategory       category of property to set.
   679    * @param aPropertyName   name of property to set.
   680    * @param aValue          new value of property.
   681    * @param aDtor           destructor function to be used when this property
   682    *                        is destroyed.
   683    * @param aTransfer       if true the property will not be deleted when the
   684    *                        ownerDocument of the node changes, if false it
   685    *                        will be deleted.
   686    * @param aOldValue [out] previous value of property.
   687    *
   688    * @return NS_PROPTABLE_PROP_OVERWRITTEN (success value) if the property
   689    *                                       was already set
   690    * @throws NS_ERROR_OUT_OF_MEMORY if that occurs
   691    */
   692   virtual nsresult SetProperty(uint16_t aCategory,
   693                                nsIAtom *aPropertyName,
   694                                void *aValue,
   695                                NSPropertyDtorFunc aDtor = nullptr,
   696                                bool aTransfer = false,
   697                                void **aOldValue = nullptr);
   699   /**
   700    * A generic destructor for property values allocated with new.
   701    */
   702   template<class T>
   703   static void DeleteProperty(void *, nsIAtom *, void *aPropertyValue, void *)
   704   {
   705     delete static_cast<T *>(aPropertyValue);
   706   }
   708   /**
   709    * Destroys a property associated with this node. The value is destroyed
   710    * using the destruction function given when that value was set.
   711    *
   712    * @param aPropertyName  name of property to destroy.
   713    */
   714   void DeleteProperty(nsIAtom *aPropertyName)
   715   {
   716     DeleteProperty(0, aPropertyName);
   717   }
   719   /**
   720    * Destroys a property associated with this node. The value is destroyed
   721    * using the destruction function given when that value was set.
   722    *
   723    * @param aCategory      category of property to destroy.
   724    * @param aPropertyName  name of property to destroy.
   725    */
   726   virtual void DeleteProperty(uint16_t aCategory, nsIAtom *aPropertyName);
   728   /**
   729    * Unset a property associated with this node. The value will not be
   730    * destroyed but rather returned. It is the caller's responsibility to
   731    * destroy the value after that point.
   732    *
   733    * @param aPropertyName  name of property to unset.
   734    * @param aStatus        out parameter for storing resulting status.
   735    *                       Set to NS_PROPTABLE_PROP_NOT_THERE if the property
   736    *                       is not set.
   737    * @return               the property. Null if the property is not set
   738    *                       (though a null return value does not imply the
   739    *                       property was not set, i.e. it can be set to null).
   740    */
   741   void* UnsetProperty(nsIAtom  *aPropertyName,
   742                       nsresult *aStatus = nullptr)
   743   {
   744     return UnsetProperty(0, aPropertyName, aStatus);
   745   }
   747   /**
   748    * Unset a property associated with this node. The value will not be
   749    * destroyed but rather returned. It is the caller's responsibility to
   750    * destroy the value after that point.
   751    *
   752    * @param aCategory      category of property to unset.
   753    * @param aPropertyName  name of property to unset.
   754    * @param aStatus        out parameter for storing resulting status.
   755    *                       Set to NS_PROPTABLE_PROP_NOT_THERE if the property
   756    *                       is not set.
   757    * @return               the property. Null if the property is not set
   758    *                       (though a null return value does not imply the
   759    *                       property was not set, i.e. it can be set to null).
   760    */
   761   virtual void* UnsetProperty(uint16_t aCategory,
   762                               nsIAtom *aPropertyName,
   763                               nsresult *aStatus = nullptr);
   765   bool HasProperties() const
   766   {
   767     return HasFlag(NODE_HAS_PROPERTIES);
   768   }
   770   /**
   771    * Return the principal of this node.  This is guaranteed to never be a null
   772    * pointer.
   773    */
   774   nsIPrincipal* NodePrincipal() const {
   775     return mNodeInfo->NodeInfoManager()->DocumentPrincipal();
   776   }
   778   /**
   779    * Get the parent nsIContent for this node.
   780    * @return the parent, or null if no parent or the parent is not an nsIContent
   781    */
   782   nsIContent* GetParent() const {
   783     return MOZ_LIKELY(GetBoolFlag(ParentIsContent)) ?
   784       reinterpret_cast<nsIContent*>(mParent) : nullptr;
   785   }
   787   /**
   788    * Get the parent nsINode for this node. This can be either an nsIContent,
   789    * an nsIDocument or an nsIAttribute.
   790    * @return the parent node
   791    */
   792   nsINode* GetParentNode() const
   793   {
   794     return mParent;
   795   }
   797   /**
   798    * Get the parent nsINode for this node if it is an Element.
   799    * @return the parent node
   800    */
   801   mozilla::dom::Element* GetParentElement() const
   802   {
   803     return mParent && mParent->IsElement() ? mParent->AsElement() : nullptr;
   804   }
   806   /**
   807    * Get the root of the subtree this node belongs to.  This never returns
   808    * null.  It may return 'this' (e.g. for document nodes, and nodes that
   809    * are the roots of disconnected subtrees).
   810    */
   811   nsINode* SubtreeRoot() const
   812   {
   813     // There are three cases of interest here.  nsINodes that are really:
   814     // 1. nsIDocument nodes - Are always in the document.
   815     // 2. nsIContent nodes - Are either in the document, or mSubtreeRoot
   816     //    is updated in BindToTree/UnbindFromTree.
   817     // 3. nsIAttribute nodes - Are never in the document, and mSubtreeRoot
   818     //    is always 'this' (as set in nsINode's ctor).
   819     nsINode* node = IsInDoc() ? OwnerDocAsNode() : mSubtreeRoot;
   820     NS_ASSERTION(node, "Should always have a node here!");
   821 #ifdef DEBUG
   822     {
   823       const nsINode* slowNode = this;
   824       const nsINode* iter = slowNode;
   825       while ((iter = iter->GetParentNode())) {
   826         slowNode = iter;
   827       }
   829       NS_ASSERTION(slowNode == node, "These should always be in sync!");
   830     }
   831 #endif
   832     return node;
   833   }
   835   /**
   836    * See nsIDOMEventTarget
   837    */
   838   NS_DECL_NSIDOMEVENTTARGET
   840   virtual mozilla::EventListenerManager*
   841     GetExistingListenerManager() const MOZ_OVERRIDE;
   842   virtual mozilla::EventListenerManager*
   843     GetOrCreateListenerManager() MOZ_OVERRIDE;
   845   using mozilla::dom::EventTarget::RemoveEventListener;
   846   using nsIDOMEventTarget::AddEventListener;
   847   virtual void AddEventListener(const nsAString& aType,
   848                                 mozilla::dom::EventListener* aListener,
   849                                 bool aUseCapture,
   850                                 const mozilla::dom::Nullable<bool>& aWantsUntrusted,
   851                                 mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
   852   using nsIDOMEventTarget::AddSystemEventListener;
   853   virtual nsIDOMWindow* GetOwnerGlobal() MOZ_OVERRIDE;
   855   /**
   856    * Adds a mutation observer to be notified when this node, or any of its
   857    * descendants, are modified. The node will hold a weak reference to the
   858    * observer, which means that it is the responsibility of the observer to
   859    * remove itself in case it dies before the node.  If an observer is added
   860    * while observers are being notified, it may also be notified.  In general,
   861    * adding observers while inside a notification is not a good idea.  An
   862    * observer that is already observing the node must not be added without
   863    * being removed first.
   864    */
   865   void AddMutationObserver(nsIMutationObserver* aMutationObserver)
   866   {
   867     nsSlots* s = Slots();
   868     NS_ASSERTION(s->mMutationObservers.IndexOf(aMutationObserver) ==
   869                  nsTArray<int>::NoIndex,
   870                  "Observer already in the list");
   871     s->mMutationObservers.AppendElement(aMutationObserver);
   872   }
   874   /**
   875    * Same as above, but only adds the observer if its not observing
   876    * the node already.
   877    */
   878   void AddMutationObserverUnlessExists(nsIMutationObserver* aMutationObserver)
   879   {
   880     nsSlots* s = Slots();
   881     s->mMutationObservers.AppendElementUnlessExists(aMutationObserver);
   882   }
   884   /**
   885    * Removes a mutation observer.
   886    */
   887   void RemoveMutationObserver(nsIMutationObserver* aMutationObserver)
   888   {
   889     nsSlots* s = GetExistingSlots();
   890     if (s) {
   891       s->mMutationObservers.RemoveElement(aMutationObserver);
   892     }
   893   }
   895   /**
   896    * Clones this node. This needs to be overriden by all node classes. aNodeInfo
   897    * should be identical to this node's nodeInfo, except for the document which
   898    * may be different. When cloning an element, all attributes of the element
   899    * will be cloned. The children of the node will not be cloned.
   900    *
   901    * @param aNodeInfo the nodeinfo to use for the clone
   902    * @param aResult the clone
   903    */
   904   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const = 0;
   906   // This class can be extended by subclasses that wish to store more
   907   // information in the slots.
   908   class nsSlots
   909   {
   910   public:
   911     nsSlots()
   912       : mChildNodes(nullptr),
   913         mWeakReference(nullptr)
   914     {
   915     }
   917     // If needed we could remove the vtable pointer this dtor causes by
   918     // putting a DestroySlots function on nsINode
   919     virtual ~nsSlots();
   921     void Traverse(nsCycleCollectionTraversalCallback &cb);
   922     void Unlink();
   924     /**
   925      * A list of mutation observers
   926      */
   927     nsTObserverArray<nsIMutationObserver*> mMutationObservers;
   929     /**
   930      * An object implementing nsIDOMNodeList for this content (childNodes)
   931      * @see nsIDOMNodeList
   932      * @see nsGenericHTMLElement::GetChildNodes
   933      *
   934      * MSVC 7 doesn't like this as an nsRefPtr
   935      */
   936     nsChildContentList* mChildNodes;
   938     /**
   939      * Weak reference to this node
   940      */
   941     nsNodeWeakReference* mWeakReference;
   942   };
   944   /**
   945    * Functions for managing flags and slots
   946    */
   947 #ifdef DEBUG
   948   nsSlots* DebugGetSlots()
   949   {
   950     return Slots();
   951   }
   952 #endif
   954   void SetFlags(uint32_t aFlagsToSet)
   955   {
   956     NS_ASSERTION(!(aFlagsToSet & (NODE_IS_ANONYMOUS_ROOT |
   957                                   NODE_IS_NATIVE_ANONYMOUS_ROOT |
   958                                   NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE |
   959                                   NODE_ATTACH_BINDING_ON_POSTCREATE |
   960                                   NODE_DESCENDANTS_NEED_FRAMES |
   961                                   NODE_NEEDS_FRAME |
   962                                   NODE_CHROME_ONLY_ACCESS)) ||
   963                  IsNodeOfType(eCONTENT),
   964                  "Flag only permitted on nsIContent nodes");
   965     nsWrapperCache::SetFlags(aFlagsToSet);
   966   }
   968   void UnsetFlags(uint32_t aFlagsToUnset)
   969   {
   970     NS_ASSERTION(!(aFlagsToUnset &
   971                    (NODE_IS_ANONYMOUS_ROOT |
   972                     NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE |
   973                     NODE_IS_NATIVE_ANONYMOUS_ROOT)),
   974                  "Trying to unset write-only flags");
   975     nsWrapperCache::UnsetFlags(aFlagsToUnset);
   976   }
   978   void SetEditableFlag(bool aEditable)
   979   {
   980     if (aEditable) {
   981       SetFlags(NODE_IS_EDITABLE);
   982     }
   983     else {
   984       UnsetFlags(NODE_IS_EDITABLE);
   985     }
   986   }
   988   bool IsEditable() const
   989   {
   990 #ifdef MOZILLA_INTERNAL_API
   991     return IsEditableInternal();
   992 #else
   993     return IsEditableExternal();
   994 #endif
   995   }
   997   /**
   998    * Returns true if |this| or any of its ancestors is native anonymous.
   999    */
  1000   bool IsInNativeAnonymousSubtree() const
  1002 #ifdef DEBUG
  1003     if (HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE)) {
  1004       return true;
  1006     CheckNotNativeAnonymous();
  1007     return false;
  1008 #else
  1009     return HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
  1010 #endif
  1013   bool IsInAnonymousSubtree() const;
  1015   // Note: This asserts |IsInAnonymousSubtree()|.
  1016   bool IsAnonymousContentInSVGUseSubtree() const;
  1018   // True for native anonymous content and for XBL content if the binging
  1019   // has chromeOnlyContent="true".
  1020   bool ChromeOnlyAccess() const
  1022     return HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | NODE_CHROME_ONLY_ACCESS);
  1025   /**
  1026    * Returns true if |this| node is the common ancestor of the start/end
  1027    * nodes of a Range in a Selection or a descendant of such a common ancestor.
  1028    * This node is definitely not selected when |false| is returned, but it may
  1029    * or may not be selected when |true| is returned.
  1030    */
  1031   bool IsSelectionDescendant() const
  1033     return IsDescendantOfCommonAncestorForRangeInSelection() ||
  1034            IsCommonAncestorForRangeInSelection();
  1037   /**
  1038    * Get the root content of an editor. So, this node must be a descendant of
  1039    * an editor. Note that this should be only used for getting input or textarea
  1040    * editor's root content. This method doesn't support HTML editors.
  1041    */
  1042   nsIContent* GetTextEditorRootContent(nsIEditor** aEditor = nullptr);
  1044   /**
  1045    * Get the nearest selection root, ie. the node that will be selected if the
  1046    * user does "Select All" while the focus is in this node. Note that if this
  1047    * node is not in an editor, the result comes from the nsFrameSelection that
  1048    * is related to aPresShell, so the result might not be the ancestor of this
  1049    * node. Be aware that if this node and the computed selection limiter are
  1050    * not in same subtree, this returns the root content of the closeset subtree.
  1051    */
  1052   nsIContent* GetSelectionRootContent(nsIPresShell* aPresShell);
  1054   virtual nsINodeList* ChildNodes();
  1055   nsIContent* GetFirstChild() const { return mFirstChild; }
  1056   nsIContent* GetLastChild() const
  1058     uint32_t count;
  1059     nsIContent* const* children = GetChildArray(&count);
  1061     return count > 0 ? children[count - 1] : nullptr;
  1064   /**
  1065    * Implementation is in nsIDocument.h, because it needs to cast from
  1066    * nsIDocument* to nsINode*.
  1067    */
  1068   nsIDocument* GetOwnerDocument() const;
  1070   void Normalize();
  1072   /**
  1073    * Get the base URI for any relative URIs within this piece of
  1074    * content. Generally, this is the document's base URI, but certain
  1075    * content carries a local base for backward compatibility, and XML
  1076    * supports setting a per-node base URI.
  1078    * @return the base URI
  1079    */
  1080   virtual already_AddRefed<nsIURI> GetBaseURI(bool aTryUseXHRDocBaseURI = false) const = 0;
  1081   already_AddRefed<nsIURI> GetBaseURIObject() const;
  1083   /**
  1084    * Facility for explicitly setting a base URI on a node.
  1085    */
  1086   nsresult SetExplicitBaseURI(nsIURI* aURI);
  1087   /**
  1088    * The explicit base URI, if set, otherwise null
  1089    */
  1090 protected:
  1091   nsIURI* GetExplicitBaseURI() const {
  1092     if (HasExplicitBaseURI()) {
  1093       return static_cast<nsIURI*>(GetProperty(nsGkAtoms::baseURIProperty));
  1095     return nullptr;
  1098 public:
  1099   void GetTextContent(nsAString& aTextContent)
  1101     GetTextContentInternal(aTextContent);
  1103   void SetTextContent(const nsAString& aTextContent,
  1104                       mozilla::ErrorResult& aError)
  1106     SetTextContentInternal(aTextContent, aError);
  1109   mozilla::dom::Element* QuerySelector(const nsAString& aSelector,
  1110                                        mozilla::ErrorResult& aResult);
  1111   already_AddRefed<nsINodeList> QuerySelectorAll(const nsAString& aSelector,
  1112                                                  mozilla::ErrorResult& aResult);
  1114   nsresult QuerySelector(const nsAString& aSelector, nsIDOMElement **aReturn);
  1115   nsresult QuerySelectorAll(const nsAString& aSelector, nsIDOMNodeList **aReturn);
  1117 protected:
  1118   // nsIDocument overrides this with its own (faster) version.  This
  1119   // should really only be called for elements and document fragments.
  1120   mozilla::dom::Element* GetElementById(const nsAString& aId);
  1122 public:
  1123   /**
  1124    * Associate an object aData to aKey on this node. If aData is null any
  1125    * previously registered object and UserDataHandler associated to aKey on
  1126    * this node will be removed.
  1127    * Should only be used to implement the DOM Level 3 UserData API.
  1129    * @param aKey the key to associate the object to
  1130    * @param aData the object to associate to aKey on this node (may be null)
  1131    * @param aHandler the UserDataHandler to call when the node is
  1132    *                 cloned/deleted/imported/renamed (may be null)
  1133    * @param aResult [out] the previously registered object for aKey on this
  1134    *                      node, if any
  1135    * @return whether adding the object and UserDataHandler succeeded
  1136    */
  1137   nsresult SetUserData(const nsAString& aKey, nsIVariant* aData,
  1138                        nsIDOMUserDataHandler* aHandler, nsIVariant** aResult);
  1140   /**
  1141    * Get the UserData object registered for a Key on this node, if any.
  1142    * Should only be used to implement the DOM Level 3 UserData API.
  1144    * @param aKey the key to get UserData for
  1145    * @return aResult the previously registered object for aKey on this node, if
  1146    *                 any
  1147    */
  1148   nsIVariant* GetUserData(const nsAString& aKey);
  1150   nsresult GetUserData(const nsAString& aKey, nsIVariant** aResult)
  1152     NS_IF_ADDREF(*aResult = GetUserData(aKey));
  1154     return NS_OK;
  1157   void LookupPrefix(const nsAString& aNamespace, nsAString& aResult);
  1158   bool IsDefaultNamespace(const nsAString& aNamespaceURI)
  1160     nsAutoString defaultNamespace;
  1161     LookupNamespaceURI(EmptyString(), defaultNamespace);
  1162     return aNamespaceURI.Equals(defaultNamespace);
  1164   void LookupNamespaceURI(const nsAString& aNamespacePrefix,
  1165                           nsAString& aNamespaceURI);
  1167   nsresult IsEqualNode(nsIDOMNode* aOther, bool* aReturn);
  1169   nsIContent* GetNextSibling() const { return mNextSibling; }
  1170   nsIContent* GetPreviousSibling() const { return mPreviousSibling; }
  1172   /**
  1173    * Get the next node in the pre-order tree traversal of the DOM.  If
  1174    * aRoot is non-null, then it must be an ancestor of |this|
  1175    * (possibly equal to |this|) and only nodes that are descendants of
  1176    * aRoot, not including aRoot itself, will be returned.  Returns
  1177    * null if there are no more nodes to traverse.
  1178    */
  1179   nsIContent* GetNextNode(const nsINode* aRoot = nullptr) const
  1181     return GetNextNodeImpl(aRoot, false);
  1184   /**
  1185    * Get the next node in the pre-order tree traversal of the DOM but ignoring
  1186    * the children of this node.  If aRoot is non-null, then it must be an
  1187    * ancestor of |this| (possibly equal to |this|) and only nodes that are
  1188    * descendants of aRoot, not including aRoot itself, will be returned.
  1189    * Returns null if there are no more nodes to traverse.
  1190    */
  1191   nsIContent* GetNextNonChildNode(const nsINode* aRoot = nullptr) const
  1193     return GetNextNodeImpl(aRoot, true);
  1196   /**
  1197    * Returns true if 'this' is either document or element or
  1198    * document fragment and aOther is a descendant in the same
  1199    * anonymous tree.
  1200    */
  1201   bool Contains(const nsINode* aOther) const;
  1202   nsresult Contains(nsIDOMNode* aOther, bool* aReturn);
  1204   bool UnoptimizableCCNode() const;
  1206 private:
  1208   nsIContent* GetNextNodeImpl(const nsINode* aRoot,
  1209                               const bool aSkipChildren) const
  1211     // Can't use nsContentUtils::ContentIsDescendantOf here, since we
  1212     // can't include it here.
  1213 #ifdef DEBUG
  1214     if (aRoot) {
  1215       const nsINode* cur = this;
  1216       for (; cur; cur = cur->GetParentNode())
  1217         if (cur == aRoot) break;
  1218       NS_ASSERTION(cur, "aRoot not an ancestor of |this|?");
  1220 #endif
  1221     if (!aSkipChildren) {
  1222       nsIContent* kid = GetFirstChild();
  1223       if (kid) {
  1224         return kid;
  1227     if (this == aRoot) {
  1228       return nullptr;
  1230     const nsINode* cur = this;
  1231     while (1) {
  1232       nsIContent* next = cur->GetNextSibling();
  1233       if (next) {
  1234         return next;
  1236       nsINode* parent = cur->GetParentNode();
  1237       if (parent == aRoot) {
  1238         return nullptr;
  1240       cur = parent;
  1242     NS_NOTREACHED("How did we get here?");
  1245 public:
  1247   /**
  1248    * Get the previous nsIContent in the pre-order tree traversal of the DOM.  If
  1249    * aRoot is non-null, then it must be an ancestor of |this|
  1250    * (possibly equal to |this|) and only nsIContents that are descendants of
  1251    * aRoot, including aRoot itself, will be returned.  Returns
  1252    * null if there are no more nsIContents to traverse.
  1253    */
  1254   nsIContent* GetPreviousContent(const nsINode* aRoot = nullptr) const
  1256       // Can't use nsContentUtils::ContentIsDescendantOf here, since we
  1257       // can't include it here.
  1258 #ifdef DEBUG
  1259       if (aRoot) {
  1260         const nsINode* cur = this;
  1261         for (; cur; cur = cur->GetParentNode())
  1262           if (cur == aRoot) break;
  1263         NS_ASSERTION(cur, "aRoot not an ancestor of |this|?");
  1265 #endif
  1267     if (this == aRoot) {
  1268       return nullptr;
  1270     nsIContent* cur = this->GetParent();
  1271     nsIContent* iter = this->GetPreviousSibling();
  1272     while (iter) {
  1273       cur = iter;
  1274       iter = reinterpret_cast<nsINode*>(iter)->GetLastChild();
  1276     return cur;
  1279   /**
  1280    * Boolean flags
  1281    */
  1282 private:
  1283   enum BooleanFlag {
  1284     // Set if we're being used from -moz-element
  1285     NodeHasRenderingObservers,
  1286     // Set if our parent chain (including this node itself) terminates
  1287     // in a document
  1288     IsInDocument,
  1289     // Set if mParent is an nsIContent
  1290     ParentIsContent,
  1291     // Set if this node is an Element
  1292     NodeIsElement,
  1293     // Set if the element has a non-empty id attribute. This can in rare
  1294     // cases lie for nsXMLElement, such as when the node has been moved between
  1295     // documents with different id mappings.
  1296     ElementHasID,
  1297     // Set if the element might have inline style.
  1298     ElementMayHaveStyle,
  1299     // Set if the element has a name attribute set.
  1300     ElementHasName,
  1301     // Set if the element might have a contenteditable attribute set.
  1302     ElementMayHaveContentEditableAttr,
  1303     // Set if the node is the common ancestor of the start/end nodes of a Range
  1304     // that is in a Selection.
  1305     NodeIsCommonAncestorForRangeInSelection,
  1306     // Set if the node is a descendant of a node with the above bit set.
  1307     NodeIsDescendantOfCommonAncestorForRangeInSelection,
  1308     // Set if CanSkipInCC check has been done for this subtree root.
  1309     NodeIsCCMarkedRoot,
  1310     // Maybe set if this node is in black subtree.
  1311     NodeIsCCBlackTree,
  1312     // Maybe set if the node is a root of a subtree 
  1313     // which needs to be kept in the purple buffer.
  1314     NodeIsPurpleRoot,
  1315     // Set if the node has an explicit base URI stored
  1316     NodeHasExplicitBaseURI,
  1317     // Set if the element has some style states locked
  1318     ElementHasLockedStyleStates,
  1319     // Set if element has pointer locked
  1320     ElementHasPointerLock,
  1321     // Set if the node may have DOMMutationObserver attached to it.
  1322     NodeMayHaveDOMMutationObserver,
  1323     // Set if node is Content
  1324     NodeIsContent,
  1325     // Set if the node has animations or transitions
  1326     ElementHasAnimations,
  1327     // Set if node has a dir attribute with a valid value (ltr, rtl, or auto)
  1328     NodeHasValidDirAttribute,
  1329     // Set if node has a dir attribute with a fixed value (ltr or rtl, NOT auto)
  1330     NodeHasFixedDir,
  1331     // Set if the node has dir=auto and has a property pointing to the text
  1332     // node that determines its direction
  1333     NodeHasDirAutoSet,
  1334     // Set if the node is a text node descendant of a node with dir=auto
  1335     // and has a TextNodeDirectionalityMap property listing the elements whose
  1336     // direction it determines.
  1337     NodeHasTextNodeDirectionalityMap,
  1338     // Set if the node has dir=auto.
  1339     NodeHasDirAuto,
  1340     // Set if a node in the node's parent chain has dir=auto.
  1341     NodeAncestorHasDirAuto,
  1342     // Set if the element is in the scope of a scoped style sheet; this flag is
  1343     // only accurate for elements bound to a document
  1344     ElementIsInStyleScope,
  1345     // Set if the element is a scoped style sheet root
  1346     ElementIsScopedStyleRoot,
  1347     // Set if the node is handling a click.
  1348     NodeHandlingClick,
  1349     // Set if the node has had :hover selectors matched against it
  1350     NodeHasRelevantHoverRules,
  1351     // Set if the element has a parser insertion mode other than "in body",
  1352     // per the HTML5 "Parse state" section.
  1353     ElementHasWeirdParserInsertionMode,
  1354     // Guard value
  1355     BooleanFlagCount
  1356   };
  1358   void SetBoolFlag(BooleanFlag name, bool value) {
  1359     static_assert(BooleanFlagCount <= 8*sizeof(mBoolFlags),
  1360                   "Too many boolean flags");
  1361     mBoolFlags = (mBoolFlags & ~(1 << name)) | (value << name);
  1364   void SetBoolFlag(BooleanFlag name) {
  1365     static_assert(BooleanFlagCount <= 8*sizeof(mBoolFlags),
  1366                   "Too many boolean flags");
  1367     mBoolFlags |= (1 << name);
  1370   void ClearBoolFlag(BooleanFlag name) {
  1371     static_assert(BooleanFlagCount <= 8*sizeof(mBoolFlags),
  1372                   "Too many boolean flags");
  1373     mBoolFlags &= ~(1 << name);
  1376   bool GetBoolFlag(BooleanFlag name) const {
  1377     static_assert(BooleanFlagCount <= 8*sizeof(mBoolFlags),
  1378                   "Too many boolean flags");
  1379     return mBoolFlags & (1 << name);
  1382 public:
  1383   bool HasRenderingObservers() const
  1384     { return GetBoolFlag(NodeHasRenderingObservers); }
  1385   void SetHasRenderingObservers(bool aValue)
  1386     { SetBoolFlag(NodeHasRenderingObservers, aValue); }
  1387   bool IsContent() const { return GetBoolFlag(NodeIsContent); }
  1388   bool HasID() const { return GetBoolFlag(ElementHasID); }
  1389   bool MayHaveStyle() const { return GetBoolFlag(ElementMayHaveStyle); }
  1390   bool HasName() const { return GetBoolFlag(ElementHasName); }
  1391   bool MayHaveContentEditableAttr() const
  1392     { return GetBoolFlag(ElementMayHaveContentEditableAttr); }
  1393   bool IsCommonAncestorForRangeInSelection() const
  1394     { return GetBoolFlag(NodeIsCommonAncestorForRangeInSelection); }
  1395   void SetCommonAncestorForRangeInSelection()
  1396     { SetBoolFlag(NodeIsCommonAncestorForRangeInSelection); }
  1397   void ClearCommonAncestorForRangeInSelection()
  1398     { ClearBoolFlag(NodeIsCommonAncestorForRangeInSelection); }
  1399   bool IsDescendantOfCommonAncestorForRangeInSelection() const
  1400     { return GetBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection); }
  1401   void SetDescendantOfCommonAncestorForRangeInSelection()
  1402     { SetBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection); }
  1403   void ClearDescendantOfCommonAncestorForRangeInSelection()
  1404     { ClearBoolFlag(NodeIsDescendantOfCommonAncestorForRangeInSelection); }
  1406   void SetCCMarkedRoot(bool aValue)
  1407     { SetBoolFlag(NodeIsCCMarkedRoot, aValue); }
  1408   bool CCMarkedRoot() const { return GetBoolFlag(NodeIsCCMarkedRoot); }
  1409   void SetInCCBlackTree(bool aValue)
  1410     { SetBoolFlag(NodeIsCCBlackTree, aValue); }
  1411   bool InCCBlackTree() const { return GetBoolFlag(NodeIsCCBlackTree); }
  1412   void SetIsPurpleRoot(bool aValue)
  1413     { SetBoolFlag(NodeIsPurpleRoot, aValue); }
  1414   bool IsPurpleRoot() const { return GetBoolFlag(NodeIsPurpleRoot); }
  1415   bool MayHaveDOMMutationObserver()
  1416     { return GetBoolFlag(NodeMayHaveDOMMutationObserver); }
  1417   void SetMayHaveDOMMutationObserver()
  1418     { SetBoolFlag(NodeMayHaveDOMMutationObserver, true); }
  1419   bool HasListenerManager() { return HasFlag(NODE_HAS_LISTENERMANAGER); }
  1420   bool HasPointerLock() const { return GetBoolFlag(ElementHasPointerLock); }
  1421   void SetPointerLock() { SetBoolFlag(ElementHasPointerLock); }
  1422   void ClearPointerLock() { ClearBoolFlag(ElementHasPointerLock); }
  1423   bool MayHaveAnimations() { return GetBoolFlag(ElementHasAnimations); }
  1424   void SetMayHaveAnimations() { SetBoolFlag(ElementHasAnimations); }
  1425   void SetHasValidDir() { SetBoolFlag(NodeHasValidDirAttribute); }
  1426   void ClearHasValidDir() { ClearBoolFlag(NodeHasValidDirAttribute); }
  1427   bool HasValidDir() const { return GetBoolFlag(NodeHasValidDirAttribute); }
  1428   void SetHasFixedDir() {
  1429     MOZ_ASSERT(NodeType() != nsIDOMNode::TEXT_NODE,
  1430                "SetHasFixedDir on text node");
  1431     SetBoolFlag(NodeHasFixedDir);
  1433   void ClearHasFixedDir() {
  1434     MOZ_ASSERT(NodeType() != nsIDOMNode::TEXT_NODE,
  1435                "ClearHasFixedDir on text node");
  1436     ClearBoolFlag(NodeHasFixedDir);
  1438   bool HasFixedDir() const { return GetBoolFlag(NodeHasFixedDir); }
  1439   void SetHasDirAutoSet() {
  1440     MOZ_ASSERT(NodeType() != nsIDOMNode::TEXT_NODE,
  1441                "SetHasDirAutoSet on text node");
  1442     SetBoolFlag(NodeHasDirAutoSet);
  1444   void ClearHasDirAutoSet() {
  1445     MOZ_ASSERT(NodeType() != nsIDOMNode::TEXT_NODE,
  1446                "ClearHasDirAutoSet on text node");
  1447     ClearBoolFlag(NodeHasDirAutoSet);
  1449   bool HasDirAutoSet() const
  1450     { return GetBoolFlag(NodeHasDirAutoSet); }
  1451   void SetHasTextNodeDirectionalityMap() {
  1452     MOZ_ASSERT(NodeType() == nsIDOMNode::TEXT_NODE,
  1453                "SetHasTextNodeDirectionalityMap on non-text node");
  1454     SetBoolFlag(NodeHasTextNodeDirectionalityMap);
  1456   void ClearHasTextNodeDirectionalityMap() {
  1457     MOZ_ASSERT(NodeType() == nsIDOMNode::TEXT_NODE,
  1458                "ClearHasTextNodeDirectionalityMap on non-text node");
  1459     ClearBoolFlag(NodeHasTextNodeDirectionalityMap);
  1461   bool HasTextNodeDirectionalityMap() const
  1462     { return GetBoolFlag(NodeHasTextNodeDirectionalityMap); }
  1464   void SetHasDirAuto() { SetBoolFlag(NodeHasDirAuto); }
  1465   void ClearHasDirAuto() { ClearBoolFlag(NodeHasDirAuto); }
  1466   bool HasDirAuto() const { return GetBoolFlag(NodeHasDirAuto); }
  1468   void SetAncestorHasDirAuto() { SetBoolFlag(NodeAncestorHasDirAuto); }
  1469   void ClearAncestorHasDirAuto() { ClearBoolFlag(NodeAncestorHasDirAuto); }
  1470   bool AncestorHasDirAuto() const { return GetBoolFlag(NodeAncestorHasDirAuto); }
  1472   bool NodeOrAncestorHasDirAuto() const
  1473     { return HasDirAuto() || AncestorHasDirAuto(); }
  1475   void SetIsElementInStyleScope(bool aValue) {
  1476     MOZ_ASSERT(IsElement(), "SetIsInStyleScope on a non-Element node");
  1477     SetBoolFlag(ElementIsInStyleScope, aValue);
  1479   void SetIsElementInStyleScope() {
  1480     MOZ_ASSERT(IsElement(), "SetIsInStyleScope on a non-Element node");
  1481     SetBoolFlag(ElementIsInStyleScope);
  1483   void ClearIsElementInStyleScope() {
  1484     MOZ_ASSERT(IsElement(), "ClearIsInStyleScope on a non-Element node");
  1485     ClearBoolFlag(ElementIsInStyleScope);
  1487   bool IsElementInStyleScope() const { return GetBoolFlag(ElementIsInStyleScope); }
  1489   void SetIsScopedStyleRoot() { SetBoolFlag(ElementIsScopedStyleRoot); }
  1490   void ClearIsScopedStyleRoot() { ClearBoolFlag(ElementIsScopedStyleRoot); }
  1491   bool IsScopedStyleRoot() { return GetBoolFlag(ElementIsScopedStyleRoot); }
  1492   bool HasRelevantHoverRules() const { return GetBoolFlag(NodeHasRelevantHoverRules); }
  1493   void SetHasRelevantHoverRules() { SetBoolFlag(NodeHasRelevantHoverRules); }
  1494 protected:
  1495   void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
  1496   void SetInDocument() { SetBoolFlag(IsInDocument); }
  1497   void SetNodeIsContent() { SetBoolFlag(NodeIsContent); }
  1498   void ClearInDocument() { ClearBoolFlag(IsInDocument); }
  1499   void SetIsElement() { SetBoolFlag(NodeIsElement); }
  1500   void SetHasID() { SetBoolFlag(ElementHasID); }
  1501   void ClearHasID() { ClearBoolFlag(ElementHasID); }
  1502   void SetMayHaveStyle() { SetBoolFlag(ElementMayHaveStyle); }
  1503   void SetHasName() { SetBoolFlag(ElementHasName); }
  1504   void ClearHasName() { ClearBoolFlag(ElementHasName); }
  1505   void SetMayHaveContentEditableAttr()
  1506     { SetBoolFlag(ElementMayHaveContentEditableAttr); }
  1507   bool HasExplicitBaseURI() const { return GetBoolFlag(NodeHasExplicitBaseURI); }
  1508   void SetHasExplicitBaseURI() { SetBoolFlag(NodeHasExplicitBaseURI); }
  1509   void SetHasLockedStyleStates() { SetBoolFlag(ElementHasLockedStyleStates); }
  1510   void ClearHasLockedStyleStates() { ClearBoolFlag(ElementHasLockedStyleStates); }
  1511   bool HasLockedStyleStates() const
  1512     { return GetBoolFlag(ElementHasLockedStyleStates); }
  1513   void SetHasWeirdParserInsertionMode() { SetBoolFlag(ElementHasWeirdParserInsertionMode); }
  1514   bool HasWeirdParserInsertionMode() const
  1515   { return GetBoolFlag(ElementHasWeirdParserInsertionMode); }
  1516   bool HandlingClick() const { return GetBoolFlag(NodeHandlingClick); }
  1517   void SetHandlingClick() { SetBoolFlag(NodeHandlingClick); }
  1518   void ClearHandlingClick() { ClearBoolFlag(NodeHandlingClick); }
  1520   void SetSubtreeRootPointer(nsINode* aSubtreeRoot)
  1522     NS_ASSERTION(aSubtreeRoot, "aSubtreeRoot can never be null!");
  1523     NS_ASSERTION(!(IsNodeOfType(eCONTENT) && IsInDoc()), "Shouldn't be here!");
  1524     mSubtreeRoot = aSubtreeRoot;
  1527   void ClearSubtreeRootPointer()
  1529     mSubtreeRoot = nullptr;
  1532 public:
  1533   // Makes nsINode object to keep aObject alive.
  1534   void BindObject(nsISupports* aObject);
  1535   // After calling UnbindObject nsINode object doesn't keep
  1536   // aObject alive anymore.
  1537   void UnbindObject(nsISupports* aObject);
  1539   void GetBoundMutationObservers(nsTArray<nsRefPtr<nsDOMMutationObserver> >& aResult);
  1541   /**
  1542    * Returns the length of this node, as specified at
  1543    * <http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node-length>
  1544    */
  1545   uint32_t Length() const;
  1547   void GetNodeName(mozilla::dom::DOMString& aNodeName)
  1549     const nsString& nodeName = NodeName();
  1550     aNodeName.SetStringBuffer(nsStringBuffer::FromString(nodeName),
  1551                               nodeName.Length());
  1553   void GetBaseURI(nsAString& aBaseURI) const;
  1554   // Return the base URI for the document.
  1555   // The returned value may differ if the document is loaded via XHR, and
  1556   // when accessed from chrome privileged script and
  1557   // from content privileged script for compatibility.
  1558   void GetBaseURIFromJS(nsAString& aBaseURI) const;
  1559   bool HasChildNodes() const
  1561     return HasChildren();
  1563   uint16_t CompareDocumentPosition(nsINode& aOther) const;
  1564   void GetNodeValue(nsAString& aNodeValue)
  1566     GetNodeValueInternal(aNodeValue);
  1568   void SetNodeValue(const nsAString& aNodeValue,
  1569                     mozilla::ErrorResult& aError)
  1571     SetNodeValueInternal(aNodeValue, aError);
  1573   virtual void GetNodeValueInternal(nsAString& aNodeValue);
  1574   virtual void SetNodeValueInternal(const nsAString& aNodeValue,
  1575                                     mozilla::ErrorResult& aError)
  1577     // The DOM spec says that when nodeValue is defined to be null "setting it
  1578     // has no effect", so we don't throw an exception.
  1580   nsINode* InsertBefore(nsINode& aNode, nsINode* aChild,
  1581                         mozilla::ErrorResult& aError)
  1583     return ReplaceOrInsertBefore(false, &aNode, aChild, aError);
  1585   nsINode* AppendChild(nsINode& aNode, mozilla::ErrorResult& aError)
  1587     return InsertBefore(aNode, nullptr, aError);
  1589   nsINode* ReplaceChild(nsINode& aNode, nsINode& aChild,
  1590                         mozilla::ErrorResult& aError)
  1592     return ReplaceOrInsertBefore(true, &aNode, &aChild, aError);
  1594   nsINode* RemoveChild(nsINode& aChild, mozilla::ErrorResult& aError);
  1595   already_AddRefed<nsINode> CloneNode(bool aDeep, mozilla::ErrorResult& aError);
  1596   bool IsEqualNode(nsINode* aNode);
  1597   void GetNamespaceURI(nsAString& aNamespaceURI) const
  1599     mNodeInfo->GetNamespaceURI(aNamespaceURI);
  1601 #ifdef MOZILLA_INTERNAL_API
  1602   void GetPrefix(nsAString& aPrefix)
  1604     mNodeInfo->GetPrefix(aPrefix);
  1606 #endif
  1607   void GetLocalName(mozilla::dom::DOMString& aLocalName)
  1609     const nsString& localName = LocalName();
  1610     if (localName.IsVoid()) {
  1611       aLocalName.SetNull();
  1612     } else {
  1613       aLocalName.SetStringBuffer(nsStringBuffer::FromString(localName),
  1614                                  localName.Length());
  1617   // HasAttributes is defined inline in Element.h.
  1618   bool HasAttributes() const;
  1619   nsDOMAttributeMap* GetAttributes();
  1620   void SetUserData(JSContext* aCx, const nsAString& aKey,
  1621                    JS::Handle<JS::Value> aData,
  1622                    nsIDOMUserDataHandler* aHandler,
  1623                    JS::MutableHandle<JS::Value> aRetval,
  1624                    mozilla::ErrorResult& aError);
  1625   void GetUserData(JSContext* aCx, const nsAString& aKey,
  1626                    JS::MutableHandle<JS::Value> aRetval,
  1627                    mozilla::ErrorResult& aError);
  1629   // Helper method to remove this node from its parent. This is not exposed
  1630   // through WebIDL.
  1631   // Only call this if the node has a parent node.
  1632   nsresult RemoveFromParent()
  1634     nsINode* parent = GetParentNode();
  1635     mozilla::ErrorResult rv;
  1636     parent->RemoveChild(*this, rv);
  1637     return rv.ErrorCode();
  1640   // ChildNode methods
  1641   mozilla::dom::Element* GetPreviousElementSibling() const;
  1642   mozilla::dom::Element* GetNextElementSibling() const;
  1643   /**
  1644    * Remove this node from its parent, if any.
  1645    */
  1646   void Remove();
  1648   // ParentNode methods
  1649   mozilla::dom::Element* GetFirstElementChild() const;
  1650   mozilla::dom::Element* GetLastElementChild() const;
  1652   void GetBoxQuads(const BoxQuadOptions& aOptions,
  1653                    nsTArray<nsRefPtr<DOMQuad> >& aResult,
  1654                    mozilla::ErrorResult& aRv);
  1656   already_AddRefed<DOMQuad> ConvertQuadFromNode(DOMQuad& aQuad,
  1657                                                 const TextOrElementOrDocument& aFrom,
  1658                                                 const ConvertCoordinateOptions& aOptions,
  1659                                                 ErrorResult& aRv);
  1660   already_AddRefed<DOMQuad> ConvertRectFromNode(DOMRectReadOnly& aRect,
  1661                                                 const TextOrElementOrDocument& aFrom,
  1662                                                 const ConvertCoordinateOptions& aOptions,
  1663                                                 ErrorResult& aRv);
  1664   already_AddRefed<DOMPoint> ConvertPointFromNode(const DOMPointInit& aPoint,
  1665                                                   const TextOrElementOrDocument& aFrom,
  1666                                                   const ConvertCoordinateOptions& aOptions,
  1667                                                   ErrorResult& aRv);
  1669 protected:
  1671   // Override this function to create a custom slots class.
  1672   // Must not return null.
  1673   virtual nsINode::nsSlots* CreateSlots();
  1675   bool HasSlots() const
  1677     return mSlots != nullptr;
  1680   nsSlots* GetExistingSlots() const
  1682     return mSlots;
  1685   nsSlots* Slots()
  1687     if (!HasSlots()) {
  1688       mSlots = CreateSlots();
  1689       MOZ_ASSERT(mSlots);
  1691     return GetExistingSlots();
  1694   nsTObserverArray<nsIMutationObserver*> *GetMutationObservers()
  1696     return HasSlots() ? &GetExistingSlots()->mMutationObservers : nullptr;
  1699   bool IsEditableInternal() const;
  1700   virtual bool IsEditableExternal() const
  1702     return IsEditableInternal();
  1705   virtual void GetTextContentInternal(nsAString& aTextContent);
  1706   virtual void SetTextContentInternal(const nsAString& aTextContent,
  1707                                       mozilla::ErrorResult& aError)
  1711 #ifdef DEBUG
  1712   // Note: virtual so that IsInNativeAnonymousSubtree can be called accross
  1713   // module boundaries.
  1714   virtual void CheckNotNativeAnonymous() const;
  1715 #endif
  1717   // These are just used to implement nsIDOMNode using
  1718   // NS_FORWARD_NSIDOMNODE_TO_NSINODE_HELPER and for quickstubs.
  1719   nsresult GetParentNode(nsIDOMNode** aParentNode);
  1720   nsresult GetParentElement(nsIDOMElement** aParentElement);
  1721   nsresult GetChildNodes(nsIDOMNodeList** aChildNodes);
  1722   nsresult GetFirstChild(nsIDOMNode** aFirstChild);
  1723   nsresult GetLastChild(nsIDOMNode** aLastChild);
  1724   nsresult GetPreviousSibling(nsIDOMNode** aPrevSibling);
  1725   nsresult GetNextSibling(nsIDOMNode** aNextSibling);
  1726   nsresult GetOwnerDocument(nsIDOMDocument** aOwnerDocument);
  1727   nsresult CompareDocumentPosition(nsIDOMNode* aOther,
  1728                                    uint16_t* aReturn);
  1730   nsresult ReplaceOrInsertBefore(bool aReplace, nsIDOMNode *aNewChild,
  1731                                  nsIDOMNode *aRefChild, nsIDOMNode **aReturn);
  1732   nsINode* ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
  1733                                  nsINode* aRefChild,
  1734                                  mozilla::ErrorResult& aError);
  1735   nsresult RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn);
  1737   /**
  1738    * Returns the Element that should be used for resolving namespaces
  1739    * on this node (ie the ownerElement for attributes, the documentElement for
  1740    * documents, the node itself for elements and for other nodes the parentNode
  1741    * if it is an element).
  1742    */
  1743   virtual mozilla::dom::Element* GetNameSpaceElement() = 0;
  1745   /**
  1746    * Most of the implementation of the nsINode RemoveChildAt method.
  1747    * Should only be called on document, element, and document fragment
  1748    * nodes.  The aChildArray passed in should be the one for |this|.
  1750    * @param aIndex The index to remove at.
  1751    * @param aNotify Whether to notify.
  1752    * @param aKid The kid at aIndex.  Must not be null.
  1753    * @param aChildArray The child array to work with.
  1754    * @param aMutationEvent whether to fire a mutation event for this removal.
  1755    */
  1756   void doRemoveChildAt(uint32_t aIndex, bool aNotify, nsIContent* aKid,
  1757                        nsAttrAndChildArray& aChildArray);
  1759   /**
  1760    * Most of the implementation of the nsINode InsertChildAt method.
  1761    * Should only be called on document, element, and document fragment
  1762    * nodes.  The aChildArray passed in should be the one for |this|.
  1764    * @param aKid The child to insert.
  1765    * @param aIndex The index to insert at.
  1766    * @param aNotify Whether to notify.
  1767    * @param aChildArray The child array to work with
  1768    */
  1769   nsresult doInsertChildAt(nsIContent* aKid, uint32_t aIndex,
  1770                            bool aNotify, nsAttrAndChildArray& aChildArray);
  1772   /**
  1773    * Parse the given selector string into an nsCSSSelectorList.
  1775    * A null return value with a non-failing aRv means the string only
  1776    * contained pseudo-element selectors.
  1778    * A failing aRv means the string was not a valid selector.
  1779    */
  1780   nsCSSSelectorList* ParseSelectorList(const nsAString& aSelectorString,
  1781                                        mozilla::ErrorResult& aRv);
  1783 public:
  1784   /* Event stuff that documents and elements share.  This needs to be
  1785      NS_IMETHOD because some subclasses implement DOM methods with
  1786      this exact name and signature and then the calling convention
  1787      needs to match.
  1789      Note that we include DOCUMENT_ONLY_EVENT events here so that we
  1790      can forward all the document stuff to this implementation.
  1791   */
  1792 #define EVENT(name_, id_, type_, struct_)                             \
  1793   mozilla::dom::EventHandlerNonNull* GetOn##name_();                  \
  1794   void SetOn##name_(mozilla::dom::EventHandlerNonNull* listener);
  1795 #define TOUCH_EVENT EVENT
  1796 #define DOCUMENT_ONLY_EVENT EVENT
  1797 #include "mozilla/EventNameList.h"
  1798 #undef DOCUMENT_ONLY_EVENT
  1799 #undef TOUCH_EVENT
  1800 #undef EVENT
  1802 protected:
  1803   static bool Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb);
  1804   static void Unlink(nsINode *tmp);
  1806   nsCOMPtr<nsINodeInfo> mNodeInfo;
  1808   nsINode* mParent;
  1810 private:
  1811   // Boolean flags.
  1812   uint32_t mBoolFlags;
  1814 protected:
  1815   nsIContent* mNextSibling;
  1816   nsIContent* mPreviousSibling;
  1817   nsIContent* mFirstChild;
  1819   union {
  1820     // Pointer to our primary frame.  Might be null.
  1821     nsIFrame* mPrimaryFrame;
  1823     // Pointer to the root of our subtree.  Might be null.
  1824     nsINode* mSubtreeRoot;
  1825   };
  1827   // Storage for more members that are usually not needed; allocated lazily.
  1828   nsSlots* mSlots;
  1829 };
  1831 // Useful inline function for getting a node given an nsIContent and an
  1832 // nsIDocument.  Returns the first argument cast to nsINode if it is non-null,
  1833 // otherwise returns the second (which may be null).  We use type variables
  1834 // instead of nsIContent* and nsIDocument* because the actual types must be
  1835 // known for the cast to work.
  1836 template<class C, class D>
  1837 inline nsINode* NODE_FROM(C& aContent, D& aDocument)
  1839   if (aContent)
  1840     return static_cast<nsINode*>(aContent);
  1841   return static_cast<nsINode*>(aDocument);
  1844 NS_DEFINE_STATIC_IID_ACCESSOR(nsINode, NS_INODE_IID)
  1846 inline nsISupports*
  1847 ToSupports(nsINode* aPointer)
  1849   return aPointer;
  1852 inline nsISupports*
  1853 ToCanonicalSupports(nsINode* aPointer)
  1855   return aPointer;
  1858 #define NS_FORWARD_NSIDOMNODE_TO_NSINODE_HELPER(...) \
  1859   NS_IMETHOD GetNodeName(nsAString& aNodeName) __VA_ARGS__ \
  1860   { \
  1861     aNodeName = nsINode::NodeName(); \
  1862     return NS_OK; \
  1863   } \
  1864   NS_IMETHOD GetNodeValue(nsAString& aNodeValue) __VA_ARGS__ \
  1865   { \
  1866     nsINode::GetNodeValue(aNodeValue); \
  1867     return NS_OK; \
  1868   } \
  1869   NS_IMETHOD SetNodeValue(const nsAString& aNodeValue) __VA_ARGS__ \
  1870   { \
  1871     mozilla::ErrorResult rv; \
  1872     nsINode::SetNodeValue(aNodeValue, rv); \
  1873     return rv.ErrorCode(); \
  1874   } \
  1875   NS_IMETHOD GetNodeType(uint16_t* aNodeType) __VA_ARGS__ \
  1876   { \
  1877     *aNodeType = nsINode::NodeType(); \
  1878     return NS_OK; \
  1879   } \
  1880   NS_IMETHOD GetParentNode(nsIDOMNode** aParentNode) __VA_ARGS__ \
  1881   { \
  1882     return nsINode::GetParentNode(aParentNode); \
  1883   } \
  1884   NS_IMETHOD GetParentElement(nsIDOMElement** aParentElement) __VA_ARGS__ \
  1885   { \
  1886     return nsINode::GetParentElement(aParentElement); \
  1887   } \
  1888   NS_IMETHOD GetChildNodes(nsIDOMNodeList** aChildNodes) __VA_ARGS__ \
  1889   { \
  1890     return nsINode::GetChildNodes(aChildNodes); \
  1891   } \
  1892   NS_IMETHOD GetFirstChild(nsIDOMNode** aFirstChild) __VA_ARGS__ \
  1893   { \
  1894     return nsINode::GetFirstChild(aFirstChild); \
  1895   } \
  1896   NS_IMETHOD GetLastChild(nsIDOMNode** aLastChild) __VA_ARGS__ \
  1897   { \
  1898     return nsINode::GetLastChild(aLastChild); \
  1899   } \
  1900   NS_IMETHOD GetPreviousSibling(nsIDOMNode** aPreviousSibling) __VA_ARGS__ \
  1901   { \
  1902     return nsINode::GetPreviousSibling(aPreviousSibling); \
  1903   } \
  1904   NS_IMETHOD GetNextSibling(nsIDOMNode** aNextSibling) __VA_ARGS__ \
  1905   { \
  1906     return nsINode::GetNextSibling(aNextSibling); \
  1907   } \
  1908   NS_IMETHOD GetOwnerDocument(nsIDOMDocument** aOwnerDocument) __VA_ARGS__ \
  1909   { \
  1910     return nsINode::GetOwnerDocument(aOwnerDocument); \
  1911   } \
  1912   NS_IMETHOD InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild, nsIDOMNode** aResult) __VA_ARGS__ \
  1913   { \
  1914     return ReplaceOrInsertBefore(false, aNewChild, aRefChild, aResult); \
  1915   } \
  1916   NS_IMETHOD ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild, nsIDOMNode** aResult) __VA_ARGS__ \
  1917   { \
  1918     return ReplaceOrInsertBefore(true, aNewChild, aOldChild, aResult); \
  1919   } \
  1920   NS_IMETHOD RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aResult) __VA_ARGS__ \
  1921   { \
  1922     return nsINode::RemoveChild(aOldChild, aResult); \
  1923   } \
  1924   NS_IMETHOD AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aResult) __VA_ARGS__ \
  1925   { \
  1926     return InsertBefore(aNewChild, nullptr, aResult); \
  1927   } \
  1928   NS_IMETHOD HasChildNodes(bool* aResult) __VA_ARGS__ \
  1929   { \
  1930     *aResult = nsINode::HasChildNodes(); \
  1931     return NS_OK; \
  1932   } \
  1933   NS_IMETHOD CloneNode(bool aDeep, uint8_t aArgc, nsIDOMNode** aResult) __VA_ARGS__ \
  1934   { \
  1935     if (aArgc == 0) { \
  1936       aDeep = true; \
  1937     } \
  1938     mozilla::ErrorResult rv; \
  1939     nsCOMPtr<nsINode> clone = nsINode::CloneNode(aDeep, rv); \
  1940     if (rv.Failed()) { \
  1941       return rv.ErrorCode(); \
  1942     } \
  1943     *aResult = clone.forget().take()->AsDOMNode(); \
  1944     return NS_OK; \
  1945   } \
  1946   NS_IMETHOD Normalize() __VA_ARGS__ \
  1947   { \
  1948     nsINode::Normalize(); \
  1949     return NS_OK; \
  1950   } \
  1951   NS_IMETHOD GetNamespaceURI(nsAString& aNamespaceURI) __VA_ARGS__ \
  1952   { \
  1953     nsINode::GetNamespaceURI(aNamespaceURI); \
  1954     return NS_OK; \
  1955   } \
  1956   NS_IMETHOD GetPrefix(nsAString& aPrefix) __VA_ARGS__ \
  1957   { \
  1958     nsINode::GetPrefix(aPrefix); \
  1959     return NS_OK; \
  1960   } \
  1961   NS_IMETHOD GetLocalName(nsAString& aLocalName) __VA_ARGS__ \
  1962   { \
  1963     aLocalName = nsINode::LocalName(); \
  1964     return NS_OK; \
  1965   } \
  1966   using nsINode::HasAttributes; \
  1967   NS_IMETHOD HasAttributes(bool* aResult) __VA_ARGS__ \
  1968   { \
  1969     *aResult = nsINode::HasAttributes(); \
  1970     return NS_OK; \
  1971   } \
  1972   NS_IMETHOD GetDOMBaseURI(nsAString& aBaseURI) __VA_ARGS__ \
  1973   { \
  1974     nsINode::GetBaseURI(aBaseURI); \
  1975     return NS_OK; \
  1976   } \
  1977   NS_IMETHOD CompareDocumentPosition(nsIDOMNode* aOther, uint16_t* aResult) __VA_ARGS__ \
  1978   { \
  1979     return nsINode::CompareDocumentPosition(aOther, aResult); \
  1980   } \
  1981   NS_IMETHOD GetTextContent(nsAString& aTextContent) __VA_ARGS__ \
  1982   { \
  1983     nsINode::GetTextContent(aTextContent); \
  1984     return NS_OK; \
  1985   } \
  1986   NS_IMETHOD SetTextContent(const nsAString& aTextContent) __VA_ARGS__ \
  1987   { \
  1988     mozilla::ErrorResult rv; \
  1989     nsINode::SetTextContent(aTextContent, rv); \
  1990     return rv.ErrorCode(); \
  1991   } \
  1992   NS_IMETHOD LookupPrefix(const nsAString& aNamespaceURI, nsAString& aResult) __VA_ARGS__ \
  1993   { \
  1994     nsINode::LookupPrefix(aNamespaceURI, aResult); \
  1995     return NS_OK; \
  1996   } \
  1997   NS_IMETHOD IsDefaultNamespace(const nsAString& aNamespaceURI, bool* aResult) __VA_ARGS__ \
  1998   { \
  1999     *aResult = nsINode::IsDefaultNamespace(aNamespaceURI); \
  2000     return NS_OK; \
  2001   } \
  2002   NS_IMETHOD LookupNamespaceURI(const nsAString& aPrefix, nsAString& aResult) __VA_ARGS__ \
  2003   { \
  2004     nsINode::LookupNamespaceURI(aPrefix, aResult); \
  2005     return NS_OK; \
  2006   } \
  2007   NS_IMETHOD IsEqualNode(nsIDOMNode* aArg, bool* aResult) __VA_ARGS__ \
  2008   { \
  2009     return nsINode::IsEqualNode(aArg, aResult); \
  2010   } \
  2011   NS_IMETHOD SetUserData(const nsAString& aKey, nsIVariant* aData, nsIDOMUserDataHandler* aHandler, nsIVariant** aResult) __VA_ARGS__ \
  2012   { \
  2013     return nsINode::SetUserData(aKey, aData, aHandler, aResult); \
  2014   } \
  2015   NS_IMETHOD GetUserData(const nsAString& aKey, nsIVariant** aResult) __VA_ARGS__ \
  2016   { \
  2017     return nsINode::GetUserData(aKey, aResult); \
  2018   } \
  2019   NS_IMETHOD Contains(nsIDOMNode* aOther, bool* aResult) __VA_ARGS__ \
  2020   { \
  2021     return nsINode::Contains(aOther, aResult); \
  2024 #define NS_FORWARD_NSIDOMNODE_TO_NSINODE \
  2025   NS_FORWARD_NSIDOMNODE_TO_NSINODE_HELPER(MOZ_FINAL)
  2027 #define NS_FORWARD_NSIDOMNODE_TO_NSINODE_OVERRIDABLE \
  2028   NS_FORWARD_NSIDOMNODE_TO_NSINODE_HELPER()
  2030 #endif /* nsINode_h___ */

mercurial