зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
d204424b35
Коммит
78f743c391
|
@ -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();
|
||||
|
@ -2841,8 +2907,6 @@ HTMLContentSink::ProcessSCRIPTTag(const nsIParserNode& aNode)
|
|||
// Don't process scripts that aren't JavaScript
|
||||
if (isJavaScript) {
|
||||
nsAutoString script;
|
||||
|
||||
mCurrentContext->FlushTags();
|
||||
|
||||
// If there is a SRC attribute...
|
||||
if (src.Length() > 0) {
|
||||
|
@ -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);
|
||||
pc->mMultipart=!aLastCall;
|
||||
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();
|
||||
|
@ -2841,8 +2907,6 @@ HTMLContentSink::ProcessSCRIPTTag(const nsIParserNode& aNode)
|
|||
// Don't process scripts that aren't JavaScript
|
||||
if (isJavaScript) {
|
||||
nsAutoString script;
|
||||
|
||||
mCurrentContext->FlushTags();
|
||||
|
||||
// If there is a SRC attribute...
|
||||
if (src.Length() > 0) {
|
||||
|
@ -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);
|
||||
pc->mMultipart=!aLastCall;
|
||||
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
|
||||
|
|
Загрузка…
Ссылка в новой задаче