LCOV - code coverage report
Current view: directory - content/base/src - nsNodeUtils.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 264 126 47.7 %
Date: 2012-06-02 Functions: 19 14 73.7 %

       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                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is Mozilla Foundation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2006
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *         Jonas Sicking <jonas@sicking.cc> (Original Author)
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "nsNodeUtils.h"
      40                 : #include "nsContentUtils.h"
      41                 : #include "nsINode.h"
      42                 : #include "nsIContent.h"
      43                 : #include "mozilla/dom/Element.h"
      44                 : #include "nsIMutationObserver.h"
      45                 : #include "nsIMutationObserver2.h"
      46                 : #include "nsIDocument.h"
      47                 : #include "nsIDOMUserDataHandler.h"
      48                 : #include "nsEventListenerManager.h"
      49                 : #include "nsIAttribute.h"
      50                 : #include "nsIXPConnect.h"
      51                 : #include "nsGenericElement.h"
      52                 : #include "pldhash.h"
      53                 : #include "nsIDOMAttr.h"
      54                 : #include "nsCOMArray.h"
      55                 : #include "nsPIDOMWindow.h"
      56                 : #include "nsDocument.h"
      57                 : #ifdef MOZ_XUL
      58                 : #include "nsXULElement.h"
      59                 : #endif
      60                 : #include "nsBindingManager.h"
      61                 : #include "nsGenericHTMLElement.h"
      62                 : #ifdef MOZ_MEDIA
      63                 : #include "nsHTMLMediaElement.h"
      64                 : #endif // MOZ_MEDIA
      65                 : #include "nsImageLoadingContent.h"
      66                 : #include "jsgc.h"
      67                 : #include "nsWrapperCacheInlines.h"
      68                 : #include "nsObjectLoadingContent.h"
      69                 : 
      70                 : using namespace mozilla::dom;
      71                 : 
      72                 : // This macro expects the ownerDocument of content_ to be in scope as
      73                 : // |nsIDocument* doc|
      74                 : // NOTE: AttributeChildRemoved doesn't use this macro but has a very similar use.
      75                 : // If you change how this macro behave please update AttributeChildRemoved.
      76                 : #define IMPL_MUTATION_NOTIFICATION(func_, content_, params_)      \
      77                 :   PR_BEGIN_MACRO                                                  \
      78                 :   nsINode* node = content_;                                       \
      79                 :   NS_ASSERTION(node->OwnerDoc() == doc, "Bogus document");     \
      80                 :   if (doc) {                                                      \
      81                 :     static_cast<nsIMutationObserver*>(doc->BindingManager())->    \
      82                 :       func_ params_;                                              \
      83                 :   }                                                               \
      84                 :   do {                                                            \
      85                 :     nsINode::nsSlots* slots = node->GetExistingSlots();           \
      86                 :     if (slots && !slots->mMutationObservers.IsEmpty()) {          \
      87                 :       /* No need to explicitly notify the first observer first    \
      88                 :          since that'll happen anyway. */                          \
      89                 :       NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(                         \
      90                 :         slots->mMutationObservers, nsIMutationObserver,           \
      91                 :         func_, params_);                                          \
      92                 :     }                                                             \
      93                 :     node = node->GetNodeParent();                                 \
      94                 :   } while (node);                                                 \
      95                 :   PR_END_MACRO
      96                 : 
      97                 : void
      98              32 : nsNodeUtils::CharacterDataWillChange(nsIContent* aContent,
      99                 :                                      CharacterDataChangeInfo* aInfo)
     100                 : {
     101              32 :   nsIDocument* doc = aContent->OwnerDoc();
     102              32 :   IMPL_MUTATION_NOTIFICATION(CharacterDataWillChange, aContent,
     103                 :                              (doc, aContent, aInfo));
     104              32 : }
     105                 : 
     106                 : void
     107              32 : nsNodeUtils::CharacterDataChanged(nsIContent* aContent,
     108                 :                                   CharacterDataChangeInfo* aInfo)
     109                 : {
     110              32 :   nsIDocument* doc = aContent->OwnerDoc();
     111              32 :   IMPL_MUTATION_NOTIFICATION(CharacterDataChanged, aContent,
     112                 :                              (doc, aContent, aInfo));
     113              32 : }
     114                 : 
     115                 : void
     116            1874 : nsNodeUtils::AttributeWillChange(Element* aElement,
     117                 :                                  PRInt32 aNameSpaceID,
     118                 :                                  nsIAtom* aAttribute,
     119                 :                                  PRInt32 aModType)
     120                 : {
     121            1874 :   nsIDocument* doc = aElement->OwnerDoc();
     122            1874 :   IMPL_MUTATION_NOTIFICATION(AttributeWillChange, aElement,
     123                 :                              (doc, aElement, aNameSpaceID, aAttribute,
     124                 :                               aModType));
     125            1874 : }
     126                 : 
     127                 : void
     128            1874 : nsNodeUtils::AttributeChanged(Element* aElement,
     129                 :                               PRInt32 aNameSpaceID,
     130                 :                               nsIAtom* aAttribute,
     131                 :                               PRInt32 aModType)
     132                 : {
     133            1874 :   nsIDocument* doc = aElement->OwnerDoc();
     134            1874 :   IMPL_MUTATION_NOTIFICATION(AttributeChanged, aElement,
     135                 :                              (doc, aElement, aNameSpaceID, aAttribute,
     136                 :                               aModType));
     137            1874 : }
     138                 : 
     139                 : void
     140            2366 : nsNodeUtils::ContentAppended(nsIContent* aContainer,
     141                 :                              nsIContent* aFirstNewContent,
     142                 :                              PRInt32 aNewIndexInContainer)
     143                 : {
     144            2366 :   nsIDocument* doc = aContainer->OwnerDoc();
     145                 : 
     146            2366 :   IMPL_MUTATION_NOTIFICATION(ContentAppended, aContainer,
     147                 :                              (doc, aContainer, aFirstNewContent,
     148                 :                               aNewIndexInContainer));
     149            2366 : }
     150                 : 
     151                 : void
     152            1295 : nsNodeUtils::ContentInserted(nsINode* aContainer,
     153                 :                              nsIContent* aChild,
     154                 :                              PRInt32 aIndexInContainer)
     155                 : {
     156            1295 :   NS_PRECONDITION(aContainer->IsNodeOfType(nsINode::eCONTENT) ||
     157                 :                   aContainer->IsNodeOfType(nsINode::eDOCUMENT),
     158                 :                   "container must be an nsIContent or an nsIDocument");
     159                 :   nsIContent* container;
     160            1295 :   nsIDocument* doc = aContainer->OwnerDoc();
     161                 :   nsIDocument* document;
     162            1295 :   if (aContainer->IsNodeOfType(nsINode::eCONTENT)) {
     163              12 :     container = static_cast<nsIContent*>(aContainer);
     164              12 :     document = doc;
     165                 :   }
     166                 :   else {
     167            1283 :     container = nsnull;
     168            1283 :     document = static_cast<nsIDocument*>(aContainer);
     169                 :   }
     170                 : 
     171            1295 :   IMPL_MUTATION_NOTIFICATION(ContentInserted, aContainer,
     172                 :                              (document, container, aChild, aIndexInContainer));
     173            1295 : }
     174                 : 
     175                 : void
     176             239 : nsNodeUtils::ContentRemoved(nsINode* aContainer,
     177                 :                             nsIContent* aChild,
     178                 :                             PRInt32 aIndexInContainer,
     179                 :                             nsIContent* aPreviousSibling)
     180                 : {
     181             239 :   NS_PRECONDITION(aContainer->IsNodeOfType(nsINode::eCONTENT) ||
     182                 :                   aContainer->IsNodeOfType(nsINode::eDOCUMENT),
     183                 :                   "container must be an nsIContent or an nsIDocument");
     184                 :   nsIContent* container;
     185             239 :   nsIDocument* doc = aContainer->OwnerDoc();
     186                 :   nsIDocument* document;
     187             239 :   if (aContainer->IsNodeOfType(nsINode::eCONTENT)) {
     188             229 :     container = static_cast<nsIContent*>(aContainer);
     189             229 :     document = doc;
     190                 :   }
     191                 :   else {
     192              10 :     container = nsnull;
     193              10 :     document = static_cast<nsIDocument*>(aContainer);
     194                 :   }
     195                 : 
     196             239 :   IMPL_MUTATION_NOTIFICATION(ContentRemoved, aContainer,
     197                 :                              (document, container, aChild, aIndexInContainer,
     198                 :                               aPreviousSibling));
     199             239 : }
     200                 : 
     201                 : void
     202               0 : nsNodeUtils::AttributeChildRemoved(nsINode* aAttribute,
     203                 :                                    nsIContent* aChild)
     204                 : {
     205               0 :   NS_PRECONDITION(aAttribute->IsNodeOfType(nsINode::eATTRIBUTE),
     206                 :                   "container must be a nsIAttribute");
     207                 : 
     208                 :   // This is a variant of IMPL_MUTATION_NOTIFICATION.
     209               0 :   do {
     210               0 :     nsINode::nsSlots* slots = aAttribute->GetExistingSlots();
     211               0 :     if (slots && !slots->mMutationObservers.IsEmpty()) {
     212                 :       // This is a variant of NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS.
     213                 :       nsTObserverArray<nsIMutationObserver*>::ForwardIterator iter_ =
     214               0 :         slots->mMutationObservers;
     215               0 :       nsCOMPtr<nsIMutationObserver2> obs_;
     216               0 :       while (iter_.HasMore()) {
     217               0 :         obs_ = do_QueryInterface(iter_.GetNext());
     218               0 :         if (obs_) {
     219               0 :           obs_->AttributeChildRemoved(aAttribute, aChild);
     220                 :         }
     221                 :       }
     222                 :     }
     223               0 :     aAttribute = aAttribute->GetNodeParent();
     224                 :   } while (aAttribute);
     225               0 : }
     226                 : 
     227                 : void
     228          481635 : nsNodeUtils::ParentChainChanged(nsIContent *aContent)
     229                 : {
     230                 :   // No need to notify observers on the parents since their parent
     231                 :   // chain must have been changed too and so their observers were
     232                 :   // notified at that time.
     233                 : 
     234          481635 :   nsINode::nsSlots* slots = aContent->GetExistingSlots();
     235          481635 :   if (slots && !slots->mMutationObservers.IsEmpty()) {
     236             512 :     NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(
     237                 :         slots->mMutationObservers,
     238                 :         nsIMutationObserver,
     239                 :         ParentChainChanged,
     240                 :         (aContent));
     241                 :   }
     242          481635 : }
     243                 : 
     244                 : void
     245          115281 : nsNodeUtils::LastRelease(nsINode* aNode)
     246                 : {
     247          115281 :   nsINode::nsSlots* slots = aNode->GetExistingSlots();
     248          115281 :   if (slots) {
     249            4609 :     if (!slots->mMutationObservers.IsEmpty()) {
     250            1292 :       NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(slots->mMutationObservers,
     251                 :                                          nsIMutationObserver,
     252                 :                                          NodeWillBeDestroyed, (aNode));
     253                 :     }
     254                 : 
     255            4609 :     delete slots;
     256            4609 :     aNode->mSlots = nsnull;
     257                 :   }
     258                 : 
     259                 :   // Kill properties first since that may run external code, so we want to
     260                 :   // be in as complete state as possible at that time.
     261          115281 :   if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) {
     262                 :     // Delete all properties before tearing down the document. Some of the
     263                 :     // properties are bound to nsINode objects and the destructor functions of
     264                 :     // the properties may want to use the owner document of the nsINode.
     265            1271 :     static_cast<nsIDocument*>(aNode)->DeleteAllProperties();
     266                 :   }
     267                 :   else {
     268          114010 :     if (aNode->HasProperties()) {
     269                 :       // Strong reference to the document so that deleting properties can't
     270                 :       // delete the document.
     271               0 :       nsCOMPtr<nsIDocument> document = aNode->OwnerDoc();
     272               0 :       document->DeleteAllPropertiesFor(aNode);
     273                 :     }
     274                 : 
     275                 :     // I wonder whether it's faster to do the HasFlag check first....
     276          114011 :     if (aNode->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) &&
     277               1 :         aNode->HasFlag(ADDED_TO_FORM)) {
     278                 :       // Tell the form (if any) this node is going away.  Don't
     279                 :       // notify, since we're being destroyed in any case.
     280               0 :       static_cast<nsGenericHTMLFormElement*>(aNode)->ClearForm(true);
     281                 :     }
     282                 :   }
     283          115281 :   aNode->UnsetFlags(NODE_HAS_PROPERTIES);
     284                 : 
     285          229291 :   if (aNode->NodeType() != nsIDOMNode::DOCUMENT_NODE &&
     286          114010 :       aNode->HasFlag(NODE_HAS_LISTENERMANAGER)) {
     287                 : #ifdef DEBUG
     288               0 :     if (nsContentUtils::IsInitialized()) {
     289                 :       nsEventListenerManager* manager =
     290               0 :         nsContentUtils::GetListenerManager(aNode, false);
     291               0 :       if (!manager) {
     292                 :         NS_ERROR("Huh, our bit says we have a listener manager list, "
     293               0 :                  "but there's nothing in the hash!?!!");
     294                 :       }
     295                 :     }
     296                 : #endif
     297                 : 
     298               0 :     nsContentUtils::RemoveListenerManager(aNode);
     299               0 :     aNode->UnsetFlags(NODE_HAS_LISTENERMANAGER);
     300                 :   }
     301                 : 
     302          115281 :   if (aNode->IsElement()) {
     303           37963 :     nsIDocument* ownerDoc = aNode->OwnerDoc();
     304           37963 :     Element* elem = aNode->AsElement();
     305           37963 :     ownerDoc->ClearBoxObjectFor(elem);
     306                 :     
     307           37963 :     NS_ASSERTION(aNode->HasFlag(NODE_FORCE_XBL_BINDINGS) ||
     308                 :                  !ownerDoc->BindingManager() ||
     309                 :                  !ownerDoc->BindingManager()->GetBinding(elem),
     310                 :                  "Non-forced node has binding on destruction");
     311                 : 
     312                 :     // if NODE_FORCE_XBL_BINDINGS is set, the node might still have a binding
     313                 :     // attached
     314           37963 :     if (aNode->HasFlag(NODE_FORCE_XBL_BINDINGS) &&
     315               0 :         ownerDoc->BindingManager()) {
     316               0 :       ownerDoc->BindingManager()->RemovedFromDocument(elem, ownerDoc);
     317                 :     }
     318                 :   }
     319                 : 
     320          115281 :   nsContentUtils::ReleaseWrapper(aNode, aNode);
     321                 : 
     322          115281 :   delete aNode;
     323          115281 : }
     324                 : 
     325                 : struct NS_STACK_CLASS nsHandlerData
     326             524 : {
     327                 :   PRUint16 mOperation;
     328                 :   nsCOMPtr<nsIDOMNode> mSource;
     329                 :   nsCOMPtr<nsIDOMNode> mDest;
     330                 :   nsCxPusher mPusher;
     331                 : };
     332                 : 
     333                 : static void
     334               0 : CallHandler(void *aObject, nsIAtom *aKey, void *aHandler, void *aData)
     335                 : {
     336               0 :   nsHandlerData *handlerData = static_cast<nsHandlerData*>(aData);
     337                 :   nsCOMPtr<nsIDOMUserDataHandler> handler =
     338               0 :     static_cast<nsIDOMUserDataHandler*>(aHandler);
     339               0 :   nsINode *node = static_cast<nsINode*>(aObject);
     340                 :   nsCOMPtr<nsIVariant> data =
     341               0 :     static_cast<nsIVariant*>(node->GetProperty(DOM_USER_DATA, aKey));
     342               0 :   NS_ASSERTION(data, "Handler without data?");
     343                 : 
     344               0 :   if (!handlerData->mPusher.RePush(node)) {
     345                 :     return;
     346                 :   }
     347               0 :   nsAutoString key;
     348               0 :   aKey->ToString(key);
     349               0 :   handler->Handle(handlerData->mOperation, key, data, handlerData->mSource,
     350               0 :                   handlerData->mDest);
     351                 : }
     352                 : 
     353                 : /* static */
     354                 : nsresult
     355             262 : nsNodeUtils::CallUserDataHandlers(nsCOMArray<nsINode> &aNodesWithProperties,
     356                 :                                   nsIDocument *aOwnerDocument,
     357                 :                                   PRUint16 aOperation, bool aCloned)
     358                 : {
     359             262 :   NS_PRECONDITION(!aCloned || (aNodesWithProperties.Count() % 2 == 0),
     360                 :                   "Expected aNodesWithProperties to contain original and "
     361                 :                   "cloned nodes.");
     362                 : 
     363             262 :   if (!nsContentUtils::IsSafeToRunScript()) {
     364               0 :     if (nsContentUtils::IsChromeDoc(aOwnerDocument)) {
     365               0 :       NS_WARNING("Fix the caller! Userdata callback disabled.");
     366                 :     } else {
     367               0 :       NS_ERROR("This is unsafe! Fix the caller! Userdata callback disabled.");
     368                 :     }
     369                 : 
     370               0 :     return NS_OK;
     371                 :   }
     372                 : 
     373             262 :   nsPropertyTable *table = aOwnerDocument->PropertyTable(DOM_USER_DATA_HANDLER);
     374                 : 
     375                 :   // Keep the document alive, just in case one of the handlers causes it to go
     376                 :   // away.
     377             524 :   nsCOMPtr<nsIDocument> ownerDoc = aOwnerDocument;
     378                 : 
     379             524 :   nsHandlerData handlerData;
     380             262 :   handlerData.mOperation = aOperation;
     381                 : 
     382             262 :   PRUint32 i, count = aNodesWithProperties.Count();
     383             262 :   for (i = 0; i < count; ++i) {
     384               0 :     nsINode *nodeWithProperties = aNodesWithProperties[i];
     385                 : 
     386                 :     nsresult rv;
     387               0 :     handlerData.mSource = do_QueryInterface(nodeWithProperties, &rv);
     388               0 :     NS_ENSURE_SUCCESS(rv, rv);
     389                 : 
     390               0 :     if (aCloned) {
     391               0 :       handlerData.mDest = do_QueryInterface(aNodesWithProperties[++i], &rv);
     392               0 :       NS_ENSURE_SUCCESS(rv, rv);
     393                 :     }
     394                 : 
     395               0 :     table->Enumerate(nodeWithProperties, CallHandler, &handlerData);
     396                 :   }
     397                 : 
     398             262 :   return NS_OK;
     399                 : }
     400                 : 
     401                 : static void
     402               0 : NoteUserData(void *aObject, nsIAtom *aKey, void *aXPCOMChild, void *aData)
     403                 : {
     404                 :   nsCycleCollectionTraversalCallback* cb =
     405               0 :     static_cast<nsCycleCollectionTraversalCallback*>(aData);
     406               0 :   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "[user data (or handler)]");
     407               0 :   cb->NoteXPCOMChild(static_cast<nsISupports*>(aXPCOMChild));
     408               0 : }
     409                 : 
     410                 : /* static */
     411                 : void
     412               0 : nsNodeUtils::TraverseUserData(nsINode* aNode,
     413                 :                               nsCycleCollectionTraversalCallback &aCb)
     414                 : {
     415               0 :   nsIDocument* ownerDoc = aNode->OwnerDoc();
     416               0 :   ownerDoc->PropertyTable(DOM_USER_DATA)->Enumerate(aNode, NoteUserData, &aCb);
     417               0 :   ownerDoc->PropertyTable(DOM_USER_DATA_HANDLER)->Enumerate(aNode, NoteUserData, &aCb);
     418               0 : }
     419                 : 
     420                 : /* static */
     421                 : nsresult
     422             262 : nsNodeUtils::CloneNodeImpl(nsINode *aNode, bool aDeep,
     423                 :                            bool aCallUserDataHandlers,
     424                 :                            nsIDOMNode **aResult)
     425                 : {
     426             262 :   *aResult = nsnull;
     427                 : 
     428             524 :   nsCOMPtr<nsIDOMNode> newNode;
     429             524 :   nsCOMArray<nsINode> nodesWithProperties;
     430                 :   nsresult rv = Clone(aNode, aDeep, nsnull, nodesWithProperties,
     431             262 :                       getter_AddRefs(newNode));
     432             262 :   NS_ENSURE_SUCCESS(rv, rv);
     433                 : 
     434             262 :   if (aCallUserDataHandlers) {
     435                 :     rv = CallUserDataHandlers(nodesWithProperties, aNode->OwnerDoc(),
     436             262 :                               nsIDOMUserDataHandler::NODE_CLONED, true);
     437             262 :     NS_ENSURE_SUCCESS(rv, rv);
     438                 :   }
     439                 : 
     440             262 :   newNode.swap(*aResult);
     441                 : 
     442             262 :   return NS_OK;
     443                 : }
     444                 : 
     445                 : /* static */
     446                 : nsresult
     447             823 : nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep,
     448                 :                            nsNodeInfoManager *aNewNodeInfoManager,
     449                 :                            JSContext *aCx, JSObject *aNewScope,
     450                 :                            nsCOMArray<nsINode> &aNodesWithProperties,
     451                 :                            nsINode *aParent, nsINode **aResult)
     452                 : {
     453             823 :   NS_PRECONDITION((!aClone && aNewNodeInfoManager) || !aCx,
     454                 :                   "If cloning or not getting a new nodeinfo we shouldn't "
     455                 :                   "rewrap");
     456             823 :   NS_PRECONDITION(!aCx || aNewScope, "Must have new scope");
     457             823 :   NS_PRECONDITION(!aParent || aNode->IsNodeOfType(nsINode::eCONTENT),
     458                 :                   "Can't insert document or attribute nodes into a parent");
     459                 : 
     460             823 :   *aResult = nsnull;
     461                 : 
     462                 :   // First deal with aNode and walk its attributes (and their children). Then,
     463                 :   // if aDeep is true, deal with aNode's children (and recurse into their
     464                 :   // attributes and children).
     465                 : 
     466                 :   nsresult rv;
     467                 :   JSObject *wrapper;
     468             823 :   if (aCx && (wrapper = aNode->GetWrapper())) {
     469               0 :       rv = xpc_MorphSlimWrapper(aCx, aNode);
     470               0 :       NS_ENSURE_SUCCESS(rv, rv);
     471                 :   }
     472                 : 
     473             823 :   nsNodeInfoManager *nodeInfoManager = aNewNodeInfoManager;
     474                 : 
     475                 :   // aNode.
     476             823 :   nsINodeInfo *nodeInfo = aNode->mNodeInfo;
     477            1646 :   nsCOMPtr<nsINodeInfo> newNodeInfo;
     478             823 :   if (nodeInfoManager) {
     479                 : 
     480                 :     // Don't allow importing/adopting nodes from non-privileged "scriptable"
     481                 :     // documents to "non-scriptable" documents.
     482               0 :     nsIDocument* newDoc = nodeInfoManager->GetDocument();
     483               0 :     NS_ENSURE_STATE(newDoc);
     484               0 :     bool hasHadScriptHandlingObject = false;
     485               0 :     if (!newDoc->GetScriptHandlingObject(hasHadScriptHandlingObject) &&
     486               0 :         !hasHadScriptHandlingObject) {
     487               0 :       nsIDocument* currentDoc = aNode->OwnerDoc();
     488               0 :       NS_ENSURE_STATE((nsContentUtils::IsChromeDoc(currentDoc) ||
     489                 :                        (!currentDoc->GetScriptHandlingObject(hasHadScriptHandlingObject) &&
     490                 :                         !hasHadScriptHandlingObject)));
     491                 :     }
     492                 : 
     493                 :     newNodeInfo = nodeInfoManager->GetNodeInfo(nodeInfo->NameAtom(),
     494                 :                                                nodeInfo->GetPrefixAtom(),
     495                 :                                                nodeInfo->NamespaceID(),
     496               0 :                                                nodeInfo->NodeType(),
     497               0 :                                                nodeInfo->GetExtraName());
     498               0 :     NS_ENSURE_TRUE(newNodeInfo, NS_ERROR_OUT_OF_MEMORY);
     499                 : 
     500               0 :     nodeInfo = newNodeInfo;
     501                 :   }
     502                 : 
     503             823 :   nsGenericElement *elem = aNode->IsElement() ?
     504                 :                            static_cast<nsGenericElement*>(aNode) :
     505             823 :                            nsnull;
     506                 : 
     507            1646 :   nsCOMPtr<nsINode> clone;
     508             823 :   if (aClone) {
     509             823 :     rv = aNode->Clone(nodeInfo, getter_AddRefs(clone));
     510             823 :     NS_ENSURE_SUCCESS(rv, rv);
     511                 : 
     512             823 :     if (aParent) {
     513                 :       // If we're cloning we need to insert the cloned children into the cloned
     514                 :       // parent.
     515             561 :       rv = aParent->AppendChildTo(static_cast<nsIContent*>(clone.get()),
     516             561 :                                   false);
     517             561 :       NS_ENSURE_SUCCESS(rv, rv);
     518                 :     }
     519             262 :     else if (aDeep && clone->IsNodeOfType(nsINode::eDOCUMENT)) {
     520                 :       // After cloning the document itself, we want to clone the children into
     521                 :       // the cloned document (somewhat like cloning and importing them into the
     522                 :       // cloned document).
     523               0 :       nodeInfoManager = clone->mNodeInfo->NodeInfoManager();
     524                 :     }
     525                 :   }
     526               0 :   else if (nodeInfoManager) {
     527               0 :     nsIDocument* oldDoc = aNode->OwnerDoc();
     528               0 :     bool wasRegistered = false;
     529               0 :     if (aNode->IsElement()) {
     530               0 :       Element* element = aNode->AsElement();
     531               0 :       oldDoc->ClearBoxObjectFor(element);
     532               0 :       wasRegistered = oldDoc->UnregisterFreezableElement(element);
     533                 :     }
     534                 : 
     535               0 :     aNode->mNodeInfo.swap(newNodeInfo);
     536               0 :     if (elem) {
     537               0 :       elem->NodeInfoChanged(newNodeInfo);
     538                 :     }
     539                 : 
     540               0 :     nsIDocument* newDoc = aNode->OwnerDoc();
     541               0 :     if (newDoc) {
     542                 :       // XXX what if oldDoc is null, we don't know if this should be
     543                 :       // registered or not! Can that really happen?
     544               0 :       if (wasRegistered) {
     545               0 :         newDoc->RegisterFreezableElement(aNode->AsElement());
     546                 :       }
     547                 : 
     548               0 :       nsPIDOMWindow* window = newDoc->GetInnerWindow();
     549               0 :       if (window) {
     550               0 :         nsEventListenerManager* elm = aNode->GetListenerManager(false);
     551               0 :         if (elm) {
     552               0 :           window->SetMutationListeners(elm->MutationListenerBits());
     553               0 :           if (elm->MayHavePaintEventListener()) {
     554               0 :             window->SetHasPaintEventListeners();
     555                 :           }
     556                 : #ifdef MOZ_MEDIA
     557               0 :           if (elm->MayHaveAudioAvailableEventListener()) {
     558               0 :             window->SetHasAudioAvailableEventListeners();
     559                 :           }
     560                 : #endif
     561               0 :           if (elm->MayHaveTouchEventListener()) {
     562               0 :             window->SetHasTouchEventListeners();
     563                 :           }
     564               0 :           if (elm->MayHaveMouseEnterLeaveEventListener()) {
     565               0 :             window->SetHasMouseEnterLeaveEventListeners();
     566                 :           }
     567                 :         }
     568                 :       }
     569                 :     }
     570                 : 
     571               0 :     if (wasRegistered && oldDoc != newDoc) {
     572                 : #ifdef MOZ_MEDIA
     573               0 :       nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aNode));
     574               0 :       if (domMediaElem) {
     575               0 :         nsHTMLMediaElement* mediaElem = static_cast<nsHTMLMediaElement*>(aNode);
     576               0 :         mediaElem->NotifyOwnerDocumentActivityChanged();
     577                 :       }
     578                 : #endif
     579               0 :       nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent(do_QueryInterface(aNode));
     580               0 :       if (objectLoadingContent) {
     581               0 :         nsObjectLoadingContent* olc = static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
     582               0 :         olc->NotifyOwnerDocumentActivityChanged();
     583                 :       }
     584                 :     }
     585                 : 
     586                 :     // nsImageLoadingContent needs to know when its document changes
     587               0 :     if (oldDoc != newDoc) {
     588               0 :       nsCOMPtr<nsIImageLoadingContent> imageContent(do_QueryInterface(aNode));
     589               0 :       if (imageContent)
     590               0 :         imageContent->NotifyOwnerDocumentChanged(oldDoc);
     591                 :     }
     592                 : 
     593               0 :     if (elem) {
     594               0 :       elem->RecompileScriptEventListeners();
     595                 :     }
     596                 : 
     597               0 :     if (aCx && wrapper) {
     598               0 :       nsIXPConnect *xpc = nsContentUtils::XPConnect();
     599               0 :       if (xpc) {
     600               0 :         nsCOMPtr<nsIXPConnectJSObjectHolder> oldWrapper;
     601                 :         rv = xpc->ReparentWrappedNativeIfFound(aCx, wrapper, aNewScope, aNode,
     602               0 :                                                getter_AddRefs(oldWrapper));
     603                 : 
     604               0 :         if (NS_FAILED(rv)) {
     605               0 :           aNode->mNodeInfo.swap(nodeInfo);
     606                 : 
     607               0 :           return rv;
     608                 :         }
     609                 :       }
     610                 :     }
     611                 :   }
     612                 : 
     613                 :   // XXX If there are any attribute nodes on this element with UserDataHandlers
     614                 :   // we should technically adopt/clone/import such attribute nodes and notify
     615                 :   // those handlers. However we currently don't have code to do so without
     616                 :   // also notifying when it's not safe so we're not doing that at this time.
     617                 : 
     618                 :   // The DOM spec says to always adopt/clone/import the children of attribute
     619                 :   // nodes.
     620                 :   // XXX The following block is here because our implementation of attribute
     621                 :   //     nodes is broken when it comes to inserting children. Instead of cloning
     622                 :   //     their children we force creation of the only child by calling
     623                 :   //     GetChildAt(0). We can remove this when
     624                 :   //     https://bugzilla.mozilla.org/show_bug.cgi?id=56758 is fixed.
     625             823 :   if (aClone && aNode->IsNodeOfType(nsINode::eATTRIBUTE)) {
     626              96 :     nsCOMPtr<nsINode> attrChildNode = aNode->GetChildAt(0);
     627                 :     // We only need to do this if the child node has properties (because we
     628                 :     // might need to call a userdata handler).
     629              48 :     if (attrChildNode && attrChildNode->HasProperties()) {
     630               0 :       nsCOMPtr<nsINode> clonedAttrChildNode = clone->GetChildAt(0);
     631               0 :       if (clonedAttrChildNode) {
     632               0 :         bool ok = aNodesWithProperties.AppendObject(attrChildNode) &&
     633               0 :                     aNodesWithProperties.AppendObject(clonedAttrChildNode);
     634               0 :         NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
     635                 :       }
     636                 :     }
     637                 :   }
     638                 :   // XXX End of workaround for broken attribute nodes.
     639             775 :   else if (aDeep || aNode->IsNodeOfType(nsINode::eATTRIBUTE)) {
     640                 :     // aNode's children.
     641            1327 :     for (nsIContent* cloneChild = aNode->GetFirstChild();
     642                 :          cloneChild;
     643             561 :        cloneChild = cloneChild->GetNextSibling()) {
     644            1122 :       nsCOMPtr<nsINode> child;
     645                 :       rv = CloneAndAdopt(cloneChild, aClone, true, nodeInfoManager,
     646                 :                          aCx, aNewScope, aNodesWithProperties, clone,
     647             561 :                          getter_AddRefs(child));
     648             561 :       NS_ENSURE_SUCCESS(rv, rv);
     649                 :     }
     650                 :   }
     651                 : 
     652                 :   // XXX setting document on some nodes not in a document so XBL will bind
     653                 :   // and chrome won't break. Make XBL bind to document-less nodes!
     654                 :   // XXXbz Once this is fixed, fix up the asserts in all implementations of
     655                 :   // BindToTree to assert what they would like to assert, and fix the
     656                 :   // ChangeDocumentFor() call in nsXULElement::BindToTree as well.  Also,
     657                 :   // remove the UnbindFromTree call in ~nsXULElement, and add back in the
     658                 :   // precondition in nsXULElement::UnbindFromTree and remove the line in
     659                 :   // nsXULElement.h that makes nsNodeUtils a friend of nsXULElement.
     660                 :   // Note: Make sure to do this witchery _after_ we've done any deep
     661                 :   // cloning, so kids of the new node aren't confused about whether they're
     662                 :   // in a document.
     663                 : #ifdef MOZ_XUL
     664             939 :   if (aClone && !aParent && aNode->IsElement() &&
     665             116 :       aNode->AsElement()->IsXUL()) {
     666               0 :     nsXULElement *xulElem = static_cast<nsXULElement*>(elem);
     667               0 :     if (!xulElem->mPrototype || xulElem->IsInDoc()) {
     668               0 :       clone->SetFlags(NODE_FORCE_XBL_BINDINGS);
     669                 :     }
     670                 :   }
     671                 : #endif
     672                 : 
     673             823 :   if (aNode->HasProperties()) {
     674               0 :     bool ok = aNodesWithProperties.AppendObject(aNode);
     675               0 :     if (aClone) {
     676               0 :       ok = ok && aNodesWithProperties.AppendObject(clone);
     677                 :     }
     678                 : 
     679               0 :     NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
     680                 :   }
     681                 : 
     682             823 :   clone.forget(aResult);
     683                 : 
     684             823 :   return NS_OK;
     685                 : }
     686                 : 
     687                 : 
     688                 : /* static */
     689                 : void
     690               0 : nsNodeUtils::UnlinkUserData(nsINode *aNode)
     691                 : {
     692               0 :   NS_ASSERTION(aNode->HasProperties(), "Call to UnlinkUserData not needed.");
     693                 : 
     694                 :   // Strong reference to the document so that deleting properties can't
     695                 :   // delete the document.
     696               0 :   nsCOMPtr<nsIDocument> document = aNode->OwnerDoc();
     697               0 :   document->PropertyTable(DOM_USER_DATA)->DeleteAllPropertiesFor(aNode);
     698               0 :   document->PropertyTable(DOM_USER_DATA_HANDLER)->DeleteAllPropertiesFor(aNode);
     699               0 : }

Generated by: LCOV version 1.7