diff --git a/parser/html/java/htmlparser/src/nu/validator/htmlparser/impl/ElementName.java b/parser/html/java/htmlparser/src/nu/validator/htmlparser/impl/ElementName.java index 4b87d3fde2..4e5e482dae 100644 --- a/parser/html/java/htmlparser/src/nu/validator/htmlparser/impl/ElementName.java +++ b/parser/html/java/htmlparser/src/nu/validator/htmlparser/impl/ElementName.java @@ -2162,7 +2162,7 @@ public final class ElementName public static final ElementName SELECT = new ElementName("select", "select", // CPPONLY: NS_NewHTMLSelectElement, // CPPONLY: NS_NewSVGUnknownElement, - TreeBuilder.SELECT | SPECIAL); + TreeBuilder.SELECT | SPECIAL | SCOPING); public static final ElementName SCALARPRODUCT = new ElementName("scalarproduct", "scalarproduct", // CPPONLY: NS_NewHTMLUnknownElement, // CPPONLY: NS_NewSVGUnknownElement, diff --git a/parser/html/nsHtml5ElementName.cpp b/parser/html/nsHtml5ElementName.cpp index ecdfb102d4..4af8f7f289 100644 --- a/parser/html/nsHtml5ElementName.cpp +++ b/parser/html/nsHtml5ElementName.cpp @@ -866,7 +866,7 @@ nsHtml5ElementName::initializeStatics() ELT_RECT = new nsHtml5ElementName(nsHtml5Atoms::rect, nsHtml5Atoms::rect, NS_NewHTMLUnknownElement, NS_NewSVGRectElement, nsHtml5TreeBuilder::OTHER); ELT_RADIALGRADIENT = new nsHtml5ElementName(nsHtml5Atoms::radialgradient, nsHtml5Atoms::radialGradient, NS_NewHTMLUnknownElement, NS_NewSVGRadialGradientElement, nsHtml5TreeBuilder::OTHER); ELT_ROOT = new nsHtml5ElementName(nsHtml5Atoms::root, nsHtml5Atoms::root, NS_NewHTMLUnknownElement, NS_NewSVGUnknownElement, nsHtml5TreeBuilder::OTHER); - ELT_SELECT = new nsHtml5ElementName(nsHtml5Atoms::select, nsHtml5Atoms::select, NS_NewHTMLSelectElement, NS_NewSVGUnknownElement, nsHtml5TreeBuilder::SELECT | SPECIAL); + ELT_SELECT = new nsHtml5ElementName(nsHtml5Atoms::select, nsHtml5Atoms::select, NS_NewHTMLSelectElement, NS_NewSVGUnknownElement, nsHtml5TreeBuilder::SELECT | SPECIAL | SCOPING); ELT_SCALARPRODUCT = new nsHtml5ElementName(nsHtml5Atoms::scalarproduct, nsHtml5Atoms::scalarproduct, NS_NewHTMLUnknownElement, NS_NewSVGUnknownElement, nsHtml5TreeBuilder::OTHER); ELT_SUBSET = new nsHtml5ElementName(nsHtml5Atoms::subset, nsHtml5Atoms::subset, NS_NewHTMLUnknownElement, NS_NewSVGUnknownElement, nsHtml5TreeBuilder::OTHER); ELT_SLOT = new nsHtml5ElementName(nsHtml5Atoms::slot, nsHtml5Atoms::slot, NS_NewHTMLSlotElement, NS_NewSVGUnknownElement, nsHtml5TreeBuilder::OTHER); diff --git a/parser/html/nsHtml5TreeBuilder.cpp b/parser/html/nsHtml5TreeBuilder.cpp index 76a2398f52..e7f6b591af 100644 --- a/parser/html/nsHtml5TreeBuilder.cpp +++ b/parser/html/nsHtml5TreeBuilder.cpp @@ -1216,6 +1216,14 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu } case HR: { implicitlyCloseP(); + if (findLastInScope(nsHtml5Atoms::select) != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) { + generateImpliedEndTags(); + if (!!MOZ_UNLIKELY(mViewSource) && + (findLastInScope(nsHtml5Atoms::option) != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK || + findLastInScope(nsHtml5Atoms::optgroup) != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK)) { + errUnclosedElements(currentPtr, name); + } + } appendVoidElementToCurrentMayFoster(elementName, attributes); selfClosing = false; attributes = nullptr; @@ -1229,6 +1237,19 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu case IMG: case KEYGEN: case INPUT: { + if (fragment && nsHtml5Atoms::select == contextName) { + errStartTagWithSelectOpen(name); + NS_HTML5_BREAK(starttagloop); + } + eltPos = findLastInScope(nsHtml5Atoms::select); + if (eltPos != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) { + errStartTagWithSelectOpen(name); + while (currentPtr >= eltPos) { + pop(); + } + resetTheInsertionMode(); + NS_HTML5_CONTINUE(starttagloop); + } reconstructTheActiveFormattingElements(); appendVoidElementToCurrentMayFoster(elementName, attributes, formPointer); selfClosing = false; @@ -1313,33 +1334,54 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu NS_HTML5_BREAK(starttagloop); } case SELECT: { + if (fragment && nsHtml5Atoms::select == contextName) { + errStartSelectWhereEndSelectExpected(); + NS_HTML5_BREAK(starttagloop); + } + eltPos = findLastInScope(nsHtml5Atoms::select); + if (eltPos != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) { + errStartSelectWhereEndSelectExpected(); + while (currentPtr >= eltPos) { + pop(); + } + NS_HTML5_BREAK(starttagloop); + } reconstructTheActiveFormattingElements(); appendToCurrentNodeAndPushElementMayFoster(elementName, attributes, formPointer); - switch(mode) { - case IN_TABLE: - case IN_CAPTION: - case IN_COLUMN_GROUP: - case IN_TABLE_BODY: - case IN_ROW: - case IN_CELL: { - mode = IN_SELECT_IN_TABLE; - break; - } - default: { - mode = IN_SELECT; - break; - } - } + framesetOk = false; attributes = nullptr; NS_HTML5_BREAK(starttagloop); } - case OPTGROUP: case OPTION: { - if (isCurrent(nsHtml5Atoms::option)) { + if (findLastInScope(nsHtml5Atoms::select) != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) { + generateImpliedEndTagsExceptFor(nsHtml5Atoms::optgroup); + eltPos = findLastInScope(nsHtml5Atoms::option); + if (!!MOZ_UNLIKELY(mViewSource) && eltPos != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) { + errUnclosedElements(eltPos, name); + } + } else { + if (isCurrent(nsHtml5Atoms::option)) { + pop(); + } + } + reconstructTheActiveFormattingElements(); + appendToCurrentNodeAndPushElement(elementName, attributes); + attributes = nullptr; + NS_HTML5_BREAK(starttagloop); + } + case OPTGROUP: { + if (findLastInScope(nsHtml5Atoms::select) != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) { + generateImpliedEndTags(); + if (!!MOZ_UNLIKELY(mViewSource) && + (findLastInScope(nsHtml5Atoms::option) != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK || + findLastInScope(nsHtml5Atoms::optgroup) != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK)) { + errUnclosedElements(currentPtr, name); + } + } else if (isCurrent(nsHtml5Atoms::option)) { pop(); } reconstructTheActiveFormattingElements(); - appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); + appendToCurrentNodeAndPushElement(elementName, attributes); attributes = nullptr; NS_HTML5_BREAK(starttagloop); } @@ -2697,6 +2739,21 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName) case TEMPLATE: { break; } + case SELECT: { + eltPos = findLastInScope(name); + if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) { + errStrayEndTag(name); + } else { + generateImpliedEndTags(); + if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) { + errUnclosedElements(eltPos, name); + } + while (currentPtr >= eltPos) { + pop(); + } + } + NS_HTML5_BREAK(endtagloop); + } case AREA_OR_WBR: #ifdef ENABLE_VOID_MENUITEM case MENUITEM: @@ -2712,7 +2769,6 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName) case IFRAME: case NOEMBED: case NOFRAMES: - case SELECT: case TABLE: case TEXTAREA: { errStrayEndTag(name); @@ -3335,23 +3391,7 @@ nsHtml5TreeBuilder::resetTheInsertionMode() return; } } - if (nsHtml5Atoms::select == name) { - int32_t ancestorIndex = i; - while (ancestorIndex > 0) { - nsHtml5StackNode* ancestor = stack[ancestorIndex--]; - if (kNameSpaceID_XHTML == ancestor->ns) { - if (nsHtml5Atoms::template_ == ancestor->name) { - break; - } - if (nsHtml5Atoms::table == ancestor->name) { - mode = IN_SELECT_IN_TABLE; - return; - } - } - } - mode = IN_SELECT; - return; - } else if (nsHtml5Atoms::td == name || nsHtml5Atoms::th == name) { + if (nsHtml5Atoms::td == name || nsHtml5Atoms::th == name) { mode = IN_CELL; return; } else if (nsHtml5Atoms::tr == name) { diff --git a/parser/htmlparser/tests/mochitest/mochitest.ini b/parser/htmlparser/tests/mochitest/mochitest.ini index dcb30d6e80..0d089e9b02 100644 --- a/parser/htmlparser/tests/mochitest/mochitest.ini +++ b/parser/htmlparser/tests/mochitest/mochitest.ini @@ -147,3 +147,4 @@ skip-if = toolkit == 'android' #TIMED_OUT # Disable test due to frequent orange on Mac # test_bug534293.html [test_bug1209658.html] +[test_select_parser_relaxed.html] diff --git a/parser/htmlparser/tests/mochitest/test_select_parser_relaxed.html b/parser/htmlparser/tests/mochitest/test_select_parser_relaxed.html new file mode 100644 index 0000000000..d78947dc5b --- /dev/null +++ b/parser/htmlparser/tests/mochitest/test_select_parser_relaxed.html @@ -0,0 +1,54 @@ + + + +
+ ++ ++ +