From 38126837d0e7c7385100f43b4103c4c238f81485 Mon Sep 17 00:00:00 2001 From: "cvshook%sicking.cc" Date: Tue, 3 Oct 2006 02:22:22 +0000 Subject: [PATCH] Bug 221335: Speed up output by using internal methods and interfaces rather than nsIDOMNode and friends. r/sr=peterv --- content/base/src/nsContentUtils.cpp | 4 + content/base/src/nsGkAtomList.h | 1 + content/xml/document/src/nsXMLContentSink.cpp | 15 +- content/xml/document/src/nsXMLContentSink.h | 4 +- content/xslt/public/nsIDocumentTransformer.h | 8 +- content/xslt/src/base/txError.h | 3 + content/xslt/src/base/txStringUtils.h | 9 + .../src/xpath/txMozillaXPathTreeWalker.cpp | 16 + content/xslt/src/xpath/txXPathTreeWalker.h | 1 + content/xslt/src/xslt/txBufferingHandler.cpp | 168 ++++- content/xslt/src/xslt/txExecutionState.cpp | 32 +- content/xslt/src/xslt/txExecutionState.h | 10 +- content/xslt/src/xslt/txInstructions.cpp | 213 +++--- content/xslt/src/xslt/txInstructions.h | 2 + content/xslt/src/xslt/txMozillaTextOutput.cpp | 171 +++-- content/xslt/src/xslt/txMozillaTextOutput.h | 8 +- content/xslt/src/xslt/txMozillaXMLOutput.cpp | 674 ++++++++++-------- content/xslt/src/xslt/txMozillaXMLOutput.h | 49 +- .../xslt/src/xslt/txMozillaXSLTProcessor.cpp | 6 +- content/xslt/src/xslt/txTextHandler.cpp | 35 +- content/xslt/src/xslt/txUnknownHandler.cpp | 82 ++- content/xslt/src/xslt/txUnknownHandler.h | 11 +- content/xslt/src/xslt/txXMLEventHandler.h | 86 ++- 23 files changed, 934 insertions(+), 674 deletions(-) diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 66d21331c077..e0825e5611c9 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -3188,6 +3188,10 @@ PRBool nsContentUtils::IsValidNodeName(nsIAtom *aLocalName, nsIAtom *aPrefix, PRInt32 aNamespaceID) { + if (aNamespaceID == kNameSpaceID_Unknown) { + return PR_FALSE; + } + if (!aPrefix) { // If the prefix is null, then either the QName must be xmlns or the // namespace must not be XMLNS. diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index 67323274867e..ef643df085ff 100755 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -804,6 +804,7 @@ GK_ATOM(topmargin, "topmargin") GK_ATOM(toppadding, "toppadding") GK_ATOM(tr, "tr") GK_ATOM(transform, "transform") +GK_ATOM(transformiix, "transformiix") GK_ATOM(translate, "translate") GK_ATOM(transparent, "transparent") GK_ATOM(tree, "tree") diff --git a/content/xml/document/src/nsXMLContentSink.cpp b/content/xml/document/src/nsXMLContentSink.cpp index 703f64b2ac1b..5ab7dff465dc 100644 --- a/content/xml/document/src/nsXMLContentSink.cpp +++ b/content/xml/document/src/nsXMLContentSink.cpp @@ -346,33 +346,36 @@ nsXMLContentSink::DidBuildModel() } NS_IMETHODIMP -nsXMLContentSink::OnDocumentCreated(nsIDOMDocument* aResultDocument) +nsXMLContentSink::OnDocumentCreated(nsIDocument* aResultDocument) { NS_ENSURE_ARG(aResultDocument); nsCOMPtr contentViewer; mDocShell->GetContentViewer(getter_AddRefs(contentViewer)); if (contentViewer) { - return contentViewer->SetDOMDocument(aResultDocument); + nsCOMPtr doc = do_QueryInterface(aResultDocument); + return contentViewer->SetDOMDocument(doc); } return NS_OK; } NS_IMETHODIMP nsXMLContentSink::OnTransformDone(nsresult aResult, - nsIDOMDocument* aResultDocument) + nsIDocument* aResultDocument) { NS_ASSERTION(NS_FAILED(aResult) || aResultDocument, "Don't notify about transform success without a document."); + nsCOMPtr domDoc = do_QueryInterface(aResultDocument); + nsCOMPtr contentViewer; mDocShell->GetContentViewer(getter_AddRefs(contentViewer)); if (NS_FAILED(aResult) && contentViewer) { // Transform failed. - if (aResultDocument) { + if (domDoc) { // We have an error document. - contentViewer->SetDOMDocument(aResultDocument); + contentViewer->SetDOMDocument(domDoc); } else { // We don't have an error document, display the @@ -386,7 +389,7 @@ nsXMLContentSink::OnTransformDone(nsresult aResult, if (NS_SUCCEEDED(aResult) || aResultDocument) { // Transform succeeded or it failed and we have an error // document to display. - mDocument = do_QueryInterface(aResultDocument); + mDocument = aResultDocument; } nsIScriptLoader *loader = originalDocument->GetScriptLoader(); diff --git a/content/xml/document/src/nsXMLContentSink.h b/content/xml/document/src/nsXMLContentSink.h index f97b6d4f0b04..775d00c0eb92 100644 --- a/content/xml/document/src/nsXMLContentSink.h +++ b/content/xml/document/src/nsXMLContentSink.h @@ -89,8 +89,8 @@ public: virtual nsISupports *GetTarget(); // nsITransformObserver - NS_IMETHOD OnDocumentCreated(nsIDOMDocument *aResultDocument); - NS_IMETHOD OnTransformDone(nsresult aResult, nsIDOMDocument *aResultDocument); + NS_IMETHOD OnDocumentCreated(nsIDocument *aResultDocument); + NS_IMETHOD OnTransformDone(nsresult aResult, nsIDocument *aResultDocument); static void ParsePIData(const nsString &aData, nsString &aHref, nsString &aTitle, nsString &aMedia, diff --git a/content/xslt/public/nsIDocumentTransformer.h b/content/xslt/public/nsIDocumentTransformer.h index 78d1b1793bd4..2f329ad9f9b2 100644 --- a/content/xslt/public/nsIDocumentTransformer.h +++ b/content/xslt/public/nsIDocumentTransformer.h @@ -48,8 +48,8 @@ class nsIPrincipal; class nsString; #define NS_ITRANSFORMOBSERVER_IID \ - {0xcce88481, 0x6eb3, 0x11d6, \ - { 0xa7, 0xf2, 0x8d, 0x82, 0xcd, 0x2a, 0xf3, 0x7c }} +{ 0x04b2d17c, 0xe98d, 0x45f5, \ + { 0x9a, 0x67, 0xb7, 0x01, 0x19, 0x59, 0x7d, 0xe7 } } class nsITransformObserver : public nsISupports { @@ -57,10 +57,10 @@ public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_ITRANSFORMOBSERVER_IID) - NS_IMETHOD OnDocumentCreated(nsIDOMDocument *aResultDocument) = 0; + NS_IMETHOD OnDocumentCreated(nsIDocument *aResultDocument) = 0; NS_IMETHOD OnTransformDone(nsresult aResult, - nsIDOMDocument *aResultDocument) = 0; + nsIDocument *aResultDocument) = 0; }; diff --git a/content/xslt/src/base/txError.h b/content/xslt/src/base/txError.h index 5c8309c39fee..94933bd550bc 100644 --- a/content/xslt/src/base/txError.h +++ b/content/xslt/src/base/txError.h @@ -138,4 +138,7 @@ #define NS_ERROR_XPATH_UNBALANCED_CURLY_BRACE \ NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XSLT, 29) +#define NS_ERROR_XSLT_BAD_NODE_NAME \ + NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XSLT, 30) + #endif // __TX_ERROR diff --git a/content/xslt/src/base/txStringUtils.h b/content/xslt/src/base/txStringUtils.h index 6022ccadc1cb..852282c46540 100644 --- a/content/xslt/src/base/txStringUtils.h +++ b/content/xslt/src/base/txStringUtils.h @@ -79,4 +79,13 @@ void TX_ToLowerCase(const nsAString& aSource, nsAString& aDest); #endif +inline already_AddRefed +TX_ToLowerCaseAtom(nsIAtom* aAtom) +{ + nsAutoString str; + aAtom->ToString(str); + TX_ToLowerCase(str); + return do_GetAtom(str); +} + #endif // txStringUtils_h__ diff --git a/content/xslt/src/xpath/txMozillaXPathTreeWalker.cpp b/content/xslt/src/xpath/txMozillaXPathTreeWalker.cpp index b099eff945db..515b1be9b272 100644 --- a/content/xslt/src/xpath/txMozillaXPathTreeWalker.cpp +++ b/content/xslt/src/xpath/txMozillaXPathTreeWalker.cpp @@ -407,6 +407,22 @@ txXPathNodeUtils::getLocalName(const txXPathNode& aNode) return localName; } +nsIAtom* +txXPathNodeUtils::getPrefix(const txXPathNode& aNode) +{ + if (aNode.isDocument()) { + return nsnull; + } + + if (aNode.isContent()) { + // All other nsIContent node types but elements have a null prefix + // which is what we want here. + return aNode.Content()->NodeInfo()->GetPrefixAtom(); + } + + return aNode.Content()->GetAttrNameAt(aNode.mIndex)->GetPrefix(); +} + /* static */ void txXPathNodeUtils::getLocalName(const txXPathNode& aNode, nsAString& aLocalName) diff --git a/content/xslt/src/xpath/txXPathTreeWalker.h b/content/xslt/src/xpath/txXPathTreeWalker.h index 0d134c0e213d..27106b29a79c 100644 --- a/content/xslt/src/xpath/txXPathTreeWalker.h +++ b/content/xslt/src/xpath/txXPathTreeWalker.h @@ -116,6 +116,7 @@ public: static PRBool getAttr(const txXPathNode& aNode, nsIAtom* aLocalName, PRInt32 aNSID, nsAString& aValue); static already_AddRefed getLocalName(const txXPathNode& aNode); + static nsIAtom* getPrefix(const txXPathNode& aNode); static void getLocalName(const txXPathNode& aNode, nsAString& aLocalName); static void getNodeName(const txXPathNode& aNode, nsAString& aName); diff --git a/content/xslt/src/xslt/txBufferingHandler.cpp b/content/xslt/src/xslt/txBufferingHandler.cpp index 3f9fd3c2d116..7beb319ac2ef 100644 --- a/content/xslt/src/xslt/txBufferingHandler.cpp +++ b/content/xslt/src/xslt/txBufferingHandler.cpp @@ -44,6 +44,7 @@ class txOutputTransaction public: enum txTransactionType { eAttributeTransaction, + eAttributeAtomTransaction, eCharacterTransaction, eCharacterNoOETransaction, eCommentTransaction, @@ -51,6 +52,7 @@ public: eEndElementTransaction, ePITransaction, eStartDocumentTransaction, + eStartElementAtomTransaction, eStartElementTransaction }; txOutputTransaction(txTransactionType aType) @@ -98,32 +100,76 @@ public: nsString mData; }; -class txElementTransaction : public txOutputTransaction +class txStartElementAtomTransaction : public txOutputTransaction { public: - txElementTransaction(txTransactionType aType, const nsAString& aName, - PRInt32 aNsID) - : txOutputTransaction(aType), - mName(aName), + txStartElementAtomTransaction(nsIAtom* aPrefix, nsIAtom* aLocalName, + nsIAtom* aLowercaseLocalName, PRInt32 aNsID) + : txOutputTransaction(eStartElementAtomTransaction), + mPrefix(aPrefix), + mLocalName(aLocalName), + mLowercaseLocalName(aLowercaseLocalName), mNsID(aNsID) { } - nsString mName; + nsCOMPtr mPrefix; + nsCOMPtr mLocalName; + nsCOMPtr mLowercaseLocalName; + PRInt32 mNsID; +}; + +class txStartElementTransaction : public txOutputTransaction +{ +public: + txStartElementTransaction(nsIAtom* aPrefix, + const nsSubstring& aLocalName, PRInt32 aNsID) + : txOutputTransaction(eStartElementTransaction), + mPrefix(aPrefix), + mLocalName(aLocalName), + mNsID(aNsID) + { + } + nsCOMPtr mPrefix; + nsString mLocalName; PRInt32 mNsID; }; class txAttributeTransaction : public txOutputTransaction { public: - txAttributeTransaction(const nsAString& aName, PRInt32 aNsID, - const nsAString& aValue) + txAttributeTransaction(nsIAtom* aPrefix, + const nsSubstring& aLocalName, PRInt32 aNsID, + const nsString& aValue) : txOutputTransaction(eAttributeTransaction), - mName(aName), + mPrefix(aPrefix), + mLocalName(aLocalName), mNsID(aNsID), mValue(aValue) { } - nsString mName; + nsCOMPtr mPrefix; + nsString mLocalName; + PRInt32 mNsID; + nsString mValue; +}; + +class txAttributeAtomTransaction : public txOutputTransaction +{ +public: + txAttributeAtomTransaction(nsIAtom* aPrefix, nsIAtom* aLocalName, + nsIAtom* aLowercaseLocalName, + PRInt32 aNsID, const nsString& aValue) + : txOutputTransaction(eAttributeAtomTransaction), + mPrefix(aPrefix), + mLocalName(aLocalName), + mLowercaseLocalName(aLowercaseLocalName), + mNsID(aNsID), + mValue(aValue) + { + } + nsCOMPtr mPrefix; + nsCOMPtr mLocalName; + nsCOMPtr mLowercaseLocalName; PRInt32 mNsID; nsString mValue; }; @@ -138,8 +184,9 @@ txBufferingHandler::~txBufferingHandler() } nsresult -txBufferingHandler::attribute(const nsAString& aName, const PRInt32 aNsID, - const nsAString& aValue) +txBufferingHandler::attribute(nsIAtom* aPrefix, nsIAtom* aLocalName, + nsIAtom* aLowercaseLocalName, PRInt32 aNsID, + const nsString& aValue) { NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY); @@ -149,14 +196,34 @@ txBufferingHandler::attribute(const nsAString& aName, const PRInt32 aNsID, } txOutputTransaction* transaction = - new txAttributeTransaction(aName, aNsID, aValue); + new txAttributeAtomTransaction(aPrefix, aLocalName, + aLowercaseLocalName, aNsID, + aValue); NS_ENSURE_TRUE(transaction, NS_ERROR_OUT_OF_MEMORY); return mBuffer->addTransaction(transaction); } nsresult -txBufferingHandler::characters(const nsAString& aData, PRBool aDOE) +txBufferingHandler::attribute(nsIAtom* aPrefix, const nsSubstring& aLocalName, + const PRInt32 aNsID, const nsString& aValue) +{ + NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY); + + if (!mCanAddAttribute) { + // XXX ErrorReport: Can't add attributes without element + return NS_OK; + } + + txOutputTransaction* transaction = + new txAttributeTransaction(aPrefix, aLocalName, aNsID, aValue); + NS_ENSURE_TRUE(transaction, NS_ERROR_OUT_OF_MEMORY); + + return mBuffer->addTransaction(transaction); +} + +nsresult +txBufferingHandler::characters(const nsSubstring& aData, PRBool aDOE) { NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY); @@ -182,7 +249,7 @@ txBufferingHandler::characters(const nsAString& aData, PRBool aDOE) } nsresult -txBufferingHandler::comment(const nsAString& aData) +txBufferingHandler::comment(const nsString& aData) { NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY); @@ -207,23 +274,22 @@ txBufferingHandler::endDocument(nsresult aResult) } nsresult -txBufferingHandler::endElement(const nsAString& aName, const PRInt32 aNsID) +txBufferingHandler::endElement() { NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY); mCanAddAttribute = PR_FALSE; txOutputTransaction* transaction = - new txElementTransaction(txOutputTransaction::eEndElementTransaction, - aName, aNsID); + new txOutputTransaction(txOutputTransaction::eEndElementTransaction); NS_ENSURE_TRUE(transaction, NS_ERROR_OUT_OF_MEMORY); return mBuffer->addTransaction(transaction); } nsresult -txBufferingHandler::processingInstruction(const nsAString& aTarget, - const nsAString& aData) +txBufferingHandler::processingInstruction(const nsString& aTarget, + const nsString& aData) { NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY); @@ -249,15 +315,33 @@ txBufferingHandler::startDocument() } nsresult -txBufferingHandler::startElement(const nsAString& aName, const PRInt32 aNsID) +txBufferingHandler::startElement(nsIAtom* aPrefix, nsIAtom* aLocalName, + nsIAtom* aLowercaseLocalName, + PRInt32 aNsID) { NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY); mCanAddAttribute = PR_TRUE; txOutputTransaction* transaction = - new txElementTransaction(txOutputTransaction::eStartElementTransaction, - aName, aNsID); + new txStartElementAtomTransaction(aPrefix, aLocalName, + aLowercaseLocalName, aNsID); + NS_ENSURE_TRUE(transaction, NS_ERROR_OUT_OF_MEMORY); + + return mBuffer->addTransaction(transaction); +} + +nsresult +txBufferingHandler::startElement(nsIAtom* aPrefix, + const nsSubstring& aLocalName, + const PRInt32 aNsID) +{ + NS_ENSURE_TRUE(mBuffer, NS_ERROR_OUT_OF_MEMORY); + + mCanAddAttribute = PR_TRUE; + + txOutputTransaction* transaction = + new txStartElementTransaction(aPrefix, aLocalName, aNsID); NS_ENSURE_TRUE(transaction, NS_ERROR_OUT_OF_MEMORY); return mBuffer->addTransaction(transaction); @@ -301,11 +385,23 @@ flushTransaction(void* aElement, void *aData) nsresult rv; switch (transaction->mType) { + case txOutputTransaction::eAttributeAtomTransaction: + { + txAttributeAtomTransaction* transaction = + NS_STATIC_CAST(txAttributeAtomTransaction*, aElement); + rv = handler->attribute(transaction->mPrefix, + transaction->mLocalName, + transaction->mLowercaseLocalName, + transaction->mNsID, + transaction->mValue); + break; + } case txOutputTransaction::eAttributeTransaction: { txAttributeTransaction* attrTransaction = NS_STATIC_CAST(txAttributeTransaction*, aElement); - rv = handler->attribute(attrTransaction->mName, + rv = handler->attribute(attrTransaction->mPrefix, + attrTransaction->mLocalName, attrTransaction->mNsID, attrTransaction->mValue); break; @@ -334,10 +430,7 @@ flushTransaction(void* aElement, void *aData) } case txOutputTransaction::eEndElementTransaction: { - txElementTransaction* elementTransaction = - NS_STATIC_CAST(txElementTransaction*, aElement); - rv = handler->endElement(elementTransaction->mName, - elementTransaction->mNsID); + rv = handler->endElement(); break; } case txOutputTransaction::ePITransaction: @@ -353,12 +446,23 @@ flushTransaction(void* aElement, void *aData) rv = handler->startDocument(); break; } + case txOutputTransaction::eStartElementAtomTransaction: + { + txStartElementAtomTransaction* transaction = + NS_STATIC_CAST(txStartElementAtomTransaction*, aElement); + rv = handler->startElement(transaction->mPrefix, + transaction->mLocalName, + transaction->mLowercaseLocalName, + transaction->mNsID); + break; + } case txOutputTransaction::eStartElementTransaction: { - txElementTransaction* elementTransaction = - NS_STATIC_CAST(txElementTransaction*, aElement); - rv = handler->startElement(elementTransaction->mName, - elementTransaction->mNsID); + txStartElementTransaction* transaction = + NS_STATIC_CAST(txStartElementTransaction*, aElement); + rv = handler->startElement(transaction->mPrefix, + transaction->mLocalName, + transaction->mNsID); break; } } diff --git a/content/xslt/src/xslt/txExecutionState.cpp b/content/xslt/src/xslt/txExecutionState.cpp index 3e19962fd142..da60bb17b3c7 100644 --- a/content/xslt/src/xslt/txExecutionState.cpp +++ b/content/xslt/src/xslt/txExecutionState.cpp @@ -365,34 +365,22 @@ txExecutionState::popEvalContext() } nsresult -txExecutionState::pushString(const nsAString& aStr) +txExecutionState::pushBool(PRBool aBool) { - if (!mStringStack.AppendString(aStr)) { - return NS_ERROR_OUT_OF_MEMORY; - } - - return NS_OK; + return mBoolStack.AppendElement(aBool) ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } -void -txExecutionState::popString(nsAString& aStr) +PRBool +txExecutionState::popBool() { - PRInt32 count = mStringStack.Count() - 1; - NS_ASSERTION(count >= 0, "stack is empty"); - mStringStack.StringAt(count, aStr); - mStringStack.RemoveStringAt(count); -} + NS_ASSERTION(mBoolStack.Length(), "popping from empty stack"); + PRUint32 last = mBoolStack.Length() - 1; + NS_ENSURE_TRUE(last != (PRUint32)-1, PR_FALSE); -nsresult -txExecutionState::pushInt(PRInt32 aInt) -{ - return mIntStack.push(NS_INT32_TO_PTR(aInt)); -} + PRBool res = mBoolStack.ElementAt(last); + mBoolStack.RemoveElementAt(last); -PRInt32 -txExecutionState::popInt() -{ - return NS_PTR_TO_INT32(mIntStack.pop()); + return res; } nsresult diff --git a/content/xslt/src/xslt/txExecutionState.h b/content/xslt/src/xslt/txExecutionState.h index 1b46ad41b61b..43b0483eabd3 100644 --- a/content/xslt/src/xslt/txExecutionState.h +++ b/content/xslt/src/xslt/txExecutionState.h @@ -50,6 +50,7 @@ #include "txKey.h" #include "txStylesheet.h" #include "txXPathTreeWalker.h" +#include "nsTArray.h" class txAOutputHandlerFactory; class txAXMLEventHandler; @@ -113,10 +114,8 @@ public: // Stack functions nsresult pushEvalContext(txIEvalContext* aContext); txIEvalContext* popEvalContext(); - nsresult pushString(const nsAString& aStr); - void popString(nsAString& aStr); - nsresult pushInt(PRInt32 aInt); - PRInt32 popInt(); + nsresult pushBool(PRBool aBool); + PRBool popBool(); nsresult pushResultHandler(txAXMLEventHandler* aHandler); txAXMLEventHandler* popResultHandler(); nsresult pushTemplateRule(txStylesheet::ImportFrame* aFrame, @@ -159,10 +158,9 @@ private: txStack mReturnStack; txStack mLocalVarsStack; txStack mEvalContextStack; - txStack mIntStack; + nsTArray mBoolStack; txStack mResultHandlerStack; txStack mParamStack; - nsStringArray mStringStack; txInstruction* mNextInstruction; txVariableMap* mLocalVariables; txVariableMap mGlobalVariableValues; diff --git a/content/xslt/src/xslt/txInstructions.cpp b/content/xslt/src/xslt/txInstructions.cpp index 2df443a381f0..457e300faec2 100644 --- a/content/xslt/src/xslt/txInstructions.cpp +++ b/content/xslt/src/xslt/txInstructions.cpp @@ -140,51 +140,39 @@ txAttribute::execute(txExecutionState& aEs) const PRUnichar* colon; if (!XMLUtils::isValidQName(name, &colon) || TX_StringEqualsAtom(name, txXMLAtoms::xmlns)) { - // truncate name to indicate failure - name.Truncate(); + return NS_OK; } nsCOMPtr prefix; + PRUint32 lnameStart = 0; if (colon) { prefix = do_GetAtom(Substring(name.get(), colon)); + lnameStart = colon - name.get() + 1; } PRInt32 nsId = kNameSpaceID_None; - if (!name.IsEmpty()) { - if (mNamespace) { - nsAutoString nspace; - rv = mNamespace->evaluateToString(aEs.getEvalContext(), - nspace); - NS_ENSURE_SUCCESS(rv, rv); + if (mNamespace) { + nsAutoString nspace; + rv = mNamespace->evaluateToString(aEs.getEvalContext(), + nspace); + NS_ENSURE_SUCCESS(rv, rv); - if (!nspace.IsEmpty()) { - nsId = txNamespaceManager::getNamespaceID(nspace); - NS_ENSURE_FALSE(nsId == kNameSpaceID_Unknown, - NS_ERROR_FAILURE); - } - } - else if (prefix) { - nsId = mMappings->lookupNamespace(prefix); - if (nsId == kNameSpaceID_Unknown) { - // tunkate name to indicate failure - name.Truncate(); - } + if (!nspace.IsEmpty()) { + nsId = txNamespaceManager::getNamespaceID(nspace); } } - - if (prefix == txXMLAtoms::xmlns) { - // Cut xmlns: (6 characters) - name.Cut(0, 6); + else if (colon) { + nsId = mMappings->lookupNamespace(prefix); } nsAutoPtr handler( NS_STATIC_CAST(txTextHandler*, aEs.popResultHandler())); - if (!name.IsEmpty()) { - // add attribute if everything was ok - return aEs.mResultHandler->attribute(name, nsId, handler->mValue); - } - return NS_OK; + // add attribute if everything was ok + return nsId != kNameSpaceID_Unknown ? + aEs.mResultHandler->attribute(prefix, Substring(name, lnameStart), + nsId, handler->mValue) : + NS_OK; } txCallTemplate::txCallTemplate(const txExpandedName& aName) @@ -272,12 +260,16 @@ txCopyBase::copyNode(const txXPathNode& aNode, txExecutionState& aEs) switch (txXPathNodeUtils::getNodeType(aNode)) { case txXPathNodeType::ATTRIBUTE_NODE: { - nsAutoString nodeName, nodeValue; - txXPathNodeUtils::getNodeName(aNode, nodeName); + nsAutoString nodeValue; txXPathNodeUtils::appendNodeValue(aNode, nodeValue); + + nsCOMPtr localName = + txXPathNodeUtils::getLocalName(aNode); return aEs.mResultHandler-> - attribute(nodeName, txXPathNodeUtils::getNamespaceID(aNode), - nodeValue); + attribute(txXPathNodeUtils::getPrefix(aNode), + localName, nsnull, + txXPathNodeUtils::getNamespaceID(aNode), + nodeValue); } case txXPathNodeType::COMMENT_NODE: { @@ -299,21 +291,28 @@ txCopyBase::copyNode(const txXPathNode& aNode, txExecutionState& aEs) } case txXPathNodeType::ELEMENT_NODE: { - nsAutoString name; - txXPathNodeUtils::getNodeName(aNode, name); - PRInt32 nsID = txXPathNodeUtils::getNamespaceID(aNode); - nsresult rv = aEs.mResultHandler->startElement(name, nsID); + nsCOMPtr localName = + txXPathNodeUtils::getLocalName(aNode); + nsresult rv = aEs.mResultHandler-> + startElement(txXPathNodeUtils::getPrefix(aNode), + localName, nsnull, + txXPathNodeUtils::getNamespaceID(aNode)); NS_ENSURE_SUCCESS(rv, rv); // Copy attributes txXPathTreeWalker walker(aNode); if (walker.moveToFirstAttribute()) { do { - nsAutoString nodeName, nodeValue; - walker.getNodeName(nodeName); + nsAutoString nodeValue; walker.appendNodeValue(nodeValue); + + const txXPathNode& attr = walker.getCurrentPosition(); + localName = txXPathNodeUtils::getLocalName(attr); rv = aEs.mResultHandler-> - attribute(nodeName, walker.getNamespaceID(), nodeValue); + attribute(txXPathNodeUtils::getPrefix(attr), + localName, nsnull, + txXPathNodeUtils::getNamespaceID(attr), + nodeValue); NS_ENSURE_SUCCESS(rv, rv); } while (walker.moveToNextAttribute()); walker.moveToParent(); @@ -326,7 +325,7 @@ txCopyBase::copyNode(const txXPathNode& aNode, txExecutionState& aEs) hasChild = walker.moveToNextSibling(); } - return aEs.mResultHandler->endElement(name, nsID); + return aEs.mResultHandler->endElement(); } case txXPathNodeType::PROCESSING_INSTRUCTION_NODE: { @@ -367,28 +366,24 @@ txCopy::execute(txExecutionState& aEs) rv = aEs.mResultHandler->characters(empty, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); - rv = aEs.pushString(empty); - NS_ENSURE_SUCCESS(rv, rv); - - rv = aEs.pushInt(kNameSpaceID_None); + rv = aEs.pushBool(PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); break; } case txXPathNodeType::ELEMENT_NODE: { - nsAutoString nodeName; - txXPathNodeUtils::getNodeName(node, nodeName); - PRInt32 nsID = txXPathNodeUtils::getNamespaceID(node); - - rv = aEs.mResultHandler->startElement(nodeName, nsID); + nsCOMPtr localName = + txXPathNodeUtils::getLocalName(node); + nsresult rv = aEs.mResultHandler-> + startElement(txXPathNodeUtils::getPrefix(node), + localName, nsnull, + txXPathNodeUtils::getNamespaceID(node)); NS_ENSURE_SUCCESS(rv, rv); + // XXX copy namespace nodes once we have them - rv = aEs.pushString(nodeName); - NS_ENSURE_SUCCESS(rv, rv); - - rv = aEs.pushInt(nsID); + rv = aEs.pushBool(PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); break; @@ -455,14 +450,11 @@ txCopyOf::execute(txExecutionState& aEs) nsresult txEndElement::execute(txExecutionState& aEs) { - PRInt32 namespaceID = aEs.popInt(); - nsAutoString nodeName; - aEs.popString(nodeName); - - - // For xsl:elements with a bad name we push an empty name - if (!nodeName.IsEmpty()) { - return aEs.mResultHandler->endElement(nodeName, namespaceID); + // This will return false if startElement was not called. This happens + // when produces a bad name, or when copies a + // document node. + if (aEs.popBool()) { + return aEs.mResultHandler->endElement(); } return NS_OK; @@ -535,24 +527,14 @@ txLREAttribute::txLREAttribute(PRInt32 aNamespaceID, nsIAtom* aLocalName, mPrefix(aPrefix), mValue(aValue) { + if (aNamespaceID == kNameSpaceID_None) { + mLowercaseLocalName = TX_ToLowerCaseAtom(aLocalName); + } } nsresult txLREAttribute::execute(txExecutionState& aEs) { - // We should atomize the resulthandler - nsAutoString nodeName; - if (mPrefix) { - mPrefix->ToString(nodeName); - nsAutoString localName; - nodeName.Append(PRUnichar(':')); - mLocalName->ToString(localName); - nodeName.Append(localName); - } - else { - mLocalName->ToString(nodeName); - } - nsRefPtr exprRes; nsresult rv = mValue->evaluate(aEs.getEvalContext(), getter_AddRefs(exprRes)); @@ -560,12 +542,16 @@ txLREAttribute::execute(txExecutionState& aEs) const nsString* value = exprRes->stringValuePointer(); if (value) { - return aEs.mResultHandler->attribute(nodeName, mNamespaceID, *value); + return aEs.mResultHandler->attribute(mPrefix, mLocalName, + mLowercaseLocalName, + mNamespaceID, *value); } nsAutoString valueStr; exprRes->stringValue(valueStr); - return aEs.mResultHandler->attribute(nodeName, mNamespaceID, valueStr); + return aEs.mResultHandler->attribute(mPrefix, mLocalName, + mLowercaseLocalName, + mNamespaceID, valueStr); } txMessage::txMessage(PRBool aTerminate) @@ -886,14 +872,18 @@ txStartElement::execute(txExecutionState& aEs) nsresult rv = mName->evaluateToString(aEs.getEvalContext(), name); NS_ENSURE_SUCCESS(rv, rv); - const PRUnichar* colon; - if (!XMLUtils::isValidQName(name, &colon)) { - // truncate name to indicate failure - name.Truncate(); - } PRInt32 nsId = kNameSpaceID_None; - if (!name.IsEmpty()) { + nsCOMPtr prefix; + PRUint32 lnameStart = 0; + + const PRUnichar* colon; + if (XMLUtils::isValidQName(name, &colon)) { + if (colon) { + prefix = do_GetAtom(Substring(name.get(), colon)); + lnameStart = colon - name.get() + 1; + } + if (mNamespace) { nsAutoString nspace; rv = mNamespace->evaluateToString(aEs.getEvalContext(), @@ -902,38 +892,36 @@ txStartElement::execute(txExecutionState& aEs) if (!nspace.IsEmpty()) { nsId = txNamespaceManager::getNamespaceID(nspace); - NS_ENSURE_FALSE(nsId == kNameSpaceID_Unknown, - NS_ERROR_FAILURE); } } else { - nsCOMPtr prefix; - if (colon) { - prefix = do_GetAtom(Substring(name.get(), colon)); - } nsId = mMappings->lookupNamespace(prefix); - if (nsId == kNameSpaceID_Unknown) { - // truncate name to indicate failure - name.Truncate(); - } } } + else { + nsId = kNameSpaceID_Unknown; + } - if (!name.IsEmpty()) { - // add element if everything was ok - rv = aEs.mResultHandler->startElement(name, nsId); + PRBool success = PR_TRUE; + + if (nsId != kNameSpaceID_Unknown) { + rv = aEs.mResultHandler->startElement(prefix, + Substring(name, lnameStart), + nsId); } else { + rv = NS_ERROR_XSLT_BAD_NODE_NAME; + } + + if (rv == NS_ERROR_XSLT_BAD_NODE_NAME) { + success = PR_FALSE; // we call characters with an empty string to "close" any element to // make sure that no attributes are added rv = aEs.mResultHandler->characters(EmptyString(), PR_FALSE); } NS_ENSURE_SUCCESS(rv, rv); - rv = aEs.pushString(name); - NS_ENSURE_SUCCESS(rv, rv); - - rv = aEs.pushInt(nsId); + rv = aEs.pushBool(success); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; @@ -947,31 +935,20 @@ txStartLREElement::txStartLREElement(PRInt32 aNamespaceID, mLocalName(aLocalName), mPrefix(aPrefix) { + if (aNamespaceID == kNameSpaceID_None) { + mLowercaseLocalName = TX_ToLowerCaseAtom(aLocalName); + } } nsresult txStartLREElement::execute(txExecutionState& aEs) { - // We should atomize the resulthandler - nsAutoString nodeName; - if (mPrefix) { - mPrefix->ToString(nodeName); - nsAutoString localName; - nodeName.Append(PRUnichar(':')); - mLocalName->ToString(localName); - nodeName.Append(localName); - } - else { - mLocalName->ToString(nodeName); - } - - nsresult rv = aEs.mResultHandler->startElement(nodeName, mNamespaceID); + nsresult rv = aEs.mResultHandler->startElement(mPrefix, mLocalName, + mLowercaseLocalName, + mNamespaceID); NS_ENSURE_SUCCESS(rv, rv); - rv = aEs.pushString(nodeName); - NS_ENSURE_SUCCESS(rv, rv); - - rv = aEs.pushInt(mNamespaceID); + rv = aEs.pushBool(PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; diff --git a/content/xslt/src/xslt/txInstructions.h b/content/xslt/src/xslt/txInstructions.h index 2bf27e97de2e..5d0df20432b1 100644 --- a/content/xslt/src/xslt/txInstructions.h +++ b/content/xslt/src/xslt/txInstructions.h @@ -228,6 +228,7 @@ public: PRInt32 mNamespaceID; nsCOMPtr mLocalName; + nsCOMPtr mLowercaseLocalName; nsCOMPtr mPrefix; nsAutoPtr mValue; }; @@ -396,6 +397,7 @@ public: PRInt32 mNamespaceID; nsCOMPtr mLocalName; + nsCOMPtr mLowercaseLocalName; nsCOMPtr mPrefix; }; diff --git a/content/xslt/src/xslt/txMozillaTextOutput.cpp b/content/xslt/src/xslt/txMozillaTextOutput.cpp index e652fbf6cad1..f536ceb88bda 100644 --- a/content/xslt/src/xslt/txMozillaTextOutput.cpp +++ b/content/xslt/src/xslt/txMozillaTextOutput.cpp @@ -52,8 +52,9 @@ #include "nsICharsetAlias.h" #include "nsIPrincipal.h" #include "txURIUtils.h" - -static NS_DEFINE_CID(kXMLDocumentCID, NS_XMLDOCUMENT_CID); +#include "nsContentCreatorFunctions.h" +#include "nsContentUtils.h" +#include "nsGkAtoms.h" txMozillaTextOutput::txMozillaTextOutput(nsIDOMDocument* aSourceDocument, nsIDOMDocument* aResultDocument, @@ -65,23 +66,8 @@ txMozillaTextOutput::txMozillaTextOutput(nsIDOMDocument* aSourceDocument, txMozillaTextOutput::txMozillaTextOutput(nsIDOMDocumentFragment* aDest) { - nsCOMPtr doc; - aDest->GetOwnerDocument(getter_AddRefs(doc)); - NS_ASSERTION(doc, "unable to get ownerdocument"); - nsCOMPtr textNode; - nsresult rv = doc->CreateTextNode(EmptyString(), - getter_AddRefs(textNode)); - if (NS_FAILED(rv)) { - return; - } - nsCOMPtr dummy; - rv = aDest->AppendChild(textNode, getter_AddRefs(dummy)); - if (NS_FAILED(rv)) { - return; - } - - mTextNode = textNode; - return; + mTextParent = do_QueryInterface(aDest); + mDocument = mTextParent->GetOwnerDoc(); } txMozillaTextOutput::~txMozillaTextOutput() @@ -89,24 +75,31 @@ txMozillaTextOutput::~txMozillaTextOutput() } nsresult -txMozillaTextOutput::attribute(const nsAString& aName, +txMozillaTextOutput::attribute(nsIAtom* aPrefix, nsIAtom* aLocalName, + nsIAtom* aLowercaseLocalName, + PRInt32 aNsID, const nsString& aValue) +{ + return NS_OK; +} + +nsresult +txMozillaTextOutput::attribute(nsIAtom* aPrefix, const nsSubstring& aName, const PRInt32 aNsID, - const nsAString& aValue) + const nsString& aValue) { return NS_OK; } nsresult -txMozillaTextOutput::characters(const nsAString& aData, PRBool aDOE) +txMozillaTextOutput::characters(const nsSubstring& aData, PRBool aDOE) { - if (mTextNode) - mTextNode->AppendData(aData); + mText.Append(aData); return NS_OK; } nsresult -txMozillaTextOutput::comment(const nsAString& aData) +txMozillaTextOutput::comment(const nsString& aData) { return NS_OK; } @@ -114,6 +107,17 @@ txMozillaTextOutput::comment(const nsAString& aData) nsresult txMozillaTextOutput::endDocument(nsresult aResult) { + NS_ENSURE_TRUE(mDocument && mTextParent, NS_ERROR_FAILURE); + + nsCOMPtr text; + nsresult rv = NS_NewTextNode(getter_AddRefs(text), + mDocument->NodeInfoManager()); + NS_ENSURE_SUCCESS(rv, rv); + + text->SetText(mText, PR_FALSE); + rv = mTextParent->AppendChildTo(text, PR_TRUE); + NS_ENSURE_SUCCESS(rv, rv); + if (NS_SUCCEEDED(aResult)) { nsCOMPtr observer = do_QueryReferent(mObserver); if (observer) { @@ -125,15 +129,14 @@ txMozillaTextOutput::endDocument(nsresult aResult) } nsresult -txMozillaTextOutput::endElement(const nsAString& aName, - const PRInt32 aNsID) +txMozillaTextOutput::endElement() { return NS_OK; } nsresult -txMozillaTextOutput::processingInstruction(const nsAString& aTarget, - const nsAString& aData) +txMozillaTextOutput::processingInstruction(const nsString& aTarget, + const nsString& aData) { return NS_OK; } @@ -149,14 +152,14 @@ txMozillaTextOutput::createResultDocument(nsIDOMDocument* aSourceDocument, nsIDOMDocument* aResultDocument) { nsresult rv = NS_OK; - + /* * Create an XHTML document to hold the text. * * * * - *
 * The text comes here * 
+ *
 * The text comes here * 
* * * @@ -165,19 +168,14 @@ txMozillaTextOutput::createResultDocument(nsIDOMDocument* aSourceDocument, * * * The text comes here * */ - - nsCOMPtr doc; + if (!aResultDocument) { // Create the document - doc = do_CreateInstance(kXMLDocumentCID, &rv); + rv = NS_NewXMLDocument(getter_AddRefs(mDocument)); NS_ENSURE_SUCCESS(rv, rv); - - mDocument = do_QueryInterface(doc); } else { - mDocument = aResultDocument; - doc = do_QueryInterface(aResultDocument, &rv); - NS_ENSURE_SUCCESS(rv, rv); + mDocument = do_QueryInterface(aResultDocument); } NS_ASSERTION(mDocument, "Need document"); @@ -188,7 +186,7 @@ txMozillaTextOutput::createResultDocument(nsIDOMDocument* aSourceDocument, } // Reset and set up document - URIUtils::ResetWithSource(doc, aSourceDocument); + URIUtils::ResetWithSource(mDocument, aSourceDocument); // Set the charset if (!mOutputFormat.mEncoding.IsEmpty()) { @@ -199,8 +197,8 @@ txMozillaTextOutput::createResultDocument(nsIDOMDocument* aSourceDocument, if (calias && NS_SUCCEEDED(calias->GetPreferred(charset, canonicalCharset))) { - doc->SetDocumentCharacterSet(canonicalCharset); - doc->SetDocumentCharacterSetSource(kCharsetFromOtherComponent); + mDocument->SetDocumentCharacterSet(canonicalCharset); + mDocument->SetDocumentCharacterSetSource(kCharsetFromOtherComponent); } } @@ -217,77 +215,64 @@ txMozillaTextOutput::createResultDocument(nsIDOMDocument* aSourceDocument, // observer) we only create a transformiix:result root element. // Don't do this when called through nsIXSLTProcessorObsolete (i.e. when // aResultDocument is set) for compability reasons - nsCOMPtr textContainer; if (!aResultDocument && !observer) { - nsCOMPtr docElement; - rv = mDocument->CreateElementNS(NS_LITERAL_STRING(kTXNameSpaceURI), - NS_LITERAL_STRING(kTXWrapper), - getter_AddRefs(docElement)); + PRInt32 namespaceID; + rv = nsContentUtils::NameSpaceManager()-> + RegisterNameSpace(NS_LITERAL_STRING(kTXNameSpaceURI), namespaceID); NS_ENSURE_SUCCESS(rv, rv); - rv = mDocument->AppendChild(docElement, getter_AddRefs(textContainer)); + rv = mDocument->CreateElem(nsGkAtoms::result, nsGkAtoms::transformiix, + namespaceID, PR_FALSE, getter_AddRefs(mTextParent)); + NS_ENSURE_SUCCESS(rv, rv); + + + rv = mDocument->AppendChildTo(mTextParent, PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); } else { - nsCOMPtr element, docElement; - nsCOMPtr parent, pre; - - NS_NAMED_LITERAL_STRING(XHTML_NSURI, "http://www.w3.org/1999/xhtml"); - - rv = mDocument->CreateElementNS(XHTML_NSURI, - NS_LITERAL_STRING("html"), - getter_AddRefs(docElement)); + nsCOMPtr html, head, body; + rv = createXHTMLElement(nsGkAtoms::html, getter_AddRefs(html)); NS_ENSURE_SUCCESS(rv, rv); - rv = mDocument->AppendChild(docElement, getter_AddRefs(parent)); + rv = createXHTMLElement(nsGkAtoms::head, getter_AddRefs(head)); NS_ENSURE_SUCCESS(rv, rv); - rv = mDocument->CreateElementNS(XHTML_NSURI, - NS_LITERAL_STRING("head"), - getter_AddRefs(element)); + rv = html->AppendChildTo(head, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); - rv = docElement->AppendChild(element, getter_AddRefs(parent)); + rv = createXHTMLElement(nsGkAtoms::body, getter_AddRefs(body)); NS_ENSURE_SUCCESS(rv, rv); - rv = mDocument->CreateElementNS(XHTML_NSURI, - NS_LITERAL_STRING("body"), - getter_AddRefs(element)); + rv = html->AppendChildTo(body, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); - rv = docElement->AppendChild(element, getter_AddRefs(parent)); + rv = createXHTMLElement(nsGkAtoms::pre, getter_AddRefs(mTextParent)); NS_ENSURE_SUCCESS(rv, rv); - rv = mDocument->CreateElementNS(XHTML_NSURI, - NS_LITERAL_STRING("pre"), - getter_AddRefs(element)); + rv = mTextParent->SetAttr(kNameSpaceID_None, nsGkAtoms::id, + NS_LITERAL_STRING("transformiixResult"), + PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); - rv = parent->AppendChild(element, getter_AddRefs(pre)); + rv = body->AppendChildTo(mTextParent, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr htmlElement = do_QueryInterface(pre); - htmlElement->SetId(NS_LITERAL_STRING("transformiixResult")); + rv = mDocument->AppendChildTo(html, PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); - - textContainer = pre; } - nsCOMPtr textNode; - rv = mDocument->CreateTextNode(EmptyString(), getter_AddRefs(textNode)); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr dummy; - rv = textContainer->AppendChild(textNode, getter_AddRefs(dummy)); - NS_ENSURE_SUCCESS(rv, rv); - - mTextNode = textNode; - return NS_OK; } nsresult -txMozillaTextOutput::startElement(const nsAString& aName, +txMozillaTextOutput::startElement(nsIAtom* aPrefix, nsIAtom* aLocalName, + nsIAtom* aLowercaseLocalName, PRInt32 aNsID) +{ + return NS_OK; +} + +nsresult +txMozillaTextOutput::startElement(nsIAtom* aPrefix, const nsSubstring& aName, const PRInt32 aNsID) { return NS_OK; @@ -295,6 +280,20 @@ txMozillaTextOutput::startElement(const nsAString& aName, void txMozillaTextOutput::getOutputDocument(nsIDOMDocument** aDocument) { - *aDocument = mDocument; - NS_IF_ADDREF(*aDocument); + CallQueryInterface(mDocument, aDocument); } + +nsresult +txMozillaTextOutput::createXHTMLElement(nsIAtom* aName, + nsIContent** aResult) +{ + *aResult = nsnull; + + nsCOMPtr ni; + nsresult rv = mDocument->NodeInfoManager()-> + GetNodeInfo(aName, nsnull, kNameSpaceID_XHTML, getter_AddRefs(ni)); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_NewHTMLElement(aResult, ni); +} + diff --git a/content/xslt/src/xslt/txMozillaTextOutput.h b/content/xslt/src/xslt/txMozillaTextOutput.h index 3d9ec11800cb..3a51cf6ce691 100644 --- a/content/xslt/src/xslt/txMozillaTextOutput.h +++ b/content/xslt/src/xslt/txMozillaTextOutput.h @@ -48,6 +48,8 @@ class nsIDOMCharacterData; class nsIDOMDocument; class nsIDOMDocumentFragment; class nsITransformObserver; +class nsIDocument; +class nsIContent; class txMozillaTextOutput : public txAOutputXMLEventHandler { @@ -64,11 +66,13 @@ public: private: nsresult createResultDocument(nsIDOMDocument* aSourceDocument, nsIDOMDocument* aResultDocument); + nsresult createXHTMLElement(nsIAtom* aName, nsIContent** aResult); - nsCOMPtr mTextNode; + nsCOMPtr mTextParent; nsWeakPtr mObserver; - nsCOMPtr mDocument; + nsCOMPtr mDocument; txOutputFormat mOutputFormat; + nsString mText; }; #endif diff --git a/content/xslt/src/xslt/txMozillaXMLOutput.cpp b/content/xslt/src/xslt/txMozillaXMLOutput.cpp index 4ceba7dceb77..c0b34917fea1 100644 --- a/content/xslt/src/xslt/txMozillaXMLOutput.cpp +++ b/content/xslt/src/xslt/txMozillaXMLOutput.cpp @@ -42,13 +42,7 @@ #include "nsIDocShell.h" #include "nsIScriptLoader.h" #include "nsIDOMDocument.h" -#include "nsIDOMComment.h" #include "nsIDOMDocumentType.h" -#include "nsIDOMDOMImplementation.h" -#include "nsIDOMNodeList.h" -#include "nsIDOMProcessingInstruction.h" -#include "nsIDOMText.h" -#include "nsIDOMHTMLTableSectionElem.h" #include "nsIScriptElement.h" #include "nsIDOMNSDocument.h" #include "nsIParser.h" @@ -74,18 +68,16 @@ #include "nsIHTMLContentSink.h" #include "nsContentUtils.h" #include "txXMLUtils.h" - -static NS_DEFINE_CID(kXMLDocumentCID, NS_XMLDOCUMENT_CID); -static NS_DEFINE_CID(kHTMLDocumentCID, NS_HTMLDOCUMENT_CID); - -#define kXHTMLNameSpaceURI "http://www.w3.org/1999/xhtml" +#include "nsINode.h" +#include "nsContentCreatorFunctions.h" +#include "txError.h" #define TX_ENSURE_CURRENTNODE \ NS_ASSERTION(mCurrentNode, "mCurrentNode is NULL"); \ if (!mCurrentNode) \ return NS_ERROR_UNEXPECTED -txMozillaXMLOutput::txMozillaXMLOutput(const nsAString& aRootName, +txMozillaXMLOutput::txMozillaXMLOutput(const nsSubstring& aRootName, PRInt32 aRootNsID, txOutputFormat* aFormat, nsIDOMDocument* aSourceDocument, @@ -98,6 +90,7 @@ txMozillaXMLOutput::txMozillaXMLOutput(const nsAString& aRootName, mHaveTitleElement(PR_FALSE), mHaveBaseElement(PR_FALSE), mCreatingNewDocument(PR_TRUE), + mOpenedElementIsHTML(PR_FALSE), mRootContentCreated(PR_FALSE) { if (aObserver) { @@ -121,17 +114,18 @@ txMozillaXMLOutput::txMozillaXMLOutput(txOutputFormat* aFormat, mDontAddCurrent(PR_FALSE), mHaveTitleElement(PR_FALSE), mHaveBaseElement(PR_FALSE), - mCreatingNewDocument(PR_FALSE) + mCreatingNewDocument(PR_FALSE), + mOpenedElementIsHTML(PR_FALSE), + mRootContentCreated(PR_FALSE) { mOutputFormat.merge(*aFormat); mOutputFormat.setFromDefaults(); - aFragment->GetOwnerDocument(getter_AddRefs(mDocument)); - - nsCOMPtr doc = do_QueryInterface(mDocument); - mDocumentIsHTML = doc && !doc->IsCaseSensitive(); - - mCurrentNode = aFragment; + mCurrentNode = do_QueryInterface(aFragment); + mDocument = mCurrentNode->GetOwnerDoc(); + if (!mDocument) { + mCurrentNode = nsnull; + } } txMozillaXMLOutput::~txMozillaXMLOutput() @@ -139,44 +133,81 @@ txMozillaXMLOutput::~txMozillaXMLOutput() } nsresult -txMozillaXMLOutput::attribute(const nsAString& aName, +txMozillaXMLOutput::attribute(nsIAtom* aPrefix, + nsIAtom* aLocalName, + nsIAtom* aLowercaseLocalName, const PRInt32 aNsID, - const nsAString& aValue) + const nsString& aValue) { - nsresult rv; - if (!mParentNode) - // XXX Signal this? (can't add attributes after element closed) - return NS_OK; + nsCOMPtr owner; + if (mOpenedElementIsHTML && aNsID == kNameSpaceID_None) { + if (aLowercaseLocalName) { + aLocalName = aLowercaseLocalName; + } + else { + owner = TX_ToLowerCaseAtom(aLocalName); + NS_ENSURE_TRUE(owner, NS_ERROR_OUT_OF_MEMORY); - if (mBadChildLevel) { - return NS_OK; + aLocalName = owner; + } } - nsCOMPtr element = do_QueryInterface(mCurrentNode); - NS_ASSERTION(element, "No element to add the attribute to."); - - if ((mOutputFormat.mMethod == eHTMLOutput) && (aNsID == kNameSpaceID_None)) { - // Outputting HTML as XHTML, lowercase attribute names - nsAutoString lowerName; - TX_ToLowerCase(aName, lowerName); - rv = element->SetAttributeNS(EmptyString(), lowerName, - aValue); - NS_ENSURE_SUCCESS(rv, rv); - } - else { - nsAutoString nsURI; - nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNsID, nsURI); - rv = element->SetAttributeNS(nsURI, aName, aValue); - NS_ENSURE_SUCCESS(rv, rv); - } - - return NS_OK; + return attributeInternal(aPrefix, aLocalName, aNsID, aValue); } nsresult -txMozillaXMLOutput::characters(const nsAString& aData, PRBool aDOE) +txMozillaXMLOutput::attribute(nsIAtom* aPrefix, + const nsSubstring& aLocalName, + const PRInt32 aNsID, + const nsString& aValue) { - nsresult rv = closePrevious(eCloseElement); + nsCOMPtr lname; + + if (mOpenedElementIsHTML && aNsID == kNameSpaceID_None) { + nsAutoString lnameStr; + ToLowerCase(aLocalName, lnameStr); + lname = do_GetAtom(lnameStr); + } + else { + lname = do_GetAtom(aLocalName); + } + + NS_ENSURE_TRUE(lname, NS_ERROR_OUT_OF_MEMORY); + + // Check that it's a valid name + if (!nsContentUtils::IsValidNodeName(lname, aPrefix, aNsID)) { + // Try without prefix + aPrefix = nsnull; + if (!nsContentUtils::IsValidNodeName(lname, aPrefix, aNsID)) { + // Don't return error here since the callers don't deal + return NS_OK; + } + } + + return attributeInternal(aPrefix, lname, aNsID, aValue); +} + +nsresult +txMozillaXMLOutput::attributeInternal(nsIAtom* aPrefix, + nsIAtom* aLocalName, + PRInt32 aNsID, + const nsString& aValue) +{ + if (!mOpenedElement) { + // XXX Signal this? (can't add attributes after element closed) + return NS_OK; + } + + NS_ASSERTION(!mBadChildLevel, "mBadChildLevel set when element is opened"); + + return mOpenedElement->SetAttr(aNsID, aLocalName, aPrefix, aValue, + PR_FALSE); +} + +nsresult +txMozillaXMLOutput::characters(const nsSubstring& aData, PRBool aDOE) +{ + nsresult rv = closePrevious(PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); if (!mBadChildLevel) { @@ -187,9 +218,9 @@ txMozillaXMLOutput::characters(const nsAString& aData, PRBool aDOE) } nsresult -txMozillaXMLOutput::comment(const nsAString& aData) +txMozillaXMLOutput::comment(const nsString& aData) { - nsresult rv = closePrevious(eCloseElement | eFlushText); + nsresult rv = closePrevious(PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); if (mBadChildLevel) { @@ -198,17 +229,21 @@ txMozillaXMLOutput::comment(const nsAString& aData) TX_ENSURE_CURRENTNODE; - nsCOMPtr comment; - rv = mDocument->CreateComment(aData, getter_AddRefs(comment)); + nsCOMPtr comment; + rv = NS_NewCommentNode(getter_AddRefs(comment), mNodeInfoManager); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr resultNode; - return mCurrentNode->AppendChild(comment, getter_AddRefs(resultNode)); + rv = comment->SetText(aData, PR_FALSE); + NS_ENSURE_SUCCESS(rv, rv); + + return mCurrentNode->AppendChildTo(comment, PR_TRUE); } nsresult txMozillaXMLOutput::endDocument(nsresult aResult) { + TX_ENSURE_CURRENTNODE; + if (NS_FAILED(aResult)) { if (mNotifier) { mNotifier->OnTransformEnd(aResult); @@ -217,7 +252,7 @@ txMozillaXMLOutput::endDocument(nsresult aResult) return NS_OK; } - nsresult rv = closePrevious(eCloseElement | eFlushText); + nsresult rv = closePrevious(PR_TRUE); if (NS_FAILED(rv)) { if (mNotifier) { mNotifier->OnTransformEnd(rv); @@ -255,7 +290,7 @@ txMozillaXMLOutput::endDocument(nsresult aResult) } nsresult -txMozillaXMLOutput::endElement(const nsAString& aName, const PRInt32 aNsID) +txMozillaXMLOutput::endElement() { TX_ENSURE_CURRENTNODE; @@ -268,40 +303,26 @@ txMozillaXMLOutput::endElement(const nsAString& aName, const PRInt32 aNsID) --mTreeDepth; -#ifdef DEBUG - if (mTableState != ADDED_TBODY) { - nsAutoString nodeName; - mCurrentNode->GetNodeName(nodeName); - NS_ASSERTION(nodeName.Equals(aName, - nsCaseInsensitiveStringComparator()), - "Unbalanced startElement and endElement calls!"); - } - else { - nsCOMPtr parent; - mCurrentNode->GetParentNode(getter_AddRefs(parent)); - nsAutoString nodeName; - parent->GetNodeName(nodeName); - NS_ASSERTION(nodeName.Equals(aName, - nsCaseInsensitiveStringComparator()), - "Unbalanced startElement and endElement calls!"); - } -#endif - - nsresult rv = closePrevious(eCloseElement | eFlushText); + nsresult rv = closePrevious(PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); + NS_ASSERTION(mCurrentNode->IsNodeOfType(nsINode::eELEMENT), + "borked mCurrentNode"); + NS_ENSURE_TRUE(mCurrentNode->IsNodeOfType(nsINode::eELEMENT), + NS_ERROR_UNEXPECTED); + + nsIContent* element = NS_STATIC_CAST(nsIContent*, + NS_STATIC_CAST(nsINode*, + mCurrentNode)); + // Handle html-elements - if ((mOutputFormat.mMethod == eHTMLOutput && aNsID == kNameSpaceID_None) || - aNsID == kNameSpaceID_XHTML) { - nsCOMPtr element = do_QueryInterface(mCurrentNode); - NS_ASSERTION(element, "endElement'ing non-element"); - + if (element->IsNodeOfType(nsINode::eHTML)) { rv = endHTMLElement(element); NS_ENSURE_SUCCESS(rv, rv); } // Handle svg script elements - if (aNsID == kNameSpaceID_SVG && txHTMLAtoms::script->Equals(aName)) { + if (element->NodeInfo()->Equals(nsGkAtoms::script, kNameSpaceID_SVG)) { // Add this script element to the array of loading script elements. nsCOMPtr scriptElement = do_QueryInterface(mCurrentNode); @@ -330,29 +351,29 @@ txMozillaXMLOutput::endElement(const nsAString& aName, const PRInt32 aNsID) // Add the element to the tree if it wasn't added before and take one step // up the tree - // we can't use GetParentNode to check if mCurrentNode is the - // "non-added node" since that does strange things when we've called - // BindToTree manually + PRUint32 last = mCurrentNodeStack.Count() - 1; + NS_ASSERTION(last != (PRUint32)-1, "empty stack"); + + nsCOMPtr parent = mCurrentNodeStack.SafeObjectAt(last); + mCurrentNodeStack.RemoveObjectAt(last); + if (mCurrentNode == mNonAddedNode) { - nsCOMPtr document = do_QueryInterface(mNonAddedParent); - NS_ASSERTION(!document || !mRootContentCreated, - "mNonAddedParent shouldn't be a document if we have a " - "root content"); - if (document) { + if (parent == mDocument) { + NS_ASSERTION(!mRootContentCreated, + "Parent to add to shouldn't be a document if we " + "have a root content"); mRootContentCreated = PR_TRUE; } - - nsCOMPtr resultNode; - mNonAddedParent->AppendChild(mCurrentNode, getter_AddRefs(resultNode)); - mCurrentNode = mNonAddedParent; - mNonAddedParent = nsnull; + + // Check to make sure that script hasn't inserted the node somewhere + // else in the tree + if (!mCurrentNode->GetNodeParent()) { + parent->AppendChildTo(mNonAddedNode, PR_TRUE); + } mNonAddedNode = nsnull; } - else { - nsCOMPtr parent; - mCurrentNode->GetParentNode(getter_AddRefs(parent)); - mCurrentNode = parent; - } + + mCurrentNode = parent; mTableState = NS_STATIC_CAST(TableState, NS_PTR_TO_INT32(mTableStateStack.pop())); @@ -362,24 +383,26 @@ txMozillaXMLOutput::endElement(const nsAString& aName, const PRInt32 aNsID) void txMozillaXMLOutput::getOutputDocument(nsIDOMDocument** aDocument) { - *aDocument = mDocument; - NS_IF_ADDREF(*aDocument); + CallQueryInterface(mDocument, aDocument); } nsresult -txMozillaXMLOutput::processingInstruction(const nsAString& aTarget, const nsAString& aData) +txMozillaXMLOutput::processingInstruction(const nsString& aTarget, const nsString& aData) { + nsresult rv = closePrevious(PR_TRUE); + NS_ENSURE_SUCCESS(rv, rv); + if (mOutputFormat.mMethod == eHTMLOutput) return NS_OK; - nsresult rv = closePrevious(eCloseElement | eFlushText); - NS_ENSURE_SUCCESS(rv, rv); - TX_ENSURE_CURRENTNODE; - nsCOMPtr pi; - rv = mDocument->CreateProcessingInstruction(aTarget, aData, - getter_AddRefs(pi)); + rv = nsContentUtils::CheckQName(aTarget, PR_FALSE); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr pi; + rv = NS_NewXMLProcessingInstruction(getter_AddRefs(pi), + mNodeInfoManager, aTarget, aData); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr ssle; @@ -391,8 +414,7 @@ txMozillaXMLOutput::processingInstruction(const nsAString& aTarget, const nsAStr } } - nsCOMPtr resultNode; - rv = mCurrentNode->AppendChild(pi, getter_AddRefs(resultNode)); + rv = mCurrentNode->AppendChildTo(pi, PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); if (ssle) { @@ -422,7 +444,67 @@ txMozillaXMLOutput::startDocument() } nsresult -txMozillaXMLOutput::startElement(const nsAString& aName, const PRInt32 aNsID) +txMozillaXMLOutput::startElement(nsIAtom* aPrefix, nsIAtom* aLocalName, + nsIAtom* aLowercaseLocalName, + const PRInt32 aNsID) +{ + NS_PRECONDITION(aNsID != kNameSpaceID_None || !aPrefix, + "Can't have prefix without namespace"); + + if (mOutputFormat.mMethod == eHTMLOutput && aNsID == kNameSpaceID_None) { + nsCOMPtr owner; + if (!aLowercaseLocalName) { + owner = TX_ToLowerCaseAtom(aLocalName); + NS_ENSURE_TRUE(owner, NS_ERROR_OUT_OF_MEMORY); + + aLowercaseLocalName = owner; + } + return startElementInternal(nsnull, aLowercaseLocalName, + kNameSpaceID_None, kNameSpaceID_XHTML); + } + + return startElementInternal(aPrefix, aLocalName, aNsID, aNsID); +} + +nsresult +txMozillaXMLOutput::startElement(nsIAtom* aPrefix, + const nsSubstring& aLocalName, + const PRInt32 aNsID) +{ + PRInt32 elemType = aNsID; + nsCOMPtr lname; + + if (mOutputFormat.mMethod == eHTMLOutput && aNsID == kNameSpaceID_None) { + elemType = kNameSpaceID_XHTML; + + nsAutoString lnameStr; + ToLowerCase(aLocalName, lnameStr); + lname = do_GetAtom(lnameStr); + } + else { + lname = do_GetAtom(aLocalName); + } + + // No biggie if we loose the prefix due to OOM + NS_ENSURE_TRUE(lname, NS_ERROR_OUT_OF_MEMORY); + + // Check that it's a valid name + if (!nsContentUtils::IsValidNodeName(lname, aPrefix, aNsID)) { + // Try without prefix + aPrefix = nsnull; + if (!nsContentUtils::IsValidNodeName(lname, aPrefix, aNsID)) { + return NS_ERROR_XSLT_BAD_NODE_NAME; + } + } + + return startElementInternal(aPrefix, lname, aNsID, elemType); +} + +nsresult +txMozillaXMLOutput::startElementInternal(nsIAtom* aPrefix, + nsIAtom* aLocalName, + PRInt32 aNsID, + PRInt32 aElemType) { TX_ENSURE_CURRENTNODE; @@ -433,9 +515,10 @@ txMozillaXMLOutput::startElement(const nsAString& aName, const PRInt32 aNsID) return NS_OK; } - nsresult rv = closePrevious(eCloseElement | eFlushText); + nsresult rv = closePrevious(PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); + // Push and init state if (mTreeDepth == MAX_REFLOW_DEPTH) { // eCloseElement couldn't add the parent so we fail as well or we've // reached the limit of the depth of the tree that we allow. @@ -450,71 +533,55 @@ txMozillaXMLOutput::startElement(const nsAString& aName, const PRInt32 aNsID) rv = mTableStateStack.push(NS_INT32_TO_PTR(mTableState)); NS_ENSURE_SUCCESS(rv, rv); - mTableState = NORMAL; - - nsCOMPtr element; - mDontAddCurrent = PR_FALSE; - - if ((mOutputFormat.mMethod == eHTMLOutput) && (aNsID == kNameSpaceID_None)) { - if (mDocumentIsHTML) { - rv = mDocument->CreateElement(aName, - getter_AddRefs(element)); - } - else { - nsAutoString lcname; - ToLowerCase(aName, lcname); - rv = mDocument->CreateElementNS(NS_LITERAL_STRING(kXHTMLNameSpaceURI), - lcname, - getter_AddRefs(element)); - } - NS_ENSURE_SUCCESS(rv, rv); - - rv = startHTMLElement(element, PR_FALSE); - NS_ENSURE_SUCCESS(rv, rv); + if (!mCurrentNodeStack.AppendObject(mCurrentNode)) { + return NS_ERROR_OUT_OF_MEMORY; } - else { - nsAutoString nsURI; - nsContentUtils::NameSpaceManager()->GetNameSpaceURI(aNsID, nsURI); - rv = mDocument->CreateElementNS(nsURI, aName, - getter_AddRefs(element)); + + mTableState = NORMAL; + mDontAddCurrent = PR_FALSE; + mOpenedElementIsHTML = PR_FALSE; + + // Create the element + nsCOMPtr ni; + rv = mNodeInfoManager->GetNodeInfo(aLocalName, aPrefix, aNsID, + getter_AddRefs(ni)); + NS_ENSURE_SUCCESS(rv, rv); + + NS_NewElement(getter_AddRefs(mOpenedElement), aElemType, ni); + + // Set up the element and adjust state + if (aElemType == kNameSpaceID_XHTML) { + mOpenedElementIsHTML = aNsID != kNameSpaceID_XHTML; + rv = startHTMLElement(mOpenedElement, mOpenedElementIsHTML); NS_ENSURE_SUCCESS(rv, rv); - if (aNsID == kNameSpaceID_XHTML) { - rv = startHTMLElement(element, PR_TRUE); - NS_ENSURE_SUCCESS(rv, rv); - - } else if (aNsID == kNameSpaceID_SVG && - txHTMLAtoms::script->Equals(aName)) { - mDontAddCurrent = PR_TRUE; - } + } + else if (aNsID == kNameSpaceID_SVG && aLocalName == txHTMLAtoms::script) { + mDontAddCurrent = PR_TRUE; } if (mCreatingNewDocument) { // Handle all sorts of stylesheets nsCOMPtr ssle = - do_QueryInterface(element); + do_QueryInterface(mOpenedElement); if (ssle) { ssle->InitStyleLinkElement(nsnull, PR_FALSE); ssle->SetEnableUpdates(PR_FALSE); } } - mParentNode = mCurrentNode; - mCurrentNode = do_QueryInterface(element); return NS_OK; } nsresult -txMozillaXMLOutput::closePrevious(PRInt8 aAction) +txMozillaXMLOutput::closePrevious(PRBool aFlushText) { TX_ENSURE_CURRENTNODE; nsresult rv; - if ((aAction & eCloseElement) && mParentNode) { - nsCOMPtr document = do_QueryInterface(mParentNode); - nsCOMPtr currentElement = do_QueryInterface(mCurrentNode); - - if (document && currentElement && mRootContentCreated) { + if (mOpenedElement) { + PRBool currentIsDoc = mCurrentNode == mDocument; + if (currentIsDoc && mRootContentCreated) { // We already have a document element, but the XSLT spec allows this. // As a workaround, create a wrapper object and use that as the // document element. @@ -523,22 +590,21 @@ txMozillaXMLOutput::closePrevious(PRInt8 aAction) NS_ENSURE_SUCCESS(rv, rv); } - if (mDontAddCurrent && !mNonAddedParent) { - mNonAddedParent = mParentNode; - mNonAddedNode = mCurrentNode; + if (mDontAddCurrent && !mNonAddedNode) { + mNonAddedNode = mOpenedElement; } else { - if (document && currentElement) { + if (currentIsDoc) { mRootContentCreated = PR_TRUE; } - nsCOMPtr resultNode; - rv = mParentNode->AppendChild(mCurrentNode, getter_AddRefs(resultNode)); + rv = mCurrentNode->AppendChildTo(mOpenedElement, PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); } - mParentNode = nsnull; + mCurrentNode = mOpenedElement; + mOpenedElement = nsnull; } - else if ((aAction & eFlushText) && !mText.IsEmpty()) { + else if (aFlushText && !mText.IsEmpty()) { // Text can't appear in the root of a document if (mDocument == mCurrentNode) { if (XMLUtils::isWhitespace(mText)) { @@ -550,12 +616,14 @@ txMozillaXMLOutput::closePrevious(PRInt8 aAction) rv = createTxWrapper(); NS_ENSURE_SUCCESS(rv, rv); } - nsCOMPtr text; - rv = mDocument->CreateTextNode(mText, getter_AddRefs(text)); + nsCOMPtr text; + rv = NS_NewTextNode(getter_AddRefs(text), mNodeInfoManager); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr resultNode; - rv = mCurrentNode->AppendChild(text, getter_AddRefs(resultNode)); + rv = text->SetText(mText, PR_FALSE); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mCurrentNode->AppendChildTo(text, PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); mText.Truncate(); @@ -567,137 +635,122 @@ txMozillaXMLOutput::closePrevious(PRInt8 aAction) nsresult txMozillaXMLOutput::createTxWrapper() { - NS_ASSERTION(mParentNode ? mDocument == mParentNode : - mDocument == mCurrentNode, + NS_ASSERTION(mDocument == mCurrentNode, "creating wrapper when document isn't parent"); - nsCOMPtr document = do_QueryInterface(mDocument); - nsCOMPtr wrapper; - nsresult rv = - mDocument->CreateElementNS(NS_LITERAL_STRING(kTXNameSpaceURI), - NS_LITERAL_STRING(kTXWrapper), - getter_AddRefs(wrapper)); + PRInt32 namespaceID; + nsresult rv = nsContentUtils::NameSpaceManager()-> + RegisterNameSpace(NS_LITERAL_STRING(kTXNameSpaceURI), namespaceID); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr child, resultNode; - PRUint32 i, j, childCount = document->GetChildCount(); + nsCOMPtr wrapper; + rv = mDocument->CreateElem(nsGkAtoms::result, nsGkAtoms::transformiix, + namespaceID, PR_FALSE, getter_AddRefs(wrapper)); + NS_ENSURE_SUCCESS(rv, rv); + + PRUint32 i, j, childCount = mDocument->GetChildCount(); #ifdef DEBUG // Keep track of the location of the current documentElement, if there is // one, so we can verify later PRUint32 rootLocation = 0; #endif for (i = 0, j = 0; i < childCount; ++i) { - nsIContent* childContent = document->GetChildAt(j); - child = do_QueryInterface(childContent); - PRUint16 nodeType; - child->GetNodeType(&nodeType); - switch (nodeType) { - case nsIDOMNode::ELEMENT_NODE: + nsIContent* childContent = mDocument->GetChildAt(j); + #ifdef DEBUG - rootLocation = j; - // Fall through + if (childContent->IsNodeOfType(nsINode::eELEMENT)) { + rootLocation = j; + } #endif - case nsIDOMNode::TEXT_NODE: - case nsIDOMNode::CDATA_SECTION_NODE: - case nsIDOMNode::ENTITY_REFERENCE_NODE: - case nsIDOMNode::PROCESSING_INSTRUCTION_NODE: - case nsIDOMNode::COMMENT_NODE: - { - // XXX need to propagate error - rv = wrapper->AppendChild(child, - getter_AddRefs(resultNode)); - NS_ENSURE_SUCCESS(rv, rv); - break; - } - case nsIDOMNode::DOCUMENT_TYPE_NODE: + + if (childContent->Tag() == nsGkAtoms::documentTypeNodeName) { #ifdef DEBUG - // The new documentElement should go after the document type. - // This is needed for cases when there is no existing - // documentElement in the document. - rootLocation = PR_MAX(rootLocation, j+1); - // Fall through + // The new documentElement should go after the document type. + // This is needed for cases when there is no existing + // documentElement in the document. + rootLocation = PR_MAX(rootLocation, j + 1); #endif - default: - { - ++j; - } + ++j; + } + else { + rv = mDocument->RemoveChildAt(j, PR_TRUE); + NS_ENSURE_SUCCESS(rv, rv); + + rv = wrapper->AppendChildTo(childContent, PR_TRUE); + NS_ENSURE_SUCCESS(rv, rv); + break; } } - if (mParentNode) { - mParentNode = wrapper; - } - else { - mCurrentNode = wrapper; - } - + mCurrentNode = wrapper; mRootContentCreated = PR_TRUE; - nsCOMPtr wrapperContent = do_QueryInterface(wrapper); - NS_ASSERTION(wrapperContent, "Must have wrapper content"); - NS_ASSERTION(rootLocation == document->GetChildCount(), + NS_ASSERTION(rootLocation == mDocument->GetChildCount(), "Incorrect root location"); - return document->AppendChildTo(wrapperContent, PR_TRUE); + return mDocument->AppendChildTo(wrapper, PR_TRUE); } nsresult -txMozillaXMLOutput::startHTMLElement(nsIDOMElement* aElement, PRBool aXHTML) +txMozillaXMLOutput::startHTMLElement(nsIContent* aElement, PRBool aIsHTML) { nsresult rv = NS_OK; - nsCOMPtr content = do_QueryInterface(aElement); - nsIAtom *atom = content->Tag(); + nsIAtom *atom = aElement->Tag(); mDontAddCurrent = (atom == txHTMLAtoms::script); - if ((atom != txHTMLAtoms::tr || aXHTML) && + if ((atom != txHTMLAtoms::tr || !aIsHTML) && NS_PTR_TO_INT32(mTableStateStack.peek()) == ADDED_TBODY) { - nsCOMPtr parent; - mCurrentNode->GetParentNode(getter_AddRefs(parent)); - mCurrentNode.swap(parent); + PRUint32 last = mCurrentNodeStack.Count() - 1; + NS_ASSERTION(last != (PRUint32)-1, "empty stack"); + + mCurrentNode = mCurrentNodeStack.SafeObjectAt(last); + mCurrentNodeStack.RemoveObjectAt(last); mTableStateStack.pop(); } - if (atom == txHTMLAtoms::table && !aXHTML) { + if (atom == txHTMLAtoms::table && aIsHTML) { mTableState = TABLE; } - else if (atom == txHTMLAtoms::tr && !aXHTML && + else if (atom == txHTMLAtoms::tr && aIsHTML && NS_PTR_TO_INT32(mTableStateStack.peek()) == TABLE) { - nsCOMPtr elem; - rv = createHTMLElement(NS_LITERAL_STRING("tbody"), - getter_AddRefs(elem)); + nsCOMPtr tbody; + rv = createHTMLElement(nsGkAtoms::tbody, getter_AddRefs(tbody)); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr dummy; - rv = mCurrentNode->AppendChild(elem, getter_AddRefs(dummy)); + rv = mCurrentNode->AppendChildTo(tbody, PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); rv = mTableStateStack.push(NS_INT32_TO_PTR(ADDED_TBODY)); NS_ENSURE_SUCCESS(rv, rv); - mCurrentNode = elem; + if (!mCurrentNodeStack.AppendObject(tbody)) { + return NS_ERROR_OUT_OF_MEMORY; + } + + mCurrentNode = tbody; } else if (atom == txHTMLAtoms::head && mOutputFormat.mMethod == eHTMLOutput) { // Insert META tag, according to spec, 16.2, like // - nsCOMPtr meta; - rv = createHTMLElement(NS_LITERAL_STRING("meta"), - getter_AddRefs(meta)); + nsCOMPtr meta; + rv = createHTMLElement(nsGkAtoms::meta, getter_AddRefs(meta)); NS_ENSURE_SUCCESS(rv, rv); - rv = meta->SetAttribute(NS_LITERAL_STRING("http-equiv"), - NS_LITERAL_STRING("Content-Type")); + rv = meta->SetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, + NS_LITERAL_STRING("Content-Type"), PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); nsAutoString metacontent; metacontent.Append(mOutputFormat.mMediaType); metacontent.AppendLiteral("; charset="); metacontent.Append(mOutputFormat.mEncoding); - rv = meta->SetAttribute(NS_LITERAL_STRING("content"), - metacontent); + rv = meta->SetAttr(kNameSpaceID_None, nsGkAtoms::content, + metacontent, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr dummy; - rv = aElement->AppendChild(meta, getter_AddRefs(dummy)); + // No need to notify since aElement hasn't been inserted yet + NS_ASSERTION(!aElement->IsInDoc(), "should not be in doc"); + rv = aElement->AppendChildTo(meta, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); } @@ -705,20 +758,19 @@ txMozillaXMLOutput::startHTMLElement(nsIDOMElement* aElement, PRBool aXHTML) } nsresult -txMozillaXMLOutput::endHTMLElement(nsIDOMElement* aElement) +txMozillaXMLOutput::endHTMLElement(nsIContent* aElement) { nsresult rv; - nsCOMPtr content = do_QueryInterface(aElement); - NS_ASSERTION(content, "Can't QI to nsIContent"); - - nsIAtom *atom = content->Tag(); + nsIAtom *atom = aElement->Tag(); if (mTableState == ADDED_TBODY) { NS_ASSERTION(atom == txHTMLAtoms::tbody, "Element flagged as added tbody isn't a tbody"); - nsCOMPtr parent; - mCurrentNode->GetParentNode(getter_AddRefs(parent)); - mCurrentNode = parent; + PRUint32 last = mCurrentNodeStack.Count() - 1; + NS_ASSERTION(last != (PRUint32)-1, "empty stack"); + + mCurrentNode = mCurrentNodeStack.SafeObjectAt(last); + mCurrentNodeStack.RemoveObjectAt(last); mTableState = NS_STATIC_CAST(TableState, NS_PTR_TO_INT32(mTableStateStack.pop())); @@ -740,13 +792,13 @@ txMozillaXMLOutput::endHTMLElement(nsIDOMElement* aElement) // The first title wins mHaveTitleElement = PR_TRUE; nsCOMPtr domDoc = do_QueryInterface(mDocument); - nsCOMPtr textNode; - aElement->GetFirstChild(getter_AddRefs(textNode)); - if (domDoc && textNode) { - nsAutoString text; - textNode->GetNodeValue(text); - text.CompressWhitespace(); - domDoc->SetTitle(text); + + nsAutoString title; + nsContentUtils::GetNodeTextContent(aElement, PR_TRUE, title); + + if (domDoc) { + title.CompressWhitespace(); + domDoc->SetTitle(title); } } else if (mCreatingNewDocument && atom == txHTMLAtoms::base && @@ -757,10 +809,10 @@ txMozillaXMLOutput::endHTMLElement(nsIDOMElement* aElement) nsCOMPtr doc = do_QueryInterface(mDocument); NS_ASSERTION(doc, "document doesn't implement nsIDocument"); nsAutoString value; - content->GetAttr(kNameSpaceID_None, txHTMLAtoms::target, value); + aElement->GetAttr(kNameSpaceID_None, txHTMLAtoms::target, value); doc->SetBaseTarget(value); - content->GetAttr(kNameSpaceID_None, txHTMLAtoms::href, value); + aElement->GetAttr(kNameSpaceID_None, txHTMLAtoms::href, value); nsCOMPtr baseURI; rv = NS_NewURI(getter_AddRefs(baseURI), value, nsnull); NS_ENSURE_SUCCESS(rv, rv); @@ -770,12 +822,12 @@ txMozillaXMLOutput::endHTMLElement(nsIDOMElement* aElement) else if (mCreatingNewDocument && atom == txHTMLAtoms::meta) { // handle HTTP-EQUIV data nsAutoString httpEquiv; - content->GetAttr(kNameSpaceID_None, txHTMLAtoms::httpEquiv, httpEquiv); + aElement->GetAttr(kNameSpaceID_None, txHTMLAtoms::httpEquiv, httpEquiv); if (!httpEquiv.IsEmpty()) { nsAutoString value; - content->GetAttr(kNameSpaceID_None, txHTMLAtoms::content, value); + aElement->GetAttr(kNameSpaceID_None, txHTMLAtoms::content, value); if (!value.IsEmpty()) { - TX_ToLowerCase(httpEquiv); + ToLowerCase(httpEquiv); nsCOMPtr header = do_GetAtom(httpEquiv); processHTTPEquiv(header, value); } @@ -785,7 +837,7 @@ txMozillaXMLOutput::endHTMLElement(nsIDOMElement* aElement) return NS_OK; } -void txMozillaXMLOutput::processHTTPEquiv(nsIAtom* aHeader, const nsAString& aValue) +void txMozillaXMLOutput::processHTTPEquiv(nsIAtom* aHeader, const nsString& aValue) { // For now we only handle "refresh". There's a longer list in // HTMLContentSink::ProcessHeaderData @@ -794,43 +846,34 @@ void txMozillaXMLOutput::processHTTPEquiv(nsIAtom* aHeader, const nsAString& aVa } nsresult -txMozillaXMLOutput::createResultDocument(const nsAString& aName, PRInt32 aNsID, +txMozillaXMLOutput::createResultDocument(const nsSubstring& aName, PRInt32 aNsID, nsIDOMDocument* aSourceDocument, nsIDOMDocument* aResultDocument) { nsresult rv; - nsCOMPtr doc; if (!aResultDocument) { // Create the document if (mOutputFormat.mMethod == eHTMLOutput) { - doc = do_CreateInstance(kHTMLDocumentCID, &rv); + rv = NS_NewHTMLDocument(getter_AddRefs(mDocument)); NS_ENSURE_SUCCESS(rv, rv); - - mDocumentIsHTML = PR_TRUE; } else { // We should check the root name/namespace here and create the // appropriate document - doc = do_CreateInstance(kXMLDocumentCID, &rv); + rv = NS_NewXMLDocument(getter_AddRefs(mDocument)); NS_ENSURE_SUCCESS(rv, rv); - - mDocumentIsHTML = PR_FALSE; } - mDocument = do_QueryInterface(doc); } else { - mDocument = aResultDocument; - doc = do_QueryInterface(aResultDocument); - - nsCOMPtr doc = do_QueryInterface(aResultDocument); - mDocumentIsHTML = doc && !doc->IsCaseSensitive(); + mDocument = do_QueryInterface(aResultDocument); } mCurrentNode = mDocument; + mNodeInfoManager = mDocument->NodeInfoManager(); // Reset and set up the document - URIUtils::ResetWithSource(doc, aSourceDocument); + URIUtils::ResetWithSource(mDocument, aSourceDocument); // Set the charset if (!mOutputFormat.mEncoding.IsEmpty()) { @@ -841,20 +884,20 @@ txMozillaXMLOutput::createResultDocument(const nsAString& aName, PRInt32 aNsID, if (calias && NS_SUCCEEDED(calias->GetPreferred(charset, canonicalCharset))) { - doc->SetDocumentCharacterSet(canonicalCharset); - doc->SetDocumentCharacterSetSource(kCharsetFromOtherComponent); + mDocument->SetDocumentCharacterSet(canonicalCharset); + mDocument->SetDocumentCharacterSetSource(kCharsetFromOtherComponent); } } // Set the mime-type if (!mOutputFormat.mMediaType.IsEmpty()) { - doc->SetContentType(mOutputFormat.mMediaType); + mDocument->SetContentType(mOutputFormat.mMediaType); } else if (mOutputFormat.mMethod == eHTMLOutput) { - doc->SetContentType(NS_LITERAL_STRING("text/html")); + mDocument->SetContentType(NS_LITERAL_STRING("text/html")); } else { - doc->SetContentType(NS_LITERAL_STRING("application/xml")); + mDocument->SetContentType(NS_LITERAL_STRING("application/xml")); } if (mOutputFormat.mMethod == eXMLOutput && @@ -873,12 +916,12 @@ txMozillaXMLOutput::createResultDocument(const nsAString& aName, PRInt32 aNsID, // Could use mOutputFormat.mVersion.get() when we support // versions > 1.0. static const PRUnichar kOneDotZero[] = { '1', '.', '0', '\0' }; - doc->SetXMLDeclaration(kOneDotZero, mOutputFormat.mEncoding.get(), - standalone); + mDocument->SetXMLDeclaration(kOneDotZero, mOutputFormat.mEncoding.get(), + standalone); } // Set up script loader of the result document. - nsIScriptLoader *loader = doc->GetScriptLoader(); + nsIScriptLoader *loader = mDocument->GetScriptLoader(); if (loader) { if (mNotifier) { loader->AddObserver(mNotifier); @@ -896,16 +939,13 @@ txMozillaXMLOutput::createResultDocument(const nsAString& aName, PRInt32 aNsID, // Do this after calling OnDocumentCreated to ensure that the // PresShell/PresContext has been hooked up and get notified. - nsCOMPtr htmlDoc = do_QueryInterface(doc); + nsCOMPtr htmlDoc = do_QueryInterface(mDocument); if (htmlDoc) { htmlDoc->SetCompatibilityMode(eCompatibility_FullStandards); } // Add a doc-type if requested if (!mOutputFormat.mSystemId.IsEmpty()) { - nsCOMPtr implementation; - rv = aSourceDocument->GetImplementation(getter_AddRefs(implementation)); - NS_ENSURE_SUCCESS(rv, rv); nsAutoString qName; if (mOutputFormat.mMethod == eHTMLOutput) { qName.AssignLiteral("html"); @@ -913,31 +953,49 @@ txMozillaXMLOutput::createResultDocument(const nsAString& aName, PRInt32 aNsID, else { qName.Assign(aName); } - nsCOMPtr documentType; - rv = implementation->CreateDocumentType(qName, - mOutputFormat.mPublicId, - mOutputFormat.mSystemId, - getter_AddRefs(documentType)); - NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr tmp; - rv = mDocument->AppendChild(documentType, getter_AddRefs(tmp)); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr documentType; + + nsresult rv = nsContentUtils::CheckQName(qName); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr doctypeName = do_GetAtom(qName); + if (!doctypeName) { + return NS_ERROR_OUT_OF_MEMORY; + } + + rv = NS_NewDOMDocumentType(getter_AddRefs(documentType), + mNodeInfoManager, nsnull, + doctypeName, nsnull, nsnull, + mOutputFormat.mPublicId, + mOutputFormat.mSystemId, + EmptyString()); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr docType = do_QueryInterface(documentType); + rv = mDocument->AppendChildTo(docType, PR_TRUE); + NS_ENSURE_SUCCESS(rv, rv); + } } return NS_OK; } nsresult -txMozillaXMLOutput::createHTMLElement(const nsAString& aName, - nsIDOMElement** aResult) +txMozillaXMLOutput::createHTMLElement(nsIAtom* aName, + nsIContent** aResult) { - if (mDocumentIsHTML) { - return mDocument->CreateElement(aName, aResult); - } + NS_ASSERTION(mOutputFormat.mMethod == eHTMLOutput, + "need to adjust createHTMLElement"); - return mDocument->CreateElementNS(NS_LITERAL_STRING(kXHTMLNameSpaceURI), - aName, aResult); + *aResult = nsnull; + + nsCOMPtr ni; + nsresult rv = mNodeInfoManager->GetNodeInfo(aName, nsnull, + kNameSpaceID_None, + getter_AddRefs(ni)); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_NewHTMLElement(aResult, ni); } txTransformNotifier::txTransformNotifier() @@ -1035,7 +1093,7 @@ txTransformNotifier::OnTransformStart() } nsresult -txTransformNotifier::SetOutputDocument(nsIDOMDocument* aDocument) +txTransformNotifier::SetOutputDocument(nsIDocument* aDocument) { mDocument = aDocument; diff --git a/content/xslt/src/xslt/txMozillaXMLOutput.h b/content/xslt/src/xslt/txMozillaXMLOutput.h index 7e675857f4ef..fbaf0d428789 100644 --- a/content/xslt/src/xslt/txMozillaXMLOutput.h +++ b/content/xslt/src/xslt/txMozillaXMLOutput.h @@ -55,6 +55,9 @@ class nsIDOMElement; class nsIStyleSheet; class nsIDOMNode; class nsITransformObserver; +class nsNodeInfoManager; +class nsIDocument; +class nsINode; class txTransformNotifier : public nsIScriptLoaderObserver, public nsICSSLoaderObserver @@ -76,12 +79,12 @@ public: nsresult AddStyleSheet(nsIStyleSheet* aStyleSheet); void OnTransformEnd(nsresult aResult = NS_OK); void OnTransformStart(); - nsresult SetOutputDocument(nsIDOMDocument* aDocument); + nsresult SetOutputDocument(nsIDocument* aDocument); private: void SignalTransformEnd(nsresult aResult = NS_OK); - nsCOMPtr mDocument; + nsCOMPtr mDocument; nsCOMPtr mObserver; nsCOMArray mScriptElements; nsCOMArray mStylesheets; @@ -91,7 +94,7 @@ private: class txMozillaXMLOutput : public txAOutputXMLEventHandler { public: - txMozillaXMLOutput(const nsAString& aRootName, + txMozillaXMLOutput(const nsSubstring& aRootName, PRInt32 aRootNsID, txOutputFormat* aFormat, nsIDOMDocument* aSourceDocument, @@ -105,23 +108,34 @@ public: TX_DECL_TXAOUTPUTXMLEVENTHANDLER private: - nsresult closePrevious(PRInt8 aAction); + nsresult closePrevious(PRBool aFlushText); nsresult createTxWrapper(); - nsresult startHTMLElement(nsIDOMElement* aElement, PRBool aXHTML); - nsresult endHTMLElement(nsIDOMElement* aElement); - void processHTTPEquiv(nsIAtom* aHeader, const nsAString& aValue); - nsresult createResultDocument(const nsAString& aName, PRInt32 aNsID, + nsresult startHTMLElement(nsIContent* aElement, PRBool aXHTML); + nsresult endHTMLElement(nsIContent* aElement); + void processHTTPEquiv(nsIAtom* aHeader, const nsString& aValue); + nsresult createResultDocument(const nsSubstring& aName, PRInt32 aNsID, nsIDOMDocument* aSourceDocument, nsIDOMDocument* aResultDocument); - nsresult createHTMLElement(const nsAString& aName, - nsIDOMElement** aResult); + nsresult createHTMLElement(nsIAtom* aName, + nsIContent** aResult); - nsCOMPtr mDocument; - nsCOMPtr mCurrentNode; - nsCOMPtr mParentNode; + nsresult attributeInternal(nsIAtom* aPrefix, nsIAtom* aLocalName, + PRInt32 aNsID, const nsString& aValue); + nsresult startElementInternal(nsIAtom* aPrefix, nsIAtom* aLocalName, + PRInt32 aNsID, PRInt32 aElemType); - nsCOMPtr mNonAddedParent; - nsCOMPtr mNonAddedNode; + nsCOMPtr mDocument; + nsCOMPtr mCurrentNode; // This is updated once an element is + // 'closed' (i.e. once we're done + // adding attributes to it). + // until then the opened element is + // kept in mOpenedElement + nsCOMPtr mOpenedElement; + nsRefPtr mNodeInfoManager; + + nsCOMArray mCurrentNodeStack; + + nsCOMPtr mNonAddedNode; nsRefPtr mNotifier; @@ -129,7 +143,7 @@ private: nsCString mRefreshString; txStack mTableStateStack; - enum TableState { + enum TableState { NORMAL, // An element needing no special treatment TABLE, // A HTML table element ADDED_TBODY // An inserted tbody not coming from the stylesheet @@ -145,9 +159,10 @@ private: PRPackedBool mHaveTitleElement; PRPackedBool mHaveBaseElement; - PRPackedBool mDocumentIsHTML; PRPackedBool mCreatingNewDocument; + PRPackedBool mOpenedElementIsHTML; + // Set to true when we know there's a root content in our document. PRPackedBool mRootContentCreated; diff --git a/content/xslt/src/xslt/txMozillaXSLTProcessor.cpp b/content/xslt/src/xslt/txMozillaXSLTProcessor.cpp index 0fe16121b096..a4e4c613eb19 100644 --- a/content/xslt/src/xslt/txMozillaXSLTProcessor.cpp +++ b/content/xslt/src/xslt/txMozillaXSLTProcessor.cpp @@ -151,7 +151,7 @@ txToDocHandlerFactory::createHandlerWith(txOutputFormat* aFormat, nsresult txToDocHandlerFactory::createHandlerWith(txOutputFormat* aFormat, - const nsAString& aName, + const nsSubstring& aName, PRInt32 aNsID, txAXMLEventHandler** aHandler) { @@ -229,7 +229,7 @@ txToFragmentHandlerFactory::createHandlerWith(txOutputFormat* aFormat, nsresult txToFragmentHandlerFactory::createHandlerWith(txOutputFormat* aFormat, - const nsAString& aName, + const nsSubstring& aName, PRInt32 aNsID, txAXMLEventHandler** aHandler) { @@ -1165,7 +1165,7 @@ txMozillaXSLTProcessor::notifyError() } } - mObserver->OnTransformDone(mTransformResult, errorDocument); + mObserver->OnTransformDone(mTransformResult, document); } nsresult diff --git a/content/xslt/src/xslt/txTextHandler.cpp b/content/xslt/src/xslt/txTextHandler.cpp index 53444064c405..00b56c73fbd6 100644 --- a/content/xslt/src/xslt/txTextHandler.cpp +++ b/content/xslt/src/xslt/txTextHandler.cpp @@ -49,15 +49,23 @@ txTextHandler::~txTextHandler() } nsresult -txTextHandler::attribute(const nsAString& aName, - const PRInt32 aNsID, - const nsAString& aValue) +txTextHandler::attribute(nsIAtom* aPrefix, nsIAtom* aLocalName, + nsIAtom* aLowercaseLocalName, PRInt32 aNsID, + const nsString& aValue) { return NS_OK; } nsresult -txTextHandler::characters(const nsAString& aData, PRBool aDOE) +txTextHandler::attribute(nsIAtom* aPrefix, const nsSubstring& aLocalName, + const PRInt32 aNsID, + const nsString& aValue) +{ + return NS_OK; +} + +nsresult +txTextHandler::characters(const nsSubstring& aData, PRBool aDOE) { if (mLevel == 0) mValue.Append(aData); @@ -66,7 +74,7 @@ txTextHandler::characters(const nsAString& aData, PRBool aDOE) } nsresult -txTextHandler::comment(const nsAString& aData) +txTextHandler::comment(const nsString& aData) { return NS_OK; } @@ -78,7 +86,7 @@ txTextHandler::endDocument(nsresult aResult) } nsresult -txTextHandler::endElement(const nsAString& aName, const PRInt32 aNsID) +txTextHandler::endElement() { if (mOnlyText) --mLevel; @@ -87,7 +95,7 @@ txTextHandler::endElement(const nsAString& aName, const PRInt32 aNsID) } nsresult -txTextHandler::processingInstruction(const nsAString& aTarget, const nsAString& aData) +txTextHandler::processingInstruction(const nsString& aTarget, const nsString& aData) { return NS_OK; } @@ -99,7 +107,18 @@ txTextHandler::startDocument() } nsresult -txTextHandler::startElement(const nsAString& aName, const PRInt32 aNsID) +txTextHandler::startElement(nsIAtom* aPrefix, nsIAtom* aLocalName, + nsIAtom* aLowercaseLocalName, const PRInt32 aNsID) +{ + if (mOnlyText) + ++mLevel; + + return NS_OK; +} + +nsresult +txTextHandler::startElement(nsIAtom* aPrefix, const nsSubstring& aLocalName, + const PRInt32 aNsID) { if (mOnlyText) ++mLevel; diff --git a/content/xslt/src/xslt/txUnknownHandler.cpp b/content/xslt/src/xslt/txUnknownHandler.cpp index 96132f5d4b9f..6ade06156223 100644 --- a/content/xslt/src/xslt/txUnknownHandler.cpp +++ b/content/xslt/src/xslt/txUnknownHandler.cpp @@ -40,6 +40,7 @@ #include "txExecutionState.h" #include "txStringUtils.h" #include "txStylesheet.h" +#include "txAtoms.h" txUnknownHandler::txUnknownHandler(txExecutionState* aEs) : mEs(aEs) @@ -50,18 +51,6 @@ txUnknownHandler::~txUnknownHandler() { } -nsresult -txUnknownHandler::attribute(const nsAString& aName, - const PRInt32 aNsID, - const nsAString& aValue) -{ - // If this is called then the stylesheet is trying to add an attribute - // without adding an element first. So we'll just ignore it. - // XXX ErrorReport: Signal this? - - return NS_OK; -} - nsresult txUnknownHandler::endDocument(nsresult aResult) { @@ -79,7 +68,7 @@ txUnknownHandler::endDocument(nsresult aResult) NS_ASSERTION(mEs->mResultHandler == this, "We're leaking mEs->mResultHandler and are going to crash."); - nsresult rv = createHandlerAndFlush(eXMLOutput, EmptyString(), + nsresult rv = createHandlerAndFlush(PR_FALSE, EmptyString(), kNameSpaceID_None); NS_ENSURE_SUCCESS(rv, rv); @@ -91,7 +80,8 @@ txUnknownHandler::endDocument(nsresult aResult) } nsresult -txUnknownHandler::startElement(const nsAString& aName, const PRInt32 aNsID) +txUnknownHandler::startElement(nsIAtom* aPrefix, nsIAtom* aLocalName, + nsIAtom* aLowercaseLocalName, PRInt32 aNsID) { // Make sure that mEs->mResultHandler == this is true, otherwise we'll // leak mEs->mResultHandler in createHandlerAndFlush and we may crash @@ -99,37 +89,67 @@ txUnknownHandler::startElement(const nsAString& aName, const PRInt32 aNsID) NS_ASSERTION(mEs->mResultHandler == this, "We're leaking mEs->mResultHandler."); - nsresult rv = NS_OK; - txOutputFormat* format = mEs->mStylesheet->getOutputFormat(); - if (format->mMethod != eMethodNotSet) { - rv = createHandlerAndFlush(format->mMethod, aName, aNsID); - } - else if (aNsID == kNameSpaceID_None && - aName.Equals(NS_LITERAL_STRING("html"), - txCaseInsensitiveStringComparator())) { - rv = createHandlerAndFlush(eHTMLOutput, aName, aNsID); - } - else { - rv = createHandlerAndFlush(eXMLOutput, aName, aNsID); + nsCOMPtr owner; + if (!aLowercaseLocalName) { + owner = TX_ToLowerCaseAtom(aLocalName); + NS_ENSURE_TRUE(owner, NS_ERROR_OUT_OF_MEMORY); + + aLowercaseLocalName = owner; } + + PRBool htmlRoot = aNsID == kNameSpaceID_None && !aPrefix && + aLowercaseLocalName == txHTMLAtoms::html; + + // Use aLocalName and not aLowercaseLocalName in case the output + // handler cares about case. For eHTMLOutput the handler will hardcode + // to 'html' anyway. + nsAutoString name; + aLocalName->ToString(name); + nsresult rv = createHandlerAndFlush(htmlRoot, name, aNsID); NS_ENSURE_SUCCESS(rv, rv); - rv = mEs->mResultHandler->startElement(aName, aNsID); + rv = mEs->mResultHandler->startElement(aPrefix, aLocalName, + aLowercaseLocalName, aNsID); delete this; return rv; } -nsresult txUnknownHandler::createHandlerAndFlush(txOutputMethod aMethod, - const nsAString& aName, +nsresult +txUnknownHandler::startElement(nsIAtom* aPrefix, const nsSubstring& aLocalName, + const PRInt32 aNsID) +{ + // Make sure that mEs->mResultHandler == this is true, otherwise we'll + // leak mEs->mResultHandler in createHandlerAndFlush and we may crash + // later on trying to delete this handler again. + NS_ASSERTION(mEs->mResultHandler == this, + "We're leaking mEs->mResultHandler."); + + PRBool htmlRoot = aNsID == kNameSpaceID_None && !aPrefix && + aLocalName.Equals(NS_LITERAL_STRING("html"), + txCaseInsensitiveStringComparator()); + nsresult rv = createHandlerAndFlush(htmlRoot, aLocalName, aNsID); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mEs->mResultHandler->startElement(aPrefix, aLocalName, aNsID); + + delete this; + + return rv; +} + +nsresult txUnknownHandler::createHandlerAndFlush(PRBool aHTMLRoot, + const nsSubstring& aName, const PRInt32 aNsID) { NS_ENSURE_TRUE(mBuffer, NS_ERROR_NOT_INITIALIZED); txOutputFormat format; - format.merge(*mEs->mStylesheet->getOutputFormat()); - format.mMethod = aMethod; + format.merge(*(mEs->mStylesheet->getOutputFormat())); + if (format.mMethod == eMethodNotSet) { + format.mMethod = aHTMLRoot ? eHTMLOutput : eXMLOutput; + } txAXMLEventHandler *handler = nsnull; nsresult rv = mEs->mOutputHandlerFactory->createHandlerWith(&format, aName, diff --git a/content/xslt/src/xslt/txUnknownHandler.h b/content/xslt/src/xslt/txUnknownHandler.h index 3eaa35d24e53..7a62aa7a0d62 100644 --- a/content/xslt/src/xslt/txUnknownHandler.h +++ b/content/xslt/src/xslt/txUnknownHandler.h @@ -50,14 +50,15 @@ public: txUnknownHandler(txExecutionState* aEs); virtual ~txUnknownHandler(); - nsresult attribute(const nsAString& aName, const PRInt32 aNsID, - const nsAString& aValue); nsresult endDocument(nsresult aResult); - nsresult startElement(const nsAString& aName, const PRInt32 aNsID); + nsresult startElement(nsIAtom* aPrefix, nsIAtom* aName, + nsIAtom* aLowercaseName, PRInt32 aNsID); + nsresult startElement(nsIAtom* aPrefix, const nsSubstring& aLocalName, + const PRInt32 aNsID); private: - nsresult createHandlerAndFlush(txOutputMethod aMethod, - const nsAString& aName, + nsresult createHandlerAndFlush(PRBool aHTMLRoot, + const nsSubstring& aName, const PRInt32 aNsID); /* diff --git a/content/xslt/src/xslt/txXMLEventHandler.h b/content/xslt/src/xslt/txXMLEventHandler.h index 8916c70a785e..ba41a41f35ff 100644 --- a/content/xslt/src/xslt/txXMLEventHandler.h +++ b/content/xslt/src/xslt/txXMLEventHandler.h @@ -40,6 +40,7 @@ #define TRANSFRMX_XML_EVENT_HANDLER_H #include "txCore.h" +#include "nsIAtom.h" class txOutputFormat; @@ -65,13 +66,28 @@ public: /** * Signals to receive the start of an attribute. * - * @param aName the name of the attribute + * @param aPrefix the prefix of the attribute + * @param aLocalName the localname of the attribute + * @param aLowercaseName the localname of the attribute in lower case * @param aNsID the namespace ID of the attribute * @param aValue the value of the attribute */ - virtual nsresult attribute(const nsAString& aName, + virtual nsresult attribute(nsIAtom* aPrefix, nsIAtom* aLocalName, + nsIAtom* aLowercaseLocalName, PRInt32 aNsID, + const nsString& aValue) = 0; + + /** + * Signals to receive the start of an attribute. + * + * @param aPrefix the prefix of the attribute + * @param aLocalName the localname of the attribute + * @param aNsID the namespace ID of the attribute + * @param aValue the value of the attribute + */ + virtual nsresult attribute(nsIAtom* aPrefix, + const nsSubstring& aLocalName, const PRInt32 aNsID, - const nsAString& aValue) = 0; + const nsString& aValue) = 0; /** * Signals to receive characters. @@ -79,14 +95,14 @@ public: * @param aData the characters to receive * @param aDOE disable output escaping for these characters */ - virtual nsresult characters(const nsAString& aData, PRBool aDOE) = 0; + virtual nsresult characters(const nsSubstring& aData, PRBool aDOE) = 0; /** * Signals to receive data that should be treated as a comment. * * @param data the comment data to receive */ - virtual nsresult comment(const nsAString& aData) = 0; + virtual nsresult comment(const nsString& aData) = 0; /** * Signals the end of a document. It is an error to call @@ -96,12 +112,8 @@ public: /** * Signals to receive the end of an element. - * - * @param aName the name of the element - * @param aNsID the namespace ID of the element */ - virtual nsresult endElement(const nsAString& aName, - const PRInt32 aNsID) = 0; + virtual nsresult endElement() = 0; /** * Signals to receive a processing instruction. @@ -109,8 +121,8 @@ public: * @param aTarget the target of the processing instruction * @param aData the data of the processing instruction */ - virtual nsresult processingInstruction(const nsAString& aTarget, - const nsAString& aData) = 0; + virtual nsresult processingInstruction(const nsString& aTarget, + const nsString& aData) = 0; /** * Signals the start of a document. @@ -120,24 +132,50 @@ public: /** * Signals to receive the start of an element. * - * @param aName the name of the element + * @param aPrefix the prefix of the element + * @param aLocalName the localname of the element + * @param aLowercaseName the localname of the element in lower case * @param aNsID the namespace ID of the element */ - virtual nsresult startElement(const nsAString& aName, + virtual nsresult startElement(nsIAtom* aPrefix, + nsIAtom* aLocalName, + nsIAtom* aLowercaseLocalName, + PRInt32 aNsID) = 0; + + /** + * Signals to receive the start of an element. Can throw + * NS_ERROR_XSLT_BAD_NODE_NAME if the name is invalid + * + * @param aPrefix the prefix of the element + * @param aLocalName the localname of the element + * @param aNsID the namespace ID of the element + */ + virtual nsresult startElement(nsIAtom* aPrefix, + const nsSubstring& aLocalName, const PRInt32 aNsID) = 0; }; #define TX_DECL_TXAXMLEVENTHANDLER \ - virtual nsresult attribute(const nsAString& aName, const PRInt32 aNsID, \ - const nsAString& aValue); \ - virtual nsresult characters(const nsAString& aData, PRBool aDOE); \ - virtual nsresult comment(const nsAString& aData); \ + virtual nsresult attribute(nsIAtom* aPrefix, nsIAtom* aLocalName, \ + nsIAtom* aLowercaseLocalName, PRInt32 aNsID, \ + const nsString& aValue); \ + virtual nsresult attribute(nsIAtom* aPrefix, \ + const nsSubstring& aLocalName, \ + const PRInt32 aNsID, \ + const nsString& aValue); \ + virtual nsresult characters(const nsSubstring& aData, PRBool aDOE); \ + virtual nsresult comment(const nsString& aData); \ virtual nsresult endDocument(nsresult aResult = NS_OK); \ - virtual nsresult endElement(const nsAString& aName, const PRInt32 aNsID);\ - virtual nsresult processingInstruction(const nsAString& aTarget, \ - const nsAString& aData); \ + virtual nsresult endElement(); \ + virtual nsresult processingInstruction(const nsString& aTarget, \ + const nsString& aData); \ virtual nsresult startDocument(); \ - virtual nsresult startElement(const nsAString& aName, \ + virtual nsresult startElement(nsIAtom* aPrefix, \ + nsIAtom* aLocalName, \ + nsIAtom* aLowercaseLocalName, \ + PRInt32 aNsID); \ + virtual nsresult startElement(nsIAtom* aPrefix, \ + const nsSubstring& aName, \ const PRInt32 aNsID); @@ -187,7 +225,7 @@ public: */ virtual nsresult createHandlerWith(txOutputFormat* aFormat, - const nsAString& aName, + const nsSubstring& aName, PRInt32 aNsID, txAXMLEventHandler** aHandler) = 0; }; @@ -196,7 +234,7 @@ public: nsresult createHandlerWith(txOutputFormat* aFormat, \ txAXMLEventHandler** aHandler); \ nsresult createHandlerWith(txOutputFormat* aFormat, \ - const nsAString& aName, \ + const nsSubstring& aName, \ PRInt32 aNsID, \ txAXMLEventHandler** aHandler);