Mozilla/mozilla/layout/xml/document/src/nsXMLDocument.cpp
peterl%netscape.com 2709b267b2 added inline style sheet support for contained HTML
git-svn-id: svn://10.0.0.236/trunk@15589 18797224-902f-48f8-a5cc-f745e15eee43
1998-12-02 00:39:10 +00:00

486 lines
12 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.0 (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 Communicator client 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.
*/
#include "nsXMLDocument.h"
#include "nsWellFormedDTD.h"
#include "nsParserCIID.h"
#include "nsIParser.h"
#include "nsIXMLContent.h"
#include "nsIXMLContentSink.h"
#include "nsIPresShell.h"
#include "nsIPresContext.h"
#include "nsIContentViewerContainer.h"
#include "nsIWebShell.h"
#include "nsIDocumentLoader.h"
#include "nsIHTMLContent.h"
#include "nsHTMLParts.h"
#include "nsIHTMLStyleSheet.h"
#include "nsIHTMLCSSStyleSheet.h"
#include "nsIStyleSet.h"
#include "nsRepository.h"
#include "nsIDOMComment.h"
#include "nsIDOMElement.h"
#include "nsIDOMText.h"
// XXX The XML world depends on the html atoms
#include "nsHTMLAtoms.h"
static NS_DEFINE_IID(kIDOMDocumentIID, NS_IDOMDOCUMENT_IID);
static NS_DEFINE_IID(kIDocumentIID, NS_IDOCUMENT_IID);
static NS_DEFINE_IID(kIXMLDocumentIID, NS_IXMLDOCUMENT_IID);
static NS_DEFINE_IID(kIWebShellIID, NS_IWEB_SHELL_IID);
static NS_DEFINE_IID(kIDOMCommentIID, NS_IDOMCOMMENT_IID);
static NS_DEFINE_IID(kIDOMElementIID, NS_IDOMELEMENT_IID);
static NS_DEFINE_IID(kIDOMTextIID, NS_IDOMTEXT_IID);
static NS_DEFINE_IID(kIHTMLContentContainerIID, NS_IHTMLCONTENTCONTAINER_IID);
NS_LAYOUT nsresult
NS_NewXMLDocument(nsIDocument** aInstancePtrResult)
{
nsXMLDocument* doc = new nsXMLDocument();
return doc->QueryInterface(kIDocumentIID, (void**) aInstancePtrResult);
}
nsXMLDocument::nsXMLDocument()
{
mParser = nsnull;
mNameSpaces = nsnull;
mAttrStyleSheet = nsnull;
mInlineStyleSheet = nsnull;
mProlog = nsnull;
mEpilog = nsnull;
// XXX The XML world depends on the html atoms
nsHTMLAtoms::AddrefAtoms();
}
nsXMLDocument::~nsXMLDocument()
{
NS_IF_RELEASE(mParser);
if (nsnull != mNameSpaces) {
int i;
for (i = 0; i < mNameSpaces->Count(); i++) {
nsXMLNameSpace *ns = (nsXMLNameSpace *)mNameSpaces->ElementAt(i);
if (nsnull != ns) {
NS_IF_RELEASE(ns->mPrefix);
delete ns->mURI;
delete ns;
}
}
mNameSpaces = nsnull;
}
if (nsnull != mAttrStyleSheet) {
mAttrStyleSheet->SetOwningDocument(nsnull);
NS_RELEASE(mAttrStyleSheet);
}
if (nsnull != mInlineStyleSheet) {
mInlineStyleSheet->SetOwningDocument(nsnull);
NS_RELEASE(mInlineStyleSheet);
}
if (nsnull != mProlog) {
delete mProlog;
}
if (nsnull != mEpilog) {
delete mProlog;
}
}
NS_IMETHODIMP
nsXMLDocument::QueryInterface(REFNSIID aIID,
void** aInstancePtr)
{
if (NULL == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(kIXMLDocumentIID)) {
NS_ADDREF_THIS();
*aInstancePtr = (void**) (nsIXMLDocument *)this;
return NS_OK;
}
if (aIID.Equals(kIHTMLContentContainerIID)) {
NS_ADDREF_THIS();
*aInstancePtr = (void**) (nsIHTMLContentContainer *)this;
return NS_OK;
}
return nsDocument::QueryInterface(aIID, aInstancePtr);
}
nsrefcnt nsXMLDocument::AddRef()
{
return nsDocument::AddRef();
}
nsrefcnt nsXMLDocument::Release()
{
return nsDocument::Release();
}
NS_IMETHODIMP
nsXMLDocument::StartDocumentLoad(nsIURL *aUrl,
nsIContentViewerContainer* aContainer,
nsIStreamListener **aDocListener,
const char* aCommand)
{
nsresult rv = nsDocument::StartDocumentLoad(aUrl, aContainer,
aDocListener);
if (NS_FAILED(rv)) {
return rv;
}
if (nsnull != mAttrStyleSheet) {
mAttrStyleSheet->SetOwningDocument(nsnull);
NS_RELEASE(mAttrStyleSheet);
}
if (nsnull != mInlineStyleSheet) {
mInlineStyleSheet->SetOwningDocument(nsnull);
NS_RELEASE(mInlineStyleSheet);
}
nsIWebShell* webShell;
static NS_DEFINE_IID(kCParserIID, NS_IPARSER_IID);
static NS_DEFINE_IID(kCParserCID, NS_PARSER_IID);
rv = nsRepository::CreateInstance(kCParserCID,
nsnull,
kCParserIID,
(void **)&mParser);
if (NS_OK == rv) {
nsIXMLContentSink* sink;
aContainer->QueryInterface(kIWebShellIID, (void**)&webShell);
rv = NS_NewXMLContentSink(&sink, this, aUrl, webShell);
NS_IF_RELEASE(webShell);
if (NS_OK == rv) {
// For the HTML content within a document
if (NS_OK == NS_NewHTMLStyleSheet(&mAttrStyleSheet, aUrl, this)) {
AddStyleSheet(mAttrStyleSheet); // tell the world about our new style sheet
}
if (NS_OK == NS_NewHTMLCSSStyleSheet(&mInlineStyleSheet, aUrl, this)) {
AddStyleSheet(mInlineStyleSheet); // tell the world about our new style sheet
}
// Set the parser as the stream listener for the document loader...
static NS_DEFINE_IID(kIStreamListenerIID, NS_ISTREAMLISTENER_IID);
rv = mParser->QueryInterface(kIStreamListenerIID, (void**)aDocListener);
if (NS_OK == rv) {
nsIDTD* theDTD=0;
// XXX For now, we'll use the HTML DTD
NS_NewWellFormed_DTD(&theDTD);
mParser->RegisterDTD(theDTD);
mParser->SetCommand(aCommand);
mParser->SetContentSink(sink);
mParser->Parse(aUrl);
}
NS_RELEASE(sink);
}
}
return rv;
}
NS_IMETHODIMP
nsXMLDocument::EndLoad()
{
NS_IF_RELEASE(mParser);
return nsDocument::EndLoad();
}
NS_IMETHODIMP
nsXMLDocument::GetAttributeStyleSheet(nsIHTMLStyleSheet** aResult)
{
NS_PRECONDITION(nsnull != aResult, "null ptr");
if (nsnull == aResult) {
return NS_ERROR_NULL_POINTER;
}
*aResult = mAttrStyleSheet;
if (nsnull == mAttrStyleSheet) {
return NS_ERROR_NOT_AVAILABLE; // probably not the right error...
}
else {
NS_ADDREF(mAttrStyleSheet);
}
return NS_OK;
}
NS_IMETHODIMP
nsXMLDocument::GetInlineStyleSheet(nsIHTMLCSSStyleSheet** aResult)
{
NS_PRECONDITION(nsnull != aResult, "null ptr");
if (nsnull == aResult) {
return NS_ERROR_NULL_POINTER;
}
*aResult = mInlineStyleSheet;
if (nsnull == mInlineStyleSheet) {
return NS_ERROR_NOT_AVAILABLE; // probably not the right error...
}
else {
NS_ADDREF(mInlineStyleSheet);
}
return NS_OK;
}
void nsXMLDocument::AddStyleSheetToSet(nsIStyleSheet* aSheet, nsIStyleSet* aSet)
{
if ((nsnull != mInlineStyleSheet) && (aSheet != mInlineStyleSheet)) {
aSet->InsertDocStyleSheetAfter(aSheet, mInlineStyleSheet);
}
else {
aSet->InsertDocStyleSheetBefore(aSheet, nsnull); // put it in front
}
}
// nsIDOMDocument interface
NS_IMETHODIMP
nsXMLDocument::GetDoctype(nsIDOMDocumentType** aDocumentType)
{
// XXX TBI
*aDocumentType = nsnull;
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsXMLDocument::CreateCDATASection(const nsString& aData, nsIDOMCDATASection** aReturn)
{
// XXX TBI
*aReturn = nsnull;
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsXMLDocument::CreateEntityReference(const nsString& aName, nsIDOMEntityReference** aReturn)
{
// XXX TBI
*aReturn = nsnull;
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsXMLDocument::CreateComment(const nsString& aData, nsIDOMComment** aReturn)
{
// XXX Should just be regular nsIContent
nsIHTMLContent* comment = nsnull;
nsresult rv = NS_NewCommentNode(&comment);
if (NS_OK == rv) {
rv = comment->QueryInterface(kIDOMCommentIID, (void**)aReturn);
(*aReturn)->AppendData(aData);
}
return rv;
}
NS_IMETHODIMP
nsXMLDocument::CreateProcessingInstruction(const nsString& aTarget, const nsString& aData, nsIDOMProcessingInstruction** aReturn)
{
// XXX TBI
*aReturn = nsnull;
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsXMLDocument::CreateAttribute(const nsString& aName, nsIDOMAttr** aReturn)
{
// XXX TBI
*aReturn = nsnull;
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsXMLDocument::CreateElement(const nsString& aTagName,
nsIDOMElement** aReturn)
{
// XXX Should actually check parse namespace, determine
// current namespace scope and, potentially, create new
// HTML content form tags with a HTML prefix.
nsIXMLContent* content;
nsIAtom* tag = NS_NewAtom(aTagName);
nsresult rv = NS_NewXMLElement(&content, tag);
NS_RELEASE(tag);
if (NS_OK != rv) {
return rv;
}
rv = content->QueryInterface(kIDOMElementIID, (void**)aReturn);
return rv;
}
NS_IMETHODIMP
nsXMLDocument::CreateTextNode(const nsString& aData, nsIDOMText** aReturn)
{
// XXX Should just be regular nsIContent
nsIHTMLContent* text = nsnull;
nsresult rv = NS_NewTextNode(&text);
if (NS_OK == rv) {
rv = text->QueryInterface(kIDOMTextIID, (void**)aReturn);
(*aReturn)->AppendData(aData);
}
return rv;
}
// nsIXMLDocument interface
NS_IMETHODIMP
nsXMLDocument::RegisterNameSpace(nsIAtom *aPrefix, const nsString& aURI,
PRInt32& aNameSpaceId)
{
if (nsnull == mNameSpaces) {
mNameSpaces = new nsVoidArray();
if (nsnull == mNameSpaces) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
nsXMLNameSpace* ns = new nsXMLNameSpace;
if (nsnull == ns) {
return NS_ERROR_OUT_OF_MEMORY;
}
ns->mPrefix = aPrefix;
NS_IF_ADDREF(ns->mPrefix);
ns->mURI = new nsString(aURI);
mNameSpaces->AppendElement((void *)ns);
aNameSpaceId = mNameSpaces->Count();
return NS_OK;
}
NS_IMETHODIMP
nsXMLDocument::GetNameSpaceURI(PRInt32 aNameSpaceId, nsString& aURI)
{
if (nsnull == mNameSpaces) {
return NS_ERROR_ILLEGAL_VALUE;
}
nsXMLNameSpace *ns = (nsXMLNameSpace *)mNameSpaces->ElementAt(aNameSpaceId - 1);
if (nsnull == ns) {
return NS_ERROR_ILLEGAL_VALUE;
}
aURI.SetString(*ns->mURI);
return NS_OK;
}
NS_IMETHODIMP
nsXMLDocument::GetNameSpacePrefix(PRInt32 aNameSpaceId, nsIAtom*& aPrefix)
{
if (nsnull == mNameSpaces) {
return NS_ERROR_ILLEGAL_VALUE;
}
nsXMLNameSpace *ns = (nsXMLNameSpace *)mNameSpaces->ElementAt(aNameSpaceId - 1);
if (nsnull == ns) {
return NS_ERROR_ILLEGAL_VALUE;
}
aPrefix = ns->mPrefix;
NS_IF_ADDREF(aPrefix);
return NS_OK;
}
NS_IMETHODIMP
nsXMLDocument::PrologElementAt(PRInt32 aIndex, nsIContent** aContent)
{
if (nsnull == mProlog) {
*aContent = nsnull;
}
else {
*aContent = (nsIContent *)mProlog->ElementAt(aIndex);
NS_ADDREF(*aContent);
}
return NS_OK;
}
NS_IMETHODIMP
nsXMLDocument::PrologCount(PRInt32* aCount)
{
if (nsnull == mProlog) {
*aCount = 0;
}
else {
*aCount = mProlog->Count();
}
return NS_OK;
}
NS_IMETHODIMP
nsXMLDocument::AppendToProlog(nsIContent* aContent)
{
if (nsnull == mProlog) {
mProlog = new nsVoidArray();
}
mProlog->AppendElement((void *)aContent);
return NS_OK;
}
NS_IMETHODIMP
nsXMLDocument::EpilogElementAt(PRInt32 aIndex, nsIContent** aContent)
{
if (nsnull == mEpilog) {
*aContent = nsnull;
}
else {
*aContent = (nsIContent *)mEpilog->ElementAt(aIndex);
NS_ADDREF(*aContent);
}
return NS_OK;
}
NS_IMETHODIMP
nsXMLDocument::EpilogCount(PRInt32* aCount)
{
if (nsnull == mEpilog) {
*aCount = 0;
}
else {
*aCount = mEpilog->Count();
}
return NS_OK;
}
NS_IMETHODIMP
nsXMLDocument::AppendToEpilog(nsIContent* aContent)
{
if (nsnull == mEpilog) {
mEpilog = new nsVoidArray();
}
mEpilog->AppendElement((void *)aContent);
return NS_OK;
}