зеркало из https://github.com/mozilla/gecko-dev.git
Bug 605466 - Implement new spec-based limits for formatting element proliferation in the HTML5 parsing algorithm. rs=jonas, a=blocking2.0-betaN.
--HG-- extra : rebase_source : b8d9c7fb5c4ef094af89ed9c29d49bd38d8fcca1
This commit is contained in:
Родитель
01fa16e8c5
Коммит
e00c8d1067
|
@ -464,6 +464,33 @@ public final class HtmlAttributes implements Attributes {
|
|||
return clone; // XXX!!!
|
||||
}
|
||||
|
||||
public boolean equalsAnother(HtmlAttributes other) {
|
||||
assert mode == 0 || mode == 3 : "Trying to compare attributes in foreign content.";
|
||||
int otherLength = other.getLength();
|
||||
if (length != otherLength) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < length; i++) {
|
||||
// Work around the limitations of C++
|
||||
boolean found = false;
|
||||
// The comparing just the local names is OK, since these attribute
|
||||
// holders are both supposed to belong to HTML formatting elements
|
||||
@Local String ownLocal = names[i].getLocal(AttributeName.HTML);
|
||||
for (int j = 0; j < otherLength; j++) {
|
||||
if (ownLocal == other.names[j].getLocal(AttributeName.HTML)) {
|
||||
found = true;
|
||||
if (!Portability.stringEqualsString(values[i], other.values[j])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// [NOCPP[
|
||||
|
||||
void processNonNcNames(TreeBuilder<?> treeBuilder, XmlViolationPolicy namePolicy) throws SAXException {
|
||||
|
|
|
@ -159,6 +159,10 @@ public final class Portability {
|
|||
return literal.equals(string);
|
||||
}
|
||||
|
||||
public static boolean stringEqualsString(String one, String other) {
|
||||
return one.equals(other);
|
||||
}
|
||||
|
||||
public static void delete(Object o) {
|
||||
|
||||
}
|
||||
|
|
|
@ -337,8 +337,6 @@ public abstract class TreeBuilder<T> implements TokenHandler,
|
|||
|
||||
private static final int NOT_FOUND_ON_STACK = Integer.MAX_VALUE;
|
||||
|
||||
private static final int AAA_MAX_ITERATIONS = 10;
|
||||
|
||||
// [NOCPP[
|
||||
|
||||
private static final @Local String HTML_LOCAL = "html";
|
||||
|
@ -1946,6 +1944,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
|
|||
case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
|
||||
case FONT:
|
||||
reconstructTheActiveFormattingElements();
|
||||
maybeForgetEarlierDuplicateFormattingElement(elementName.name, attributes);
|
||||
appendToCurrentNodeAndPushFormattingElementMayFoster(
|
||||
"http://www.w3.org/1999/xhtml",
|
||||
elementName, attributes);
|
||||
|
@ -3529,12 +3528,6 @@ public abstract class TreeBuilder<T> implements TokenHandler,
|
|||
}
|
||||
}
|
||||
break endtagloop;
|
||||
case A:
|
||||
case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
|
||||
case FONT:
|
||||
case NOBR:
|
||||
adoptionAgencyEndTag(name);
|
||||
break endtagloop;
|
||||
case OBJECT:
|
||||
case MARQUEE_OR_APPLET:
|
||||
eltPos = findLastInScope(name);
|
||||
|
@ -3593,6 +3586,14 @@ public abstract class TreeBuilder<T> implements TokenHandler,
|
|||
} else {
|
||||
// fall through
|
||||
}
|
||||
case A:
|
||||
case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
|
||||
case FONT:
|
||||
case NOBR:
|
||||
if (adoptionAgencyEndTag(name)) {
|
||||
break endtagloop;
|
||||
}
|
||||
// else handle like any other tag
|
||||
default:
|
||||
if (isCurrent(name)) {
|
||||
pop();
|
||||
|
@ -4326,10 +4327,10 @@ public abstract class TreeBuilder<T> implements TokenHandler,
|
|||
listPtr--;
|
||||
}
|
||||
|
||||
private void adoptionAgencyEndTag(@Local String name) throws SAXException {
|
||||
private boolean adoptionAgencyEndTag(@Local String name) throws SAXException {
|
||||
// If you crash around here, perhaps some stack node variable claimed to
|
||||
// be a weak ref isn't.
|
||||
for (int i = 0; i < AAA_MAX_ITERATIONS; ++i) {
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
int formattingEltListPos = listPtr;
|
||||
while (formattingEltListPos > -1) {
|
||||
StackNode<T> listNode = listOfActiveFormattingElements[formattingEltListPos]; // weak
|
||||
|
@ -4343,8 +4344,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
|
|||
formattingEltListPos--;
|
||||
}
|
||||
if (formattingEltListPos == -1) {
|
||||
err("No element \u201C" + name + "\u201D to close.");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
StackNode<T> formattingElt = listOfActiveFormattingElements[formattingEltListPos]; // this
|
||||
// *looks*
|
||||
|
@ -4372,11 +4372,11 @@ public abstract class TreeBuilder<T> implements TokenHandler,
|
|||
if (formattingEltStackPos == -1) {
|
||||
err("No element \u201C" + name + "\u201D to close.");
|
||||
removeFromListOfActiveFormattingElements(formattingEltListPos);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
if (!inScope) {
|
||||
err("No element \u201C" + name + "\u201D to close.");
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
// stackPos now points to the formatting element and it is in scope
|
||||
if (errorHandler != null && formattingEltStackPos != currentPtr) {
|
||||
|
@ -4396,7 +4396,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
|
|||
pop();
|
||||
}
|
||||
removeFromListOfActiveFormattingElements(formattingEltListPos);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
StackNode<T> commonAncestor = stack[formattingEltStackPos - 1]; // weak
|
||||
// ref
|
||||
|
@ -4405,7 +4405,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
|
|||
int bookmark = formattingEltListPos;
|
||||
int nodePos = furthestBlockPos;
|
||||
StackNode<T> lastNode = furthestBlock; // weak ref
|
||||
for (int j = 0; j < AAA_MAX_ITERATIONS; ++j) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
nodePos--;
|
||||
StackNode<T> node = stack[nodePos]; // weak ref
|
||||
int nodeListPos = findInListOfActiveFormattingElements(node);
|
||||
|
@ -4483,6 +4483,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
|
|||
insertIntoStack(formattingClone, furthestBlockPos);
|
||||
Portability.releaseElement(clone);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void insertIntoStack(StackNode<T> node, int position)
|
||||
|
@ -4534,6 +4535,26 @@ public abstract class TreeBuilder<T> implements TokenHandler,
|
|||
return -1;
|
||||
}
|
||||
|
||||
|
||||
private void maybeForgetEarlierDuplicateFormattingElement(
|
||||
@Local String name, HtmlAttributes attributes) throws SAXException {
|
||||
int candidate = -1;
|
||||
int count = 0;
|
||||
for (int i = listPtr; i >= 0; i--) {
|
||||
StackNode<T> node = listOfActiveFormattingElements[i];
|
||||
if (node == null) {
|
||||
break;
|
||||
}
|
||||
if (node.name == name && node.attributes.equalsAnother(attributes)) {
|
||||
candidate = i;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
if (count >= 3) {
|
||||
removeFromListOfActiveFormattingElements(candidate);
|
||||
}
|
||||
}
|
||||
|
||||
private int findLastOrRoot(@Local String name) {
|
||||
for (int i = currentPtr; i > 0; i--) {
|
||||
if (stack[i].name == name) {
|
||||
|
|
|
@ -235,6 +235,32 @@ nsHtml5HtmlAttributes::cloneAttributes(nsHtml5AtomTable* interner)
|
|||
return clone;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHtml5HtmlAttributes::equalsAnother(nsHtml5HtmlAttributes* other)
|
||||
{
|
||||
|
||||
PRInt32 otherLength = other->getLength();
|
||||
if (length != otherLength) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
for (PRInt32 i = 0; i < length; i++) {
|
||||
PRBool found = PR_FALSE;
|
||||
nsIAtom* ownLocal = names[i]->getLocal(NS_HTML5ATTRIBUTE_NAME_HTML);
|
||||
for (PRInt32 j = 0; j < otherLength; j++) {
|
||||
if (ownLocal == other->names[j]->getLocal(NS_HTML5ATTRIBUTE_NAME_HTML)) {
|
||||
found = PR_TRUE;
|
||||
if (!nsHtml5Portability::stringEqualsString(values[i], other->values[j])) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nsHtml5HtmlAttributes::initializeStatics()
|
||||
{
|
||||
|
|
|
@ -88,6 +88,7 @@ class nsHtml5HtmlAttributes
|
|||
void adjustForMath();
|
||||
void adjustForSvg();
|
||||
nsHtml5HtmlAttributes* cloneAttributes(nsHtml5AtomTable* interner);
|
||||
PRBool equalsAnother(nsHtml5HtmlAttributes* other);
|
||||
static void initializeStatics();
|
||||
static void releaseStatics();
|
||||
};
|
||||
|
|
|
@ -179,6 +179,12 @@ nsHtml5Portability::literalEqualsString(const char* literal, nsString* string)
|
|||
return string->EqualsASCII(literal);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHtml5Portability::stringEqualsString(nsString* one, nsString* other)
|
||||
{
|
||||
return one->Equals(*other);
|
||||
}
|
||||
|
||||
void
|
||||
nsHtml5Portability::initializeStatics()
|
||||
{
|
||||
|
|
|
@ -77,6 +77,7 @@ class nsHtml5Portability
|
|||
static PRBool lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(const char* lowerCaseLiteral, nsString* string);
|
||||
static PRBool lowerCaseLiteralEqualsIgnoreAsciiCaseString(const char* lowerCaseLiteral, nsString* string);
|
||||
static PRBool literalEqualsString(const char* literal, nsString* string);
|
||||
static PRBool stringEqualsString(nsString* one, nsString* other);
|
||||
static void initializeStatics();
|
||||
static void releaseStatics();
|
||||
};
|
||||
|
|
|
@ -1026,6 +1026,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
|
|||
case NS_HTML5TREE_BUILDER_B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
|
||||
case NS_HTML5TREE_BUILDER_FONT: {
|
||||
reconstructTheActiveFormattingElements();
|
||||
maybeForgetEarlierDuplicateFormattingElement(elementName->name, attributes);
|
||||
appendToCurrentNodeAndPushFormattingElementMayFoster(kNameSpaceID_XHTML, elementName, attributes);
|
||||
attributes = nsnull;
|
||||
NS_HTML5_BREAK(starttagloop);
|
||||
|
@ -2387,13 +2388,6 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
|
|||
}
|
||||
NS_HTML5_BREAK(endtagloop);
|
||||
}
|
||||
case NS_HTML5TREE_BUILDER_A:
|
||||
case NS_HTML5TREE_BUILDER_B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
|
||||
case NS_HTML5TREE_BUILDER_FONT:
|
||||
case NS_HTML5TREE_BUILDER_NOBR: {
|
||||
adoptionAgencyEndTag(name);
|
||||
NS_HTML5_BREAK(endtagloop);
|
||||
}
|
||||
case NS_HTML5TREE_BUILDER_OBJECT:
|
||||
case NS_HTML5TREE_BUILDER_MARQUEE_OR_APPLET: {
|
||||
eltPos = findLastInScope(name);
|
||||
|
@ -2444,6 +2438,14 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
|
|||
} else {
|
||||
}
|
||||
}
|
||||
case NS_HTML5TREE_BUILDER_A:
|
||||
case NS_HTML5TREE_BUILDER_B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
|
||||
case NS_HTML5TREE_BUILDER_FONT:
|
||||
case NS_HTML5TREE_BUILDER_NOBR: {
|
||||
if (adoptionAgencyEndTag(name)) {
|
||||
NS_HTML5_BREAK(endtagloop);
|
||||
}
|
||||
}
|
||||
default: {
|
||||
if (isCurrent(name)) {
|
||||
pop();
|
||||
|
@ -3172,10 +3174,10 @@ nsHtml5TreeBuilder::removeFromListOfActiveFormattingElements(PRInt32 pos)
|
|||
listPtr--;
|
||||
}
|
||||
|
||||
void
|
||||
PRBool
|
||||
nsHtml5TreeBuilder::adoptionAgencyEndTag(nsIAtom* name)
|
||||
{
|
||||
for (PRInt32 i = 0; i < NS_HTML5TREE_BUILDER_AAA_MAX_ITERATIONS; ++i) {
|
||||
for (PRInt32 i = 0; i < 8; ++i) {
|
||||
PRInt32 formattingEltListPos = listPtr;
|
||||
while (formattingEltListPos > -1) {
|
||||
nsHtml5StackNode* listNode = listOfActiveFormattingElements[formattingEltListPos];
|
||||
|
@ -3188,8 +3190,7 @@ nsHtml5TreeBuilder::adoptionAgencyEndTag(nsIAtom* name)
|
|||
formattingEltListPos--;
|
||||
}
|
||||
if (formattingEltListPos == -1) {
|
||||
|
||||
return;
|
||||
return PR_FALSE;
|
||||
}
|
||||
nsHtml5StackNode* formattingElt = listOfActiveFormattingElements[formattingEltListPos];
|
||||
PRInt32 formattingEltStackPos = currentPtr;
|
||||
|
@ -3206,11 +3207,11 @@ nsHtml5TreeBuilder::adoptionAgencyEndTag(nsIAtom* name)
|
|||
if (formattingEltStackPos == -1) {
|
||||
|
||||
removeFromListOfActiveFormattingElements(formattingEltListPos);
|
||||
return;
|
||||
return PR_TRUE;
|
||||
}
|
||||
if (!inScope) {
|
||||
|
||||
return;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRInt32 furthestBlockPos = formattingEltStackPos + 1;
|
||||
|
@ -3226,14 +3227,14 @@ nsHtml5TreeBuilder::adoptionAgencyEndTag(nsIAtom* name)
|
|||
pop();
|
||||
}
|
||||
removeFromListOfActiveFormattingElements(formattingEltListPos);
|
||||
return;
|
||||
return PR_TRUE;
|
||||
}
|
||||
nsHtml5StackNode* commonAncestor = stack[formattingEltStackPos - 1];
|
||||
nsHtml5StackNode* furthestBlock = stack[furthestBlockPos];
|
||||
PRInt32 bookmark = formattingEltListPos;
|
||||
PRInt32 nodePos = furthestBlockPos;
|
||||
nsHtml5StackNode* lastNode = furthestBlock;
|
||||
for (PRInt32 j = 0; j < NS_HTML5TREE_BUILDER_AAA_MAX_ITERATIONS; ++j) {
|
||||
for (PRInt32 j = 0; j < 3; ++j) {
|
||||
nodePos--;
|
||||
nsHtml5StackNode* node = stack[nodePos];
|
||||
PRInt32 nodeListPos = findInListOfActiveFormattingElements(node);
|
||||
|
@ -3287,6 +3288,7 @@ nsHtml5TreeBuilder::adoptionAgencyEndTag(nsIAtom* name)
|
|||
insertIntoStack(formattingClone, furthestBlockPos);
|
||||
;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -3340,6 +3342,26 @@ nsHtml5TreeBuilder::findInListOfActiveFormattingElementsContainsBetweenEndAndLas
|
|||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
nsHtml5TreeBuilder::maybeForgetEarlierDuplicateFormattingElement(nsIAtom* name, nsHtml5HtmlAttributes* attributes)
|
||||
{
|
||||
PRInt32 candidate = -1;
|
||||
PRInt32 count = 0;
|
||||
for (PRInt32 i = listPtr; i >= 0; i--) {
|
||||
nsHtml5StackNode* node = listOfActiveFormattingElements[i];
|
||||
if (!node) {
|
||||
break;
|
||||
}
|
||||
if (node->name == name && node->attributes->equalsAnother(attributes)) {
|
||||
candidate = i;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
if (count >= 3) {
|
||||
removeFromListOfActiveFormattingElements(candidate);
|
||||
}
|
||||
}
|
||||
|
||||
PRInt32
|
||||
nsHtml5TreeBuilder::findLastOrRoot(nsIAtom* name)
|
||||
{
|
||||
|
|
|
@ -152,11 +152,12 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState
|
|||
void removeFromStack(PRInt32 pos);
|
||||
void removeFromStack(nsHtml5StackNode* node);
|
||||
void removeFromListOfActiveFormattingElements(PRInt32 pos);
|
||||
void adoptionAgencyEndTag(nsIAtom* name);
|
||||
PRBool adoptionAgencyEndTag(nsIAtom* name);
|
||||
void insertIntoStack(nsHtml5StackNode* node, PRInt32 position);
|
||||
void insertIntoListOfActiveFormattingElements(nsHtml5StackNode* formattingClone, PRInt32 bookmark);
|
||||
PRInt32 findInListOfActiveFormattingElements(nsHtml5StackNode* node);
|
||||
PRInt32 findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker(nsIAtom* name);
|
||||
void maybeForgetEarlierDuplicateFormattingElement(nsIAtom* name, nsHtml5HtmlAttributes* attributes);
|
||||
PRInt32 findLastOrRoot(nsIAtom* name);
|
||||
PRInt32 findLastOrRoot(PRInt32 group);
|
||||
PRBool addAttributesToBody(nsHtml5HtmlAttributes* attributes);
|
||||
|
@ -345,7 +346,6 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState
|
|||
#define NS_HTML5TREE_BUILDER_CHARSET_DOUBLE_QUOTED 10
|
||||
#define NS_HTML5TREE_BUILDER_CHARSET_UNQUOTED 11
|
||||
#define NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK PR_INT32_MAX
|
||||
#define NS_HTML5TREE_BUILDER_AAA_MAX_ITERATIONS 10
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,4 +7,5 @@
|
|||
var html5Exceptions = {
|
||||
"<!doctype html><keygen><frameset>" : true, // Bug 101019
|
||||
"<select><keygen>" : true, // Bug 101019
|
||||
"<math><mi><div><object><div><span></span></div></object></div></mi><mi>" : true, // Bug 606925
|
||||
}
|
||||
|
|
|
@ -853,11 +853,50 @@ Line: 1 Col: 50 Expected closing tag. Unexpected end of file.
|
|||
| <i>
|
||||
| <i>
|
||||
| <i>
|
||||
| <i>
|
||||
| <div>
|
||||
| <b>
|
||||
| <div>
|
||||
| <b>
|
||||
| "X"
|
||||
| "TEST"
|
||||
|
||||
#data
|
||||
<p><font size=4><font color=red><font size=4><font size=4><font size=4><font size=4><font size=4><font color=red><p>X
|
||||
#errors
|
||||
3: Start tag seen without seeing a doctype first. Expected “<!DOCTYPE html>”.
|
||||
116: Unclosed elements.
|
||||
117: End of file seen and there were open elements.
|
||||
#document
|
||||
| <html>
|
||||
| <head>
|
||||
| <body>
|
||||
| <p>
|
||||
| <font>
|
||||
| size="4"
|
||||
| <font>
|
||||
| color="red"
|
||||
| <font>
|
||||
| size="4"
|
||||
| <font>
|
||||
| size="4"
|
||||
| <font>
|
||||
| size="4"
|
||||
| <font>
|
||||
| size="4"
|
||||
| <font>
|
||||
| size="4"
|
||||
| <font>
|
||||
| color="red"
|
||||
| <p>
|
||||
| <font>
|
||||
| color="red"
|
||||
| <font>
|
||||
| size="4"
|
||||
| <font>
|
||||
| size="4"
|
||||
| <font>
|
||||
| size="4"
|
||||
| <font>
|
||||
| color="red"
|
||||
| "X"
|
||||
| "TEST"
|
||||
|
||||
#data
|
||||
|
||||
|
|
|
@ -573,7 +573,7 @@
|
|||
| <object>
|
||||
| <div>
|
||||
| <span>
|
||||
| <mi>
|
||||
| <math mi>
|
||||
|
||||
#data
|
||||
<math><mi><svg><foreignObject><div><div></div></div></foreignObject></svg></mi><mi>
|
||||
|
|
Загрузка…
Ссылка в новой задаче