/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #include "plstr.h" #include "nsCOMPtr.h" #include "nsDocument.h" #include "nsIArena.h" #include "nsIURL.h" #include "nsIURLGroup.h" #include "nsString.h" #include "nsIContent.h" #include "nsIDocumentObserver.h" #include "nsIStyleSet.h" #include "nsIStyleSheet.h" #include "nsIPresShell.h" #include "nsIDocumentObserver.h" #include "nsEventListenerManager.h" #include "nsIScriptGlobalObject.h" #include "nsIScriptContextOwner.h" #include "nsIScriptEventListener.h" #include "nsDOMEvent.h" #include "nsDOMEventsIIDs.h" #include "nsIPrivateDOMEvent.h" #include "nsIEventStateManager.h" #include "nsContentList.h" #include "nsIDOMEventListener.h" #include "nsIDOMStyleSheet.h" #include "nsIDOMStyleSheetCollection.h" #include "nsDOMAttribute.h" #include "nsDOMCID.h" #include "nsIDOMScriptObjectFactory.h" #include "nsIDOMDOMImplementation.h" #include "nsGenericElement.h" #include "nsCSSPropIDs.h" #include "nsCSSProps.h" #include "nsICSSStyleSheet.h" #include "nsICSSStyleRule.h" #include "nsICSSDeclaration.h" #include "nsITextContent.h" #include "nsXIFConverter.h" #include "nsIDOMText.h" #include "nsIDOMComment.h" #include "nsINameSpaceManager.h" #include "nsIServiceManager.h" #include "nsLayoutCID.h" #include "nsIDOMSelection.h" #include "nsIDOMRange.h" #include "nsIEnumerator.h" static NS_DEFINE_IID(kIDOMTextIID, NS_IDOMTEXT_IID); static NS_DEFINE_IID(kIDOMCommentIID, NS_IDOMCOMMENT_IID); static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID); #include "nsIDOMElement.h" static NS_DEFINE_IID(kIDOMDocumentIID, NS_IDOMDOCUMENT_IID); static NS_DEFINE_IID(kIDOMNSDocumentIID, NS_IDOMNSDOCUMENT_IID); static NS_DEFINE_IID(kIDOMNodeListIID, NS_IDOMNODELIST_IID); static NS_DEFINE_IID(kIDOMAttrIID, NS_IDOMATTR_IID); static NS_DEFINE_IID(kIScriptEventListenerIID, NS_ISCRIPTEVENTLISTENER_IID); static NS_DEFINE_IID(kIDOMEventCapturerIID, NS_IDOMEVENTCAPTURER_IID); static NS_DEFINE_IID(kIPrivateDOMEventIID, NS_IPRIVATEDOMEVENT_IID); static NS_DEFINE_IID(kIEventListenerManagerIID, NS_IEVENTLISTENERMANAGER_IID); static NS_DEFINE_IID(kIPostDataIID, NS_IPOSTDATA_IID); static NS_DEFINE_IID(kIDOMStyleSheetCollectionIID, NS_IDOMSTYLESHEETCOLLECTION_IID); static NS_DEFINE_IID(kIDOMStyleSheetIID, NS_IDOMSTYLESHEET_IID); static NS_DEFINE_IID(kIDOMDOMImplementationIID, NS_IDOMDOMIMPLEMENTATION_IID); static NS_DEFINE_IID(kIDocumentObserverIID, NS_IDOCUMENT_OBSERVER_IID); static NS_DEFINE_IID(kICSSStyleSheetIID, NS_ICSS_STYLE_SHEET_IID); static NS_DEFINE_IID(kCRangeCID, NS_RANGE_CID); static NS_DEFINE_IID(kIDOMRange, NS_IDOMRANGE_IID); static NS_DEFINE_IID(kCRangeListCID, NS_RANGELIST_CID); static NS_DEFINE_IID(kIEnumeratorIID, NS_IENUMERATOR_IID); static NS_DEFINE_IID(kIDOMScriptObjectFactoryIID, NS_IDOM_SCRIPT_OBJECT_FACTORY_IID); static NS_DEFINE_IID(kDOMScriptObjectFactoryCID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID); #include "nsILineBreakerFactory.h" #include "nsIWordBreakerFactory.h" #include "nsLWBrkCIID.h" static NS_DEFINE_IID(kLWBrkCID, NS_LWBRK_CID); static NS_DEFINE_IID(kILineBreakerFactoryIID, NS_ILINEBREAKERFACTORY_IID); static NS_DEFINE_IID(kIWordBreakerFactoryIID, NS_IWORDBREAKERFACTORY_IID); class nsDOMStyleSheetCollection : public nsIDOMStyleSheetCollection, public nsIScriptObjectOwner, public nsIDocumentObserver { public: nsDOMStyleSheetCollection(nsIDocument *aDocument); virtual ~nsDOMStyleSheetCollection(); NS_DECL_ISUPPORTS NS_DECL_IDOMSTYLESHEETCOLLECTION NS_IMETHOD BeginUpdate(nsIDocument *aDocument) { return NS_OK; } NS_IMETHOD EndUpdate(nsIDocument *aDocument) { return NS_OK; } NS_IMETHOD BeginLoad(nsIDocument *aDocument) { return NS_OK; } NS_IMETHOD EndLoad(nsIDocument *aDocument) { return NS_OK; } NS_IMETHOD BeginReflow(nsIDocument *aDocument, nsIPresShell* aShell) { return NS_OK; } NS_IMETHOD EndReflow(nsIDocument *aDocument, nsIPresShell* aShell) { return NS_OK; } NS_IMETHOD ContentChanged(nsIDocument *aDocument, nsIContent* aContent, nsISupports* aSubContent) { return NS_OK; } NS_IMETHOD ContentStateChanged(nsIDocument* aDocument, nsIContent* aContent) { return NS_OK; } NS_IMETHOD AttributeChanged(nsIDocument *aDocument, nsIContent* aContent, nsIAtom* aAttribute, PRInt32 aHint) { return NS_OK; } NS_IMETHOD ContentAppended(nsIDocument *aDocument, nsIContent* aContainer, PRInt32 aNewIndexInContainer) { return NS_OK; } NS_IMETHOD ContentInserted(nsIDocument *aDocument, nsIContent* aContainer, nsIContent* aChild, PRInt32 aIndexInContainer) { return NS_OK; } NS_IMETHOD ContentReplaced(nsIDocument *aDocument, nsIContent* aContainer, nsIContent* aOldChild, nsIContent* aNewChild, PRInt32 aIndexInContainer) { return NS_OK; } NS_IMETHOD ContentRemoved(nsIDocument *aDocument, nsIContent* aContainer, nsIContent* aChild, PRInt32 aIndexInContainer) { return NS_OK; } NS_IMETHOD StyleSheetAdded(nsIDocument *aDocument, nsIStyleSheet* aStyleSheet); NS_IMETHOD StyleSheetRemoved(nsIDocument *aDocument, nsIStyleSheet* aStyleSheet); NS_IMETHOD StyleSheetDisabledStateChanged(nsIDocument *aDocument, nsIStyleSheet* aStyleSheet, PRBool aDisabled) { return NS_OK; } NS_IMETHOD StyleRuleChanged(nsIDocument *aDocument, nsIStyleSheet* aStyleSheet, nsIStyleRule* aStyleRule, PRInt32 aHint) { return NS_OK; } NS_IMETHOD StyleRuleAdded(nsIDocument *aDocument, nsIStyleSheet* aStyleSheet, nsIStyleRule* aStyleRule) { return NS_OK; } NS_IMETHOD StyleRuleRemoved(nsIDocument *aDocument, nsIStyleSheet* aStyleSheet, nsIStyleRule* aStyleRule) { return NS_OK; } NS_IMETHOD DocumentWillBeDestroyed(nsIDocument *aDocument); // nsIScriptObjectOwner interface NS_IMETHOD GetScriptObject(nsIScriptContext *aContext, void** aScriptObject); NS_IMETHOD SetScriptObject(void* aScriptObject); protected: PRInt32 mLength; nsIDocument* mDocument; void* mScriptObject; }; nsDOMStyleSheetCollection::nsDOMStyleSheetCollection(nsIDocument *aDocument) { NS_INIT_REFCNT(); mLength = -1; // Not reference counted to avoid circular references. // The document will tell us when its going away. mDocument = aDocument; mDocument->AddObserver(this); mScriptObject = nsnull; } nsDOMStyleSheetCollection::~nsDOMStyleSheetCollection() { if (nsnull != mDocument) { mDocument->RemoveObserver(this); } mDocument = nsnull; } NS_IMPL_ADDREF(nsDOMStyleSheetCollection) NS_IMPL_RELEASE(nsDOMStyleSheetCollection) nsresult nsDOMStyleSheetCollection::QueryInterface(REFNSIID aIID, void** aInstancePtrResult) { if (NULL == aInstancePtrResult) { return NS_ERROR_NULL_POINTER; } static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); if (aIID.Equals(kIDOMStyleSheetCollectionIID)) { nsIDOMStyleSheetCollection *tmp = this; *aInstancePtrResult = (void*) tmp; AddRef(); return NS_OK; } if (aIID.Equals(kIScriptObjectOwnerIID)) { nsIScriptObjectOwner *tmp = this; *aInstancePtrResult = (void*) tmp; AddRef(); return NS_OK; } if (aIID.Equals(kIDocumentObserverIID)) { nsIDocumentObserver *tmp = this; *aInstancePtrResult = (void*) tmp; AddRef(); return NS_OK; } if (aIID.Equals(kISupportsIID)) { nsIDOMStyleSheetCollection *tmp = this; nsISupports *tmp2 = tmp; *aInstancePtrResult = (void*) tmp2; AddRef(); return NS_OK; } return NS_NOINTERFACE; } NS_IMETHODIMP nsDOMStyleSheetCollection::GetLength(PRUint32* aLength) { if (nsnull != 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 = mDocument->GetNumberOfStyleSheets(); for (i = 0; i < imax; i++) { nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(i); nsIDOMStyleSheet *domss; if (NS_OK == sheet->QueryInterface(kIDOMStyleSheetIID, (void **)&domss)) { count++; NS_RELEASE(domss); } NS_RELEASE(sheet); } mLength = count; } *aLength = mLength; } else { *aLength = 0; } return NS_OK; } NS_IMETHODIMP nsDOMStyleSheetCollection::Item(PRUint32 aIndex, nsIDOMStyleSheet** aReturn) { *aReturn = nsnull; if (nsnull != mDocument) { PRUint32 count = 0; PRInt32 i, imax = mDocument->GetNumberOfStyleSheets(); // XXX Not particularly efficient, but does anyone care? for (i = 0; (i < imax) && (nsnull == *aReturn); i++) { nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(i); nsIDOMStyleSheet *domss; if (NS_OK == sheet->QueryInterface(kIDOMStyleSheetIID, (void **)&domss)) { if (count++ == aIndex) { *aReturn = domss; NS_ADDREF(domss); } NS_RELEASE(domss); } NS_RELEASE(sheet); } } return NS_OK; } NS_IMETHODIMP nsDOMStyleSheetCollection::GetScriptObject(nsIScriptContext *aContext, void** aScriptObject) { nsresult res = NS_OK; if (nsnull == mScriptObject) { nsISupports *supports = (nsISupports *)(nsIDOMStyleSheetCollection *)this; nsISupports *parent = (nsISupports *)mDocument; // XXX Should be done through factory res = NS_NewScriptStyleSheetCollection(aContext, supports, parent, (void**)&mScriptObject); } *aScriptObject = mScriptObject; return res; } NS_IMETHODIMP nsDOMStyleSheetCollection::SetScriptObject(void* aScriptObject) { mScriptObject = aScriptObject; return NS_OK; } NS_IMETHODIMP nsDOMStyleSheetCollection::StyleSheetAdded(nsIDocument *aDocument, nsIStyleSheet* aStyleSheet) { if (-1 != mLength) { nsIDOMStyleSheet *domss; if (NS_OK == aStyleSheet->QueryInterface(kIDOMStyleSheetIID, (void **)&domss)) { mLength++; NS_RELEASE(domss); } } return NS_OK; } NS_IMETHODIMP nsDOMStyleSheetCollection::StyleSheetRemoved(nsIDocument *aDocument, nsIStyleSheet* aStyleSheet) { if (-1 != mLength) { nsIDOMStyleSheet *domss; if (NS_OK == aStyleSheet->QueryInterface(kIDOMStyleSheetIID, (void **)&domss)) { mLength--; NS_RELEASE(domss); } } return NS_OK; } NS_IMETHODIMP nsDOMStyleSheetCollection::DocumentWillBeDestroyed(nsIDocument *aDocument) { if (nsnull != mDocument) { aDocument->RemoveObserver(this); mDocument = nsnull; } return NS_OK; } // ================================================================== // = // ================================================================== class nsDOMImplementation : public nsIDOMDOMImplementation, public nsIScriptObjectOwner { public: nsDOMImplementation(); virtual ~nsDOMImplementation(); NS_DECL_ISUPPORTS NS_IMETHOD HasFeature(const nsString& aFeature, const nsString& aVersion, PRBool* aReturn); NS_IMETHOD GetScriptObject(nsIScriptContext *aContext, void** aScriptObject); NS_IMETHOD SetScriptObject(void *aScriptObject); protected: void *mScriptObject; }; nsDOMImplementation::nsDOMImplementation() { NS_INIT_REFCNT(); mScriptObject = nsnull; } nsDOMImplementation::~nsDOMImplementation() { } NS_IMPL_ADDREF(nsDOMImplementation) NS_IMPL_RELEASE(nsDOMImplementation) nsresult nsDOMImplementation::QueryInterface(REFNSIID aIID, void** aInstancePtr) { static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); if (nsnull == aInstancePtr) { return NS_ERROR_NULL_POINTER; } if (aIID.Equals(kIDOMDOMImplementationIID)) { nsIDOMDOMImplementation* tmp = this; *aInstancePtr = (void*) tmp; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIScriptObjectOwnerIID)) { nsIScriptObjectOwner* tmp = this; *aInstancePtr = (void*) tmp; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kISupportsIID)) { nsIDOMDOMImplementation* tmp = this; nsISupports* tmp2 = tmp; *aInstancePtr = (void*) tmp2; NS_ADDREF_THIS(); return NS_OK; } return NS_NOINTERFACE; } NS_IMETHODIMP nsDOMImplementation::HasFeature(const nsString& aFeature, const nsString& aVersion, PRBool* aReturn) { // XXX Currently this is hardcoded. In the future, we should // probably figure out some of this by querying the registry?? if (aFeature.EqualsIgnoreCase("HTML") || aFeature.EqualsIgnoreCase("XML")) { *aReturn = PR_TRUE; } else { *aReturn = PR_FALSE; } return NS_OK; } NS_IMETHODIMP nsDOMImplementation::GetScriptObject(nsIScriptContext *aContext, void** aScriptObject) { nsresult result = NS_OK; if (nsnull == mScriptObject) { nsIDOMScriptObjectFactory *factory; result = nsServiceManager::GetService(kDOMScriptObjectFactoryCID, kIDOMScriptObjectFactoryIID, (nsISupports **)&factory); if (NS_OK == result) { nsIScriptGlobalObject *global = aContext->GetGlobalObject(); result = factory->NewScriptDOMImplementation(aContext, (nsISupports*)(nsIDOMDOMImplementation*)this, global, &mScriptObject); NS_RELEASE(global); NS_RELEASE(factory); } } *aScriptObject = mScriptObject; return result; } NS_IMETHODIMP nsDOMImplementation::SetScriptObject(void *aScriptObject) { mScriptObject = nsnull; return NS_OK; } // ================================================================== // = // ================================================================== NS_LAYOUT nsresult NS_NewPostData(PRBool aIsFile, char* aData, nsIPostData** aInstancePtrResult) { nsresult rv = NS_OK; if (nsnull == aInstancePtrResult) { return NS_ERROR_NULL_POINTER; } *aInstancePtrResult = new nsPostData(aIsFile, aData); if (nsnull != *aInstancePtrResult) { NS_ADDREF(*aInstancePtrResult); } else { rv = NS_ERROR_OUT_OF_MEMORY; } return rv; } nsPostData::nsPostData(PRBool aIsFile, char* aData) { NS_INIT_REFCNT(); mData = nsnull; mDataLen = 0; mIsFile = aIsFile; if (aData) { mDataLen = PL_strlen(aData); mData = aData; } } nsPostData::~nsPostData() { if (nsnull != mData) { delete [] mData; mData = nsnull; } } /* * Implementation of ISupports methods... */ NS_IMPL_ISUPPORTS(nsPostData,kIPostDataIID); PRBool nsPostData::IsFile() { return mIsFile; } const char* nsPostData::GetData() { return mData; } PRInt32 nsPostData::GetDataLength() { return mDataLen; } // ================================================================== // = // ================================================================== nsDocumentChildNodes::nsDocumentChildNodes(nsIDocument* aDocument) { // 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() { } 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; nsIContent* content = nsnull; *aReturn = nsnull; if (nsnull != mDocument) { result = mDocument->ChildAt(aIndex, content); if ((NS_OK == result) && (nsnull != content)) { result = content->QueryInterface(kIDOMNodeIID, (void**)aReturn); } } return result; } void nsDocumentChildNodes::DropReference() { mDocument = nsnull; } // ================================================================== // = // ================================================================== nsDocument::nsDocument() { NS_INIT_REFCNT(); mArena = nsnull; mDocumentTitle = nsnull; mDocumentURL = nsnull; mDocumentURLGroup = nsnull; mCharacterSet = nsnull; mParentDocument = nsnull; mRootContent = nsnull; mScriptObject = nsnull; mScriptContextOwner = nsnull; mListenerManager = nsnull; mDisplaySelection = PR_FALSE; mInDestructor = PR_FALSE; mDOMStyleSheets = nsnull; mNameSpaceManager = nsnull; mHeaderData = nsnull; mLineBreaker = nsnull; mProlog = nsnull; mEpilog = nsnull; mChildNodes = nsnull; mWordBreaker = nsnull; Init();/* XXX */ } nsDocument::~nsDocument() { // 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 index, count; for (index = 0; index < mObservers.Count(); index++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers.ElementAt(index); observer->DocumentWillBeDestroyed(this); } if (nsnull != mDocumentTitle) { delete mDocumentTitle; mDocumentTitle = nsnull; } NS_IF_RELEASE(mDocumentURL); NS_IF_RELEASE(mDocumentURLGroup); mParentDocument = nsnull; // Delete references to sub-documents index = mSubDocuments.Count(); while (--index >= 0) { nsIDocument* subdoc = (nsIDocument*) mSubDocuments.ElementAt(index); NS_RELEASE(subdoc); } NS_IF_RELEASE(mRootContent); // Delete references to style sheets index = mStyleSheets.Count(); while (--index >= 0) { nsIStyleSheet* sheet = (nsIStyleSheet*) mStyleSheets.ElementAt(index); sheet->SetOwningDocument(nsnull); NS_RELEASE(sheet); } nsIContent* content; if (nsnull != mProlog) { count = mProlog->Count(); for (index = 0; index < count; index++) { content = (nsIContent*)mProlog->ElementAt(index); NS_RELEASE(content); } delete mProlog; } if (nsnull != mEpilog) { count = mEpilog->Count(); for (index = 0; index < count; index++) { content = (nsIContent*)mEpilog->ElementAt(index); NS_RELEASE(content); } delete mEpilog; } if (nsnull != mChildNodes) { mChildNodes->DropReference(); NS_RELEASE(mChildNodes); } NS_IF_RELEASE(mArena); NS_IF_RELEASE(mScriptContextOwner); NS_IF_RELEASE(mListenerManager); NS_IF_RELEASE(mDOMStyleSheets); NS_IF_RELEASE(mNameSpaceManager); if (nsnull != mHeaderData) { delete mHeaderData; mHeaderData = nsnull; } NS_IF_RELEASE(mLineBreaker); NS_IF_RELEASE(mWordBreaker); } nsresult nsDocument::QueryInterface(REFNSIID aIID, void** aInstancePtr) { if (nsnull == aInstancePtr) { return NS_ERROR_NULL_POINTER; } if (aIID.Equals(kIDocumentIID)) { nsIDocument* tmp = this; *aInstancePtr = (void*) tmp; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIDOMDocumentIID)) { nsIDOMDocument* tmp = this; *aInstancePtr = (void*) tmp; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIDOMNSDocumentIID)) { nsIDOMNSDocument* tmp = this; *aInstancePtr = (void*) tmp; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIScriptObjectOwnerIID)) { nsIScriptObjectOwner* tmp = this; *aInstancePtr = (void*) tmp; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIJSScriptObjectIID)) { nsIJSScriptObject* tmp = this; *aInstancePtr = (void*) tmp; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIDOMEventCapturerIID)) { nsIDOMEventCapturer* tmp = this; *aInstancePtr = (void*) tmp; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIDOMEventReceiverIID)) { nsIDOMEventReceiver* tmp = this; *aInstancePtr = (void*) tmp; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIDOMEventTargetIID)) { nsIDOMEventTarget* tmp = this; *aInstancePtr = (void*) tmp; NS_ADDREF_THIS(); return NS_OK; } if (aIID.Equals(kIDOMNodeIID)) { nsIDOMNode* tmp = this; *aInstancePtr = (void*) tmp; NS_ADDREF_THIS(); return NS_OK; } static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); if (aIID.Equals(kISupportsIID)) { nsIDocument* tmp = this; nsISupports* tmp2 = tmp; *aInstancePtr = (void*) tmp2; NS_ADDREF_THIS(); return NS_OK; } return NS_NOINTERFACE; } NS_IMPL_ADDREF(nsDocument) NS_IMPL_RELEASE(nsDocument) nsresult nsDocument::Init() { nsresult rv = NS_NewHeapArena(&mArena, nsnull); return rv; } nsIArena* nsDocument::GetArena() { if (nsnull != mArena) { NS_ADDREF(mArena); } return mArena; } nsresult nsDocument::Reset(nsIURL *aURL) { nsresult rv = NS_OK; if (nsnull != mDocumentTitle) { delete mDocumentTitle; mDocumentTitle = nsnull; } NS_IF_RELEASE(mDocumentURL); NS_IF_RELEASE(mDocumentURLGroup); // Delete references to sub-documents PRInt32 index = mSubDocuments.Count(); while (--index >= 0) { nsIDocument* subdoc = (nsIDocument*) mSubDocuments.ElementAt(index); NS_RELEASE(subdoc); } if (nsnull != mRootContent) { // Ensure that document is nsnull to allow validity checks on content mRootContent->SetDocument(nsnull, PR_TRUE); ContentRemoved(nsnull, mRootContent, 0); NS_IF_RELEASE(mRootContent); } // Delete references to style sheets index = mStyleSheets.Count(); while (--index >= 0) { nsIStyleSheet* sheet = (nsIStyleSheet*) mStyleSheets.ElementAt(index); sheet->SetOwningDocument(nsnull); PRInt32 pscount = mPresShells.Count(); PRInt32 psindex; for (psindex = 0; psindex < pscount; psindex++) { nsIPresShell* 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(mDOMStyleSheets); NS_IF_RELEASE(mNameSpaceManager); mDocumentURL = aURL; if (nsnull != aURL) { NS_ADDREF(aURL); rv = aURL->GetURLGroup(&mDocumentURLGroup); } if (NS_OK == rv) { rv = NS_NewNameSpaceManager(&mNameSpaceManager); } return rv; } nsresult nsDocument::StartDocumentLoad(nsIURL *aURL, nsIContentViewerContainer* aContainer, nsIStreamListener **aDocListener, const char* aCommand) { return Reset(aURL); } const nsString* nsDocument::GetDocumentTitle() const { return mDocumentTitle; } nsIURL* nsDocument::GetDocumentURL() const { NS_IF_ADDREF(mDocumentURL); return mDocumentURL; } nsIURLGroup* nsDocument::GetDocumentURLGroup() const { NS_IF_ADDREF(mDocumentURLGroup); return mDocumentURLGroup; } NS_IMETHODIMP nsDocument::GetBaseURL(nsIURL*& aURL) const { aURL = mDocumentURL; NS_IF_ADDREF(mDocumentURL); return NS_OK; } nsString* nsDocument::GetDocumentCharacterSet() const { return mCharacterSet; } void nsDocument::SetDocumentCharacterSet(nsString* aCharSetID) { mCharacterSet = aCharSetID; } NS_IMETHODIMP nsDocument::GetLineBreaker(nsILineBreaker** aResult) { if(nsnull == mLineBreaker ) { // no line breaker, find a default one nsILineBreakerFactory *lf; nsresult result; result = nsServiceManager::GetService(kLWBrkCID, kILineBreakerFactoryIID, (nsISupports **)&lf); if (NS_SUCCEEDED(result)) { nsILineBreaker *lb = nsnull ; nsAutoString lbarg(""); result = lf->GetBreaker(lbarg, &lb); if(NS_SUCCEEDED(result)) { mLineBreaker = lb; } result = nsServiceManager::ReleaseService(kLWBrkCID, lf); } } *aResult = mLineBreaker; NS_IF_ADDREF(mLineBreaker); return NS_OK; // XXX we should do error handling here } NS_IMETHODIMP nsDocument::SetLineBreaker(nsILineBreaker* aLineBreaker) { NS_IF_RELEASE(mLineBreaker); mLineBreaker = aLineBreaker; NS_IF_ADDREF(mLineBreaker); return NS_OK; } NS_IMETHODIMP nsDocument::GetWordBreaker(nsIWordBreaker** aResult) { if(nsnull == mWordBreaker ) { // no line breaker, find a default one nsIWordBreakerFactory *lf; nsresult result; result = nsServiceManager::GetService(kLWBrkCID, kIWordBreakerFactoryIID, (nsISupports **)&lf); if (NS_SUCCEEDED(result)) { nsIWordBreaker *lb = nsnull ; nsAutoString lbarg(""); result = lf->GetBreaker(lbarg, &lb); if(NS_SUCCEEDED(result)) { mWordBreaker = lb; } result = nsServiceManager::ReleaseService(kLWBrkCID, lf); } } *aResult = mWordBreaker; NS_IF_ADDREF(mWordBreaker); return NS_OK; // XXX we should do error handling here } NS_IMETHODIMP nsDocument::SetWordBreaker(nsIWordBreaker* aWordBreaker) { NS_IF_RELEASE(mWordBreaker); mWordBreaker = aWordBreaker; NS_IF_ADDREF(mWordBreaker); return NS_OK; } NS_IMETHODIMP nsDocument::GetHeaderData(nsIAtom* aHeaderField, nsString& 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 nsString& aData) { if (nsnull != aHeaderField) { if (nsnull == mHeaderData) { if (0 < aData.Length()) { // don't bother storing empty string mHeaderData = new nsDocHeaderData(aHeaderField, aData); } } else { nsDocHeaderData* data = mHeaderData; nsDocHeaderData** lastPtr = &mHeaderData; do { // look for existing and replace if (data->mField == aHeaderField) { if (0 < aData.Length()) { data->mData = aData; } else { // don't store empty string (*lastPtr)->mNext = data->mNext; data->mNext = nsnull; delete data; } return NS_OK; } lastPtr = &(data->mNext); data = data->mNext; } while (nsnull != data); // didn't find, append if (0 < aData.Length()) { *lastPtr = new nsDocHeaderData(aHeaderField, aData); } } return NS_OK; } return NS_ERROR_NULL_POINTER; } #if 0 // XXX Temp hack: moved to nsMarkupDocument nsresult nsDocument::CreateShell(nsIPresContext* aContext, nsIViewManager* aViewManager, nsIStyleSet* aStyleSet, nsIPresShell** aInstancePtrResult) { NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); if (nsnull == aInstancePtrResult) { return NS_ERROR_NULL_POINTER; } nsIPresShell* shell; nsresult rv = NS_NewPresShell(&shell); if (NS_OK != rv) { return rv; } if (NS_OK != shell->Init(this, aContext, aViewManager, aStyleSet)) { NS_RELEASE(shell); return rv; } // Note: we don't hold a ref to the shell (it holds a ref to us) mPresShells.AppendElement(shell); *aInstancePtrResult = shell; return NS_OK; } #endif PRBool nsDocument::DeleteShell(nsIPresShell* aShell) { return mPresShells.RemoveElement(aShell); } PRInt32 nsDocument::GetNumberOfShells() { return mPresShells.Count(); } nsIPresShell* nsDocument::GetShellAt(PRInt32 aIndex) { nsIPresShell* shell = (nsIPresShell*) mPresShells.ElementAt(aIndex); if (nsnull != shell) { NS_ADDREF(shell); } return shell; } nsIDocument* nsDocument::GetParentDocument() { if (nsnull != mParentDocument) { NS_ADDREF(mParentDocument); } return mParentDocument; } /** * Note that we do *not* AddRef our parent because that would * create a circular reference. */ void nsDocument::SetParentDocument(nsIDocument* aParent) { mParentDocument = aParent; } void nsDocument::AddSubDocument(nsIDocument* aSubDoc) { NS_ADDREF(aSubDoc); mSubDocuments.AppendElement(aSubDoc); } PRInt32 nsDocument::GetNumberOfSubDocuments() { return mSubDocuments.Count(); } nsIDocument* nsDocument::GetSubDocumentAt(PRInt32 aIndex) { nsIDocument* doc = (nsIDocument*) mSubDocuments.ElementAt(aIndex); if (nsnull != doc) { NS_ADDREF(doc); } return doc; } nsIContent* nsDocument::GetRootContent() { if (nsnull != mRootContent) { NS_ADDREF(mRootContent); } return mRootContent; } void nsDocument::SetRootContent(nsIContent* aRoot) { NS_IF_RELEASE(mRootContent); if (nsnull != aRoot) { mRootContent = aRoot; NS_ADDREF(aRoot); } } NS_IMETHODIMP nsDocument::AppendToProlog(nsIContent* aContent) { if (nsnull == mProlog) { mProlog = new nsVoidArray(); } mProlog->AppendElement((void *)aContent); NS_ADDREF(aContent); return NS_OK; } NS_IMETHODIMP nsDocument::AppendToEpilog(nsIContent* aContent) { if (nsnull == mEpilog) { mEpilog = new nsVoidArray(); } mEpilog->AppendElement((void *)aContent); NS_ADDREF(aContent); return NS_OK; } NS_IMETHODIMP nsDocument::ChildAt(PRInt32 aIndex, nsIContent*& aResult) const { nsIContent* content = nsnull; PRInt32 prolog = 0; if (nsnull != mProlog) { prolog = mProlog->Count(); if (aIndex < prolog) { // It's in the prolog content = (nsIContent*)mProlog->ElementAt(aIndex); } } if (aIndex == prolog) { // It's the document element content = mRootContent; } else if ((aIndex > prolog) && (nsnull != mEpilog)) { // It's in the epilog content = (nsIContent*)mEpilog->ElementAt(aIndex-prolog-1); } NS_IF_ADDREF(content); aResult = content; return NS_OK; } NS_IMETHODIMP nsDocument::IndexOf(nsIContent* aPossibleChild, PRInt32& aIndex) const { PRInt32 index = -1; PRInt32 prolog = 0; if (nsnull != mProlog) { index = mProlog->IndexOf(aPossibleChild); prolog = mProlog->Count(); } if (-1 == index) { if (aPossibleChild == mRootContent) { index = prolog; } else if (nsnull != mEpilog) { index = mEpilog->IndexOf(aPossibleChild); if (-1 != index) { index += (prolog+1); } } } aIndex = index; return NS_OK; } NS_IMETHODIMP nsDocument::GetChildCount(PRInt32& aCount) { aCount = 1; if (nsnull != mProlog) { aCount += mProlog->Count(); } if (nsnull != mEpilog) { aCount += mEpilog->Count(); } return NS_OK; } PRInt32 nsDocument::GetNumberOfStyleSheets() { return mStyleSheets.Count(); } nsIStyleSheet* nsDocument::GetStyleSheetAt(PRInt32 aIndex) { nsIStyleSheet* sheet = (nsIStyleSheet*)mStyleSheets.ElementAt(aIndex); NS_IF_ADDREF(sheet); return sheet; } PRInt32 nsDocument::GetIndexOfStyleSheet(nsIStyleSheet* aSheet) { return mStyleSheets.IndexOf(aSheet); } void nsDocument::InternalAddStyleSheet(nsIStyleSheet* aSheet) // subclass hook for sheet ordering { mStyleSheets.AppendElement(aSheet); } void nsDocument::AddStyleSheet(nsIStyleSheet* aSheet) { NS_PRECONDITION(nsnull != aSheet, "null arg"); InternalAddStyleSheet(aSheet); NS_ADDREF(aSheet); aSheet->SetOwningDocument(this); PRBool enabled = PR_TRUE; aSheet->GetEnabled(enabled); if (enabled) { PRInt32 count = mPresShells.Count(); PRInt32 index; for (index = 0; index < count; index++) { nsIPresShell* shell = (nsIPresShell*)mPresShells.ElementAt(index); nsCOMPtr set; if (NS_SUCCEEDED(shell->GetStyleSet(getter_AddRefs(set)))) { if (set) { set->AddDocStyleSheet(aSheet, this); } } } // XXX should observers be notified for disabled sheets??? I think not, but I could be wrong for (index = 0; index < mObservers.Count(); index++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers.ElementAt(index); observer->StyleSheetAdded(this, aSheet); } } } void nsDocument::SetStyleSheetDisabledState(nsIStyleSheet* aSheet, PRBool aDisabled) { NS_PRECONDITION(nsnull != aSheet, "null arg"); PRInt32 index = mStyleSheets.IndexOf((void *)aSheet); PRInt32 count; // If we're actually in the document style sheet list if (-1 != index) { count = mPresShells.Count(); for (index = 0; index < count; index++) { nsIPresShell* shell = (nsIPresShell*)mPresShells.ElementAt(index); nsCOMPtr set; if (NS_SUCCEEDED(shell->GetStyleSet(getter_AddRefs(set)))) { if (set) { if (aDisabled) { set->RemoveDocStyleSheet(aSheet); } else { set->AddDocStyleSheet(aSheet, this); } } } } } for (index = 0; index < mObservers.Count(); index++) { nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers.ElementAt(index); observer->StyleSheetDisabledStateChanged(this, aSheet, aDisabled); } } nsIScriptContextOwner *nsDocument::GetScriptContextOwner() { if (nsnull != mScriptContextOwner) { NS_ADDREF(mScriptContextOwner); } return mScriptContextOwner; } void nsDocument::SetScriptContextOwner(nsIScriptContextOwner *aScriptContextOwner) { // 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 ((nsnull == aScriptContextOwner) && (nsnull != mRootContent)) { mRootContent->SetDocument(nsnull, PR_TRUE); } if (nsnull != mScriptContextOwner) { NS_RELEASE(mScriptContextOwner); } mScriptContextOwner = aScriptContextOwner; if (nsnull != mScriptContextOwner) { NS_ADDREF(mScriptContextOwner); } } NS_IMETHODIMP nsDocument::GetNameSpaceManager(nsINameSpaceManager*& aManager) { aManager = mNameSpaceManager; NS_IF_ADDREF(aManager); 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::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 (observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } 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 (observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } NS_IMETHODIMP nsDocument::ContentChanged(nsIContent* aContent, nsISupports* aSubContent) { 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 (observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } NS_IMETHODIMP nsDocument::ContentStateChanged(nsIContent* aContent) { 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->ContentStateChanged(this, aContent); // Make sure that the observer didn't remove itself during the // notification. If it did, update our index and count. if (observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } NS_IMETHODIMP nsDocument::ContentAppended(nsIContent* aContainer, PRInt32 aNewIndexInContainer) { 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 (observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } NS_IMETHODIMP nsDocument::ContentInserted(nsIContent* aContainer, nsIContent* aChild, PRInt32 aIndexInContainer) { 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 (observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } NS_IMETHODIMP nsDocument::ContentReplaced(nsIContent* aContainer, nsIContent* aOldChild, nsIContent* aNewChild, PRInt32 aIndexInContainer) { 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 (observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } NS_IMETHODIMP nsDocument::ContentRemoved(nsIContent* aContainer, nsIContent* aChild, PRInt32 aIndexInContainer) { 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 (observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } NS_IMETHODIMP nsDocument::AttributeChanged(nsIContent* aChild, nsIAtom* aAttribute, PRInt32 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->AttributeChanged(this, aChild, aAttribute, aHint); // Make sure that the observer didn't remove itself during the // notification. If it did, update our index and count. if (observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } NS_IMETHODIMP nsDocument::StyleRuleChanged(nsIStyleSheet* aStyleSheet, nsIStyleRule* aStyleRule, PRInt32 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->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 (observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } 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->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 (observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } 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->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 (observer != (nsIDocumentObserver*)mObservers[i]) { i--; } } return NS_OK; } nsresult nsDocument::GetScriptObject(nsIScriptContext *aContext, void** aScriptObject) { nsresult res = NS_OK; nsIScriptGlobalObject *global = aContext->GetGlobalObject(); if (nsnull == mScriptObject) { res = NS_NewScriptDocument(aContext, (nsISupports *)(nsIDOMDocument *)this, global, (void**)&mScriptObject); } *aScriptObject = mScriptObject; NS_RELEASE(global); return res; } nsresult nsDocument::SetScriptObject(void *aScriptObject) { mScriptObject = aScriptObject; return NS_OK; } // // nsIDOMDocument interface // NS_IMETHODIMP nsDocument::GetDoctype(nsIDOMDocumentType** aDoctype) { // Should be implemented by subclass return NS_ERROR_NOT_IMPLEMENTED; } 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(); if (nsnull == impl) { return NS_ERROR_OUT_OF_MEMORY; } return impl->QueryInterface(kIDOMDOMImplementationIID, (void**)aImplementation); } NS_IMETHODIMP nsDocument::GetDocumentElement(nsIDOMElement** aDocumentElement) { if (nsnull == aDocumentElement) { return NS_ERROR_NULL_POINTER; } nsresult res = NS_ERROR_FAILURE; if (nsnull != mRootContent) { res = mRootContent->QueryInterface(kIDOMElementIID, (void**)aDocumentElement); NS_ASSERTION(NS_OK == res, "Must be a DOM Element"); } return res; } NS_IMETHODIMP nsDocument::CreateElement(const nsString& aTagName, nsIDOMElement** aReturn) { // Should be implemented by subclass return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsDocument::CreateTextNode(const nsString& aData, nsIDOMText** aReturn) { nsIContent* text = nsnull; nsresult rv = NS_NewTextNode(&text); if (NS_OK == rv) { rv = text->QueryInterface(kIDOMTextIID, (void**)aReturn); (*aReturn)->AppendData(aData); NS_RELEASE(text); } return rv; } NS_IMETHODIMP nsDocument::CreateDocumentFragment(nsIDOMDocumentFragment** aReturn) { return NS_NewDocumentFragment(aReturn, this); } NS_IMETHODIMP nsDocument::CreateComment(const nsString& aData, nsIDOMComment** aReturn) { nsIContent* comment = nsnull; nsresult rv = NS_NewCommentNode(&comment); if (NS_OK == rv) { rv = comment->QueryInterface(kIDOMCommentIID, (void**)aReturn); (*aReturn)->AppendData(aData); NS_RELEASE(comment); } return rv; } NS_IMETHODIMP nsDocument::CreateCDATASection(const nsString& aData, nsIDOMCDATASection** aReturn) { // Should be implemented by subclass return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsDocument::CreateProcessingInstruction(const nsString& aTarget, const nsString& aData, nsIDOMProcessingInstruction** aReturn) { // Should be implemented by subclass return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsDocument::CreateAttribute(const nsString& aName, nsIDOMAttr** aReturn) { nsAutoString value; nsDOMAttribute* attribute; value.Truncate(); attribute = new nsDOMAttribute(nsnull, aName, value); if (nsnull == attribute) { return NS_ERROR_OUT_OF_MEMORY; } return attribute->QueryInterface(kIDOMAttrIID, (void**)aReturn); } NS_IMETHODIMP nsDocument::CreateEntityReference(const nsString& aName, nsIDOMEntityReference** aReturn) { // Should be implemented by subclass return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsDocument::GetElementsByTagName(const nsString& aTagname, nsIDOMNodeList** aReturn) { nsIAtom* nameAtom; PRInt32 nameSpaceId; nsresult result = NS_OK; if (nsnull != mRootContent) { result = mRootContent->ParseAttributeString(aTagname, nameAtom, nameSpaceId); if (NS_OK != result) { return result; } } else { nameAtom = NS_NewAtom(aTagname); nameSpaceId = kNameSpaceID_None; } nsContentList* list = new nsContentList(this, nameAtom, nameSpaceId); NS_IF_RELEASE(nameAtom); if (nsnull == list) { return NS_ERROR_OUT_OF_MEMORY; } return list->QueryInterface(kIDOMNodeListIID, (void **)aReturn); } NS_IMETHODIMP nsDocument::GetStyleSheets(nsIDOMStyleSheetCollection** aStyleSheets) { if (nsnull == mDOMStyleSheets) { mDOMStyleSheets = new nsDOMStyleSheetCollection(this); if (nsnull == mDOMStyleSheets) { return NS_ERROR_OUT_OF_MEMORY; } NS_ADDREF(mDOMStyleSheets); } *aStyleSheets = mDOMStyleSheets; NS_ADDREF(mDOMStyleSheets); return NS_OK; } NS_IMETHODIMP nsDocument::CreateElementWithNameSpace(const nsString& aTagName, const nsString& aNameSpace, nsIDOMElement** aReturn) { return NS_OK; } // // nsIDOMNode methods // NS_IMETHODIMP nsDocument::GetNodeName(nsString& aNodeName) { aNodeName.SetString("#document"); return NS_OK; } NS_IMETHODIMP nsDocument::GetNodeValue(nsString& aNodeValue) { aNodeValue.Truncate(); return NS_OK; } NS_IMETHODIMP nsDocument::SetNodeValue(const nsString& aNodeValue) { return NS_OK; } 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(kIDOMNodeListIID, (void**)aChildNodes); } NS_IMETHODIMP nsDocument::HasChildNodes(PRBool* aHasChildNodes) { *aHasChildNodes = PR_TRUE; return NS_OK; } NS_IMETHODIMP nsDocument::GetFirstChild(nsIDOMNode** aFirstChild) { nsresult result = NS_OK; if ((nsnull != mProlog) && (0 != mProlog->Count())) { nsIContent* content; content = (nsIContent *)mProlog->ElementAt(0); if (nsnull != content) { result = content->QueryInterface(kIDOMNodeIID, (void**)aFirstChild); } } else { nsIDOMElement* element; result = GetDocumentElement(&element); if (NS_OK == result) { result = element->QueryInterface(kIDOMNodeIID, (void**)aFirstChild); NS_RELEASE(element); } } return result; } NS_IMETHODIMP nsDocument::GetLastChild(nsIDOMNode** aLastChild) { nsresult result = NS_OK; if ((nsnull != mEpilog) && (0 != mEpilog->Count())) { nsIContent* content; content = (nsIContent *)mEpilog->ElementAt(mEpilog->Count()-1); if (nsnull != content) { result = content->QueryInterface(kIDOMNodeIID, (void**)aLastChild); } } else { nsIDOMElement* element; result = GetDocumentElement(&element); if (NS_OK == result) { result = element->QueryInterface(kIDOMNodeIID, (void**)aLastChild); NS_RELEASE(element); } } 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::InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild, nsIDOMNode** aReturn) { NS_ASSERTION(nsnull != aNewChild, "null ptr"); nsresult result = NS_OK; PRInt32 index; PRUint16 nodeType; nsIContent *content, *refContent = nsnull; if (nsnull == aNewChild) { return NS_ERROR_INVALID_ARG; } aNewChild->GetNodeType(&nodeType); if ((COMMENT_NODE != nodeType) && (PROCESSING_INSTRUCTION_NODE != nodeType)) { return NS_ERROR_INVALID_ARG; } result = aNewChild->QueryInterface(kIContentIID, (void**)&content); if (NS_OK != result) { return result; } if (nsnull == aRefChild) { AppendToEpilog(content); } else { result = aRefChild->QueryInterface(kIContentIID, (void**)&refContent); if (NS_OK != result) { NS_RELEASE(content); return result; } if ((nsnull != mProlog) && (0 != mProlog->Count())) { index = mProlog->IndexOf(refContent); if (-1 != index) { mProlog->InsertElementAt(content, index); NS_ADDREF(content); } } if (refContent == mRootContent) { AppendToProlog(content); } else if ((nsnull != mEpilog) && (0 != mEpilog->Count())) { index = mEpilog->IndexOf(refContent); if (-1 != index) { mEpilog->InsertElementAt(content, index); NS_ADDREF(content); } } NS_RELEASE(refContent); } if (NS_OK == result) { content->SetDocument(this, PR_TRUE); *aReturn = aNewChild; NS_ADDREF(aNewChild); } else { *aReturn = nsnull; } NS_RELEASE(content); return result; } NS_IMETHODIMP nsDocument::ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild, nsIDOMNode** aReturn) { NS_ASSERTION(((nsnull != aNewChild) && (nsnull != aOldChild)), "null ptr"); nsresult result = NS_OK; PRInt32 index; PRUint16 nodeType; nsIContent *content, *refContent; if ((nsnull == aNewChild) || (nsnull == aOldChild)) { return NS_ERROR_INVALID_ARG; } aNewChild->GetNodeType(&nodeType); if ((COMMENT_NODE != nodeType) && (PROCESSING_INSTRUCTION_NODE != nodeType)) { return NS_ERROR_INVALID_ARG; } result = aNewChild->QueryInterface(kIContentIID, (void**)&content); if (NS_OK != result) { return result; } result = aOldChild->QueryInterface(kIContentIID, (void**)&refContent); if (NS_OK != result) { NS_RELEASE(content); return result; } if ((nsnull != mProlog) && (0 != mProlog->Count())) { index = mProlog->IndexOf(refContent); if (-1 != index) { nsIContent* oldContent; oldContent = (nsIContent*)mProlog->ElementAt(index); NS_RELEASE(oldContent); mProlog->ReplaceElementAt(content, index); NS_ADDREF(content); } } if (refContent == mRootContent) { result = NS_ERROR_INVALID_ARG; } else if ((nsnull != mEpilog) && (0 != mEpilog->Count())) { index = mEpilog->IndexOf(refContent); if (-1 != index) { nsIContent* oldContent; oldContent = (nsIContent*)mEpilog->ElementAt(index); NS_RELEASE(oldContent); mEpilog->ReplaceElementAt(content, index); NS_ADDREF(content); } } if (NS_OK == result) { content->SetDocument(this, PR_TRUE); refContent->SetDocument(nsnull, PR_TRUE); *aReturn = aNewChild; NS_ADDREF(aNewChild); } else { *aReturn = nsnull; } NS_RELEASE(content); NS_RELEASE(refContent); return result; } NS_IMETHODIMP nsDocument::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn) { NS_ASSERTION(nsnull != aOldChild, "null ptr"); nsresult result = NS_OK; PRInt32 index; nsIContent *content; if (nsnull == aOldChild) { return NS_ERROR_INVALID_ARG; } result = aOldChild->QueryInterface(kIContentIID, (void**)&content); if (NS_OK != result) { return result; } if ((nsnull != mProlog) && (0 != mProlog->Count())) { index = mProlog->IndexOf(content); if (-1 != index) { // Don't drop reference count since we're going // to return this element anyway. mProlog->RemoveElementAt(index); } } if (content == mRootContent) { result = NS_ERROR_INVALID_ARG; } else if ((nsnull != mEpilog) && (0 != mEpilog->Count())) { index = mEpilog->IndexOf(content); if (-1 != index) { mEpilog->RemoveElementAt(index); } } if (NS_OK == result) { content->SetDocument(nsnull, PR_TRUE); *aReturn = aOldChild; } else { *aReturn = nsnull; } NS_RELEASE(content); return result; } NS_IMETHODIMP nsDocument::AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn) { return InsertBefore(aNewChild, nsnull, aReturn); } NS_IMETHODIMP nsDocument::CloneNode(PRBool aDeep, nsIDOMNode** aReturn) { // We don't allow cloning of a document *aReturn = nsnull; return NS_OK; } NS_IMETHODIMP nsDocument::GetOwnerDocument(nsIDOMDocument** aOwnerDocument) { return QueryInterface(kIDOMDocumentIID, (void **)aOwnerDocument); } nsresult nsDocument::GetListenerManager(nsIEventListenerManager **aInstancePtrResult) { if (nsnull != mListenerManager) { return mListenerManager->QueryInterface(kIEventListenerManagerIID, (void**) aInstancePtrResult);; } if (NS_OK == NS_NewEventListenerManager(aInstancePtrResult)) { mListenerManager = *aInstancePtrResult; NS_ADDREF(mListenerManager); return NS_OK; } return NS_ERROR_FAILURE; } nsresult nsDocument::GetNewListenerManager(nsIEventListenerManager **aInstancePtrResult) { return NS_NewEventListenerManager(aInstancePtrResult); } nsresult nsDocument::HandleDOMEvent(nsIPresContext& aPresContext, nsEvent* aEvent, nsIDOMEvent** aDOMEvent, PRUint32 aFlags, nsEventStatus& aEventStatus) { nsresult mRet = NS_OK; nsIDOMEvent* mDOMEvent = nsnull; if (NS_EVENT_FLAG_INIT == aFlags) { aDOMEvent = &mDOMEvent; } //Capturing stage if (NS_EVENT_FLAG_BUBBLE != aFlags) { //XXX Check window capture here } //Local handling stage if (nsnull != mListenerManager) { mListenerManager->HandleEvent(aPresContext, aEvent, aDOMEvent, aFlags, aEventStatus); } //Bubbling stage if (NS_EVENT_FLAG_CAPTURE != aFlags && nsnull != mScriptContextOwner) { nsIScriptGlobalObject* mGlobal; if (NS_OK == mScriptContextOwner->GetScriptGlobalObject(&mGlobal)) { mGlobal->HandleDOMEvent(aPresContext, aEvent, aDOMEvent, NS_EVENT_FLAG_BUBBLE, aEventStatus); NS_RELEASE(mGlobal); } } if (NS_EVENT_FLAG_INIT == aFlags) { // We're leaving the DOM event loop so if we created a DOM event, release here. if (nsnull != *aDOMEvent) { 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(kIPrivateDOMEventIID, (void**)&mPrivateEvent)) { mPrivateEvent->DuplicatePrivateData(); NS_RELEASE(mPrivateEvent); } } } aDOMEvent = nsnull; } return mRet; } nsresult nsDocument::AddEventListenerByIID(nsIDOMEventListener *aListener, const nsIID& aIID) { nsIEventListenerManager *manager; if (NS_OK == GetListenerManager(&manager)) { manager->AddEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE); NS_RELEASE(manager); 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 nsString& aType, nsIDOMEventListener* aListener, PRBool aPostProcess, PRBool aUseCapture) { nsIEventListenerManager *manager; if (NS_OK == GetListenerManager(&manager)) { PRInt32 flags = (aPostProcess ? NS_EVENT_FLAG_POST_PROCESS : NS_EVENT_FLAG_NONE) | (aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE); manager->AddEventListenerByType(aListener, aType, flags); NS_RELEASE(manager); return NS_OK; } return NS_ERROR_FAILURE; } nsresult nsDocument::RemoveEventListener(const nsString& aType, nsIDOMEventListener* aListener, PRBool aPostProcess, PRBool aUseCapture) { if (nsnull != mListenerManager) { PRInt32 flags = (aPostProcess ? NS_EVENT_FLAG_POST_PROCESS : NS_EVENT_FLAG_NONE) | (aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE); mListenerManager->RemoveEventListenerByType(aListener, aType, flags); return NS_OK; } return NS_ERROR_FAILURE; } nsresult nsDocument::CaptureEvent(const nsString& aType) { nsIEventListenerManager *mManager; if (NS_OK == GetListenerManager(&mManager)) { //mManager->CaptureEvent(aListener); NS_RELEASE(mManager); return NS_OK; } return NS_ERROR_FAILURE; } nsresult nsDocument::ReleaseEvent(const nsString& aType) { if (nsnull != mListenerManager) { //mListenerManager->ReleaseEvent(aListener); return NS_OK; } return NS_ERROR_FAILURE; } PRBool nsDocument::AddProperty(JSContext *aContext, jsval aID, jsval *aVp) { return PR_TRUE; } PRBool nsDocument::DeleteProperty(JSContext *aContext, jsval aID, jsval *aVp) { return PR_TRUE; } PRBool nsDocument::GetProperty(JSContext *aContext, jsval aID, jsval *aVp) { PRBool result = PR_TRUE; if (JSVAL_IS_STRING(aID) && PL_strcmp("location", JS_GetStringBytes(JS_ValueToString(aContext, aID))) == 0) { if (nsnull != mScriptContextOwner) { nsIScriptGlobalObject *global; mScriptContextOwner->GetScriptGlobalObject(&global); if (nsnull != global) { nsIJSScriptObject *window; if (NS_OK == global->QueryInterface(kIJSScriptObjectIID, (void **)&window)) { result = window->GetProperty(aContext, aID, aVp); NS_RELEASE(window); } else { result = PR_FALSE; } NS_RELEASE(global); } } } return result; } PRBool nsDocument::SetProperty(JSContext *aContext, jsval aID, jsval *aVp) { PRBool result = PR_TRUE; if (JS_TypeOfValue(aContext, *aVp) == JSTYPE_FUNCTION && JSVAL_IS_STRING(aID)) { nsAutoString mPropName, mPrefix; mPropName.SetString(JS_GetStringChars(JS_ValueToString(aContext, aID))); mPrefix.SetString(mPropName, 2); if (mPrefix == "on") { nsIEventListenerManager *mManager = nsnull; if (mPropName == "onmousedown" || mPropName == "onmouseup" || mPropName == "onclick" || mPropName == "onmouseover" || mPropName == "onmouseout") { if (NS_OK == GetListenerManager(&mManager)) { nsIScriptContext *mScriptCX = (nsIScriptContext *)JS_GetContextPrivate(aContext); if (NS_OK != mManager->RegisterScriptEventListener(mScriptCX, this, kIDOMMouseListenerIID)) { NS_RELEASE(mManager); return PR_FALSE; } } } else if (mPropName == "onkeydown" || mPropName == "onkeyup" || mPropName == "onkeypress") { if (NS_OK == GetListenerManager(&mManager)) { nsIScriptContext *mScriptCX = (nsIScriptContext *)JS_GetContextPrivate(aContext); if (NS_OK != mManager->RegisterScriptEventListener(mScriptCX, this, kIDOMKeyListenerIID)) { NS_RELEASE(mManager); return PR_FALSE; } } } else if (mPropName == "onmousemove") { if (NS_OK == GetListenerManager(&mManager)) { nsIScriptContext *mScriptCX = (nsIScriptContext *)JS_GetContextPrivate(aContext); if (NS_OK != mManager->RegisterScriptEventListener(mScriptCX, this, kIDOMMouseMotionListenerIID)) { NS_RELEASE(mManager); return PR_FALSE; } } } else if (mPropName == "onfocus" || mPropName == "onblur") { if (NS_OK == GetListenerManager(&mManager)) { nsIScriptContext *mScriptCX = (nsIScriptContext *)JS_GetContextPrivate(aContext); if (NS_OK != mManager->RegisterScriptEventListener(mScriptCX, this, kIDOMFocusListenerIID)) { NS_RELEASE(mManager); return PR_FALSE; } } } else if (mPropName == "onsubmit" || mPropName == "onreset" || mPropName == "onchange") { if (NS_OK == GetListenerManager(&mManager)) { nsIScriptContext *mScriptCX = (nsIScriptContext *)JS_GetContextPrivate(aContext); if (NS_OK != mManager->RegisterScriptEventListener(mScriptCX, this, kIDOMFormListenerIID)) { NS_RELEASE(mManager); return PR_FALSE; } } } else if (mPropName == "onload" || mPropName == "onunload" || mPropName == "onabort" || mPropName == "onerror") { if (NS_OK == GetListenerManager(&mManager)) { nsIScriptContext *mScriptCX = (nsIScriptContext *)JS_GetContextPrivate(aContext); if (NS_OK != mManager->RegisterScriptEventListener(mScriptCX, this, kIDOMLoadListenerIID)) { NS_RELEASE(mManager); return PR_FALSE; } } } else if (mPropName == "onpaint") { if (NS_OK == GetListenerManager(&mManager)) { nsIScriptContext *mScriptCX = (nsIScriptContext *) JS_GetContextPrivate(aContext); if (NS_OK != mManager->RegisterScriptEventListener(mScriptCX, this, kIDOMPaintListenerIID)) { NS_RELEASE(mManager); return PR_FALSE; } } } NS_IF_RELEASE(mManager); } } else if (JSVAL_IS_STRING(aID) && PL_strcmp("location", JS_GetStringBytes(JS_ValueToString(aContext, aID))) == 0) { if (nsnull != mScriptContextOwner) { nsIScriptGlobalObject *global; mScriptContextOwner->GetScriptGlobalObject(&global); if (nsnull != global) { nsIJSScriptObject *window; if (NS_OK == global->QueryInterface(kIJSScriptObjectIID, (void **)&window)) { result = window->SetProperty(aContext, aID, aVp); NS_RELEASE(window); } else { result = PR_FALSE; } NS_RELEASE(global); } } } return result; } PRBool nsDocument::EnumerateProperty(JSContext *aContext) { return PR_TRUE; } PRBool nsDocument::Resolve(JSContext *aContext, jsval aID) { return PR_TRUE; } PRBool nsDocument::Convert(JSContext *aContext, jsval aID) { return PR_TRUE; } void nsDocument::Finalize(JSContext *aContext) { } /** * Returns the Selection Object */ NS_IMETHODIMP nsDocument::GetSelection(nsIDOMSelection ** aSelection) { if (!aSelection) return NS_ERROR_NULL_POINTER; return NS_ERROR_FAILURE; } /** * Selects all the Content */ NS_IMETHODIMP nsDocument::SelectAll() { nsIContent * start = nsnull; nsIContent * end = nsnull; nsIContent * body = nsnull; nsString bodyStr("BODY"); PRInt32 i, n; mRootContent->ChildCount(n); for (i=0;iChildAt(i, child); PRBool isSynthetic; child->IsSynthetic(isSynthetic); if (!isSynthetic) { nsIAtom * atom; child->GetTag(atom); if (bodyStr.EqualsIgnoreCase(atom)) { body = child; break; } NS_IF_RELEASE(atom); } NS_RELEASE(child); } if (body == nsnull) { return NS_ERROR_FAILURE; } start = body; // Find Very first Piece of Content NS_ADDREF(start); //to balance release below for (;;) { start->ChildCount(n); if (n <= 0) { break; } nsIContent * child = start; child->ChildAt(0, start); NS_RELEASE(child); } end = body; NS_ADDREF(end); //to balance release below // Last piece of Content for (;;) { end->ChildCount(n); if (n <= 0) { break; } nsIContent * child = end; child->ChildAt(n-1, end); NS_RELEASE(child); } NS_RELEASE(body); SetDisplaySelection(PR_TRUE); return NS_OK; } /** * Finds text in content */ NS_IMETHODIMP nsDocument::FindNext(const nsString &aSearchStr, PRBool aMatchCase, PRBool aSearchDown, PRBool &aIsFound) { aIsFound = PR_FALSE; return NS_ERROR_FAILURE; } void nsDocument::BeginConvertToXIF(nsXIFConverter& aConverter, nsIDOMNode* aNode) { nsIContent* content = nsnull; nsresult isContent = aNode->QueryInterface(kIContentIID, (void**)&content); PRBool isSynthetic = PR_TRUE; // Begin Conversion if (NS_OK == isContent) { content->IsSynthetic(isSynthetic); if (PR_FALSE == isSynthetic) { content->BeginConvertToXIF(aConverter); content->ConvertContentToXIF(aConverter); } NS_RELEASE(content); } } void nsDocument::ConvertChildrenToXIF(nsXIFConverter& aConverter, nsIDOMNode* aNode) { // Iterate through the children, convertion child nodes nsresult result = NS_OK; nsIDOMNode* child = nsnull; result = aNode->GetFirstChild(&child); while ((result == NS_OK) && (child != nsnull)) { nsIDOMNode* temp = child; ToXIF(aConverter,child); result = child->GetNextSibling(&child); NS_RELEASE(temp); } } void nsDocument::FinishConvertToXIF(nsXIFConverter& aConverter, nsIDOMNode* aNode) { nsIContent* content = nsnull; nsresult isContent = aNode->QueryInterface(kIContentIID, (void**)&content); PRBool isSynthetic = PR_TRUE; if (NS_OK == isContent) { content->IsSynthetic(isSynthetic); if (PR_FALSE == isSynthetic) content->FinishConvertToXIF(aConverter); NS_RELEASE(content); } } void nsDocument::ToXIF(nsXIFConverter& aConverter, nsIDOMNode* aNode) { nsIDOMSelection* sel = aConverter.GetSelection(); if (sel != nsnull) { nsIContent* content = nsnull; nsresult isContent = aNode->QueryInterface(kIContentIID, (void**)&content); if (isContent != nsnull) { PRBool isInSelection = IsInSelection(sel,content); if (isInSelection == PR_TRUE) { BeginConvertToXIF(aConverter,aNode); ConvertChildrenToXIF(aConverter,aNode); FinishConvertToXIF(aConverter,aNode); } else { ConvertChildrenToXIF(aConverter,aNode); } NS_RELEASE(content); } } else { BeginConvertToXIF(aConverter,aNode); ConvertChildrenToXIF(aConverter,aNode); FinishConvertToXIF(aConverter,aNode); } } void nsDocument::CreateXIF(nsString & aBuffer, nsIDOMSelection* aSelection) { nsXIFConverter converter(aBuffer); // call the function converter.SetSelection(aSelection); converter.AddStartTag("section"); converter.AddStartTag("section_head"); converter.AddEndTag("section_head"); converter.AddStartTag("section_body"); nsIDOMElement* root = nsnull; if (NS_OK == GetDocumentElement(&root)) { ToXIF(converter,root); NS_RELEASE(root); } converter.AddEndTag("section_body"); converter.AddEndTag("section"); converter.Write(); } nsIContent* nsDocument::FindContent(const nsIContent* aStartNode, const nsIContent* aTest1, const nsIContent* aTest2) const { PRInt32 count; aStartNode->ChildCount(count); PRInt32 index; for(index = 0; index < count;index++) { nsIContent* child; aStartNode->ChildAt(index, child); nsIContent* content = FindContent(child,aTest1,aTest2); if (content != nsnull) { NS_IF_RELEASE(child); return content; } if (child == aTest1 || child == aTest2) { NS_IF_RELEASE(content); return child; } NS_IF_RELEASE(child); NS_IF_RELEASE(content); } return nsnull; } PRBool nsDocument::IsInRange(const nsIContent *aStartContent, const nsIContent* aEndContent, const nsIContent* aContent) const { PRBool result; if (aStartContent == aEndContent) { return PRBool(aContent == aStartContent); } else if (aStartContent == aContent || aEndContent == aContent) { result = PR_TRUE; } else { result = IsBefore(aStartContent,aContent); if (result == PR_TRUE) result = IsBefore(aContent,aEndContent); } return result; } /** * Determines if the content is found within the selection * * @update gpk 1/8/99 * @param param -- description * @param param -- description * @return PR_TRUE if the content is found within the selection */ PRBool nsDocument::IsInSelection(nsIDOMSelection* aSelection, const nsIContent* aContent) const { PRBool result = PR_FALSE; if (aSelection != nsnull) { //traverses through an iterator to see if the acontent is in the ranges nsIEnumerator *enumerator; if (NS_SUCCEEDED(aSelection->QueryInterface(kIEnumeratorIID, (void **)&enumerator))) { for (enumerator->First();NS_OK != enumerator->IsDone() ; enumerator->Next()) { nsIDOMRange* range = nsnull; if (NS_SUCCEEDED(enumerator->CurrentItem((nsISupports**)&range))) { nsIDOMNode* startNode = nsnull; nsIDOMNode* endNode = nsnull; range->GetStartParent(&startNode); range->GetEndParent(&endNode); if (startNode && endNode) { nsIContent* start; nsIContent* end; if (NS_SUCCEEDED(startNode->QueryInterface(kIContentIID, (void **)&start)) && NS_SUCCEEDED(endNode->QueryInterface(kIContentIID, (void **)&end)) ) { result = IsInRange(start,end,aContent); } NS_IF_RELEASE(start); NS_IF_RELEASE(end); } NS_IF_RELEASE(startNode); NS_IF_RELEASE(endNode); NS_RELEASE(range); } if (result) break; } NS_IF_RELEASE(enumerator); } } return result; } PRBool nsDocument::IsBefore(const nsIContent *aNewContent, const nsIContent* aCurrentContent) const { PRBool result = PR_FALSE; if (nsnull != aNewContent && nsnull != aCurrentContent && aNewContent != aCurrentContent) { nsIContent* test = FindContent(mRootContent,aNewContent,aCurrentContent); if (test == aNewContent) result = PR_TRUE; NS_RELEASE(test); } return result; } nsIContent* nsDocument::GetPrevContent(const nsIContent *aContent) const { nsIContent* result = nsnull; // Look at previous sibling if (nsnull != aContent) { nsIContent* parent; aContent->GetParent(parent); if (parent != nsnull && parent != mRootContent) { PRInt32 index; parent->IndexOf((nsIContent*)aContent, index); if (index > 0) parent->ChildAt(index-1, result); else result = GetPrevContent(parent); } NS_IF_RELEASE(parent); } return result; } nsIContent* nsDocument::GetNextContent(const nsIContent *aContent) const { nsIContent* result = nsnull; if (nsnull != aContent) { // Look at next sibling nsIContent* parent; aContent->GetParent(parent); if (parent != nsnull && parent != mRootContent) { PRInt32 index; parent->IndexOf((nsIContent*)aContent, index); PRInt32 count; parent->ChildCount(count); if (index+1 < count) { parent->ChildAt(index+1, result); // Get first child down the tree for (;;) { PRInt32 n; result->ChildCount(n); if (n <= 0) { break; } nsIContent * old = result; old->ChildAt(0, result); NS_RELEASE(old); result->ChildCount(n); } } else { result = GetNextContent(parent); } } NS_IF_RELEASE(parent); } return result; } void nsDocument::SetDisplaySelection(PRBool aToggle) { mDisplaySelection = aToggle; } PRBool nsDocument::GetDisplaySelection() const { return mDisplaySelection; }