LCOV - code coverage report
Current view: top level - dom/base - nsNodeUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 156 276 56.5 %
Date: 2017-07-14 16:53:18 Functions: 19 22 86.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsNodeUtils.h"
       8             : #include "nsContentUtils.h"
       9             : #include "nsCSSPseudoElements.h"
      10             : #include "nsINode.h"
      11             : #include "nsIContent.h"
      12             : #include "mozilla/dom/Element.h"
      13             : #include "nsIMutationObserver.h"
      14             : #include "nsIDocument.h"
      15             : #include "mozilla/EventListenerManager.h"
      16             : #include "nsIXPConnect.h"
      17             : #include "PLDHashTable.h"
      18             : #include "nsIDOMAttr.h"
      19             : #include "nsCOMArray.h"
      20             : #include "nsPIDOMWindow.h"
      21             : #include "nsDocument.h"
      22             : #ifdef MOZ_XUL
      23             : #include "nsXULElement.h"
      24             : #endif
      25             : #include "nsBindingManager.h"
      26             : #include "nsGenericHTMLElement.h"
      27             : #include "mozilla/AnimationTarget.h"
      28             : #include "mozilla/Assertions.h"
      29             : #include "mozilla/dom/Animation.h"
      30             : #include "mozilla/dom/HTMLImageElement.h"
      31             : #include "mozilla/dom/HTMLMediaElement.h"
      32             : #include "mozilla/dom/KeyframeEffectReadOnly.h"
      33             : #include "nsWrapperCacheInlines.h"
      34             : #include "nsObjectLoadingContent.h"
      35             : #include "nsDOMMutationObserver.h"
      36             : #include "mozilla/dom/BindingUtils.h"
      37             : #include "mozilla/dom/HTMLTemplateElement.h"
      38             : #include "mozilla/dom/ShadowRoot.h"
      39             : 
      40             : using namespace mozilla;
      41             : using namespace mozilla::dom;
      42             : using mozilla::AutoJSContext;
      43             : 
      44             : // This macro expects the ownerDocument of content_ to be in scope as
      45             : // |nsIDocument* doc|
      46             : #define IMPL_MUTATION_NOTIFICATION(func_, content_, params_)      \
      47             :   PR_BEGIN_MACRO                                                  \
      48             :   bool needsEnterLeave = doc->MayHaveDOMMutationObservers();      \
      49             :   if (needsEnterLeave) {                                          \
      50             :     nsDOMMutationObserver::EnterMutationHandling();               \
      51             :   }                                                               \
      52             :   nsINode* node = content_;                                       \
      53             :   NS_ASSERTION(node->OwnerDoc() == doc, "Bogus document");        \
      54             :   if (doc) {                                                      \
      55             :     doc->BindingManager()->func_ params_;                         \
      56             :   }                                                               \
      57             :   do {                                                            \
      58             :     nsINode::nsSlots* slots = node->GetExistingSlots();           \
      59             :     if (slots && !slots->mMutationObservers.IsEmpty()) {          \
      60             :       /* No need to explicitly notify the first observer first    \
      61             :          since that'll happen anyway. */                          \
      62             :       NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(                         \
      63             :         slots->mMutationObservers, nsIMutationObserver,           \
      64             :         func_, params_);                                          \
      65             :     }                                                             \
      66             :     ShadowRoot* shadow = ShadowRoot::FromNode(node);              \
      67             :     if (shadow) {                                                 \
      68             :       node = shadow->GetPoolHost();                               \
      69             :     } else {                                                      \
      70             :       node = node->GetParentNode();                               \
      71             :     }                                                             \
      72             :   } while (node);                                                 \
      73             :   if (needsEnterLeave) {                                          \
      74             :     nsDOMMutationObserver::LeaveMutationHandling();               \
      75             :   }                                                               \
      76             :   PR_END_MACRO
      77             : 
      78             : #define IMPL_ANIMATION_NOTIFICATION(func_, content_, params_)     \
      79             :   PR_BEGIN_MACRO                                                  \
      80             :   bool needsEnterLeave = doc->MayHaveDOMMutationObservers();      \
      81             :   if (needsEnterLeave) {                                          \
      82             :     nsDOMMutationObserver::EnterMutationHandling();               \
      83             :   }                                                               \
      84             :   nsINode* node = content_;                                       \
      85             :   do {                                                            \
      86             :     nsINode::nsSlots* slots = node->GetExistingSlots();           \
      87             :     if (slots && !slots->mMutationObservers.IsEmpty()) {          \
      88             :       /* No need to explicitly notify the first observer first    \
      89             :          since that'll happen anyway. */                          \
      90             :       NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS_WITH_QI(                 \
      91             :         slots->mMutationObservers, nsIMutationObserver,           \
      92             :         nsIAnimationObserver, func_, params_);                    \
      93             :     }                                                             \
      94             :     ShadowRoot* shadow = ShadowRoot::FromNode(node);              \
      95             :     if (shadow) {                                                 \
      96             :       node = shadow->GetPoolHost();                               \
      97             :     } else {                                                      \
      98             :       node = node->GetParentNode();                               \
      99             :     }                                                             \
     100             :   } while (node);                                                 \
     101             :   if (needsEnterLeave) {                                          \
     102             :     nsDOMMutationObserver::LeaveMutationHandling();               \
     103             :   }                                                               \
     104             :   PR_END_MACRO
     105             : 
     106             : void
     107           7 : nsNodeUtils::CharacterDataWillChange(nsIContent* aContent,
     108             :                                      CharacterDataChangeInfo* aInfo)
     109             : {
     110           7 :   nsIDocument* doc = aContent->OwnerDoc();
     111           7 :   IMPL_MUTATION_NOTIFICATION(CharacterDataWillChange, aContent,
     112             :                              (doc, aContent, aInfo));
     113           7 : }
     114             : 
     115             : void
     116           7 : nsNodeUtils::CharacterDataChanged(nsIContent* aContent,
     117             :                                   CharacterDataChangeInfo* aInfo)
     118             : {
     119           7 :   nsIDocument* doc = aContent->OwnerDoc();
     120           7 :   IMPL_MUTATION_NOTIFICATION(CharacterDataChanged, aContent,
     121             :                              (doc, aContent, aInfo));
     122           7 : }
     123             : 
     124             : void
     125         599 : nsNodeUtils::AttributeWillChange(Element* aElement,
     126             :                                  int32_t aNameSpaceID,
     127             :                                  nsIAtom* aAttribute,
     128             :                                  int32_t aModType,
     129             :                                  const nsAttrValue* aNewValue)
     130             : {
     131         599 :   nsIDocument* doc = aElement->OwnerDoc();
     132         599 :   IMPL_MUTATION_NOTIFICATION(AttributeWillChange, aElement,
     133             :                              (doc, aElement, aNameSpaceID, aAttribute,
     134             :                               aModType, aNewValue));
     135         599 : }
     136             : 
     137             : void
     138         595 : nsNodeUtils::AttributeChanged(Element* aElement,
     139             :                               int32_t aNameSpaceID,
     140             :                               nsIAtom* aAttribute,
     141             :                               int32_t aModType,
     142             :                               const nsAttrValue* aOldValue)
     143             : {
     144         595 :   nsIDocument* doc = aElement->OwnerDoc();
     145         595 :   IMPL_MUTATION_NOTIFICATION(AttributeChanged, aElement,
     146             :                              (doc, aElement, aNameSpaceID, aAttribute,
     147             :                               aModType, aOldValue));
     148         595 : }
     149             : 
     150             : void
     151         101 : nsNodeUtils::AttributeSetToCurrentValue(Element* aElement,
     152             :                                         int32_t aNameSpaceID,
     153             :                                         nsIAtom* aAttribute)
     154             : {
     155         101 :   nsIDocument* doc = aElement->OwnerDoc();
     156         101 :   IMPL_MUTATION_NOTIFICATION(AttributeSetToCurrentValue, aElement,
     157             :                              (doc, aElement, aNameSpaceID, aAttribute));
     158         101 : }
     159             : 
     160             : void
     161         143 : nsNodeUtils::ContentAppended(nsIContent* aContainer,
     162             :                              nsIContent* aFirstNewContent,
     163             :                              int32_t aNewIndexInContainer)
     164             : {
     165         143 :   nsIDocument* doc = aContainer->OwnerDoc();
     166             : 
     167         143 :   IMPL_MUTATION_NOTIFICATION(ContentAppended, aContainer,
     168             :                              (doc, aContainer, aFirstNewContent,
     169             :                               aNewIndexInContainer));
     170         143 : }
     171             : 
     172             : void
     173          49 : nsNodeUtils::NativeAnonymousChildListChange(nsIContent* aContent,
     174             :                                             bool aIsRemove)
     175             : {
     176          49 :   nsIDocument* doc = aContent->OwnerDoc();
     177          49 :   IMPL_MUTATION_NOTIFICATION(NativeAnonymousChildListChange, aContent,
     178             :                             (doc, aContent, aIsRemove));
     179          49 : }
     180             : 
     181             : void
     182          71 : nsNodeUtils::ContentInserted(nsINode* aContainer,
     183             :                              nsIContent* aChild,
     184             :                              int32_t aIndexInContainer)
     185             : {
     186          71 :   NS_PRECONDITION(aContainer->IsNodeOfType(nsINode::eCONTENT) ||
     187             :                   aContainer->IsNodeOfType(nsINode::eDOCUMENT),
     188             :                   "container must be an nsIContent or an nsIDocument");
     189             :   nsIContent* container;
     190          71 :   nsIDocument* doc = aContainer->OwnerDoc();
     191             :   nsIDocument* document;
     192          71 :   if (aContainer->IsNodeOfType(nsINode::eCONTENT)) {
     193          19 :     container = static_cast<nsIContent*>(aContainer);
     194          19 :     document = doc;
     195             :   }
     196             :   else {
     197          52 :     container = nullptr;
     198          52 :     document = static_cast<nsIDocument*>(aContainer);
     199             :   }
     200             : 
     201          71 :   IMPL_MUTATION_NOTIFICATION(ContentInserted, aContainer,
     202             :                              (document, container, aChild, aIndexInContainer));
     203          71 : }
     204             : 
     205             : void
     206          47 : nsNodeUtils::ContentRemoved(nsINode* aContainer,
     207             :                             nsIContent* aChild,
     208             :                             int32_t aIndexInContainer,
     209             :                             nsIContent* aPreviousSibling)
     210             : {
     211          47 :   NS_PRECONDITION(aContainer->IsNodeOfType(nsINode::eCONTENT) ||
     212             :                   aContainer->IsNodeOfType(nsINode::eDOCUMENT),
     213             :                   "container must be an nsIContent or an nsIDocument");
     214             :   nsIContent* container;
     215          47 :   nsIDocument* doc = aContainer->OwnerDoc();
     216             :   nsIDocument* document;
     217          47 :   if (aContainer->IsNodeOfType(nsINode::eCONTENT)) {
     218          47 :     container = static_cast<nsIContent*>(aContainer);
     219          47 :     document = doc;
     220             :   }
     221             :   else {
     222           0 :     container = nullptr;
     223           0 :     document = static_cast<nsIDocument*>(aContainer);
     224             :   }
     225             : 
     226          47 :   IMPL_MUTATION_NOTIFICATION(ContentRemoved, aContainer,
     227             :                              (document, container, aChild, aIndexInContainer,
     228             :                               aPreviousSibling));
     229          47 : }
     230             : 
     231             : Maybe<NonOwningAnimationTarget>
     232          10 : nsNodeUtils::GetTargetForAnimation(const Animation* aAnimation)
     233             : {
     234          10 :   AnimationEffectReadOnly* effect = aAnimation->GetEffect();
     235          10 :   if (!effect || !effect->AsKeyframeEffect()) {
     236           2 :     return Nothing();
     237             :   }
     238           8 :   return effect->AsKeyframeEffect()->GetTarget();
     239             : }
     240             : 
     241             : void
     242           6 : nsNodeUtils::AnimationMutated(Animation* aAnimation,
     243             :                               AnimationMutationType aMutatedType)
     244             : {
     245          12 :   Maybe<NonOwningAnimationTarget> target = GetTargetForAnimation(aAnimation);
     246           6 :   if (!target) {
     247           0 :     return;
     248             :   }
     249             : 
     250             :   // A pseudo element and its parent element use the same owner doc.
     251           6 :   nsIDocument* doc = target->mElement->OwnerDoc();
     252           6 :   if (doc->MayHaveAnimationObservers()) {
     253             :     // we use the its parent element as the subject in DOM Mutation Observer.
     254           0 :     Element* elem = target->mElement;
     255           0 :     switch (aMutatedType) {
     256             :       case AnimationMutationType::Added:
     257           0 :         IMPL_ANIMATION_NOTIFICATION(AnimationAdded, elem, (aAnimation));
     258           0 :         break;
     259             :       case AnimationMutationType::Changed:
     260           0 :         IMPL_ANIMATION_NOTIFICATION(AnimationChanged, elem, (aAnimation));
     261           0 :         break;
     262             :       case AnimationMutationType::Removed:
     263           0 :         IMPL_ANIMATION_NOTIFICATION(AnimationRemoved, elem, (aAnimation));
     264           0 :         break;
     265             :       default:
     266           0 :         MOZ_ASSERT_UNREACHABLE("unexpected mutation type");
     267             :     }
     268             :   }
     269             : }
     270             : 
     271             : void
     272           2 : nsNodeUtils::AnimationAdded(Animation* aAnimation)
     273             : {
     274           2 :   AnimationMutated(aAnimation, AnimationMutationType::Added);
     275           2 : }
     276             : 
     277             : void
     278           2 : nsNodeUtils::AnimationChanged(Animation* aAnimation)
     279             : {
     280           2 :   AnimationMutated(aAnimation, AnimationMutationType::Changed);
     281           2 : }
     282             : 
     283             : void
     284           2 : nsNodeUtils::AnimationRemoved(Animation* aAnimation)
     285             : {
     286           2 :   AnimationMutated(aAnimation, AnimationMutationType::Removed);
     287           2 : }
     288             : 
     289             : void
     290          47 : nsNodeUtils::LastRelease(nsINode* aNode)
     291             : {
     292          47 :   nsINode::nsSlots* slots = aNode->GetExistingSlots();
     293          47 :   if (slots) {
     294           4 :     if (!slots->mMutationObservers.IsEmpty()) {
     295           0 :       NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(slots->mMutationObservers,
     296             :                                          nsIMutationObserver,
     297             :                                          NodeWillBeDestroyed, (aNode));
     298             :     }
     299             : 
     300           4 :     if (aNode->IsElement()) {
     301           1 :       Element* elem = aNode->AsElement();
     302             :       FragmentOrElement::nsDOMSlots* domSlots =
     303           1 :         static_cast<FragmentOrElement::nsDOMSlots*>(slots);
     304           1 :       for (auto iter = domSlots->mRegisteredIntersectionObservers.Iter(); !iter.Done(); iter.Next()) {
     305           0 :         DOMIntersectionObserver* observer = iter.Key();
     306           0 :         observer->UnlinkTarget(*elem);
     307             :       }
     308             :     }
     309             : 
     310           4 :     delete slots;
     311           4 :     aNode->mSlots = nullptr;
     312             :   }
     313             : 
     314             :   // Kill properties first since that may run external code, so we want to
     315             :   // be in as complete state as possible at that time.
     316          47 :   if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) {
     317             :     // Delete all properties before tearing down the document. Some of the
     318             :     // properties are bound to nsINode objects and the destructor functions of
     319             :     // the properties may want to use the owner document of the nsINode.
     320           0 :     static_cast<nsIDocument*>(aNode)->DeleteAllProperties();
     321             :   }
     322             :   else {
     323          47 :     if (aNode->HasProperties()) {
     324             :       // Strong reference to the document so that deleting properties can't
     325             :       // delete the document.
     326           0 :       nsCOMPtr<nsIDocument> document = aNode->OwnerDoc();
     327           0 :       document->DeleteAllPropertiesFor(aNode);
     328             :     }
     329             : 
     330             :     // I wonder whether it's faster to do the HasFlag check first....
     331          47 :     if (aNode->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) &&
     332           0 :         aNode->HasFlag(ADDED_TO_FORM)) {
     333             :       // Tell the form (if any) this node is going away.  Don't
     334             :       // notify, since we're being destroyed in any case.
     335           0 :       static_cast<nsGenericHTMLFormElement*>(aNode)->ClearForm(true, true);
     336             :     }
     337             : 
     338          47 :     if (aNode->IsHTMLElement(nsGkAtoms::img) &&
     339           0 :         aNode->HasFlag(ADDED_TO_FORM)) {
     340           0 :       HTMLImageElement* imageElem = static_cast<HTMLImageElement*>(aNode);
     341           0 :       imageElem->ClearForm(true);
     342             :     }
     343             :   }
     344          47 :   aNode->UnsetFlags(NODE_HAS_PROPERTIES);
     345             : 
     346          94 :   if (aNode->NodeType() != nsIDOMNode::DOCUMENT_NODE &&
     347          47 :       aNode->HasFlag(NODE_HAS_LISTENERMANAGER)) {
     348             : #ifdef DEBUG
     349           3 :     if (nsContentUtils::IsInitialized()) {
     350             :       EventListenerManager* manager =
     351           3 :         nsContentUtils::GetExistingListenerManagerForNode(aNode);
     352           3 :       if (!manager) {
     353           0 :         NS_ERROR("Huh, our bit says we have a listener manager list, "
     354             :                  "but there's nothing in the hash!?!!");
     355             :       }
     356             :     }
     357             : #endif
     358             : 
     359           3 :     nsContentUtils::RemoveListenerManager(aNode);
     360           3 :     aNode->UnsetFlags(NODE_HAS_LISTENERMANAGER);
     361             :   }
     362             : 
     363          47 :   if (aNode->IsElement()) {
     364          42 :     nsIDocument* ownerDoc = aNode->OwnerDoc();
     365          42 :     Element* elem = aNode->AsElement();
     366          42 :     ownerDoc->ClearBoxObjectFor(elem);
     367             : 
     368          42 :     NS_ASSERTION(aNode->HasFlag(NODE_FORCE_XBL_BINDINGS) ||
     369             :                  !elem->GetXBLBinding(),
     370             :                  "Non-forced node has binding on destruction");
     371             : 
     372             :     // if NODE_FORCE_XBL_BINDINGS is set, the node might still have a binding
     373             :     // attached
     374          42 :     if (aNode->HasFlag(NODE_FORCE_XBL_BINDINGS) &&
     375           0 :         ownerDoc->BindingManager()) {
     376           0 :       ownerDoc->BindingManager()->RemovedFromDocument(elem, ownerDoc,
     377           0 :                                                       nsBindingManager::eRunDtor);
     378             :     }
     379             :   }
     380             : 
     381          47 :   aNode->ReleaseWrapper(aNode);
     382             : 
     383          47 :   FragmentOrElement::RemoveBlackMarkedNode(aNode);
     384          47 : }
     385             : 
     386             : static void
     387           0 : NoteUserData(void *aObject, nsIAtom *aKey, void *aXPCOMChild, void *aData)
     388             : {
     389             :   nsCycleCollectionTraversalCallback* cb =
     390           0 :     static_cast<nsCycleCollectionTraversalCallback*>(aData);
     391           0 :   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "[user data]");
     392           0 :   cb->NoteXPCOMChild(static_cast<nsISupports*>(aXPCOMChild));
     393           0 : }
     394             : 
     395             : /* static */
     396             : void
     397           1 : nsNodeUtils::TraverseUserData(nsINode* aNode,
     398             :                               nsCycleCollectionTraversalCallback &aCb)
     399             : {
     400           1 :   nsIDocument* ownerDoc = aNode->OwnerDoc();
     401           1 :   ownerDoc->PropertyTable(DOM_USER_DATA)->Enumerate(aNode, NoteUserData, &aCb);
     402           1 : }
     403             : 
     404             : /* static */
     405             : nsresult
     406           2 : nsNodeUtils::CloneNodeImpl(nsINode *aNode, bool aDeep, nsINode **aResult)
     407             : {
     408           2 :   *aResult = nullptr;
     409             : 
     410           4 :   nsCOMPtr<nsINode> newNode;
     411           2 :   nsresult rv = Clone(aNode, aDeep, nullptr, nullptr, getter_AddRefs(newNode));
     412           2 :   NS_ENSURE_SUCCESS(rv, rv);
     413             : 
     414           2 :   newNode.forget(aResult);
     415           2 :   return NS_OK;
     416             : }
     417             : 
     418             : /* static */
     419             : nsresult
     420         906 : nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep,
     421             :                            nsNodeInfoManager *aNewNodeInfoManager,
     422             :                            JS::Handle<JSObject*> aReparentScope,
     423             :                            nsCOMArray<nsINode> *aNodesWithProperties,
     424             :                            nsINode *aParent, nsINode **aResult)
     425             : {
     426         906 :   NS_PRECONDITION((!aClone && aNewNodeInfoManager) || !aReparentScope,
     427             :                   "If cloning or not getting a new nodeinfo we shouldn't "
     428             :                   "rewrap");
     429         906 :   NS_PRECONDITION(!aParent || aNode->IsNodeOfType(nsINode::eCONTENT),
     430             :                   "Can't insert document or attribute nodes into a parent");
     431             : 
     432         906 :   *aResult = nullptr;
     433             : 
     434             :   // First deal with aNode and walk its attributes (and their children). Then,
     435             :   // if aDeep is true, deal with aNode's children (and recurse into their
     436             :   // attributes and children).
     437             : 
     438        1812 :   nsAutoScriptBlocker scriptBlocker;
     439             :   nsresult rv;
     440             : 
     441         906 :   nsNodeInfoManager *nodeInfoManager = aNewNodeInfoManager;
     442             : 
     443             :   // aNode.
     444         906 :   NodeInfo *nodeInfo = aNode->mNodeInfo;
     445        1812 :   RefPtr<NodeInfo> newNodeInfo;
     446         906 :   if (nodeInfoManager) {
     447             : 
     448             :     // Don't allow importing/adopting nodes from non-privileged "scriptable"
     449             :     // documents to "non-scriptable" documents.
     450         881 :     nsIDocument* newDoc = nodeInfoManager->GetDocument();
     451         881 :     NS_ENSURE_STATE(newDoc);
     452         881 :     bool hasHadScriptHandlingObject = false;
     453         881 :     if (!newDoc->GetScriptHandlingObject(hasHadScriptHandlingObject) &&
     454           0 :         !hasHadScriptHandlingObject) {
     455           0 :       nsIDocument* currentDoc = aNode->OwnerDoc();
     456           0 :       NS_ENSURE_STATE((nsContentUtils::IsChromeDoc(currentDoc) ||
     457             :                        (!currentDoc->GetScriptHandlingObject(hasHadScriptHandlingObject) &&
     458             :                         !hasHadScriptHandlingObject)));
     459             :     }
     460             : 
     461        2643 :     newNodeInfo = nodeInfoManager->GetNodeInfo(nodeInfo->NameAtom(),
     462             :                                                nodeInfo->GetPrefixAtom(),
     463             :                                                nodeInfo->NamespaceID(),
     464         881 :                                                nodeInfo->NodeType(),
     465         881 :                                                nodeInfo->GetExtraName());
     466             : 
     467         881 :     nodeInfo = newNodeInfo;
     468             :   }
     469             : 
     470         906 :   Element *elem = aNode->IsElement() ? aNode->AsElement() : nullptr;
     471             : 
     472        1812 :   nsCOMPtr<nsINode> clone;
     473         906 :   if (aClone) {
     474         906 :     rv = aNode->Clone(nodeInfo, getter_AddRefs(clone), aDeep);
     475         906 :     NS_ENSURE_SUCCESS(rv, rv);
     476             : 
     477         906 :     if (clone->IsElement()) {
     478             :       // The cloned node may be a custom element that may require
     479             :       // enqueing created callback and prototype swizzling.
     480         883 :       Element* elem = clone->AsElement();
     481         883 :       if (nsContentUtils::IsCustomElementName(nodeInfo->NameAtom())) {
     482           0 :         nsContentUtils::SetupCustomElement(elem);
     483             :       } else {
     484             :         // Check if node may be custom element by type extension.
     485             :         // ex. <button is="x-button">
     486        1766 :         nsAutoString extension;
     487         883 :         if (elem->GetAttr(kNameSpaceID_None, nsGkAtoms::is, extension) &&
     488           0 :             !extension.IsEmpty()) {
     489           0 :           nsContentUtils::SetupCustomElement(elem, &extension);
     490             :         }
     491             :       }
     492             :     }
     493             : 
     494         906 :     if (aParent) {
     495             :       // If we're cloning we need to insert the cloned children into the cloned
     496             :       // parent.
     497         730 :       rv = aParent->AppendChildTo(static_cast<nsIContent*>(clone.get()),
     498         730 :                                   false);
     499         730 :       NS_ENSURE_SUCCESS(rv, rv);
     500             :     }
     501         176 :     else if (aDeep && clone->IsNodeOfType(nsINode::eDOCUMENT)) {
     502             :       // After cloning the document itself, we want to clone the children into
     503             :       // the cloned document (somewhat like cloning and importing them into the
     504             :       // cloned document).
     505           0 :       nodeInfoManager = clone->mNodeInfo->NodeInfoManager();
     506             :     }
     507             :   }
     508           0 :   else if (nodeInfoManager) {
     509           0 :     nsIDocument* oldDoc = aNode->OwnerDoc();
     510           0 :     bool wasRegistered = false;
     511           0 :     if (aNode->IsElement()) {
     512           0 :       Element* element = aNode->AsElement();
     513           0 :       oldDoc->ClearBoxObjectFor(element);
     514           0 :       wasRegistered = oldDoc->UnregisterActivityObserver(element);
     515             :     }
     516             : 
     517           0 :     aNode->mNodeInfo.swap(newNodeInfo);
     518           0 :     if (elem) {
     519           0 :       elem->NodeInfoChanged(oldDoc);
     520             :     }
     521             : 
     522           0 :     nsIDocument* newDoc = aNode->OwnerDoc();
     523           0 :     if (newDoc) {
     524             :       // XXX what if oldDoc is null, we don't know if this should be
     525             :       // registered or not! Can that really happen?
     526           0 :       if (wasRegistered) {
     527           0 :         newDoc->RegisterActivityObserver(aNode->AsElement());
     528             :       }
     529             : 
     530           0 :       if (nsPIDOMWindowInner* window = newDoc->GetInnerWindow()) {
     531           0 :         EventListenerManager* elm = aNode->GetExistingListenerManager();
     532           0 :         if (elm) {
     533           0 :           window->SetMutationListeners(elm->MutationListenerBits());
     534           0 :           if (elm->MayHavePaintEventListener()) {
     535           0 :             window->SetHasPaintEventListeners();
     536             :           }
     537           0 :           if (elm->MayHaveTouchEventListener()) {
     538           0 :             window->SetHasTouchEventListeners();
     539             :           }
     540           0 :           if (elm->MayHaveMouseEnterLeaveEventListener()) {
     541           0 :             window->SetHasMouseEnterLeaveEventListeners();
     542             :           }
     543           0 :           if (elm->MayHavePointerEnterLeaveEventListener()) {
     544           0 :             window->SetHasPointerEnterLeaveEventListeners();
     545             :           }
     546           0 :           if (elm->MayHaveSelectionChangeEventListener()) {
     547           0 :             window->SetHasSelectionChangeEventListeners();
     548             :           }
     549             :         }
     550             :       }
     551             :     }
     552             : 
     553           0 :     if (wasRegistered && oldDoc != newDoc) {
     554           0 :       nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aNode));
     555           0 :       if (domMediaElem) {
     556           0 :         HTMLMediaElement* mediaElem = static_cast<HTMLMediaElement*>(aNode);
     557           0 :         mediaElem->NotifyOwnerDocumentActivityChanged();
     558             :       }
     559           0 :       nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent(do_QueryInterface(aNode));
     560           0 :       if (objectLoadingContent) {
     561           0 :         nsObjectLoadingContent* olc = static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
     562           0 :         olc->NotifyOwnerDocumentActivityChanged();
     563             :       }
     564             :     }
     565             : 
     566           0 :     if (oldDoc != newDoc && oldDoc->MayHaveDOMMutationObservers()) {
     567           0 :       newDoc->SetMayHaveDOMMutationObservers();
     568             :     }
     569             : 
     570           0 :     if (oldDoc != newDoc && oldDoc->MayHaveAnimationObservers()) {
     571           0 :       newDoc->SetMayHaveAnimationObservers();
     572             :     }
     573             : 
     574           0 :     if (elem) {
     575           0 :       elem->RecompileScriptEventListeners();
     576             :     }
     577             : 
     578           0 :     if (aReparentScope) {
     579           0 :       AutoJSContext cx;
     580           0 :       JS::Rooted<JSObject*> wrapper(cx);
     581           0 :       if ((wrapper = aNode->GetWrapper())) {
     582           0 :         MOZ_ASSERT(IsDOMObject(wrapper));
     583           0 :         JSAutoCompartment ac(cx, wrapper);
     584           0 :         rv = ReparentWrapper(cx, wrapper);
     585           0 :         if (NS_FAILED(rv)) {
     586           0 :           if (wasRegistered) {
     587           0 :             aNode->OwnerDoc()->UnregisterActivityObserver(aNode->AsElement());
     588             :           }
     589           0 :           aNode->mNodeInfo.swap(newNodeInfo);
     590           0 :           if (wasRegistered) {
     591           0 :             aNode->OwnerDoc()->RegisterActivityObserver(aNode->AsElement());
     592             :           }
     593           0 :           return rv;
     594             :         }
     595             :       }
     596             :     }
     597             :   }
     598             : 
     599         906 :   if (aDeep && (!aClone || !aNode->IsNodeOfType(nsINode::eATTRIBUTE))) {
     600             :     // aNode's children.
     601        1636 :     for (nsIContent* cloneChild = aNode->GetFirstChild();
     602        1636 :          cloneChild;
     603         730 :          cloneChild = cloneChild->GetNextSibling()) {
     604        1460 :       nsCOMPtr<nsINode> child;
     605         730 :       rv = CloneAndAdopt(cloneChild, aClone, true, nodeInfoManager,
     606             :                          aReparentScope, aNodesWithProperties, clone,
     607        1460 :                          getter_AddRefs(child));
     608         730 :       NS_ENSURE_SUCCESS(rv, rv);
     609             :     }
     610             :   }
     611             : 
     612             :   // Cloning template element.
     613         906 :   if (aDeep && aClone && IsTemplateElement(aNode)) {
     614             :     DocumentFragment* origContent =
     615           0 :       static_cast<HTMLTemplateElement*>(aNode)->Content();
     616             :     DocumentFragment* cloneContent =
     617           0 :       static_cast<HTMLTemplateElement*>(clone.get())->Content();
     618             : 
     619             :     // Clone the children into the clone's template content owner
     620             :     // document's nodeinfo manager.
     621             :     nsNodeInfoManager* ownerNodeInfoManager =
     622           0 :       cloneContent->mNodeInfo->NodeInfoManager();
     623             : 
     624           0 :     for (nsIContent* cloneChild = origContent->GetFirstChild();
     625           0 :          cloneChild;
     626           0 :          cloneChild = cloneChild->GetNextSibling()) {
     627           0 :       nsCOMPtr<nsINode> child;
     628           0 :       rv = CloneAndAdopt(cloneChild, aClone, aDeep, ownerNodeInfoManager,
     629             :                          aReparentScope, aNodesWithProperties, cloneContent,
     630           0 :                          getter_AddRefs(child));
     631           0 :       NS_ENSURE_SUCCESS(rv, rv);
     632             :     }
     633             :   }
     634             : 
     635             :   // XXX setting document on some nodes not in a document so XBL will bind
     636             :   // and chrome won't break. Make XBL bind to document-less nodes!
     637             :   // XXXbz Once this is fixed, fix up the asserts in all implementations of
     638             :   // BindToTree to assert what they would like to assert, and fix the
     639             :   // ChangeDocumentFor() call in nsXULElement::BindToTree as well.  Also,
     640             :   // remove the UnbindFromTree call in ~nsXULElement, and add back in the
     641             :   // precondition in nsXULElement::UnbindFromTree and remove the line in
     642             :   // nsXULElement.h that makes nsNodeUtils a friend of nsXULElement.
     643             :   // Note: Make sure to do this witchery _after_ we've done any deep
     644             :   // cloning, so kids of the new node aren't confused about whether they're
     645             :   // in a document.
     646             : #ifdef MOZ_XUL
     647         906 :   if (aClone && !aParent && aNode->IsXULElement()) {
     648           2 :     if (!aNode->OwnerDoc()->IsLoadedAsInteractiveData()) {
     649           2 :       clone->SetFlags(NODE_FORCE_XBL_BINDINGS);
     650             :     }
     651             :   }
     652             : #endif
     653             : 
     654         906 :   if (aNodesWithProperties && aNode->HasProperties()) {
     655           0 :     bool ok = aNodesWithProperties->AppendObject(aNode);
     656           0 :     if (aClone) {
     657           0 :       ok = ok && aNodesWithProperties->AppendObject(clone);
     658             :     }
     659             : 
     660           0 :     NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
     661             :   }
     662             : 
     663         906 :   clone.forget(aResult);
     664             : 
     665         906 :   return NS_OK;
     666             : }
     667             : 
     668             : 
     669             : /* static */
     670             : void
     671           0 : nsNodeUtils::UnlinkUserData(nsINode *aNode)
     672             : {
     673           0 :   NS_ASSERTION(aNode->HasProperties(), "Call to UnlinkUserData not needed.");
     674             : 
     675             :   // Strong reference to the document so that deleting properties can't
     676             :   // delete the document.
     677           0 :   nsCOMPtr<nsIDocument> document = aNode->OwnerDoc();
     678           0 :   document->PropertyTable(DOM_USER_DATA)->DeleteAllPropertiesFor(aNode);
     679           0 : }
     680             : 
     681             : bool
     682         906 : nsNodeUtils::IsTemplateElement(const nsINode *aNode)
     683             : {
     684         906 :   return aNode->IsHTMLElement(nsGkAtoms::_template);
     685             : }
     686             : 
     687             : nsIContent*
     688           0 : nsNodeUtils::GetFirstChildOfTemplateOrNode(nsINode* aNode)
     689             : {
     690           0 :   if (nsNodeUtils::IsTemplateElement(aNode)) {
     691             :     DocumentFragment* frag =
     692           0 :       static_cast<HTMLTemplateElement*>(aNode)->Content();
     693           0 :     return frag->GetFirstChild();
     694             :   }
     695             : 
     696           0 :   return aNode->GetFirstChild();
     697             : }
     698             : 

Generated by: LCOV version 1.13