bug 263053: Get rid of the <endnote> tag when parsing fragments with context, since this can fail if the input stream contains another <endnote> tag. Instead, parse the context in different "chunks" from the new buffer, and notify the fragment sink by way of functions. r=peterv sr=bzbarsky

This commit is contained in:
mrbkap%gmail.com 2005-02-18 19:18:39 +00:00
parent 58396e7490
commit 76f3ff6fb1
11 changed files with 148 additions and 94 deletions

View File

@ -137,7 +137,6 @@ 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")

View File

@ -123,6 +123,8 @@ public:
// nsIFragmentContentSink
NS_IMETHOD GetFragment(nsIDOMDocumentFragment** aFragment);
NS_IMETHOD SetTargetDocument(nsIDocument* aDocument);
NS_IMETHOD WillBuildContent();
NS_IMETHOD DidBuildContent();
nsIContent* GetCurrentContent();
PRInt32 PushContent(nsIContent *aContent);
@ -140,13 +142,12 @@ public:
nsresult Init();
PRBool mHitSentinel;
PRBool mSeenBody;
PRPackedBool mAllContent;
PRPackedBool mProcessing;
PRPackedBool mSeenBody;
nsIContent* mRoot;
nsIParser* mParser;
nsIDOMHTMLFormElement* mCurrentForm;
nsGenericHTMLElement* mCurrentMap;
nsCOMPtr<nsIContent> mRoot;
nsCOMPtr<nsIParser> mParser;
nsVoidArray* mContentStack;
@ -192,22 +193,14 @@ NS_NewHTMLFragmentContentSink(nsIFragmentContentSink** aResult)
}
nsHTMLFragmentContentSink::nsHTMLFragmentContentSink(PRBool aAllContent)
: mAllContent(aAllContent),
mProcessing(aAllContent),
mSeenBody(!aAllContent),
mContentStack(nsnull),
mText(nsnull),
mTextLength(0),
mTextSize(0)
{
if (aAllContent) {
mHitSentinel = PR_TRUE;
mSeenBody = PR_FALSE;
} else {
mHitSentinel = PR_FALSE;
mSeenBody = PR_TRUE;
}
mRoot = nsnull;
mParser = nsnull;
mCurrentForm = nsnull;
mCurrentMap = nsnull;
mContentStack = nsnull;
mText = nsnull;
mTextLength = 0;
mTextSize = 0;
}
nsHTMLFragmentContentSink::~nsHTMLFragmentContentSink()
@ -215,10 +208,6 @@ nsHTMLFragmentContentSink::~nsHTMLFragmentContentSink()
// Should probably flush the text buffer here, just to make sure:
//FlushText();
NS_IF_RELEASE(mRoot);
NS_IF_RELEASE(mParser);
NS_IF_RELEASE(mCurrentForm);
NS_IF_RELEASE(mCurrentMap);
if (nsnull != mContentStack) {
// there shouldn't be anything here except in an error condition
PRInt32 indx = mContentStack->Count();
@ -256,7 +245,9 @@ nsHTMLFragmentContentSink::WillBuildModel(void)
nsresult rv = NS_NewDocumentFragment(getter_AddRefs(frag), mTargetDocument);
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(frag, &mRoot);
mRoot = do_QueryInterface(frag, &rv);
return rv;
}
NS_IMETHODIMP
@ -266,7 +257,7 @@ nsHTMLFragmentContentSink::DidBuildModel(void)
// Drop our reference to the parser to get rid of a circular
// reference.
NS_IF_RELEASE(mParser);
mParser = nsnull;
return NS_OK;
}
@ -286,9 +277,7 @@ nsHTMLFragmentContentSink::WillResume(void)
NS_IMETHODIMP
nsHTMLFragmentContentSink::SetParser(nsIParser* aParser)
{
NS_IF_RELEASE(mParser);
mParser = aParser;
NS_IF_ADDREF(mParser);
return NS_OK;
}
@ -449,15 +438,9 @@ nsHTMLFragmentContentSink::OpenContainer(const nsIParserNode& aNode)
{
NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_NOT_INITIALIZED);
nsAutoString tag;
nsresult result = NS_OK;
tag.Assign(aNode.GetText());
if (nsHTMLAtoms::endnote->Equals(tag)) {
mHitSentinel = PR_TRUE;
}
else if (mHitSentinel) {
if (mProcessing) {
FlushText();
nsHTMLTag nodeType = nsHTMLTag(aNode.GetNodeType());
@ -522,7 +505,7 @@ nsHTMLFragmentContentSink::OpenContainer(const nsIParserNode& aNode)
NS_IMETHODIMP
nsHTMLFragmentContentSink::CloseContainer(const nsHTMLTag aTag)
{
if (mHitSentinel && (nsnull != GetCurrentContent())) {
if (mProcessing && (nsnull != GetCurrentContent())) {
nsIContent* content;
FlushText();
content = PopContent();
@ -597,7 +580,7 @@ nsHTMLFragmentContentSink::AddLeaf(const nsIParserNode& aNode)
if(nodeType == eHTMLTag_script ||
nodeType == eHTMLTag_style ||
nodeType == eHTMLTag_textarea ||
nodeType == eHTMLTag_xmp) {
nodeType == eHTMLTag_server) {
// Create a text node holding the content
nsCOMPtr<nsIDTD> dtd;
@ -711,6 +694,25 @@ nsHTMLFragmentContentSink::SetTargetDocument(nsIDocument* aTargetDocument)
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::WillBuildContent()
{
mProcessing = PR_TRUE;
return NS_OK;
}
NS_IMETHODIMP
nsHTMLFragmentContentSink::DidBuildContent()
{
if (!mAllContent) {
FlushText();
mProcessing = PR_FALSE;
}
return NS_OK;
}
nsIContent*
nsHTMLFragmentContentSink::GetCurrentContent()
{

View File

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Blake Kaplan <mrbkap@gmail.com>
*
* 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"),
@ -87,6 +88,8 @@ public:
// nsIFragmentContentSink
NS_IMETHOD GetFragment(nsIDOMDocumentFragment** aFragment);
NS_IMETHOD SetTargetDocument(nsIDocument* aDocument);
NS_IMETHOD WillBuildContent();
NS_IMETHOD DidBuildContent();
protected:
virtual PRBool SetDocElement(PRInt32 aNameSpaceID,
@ -114,7 +117,6 @@ protected:
// if FALSE, take content inside endnote tag
PRPackedBool mAllContent;
nsCOMPtr<nsIContent> mEndnote;
};
static nsresult
@ -171,29 +173,20 @@ nsXMLFragmentContentSink::WillBuildModel(void)
NS_ENSURE_SUCCESS(rv, rv);
mRoot = do_QueryInterface(frag);
PushContent(mRoot); // preload content stack because we know all content goes in the fragment
if (mAllContent) {
// Preload content stack because we know all content goes in the fragment
PushContent(mRoot);
}
return rv;
}
NS_IMETHODIMP
nsXMLFragmentContentSink::DidBuildModel()
{
PopContent(); // remove mRoot pushed above
if (!mAllContent && !mParseError) {
NS_ASSERTION(mEndnote, "<endnote> 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<nsIContent> 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?
if (mAllContent) {
PopContent(); // remove mRoot pushed above
}
nsCOMPtr<nsIParser> kungFuDeathGrip(mParser);
@ -237,11 +230,17 @@ nsXMLFragmentContentSink::CreateElement(const PRUnichar** aAtts, PRUint32 aAttsC
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;
// Make sure that scripts are added immediately, not on close.
*aAppendContent = PR_TRUE;
// However, when we aren't grabbing all of the content we, never open a doc
// element, we run into trouble on the first element, so we don't append,
// and simply push this onto the content stack.
if (!mAllContent && mContentStack.Count() == 0) {
*aAppendContent = PR_FALSE;
}
return rv;
}
@ -387,3 +386,28 @@ nsXMLFragmentContentSink::SetTargetDocument(nsIDocument* aTargetDocument)
return NS_OK;
}
NS_IMETHODIMP
nsXMLFragmentContentSink::WillBuildContent()
{
// If we're taking all of the content, then we've already pushed mRoot
// onto the content stack, otherwise, start here.
if (!mAllContent) {
PushContent(mRoot);
}
return NS_OK;
}
NS_IMETHODIMP
nsXMLFragmentContentSink::DidBuildContent()
{
// If we're taking all of the content, then this is handled in DidBuildModel
if (!mAllContent) {
// Note: we need to FlushText() here because if we don't, we might not get
// an end element to do it for us, so make sure.
FlushText();
PopContent();
}
return NS_OK;
}

View File

@ -96,7 +96,6 @@ HTML_TAG(dl, SharedList)
HTML_TAG(dt, Span)
HTML_TAG(em, Span)
HTML_TAG(embed, Shared)
HTML_TAG(endnote, Span)
HTML_TAG(fieldset, FieldSet)
HTML_TAG(font, Font)
HTML_TAG(form, NOTUSED)

View File

@ -63,7 +63,7 @@ enum nsHTMLTag {
#undef HTML_TAG
#undef HTML_OTHER
// Currently there are 108 HTML tags. eHTMLTag_text = 110.
// Currently there are 107 HTML tags. eHTMLTag_text = 109.
#define NS_HTML_TAG_MAX PRInt32(eHTMLTag_text - 1)
class nsHTMLTags {

View File

@ -43,8 +43,8 @@ class nsIDOMDocumentFragment;
class nsIDocument;
#define NS_I_FRAGMENT_CONTENT_SINK_IID \
{ 0x2b23c1fb, 0xb83c, 0x436b, \
{ 0xb7, 0x2a, 0x9c, 0xbe, 0xf1, 0xe9, 0x9b, 0x20 } };
{ 0xe9ea6afb, 0x92f3, 0x4270, \
{ 0xb2, 0x67, 0xd2, 0xe3, 0x8d, 0x0e, 0x95, 0x45 } }
class nsIFragmentContentSink : public nsISupports {
public:
@ -66,11 +66,25 @@ public:
* (should not be null)
*/
NS_IMETHOD SetTargetDocument(nsIDocument* aDocument) = 0;
/**
* This method is used to indicate to the sink that we're done building
* the context and should start paying attention to the incoming content
*/
NS_IMETHOD WillBuildContent() = 0;
/**
* This method is used to indicate to the sink that we're done building
* The real content. This is useful if you want to parse additional context
* (such as an end context).
*/
NS_IMETHOD DidBuildContent() = 0;
};
/**
* Base version takes string nested in context, context ends with <endnote>.
* 2 version just loads whole string.
* Base version takes string nested in context, content surrounded by
* WillBuildContent()/DidBuildContent() calls. The 2nd version just loads
* the whole string.
*/
#define NS_HTMLFRAGMENTSINK_CONTRACTID "@mozilla.org/layout/htmlfragmentsink;1"

View File

@ -259,6 +259,19 @@ class nsIParser : public nsISupports {
NS_IMETHOD Terminate(void) = 0;
/**
* This method gets called when you want to parse a fragment of HTML or XML
* surrounded by the context |aTagStack|. It requires that the parser have
* been given a fragment content sink.
*
* @param aSourceBuffer The XML or HTML that hasn't been parsed yet.
* @param aKey The key used by the parser.
* @param aTagStack The context of the source buffer.
* @param aXMLMode Whether this is XML or HTML
* @param aContentType The content-type of this document.
* @param aMode The DTDMode that the parser should parse this fragment in.
* @return Success or failure.
*/
NS_IMETHOD ParseFragment(const nsAString& aSourceBuffer,
void* aKey,
nsVoidArray& aTagStack,

View File

@ -2251,7 +2251,6 @@ void CElementTable::InitializeElements() {
CPhraseElement::Initialize( mDfltElements[eHTMLTag_em], eHTMLTag_em);
CElement::Initialize( mDfltElements[eHTMLTag_embed], eHTMLTag_embed);
CBlockElement::Initialize( mDfltElements[eHTMLTag_endnote], eHTMLTag_endnote);
CElement::Initialize( mDfltElements[eHTMLTag_fieldset], eHTMLTag_fieldset, CBlockElement::GetGroup(), CFlowElement::GetContainedGroups());
mDfltElements[eHTMLTag_fieldset].mIncludeKids=kFieldsetKids;

View File

@ -545,15 +545,6 @@ void InitializeElementTable(void) {
/*special props, prop-range*/ kNonContainer,kDefaultPropRange,
/*special parents,kids,skip*/ 0,&gContainsParam,eHTMLTag_unknown);
Initialize(
/*tag*/ eHTMLTag_endnote,
/*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown,
/*rootnodes,endrootnodes*/ &gRootTags,&gRootTags,
/*autoclose starttags and endtags*/ 0,0,0,0,
/*parent,incl,exclgroups*/ kFlowEntity, kFlowEntity, kNone,
/*special props, prop-range*/ kLegalOpen,kDefaultPropRange, // Don't munge the content model around <endnote>. bug 100175
/*special parents,kids,skip*/ 0,0,eHTMLTag_unknown);
Initialize(
/*tag*/ eHTMLTag_fieldset,
/*requiredAncestor*/ eHTMLTag_unknown,eHTMLTag_unknown,

View File

@ -111,8 +111,6 @@ static const PRUnichar sHTMLTagUnicodeName_em[] =
{'e', 'm', '\0'};
static const PRUnichar sHTMLTagUnicodeName_embed[] =
{'e', 'm', 'b', 'e', 'd', '\0'};
static const PRUnichar sHTMLTagUnicodeName_endnote[] =
{'e', 'n', 'd', 'n', 'o', 't', 'e', '\0'};
static const PRUnichar sHTMLTagUnicodeName_fieldset[] =
{'f', 'i', 'e', 'l', 'd', 's', 'e', 't', '\0'};
static const PRUnichar sHTMLTagUnicodeName_font[] =

View File

@ -65,6 +65,7 @@
#include "nsIServiceManager.h"
#include "nsICategoryManager.h"
#include "nsISupportsPrimitives.h"
#include "nsIFragmentContentSink.h"
#ifdef MOZ_VIEW_SOURCE
#include "nsViewSourceHTML.h"
@ -1804,25 +1805,40 @@ nsParser::ParseFragment(const nsAString& aSourceBuffer,
nsDTDMode aMode)
{
nsresult result = NS_OK;
nsAutoString theContext, endContext;
nsAutoString theContext;
PRUint32 theCount = aTagStack.Count();
PRUint32 theIndex = 0;
// Disable observers for fragments
mFlags &= ~NS_PARSER_FLAG_OBSERVERS_ENABLED;
for (theIndex = 0; theIndex < theCount; theIndex++) {
theContext.AppendLiteral("<");
theContext.Append((PRUnichar*)aTagStack.ElementAt(theCount - theIndex - 1));
theContext.AppendLiteral(">");
}
// Note duplication: nsHTMLAtoms::endnote == an atom in nsHTMLTags
theContext.AppendLiteral("<");
theContext.Append(nsHTMLTags::GetStringValue(eHTMLTag_endnote));
theContext.AppendLiteral(">");
if (aXMLMode) {
endContext.AppendLiteral("</");
endContext.Append(nsHTMLTags::GetStringValue(eHTMLTag_endnote));
endContext.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,
PR_FALSE, PR_FALSE, aMode);
if (NS_FAILED(result)) {
mFlags |= NS_PARSER_FLAG_OBSERVERS_ENABLED;
return result;
}
nsCOMPtr<nsIFragmentContentSink> fragSink = do_QueryInterface(mSink);
NS_ASSERTION(fragSink, "ParseFragment requires a fragment content sink");
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.
result = Parse(aSourceBuffer, (void*)&theContext, aMimeType,
PR_FALSE, !aXMLMode, aMode);
fragSink->DidBuildContent();
if (aXMLMode && NS_SUCCEEDED(result)) {
nsAutoString endContext;
for (theIndex = 0; theIndex < theCount; theIndex++) {
endContext.AppendLiteral("</");
@ -1834,12 +1850,11 @@ nsParser::ParseFragment(const nsAString& aSourceBuffer,
endContext.Append( Substring(thisTag,0,endOfTag) );
endContext.AppendLiteral(">");
}
result = Parse(endContext, (void*)&theContext, aMimeType,
PR_FALSE, PR_TRUE, aMode);
}
//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 + endContext,(void*)&theContext,aMimeType,PR_FALSE,PR_TRUE, aMode);
mFlags |= NS_PARSER_FLAG_OBSERVERS_ENABLED; //now reenable.
return result;