Fix bug 390565. r+sr=mrbkap

git-svn-id: svn://10.0.0.236/trunk@240269 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
bzbarsky%mit.edu
2007-12-03 02:29:49 +00:00
parent fe0baddfd0
commit 607d0f5160
4 changed files with 384 additions and 43 deletions

View File

@@ -474,47 +474,52 @@ CNavDTD::GetType()
return NS_IPARSER_FLAG_HTML;
}
/**
* Text and some tags require a body when they're added, this function returns
* true for those tags.
*
* @param aToken The current token that we care about.
* @param aTokenizer A tokenizer that we can get the tags attributes off of.
* @return PR_TRUE if aToken does indeed force the body to open.
*/
static PRBool
DoesRequireBody(CToken* aToken, nsITokenizer* aTokenizer)
ValueIsHidden(const nsAString& aValue)
{
PRBool result = PR_FALSE;
// Having to deal with whitespace here sucks, but we have to match
// what the content sink does.
nsAutoString str(aValue);
str.Trim("\n\r\t\b");
return str.LowerCaseEqualsLiteral("hidden");
}
if (aToken) {
eHTMLTags theTag = (eHTMLTags)aToken->GetTypeID();
if (gHTMLElements[theTag].HasSpecialProperty(kRequiresBody)) {
if (theTag == eHTMLTag_input) {
// IE & Nav4x opens up a body for type=text - Bug 66985
PRInt32 ac = aToken->GetAttributeCount();
for(PRInt32 i = 0; i < ac; ++i) {
CAttributeToken* attr = static_cast<CAttributeToken*>
(aTokenizer->GetTokenAt(i));
const nsSubstring& name = attr->GetKey();
const nsAString& value = attr->GetValue();
if ((name.EqualsLiteral("type") ||
name.EqualsLiteral("TYPE"))
&&
!(value.EqualsLiteral("hidden") ||
value.EqualsLiteral("HIDDEN"))) {
result = PR_TRUE;
break;
}
}
} else {
result = PR_TRUE;
}
// Check whether aToken corresponds to a <input type="hidden"> tag. The token
// must be a start tag token for an <input>. This must be called at a point
// when all the attributes for the input are still in the tokenizer.
static PRBool
IsHiddenInput(CToken* aToken, nsITokenizer* aTokenizer)
{
NS_PRECONDITION(eHTMLTokenTypes(aToken->GetTokenType()) == eToken_start,
"Must be start token");
NS_PRECONDITION(eHTMLTags(aToken->GetTypeID()) == eHTMLTag_input,
"Must be <input> tag");
PRInt32 ac = aToken->GetAttributeCount();
NS_ASSERTION(ac <= aTokenizer->GetCount(),
"Not enough tokens in the tokenizer");
// But we don't really trust ourselves to get that right
ac = PR_MIN(ac, aTokenizer->GetCount());
for (PRInt32 i = 0; i < ac; ++i) {
NS_ASSERTION(eHTMLTokenTypes(aTokenizer->GetTokenAt(i)->GetTokenType()) ==
eToken_attribute, "Unexpected token type");
// Again, we're not sure we actually manage to guarantee that
if (eHTMLTokenTypes(aTokenizer->GetTokenAt(i)->GetTokenType()) !=
eToken_attribute) {
break;
}
CAttributeToken* attrToken =
static_cast<CAttributeToken*>(aTokenizer->GetTokenAt(i));
if (!attrToken->GetKey().LowerCaseEqualsLiteral("type")) {
continue;
}
return ValueIsHidden(attrToken->GetValue());
}
return result;
return PR_FALSE;
}
/**
@@ -566,7 +571,6 @@ CNavDTD::HandleToken(CToken* aToken, nsIParser* aParser)
}
eHTMLTags theParentTag = mBodyContext->Last();
theTag = (eHTMLTags)theToken->GetTypeID();
if (FindTagInSet(theTag, gLegalElements,
NS_ARRAY_LENGTH(gLegalElements)) ||
(gHTMLElements[theParentTag].CanContain(theTag, mDTDMode) &&
@@ -581,7 +585,11 @@ CNavDTD::HandleToken(CToken* aToken, nsIParser* aParser)
// noscript, etc). Script is special, though. Shipping it out
// breaks document.write stuff. See bug 243064.
(!gHTMLElements[theTag].HasSpecialProperty(kLegalOpen) ||
theTag == eHTMLTag_script))) {
theTag == eHTMLTag_script)) ||
(theTag == eHTMLTag_input && theType == eToken_start &&
FindTagInSet(theParentTag, gLegalElements,
NS_ARRAY_LENGTH(gLegalElements)) &&
IsHiddenInput(theToken, mTokenizer))) {
// Reset the state since all the misplaced tokens are about to get
// handled.
mFlags &= ~NS_DTD_FLAG_MISPLACED_CONTENT;
@@ -677,7 +685,9 @@ CNavDTD::HandleToken(CToken* aToken, nsIParser* aParser)
// end tag.
}
if (DoesRequireBody(aToken, mTokenizer)) {
if (gHTMLElements[theTag].HasSpecialProperty(kRequiresBody) &&
((theTag != eHTMLTag_input) ||
!IsHiddenInput(aToken, mTokenizer))) {
CToken* theBodyToken =
mTokenAllocator->CreateTokenOfType(eToken_start,
eHTMLTag_body,
@@ -875,9 +885,33 @@ CNavDTD::HandleDefaultStartToken(CToken* aToken, eHTMLTags aChildTag,
do {
eHTMLTags theParentTag = mBodyContext->TagAt(--theIndex);
// Figure out whether this is a hidden input inside a
// table/tbody/thead/tfoot/tr
static eHTMLTags sTableElements[] = {
eHTMLTag_table, eHTMLTag_thead, eHTMLTag_tbody,
eHTMLTag_tr, eHTMLTag_tfoot
};
PRBool isHiddenInputInsideTableElement = PR_FALSE;
if (aChildTag == eHTMLTag_input &&
FindTagInSet(theParentTag, sTableElements,
NS_ARRAY_LENGTH(sTableElements))) {
PRInt32 attrCount = aNode->GetAttributeCount();
for (PRInt32 attrIndex = 0; attrIndex < attrCount; ++attrIndex) {
const nsAString& key = aNode->GetKeyAt(attrIndex);
if (key.LowerCaseEqualsLiteral("type")) {
isHiddenInputInsideTableElement =
ValueIsHidden(aNode->GetValueAt(attrIndex));
break;
}
}
}
// Precompute containment, and pass it to CanOmit()...
theParentContains = CanContain(theParentTag, aChildTag);
if (CanOmit(theParentTag, aChildTag, theParentContains)) {
theParentContains =
isHiddenInputInsideTableElement || CanContain(theParentTag, aChildTag);
if (!isHiddenInputInsideTableElement &&
CanOmit(theParentTag, aChildTag, theParentContains)) {
HandleOmittedTag(aToken, aChildTag, theParentTag, aNode);
return NS_OK;
}