content/base/src/nsINode.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     7 /*
     8  * Base class for all DOM nodes.
     9  */
    11 #include "nsINode.h"
    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/Telemetry.h"
    24 #include "mozilla/dom/Element.h"
    25 #include "mozilla/dom/Event.h"
    26 #include "mozilla/dom/ShadowRoot.h"
    27 #include "nsAttrValueOrString.h"
    28 #include "nsBindingManager.h"
    29 #include "nsCCUncollectableMarker.h"
    30 #include "nsContentCreatorFunctions.h"
    31 #include "nsContentList.h"
    32 #include "nsContentUtils.h"
    33 #include "nsCycleCollectionParticipant.h"
    34 #include "nsDocument.h"
    35 #include "mozilla/dom/Attr.h"
    36 #include "nsDOMAttributeMap.h"
    37 #include "nsDOMCID.h"
    38 #include "nsDOMCSSAttrDeclaration.h"
    39 #include "nsError.h"
    40 #include "nsDOMMutationObserver.h"
    41 #include "nsDOMString.h"
    42 #include "nsDOMTokenList.h"
    43 #include "nsFocusManager.h"
    44 #include "nsFrameManager.h"
    45 #include "nsFrameSelection.h"
    46 #include "nsGenericHTMLElement.h"
    47 #include "nsGkAtoms.h"
    48 #include "nsIAnonymousContentCreator.h"
    49 #include "nsIAtom.h"
    50 #include "nsIBaseWindow.h"
    51 #include "nsICategoryManager.h"
    52 #include "nsIContentIterator.h"
    53 #include "nsIControllers.h"
    54 #include "nsIDocument.h"
    55 #include "nsIDOMDocument.h"
    56 #include "nsIDOMDocumentType.h"
    57 #include "nsIDOMEvent.h"
    58 #include "nsIDOMEventListener.h"
    59 #include "nsIDOMMutationEvent.h"
    60 #include "nsIDOMNodeList.h"
    61 #include "nsIDOMUserDataHandler.h"
    62 #include "nsIEditor.h"
    63 #include "nsIEditorIMESupport.h"
    64 #include "nsILinkHandler.h"
    65 #include "nsINodeInfo.h"
    66 #include "nsIPresShell.h"
    67 #include "nsIScriptError.h"
    68 #include "nsIScriptGlobalObject.h"
    69 #include "nsIScriptSecurityManager.h"
    70 #include "nsIScrollableFrame.h"
    71 #include "nsIServiceManager.h"
    72 #include "nsIURL.h"
    73 #include "nsView.h"
    74 #include "nsViewManager.h"
    75 #include "nsIWebNavigation.h"
    76 #include "nsIWidget.h"
    77 #include "nsLayoutUtils.h"
    78 #include "nsNameSpaceManager.h"
    79 #include "nsNetUtil.h"
    80 #include "nsNodeInfoManager.h"
    81 #include "nsNodeUtils.h"
    82 #include "nsPIBoxObject.h"
    83 #include "nsPIDOMWindow.h"
    84 #include "nsPresContext.h"
    85 #include "nsRuleProcessorData.h"
    86 #include "nsString.h"
    87 #include "nsStyleConsts.h"
    88 #include "nsSVGFeatures.h"
    89 #include "nsSVGUtils.h"
    90 #include "nsTextNode.h"
    91 #include "nsUnicharUtils.h"
    92 #include "nsXBLBinding.h"
    93 #include "nsXBLPrototypeBinding.h"
    94 #include "prprf.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"
   107 using namespace mozilla;
   108 using namespace mozilla::dom;
   110 nsINode::nsSlots::~nsSlots()
   111 {
   112   if (mChildNodes) {
   113     mChildNodes->DropReference();
   114     NS_RELEASE(mChildNodes);
   115   }
   117   if (mWeakReference) {
   118     mWeakReference->NoticeNodeDestruction();
   119   }
   120 }
   122 void
   123 nsINode::nsSlots::Traverse(nsCycleCollectionTraversalCallback &cb)
   124 {
   125   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildNodes");
   126   cb.NoteXPCOMChild(mChildNodes);
   127 }
   129 void
   130 nsINode::nsSlots::Unlink()
   131 {
   132   if (mChildNodes) {
   133     mChildNodes->DropReference();
   134     NS_RELEASE(mChildNodes);
   135   }
   136 }
   138 //----------------------------------------------------------------------
   140 nsINode::~nsINode()
   141 {
   142   MOZ_ASSERT(!HasSlots(), "nsNodeUtils::LastRelease was not called?");
   143   MOZ_ASSERT(mSubtreeRoot == this, "Didn't restore state properly?");
   144 }
   146 void*
   147 nsINode::GetProperty(uint16_t aCategory, nsIAtom *aPropertyName,
   148                      nsresult *aStatus) const
   149 {
   150   return OwnerDoc()->PropertyTable(aCategory)->GetProperty(this, aPropertyName,
   151                                                            aStatus);
   152 }
   154 nsresult
   155 nsINode::SetProperty(uint16_t aCategory, nsIAtom *aPropertyName, void *aValue,
   156                      NSPropertyDtorFunc aDtor, bool aTransfer,
   157                      void **aOldValue)
   158 {
   159   nsresult rv = OwnerDoc()->PropertyTable(aCategory)->SetProperty(this,
   160                                                                   aPropertyName,
   161                                                                   aValue, aDtor,
   162                                                                   nullptr,
   163                                                                   aTransfer,
   164                                                                   aOldValue);
   165   if (NS_SUCCEEDED(rv)) {
   166     SetFlags(NODE_HAS_PROPERTIES);
   167   }
   169   return rv;
   170 }
   172 void
   173 nsINode::DeleteProperty(uint16_t aCategory, nsIAtom *aPropertyName)
   174 {
   175   OwnerDoc()->PropertyTable(aCategory)->DeleteProperty(this, aPropertyName);
   176 }
   178 void*
   179 nsINode::UnsetProperty(uint16_t aCategory, nsIAtom *aPropertyName,
   180                        nsresult *aStatus)
   181 {
   182   return OwnerDoc()->PropertyTable(aCategory)->UnsetProperty(this,
   183                                                              aPropertyName,
   184                                                              aStatus);
   185 }
   187 nsINode::nsSlots*
   188 nsINode::CreateSlots()
   189 {
   190   return new nsSlots();
   191 }
   193 bool
   194 nsINode::IsEditableInternal() const
   195 {
   196   if (HasFlag(NODE_IS_EDITABLE)) {
   197     // The node is in an editable contentEditable subtree.
   198     return true;
   199   }
   201   nsIDocument *doc = GetCurrentDoc();
   203   // Check if the node is in a document and the document is in designMode.
   204   return doc && doc->HasFlag(NODE_IS_EDITABLE);
   205 }
   207 static nsIContent* GetEditorRootContent(nsIEditor* aEditor)
   208 {
   209   nsCOMPtr<nsIDOMElement> rootElement;
   210   aEditor->GetRootElement(getter_AddRefs(rootElement));
   211   nsCOMPtr<nsIContent> rootContent(do_QueryInterface(rootElement));
   212   return rootContent;
   213 }
   215 nsIContent*
   216 nsINode::GetTextEditorRootContent(nsIEditor** aEditor)
   217 {
   218   if (aEditor)
   219     *aEditor = nullptr;
   220   for (nsINode* node = this; node; node = node->GetParentNode()) {
   221     if (!node->IsElement() ||
   222         !node->AsElement()->IsHTML())
   223       continue;
   225     nsCOMPtr<nsIEditor> editor =
   226       static_cast<nsGenericHTMLElement*>(node)->GetEditorInternal();
   227     if (!editor)
   228       continue;
   230     nsIContent* rootContent = GetEditorRootContent(editor);
   231     if (aEditor)
   232       editor.swap(*aEditor);
   233     return rootContent;
   234   }
   235   return nullptr;
   236 }
   238 static nsIContent* GetRootForContentSubtree(nsIContent* aContent)
   239 {
   240   NS_ENSURE_TRUE(aContent, nullptr);
   242   // Special case for ShadowRoot because the ShadowRoot itself is
   243   // the root. This is necessary to prevent selection from crossing
   244   // the ShadowRoot boundary.
   245   ShadowRoot* containingShadow = aContent->GetContainingShadow();
   246   if (containingShadow) {
   247     return containingShadow;
   248   }
   250   nsIContent* stop = aContent->GetBindingParent();
   251   while (aContent) {
   252     nsIContent* parent = aContent->GetParent();
   253     if (parent == stop) {
   254       break;
   255     }
   256     aContent = parent;
   257   }
   258   return aContent;
   259 }
   261 nsIContent*
   262 nsINode::GetSelectionRootContent(nsIPresShell* aPresShell)
   263 {
   264   NS_ENSURE_TRUE(aPresShell, nullptr);
   266   if (IsNodeOfType(eDOCUMENT))
   267     return static_cast<nsIDocument*>(this)->GetRootElement();
   268   if (!IsNodeOfType(eCONTENT))
   269     return nullptr;
   271   if (GetCurrentDoc() != aPresShell->GetDocument()) {
   272     return nullptr;
   273   }
   275   if (static_cast<nsIContent*>(this)->HasIndependentSelection()) {
   276     // This node should be a descendant of input/textarea editor.
   277     nsIContent* content = GetTextEditorRootContent();
   278     if (content)
   279       return content;
   280   }
   282   nsPresContext* presContext = aPresShell->GetPresContext();
   283   if (presContext) {
   284     nsIEditor* editor = nsContentUtils::GetHTMLEditor(presContext);
   285     if (editor) {
   286       // This node is in HTML editor.
   287       nsIDocument* doc = GetCurrentDoc();
   288       if (!doc || doc->HasFlag(NODE_IS_EDITABLE) ||
   289           !HasFlag(NODE_IS_EDITABLE)) {
   290         nsIContent* editorRoot = GetEditorRootContent(editor);
   291         NS_ENSURE_TRUE(editorRoot, nullptr);
   292         return nsContentUtils::IsInSameAnonymousTree(this, editorRoot) ?
   293                  editorRoot :
   294                  GetRootForContentSubtree(static_cast<nsIContent*>(this));
   295       }
   296       // If the document isn't editable but this is editable, this is in
   297       // contenteditable.  Use the editing host element for selection root.
   298       return static_cast<nsIContent*>(this)->GetEditingHost();
   299     }
   300   }
   302   nsRefPtr<nsFrameSelection> fs = aPresShell->FrameSelection();
   303   nsIContent* content = fs->GetLimiter();
   304   if (!content) {
   305     content = fs->GetAncestorLimiter();
   306     if (!content) {
   307       nsIDocument* doc = aPresShell->GetDocument();
   308       NS_ENSURE_TRUE(doc, nullptr);
   309       content = doc->GetRootElement();
   310       if (!content)
   311         return nullptr;
   312     }
   313   }
   315   // This node might be in another subtree, if so, we should find this subtree's
   316   // root.  Otherwise, we can return the content simply.
   317   NS_ENSURE_TRUE(content, nullptr);
   318   if (!nsContentUtils::IsInSameAnonymousTree(this, content)) {
   319     content = GetRootForContentSubtree(static_cast<nsIContent*>(this));
   320     // Fixup for ShadowRoot because the ShadowRoot itself does not have a frame.
   321     // Use the host as the root.
   322     ShadowRoot* shadowRoot = ShadowRoot::FromNode(content);
   323     if (shadowRoot) {
   324       content = shadowRoot->GetHost();
   325     }
   326   }
   328   return content;
   329 }
   331 nsINodeList*
   332 nsINode::ChildNodes()
   333 {
   334   nsSlots* slots = Slots();
   335   if (!slots->mChildNodes) {
   336     slots->mChildNodes = new nsChildContentList(this);
   337     if (slots->mChildNodes) {
   338       NS_ADDREF(slots->mChildNodes);
   339     }
   340   }
   342   return slots->mChildNodes;
   343 }
   345 void
   346 nsINode::GetTextContentInternal(nsAString& aTextContent)
   347 {
   348   SetDOMStringToNull(aTextContent);
   349 }
   351 #ifdef DEBUG
   352 void
   353 nsINode::CheckNotNativeAnonymous() const
   354 {
   355   if (!IsNodeOfType(eCONTENT))
   356     return;
   357   nsIContent* content = static_cast<const nsIContent *>(this)->GetBindingParent();
   358   while (content) {
   359     if (content->IsRootOfNativeAnonymousSubtree()) {
   360       NS_ERROR("Element not marked to be in native anonymous subtree!");
   361       break;
   362     }
   363     content = content->GetBindingParent();
   364   }
   365 }
   366 #endif
   368 bool
   369 nsINode::IsInAnonymousSubtree() const
   370 {
   371   if (!IsContent()) {
   372     return false;
   373   }
   375   return AsContent()->IsInAnonymousSubtree();
   376 }
   378 bool
   379 nsINode::IsAnonymousContentInSVGUseSubtree() const
   380 {
   381   MOZ_ASSERT(IsInAnonymousSubtree());
   382   nsIContent* parent = AsContent()->GetBindingParent();
   383   // Watch out for parentless native-anonymous subtrees.
   384   return parent && parent->IsSVG(nsGkAtoms::use);
   385 }
   387 nsresult
   388 nsINode::GetParentNode(nsIDOMNode** aParentNode)
   389 {
   390   *aParentNode = nullptr;
   392   nsINode *parent = GetParentNode();
   394   return parent ? CallQueryInterface(parent, aParentNode) : NS_OK;
   395 }
   397 nsresult
   398 nsINode::GetParentElement(nsIDOMElement** aParentElement)
   399 {
   400   *aParentElement = nullptr;
   401   nsINode* parent = GetParentElement();
   402   return parent ? CallQueryInterface(parent, aParentElement) : NS_OK;
   403 }
   405 nsresult
   406 nsINode::GetChildNodes(nsIDOMNodeList** aChildNodes)
   407 {
   408   NS_ADDREF(*aChildNodes = ChildNodes());
   410   return NS_OK;
   411 }
   413 nsresult
   414 nsINode::GetFirstChild(nsIDOMNode** aNode)
   415 {
   416   nsIContent* child = GetFirstChild();
   417   if (child) {
   418     return CallQueryInterface(child, aNode);
   419   }
   421   *aNode = nullptr;
   423   return NS_OK;
   424 }
   426 nsresult
   427 nsINode::GetLastChild(nsIDOMNode** aNode)
   428 {
   429   nsIContent* child = GetLastChild();
   430   if (child) {
   431     return CallQueryInterface(child, aNode);
   432   }
   434   *aNode = nullptr;
   436   return NS_OK;
   437 }
   439 nsresult
   440 nsINode::GetPreviousSibling(nsIDOMNode** aPrevSibling)
   441 {
   442   *aPrevSibling = nullptr;
   444   nsIContent *sibling = GetPreviousSibling();
   446   return sibling ? CallQueryInterface(sibling, aPrevSibling) : NS_OK;
   447 }
   449 nsresult
   450 nsINode::GetNextSibling(nsIDOMNode** aNextSibling)
   451 {
   452   *aNextSibling = nullptr;
   454   nsIContent *sibling = GetNextSibling();
   456   return sibling ? CallQueryInterface(sibling, aNextSibling) : NS_OK;
   457 }
   459 nsresult
   460 nsINode::GetOwnerDocument(nsIDOMDocument** aOwnerDocument)
   461 {
   462   *aOwnerDocument = nullptr;
   464   nsIDocument *ownerDoc = GetOwnerDocument();
   466   return ownerDoc ? CallQueryInterface(ownerDoc, aOwnerDocument) : NS_OK;
   467 }
   469 void
   470 nsINode::GetNodeValueInternal(nsAString& aNodeValue)
   471 {
   472   SetDOMStringToNull(aNodeValue);
   473 }
   475 nsINode*
   476 nsINode::RemoveChild(nsINode& aOldChild, ErrorResult& aError)
   477 {
   478   if (IsNodeOfType(eDATA_NODE)) {
   479     // aOldChild can't be one of our children.
   480     aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
   481     return nullptr;
   482   }
   484   if (aOldChild.GetParentNode() == this) {
   485     nsContentUtils::MaybeFireNodeRemoved(&aOldChild, this, OwnerDoc());
   486   }
   488   int32_t index = IndexOf(&aOldChild);
   489   if (index == -1) {
   490     // aOldChild isn't one of our children.
   491     aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
   492     return nullptr;
   493   }
   495   RemoveChildAt(index, true);
   496   return &aOldChild;
   497 }
   499 nsresult
   500 nsINode::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
   501 {
   502   nsCOMPtr<nsINode> oldChild = do_QueryInterface(aOldChild);
   503   if (!oldChild) {
   504     return NS_ERROR_NULL_POINTER;
   505   }
   507   ErrorResult rv;
   508   RemoveChild(*oldChild, rv);
   509   if (!rv.Failed()) {
   510     NS_ADDREF(*aReturn = aOldChild);
   511   }
   512   return rv.ErrorCode();
   513 }
   515 void
   516 nsINode::Normalize()
   517 {
   518   // First collect list of nodes to be removed
   519   nsAutoTArray<nsCOMPtr<nsIContent>, 50> nodes;
   521   bool canMerge = false;
   522   for (nsIContent* node = this->GetFirstChild();
   523        node;
   524        node = node->GetNextNode(this)) {
   525     if (node->NodeType() != nsIDOMNode::TEXT_NODE) {
   526       canMerge = false;
   527       continue;
   528     }
   530     if (canMerge || node->TextLength() == 0) {
   531       // No need to touch canMerge. That way we can merge across empty
   532       // textnodes if and only if the node before is a textnode
   533       nodes.AppendElement(node);
   534     }
   535     else {
   536       canMerge = true;
   537     }
   539     // If there's no following sibling, then we need to ensure that we don't
   540     // collect following siblings of our (grand)parent as to-be-removed
   541     canMerge = canMerge && !!node->GetNextSibling();
   542   }
   544   if (nodes.IsEmpty()) {
   545     return;
   546   }
   548   // We're relying on mozAutoSubtreeModified to keep the doc alive here.
   549   nsIDocument* doc = OwnerDoc();
   551   // Batch possible DOMSubtreeModified events.
   552   mozAutoSubtreeModified subtree(doc, nullptr);
   554   // Fire all DOMNodeRemoved events. Optimize the common case of there being
   555   // no listeners
   556   bool hasRemoveListeners = nsContentUtils::
   557       HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEREMOVED);
   558   if (hasRemoveListeners) {
   559     for (uint32_t i = 0; i < nodes.Length(); ++i) {
   560       nsINode* parentNode = nodes[i]->GetParentNode();
   561       if (parentNode) { // Node may have already been removed.
   562         nsContentUtils::MaybeFireNodeRemoved(nodes[i], parentNode,
   563                                              doc);
   564       }
   565     }
   566   }
   568   mozAutoDocUpdate batch(doc, UPDATE_CONTENT_MODEL, true);
   570   // Merge and remove all nodes
   571   nsAutoString tmpStr;
   572   for (uint32_t i = 0; i < nodes.Length(); ++i) {
   573     nsIContent* node = nodes[i];
   574     // Merge with previous node unless empty
   575     const nsTextFragment* text = node->GetText();
   576     if (text->GetLength()) {
   577       nsIContent* target = node->GetPreviousSibling();
   578       NS_ASSERTION((target && target->NodeType() == nsIDOMNode::TEXT_NODE) ||
   579                    hasRemoveListeners,
   580                    "Should always have a previous text sibling unless "
   581                    "mutation events messed us up");
   582       if (!hasRemoveListeners ||
   583           (target && target->NodeType() == nsIDOMNode::TEXT_NODE)) {
   584         nsTextNode* t = static_cast<nsTextNode*>(target);
   585         if (text->Is2b()) {
   586           t->AppendTextForNormalize(text->Get2b(), text->GetLength(), true, node);
   587         }
   588         else {
   589           tmpStr.Truncate();
   590           text->AppendTo(tmpStr);
   591           t->AppendTextForNormalize(tmpStr.get(), tmpStr.Length(), true, node);
   592         }
   593       }
   594     }
   596     // Remove node
   597     nsCOMPtr<nsINode> parent = node->GetParentNode();
   598     NS_ASSERTION(parent || hasRemoveListeners,
   599                  "Should always have a parent unless "
   600                  "mutation events messed us up");
   601     if (parent) {
   602       parent->RemoveChildAt(parent->IndexOf(node), true);
   603     }
   604   }
   605 }
   607 void
   608 nsINode::GetBaseURI(nsAString &aURI) const
   609 {
   610   nsCOMPtr<nsIURI> baseURI = GetBaseURI();
   612   nsAutoCString spec;
   613   if (baseURI) {
   614     baseURI->GetSpec(spec);
   615   }
   617   CopyUTF8toUTF16(spec, aURI);
   618 }
   620 void
   621 nsINode::GetBaseURIFromJS(nsAString& aURI) const
   622 {
   623   nsCOMPtr<nsIURI> baseURI = GetBaseURI(nsContentUtils::IsCallerChrome());
   624   nsAutoCString spec;
   625   if (baseURI) {
   626     baseURI->GetSpec(spec);
   627   }
   628   CopyUTF8toUTF16(spec, aURI);
   629 }
   631 already_AddRefed<nsIURI>
   632 nsINode::GetBaseURIObject() const
   633 {
   634   return GetBaseURI(true);
   635 }
   637 void
   638 nsINode::LookupPrefix(const nsAString& aNamespaceURI, nsAString& aPrefix)
   639 {
   640   Element *element = GetNameSpaceElement();
   641   if (element) {
   642     // XXX Waiting for DOM spec to list error codes.
   644     // Trace up the content parent chain looking for the namespace
   645     // declaration that defines the aNamespaceURI namespace. Once found,
   646     // return the prefix (i.e. the attribute localName).
   647     for (nsIContent* content = element; content;
   648          content = content->GetParent()) {
   649       uint32_t attrCount = content->GetAttrCount();
   651       for (uint32_t i = 0; i < attrCount; ++i) {
   652         const nsAttrName* name = content->GetAttrNameAt(i);
   654         if (name->NamespaceEquals(kNameSpaceID_XMLNS) &&
   655             content->AttrValueIs(kNameSpaceID_XMLNS, name->LocalName(),
   656                                  aNamespaceURI, eCaseMatters)) {
   657           // If the localName is "xmlns", the prefix we output should be
   658           // null.
   659           nsIAtom *localName = name->LocalName();
   661           if (localName != nsGkAtoms::xmlns) {
   662             localName->ToString(aPrefix);
   663           }
   664           else {
   665             SetDOMStringToNull(aPrefix);
   666           }
   667           return;
   668         }
   669       }
   670     }
   671   }
   673   SetDOMStringToNull(aPrefix);
   674 }
   676 static nsresult
   677 SetUserDataProperty(uint16_t aCategory, nsINode *aNode, nsIAtom *aKey,
   678                     nsISupports* aValue, void** aOldValue)
   679 {
   680   nsresult rv = aNode->SetProperty(aCategory, aKey, aValue,
   681                                    nsPropertyTable::SupportsDtorFunc, true,
   682                                    aOldValue);
   683   NS_ENSURE_SUCCESS(rv, rv);
   685   // Property table owns it now.
   686   NS_ADDREF(aValue);
   688   return NS_OK;
   689 }
   691 nsresult
   692 nsINode::SetUserData(const nsAString &aKey, nsIVariant *aData,
   693                      nsIDOMUserDataHandler *aHandler, nsIVariant **aResult)
   694 {
   695   OwnerDoc()->WarnOnceAbout(nsIDocument::eGetSetUserData);
   696   *aResult = nullptr;
   698   nsCOMPtr<nsIAtom> key = do_GetAtom(aKey);
   699   if (!key) {
   700     return NS_ERROR_OUT_OF_MEMORY;
   701   }
   703   nsresult rv;
   704   void *data;
   705   if (aData) {
   706     rv = SetUserDataProperty(DOM_USER_DATA, this, key, aData, &data);
   707     NS_ENSURE_SUCCESS(rv, rv);
   708   }
   709   else {
   710     data = UnsetProperty(DOM_USER_DATA, key);
   711   }
   713   // Take over ownership of the old data from the property table.
   714   nsCOMPtr<nsIVariant> oldData = dont_AddRef(static_cast<nsIVariant*>(data));
   716   if (aData && aHandler) {
   717     nsCOMPtr<nsIDOMUserDataHandler> oldHandler;
   718     rv = SetUserDataProperty(DOM_USER_DATA_HANDLER, this, key, aHandler,
   719                              getter_AddRefs(oldHandler));
   720     if (NS_FAILED(rv)) {
   721       // We failed to set the handler, remove the data.
   722       DeleteProperty(DOM_USER_DATA, key);
   724       return rv;
   725     }
   726   }
   727   else {
   728     DeleteProperty(DOM_USER_DATA_HANDLER, key);
   729   }
   731   oldData.swap(*aResult);
   733   return NS_OK;
   734 }
   736 void
   737 nsINode::SetUserData(JSContext* aCx, const nsAString& aKey,
   738                      JS::Handle<JS::Value> aData,
   739                      nsIDOMUserDataHandler* aHandler,
   740                      JS::MutableHandle<JS::Value> aRetval,
   741                      ErrorResult& aError)
   742 {
   743   nsCOMPtr<nsIVariant> data;
   744   aError = nsContentUtils::XPConnect()->JSValToVariant(aCx, aData, getter_AddRefs(data));
   745   if (aError.Failed()) {
   746     return;
   747   }
   749   nsCOMPtr<nsIVariant> oldData;
   750   aError = SetUserData(aKey, data, aHandler, getter_AddRefs(oldData));
   751   if (aError.Failed()) {
   752     return;
   753   }
   755   if (!oldData) {
   756     aRetval.setNull();
   757     return;
   758   }
   760   JSAutoCompartment ac(aCx, GetWrapper());
   761   aError = nsContentUtils::XPConnect()->VariantToJS(aCx, GetWrapper(), oldData,
   762                                                     aRetval);
   763 }
   765 nsIVariant*
   766 nsINode::GetUserData(const nsAString& aKey)
   767 {
   768   OwnerDoc()->WarnOnceAbout(nsIDocument::eGetSetUserData);
   769   nsCOMPtr<nsIAtom> key = do_GetAtom(aKey);
   770   if (!key) {
   771     return nullptr;
   772   }
   774   return static_cast<nsIVariant*>(GetProperty(DOM_USER_DATA, key));
   775 }
   777 void
   778 nsINode::GetUserData(JSContext* aCx, const nsAString& aKey,
   779                      JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError)
   780 {
   781   nsIVariant* data = GetUserData(aKey);
   782   if (!data) {
   783     aRetval.setNull();
   784     return;
   785   }
   787   JSAutoCompartment ac(aCx, GetWrapper());
   788   aError = nsContentUtils::XPConnect()->VariantToJS(aCx, GetWrapper(), data,
   789                                                     aRetval);
   790 }
   792 uint16_t
   793 nsINode::CompareDocumentPosition(nsINode& aOtherNode) const
   794 {
   795   if (this == &aOtherNode) {
   796     return 0;
   797   }
   798   if (GetPreviousSibling() == &aOtherNode) {
   799     MOZ_ASSERT(GetParentNode() == aOtherNode.GetParentNode());
   800     return static_cast<uint16_t>(nsIDOMNode::DOCUMENT_POSITION_PRECEDING);
   801   }
   802   if (GetNextSibling() == &aOtherNode) {
   803     MOZ_ASSERT(GetParentNode() == aOtherNode.GetParentNode());
   804     return static_cast<uint16_t>(nsIDOMNode::DOCUMENT_POSITION_FOLLOWING);
   805   }
   807   nsAutoTArray<const nsINode*, 32> parents1, parents2;
   809   const nsINode *node1 = &aOtherNode, *node2 = this;
   811   // Check if either node is an attribute
   812   const Attr* attr1 = nullptr;
   813   if (node1->IsNodeOfType(nsINode::eATTRIBUTE)) {
   814     attr1 = static_cast<const Attr*>(node1);
   815     const Element* elem = attr1->GetElement();
   816     // If there is an owner element add the attribute
   817     // to the chain and walk up to the element
   818     if (elem) {
   819       node1 = elem;
   820       parents1.AppendElement(attr1);
   821     }
   822   }
   823   if (node2->IsNodeOfType(nsINode::eATTRIBUTE)) {
   824     const Attr* attr2 = static_cast<const Attr*>(node2);
   825     const Element* elem = attr2->GetElement();
   826     if (elem == node1 && attr1) {
   827       // Both nodes are attributes on the same element.
   828       // Compare position between the attributes.
   830       uint32_t i;
   831       const nsAttrName* attrName;
   832       for (i = 0; (attrName = elem->GetAttrNameAt(i)); ++i) {
   833         if (attrName->Equals(attr1->NodeInfo())) {
   834           NS_ASSERTION(!attrName->Equals(attr2->NodeInfo()),
   835                        "Different attrs at same position");
   836           return nsIDOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
   837             nsIDOMNode::DOCUMENT_POSITION_PRECEDING;
   838         }
   839         if (attrName->Equals(attr2->NodeInfo())) {
   840           return nsIDOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC |
   841             nsIDOMNode::DOCUMENT_POSITION_FOLLOWING;
   842         }
   843       }
   844       NS_NOTREACHED("neither attribute in the element");
   845       return nsIDOMNode::DOCUMENT_POSITION_DISCONNECTED;
   846     }
   848     if (elem) {
   849       node2 = elem;
   850       parents2.AppendElement(attr2);
   851     }
   852   }
   854   // We now know that both nodes are either nsIContents or nsIDocuments.
   855   // If either node started out as an attribute, that attribute will have
   856   // the same relative position as its ownerElement, except if the
   857   // ownerElement ends up being the container for the other node
   859   // Build the chain of parents
   860   do {
   861     parents1.AppendElement(node1);
   862     node1 = node1->GetParentNode();
   863   } while (node1);
   864   do {
   865     parents2.AppendElement(node2);
   866     node2 = node2->GetParentNode();
   867   } while (node2);
   869   // Check if the nodes are disconnected.
   870   uint32_t pos1 = parents1.Length();
   871   uint32_t pos2 = parents2.Length();
   872   const nsINode* top1 = parents1.ElementAt(--pos1);
   873   const nsINode* top2 = parents2.ElementAt(--pos2);
   874   if (top1 != top2) {
   875     return top1 < top2 ?
   876       (nsIDOMNode::DOCUMENT_POSITION_PRECEDING |
   877        nsIDOMNode::DOCUMENT_POSITION_DISCONNECTED |
   878        nsIDOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC) :
   879       (nsIDOMNode::DOCUMENT_POSITION_FOLLOWING |
   880        nsIDOMNode::DOCUMENT_POSITION_DISCONNECTED |
   881        nsIDOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
   882   }
   884   // Find where the parent chain differs and check indices in the parent.
   885   const nsINode* parent = top1;
   886   uint32_t len;
   887   for (len = std::min(pos1, pos2); len > 0; --len) {
   888     const nsINode* child1 = parents1.ElementAt(--pos1);
   889     const nsINode* child2 = parents2.ElementAt(--pos2);
   890     if (child1 != child2) {
   891       // child1 or child2 can be an attribute here. This will work fine since
   892       // IndexOf will return -1 for the attribute making the attribute be
   893       // considered before any child.
   894       return parent->IndexOf(child1) < parent->IndexOf(child2) ?
   895         static_cast<uint16_t>(nsIDOMNode::DOCUMENT_POSITION_PRECEDING) :
   896         static_cast<uint16_t>(nsIDOMNode::DOCUMENT_POSITION_FOLLOWING);
   897     }
   898     parent = child1;
   899   }
   901   // We hit the end of one of the parent chains without finding a difference
   902   // between the chains. That must mean that one node is an ancestor of the
   903   // other. The one with the shortest chain must be the ancestor.
   904   return pos1 < pos2 ?
   905     (nsIDOMNode::DOCUMENT_POSITION_PRECEDING |
   906      nsIDOMNode::DOCUMENT_POSITION_CONTAINS) :
   907     (nsIDOMNode::DOCUMENT_POSITION_FOLLOWING |
   908      nsIDOMNode::DOCUMENT_POSITION_CONTAINED_BY);    
   909 }
   911 bool
   912 nsINode::IsEqualNode(nsINode* aOther)
   913 {
   914   if (!aOther) {
   915     return false;
   916   }
   918   nsAutoString string1, string2;
   920   nsINode* node1 = this;
   921   nsINode* node2 = aOther;
   922   do {
   923     uint16_t nodeType = node1->NodeType();
   924     if (nodeType != node2->NodeType()) {
   925       return false;
   926     }
   928     nsINodeInfo* nodeInfo1 = node1->mNodeInfo;
   929     nsINodeInfo* nodeInfo2 = node2->mNodeInfo;
   930     if (!nodeInfo1->Equals(nodeInfo2) ||
   931         nodeInfo1->GetExtraName() != nodeInfo2->GetExtraName()) {
   932       return false;
   933     }
   935     switch(nodeType) {
   936       case nsIDOMNode::ELEMENT_NODE:
   937       {
   938         // Both are elements (we checked that their nodeinfos are equal). Do the
   939         // check on attributes.
   940         Element* element1 = node1->AsElement();
   941         Element* element2 = node2->AsElement();
   942         uint32_t attrCount = element1->GetAttrCount();
   943         if (attrCount != element2->GetAttrCount()) {
   944           return false;
   945         }
   947         // Iterate over attributes.
   948         for (uint32_t i = 0; i < attrCount; ++i) {
   949           const nsAttrName* attrName = element1->GetAttrNameAt(i);
   950 #ifdef DEBUG
   951           bool hasAttr =
   952 #endif
   953           element1->GetAttr(attrName->NamespaceID(), attrName->LocalName(),
   954                             string1);
   955           NS_ASSERTION(hasAttr, "Why don't we have an attr?");
   957           if (!element2->AttrValueIs(attrName->NamespaceID(),
   958                                      attrName->LocalName(),
   959                                      string1,
   960                                      eCaseMatters)) {
   961             return false;
   962           }
   963         }
   964         break;
   965       }
   966       case nsIDOMNode::TEXT_NODE:
   967       case nsIDOMNode::COMMENT_NODE:
   968       case nsIDOMNode::CDATA_SECTION_NODE:
   969       case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
   970       {
   971         string1.Truncate();
   972         static_cast<nsIContent*>(node1)->AppendTextTo(string1);
   973         string2.Truncate();
   974         static_cast<nsIContent*>(node2)->AppendTextTo(string2);
   976         if (!string1.Equals(string2)) {
   977           return false;
   978         }
   980         break;
   981       }
   982       case nsIDOMNode::DOCUMENT_NODE:
   983       case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
   984         break;
   985       case nsIDOMNode::ATTRIBUTE_NODE:
   986       {
   987         NS_ASSERTION(node1 == this && node2 == aOther,
   988                      "Did we come upon an attribute node while walking a "
   989                      "subtree?");
   990         node1->GetNodeValue(string1);
   991         node2->GetNodeValue(string2);
   993         // Returning here as to not bother walking subtree. And there is no
   994         // risk that we're half way through walking some other subtree since
   995         // attribute nodes doesn't appear in subtrees.
   996         return string1.Equals(string2);
   997       }
   998       case nsIDOMNode::DOCUMENT_TYPE_NODE:
   999       {
  1000         nsCOMPtr<nsIDOMDocumentType> docType1 = do_QueryInterface(node1);
  1001         nsCOMPtr<nsIDOMDocumentType> docType2 = do_QueryInterface(node2);
  1003         NS_ASSERTION(docType1 && docType2, "Why don't we have a document type node?");
  1005         // Public ID
  1006         docType1->GetPublicId(string1);
  1007         docType2->GetPublicId(string2);
  1008         if (!string1.Equals(string2)) {
  1009           return false;
  1012         // System ID
  1013         docType1->GetSystemId(string1);
  1014         docType2->GetSystemId(string2);
  1015         if (!string1.Equals(string2)) {
  1016           return false;
  1019         // Internal subset
  1020         docType1->GetInternalSubset(string1);
  1021         docType2->GetInternalSubset(string2);
  1022         if (!string1.Equals(string2)) {
  1023           return false;
  1026         break;
  1028       default:
  1029         NS_ABORT_IF_FALSE(false, "Unknown node type");
  1032     nsINode* nextNode = node1->GetFirstChild();
  1033     if (nextNode) {
  1034       node1 = nextNode;
  1035       node2 = node2->GetFirstChild();
  1037     else {
  1038       if (node2->GetFirstChild()) {
  1039         // node2 has a firstChild, but node1 doesn't
  1040         return false;
  1043       // Find next sibling, possibly walking parent chain.
  1044       while (1) {
  1045         if (node1 == this) {
  1046           NS_ASSERTION(node2 == aOther, "Should have reached the start node "
  1047                                         "for both trees at the same time");
  1048           return true;
  1051         nextNode = node1->GetNextSibling();
  1052         if (nextNode) {
  1053           node1 = nextNode;
  1054           node2 = node2->GetNextSibling();
  1055           break;
  1058         if (node2->GetNextSibling()) {
  1059           // node2 has a nextSibling, but node1 doesn't
  1060           return false;
  1063         node1 = node1->GetParentNode();
  1064         node2 = node2->GetParentNode();
  1065         NS_ASSERTION(node1 && node2, "no parent while walking subtree");
  1068   } while(node2);
  1070   return false;
  1073 void
  1074 nsINode::LookupNamespaceURI(const nsAString& aNamespacePrefix,
  1075                             nsAString& aNamespaceURI)
  1077   Element *element = GetNameSpaceElement();
  1078   if (!element ||
  1079       NS_FAILED(element->LookupNamespaceURIInternal(aNamespacePrefix,
  1080                                                     aNamespaceURI))) {
  1081     SetDOMStringToNull(aNamespaceURI);
  1085 NS_IMPL_DOMTARGET_DEFAULTS(nsINode)
  1087 NS_IMETHODIMP
  1088 nsINode::AddEventListener(const nsAString& aType,
  1089                           nsIDOMEventListener *aListener,
  1090                           bool aUseCapture,
  1091                           bool aWantsUntrusted,
  1092                           uint8_t aOptionalArgc)
  1094   NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
  1095                "Won't check if this is chrome, you want to set "
  1096                "aWantsUntrusted to false or make the aWantsUntrusted "
  1097                "explicit by making aOptionalArgc non-zero.");
  1099   if (!aWantsUntrusted &&
  1100       (aOptionalArgc < 2 &&
  1101        !nsContentUtils::IsChromeDoc(OwnerDoc()))) {
  1102     aWantsUntrusted = true;
  1105   EventListenerManager* listener_manager = GetOrCreateListenerManager();
  1106   NS_ENSURE_STATE(listener_manager);
  1107   listener_manager->AddEventListener(aType, aListener, aUseCapture,
  1108                                      aWantsUntrusted);
  1109   return NS_OK;
  1112 void
  1113 nsINode::AddEventListener(const nsAString& aType,
  1114                           EventListener* aListener,
  1115                           bool aUseCapture,
  1116                           const Nullable<bool>& aWantsUntrusted,
  1117                           ErrorResult& aRv)
  1119   bool wantsUntrusted;
  1120   if (aWantsUntrusted.IsNull()) {
  1121     wantsUntrusted = !nsContentUtils::IsChromeDoc(OwnerDoc());
  1122   } else {
  1123     wantsUntrusted = aWantsUntrusted.Value();
  1126   EventListenerManager* listener_manager = GetOrCreateListenerManager();
  1127   if (!listener_manager) {
  1128     aRv.Throw(NS_ERROR_UNEXPECTED);
  1129     return;
  1131   listener_manager->AddEventListener(aType, aListener, aUseCapture,
  1132                                      wantsUntrusted);
  1135 NS_IMETHODIMP
  1136 nsINode::AddSystemEventListener(const nsAString& aType,
  1137                                 nsIDOMEventListener *aListener,
  1138                                 bool aUseCapture,
  1139                                 bool aWantsUntrusted,
  1140                                 uint8_t aOptionalArgc)
  1142   NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
  1143                "Won't check if this is chrome, you want to set "
  1144                "aWantsUntrusted to false or make the aWantsUntrusted "
  1145                "explicit by making aOptionalArgc non-zero.");
  1147   if (!aWantsUntrusted &&
  1148       (aOptionalArgc < 2 &&
  1149        !nsContentUtils::IsChromeDoc(OwnerDoc()))) {
  1150     aWantsUntrusted = true;
  1153   return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
  1154                                    aWantsUntrusted);
  1157 NS_IMETHODIMP
  1158 nsINode::RemoveEventListener(const nsAString& aType,
  1159                              nsIDOMEventListener* aListener,
  1160                              bool aUseCapture)
  1162   EventListenerManager* elm = GetExistingListenerManager();
  1163   if (elm) {
  1164     elm->RemoveEventListener(aType, aListener, aUseCapture);
  1166   return NS_OK;
  1169 NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsINode)
  1171 nsresult
  1172 nsINode::PreHandleEvent(EventChainPreVisitor& aVisitor)
  1174   // This is only here so that we can use the NS_DECL_NSIDOMTARGET macro
  1175   NS_ABORT();
  1176   return NS_ERROR_NOT_IMPLEMENTED;
  1179 void
  1180 nsINode::GetBoxQuads(const BoxQuadOptions& aOptions,
  1181                      nsTArray<nsRefPtr<DOMQuad> >& aResult,
  1182                      mozilla::ErrorResult& aRv)
  1184   mozilla::GetBoxQuads(this, aOptions, aResult, aRv);
  1187 already_AddRefed<DOMQuad>
  1188 nsINode::ConvertQuadFromNode(DOMQuad& aQuad,
  1189                              const GeometryNode& aFrom,
  1190                              const ConvertCoordinateOptions& aOptions,
  1191                              ErrorResult& aRv)
  1193   return mozilla::ConvertQuadFromNode(this, aQuad, aFrom, aOptions, aRv);
  1196 already_AddRefed<DOMQuad>
  1197 nsINode::ConvertRectFromNode(DOMRectReadOnly& aRect,
  1198                              const GeometryNode& aFrom,
  1199                              const ConvertCoordinateOptions& aOptions,
  1200                              ErrorResult& aRv)
  1202   return mozilla::ConvertRectFromNode(this, aRect, aFrom, aOptions, aRv);
  1205 already_AddRefed<DOMPoint>
  1206 nsINode::ConvertPointFromNode(const DOMPointInit& aPoint,
  1207                               const GeometryNode& aFrom,
  1208                               const ConvertCoordinateOptions& aOptions,
  1209                               ErrorResult& aRv)
  1211   return mozilla::ConvertPointFromNode(this, aPoint, aFrom, aOptions, aRv);
  1214 nsresult
  1215 nsINode::DispatchEvent(nsIDOMEvent *aEvent, bool* aRetVal)
  1217   // XXX sXBL/XBL2 issue -- do we really want the owner here?  What
  1218   // if that's the XBL document?  Would we want its presshell?  Or what?
  1219   nsCOMPtr<nsIDocument> document = OwnerDoc();
  1221   // Do nothing if the element does not belong to a document
  1222   if (!document) {
  1223     *aRetVal = true;
  1224     return NS_OK;
  1227   // Obtain a presentation shell
  1228   nsIPresShell *shell = document->GetShell();
  1229   nsRefPtr<nsPresContext> context;
  1230   if (shell) {
  1231     context = shell->GetPresContext();
  1234   nsEventStatus status = nsEventStatus_eIgnore;
  1235   nsresult rv =
  1236     EventDispatcher::DispatchDOMEvent(this, nullptr, aEvent, context, &status);
  1237   *aRetVal = (status != nsEventStatus_eConsumeNoDefault);
  1238   return rv;
  1241 nsresult
  1242 nsINode::PostHandleEvent(EventChainPostVisitor& /*aVisitor*/)
  1244   return NS_OK;
  1247 nsresult
  1248 nsINode::DispatchDOMEvent(WidgetEvent* aEvent,
  1249                           nsIDOMEvent* aDOMEvent,
  1250                           nsPresContext* aPresContext,
  1251                           nsEventStatus* aEventStatus)
  1253   return EventDispatcher::DispatchDOMEvent(this, aEvent, aDOMEvent,
  1254                                            aPresContext, aEventStatus);
  1257 EventListenerManager*
  1258 nsINode::GetOrCreateListenerManager()
  1260   return nsContentUtils::GetListenerManagerForNode(this);
  1263 EventListenerManager*
  1264 nsINode::GetExistingListenerManager() const
  1266   return nsContentUtils::GetExistingListenerManagerForNode(this);
  1269 nsIScriptContext*
  1270 nsINode::GetContextForEventHandlers(nsresult* aRv)
  1272   return nsContentUtils::GetContextForEventHandlers(this, aRv);
  1275 nsIDOMWindow*
  1276 nsINode::GetOwnerGlobal()
  1278   bool dummy;
  1279   return nsPIDOMWindow::GetOuterFromCurrentInner(
  1280     static_cast<nsGlobalWindow*>(OwnerDoc()->GetScriptHandlingObject(dummy)));
  1283 bool
  1284 nsINode::UnoptimizableCCNode() const
  1286   const uintptr_t problematicFlags = (NODE_IS_ANONYMOUS_ROOT |
  1287                                       NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE |
  1288                                       NODE_IS_NATIVE_ANONYMOUS_ROOT |
  1289                                       NODE_MAY_BE_IN_BINDING_MNGR |
  1290                                       NODE_IS_IN_SHADOW_TREE);
  1291   return HasFlag(problematicFlags) ||
  1292          NodeType() == nsIDOMNode::ATTRIBUTE_NODE ||
  1293          // For strange cases like xbl:content/xbl:children
  1294          (IsElement() &&
  1295           AsElement()->IsInNamespace(kNameSpaceID_XBL));
  1298 /* static */
  1299 bool
  1300 nsINode::Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb)
  1302   if (MOZ_LIKELY(!cb.WantAllTraces())) {
  1303     nsIDocument *currentDoc = tmp->GetCurrentDoc();
  1304     if (currentDoc &&
  1305         nsCCUncollectableMarker::InGeneration(currentDoc->GetMarkedCCGeneration())) {
  1306       return false;
  1309     if (nsCCUncollectableMarker::sGeneration) {
  1310       // If we're black no need to traverse.
  1311       if (tmp->IsBlack() || tmp->InCCBlackTree()) {
  1312         return false;
  1315       if (!tmp->UnoptimizableCCNode()) {
  1316         // If we're in a black document, return early.
  1317         if ((currentDoc && currentDoc->IsBlack())) {
  1318           return false;
  1320         // If we're not in anonymous content and we have a black parent,
  1321         // return early.
  1322         nsIContent* parent = tmp->GetParent();
  1323         if (parent && !parent->UnoptimizableCCNode() && parent->IsBlack()) {
  1324           NS_ABORT_IF_FALSE(parent->IndexOf(tmp) >= 0, "Parent doesn't own us?");
  1325           return false;
  1331   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfo)
  1332   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(GetParent())
  1334   nsSlots *slots = tmp->GetExistingSlots();
  1335   if (slots) {
  1336     slots->Traverse(cb);
  1339   if (tmp->HasProperties()) {
  1340     nsNodeUtils::TraverseUserData(tmp, cb);
  1341     nsCOMArray<nsISupports>* objects =
  1342       static_cast<nsCOMArray<nsISupports>*>(tmp->GetProperty(nsGkAtoms::keepobjectsalive));
  1343     if (objects) {
  1344       for (int32_t i = 0; i < objects->Count(); ++i) {
  1345          cb.NoteXPCOMChild(objects->ObjectAt(i));
  1350   if (tmp->NodeType() != nsIDOMNode::DOCUMENT_NODE &&
  1351       tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) {
  1352     nsContentUtils::TraverseListenerManager(tmp, cb);
  1355   return true;
  1358 /* static */
  1359 void
  1360 nsINode::Unlink(nsINode* tmp)
  1362   tmp->ReleaseWrapper(tmp);
  1364   nsSlots *slots = tmp->GetExistingSlots();
  1365   if (slots) {
  1366     slots->Unlink();
  1369   if (tmp->NodeType() != nsIDOMNode::DOCUMENT_NODE &&
  1370       tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) {
  1371     nsContentUtils::RemoveListenerManager(tmp);
  1372     tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER);
  1375   if (tmp->HasProperties()) {
  1376     nsNodeUtils::UnlinkUserData(tmp);
  1377     tmp->DeleteProperty(nsGkAtoms::keepobjectsalive);
  1381 static void
  1382 ReleaseURI(void*, /* aObject*/
  1383            nsIAtom*, /* aPropertyName */
  1384            void* aPropertyValue,
  1385            void* /* aData */)
  1387   nsIURI* uri = static_cast<nsIURI*>(aPropertyValue);
  1388   NS_RELEASE(uri);
  1391 nsresult
  1392 nsINode::SetExplicitBaseURI(nsIURI* aURI)
  1394   nsresult rv = SetProperty(nsGkAtoms::baseURIProperty, aURI, ReleaseURI);
  1395   if (NS_SUCCEEDED(rv)) {
  1396     SetHasExplicitBaseURI();
  1397     NS_ADDREF(aURI);
  1399   return rv;
  1402 static nsresult
  1403 AdoptNodeIntoOwnerDoc(nsINode *aParent, nsINode *aNode)
  1405   NS_ASSERTION(!aNode->GetParentNode(),
  1406                "Should have removed from parent already");
  1408   nsIDocument *doc = aParent->OwnerDoc();
  1410   nsresult rv;
  1411   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc, &rv);
  1412   NS_ENSURE_SUCCESS(rv, rv);
  1414   nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode, &rv);
  1415   NS_ENSURE_SUCCESS(rv, rv);
  1417   nsCOMPtr<nsIDOMNode> adoptedNode;
  1418   rv = domDoc->AdoptNode(node, getter_AddRefs(adoptedNode));
  1419   NS_ENSURE_SUCCESS(rv, rv);
  1421   NS_ASSERTION(aParent->OwnerDoc() == doc,
  1422                "ownerDoc chainged while adopting");
  1423   NS_ASSERTION(adoptedNode == node, "Uh, adopt node changed nodes?");
  1424   NS_ASSERTION(aParent->OwnerDoc() == aNode->OwnerDoc(),
  1425                "ownerDocument changed again after adopting!");
  1427   return NS_OK;
  1430 static nsresult
  1431 CheckForOutdatedParent(nsINode* aParent, nsINode* aNode)
  1433   if (JSObject* existingObjUnrooted = aNode->GetWrapper()) {
  1434     AutoJSContext cx;
  1435     JS::Rooted<JSObject*> existingObj(cx, existingObjUnrooted);
  1436     nsIGlobalObject* global = aParent->OwnerDoc()->GetScopeObject();
  1437     MOZ_ASSERT(global);
  1439     if (js::GetGlobalForObjectCrossCompartment(existingObj) !=
  1440         global->GetGlobalJSObject()) {
  1441       JSAutoCompartment ac(cx, existingObj);
  1442       nsresult rv = ReparentWrapper(cx, existingObj);
  1443       NS_ENSURE_SUCCESS(rv, rv);
  1447   return NS_OK;
  1450 nsresult
  1451 nsINode::doInsertChildAt(nsIContent* aKid, uint32_t aIndex,
  1452                          bool aNotify, nsAttrAndChildArray& aChildArray)
  1454   NS_PRECONDITION(!aKid->GetParentNode(),
  1455                   "Inserting node that already has parent");
  1456   nsresult rv;
  1458   // The id-handling code, and in the future possibly other code, need to
  1459   // react to unexpected attribute changes.
  1460   nsMutationGuard::DidMutate();
  1462   // Do this before checking the child-count since this could cause mutations
  1463   nsIDocument* doc = GetCurrentDoc();
  1464   mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, aNotify);
  1466   if (OwnerDoc() != aKid->OwnerDoc()) {
  1467     rv = AdoptNodeIntoOwnerDoc(this, aKid);
  1468     NS_ENSURE_SUCCESS(rv, rv);
  1469   } else if (OwnerDoc()->DidDocumentOpen()) {
  1470     rv = CheckForOutdatedParent(this, aKid);
  1471     NS_ENSURE_SUCCESS(rv, rv);
  1474   uint32_t childCount = aChildArray.ChildCount();
  1475   NS_ENSURE_TRUE(aIndex <= childCount, NS_ERROR_ILLEGAL_VALUE);
  1476   bool isAppend = (aIndex == childCount);
  1478   rv = aChildArray.InsertChildAt(aKid, aIndex);
  1479   NS_ENSURE_SUCCESS(rv, rv);
  1480   if (aIndex == 0) {
  1481     mFirstChild = aKid;
  1484   nsIContent* parent =
  1485     IsNodeOfType(eDOCUMENT) ? nullptr : static_cast<nsIContent*>(this);
  1487   rv = aKid->BindToTree(doc, parent,
  1488                         parent ? parent->GetBindingParent() : nullptr,
  1489                         true);
  1490   if (NS_FAILED(rv)) {
  1491     if (GetFirstChild() == aKid) {
  1492       mFirstChild = aKid->GetNextSibling();
  1494     aChildArray.RemoveChildAt(aIndex);
  1495     aKid->UnbindFromTree();
  1496     return rv;
  1499   NS_ASSERTION(aKid->GetParentNode() == this,
  1500                "Did we run script inappropriately?");
  1502   if (aNotify) {
  1503     // Note that we always want to call ContentInserted when things are added
  1504     // as kids to documents
  1505     if (parent && isAppend) {
  1506       nsNodeUtils::ContentAppended(parent, aKid, aIndex);
  1507     } else {
  1508       nsNodeUtils::ContentInserted(this, aKid, aIndex);
  1511     if (nsContentUtils::HasMutationListeners(aKid,
  1512           NS_EVENT_BITS_MUTATION_NODEINSERTED, this)) {
  1513       InternalMutationEvent mutation(true, NS_MUTATION_NODEINSERTED);
  1514       mutation.mRelatedNode = do_QueryInterface(this);
  1516       mozAutoSubtreeModified subtree(OwnerDoc(), this);
  1517       (new AsyncEventDispatcher(aKid, mutation))->RunDOMEventWhenSafe();
  1521   return NS_OK;
  1524 Element*
  1525 nsINode::GetPreviousElementSibling() const
  1527   nsIContent* previousSibling = GetPreviousSibling();
  1528   while (previousSibling) {
  1529     if (previousSibling->IsElement()) {
  1530       return previousSibling->AsElement();
  1532     previousSibling = previousSibling->GetPreviousSibling();
  1535   return nullptr;
  1538 Element*
  1539 nsINode::GetNextElementSibling() const
  1541   nsIContent* nextSibling = GetNextSibling();
  1542   while (nextSibling) {
  1543     if (nextSibling->IsElement()) {
  1544       return nextSibling->AsElement();
  1546     nextSibling = nextSibling->GetNextSibling();
  1549   return nullptr;
  1552 void
  1553 nsINode::Remove()
  1555   nsCOMPtr<nsINode> parent = GetParentNode();
  1556   if (!parent) {
  1557     return;
  1559   int32_t index = parent->IndexOf(this);
  1560   if (index < 0) {
  1561     NS_WARNING("Ignoring call to nsINode::Remove on anonymous child.");
  1562     return;
  1564   parent->RemoveChildAt(uint32_t(index), true);
  1567 Element*
  1568 nsINode::GetFirstElementChild() const
  1570   for (nsIContent* child = GetFirstChild();
  1571        child;
  1572        child = child->GetNextSibling()) {
  1573     if (child->IsElement()) {
  1574       return child->AsElement();
  1578   return nullptr;
  1581 Element*
  1582 nsINode::GetLastElementChild() const
  1584   for (nsIContent* child = GetLastChild();
  1585        child;
  1586        child = child->GetPreviousSibling()) {
  1587     if (child->IsElement()) {
  1588       return child->AsElement();
  1592   return nullptr;
  1595 void
  1596 nsINode::doRemoveChildAt(uint32_t aIndex, bool aNotify,
  1597                          nsIContent* aKid, nsAttrAndChildArray& aChildArray)
  1599   NS_PRECONDITION(aKid && aKid->GetParentNode() == this &&
  1600                   aKid == GetChildAt(aIndex) &&
  1601                   IndexOf(aKid) == (int32_t)aIndex, "Bogus aKid");
  1603   nsMutationGuard::DidMutate();
  1605   nsIDocument* doc = GetCurrentDoc();
  1607   mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, aNotify);
  1609   nsIContent* previousSibling = aKid->GetPreviousSibling();
  1611   if (GetFirstChild() == aKid) {
  1612     mFirstChild = aKid->GetNextSibling();
  1615   aChildArray.RemoveChildAt(aIndex);
  1617   if (aNotify) {
  1618     nsNodeUtils::ContentRemoved(this, aKid, aIndex, previousSibling);
  1621   aKid->UnbindFromTree();
  1624 // When replacing, aRefChild is the content being replaced; when
  1625 // inserting it's the content before which we're inserting.  In the
  1626 // latter case it may be null.
  1627 static
  1628 bool IsAllowedAsChild(nsIContent* aNewChild, nsINode* aParent,
  1629                       bool aIsReplace, nsINode* aRefChild)
  1631   MOZ_ASSERT(aNewChild, "Must have new child");
  1632   MOZ_ASSERT_IF(aIsReplace, aRefChild);
  1633   MOZ_ASSERT(aParent);
  1634   MOZ_ASSERT(aParent->IsNodeOfType(nsINode::eDOCUMENT) ||
  1635              aParent->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT) ||
  1636              aParent->IsElement(),
  1637              "Nodes that are not documents, document fragments or elements "
  1638              "can't be parents!");
  1640   // A common case is that aNewChild has no kids, in which case
  1641   // aParent can't be a descendant of aNewChild unless they're
  1642   // actually equal to each other.  Fast-path that case, since aParent
  1643   // could be pretty deep in the DOM tree.
  1644   if (aNewChild == aParent ||
  1645       ((aNewChild->GetFirstChild() ||
  1646         // HTML template elements and ShadowRoot hosts need
  1647         // to be checked to ensure that they are not inserted into
  1648         // the hosted content.
  1649         aNewChild->Tag() == nsGkAtoms::_template ||
  1650         aNewChild->GetShadowRoot()) &&
  1651        nsContentUtils::ContentIsHostIncludingDescendantOf(aParent,
  1652                                                           aNewChild))) {
  1653     return false;
  1656   // The allowed child nodes differ for documents and elements
  1657   switch (aNewChild->NodeType()) {
  1658   case nsIDOMNode::COMMENT_NODE :
  1659   case nsIDOMNode::PROCESSING_INSTRUCTION_NODE :
  1660     // OK in both cases
  1661     return true;
  1662   case nsIDOMNode::TEXT_NODE :
  1663   case nsIDOMNode::CDATA_SECTION_NODE :
  1664   case nsIDOMNode::ENTITY_REFERENCE_NODE :
  1665     // Allowed under Elements and DocumentFragments
  1666     return aParent->NodeType() != nsIDOMNode::DOCUMENT_NODE;
  1667   case nsIDOMNode::ELEMENT_NODE :
  1669       if (!aParent->IsNodeOfType(nsINode::eDOCUMENT)) {
  1670         // Always ok to have elements under other elements or document fragments
  1671         return true;
  1674       nsIDocument* parentDocument = static_cast<nsIDocument*>(aParent);
  1675       Element* rootElement = parentDocument->GetRootElement();
  1676       if (rootElement) {
  1677         // Already have a documentElement, so this is only OK if we're
  1678         // replacing it.
  1679         return aIsReplace && rootElement == aRefChild;
  1682       // We don't have a documentElement yet.  Our one remaining constraint is
  1683       // that the documentElement must come after the doctype.
  1684       if (!aRefChild) {
  1685         // Appending is just fine.
  1686         return true;
  1689       nsIContent* docTypeContent = parentDocument->GetDoctype();
  1690       if (!docTypeContent) {
  1691         // It's all good.
  1692         return true;
  1695       int32_t doctypeIndex = aParent->IndexOf(docTypeContent);
  1696       int32_t insertIndex = aParent->IndexOf(aRefChild);
  1698       // Now we're OK in the following two cases only:
  1699       // 1) We're replacing something that's not before the doctype
  1700       // 2) We're inserting before something that comes after the doctype 
  1701       return aIsReplace ? (insertIndex >= doctypeIndex) :
  1702         insertIndex > doctypeIndex;
  1704   case nsIDOMNode::DOCUMENT_TYPE_NODE :
  1706       if (!aParent->IsNodeOfType(nsINode::eDOCUMENT)) {
  1707         // doctypes only allowed under documents
  1708         return false;
  1711       nsIDocument* parentDocument = static_cast<nsIDocument*>(aParent);
  1712       nsIContent* docTypeContent = parentDocument->GetDoctype();
  1713       if (docTypeContent) {
  1714         // Already have a doctype, so this is only OK if we're replacing it
  1715         return aIsReplace && docTypeContent == aRefChild;
  1718       // We don't have a doctype yet.  Our one remaining constraint is
  1719       // that the doctype must come before the documentElement.
  1720       Element* rootElement = parentDocument->GetRootElement();
  1721       if (!rootElement) {
  1722         // It's all good
  1723         return true;
  1726       if (!aRefChild) {
  1727         // Trying to append a doctype, but have a documentElement
  1728         return false;
  1731       int32_t rootIndex = aParent->IndexOf(rootElement);
  1732       int32_t insertIndex = aParent->IndexOf(aRefChild);
  1734       // Now we're OK if and only if insertIndex <= rootIndex.  Indeed, either
  1735       // we end up replacing aRefChild or we end up before it.  Either one is
  1736       // ok as long as aRefChild is not after rootElement.
  1737       return insertIndex <= rootIndex;
  1739   case nsIDOMNode::DOCUMENT_FRAGMENT_NODE :
  1741       // Note that for now we only allow nodes inside document fragments if
  1742       // they're allowed inside elements.  If we ever change this to allow
  1743       // doctype nodes in document fragments, we'll need to update this code.
  1744       // Also, there's a version of this code in ReplaceOrInsertBefore.  If you
  1745       // change this code, change that too.
  1746       if (!aParent->IsNodeOfType(nsINode::eDOCUMENT)) {
  1747         // All good here
  1748         return true;
  1751       bool sawElement = false;
  1752       for (nsIContent* child = aNewChild->GetFirstChild();
  1753            child;
  1754            child = child->GetNextSibling()) {
  1755         if (child->IsElement()) {
  1756           if (sawElement) {
  1757             // Can't put two elements into a document
  1758             return false;
  1760           sawElement = true;
  1762         // If we can put this content at the the right place, we might be ok;
  1763         // if not, we bail out.
  1764         if (!IsAllowedAsChild(child, aParent, aIsReplace, aRefChild)) {
  1765           return false;
  1769       // Everything in the fragment checked out ok, so we can stick it in here
  1770       return true;
  1772   default:
  1773     /*
  1774      * aNewChild is of invalid type.
  1775      */
  1776     break;
  1779   return false;
  1782 nsINode*
  1783 nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild,
  1784                                nsINode* aRefChild, ErrorResult& aError)
  1786   // XXXbz I wish I could assert that nsContentUtils::IsSafeToRunScript() so we
  1787   // could rely on scriptblockers going out of scope to actually run XBL
  1788   // teardown, but various crud adds nodes under scriptblockers (e.g. native
  1789   // anonymous content).  The only good news is those insertions can't trigger
  1790   // the bad XBL cases.
  1791   MOZ_ASSERT_IF(aReplace, aRefChild);
  1793   if ((!IsNodeOfType(eDOCUMENT) &&
  1794        !IsNodeOfType(eDOCUMENT_FRAGMENT) &&
  1795        !IsElement()) ||
  1796       !aNewChild->IsNodeOfType(eCONTENT)) {
  1797     aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
  1798     return nullptr;
  1801   uint16_t nodeType = aNewChild->NodeType();
  1803   // Before we do anything else, fire all DOMNodeRemoved mutation events
  1804   // We do this up front as to avoid having to deal with script running
  1805   // at random places further down.
  1806   // Scope firing mutation events so that we don't carry any state that
  1807   // might be stale
  1809     // This check happens again further down (though then using IndexOf).
  1810     // We're only checking this here to avoid firing mutation events when
  1811     // none should be fired.
  1812     // It's ok that we do the check twice in the case when firing mutation
  1813     // events as we need to recheck after running script anyway.
  1814     if (aRefChild && aRefChild->GetParentNode() != this) {
  1815       aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
  1816       return nullptr;
  1819     // If we're replacing, fire for node-to-be-replaced.
  1820     // If aRefChild == aNewChild then we'll fire for it in check below
  1821     if (aReplace && aRefChild != aNewChild) {
  1822       nsContentUtils::MaybeFireNodeRemoved(aRefChild, this, OwnerDoc());
  1825     // If the new node already has a parent, fire for removing from old
  1826     // parent
  1827     nsINode* oldParent = aNewChild->GetParentNode();
  1828     if (oldParent) {
  1829       nsContentUtils::MaybeFireNodeRemoved(aNewChild, oldParent,
  1830                                            aNewChild->OwnerDoc());
  1833     // If we're inserting a fragment, fire for all the children of the
  1834     // fragment
  1835     if (nodeType == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
  1836       static_cast<FragmentOrElement*>(aNewChild)->FireNodeRemovedForChildren();
  1838     // Verify that our aRefChild is still sensible
  1839     if (aRefChild && aRefChild->GetParentNode() != this) {
  1840       aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
  1841       return nullptr;
  1845   nsIDocument* doc = OwnerDoc();
  1846   nsIContent* newContent = static_cast<nsIContent*>(aNewChild);
  1847   if (newContent->IsRootOfAnonymousSubtree()) {
  1848     // This is anonymous content.  Don't allow its insertion
  1849     // anywhere, since it might have UnbindFromTree calls coming
  1850     // its way.
  1851     aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
  1852     return nullptr;
  1855   // Make sure that the inserted node is allowed as a child of its new parent.
  1856   if (!IsAllowedAsChild(newContent, this, aReplace, aRefChild)) {
  1857     aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
  1858     return nullptr;
  1861   // Record the node to insert before, if any
  1862   nsINode* nodeToInsertBefore;
  1863   if (aReplace) {
  1864     nodeToInsertBefore = aRefChild->GetNextSibling();
  1865   } else {
  1866     nodeToInsertBefore = aRefChild;
  1868   if (nodeToInsertBefore == aNewChild) {
  1869     // We're going to remove aNewChild from its parent, so use its next sibling
  1870     // as the node to insert before.
  1871     nodeToInsertBefore = nodeToInsertBefore->GetNextSibling();
  1874   Maybe<nsAutoTArray<nsCOMPtr<nsIContent>, 50> > fragChildren;
  1876   // Remove the new child from the old parent if one exists
  1877   nsCOMPtr<nsINode> oldParent = newContent->GetParentNode();
  1878   if (oldParent) {
  1879     int32_t removeIndex = oldParent->IndexOf(newContent);
  1880     if (removeIndex < 0) {
  1881       // newContent is anonymous.  We can't deal with this, so just bail
  1882       NS_ERROR("How come our flags didn't catch this?");
  1883       aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
  1884       return nullptr;
  1887     // Hold a strong ref to nodeToInsertBefore across the removal of newContent
  1888     nsCOMPtr<nsINode> kungFuDeathGrip = nodeToInsertBefore;
  1890     // Removing a child can run script, via XBL destructors.
  1891     nsMutationGuard guard;
  1893     // Scope for the mutation batch and scriptblocker, so they go away
  1894     // while kungFuDeathGrip is still alive.
  1896       mozAutoDocUpdate batch(newContent->GetCurrentDoc(),
  1897                              UPDATE_CONTENT_MODEL, true);
  1898       nsAutoMutationBatch mb(oldParent, true, true);
  1899       oldParent->RemoveChildAt(removeIndex, true);
  1900       if (nsAutoMutationBatch::GetCurrentBatch() == &mb) {
  1901         mb.RemovalDone();
  1902         mb.SetPrevSibling(oldParent->GetChildAt(removeIndex - 1));
  1903         mb.SetNextSibling(oldParent->GetChildAt(removeIndex));
  1907     // We expect one mutation (the removal) to have happened.
  1908     if (guard.Mutated(1)) {
  1909       // XBL destructors, yuck.
  1911       // Verify that nodeToInsertBefore, if non-null, is still our child.  If
  1912       // it's not, there's no way we can do this insert sanely; just bail out.
  1913       if (nodeToInsertBefore && nodeToInsertBefore->GetParent() != this) {
  1914         aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
  1915         return nullptr;
  1918       // Verify that newContent has no parent.
  1919       if (newContent->GetParentNode()) {
  1920         aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
  1921         return nullptr;
  1924       // And verify that newContent is still allowed as our child.
  1925       if (aNewChild == aRefChild) {
  1926         // We've already removed aRefChild.  So even if we were doing a replace,
  1927         // now we're doing a simple insert before nodeToInsertBefore.
  1928         if (!IsAllowedAsChild(newContent, this, false, nodeToInsertBefore)) {
  1929           aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
  1930           return nullptr;
  1932       } else {
  1933         if ((aRefChild && aRefChild->GetParent() != this) ||
  1934             !IsAllowedAsChild(newContent, this, aReplace, aRefChild)) {
  1935           aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
  1936           return nullptr;
  1938         // And recompute nodeToInsertBefore, just in case.
  1939         if (aReplace) {
  1940           nodeToInsertBefore = aRefChild->GetNextSibling();
  1941         } else {
  1942           nodeToInsertBefore = aRefChild;
  1946   } else if (nodeType == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
  1947     // Make sure to remove all the fragment's kids.  We need to do this before
  1948     // we start inserting anything, so we will run out XBL destructors and
  1949     // binding teardown (GOD, I HATE THESE THINGS) before we insert anything
  1950     // into the DOM.
  1951     uint32_t count = newContent->GetChildCount();
  1953     fragChildren.construct();
  1955     // Copy the children into a separate array to avoid having to deal with
  1956     // mutations to the fragment later on here.
  1957     fragChildren.ref().SetCapacity(count);
  1958     for (nsIContent* child = newContent->GetFirstChild();
  1959          child;
  1960          child = child->GetNextSibling()) {
  1961       NS_ASSERTION(child->GetCurrentDoc() == nullptr,
  1962                    "How did we get a child with a current doc?");
  1963       fragChildren.ref().AppendElement(child);
  1966     // Hold a strong ref to nodeToInsertBefore across the removals
  1967     nsCOMPtr<nsINode> kungFuDeathGrip = nodeToInsertBefore;
  1969     nsMutationGuard guard;
  1971     // Scope for the mutation batch and scriptblocker, so they go away
  1972     // while kungFuDeathGrip is still alive.
  1974       mozAutoDocUpdate batch(newContent->GetCurrentDoc(),
  1975                              UPDATE_CONTENT_MODEL, true);
  1976       nsAutoMutationBatch mb(newContent, false, true);
  1978       for (uint32_t i = count; i > 0;) {
  1979         newContent->RemoveChildAt(--i, true);
  1983     // We expect |count| removals
  1984     if (guard.Mutated(count)) {
  1985       // XBL destructors, yuck.
  1987       // Verify that nodeToInsertBefore, if non-null, is still our child.  If
  1988       // it's not, there's no way we can do this insert sanely; just bail out.
  1989       if (nodeToInsertBefore && nodeToInsertBefore->GetParent() != this) {
  1990         aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
  1991         return nullptr;
  1994       // Verify that all the things in fragChildren have no parent.
  1995       for (uint32_t i = 0; i < count; ++i) {
  1996         if (fragChildren.ref().ElementAt(i)->GetParentNode()) {
  1997           aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
  1998           return nullptr;
  2002       // Note that unlike the single-element case above, none of our kids can
  2003       // be aRefChild, so we can always pass through aReplace in the
  2004       // IsAllowedAsChild checks below and don't have to worry about whether
  2005       // recomputing nodeToInsertBefore is OK.
  2007       // Verify that our aRefChild is still sensible
  2008       if (aRefChild && aRefChild->GetParent() != this) {
  2009         aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
  2010         return nullptr;
  2013       // Recompute nodeToInsertBefore, just in case.
  2014       if (aReplace) {
  2015         nodeToInsertBefore = aRefChild->GetNextSibling();
  2016       } else {
  2017         nodeToInsertBefore = aRefChild;
  2020       // And verify that newContent is still allowed as our child.  Sadly, we
  2021       // need to reimplement the relevant part of IsAllowedAsChild() because
  2022       // now our nodes are in an array and all.  If you change this code,
  2023       // change the code there.
  2024       if (IsNodeOfType(nsINode::eDOCUMENT)) {
  2025         bool sawElement = false;
  2026         for (uint32_t i = 0; i < count; ++i) {
  2027           nsIContent* child = fragChildren.ref().ElementAt(i);
  2028           if (child->IsElement()) {
  2029             if (sawElement) {
  2030               // No good
  2031               aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
  2032               return nullptr;
  2034             sawElement = true;
  2036           if (!IsAllowedAsChild(child, this, aReplace, aRefChild)) {
  2037             aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
  2038             return nullptr;
  2045   mozAutoDocUpdate batch(GetCurrentDoc(), UPDATE_CONTENT_MODEL, true);
  2046   nsAutoMutationBatch mb;
  2048   // Figure out which index we want to insert at.  Note that we use
  2049   // nodeToInsertBefore to determine this, because it's possible that
  2050   // aRefChild == aNewChild, in which case we just removed it from the
  2051   // parent list.
  2052   int32_t insPos;
  2053   if (nodeToInsertBefore) {
  2054     insPos = IndexOf(nodeToInsertBefore);
  2055     if (insPos < 0) {
  2056       // XXXbz How the heck would _that_ happen, exactly?
  2057       aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
  2058       return nullptr;
  2061   else {
  2062     insPos = GetChildCount();
  2065   // If we're replacing and we haven't removed aRefChild yet, do so now
  2066   if (aReplace && aRefChild != aNewChild) {
  2067     mb.Init(this, true, true);
  2069     // Since aRefChild is never null in the aReplace case, we know that at
  2070     // this point nodeToInsertBefore is the next sibling of aRefChild.
  2071     NS_ASSERTION(aRefChild->GetNextSibling() == nodeToInsertBefore,
  2072                  "Unexpected nodeToInsertBefore");
  2074     // An since nodeToInsertBefore is at index insPos, we want to remove
  2075     // at the previous index.
  2076     NS_ASSERTION(insPos >= 1, "insPos too small");
  2077     RemoveChildAt(insPos-1, true);
  2078     --insPos;
  2081   // Move new child over to our document if needed. Do this after removing
  2082   // it from its parent so that AdoptNode doesn't fire DOMNodeRemoved
  2083   // DocumentType nodes are the only nodes that can have a null
  2084   // ownerDocument according to the DOM spec, and we need to allow
  2085   // inserting them w/o calling AdoptNode().
  2086   if (doc != newContent->OwnerDoc()) {
  2087     aError = AdoptNodeIntoOwnerDoc(this, aNewChild);
  2088     if (aError.Failed()) {
  2089       return nullptr;
  2091   } else if (doc->DidDocumentOpen()) {
  2092     aError = CheckForOutdatedParent(this, aNewChild);
  2093     if (aError.Failed()) {
  2094       return nullptr;
  2098   /*
  2099    * Check if we're inserting a document fragment. If we are, we need
  2100    * to actually add its children individually (i.e. we don't add the
  2101    * actual document fragment).
  2102    */
  2103   nsINode* result = aReplace ? aRefChild : aNewChild;
  2104   if (nodeType == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
  2105     if (!aReplace) {
  2106       mb.Init(this, true, true);
  2108     nsAutoMutationBatch* mutationBatch = nsAutoMutationBatch::GetCurrentBatch();
  2109     if (mutationBatch) {
  2110       mutationBatch->RemovalDone();
  2111       mutationBatch->SetPrevSibling(GetChildAt(insPos - 1));
  2112       mutationBatch->SetNextSibling(GetChildAt(insPos));
  2115     uint32_t count = fragChildren.ref().Length();
  2116     if (!count) {
  2117       return result;
  2120     bool appending =
  2121       !IsNodeOfType(eDOCUMENT) && uint32_t(insPos) == GetChildCount();
  2122     int32_t firstInsPos = insPos;
  2123     nsIContent* firstInsertedContent = fragChildren.ref().ElementAt(0);
  2125     // Iterate through the fragment's children, and insert them in the new
  2126     // parent
  2127     for (uint32_t i = 0; i < count; ++i, ++insPos) {
  2128       // XXXbz how come no reparenting here?  That seems odd...
  2129       // Insert the child.
  2130       aError = InsertChildAt(fragChildren.ref().ElementAt(i), insPos,
  2131                              !appending);
  2132       if (aError.Failed()) {
  2133         // Make sure to notify on any children that we did succeed to insert
  2134         if (appending && i != 0) {
  2135           nsNodeUtils::ContentAppended(static_cast<nsIContent*>(this),
  2136                                        firstInsertedContent,
  2137                                        firstInsPos);
  2139         return nullptr;
  2143     if (mutationBatch && !appending) {
  2144       mutationBatch->NodesAdded();
  2147     // Notify and fire mutation events when appending
  2148     if (appending) {
  2149       nsNodeUtils::ContentAppended(static_cast<nsIContent*>(this),
  2150                                    firstInsertedContent, firstInsPos);
  2151       if (mutationBatch) {
  2152         mutationBatch->NodesAdded();
  2154       // Optimize for the case when there are no listeners
  2155       if (nsContentUtils::
  2156             HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEINSERTED)) {
  2157         Element::FireNodeInserted(doc, this, fragChildren.ref());
  2161   else {
  2162     // Not inserting a fragment but rather a single node.
  2164     // FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=544654
  2165     //       We need to reparent here for nodes for which the parent of their
  2166     //       wrapper is not the wrapper for their ownerDocument (XUL elements,
  2167     //       form controls, ...). Also applies in the fragment code above.
  2169     if (nsAutoMutationBatch::GetCurrentBatch() == &mb) {
  2170       mb.RemovalDone();
  2171       mb.SetPrevSibling(GetChildAt(insPos - 1));
  2172       mb.SetNextSibling(GetChildAt(insPos));
  2174     aError = InsertChildAt(newContent, insPos, true);
  2175     if (aError.Failed()) {
  2176       return nullptr;
  2180   return result;
  2183 nsresult
  2184 nsINode::ReplaceOrInsertBefore(bool aReplace, nsIDOMNode *aNewChild,
  2185                                nsIDOMNode *aRefChild, nsIDOMNode **aReturn)
  2187   nsCOMPtr<nsINode> newChild = do_QueryInterface(aNewChild);
  2188   if (!newChild) {
  2189     return NS_ERROR_NULL_POINTER;
  2192   if (aReplace && !aRefChild) {
  2193     return NS_ERROR_NULL_POINTER;
  2196   nsCOMPtr<nsINode> refChild = do_QueryInterface(aRefChild);
  2197   if (aRefChild && !refChild) {
  2198     return NS_NOINTERFACE;
  2201   ErrorResult rv;
  2202   nsINode* result = ReplaceOrInsertBefore(aReplace, newChild, refChild, rv);
  2203   if (result) {
  2204     NS_ADDREF(*aReturn = result->AsDOMNode());
  2206   return rv.ErrorCode();
  2209 nsresult
  2210 nsINode::CompareDocumentPosition(nsIDOMNode* aOther, uint16_t* aReturn)
  2212   nsCOMPtr<nsINode> other = do_QueryInterface(aOther);
  2213   NS_ENSURE_ARG(other);
  2214   *aReturn = CompareDocumentPosition(*other);
  2215   return NS_OK;
  2218 nsresult
  2219 nsINode::IsEqualNode(nsIDOMNode* aOther, bool* aReturn)
  2221   nsCOMPtr<nsINode> other = do_QueryInterface(aOther);
  2222   *aReturn = IsEqualNode(other);
  2223   return NS_OK;
  2226 void
  2227 nsINode::BindObject(nsISupports* aObject)
  2229   nsCOMArray<nsISupports>* objects =
  2230     static_cast<nsCOMArray<nsISupports>*>(GetProperty(nsGkAtoms::keepobjectsalive));
  2231   if (!objects) {
  2232     objects = new nsCOMArray<nsISupports>();
  2233     SetProperty(nsGkAtoms::keepobjectsalive, objects,
  2234                 nsINode::DeleteProperty< nsCOMArray<nsISupports> >, true);
  2236   objects->AppendObject(aObject);
  2239 void
  2240 nsINode::UnbindObject(nsISupports* aObject)
  2242   nsCOMArray<nsISupports>* objects =
  2243     static_cast<nsCOMArray<nsISupports>*>(GetProperty(nsGkAtoms::keepobjectsalive));
  2244   if (objects) {
  2245     objects->RemoveObject(aObject);
  2249 void
  2250 nsINode::GetBoundMutationObservers(nsTArray<nsRefPtr<nsDOMMutationObserver> >& aResult)
  2252   nsCOMArray<nsISupports>* objects =
  2253     static_cast<nsCOMArray<nsISupports>*>(GetProperty(nsGkAtoms::keepobjectsalive));
  2254   if (objects) {
  2255     for (int32_t i = 0; i < objects->Count(); ++i) {
  2256       nsCOMPtr<nsDOMMutationObserver> mo = do_QueryInterface(objects->ObjectAt(i));
  2257       if (mo) {
  2258         MOZ_ASSERT(!aResult.Contains(mo));
  2259         aResult.AppendElement(mo);
  2265 size_t
  2266 nsINode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
  2268   size_t n = 0;
  2269   EventListenerManager* elm = GetExistingListenerManager();
  2270   if (elm) {
  2271     n += elm->SizeOfIncludingThis(aMallocSizeOf);
  2274   // Measurement of the following members may be added later if DMD finds it is
  2275   // worthwhile:
  2276   // - mNodeInfo
  2277   // - mSlots
  2278   //
  2279   // The following members are not measured:
  2280   // - mParent, mNextSibling, mPreviousSibling, mFirstChild: because they're
  2281   //   non-owning
  2282   return n;
  2285 #define EVENT(name_, id_, type_, struct_)                                    \
  2286   EventHandlerNonNull* nsINode::GetOn##name_() {                             \
  2287     EventListenerManager *elm = GetExistingListenerManager();                \
  2288     return elm ? elm->GetEventHandler(nsGkAtoms::on##name_, EmptyString())   \
  2289                : nullptr;                                                    \
  2290   }                                                                          \
  2291   void nsINode::SetOn##name_(EventHandlerNonNull* handler)                   \
  2292   {                                                                          \
  2293     EventListenerManager *elm = GetOrCreateListenerManager();                \
  2294     if (elm) {                                                               \
  2295       elm->SetEventHandler(nsGkAtoms::on##name_, EmptyString(), handler);    \
  2296     }                                                                        \
  2298 #define TOUCH_EVENT EVENT
  2299 #define DOCUMENT_ONLY_EVENT EVENT
  2300 #include "mozilla/EventNameList.h"
  2301 #undef DOCUMENT_ONLY_EVENT
  2302 #undef TOUCH_EVENT
  2303 #undef EVENT
  2305 bool
  2306 nsINode::Contains(const nsINode* aOther) const
  2308   if (aOther == this) {
  2309     return true;
  2311   if (!aOther ||
  2312       OwnerDoc() != aOther->OwnerDoc() ||
  2313       IsInDoc() != aOther->IsInDoc() ||
  2314       !(aOther->IsElement() ||
  2315         aOther->IsNodeOfType(nsINode::eCONTENT)) ||
  2316       !GetFirstChild()) {
  2317     return false;
  2320   const nsIContent* other = static_cast<const nsIContent*>(aOther);
  2321   if (this == OwnerDoc()) {
  2322     // document.contains(aOther) returns true if aOther is in the document,
  2323     // but is not in any anonymous subtree.
  2324     // IsInDoc() check is done already before this.
  2325     return !other->IsInAnonymousSubtree();
  2328   if (!IsElement() && !IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT)) {
  2329     return false;
  2332   const nsIContent* thisContent = static_cast<const nsIContent*>(this);
  2333   if (thisContent->GetBindingParent() != other->GetBindingParent()) {
  2334     return false;
  2337   return nsContentUtils::ContentIsDescendantOf(other, this);
  2340 nsresult
  2341 nsINode::Contains(nsIDOMNode* aOther, bool* aReturn)
  2343   nsCOMPtr<nsINode> node = do_QueryInterface(aOther);
  2344   *aReturn = Contains(node);
  2345   return NS_OK;
  2348 uint32_t
  2349 nsINode::Length() const
  2351   switch (NodeType()) {
  2352   case nsIDOMNode::DOCUMENT_TYPE_NODE:
  2353     return 0;
  2355   case nsIDOMNode::TEXT_NODE:
  2356   case nsIDOMNode::CDATA_SECTION_NODE:
  2357   case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
  2358   case nsIDOMNode::COMMENT_NODE:
  2359     MOZ_ASSERT(IsNodeOfType(eCONTENT));
  2360     return static_cast<const nsIContent*>(this)->TextLength();
  2362   default:
  2363     return GetChildCount();
  2367 nsCSSSelectorList*
  2368 nsINode::ParseSelectorList(const nsAString& aSelectorString,
  2369                            ErrorResult& aRv)
  2371   nsIDocument* doc = OwnerDoc();
  2372   nsIDocument::SelectorCache& cache = doc->GetSelectorCache();
  2373   nsCSSSelectorList* selectorList = nullptr;
  2374   bool haveCachedList = cache.GetList(aSelectorString, &selectorList);
  2375   if (haveCachedList) {
  2376     if (!selectorList) {
  2377       // Invalid selector.
  2378       aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
  2380     return selectorList;
  2383   nsCSSParser parser(doc->CSSLoader());
  2385   aRv = parser.ParseSelectorString(aSelectorString,
  2386                                    doc->GetDocumentURI(),
  2387                                    0, // XXXbz get the line number!
  2388                                    &selectorList);
  2389   if (aRv.Failed()) {
  2390     // We hit this for syntax errors, which are quite common, so don't
  2391     // use NS_ENSURE_SUCCESS.  (For example, jQuery has an extended set
  2392     // of selectors, but it sees if we can parse them first.)
  2393     MOZ_ASSERT(aRv.ErrorCode() == NS_ERROR_DOM_SYNTAX_ERR,
  2394                "Unexpected error, so cached version won't return it");
  2395     cache.CacheList(aSelectorString, nullptr);
  2396     return nullptr;
  2399   // Filter out pseudo-element selectors from selectorList
  2400   nsCSSSelectorList** slot = &selectorList;
  2401   do {
  2402     nsCSSSelectorList* cur = *slot;
  2403     if (cur->mSelectors->IsPseudoElement()) {
  2404       *slot = cur->mNext;
  2405       cur->mNext = nullptr;
  2406       delete cur;
  2407     } else {
  2408       slot = &cur->mNext;
  2410   } while (*slot);
  2412   if (selectorList) {
  2413     NS_ASSERTION(selectorList->mSelectors,
  2414                  "How can we not have any selectors?");
  2415     cache.CacheList(aSelectorString, selectorList);
  2416   } else {
  2417     // This is the "only pseudo-element selectors" case, which is
  2418     // not common, so just don't worry about caching it.  That way a
  2419     // null cached value can always indicate an invalid selector.
  2422   return selectorList;
  2425 static void
  2426 AddScopeElements(TreeMatchContext& aMatchContext,
  2427                  nsINode* aMatchContextNode)
  2429   if (aMatchContextNode->IsElement()) {
  2430     aMatchContext.SetHasSpecifiedScope();
  2431     aMatchContext.AddScopeElement(aMatchContextNode->AsElement());
  2435 namespace {
  2436 struct SelectorMatchInfo {
  2437   nsCSSSelectorList* const mSelectorList;
  2438   TreeMatchContext& mMatchContext;
  2439 };
  2442 // Given an id, find elements with that id under aRoot that match aMatchInfo if
  2443 // any is provided.  If no SelectorMatchInfo is provided, just find the ones
  2444 // with the given id.  aRoot must be in the document.
  2445 template<bool onlyFirstMatch, class T>
  2446 inline static void
  2447 FindMatchingElementsWithId(const nsAString& aId, nsINode* aRoot,
  2448                            SelectorMatchInfo* aMatchInfo,
  2449                            T& aList)
  2451   MOZ_ASSERT(aRoot->IsInDoc(),
  2452              "Don't call me if the root is not in the document");
  2453   MOZ_ASSERT(aRoot->IsElement() || aRoot->IsNodeOfType(nsINode::eDOCUMENT),
  2454              "The optimization below to check ContentIsDescendantOf only for "
  2455              "elements depends on aRoot being either an element or a "
  2456              "document if it's in the document.  Note that document fragments "
  2457              "can't be IsInDoc(), so should never show up here.");
  2459   const nsSmallVoidArray* elements = aRoot->OwnerDoc()->GetAllElementsForId(aId);
  2461   if (!elements) {
  2462     // Nothing to do; we're done
  2463     return;
  2466   // XXXbz: Should we fall back to the tree walk if aRoot is not the
  2467   // document and |elements| is long, for some value of "long"?
  2468   for (int32_t i = 0; i < elements->Count(); ++i) {
  2469     Element *element = static_cast<Element*>(elements->ElementAt(i));
  2470     if (!aRoot->IsElement() ||
  2471         (element != aRoot &&
  2472            nsContentUtils::ContentIsDescendantOf(element, aRoot))) {
  2473       // We have an element with the right id and it's a strict descendant
  2474       // of aRoot.  Make sure it really matches the selector.
  2475       if (!aMatchInfo ||
  2476           nsCSSRuleProcessor::SelectorListMatches(element,
  2477                                                   aMatchInfo->mMatchContext,
  2478                                                   aMatchInfo->mSelectorList)) {
  2479         aList.AppendElement(element);
  2480         if (onlyFirstMatch) {
  2481           return;
  2488 // Actually find elements matching aSelectorList (which must not be
  2489 // null) and which are descendants of aRoot and put them in aList.  If
  2490 // onlyFirstMatch, then stop once the first one is found.
  2491 template<bool onlyFirstMatch, class Collector, class T>
  2492 MOZ_ALWAYS_INLINE static void
  2493 FindMatchingElements(nsINode* aRoot, nsCSSSelectorList* aSelectorList, T &aList,
  2494                      ErrorResult& aRv)
  2496   nsIDocument* doc = aRoot->OwnerDoc();
  2498   TreeMatchContext matchingContext(false, nsRuleWalker::eRelevantLinkUnvisited,
  2499                                    doc, TreeMatchContext::eNeverMatchVisited);
  2500   doc->FlushPendingLinkUpdates();
  2501   AddScopeElements(matchingContext, aRoot);
  2503   // Fast-path selectors involving IDs.  We can only do this if aRoot
  2504   // is in the document and the document is not in quirks mode, since
  2505   // ID selectors are case-insensitive in quirks mode.  Also, only do
  2506   // this if aSelectorList only has one selector, because otherwise
  2507   // ordering the elements correctly is a pain.
  2508   NS_ASSERTION(aRoot->IsElement() || aRoot->IsNodeOfType(nsINode::eDOCUMENT) ||
  2509                !aRoot->IsInDoc(),
  2510                "The optimization below to check ContentIsDescendantOf only for "
  2511                "elements depends on aRoot being either an element or a "
  2512                "document if it's in the document.");
  2513   if (aRoot->IsInDoc() &&
  2514       doc->GetCompatibilityMode() != eCompatibility_NavQuirks &&
  2515       !aSelectorList->mNext &&
  2516       aSelectorList->mSelectors->mIDList) {
  2517     nsIAtom* id = aSelectorList->mSelectors->mIDList->mAtom;
  2518     SelectorMatchInfo info = { aSelectorList, matchingContext };
  2519     FindMatchingElementsWithId<onlyFirstMatch, T>(nsDependentAtomString(id),
  2520                                                   aRoot, &info, aList);
  2521     return;
  2524   Collector results;
  2525   for (nsIContent* cur = aRoot->GetFirstChild();
  2526        cur;
  2527        cur = cur->GetNextNode(aRoot)) {
  2528     if (cur->IsElement() &&
  2529         nsCSSRuleProcessor::SelectorListMatches(cur->AsElement(),
  2530                                                 matchingContext,
  2531                                                 aSelectorList)) {
  2532       if (onlyFirstMatch) {
  2533         aList.AppendElement(cur->AsElement());
  2534         return;
  2536       results.AppendElement(cur->AsElement());
  2540   const uint32_t len = results.Length();
  2541   if (len) {
  2542     aList.SetCapacity(len);
  2543     for (uint32_t i = 0; i < len; ++i) {
  2544       aList.AppendElement(results.ElementAt(i));
  2549 struct ElementHolder {
  2550   ElementHolder() : mElement(nullptr) {}
  2551   void AppendElement(Element* aElement) {
  2552     NS_ABORT_IF_FALSE(!mElement, "Should only get one element");
  2553     mElement = aElement;
  2555   void SetCapacity(uint32_t aCapacity) { MOZ_CRASH("Don't call me!"); }
  2556   uint32_t Length() { return 0; }
  2557   Element* ElementAt(uint32_t aIndex) { return nullptr; }
  2559   Element* mElement;
  2560 };
  2562 Element*
  2563 nsINode::QuerySelector(const nsAString& aSelector, ErrorResult& aResult)
  2565   nsCSSSelectorList* selectorList = ParseSelectorList(aSelector, aResult);
  2566   if (!selectorList) {
  2567     // Either we failed (and aResult already has the exception), or this
  2568     // is a pseudo-element-only selector that matches nothing.
  2569     return nullptr;
  2571   ElementHolder holder;
  2572   FindMatchingElements<true, ElementHolder>(this, selectorList, holder, aResult);
  2573   return holder.mElement;
  2576 already_AddRefed<nsINodeList>
  2577 nsINode::QuerySelectorAll(const nsAString& aSelector, ErrorResult& aResult)
  2579   nsRefPtr<nsSimpleContentList> contentList = new nsSimpleContentList(this);
  2581   nsCSSSelectorList* selectorList = ParseSelectorList(aSelector, aResult);
  2582   if (selectorList) {
  2583     FindMatchingElements<false, nsAutoTArray<Element*, 128>>(this,
  2584                                                              selectorList,
  2585                                                              *contentList,
  2586                                                              aResult);
  2587   } else {
  2588     // Either we failed (and aResult already has the exception), or this
  2589     // is a pseudo-element-only selector that matches nothing.
  2592   return contentList.forget();
  2595 nsresult
  2596 nsINode::QuerySelector(const nsAString& aSelector, nsIDOMElement **aReturn)
  2598   ErrorResult rv;
  2599   Element* result = nsINode::QuerySelector(aSelector, rv);
  2600   if (rv.Failed()) {
  2601     return rv.ErrorCode();
  2603   nsCOMPtr<nsIDOMElement> elt = do_QueryInterface(result);
  2604   elt.forget(aReturn);
  2605   return NS_OK;
  2608 nsresult
  2609 nsINode::QuerySelectorAll(const nsAString& aSelector, nsIDOMNodeList **aReturn)
  2611   ErrorResult rv;
  2612   *aReturn = nsINode::QuerySelectorAll(aSelector, rv).take();
  2613   return rv.ErrorCode();
  2616 Element*
  2617 nsINode::GetElementById(const nsAString& aId)
  2619   MOZ_ASSERT(IsElement() || IsNodeOfType(eDOCUMENT_FRAGMENT),
  2620              "Bogus this object for GetElementById call");
  2621   if (IsInDoc()) {
  2622     ElementHolder holder;
  2623     FindMatchingElementsWithId<true>(aId, this, nullptr, holder);
  2624     return holder.mElement;
  2627   for (nsIContent* kid = GetFirstChild(); kid; kid = kid->GetNextNode(this)) {
  2628     if (!kid->IsElement()) {
  2629       continue;
  2631     nsIAtom* id = kid->AsElement()->GetID();
  2632     if (id && id->Equals(aId)) {
  2633       return kid->AsElement();
  2636   return nullptr;
  2639 JSObject*
  2640 nsINode::WrapObject(JSContext *aCx)
  2642   MOZ_ASSERT(IsDOMBinding());
  2644   // Make sure one of these is true
  2645   // (1) our owner document has a script handling object,
  2646   // (2) Our owner document has had a script handling object, or has been marked
  2647   //     to have had one,
  2648   // (3) we are running a privileged script.
  2649   // Event handling is possible only if (1). If (2) event handling is
  2650   // prevented.
  2651   // If the document has never had a script handling object, untrusted
  2652   // scripts (3) shouldn't touch it!
  2653   bool hasHadScriptHandlingObject = false;
  2654   if (!OwnerDoc()->GetScriptHandlingObject(hasHadScriptHandlingObject) &&
  2655       !hasHadScriptHandlingObject &&
  2656       !nsContentUtils::IsCallerChrome()) {
  2657     Throw(aCx, NS_ERROR_UNEXPECTED);
  2658     return nullptr;
  2661   JS::Rooted<JSObject*> obj(aCx, WrapNode(aCx));
  2662   MOZ_ASSERT_IF(ChromeOnlyAccess(),
  2663                 xpc::IsInXBLScope(obj) || !xpc::UseXBLScope(js::GetObjectCompartment(obj)));
  2664   return obj;
  2667 already_AddRefed<nsINode>
  2668 nsINode::CloneNode(bool aDeep, ErrorResult& aError)
  2670   bool callUserDataHandlers = NodeType() != nsIDOMNode::DOCUMENT_NODE ||
  2671                               !static_cast<nsIDocument*>(this)->CreatingStaticClone();
  2673   nsCOMPtr<nsINode> result;
  2674   aError = nsNodeUtils::CloneNodeImpl(this, aDeep, callUserDataHandlers,
  2675                                       getter_AddRefs(result));
  2676   return result.forget();
  2679 nsDOMAttributeMap*
  2680 nsINode::GetAttributes()
  2682   if (!IsElement()) {
  2683     return nullptr;
  2685   return AsElement()->Attributes();
  2688 bool
  2689 EventTarget::DispatchEvent(Event& aEvent,
  2690                            ErrorResult& aRv)
  2692   bool result = false;
  2693   aRv = DispatchEvent(&aEvent, &result);
  2694   return result;

mercurial