Fixes for bugs 4783 and 2243. Content can now be added via the DOM during document loading. document.written content can also cause the parser to block.

This commit is contained in:
vidur%netscape.com 1999-04-13 22:22:51 +00:00
Родитель d204424b35
Коммит 78f743c391
8 изменённых файлов: 224 добавлений и 10 удалений

Просмотреть файл

@ -258,6 +258,8 @@ public:
// Script processing related routines
nsresult ResumeParsing();
nsresult PreEvaluateScript();
nsresult PostEvaluateScript();
nsresult EvaluateScript(nsString& aScript,
PRInt32 aLineNo);
@ -296,6 +298,8 @@ public:
nsresult FlushText(PRBool* aDidFlush = nsnull);
nsresult FlushTags();
PRBool IsCurrentContainer(nsHTMLTag mType);
void MaybeMarkSinkDirty();
void MaybeMarkSinkClean();
@ -528,8 +532,8 @@ MakeContentObject(nsHTMLTag aNodeType,
case eHTMLTag_basefont:
rv = NS_NewHTMLBaseFontElement(aResult, aAtom);
break;
case eHTMLTag_blockquote:/* XXX need a real object??? how does type=cite work? */
rv = NS_NewHTMLSpanElement(aResult, aAtom);
case eHTMLTag_blockquote:
rv = NS_NewHTMLQuoteElement(aResult, aAtom);
break;
case eHTMLTag_body:
rv = NS_NewHTMLBodyElement(aResult, aAtom);
@ -921,6 +925,17 @@ SinkContext::Begin(nsHTMLTag aNodeType, nsIHTMLContent* aRoot)
return NS_OK;
}
PRBool
SinkContext::IsCurrentContainer(nsHTMLTag aTag)
{
if (aTag == mStack[mStackPos-1].mType) {
return PR_TRUE;
}
else {
return PR_FALSE;
}
}
void
SinkContext::MaybeMarkSinkDirty()
{
@ -2747,6 +2762,52 @@ HTMLContentSink::ResumeParsing()
return NS_OK;
}
nsresult
HTMLContentSink::PreEvaluateScript()
{
// Cause frame creation and reflow of all body children that
// have thus far been appended. Note that if mDirty is true
// then we know that the current body child has not yet been
// added to the content model.
// We don't want the current body child to be appended (and
// have frames be constructed for it) since the current script
// may add new content to the tree (and cause an immediate
// reflow). As long as frames don't exist for the subtree rooted
// by the current body child, new content added to the subtree
// will not generate new frames and, hence, we won't have to
// worry about reflowing of incomplete content or double frame
// creation.
if (mDirty) {
if (nsnull != mBody) {
SINK_TRACE(SINK_TRACE_REFLOW,
("HTMLContentSink::PreEvaluateScript: reflow content"));
mDocument->ContentAppended(mBody, mBodyChildCount);
mBody->ChildCount(mBodyChildCount);
}
mDirty = PR_FALSE;
}
return mCurrentContext->FlushTags();
}
nsresult
HTMLContentSink::PostEvaluateScript()
{
// If the script added new content directly to the body, we update
// our body child count so that frames aren't created twice.
if (nsnull != mBody) {
mBody->ChildCount(mBodyChildCount);
// If the script is not a body child, we shouldn't include
// the element that we eagerly appended (the ancestor of the
// script), since it is not yet complete.
if (!mCurrentContext->IsCurrentContainer(eHTMLTag_body)) {
mBodyChildCount--;
}
}
return NS_OK;
}
nsresult
HTMLContentSink::EvaluateScript(nsString& aScript,
PRInt32 aLineNo)
@ -2795,8 +2856,13 @@ nsDoneLoadingScript(nsIUnicharStreamLoader* aLoader,
HTMLContentSink* sink = (HTMLContentSink*)aRef;
if (NS_OK == aStatus) {
sink->PreEvaluateScript();
// XXX We have no way of indicating failure. Silently fail?
sink->EvaluateScript(aData, 0);
sink->PostEvaluateScript();
}
sink->ResumeParsing();
@ -2842,8 +2908,6 @@ HTMLContentSink::ProcessSCRIPTTag(const nsIParserNode& aNode)
if (isJavaScript) {
nsAutoString script;
mCurrentContext->FlushTags();
// If there is a SRC attribute...
if (src.Length() > 0) {
// Use the SRC attribute value to load the URL
@ -2876,12 +2940,25 @@ HTMLContentSink::ProcessSCRIPTTag(const nsIParserNode& aNode)
}
}
else {
PRBool enabled = PR_TRUE;
PreEvaluateScript();
// Otherwise, get the text content of the script tag
script = aNode.GetSkippedContent();
PRUint32 lineNo = (PRUint32)aNode.GetSourceLineNumber();
EvaluateScript(script, lineNo);
PostEvaluateScript();
// If the parse was disabled as a result of this evaluate script
// (for example, if the script document.wrote a SCRIPT SRC= tag,
// we remind the parser to block.
if ((nsnull != mParser) && (PR_FALSE == mParser->IsParserEnabled())) {
rv = NS_ERROR_HTMLPARSER_BLOCK;
}
}
}

Просмотреть файл

@ -122,6 +122,7 @@ class nsIParser : public nsISupports {
* be a proxy for the NGLayout content model).
******************************************************************************************/
virtual PRBool EnableParser(PRBool aState) = 0;
virtual PRBool IsParserEnabled() = 0;
virtual nsresult Parse(nsIURL* aURL,nsIStreamObserver* aListener = nsnull,PRBool aEnableVerify=PR_FALSE) = 0;
virtual nsresult Parse(nsIInputStream& aStream, PRBool aEnableVerify=PR_FALSE) = 0;
virtual nsresult Parse(nsString& aSourceBuffer,void* aKey,const nsString& aContentType,PRBool aEnableVerify,PRBool aLastCall) = 0;

Просмотреть файл

@ -474,6 +474,11 @@ CParserContext* nsParser::PopContext() {
CParserContext* oldContext=mParserContext;
if(oldContext) {
mParserContext=oldContext->mPrevContext;
// If the old context was blocked, propogate the blocked state
// back to the newe one.
if (mParserContext) {
mParserContext->mParserEnabled = oldContext->mParserEnabled;
}
}
return oldContext;
}
@ -523,6 +528,18 @@ PRBool nsParser::EnableParser(PRBool aState){
return aState;
}
/**
* Call this to query whether the parser is enabled or not.
*
* @update vidur 4/12/99
* @return current state
*/
PRBool
nsParser::IsParserEnabled()
{
return mParserContext->mParserEnabled;
}
/**
* This is the main controlling routine in the parsing process.
@ -738,7 +755,12 @@ nsresult nsParser::Parse(nsString& aSourceBuffer,void* aKey,const nsString& aCon
pc->mScanner->Append(mUnusedInput);
}
pc->mScanner->Append(aSourceBuffer);
if (nsnull != pc->mPrevContext) {
pc->mMultipart = (pc->mPrevContext->mMultipart || !aLastCall);
}
else {
pc->mMultipart=!aLastCall;
}
result=ResumeParse();
if(aLastCall) {
pc->mScanner->CopyUnusedData(mUnusedInput);

Просмотреть файл

@ -186,6 +186,13 @@ friend class CTokenHandler;
*/
virtual PRBool EnableParser(PRBool aState);
/**
* Call this to query whether the parser is enabled or not.
*
* @update vidur 4/12/99
* @return current state
*/
virtual PRBool IsParserEnabled();
/**
* This rather arcane method (hack) is used as a signal between the

Просмотреть файл

@ -258,6 +258,8 @@ public:
// Script processing related routines
nsresult ResumeParsing();
nsresult PreEvaluateScript();
nsresult PostEvaluateScript();
nsresult EvaluateScript(nsString& aScript,
PRInt32 aLineNo);
@ -296,6 +298,8 @@ public:
nsresult FlushText(PRBool* aDidFlush = nsnull);
nsresult FlushTags();
PRBool IsCurrentContainer(nsHTMLTag mType);
void MaybeMarkSinkDirty();
void MaybeMarkSinkClean();
@ -528,8 +532,8 @@ MakeContentObject(nsHTMLTag aNodeType,
case eHTMLTag_basefont:
rv = NS_NewHTMLBaseFontElement(aResult, aAtom);
break;
case eHTMLTag_blockquote:/* XXX need a real object??? how does type=cite work? */
rv = NS_NewHTMLSpanElement(aResult, aAtom);
case eHTMLTag_blockquote:
rv = NS_NewHTMLQuoteElement(aResult, aAtom);
break;
case eHTMLTag_body:
rv = NS_NewHTMLBodyElement(aResult, aAtom);
@ -921,6 +925,17 @@ SinkContext::Begin(nsHTMLTag aNodeType, nsIHTMLContent* aRoot)
return NS_OK;
}
PRBool
SinkContext::IsCurrentContainer(nsHTMLTag aTag)
{
if (aTag == mStack[mStackPos-1].mType) {
return PR_TRUE;
}
else {
return PR_FALSE;
}
}
void
SinkContext::MaybeMarkSinkDirty()
{
@ -2747,6 +2762,52 @@ HTMLContentSink::ResumeParsing()
return NS_OK;
}
nsresult
HTMLContentSink::PreEvaluateScript()
{
// Cause frame creation and reflow of all body children that
// have thus far been appended. Note that if mDirty is true
// then we know that the current body child has not yet been
// added to the content model.
// We don't want the current body child to be appended (and
// have frames be constructed for it) since the current script
// may add new content to the tree (and cause an immediate
// reflow). As long as frames don't exist for the subtree rooted
// by the current body child, new content added to the subtree
// will not generate new frames and, hence, we won't have to
// worry about reflowing of incomplete content or double frame
// creation.
if (mDirty) {
if (nsnull != mBody) {
SINK_TRACE(SINK_TRACE_REFLOW,
("HTMLContentSink::PreEvaluateScript: reflow content"));
mDocument->ContentAppended(mBody, mBodyChildCount);
mBody->ChildCount(mBodyChildCount);
}
mDirty = PR_FALSE;
}
return mCurrentContext->FlushTags();
}
nsresult
HTMLContentSink::PostEvaluateScript()
{
// If the script added new content directly to the body, we update
// our body child count so that frames aren't created twice.
if (nsnull != mBody) {
mBody->ChildCount(mBodyChildCount);
// If the script is not a body child, we shouldn't include
// the element that we eagerly appended (the ancestor of the
// script), since it is not yet complete.
if (!mCurrentContext->IsCurrentContainer(eHTMLTag_body)) {
mBodyChildCount--;
}
}
return NS_OK;
}
nsresult
HTMLContentSink::EvaluateScript(nsString& aScript,
PRInt32 aLineNo)
@ -2795,8 +2856,13 @@ nsDoneLoadingScript(nsIUnicharStreamLoader* aLoader,
HTMLContentSink* sink = (HTMLContentSink*)aRef;
if (NS_OK == aStatus) {
sink->PreEvaluateScript();
// XXX We have no way of indicating failure. Silently fail?
sink->EvaluateScript(aData, 0);
sink->PostEvaluateScript();
}
sink->ResumeParsing();
@ -2842,8 +2908,6 @@ HTMLContentSink::ProcessSCRIPTTag(const nsIParserNode& aNode)
if (isJavaScript) {
nsAutoString script;
mCurrentContext->FlushTags();
// If there is a SRC attribute...
if (src.Length() > 0) {
// Use the SRC attribute value to load the URL
@ -2876,12 +2940,25 @@ HTMLContentSink::ProcessSCRIPTTag(const nsIParserNode& aNode)
}
}
else {
PRBool enabled = PR_TRUE;
PreEvaluateScript();
// Otherwise, get the text content of the script tag
script = aNode.GetSkippedContent();
PRUint32 lineNo = (PRUint32)aNode.GetSourceLineNumber();
EvaluateScript(script, lineNo);
PostEvaluateScript();
// If the parse was disabled as a result of this evaluate script
// (for example, if the script document.wrote a SCRIPT SRC= tag,
// we remind the parser to block.
if ((nsnull != mParser) && (PR_FALSE == mParser->IsParserEnabled())) {
rv = NS_ERROR_HTMLPARSER_BLOCK;
}
}
}

Просмотреть файл

@ -122,6 +122,7 @@ class nsIParser : public nsISupports {
* be a proxy for the NGLayout content model).
******************************************************************************************/
virtual PRBool EnableParser(PRBool aState) = 0;
virtual PRBool IsParserEnabled() = 0;
virtual nsresult Parse(nsIURL* aURL,nsIStreamObserver* aListener = nsnull,PRBool aEnableVerify=PR_FALSE) = 0;
virtual nsresult Parse(nsIInputStream& aStream, PRBool aEnableVerify=PR_FALSE) = 0;
virtual nsresult Parse(nsString& aSourceBuffer,void* aKey,const nsString& aContentType,PRBool aEnableVerify,PRBool aLastCall) = 0;

Просмотреть файл

@ -474,6 +474,11 @@ CParserContext* nsParser::PopContext() {
CParserContext* oldContext=mParserContext;
if(oldContext) {
mParserContext=oldContext->mPrevContext;
// If the old context was blocked, propogate the blocked state
// back to the newe one.
if (mParserContext) {
mParserContext->mParserEnabled = oldContext->mParserEnabled;
}
}
return oldContext;
}
@ -523,6 +528,18 @@ PRBool nsParser::EnableParser(PRBool aState){
return aState;
}
/**
* Call this to query whether the parser is enabled or not.
*
* @update vidur 4/12/99
* @return current state
*/
PRBool
nsParser::IsParserEnabled()
{
return mParserContext->mParserEnabled;
}
/**
* This is the main controlling routine in the parsing process.
@ -738,7 +755,12 @@ nsresult nsParser::Parse(nsString& aSourceBuffer,void* aKey,const nsString& aCon
pc->mScanner->Append(mUnusedInput);
}
pc->mScanner->Append(aSourceBuffer);
if (nsnull != pc->mPrevContext) {
pc->mMultipart = (pc->mPrevContext->mMultipart || !aLastCall);
}
else {
pc->mMultipart=!aLastCall;
}
result=ResumeParse();
if(aLastCall) {
pc->mScanner->CopyUnusedData(mUnusedInput);

Просмотреть файл

@ -186,6 +186,13 @@ friend class CTokenHandler;
*/
virtual PRBool EnableParser(PRBool aState);
/**
* Call this to query whether the parser is enabled or not.
*
* @update vidur 4/12/99
* @return current state
*/
virtual PRBool IsParserEnabled();
/**
* This rather arcane method (hack) is used as a signal between the