/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: NPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Netscape Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * L. David Baron * Pierre Phaneuf * Pete Collins * * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the NPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the NPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "plstr.h" #include "nsCOMPtr.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" #include "nsDocument.h" #include "nsIArena.h" #include "nsIURL.h" #include "nsILoadGroup.h" #include "nsIChannel.h" #include "nsString.h" #include "nsUnicharUtils.h" #include "nsIContent.h" #include "nsIStyleSet.h" #include "nsIStyleSheet.h" #include "nsIPresShell.h" #include "nsIPresContext.h" #include "nsIDocumentObserver.h" #include "nsIEventListenerManager.h" #include "nsIScriptGlobalObject.h" #include "nsIScriptEventListener.h" #include "nsIDOMEvent.h" #include "nsIPrivateDOMEvent.h" #include "nsIEventStateManager.h" #include "nsContentList.h" #include "nsIObserver.h" #include "nsIBaseWindow.h" #include "nsIDocShell.h" #include "nsIDocShellTreeItem.h" #include "nsIDOMEventListener.h" #include "nsGUIEvent.h" #include "nsIDOMStyleSheet.h" #include "nsDOMAttribute.h" #include "nsDOMCID.h" #include "nsIDOMDOMImplementation.h" #include "nsIDOMDocumentView.h" #include "nsIDOMAbstractView.h" #include "nsIDOMDocumentXBL.h" #include "nsIDOMNavigator.h" #include "nsGenericElement.h" #include "nsICSSStyleSheet.h" #include "nsITextContent.h" #include "nsIDocumentEncoder.h" #include "nsIHTMLContentSink.h" #include "nsIParser.h" #include "nsParserCIID.h" #include "nsIFileStreams.h" #include "nsRange.h" #include "nsIDOMText.h" #include "nsIDOMComment.h" #include "nsDOMDocumentType.h" #include "nsTreeWalker.h" #include "nsINameSpaceManager.h" #include "nsIServiceManager.h" #include "nsLayoutAtoms.h" #include "nsContentCID.h" #include "nsLayoutCID.h" #include "nsIDOMRange.h" #include "nsIEnumerator.h" #include "nsDOMError.h" #include "nsIScrollableView.h" #include "nsIFrame.h" #include "nsContentUtils.h" #include "nsNodeInfoManager.h" #include "nsIXBLService.h" #include "nsNetUtil.h" // for NS_MakeAbsoluteURI #include "nsIScriptSecurityManager.h" #include "nsIAggregatePrincipal.h" #include "nsIPrivateDOMImplementation.h" #include "nsIDOMWindowInternal.h" #include "nsPIDOMWindow.h" #include "nsIDOMElement.h" #include "nsIBoxObject.h" #include "nsPIBoxObject.h" #include "nsXULAtoms.h" // for radio group stuff #include "nsIDOMHTMLInputElement.h" #include "nsIRadioVisitor.h" #include "nsIFormControl.h" #ifdef IBMBIDI #include "nsBidiUtils.h" #endif static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID); #include "nsILineBreakerFactory.h" #include "nsIWordBreakerFactory.h" #include "nsLWBrkCIID.h" #include "nsIHTMLDocument.h" #include "nsHTMLAtoms.h" #include "nsIHttpChannel.h" #include "nsIPref.h" /** * A struct that holds all the information about a radio group. */ struct nsRadioGroupStruct { /** A strong pointer to the currently selected radio button. */ nsCOMPtr mSelectedRadioButton; nsSmallVoidArray mRadioButtons; }; nsDOMStyleSheetList::nsDOMStyleSheetList(nsIDocument *aDocument) { NS_INIT_ISUPPORTS(); mLength = -1; // Not reference counted to avoid circular references. // The document will tell us when its going away. mDocument = aDocument; mDocument->AddObserver(this); } nsDOMStyleSheetList::~nsDOMStyleSheetList() { if (nsnull != mDocument) { mDocument->RemoveObserver(this); } mDocument = nsnull; } // XXX couldn't we use the GetIIDs method from CSSStyleSheetList here? // QueryInterface implementation for nsDOMStyleSheetList NS_INTERFACE_MAP_BEGIN(nsDOMStyleSheetList) NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheetList) NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStyleSheetList) NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(DocumentStyleSheetList) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsDOMStyleSheetList) NS_IMPL_RELEASE(nsDOMStyleSheetList) NS_IMETHODIMP nsDOMStyleSheetList::GetLength(PRUint32* aLength) { if (mDocument) { // XXX Find the number and then cache it. We'll use the // observer notification to figure out if new ones have // been added or removed. if (-1 == mLength) { PRUint32 count = 0; PRInt32 i, imax = 0; mDocument->GetNumberOfStyleSheets(&imax); for (i = 0; i < imax; i++) { nsCOMPtr sheet; mDocument->GetStyleSheetAt(i, getter_AddRefs(sheet)); if (!sheet) continue; nsCOMPtr domss(do_QueryInterface(sheet)); if (domss) { count++; } } mLength = count; } *aLength = mLength; } else { *aLength = 0; } return NS_OK; } NS_IMETHODIMP nsDOMStyleSheetList::Item(PRUint32 aIndex, nsIDOMStyleSheet** aReturn) { *aReturn = nsnull; if (nsnull != mDocument) { PRUint32 count = 0; PRInt32 i, imax = 0; mDocument->GetNumberOfStyleSheets(&imax); // XXX Not particularly efficient, but does anyone care? for (i = 0; (i < imax) && (nsnull == *aReturn); i++) { nsCOMPtr sheet; mDocument->GetStyleSheetAt(i, getter_AddRefs(sheet)); if (!sheet) continue; nsCOMPtr domss(do_QueryInterface(sheet)); if (domss) { if (count++ == aIndex) { *aReturn = domss; NS_IF_ADDREF(*aReturn); } } } } return NS_OK; } NS_IMETHODIMP nsDOMStyleSheetList::StyleSheetAdded(nsIDocument *aDocument, nsIStyleSheet* aStyleSheet) { if (-1 != mLength) { nsCOMPtr domss(do_QueryInterface(aStyleSheet)); if (domss) { mLength++; } } return NS_OK; } NS_IMETHODIMP nsDOMStyleSheetList::StyleSheetRemoved(nsIDocument *aDocument, nsIStyleSheet* aStyleSheet) { if (-1 != mLength) { nsCOMPtr domss(do_QueryInterface(aStyleSheet)); if (domss) { mLength--; } } return NS_OK; } NS_IMETHODIMP nsDOMStyleSheetList::DocumentWillBeDestroyed(nsIDocument *aDocument) { if (nsnull != mDocument) { aDocument->RemoveObserver(this); mDocument = nsnull; } return NS_OK; } // ================================================================== // = // ================================================================== class nsDOMImplementation : public nsIDOMDOMImplementation, public nsIPrivateDOMImplementation { public: nsDOMImplementation(nsIURI* aBaseURI = nsnull); virtual ~nsDOMImplementation(); NS_DECL_ISUPPORTS // nsIDOMDOMImplementation NS_IMETHOD HasFeature(const nsAString& aFeature, const nsAString& aVersion, PRBool* aReturn); NS_IMETHOD CreateDocumentType(const nsAString& aQualifiedName, const nsAString& aPublicId, const nsAString& aSystemId, nsIDOMDocumentType** aReturn); NS_IMETHOD CreateDocument(const nsAString& aNamespaceURI, const nsAString& aQualifiedName, nsIDOMDocumentType* aDoctype, nsIDOMDocument** aReturn); //nsIPrivateDOMImplementation NS_IMETHOD Init(nsIURI* aBaseURI); protected: nsCOMPtr mBaseURI; }; NS_EXPORT nsresult NS_NewDOMImplementation(nsIDOMDOMImplementation** aInstancePtrResult) { nsDOMImplementation* domImpl = new nsDOMImplementation(); if (domImpl == nsnull) return NS_ERROR_OUT_OF_MEMORY; return domImpl->QueryInterface(NS_GET_IID(nsIDOMDOMImplementation), (void**) aInstancePtrResult); } nsDOMImplementation::nsDOMImplementation(nsIURI* aBaseURI) { NS_INIT_ISUPPORTS(); mBaseURI = aBaseURI; } nsDOMImplementation::~nsDOMImplementation() { } // QueryInterface implementation for nsDOMImplementation NS_INTERFACE_MAP_BEGIN(nsDOMImplementation) NS_INTERFACE_MAP_ENTRY(nsIDOMDOMImplementation) NS_INTERFACE_MAP_ENTRY(nsIPrivateDOMImplementation) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDOMImplementation) NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(DOMImplementation) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsDOMImplementation); NS_IMPL_RELEASE(nsDOMImplementation); NS_IMETHODIMP nsDOMImplementation::HasFeature(const nsAString& aFeature, const nsAString& aVersion, PRBool* aReturn) { return nsGenericElement::InternalIsSupported(aFeature, aVersion, aReturn); } NS_IMETHODIMP nsDOMImplementation::CreateDocumentType(const nsAString& aQualifiedName, const nsAString& aPublicId, const nsAString& aSystemId, nsIDOMDocumentType** aReturn) { NS_ENSURE_ARG_POINTER(aReturn); return NS_NewDOMDocumentType(aReturn, aQualifiedName, nsnull, nsnull, aPublicId, aSystemId, nsString()); } NS_IMETHODIMP nsDOMImplementation::CreateDocument(const nsAString& aNamespaceURI, const nsAString& aQualifiedName, nsIDOMDocumentType* aDoctype, nsIDOMDocument** aReturn) { NS_ENSURE_ARG_POINTER(aReturn); *aReturn = nsnull; if (aDoctype) { nsCOMPtr owner; aDoctype->GetOwnerDocument(getter_AddRefs(owner)); if (owner) { return NS_ERROR_DOM_WRONG_DOCUMENT_ERR; } } nsresult rv = NS_NewDOMDocument(aReturn, aNamespaceURI, aQualifiedName, aDoctype, mBaseURI); nsCOMPtr docShell; nsContentUtils::GetDocShellFromCaller(getter_AddRefs(docShell)); if (docShell) { nsCOMPtr presContext; docShell->GetPresContext(getter_AddRefs(presContext)); if (presContext) { nsCOMPtr container; presContext->GetContainer(getter_AddRefs(container)); nsCOMPtr document = do_QueryInterface(*aReturn); if (document) { document->SetContainer(container); } } } return rv; } NS_IMETHODIMP nsDOMImplementation::Init(nsIURI* aBaseURI) { mBaseURI = aBaseURI; return NS_OK; } // ================================================================== // = // ================================================================== nsDocumentChildNodes::nsDocumentChildNodes(nsIDocument* aDocument) { MOZ_COUNT_CTOR(nsDocumentChildNodes); // We don't reference count our document reference (to avoid circular // references). We'll be told when the document goes away. mDocument = aDocument; } nsDocumentChildNodes::~nsDocumentChildNodes() { MOZ_COUNT_DTOR(nsDocumentChildNodes); } NS_IMETHODIMP nsDocumentChildNodes::GetLength(PRUint32* aLength) { if (nsnull != mDocument) { PRInt32 count; mDocument->GetChildCount(count); *aLength = (PRUint32)count; } else { *aLength = 0; } return NS_OK; } NS_IMETHODIMP nsDocumentChildNodes::Item(PRUint32 aIndex, nsIDOMNode** aReturn) { nsresult result = NS_OK; nsCOMPtr content; *aReturn = nsnull; if (nsnull != mDocument) { result = mDocument->ChildAt(aIndex, *getter_AddRefs(content)); if ((NS_OK == result) && (nsnull != content)) { result = content->QueryInterface(NS_GET_IID(nsIDOMNode), (void**)aReturn); } } return result; } void nsDocumentChildNodes::DropReference() { mDocument = nsnull; } class nsXPathDocumentTearoff : public nsIDOMXPathEvaluator { public: nsXPathDocumentTearoff(nsIDOMXPathEvaluator* aEvaluator, nsIDocument* aDocument) : mEvaluator(aEvaluator), mDocument(aDocument) { } virtual ~nsXPathDocumentTearoff() { } NS_DECL_ISUPPORTS_INHERITED NS_FORWARD_NSIDOMXPATHEVALUATOR(mEvaluator->) private: nsCOMPtr mEvaluator; nsIDocument* mDocument; }; NS_INTERFACE_MAP_BEGIN(nsXPathDocumentTearoff) NS_INTERFACE_MAP_ENTRY(nsIDOMXPathEvaluator) NS_INTERFACE_MAP_END_AGGREGATED(mDocument) NS_IMPL_ADDREF_USING_AGGREGATOR(nsXPathDocumentTearoff, mDocument) NS_IMPL_RELEASE_USING_AGGREGATOR(nsXPathDocumentTearoff, mDocument) // ================================================================== // = // ================================================================== nsDocument::nsDocument() : mSubDocuments(nsnull), mIsGoingAway(PR_FALSE), mCSSLoader(nsnull), mXPathDocument(nsnull) { NS_INIT_ISUPPORTS(); mArena = nsnull; mDocumentURL = nsnull; mCharacterSet.Assign(NS_LITERAL_STRING("ISO-8859-1")); mParentDocument = nsnull; mRootContent = nsnull; mListenerManager = nsnull; mInDestructor = PR_FALSE; mNameSpaceManager = nsnull; mHeaderData = nsnull; mChildNodes = nsnull; mModCount = 0; mNextContentID = NS_CONTENT_ID_COUNTER_BASE; mDTD = 0; mBoxObjectTable = nsnull; mNumCapturers = 0; #ifdef IBMBIDI mBidiEnabled = PR_FALSE; #endif // IBMBIDI // Force initialization. mBindingManager = do_CreateInstance("@mozilla.org/xbl/binding-manager;1"); nsCOMPtr observer(do_QueryInterface(mBindingManager)); if (observer) // We must always be the first observer of the document. mObservers.InsertElementAt(observer, 0); } nsDocument::~nsDocument() { delete mXPathDocument; // XXX Inform any remaining observers that we are going away. // Note that this currently contradicts the rule that all // observers must hold on to live references to the document. // This notification will occur only after the reference has // been dropped. mInDestructor = PR_TRUE; PRInt32 indx; for (indx = 0; indx < mObservers.Count(); indx++) { // XXX Should this be a kungfudeathgrip?!!!! nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers.ElementAt(indx); observer->DocumentWillBeDestroyed(this); // Test to see if the observer was removed if (observer != (nsIDocumentObserver*)mObservers.ElementAt(indx)) { indx--; } } mPrincipal = nsnull; mLoadFlags = nsIRequest::LOAD_NORMAL; // XXX maybe not required mDocumentLoadGroup = nsnull; mParentDocument = nsnull; // Kill the subdocument map, doing this will release its strong // references, if any. if (mSubDocuments) { PL_DHashTableDestroy(mSubDocuments); mSubDocuments = nsnull; } if (mRootContent) { nsCOMPtr doc; mRootContent->GetDocument(*getter_AddRefs(doc)); if (doc) { // The root content still has a pointer back to the document, // clear the document pointer in all children. PRUint32 count; mChildren->Count(&count); for (indx = 0; (PRUint32)indx < count; indx++) { nsCOMPtr content; mChildren->QueryElementAt(indx, NS_GET_IID(nsIContent), getter_AddRefs(content)); content->SetDocument(nsnull, PR_TRUE, PR_FALSE); } } } mRootContent = nsnull; mChildren->Clear(); // Delete references to style sheets indx = mStyleSheets.Count(); while (--indx >= 0) { nsIStyleSheet* sheet = (nsIStyleSheet*) mStyleSheets.ElementAt(indx); sheet->SetOwningDocument(nsnull); NS_RELEASE(sheet); } if (nsnull != mChildNodes) { mChildNodes->DropReference(); NS_RELEASE(mChildNodes); } NS_IF_RELEASE(mArena); if (mListenerManager != nsnull) { mListenerManager->SetListenerTarget(nsnull); NS_RELEASE(mListenerManager); } NS_IF_RELEASE(mNameSpaceManager); if (mScriptLoader) { mScriptLoader->DropDocumentReference(); } mDOMStyleSheets = nsnull; // Release the stylesheets list. if (nsnull != mHeaderData) { delete mHeaderData; mHeaderData = nsnull; } NS_IF_RELEASE(mDTD); delete mBoxObjectTable; if (mNodeInfoManager) { mNodeInfoManager->DropDocumentReference(); } // Do this after notifying the nodeinfo manager that we're going away since // it will save our url before dropping the reference. NS_IF_RELEASE(mDocumentURL); } PRBool gCheckedForXPathDOM = PR_FALSE; PRBool gHaveXPathDOM = PR_FALSE; NS_INTERFACE_MAP_BEGIN(nsDocument) NS_INTERFACE_MAP_ENTRY(nsIDocument) NS_INTERFACE_MAP_ENTRY(nsIDOMDocument) NS_INTERFACE_MAP_ENTRY(nsIDOMNSDocument) NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentEvent) NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentStyle) NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentView) NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentRange) NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentTraversal) NS_INTERFACE_MAP_ENTRY(nsIDOMDocumentXBL) NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal) NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver) NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget) NS_INTERFACE_MAP_ENTRY(nsIDOMNode) NS_INTERFACE_MAP_ENTRY(nsIDOM3Node) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY(nsIRadioGroupContainer) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocument) if (aIID.Equals(NS_GET_IID(nsIDOMXPathEvaluator)) && (!gCheckedForXPathDOM || gHaveXPathDOM)) { if (!mXPathDocument) { nsCOMPtr evaluator; nsresult rv; evaluator = do_CreateInstance(NS_XPATH_EVALUATOR_CONTRACTID, &rv); gCheckedForXPathDOM = PR_TRUE; gHaveXPathDOM = (evaluator != nsnull); if (rv == NS_ERROR_FACTORY_NOT_REGISTERED) { return NS_ERROR_NO_INTERFACE; } NS_ENSURE_SUCCESS(rv, rv); mXPathDocument = new nsXPathDocumentTearoff(evaluator, this); NS_ENSURE_TRUE(mXPathDocument, NS_ERROR_OUT_OF_MEMORY); } foundInterface = mXPathDocument; } else NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsDocument) NS_IMPL_RELEASE(nsDocument) nsresult nsDocument::Init() { if (mNameSpaceManager) { return NS_ERROR_ALREADY_INITIALIZED; } nsresult rv; rv = NS_NewISupportsArray(getter_AddRefs(mChildren)); NS_ENSURE_SUCCESS(rv, rv); rv = NS_NewHeapArena(&mArena, nsnull); NS_ENSURE_SUCCESS(rv, rv); rv = NS_NewNameSpaceManager(&mNameSpaceManager); NS_ENSURE_SUCCESS(rv, rv); mNodeInfoManager = new nsNodeInfoManager(); NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_OUT_OF_MEMORY); mNodeInfoManager->Init(this, mNameSpaceManager); return rv; } NS_IMETHODIMP nsDocument::GetArena(nsIArena** aArena) { NS_IF_ADDREF(*aArena = mArena); return NS_OK; } NS_IMETHODIMP nsDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) { nsresult rv = NS_OK; nsCOMPtr uri; if (aChannel) { aChannel->GetOriginalURI(getter_AddRefs(uri)); PRBool isChrome = PR_FALSE; PRBool isRes = PR_FALSE; (void)uri->SchemeIs("chrome", &isChrome); (void)uri->SchemeIs("resource", &isRes); if (!isChrome && !isRes) aChannel->GetURI(getter_AddRefs(uri)); } rv = ResetToURI(uri, aLoadGroup); if (aChannel) { nsCOMPtr owner; aChannel->GetOwner(getter_AddRefs(owner)); if (owner) mPrincipal = do_QueryInterface(owner); aChannel->GetLoadFlags(&mLoadFlags); } return rv; } NS_IMETHODIMP nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup) { nsresult rv = NS_OK; mDocumentTitle.Truncate(); NS_IF_RELEASE(mDocumentURL); mPrincipal = nsnull; mLoadFlags = nsIRequest::LOAD_NORMAL; mDocumentLoadGroup = nsnull; // Delete references to sub-documents and kill the subdocument map, // if any. It holds strong references if (mSubDocuments) { PL_DHashTableDestroy(mSubDocuments); mSubDocuments = nsnull; } mRootContent = nsnull; PRUint32 count, i; mChildren->Count(&count); for (i = 0; i < count; i++) { nsCOMPtr content = dont_AddRef(NS_STATIC_CAST(nsIContent *, mChildren->ElementAt(i))); content->SetDocument(nsnull, PR_TRUE, PR_TRUE); ContentRemoved(nsnull, content, i); } mChildren->Clear(); // Delete references to style sheets PRInt32 indx = mStyleSheets.Count(); while (--indx >= 0) { nsIStyleSheet* sheet = (nsIStyleSheet*) mStyleSheets.ElementAt(indx); sheet->SetOwningDocument(nsnull); PRInt32 pscount = mPresShells.Count(); PRInt32 psindex; for (psindex = 0; psindex < pscount; psindex++) { nsCOMPtr shell = (nsIPresShell*)mPresShells.ElementAt(psindex); nsCOMPtr set; if (NS_SUCCEEDED(shell->GetStyleSet(getter_AddRefs(set)))) { if (set) { set->RemoveDocStyleSheet(sheet); } } } // XXX Tell observers? NS_RELEASE(sheet); } mStyleSheets.Clear(); NS_IF_RELEASE(mListenerManager); NS_IF_RELEASE(mNameSpaceManager); mDOMStyleSheets = nsnull; // Release the stylesheets list. mDocumentURL = aURI; NS_IF_ADDREF(mDocumentURL); mDocumentBaseURL = mDocumentURL; if (aLoadGroup) { mDocumentLoadGroup = getter_AddRefs(NS_GetWeakReference(aLoadGroup)); // there was an assertion here that aLoadGroup was not null. This // is no longer valid nsWebShell::SetDocument does not create a // load group, and it works just fine. } if (NS_OK == rv) rv = NS_NewNameSpaceManager(&mNameSpaceManager); return rv; } NS_IMETHODIMP nsDocument::SetDocumentURL(nsIURI* aURI) { NS_IF_RELEASE(mDocumentURL); mDocumentURL = aURI; NS_IF_ADDREF(mDocumentURL); return NS_OK; } NS_IMETHODIMP nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel, nsILoadGroup* aLoadGroup, nsISupports* aContainer, nsIStreamListener **aDocListener, PRBool aReset, nsIContentSink* aSink) { nsresult rv = NS_OK; if (aReset) rv = Reset(aChannel, aLoadGroup); nsCAutoString contentType; if (NS_SUCCEEDED(aChannel->GetContentType(contentType))) { // XXX this is only necessary for viewsource: nsACString::const_iterator start, end, semicolon; contentType.BeginReading(start); contentType.EndReading(end); semicolon = start; FindCharInReadable(';', semicolon, end); CopyASCIItoUCS2(Substring(start, semicolon), mContentType); } PRBool have_contentLanguage = PR_FALSE; nsCOMPtr httpChannel = do_QueryInterface(aChannel); if (httpChannel) { nsCAutoString contentLanguage; if (NS_SUCCEEDED(httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Language"), contentLanguage))) { CopyASCIItoUCS2(contentLanguage, mContentLanguage); // XXX what's wrong w/ ASCII? have_contentLanguage = PR_TRUE; } } if (!have_contentLanguage) { nsCOMPtr pref(do_GetService(NS_PREF_CONTRACTID)); if(pref) { nsXPIDLCString prefLanguage; if (NS_SUCCEEDED(pref->GetCharPref("intl.accept_languages", getter_Copies(prefLanguage)))) { mContentLanguage.AssignWithConversion(prefLanguage); have_contentLanguage = PR_TRUE; } } } return rv; } NS_IMETHODIMP nsDocument::StopDocumentLoad() { return NS_OK; } const nsString* nsDocument::GetDocumentTitle() const { return &mDocumentTitle; } NS_IMETHODIMP nsDocument::GetDocumentURL(nsIURI** aURI) const { NS_IF_ADDREF(*aURI = mDocumentURL); return NS_OK; } NS_IMETHODIMP nsDocument::GetPrincipal(nsIPrincipal **aPrincipal) { if (!mPrincipal) { nsresult rv; nsCOMPtr securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); if (NS_FAILED(rv)) return rv; NS_WARN_IF_FALSE(mDocumentURL, "no URL!"); if (NS_FAILED(rv = securityManager->GetCodebasePrincipal(mDocumentURL, getter_AddRefs(mPrincipal)))) return rv; } if(aPrincipal) { *aPrincipal = mPrincipal; NS_ADDREF(*aPrincipal); } return NS_OK; } NS_IMETHODIMP nsDocument::AddPrincipal(nsIPrincipal *aNewPrincipal) { nsresult rv; if (!mPrincipal) GetPrincipal(nsnull); nsCOMPtr agg(do_QueryInterface(mPrincipal, &rv)); if (NS_SUCCEEDED(rv)) { rv = agg->Intersect(aNewPrincipal); if (NS_FAILED(rv)) return rv; } return NS_OK; } NS_IMETHODIMP nsDocument::GetContentType(nsAString& aContentType) { aContentType = mContentType; return NS_OK; } NS_IMETHODIMP nsDocument::GetContentLanguage(nsAString& aContentLanguage) const { aContentLanguage = mContentLanguage; return NS_OK; } NS_IMETHODIMP nsDocument::GetDocumentLoadGroup(nsILoadGroup **aGroup) const { nsCOMPtr group(do_QueryReferent(mDocumentLoadGroup)); *aGroup = group; NS_IF_ADDREF(*aGroup); return NS_OK; } NS_IMETHODIMP nsDocument::GetBaseURL(nsIURI*& aURL) const { aURL = mDocumentBaseURL.get(); NS_IF_ADDREF(aURL); return NS_OK; } NS_IMETHODIMP nsDocument::SetBaseURL(nsIURI* aURL) { nsresult rv = NS_OK; if (aURL) { nsCOMPtr securityManager = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); if (NS_SUCCEEDED(rv)) { rv = securityManager->CheckLoadURI(mDocumentURL, aURL, nsIScriptSecurityManager::STANDARD); if (NS_SUCCEEDED(rv)) { mDocumentBaseURL = aURL; } } } else { mDocumentBaseURL = aURL; } return rv; } NS_IMETHODIMP nsDocument::GetBaseTarget(nsAString &aBaseTarget) { aBaseTarget.Truncate(); return NS_OK; } NS_IMETHODIMP nsDocument::SetBaseTarget(const nsAString &aBaseTarget) { return NS_OK; } NS_IMETHODIMP nsDocument::GetDocumentCharacterSet(nsAString& oCharSetID) { oCharSetID = mCharacterSet; return NS_OK; } NS_IMETHODIMP nsDocument::SetDocumentCharacterSet(const nsAString& aCharSetID) { if (!mCharacterSet.Equals(aCharSetID)) { mCharacterSet = aCharSetID; PRInt32 n = mCharSetObservers.Count(); for (PRInt32 i = 0; i < n; i++) { nsIObserver* observer = (nsIObserver*) mCharSetObservers.ElementAt(i); observer->Observe((nsIDocument*) this, "charset", PromiseFlatString(aCharSetID).get()); } } return NS_OK; } NS_IMETHODIMP nsDocument::GetDocumentCharacterSetSource(PRInt32* aCharsetSource) { *aCharsetSource = mCharacterSetSource; return NS_OK; } NS_IMETHODIMP nsDocument::SetDocumentCharacterSetSource(PRInt32 aCharsetSource) { mCharacterSetSource = aCharsetSource; return NS_OK; } NS_IMETHODIMP nsDocument::AddCharSetObserver(nsIObserver* aObserver) { NS_ENSURE_ARG_POINTER(aObserver); NS_ENSURE_TRUE(mCharSetObservers.AppendElement(aObserver), NS_ERROR_FAILURE); return NS_OK; } NS_IMETHODIMP nsDocument::RemoveCharSetObserver(nsIObserver* aObserver) { NS_ENSURE_ARG_POINTER(aObserver); NS_ENSURE_TRUE(mCharSetObservers.RemoveElement(aObserver), NS_ERROR_FAILURE); return NS_OK; } NS_IMETHODIMP nsDocument::GetLineBreaker(nsILineBreaker** aResult) { if (!mLineBreaker) { // no line breaker, find a default one nsresult result; nsCOMPtr lbf(do_GetService(NS_LWBRK_CONTRACTID, &result)); if (NS_SUCCEEDED(result)) { nsAutoString lbarg; lbf->GetBreaker(lbarg, getter_AddRefs(mLineBreaker)); } } *aResult = mLineBreaker; NS_IF_ADDREF(*aResult); return NS_OK; // XXX we should do error handling here } NS_IMETHODIMP nsDocument::SetLineBreaker(nsILineBreaker* aLineBreaker) { mLineBreaker = aLineBreaker; return NS_OK; } NS_IMETHODIMP nsDocument::GetWordBreaker(nsIWordBreaker** aResult) { if (!mWordBreaker) { // no word breaker, find a default one nsresult result; nsCOMPtr wbf(do_GetService(NS_LWBRK_CONTRACTID, &result)); if (NS_SUCCEEDED(result)) { nsAutoString wbarg; wbf->GetBreaker(wbarg, getter_AddRefs(mWordBreaker)); } } *aResult = mWordBreaker; NS_IF_ADDREF(*aResult); return NS_OK; // XXX we should do error handling here } NS_IMETHODIMP nsDocument::SetWordBreaker(nsIWordBreaker* aWordBreaker) { mWordBreaker = aWordBreaker; return NS_OK; } NS_IMETHODIMP nsDocument::GetHeaderData(nsIAtom* aHeaderField, nsAString& aData) const { aData.Truncate(); const nsDocHeaderData* data = mHeaderData; while (nsnull != data) { if (data->mField == aHeaderField) { aData = data->mData; break; } data = data->mNext; } return NS_OK; } NS_IMETHODIMP nsDocument::SetHeaderData(nsIAtom* aHeaderField, const nsAString& aData) { if (nsnull != aHeaderField) { if (nsnull == mHeaderData) { if (!aData.IsEmpty()) { // don't bother storing empty string mHeaderData = new nsDocHeaderData(aHeaderField, aData); } } else { nsDocHeaderData* data = mHeaderData; nsDocHeaderData** lastPtr = &mHeaderData; PRBool found = PR_FALSE; do { // look for existing and replace if (data->mField == aHeaderField) { if (!aData.IsEmpty()) { data->mData.Assign(aData); } else { // don't store empty string *lastPtr = data->mNext; data->mNext = nsnull; delete data; } found = PR_TRUE; break; } lastPtr = &(data->mNext); data = *lastPtr; } while (data); if (!aData.IsEmpty() && !found) { // didn't find, append *lastPtr = new nsDocHeaderData(aHeaderField, aData); } } if (aHeaderField == nsHTMLAtoms::headerDefaultStyle) { // switch alternate style sheets based on default nsAutoString type; nsAutoString title; PRInt32 index; mCSSLoader->SetPreferredSheet(aData); PRInt32 count = mStyleSheets.Count(); for (index = 0; index < count; index++) { nsIStyleSheet* sheet = (nsIStyleSheet*)mStyleSheets.ElementAt(index); sheet->GetType(type); if (!type.Equals(NS_LITERAL_STRING("text/html"))) { sheet->GetTitle(title); if (!title.IsEmpty()) { // if sheet has title PRBool enabled = (!aData.IsEmpty() && title.Equals(aData, nsCaseInsensitiveStringComparator())); sheet->SetEnabled(enabled); } } } } return NS_OK; } return NS_ERROR_NULL_POINTER; } #if 0 // XXX Temp hack: moved to nsMarkupDocument NS_IMETHODIMP nsDocument::CreateShell(nsIPresContext* aContext, nsIViewManager* aViewManager, nsIStyleSet* aStyleSet, nsIPresShell** aInstancePtrResult) { NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); if (nsnull == aInstancePtrResult) { return NS_ERROR_NULL_POINTER; } nsresult rv; nsCOMPtr shell(do_CreateInstance(kPresShellCID,&rv)); if (NS_FAILED(rv)) { return rv; } rv = shell->Init(this, aContext, aViewManager, aStyleSet); if (NS_FAILED(rv)) { return rv; } // Note: we don't hold a ref to the shell (it holds a ref to us) mPresShells.AppendElement(shell); *aInstancePtrResult = shell.get(); NS_ADDREF(*aInstancePtrResult); // tell the context the mode we want (always standard, which // should be correct for everything except HTML) // nsHTMLDocument overrides this method and sets it differently aContext->SetCompatibilityMode(eCompatibility_Standard); return NS_OK; } #endif PRBool nsDocument::DeleteShell(nsIPresShell* aShell) { return mPresShells.RemoveElement(aShell); } PRInt32 nsDocument::GetNumberOfShells() { return mPresShells.Count(); } NS_IMETHODIMP nsDocument::GetShellAt(PRInt32 aIndex, nsIPresShell** aShell) { *aShell = (nsIPresShell*) mPresShells.SafeElementAt(aIndex); NS_IF_ADDREF(*aShell); return NS_OK; } NS_IMETHODIMP nsDocument::GetParentDocument(nsIDocument** aParent) { NS_IF_ADDREF(*aParent = mParentDocument); return NS_OK; } /** * Note that we do *not* AddRef our parent because that would * create a circular reference. */ NS_IMETHODIMP nsDocument::SetParentDocument(nsIDocument* aParent) { mParentDocument = aParent; return NS_OK; } PR_STATIC_CALLBACK(void) SubDocClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) { SubDocMapEntry *e = NS_STATIC_CAST(SubDocMapEntry *, entry); NS_RELEASE(e->mKey); NS_IF_RELEASE(e->mSubDocument); } PR_STATIC_CALLBACK(void) SubDocInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, const void *key) { SubDocMapEntry *e = NS_CONST_CAST(SubDocMapEntry *, NS_STATIC_CAST(const SubDocMapEntry *, entry)); e->mKey = NS_CONST_CAST(nsIContent *, NS_STATIC_CAST(const nsIContent *, key)); NS_ADDREF(e->mKey); e->mSubDocument = nsnull; } NS_IMETHODIMP nsDocument::SetSubDocumentFor(nsIContent *aContent, nsIDocument* aSubDoc) { NS_ENSURE_TRUE(aContent, NS_ERROR_UNEXPECTED); if (!aSubDoc) { // aSubDoc is nsnull, remove the mapping if (mSubDocuments) { SubDocMapEntry *entry = NS_STATIC_CAST(SubDocMapEntry*, PL_DHashTableOperate(mSubDocuments, aContent, PL_DHASH_LOOKUP)); if (PL_DHASH_ENTRY_IS_LIVE(entry)) { entry->mSubDocument->SetParentDocument(nsnull); PL_DHashTableRawRemove(mSubDocuments, entry); } } } else { if (!mSubDocuments) { // Create a new hashtable static PLDHashTableOps hash_table_ops = { PL_DHashAllocTable, PL_DHashFreeTable, PL_DHashGetKeyStub, PL_DHashVoidPtrKeyStub, PL_DHashMatchEntryStub, PL_DHashMoveEntryStub, SubDocClearEntry, PL_DHashFinalizeStub, SubDocInitEntry }; mSubDocuments = PL_NewDHashTable(&hash_table_ops, nsnull, sizeof(SubDocMapEntry), 16); if (!mSubDocuments) { return NS_ERROR_OUT_OF_MEMORY; } } // Add a mapping to the hash table SubDocMapEntry *entry = NS_STATIC_CAST(SubDocMapEntry*, PL_DHashTableOperate(mSubDocuments, aContent, PL_DHASH_ADD)); if (!entry) { return NS_ERROR_OUT_OF_MEMORY; } if (entry->mSubDocument) { entry->mSubDocument->SetParentDocument(nsnull); // Release the old sub document NS_RELEASE(entry->mSubDocument); } entry->mSubDocument = aSubDoc; NS_ADDREF(entry->mSubDocument); aSubDoc->SetParentDocument(this); } return NS_OK; } NS_IMETHODIMP nsDocument::GetSubDocumentFor(nsIContent *aContent, nsIDocument** aSubDoc) { *aSubDoc = nsnull; if (mSubDocuments) { SubDocMapEntry *entry = NS_STATIC_CAST(SubDocMapEntry*, PL_DHashTableOperate(mSubDocuments, aContent, PL_DHASH_LOOKUP)); if (PL_DHASH_ENTRY_IS_LIVE(entry)) { *aSubDoc = entry->mSubDocument; NS_ADDREF(*aSubDoc); } } return NS_OK; } PR_STATIC_CALLBACK(PLDHashOperator) FindContentEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr, PRUint32 number, void *arg) { SubDocMapEntry *entry = NS_STATIC_CAST(SubDocMapEntry*, hdr); FindContentData *data = NS_STATIC_CAST(FindContentData*, arg); if (entry->mSubDocument == data->mSubDocument) { data->mResult = entry->mKey; return PL_DHASH_STOP; } return PL_DHASH_NEXT; } NS_IMETHODIMP nsDocument::FindContentForSubDocument(nsIDocument *aDocument, nsIContent **aContent) { NS_ENSURE_ARG_POINTER(aDocument); if (!mSubDocuments) { *aContent = nsnull; return NS_OK; } FindContentData data(aDocument); PL_DHashTableEnumerate(mSubDocuments, FindContentEnumerator, &data); *aContent = data.mResult; NS_IF_ADDREF(*aContent); return NS_OK; } NS_IMETHODIMP nsDocument::GetRootContent(nsIContent** aRoot) { NS_IF_ADDREF(*aRoot = mRootContent); return NS_OK; } NS_IMETHODIMP nsDocument::SetRootContent(nsIContent* aRoot) { if (mRootContent) { PRInt32 indx = mChildren->IndexOf(mRootContent); if (aRoot) { mChildren->ReplaceElementAt(aRoot, indx); } else { mChildren->RemoveElementAt(indx); } } else if (aRoot) { mChildren->AppendElement(aRoot); } mRootContent = aRoot; return NS_OK; } NS_IMETHODIMP nsDocument::ChildAt(PRInt32 aIndex, nsIContent*& aResult) const { nsCOMPtr content( dont_AddRef(NS_STATIC_CAST(nsIContent*, mChildren->ElementAt(aIndex))) ); NS_IF_ADDREF(aResult = content); return NS_OK; } NS_IMETHODIMP nsDocument::IndexOf(nsIContent* aPossibleChild, PRInt32& aIndex) const { aIndex = mChildren->IndexOf(aPossibleChild); return NS_OK; } NS_IMETHODIMP nsDocument::GetChildCount(PRInt32& aCount) { PRUint32 count; mChildren->Count(&count); aCount = NS_STATIC_CAST(PRInt32, count); return NS_OK; } NS_IMETHODIMP nsDocument::GetNumberOfStyleSheets(PRInt32* aCount) { *aCount = mStyleSheets.Count(); return NS_OK; } NS_IMETHODIMP nsDocument::GetStyleSheetAt(PRInt32 aIndex, nsIStyleSheet** aSheet) { *aSheet = (nsIStyleSheet*)mStyleSheets.SafeElementAt(aIndex); NS_IF_ADDREF(*aSheet); return NS_OK; } NS_IMETHODIMP nsDocument::GetIndexOfStyleSheet(nsIStyleSheet* aSheet, PRInt32* aIndex) { *aIndex = mStyleSheets.IndexOf(aSheet); return NS_OK; } // subclass hooks for sheet ordering void nsDocument::InternalAddStyleSheet(nsIStyleSheet* aSheet, PRUint32 aFlags) { mStyleSheets.AppendElement(aSheet); } void nsDocument::AddStyleSheetToStyleSets(nsIStyleSheet* aSheet) { PRInt32 count = mPresShells.Count(); PRInt32 indx; for (indx = 0; indx < count; indx++) { nsCOMPtr shell = (nsIPresShell*)mPresShells.ElementAt(indx); nsCOMPtr set; if (NS_SUCCEEDED(shell->GetStyleSet(getter_AddRefs(set)))) { if (set) { set->AddDocStyleSheet(aSheet, this); } } } } void nsDocument::AddStyleSheet(nsIStyleSheet* aSheet, PRUint32 aFlags) { NS_PRECONDITION(nsnull != aSheet, "null arg"); InternalAddStyleSheet(aSheet, aFlags); NS_ADDREF(aSheet); aSheet->SetOwningDocument(this); PRBool enabled = PR_TRUE; aSheet->GetEnabled(enabled); if (enabled) { AddStyleSheetToStyleSets(aSheet); // XXX should observers be notified for disabled sheets??? I think not, but I could be wrong for (PRInt32 indx = 0; indx < mObservers.Count(); indx++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers.ElementAt(indx); observer->StyleSheetAdded(this, aSheet); // handle the observer removing itself! if (observer != (nsIDocumentObserver*)mObservers.ElementAt(indx)) { indx--; } } } } void nsDocument::RemoveStyleSheetFromStyleSets(nsIStyleSheet* aSheet) { PRInt32 count = mPresShells.Count(); PRInt32 indx; for (indx = 0; indx < count; indx++) { nsCOMPtr shell = (nsIPresShell*)mPresShells.ElementAt(indx); nsCOMPtr set; if (NS_SUCCEEDED(shell->GetStyleSet(getter_AddRefs(set)))) { if (set) { set->RemoveDocStyleSheet(aSheet); } } } } void nsDocument::RemoveStyleSheet(nsIStyleSheet* aSheet) { NS_PRECONDITION(nsnull != aSheet, "null arg"); if (!mStyleSheets.RemoveElement(aSheet)) { NS_NOTREACHED("stylesheet not found"); return; } PRBool enabled = PR_TRUE; aSheet->GetEnabled(enabled); if (enabled && !mIsGoingAway) { RemoveStyleSheetFromStyleSets(aSheet); // XXX should observers be notified for disabled sheets??? I think not, but I could be wrong for (PRInt32 indx = 0; indx < mObservers.Count(); indx++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers.ElementAt(indx); observer->StyleSheetRemoved(this, aSheet); // handle the observer removing itself! if (observer != (nsIDocumentObserver*)mObservers.ElementAt(indx)) { indx--; } } } aSheet->SetOwningDocument(nsnull); NS_RELEASE(aSheet); } NS_IMETHODIMP nsDocument::UpdateStyleSheets(nsISupportsArray* aOldSheets, nsISupportsArray* aNewSheets) { PRUint32 oldCount; aOldSheets->Count(&oldCount); nsCOMPtr sheet; PRUint32 i; for (i = 0; i < oldCount; i++) { nsCOMPtr supp; aOldSheets->GetElementAt(i, getter_AddRefs(supp)); sheet = do_QueryInterface(supp); if (sheet) { PRBool found = mStyleSheets.RemoveElement(sheet); NS_ASSERTION(found, "stylesheet not found"); if (found) { PRBool enabled = PR_TRUE; sheet->GetEnabled(enabled); if (enabled) { RemoveStyleSheetFromStyleSets(sheet); } sheet->SetOwningDocument(nsnull); nsIStyleSheet* sheetPtr = sheet.get(); NS_RELEASE(sheetPtr); } } } PRUint32 newCount; aNewSheets->Count(&newCount); for (i = 0; i < newCount; i++) { nsCOMPtr supp; aNewSheets->GetElementAt(i, getter_AddRefs(supp)); sheet = do_QueryInterface(supp); if (sheet) { InternalAddStyleSheet(sheet, 0); nsIStyleSheet* sheetPtr = sheet; NS_ADDREF(sheetPtr); sheet->SetOwningDocument(this); PRBool enabled = PR_TRUE; sheet->GetEnabled(enabled); if (enabled) { AddStyleSheetToStyleSets(sheet); sheet->SetOwningDocument(nsnull); } } } // XXXldb Hopefully the observer doesn't care which sheet you use. for (PRInt32 indx = 0; indx < mObservers.Count(); indx++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers.ElementAt(indx); observer->StyleSheetRemoved(this, sheet); // handle the observer removing itself! if (observer != (nsIDocumentObserver*)mObservers.ElementAt(indx)) { indx--; } } return NS_OK; } void nsDocument::InternalInsertStyleSheetAt(nsIStyleSheet* aSheet, PRInt32 aIndex) { // subclass hook for sheet ordering mStyleSheets.InsertElementAt(aSheet, aIndex); } NS_IMETHODIMP nsDocument::InsertStyleSheetAt(nsIStyleSheet* aSheet, PRInt32 aIndex, PRBool aNotify) { NS_PRECONDITION(nsnull != aSheet, "null ptr"); InternalInsertStyleSheetAt(aSheet, aIndex); NS_ADDREF(aSheet); aSheet->SetOwningDocument(this); PRBool enabled = PR_TRUE; aSheet->GetEnabled(enabled); PRInt32 count; PRInt32 indx; if (enabled) { count = mPresShells.Count(); for (indx = 0; indx < count; indx++) { nsCOMPtr shell = (nsIPresShell*)mPresShells.ElementAt(indx); nsCOMPtr set; shell->GetStyleSet(getter_AddRefs(set)); if (set) { set->AddDocStyleSheet(aSheet, this); } } } if (aNotify) { // notify here even if disabled, there may have been others that weren't notified for (indx = 0; indx < mObservers.Count(); indx++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers.ElementAt(indx); observer->StyleSheetAdded(this, aSheet); // handle the observer removing itself! if (observer != (nsIDocumentObserver*)mObservers.ElementAt(indx)) { indx--; } } } return NS_OK; } void nsDocument::SetStyleSheetDisabledState(nsIStyleSheet* aSheet, PRBool aDisabled) { NS_PRECONDITION(nsnull != aSheet, "null arg"); PRInt32 indx = mStyleSheets.IndexOf((void *)aSheet); PRInt32 count; // If we're actually in the document style sheet list if (-1 != indx) { count = mPresShells.Count(); for (indx = 0; indx < count; indx++) { nsCOMPtr shell = (nsIPresShell*)mPresShells.ElementAt(indx); nsCOMPtr set; if (NS_SUCCEEDED(shell->GetStyleSet(getter_AddRefs(set)))) { if (set) { if (aDisabled) { set->RemoveDocStyleSheet(aSheet); } else { set->AddDocStyleSheet(aSheet, this); } } } } } for (indx = 0; indx < mObservers.Count(); indx++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers.ElementAt(indx); observer->StyleSheetDisabledStateChanged(this, aSheet, aDisabled); // handle the observer removing itself! if (observer != (nsIDocumentObserver*)mObservers.ElementAt(indx)) { indx--; } } } NS_IMETHODIMP nsDocument::GetScriptGlobalObject(nsIScriptGlobalObject** aScriptGlobalObject) { NS_ENSURE_ARG_POINTER(aScriptGlobalObject); // If we're going away, we've already released the reference to our // ScriptGlobalObject. We can, however, try to obtain it for the // caller through our docshell. if (mIsGoingAway) { nsCOMPtr requestor = do_QueryReferent(mDocumentContainer); if (requestor) return CallGetInterface(requestor.get(), aScriptGlobalObject); } *aScriptGlobalObject = mScriptGlobalObject; NS_IF_ADDREF(*aScriptGlobalObject); return NS_OK; } NS_IMETHODIMP nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject) { // XXX HACK ALERT! If the script context owner is null, the document // will soon be going away. So tell our content that to lose its // reference to the document. This has to be done before we // actually set the script context owner to null so that the // content elements can remove references to their script objects. if (!aScriptGlobalObject) { PRUint32 ucount, indx; mChildren->Count(&ucount); mIsGoingAway = PR_TRUE; for (indx = 0; indx < ucount; indx++) { nsCOMPtr content(dont_AddRef(NS_STATIC_CAST(nsIContent*,mChildren->ElementAt(indx)))); content->SetDocument(nsnull, PR_TRUE, PR_TRUE); } // Propagate the out-of-band notification to each PresShell's // anonymous content as well. This ensures that there aren't any // accidental script references left in anonymous content keeping // the document alive. (While not strictly necessary -- the // PresShell owns us -- it's tidy.) PRInt32 count; for (count = mPresShells.Count() - 1; count >= 0; --count) { nsCOMPtr shell = NS_STATIC_CAST(nsIPresShell*, mPresShells[count]); if (!shell) continue; shell->ReleaseAnonymousContent(); } #ifdef DEBUG_jst printf ("Content wrapper hash had %d entries.\n", mContentWrapperHash.Count()); #endif mContentWrapperHash.Reset(); } mScriptGlobalObject = aScriptGlobalObject; return NS_OK; } NS_IMETHODIMP nsDocument::GetNameSpaceManager(nsINameSpaceManager*& aManager) { aManager = mNameSpaceManager; NS_IF_ADDREF(aManager); return NS_OK; } NS_IMETHODIMP nsDocument::GetScriptLoader(nsIScriptLoader** aScriptLoader) { NS_ENSURE_ARG_POINTER(aScriptLoader); if (!mScriptLoader) { nsScriptLoader* loader = new nsScriptLoader(); if (!loader) { return NS_ERROR_OUT_OF_MEMORY; } mScriptLoader = loader; mScriptLoader->Init(this); } *aScriptLoader = mScriptLoader; NS_IF_ADDREF(*aScriptLoader); return NS_OK; } // Note: We don't hold a reference to the document observer; we assume // that it has a live reference to the document. void nsDocument::AddObserver(nsIDocumentObserver* aObserver) { // XXX Make sure the observer isn't already in the list if (mObservers.IndexOf(aObserver) == -1) { mObservers.AppendElement(aObserver); } } PRBool nsDocument::RemoveObserver(nsIDocumentObserver* aObserver) { // If we're in the process of destroying the document (and we're // informing the observers of the destruction), don't remove the // observers from the list. This is not a big deal, since we // don't hold a live reference to the observers. if (!mInDestructor) return mObservers.RemoveElement(aObserver); else return (mObservers.IndexOf(aObserver) != -1); } NS_IMETHODIMP nsDocument::BeginUpdate() { PRInt32 i; // Get new value of count for every iteration in case // observers remove themselves during the loop. for (i = 0; i < mObservers.Count(); i++) { nsIDocumentObserver* observer = (nsIDocumentObserver*) mObservers[i]; observer->BeginUpdate(this); // Make sure that the observer didn't remove itself during the // notification. If it did, update our index and count. if (i < mObservers.Count() && observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } NS_IMETHODIMP nsDocument::EndUpdate() { PRInt32 i; // Get new value of count for every iteration in case // observers remove themselves during the loop. for (i = 0; i < mObservers.Count(); i++) { nsIDocumentObserver* observer = (nsIDocumentObserver*) mObservers[i]; observer->EndUpdate(this); // Make sure that the observer didn't remove itself during the // notification. If it did, update our index and count. if (i < mObservers.Count() && observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } NS_IMETHODIMP nsDocument::BeginLoad() { PRInt32 i; // Get new value of count for every iteration in case // observers remove themselves during the loop. for (i = 0; i < mObservers.Count(); i++) { nsIDocumentObserver* observer = (nsIDocumentObserver*) mObservers[i]; observer->BeginLoad(this); // Make sure that the observer didn't remove itself during the // notification. If it did, update our index and count. if (i < mObservers.Count() && observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } static void GetDocumentFromDocShellTreeItem(nsIDocShellTreeItem *aDocShell, nsIDocument **aDocument) { *aDocument = nsnull; nsCOMPtr window(do_GetInterface(aDocShell)); if (window) { nsCOMPtr dom_doc; window->GetDocument(getter_AddRefs(dom_doc)); if (dom_doc) { CallQueryInterface(dom_doc, aDocument); } } } NS_IMETHODIMP nsDocument::EndLoad() { PRInt32 i; // Get new value of count for every iteration in case // observers remove themselves during the loop. for (i = 0; i < mObservers.Count(); i++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; observer->EndLoad(this); // Make sure that the observer didn't remove itself during the // notification. If it did, update our index and count. if (i < mObservers.Count() && observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } // Fire a DOM event notifying listeners that this document has been // loaded (excluding images and other loads initiated by this // document). nsCOMPtr event; CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event)); if (event) { event->InitEvent(NS_LITERAL_STRING("DOMContentLoaded"), PR_TRUE, PR_TRUE); PRBool noDefault; DispatchEvent(event, &noDefault); } // If this document is a [i]frame, fire a DOMFrameContentLoaded // event on all parent documents notifying that the HTML (excluding // other external files such as images and stylesheets) in a frame // has finished loading. nsCOMPtr docShellParent; // target_frame is the [i]frame element that will be used as the // target for the event. It's the [i]frame whose content is done // loading. nsCOMPtr target_frame; if (mScriptGlobalObject) { nsCOMPtr docShell; mScriptGlobalObject->GetDocShell(getter_AddRefs(docShell)); nsCOMPtr docShellAsItem = do_QueryInterface(docShell); if (docShellAsItem) { docShellAsItem->GetSameTypeParent(getter_AddRefs(docShellParent)); nsCOMPtr parent_doc; GetDocumentFromDocShellTreeItem(docShellParent, getter_AddRefs(parent_doc)); if (parent_doc) { nsCOMPtr target_content; parent_doc->FindContentForSubDocument(this, getter_AddRefs(target_content)); target_frame = do_QueryInterface(target_content); } } } if (target_frame) { while (docShellParent) { nsCOMPtr ancestor_doc; GetDocumentFromDocShellTreeItem(docShellParent, getter_AddRefs(ancestor_doc)); if (!ancestor_doc) { break; } nsCOMPtr private_event; nsCOMPtr document_event = do_QueryInterface(ancestor_doc); if (document_event) { document_event->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event)); private_event = do_QueryInterface(event); } if (event && private_event) { event->InitEvent(NS_LITERAL_STRING("DOMFrameContentLoaded"), PR_TRUE, PR_TRUE); private_event->SetTarget(target_frame); // To dispatch this event we must manually call // HandleDOMEvent() on the ancestor document since the target // is not in the same document, so the event would never reach // the ancestor document if we used the normal event // dispatching code. nsEvent* innerEvent; private_event->GetInternalNSEvent(&innerEvent); if (innerEvent) { nsEventStatus status = nsEventStatus_eIgnore; nsCOMPtr shell; ancestor_doc->GetShellAt(0, getter_AddRefs(shell)); if (shell) { nsCOMPtr context; shell->GetPresContext(getter_AddRefs(context)); if (context) { // The event argument to HandleDOMEvent() is inout, and // that doesn't mix well with nsCOMPtr's. We'll need to // perform some refcounting magic here. nsIDOMEvent *tmp_event = event; NS_ADDREF(tmp_event); ancestor_doc->HandleDOMEvent(context, innerEvent, &tmp_event, NS_EVENT_FLAG_INIT, &status); NS_IF_RELEASE(tmp_event); } } } } nsCOMPtr tmp(docShellParent); tmp->GetSameTypeParent(getter_AddRefs(docShellParent)); } } return NS_OK; } NS_IMETHODIMP nsDocument::ContentChanged(nsIContent* aContent, nsISupports* aSubContent) { NS_ABORT_IF_FALSE(aContent, "Null content!"); PRInt32 i; // Get new value of count for every iteration in case // observers remove themselves during the loop. for (i = 0; i < mObservers.Count(); i++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; observer->ContentChanged(this, aContent, aSubContent); // Make sure that the observer didn't remove itself during the // notification. If it did, update our index and count. if (i < mObservers.Count() && observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } NS_IMETHODIMP nsDocument::ContentStatesChanged(nsIContent* aContent1, nsIContent* aContent2, PRInt32 aStateMask) { PRInt32 i; // Get new value of count for every iteration in case // observers remove themselves during the loop. for (i = 0; i < mObservers.Count(); i++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; observer->ContentStatesChanged(this, aContent1, aContent2, aStateMask); // Make sure that the observer didn't remove itself during the // notification. If it did, update our index and count. if (i < mObservers.Count() && observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } NS_IMETHODIMP nsDocument::ContentAppended(nsIContent* aContainer, PRInt32 aNewIndexInContainer) { NS_ABORT_IF_FALSE(aContainer, "Null container!"); #ifdef XP_OS2_VACPP volatile #endif PRInt32 i; // Get new value of count for every iteration in case // observers remove themselves during the loop. for (i = 0; i < mObservers.Count(); i++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; observer->ContentAppended(this, aContainer, aNewIndexInContainer); // Make sure that the observer didn't remove itself during the // notification. If it did, update our index and count. if (i < mObservers.Count() && observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } NS_IMETHODIMP nsDocument::ContentInserted(nsIContent* aContainer, nsIContent* aChild, PRInt32 aIndexInContainer) { NS_ABORT_IF_FALSE(aChild, "Null child!"); PRInt32 i; // Get new value of count for every iteration in case // observers remove themselves during the loop. for (i = 0; i < mObservers.Count(); i++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; observer->ContentInserted(this, aContainer, aChild, aIndexInContainer); // Make sure that the observer didn't remove itself during the // notification. If it did, update our index and count. if (i < mObservers.Count() && observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } NS_IMETHODIMP nsDocument::ContentReplaced(nsIContent* aContainer, nsIContent* aOldChild, nsIContent* aNewChild, PRInt32 aIndexInContainer) { NS_ABORT_IF_FALSE(aOldChild && aNewChild, "Null old or new child child!"); PRInt32 i; // Get new value of count for every iteration in case // observers remove themselves during the loop. for (i = 0; i < mObservers.Count(); i++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; observer->ContentReplaced(this, aContainer, aOldChild, aNewChild, aIndexInContainer); // Make sure that the observer didn't remove itself during the // notification. If it did, update our index and count. if (i < mObservers.Count() && observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } NS_IMETHODIMP nsDocument::ContentRemoved(nsIContent* aContainer, nsIContent* aChild, PRInt32 aIndexInContainer) { NS_ABORT_IF_FALSE(aChild, "Null child!"); PRInt32 i; // Get new value of count for every iteration in case // observers remove themselves during the loop. for (i = 0; i < mObservers.Count(); i++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; observer->ContentRemoved(this, aContainer, aChild, aIndexInContainer); // Make sure that the observer didn't remove itself during the // notification. If it did, update our index and count. if (i < mObservers.Count() && observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } NS_IMETHODIMP nsDocument::AttributeWillChange(nsIContent* aChild, PRInt32 aNameSpaceID, nsIAtom* aAttribute) { NS_ABORT_IF_FALSE(aChild, "Null child!"); return NS_OK; } NS_IMETHODIMP nsDocument::AttributeChanged(nsIContent* aChild, PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRInt32 aModType, nsChangeHint aHint) { NS_ABORT_IF_FALSE(aChild, "Null child!"); PRInt32 i; nsresult result = NS_OK; // Get new value of count for every iteration in case // observers remove themselves during the loop. for (i = 0; i < mObservers.Count(); i++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; nsresult rv = observer->AttributeChanged(this, aChild, aNameSpaceID, aAttribute, aModType, aHint); if (NS_FAILED(rv) && NS_SUCCEEDED(result)) result = rv; // Make sure that the observer didn't remove itself during the // notification. If it did, update our index and count. if (i < mObservers.Count() && observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return result; } NS_IMETHODIMP nsDocument::StyleRuleChanged(nsIStyleSheet* aStyleSheet, nsIStyleRule* aStyleRule, nsChangeHint aHint) { PRInt32 i; // Get new value of count for every iteration in case // observers remove themselves during the loop. for (i = 0; i < mObservers.Count(); i++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; observer->BeginUpdate(this); observer->StyleRuleChanged(this, aStyleSheet, aStyleRule, aHint); // Make sure that the observer didn't remove itself during the // notification. If it did, update our index and count. if (i < mObservers.Count() && observer != (nsIDocumentObserver*)mObservers[i]) { i--; } else { observer->EndUpdate(this); } } return NS_OK; } NS_IMETHODIMP nsDocument::StyleRuleAdded(nsIStyleSheet* aStyleSheet, nsIStyleRule* aStyleRule) { PRInt32 i; // Get new value of count for every iteration in case // observers remove themselves during the loop. for (i = 0; i < mObservers.Count(); i++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; observer->BeginUpdate(this); observer->StyleRuleAdded(this, aStyleSheet, aStyleRule); // Make sure that the observer didn't remove itself during the // notification. If it did, update our index and count. if (i < mObservers.Count() && observer != (nsIDocumentObserver*)mObservers[i]) { i--; } else { observer->EndUpdate(this); } } return NS_OK; } NS_IMETHODIMP nsDocument::StyleRuleRemoved(nsIStyleSheet* aStyleSheet, nsIStyleRule* aStyleRule) { PRInt32 i; // Get new value of count for every iteration in case // observers remove themselves during the loop. for (i = 0; i < mObservers.Count(); i++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers[i]; observer->BeginUpdate(this); observer->StyleRuleRemoved(this, aStyleSheet, aStyleRule); // Make sure that the observer didn't remove itself during the // notification. If it did, update our index and count. if (i < mObservers.Count() && observer != (nsIDocumentObserver*)mObservers[i]) { i--; } else { observer->EndUpdate(this); } } return NS_OK; } // // nsIDOMDocument interface // NS_IMETHODIMP nsDocument::GetDoctype(nsIDOMDocumentType** aDoctype) { NS_ENSURE_ARG_POINTER(aDoctype); *aDoctype = nsnull; PRUint32 i, count; mChildren->Count(&count); nsCOMPtr rootContentNode( do_QueryInterface(mRootContent) ); nsCOMPtr node; for (i = 0; i < count; i++) { mChildren->QueryElementAt(i, NS_GET_IID(nsIDOMNode), getter_AddRefs(node)); NS_ASSERTION(node, "null element of mChildren"); // doctype can't be after the root // XXX Do we really want to enforce this when we don't enforce // anything else? if (node == rootContentNode) return NS_OK; if (node) { PRUint16 nodeType; node->GetNodeType(&nodeType); if (nodeType == nsIDOMNode::DOCUMENT_TYPE_NODE) { return node->QueryInterface(NS_GET_IID(nsIDOMDocumentType), (void **)aDoctype); } } } return NS_OK; } NS_IMETHODIMP nsDocument::GetImplementation(nsIDOMDOMImplementation** aImplementation) { // For now, create a new implementation every time. This shouldn't // be a high bandwidth operation nsDOMImplementation* impl = new nsDOMImplementation(mDocumentURL); if (nsnull == impl) { return NS_ERROR_OUT_OF_MEMORY; } return impl->QueryInterface(NS_GET_IID(nsIDOMDOMImplementation), (void**)aImplementation); } NS_IMETHODIMP nsDocument::GetDocumentElement(nsIDOMElement** aDocumentElement) { if (nsnull == aDocumentElement) { return NS_ERROR_NULL_POINTER; } nsresult res = NS_OK; if (mRootContent) { res = CallQueryInterface(mRootContent, aDocumentElement); NS_ASSERTION(NS_OK == res, "Must be a DOM Element"); } else { *aDocumentElement = nsnull; } return res; } NS_IMETHODIMP nsDocument::CreateElement(const nsAString& aTagName, nsIDOMElement** aReturn) { // Should be implemented by subclass return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsDocument::CreateElementNS(const nsAString & namespaceURI, const nsAString & qualifiedName, nsIDOMElement **_retval) { // Should be implemented by subclass return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsDocument::CreateTextNode(const nsAString& aData, nsIDOMText** aReturn) { nsCOMPtr text; nsresult rv = NS_NewTextNode(getter_AddRefs(text)); if (NS_OK == rv) { rv = text->QueryInterface(NS_GET_IID(nsIDOMText), (void**)aReturn); (*aReturn)->AppendData(aData); } return rv; } NS_IMETHODIMP nsDocument::CreateDocumentFragment(nsIDOMDocumentFragment** aReturn) { return NS_NewDocumentFragment(aReturn, this); } NS_IMETHODIMP nsDocument::CreateComment(const nsAString& aData, nsIDOMComment** aReturn) { nsCOMPtr comment; nsresult rv = NS_NewCommentNode(getter_AddRefs(comment)); if (NS_OK == rv) { rv = comment->QueryInterface(NS_GET_IID(nsIDOMComment), (void**)aReturn); (*aReturn)->AppendData(aData); } return rv; } NS_IMETHODIMP nsDocument::CreateCDATASection(const nsAString& aData, nsIDOMCDATASection** aReturn) { // Should be implemented by subclass return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsDocument::CreateProcessingInstruction(const nsAString& aTarget, const nsAString& aData, nsIDOMProcessingInstruction** aReturn) { // Should be implemented by subclass return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsDocument::CreateAttribute(const nsAString& aName, nsIDOMAttr** aReturn) { NS_ENSURE_ARG_POINTER(aReturn); NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_NOT_INITIALIZED); nsAutoString value; nsDOMAttribute* attribute; nsCOMPtr nodeInfo; nsresult rv = mNodeInfoManager->GetNodeInfo(aName, nsnull, kNameSpaceID_None, *getter_AddRefs(nodeInfo)); NS_ENSURE_SUCCESS(rv, rv); attribute = new nsDOMAttribute(nsnull, nodeInfo, value); NS_ENSURE_TRUE(attribute, NS_ERROR_OUT_OF_MEMORY); return attribute->QueryInterface(NS_GET_IID(nsIDOMAttr), (void**)aReturn); } NS_IMETHODIMP nsDocument::CreateAttributeNS(const nsAString & namespaceURI, const nsAString & qualifiedName, nsIDOMAttr **_retval) { // Should be implemented by subclass return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsDocument::CreateEntityReference(const nsAString& aName, nsIDOMEntityReference** aReturn) { // Should be implemented by subclass return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsDocument::GetElementsByTagName(const nsAString& aTagname, nsIDOMNodeList** aReturn) { nsCOMPtr nameAtom(dont_AddRef(NS_NewAtom(aTagname))); nsCOMPtr list; NS_GetContentList(this, nameAtom, kNameSpaceID_Unknown, nsnull, getter_AddRefs(list)); NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY); return CallQueryInterface(list, aReturn); } NS_IMETHODIMP nsDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI, const nsAString& aLocalName, nsIDOMNodeList** aReturn) { PRInt32 nameSpaceId = kNameSpaceID_Unknown; nsCOMPtr list; if (!aNamespaceURI.Equals(NS_LITERAL_STRING("*"))) { mNameSpaceManager->GetNameSpaceID(aNamespaceURI, nameSpaceId); if (nameSpaceId == kNameSpaceID_Unknown) { // Unkonwn namespace means no matches, we create an empty list... NS_GetContentList(this, nsnull, kNameSpaceID_None, nsnull, getter_AddRefs(list)); NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY); } } if (!list) { nsCOMPtr nameAtom(dont_AddRef(NS_NewAtom(aLocalName))); NS_GetContentList(this, nameAtom, nameSpaceId, nsnull, getter_AddRefs(list)); NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY); } return CallQueryInterface(list, aReturn); } NS_IMETHODIMP nsDocument::GetElementById(const nsAString & elementId, nsIDOMElement **_retval) { // Should be implemented by subclass return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsDocument::Load(const nsAString& aUrl) { NS_ERROR("nsDocument::Load() should be overriden by subclass!"); return NS_OK; } NS_IMETHODIMP nsDocument::EvaluateFIXptr(const nsAString& aExpression, nsIDOMRange **aRange) { NS_ERROR("nsDocument::EvaluateFIXptr() should be overriden by subclass!"); return NS_OK; } NS_IMETHODIMP nsDocument::GetStyleSheets(nsIDOMStyleSheetList** aStyleSheets) { if (!mDOMStyleSheets) { mDOMStyleSheets = new nsDOMStyleSheetList(this); if (!mDOMStyleSheets) { return NS_ERROR_OUT_OF_MEMORY; } } *aStyleSheets = mDOMStyleSheets; NS_ADDREF(*aStyleSheets); return NS_OK; } NS_IMETHODIMP nsDocument::GetCharacterSet(nsAString& aCharacterSet) { return GetDocumentCharacterSet(aCharacterSet); } NS_IMETHODIMP nsDocument::ImportNode(nsIDOMNode* aImportedNode, PRBool aDeep, nsIDOMNode** aReturn) { NS_ENSURE_ARG(aImportedNode); NS_ENSURE_ARG_POINTER(aReturn); nsresult rv = nsContentUtils::CheckSameOrigin(this, aImportedNode); if (NS_FAILED(rv)) { return rv; } return aImportedNode->CloneNode(aDeep, aReturn); } NS_IMETHODIMP nsDocument::AddBinding(nsIDOMElement* aContent, const nsAString& aURL) { nsresult rv = nsContentUtils::CheckSameOrigin(this, aContent); if (NS_FAILED(rv)) { return rv; } nsCOMPtr bm; GetBindingManager(getter_AddRefs(bm)); nsCOMPtr content(do_QueryInterface(aContent)); return bm->AddLayeredBinding(content, aURL); } NS_IMETHODIMP nsDocument::RemoveBinding(nsIDOMElement* aContent, const nsAString& aURL) { nsresult rv = nsContentUtils::CheckSameOrigin(this, aContent); if (NS_FAILED(rv)) { return rv; } if (mBindingManager) { nsCOMPtr content(do_QueryInterface(aContent)); return mBindingManager->RemoveLayeredBinding(content, aURL); } return NS_ERROR_FAILURE; } NS_IMETHODIMP nsDocument::LoadBindingDocument(const nsAString& aURL, nsIDOMDocument** aResult) { if (mBindingManager) { nsCOMPtr doc; mBindingManager->LoadBindingDocument(this, aURL, getter_AddRefs(doc)); nsCOMPtr domDoc(do_QueryInterface(doc)); *aResult = domDoc; NS_IF_ADDREF(*aResult); return NS_OK; } return NS_ERROR_FAILURE; } NS_IMETHODIMP nsDocument::GetBindingParent(nsIDOMNode* aNode, nsIDOMElement** aResult) { *aResult = nsnull; nsCOMPtr content(do_QueryInterface(aNode)); if (!content) return NS_ERROR_FAILURE; nsCOMPtr result; content->GetBindingParent(getter_AddRefs(result)); nsCOMPtr elt(do_QueryInterface(result)); *aResult = elt; NS_IF_ADDREF(*aResult); return NS_OK; } static nsresult GetElementByAttribute(nsIContent* aContent, nsIAtom* aAttrName, const nsAString& aAttrValue, PRBool aUniversalMatch, nsIDOMElement** aResult) { nsAutoString value; nsresult rv = aContent->GetAttr(kNameSpaceID_None, aAttrName, value); if (rv == NS_CONTENT_ATTR_HAS_VALUE) { if (aUniversalMatch || value.Equals(aAttrValue)) return aContent->QueryInterface(NS_GET_IID(nsIDOMElement), (void**)aResult); } PRInt32 childCount; aContent->ChildCount(childCount); for (PRInt32 i = 0; i < childCount; ++i) { nsCOMPtr current; aContent->ChildAt(i, *getter_AddRefs(current)); GetElementByAttribute(current, aAttrName, aAttrValue, aUniversalMatch, aResult); if (*aResult) return NS_OK; } return NS_OK; } NS_IMETHODIMP nsDocument::GetAnonymousElementByAttribute(nsIDOMElement* aElement, const nsAString& aAttrName, const nsAString& aAttrValue, nsIDOMElement** aResult) { *aResult = nsnull; nsCOMPtr nodeList; GetAnonymousNodes(aElement, getter_AddRefs(nodeList)); if (!nodeList) return NS_OK; nsCOMPtr attribute = getter_AddRefs(NS_NewAtom(aAttrName)); PRUint32 length; nodeList->GetLength(&length); PRBool universalMatch = aAttrValue.Equals(NS_LITERAL_STRING("*")); for (PRUint32 i = 0; i < length; ++i) { nsCOMPtr current; nodeList->Item(i, getter_AddRefs(current)); nsCOMPtr content(do_QueryInterface(current)); GetElementByAttribute(content, attribute, aAttrValue, universalMatch, aResult); if (*aResult) return NS_OK; } return NS_OK; } NS_IMETHODIMP nsDocument::GetAnonymousNodes(nsIDOMElement* aElement, nsIDOMNodeList** aResult) { *aResult = nsnull; if (mBindingManager) { nsCOMPtr content(do_QueryInterface(aElement)); return mBindingManager->GetAnonymousNodesFor(content, aResult); } return NS_OK; } NS_IMETHODIMP nsDocument::CreateRange(nsIDOMRange** aReturn) { return NS_NewRange(aReturn); } NS_IMETHODIMP nsDocument::CreateNodeIterator(nsIDOMNode *aRoot, PRUint32 aWhatToShow, nsIDOMNodeFilter *aFilter, PRBool aEntityReferenceExpansion, nsIDOMNodeIterator **_retval) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsDocument::CreateTreeWalker(nsIDOMNode *aRoot, PRUint32 aWhatToShow, nsIDOMNodeFilter *aFilter, PRBool aEntityReferenceExpansion, nsIDOMTreeWalker **_retval) { *_retval = nsnull; nsresult rv = nsContentUtils::CheckSameOrigin(this, aRoot); if(NS_FAILED(rv)) return rv; return NS_NewTreeWalker(aRoot, aWhatToShow, aFilter, aEntityReferenceExpansion, _retval); } NS_IMETHODIMP nsDocument::GetDefaultView(nsIDOMAbstractView** aDefaultView) { NS_ENSURE_ARG_POINTER(aDefaultView); *aDefaultView = nsnull; NS_ENSURE_TRUE(mPresShells.Count() != 0, NS_OK); nsCOMPtr shell = NS_STATIC_CAST(nsIPresShell *, mPresShells.ElementAt(0)); NS_ENSURE_TRUE(shell, NS_OK); nsCOMPtr ctx; nsresult rv = shell->GetPresContext(getter_AddRefs(ctx)); NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && ctx, rv); nsCOMPtr container; rv = ctx->GetContainer(getter_AddRefs(container)); NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && container, rv); nsCOMPtr ifrq(do_QueryInterface(container)); NS_ENSURE_TRUE(ifrq, NS_OK); nsCOMPtr window; ifrq->GetInterface(NS_GET_IID(nsIDOMWindowInternal), getter_AddRefs(window)); NS_ENSURE_TRUE(window, NS_OK); window->QueryInterface(NS_GET_IID(nsIDOMAbstractView), (void **)aDefaultView); return NS_OK; } NS_IMETHODIMP nsDocument::GetLocation(nsIDOMLocation **_retval) { NS_ENSURE_ARG_POINTER(_retval); *_retval = nsnull; nsCOMPtr w(do_QueryInterface(mScriptGlobalObject)); if(w) { return w->GetLocation(_retval); } return NS_OK; } NS_IMETHODIMP nsDocument::GetTitle(nsAString& aTitle) { aTitle.Assign(mDocumentTitle); return NS_OK; } NS_IMETHODIMP nsDocument::SetTitle(const nsAString& aTitle) { for (PRInt32 i = mPresShells.Count() - 1; i >= 0; --i) { nsCOMPtr shell = NS_STATIC_CAST(nsIPresShell*, mPresShells[i]); nsCOMPtr context; nsresult rv = shell->GetPresContext(getter_AddRefs(context)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr container; rv = context->GetContainer(getter_AddRefs(container)); NS_ENSURE_SUCCESS(rv, rv); if (!container) continue; nsCOMPtr docShellWin = do_QueryInterface(container); if(!docShellWin) continue; rv = docShellWin->SetTitle(PromiseFlatString(aTitle).get()); NS_ENSURE_SUCCESS(rv, rv); } mDocumentTitle.Assign(aTitle); // Fire a DOM event for the title change. nsCOMPtr event; CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event)); if (event) { event->InitEvent(NS_LITERAL_STRING("DOMTitleChanged"), PR_TRUE, PR_TRUE); PRBool noDefault; DispatchEvent(event, &noDefault); } return NS_OK; } NS_IMETHODIMP nsDocument::GetBoxObjectFor(nsIDOMElement* aElement, nsIBoxObject** aResult) { nsresult rv; *aResult = nsnull; if (!mBoxObjectTable) mBoxObjectTable = new nsSupportsHashtable; else { nsISupportsKey key(aElement); nsCOMPtr supports(dont_AddRef(NS_STATIC_CAST(nsISupports*, mBoxObjectTable->Get(&key)))); nsCOMPtr boxObject(do_QueryInterface(supports)); if (boxObject) { *aResult = boxObject; NS_ADDREF(*aResult); return NS_OK; } } nsCOMPtr shell; GetShellAt(0, getter_AddRefs(shell)); if (!shell) return NS_ERROR_FAILURE; PRInt32 namespaceID; nsCOMPtr tag; nsCOMPtr xblService = do_GetService("@mozilla.org/xbl;1", &rv); nsCOMPtr content(do_QueryInterface(aElement)); xblService->ResolveTag(content, &namespaceID, getter_AddRefs(tag)); nsCAutoString contractID("@mozilla.org/layout/xul-boxobject"); if (namespaceID == nsXULAtoms::nameSpaceID) { if (tag.get() == nsXULAtoms::browser) contractID += "-browser"; else if (tag.get() == nsXULAtoms::editor) contractID += "-editor"; else if (tag.get() == nsXULAtoms::iframe) contractID += "-iframe"; else if (tag.get() == nsXULAtoms::menu) contractID += "-menu"; else if (tag.get() == nsXULAtoms::popup || tag.get() == nsXULAtoms::menupopup || tag.get() == nsXULAtoms::tooltip) contractID += "-popup"; else if (tag.get() == nsXULAtoms::scrollbox) contractID += "-scrollbox"; else if (tag.get() == nsXULAtoms::tree) contractID += "-tree"; } contractID += ";1"; nsCOMPtr boxObject(do_CreateInstance(contractID.get())); if (!boxObject) return NS_ERROR_FAILURE; nsCOMPtr privateBox(do_QueryInterface(boxObject)); if (NS_FAILED(rv = privateBox->Init(content, shell))) return rv; SetBoxObjectFor(aElement, boxObject); *aResult = boxObject; NS_ADDREF(*aResult); return NS_OK; } NS_IMETHODIMP nsDocument::SetBoxObjectFor(nsIDOMElement* aElement, nsIBoxObject* aBoxObject) { if (!mBoxObjectTable) { if (!aBoxObject) return NS_OK; mBoxObjectTable = new nsSupportsHashtable(12); } nsISupportsKey key(aElement); if (aBoxObject) mBoxObjectTable->Put(&key, aBoxObject); else { nsCOMPtr supp; mBoxObjectTable->Remove(&key, getter_AddRefs(supp)); nsCOMPtr boxObject(do_QueryInterface(supp)); if (boxObject) boxObject->SetDocument(nsnull); } return NS_OK; } #ifdef IBMBIDI struct DirTable { const char* mName; PRUint8 mValue; }; static const DirTable dirAttributes[] = { {"ltr", IBMBIDI_TEXTDIRECTION_LTR}, {"rtl", IBMBIDI_TEXTDIRECTION_RTL}, {0} }; #endif // IBMBIDI /** * Retrieve the "direction" property of the document. * * @lina 01/09/2001 */ NS_IMETHODIMP nsDocument::GetDir(nsAString& aDirection) { #ifdef IBMBIDI nsCOMPtr shell = (nsIPresShell*)mPresShells.SafeElementAt(0); if (shell) { nsCOMPtr context; shell->GetPresContext(getter_AddRefs(context) ); if (context) { PRUint32 options; context->GetBidi(&options); for (const DirTable* elt = dirAttributes; elt->mName; elt++) { if (GET_BIDI_OPTION_DIRECTION(options) == elt->mValue) { aDirection.Assign(NS_ConvertASCIItoUCS2(elt->mName) ); break; } } } } #else aDirection.Assign(NS_LITERAL_STRING("ltr")); #endif // IBMBIDI return NS_OK; } /** * Set the "direction" property of the document. * * @lina 01/09/2001 */ NS_IMETHODIMP nsDocument::SetDir(const nsAString& aDirection) { #ifdef IBMBIDI if (mPresShells.Count() != 0) { nsCOMPtr shell = (nsIPresShell*)mPresShells.ElementAt(0); if (shell) { nsCOMPtr context; shell->GetPresContext(getter_AddRefs(context) ); if (context) { PRUint32 options; context->GetBidi(&options); for (const DirTable* elt = dirAttributes; elt->mName; elt++) { if (aDirection == NS_ConvertASCIItoUCS2(elt->mName) ) { if (GET_BIDI_OPTION_DIRECTION(options) != elt->mValue) { SET_BIDI_OPTION_DIRECTION(options, elt->mValue); context->SetBidi(options, PR_TRUE); } break; } } // for } } } #endif // IBMBIDI return NS_OK; } // // nsIDOMNode methods // NS_IMETHODIMP nsDocument::GetNodeName(nsAString& aNodeName) { aNodeName.Assign(NS_LITERAL_STRING("#document")); return NS_OK; } NS_IMETHODIMP nsDocument::GetNodeValue(nsAString& aNodeValue) { SetDOMStringToNull(aNodeValue); return NS_OK; } NS_IMETHODIMP nsDocument::SetNodeValue(const nsAString& aNodeValue) { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; } NS_IMETHODIMP nsDocument::GetNodeType(PRUint16* aNodeType) { *aNodeType = nsIDOMNode::DOCUMENT_NODE; return NS_OK; } NS_IMETHODIMP nsDocument::GetParentNode(nsIDOMNode** aParentNode) { *aParentNode = nsnull; return NS_OK; } NS_IMETHODIMP nsDocument::GetChildNodes(nsIDOMNodeList** aChildNodes) { if (nsnull == mChildNodes) { mChildNodes = new nsDocumentChildNodes(this); if (nsnull == mChildNodes) { return NS_ERROR_OUT_OF_MEMORY; } NS_ADDREF(mChildNodes); } return mChildNodes->QueryInterface(NS_GET_IID(nsIDOMNodeList), (void**)aChildNodes); } NS_IMETHODIMP nsDocument::HasChildNodes(PRBool* aHasChildNodes) { NS_ENSURE_ARG(aHasChildNodes); PRUint32 count; mChildren->Count(&count); *aHasChildNodes = (count != 0); return NS_OK; } NS_IMETHODIMP nsDocument::HasAttributes(PRBool* aHasAttributes) { NS_ENSURE_ARG(aHasAttributes); *aHasAttributes = PR_FALSE; return NS_OK; } NS_IMETHODIMP nsDocument::GetFirstChild(nsIDOMNode** aFirstChild) { nsresult result = NS_OK; PRUint32 count; mChildren->Count(&count); if (count) { result = mChildren->QueryElementAt(0, NS_GET_IID(nsIDOMNode), NS_REINTERPRET_CAST(void**, aFirstChild)); } else { *aFirstChild = nsnull; } return result; } NS_IMETHODIMP nsDocument::GetLastChild(nsIDOMNode** aLastChild) { nsresult result = NS_OK; PRUint32 count; mChildren->Count(&count); if (count) { result = mChildren->QueryElementAt(count-1, NS_GET_IID(nsIDOMNode), NS_REINTERPRET_CAST(void**, aLastChild)); } else { *aLastChild = nsnull; } return result; } NS_IMETHODIMP nsDocument::GetPreviousSibling(nsIDOMNode** aPreviousSibling) { *aPreviousSibling = nsnull; return NS_OK; } NS_IMETHODIMP nsDocument::GetNextSibling(nsIDOMNode** aNextSibling) { *aNextSibling = nsnull; return NS_OK; } NS_IMETHODIMP nsDocument::GetAttributes(nsIDOMNamedNodeMap** aAttributes) { *aAttributes = nsnull; return NS_OK; } NS_IMETHODIMP nsDocument::GetNamespaceURI(nsAString& aNamespaceURI) { SetDOMStringToNull(aNamespaceURI); return NS_OK; } NS_IMETHODIMP nsDocument::GetPrefix(nsAString& aPrefix) { SetDOMStringToNull(aPrefix); return NS_OK; } NS_IMETHODIMP nsDocument::SetPrefix(const nsAString& aPrefix) { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; } NS_IMETHODIMP nsDocument::GetLocalName(nsAString& aLocalName) { SetDOMStringToNull(aLocalName); return NS_OK; } NS_IMETHODIMP nsDocument::InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild, nsIDOMNode** aReturn) { NS_ASSERTION(nsnull != aNewChild, "null ptr"); PRInt32 indx; PRUint16 nodeType; *aReturn = nsnull; // Do we need to do this? if (nsnull == aNewChild) { return NS_ERROR_NULL_POINTER; } nsresult rv = nsContentUtils::CheckSameOrigin(this, aNewChild); if (NS_FAILED(rv)) { return rv; } // If it's a child type we can't handle (per DOM spec), or if it's an // element and we already have a root (our addition to DOM spec), throw // HIERARCHY_REQUEST_ERR. aNewChild->GetNodeType(&nodeType); if (((COMMENT_NODE != nodeType) && (TEXT_NODE != nodeType) && (PROCESSING_INSTRUCTION_NODE != nodeType) && (DOCUMENT_TYPE_NODE != nodeType) && (ELEMENT_NODE != nodeType)) || ((ELEMENT_NODE == nodeType) && mRootContent)){ return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; } nsCOMPtr content( do_QueryInterface(aNewChild) ); if (!content) { return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; } if (!aRefChild) { PRUint32 count; mChildren->Count(&count); indx = count; mChildren->AppendElement(content); } else { nsCOMPtr refContent( do_QueryInterface(aRefChild) ); if (!refContent) { return NS_ERROR_DOM_NOT_FOUND_ERR; } indx = mChildren->IndexOf(refContent); if (indx != -1) { mChildren->InsertElementAt(content, indx); } else { // couldn't find refChild return NS_ERROR_DOM_NOT_FOUND_ERR; } } // If we get here, we've succesfully inserted content into the // index-th spot in mChildren. if (ELEMENT_NODE == nodeType) mRootContent = content; content->SetDocument(this, PR_TRUE, PR_TRUE); ContentInserted(nsnull, content, indx); *aReturn = aNewChild; NS_ADDREF(aNewChild); return NS_OK; } NS_IMETHODIMP nsDocument::ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild, nsIDOMNode** aReturn) { NS_ASSERTION(((nsnull != aNewChild) && (nsnull != aOldChild)), "null ptr"); nsresult result = NS_OK; PRInt32 indx; PRUint16 nodeType; *aReturn = nsnull; // is this necessary? if ((nsnull == aNewChild) || (nsnull == aOldChild)) { return NS_ERROR_NULL_POINTER; } result = nsContentUtils::CheckSameOrigin(this, aNewChild); if (NS_FAILED(result)) { return result; } aNewChild->GetNodeType(&nodeType); if ((COMMENT_NODE != nodeType) && (TEXT_NODE != nodeType) && (PROCESSING_INSTRUCTION_NODE != nodeType) && (DOCUMENT_TYPE_NODE != nodeType) && (ELEMENT_NODE != nodeType)) { return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; } nsCOMPtr content( do_QueryInterface(aNewChild) ); nsCOMPtr refContent( do_QueryInterface(aOldChild) ); if (!content || !refContent) { return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; } if ((ELEMENT_NODE == nodeType) && mRootContent && (mRootContent != refContent.get())) { // Caller attempted to add a second element as a child. return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; } indx = mChildren->IndexOf(refContent); if (-1 == indx) { // The reference child is not a child of the document. return NS_ERROR_DOM_NOT_FOUND_ERR; } ContentRemoved(nsnull, refContent, indx); refContent->SetDocument(nsnull, PR_TRUE, PR_TRUE); mChildren->ReplaceElementAt(content, indx); // This is OK because we checked above. if (ELEMENT_NODE == nodeType) mRootContent = content; content->SetDocument(this, PR_TRUE, PR_TRUE); ContentInserted(nsnull, content, indx); *aReturn = aOldChild; NS_ADDREF(aOldChild); return result; } NS_IMETHODIMP nsDocument::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn) { NS_ASSERTION(nsnull != aOldChild, "null ptr"); *aReturn = nsnull; // do we need to do this? if (nsnull == aOldChild) { return NS_ERROR_NULL_POINTER; } nsCOMPtr content( do_QueryInterface(aOldChild) ); if (!content) { return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; } PRInt32 indx = mChildren->IndexOf(content); if (-1 == indx) { return NS_ERROR_DOM_NOT_FOUND_ERR; } ContentRemoved(nsnull, content, indx); mChildren->RemoveElementAt(indx); if (content.get() == mRootContent) mRootContent = nsnull; content->SetDocument(nsnull, PR_TRUE, PR_TRUE); *aReturn = aOldChild; NS_ADDREF(aOldChild); return NS_OK; } NS_IMETHODIMP nsDocument::AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn) { return InsertBefore(aNewChild, nsnull, aReturn); } NS_IMETHODIMP nsDocument::CloneNode(PRBool aDeep, nsIDOMNode** aReturn) { // XXX should be implemented by subclass *aReturn = nsnull; return NS_OK; } NS_IMETHODIMP nsDocument::Normalize() { // XXX Not completely correct, since you can still have unnormalized // text nodes as immediate children of the document. if (mRootContent) { nsCOMPtr node(do_QueryInterface(mRootContent)); if (node) { return node->Normalize(); } } return NS_OK; } NS_IMETHODIMP nsDocument::IsSupported(const nsAString& aFeature, const nsAString& aVersion, PRBool* aReturn) { return nsGenericElement::InternalIsSupported(aFeature, aVersion, aReturn); } NS_IMETHODIMP nsDocument::GetBaseURI(nsAString &aURI) { aURI.Truncate(); if (mDocumentBaseURL) { nsCAutoString spec; mDocumentBaseURL->GetSpec(spec); aURI = NS_ConvertUTF8toUCS2(spec); } return NS_OK; } NS_IMETHODIMP nsDocument::CompareTreePosition(nsIDOMNode* aOther, PRUint16* aReturn) { NS_ENSURE_ARG_POINTER(aOther); PRUint16 mask = nsIDOMNode::TREE_POSITION_DISCONNECTED; PRBool sameNode = PR_FALSE; IsSameNode(aOther, &sameNode); if (sameNode) { mask |= (nsIDOMNode::TREE_POSITION_SAME_NODE | nsIDOMNode::TREE_POSITION_EQUIVALENT); } else { nsCOMPtr otherDoc; aOther->GetOwnerDocument(getter_AddRefs(otherDoc)); nsCOMPtr other(do_QueryInterface(otherDoc)); IsSameNode(other, &sameNode); if (sameNode) { mask |= (nsIDOMNode::TREE_POSITION_DESCENDANT | nsIDOMNode::TREE_POSITION_FOLLOWING); } } *aReturn = mask; return NS_OK; } NS_IMETHODIMP nsDocument::IsSameNode(nsIDOMNode* aOther, PRBool* aReturn) { PRBool sameNode = PR_FALSE; if (this == aOther) { sameNode = PR_TRUE; } *aReturn = sameNode; return NS_OK; } NS_IMETHODIMP nsDocument::LookupNamespacePrefix(const nsAString& aNamespaceURI, nsAString& aPrefix) { aPrefix.Truncate(); return NS_OK; } NS_IMETHODIMP nsDocument::LookupNamespaceURI(const nsAString& aNamespacePrefix, nsAString& aNamespaceURI) { aNamespaceURI.Truncate(); return NS_OK; } NS_IMETHODIMP nsDocument::GetOwnerDocument(nsIDOMDocument** aOwnerDocument) { *aOwnerDocument = nsnull; return NS_OK; } nsresult nsDocument::GetListenerManager(nsIEventListenerManager **aInstancePtrResult) { if (nsnull != mListenerManager) { return mListenerManager->QueryInterface(NS_GET_IID(nsIEventListenerManager), (void**) aInstancePtrResult); } if (NS_OK == NS_NewEventListenerManager(aInstancePtrResult)) { mListenerManager = *aInstancePtrResult; NS_ADDREF(mListenerManager); mListenerManager->SetListenerTarget(NS_STATIC_CAST(nsIDocument*,this)); return NS_OK; } return NS_ERROR_FAILURE; } nsresult nsDocument::HandleEvent(nsIDOMEvent *aEvent) { PRBool noDefault; return DispatchEvent(aEvent, &noDefault); } nsresult nsDocument::HandleDOMEvent(nsIPresContext* aPresContext, nsEvent* aEvent, nsIDOMEvent** aDOMEvent, PRUint32 aFlags, nsEventStatus* aEventStatus) { nsresult mRet = NS_OK; PRBool externalDOMEvent = PR_FALSE; nsIDOMEvent* domEvent = nsnull; if (NS_EVENT_FLAG_INIT & aFlags) { if (aDOMEvent) { if (*aDOMEvent) { externalDOMEvent = PR_TRUE; } } else { aDOMEvent = &domEvent; } aEvent->flags = aFlags; aFlags &= ~(NS_EVENT_FLAG_CANT_BUBBLE | NS_EVENT_FLAG_CANT_CANCEL); } //Capturing stage if (NS_EVENT_FLAG_BUBBLE != aFlags && nsnull != mScriptGlobalObject) { mScriptGlobalObject->HandleDOMEvent(aPresContext, aEvent, aDOMEvent, NS_EVENT_FLAG_CAPTURE, aEventStatus); } //Local handling stage if (mListenerManager && !(aEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH) && !(NS_EVENT_FLAG_BUBBLE & aFlags && NS_EVENT_FLAG_CANT_BUBBLE & aEvent->flags)) { aEvent->flags |= aFlags; mListenerManager->HandleEvent(aPresContext, aEvent, aDOMEvent, this, aFlags, aEventStatus); aEvent->flags &= ~aFlags; } //Bubbling stage if (NS_EVENT_FLAG_CAPTURE != aFlags && nsnull != mScriptGlobalObject) { mScriptGlobalObject->HandleDOMEvent(aPresContext, aEvent, aDOMEvent, NS_EVENT_FLAG_BUBBLE, aEventStatus); } if (NS_EVENT_FLAG_INIT & aFlags) { // We're leaving the DOM event loop so if we created a DOM event, release here. if (*aDOMEvent && !externalDOMEvent) { nsrefcnt rc; NS_RELEASE2(*aDOMEvent, rc); if (0 != rc) { //Okay, so someone in the DOM loop (a listener, JS object) still has a ref to the DOM Event but //the internal data hasn't been malloc'd. Force a copy of the data here so the DOM Event is still valid. nsIPrivateDOMEvent *mPrivateEvent; if (NS_OK == (*aDOMEvent)->QueryInterface(NS_GET_IID(nsIPrivateDOMEvent), (void**)&mPrivateEvent)) { mPrivateEvent->DuplicatePrivateData(); NS_RELEASE(mPrivateEvent); } } aDOMEvent = nsnull; } } return mRet; } NS_IMETHODIMP_(PRBool) nsDocument::EventCaptureRegistration(PRInt32 aCapturerIncrement) { mNumCapturers += aCapturerIncrement; NS_WARN_IF_FALSE(mNumCapturers >= 0, "Number of capturers has become negative"); return (mNumCapturers > 0 ? PR_TRUE : PR_FALSE); } nsresult nsDocument::AddEventListenerByIID(nsIDOMEventListener *aListener, const nsIID& aIID) { nsCOMPtr manager; GetListenerManager(getter_AddRefs(manager)); if (manager) { manager->AddEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE); return NS_OK; } return NS_ERROR_FAILURE; } nsresult nsDocument::RemoveEventListenerByIID(nsIDOMEventListener *aListener, const nsIID& aIID) { if (nsnull != mListenerManager) { mListenerManager->RemoveEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE); return NS_OK; } return NS_ERROR_FAILURE; } nsresult nsDocument::AddEventListener(const nsAString& aType, nsIDOMEventListener* aListener, PRBool aUseCapture) { nsCOMPtr manager; GetListenerManager(getter_AddRefs(manager)); if (manager) { PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE; manager->AddEventListenerByType(aListener, aType, flags); return NS_OK; } return NS_ERROR_FAILURE; } nsresult nsDocument::RemoveEventListener(const nsAString& aType, nsIDOMEventListener* aListener, PRBool aUseCapture) { if (nsnull != mListenerManager) { PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE; mListenerManager->RemoveEventListenerByType(aListener, aType, flags); return NS_OK; } return NS_ERROR_FAILURE; } NS_IMETHODIMP nsDocument::DispatchEvent(nsIDOMEvent* aEvent, PRBool *_retval) { // Obtain a presentation context PRInt32 count = GetNumberOfShells(); if (count == 0) return NS_OK; nsCOMPtr shell; GetShellAt(0, getter_AddRefs(shell)); if (!shell) return NS_ERROR_FAILURE; // Retrieve the context nsCOMPtr presContext; shell->GetPresContext(getter_AddRefs(presContext)); nsCOMPtr esm; if (NS_SUCCEEDED(presContext->GetEventStateManager(getter_AddRefs(esm)))) { return esm->DispatchNewEvent(NS_STATIC_CAST(nsIDOMDocument *, this), aEvent, _retval); } return NS_ERROR_FAILURE; } NS_IMETHODIMP nsDocument::CreateEvent(const nsAString& aEventType, nsIDOMEvent** aReturn) { NS_ENSURE_ARG_POINTER(aReturn); *aReturn = nsnull; // Obtain a presentation context PRInt32 count = GetNumberOfShells(); if (count == 0) return NS_OK; nsCOMPtr shell; GetShellAt(0, getter_AddRefs(shell)); if (!shell) return NS_ERROR_FAILURE; // Retrieve the context nsCOMPtr presContext; shell->GetPresContext(getter_AddRefs(presContext)); if (presContext) { nsCOMPtr manager; GetListenerManager(getter_AddRefs(manager)); if (manager) { return manager->CreateEvent(presContext, nsnull, aEventType, aReturn); } } return NS_ERROR_FAILURE; } NS_IMETHODIMP nsDocument::FlushPendingNotifications(PRBool aFlushReflows, PRBool aUpdateViews) { if (aFlushReflows && mScriptGlobalObject) { // We should be able to replace all this nsIDocShell* code with // code that uses mParentDocument, but mParentDocument is never // set in the current code! nsCOMPtr docShell; mScriptGlobalObject->GetDocShell(getter_AddRefs(docShell)); nsCOMPtr docShellAsItem = do_QueryInterface(docShell); if (docShellAsItem) { nsCOMPtr docShellParent; docShellAsItem->GetSameTypeParent(getter_AddRefs(docShellParent)); nsCOMPtr win(do_GetInterface(docShellParent)); if (win) { nsCOMPtr dom_doc; win->GetDocument(getter_AddRefs(dom_doc)); nsCOMPtr doc(do_QueryInterface(dom_doc)); if (doc) { // If we have a parent we must flush the parent too to ensure // that our container is reflown if its size was changed. doc->FlushPendingNotifications(aFlushReflows, aUpdateViews); } } } PRInt32 i, count = mPresShells.Count(); for (i = 0; i < count; i++) { nsCOMPtr shell = NS_STATIC_CAST(nsIPresShell*, mPresShells[i]); if (shell) { shell->FlushPendingNotifications(aUpdateViews); } } } return NS_OK; } NS_IMETHODIMP nsDocument::GetAndIncrementContentID(PRInt32* aID) { *aID = mNextContentID++; return NS_OK; } NS_IMETHODIMP nsDocument::GetBindingManager(nsIBindingManager** aResult) { *aResult = mBindingManager; NS_IF_ADDREF(*aResult); return NS_OK; } NS_IMETHODIMP nsDocument::GetNodeInfoManager(nsINodeInfoManager*& aNodeInfoManager) { NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_NOT_INITIALIZED); aNodeInfoManager = mNodeInfoManager; NS_ADDREF(aNodeInfoManager); return NS_OK; } NS_IMETHODIMP nsDocument::AddReference(void *aKey, nsISupports *aReference) { nsVoidKey key(aKey); if (mScriptGlobalObject) { mContentWrapperHash.Put(&key, aReference); } return NS_OK; } NS_IMETHODIMP nsDocument::RemoveReference(void *aKey, nsISupports **aOldReference) { nsVoidKey key(aKey); mContentWrapperHash.Remove(&key, aOldReference); return NS_OK; } NS_IMETHODIMP nsDocument::SetContainer(nsISupports *aContainer) { mDocumentContainer = dont_AddRef(NS_GetWeakReference(aContainer)); return NS_OK; } NS_IMETHODIMP nsDocument::GetContainer(nsISupports **aContainer) { nsCOMPtr container = do_QueryReferent(mDocumentContainer); *aContainer = container; NS_IF_ADDREF(*aContainer); return NS_OK; } nsresult nsDocument::GetRadioGroup(const nsAString& aName, nsRadioGroupStruct **aRadioGroup) { nsStringKey key(aName); nsRadioGroupStruct* radioGroup = (nsRadioGroupStruct*)mRadioGroups.Get(&key); if (!radioGroup) { radioGroup = new nsRadioGroupStruct(); NS_ENSURE_TRUE(radioGroup, NS_ERROR_OUT_OF_MEMORY); mRadioGroups.Put(&key, radioGroup); } *aRadioGroup = radioGroup; return NS_OK; } NS_IMETHODIMP nsDocument::SetCurrentRadioButton(const nsAString& aName, nsIDOMHTMLInputElement* aRadio) { nsRadioGroupStruct* radioGroup = nsnull; GetRadioGroup(aName, &radioGroup); if (radioGroup) { radioGroup->mSelectedRadioButton = aRadio; } return NS_OK; } NS_IMETHODIMP nsDocument::GetCurrentRadioButton(const nsAString& aName, nsIDOMHTMLInputElement** aRadio) { nsRadioGroupStruct* radioGroup = nsnull; GetRadioGroup(aName, &radioGroup); if (radioGroup) { *aRadio = radioGroup->mSelectedRadioButton; NS_IF_ADDREF(*aRadio); } return NS_OK; } NS_IMETHODIMP nsDocument::AddToRadioGroup(const nsAString& aName, nsIFormControl* aRadio) { nsRadioGroupStruct* radioGroup = nsnull; GetRadioGroup(aName, &radioGroup); if (radioGroup) { radioGroup->mRadioButtons.AppendElement(aRadio); NS_IF_ADDREF(aRadio); } return NS_OK; } NS_IMETHODIMP nsDocument::RemoveFromRadioGroup(const nsAString& aName, nsIFormControl* aRadio) { nsRadioGroupStruct* radioGroup = nsnull; GetRadioGroup(aName, &radioGroup); if (radioGroup) { if (radioGroup->mRadioButtons.RemoveElement(aRadio)) { NS_IF_RELEASE(aRadio); } } return NS_OK; } NS_IMETHODIMP nsDocument::WalkRadioGroup(const nsAString& aName, nsIRadioVisitor* aVisitor) { nsresult rv = NS_OK; nsRadioGroupStruct* radioGroup = nsnull; GetRadioGroup(aName, &radioGroup); if (radioGroup) { PRBool stop = PR_FALSE; for (int i = 0; i < radioGroup->mRadioButtons.Count(); i++) { aVisitor->Visit(NS_STATIC_CAST(nsIFormControl *, radioGroup->mRadioButtons.ElementAt(i)), &stop); if (stop) { break; } } } return rv; } #ifdef IBMBIDI /** * Check if bidi enabled (set depending on the presence of RTL * characters). If enabled, we should apply the Unicode Bidi Algorithm * * @lina 07/12/2000 */ NS_IMETHODIMP nsDocument::GetBidiEnabled(PRBool* aBidiEnabled) const { NS_ENSURE_ARG_POINTER(aBidiEnabled); *aBidiEnabled = mBidiEnabled; return NS_OK; } /** * Indicate the document contains RTL characters. * * @lina 07/12/2000 */ NS_IMETHODIMP nsDocument::SetBidiEnabled(PRBool aBidiEnabled) { mBidiEnabled = aBidiEnabled; return NS_OK; } #endif // IBMBIDI