Bug 63558, we now store XML declaration in the document and can serialize it. There is fix for 158617 as well, newlines behave properly around doctype. r=bzbarsky, sr=jst.

This commit is contained in:
heikki%netscape.com 2002-08-13 18:41:16 +00:00
parent 47a05fb135
commit 3c4832e229
24 changed files with 339 additions and 10 deletions

View File

@ -49,6 +49,7 @@ class nsIDOMProcessingInstruction; /* forward declaration */
class nsIDOMComment; /* forward declaration */
class nsIDOMDocumentType; /* forward declaration */
class nsIDOMElement; /* forward declaration */
class nsIDOMDocument; /* forward declaration */
/* starting interface: nsIContentSerializer */
#define NS_ICONTENTSERIALIZER_IID_STR "61e9b9a3-d30c-429e-b0cf-ade73466df06"
@ -91,6 +92,14 @@ class nsIContentSerializer : public nsISupports {
nsAString& aStr) = 0;
NS_IMETHOD Flush(nsAString& aStr) = 0;
/**
* Append any items in the beginning of the document that won't be
* serialized by other methods. XML declaration is the most likely
* thing this method can produce.
*/
NS_IMETHOD AppendDocumentStart(nsIDOMDocument *aDocument,
nsAString& aStr) = 0;
};
#define NS_CONTENTSERIALIZER_CONTRACTID_PREFIX \

View File

@ -157,6 +157,13 @@ mozSanitizingHTMLSerializer::Flush(nsAString& aStr)
return NS_OK;
}
NS_IMETHODIMP
mozSanitizingHTMLSerializer::AppendDocumentStart(nsIDOMDocument *aDocument,
nsAString& aStr)
{
return NS_OK;
}
void
mozSanitizingHTMLSerializer::Write(const nsAString& aString)
{

View File

@ -89,6 +89,9 @@ public:
NS_IMETHOD AppendElementEnd(nsIDOMElement *aElement, nsAString& aStr);
NS_IMETHOD Flush(nsAString& aStr);
NS_IMETHOD AppendDocumentStart(nsIDOMDocument *aDocument,
nsAString& aStr);
// nsIContentSink
NS_IMETHOD WillBuildModel(void) { return NS_OK; }
NS_IMETHOD DidBuildModel(PRInt32 aQualityLevel) { return NS_OK; }

View File

@ -59,6 +59,7 @@
#include "nsIDOMDocumentType.h"
#include "nsIDOMNodeList.h"
#include "nsIDOMRange.h"
#include "nsIDOMDocument.h"
#include "nsICharsetConverterManager.h"
#include "nsICharsetConverterManager2.h"
#include "nsHTMLAtoms.h"
@ -159,12 +160,12 @@ protected:
PRUint32 mEndDepth;
PRInt32 mStartRootIndex;
PRInt32 mEndRootIndex;
PRBool mHaltRangeHint;
nsAutoVoidArray mCommonAncestors;
nsAutoVoidArray mStartNodes;
nsAutoVoidArray mStartOffsets;
nsAutoVoidArray mEndNodes;
nsAutoVoidArray mEndOffsets;
PRPackedBool mHaltRangeHint;
PRPackedBool mIsCopying; // Set to PR_TRUE only while copying
};
@ -937,9 +938,14 @@ nsDocumentEncoder::EncodeToString(nsAString& aOutputString)
mRange = nsnull;
} else {
nsCOMPtr<nsIDOMNode> doc(do_QueryInterface(mDocument));
nsCOMPtr<nsIDOMDocument> domdoc(do_QueryInterface(mDocument));
rv = mSerializer->AppendDocumentStart(domdoc, aOutputString);
rv = SerializeToStringRecursive(doc, aOutputString);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIDOMNode> doc(do_QueryInterface(mDocument));
rv = SerializeToStringRecursive(doc, aOutputString);
}
}
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -206,6 +206,13 @@ nsHTMLContentSerializer::AppendText(nsIDOMText* aText,
return NS_OK;
}
NS_IMETHODIMP
nsHTMLContentSerializer::AppendDocumentStart(nsIDOMDocument *aDocument,
nsAString& aStr)
{
return NS_OK;
}
PRBool
nsHTMLContentSerializer::IsJavaScript(nsIAtom* aAttrNameAtom, const nsAString& aValueString)
{

View File

@ -64,6 +64,9 @@ class nsHTMLContentSerializer : public nsXMLContentSerializer {
NS_IMETHOD AppendElementEnd(nsIDOMElement *aElement,
nsAString& aStr);
NS_IMETHOD AppendDocumentStart(nsIDOMDocument *aDocument,
nsAString& aStr);
protected:
PRBool HasDirtyAttr(nsIContent* aContent);
PRBool LineBreakBeforeOpen(nsIAtom* aName, PRBool aHasDirtyAttr);

View File

@ -401,6 +401,13 @@ nsPlainTextSerializer::Flush(nsAString& aStr)
return NS_OK;
}
NS_IMETHODIMP
nsPlainTextSerializer::AppendDocumentStart(nsIDOMDocument *aDocument,
nsAString& aStr)
{
return NS_OK;
}
NS_IMETHODIMP
nsPlainTextSerializer::OpenContainer(const nsIParserNode& aNode)
{

View File

@ -86,6 +86,9 @@ public:
nsAString& aStr);
NS_IMETHOD Flush(nsAString& aStr);
NS_IMETHOD AppendDocumentStart(nsIDOMDocument *aDocument,
nsAString& aStr);
// nsIContentSink
NS_IMETHOD WillBuildModel(void) { return NS_OK; }
NS_IMETHOD DidBuildModel(PRInt32 aQualityLevel) { return NS_OK; }

View File

@ -43,6 +43,7 @@
#include "nsIDOMCDATASection.h"
#include "nsIDOMProcessingInstruction.h"
#include "nsIDOMComment.h"
#include "nsIDOMDocument.h"
#include "nsIDOMDocumentType.h"
#include "nsIDOMElement.h"
#include "nsIContent.h"
@ -54,6 +55,7 @@
#include "prprf.h"
#include "nsUnicharUtils.h"
#include "nsCRT.h"
#include "nsIXMLDocument.h"
typedef struct {
nsString mPrefix;
@ -754,3 +756,35 @@ nsXMLContentSerializer::IsShorthandAttr(const nsIAtom* aAttrName,
return PR_FALSE;
}
NS_IMETHODIMP
nsXMLContentSerializer::AppendDocumentStart(nsIDOMDocument *aDocument,
nsAString& aStr)
{
NS_ENSURE_ARG_POINTER(aDocument);
nsCOMPtr<nsIXMLDocument> xml(do_QueryInterface(aDocument));
NS_ENSURE_TRUE(xml, NS_ERROR_UNEXPECTED);
nsAutoString version, encoding, standalone;
xml->GetXMLDeclaration(version, encoding, standalone);
if (version.IsEmpty())
return NS_OK; // A declaration must have version, or there is no decl
NS_NAMED_LITERAL_STRING(endQuote, "\"");
aStr += NS_LITERAL_STRING("<?xml version=\"") + version + endQuote;
if (!encoding.IsEmpty()) {
aStr += NS_LITERAL_STRING(" encoding=\"") + encoding + endQuote;
}
if (!standalone.IsEmpty()) {
aStr += NS_LITERAL_STRING(" standalone=\"") + standalone + endQuote;
}
aStr += NS_LITERAL_STRING("?>");
return NS_OK;
}

View File

@ -83,6 +83,9 @@ class nsXMLContentSerializer : public nsIContentSerializer {
NS_IMETHOD Flush(nsAString& aStr) { return NS_OK; }
NS_IMETHOD AppendDocumentStart(nsIDOMDocument *aDocument,
nsAString& aStr);
protected:
virtual void AppendToString(const PRUnichar* aStr,
PRInt32 aLength,

View File

@ -57,6 +57,17 @@ public:
NS_DEFINE_STATIC_IID_ACCESSOR(NS_IXMLDOCUMENT_IID)
NS_IMETHOD SetDefaultStylesheets(nsIURI* aUrl)=0;
/**
* Set and get XML declaration. Notice that if version is empty,
* there can be no XML declaration (it is a required part).
*/
NS_IMETHOD SetXMLDeclaration(const nsAString& aVersion,
const nsAString& aEncoding,
const nsAString& Standalone)=0;
NS_IMETHOD GetXMLDeclaration(nsAString& aVersion,
nsAString& aEncoding,
nsAString& Standalone)=0;
};
#endif // nsIXMLDocument_h___

View File

@ -1832,6 +1832,8 @@ nsXMLContentSink::HandleDoctypeDecl(const nsAString & aSubset,
const nsAString & aPublicId,
nsISupports* aCatalogData)
{
FlushText();
nsresult rv = NS_OK;
nsCOMPtr<nsIDOMDocument> doc(do_QueryInterface(mDocument));
@ -1949,6 +1951,32 @@ nsXMLContentSink::HandleProcessingInstruction(const PRUnichar *aTarget,
return result;
}
NS_IMETHODIMP
nsXMLContentSink::HandleXMLDeclaration(const PRUnichar *aData,
PRUint32 aLength)
{
NS_ENSURE_ARG_POINTER(aData);
// strlen("<?xml version='a'?>") == 19, shortest decl
NS_ENSURE_TRUE(aLength >= 19, NS_ERROR_INVALID_ARG);
nsCOMPtr<nsIXMLDocument> xml(do_QueryInterface(mDocument));
NS_WARN_IF_FALSE(xml, "why is XML sink building non-XML document?");
if (!xml)
return NS_OK;
// <?xml version="a" encoding="a" standalone="yes|no"?>
const nsAString& data = Substring(aData + 6, aData + aLength - 2); // strip out "<?xml " and "?>"
nsAutoString version, encoding, standalone;
// XXX If this is too slow we need to parse this here
nsParserUtils::GetQuotedAttributeValue(data, NS_LITERAL_STRING("version"), version);
nsParserUtils::GetQuotedAttributeValue(data, NS_LITERAL_STRING("encoding"), encoding);
nsParserUtils::GetQuotedAttributeValue(data, NS_LITERAL_STRING("standalone"), standalone);
return xml->SetXMLDeclaration(version, encoding, standalone);
}
NS_IMETHODIMP
nsXMLContentSink::ReportError(const PRUnichar* aErrorText,
const PRUnichar* aSourceText)

View File

@ -221,7 +221,7 @@ NS_NewXMLDocument(nsIDocument** aInstancePtrResult)
nsXMLDocument::nsXMLDocument()
: mAttrStyleSheet(nsnull), mInlineStyleSheet(nsnull),
mCountCatalogSheets(0), mParser(nsnull),
mCrossSiteAccessEnabled(PR_FALSE)
mCrossSiteAccessEnabled(PR_FALSE), mXMLDeclarationBits(0)
{
}
@ -422,9 +422,12 @@ nsXMLDocument::Load(const nsAString& aUrl)
// Find out if UniversalBrowserRead privileges are enabled - we will need this
// in case of a redirect
rv = secMan->IsCapabilityEnabled("UniversalBrowserRead", &mCrossSiteAccessEnabled);
PRBool crossSiteAccessEnabled;
rv = secMan->IsCapabilityEnabled("UniversalBrowserRead", &crossSiteAccessEnabled);
if (NS_FAILED(rv)) return rv;
mCrossSiteAccessEnabled = crossSiteAccessEnabled;
// Create a channel
rv = NS_NewChannel(getter_AddRefs(channel), uri, nsnull, nsnull, this);
if (NS_FAILED(rv)) return rv;
@ -1094,6 +1097,63 @@ nsXMLDocument::SetDefaultStylesheets(nsIURI* aUrl)
return result;
}
NS_IMETHODIMP
nsXMLDocument::SetXMLDeclaration(const nsAString& aVersion,
const nsAString& aEncoding,
const nsAString& aStandalone)
{
if (aVersion.IsEmpty()) {
mXMLDeclarationBits = 0;
return NS_OK;
}
mXMLDeclarationBits = XML_DECLARATION_BITS_DECLARATION_EXISTS;
if (!aEncoding.IsEmpty()) {
mXMLDeclarationBits |= XML_DECLARATION_BITS_ENCODING_EXISTS;
}
if (aStandalone.Equals(NS_LITERAL_STRING("yes"))) {
mXMLDeclarationBits |= XML_DECLARATION_BITS_STANDALONE_EXISTS |
XML_DECLARATION_BITS_STANDALONE_YES;
} else if (aStandalone.Equals(NS_LITERAL_STRING("no"))) {
mXMLDeclarationBits |= XML_DECLARATION_BITS_STANDALONE_EXISTS;
}
return NS_OK;
}
NS_IMETHODIMP
nsXMLDocument::GetXMLDeclaration(nsAString& aVersion,
nsAString& aEncoding,
nsAString& aStandalone)
{
aVersion.Truncate();
aEncoding.Truncate();
aStandalone.Truncate();
if (!(mXMLDeclarationBits & XML_DECLARATION_BITS_DECLARATION_EXISTS)) {
return NS_OK;
}
aVersion.Assign(NS_LITERAL_STRING("1.0")); // always until we start supporting 1.1 etc.
if (mXMLDeclarationBits & XML_DECLARATION_BITS_ENCODING_EXISTS) {
GetDocumentCharacterSet(aEncoding); // This is what we have stored, not necessarily what was written in the original
}
if (mXMLDeclarationBits & XML_DECLARATION_BITS_STANDALONE_EXISTS) {
if (mXMLDeclarationBits & XML_DECLARATION_BITS_STANDALONE_YES) {
aStandalone.Assign(NS_LITERAL_STRING("yes"));
} else {
aStandalone.Assign(NS_LITERAL_STRING("no"));
}
}
return NS_OK;
}
NS_IMETHODIMP
nsXMLDocument::SetBaseTarget(const nsAString &aBaseTarget)
{

View File

@ -53,6 +53,11 @@ class nsIDOMNode;
class nsICSSLoader;
class nsIURI;
#define XML_DECLARATION_BITS_DECLARATION_EXISTS 1
#define XML_DECLARATION_BITS_ENCODING_EXISTS 2
#define XML_DECLARATION_BITS_STANDALONE_EXISTS 4
#define XML_DECLARATION_BITS_STANDALONE_YES 8
class nsXMLDocument : public nsMarkupDocument,
public nsIXMLDocument,
public nsIHTMLContentContainer,
@ -107,6 +112,12 @@ public:
// nsIXMLDocument interface
NS_IMETHOD SetDefaultStylesheets(nsIURI* aUrl);
NS_IMETHOD SetXMLDeclaration(const nsAString& aVersion,
const nsAString& aEncoding,
const nsAString& Standalone);
NS_IMETHOD GetXMLDeclaration(nsAString& aVersion,
nsAString& aEncoding,
nsAString& Standalone);
// nsIHTMLContentContainer
NS_IMETHOD GetAttributeStyleSheet(nsIHTMLStyleSheet** aResult);
@ -142,7 +153,9 @@ protected:
nsIParser *mParser;
nsCOMPtr<nsIScriptContext> mScriptContext;
PRBool mCrossSiteAccessEnabled;
PRPackedBool mCrossSiteAccessEnabled;
PRUint8 mXMLDeclarationBits;
};

View File

@ -1106,6 +1106,15 @@ XULContentSinkImpl::HandleProcessingInstruction(const PRUnichar *aTarget,
return NS_OK;
}
NS_IMETHODIMP
XULContentSinkImpl::HandleXMLDeclaration(const PRUnichar *aData,
const PRUint32 aLength)
{
return NS_OK;
}
NS_IMETHODIMP
XULContentSinkImpl::ReportError(const PRUnichar* aErrorText,
const PRUnichar* aSourceText)

View File

@ -2670,6 +2670,27 @@ nsXULDocument::SetTitle(const PRUnichar *aTitle)
return SetTitle(nsDependentString(aTitle));
}
NS_IMETHODIMP
nsXULDocument::SetXMLDeclaration(const nsAString& aVersion,
const nsAString& aEncoding,
const nsAString& aStandalone)
{
return NS_OK;
}
NS_IMETHODIMP
nsXULDocument::GetXMLDeclaration(nsAString& aVersion,
nsAString& aEncoding,
nsAString& aStandalone)
{
aVersion.Truncate();
aEncoding.Truncate();
aStandalone.Truncate();
return NS_OK;
}
//----------------------------------------------------------------------
//
// nsIXULDocument interface

View File

@ -351,6 +351,12 @@ public:
// nsIXMLDocument interface
NS_IMETHOD SetDefaultStylesheets(nsIURI* aUrl);
NS_IMETHOD SetTitle(const PRUnichar *aTitle);
NS_IMETHOD SetXMLDeclaration(const nsAString& aVersion,
const nsAString& aEncoding,
const nsAString& Standalone);
NS_IMETHOD GetXMLDeclaration(nsAString& aVersion,
nsAString& aEncoding,
nsAString& Standalone);
// nsIXULDocument interface
NS_IMETHOD AddElementForID(const nsAString& aID, nsIContent* aElement);

View File

@ -66,6 +66,16 @@ interface nsIExpatSink : nsISupports
void HandleProcessingInstruction(in wstring aTarget,
in wstring aData);
/**
* Handle the XML Declaration.
*
* @param aData The string.
* @param aLength The length of the declaration from
* opening '<' to closing '>'.
**/
void HandleXMLDeclaration(in wstring aData,
in unsigned long aLength);
void ReportError(in wstring aErrorText,
in wstring aSourceText);
};

View File

@ -300,8 +300,9 @@ NS_NewExpatDriver(nsIDTD** aResult) {
nsExpatDriver::nsExpatDriver()
:mExpatParser(0),
mInCData(0),
mInDoctype(0),
mInCData(PR_FALSE),
mInDoctype(PR_FALSE),
mHandledXMLDeclaration(PR_FALSE),
mBytePosition(0),
mInternalState(NS_OK),
mBytesParsed(0),
@ -399,6 +400,30 @@ nsExpatDriver::HandleProcessingInstruction(const PRUnichar *aTarget,
return NS_OK;
}
nsresult
nsExpatDriver::HandleXMLDeclaration(const PRUnichar *aValue,
const PRUint32 aLength)
{
mHandledXMLDeclaration = PR_TRUE;
// <?xml version='a'?>
// 0123456789012345678
PRUint32 i = 17; // ?> can start at position 17 at the earliest
for (; i < aLength; i++) {
if (aValue[i] == '?')
break;
}
// +1 because index starts from 0
// +1 because '>' follows '?'
i += 2;
if (i > aLength)
return NS_OK; // Bad declaration
return mSink->HandleXMLDeclaration(aValue, i);
}
nsresult
nsExpatDriver::HandleDefault(const PRUnichar *aValue,
const PRUint32 aLength)
@ -409,6 +434,15 @@ nsExpatDriver::HandleDefault(const PRUnichar *aValue,
mDoctypeText.Append(aValue, aLength);
}
else if (mSink) {
if (!mHandledXMLDeclaration && !mBytesParsed) {
static const PRUnichar xmlDecl[] = {'<', '?', 'x', 'm', 'l', ' ', '\0'};
// strlen("<?xml version='a'?>") == 19, shortest decl
if ((aLength >= 19) &&
(nsCRT::strncmp(aValue, xmlDecl, 6) == 0)) {
HandleXMLDeclaration(aValue, aLength);
}
}
static const PRUnichar newline[] = {'\n','\0'};
for (PRUint32 i = 0; i < aLength && NS_SUCCEEDED(mInternalState); i++) {
if (aValue[i] == '\n' || aValue[i] == '\r') {

View File

@ -68,6 +68,7 @@ public:
nsresult HandleCharacterData(const PRUnichar *aCData, const PRUint32 aLength);
nsresult HandleComment(const PRUnichar *aName);
nsresult HandleProcessingInstruction(const PRUnichar *aTarget, const PRUnichar *aData);
nsresult HandleXMLDeclaration(const PRUnichar *aData, const PRUint32 aLength);
nsresult HandleDefault(const PRUnichar *aData, const PRUint32 aLength);
nsresult HandleStartCdataSection();
nsresult HandleEndCdataSection();
@ -93,6 +94,7 @@ protected:
nsString mDoctypeText;
PRPackedBool mInCData;
PRPackedBool mInDoctype;
PRPackedBool mHandledXMLDeclaration;
PRInt32 mBytePosition;
nsresult mInternalState;
PRUint32 mBytesParsed;

View File

@ -66,6 +66,16 @@ interface nsIExpatSink : nsISupports
void HandleProcessingInstruction(in wstring aTarget,
in wstring aData);
/**
* Handle the XML Declaration.
*
* @param aData The string.
* @param aLength The length of the declaration from
* opening '<' to closing '>'.
**/
void HandleXMLDeclaration(in wstring aData,
in unsigned long aLength);
void ReportError(in wstring aErrorText,
in wstring aSourceText);
};

View File

@ -300,8 +300,9 @@ NS_NewExpatDriver(nsIDTD** aResult) {
nsExpatDriver::nsExpatDriver()
:mExpatParser(0),
mInCData(0),
mInDoctype(0),
mInCData(PR_FALSE),
mInDoctype(PR_FALSE),
mHandledXMLDeclaration(PR_FALSE),
mBytePosition(0),
mInternalState(NS_OK),
mBytesParsed(0),
@ -399,6 +400,30 @@ nsExpatDriver::HandleProcessingInstruction(const PRUnichar *aTarget,
return NS_OK;
}
nsresult
nsExpatDriver::HandleXMLDeclaration(const PRUnichar *aValue,
const PRUint32 aLength)
{
mHandledXMLDeclaration = PR_TRUE;
// <?xml version='a'?>
// 0123456789012345678
PRUint32 i = 17; // ?> can start at position 17 at the earliest
for (; i < aLength; i++) {
if (aValue[i] == '?')
break;
}
// +1 because index starts from 0
// +1 because '>' follows '?'
i += 2;
if (i > aLength)
return NS_OK; // Bad declaration
return mSink->HandleXMLDeclaration(aValue, i);
}
nsresult
nsExpatDriver::HandleDefault(const PRUnichar *aValue,
const PRUint32 aLength)
@ -409,6 +434,15 @@ nsExpatDriver::HandleDefault(const PRUnichar *aValue,
mDoctypeText.Append(aValue, aLength);
}
else if (mSink) {
if (!mHandledXMLDeclaration && !mBytesParsed) {
static const PRUnichar xmlDecl[] = {'<', '?', 'x', 'm', 'l', ' ', '\0'};
// strlen("<?xml version='a'?>") == 19, shortest decl
if ((aLength >= 19) &&
(nsCRT::strncmp(aValue, xmlDecl, 6) == 0)) {
HandleXMLDeclaration(aValue, aLength);
}
}
static const PRUnichar newline[] = {'\n','\0'};
for (PRUint32 i = 0; i < aLength && NS_SUCCEEDED(mInternalState); i++) {
if (aValue[i] == '\n' || aValue[i] == '\r') {

View File

@ -68,6 +68,7 @@ public:
nsresult HandleCharacterData(const PRUnichar *aCData, const PRUint32 aLength);
nsresult HandleComment(const PRUnichar *aName);
nsresult HandleProcessingInstruction(const PRUnichar *aTarget, const PRUnichar *aData);
nsresult HandleXMLDeclaration(const PRUnichar *aData, const PRUint32 aLength);
nsresult HandleDefault(const PRUnichar *aData, const PRUint32 aLength);
nsresult HandleStartCdataSection();
nsresult HandleEndCdataSection();
@ -93,6 +94,7 @@ protected:
nsString mDoctypeText;
PRPackedBool mInCData;
PRPackedBool mInDoctype;
PRPackedBool mHandledXMLDeclaration;
PRInt32 mBytePosition;
nsresult mInternalState;
PRUint32 mBytesParsed;

View File

@ -625,6 +625,13 @@ RDFContentSinkImpl::HandleProcessingInstruction(const PRUnichar *aTarget,
return NS_OK;
}
NS_IMETHODIMP
RDFContentSinkImpl::HandleXMLDeclaration(const PRUnichar *aData,
PRUint32 aLength)
{
return NS_OK;
}
NS_IMETHODIMP
RDFContentSinkImpl::ReportError(const PRUnichar* aErrorText,
const PRUnichar* aSourceText)