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;
}

View File

@@ -873,7 +873,7 @@ nsHTMLTokenizer::ConsumeStartTag(PRUnichar aChar,
// If you're here, it's because we were in the midst of consuming a start
// tag but ran out of data (not in the stream, but in this *part* of the
// stream. For simplicity, we have to unwind our input. Therefore, we pop
// and discard any new tokens we've cued this round. Later we can get
// and discard any new tokens we've queued this round. Later we can get
// smarter about this.
if (NS_FAILED(result)) {
while (mTokenDeque.GetSize()>theDequeSize) {

View File

@@ -74,3 +74,310 @@ Expected closing tag after </.
| <style>
| "
x { content:"</style" } "
#data
<!DOCTYPE html><body><table><tr><td></td><input><td></td></tr></table></body>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <body>
| <input>
| <table>
| <tbody>
| <tr>
| <td>
| <td>
#data
<!DOCTYPE html><body><table><tr><td></td><input type="hidden"><td></td></tr></table></body>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <body>
| <table>
| <tbody>
| <tr>
| <td>
| <input>
| type="hidden"
| <td>
#data
<!DOCTYPE html><body><table><tr><td></td><input tYPe=" hiDDen "><td></td></tr></table></body>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <body>
| <table>
| <tbody>
| <tr>
| <td>
| <input>
| type="hidden"
| <td>
#data
<!DOCTYPE html><body><table><tr><td></td><input tYPe=" hiDDen "><td></td></tr></table></body>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <body>
| <input>
| type=" hiDDen "
| <table>
| <tbody>
| <tr>
| <td>
| <td>
#data
<!DOCTYPE html><body><table><tr><td></td><input type="text" type="hidden"><td></td></tr></table></body>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <body>
| <input>
| type="text"
| <table>
| <tbody>
| <tr>
| <td>
| <td>
#data
<!DOCTYPE html><body><table><tr><td></td><input type="hidden" type="text"><td></td></tr></table></body>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <body>
| <table>
| <tbody>
| <tr>
| <td>
| <input>
| type="hidden"
| <td>
#data
<!DOCTYPE html><body><table><tr><td></td><input id="one"><input type="hidden"><input id="two"><td></td></tr></table></body>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <body>
| <input>
| id="one"
| <input>
| id="two"
| <table>
| <tbody>
| <tr>
| <td>
| <input>
| type="hidden"
| <td>
#data
<!DOCTYPE html><body><table><tr><td></td><input id="one" type="hidden"><input id="two"><input id="three" type="hidden"><td></td></tr></table></body>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <body>
| <input>
| id="two"
| <table>
| <tbody>
| <tr>
| <td>
| <input>
| type="hidden"
| id="one"
| <input>
| type="hidden"
| id="three"
| <td>
#data
<!DOCTYPE html><body><table><input><tr><td></td><td></td></tr></table></body>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <body>
| <input>
| <table>
| <tbody>
| <tr>
| <td>
| <td>
#data
<!DOCTYPE html><body><table><input type="hidden"><tr><td></td><td></td></tr></table></body>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <body>
| <table>
| <input>
| type="hidden"
| <tbody>
| <tr>
| <td>
| <td>
#data
<!DOCTYPE html><body><table><tbody><input><tr><td></td><td></td></tr></tbody></table></body>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <body>
| <input>
| <table>
| <tbody>
| <tr>
| <td>
| <td>
#data
<!DOCTYPE html><body><table><tbody><input type="hidden"><tr><td></td><td></td></tr></tbody></table></body>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <body>
| <table>
| <tbody>
| <input>
| type="hidden"
| <tr>
| <td>
| <td>
#data
<!DOCTYPE html><body><table><thead><input><tr><td></td><td></td></tr></thead></table></body>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <body>
| <input>
| <table>
| <thead>
| <tr>
| <td>
| <td>
#data
<!DOCTYPE html><body><table><thead><input type="hidden"><tr><td></td><td></td></tr></thead></table></body>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <body>
| <table>
| <thead>
| <input>
| type="hidden"
| <tr>
| <td>
| <td>
#data
<!DOCTYPE html><body><table><tfoot><input><tr><td></td><td></td></tr></tfoot></table></body>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <body>
| <input>
| <table>
| <tfoot>
| <tr>
| <td>
| <td>
#data
<!DOCTYPE html><body><table><tfoot><input type="hidden"><tr><td></td><td></td></tr></tfoot></table></body>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <body>
| <table>
| <tfoot>
| <input>
| type="hidden"
| <tr>
| <td>
| <td>
#data
<!DOCTYPE html><html><head></head><form><input></form><frameset rows="*"><frame></frameset></html>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <body>
| <form>
| <input>
#data
<!DOCTYPE html><html><head></head><form><input type="hidden"></form><frameset rows="*"><frame></frameset></html>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <frameset>
| rows="*"
| <frame>
#data
<!DOCTYPE html><html><head></head><form><input tYpE=" HIdDen "></form><frameset rows="*"><frame></frameset></html>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <frameset>
| rows="*"
| <frame>
#data
<!DOCTYPE html><html><head></head><form><input type=" hidden"></form><frameset rows="*"><frame></frameset></html>
#errors
#document
| <!DOCTYPE HTML>
| <html>
| <head>
| <body>
| <form>
| <input>
| type=" hidden"