From 607d0f5160980136f99d2e3e85f06781e4e869ce Mon Sep 17 00:00:00 2001 From: "bzbarsky%mit.edu" Date: Mon, 3 Dec 2007 02:29:49 +0000 Subject: [PATCH] Fix bug 390565. r+sr=mrbkap git-svn-id: svn://10.0.0.236/trunk@240269 18797224-902f-48f8-a5cc-f745e15eee43 --- .../html/content/test/test_bug353415-2.html | 2 +- mozilla/parser/htmlparser/src/CNavDTD.cpp | 116 ++++--- .../parser/htmlparser/src/nsHTMLTokenizer.cpp | 2 +- .../tests/mochitest/regressions.txt | 307 ++++++++++++++++++ 4 files changed, 384 insertions(+), 43 deletions(-) diff --git a/mozilla/content/html/content/test/test_bug353415-2.html b/mozilla/content/html/content/test/test_bug353415-2.html index f41342afe63..78817cf52be 100644 --- a/mozilla/content/html/content/test/test_bug353415-2.html +++ b/mozilla/content/html/content/test/test_bug353415-2.html @@ -57,7 +57,7 @@ SimpleTest.waitForExplicitFinish(); function doCheck(){ - is(frames['submit_frame'].location.href, "http://localhost:8888/blah?field1-2=teststring&field2-2=0&field4-2=1&field6-2=3&field7-2=2&field8-2=8&field9-2=9&field12-2=&field14-2=14&field1=teststring&field2=0&field4=1&field6=3&field7=2&field8=8&field9=9&field12=&field14=14", "Submit string was correct."); + is(frames['submit_frame'].location.href, "http://localhost:8888/blah?field1-2=teststring&field2-2=0&field4-2=1&field6-2=3&field7-2=2&field8-2=8&field9-2=9&field12-2=&field1=teststring&field2=0&field4=1&field6=3&field7=2&field8=8&field9=9&field12=&field14=14&field14-2=14", "Submit string was correct."); SimpleTest.finish(); } diff --git a/mozilla/parser/htmlparser/src/CNavDTD.cpp b/mozilla/parser/htmlparser/src/CNavDTD.cpp index 9aa35c5bd0e..ecda0ae4178 100644 --- a/mozilla/parser/htmlparser/src/CNavDTD.cpp +++ b/mozilla/parser/htmlparser/src/CNavDTD.cpp @@ -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 - (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 tag. The token +// must be a start tag token for an . 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 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(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; } diff --git a/mozilla/parser/htmlparser/src/nsHTMLTokenizer.cpp b/mozilla/parser/htmlparser/src/nsHTMLTokenizer.cpp index 3147c149ddc..e458d88f141 100644 --- a/mozilla/parser/htmlparser/src/nsHTMLTokenizer.cpp +++ b/mozilla/parser/htmlparser/src/nsHTMLTokenizer.cpp @@ -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) { diff --git a/mozilla/parser/htmlparser/tests/mochitest/regressions.txt b/mozilla/parser/htmlparser/tests/mochitest/regressions.txt index 93ce44f7f36..bc1ff381a35 100644 --- a/mozilla/parser/htmlparser/tests/mochitest/regressions.txt +++ b/mozilla/parser/htmlparser/tests/mochitest/regressions.txt @@ -74,3 +74,310 @@ Expected closing tag after | " x { content:"
+#errors +#document +| +| +| +| +| +| +| +| +|
+| + +#data +
+#errors +#document +| +| +| +| +| +| +| +|
+| +| type="hidden" +| + +#data +
+#errors +#document +| +| +| +| +| +| +| +|
+| +| type="hidden" +| + +#data +
+#errors +#document +| +| +| +| +| +| type=" hiDDen " +| +| +| +|
+| + +#data +
+#errors +#document +| +| +| +| +| +| type="text" +| +| +| +|
+| + +#data +
+#errors +#document +| +| +| +| +| +| +| +|
+| +| type="hidden" +| + +#data +
+#errors +#document +| +| +| +| +| +| id="one" +| +| id="two" +| +| +| +|
+| +| type="hidden" +| + +#data +
+#errors +#document +| +| +| +| +| +| id="two" +| +| +| +|
+| +| type="hidden" +| id="one" +| +| type="hidden" +| id="three" +| + +#data +
+#errors +#document +| +| +| +| +| +| +| +| +|
+| + +#data +
+#errors +#document +| +| +| +| +| +| +| type="hidden" +| +| +|
+| + +#data +
+#errors +#document +| +| +| +| +| +| +| +| +|
+| + +#data +
+#errors +#document +| +| +| +| +| +| +| +| type="hidden" +| +|
+| + +#data +
+#errors +#document +| +| +| +| +| +| +| +| +|
+| + +#data +
+#errors +#document +| +| +| +| +| +| +| +| type="hidden" +| +|
+| + +#data +
+#errors +#document +| +| +| +| +| +| +| +| +|
+| + +#data +
+#errors +#document +| +| +| +| +| +| +| +| type="hidden" +| +|
+| + +#data +
+#errors +#document +| +| +| +| +|
+| + +#data +
+#errors +#document +| +| +| +| +| rows="*" +| + +#data +
+#errors +#document +| +| +| +| +| rows="*" +| + +#data +
+#errors +#document +| +| +| +| +|
+| +| type=" hidden" +