Bug 946585 - Change how the form element pointer affects parsing template elements. r=hsivonen

This commit is contained in:
William Chen 2014-01-31 15:03:24 -08:00
Родитель ce740641cb
Коммит 81d44a0834
8 изменённых файлов: 244 добавлений и 36 удалений

Просмотреть файл

@ -430,3 +430,4 @@ support-files =
[test_video_wakelock.html]
[test_input_files_not_nsIFile.html]
[test_ignoreuserfocus.html]
[test_fragment_form_pointer.html]

Просмотреть файл

@ -0,0 +1,27 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=946585
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 946585</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=946585">Mozilla Bug 946585</a>
<p id="display"></p>
<div id="content" style="display: none">
<form><div id="formdiv"></div></form>
</div>
<pre id="test">
</pre>
<script type="application/javascript">
/** Test for Bug 946585 **/
var formDiv = document.getElementById("formdiv");
formDiv.innerHTML = '<form>';
is(formDiv.firstChild, null, "InnerHTML should not produce form element because the div has a form pointer.");
</script>
</body>
</html>

Просмотреть файл

@ -620,6 +620,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
pushTemplateMode(IN_TEMPLATE);
}
resetTheInsertionMode();
formPointer = getFormPointerForContext(contextNode);
if ("title" == contextName || "textarea" == contextName) {
tokenizer.setStateAndEndTagExpectation(Tokenizer.RCDATA, contextName);
} else if ("style" == contextName || "xmp" == contextName
@ -1892,7 +1893,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
attributes = null; // CPP
break starttagloop;
case FORM:
if (formPointer != null) {
if (formPointer != null || isTemplateContents()) {
errFormWhenFormOpen();
break starttagloop;
} else {
@ -2078,7 +2079,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
attributes = null; // CPP
break starttagloop;
case FORM:
if (formPointer != null) {
if (formPointer != null && !isTemplateContents()) {
errFormWhenFormOpen();
break starttagloop;
} else {
@ -2255,7 +2256,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
break starttagloop;
case ISINDEX:
errIsindex();
if (formPointer != null) {
if (formPointer != null && !isTemplateContents()) {
break starttagloop;
}
implicitlyCloseP();
@ -2319,6 +2320,11 @@ public abstract class TreeBuilder<T> implements TokenHandler,
ElementName.HR,
HtmlAttributes.EMPTY_ATTRIBUTES);
pop(); // form
if (!isTemplateContents()) {
formPointer = null;
}
selfClosing = false;
// Portability.delete(formAttrs);
// Portability.delete(inputAttributes);
@ -3574,22 +3580,38 @@ public abstract class TreeBuilder<T> implements TokenHandler,
}
break endtagloop;
case FORM:
if (formPointer == null) {
errStrayEndTag(name);
if (!isTemplateContents()) {
if (formPointer == null) {
errStrayEndTag(name);
break endtagloop;
}
formPointer = null;
eltPos = findLastInScope(name);
if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
errStrayEndTag(name);
break endtagloop;
}
generateImpliedEndTags();
if (errorHandler != null && !isCurrent(name)) {
errUnclosedElements(eltPos, name);
}
removeFromStack(eltPos);
break endtagloop;
} else {
eltPos = findLastInScope(name);
if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
errStrayEndTag(name);
break endtagloop;
}
generateImpliedEndTags();
if (errorHandler != null && !isCurrent(name)) {
errUnclosedElements(eltPos, name);
}
while (currentPtr >= eltPos) {
pop();
}
break endtagloop;
}
formPointer = null;
eltPos = findLastInScope(name);
if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
errStrayEndTag(name);
break endtagloop;
}
generateImpliedEndTags();
if (errorHandler != null && !isCurrent(name)) {
errUnclosedElements(eltPos, name);
}
removeFromStack(eltPos);
break endtagloop;
case P:
eltPos = findLastInButtonScope("p");
if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
@ -5078,7 +5100,11 @@ public abstract class TreeBuilder<T> implements TokenHandler,
// ]NOCPP]
T elt = createElement("http://www.w3.org/1999/xhtml", "form",
attributes);
formPointer = elt;
if (!isTemplateContents()) {
formPointer = elt;
}
StackNode<T> current = stack[currentPtr];
if (current.isFosterParenting()) {
fatal();
@ -5203,6 +5229,10 @@ public abstract class TreeBuilder<T> implements TokenHandler,
T getDocumentFragmentForTemplate(T template) {
return template;
}
T getFormPointerForContext(T context) {
return null;
}
// ]NOCPP]
private boolean annotationXmlEncodingPermitsHtml(HtmlAttributes attributes) {

Просмотреть файл

@ -102,6 +102,7 @@ nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self)
pushTemplateMode(NS_HTML5TREE_BUILDER_IN_TEMPLATE);
}
resetTheInsertionMode();
formPointer = getFormPointerForContext(contextNode);
if (nsHtml5Atoms::title == contextName || nsHtml5Atoms::textarea == contextName) {
tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RCDATA, contextName);
} else if (nsHtml5Atoms::style == contextName || nsHtml5Atoms::xmp == contextName || nsHtml5Atoms::iframe == contextName || nsHtml5Atoms::noembed == contextName || nsHtml5Atoms::noframes == contextName || (scriptingEnabled && nsHtml5Atoms::noscript == contextName)) {
@ -868,7 +869,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
NS_HTML5_BREAK(starttagloop);
}
case NS_HTML5TREE_BUILDER_FORM: {
if (formPointer) {
if (!!formPointer || isTemplateContents()) {
errFormWhenFormOpen();
NS_HTML5_BREAK(starttagloop);
} else {
@ -1055,7 +1056,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
NS_HTML5_BREAK(starttagloop);
}
case NS_HTML5TREE_BUILDER_FORM: {
if (formPointer) {
if (!!formPointer && !isTemplateContents()) {
errFormWhenFormOpen();
NS_HTML5_BREAK(starttagloop);
} else {
@ -1213,7 +1214,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
}
case NS_HTML5TREE_BUILDER_ISINDEX: {
errIsindex();
if (formPointer) {
if (!!formPointer && !isTemplateContents()) {
NS_HTML5_BREAK(starttagloop);
}
implicitlyCloseP();
@ -1247,6 +1248,9 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
pop();
appendVoidElementToCurrentMayFoster(nsHtml5ElementName::ELT_HR, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
pop();
if (!isTemplateContents()) {
formPointer = nullptr;
}
selfClosing = false;
NS_HTML5_BREAK(starttagloop);
}
@ -2508,22 +2512,38 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
NS_HTML5_BREAK(endtagloop);
}
case NS_HTML5TREE_BUILDER_FORM: {
if (!formPointer) {
errStrayEndTag(name);
if (!isTemplateContents()) {
if (!formPointer) {
errStrayEndTag(name);
NS_HTML5_BREAK(endtagloop);
}
formPointer = nullptr;
eltPos = findLastInScope(name);
if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
errStrayEndTag(name);
NS_HTML5_BREAK(endtagloop);
}
generateImpliedEndTags();
if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
errUnclosedElements(eltPos, name);
}
removeFromStack(eltPos);
NS_HTML5_BREAK(endtagloop);
} else {
eltPos = findLastInScope(name);
if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
errStrayEndTag(name);
NS_HTML5_BREAK(endtagloop);
}
generateImpliedEndTags();
if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
errUnclosedElements(eltPos, name);
}
while (currentPtr >= eltPos) {
pop();
}
NS_HTML5_BREAK(endtagloop);
}
formPointer = nullptr;
eltPos = findLastInScope(name);
if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) {
errStrayEndTag(name);
NS_HTML5_BREAK(endtagloop);
}
generateImpliedEndTags();
if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
errUnclosedElements(eltPos, name);
}
removeFromStack(eltPos);
NS_HTML5_BREAK(endtagloop);
}
case NS_HTML5TREE_BUILDER_P: {
eltPos = findLastInButtonScope(nsHtml5Atoms::p);
@ -3855,7 +3875,9 @@ void
nsHtml5TreeBuilder::appendToCurrentNodeAndPushFormElementMayFoster(nsHtml5HtmlAttributes* attributes)
{
nsIContent** elt = createElement(kNameSpaceID_XHTML, nsHtml5Atoms::form, attributes);
formPointer = elt;
if (!isTemplateContents()) {
formPointer = elt;
}
nsHtml5StackNode* current = stack[currentPtr];
if (current->isFosterParenting()) {

Просмотреть файл

@ -761,6 +761,40 @@ nsHtml5TreeBuilder::getDocumentFragmentForTemplate(nsIContent** aTemplate)
return fragHandle;
}
nsIContent**
nsHtml5TreeBuilder::getFormPointerForContext(nsIContent** aContext)
{
if (!aContext) {
return nullptr;
}
MOZ_ASSERT(NS_IsMainThread());
// aContext must always be a handle to an element that already exists
// in the document. It must never be an empty handle.
nsIContent* contextNode = *aContext;
nsIContent* currentAncestor = contextNode;
// We traverse the ancestors of the context node to find the nearest
// form pointer. This traversal is why aContext must not be an emtpy handle.
nsIContent* nearestForm = nullptr;
while (currentAncestor) {
if (currentAncestor->IsHTML(nsGkAtoms::form)) {
nearestForm = currentAncestor;
break;
}
currentAncestor = currentAncestor->GetParent();
}
if (!nearestForm) {
return nullptr;
}
nsIContent** formPointer = AllocateContentHandle();
*formPointer = nearestForm;
return formPointer;
}
// Error reporting
void

Просмотреть файл

@ -28,6 +28,8 @@
nsIContent** getDocumentFragmentForTemplate(nsIContent** aTemplate);
nsIContent** getFormPointerForContext(nsIContent** aContext);
/**
* Using nsIContent** instead of nsIContent* is the parser deals with DOM
* nodes in a way that works off the main thread. Non-main-thread code

Просмотреть файл

@ -45,3 +45,23 @@
| <head>
| <body>
| <form>
#data
<body><isindex><form>
#errors
6: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
15: “isindex” seen.
21: End of file seen and there were open elements.
21: Unclosed element “form”.
#document
| <html>
| <head>
| <body>
| <form>
| <hr>
| <label>
| "This is a searchable index. Enter search keywords: "
| <input>
| name="isindex"
| <hr>
| <form>

Просмотреть файл

@ -1344,3 +1344,75 @@
| content
| "Foo"
| <body>
#data
<body><form><template><form>
#errors
#document
| <html>
| <head>
| <body>
| <form>
| <template>
| content
| <form>
#data
<body><template><table><form>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <table>
#data
<body><template><form><form>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <form>
| <form>
#data
<body><form><template><isindex>
#errors
#document
| <html>
| <head>
| <body>
| <form>
| <template>
| content
| <form>
| <hr>
| <label>
| "This is a searchable index. Enter search keywords: "
| <input>
| name="isindex"
| <hr>
#data
<body><form><template><isindex><form>
#errors
#document
| <html>
| <head>
| <body>
| <form>
| <template>
| content
| <form>
| <hr>
| <label>
| "This is a searchable index. Enter search keywords: "
| <input>
| name="isindex"
| <hr>
| <form>