1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/src/nsINode.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2695 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 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 +/* 1.11 + * Base class for all DOM nodes. 1.12 + */ 1.13 + 1.14 +#include "nsINode.h" 1.15 + 1.16 +#include "AccessCheck.h" 1.17 +#include "jsapi.h" 1.18 +#include "mozAutoDocUpdate.h" 1.19 +#include "mozilla/AsyncEventDispatcher.h" 1.20 +#include "mozilla/CORSMode.h" 1.21 +#include "mozilla/EventDispatcher.h" 1.22 +#include "mozilla/EventListenerManager.h" 1.23 +#include "mozilla/InternalMutationEvent.h" 1.24 +#include "mozilla/Likely.h" 1.25 +#include "mozilla/MemoryReporting.h" 1.26 +#include "mozilla/Telemetry.h" 1.27 +#include "mozilla/dom/Element.h" 1.28 +#include "mozilla/dom/Event.h" 1.29 +#include "mozilla/dom/ShadowRoot.h" 1.30 +#include "nsAttrValueOrString.h" 1.31 +#include "nsBindingManager.h" 1.32 +#include "nsCCUncollectableMarker.h" 1.33 +#include "nsContentCreatorFunctions.h" 1.34 +#include "nsContentList.h" 1.35 +#include "nsContentUtils.h" 1.36 +#include "nsCycleCollectionParticipant.h" 1.37 +#include "nsDocument.h" 1.38 +#include "mozilla/dom/Attr.h" 1.39 +#include "nsDOMAttributeMap.h" 1.40 +#include "nsDOMCID.h" 1.41 +#include "nsDOMCSSAttrDeclaration.h" 1.42 +#include "nsError.h" 1.43 +#include "nsDOMMutationObserver.h" 1.44 +#include "nsDOMString.h" 1.45 +#include "nsDOMTokenList.h" 1.46 +#include "nsFocusManager.h" 1.47 +#include "nsFrameManager.h" 1.48 +#include "nsFrameSelection.h" 1.49 +#include "nsGenericHTMLElement.h" 1.50 +#include "nsGkAtoms.h" 1.51 +#include "nsIAnonymousContentCreator.h" 1.52 +#include "nsIAtom.h" 1.53 +#include "nsIBaseWindow.h" 1.54 +#include "nsICategoryManager.h" 1.55 +#include "nsIContentIterator.h" 1.56 +#include "nsIControllers.h" 1.57 +#include "nsIDocument.h" 1.58 +#include "nsIDOMDocument.h" 1.59 +#include "nsIDOMDocumentType.h" 1.60 +#include "nsIDOMEvent.h" 1.61 +#include "nsIDOMEventListener.h" 1.62 +#include "nsIDOMMutationEvent.h" 1.63 +#include "nsIDOMNodeList.h" 1.64 +#include "nsIDOMUserDataHandler.h" 1.65 +#include "nsIEditor.h" 1.66 +#include "nsIEditorIMESupport.h" 1.67 +#include "nsILinkHandler.h" 1.68 +#include "nsINodeInfo.h" 1.69 +#include "nsIPresShell.h" 1.70 +#include "nsIScriptError.h" 1.71 +#include "nsIScriptGlobalObject.h" 1.72 +#include "nsIScriptSecurityManager.h" 1.73 +#include "nsIScrollableFrame.h" 1.74 +#include "nsIServiceManager.h" 1.75 +#include "nsIURL.h" 1.76 +#include "nsView.h" 1.77 +#include "nsViewManager.h" 1.78 +#include "nsIWebNavigation.h" 1.79 +#include "nsIWidget.h" 1.80 +#include "nsLayoutUtils.h" 1.81 +#include "nsNameSpaceManager.h" 1.82 +#include "nsNetUtil.h" 1.83 +#include "nsNodeInfoManager.h" 1.84 +#include "nsNodeUtils.h" 1.85 +#include "nsPIBoxObject.h" 1.86 +#include "nsPIDOMWindow.h" 1.87 +#include "nsPresContext.h" 1.88 +#include "nsRuleProcessorData.h" 1.89 +#include "nsString.h" 1.90 +#include "nsStyleConsts.h" 1.91 +#include "nsSVGFeatures.h" 1.92 +#include "nsSVGUtils.h" 1.93 +#include "nsTextNode.h" 1.94 +#include "nsUnicharUtils.h" 1.95 +#include "nsXBLBinding.h" 1.96 +#include "nsXBLPrototypeBinding.h" 1.97 +#include "prprf.h" 1.98 +#include "xpcpublic.h" 1.99 +#include "nsCSSRuleProcessor.h" 1.100 +#include "nsCSSParser.h" 1.101 +#include "HTMLLegendElement.h" 1.102 +#include "nsWrapperCacheInlines.h" 1.103 +#include "WrapperFactory.h" 1.104 +#include "DocumentType.h" 1.105 +#include <algorithm> 1.106 +#include "nsGlobalWindow.h" 1.107 +#include "nsDOMMutationObserver.h" 1.108 +#include "GeometryUtils.h" 1.109 + 1.110 +using namespace mozilla; 1.111 +using namespace mozilla::dom; 1.112 + 1.113 +nsINode::nsSlots::~nsSlots() 1.114 +{ 1.115 + if (mChildNodes) { 1.116 + mChildNodes->DropReference(); 1.117 + NS_RELEASE(mChildNodes); 1.118 + } 1.119 + 1.120 + if (mWeakReference) { 1.121 + mWeakReference->NoticeNodeDestruction(); 1.122 + } 1.123 +} 1.124 + 1.125 +void 1.126 +nsINode::nsSlots::Traverse(nsCycleCollectionTraversalCallback &cb) 1.127 +{ 1.128 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mChildNodes"); 1.129 + cb.NoteXPCOMChild(mChildNodes); 1.130 +} 1.131 + 1.132 +void 1.133 +nsINode::nsSlots::Unlink() 1.134 +{ 1.135 + if (mChildNodes) { 1.136 + mChildNodes->DropReference(); 1.137 + NS_RELEASE(mChildNodes); 1.138 + } 1.139 +} 1.140 + 1.141 +//---------------------------------------------------------------------- 1.142 + 1.143 +nsINode::~nsINode() 1.144 +{ 1.145 + MOZ_ASSERT(!HasSlots(), "nsNodeUtils::LastRelease was not called?"); 1.146 + MOZ_ASSERT(mSubtreeRoot == this, "Didn't restore state properly?"); 1.147 +} 1.148 + 1.149 +void* 1.150 +nsINode::GetProperty(uint16_t aCategory, nsIAtom *aPropertyName, 1.151 + nsresult *aStatus) const 1.152 +{ 1.153 + return OwnerDoc()->PropertyTable(aCategory)->GetProperty(this, aPropertyName, 1.154 + aStatus); 1.155 +} 1.156 + 1.157 +nsresult 1.158 +nsINode::SetProperty(uint16_t aCategory, nsIAtom *aPropertyName, void *aValue, 1.159 + NSPropertyDtorFunc aDtor, bool aTransfer, 1.160 + void **aOldValue) 1.161 +{ 1.162 + nsresult rv = OwnerDoc()->PropertyTable(aCategory)->SetProperty(this, 1.163 + aPropertyName, 1.164 + aValue, aDtor, 1.165 + nullptr, 1.166 + aTransfer, 1.167 + aOldValue); 1.168 + if (NS_SUCCEEDED(rv)) { 1.169 + SetFlags(NODE_HAS_PROPERTIES); 1.170 + } 1.171 + 1.172 + return rv; 1.173 +} 1.174 + 1.175 +void 1.176 +nsINode::DeleteProperty(uint16_t aCategory, nsIAtom *aPropertyName) 1.177 +{ 1.178 + OwnerDoc()->PropertyTable(aCategory)->DeleteProperty(this, aPropertyName); 1.179 +} 1.180 + 1.181 +void* 1.182 +nsINode::UnsetProperty(uint16_t aCategory, nsIAtom *aPropertyName, 1.183 + nsresult *aStatus) 1.184 +{ 1.185 + return OwnerDoc()->PropertyTable(aCategory)->UnsetProperty(this, 1.186 + aPropertyName, 1.187 + aStatus); 1.188 +} 1.189 + 1.190 +nsINode::nsSlots* 1.191 +nsINode::CreateSlots() 1.192 +{ 1.193 + return new nsSlots(); 1.194 +} 1.195 + 1.196 +bool 1.197 +nsINode::IsEditableInternal() const 1.198 +{ 1.199 + if (HasFlag(NODE_IS_EDITABLE)) { 1.200 + // The node is in an editable contentEditable subtree. 1.201 + return true; 1.202 + } 1.203 + 1.204 + nsIDocument *doc = GetCurrentDoc(); 1.205 + 1.206 + // Check if the node is in a document and the document is in designMode. 1.207 + return doc && doc->HasFlag(NODE_IS_EDITABLE); 1.208 +} 1.209 + 1.210 +static nsIContent* GetEditorRootContent(nsIEditor* aEditor) 1.211 +{ 1.212 + nsCOMPtr<nsIDOMElement> rootElement; 1.213 + aEditor->GetRootElement(getter_AddRefs(rootElement)); 1.214 + nsCOMPtr<nsIContent> rootContent(do_QueryInterface(rootElement)); 1.215 + return rootContent; 1.216 +} 1.217 + 1.218 +nsIContent* 1.219 +nsINode::GetTextEditorRootContent(nsIEditor** aEditor) 1.220 +{ 1.221 + if (aEditor) 1.222 + *aEditor = nullptr; 1.223 + for (nsINode* node = this; node; node = node->GetParentNode()) { 1.224 + if (!node->IsElement() || 1.225 + !node->AsElement()->IsHTML()) 1.226 + continue; 1.227 + 1.228 + nsCOMPtr<nsIEditor> editor = 1.229 + static_cast<nsGenericHTMLElement*>(node)->GetEditorInternal(); 1.230 + if (!editor) 1.231 + continue; 1.232 + 1.233 + nsIContent* rootContent = GetEditorRootContent(editor); 1.234 + if (aEditor) 1.235 + editor.swap(*aEditor); 1.236 + return rootContent; 1.237 + } 1.238 + return nullptr; 1.239 +} 1.240 + 1.241 +static nsIContent* GetRootForContentSubtree(nsIContent* aContent) 1.242 +{ 1.243 + NS_ENSURE_TRUE(aContent, nullptr); 1.244 + 1.245 + // Special case for ShadowRoot because the ShadowRoot itself is 1.246 + // the root. This is necessary to prevent selection from crossing 1.247 + // the ShadowRoot boundary. 1.248 + ShadowRoot* containingShadow = aContent->GetContainingShadow(); 1.249 + if (containingShadow) { 1.250 + return containingShadow; 1.251 + } 1.252 + 1.253 + nsIContent* stop = aContent->GetBindingParent(); 1.254 + while (aContent) { 1.255 + nsIContent* parent = aContent->GetParent(); 1.256 + if (parent == stop) { 1.257 + break; 1.258 + } 1.259 + aContent = parent; 1.260 + } 1.261 + return aContent; 1.262 +} 1.263 + 1.264 +nsIContent* 1.265 +nsINode::GetSelectionRootContent(nsIPresShell* aPresShell) 1.266 +{ 1.267 + NS_ENSURE_TRUE(aPresShell, nullptr); 1.268 + 1.269 + if (IsNodeOfType(eDOCUMENT)) 1.270 + return static_cast<nsIDocument*>(this)->GetRootElement(); 1.271 + if (!IsNodeOfType(eCONTENT)) 1.272 + return nullptr; 1.273 + 1.274 + if (GetCurrentDoc() != aPresShell->GetDocument()) { 1.275 + return nullptr; 1.276 + } 1.277 + 1.278 + if (static_cast<nsIContent*>(this)->HasIndependentSelection()) { 1.279 + // This node should be a descendant of input/textarea editor. 1.280 + nsIContent* content = GetTextEditorRootContent(); 1.281 + if (content) 1.282 + return content; 1.283 + } 1.284 + 1.285 + nsPresContext* presContext = aPresShell->GetPresContext(); 1.286 + if (presContext) { 1.287 + nsIEditor* editor = nsContentUtils::GetHTMLEditor(presContext); 1.288 + if (editor) { 1.289 + // This node is in HTML editor. 1.290 + nsIDocument* doc = GetCurrentDoc(); 1.291 + if (!doc || doc->HasFlag(NODE_IS_EDITABLE) || 1.292 + !HasFlag(NODE_IS_EDITABLE)) { 1.293 + nsIContent* editorRoot = GetEditorRootContent(editor); 1.294 + NS_ENSURE_TRUE(editorRoot, nullptr); 1.295 + return nsContentUtils::IsInSameAnonymousTree(this, editorRoot) ? 1.296 + editorRoot : 1.297 + GetRootForContentSubtree(static_cast<nsIContent*>(this)); 1.298 + } 1.299 + // If the document isn't editable but this is editable, this is in 1.300 + // contenteditable. Use the editing host element for selection root. 1.301 + return static_cast<nsIContent*>(this)->GetEditingHost(); 1.302 + } 1.303 + } 1.304 + 1.305 + nsRefPtr<nsFrameSelection> fs = aPresShell->FrameSelection(); 1.306 + nsIContent* content = fs->GetLimiter(); 1.307 + if (!content) { 1.308 + content = fs->GetAncestorLimiter(); 1.309 + if (!content) { 1.310 + nsIDocument* doc = aPresShell->GetDocument(); 1.311 + NS_ENSURE_TRUE(doc, nullptr); 1.312 + content = doc->GetRootElement(); 1.313 + if (!content) 1.314 + return nullptr; 1.315 + } 1.316 + } 1.317 + 1.318 + // This node might be in another subtree, if so, we should find this subtree's 1.319 + // root. Otherwise, we can return the content simply. 1.320 + NS_ENSURE_TRUE(content, nullptr); 1.321 + if (!nsContentUtils::IsInSameAnonymousTree(this, content)) { 1.322 + content = GetRootForContentSubtree(static_cast<nsIContent*>(this)); 1.323 + // Fixup for ShadowRoot because the ShadowRoot itself does not have a frame. 1.324 + // Use the host as the root. 1.325 + ShadowRoot* shadowRoot = ShadowRoot::FromNode(content); 1.326 + if (shadowRoot) { 1.327 + content = shadowRoot->GetHost(); 1.328 + } 1.329 + } 1.330 + 1.331 + return content; 1.332 +} 1.333 + 1.334 +nsINodeList* 1.335 +nsINode::ChildNodes() 1.336 +{ 1.337 + nsSlots* slots = Slots(); 1.338 + if (!slots->mChildNodes) { 1.339 + slots->mChildNodes = new nsChildContentList(this); 1.340 + if (slots->mChildNodes) { 1.341 + NS_ADDREF(slots->mChildNodes); 1.342 + } 1.343 + } 1.344 + 1.345 + return slots->mChildNodes; 1.346 +} 1.347 + 1.348 +void 1.349 +nsINode::GetTextContentInternal(nsAString& aTextContent) 1.350 +{ 1.351 + SetDOMStringToNull(aTextContent); 1.352 +} 1.353 + 1.354 +#ifdef DEBUG 1.355 +void 1.356 +nsINode::CheckNotNativeAnonymous() const 1.357 +{ 1.358 + if (!IsNodeOfType(eCONTENT)) 1.359 + return; 1.360 + nsIContent* content = static_cast<const nsIContent *>(this)->GetBindingParent(); 1.361 + while (content) { 1.362 + if (content->IsRootOfNativeAnonymousSubtree()) { 1.363 + NS_ERROR("Element not marked to be in native anonymous subtree!"); 1.364 + break; 1.365 + } 1.366 + content = content->GetBindingParent(); 1.367 + } 1.368 +} 1.369 +#endif 1.370 + 1.371 +bool 1.372 +nsINode::IsInAnonymousSubtree() const 1.373 +{ 1.374 + if (!IsContent()) { 1.375 + return false; 1.376 + } 1.377 + 1.378 + return AsContent()->IsInAnonymousSubtree(); 1.379 +} 1.380 + 1.381 +bool 1.382 +nsINode::IsAnonymousContentInSVGUseSubtree() const 1.383 +{ 1.384 + MOZ_ASSERT(IsInAnonymousSubtree()); 1.385 + nsIContent* parent = AsContent()->GetBindingParent(); 1.386 + // Watch out for parentless native-anonymous subtrees. 1.387 + return parent && parent->IsSVG(nsGkAtoms::use); 1.388 +} 1.389 + 1.390 +nsresult 1.391 +nsINode::GetParentNode(nsIDOMNode** aParentNode) 1.392 +{ 1.393 + *aParentNode = nullptr; 1.394 + 1.395 + nsINode *parent = GetParentNode(); 1.396 + 1.397 + return parent ? CallQueryInterface(parent, aParentNode) : NS_OK; 1.398 +} 1.399 + 1.400 +nsresult 1.401 +nsINode::GetParentElement(nsIDOMElement** aParentElement) 1.402 +{ 1.403 + *aParentElement = nullptr; 1.404 + nsINode* parent = GetParentElement(); 1.405 + return parent ? CallQueryInterface(parent, aParentElement) : NS_OK; 1.406 +} 1.407 + 1.408 +nsresult 1.409 +nsINode::GetChildNodes(nsIDOMNodeList** aChildNodes) 1.410 +{ 1.411 + NS_ADDREF(*aChildNodes = ChildNodes()); 1.412 + 1.413 + return NS_OK; 1.414 +} 1.415 + 1.416 +nsresult 1.417 +nsINode::GetFirstChild(nsIDOMNode** aNode) 1.418 +{ 1.419 + nsIContent* child = GetFirstChild(); 1.420 + if (child) { 1.421 + return CallQueryInterface(child, aNode); 1.422 + } 1.423 + 1.424 + *aNode = nullptr; 1.425 + 1.426 + return NS_OK; 1.427 +} 1.428 + 1.429 +nsresult 1.430 +nsINode::GetLastChild(nsIDOMNode** aNode) 1.431 +{ 1.432 + nsIContent* child = GetLastChild(); 1.433 + if (child) { 1.434 + return CallQueryInterface(child, aNode); 1.435 + } 1.436 + 1.437 + *aNode = nullptr; 1.438 + 1.439 + return NS_OK; 1.440 +} 1.441 + 1.442 +nsresult 1.443 +nsINode::GetPreviousSibling(nsIDOMNode** aPrevSibling) 1.444 +{ 1.445 + *aPrevSibling = nullptr; 1.446 + 1.447 + nsIContent *sibling = GetPreviousSibling(); 1.448 + 1.449 + return sibling ? CallQueryInterface(sibling, aPrevSibling) : NS_OK; 1.450 +} 1.451 + 1.452 +nsresult 1.453 +nsINode::GetNextSibling(nsIDOMNode** aNextSibling) 1.454 +{ 1.455 + *aNextSibling = nullptr; 1.456 + 1.457 + nsIContent *sibling = GetNextSibling(); 1.458 + 1.459 + return sibling ? CallQueryInterface(sibling, aNextSibling) : NS_OK; 1.460 +} 1.461 + 1.462 +nsresult 1.463 +nsINode::GetOwnerDocument(nsIDOMDocument** aOwnerDocument) 1.464 +{ 1.465 + *aOwnerDocument = nullptr; 1.466 + 1.467 + nsIDocument *ownerDoc = GetOwnerDocument(); 1.468 + 1.469 + return ownerDoc ? CallQueryInterface(ownerDoc, aOwnerDocument) : NS_OK; 1.470 +} 1.471 + 1.472 +void 1.473 +nsINode::GetNodeValueInternal(nsAString& aNodeValue) 1.474 +{ 1.475 + SetDOMStringToNull(aNodeValue); 1.476 +} 1.477 + 1.478 +nsINode* 1.479 +nsINode::RemoveChild(nsINode& aOldChild, ErrorResult& aError) 1.480 +{ 1.481 + if (IsNodeOfType(eDATA_NODE)) { 1.482 + // aOldChild can't be one of our children. 1.483 + aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR); 1.484 + return nullptr; 1.485 + } 1.486 + 1.487 + if (aOldChild.GetParentNode() == this) { 1.488 + nsContentUtils::MaybeFireNodeRemoved(&aOldChild, this, OwnerDoc()); 1.489 + } 1.490 + 1.491 + int32_t index = IndexOf(&aOldChild); 1.492 + if (index == -1) { 1.493 + // aOldChild isn't one of our children. 1.494 + aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR); 1.495 + return nullptr; 1.496 + } 1.497 + 1.498 + RemoveChildAt(index, true); 1.499 + return &aOldChild; 1.500 +} 1.501 + 1.502 +nsresult 1.503 +nsINode::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn) 1.504 +{ 1.505 + nsCOMPtr<nsINode> oldChild = do_QueryInterface(aOldChild); 1.506 + if (!oldChild) { 1.507 + return NS_ERROR_NULL_POINTER; 1.508 + } 1.509 + 1.510 + ErrorResult rv; 1.511 + RemoveChild(*oldChild, rv); 1.512 + if (!rv.Failed()) { 1.513 + NS_ADDREF(*aReturn = aOldChild); 1.514 + } 1.515 + return rv.ErrorCode(); 1.516 +} 1.517 + 1.518 +void 1.519 +nsINode::Normalize() 1.520 +{ 1.521 + // First collect list of nodes to be removed 1.522 + nsAutoTArray<nsCOMPtr<nsIContent>, 50> nodes; 1.523 + 1.524 + bool canMerge = false; 1.525 + for (nsIContent* node = this->GetFirstChild(); 1.526 + node; 1.527 + node = node->GetNextNode(this)) { 1.528 + if (node->NodeType() != nsIDOMNode::TEXT_NODE) { 1.529 + canMerge = false; 1.530 + continue; 1.531 + } 1.532 + 1.533 + if (canMerge || node->TextLength() == 0) { 1.534 + // No need to touch canMerge. That way we can merge across empty 1.535 + // textnodes if and only if the node before is a textnode 1.536 + nodes.AppendElement(node); 1.537 + } 1.538 + else { 1.539 + canMerge = true; 1.540 + } 1.541 + 1.542 + // If there's no following sibling, then we need to ensure that we don't 1.543 + // collect following siblings of our (grand)parent as to-be-removed 1.544 + canMerge = canMerge && !!node->GetNextSibling(); 1.545 + } 1.546 + 1.547 + if (nodes.IsEmpty()) { 1.548 + return; 1.549 + } 1.550 + 1.551 + // We're relying on mozAutoSubtreeModified to keep the doc alive here. 1.552 + nsIDocument* doc = OwnerDoc(); 1.553 + 1.554 + // Batch possible DOMSubtreeModified events. 1.555 + mozAutoSubtreeModified subtree(doc, nullptr); 1.556 + 1.557 + // Fire all DOMNodeRemoved events. Optimize the common case of there being 1.558 + // no listeners 1.559 + bool hasRemoveListeners = nsContentUtils:: 1.560 + HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEREMOVED); 1.561 + if (hasRemoveListeners) { 1.562 + for (uint32_t i = 0; i < nodes.Length(); ++i) { 1.563 + nsINode* parentNode = nodes[i]->GetParentNode(); 1.564 + if (parentNode) { // Node may have already been removed. 1.565 + nsContentUtils::MaybeFireNodeRemoved(nodes[i], parentNode, 1.566 + doc); 1.567 + } 1.568 + } 1.569 + } 1.570 + 1.571 + mozAutoDocUpdate batch(doc, UPDATE_CONTENT_MODEL, true); 1.572 + 1.573 + // Merge and remove all nodes 1.574 + nsAutoString tmpStr; 1.575 + for (uint32_t i = 0; i < nodes.Length(); ++i) { 1.576 + nsIContent* node = nodes[i]; 1.577 + // Merge with previous node unless empty 1.578 + const nsTextFragment* text = node->GetText(); 1.579 + if (text->GetLength()) { 1.580 + nsIContent* target = node->GetPreviousSibling(); 1.581 + NS_ASSERTION((target && target->NodeType() == nsIDOMNode::TEXT_NODE) || 1.582 + hasRemoveListeners, 1.583 + "Should always have a previous text sibling unless " 1.584 + "mutation events messed us up"); 1.585 + if (!hasRemoveListeners || 1.586 + (target && target->NodeType() == nsIDOMNode::TEXT_NODE)) { 1.587 + nsTextNode* t = static_cast<nsTextNode*>(target); 1.588 + if (text->Is2b()) { 1.589 + t->AppendTextForNormalize(text->Get2b(), text->GetLength(), true, node); 1.590 + } 1.591 + else { 1.592 + tmpStr.Truncate(); 1.593 + text->AppendTo(tmpStr); 1.594 + t->AppendTextForNormalize(tmpStr.get(), tmpStr.Length(), true, node); 1.595 + } 1.596 + } 1.597 + } 1.598 + 1.599 + // Remove node 1.600 + nsCOMPtr<nsINode> parent = node->GetParentNode(); 1.601 + NS_ASSERTION(parent || hasRemoveListeners, 1.602 + "Should always have a parent unless " 1.603 + "mutation events messed us up"); 1.604 + if (parent) { 1.605 + parent->RemoveChildAt(parent->IndexOf(node), true); 1.606 + } 1.607 + } 1.608 +} 1.609 + 1.610 +void 1.611 +nsINode::GetBaseURI(nsAString &aURI) const 1.612 +{ 1.613 + nsCOMPtr<nsIURI> baseURI = GetBaseURI(); 1.614 + 1.615 + nsAutoCString spec; 1.616 + if (baseURI) { 1.617 + baseURI->GetSpec(spec); 1.618 + } 1.619 + 1.620 + CopyUTF8toUTF16(spec, aURI); 1.621 +} 1.622 + 1.623 +void 1.624 +nsINode::GetBaseURIFromJS(nsAString& aURI) const 1.625 +{ 1.626 + nsCOMPtr<nsIURI> baseURI = GetBaseURI(nsContentUtils::IsCallerChrome()); 1.627 + nsAutoCString spec; 1.628 + if (baseURI) { 1.629 + baseURI->GetSpec(spec); 1.630 + } 1.631 + CopyUTF8toUTF16(spec, aURI); 1.632 +} 1.633 + 1.634 +already_AddRefed<nsIURI> 1.635 +nsINode::GetBaseURIObject() const 1.636 +{ 1.637 + return GetBaseURI(true); 1.638 +} 1.639 + 1.640 +void 1.641 +nsINode::LookupPrefix(const nsAString& aNamespaceURI, nsAString& aPrefix) 1.642 +{ 1.643 + Element *element = GetNameSpaceElement(); 1.644 + if (element) { 1.645 + // XXX Waiting for DOM spec to list error codes. 1.646 + 1.647 + // Trace up the content parent chain looking for the namespace 1.648 + // declaration that defines the aNamespaceURI namespace. Once found, 1.649 + // return the prefix (i.e. the attribute localName). 1.650 + for (nsIContent* content = element; content; 1.651 + content = content->GetParent()) { 1.652 + uint32_t attrCount = content->GetAttrCount(); 1.653 + 1.654 + for (uint32_t i = 0; i < attrCount; ++i) { 1.655 + const nsAttrName* name = content->GetAttrNameAt(i); 1.656 + 1.657 + if (name->NamespaceEquals(kNameSpaceID_XMLNS) && 1.658 + content->AttrValueIs(kNameSpaceID_XMLNS, name->LocalName(), 1.659 + aNamespaceURI, eCaseMatters)) { 1.660 + // If the localName is "xmlns", the prefix we output should be 1.661 + // null. 1.662 + nsIAtom *localName = name->LocalName(); 1.663 + 1.664 + if (localName != nsGkAtoms::xmlns) { 1.665 + localName->ToString(aPrefix); 1.666 + } 1.667 + else { 1.668 + SetDOMStringToNull(aPrefix); 1.669 + } 1.670 + return; 1.671 + } 1.672 + } 1.673 + } 1.674 + } 1.675 + 1.676 + SetDOMStringToNull(aPrefix); 1.677 +} 1.678 + 1.679 +static nsresult 1.680 +SetUserDataProperty(uint16_t aCategory, nsINode *aNode, nsIAtom *aKey, 1.681 + nsISupports* aValue, void** aOldValue) 1.682 +{ 1.683 + nsresult rv = aNode->SetProperty(aCategory, aKey, aValue, 1.684 + nsPropertyTable::SupportsDtorFunc, true, 1.685 + aOldValue); 1.686 + NS_ENSURE_SUCCESS(rv, rv); 1.687 + 1.688 + // Property table owns it now. 1.689 + NS_ADDREF(aValue); 1.690 + 1.691 + return NS_OK; 1.692 +} 1.693 + 1.694 +nsresult 1.695 +nsINode::SetUserData(const nsAString &aKey, nsIVariant *aData, 1.696 + nsIDOMUserDataHandler *aHandler, nsIVariant **aResult) 1.697 +{ 1.698 + OwnerDoc()->WarnOnceAbout(nsIDocument::eGetSetUserData); 1.699 + *aResult = nullptr; 1.700 + 1.701 + nsCOMPtr<nsIAtom> key = do_GetAtom(aKey); 1.702 + if (!key) { 1.703 + return NS_ERROR_OUT_OF_MEMORY; 1.704 + } 1.705 + 1.706 + nsresult rv; 1.707 + void *data; 1.708 + if (aData) { 1.709 + rv = SetUserDataProperty(DOM_USER_DATA, this, key, aData, &data); 1.710 + NS_ENSURE_SUCCESS(rv, rv); 1.711 + } 1.712 + else { 1.713 + data = UnsetProperty(DOM_USER_DATA, key); 1.714 + } 1.715 + 1.716 + // Take over ownership of the old data from the property table. 1.717 + nsCOMPtr<nsIVariant> oldData = dont_AddRef(static_cast<nsIVariant*>(data)); 1.718 + 1.719 + if (aData && aHandler) { 1.720 + nsCOMPtr<nsIDOMUserDataHandler> oldHandler; 1.721 + rv = SetUserDataProperty(DOM_USER_DATA_HANDLER, this, key, aHandler, 1.722 + getter_AddRefs(oldHandler)); 1.723 + if (NS_FAILED(rv)) { 1.724 + // We failed to set the handler, remove the data. 1.725 + DeleteProperty(DOM_USER_DATA, key); 1.726 + 1.727 + return rv; 1.728 + } 1.729 + } 1.730 + else { 1.731 + DeleteProperty(DOM_USER_DATA_HANDLER, key); 1.732 + } 1.733 + 1.734 + oldData.swap(*aResult); 1.735 + 1.736 + return NS_OK; 1.737 +} 1.738 + 1.739 +void 1.740 +nsINode::SetUserData(JSContext* aCx, const nsAString& aKey, 1.741 + JS::Handle<JS::Value> aData, 1.742 + nsIDOMUserDataHandler* aHandler, 1.743 + JS::MutableHandle<JS::Value> aRetval, 1.744 + ErrorResult& aError) 1.745 +{ 1.746 + nsCOMPtr<nsIVariant> data; 1.747 + aError = nsContentUtils::XPConnect()->JSValToVariant(aCx, aData, getter_AddRefs(data)); 1.748 + if (aError.Failed()) { 1.749 + return; 1.750 + } 1.751 + 1.752 + nsCOMPtr<nsIVariant> oldData; 1.753 + aError = SetUserData(aKey, data, aHandler, getter_AddRefs(oldData)); 1.754 + if (aError.Failed()) { 1.755 + return; 1.756 + } 1.757 + 1.758 + if (!oldData) { 1.759 + aRetval.setNull(); 1.760 + return; 1.761 + } 1.762 + 1.763 + JSAutoCompartment ac(aCx, GetWrapper()); 1.764 + aError = nsContentUtils::XPConnect()->VariantToJS(aCx, GetWrapper(), oldData, 1.765 + aRetval); 1.766 +} 1.767 + 1.768 +nsIVariant* 1.769 +nsINode::GetUserData(const nsAString& aKey) 1.770 +{ 1.771 + OwnerDoc()->WarnOnceAbout(nsIDocument::eGetSetUserData); 1.772 + nsCOMPtr<nsIAtom> key = do_GetAtom(aKey); 1.773 + if (!key) { 1.774 + return nullptr; 1.775 + } 1.776 + 1.777 + return static_cast<nsIVariant*>(GetProperty(DOM_USER_DATA, key)); 1.778 +} 1.779 + 1.780 +void 1.781 +nsINode::GetUserData(JSContext* aCx, const nsAString& aKey, 1.782 + JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError) 1.783 +{ 1.784 + nsIVariant* data = GetUserData(aKey); 1.785 + if (!data) { 1.786 + aRetval.setNull(); 1.787 + return; 1.788 + } 1.789 + 1.790 + JSAutoCompartment ac(aCx, GetWrapper()); 1.791 + aError = nsContentUtils::XPConnect()->VariantToJS(aCx, GetWrapper(), data, 1.792 + aRetval); 1.793 +} 1.794 + 1.795 +uint16_t 1.796 +nsINode::CompareDocumentPosition(nsINode& aOtherNode) const 1.797 +{ 1.798 + if (this == &aOtherNode) { 1.799 + return 0; 1.800 + } 1.801 + if (GetPreviousSibling() == &aOtherNode) { 1.802 + MOZ_ASSERT(GetParentNode() == aOtherNode.GetParentNode()); 1.803 + return static_cast<uint16_t>(nsIDOMNode::DOCUMENT_POSITION_PRECEDING); 1.804 + } 1.805 + if (GetNextSibling() == &aOtherNode) { 1.806 + MOZ_ASSERT(GetParentNode() == aOtherNode.GetParentNode()); 1.807 + return static_cast<uint16_t>(nsIDOMNode::DOCUMENT_POSITION_FOLLOWING); 1.808 + } 1.809 + 1.810 + nsAutoTArray<const nsINode*, 32> parents1, parents2; 1.811 + 1.812 + const nsINode *node1 = &aOtherNode, *node2 = this; 1.813 + 1.814 + // Check if either node is an attribute 1.815 + const Attr* attr1 = nullptr; 1.816 + if (node1->IsNodeOfType(nsINode::eATTRIBUTE)) { 1.817 + attr1 = static_cast<const Attr*>(node1); 1.818 + const Element* elem = attr1->GetElement(); 1.819 + // If there is an owner element add the attribute 1.820 + // to the chain and walk up to the element 1.821 + if (elem) { 1.822 + node1 = elem; 1.823 + parents1.AppendElement(attr1); 1.824 + } 1.825 + } 1.826 + if (node2->IsNodeOfType(nsINode::eATTRIBUTE)) { 1.827 + const Attr* attr2 = static_cast<const Attr*>(node2); 1.828 + const Element* elem = attr2->GetElement(); 1.829 + if (elem == node1 && attr1) { 1.830 + // Both nodes are attributes on the same element. 1.831 + // Compare position between the attributes. 1.832 + 1.833 + uint32_t i; 1.834 + const nsAttrName* attrName; 1.835 + for (i = 0; (attrName = elem->GetAttrNameAt(i)); ++i) { 1.836 + if (attrName->Equals(attr1->NodeInfo())) { 1.837 + NS_ASSERTION(!attrName->Equals(attr2->NodeInfo()), 1.838 + "Different attrs at same position"); 1.839 + return nsIDOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | 1.840 + nsIDOMNode::DOCUMENT_POSITION_PRECEDING; 1.841 + } 1.842 + if (attrName->Equals(attr2->NodeInfo())) { 1.843 + return nsIDOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | 1.844 + nsIDOMNode::DOCUMENT_POSITION_FOLLOWING; 1.845 + } 1.846 + } 1.847 + NS_NOTREACHED("neither attribute in the element"); 1.848 + return nsIDOMNode::DOCUMENT_POSITION_DISCONNECTED; 1.849 + } 1.850 + 1.851 + if (elem) { 1.852 + node2 = elem; 1.853 + parents2.AppendElement(attr2); 1.854 + } 1.855 + } 1.856 + 1.857 + // We now know that both nodes are either nsIContents or nsIDocuments. 1.858 + // If either node started out as an attribute, that attribute will have 1.859 + // the same relative position as its ownerElement, except if the 1.860 + // ownerElement ends up being the container for the other node 1.861 + 1.862 + // Build the chain of parents 1.863 + do { 1.864 + parents1.AppendElement(node1); 1.865 + node1 = node1->GetParentNode(); 1.866 + } while (node1); 1.867 + do { 1.868 + parents2.AppendElement(node2); 1.869 + node2 = node2->GetParentNode(); 1.870 + } while (node2); 1.871 + 1.872 + // Check if the nodes are disconnected. 1.873 + uint32_t pos1 = parents1.Length(); 1.874 + uint32_t pos2 = parents2.Length(); 1.875 + const nsINode* top1 = parents1.ElementAt(--pos1); 1.876 + const nsINode* top2 = parents2.ElementAt(--pos2); 1.877 + if (top1 != top2) { 1.878 + return top1 < top2 ? 1.879 + (nsIDOMNode::DOCUMENT_POSITION_PRECEDING | 1.880 + nsIDOMNode::DOCUMENT_POSITION_DISCONNECTED | 1.881 + nsIDOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC) : 1.882 + (nsIDOMNode::DOCUMENT_POSITION_FOLLOWING | 1.883 + nsIDOMNode::DOCUMENT_POSITION_DISCONNECTED | 1.884 + nsIDOMNode::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC); 1.885 + } 1.886 + 1.887 + // Find where the parent chain differs and check indices in the parent. 1.888 + const nsINode* parent = top1; 1.889 + uint32_t len; 1.890 + for (len = std::min(pos1, pos2); len > 0; --len) { 1.891 + const nsINode* child1 = parents1.ElementAt(--pos1); 1.892 + const nsINode* child2 = parents2.ElementAt(--pos2); 1.893 + if (child1 != child2) { 1.894 + // child1 or child2 can be an attribute here. This will work fine since 1.895 + // IndexOf will return -1 for the attribute making the attribute be 1.896 + // considered before any child. 1.897 + return parent->IndexOf(child1) < parent->IndexOf(child2) ? 1.898 + static_cast<uint16_t>(nsIDOMNode::DOCUMENT_POSITION_PRECEDING) : 1.899 + static_cast<uint16_t>(nsIDOMNode::DOCUMENT_POSITION_FOLLOWING); 1.900 + } 1.901 + parent = child1; 1.902 + } 1.903 + 1.904 + // We hit the end of one of the parent chains without finding a difference 1.905 + // between the chains. That must mean that one node is an ancestor of the 1.906 + // other. The one with the shortest chain must be the ancestor. 1.907 + return pos1 < pos2 ? 1.908 + (nsIDOMNode::DOCUMENT_POSITION_PRECEDING | 1.909 + nsIDOMNode::DOCUMENT_POSITION_CONTAINS) : 1.910 + (nsIDOMNode::DOCUMENT_POSITION_FOLLOWING | 1.911 + nsIDOMNode::DOCUMENT_POSITION_CONTAINED_BY); 1.912 +} 1.913 + 1.914 +bool 1.915 +nsINode::IsEqualNode(nsINode* aOther) 1.916 +{ 1.917 + if (!aOther) { 1.918 + return false; 1.919 + } 1.920 + 1.921 + nsAutoString string1, string2; 1.922 + 1.923 + nsINode* node1 = this; 1.924 + nsINode* node2 = aOther; 1.925 + do { 1.926 + uint16_t nodeType = node1->NodeType(); 1.927 + if (nodeType != node2->NodeType()) { 1.928 + return false; 1.929 + } 1.930 + 1.931 + nsINodeInfo* nodeInfo1 = node1->mNodeInfo; 1.932 + nsINodeInfo* nodeInfo2 = node2->mNodeInfo; 1.933 + if (!nodeInfo1->Equals(nodeInfo2) || 1.934 + nodeInfo1->GetExtraName() != nodeInfo2->GetExtraName()) { 1.935 + return false; 1.936 + } 1.937 + 1.938 + switch(nodeType) { 1.939 + case nsIDOMNode::ELEMENT_NODE: 1.940 + { 1.941 + // Both are elements (we checked that their nodeinfos are equal). Do the 1.942 + // check on attributes. 1.943 + Element* element1 = node1->AsElement(); 1.944 + Element* element2 = node2->AsElement(); 1.945 + uint32_t attrCount = element1->GetAttrCount(); 1.946 + if (attrCount != element2->GetAttrCount()) { 1.947 + return false; 1.948 + } 1.949 + 1.950 + // Iterate over attributes. 1.951 + for (uint32_t i = 0; i < attrCount; ++i) { 1.952 + const nsAttrName* attrName = element1->GetAttrNameAt(i); 1.953 +#ifdef DEBUG 1.954 + bool hasAttr = 1.955 +#endif 1.956 + element1->GetAttr(attrName->NamespaceID(), attrName->LocalName(), 1.957 + string1); 1.958 + NS_ASSERTION(hasAttr, "Why don't we have an attr?"); 1.959 + 1.960 + if (!element2->AttrValueIs(attrName->NamespaceID(), 1.961 + attrName->LocalName(), 1.962 + string1, 1.963 + eCaseMatters)) { 1.964 + return false; 1.965 + } 1.966 + } 1.967 + break; 1.968 + } 1.969 + case nsIDOMNode::TEXT_NODE: 1.970 + case nsIDOMNode::COMMENT_NODE: 1.971 + case nsIDOMNode::CDATA_SECTION_NODE: 1.972 + case nsIDOMNode::PROCESSING_INSTRUCTION_NODE: 1.973 + { 1.974 + string1.Truncate(); 1.975 + static_cast<nsIContent*>(node1)->AppendTextTo(string1); 1.976 + string2.Truncate(); 1.977 + static_cast<nsIContent*>(node2)->AppendTextTo(string2); 1.978 + 1.979 + if (!string1.Equals(string2)) { 1.980 + return false; 1.981 + } 1.982 + 1.983 + break; 1.984 + } 1.985 + case nsIDOMNode::DOCUMENT_NODE: 1.986 + case nsIDOMNode::DOCUMENT_FRAGMENT_NODE: 1.987 + break; 1.988 + case nsIDOMNode::ATTRIBUTE_NODE: 1.989 + { 1.990 + NS_ASSERTION(node1 == this && node2 == aOther, 1.991 + "Did we come upon an attribute node while walking a " 1.992 + "subtree?"); 1.993 + node1->GetNodeValue(string1); 1.994 + node2->GetNodeValue(string2); 1.995 + 1.996 + // Returning here as to not bother walking subtree. And there is no 1.997 + // risk that we're half way through walking some other subtree since 1.998 + // attribute nodes doesn't appear in subtrees. 1.999 + return string1.Equals(string2); 1.1000 + } 1.1001 + case nsIDOMNode::DOCUMENT_TYPE_NODE: 1.1002 + { 1.1003 + nsCOMPtr<nsIDOMDocumentType> docType1 = do_QueryInterface(node1); 1.1004 + nsCOMPtr<nsIDOMDocumentType> docType2 = do_QueryInterface(node2); 1.1005 + 1.1006 + NS_ASSERTION(docType1 && docType2, "Why don't we have a document type node?"); 1.1007 + 1.1008 + // Public ID 1.1009 + docType1->GetPublicId(string1); 1.1010 + docType2->GetPublicId(string2); 1.1011 + if (!string1.Equals(string2)) { 1.1012 + return false; 1.1013 + } 1.1014 + 1.1015 + // System ID 1.1016 + docType1->GetSystemId(string1); 1.1017 + docType2->GetSystemId(string2); 1.1018 + if (!string1.Equals(string2)) { 1.1019 + return false; 1.1020 + } 1.1021 + 1.1022 + // Internal subset 1.1023 + docType1->GetInternalSubset(string1); 1.1024 + docType2->GetInternalSubset(string2); 1.1025 + if (!string1.Equals(string2)) { 1.1026 + return false; 1.1027 + } 1.1028 + 1.1029 + break; 1.1030 + } 1.1031 + default: 1.1032 + NS_ABORT_IF_FALSE(false, "Unknown node type"); 1.1033 + } 1.1034 + 1.1035 + nsINode* nextNode = node1->GetFirstChild(); 1.1036 + if (nextNode) { 1.1037 + node1 = nextNode; 1.1038 + node2 = node2->GetFirstChild(); 1.1039 + } 1.1040 + else { 1.1041 + if (node2->GetFirstChild()) { 1.1042 + // node2 has a firstChild, but node1 doesn't 1.1043 + return false; 1.1044 + } 1.1045 + 1.1046 + // Find next sibling, possibly walking parent chain. 1.1047 + while (1) { 1.1048 + if (node1 == this) { 1.1049 + NS_ASSERTION(node2 == aOther, "Should have reached the start node " 1.1050 + "for both trees at the same time"); 1.1051 + return true; 1.1052 + } 1.1053 + 1.1054 + nextNode = node1->GetNextSibling(); 1.1055 + if (nextNode) { 1.1056 + node1 = nextNode; 1.1057 + node2 = node2->GetNextSibling(); 1.1058 + break; 1.1059 + } 1.1060 + 1.1061 + if (node2->GetNextSibling()) { 1.1062 + // node2 has a nextSibling, but node1 doesn't 1.1063 + return false; 1.1064 + } 1.1065 + 1.1066 + node1 = node1->GetParentNode(); 1.1067 + node2 = node2->GetParentNode(); 1.1068 + NS_ASSERTION(node1 && node2, "no parent while walking subtree"); 1.1069 + } 1.1070 + } 1.1071 + } while(node2); 1.1072 + 1.1073 + return false; 1.1074 +} 1.1075 + 1.1076 +void 1.1077 +nsINode::LookupNamespaceURI(const nsAString& aNamespacePrefix, 1.1078 + nsAString& aNamespaceURI) 1.1079 +{ 1.1080 + Element *element = GetNameSpaceElement(); 1.1081 + if (!element || 1.1082 + NS_FAILED(element->LookupNamespaceURIInternal(aNamespacePrefix, 1.1083 + aNamespaceURI))) { 1.1084 + SetDOMStringToNull(aNamespaceURI); 1.1085 + } 1.1086 +} 1.1087 + 1.1088 +NS_IMPL_DOMTARGET_DEFAULTS(nsINode) 1.1089 + 1.1090 +NS_IMETHODIMP 1.1091 +nsINode::AddEventListener(const nsAString& aType, 1.1092 + nsIDOMEventListener *aListener, 1.1093 + bool aUseCapture, 1.1094 + bool aWantsUntrusted, 1.1095 + uint8_t aOptionalArgc) 1.1096 +{ 1.1097 + NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1, 1.1098 + "Won't check if this is chrome, you want to set " 1.1099 + "aWantsUntrusted to false or make the aWantsUntrusted " 1.1100 + "explicit by making aOptionalArgc non-zero."); 1.1101 + 1.1102 + if (!aWantsUntrusted && 1.1103 + (aOptionalArgc < 2 && 1.1104 + !nsContentUtils::IsChromeDoc(OwnerDoc()))) { 1.1105 + aWantsUntrusted = true; 1.1106 + } 1.1107 + 1.1108 + EventListenerManager* listener_manager = GetOrCreateListenerManager(); 1.1109 + NS_ENSURE_STATE(listener_manager); 1.1110 + listener_manager->AddEventListener(aType, aListener, aUseCapture, 1.1111 + aWantsUntrusted); 1.1112 + return NS_OK; 1.1113 +} 1.1114 + 1.1115 +void 1.1116 +nsINode::AddEventListener(const nsAString& aType, 1.1117 + EventListener* aListener, 1.1118 + bool aUseCapture, 1.1119 + const Nullable<bool>& aWantsUntrusted, 1.1120 + ErrorResult& aRv) 1.1121 +{ 1.1122 + bool wantsUntrusted; 1.1123 + if (aWantsUntrusted.IsNull()) { 1.1124 + wantsUntrusted = !nsContentUtils::IsChromeDoc(OwnerDoc()); 1.1125 + } else { 1.1126 + wantsUntrusted = aWantsUntrusted.Value(); 1.1127 + } 1.1128 + 1.1129 + EventListenerManager* listener_manager = GetOrCreateListenerManager(); 1.1130 + if (!listener_manager) { 1.1131 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.1132 + return; 1.1133 + } 1.1134 + listener_manager->AddEventListener(aType, aListener, aUseCapture, 1.1135 + wantsUntrusted); 1.1136 +} 1.1137 + 1.1138 +NS_IMETHODIMP 1.1139 +nsINode::AddSystemEventListener(const nsAString& aType, 1.1140 + nsIDOMEventListener *aListener, 1.1141 + bool aUseCapture, 1.1142 + bool aWantsUntrusted, 1.1143 + uint8_t aOptionalArgc) 1.1144 +{ 1.1145 + NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1, 1.1146 + "Won't check if this is chrome, you want to set " 1.1147 + "aWantsUntrusted to false or make the aWantsUntrusted " 1.1148 + "explicit by making aOptionalArgc non-zero."); 1.1149 + 1.1150 + if (!aWantsUntrusted && 1.1151 + (aOptionalArgc < 2 && 1.1152 + !nsContentUtils::IsChromeDoc(OwnerDoc()))) { 1.1153 + aWantsUntrusted = true; 1.1154 + } 1.1155 + 1.1156 + return NS_AddSystemEventListener(this, aType, aListener, aUseCapture, 1.1157 + aWantsUntrusted); 1.1158 +} 1.1159 + 1.1160 +NS_IMETHODIMP 1.1161 +nsINode::RemoveEventListener(const nsAString& aType, 1.1162 + nsIDOMEventListener* aListener, 1.1163 + bool aUseCapture) 1.1164 +{ 1.1165 + EventListenerManager* elm = GetExistingListenerManager(); 1.1166 + if (elm) { 1.1167 + elm->RemoveEventListener(aType, aListener, aUseCapture); 1.1168 + } 1.1169 + return NS_OK; 1.1170 +} 1.1171 + 1.1172 +NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsINode) 1.1173 + 1.1174 +nsresult 1.1175 +nsINode::PreHandleEvent(EventChainPreVisitor& aVisitor) 1.1176 +{ 1.1177 + // This is only here so that we can use the NS_DECL_NSIDOMTARGET macro 1.1178 + NS_ABORT(); 1.1179 + return NS_ERROR_NOT_IMPLEMENTED; 1.1180 +} 1.1181 + 1.1182 +void 1.1183 +nsINode::GetBoxQuads(const BoxQuadOptions& aOptions, 1.1184 + nsTArray<nsRefPtr<DOMQuad> >& aResult, 1.1185 + mozilla::ErrorResult& aRv) 1.1186 +{ 1.1187 + mozilla::GetBoxQuads(this, aOptions, aResult, aRv); 1.1188 +} 1.1189 + 1.1190 +already_AddRefed<DOMQuad> 1.1191 +nsINode::ConvertQuadFromNode(DOMQuad& aQuad, 1.1192 + const GeometryNode& aFrom, 1.1193 + const ConvertCoordinateOptions& aOptions, 1.1194 + ErrorResult& aRv) 1.1195 +{ 1.1196 + return mozilla::ConvertQuadFromNode(this, aQuad, aFrom, aOptions, aRv); 1.1197 +} 1.1198 + 1.1199 +already_AddRefed<DOMQuad> 1.1200 +nsINode::ConvertRectFromNode(DOMRectReadOnly& aRect, 1.1201 + const GeometryNode& aFrom, 1.1202 + const ConvertCoordinateOptions& aOptions, 1.1203 + ErrorResult& aRv) 1.1204 +{ 1.1205 + return mozilla::ConvertRectFromNode(this, aRect, aFrom, aOptions, aRv); 1.1206 +} 1.1207 + 1.1208 +already_AddRefed<DOMPoint> 1.1209 +nsINode::ConvertPointFromNode(const DOMPointInit& aPoint, 1.1210 + const GeometryNode& aFrom, 1.1211 + const ConvertCoordinateOptions& aOptions, 1.1212 + ErrorResult& aRv) 1.1213 +{ 1.1214 + return mozilla::ConvertPointFromNode(this, aPoint, aFrom, aOptions, aRv); 1.1215 +} 1.1216 + 1.1217 +nsresult 1.1218 +nsINode::DispatchEvent(nsIDOMEvent *aEvent, bool* aRetVal) 1.1219 +{ 1.1220 + // XXX sXBL/XBL2 issue -- do we really want the owner here? What 1.1221 + // if that's the XBL document? Would we want its presshell? Or what? 1.1222 + nsCOMPtr<nsIDocument> document = OwnerDoc(); 1.1223 + 1.1224 + // Do nothing if the element does not belong to a document 1.1225 + if (!document) { 1.1226 + *aRetVal = true; 1.1227 + return NS_OK; 1.1228 + } 1.1229 + 1.1230 + // Obtain a presentation shell 1.1231 + nsIPresShell *shell = document->GetShell(); 1.1232 + nsRefPtr<nsPresContext> context; 1.1233 + if (shell) { 1.1234 + context = shell->GetPresContext(); 1.1235 + } 1.1236 + 1.1237 + nsEventStatus status = nsEventStatus_eIgnore; 1.1238 + nsresult rv = 1.1239 + EventDispatcher::DispatchDOMEvent(this, nullptr, aEvent, context, &status); 1.1240 + *aRetVal = (status != nsEventStatus_eConsumeNoDefault); 1.1241 + return rv; 1.1242 +} 1.1243 + 1.1244 +nsresult 1.1245 +nsINode::PostHandleEvent(EventChainPostVisitor& /*aVisitor*/) 1.1246 +{ 1.1247 + return NS_OK; 1.1248 +} 1.1249 + 1.1250 +nsresult 1.1251 +nsINode::DispatchDOMEvent(WidgetEvent* aEvent, 1.1252 + nsIDOMEvent* aDOMEvent, 1.1253 + nsPresContext* aPresContext, 1.1254 + nsEventStatus* aEventStatus) 1.1255 +{ 1.1256 + return EventDispatcher::DispatchDOMEvent(this, aEvent, aDOMEvent, 1.1257 + aPresContext, aEventStatus); 1.1258 +} 1.1259 + 1.1260 +EventListenerManager* 1.1261 +nsINode::GetOrCreateListenerManager() 1.1262 +{ 1.1263 + return nsContentUtils::GetListenerManagerForNode(this); 1.1264 +} 1.1265 + 1.1266 +EventListenerManager* 1.1267 +nsINode::GetExistingListenerManager() const 1.1268 +{ 1.1269 + return nsContentUtils::GetExistingListenerManagerForNode(this); 1.1270 +} 1.1271 + 1.1272 +nsIScriptContext* 1.1273 +nsINode::GetContextForEventHandlers(nsresult* aRv) 1.1274 +{ 1.1275 + return nsContentUtils::GetContextForEventHandlers(this, aRv); 1.1276 +} 1.1277 + 1.1278 +nsIDOMWindow* 1.1279 +nsINode::GetOwnerGlobal() 1.1280 +{ 1.1281 + bool dummy; 1.1282 + return nsPIDOMWindow::GetOuterFromCurrentInner( 1.1283 + static_cast<nsGlobalWindow*>(OwnerDoc()->GetScriptHandlingObject(dummy))); 1.1284 +} 1.1285 + 1.1286 +bool 1.1287 +nsINode::UnoptimizableCCNode() const 1.1288 +{ 1.1289 + const uintptr_t problematicFlags = (NODE_IS_ANONYMOUS_ROOT | 1.1290 + NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE | 1.1291 + NODE_IS_NATIVE_ANONYMOUS_ROOT | 1.1292 + NODE_MAY_BE_IN_BINDING_MNGR | 1.1293 + NODE_IS_IN_SHADOW_TREE); 1.1294 + return HasFlag(problematicFlags) || 1.1295 + NodeType() == nsIDOMNode::ATTRIBUTE_NODE || 1.1296 + // For strange cases like xbl:content/xbl:children 1.1297 + (IsElement() && 1.1298 + AsElement()->IsInNamespace(kNameSpaceID_XBL)); 1.1299 +} 1.1300 + 1.1301 +/* static */ 1.1302 +bool 1.1303 +nsINode::Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb) 1.1304 +{ 1.1305 + if (MOZ_LIKELY(!cb.WantAllTraces())) { 1.1306 + nsIDocument *currentDoc = tmp->GetCurrentDoc(); 1.1307 + if (currentDoc && 1.1308 + nsCCUncollectableMarker::InGeneration(currentDoc->GetMarkedCCGeneration())) { 1.1309 + return false; 1.1310 + } 1.1311 + 1.1312 + if (nsCCUncollectableMarker::sGeneration) { 1.1313 + // If we're black no need to traverse. 1.1314 + if (tmp->IsBlack() || tmp->InCCBlackTree()) { 1.1315 + return false; 1.1316 + } 1.1317 + 1.1318 + if (!tmp->UnoptimizableCCNode()) { 1.1319 + // If we're in a black document, return early. 1.1320 + if ((currentDoc && currentDoc->IsBlack())) { 1.1321 + return false; 1.1322 + } 1.1323 + // If we're not in anonymous content and we have a black parent, 1.1324 + // return early. 1.1325 + nsIContent* parent = tmp->GetParent(); 1.1326 + if (parent && !parent->UnoptimizableCCNode() && parent->IsBlack()) { 1.1327 + NS_ABORT_IF_FALSE(parent->IndexOf(tmp) >= 0, "Parent doesn't own us?"); 1.1328 + return false; 1.1329 + } 1.1330 + } 1.1331 + } 1.1332 + } 1.1333 + 1.1334 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfo) 1.1335 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(GetParent()) 1.1336 + 1.1337 + nsSlots *slots = tmp->GetExistingSlots(); 1.1338 + if (slots) { 1.1339 + slots->Traverse(cb); 1.1340 + } 1.1341 + 1.1342 + if (tmp->HasProperties()) { 1.1343 + nsNodeUtils::TraverseUserData(tmp, cb); 1.1344 + nsCOMArray<nsISupports>* objects = 1.1345 + static_cast<nsCOMArray<nsISupports>*>(tmp->GetProperty(nsGkAtoms::keepobjectsalive)); 1.1346 + if (objects) { 1.1347 + for (int32_t i = 0; i < objects->Count(); ++i) { 1.1348 + cb.NoteXPCOMChild(objects->ObjectAt(i)); 1.1349 + } 1.1350 + } 1.1351 + } 1.1352 + 1.1353 + if (tmp->NodeType() != nsIDOMNode::DOCUMENT_NODE && 1.1354 + tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) { 1.1355 + nsContentUtils::TraverseListenerManager(tmp, cb); 1.1356 + } 1.1357 + 1.1358 + return true; 1.1359 +} 1.1360 + 1.1361 +/* static */ 1.1362 +void 1.1363 +nsINode::Unlink(nsINode* tmp) 1.1364 +{ 1.1365 + tmp->ReleaseWrapper(tmp); 1.1366 + 1.1367 + nsSlots *slots = tmp->GetExistingSlots(); 1.1368 + if (slots) { 1.1369 + slots->Unlink(); 1.1370 + } 1.1371 + 1.1372 + if (tmp->NodeType() != nsIDOMNode::DOCUMENT_NODE && 1.1373 + tmp->HasFlag(NODE_HAS_LISTENERMANAGER)) { 1.1374 + nsContentUtils::RemoveListenerManager(tmp); 1.1375 + tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER); 1.1376 + } 1.1377 + 1.1378 + if (tmp->HasProperties()) { 1.1379 + nsNodeUtils::UnlinkUserData(tmp); 1.1380 + tmp->DeleteProperty(nsGkAtoms::keepobjectsalive); 1.1381 + } 1.1382 +} 1.1383 + 1.1384 +static void 1.1385 +ReleaseURI(void*, /* aObject*/ 1.1386 + nsIAtom*, /* aPropertyName */ 1.1387 + void* aPropertyValue, 1.1388 + void* /* aData */) 1.1389 +{ 1.1390 + nsIURI* uri = static_cast<nsIURI*>(aPropertyValue); 1.1391 + NS_RELEASE(uri); 1.1392 +} 1.1393 + 1.1394 +nsresult 1.1395 +nsINode::SetExplicitBaseURI(nsIURI* aURI) 1.1396 +{ 1.1397 + nsresult rv = SetProperty(nsGkAtoms::baseURIProperty, aURI, ReleaseURI); 1.1398 + if (NS_SUCCEEDED(rv)) { 1.1399 + SetHasExplicitBaseURI(); 1.1400 + NS_ADDREF(aURI); 1.1401 + } 1.1402 + return rv; 1.1403 +} 1.1404 + 1.1405 +static nsresult 1.1406 +AdoptNodeIntoOwnerDoc(nsINode *aParent, nsINode *aNode) 1.1407 +{ 1.1408 + NS_ASSERTION(!aNode->GetParentNode(), 1.1409 + "Should have removed from parent already"); 1.1410 + 1.1411 + nsIDocument *doc = aParent->OwnerDoc(); 1.1412 + 1.1413 + nsresult rv; 1.1414 + nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc, &rv); 1.1415 + NS_ENSURE_SUCCESS(rv, rv); 1.1416 + 1.1417 + nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aNode, &rv); 1.1418 + NS_ENSURE_SUCCESS(rv, rv); 1.1419 + 1.1420 + nsCOMPtr<nsIDOMNode> adoptedNode; 1.1421 + rv = domDoc->AdoptNode(node, getter_AddRefs(adoptedNode)); 1.1422 + NS_ENSURE_SUCCESS(rv, rv); 1.1423 + 1.1424 + NS_ASSERTION(aParent->OwnerDoc() == doc, 1.1425 + "ownerDoc chainged while adopting"); 1.1426 + NS_ASSERTION(adoptedNode == node, "Uh, adopt node changed nodes?"); 1.1427 + NS_ASSERTION(aParent->OwnerDoc() == aNode->OwnerDoc(), 1.1428 + "ownerDocument changed again after adopting!"); 1.1429 + 1.1430 + return NS_OK; 1.1431 +} 1.1432 + 1.1433 +static nsresult 1.1434 +CheckForOutdatedParent(nsINode* aParent, nsINode* aNode) 1.1435 +{ 1.1436 + if (JSObject* existingObjUnrooted = aNode->GetWrapper()) { 1.1437 + AutoJSContext cx; 1.1438 + JS::Rooted<JSObject*> existingObj(cx, existingObjUnrooted); 1.1439 + nsIGlobalObject* global = aParent->OwnerDoc()->GetScopeObject(); 1.1440 + MOZ_ASSERT(global); 1.1441 + 1.1442 + if (js::GetGlobalForObjectCrossCompartment(existingObj) != 1.1443 + global->GetGlobalJSObject()) { 1.1444 + JSAutoCompartment ac(cx, existingObj); 1.1445 + nsresult rv = ReparentWrapper(cx, existingObj); 1.1446 + NS_ENSURE_SUCCESS(rv, rv); 1.1447 + } 1.1448 + } 1.1449 + 1.1450 + return NS_OK; 1.1451 +} 1.1452 + 1.1453 +nsresult 1.1454 +nsINode::doInsertChildAt(nsIContent* aKid, uint32_t aIndex, 1.1455 + bool aNotify, nsAttrAndChildArray& aChildArray) 1.1456 +{ 1.1457 + NS_PRECONDITION(!aKid->GetParentNode(), 1.1458 + "Inserting node that already has parent"); 1.1459 + nsresult rv; 1.1460 + 1.1461 + // The id-handling code, and in the future possibly other code, need to 1.1462 + // react to unexpected attribute changes. 1.1463 + nsMutationGuard::DidMutate(); 1.1464 + 1.1465 + // Do this before checking the child-count since this could cause mutations 1.1466 + nsIDocument* doc = GetCurrentDoc(); 1.1467 + mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, aNotify); 1.1468 + 1.1469 + if (OwnerDoc() != aKid->OwnerDoc()) { 1.1470 + rv = AdoptNodeIntoOwnerDoc(this, aKid); 1.1471 + NS_ENSURE_SUCCESS(rv, rv); 1.1472 + } else if (OwnerDoc()->DidDocumentOpen()) { 1.1473 + rv = CheckForOutdatedParent(this, aKid); 1.1474 + NS_ENSURE_SUCCESS(rv, rv); 1.1475 + } 1.1476 + 1.1477 + uint32_t childCount = aChildArray.ChildCount(); 1.1478 + NS_ENSURE_TRUE(aIndex <= childCount, NS_ERROR_ILLEGAL_VALUE); 1.1479 + bool isAppend = (aIndex == childCount); 1.1480 + 1.1481 + rv = aChildArray.InsertChildAt(aKid, aIndex); 1.1482 + NS_ENSURE_SUCCESS(rv, rv); 1.1483 + if (aIndex == 0) { 1.1484 + mFirstChild = aKid; 1.1485 + } 1.1486 + 1.1487 + nsIContent* parent = 1.1488 + IsNodeOfType(eDOCUMENT) ? nullptr : static_cast<nsIContent*>(this); 1.1489 + 1.1490 + rv = aKid->BindToTree(doc, parent, 1.1491 + parent ? parent->GetBindingParent() : nullptr, 1.1492 + true); 1.1493 + if (NS_FAILED(rv)) { 1.1494 + if (GetFirstChild() == aKid) { 1.1495 + mFirstChild = aKid->GetNextSibling(); 1.1496 + } 1.1497 + aChildArray.RemoveChildAt(aIndex); 1.1498 + aKid->UnbindFromTree(); 1.1499 + return rv; 1.1500 + } 1.1501 + 1.1502 + NS_ASSERTION(aKid->GetParentNode() == this, 1.1503 + "Did we run script inappropriately?"); 1.1504 + 1.1505 + if (aNotify) { 1.1506 + // Note that we always want to call ContentInserted when things are added 1.1507 + // as kids to documents 1.1508 + if (parent && isAppend) { 1.1509 + nsNodeUtils::ContentAppended(parent, aKid, aIndex); 1.1510 + } else { 1.1511 + nsNodeUtils::ContentInserted(this, aKid, aIndex); 1.1512 + } 1.1513 + 1.1514 + if (nsContentUtils::HasMutationListeners(aKid, 1.1515 + NS_EVENT_BITS_MUTATION_NODEINSERTED, this)) { 1.1516 + InternalMutationEvent mutation(true, NS_MUTATION_NODEINSERTED); 1.1517 + mutation.mRelatedNode = do_QueryInterface(this); 1.1518 + 1.1519 + mozAutoSubtreeModified subtree(OwnerDoc(), this); 1.1520 + (new AsyncEventDispatcher(aKid, mutation))->RunDOMEventWhenSafe(); 1.1521 + } 1.1522 + } 1.1523 + 1.1524 + return NS_OK; 1.1525 +} 1.1526 + 1.1527 +Element* 1.1528 +nsINode::GetPreviousElementSibling() const 1.1529 +{ 1.1530 + nsIContent* previousSibling = GetPreviousSibling(); 1.1531 + while (previousSibling) { 1.1532 + if (previousSibling->IsElement()) { 1.1533 + return previousSibling->AsElement(); 1.1534 + } 1.1535 + previousSibling = previousSibling->GetPreviousSibling(); 1.1536 + } 1.1537 + 1.1538 + return nullptr; 1.1539 +} 1.1540 + 1.1541 +Element* 1.1542 +nsINode::GetNextElementSibling() const 1.1543 +{ 1.1544 + nsIContent* nextSibling = GetNextSibling(); 1.1545 + while (nextSibling) { 1.1546 + if (nextSibling->IsElement()) { 1.1547 + return nextSibling->AsElement(); 1.1548 + } 1.1549 + nextSibling = nextSibling->GetNextSibling(); 1.1550 + } 1.1551 + 1.1552 + return nullptr; 1.1553 +} 1.1554 + 1.1555 +void 1.1556 +nsINode::Remove() 1.1557 +{ 1.1558 + nsCOMPtr<nsINode> parent = GetParentNode(); 1.1559 + if (!parent) { 1.1560 + return; 1.1561 + } 1.1562 + int32_t index = parent->IndexOf(this); 1.1563 + if (index < 0) { 1.1564 + NS_WARNING("Ignoring call to nsINode::Remove on anonymous child."); 1.1565 + return; 1.1566 + } 1.1567 + parent->RemoveChildAt(uint32_t(index), true); 1.1568 +} 1.1569 + 1.1570 +Element* 1.1571 +nsINode::GetFirstElementChild() const 1.1572 +{ 1.1573 + for (nsIContent* child = GetFirstChild(); 1.1574 + child; 1.1575 + child = child->GetNextSibling()) { 1.1576 + if (child->IsElement()) { 1.1577 + return child->AsElement(); 1.1578 + } 1.1579 + } 1.1580 + 1.1581 + return nullptr; 1.1582 +} 1.1583 + 1.1584 +Element* 1.1585 +nsINode::GetLastElementChild() const 1.1586 +{ 1.1587 + for (nsIContent* child = GetLastChild(); 1.1588 + child; 1.1589 + child = child->GetPreviousSibling()) { 1.1590 + if (child->IsElement()) { 1.1591 + return child->AsElement(); 1.1592 + } 1.1593 + } 1.1594 + 1.1595 + return nullptr; 1.1596 +} 1.1597 + 1.1598 +void 1.1599 +nsINode::doRemoveChildAt(uint32_t aIndex, bool aNotify, 1.1600 + nsIContent* aKid, nsAttrAndChildArray& aChildArray) 1.1601 +{ 1.1602 + NS_PRECONDITION(aKid && aKid->GetParentNode() == this && 1.1603 + aKid == GetChildAt(aIndex) && 1.1604 + IndexOf(aKid) == (int32_t)aIndex, "Bogus aKid"); 1.1605 + 1.1606 + nsMutationGuard::DidMutate(); 1.1607 + 1.1608 + nsIDocument* doc = GetCurrentDoc(); 1.1609 + 1.1610 + mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, aNotify); 1.1611 + 1.1612 + nsIContent* previousSibling = aKid->GetPreviousSibling(); 1.1613 + 1.1614 + if (GetFirstChild() == aKid) { 1.1615 + mFirstChild = aKid->GetNextSibling(); 1.1616 + } 1.1617 + 1.1618 + aChildArray.RemoveChildAt(aIndex); 1.1619 + 1.1620 + if (aNotify) { 1.1621 + nsNodeUtils::ContentRemoved(this, aKid, aIndex, previousSibling); 1.1622 + } 1.1623 + 1.1624 + aKid->UnbindFromTree(); 1.1625 +} 1.1626 + 1.1627 +// When replacing, aRefChild is the content being replaced; when 1.1628 +// inserting it's the content before which we're inserting. In the 1.1629 +// latter case it may be null. 1.1630 +static 1.1631 +bool IsAllowedAsChild(nsIContent* aNewChild, nsINode* aParent, 1.1632 + bool aIsReplace, nsINode* aRefChild) 1.1633 +{ 1.1634 + MOZ_ASSERT(aNewChild, "Must have new child"); 1.1635 + MOZ_ASSERT_IF(aIsReplace, aRefChild); 1.1636 + MOZ_ASSERT(aParent); 1.1637 + MOZ_ASSERT(aParent->IsNodeOfType(nsINode::eDOCUMENT) || 1.1638 + aParent->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT) || 1.1639 + aParent->IsElement(), 1.1640 + "Nodes that are not documents, document fragments or elements " 1.1641 + "can't be parents!"); 1.1642 + 1.1643 + // A common case is that aNewChild has no kids, in which case 1.1644 + // aParent can't be a descendant of aNewChild unless they're 1.1645 + // actually equal to each other. Fast-path that case, since aParent 1.1646 + // could be pretty deep in the DOM tree. 1.1647 + if (aNewChild == aParent || 1.1648 + ((aNewChild->GetFirstChild() || 1.1649 + // HTML template elements and ShadowRoot hosts need 1.1650 + // to be checked to ensure that they are not inserted into 1.1651 + // the hosted content. 1.1652 + aNewChild->Tag() == nsGkAtoms::_template || 1.1653 + aNewChild->GetShadowRoot()) && 1.1654 + nsContentUtils::ContentIsHostIncludingDescendantOf(aParent, 1.1655 + aNewChild))) { 1.1656 + return false; 1.1657 + } 1.1658 + 1.1659 + // The allowed child nodes differ for documents and elements 1.1660 + switch (aNewChild->NodeType()) { 1.1661 + case nsIDOMNode::COMMENT_NODE : 1.1662 + case nsIDOMNode::PROCESSING_INSTRUCTION_NODE : 1.1663 + // OK in both cases 1.1664 + return true; 1.1665 + case nsIDOMNode::TEXT_NODE : 1.1666 + case nsIDOMNode::CDATA_SECTION_NODE : 1.1667 + case nsIDOMNode::ENTITY_REFERENCE_NODE : 1.1668 + // Allowed under Elements and DocumentFragments 1.1669 + return aParent->NodeType() != nsIDOMNode::DOCUMENT_NODE; 1.1670 + case nsIDOMNode::ELEMENT_NODE : 1.1671 + { 1.1672 + if (!aParent->IsNodeOfType(nsINode::eDOCUMENT)) { 1.1673 + // Always ok to have elements under other elements or document fragments 1.1674 + return true; 1.1675 + } 1.1676 + 1.1677 + nsIDocument* parentDocument = static_cast<nsIDocument*>(aParent); 1.1678 + Element* rootElement = parentDocument->GetRootElement(); 1.1679 + if (rootElement) { 1.1680 + // Already have a documentElement, so this is only OK if we're 1.1681 + // replacing it. 1.1682 + return aIsReplace && rootElement == aRefChild; 1.1683 + } 1.1684 + 1.1685 + // We don't have a documentElement yet. Our one remaining constraint is 1.1686 + // that the documentElement must come after the doctype. 1.1687 + if (!aRefChild) { 1.1688 + // Appending is just fine. 1.1689 + return true; 1.1690 + } 1.1691 + 1.1692 + nsIContent* docTypeContent = parentDocument->GetDoctype(); 1.1693 + if (!docTypeContent) { 1.1694 + // It's all good. 1.1695 + return true; 1.1696 + } 1.1697 + 1.1698 + int32_t doctypeIndex = aParent->IndexOf(docTypeContent); 1.1699 + int32_t insertIndex = aParent->IndexOf(aRefChild); 1.1700 + 1.1701 + // Now we're OK in the following two cases only: 1.1702 + // 1) We're replacing something that's not before the doctype 1.1703 + // 2) We're inserting before something that comes after the doctype 1.1704 + return aIsReplace ? (insertIndex >= doctypeIndex) : 1.1705 + insertIndex > doctypeIndex; 1.1706 + } 1.1707 + case nsIDOMNode::DOCUMENT_TYPE_NODE : 1.1708 + { 1.1709 + if (!aParent->IsNodeOfType(nsINode::eDOCUMENT)) { 1.1710 + // doctypes only allowed under documents 1.1711 + return false; 1.1712 + } 1.1713 + 1.1714 + nsIDocument* parentDocument = static_cast<nsIDocument*>(aParent); 1.1715 + nsIContent* docTypeContent = parentDocument->GetDoctype(); 1.1716 + if (docTypeContent) { 1.1717 + // Already have a doctype, so this is only OK if we're replacing it 1.1718 + return aIsReplace && docTypeContent == aRefChild; 1.1719 + } 1.1720 + 1.1721 + // We don't have a doctype yet. Our one remaining constraint is 1.1722 + // that the doctype must come before the documentElement. 1.1723 + Element* rootElement = parentDocument->GetRootElement(); 1.1724 + if (!rootElement) { 1.1725 + // It's all good 1.1726 + return true; 1.1727 + } 1.1728 + 1.1729 + if (!aRefChild) { 1.1730 + // Trying to append a doctype, but have a documentElement 1.1731 + return false; 1.1732 + } 1.1733 + 1.1734 + int32_t rootIndex = aParent->IndexOf(rootElement); 1.1735 + int32_t insertIndex = aParent->IndexOf(aRefChild); 1.1736 + 1.1737 + // Now we're OK if and only if insertIndex <= rootIndex. Indeed, either 1.1738 + // we end up replacing aRefChild or we end up before it. Either one is 1.1739 + // ok as long as aRefChild is not after rootElement. 1.1740 + return insertIndex <= rootIndex; 1.1741 + } 1.1742 + case nsIDOMNode::DOCUMENT_FRAGMENT_NODE : 1.1743 + { 1.1744 + // Note that for now we only allow nodes inside document fragments if 1.1745 + // they're allowed inside elements. If we ever change this to allow 1.1746 + // doctype nodes in document fragments, we'll need to update this code. 1.1747 + // Also, there's a version of this code in ReplaceOrInsertBefore. If you 1.1748 + // change this code, change that too. 1.1749 + if (!aParent->IsNodeOfType(nsINode::eDOCUMENT)) { 1.1750 + // All good here 1.1751 + return true; 1.1752 + } 1.1753 + 1.1754 + bool sawElement = false; 1.1755 + for (nsIContent* child = aNewChild->GetFirstChild(); 1.1756 + child; 1.1757 + child = child->GetNextSibling()) { 1.1758 + if (child->IsElement()) { 1.1759 + if (sawElement) { 1.1760 + // Can't put two elements into a document 1.1761 + return false; 1.1762 + } 1.1763 + sawElement = true; 1.1764 + } 1.1765 + // If we can put this content at the the right place, we might be ok; 1.1766 + // if not, we bail out. 1.1767 + if (!IsAllowedAsChild(child, aParent, aIsReplace, aRefChild)) { 1.1768 + return false; 1.1769 + } 1.1770 + } 1.1771 + 1.1772 + // Everything in the fragment checked out ok, so we can stick it in here 1.1773 + return true; 1.1774 + } 1.1775 + default: 1.1776 + /* 1.1777 + * aNewChild is of invalid type. 1.1778 + */ 1.1779 + break; 1.1780 + } 1.1781 + 1.1782 + return false; 1.1783 +} 1.1784 + 1.1785 +nsINode* 1.1786 +nsINode::ReplaceOrInsertBefore(bool aReplace, nsINode* aNewChild, 1.1787 + nsINode* aRefChild, ErrorResult& aError) 1.1788 +{ 1.1789 + // XXXbz I wish I could assert that nsContentUtils::IsSafeToRunScript() so we 1.1790 + // could rely on scriptblockers going out of scope to actually run XBL 1.1791 + // teardown, but various crud adds nodes under scriptblockers (e.g. native 1.1792 + // anonymous content). The only good news is those insertions can't trigger 1.1793 + // the bad XBL cases. 1.1794 + MOZ_ASSERT_IF(aReplace, aRefChild); 1.1795 + 1.1796 + if ((!IsNodeOfType(eDOCUMENT) && 1.1797 + !IsNodeOfType(eDOCUMENT_FRAGMENT) && 1.1798 + !IsElement()) || 1.1799 + !aNewChild->IsNodeOfType(eCONTENT)) { 1.1800 + aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); 1.1801 + return nullptr; 1.1802 + } 1.1803 + 1.1804 + uint16_t nodeType = aNewChild->NodeType(); 1.1805 + 1.1806 + // Before we do anything else, fire all DOMNodeRemoved mutation events 1.1807 + // We do this up front as to avoid having to deal with script running 1.1808 + // at random places further down. 1.1809 + // Scope firing mutation events so that we don't carry any state that 1.1810 + // might be stale 1.1811 + { 1.1812 + // This check happens again further down (though then using IndexOf). 1.1813 + // We're only checking this here to avoid firing mutation events when 1.1814 + // none should be fired. 1.1815 + // It's ok that we do the check twice in the case when firing mutation 1.1816 + // events as we need to recheck after running script anyway. 1.1817 + if (aRefChild && aRefChild->GetParentNode() != this) { 1.1818 + aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR); 1.1819 + return nullptr; 1.1820 + } 1.1821 + 1.1822 + // If we're replacing, fire for node-to-be-replaced. 1.1823 + // If aRefChild == aNewChild then we'll fire for it in check below 1.1824 + if (aReplace && aRefChild != aNewChild) { 1.1825 + nsContentUtils::MaybeFireNodeRemoved(aRefChild, this, OwnerDoc()); 1.1826 + } 1.1827 + 1.1828 + // If the new node already has a parent, fire for removing from old 1.1829 + // parent 1.1830 + nsINode* oldParent = aNewChild->GetParentNode(); 1.1831 + if (oldParent) { 1.1832 + nsContentUtils::MaybeFireNodeRemoved(aNewChild, oldParent, 1.1833 + aNewChild->OwnerDoc()); 1.1834 + } 1.1835 + 1.1836 + // If we're inserting a fragment, fire for all the children of the 1.1837 + // fragment 1.1838 + if (nodeType == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) { 1.1839 + static_cast<FragmentOrElement*>(aNewChild)->FireNodeRemovedForChildren(); 1.1840 + } 1.1841 + // Verify that our aRefChild is still sensible 1.1842 + if (aRefChild && aRefChild->GetParentNode() != this) { 1.1843 + aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR); 1.1844 + return nullptr; 1.1845 + } 1.1846 + } 1.1847 + 1.1848 + nsIDocument* doc = OwnerDoc(); 1.1849 + nsIContent* newContent = static_cast<nsIContent*>(aNewChild); 1.1850 + if (newContent->IsRootOfAnonymousSubtree()) { 1.1851 + // This is anonymous content. Don't allow its insertion 1.1852 + // anywhere, since it might have UnbindFromTree calls coming 1.1853 + // its way. 1.1854 + aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); 1.1855 + return nullptr; 1.1856 + } 1.1857 + 1.1858 + // Make sure that the inserted node is allowed as a child of its new parent. 1.1859 + if (!IsAllowedAsChild(newContent, this, aReplace, aRefChild)) { 1.1860 + aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); 1.1861 + return nullptr; 1.1862 + } 1.1863 + 1.1864 + // Record the node to insert before, if any 1.1865 + nsINode* nodeToInsertBefore; 1.1866 + if (aReplace) { 1.1867 + nodeToInsertBefore = aRefChild->GetNextSibling(); 1.1868 + } else { 1.1869 + nodeToInsertBefore = aRefChild; 1.1870 + } 1.1871 + if (nodeToInsertBefore == aNewChild) { 1.1872 + // We're going to remove aNewChild from its parent, so use its next sibling 1.1873 + // as the node to insert before. 1.1874 + nodeToInsertBefore = nodeToInsertBefore->GetNextSibling(); 1.1875 + } 1.1876 + 1.1877 + Maybe<nsAutoTArray<nsCOMPtr<nsIContent>, 50> > fragChildren; 1.1878 + 1.1879 + // Remove the new child from the old parent if one exists 1.1880 + nsCOMPtr<nsINode> oldParent = newContent->GetParentNode(); 1.1881 + if (oldParent) { 1.1882 + int32_t removeIndex = oldParent->IndexOf(newContent); 1.1883 + if (removeIndex < 0) { 1.1884 + // newContent is anonymous. We can't deal with this, so just bail 1.1885 + NS_ERROR("How come our flags didn't catch this?"); 1.1886 + aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); 1.1887 + return nullptr; 1.1888 + } 1.1889 + 1.1890 + // Hold a strong ref to nodeToInsertBefore across the removal of newContent 1.1891 + nsCOMPtr<nsINode> kungFuDeathGrip = nodeToInsertBefore; 1.1892 + 1.1893 + // Removing a child can run script, via XBL destructors. 1.1894 + nsMutationGuard guard; 1.1895 + 1.1896 + // Scope for the mutation batch and scriptblocker, so they go away 1.1897 + // while kungFuDeathGrip is still alive. 1.1898 + { 1.1899 + mozAutoDocUpdate batch(newContent->GetCurrentDoc(), 1.1900 + UPDATE_CONTENT_MODEL, true); 1.1901 + nsAutoMutationBatch mb(oldParent, true, true); 1.1902 + oldParent->RemoveChildAt(removeIndex, true); 1.1903 + if (nsAutoMutationBatch::GetCurrentBatch() == &mb) { 1.1904 + mb.RemovalDone(); 1.1905 + mb.SetPrevSibling(oldParent->GetChildAt(removeIndex - 1)); 1.1906 + mb.SetNextSibling(oldParent->GetChildAt(removeIndex)); 1.1907 + } 1.1908 + } 1.1909 + 1.1910 + // We expect one mutation (the removal) to have happened. 1.1911 + if (guard.Mutated(1)) { 1.1912 + // XBL destructors, yuck. 1.1913 + 1.1914 + // Verify that nodeToInsertBefore, if non-null, is still our child. If 1.1915 + // it's not, there's no way we can do this insert sanely; just bail out. 1.1916 + if (nodeToInsertBefore && nodeToInsertBefore->GetParent() != this) { 1.1917 + aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); 1.1918 + return nullptr; 1.1919 + } 1.1920 + 1.1921 + // Verify that newContent has no parent. 1.1922 + if (newContent->GetParentNode()) { 1.1923 + aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); 1.1924 + return nullptr; 1.1925 + } 1.1926 + 1.1927 + // And verify that newContent is still allowed as our child. 1.1928 + if (aNewChild == aRefChild) { 1.1929 + // We've already removed aRefChild. So even if we were doing a replace, 1.1930 + // now we're doing a simple insert before nodeToInsertBefore. 1.1931 + if (!IsAllowedAsChild(newContent, this, false, nodeToInsertBefore)) { 1.1932 + aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); 1.1933 + return nullptr; 1.1934 + } 1.1935 + } else { 1.1936 + if ((aRefChild && aRefChild->GetParent() != this) || 1.1937 + !IsAllowedAsChild(newContent, this, aReplace, aRefChild)) { 1.1938 + aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); 1.1939 + return nullptr; 1.1940 + } 1.1941 + // And recompute nodeToInsertBefore, just in case. 1.1942 + if (aReplace) { 1.1943 + nodeToInsertBefore = aRefChild->GetNextSibling(); 1.1944 + } else { 1.1945 + nodeToInsertBefore = aRefChild; 1.1946 + } 1.1947 + } 1.1948 + } 1.1949 + } else if (nodeType == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) { 1.1950 + // Make sure to remove all the fragment's kids. We need to do this before 1.1951 + // we start inserting anything, so we will run out XBL destructors and 1.1952 + // binding teardown (GOD, I HATE THESE THINGS) before we insert anything 1.1953 + // into the DOM. 1.1954 + uint32_t count = newContent->GetChildCount(); 1.1955 + 1.1956 + fragChildren.construct(); 1.1957 + 1.1958 + // Copy the children into a separate array to avoid having to deal with 1.1959 + // mutations to the fragment later on here. 1.1960 + fragChildren.ref().SetCapacity(count); 1.1961 + for (nsIContent* child = newContent->GetFirstChild(); 1.1962 + child; 1.1963 + child = child->GetNextSibling()) { 1.1964 + NS_ASSERTION(child->GetCurrentDoc() == nullptr, 1.1965 + "How did we get a child with a current doc?"); 1.1966 + fragChildren.ref().AppendElement(child); 1.1967 + } 1.1968 + 1.1969 + // Hold a strong ref to nodeToInsertBefore across the removals 1.1970 + nsCOMPtr<nsINode> kungFuDeathGrip = nodeToInsertBefore; 1.1971 + 1.1972 + nsMutationGuard guard; 1.1973 + 1.1974 + // Scope for the mutation batch and scriptblocker, so they go away 1.1975 + // while kungFuDeathGrip is still alive. 1.1976 + { 1.1977 + mozAutoDocUpdate batch(newContent->GetCurrentDoc(), 1.1978 + UPDATE_CONTENT_MODEL, true); 1.1979 + nsAutoMutationBatch mb(newContent, false, true); 1.1980 + 1.1981 + for (uint32_t i = count; i > 0;) { 1.1982 + newContent->RemoveChildAt(--i, true); 1.1983 + } 1.1984 + } 1.1985 + 1.1986 + // We expect |count| removals 1.1987 + if (guard.Mutated(count)) { 1.1988 + // XBL destructors, yuck. 1.1989 + 1.1990 + // Verify that nodeToInsertBefore, if non-null, is still our child. If 1.1991 + // it's not, there's no way we can do this insert sanely; just bail out. 1.1992 + if (nodeToInsertBefore && nodeToInsertBefore->GetParent() != this) { 1.1993 + aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); 1.1994 + return nullptr; 1.1995 + } 1.1996 + 1.1997 + // Verify that all the things in fragChildren have no parent. 1.1998 + for (uint32_t i = 0; i < count; ++i) { 1.1999 + if (fragChildren.ref().ElementAt(i)->GetParentNode()) { 1.2000 + aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); 1.2001 + return nullptr; 1.2002 + } 1.2003 + } 1.2004 + 1.2005 + // Note that unlike the single-element case above, none of our kids can 1.2006 + // be aRefChild, so we can always pass through aReplace in the 1.2007 + // IsAllowedAsChild checks below and don't have to worry about whether 1.2008 + // recomputing nodeToInsertBefore is OK. 1.2009 + 1.2010 + // Verify that our aRefChild is still sensible 1.2011 + if (aRefChild && aRefChild->GetParent() != this) { 1.2012 + aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); 1.2013 + return nullptr; 1.2014 + } 1.2015 + 1.2016 + // Recompute nodeToInsertBefore, just in case. 1.2017 + if (aReplace) { 1.2018 + nodeToInsertBefore = aRefChild->GetNextSibling(); 1.2019 + } else { 1.2020 + nodeToInsertBefore = aRefChild; 1.2021 + } 1.2022 + 1.2023 + // And verify that newContent is still allowed as our child. Sadly, we 1.2024 + // need to reimplement the relevant part of IsAllowedAsChild() because 1.2025 + // now our nodes are in an array and all. If you change this code, 1.2026 + // change the code there. 1.2027 + if (IsNodeOfType(nsINode::eDOCUMENT)) { 1.2028 + bool sawElement = false; 1.2029 + for (uint32_t i = 0; i < count; ++i) { 1.2030 + nsIContent* child = fragChildren.ref().ElementAt(i); 1.2031 + if (child->IsElement()) { 1.2032 + if (sawElement) { 1.2033 + // No good 1.2034 + aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); 1.2035 + return nullptr; 1.2036 + } 1.2037 + sawElement = true; 1.2038 + } 1.2039 + if (!IsAllowedAsChild(child, this, aReplace, aRefChild)) { 1.2040 + aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); 1.2041 + return nullptr; 1.2042 + } 1.2043 + } 1.2044 + } 1.2045 + } 1.2046 + } 1.2047 + 1.2048 + mozAutoDocUpdate batch(GetCurrentDoc(), UPDATE_CONTENT_MODEL, true); 1.2049 + nsAutoMutationBatch mb; 1.2050 + 1.2051 + // Figure out which index we want to insert at. Note that we use 1.2052 + // nodeToInsertBefore to determine this, because it's possible that 1.2053 + // aRefChild == aNewChild, in which case we just removed it from the 1.2054 + // parent list. 1.2055 + int32_t insPos; 1.2056 + if (nodeToInsertBefore) { 1.2057 + insPos = IndexOf(nodeToInsertBefore); 1.2058 + if (insPos < 0) { 1.2059 + // XXXbz How the heck would _that_ happen, exactly? 1.2060 + aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR); 1.2061 + return nullptr; 1.2062 + } 1.2063 + } 1.2064 + else { 1.2065 + insPos = GetChildCount(); 1.2066 + } 1.2067 + 1.2068 + // If we're replacing and we haven't removed aRefChild yet, do so now 1.2069 + if (aReplace && aRefChild != aNewChild) { 1.2070 + mb.Init(this, true, true); 1.2071 + 1.2072 + // Since aRefChild is never null in the aReplace case, we know that at 1.2073 + // this point nodeToInsertBefore is the next sibling of aRefChild. 1.2074 + NS_ASSERTION(aRefChild->GetNextSibling() == nodeToInsertBefore, 1.2075 + "Unexpected nodeToInsertBefore"); 1.2076 + 1.2077 + // An since nodeToInsertBefore is at index insPos, we want to remove 1.2078 + // at the previous index. 1.2079 + NS_ASSERTION(insPos >= 1, "insPos too small"); 1.2080 + RemoveChildAt(insPos-1, true); 1.2081 + --insPos; 1.2082 + } 1.2083 + 1.2084 + // Move new child over to our document if needed. Do this after removing 1.2085 + // it from its parent so that AdoptNode doesn't fire DOMNodeRemoved 1.2086 + // DocumentType nodes are the only nodes that can have a null 1.2087 + // ownerDocument according to the DOM spec, and we need to allow 1.2088 + // inserting them w/o calling AdoptNode(). 1.2089 + if (doc != newContent->OwnerDoc()) { 1.2090 + aError = AdoptNodeIntoOwnerDoc(this, aNewChild); 1.2091 + if (aError.Failed()) { 1.2092 + return nullptr; 1.2093 + } 1.2094 + } else if (doc->DidDocumentOpen()) { 1.2095 + aError = CheckForOutdatedParent(this, aNewChild); 1.2096 + if (aError.Failed()) { 1.2097 + return nullptr; 1.2098 + } 1.2099 + } 1.2100 + 1.2101 + /* 1.2102 + * Check if we're inserting a document fragment. If we are, we need 1.2103 + * to actually add its children individually (i.e. we don't add the 1.2104 + * actual document fragment). 1.2105 + */ 1.2106 + nsINode* result = aReplace ? aRefChild : aNewChild; 1.2107 + if (nodeType == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) { 1.2108 + if (!aReplace) { 1.2109 + mb.Init(this, true, true); 1.2110 + } 1.2111 + nsAutoMutationBatch* mutationBatch = nsAutoMutationBatch::GetCurrentBatch(); 1.2112 + if (mutationBatch) { 1.2113 + mutationBatch->RemovalDone(); 1.2114 + mutationBatch->SetPrevSibling(GetChildAt(insPos - 1)); 1.2115 + mutationBatch->SetNextSibling(GetChildAt(insPos)); 1.2116 + } 1.2117 + 1.2118 + uint32_t count = fragChildren.ref().Length(); 1.2119 + if (!count) { 1.2120 + return result; 1.2121 + } 1.2122 + 1.2123 + bool appending = 1.2124 + !IsNodeOfType(eDOCUMENT) && uint32_t(insPos) == GetChildCount(); 1.2125 + int32_t firstInsPos = insPos; 1.2126 + nsIContent* firstInsertedContent = fragChildren.ref().ElementAt(0); 1.2127 + 1.2128 + // Iterate through the fragment's children, and insert them in the new 1.2129 + // parent 1.2130 + for (uint32_t i = 0; i < count; ++i, ++insPos) { 1.2131 + // XXXbz how come no reparenting here? That seems odd... 1.2132 + // Insert the child. 1.2133 + aError = InsertChildAt(fragChildren.ref().ElementAt(i), insPos, 1.2134 + !appending); 1.2135 + if (aError.Failed()) { 1.2136 + // Make sure to notify on any children that we did succeed to insert 1.2137 + if (appending && i != 0) { 1.2138 + nsNodeUtils::ContentAppended(static_cast<nsIContent*>(this), 1.2139 + firstInsertedContent, 1.2140 + firstInsPos); 1.2141 + } 1.2142 + return nullptr; 1.2143 + } 1.2144 + } 1.2145 + 1.2146 + if (mutationBatch && !appending) { 1.2147 + mutationBatch->NodesAdded(); 1.2148 + } 1.2149 + 1.2150 + // Notify and fire mutation events when appending 1.2151 + if (appending) { 1.2152 + nsNodeUtils::ContentAppended(static_cast<nsIContent*>(this), 1.2153 + firstInsertedContent, firstInsPos); 1.2154 + if (mutationBatch) { 1.2155 + mutationBatch->NodesAdded(); 1.2156 + } 1.2157 + // Optimize for the case when there are no listeners 1.2158 + if (nsContentUtils:: 1.2159 + HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEINSERTED)) { 1.2160 + Element::FireNodeInserted(doc, this, fragChildren.ref()); 1.2161 + } 1.2162 + } 1.2163 + } 1.2164 + else { 1.2165 + // Not inserting a fragment but rather a single node. 1.2166 + 1.2167 + // FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=544654 1.2168 + // We need to reparent here for nodes for which the parent of their 1.2169 + // wrapper is not the wrapper for their ownerDocument (XUL elements, 1.2170 + // form controls, ...). Also applies in the fragment code above. 1.2171 + 1.2172 + if (nsAutoMutationBatch::GetCurrentBatch() == &mb) { 1.2173 + mb.RemovalDone(); 1.2174 + mb.SetPrevSibling(GetChildAt(insPos - 1)); 1.2175 + mb.SetNextSibling(GetChildAt(insPos)); 1.2176 + } 1.2177 + aError = InsertChildAt(newContent, insPos, true); 1.2178 + if (aError.Failed()) { 1.2179 + return nullptr; 1.2180 + } 1.2181 + } 1.2182 + 1.2183 + return result; 1.2184 +} 1.2185 + 1.2186 +nsresult 1.2187 +nsINode::ReplaceOrInsertBefore(bool aReplace, nsIDOMNode *aNewChild, 1.2188 + nsIDOMNode *aRefChild, nsIDOMNode **aReturn) 1.2189 +{ 1.2190 + nsCOMPtr<nsINode> newChild = do_QueryInterface(aNewChild); 1.2191 + if (!newChild) { 1.2192 + return NS_ERROR_NULL_POINTER; 1.2193 + } 1.2194 + 1.2195 + if (aReplace && !aRefChild) { 1.2196 + return NS_ERROR_NULL_POINTER; 1.2197 + } 1.2198 + 1.2199 + nsCOMPtr<nsINode> refChild = do_QueryInterface(aRefChild); 1.2200 + if (aRefChild && !refChild) { 1.2201 + return NS_NOINTERFACE; 1.2202 + } 1.2203 + 1.2204 + ErrorResult rv; 1.2205 + nsINode* result = ReplaceOrInsertBefore(aReplace, newChild, refChild, rv); 1.2206 + if (result) { 1.2207 + NS_ADDREF(*aReturn = result->AsDOMNode()); 1.2208 + } 1.2209 + return rv.ErrorCode(); 1.2210 +} 1.2211 + 1.2212 +nsresult 1.2213 +nsINode::CompareDocumentPosition(nsIDOMNode* aOther, uint16_t* aReturn) 1.2214 +{ 1.2215 + nsCOMPtr<nsINode> other = do_QueryInterface(aOther); 1.2216 + NS_ENSURE_ARG(other); 1.2217 + *aReturn = CompareDocumentPosition(*other); 1.2218 + return NS_OK; 1.2219 +} 1.2220 + 1.2221 +nsresult 1.2222 +nsINode::IsEqualNode(nsIDOMNode* aOther, bool* aReturn) 1.2223 +{ 1.2224 + nsCOMPtr<nsINode> other = do_QueryInterface(aOther); 1.2225 + *aReturn = IsEqualNode(other); 1.2226 + return NS_OK; 1.2227 +} 1.2228 + 1.2229 +void 1.2230 +nsINode::BindObject(nsISupports* aObject) 1.2231 +{ 1.2232 + nsCOMArray<nsISupports>* objects = 1.2233 + static_cast<nsCOMArray<nsISupports>*>(GetProperty(nsGkAtoms::keepobjectsalive)); 1.2234 + if (!objects) { 1.2235 + objects = new nsCOMArray<nsISupports>(); 1.2236 + SetProperty(nsGkAtoms::keepobjectsalive, objects, 1.2237 + nsINode::DeleteProperty< nsCOMArray<nsISupports> >, true); 1.2238 + } 1.2239 + objects->AppendObject(aObject); 1.2240 +} 1.2241 + 1.2242 +void 1.2243 +nsINode::UnbindObject(nsISupports* aObject) 1.2244 +{ 1.2245 + nsCOMArray<nsISupports>* objects = 1.2246 + static_cast<nsCOMArray<nsISupports>*>(GetProperty(nsGkAtoms::keepobjectsalive)); 1.2247 + if (objects) { 1.2248 + objects->RemoveObject(aObject); 1.2249 + } 1.2250 +} 1.2251 + 1.2252 +void 1.2253 +nsINode::GetBoundMutationObservers(nsTArray<nsRefPtr<nsDOMMutationObserver> >& aResult) 1.2254 +{ 1.2255 + nsCOMArray<nsISupports>* objects = 1.2256 + static_cast<nsCOMArray<nsISupports>*>(GetProperty(nsGkAtoms::keepobjectsalive)); 1.2257 + if (objects) { 1.2258 + for (int32_t i = 0; i < objects->Count(); ++i) { 1.2259 + nsCOMPtr<nsDOMMutationObserver> mo = do_QueryInterface(objects->ObjectAt(i)); 1.2260 + if (mo) { 1.2261 + MOZ_ASSERT(!aResult.Contains(mo)); 1.2262 + aResult.AppendElement(mo); 1.2263 + } 1.2264 + } 1.2265 + } 1.2266 +} 1.2267 + 1.2268 +size_t 1.2269 +nsINode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const 1.2270 +{ 1.2271 + size_t n = 0; 1.2272 + EventListenerManager* elm = GetExistingListenerManager(); 1.2273 + if (elm) { 1.2274 + n += elm->SizeOfIncludingThis(aMallocSizeOf); 1.2275 + } 1.2276 + 1.2277 + // Measurement of the following members may be added later if DMD finds it is 1.2278 + // worthwhile: 1.2279 + // - mNodeInfo 1.2280 + // - mSlots 1.2281 + // 1.2282 + // The following members are not measured: 1.2283 + // - mParent, mNextSibling, mPreviousSibling, mFirstChild: because they're 1.2284 + // non-owning 1.2285 + return n; 1.2286 +} 1.2287 + 1.2288 +#define EVENT(name_, id_, type_, struct_) \ 1.2289 + EventHandlerNonNull* nsINode::GetOn##name_() { \ 1.2290 + EventListenerManager *elm = GetExistingListenerManager(); \ 1.2291 + return elm ? elm->GetEventHandler(nsGkAtoms::on##name_, EmptyString()) \ 1.2292 + : nullptr; \ 1.2293 + } \ 1.2294 + void nsINode::SetOn##name_(EventHandlerNonNull* handler) \ 1.2295 + { \ 1.2296 + EventListenerManager *elm = GetOrCreateListenerManager(); \ 1.2297 + if (elm) { \ 1.2298 + elm->SetEventHandler(nsGkAtoms::on##name_, EmptyString(), handler); \ 1.2299 + } \ 1.2300 + } 1.2301 +#define TOUCH_EVENT EVENT 1.2302 +#define DOCUMENT_ONLY_EVENT EVENT 1.2303 +#include "mozilla/EventNameList.h" 1.2304 +#undef DOCUMENT_ONLY_EVENT 1.2305 +#undef TOUCH_EVENT 1.2306 +#undef EVENT 1.2307 + 1.2308 +bool 1.2309 +nsINode::Contains(const nsINode* aOther) const 1.2310 +{ 1.2311 + if (aOther == this) { 1.2312 + return true; 1.2313 + } 1.2314 + if (!aOther || 1.2315 + OwnerDoc() != aOther->OwnerDoc() || 1.2316 + IsInDoc() != aOther->IsInDoc() || 1.2317 + !(aOther->IsElement() || 1.2318 + aOther->IsNodeOfType(nsINode::eCONTENT)) || 1.2319 + !GetFirstChild()) { 1.2320 + return false; 1.2321 + } 1.2322 + 1.2323 + const nsIContent* other = static_cast<const nsIContent*>(aOther); 1.2324 + if (this == OwnerDoc()) { 1.2325 + // document.contains(aOther) returns true if aOther is in the document, 1.2326 + // but is not in any anonymous subtree. 1.2327 + // IsInDoc() check is done already before this. 1.2328 + return !other->IsInAnonymousSubtree(); 1.2329 + } 1.2330 + 1.2331 + if (!IsElement() && !IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT)) { 1.2332 + return false; 1.2333 + } 1.2334 + 1.2335 + const nsIContent* thisContent = static_cast<const nsIContent*>(this); 1.2336 + if (thisContent->GetBindingParent() != other->GetBindingParent()) { 1.2337 + return false; 1.2338 + } 1.2339 + 1.2340 + return nsContentUtils::ContentIsDescendantOf(other, this); 1.2341 +} 1.2342 + 1.2343 +nsresult 1.2344 +nsINode::Contains(nsIDOMNode* aOther, bool* aReturn) 1.2345 +{ 1.2346 + nsCOMPtr<nsINode> node = do_QueryInterface(aOther); 1.2347 + *aReturn = Contains(node); 1.2348 + return NS_OK; 1.2349 +} 1.2350 + 1.2351 +uint32_t 1.2352 +nsINode::Length() const 1.2353 +{ 1.2354 + switch (NodeType()) { 1.2355 + case nsIDOMNode::DOCUMENT_TYPE_NODE: 1.2356 + return 0; 1.2357 + 1.2358 + case nsIDOMNode::TEXT_NODE: 1.2359 + case nsIDOMNode::CDATA_SECTION_NODE: 1.2360 + case nsIDOMNode::PROCESSING_INSTRUCTION_NODE: 1.2361 + case nsIDOMNode::COMMENT_NODE: 1.2362 + MOZ_ASSERT(IsNodeOfType(eCONTENT)); 1.2363 + return static_cast<const nsIContent*>(this)->TextLength(); 1.2364 + 1.2365 + default: 1.2366 + return GetChildCount(); 1.2367 + } 1.2368 +} 1.2369 + 1.2370 +nsCSSSelectorList* 1.2371 +nsINode::ParseSelectorList(const nsAString& aSelectorString, 1.2372 + ErrorResult& aRv) 1.2373 +{ 1.2374 + nsIDocument* doc = OwnerDoc(); 1.2375 + nsIDocument::SelectorCache& cache = doc->GetSelectorCache(); 1.2376 + nsCSSSelectorList* selectorList = nullptr; 1.2377 + bool haveCachedList = cache.GetList(aSelectorString, &selectorList); 1.2378 + if (haveCachedList) { 1.2379 + if (!selectorList) { 1.2380 + // Invalid selector. 1.2381 + aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); 1.2382 + } 1.2383 + return selectorList; 1.2384 + } 1.2385 + 1.2386 + nsCSSParser parser(doc->CSSLoader()); 1.2387 + 1.2388 + aRv = parser.ParseSelectorString(aSelectorString, 1.2389 + doc->GetDocumentURI(), 1.2390 + 0, // XXXbz get the line number! 1.2391 + &selectorList); 1.2392 + if (aRv.Failed()) { 1.2393 + // We hit this for syntax errors, which are quite common, so don't 1.2394 + // use NS_ENSURE_SUCCESS. (For example, jQuery has an extended set 1.2395 + // of selectors, but it sees if we can parse them first.) 1.2396 + MOZ_ASSERT(aRv.ErrorCode() == NS_ERROR_DOM_SYNTAX_ERR, 1.2397 + "Unexpected error, so cached version won't return it"); 1.2398 + cache.CacheList(aSelectorString, nullptr); 1.2399 + return nullptr; 1.2400 + } 1.2401 + 1.2402 + // Filter out pseudo-element selectors from selectorList 1.2403 + nsCSSSelectorList** slot = &selectorList; 1.2404 + do { 1.2405 + nsCSSSelectorList* cur = *slot; 1.2406 + if (cur->mSelectors->IsPseudoElement()) { 1.2407 + *slot = cur->mNext; 1.2408 + cur->mNext = nullptr; 1.2409 + delete cur; 1.2410 + } else { 1.2411 + slot = &cur->mNext; 1.2412 + } 1.2413 + } while (*slot); 1.2414 + 1.2415 + if (selectorList) { 1.2416 + NS_ASSERTION(selectorList->mSelectors, 1.2417 + "How can we not have any selectors?"); 1.2418 + cache.CacheList(aSelectorString, selectorList); 1.2419 + } else { 1.2420 + // This is the "only pseudo-element selectors" case, which is 1.2421 + // not common, so just don't worry about caching it. That way a 1.2422 + // null cached value can always indicate an invalid selector. 1.2423 + } 1.2424 + 1.2425 + return selectorList; 1.2426 +} 1.2427 + 1.2428 +static void 1.2429 +AddScopeElements(TreeMatchContext& aMatchContext, 1.2430 + nsINode* aMatchContextNode) 1.2431 +{ 1.2432 + if (aMatchContextNode->IsElement()) { 1.2433 + aMatchContext.SetHasSpecifiedScope(); 1.2434 + aMatchContext.AddScopeElement(aMatchContextNode->AsElement()); 1.2435 + } 1.2436 +} 1.2437 + 1.2438 +namespace { 1.2439 +struct SelectorMatchInfo { 1.2440 + nsCSSSelectorList* const mSelectorList; 1.2441 + TreeMatchContext& mMatchContext; 1.2442 +}; 1.2443 +} 1.2444 + 1.2445 +// Given an id, find elements with that id under aRoot that match aMatchInfo if 1.2446 +// any is provided. If no SelectorMatchInfo is provided, just find the ones 1.2447 +// with the given id. aRoot must be in the document. 1.2448 +template<bool onlyFirstMatch, class T> 1.2449 +inline static void 1.2450 +FindMatchingElementsWithId(const nsAString& aId, nsINode* aRoot, 1.2451 + SelectorMatchInfo* aMatchInfo, 1.2452 + T& aList) 1.2453 +{ 1.2454 + MOZ_ASSERT(aRoot->IsInDoc(), 1.2455 + "Don't call me if the root is not in the document"); 1.2456 + MOZ_ASSERT(aRoot->IsElement() || aRoot->IsNodeOfType(nsINode::eDOCUMENT), 1.2457 + "The optimization below to check ContentIsDescendantOf only for " 1.2458 + "elements depends on aRoot being either an element or a " 1.2459 + "document if it's in the document. Note that document fragments " 1.2460 + "can't be IsInDoc(), so should never show up here."); 1.2461 + 1.2462 + const nsSmallVoidArray* elements = aRoot->OwnerDoc()->GetAllElementsForId(aId); 1.2463 + 1.2464 + if (!elements) { 1.2465 + // Nothing to do; we're done 1.2466 + return; 1.2467 + } 1.2468 + 1.2469 + // XXXbz: Should we fall back to the tree walk if aRoot is not the 1.2470 + // document and |elements| is long, for some value of "long"? 1.2471 + for (int32_t i = 0; i < elements->Count(); ++i) { 1.2472 + Element *element = static_cast<Element*>(elements->ElementAt(i)); 1.2473 + if (!aRoot->IsElement() || 1.2474 + (element != aRoot && 1.2475 + nsContentUtils::ContentIsDescendantOf(element, aRoot))) { 1.2476 + // We have an element with the right id and it's a strict descendant 1.2477 + // of aRoot. Make sure it really matches the selector. 1.2478 + if (!aMatchInfo || 1.2479 + nsCSSRuleProcessor::SelectorListMatches(element, 1.2480 + aMatchInfo->mMatchContext, 1.2481 + aMatchInfo->mSelectorList)) { 1.2482 + aList.AppendElement(element); 1.2483 + if (onlyFirstMatch) { 1.2484 + return; 1.2485 + } 1.2486 + } 1.2487 + } 1.2488 + } 1.2489 +} 1.2490 + 1.2491 +// Actually find elements matching aSelectorList (which must not be 1.2492 +// null) and which are descendants of aRoot and put them in aList. If 1.2493 +// onlyFirstMatch, then stop once the first one is found. 1.2494 +template<bool onlyFirstMatch, class Collector, class T> 1.2495 +MOZ_ALWAYS_INLINE static void 1.2496 +FindMatchingElements(nsINode* aRoot, nsCSSSelectorList* aSelectorList, T &aList, 1.2497 + ErrorResult& aRv) 1.2498 +{ 1.2499 + nsIDocument* doc = aRoot->OwnerDoc(); 1.2500 + 1.2501 + TreeMatchContext matchingContext(false, nsRuleWalker::eRelevantLinkUnvisited, 1.2502 + doc, TreeMatchContext::eNeverMatchVisited); 1.2503 + doc->FlushPendingLinkUpdates(); 1.2504 + AddScopeElements(matchingContext, aRoot); 1.2505 + 1.2506 + // Fast-path selectors involving IDs. We can only do this if aRoot 1.2507 + // is in the document and the document is not in quirks mode, since 1.2508 + // ID selectors are case-insensitive in quirks mode. Also, only do 1.2509 + // this if aSelectorList only has one selector, because otherwise 1.2510 + // ordering the elements correctly is a pain. 1.2511 + NS_ASSERTION(aRoot->IsElement() || aRoot->IsNodeOfType(nsINode::eDOCUMENT) || 1.2512 + !aRoot->IsInDoc(), 1.2513 + "The optimization below to check ContentIsDescendantOf only for " 1.2514 + "elements depends on aRoot being either an element or a " 1.2515 + "document if it's in the document."); 1.2516 + if (aRoot->IsInDoc() && 1.2517 + doc->GetCompatibilityMode() != eCompatibility_NavQuirks && 1.2518 + !aSelectorList->mNext && 1.2519 + aSelectorList->mSelectors->mIDList) { 1.2520 + nsIAtom* id = aSelectorList->mSelectors->mIDList->mAtom; 1.2521 + SelectorMatchInfo info = { aSelectorList, matchingContext }; 1.2522 + FindMatchingElementsWithId<onlyFirstMatch, T>(nsDependentAtomString(id), 1.2523 + aRoot, &info, aList); 1.2524 + return; 1.2525 + } 1.2526 + 1.2527 + Collector results; 1.2528 + for (nsIContent* cur = aRoot->GetFirstChild(); 1.2529 + cur; 1.2530 + cur = cur->GetNextNode(aRoot)) { 1.2531 + if (cur->IsElement() && 1.2532 + nsCSSRuleProcessor::SelectorListMatches(cur->AsElement(), 1.2533 + matchingContext, 1.2534 + aSelectorList)) { 1.2535 + if (onlyFirstMatch) { 1.2536 + aList.AppendElement(cur->AsElement()); 1.2537 + return; 1.2538 + } 1.2539 + results.AppendElement(cur->AsElement()); 1.2540 + } 1.2541 + } 1.2542 + 1.2543 + const uint32_t len = results.Length(); 1.2544 + if (len) { 1.2545 + aList.SetCapacity(len); 1.2546 + for (uint32_t i = 0; i < len; ++i) { 1.2547 + aList.AppendElement(results.ElementAt(i)); 1.2548 + } 1.2549 + } 1.2550 +} 1.2551 + 1.2552 +struct ElementHolder { 1.2553 + ElementHolder() : mElement(nullptr) {} 1.2554 + void AppendElement(Element* aElement) { 1.2555 + NS_ABORT_IF_FALSE(!mElement, "Should only get one element"); 1.2556 + mElement = aElement; 1.2557 + } 1.2558 + void SetCapacity(uint32_t aCapacity) { MOZ_CRASH("Don't call me!"); } 1.2559 + uint32_t Length() { return 0; } 1.2560 + Element* ElementAt(uint32_t aIndex) { return nullptr; } 1.2561 + 1.2562 + Element* mElement; 1.2563 +}; 1.2564 + 1.2565 +Element* 1.2566 +nsINode::QuerySelector(const nsAString& aSelector, ErrorResult& aResult) 1.2567 +{ 1.2568 + nsCSSSelectorList* selectorList = ParseSelectorList(aSelector, aResult); 1.2569 + if (!selectorList) { 1.2570 + // Either we failed (and aResult already has the exception), or this 1.2571 + // is a pseudo-element-only selector that matches nothing. 1.2572 + return nullptr; 1.2573 + } 1.2574 + ElementHolder holder; 1.2575 + FindMatchingElements<true, ElementHolder>(this, selectorList, holder, aResult); 1.2576 + return holder.mElement; 1.2577 +} 1.2578 + 1.2579 +already_AddRefed<nsINodeList> 1.2580 +nsINode::QuerySelectorAll(const nsAString& aSelector, ErrorResult& aResult) 1.2581 +{ 1.2582 + nsRefPtr<nsSimpleContentList> contentList = new nsSimpleContentList(this); 1.2583 + 1.2584 + nsCSSSelectorList* selectorList = ParseSelectorList(aSelector, aResult); 1.2585 + if (selectorList) { 1.2586 + FindMatchingElements<false, nsAutoTArray<Element*, 128>>(this, 1.2587 + selectorList, 1.2588 + *contentList, 1.2589 + aResult); 1.2590 + } else { 1.2591 + // Either we failed (and aResult already has the exception), or this 1.2592 + // is a pseudo-element-only selector that matches nothing. 1.2593 + } 1.2594 + 1.2595 + return contentList.forget(); 1.2596 +} 1.2597 + 1.2598 +nsresult 1.2599 +nsINode::QuerySelector(const nsAString& aSelector, nsIDOMElement **aReturn) 1.2600 +{ 1.2601 + ErrorResult rv; 1.2602 + Element* result = nsINode::QuerySelector(aSelector, rv); 1.2603 + if (rv.Failed()) { 1.2604 + return rv.ErrorCode(); 1.2605 + } 1.2606 + nsCOMPtr<nsIDOMElement> elt = do_QueryInterface(result); 1.2607 + elt.forget(aReturn); 1.2608 + return NS_OK; 1.2609 +} 1.2610 + 1.2611 +nsresult 1.2612 +nsINode::QuerySelectorAll(const nsAString& aSelector, nsIDOMNodeList **aReturn) 1.2613 +{ 1.2614 + ErrorResult rv; 1.2615 + *aReturn = nsINode::QuerySelectorAll(aSelector, rv).take(); 1.2616 + return rv.ErrorCode(); 1.2617 +} 1.2618 + 1.2619 +Element* 1.2620 +nsINode::GetElementById(const nsAString& aId) 1.2621 +{ 1.2622 + MOZ_ASSERT(IsElement() || IsNodeOfType(eDOCUMENT_FRAGMENT), 1.2623 + "Bogus this object for GetElementById call"); 1.2624 + if (IsInDoc()) { 1.2625 + ElementHolder holder; 1.2626 + FindMatchingElementsWithId<true>(aId, this, nullptr, holder); 1.2627 + return holder.mElement; 1.2628 + } 1.2629 + 1.2630 + for (nsIContent* kid = GetFirstChild(); kid; kid = kid->GetNextNode(this)) { 1.2631 + if (!kid->IsElement()) { 1.2632 + continue; 1.2633 + } 1.2634 + nsIAtom* id = kid->AsElement()->GetID(); 1.2635 + if (id && id->Equals(aId)) { 1.2636 + return kid->AsElement(); 1.2637 + } 1.2638 + } 1.2639 + return nullptr; 1.2640 +} 1.2641 + 1.2642 +JSObject* 1.2643 +nsINode::WrapObject(JSContext *aCx) 1.2644 +{ 1.2645 + MOZ_ASSERT(IsDOMBinding()); 1.2646 + 1.2647 + // Make sure one of these is true 1.2648 + // (1) our owner document has a script handling object, 1.2649 + // (2) Our owner document has had a script handling object, or has been marked 1.2650 + // to have had one, 1.2651 + // (3) we are running a privileged script. 1.2652 + // Event handling is possible only if (1). If (2) event handling is 1.2653 + // prevented. 1.2654 + // If the document has never had a script handling object, untrusted 1.2655 + // scripts (3) shouldn't touch it! 1.2656 + bool hasHadScriptHandlingObject = false; 1.2657 + if (!OwnerDoc()->GetScriptHandlingObject(hasHadScriptHandlingObject) && 1.2658 + !hasHadScriptHandlingObject && 1.2659 + !nsContentUtils::IsCallerChrome()) { 1.2660 + Throw(aCx, NS_ERROR_UNEXPECTED); 1.2661 + return nullptr; 1.2662 + } 1.2663 + 1.2664 + JS::Rooted<JSObject*> obj(aCx, WrapNode(aCx)); 1.2665 + MOZ_ASSERT_IF(ChromeOnlyAccess(), 1.2666 + xpc::IsInXBLScope(obj) || !xpc::UseXBLScope(js::GetObjectCompartment(obj))); 1.2667 + return obj; 1.2668 +} 1.2669 + 1.2670 +already_AddRefed<nsINode> 1.2671 +nsINode::CloneNode(bool aDeep, ErrorResult& aError) 1.2672 +{ 1.2673 + bool callUserDataHandlers = NodeType() != nsIDOMNode::DOCUMENT_NODE || 1.2674 + !static_cast<nsIDocument*>(this)->CreatingStaticClone(); 1.2675 + 1.2676 + nsCOMPtr<nsINode> result; 1.2677 + aError = nsNodeUtils::CloneNodeImpl(this, aDeep, callUserDataHandlers, 1.2678 + getter_AddRefs(result)); 1.2679 + return result.forget(); 1.2680 +} 1.2681 + 1.2682 +nsDOMAttributeMap* 1.2683 +nsINode::GetAttributes() 1.2684 +{ 1.2685 + if (!IsElement()) { 1.2686 + return nullptr; 1.2687 + } 1.2688 + return AsElement()->Attributes(); 1.2689 +} 1.2690 + 1.2691 +bool 1.2692 +EventTarget::DispatchEvent(Event& aEvent, 1.2693 + ErrorResult& aRv) 1.2694 +{ 1.2695 + bool result = false; 1.2696 + aRv = DispatchEvent(&aEvent, &result); 1.2697 + return result; 1.2698 +}