1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/src/nsGenericDOMDataNode.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1098 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * Base class for DOM Core's nsIDOMComment, nsIDOMDocumentType, nsIDOMText, 1.11 + * nsIDOMCDATASection, and nsIDOMProcessingInstruction nodes. 1.12 + */ 1.13 + 1.14 +#include "mozilla/DebugOnly.h" 1.15 + 1.16 +#include "nsGenericDOMDataNode.h" 1.17 +#include "mozilla/AsyncEventDispatcher.h" 1.18 +#include "mozilla/MemoryReporting.h" 1.19 +#include "mozilla/dom/Element.h" 1.20 +#include "mozilla/dom/ShadowRoot.h" 1.21 +#include "nsIDocument.h" 1.22 +#include "nsIDOMDocument.h" 1.23 +#include "nsReadableUtils.h" 1.24 +#include "mozilla/InternalMutationEvent.h" 1.25 +#include "nsIURI.h" 1.26 +#include "nsIDOMEvent.h" 1.27 +#include "nsIDOMText.h" 1.28 +#include "nsCOMPtr.h" 1.29 +#include "nsDOMString.h" 1.30 +#include "nsIDOMUserDataHandler.h" 1.31 +#include "nsChangeHint.h" 1.32 +#include "nsCOMArray.h" 1.33 +#include "nsNodeUtils.h" 1.34 +#include "mozilla/dom/DirectionalityUtils.h" 1.35 +#include "nsBindingManager.h" 1.36 +#include "nsCCUncollectableMarker.h" 1.37 +#include "mozAutoDocUpdate.h" 1.38 + 1.39 +#include "pldhash.h" 1.40 +#include "prprf.h" 1.41 +#include "nsWrapperCacheInlines.h" 1.42 + 1.43 +using namespace mozilla; 1.44 +using namespace mozilla::dom; 1.45 + 1.46 +nsGenericDOMDataNode::nsGenericDOMDataNode(already_AddRefed<nsINodeInfo>& aNodeInfo) 1.47 + : nsIContent(aNodeInfo) 1.48 +{ 1.49 + NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::TEXT_NODE || 1.50 + mNodeInfo->NodeType() == nsIDOMNode::CDATA_SECTION_NODE || 1.51 + mNodeInfo->NodeType() == nsIDOMNode::COMMENT_NODE || 1.52 + mNodeInfo->NodeType() == 1.53 + nsIDOMNode::PROCESSING_INSTRUCTION_NODE || 1.54 + mNodeInfo->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE, 1.55 + "Bad NodeType in aNodeInfo"); 1.56 +} 1.57 + 1.58 +nsGenericDOMDataNode::nsGenericDOMDataNode(already_AddRefed<nsINodeInfo>&& aNodeInfo) 1.59 + : nsIContent(aNodeInfo) 1.60 +{ 1.61 + NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::TEXT_NODE || 1.62 + mNodeInfo->NodeType() == nsIDOMNode::CDATA_SECTION_NODE || 1.63 + mNodeInfo->NodeType() == nsIDOMNode::COMMENT_NODE || 1.64 + mNodeInfo->NodeType() == 1.65 + nsIDOMNode::PROCESSING_INSTRUCTION_NODE || 1.66 + mNodeInfo->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE, 1.67 + "Bad NodeType in aNodeInfo"); 1.68 +} 1.69 + 1.70 +nsGenericDOMDataNode::~nsGenericDOMDataNode() 1.71 +{ 1.72 + NS_PRECONDITION(!IsInDoc(), 1.73 + "Please remove this from the document properly"); 1.74 + if (GetParent()) { 1.75 + NS_RELEASE(mParent); 1.76 + } 1.77 +} 1.78 + 1.79 +NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericDOMDataNode) 1.80 + 1.81 +NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsGenericDOMDataNode) 1.82 + 1.83 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGenericDOMDataNode) 1.84 + return Element::CanSkip(tmp, aRemovingAllowed); 1.85 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END 1.86 + 1.87 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGenericDOMDataNode) 1.88 + return Element::CanSkipInCC(tmp); 1.89 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END 1.90 + 1.91 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGenericDOMDataNode) 1.92 + return Element::CanSkipThis(tmp); 1.93 +NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END 1.94 + 1.95 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGenericDOMDataNode) 1.96 + // Always need to traverse script objects, so do that before we check 1.97 + // if we're uncollectable. 1.98 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS 1.99 + 1.100 + if (!nsINode::Traverse(tmp, cb)) { 1.101 + return NS_SUCCESS_INTERRUPTED_TRAVERSE; 1.102 + } 1.103 + 1.104 + nsDataSlots *slots = tmp->GetExistingDataSlots(); 1.105 + if (slots) { 1.106 + slots->Traverse(cb); 1.107 + } 1.108 + 1.109 + tmp->OwnerDoc()->BindingManager()->Traverse(tmp, cb); 1.110 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.111 + 1.112 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericDOMDataNode) 1.113 + nsINode::Unlink(tmp); 1.114 + 1.115 + nsDataSlots *slots = tmp->GetExistingDataSlots(); 1.116 + if (slots) { 1.117 + slots->Unlink(); 1.118 + } 1.119 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.120 + 1.121 +NS_INTERFACE_MAP_BEGIN(nsGenericDOMDataNode) 1.122 + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 1.123 + NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsGenericDOMDataNode) 1.124 + NS_INTERFACE_MAP_ENTRY(nsIContent) 1.125 + NS_INTERFACE_MAP_ENTRY(nsINode) 1.126 + NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget) 1.127 + NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget) 1.128 + NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference, 1.129 + new nsNodeSupportsWeakRefTearoff(this)) 1.130 + NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMXPathNSResolver, 1.131 + new nsNode3Tearoff(this)) 1.132 + // DOM bindings depend on the identity pointer being the 1.133 + // same as nsINode (which nsIContent inherits). 1.134 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent) 1.135 +NS_INTERFACE_MAP_END 1.136 + 1.137 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGenericDOMDataNode) 1.138 +NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsGenericDOMDataNode, 1.139 + nsNodeUtils::LastRelease(this)) 1.140 + 1.141 + 1.142 +void 1.143 +nsGenericDOMDataNode::GetNodeValueInternal(nsAString& aNodeValue) 1.144 +{ 1.145 + DebugOnly<nsresult> rv = GetData(aNodeValue); 1.146 + NS_ASSERTION(NS_SUCCEEDED(rv), "GetData() failed!"); 1.147 +} 1.148 + 1.149 +void 1.150 +nsGenericDOMDataNode::SetNodeValueInternal(const nsAString& aNodeValue, 1.151 + ErrorResult& aError) 1.152 +{ 1.153 + aError = SetTextInternal(0, mText.GetLength(), aNodeValue.BeginReading(), 1.154 + aNodeValue.Length(), true); 1.155 +} 1.156 + 1.157 +//---------------------------------------------------------------------- 1.158 + 1.159 +// Implementation of nsIDOMCharacterData 1.160 + 1.161 +nsresult 1.162 +nsGenericDOMDataNode::GetData(nsAString& aData) const 1.163 +{ 1.164 + if (mText.Is2b()) { 1.165 + aData.Assign(mText.Get2b(), mText.GetLength()); 1.166 + } else { 1.167 + // Must use Substring() since nsDependentCString() requires null 1.168 + // terminated strings. 1.169 + 1.170 + const char *data = mText.Get1b(); 1.171 + 1.172 + if (data) { 1.173 + CopyASCIItoUTF16(Substring(data, data + mText.GetLength()), aData); 1.174 + } else { 1.175 + aData.Truncate(); 1.176 + } 1.177 + } 1.178 + 1.179 + return NS_OK; 1.180 +} 1.181 + 1.182 +nsresult 1.183 +nsGenericDOMDataNode::SetData(const nsAString& aData) 1.184 +{ 1.185 + return SetTextInternal(0, mText.GetLength(), aData.BeginReading(), 1.186 + aData.Length(), true); 1.187 +} 1.188 + 1.189 +nsresult 1.190 +nsGenericDOMDataNode::GetLength(uint32_t* aLength) 1.191 +{ 1.192 + *aLength = mText.GetLength(); 1.193 + return NS_OK; 1.194 +} 1.195 + 1.196 +nsresult 1.197 +nsGenericDOMDataNode::SubstringData(uint32_t aStart, uint32_t aCount, 1.198 + nsAString& aReturn) 1.199 +{ 1.200 + ErrorResult rv; 1.201 + SubstringData(aStart, aCount, aReturn, rv); 1.202 + return rv.ErrorCode(); 1.203 +} 1.204 + 1.205 +void 1.206 +nsGenericDOMDataNode::SubstringData(uint32_t aStart, uint32_t aCount, 1.207 + nsAString& aReturn, ErrorResult& rv) 1.208 +{ 1.209 + aReturn.Truncate(); 1.210 + 1.211 + uint32_t textLength = mText.GetLength(); 1.212 + if (aStart > textLength) { 1.213 + rv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); 1.214 + return; 1.215 + } 1.216 + 1.217 + uint32_t amount = aCount; 1.218 + if (amount > textLength - aStart) { 1.219 + amount = textLength - aStart; 1.220 + } 1.221 + 1.222 + if (mText.Is2b()) { 1.223 + aReturn.Assign(mText.Get2b() + aStart, amount); 1.224 + } else { 1.225 + // Must use Substring() since nsDependentCString() requires null 1.226 + // terminated strings. 1.227 + 1.228 + const char *data = mText.Get1b() + aStart; 1.229 + CopyASCIItoUTF16(Substring(data, data + amount), aReturn); 1.230 + } 1.231 +} 1.232 + 1.233 +NS_IMETHODIMP 1.234 +nsGenericDOMDataNode::MozRemove() 1.235 +{ 1.236 + Remove(); 1.237 + return NS_OK; 1.238 +} 1.239 + 1.240 +//---------------------------------------------------------------------- 1.241 + 1.242 +nsresult 1.243 +nsGenericDOMDataNode::AppendData(const nsAString& aData) 1.244 +{ 1.245 + return SetTextInternal(mText.GetLength(), 0, aData.BeginReading(), 1.246 + aData.Length(), true); 1.247 +} 1.248 + 1.249 +nsresult 1.250 +nsGenericDOMDataNode::InsertData(uint32_t aOffset, 1.251 + const nsAString& aData) 1.252 +{ 1.253 + return SetTextInternal(aOffset, 0, aData.BeginReading(), 1.254 + aData.Length(), true); 1.255 +} 1.256 + 1.257 +nsresult 1.258 +nsGenericDOMDataNode::DeleteData(uint32_t aOffset, uint32_t aCount) 1.259 +{ 1.260 + return SetTextInternal(aOffset, aCount, nullptr, 0, true); 1.261 +} 1.262 + 1.263 +nsresult 1.264 +nsGenericDOMDataNode::ReplaceData(uint32_t aOffset, uint32_t aCount, 1.265 + const nsAString& aData) 1.266 +{ 1.267 + return SetTextInternal(aOffset, aCount, aData.BeginReading(), 1.268 + aData.Length(), true); 1.269 +} 1.270 + 1.271 +nsresult 1.272 +nsGenericDOMDataNode::SetTextInternal(uint32_t aOffset, uint32_t aCount, 1.273 + const char16_t* aBuffer, 1.274 + uint32_t aLength, bool aNotify, 1.275 + CharacterDataChangeInfo::Details* aDetails) 1.276 +{ 1.277 + NS_PRECONDITION(aBuffer || !aLength, 1.278 + "Null buffer passed to SetTextInternal!"); 1.279 + 1.280 + // sanitize arguments 1.281 + uint32_t textLength = mText.GetLength(); 1.282 + if (aOffset > textLength) { 1.283 + return NS_ERROR_DOM_INDEX_SIZE_ERR; 1.284 + } 1.285 + 1.286 + if (aCount > textLength - aOffset) { 1.287 + aCount = textLength - aOffset; 1.288 + } 1.289 + 1.290 + uint32_t endOffset = aOffset + aCount; 1.291 + 1.292 + // Make sure the text fragment can hold the new data. 1.293 + if (aLength > aCount && !mText.CanGrowBy(aLength - aCount)) { 1.294 + return NS_ERROR_OUT_OF_MEMORY; 1.295 + } 1.296 + 1.297 + nsIDocument *document = GetCurrentDoc(); 1.298 + mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify); 1.299 + 1.300 + bool haveMutationListeners = aNotify && 1.301 + nsContentUtils::HasMutationListeners(this, 1.302 + NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED, 1.303 + this); 1.304 + 1.305 + nsCOMPtr<nsIAtom> oldValue; 1.306 + if (haveMutationListeners) { 1.307 + oldValue = GetCurrentValueAtom(); 1.308 + } 1.309 + 1.310 + if (aNotify) { 1.311 + CharacterDataChangeInfo info = { 1.312 + aOffset == textLength, 1.313 + aOffset, 1.314 + endOffset, 1.315 + aLength, 1.316 + aDetails 1.317 + }; 1.318 + nsNodeUtils::CharacterDataWillChange(this, &info); 1.319 + } 1.320 + 1.321 + Directionality oldDir = eDir_NotSet; 1.322 + bool dirAffectsAncestor = (NodeType() == nsIDOMNode::TEXT_NODE && 1.323 + TextNodeWillChangeDirection(this, &oldDir, aOffset)); 1.324 + 1.325 + if (aOffset == 0 && endOffset == textLength) { 1.326 + // Replacing whole text or old text was empty. Don't bother to check for 1.327 + // bidi in this string if the document already has bidi enabled. 1.328 + bool ok = mText.SetTo(aBuffer, aLength, !document || !document->GetBidiEnabled()); 1.329 + NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY); 1.330 + } 1.331 + else if (aOffset == textLength) { 1.332 + // Appending to existing 1.333 + bool ok = mText.Append(aBuffer, aLength, !document || !document->GetBidiEnabled()); 1.334 + NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY); 1.335 + } 1.336 + else { 1.337 + // Merging old and new 1.338 + 1.339 + // Allocate new buffer 1.340 + int32_t newLength = textLength - aCount + aLength; 1.341 + char16_t* to = new char16_t[newLength]; 1.342 + NS_ENSURE_TRUE(to, NS_ERROR_OUT_OF_MEMORY); 1.343 + 1.344 + // Copy over appropriate data 1.345 + if (aOffset) { 1.346 + mText.CopyTo(to, 0, aOffset); 1.347 + } 1.348 + if (aLength) { 1.349 + memcpy(to + aOffset, aBuffer, aLength * sizeof(char16_t)); 1.350 + } 1.351 + if (endOffset != textLength) { 1.352 + mText.CopyTo(to + aOffset + aLength, endOffset, textLength - endOffset); 1.353 + } 1.354 + 1.355 + bool ok = mText.SetTo(to, newLength, !document || !document->GetBidiEnabled()); 1.356 + 1.357 + delete [] to; 1.358 + 1.359 + NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY); 1.360 + } 1.361 + 1.362 + UnsetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE); 1.363 + 1.364 + if (document && mText.IsBidi()) { 1.365 + // If we found bidi characters in mText.SetTo() above, indicate that the 1.366 + // document contains bidi characters. 1.367 + document->SetBidiEnabled(); 1.368 + } 1.369 + 1.370 + if (dirAffectsAncestor) { 1.371 + TextNodeChangedDirection(this, oldDir, aNotify); 1.372 + } 1.373 + 1.374 + // Notify observers 1.375 + if (aNotify) { 1.376 + CharacterDataChangeInfo info = { 1.377 + aOffset == textLength, 1.378 + aOffset, 1.379 + endOffset, 1.380 + aLength, 1.381 + aDetails 1.382 + }; 1.383 + nsNodeUtils::CharacterDataChanged(this, &info); 1.384 + 1.385 + if (haveMutationListeners) { 1.386 + InternalMutationEvent mutation(true, NS_MUTATION_CHARACTERDATAMODIFIED); 1.387 + 1.388 + mutation.mPrevAttrValue = oldValue; 1.389 + if (aLength > 0) { 1.390 + nsAutoString val; 1.391 + mText.AppendTo(val); 1.392 + mutation.mNewAttrValue = do_GetAtom(val); 1.393 + } 1.394 + 1.395 + mozAutoSubtreeModified subtree(OwnerDoc(), this); 1.396 + (new AsyncEventDispatcher(this, mutation))->RunDOMEventWhenSafe(); 1.397 + } 1.398 + } 1.399 + 1.400 + return NS_OK; 1.401 +} 1.402 + 1.403 +//---------------------------------------------------------------------- 1.404 + 1.405 +// Implementation of nsIContent 1.406 + 1.407 +#ifdef DEBUG 1.408 +void 1.409 +nsGenericDOMDataNode::ToCString(nsAString& aBuf, int32_t aOffset, 1.410 + int32_t aLen) const 1.411 +{ 1.412 + if (mText.Is2b()) { 1.413 + const char16_t* cp = mText.Get2b() + aOffset; 1.414 + const char16_t* end = cp + aLen; 1.415 + 1.416 + while (cp < end) { 1.417 + char16_t ch = *cp++; 1.418 + if (ch == '&') { 1.419 + aBuf.AppendLiteral("&"); 1.420 + } else if (ch == '<') { 1.421 + aBuf.AppendLiteral("<"); 1.422 + } else if (ch == '>') { 1.423 + aBuf.AppendLiteral(">"); 1.424 + } else if ((ch < ' ') || (ch >= 127)) { 1.425 + char buf[10]; 1.426 + PR_snprintf(buf, sizeof(buf), "\\u%04x", ch); 1.427 + AppendASCIItoUTF16(buf, aBuf); 1.428 + } else { 1.429 + aBuf.Append(ch); 1.430 + } 1.431 + } 1.432 + } else { 1.433 + unsigned char* cp = (unsigned char*)mText.Get1b() + aOffset; 1.434 + const unsigned char* end = cp + aLen; 1.435 + 1.436 + while (cp < end) { 1.437 + char16_t ch = *cp++; 1.438 + if (ch == '&') { 1.439 + aBuf.AppendLiteral("&"); 1.440 + } else if (ch == '<') { 1.441 + aBuf.AppendLiteral("<"); 1.442 + } else if (ch == '>') { 1.443 + aBuf.AppendLiteral(">"); 1.444 + } else if ((ch < ' ') || (ch >= 127)) { 1.445 + char buf[10]; 1.446 + PR_snprintf(buf, sizeof(buf), "\\u%04x", ch); 1.447 + AppendASCIItoUTF16(buf, aBuf); 1.448 + } else { 1.449 + aBuf.Append(ch); 1.450 + } 1.451 + } 1.452 + } 1.453 +} 1.454 +#endif 1.455 + 1.456 + 1.457 +nsresult 1.458 +nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent, 1.459 + nsIContent* aBindingParent, 1.460 + bool aCompileEventHandlers) 1.461 +{ 1.462 + NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!"); 1.463 + NS_PRECONDITION(NODE_FROM(aParent, aDocument)->OwnerDoc() == OwnerDoc(), 1.464 + "Must have the same owner document"); 1.465 + NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(), 1.466 + "aDocument must be current doc of aParent"); 1.467 + NS_PRECONDITION(!GetCurrentDoc() && !IsInDoc(), 1.468 + "Already have a document. Unbind first!"); 1.469 + // Note that as we recurse into the kids, they'll have a non-null parent. So 1.470 + // only assert if our parent is _changing_ while we have a parent. 1.471 + NS_PRECONDITION(!GetParent() || aParent == GetParent(), 1.472 + "Already have a parent. Unbind first!"); 1.473 + NS_PRECONDITION(!GetBindingParent() || 1.474 + aBindingParent == GetBindingParent() || 1.475 + (!aBindingParent && aParent && 1.476 + aParent->GetBindingParent() == GetBindingParent()), 1.477 + "Already have a binding parent. Unbind first!"); 1.478 + NS_PRECONDITION(aBindingParent != this, 1.479 + "Content must not be its own binding parent"); 1.480 + NS_PRECONDITION(!IsRootOfNativeAnonymousSubtree() || 1.481 + aBindingParent == aParent, 1.482 + "Native anonymous content must have its parent as its " 1.483 + "own binding parent"); 1.484 + 1.485 + if (!aBindingParent && aParent) { 1.486 + aBindingParent = aParent->GetBindingParent(); 1.487 + } 1.488 + 1.489 + // First set the binding parent 1.490 + if (aBindingParent) { 1.491 + NS_ASSERTION(IsRootOfNativeAnonymousSubtree() || 1.492 + !HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE) || 1.493 + (aParent && aParent->IsInNativeAnonymousSubtree()), 1.494 + "Trying to re-bind content from native anonymous subtree to " 1.495 + "non-native anonymous parent!"); 1.496 + DataSlots()->mBindingParent = aBindingParent; // Weak, so no addref happens. 1.497 + if (aParent->IsInNativeAnonymousSubtree()) { 1.498 + SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE); 1.499 + } 1.500 + if (aParent->HasFlag(NODE_CHROME_ONLY_ACCESS)) { 1.501 + SetFlags(NODE_CHROME_ONLY_ACCESS); 1.502 + } 1.503 + if (aParent->HasFlag(NODE_IS_IN_SHADOW_TREE)) { 1.504 + SetFlags(NODE_IS_IN_SHADOW_TREE); 1.505 + } 1.506 + ShadowRoot* parentContainingShadow = aParent->GetContainingShadow(); 1.507 + if (parentContainingShadow) { 1.508 + DataSlots()->mContainingShadow = parentContainingShadow; 1.509 + } 1.510 + } 1.511 + 1.512 + // Set parent 1.513 + if (aParent) { 1.514 + if (!GetParent()) { 1.515 + NS_ADDREF(aParent); 1.516 + } 1.517 + mParent = aParent; 1.518 + } 1.519 + else { 1.520 + mParent = aDocument; 1.521 + } 1.522 + SetParentIsContent(aParent); 1.523 + 1.524 + // XXXbz sXBL/XBL2 issue! 1.525 + 1.526 + // Set document 1.527 + if (aDocument) { 1.528 + // We no longer need to track the subtree pointer (and in fact we'll assert 1.529 + // if we do this any later). 1.530 + ClearSubtreeRootPointer(); 1.531 + 1.532 + // XXX See the comment in Element::BindToTree 1.533 + SetInDocument(); 1.534 + if (mText.IsBidi()) { 1.535 + aDocument->SetBidiEnabled(); 1.536 + } 1.537 + // Clear the lazy frame construction bits. 1.538 + UnsetFlags(NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES); 1.539 + } else { 1.540 + // If we're not in the doc, update our subtree pointer. 1.541 + SetSubtreeRootPointer(aParent->SubtreeRoot()); 1.542 + } 1.543 + 1.544 + nsNodeUtils::ParentChainChanged(this); 1.545 + 1.546 + UpdateEditableState(false); 1.547 + 1.548 + NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document"); 1.549 + NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent"); 1.550 + NS_POSTCONDITION(aBindingParent == GetBindingParent(), 1.551 + "Bound to wrong binding parent"); 1.552 + 1.553 + return NS_OK; 1.554 +} 1.555 + 1.556 +void 1.557 +nsGenericDOMDataNode::UnbindFromTree(bool aDeep, bool aNullParent) 1.558 +{ 1.559 + // Unset frame flags; if we need them again later, they'll get set again. 1.560 + UnsetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE | 1.561 + NS_REFRAME_IF_WHITESPACE | 1.562 + // Also unset the shadow tree flag because it can 1.563 + // no longer be a descendant of a ShadowRoot. 1.564 + NODE_IS_IN_SHADOW_TREE); 1.565 + 1.566 + nsIDocument *document = GetCurrentDoc(); 1.567 + if (document) { 1.568 + // Notify XBL- & nsIAnonymousContentCreator-generated 1.569 + // anonymous content that the document is changing. 1.570 + // This is needed to update the insertion point. 1.571 + document->BindingManager()->RemovedFromDocument(this, document); 1.572 + } 1.573 + 1.574 + if (aNullParent) { 1.575 + if (GetParent()) { 1.576 + NS_RELEASE(mParent); 1.577 + } else { 1.578 + mParent = nullptr; 1.579 + } 1.580 + SetParentIsContent(false); 1.581 + } 1.582 + ClearInDocument(); 1.583 + 1.584 + // Begin keeping track of our subtree root. 1.585 + SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot()); 1.586 + 1.587 + nsDataSlots *slots = GetExistingDataSlots(); 1.588 + if (slots) { 1.589 + slots->mBindingParent = nullptr; 1.590 + slots->mContainingShadow = nullptr; 1.591 + } 1.592 + 1.593 + nsNodeUtils::ParentChainChanged(this); 1.594 +} 1.595 + 1.596 +already_AddRefed<nsINodeList> 1.597 +nsGenericDOMDataNode::GetChildren(uint32_t aFilter) 1.598 +{ 1.599 + return nullptr; 1.600 +} 1.601 + 1.602 +nsIAtom * 1.603 +nsGenericDOMDataNode::GetIDAttributeName() const 1.604 +{ 1.605 + return nullptr; 1.606 +} 1.607 + 1.608 +nsresult 1.609 +nsGenericDOMDataNode::SetAttr(int32_t aNameSpaceID, nsIAtom* aAttr, 1.610 + nsIAtom* aPrefix, const nsAString& aValue, 1.611 + bool aNotify) 1.612 +{ 1.613 + return NS_OK; 1.614 +} 1.615 + 1.616 +nsresult 1.617 +nsGenericDOMDataNode::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttr, 1.618 + bool aNotify) 1.619 +{ 1.620 + return NS_OK; 1.621 +} 1.622 + 1.623 +const nsAttrName* 1.624 +nsGenericDOMDataNode::GetAttrNameAt(uint32_t aIndex) const 1.625 +{ 1.626 + return nullptr; 1.627 +} 1.628 + 1.629 +uint32_t 1.630 +nsGenericDOMDataNode::GetAttrCount() const 1.631 +{ 1.632 + return 0; 1.633 +} 1.634 + 1.635 +uint32_t 1.636 +nsGenericDOMDataNode::GetChildCount() const 1.637 +{ 1.638 + return 0; 1.639 +} 1.640 + 1.641 +nsIContent * 1.642 +nsGenericDOMDataNode::GetChildAt(uint32_t aIndex) const 1.643 +{ 1.644 + return nullptr; 1.645 +} 1.646 + 1.647 +nsIContent * const * 1.648 +nsGenericDOMDataNode::GetChildArray(uint32_t* aChildCount) const 1.649 +{ 1.650 + *aChildCount = 0; 1.651 + return nullptr; 1.652 +} 1.653 + 1.654 +int32_t 1.655 +nsGenericDOMDataNode::IndexOf(const nsINode* aPossibleChild) const 1.656 +{ 1.657 + return -1; 1.658 +} 1.659 + 1.660 +nsresult 1.661 +nsGenericDOMDataNode::InsertChildAt(nsIContent* aKid, uint32_t aIndex, 1.662 + bool aNotify) 1.663 +{ 1.664 + return NS_OK; 1.665 +} 1.666 + 1.667 +void 1.668 +nsGenericDOMDataNode::RemoveChildAt(uint32_t aIndex, bool aNotify) 1.669 +{ 1.670 +} 1.671 + 1.672 +nsIContent * 1.673 +nsGenericDOMDataNode::GetBindingParent() const 1.674 +{ 1.675 + nsDataSlots *slots = GetExistingDataSlots(); 1.676 + return slots ? slots->mBindingParent : nullptr; 1.677 +} 1.678 + 1.679 +ShadowRoot * 1.680 +nsGenericDOMDataNode::GetShadowRoot() const 1.681 +{ 1.682 + return nullptr; 1.683 +} 1.684 + 1.685 +ShadowRoot * 1.686 +nsGenericDOMDataNode::GetContainingShadow() const 1.687 +{ 1.688 + nsDataSlots *slots = GetExistingDataSlots(); 1.689 + return slots ? slots->mContainingShadow : nullptr; 1.690 +} 1.691 + 1.692 +void 1.693 +nsGenericDOMDataNode::SetShadowRoot(ShadowRoot* aShadowRoot) 1.694 +{ 1.695 +} 1.696 + 1.697 +nsXBLBinding * 1.698 +nsGenericDOMDataNode::GetXBLBinding() const 1.699 +{ 1.700 + return nullptr; 1.701 +} 1.702 + 1.703 +void 1.704 +nsGenericDOMDataNode::SetXBLBinding(nsXBLBinding* aBinding, 1.705 + nsBindingManager* aOldBindingManager) 1.706 +{ 1.707 +} 1.708 + 1.709 +nsIContent * 1.710 +nsGenericDOMDataNode::GetXBLInsertionParent() const 1.711 +{ 1.712 + if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) { 1.713 + nsDataSlots *slots = GetExistingDataSlots(); 1.714 + if (slots) { 1.715 + return slots->mXBLInsertionParent; 1.716 + } 1.717 + } 1.718 + 1.719 + return nullptr; 1.720 +} 1.721 + 1.722 +void 1.723 +nsGenericDOMDataNode::SetXBLInsertionParent(nsIContent* aContent) 1.724 +{ 1.725 + nsDataSlots *slots = DataSlots(); 1.726 + if (aContent) { 1.727 + SetFlags(NODE_MAY_BE_IN_BINDING_MNGR); 1.728 + } 1.729 + slots->mXBLInsertionParent = aContent; 1.730 +} 1.731 + 1.732 +CustomElementData * 1.733 +nsGenericDOMDataNode::GetCustomElementData() const 1.734 +{ 1.735 + return nullptr; 1.736 +} 1.737 + 1.738 +void 1.739 +nsGenericDOMDataNode::SetCustomElementData(CustomElementData* aData) 1.740 +{ 1.741 +} 1.742 + 1.743 +bool 1.744 +nsGenericDOMDataNode::IsNodeOfType(uint32_t aFlags) const 1.745 +{ 1.746 + return !(aFlags & ~(eCONTENT | eDATA_NODE)); 1.747 +} 1.748 + 1.749 +void 1.750 +nsGenericDOMDataNode::SaveSubtreeState() 1.751 +{ 1.752 +} 1.753 + 1.754 +void 1.755 +nsGenericDOMDataNode::DestroyContent() 1.756 +{ 1.757 + // XXX We really should let cycle collection do this, but that currently still 1.758 + // leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684). 1.759 + ReleaseWrapper(this); 1.760 +} 1.761 + 1.762 +#ifdef DEBUG 1.763 +void 1.764 +nsGenericDOMDataNode::List(FILE* out, int32_t aIndent) const 1.765 +{ 1.766 +} 1.767 + 1.768 +void 1.769 +nsGenericDOMDataNode::DumpContent(FILE* out, int32_t aIndent, 1.770 + bool aDumpAll) const 1.771 +{ 1.772 +} 1.773 +#endif 1.774 + 1.775 +bool 1.776 +nsGenericDOMDataNode::IsLink(nsIURI** aURI) const 1.777 +{ 1.778 + *aURI = nullptr; 1.779 + return false; 1.780 +} 1.781 + 1.782 +nsINode::nsSlots* 1.783 +nsGenericDOMDataNode::CreateSlots() 1.784 +{ 1.785 + return new nsDataSlots(); 1.786 +} 1.787 + 1.788 +nsGenericDOMDataNode::nsDataSlots::nsDataSlots() 1.789 + : nsINode::nsSlots(), mBindingParent(nullptr) 1.790 +{ 1.791 +} 1.792 + 1.793 +void 1.794 +nsGenericDOMDataNode::nsDataSlots::Traverse(nsCycleCollectionTraversalCallback &cb) 1.795 +{ 1.796 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mXBLInsertionParent"); 1.797 + cb.NoteXPCOMChild(mXBLInsertionParent.get()); 1.798 + 1.799 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mContainingShadow"); 1.800 + cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mContainingShadow)); 1.801 +} 1.802 + 1.803 +void 1.804 +nsGenericDOMDataNode::nsDataSlots::Unlink() 1.805 +{ 1.806 + mXBLInsertionParent = nullptr; 1.807 + mContainingShadow = nullptr; 1.808 +} 1.809 + 1.810 +//---------------------------------------------------------------------- 1.811 + 1.812 +// Implementation of the nsIDOMText interface 1.813 + 1.814 +nsresult 1.815 +nsGenericDOMDataNode::SplitData(uint32_t aOffset, nsIContent** aReturn, 1.816 + bool aCloneAfterOriginal) 1.817 +{ 1.818 + *aReturn = nullptr; 1.819 + nsresult rv = NS_OK; 1.820 + nsAutoString cutText; 1.821 + uint32_t length = TextLength(); 1.822 + 1.823 + if (aOffset > length) { 1.824 + return NS_ERROR_DOM_INDEX_SIZE_ERR; 1.825 + } 1.826 + 1.827 + uint32_t cutStartOffset = aCloneAfterOriginal ? aOffset : 0; 1.828 + uint32_t cutLength = aCloneAfterOriginal ? length - aOffset : aOffset; 1.829 + rv = SubstringData(cutStartOffset, cutLength, cutText); 1.830 + if (NS_FAILED(rv)) { 1.831 + return rv; 1.832 + } 1.833 + 1.834 + nsIDocument* document = GetCurrentDoc(); 1.835 + mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, true); 1.836 + 1.837 + // Use Clone for creating the new node so that the new node is of same class 1.838 + // as this node! 1.839 + nsCOMPtr<nsIContent> newContent = CloneDataNode(mNodeInfo, false); 1.840 + if (!newContent) { 1.841 + return NS_ERROR_OUT_OF_MEMORY; 1.842 + } 1.843 + newContent->SetText(cutText, true); // XXX should be false? 1.844 + 1.845 + CharacterDataChangeInfo::Details details = { 1.846 + CharacterDataChangeInfo::Details::eSplit, newContent 1.847 + }; 1.848 + rv = SetTextInternal(cutStartOffset, cutLength, nullptr, 0, true, 1.849 + aCloneAfterOriginal ? &details : nullptr); 1.850 + if (NS_FAILED(rv)) { 1.851 + return rv; 1.852 + } 1.853 + 1.854 + nsCOMPtr<nsINode> parent = GetParentNode(); 1.855 + if (parent) { 1.856 + int32_t insertionIndex = parent->IndexOf(this); 1.857 + if (aCloneAfterOriginal) { 1.858 + ++insertionIndex; 1.859 + } 1.860 + parent->InsertChildAt(newContent, insertionIndex, true); 1.861 + } 1.862 + 1.863 + newContent.swap(*aReturn); 1.864 + return rv; 1.865 +} 1.866 + 1.867 +nsresult 1.868 +nsGenericDOMDataNode::SplitText(uint32_t aOffset, nsIDOMText** aReturn) 1.869 +{ 1.870 + nsCOMPtr<nsIContent> newChild; 1.871 + nsresult rv = SplitData(aOffset, getter_AddRefs(newChild)); 1.872 + if (NS_SUCCEEDED(rv)) { 1.873 + rv = CallQueryInterface(newChild, aReturn); 1.874 + } 1.875 + return rv; 1.876 +} 1.877 + 1.878 +/* static */ int32_t 1.879 +nsGenericDOMDataNode::FirstLogicallyAdjacentTextNode(nsIContent* aParent, 1.880 + int32_t aIndex) 1.881 +{ 1.882 + while (aIndex-- > 0) { 1.883 + nsIContent* sibling = aParent->GetChildAt(aIndex); 1.884 + if (!sibling->IsNodeOfType(nsINode::eTEXT)) 1.885 + return aIndex + 1; 1.886 + } 1.887 + return 0; 1.888 +} 1.889 + 1.890 +/* static */ int32_t 1.891 +nsGenericDOMDataNode::LastLogicallyAdjacentTextNode(nsIContent* aParent, 1.892 + int32_t aIndex, 1.893 + uint32_t aCount) 1.894 +{ 1.895 + while (++aIndex < int32_t(aCount)) { 1.896 + nsIContent* sibling = aParent->GetChildAt(aIndex); 1.897 + if (!sibling->IsNodeOfType(nsINode::eTEXT)) 1.898 + return aIndex - 1; 1.899 + } 1.900 + return aCount - 1; 1.901 +} 1.902 + 1.903 +nsresult 1.904 +nsGenericDOMDataNode::GetWholeText(nsAString& aWholeText) 1.905 +{ 1.906 + nsIContent* parent = GetParent(); 1.907 + 1.908 + // Handle parent-less nodes 1.909 + if (!parent) 1.910 + return GetData(aWholeText); 1.911 + 1.912 + int32_t index = parent->IndexOf(this); 1.913 + NS_WARN_IF_FALSE(index >= 0, 1.914 + "Trying to use .wholeText with an anonymous" 1.915 + "text node child of a binding parent?"); 1.916 + NS_ENSURE_TRUE(index >= 0, NS_ERROR_DOM_NOT_SUPPORTED_ERR); 1.917 + int32_t first = 1.918 + FirstLogicallyAdjacentTextNode(parent, index); 1.919 + int32_t last = 1.920 + LastLogicallyAdjacentTextNode(parent, index, parent->GetChildCount()); 1.921 + 1.922 + aWholeText.Truncate(); 1.923 + 1.924 + nsCOMPtr<nsIDOMText> node; 1.925 + nsAutoString tmp; 1.926 + do { 1.927 + node = do_QueryInterface(parent->GetChildAt(first)); 1.928 + node->GetData(tmp); 1.929 + aWholeText.Append(tmp); 1.930 + } while (first++ < last); 1.931 + 1.932 + return NS_OK; 1.933 +} 1.934 + 1.935 +//---------------------------------------------------------------------- 1.936 + 1.937 +// Implementation of the nsIContent interface text functions 1.938 + 1.939 +const nsTextFragment * 1.940 +nsGenericDOMDataNode::GetText() 1.941 +{ 1.942 + return &mText; 1.943 +} 1.944 + 1.945 +uint32_t 1.946 +nsGenericDOMDataNode::TextLength() const 1.947 +{ 1.948 + return mText.GetLength(); 1.949 +} 1.950 + 1.951 +nsresult 1.952 +nsGenericDOMDataNode::SetText(const char16_t* aBuffer, 1.953 + uint32_t aLength, 1.954 + bool aNotify) 1.955 +{ 1.956 + return SetTextInternal(0, mText.GetLength(), aBuffer, aLength, aNotify); 1.957 +} 1.958 + 1.959 +nsresult 1.960 +nsGenericDOMDataNode::AppendText(const char16_t* aBuffer, 1.961 + uint32_t aLength, 1.962 + bool aNotify) 1.963 +{ 1.964 + return SetTextInternal(mText.GetLength(), 0, aBuffer, aLength, aNotify); 1.965 +} 1.966 + 1.967 +bool 1.968 +nsGenericDOMDataNode::TextIsOnlyWhitespace() 1.969 +{ 1.970 + // FIXME: should this method take content language into account? 1.971 + if (mText.Is2b()) { 1.972 + // The fragment contains non-8bit characters and such characters 1.973 + // are never considered whitespace. 1.974 + return false; 1.975 + } 1.976 + 1.977 + if (HasFlag(NS_CACHED_TEXT_IS_ONLY_WHITESPACE)) { 1.978 + return HasFlag(NS_TEXT_IS_ONLY_WHITESPACE); 1.979 + } 1.980 + 1.981 + const char* cp = mText.Get1b(); 1.982 + const char* end = cp + mText.GetLength(); 1.983 + 1.984 + while (cp < end) { 1.985 + char ch = *cp; 1.986 + 1.987 + if (!dom::IsSpaceCharacter(ch)) { 1.988 + UnsetFlags(NS_TEXT_IS_ONLY_WHITESPACE); 1.989 + SetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE); 1.990 + return false; 1.991 + } 1.992 + 1.993 + ++cp; 1.994 + } 1.995 + 1.996 + SetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE | NS_TEXT_IS_ONLY_WHITESPACE); 1.997 + return true; 1.998 +} 1.999 + 1.1000 +bool 1.1001 +nsGenericDOMDataNode::HasTextForTranslation() 1.1002 +{ 1.1003 + if (mText.Is2b()) { 1.1004 + // The fragment contains non-8bit characters which means there 1.1005 + // was at least one "interesting" character to trigger non-8bit. 1.1006 + return true; 1.1007 + } 1.1008 + 1.1009 + if (HasFlag(NS_CACHED_TEXT_IS_ONLY_WHITESPACE) && 1.1010 + HasFlag(NS_TEXT_IS_ONLY_WHITESPACE)) { 1.1011 + return false; 1.1012 + } 1.1013 + 1.1014 + const char* cp = mText.Get1b(); 1.1015 + const char* end = cp + mText.GetLength(); 1.1016 + 1.1017 + unsigned char ch; 1.1018 + for (; cp < end; cp++) { 1.1019 + ch = *cp; 1.1020 + 1.1021 + // These are the characters that are letters 1.1022 + // in the first 256 UTF-8 codepoints. 1.1023 + if ((ch >= 'a' && ch <= 'z') || 1.1024 + (ch >= 'A' && ch <= 'Z') || 1.1025 + (ch >= 192 && ch <= 214) || 1.1026 + (ch >= 216 && ch <= 246) || 1.1027 + (ch >= 248)) { 1.1028 + return true; 1.1029 + } 1.1030 + } 1.1031 + 1.1032 + return false; 1.1033 +} 1.1034 + 1.1035 +void 1.1036 +nsGenericDOMDataNode::AppendTextTo(nsAString& aResult) 1.1037 +{ 1.1038 + mText.AppendTo(aResult); 1.1039 +} 1.1040 + 1.1041 +bool 1.1042 +nsGenericDOMDataNode::AppendTextTo(nsAString& aResult, const mozilla::fallible_t&) 1.1043 +{ 1.1044 + return mText.AppendTo(aResult, mozilla::fallible_t()); 1.1045 +} 1.1046 + 1.1047 +already_AddRefed<nsIAtom> 1.1048 +nsGenericDOMDataNode::GetCurrentValueAtom() 1.1049 +{ 1.1050 + nsAutoString val; 1.1051 + GetData(val); 1.1052 + return NS_NewAtom(val); 1.1053 +} 1.1054 + 1.1055 +nsIAtom* 1.1056 +nsGenericDOMDataNode::DoGetID() const 1.1057 +{ 1.1058 + return nullptr; 1.1059 +} 1.1060 + 1.1061 +const nsAttrValue* 1.1062 +nsGenericDOMDataNode::DoGetClasses() const 1.1063 +{ 1.1064 + NS_NOTREACHED("Shouldn't ever be called"); 1.1065 + return nullptr; 1.1066 +} 1.1067 + 1.1068 +NS_IMETHODIMP 1.1069 +nsGenericDOMDataNode::WalkContentStyleRules(nsRuleWalker* aRuleWalker) 1.1070 +{ 1.1071 + return NS_OK; 1.1072 +} 1.1073 + 1.1074 +NS_IMETHODIMP_(bool) 1.1075 +nsGenericDOMDataNode::IsAttributeMapped(const nsIAtom* aAttribute) const 1.1076 +{ 1.1077 + return false; 1.1078 +} 1.1079 + 1.1080 +nsChangeHint 1.1081 +nsGenericDOMDataNode::GetAttributeChangeHint(const nsIAtom* aAttribute, 1.1082 + int32_t aModType) const 1.1083 +{ 1.1084 + NS_NOTREACHED("Shouldn't be calling this!"); 1.1085 + return nsChangeHint(0); 1.1086 +} 1.1087 + 1.1088 +nsIAtom* 1.1089 +nsGenericDOMDataNode::GetClassAttributeName() const 1.1090 +{ 1.1091 + return nullptr; 1.1092 +} 1.1093 + 1.1094 +size_t 1.1095 +nsGenericDOMDataNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const 1.1096 +{ 1.1097 + size_t n = nsIContent::SizeOfExcludingThis(aMallocSizeOf); 1.1098 + n += mText.SizeOfExcludingThis(aMallocSizeOf); 1.1099 + return n; 1.1100 +} 1.1101 +