mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
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:
parent
cfffe8fe59
commit
0ef1113d9d
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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); }
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user