1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/src/nsNodeUtils.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,661 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 sw=2 et tw=99: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsNodeUtils.h" 1.11 +#include "nsContentUtils.h" 1.12 +#include "nsCxPusher.h" 1.13 +#include "nsINode.h" 1.14 +#include "nsIContent.h" 1.15 +#include "mozilla/dom/Element.h" 1.16 +#include "nsIMutationObserver.h" 1.17 +#include "nsIDocument.h" 1.18 +#include "nsIDOMUserDataHandler.h" 1.19 +#include "mozilla/EventListenerManager.h" 1.20 +#include "nsIXPConnect.h" 1.21 +#include "pldhash.h" 1.22 +#include "nsIDOMAttr.h" 1.23 +#include "nsCOMArray.h" 1.24 +#include "nsPIDOMWindow.h" 1.25 +#include "nsDocument.h" 1.26 +#ifdef MOZ_XUL 1.27 +#include "nsXULElement.h" 1.28 +#endif 1.29 +#include "nsBindingManager.h" 1.30 +#include "nsGenericHTMLElement.h" 1.31 +#include "mozilla/dom/HTMLImageElement.h" 1.32 +#include "mozilla/dom/HTMLMediaElement.h" 1.33 +#include "nsWrapperCacheInlines.h" 1.34 +#include "nsObjectLoadingContent.h" 1.35 +#include "nsDOMMutationObserver.h" 1.36 +#include "mozilla/dom/BindingUtils.h" 1.37 +#include "mozilla/dom/HTMLTemplateElement.h" 1.38 +#include "mozilla/dom/ShadowRoot.h" 1.39 + 1.40 +using namespace mozilla; 1.41 +using namespace mozilla::dom; 1.42 +using mozilla::AutoJSContext; 1.43 + 1.44 +// This macro expects the ownerDocument of content_ to be in scope as 1.45 +// |nsIDocument* doc| 1.46 +#define IMPL_MUTATION_NOTIFICATION(func_, content_, params_) \ 1.47 + PR_BEGIN_MACRO \ 1.48 + bool needsEnterLeave = doc->MayHaveDOMMutationObservers(); \ 1.49 + if (needsEnterLeave) { \ 1.50 + nsDOMMutationObserver::EnterMutationHandling(); \ 1.51 + } \ 1.52 + nsINode* node = content_; \ 1.53 + NS_ASSERTION(node->OwnerDoc() == doc, "Bogus document"); \ 1.54 + if (doc) { \ 1.55 + doc->BindingManager()->func_ params_; \ 1.56 + } \ 1.57 + do { \ 1.58 + nsINode::nsSlots* slots = node->GetExistingSlots(); \ 1.59 + if (slots && !slots->mMutationObservers.IsEmpty()) { \ 1.60 + /* No need to explicitly notify the first observer first \ 1.61 + since that'll happen anyway. */ \ 1.62 + NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS( \ 1.63 + slots->mMutationObservers, nsIMutationObserver, \ 1.64 + func_, params_); \ 1.65 + } \ 1.66 + ShadowRoot* shadow = ShadowRoot::FromNode(node); \ 1.67 + if (shadow) { \ 1.68 + node = shadow->GetPoolHost(); \ 1.69 + } else { \ 1.70 + node = node->GetParentNode(); \ 1.71 + } \ 1.72 + } while (node); \ 1.73 + if (needsEnterLeave) { \ 1.74 + nsDOMMutationObserver::LeaveMutationHandling(); \ 1.75 + } \ 1.76 + PR_END_MACRO 1.77 + 1.78 +void 1.79 +nsNodeUtils::CharacterDataWillChange(nsIContent* aContent, 1.80 + CharacterDataChangeInfo* aInfo) 1.81 +{ 1.82 + nsIDocument* doc = aContent->OwnerDoc(); 1.83 + IMPL_MUTATION_NOTIFICATION(CharacterDataWillChange, aContent, 1.84 + (doc, aContent, aInfo)); 1.85 +} 1.86 + 1.87 +void 1.88 +nsNodeUtils::CharacterDataChanged(nsIContent* aContent, 1.89 + CharacterDataChangeInfo* aInfo) 1.90 +{ 1.91 + nsIDocument* doc = aContent->OwnerDoc(); 1.92 + IMPL_MUTATION_NOTIFICATION(CharacterDataChanged, aContent, 1.93 + (doc, aContent, aInfo)); 1.94 +} 1.95 + 1.96 +void 1.97 +nsNodeUtils::AttributeWillChange(Element* aElement, 1.98 + int32_t aNameSpaceID, 1.99 + nsIAtom* aAttribute, 1.100 + int32_t aModType) 1.101 +{ 1.102 + nsIDocument* doc = aElement->OwnerDoc(); 1.103 + IMPL_MUTATION_NOTIFICATION(AttributeWillChange, aElement, 1.104 + (doc, aElement, aNameSpaceID, aAttribute, 1.105 + aModType)); 1.106 +} 1.107 + 1.108 +void 1.109 +nsNodeUtils::AttributeChanged(Element* aElement, 1.110 + int32_t aNameSpaceID, 1.111 + nsIAtom* aAttribute, 1.112 + int32_t aModType) 1.113 +{ 1.114 + nsIDocument* doc = aElement->OwnerDoc(); 1.115 + IMPL_MUTATION_NOTIFICATION(AttributeChanged, aElement, 1.116 + (doc, aElement, aNameSpaceID, aAttribute, 1.117 + aModType)); 1.118 +} 1.119 + 1.120 +void 1.121 +nsNodeUtils::AttributeSetToCurrentValue(Element* aElement, 1.122 + int32_t aNameSpaceID, 1.123 + nsIAtom* aAttribute) 1.124 +{ 1.125 + nsIDocument* doc = aElement->OwnerDoc(); 1.126 + IMPL_MUTATION_NOTIFICATION(AttributeSetToCurrentValue, aElement, 1.127 + (doc, aElement, aNameSpaceID, aAttribute)); 1.128 +} 1.129 + 1.130 +void 1.131 +nsNodeUtils::ContentAppended(nsIContent* aContainer, 1.132 + nsIContent* aFirstNewContent, 1.133 + int32_t aNewIndexInContainer) 1.134 +{ 1.135 + nsIDocument* doc = aContainer->OwnerDoc(); 1.136 + 1.137 + IMPL_MUTATION_NOTIFICATION(ContentAppended, aContainer, 1.138 + (doc, aContainer, aFirstNewContent, 1.139 + aNewIndexInContainer)); 1.140 +} 1.141 + 1.142 +void 1.143 +nsNodeUtils::ContentInserted(nsINode* aContainer, 1.144 + nsIContent* aChild, 1.145 + int32_t aIndexInContainer) 1.146 +{ 1.147 + NS_PRECONDITION(aContainer->IsNodeOfType(nsINode::eCONTENT) || 1.148 + aContainer->IsNodeOfType(nsINode::eDOCUMENT), 1.149 + "container must be an nsIContent or an nsIDocument"); 1.150 + nsIContent* container; 1.151 + nsIDocument* doc = aContainer->OwnerDoc(); 1.152 + nsIDocument* document; 1.153 + if (aContainer->IsNodeOfType(nsINode::eCONTENT)) { 1.154 + container = static_cast<nsIContent*>(aContainer); 1.155 + document = doc; 1.156 + } 1.157 + else { 1.158 + container = nullptr; 1.159 + document = static_cast<nsIDocument*>(aContainer); 1.160 + } 1.161 + 1.162 + IMPL_MUTATION_NOTIFICATION(ContentInserted, aContainer, 1.163 + (document, container, aChild, aIndexInContainer)); 1.164 +} 1.165 + 1.166 +void 1.167 +nsNodeUtils::ContentRemoved(nsINode* aContainer, 1.168 + nsIContent* aChild, 1.169 + int32_t aIndexInContainer, 1.170 + nsIContent* aPreviousSibling) 1.171 +{ 1.172 + NS_PRECONDITION(aContainer->IsNodeOfType(nsINode::eCONTENT) || 1.173 + aContainer->IsNodeOfType(nsINode::eDOCUMENT), 1.174 + "container must be an nsIContent or an nsIDocument"); 1.175 + nsIContent* container; 1.176 + nsIDocument* doc = aContainer->OwnerDoc(); 1.177 + nsIDocument* document; 1.178 + if (aContainer->IsNodeOfType(nsINode::eCONTENT)) { 1.179 + container = static_cast<nsIContent*>(aContainer); 1.180 + document = doc; 1.181 + } 1.182 + else { 1.183 + container = nullptr; 1.184 + document = static_cast<nsIDocument*>(aContainer); 1.185 + } 1.186 + 1.187 + IMPL_MUTATION_NOTIFICATION(ContentRemoved, aContainer, 1.188 + (document, container, aChild, aIndexInContainer, 1.189 + aPreviousSibling)); 1.190 +} 1.191 + 1.192 +void 1.193 +nsNodeUtils::LastRelease(nsINode* aNode) 1.194 +{ 1.195 + nsINode::nsSlots* slots = aNode->GetExistingSlots(); 1.196 + if (slots) { 1.197 + if (!slots->mMutationObservers.IsEmpty()) { 1.198 + NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(slots->mMutationObservers, 1.199 + nsIMutationObserver, 1.200 + NodeWillBeDestroyed, (aNode)); 1.201 + } 1.202 + 1.203 + delete slots; 1.204 + aNode->mSlots = nullptr; 1.205 + } 1.206 + 1.207 + // Kill properties first since that may run external code, so we want to 1.208 + // be in as complete state as possible at that time. 1.209 + if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) { 1.210 + // Delete all properties before tearing down the document. Some of the 1.211 + // properties are bound to nsINode objects and the destructor functions of 1.212 + // the properties may want to use the owner document of the nsINode. 1.213 + static_cast<nsIDocument*>(aNode)->DeleteAllProperties(); 1.214 + } 1.215 + else { 1.216 + if (aNode->HasProperties()) { 1.217 + // Strong reference to the document so that deleting properties can't 1.218 + // delete the document. 1.219 + nsCOMPtr<nsIDocument> document = aNode->OwnerDoc(); 1.220 + document->DeleteAllPropertiesFor(aNode); 1.221 + } 1.222 + 1.223 + // I wonder whether it's faster to do the HasFlag check first.... 1.224 + if (aNode->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) && 1.225 + aNode->HasFlag(ADDED_TO_FORM)) { 1.226 + // Tell the form (if any) this node is going away. Don't 1.227 + // notify, since we're being destroyed in any case. 1.228 + static_cast<nsGenericHTMLFormElement*>(aNode)->ClearForm(true); 1.229 + } 1.230 + 1.231 + if (aNode->IsElement() && aNode->AsElement()->IsHTML(nsGkAtoms::img) && 1.232 + aNode->HasFlag(ADDED_TO_FORM)) { 1.233 + HTMLImageElement* imageElem = static_cast<HTMLImageElement*>(aNode); 1.234 + imageElem->ClearForm(true); 1.235 + } 1.236 + } 1.237 + aNode->UnsetFlags(NODE_HAS_PROPERTIES); 1.238 + 1.239 + if (aNode->NodeType() != nsIDOMNode::DOCUMENT_NODE && 1.240 + aNode->HasFlag(NODE_HAS_LISTENERMANAGER)) { 1.241 +#ifdef DEBUG 1.242 + if (nsContentUtils::IsInitialized()) { 1.243 + EventListenerManager* manager = 1.244 + nsContentUtils::GetExistingListenerManagerForNode(aNode); 1.245 + if (!manager) { 1.246 + NS_ERROR("Huh, our bit says we have a listener manager list, " 1.247 + "but there's nothing in the hash!?!!"); 1.248 + } 1.249 + } 1.250 +#endif 1.251 + 1.252 + nsContentUtils::RemoveListenerManager(aNode); 1.253 + aNode->UnsetFlags(NODE_HAS_LISTENERMANAGER); 1.254 + } 1.255 + 1.256 + if (aNode->IsElement()) { 1.257 + nsIDocument* ownerDoc = aNode->OwnerDoc(); 1.258 + Element* elem = aNode->AsElement(); 1.259 + ownerDoc->ClearBoxObjectFor(elem); 1.260 + 1.261 + NS_ASSERTION(aNode->HasFlag(NODE_FORCE_XBL_BINDINGS) || 1.262 + !elem->GetXBLBinding(), 1.263 + "Non-forced node has binding on destruction"); 1.264 + 1.265 + // if NODE_FORCE_XBL_BINDINGS is set, the node might still have a binding 1.266 + // attached 1.267 + if (aNode->HasFlag(NODE_FORCE_XBL_BINDINGS) && 1.268 + ownerDoc->BindingManager()) { 1.269 + ownerDoc->BindingManager()->RemovedFromDocument(elem, ownerDoc); 1.270 + } 1.271 + } 1.272 + 1.273 + aNode->ReleaseWrapper(aNode); 1.274 + 1.275 + FragmentOrElement::RemoveBlackMarkedNode(aNode); 1.276 +} 1.277 + 1.278 +struct MOZ_STACK_CLASS nsHandlerData 1.279 +{ 1.280 + uint16_t mOperation; 1.281 + nsCOMPtr<nsIDOMNode> mSource; 1.282 + nsCOMPtr<nsIDOMNode> mDest; 1.283 + nsCxPusher mPusher; 1.284 +}; 1.285 + 1.286 +static void 1.287 +CallHandler(void *aObject, nsIAtom *aKey, void *aHandler, void *aData) 1.288 +{ 1.289 + nsHandlerData *handlerData = static_cast<nsHandlerData*>(aData); 1.290 + nsCOMPtr<nsIDOMUserDataHandler> handler = 1.291 + static_cast<nsIDOMUserDataHandler*>(aHandler); 1.292 + nsINode *node = static_cast<nsINode*>(aObject); 1.293 + nsCOMPtr<nsIVariant> data = 1.294 + static_cast<nsIVariant*>(node->GetProperty(DOM_USER_DATA, aKey)); 1.295 + NS_ASSERTION(data, "Handler without data?"); 1.296 + 1.297 + if (!handlerData->mPusher.RePush(node)) { 1.298 + return; 1.299 + } 1.300 + nsAutoString key; 1.301 + aKey->ToString(key); 1.302 + handler->Handle(handlerData->mOperation, key, data, handlerData->mSource, 1.303 + handlerData->mDest); 1.304 +} 1.305 + 1.306 +/* static */ 1.307 +nsresult 1.308 +nsNodeUtils::CallUserDataHandlers(nsCOMArray<nsINode> &aNodesWithProperties, 1.309 + nsIDocument *aOwnerDocument, 1.310 + uint16_t aOperation, bool aCloned) 1.311 +{ 1.312 + NS_PRECONDITION(!aCloned || (aNodesWithProperties.Count() % 2 == 0), 1.313 + "Expected aNodesWithProperties to contain original and " 1.314 + "cloned nodes."); 1.315 + 1.316 + if (!nsContentUtils::IsSafeToRunScript()) { 1.317 + if (nsContentUtils::IsChromeDoc(aOwnerDocument)) { 1.318 + NS_WARNING("Fix the caller! Userdata callback disabled."); 1.319 + } else { 1.320 + NS_ERROR("This is unsafe! Fix the caller! Userdata callback disabled."); 1.321 + } 1.322 + 1.323 + return NS_OK; 1.324 + } 1.325 + 1.326 + nsPropertyTable *table = aOwnerDocument->PropertyTable(DOM_USER_DATA_HANDLER); 1.327 + 1.328 + // Keep the document alive, just in case one of the handlers causes it to go 1.329 + // away. 1.330 + nsCOMPtr<nsIDocument> ownerDoc = aOwnerDocument; 1.331 + 1.332 + nsHandlerData handlerData; 1.333 + handlerData.mOperation = aOperation; 1.334 + 1.335 + uint32_t i, count = aNodesWithProperties.Count(); 1.336 + for (i = 0; i < count; ++i) { 1.337 + nsINode *nodeWithProperties = aNodesWithProperties[i]; 1.338 + 1.339 + nsresult rv; 1.340 + handlerData.mSource = do_QueryInterface(nodeWithProperties, &rv); 1.341 + NS_ENSURE_SUCCESS(rv, rv); 1.342 + 1.343 + if (aCloned) { 1.344 + handlerData.mDest = do_QueryInterface(aNodesWithProperties[++i], &rv); 1.345 + NS_ENSURE_SUCCESS(rv, rv); 1.346 + } 1.347 + 1.348 + table->Enumerate(nodeWithProperties, CallHandler, &handlerData); 1.349 + } 1.350 + 1.351 + return NS_OK; 1.352 +} 1.353 + 1.354 +static void 1.355 +NoteUserData(void *aObject, nsIAtom *aKey, void *aXPCOMChild, void *aData) 1.356 +{ 1.357 + nsCycleCollectionTraversalCallback* cb = 1.358 + static_cast<nsCycleCollectionTraversalCallback*>(aData); 1.359 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "[user data (or handler)]"); 1.360 + cb->NoteXPCOMChild(static_cast<nsISupports*>(aXPCOMChild)); 1.361 +} 1.362 + 1.363 +/* static */ 1.364 +void 1.365 +nsNodeUtils::TraverseUserData(nsINode* aNode, 1.366 + nsCycleCollectionTraversalCallback &aCb) 1.367 +{ 1.368 + nsIDocument* ownerDoc = aNode->OwnerDoc(); 1.369 + ownerDoc->PropertyTable(DOM_USER_DATA)->Enumerate(aNode, NoteUserData, &aCb); 1.370 + ownerDoc->PropertyTable(DOM_USER_DATA_HANDLER)->Enumerate(aNode, NoteUserData, &aCb); 1.371 +} 1.372 + 1.373 +/* static */ 1.374 +nsresult 1.375 +nsNodeUtils::CloneNodeImpl(nsINode *aNode, bool aDeep, 1.376 + bool aCallUserDataHandlers, 1.377 + nsINode **aResult) 1.378 +{ 1.379 + *aResult = nullptr; 1.380 + 1.381 + nsCOMPtr<nsINode> newNode; 1.382 + nsCOMArray<nsINode> nodesWithProperties; 1.383 + nsresult rv = Clone(aNode, aDeep, nullptr, nodesWithProperties, 1.384 + getter_AddRefs(newNode)); 1.385 + NS_ENSURE_SUCCESS(rv, rv); 1.386 + 1.387 + if (aCallUserDataHandlers) { 1.388 + rv = CallUserDataHandlers(nodesWithProperties, aNode->OwnerDoc(), 1.389 + nsIDOMUserDataHandler::NODE_CLONED, true); 1.390 + NS_ENSURE_SUCCESS(rv, rv); 1.391 + } 1.392 + 1.393 + newNode.swap(*aResult); 1.394 + 1.395 + return NS_OK; 1.396 +} 1.397 + 1.398 +/* static */ 1.399 +nsresult 1.400 +nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep, 1.401 + nsNodeInfoManager *aNewNodeInfoManager, 1.402 + JS::Handle<JSObject*> aReparentScope, 1.403 + nsCOMArray<nsINode> &aNodesWithProperties, 1.404 + nsINode *aParent, nsINode **aResult) 1.405 +{ 1.406 + NS_PRECONDITION((!aClone && aNewNodeInfoManager) || !aReparentScope, 1.407 + "If cloning or not getting a new nodeinfo we shouldn't " 1.408 + "rewrap"); 1.409 + NS_PRECONDITION(!aParent || aNode->IsNodeOfType(nsINode::eCONTENT), 1.410 + "Can't insert document or attribute nodes into a parent"); 1.411 + 1.412 + *aResult = nullptr; 1.413 + 1.414 + // First deal with aNode and walk its attributes (and their children). Then, 1.415 + // if aDeep is true, deal with aNode's children (and recurse into their 1.416 + // attributes and children). 1.417 + 1.418 + AutoJSContext cx; 1.419 + nsresult rv; 1.420 + 1.421 + nsNodeInfoManager *nodeInfoManager = aNewNodeInfoManager; 1.422 + 1.423 + // aNode. 1.424 + nsINodeInfo *nodeInfo = aNode->mNodeInfo; 1.425 + nsCOMPtr<nsINodeInfo> newNodeInfo; 1.426 + if (nodeInfoManager) { 1.427 + 1.428 + // Don't allow importing/adopting nodes from non-privileged "scriptable" 1.429 + // documents to "non-scriptable" documents. 1.430 + nsIDocument* newDoc = nodeInfoManager->GetDocument(); 1.431 + NS_ENSURE_STATE(newDoc); 1.432 + bool hasHadScriptHandlingObject = false; 1.433 + if (!newDoc->GetScriptHandlingObject(hasHadScriptHandlingObject) && 1.434 + !hasHadScriptHandlingObject) { 1.435 + nsIDocument* currentDoc = aNode->OwnerDoc(); 1.436 + NS_ENSURE_STATE((nsContentUtils::IsChromeDoc(currentDoc) || 1.437 + (!currentDoc->GetScriptHandlingObject(hasHadScriptHandlingObject) && 1.438 + !hasHadScriptHandlingObject))); 1.439 + } 1.440 + 1.441 + newNodeInfo = nodeInfoManager->GetNodeInfo(nodeInfo->NameAtom(), 1.442 + nodeInfo->GetPrefixAtom(), 1.443 + nodeInfo->NamespaceID(), 1.444 + nodeInfo->NodeType(), 1.445 + nodeInfo->GetExtraName()); 1.446 + 1.447 + nodeInfo = newNodeInfo; 1.448 + } 1.449 + 1.450 + Element *elem = aNode->IsElement() ? aNode->AsElement() : nullptr; 1.451 + 1.452 + nsCOMPtr<nsINode> clone; 1.453 + if (aClone) { 1.454 + rv = aNode->Clone(nodeInfo, getter_AddRefs(clone)); 1.455 + NS_ENSURE_SUCCESS(rv, rv); 1.456 + 1.457 + if (aParent) { 1.458 + // If we're cloning we need to insert the cloned children into the cloned 1.459 + // parent. 1.460 + rv = aParent->AppendChildTo(static_cast<nsIContent*>(clone.get()), 1.461 + false); 1.462 + NS_ENSURE_SUCCESS(rv, rv); 1.463 + } 1.464 + else if (aDeep && clone->IsNodeOfType(nsINode::eDOCUMENT)) { 1.465 + // After cloning the document itself, we want to clone the children into 1.466 + // the cloned document (somewhat like cloning and importing them into the 1.467 + // cloned document). 1.468 + nodeInfoManager = clone->mNodeInfo->NodeInfoManager(); 1.469 + } 1.470 + } 1.471 + else if (nodeInfoManager) { 1.472 + nsIDocument* oldDoc = aNode->OwnerDoc(); 1.473 + bool wasRegistered = false; 1.474 + if (aNode->IsElement()) { 1.475 + Element* element = aNode->AsElement(); 1.476 + oldDoc->ClearBoxObjectFor(element); 1.477 + wasRegistered = oldDoc->UnregisterFreezableElement(element); 1.478 + } 1.479 + 1.480 + aNode->mNodeInfo.swap(newNodeInfo); 1.481 + if (elem) { 1.482 + elem->NodeInfoChanged(newNodeInfo); 1.483 + } 1.484 + 1.485 + nsIDocument* newDoc = aNode->OwnerDoc(); 1.486 + if (newDoc) { 1.487 + // XXX what if oldDoc is null, we don't know if this should be 1.488 + // registered or not! Can that really happen? 1.489 + if (wasRegistered) { 1.490 + newDoc->RegisterFreezableElement(aNode->AsElement()); 1.491 + } 1.492 + 1.493 + nsPIDOMWindow* window = newDoc->GetInnerWindow(); 1.494 + if (window) { 1.495 + EventListenerManager* elm = aNode->GetExistingListenerManager(); 1.496 + if (elm) { 1.497 + window->SetMutationListeners(elm->MutationListenerBits()); 1.498 + if (elm->MayHavePaintEventListener()) { 1.499 + window->SetHasPaintEventListeners(); 1.500 + } 1.501 + if (elm->MayHaveTouchEventListener()) { 1.502 + window->SetHasTouchEventListeners(); 1.503 + } 1.504 + if (elm->MayHaveMouseEnterLeaveEventListener()) { 1.505 + window->SetHasMouseEnterLeaveEventListeners(); 1.506 + } 1.507 + if (elm->MayHavePointerEnterLeaveEventListener()) { 1.508 + window->SetHasPointerEnterLeaveEventListeners(); 1.509 + } 1.510 + } 1.511 + } 1.512 + } 1.513 + 1.514 + if (wasRegistered && oldDoc != newDoc) { 1.515 + nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aNode)); 1.516 + if (domMediaElem) { 1.517 + HTMLMediaElement* mediaElem = static_cast<HTMLMediaElement*>(aNode); 1.518 + mediaElem->NotifyOwnerDocumentActivityChanged(); 1.519 + } 1.520 + nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent(do_QueryInterface(aNode)); 1.521 + if (objectLoadingContent) { 1.522 + nsObjectLoadingContent* olc = static_cast<nsObjectLoadingContent*>(objectLoadingContent.get()); 1.523 + olc->NotifyOwnerDocumentActivityChanged(); 1.524 + } 1.525 + } 1.526 + 1.527 + if (oldDoc != newDoc && oldDoc->MayHaveDOMMutationObservers()) { 1.528 + newDoc->SetMayHaveDOMMutationObservers(); 1.529 + } 1.530 + 1.531 + if (elem) { 1.532 + elem->RecompileScriptEventListeners(); 1.533 + } 1.534 + 1.535 + if (aReparentScope) { 1.536 + JS::Rooted<JSObject*> wrapper(cx); 1.537 + if ((wrapper = aNode->GetWrapper())) { 1.538 + if (IsDOMObject(wrapper)) { 1.539 + JSAutoCompartment ac(cx, wrapper); 1.540 + rv = ReparentWrapper(cx, wrapper); 1.541 + } else { 1.542 + nsIXPConnect *xpc = nsContentUtils::XPConnect(); 1.543 + if (xpc) { 1.544 + rv = xpc->ReparentWrappedNativeIfFound(cx, wrapper, aReparentScope, aNode); 1.545 + } else { 1.546 + rv = NS_ERROR_FAILURE; 1.547 + } 1.548 + } 1.549 + if (NS_FAILED(rv)) { 1.550 + aNode->mNodeInfo.swap(nodeInfo); 1.551 + 1.552 + return rv; 1.553 + } 1.554 + } 1.555 + } 1.556 + } 1.557 + 1.558 + // XXX If there are any attribute nodes on this element with UserDataHandlers 1.559 + // we should technically adopt/clone/import such attribute nodes and notify 1.560 + // those handlers. However we currently don't have code to do so without 1.561 + // also notifying when it's not safe so we're not doing that at this time. 1.562 + 1.563 + if (aDeep && (!aClone || !aNode->IsNodeOfType(nsINode::eATTRIBUTE))) { 1.564 + // aNode's children. 1.565 + for (nsIContent* cloneChild = aNode->GetFirstChild(); 1.566 + cloneChild; 1.567 + cloneChild = cloneChild->GetNextSibling()) { 1.568 + nsCOMPtr<nsINode> child; 1.569 + rv = CloneAndAdopt(cloneChild, aClone, true, nodeInfoManager, 1.570 + aReparentScope, aNodesWithProperties, clone, 1.571 + getter_AddRefs(child)); 1.572 + NS_ENSURE_SUCCESS(rv, rv); 1.573 + } 1.574 + } 1.575 + 1.576 + // Cloning template element. 1.577 + if (aDeep && aClone && IsTemplateElement(aNode)) { 1.578 + DocumentFragment* origContent = 1.579 + static_cast<HTMLTemplateElement*>(aNode)->Content(); 1.580 + DocumentFragment* cloneContent = 1.581 + static_cast<HTMLTemplateElement*>(clone.get())->Content(); 1.582 + 1.583 + // Clone the children into the clone's template content owner 1.584 + // document's nodeinfo manager. 1.585 + nsNodeInfoManager* ownerNodeInfoManager = 1.586 + cloneContent->mNodeInfo->NodeInfoManager(); 1.587 + 1.588 + for (nsIContent* cloneChild = origContent->GetFirstChild(); 1.589 + cloneChild; 1.590 + cloneChild = cloneChild->GetNextSibling()) { 1.591 + nsCOMPtr<nsINode> child; 1.592 + rv = CloneAndAdopt(cloneChild, aClone, aDeep, ownerNodeInfoManager, 1.593 + aReparentScope, aNodesWithProperties, cloneContent, 1.594 + getter_AddRefs(child)); 1.595 + NS_ENSURE_SUCCESS(rv, rv); 1.596 + } 1.597 + } 1.598 + 1.599 + // XXX setting document on some nodes not in a document so XBL will bind 1.600 + // and chrome won't break. Make XBL bind to document-less nodes! 1.601 + // XXXbz Once this is fixed, fix up the asserts in all implementations of 1.602 + // BindToTree to assert what they would like to assert, and fix the 1.603 + // ChangeDocumentFor() call in nsXULElement::BindToTree as well. Also, 1.604 + // remove the UnbindFromTree call in ~nsXULElement, and add back in the 1.605 + // precondition in nsXULElement::UnbindFromTree and remove the line in 1.606 + // nsXULElement.h that makes nsNodeUtils a friend of nsXULElement. 1.607 + // Note: Make sure to do this witchery _after_ we've done any deep 1.608 + // cloning, so kids of the new node aren't confused about whether they're 1.609 + // in a document. 1.610 +#ifdef MOZ_XUL 1.611 + if (aClone && !aParent && aNode->IsElement() && 1.612 + aNode->AsElement()->IsXUL()) { 1.613 + if (!aNode->OwnerDoc()->IsLoadedAsInteractiveData()) { 1.614 + clone->SetFlags(NODE_FORCE_XBL_BINDINGS); 1.615 + } 1.616 + } 1.617 +#endif 1.618 + 1.619 + if (aNode->HasProperties()) { 1.620 + bool ok = aNodesWithProperties.AppendObject(aNode); 1.621 + if (aClone) { 1.622 + ok = ok && aNodesWithProperties.AppendObject(clone); 1.623 + } 1.624 + 1.625 + NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY); 1.626 + } 1.627 + 1.628 + clone.forget(aResult); 1.629 + 1.630 + return NS_OK; 1.631 +} 1.632 + 1.633 + 1.634 +/* static */ 1.635 +void 1.636 +nsNodeUtils::UnlinkUserData(nsINode *aNode) 1.637 +{ 1.638 + NS_ASSERTION(aNode->HasProperties(), "Call to UnlinkUserData not needed."); 1.639 + 1.640 + // Strong reference to the document so that deleting properties can't 1.641 + // delete the document. 1.642 + nsCOMPtr<nsIDocument> document = aNode->OwnerDoc(); 1.643 + document->PropertyTable(DOM_USER_DATA)->DeleteAllPropertiesFor(aNode); 1.644 + document->PropertyTable(DOM_USER_DATA_HANDLER)->DeleteAllPropertiesFor(aNode); 1.645 +} 1.646 + 1.647 +bool 1.648 +nsNodeUtils::IsTemplateElement(const nsINode *aNode) 1.649 +{ 1.650 + return aNode->IsElement() && aNode->AsElement()->IsHTML(nsGkAtoms::_template); 1.651 +} 1.652 + 1.653 +nsIContent* 1.654 +nsNodeUtils::GetFirstChildOfTemplateOrNode(nsINode* aNode) 1.655 +{ 1.656 + if (nsNodeUtils::IsTemplateElement(aNode)) { 1.657 + DocumentFragment* frag = 1.658 + static_cast<HTMLTemplateElement*>(aNode)->Content(); 1.659 + return frag->GetFirstChild(); 1.660 + } 1.661 + 1.662 + return aNode->GetFirstChild(); 1.663 +} 1.664 +