diff --git a/content/html/document/src/nsHTMLFragmentContentSink.cpp b/content/html/document/src/nsHTMLFragmentContentSink.cpp index 61c5669d6a5e..aa9e59ff3493 100644 --- a/content/html/document/src/nsHTMLFragmentContentSink.cpp +++ b/content/html/document/src/nsHTMLFragmentContentSink.cpp @@ -1,4 +1,5 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=2 et tw=80: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -125,6 +126,7 @@ public: NS_IMETHOD SetTargetDocument(nsIDocument* aDocument); NS_IMETHOD WillBuildContent(); NS_IMETHOD DidBuildContent(); + NS_IMETHOD IgnoreFirstContainer(); nsIContent* GetCurrentContent(); PRInt32 PushContent(nsIContent *aContent); @@ -146,6 +148,7 @@ public: PRPackedBool mAllContent; PRPackedBool mProcessing; PRPackedBool mSeenBody; + PRPackedBool mIgnoreContainer; nsCOMPtr mRoot; nsCOMPtr mParser; @@ -197,6 +200,7 @@ nsHTMLFragmentContentSink::nsHTMLFragmentContentSink(PRBool aAllContent) : mAllContent(aAllContent), mProcessing(aAllContent), mSeenBody(!aAllContent), + mIgnoreContainer(PR_FALSE), mContentStack(nsnull), mText(nsnull), mTextLength(0), @@ -443,7 +447,7 @@ nsHTMLFragmentContentSink::OpenContainer(const nsIParserNode& aNode) nsresult result = NS_OK; - if (mProcessing) { + if (mProcessing && !mIgnoreContainer) { FlushText(); nsHTMLTag nodeType = nsHTMLTag(aNode.GetNodeType()); @@ -497,6 +501,9 @@ nsHTMLFragmentContentSink::OpenContainer(const nsIParserNode& aNode) // XXX if navigator_quirks_mode (only body in html supports background) AddBaseTagInfo(content); } + else if (mProcessing && mIgnoreContainer) { + mIgnoreContainer = PR_FALSE; + } return result; } @@ -723,6 +730,13 @@ nsHTMLFragmentContentSink::DidBuildContent() return NS_OK; } +NS_IMETHODIMP +nsHTMLFragmentContentSink::IgnoreFirstContainer() +{ + mIgnoreContainer = PR_TRUE; + return NS_OK; +} + nsIContent* nsHTMLFragmentContentSink::GetCurrentContent() { diff --git a/content/xml/document/src/nsXMLFragmentContentSink.cpp b/content/xml/document/src/nsXMLFragmentContentSink.cpp index cb7727a551ae..940824129f36 100644 --- a/content/xml/document/src/nsXMLFragmentContentSink.cpp +++ b/content/xml/document/src/nsXMLFragmentContentSink.cpp @@ -90,6 +90,7 @@ public: NS_IMETHOD SetTargetDocument(nsIDocument* aDocument); NS_IMETHOD WillBuildContent(); NS_IMETHOD DidBuildContent(); + NS_IMETHOD IgnoreFirstContainer(); protected: virtual PRBool SetDocElement(PRInt32 aNameSpaceID, @@ -423,3 +424,11 @@ nsXMLFragmentContentSink::DidBuildContent() return NS_OK; } + +NS_IMETHODIMP +nsXMLFragmentContentSink::IgnoreFirstContainer() +{ + NS_NOTREACHED("XML isn't as broken as HTML"); + return NS_ERROR_FAILURE; +} + diff --git a/parser/htmlparser/public/nsIFragmentContentSink.h b/parser/htmlparser/public/nsIFragmentContentSink.h index 91f4e35fc9bf..8b959900fb0a 100644 --- a/parser/htmlparser/public/nsIFragmentContentSink.h +++ b/parser/htmlparser/public/nsIFragmentContentSink.h @@ -43,8 +43,8 @@ class nsIDOMDocumentFragment; class nsIDocument; #define NS_I_FRAGMENT_CONTENT_SINK_IID \ - { 0xe9ea6afb, 0x92f3, 0x4270, \ - { 0xb2, 0x67, 0xd2, 0xe3, 0x8d, 0x0e, 0x95, 0x45 } } + { 0x2cec7263, 0x9dd0, 0x4413, \ + { 0xb6, 0x68, 0x6f, 0xf0, 0xa1, 0x40, 0xc1, 0xbe } } /** * The fragment sink allows a client to parse a fragment of sink, possibly @@ -85,6 +85,14 @@ public: * (such as an end context). */ NS_IMETHOD DidBuildContent() = 0; + + /** + * This method is a total hack to help with parsing fragments. It is called to + * tell the fragment sink that a container from the context will be delivered + * after the call to WillBuildContent(). This is only relevent for HTML + * fragments that use nsHTMLTokenizer/CNavDTD. + */ + NS_IMETHOD IgnoreFirstContainer() = 0; }; /** diff --git a/parser/htmlparser/src/nsParser.cpp b/parser/htmlparser/src/nsParser.cpp index 4c5fcda3c352..99a835409368 100644 --- a/parser/htmlparser/src/nsParser.cpp +++ b/parser/htmlparser/src/nsParser.cpp @@ -1839,15 +1839,6 @@ nsParser::ParseFragment(const nsAString& aSourceBuffer, theContext.AppendLiteral(">"); } - if (!aXMLMode) { - // Make sure we flush the context out if there wasn't a body tag. This is - // safe, since the fragment sink doesn't make a distinction between the - // head and body context. This is needed because if there wasn't a body - // tag, the DTD will store tags that belong in the body until it sees - // text or a body tag. This flushes all context tags out of the DTD. - theContext.AppendLiteral(""); - } - // First, parse the context to build up the DTD's tag stack. Note that we // pass PR_FALSE for the aLastCall parameter. result = Parse(theContext, (void*)&theContext, aMimeType, @@ -1860,6 +1851,42 @@ nsParser::ParseFragment(const nsAString& aSourceBuffer, nsCOMPtr fragSink = do_QueryInterface(mSink); NS_ASSERTION(fragSink, "ParseFragment requires a fragment content sink"); + if (!aXMLMode) { + // First, we have to flush any tags that don't belong in the head if there + // was no in the context. + // XXX This is extremely ugly. Maybe CNavDTD should have FlushMisplaced()? + NS_ASSERTION(mParserContext, "Parsing didn't create a parser context?"); + nsCOMPtr dtd = do_QueryInterface(mParserContext->mDTD); + + if (dtd) { + CStartToken bodyToken(NS_LITERAL_STRING("BODY"), eHTMLTag_body); + nsCParserNode bodyNode(&bodyToken, 0); + + dtd->OpenBody(&bodyNode); + + // Now parse the flushed out tags. + result = BuildModel(); + if (NS_FAILED(result)) { + mFlags |= NS_PARSER_FLAG_OBSERVERS_ENABLED; + return result; + } + } + + // Now that we've flushed all of the tags out of the body, we have to make + // sure that there aren't any context tags left in the scanner. + NS_ASSERTION(mParserContext->mScanner, "Where'd the scanner go?"); + + PRUnichar next; + if (NS_SUCCEEDED(mParserContext->mScanner->Peek(next))) { + // Uh, oh. This must mean that the context stack has a special tag on + // it, such as