Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /*
7 * Base class for DOM Core's nsIDOMComment, nsIDOMDocumentType, nsIDOMText,
8 * nsIDOMCDATASection, and nsIDOMProcessingInstruction nodes.
9 */
11 #include "mozilla/DebugOnly.h"
13 #include "nsGenericDOMDataNode.h"
14 #include "mozilla/AsyncEventDispatcher.h"
15 #include "mozilla/MemoryReporting.h"
16 #include "mozilla/dom/Element.h"
17 #include "mozilla/dom/ShadowRoot.h"
18 #include "nsIDocument.h"
19 #include "nsIDOMDocument.h"
20 #include "nsReadableUtils.h"
21 #include "mozilla/InternalMutationEvent.h"
22 #include "nsIURI.h"
23 #include "nsIDOMEvent.h"
24 #include "nsIDOMText.h"
25 #include "nsCOMPtr.h"
26 #include "nsDOMString.h"
27 #include "nsIDOMUserDataHandler.h"
28 #include "nsChangeHint.h"
29 #include "nsCOMArray.h"
30 #include "nsNodeUtils.h"
31 #include "mozilla/dom/DirectionalityUtils.h"
32 #include "nsBindingManager.h"
33 #include "nsCCUncollectableMarker.h"
34 #include "mozAutoDocUpdate.h"
36 #include "pldhash.h"
37 #include "prprf.h"
38 #include "nsWrapperCacheInlines.h"
40 using namespace mozilla;
41 using namespace mozilla::dom;
43 nsGenericDOMDataNode::nsGenericDOMDataNode(already_AddRefed<nsINodeInfo>& aNodeInfo)
44 : nsIContent(aNodeInfo)
45 {
46 NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::TEXT_NODE ||
47 mNodeInfo->NodeType() == nsIDOMNode::CDATA_SECTION_NODE ||
48 mNodeInfo->NodeType() == nsIDOMNode::COMMENT_NODE ||
49 mNodeInfo->NodeType() ==
50 nsIDOMNode::PROCESSING_INSTRUCTION_NODE ||
51 mNodeInfo->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE,
52 "Bad NodeType in aNodeInfo");
53 }
55 nsGenericDOMDataNode::nsGenericDOMDataNode(already_AddRefed<nsINodeInfo>&& aNodeInfo)
56 : nsIContent(aNodeInfo)
57 {
58 NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::TEXT_NODE ||
59 mNodeInfo->NodeType() == nsIDOMNode::CDATA_SECTION_NODE ||
60 mNodeInfo->NodeType() == nsIDOMNode::COMMENT_NODE ||
61 mNodeInfo->NodeType() ==
62 nsIDOMNode::PROCESSING_INSTRUCTION_NODE ||
63 mNodeInfo->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE,
64 "Bad NodeType in aNodeInfo");
65 }
67 nsGenericDOMDataNode::~nsGenericDOMDataNode()
68 {
69 NS_PRECONDITION(!IsInDoc(),
70 "Please remove this from the document properly");
71 if (GetParent()) {
72 NS_RELEASE(mParent);
73 }
74 }
76 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericDOMDataNode)
78 NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsGenericDOMDataNode)
80 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGenericDOMDataNode)
81 return Element::CanSkip(tmp, aRemovingAllowed);
82 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
84 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGenericDOMDataNode)
85 return Element::CanSkipInCC(tmp);
86 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
88 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGenericDOMDataNode)
89 return Element::CanSkipThis(tmp);
90 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
92 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGenericDOMDataNode)
93 // Always need to traverse script objects, so do that before we check
94 // if we're uncollectable.
95 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
97 if (!nsINode::Traverse(tmp, cb)) {
98 return NS_SUCCESS_INTERRUPTED_TRAVERSE;
99 }
101 nsDataSlots *slots = tmp->GetExistingDataSlots();
102 if (slots) {
103 slots->Traverse(cb);
104 }
106 tmp->OwnerDoc()->BindingManager()->Traverse(tmp, cb);
107 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
109 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericDOMDataNode)
110 nsINode::Unlink(tmp);
112 nsDataSlots *slots = tmp->GetExistingDataSlots();
113 if (slots) {
114 slots->Unlink();
115 }
116 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
118 NS_INTERFACE_MAP_BEGIN(nsGenericDOMDataNode)
119 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
120 NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsGenericDOMDataNode)
121 NS_INTERFACE_MAP_ENTRY(nsIContent)
122 NS_INTERFACE_MAP_ENTRY(nsINode)
123 NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
124 NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
125 NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
126 new nsNodeSupportsWeakRefTearoff(this))
127 NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMXPathNSResolver,
128 new nsNode3Tearoff(this))
129 // DOM bindings depend on the identity pointer being the
130 // same as nsINode (which nsIContent inherits).
131 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
132 NS_INTERFACE_MAP_END
134 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGenericDOMDataNode)
135 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsGenericDOMDataNode,
136 nsNodeUtils::LastRelease(this))
139 void
140 nsGenericDOMDataNode::GetNodeValueInternal(nsAString& aNodeValue)
141 {
142 DebugOnly<nsresult> rv = GetData(aNodeValue);
143 NS_ASSERTION(NS_SUCCEEDED(rv), "GetData() failed!");
144 }
146 void
147 nsGenericDOMDataNode::SetNodeValueInternal(const nsAString& aNodeValue,
148 ErrorResult& aError)
149 {
150 aError = SetTextInternal(0, mText.GetLength(), aNodeValue.BeginReading(),
151 aNodeValue.Length(), true);
152 }
154 //----------------------------------------------------------------------
156 // Implementation of nsIDOMCharacterData
158 nsresult
159 nsGenericDOMDataNode::GetData(nsAString& aData) const
160 {
161 if (mText.Is2b()) {
162 aData.Assign(mText.Get2b(), mText.GetLength());
163 } else {
164 // Must use Substring() since nsDependentCString() requires null
165 // terminated strings.
167 const char *data = mText.Get1b();
169 if (data) {
170 CopyASCIItoUTF16(Substring(data, data + mText.GetLength()), aData);
171 } else {
172 aData.Truncate();
173 }
174 }
176 return NS_OK;
177 }
179 nsresult
180 nsGenericDOMDataNode::SetData(const nsAString& aData)
181 {
182 return SetTextInternal(0, mText.GetLength(), aData.BeginReading(),
183 aData.Length(), true);
184 }
186 nsresult
187 nsGenericDOMDataNode::GetLength(uint32_t* aLength)
188 {
189 *aLength = mText.GetLength();
190 return NS_OK;
191 }
193 nsresult
194 nsGenericDOMDataNode::SubstringData(uint32_t aStart, uint32_t aCount,
195 nsAString& aReturn)
196 {
197 ErrorResult rv;
198 SubstringData(aStart, aCount, aReturn, rv);
199 return rv.ErrorCode();
200 }
202 void
203 nsGenericDOMDataNode::SubstringData(uint32_t aStart, uint32_t aCount,
204 nsAString& aReturn, ErrorResult& rv)
205 {
206 aReturn.Truncate();
208 uint32_t textLength = mText.GetLength();
209 if (aStart > textLength) {
210 rv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
211 return;
212 }
214 uint32_t amount = aCount;
215 if (amount > textLength - aStart) {
216 amount = textLength - aStart;
217 }
219 if (mText.Is2b()) {
220 aReturn.Assign(mText.Get2b() + aStart, amount);
221 } else {
222 // Must use Substring() since nsDependentCString() requires null
223 // terminated strings.
225 const char *data = mText.Get1b() + aStart;
226 CopyASCIItoUTF16(Substring(data, data + amount), aReturn);
227 }
228 }
230 NS_IMETHODIMP
231 nsGenericDOMDataNode::MozRemove()
232 {
233 Remove();
234 return NS_OK;
235 }
237 //----------------------------------------------------------------------
239 nsresult
240 nsGenericDOMDataNode::AppendData(const nsAString& aData)
241 {
242 return SetTextInternal(mText.GetLength(), 0, aData.BeginReading(),
243 aData.Length(), true);
244 }
246 nsresult
247 nsGenericDOMDataNode::InsertData(uint32_t aOffset,
248 const nsAString& aData)
249 {
250 return SetTextInternal(aOffset, 0, aData.BeginReading(),
251 aData.Length(), true);
252 }
254 nsresult
255 nsGenericDOMDataNode::DeleteData(uint32_t aOffset, uint32_t aCount)
256 {
257 return SetTextInternal(aOffset, aCount, nullptr, 0, true);
258 }
260 nsresult
261 nsGenericDOMDataNode::ReplaceData(uint32_t aOffset, uint32_t aCount,
262 const nsAString& aData)
263 {
264 return SetTextInternal(aOffset, aCount, aData.BeginReading(),
265 aData.Length(), true);
266 }
268 nsresult
269 nsGenericDOMDataNode::SetTextInternal(uint32_t aOffset, uint32_t aCount,
270 const char16_t* aBuffer,
271 uint32_t aLength, bool aNotify,
272 CharacterDataChangeInfo::Details* aDetails)
273 {
274 NS_PRECONDITION(aBuffer || !aLength,
275 "Null buffer passed to SetTextInternal!");
277 // sanitize arguments
278 uint32_t textLength = mText.GetLength();
279 if (aOffset > textLength) {
280 return NS_ERROR_DOM_INDEX_SIZE_ERR;
281 }
283 if (aCount > textLength - aOffset) {
284 aCount = textLength - aOffset;
285 }
287 uint32_t endOffset = aOffset + aCount;
289 // Make sure the text fragment can hold the new data.
290 if (aLength > aCount && !mText.CanGrowBy(aLength - aCount)) {
291 return NS_ERROR_OUT_OF_MEMORY;
292 }
294 nsIDocument *document = GetCurrentDoc();
295 mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
297 bool haveMutationListeners = aNotify &&
298 nsContentUtils::HasMutationListeners(this,
299 NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED,
300 this);
302 nsCOMPtr<nsIAtom> oldValue;
303 if (haveMutationListeners) {
304 oldValue = GetCurrentValueAtom();
305 }
307 if (aNotify) {
308 CharacterDataChangeInfo info = {
309 aOffset == textLength,
310 aOffset,
311 endOffset,
312 aLength,
313 aDetails
314 };
315 nsNodeUtils::CharacterDataWillChange(this, &info);
316 }
318 Directionality oldDir = eDir_NotSet;
319 bool dirAffectsAncestor = (NodeType() == nsIDOMNode::TEXT_NODE &&
320 TextNodeWillChangeDirection(this, &oldDir, aOffset));
322 if (aOffset == 0 && endOffset == textLength) {
323 // Replacing whole text or old text was empty. Don't bother to check for
324 // bidi in this string if the document already has bidi enabled.
325 bool ok = mText.SetTo(aBuffer, aLength, !document || !document->GetBidiEnabled());
326 NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
327 }
328 else if (aOffset == textLength) {
329 // Appending to existing
330 bool ok = mText.Append(aBuffer, aLength, !document || !document->GetBidiEnabled());
331 NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
332 }
333 else {
334 // Merging old and new
336 // Allocate new buffer
337 int32_t newLength = textLength - aCount + aLength;
338 char16_t* to = new char16_t[newLength];
339 NS_ENSURE_TRUE(to, NS_ERROR_OUT_OF_MEMORY);
341 // Copy over appropriate data
342 if (aOffset) {
343 mText.CopyTo(to, 0, aOffset);
344 }
345 if (aLength) {
346 memcpy(to + aOffset, aBuffer, aLength * sizeof(char16_t));
347 }
348 if (endOffset != textLength) {
349 mText.CopyTo(to + aOffset + aLength, endOffset, textLength - endOffset);
350 }
352 bool ok = mText.SetTo(to, newLength, !document || !document->GetBidiEnabled());
354 delete [] to;
356 NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
357 }
359 UnsetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE);
361 if (document && mText.IsBidi()) {
362 // If we found bidi characters in mText.SetTo() above, indicate that the
363 // document contains bidi characters.
364 document->SetBidiEnabled();
365 }
367 if (dirAffectsAncestor) {
368 TextNodeChangedDirection(this, oldDir, aNotify);
369 }
371 // Notify observers
372 if (aNotify) {
373 CharacterDataChangeInfo info = {
374 aOffset == textLength,
375 aOffset,
376 endOffset,
377 aLength,
378 aDetails
379 };
380 nsNodeUtils::CharacterDataChanged(this, &info);
382 if (haveMutationListeners) {
383 InternalMutationEvent mutation(true, NS_MUTATION_CHARACTERDATAMODIFIED);
385 mutation.mPrevAttrValue = oldValue;
386 if (aLength > 0) {
387 nsAutoString val;
388 mText.AppendTo(val);
389 mutation.mNewAttrValue = do_GetAtom(val);
390 }
392 mozAutoSubtreeModified subtree(OwnerDoc(), this);
393 (new AsyncEventDispatcher(this, mutation))->RunDOMEventWhenSafe();
394 }
395 }
397 return NS_OK;
398 }
400 //----------------------------------------------------------------------
402 // Implementation of nsIContent
404 #ifdef DEBUG
405 void
406 nsGenericDOMDataNode::ToCString(nsAString& aBuf, int32_t aOffset,
407 int32_t aLen) const
408 {
409 if (mText.Is2b()) {
410 const char16_t* cp = mText.Get2b() + aOffset;
411 const char16_t* end = cp + aLen;
413 while (cp < end) {
414 char16_t ch = *cp++;
415 if (ch == '&') {
416 aBuf.AppendLiteral("&");
417 } else if (ch == '<') {
418 aBuf.AppendLiteral("<");
419 } else if (ch == '>') {
420 aBuf.AppendLiteral(">");
421 } else if ((ch < ' ') || (ch >= 127)) {
422 char buf[10];
423 PR_snprintf(buf, sizeof(buf), "\\u%04x", ch);
424 AppendASCIItoUTF16(buf, aBuf);
425 } else {
426 aBuf.Append(ch);
427 }
428 }
429 } else {
430 unsigned char* cp = (unsigned char*)mText.Get1b() + aOffset;
431 const unsigned char* end = cp + aLen;
433 while (cp < end) {
434 char16_t ch = *cp++;
435 if (ch == '&') {
436 aBuf.AppendLiteral("&");
437 } else if (ch == '<') {
438 aBuf.AppendLiteral("<");
439 } else if (ch == '>') {
440 aBuf.AppendLiteral(">");
441 } else if ((ch < ' ') || (ch >= 127)) {
442 char buf[10];
443 PR_snprintf(buf, sizeof(buf), "\\u%04x", ch);
444 AppendASCIItoUTF16(buf, aBuf);
445 } else {
446 aBuf.Append(ch);
447 }
448 }
449 }
450 }
451 #endif
454 nsresult
455 nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
456 nsIContent* aBindingParent,
457 bool aCompileEventHandlers)
458 {
459 NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
460 NS_PRECONDITION(NODE_FROM(aParent, aDocument)->OwnerDoc() == OwnerDoc(),
461 "Must have the same owner document");
462 NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(),
463 "aDocument must be current doc of aParent");
464 NS_PRECONDITION(!GetCurrentDoc() && !IsInDoc(),
465 "Already have a document. Unbind first!");
466 // Note that as we recurse into the kids, they'll have a non-null parent. So
467 // only assert if our parent is _changing_ while we have a parent.
468 NS_PRECONDITION(!GetParent() || aParent == GetParent(),
469 "Already have a parent. Unbind first!");
470 NS_PRECONDITION(!GetBindingParent() ||
471 aBindingParent == GetBindingParent() ||
472 (!aBindingParent && aParent &&
473 aParent->GetBindingParent() == GetBindingParent()),
474 "Already have a binding parent. Unbind first!");
475 NS_PRECONDITION(aBindingParent != this,
476 "Content must not be its own binding parent");
477 NS_PRECONDITION(!IsRootOfNativeAnonymousSubtree() ||
478 aBindingParent == aParent,
479 "Native anonymous content must have its parent as its "
480 "own binding parent");
482 if (!aBindingParent && aParent) {
483 aBindingParent = aParent->GetBindingParent();
484 }
486 // First set the binding parent
487 if (aBindingParent) {
488 NS_ASSERTION(IsRootOfNativeAnonymousSubtree() ||
489 !HasFlag(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE) ||
490 (aParent && aParent->IsInNativeAnonymousSubtree()),
491 "Trying to re-bind content from native anonymous subtree to "
492 "non-native anonymous parent!");
493 DataSlots()->mBindingParent = aBindingParent; // Weak, so no addref happens.
494 if (aParent->IsInNativeAnonymousSubtree()) {
495 SetFlags(NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE);
496 }
497 if (aParent->HasFlag(NODE_CHROME_ONLY_ACCESS)) {
498 SetFlags(NODE_CHROME_ONLY_ACCESS);
499 }
500 if (aParent->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
501 SetFlags(NODE_IS_IN_SHADOW_TREE);
502 }
503 ShadowRoot* parentContainingShadow = aParent->GetContainingShadow();
504 if (parentContainingShadow) {
505 DataSlots()->mContainingShadow = parentContainingShadow;
506 }
507 }
509 // Set parent
510 if (aParent) {
511 if (!GetParent()) {
512 NS_ADDREF(aParent);
513 }
514 mParent = aParent;
515 }
516 else {
517 mParent = aDocument;
518 }
519 SetParentIsContent(aParent);
521 // XXXbz sXBL/XBL2 issue!
523 // Set document
524 if (aDocument) {
525 // We no longer need to track the subtree pointer (and in fact we'll assert
526 // if we do this any later).
527 ClearSubtreeRootPointer();
529 // XXX See the comment in Element::BindToTree
530 SetInDocument();
531 if (mText.IsBidi()) {
532 aDocument->SetBidiEnabled();
533 }
534 // Clear the lazy frame construction bits.
535 UnsetFlags(NODE_NEEDS_FRAME | NODE_DESCENDANTS_NEED_FRAMES);
536 } else {
537 // If we're not in the doc, update our subtree pointer.
538 SetSubtreeRootPointer(aParent->SubtreeRoot());
539 }
541 nsNodeUtils::ParentChainChanged(this);
543 UpdateEditableState(false);
545 NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document");
546 NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
547 NS_POSTCONDITION(aBindingParent == GetBindingParent(),
548 "Bound to wrong binding parent");
550 return NS_OK;
551 }
553 void
554 nsGenericDOMDataNode::UnbindFromTree(bool aDeep, bool aNullParent)
555 {
556 // Unset frame flags; if we need them again later, they'll get set again.
557 UnsetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE |
558 NS_REFRAME_IF_WHITESPACE |
559 // Also unset the shadow tree flag because it can
560 // no longer be a descendant of a ShadowRoot.
561 NODE_IS_IN_SHADOW_TREE);
563 nsIDocument *document = GetCurrentDoc();
564 if (document) {
565 // Notify XBL- & nsIAnonymousContentCreator-generated
566 // anonymous content that the document is changing.
567 // This is needed to update the insertion point.
568 document->BindingManager()->RemovedFromDocument(this, document);
569 }
571 if (aNullParent) {
572 if (GetParent()) {
573 NS_RELEASE(mParent);
574 } else {
575 mParent = nullptr;
576 }
577 SetParentIsContent(false);
578 }
579 ClearInDocument();
581 // Begin keeping track of our subtree root.
582 SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot());
584 nsDataSlots *slots = GetExistingDataSlots();
585 if (slots) {
586 slots->mBindingParent = nullptr;
587 slots->mContainingShadow = nullptr;
588 }
590 nsNodeUtils::ParentChainChanged(this);
591 }
593 already_AddRefed<nsINodeList>
594 nsGenericDOMDataNode::GetChildren(uint32_t aFilter)
595 {
596 return nullptr;
597 }
599 nsIAtom *
600 nsGenericDOMDataNode::GetIDAttributeName() const
601 {
602 return nullptr;
603 }
605 nsresult
606 nsGenericDOMDataNode::SetAttr(int32_t aNameSpaceID, nsIAtom* aAttr,
607 nsIAtom* aPrefix, const nsAString& aValue,
608 bool aNotify)
609 {
610 return NS_OK;
611 }
613 nsresult
614 nsGenericDOMDataNode::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttr,
615 bool aNotify)
616 {
617 return NS_OK;
618 }
620 const nsAttrName*
621 nsGenericDOMDataNode::GetAttrNameAt(uint32_t aIndex) const
622 {
623 return nullptr;
624 }
626 uint32_t
627 nsGenericDOMDataNode::GetAttrCount() const
628 {
629 return 0;
630 }
632 uint32_t
633 nsGenericDOMDataNode::GetChildCount() const
634 {
635 return 0;
636 }
638 nsIContent *
639 nsGenericDOMDataNode::GetChildAt(uint32_t aIndex) const
640 {
641 return nullptr;
642 }
644 nsIContent * const *
645 nsGenericDOMDataNode::GetChildArray(uint32_t* aChildCount) const
646 {
647 *aChildCount = 0;
648 return nullptr;
649 }
651 int32_t
652 nsGenericDOMDataNode::IndexOf(const nsINode* aPossibleChild) const
653 {
654 return -1;
655 }
657 nsresult
658 nsGenericDOMDataNode::InsertChildAt(nsIContent* aKid, uint32_t aIndex,
659 bool aNotify)
660 {
661 return NS_OK;
662 }
664 void
665 nsGenericDOMDataNode::RemoveChildAt(uint32_t aIndex, bool aNotify)
666 {
667 }
669 nsIContent *
670 nsGenericDOMDataNode::GetBindingParent() const
671 {
672 nsDataSlots *slots = GetExistingDataSlots();
673 return slots ? slots->mBindingParent : nullptr;
674 }
676 ShadowRoot *
677 nsGenericDOMDataNode::GetShadowRoot() const
678 {
679 return nullptr;
680 }
682 ShadowRoot *
683 nsGenericDOMDataNode::GetContainingShadow() const
684 {
685 nsDataSlots *slots = GetExistingDataSlots();
686 return slots ? slots->mContainingShadow : nullptr;
687 }
689 void
690 nsGenericDOMDataNode::SetShadowRoot(ShadowRoot* aShadowRoot)
691 {
692 }
694 nsXBLBinding *
695 nsGenericDOMDataNode::GetXBLBinding() const
696 {
697 return nullptr;
698 }
700 void
701 nsGenericDOMDataNode::SetXBLBinding(nsXBLBinding* aBinding,
702 nsBindingManager* aOldBindingManager)
703 {
704 }
706 nsIContent *
707 nsGenericDOMDataNode::GetXBLInsertionParent() const
708 {
709 if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
710 nsDataSlots *slots = GetExistingDataSlots();
711 if (slots) {
712 return slots->mXBLInsertionParent;
713 }
714 }
716 return nullptr;
717 }
719 void
720 nsGenericDOMDataNode::SetXBLInsertionParent(nsIContent* aContent)
721 {
722 nsDataSlots *slots = DataSlots();
723 if (aContent) {
724 SetFlags(NODE_MAY_BE_IN_BINDING_MNGR);
725 }
726 slots->mXBLInsertionParent = aContent;
727 }
729 CustomElementData *
730 nsGenericDOMDataNode::GetCustomElementData() const
731 {
732 return nullptr;
733 }
735 void
736 nsGenericDOMDataNode::SetCustomElementData(CustomElementData* aData)
737 {
738 }
740 bool
741 nsGenericDOMDataNode::IsNodeOfType(uint32_t aFlags) const
742 {
743 return !(aFlags & ~(eCONTENT | eDATA_NODE));
744 }
746 void
747 nsGenericDOMDataNode::SaveSubtreeState()
748 {
749 }
751 void
752 nsGenericDOMDataNode::DestroyContent()
753 {
754 // XXX We really should let cycle collection do this, but that currently still
755 // leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684).
756 ReleaseWrapper(this);
757 }
759 #ifdef DEBUG
760 void
761 nsGenericDOMDataNode::List(FILE* out, int32_t aIndent) const
762 {
763 }
765 void
766 nsGenericDOMDataNode::DumpContent(FILE* out, int32_t aIndent,
767 bool aDumpAll) const
768 {
769 }
770 #endif
772 bool
773 nsGenericDOMDataNode::IsLink(nsIURI** aURI) const
774 {
775 *aURI = nullptr;
776 return false;
777 }
779 nsINode::nsSlots*
780 nsGenericDOMDataNode::CreateSlots()
781 {
782 return new nsDataSlots();
783 }
785 nsGenericDOMDataNode::nsDataSlots::nsDataSlots()
786 : nsINode::nsSlots(), mBindingParent(nullptr)
787 {
788 }
790 void
791 nsGenericDOMDataNode::nsDataSlots::Traverse(nsCycleCollectionTraversalCallback &cb)
792 {
793 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mXBLInsertionParent");
794 cb.NoteXPCOMChild(mXBLInsertionParent.get());
796 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mSlots->mContainingShadow");
797 cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIContent*, mContainingShadow));
798 }
800 void
801 nsGenericDOMDataNode::nsDataSlots::Unlink()
802 {
803 mXBLInsertionParent = nullptr;
804 mContainingShadow = nullptr;
805 }
807 //----------------------------------------------------------------------
809 // Implementation of the nsIDOMText interface
811 nsresult
812 nsGenericDOMDataNode::SplitData(uint32_t aOffset, nsIContent** aReturn,
813 bool aCloneAfterOriginal)
814 {
815 *aReturn = nullptr;
816 nsresult rv = NS_OK;
817 nsAutoString cutText;
818 uint32_t length = TextLength();
820 if (aOffset > length) {
821 return NS_ERROR_DOM_INDEX_SIZE_ERR;
822 }
824 uint32_t cutStartOffset = aCloneAfterOriginal ? aOffset : 0;
825 uint32_t cutLength = aCloneAfterOriginal ? length - aOffset : aOffset;
826 rv = SubstringData(cutStartOffset, cutLength, cutText);
827 if (NS_FAILED(rv)) {
828 return rv;
829 }
831 nsIDocument* document = GetCurrentDoc();
832 mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, true);
834 // Use Clone for creating the new node so that the new node is of same class
835 // as this node!
836 nsCOMPtr<nsIContent> newContent = CloneDataNode(mNodeInfo, false);
837 if (!newContent) {
838 return NS_ERROR_OUT_OF_MEMORY;
839 }
840 newContent->SetText(cutText, true); // XXX should be false?
842 CharacterDataChangeInfo::Details details = {
843 CharacterDataChangeInfo::Details::eSplit, newContent
844 };
845 rv = SetTextInternal(cutStartOffset, cutLength, nullptr, 0, true,
846 aCloneAfterOriginal ? &details : nullptr);
847 if (NS_FAILED(rv)) {
848 return rv;
849 }
851 nsCOMPtr<nsINode> parent = GetParentNode();
852 if (parent) {
853 int32_t insertionIndex = parent->IndexOf(this);
854 if (aCloneAfterOriginal) {
855 ++insertionIndex;
856 }
857 parent->InsertChildAt(newContent, insertionIndex, true);
858 }
860 newContent.swap(*aReturn);
861 return rv;
862 }
864 nsresult
865 nsGenericDOMDataNode::SplitText(uint32_t aOffset, nsIDOMText** aReturn)
866 {
867 nsCOMPtr<nsIContent> newChild;
868 nsresult rv = SplitData(aOffset, getter_AddRefs(newChild));
869 if (NS_SUCCEEDED(rv)) {
870 rv = CallQueryInterface(newChild, aReturn);
871 }
872 return rv;
873 }
875 /* static */ int32_t
876 nsGenericDOMDataNode::FirstLogicallyAdjacentTextNode(nsIContent* aParent,
877 int32_t aIndex)
878 {
879 while (aIndex-- > 0) {
880 nsIContent* sibling = aParent->GetChildAt(aIndex);
881 if (!sibling->IsNodeOfType(nsINode::eTEXT))
882 return aIndex + 1;
883 }
884 return 0;
885 }
887 /* static */ int32_t
888 nsGenericDOMDataNode::LastLogicallyAdjacentTextNode(nsIContent* aParent,
889 int32_t aIndex,
890 uint32_t aCount)
891 {
892 while (++aIndex < int32_t(aCount)) {
893 nsIContent* sibling = aParent->GetChildAt(aIndex);
894 if (!sibling->IsNodeOfType(nsINode::eTEXT))
895 return aIndex - 1;
896 }
897 return aCount - 1;
898 }
900 nsresult
901 nsGenericDOMDataNode::GetWholeText(nsAString& aWholeText)
902 {
903 nsIContent* parent = GetParent();
905 // Handle parent-less nodes
906 if (!parent)
907 return GetData(aWholeText);
909 int32_t index = parent->IndexOf(this);
910 NS_WARN_IF_FALSE(index >= 0,
911 "Trying to use .wholeText with an anonymous"
912 "text node child of a binding parent?");
913 NS_ENSURE_TRUE(index >= 0, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
914 int32_t first =
915 FirstLogicallyAdjacentTextNode(parent, index);
916 int32_t last =
917 LastLogicallyAdjacentTextNode(parent, index, parent->GetChildCount());
919 aWholeText.Truncate();
921 nsCOMPtr<nsIDOMText> node;
922 nsAutoString tmp;
923 do {
924 node = do_QueryInterface(parent->GetChildAt(first));
925 node->GetData(tmp);
926 aWholeText.Append(tmp);
927 } while (first++ < last);
929 return NS_OK;
930 }
932 //----------------------------------------------------------------------
934 // Implementation of the nsIContent interface text functions
936 const nsTextFragment *
937 nsGenericDOMDataNode::GetText()
938 {
939 return &mText;
940 }
942 uint32_t
943 nsGenericDOMDataNode::TextLength() const
944 {
945 return mText.GetLength();
946 }
948 nsresult
949 nsGenericDOMDataNode::SetText(const char16_t* aBuffer,
950 uint32_t aLength,
951 bool aNotify)
952 {
953 return SetTextInternal(0, mText.GetLength(), aBuffer, aLength, aNotify);
954 }
956 nsresult
957 nsGenericDOMDataNode::AppendText(const char16_t* aBuffer,
958 uint32_t aLength,
959 bool aNotify)
960 {
961 return SetTextInternal(mText.GetLength(), 0, aBuffer, aLength, aNotify);
962 }
964 bool
965 nsGenericDOMDataNode::TextIsOnlyWhitespace()
966 {
967 // FIXME: should this method take content language into account?
968 if (mText.Is2b()) {
969 // The fragment contains non-8bit characters and such characters
970 // are never considered whitespace.
971 return false;
972 }
974 if (HasFlag(NS_CACHED_TEXT_IS_ONLY_WHITESPACE)) {
975 return HasFlag(NS_TEXT_IS_ONLY_WHITESPACE);
976 }
978 const char* cp = mText.Get1b();
979 const char* end = cp + mText.GetLength();
981 while (cp < end) {
982 char ch = *cp;
984 if (!dom::IsSpaceCharacter(ch)) {
985 UnsetFlags(NS_TEXT_IS_ONLY_WHITESPACE);
986 SetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE);
987 return false;
988 }
990 ++cp;
991 }
993 SetFlags(NS_CACHED_TEXT_IS_ONLY_WHITESPACE | NS_TEXT_IS_ONLY_WHITESPACE);
994 return true;
995 }
997 bool
998 nsGenericDOMDataNode::HasTextForTranslation()
999 {
1000 if (mText.Is2b()) {
1001 // The fragment contains non-8bit characters which means there
1002 // was at least one "interesting" character to trigger non-8bit.
1003 return true;
1004 }
1006 if (HasFlag(NS_CACHED_TEXT_IS_ONLY_WHITESPACE) &&
1007 HasFlag(NS_TEXT_IS_ONLY_WHITESPACE)) {
1008 return false;
1009 }
1011 const char* cp = mText.Get1b();
1012 const char* end = cp + mText.GetLength();
1014 unsigned char ch;
1015 for (; cp < end; cp++) {
1016 ch = *cp;
1018 // These are the characters that are letters
1019 // in the first 256 UTF-8 codepoints.
1020 if ((ch >= 'a' && ch <= 'z') ||
1021 (ch >= 'A' && ch <= 'Z') ||
1022 (ch >= 192 && ch <= 214) ||
1023 (ch >= 216 && ch <= 246) ||
1024 (ch >= 248)) {
1025 return true;
1026 }
1027 }
1029 return false;
1030 }
1032 void
1033 nsGenericDOMDataNode::AppendTextTo(nsAString& aResult)
1034 {
1035 mText.AppendTo(aResult);
1036 }
1038 bool
1039 nsGenericDOMDataNode::AppendTextTo(nsAString& aResult, const mozilla::fallible_t&)
1040 {
1041 return mText.AppendTo(aResult, mozilla::fallible_t());
1042 }
1044 already_AddRefed<nsIAtom>
1045 nsGenericDOMDataNode::GetCurrentValueAtom()
1046 {
1047 nsAutoString val;
1048 GetData(val);
1049 return NS_NewAtom(val);
1050 }
1052 nsIAtom*
1053 nsGenericDOMDataNode::DoGetID() const
1054 {
1055 return nullptr;
1056 }
1058 const nsAttrValue*
1059 nsGenericDOMDataNode::DoGetClasses() const
1060 {
1061 NS_NOTREACHED("Shouldn't ever be called");
1062 return nullptr;
1063 }
1065 NS_IMETHODIMP
1066 nsGenericDOMDataNode::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
1067 {
1068 return NS_OK;
1069 }
1071 NS_IMETHODIMP_(bool)
1072 nsGenericDOMDataNode::IsAttributeMapped(const nsIAtom* aAttribute) const
1073 {
1074 return false;
1075 }
1077 nsChangeHint
1078 nsGenericDOMDataNode::GetAttributeChangeHint(const nsIAtom* aAttribute,
1079 int32_t aModType) const
1080 {
1081 NS_NOTREACHED("Shouldn't be calling this!");
1082 return nsChangeHint(0);
1083 }
1085 nsIAtom*
1086 nsGenericDOMDataNode::GetClassAttributeName() const
1087 {
1088 return nullptr;
1089 }
1091 size_t
1092 nsGenericDOMDataNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
1093 {
1094 size_t n = nsIContent::SizeOfExcludingThis(aMallocSizeOf);
1095 n += mText.SizeOfExcludingThis(aMallocSizeOf);
1096 return n;
1097 }