Mozilla/mozilla/layout/base/src/nsDocument.cpp
jband%netscape.com 191411b358 Landing big set of DOM and XPConnect changes:
DOM: getting rid of JS_GetContextPrivate wherever possible. Use static parent
links where we can. When we do need to find this info about the caller
we call a function that knows how to get that info rather than inline calls
to JS_GetContextPrivate. This is all required for calling DOM objects on
non-DOM JSContexts as we do via xpconnect.

XPConnect: basic refactoring work to disassociate wrappers from the JSContext
that was active when the wrapper was constructed. This allows for calling into
wrapped JS objects on the right JSContext and for proper grouping of wrapped
native objects so that they can share proto objects. This also allows for
better sharing of objects and lays the foundations for threadsafety and
interface flattening.

Also, xpconnect tests are reorganized and improved.

fixes bugs: 13419, 17736, 17746, 17952, 22086

r=vidur r=mccabe r=norris r=cbegle
a=chofmann


git-svn-id: svn://10.0.0.236/trunk@56202 18797224-902f-48f8-a5cc-f745e15eee43
1999-12-18 20:29:29 +00:00

3109 lines
85 KiB
C++

/* -*- 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.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 Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "plstr.h"
#include "nsCOMPtr.h"
#include "nsIInterfaceRequestor.h"
#include "nsDocument.h"
#include "nsIArena.h"
#include "nsIURL.h"
#include "nsILoadGroup.h"
#include "nsIChannel.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 "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 "nsICSSStyleSheet.h"
#include "nsITextContent.h"
#include "nsXIFConverter.h"
#include "nsIHTMLContentSink.h"
#include "nsHTMLContentSinkStream.h"
#include "nsHTMLToTXTSinkStream.h"
#include "nsXIFDTD.h"
#include "nsIParser.h"
#include "nsParserCIID.h"
#include "nsFileSpec.h"
#include "nsFileStream.h"
#include "nsRange.h"
#include "nsIDOMText.h"
#include "nsIDOMComment.h"
#include "nsINameSpaceManager.h"
#include "nsIServiceManager.h"
#include "nsLayoutAtoms.h"
#include "nsLayoutCID.h"
#include "nsIDOMSelection.h"
#include "nsIDOMRange.h"
#include "nsIEnumerator.h"
#include "nsDOMError.h"
#include "nsIScrollableView.h"
#include "nsIFrame.h"
#include "nsLayoutUtils.h"
#include "nsIScriptSecurityManager.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(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(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);
#include "nsIHTMLDocument.h"
static NS_DEFINE_IID(kIHTMLDocumentIID, NS_IHTMLDOCUMENT_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 ContentStatesChanged(nsIDocument* aDocument,
nsIContent* aContent1,
nsIContent* aContent2) { return NS_OK; }
NS_IMETHOD AttributeChanged(nsIDocument *aDocument,
nsIContent* aContent,
PRInt32 aNameSpaceID,
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;
}
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)
{
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??
PRInt32 result;
float ver = aVersion.ToFloat(&result);
if (NS_FAILED(result)) {
return result;
}
if ((aFeature.EqualsIgnoreCase("HTML") ||
aFeature.EqualsIgnoreCase("XML")) &&
((ver == 1.0) || (ver == 2.0) || (0 ==aVersion.Length()))) {
*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) {
NS_WITH_SERVICE(nsIDOMScriptObjectFactory, factory,
kDOMScriptObjectFactoryCID, &result);
if (NS_OK == result) {
nsIScriptGlobalObject *global = aContext->GetGlobalObject();
result = factory->NewScriptDOMImplementation(aContext, (nsISupports*)(nsIDOMDOMImplementation*)this,
global, &mScriptObject);
NS_RELEASE(global);
}
}
*aScriptObject = mScriptObject;
return result;
}
NS_IMETHODIMP
nsDOMImplementation::SetScriptObject(void *aScriptObject)
{
mScriptObject = nsnull;
return NS_OK;
}
// ==================================================================
// =
// ==================================================================
MOZ_DECL_CTOR_COUNTER(nsDocumentChildNodes);
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;
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;
mCharacterSet = "ISO-8859-1";
mParentDocument = nsnull;
mRootContent = nsnull;
mScriptObject = 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;
mModCount = 0;
mFileSpec = nsnull;
mPrincipal = 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 (observer != (nsIDocumentObserver*)mObservers.ElementAt(index)) {
index--;
}
}
if (nsnull != mDocumentTitle) {
delete mDocumentTitle;
mDocumentTitle = nsnull;
}
NS_IF_RELEASE(mDocumentURL);
NS_IF_RELEASE(mPrincipal);
mDocumentLoadGroup = null_nsCOMPtr();
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(mListenerManager);
NS_IF_RELEASE(mDOMStyleSheets);
NS_IF_RELEASE(mNameSpaceManager);
if (nsnull != mHeaderData) {
delete mHeaderData;
mHeaderData = nsnull;
}
NS_IF_RELEASE(mLineBreaker);
NS_IF_RELEASE(mWordBreaker);
delete mFileSpec;
}
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(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;
}
if (aIID.Equals(nsIDiskDocument::GetIID())) {
nsIDiskDocument* tmp = this;
*aInstancePtr = (void*) tmp;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(nsCOMTypeInfo<nsISupportsWeakReference>::GetIID())) {
nsISupportsWeakReference* tmp = this;
*aInstancePtr = (void*) tmp;
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(nsCOMTypeInfo<nsISupports>::GetIID())) {
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(nsIChannel* aChannel, nsILoadGroup* aLoadGroup)
{
nsresult rv = NS_OK;
if (nsnull != mDocumentTitle) {
delete mDocumentTitle;
mDocumentTitle = nsnull;
}
NS_IF_RELEASE(mDocumentURL);
NS_IF_RELEASE(mPrincipal);
mDocumentLoadGroup = null_nsCOMPtr();
// 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<nsIStyleSet> 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);
(void)aChannel->GetURI(&mDocumentURL);
nsCOMPtr<nsISupports> owner;
aChannel->GetOwner(getter_AddRefs(owner));
if (owner)
owner->QueryInterface(nsIPrincipal::GetIID(), (void**)&mPrincipal);
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;
}
nsresult
nsDocument::StartDocumentLoad(const char* aCommand,
nsIChannel* aChannel,
nsILoadGroup* aLoadGroup,
nsISupports* aContainer,
nsIStreamListener **aDocListener)
{
return Reset(aChannel, aLoadGroup);
}
const nsString* nsDocument::GetDocumentTitle() const
{
return mDocumentTitle;
}
nsIURI* nsDocument::GetDocumentURL() const
{
NS_IF_ADDREF(mDocumentURL);
return mDocumentURL;
}
nsIPrincipal* nsDocument::GetDocumentPrincipal()
{
if (!mPrincipal) {
nsresult rv;
NS_WITH_SERVICE(nsIScriptSecurityManager, securityManager,
NS_SCRIPTSECURITYMANAGER_PROGID, &rv);
if (NS_FAILED(rv))
return nsnull;
if (NS_FAILED(securityManager->GetCodebasePrincipal(mDocumentURL,
&mPrincipal)))
return nsnull;
}
NS_ADDREF(mPrincipal);
return mPrincipal;
}
NS_IMETHODIMP
nsDocument::GetContentType(nsString& aContentType) const
{
// Must be implemented by derived class.
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDocument::GetDocumentLoadGroup(nsILoadGroup **aGroup) const
{
nsCOMPtr<nsILoadGroup> group = do_QueryReferent(mDocumentLoadGroup);
*aGroup = group;
NS_IF_ADDREF(*aGroup);
return NS_OK;
}
NS_IMETHODIMP
nsDocument::GetBaseURL(nsIURI*& aURL) const
{
aURL = mDocumentURL;
NS_IF_ADDREF(mDocumentURL);
return NS_OK;
}
NS_IMETHODIMP nsDocument::GetDocumentCharacterSet(nsString& oCharSetID)
{
oCharSetID = mCharacterSet;
return NS_OK;
}
NS_IMETHODIMP nsDocument::SetDocumentCharacterSet(const nsString& aCharSetID)
{
mCharacterSet = aCharSetID;
return NS_OK;
}
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
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;
}
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<nsIStyleSet> 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);
if (observer != (nsIDocumentObserver*)mObservers.ElementAt(index)) {
index--;
}
}
}
}
void nsDocument::RemoveStyleSheet(nsIStyleSheet* aSheet)
{
NS_PRECONDITION(nsnull != aSheet, "null arg");
mStyleSheets.RemoveElement(aSheet);
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<nsIStyleSet> set;
if (NS_SUCCEEDED(shell->GetStyleSet(getter_AddRefs(set)))) {
if (set) {
set->RemoveDocStyleSheet(aSheet);
}
}
}
// 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->StyleSheetRemoved(this, aSheet);
if (observer != (nsIDocumentObserver*)mObservers.ElementAt(index)) {
index--;
}
}
}
aSheet->SetOwningDocument(nsnull);
NS_RELEASE(aSheet);
}
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 index;
if (enabled) {
count = mPresShells.Count();
for (index = 0; index < count; index++) {
nsIPresShell* shell = (nsIPresShell*)mPresShells.ElementAt(index);
nsCOMPtr<nsIStyleSet> 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 (index = 0; index < mObservers.Count(); index++) {
nsIDocumentObserver* observer = (nsIDocumentObserver*)mObservers.ElementAt(index);
observer->StyleSheetAdded(this, aSheet);
if (observer != (nsIDocumentObserver*)mObservers.ElementAt(index)) {
index--;
}
}
}
return NS_OK;
}
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<nsIStyleSet> 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);
if (observer != (nsIDocumentObserver*)mObservers.ElementAt(index)) {
index--;
}
}
}
NS_IMETHODIMP
nsDocument::GetScriptGlobalObject(nsIScriptGlobalObject** aScriptGlobalObject)
{
NS_ENSURE_ARG_POINTER(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 ((nsnull == aScriptGlobalObject) && (nsnull != mRootContent)) {
mRootContent->SetDocument(nsnull, PR_TRUE);
}
mScriptGlobalObject = aScriptGlobalObject;
return NS_OK;
}
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::ContentStatesChanged(nsIContent* aContent1,
nsIContent* aContent2)
{
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);
// 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,
PRInt32 aNameSpaceID,
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, aNameSpaceID, 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;
nsCOMPtr<nsIScriptGlobalObject> global;
if (nsnull == mScriptObject) {
// XXX We make the (possibly erroneous) assumption that the first
// presentation shell represents the "primary view" of the document
// and that the JS parent chain should incorporate just that view.
// This is done for lack of a better model when we have multiple
// views.
nsIPresShell* shell = (nsIPresShell*) mPresShells.ElementAt(0);
if (shell) {
nsCOMPtr<nsIPresContext> cx;
shell->GetPresContext(getter_AddRefs(cx));
nsCOMPtr<nsISupports> container;
res = cx->GetContainer(getter_AddRefs(container));
if (NS_SUCCEEDED(res) && container) {
global = do_GetInterface(container);
}
}
// XXX If we can't find a view, parent to the calling context's
// global object. This may not be right either, but we need
// something.
else {
global = getter_AddRefs(aContext->GetGlobalObject());
}
if (NS_SUCCEEDED(res)) {
res = NS_NewScriptDocument(aContext,
(nsISupports *)(nsIDOMDocument *)this,
(nsISupports *)global,
(void**)&mScriptObject);
}
}
*aScriptObject = mScriptObject;
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)
{
*aReturn = nsnull;
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsDocument::CreateRange(nsIDOMRange** aReturn)
{
return NS_NewRange(aReturn);
}
nsresult
nsDocument::GetPixelDimensions(nsIPresShell* aShell,
PRInt32* aWidth,
PRInt32* aHeight)
{
nsresult result = NS_OK;
nsSize size;
nsIFrame* frame;
result = aShell->GetPrimaryFrameFor(mRootContent, &frame);
if (NS_SUCCEEDED(result) && frame) {
nsIView* view;
nsCOMPtr<nsIPresContext> presContext;
aShell->GetPresContext(getter_AddRefs(presContext));
result = frame->GetView(presContext, &view);
if (NS_SUCCEEDED(result)) {
// If we have a view check if it's scrollable. If not,
// just use the view size itself
if (view) {
nsIScrollableView* scrollableView;
if (NS_SUCCEEDED(view->QueryInterface(NS_GET_IID(nsIScrollableView), (void**)&scrollableView))) {
scrollableView->GetScrolledView(view);
}
result = view->GetDimensions(&size.width, &size.height);
}
// If we don't have a view, use the frame size
else {
result = frame->GetSize(size);
}
}
// Convert from twips to pixels
if (NS_SUCCEEDED(result)) {
nsCOMPtr<nsIPresContext> context;
result = aShell->GetPresContext(getter_AddRefs(context));
if (NS_SUCCEEDED(result)) {
float scale;
context->GetTwipsToPixels(&scale);
*aWidth = NSTwipsToIntPixels(size.width, scale);
*aHeight = NSTwipsToIntPixels(size.height, scale);
}
}
}
else {
*aWidth = 0;
*aHeight = 0;
}
return result;
}
NS_IMETHODIMP
nsDocument::GetWidth(PRInt32* aWidth)
{
nsresult result;
nsCOMPtr<nsIPresShell> shell;
// We make the assumption that the first presentation shell
// is the one for which we need information.
shell = getter_AddRefs(GetShellAt(0));
if (shell) {
PRInt32 width, height;
result = GetPixelDimensions(shell, &width, &height);
*aWidth = width;
}
return result;
}
NS_IMETHODIMP
nsDocument::GetHeight(PRInt32* aHeight)
{
nsresult result;
nsCOMPtr<nsIPresShell> shell;
// We make the assumption that the first presentation shell
// is the one for which we need information.
shell = getter_AddRefs(GetShellAt(0));
if (shell) {
PRInt32 width, height;
result = GetPixelDimensions(shell, &width, &height);
*aHeight = height;
}
return result;
}
//
// 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_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(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_NULL_POINTER;
}
aNewChild->GetNodeType(&nodeType);
if ((COMMENT_NODE != nodeType) && (PROCESSING_INSTRUCTION_NODE != nodeType)) {
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
result = aNewChild->QueryInterface(kIContentIID, (void**)&content);
if (NS_OK != result) {
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
if (nsnull == aRefChild) {
AppendToEpilog(content);
}
else {
result = aRefChild->QueryInterface(kIContentIID, (void**)&refContent);
if (NS_OK != result) {
NS_RELEASE(content);
return NS_ERROR_DOM_NOT_FOUND_ERR;
}
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_NULL_POINTER;
}
aNewChild->GetNodeType(&nodeType);
if ((COMMENT_NODE != nodeType) && (PROCESSING_INSTRUCTION_NODE != nodeType)) {
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
result = aNewChild->QueryInterface(kIContentIID, (void**)&content);
if (NS_OK != result) {
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
result = aOldChild->QueryInterface(kIContentIID, (void**)&refContent);
if (NS_OK != result) {
NS_RELEASE(content);
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
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) {
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
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_NULL_POINTER;
}
result = aOldChild->QueryInterface(kIContentIID, (void**)&content);
if (NS_OK != result) {
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
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_DOM_HIERARCHY_REQUEST_ERR;
}
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)
{
*aOwnerDocument = nsnull;
return NS_OK;
}
nsresult nsDocument::GetListenerManager(nsIEventListenerManager **aInstancePtrResult)
{
if (nsnull != mListenerManager) {
return mListenerManager->QueryInterface(kIEventListenerManagerIID, (void**) aInstancePtrResult);
}
if (NS_OK == GetNewListenerManager(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;
aEvent->flags = NS_EVENT_FLAG_NONE;
}
//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)) {
aEvent->flags = aFlags;
mListenerManager->HandleEvent(aPresContext, aEvent, aDOMEvent, aFlags, aEventStatus);
}
//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 (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 aUseCapture)
{
nsIEventListenerManager *manager;
if (NS_OK == GetListenerManager(&manager)) {
PRInt32 flags = 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 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;
}
PRBool nsDocument::AddProperty(JSContext *aContext, JSObject *aObj, jsval aID, jsval *aVp)
{
return PR_TRUE;
}
PRBool nsDocument::DeleteProperty(JSContext *aContext, JSObject *aObj, jsval aID, jsval *aVp)
{
return PR_TRUE;
}
PRBool nsDocument::GetProperty(JSContext *aContext, JSObject *aObj, jsval aID, jsval *aVp)
{
PRBool result = PR_TRUE;
if (JSVAL_IS_STRING(aID) &&
PL_strcmp("location", JS_GetStringBytes(JS_ValueToString(aContext, aID))) == 0) {
if (mScriptGlobalObject) {
nsCOMPtr<nsIJSScriptObject> window(do_QueryInterface(mScriptGlobalObject));
if(window) {
result = window->GetProperty(aContext, aObj, aID, aVp);
}
else {
result = PR_FALSE;
}
}
}
return result;
}
PRBool nsDocument::SetProperty(JSContext *aContext, JSObject *aObj, 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.GetUnicode(), 2);
if (mPrefix == "on") {
nsCOMPtr<nsIAtom> atom = getter_AddRefs(NS_NewAtom(mPropName));
nsIEventListenerManager *mManager = nsnull;
if (atom.get() == nsLayoutAtoms::onmousedown || atom.get() == nsLayoutAtoms::onmouseup || atom.get() == nsLayoutAtoms::onclick ||
atom.get() == nsLayoutAtoms::onmouseover || atom.get() == nsLayoutAtoms::onmouseout) {
if (NS_OK == GetListenerManager(&mManager)) {
nsCOMPtr<nsIScriptContext> mScriptCX;
if(NS_FAILED(nsLayoutUtils::GetStaticScriptContext(aContext, (JSObject*)mScriptObject, getter_AddRefs(mScriptCX))) ||
NS_OK != mManager->RegisterScriptEventListener(mScriptCX, this, atom, kIDOMMouseListenerIID)) {
NS_RELEASE(mManager);
return PR_FALSE;
}
}
}
else if (atom.get() == nsLayoutAtoms::onkeydown || atom.get() == nsLayoutAtoms::onkeyup || atom.get() == nsLayoutAtoms::onkeypress) {
if (NS_OK == GetListenerManager(&mManager)) {
nsCOMPtr<nsIScriptContext> mScriptCX;
if(NS_FAILED(nsLayoutUtils::GetStaticScriptContext(aContext, (JSObject*)mScriptObject, getter_AddRefs(mScriptCX))) ||
NS_OK != mManager->RegisterScriptEventListener(mScriptCX, this, atom, kIDOMKeyListenerIID)) {
NS_RELEASE(mManager);
return PR_FALSE;
}
}
}
else if (atom.get() == nsLayoutAtoms::onmousemove) {
if (NS_OK == GetListenerManager(&mManager)) {
nsCOMPtr<nsIScriptContext> mScriptCX;
if(NS_FAILED(nsLayoutUtils::GetStaticScriptContext(aContext, (JSObject*)mScriptObject, getter_AddRefs(mScriptCX))) ||
NS_OK != mManager->RegisterScriptEventListener(mScriptCX, this, atom, kIDOMMouseMotionListenerIID)) {
NS_RELEASE(mManager);
return PR_FALSE;
}
}
}
else if (atom.get() == nsLayoutAtoms::onfocus || atom.get() == nsLayoutAtoms::onblur) {
if (NS_OK == GetListenerManager(&mManager)) {
nsCOMPtr<nsIScriptContext> mScriptCX;
if(NS_FAILED(nsLayoutUtils::GetStaticScriptContext(aContext, (JSObject*)mScriptObject, getter_AddRefs(mScriptCX))) ||
NS_OK != mManager->RegisterScriptEventListener(mScriptCX, this, atom, kIDOMFocusListenerIID)) {
NS_RELEASE(mManager);
return PR_FALSE;
}
}
}
else if (atom.get() == nsLayoutAtoms::onsubmit || atom.get() == nsLayoutAtoms::onreset || atom.get() == nsLayoutAtoms::onchange ||
atom.get() == nsLayoutAtoms::onselect) {
if (NS_OK == GetListenerManager(&mManager)) {
nsCOMPtr<nsIScriptContext> mScriptCX;
if(NS_FAILED(nsLayoutUtils::GetStaticScriptContext(aContext, (JSObject*)mScriptObject, getter_AddRefs(mScriptCX))) ||
NS_OK != mManager->RegisterScriptEventListener(mScriptCX, this, atom, kIDOMFormListenerIID)) {
NS_RELEASE(mManager);
return PR_FALSE;
}
}
}
else if (atom.get() == nsLayoutAtoms::onload || atom.get() == nsLayoutAtoms::onunload || atom.get() == nsLayoutAtoms::onabort ||
atom.get() == nsLayoutAtoms::onerror) {
if (NS_OK == GetListenerManager(&mManager)) {
nsCOMPtr<nsIScriptContext> mScriptCX;
if(NS_FAILED(nsLayoutUtils::GetStaticScriptContext(aContext, (JSObject*)mScriptObject, getter_AddRefs(mScriptCX))) ||
NS_OK != mManager->RegisterScriptEventListener(mScriptCX, this, atom, kIDOMLoadListenerIID)) {
NS_RELEASE(mManager);
return PR_FALSE;
}
}
}
else if (atom.get() == nsLayoutAtoms::onpaint) {
if (NS_OK == GetListenerManager(&mManager)) {
nsCOMPtr<nsIScriptContext> mScriptCX;
if(NS_FAILED(nsLayoutUtils::GetStaticScriptContext(aContext, (JSObject*)mScriptObject, getter_AddRefs(mScriptCX))) ||
NS_OK != mManager->RegisterScriptEventListener(mScriptCX, this,
atom, 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 (mScriptGlobalObject) {
nsCOMPtr<nsIJSScriptObject> window(do_QueryInterface(mScriptGlobalObject));
if(window) {
result = window->SetProperty(aContext, aObj, aID, aVp);
}
else {
result = PR_FALSE;
}
}
}
return result;
}
PRBool nsDocument::EnumerateProperty(JSContext *aContext, JSObject *aObj)
{
return PR_TRUE;
}
PRBool nsDocument::Resolve(JSContext *aContext, JSObject *aObj, jsval aID)
{
return PR_TRUE;
}
PRBool nsDocument::Convert(JSContext *aContext, JSObject *aObj, jsval aID)
{
return PR_TRUE;
}
void nsDocument::Finalize(JSContext *aContext, JSObject *aObj)
{
}
/**
* 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;
result=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);
}
}
NS_IMETHODIMP
nsDocument::ToXIF(nsXIFConverter& aConverter, nsIDOMNode* aNode)
{
nsresult result=NS_OK;
nsIDOMSelection* sel = aConverter.GetSelection();
if (sel != nsnull)
{
nsIContent* content = nsnull;
result=aNode->QueryInterface(kIContentIID, (void**)&content);
if (NS_SUCCEEDED(result) && content)
{
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);
}
return result;
}
NS_IMETHODIMP
nsDocument::CreateXIF(nsString & aBuffer, nsIDOMSelection* aSelection)
{
nsresult result=NS_OK;
nsXIFConverter converter(aBuffer);
converter.SetSelection(aSelection);
converter.AddStartTag("section");
converter.AddStartTag("section_head");
nsString charset = mCharacterSet;
converter.BeginStartTag("document_info");
converter.AddAttribute(nsString("charset"),charset);
converter.FinishStartTag("document_info",PR_TRUE,PR_TRUE);
converter.AddEndTag("section_head");
converter.AddStartTag("section_body");
nsIHTMLDocument* htmldoc=nsnull;
result=this->QueryInterface(kIHTMLDocumentIID,(void**)&htmldoc);
if(NS_SUCCEEDED(result)) {
nsAutoString docTypeStr;
htmldoc->GetDocTypeStr(docTypeStr);
if(docTypeStr.Length()>0) converter.AddMarkupDeclaration(docTypeStr);
nsIDOMElement* root = nsnull;
result=GetDocumentElement(&root);
if (NS_SUCCEEDED(result))
{
#if 1
result=ToXIF(converter,root);
#else
if(NS_SUCCEEDED(rv)) {
// Make a content iterator over the selection:
nsCOMPtr<nsIContentIterator> iter;
result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull,
nsIContentIterator::GetIID(),
getter_AddRefs(iter));
if ((NS_SUCCEEDED(result)) && iter)
{
nsCOMPtr<nsIContent> rootContent (do_QueryInterface(root));
if (rootContent)
{
iter->Init(rootContent);
// loop through the content iterator for each content node
while (NS_COMFALSE == iter->IsDone())
{
nsCOMPtr<nsIContent> content;
res = iter->CurrentNode(getter_AddRefs(content));
if (NS_FAILED(res))
break;
//content->BeginConvertToXIF(converter);
content->ConvertContentToXIF(converter);
//content->FinishConvertToXIF(converter);
#if 0
nsCOMPtr<nsIDOMNode> node (do_QueryInterface(content));
if (node)
ToXIF(converter, node);
#endif
iter->Next();
}
}
}
}
#endif
NS_RELEASE(root);
}
}
converter.AddEndTag("section_body");
converter.AddEndTag("section");
NS_IF_RELEASE(htmldoc);
return result;
}
static NS_DEFINE_IID(kCParserIID, NS_IPARSER_IID);
static NS_DEFINE_IID(kCParserCID, NS_PARSER_IID);
nsresult
nsDocument::OutputDocumentAs(nsIOutputStream* aStream, nsIDOMSelection* selection, EOutputFormat aOutputFormat, const nsString& aCharset)
{
nsresult rv = NS_OK;
nsAutoString charsetStr = aCharset;
if (charsetStr.Length() == 0)
{
rv = GetDocumentCharacterSet(charsetStr);
if(NS_FAILED(rv)) {
charsetStr = "ISO-8859-1";
}
}
nsCOMPtr<nsIParser> parser;
rv = nsComponentManager::CreateInstance(kCParserCID,
nsnull,
kCParserIID,
getter_AddRefs(parser));
if (NS_SUCCEEDED(rv))
{
nsString buffer;
rv=CreateXIF(buffer, selection); // if selection is null, ignores the selection
if(NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIHTMLContentSink> sink;
switch (aOutputFormat)
{
case eOutputText:
rv = NS_New_HTMLToTXT_SinkStream(getter_AddRefs(sink), aStream, &charsetStr, 0);
break;
case eOutputHTML:
rv = NS_New_HTML_ContentSinkStream(getter_AddRefs(sink), aStream, &charsetStr, 0);
break;
default:
rv = NS_ERROR_INVALID_ARG;
}
if (NS_SUCCEEDED(rv) && sink)
{
parser->SetContentSink(sink);
parser->SetDocumentCharset(charsetStr, kCharsetFromPreviousLoading);
nsCOMPtr<nsIDTD> dtd;
rv = NS_NewXIFDTD(getter_AddRefs(dtd));
if (NS_SUCCEEDED(rv) && dtd)
{
parser->RegisterDTD(dtd);
parser->Parse(buffer, 0, "text/xif", PR_FALSE, PR_TRUE);
}
}
}
}
return rv;
}
nsresult
nsDocument::OutputDocumentAsHTML(nsIOutputStream* aStream, nsIDOMSelection* selection, const nsString& aCharset)
{
return OutputDocumentAs(aStream, selection, eOutputHTML, aCharset);
}
nsresult
nsDocument::OutputDocumentAsText(nsIOutputStream* aStream, nsIDOMSelection* selection, const nsString& aCharset)
{
return OutputDocumentAs(aStream, selection, eOutputText, aCharset);
}
NS_IMETHODIMP
nsDocument::InitDiskDocument(nsFileSpec* aFileSpec)
{
mFileSpec = nsnull;
if (aFileSpec)
{
mFileSpec = new nsFileSpec(*aFileSpec);
if (!mFileSpec)
return NS_ERROR_OUT_OF_MEMORY;
}
mModCount = 0;
return NS_OK;
}
NS_IMETHODIMP
nsDocument::SaveFile( nsFileSpec* aFileSpec,
PRBool aReplaceExisting,
PRBool aSaveCopy,
ESaveFileType aSaveFileType,
const nsString& aSaveCharset)
{
if (!aFileSpec)
return NS_ERROR_NULL_POINTER;
nsresult rv = NS_OK;
// if we're not replacing an existing file but the file
// exists, somethine is wrong
if (!aReplaceExisting && aFileSpec->Exists())
return NS_ERROR_FAILURE; // where are the file I/O errors?
nsOutputFileStream stream(*aFileSpec);
// if the stream didn't open, something went wrong
if (!stream.is_open())
return NS_BASE_STREAM_CLOSED;
// convert to our internal enum. Shame we have to do this.
EOutputFormat outputFormat = eOutputHTML;
switch (aSaveFileType)
{
case eSaveFileText: outputFormat = eOutputText; break;
case eSaveFileHTML: outputFormat = eOutputHTML; break;
}
rv = OutputDocumentAs(stream.GetIStream(), nsnull, outputFormat, aSaveCharset);
if (NS_SUCCEEDED(rv))
{
// if everything went OK and we're not just saving off a copy,
// store the new fileSpec in the doc
if (!aSaveCopy)
{
delete mFileSpec;
mFileSpec = new nsFileSpec(*aFileSpec);
if (!mFileSpec)
return NS_ERROR_OUT_OF_MEMORY;
// and mark the document as clean
ResetModCount();
}
}
return rv;
}
NS_IMETHODIMP
nsDocument::GetFileSpec(nsFileSpec& aFileSpec)
{
if (mFileSpec)
{
aFileSpec = *mFileSpec;
return NS_OK;
}
return NS_ERROR_NOT_INITIALIZED;
}
NS_IMETHODIMP
nsDocument::GetModCount(PRInt32 *outModCount)
{
if (!outModCount)
return NS_ERROR_NULL_POINTER;
*outModCount = mModCount;
return NS_OK;
}
NS_IMETHODIMP
nsDocument::ResetModCount()
{
mModCount = 0;
return NS_OK;
}
NS_IMETHODIMP
nsDocument::IncrementModCount(PRInt32 aNumMods)
{
mModCount += aNumMods;
//NS_ASSERTION(mModCount >= 0, "Modification count went negative");
return NS_OK;
}
//
// FindContent does a depth-first search from aStartNode
// and returns the first of aTest1 or aTest2 which it finds.
// I think.
//
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;
}
/**
* 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 aYes = PR_FALSE;
nsCOMPtr<nsIDOMNode> node (do_QueryInterface((nsIContent *) aContent));
aSelection->ContainsNode(node, PR_FALSE, &aYes);
return aYes;
}
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;
}