Back to index

lightning-sunbird  0.9+nobinonly
nsGenericDOMDataNode.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 #include "nsGenericDOMDataNode.h"
00038 #include "nsGenericElement.h"
00039 #include "nsIDocument.h"
00040 #include "nsIEventListenerManager.h"
00041 #include "nsIDOMRange.h"
00042 #include "nsIDOMDocument.h"
00043 #include "nsRange.h"
00044 #include "nsISelection.h"
00045 #include "nsISelectionPrivate.h"
00046 #include "nsReadableUtils.h"
00047 #include "nsMutationEvent.h"
00048 #include "nsINameSpaceManager.h"
00049 #include "nsIDOM3Node.h"
00050 #include "nsIURI.h"
00051 #include "nsIPrivateDOMEvent.h"
00052 #include "nsIDOMEvent.h"
00053 #include "nsIDOMText.h"
00054 #include "nsCOMPtr.h"
00055 #include "nsDOMString.h"
00056 
00057 #include "pldhash.h"
00058 #include "prprf.h"
00059 
00060 nsGenericDOMDataNode::nsGenericDOMDataNode(nsNodeInfoManager *aNodeInfoManager)
00061   : mNodeInfoManagerBits(aNodeInfoManager)
00062 {
00063   NS_IF_ADDREF(aNodeInfoManager);
00064 }
00065 
00066 nsGenericDOMDataNode::~nsGenericDOMDataNode()
00067 {
00068   if (CouldHaveEventListenerManager()) {
00069     EventListenerManagerMapEntry *entry =
00070       NS_STATIC_CAST(EventListenerManagerMapEntry *,
00071                      PL_DHashTableOperate(&nsGenericElement::
00072                                           sEventListenerManagersHash, this,
00073                                           PL_DHASH_LOOKUP));
00074     if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
00075       nsCOMPtr<nsIEventListenerManager> listenerManager;
00076       listenerManager.swap(entry->mListenerManager);
00077       // Remove the entry and *then* do operations that could cause further
00078       // modification of sEventListenerManagersHash.  See bug 334177.
00079       PL_DHashTableRawRemove(&nsGenericElement::
00080                              sEventListenerManagersHash, entry);
00081       if (listenerManager) {
00082         listenerManager->Disconnect();
00083       }
00084     }
00085   }
00086 
00087   if (CouldHaveRangeList()) {
00088     PL_DHashTableOperate(&nsGenericElement::sRangeListsHash,
00089                          this, PL_DHASH_REMOVE);
00090   }
00091 
00092   nsNodeInfoManager* nim = GetNodeInfoManager();
00093   NS_IF_RELEASE(nim);
00094 }
00095 
00096 
00097 NS_IMPL_ADDREF(nsGenericDOMDataNode)
00098 NS_IMPL_RELEASE(nsGenericDOMDataNode)
00099 
00100 NS_INTERFACE_MAP_BEGIN(nsGenericDOMDataNode)
00101   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
00102   NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
00103   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMEventReceiver,
00104                                  nsDOMEventRTTearoff::Create(this))
00105   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMEventTarget,
00106                                  nsDOMEventRTTearoff::Create(this))
00107   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3EventTarget,
00108                                  nsDOMEventRTTearoff::Create(this))
00109   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMNSEventTarget,
00110                                  nsDOMEventRTTearoff::Create(this))
00111   NS_INTERFACE_MAP_ENTRY(nsIContent)
00112   // No nsITextContent since all subclasses might not want that.
00113   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3Node, new nsNode3Tearoff(this))
00114 NS_INTERFACE_MAP_END
00115 
00116 
00117 nsresult
00118 nsGenericDOMDataNode::GetNodeValue(nsAString& aNodeValue)
00119 {
00120   return GetData(aNodeValue);
00121 }
00122 
00123 nsresult
00124 nsGenericDOMDataNode::SetNodeValue(const nsAString& aNodeValue)
00125 {
00126   return SetData(aNodeValue);
00127 }
00128 
00129 nsresult
00130 nsGenericDOMDataNode::GetParentNode(nsIDOMNode** aParentNode)
00131 {
00132   nsresult rv = NS_OK;
00133 
00134   nsIContent *parent = GetParent();
00135   if (parent) {
00136     rv = CallQueryInterface(parent, aParentNode);
00137   }
00138   else if (IsInDoc()) {
00139     rv = CallQueryInterface(GetCurrentDoc(), aParentNode);
00140   }
00141   else {
00142     *aParentNode = nsnull;
00143   }
00144 
00145   NS_ASSERTION(NS_SUCCEEDED(rv), "Must be a DOM Node");
00146 
00147   return rv;
00148 }
00149 
00150 nsresult
00151 nsGenericDOMDataNode::GetPreviousSibling(nsIDOMNode** aPrevSibling)
00152 {
00153   nsresult rv = NS_OK;
00154 
00155   nsIContent *sibling = nsnull;
00156   nsIContent *parent = GetParent();
00157   if (parent) {
00158     PRInt32 pos = parent->IndexOf(this);
00159     if (pos > 0) {
00160       sibling = parent->GetChildAt(pos - 1);
00161     }
00162   }
00163   else {
00164     nsIDocument *doc = GetCurrentDoc();
00165     if (doc) {
00166       PRInt32 pos = doc->IndexOf(this);
00167       if (pos > 0) {
00168         sibling = doc->GetChildAt(pos - 1);
00169       }
00170     }
00171   }
00172 
00173   if (sibling) {
00174     rv = CallQueryInterface(sibling, aPrevSibling);
00175     NS_ASSERTION(NS_SUCCEEDED(rv), "Must be a DOM Node");
00176   } else {
00177     *aPrevSibling = nsnull;
00178   }
00179 
00180   return rv;
00181 }
00182 
00183 nsresult
00184 nsGenericDOMDataNode::GetNextSibling(nsIDOMNode** aNextSibling)
00185 {
00186   nsresult rv = NS_OK;
00187 
00188   nsIContent *sibling = nsnull;
00189   nsIContent *parent = GetParent();
00190   if (parent) {
00191     PRInt32 pos = parent->IndexOf(this);
00192     if (pos > -1) {
00193       sibling = parent->GetChildAt(pos + 1);
00194     }
00195   }
00196   else {
00197     nsIDocument *doc = GetCurrentDoc();
00198     if (doc) {
00199       PRInt32 pos = doc->IndexOf(this);
00200       if (pos > -1) {
00201         sibling = doc->GetChildAt(pos + 1);
00202       }
00203     }
00204   }
00205 
00206   if (sibling) {
00207     rv = CallQueryInterface(sibling, aNextSibling);
00208     NS_ASSERTION(NS_SUCCEEDED(rv), "Must be a DOM Node");
00209   } else {
00210     *aNextSibling = nsnull;
00211   }
00212 
00213   return rv;
00214 }
00215 
00216 nsresult
00217 nsGenericDOMDataNode::GetChildNodes(nsIDOMNodeList** aChildNodes)
00218 {
00219   // XXX Since we believe this won't be done very often, we won't
00220   // burn another slot in the data node and just create a new
00221   // (empty) childNodes list every time we're asked.
00222   nsChildContentList* list = new nsChildContentList(nsnull);
00223   if (!list) {
00224     return NS_ERROR_OUT_OF_MEMORY;
00225   }
00226 
00227   return CallQueryInterface(list, aChildNodes);
00228 }
00229 
00230 nsresult
00231 nsGenericDOMDataNode::GetOwnerDocument(nsIDOMDocument** aOwnerDocument)
00232 {
00233   nsIDocument *document = GetOwnerDoc();
00234   if (document) {
00235     return CallQueryInterface(document, aOwnerDocument);
00236   }
00237 
00238   *aOwnerDocument = nsnull;
00239 
00240   return NS_OK;
00241 }
00242 
00243 nsresult
00244 nsGenericDOMDataNode::GetNamespaceURI(nsAString& aNamespaceURI)
00245 {
00246   SetDOMStringToNull(aNamespaceURI);
00247 
00248   return NS_OK;
00249 }
00250 
00251 nsresult
00252 nsGenericDOMDataNode::GetPrefix(nsAString& aPrefix)
00253 {
00254   SetDOMStringToNull(aPrefix);
00255 
00256   return NS_OK;
00257 }
00258 
00259 nsresult
00260 nsGenericDOMDataNode::SetPrefix(const nsAString& aPrefix)
00261 {
00262   return NS_ERROR_DOM_NAMESPACE_ERR;
00263 }
00264 
00265 nsresult
00266 nsGenericDOMDataNode::GetLocalName(nsAString& aLocalName)
00267 {
00268   SetDOMStringToNull(aLocalName);
00269 
00270   return NS_OK;
00271 }
00272 
00273 nsresult
00274 nsGenericDOMDataNode::Normalize()
00275 {
00276   return NS_OK;
00277 }
00278 
00279 nsresult
00280 nsGenericDOMDataNode::IsSupported(const nsAString& aFeature,
00281                                   const nsAString& aVersion,
00282                                   PRBool* aReturn)
00283 {
00284   return nsGenericElement::InternalIsSupported(NS_STATIC_CAST(nsIContent*, this),
00285                                                aFeature, aVersion, aReturn);
00286 }
00287 
00288 nsresult
00289 nsGenericDOMDataNode::GetBaseURI(nsAString& aURI)
00290 {
00291   nsCOMPtr<nsIURI> baseURI = GetBaseURI();
00292   nsCAutoString spec;
00293 
00294   if (baseURI) {
00295     baseURI->GetSpec(spec);
00296   }
00297 
00298   CopyUTF8toUTF16(spec, aURI);
00299 
00300   return NS_OK;
00301 }
00302 
00303 nsresult
00304 nsGenericDOMDataNode::LookupPrefix(const nsAString& aNamespaceURI,
00305                                    nsAString& aPrefix)
00306 {
00307   aPrefix.Truncate();
00308 
00309   nsIContent *parent_weak = GetParent();
00310 
00311   // DOM Data Node passes the query on to its parent
00312   nsCOMPtr<nsIDOM3Node> node(do_QueryInterface(parent_weak));
00313   if (node) {
00314     return node->LookupPrefix(aNamespaceURI, aPrefix);
00315   }
00316 
00317   return NS_OK;
00318 }
00319 
00320 nsresult
00321 nsGenericDOMDataNode::LookupNamespaceURI(const nsAString& aNamespacePrefix,
00322                                          nsAString& aNamespaceURI)
00323 {
00324   aNamespaceURI.Truncate();
00325 
00326   nsIContent *parent_weak = GetParent();
00327 
00328   // DOM Data Node passes the query on to its parent
00329   nsCOMPtr<nsIDOM3Node> node(do_QueryInterface(parent_weak));
00330 
00331   if (node) {
00332     return node->LookupNamespaceURI(aNamespacePrefix, aNamespaceURI);
00333   }
00334 
00335   return NS_OK;
00336 }
00337 
00338 //----------------------------------------------------------------------
00339 
00340 // Implementation of nsIDOMCharacterData
00341 
00342 nsresult
00343 nsGenericDOMDataNode::GetData(nsAString& aData)
00344 {
00345   if (mText.Is2b()) {
00346     aData.Assign(mText.Get2b(), mText.GetLength());
00347   } else {
00348     // Must use Substring() since nsDependentCString() requires null
00349     // terminated strings.
00350 
00351     const char *data = mText.Get1b();
00352 
00353     if (data) {
00354       CopyASCIItoUCS2(Substring(data, data + mText.GetLength()), aData);
00355     } else {
00356       aData.Truncate();
00357     }
00358   }
00359 
00360   return NS_OK;
00361 }
00362 
00363 nsresult
00364 nsGenericDOMDataNode::SetData(const nsAString& aData)
00365 {
00366   // inform any enclosed ranges of change
00367   // we can lie and say we are deleting all the text, since in a total
00368   // text replacement we should just collapse all the ranges.
00369 
00370   nsVoidArray *rangeList = LookupRangeList();
00371   if (rangeList) {
00372     nsRange::TextOwnerChanged(this, rangeList, 0, mText.GetLength(), 0);
00373   }
00374 
00375   nsCOMPtr<nsITextContent> textContent = do_QueryInterface(this);
00376 
00377   SetText(aData, PR_TRUE);
00378 
00379   return NS_OK;
00380 }
00381 
00382 nsresult
00383 nsGenericDOMDataNode::GetLength(PRUint32* aLength)
00384 {
00385   *aLength = mText.GetLength();
00386   return NS_OK;
00387 }
00388 
00389 nsresult
00390 nsGenericDOMDataNode::SubstringData(PRUint32 aStart, PRUint32 aCount,
00391                                     nsAString& aReturn)
00392 {
00393   aReturn.Truncate();
00394 
00395   // XXX add <0 checks if types change
00396   PRUint32 textLength = PRUint32( mText.GetLength() );
00397   if (aStart > textLength) {
00398     return NS_ERROR_DOM_INDEX_SIZE_ERR;
00399   }
00400 
00401   PRUint32 amount = aCount;
00402   if (amount > textLength - aStart) {
00403     amount = textLength - aStart;
00404   }
00405 
00406   if (mText.Is2b()) {
00407     aReturn.Assign(mText.Get2b() + aStart, amount);
00408   } else {
00409     // Must use Substring() since nsDependentCString() requires null
00410     // terminated strings.
00411 
00412     const char *data = mText.Get1b() + aStart;
00413     CopyASCIItoUCS2(Substring(data, data + amount), aReturn);
00414   }
00415 
00416   return NS_OK;
00417 }
00418 
00419 //----------------------------------------------------------------------
00420 
00421 nsresult
00422 nsGenericDOMDataNode::AppendData(const nsAString& aData)
00423 {
00424   PRInt32 length = 0;
00425 
00426   // See bugzilla bug 77585.
00427   if (mText.Is2b() || (!IsASCII(aData))) {
00428     nsAutoString old_data;
00429     mText.AppendTo(old_data);
00430     length = old_data.Length();
00431     // XXXjag We'd like to just say |old_data + aData|, but due
00432     // to issues with dependent concatenation and sliding (sub)strings
00433     // we'll just have to copy for now. See bug 121841 for details.
00434     old_data.Append(aData);
00435     DoSetText(old_data, PR_TRUE, PR_TRUE);
00436   } else {
00437     // We know aData and the current data is ASCII, so use a
00438     // nsC*String, no need for any fancy unicode stuff here.
00439     nsCAutoString old_data;
00440     mText.AppendTo(old_data);
00441     length = old_data.Length();
00442     LossyAppendUTF16toASCII(aData, old_data);
00443     DoSetText(old_data.get(), old_data.Length(), PR_TRUE, PR_TRUE);
00444   }
00445 
00446   return NS_OK;
00447 }
00448 
00449 nsresult
00450 nsGenericDOMDataNode::InsertData(PRUint32 aOffset,
00451                                  const nsAString& aData)
00452 {
00453   return ReplaceData(aOffset, 0, aData);
00454 }
00455 
00456 nsresult
00457 nsGenericDOMDataNode::DeleteData(PRUint32 aOffset, PRUint32 aCount)
00458 {
00459   nsAutoString empty;
00460   return ReplaceData(aOffset, aCount, empty);
00461 }
00462 
00463 nsresult
00464 nsGenericDOMDataNode::ReplaceData(PRUint32 aOffset, PRUint32 aCount,
00465                                   const nsAString& aData)
00466 {
00467   // sanitize arguments
00468   PRUint32 textLength = mText.GetLength();
00469   if (aOffset > textLength) {
00470     return NS_ERROR_DOM_INDEX_SIZE_ERR;
00471   }
00472 
00473   // Fast path (hit by editor when typing at the end of the paragraph, for
00474   // example): aOffset == textLength (so just doing an append; note that in
00475   // this case any value of aCount would just get converted to 0 by the very
00476   // next if block).  Call AppendData so that we pass PR_TRUE for our aAppend
00477   // arg to CharacterDataChanged.
00478   if (aOffset == textLength) {
00479     return AppendData(aData);
00480   }
00481 
00482   // Allocate new buffer
00483   PRUint32 endOffset = aOffset + aCount;
00484   if (endOffset > textLength) {
00485     aCount = textLength - aOffset;
00486     endOffset = textLength;
00487   }
00488   PRInt32 dataLength = aData.Length();
00489   PRInt32 newLength = textLength - aCount + dataLength;
00490   PRUnichar* to = new PRUnichar[newLength + 1];
00491   if (!to) {
00492     return NS_ERROR_OUT_OF_MEMORY;
00493   }
00494 
00495   // inform any enclosed ranges of change
00496   nsVoidArray *rangeList = LookupRangeList();
00497   if (rangeList) {
00498     nsRange::TextOwnerChanged(this, rangeList, aOffset, endOffset, dataLength);
00499   }
00500 
00501   // Copy over appropriate data
00502   if (0 != aOffset) {
00503     mText.CopyTo(to, 0, aOffset);
00504   }
00505   if (0 != dataLength) {
00506     CopyUnicodeTo(aData, 0, to+aOffset, dataLength);
00507   }
00508   if (endOffset != textLength) {
00509     mText.CopyTo(to + aOffset + dataLength, endOffset, textLength - endOffset);
00510   }
00511 
00512   // Null terminate the new buffer...
00513   to[newLength] = (PRUnichar)0;
00514 
00515   SetText(to, newLength, PR_TRUE);
00516   delete [] to;
00517 
00518   return NS_OK;
00519 }
00520 
00521 //----------------------------------------------------------------------
00522 
00523 nsresult
00524 nsGenericDOMDataNode::GetListenerManager(nsIEventListenerManager **aResult)
00525 {
00526   nsCOMPtr<nsIEventListenerManager> listener_manager;
00527   LookupListenerManager(getter_AddRefs(listener_manager));
00528 
00529   if (listener_manager) {
00530     *aResult = listener_manager;
00531     NS_ADDREF(*aResult);
00532 
00533     return NS_OK;
00534   }
00535 
00536   if (!nsGenericElement::sEventListenerManagersHash.ops) {
00537     nsresult rv = nsGenericElement::InitHashes();
00538     NS_ENSURE_SUCCESS(rv, rv);
00539   }
00540 
00541   nsresult rv = NS_NewEventListenerManager(aResult);
00542   NS_ENSURE_SUCCESS(rv, rv);
00543 
00544   // Add a mapping to the hash table
00545   EventListenerManagerMapEntry *entry =
00546     NS_STATIC_CAST(EventListenerManagerMapEntry *,
00547                    PL_DHashTableOperate(&nsGenericElement::
00548                                         sEventListenerManagersHash, this,
00549                                         PL_DHASH_ADD));
00550 
00551   entry->mListenerManager = *aResult;
00552 
00553   entry->mListenerManager->SetListenerTarget(this);
00554 
00555   SetHasEventListenerManager();
00556 
00557   return NS_OK;
00558 }
00559 
00560 //----------------------------------------------------------------------
00561 
00562 // Implementation of nsIContent
00563 
00564 #ifdef DEBUG
00565 void
00566 nsGenericDOMDataNode::ToCString(nsAString& aBuf, PRInt32 aOffset,
00567                                 PRInt32 aLen) const
00568 {
00569   if (mText.Is2b()) {
00570     const PRUnichar* cp = mText.Get2b() + aOffset;
00571     const PRUnichar* end = cp + aLen;
00572 
00573     while (cp < end) {
00574       PRUnichar ch = *cp++;
00575       if (ch == '\r') {
00576         aBuf.AppendLiteral("\\r");
00577       } else if (ch == '\n') {
00578         aBuf.AppendLiteral("\\n");
00579       } else if (ch == '\t') {
00580         aBuf.AppendLiteral("\\t");
00581       } else if ((ch < ' ') || (ch >= 127)) {
00582         char buf[10];
00583         PR_snprintf(buf, sizeof(buf), "\\u%04x", ch);
00584         AppendASCIItoUTF16(buf, aBuf);
00585       } else {
00586         aBuf.Append(ch);
00587       }
00588     }
00589   } else {
00590     unsigned char* cp = (unsigned char*)mText.Get1b() + aOffset;
00591     const unsigned char* end = cp + aLen;
00592 
00593     while (cp < end) {
00594       PRUnichar ch = *cp++;
00595       if (ch == '\r') {
00596         aBuf.AppendLiteral("\\r");
00597       } else if (ch == '\n') {
00598         aBuf.AppendLiteral("\\n");
00599       } else if (ch == '\t') {
00600         aBuf.AppendLiteral("\\t");
00601       } else if ((ch < ' ') || (ch >= 127)) {
00602         char buf[10];
00603         PR_snprintf(buf, sizeof(buf), "\\u%04x", ch);
00604         AppendASCIItoUTF16(buf, aBuf);
00605       } else {
00606         aBuf.Append(ch);
00607       }
00608     }
00609   }
00610 }
00611 #endif
00612 
00613 nsIDocument*
00614 nsGenericDOMDataNode::GetDocument() const
00615 {
00616   return GetCurrentDoc();
00617 }
00618 
00622 nsIDOMGCParticipant*
00623 nsGenericDOMDataNode::GetSCCIndex()
00624 {
00625   // This is an optimized way of walking nsIDOMNode::GetParentNode to
00626   // the top of the tree.
00627   nsCOMPtr<nsIDOMGCParticipant> result = do_QueryInterface(GetCurrentDoc());
00628   if (!result) {
00629     nsIContent *top = this;
00630     while (top->GetParent())
00631       top = top->GetParent();
00632     result = do_QueryInterface(top);
00633   }
00634 
00635   return result;
00636 }
00637 
00638 void
00639 nsGenericDOMDataNode::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
00640 {
00641   NS_ASSERTION(GetCurrentDoc() == nsnull,
00642                "shouldn't be an SCC index if we're in a doc");
00643 
00644   // This node is the root of a subtree that's been removed from the
00645   // document (since AppendReachableList is only called on SCC index
00646   // nodes).  The document is reachable from it (through
00647   // .ownerDocument), but it's not reachable from the document.
00648   nsCOMPtr<nsIDOMGCParticipant> participant = do_QueryInterface(GetOwnerDoc());
00649   aArray.AppendObject(participant);
00650 }
00651 
00652 void
00653 nsGenericDOMDataNode::SetNodeInfoManager(nsNodeInfoManager* aNodeInfoManager)
00654 {
00655   nsNodeInfoManager* old = GetNodeInfoManager();
00656   if (old != aNodeInfoManager) {
00657     NS_IF_ADDREF(aNodeInfoManager);
00658     NS_IF_RELEASE(old);
00659     mNodeInfoManagerBits = (void*)(PtrBits(aNodeInfoManager) |
00660                                    (PtrBits(mNodeInfoManagerBits) &
00661                                     NODEINFOMANAGER_BIT_IS_NATIVE_ANONYMOUS));
00662   }
00663 }
00664 
00665 nsresult
00666 nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
00667                                  nsIContent* aBindingParent,
00668                                  PRBool aCompileEventHandlers)
00669 {
00670   NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
00671   // XXXbz XUL elements are confused about their current doc when they're
00672   // cloned, so we don't assert if aParent is a XUL element and aDocument is
00673   // null, even if aParent->GetCurrentDoc() is non-null
00674   //  NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(),
00675   //                  "aDocument must be current doc of aParent");
00676   NS_PRECONDITION(!aParent ||
00677                   (aParent->IsContentOfType(eXUL) && aDocument == nsnull) ||
00678                   aDocument == aParent->GetCurrentDoc(),
00679                   "aDocument must be current doc of aParent");
00680   NS_PRECONDITION(!GetCurrentDoc(), "Already have a document.  Unbind first!");
00681   // Note that as we recurse into the kids, they'll have a non-null parent.  So
00682   // only assert if our parent is _changing_ while we have a parent.
00683   NS_PRECONDITION(!GetParent() || aParent == GetParent(),
00684                   "Already have a parent.  Unbind first!");
00685   // XXXbz GetBindingParent() is broken for us, so can't assert
00686   // anything about it yet.
00687   //  NS_PRECONDITION(!GetBindingParent() ||
00688   //                  aBindingParent == GetBindingParent() ||
00689   //                  (aParent &&
00690   //                   aParent->GetBindingParent() == GetBindingParent()),
00691   //                  "Already have a binding parent.  Unbind first!");
00692 
00693   // XXXbz we don't keep track of the binding parent yet.  We should.
00694   
00695   // Set parent
00696   PtrBits new_bits = NS_REINTERPRET_CAST(PtrBits, aParent);
00697   new_bits |= mParentPtrBits & nsIContent::kParentBitMask;
00698   mParentPtrBits = new_bits;
00699 
00700   nsIDocument *oldOwnerDocument = GetOwnerDoc();
00701   nsIDocument *newOwnerDocument;
00702   nsNodeInfoManager* nodeInfoManager;
00703 
00704   // XXXbz sXBL/XBL2 issue!
00705   // Set document
00706   if (aDocument) {
00707     mParentPtrBits |= PARENT_BIT_INDOCUMENT;
00708     if (mText.IsBidi()) {
00709       aDocument->SetBidiEnabled(PR_TRUE);
00710     }
00711 
00712     newOwnerDocument = aDocument;
00713     nodeInfoManager = newOwnerDocument->NodeInfoManager();
00714   } else {
00715     newOwnerDocument = aParent->GetOwnerDoc();
00716     nodeInfoManager = aParent->GetNodeInfo()->NodeInfoManager();
00717   }
00718 
00719   if (oldOwnerDocument && oldOwnerDocument != newOwnerDocument) {
00720     // Remove all properties.
00721     oldOwnerDocument->PropertyTable()->DeleteAllPropertiesFor(this);
00722   }
00723 
00724   SetNodeInfoManager(nodeInfoManager);
00725 
00726   NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document");
00727   NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
00728   // XXXbz GetBindingParent() is broken for us, so can't assert
00729   // anything about it yet.
00730   //  NS_POSTCONDITION(aBindingParent = GetBindingParent(),
00731   //                   "Bound to wrong binding parent");
00732 
00733   return NS_OK;
00734 }
00735 
00736 void
00737 nsGenericDOMDataNode::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
00738 {
00739   mParentPtrBits &= ~PARENT_BIT_INDOCUMENT;
00740   if (aNullParent) {
00741     mParentPtrBits &= nsIContent::kParentBitMask;
00742   }
00743 }
00744 
00745 PRBool
00746 nsGenericDOMDataNode::IsNativeAnonymous() const
00747 {
00748   return !!(PtrBits(mNodeInfoManagerBits) & NODEINFOMANAGER_BIT_IS_NATIVE_ANONYMOUS);
00749 }
00750 
00751 void
00752 nsGenericDOMDataNode::SetNativeAnonymous(PRBool aAnonymous)
00753 {
00754   mNodeInfoManagerBits = (void*)
00755     (aAnonymous ? (PtrBits(mNodeInfoManagerBits) | NODEINFOMANAGER_BIT_IS_NATIVE_ANONYMOUS) :
00756                   (PtrBits(mNodeInfoManagerBits) & ~NODEINFOMANAGER_BIT_IS_NATIVE_ANONYMOUS));
00757 }
00758 
00759 PRInt32
00760 nsGenericDOMDataNode::GetNameSpaceID() const
00761 {
00762   return kNameSpaceID_None;
00763 }
00764 
00765 nsIAtom *
00766 nsGenericDOMDataNode::GetIDAttributeName() const
00767 {
00768   return nsnull;
00769 }
00770 
00771 already_AddRefed<nsINodeInfo>
00772 nsGenericDOMDataNode::GetExistingAttrNameFromQName(const nsAString& aStr) const
00773 {
00774   return nsnull;
00775 }
00776 
00777 nsresult
00778 nsGenericDOMDataNode::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttr,
00779                               nsIAtom* aPrefix, const nsAString& aValue,
00780                               PRBool aNotify)
00781 {
00782   return NS_OK;
00783 }
00784 
00785 nsresult
00786 nsGenericDOMDataNode::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttr,
00787                                 PRBool aNotify)
00788 {
00789   return NS_OK;
00790 }
00791 
00792 nsresult
00793 nsGenericDOMDataNode::GetAttr(PRInt32 aNameSpaceID, nsIAtom *aAttr,
00794                               nsAString& aResult) const
00795 {
00796   aResult.Truncate();
00797 
00798   return NS_CONTENT_ATTR_NOT_THERE;
00799 }
00800 
00801 PRBool
00802 nsGenericDOMDataNode::HasAttr(PRInt32 aNameSpaceID, nsIAtom *aAttribute) const
00803 {
00804   return PR_FALSE;
00805 }
00806 
00807 nsresult
00808 nsGenericDOMDataNode::GetAttrNameAt(PRUint32 aIndex, PRInt32* aNameSpaceID,
00809                                     nsIAtom** aName, nsIAtom** aPrefix) const
00810 {
00811   *aNameSpaceID = kNameSpaceID_None;
00812   *aName = nsnull;
00813   *aPrefix = nsnull;
00814 
00815   return NS_ERROR_ILLEGAL_VALUE;
00816 }
00817 
00818 PRUint32
00819 nsGenericDOMDataNode::GetAttrCount() const
00820 {
00821   return 0;
00822 }
00823 
00824 nsresult
00825 nsGenericDOMDataNode::HandleDOMEvent(nsPresContext* aPresContext,
00826                                      nsEvent* aEvent, nsIDOMEvent** aDOMEvent,
00827                                      PRUint32 aFlags,
00828                                      nsEventStatus* aEventStatus)
00829 {
00830   // Make sure to tell the event that dispatch has started.
00831   NS_MARK_EVENT_DISPATCH_STARTED(aEvent);
00832 
00833   nsresult ret = NS_OK;
00834   nsIDOMEvent* domEvent = nsnull;
00835 
00836   PRBool externalDOMEvent = PR_FALSE;
00837 
00838   if (NS_EVENT_FLAG_INIT & aFlags) {
00839     if (!aDOMEvent) {
00840       aDOMEvent = &domEvent;
00841     } else {
00842       externalDOMEvent = PR_TRUE;
00843     }
00844 
00845     aEvent->flags |= aFlags;
00846     aFlags &= ~(NS_EVENT_FLAG_CANT_BUBBLE | NS_EVENT_FLAG_CANT_CANCEL);
00847     aFlags |= NS_EVENT_FLAG_BUBBLE | NS_EVENT_FLAG_CAPTURE;
00848   }
00849 
00850   nsIContent *parent = GetParent();
00851 
00852   //Capturing stage evaluation
00853   if ((NS_EVENT_FLAG_CAPTURE & aFlags) &&
00854       !(IsNativeAnonymous() && aEvent->eventStructType == NS_MUTATION_EVENT)) {
00855     //Initiate capturing phase.  Special case first call to document
00856     if (parent) {
00857       parent->HandleDOMEvent(aPresContext, aEvent, aDOMEvent,
00858                              aFlags & NS_EVENT_CAPTURE_MASK, aEventStatus);
00859     }
00860     else {
00861       nsIDocument *document = GetCurrentDoc();
00862       if (document) {
00863         document->HandleDOMEvent(aPresContext, aEvent, aDOMEvent,
00864                                  aFlags & NS_EVENT_CAPTURE_MASK,
00865                                  aEventStatus);
00866       }
00867     }
00868   }
00869 
00870   nsCOMPtr<nsIEventListenerManager> listener_manager;
00871   LookupListenerManager(getter_AddRefs(listener_manager));
00872 
00873   //Local handling stage
00874   //Check for null ELM, check if we're a non-bubbling event in the bubbling state (bubbling state
00875   //is indicated by the presence of the NS_EVENT_FLAG_BUBBLE flag and not the NS_EVENT_FLAG_INIT), and check 
00876   //if we're a no content dispatch event
00877   if (listener_manager &&
00878        !(NS_EVENT_FLAG_CANT_BUBBLE & aEvent->flags && NS_EVENT_FLAG_BUBBLE & aFlags && !(NS_EVENT_FLAG_INIT & aFlags)) &&
00879        !(aEvent->flags & NS_EVENT_FLAG_NO_CONTENT_DISPATCH)) {
00880     aEvent->flags |= aFlags;
00881     listener_manager->HandleEvent(aPresContext, aEvent, aDOMEvent, nsnull,
00882                                   aFlags, aEventStatus);
00883     aEvent->flags &= ~aFlags;
00884   }
00885 
00886   //Bubbling stage
00887   if ((NS_EVENT_FLAG_BUBBLE & aFlags) && parent &&
00888       !(IsNativeAnonymous() && aEvent->eventStructType == NS_MUTATION_EVENT)) {
00889     ret = parent->HandleDOMEvent(aPresContext, aEvent, aDOMEvent,
00890                                  aFlags & NS_EVENT_BUBBLE_MASK, aEventStatus);
00891   }
00892 
00893   if (NS_EVENT_FLAG_INIT & aFlags) {
00894     // We're leaving the DOM event loop so if we created a DOM event,
00895     // release here.
00896 
00897     if (!externalDOMEvent && *aDOMEvent) {
00898       if (0 != (*aDOMEvent)->Release()) {
00899         // Okay, so someone in the DOM loop (a listener, JS object)
00900         // still has a ref to the DOM Event but the internal data
00901         // hasn't been malloc'd.  Force a copy of the data here so the
00902         // DOM Event is still valid.
00903 
00904         nsCOMPtr<nsIPrivateDOMEvent> privateEvent =
00905           do_QueryInterface(*aDOMEvent);
00906 
00907         if (privateEvent) {
00908           privateEvent->DuplicatePrivateData();
00909         }
00910       }
00911     }
00912 
00913     aDOMEvent = nsnull;
00914 
00915     // Now that we're done with this event, remove the flag that says
00916     // we're in the process of dispatching this event.
00917     NS_MARK_EVENT_DISPATCH_DONE(aEvent);
00918   }
00919 
00920   return ret;
00921 }
00922 
00923 PRUint32
00924 nsGenericDOMDataNode::ContentID() const
00925 {
00926   return 0;
00927 }
00928 
00929 nsINodeInfo *
00930 nsGenericDOMDataNode::GetNodeInfo() const
00931 {
00932   return nsnull;
00933 }
00934 
00935 PRUint32
00936 nsGenericDOMDataNode::GetChildCount() const
00937 {
00938   return 0;
00939 }
00940 
00941 nsIContent *
00942 nsGenericDOMDataNode::GetChildAt(PRUint32 aIndex) const
00943 {
00944   return nsnull;
00945 }
00946 
00947 PRInt32
00948 nsGenericDOMDataNode::IndexOf(nsIContent* aPossibleChild) const
00949 {
00950   return -1;
00951 }
00952 
00953 nsresult
00954 nsGenericDOMDataNode::InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
00955                                     PRBool aNotify)
00956 {
00957   return NS_OK;
00958 }
00959 
00960 nsresult
00961 nsGenericDOMDataNode::AppendChildTo(nsIContent* aKid, PRBool aNotify)
00962 {
00963   return NS_OK;
00964 }
00965 
00966 nsresult
00967 nsGenericDOMDataNode::RemoveChildAt(PRUint32 aIndex, PRBool aNotify)
00968 {
00969   return NS_OK;
00970 }
00971 
00972 // virtual
00973 PRBool
00974 nsGenericDOMDataNode::MayHaveFrame() const
00975 {
00976   nsIContent* parent = GetParent();
00977   return parent && parent->MayHaveFrame();
00978 }
00979 
00980 nsresult
00981 nsGenericDOMDataNode::RangeAdd(nsIDOMRange* aRange)
00982 {
00983   // lazy allocation of range list
00984 
00985   if (!nsGenericElement::sRangeListsHash.ops) {
00986     nsresult rv = nsGenericElement::InitHashes();
00987     NS_ENSURE_SUCCESS(rv, rv);
00988   }
00989 
00990   RangeListMapEntry *entry =
00991     NS_STATIC_CAST(RangeListMapEntry *,
00992                    PL_DHashTableOperate(&nsGenericElement::sRangeListsHash,
00993                                         this, PL_DHASH_ADD));
00994 
00995   if (!entry) {
00996     return NS_ERROR_OUT_OF_MEMORY;
00997   }
00998 
00999   nsVoidArray *range_list = entry->mRangeList;
01000 
01001   if (!range_list) {
01002     range_list = new nsAutoVoidArray();
01003 
01004     if (!range_list) {
01005       PL_DHashTableRawRemove(&nsGenericElement::sRangeListsHash, entry);
01006 
01007       return NS_ERROR_OUT_OF_MEMORY;
01008     }
01009 
01010     entry->mRangeList = range_list;
01011 
01012     SetHasRangeList();
01013   } else {
01014     // Make sure we don't add a range that is already
01015     // in the list!
01016     PRInt32 i = range_list->IndexOf(aRange);
01017 
01018     if (i >= 0) {
01019       // Range is already in the list, so there is nothing to do!
01020 
01021       return NS_OK;
01022     }
01023   }
01024 
01025   // dont need to addref - this call is made by the range object itself
01026   PRBool rv = range_list->AppendElement(aRange);
01027 
01028   return rv ? NS_OK : NS_ERROR_FAILURE;
01029 }
01030 
01031 
01032 void
01033 nsGenericDOMDataNode::RangeRemove(nsIDOMRange* aRange)
01034 {
01035   if (!CouldHaveRangeList()) {
01036     return;
01037   }
01038 
01039   RangeListMapEntry *entry =
01040     NS_STATIC_CAST(RangeListMapEntry *,
01041                    PL_DHashTableOperate(&nsGenericElement::sRangeListsHash,
01042                                         this, PL_DHASH_LOOKUP));
01043 
01044   // Don't need to release: this call is made by the range object itself.
01045   if (entry && PL_DHASH_ENTRY_IS_BUSY(entry) &&
01046       entry->mRangeList->RemoveElement(aRange) &&
01047       entry->mRangeList->Count() == 0) {
01048     PL_DHashTableRawRemove(&nsGenericElement::sRangeListsHash, entry);
01049   }
01050 }
01051 
01052 const nsVoidArray *
01053 nsGenericDOMDataNode::GetRangeList() const
01054 {
01055   return LookupRangeList();
01056 }
01057 
01058 nsIContent *
01059 nsGenericDOMDataNode::GetBindingParent() const
01060 {
01061   nsIContent* parent = GetParent();
01062   return parent ? parent->GetBindingParent() : nsnull;
01063 }
01064 
01065 PRBool
01066 nsGenericDOMDataNode::IsContentOfType(PRUint32 aFlags) const
01067 {
01068   return PR_FALSE;
01069 }
01070 
01071 #ifdef DEBUG
01072 void
01073 nsGenericDOMDataNode::List(FILE* out, PRInt32 aIndent) const
01074 {
01075 }
01076 
01077 void
01078 nsGenericDOMDataNode::DumpContent(FILE* out, PRInt32 aIndent,
01079                                   PRBool aDumpAll) const 
01080 {
01081 }
01082 #endif
01083 
01084 already_AddRefed<nsIURI>
01085 nsGenericDOMDataNode::GetBaseURI() const
01086 {
01087   // DOM Data Node inherits the base from its parent element/document
01088   nsIContent *parent = GetParent();
01089   if (parent) {
01090     return parent->GetBaseURI();
01091   }
01092 
01093   nsIURI *uri;
01094   nsIDocument *doc = GetOwnerDoc();
01095   if (doc) {
01096     NS_IF_ADDREF(uri = doc->GetBaseURI());
01097   }
01098   else {
01099     uri = nsnull;
01100   }
01101 
01102   return uri;
01103 }
01104 
01105 //----------------------------------------------------------------------
01106 
01107 // Implementation of the nsIDOMText interface
01108 
01109 nsresult
01110 nsGenericDOMDataNode::SplitText(PRUint32 aOffset, nsIDOMText** aReturn)
01111 {
01112   nsresult rv = NS_OK;
01113   nsAutoString cutText;
01114   PRUint32 length = TextLength();
01115 
01116   if (aOffset > length) {
01117     return NS_ERROR_DOM_INDEX_SIZE_ERR;
01118   }
01119 
01120   rv = SubstringData(aOffset, length - aOffset, cutText);
01121   if (NS_FAILED(rv)) {
01122     return rv;
01123   }
01124 
01125   rv = DeleteData(aOffset, length - aOffset);
01126   if (NS_FAILED(rv)) {
01127     return rv;
01128   }
01129 
01130   /*
01131    * Use CloneContent() for creating the new node so that the new node is of
01132    * same class as this node!
01133    */
01134 
01135   nsCOMPtr<nsITextContent> newContent = CloneContent(PR_FALSE,
01136                                                      GetNodeInfoManager());
01137   if (!newContent) {
01138     return NS_ERROR_OUT_OF_MEMORY;
01139   }
01140 
01141   newContent->SetText(cutText, PR_TRUE);
01142 
01143   nsIContent* parent = GetParent();
01144 
01145   if (parent) {
01146     PRInt32 index = parent->IndexOf(this);
01147 
01148     nsCOMPtr<nsIContent> content(do_QueryInterface(newContent));
01149 
01150     parent->InsertChildAt(content, index+1, PR_TRUE);
01151   }
01152 
01153   // XXX Shouldn't we handle the case where this is a child of the document?
01154 
01155   return CallQueryInterface(newContent, aReturn);
01156 }
01157 
01158 //----------------------------------------------------------------------
01159 
01160 // Implementation of the nsITextContent interface
01161 
01162 const nsTextFragment *
01163 nsGenericDOMDataNode::Text()
01164 {
01165   return &mText;
01166 }
01167 
01168 PRUint32
01169 nsGenericDOMDataNode::TextLength()
01170 {
01171   return mText.GetLength();
01172 }
01173 
01174 void
01175 nsGenericDOMDataNode::DoSetText(const PRUnichar* aBuffer, PRUint32 aLength,
01176                                 PRBool aIsAppend, PRBool aNotify)
01177 {
01178   if (!aBuffer) {
01179     NS_ERROR("Null buffer passed to SetText()!");
01180 
01181     return;
01182   }
01183 
01184   nsIDocument *document = GetCurrentDoc();
01185   mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
01186 
01187   PRBool haveMutationListeners =
01188     document && nsGenericElement::HasMutationListeners(this, NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED);
01189 
01190   nsCOMPtr<nsIAtom> oldValue;
01191   if (haveMutationListeners) {
01192     oldValue = GetCurrentValueAtom();
01193   }
01194     
01195   mText.SetTo(aBuffer, aLength);
01196 
01197   SetBidiStatus();
01198 
01199   // Trigger a reflow
01200   if (aNotify && document) {
01201     document->CharacterDataChanged(this, aIsAppend);
01202   }
01203 
01204   if (haveMutationListeners) {
01205     nsCOMPtr<nsIDOMEventTarget> node(do_QueryInterface(this));
01206     nsMutationEvent mutation(PR_TRUE, NS_MUTATION_CHARACTERDATAMODIFIED, node);
01207 
01208     mutation.mPrevAttrValue = oldValue;
01209     if (aLength > 0) {
01210       // Must use Substring() since nsDependentString() requires null
01211       // terminated strings.
01212       mutation.mNewAttrValue =
01213         do_GetAtom(Substring(aBuffer, aBuffer + aLength));
01214     }
01215 
01216     nsEventStatus status = nsEventStatus_eIgnore;
01217     HandleDOMEvent(nsnull, &mutation, nsnull,
01218                    NS_EVENT_FLAG_INIT, &status);
01219   }
01220 }
01221 
01222 void
01223 nsGenericDOMDataNode::DoSetText(const char* aBuffer, PRUint32 aLength,
01224                                 PRBool aIsAppend, PRBool aNotify)
01225 {
01226   if (!aBuffer) {
01227     NS_ERROR("Null buffer passed to SetText()!");
01228 
01229     return;
01230   }
01231 
01232   nsIDocument *document = GetCurrentDoc();
01233   mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
01234 
01235   PRBool haveMutationListeners =
01236     document && nsGenericElement::HasMutationListeners(this, NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED);
01237 
01238   nsCOMPtr<nsIAtom> oldValue;
01239   if (haveMutationListeners) {
01240     oldValue = GetCurrentValueAtom();
01241   }
01242     
01243   mText.SetTo(aBuffer, aLength);
01244 
01245   // Trigger a reflow
01246   if (aNotify && document) {
01247     document->CharacterDataChanged(this, aIsAppend);
01248   }
01249 
01250   if (haveMutationListeners) {
01251     nsCOMPtr<nsIDOMEventTarget> node(do_QueryInterface(this));
01252     nsMutationEvent mutation(PR_TRUE, NS_MUTATION_CHARACTERDATAMODIFIED, node);
01253 
01254     mutation.mPrevAttrValue = oldValue;
01255     if (aLength > 0) {
01256       // Must use Substring() since nsDependentCString() requires null
01257       // terminated strings.
01258       mutation.mNewAttrValue =
01259         do_GetAtom(Substring(aBuffer, aBuffer + aLength));
01260     }
01261 
01262     nsEventStatus status = nsEventStatus_eIgnore;
01263     HandleDOMEvent(nsnull, &mutation, nsnull,
01264                    NS_EVENT_FLAG_INIT, &status);
01265   }
01266 }
01267 
01268 void
01269 nsGenericDOMDataNode::DoSetText(const nsAString& aStr, PRBool aIsAppend,
01270                                 PRBool aNotify)
01271 {
01272   nsIDocument *document = GetCurrentDoc();
01273   mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
01274 
01275   PRBool haveMutationListeners =
01276     document && nsGenericElement::HasMutationListeners(this, NS_EVENT_BITS_MUTATION_CHARACTERDATAMODIFIED);
01277 
01278   nsCOMPtr<nsIAtom> oldValue;
01279   if (haveMutationListeners) {
01280     oldValue = GetCurrentValueAtom();
01281   }
01282 
01283   mText = aStr;
01284 
01285   SetBidiStatus();
01286 
01287   // Trigger a reflow
01288   if (aNotify && document) {
01289     document->CharacterDataChanged(this, aIsAppend);
01290   }
01291 
01292   if (haveMutationListeners) {
01293     nsCOMPtr<nsIDOMEventTarget> node(do_QueryInterface(this));
01294     nsMutationEvent mutation(PR_TRUE, NS_MUTATION_CHARACTERDATAMODIFIED, node);
01295 
01296     mutation.mPrevAttrValue = oldValue;
01297     if (!aStr.IsEmpty())
01298       mutation.mNewAttrValue = do_GetAtom(aStr);
01299     nsEventStatus status = nsEventStatus_eIgnore;
01300     HandleDOMEvent(nsnull, &mutation, nsnull,
01301                    NS_EVENT_FLAG_INIT, &status);
01302   }
01303 }
01304 
01305 PRBool
01306 nsGenericDOMDataNode::IsOnlyWhitespace()
01307 {
01308   nsTextFragment& frag = mText;
01309   if (frag.Is2b()) {
01310     const PRUnichar* cp = frag.Get2b();
01311     const PRUnichar* end = cp + frag.GetLength();
01312 
01313     while (cp < end) {
01314       PRUnichar ch = *cp++;
01315 
01316       if (!XP_IS_SPACE(ch)) {
01317         return PR_FALSE;
01318       }
01319     }
01320   } else {
01321     const char* cp = frag.Get1b();
01322     const char* end = cp + frag.GetLength();
01323 
01324     while (cp < end) {
01325       PRUnichar ch = PRUnichar(*(unsigned char*)cp);
01326       ++cp;
01327 
01328       if (!XP_IS_SPACE(ch)) {
01329         return PR_FALSE;
01330       }
01331     }
01332   }
01333 
01334   return PR_TRUE;
01335 }
01336 
01337 void
01338 nsGenericDOMDataNode::AppendTextTo(nsAString& aResult)
01339 {
01340   mText.AppendTo(aResult);
01341 }
01342 
01343 void
01344 nsGenericDOMDataNode::LookupListenerManager(nsIEventListenerManager **aListenerManager) const
01345 {
01346   *aListenerManager = nsnull;
01347 
01348   if (!CouldHaveEventListenerManager()) {
01349     return;
01350   }
01351 
01352   EventListenerManagerMapEntry *entry =
01353     NS_STATIC_CAST(EventListenerManagerMapEntry *,
01354                    PL_DHashTableOperate(&nsGenericElement::
01355                                         sEventListenerManagersHash, this,
01356                                         PL_DHASH_LOOKUP));
01357 
01358   if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
01359     *aListenerManager = entry->mListenerManager;
01360     NS_ADDREF(*aListenerManager);
01361   }
01362 }
01363 
01364 nsVoidArray *
01365 nsGenericDOMDataNode::LookupRangeList() const
01366 {
01367   if (!CouldHaveRangeList()) {
01368     return nsnull;
01369   }
01370 
01371   RangeListMapEntry *entry =
01372     NS_STATIC_CAST(RangeListMapEntry *,
01373                    PL_DHashTableOperate(&nsGenericElement::sRangeListsHash,
01374                                         this, PL_DHASH_LOOKUP));
01375 
01376   if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
01377     return entry->mRangeList;
01378   }
01379 
01380   return nsnull;
01381 }
01382 
01383 void nsGenericDOMDataNode::SetBidiStatus()
01384 {
01385   nsIDocument *document = GetCurrentDoc();
01386   if (document && document->GetBidiEnabled()) {
01387     // OK, we already know it's Bidi, so we won't test again
01388     return;
01389   }
01390 
01391   mText.SetBidiFlag();
01392 
01393   if (document && mText.IsBidi()) {
01394     document->SetBidiEnabled(PR_TRUE);
01395   }
01396 }
01397 
01398 already_AddRefed<nsIAtom>
01399 nsGenericDOMDataNode::GetCurrentValueAtom()
01400 {
01401   nsAutoString val;
01402   GetData(val);
01403   return NS_NewAtom(val);
01404 }
01405 
01406 already_AddRefed<nsITextContent> 
01407 nsGenericDOMDataNode::CloneContent(PRBool aCloneText,
01408                                    nsNodeInfoManager *aNodeInfoManager)
01409 {
01410   NS_ERROR("Huh, this shouldn't be called!");
01411 
01412   return nsnull;
01413 }