Line data Source code
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 : /*
8 : * Base class for all DOM nodes.
9 : */
10 :
11 : #include "nsINode.h"
12 :
13 : #include "AccessCheck.h"
14 : #include "jsapi.h"
15 : #include "mozAutoDocUpdate.h"
16 : #include "mozilla/AsyncEventDispatcher.h"
17 : #include "mozilla/CORSMode.h"
18 : #include "mozilla/EventDispatcher.h"
19 : #include "mozilla/EventListenerManager.h"
20 : #include "mozilla/HTMLEditor.h"
21 : #include "mozilla/InternalMutationEvent.h"
22 : #include "mozilla/Likely.h"
23 : #include "mozilla/MemoryReporting.h"
24 : #include "mozilla/ServoBindings.h"
25 : #include "mozilla/Telemetry.h"
26 : #include "mozilla/TextEditor.h"
27 : #include "mozilla/TimeStamp.h"
28 : #include "mozilla/dom/CharacterData.h"
29 : #include "mozilla/dom/DocumentType.h"
30 : #include "mozilla/dom/Element.h"
31 : #include "mozilla/dom/Event.h"
32 : #include "mozilla/dom/L10nUtilsBinding.h"
33 : #include "mozilla/dom/Promise.h"
34 : #include "mozilla/dom/PromiseNativeHandler.h"
35 : #include "mozilla/dom/ShadowRoot.h"
36 : #include "mozilla/dom/ScriptSettings.h"
37 : #include "nsAttrValueOrString.h"
38 : #include "nsBindingManager.h"
39 : #include "nsCCUncollectableMarker.h"
40 : #include "nsContentCreatorFunctions.h"
41 : #include "nsContentList.h"
42 : #include "nsContentUtils.h"
43 : #include "nsCycleCollectionParticipant.h"
44 : #include "nsDocument.h"
45 : #include "mozilla/dom/Attr.h"
46 : #include "nsDOMAttributeMap.h"
47 : #include "nsDOMCID.h"
48 : #include "nsDOMCSSAttrDeclaration.h"
49 : #include "nsError.h"
50 : #include "nsDOMMutationObserver.h"
51 : #include "nsDOMString.h"
52 : #include "nsDOMTokenList.h"
53 : #include "nsFocusManager.h"
54 : #include "nsFrameSelection.h"
55 : #include "nsGenericHTMLElement.h"
56 : #include "nsGkAtoms.h"
57 : #include "nsIAnonymousContentCreator.h"
58 : #include "nsAtom.h"
59 : #include "nsIBaseWindow.h"
60 : #include "nsICategoryManager.h"
61 : #include "nsIContentIterator.h"
62 : #include "nsIControllers.h"
63 : #include "nsIDocument.h"
64 : #include "nsIDOMEventListener.h"
65 : #include "nsILinkHandler.h"
66 : #include "mozilla/dom/NodeInfo.h"
67 : #include "mozilla/dom/NodeInfoInlines.h"
68 : #include "nsIPresShell.h"
69 : #include "nsIScriptError.h"
70 : #include "nsIScriptGlobalObject.h"
71 : #include "nsIScriptSecurityManager.h"
72 : #include "nsIScrollableFrame.h"
73 : #include "nsIServiceManager.h"
74 : #include "nsIURL.h"
75 : #include "nsView.h"
76 : #include "nsViewManager.h"
77 : #include "nsIWebNavigation.h"
78 : #include "nsIWidget.h"
79 : #include "nsLayoutUtils.h"
80 : #include "nsNameSpaceManager.h"
81 : #include "nsNodeInfoManager.h"
82 : #include "nsNodeUtils.h"
83 : #include "nsPIBoxObject.h"
84 : #include "nsPIDOMWindow.h"
85 : #include "nsPresContext.h"
86 : #include "nsString.h"
87 : #include "nsStyleConsts.h"
88 : #include "nsSVGUtils.h"
89 : #include "nsTextNode.h"
90 : #include "nsUnicharUtils.h"
91 : #include "nsXBLBinding.h"
92 : #include "nsXBLPrototypeBinding.h"
93 : #include "mozilla/Preferences.h"
94 : #include "xpcpublic.h"
95 : #include "HTMLLegendElement.h"
96 : #include "nsWrapperCacheInlines.h"
97 : #include "WrapperFactory.h"
98 : #include <algorithm>
99 : #include "nsGlobalWindow.h"
100 : #include "nsDOMMutationObserver.h"
101 : #include "GeometryUtils.h"
102 : #include "nsIAnimationObserver.h"
103 : #include "nsChildContentList.h"
104 : #include "mozilla/dom/NodeBinding.h"
105 : #include "mozilla/dom/BindingDeclarations.h"
106 :
107 : #include "XPathGenerator.h"
108 :
109 : #ifdef ACCESSIBILITY
110 : #include "mozilla/dom/AccessibleNode.h"
111 : #endif
112 :
113 : using namespace mozilla;
114 : using namespace mozilla::dom;
115 0 :
116 : nsINode::nsSlots::nsSlots()
117 0 : : mWeakReference(nullptr),
118 : mEditableDescendantCount(0)
119 0 : {
120 : }
121 0 :
122 : nsINode::nsSlots::~nsSlots()
123 0 : {
124 0 : if (mChildNodes) {
125 : mChildNodes->DropReference();
126 : }
127 0 :
128 0 : if (mWeakReference) {
129 : mWeakReference->NoticeNodeDestruction();
130 0 : }
131 : }
132 :
133 0 : void
134 : nsINode::nsSlots::Traverse(nsCycleCollectionTraversalCallback &cb)
135 0 : {
136 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildNodes");
137 0 : cb.NoteXPCOMChild(mChildNodes);
138 : }
139 :
140 0 : void
141 : nsINode::nsSlots::Unlink()
142 0 : {
143 0 : if (mChildNodes) {
144 : mChildNodes->DropReference();
145 0 : }
146 : }
147 :
148 : //----------------------------------------------------------------------
149 0 :
150 : nsINode::~nsINode()
151 0 : {
152 0 : MOZ_ASSERT(!HasSlots(), "nsNodeUtils::LastRelease was not called?");
153 0 : MOZ_ASSERT(mSubtreeRoot == this, "Didn't restore state properly?");
154 : }
155 :
156 0 : void*
157 : nsINode::GetProperty(nsAtom* aPropertyName, nsresult* aStatus) const
158 0 : {
159 0 : if (!HasProperties()) { // a fast HasFlag() test
160 0 : if (aStatus) {
161 : *aStatus = NS_PROPTABLE_PROP_NOT_THERE;
162 : }
163 : return nullptr;
164 0 : }
165 : return OwnerDoc()->PropertyTable().GetProperty(this, aPropertyName, aStatus);
166 : }
167 :
168 0 : nsresult
169 : nsINode::SetProperty(nsAtom* aPropertyName,
170 : void* aValue,
171 : NSPropertyDtorFunc aDtor,
172 : bool aTransfer)
173 0 : {
174 : nsresult rv = OwnerDoc()->PropertyTable().SetProperty(this,
175 : aPropertyName,
176 : aValue,
177 : aDtor,
178 0 : nullptr,
179 0 : aTransfer);
180 0 : if (NS_SUCCEEDED(rv)) {
181 : SetFlags(NODE_HAS_PROPERTIES);
182 : }
183 0 :
184 : return rv;
185 : }
186 :
187 0 : void
188 : nsINode::DeleteProperty(nsAtom* aPropertyName)
189 0 : {
190 0 : OwnerDoc()->PropertyTable().DeleteProperty(this, aPropertyName);
191 : }
192 :
193 0 : void*
194 : nsINode::UnsetProperty(nsAtom* aPropertyName, nsresult* aStatus)
195 0 : {
196 : return OwnerDoc()->PropertyTable().UnsetProperty(this, aPropertyName, aStatus);
197 : }
198 :
199 0 : nsINode::nsSlots*
200 : nsINode::CreateSlots()
201 0 : {
202 : return new nsSlots();
203 : }
204 :
205 0 : nsIContent*
206 : nsINode::GetTextEditorRootContent(TextEditor** aTextEditor)
207 0 : {
208 0 : if (aTextEditor) {
209 : *aTextEditor = nullptr;
210 9 : }
211 12 : for (nsINode* node = this; node; node = node->GetParentNode()) {
212 0 : if (!node->IsElement() ||
213 3 : !node->IsHTMLElement())
214 : continue;
215 :
216 6 : RefPtr<TextEditor> textEditor =
217 6 : static_cast<nsGenericHTMLElement*>(node)->GetTextEditorInternal();
218 3 : if (!textEditor) {
219 : continue;
220 : }
221 0 :
222 : MOZ_ASSERT(!textEditor->AsHTMLEditor(),
223 6 : "If it were an HTML editor, needs to use GetRootElement()");
224 0 : Element* rootElement = textEditor->GetRoot();
225 0 : if (aTextEditor) {
226 : textEditor.forget(aTextEditor);
227 0 : }
228 : return rootElement;
229 : }
230 : return nullptr;
231 : }
232 0 :
233 : nsINode* nsINode::GetRootNode(const GetRootNodeOptions& aOptions)
234 0 : {
235 0 : if (aOptions.mComposed) {
236 0 : if (IsInComposedDoc() && GetComposedDoc()) {
237 : return OwnerDoc();
238 : }
239 :
240 0 : nsINode* node = this;
241 0 : while(node) {
242 0 : node = node->SubtreeRoot();
243 0 : ShadowRoot* shadow = ShadowRoot::FromNode(node);
244 : if (!shadow) {
245 : break;
246 0 : }
247 : node = shadow->GetHost();
248 : }
249 :
250 : return node;
251 : }
252 0 :
253 : return SubtreeRoot();
254 : }
255 :
256 0 : nsINode*
257 : nsINode::GetParentOrHostNode() const
258 65 : {
259 : if (mParent) {
260 : return mParent;
261 : }
262 6 :
263 6 : const ShadowRoot* shadowRoot = ShadowRoot::FromNode(this);
264 : return shadowRoot ? shadowRoot->GetHost() : nullptr;
265 : }
266 :
267 1167 : nsINode*
268 : nsINode::SubtreeRoot() const
269 : {
270 : auto RootOfNode = [](const nsINode* aStart) -> nsINode* {
271 : const nsINode* node = aStart;
272 0 : const nsINode* iter = node;
273 : while ((iter = iter->GetParentNode())) {
274 : node = iter;
275 : }
276 : return const_cast<nsINode*>(node);
277 : };
278 :
279 : // There are four cases of interest here. nsINodes that are really:
280 : // 1. nsIDocument nodes - Are always in the document.
281 : // 2.a nsIContent nodes not in a shadow tree - Are either in the document,
282 : // or mSubtreeRoot is updated in BindToTree/UnbindFromTree.
283 : // 2.b nsIContent nodes in a shadow tree - Are never in the document,
284 : // ignore mSubtreeRoot and return the containing shadow root.
285 : // 4. nsIAttribute nodes - Are never in the document, and mSubtreeRoot
286 : // is always 'this' (as set in nsINode's ctor).
287 1167 : nsINode* node;
288 83 : if (IsInUncomposedDoc()) {
289 1084 : node = OwnerDocAsNode();
290 1084 : } else if (IsContent()) {
291 1084 : ShadowRoot* containingShadow = AsContent()->GetContainingShadow();
292 1084 : node = containingShadow ? containingShadow : mSubtreeRoot;
293 0 : if (!node) {
294 0 : NS_WARNING("Using SubtreeRoot() on unlinked element?");
295 : node = RootOfNode(this);
296 : }
297 0 : } else {
298 : node = mSubtreeRoot;
299 1167 : }
300 : MOZ_ASSERT(node, "Should always have a node here!");
301 : #ifdef DEBUG
302 0 : {
303 0 : const nsINode* slowNode = RootOfNode(this);
304 : MOZ_ASSERT(slowNode == node, "These should always be in sync!");
305 : }
306 0 : #endif
307 : return node;
308 : }
309 0 :
310 : static nsIContent* GetRootForContentSubtree(nsIContent* aContent)
311 0 : {
312 : NS_ENSURE_TRUE(aContent, nullptr);
313 :
314 : // Special case for ShadowRoot because the ShadowRoot itself is
315 : // the root. This is necessary to prevent selection from crossing
316 0 : // the ShadowRoot boundary.
317 0 : ShadowRoot* containingShadow = aContent->GetContainingShadow();
318 : if (containingShadow) {
319 : return containingShadow;
320 : }
321 0 :
322 0 : nsIContent* stop = aContent->GetBindingParent();
323 0 : while (aContent) {
324 0 : nsIContent* parent = aContent->GetParent();
325 : if (parent == stop) {
326 : break;
327 : }
328 : aContent = parent;
329 : }
330 : return aContent;
331 : }
332 :
333 3 : nsIContent*
334 : nsINode::GetSelectionRootContent(nsIPresShell* aPresShell)
335 0 : {
336 : NS_ENSURE_TRUE(aPresShell, nullptr);
337 0 :
338 0 : if (IsDocument())
339 3 : return AsDocument()->GetRootElement();
340 : if (!IsContent())
341 : return nullptr;
342 6 :
343 : if (GetComposedDoc() != aPresShell->GetDocument()) {
344 : return nullptr;
345 : }
346 3 :
347 : if (static_cast<nsIContent*>(this)->HasIndependentSelection()) {
348 3 : // This node should be a descendant of input/textarea editor.
349 0 : nsIContent* content = GetTextEditorRootContent();
350 : if (content)
351 : return content;
352 : }
353 0 :
354 0 : nsPresContext* presContext = aPresShell->GetPresContext();
355 0 : if (presContext) {
356 0 : HTMLEditor* htmlEditor = nsContentUtils::GetHTMLEditor(presContext);
357 : if (htmlEditor) {
358 0 : // This node is in HTML editor.
359 0 : nsIDocument* doc = GetComposedDoc();
360 0 : if (!doc || doc->HasFlag(NODE_IS_EDITABLE) ||
361 0 : !HasFlag(NODE_IS_EDITABLE)) {
362 0 : nsIContent* editorRoot = htmlEditor->GetRoot();
363 0 : NS_ENSURE_TRUE(editorRoot, nullptr);
364 : return nsContentUtils::IsInSameAnonymousTree(this, editorRoot) ?
365 : editorRoot :
366 : GetRootForContentSubtree(static_cast<nsIContent*>(this));
367 : }
368 : // If the document isn't editable but this is editable, this is in
369 0 : // contenteditable. Use the editing host element for selection root.
370 : return static_cast<nsIContent*>(this)->GetEditingHost();
371 : }
372 : }
373 0 :
374 0 : RefPtr<nsFrameSelection> fs = aPresShell->FrameSelection();
375 0 : nsIContent* content = fs->GetLimiter();
376 0 : if (!content) {
377 0 : content = fs->GetAncestorLimiter();
378 0 : if (!content) {
379 0 : nsIDocument* doc = aPresShell->GetDocument();
380 0 : NS_ENSURE_TRUE(doc, nullptr);
381 0 : content = doc->GetRootElement();
382 : if (!content)
383 : return nullptr;
384 : }
385 : }
386 :
387 : // This node might be in another subtree, if so, we should find this subtree's
388 0 : // root. Otherwise, we can return the content simply.
389 0 : NS_ENSURE_TRUE(content, nullptr);
390 0 : if (!nsContentUtils::IsInSameAnonymousTree(this, content)) {
391 : content = GetRootForContentSubtree(static_cast<nsIContent*>(this));
392 : // Fixup for ShadowRoot because the ShadowRoot itself does not have a frame.
393 0 : // Use the host as the root.
394 0 : if (ShadowRoot* shadowRoot = ShadowRoot::FromNode(content)) {
395 : content = shadowRoot->GetHost();
396 : }
397 : }
398 :
399 : return content;
400 : }
401 :
402 0 : nsINodeList*
403 : nsINode::ChildNodes()
404 0 : {
405 6666 : nsSlots* slots = Slots();
406 1654 : if (!slots->mChildNodes) {
407 0 : slots->mChildNodes = IsAttr()
408 1 : ? new nsAttrChildContentList(this)
409 : : new nsParentNodeChildContentList(this);
410 : }
411 6666 :
412 : return slots->mChildNodes;
413 : }
414 :
415 8642 : void
416 : nsINode::InvalidateChildNodes()
417 8642 : {
418 : MOZ_ASSERT(!IsAttr());
419 0 :
420 0 : nsSlots* slots = GetExistingSlots();
421 : if (!slots || !slots->mChildNodes) {
422 : return;
423 : }
424 :
425 0 : auto childNodes =
426 0 : static_cast<nsParentNodeChildContentList*>(slots->mChildNodes.get());
427 : childNodes->InvalidateCache();
428 : }
429 :
430 0 : void
431 : nsINode::GetTextContentInternal(nsAString& aTextContent, OOMReporter& aError)
432 0 : {
433 0 : SetDOMStringToNull(aTextContent);
434 : }
435 :
436 0 : nsIDocument*
437 : nsINode::GetComposedDocInternal() const
438 0 : {
439 : MOZ_ASSERT(HasFlag(NODE_IS_IN_SHADOW_TREE) && IsContent(),
440 : "Should only be caled on nodes in the shadow tree.");
441 0 :
442 0 : ShadowRoot* containingShadow = AsContent()->GetContainingShadow();
443 0 : return containingShadow && containingShadow->IsComposedDocParticipant() ?
444 : OwnerDoc() : nullptr;
445 : }
446 :
447 0 : DocumentOrShadowRoot*
448 : nsINode::GetUncomposedDocOrConnectedShadowRoot() const
449 0 : {
450 0 : if (IsInUncomposedDoc()) {
451 : return OwnerDoc();
452 : }
453 0 :
454 0 : if (IsInComposedDoc() && HasFlag(NODE_IS_IN_SHADOW_TREE)) {
455 : return AsContent()->GetContainingShadow();
456 : }
457 :
458 : return nullptr;
459 : }
460 :
461 : #ifdef DEBUG
462 27154 : void
463 : nsINode::CheckNotNativeAnonymous() const
464 0 : {
465 : if (!IsContent())
466 27154 : return;
467 0 : nsIContent* content = static_cast<const nsIContent *>(this)->GetBindingParent();
468 0 : while (content) {
469 0 : if (content->IsRootOfNativeAnonymousSubtree()) {
470 : NS_ERROR("Element not marked to be in native anonymous subtree!");
471 : break;
472 1704 : }
473 : content = content->GetBindingParent();
474 : }
475 : }
476 : #endif
477 :
478 0 : bool
479 : nsINode::IsInAnonymousSubtree() const
480 0 : {
481 : if (!IsContent()) {
482 : return false;
483 : }
484 5638 :
485 : return AsContent()->IsInAnonymousSubtree();
486 : }
487 :
488 0 : std::ostream&
489 : operator<<(std::ostream& aStream, const nsINode& aNode)
490 0 : {
491 0 : nsAutoString elemDesc;
492 0 : const nsINode* curr = &aNode;
493 0 : while (curr) {
494 0 : const nsString& localName = curr->LocalName();
495 0 : nsString id;
496 0 : if (curr->IsElement()) {
497 : curr->AsElement()->GetId(id);
498 : }
499 0 :
500 0 : if (!elemDesc.IsEmpty()) {
501 : elemDesc = elemDesc + NS_LITERAL_STRING(".");
502 : }
503 0 :
504 : elemDesc = elemDesc + localName;
505 0 :
506 0 : if (!id.IsEmpty()) {
507 0 : elemDesc = elemDesc + NS_LITERAL_STRING("['") + id +
508 : NS_LITERAL_STRING("']");
509 : }
510 0 :
511 : curr = curr->GetParentNode();
512 : }
513 0 :
514 0 : NS_ConvertUTF16toUTF8 str(elemDesc);
515 : return aStream << str.get();
516 : }
517 :
518 53 : bool
519 : nsINode::IsAnonymousContentInSVGUseSubtree() const
520 1 : {
521 1 : MOZ_ASSERT(IsInAnonymousSubtree());
522 : nsIContent* parent = AsContent()->GetBindingParent();
523 53 : // Watch out for parentless native-anonymous subtrees.
524 : return parent && parent->IsSVGElement(nsGkAtoms::use);
525 : }
526 :
527 0 : void
528 : nsINode::GetNodeValueInternal(nsAString& aNodeValue)
529 0 : {
530 0 : SetDOMStringToNull(aNodeValue);
531 : }
532 :
533 2 : nsINode*
534 : nsINode::RemoveChild(nsINode& aOldChild, ErrorResult& aError)
535 0 : {
536 : if (IsCharacterData()) {
537 0 : // aOldChild can't be one of our children.
538 0 : aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
539 : return nullptr;
540 : }
541 0 :
542 2 : if (aOldChild.GetParentNode() == this) {
543 : nsContentUtils::MaybeFireNodeRemoved(&aOldChild, this);
544 : }
545 2 :
546 2 : int32_t index = ComputeIndexOf(&aOldChild);
547 : if (index == -1) {
548 0 : // aOldChild isn't one of our children.
549 0 : aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
550 : return nullptr;
551 : }
552 0 :
553 2 : RemoveChildAt_Deprecated(index, true);
554 : return &aOldChild;
555 : }
556 :
557 0 : void
558 : nsINode::Normalize()
559 : {
560 0 : // First collect list of nodes to be removed
561 : AutoTArray<nsCOMPtr<nsIContent>, 50> nodes;
562 0 :
563 0 : bool canMerge = false;
564 0 : for (nsIContent* node = this->GetFirstChild();
565 0 : node;
566 0 : node = node->GetNextNode(this)) {
567 : if (node->NodeType() != TEXT_NODE) {
568 : canMerge = false;
569 : continue;
570 : }
571 0 :
572 : if (canMerge || node->TextLength() == 0) {
573 : // No need to touch canMerge. That way we can merge across empty
574 0 : // textnodes if and only if the node before is a textnode
575 : nodes.AppendElement(node);
576 : }
577 : else {
578 : canMerge = true;
579 : }
580 :
581 : // If there's no following sibling, then we need to ensure that we don't
582 0 : // collect following siblings of our (grand)parent as to-be-removed
583 : canMerge = canMerge && !!node->GetNextSibling();
584 : }
585 0 :
586 0 : if (nodes.IsEmpty()) {
587 : return;
588 : }
589 :
590 0 : // We're relying on mozAutoSubtreeModified to keep the doc alive here.
591 : nsIDocument* doc = OwnerDoc();
592 :
593 0 : // Batch possible DOMSubtreeModified events.
594 : mozAutoSubtreeModified subtree(doc, nullptr);
595 :
596 : // Fire all DOMNodeRemoved events. Optimize the common case of there being
597 : // no listeners
598 0 : bool hasRemoveListeners = nsContentUtils::
599 0 : HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEREMOVED);
600 0 : if (hasRemoveListeners) {
601 0 : for (uint32_t i = 0; i < nodes.Length(); ++i) {
602 0 : nsINode* parentNode = nodes[i]->GetParentNode();
603 0 : if (parentNode) { // Node may have already been removed.
604 : nsContentUtils::MaybeFireNodeRemoved(nodes[i], parentNode);
605 : }
606 : }
607 : }
608 0 :
609 : mozAutoDocUpdate batch(doc, true);
610 :
611 0 : // Merge and remove all nodes
612 0 : nsAutoString tmpStr;
613 0 : for (uint32_t i = 0; i < nodes.Length(); ++i) {
614 : nsIContent* node = nodes[i];
615 0 : // Merge with previous node unless empty
616 0 : const nsTextFragment* text = node->GetText();
617 0 : if (text->GetLength()) {
618 0 : nsIContent* target = node->GetPreviousSibling();
619 : NS_ASSERTION((target && target->NodeType() == TEXT_NODE) ||
620 : hasRemoveListeners,
621 : "Should always have a previous text sibling unless "
622 0 : "mutation events messed us up");
623 0 : if (!hasRemoveListeners ||
624 0 : (target && target->NodeType() == TEXT_NODE)) {
625 0 : nsTextNode* t = static_cast<nsTextNode*>(target);
626 0 : if (text->Is2b()) {
627 : t->AppendTextForNormalize(text->Get2b(), text->GetLength(), true, node);
628 : }
629 0 : else {
630 0 : tmpStr.Truncate();
631 0 : text->AppendTo(tmpStr);
632 : t->AppendTextForNormalize(tmpStr.get(), tmpStr.Length(), true, node);
633 : }
634 : }
635 : }
636 :
637 0 : // Remove node
638 0 : nsCOMPtr<nsINode> parent = node->GetParentNode();
639 : NS_ASSERTION(parent || hasRemoveListeners,
640 : "Should always have a parent unless "
641 0 : "mutation events messed us up");
642 0 : if (parent) {
643 : parent->RemoveChildAt_Deprecated(parent->ComputeIndexOf(node), true);
644 : }
645 : }
646 : }
647 :
648 0 : nsresult
649 : nsINode::GetBaseURI(nsAString &aURI) const
650 0 : {
651 : nsCOMPtr<nsIURI> baseURI = GetBaseURI();
652 0 :
653 0 : nsAutoCString spec;
654 0 : if (baseURI) {
655 0 : nsresult rv = baseURI->GetSpec(spec);
656 : NS_ENSURE_SUCCESS(rv, rv);
657 : }
658 0 :
659 0 : CopyUTF8toUTF16(spec, aURI);
660 : return NS_OK;
661 : }
662 :
663 10 : void
664 : nsINode::GetBaseURIFromJS(nsAString& aURI,
665 : CallerType aCallerType,
666 : ErrorResult& aRv) const
667 0 : {
668 0 : nsCOMPtr<nsIURI> baseURI = GetBaseURI(aCallerType == CallerType::System);
669 0 : nsAutoCString spec;
670 10 : if (baseURI) {
671 10 : nsresult res = baseURI->GetSpec(spec);
672 0 : if (NS_FAILED(res)) {
673 0 : aRv.Throw(res);
674 : return;
675 : }
676 10 : }
677 : CopyUTF8toUTF16(spec, aURI);
678 : }
679 :
680 0 : already_AddRefed<nsIURI>
681 : nsINode::GetBaseURIObject() const
682 0 : {
683 : return GetBaseURI(true);
684 : }
685 :
686 0 : void
687 : nsINode::LookupPrefix(const nsAString& aNamespaceURI, nsAString& aPrefix)
688 0 : {
689 0 : Element *element = GetNameSpaceElement();
690 : if (element) {
691 : // XXX Waiting for DOM spec to list error codes.
692 :
693 : // Trace up the content parent chain looking for the namespace
694 : // declaration that defines the aNamespaceURI namespace. Once found,
695 0 : // return the prefix (i.e. the attribute localName).
696 0 : for (nsIContent* content = element; content;
697 0 : content = content->GetParent()) {
698 : if (!content->IsElement()) {
699 : continue;
700 : }
701 0 :
702 0 : Element* element = content->AsElement();
703 : uint32_t attrCount = element->GetAttrCount();
704 0 :
705 0 : for (uint32_t i = 0; i < attrCount; ++i) {
706 : const nsAttrName* name = element->GetAttrNameAt(i);
707 0 :
708 0 : if (name->NamespaceEquals(kNameSpaceID_XMLNS) &&
709 : element->AttrValueIs(kNameSpaceID_XMLNS, name->LocalName(),
710 : aNamespaceURI, eCaseMatters)) {
711 : // If the localName is "xmlns", the prefix we output should be
712 0 : // null.
713 : nsAtom* localName = name->LocalName();
714 0 :
715 0 : if (localName != nsGkAtoms::xmlns) {
716 : localName->ToString(aPrefix);
717 : }
718 0 : else {
719 : SetDOMStringToNull(aPrefix);
720 : }
721 : return;
722 : }
723 : }
724 : }
725 : }
726 0 :
727 : SetDOMStringToNull(aPrefix);
728 : }
729 :
730 105 : uint16_t
731 : nsINode::CompareDocumentPosition(nsINode& aOtherNode) const
732 0 : {
733 : if (this == &aOtherNode) {
734 : return 0;
735 105 : }
736 12 : if (GetPreviousSibling() == &aOtherNode) {
737 : MOZ_ASSERT(GetParentNode() == aOtherNode.GetParentNode());
738 : return NodeBinding::DOCUMENT_POSITION_PRECEDING;
739 93 : }
740 0 : if (GetNextSibling() == &aOtherNode) {
741 : MOZ_ASSERT(GetParentNode() == aOtherNode.GetParentNode());
742 : return NodeBinding::DOCUMENT_POSITION_FOLLOWING;
743 : }
744 0 :
745 : AutoTArray<const nsINode*, 32> parents1, parents2;
746 0 :
747 93 : const nsINode* node1 = &aOtherNode;
748 : const nsINode* node2 = this;
749 :
750 0 : // Check if either node is an attribute
751 93 : const Attr* attr1 = Attr::FromNode(node1);
752 0 : if (attr1) {
753 : const Element* elem = attr1->GetElement();
754 : // If there is an owner element add the attribute
755 0 : // to the chain and walk up to the element
756 0 : if (elem) {
757 0 : node1 = elem;
758 : parents1.AppendElement(attr1);
759 : }
760 0 : }
761 0 : if (auto* attr2 = Attr::FromNode(node2)) {
762 0 : const Element* elem = attr2->GetElement();
763 : if (elem == node1 && attr1) {
764 : // Both nodes are attributes on the same element.
765 : // Compare position between the attributes.
766 :
767 : uint32_t i;
768 0 : const nsAttrName* attrName;
769 0 : for (i = 0; (attrName = elem->GetAttrNameAt(i)); ++i) {
770 0 : if (attrName->Equals(attr1->NodeInfo())) {
771 : NS_ASSERTION(!attrName->Equals(attr2->NodeInfo()),
772 : "Different attrs at same position");
773 0 : return NodeBinding::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
774 : NodeBinding::DOCUMENT_POSITION_PRECEDING;
775 0 : }
776 : if (attrName->Equals(attr2->NodeInfo())) {
777 : return NodeBinding::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
778 : NodeBinding::DOCUMENT_POSITION_FOLLOWING;
779 : }
780 0 : }
781 0 : NS_NOTREACHED("neither attribute in the element");
782 : return NodeBinding::DOCUMENT_POSITION_DISCONNECTED;
783 : }
784 0 :
785 0 : if (elem) {
786 0 : node2 = elem;
787 : parents2.AppendElement(attr2);
788 : }
789 : }
790 :
791 : // We now know that both nodes are either nsIContents or nsIDocuments.
792 : // If either node started out as an attribute, that attribute will have
793 : // the same relative position as its ownerElement, except if the
794 : // ownerElement ends up being the container for the other node
795 :
796 : // Build the chain of parents
797 555 : do {
798 1 : parents1.AppendElement(node1);
799 1 : node1 = node1->GetParentNode();
800 : } while (node1);
801 551 : do {
802 551 : parents2.AppendElement(node2);
803 551 : node2 = node2->GetParentNode();
804 : } while (node2);
805 :
806 93 : // Check if the nodes are disconnected.
807 93 : uint32_t pos1 = parents1.Length();
808 93 : uint32_t pos2 = parents2.Length();
809 93 : const nsINode* top1 = parents1.ElementAt(--pos1);
810 93 : const nsINode* top2 = parents2.ElementAt(--pos2);
811 : if (top1 != top2) {
812 : return top1 < top2 ?
813 : (NodeBinding::DOCUMENT_POSITION_PRECEDING |
814 : NodeBinding::DOCUMENT_POSITION_DISCONNECTED |
815 : NodeBinding::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC) :
816 : (NodeBinding::DOCUMENT_POSITION_FOLLOWING |
817 0 : NodeBinding::DOCUMENT_POSITION_DISCONNECTED |
818 : NodeBinding::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
819 : }
820 :
821 0 : // Find where the parent chain differs and check indices in the parent.
822 : const nsINode* parent = top1;
823 0 : uint32_t len;
824 0 : for (len = std::min(pos1, pos2); len > 0; --len) {
825 282 : const nsINode* child1 = parents1.ElementAt(--pos1);
826 282 : const nsINode* child2 = parents2.ElementAt(--pos2);
827 : if (child1 != child2) {
828 : // child1 or child2 can be an attribute here. This will work fine since
829 : // ComputeIndexOf will return -1 for the attribute making the
830 93 : // attribute be considered before any child.
831 : return parent->ComputeIndexOf(child1) < parent->ComputeIndexOf(child2) ?
832 : NodeBinding::DOCUMENT_POSITION_PRECEDING :
833 : NodeBinding::DOCUMENT_POSITION_FOLLOWING;
834 189 : }
835 : parent = child1;
836 : }
837 :
838 : // We hit the end of one of the parent chains without finding a difference
839 : // between the chains. That must mean that one node is an ancestor of the
840 0 : // other. The one with the shortest chain must be the ancestor.
841 : return pos1 < pos2 ?
842 : (NodeBinding::DOCUMENT_POSITION_PRECEDING |
843 : NodeBinding::DOCUMENT_POSITION_CONTAINS) :
844 0 : (NodeBinding::DOCUMENT_POSITION_FOLLOWING |
845 : NodeBinding::DOCUMENT_POSITION_CONTAINED_BY);
846 : }
847 :
848 0 : bool
849 : nsINode::IsSameNode(nsINode *other)
850 0 : {
851 : return other == this;
852 : }
853 :
854 0 : bool
855 : nsINode::IsEqualNode(nsINode* aOther)
856 1 : {
857 : if (!aOther) {
858 : return false;
859 : }
860 2 :
861 : nsAutoString string1, string2;
862 0 :
863 1 : nsINode* node1 = this;
864 : nsINode* node2 = aOther;
865 1 : do {
866 1 : uint16_t nodeType = node1->NodeType();
867 : if (nodeType != node2->NodeType()) {
868 : return false;
869 : }
870 0 :
871 2 : mozilla::dom::NodeInfo* nodeInfo1 = node1->mNodeInfo;
872 1 : mozilla::dom::NodeInfo* nodeInfo2 = node2->mNodeInfo;
873 : if (!nodeInfo1->Equals(nodeInfo2) ||
874 : nodeInfo1->GetExtraName() != nodeInfo2->GetExtraName()) {
875 : return false;
876 : }
877 0 :
878 : switch(nodeType) {
879 : case ELEMENT_NODE:
880 : {
881 : // Both are elements (we checked that their nodeinfos are equal). Do the
882 1 : // check on attributes.
883 1 : Element* element1 = node1->AsElement();
884 0 : Element* element2 = node2->AsElement();
885 0 : uint32_t attrCount = element1->GetAttrCount();
886 : if (attrCount != element2->GetAttrCount()) {
887 : return false;
888 : }
889 :
890 15 : // Iterate over attributes.
891 0 : for (uint32_t i = 0; i < attrCount; ++i) {
892 : const nsAttrName* attrName = element1->GetAttrNameAt(i);
893 : #ifdef DEBUG
894 : bool hasAttr =
895 7 : #endif
896 0 : element1->GetAttr(attrName->NamespaceID(), attrName->LocalName(),
897 0 : string1);
898 : NS_ASSERTION(hasAttr, "Why don't we have an attr?");
899 0 :
900 : if (!element2->AttrValueIs(attrName->NamespaceID(),
901 : attrName->LocalName(),
902 : string1,
903 : eCaseMatters)) {
904 : return false;
905 : }
906 : }
907 : break;
908 : }
909 : case TEXT_NODE:
910 : case COMMENT_NODE:
911 : case CDATA_SECTION_NODE:
912 : case PROCESSING_INSTRUCTION_NODE:
913 0 : {
914 0 : MOZ_ASSERT(node1->IsCharacterData());
915 0 : MOZ_ASSERT(node2->IsCharacterData());
916 0 : string1.Truncate();
917 0 : static_cast<CharacterData*>(node1)->AppendTextTo(string1);
918 0 : string2.Truncate();
919 : static_cast<CharacterData*>(node2)->AppendTextTo(string2);
920 0 :
921 : if (!string1.Equals(string2)) {
922 : return false;
923 : }
924 :
925 : break;
926 : }
927 : case DOCUMENT_NODE:
928 : case DOCUMENT_FRAGMENT_NODE:
929 : break;
930 : case ATTRIBUTE_NODE:
931 0 : {
932 : NS_ASSERTION(node1 == this && node2 == aOther,
933 : "Did we come upon an attribute node while walking a "
934 0 : "subtree?");
935 0 : node1->GetNodeValue(string1);
936 : node2->GetNodeValue(string2);
937 :
938 : // Returning here as to not bother walking subtree. And there is no
939 : // risk that we're half way through walking some other subtree since
940 0 : // attribute nodes doesn't appear in subtrees.
941 : return string1.Equals(string2);
942 : }
943 : case DOCUMENT_TYPE_NODE:
944 0 : {
945 0 : DocumentType* docType1 = static_cast<DocumentType*>(node1);
946 : DocumentType* docType2 = static_cast<DocumentType*>(node2);
947 :
948 0 : // Public ID
949 0 : docType1->GetPublicId(string1);
950 0 : docType2->GetPublicId(string2);
951 : if (!string1.Equals(string2)) {
952 : return false;
953 : }
954 :
955 0 : // System ID
956 0 : docType1->GetSystemId(string1);
957 0 : docType2->GetSystemId(string2);
958 : if (!string1.Equals(string2)) {
959 : return false;
960 : }
961 :
962 : break;
963 : }
964 0 : default:
965 : MOZ_ASSERT(false, "Unknown node type");
966 : }
967 1 :
968 1 : nsINode* nextNode = node1->GetFirstChild();
969 0 : if (nextNode) {
970 0 : node1 = nextNode;
971 : node2 = node2->GetFirstChild();
972 : }
973 1 : else {
974 : if (node2->GetFirstChild()) {
975 : // node2 has a firstChild, but node1 doesn't
976 : return false;
977 : }
978 :
979 : // Find next sibling, possibly walking parent chain.
980 1 : while (1) {
981 0 : if (node1 == this) {
982 : NS_ASSERTION(node2 == aOther, "Should have reached the start node "
983 : "for both trees at the same time");
984 : return true;
985 : }
986 0 :
987 0 : nextNode = node1->GetNextSibling();
988 0 : if (nextNode) {
989 0 : node1 = nextNode;
990 0 : node2 = node2->GetNextSibling();
991 : break;
992 : }
993 0 :
994 : if (node2->GetNextSibling()) {
995 : // node2 has a nextSibling, but node1 doesn't
996 : return false;
997 : }
998 0 :
999 0 : node1 = node1->GetParentNode();
1000 0 : node2 = node2->GetParentNode();
1001 : NS_ASSERTION(node1 && node2, "no parent while walking subtree");
1002 : }
1003 0 : }
1004 : } while(node2);
1005 :
1006 : return false;
1007 : }
1008 :
1009 63 : void
1010 : nsINode::LookupNamespaceURI(const nsAString& aNamespacePrefix,
1011 : nsAString& aNamespaceURI)
1012 0 : {
1013 0 : Element *element = GetNameSpaceElement();
1014 0 : if (!element ||
1015 : NS_FAILED(element->LookupNamespaceURIInternal(aNamespacePrefix,
1016 53 : aNamespaceURI))) {
1017 : SetDOMStringToNull(aNamespaceURI);
1018 63 : }
1019 : }
1020 :
1021 144 : bool
1022 : nsINode::ComputeDefaultWantsUntrusted(ErrorResult& aRv)
1023 0 : {
1024 : return !nsContentUtils::IsChromeDoc(OwnerDoc());
1025 : }
1026 :
1027 0 : void
1028 : nsINode::GetBoxQuads(const BoxQuadOptions& aOptions,
1029 : nsTArray<RefPtr<DOMQuad> >& aResult,
1030 : CallerType aCallerType,
1031 : mozilla::ErrorResult& aRv)
1032 0 : {
1033 0 : mozilla::GetBoxQuads(this, aOptions, aResult, aCallerType, aRv);
1034 : }
1035 :
1036 0 : already_AddRefed<DOMQuad>
1037 : nsINode::ConvertQuadFromNode(DOMQuad& aQuad,
1038 : const GeometryNode& aFrom,
1039 : const ConvertCoordinateOptions& aOptions,
1040 : CallerType aCallerType,
1041 : ErrorResult& aRv)
1042 : {
1043 0 : return mozilla::ConvertQuadFromNode(this, aQuad, aFrom, aOptions, aCallerType,
1044 : aRv);
1045 : }
1046 :
1047 0 : already_AddRefed<DOMQuad>
1048 : nsINode::ConvertRectFromNode(DOMRectReadOnly& aRect,
1049 : const GeometryNode& aFrom,
1050 : const ConvertCoordinateOptions& aOptions,
1051 : CallerType aCallerType,
1052 : ErrorResult& aRv)
1053 : {
1054 0 : return mozilla::ConvertRectFromNode(this, aRect, aFrom, aOptions, aCallerType,
1055 : aRv);
1056 : }
1057 :
1058 0 : already_AddRefed<DOMPoint>
1059 : nsINode::ConvertPointFromNode(const DOMPointInit& aPoint,
1060 : const GeometryNode& aFrom,
1061 : const ConvertCoordinateOptions& aOptions,
1062 : CallerType aCallerType,
1063 : ErrorResult& aRv)
1064 : {
1065 0 : return mozilla::ConvertPointFromNode(this, aPoint, aFrom, aOptions,
1066 : aCallerType, aRv);
1067 : }
1068 :
1069 245 : bool
1070 : nsINode::DispatchEvent(Event& aEvent, CallerType aCallerType, ErrorResult& aRv)
1071 : {
1072 : // XXX sXBL/XBL2 issue -- do we really want the owner here? What
1073 490 : // if that's the XBL document? Would we want its presshell? Or what?
1074 : nsCOMPtr<nsIDocument> document = OwnerDoc();
1075 :
1076 245 : // Do nothing if the element does not belong to a document
1077 : if (!document) {
1078 : return true;
1079 : }
1080 :
1081 490 : // Obtain a presentation shell
1082 : RefPtr<nsPresContext> context = document->GetPresContext();
1083 0 :
1084 : nsEventStatus status = nsEventStatus_eIgnore;
1085 245 : nsresult rv =
1086 245 : EventDispatcher::DispatchDOMEvent(this, nullptr, &aEvent, context, &status);
1087 0 : bool retval = !aEvent.DefaultPrevented(aCallerType);
1088 0 : if (NS_FAILED(rv)) {
1089 : aRv.Throw(rv);
1090 : }
1091 : return retval;
1092 : }
1093 :
1094 610 : nsresult
1095 : nsINode::PostHandleEvent(EventChainPostVisitor& /*aVisitor*/)
1096 610 : {
1097 : return NS_OK;
1098 : }
1099 :
1100 0 : EventListenerManager*
1101 : nsINode::GetOrCreateListenerManager()
1102 0 : {
1103 : return nsContentUtils::GetListenerManagerForNode(this);
1104 : }
1105 :
1106 514 : EventListenerManager*
1107 : nsINode::GetExistingListenerManager() const
1108 0 : {
1109 : return nsContentUtils::GetExistingListenerManagerForNode(this);
1110 : }
1111 :
1112 29 : nsPIDOMWindowOuter*
1113 : nsINode::GetOwnerGlobalForBindings()
1114 : {
1115 29 : bool dummy;
1116 0 : auto* window = static_cast<nsGlobalWindowInner*>(OwnerDoc()->GetScriptHandlingObject(dummy));
1117 : return window ? nsPIDOMWindowOuter::GetFromCurrentInner(window->AsInner()) : nullptr;
1118 : }
1119 :
1120 0 : nsIGlobalObject*
1121 : nsINode::GetOwnerGlobal() const
1122 : {
1123 156 : bool dummy;
1124 : return OwnerDoc()->GetScriptHandlingObject(dummy);
1125 : }
1126 :
1127 4885 : void
1128 : nsINode::ChangeEditableDescendantCount(int32_t aDelta)
1129 0 : {
1130 : if (aDelta == 0) {
1131 : return;
1132 : }
1133 0 :
1134 0 : nsSlots* s = Slots();
1135 : MOZ_ASSERT(aDelta > 0 ||
1136 0 : s->mEditableDescendantCount >= (uint32_t) (-1 * aDelta));
1137 : s->mEditableDescendantCount += aDelta;
1138 : }
1139 :
1140 700 : void
1141 : nsINode::ResetEditableDescendantCount()
1142 700 : {
1143 0 : nsSlots* s = GetExistingSlots();
1144 517 : if (s) {
1145 : s->mEditableDescendantCount = 0;
1146 700 : }
1147 : }
1148 :
1149 9830 : uint32_t
1150 : nsINode::EditableDescendantCount()
1151 9830 : {
1152 9830 : nsSlots* s = GetExistingSlots();
1153 4610 : if (s) {
1154 : return s->mEditableDescendantCount;
1155 : }
1156 : return 0;
1157 : }
1158 :
1159 0 : bool
1160 : nsINode::UnoptimizableCCNode() const
1161 : {
1162 : const uintptr_t problematicFlags = (NODE_IS_ANONYMOUS_ROOT |
1163 : NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE |
1164 0 : NODE_IS_NATIVE_ANONYMOUS_ROOT |
1165 0 : NODE_MAY_BE_IN_BINDING_MNGR);
1166 0 : return HasFlag(problematicFlags) ||
1167 : NodeType() == ATTRIBUTE_NODE ||
1168 0 : // For strange cases like xbl:content/xbl:children
1169 0 : (IsElement() &&
1170 : AsElement()->IsInNamespace(kNameSpaceID_XBL));
1171 : }
1172 :
1173 : /* static */
1174 5732 : bool
1175 : nsINode::Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb)
1176 11464 : {
1177 0 : if (MOZ_LIKELY(!cb.WantAllTraces())) {
1178 0 : nsIDocument* currentDoc = tmp->GetComposedDoc();
1179 0 : if (currentDoc &&
1180 : nsCCUncollectableMarker::InGeneration(currentDoc->GetMarkedCCGeneration())) {
1181 : return false;
1182 : }
1183 0 :
1184 : if (nsCCUncollectableMarker::sGeneration) {
1185 0 : // If we're black no need to traverse.
1186 : if (tmp->HasKnownLiveWrapper() || tmp->InCCBlackTree()) {
1187 : return false;
1188 : }
1189 0 :
1190 : if (!tmp->UnoptimizableCCNode()) {
1191 0 : // If we're in a black document, return early.
1192 : if ((currentDoc && currentDoc->HasKnownLiveWrapper())) {
1193 : return false;
1194 : }
1195 : // If we're not in anonymous content and we have a black parent,
1196 0 : // return early.
1197 0 : nsIContent* parent = tmp->GetParent();
1198 0 : if (parent && !parent->UnoptimizableCCNode() &&
1199 0 : parent->HasKnownLiveWrapper()) {
1200 : MOZ_ASSERT(parent->ComputeIndexOf(tmp) >= 0, "Parent doesn't own us?");
1201 : return false;
1202 : }
1203 : }
1204 : }
1205 : }
1206 5732 :
1207 5732 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfo)
1208 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(GetParent())
1209 5732 :
1210 0 : nsSlots *slots = tmp->GetExistingSlots();
1211 0 : if (slots) {
1212 : slots->Traverse(cb);
1213 : }
1214 5732 :
1215 : if (tmp->HasProperties()) {
1216 1 : nsCOMArray<nsISupports>* objects =
1217 1 : static_cast<nsCOMArray<nsISupports>*>(tmp->GetProperty(nsGkAtoms::keepobjectsalive));
1218 0 : if (objects) {
1219 0 : for (int32_t i = 0; i < objects->Count(); ++i) {
1220 : cb.NoteXPCOMChild(objects->ObjectAt(i));
1221 : }
1222 : }
1223 :
1224 : #ifdef ACCESSIBILITY
1225 0 : AccessibleNode* anode =
1226 1 : static_cast<AccessibleNode*>(tmp->GetProperty(nsGkAtoms::accessiblenode));
1227 0 : if (anode) {
1228 : cb.NoteXPCOMChild(anode);
1229 : }
1230 : #endif
1231 : }
1232 0 :
1233 0 : if (tmp->NodeType() != DOCUMENT_NODE &&
1234 158 : tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) {
1235 : nsContentUtils::TraverseListenerManager(tmp, cb);
1236 : }
1237 :
1238 : return true;
1239 : }
1240 :
1241 : /* static */
1242 0 : void
1243 : nsINode::Unlink(nsINode* tmp)
1244 0 : {
1245 : tmp->ReleaseWrapper(tmp);
1246 0 :
1247 0 : nsSlots *slots = tmp->GetExistingSlots();
1248 0 : if (slots) {
1249 : slots->Unlink();
1250 : }
1251 0 :
1252 0 : if (tmp->NodeType() != DOCUMENT_NODE &&
1253 0 : tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) {
1254 0 : nsContentUtils::RemoveListenerManager(tmp);
1255 : tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER);
1256 : }
1257 0 :
1258 0 : if (tmp->HasProperties()) {
1259 0 : tmp->DeleteProperty(nsGkAtoms::keepobjectsalive);
1260 : tmp->DeleteProperty(nsGkAtoms::accessiblenode);
1261 0 : }
1262 : }
1263 :
1264 0 : static void
1265 : AdoptNodeIntoOwnerDoc(nsINode *aParent, nsINode *aNode, ErrorResult& aError)
1266 0 : {
1267 : NS_ASSERTION(!aNode->GetParentNode(),
1268 : "Should have removed from parent already");
1269 0 :
1270 : nsIDocument *doc = aParent->OwnerDoc();
1271 0 :
1272 : DebugOnly<nsINode*> adoptedNode = doc->AdoptNode(*aNode, aError);
1273 :
1274 0 : #ifdef DEBUG
1275 0 : if (!aError.Failed()) {
1276 : MOZ_ASSERT(aParent->OwnerDoc() == doc,
1277 0 : "ownerDoc chainged while adopting");
1278 0 : MOZ_ASSERT(adoptedNode == aNode, "Uh, adopt node changed nodes?");
1279 : MOZ_ASSERT(aParent->OwnerDoc() == aNode->OwnerDoc(),
1280 : "ownerDocument changed again after adopting!");
1281 : }
1282 0 : #endif // DEBUG
1283 : }
1284 :
1285 0 : static void
1286 : CheckForOutdatedParent(nsINode* aParent, nsINode* aNode, ErrorResult& aError)
1287 0 : {
1288 0 : if (JSObject* existingObjUnrooted = aNode->GetWrapper()) {
1289 : JS::Rooted<JSObject*> existingObj(RootingCx(), existingObjUnrooted);
1290 0 :
1291 0 : AutoJSContext cx;
1292 0 : nsIGlobalObject* global = aParent->OwnerDoc()->GetScopeObject();
1293 : MOZ_ASSERT(global);
1294 0 :
1295 0 : if (js::GetGlobalForObjectCrossCompartment(existingObj) !=
1296 0 : global->GetGlobalJSObject()) {
1297 0 : JSAutoRealm ar(cx, existingObj);
1298 : ReparentWrapper(cx, existingObj, aError);
1299 : }
1300 0 : }
1301 : }
1302 :
1303 8591 : static nsresult
1304 : ReparentWrappersInSubtree(nsIContent* aRoot)
1305 : {
1306 8591 : MOZ_ASSERT(ShouldUseXBLScope(aRoot));
1307 8591 : // Start off with no global so we don't fire any error events on failure.
1308 : AutoJSAPI jsapi;
1309 : jsapi.Init();
1310 :
1311 0 : JSContext* cx = jsapi.cx();
1312 :
1313 : nsIGlobalObject* docGlobal = aRoot->OwnerDoc()->GetScopeObject();
1314 8591 : if (NS_WARN_IF(!docGlobal)) {
1315 17182 : return NS_ERROR_UNEXPECTED;
1316 : }
1317 8591 :
1318 0 : JS::Rooted<JSObject*> rootedGlobal(cx, docGlobal->GetGlobalJSObject());
1319 0 : if (NS_WARN_IF(!rootedGlobal)) {
1320 : return NS_ERROR_UNEXPECTED;
1321 : }
1322 :
1323 : rootedGlobal = xpc::GetXBLScope(cx, rootedGlobal);
1324 0 :
1325 0 : ErrorResult rv;
1326 0 : JS::Rooted<JSObject*> reflector(cx);
1327 : for (nsIContent* cur = aRoot; cur; cur = cur->GetNextNode(aRoot)) {
1328 17182 : if ((reflector = cur->GetWrapper())) {
1329 0 : JSAutoRealm ar(cx, reflector);
1330 0 : ReparentWrapper(cx, reflector, rv);
1331 : rv.WouldReportJSException();
1332 : if (rv.Failed()) {
1333 : // We _could_ consider BlastSubtreeToPieces here, but it's not really
1334 : // needed. Having some nodes in here accessible to content while others
1335 0 : // are not is probably OK. We just need to fail out of the actual
1336 0 : // insertion, so they're not in the DOM. Returning a failure here will
1337 0 : // do that.
1338 : return rv.StealNSResult();
1339 : }
1340 : }
1341 0 : }
1342 1 :
1343 8591 : return NS_OK;
1344 : }
1345 8591 :
1346 0 : nsresult
1347 0 : nsINode::doInsertChildAt(nsIContent* aKid, uint32_t aIndex,
1348 0 : bool aNotify, nsAttrAndChildArray& aChildArray)
1349 : {
1350 : MOZ_ASSERT(!aKid->GetParentNode(), "Inserting node that already has parent");
1351 0 : MOZ_ASSERT(!IsAttr());
1352 :
1353 0 : // The id-handling code, and in the future possibly other code, need to
1354 8460 : // react to unexpected attribute changes.
1355 17182 : nsMutationGuard::DidMutate();
1356 0 :
1357 0 : // Do this before checking the child-count since this could cause mutations
1358 0 : nsIDocument* doc = GetUncomposedDoc();
1359 : mozAutoDocUpdate updateBatch(GetComposedDoc(), aNotify);
1360 0 :
1361 0 : if (OwnerDoc() != aKid->OwnerDoc()) {
1362 0 : ErrorResult error;
1363 : AdoptNodeIntoOwnerDoc(this, aKid, error);
1364 :
1365 : // Need to WouldReportJSException() if our callee can throw a JS
1366 1 : // exception (which it can) and we're neither propagating the
1367 : // error out nor unconditionally suppressing it.
1368 8591 : error.WouldReportJSException();
1369 : if (NS_WARN_IF(error.Failed())) {
1370 : return error.StealNSResult();
1371 0 : }
1372 : } else if (OwnerDoc()->DidDocumentOpen()) {
1373 : ErrorResult error;
1374 90 : CheckForOutdatedParent(this, aKid, error);
1375 61 :
1376 : // Need to WouldReportJSException() if our callee can throw a JS
1377 29 : // exception (which it can) and we're neither propagating the
1378 : // error out nor unconditionally suppressing it.
1379 : error.WouldReportJSException();
1380 0 : if (NS_WARN_IF(error.Failed())) {
1381 : return error.StealNSResult();
1382 0 : }
1383 0 : }
1384 :
1385 0 : uint32_t childCount = aChildArray.ChildCount();
1386 0 : NS_ENSURE_TRUE(aIndex <= childCount, NS_ERROR_ILLEGAL_VALUE);
1387 : bool isAppend = (aIndex == childCount);
1388 :
1389 : nsresult rv = aChildArray.InsertChildAt(aKid, aIndex);
1390 : NS_ENSURE_SUCCESS(rv, rv);
1391 : if (aIndex == 0) {
1392 : mFirstChild = aKid;
1393 : }
1394 0 :
1395 : nsIContent* parent = IsContent() ? AsContent() : nullptr;
1396 0 :
1397 0 : bool wasInXBLScope = ShouldUseXBLScope(aKid);
1398 0 : rv = aKid->BindToTree(doc, parent,
1399 0 : parent ? parent->GetBindingParent() : nullptr,
1400 : true);
1401 0 : if (NS_SUCCEEDED(rv) && !wasInXBLScope && ShouldUseXBLScope(aKid)) {
1402 : MOZ_ASSERT(ShouldUseXBLScope(this),
1403 : "Why does the kid need to use an XBL scope?");
1404 : rv = ReparentWrappersInSubtree(aKid);
1405 : }
1406 : if (NS_FAILED(rv)) {
1407 : if (GetFirstChild() == aKid) {
1408 4 : mFirstChild = aKid->GetNextSibling();
1409 : }
1410 4 : aChildArray.RemoveChildAt(aIndex);
1411 4 : aKid->UnbindFromTree();
1412 4 : return rv;
1413 0 : }
1414 :
1415 0 : // Invalidate cached array of child nodes
1416 : InvalidateChildNodes();
1417 :
1418 : NS_ASSERTION(aKid->GetParentNode() == this,
1419 : "Did we run script inappropriately?");
1420 :
1421 : if (aNotify) {
1422 0 : // Note that we always want to call ContentInserted when things are added
1423 : // as kids to documents
1424 : if (parent && isAppend) {
1425 0 : nsNodeUtils::ContentAppended(parent, aKid);
1426 0 : } else {
1427 0 : nsNodeUtils::ContentInserted(this, aKid);
1428 : }
1429 :
1430 0 : if (nsContentUtils::HasMutationListeners(aKid,
1431 : NS_EVENT_BITS_MUTATION_NODEINSERTED, this)) {
1432 0 : InternalMutationEvent mutation(true, eLegacyNodeInserted);
1433 0 : mutation.mRelatedNode = this;
1434 :
1435 : mozAutoSubtreeModified subtree(OwnerDoc(), this);
1436 0 : (new AsyncEventDispatcher(aKid, mutation))->RunDOMEventWhenSafe();
1437 : }
1438 : }
1439 :
1440 : return NS_OK;
1441 : }
1442 :
1443 : Element*
1444 : nsINode::GetPreviousElementSibling() const
1445 0 : {
1446 : nsIContent* previousSibling = GetPreviousSibling();
1447 : while (previousSibling) {
1448 : if (previousSibling->IsElement()) {
1449 0 : return previousSibling->AsElement();
1450 0 : }
1451 : previousSibling = previousSibling->GetPreviousSibling();
1452 : }
1453 0 :
1454 : return nullptr;
1455 0 : }
1456 0 :
1457 0 : Element*
1458 0 : nsINode::GetNextElementSibling() const
1459 0 : {
1460 : nsIContent* nextSibling = GetNextSibling();
1461 : while (nextSibling) {
1462 : if (nextSibling->IsElement()) {
1463 0 : return nextSibling->AsElement();
1464 : }
1465 : nextSibling = nextSibling->GetNextSibling();
1466 : }
1467 0 :
1468 : return nullptr;
1469 : }
1470 0 :
1471 0 : static already_AddRefed<nsINode>
1472 0 : GetNodeFromNodeOrString(const OwningNodeOrString& aNode,
1473 : nsIDocument* aDocument)
1474 : {
1475 0 : if (aNode.IsNode()) {
1476 : nsCOMPtr<nsINode> node = aNode.GetAsNode();
1477 : return node.forget();
1478 0 : }
1479 :
1480 : if (aNode.IsString()){
1481 0 : RefPtr<nsTextNode> textNode =
1482 0 : aDocument->CreateTextNode(aNode.GetAsString());
1483 : return textNode.forget();
1484 0 : }
1485 0 :
1486 : MOZ_CRASH("Impossible type");
1487 0 : }
1488 :
1489 : /**
1490 : * Implement the algorithm specified at
1491 : * https://dom.spec.whatwg.org/#converting-nodes-into-a-node for |prepend()|,
1492 : * |append()|, |before()|, |after()|, and |replaceWith()| APIs.
1493 0 : */
1494 : MOZ_CAN_RUN_SCRIPT static already_AddRefed<nsINode>
1495 : ConvertNodesOrStringsIntoNode(const Sequence<OwningNodeOrString>& aNodes,
1496 : nsIDocument* aDocument,
1497 0 : ErrorResult& aRv)
1498 : {
1499 : if (aNodes.Length() == 1) {
1500 0 : return GetNodeFromNodeOrString(aNodes[0], aDocument);
1501 0 : }
1502 :
1503 0 : nsCOMPtr<nsINode> fragment = aDocument->CreateDocumentFragment();
1504 0 :
1505 : for (const auto& node : aNodes) {
1506 0 : nsCOMPtr<nsINode> childNode = GetNodeFromNodeOrString(node, aDocument);
1507 : fragment->AppendChild(*childNode, aRv);
1508 : if (aRv.Failed()) {
1509 : return nullptr;
1510 : }
1511 : }
1512 0 :
1513 : return fragment.forget();
1514 : }
1515 :
1516 0 : static void
1517 : InsertNodesIntoHashset(const Sequence<OwningNodeOrString>& aNodes,
1518 : nsTHashtable<nsPtrHashKey<nsINode>>& aHashset)
1519 0 : {
1520 0 : for (const auto& node : aNodes) {
1521 0 : if (node.IsNode()) {
1522 : aHashset.PutEntry(node.GetAsNode());
1523 : }
1524 : }
1525 0 : }
1526 :
1527 0 : static nsINode*
1528 0 : FindViablePreviousSibling(const nsINode& aNode,
1529 0 : const Sequence<OwningNodeOrString>& aNodes)
1530 0 : {
1531 : nsTHashtable<nsPtrHashKey<nsINode>> nodeSet(16);
1532 : InsertNodesIntoHashset(aNodes, nodeSet);
1533 :
1534 0 : nsINode* viablePreviousSibling = nullptr;
1535 : for (nsINode* sibling = aNode.GetPreviousSibling(); sibling;
1536 0 : sibling = sibling->GetPreviousSibling()) {
1537 : if (!nodeSet.Contains(sibling)) {
1538 : viablePreviousSibling = sibling;
1539 : break;
1540 0 : }
1541 : }
1542 :
1543 0 : return viablePreviousSibling;
1544 0 : }
1545 0 :
1546 : static nsINode*
1547 : FindViableNextSibling(const nsINode& aNode,
1548 0 : const Sequence<OwningNodeOrString>& aNodes)
1549 : {
1550 0 : nsTHashtable<nsPtrHashKey<nsINode>> nodeSet(16);
1551 0 : InsertNodesIntoHashset(aNodes, nodeSet);
1552 0 :
1553 0 : nsINode* viableNextSibling = nullptr;
1554 : for (nsINode* sibling = aNode.GetNextSibling(); sibling;
1555 : sibling = sibling->GetNextSibling()) {
1556 0 : if (!nodeSet.Contains(sibling)) {
1557 : viableNextSibling = sibling;
1558 : break;
1559 : }
1560 0 : }
1561 :
1562 : return viableNextSibling;
1563 0 : }
1564 0 :
1565 0 : void
1566 : nsINode::Before(const Sequence<OwningNodeOrString>& aNodes,
1567 : ErrorResult& aRv)
1568 0 : {
1569 : nsCOMPtr<nsINode> parent = GetParentNode();
1570 0 : if (!parent) {
1571 0 : return;
1572 0 : }
1573 0 :
1574 : nsCOMPtr<nsINode> viablePreviousSibling =
1575 : FindViablePreviousSibling(*this, aNodes);
1576 0 :
1577 0 : nsCOMPtr<nsIDocument> doc = OwnerDoc();
1578 : nsCOMPtr<nsINode> node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv);
1579 0 : if (aRv.Failed()) {
1580 : return;
1581 : }
1582 :
1583 : viablePreviousSibling = viablePreviousSibling ?
1584 0 : viablePreviousSibling->GetNextSibling() : parent->GetFirstChild();
1585 :
1586 2 : parent->InsertBefore(*node, viablePreviousSibling, aRv);
1587 1 : }
1588 0 :
1589 : void
1590 : nsINode::After(const Sequence<OwningNodeOrString>& aNodes,
1591 0 : ErrorResult& aRv)
1592 : {
1593 : nsCOMPtr<nsINode> parent = GetParentNode();
1594 : if (!parent) {
1595 0 : return;
1596 : }
1597 0 :
1598 0 : nsCOMPtr<nsINode> viableNextSibling = FindViableNextSibling(*this, aNodes);
1599 0 :
1600 0 : nsCOMPtr<nsIDocument> doc = OwnerDoc();
1601 0 : nsCOMPtr<nsINode> node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv);
1602 : if (aRv.Failed()) {
1603 : return;
1604 : }
1605 :
1606 : parent->InsertBefore(*node, viableNextSibling, aRv);
1607 : }
1608 :
1609 0 : void
1610 : nsINode::ReplaceWith(const Sequence<OwningNodeOrString>& aNodes,
1611 0 : ErrorResult& aRv)
1612 0 : {
1613 0 : nsCOMPtr<nsINode> parent = GetParentNode();
1614 0 : if (!parent) {
1615 0 : return;
1616 : }
1617 :
1618 : nsCOMPtr<nsINode> viableNextSibling = FindViableNextSibling(*this, aNodes);
1619 :
1620 : nsCOMPtr<nsIDocument> doc = OwnerDoc();
1621 : nsCOMPtr<nsINode> node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv);
1622 : if (aRv.Failed()) {
1623 0 : return;
1624 : }
1625 :
1626 0 : if (parent == GetParentNode()) {
1627 0 : parent->ReplaceChild(*node, *this, aRv);
1628 0 : } else {
1629 0 : parent->InsertBefore(*node, viableNextSibling, aRv);
1630 : }
1631 : }
1632 0 :
1633 0 : void
1634 : nsINode::Remove()
1635 : {
1636 : nsCOMPtr<nsINode> parent = GetParentNode();
1637 0 : if (!parent) {
1638 : return;
1639 : }
1640 0 :
1641 0 : parent->RemoveChild(*this, IgnoreErrors());
1642 0 : }
1643 0 :
1644 : Element*
1645 : nsINode::GetFirstElementChild() const
1646 0 : {
1647 : for (nsIContent* child = GetFirstChild();
1648 : child;
1649 : child = child->GetNextSibling()) {
1650 5 : if (child->IsElement()) {
1651 : return child->AsElement();
1652 : }
1653 : }
1654 :
1655 : return nullptr;
1656 : }
1657 :
1658 5 : Element*
1659 : nsINode::GetLastElementChild() const
1660 : {
1661 5 : for (nsIContent* child = GetLastChild();
1662 : child;
1663 0 : child = child->GetPreviousSibling()) {
1664 10 : if (child->IsElement()) {
1665 : return child->AsElement();
1666 0 : }
1667 : }
1668 0 :
1669 0 : return nullptr;
1670 : }
1671 :
1672 5 : void
1673 : nsINode::Prepend(const Sequence<OwningNodeOrString>& aNodes,
1674 : ErrorResult& aRv)
1675 5 : {
1676 : nsCOMPtr<nsIDocument> doc = OwnerDoc();
1677 0 : nsCOMPtr<nsINode> node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv);
1678 5 : if (aRv.Failed()) {
1679 : return;
1680 : }
1681 5 :
1682 0 : nsCOMPtr<nsINode> refNode = mFirstChild;
1683 : InsertBefore(*node, refNode, aRv);
1684 : }
1685 :
1686 : void
1687 : nsINode::Append(const Sequence<OwningNodeOrString>& aNodes,
1688 65 : ErrorResult& aRv)
1689 : {
1690 : nsCOMPtr<nsIDocument> doc = OwnerDoc();
1691 65 : nsCOMPtr<nsINode> node = ConvertNodesOrStringsIntoNode(aNodes, doc, aRv);
1692 65 : if (aRv.Failed()) {
1693 0 : return;
1694 130 : }
1695 :
1696 : AppendChild(*node, aRv);
1697 : }
1698 :
1699 : void
1700 : nsINode::doRemoveChildAt(uint32_t aIndex, bool aNotify,
1701 : nsIContent* aKid, nsAttrAndChildArray& aChildArray)
1702 : {
1703 : // NOTE: This function must not trigger any calls to
1704 195 : // nsIDocument::GetRootElement() calls until *after* it has removed aKid from
1705 125 : // aChildArray. Any calls before then could potentially restore a stale
1706 : // value for our cached root element, per note in
1707 : // nsDocument::RemoveChildNode().
1708 : MOZ_ASSERT(aKid && aKid->GetParentNode() == this &&
1709 0 : aKid == GetChildAt_Deprecated(aIndex) &&
1710 0 : ComputeIndexOf(aKid) == (int32_t)aIndex, "Bogus aKid");
1711 5 : MOZ_ASSERT(!IsAttr());
1712 :
1713 : nsMutationGuard::DidMutate();
1714 : mozAutoDocUpdate updateBatch(GetComposedDoc(), aNotify);
1715 :
1716 : nsIContent* previousSibling = aKid->GetPreviousSibling();
1717 65 :
1718 : if (GetFirstChild() == aKid) {
1719 : mFirstChild = aKid->GetNextSibling();
1720 : }
1721 :
1722 : aChildArray.RemoveChildAt(aIndex);
1723 :
1724 : // Invalidate cached array of child nodes
1725 : InvalidateChildNodes();
1726 0 :
1727 : if (aNotify) {
1728 : nsNodeUtils::ContentRemoved(this, aKid, previousSibling);
1729 65 : }
1730 :
1731 : aKid->UnbindFromTree();
1732 : }
1733 :
1734 0 : // When replacing, aRefChild is the content being replaced; when
1735 0 : // inserting it's the content before which we're inserting. In the
1736 0 : // latter case it may be null.
1737 : static
1738 : bool IsAllowedAsChild(nsIContent* aNewChild, nsINode* aParent,
1739 0 : bool aIsReplace, nsINode* aRefChild)
1740 : {
1741 : MOZ_ASSERT(aNewChild, "Must have new child");
1742 : MOZ_ASSERT_IF(aIsReplace, aRefChild);
1743 : MOZ_ASSERT(aParent);
1744 0 : MOZ_ASSERT(aParent->IsDocument() ||
1745 : aParent->IsDocumentFragment() ||
1746 : aParent->IsElement(),
1747 : "Nodes that are not documents, document fragments or elements "
1748 : "can't be parents!");
1749 0 :
1750 0 : // A common case is that aNewChild has no kids, in which case
1751 : // aParent can't be a descendant of aNewChild unless they're
1752 : // actually equal to each other. Fast-path that case, since aParent
1753 : // could be pretty deep in the DOM tree.
1754 : if (aNewChild == aParent ||
1755 0 : ((aNewChild->GetFirstChild() ||
1756 0 : // HTML template elements and ShadowRoot hosts need
1757 : // to be checked to ensure that they are not inserted into
1758 : // the hosted content.
1759 : aNewChild->NodeInfo()->NameAtom() == nsGkAtoms::_template ||
1760 : aNewChild->GetShadowRoot()) &&
1761 0 : nsContentUtils::ContentIsHostIncludingDescendantOf(aParent,
1762 : aNewChild))) {
1763 : return false;
1764 : }
1765 :
1766 0 : // The allowed child nodes differ for documents and elements
1767 : switch (aNewChild->NodeType()) {
1768 : case nsINode::COMMENT_NODE :
1769 : case nsINode::PROCESSING_INSTRUCTION_NODE :
1770 : // OK in both cases
1771 0 : return true;
1772 0 : case nsINode::TEXT_NODE :
1773 0 : case nsINode::CDATA_SECTION_NODE :
1774 : case nsINode::ENTITY_REFERENCE_NODE :
1775 0 : // Allowed under Elements and DocumentFragments
1776 : return aParent->NodeType() != nsINode::DOCUMENT_NODE;
1777 : case nsINode::ELEMENT_NODE :
1778 : {
1779 : if (!aParent->IsDocument()) {
1780 0 : // Always ok to have elements under other elements or document fragments
1781 0 : return true;
1782 : }
1783 :
1784 : nsIDocument* parentDocument = aParent->AsDocument();
1785 : Element* rootElement = parentDocument->GetRootElement();
1786 0 : if (rootElement) {
1787 : // Already have a documentElement, so this is only OK if we're
1788 : // replacing it.
1789 : return aIsReplace && rootElement == aRefChild;
1790 : }
1791 0 :
1792 0 : // We don't have a documentElement yet. Our one remaining constraint is
1793 : // that the documentElement must come after the doctype.
1794 : if (!aRefChild) {
1795 : // Appending is just fine.
1796 : return true;
1797 0 : }
1798 :
1799 : nsIContent* docTypeContent = parentDocument->GetDoctype();
1800 : if (!docTypeContent) {
1801 : // It's all good.
1802 : return true;
1803 : }
1804 :
1805 : int32_t doctypeIndex = aParent->ComputeIndexOf(docTypeContent);
1806 0 : int32_t insertIndex = aParent->ComputeIndexOf(aRefChild);
1807 :
1808 : // Now we're OK in the following two cases only:
1809 : // 1) We're replacing something that's not before the doctype
1810 : // 2) We're inserting before something that comes after the doctype
1811 0 : return aIsReplace ? (insertIndex >= doctypeIndex) :
1812 0 : insertIndex > doctypeIndex;
1813 0 : }
1814 0 : case nsINode::DOCUMENT_TYPE_NODE :
1815 0 : {
1816 0 : if (!aParent->IsDocument()) {
1817 : // doctypes only allowed under documents
1818 : return false;
1819 : }
1820 :
1821 : nsIDocument* parentDocument = aParent->AsDocument();
1822 : nsIContent* docTypeContent = parentDocument->GetDoctype();
1823 : if (docTypeContent) {
1824 0 : // Already have a doctype, so this is only OK if we're replacing it
1825 : return aIsReplace && docTypeContent == aRefChild;
1826 : }
1827 :
1828 : // We don't have a doctype yet. Our one remaining constraint is
1829 : // that the doctype must come before the documentElement.
1830 : Element* rootElement = parentDocument->GetRootElement();
1831 : if (!rootElement) {
1832 : // It's all good
1833 : return true;
1834 : }
1835 :
1836 : if (!aRefChild) {
1837 : // Trying to append a doctype, but have a documentElement
1838 : return false;
1839 0 : }
1840 :
1841 : int32_t rootIndex = aParent->ComputeIndexOf(rootElement);
1842 : int32_t insertIndex = aParent->ComputeIndexOf(aRefChild);
1843 0 :
1844 : // Now we're OK if and only if insertIndex <= rootIndex. Indeed, either
1845 : // we end up replacing aRefChild or we end up before it. Either one is
1846 0 : // ok as long as aRefChild is not after rootElement.
1847 0 : return insertIndex <= rootIndex;
1848 : }
1849 : case nsINode::DOCUMENT_FRAGMENT_NODE :
1850 0 : {
1851 : // Note that for now we only allow nodes inside document fragments if
1852 : // they're allowed inside elements. If we ever change this to allow
1853 : // doctype nodes in document fragments, we'll need to update this code.
1854 65 : // Also, there's a version of this code in ReplaceOrInsertBefore. If you
1855 : // change this code, change that too.
1856 : if (!aParent->IsDocument()) {
1857 195 : // All good here
1858 65 : return true;
1859 0 : }
1860 0 :
1861 : bool sawElement = false;
1862 : for (nsIContent* child = aNewChild->GetFirstChild();
1863 : child;
1864 : child = child->GetNextSibling()) {
1865 0 : if (child->IsElement()) {
1866 : if (sawElement) {
1867 : // Can't put two elements into a document
1868 65 : return false;
1869 65 : }
1870 : sawElement = true;
1871 : }
1872 : // If we can put this content at the the right place, we might be ok;
1873 0 : // if not, we bail out.
1874 0 : if (!IsAllowedAsChild(child, aParent, aIsReplace, aRefChild)) {
1875 : return false;
1876 : }
1877 : }
1878 0 :
1879 0 : // Everything in the fragment checked out ok, so we can stick it in here
1880 0 : return true;
1881 : }
1882 : default:
1883 : /*
1884 : * aNewChild is of invalid type.
1885 0 : */
1886 : break;
1887 : }
1888 :
1889 : return false;
1890 : }
1891 :
1892 : void
1893 65 : nsINode::EnsurePreInsertionValidity(nsINode& aNewChild, nsINode* aRefChild,
1894 : ErrorResult& aError)
1895 65 : {
1896 130 : EnsurePreInsertionValidity1(aNewChild, aRefChild, aError);
1897 : if (aError.Failed()) {
1898 : return;
1899 : }
1900 0 : EnsurePreInsertionValidity2(false, aNewChild, aRefChild, aError);
1901 : }
1902 :
1903 : void
1904 : nsINode::EnsurePreInsertionValidity1(nsINode& aNewChild, nsINode* aRefChild,
1905 : ErrorResult& aError)
1906 : {
1907 : if ((!IsDocument() && !IsDocumentFragment() && !IsElement()) ||
1908 : !aNewChild.IsContent()) {
1909 : aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
1910 : return;
1911 : }
1912 : }
1913 :
1914 65 : void
1915 0 : nsINode::EnsurePreInsertionValidity2(bool aReplace, nsINode& aNewChild,
1916 0 : nsINode* aRefChild, ErrorResult& aError)
1917 : {
1918 : nsIContent* newContent = aNewChild.AsContent();
1919 : if (newContent->IsRootOfAnonymousSubtree()) {
1920 : // This is anonymous content. Don't allow its insertion
1921 0 : // anywhere, since it might have UnbindFromTree calls coming
1922 0 : // its way.
1923 : aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
1924 : return;
1925 : }
1926 :
1927 0 : // Make sure that the inserted node is allowed as a child of its new parent.
1928 65 : if (!IsAllowedAsChild(newContent, this, aReplace, aRefChild)) {
1929 2 : aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
1930 : return;
1931 : }
1932 : }
1933 :
1934 0 : nsINode*
1935 0 : nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
1936 : nsINode* aRefChild, ErrorResult& aError)
1937 : {
1938 65 : // XXXbz I wish I could assert that nsContentUtils::IsSafeToRunScript() so we
1939 0 : // could rely on scriptblockers going out of scope to actually run XBL
1940 0 : // teardown, but various crud adds nodes under scriptblockers (e.g. native
1941 : // anonymous content). The only good news is those insertions can't trigger
1942 : // the bad XBL cases.
1943 : MOZ_ASSERT_IF(aReplace, aRefChild);
1944 1 :
1945 1 : EnsurePreInsertionValidity1(*aNewChild, aRefChild, aError);
1946 : if (aError.Failed()) {
1947 : return nullptr;
1948 : }
1949 :
1950 : uint16_t nodeType = aNewChild->NodeType();
1951 65 :
1952 0 : // Before we do anything else, fire all DOMNodeRemoved mutation events
1953 : // We do this up front as to avoid having to deal with script running
1954 : // at random places further down.
1955 : // Scope firing mutation events so that we don't carry any state that
1956 0 : // might be stale
1957 : {
1958 : // This check happens again further down (though then using
1959 0 : // ComputeIndexOf).
1960 : // We're only checking this here to avoid firing mutation events when
1961 : // none should be fired.
1962 65 : // It's ok that we do the check twice in the case when firing mutation
1963 : // events as we need to recheck after running script anyway.
1964 : if (aRefChild && aRefChild->GetParentNode() != this) {
1965 65 : aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
1966 130 : return nullptr;
1967 0 : }
1968 2 :
1969 2 : // If we're replacing, fire for node-to-be-replaced.
1970 : // If aRefChild == aNewChild then we'll fire for it in check below
1971 0 : if (aReplace && aRefChild != aNewChild) {
1972 0 : nsContentUtils::MaybeFireNodeRemoved(aRefChild, this);
1973 0 : }
1974 :
1975 : // If the new node already has a parent, fire for removing from old
1976 : // parent
1977 1 : nsINode* oldParent = aNewChild->GetParentNode();
1978 : if (oldParent) {
1979 : nsContentUtils::MaybeFireNodeRemoved(aNewChild, oldParent);
1980 2 : }
1981 :
1982 : // If we're inserting a fragment, fire for all the children of the
1983 : // fragment
1984 : if (nodeType == DOCUMENT_FRAGMENT_NODE) {
1985 0 : static_cast<FragmentOrElement*>(aNewChild)->FireNodeRemovedForChildren();
1986 4 : }
1987 2 : // Verify that our aRefChild is still sensible
1988 2 : if (aRefChild && aRefChild->GetParentNode() != this) {
1989 2 : aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
1990 0 : return nullptr;
1991 0 : }
1992 : }
1993 :
1994 : EnsurePreInsertionValidity2(aReplace, *aNewChild, aRefChild, aError);
1995 : if (aError.Failed()) {
1996 0 : return nullptr;
1997 : }
1998 :
1999 : // Record the node to insert before, if any
2000 : nsINode* nodeToInsertBefore;
2001 0 : if (aReplace) {
2002 0 : nodeToInsertBefore = aRefChild->GetNextSibling();
2003 0 : } else {
2004 : nodeToInsertBefore = aRefChild;
2005 : }
2006 : if (nodeToInsertBefore == aNewChild) {
2007 0 : // We're going to remove aNewChild from its parent, so use its next sibling
2008 0 : // as the node to insert before.
2009 0 : nodeToInsertBefore = nodeToInsertBefore->GetNextSibling();
2010 : }
2011 :
2012 : Maybe<AutoTArray<nsCOMPtr<nsIContent>, 50> > fragChildren;
2013 0 :
2014 : // Remove the new child from the old parent if one exists
2015 : nsIContent* newContent = aNewChild->AsContent();
2016 0 : nsCOMPtr<nsINode> oldParent = newContent->GetParentNode();
2017 0 : if (oldParent) {
2018 0 : int32_t removeIndex = oldParent->ComputeIndexOf(newContent);
2019 : if (removeIndex < 0) {
2020 : // newContent is anonymous. We can't deal with this, so just bail
2021 0 : NS_ERROR("How come our flags didn't catch this?");
2022 0 : aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
2023 0 : return nullptr;
2024 0 : }
2025 :
2026 : // Hold a strong ref to nodeToInsertBefore across the removal of newContent
2027 0 : nsCOMPtr<nsINode> kungFuDeathGrip = nodeToInsertBefore;
2028 0 :
2029 : // Removing a child can run script, via XBL destructors.
2030 : nsMutationGuard guard;
2031 :
2032 : // Scope for the mutation batch and scriptblocker, so they go away
2033 : // while kungFuDeathGrip is still alive.
2034 63 : {
2035 : mozAutoDocUpdate batch(newContent->GetComposedDoc(), true);
2036 : nsAutoMutationBatch mb(oldParent, true, true);
2037 : oldParent->RemoveChildAt_Deprecated(removeIndex, true);
2038 : if (nsAutoMutationBatch::GetCurrentBatch() == &mb) {
2039 0 : mb.RemovalDone();
2040 : mb.SetPrevSibling(oldParent->GetChildAt_Deprecated(removeIndex - 1));
2041 0 : mb.SetNextSibling(oldParent->GetChildAt_Deprecated(removeIndex));
2042 : }
2043 : }
2044 :
2045 0 : // We expect one mutation (the removal) to have happened.
2046 0 : if (guard.Mutated(1)) {
2047 0 : // XBL destructors, yuck.
2048 0 :
2049 0 : // Verify that nodeToInsertBefore, if non-null, is still our child. If
2050 : // it's not, there's no way we can do this insert sanely; just bail out.
2051 0 : if (nodeToInsertBefore && nodeToInsertBefore->GetParent() != this) {
2052 : aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
2053 : return nullptr;
2054 : }
2055 0 :
2056 : // Verify that newContent has no parent.
2057 0 : if (newContent->GetParentNode()) {
2058 : aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
2059 : return nullptr;
2060 : }
2061 :
2062 0 : // And verify that newContent is still allowed as our child.
2063 0 : if (aNewChild == aRefChild) {
2064 : // We've already removed aRefChild. So even if we were doing a replace,
2065 0 : // now we're doing a simple insert before nodeToInsertBefore.
2066 0 : if (!IsAllowedAsChild(newContent, this, false, nodeToInsertBefore)) {
2067 : aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
2068 : return nullptr;
2069 : }
2070 : } else {
2071 0 : if ((aRefChild && aRefChild->GetParent() != this) ||
2072 : !IsAllowedAsChild(newContent, this, aReplace, aRefChild)) {
2073 : aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
2074 : return nullptr;
2075 : }
2076 0 : // And recompute nodeToInsertBefore, just in case.
2077 0 : if (aReplace) {
2078 0 : nodeToInsertBefore = aRefChild->GetNextSibling();
2079 : } else {
2080 : nodeToInsertBefore = aRefChild;
2081 : }
2082 0 : }
2083 0 : }
2084 0 : } else if (nodeType == DOCUMENT_FRAGMENT_NODE) {
2085 0 : // Make sure to remove all the fragment's kids. We need to do this before
2086 : // we start inserting anything, so we will run out XBL destructors and
2087 : // binding teardown (GOD, I HATE THESE THINGS) before we insert anything
2088 : // into the DOM.
2089 : uint32_t count = newContent->GetChildCount();
2090 :
2091 : fragChildren.emplace();
2092 :
2093 : // Copy the children into a separate array to avoid having to deal with
2094 : // mutations to the fragment later on here.
2095 0 : fragChildren->SetCapacity(count);
2096 0 : for (nsIContent* child = newContent->GetFirstChild();
2097 0 : child;
2098 : child = child->GetNextSibling()) {
2099 : NS_ASSERTION(child->GetComposedDoc() == nullptr,
2100 : "How did we get a child with a current doc?");
2101 0 : fragChildren->AppendElement(child);
2102 0 : }
2103 :
2104 : // Hold a strong ref to nodeToInsertBefore across the removals
2105 : nsCOMPtr<nsINode> kungFuDeathGrip = nodeToInsertBefore;
2106 :
2107 : nsMutationGuard guard;
2108 :
2109 : // Scope for the mutation batch and scriptblocker, so they go away
2110 : // while kungFuDeathGrip is still alive.
2111 0 : {
2112 : mozAutoDocUpdate batch(newContent->GetComposedDoc(), true);
2113 0 : nsAutoMutationBatch mb(newContent, false, true);
2114 0 :
2115 0 : for (uint32_t i = count; i > 0;) {
2116 0 : newContent->RemoveChildAt_Deprecated(--i, true);
2117 : }
2118 0 : }
2119 0 :
2120 : // We expect |count| removals
2121 : if (guard.Mutated(count)) {
2122 : // XBL destructors, yuck.
2123 0 :
2124 0 : // Verify that nodeToInsertBefore, if non-null, is still our child. If
2125 0 : // it's not, there's no way we can do this insert sanely; just bail out.
2126 : if (nodeToInsertBefore && nodeToInsertBefore->GetParent() != this) {
2127 : aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
2128 : return nullptr;
2129 : }
2130 :
2131 : // Verify that all the things in fragChildren have no parent.
2132 130 : for (uint32_t i = 0; i < count; ++i) {
2133 130 : if (fragChildren->ElementAt(i)->GetParentNode()) {
2134 : aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
2135 : return nullptr;
2136 : }
2137 : }
2138 :
2139 : // Note that unlike the single-element case above, none of our kids can
2140 65 : // be aRefChild, so we can always pass through aReplace in the
2141 5 : // IsAllowedAsChild checks below and don't have to worry about whether
2142 5 : // recomputing nodeToInsertBefore is OK.
2143 :
2144 0 : // Verify that our aRefChild is still sensible
2145 0 : if (aRefChild && aRefChild->GetParent() != this) {
2146 : aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
2147 : return nullptr;
2148 : }
2149 1 :
2150 : // Recompute nodeToInsertBefore, just in case.
2151 : if (aReplace) {
2152 : nodeToInsertBefore = aRefChild->GetNextSibling();
2153 65 : } else {
2154 0 : nodeToInsertBefore = aRefChild;
2155 : }
2156 :
2157 : // And verify that newContent is still allowed as our child. Sadly, we
2158 0 : // need to reimplement the relevant part of IsAllowedAsChild() because
2159 : // now our nodes are in an array and all. If you change this code,
2160 : // change the code there.
2161 : if (IsDocument()) {
2162 : bool sawElement = false;
2163 0 : for (uint32_t i = 0; i < count; ++i) {
2164 0 : nsIContent* child = fragChildren->ElementAt(i);
2165 0 : if (child->IsElement()) {
2166 : if (sawElement) {
2167 : // No good
2168 : aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
2169 : return nullptr;
2170 : }
2171 : sawElement = true;
2172 : }
2173 65 : if (!IsAllowedAsChild(child, this, aReplace, aRefChild)) {
2174 65 : aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
2175 0 : return nullptr;
2176 0 : }
2177 : }
2178 : }
2179 0 : }
2180 0 : }
2181 0 :
2182 : mozAutoDocUpdate batch(GetComposedDoc(), true);
2183 : nsAutoMutationBatch mb;
2184 :
2185 : // Figure out which index we want to insert at. Note that we use
2186 : // nodeToInsertBefore to determine this, because it's possible that
2187 : // aRefChild == aNewChild, in which case we just removed it from the
2188 : // parent list.
2189 : int32_t insPos;
2190 : if (nodeToInsertBefore) {
2191 65 : insPos = ComputeIndexOf(nodeToInsertBefore);
2192 65 : if (insPos < 0) {
2193 0 : // XXXbz How the heck would _that_ happen, exactly?
2194 0 : aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
2195 : return nullptr;
2196 0 : }
2197 0 : }
2198 : else {
2199 0 : insPos = GetChildCount();
2200 0 : }
2201 :
2202 : // If we're replacing and we haven't removed aRefChild yet, do so now
2203 0 : if (aReplace && aRefChild != aNewChild) {
2204 0 : mb.Init(this, true, true);
2205 :
2206 : // Since aRefChild is never null in the aReplace case, we know that at
2207 : // this point nodeToInsertBefore is the next sibling of aRefChild.
2208 0 : NS_ASSERTION(aRefChild->GetNextSibling() == nodeToInsertBefore,
2209 0 : "Unexpected nodeToInsertBefore");
2210 :
2211 : // An since nodeToInsertBefore is at index insPos, we want to remove
2212 : // at the previous index.
2213 0 : NS_ASSERTION(insPos >= 1, "insPos too small");
2214 : RemoveChildAt_Deprecated(insPos-1, true);
2215 : --insPos;
2216 0 : }
2217 0 :
2218 0 : // Move new child over to our document if needed. Do this after removing
2219 : // it from its parent so that AdoptNode doesn't fire DOMNodeRemoved
2220 0 : // DocumentType nodes are the only nodes that can have a null
2221 : // ownerDocument according to the DOM spec, and we need to allow
2222 0 : // inserting them w/o calling AdoptNode().
2223 : nsIDocument* doc = OwnerDoc();
2224 : if (doc != newContent->OwnerDoc()) {
2225 : AdoptNodeIntoOwnerDoc(this, aNewChild, aError);
2226 : if (aError.Failed()) {
2227 : return nullptr;
2228 0 : }
2229 0 : } else if (doc->DidDocumentOpen()) {
2230 : CheckForOutdatedParent(this, aNewChild, aError);
2231 : if (aError.Failed()) {
2232 : return nullptr;
2233 0 : }
2234 : }
2235 0 :
2236 0 : /*
2237 0 : * Check if we're inserting a document fragment. If we are, we need
2238 : * to actually add its children individually (i.e. we don't add the
2239 : * actual document fragment).
2240 0 : */
2241 : nsINode* result = aReplace ? aRefChild : aNewChild;
2242 0 : if (nodeType == DOCUMENT_FRAGMENT_NODE) {
2243 : if (!aReplace) {
2244 : mb.Init(this, true, true);
2245 : }
2246 : nsAutoMutationBatch* mutationBatch = nsAutoMutationBatch::GetCurrentBatch();
2247 : if (mutationBatch) {
2248 : mutationBatch->RemovalDone();
2249 : mutationBatch->SetPrevSibling(GetChildAt_Deprecated(insPos - 1));
2250 : mutationBatch->SetNextSibling(GetChildAt_Deprecated(insPos));
2251 : }
2252 :
2253 : uint32_t count = fragChildren->Length();
2254 65 : if (!count) {
2255 0 : return result;
2256 0 : }
2257 0 :
2258 : bool appending = !IsDocument() && uint32_t(insPos) == GetChildCount();
2259 0 : nsIContent* firstInsertedContent = fragChildren->ElementAt(0);
2260 0 :
2261 : // Iterate through the fragment's children, and insert them in the new
2262 : // parent
2263 : for (uint32_t i = 0; i < count; ++i, ++insPos) {
2264 : // XXXbz how come no reparenting here? That seems odd...
2265 : // Insert the child.
2266 : aError = InsertChildAt_Deprecated(fragChildren->ElementAt(i), insPos,
2267 : !appending);
2268 : if (aError.Failed()) {
2269 1 : // Make sure to notify on any children that we did succeed to insert
2270 : if (appending && i != 0) {
2271 : nsNodeUtils::ContentAppended(static_cast<nsIContent*>(this),
2272 1 : firstInsertedContent);
2273 1 : }
2274 0 : return nullptr;
2275 1 : }
2276 1 : }
2277 :
2278 0 : if (mutationBatch && !appending) {
2279 0 : mutationBatch->NodesAdded();
2280 : }
2281 :
2282 0 : // Notify and fire mutation events when appending
2283 : if (appending) {
2284 : nsNodeUtils::ContentAppended(static_cast<nsIContent*>(this),
2285 0 : firstInsertedContent);
2286 0 : if (mutationBatch) {
2287 0 : mutationBatch->NodesAdded();
2288 : }
2289 0 : // Optimize for the case when there are no listeners
2290 : if (nsContentUtils::
2291 : HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEINSERTED)) {
2292 0 : Element::FireNodeInserted(doc, this, *fragChildren);
2293 : }
2294 : }
2295 0 : }
2296 : else {
2297 : // Not inserting a fragment but rather a single node.
2298 0 :
2299 0 : // FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=544654
2300 0 : // We need to reparent here for nodes for which the parent of their
2301 0 : // wrapper is not the wrapper for their ownerDocument (XUL elements,
2302 0 : // form controls, ...). Also applies in the fragment code above.
2303 :
2304 0 : if (nsAutoMutationBatch::GetCurrentBatch() == &mb) {
2305 0 : mb.RemovalDone();
2306 0 : mb.SetPrevSibling(GetChildAt_Deprecated(insPos - 1));
2307 : mb.SetNextSibling(GetChildAt_Deprecated(insPos));
2308 : }
2309 : aError = InsertChildAt_Deprecated(newContent, insPos, true);
2310 : if (aError.Failed()) {
2311 : return nullptr;
2312 : }
2313 : }
2314 :
2315 : return result;
2316 95 : }
2317 :
2318 95 : void
2319 95 : nsINode::BindObject(nsISupports* aObject)
2320 13 : {
2321 : nsCOMArray<nsISupports>* objects =
2322 : static_cast<nsCOMArray<nsISupports>*>(GetProperty(nsGkAtoms::keepobjectsalive));
2323 : if (!objects) {
2324 : objects = new nsCOMArray<nsISupports>();
2325 : SetProperty(nsGkAtoms::keepobjectsalive, objects,
2326 : nsINode::DeleteProperty< nsCOMArray<nsISupports> >, true);
2327 : }
2328 : objects->AppendObject(aObject);
2329 : }
2330 :
2331 95 : void
2332 : nsINode::UnbindObject(nsISupports* aObject)
2333 : {
2334 82 : nsCOMArray<nsISupports>* objects =
2335 : static_cast<nsCOMArray<nsISupports>*>(GetProperty(nsGkAtoms::keepobjectsalive));
2336 82 : if (objects) {
2337 82 : objects->RemoveObject(aObject);
2338 82 : }
2339 : }
2340 :
2341 : already_AddRefed<AccessibleNode>
2342 : nsINode::GetAccessibleNode()
2343 : {
2344 : #ifdef ACCESSIBILITY
2345 : nsresult rv = NS_OK;
2346 :
2347 : RefPtr<AccessibleNode> anode =
2348 : static_cast<AccessibleNode*>(GetProperty(nsGkAtoms::accessiblenode, &rv));
2349 : if (NS_FAILED(rv)) {
2350 : anode = new AccessibleNode(this);
2351 : RefPtr<AccessibleNode> temp = anode;
2352 : rv = SetProperty(nsGkAtoms::accessiblenode, temp.forget().take(),
2353 : nsPropertyTable::SupportsDtorFunc, true);
2354 : if (NS_FAILED(rv)) {
2355 : NS_WARNING("SetProperty failed");
2356 : return nullptr;
2357 : }
2358 : }
2359 : return anode.forget();
2360 : #else
2361 0 : return nullptr;
2362 : #endif
2363 0 : }
2364 :
2365 : void
2366 0 : nsINode::AddSizeOfExcludingThis(nsWindowSizes& aSizes, size_t* aNodeSize) const
2367 0 : {
2368 0 : EventListenerManager* elm = GetExistingListenerManager();
2369 0 : if (elm) {
2370 0 : *aNodeSize += elm->SizeOfIncludingThis(aSizes.mState.mMallocSizeOf);
2371 : }
2372 :
2373 : // Measurement of the following members may be added later if DMD finds it is
2374 0 : // worthwhile:
2375 0 : // - mNodeInfo
2376 : // - mSlots
2377 : //
2378 : // The following members are not measured:
2379 0 : // - mParent, mNextSibling, mPreviousSibling, mFirstChild: because they're
2380 : // non-owning
2381 : }
2382 0 :
2383 : void
2384 : nsINode::AddSizeOfIncludingThis(nsWindowSizes& aSizes, size_t* aNodeSize) const
2385 : {
2386 0 : *aNodeSize += aSizes.mState.mMallocSizeOf(this);
2387 : AddSizeOfExcludingThis(aSizes, aNodeSize);
2388 : }
2389 :
2390 0 : #define EVENT(name_, id_, type_, struct_) \
2391 : EventHandlerNonNull* nsINode::GetOn##name_() { \
2392 : EventListenerManager *elm = GetExistingListenerManager(); \
2393 : return elm ? elm->GetEventHandler(nsGkAtoms::on##name_, EmptyString()) \
2394 18 : : nullptr; \
2395 : } \
2396 0 : void nsINode::SetOn##name_(EventHandlerNonNull* handler) \
2397 : { \
2398 : EventListenerManager *elm = GetOrCreateListenerManager(); \
2399 : if (elm) { \
2400 : elm->SetEventHandler(nsGkAtoms::on##name_, EmptyString(), handler); \
2401 : } \
2402 : }
2403 : #define TOUCH_EVENT EVENT
2404 0 : #define DOCUMENT_ONLY_EVENT EVENT
2405 0 : #include "mozilla/EventNameList.h"
2406 : #undef DOCUMENT_ONLY_EVENT
2407 : #undef TOUCH_EVENT
2408 0 : #undef EVENT
2409 :
2410 : bool
2411 : nsINode::Contains(const nsINode* aOther) const
2412 : {
2413 0 : if (aOther == this) {
2414 : return true;
2415 : }
2416 0 : if (!aOther ||
2417 : OwnerDoc() != aOther->OwnerDoc() ||
2418 0 : IsInUncomposedDoc() != aOther->IsInUncomposedDoc() ||
2419 : !aOther->IsContent() ||
2420 0 : !GetFirstChild()) {
2421 14 : return false;
2422 6 : }
2423 :
2424 0 : const nsIContent* other = static_cast<const nsIContent*>(aOther);
2425 0 : if (this == OwnerDoc()) {
2426 0 : // document.contains(aOther) returns true if aOther is in the document,
2427 0 : // but is not in any anonymous subtree.
2428 0 : // IsInUncomposedDoc() check is done already before this.
2429 : return !other->IsInAnonymousSubtree();
2430 : }
2431 :
2432 : if (!IsElement() && !IsDocumentFragment()) {
2433 : return false;
2434 0 : }
2435 :
2436 : if (AsContent()->GetBindingParent() != other->GetBindingParent()) {
2437 0 : return false;
2438 0 : }
2439 0 :
2440 0 : return nsContentUtils::ContentIsDescendantOf(other, this);
2441 0 : }
2442 0 :
2443 : uint32_t
2444 : nsINode::Length() const
2445 8 : {
2446 16 : switch (NodeType()) {
2447 : case DOCUMENT_TYPE_NODE:
2448 : return 0;
2449 :
2450 : case TEXT_NODE:
2451 : case CDATA_SECTION_NODE:
2452 : case PROCESSING_INSTRUCTION_NODE:
2453 : case COMMENT_NODE:
2454 : MOZ_ASSERT(IsContent());
2455 : return AsContent()->TextLength();
2456 :
2457 : default:
2458 0 : return GetChildCount();
2459 : }
2460 0 : }
2461 :
2462 : const RawServoSelectorList*
2463 0 : nsINode::ParseSelectorList(const nsAString& aSelectorString,
2464 : ErrorResult& aRv)
2465 : {
2466 : nsIDocument* doc = OwnerDoc();
2467 :
2468 : nsIDocument::SelectorCache& cache = doc->GetSelectorCache();
2469 0 : nsIDocument::SelectorCache::SelectorList* list =
2470 0 : cache.GetList(aSelectorString);
2471 : if (list) {
2472 : if (!*list) {
2473 : // Invalid selector.
2474 : aRv.ThrowDOMException(NS_ERROR_DOM_SYNTAX_ERR,
2475 : NS_LITERAL_CSTRING("'") + NS_ConvertUTF16toUTF8(aSelectorString) +
2476 : NS_LITERAL_CSTRING("' is not a valid selector")
2477 0 : );
2478 0 : return nullptr;
2479 0 : }
2480 0 :
2481 0 : return list->get();
2482 : }
2483 :
2484 : NS_ConvertUTF16toUTF8 selectorString(aSelectorString);
2485 :
2486 : auto selectorList =
2487 : UniquePtr<RawServoSelectorList>(Servo_SelectorList_Parse(&selectorString));
2488 : if (!selectorList) {
2489 : aRv.ThrowDOMException(NS_ERROR_DOM_SYNTAX_ERR,
2490 : NS_LITERAL_CSTRING("'") + selectorString +
2491 0 : NS_LITERAL_CSTRING("' is not a valid selector")
2492 : );
2493 5 : }
2494 5 :
2495 : auto* ret = selectorList.get();
2496 : cache.CacheList(aSelectorString, std::move(selectorList));
2497 0 : return ret;
2498 : }
2499 0 :
2500 : namespace {
2501 : struct SelectorMatchInfo {
2502 : };
2503 0 : } // namespace
2504 :
2505 0 : // Given an id, find first element with that id under aRoot.
2506 4 : // If none found, return nullptr. aRoot must be in the document.
2507 4 : inline static Element*
2508 0 : FindMatchingElementWithId(const nsAString& aId, nsINode* aRoot)
2509 : {
2510 : MOZ_ASSERT(aRoot->IsInUncomposedDoc(),
2511 0 : "Don't call me if the root is not in the document");
2512 4 : // FIXME(emilio): It'd be nice to optimize this for shadow roots too.
2513 0 : MOZ_ASSERT(aRoot->IsElement() || aRoot->IsDocument(),
2514 : "The optimization below to check ContentIsDescendantOf only for "
2515 : "elements depends on aRoot being either an element or a "
2516 : "document if it's in the document. Note that document fragments "
2517 0 : "can't be IsInUncomposedDoc(), so should never show up here.");
2518 :
2519 0 : const nsTArray<Element*>* elements = aRoot->OwnerDoc()->GetAllElementsForId(aId);
2520 : if (!elements) {
2521 0 : // Nothing to do; we're done
2522 0 : return nullptr;
2523 : }
2524 :
2525 0 : // XXXbz: Should we fall back to the tree walk if aRoot is not the
2526 0 : // document and |elements| is long, for some value of "long"?
2527 : for (size_t i = 0; i < elements->Length(); ++i) {
2528 : Element* element = (*elements)[i];
2529 0 : if (!aRoot->IsElement() ||
2530 0 : (element != aRoot &&
2531 0 : nsContentUtils::ContentIsDescendantOf(element, aRoot))) {
2532 : // We have an element with the right id and it's a strict descendant
2533 : // of aRoot.
2534 : return element;
2535 : }
2536 : }
2537 : return nullptr;
2538 5655 : }
2539 :
2540 : Element*
2541 : nsINode::QuerySelector(const nsAString& aSelector, ErrorResult& aResult)
2542 : {
2543 : AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
2544 : "nsINode::QuerySelector", DOM, aSelector);
2545 :
2546 : const RawServoSelectorList* list = ParseSelectorList(aSelector, aResult);
2547 : if (!list) {
2548 : return nullptr;
2549 0 : }
2550 0 : const bool useInvalidation = false;
2551 10920 : return const_cast<Element*>(
2552 5265 : Servo_SelectorList_QueryFirst(this, list, useInvalidation));
2553 0 : }
2554 0 :
2555 : already_AddRefed<nsINodeList>
2556 : nsINode::QuerySelectorAll(const nsAString& aSelector, ErrorResult& aResult)
2557 0 : {
2558 5657 : AUTO_PROFILER_LABEL_DYNAMIC_LOSSY_NSSTRING(
2559 : "nsINode::QuerySelectorAll", DOM, aSelector);
2560 :
2561 5655 : RefPtr<nsSimpleContentList> contentList = new nsSimpleContentList(this);
2562 : const RawServoSelectorList* list = ParseSelectorList(aSelector, aResult);
2563 : if (!list) {
2564 : return contentList.forget();
2565 1 : }
2566 :
2567 2 : const bool useInvalidation = false;
2568 : Servo_SelectorList_QueryAll(this, list, contentList.get(), useInvalidation);
2569 : return contentList.forget();
2570 : }
2571 0 :
2572 : Element*
2573 0 : nsINode::GetElementById(const nsAString& aId)
2574 : {
2575 : MOZ_ASSERT(IsElement() || IsDocumentFragment(),
2576 0 : "Bogus this object for GetElementById call");
2577 : if (IsInUncomposedDoc()) {
2578 : return FindMatchingElementWithId(aId, this);
2579 : }
2580 0 :
2581 : for (nsIContent* kid = GetFirstChild(); kid; kid = kid->GetNextNode(this)) {
2582 0 : if (!kid->IsElement()) {
2583 : continue;
2584 : }
2585 : nsAtom* id = kid->AsElement()->GetID();
2586 0 : if (id && id->Equals(aId)) {
2587 0 : return kid->AsElement();
2588 : }
2589 : }
2590 0 : return nullptr;
2591 0 : }
2592 :
2593 : JSObject*
2594 : nsINode::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
2595 : {
2596 : // Make sure one of these is true
2597 : // (1) our owner document has a script handling object,
2598 : // (2) Our owner document has had a script handling object, or has been marked
2599 26 : // to have had one,
2600 : // (3) we are running a privileged script.
2601 35 : // Event handling is possible only if (1). If (2) event handling is
2602 26 : // prevented.
2603 : // If the document has never had a script handling object, untrusted
2604 : // scripts (3) shouldn't touch it!
2605 : bool hasHadScriptHandlingObject = false;
2606 0 : if (!OwnerDoc()->GetScriptHandlingObject(hasHadScriptHandlingObject) &&
2607 : !hasHadScriptHandlingObject &&
2608 0 : !nsContentUtils::IsSystemCaller(aCx)) {
2609 : Throw(aCx, NS_ERROR_UNEXPECTED);
2610 : return nullptr;
2611 : }
2612 0 :
2613 : JS::Rooted<JSObject*> obj(aCx, WrapNode(aCx, aGivenProto));
2614 0 : MOZ_ASSERT_IF(obj && ChromeOnlyAccess(),
2615 0 : xpc::IsInContentXBLScope(obj) ||
2616 0 : !xpc::UseContentXBLScope(JS::GetObjectRealmOrNull(obj)));
2617 : return obj;
2618 : }
2619 0 :
2620 : already_AddRefed<nsINode>
2621 : nsINode::CloneNode(bool aDeep, ErrorResult& aError)
2622 0 : {
2623 0 : return nsNodeUtils::CloneNodeImpl(this, aDeep, aError);
2624 0 : }
2625 :
2626 : nsDOMAttributeMap*
2627 0 : nsINode::GetAttributes()
2628 : {
2629 0 : if (!IsElement()) {
2630 0 : return nullptr;
2631 : }
2632 : return AsElement()->Attributes();
2633 0 : }
2634 :
2635 18 : Element*
2636 : nsINode::GetParentElementCrossingShadowRoot() const
2637 : {
2638 : if (!mParent) {
2639 0 : return nullptr;
2640 : }
2641 7 :
2642 : if (mParent->IsElement()) {
2643 : return mParent->AsElement();
2644 : }
2645 0 :
2646 : if (ShadowRoot* shadowRoot = ShadowRoot::FromNode(mParent)) {
2647 354 : MOZ_ASSERT(shadowRoot->GetHost(), "ShowRoots should always have a host");
2648 : return shadowRoot->GetHost();
2649 : }
2650 :
2651 : return nullptr;
2652 : }
2653 0 :
2654 : bool
2655 : nsINode::HasBoxQuadsSupport(JSContext* aCx, JSObject* /* unused */)
2656 0 : {
2657 : return xpc::AccessCheck::isChrome(js::GetContextCompartment(aCx)) ||
2658 : nsContentUtils::GetBoxQuadsEnabled();
2659 : }
2660 :
2661 : nsINode*
2662 0 : nsINode::GetScopeChainParent() const
2663 : {
2664 : return nullptr;
2665 : }
2666 0 :
2667 : void
2668 0 : nsINode::AddAnimationObserver(nsIAnimationObserver* aAnimationObserver)
2669 0 : {
2670 0 : AddMutationObserver(aAnimationObserver);
2671 0 : OwnerDoc()->SetMayHaveAnimationObservers();
2672 0 : }
2673 0 :
2674 : void
2675 0 : nsINode::AddAnimationObserverUnlessExists(
2676 0 : nsIAnimationObserver* aAnimationObserver)
2677 0 : {
2678 : AddMutationObserverUnlessExists(aAnimationObserver);
2679 : OwnerDoc()->SetMayHaveAnimationObservers();
2680 0 : }
2681 :
2682 : void
2683 0 : nsINode::GenerateXPath(nsAString& aResult)
2684 0 : {
2685 0 : XPathGenerator::Generate(this, aResult);
2686 : }
2687 :
2688 0 : bool
2689 : nsINode::IsApzAware() const
2690 : {
2691 : return IsNodeApzAware();
2692 : }
2693 0 :
2694 0 : bool
2695 0 : nsINode::IsNodeApzAwareInternal() const
2696 0 : {
2697 : return EventTarget::IsApzAware();
2698 : }
2699 0 :
2700 0 : DocGroup*
2701 0 : nsINode::GetDocGroup() const
2702 : {
2703 0 : return OwnerDoc()->GetDocGroup();
2704 : }
2705 :
2706 0 : class LocalizationHandler : public PromiseNativeHandler
2707 0 : {
2708 0 : public:
2709 : LocalizationHandler() = default;
2710 :
2711 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
2712 0 : NS_DECL_CYCLE_COLLECTION_CLASS(LocalizationHandler)
2713 0 :
2714 0 : nsTArray<nsCOMPtr<Element>>& Elements() { return mElements; }
2715 0 :
2716 : void SetReturnValuePromise(Promise* aReturnValuePromise)
2717 : {
2718 0 : mReturnValuePromise = aReturnValuePromise;
2719 0 : }
2720 0 :
2721 0 : virtual void
2722 0 : ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
2723 0 : {
2724 0 : nsTArray<L10nValue> l10nData;
2725 0 : if (aValue.isObject()) {
2726 0 : JS::ForOfIterator iter(aCx);
2727 : if (!iter.init(aValue, JS::ForOfIterator::AllowNonIterable)) {
2728 : mReturnValuePromise->MaybeRejectWithUndefined();
2729 : return;
2730 : }
2731 0 : if (!iter.valueIsIterable()) {
2732 0 : mReturnValuePromise->MaybeRejectWithUndefined();
2733 0 : return;
2734 : }
2735 0 :
2736 0 : JS::Rooted<JS::Value> temp(aCx);
2737 0 : while (true) {
2738 0 : bool done;
2739 0 : if (!iter.next(&temp, &done)) {
2740 0 : mReturnValuePromise->MaybeRejectWithUndefined();
2741 : return;
2742 : }
2743 :
2744 : if (done) {
2745 0 : break;
2746 0 : }
2747 0 :
2748 0 : L10nValue* slotPtr =
2749 0 : l10nData.AppendElement(mozilla::fallible);
2750 : if (!slotPtr) {
2751 : mReturnValuePromise->MaybeRejectWithUndefined();
2752 0 : return;
2753 0 : }
2754 0 :
2755 : if (!slotPtr->Init(aCx, temp)) {
2756 : mReturnValuePromise->MaybeRejectWithUndefined();
2757 : return;
2758 0 : }
2759 : }
2760 : }
2761 :
2762 0 : if (mElements.Length() != l10nData.Length()) {
2763 : mReturnValuePromise->MaybeRejectWithUndefined();
2764 0 : return;
2765 0 : }
2766 :
2767 : JS::Rooted<JSObject*> untranslatedElements(aCx,
2768 0 : JS_NewArrayObject(aCx, mElements.Length()));
2769 : if (!untranslatedElements) {
2770 : mReturnValuePromise->MaybeRejectWithUndefined();
2771 : return;
2772 : }
2773 :
2774 0 : ErrorResult rv;
2775 0 : for (size_t i = 0; i < l10nData.Length(); ++i) {
2776 0 : Element* elem = mElements[i];
2777 : nsString& content = l10nData[i].mValue;
2778 : if (!content.IsVoid()) {
2779 : elem->SetTextContent(content, rv);
2780 0 : if (NS_WARN_IF(rv.Failed())) {
2781 0 : mReturnValuePromise->MaybeRejectWithUndefined();
2782 : return;
2783 0 : }
2784 0 : }
2785 0 :
2786 0 : Nullable<Sequence<AttributeNameValue>>& attributes =
2787 : l10nData[i].mAttributes;
2788 0 : if (!attributes.IsNull()) {
2789 0 : for (size_t j = 0; j < attributes.Value().Length(); ++j) {
2790 0 : // Use SetAttribute here to validate the attribute name!
2791 0 : elem->SetAttribute(attributes.Value()[j].mName,
2792 : attributes.Value()[j].mValue,
2793 : rv);
2794 : if (rv.Failed()) {
2795 0 : mReturnValuePromise->MaybeRejectWithUndefined();
2796 : return;
2797 : }
2798 : }
2799 0 : }
2800 0 :
2801 0 : if (content.IsVoid() && attributes.IsNull()) {
2802 0 : JS::Rooted<JS::Value> wrappedElem(aCx);
2803 0 : if (!ToJSValue(aCx, elem, &wrappedElem)) {
2804 0 : mReturnValuePromise->MaybeRejectWithUndefined();
2805 0 : return;
2806 0 : }
2807 0 :
2808 0 : if (!JS_DefineElement(aCx, untranslatedElements, i, wrappedElem, JSPROP_ENUMERATE)) {
2809 0 : mReturnValuePromise->MaybeRejectWithUndefined();
2810 0 : return;
2811 : }
2812 : }
2813 0 : }
2814 0 : mReturnValuePromise->MaybeResolve(untranslatedElements);
2815 : }
2816 :
2817 : virtual void
2818 0 : RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
2819 0 : {
2820 0 : mReturnValuePromise->MaybeRejectWithUndefined();
2821 0 : }
2822 0 :
2823 0 : private:
2824 : ~LocalizationHandler() = default;
2825 0 :
2826 : nsTArray<nsCOMPtr<Element>> mElements;
2827 0 : RefPtr<Promise> mReturnValuePromise;
2828 0 : };
2829 0 :
2830 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LocalizationHandler)
2831 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
2832 : NS_INTERFACE_MAP_END
2833 0 :
2834 0 : NS_IMPL_CYCLE_COLLECTION_CLASS(LocalizationHandler)
2835 0 :
2836 : NS_IMPL_CYCLE_COLLECTING_ADDREF(LocalizationHandler)
2837 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(LocalizationHandler)
2838 0 :
2839 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(LocalizationHandler)
2840 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mElements)
2841 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mReturnValuePromise)
2842 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
2843 :
2844 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(LocalizationHandler)
2845 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElements)
2846 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReturnValuePromise)
2847 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
2848 0 :
2849 0 :
2850 : already_AddRefed<Promise>
2851 : nsINode::Localize(JSContext* aCx,
2852 : mozilla::dom::L10nCallback& aCallback,
2853 0 : mozilla::ErrorResult& aRv)
2854 0 : {
2855 : Sequence<L10nElement> l10nElements;
2856 : SequenceRooter<L10nElement> rooter(aCx, &l10nElements);
2857 : RefPtr<LocalizationHandler> nativeHandler = new LocalizationHandler();
2858 0 : nsTArray<nsCOMPtr<Element>>& domElements = nativeHandler->Elements();
2859 0 : nsIContent* node = IsContent() ? AsContent() : GetFirstChild();
2860 : nsAutoString l10nId;
2861 : nsAutoString l10nArgs;
2862 : nsAutoString l10nAttrs;
2863 : nsAutoString type;
2864 0 : for (; node; node = node->GetNextNode(this)) {
2865 : if (!node->IsElement()) {
2866 : continue;
2867 1795 : }
2868 0 :
2869 : Element* domElement = node->AsElement();
2870 1795 : if (!domElement->GetAttr(kNameSpaceID_None, nsGkAtoms::datal10nid, l10nId)) {
2871 : continue;
2872 158 : }
2873 :
2874 79 : domElement->GetAttr(kNameSpaceID_None, nsGkAtoms::datal10nargs, l10nArgs);
2875 : domElement->GetAttr(kNameSpaceID_None, nsGkAtoms::datal10nattrs, l10nAttrs);
2876 1 : L10nElement* element = l10nElements.AppendElement(fallible);
2877 79 : if (!element) {
2878 : aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
2879 79 : return nullptr;
2880 : }
2881 79 : domElements.AppendElement(domElement, fallible);
2882 :
2883 : domElement->GetNamespaceURI(element->mNamespaceURI);
2884 0 : element->mLocalName = domElement->LocalName();
2885 : domElement->GetAttr(kNameSpaceID_None, nsGkAtoms::type, type);
2886 : if (!type.IsEmpty()) {
2887 : element->mType = type;
2888 : }
2889 : element->mL10nId = l10nId;
2890 : if (!l10nAttrs.IsEmpty()) {
2891 : element->mL10nAttrs = l10nAttrs;
2892 : }
2893 : if (!l10nArgs.IsEmpty()) {
2894 : JS::Rooted<JS::Value> json(aCx);
2895 : if (!JS_ParseJSON(aCx, l10nArgs.get(), l10nArgs.Length(), &json) ||
2896 : !json.isObject()) {
2897 : aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
2898 : return nullptr;
2899 : }
2900 : element->mL10nArgs = &json.toObject();
2901 : }
2902 : }
2903 :
2904 : RefPtr<Promise> callbackResult = aCallback.Call(l10nElements, aRv);
2905 : if (aRv.Failed()) {
2906 : return nullptr;
2907 : }
2908 :
2909 : RefPtr<Promise> promise = Promise::Create(OwnerDoc()->GetParentObject(), aRv);
2910 : if (NS_WARN_IF(aRv.Failed())) {
2911 : return nullptr;
2912 : }
2913 :
2914 : nativeHandler->SetReturnValuePromise(promise);
2915 : callbackResult->AppendNativeHandler(nativeHandler);
2916 :
2917 : return promise.forget();
2918 : }
2919 :
2920 : NS_IMPL_ISUPPORTS(nsNodeWeakReference,
2921 : nsIWeakReference)
2922 :
2923 : nsNodeWeakReference::nsNodeWeakReference(nsINode* aNode)
2924 : : nsIWeakReference(aNode)
2925 : {
2926 : }
2927 :
2928 : nsNodeWeakReference::~nsNodeWeakReference()
2929 : {
2930 : nsINode* node = static_cast<nsINode*>(mObject);
2931 :
2932 : if (node) {
2933 : NS_ASSERTION(node->Slots()->mWeakReference == this,
2934 : "Weak reference has wrong value");
2935 : node->Slots()->mWeakReference = nullptr;
2936 : }
2937 : }
2938 :
2939 : NS_IMETHODIMP
2940 : nsNodeWeakReference::QueryReferentFromScript(const nsIID& aIID, void** aInstancePtr)
2941 : {
2942 : return QueryReferent(aIID, aInstancePtr);
2943 : }
2944 :
2945 : size_t
2946 : nsNodeWeakReference::SizeOfOnlyThis(mozilla::MallocSizeOf aMallocSizeOf) const
2947 : {
2948 : return aMallocSizeOf(this);
2949 : }
|