Bug 454821. Better signature for GetChildArray. r+sr=sicking
[mozilla-central.git] / content / base / src / nsGenericDOMDataNode.cpp
blob43c930710c5305ecb34ee210faae6faa1bab5189
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 * Base class for DOM Core's nsIDOMComment, nsIDOMDocumentType, nsIDOMText,
40 * nsIDOMCDATASection, and nsIDOMProcessingInstruction nodes.
43 #include "nsGenericDOMDataNode.h"
44 #include "nsGenericElement.h"
45 #include "nsIDocument.h"
46 #include "nsIEventListenerManager.h"
47 #include "nsIDOMDocument.h"
48 #include "nsReadableUtils.h"
49 #include "nsMutationEvent.h"
50 #include "nsINameSpaceManager.h"
51 #include "nsIDOM3Node.h"
52 #include "nsIURI.h"
53 #include "nsIPrivateDOMEvent.h"
54 #include "nsIDOMEvent.h"
55 #include "nsIDOMText.h"
56 #include "nsCOMPtr.h"
57 #include "nsDOMString.h"
58 #include "nsIDOMUserDataHandler.h"
59 #include "nsChangeHint.h"
60 #include "nsEventDispatcher.h"
61 #include "nsCOMArray.h"
62 #include "nsNodeUtils.h"
63 #include "nsBindingManager.h"
64 #include "nsCCUncollectableMarker.h"
65 #include "mozAutoDocUpdate.h"
67 #include "pldhash.h"
68 #include "prprf.h"
70 nsGenericDOMDataNode::nsGenericDOMDataNode(nsINodeInfo *aNodeInfo)
71 : nsIContent(aNodeInfo)
75 nsGenericDOMDataNode::~nsGenericDOMDataNode()
77 NS_PRECONDITION(!IsInDoc(),
78 "Please remove this from the document properly");
81 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericDOMDataNode)
83 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsGenericDOMDataNode)
84 nsIDocument* currentDoc = tmp->GetCurrentDoc();
85 if (currentDoc && nsCCUncollectableMarker::InGeneration(
86 currentDoc->GetMarkedCCGeneration())) {
87 return NS_OK;
90 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNodeInfo)
92 nsIDocument* ownerDoc = tmp->GetOwnerDoc();
93 if (ownerDoc) {
94 ownerDoc->BindingManager()->Traverse(tmp, cb);
97 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_LISTENERMANAGER
98 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_USERDATA
99 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_PRESERVED_WRAPPER
100 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
102 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericDOMDataNode)
103 NS_IMPL_CYCLE_COLLECTION_UNLINK_LISTENERMANAGER
104 NS_IMPL_CYCLE_COLLECTION_UNLINK_USERDATA
105 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
106 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
108 NS_INTERFACE_MAP_BEGIN(nsGenericDOMDataNode)
109 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
110 NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsGenericDOMDataNode)
111 NS_INTERFACE_MAP_ENTRY(nsIContent)
112 NS_INTERFACE_MAP_ENTRY(nsINode)
113 NS_INTERFACE_MAP_ENTRY(nsPIDOMEventTarget)
114 NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMEventTarget,
115 nsDOMEventRTTearoff::Create(this))
116 NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3EventTarget,
117 nsDOMEventRTTearoff::Create(this))
118 NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMNSEventTarget,
119 nsDOMEventRTTearoff::Create(this))
120 NS_INTERFACE_MAP_ENTRY_TEAROFF(nsISupportsWeakReference,
121 new nsNodeSupportsWeakRefTearoff(this))
122 NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3Node, new nsNode3Tearoff(this))
123 // nsNodeSH::PreCreate() depends on the identity pointer being the
124 // same as nsINode (which nsIContent inherits), so if you change the
125 // below line, make sure nsNodeSH::PreCreate() still does the right
126 // thing!
127 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
128 NS_INTERFACE_MAP_END
130 NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsGenericDOMDataNode, nsIContent)
131 NS_IMPL_CYCLE_COLLECTING_RELEASE_FULL(nsGenericDOMDataNode, nsIContent,
132 nsNodeUtils::LastRelease(this))
135 nsresult
136 nsGenericDOMDataNode::GetNodeValue(nsAString& aNodeValue)
138 return GetData(aNodeValue);
141 nsresult
142 nsGenericDOMDataNode::SetNodeValue(const nsAString& aNodeValue)
144 return SetTextInternal(0, mText.GetLength(), aNodeValue.BeginReading(),
145 aNodeValue.Length(), PR_TRUE);
148 nsresult
149 nsGenericDOMDataNode::GetParentNode(nsIDOMNode** aParentNode)
151 *aParentNode = nsnull;
152 nsINode *parent = GetNodeParent();
154 return parent ? CallQueryInterface(parent, aParentNode) : NS_OK;
157 nsresult
158 nsGenericDOMDataNode::GetPreviousSibling(nsIDOMNode** aPrevSibling)
160 *aPrevSibling = nsnull;
162 nsINode *parent = GetNodeParent();
163 if (!parent) {
164 return NS_OK;
167 PRInt32 pos = parent->IndexOf(this);
168 nsIContent *sibling = parent->GetChildAt(pos - 1);
170 return sibling ? CallQueryInterface(sibling, aPrevSibling) : NS_OK;
173 nsresult
174 nsGenericDOMDataNode::GetNextSibling(nsIDOMNode** aNextSibling)
176 *aNextSibling = nsnull;
178 nsINode *parent = GetNodeParent();
179 if (!parent) {
180 return NS_OK;
183 PRInt32 pos = parent->IndexOf(this);
184 nsIContent *sibling = parent->GetChildAt(pos + 1);
186 return sibling ? CallQueryInterface(sibling, aNextSibling) : NS_OK;
189 nsresult
190 nsGenericDOMDataNode::GetChildNodes(nsIDOMNodeList** aChildNodes)
192 *aChildNodes = nsnull;
193 nsDataSlots *slots = GetDataSlots();
194 NS_ENSURE_TRUE(slots, NS_ERROR_OUT_OF_MEMORY);
196 if (!slots->mChildNodes) {
197 slots->mChildNodes = new nsChildContentList(this);
198 NS_ENSURE_TRUE(slots->mChildNodes, NS_ERROR_OUT_OF_MEMORY);
199 NS_ADDREF(slots->mChildNodes);
202 NS_ADDREF(*aChildNodes = slots->mChildNodes);
203 return NS_OK;
206 nsresult
207 nsGenericDOMDataNode::GetOwnerDocument(nsIDOMDocument** aOwnerDocument)
209 nsIDocument *document = GetOwnerDoc();
210 if (document) {
211 return CallQueryInterface(document, aOwnerDocument);
214 *aOwnerDocument = nsnull;
216 return NS_OK;
219 nsresult
220 nsGenericDOMDataNode::GetNamespaceURI(nsAString& aNamespaceURI)
222 SetDOMStringToNull(aNamespaceURI);
224 return NS_OK;
227 nsresult
228 nsGenericDOMDataNode::GetPrefix(nsAString& aPrefix)
230 SetDOMStringToNull(aPrefix);
232 return NS_OK;
235 nsresult
236 nsGenericDOMDataNode::SetPrefix(const nsAString& aPrefix)
238 return NS_ERROR_DOM_NAMESPACE_ERR;
241 nsresult
242 nsGenericDOMDataNode::GetLocalName(nsAString& aLocalName)
244 SetDOMStringToNull(aLocalName);
246 return NS_OK;
249 nsresult
250 nsGenericDOMDataNode::Normalize()
252 return NS_OK;
255 nsresult
256 nsGenericDOMDataNode::IsSupported(const nsAString& aFeature,
257 const nsAString& aVersion,
258 PRBool* aReturn)
260 return nsGenericElement::InternalIsSupported(static_cast<nsIContent*>(this),
261 aFeature, aVersion, aReturn);
264 nsresult
265 nsGenericDOMDataNode::GetBaseURI(nsAString& aURI)
267 nsCOMPtr<nsIURI> baseURI = GetBaseURI();
268 nsCAutoString spec;
270 if (baseURI) {
271 baseURI->GetSpec(spec);
274 CopyUTF8toUTF16(spec, aURI);
276 return NS_OK;
279 nsresult
280 nsGenericDOMDataNode::LookupPrefix(const nsAString& aNamespaceURI,
281 nsAString& aPrefix)
283 aPrefix.Truncate();
285 nsIContent *parent_weak = GetParent();
287 // DOM Data Node passes the query on to its parent
288 nsCOMPtr<nsIDOM3Node> node(do_QueryInterface(parent_weak));
289 if (node) {
290 return node->LookupPrefix(aNamespaceURI, aPrefix);
293 return NS_OK;
296 nsresult
297 nsGenericDOMDataNode::LookupNamespaceURI(const nsAString& aNamespacePrefix,
298 nsAString& aNamespaceURI)
300 aNamespaceURI.Truncate();
302 nsIContent *parent_weak = GetParent();
304 // DOM Data Node passes the query on to its parent
305 nsCOMPtr<nsIDOM3Node> node(do_QueryInterface(parent_weak));
307 if (node) {
308 return node->LookupNamespaceURI(aNamespacePrefix, aNamespaceURI);
311 return NS_OK;
314 //----------------------------------------------------------------------
316 // Implementation of nsIDOMCharacterData
318 nsresult
319 nsGenericDOMDataNode::GetData(nsAString& aData) const
321 if (mText.Is2b()) {
322 aData.Assign(mText.Get2b(), mText.GetLength());
323 } else {
324 // Must use Substring() since nsDependentCString() requires null
325 // terminated strings.
327 const char *data = mText.Get1b();
329 if (data) {
330 CopyASCIItoUTF16(Substring(data, data + mText.GetLength()), aData);
331 } else {
332 aData.Truncate();
336 return NS_OK;
339 nsresult
340 nsGenericDOMDataNode::SetData(const nsAString& aData)
342 return SetTextInternal(0, mText.GetLength(), aData.BeginReading(),
343 aData.Length(), PR_TRUE);
346 nsresult
347 nsGenericDOMDataNode::GetLength(PRUint32* aLength)
349 *aLength = mText.GetLength();
350 return NS_OK;
353 nsresult
354 nsGenericDOMDataNode::SubstringData(PRUint32 aStart, PRUint32 aCount,
355 nsAString& aReturn)
357 aReturn.Truncate();
359 // XXX add <0 checks if types change
360 PRUint32 textLength = PRUint32( mText.GetLength() );
361 if (aStart > textLength) {
362 return NS_ERROR_DOM_INDEX_SIZE_ERR;
365 PRUint32 amount = aCount;
366 if (amount > textLength - aStart) {
367 amount = textLength - aStart;
370 if (mText.Is2b()) {
371 aReturn.Assign(mText.Get2b() + aStart, amount);
372 } else {
373 // Must use Substring() since nsDependentCString() requires null
374 // terminated strings.
376 const char *data = mText.Get1b() + aStart;
377 CopyASCIItoUTF16(Substring(data, data + amount), aReturn);
380 return NS_OK;
383 //----------------------------------------------------------------------
385 nsresult
386 nsGenericDOMDataNode::AppendData(const nsAString& aData)
388 return SetTextInternal(mText.GetLength(), 0, aData.BeginReading(),
389 aData.Length(), PR_TRUE);
392 nsresult
393 nsGenericDOMDataNode::InsertData(PRUint32 aOffset,
394 const nsAString& aData)
396 return SetTextInternal(aOffset, 0, aData.BeginReading(),
397 aData.Length(), PR_TRUE);
400 nsresult
401 nsGenericDOMDataNode::DeleteData(PRUint32 aOffset, PRUint32 aCount)
403 return SetTextInternal(aOffset, aCount, nsnull, 0, PR_TRUE);
406 nsresult
407 nsGenericDOMDataNode::ReplaceData(PRUint32 aOffset, PRUint32 aCount,
408 const nsAString& aData)
410 return SetTextInternal(aOffset, aCount, aData.BeginReading(),
411 aData.Length(), PR_TRUE);
414 nsresult
415 nsGenericDOMDataNode::SetTextInternal(PRUint32 aOffset, PRUint32 aCount,
416 const PRUnichar* aBuffer,
417 PRUint32 aLength, PRBool aNotify)
419 NS_PRECONDITION(aBuffer || !aLength,
420 "Null buffer passed to SetTextInternal!");
422 // sanitize arguments
423 PRUint32 textLength = mText.GetLength();
424 if (aOffset > textLength) {
425 return NS_ERROR_DOM_INDEX_SIZE_ERR;
428 nsIDocument *document = GetCurrentDoc();
429 mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
431 PRBool haveMutationListeners = aNotify &&
432 nsContentUtils::HasMutationListeners(this,
433 NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED,
434 this);
436 nsCOMPtr<nsIAtom> oldValue;
437 if (haveMutationListeners) {
438 oldValue = GetCurrentValueAtom();
441 PRUint32 endOffset = aOffset + aCount;
442 if (endOffset > textLength) {
443 aCount = textLength - aOffset;
444 endOffset = textLength;
447 if (aNotify) {
448 CharacterDataChangeInfo info = {
449 aOffset == textLength,
450 aOffset,
451 endOffset,
452 aLength
454 nsNodeUtils::CharacterDataWillChange(this, &info);
457 if (aOffset == 0 && endOffset == textLength) {
458 // Replacing whole text or old text was empty
459 mText.SetTo(aBuffer, aLength);
461 else if (aOffset == textLength) {
462 // Appending to existing
463 mText.Append(aBuffer, aLength);
465 else {
466 // Merging old and new
468 // Allocate new buffer
469 PRInt32 newLength = textLength - aCount + aLength;
470 PRUnichar* to = new PRUnichar[newLength];
471 NS_ENSURE_TRUE(to, NS_ERROR_OUT_OF_MEMORY);
473 // Copy over appropriate data
474 if (0 != aOffset) {
475 mText.CopyTo(to, 0, aOffset);
477 if (0 != aLength) {
478 memcpy(to + aOffset, aBuffer, aLength * sizeof(PRUnichar));
480 if (endOffset != textLength) {
481 mText.CopyTo(to + aOffset + aLength, endOffset, textLength - endOffset);
484 // XXX Add OOM checking to this
485 mText.SetTo(to, newLength);
487 delete [] to;
490 SetBidiStatus();
492 // Notify observers
493 if (aNotify) {
494 CharacterDataChangeInfo info = {
495 aOffset == textLength,
496 aOffset,
497 endOffset,
498 aLength
500 nsNodeUtils::CharacterDataChanged(this, &info);
502 if (haveMutationListeners) {
503 mozAutoRemovableBlockerRemover blockerRemover;
505 nsMutationEvent mutation(PR_TRUE, NS_MUTATION_CHARACTERDATAMODIFIED);
507 mutation.mPrevAttrValue = oldValue;
508 if (aLength > 0) {
509 nsAutoString val;
510 mText.AppendTo(val);
511 mutation.mNewAttrValue = do_GetAtom(val);
514 mozAutoSubtreeModified subtree(GetOwnerDoc(), this);
515 nsEventDispatcher::Dispatch(this, nsnull, &mutation);
519 return NS_OK;
522 //----------------------------------------------------------------------
524 // Implementation of nsIContent
526 #ifdef DEBUG
527 void
528 nsGenericDOMDataNode::ToCString(nsAString& aBuf, PRInt32 aOffset,
529 PRInt32 aLen) const
531 if (mText.Is2b()) {
532 const PRUnichar* cp = mText.Get2b() + aOffset;
533 const PRUnichar* end = cp + aLen;
535 while (cp < end) {
536 PRUnichar ch = *cp++;
537 if (ch == '&') {
538 aBuf.AppendLiteral("&amp;");
539 } else if (ch == '<') {
540 aBuf.AppendLiteral("&lt;");
541 } else if (ch == '>') {
542 aBuf.AppendLiteral("&gt;");
543 } else if ((ch < ' ') || (ch >= 127)) {
544 char buf[10];
545 PR_snprintf(buf, sizeof(buf), "\\u%04x", ch);
546 AppendASCIItoUTF16(buf, aBuf);
547 } else {
548 aBuf.Append(ch);
551 } else {
552 unsigned char* cp = (unsigned char*)mText.Get1b() + aOffset;
553 const unsigned char* end = cp + aLen;
555 while (cp < end) {
556 PRUnichar ch = *cp++;
557 if (ch == '&') {
558 aBuf.AppendLiteral("&amp;");
559 } else if (ch == '<') {
560 aBuf.AppendLiteral("&lt;");
561 } else if (ch == '>') {
562 aBuf.AppendLiteral("&gt;");
563 } else if ((ch < ' ') || (ch >= 127)) {
564 char buf[10];
565 PR_snprintf(buf, sizeof(buf), "\\u%04x", ch);
566 AppendASCIItoUTF16(buf, aBuf);
567 } else {
568 aBuf.Append(ch);
573 #endif
576 nsresult
577 nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
578 nsIContent* aBindingParent,
579 PRBool aCompileEventHandlers)
581 NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
582 NS_PRECONDITION(HasSameOwnerDoc(NODE_FROM(aParent, aDocument)),
583 "Must have the same owner document");
584 NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(),
585 "aDocument must be current doc of aParent");
586 NS_PRECONDITION(!GetCurrentDoc() && !IsInDoc(),
587 "Already have a document. Unbind first!");
588 // Note that as we recurse into the kids, they'll have a non-null parent. So
589 // only assert if our parent is _changing_ while we have a parent.
590 NS_PRECONDITION(!GetParent() || aParent == GetParent(),
591 "Already have a parent. Unbind first!");
592 NS_PRECONDITION(!GetBindingParent() ||
593 aBindingParent == GetBindingParent() ||
594 (!aBindingParent && aParent &&
595 aParent->GetBindingParent() == GetBindingParent()),
596 "Already have a binding parent. Unbind first!");
597 NS_PRECONDITION(aBindingParent != this,
598 "Content must not be its own binding parent");
599 NS_PRECONDITION(!IsRootOfNativeAnonymousSubtree() ||
600 aBindingParent == aParent,
601 "Native anonymous content must have its parent as its "
602 "own binding parent");
604 if (!aBindingParent && aParent) {
605 aBindingParent = aParent->GetBindingParent();
608 // First set the binding parent
609 if (aBindingParent) {
610 nsDataSlots *slots = GetDataSlots();
611 NS_ENSURE_TRUE(slots, NS_ERROR_OUT_OF_MEMORY);
613 NS_ASSERTION(IsRootOfNativeAnonymousSubtree() ||
614 !HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE) ||
615 (aParent && aParent->IsInNativeAnonymousSubtree()),
616 "Trying to re-bind content from native anonymous subtree to "
617 "non-native anonymous parent!");
618 slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
619 if (IsRootOfNativeAnonymousSubtree() ||
620 aParent->IsInNativeAnonymousSubtree()) {
621 SetFlags(NODE_IS_IN_ANONYMOUS_SUBTREE);
625 // Set parent
626 if (aParent) {
627 mParentPtrBits =
628 reinterpret_cast<PtrBits>(aParent) | PARENT_BIT_PARENT_IS_CONTENT;
630 else {
631 mParentPtrBits = reinterpret_cast<PtrBits>(aDocument);
634 // XXXbz sXBL/XBL2 issue!
636 // Set document
637 if (aDocument) {
638 // XXX See the comment in nsGenericElement::BindToTree
639 mParentPtrBits |= PARENT_BIT_INDOCUMENT;
640 if (mText.IsBidi()) {
641 aDocument->SetBidiEnabled();
645 nsNodeUtils::ParentChainChanged(this);
647 UpdateEditableState();
649 NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document");
650 NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
651 NS_POSTCONDITION(aBindingParent == GetBindingParent(),
652 "Bound to wrong binding parent");
654 return NS_OK;
657 void
658 nsGenericDOMDataNode::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
660 nsIDocument *document = GetCurrentDoc();
661 if (document) {
662 // Notify XBL- & nsIAnonymousContentCreator-generated
663 // anonymous content that the document is changing.
664 // This is needed to update the insertion point.
665 document->BindingManager()->ChangeDocumentFor(this, document, nsnull);
668 mParentPtrBits = aNullParent ? 0 : mParentPtrBits & ~PARENT_BIT_INDOCUMENT;
670 nsDataSlots *slots = GetExistingDataSlots();
671 if (slots) {
672 slots->mBindingParent = nsnull;
675 nsNodeUtils::ParentChainChanged(this);
678 nsIAtom *
679 nsGenericDOMDataNode::GetIDAttributeName() const
681 return nsnull;
684 already_AddRefed<nsINodeInfo>
685 nsGenericDOMDataNode::GetExistingAttrNameFromQName(const nsAString& aStr) const
687 return nsnull;
690 nsresult
691 nsGenericDOMDataNode::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttr,
692 nsIAtom* aPrefix, const nsAString& aValue,
693 PRBool aNotify)
695 return NS_OK;
698 nsresult
699 nsGenericDOMDataNode::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttr,
700 PRBool aNotify)
702 return NS_OK;
705 PRBool
706 nsGenericDOMDataNode::GetAttr(PRInt32 aNameSpaceID, nsIAtom *aAttr,
707 nsAString& aResult) const
709 aResult.Truncate();
711 return PR_FALSE;
714 PRBool
715 nsGenericDOMDataNode::HasAttr(PRInt32 aNameSpaceID, nsIAtom *aAttribute) const
717 return PR_FALSE;
720 const nsAttrName*
721 nsGenericDOMDataNode::GetAttrNameAt(PRUint32 aIndex) const
723 return nsnull;
726 PRUint32
727 nsGenericDOMDataNode::GetAttrCount() const
729 return 0;
732 nsresult
733 nsGenericDOMDataNode::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
735 return nsGenericElement::doPreHandleEvent(this, aVisitor);
738 nsresult
739 nsGenericDOMDataNode::PostHandleEvent(nsEventChainPostVisitor& /*aVisitor*/)
741 return NS_OK;
744 nsresult
745 nsGenericDOMDataNode::DispatchDOMEvent(nsEvent* aEvent,
746 nsIDOMEvent* aDOMEvent,
747 nsPresContext* aPresContext,
748 nsEventStatus* aEventStatus)
750 return nsEventDispatcher::DispatchDOMEvent(static_cast<nsINode*>(this),
751 aEvent, aDOMEvent,
752 aPresContext, aEventStatus);
755 nsresult
756 nsGenericDOMDataNode::GetListenerManager(PRBool aCreateIfNotFound,
757 nsIEventListenerManager** aResult)
759 return nsContentUtils::GetListenerManager(this, aCreateIfNotFound, aResult);
762 nsresult
763 nsGenericDOMDataNode::AddEventListenerByIID(nsIDOMEventListener *aListener,
764 const nsIID& aIID)
766 nsCOMPtr<nsIEventListenerManager> elm;
767 nsresult rv = GetListenerManager(PR_TRUE, getter_AddRefs(elm));
768 if (elm) {
769 return elm->AddEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE);
771 return rv;
774 nsresult
775 nsGenericDOMDataNode::RemoveEventListenerByIID(nsIDOMEventListener *aListener,
776 const nsIID& aIID)
778 nsCOMPtr<nsIEventListenerManager> elm;
779 GetListenerManager(PR_FALSE, getter_AddRefs(elm));
780 if (elm) {
781 return elm->RemoveEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE);
783 return NS_OK;
786 nsresult
787 nsGenericDOMDataNode::GetSystemEventGroup(nsIDOMEventGroup** aGroup)
789 nsCOMPtr<nsIEventListenerManager> elm;
790 nsresult rv = GetListenerManager(PR_TRUE, getter_AddRefs(elm));
791 if (elm) {
792 return elm->GetSystemEventGroupLM(aGroup);
794 return rv;
797 PRUint32
798 nsGenericDOMDataNode::GetChildCount() const
800 return 0;
803 nsIContent *
804 nsGenericDOMDataNode::GetChildAt(PRUint32 aIndex) const
806 return nsnull;
809 nsIContent * const *
810 nsGenericDOMDataNode::GetChildArray(PRUint32* aChildCount) const
812 *aChildCount = 0;
813 return nsnull;
816 PRInt32
817 nsGenericDOMDataNode::IndexOf(nsINode* aPossibleChild) const
819 return -1;
822 nsresult
823 nsGenericDOMDataNode::InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
824 PRBool aNotify)
826 return NS_OK;
829 nsresult
830 nsGenericDOMDataNode::RemoveChildAt(PRUint32 aIndex, PRBool aNotify)
832 return NS_OK;
835 // virtual
836 PRBool
837 nsGenericDOMDataNode::MayHaveFrame() const
839 nsIContent* parent = GetParent();
840 return parent && parent->MayHaveFrame();
843 nsIContent *
844 nsGenericDOMDataNode::GetBindingParent() const
846 nsDataSlots *slots = GetExistingDataSlots();
847 return slots ? slots->mBindingParent : nsnull;
850 PRBool
851 nsGenericDOMDataNode::IsNodeOfType(PRUint32 aFlags) const
853 return !(aFlags & ~(eCONTENT | eDATA_NODE));
856 void
857 nsGenericDOMDataNode::SaveSubtreeState()
861 void
862 nsGenericDOMDataNode::DestroyContent()
864 // XXX We really should let cycle collection do this, but that currently still
865 // leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684).
866 ReleaseWrapper();
869 #ifdef DEBUG
870 void
871 nsGenericDOMDataNode::List(FILE* out, PRInt32 aIndent) const
875 void
876 nsGenericDOMDataNode::DumpContent(FILE* out, PRInt32 aIndent,
877 PRBool aDumpAll) const
880 #endif
882 already_AddRefed<nsIURI>
883 nsGenericDOMDataNode::GetBaseURI() const
885 // DOM Data Node inherits the base from its parent element/document
886 nsIContent *parent = GetParent();
887 if (parent) {
888 return parent->GetBaseURI();
891 nsIURI *uri;
892 nsIDocument *doc = GetOwnerDoc();
893 if (doc) {
894 NS_IF_ADDREF(uri = doc->GetBaseURI());
896 else {
897 uri = nsnull;
900 return uri;
903 PRBool
904 nsGenericDOMDataNode::IsLink(nsIURI** aURI) const
906 *aURI = nsnull;
907 return PR_FALSE;
910 nsINode::nsSlots*
911 nsGenericDOMDataNode::CreateSlots()
913 return new nsDataSlots(mFlagsOrSlots);
916 //----------------------------------------------------------------------
918 // Implementation of the nsIDOMText interface
920 nsresult
921 nsGenericDOMDataNode::SplitData(PRUint32 aOffset, nsIContent** aReturn,
922 PRBool aCloneAfterOriginal)
924 *aReturn = nsnull;
925 nsresult rv = NS_OK;
926 nsAutoString cutText;
927 PRUint32 length = TextLength();
929 if (aOffset > length) {
930 return NS_ERROR_DOM_INDEX_SIZE_ERR;
933 PRUint32 cutStartOffset = aCloneAfterOriginal ? aOffset : 0;
934 PRUint32 cutLength = aCloneAfterOriginal ? length - aOffset : aOffset;
935 rv = SubstringData(cutStartOffset, cutLength, cutText);
936 if (NS_FAILED(rv)) {
937 return rv;
940 rv = DeleteData(cutStartOffset, cutLength);
941 if (NS_FAILED(rv)) {
942 return rv;
946 * Use Clone for creating the new node so that the new node is of same class
947 * as this node!
950 nsCOMPtr<nsIContent> newContent = CloneDataNode(mNodeInfo, PR_FALSE);
951 if (!newContent) {
952 return NS_ERROR_OUT_OF_MEMORY;
955 newContent->SetText(cutText, PR_TRUE);
957 nsCOMPtr<nsINode> parent = GetNodeParent();
959 if (parent) {
960 PRInt32 insertionIndex = parent->IndexOf(this);
961 if (aCloneAfterOriginal) {
962 ++insertionIndex;
964 parent->InsertChildAt(newContent, insertionIndex, PR_TRUE);
967 newContent.swap(*aReturn);
968 return rv;
971 nsresult
972 nsGenericDOMDataNode::SplitText(PRUint32 aOffset, nsIDOMText** aReturn)
974 nsCOMPtr<nsIContent> newChild;
975 nsresult rv = SplitData(aOffset, getter_AddRefs(newChild));
976 if (NS_SUCCEEDED(rv)) {
977 rv = CallQueryInterface(newChild, aReturn);
979 return rv;
982 //----------------------------------------------------------------------
984 // Implementation of the nsGenericDOMDataNode nsIDOM3Text tearoff
986 NS_IMPL_CYCLE_COLLECTION_CLASS(nsText3Tearoff)
988 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsText3Tearoff)
989 NS_INTERFACE_MAP_ENTRY(nsIDOM3Text)
990 NS_INTERFACE_MAP_END_AGGREGATED(mNode)
992 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsText3Tearoff)
993 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNode)
994 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
996 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsText3Tearoff)
997 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mNode, nsIContent)
998 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1000 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsText3Tearoff)
1001 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsText3Tearoff)
1003 NS_IMETHODIMP
1004 nsText3Tearoff::GetIsElementContentWhitespace(PRBool *aReturn)
1006 *aReturn = mNode->TextIsOnlyWhitespace();
1007 return NS_OK;
1010 NS_IMETHODIMP
1011 nsText3Tearoff::GetWholeText(nsAString& aWholeText)
1013 return mNode->GetWholeText(aWholeText);
1016 NS_IMETHODIMP
1017 nsText3Tearoff::ReplaceWholeText(const nsAString& aContent,
1018 nsIDOMText **aReturn)
1020 return mNode->ReplaceWholeText(PromiseFlatString(aContent), aReturn);
1023 // Implementation of the nsIDOM3Text interface
1025 /* static */ PRInt32
1026 nsGenericDOMDataNode::FirstLogicallyAdjacentTextNode(nsIContent* aParent,
1027 PRInt32 aIndex)
1029 while (aIndex-- > 0) {
1030 nsIContent* sibling = aParent->GetChildAt(aIndex);
1031 if (!sibling->IsNodeOfType(nsINode::eTEXT))
1032 return aIndex + 1;
1034 return 0;
1037 /* static */ PRInt32
1038 nsGenericDOMDataNode::LastLogicallyAdjacentTextNode(nsIContent* aParent,
1039 PRInt32 aIndex,
1040 PRUint32 aCount)
1042 while (++aIndex < PRInt32(aCount)) {
1043 nsIContent* sibling = aParent->GetChildAt(aIndex);
1044 if (!sibling->IsNodeOfType(nsINode::eTEXT))
1045 return aIndex - 1;
1047 return aCount - 1;
1050 nsresult
1051 nsGenericDOMDataNode::GetWholeText(nsAString& aWholeText)
1053 nsIContent* parent = GetParent();
1055 // Handle parent-less nodes
1056 if (!parent)
1057 return GetData(aWholeText);
1059 PRInt32 index = parent->IndexOf(this);
1060 NS_WARN_IF_FALSE(index >= 0,
1061 "Trying to use .wholeText with an anonymous"
1062 "text node child of a binding parent?");
1063 NS_ENSURE_TRUE(index >= 0, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
1064 PRInt32 first =
1065 FirstLogicallyAdjacentTextNode(parent, index);
1066 PRInt32 last =
1067 LastLogicallyAdjacentTextNode(parent, index, parent->GetChildCount());
1069 aWholeText.Truncate();
1071 nsCOMPtr<nsIDOMText> node;
1072 nsAutoString tmp;
1073 do {
1074 node = do_QueryInterface(parent->GetChildAt(first));
1075 node->GetData(tmp);
1076 aWholeText.Append(tmp);
1077 } while (first++ < last);
1079 return NS_OK;
1082 nsresult
1083 nsGenericDOMDataNode::ReplaceWholeText(const nsAFlatString& aContent,
1084 nsIDOMText **aReturn)
1086 // Batch possible DOMSubtreeModified events.
1087 mozAutoSubtreeModified subtree(GetOwnerDoc(), nsnull);
1088 mozAutoDocUpdate updateBatch(GetCurrentDoc(), UPDATE_CONTENT_MODEL, PR_TRUE);
1090 nsCOMPtr<nsIContent> parent = GetParent();
1092 // Handle parent-less nodes
1093 if (!parent) {
1094 if (aContent.IsEmpty()) {
1095 *aReturn = nsnull;
1096 return NS_OK;
1099 SetText(aContent.get(), aContent.Length(), PR_TRUE);
1100 return CallQueryInterface(this, aReturn);
1103 PRInt32 index = parent->IndexOf(this);
1104 NS_WARN_IF_FALSE(index >= 0,
1105 "Trying to use .replaceWholeText with an anonymous"
1106 "text node child of a binding parent?");
1107 NS_ENSURE_TRUE(index >= 0, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
1109 // We don't support entity references or read-only nodes, so remove the
1110 // logically adjacent text nodes (which therefore must all be siblings of
1111 // this) and set this one to the provided text, if that text isn't empty.
1112 PRInt32 first =
1113 FirstLogicallyAdjacentTextNode(parent, index);
1114 PRInt32 last =
1115 LastLogicallyAdjacentTextNode(parent, index, parent->GetChildCount());
1117 do {
1118 if (last == index && !aContent.IsEmpty())
1119 continue;
1121 parent->RemoveChildAt(last, PR_TRUE);
1122 } while (last-- > first);
1124 // Empty string means we removed this node too.
1125 if (aContent.IsEmpty()) {
1126 *aReturn = nsnull;
1127 return NS_OK;
1130 SetText(aContent.get(), aContent.Length(), PR_TRUE);
1131 return CallQueryInterface(this, aReturn);
1134 //----------------------------------------------------------------------
1136 // Implementation of the nsIContent interface text functions
1138 const nsTextFragment *
1139 nsGenericDOMDataNode::GetText()
1141 return &mText;
1144 PRUint32
1145 nsGenericDOMDataNode::TextLength()
1147 return mText.GetLength();
1150 nsresult
1151 nsGenericDOMDataNode::SetText(const PRUnichar* aBuffer,
1152 PRUint32 aLength,
1153 PRBool aNotify)
1155 return SetTextInternal(0, mText.GetLength(), aBuffer, aLength, aNotify);
1158 nsresult
1159 nsGenericDOMDataNode::AppendText(const PRUnichar* aBuffer,
1160 PRUint32 aLength,
1161 PRBool aNotify)
1163 return SetTextInternal(mText.GetLength(), 0, aBuffer, aLength, aNotify);
1166 PRBool
1167 nsGenericDOMDataNode::TextIsOnlyWhitespace()
1169 if (mText.Is2b()) {
1170 // The fragment contains non-8bit characters and such characters
1171 // are never considered whitespace.
1172 return PR_FALSE;
1175 const char* cp = mText.Get1b();
1176 const char* end = cp + mText.GetLength();
1178 while (cp < end) {
1179 char ch = *cp;
1181 if (!XP_IS_SPACE(ch)) {
1182 return PR_FALSE;
1185 ++cp;
1188 return PR_TRUE;
1191 void
1192 nsGenericDOMDataNode::AppendTextTo(nsAString& aResult)
1194 mText.AppendTo(aResult);
1197 void nsGenericDOMDataNode::SetBidiStatus()
1199 nsIDocument *document = GetCurrentDoc();
1200 if (document && document->GetBidiEnabled()) {
1201 // OK, we already know it's Bidi, so we won't test again
1202 return;
1205 mText.SetBidiFlag();
1207 if (document && mText.IsBidi()) {
1208 document->SetBidiEnabled();
1212 already_AddRefed<nsIAtom>
1213 nsGenericDOMDataNode::GetCurrentValueAtom()
1215 nsAutoString val;
1216 GetData(val);
1217 return NS_NewAtom(val);
1220 nsIAtom*
1221 nsGenericDOMDataNode::GetID() const
1223 return nsnull;
1226 const nsAttrValue*
1227 nsGenericDOMDataNode::DoGetClasses() const
1229 NS_NOTREACHED("Shouldn't ever be called");
1230 return nsnull;
1233 NS_IMETHODIMP
1234 nsGenericDOMDataNode::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
1236 return NS_OK;
1239 nsICSSStyleRule*
1240 nsGenericDOMDataNode::GetInlineStyleRule()
1242 return nsnull;
1245 NS_IMETHODIMP
1246 nsGenericDOMDataNode::SetInlineStyleRule(nsICSSStyleRule* aStyleRule,
1247 PRBool aNotify)
1249 NS_NOTREACHED("How come we're setting inline style on a non-element?");
1250 return NS_ERROR_UNEXPECTED;
1253 NS_IMETHODIMP_(PRBool)
1254 nsGenericDOMDataNode::IsAttributeMapped(const nsIAtom* aAttribute) const
1256 return PR_FALSE;
1259 nsChangeHint
1260 nsGenericDOMDataNode::GetAttributeChangeHint(const nsIAtom* aAttribute,
1261 PRInt32 aModType) const
1263 NS_NOTREACHED("Shouldn't be calling this!");
1264 return nsChangeHint(0);
1267 nsIAtom*
1268 nsGenericDOMDataNode::GetClassAttributeName() const
1270 return nsnull;