Fixed a crash my making sure that the CNavDTD and HTMLContentSink stacks are synchronized when handling a FORM. b=133410, r=heikki, sr=jst

This commit is contained in:
harishd%netscape.com 2002-04-11 23:50:44 +00:00
Родитель 2cc4de292f
Коммит cd7eee0829
14 изменённых файлов: 69 добавлений и 47 удалений

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

@ -193,11 +193,12 @@ static PRLogModuleInfo* gSinkLogModuleInfo;
//----------------------------------------------------------------------
#define NS_SINK_FLAG_SCRIPT_ENABLED 0x8
#define NS_SINK_FLAG_FRAMES_ENABLED 0x10
#define NS_SINK_FLAG_SCRIPT_ENABLED 0x8
#define NS_SINK_FLAG_FRAMES_ENABLED 0x10
#define NS_SINK_FLAG_CAN_INTERRUPT_PARSER 0x20 //Interrupt parsing when mMaxTokenProcessingTime is exceeded
#define NS_SINK_FLAG_DYNAMIC_LOWER_VALUE 0x40 // Lower the value for mNotificationInterval and mMaxTokenProcessingTime
#define NS_SINK_FLAG_IS_BASE_HREF_SET 0x80 //Set a flag as soon as Base Href is set for the document
#define NS_SINK_FLAG_DYNAMIC_LOWER_VALUE 0x40 // Lower the value for mNotificationInterval and mMaxTokenProcessingTime
#define NS_SINK_FLAG_IS_BASE_HREF_SET 0x80 //Set a flag as soon as Base Href is set for the document
#define NS_SINK_FLAG_FORM_ON_STACK 0x100
#define NS_DELAY_FOR_WINDOW_CREATION 500000 // 1/2 second fudge factor for window creation
#define NS_MAX_TOKENS_DEFLECTED_IN_LOW_FREQ_MODE 200 //200 determined empirically to provide good user response without
@ -268,6 +269,7 @@ public:
NS_IMETHOD OpenMap(const nsIParserNode& aNode);
NS_IMETHOD CloseMap(const nsIParserNode& aNode);
NS_IMETHOD GetPref(PRInt32 aTag,PRBool& aPref);
NS_IMETHOD_(PRBool) IsFormOnStack();
NS_IMETHOD DoFragment(PRBool aFlag);
@ -1592,6 +1594,7 @@ SinkContext::CloseContainer(const nsIParserNode& aNode)
case eHTMLTag_form:
{
mSink->mFlags &= ~NS_SINK_FLAG_FORM_ON_STACK;
nsHTMLTag parserNodeType = nsHTMLTag(aNode.GetNodeType());
// If there's a FORM on the stack, but this close tag doesn't
@ -2936,9 +2939,16 @@ HTMLContentSink::SetParser(nsIParser* aParser)
return NS_OK;
}
NS_IMETHODIMP_(PRBool)
HTMLContentSink::IsFormOnStack()
{
return mFlags & NS_SINK_FLAG_FORM_ON_STACK;
}
NS_IMETHODIMP
HTMLContentSink::BeginContext(PRInt32 aPosition)
{
{
MOZ_TIMER_DEBUGLOG(("Start: nsHTMLContentSink::BeginContext()\n"));
MOZ_TIMER_START(mWatch);
NS_PRECONDITION(aPosition > -1, "out of bounds");
@ -3289,6 +3299,7 @@ HTMLContentSink::OpenForm(const nsIParserNode& aNode)
result = AddLeaf(aNode);
}
else {
mFlags |= NS_SINK_FLAG_FORM_ON_STACK;
// Otherwise the form can be a content parent.
result = mCurrentContext->OpenContainer(aNode);
if (NS_SUCCEEDED(result)) {
@ -3326,6 +3337,7 @@ HTMLContentSink::CloseForm(const nsIParserNode& aNode)
// Check if this is a well-formed form
if (mCurrentContext->IsCurrentContainer(eHTMLTag_form)) {
result = mCurrentContext->CloseContainer(aNode);
mFlags &= ~NS_SINK_FLAG_FORM_ON_STACK;
}
else if (mCurrentContext->IsAncestorContainer(eHTMLTag_form)) {
result = mCurrentContext->DemoteForm(aNode);

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

@ -108,6 +108,8 @@ public:
NS_IMETHOD OpenNoscript(const nsIParserNode& aNode);
NS_IMETHOD CloseNoscript(const nsIParserNode& aNode);
NS_IMETHOD GetPref(PRInt32 aTag,PRBool& aPref) { return NS_OK; }
NS_IMETHOD_(PRBool) IsFormOnStack() { return PR_FALSE; }
NS_IMETHOD OpenMap(const nsIParserNode& aNode);
NS_IMETHOD CloseMap(const nsIParserNode& aNode);
NS_IMETHOD FlushPendingNotifications() { return NS_OK; }

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

@ -336,6 +336,13 @@ public:
*/
NS_IMETHOD NotifyTagObservers(nsIParserNode* aNode)=0;
/**
* Call this method to determnine if a FORM is on the sink's stack
*
* @return PR_TRUE if found else PR_FALSE
*/
NS_IMETHOD_(PRBool) IsFormOnStack() = 0;
};
#ifdef NS_DEBUG
@ -345,3 +352,4 @@ extern nsresult NS_NewHTMLNullSink(nsIContentSink** aInstancePtrResult);
#endif
#endif /* nsIHTMLContentSink_h___ */

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

@ -90,6 +90,8 @@ public:
NS_IMETHOD OpenFrameset(const nsIParserNode& aNode);
NS_IMETHOD CloseFrameset(const nsIParserNode& aNode);
NS_IMETHOD GetPref(PRInt32 aTag,PRBool& aPref) { return NS_OK; }
NS_IMETHOD_(PRBool) IsFormOnStack() { return PR_FALSE; }
NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
NS_IMETHOD CloseContainer(const nsIParserNode& aNode);
NS_IMETHOD CloseTopmostContainer();

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

@ -117,7 +117,6 @@ static char gShowCRC;
#define NS_DTD_FLAG_HAD_FRAMESET 0x00000010
#define NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE 0x00000020
#define NS_DTD_FLAG_REQUESTED_HEAD 0x00000040
#define NS_DTD_FLAG_IS_FORM_CONTAINER 0x00000080
#define NS_DTD_FLAG_SCRIPT_ENABLED 0x00000100
#define NS_DTD_FLAG_FRAMES_ENABLED 0x00000200
#define NS_DTD_FLAG_ALTERNATE_CONTENT 0x00000400 // NOFRAMES, NOSCRIPT
@ -579,7 +578,7 @@ nsresult CNavDTD::DidBuildModel(nsresult anErrorCode,PRBool aNotifySink,nsIParse
result=HandleToken(theTableToken,mParser);
}
}
if(result==NS_OK) {
if(NS_SUCCEEDED(result)) {
eHTMLTags theTarget;
//now let's disable style handling to save time when closing remaining stack members...
@ -2034,14 +2033,15 @@ nsresult CNavDTD::HandleSavedTokens(PRInt32 anIndex) {
PRInt32 attrCount;
PRInt32 theTopIndex = anIndex + 1;
PRInt32 theTagCount = mBodyContext->GetCount();
//eHTMLTags theParentTag= mBodyContext->TagAt(anIndex);
//XXX In the content sink, FORM behaves as a container for parents
//other than eHTMLTag_table,eHTMLTag_tbody,eHTMLTag_tr,eHTMLTag_col,
//eHTMLTag_tfoot,eHTMLTag_thead,eHTMLTag_colgroup.In those cases the stack
//position, in the parser, should be synchronized with the sink. -- Ref: Bug 20087.
if (!(~mFlags & (NS_DTD_FLAG_HAS_OPEN_FORM | NS_DTD_FLAG_IS_FORM_CONTAINER))) anIndex++;
if (mSink && mSink->IsFormOnStack()) {
// Do this to synchronize dtd stack and the sink stack.
// Note: FORM is never on the dtd stack because its always
// considered as a leaf. However, in the sink FORM can either
// be a container or a leaf. Therefore, we have to check
// with the sink -- Ref: Bug 20087.
anIndex++;
}
STOP_TIMER()
MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::HandleSavedTokensAbove(), this=%p\n", this));
@ -3188,18 +3188,8 @@ nsresult CNavDTD::CloseBody(const nsIParserNode *aNode){
* @return TRUE if ok, FALSE if error
*/
nsresult CNavDTD::OpenForm(const nsIParserNode *aNode){
static eHTMLTags gTableElements[]={eHTMLTag_table,eHTMLTag_tbody,eHTMLTag_tr,
eHTMLTag_tfoot,eHTMLTag_thead,
eHTMLTag_col,eHTMLTag_colgroup};
nsresult result=NS_OK;
if(!(mFlags & NS_DTD_FLAG_HAS_OPEN_FORM)) { // discard nested forms - bug 72639
// Check if the parent is a table, tbody, thead, tfoot, tr, col or
// colgroup. If so, treat form as a leaf content. [ Ex. bug 92530 ]
if(!FindTagInSet(mBodyContext->Last(),gTableElements,
sizeof(gTableElements)/sizeof(eHTMLTag_unknown))) {
mFlags |= NS_DTD_FLAG_IS_FORM_CONTAINER;
}
STOP_TIMER();
MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::OpenForm(), this=%p\n", this));
@ -3238,8 +3228,6 @@ nsresult CNavDTD::CloseForm(const nsIParserNode *aNode){
MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::CloseForm(), this=%p\n", this));
START_TIMER();
mFlags &= ~NS_DTD_FLAG_IS_FORM_CONTAINER;
}
return result;
}

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

@ -88,6 +88,8 @@ public:
NS_IMETHOD OpenFrameset(const nsIParserNode& aNode);
NS_IMETHOD CloseFrameset(const nsIParserNode& aNode);
NS_IMETHOD GetPref(PRInt32 aTag,PRBool& aPref) { return NS_OK; }
NS_IMETHOD_(PRBool) IsFormOnStack() { return PR_FALSE; }
NS_IMETHOD WillProcessTokens(void) { return NS_OK; }
NS_IMETHOD DidProcessTokens(void) { return NS_OK; }
NS_IMETHOD WillProcessAToken(void) { return NS_OK; }

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

@ -630,6 +630,7 @@ nsresult nsHTMLTokenizer::ConsumeAttributes(PRUnichar aChar,
PRBool isUsableAttr = PR_TRUE;
const nsAString& key=theToken->GetKey();
const nsAString& text=theToken->GetValue();
// support XML like syntax to fix bugs like 44186
if(!key.IsEmpty() && kForwardSlash==key.First() && text.IsEmpty()) {
isUsableAttr = PRBool(mFlags & NS_IPARSER_FLAG_VIEW_SOURCE); // Fix bug 103095

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

@ -91,6 +91,8 @@ public:
NS_IMETHOD OpenFrameset(const nsIParserNode& aNode);
NS_IMETHOD CloseFrameset(const nsIParserNode& aNode);
NS_IMETHOD GetPref(PRInt32 aTag,PRBool& aPref) { return NS_OK; }
NS_IMETHOD_(PRBool) IsFormOnStack() { return PR_FALSE; }
NS_IMETHOD DoFragment(PRBool aFlag);
NS_IMETHOD BeginContext(PRInt32 aPosition);
NS_IMETHOD EndContext(PRInt32 aPosition);
@ -119,3 +121,4 @@ protected:
};
#endif

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

@ -336,6 +336,13 @@ public:
*/
NS_IMETHOD NotifyTagObservers(nsIParserNode* aNode)=0;
/**
* Call this method to determnine if a FORM is on the sink's stack
*
* @return PR_TRUE if found else PR_FALSE
*/
NS_IMETHOD_(PRBool) IsFormOnStack() = 0;
};
#ifdef NS_DEBUG
@ -345,3 +352,4 @@ extern nsresult NS_NewHTMLNullSink(nsIContentSink** aInstancePtrResult);
#endif
#endif /* nsIHTMLContentSink_h___ */

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

@ -90,6 +90,8 @@ public:
NS_IMETHOD OpenFrameset(const nsIParserNode& aNode);
NS_IMETHOD CloseFrameset(const nsIParserNode& aNode);
NS_IMETHOD GetPref(PRInt32 aTag,PRBool& aPref) { return NS_OK; }
NS_IMETHOD_(PRBool) IsFormOnStack() { return PR_FALSE; }
NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
NS_IMETHOD CloseContainer(const nsIParserNode& aNode);
NS_IMETHOD CloseTopmostContainer();

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

@ -117,7 +117,6 @@ static char gShowCRC;
#define NS_DTD_FLAG_HAD_FRAMESET 0x00000010
#define NS_DTD_FLAG_ENABLE_RESIDUAL_STYLE 0x00000020
#define NS_DTD_FLAG_REQUESTED_HEAD 0x00000040
#define NS_DTD_FLAG_IS_FORM_CONTAINER 0x00000080
#define NS_DTD_FLAG_SCRIPT_ENABLED 0x00000100
#define NS_DTD_FLAG_FRAMES_ENABLED 0x00000200
#define NS_DTD_FLAG_ALTERNATE_CONTENT 0x00000400 // NOFRAMES, NOSCRIPT
@ -579,7 +578,7 @@ nsresult CNavDTD::DidBuildModel(nsresult anErrorCode,PRBool aNotifySink,nsIParse
result=HandleToken(theTableToken,mParser);
}
}
if(result==NS_OK) {
if(NS_SUCCEEDED(result)) {
eHTMLTags theTarget;
//now let's disable style handling to save time when closing remaining stack members...
@ -2034,14 +2033,15 @@ nsresult CNavDTD::HandleSavedTokens(PRInt32 anIndex) {
PRInt32 attrCount;
PRInt32 theTopIndex = anIndex + 1;
PRInt32 theTagCount = mBodyContext->GetCount();
//eHTMLTags theParentTag= mBodyContext->TagAt(anIndex);
//XXX In the content sink, FORM behaves as a container for parents
//other than eHTMLTag_table,eHTMLTag_tbody,eHTMLTag_tr,eHTMLTag_col,
//eHTMLTag_tfoot,eHTMLTag_thead,eHTMLTag_colgroup.In those cases the stack
//position, in the parser, should be synchronized with the sink. -- Ref: Bug 20087.
if (!(~mFlags & (NS_DTD_FLAG_HAS_OPEN_FORM | NS_DTD_FLAG_IS_FORM_CONTAINER))) anIndex++;
if (mSink && mSink->IsFormOnStack()) {
// Do this to synchronize dtd stack and the sink stack.
// Note: FORM is never on the dtd stack because its always
// considered as a leaf. However, in the sink FORM can either
// be a container or a leaf. Therefore, we have to check
// with the sink -- Ref: Bug 20087.
anIndex++;
}
STOP_TIMER()
MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::HandleSavedTokensAbove(), this=%p\n", this));
@ -3188,18 +3188,8 @@ nsresult CNavDTD::CloseBody(const nsIParserNode *aNode){
* @return TRUE if ok, FALSE if error
*/
nsresult CNavDTD::OpenForm(const nsIParserNode *aNode){
static eHTMLTags gTableElements[]={eHTMLTag_table,eHTMLTag_tbody,eHTMLTag_tr,
eHTMLTag_tfoot,eHTMLTag_thead,
eHTMLTag_col,eHTMLTag_colgroup};
nsresult result=NS_OK;
if(!(mFlags & NS_DTD_FLAG_HAS_OPEN_FORM)) { // discard nested forms - bug 72639
// Check if the parent is a table, tbody, thead, tfoot, tr, col or
// colgroup. If so, treat form as a leaf content. [ Ex. bug 92530 ]
if(!FindTagInSet(mBodyContext->Last(),gTableElements,
sizeof(gTableElements)/sizeof(eHTMLTag_unknown))) {
mFlags |= NS_DTD_FLAG_IS_FORM_CONTAINER;
}
STOP_TIMER();
MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::OpenForm(), this=%p\n", this));
@ -3238,8 +3228,6 @@ nsresult CNavDTD::CloseForm(const nsIParserNode *aNode){
MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::CloseForm(), this=%p\n", this));
START_TIMER();
mFlags &= ~NS_DTD_FLAG_IS_FORM_CONTAINER;
}
return result;
}

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

@ -88,6 +88,8 @@ public:
NS_IMETHOD OpenFrameset(const nsIParserNode& aNode);
NS_IMETHOD CloseFrameset(const nsIParserNode& aNode);
NS_IMETHOD GetPref(PRInt32 aTag,PRBool& aPref) { return NS_OK; }
NS_IMETHOD_(PRBool) IsFormOnStack() { return PR_FALSE; }
NS_IMETHOD WillProcessTokens(void) { return NS_OK; }
NS_IMETHOD DidProcessTokens(void) { return NS_OK; }
NS_IMETHOD WillProcessAToken(void) { return NS_OK; }

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

@ -630,6 +630,7 @@ nsresult nsHTMLTokenizer::ConsumeAttributes(PRUnichar aChar,
PRBool isUsableAttr = PR_TRUE;
const nsAString& key=theToken->GetKey();
const nsAString& text=theToken->GetValue();
// support XML like syntax to fix bugs like 44186
if(!key.IsEmpty() && kForwardSlash==key.First() && text.IsEmpty()) {
isUsableAttr = PRBool(mFlags & NS_IPARSER_FLAG_VIEW_SOURCE); // Fix bug 103095

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

@ -91,6 +91,8 @@ public:
NS_IMETHOD OpenFrameset(const nsIParserNode& aNode);
NS_IMETHOD CloseFrameset(const nsIParserNode& aNode);
NS_IMETHOD GetPref(PRInt32 aTag,PRBool& aPref) { return NS_OK; }
NS_IMETHOD_(PRBool) IsFormOnStack() { return PR_FALSE; }
NS_IMETHOD DoFragment(PRBool aFlag);
NS_IMETHOD BeginContext(PRInt32 aPosition);
NS_IMETHOD EndContext(PRInt32 aPosition);
@ -119,3 +121,4 @@ protected:
};
#endif