Keep the DTD's stack in sync with the content sink's stack to avoid miscommunication. bug 333497, r=sicking sr=jst

This commit is contained in:
mrbkap%gmail.com 2006-06-22 21:34:35 +00:00
parent cfffe8fe59
commit 0ef1113d9d
4 changed files with 65 additions and 9 deletions

View File

@ -409,7 +409,10 @@ CNavDTD::DidBuildModel(nsresult anErrorCode,
// mContextTopIndex refers to the misplaced content's legal parent index.
result = HandleSavedTokens(mBodyContext->mContextTopIndex);
NS_ENSURE_SUCCESS(result, result);
if (NS_FAILED(result)) {
NS_ERROR("Bug in the DTD");
break;
}
// If we start handling misplaced content while handling misplaced
// content, mContextTopIndex gets modified. However, this new index
@ -601,7 +604,6 @@ CNavDTD::HandleToken(CToken* aToken, nsIParser* aParser)
switch(theTag) {
case eHTMLTag_html:
case eHTMLTag_noframes:
case eHTMLTag_noscript:
case eHTMLTag_script:
case eHTMLTag_doctypeDecl:
case eHTMLTag_instruction:
@ -613,14 +615,16 @@ CNavDTD::HandleToken(CToken* aToken, nsIParser* aParser)
NS_DTD_FLAG_ALTERNATE_CONTENT))) {
// For bug examples from this code, see bugs: 18928, 20989.
// At this point we know the body/frameset aren't open.
// If the child belongs in the head, then handle it (which may open the head);
// otherwise, push it onto the misplaced stack.
// If the child belongs in the head, then handle it (which may open
// the head); otherwise, push it onto the misplaced stack.
PRBool isExclusive = PR_FALSE;
PRBool theChildBelongsInHead =
gHTMLElements[eHTMLTag_head].IsChildOfHead(theTag, isExclusive);
if (theChildBelongsInHead && !isExclusive) {
if (mMisplacedContent.GetSize() == 0) {
if (mMisplacedContent.GetSize() == 0 &&
(!gHTMLElements[theTag].HasSpecialProperty(kPreferBody) ||
(mFlags & NS_DTD_FLAG_HAS_EXPLICIT_HEAD))) {
// This tag can either be in the body or the head. Since
// there is no indication that the body should be open,
// put this token in the head.
@ -636,7 +640,7 @@ CNavDTD::HandleToken(CToken* aToken, nsIParser* aParser)
eHTMLTags top = mBodyContext->Last();
NS_ASSERTION(top != eHTMLTag_userdefined,
"Userdefined tags should act as leaves in the head");
if (top != eHTMLTag_html &&
if (top != eHTMLTag_html && top != eHTMLTag_head &&
gHTMLElements[top].CanContain(theTag, mDTDMode)) {
// Some tags (such as <object> and <script>) are opened in the
// head and allow other non-head content to be children.
@ -1543,7 +1547,8 @@ CNavDTD::HandleEndToken(CToken* aToken)
case eHTMLTag_head:
StripWSFollowingTag(theChildTag, mTokenizer, mTokenAllocator, mLineNumber);
result = CloseContainer(eHTMLTag_head, PR_FALSE);
result = CloseContainersTo(eHTMLTag_head, PR_FALSE);
mFlags &= ~NS_DTD_FLAG_HAS_EXPLICIT_HEAD;
break;
case eHTMLTag_form:
@ -1723,10 +1728,12 @@ CNavDTD::HandleSavedTokens(PRInt32 anIndex)
STOP_TIMER()
MOZ_TIMER_DEBUGLOG(("Stop: Parse Time: CNavDTD::HandleSavedTokensAbove(), this=%p\n", this));
// Pause the main context and switch to the new context.
mSink->BeginContext(anIndex);
result = mSink->BeginContext(anIndex);
MOZ_TIMER_DEBUGLOG(("Start: Parse Time: CNavDTD::HandleSavedTokensAbove(), this=%p\n", this));
START_TIMER()
NS_ENSURE_SUCCESS(result, result);
// The body context should contain contents only upto the marked position.
mBodyContext->MoveEntries(*mTempContext, theTagCount - theTopIndex);
@ -2642,6 +2649,15 @@ CNavDTD::CloseContainer(const eHTMLTags aTag, PRBool aMalformed)
case eHTMLTag_head:
if (mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD) {
mFlags &= ~NS_DTD_FLAG_HAS_OPEN_HEAD;
if (mBodyContext->Last() == eHTMLTag_head) {
mBodyContext->Pop();
} else {
// This else can happen because CloseContainer is called both directly
// and from CloseContainersTo. CloseContainersTo pops the current tag
// off of the stack before calling CloseContainer.
NS_ASSERTION(mBodyContext->LastOf(eHTMLTag_head) == kNotFound,
"Closing the wrong tag");
}
done = PR_FALSE;
}
break;
@ -2967,6 +2983,7 @@ CNavDTD::AddHeadContent(nsIParserNode *aNode)
// Make sure the head is opened.
if (!(mFlags & NS_DTD_FLAG_HAS_OPEN_HEAD)) {
mFlags |= NS_DTD_FLAG_HAS_OPEN_HEAD;
mBodyContext->PushTag(eHTMLTag_head);
result = mSink->OpenHead();
}

View File

@ -167,6 +167,15 @@ void nsEntryStack::Push(nsCParserNode* aNode,
}
}
void nsEntryStack::PushTag(eHTMLTags aTag)
{
EnsureCapacityFor(mCount + 1);
mEntries[mCount].mTag = aTag;
mEntries[mCount].mParent = nsnull;
mEntries[mCount].mStyles = nsnull;
++mCount;
}
/**
* This method inserts the given node onto the front of this stack
@ -490,6 +499,17 @@ void nsDTDContext::Push(nsCParserNode* aNode,
}
}
void nsDTDContext::PushTag(eHTMLTags aTag)
{
#ifdef NS_DEBUG
if (mStack.mCount < eMaxTags) {
mXTags[mStack.mCount] = aTag;
}
#endif
mStack.PushTag(aTag);
}
nsTagEntry*
nsDTDContext::PopEntry()
{

View File

@ -124,6 +124,7 @@ public:
void PushEntry(nsTagEntry* aEntry, PRBool aRefCntNode = PR_TRUE);
void EnsureCapacityFor(PRInt32 aNewMax, PRInt32 aShiftOffset=0);
void Push(nsCParserNode* aNode,nsEntryStack* aStyleStack=0, PRBool aRefCntNode = PR_TRUE);
void PushTag(eHTMLTags aTag);
void PushFront(nsCParserNode* aNode,nsEntryStack* aStyleStack=0, PRBool aRefCntNode = PR_TRUE);
void Append(nsEntryStack *aStack);
nsCParserNode* Pop(void);
@ -309,6 +310,7 @@ public:
void PushEntry(nsTagEntry* aEntry, PRBool aRefCntNode = PR_TRUE);
void MoveEntries(nsDTDContext& aDest, PRInt32 aCount);
void Push(nsCParserNode* aNode,nsEntryStack* aStyleStack=0, PRBool aRefCntNode = PR_TRUE);
void PushTag(eHTMLTags aTag);
nsCParserNode* Pop(nsEntryStack*& aChildStack);
nsCParserNode* Pop();
nsCParserNode* PeekNode() { return mStack.NodeAt(mStack.mCount-1); }

View File

@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 sw=2 et tw=78: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -889,7 +890,7 @@ const nsHTMLElement gHTMLElements[] = {
/*req-parent excl-parent*/ eHTMLTag_unknown,eHTMLTag_unknown,
/*rootnodes,endrootnodes*/ &gRootTags,&gRootTags,
/*autoclose starttags and endtags*/ 0,0,0,0,
/*parent,incl,exclgroups*/ kHeadMisc|kFlowEntity, kFlowEntity|kSelf, kNone,
/*parent,incl,exclgroups*/ kFlowEntity, kFlowEntity|kSelf, kNone,
/*special props, prop-range*/ 0, kNoPropRange,
/*special parents,kids,skip*/ 0,0,eHTMLTag_unknown,
/*contain-func*/ 0
@ -2221,6 +2222,22 @@ eHTMLTags nsHTMLElement::GetCloseTargetForEndTag(nsDTDContext& aContext,PRInt32
}
}
else if (mTagID == eHTMLTag_head) {
while (--theIndex >= anIndex) {
eHTMLTags tag = aContext.TagAt(theIndex);
if (tag == eHTMLTag_html) {
// HTML gates head closing, but the head should never be the parent of
// an html tag.
break;
}
if (tag == eHTMLTag_head) {
result = eHTMLTag_head;
break;
}
}
}
return result;
}