LCOV - code coverage report
Current view: top level - dom/base - nsINode.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 241 1159 20.8 %
Date: 2018-08-07 16:42:27 Functions: 0 0 -
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.13-14-ga5dd952