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

Generated by: LCOV version 1.13