From e2c56f978523f473a18e6d61c8e16ae711e77a11 Mon Sep 17 00:00:00 2001 From: "bzbarsky%mit.edu" Date: Thu, 30 Sep 2004 22:27:45 +0000 Subject: [PATCH] Make createContextualFragment work for XML. Bug 133827, patch by steve.swanson@mackichan.com, r=bzbarsky, sr=jst --- content/base/public/nsContentCID.h | 8 + content/base/src/nsRange.cpp | 76 +++- content/html/content/src/nsHTMLAtomList.h | 1 + .../src/nsHTMLFragmentContentSink.cpp | 73 ++-- content/shared/public/nsHTMLAtomList.h | 1 + content/xml/document/src/Makefile.in | 1 + content/xml/document/src/nsXMLContentSink.cpp | 90 +++-- content/xml/document/src/nsXMLContentSink.h | 11 + .../document/src/nsXMLFragmentContentSink.cpp | 344 ++++++++++++++++++ editor/libeditor/html/nsHTMLDataTransfer.cpp | 7 +- layout/build/nsLayoutModule.cpp | 18 +- layout/generic/nsHTMLParts.h | 6 +- layout/html/base/src/nsHTMLParts.h | 6 +- parser/htmlparser/public/Makefile.in | 2 +- .../public/nsIFragmentContentSink.h | 88 +++++ parser/htmlparser/public/nsIParser.h | 2 +- parser/htmlparser/src/nsParser.cpp | 32 +- parser/htmlparser/src/nsParser.h | 5 +- 18 files changed, 662 insertions(+), 109 deletions(-) create mode 100644 content/xml/document/src/nsXMLFragmentContentSink.cpp create mode 100644 parser/htmlparser/public/nsIFragmentContentSink.h diff --git a/content/base/public/nsContentCID.h b/content/base/public/nsContentCID.h index 11bdfbb5b8a7..f36712277222 100644 --- a/content/base/public/nsContentCID.h +++ b/content/base/public/nsContentCID.h @@ -217,6 +217,14 @@ #define NS_HTMLFRAGMENTSINK2_CID \ { 0x13111d00, 0xce81, 0x11d6, { 0x80, 0x82, 0xec, 0xf3, 0x66, 0x5a, 0xf6, 0x7c } } +// {4B664E54-72A2-4bbf-A5C2-66D4DC3066A0} +#define NS_XMLFRAGMENTSINK_CID \ +{ 0x4b664e54, 0x72a2, 0x4bbf, { 0xa5, 0xc2, 0x66, 0xd4, 0xdc, 0x30, 0x66, 0xa0 } } + +// {4DC30689-929D-425e-A709-082C6294E542} +#define NS_XMLFRAGMENTSINK2_CID \ +{ 0x4dc30689, 0x929d, 0x425e, { 0xa7, 0x9, 0x8, 0x2c, 0x62, 0x94, 0xe5, 0x42 } } + // {3986B301-097C-11d3-BF87-00105A1B0627} #define NS_XULPOPUPLISTENER_CID \ { 0x3986b301, 0x97c, 0x11d3, { 0xbf, 0x87, 0x0, 0x10, 0x5a, 0x1b, 0x6, 0x27 } } diff --git a/content/base/src/nsRange.cpp b/content/base/src/nsRange.cpp index 4c0497e5966c..200affcffec9 100644 --- a/content/base/src/nsRange.cpp +++ b/content/base/src/nsRange.cpp @@ -58,7 +58,8 @@ #include "nsIParser.h" #include "nsIComponentManager.h" #include "nsParserCIID.h" -#include "nsIHTMLFragmentContentSink.h" +#include "nsIFragmentContentSink.h" +#include "nsIContentSink.h" #include "nsIEnumerator.h" #include "nsIScriptSecurityManager.h" #include "nsIScriptGlobalObject.h" @@ -2366,8 +2367,40 @@ nsRange::CreateContextualFragment(const nsAString& aFragment, parent->GetNodeType(&nodeType); if (nsIDOMNode::ELEMENT_NODE == nodeType) { - nsAutoString tagName; + PRInt32 namespaceID; + nsAutoString tagName, uriStr; parent->GetNodeName(tagName); + + // see if we need to add xmlns declarations + nsCOMPtr content( do_QueryInterface(parent) ); + PRUint32 count = content->GetAttrCount(); + if (count > 0) { + PRUint32 index; + nsAutoString nameStr, prefixStr, valueStr; + nsCOMPtr attrName, attrPrefix; + + for (index = 0; index < count; index++) { + + content->GetAttrNameAt(index, + &namespaceID, + getter_AddRefs(attrName), + getter_AddRefs(attrPrefix)); + + if (namespaceID == kNameSpaceID_XMLNS) { + content->GetAttr(namespaceID, attrName, uriStr); + + // really want something like nsXMLContentSerializer::SerializeAttr() + tagName.Append(NS_LITERAL_STRING(" xmlns")); // space important + if (attrPrefix) { + tagName.Append(PRUnichar(':')); + attrName->ToString(nameStr); + tagName.Append(nameStr); + } + tagName.Append(NS_LITERAL_STRING("=\"") + uriStr + NS_LITERAL_STRING("\"")); + } + } + } + // XXX Wish we didn't have to allocate here PRUnichar* name = ToNewUnicode(tagName); if (name) { @@ -2387,22 +2420,29 @@ nsRange::CreateContextualFragment(const nsAString& aFragment, if (NS_SUCCEEDED(result)) { nsCAutoString contentType; - nsCOMPtr sink; + PRBool bCaseSensitive = PR_TRUE; + if (document) { + nsAutoString buf; + document->GetContentType(buf); + CopyUCS2toASCII(buf, contentType); + bCaseSensitive = document->IsCaseSensitive(); + } + else { + contentType.AssignLiteral("text/xml"); + } - result = NS_NewHTMLFragmentContentSink(getter_AddRefs(sink)); + nsCOMPtr htmlDoc(do_QueryInterface(domDocument)); + PRBool bHTML = htmlDoc && !bCaseSensitive; + nsCOMPtr sink; + if (bHTML) { + result = NS_NewHTMLFragmentContentSink(getter_AddRefs(sink)); + } else { + result = NS_NewXMLFragmentContentSink(getter_AddRefs(sink)); + } if (NS_SUCCEEDED(result)) { sink->SetTargetDocument(document); - parser->SetContentSink(sink); - nsCOMPtr domnsDocument(do_QueryInterface(document)); - if (domnsDocument) { - nsAutoString buf; - domnsDocument->GetContentType(buf); - CopyUCS2toASCII(buf, contentType); - } - else { - // Who're we kidding. This only works for html. - contentType.AssignLiteral("text/html"); - } + nsCOMPtr contentsink( do_QueryInterface(sink) ); + parser->SetContentSink(contentsink); // If there's no JS or system JS running, // push the current document's context on the JS context stack @@ -2445,7 +2485,7 @@ nsRange::CreateContextualFragment(const nsAString& aFragment, nsDTDMode mode = eDTDMode_autodetect; nsCOMPtr htmlDoc(do_QueryInterface(domDocument)); - if (htmlDoc) { + if (bHTML) { switch (htmlDoc->GetCompatibilityMode()) { case eCompatibility_NavQuirks: mode = eDTDMode_quirks; @@ -2460,10 +2500,12 @@ nsRange::CreateContextualFragment(const nsAString& aFragment, NS_NOTREACHED("unknown mode"); break; } + } else { + mode = eDTDMode_full_standards; } result = parser->ParseFragment(aFragment, (void*)0, tagStack, - 0, contentType, mode); + !bHTML, contentType, mode); if (ContextStack) { JSContext *notused; diff --git a/content/html/content/src/nsHTMLAtomList.h b/content/html/content/src/nsHTMLAtomList.h index 718b40af3f30..7de45fe25d50 100644 --- a/content/html/content/src/nsHTMLAtomList.h +++ b/content/html/content/src/nsHTMLAtomList.h @@ -134,6 +134,7 @@ HTML_ATOM(em, "em") HTML_ATOM(embed, "embed") HTML_ATOM(encoding, "encoding") HTML_ATOM(enctype, "enctype") +HTML_ATOM(endnote, "endnote") // contextual fragments HTML_ATOM(_event, "event") HTML_ATOM(face, "face") HTML_ATOM(fieldset, "fieldset") diff --git a/content/html/document/src/nsHTMLFragmentContentSink.cpp b/content/html/document/src/nsHTMLFragmentContentSink.cpp index ba51e8b54dde..c5a9a343b202 100644 --- a/content/html/document/src/nsHTMLFragmentContentSink.cpp +++ b/content/html/document/src/nsHTMLFragmentContentSink.cpp @@ -36,7 +36,8 @@ * ***** END LICENSE BLOCK ***** */ #include "nsCOMPtr.h" #include "nsIServiceManager.h" -#include "nsIHTMLFragmentContentSink.h" +#include "nsIFragmentContentSink.h" +#include "nsIHTMLContentSink.h" #include "nsIParser.h" #include "nsIParserService.h" #include "nsIHTMLContent.h" @@ -68,9 +69,10 @@ // at some pointe really soon! // -class nsHTMLFragmentContentSink : public nsIHTMLFragmentContentSink { +class nsHTMLFragmentContentSink : public nsIFragmentContentSink, + public nsIHTMLContentSink { public: - nsHTMLFragmentContentSink(); + nsHTMLFragmentContentSink(PRBool aAllContent = PR_FALSE); virtual ~nsHTMLFragmentContentSink(); // nsISupports @@ -119,7 +121,7 @@ public: NS_IMETHOD AddProcessingInstruction(const nsIParserNode& aNode); NS_IMETHOD AddDocTypeDecl(const nsIParserNode& aNode); - // nsIHTMLFragmentContentSink + // nsIFragmentContentSink NS_IMETHOD GetFragment(nsIDOMDocumentFragment** aFragment); NS_IMETHOD SetTargetDocument(nsIDocument* aDocument); @@ -160,43 +162,45 @@ public: nsRefPtr mNodeInfoManager; }; -class nsHTMLFragmentContentSink2 : public nsHTMLFragmentContentSink -{ -public: - nsHTMLFragmentContentSink2() { mHitSentinel = PR_TRUE; mSeenBody = PR_FALSE;} - virtual ~nsHTMLFragmentContentSink2() {} -}; - -nsresult -NS_NewHTMLFragmentContentSink2(nsIHTMLFragmentContentSink** aResult) +static nsresult +NewHTMLFragmentContentSinkHelper(PRBool aAllContent, nsIFragmentContentSink** aResult) { NS_PRECONDITION(aResult, "Null out ptr"); + if (nsnull == aResult) { + return NS_ERROR_NULL_POINTER; + } - *aResult = new nsHTMLFragmentContentSink2(); - NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); - - NS_ADDREF(*aResult); - + nsHTMLFragmentContentSink* it = new nsHTMLFragmentContentSink(aAllContent); + if (nsnull == it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(*aResult = it); + return NS_OK; } nsresult -NS_NewHTMLFragmentContentSink(nsIHTMLFragmentContentSink** aResult) +NS_NewHTMLFragmentContentSink2(nsIFragmentContentSink** aResult) { - NS_PRECONDITION(aResult, "Null out ptr"); - - *aResult = new nsHTMLFragmentContentSink(); - NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); - - NS_ADDREF(*aResult); - - return NS_OK; + return NewHTMLFragmentContentSinkHelper(PR_TRUE,aResult); } -nsHTMLFragmentContentSink::nsHTMLFragmentContentSink() +nsresult +NS_NewHTMLFragmentContentSink(nsIFragmentContentSink** aResult) { - mHitSentinel = PR_FALSE; - mSeenBody = PR_TRUE; + return NewHTMLFragmentContentSinkHelper(PR_FALSE,aResult); +} + +nsHTMLFragmentContentSink::nsHTMLFragmentContentSink(PRBool aAllContent) +{ + if (aAllContent) { + mHitSentinel = PR_TRUE; + mSeenBody = PR_FALSE; + } else { + mHitSentinel = PR_FALSE; + mSeenBody = PR_TRUE; + } mRoot = nsnull; mParser = nsnull; mCurrentForm = nsnull; @@ -233,10 +237,10 @@ NS_IMPL_ADDREF(nsHTMLFragmentContentSink) NS_IMPL_RELEASE(nsHTMLFragmentContentSink) NS_INTERFACE_MAP_BEGIN(nsHTMLFragmentContentSink) - NS_INTERFACE_MAP_ENTRY(nsIHTMLFragmentContentSink) + NS_INTERFACE_MAP_ENTRY(nsIFragmentContentSink) NS_INTERFACE_MAP_ENTRY(nsIHTMLContentSink) NS_INTERFACE_MAP_ENTRY(nsIContentSink) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIHTMLFragmentContentSink) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFragmentContentSink) NS_INTERFACE_MAP_END @@ -441,8 +445,6 @@ nsHTMLFragmentContentSink::AddBaseTagInfo(nsIContent* aContent) } } -static const char kSentinelStr[] = "endnote"; - NS_IMETHODIMP nsHTMLFragmentContentSink::OpenContainer(const nsIParserNode& aNode) { @@ -452,7 +454,8 @@ nsHTMLFragmentContentSink::OpenContainer(const nsIParserNode& aNode) nsresult result = NS_OK; tag.Assign(aNode.GetText()); - if (tag.EqualsIgnoreCase(kSentinelStr)) { + + if (nsHTMLAtoms::endnote->Equals(tag)) { mHitSentinel = PR_TRUE; } else if (mHitSentinel) { diff --git a/content/shared/public/nsHTMLAtomList.h b/content/shared/public/nsHTMLAtomList.h index 718b40af3f30..7de45fe25d50 100644 --- a/content/shared/public/nsHTMLAtomList.h +++ b/content/shared/public/nsHTMLAtomList.h @@ -134,6 +134,7 @@ HTML_ATOM(em, "em") HTML_ATOM(embed, "embed") HTML_ATOM(encoding, "encoding") HTML_ATOM(enctype, "enctype") +HTML_ATOM(endnote, "endnote") // contextual fragments HTML_ATOM(_event, "event") HTML_ATOM(face, "face") HTML_ATOM(fieldset, "fieldset") diff --git a/content/xml/document/src/Makefile.in b/content/xml/document/src/Makefile.in index fe6e774baf14..36f2d171707a 100644 --- a/content/xml/document/src/Makefile.in +++ b/content/xml/document/src/Makefile.in @@ -72,6 +72,7 @@ REQUIRES = xpcom \ CPPSRCS = \ nsXMLContentSink.cpp \ + nsXMLFragmentContentSink.cpp \ nsXMLDocument.cpp \ nsXMLPrettyPrinter.cpp \ $(NULL) diff --git a/content/xml/document/src/nsXMLContentSink.cpp b/content/xml/document/src/nsXMLContentSink.cpp index 2de11d54a659..3ed86e41b129 100644 --- a/content/xml/document/src/nsXMLContentSink.cpp +++ b/content/xml/document/src/nsXMLContentSink.cpp @@ -911,6 +911,43 @@ NS_NewMathMLElement(nsIContent** aResult, nsINodeInfo* aNodeInfo) //////////////////////////////////////////////////////////////////////// +PRBool +nsXMLContentSink::SetDocElement(PRInt32 aNameSpaceID, + nsIAtom* aTagName, + nsIContent *aContent) +{ + if (mDocElement) + return PR_FALSE; + + // check for root elements that needs special handling for + // prettyprinting + if ((aNameSpaceID == kNameSpaceID_XBL && + aTagName == nsXBLAtoms::bindings) || + (aNameSpaceID == kNameSpaceID_XSLT && + (aTagName == nsLayoutAtoms::stylesheet || + aTagName == nsLayoutAtoms::transform))) { + mPrettyPrintHasSpecialRoot = PR_TRUE; + if (mPrettyPrintXML) { + // In this case, disable script execution, stylesheet + // loading, and auto XLinks since we plan to prettyprint. + mAllowAutoXLinks = PR_FALSE; + nsIScriptLoader* scriptLoader = mDocument->GetScriptLoader(); + if (scriptLoader) { + scriptLoader->SetEnabled(PR_FALSE); + } + if (mCSSLoader) { + mCSSLoader->SetEnabled(PR_FALSE); + } + } + } + + mDocElement = aContent; + NS_ADDREF(mDocElement); + + mDocument->SetRootContent(mDocElement); + return PR_TRUE; +} + NS_IMETHODIMP nsXMLContentSink::HandleStartElement(const PRUnichar *aName, const PRUnichar **aAtts, @@ -967,44 +1004,17 @@ nsXMLContentSink::HandleStartElement(const PRUnichar *aName, getter_AddRefs(content), &appendContent); NS_ENSURE_SUCCESS(result, result); - content->SetContentID(mDocument->GetAndIncrementContentID()); + if (mDocument) { + content->SetContentID(mDocument->GetAndIncrementContentID()); + } content->SetDocument(mDocument, PR_FALSE, PR_TRUE); // Set the attributes on the new content element result = AddAttributes(aAtts, content); if (NS_OK == result) { - // If this is the document element - if (!mDocElement) { - - // check for root elements that needs special handling for - // prettyprinting - if ((nameSpaceID == kNameSpaceID_XBL && - tagAtom == nsXBLAtoms::bindings) || - (nameSpaceID == kNameSpaceID_XSLT && - (tagAtom == nsLayoutAtoms::stylesheet || - tagAtom == nsLayoutAtoms::transform))) { - mPrettyPrintHasSpecialRoot = PR_TRUE; - if (mPrettyPrintXML) { - // In this case, disable script execution, stylesheet - // loading, and auto XLinks since we plan to prettyprint. - mAllowAutoXLinks = PR_FALSE; - nsIScriptLoader* scriptLoader = mDocument->GetScriptLoader(); - if (scriptLoader) { - scriptLoader->SetEnabled(PR_FALSE); - } - if (mCSSLoader) { - mCSSLoader->SetEnabled(PR_FALSE); - } - } - } - - mDocElement = content; - NS_ADDREF(mDocElement); - - mDocument->SetRootContent(mDocElement); - } - else if (appendContent) { + // Store the element + if (!SetDocElement(nameSpaceID,tagAtom,content) && appendContent) { nsCOMPtr parent = GetCurrentContent(); NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED); @@ -1265,6 +1275,15 @@ nsXMLContentSink::HandleXMLDeclaration(const PRUnichar *aData, NS_IMETHODIMP nsXMLContentSink::ReportError(const PRUnichar* aErrorText, const PRUnichar* aSourceText) +{ + nsCOMPtr node(do_QueryInterface(mDocument)); + return ReportErrorFrom( aErrorText, aSourceText, node ); +} + +NS_IMETHODIMP +nsXMLContentSink::ReportErrorFrom(const PRUnichar* aErrorText, + const PRUnichar* aSourceText, + nsIDOMNode* aNode) { nsresult rv = NS_OK; @@ -1278,14 +1297,13 @@ nsXMLContentSink::ReportError(const PRUnichar* aErrorText, // Clear the current content and // prepare to set as the document root - nsCOMPtr node(do_QueryInterface(mDocument)); - if (node) { + if (aNode) { for (;;) { nsCOMPtr child, dummy; - node->GetLastChild(getter_AddRefs(child)); + aNode->GetLastChild(getter_AddRefs(child)); if (!child) break; - node->RemoveChild(child, getter_AddRefs(dummy)); + aNode->RemoveChild(child, getter_AddRefs(dummy)); } } NS_IF_RELEASE(mDocElement); diff --git a/content/xml/document/src/nsXMLContentSink.h b/content/xml/document/src/nsXMLContentSink.h index 35fd67d17e62..bf54c6b696ca 100644 --- a/content/xml/document/src/nsXMLContentSink.h +++ b/content/xml/document/src/nsXMLContentSink.h @@ -107,6 +107,12 @@ protected: PRInt32 aNameSpaceID, nsIAtom* aTagName, PRUint32 aLineNumber) { return PR_TRUE; } + // Set the given content as the root element for the created document + // don't set if root element was already set. + // return TRUE if this call set the root element + virtual PRBool SetDocElement(PRInt32 aNameSpaceID, + nsIAtom *aTagName, + nsIContent *aContent); virtual nsresult CreateElement(const PRUnichar** aAtts, PRUint32 aAttsCount, nsINodeInfo* aNodeInfo, PRUint32 aLineNumber, nsIContent** aResult, PRBool* aAppendContent); @@ -125,6 +131,11 @@ protected: PRInt32 PushContent(nsIContent *aContent); already_AddRefed PopContent(); + // node is the base content which will be cleared out and an error fragment will be inserted + // return value indicates whether fragment was successfully created + NS_IMETHOD ReportErrorFrom(const PRUnichar* aErrorText, + const PRUnichar* aSourceText, + nsIDOMNode* aNode); nsresult ProcessBASETag(nsIContent* aContent); diff --git a/content/xml/document/src/nsXMLFragmentContentSink.cpp b/content/xml/document/src/nsXMLFragmentContentSink.cpp new file mode 100644 index 000000000000..11f724d4b5ac --- /dev/null +++ b/content/xml/document/src/nsXMLFragmentContentSink.cpp @@ -0,0 +1,344 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Steve Swanson steve.swanson@mackichan.com. + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "nsCOMPtr.h" +#include "nsXMLContentSink.h" +#include "nsIFragmentContentSink.h" +#include "nsIXMLContentSink.h" +#include "nsContentSink.h" +#include "nsIExpatSink.h" +#include "nsIParser.h" +#include "nsIDocument.h" +#include "nsIDOMDocumentFragment.h" +#include "nsIXMLContent.h" +#include "nsHTMLAtoms.h" +#include "nsINodeInfo.h" +#include "nsNodeInfoManager.h" +#include "nsContentCreatorFunctions.h" + + +class nsXMLFragmentContentSink : public nsXMLContentSink, + public nsIFragmentContentSink +{ +public: + nsXMLFragmentContentSink(PRBool aAllContent = PR_FALSE); + virtual ~nsXMLFragmentContentSink(); + + // nsISupports + NS_DECL_ISUPPORTS_INHERITED + + // nsIExpatSink + NS_IMETHOD HandleDoctypeDecl(const nsAString & aSubset, + const nsAString & aName, + const nsAString & aSystemId, + const nsAString & aPublicId, + nsISupports* aCatalogData); + NS_IMETHOD HandleProcessingInstruction(const PRUnichar *aTarget, + const PRUnichar *aData); + NS_IMETHOD HandleXMLDeclaration(const PRUnichar *aData, + PRUint32 aLength); + NS_IMETHOD ReportError(const PRUnichar* aErrorText, + const PRUnichar* aSourceText); + + // nsIContentSink + NS_IMETHOD WillBuildModel(void); + NS_IMETHOD DidBuildModel(); + NS_IMETHOD SetDocumentCharset(nsACString& aCharset); + + // nsIXMLContentSink + + // nsIFragmentContentSink + NS_IMETHOD GetFragment(nsIDOMDocumentFragment** aFragment); + NS_IMETHOD SetTargetDocument(nsIDocument* aDocument); + +protected: + virtual PRBool SetDocElement(PRInt32 aNameSpaceID, + nsIAtom *aTagName, + nsIContent *aContent); + virtual nsresult CreateElement(const PRUnichar** aAtts, PRUint32 aAttsCount, + nsINodeInfo* aNodeInfo, PRUint32 aLineNumber, + nsIContent** aResult, PRBool* aAppendContent); + virtual nsresult CloseElement(nsIContent* aContent, PRBool* aAppendContent); + + // nsContentSink overrides + virtual nsresult ProcessStyleLink(nsIContent* aElement, + const nsAString& aHref, + PRBool aAlternate, + const nsAString& aTitle, + const nsAString& aType, + const nsAString& aMedia); + nsresult LoadXSLStyleSheet(nsIURI* aUrl); + void StartLayout(); + + nsCOMPtr mTargetDocument; + // the fragment + nsCOMPtr mRoot; + + // if FALSE, take content inside endnote tag + PRBool mAllContent; + nsCOMPtr mEndnote; +}; + +static nsresult +NewXMLFragmentContentSinkHelper(PRBool aAllContent, nsIFragmentContentSink** aResult) +{ + nsXMLFragmentContentSink* it = new nsXMLFragmentContentSink(aAllContent); + if (!it) { + return NS_ERROR_OUT_OF_MEMORY; + } + + NS_ADDREF(*aResult = it); + + return NS_OK; +} + +nsresult +NS_NewXMLFragmentContentSink2(nsIFragmentContentSink** aResult) +{ + return NewXMLFragmentContentSinkHelper(PR_TRUE, aResult); +} + +nsresult +NS_NewXMLFragmentContentSink(nsIFragmentContentSink** aResult) +{ + return NewXMLFragmentContentSinkHelper(PR_FALSE, aResult); +} + +nsXMLFragmentContentSink::nsXMLFragmentContentSink(PRBool aAllContent) + : mAllContent(aAllContent) +{ +} + +nsXMLFragmentContentSink::~nsXMLFragmentContentSink() +{ +} + +NS_IMPL_ISUPPORTS_INHERITED1(nsXMLFragmentContentSink, + nsXMLContentSink, + nsIFragmentContentSink) + +NS_IMETHODIMP +nsXMLFragmentContentSink::WillBuildModel(void) +{ + if (mRoot) { + return NS_OK; + } + + mState = eXMLContentSinkState_InDocumentElement; + + NS_ASSERTION(mTargetDocument, "Need a document!"); + + nsCOMPtr frag; + nsresult rv = NS_NewDocumentFragment(getter_AddRefs(frag), mTargetDocument); + NS_ENSURE_SUCCESS(rv, rv); + + mRoot = do_QueryInterface(frag); + PushContent(mRoot); // preload content stack because we know all content goes in the fragment + return rv; +} + +NS_IMETHODIMP +nsXMLFragmentContentSink::DidBuildModel() +{ + PopContent(); // remove mRoot pushed above + + if (!mAllContent) { + NS_ASSERTION(mEndnote, " missing in fragment string."); + if (mEndnote) { + NS_ASSERTION(mRoot->GetChildCount() == 1, "contents have too many children!"); + // move guts + for (PRUint32 child = mEndnote->GetChildCount(); child > 0; child--) { + nsCOMPtr firstchild = mEndnote->GetChildAt(0); + mEndnote->RemoveChildAt( 0, PR_FALSE ); + mRoot->AppendChildTo( firstchild, PR_FALSE, PR_FALSE ); + } + // delete outer content + mRoot->RemoveChildAt( 0, PR_FALSE ); + } + // else just leave the content in the fragment. or should we fail? + } + + nsCOMPtr kungFuDeathGrip(mParser); + + // Drop our reference to the parser to get rid of a circular + // reference. + mParser = nsnull; + + return NS_OK; +} + +NS_IMETHODIMP +nsXMLFragmentContentSink::SetDocumentCharset(nsACString& aCharset) +{ + NS_NOTREACHED("fragments shouldn't set charset"); + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////// + +PRBool +nsXMLFragmentContentSink::SetDocElement(PRInt32 aNameSpaceID, + nsIAtom* aTagName, + nsIContent *aContent) +{ + // this is a fragment, not a document + return PR_FALSE; +} + +nsresult +nsXMLFragmentContentSink::CreateElement(const PRUnichar** aAtts, PRUint32 aAttsCount, + nsINodeInfo* aNodeInfo, PRUint32 aLineNumber, + nsIContent** aResult, PRBool* aAppendContent) +{ + nsresult rv = nsXMLContentSink::CreateElement(aAtts, aAttsCount, + aNodeInfo, aLineNumber, + aResult, aAppendContent); + *aAppendContent = PR_TRUE; // make sure scripts added immediately, not on close. + + if (NS_SUCCEEDED(rv) && aNodeInfo->Equals(nsHTMLAtoms::endnote)) + mEndnote = *aResult; + + return rv; +} + +nsresult +nsXMLFragmentContentSink::CloseElement(nsIContent* aContent, PRBool* aAppendContent) +{ + // don't do fancy stuff in nsXMLContentSink + *aAppendContent = PR_FALSE; + + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////// + +NS_IMETHODIMP +nsXMLFragmentContentSink::HandleDoctypeDecl(const nsAString & aSubset, + const nsAString & aName, + const nsAString & aSystemId, + const nsAString & aPublicId, + nsISupports* aCatalogData) +{ + NS_NOTREACHED("fragments shouldn't have doctype declarations"); + return NS_OK; +} + +NS_IMETHODIMP +nsXMLFragmentContentSink::HandleProcessingInstruction(const PRUnichar *aTarget, + const PRUnichar *aData) +{ + FlushText(); + + nsresult result = NS_OK; + const nsDependentString target(aTarget); + const nsDependentString data(aData); + + nsCOMPtr node; + + result = NS_NewXMLProcessingInstruction(getter_AddRefs(node), target, data); + if (NS_SUCCEEDED(result)) { + // no special processing here. that should happen when the fragment moves into the document + result = AddContentAsLeaf(node); + } + return result; +} + +NS_IMETHODIMP +nsXMLFragmentContentSink::HandleXMLDeclaration(const PRUnichar *aData, + PRUint32 aLength) +{ + NS_NOTREACHED("fragments shouldn't have XML declarations"); + return NS_OK; +} + +NS_IMETHODIMP +nsXMLFragmentContentSink::ReportError(const PRUnichar* aErrorText, + const PRUnichar* aSourceText) +{ + nsCOMPtr node(do_QueryInterface(mRoot)); + return ReportErrorFrom( aErrorText, aSourceText, node ); +} + +nsresult +nsXMLFragmentContentSink::ProcessStyleLink(nsIContent* aElement, + const nsAString& aHref, + PRBool aAlternate, + const nsAString& aTitle, + const nsAString& aType, + const nsAString& aMedia) +{ + // don't process until moved to document + return NS_OK; +} + +nsresult +nsXMLFragmentContentSink::LoadXSLStyleSheet(nsIURI* aUrl) +{ + NS_NOTREACHED("fragments shouldn't have XSL style sheets"); + return NS_ERROR_UNEXPECTED; +} + +void +nsXMLFragmentContentSink::StartLayout() +{ + NS_NOTREACHED("fragments shouldn't layout"); +} + +//////////////////////////////////////////////////////////////////////// + +NS_IMETHODIMP +nsXMLFragmentContentSink::GetFragment(nsIDOMDocumentFragment** aFragment) +{ + if (mRoot) { + return CallQueryInterface(mRoot, aFragment); + } + + *aFragment = nsnull; + + return NS_OK; +} + +NS_IMETHODIMP +nsXMLFragmentContentSink::SetTargetDocument(nsIDocument* aTargetDocument) +{ + NS_ENSURE_ARG_POINTER(aTargetDocument); + + mTargetDocument = aTargetDocument; + mNodeInfoManager = aTargetDocument->NodeInfoManager(); + + return NS_OK; +} + diff --git a/editor/libeditor/html/nsHTMLDataTransfer.cpp b/editor/libeditor/html/nsHTMLDataTransfer.cpp index a44ce9e12105..101691170815 100644 --- a/editor/libeditor/html/nsHTMLDataTransfer.cpp +++ b/editor/libeditor/html/nsHTMLDataTransfer.cpp @@ -93,7 +93,8 @@ #include "nsXPCOM.h" #include "nsISupportsPrimitives.h" #include "nsLinebreakConverter.h" -#include "nsIHTMLFragmentContentSink.h" +#include "nsIFragmentContentSink.h" +#include "nsIContentSink.h" // netwerk #include "nsIURI.h" @@ -2529,7 +2530,7 @@ nsresult nsHTMLEditor::ParseFragment(const nsAString & aFragStr, sink = do_CreateInstance(NS_HTMLFRAGMENTSINK_CONTRACTID); NS_ENSURE_TRUE(sink, NS_ERROR_FAILURE); - nsCOMPtr fragSink(do_QueryInterface(sink)); + nsCOMPtr fragSink(do_QueryInterface(sink)); NS_ENSURE_TRUE(fragSink, NS_ERROR_FAILURE); fragSink->SetTargetDocument(aTargetDocument); @@ -2539,7 +2540,7 @@ nsresult nsHTMLEditor::ParseFragment(const nsAString & aFragStr, if (bContext) parser->Parse(aFragStr, (void*)0, NS_LITERAL_CSTRING("text/html"), PR_FALSE, PR_TRUE, eDTDMode_fragment); else - parser->ParseFragment(aFragStr, 0, aTagStack, 0, NS_LITERAL_CSTRING("text/html"), eDTDMode_quirks); + parser->ParseFragment(aFragStr, 0, aTagStack, PR_FALSE, NS_LITERAL_CSTRING("text/html"), eDTDMode_quirks); // get the fragment node nsCOMPtr contextfrag; res = fragSink->GetFragment(getter_AddRefs(contextfrag)); diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp index 985687da877f..b0bbda0cbea5 100644 --- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -83,7 +83,7 @@ #include "nsIGenericFactory.h" #include "nsIHTMLCSSStyleSheet.h" #include "nsIHTMLContent.h" -#include "nsIHTMLFragmentContentSink.h" +#include "nsIFragmentContentSink.h" #include "nsHTMLStyleSheet.h" #include "nsIHTMLToTextSink.h" #include "nsILayoutDebugger.h" @@ -575,8 +575,10 @@ MAKE_CTOR(CreateHTMLCopyTextEncoder, nsIDocumentEncoder, NS_NewHTM MAKE_CTOR(CreateXMLContentSerializer, nsIContentSerializer, NS_NewXMLContentSerializer) MAKE_CTOR(CreateHTMLContentSerializer, nsIContentSerializer, NS_NewHTMLContentSerializer) MAKE_CTOR(CreatePlainTextSerializer, nsIContentSerializer, NS_NewPlainTextSerializer) -MAKE_CTOR(CreateHTMLFragmentSink, nsIHTMLFragmentContentSink, NS_NewHTMLFragmentContentSink) -MAKE_CTOR(CreateHTMLFragmentSink2, nsIHTMLFragmentContentSink, NS_NewHTMLFragmentContentSink2) +MAKE_CTOR(CreateHTMLFragmentSink, nsIFragmentContentSink, NS_NewHTMLFragmentContentSink) +MAKE_CTOR(CreateHTMLFragmentSink2, nsIFragmentContentSink, NS_NewHTMLFragmentContentSink2) +MAKE_CTOR(CreateXMLFragmentSink, nsIFragmentContentSink, NS_NewXMLFragmentContentSink) +MAKE_CTOR(CreateXMLFragmentSink2, nsIFragmentContentSink, NS_NewXMLFragmentContentSink2) MAKE_CTOR(CreateSanitizingHTMLSerializer, nsIContentSerializer, NS_NewSanitizingHTMLSerializer) MAKE_CTOR(CreateXBLService, nsIXBLService, NS_NewXBLService) MAKE_CTOR(CreateBindingManager, nsIBindingManager, NS_NewBindingManager) @@ -1144,6 +1146,16 @@ static const nsModuleComponentInfo gComponents[] = { MOZ_SANITIZINGHTMLSERIALIZER_CONTRACTID, CreateSanitizingHTMLSerializer }, + { "xml fragment sink", + NS_XMLFRAGMENTSINK_CID, + NS_XMLFRAGMENTSINK_CONTRACTID, + CreateXMLFragmentSink }, + + { "xml fragment sink 2", + NS_XMLFRAGMENTSINK2_CID, + NS_XMLFRAGMENTSINK2_CONTRACTID, + CreateXMLFragmentSink2 }, + { "XBL Service", NS_XBLSERVICE_CID, "@mozilla.org/xbl;1", diff --git a/layout/generic/nsHTMLParts.h b/layout/generic/nsHTMLParts.h index ad6beda6c0f4..1ad54fa6350e 100644 --- a/layout/generic/nsHTMLParts.h +++ b/layout/generic/nsHTMLParts.h @@ -49,7 +49,7 @@ class nsIDocument; class nsIFrame; class nsIHTMLContent; class nsIHTMLContentSink; -class nsIHTMLFragmentContentSink; +class nsIFragmentContentSink; class nsPresContext; class nsITextContent; class nsIURI; @@ -253,9 +253,9 @@ NS_NewHTMLContentSink(nsIHTMLContentSink** aInstancePtrResult, nsISupports* aContainer, // e.g. docshell nsIChannel* aChannel); nsresult -NS_NewHTMLFragmentContentSink(nsIHTMLFragmentContentSink** aInstancePtrResult); +NS_NewHTMLFragmentContentSink(nsIFragmentContentSink** aInstancePtrResult); nsresult -NS_NewHTMLFragmentContentSink2(nsIHTMLFragmentContentSink** aInstancePtrResult); +NS_NewHTMLFragmentContentSink2(nsIFragmentContentSink** aInstancePtrResult); /** Create a new HTML reflow command */ nsresult diff --git a/layout/html/base/src/nsHTMLParts.h b/layout/html/base/src/nsHTMLParts.h index ad6beda6c0f4..1ad54fa6350e 100644 --- a/layout/html/base/src/nsHTMLParts.h +++ b/layout/html/base/src/nsHTMLParts.h @@ -49,7 +49,7 @@ class nsIDocument; class nsIFrame; class nsIHTMLContent; class nsIHTMLContentSink; -class nsIHTMLFragmentContentSink; +class nsIFragmentContentSink; class nsPresContext; class nsITextContent; class nsIURI; @@ -253,9 +253,9 @@ NS_NewHTMLContentSink(nsIHTMLContentSink** aInstancePtrResult, nsISupports* aContainer, // e.g. docshell nsIChannel* aChannel); nsresult -NS_NewHTMLFragmentContentSink(nsIHTMLFragmentContentSink** aInstancePtrResult); +NS_NewHTMLFragmentContentSink(nsIFragmentContentSink** aInstancePtrResult); nsresult -NS_NewHTMLFragmentContentSink2(nsIHTMLFragmentContentSink** aInstancePtrResult); +NS_NewHTMLFragmentContentSink2(nsIFragmentContentSink** aInstancePtrResult); /** Create a new HTML reflow command */ nsresult diff --git a/parser/htmlparser/public/Makefile.in b/parser/htmlparser/public/Makefile.in index 33ab884f9ba9..0b092308d210 100644 --- a/parser/htmlparser/public/Makefile.in +++ b/parser/htmlparser/public/Makefile.in @@ -53,7 +53,7 @@ EXPORTS = \ nsIContentSink.h \ nsITokenizer.h \ nsIHTMLContentSink.h \ - nsIHTMLFragmentContentSink.h\ + nsIFragmentContentSink.h \ nsIParserNode.h \ nsIParser.h \ nsIDTD.h \ diff --git a/parser/htmlparser/public/nsIFragmentContentSink.h b/parser/htmlparser/public/nsIFragmentContentSink.h new file mode 100644 index 000000000000..58fbdf2a906c --- /dev/null +++ b/parser/htmlparser/public/nsIFragmentContentSink.h @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#ifndef nsIFragmentContentSink_h___ +#define nsIFragmentContentSink_h___ + +#include "nsISupports.h" + +class nsIDOMDocumentFragment; +class nsIDocument; + +#define NS_I_FRAGMENT_CONTENT_SINK_IID \ + { 0x2b23c1fb, 0xb83c, 0x436b, \ + { 0xb7, 0x2a, 0x9c, 0xbe, 0xf1, 0xe9, 0x9b, 0x20 } }; + +class nsIFragmentContentSink : public nsISupports { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_I_FRAGMENT_CONTENT_SINK_IID) + /** + * This method is used to obtain the fragment created by + * a fragment content sink. The value returned will be null + * if the content sink hasn't yet received parser notifications. + * + */ + NS_IMETHOD GetFragment(nsIDOMDocumentFragment** aFragment) = 0; + + /** + * This method is used to set the target document for this fragment + * sink. This document's nodeinfo manager will be used to create + * the content objects. This MUST be called before the sink is used. + * + * @param aDocument the document the new nodes will belong to + * (should not be null) + */ + NS_IMETHOD SetTargetDocument(nsIDocument* aDocument) = 0; +}; + +/** + * Base version takes string nested in context, context ends with . + * 2 version just loads whole string. + */ + +#define NS_HTMLFRAGMENTSINK_CONTRACTID "@mozilla.org/layout/htmlfragmentsink;1" +#define NS_HTMLFRAGMENTSINK2_CONTRACTID "@mozilla.org/layout/htmlfragmentsink;2" + +#define NS_XMLFRAGMENTSINK_CONTRACTID "@mozilla.org/layout/xmlfragmentsink;1" +#define NS_XMLFRAGMENTSINK2_CONTRACTID "@mozilla.org/layout/xmlfragmentsink;2" + +// the HTML versions are in nsHTMLParts.h +nsresult +NS_NewXMLFragmentContentSink(nsIFragmentContentSink** aInstancePtrResult); +nsresult +NS_NewXMLFragmentContentSink2(nsIFragmentContentSink** aInstancePtrResult); + +#endif diff --git a/parser/htmlparser/public/nsIParser.h b/parser/htmlparser/public/nsIParser.h index 5bab740944c2..9355c134ce9f 100644 --- a/parser/htmlparser/public/nsIParser.h +++ b/parser/htmlparser/public/nsIParser.h @@ -251,7 +251,7 @@ class nsIParser : public nsISupports { NS_IMETHOD ParseFragment(const nsAString& aSourceBuffer, void* aKey, nsVoidArray& aTagStack, - PRUint32 anInsertPos, + PRBool aXMLMode, const nsACString& aContentType, nsDTDMode aMode = eDTDMode_autodetect) = 0; diff --git a/parser/htmlparser/src/nsParser.cpp b/parser/htmlparser/src/nsParser.cpp index 3c37c4731a7c..b698402fbb94 100644 --- a/parser/htmlparser/src/nsParser.cpp +++ b/parser/htmlparser/src/nsParser.cpp @@ -1672,27 +1672,47 @@ NS_IMETHODIMP nsParser::ParseFragment(const nsAString& aSourceBuffer, void* aKey, nsVoidArray& aTagStack, - PRUint32 anInsertPos, + PRBool aXMLMode, const nsACString& aMimeType, nsDTDMode aMode) { nsresult result = NS_OK; - nsAutoString theContext; + nsAutoString theContext, endContext; PRUint32 theCount = aTagStack.Count(); PRUint32 theIndex = 0; - while (theIndex++ < theCount){ + for (theIndex = 0; theIndex < theCount; theIndex++) { theContext.AppendLiteral("<"); - theContext.Append((PRUnichar*)aTagStack.ElementAt(theCount - theIndex)); + theContext.Append((PRUnichar*)aTagStack.ElementAt(theCount - theIndex - 1)); theContext.AppendLiteral(">"); } - theContext.AppendLiteral(""); //XXXHack! I'll make this better later. + // Note duplication: nsHTMLAtoms::endnote == an atom in nsHTMLTags + theContext.AppendLiteral("<"); + theContext.Append(nsHTMLTags::GetStringValue(eHTMLTag_endnote)); + theContext.AppendLiteral(">"); + + if (aXMLMode) { + endContext.AppendLiteral(""); + + for (theIndex = 0; theIndex < theCount; theIndex++) { + endContext.AppendLiteral(""); + } + } //now it's time to try to build the model from this fragment mFlags &= ~NS_PARSER_FLAG_OBSERVERS_ENABLED; //disable observers for fragments - result = Parse(theContext + aSourceBuffer,(void*)&theContext,aMimeType,PR_FALSE,PR_TRUE, aMode); + result = Parse(theContext + aSourceBuffer + endContext,(void*)&theContext,aMimeType,PR_FALSE,PR_TRUE, aMode); mFlags |= NS_PARSER_FLAG_OBSERVERS_ENABLED; //now reenable. return result; diff --git a/parser/htmlparser/src/nsParser.h b/parser/htmlparser/src/nsParser.h index 30ee261784ef..0d50ed758604 100644 --- a/parser/htmlparser/src/nsParser.h +++ b/parser/htmlparser/src/nsParser.h @@ -218,10 +218,13 @@ class nsParser : public nsIParser, PRBool aLastCall, nsDTDMode aMode = eDTDMode_autodetect); + /** + * This method needs documentation + */ NS_IMETHOD ParseFragment(const nsAString& aSourceBuffer, void* aKey, nsVoidArray& aTagStack, - PRUint32 anInsertPos, + PRBool aXMLMode, const nsACString& aContentType, nsDTDMode aMode = eDTDMode_autodetect);