bug 296677: Fix nsParser::ParseFragment to not screw up setting <textarea>'s innerHTML. r=jst sr=peterv a=asa

This commit is contained in:
mrbkap%gmail.com 2005-06-16 18:59:59 +00:00
parent 13e87d6df0
commit 6664814803
4 changed files with 70 additions and 12 deletions

View File

@ -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<nsIContent> mRoot;
nsCOMPtr<nsIParser> 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()
{

View File

@ -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;
}

View File

@ -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;
};
/**

View File

@ -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("<BODY>");
}
// 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<nsIFragmentContentSink> 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 <body> in the context.
// XXX This is extremely ugly. Maybe CNavDTD should have FlushMisplaced()?
NS_ASSERTION(mParserContext, "Parsing didn't create a parser context?");
nsCOMPtr<CNavDTD> 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 <textarea> or <title> that requires its end tag before it
// will be consumed. Tell the content sink that it will be coming.
// Note: For now, we can assume that there is only one such tag.
NS_ASSERTION(next == '<', "The tokenizer failed to consume a token");
fragSink->IgnoreFirstContainer();
}
}
fragSink->WillBuildContent();
// Now, parse the actual content. Note that this is the last call for HTML
// content, but for XML, we will want to build and parse the end tags.