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