зеркало из https://github.com/mozilla/gecko-dev.git
Bug 946585 - Change how the form element pointer affects parsing template elements. r=hsivonen
This commit is contained in:
Родитель
ce740641cb
Коммит
81d44a0834
|
@ -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>
|
||||
|
|
Загрузка…
Ссылка в новой задаче