content/base/src/nsNodeUtils.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 sw=2 et tw=99: */
     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 #include "nsNodeUtils.h"
     8 #include "nsContentUtils.h"
     9 #include "nsCxPusher.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 "nsIDOMUserDataHandler.h"
    16 #include "mozilla/EventListenerManager.h"
    17 #include "nsIXPConnect.h"
    18 #include "pldhash.h"
    19 #include "nsIDOMAttr.h"
    20 #include "nsCOMArray.h"
    21 #include "nsPIDOMWindow.h"
    22 #include "nsDocument.h"
    23 #ifdef MOZ_XUL
    24 #include "nsXULElement.h"
    25 #endif
    26 #include "nsBindingManager.h"
    27 #include "nsGenericHTMLElement.h"
    28 #include "mozilla/dom/HTMLImageElement.h"
    29 #include "mozilla/dom/HTMLMediaElement.h"
    30 #include "nsWrapperCacheInlines.h"
    31 #include "nsObjectLoadingContent.h"
    32 #include "nsDOMMutationObserver.h"
    33 #include "mozilla/dom/BindingUtils.h"
    34 #include "mozilla/dom/HTMLTemplateElement.h"
    35 #include "mozilla/dom/ShadowRoot.h"
    37 using namespace mozilla;
    38 using namespace mozilla::dom;
    39 using mozilla::AutoJSContext;
    41 // This macro expects the ownerDocument of content_ to be in scope as
    42 // |nsIDocument* doc|
    43 #define IMPL_MUTATION_NOTIFICATION(func_, content_, params_)      \
    44   PR_BEGIN_MACRO                                                  \
    45   bool needsEnterLeave = doc->MayHaveDOMMutationObservers();      \
    46   if (needsEnterLeave) {                                          \
    47     nsDOMMutationObserver::EnterMutationHandling();               \
    48   }                                                               \
    49   nsINode* node = content_;                                       \
    50   NS_ASSERTION(node->OwnerDoc() == doc, "Bogus document");        \
    51   if (doc) {                                                      \
    52     doc->BindingManager()->func_ params_;                         \
    53   }                                                               \
    54   do {                                                            \
    55     nsINode::nsSlots* slots = node->GetExistingSlots();           \
    56     if (slots && !slots->mMutationObservers.IsEmpty()) {          \
    57       /* No need to explicitly notify the first observer first    \
    58          since that'll happen anyway. */                          \
    59       NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(                         \
    60         slots->mMutationObservers, nsIMutationObserver,           \
    61         func_, params_);                                          \
    62     }                                                             \
    63     ShadowRoot* shadow = ShadowRoot::FromNode(node);              \
    64     if (shadow) {                                                 \
    65       node = shadow->GetPoolHost();                               \
    66     } else {                                                      \
    67       node = node->GetParentNode();                               \
    68     }                                                             \
    69   } while (node);                                                 \
    70   if (needsEnterLeave) {                                          \
    71     nsDOMMutationObserver::LeaveMutationHandling();               \
    72   }                                                               \
    73   PR_END_MACRO
    75 void
    76 nsNodeUtils::CharacterDataWillChange(nsIContent* aContent,
    77                                      CharacterDataChangeInfo* aInfo)
    78 {
    79   nsIDocument* doc = aContent->OwnerDoc();
    80   IMPL_MUTATION_NOTIFICATION(CharacterDataWillChange, aContent,
    81                              (doc, aContent, aInfo));
    82 }
    84 void
    85 nsNodeUtils::CharacterDataChanged(nsIContent* aContent,
    86                                   CharacterDataChangeInfo* aInfo)
    87 {
    88   nsIDocument* doc = aContent->OwnerDoc();
    89   IMPL_MUTATION_NOTIFICATION(CharacterDataChanged, aContent,
    90                              (doc, aContent, aInfo));
    91 }
    93 void
    94 nsNodeUtils::AttributeWillChange(Element* aElement,
    95                                  int32_t aNameSpaceID,
    96                                  nsIAtom* aAttribute,
    97                                  int32_t aModType)
    98 {
    99   nsIDocument* doc = aElement->OwnerDoc();
   100   IMPL_MUTATION_NOTIFICATION(AttributeWillChange, aElement,
   101                              (doc, aElement, aNameSpaceID, aAttribute,
   102                               aModType));
   103 }
   105 void
   106 nsNodeUtils::AttributeChanged(Element* aElement,
   107                               int32_t aNameSpaceID,
   108                               nsIAtom* aAttribute,
   109                               int32_t aModType)
   110 {
   111   nsIDocument* doc = aElement->OwnerDoc();
   112   IMPL_MUTATION_NOTIFICATION(AttributeChanged, aElement,
   113                              (doc, aElement, aNameSpaceID, aAttribute,
   114                               aModType));
   115 }
   117 void
   118 nsNodeUtils::AttributeSetToCurrentValue(Element* aElement,
   119                                         int32_t aNameSpaceID,
   120                                         nsIAtom* aAttribute)
   121 {
   122   nsIDocument* doc = aElement->OwnerDoc();
   123   IMPL_MUTATION_NOTIFICATION(AttributeSetToCurrentValue, aElement,
   124                              (doc, aElement, aNameSpaceID, aAttribute));
   125 }
   127 void
   128 nsNodeUtils::ContentAppended(nsIContent* aContainer,
   129                              nsIContent* aFirstNewContent,
   130                              int32_t aNewIndexInContainer)
   131 {
   132   nsIDocument* doc = aContainer->OwnerDoc();
   134   IMPL_MUTATION_NOTIFICATION(ContentAppended, aContainer,
   135                              (doc, aContainer, aFirstNewContent,
   136                               aNewIndexInContainer));
   137 }
   139 void
   140 nsNodeUtils::ContentInserted(nsINode* aContainer,
   141                              nsIContent* aChild,
   142                              int32_t aIndexInContainer)
   143 {
   144   NS_PRECONDITION(aContainer->IsNodeOfType(nsINode::eCONTENT) ||
   145                   aContainer->IsNodeOfType(nsINode::eDOCUMENT),
   146                   "container must be an nsIContent or an nsIDocument");
   147   nsIContent* container;
   148   nsIDocument* doc = aContainer->OwnerDoc();
   149   nsIDocument* document;
   150   if (aContainer->IsNodeOfType(nsINode::eCONTENT)) {
   151     container = static_cast<nsIContent*>(aContainer);
   152     document = doc;
   153   }
   154   else {
   155     container = nullptr;
   156     document = static_cast<nsIDocument*>(aContainer);
   157   }
   159   IMPL_MUTATION_NOTIFICATION(ContentInserted, aContainer,
   160                              (document, container, aChild, aIndexInContainer));
   161 }
   163 void
   164 nsNodeUtils::ContentRemoved(nsINode* aContainer,
   165                             nsIContent* aChild,
   166                             int32_t aIndexInContainer,
   167                             nsIContent* aPreviousSibling)
   168 {
   169   NS_PRECONDITION(aContainer->IsNodeOfType(nsINode::eCONTENT) ||
   170                   aContainer->IsNodeOfType(nsINode::eDOCUMENT),
   171                   "container must be an nsIContent or an nsIDocument");
   172   nsIContent* container;
   173   nsIDocument* doc = aContainer->OwnerDoc();
   174   nsIDocument* document;
   175   if (aContainer->IsNodeOfType(nsINode::eCONTENT)) {
   176     container = static_cast<nsIContent*>(aContainer);
   177     document = doc;
   178   }
   179   else {
   180     container = nullptr;
   181     document = static_cast<nsIDocument*>(aContainer);
   182   }
   184   IMPL_MUTATION_NOTIFICATION(ContentRemoved, aContainer,
   185                              (document, container, aChild, aIndexInContainer,
   186                               aPreviousSibling));
   187 }
   189 void
   190 nsNodeUtils::LastRelease(nsINode* aNode)
   191 {
   192   nsINode::nsSlots* slots = aNode->GetExistingSlots();
   193   if (slots) {
   194     if (!slots->mMutationObservers.IsEmpty()) {
   195       NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(slots->mMutationObservers,
   196                                          nsIMutationObserver,
   197                                          NodeWillBeDestroyed, (aNode));
   198     }
   200     delete slots;
   201     aNode->mSlots = nullptr;
   202   }
   204   // Kill properties first since that may run external code, so we want to
   205   // be in as complete state as possible at that time.
   206   if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) {
   207     // Delete all properties before tearing down the document. Some of the
   208     // properties are bound to nsINode objects and the destructor functions of
   209     // the properties may want to use the owner document of the nsINode.
   210     static_cast<nsIDocument*>(aNode)->DeleteAllProperties();
   211   }
   212   else {
   213     if (aNode->HasProperties()) {
   214       // Strong reference to the document so that deleting properties can't
   215       // delete the document.
   216       nsCOMPtr<nsIDocument> document = aNode->OwnerDoc();
   217       document->DeleteAllPropertiesFor(aNode);
   218     }
   220     // I wonder whether it's faster to do the HasFlag check first....
   221     if (aNode->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) &&
   222         aNode->HasFlag(ADDED_TO_FORM)) {
   223       // Tell the form (if any) this node is going away.  Don't
   224       // notify, since we're being destroyed in any case.
   225       static_cast<nsGenericHTMLFormElement*>(aNode)->ClearForm(true);
   226     }
   228     if (aNode->IsElement() && aNode->AsElement()->IsHTML(nsGkAtoms::img) &&
   229         aNode->HasFlag(ADDED_TO_FORM)) {
   230       HTMLImageElement* imageElem = static_cast<HTMLImageElement*>(aNode);
   231       imageElem->ClearForm(true);
   232     }
   233   }
   234   aNode->UnsetFlags(NODE_HAS_PROPERTIES);
   236   if (aNode->NodeType() != nsIDOMNode::DOCUMENT_NODE &&
   237       aNode->HasFlag(NODE_HAS_LISTENERMANAGER)) {
   238 #ifdef DEBUG
   239     if (nsContentUtils::IsInitialized()) {
   240       EventListenerManager* manager =
   241         nsContentUtils::GetExistingListenerManagerForNode(aNode);
   242       if (!manager) {
   243         NS_ERROR("Huh, our bit says we have a listener manager list, "
   244                  "but there's nothing in the hash!?!!");
   245       }
   246     }
   247 #endif
   249     nsContentUtils::RemoveListenerManager(aNode);
   250     aNode->UnsetFlags(NODE_HAS_LISTENERMANAGER);
   251   }
   253   if (aNode->IsElement()) {
   254     nsIDocument* ownerDoc = aNode->OwnerDoc();
   255     Element* elem = aNode->AsElement();
   256     ownerDoc->ClearBoxObjectFor(elem);
   258     NS_ASSERTION(aNode->HasFlag(NODE_FORCE_XBL_BINDINGS) ||
   259                  !elem->GetXBLBinding(),
   260                  "Non-forced node has binding on destruction");
   262     // if NODE_FORCE_XBL_BINDINGS is set, the node might still have a binding
   263     // attached
   264     if (aNode->HasFlag(NODE_FORCE_XBL_BINDINGS) &&
   265         ownerDoc->BindingManager()) {
   266       ownerDoc->BindingManager()->RemovedFromDocument(elem, ownerDoc);
   267     }
   268   }
   270   aNode->ReleaseWrapper(aNode);
   272   FragmentOrElement::RemoveBlackMarkedNode(aNode);
   273 }
   275 struct MOZ_STACK_CLASS nsHandlerData
   276 {
   277   uint16_t mOperation;
   278   nsCOMPtr<nsIDOMNode> mSource;
   279   nsCOMPtr<nsIDOMNode> mDest;
   280   nsCxPusher mPusher;
   281 };
   283 static void
   284 CallHandler(void *aObject, nsIAtom *aKey, void *aHandler, void *aData)
   285 {
   286   nsHandlerData *handlerData = static_cast<nsHandlerData*>(aData);
   287   nsCOMPtr<nsIDOMUserDataHandler> handler =
   288     static_cast<nsIDOMUserDataHandler*>(aHandler);
   289   nsINode *node = static_cast<nsINode*>(aObject);
   290   nsCOMPtr<nsIVariant> data =
   291     static_cast<nsIVariant*>(node->GetProperty(DOM_USER_DATA, aKey));
   292   NS_ASSERTION(data, "Handler without data?");
   294   if (!handlerData->mPusher.RePush(node)) {
   295     return;
   296   }
   297   nsAutoString key;
   298   aKey->ToString(key);
   299   handler->Handle(handlerData->mOperation, key, data, handlerData->mSource,
   300                   handlerData->mDest);
   301 }
   303 /* static */
   304 nsresult
   305 nsNodeUtils::CallUserDataHandlers(nsCOMArray<nsINode> &aNodesWithProperties,
   306                                   nsIDocument *aOwnerDocument,
   307                                   uint16_t aOperation, bool aCloned)
   308 {
   309   NS_PRECONDITION(!aCloned || (aNodesWithProperties.Count() % 2 == 0),
   310                   "Expected aNodesWithProperties to contain original and "
   311                   "cloned nodes.");
   313   if (!nsContentUtils::IsSafeToRunScript()) {
   314     if (nsContentUtils::IsChromeDoc(aOwnerDocument)) {
   315       NS_WARNING("Fix the caller! Userdata callback disabled.");
   316     } else {
   317       NS_ERROR("This is unsafe! Fix the caller! Userdata callback disabled.");
   318     }
   320     return NS_OK;
   321   }
   323   nsPropertyTable *table = aOwnerDocument->PropertyTable(DOM_USER_DATA_HANDLER);
   325   // Keep the document alive, just in case one of the handlers causes it to go
   326   // away.
   327   nsCOMPtr<nsIDocument> ownerDoc = aOwnerDocument;
   329   nsHandlerData handlerData;
   330   handlerData.mOperation = aOperation;
   332   uint32_t i, count = aNodesWithProperties.Count();
   333   for (i = 0; i < count; ++i) {
   334     nsINode *nodeWithProperties = aNodesWithProperties[i];
   336     nsresult rv;
   337     handlerData.mSource = do_QueryInterface(nodeWithProperties, &rv);
   338     NS_ENSURE_SUCCESS(rv, rv);
   340     if (aCloned) {
   341       handlerData.mDest = do_QueryInterface(aNodesWithProperties[++i], &rv);
   342       NS_ENSURE_SUCCESS(rv, rv);
   343     }
   345     table->Enumerate(nodeWithProperties, CallHandler, &handlerData);
   346   }
   348   return NS_OK;
   349 }
   351 static void
   352 NoteUserData(void *aObject, nsIAtom *aKey, void *aXPCOMChild, void *aData)
   353 {
   354   nsCycleCollectionTraversalCallback* cb =
   355     static_cast<nsCycleCollectionTraversalCallback*>(aData);
   356   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "[user data (or handler)]");
   357   cb->NoteXPCOMChild(static_cast<nsISupports*>(aXPCOMChild));
   358 }
   360 /* static */
   361 void
   362 nsNodeUtils::TraverseUserData(nsINode* aNode,
   363                               nsCycleCollectionTraversalCallback &aCb)
   364 {
   365   nsIDocument* ownerDoc = aNode->OwnerDoc();
   366   ownerDoc->PropertyTable(DOM_USER_DATA)->Enumerate(aNode, NoteUserData, &aCb);
   367   ownerDoc->PropertyTable(DOM_USER_DATA_HANDLER)->Enumerate(aNode, NoteUserData, &aCb);
   368 }
   370 /* static */
   371 nsresult
   372 nsNodeUtils::CloneNodeImpl(nsINode *aNode, bool aDeep,
   373                            bool aCallUserDataHandlers,
   374                            nsINode **aResult)
   375 {
   376   *aResult = nullptr;
   378   nsCOMPtr<nsINode> newNode;
   379   nsCOMArray<nsINode> nodesWithProperties;
   380   nsresult rv = Clone(aNode, aDeep, nullptr, nodesWithProperties,
   381                       getter_AddRefs(newNode));
   382   NS_ENSURE_SUCCESS(rv, rv);
   384   if (aCallUserDataHandlers) {
   385     rv = CallUserDataHandlers(nodesWithProperties, aNode->OwnerDoc(),
   386                               nsIDOMUserDataHandler::NODE_CLONED, true);
   387     NS_ENSURE_SUCCESS(rv, rv);
   388   }
   390   newNode.swap(*aResult);
   392   return NS_OK;
   393 }
   395 /* static */
   396 nsresult
   397 nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep,
   398                            nsNodeInfoManager *aNewNodeInfoManager,
   399                            JS::Handle<JSObject*> aReparentScope,
   400                            nsCOMArray<nsINode> &aNodesWithProperties,
   401                            nsINode *aParent, nsINode **aResult)
   402 {
   403   NS_PRECONDITION((!aClone && aNewNodeInfoManager) || !aReparentScope,
   404                   "If cloning or not getting a new nodeinfo we shouldn't "
   405                   "rewrap");
   406   NS_PRECONDITION(!aParent || aNode->IsNodeOfType(nsINode::eCONTENT),
   407                   "Can't insert document or attribute nodes into a parent");
   409   *aResult = nullptr;
   411   // First deal with aNode and walk its attributes (and their children). Then,
   412   // if aDeep is true, deal with aNode's children (and recurse into their
   413   // attributes and children).
   415   AutoJSContext cx;
   416   nsresult rv;
   418   nsNodeInfoManager *nodeInfoManager = aNewNodeInfoManager;
   420   // aNode.
   421   nsINodeInfo *nodeInfo = aNode->mNodeInfo;
   422   nsCOMPtr<nsINodeInfo> newNodeInfo;
   423   if (nodeInfoManager) {
   425     // Don't allow importing/adopting nodes from non-privileged "scriptable"
   426     // documents to "non-scriptable" documents.
   427     nsIDocument* newDoc = nodeInfoManager->GetDocument();
   428     NS_ENSURE_STATE(newDoc);
   429     bool hasHadScriptHandlingObject = false;
   430     if (!newDoc->GetScriptHandlingObject(hasHadScriptHandlingObject) &&
   431         !hasHadScriptHandlingObject) {
   432       nsIDocument* currentDoc = aNode->OwnerDoc();
   433       NS_ENSURE_STATE((nsContentUtils::IsChromeDoc(currentDoc) ||
   434                        (!currentDoc->GetScriptHandlingObject(hasHadScriptHandlingObject) &&
   435                         !hasHadScriptHandlingObject)));
   436     }
   438     newNodeInfo = nodeInfoManager->GetNodeInfo(nodeInfo->NameAtom(),
   439                                                nodeInfo->GetPrefixAtom(),
   440                                                nodeInfo->NamespaceID(),
   441                                                nodeInfo->NodeType(),
   442                                                nodeInfo->GetExtraName());
   444     nodeInfo = newNodeInfo;
   445   }
   447   Element *elem = aNode->IsElement() ? aNode->AsElement() : nullptr;
   449   nsCOMPtr<nsINode> clone;
   450   if (aClone) {
   451     rv = aNode->Clone(nodeInfo, getter_AddRefs(clone));
   452     NS_ENSURE_SUCCESS(rv, rv);
   454     if (aParent) {
   455       // If we're cloning we need to insert the cloned children into the cloned
   456       // parent.
   457       rv = aParent->AppendChildTo(static_cast<nsIContent*>(clone.get()),
   458                                   false);
   459       NS_ENSURE_SUCCESS(rv, rv);
   460     }
   461     else if (aDeep && clone->IsNodeOfType(nsINode::eDOCUMENT)) {
   462       // After cloning the document itself, we want to clone the children into
   463       // the cloned document (somewhat like cloning and importing them into the
   464       // cloned document).
   465       nodeInfoManager = clone->mNodeInfo->NodeInfoManager();
   466     }
   467   }
   468   else if (nodeInfoManager) {
   469     nsIDocument* oldDoc = aNode->OwnerDoc();
   470     bool wasRegistered = false;
   471     if (aNode->IsElement()) {
   472       Element* element = aNode->AsElement();
   473       oldDoc->ClearBoxObjectFor(element);
   474       wasRegistered = oldDoc->UnregisterFreezableElement(element);
   475     }
   477     aNode->mNodeInfo.swap(newNodeInfo);
   478     if (elem) {
   479       elem->NodeInfoChanged(newNodeInfo);
   480     }
   482     nsIDocument* newDoc = aNode->OwnerDoc();
   483     if (newDoc) {
   484       // XXX what if oldDoc is null, we don't know if this should be
   485       // registered or not! Can that really happen?
   486       if (wasRegistered) {
   487         newDoc->RegisterFreezableElement(aNode->AsElement());
   488       }
   490       nsPIDOMWindow* window = newDoc->GetInnerWindow();
   491       if (window) {
   492         EventListenerManager* elm = aNode->GetExistingListenerManager();
   493         if (elm) {
   494           window->SetMutationListeners(elm->MutationListenerBits());
   495           if (elm->MayHavePaintEventListener()) {
   496             window->SetHasPaintEventListeners();
   497           }
   498           if (elm->MayHaveTouchEventListener()) {
   499             window->SetHasTouchEventListeners();
   500           }
   501           if (elm->MayHaveMouseEnterLeaveEventListener()) {
   502             window->SetHasMouseEnterLeaveEventListeners();
   503           }
   504           if (elm->MayHavePointerEnterLeaveEventListener()) {
   505             window->SetHasPointerEnterLeaveEventListeners();
   506           }
   507         }
   508       }
   509     }
   511     if (wasRegistered && oldDoc != newDoc) {
   512       nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aNode));
   513       if (domMediaElem) {
   514         HTMLMediaElement* mediaElem = static_cast<HTMLMediaElement*>(aNode);
   515         mediaElem->NotifyOwnerDocumentActivityChanged();
   516       }
   517       nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent(do_QueryInterface(aNode));
   518       if (objectLoadingContent) {
   519         nsObjectLoadingContent* olc = static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
   520         olc->NotifyOwnerDocumentActivityChanged();
   521       }
   522     }
   524     if (oldDoc != newDoc && oldDoc->MayHaveDOMMutationObservers()) {
   525       newDoc->SetMayHaveDOMMutationObservers();
   526     }
   528     if (elem) {
   529       elem->RecompileScriptEventListeners();
   530     }
   532     if (aReparentScope) {
   533       JS::Rooted<JSObject*> wrapper(cx);
   534       if ((wrapper = aNode->GetWrapper())) {
   535         if (IsDOMObject(wrapper)) {
   536           JSAutoCompartment ac(cx, wrapper);
   537           rv = ReparentWrapper(cx, wrapper);
   538         } else {
   539           nsIXPConnect *xpc = nsContentUtils::XPConnect();
   540           if (xpc) {
   541             rv = xpc->ReparentWrappedNativeIfFound(cx, wrapper, aReparentScope, aNode);
   542           } else {
   543             rv = NS_ERROR_FAILURE;
   544           }
   545         }
   546         if (NS_FAILED(rv)) {
   547           aNode->mNodeInfo.swap(nodeInfo);
   549           return rv;
   550         }
   551       }
   552     }
   553   }
   555   // XXX If there are any attribute nodes on this element with UserDataHandlers
   556   // we should technically adopt/clone/import such attribute nodes and notify
   557   // those handlers. However we currently don't have code to do so without
   558   // also notifying when it's not safe so we're not doing that at this time.
   560   if (aDeep && (!aClone || !aNode->IsNodeOfType(nsINode::eATTRIBUTE))) {
   561     // aNode's children.
   562     for (nsIContent* cloneChild = aNode->GetFirstChild();
   563          cloneChild;
   564          cloneChild = cloneChild->GetNextSibling()) {
   565       nsCOMPtr<nsINode> child;
   566       rv = CloneAndAdopt(cloneChild, aClone, true, nodeInfoManager,
   567                          aReparentScope, aNodesWithProperties, clone,
   568                          getter_AddRefs(child));
   569       NS_ENSURE_SUCCESS(rv, rv);
   570     }
   571   }
   573   // Cloning template element.
   574   if (aDeep && aClone && IsTemplateElement(aNode)) {
   575     DocumentFragment* origContent =
   576       static_cast<HTMLTemplateElement*>(aNode)->Content();
   577     DocumentFragment* cloneContent =
   578       static_cast<HTMLTemplateElement*>(clone.get())->Content();
   580     // Clone the children into the clone's template content owner
   581     // document's nodeinfo manager.
   582     nsNodeInfoManager* ownerNodeInfoManager =
   583       cloneContent->mNodeInfo->NodeInfoManager();
   585     for (nsIContent* cloneChild = origContent->GetFirstChild();
   586          cloneChild;
   587          cloneChild = cloneChild->GetNextSibling()) {
   588       nsCOMPtr<nsINode> child;
   589       rv = CloneAndAdopt(cloneChild, aClone, aDeep, ownerNodeInfoManager,
   590                          aReparentScope, aNodesWithProperties, cloneContent,
   591                          getter_AddRefs(child));
   592       NS_ENSURE_SUCCESS(rv, rv);
   593     }
   594   }
   596   // XXX setting document on some nodes not in a document so XBL will bind
   597   // and chrome won't break. Make XBL bind to document-less nodes!
   598   // XXXbz Once this is fixed, fix up the asserts in all implementations of
   599   // BindToTree to assert what they would like to assert, and fix the
   600   // ChangeDocumentFor() call in nsXULElement::BindToTree as well.  Also,
   601   // remove the UnbindFromTree call in ~nsXULElement, and add back in the
   602   // precondition in nsXULElement::UnbindFromTree and remove the line in
   603   // nsXULElement.h that makes nsNodeUtils a friend of nsXULElement.
   604   // Note: Make sure to do this witchery _after_ we've done any deep
   605   // cloning, so kids of the new node aren't confused about whether they're
   606   // in a document.
   607 #ifdef MOZ_XUL
   608   if (aClone && !aParent && aNode->IsElement() &&
   609       aNode->AsElement()->IsXUL()) {
   610     if (!aNode->OwnerDoc()->IsLoadedAsInteractiveData()) {
   611       clone->SetFlags(NODE_FORCE_XBL_BINDINGS);
   612     }
   613   }
   614 #endif
   616   if (aNode->HasProperties()) {
   617     bool ok = aNodesWithProperties.AppendObject(aNode);
   618     if (aClone) {
   619       ok = ok && aNodesWithProperties.AppendObject(clone);
   620     }
   622     NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
   623   }
   625   clone.forget(aResult);
   627   return NS_OK;
   628 }
   631 /* static */
   632 void
   633 nsNodeUtils::UnlinkUserData(nsINode *aNode)
   634 {
   635   NS_ASSERTION(aNode->HasProperties(), "Call to UnlinkUserData not needed.");
   637   // Strong reference to the document so that deleting properties can't
   638   // delete the document.
   639   nsCOMPtr<nsIDocument> document = aNode->OwnerDoc();
   640   document->PropertyTable(DOM_USER_DATA)->DeleteAllPropertiesFor(aNode);
   641   document->PropertyTable(DOM_USER_DATA_HANDLER)->DeleteAllPropertiesFor(aNode);
   642 }
   644 bool
   645 nsNodeUtils::IsTemplateElement(const nsINode *aNode)
   646 {
   647   return aNode->IsElement() && aNode->AsElement()->IsHTML(nsGkAtoms::_template);
   648 }
   650 nsIContent*
   651 nsNodeUtils::GetFirstChildOfTemplateOrNode(nsINode* aNode)
   652 {
   653   if (nsNodeUtils::IsTemplateElement(aNode)) {
   654     DocumentFragment* frag =
   655       static_cast<HTMLTemplateElement*>(aNode)->Content();
   656     return frag->GetFirstChild();
   657   }
   659   return aNode->GetFirstChild();
   660 }

mercurial