Back to index

lightning-sunbird  0.9+nobinonly
nsDocument.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* vim: set ts=2 sw=2 et tw=78: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Johnny Stenback <jst@netscape.com>
00025  *   L. David Baron  <dbaron@dbaron.org>
00026  *   Pierre Phaneuf  <pp@ludusdesign.com>
00027  *   Pete Collins    <petejc@collab.net>
00028  *   James Ross      <silver@warwickcompsocc.o.uk>
00029  *
00030  * Alternatively, the contents of this file may be used under the terms of
00031  * either of the GNU General Public License Version 2 or later (the "GPL"),
00032  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00033  * in which case the provisions of the GPL or the LGPL are applicable instead
00034  * of those above. If you wish to allow use of your version of this file only
00035  * under the terms of either the GPL or the LGPL, and not to allow others to
00036  * use your version of this file under the terms of the MPL, indicate your
00037  * decision by deleting the provisions above and replace them with the notice
00038  * and other provisions required by the GPL or the LGPL. If you do not delete
00039  * the provisions above, a recipient may use your version of this file under
00040  * the terms of any one of the MPL, the GPL or the LGPL.
00041  *
00042  * ***** END LICENSE BLOCK ***** */
00043 #include "plstr.h"
00044 #include "prprf.h"
00045 
00046 #include "nsIInterfaceRequestor.h"
00047 #include "nsIInterfaceRequestorUtils.h"
00048 #include "nsDocument.h"
00049 #include "nsUnicharUtils.h"
00050 #include "nsIPrivateDOMEvent.h"
00051 #include "nsIEventStateManager.h"
00052 #include "nsContentList.h"
00053 #include "nsIObserver.h"
00054 #include "nsIBaseWindow.h"
00055 #include "nsIDocShell.h"
00056 #include "nsIDocShellTreeItem.h"
00057 #include "nsCOMArray.h"
00058 
00059 #include "nsGUIEvent.h"
00060 
00061 #include "nsIDOMStyleSheet.h"
00062 #include "nsDOMAttribute.h"
00063 #include "nsIDOMDOMImplementation.h"
00064 #include "nsIDOMDocumentView.h"
00065 #include "nsIDOMAbstractView.h"
00066 #include "nsIDOMDocumentXBL.h"
00067 #include "nsGenericElement.h"
00068 #include "nsIDOMEventGroup.h"
00069 #include "nsIDOMCDATASection.h"
00070 #include "nsIDOMProcessingInstruction.h"
00071 #include "nsDOMString.h"
00072 
00073 #include "nsRange.h"
00074 #include "nsIDOMText.h"
00075 #include "nsIDOMComment.h"
00076 #include "nsDOMDocumentType.h"
00077 #include "nsTreeWalker.h"
00078 
00079 #include "nsIServiceManager.h"
00080 
00081 #include "nsContentCID.h"
00082 #include "nsDOMError.h"
00083 #include "nsIScrollableView.h"
00084 #include "nsIPresShell.h"
00085 #include "nsPresContext.h"
00086 #include "nsContentUtils.h"
00087 #include "nsNodeInfoManager.h"
00088 #include "nsIXBLService.h"
00089 #include "nsIXPointer.h"
00090 #include "nsIFileChannel.h"
00091 #include "nsIMultiPartChannel.h"
00092 #include "nsIRefreshURI.h"
00093 #include "nsIWebNavigation.h"
00094 
00095 #include "nsNetUtil.h"     // for NS_MakeAbsoluteURI
00096 
00097 #include "nsIScriptSecurityManager.h"
00098 #include "nsIPrincipal.h"
00099 #include "nsIPrivateDOMImplementation.h"
00100 
00101 #include "nsIDOMWindowInternal.h"
00102 #include "nsPIDOMWindow.h"
00103 #include "nsIDOMElement.h"
00104 
00105 #include "nsIBoxObject.h"
00106 #include "nsPIBoxObject.h"
00107 #include "nsXULAtoms.h"
00108 
00109 // for radio group stuff
00110 #include "nsIDOMHTMLInputElement.h"
00111 #include "nsIRadioVisitor.h"
00112 #include "nsIFormControl.h"
00113 
00114 #include "nsXMLEventsManager.h"
00115 
00116 #include "nsBidiUtils.h"
00117 
00118 static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID);
00119 
00120 #include "nsILineBreakerFactory.h"
00121 #include "nsIWordBreakerFactory.h"
00122 #include "nsLWBrkCIID.h"
00123 
00124 #include "nsHTMLAtoms.h"
00125 
00126 #include "nsScriptEventManager.h"
00127 #include "nsIXPathEvaluatorInternal.h"
00128 #include "nsIParserService.h"
00129 #include "nsContentCreatorFunctions.h"
00130 
00131 #include "nsIScriptContext.h"
00132 #include "nsBindingManager.h"
00133 #include "nsIDOMHTMLFormElement.h"
00134 #include "nsIRequest.h"
00135 #include "nsILink.h"
00136 
00137 #include "nsICharsetAlias.h"
00138 #include "nsIParser.h"
00139 
00140 #include "nsDateTimeFormatCID.h"
00141 #include "nsIDateTimeFormat.h"
00142 
00143 #include "nsLayoutStatics.h"
00144 
00145 #ifdef MOZ_LOGGING
00146 // so we can get logging even in release builds
00147 #define FORCE_PR_LOG 1
00148 #endif
00149 #include "prlog.h"
00150 
00151 #ifdef PR_LOGGING
00152 static PRLogModuleInfo* gDocumentLeakPRLog;
00153 #endif
00154 
00155 static NS_DEFINE_CID(kCharsetAliasCID, NS_CHARSETALIAS_CID);
00156 static NS_DEFINE_CID(kDateTimeFormatCID, NS_DATETIMEFORMAT_CID);
00157 
00158 void
00159 nsUint32ToContentHashEntry::Destroy()
00160 {
00161   HashSet* set = GetHashSet();
00162   if (set) {
00163     delete set;
00164   } else {
00165     nsIContent* content = GetContent();
00166     NS_IF_RELEASE(content);
00167   }
00168 }
00169 
00170 nsresult
00171 nsUint32ToContentHashEntry::PutContent(nsIContent* aVal)
00172 {
00173   // Add the value to the hash if it is there
00174   HashSet* set = GetHashSet();
00175   if (set) {
00176     nsISupportsHashKey* entry = set->PutEntry(aVal);
00177     return entry ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00178   }
00179 
00180   // If an element is already there, create a hashtable and both of these to it
00181   if (GetContent()) {
00182     nsIContent* oldVal = GetContent();
00183     nsresult rv = InitHashSet(&set);
00184     NS_ENSURE_SUCCESS(rv, rv);
00185 
00186     nsISupportsHashKey* entry = set->PutEntry(oldVal);
00187     if (!entry)
00188       return NS_ERROR_OUT_OF_MEMORY;
00189     // The hashset adds its own reference, so release the one we had
00190     NS_RELEASE(oldVal);
00191 
00192     entry = set->PutEntry(aVal);
00193     return entry ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00194   }
00195 
00196   // Nothing exists in the hash right now, so just set the single pointer
00197   return SetContent(aVal);
00198 }
00199 
00200 void
00201 nsUint32ToContentHashEntry::RemoveContent(nsIContent* aVal)
00202 {
00203   // Remove from the hash if the hash is there
00204   HashSet* set = GetHashSet();
00205   if (set) {
00206     set->RemoveEntry(aVal);
00207     if (set->Count() == 0) {
00208       delete set;
00209       mValOrHash = nsnull;
00210     }
00211     return;
00212   }
00213 
00214   // Remove the ptr if there is just a ptr
00215   nsIContent* v = GetContent();
00216   if (v == aVal) {
00217     NS_IF_RELEASE(v);
00218     mValOrHash = nsnull;
00219   }
00220 }
00221 
00222 nsresult
00223 nsUint32ToContentHashEntry::InitHashSet(HashSet** aSet)
00224 {
00225   HashSet* newSet = new HashSet();
00226   if (!newSet) {
00227     return NS_ERROR_OUT_OF_MEMORY;
00228   }
00229 
00230   nsresult rv = newSet->Init();
00231   NS_ENSURE_SUCCESS(rv, rv);
00232 
00233   mValOrHash = newSet;
00234   *aSet = newSet;
00235   return NS_OK;
00236 }
00237 
00238 static PLDHashOperator PR_CALLBACK
00239 nsUint32ToContentHashEntryVisitorCallback(nsISupportsHashKey* aEntry,
00240                                           void* aClosure)
00241 {
00242   nsUint32ToContentHashEntry::Visitor* visitor =
00243     NS_STATIC_CAST(nsUint32ToContentHashEntry::Visitor*, aClosure);
00244   visitor->Visit(NS_STATIC_CAST(nsIContent*, aEntry->GetKey()));
00245   return PL_DHASH_NEXT;
00246 }
00247 
00248 void
00249 nsUint32ToContentHashEntry::VisitContent(Visitor* aVisitor)
00250 {
00251   HashSet* set = GetHashSet();
00252   if (set) {
00253     set->EnumerateEntries(nsUint32ToContentHashEntryVisitorCallback, aVisitor);
00254     if (set->Count() == 0) {
00255       delete set;
00256       mValOrHash = nsnull;
00257     }
00258     return;
00259   }
00260 
00261   nsIContent* v = GetContent();
00262   if (v) {
00263     aVisitor->Visit(v);
00264   }
00265 }
00266 
00267 // Helper structs for the content->subdoc map
00268 
00269 class SubDocMapEntry : public PLDHashEntryHdr
00270 {
00271 public:
00272   // Both of these are strong references
00273   nsIContent *mKey; // must be first, to look like PLDHashEntryStub
00274   nsIDocument *mSubDocument;
00275 };
00276 
00277 struct FindContentData
00278 {
00279   FindContentData(nsIDocument *aSubDoc)
00280     : mSubDocument(aSubDoc), mResult(nsnull)
00281   {
00282   }
00283 
00284   nsISupports *mSubDocument;
00285   nsIContent *mResult;
00286 };
00287 
00288 
00292 struct nsRadioGroupStruct
00293 {
00297   nsCOMPtr<nsIDOMHTMLInputElement> mSelectedRadioButton;
00298   nsSmallVoidArray mRadioButtons;
00299 };
00300 
00301 
00302 nsDOMStyleSheetList::nsDOMStyleSheetList(nsIDocument *aDocument)
00303 {
00304   mLength = -1;
00305   // Not reference counted to avoid circular references.
00306   // The document will tell us when its going away.
00307   mDocument = aDocument;
00308   mDocument->AddObserver(this);
00309 }
00310 
00311 nsDOMStyleSheetList::~nsDOMStyleSheetList()
00312 {
00313   if (mDocument) {
00314     mDocument->RemoveObserver(this);
00315   }
00316 }
00317 
00318 
00319 // XXX couldn't we use the GetIIDs method from CSSStyleSheetList here?
00320 // QueryInterface implementation for nsDOMStyleSheetList
00321 NS_INTERFACE_MAP_BEGIN(nsDOMStyleSheetList)
00322   NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheetList)
00323   NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
00324   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStyleSheetList)
00325   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(DocumentStyleSheetList)
00326 NS_INTERFACE_MAP_END
00327 
00328 
00329 NS_IMPL_ADDREF(nsDOMStyleSheetList)
00330 NS_IMPL_RELEASE(nsDOMStyleSheetList)
00331 
00332 
00333 NS_IMETHODIMP
00334 nsDOMStyleSheetList::GetLength(PRUint32* aLength)
00335 {
00336   if (mDocument) {
00337     // XXX Find the number and then cache it. We'll use the
00338     // observer notification to figure out if new ones have
00339     // been added or removed.
00340     if (-1 == mLength) {
00341       mLength = mDocument->GetNumberOfStyleSheets();
00342 
00343 #ifdef DEBUG
00344       PRInt32 i;
00345       for (i = 0; i < mLength; i++) {
00346         nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(i);
00347         nsCOMPtr<nsIDOMStyleSheet> domss(do_QueryInterface(sheet));
00348         NS_ASSERTION(domss, "All \"normal\" sheets implement nsIDOMStyleSheet");
00349       }
00350 #endif
00351     }
00352     *aLength = mLength;
00353   }
00354   else {
00355     *aLength = 0;
00356   }
00357 
00358   return NS_OK;
00359 }
00360 
00361 NS_IMETHODIMP
00362 nsDOMStyleSheetList::Item(PRUint32 aIndex, nsIDOMStyleSheet** aReturn)
00363 {
00364   *aReturn = nsnull;
00365   if (mDocument) {
00366     PRInt32 count = mDocument->GetNumberOfStyleSheets();
00367     if (aIndex < (PRUint32)count) {
00368       nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(aIndex);
00369       NS_ASSERTION(sheet, "Must have a sheet");
00370       return CallQueryInterface(sheet, aReturn);
00371     }
00372   }
00373 
00374   return NS_OK;
00375 }
00376 
00377 void
00378 nsDOMStyleSheetList::DocumentWillBeDestroyed(nsIDocument *aDocument)
00379 {
00380   if (nsnull != mDocument) {
00381     aDocument->RemoveObserver(this);
00382     mDocument = nsnull;
00383   }
00384 }
00385 
00386 void
00387 nsDOMStyleSheetList::StyleSheetAdded(nsIDocument *aDocument,
00388                                      nsIStyleSheet* aStyleSheet,
00389                                      PRBool aDocumentSheet)
00390 {
00391   if (aDocumentSheet && -1 != mLength) {
00392     nsCOMPtr<nsIDOMStyleSheet> domss(do_QueryInterface(aStyleSheet));
00393     if (domss) {
00394       mLength++;
00395     }
00396   }
00397 }
00398 
00399 void
00400 nsDOMStyleSheetList::StyleSheetRemoved(nsIDocument *aDocument,
00401                                        nsIStyleSheet* aStyleSheet,
00402                                        PRBool aDocumentSheet)
00403 {
00404   if (aDocumentSheet && -1 != mLength) {
00405     nsCOMPtr<nsIDOMStyleSheet> domss(do_QueryInterface(aStyleSheet));
00406     if (domss) {
00407       mLength--;
00408     }
00409   }
00410 }
00411 
00412 // nsOnloadBlocker implementation
00413 NS_IMPL_ISUPPORTS1(nsOnloadBlocker, nsIRequest)
00414 
00415 NS_IMETHODIMP
00416 nsOnloadBlocker::GetName(nsACString &aResult)
00417 { 
00418   aResult.AssignLiteral("about:document-onload-blocker");
00419   return NS_OK;
00420 }
00421 
00422 NS_IMETHODIMP
00423 nsOnloadBlocker::IsPending(PRBool *_retval)
00424 {
00425   *_retval = PR_TRUE;
00426   return NS_OK;
00427 }
00428 
00429 NS_IMETHODIMP
00430 nsOnloadBlocker::GetStatus(nsresult *status)
00431 {
00432   *status = NS_OK;
00433   return NS_OK;
00434 } 
00435 
00436 NS_IMETHODIMP
00437 nsOnloadBlocker::Cancel(nsresult status)
00438 {
00439   return NS_OK;
00440 }
00441 NS_IMETHODIMP
00442 nsOnloadBlocker::Suspend(void)
00443 {
00444   return NS_OK;
00445 }
00446 NS_IMETHODIMP
00447 nsOnloadBlocker::Resume(void)
00448 {
00449   return NS_OK;
00450 }
00451 
00452 NS_IMETHODIMP
00453 nsOnloadBlocker::GetLoadGroup(nsILoadGroup * *aLoadGroup)
00454 {
00455   *aLoadGroup = nsnull;
00456   return NS_OK;
00457 }
00458 
00459 NS_IMETHODIMP
00460 nsOnloadBlocker::SetLoadGroup(nsILoadGroup * aLoadGroup)
00461 {
00462   return NS_OK;
00463 }
00464 
00465 NS_IMETHODIMP
00466 nsOnloadBlocker::GetLoadFlags(nsLoadFlags *aLoadFlags)
00467 {
00468   *aLoadFlags = nsIRequest::LOAD_NORMAL;
00469   return NS_OK;
00470 }
00471 
00472 NS_IMETHODIMP
00473 nsOnloadBlocker::SetLoadFlags(nsLoadFlags aLoadFlags)
00474 {
00475   return NS_OK;
00476 }
00477 
00478 
00479 class nsDOMImplementation : public nsIDOMDOMImplementation,
00480                             public nsIPrivateDOMImplementation
00481 {
00482 public:
00483   nsDOMImplementation(nsIScriptGlobalObject* aScriptObject,
00484                       nsIURI* aBaseURI = nsnull);
00485   virtual ~nsDOMImplementation();
00486 
00487   NS_DECL_ISUPPORTS
00488 
00489   // nsIDOMDOMImplementation
00490   NS_DECL_NSIDOMDOMIMPLEMENTATION
00491 
00492   // nsIPrivateDOMImplementation
00493   NS_IMETHOD Init(nsIURI* aBaseURI);
00494 
00495 protected:
00496   nsWeakPtr mScriptObject;
00497   nsCOMPtr<nsIURI> mBaseURI;
00498 };
00499 
00500 
00501 nsresult
00502 NS_NewDOMImplementation(nsIDOMDOMImplementation** aInstancePtrResult)
00503 {
00504   *aInstancePtrResult = new nsDOMImplementation(nsnull);
00505   if (!*aInstancePtrResult) {
00506     return NS_ERROR_OUT_OF_MEMORY;
00507   }
00508 
00509   NS_ADDREF(*aInstancePtrResult);
00510 
00511   return NS_OK;
00512 }
00513 
00514 nsDOMImplementation::nsDOMImplementation(nsIScriptGlobalObject* aScriptObject,
00515                                          nsIURI* aBaseURI)
00516 {
00517   mScriptObject = do_GetWeakReference(aScriptObject);
00518   mBaseURI = aBaseURI;
00519 }
00520 
00521 nsDOMImplementation::~nsDOMImplementation()
00522 {
00523 }
00524 
00525 // QueryInterface implementation for nsDOMImplementation
00526 NS_INTERFACE_MAP_BEGIN(nsDOMImplementation)
00527   NS_INTERFACE_MAP_ENTRY(nsIDOMDOMImplementation)
00528   NS_INTERFACE_MAP_ENTRY(nsIPrivateDOMImplementation)
00529   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDOMImplementation)
00530   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(DOMImplementation)
00531 NS_INTERFACE_MAP_END
00532 
00533 
00534 NS_IMPL_ADDREF(nsDOMImplementation)
00535 NS_IMPL_RELEASE(nsDOMImplementation)
00536 
00537 
00538 NS_IMETHODIMP
00539 nsDOMImplementation::HasFeature(const nsAString& aFeature,
00540                                 const nsAString& aVersion,
00541                                 PRBool* aReturn)
00542 {
00543   return nsGenericElement::InternalIsSupported(
00544            NS_STATIC_CAST(nsIDOMDOMImplementation*, this),
00545            aFeature, aVersion, aReturn);
00546 }
00547 
00548 NS_IMETHODIMP
00549 nsDOMImplementation::CreateDocumentType(const nsAString& aQualifiedName,
00550                                         const nsAString& aPublicId,
00551                                         const nsAString& aSystemId,
00552                                         nsIDOMDocumentType** aReturn)
00553 {
00554   *aReturn = nsnull;
00555 
00556   nsresult rv = nsContentUtils::CheckQName(aQualifiedName);
00557   NS_ENSURE_SUCCESS(rv, rv);
00558 
00559   nsCOMPtr<nsIAtom> name = do_GetAtom(aQualifiedName);
00560   NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
00561 
00562   nsCOMPtr<nsIPrincipal> principal;
00563   rv = nsContentUtils::GetSecurityManager()->
00564     GetCodebasePrincipal(mBaseURI, getter_AddRefs(principal));
00565   NS_ENSURE_SUCCESS(rv, rv);
00566     
00567   return NS_NewDOMDocumentType(aReturn, nsnull, principal, name, nsnull,
00568                                nsnull, aPublicId, aSystemId, EmptyString());
00569 }
00570 
00571 NS_IMETHODIMP
00572 nsDOMImplementation::CreateDocument(const nsAString& aNamespaceURI,
00573                                     const nsAString& aQualifiedName,
00574                                     nsIDOMDocumentType* aDoctype,
00575                                     nsIDOMDocument** aReturn)
00576 {
00577   *aReturn = nsnull;
00578 
00579   nsresult rv;
00580   if (!aQualifiedName.IsEmpty()) {
00581     nsIParserService *parserService =
00582       nsContentUtils::GetParserServiceWeakRef();
00583     NS_ENSURE_TRUE(parserService, NS_ERROR_FAILURE);
00584 
00585     const nsAFlatString& qName = PromiseFlatString(aQualifiedName);
00586     const PRUnichar *colon;
00587     rv = parserService->CheckQName(qName, PR_TRUE, &colon);
00588     NS_ENSURE_SUCCESS(rv, rv);
00589 
00590     if (colon &&
00591         (DOMStringIsNull(aNamespaceURI) ||
00592          (Substring(qName.get(), colon).EqualsLiteral("xml") &&
00593           !aNamespaceURI.EqualsLiteral("http://www.w3.org/XML/1998/namespace")))) {
00594       return NS_ERROR_DOM_NAMESPACE_ERR;
00595     }
00596   }
00597   else if (DOMStringIsNull(aQualifiedName) &&
00598            !DOMStringIsNull(aNamespaceURI)) {
00599     return NS_ERROR_DOM_NAMESPACE_ERR;
00600   }
00601 
00602   if (aDoctype) {
00603     nsCOMPtr<nsIDOMDocument> owner;
00604     aDoctype->GetOwnerDocument(getter_AddRefs(owner));
00605     if (owner) {
00606       return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
00607     }
00608   }
00609 
00610   nsCOMPtr<nsIScriptGlobalObject> scriptHandlingObject =
00611     do_QueryReferent(mScriptObject);
00612 
00613   rv = NS_NewDOMDocument_MOZILLA_1_8_BRANCH(aReturn, aNamespaceURI,
00614                                             aQualifiedName, aDoctype,
00615                                             mBaseURI, scriptHandlingObject,
00616                                             PR_TRUE);
00617 
00618   nsIDocShell *docShell = nsContentUtils::GetDocShellFromCaller();
00619   if (docShell) {
00620     nsCOMPtr<nsPresContext> presContext;
00621     docShell->GetPresContext(getter_AddRefs(presContext));
00622     if (presContext) {
00623       nsCOMPtr<nsISupports> container = presContext->GetContainer();
00624       nsCOMPtr<nsIDocument> document = do_QueryInterface(*aReturn);
00625       if (document) {
00626         document->SetContainer(container);
00627       }
00628     }
00629   }
00630 
00631   return rv;
00632 }
00633 
00634 NS_IMETHODIMP
00635 nsDOMImplementation::Init(nsIURI* aBaseURI)
00636 {
00637   mBaseURI = aBaseURI;
00638   return NS_OK;
00639 }
00640 
00641 PRBool
00642 nsDocumentObserverList::PrependElement(nsIDocumentObserver* aObserver)
00643 {
00644   PRBool prepended = mObservers.InsertElementAt(aObserver, 0);
00645 
00646   // This introduces an inconsistency -- forward iterators will not see the new
00647   // element, while backwards ones will.  That's kinda inherent in the
00648   // different iteration orders, though.
00649   if (prepended) {
00650     for (Iterator* iter = mIterators; iter; iter = iter->mNext) {
00651       iter->mPosition++;
00652     }
00653   }
00654 
00655   return prepended;
00656 }
00657 
00658 PRBool
00659 nsDocumentObserverList::RemoveElement(nsIDocumentObserver* aElement)
00660 {
00661   PRInt32 index = mObservers.IndexOf(aElement);
00662   if (index == -1) {
00663     return PR_FALSE;
00664   }
00665 
00666 #ifdef DEBUG
00667   PRBool removed =
00668 #endif
00669     mObservers.RemoveElementAt(index);
00670   NS_ASSERTION(removed, "How could we fail to remove by index?");
00671 
00672   for (Iterator* iter = mIterators; iter; iter = iter->mNext) {
00673     // If iter->mPosition == index then forward iterators are safe, since in
00674     // that case the position is not affected by the removal; all that's
00675     // affected is what element is at that position.  Backward iterators,
00676     // however, need to decrement mPosition in that case.
00677     if (iter->mPosition > index ||
00678         (iter->mPosition == index && iter->mStep < 0)) {
00679       iter->mPosition--;
00680     }
00681   }
00682   
00683   return PR_TRUE;
00684 }
00685 
00686 void
00687 nsDocumentObserverList::Clear()
00688 {
00689   mObservers.Clear(); 
00690 
00691   // Reset all iterators to a bogus position so they don't return
00692   // anything next time they're called.
00693   for (Iterator* iter = mIterators; iter; iter = iter->mNext) {
00694     iter->mPosition = -1;
00695   }
00696 }
00697 
00698 nsIDocumentObserver*
00699 nsDocumentObserverList::Iterator::GetNext()
00700 {
00701   nsIDocumentObserver* ret =
00702     NS_STATIC_CAST(nsIDocumentObserver*,
00703                    mList.mObservers.SafeElementAt(mPosition));
00704   mPosition += mStep;
00705   return ret;
00706 }
00707 
00708 // ==================================================================
00709 // =
00710 // ==================================================================
00711 
00712 nsDocumentChildNodes::nsDocumentChildNodes(nsIDocument* aDocument)
00713 {
00714   MOZ_COUNT_CTOR(nsDocumentChildNodes);
00715 
00716   // We don't reference count our document reference (to avoid circular
00717   // references). We'll be told when the document goes away.
00718   mDocument = aDocument;
00719 }
00720 
00721 nsDocumentChildNodes::~nsDocumentChildNodes()
00722 {
00723   MOZ_COUNT_DTOR(nsDocumentChildNodes);
00724 }
00725 
00726 NS_IMETHODIMP
00727 nsDocumentChildNodes::GetLength(PRUint32* aLength)
00728 {
00729   if (mDocument) {
00730     *aLength = mDocument->GetChildCount();
00731   } else {
00732     *aLength = 0;
00733   }
00734 
00735   return NS_OK;
00736 }
00737 
00738 NS_IMETHODIMP
00739 nsDocumentChildNodes::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
00740 {
00741   *aReturn = nsnull;
00742 
00743   if (mDocument) {
00744     nsIContent *content = mDocument->GetChildAt(aIndex);
00745 
00746     if (content) {
00747       return CallQueryInterface(content, aReturn);
00748     }
00749   }
00750 
00751   return NS_OK;
00752 }
00753 
00754 void
00755 nsDocumentChildNodes::DropReference()
00756 {
00757   mDocument = nsnull;
00758 }
00759 
00760 class nsXPathDocumentTearoff : public nsIDOMXPathEvaluator
00761 {
00762 public:
00763   nsXPathDocumentTearoff(nsIDOMXPathEvaluator* aEvaluator,
00764                          nsIDocument* aDocument)
00765     : mEvaluator(aEvaluator), mDocument(aDocument)
00766   {
00767   }
00768   virtual ~nsXPathDocumentTearoff()
00769   {
00770   }
00771 
00772   NS_DECL_ISUPPORTS_INHERITED
00773 
00774   NS_FORWARD_NSIDOMXPATHEVALUATOR(mEvaluator->)
00775 
00776 private:
00777   nsCOMPtr<nsIDOMXPathEvaluator> mEvaluator;
00778   nsIDocument* mDocument;
00779 };
00780 
00781 NS_INTERFACE_MAP_BEGIN(nsXPathDocumentTearoff)
00782   NS_INTERFACE_MAP_ENTRY(nsIDOMXPathEvaluator)
00783 NS_INTERFACE_MAP_END_AGGREGATED(mDocument)
00784 
00785 NS_IMPL_ADDREF_USING_AGGREGATOR(nsXPathDocumentTearoff, mDocument)
00786 NS_IMPL_RELEASE_USING_AGGREGATOR(nsXPathDocumentTearoff, mDocument)
00787 
00788 
00789 // ==================================================================
00790 // =
00791 // ==================================================================
00792 
00793   // NOTE! nsDocument::operator new() zeroes out all members, so don't
00794   // bother initializing members to 0.
00795 
00796 nsDocument::nsDocument()
00797   : nsIDocument(),
00798     nsIDocument_MOZILLA_1_8_BRANCH2(),
00799     mVisible(PR_TRUE)
00800 {
00801   nsLayoutStatics::AddRef();
00802 
00803 #ifdef PR_LOGGING
00804   if (!gDocumentLeakPRLog)
00805     gDocumentLeakPRLog = PR_NewLogModule("DocumentLeak");
00806 
00807   if (gDocumentLeakPRLog)
00808     PR_LOG(gDocumentLeakPRLog, PR_LOG_DEBUG,
00809            ("DOCUMENT %p created", this));
00810 #endif
00811 }
00812 
00813 PR_STATIC_CALLBACK(PRBool)
00814 DropBoxObjectDocumentReference(nsHashKey* aKey, void* aData, void* aClosure)
00815 {
00816   nsISupports* data = NS_STATIC_CAST(nsISupports*, aData);
00817   nsCOMPtr<nsPIBoxObject> boxObject(do_QueryInterface(data));
00818   if (boxObject) {
00819     boxObject->SetDocument(nsnull);
00820   }
00821   return PR_TRUE;
00822 }
00823 
00824 nsDocument::~nsDocument()
00825 {
00826 #ifdef PR_LOGGING
00827   if (gDocumentLeakPRLog)
00828     PR_LOG(gDocumentLeakPRLog, PR_LOG_DEBUG,
00829            ("DOCUMENT %p destroyed", this));
00830 #endif
00831 
00832   mInDestructor = PR_TRUE;
00833 
00834   // XXX Inform any remaining observers that we are going away.
00835   // Note that this currently contradicts the rule that all
00836   // observers must hold on to live references to the document.
00837   // This notification will occur only after the reference has
00838   // been dropped.
00839 
00840   PRInt32 indx;
00841   NS_DOCUMENT_NOTIFY_OBSERVERS(DocumentWillBeDestroyed, (this));
00842 
00843   mParentDocument = nsnull;
00844 
00845   // Kill the subdocument map, doing this will release its strong
00846   // references, if any.
00847   if (mSubDocuments) {
00848     PL_DHashTableDestroy(mSubDocuments);
00849 
00850     mSubDocuments = nsnull;
00851   }
00852 
00853   if (mRootContent) {
00854     if (mRootContent->GetCurrentDoc()) {
00855       NS_ASSERTION(mRootContent->GetCurrentDoc() == this,
00856                    "Unexpected current doc in root content");
00857       // The root content still has a pointer back to the document,
00858       // clear the document pointer in all children.
00859       
00860       // Destroy link map now so we don't waste time removing
00861       // links one by one
00862       DestroyLinkMap();
00863 
00864       PRUint32 count = mChildren.ChildCount();
00865       for (indx = PRInt32(count) - 1; indx >= 0; --indx) {
00866         mChildren.ChildAt(indx)->UnbindFromTree();
00867         mChildren.RemoveChildAt(indx);
00868       }
00869     }
00870   }
00871 
00872   mRootContent = nsnull;
00873 
00874   // Let the stylesheets know we're going away
00875   indx = mStyleSheets.Count();
00876   while (--indx >= 0) {
00877     mStyleSheets[indx]->SetOwningDocument(nsnull);
00878   }
00879   indx = mCatalogSheets.Count();
00880   while (--indx >= 0) {
00881     mCatalogSheets[indx]->SetOwningDocument(nsnull);
00882   }
00883   if (mAttrStyleSheet)
00884     mAttrStyleSheet->SetOwningDocument(nsnull);
00885   if (mStyleAttrStyleSheet)
00886     mStyleAttrStyleSheet->SetOwningDocument(nsnull);
00887 
00888   if (mChildNodes) {
00889     mChildNodes->DropReference();
00890   }
00891 
00892   if (mListenerManager) {
00893     mListenerManager->Disconnect();
00894   }
00895 
00896   if (mScriptLoader) {
00897     mScriptLoader->DropDocumentReference();
00898   }
00899 
00900   if (mCSSLoader) {
00901     // Could be null here if Init() failed
00902     mCSSLoader->DropDocumentReference();
00903     NS_RELEASE(mCSSLoader);
00904   }
00905 
00906   // XXX Ideally we'd do this cleanup in the nsIDocument destructor.
00907   if (mNodeInfoManager) {
00908     mNodeInfoManager->DropDocumentReference();
00909     NS_RELEASE(mNodeInfoManager);
00910   }
00911 
00912   if (mAttrStyleSheet) {
00913     mAttrStyleSheet->SetOwningDocument(nsnull);
00914   }
00915   
00916   if (mStyleAttrStyleSheet) {
00917     mStyleAttrStyleSheet->SetOwningDocument(nsnull);
00918   }
00919 
00920   delete mHeaderData;
00921   if (mBoxObjectTable) {
00922     mBoxObjectTable->Enumerate(DropBoxObjectDocumentReference, nsnull);
00923     delete mBoxObjectTable;
00924   }
00925   delete mXPathDocument;
00926   nsLayoutStatics::Release();
00927 }
00928 
00929 PRBool gCheckedForXPathDOM = PR_FALSE;
00930 PRBool gHaveXPathDOM = PR_FALSE;
00931 
00932 NS_INTERFACE_MAP_BEGIN(nsDocument)
00933   NS_INTERFACE_MAP_ENTRY(nsIDocument)
00934   NS_INTERFACE_MAP_ENTRY(nsIDocument_MOZILLA_1_8_0_BRANCH)
00935   NS_INTERFACE_MAP_ENTRY(nsIDocument_MOZILLA_1_8_BRANCH2)
00936   NS_INTERFACE_MAP_ENTRY(nsIDocument_MOZILLA_1_8_BRANCH3)
00937   NS_INTERFACE_MAP_ENTRY(nsIDOMDocument)
00938   NS_INTERFACE_MAP_ENTRY(nsIDOMNSDocument)
00939   NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentEvent)
00940   NS_INTERFACE_MAP_ENTRY(nsIDOM3DocumentEvent)
00941   NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentStyle)
00942   NS_INTERFACE_MAP_ENTRY(nsIDOMNSDocumentStyle)
00943   NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentView)
00944   NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentRange)
00945   NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentTraversal)
00946   NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentXBL)
00947   NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
00948   NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
00949   NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
00950   NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
00951   NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
00952   NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
00953   NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
00954   NS_INTERFACE_MAP_ENTRY(nsIDOM3Node)
00955   NS_INTERFACE_MAP_ENTRY(nsIDOM3Document)
00956   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
00957   NS_INTERFACE_MAP_ENTRY(nsIRadioGroupContainer)
00958   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocument)
00959   if (aIID.Equals(NS_GET_IID(nsIDOMXPathEvaluator)) &&
00960       (!gCheckedForXPathDOM || gHaveXPathDOM)) {
00961     if (!mXPathDocument) {
00962       nsCOMPtr<nsIDOMXPathEvaluator> evaluator;
00963       nsresult rv;
00964       evaluator = do_CreateInstance(NS_XPATH_EVALUATOR_CONTRACTID, &rv);
00965       gCheckedForXPathDOM = PR_TRUE;
00966       gHaveXPathDOM = (evaluator != nsnull);
00967       if (rv == NS_ERROR_FACTORY_NOT_REGISTERED) {
00968           return NS_ERROR_NO_INTERFACE;
00969       }
00970       NS_ENSURE_SUCCESS(rv, rv);
00971 
00972       nsCOMPtr<nsIXPathEvaluatorInternal> internal =
00973           do_QueryInterface(evaluator);
00974       if (internal) {
00975           internal->SetDocument(this);
00976       }
00977 
00978       mXPathDocument = new nsXPathDocumentTearoff(evaluator, this);
00979       NS_ENSURE_TRUE(mXPathDocument, NS_ERROR_OUT_OF_MEMORY);
00980     }
00981     foundInterface = mXPathDocument;
00982   }
00983   else
00984 NS_INTERFACE_MAP_END
00985 
00986 NS_IMPL_ADDREF(nsDocument)
00987 NS_IMPL_RELEASE(nsDocument)
00988 
00989 nsresult
00990 nsDocument::Init()
00991 {
00992   if (mBindingManager || mCSSLoader || mNodeInfoManager || mScriptLoader) {
00993     return NS_ERROR_ALREADY_INITIALIZED;
00994   }
00995 
00996   mLinkMap.Init();
00997 
00998   // Force initialization.
00999   nsBindingManager *bindingManager = new nsBindingManager(this);
01000   NS_ENSURE_TRUE(bindingManager, NS_ERROR_OUT_OF_MEMORY);
01001   mBindingManager = bindingManager;
01002 
01003   // The binding manager must always be the first observer of the document.
01004   if (!mObservers.PrependElement(bindingManager)) {
01005     return NS_ERROR_OUT_OF_MEMORY;
01006   }
01007 
01008   mOnloadBlocker = new nsOnloadBlocker();
01009   NS_ENSURE_TRUE(mOnloadBlocker, NS_ERROR_OUT_OF_MEMORY);
01010   
01011   NS_NewCSSLoader(this, &mCSSLoader);
01012   NS_ENSURE_TRUE(mCSSLoader, NS_ERROR_OUT_OF_MEMORY);
01013   // Assume we're not HTML and not quirky, until we know otherwise
01014   mCSSLoader->SetCaseSensitive(PR_TRUE);
01015   mCSSLoader->SetCompatibilityMode(eCompatibility_FullStandards);
01016 
01017   mScriptLoader = new nsScriptLoader();
01018   NS_ENSURE_TRUE(mScriptLoader, NS_ERROR_OUT_OF_MEMORY);
01019   mScriptLoader->Init(this);
01020 
01021   mNodeInfoManager = new nsNodeInfoManager();
01022   NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_OUT_OF_MEMORY);
01023 
01024   NS_ADDREF(mNodeInfoManager);
01025 
01026   return mNodeInfoManager->Init(this);
01027 }
01028 
01029 nsresult
01030 nsDocument::AddXMLEventsContent(nsIContent *aXMLEventsElement)
01031 {
01032   if (!mXMLEventsManager) {
01033     mXMLEventsManager = new nsXMLEventsManager();
01034     NS_ENSURE_TRUE(mXMLEventsManager, NS_ERROR_OUT_OF_MEMORY);
01035     AddObserver(mXMLEventsManager);
01036   }
01037   mXMLEventsManager->AddXMLEventsContent(aXMLEventsElement);
01038   return NS_OK;
01039 }
01040 
01041 void
01042 nsDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup)
01043 {
01044   nsCOMPtr<nsIURI> uri;
01045   if (aChannel) {
01046     // Note: this code is duplicated in nsXULDocument::StartDocumentLoad.
01047     // Note: this should match nsDocShell::OnLoadingSite
01048     nsLoadFlags loadFlags = 0;
01049     nsresult rv = aChannel->GetLoadFlags(&loadFlags);
01050     if (NS_SUCCEEDED(rv) && (loadFlags & nsIChannel::LOAD_REPLACE)) {
01051       aChannel->GetURI(getter_AddRefs(uri));
01052     } else {
01053       aChannel->GetOriginalURI(getter_AddRefs(uri));
01054     }
01055   }
01056 
01057   ResetToURI(uri, aLoadGroup);
01058 
01059   if (aChannel) {
01060     nsCOMPtr<nsISupports> owner;
01061     aChannel->GetOwner(getter_AddRefs(owner));
01062 
01063     mPrincipal = do_QueryInterface(owner);
01064   }
01065 
01066   mChannel = aChannel;
01067 }
01068 
01069 void
01070 nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup)
01071 {
01072   NS_PRECONDITION(aURI, "Null URI passed to ResetToURI");
01073 
01074 #ifdef PR_LOGGING
01075   if (gDocumentLeakPRLog && PR_LOG_TEST(gDocumentLeakPRLog, PR_LOG_DEBUG)) {
01076     nsCAutoString spec;
01077     aURI->GetSpec(spec);
01078     PR_LogPrint("DOCUMENT %p ResetToURI %s", this, spec.get());
01079   }
01080 #endif
01081 
01082   mDocumentTitle.SetIsVoid(PR_TRUE);
01083 
01084   mPrincipal = nsnull;
01085   mSecurityInfo = nsnull;
01086 
01087   mDocumentLoadGroup = nsnull;
01088 
01089   // Delete references to sub-documents and kill the subdocument map,
01090   // if any. It holds strong references
01091   if (mSubDocuments) {
01092     PL_DHashTableDestroy(mSubDocuments);
01093 
01094     mSubDocuments = nsnull;
01095   }
01096 
01097   // Destroy link map now so we don't waste time removing
01098   // links one by one
01099   DestroyLinkMap();
01100 
01101   mRootContent = nsnull;
01102   PRUint32 count = mChildren.ChildCount();
01103   for (PRInt32 i = PRInt32(count) - 1; i >= 0; i--) {
01104     nsCOMPtr<nsIContent> content = mChildren.ChildAt(i);
01105 
01106     ContentRemoved(nsnull, content, i);
01107     content->UnbindFromTree();
01108     mChildren.RemoveChildAt(i);
01109   }
01110 
01111   // Reset our stylesheets
01112   ResetStylesheetsToURI(aURI);
01113   
01114   // Release the listener manager
01115   if (mListenerManager) {
01116     mListenerManager->Disconnect();
01117     mListenerManager = nsnull;
01118   }
01119 
01120   // Release the stylesheets list.
01121   mDOMStyleSheets = nsnull;
01122 
01123   mDocumentURI = aURI;
01124   mDocumentBaseURI = mDocumentURI;
01125 
01126   if (aLoadGroup) {
01127     mDocumentLoadGroup = do_GetWeakReference(aLoadGroup);
01128     // there was an assertion here that aLoadGroup was not null.  This
01129     // is no longer valid nsWebShell::SetDocument does not create a
01130     // load group, and it works just fine.
01131   }
01132 
01133   mLastModified.Truncate();
01134   mContentType.Truncate();
01135   mContentLanguage.Truncate();
01136   mBaseTarget.Truncate();
01137   mReferrer.Truncate();
01138 
01139   mXMLDeclarationBits = 0;
01140 }
01141 
01142 nsresult
01143 nsDocument::ResetStylesheetsToURI(nsIURI* aURI)
01144 {
01145   NS_PRECONDITION(aURI, "Null URI passed to ResetStylesheetsToURI");
01146 
01147   mozAutoDocUpdate(this, UPDATE_STYLE, PR_TRUE);
01148   
01149   // The stylesheets should forget us
01150   PRInt32 indx = mStyleSheets.Count();
01151   while (--indx >= 0) {
01152     nsIStyleSheet* sheet = mStyleSheets[indx];
01153     sheet->SetOwningDocument(nsnull);
01154 
01155     PRBool applicable;
01156     sheet->GetApplicable(applicable);
01157     if (applicable) {
01158       RemoveStyleSheetFromStyleSets(sheet);
01159     }
01160 
01161     // XXX Tell observers?
01162   }
01163 
01164   indx = mCatalogSheets.Count();
01165   while (--indx >= 0) {
01166     nsIStyleSheet* sheet = mCatalogSheets[indx];
01167     sheet->SetOwningDocument(nsnull);
01168 
01169     PRBool applicable;
01170     sheet->GetApplicable(applicable);
01171     if (applicable) {
01172       for (PRInt32 i = 0, i_end = mPresShells.Count(); i < i_end; ++i) {
01173         NS_STATIC_CAST(nsIPresShell*, mPresShells.ElementAt(i))->StyleSet()->
01174           RemoveStyleSheet(nsStyleSet::eAgentSheet, sheet);
01175       }
01176     }
01177 
01178     // XXX Tell observers?
01179   }
01180 
01181 
01182   // Release all the sheets
01183   mStyleSheets.Clear();
01184   // NOTE:  We don't release the catalog sheets.  It doesn't really matter
01185   // now, but it could in the future -- in which case not releasing them
01186   // is probably the right thing to do.
01187 
01188   // Now reset our inline style and attribute sheets.
01189   nsresult rv;
01190   nsStyleSet::sheetType attrSheetType = GetAttrSheetType();
01191   if (mAttrStyleSheet) {
01192     // Remove this sheet from all style sets
01193     PRInt32 count = mPresShells.Count();
01194     for (indx = 0; indx < count; ++indx) {
01195       NS_STATIC_CAST(nsIPresShell*, mPresShells.ElementAt(indx))->StyleSet()->
01196         RemoveStyleSheet(attrSheetType, mAttrStyleSheet);
01197     }
01198     rv = mAttrStyleSheet->Reset(aURI);
01199   } else {
01200     rv = NS_NewHTMLStyleSheet(getter_AddRefs(mAttrStyleSheet), aURI, this);
01201   }
01202   NS_ENSURE_SUCCESS(rv, rv);
01203 
01204   // Don't use AddStyleSheet, since it'll put the sheet into style
01205   // sets in the document level, which is not desirable here.
01206   mAttrStyleSheet->SetOwningDocument(this);
01207   
01208   if (mStyleAttrStyleSheet) {
01209     // Remove this sheet from all style sets
01210     PRInt32 count = mPresShells.Count();
01211     for (indx = 0; indx < count; ++indx) {
01212       NS_STATIC_CAST(nsIPresShell*, mPresShells.ElementAt(indx))->StyleSet()->
01213         RemoveStyleSheet(nsStyleSet::eStyleAttrSheet, mStyleAttrStyleSheet);
01214     }
01215     rv = mStyleAttrStyleSheet->Reset(aURI);
01216   } else {
01217     rv = NS_NewHTMLCSSStyleSheet(getter_AddRefs(mStyleAttrStyleSheet), aURI,
01218                                                 this);
01219   }
01220   NS_ENSURE_SUCCESS(rv, rv);
01221 
01222   // The loop over style sets below will handle putting this sheet
01223   // into style sets as needed.
01224   mStyleAttrStyleSheet->SetOwningDocument(this);
01225 
01226   // Now set up our style sets
01227   PRInt32 count = mPresShells.Count();
01228   for (indx = 0; indx < count; ++indx) {
01229     FillStyleSet(NS_STATIC_CAST(nsIPresShell*,
01230                                 mPresShells.ElementAt(indx))->StyleSet());
01231   }
01232 
01233   return rv;
01234 }
01235 
01236 nsStyleSet::sheetType
01237 nsDocument::GetAttrSheetType()
01238 {
01239   return nsStyleSet::ePresHintSheet;
01240 }
01241 
01242 void
01243 nsDocument::FillStyleSet(nsStyleSet* aStyleSet)
01244 {
01245   NS_PRECONDITION(aStyleSet, "Must have a style set");
01246   NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::ePresHintSheet) == 0,
01247                   "Style set already has a preshint sheet?");
01248   NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::eHTMLPresHintSheet) == 0,
01249                   "Style set already has a HTML preshint sheet?");
01250   NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::eDocSheet) == 0,
01251                   "Style set already has document sheets?");
01252   NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::eStyleAttrSheet) == 0,
01253                   "Style set already has style attr sheets?");
01254   NS_PRECONDITION(mStyleAttrStyleSheet, "No style attr stylesheet?");
01255   NS_PRECONDITION(mAttrStyleSheet, "No attr stylesheet?");
01256   
01257   aStyleSet->AppendStyleSheet(GetAttrSheetType(), mAttrStyleSheet);
01258 
01259   aStyleSet->AppendStyleSheet(nsStyleSet::eStyleAttrSheet,
01260                               mStyleAttrStyleSheet);
01261 
01262   PRInt32 i;
01263   for (i = mStyleSheets.Count() - 1; i >= 0; --i) {
01264     nsIStyleSheet* sheet = mStyleSheets[i];
01265     PRBool sheetApplicable;
01266     sheet->GetApplicable(sheetApplicable);
01267     if (sheetApplicable) {
01268       aStyleSet->AddDocStyleSheet(sheet, this);
01269     }
01270   }
01271 
01272   for (i = mCatalogSheets.Count() - 1; i >= 0; --i) {
01273     nsIStyleSheet* sheet = mCatalogSheets[i];
01274     PRBool sheetApplicable;
01275     sheet->GetApplicable(sheetApplicable);
01276     if (sheetApplicable) {
01277       aStyleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, sheet);
01278     }
01279   }
01280 }
01281 
01282 nsresult
01283 nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
01284                               nsILoadGroup* aLoadGroup,
01285                               nsISupports* aContainer,
01286                               nsIStreamListener **aDocListener,
01287                               PRBool aReset, nsIContentSink* aSink)
01288 {
01289 #ifdef PR_LOGGING
01290   if (gDocumentLeakPRLog && PR_LOG_TEST(gDocumentLeakPRLog, PR_LOG_DEBUG)) {
01291     nsCOMPtr<nsIURI> uri;
01292     aChannel->GetURI(getter_AddRefs(uri));
01293     nsCAutoString spec;
01294     if (uri)
01295       uri->GetSpec(spec);
01296     PR_LogPrint("DOCUMENT %p StartDocumentLoad %s", this, spec.get());
01297   }
01298 #endif
01299 
01300   if (aReset) {
01301     Reset(aChannel, aLoadGroup);
01302   }
01303 
01304   nsCAutoString contentType;
01305   if (NS_SUCCEEDED(aChannel->GetContentType(contentType))) {
01306     // XXX this is only necessary for viewsource:
01307     nsACString::const_iterator start, end, semicolon;
01308     contentType.BeginReading(start);
01309     contentType.EndReading(end);
01310     semicolon = start;
01311     FindCharInReadable(';', semicolon, end);
01312     mContentType = Substring(start, semicolon);
01313   }
01314 
01315   RetrieveRelevantHeaders(aChannel);
01316 
01317   mChannel = aChannel;
01318 
01319   return NS_OK;
01320 }
01321 
01322 void
01323 nsDocument::StopDocumentLoad()
01324 {
01325   if (mParser) {
01326     mParser->Terminate();
01327   }
01328 }
01329 
01330 NS_IMETHODIMP
01331 nsDocument::GetLastModified(nsAString& aLastModified)
01332 {
01333   if (!mLastModified.IsEmpty()) {
01334     aLastModified.Assign(mLastModified);
01335   } else {
01336     // If we for whatever reason failed to find the last modified time
01337     // (or even the current time), fall back to what NS4.x returned.
01338     aLastModified.Assign(NS_LITERAL_STRING("01/01/1970 00:00:00"));
01339   }
01340 
01341   return NS_OK;
01342 }
01343 
01344 nsIPrincipal*
01345 nsDocument::GetPrincipal()
01346 {
01347   if (!mPrincipal) {
01348     nsIScriptSecurityManager *securityManager =
01349       nsContentUtils::GetSecurityManager();
01350 
01351     if (!securityManager) {
01352       return nsnull;
01353     }
01354 
01355     NS_WARN_IF_FALSE(mDocumentURI, "no URI!");
01356     nsresult rv =
01357       securityManager->GetCodebasePrincipal(mDocumentURI,
01358                                             getter_AddRefs(mPrincipal));
01359 
01360     if (NS_FAILED(rv)) {
01361       return nsnull;
01362     }
01363   }
01364 
01365   return mPrincipal;
01366 }
01367 
01368 void
01369 nsDocument::SetPrincipal(nsIPrincipal *aNewPrincipal)
01370 {
01371   mPrincipal = aNewPrincipal;
01372 }
01373 
01374 NS_IMETHODIMP
01375 nsDocument::GetContentType(nsAString& aContentType)
01376 {
01377   CopyUTF8toUTF16(mContentType, aContentType);
01378 
01379   return NS_OK;
01380 }
01381 
01382 void
01383 nsDocument::SetContentType(const nsAString& aContentType)
01384 {
01385   NS_ASSERTION(mContentType.IsEmpty() ||
01386                mContentType.Equals(NS_ConvertUCS2toUTF8(aContentType)),
01387                "Do you really want to change the content-type?");
01388 
01389   CopyUTF16toUTF8(aContentType, mContentType);
01390 }
01391 
01392 NS_IMETHODIMP
01393 nsDocument::GetReferrer(nsAString& aReferrer)
01394 {
01395   CopyUTF8toUTF16(mReferrer, aReferrer);
01396   return NS_OK;
01397 }
01398 
01399 nsresult
01400 nsDocument::SetBaseURI(nsIURI* aURI)
01401 {
01402   nsresult rv = NS_OK;
01403 
01404   if (aURI) {
01405     nsIPrincipal* principal = GetPrincipal();
01406     NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
01407     
01408     nsIScriptSecurityManager* securityManager =
01409       nsContentUtils::GetSecurityManager();
01410     rv = securityManager->
01411       CheckLoadURIWithPrincipal(principal, aURI,
01412                                 nsIScriptSecurityManager::STANDARD);
01413     if (NS_SUCCEEDED(rv)) {
01414       mDocumentBaseURI = aURI;
01415     }
01416   } else {
01417     mDocumentBaseURI = nsnull;
01418   }
01419 
01420   return rv;
01421 }
01422 
01423 void
01424 nsDocument::GetBaseTarget(nsAString &aBaseTarget) const
01425 {
01426   aBaseTarget.Assign(mBaseTarget);
01427 }
01428 
01429 void
01430 nsDocument::SetBaseTarget(const nsAString &aBaseTarget)
01431 {
01432   mBaseTarget.Assign(aBaseTarget);
01433 }
01434 
01435 void
01436 nsDocument::SetDocumentCharacterSet(const nsACString& aCharSetID)
01437 {
01438   if (!mCharacterSet.Equals(aCharSetID)) {
01439     mCharacterSet = aCharSetID;
01440 
01441 #ifdef DEBUG
01442     nsCOMPtr<nsICharsetAlias> calias(do_GetService(kCharsetAliasCID));
01443     if (calias) {
01444       nsCAutoString canonicalName;
01445       calias->GetPreferred(aCharSetID, canonicalName);
01446       NS_ASSERTION(canonicalName.Equals(aCharSetID),
01447                    "charset name must be canonical");
01448     }
01449 #endif
01450 
01451     PRInt32 n = mCharSetObservers.Count();
01452 
01453     for (PRInt32 i = 0; i < n; i++) {
01454       nsIObserver* observer =
01455         NS_STATIC_CAST(nsIObserver *, mCharSetObservers.ElementAt(i));
01456 
01457       observer->Observe(NS_STATIC_CAST(nsIDocument *, this), "charset",
01458                         NS_ConvertASCIItoUTF16(aCharSetID).get());
01459     }
01460   }
01461 }
01462 
01463 nsresult
01464 nsDocument::AddCharSetObserver(nsIObserver* aObserver)
01465 {
01466   NS_ENSURE_ARG_POINTER(aObserver);
01467 
01468   NS_ENSURE_TRUE(mCharSetObservers.AppendElement(aObserver), NS_ERROR_FAILURE);
01469 
01470   return NS_OK;
01471 }
01472 
01473 void
01474 nsDocument::RemoveCharSetObserver(nsIObserver* aObserver)
01475 {
01476   mCharSetObservers.RemoveElement(aObserver);
01477 }
01478 
01479 nsILineBreaker*
01480 nsDocument::GetLineBreaker()
01481 {
01482   if (!mLineBreaker) {
01483     // no line breaker, find a default one
01484     nsresult rv;
01485     nsCOMPtr<nsILineBreakerFactory> lbf =
01486       do_GetService(NS_LWBRK_CONTRACTID, &rv);
01487     NS_ENSURE_SUCCESS(rv, nsnull);
01488 
01489     lbf->GetBreaker(EmptyString(), getter_AddRefs(mLineBreaker));
01490     NS_ENSURE_TRUE(mLineBreaker, nsnull);
01491   }
01492 
01493   return mLineBreaker;
01494 }
01495 
01496 void
01497 nsDocument::SetLineBreaker(nsILineBreaker* aLineBreaker)
01498 {
01499   mLineBreaker = aLineBreaker;
01500 }
01501 
01502 nsIWordBreaker*
01503 nsDocument::GetWordBreaker()
01504 {
01505   if (!mWordBreaker) {
01506     // no word breaker, find a default one
01507     nsresult rv;
01508     nsCOMPtr<nsIWordBreakerFactory> wbf =
01509       do_GetService(NS_LWBRK_CONTRACTID, &rv);
01510     NS_ENSURE_SUCCESS(rv, nsnull);
01511 
01512     wbf->GetBreaker(EmptyString(), getter_AddRefs(mWordBreaker));
01513     NS_ENSURE_TRUE(wbf, nsnull);
01514   }
01515 
01516   return mWordBreaker;
01517 }
01518 
01519 void
01520 nsDocument::SetWordBreaker(nsIWordBreaker* aWordBreaker)
01521 {
01522   mWordBreaker = aWordBreaker;
01523 }
01524 
01525 void
01526 nsDocument::GetHeaderData(nsIAtom* aHeaderField, nsAString& aData) const
01527 {
01528   aData.Truncate();
01529   const nsDocHeaderData* data = mHeaderData;
01530   while (data) {
01531     if (data->mField == aHeaderField) {
01532       aData = data->mData;
01533 
01534       break;
01535     }
01536     data = data->mNext;
01537   }
01538 }
01539 
01540 void
01541 nsDocument::SetHeaderData(nsIAtom* aHeaderField, const nsAString& aData)
01542 {
01543   if (!aHeaderField) {
01544     NS_ERROR("null headerField");
01545     return;
01546   }
01547 
01548   if (!mHeaderData) {
01549     if (!aData.IsEmpty()) { // don't bother storing empty string
01550       mHeaderData = new nsDocHeaderData(aHeaderField, aData);
01551     }
01552   }
01553   else {
01554     nsDocHeaderData* data = mHeaderData;
01555     nsDocHeaderData** lastPtr = &mHeaderData;
01556     PRBool found = PR_FALSE;
01557     do {  // look for existing and replace
01558       if (data->mField == aHeaderField) {
01559         if (!aData.IsEmpty()) {
01560           data->mData.Assign(aData);
01561         }
01562         else {  // don't store empty string
01563           *lastPtr = data->mNext;
01564           data->mNext = nsnull;
01565           delete data;
01566         }
01567         found = PR_TRUE;
01568 
01569         break;
01570       }
01571       lastPtr = &(data->mNext);
01572       data = *lastPtr;
01573     } while (data);
01574 
01575     if (!aData.IsEmpty() && !found) {
01576       // didn't find, append
01577       *lastPtr = new nsDocHeaderData(aHeaderField, aData);
01578     }
01579   }
01580 
01581   if (aHeaderField == nsHTMLAtoms::headerContentLanguage) {
01582     CopyUTF16toUTF8(aData, mContentLanguage);
01583   }
01584   
01585   if (aHeaderField == nsHTMLAtoms::headerDefaultStyle) {
01586     // switch alternate style sheets based on default
01587     // XXXldb What if we don't have all the sheets yet?  Should this use
01588     // the DOM API for preferred stylesheet set that's "coming soon"?
01589     nsAutoString type;
01590     nsAutoString title;
01591     PRInt32 index;
01592 
01593     CSSLoader()->SetPreferredSheet(aData);
01594 
01595     PRInt32 count = mStyleSheets.Count();
01596     for (index = 0; index < count; index++) {
01597       nsIStyleSheet* sheet = mStyleSheets[index];
01598       sheet->GetType(type);
01599       if (!type.EqualsLiteral("text/html")) {
01600         sheet->GetTitle(title);
01601         if (!title.IsEmpty()) {  // if sheet has title
01602           PRBool enabled =
01603             (!aData.IsEmpty() &&
01604              title.Equals(aData, nsCaseInsensitiveStringComparator()));
01605 
01606           sheet->SetEnabled(enabled);
01607         }
01608       }
01609     }
01610   }
01611 
01612   if (aHeaderField == nsHTMLAtoms::refresh) {
01613     // We get into this code before we have a script global yet, so get to
01614     // our container via mDocumentContainer.
01615     nsCOMPtr<nsIRefreshURI> refresher = do_QueryReferent(mDocumentContainer);
01616     if (refresher) {
01617       // Note: using mDocumentURI instead of mBaseURI here, for consistency
01618       // (used to just use the current URI of our webnavigation, but that
01619       // should really be the same thing).  Note that this code can run
01620       // before the current URI of the webnavigation has been updated, so we
01621       // can't assert equality here.
01622       refresher->SetupRefreshURIFromHeader(mDocumentURI,
01623                                            NS_LossyConvertUTF16toASCII(aData));
01624     }
01625   }
01626 }
01627 
01628 PRBool
01629 nsDocument::TryChannelCharset(nsIChannel *aChannel,
01630                               PRInt32& aCharsetSource,
01631                               nsACString& aCharset)
01632 {
01633   if(kCharsetFromChannel <= aCharsetSource) {
01634     return PR_TRUE;
01635   }
01636 
01637   if (aChannel) {
01638     nsCAutoString charsetVal;
01639     nsresult rv = aChannel->GetContentCharset(charsetVal);
01640     if (NS_SUCCEEDED(rv)) {
01641       nsCOMPtr<nsICharsetAlias> calias(do_GetService(kCharsetAliasCID));
01642       if (calias) {
01643         nsCAutoString preferred;
01644         rv = calias->GetPreferred(charsetVal,
01645                                   preferred);
01646         if(NS_SUCCEEDED(rv)) {
01647           aCharset = preferred;
01648           aCharsetSource = kCharsetFromChannel;
01649           return PR_TRUE;
01650         }
01651       }
01652     }
01653   }
01654   return PR_FALSE;
01655 }
01656 
01657 nsresult
01658 nsDocument::CreateShell(nsPresContext* aContext, nsIViewManager* aViewManager,
01659                         nsStyleSet* aStyleSet,
01660                         nsIPresShell** aInstancePtrResult)
01661 {
01662   // Don't add anything here.  Add it to |doCreateShell| instead.
01663   // This exists so that subclasses can pass other values for the 4th
01664   // parameter some of the time.
01665   return doCreateShell(aContext, aViewManager, aStyleSet,
01666                        eCompatibility_FullStandards, aInstancePtrResult);
01667 }
01668 
01669 nsresult
01670 nsDocument::doCreateShell(nsPresContext* aContext,
01671                           nsIViewManager* aViewManager, nsStyleSet* aStyleSet,
01672                           nsCompatibility aCompatMode,
01673                           nsIPresShell** aInstancePtrResult)
01674 {
01675   *aInstancePtrResult = nsnull;
01676   
01677   FillStyleSet(aStyleSet);
01678   
01679   nsCOMPtr<nsIPresShell> shell;
01680   nsresult rv = NS_NewPresShell(getter_AddRefs(shell));
01681   if (NS_FAILED(rv)) {
01682     return rv;
01683   }
01684 
01685   rv = shell->Init(this, aContext, aViewManager, aStyleSet, aCompatMode);
01686   NS_ENSURE_SUCCESS(rv, rv);
01687 
01688   // Note: we don't hold a ref to the shell (it holds a ref to us)
01689   mPresShells.AppendElement(shell);
01690   shell.swap(*aInstancePtrResult);
01691 
01692   return NS_OK;
01693 }
01694 
01695 PRBool
01696 nsDocument::DeleteShell(nsIPresShell* aShell)
01697 {
01698   return mPresShells.RemoveElement(aShell);
01699 }
01700 
01701 PRUint32
01702 nsDocument::GetNumberOfShells() const
01703 {
01704   return mPresShells.Count();
01705 }
01706 
01707 nsIPresShell *
01708 nsDocument::GetShellAt(PRUint32 aIndex) const
01709 {
01710   return (nsIPresShell*)mPresShells.SafeElementAt(aIndex);
01711 }
01712 
01713 PR_STATIC_CALLBACK(void)
01714 SubDocClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
01715 {
01716   SubDocMapEntry *e = NS_STATIC_CAST(SubDocMapEntry *, entry);
01717 
01718   NS_RELEASE(e->mKey);
01719   NS_IF_RELEASE(e->mSubDocument);
01720 }
01721 
01722 PR_STATIC_CALLBACK(PRBool)
01723 SubDocInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, const void *key)
01724 {
01725   SubDocMapEntry *e =
01726     NS_CONST_CAST(SubDocMapEntry *,
01727                   NS_STATIC_CAST(const SubDocMapEntry *, entry));
01728 
01729   e->mKey = NS_CONST_CAST(nsIContent *,
01730                           NS_STATIC_CAST(const nsIContent *, key));
01731   NS_ADDREF(e->mKey);
01732 
01733   e->mSubDocument = nsnull;
01734   return PR_TRUE;
01735 }
01736 
01737 nsresult
01738 nsDocument::SetSubDocumentFor(nsIContent *aContent, nsIDocument* aSubDoc)
01739 {
01740   NS_ENSURE_TRUE(aContent, NS_ERROR_UNEXPECTED);
01741 
01742   if (!aSubDoc) {
01743     // aSubDoc is nsnull, remove the mapping
01744 
01745     if (mSubDocuments) {
01746       SubDocMapEntry *entry =
01747         NS_STATIC_CAST(SubDocMapEntry*,
01748                        PL_DHashTableOperate(mSubDocuments, aContent,
01749                                             PL_DHASH_LOOKUP));
01750 
01751       if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
01752         entry->mSubDocument->SetParentDocument(nsnull);
01753 
01754         PL_DHashTableRawRemove(mSubDocuments, entry);
01755       }
01756     }
01757   } else {
01758     if (!mSubDocuments) {
01759       // Create a new hashtable
01760 
01761       static PLDHashTableOps hash_table_ops =
01762       {
01763         PL_DHashAllocTable,
01764         PL_DHashFreeTable,
01765         PL_DHashGetKeyStub,
01766         PL_DHashVoidPtrKeyStub,
01767         PL_DHashMatchEntryStub,
01768         PL_DHashMoveEntryStub,
01769         SubDocClearEntry,
01770         PL_DHashFinalizeStub,
01771         SubDocInitEntry
01772       };
01773 
01774       mSubDocuments = PL_NewDHashTable(&hash_table_ops, nsnull,
01775                                        sizeof(SubDocMapEntry), 16);
01776       if (!mSubDocuments) {
01777         return NS_ERROR_OUT_OF_MEMORY;
01778       }
01779     }
01780 
01781     // Add a mapping to the hash table
01782     SubDocMapEntry *entry =
01783       NS_STATIC_CAST(SubDocMapEntry*,
01784                      PL_DHashTableOperate(mSubDocuments, aContent,
01785                                           PL_DHASH_ADD));
01786 
01787     if (!entry) {
01788       return NS_ERROR_OUT_OF_MEMORY;
01789     }
01790 
01791     if (entry->mSubDocument) {
01792       entry->mSubDocument->SetParentDocument(nsnull);
01793 
01794       // Release the old sub document
01795       NS_RELEASE(entry->mSubDocument);
01796     }
01797 
01798     entry->mSubDocument = aSubDoc;
01799     NS_ADDREF(entry->mSubDocument);
01800 
01801     aSubDoc->SetParentDocument(this);
01802   }
01803 
01804   return NS_OK;
01805 }
01806 
01807 nsIDocument*
01808 nsDocument::GetSubDocumentFor(nsIContent *aContent) const
01809 {
01810   if (mSubDocuments) {
01811     SubDocMapEntry *entry =
01812       NS_STATIC_CAST(SubDocMapEntry*,
01813                      PL_DHashTableOperate(mSubDocuments, aContent,
01814                                           PL_DHASH_LOOKUP));
01815 
01816     if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
01817       return entry->mSubDocument;
01818     }
01819   }
01820 
01821   return nsnull;
01822 }
01823 
01824 PR_STATIC_CALLBACK(PLDHashOperator)
01825 FindContentEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr,
01826                       PRUint32 number, void *arg)
01827 {
01828   SubDocMapEntry *entry = NS_STATIC_CAST(SubDocMapEntry*, hdr);
01829   FindContentData *data = NS_STATIC_CAST(FindContentData*, arg);
01830 
01831   if (entry->mSubDocument == data->mSubDocument) {
01832     data->mResult = entry->mKey;
01833 
01834     return PL_DHASH_STOP;
01835   }
01836 
01837   return PL_DHASH_NEXT;
01838 }
01839 
01840 nsIContent*
01841 nsDocument::FindContentForSubDocument(nsIDocument *aDocument) const
01842 {
01843   NS_ENSURE_TRUE(aDocument, nsnull);
01844 
01845   if (!mSubDocuments) {
01846     return nsnull;
01847   }
01848 
01849   FindContentData data(aDocument);
01850   PL_DHashTableEnumerate(mSubDocuments, FindContentEnumerator, &data);
01851 
01852   return data.mResult;
01853 }
01854 
01855 nsresult
01856 nsDocument::SetRootContent(nsIContent* aRoot)
01857 {
01858   if (aRoot) {
01859     NS_ASSERTION(!mRootContent,
01860                  "Already have a root content!  Clear out first!");
01861     nsresult rv = aRoot->BindToTree(this, nsnull, nsnull, PR_TRUE);
01862 
01863     if (NS_SUCCEEDED(rv)) {
01864       rv = mChildren.AppendChild(aRoot);
01865     }
01866 
01867     if (NS_FAILED(rv)) {
01868       aRoot->UnbindFromTree();
01869     } else {
01870       mRootContent = aRoot;
01871     }
01872     
01873     return rv;
01874   }
01875 
01876   if (mRootContent) {
01877     DestroyLinkMap();
01878     mRootContent->UnbindFromTree();
01879     PRInt32 pos = mChildren.IndexOfChild(mRootContent);
01880     if (pos >= 0) {
01881       mChildren.RemoveChildAt(pos);
01882     }
01883     mRootContent = nsnull;
01884   }
01885 
01886   return NS_OK;
01887 }
01888 
01889 nsIContent *
01890 nsDocument::GetChildAt(PRUint32 aIndex) const
01891 {
01892   return mChildren.GetSafeChildAt(aIndex);
01893 }
01894 
01895 PRInt32
01896 nsDocument::IndexOf(nsIContent* aPossibleChild) const
01897 {
01898   return mChildren.IndexOfChild(aPossibleChild);
01899 }
01900 
01901 PRUint32
01902 nsDocument::GetChildCount() const
01903 {
01904   return mChildren.ChildCount();
01905 }
01906 
01907 nsresult
01908 nsDocument::RemoveChildAt(PRUint32 aIndex, PRBool aNotify)
01909 {
01910   extern nsresult
01911   doRemoveChildAt(PRUint32 aIndex, PRBool aNotify, nsIContent* aKid,
01912                   nsIContent* aParent, nsIDocument* aDocument,
01913                   nsAttrAndChildArray& aChildArray);
01914 
01915   nsIContent* kid = GetChildAt(aIndex);
01916   if (kid) {
01917     return doRemoveChildAt(aIndex, aNotify, kid, nsnull, this,
01918                            mChildren);
01919   }
01920   
01921   return NS_OK;
01922 }
01923 
01924 PRInt32
01925 nsDocument::GetNumberOfStyleSheets() const
01926 {
01927   return mStyleSheets.Count();
01928 }
01929 
01930 nsIStyleSheet*
01931 nsDocument::GetStyleSheetAt(PRInt32 aIndex) const
01932 {
01933   NS_ENSURE_TRUE(0 <= aIndex && aIndex < mStyleSheets.Count(), nsnull);
01934   return mStyleSheets[aIndex];
01935 }
01936 
01937 PRInt32
01938 nsDocument::GetIndexOfStyleSheet(nsIStyleSheet* aSheet) const
01939 {
01940   return mStyleSheets.IndexOf(aSheet);
01941 }
01942 
01943 void
01944 nsDocument::AddStyleSheetToStyleSets(nsIStyleSheet* aSheet)
01945 {
01946   PRInt32 count = mPresShells.Count();
01947   PRInt32 indx;
01948   for (indx = 0; indx < count; ++indx) {
01949     NS_STATIC_CAST(nsIPresShell*, mPresShells.ElementAt(indx))->StyleSet()->
01950       AddDocStyleSheet(aSheet, this);
01951   }
01952 }
01953 
01954 void
01955 nsDocument::AddStyleSheet(nsIStyleSheet* aSheet)
01956 {
01957   NS_PRECONDITION(aSheet, "null arg");
01958   mStyleSheets.AppendObject(aSheet);
01959   aSheet->SetOwningDocument(this);
01960 
01961   PRBool applicable;
01962   aSheet->GetApplicable(applicable);
01963 
01964   if (applicable) {
01965     AddStyleSheetToStyleSets(aSheet);
01966   }
01967 
01968   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (this, aSheet, PR_TRUE));
01969 }
01970 
01971 void
01972 nsDocument::RemoveStyleSheetFromStyleSets(nsIStyleSheet* aSheet)
01973 {
01974   for (PRInt32 i = 0, i_end = mPresShells.Count(); i < i_end; ++i)
01975     NS_STATIC_CAST(nsIPresShell*, mPresShells.ElementAt(i))->StyleSet()->
01976       RemoveStyleSheet(nsStyleSet::eDocSheet, aSheet);
01977 }
01978 
01979 void
01980 nsDocument::RemoveStyleSheet(nsIStyleSheet* aSheet)
01981 {
01982   NS_PRECONDITION(aSheet, "null arg");
01983   nsCOMPtr<nsIStyleSheet> sheet = aSheet; // hold ref so it won't die too soon
01984 
01985   if (!mStyleSheets.RemoveObject(aSheet)) {
01986     NS_NOTREACHED("stylesheet not found");
01987     return;
01988   }
01989 
01990   if (!mIsGoingAway) {
01991     PRBool applicable = PR_TRUE;
01992     aSheet->GetApplicable(applicable);
01993     if (applicable) {
01994       RemoveStyleSheetFromStyleSets(aSheet);
01995     }
01996 
01997     NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetRemoved, (this, aSheet, PR_TRUE));
01998   }
01999 
02000   aSheet->SetOwningDocument(nsnull);
02001 }
02002 
02003 void
02004 nsDocument::UpdateStyleSheets(nsCOMArray<nsIStyleSheet>& aOldSheets,
02005                               nsCOMArray<nsIStyleSheet>& aNewSheets)
02006 {
02007   BeginUpdate(UPDATE_STYLE);
02008 
02009   // XXX Need to set the sheet on the ownernode, if any
02010   NS_PRECONDITION(aOldSheets.Count() == aNewSheets.Count(),
02011                   "The lists must be the same length!");
02012   PRInt32 count = aOldSheets.Count();
02013 
02014   nsCOMPtr<nsIStyleSheet> oldSheet;
02015   PRInt32 i;
02016   for (i = 0; i < count; ++i) {
02017     oldSheet = aOldSheets[i];
02018 
02019     // First remove the old sheet.
02020     NS_ASSERTION(oldSheet, "None of the old sheets should be null");
02021     PRInt32 oldIndex = mStyleSheets.IndexOf(oldSheet);
02022     RemoveStyleSheet(oldSheet);  // This does the right notifications
02023 
02024     // Now put the new one in its place.  If it's null, just ignore it.
02025     nsIStyleSheet* newSheet = aNewSheets[i];
02026     if (newSheet) {
02027       mStyleSheets.InsertObjectAt(newSheet, oldIndex);
02028       newSheet->SetOwningDocument(this);
02029       PRBool applicable = PR_TRUE;
02030       newSheet->GetApplicable(applicable);
02031       if (applicable) {
02032         AddStyleSheetToStyleSets(newSheet);
02033       }
02034 
02035       NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (this, newSheet, PR_TRUE));
02036     }
02037   }
02038 
02039   EndUpdate(UPDATE_STYLE);
02040 }
02041 
02042 void
02043 nsDocument::InsertStyleSheetAt(nsIStyleSheet* aSheet, PRInt32 aIndex)
02044 {
02045   NS_PRECONDITION(aSheet, "null ptr");
02046   mStyleSheets.InsertObjectAt(aSheet, aIndex);
02047 
02048   aSheet->SetOwningDocument(this);
02049 
02050   PRBool applicable;
02051   aSheet->GetApplicable(applicable);
02052 
02053   if (applicable) {
02054     AddStyleSheetToStyleSets(aSheet);
02055   }
02056 
02057   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (this, aSheet, PR_TRUE));
02058 }
02059 
02060 
02061 void
02062 nsDocument::SetStyleSheetApplicableState(nsIStyleSheet* aSheet,
02063                                          PRBool aApplicable)
02064 {
02065   NS_PRECONDITION(aSheet, "null arg");
02066 
02067   // If we're actually in the document style sheet list
02068   if (-1 != mStyleSheets.IndexOf(aSheet)) {
02069     if (aApplicable) {
02070       AddStyleSheetToStyleSets(aSheet);
02071     } else {
02072       RemoveStyleSheetFromStyleSets(aSheet);
02073     }
02074   }
02075 
02076   // We have to always notify, since this will be called for sheets
02077   // that are children of sheets in our style set, as well as some
02078   // sheets for nsHTMLEditor.
02079 
02080   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetApplicableStateChanged,
02081                                (this, aSheet, aApplicable));
02082 }
02083 
02084 // These three functions are a lot like the implementation of the
02085 // corresponding API for regular stylesheets.
02086 
02087 PRInt32
02088 nsDocument::GetNumberOfCatalogStyleSheets() const
02089 {
02090   return mCatalogSheets.Count();
02091 }
02092 
02093 nsIStyleSheet*
02094 nsDocument::GetCatalogStyleSheetAt(PRInt32 aIndex) const
02095 {
02096   NS_ENSURE_TRUE(0 <= aIndex && aIndex < mCatalogSheets.Count(), nsnull);
02097   return mCatalogSheets[aIndex];
02098 }
02099 
02100 void
02101 nsDocument::AddCatalogStyleSheet(nsIStyleSheet* aSheet)
02102 {
02103   mCatalogSheets.AppendObject(aSheet);
02104   aSheet->SetOwningDocument(this);
02105 
02106   PRBool applicable;
02107   aSheet->GetApplicable(applicable);
02108                                                                                 
02109   if (applicable) {
02110     // This is like |AddStyleSheetToStyleSets|, but for an agent sheet.
02111     for (PRInt32 i = 0, i_end = mPresShells.Count(); i < i_end; ++i)
02112       NS_STATIC_CAST(nsIPresShell*, mPresShells.ElementAt(i))->StyleSet()->
02113         AppendStyleSheet(nsStyleSet::eAgentSheet, aSheet);
02114   }
02115                                                                                 
02116   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (this, aSheet, PR_FALSE));
02117 }
02118 
02119 void
02120 nsDocument::EnsureCatalogStyleSheet(const char *aStyleSheetURI)
02121 {
02122   nsICSSLoader* cssLoader = CSSLoader();
02123   PRBool enabled;
02124   if (NS_SUCCEEDED(cssLoader->GetEnabled(&enabled)) && enabled) {
02125     PRInt32 sheetCount = GetNumberOfCatalogStyleSheets();
02126     for (PRInt32 i = 0; i < sheetCount; i++) {
02127       nsIStyleSheet* sheet = GetCatalogStyleSheetAt(i);
02128       NS_ASSERTION(sheet, "unexpected null stylesheet in the document");
02129       if (sheet) {
02130         nsCOMPtr<nsIURI> uri;
02131         sheet->GetSheetURI(getter_AddRefs(uri));
02132         nsCAutoString uriStr;
02133         uri->GetSpec(uriStr);
02134         if (uriStr.Equals(aStyleSheetURI))
02135           return;
02136       }
02137     }
02138 
02139     nsCOMPtr<nsIURI> uri;
02140     NS_NewURI(getter_AddRefs(uri), aStyleSheetURI);
02141     if (uri) {
02142       nsCOMPtr<nsICSSLoader_MOZILLA_1_8_BRANCH> loader = do_QueryInterface(cssLoader);
02143       nsCOMPtr<nsICSSStyleSheet> sheet;
02144       loader->LoadSheetSync(uri, PR_TRUE, getter_AddRefs(sheet));
02145       if (sheet) {
02146         BeginUpdate(UPDATE_STYLE);
02147         AddCatalogStyleSheet(sheet);
02148         EndUpdate(UPDATE_STYLE);
02149       }
02150     }
02151   }
02152 }
02153 
02154 nsIScriptGlobalObject*
02155 nsDocument::GetScriptGlobalObject() const
02156 {
02157    // If we're going away, we've already released the reference to our
02158    // ScriptGlobalObject.  We can, however, try to obtain it for the
02159    // caller through our docshell.
02160 
02161    if (mIsGoingAway) {
02162      nsCOMPtr<nsIInterfaceRequestor> requestor =
02163        do_QueryReferent(mDocumentContainer);
02164      if (requestor) {
02165        nsCOMPtr<nsIScriptGlobalObject> globalObject = do_GetInterface(requestor);
02166        return globalObject;
02167      }
02168    }
02169 
02170    return mScriptGlobalObject;
02171 }
02172 
02173 nsIScriptGlobalObject*
02174 nsDocument::GetScopeObject()
02175 {
02176     nsCOMPtr<nsIScriptGlobalObject> scope(do_QueryReferent(mScopeObject));
02177     return scope;
02178 }
02179 
02180 void
02181 nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
02182 {
02183 #ifdef DEBUG
02184   {
02185     nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aScriptGlobalObject));
02186 
02187     NS_ASSERTION(!win || win->IsInnerWindow(),
02188                  "Script global object must be an inner window!");
02189   }
02190 #endif
02191 
02192   if (mScriptGlobalObject && !aScriptGlobalObject) {
02193     // We're detaching from the window.  We need to grab a pointer to
02194     // our layout history state now.
02195     mLayoutHistoryState = GetLayoutHistoryState();
02196   }
02197 
02198   mScriptGlobalObject = aScriptGlobalObject;
02199 
02200   if (aScriptGlobalObject) {
02201     mScriptObject = nsnull;
02202     mHasHadScriptHandlingObject = PR_TRUE;
02203     // Go back to using the docshell for the layout history state
02204     mLayoutHistoryState = nsnull;
02205     mScopeObject = do_GetWeakReference(aScriptGlobalObject);
02206   }
02207 }
02208 
02209 nsIScriptGlobalObject*
02210 nsDocument::GetScriptHandlingObject(PRBool& aHasHadScriptHandlingObject) const
02211 {
02212   aHasHadScriptHandlingObject = mHasHadScriptHandlingObject;
02213   if (mScriptGlobalObject) {
02214     return mScriptGlobalObject;
02215   }
02216 
02217   nsCOMPtr<nsIScriptGlobalObject> scriptHandlingObject =
02218     do_QueryReferent(mScriptObject);
02219   nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(scriptHandlingObject);
02220   if (win) {
02221     NS_ASSERTION(win->IsInnerWindow(), "Should have inner window here!");
02222     nsPIDOMWindow* outer = win->GetOuterWindow();
02223     if (!outer || outer->GetCurrentInnerWindow() != win) {
02224       NS_WARNING("Wrong inner/outer window combination!");
02225       return nsnull;
02226     }
02227   }
02228   return scriptHandlingObject;
02229 }
02230 
02231 void
02232 nsDocument::SetScriptHandlingObject(nsIScriptGlobalObject* aScriptObject)
02233 {
02234   NS_ASSERTION(!mScriptGlobalObject ||
02235                mScriptGlobalObject == aScriptObject,
02236                "Wrong script object!");
02237   mScriptObject = do_GetWeakReference(aScriptObject);
02238   if (aScriptObject) {
02239     mHasHadScriptHandlingObject = PR_TRUE;
02240   }
02241 }
02242 
02243 nsPIDOMWindow *
02244 nsDocument::GetWindow()
02245 {
02246   nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(GetScriptGlobalObject()));
02247 
02248   if (!win) {
02249     return nsnull;
02250   }
02251 
02252   return win->GetOuterWindow();
02253 }
02254 
02255 nsIScriptLoader *
02256 nsDocument::GetScriptLoader()
02257 {
02258   return mScriptLoader;
02259 }
02260 
02261 // Note: We don't hold a reference to the document observer; we assume
02262 // that it has a live reference to the document.
02263 void
02264 nsDocument::AddObserver(nsIDocumentObserver* aObserver)
02265 {
02266   // XXX Make sure the observer isn't already in the list
02267   if (!mObservers.Contains(aObserver)) {
02268     mObservers.AppendElement(aObserver);
02269   }
02270 }
02271 
02272 PRBool
02273 nsDocument::RemoveObserver(nsIDocumentObserver* aObserver)
02274 {
02275   // If we're in the process of destroying the document (and we're
02276   // informing the observers of the destruction), don't remove the
02277   // observers from the list. This is not a big deal, since we
02278   // don't hold a live reference to the observers.
02279   if (!mInDestructor) {
02280     return mObservers.RemoveElement(aObserver);
02281   }
02282 
02283   return mObservers.Contains(aObserver);
02284 }
02285 
02286 void
02287 nsDocument::BeginUpdate(nsUpdateType aUpdateType)
02288 {
02289   if (mUpdateNestLevel == 0) {
02290     nsIBindingManager* bm = mBindingManager;
02291     NS_STATIC_CAST(nsBindingManager*, bm)->BeginOutermostUpdate();
02292   }
02293   
02294   ++mUpdateNestLevel;
02295   if (mScriptLoader) {
02296     NS_STATIC_CAST(nsScriptLoader*,
02297                    NS_STATIC_CAST(nsIScriptLoader*,
02298                                   mScriptLoader))->AddExecuteBlocker();
02299   }
02300   NS_DOCUMENT_NOTIFY_OBSERVERS(BeginUpdate, (this, aUpdateType));
02301 }
02302 
02303 void
02304 nsDocument::EndUpdate(nsUpdateType aUpdateType)
02305 {
02306   NS_DOCUMENT_NOTIFY_OBSERVERS(EndUpdate, (this, aUpdateType));
02307 
02308   --mUpdateNestLevel;
02309   if (mUpdateNestLevel == 0) {
02310     // This set of updates may have created XBL bindings.  Let the
02311     // binding manager know we're done.
02312     nsIBindingManager* bm = mBindingManager;
02313     NS_STATIC_CAST(nsBindingManager*, bm)->EndOutermostUpdate();
02314   }
02315 
02316   if (mScriptLoader) {
02317     NS_STATIC_CAST(nsScriptLoader*,
02318                    NS_STATIC_CAST(nsIScriptLoader*,
02319                                   mScriptLoader))->RemoveExecuteBlocker();
02320   }
02321 }
02322 
02323 void
02324 nsDocument::BeginLoad()
02325 {
02326   NS_DOCUMENT_NOTIFY_OBSERVERS(BeginLoad, (this));
02327 }
02328 
02329 static void
02330 GetDocumentFromDocShellTreeItem(nsIDocShellTreeItem *aDocShell,
02331                                 nsIDocument **aDocument)
02332 {
02333   *aDocument = nsnull;
02334 
02335   nsCOMPtr<nsIDOMWindow> window(do_GetInterface(aDocShell));
02336 
02337   if (window) {
02338     nsCOMPtr<nsIDOMDocument> dom_doc;
02339     window->GetDocument(getter_AddRefs(dom_doc));
02340 
02341     if (dom_doc) {
02342       CallQueryInterface(dom_doc, aDocument);
02343     }
02344   }
02345 }
02346 
02347 void
02348 nsDocument::DispatchContentLoadedEvents()
02349 {
02350   // Fire a DOM event notifying listeners that this document has been
02351   // loaded (excluding images and other loads initiated by this
02352   // document).
02353   nsCOMPtr<nsIDOMEvent> event;
02354   CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event));
02355 
02356   nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
02357 
02358   if (privateEvent) {
02359     event->InitEvent(NS_LITERAL_STRING("DOMContentLoaded"), PR_TRUE, PR_TRUE);
02360     privateEvent->SetTrusted(PR_TRUE);
02361 
02362     PRBool defaultActionEnabled;
02363     DispatchEvent(event, &defaultActionEnabled);
02364   }
02365 
02366   // If this document is a [i]frame, fire a DOMFrameContentLoaded
02367   // event on all parent documents notifying that the HTML (excluding
02368   // other external files such as images and stylesheets) in a frame
02369   // has finished loading.
02370 
02371   nsCOMPtr<nsIDocShellTreeItem> docShellParent;
02372 
02373   // target_frame is the [i]frame element that will be used as the
02374   // target for the event. It's the [i]frame whose content is done
02375   // loading.
02376   nsCOMPtr<nsIDOMEventTarget> target_frame;
02377 
02378   if (mScriptGlobalObject) {
02379     nsCOMPtr<nsIDocShellTreeItem> docShellAsItem =
02380       do_QueryInterface(mScriptGlobalObject->GetDocShell());
02381 
02382     if (docShellAsItem) {
02383       docShellAsItem->GetSameTypeParent(getter_AddRefs(docShellParent));
02384 
02385       nsCOMPtr<nsIDocument> parent_doc;
02386 
02387       GetDocumentFromDocShellTreeItem(docShellParent,
02388                                       getter_AddRefs(parent_doc));
02389 
02390       if (parent_doc) {
02391         target_frame = do_QueryInterface(parent_doc->FindContentForSubDocument(this));
02392       }
02393     }
02394   }
02395 
02396   if (target_frame) {
02397     while (docShellParent) {
02398       nsCOMPtr<nsIDocument> ancestor_doc;
02399 
02400       GetDocumentFromDocShellTreeItem(docShellParent,
02401                                       getter_AddRefs(ancestor_doc));
02402 
02403       if (!ancestor_doc) {
02404         break;
02405       }
02406 
02407       nsCOMPtr<nsIDOMDocumentEvent> document_event =
02408         do_QueryInterface(ancestor_doc);
02409 
02410       if (document_event) {
02411         document_event->CreateEvent(NS_LITERAL_STRING("Events"),
02412                                     getter_AddRefs(event));
02413 
02414         privateEvent = do_QueryInterface(event);
02415       }
02416 
02417       if (event && privateEvent) {
02418         event->InitEvent(NS_LITERAL_STRING("DOMFrameContentLoaded"), PR_TRUE,
02419                          PR_TRUE);
02420 
02421         privateEvent->SetTarget(target_frame);
02422         privateEvent->SetTrusted(PR_TRUE);
02423 
02424         // To dispatch this event we must manually call
02425         // HandleDOMEvent() on the ancestor document since the target
02426         // is not in the same document, so the event would never reach
02427         // the ancestor document if we used the normal event
02428         // dispatching code.
02429 
02430         nsEvent* innerEvent;
02431         privateEvent->GetInternalNSEvent(&innerEvent);
02432         if (innerEvent) {
02433           nsEventStatus status = nsEventStatus_eIgnore;
02434 
02435           nsIPresShell *shell = ancestor_doc->GetShellAt(0);
02436           if (shell) {
02437             nsCOMPtr<nsPresContext> context = shell->GetPresContext();
02438 
02439             if (context) {
02440               // The event argument to HandleDOMEvent() is inout, and
02441               // that doesn't mix well with nsCOMPtr's. We'll need to
02442               // perform some refcounting magic here.
02443               nsIDOMEvent *tmp_event = event;
02444               NS_ADDREF(tmp_event);
02445 
02446               ancestor_doc->HandleDOMEvent(context, innerEvent, &tmp_event,
02447                                            NS_EVENT_FLAG_INIT, &status);
02448 
02449               NS_IF_RELEASE(tmp_event);
02450             }
02451           }
02452         }
02453       }
02454 
02455       nsCOMPtr<nsIDocShellTreeItem> tmp(docShellParent);
02456       tmp->GetSameTypeParent(getter_AddRefs(docShellParent));
02457     }
02458   }
02459 }
02460 
02461 void
02462 nsDocument::EndLoad()
02463 {
02464   // Drop the ref to our parser, if any
02465   mParser = nsnull;
02466   
02467   NS_DOCUMENT_NOTIFY_OBSERVERS(EndLoad, (this));
02468 
02469   DispatchContentLoadedEvents();
02470 }
02471 
02472 void
02473 nsDocument::CharacterDataChanged(nsIContent* aContent, PRBool aAppend)
02474 {
02475   NS_ABORT_IF_FALSE(aContent, "Null content!");
02476 
02477   NS_DOCUMENT_NOTIFY_OBSERVERS(CharacterDataChanged, (this, aContent, aAppend));
02478 }
02479 
02480 void
02481 nsDocument::ContentStatesChanged(nsIContent* aContent1, nsIContent* aContent2,
02482                                  PRInt32 aStateMask)
02483 {
02484   NS_DOCUMENT_NOTIFY_OBSERVERS(ContentStatesChanged,
02485                                (this, aContent1, aContent2, aStateMask));
02486 }
02487 
02488 
02489 void
02490 nsDocument::ContentAppended(nsIContent* aContainer,
02491                             PRInt32 aNewIndexInContainer)
02492 {
02493   NS_ABORT_IF_FALSE(aContainer, "Null container!");
02494 
02495   // XXXdwh There is a hacky ordering dependency between the binding
02496   // manager and the frame constructor that forces us to walk the
02497   // observer list in a forward order
02498   // XXXldb So one should notify the other rather than both being
02499   // registered.
02500   NS_DOCUMENT_FORWARD_NOTIFY_OBSERVERS(ContentAppended,
02501                                        (this, aContainer,
02502                                         aNewIndexInContainer));
02503 }
02504 
02505 void
02506 nsDocument::ContentInserted(nsIContent* aContainer, nsIContent* aChild,
02507                             PRInt32 aIndexInContainer)
02508 {
02509   NS_ABORT_IF_FALSE(aChild, "Null child!");
02510 
02511   // XXXdwh There is a hacky ordering dependency between the binding manager
02512   // and the frame constructor that forces us to walk the observer list
02513   // in a forward order
02514   // XXXldb So one should notify the other rather than both being
02515   // registered.
02516   NS_DOCUMENT_FORWARD_NOTIFY_OBSERVERS(ContentInserted,
02517                                        (this, aContainer, aChild,
02518                                         aIndexInContainer));
02519 }
02520 
02521 void
02522 nsDocument::ContentRemoved(nsIContent* aContainer, nsIContent* aChild,
02523                            PRInt32 aIndexInContainer)
02524 {
02525   NS_ABORT_IF_FALSE(aChild, "Null child!");
02526 
02527   NS_DOCUMENT_FORWARD_NOTIFY_OBSERVERS(ContentRemoved,
02528                                        (this, aContainer, aChild, aIndexInContainer));
02529 }
02530 
02531 void
02532 nsDocument::AttributeWillChange(nsIContent* aChild, PRInt32 aNameSpaceID,
02533                                 nsIAtom* aAttribute)
02534 {
02535   NS_ASSERTION(aChild, "Null child!");
02536 }
02537 
02538 void
02539 nsDocument::AttributeChanged(nsIContent* aChild, PRInt32 aNameSpaceID,
02540                              nsIAtom* aAttribute, PRInt32 aModType)
02541 {
02542   NS_ABORT_IF_FALSE(aChild, "Null child!");
02543 
02544   NS_DOCUMENT_NOTIFY_OBSERVERS(AttributeChanged, (this, aChild, aNameSpaceID,
02545                                                   aAttribute, aModType));
02546 }
02547 
02548 
02549 void
02550 nsDocument::StyleRuleChanged(nsIStyleSheet* aStyleSheet,
02551                              nsIStyleRule* aOldStyleRule,
02552                              nsIStyleRule* aNewStyleRule)
02553 {
02554   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleChanged,
02555                                (this, aStyleSheet,
02556                                 aOldStyleRule, aNewStyleRule));
02557 }
02558 
02559 void
02560 nsDocument::StyleRuleAdded(nsIStyleSheet* aStyleSheet,
02561                            nsIStyleRule* aStyleRule)
02562 {
02563   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleAdded,
02564                                (this, aStyleSheet, aStyleRule));
02565 }
02566 
02567 void
02568 nsDocument::StyleRuleRemoved(nsIStyleSheet* aStyleSheet,
02569                              nsIStyleRule* aStyleRule)
02570 {
02571   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleRemoved,
02572                                (this, aStyleSheet, aStyleRule));
02573 }
02574 
02575 
02576 //
02577 // nsIDOMDocument interface
02578 //
02579 NS_IMETHODIMP
02580 nsDocument::GetDoctype(nsIDOMDocumentType** aDoctype)
02581 {
02582   NS_ENSURE_ARG_POINTER(aDoctype);
02583 
02584   *aDoctype = nsnull;
02585   PRInt32 i, count;
02586   count = mChildren.ChildCount();
02587   nsCOMPtr<nsIDOMNode> rootContentNode(do_QueryInterface(mRootContent) );
02588   nsCOMPtr<nsIDOMNode> node;
02589 
02590   for (i = 0; i < count; i++) {
02591     node = do_QueryInterface(mChildren.ChildAt(i));
02592 
02593     NS_ASSERTION(node, "null element of mChildren");
02594 
02595     // doctype can't be after the root
02596     // XXX Do we really want to enforce this when we don't enforce
02597     // anything else?
02598     if (node == rootContentNode)
02599       return NS_OK;
02600 
02601     if (node) {
02602       PRUint16 nodeType;
02603 
02604       node->GetNodeType(&nodeType);
02605 
02606       if (nodeType == nsIDOMNode::DOCUMENT_TYPE_NODE) {
02607         return CallQueryInterface(node, aDoctype);
02608       }
02609     }
02610   }
02611 
02612   return NS_OK;
02613 }
02614 
02615 NS_IMETHODIMP
02616 nsDocument::GetImplementation(nsIDOMDOMImplementation** aImplementation)
02617 {
02618   // For now, create a new implementation every time. This shouldn't
02619   // be a high bandwidth operation
02620   PRBool hasHadScriptObject = PR_TRUE;
02621   nsIScriptGlobalObject* scriptObject =
02622     GetScriptHandlingObject(hasHadScriptObject);
02623   NS_ENSURE_STATE(scriptObject || !hasHadScriptObject);
02624   *aImplementation = new nsDOMImplementation(scriptObject, mDocumentURI);
02625   if (!*aImplementation) {
02626     return NS_ERROR_OUT_OF_MEMORY;
02627   }
02628 
02629   NS_ADDREF(*aImplementation);
02630 
02631   return NS_OK;
02632 }
02633 
02634 NS_IMETHODIMP
02635 nsDocument::GetDocumentElement(nsIDOMElement** aDocumentElement)
02636 {
02637   NS_ENSURE_ARG_POINTER(aDocumentElement);
02638 
02639   nsresult rv = NS_OK;
02640 
02641   if (mRootContent) {
02642     rv = CallQueryInterface(mRootContent, aDocumentElement);
02643     NS_ASSERTION(NS_OK == rv, "Must be a DOM Element");
02644   } else {
02645     *aDocumentElement = nsnull;
02646   }
02647 
02648   return rv;
02649 }
02650 
02651 NS_IMETHODIMP
02652 nsDocument::CreateElement(const nsAString& aTagName,
02653                           nsIDOMElement** aReturn)
02654 {
02655   *aReturn = nsnull;
02656 
02657   nsresult rv = nsContentUtils::CheckQName(aTagName, PR_FALSE);
02658   NS_ENSURE_SUCCESS(rv, rv);
02659 
02660   NS_ASSERTION(IsCaseSensitive(),
02661                "nsDocument::CreateElement() called on document that is not "
02662                "case sensitive. Fix caller, or fix "
02663                "nsDocument::CreateElement()!");
02664 
02665   nsCOMPtr<nsIAtom> name = do_GetAtom(aTagName);
02666 
02667   nsCOMPtr<nsIContent> content;
02668   rv = CreateElem(name, nsnull, GetDefaultNamespaceID(), PR_TRUE,
02669                   getter_AddRefs(content));
02670   NS_ENSURE_SUCCESS(rv, rv);
02671 
02672   return CallQueryInterface(content, aReturn);
02673 }
02674 
02675 NS_IMETHODIMP
02676 nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
02677                             const nsAString& aQualifiedName,
02678                             nsIDOMElement** aReturn)
02679 {
02680   *aReturn = nsnull;
02681 
02682   nsCOMPtr<nsINodeInfo> nodeInfo;
02683   nsresult rv = nsContentUtils::GetNodeInfoFromQName(aNamespaceURI,
02684                                                      aQualifiedName,
02685                                                      mNodeInfoManager,
02686                                                      getter_AddRefs(nodeInfo));
02687   NS_ENSURE_SUCCESS(rv, rv);
02688 
02689   nsCOMPtr<nsIContent> content;
02690   rv = CreateElement(nodeInfo, nodeInfo->NamespaceID(),
02691                      getter_AddRefs(content));
02692   NS_ENSURE_SUCCESS(rv, rv);
02693 
02694   return CallQueryInterface(content, aReturn);
02695 }
02696 
02697 NS_IMETHODIMP
02698 nsDocument::CreateTextNode(const nsAString& aData, nsIDOMText** aReturn)
02699 {
02700   *aReturn = nsnull;
02701 
02702   nsCOMPtr<nsITextContent> text;
02703   nsresult rv = NS_NewTextNode(getter_AddRefs(text), mNodeInfoManager);
02704 
02705   if (NS_SUCCEEDED(rv)) {
02706     rv = CallQueryInterface(text, aReturn);
02707     (*aReturn)->AppendData(aData);
02708   }
02709 
02710   return rv;
02711 }
02712 
02713 NS_IMETHODIMP
02714 nsDocument::CreateDocumentFragment(nsIDOMDocumentFragment** aReturn)
02715 {
02716   return NS_NewDocumentFragment(aReturn, mNodeInfoManager);
02717 }
02718 
02719 NS_IMETHODIMP
02720 nsDocument::CreateComment(const nsAString& aData, nsIDOMComment** aReturn)
02721 {
02722   *aReturn = nsnull;
02723 
02724   nsCOMPtr<nsIContent> comment;
02725   nsresult rv = NS_NewCommentNode(getter_AddRefs(comment), mNodeInfoManager);
02726 
02727   if (NS_SUCCEEDED(rv)) {
02728     rv = CallQueryInterface(comment, aReturn);
02729     (*aReturn)->AppendData(aData);
02730   }
02731 
02732   return rv;
02733 }
02734 
02735 NS_IMETHODIMP
02736 nsDocument::CreateCDATASection(const nsAString& aData,
02737                                nsIDOMCDATASection** aReturn)
02738 {
02739   NS_ENSURE_ARG_POINTER(aReturn);
02740   *aReturn = nsnull;
02741 
02742   nsReadingIterator<PRUnichar> begin;
02743   nsReadingIterator<PRUnichar> end;
02744   aData.BeginReading(begin);
02745   aData.EndReading(end);
02746   if (FindInReadable(NS_LITERAL_STRING("]]>"),begin,end))
02747     return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
02748 
02749   nsCOMPtr<nsIContent> content;
02750   nsresult rv = NS_NewXMLCDATASection(getter_AddRefs(content),
02751                                       mNodeInfoManager);
02752 
02753   if (NS_SUCCEEDED(rv)) {
02754     rv = CallQueryInterface(content, aReturn);
02755     (*aReturn)->AppendData(aData);
02756   }
02757 
02758   return rv;
02759 }
02760 
02761 NS_IMETHODIMP
02762 nsDocument::CreateProcessingInstruction(const nsAString& aTarget,
02763                                         const nsAString& aData,
02764                                         nsIDOMProcessingInstruction** aReturn)
02765 {
02766   *aReturn = nsnull;
02767 
02768   nsresult rv = nsContentUtils::CheckQName(aTarget, PR_FALSE);
02769   NS_ENSURE_SUCCESS(rv, rv);
02770 
02771   nsCOMPtr<nsIContent> content;
02772   rv = NS_NewXMLProcessingInstruction(getter_AddRefs(content),
02773                                       mNodeInfoManager, aTarget, aData);
02774   if (NS_FAILED(rv)) {
02775     return rv;
02776   }
02777 
02778   return CallQueryInterface(content, aReturn);
02779 }
02780 
02781 NS_IMETHODIMP
02782 nsDocument::CreateAttribute(const nsAString& aName,
02783                             nsIDOMAttr** aReturn)
02784 {
02785   *aReturn = nsnull;
02786   NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_NOT_INITIALIZED);
02787 
02788   nsresult rv = nsContentUtils::CheckQName(aName, PR_FALSE);
02789   NS_ENSURE_SUCCESS(rv, rv);
02790 
02791   nsAutoString value;
02792   nsDOMAttribute* attribute;
02793 
02794   nsCOMPtr<nsINodeInfo> nodeInfo;
02795   rv = mNodeInfoManager->GetNodeInfo(aName, nsnull, kNameSpaceID_None,
02796                                      getter_AddRefs(nodeInfo));
02797   NS_ENSURE_SUCCESS(rv, rv);
02798 
02799   attribute = new nsDOMAttribute(nsnull, nodeInfo, value);
02800   NS_ENSURE_TRUE(attribute, NS_ERROR_OUT_OF_MEMORY);
02801 
02802   return CallQueryInterface(attribute, aReturn);
02803 }
02804 
02805 NS_IMETHODIMP
02806 nsDocument::CreateAttributeNS(const nsAString & aNamespaceURI,
02807                               const nsAString & aQualifiedName,
02808                               nsIDOMAttr **aResult)
02809 {
02810   NS_ENSURE_ARG_POINTER(aResult);
02811   *aResult = nsnull;
02812 
02813   nsCOMPtr<nsINodeInfo> nodeInfo;
02814   nsresult rv = nsContentUtils::GetNodeInfoFromQName(aNamespaceURI,
02815                                                      aQualifiedName,
02816                                                      mNodeInfoManager,
02817                                                      getter_AddRefs(nodeInfo));
02818   NS_ENSURE_SUCCESS(rv, rv);
02819 
02820   nsAutoString value;
02821   nsDOMAttribute* attribute = new nsDOMAttribute(nsnull, nodeInfo, value);
02822   NS_ENSURE_TRUE(attribute, NS_ERROR_OUT_OF_MEMORY);
02823 
02824   return CallQueryInterface(attribute, aResult);
02825 }
02826 
02827 NS_IMETHODIMP
02828 nsDocument::CreateEntityReference(const nsAString& aName,
02829                                   nsIDOMEntityReference** aReturn)
02830 {
02831   NS_ENSURE_ARG_POINTER(aReturn);
02832 
02833   *aReturn = nsnull;
02834   return NS_OK;
02835 }
02836 
02837 NS_IMETHODIMP
02838 nsDocument::GetElementsByTagName(const nsAString& aTagname,
02839                                  nsIDOMNodeList** aReturn)
02840 {
02841   nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aTagname);
02842   NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY);
02843 
02844   nsContentList *list = NS_GetContentList(this, nameAtom, kNameSpaceID_Unknown,
02845                                           nsnull).get();
02846   NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
02847 
02848   // transfer ref to aReturn
02849   *aReturn = list;
02850   return NS_OK;
02851 }
02852 
02853 NS_IMETHODIMP
02854 nsDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
02855                                    const nsAString& aLocalName,
02856                                    nsIDOMNodeList** aReturn)
02857 {
02858   PRInt32 nameSpaceId = kNameSpaceID_Unknown;
02859 
02860   nsContentList *list = nsnull;
02861 
02862   if (!aNamespaceURI.EqualsLiteral("*")) {
02863     nsContentUtils::GetNSManagerWeakRef()->GetNameSpaceID(aNamespaceURI,
02864                                                           &nameSpaceId);
02865 
02866     if (nameSpaceId == kNameSpaceID_Unknown) {
02867       // Unknown namespace means no matches, we create an empty list...
02868       list = NS_GetContentList(this, nsnull, kNameSpaceID_None, nsnull).get();
02869       NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
02870     }
02871   }
02872 
02873   if (!list) {
02874     nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aLocalName);
02875     NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY);
02876 
02877     list = NS_GetContentList(this, nameAtom, nameSpaceId, nsnull).get();
02878     NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
02879   }
02880 
02881   // transfer ref to aReturn
02882   *aReturn = list;
02883   return NS_OK;
02884 }
02885 
02886 NS_IMETHODIMP
02887 nsDocument::GetElementById(const nsAString & elementId,
02888                            nsIDOMElement **_retval)
02889 {
02890   // Should be implemented by subclass
02891   return NS_ERROR_NOT_IMPLEMENTED;
02892 }
02893 
02894 NS_IMETHODIMP
02895 nsDocument::GetAsync(PRBool *aAsync)
02896 {
02897   NS_ERROR("nsDocument::GetAsync() should be overriden by subclass!");
02898 
02899   return NS_ERROR_NOT_IMPLEMENTED;
02900 }
02901 
02902 NS_IMETHODIMP
02903 nsDocument::SetAsync(PRBool aAsync)
02904 {
02905   NS_ERROR("nsDocument::SetAsync() should be overriden by subclass!");
02906 
02907   return NS_ERROR_NOT_IMPLEMENTED;
02908 }
02909 
02910 NS_IMETHODIMP
02911 nsDocument::Load(const nsAString& aUrl, PRBool *aReturn)
02912 {
02913   NS_ERROR("nsDocument::Load() should be overriden by subclass!");
02914 
02915   return NS_ERROR_NOT_IMPLEMENTED;
02916 }
02917 
02918 NS_IMETHODIMP
02919 nsDocument::EvaluateFIXptr(const nsAString& aExpression, nsIDOMRange **aRange)
02920 {
02921   NS_ERROR("nsDocument::EvaluateFIXptr() should be overriden by subclass!");
02922 
02923   return NS_ERROR_NOT_IMPLEMENTED;
02924 }
02925 
02926 NS_IMETHODIMP
02927 nsDocument::EvaluateXPointer(const nsAString& aExpression,
02928                              nsIXPointerResult **aResult)
02929 {
02930   NS_ERROR("nsDocument::EvaluateXPointer() should be overriden by subclass!");
02931 
02932   return NS_ERROR_NOT_IMPLEMENTED;
02933 }
02934 
02935 NS_IMETHODIMP
02936 nsDocument::GetStyleSheets(nsIDOMStyleSheetList** aStyleSheets)
02937 {
02938   if (!mDOMStyleSheets) {
02939     mDOMStyleSheets = new nsDOMStyleSheetList(this);
02940     if (!mDOMStyleSheets) {
02941       return NS_ERROR_OUT_OF_MEMORY;
02942     }
02943   }
02944 
02945   *aStyleSheets = mDOMStyleSheets;
02946   NS_ADDREF(*aStyleSheets);
02947 
02948   return NS_OK;
02949 }
02950 
02951 NS_IMETHODIMP
02952 nsDocument::GetPreferredStylesheetSet(nsAString& aStyleTitle)
02953 {
02954   CSSLoader()->GetPreferredSheet(aStyleTitle);
02955   return NS_OK;
02956 }
02957 
02958 NS_IMETHODIMP
02959 nsDocument::GetCharacterSet(nsAString& aCharacterSet)
02960 {
02961   CopyASCIItoUCS2(GetDocumentCharacterSet(), aCharacterSet);
02962   return NS_OK;
02963 }
02964 
02965 NS_IMETHODIMP
02966 nsDocument::ImportNode(nsIDOMNode* aImportedNode,
02967                        PRBool aDeep,
02968                        nsIDOMNode** aReturn)
02969 {
02970   NS_ENSURE_ARG(aImportedNode);
02971   NS_PRECONDITION(aReturn, "Null out param!");
02972 
02973   nsresult rv = nsContentUtils::CheckSameOrigin(this, aImportedNode);
02974   if (NS_FAILED(rv)) {
02975     return rv;
02976   }
02977 
02978   return aImportedNode->CloneNode(aDeep, aReturn);
02979 }
02980 
02981 NS_IMETHODIMP
02982 nsDocument::AddBinding(nsIDOMElement* aContent, const nsAString& aURI)
02983 {
02984   NS_ENSURE_ARG(aContent);
02985   
02986   nsresult rv = nsContentUtils::CheckSameOrigin(this, aContent);
02987   if (NS_FAILED(rv)) {
02988     return rv;
02989   }
02990 
02991   nsCOMPtr<nsIContent> content(do_QueryInterface(aContent));
02992 
02993   nsCOMPtr<nsIURI> uri;
02994   rv = NS_NewURI(getter_AddRefs(uri), aURI);
02995   if (NS_FAILED(rv)) {
02996     return rv;
02997   }
02998   
02999   return mBindingManager->AddLayeredBinding(content, uri);
03000 }
03001 
03002 NS_IMETHODIMP
03003 nsDocument::RemoveBinding(nsIDOMElement* aContent, const nsAString& aURI)
03004 {
03005   NS_ENSURE_ARG(aContent);
03006 
03007   nsresult rv = nsContentUtils::CheckSameOrigin(this, aContent);
03008   if (NS_FAILED(rv)) {
03009     return rv;
03010   }
03011 
03012   nsCOMPtr<nsIURI> uri;
03013   rv = NS_NewURI(getter_AddRefs(uri), aURI);
03014   if (NS_FAILED(rv)) {
03015     return rv;
03016   }
03017 
03018   nsCOMPtr<nsIContent> content(do_QueryInterface(aContent));
03019   return mBindingManager->RemoveLayeredBinding(content, uri);
03020 }
03021 
03022 NS_IMETHODIMP
03023 nsDocument::LoadBindingDocument(const nsAString& aURI,
03024                                 nsIDOMDocument** aResult)
03025 {
03026   nsCOMPtr<nsIURI> uri;
03027   nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI,
03028                           mCharacterSet.get(),
03029                           NS_STATIC_CAST(nsIDocument *, this)->GetBaseURI());
03030 
03031   NS_ENSURE_SUCCESS(rv, rv);
03032   
03033   nsCOMPtr<nsIDocument> doc;
03034   mBindingManager->LoadBindingDocument(this, uri, getter_AddRefs(doc));
03035 
03036   if (doc) {
03037     CallQueryInterface(doc, aResult);
03038   }
03039   
03040   return NS_OK;
03041 }
03042 
03043 NS_IMETHODIMP
03044 nsDocument::GetBindingParent(nsIDOMNode* aNode, nsIDOMElement** aResult)
03045 {
03046   *aResult = nsnull;
03047   nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
03048   if (!content)
03049     return NS_ERROR_FAILURE;
03050 
03051   nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(content->GetBindingParent()));
03052   NS_IF_ADDREF(*aResult = elt);
03053   return NS_OK;
03054 }
03055 
03056 static nsresult
03057 GetElementByAttribute(nsIContent* aContent, nsIAtom* aAttrName,
03058                       const nsAString& aAttrValue, PRBool aUniversalMatch,
03059                       nsIDOMElement** aResult)
03060 {
03061   nsAutoString value;
03062   nsresult rv = aContent->GetAttr(kNameSpaceID_None, aAttrName, value);
03063   if (rv == NS_CONTENT_ATTR_HAS_VALUE &&
03064       (aUniversalMatch || value.Equals(aAttrValue))) {
03065     return CallQueryInterface(aContent, aResult);
03066   }
03067 
03068   PRUint32 childCount = aContent->GetChildCount();
03069 
03070   for (PRUint32 i = 0; i < childCount; ++i) {
03071     nsIContent *current = aContent->GetChildAt(i);
03072 
03073     GetElementByAttribute(current, aAttrName, aAttrValue, aUniversalMatch,
03074                           aResult);
03075 
03076     if (*aResult)
03077       return NS_OK;
03078   }
03079 
03080   return NS_OK;
03081 }
03082 
03083 NS_IMETHODIMP
03084 nsDocument::GetAnonymousElementByAttribute(nsIDOMElement* aElement,
03085                                            const nsAString& aAttrName,
03086                                            const nsAString& aAttrValue,
03087                                            nsIDOMElement** aResult)
03088 {
03089   *aResult = nsnull;
03090 
03091   nsCOMPtr<nsIDOMNodeList> nodeList;
03092   GetAnonymousNodes(aElement, getter_AddRefs(nodeList));
03093 
03094   if (!nodeList)
03095     return NS_OK;
03096 
03097   nsCOMPtr<nsIAtom> attribute = do_GetAtom(aAttrName);
03098 
03099   PRUint32 length;
03100   nodeList->GetLength(&length);
03101 
03102   PRBool universalMatch = aAttrValue.EqualsLiteral("*");
03103 
03104   for (PRUint32 i = 0; i < length; ++i) {
03105     nsCOMPtr<nsIDOMNode> current;
03106     nodeList->Item(i, getter_AddRefs(current));
03107 
03108     nsCOMPtr<nsIContent> content(do_QueryInterface(current));
03109 
03110     GetElementByAttribute(content, attribute, aAttrValue, universalMatch,
03111                           aResult);
03112     if (*aResult)
03113       return NS_OK;
03114   }
03115 
03116   return NS_OK;
03117 }
03118 
03119 
03120 NS_IMETHODIMP
03121 nsDocument::GetAnonymousNodes(nsIDOMElement* aElement,
03122                               nsIDOMNodeList** aResult)
03123 {
03124   *aResult = nsnull;
03125 
03126   nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
03127   return mBindingManager->GetAnonymousNodesFor(content, aResult);
03128 }
03129 
03130 NS_IMETHODIMP
03131 nsDocument::CreateRange(nsIDOMRange** aReturn)
03132 {
03133   nsresult rv = NS_NewRange(aReturn);
03134 
03135   if (NS_SUCCEEDED(rv)) {
03136     (*aReturn)->SetStart(this, 0);
03137     (*aReturn)->SetEnd(this, 0);
03138   }
03139 
03140   return rv;
03141 }
03142 
03143 NS_IMETHODIMP
03144 nsDocument::CreateNodeIterator(nsIDOMNode *aRoot,
03145                                PRUint32 aWhatToShow,
03146                                nsIDOMNodeFilter *aFilter,
03147                                PRBool aEntityReferenceExpansion,
03148                                nsIDOMNodeIterator **_retval)
03149 {
03150   return NS_ERROR_NOT_IMPLEMENTED;
03151 }
03152 
03153 NS_IMETHODIMP
03154 nsDocument::CreateTreeWalker(nsIDOMNode *aRoot,
03155                              PRUint32 aWhatToShow,
03156                              nsIDOMNodeFilter *aFilter,
03157                              PRBool aEntityReferenceExpansion,
03158                              nsIDOMTreeWalker **_retval)
03159 {
03160   *_retval = nsnull;
03161 
03162   if (!aRoot) {
03163     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
03164   }
03165 
03166   nsresult rv = nsContentUtils::CheckSameOrigin(this, aRoot);
03167   if (NS_FAILED(rv)) {
03168     return rv;
03169   }
03170 
03171   return NS_NewTreeWalker(aRoot, aWhatToShow, aFilter,
03172                           aEntityReferenceExpansion, _retval);
03173 }
03174 
03175 
03176 NS_IMETHODIMP
03177 nsDocument::GetDefaultView(nsIDOMAbstractView** aDefaultView)
03178 {
03179   *aDefaultView = nsnull;
03180 
03181   nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(mScriptGlobalObject));
03182 
03183   if (win) {
03184     // The default view is our outer window.
03185     nsPIDOMWindow *outer = win->GetOuterWindow();
03186 
03187     if (outer) {
03188       return CallQueryInterface(outer, aDefaultView);
03189     }
03190 
03191     // Fall through here and return null in case our window no longer
03192     // has an outer window.
03193   }
03194 
03195   return NS_OK;
03196 }
03197 
03198 NS_IMETHODIMP
03199 nsDocument::GetLocation(nsIDOMLocation **_retval)
03200 {
03201   NS_ENSURE_ARG_POINTER(_retval);
03202   *_retval = nsnull;
03203 
03204   nsCOMPtr<nsIDOMWindowInternal> w(do_QueryInterface(mScriptGlobalObject));
03205 
03206   if (!w) {
03207     return NS_OK;
03208   }
03209 
03210   return w->GetLocation(_retval);
03211 }
03212 
03213 NS_IMETHODIMP
03214 nsDocument::GetTitle(nsAString& aTitle)
03215 {
03216   aTitle.Assign(mDocumentTitle);
03217   // Make sure not to return null from this method even if
03218   // mDocumentTitle is void.
03219   aTitle.SetIsVoid(PR_FALSE);
03220 
03221   return NS_OK;
03222 }
03223 
03224 NS_IMETHODIMP
03225 nsDocument::SetTitle(const nsAString& aTitle)
03226 {
03227   for (PRInt32 i = mPresShells.Count() - 1; i >= 0; --i) {
03228     nsCOMPtr<nsIPresShell> shell =
03229       NS_STATIC_CAST(nsIPresShell*, mPresShells[i]);
03230 
03231     nsCOMPtr<nsISupports> container = shell->GetPresContext()->GetContainer();
03232     if (!container)
03233       continue;
03234 
03235     nsCOMPtr<nsIBaseWindow> docShellWin = do_QueryInterface(container);
03236     if (!docShellWin)
03237       continue;
03238 
03239     nsresult rv = docShellWin->SetTitle(PromiseFlatString(aTitle).get());
03240     NS_ENSURE_SUCCESS(rv, rv);
03241   }
03242 
03243   mDocumentTitle.Assign(aTitle);
03244 
03245   // Fire a DOM event for the title change.
03246   nsCOMPtr<nsIDOMEvent> event;
03247   CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event));
03248   if (event) {
03249     event->InitEvent(NS_LITERAL_STRING("DOMTitleChanged"), PR_TRUE, PR_TRUE);
03250     // There might be script running, so the event might have ended up
03251     // untrusted.  Make it trusted.
03252     nsCOMPtr<nsIPrivateDOMEvent> privEvt(do_QueryInterface(event));
03253     privEvt->SetTrusted(PR_TRUE);
03254     PRBool defaultActionEnabled;
03255     DispatchEvent(event, &defaultActionEnabled);
03256   }
03257 
03258   return NS_OK;
03259 }
03260 
03261 NS_IMETHODIMP
03262 nsDocument::GetBoxObjectFor(nsIDOMElement* aElement, nsIBoxObject** aResult)
03263 {
03264   nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
03265   NS_ENSURE_TRUE(content, NS_ERROR_UNEXPECTED);
03266 
03267   // This check must match the one in nsXULElement.cpp::GetBoxObject()
03268   NS_ENSURE_TRUE(content->GetOwnerDoc() == this,
03269                  NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
03270   
03271   nsresult rv;
03272 
03273   *aResult = nsnull;
03274 
03275   if (!mBoxObjectTable) {
03276     mBoxObjectTable = new nsSupportsHashtable;
03277   } else {
03278     nsISupportsKey key(aElement);
03279     nsCOMPtr<nsISupports> supports = dont_AddRef(mBoxObjectTable->Get(&key));
03280 
03281     nsCOMPtr<nsIBoxObject> boxObject(do_QueryInterface(supports));
03282     if (boxObject) {
03283       *aResult = boxObject;
03284       NS_ADDREF(*aResult);
03285 
03286       return NS_OK;
03287     }
03288   }
03289 
03290   nsIPresShell *shell = GetShellAt(0);
03291   if (!shell)
03292     return NS_ERROR_FAILURE;
03293 
03294   PRInt32 namespaceID;
03295   nsCOMPtr<nsIAtom> tag;
03296   nsCOMPtr<nsIXBLService> xblService =
03297            do_GetService("@mozilla.org/xbl;1", &rv);
03298   xblService->ResolveTag(content, &namespaceID, getter_AddRefs(tag));
03299 
03300   nsCAutoString contractID("@mozilla.org/layout/xul-boxobject");
03301   if (namespaceID == kNameSpaceID_XUL) {
03302     if (tag == nsXULAtoms::browser)
03303       contractID += "-browser";
03304     else if (tag == nsXULAtoms::editor)
03305       contractID += "-editor";
03306     else if (tag == nsXULAtoms::iframe)
03307       contractID += "-iframe";
03308     else if (tag == nsXULAtoms::menu)
03309       contractID += "-menu";
03310     else if (tag == nsXULAtoms::popup ||
03311              tag == nsXULAtoms::menupopup ||
03312              tag == nsXULAtoms::tooltip)
03313       contractID += "-popup";
03314     else if (tag == nsXULAtoms::tree)
03315       contractID += "-tree";
03316     else if (tag == nsXULAtoms::listbox)
03317       contractID += "-listbox";
03318     else if (tag == nsXULAtoms::scrollbox)
03319       contractID += "-scrollbox";
03320   }
03321   contractID += ";1";
03322 
03323   nsCOMPtr<nsIBoxObject> boxObject(do_CreateInstance(contractID.get()));
03324   if (!boxObject)
03325     return NS_ERROR_FAILURE;
03326 
03327   nsCOMPtr<nsPIBoxObject> privateBox(do_QueryInterface(boxObject));
03328   rv = privateBox->Init(content, shell);
03329 
03330   if (NS_FAILED(rv)) {
03331     return rv;
03332   }
03333 
03334   if (!mBoxObjectTable) {
03335     mBoxObjectTable = new nsSupportsHashtable(12);
03336   }
03337 
03338   if (mBoxObjectTable) {
03339     nsISupportsKey key(aElement);
03340     mBoxObjectTable->Put(&key, boxObject);
03341   }
03342 
03343   *aResult = boxObject;
03344   NS_ADDREF(*aResult);
03345 
03346   return NS_OK;
03347 }
03348 
03349 NS_IMETHODIMP
03350 nsDocument::SetBoxObjectFor(nsIDOMElement* aElement, nsIBoxObject* aBoxObject)
03351 {
03352   if (aBoxObject) {
03353     return NS_ERROR_INVALID_ARG;
03354   }
03355 
03356   if (!mBoxObjectTable) {
03357     return NS_OK;
03358   }
03359 
03360   nsISupportsKey key(aElement);
03361   nsCOMPtr<nsISupports> supp;
03362   mBoxObjectTable->Remove(&key, getter_AddRefs(supp));
03363   nsCOMPtr<nsPIBoxObject> boxObject(do_QueryInterface(supp));
03364   if (boxObject) {
03365     boxObject->SetDocument(nsnull);
03366   }
03367 
03368   return NS_OK;
03369 }
03370 
03371 struct DirTable {
03372   const char* mName;
03373   PRUint8     mValue;
03374 };
03375 
03376 static const DirTable dirAttributes[] = {
03377   {"ltr", IBMBIDI_TEXTDIRECTION_LTR},
03378   {"rtl", IBMBIDI_TEXTDIRECTION_RTL},
03379   {0}
03380 };
03381 
03387 NS_IMETHODIMP
03388 nsDocument::GetDir(nsAString& aDirection)
03389 {
03390   nsCOMPtr<nsIPresShell> shell = (nsIPresShell*)mPresShells.SafeElementAt(0);
03391   if (shell) {
03392     nsPresContext *context = shell->GetPresContext();
03393     if (context) {
03394       PRUint32 options = context->GetBidi();
03395       for (const DirTable* elt = dirAttributes; elt->mName; elt++) {
03396         if (GET_BIDI_OPTION_DIRECTION(options) == elt->mValue) {
03397           CopyASCIItoUTF16(elt->mName, aDirection);
03398           break;
03399         }
03400       }
03401     }
03402   }
03403 
03404   return NS_OK;
03405 }
03406 
03412 NS_IMETHODIMP
03413 nsDocument::SetDir(const nsAString& aDirection)
03414 {
03415   nsIPresShell *shell =
03416     NS_STATIC_CAST(nsIPresShell *, mPresShells.SafeElementAt(0));
03417 
03418   if (!shell) {
03419     return NS_OK;
03420   }
03421 
03422   nsPresContext *context = shell->GetPresContext();
03423   NS_ENSURE_TRUE(context, NS_ERROR_UNEXPECTED);
03424 
03425   PRUint32 options = context->GetBidi();
03426 
03427   for (const DirTable* elt = dirAttributes; elt->mName; elt++) {
03428     if (aDirection == NS_ConvertASCIItoUCS2(elt->mName)) {
03429       if (GET_BIDI_OPTION_DIRECTION(options) != elt->mValue) {
03430         SET_BIDI_OPTION_DIRECTION(options, elt->mValue);
03431         context->SetBidi(options, PR_TRUE);
03432       }
03433 
03434       break;
03435     }
03436   }
03437 
03438   return NS_OK;
03439 }
03440 
03441 //
03442 // nsIDOMGCParticipant methods
03443 //
03444 nsIDOMGCParticipant*
03445 nsDocument::GetSCCIndex()
03446 {
03447   return this;
03448 }
03449 
03450 void
03451 nsDocument::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
03452 {
03453   nsCOMPtr<nsIDOMGCParticipant> gcp = do_QueryInterface(mScriptGlobalObject);
03454   if (gcp)
03455     aArray.AppendObject(gcp);
03456 }
03457 
03458 
03459 //
03460 // nsIDOMNode methods
03461 //
03462 NS_IMETHODIMP
03463 nsDocument::GetNodeName(nsAString& aNodeName)
03464 {
03465   aNodeName.AssignLiteral("#document");
03466 
03467   return NS_OK;
03468 }
03469 
03470 NS_IMETHODIMP
03471 nsDocument::GetNodeValue(nsAString& aNodeValue)
03472 {
03473   SetDOMStringToNull(aNodeValue);
03474 
03475   return NS_OK;
03476 }
03477 
03478 NS_IMETHODIMP
03479 nsDocument::SetNodeValue(const nsAString& aNodeValue)
03480 {
03481   // The DOM spec says that when nodeValue is defined to be null "setting it
03482   // has no effect", so we don't throw an exception.
03483   return NS_OK;
03484 }
03485 
03486 NS_IMETHODIMP
03487 nsDocument::GetNodeType(PRUint16* aNodeType)
03488 {
03489   *aNodeType = nsIDOMNode::DOCUMENT_NODE;
03490 
03491   return NS_OK;
03492 }
03493 
03494 NS_IMETHODIMP
03495 nsDocument::GetParentNode(nsIDOMNode** aParentNode)
03496 {
03497   *aParentNode = nsnull;
03498 
03499   return NS_OK;
03500 }
03501 
03502 NS_IMETHODIMP
03503 nsDocument::GetChildNodes(nsIDOMNodeList** aChildNodes)
03504 {
03505   if (!mChildNodes) {
03506     mChildNodes = new nsDocumentChildNodes(this);
03507     if (!mChildNodes) {
03508       return NS_ERROR_OUT_OF_MEMORY;
03509     }
03510   }
03511 
03512   return CallQueryInterface(mChildNodes.get(), aChildNodes);
03513 }
03514 
03515 NS_IMETHODIMP
03516 nsDocument::HasChildNodes(PRBool* aHasChildNodes)
03517 {
03518   NS_ENSURE_ARG(aHasChildNodes);
03519 
03520   *aHasChildNodes = (mChildren.ChildCount() != 0);
03521 
03522   return NS_OK;
03523 }
03524 
03525 NS_IMETHODIMP
03526 nsDocument::HasAttributes(PRBool* aHasAttributes)
03527 {
03528   NS_ENSURE_ARG(aHasAttributes);
03529 
03530   *aHasAttributes = PR_FALSE;
03531 
03532   return NS_OK;
03533 }
03534 
03535 NS_IMETHODIMP
03536 nsDocument::GetFirstChild(nsIDOMNode** aFirstChild)
03537 {
03538   if (mChildren.ChildCount()) {
03539     return CallQueryInterface(mChildren.ChildAt(0), aFirstChild);
03540   }
03541 
03542   *aFirstChild = nsnull;
03543 
03544   return NS_OK;
03545 }
03546 
03547 NS_IMETHODIMP
03548 nsDocument::GetLastChild(nsIDOMNode** aLastChild)
03549 {
03550   PRInt32 count = mChildren.ChildCount();
03551   if (count) {
03552     return CallQueryInterface(mChildren.ChildAt(count-1), aLastChild);
03553   }
03554 
03555   *aLastChild = nsnull;
03556 
03557   return NS_OK;
03558 }
03559 
03560 NS_IMETHODIMP
03561 nsDocument::GetPreviousSibling(nsIDOMNode** aPreviousSibling)
03562 {
03563   *aPreviousSibling = nsnull;
03564 
03565   return NS_OK;
03566 }
03567 
03568 NS_IMETHODIMP
03569 nsDocument::GetNextSibling(nsIDOMNode** aNextSibling)
03570 {
03571   *aNextSibling = nsnull;
03572 
03573   return NS_OK;
03574 }
03575 
03576 NS_IMETHODIMP
03577 nsDocument::GetAttributes(nsIDOMNamedNodeMap** aAttributes)
03578 {
03579   *aAttributes = nsnull;
03580 
03581   return NS_OK;
03582 }
03583 
03584 NS_IMETHODIMP
03585 nsDocument::GetNamespaceURI(nsAString& aNamespaceURI)
03586 {
03587   SetDOMStringToNull(aNamespaceURI);
03588 
03589   return NS_OK;
03590 }
03591 
03592 NS_IMETHODIMP
03593 nsDocument::GetPrefix(nsAString& aPrefix)
03594 {
03595   SetDOMStringToNull(aPrefix);
03596 
03597   return NS_OK;
03598 }
03599 
03600 NS_IMETHODIMP
03601 nsDocument::SetPrefix(const nsAString& aPrefix)
03602 {
03603   return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
03604 }
03605 
03606 NS_IMETHODIMP
03607 nsDocument::GetLocalName(nsAString& aLocalName)
03608 {
03609   SetDOMStringToNull(aLocalName);
03610 
03611   return NS_OK;
03612 }
03613 
03614 nsresult
03615 nsDocument::IsAllowedAsChild(PRUint16 aNodeType, nsIContent* aRefContent)
03616 {
03617   if (aNodeType != nsIDOMNode::COMMENT_NODE &&
03618       aNodeType != nsIDOMNode::ELEMENT_NODE &&
03619       aNodeType != nsIDOMNode::PROCESSING_INSTRUCTION_NODE &&
03620       aNodeType != nsIDOMNode::DOCUMENT_TYPE_NODE) {
03621     return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
03622   }
03623 
03624   if (aNodeType == nsIDOMNode::ELEMENT_NODE && mRootContent &&
03625       mRootContent != aRefContent) {
03626     // We already have a child Element, and we're not trying to
03627     // replace it, so throw an error.
03628     return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
03629   }
03630 
03631   if (aNodeType == nsIDOMNode::DOCUMENT_TYPE_NODE) {
03632     nsCOMPtr<nsIDOMDocumentType> docType;
03633     GetDoctype(getter_AddRefs(docType));
03634 
03635     nsCOMPtr<nsIContent> docTypeContent = do_QueryInterface(docType);
03636     if (docTypeContent && docTypeContent != aRefContent) {
03637       // We already have a doctype, and we're not trying to
03638       // replace it, so throw an error.
03639       return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
03640     }
03641   }
03642 
03643   return NS_OK;
03644 }
03645 
03646 NS_IMETHODIMP
03647 nsDocument::InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild,
03648                          nsIDOMNode** aReturn)
03649 {
03650   return nsGenericElement::doReplaceOrInsertBefore(PR_FALSE, aNewChild,
03651                                                    aRefChild, nsnull, this,
03652                                                    mChildren, aReturn);
03653 }
03654 
03655 NS_IMETHODIMP
03656 nsDocument::ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild,
03657                          nsIDOMNode** aReturn)
03658 {
03659   return nsGenericElement::doReplaceOrInsertBefore(PR_TRUE, aNewChild,
03660                                                    aOldChild, nsnull, this,
03661                                                    mChildren, aReturn);
03662 }
03663 
03664 NS_IMETHODIMP
03665 nsDocument::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
03666 {
03667   *aReturn = nsnull; // do we need to do this?
03668 
03669   NS_ENSURE_TRUE(aOldChild, NS_ERROR_NULL_POINTER);
03670 
03671   nsCOMPtr<nsIContent> content(do_QueryInterface(aOldChild));
03672   if (!content) {
03673     return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
03674   }
03675 
03676   PRInt32 indx = mChildren.IndexOfChild(content);
03677   if (indx == -1) {
03678     return NS_ERROR_DOM_NOT_FOUND_ERR;
03679   }
03680 
03681   ContentRemoved(nsnull, content, indx);
03682 
03683   mChildren.RemoveChildAt(indx);
03684   if (content == mRootContent) {
03685     DestroyLinkMap();
03686     mRootContent = nsnull;
03687   }
03688 
03689   content->UnbindFromTree();
03690 
03691   *aReturn = aOldChild;
03692   NS_ADDREF(aOldChild);
03693 
03694   return NS_OK;
03695 }
03696 
03697 NS_IMETHODIMP
03698 nsDocument::AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn)
03699 {
03700   return InsertBefore(aNewChild, nsnull, aReturn);
03701 }
03702 
03703 NS_IMETHODIMP
03704 nsDocument::CloneNode(PRBool aDeep, nsIDOMNode** aReturn)
03705 {
03706   // XXX should be implemented by subclass
03707   *aReturn = nsnull;
03708 
03709   return NS_OK;
03710 }
03711 
03712 NS_IMETHODIMP
03713 nsDocument::Normalize()
03714 {
03715   PRInt32 count = mChildren.ChildCount();
03716   for (PRInt32 i = 0; i < count; ++i) {
03717     nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mChildren.ChildAt(i)));
03718 
03719     if (node) {
03720       node->Normalize();
03721     }
03722   }
03723 
03724   return NS_OK;
03725 }
03726 
03727 NS_IMETHODIMP
03728 nsDocument::IsSupported(const nsAString& aFeature, const nsAString& aVersion,
03729                         PRBool* aReturn)
03730 {
03731   return nsGenericElement::InternalIsSupported(NS_STATIC_CAST(nsIDOMDocument*, this),
03732                                                aFeature, aVersion, aReturn);
03733 }
03734 
03735 NS_IMETHODIMP
03736 nsDocument::GetBaseURI(nsAString &aURI)
03737 {
03738   nsCAutoString spec;
03739   if (mDocumentBaseURI) {
03740     mDocumentBaseURI->GetSpec(spec);
03741   }
03742 
03743   CopyUTF8toUTF16(spec, aURI);
03744 
03745   return NS_OK;
03746 }
03747 
03748 NS_IMETHODIMP
03749 nsDocument::GetTextContent(nsAString &aTextContent)
03750 {
03751   SetDOMStringToNull(aTextContent);
03752 
03753   return NS_OK;
03754 }
03755 
03756 NS_IMETHODIMP
03757 nsDocument::SetTextContent(const nsAString& aTextContent)
03758 {
03759   return NS_OK;
03760 }
03761 
03762 
03763 NS_IMETHODIMP
03764 nsDocument::CompareDocumentPosition(nsIDOMNode* aOther, PRUint16* aReturn)
03765 {
03766   NS_ENSURE_ARG_POINTER(aOther);
03767   NS_PRECONDITION(aReturn, "Must have an out parameter");
03768 
03769   if (this == aOther) {
03770     // If the two nodes being compared are the same node,
03771     // then no flags are set on the return.
03772     *aReturn = 0;
03773 
03774     return NS_OK;
03775   }
03776 
03777   PRUint16 mask = 0;
03778 
03779   nsCOMPtr<nsIContent> otherContent(do_QueryInterface(aOther));
03780   if (!otherContent) {
03781     PRUint16 otherNodeType = 0;
03782     aOther->GetNodeType(&otherNodeType);
03783     NS_ASSERTION(otherNodeType == nsIDOMNode::DOCUMENT_NODE ||
03784                  otherNodeType == nsIDOMNode::ATTRIBUTE_NODE,
03785                  "Hmm, this really _should_ support nsIContent...");
03786     if (otherNodeType == nsIDOMNode::ATTRIBUTE_NODE) {
03787       nsCOMPtr<nsIDOMAttr> otherAttr(do_QueryInterface(aOther));
03788       NS_ASSERTION(otherAttr, "Attributes really should be supporting "
03789                               "nsIDOMAttr you know...");
03790 
03791       nsCOMPtr<nsIDOMElement> otherOwnerEl;
03792       otherAttr->GetOwnerElement(getter_AddRefs(otherOwnerEl));
03793       if (otherOwnerEl) {
03794         // Documents have no direct relationship to attribute
03795         // nodes.  So we'll look at our relationship in relation
03796         // to its owner element, since that is also our relation
03797         // to the attribute.
03798         return CompareDocumentPosition(otherOwnerEl, aReturn);
03799       }
03800     }
03801 
03802     // If there is no common container node, then the order
03803     // is based upon order between the root container of each
03804     // node that is in no container. In this case, the result
03805     // is disconnected and implementation-dependent.
03806     mask |= (nsIDOM3Node::DOCUMENT_POSITION_DISCONNECTED |
03807              nsIDOM3Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
03808 
03809     *aReturn = mask;
03810     return NS_OK;
03811   }
03812 
03813   if (this == otherContent->GetDocument()) {
03814     // If the node being compared is contained by our node,
03815     // then it follows it.
03816     mask |= (nsIDOM3Node::DOCUMENT_POSITION_CONTAINED_BY |
03817              nsIDOM3Node::DOCUMENT_POSITION_FOLLOWING);
03818   }
03819   else {
03820     // If there is no common container node, then the order
03821     // is based upon order between the root container of each
03822     // node that is in no container. In this case, the result
03823     // is disconnected and implementation-dependent.
03824     mask |= (nsIDOM3Node::DOCUMENT_POSITION_DISCONNECTED |
03825              nsIDOM3Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
03826   }
03827 
03828   *aReturn = mask;
03829 
03830   return NS_OK;
03831 }
03832 
03833 NS_IMETHODIMP
03834 nsDocument::IsSameNode(nsIDOMNode* aOther, PRBool* aReturn)
03835 {
03836   PRBool sameNode = PR_FALSE;
03837 
03838   if (this == aOther) {
03839     sameNode = PR_TRUE;
03840   }
03841 
03842   *aReturn = sameNode;
03843 
03844   return NS_OK;
03845 }
03846 
03847 NS_IMETHODIMP
03848 nsDocument::IsEqualNode(nsIDOMNode* aOther, PRBool* aReturn)
03849 {
03850   NS_NOTYETIMPLEMENTED("nsDocument::IsEqualNode()");
03851 
03852   return NS_ERROR_NOT_IMPLEMENTED;
03853 }
03854 
03855 NS_IMETHODIMP
03856 nsDocument::IsDefaultNamespace(const nsAString& aNamespaceURI,
03857                                PRBool* aReturn)
03858 {
03859   *aReturn = PR_FALSE;
03860   return NS_OK;
03861 }
03862 
03863 NS_IMETHODIMP
03864 nsDocument::GetFeature(const nsAString& aFeature,
03865                        const nsAString& aVersion,
03866                        nsISupports** aReturn)
03867 {
03868   return nsGenericElement::InternalGetFeature(NS_STATIC_CAST(nsIDOMDocument*, this),
03869                                               aFeature, aVersion, aReturn);
03870 }
03871 
03872 NS_IMETHODIMP
03873 nsDocument::SetUserData(const nsAString& aKey,
03874                         nsIVariant* aData,
03875                         nsIDOMUserDataHandler* aHandler,
03876                         nsIVariant** aReturn)
03877 {
03878   NS_NOTYETIMPLEMENTED("nsDocument::SetUserData()");
03879 
03880   return NS_ERROR_NOT_IMPLEMENTED;
03881 }
03882 
03883 NS_IMETHODIMP
03884 nsDocument::GetUserData(const nsAString& aKey,
03885                         nsIVariant** aReturn)
03886 {
03887   NS_NOTYETIMPLEMENTED("nsDocument::GetUserData()");
03888 
03889   return NS_ERROR_NOT_IMPLEMENTED;
03890 }
03891 
03892 
03893 NS_IMETHODIMP
03894 nsDocument::LookupPrefix(const nsAString& aNamespaceURI,
03895                          nsAString& aPrefix)
03896 {
03897   aPrefix.Truncate();
03898 
03899   return NS_OK;
03900 }
03901 
03902 NS_IMETHODIMP
03903 nsDocument::LookupNamespaceURI(const nsAString& aNamespacePrefix,
03904                                nsAString& aNamespaceURI)
03905 {
03906   aNamespaceURI.Truncate();
03907 
03908   return NS_OK;
03909 }
03910 
03911 NS_IMETHODIMP
03912 nsDocument::GetInputEncoding(nsAString& aInputEncoding)
03913 {
03914   return GetCharacterSet(aInputEncoding);
03915 }
03916 
03917 NS_IMETHODIMP
03918 nsDocument::GetXmlEncoding(nsAString& aXmlEncoding)
03919 {
03920   if (mXMLDeclarationBits & XML_DECLARATION_BITS_DECLARATION_EXISTS &&
03921       mXMLDeclarationBits & XML_DECLARATION_BITS_ENCODING_EXISTS) {
03922     // XXX We don't store the encoding given in the xml declaration.
03923     // For now, just output the inputEncoding which we do store.
03924     GetInputEncoding(aXmlEncoding);
03925   } else {
03926     SetDOMStringToNull(aXmlEncoding);
03927   }
03928 
03929   return NS_OK;
03930 }
03931 
03932 NS_IMETHODIMP
03933 nsDocument::GetXmlStandalone(PRBool *aXmlStandalone)
03934 {
03935   *aXmlStandalone = 
03936     mXMLDeclarationBits & XML_DECLARATION_BITS_DECLARATION_EXISTS &&
03937     mXMLDeclarationBits & XML_DECLARATION_BITS_STANDALONE_EXISTS &&
03938     mXMLDeclarationBits & XML_DECLARATION_BITS_STANDALONE_YES;
03939 
03940   return NS_OK;
03941 }
03942 
03943 NS_IMETHODIMP
03944 nsDocument::SetXmlStandalone(PRBool aXmlStandalone)
03945 {
03946   return NS_ERROR_NOT_IMPLEMENTED;
03947 }
03948 
03949 NS_IMETHODIMP
03950 nsDocument::GetXmlVersion(nsAString& aXmlVersion)
03951 {
03952   // If there is no declaration, the value is "1.0".
03953 
03954   // XXX We only support "1.0", so always output "1.0" until that changes.
03955   aXmlVersion.AssignLiteral("1.0");
03956 
03957   return NS_OK;
03958 }
03959 
03960 NS_IMETHODIMP
03961 nsDocument::SetXmlVersion(const nsAString& aXmlVersion)
03962 {
03963   return NS_ERROR_NOT_IMPLEMENTED;
03964 }
03965 
03966 NS_IMETHODIMP
03967 nsDocument::GetStrictErrorChecking(PRBool *aStrictErrorChecking)
03968 {
03969   // This attribute is true by default, and we don't really support it being false.
03970   *aStrictErrorChecking = PR_TRUE;
03971   return NS_OK;
03972 }
03973 
03974 NS_IMETHODIMP
03975 nsDocument::SetStrictErrorChecking(PRBool aStrictErrorChecking)
03976 {
03977   // We don't really support non-strict error checking, so just no-op for now.
03978   return NS_OK;
03979 }
03980 
03981 NS_IMETHODIMP
03982 nsDocument::GetDocumentURI(nsAString& aDocumentURI)
03983 {
03984   if (mDocumentURI) {
03985     nsCAutoString uri;
03986     mDocumentURI->GetSpec(uri);
03987     CopyUTF8toUTF16(uri, aDocumentURI);
03988   } else {
03989     SetDOMStringToNull(aDocumentURI);
03990   }
03991 
03992   return NS_OK;
03993 }
03994 
03995 NS_IMETHODIMP
03996 nsDocument::SetDocumentURI(const nsAString& aDocumentURI)
03997 {
03998   // Not allowing this yet, need to think about security ramifications first.
03999   // We use mDocumentURI to get principals for this document.
04000   return NS_ERROR_NOT_IMPLEMENTED;
04001 }
04002 
04003 NS_IMETHODIMP
04004 nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult)
04005 {
04006   NS_ENSURE_ARG(aAdoptedNode);
04007 
04008   *aResult = nsnull;
04009 
04010   nsresult rv;
04011   PRUint16 nodeType;
04012   aAdoptedNode->GetNodeType(&nodeType);
04013   switch (nodeType) {
04014     case nsIDOMNode::ATTRIBUTE_NODE:
04015     {
04016       // Remove from ownerElement.
04017       nsCOMPtr<nsIDOMAttr> adoptedAttr = do_QueryInterface(aAdoptedNode, &rv);
04018       NS_ENSURE_SUCCESS(rv, rv);
04019 
04020       nsCOMPtr<nsIDOMElement> ownerElement;
04021       rv = adoptedAttr->GetOwnerElement(getter_AddRefs(ownerElement));
04022       NS_ENSURE_SUCCESS(rv, rv);
04023 
04024       if (ownerElement) {
04025         nsCOMPtr<nsIDOMAttr> newAttr;
04026         rv = ownerElement->RemoveAttributeNode(adoptedAttr,
04027                                                getter_AddRefs(newAttr));
04028         NS_ENSURE_SUCCESS(rv, rv);
04029 
04030         newAttr.swap(adoptedAttr);
04031       }
04032 
04033       return CallQueryInterface(adoptedAttr, aResult);
04034     }
04035     case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
04036     case nsIDOMNode::ELEMENT_NODE:
04037     case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
04038     case nsIDOMNode::TEXT_NODE:
04039     case nsIDOMNode::CDATA_SECTION_NODE:
04040     case nsIDOMNode::COMMENT_NODE:
04041     {
04042       nsCOMPtr<nsIContent> adoptedNode = do_QueryInterface(aAdoptedNode, &rv);
04043       NS_ENSURE_SUCCESS(rv, rv);
04044 
04045       // We don't want to adopt an element into its own contentDocument or into
04046       // a descendant contentDocument, so we check if the frameElement of this
04047       // document or any of its parents is the adopted node or one of its
04048       // descendants.
04049       nsIDocument *doc = this;
04050       do {
04051         nsPIDOMWindow *win = doc->GetWindow();
04052         if (win) {
04053           nsCOMPtr<nsIContent> node =
04054             do_QueryInterface(win->GetFrameElementInternal());
04055           if (node &&
04056               nsContentUtils::ContentIsDescendantOf(node, adoptedNode)) {
04057             return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
04058           }
04059         }
04060       } while ((doc = doc->GetParentDocument()));
04061 
04062       // Remove from parent.
04063       nsCOMPtr<nsIDOMNode> parent;
04064       aAdoptedNode->GetParentNode(getter_AddRefs(parent));
04065       NS_ENSURE_SUCCESS(rv, rv);
04066 
04067       if (parent) {
04068         return parent->RemoveChild(aAdoptedNode, aResult);
04069       }
04070 
04071       NS_ADDREF(*aResult = aAdoptedNode);
04072 
04073       return NS_OK;
04074     }
04075     case nsIDOMNode::ENTITY_REFERENCE_NODE:
04076     {
04077       return NS_ERROR_NOT_IMPLEMENTED;
04078     }
04079     case nsIDOMNode::DOCUMENT_NODE:
04080     case nsIDOMNode::DOCUMENT_TYPE_NODE:
04081     case nsIDOMNode::ENTITY_NODE:
04082     case nsIDOMNode::NOTATION_NODE:
04083     {
04084       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
04085     }
04086     default:
04087     {
04088       NS_WARNING("Don't know how to adopt this nodetype for adoptNode.");
04089 
04090       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
04091     }
04092   }
04093 }
04094 
04095 NS_IMETHODIMP
04096 nsDocument::GetDomConfig(nsIDOMDOMConfiguration **aConfig)
04097 {
04098   return NS_ERROR_NOT_IMPLEMENTED;
04099 }
04100 
04101 NS_IMETHODIMP
04102 nsDocument::NormalizeDocument()
04103 {
04104   // We don't support DOMConfigurations yet, so this just
04105   // does a straight shot of normalization.
04106   return Normalize();
04107 }
04108 
04109 NS_IMETHODIMP
04110 nsDocument::RenameNode(nsIDOMNode *aNode,
04111                        const nsAString& namespaceURI,
04112                        const nsAString& qualifiedName,
04113                        nsIDOMNode **aReturn)
04114 {
04115   if (!aNode) {
04116     // not an element or attribute
04117     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
04118   }
04119   
04120   PRUint16 nodeType;
04121   aNode->GetNodeType(&nodeType);
04122   if (nodeType == nsIDOMNode::ELEMENT_NODE ||
04123       nodeType == nsIDOMNode::ATTRIBUTE_NODE) {
04124     // XXXcaa Write me - Coming soon to a document near you!
04125     return NS_ERROR_NOT_IMPLEMENTED;
04126   }
04127 
04128   return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
04129 }
04130 
04131 
04132 NS_IMETHODIMP
04133 nsDocument::GetOwnerDocument(nsIDOMDocument** aOwnerDocument)
04134 {
04135   *aOwnerDocument = nsnull;
04136 
04137   return NS_OK;
04138 }
04139 
04140 nsresult
04141 nsDocument::GetListenerManager(nsIEventListenerManager **aInstancePtrResult)
04142 {
04143   if (mListenerManager) {
04144     *aInstancePtrResult = mListenerManager;
04145     NS_ADDREF(*aInstancePtrResult);
04146 
04147     return NS_OK;
04148   }
04149 
04150   nsresult rv = NS_NewEventListenerManager(getter_AddRefs(mListenerManager));
04151   NS_ENSURE_SUCCESS(rv, rv);
04152 
04153   mListenerManager->SetListenerTarget(NS_STATIC_CAST(nsIDocument *,this));
04154 
04155   *aInstancePtrResult = mListenerManager;
04156   NS_ADDREF(*aInstancePtrResult);
04157 
04158   return NS_OK;
04159 }
04160 
04161 nsresult
04162 nsDocument::HandleEvent(nsIDOMEvent *aEvent)
04163 {
04164   PRBool defaultActionEnabled;
04165   return DispatchEvent(aEvent, &defaultActionEnabled);
04166 }
04167 
04168 NS_IMETHODIMP
04169 nsDocument::GetSystemEventGroup(nsIDOMEventGroup **aGroup)
04170 {
04171   nsCOMPtr<nsIEventListenerManager> manager;
04172   if (NS_SUCCEEDED(GetListenerManager(getter_AddRefs(manager))) && manager) {
04173     return manager->GetSystemEventGroupLM(aGroup);
04174   }
04175 
04176   return NS_ERROR_FAILURE;
04177 }
04178 
04179 nsresult
04180 nsDocument::HandleDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent,
04181                            nsIDOMEvent** aDOMEvent, PRUint32 aFlags,
04182                            nsEventStatus* aEventStatus)
04183 {
04184   // Make sure to tell the event that dispatch has started.
04185   NS_MARK_EVENT_DISPATCH_STARTED(aEvent);
04186 
04187   nsresult mRet = NS_OK;
04188   PRBool externalDOMEvent = PR_FALSE;
04189 
04190   nsIDOMEvent* domEvent = nsnull;
04191 
04192   if (NS_EVENT_FLAG_INIT & aFlags) {
04193     if (aDOMEvent) {
04194       if (*aDOMEvent) {
04195         externalDOMEvent = PR_TRUE;
04196       }
04197     }
04198     else {
04199       aDOMEvent = &domEvent;
04200     }
04201     aEvent->flags |= aFlags;
04202     aFlags &= ~(NS_EVENT_FLAG_CANT_BUBBLE | NS_EVENT_FLAG_CANT_CANCEL);
04203     aFlags |= NS_EVENT_FLAG_BUBBLE | NS_EVENT_FLAG_CAPTURE;
04204   }
04205 
04206   // Capturing stage
04207   if (NS_EVENT_FLAG_CAPTURE & aFlags && nsnull != mScriptGlobalObject) {
04208     mScriptGlobalObject->HandleDOMEvent(aPresContext, aEvent, aDOMEvent,
04209                                         aFlags & NS_EVENT_CAPTURE_MASK,
04210                                         aEventStatus);
04211   }
04212 
04213   // Local handling stage
04214   // Check for null mDOMSlots or ELM, check if we're a non-bubbling
04215   // event in the bubbling state (bubbling state is indicated by the
04216   // presence of the NS_EVENT_FLAG_BUBBLE flag and not the
04217   // NS_EVENT_FLAG_INIT).
04218   if (mListenerManager &&
04219       !(NS_EVENT_FLAG_CANT_BUBBLE & aEvent->flags &&
04220         NS_EVENT_FLAG_BUBBLE & aFlags && !(NS_EVENT_FLAG_INIT & aFlags))) {
04221     aEvent->flags |= aFlags;
04222     mListenerManager->HandleEvent(aPresContext, aEvent, aDOMEvent, this,
04223                                   aFlags, aEventStatus);
04224     aEvent->flags &= ~aFlags;
04225   }
04226 
04227   // Bubbling stage
04228   if (NS_EVENT_FLAG_BUBBLE & aFlags && nsnull != mScriptGlobalObject) {
04229     mScriptGlobalObject->HandleDOMEvent(aPresContext, aEvent, aDOMEvent,
04230                                         aFlags & NS_EVENT_BUBBLE_MASK,
04231                                         aEventStatus);
04232   }
04233 
04234   if (NS_EVENT_FLAG_INIT & aFlags) {
04235     // We're leaving the DOM event loop so if we created a DOM event,
04236     // release here.
04237     if (*aDOMEvent && !externalDOMEvent) {
04238       nsrefcnt rc;
04239       NS_RELEASE2(*aDOMEvent, rc);
04240       if (0 != rc) {
04241         // Okay, so someone in the DOM loop (a listener, JS object)
04242         // still has a ref to the DOM Event but the internal data
04243         // hasn't been malloc'd.  Force a copy of the data here so the
04244         // DOM Event is still valid.
04245         nsCOMPtr<nsIPrivateDOMEvent> privateEvent =
04246           do_QueryInterface(*aDOMEvent);
04247         if (privateEvent) {
04248           privateEvent->DuplicatePrivateData();
04249         }
04250       }
04251       aDOMEvent = nsnull;
04252     }
04253 
04254     // Now that we're done with this event, remove the flag that says
04255     // we're in the process of dispatching this event.
04256     NS_MARK_EVENT_DISPATCH_DONE(aEvent);
04257   }
04258 
04259   return mRet;
04260 }
04261 
04262 nsresult
04263 nsDocument::AddEventListenerByIID(nsIDOMEventListener *aListener,
04264                                   const nsIID& aIID)
04265 {
04266   nsCOMPtr<nsIEventListenerManager> manager;
04267 
04268   GetListenerManager(getter_AddRefs(manager));
04269   if (manager) {
04270     manager->AddEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE);
04271     return NS_OK;
04272   }
04273 
04274   return NS_ERROR_FAILURE;
04275 }
04276 
04277 nsresult
04278 nsDocument::RemoveEventListenerByIID(nsIDOMEventListener *aListener,
04279                                      const nsIID& aIID)
04280 {
04281   if (!mListenerManager) {
04282     return NS_ERROR_FAILURE;
04283   }
04284 
04285   mListenerManager->RemoveEventListenerByIID(aListener, aIID,
04286                                              NS_EVENT_FLAG_BUBBLE);
04287   return NS_OK;
04288 }
04289 
04290 nsresult
04291 nsDocument::AddEventListener(const nsAString& aType,
04292                              nsIDOMEventListener* aListener,
04293                              PRBool aUseCapture)
04294 {
04295   return AddEventListener(aType, aListener, aUseCapture,
04296                           !nsContentUtils::IsChromeDoc(this));
04297 }
04298 
04299 nsresult
04300 nsDocument::RemoveEventListener(const nsAString& aType,
04301                                 nsIDOMEventListener* aListener,
04302                                 PRBool aUseCapture)
04303 {
04304   return RemoveGroupedEventListener(aType, aListener, aUseCapture, nsnull);
04305 }
04306 
04307 NS_IMETHODIMP
04308 nsDocument::DispatchEvent(nsIDOMEvent* aEvent, PRBool *_retval)
04309 {
04310   // Obtain a presentation context
04311   nsIPresShell *shell = GetShellAt(0);
04312   if (!shell)
04313     return NS_ERROR_FAILURE;
04314 
04315   nsCOMPtr<nsPresContext> context = shell->GetPresContext();
04316 
04317   return context->EventStateManager()->
04318     DispatchNewEvent(NS_STATIC_CAST(nsIDOMDocument*, this), aEvent, _retval);
04319 }
04320 
04321 NS_IMETHODIMP
04322 nsDocument::AddGroupedEventListener(const nsAString& aType,
04323                                     nsIDOMEventListener *aListener,
04324                                     PRBool aUseCapture,
04325                                     nsIDOMEventGroup *aEvtGrp)
04326 {
04327   nsCOMPtr<nsIEventListenerManager> manager;
04328 
04329   nsresult rv = GetListenerManager(getter_AddRefs(manager));
04330   if (NS_SUCCEEDED(rv) && manager) {
04331     PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
04332 
04333     manager->AddEventListenerByType(aListener, aType, flags, aEvtGrp);
04334     return NS_OK;
04335   }
04336 
04337   return rv;
04338 }
04339 
04340 NS_IMETHODIMP
04341 nsDocument::RemoveGroupedEventListener(const nsAString& aType,
04342                                        nsIDOMEventListener *aListener,
04343                                        PRBool aUseCapture,
04344                                        nsIDOMEventGroup *aEvtGrp)
04345 {
04346   if (!mListenerManager) {
04347     return NS_ERROR_FAILURE;
04348   }
04349 
04350   PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
04351 
04352   mListenerManager->RemoveEventListenerByType(aListener, aType, flags,
04353                                               aEvtGrp);
04354   return NS_OK;
04355 }
04356 
04357 NS_IMETHODIMP
04358 nsDocument::CanTrigger(const nsAString & type, PRBool *_retval)
04359 {
04360   return NS_ERROR_NOT_IMPLEMENTED;
04361 }
04362 
04363 NS_IMETHODIMP
04364 nsDocument::IsRegisteredHere(const nsAString & type, PRBool *_retval)
04365 {
04366   return NS_ERROR_NOT_IMPLEMENTED;
04367 }
04368 
04369 NS_IMETHODIMP
04370 nsDocument::AddEventListener(const nsAString& aType,
04371                              nsIDOMEventListener *aListener,
04372                              PRBool aUseCapture, PRBool aWantsUntrusted)
04373 {
04374   nsCOMPtr<nsIEventListenerManager> manager;
04375   nsresult rv = GetListenerManager(getter_AddRefs(manager));
04376   NS_ENSURE_SUCCESS(rv, rv);
04377 
04378   PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
04379 
04380   if (aWantsUntrusted) {
04381     flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
04382   }
04383 
04384   return manager->AddEventListenerByType(aListener, aType, flags, nsnull);
04385 }
04386 
04387 NS_IMETHODIMP
04388 nsDocument::CreateEvent(const nsAString& aEventType, nsIDOMEvent** aReturn)
04389 {
04390   NS_ENSURE_ARG_POINTER(aReturn);
04391   *aReturn = nsnull;
04392 
04393   // Obtain a presentation shell
04394 
04395   nsIPresShell *shell = GetShellAt(0);
04396 
04397   nsPresContext *presContext = nsnull;
04398 
04399   if (shell) {
04400     // Retrieve the context
04401     presContext = shell->GetPresContext();
04402   }
04403 
04404   nsCOMPtr<nsIEventListenerManager> manager;
04405   GetListenerManager(getter_AddRefs(manager));
04406   if (manager) {
04407     return manager->CreateEvent(presContext, nsnull, aEventType, aReturn);
04408   }
04409 
04410   return NS_ERROR_FAILURE;
04411 }
04412 
04413 NS_IMETHODIMP
04414 nsDocument::CreateEventGroup(nsIDOMEventGroup **aInstancePtrResult)
04415 {
04416   nsresult rv;
04417   nsCOMPtr<nsIDOMEventGroup> group(do_CreateInstance(kDOMEventGroupCID, &rv));
04418   NS_ENSURE_SUCCESS(rv, rv);
04419 
04420   *aInstancePtrResult = group;
04421   NS_ADDREF(*aInstancePtrResult);
04422 
04423   return NS_OK;
04424 }
04425 
04426 void
04427 nsDocument::FlushPendingNotifications(mozFlushType aType)
04428 {
04429   if (aType == (aType & (Flush_Content | Flush_SinkNotifications)) ||
04430       !mScriptGlobalObject) {
04431     // Nothing to do here
04432     return;
04433   }
04434 
04435   // We should be able to replace all this nsIDocShell* code with code
04436   // that uses mParentDocument, but mParentDocument is never set in
04437   // the current code!
04438 
04439   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem =
04440     do_QueryInterface(mScriptGlobalObject->GetDocShell());
04441 
04442   if (docShellAsItem) {
04443     nsCOMPtr<nsIDocShellTreeItem> docShellParent;
04444     docShellAsItem->GetSameTypeParent(getter_AddRefs(docShellParent));
04445 
04446     nsCOMPtr<nsIDOMWindow> win(do_GetInterface(docShellParent));
04447 
04448     if (win) {
04449       nsCOMPtr<nsIDOMDocument> dom_doc;
04450       win->GetDocument(getter_AddRefs(dom_doc));
04451 
04452       nsCOMPtr<nsIDocument> doc(do_QueryInterface(dom_doc));
04453 
04454       // If we have a parent we must flush the parent too to ensure that our
04455       // container is reflown if its size was changed.  But if it's not safe to
04456       // flush ourselves, then don't flush the parent, since that can cause
04457       // things like resizes of our frame's widget, which we can't handle while
04458       // flushing is unsafe.
04459       if (doc && IsSafeToFlush()) {
04460         doc->FlushPendingNotifications(aType);
04461       }
04462     }
04463   }
04464 
04465   PRInt32 i, count = mPresShells.Count();
04466 
04467   for (i = 0; i < count; i++) {
04468     nsCOMPtr<nsIPresShell> shell =
04469       NS_STATIC_CAST(nsIPresShell*, mPresShells[i]);
04470 
04471     if (shell) {
04472       shell->FlushPendingNotifications(aType);
04473     }
04474   }
04475 }
04476 
04477 nsIScriptEventManager*
04478 nsDocument::GetScriptEventManager()
04479 {
04480   if (!mScriptEventManager) {
04481     mScriptEventManager = new nsScriptEventManager(this);
04482     // automatically AddRefs
04483   }
04484 
04485   return mScriptEventManager;
04486 }
04487 
04488 void
04489 nsDocument::SetXMLDeclaration(const PRUnichar *aVersion,
04490                               const PRUnichar *aEncoding,
04491                               const PRInt32 aStandalone)
04492 {
04493   if (!aVersion || *aVersion == '\0') {
04494     mXMLDeclarationBits = 0;
04495     return;
04496   }
04497 
04498   mXMLDeclarationBits = XML_DECLARATION_BITS_DECLARATION_EXISTS;
04499 
04500   if (aEncoding && *aEncoding != '\0') {
04501     mXMLDeclarationBits |= XML_DECLARATION_BITS_ENCODING_EXISTS;
04502   }
04503 
04504   if (aStandalone == 1) {
04505     mXMLDeclarationBits |= XML_DECLARATION_BITS_STANDALONE_EXISTS |
04506                            XML_DECLARATION_BITS_STANDALONE_YES;
04507   }
04508   else if (aStandalone == 0) {
04509     mXMLDeclarationBits |= XML_DECLARATION_BITS_STANDALONE_EXISTS;
04510   }
04511 }
04512 
04513 void
04514 nsDocument::GetXMLDeclaration(nsAString& aVersion, nsAString& aEncoding,
04515                               nsAString& aStandalone)
04516 {
04517   aVersion.Truncate();
04518   aEncoding.Truncate();
04519   aStandalone.Truncate();
04520 
04521   if (!(mXMLDeclarationBits & XML_DECLARATION_BITS_DECLARATION_EXISTS)) {
04522     return;
04523   }
04524 
04525   // always until we start supporting 1.1 etc.
04526   aVersion.AssignLiteral("1.0");
04527 
04528   if (mXMLDeclarationBits & XML_DECLARATION_BITS_ENCODING_EXISTS) {
04529     // This is what we have stored, not necessarily what was written
04530     // in the original
04531     GetCharacterSet(aEncoding);
04532   }
04533 
04534   if (mXMLDeclarationBits & XML_DECLARATION_BITS_STANDALONE_EXISTS) {
04535     if (mXMLDeclarationBits & XML_DECLARATION_BITS_STANDALONE_YES) {
04536       aStandalone.AssignLiteral("yes");
04537     } else {
04538       aStandalone.AssignLiteral("no");
04539     }
04540   }
04541 }
04542 
04543 PRBool
04544 nsDocument::IsScriptEnabled()
04545 {
04546   nsCOMPtr<nsIScriptSecurityManager> sm(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID));
04547   NS_ENSURE_TRUE(sm, PR_TRUE);
04548 
04549   nsIPrincipal* principal = GetPrincipal();
04550   NS_ENSURE_TRUE(principal, PR_TRUE);
04551 
04552   nsIScriptGlobalObject* globalObject = GetScriptGlobalObject();
04553   NS_ENSURE_TRUE(globalObject, PR_TRUE);
04554 
04555   nsIScriptContext *scriptContext = globalObject->GetContext();
04556   NS_ENSURE_TRUE(scriptContext, PR_TRUE);
04557 
04558   JSContext* cx = (JSContext *) scriptContext->GetNativeContext();
04559   NS_ENSURE_TRUE(cx, PR_TRUE);
04560 
04561   PRBool enabled;
04562   nsresult rv = sm->CanExecuteScripts(cx, principal, &enabled);
04563   NS_ENSURE_SUCCESS(rv, PR_TRUE);
04564   return enabled;
04565 }
04566 
04567 nsresult
04568 nsDocument::GetRadioGroup(const nsAString& aName,
04569                           nsRadioGroupStruct **aRadioGroup)
04570 {
04571   nsStringKey key(aName);
04572   nsRadioGroupStruct *radioGroup =
04573     NS_STATIC_CAST(nsRadioGroupStruct *, mRadioGroups.Get(&key));
04574 
04575   if (!radioGroup) {
04576     radioGroup = new nsRadioGroupStruct();
04577     NS_ENSURE_TRUE(radioGroup, NS_ERROR_OUT_OF_MEMORY);
04578     mRadioGroups.Put(&key, radioGroup);
04579   }
04580 
04581   *aRadioGroup = radioGroup;
04582 
04583   return NS_OK;
04584 }
04585 
04586 NS_IMETHODIMP
04587 nsDocument::SetCurrentRadioButton(const nsAString& aName,
04588                                   nsIDOMHTMLInputElement* aRadio)
04589 {
04590   nsRadioGroupStruct* radioGroup = nsnull;
04591   GetRadioGroup(aName, &radioGroup);
04592   if (radioGroup) {
04593     radioGroup->mSelectedRadioButton = aRadio;
04594   }
04595 
04596   return NS_OK;
04597 }
04598 
04599 NS_IMETHODIMP
04600 nsDocument::GetCurrentRadioButton(const nsAString& aName,
04601                                   nsIDOMHTMLInputElement** aRadio)
04602 {
04603   nsRadioGroupStruct* radioGroup = nsnull;
04604   GetRadioGroup(aName, &radioGroup);
04605   if (radioGroup) {
04606     *aRadio = radioGroup->mSelectedRadioButton;
04607     NS_IF_ADDREF(*aRadio);
04608   }
04609 
04610   return NS_OK;
04611 }
04612 
04613 NS_IMETHODIMP
04614 nsDocument::GetPositionInGroup(nsIDOMHTMLInputElement *aRadio,
04615                                PRInt32 *aPositionIndex,
04616                                PRInt32 *aItemsInGroup)
04617 {
04618   *aPositionIndex = 0;
04619   *aItemsInGroup = 1;
04620   nsAutoString name;
04621   aRadio->GetName(name);
04622   if (name.IsEmpty()) {
04623     return NS_OK;
04624   }
04625 
04626   nsRadioGroupStruct* radioGroup = nsnull;
04627   nsresult rv = GetRadioGroup(name, &radioGroup);
04628   NS_ENSURE_SUCCESS(rv, rv);
04629 
04630   nsCOMPtr<nsIFormControl> radioControl(do_QueryInterface(aRadio));
04631   NS_ASSERTION(radioControl, "Radio button should implement nsIFormControl");
04632   *aPositionIndex = radioGroup->mRadioButtons.IndexOf(radioControl);
04633   NS_ASSERTION(*aPositionIndex >= 0, "Radio button not found in its own group");
04634   *aItemsInGroup = radioGroup->mRadioButtons.Count();
04635 
04636   return NS_OK;
04637 }
04638 
04639 NS_IMETHODIMP
04640 nsDocument::GetNextRadioButton(const nsAString& aName,
04641                                const PRBool aPrevious,
04642                                nsIDOMHTMLInputElement*  aFocusedRadio,
04643                                nsIDOMHTMLInputElement** aRadioOut)
04644 {
04645   // XXX Can we combine the HTML radio button method impls of 
04646   //     nsDocument and nsHTMLFormControl?
04647   // XXX Why is HTML radio button stuff in nsDocument, as 
04648   //     opposed to nsHTMLDocument?
04649   *aRadioOut = nsnull;
04650 
04651   nsRadioGroupStruct* radioGroup = nsnull;
04652   GetRadioGroup(aName, &radioGroup);
04653   if (!radioGroup) {
04654     return NS_ERROR_FAILURE;
04655   }
04656 
04657   // Return the radio button relative to the focused radio button.
04658   // If no radio is focused, get the radio relative to the selected one.
04659   nsCOMPtr<nsIDOMHTMLInputElement> currentRadio;
04660   if (aFocusedRadio) {
04661     currentRadio = aFocusedRadio;
04662   }
04663   else {
04664     currentRadio = radioGroup->mSelectedRadioButton;
04665     if (!currentRadio) {
04666       return NS_ERROR_FAILURE;
04667     }
04668   }
04669   nsCOMPtr<nsIFormControl> radioControl(do_QueryInterface(currentRadio));
04670   PRInt32 index = radioGroup->mRadioButtons.IndexOf(radioControl);
04671   if (index < 0) {
04672     return NS_ERROR_FAILURE;
04673   }
04674 
04675   PRInt32 numRadios = radioGroup->mRadioButtons.Count();
04676   PRBool disabled;
04677   nsCOMPtr<nsIDOMHTMLInputElement> radio;
04678   do {
04679     if (aPrevious) {
04680       if (--index < 0) {
04681         index = numRadios -1;
04682       }
04683     }
04684     else if (++index >= numRadios) {
04685       index = 0;
04686     }
04687     radio = do_QueryInterface(NS_STATIC_CAST(nsIFormControl*, 
04688                               radioGroup->mRadioButtons.ElementAt(index)));
04689     NS_ASSERTION(radio, "mRadioButtons holding a non-radio button");
04690     radio->GetDisabled(&disabled);
04691   } while (disabled && radio != currentRadio);
04692 
04693   NS_IF_ADDREF(*aRadioOut = radio);
04694   return NS_OK;
04695 }
04696 
04697 NS_IMETHODIMP
04698 nsDocument::AddToRadioGroup(const nsAString& aName,
04699                             nsIFormControl* aRadio)
04700 {
04701   nsRadioGroupStruct* radioGroup = nsnull;
04702   GetRadioGroup(aName, &radioGroup);
04703   if (radioGroup) {
04704     radioGroup->mRadioButtons.AppendElement(aRadio);
04705     NS_IF_ADDREF(aRadio);
04706   }
04707 
04708   return NS_OK;
04709 }
04710 
04711 NS_IMETHODIMP
04712 nsDocument::RemoveFromRadioGroup(const nsAString& aName,
04713                                  nsIFormControl* aRadio)
04714 {
04715   nsRadioGroupStruct* radioGroup = nsnull;
04716   GetRadioGroup(aName, &radioGroup);
04717   if (radioGroup) {
04718     if (radioGroup->mRadioButtons.RemoveElement(aRadio)) {
04719       NS_IF_RELEASE(aRadio);
04720     }
04721   }
04722 
04723   return NS_OK;
04724 }
04725 
04726 NS_IMETHODIMP
04727 nsDocument::WalkRadioGroup(const nsAString& aName,
04728                            nsIRadioVisitor* aVisitor)
04729 {
04730   nsRadioGroupStruct* radioGroup = nsnull;
04731   GetRadioGroup(aName, &radioGroup);
04732   if (!radioGroup) {
04733     return NS_OK;
04734   }
04735 
04736   PRBool stop = PR_FALSE;
04737   for (int i = 0; i < radioGroup->mRadioButtons.Count(); i++) {
04738     aVisitor->Visit(NS_STATIC_CAST(nsIFormControl *,
04739                                    radioGroup->mRadioButtons.ElementAt(i)),
04740                     &stop);
04741     if (stop) {
04742       return NS_OK;
04743     }
04744   }
04745 
04746   return NS_OK;
04747 }
04748 
04749 void
04750 nsDocument::RetrieveRelevantHeaders(nsIChannel *aChannel)
04751 {
04752   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
04753   PRTime modDate = LL_ZERO;
04754   nsresult rv;
04755 
04756   if (httpChannel) {
04757     nsCAutoString tmp;
04758     rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("last-modified"),
04759                                         tmp);
04760 
04761     if (NS_SUCCEEDED(rv)) {
04762       PRTime time;
04763       PRStatus st = PR_ParseTimeString(tmp.get(), PR_TRUE, &time);
04764       if (st == PR_SUCCESS) {
04765         modDate = time;
04766       }
04767     }
04768 
04769     // The misspelled key 'referer' is as per the HTTP spec
04770     rv = httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("referer"),
04771                                        mReferrer);
04772     if (NS_FAILED(rv)) {
04773       mReferrer.Truncate();
04774     }
04775 
04776     static const char *const headers[] = {
04777       "default-style",
04778       "content-style-type",
04779       "content-language",
04780       "content-disposition",
04781       "refresh",
04782       // add more http headers if you need
04783       // XXXbz don't add content-location support without reading bug
04784       // 238654 and its dependencies/dups first.
04785       0
04786     };
04787     
04788     nsCAutoString headerVal;
04789     const char *const *name = headers;
04790     while (*name) {
04791       rv =
04792         httpChannel->GetResponseHeader(nsDependentCString(*name), headerVal);
04793       if (NS_SUCCEEDED(rv) && !headerVal.IsEmpty()) {
04794         nsCOMPtr<nsIAtom> key = do_GetAtom(*name);
04795         SetHeaderData(key, NS_ConvertASCIItoUCS2(headerVal));
04796       }
04797       ++name;
04798     }
04799   } else {
04800     nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(aChannel);
04801     if (fileChannel) {
04802       nsCOMPtr<nsIFile> file;
04803       fileChannel->GetFile(getter_AddRefs(file));
04804       if (file) {
04805         PRTime msecs;
04806         rv = file->GetLastModifiedTime(&msecs);
04807 
04808         if (NS_SUCCEEDED(rv)) {
04809           PRInt64 intermediateValue;
04810           LL_I2L(intermediateValue, PR_USEC_PER_MSEC);
04811           LL_MUL(modDate, msecs, intermediateValue);
04812         }
04813       }
04814     } else {
04815       nsCOMPtr<nsIMultiPartChannel> partChannel = do_QueryInterface(aChannel);
04816       if (partChannel) {
04817         nsCAutoString contentDisp;
04818         rv = partChannel->GetContentDisposition(contentDisp);
04819         if (NS_SUCCEEDED(rv) && !contentDisp.IsEmpty()) {
04820           SetHeaderData(nsHTMLAtoms::headerContentDisposition,
04821                         NS_ConvertASCIItoUCS2(contentDisp));
04822         }
04823       }
04824     }
04825   }
04826 
04827   if (LL_IS_ZERO(modDate)) {
04828     // We got nothing from our attempt to ask nsIFileChannel and
04829     // nsIHttpChannel for the last modified time. Return the current
04830     // time.
04831     modDate = PR_Now();
04832   }
04833 
04834   mLastModified.Truncate();
04835   if (LL_NE(modDate, LL_ZERO)) {
04836     PRExplodedTime prtime;
04837     PR_ExplodeTime(modDate, PR_LocalTimeParameters, &prtime);
04838     // "MM/DD/YYYY hh:mm:ss"
04839     char formatedTime[24];
04840     if (PR_snprintf(formatedTime, sizeof(formatedTime),
04841                     "%02ld/%02ld/%04hd %02ld:%02ld:%02ld",
04842                     prtime.tm_month + 1, prtime.tm_mday, prtime.tm_year,
04843                     prtime.tm_hour     ,  prtime.tm_min,  prtime.tm_sec)) {
04844       CopyASCIItoUTF16(nsDependentCString(formatedTime), mLastModified);
04845     }
04846   }
04847 }
04848 
04849 nsresult
04850 nsDocument::CreateElem(nsIAtom *aName, nsIAtom *aPrefix, PRInt32 aNamespaceID,
04851                        PRBool aDocumentDefaultType, nsIContent **aResult)
04852 {
04853   nsresult rv;
04854 #ifdef DEBUG
04855   nsAutoString qName;
04856   if (aPrefix) {
04857     aPrefix->ToString(qName);
04858     qName.Append(':');
04859   }
04860   const char *name;
04861   aName->GetUTF8String(&name);
04862   AppendUTF8toUTF16(name, qName);
04863 
04864   rv = nsContentUtils::CheckQName(qName, PR_TRUE);
04865   NS_ASSERTION(NS_SUCCEEDED(rv),
04866                "Don't pass invalid names to nsDocument::CreateElem, "
04867                "check caller.");
04868 #endif
04869 
04870   *aResult = nsnull;
04871   
04872   PRInt32 elementType = aDocumentDefaultType ? mDefaultElementType :
04873                                                aNamespaceID;
04874 
04875   nsCOMPtr<nsINodeInfo> nodeInfo;
04876   rv = mNodeInfoManager->GetNodeInfo(aName, aPrefix, aNamespaceID,
04877                                      getter_AddRefs(nodeInfo));
04878   NS_ENSURE_SUCCESS(rv, rv);
04879 
04880   return CreateElement(nodeInfo, elementType, aResult);
04881 }
04882 
04883 nsresult
04884 nsDocument::CreateElement(nsINodeInfo *aNodeInfo, PRInt32 aElementType,
04885                           nsIContent** aResult)
04886 {
04887   nsCOMPtr<nsIContent> content;
04888   nsresult rv = NS_NewElement(getter_AddRefs(content), aElementType,
04889                               aNodeInfo);
04890   NS_ENSURE_SUCCESS(rv, rv);
04891 
04892   content->SetContentID(mNextContentID++);
04893 
04894   content.swap(*aResult);
04895 
04896   return NS_OK;
04897 }
04898 
04899 PRBool
04900 nsDocument::IsSafeToFlush() const
04901 {
04902   PRBool isSafeToFlush = PR_TRUE;
04903   PRInt32 i = 0, n = mPresShells.Count();
04904   while (i < n && isSafeToFlush) {
04905     nsCOMPtr<nsIPresShell> shell =
04906       NS_STATIC_CAST(nsIPresShell*, mPresShells[i]);
04907 
04908     if (shell) {
04909       shell->IsSafeToFlush(isSafeToFlush);
04910     }
04911     ++i;
04912   }
04913   return isSafeToFlush;
04914 }
04915 
04916 void*
04917 nsDocument::GetProperty(nsIAtom *aPropertyName, nsresult *aStatus) const
04918 {
04919   // ick
04920   return NS_CONST_CAST(nsDocument*, this)->mPropertyTable.GetProperty(this, aPropertyName, aStatus);
04921 }
04922 
04923 nsresult
04924 nsDocument::SetProperty(nsIAtom            *aPropertyName,
04925                         void               *aValue,
04926                         NSPropertyDtorFunc  aDtor)
04927 {
04928   return mPropertyTable.SetProperty(this, aPropertyName, aValue,
04929                                     aDtor, nsnull);
04930 }
04931 
04932 nsresult
04933 nsDocument::DeleteProperty(nsIAtom *aPropertyName)
04934 {
04935   return mPropertyTable.DeleteProperty(this, aPropertyName);
04936 }
04937 
04938 void*
04939 nsDocument::UnsetProperty(nsIAtom *aPropertyName, nsresult *aStatus)
04940 {
04941   return mPropertyTable.UnsetProperty(this, aPropertyName, aStatus);
04942 }
04943 
04944 nsresult
04945 nsDocument::Sanitize()
04946 {
04947   // Sanitize the document by resetting all password fields and any form
04948   // fields with autocomplete=off to their default values.  We do this now,
04949   // instead of when the presentation is restored, to offer some protection
04950   // in case there is ever an exploit that allows a cached document to be
04951   // accessed from a different document.
04952 
04953   // First locate all input elements, regardless of whether they are
04954   // in a form, and reset the password and autocomplete=off elements.
04955 
04956   nsCOMPtr<nsIDOMNodeList> nodes;
04957   nsresult rv = GetElementsByTagName(NS_LITERAL_STRING("input"),
04958                                      getter_AddRefs(nodes));
04959   NS_ENSURE_SUCCESS(rv, rv);
04960 
04961   PRUint32 length = 0;
04962   if (nodes)
04963     nodes->GetLength(&length);
04964 
04965   nsCOMPtr<nsIDOMNode> item;
04966   nsAutoString value;
04967   PRUint32 i;
04968 
04969   for (i = 0; i < length; ++i) {
04970     nodes->Item(i, getter_AddRefs(item));
04971     NS_ASSERTION(item, "null item in node list!");
04972 
04973     nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(item);
04974     if (!input)
04975       continue;
04976 
04977     PRBool resetValue = PR_FALSE;
04978 
04979     input->GetAttribute(NS_LITERAL_STRING("autocomplete"), value);
04980     if (value.LowerCaseEqualsLiteral("off")) {
04981       resetValue = PR_TRUE;
04982     } else {
04983       input->GetType(value);
04984       if (value.LowerCaseEqualsLiteral("password"))
04985         resetValue = PR_TRUE;
04986     }
04987 
04988     if (resetValue) {
04989       nsCOMPtr<nsIFormControl> fc = do_QueryInterface(input);
04990       fc->Reset();
04991     }
04992   }
04993 
04994   // Now locate all _form_ elements that have autocomplete=off and reset them
04995   rv = GetElementsByTagName(NS_LITERAL_STRING("form"), getter_AddRefs(nodes));
04996   NS_ENSURE_SUCCESS(rv, rv);
04997 
04998   length = 0;
04999   if (nodes)
05000     nodes->GetLength(&length);
05001 
05002   for (i = 0; i < length; ++i) {
05003     nodes->Item(i, getter_AddRefs(item));
05004     NS_ASSERTION(item, "null item in nodelist");
05005 
05006     nsCOMPtr<nsIDOMHTMLFormElement> form = do_QueryInterface(item);
05007     if (!form)
05008       continue;
05009 
05010     form->GetAttribute(NS_LITERAL_STRING("autocomplete"), value);
05011     if (value.LowerCaseEqualsLiteral("off"))
05012       form->Reset();
05013   }
05014 
05015   return NS_OK;
05016 }
05017 
05018 struct SubDocEnumArgs
05019 {
05020   nsIDocument::nsSubDocEnumFunc callback;
05021   void *data;
05022 };
05023 
05024 PR_STATIC_CALLBACK(PLDHashOperator)
05025 SubDocHashEnum(PLDHashTable *table, PLDHashEntryHdr *hdr,
05026                PRUint32 number, void *arg)
05027 {
05028   SubDocMapEntry *entry = NS_STATIC_CAST(SubDocMapEntry*, hdr);
05029   SubDocEnumArgs *args = NS_STATIC_CAST(SubDocEnumArgs*, arg);
05030 
05031   nsIDocument *subdoc = entry->mSubDocument;
05032   PRBool next = subdoc ? args->callback(subdoc, args->data) : PR_TRUE;
05033 
05034   return next ? PL_DHASH_NEXT : PL_DHASH_STOP;
05035 }
05036 
05037 void
05038 nsDocument::EnumerateSubDocuments(nsSubDocEnumFunc aCallback, void *aData)
05039 {
05040   if (mSubDocuments) {
05041     SubDocEnumArgs args = { aCallback, aData };
05042     PL_DHashTableEnumerate(mSubDocuments, SubDocHashEnum, &args);
05043   }
05044 }
05045 
05046 PR_STATIC_CALLBACK(PLDHashOperator)
05047 CanCacheSubDocument(PLDHashTable *table, PLDHashEntryHdr *hdr,
05048                     PRUint32 number, void *arg)
05049 {
05050   SubDocMapEntry *entry = NS_STATIC_CAST(SubDocMapEntry*, hdr);
05051   PRBool *canCacheArg = NS_STATIC_CAST(PRBool*, arg);
05052 
05053   nsIDocument *subdoc = entry->mSubDocument;
05054 
05055   // The aIgnoreRequest we were passed is only for us, so don't pass it on.
05056   PRBool canCache = subdoc ? subdoc->CanSavePresentation(nsnull) : PR_FALSE;
05057   if (!canCache) {
05058     *canCacheArg = PR_FALSE;
05059     return PL_DHASH_STOP;
05060   }
05061 
05062   return PL_DHASH_NEXT;
05063 }
05064 
05065 #ifdef DEBUG_bryner
05066 #define DEBUG_PAGE_CACHE
05067 #endif
05068 
05069 PRBool
05070 nsDocument::CanSavePresentation(nsIRequest *aNewRequest)
05071 {
05072   // Check our event listneer manager for unload/beforeunload listeners.
05073   nsCOMPtr<nsIDOMEventReceiver> er = do_QueryInterface(mScriptGlobalObject);
05074   if (er) {
05075     nsCOMPtr<nsIEventListenerManager> manager;
05076     er->GetListenerManager(getter_AddRefs(manager));
05077     if (manager && manager->HasUnloadListeners()) {
05078       return PR_FALSE;
05079     }
05080   }
05081 
05082   nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
05083   if (loadGroup) {
05084     nsCOMPtr<nsISimpleEnumerator> requests;
05085     loadGroup->GetRequests(getter_AddRefs(requests));
05086 
05087     PRBool hasMore = PR_FALSE;
05088 
05089     while (NS_SUCCEEDED(requests->HasMoreElements(&hasMore)) && hasMore) {
05090       nsCOMPtr<nsISupports> elem;
05091       requests->GetNext(getter_AddRefs(elem));
05092 
05093       nsCOMPtr<nsIRequest> request = do_QueryInterface(elem);
05094       if (request && request != aNewRequest) {
05095 #ifdef DEBUG_PAGE_CACHE
05096         nsCAutoString requestName, docSpec;
05097         request->GetName(requestName);
05098         if (mDocumentURI)
05099           mDocumentURI->GetSpec(docSpec);
05100 
05101         printf("document %s has request %s\n",
05102                docSpec.get(), requestName.get());
05103 #endif
05104         return PR_FALSE;
05105       }
05106     }
05107   }
05108 
05109   PRBool canCache = PR_TRUE;
05110   if (mSubDocuments)
05111     PL_DHashTableEnumerate(mSubDocuments, CanCacheSubDocument, &canCache);
05112 
05113   return canCache;
05114 }
05115 
05116 void
05117 nsDocument::Destroy()
05118 {
05119   // The ContentViewer wants to release the document now.  So, tell our content
05120   // to drop any references to the document so that it can be destroyed.
05121   if (mIsGoingAway)
05122     return;
05123 
05124   PRInt32 count = mChildren.ChildCount();
05125 
05126   mIsGoingAway = PR_TRUE;
05127   DestroyLinkMap();
05128   for (PRInt32 indx = 0; indx < count; ++indx) {
05129     // XXXbz what we _should_ do here is to clear mChildren and null out
05130     // mRootContent.  If we did this (or at least the latter), we could remove
05131     // the silly null-checks in nsHTMLDocument::MatchLinks.  Unfortunately,
05132     // doing that introduces several problems:
05133     // 1) Focus issues (see bug 341730).  The fix for bug 303260 may fix these.
05134     // 2) Crashes in OnPageHide if it fires after Destroy.  See bug 303260
05135     //    comments 9 and 10.
05136     // So we're just creating an inconsistent DOM for now and hoping.  :(
05137     mChildren.ChildAt(indx)->UnbindFromTree();
05138   }
05139 
05140   // Propagate the out-of-band notification to each PresShell's anonymous
05141   // content as well. This ensures that there aren't any accidental references
05142   // left in anonymous content keeping the document alive. (While not strictly
05143   // necessary -- the PresShell owns us -- it's tidy.)
05144   for (count = mPresShells.Count() - 1; count >= 0; --count) {
05145     nsCOMPtr<nsIPresShell> shell =
05146       NS_STATIC_CAST(nsIPresShell*, mPresShells[count]);
05147     if (!shell)
05148       continue;
05149 
05150     shell->ReleaseAnonymousContent();
05151   }
05152 
05153   mLayoutHistoryState = nsnull;
05154 
05155   nsContentList::OnDocumentDestroy(this);
05156 }
05157 
05158 already_AddRefed<nsILayoutHistoryState>
05159 nsDocument::GetLayoutHistoryState() const
05160 {
05161   nsILayoutHistoryState* state = nsnull;
05162   if (!mScriptGlobalObject) {
05163     NS_IF_ADDREF(state = mLayoutHistoryState);
05164   } else {
05165     nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocumentContainer));
05166     if (docShell) {
05167       docShell->GetLayoutHistoryState(&state);
05168     }
05169   }
05170 
05171   return state;
05172 }
05173 
05174 void
05175 nsDocument::BlockOnload()
05176 {
05177   if (mOnloadBlockCount == 0) {
05178     nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
05179     if (loadGroup) {
05180       loadGroup->AddRequest(mOnloadBlocker, nsnull);
05181     }
05182   }
05183   ++mOnloadBlockCount;      
05184 }
05185 
05186 void
05187 nsDocument::UnblockOnload()
05188 {
05189   if (mOnloadBlockCount == 0) {
05190     return;
05191   }
05192 
05193   --mOnloadBlockCount;
05194 
05195   if (mOnloadBlockCount == 0) {
05196     nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
05197     if (loadGroup) {
05198       loadGroup->RemoveRequest(mOnloadBlocker, nsnull, NS_OK);
05199     }
05200   }    
05201 }
05202 
05203 void
05204 nsDocument::DispatchEventToWindow(nsEvent *aEvent)
05205 {
05206   nsIScriptGlobalObject *sgo = GetScriptGlobalObject();
05207   if (!sgo)
05208     return;
05209 
05210   nsEventStatus status = nsEventStatus_eIgnore;
05211 
05212   // There's not always a prescontext that we can use for the event.
05213   // So, we force creation of a DOMEvent so that it can explicitly targeted.
05214 
05215   nsCOMPtr<nsIEventListenerManager> lm;
05216   GetListenerManager(getter_AddRefs(lm));
05217   if (!lm)
05218     return;
05219 
05220   nsCOMPtr<nsIDOMEvent> domEvt;
05221   lm->CreateEvent(nsnull, aEvent, EmptyString(), getter_AddRefs(domEvt));
05222   if (!domEvt)
05223     return;
05224 
05225   nsCOMPtr<nsIPrivateDOMEvent> privEvt = do_QueryInterface(domEvt);
05226   NS_ASSERTION(privEvt, "DOM Event objects must implement nsIPrivateDOMEvent");
05227 
05228   privEvt->SetTarget(this);
05229 
05230   nsIDOMEvent *domEvtPtr = domEvt;
05231   sgo->HandleDOMEvent(nsnull, aEvent, &domEvtPtr, NS_EVENT_FLAG_INIT, &status);
05232 
05233   NS_ASSERTION(domEvtPtr == domEvt, "event modified during dipatch");
05234 }
05235 
05236 void
05237 nsDocument::OnPageShow(PRBool aPersisted)
05238 {
05239   mVisible = PR_TRUE;
05240   UpdateLinkMap();
05241   
05242   if (aPersisted) {
05243     // Send out notifications that our <link> elements are attached.
05244     nsRefPtr<nsContentList> links = NS_GetContentList(this,
05245                                                       nsHTMLAtoms::link,
05246                                                       kNameSpaceID_Unknown,
05247                                                       mRootContent);
05248 
05249     if (links) {
05250       PRUint32 linkCount = links->Length(PR_TRUE);
05251       for (PRUint32 i = 0; i < linkCount; ++i) {
05252         nsCOMPtr<nsILink> link = do_QueryInterface(links->Item(i, PR_FALSE));
05253         if (link) {
05254           link->LinkAdded();
05255         }
05256       }
05257     }
05258   }
05259 
05260   nsPageTransitionEvent event(PR_TRUE, NS_PAGE_SHOW, aPersisted);
05261   DispatchEventToWindow(&event);
05262 }
05263 
05264 void
05265 nsDocument::OnPageHide(PRBool aPersisted)
05266 {
05267   // Send out notifications that our <link> elements are detached,
05268   // but only if this is not a full unload.
05269   if (aPersisted) {
05270     nsRefPtr<nsContentList> links = NS_GetContentList(this,
05271                                                       nsHTMLAtoms::link,
05272                                                       kNameSpaceID_Unknown,
05273                                                       mRootContent);
05274 
05275     if (links) {
05276       PRUint32 linkCount = links->Length(PR_TRUE);
05277       for (PRUint32 i = 0; i < linkCount; ++i) {
05278         nsCOMPtr<nsILink> link = do_QueryInterface(links->Item(i, PR_FALSE));
05279         if (link) {
05280           link->LinkRemoved();
05281         }
05282       }
05283     }
05284   }
05285 
05286   // Now send out a PageHide event.
05287   nsPageTransitionEvent event(PR_TRUE, NS_PAGE_HIDE, aPersisted);
05288   DispatchEventToWindow(&event);
05289 
05290   mVisible = PR_FALSE;
05291 }
05292 
05293 static PRUint32 GetURIHash(nsIURI* aURI)
05294 {
05295   nsCAutoString str;
05296   aURI->GetSpec(str);
05297   return HashString(str);
05298 }
05299 
05300 void
05301 nsDocument::AddStyleRelevantLink(nsIContent* aContent, nsIURI* aURI)
05302 {
05303   nsUint32ToContentHashEntry* entry = mLinkMap.PutEntry(GetURIHash(aURI));
05304   if (!entry) // out of memory?
05305     return;
05306   entry->PutContent(aContent);
05307 }
05308 
05309 void
05310 nsDocument::ForgetLink(nsIContent* aContent)
05311 {
05312   // Important optimization! If the link map is empty (as it will be
05313   // during teardown because we destroy the map early), then stop
05314   // now before we waste time constructing a URI object.
05315   if (mLinkMap.Count() == 0)
05316     return;
05317     
05318   nsCOMPtr<nsIURI> uri = nsContentUtils::GetLinkURI(aContent);
05319   if (!uri)
05320     return;
05321   PRUint32 hash = GetURIHash(uri);
05322   nsUint32ToContentHashEntry* entry = mLinkMap.GetEntry(hash);
05323   if (!entry)
05324     return;
05325 
05326   entry->RemoveContent(aContent);
05327   if (entry->IsEmpty()) {
05328     // Remove the entry and allow the table to resize, in case
05329     // a lot of links are being removed from the document or modified
05330     mLinkMap.RemoveEntry(hash);
05331   }
05332 }
05333 
05334 class URIVisitNotifier : public nsUint32ToContentHashEntry::Visitor
05335 {
05336 public:
05337   nsCAutoString matchURISpec;
05338   nsCOMArray<nsIContent> contentVisited;
05339   
05340   virtual void Visit(nsIContent* aContent) {
05341     // Ensure that the URIs really match before we try to do anything
05342     nsCOMPtr<nsIURI> uri = nsContentUtils::GetLinkURI(aContent);
05343     if (!uri) {
05344       NS_ERROR("Should have found a URI for content in the link map");
05345       return;
05346     }
05347     nsCAutoString spec;
05348     uri->GetSpec(spec);
05349     // We use nsCString::Equals here instead of nsIURI::Equals because
05350     // history matching is all based on spec equality
05351     if (!spec.Equals(matchURISpec))
05352       return;
05353 
05354     // Throw away the cached link state so it gets refetched by the style
05355     // system      
05356     nsCOMPtr<nsILink> link = do_QueryInterface(aContent);
05357     if (link) {
05358       link->SetLinkState(eLinkState_Unknown);
05359     }
05360     contentVisited.AppendObject(aContent);
05361   }
05362 };
05363 
05364 void
05365 nsDocument::NotifyURIVisitednessChanged(nsIURI* aURI)
05366 {
05367   if (!mVisible) {
05368     mVisitednessChangedURIs.AppendObject(aURI);
05369     return;
05370   }
05371 
05372   nsUint32ToContentHashEntry* entry = mLinkMap.GetEntry(GetURIHash(aURI));
05373   if (!entry)
05374     return;
05375   
05376   URIVisitNotifier visitor;
05377   aURI->GetSpec(visitor.matchURISpec);
05378   entry->VisitContent(&visitor);
05379   for (PRUint32 count = visitor.contentVisited.Count(), i = 0; i < count; ++i) {
05380     ContentStatesChanged(visitor.contentVisited[i],
05381                          nsnull, NS_EVENT_STATE_VISITED);
05382   }
05383 }
05384 
05385 void
05386 nsDocument::DestroyLinkMap()
05387 {
05388   mVisitednessChangedURIs.Clear();
05389   mLinkMap.Clear();
05390 }
05391 
05392 void
05393 nsDocument::UpdateLinkMap()
05394 {
05395   NS_ASSERTION(mVisible,
05396                "Should only be updating the link map in visible documents");
05397   if (!mVisible)
05398     return;
05399     
05400   PRInt32 count = mVisitednessChangedURIs.Count();
05401   for (PRInt32 i = 0; i < count; ++i) {
05402     NotifyURIVisitednessChanged(mVisitednessChangedURIs[i]);
05403   }
05404   mVisitednessChangedURIs.Clear();
05405 }