/* * Copyright (c) 2007 Henri Sivonen * Copyright (c) 2007-2017 Mozilla Foundation * Portions of comments Copyright 2004-2008 Apple Computer, Inc., Mozilla * Foundation, and Opera Software ASA. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE.
*/
@Literal privatefinalstatic String[] QUIRKY_PUBLIC_IDS = { "+//silmaril//dtd html pro v0r11 19970101//", "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", "-//as//dtd html 3.0 aswedit + extensions//", "-//ietf//dtd html 2.0 level 1//", "-//ietf//dtd html 2.0 level 2//", "-//ietf//dtd html 2.0 strict level 1//", "-//ietf//dtd html 2.0 strict level 2//", "-//ietf//dtd html 2.0 strict//", "-//ietf//dtd html 2.0//", "-//ietf//dtd html 2.1e//", "-//ietf//dtd html 3.0//", "-//ietf//dtd html 3.2 final//", "-//ietf//dtd html 3.2//", "-//ietf//dtd html 3//", "-//ietf//dtd html level 0//", "-//ietf//dtd html level 1//", "-//ietf//dtd html level 2//", "-//ietf//dtd html level 3//", "-//ietf//dtd html strict level 0//", "-//ietf//dtd html strict level 1//", "-//ietf//dtd html strict level 2//", "-//ietf//dtd html strict level 3//", "-//ietf//dtd html strict//", "-//ietf//dtd html//", "-//metrius//dtd metrius presentational//", "-//microsoft//dtd internet explorer 2.0 html strict//", "-//microsoft//dtd internet explorer 2.0 html//", "-//microsoft//dtd internet explorer 2.0 tables//", "-//microsoft//dtd internet explorer 3.0 html strict//", "-//microsoft//dtd internet explorer 3.0 html//", "-//microsoft//dtd internet explorer 3.0 tables//", "-//netscape comm. corp.//dtd html//", "-//netscape comm. corp.//dtd strict html//", "-//o'reilly and associates//dtd html 2.0//", "-//o'reilly and associates//dtd html extended 1.0//", "-//o'reilly and associates//dtd html extended relaxed 1.0//", "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//", "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//", "-//spyglass//dtd html 2.0 extended//", "-//sq//dtd html 2.0 hotmetal + extensions//", "-//sun microsystems corp.//dtd hotjava html//", "-//sun microsystems corp.//dtd hotjava strict html//", "-//w3c//dtd html 3 1995-03-24//", "-//w3c//dtd html 3.2 draft//", "-//w3c//dtd html 3.2 final//", "-//w3c//dtd html 3.2//", "-//w3c//dtd html 3.2s draft//", "-//w3c//dtd html 4.0 frameset//", "-//w3c//dtd html 4.0 transitional//", "-//w3c//dtd html experimental 19960712//", "-//w3c//dtd html experimental 970421//", "-//w3c//dtd w3 html//", "-//w3o//dtd w3 html 3.0//", "-//webtechs//dtd mozilla html 2.0//", "-//webtechs//dtd mozilla html//" };
privatefinal Map<String, LocatorImpl> idLocations = new HashMap<String, LocatorImpl>();
// ]NOCPP]
protected TreeBuilder() {
fragment = false;
}
/** * Reports an condition that would make the infoset incompatible with XML * 1.0 as fatal. * * @throws SAXException * @throws SAXParseException
*/ protectedvoid fatal() throws SAXException {
}
@SuppressWarnings("unchecked") publicfinalvoid startTokenization(Tokenizer self) throws SAXException {
tokenizer = self;
stackNodes = new StackNode[64];
stack = new StackNode[64];
templateModeStack = newint[64];
listOfActiveFormattingElements = new StackNode[64];
needToDropLF = false;
originalMode = INITIAL;
templateModePtr = -1;
stackNodesIdx = 0;
numStackNodes = 0;
currentPtr = -1;
listPtr = -1;
formPointer = null;
headPointer = null; // [NOCPP[
idLocations.clear();
wantingComments = wantsComments(); // ]NOCPP]
start(fragment);
charBufferLen = 0; if (!keepBuffer) {
charBuffer = null;
}
framesetOk = true; if (fragment) {
T elt; if (contextNode != null) {
elt = contextNode;
} else {
elt = createHtmlElementSetAsRoot(tokenizer.emptyAttributes());
} // When the context node is not in the HTML namespace, contrary // to the spec, the first node on the stack is not set to "html" // in the HTML namespace. Instead, it is set to a node that has // the characteristics of the appropriate "adjusted current node". // This way, there is no need to perform "adjusted current node" // checks during tree construction. Instead, it's sufficient to // just look at the current node. However, this also means that it // is not safe to treat "html" in the HTML namespace as a sentinel // that ends stack popping. Instead, stack popping loops that are // meant not to pop the first element on the stack need to check // for currentPos becoming zero. if (contextNamespace == "http://www.w3.org/2000/svg") {
ElementName elementName = ElementName.SVG; if ("title" == contextName || "desc" == contextName
|| "foreignObject" == contextName) { // These elements are all alike and we don't care about // the exact name.
elementName = ElementName.FOREIGNOBJECT;
} // This is the SVG variant of the StackNode constructor.
StackNode<T> node = createStackNode(elementName,
elementName.getCamelCaseName(), elt // [NOCPP[
, errorHandler == null ? null
: new TaintableLocatorImpl(tokenizer) // ]NOCPP]
);
currentPtr++;
stack[currentPtr] = node;
tokenizer.setState(Tokenizer.DATA); // The frameset-ok flag is set even though <frameset> never // ends up being allowed as HTML frameset in the fragment case.
mode = FRAMESET_OK;
} elseif (contextNamespace == "http://www.w3.org/1998/Math/MathML") {
ElementName elementName = ElementName.MATH; if ("mi" == contextName || "mo" == contextName
|| "mn" == contextName || "ms" == contextName
|| "mtext" == contextName) { // These elements are all alike and we don't care about // the exact name.
elementName = ElementName.MTEXT;
} elseif ("annotation-xml" == contextName) {
elementName = ElementName.ANNOTATION_XML; // Blink does not check the encoding attribute of the // annotation-xml element innerHTML is being set on. // Let's do the same at least until // https://www.w3.org/Bugs/Public/show_bug.cgi?id=26783 // is resolved.
} // This is the MathML variant of the StackNode constructor.
StackNode<T> node = createStackNode(elementName, elt,
elementName.getName(), false // [NOCPP[
, errorHandler == null ? null
: new TaintableLocatorImpl(tokenizer) // ]NOCPP]
);
currentPtr++;
stack[currentPtr] = node;
tokenizer.setState(Tokenizer.DATA); // The frameset-ok flag is set even though <frameset> never // ends up being allowed as HTML frameset in the fragment case.
mode = FRAMESET_OK;
} else { // html
StackNode<T> node = createStackNode(ElementName.HTML, elt // [NOCPP[
, errorHandler == null ? null
: new TaintableLocatorImpl(tokenizer) // ]NOCPP]
);
currentPtr++;
stack[currentPtr] = node; if ("template" == contextName) {
pushTemplateMode(IN_TEMPLATE);
}
resetTheInsertionMode();
formPointer = getFormPointerForContext(contextNode); if ("title" == contextName || "textarea" == contextName) {
tokenizer.setState(Tokenizer.RCDATA);
} elseif ("style" == contextName || "xmp" == contextName
|| "iframe" == contextName || "noembed" == contextName
|| "noframes" == contextName
|| (scriptingEnabled && "noscript" == contextName)) {
tokenizer.setState(Tokenizer.RAWTEXT);
} elseif ("plaintext" == contextName) {
tokenizer.setState(Tokenizer.PLAINTEXT);
} elseif ("script" == contextName) {
tokenizer.setState(Tokenizer.SCRIPT_DATA);
} else {
tokenizer.setState(Tokenizer.DATA);
}
}
} else {
mode = INITIAL; // If we are viewing XML source, put a foreign element permanently // on the stack so that cdataSectionAllowed() returns true. // CPPONLY: if (tokenizer.isViewingXmlSource()) { // CPPONLY: T elt = createElement("http://www.w3.org/2000/svg", // CPPONLY: "svg", // CPPONLY: tokenizer.emptyAttributes(), null, // CPPONLY: svgCreator(NS_NewSVGSVGElement)); // CPPONLY: StackNode<T> node = createStackNode(ElementName.SVG, // CPPONLY: "svg", // CPPONLY: elt); // CPPONLY: currentPtr++; // CPPONLY: stack[currentPtr] = node; // CPPONLY: }
}
}
/* * * Then, switch to the root element mode of the tree construction * stage.
*/
mode = BEFORE_HTML; return;
} /* * A DOCTYPE token Parse error.
*/
errStrayDoctype(); /* * Ignore the token.
*/ return;
}
publicfinalvoid comment(@NoLength char[] buf, int start, int length) throws SAXException {
needToDropLF = false; // [NOCPP[ if (!wantingComments) { return;
} // ]NOCPP] if (!isInForeign()) { switch (mode) { case INITIAL: case BEFORE_HTML: case AFTER_AFTER_BODY: case AFTER_AFTER_FRAMESET: /* * A comment token Append a Comment node to the Document * object with the data attribute set to the data given in * the comment token.
*/
appendCommentToDocument(buf, start, length); return; case AFTER_BODY: /* * A comment token Append a Comment node to the first * element in the stack of open elements (the html element), * with the data attribute set to the data given in the * comment token.
*/
flushCharacters();
appendComment(stack[0].node, buf, start, length); return; default: break;
}
} /* * A comment token Append a Comment node to the current node with the * data attribute set to the data given in the comment token.
*/
flushCharacters();
appendComment(stack[currentPtr].node, buf, start, length); return;
}
/** * @see nu.validator.htmlparser.common.TokenHandler#characters(char[], int, * int)
*/ publicfinalvoid characters(@Const @NoLength char[] buf, int start, int length) throws SAXException { // Note: Can't attach error messages to EOF in C++ yet
// CPPONLY: if (tokenizer.isViewingXmlSource()) { // CPPONLY: return; // CPPONLY: } if (needToDropLF) {
needToDropLF = false; if (buf[start] == '\n') {
start++;
length--; if (length == 0) { return;
}
}
}
// optimize the most common case switch (mode) { case IN_BODY: case IN_CELL: case IN_CAPTION: if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
reconstructTheActiveFormattingElements();
} // CPPONLY: MOZ_FALLTHROUGH; case TEXT:
accumulateCharacters(buf, start, length); return; case IN_TABLE: case IN_TABLE_BODY: case IN_ROW:
accumulateCharactersForced(buf, start, length); return; default: int end = start + length;
charactersloop: for (int i = start; i < end; i++) { switch (buf[i]) { case' ': case'\t': case'\n': case'\r': case'\u000C': /* * A character token that is one of one of U+0009 * CHARACTER TABULATION, U+000A LINE FEED (LF), * U+000C FORM FEED (FF), or U+0020 SPACE
*/ switch (mode) { case INITIAL: case BEFORE_HTML: case BEFORE_HEAD: /* * Ignore the token.
*/
start = i + 1; continue; case IN_HEAD: case IN_HEAD_NOSCRIPT: case AFTER_HEAD: case IN_COLUMN_GROUP: case IN_FRAMESET: case AFTER_FRAMESET: /* * Append the character to the current node.
*/ continue; case FRAMESET_OK: case IN_TEMPLATE: case IN_BODY: case IN_CELL: case IN_CAPTION: if (start < i) {
accumulateCharacters(buf, start, i
- start);
start = i;
}
/* * Reconstruct the active formatting * elements, if any.
*/ if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
flushCharacters();
reconstructTheActiveFormattingElements();
} /* * Append the token's character to the * current node.
*/ break charactersloop; case IN_SELECT: case IN_SELECT_IN_TABLE: break charactersloop; case IN_TABLE: case IN_TABLE_BODY: case IN_ROW:
accumulateCharactersForced(buf, i, 1);
start = i + 1; continue; case AFTER_BODY: case AFTER_AFTER_BODY: case AFTER_AFTER_FRAMESET: if (start < i) {
accumulateCharacters(buf, start, i
- start);
start = i;
} /* * Reconstruct the active formatting * elements, if any.
*/
flushCharacters();
reconstructTheActiveFormattingElements(); /* * Append the token's character to the * current node.
*/ continue;
} // CPPONLY: MOZ_FALLTHROUGH_ASSERT(); default: /* * A character token that is not one of one of * U+0009 CHARACTER TABULATION, U+000A LINE FEED * (LF), U+000C FORM FEED (FF), or U+0020 SPACE
*/ switch (mode) { case INITIAL: /* * Parse error.
*/ // [NOCPP[ // XXX figure out a way to report this in the Gecko View Source case
err("Non-space characters found without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D."); // ]NOCPP] /* * * Set the document to quirks mode.
*/
documentModeInternal(
DocumentMode.QUIRKS_MODE, null, null); /* * Then, switch to the root element mode of * the tree construction stage
*/
mode = BEFORE_HTML; /* * and reprocess the current token.
*/
i--; continue; case BEFORE_HTML: /* * Create an HTMLElement node with the tag * name html, in the HTML namespace. Append * it to the Document object.
*/ // No need to flush characters here, // because there's nothing to flush.
appendHtmlElementToDocumentAndPush(); /* Switch to the main mode */
mode = BEFORE_HEAD; /* * reprocess the current token.
*/
i--; continue; case BEFORE_HEAD: if (start < i) {
accumulateCharacters(buf, start, i
- start);
start = i;
} /* * /Act as if a start tag token with the tag * name "head" and no attributes had been * seen,
*/
flushCharacters();
appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES);
mode = IN_HEAD; /* * then reprocess the current token. * * This will result in an empty head element * being generated, with the current token * being reprocessed in the "after head" * insertion mode.
*/
i--; continue; case IN_HEAD: if (start < i) {
accumulateCharacters(buf, start, i
- start);
start = i;
} /* * Act as if an end tag token with the tag * name "head" had been seen,
*/
flushCharacters();
pop();
mode = AFTER_HEAD; /* * and reprocess the current token.
*/
i--; continue; case IN_HEAD_NOSCRIPT: if (start < i) {
accumulateCharacters(buf, start, i
- start);
start = i;
} /* * Parse error. Act as if an end tag with * the tag name "noscript" had been seen
*/
errNonSpaceInNoscriptInHead();
flushCharacters();
pop();
mode = IN_HEAD; /* * and reprocess the current token.
*/
i--; continue; case AFTER_HEAD: if (start < i) {
accumulateCharacters(buf, start, i
- start);
start = i;
} /* * Act as if a start tag token with the tag * name "body" and no attributes had been * seen,
*/
flushCharacters();
appendToCurrentNodeAndPushBodyElement();
mode = FRAMESET_OK; /* * and then reprocess the current token.
*/
i--; continue; case FRAMESET_OK:
framesetOk = false;
mode = IN_BODY;
i--; continue; case IN_TEMPLATE: case IN_BODY: case IN_CELL: case IN_CAPTION: if (start < i) {
accumulateCharacters(buf, start, i
- start);
start = i;
} /* * Reconstruct the active formatting * elements, if any.
*/ if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
flushCharacters();
reconstructTheActiveFormattingElements();
} /* * Append the token's character to the * current node.
*/ break charactersloop; case IN_TABLE: case IN_TABLE_BODY: case IN_ROW:
accumulateCharactersForced(buf, i, 1);
start = i + 1; continue; case IN_COLUMN_GROUP: if (start < i) {
accumulateCharacters(buf, start, i
- start);
start = i;
} /* * Act as if an end tag with the tag name * "colgroup" had been seen, and then, if * that token wasn't ignored, reprocess the * current token.
*/ if (currentPtr == 0 || stack[currentPtr].getGroup() ==
TreeBuilder.TEMPLATE) {
errNonSpaceInColgroupInFragment();
start = i + 1; continue;
}
flushCharacters();
pop();
mode = IN_TABLE;
i--; continue; case IN_SELECT: case IN_SELECT_IN_TABLE: break charactersloop; case AFTER_BODY:
errNonSpaceAfterBody();
fatal();
mode = framesetOk ? FRAMESET_OK : IN_BODY;
i--; continue; case IN_FRAMESET: if (start < i) {
accumulateCharacters(buf, start, i
- start); // start index is adjusted below.
} /* * Parse error.
*/
errNonSpaceInFrameset(); /* * Ignore the token.
*/
start = i + 1; continue; case AFTER_FRAMESET: if (start < i) {
accumulateCharacters(buf, start, i
- start); // start index is adjusted below.
} /* * Parse error.
*/
errNonSpaceAfterFrameset(); /* * Ignore the token.
*/
start = i + 1; continue; case AFTER_AFTER_BODY: /* * Parse error.
*/
errNonSpaceInTrailer(); /* * Switch back to the main mode and * reprocess the token.
*/
mode = framesetOk ? FRAMESET_OK : IN_BODY;
i--; continue; case AFTER_AFTER_FRAMESET: if (start < i) {
accumulateCharacters(buf, start, i
- start); // start index is adjusted below.
} /* * Parse error.
*/
errNonSpaceInTrailer(); /* * Ignore the token.
*/
start = i + 1; continue;
}
}
} if (start < end) {
accumulateCharacters(buf, start, end - start);
}
}
}
publicfinalvoid eof() throws SAXException {
flushCharacters(); // Note: Can't attach error messages to EOF in C++ yet
eofloop: for (;;) { switch (mode) { case INITIAL: /* * Parse error.
*/ // [NOCPP[
err("End of file seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D."); // ]NOCPP] /* * * Set the document to quirks mode.
*/
documentModeInternal(DocumentMode.QUIRKS_MODE, null, null); /* * Then, switch to the root element mode of the tree * construction stage
*/
mode = BEFORE_HTML; /* * and reprocess the current token.
*/ continue; case BEFORE_HTML: /* * Create an HTMLElement node with the tag name html, in the * HTML namespace. Append it to the Document object.
*/
appendHtmlElementToDocumentAndPush(); // XXX application cache manifest /* Switch to the main mode */
mode = BEFORE_HEAD; /* * reprocess the current token.
*/ continue; case BEFORE_HEAD:
appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES);
mode = IN_HEAD; continue; case IN_HEAD: // [NOCPP[ if (errorHandler != null && currentPtr > 1) {
errEofWithUnclosedElements();
} // ]NOCPP] while (currentPtr > 0) {
popOnEof();
}
mode = AFTER_HEAD; continue; case IN_HEAD_NOSCRIPT: // [NOCPP[
errEofWithUnclosedElements(); // ]NOCPP] while (currentPtr > 1) {
popOnEof();
}
mode = IN_HEAD; continue; case AFTER_HEAD:
appendToCurrentNodeAndPushBodyElement();
mode = IN_BODY; continue; case IN_TABLE_BODY: case IN_ROW: case IN_TABLE: case IN_SELECT_IN_TABLE: case IN_SELECT: case IN_COLUMN_GROUP: case FRAMESET_OK: case IN_CAPTION: case IN_CELL: case IN_BODY: // [NOCPP[ // i > 0 to stop in time in the foreign fragment case.
openelementloop: for (int i = currentPtr; i > 0; i--) { int group = stack[i].getGroup(); switch (group) { case DD_OR_DT: case LI: case P: case TBODY_OR_THEAD_OR_TFOOT: case TD_OR_TH: case BODY: case HTML: break; default:
errEofWithUnclosedElements(); break openelementloop;
}
} // ]NOCPP]
if (isTemplateModeStackEmpty()) { break eofloop;
}
// fall through to IN_TEMPLATE // CPPONLY: MOZ_FALLTHROUGH; case IN_TEMPLATE: int eltPos = findLast("template"); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { assert fragment; break eofloop;
} if (errorHandler != null) {
errListUnclosedStartTags(0);
} while (currentPtr >= eltPos) {
pop();
}
clearTheListOfActiveFormattingElementsUpToTheLastMarker();
popTemplateMode();
resetTheInsertionMode();
// Reprocess token. continue; case TEXT: // [NOCPP[ if (errorHandler != null) {
errNoCheck("End of file seen when expecting text or an end tag.");
errListUnclosedStartTags(0);
} // ]NOCPP] // XXX mark script as already executed if (originalMode == AFTER_HEAD) {
popOnEof();
}
popOnEof();
mode = originalMode; continue; case IN_FRAMESET: // [NOCPP[ if (errorHandler != null && currentPtr > 0) {
errEofWithUnclosedElements();
} // ]NOCPP] break eofloop; case AFTER_BODY: case AFTER_FRAMESET: case AFTER_AFTER_BODY: case AFTER_AFTER_FRAMESET: default: // [NOCPP[ if (currentPtr == 0) { // This silliness is here to poison // buggy compiler optimizations in // GWT
System.currentTimeMillis();
} // ]NOCPP] break eofloop;
}
} while (currentPtr > 0) {
popOnEof();
} if (!fragment) {
popOnEof();
} /* Stop parsing. */
}
// [NOCPP[ boolean wasSelfClosing = selfClosing; boolean voidElement = false; if (errorHandler != null) { // ID uniqueness
@IdType String id = attributes.getId(); if (id != null && !isTemplateContents()) {
LocatorImpl oldLoc = idLocations.get(id); if (oldLoc != null) {
err("Duplicate ID \u201C" + id + "\u201D.");
errorHandler.warning(new SAXParseException( "The first occurrence of ID \u201C" + id
+ "\u201D was here.", oldLoc));
} else {
idLocations.put(id, new LocatorImpl(tokenizer));
}
}
} // ]NOCPP]
int eltPos;
needToDropLF = false;
starttagloop: for (;;) { int group = elementName.getGroup();
@Local String name = elementName.getName(); if (isInForeign()) {
StackNode<T> currentNode = stack[currentPtr];
@NsUri String currNs = currentNode.ns; if (!(currentNode.isHtmlIntegrationPoint() || (currNs == "http://www.w3.org/1998/Math/MathML" && ((currentNode.getGroup() == MI_MO_MN_MS_MTEXT && group != MGLYPH_OR_MALIGNMARK) || (currentNode.getGroup() == ANNOTATION_XML && group == SVG))))) { switch (group) { case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U: case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU: case BODY: case BR: case RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR: case DD_OR_DT: case UL_OR_OL_OR_DL: case EMBED: case IMG: case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: case HEAD: case HR: case LI: case META: case NOBR: case P: case PRE_OR_LISTING: case TABLE: case FONT: // re-check FONT to deal with the special case if (!(group == FONT && !(attributes.contains(AttributeName.COLOR)
|| attributes.contains(AttributeName.FACE) || attributes.contains(AttributeName.SIZE)))) {
errHtmlStartTagInForeignContext(name); if (!fragment) { while (!isSpecialParentInForeign(stack[currentPtr])) {
popForeign(-1, -1);
} continue starttagloop;
} // else fall thru
} // CPPONLY: MOZ_FALLTHROUGH; default: if ("http://www.w3.org/2000/svg" == currNs) {
attributes.adjustForSvg(); if (selfClosing) {
appendVoidElementToCurrentMayFosterSVG(
elementName, attributes);
selfClosing = false;
} else {
appendToCurrentNodeAndPushElementMayFosterSVG(
elementName, attributes);
}
attributes = null; // CPP break starttagloop;
} else {
attributes.adjustForMath(); if (selfClosing) {
appendVoidElementToCurrentMayFosterMathML(
elementName, attributes);
selfClosing = false;
} else {
appendToCurrentNodeAndPushElementMayFosterMathML(
elementName, attributes);
}
attributes = null; // CPP break starttagloop;
}
} // switch
} // foreignObject / annotation-xml
} switch (mode) { case IN_TEMPLATE: switch (group) { case COL:
popTemplateMode();
pushTemplateMode(IN_COLUMN_GROUP);
mode = IN_COLUMN_GROUP; // Reprocess token. continue; case CAPTION: case COLGROUP: case TBODY_OR_THEAD_OR_TFOOT:
popTemplateMode();
pushTemplateMode(IN_TABLE);
mode = IN_TABLE; // Reprocess token. continue; case TR:
popTemplateMode();
pushTemplateMode(IN_TABLE_BODY);
mode = IN_TABLE_BODY; // Reprocess token. continue; case TD_OR_TH:
popTemplateMode();
pushTemplateMode(IN_ROW);
mode = IN_ROW; // Reprocess token. continue; case META:
checkMetaCharset(attributes);
appendVoidElementToCurrentMayFoster(
elementName,
attributes);
selfClosing = false; // [NOCPP[
voidElement = true; // ]NOCPP]
attributes = null; // CPP break starttagloop; case TITLE:
startTagTitleInHead(elementName, attributes);
attributes = null; // CPP break starttagloop; case BASE: case LINK_OR_BASEFONT_OR_BGSOUND:
appendVoidElementToCurrentMayFoster(
elementName,
attributes);
selfClosing = false; // [NOCPP[
voidElement = true; // ]NOCPP]
attributes = null; // CPP break starttagloop; case SCRIPT:
startTagScriptInHead(elementName, attributes);
attributes = null; // CPP break starttagloop; case NOFRAMES: case STYLE:
startTagGenericRawText(elementName, attributes);
attributes = null; // CPP break starttagloop; case TEMPLATE:
startTagTemplateInHead(elementName, attributes);
attributes = null; // CPP break starttagloop; default:
popTemplateMode();
pushTemplateMode(IN_BODY);
mode = IN_BODY; // Reprocess token. continue;
} case IN_ROW: switch (group) { case TD_OR_TH:
clearStackBackTo(findLastOrRoot(TreeBuilder.TR));
appendToCurrentNodeAndPushElement(
elementName,
attributes);
mode = IN_CELL;
insertMarker();
attributes = null; // CPP break starttagloop; case CAPTION: case COL: case COLGROUP: case TBODY_OR_THEAD_OR_TFOOT: case TR:
eltPos = findLastOrRoot(TreeBuilder.TR); if (eltPos == 0) { assert fragment || isTemplateContents();
errNoTableRowToClose(); break starttagloop;
}
clearStackBackTo(eltPos);
pop();
mode = IN_TABLE_BODY; continue; default: // fall through to IN_TABLE
} // CPPONLY: MOZ_FALLTHROUGH; case IN_TABLE_BODY: switch (group) { case TR:
clearStackBackTo(findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
appendToCurrentNodeAndPushElement(
elementName,
attributes);
mode = IN_ROW;
attributes = null; // CPP break starttagloop; case TD_OR_TH:
errStartTagInTableBody(name);
clearStackBackTo(findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
appendToCurrentNodeAndPushElement(
ElementName.TR,
HtmlAttributes.EMPTY_ATTRIBUTES);
mode = IN_ROW; continue; case CAPTION: case COL: case COLGROUP: case TBODY_OR_THEAD_OR_TFOOT:
eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot(); if (eltPos == 0 || stack[eltPos].getGroup() == TEMPLATE) { assert fragment || isTemplateContents();
errStrayStartTag(name); break starttagloop;
} else {
clearStackBackTo(eltPos);
pop();
mode = IN_TABLE; continue;
} default: // fall through to IN_TABLE
} // CPPONLY: MOZ_FALLTHROUGH; case IN_TABLE:
intableloop: for (;;) { switch (group) { case CAPTION:
clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE));
insertMarker();
appendToCurrentNodeAndPushElement(
elementName,
attributes);
mode = IN_CAPTION;
attributes = null; // CPP break starttagloop; case COLGROUP:
clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE));
appendToCurrentNodeAndPushElement(
elementName,
attributes);
mode = IN_COLUMN_GROUP;
attributes = null; // CPP break starttagloop; case COL:
clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE));
appendToCurrentNodeAndPushElement(
ElementName.COLGROUP,
HtmlAttributes.EMPTY_ATTRIBUTES);
mode = IN_COLUMN_GROUP; continue starttagloop; case TBODY_OR_THEAD_OR_TFOOT:
clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE));
appendToCurrentNodeAndPushElement(
elementName,
attributes);
mode = IN_TABLE_BODY;
attributes = null; // CPP break starttagloop; case TR: case TD_OR_TH:
clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE));
appendToCurrentNodeAndPushElement(
ElementName.TBODY,
HtmlAttributes.EMPTY_ATTRIBUTES);
mode = IN_TABLE_BODY; continue starttagloop; case TEMPLATE: // fall through to IN_HEAD break intableloop; case TABLE:
errTableSeenWhileTableOpen();
eltPos = findLastInTableScope(name); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { assert fragment || isTemplateContents(); break starttagloop;
}
generateImpliedEndTags(); if (errorHandler != null && !isCurrent("table")) {
errNoCheckUnclosedElementsOnStack();
} while (currentPtr >= eltPos) {
pop();
}
resetTheInsertionMode(); continue starttagloop; case SCRIPT: // XXX need to manage much more stuff // here if // supporting // document.write()
appendToCurrentNodeAndPushElement(
elementName,
attributes);
originalMode = mode;
mode = TEXT;
tokenizer.setStateAndEndTagExpectation(
Tokenizer.SCRIPT_DATA, elementName);
attributes = null; // CPP break starttagloop; case STYLE:
appendToCurrentNodeAndPushElement(
elementName,
attributes);
originalMode = mode;
mode = TEXT;
tokenizer.setStateAndEndTagExpectation(
Tokenizer.RAWTEXT, elementName);
attributes = null; // CPP break starttagloop; case INPUT:
errStartTagInTable(name); if (!Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( "hidden",
attributes.getValue(AttributeName.TYPE))) { break intableloop;
}
appendVoidInputToCurrent(
attributes,
formPointer);
selfClosing = false; // [NOCPP[
voidElement = true; // ]NOCPP]
attributes = null; // CPP break starttagloop; case FORM: if (formPointer != null || isTemplateContents()) {
errFormWhenFormOpen(); break starttagloop;
} else {
errStartTagInTable(name);
appendVoidFormToCurrent(attributes);
attributes = null; // CPP break starttagloop;
} default:
errStartTagInTable(name); // fall through to IN_BODY break intableloop;
}
} // CPPONLY: MOZ_FALLTHROUGH; case IN_CAPTION: switch (group) { case CAPTION: case COL: case COLGROUP: case TBODY_OR_THEAD_OR_TFOOT: case TR: case TD_OR_TH:
eltPos = findLastInTableScope("caption"); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { assert fragment || isTemplateContents();
errStrayStartTag(name); break starttagloop;
}
generateImpliedEndTags(); if (errorHandler != null && currentPtr != eltPos) {
errNoCheckUnclosedElementsOnStack();
} while (currentPtr >= eltPos) {
pop();
}
clearTheListOfActiveFormattingElementsUpToTheLastMarker();
mode = IN_TABLE; continue; default: // fall through to IN_BODY
} // CPPONLY: MOZ_FALLTHROUGH; case IN_CELL: switch (group) { case CAPTION: case COL: case COLGROUP: case TBODY_OR_THEAD_OR_TFOOT: case TR: case TD_OR_TH:
eltPos = findLastInTableScopeTdTh(); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
errNoCellToClose(); break starttagloop;
} else {
closeTheCell(eltPos); continue;
} default: // fall through to IN_BODY
} // CPPONLY: MOZ_FALLTHROUGH; case FRAMESET_OK: switch (group) { case FRAMESET: if (mode == FRAMESET_OK) { if (currentPtr == 0 || stack[1].getGroup() != BODY) { assert fragment || isTemplateContents();
errStrayStartTag(name); break starttagloop;
} else {
errFramesetStart();
detachFromParent(stack[1].node); while (currentPtr > 0) {
pop();
}
appendToCurrentNodeAndPushElement(
elementName,
attributes);
mode = IN_FRAMESET;
attributes = null; // CPP break starttagloop;
}
} else {
errStrayStartTag(name); break starttagloop;
} // NOT falling through! case PRE_OR_LISTING: case LI: case DD_OR_DT: case BUTTON: case MARQUEE_OR_APPLET: case OBJECT: case TABLE: case AREA_OR_WBR: case KEYGEN: case BR: case EMBED: case IMG: case INPUT: case HR: case TEXTAREA: case XMP: case IFRAME: case SELECT: if (mode == FRAMESET_OK
&& !(group == INPUT && Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( "hidden",
attributes.getValue(AttributeName.TYPE)))) {
framesetOk = false;
mode = IN_BODY;
} // CPPONLY: MOZ_FALLTHROUGH; default: // fall through to IN_BODY
} // CPPONLY: MOZ_FALLTHROUGH; case IN_BODY:
inbodyloop: for (;;) { switch (group) { case HTML:
errStrayStartTag(name); if (!fragment && !isTemplateContents()) {
addAttributesToHtml(attributes);
attributes = null; // CPP
} break starttagloop; case BASE: case LINK_OR_BASEFONT_OR_BGSOUND: case META: case STYLE: case SCRIPT: case TITLE: case TEMPLATE: // Fall through to IN_HEAD break inbodyloop; case BODY: if (currentPtr == 0 || stack[1].getGroup() != BODY || isTemplateContents()) { assert fragment || isTemplateContents();
errStrayStartTag(name); break starttagloop;
}
errFooSeenWhenFooOpen(name);
framesetOk = false; if (mode == FRAMESET_OK) {
mode = IN_BODY;
} if (addAttributesToBody(attributes)) {
attributes = null; // CPP
} break starttagloop; case P: case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU: case UL_OR_OL_OR_DL: case ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIALOG_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SEARCH_OR_SECTION_OR_SUMMARY:
implicitlyCloseP();
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes);
attributes = null; // CPP break starttagloop; case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6:
implicitlyCloseP(); if (stack[currentPtr].getGroup() == H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) {
errHeadingWhenHeadingOpen();
pop();
}
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes);
attributes = null; // CPP break starttagloop; case FIELDSET:
implicitlyCloseP();
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes, formPointer);
attributes = null; // CPP break starttagloop; case PRE_OR_LISTING:
implicitlyCloseP();
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes);
needToDropLF = true;
attributes = null; // CPP break starttagloop; case FORM: if (formPointer != null && !isTemplateContents()) {
errFormWhenFormOpen(); break starttagloop;
} else {
implicitlyCloseP();
appendToCurrentNodeAndPushFormElementMayFoster(attributes);
attributes = null; // CPP break starttagloop;
} case LI: case DD_OR_DT:
eltPos = currentPtr; for (;;) {
StackNode<T> node = stack[eltPos]; // weak // ref if (node.getGroup() == group) { // LI or // DD_OR_DT
generateImpliedEndTagsExceptFor(node.name); if (errorHandler != null
&& eltPos != currentPtr) {
errUnclosedElementsImplied(eltPos, name);
} while (currentPtr >= eltPos) {
pop();
} break;
} elseif (eltPos == 0 || (node.isSpecial()
&& (node.ns != "http://www.w3.org/1999/xhtml"
|| (node.name != "p"
&& node.name != "address"
&& node.name != "div")))) { break;
}
eltPos--;
}
implicitlyCloseP();
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes);
attributes = null; // CPP break starttagloop; case PLAINTEXT:
implicitlyCloseP();
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes);
tokenizer.setStateAndEndTagExpectation(
Tokenizer.PLAINTEXT, elementName);
attributes = null; // CPP break starttagloop; case A: int activeAPos = findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker("a"); if (activeAPos != -1) {
errFooSeenWhenFooOpen(name);
StackNode<T> activeA = listOfActiveFormattingElements[activeAPos];
activeA.retain();
adoptionAgencyEndTag("a");
removeFromStack(activeA);
activeAPos = findInListOfActiveFormattingElements(activeA); if (activeAPos != -1) {
removeFromListOfActiveFormattingElements(activeAPos);
}
activeA.release(this);
}
reconstructTheActiveFormattingElements();
appendToCurrentNodeAndPushFormattingElementMayFoster(
elementName,
attributes);
attributes = null; // CPP break starttagloop; 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.getName(), attributes);
appendToCurrentNodeAndPushFormattingElementMayFoster(
elementName,
attributes);
attributes = null; // CPP break starttagloop; case NOBR:
reconstructTheActiveFormattingElements(); if (TreeBuilder.NOT_FOUND_ON_STACK != findLastInScope("nobr")) {
errFooSeenWhenFooOpen(name);
adoptionAgencyEndTag("nobr");
reconstructTheActiveFormattingElements();
}
appendToCurrentNodeAndPushFormattingElementMayFoster(
elementName,
attributes);
attributes = null; // CPP break starttagloop; case BUTTON:
eltPos = findLastInScope(name); if (eltPos != TreeBuilder.NOT_FOUND_ON_STACK) {
errFooSeenWhenFooOpen(name);
generateImpliedEndTags(); if (errorHandler != null
&& !isCurrent(name)) {
errUnclosedElementsImplied(eltPos, name);
} while (currentPtr >= eltPos) {
pop();
} continue starttagloop;
} else {
reconstructTheActiveFormattingElements();
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes, formPointer);
attributes = null; // CPP break starttagloop;
} case OBJECT:
reconstructTheActiveFormattingElements();
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes, formPointer);
insertMarker();
attributes = null; // CPP break starttagloop; case MARQUEE_OR_APPLET:
reconstructTheActiveFormattingElements();
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes);
insertMarker();
attributes = null; // CPP break starttagloop; case TABLE: // The only quirk. Blame Hixie and // Acid2. if (!quirks) {
implicitlyCloseP();
}
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes);
mode = IN_TABLE;
attributes = null; // CPP break starttagloop; case BR: case EMBED: case AREA_OR_WBR: case KEYGEN:
reconstructTheActiveFormattingElements(); // FALL THROUGH to PARAM_OR_SOURCE_OR_TRACK // CPPONLY: MOZ_FALLTHROUGH; case PARAM_OR_SOURCE_OR_TRACK:
appendVoidElementToCurrentMayFoster(
elementName,
attributes);
selfClosing = false; // [NOCPP[
voidElement = true; // ]NOCPP]
attributes = null; // CPP break starttagloop; case HR:
implicitlyCloseP();
appendVoidElementToCurrentMayFoster(
elementName,
attributes);
selfClosing = false; // [NOCPP[
voidElement = true; // ]NOCPP]
attributes = null; // CPP break starttagloop; case IMAGE:
errImage();
elementName = ElementName.IMG; continue starttagloop; case IMG: case INPUT:
reconstructTheActiveFormattingElements();
appendVoidElementToCurrentMayFoster(
elementName, attributes,
formPointer);
selfClosing = false; // [NOCPP[
voidElement = true; // ]NOCPP]
attributes = null; // CPP break starttagloop; case TEXTAREA:
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes, formPointer);
tokenizer.setStateAndEndTagExpectation(
Tokenizer.RCDATA, elementName);
originalMode = mode;
mode = TEXT;
needToDropLF = true;
attributes = null; // CPP break starttagloop; case XMP:
implicitlyCloseP();
reconstructTheActiveFormattingElements();
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes);
originalMode = mode;
mode = TEXT;
tokenizer.setStateAndEndTagExpectation(
Tokenizer.RAWTEXT, elementName);
attributes = null; // CPP break starttagloop; case NOSCRIPT: if (!scriptingEnabled) {
reconstructTheActiveFormattingElements();
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes);
attributes = null; // CPP break starttagloop;
} // CPPONLY: MOZ_FALLTHROUGH; case NOFRAMES: case IFRAME: case NOEMBED:
startTagGenericRawText(elementName, attributes);
attributes = null; // CPP break starttagloop; case SELECT:
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;
}
attributes = null; // CPP break starttagloop; case OPTGROUP: case OPTION: if (isCurrent("option")) {
pop();
}
reconstructTheActiveFormattingElements();
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes);
attributes = null; // CPP break starttagloop; case RB_OR_RTC:
eltPos = findLastInScope("ruby"); if (eltPos != NOT_FOUND_ON_STACK) {
generateImpliedEndTags();
} if (eltPos != currentPtr) { if (eltPos == NOT_FOUND_ON_STACK) {
errStartTagSeenWithoutRuby(name);
} else {
errUnclosedChildrenInRuby();
}
}
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes);
attributes = null; // CPP break starttagloop; case RT_OR_RP:
eltPos = findLastInScope("ruby"); if (eltPos != NOT_FOUND_ON_STACK) {
generateImpliedEndTagsExceptFor("rtc");
} if (eltPos != currentPtr) { if (!isCurrent("rtc")) { if (eltPos == NOT_FOUND_ON_STACK) {
errStartTagSeenWithoutRuby(name);
} else {
errUnclosedChildrenInRuby();
}
}
}
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes);
attributes = null; // CPP break starttagloop; case MATH:
reconstructTheActiveFormattingElements();
attributes.adjustForMath(); if (selfClosing) {
appendVoidElementToCurrentMayFosterMathML(
elementName, attributes);
selfClosing = false;
} else {
appendToCurrentNodeAndPushElementMayFosterMathML(
elementName, attributes);
}
attributes = null; // CPP break starttagloop; case SVG:
reconstructTheActiveFormattingElements();
attributes.adjustForSvg(); if (selfClosing) {
appendVoidElementToCurrentMayFosterSVG(
elementName,
attributes);
selfClosing = false;
} else {
appendToCurrentNodeAndPushElementMayFosterSVG(
elementName, attributes);
}
attributes = null; // CPP break starttagloop; case CAPTION: case COL: case COLGROUP: case TBODY_OR_THEAD_OR_TFOOT: case TR: case TD_OR_TH: case FRAME: case FRAMESET: case HEAD:
errStrayStartTag(name); break starttagloop; case OUTPUT:
reconstructTheActiveFormattingElements();
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes, formPointer);
attributes = null; // CPP break starttagloop; default:
reconstructTheActiveFormattingElements();
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes);
attributes = null; // CPP break starttagloop;
}
} // CPPONLY: MOZ_FALLTHROUGH; case IN_HEAD:
inheadloop: for (;;) { switch (group) { case HTML:
errStrayStartTag(name); if (!fragment && !isTemplateContents()) {
addAttributesToHtml(attributes);
attributes = null; // CPP
} break starttagloop; case BASE: case LINK_OR_BASEFONT_OR_BGSOUND:
appendVoidElementToCurrentMayFoster(
elementName,
attributes);
selfClosing = false; // [NOCPP[
voidElement = true; // ]NOCPP]
attributes = null; // CPP break starttagloop; case META: // Fall through to IN_HEAD_NOSCRIPT break inheadloop; case TITLE:
startTagTitleInHead(elementName, attributes);
attributes = null; // CPP break starttagloop; case NOSCRIPT: if (scriptingEnabled) {
appendToCurrentNodeAndPushElement(
elementName,
attributes);
originalMode = mode;
mode = TEXT;
tokenizer.setStateAndEndTagExpectation(
Tokenizer.RAWTEXT, elementName);
} else {
appendToCurrentNodeAndPushElementMayFoster(
elementName,
attributes);
mode = IN_HEAD_NOSCRIPT;
}
attributes = null; // CPP break starttagloop; case SCRIPT:
startTagScriptInHead(elementName, attributes);
attributes = null; // CPP break starttagloop; case STYLE: case NOFRAMES:
startTagGenericRawText(elementName, attributes);
attributes = null; // CPP break starttagloop; case HEAD: /* Parse error. */
errFooSeenWhenFooOpen(name); /* Ignore the token. */ break starttagloop; case TEMPLATE:
startTagTemplateInHead(elementName, attributes);
attributes = null; // CPP break starttagloop; default:
pop();
mode = AFTER_HEAD; continue starttagloop;
}
} // CPPONLY: MOZ_FALLTHROUGH; case IN_HEAD_NOSCRIPT: switch (group) { case HTML: // XXX did Hixie really mean to omit "base" // here?
errStrayStartTag(name); if (!fragment && !isTemplateContents()) {
addAttributesToHtml(attributes);
attributes = null; // CPP
} break starttagloop; case LINK_OR_BASEFONT_OR_BGSOUND:
appendVoidElementToCurrentMayFoster(
elementName,
attributes);
selfClosing = false; // [NOCPP[
voidElement = true; // ]NOCPP]
attributes = null; // CPP break starttagloop; case META:
checkMetaCharset(attributes);
appendVoidElementToCurrentMayFoster(
elementName,
attributes);
selfClosing = false; // [NOCPP[
voidElement = true; // ]NOCPP]
attributes = null; // CPP break starttagloop; case STYLE: case NOFRAMES:
appendToCurrentNodeAndPushElement(
elementName,
attributes);
originalMode = mode;
mode = TEXT;
tokenizer.setStateAndEndTagExpectation(
Tokenizer.RAWTEXT, elementName);
attributes = null; // CPP break starttagloop; case HEAD:
errFooSeenWhenFooOpen(name); break starttagloop; case NOSCRIPT:
errFooSeenWhenFooOpen(name); break starttagloop; default:
errBadStartTagInNoscriptInHead(name);
pop();
mode = IN_HEAD; continue;
} case IN_COLUMN_GROUP: switch (group) { case HTML:
errStrayStartTag(name); if (!fragment && !isTemplateContents()) {
addAttributesToHtml(attributes);
attributes = null; // CPP
} break starttagloop; case COL:
appendVoidElementToCurrentMayFoster(
elementName,
attributes);
selfClosing = false; // [NOCPP[
voidElement = true; // ]NOCPP]
attributes = null; // CPP break starttagloop; case TEMPLATE:
startTagTemplateInHead(elementName, attributes);
attributes = null; // CPP break starttagloop; default: if (currentPtr == 0 || stack[currentPtr].getGroup() == TEMPLATE) { assert fragment || isTemplateContents();
errGarbageInColgroup(); break starttagloop;
}
pop();
mode = IN_TABLE; continue;
} case IN_SELECT_IN_TABLE: switch (group) { case CAPTION: case TBODY_OR_THEAD_OR_TFOOT: case TR: case TD_OR_TH: case TABLE:
errStartTagWithSelectOpen(name);
eltPos = findLastInTableScope("select"); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { assert fragment; break starttagloop; // http://www.w3.org/Bugs/Public/show_bug.cgi?id=8375
} while (currentPtr >= eltPos) {
pop();
}
resetTheInsertionMode(); continue; default: // fall through to IN_SELECT
} // CPPONLY: MOZ_FALLTHROUGH; case IN_SELECT: switch (group) { case HTML:
errStrayStartTag(name); if (!fragment) {
addAttributesToHtml(attributes);
attributes = null; // CPP
} break starttagloop; case OPTION: if (isCurrent("option")) {
pop();
}
appendToCurrentNodeAndPushElement(
elementName,
attributes);
attributes = null; // CPP break starttagloop; case OPTGROUP: if (isCurrent("option")) {
pop();
} if (isCurrent("optgroup")) {
pop();
}
appendToCurrentNodeAndPushElement(
elementName,
attributes);
attributes = null; // CPP break starttagloop; case SELECT:
errStartSelectWhereEndSelectExpected();
eltPos = findLastInTableScope(name); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { assert fragment;
errNoSelectInTableScope(); break starttagloop;
} else { while (currentPtr >= eltPos) {
pop();
}
resetTheInsertionMode(); break starttagloop;
} case INPUT: case TEXTAREA:
errStartTagWithSelectOpen(name);
eltPos = findLastInTableScope("select"); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { assert fragment; break starttagloop;
} while (currentPtr >= eltPos) {
pop();
}
resetTheInsertionMode(); continue; case SCRIPT:
startTagScriptInHead(elementName, attributes);
attributes = null; // CPP break starttagloop; case TEMPLATE:
startTagTemplateInHead(elementName, attributes);
attributes = null; // CPP break starttagloop; case HR: if (isCurrent("option")) {
pop();
} if (isCurrent("optgroup")) {
pop();
}
appendVoidElementToCurrent(elementName, attributes);
selfClosing = false; // [NOCPP[
voidElement = true; // ]NOCPP]
attributes = null; // CPP break starttagloop; default:
errStrayStartTag(name); break starttagloop;
} case AFTER_BODY: switch (group) { case HTML:
errStrayStartTag(name); if (!fragment && !isTemplateContents()) {
addAttributesToHtml(attributes);
attributes = null; // CPP
} break starttagloop; default:
errStrayStartTag(name);
mode = framesetOk ? FRAMESET_OK : IN_BODY; continue;
} case IN_FRAMESET: switch (group) { case FRAMESET:
appendToCurrentNodeAndPushElement(
elementName,
attributes);
attributes = null; // CPP break starttagloop; case FRAME:
appendVoidElementToCurrentMayFoster(
elementName,
attributes);
selfClosing = false; // [NOCPP[
voidElement = true; // ]NOCPP]
attributes = null; // CPP break starttagloop; default: // fall through to AFTER_FRAMESET
} // CPPONLY: MOZ_FALLTHROUGH; case AFTER_FRAMESET: switch (group) { case HTML:
errStrayStartTag(name); if (!fragment && !isTemplateContents()) {
addAttributesToHtml(attributes);
attributes = null; // CPP
} break starttagloop; case NOFRAMES:
appendToCurrentNodeAndPushElement(
elementName,
attributes);
originalMode = mode;
mode = TEXT;
tokenizer.setStateAndEndTagExpectation(
Tokenizer.RAWTEXT, elementName);
attributes = null; // CPP break starttagloop; default:
errStrayStartTag(name); break starttagloop;
} case INITIAL: /* * Parse error.
*/
errStartTagWithoutDoctype(); /* * * Set the document to quirks mode.
*/
documentModeInternal(DocumentMode.QUIRKS_MODE, null, null); /* * Then, switch to the root element mode of the tree * construction stage
*/
mode = BEFORE_HTML; /* * and reprocess the current token.
*/ continue; case BEFORE_HTML: switch (group) { case HTML: // optimize error check and streaming SAX by // hoisting // "html" handling here. if (attributes == HtmlAttributes.EMPTY_ATTRIBUTES) { // This has the right magic side effect // that // it // makes attributes in SAX Tree mutable.
appendHtmlElementToDocumentAndPush();
} else {
appendHtmlElementToDocumentAndPush(attributes);
} // XXX application cache should fire here
mode = BEFORE_HEAD;
attributes = null; // CPP break starttagloop; default: /* * Create an HTMLElement node with the tag name * html, in the HTML namespace. Append it to the * Document object.
*/
appendHtmlElementToDocumentAndPush(); /* Switch to the main mode */
mode = BEFORE_HEAD; /* * reprocess the current token.
*/ continue;
} case BEFORE_HEAD: switch (group) { case HTML:
errStrayStartTag(name); if (!fragment && !isTemplateContents()) {
addAttributesToHtml(attributes);
attributes = null; // CPP
} break starttagloop; case HEAD: /* * A start tag whose tag name is "head" * * Create an element for the token. * * Set the head element pointer to this new element * node. * * Append the new element to the current node and * push it onto the stack of open elements.
*/
appendToCurrentNodeAndPushHeadElement(attributes); /* * Change the insertion mode to "in head".
*/
mode = IN_HEAD;
attributes = null; // CPP break starttagloop; default: /* * Any other start tag token * * Act as if a start tag token with the tag name * "head" and no attributes had been seen,
*/
appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES);
mode = IN_HEAD; /* * then reprocess the current token. * * This will result in an empty head element being * generated, with the current token being * reprocessed in the "after head" insertion mode.
*/ continue;
} case AFTER_HEAD: switch (group) { case HTML:
errStrayStartTag(name); if (!fragment && !isTemplateContents()) {
addAttributesToHtml(attributes);
attributes = null; // CPP
} break starttagloop; case BODY: if (attributes.getLength() == 0) { // This has the right magic side effect // that // it // makes attributes in SAX Tree mutable.
appendToCurrentNodeAndPushBodyElement();
} else {
appendToCurrentNodeAndPushBodyElement(attributes);
}
framesetOk = false;
mode = IN_BODY;
attributes = null; // CPP break starttagloop; case FRAMESET:
appendToCurrentNodeAndPushElement(
elementName,
attributes);
mode = IN_FRAMESET;
attributes = null; // CPP break starttagloop; case TEMPLATE:
errFooBetweenHeadAndBody(name);
pushHeadPointerOntoStack();
StackNode<T> headOnStack = stack[currentPtr];
startTagTemplateInHead(elementName, attributes);
removeFromStack(headOnStack);
attributes = null; // CPP break starttagloop; case BASE: case LINK_OR_BASEFONT_OR_BGSOUND:
errFooBetweenHeadAndBody(name);
pushHeadPointerOntoStack();
appendVoidElementToCurrentMayFoster(
elementName,
attributes);
selfClosing = false; // [NOCPP[
voidElement = true; // ]NOCPP]
pop(); // head
attributes = null; // CPP break starttagloop; case META:
errFooBetweenHeadAndBody(name);
checkMetaCharset(attributes);
pushHeadPointerOntoStack();
appendVoidElementToCurrentMayFoster(
elementName,
attributes);
selfClosing = false; // [NOCPP[
voidElement = true; // ]NOCPP]
pop(); // head
attributes = null; // CPP break starttagloop; case SCRIPT:
errFooBetweenHeadAndBody(name);
pushHeadPointerOntoStack();
appendToCurrentNodeAndPushElement(
elementName,
attributes);
originalMode = mode;
mode = TEXT;
tokenizer.setStateAndEndTagExpectation(
Tokenizer.SCRIPT_DATA, elementName);
attributes = null; // CPP break starttagloop; case STYLE: case NOFRAMES:
errFooBetweenHeadAndBody(name);
pushHeadPointerOntoStack();
appendToCurrentNodeAndPushElement(
elementName,
attributes);
originalMode = mode;
mode = TEXT;
tokenizer.setStateAndEndTagExpectation(
Tokenizer.RAWTEXT, elementName);
attributes = null; // CPP break starttagloop; case TITLE:
errFooBetweenHeadAndBody(name);
pushHeadPointerOntoStack();
appendToCurrentNodeAndPushElement(
elementName,
attributes);
originalMode = mode;
mode = TEXT;
tokenizer.setStateAndEndTagExpectation(
Tokenizer.RCDATA, elementName);
attributes = null; // CPP break starttagloop; case HEAD:
errStrayStartTag(name); break starttagloop; default:
appendToCurrentNodeAndPushBodyElement();
mode = FRAMESET_OK; continue;
} case AFTER_AFTER_BODY: switch (group) { case HTML:
errStrayStartTag(name); if (!fragment && !isTemplateContents()) {
addAttributesToHtml(attributes);
attributes = null; // CPP
} break starttagloop; default:
errStrayStartTag(name);
fatal();
mode = framesetOk ? FRAMESET_OK : IN_BODY; continue;
} case AFTER_AFTER_FRAMESET: switch (group) { case HTML:
errStrayStartTag(name); if (!fragment && !isTemplateContents()) {
addAttributesToHtml(attributes);
attributes = null; // CPP
} break starttagloop; case NOFRAMES:
startTagGenericRawText(elementName, attributes);
attributes = null; // CPP break starttagloop; default:
errStrayStartTag(name); break starttagloop;
} case TEXT: assertfalse; break starttagloop; // Avoid infinite loop if the assertion // fails
}
} if (selfClosing) {
errSelfClosing(); // [NOCPP[
} elseif (wasSelfClosing && voidElement
&& tokenizer.getErrorProfile() != null
&& tokenizer.getErrorProfile().get("html-strict") != null) {
warn("Trailing slash on void elements has no effect and interacts"
+ " badly with unquoted attribute values."); // ]NOCPP]
} // CPPONLY: if (mBuilder == null && attributes != HtmlAttributes.EMPTY_ATTRIBUTES) { // CPPONLY: Portability.delete(attributes); // CPPONLY: }
}
/** * * <p> * C++ memory note: The return value must be released. * * @return * @throws SAXException * @throws StopSniffingException
*/ publicstatic String extractCharsetFromContent(String attributeValue // CPPONLY: , TreeBuilder tb
) { // This is a bit ugly. Converting the string to char array in order to // make the portability layer smaller. int charsetState = CHARSET_INITIAL; int start = -1; int end = -1;
@Auto char[] buffer = Portability.newCharArrayFromString(attributeValue);
privatevoid checkMetaCharset(HtmlAttributes attributes) throws SAXException {
String charset = attributes.getValue(AttributeName.CHARSET); if (charset != null) { if (tokenizer.internalEncodingDeclaration(charset)) {
requestSuspension(); return;
} return;
} if (!Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( "content-type",
attributes.getValue(AttributeName.HTTP_EQUIV))) { return;
}
String content = attributes.getValue(AttributeName.CONTENT); if (content != null) {
String extract = TreeBuilder.extractCharsetFromContent(content // CPPONLY: , this
); // remember not to return early without releasing the string if (extract != null) { if (tokenizer.internalEncodingDeclaration(extract)) {
requestSuspension();
}
}
Portability.releaseString(extract);
}
}
publicfinalvoid endTag(ElementName elementName) throws SAXException {
flushCharacters();
needToDropLF = false; int eltPos; int group = elementName.getGroup();
@Local String name = elementName.getName();
endtagloop: for (;;) { if (isInForeign()) { if (stack[currentPtr].name != name) { if (currentPtr == 0) {
errStrayEndTag(name);
} else {
errEndTagDidNotMatchCurrentOpenElement(name, stack[currentPtr].popName);
}
}
eltPos = currentPtr; int origPos = currentPtr; for (;;) { if (eltPos == 0) { assert fragment: "We can get this close to the root of the stack in foreign content only in the fragment case."; break endtagloop;
} if (stack[eltPos].name == name) { while (currentPtr >= eltPos) {
popForeign(origPos, eltPos);
} break endtagloop;
} if (stack[--eltPos].ns == "http://www.w3.org/1999/xhtml") { break;
}
}
} switch (mode) { case IN_TEMPLATE: switch (group) { case TEMPLATE: // fall through to IN_HEAD break; default:
errStrayEndTag(name); break endtagloop;
} // CPPONLY: MOZ_FALLTHROUGH; case IN_ROW: switch (group) { case TR:
eltPos = findLastOrRoot(TreeBuilder.TR); if (eltPos == 0) { assert fragment || isTemplateContents();
errNoTableRowToClose(); break endtagloop;
}
clearStackBackTo(eltPos);
pop();
mode = IN_TABLE_BODY; break endtagloop; case TABLE:
eltPos = findLastOrRoot(TreeBuilder.TR); if (eltPos == 0) { assert fragment || isTemplateContents();
errNoTableRowToClose(); break endtagloop;
}
clearStackBackTo(eltPos);
pop();
mode = IN_TABLE_BODY; continue; case TBODY_OR_THEAD_OR_TFOOT: if (findLastInTableScope(name) == TreeBuilder.NOT_FOUND_ON_STACK) {
errStrayEndTag(name); break endtagloop;
}
eltPos = findLastOrRoot(TreeBuilder.TR); if (eltPos == 0) { assert fragment || isTemplateContents();
errNoTableRowToClose(); break endtagloop;
}
clearStackBackTo(eltPos);
pop();
mode = IN_TABLE_BODY; continue; case BODY: case CAPTION: case COL: case COLGROUP: case HTML: case TD_OR_TH:
errStrayEndTag(name); break endtagloop; default: // fall through to IN_TABLE
} // CPPONLY: MOZ_FALLTHROUGH; case IN_TABLE_BODY: switch (group) { case TBODY_OR_THEAD_OR_TFOOT:
eltPos = findLastOrRoot(name); if (eltPos == 0) {
errStrayEndTag(name); break endtagloop;
}
clearStackBackTo(eltPos);
pop();
mode = IN_TABLE; break endtagloop; case TABLE:
eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot(); if (eltPos == 0 || stack[eltPos].getGroup() == TEMPLATE) { assert fragment || isTemplateContents();
errStrayEndTag(name); break endtagloop;
}
clearStackBackTo(eltPos);
pop();
mode = IN_TABLE; continue; case BODY: case CAPTION: case COL: case COLGROUP: case HTML: case TD_OR_TH: case TR:
errStrayEndTag(name); break endtagloop; default: // fall through to IN_TABLE
} // CPPONLY: MOZ_FALLTHROUGH; case IN_TABLE: switch (group) { case TABLE:
eltPos = findLast("table"); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { assert fragment || isTemplateContents();
errStrayEndTag(name); break endtagloop;
} while (currentPtr >= eltPos) {
pop();
}
resetTheInsertionMode(); break endtagloop; case BODY: case CAPTION: case COL: case COLGROUP: case HTML: case TBODY_OR_THEAD_OR_TFOOT: case TD_OR_TH: case TR:
errStrayEndTag(name); break endtagloop; case TEMPLATE: // fall through to IN_HEAD break; default:
errStrayEndTag(name); // fall through to IN_BODY
} // CPPONLY: MOZ_FALLTHROUGH; case IN_CAPTION: switch (group) { case CAPTION:
eltPos = findLastInTableScope("caption"); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { break endtagloop;
}
generateImpliedEndTags(); if (errorHandler != null && currentPtr != eltPos) {
errUnclosedElements(eltPos, name);
} while (currentPtr >= eltPos) {
pop();
}
clearTheListOfActiveFormattingElementsUpToTheLastMarker();
mode = IN_TABLE; break endtagloop; case TABLE:
eltPos = findLastInTableScope("caption");
if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { assert fragment || isTemplateContents();
errStrayEndTag(name); break endtagloop;
}
generateImpliedEndTags(); if (errorHandler != null && currentPtr != eltPos) {
errUnclosedElements(eltPos, name);
} while (currentPtr >= eltPos) {
pop();
}
clearTheListOfActiveFormattingElementsUpToTheLastMarker();
mode = IN_TABLE; continue; case BODY: case COL: case COLGROUP: case HTML: case TBODY_OR_THEAD_OR_TFOOT: case TD_OR_TH: case TR:
errStrayEndTag(name); break endtagloop; default: // fall through to IN_BODY
} // CPPONLY: MOZ_FALLTHROUGH; case IN_CELL: switch (group) { case TD_OR_TH:
eltPos = findLastInTableScope(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();
}
clearTheListOfActiveFormattingElementsUpToTheLastMarker();
mode = IN_ROW; break endtagloop; case TABLE: case TBODY_OR_THEAD_OR_TFOOT: case TR: if (findLastInTableScope(name) == TreeBuilder.NOT_FOUND_ON_STACK) { assert name == "tbody" || name == "tfoot" || name == "thead" || fragment || isTemplateContents();
errStrayEndTag(name); break endtagloop;
}
closeTheCell(findLastInTableScopeTdTh()); continue; case BODY: case CAPTION: case COL: case COLGROUP: case HTML:
errStrayEndTag(name); break endtagloop; default: // fall through to IN_BODY
} // CPPONLY: MOZ_FALLTHROUGH; case FRAMESET_OK: case IN_BODY: switch (group) { case BODY: if (!isSecondOnStackBody()) { assert fragment || isTemplateContents();
errStrayEndTag(name); break endtagloop;
} assert currentPtr >= 1; if (errorHandler != null) {
uncloseloop1: for (int i = 2; i <= currentPtr; i++) { switch (stack[i].getGroup()) { case DD_OR_DT: case LI: case OPTGROUP: case OPTION: // is this possible? case P: case RB_OR_RTC: case RT_OR_RP: case TD_OR_TH: case TBODY_OR_THEAD_OR_TFOOT: break; default:
errEndWithUnclosedElements(name); break uncloseloop1;
}
}
}
mode = AFTER_BODY; break endtagloop; case HTML: if (!isSecondOnStackBody()) { assert fragment || isTemplateContents();
errStrayEndTag(name); break endtagloop;
} if (errorHandler != null) {
uncloseloop2: for (int i = 0; i <= currentPtr; i++) { switch (stack[i].getGroup()) { case DD_OR_DT: case LI: case P: case RB_OR_RTC: case RT_OR_RP: case TBODY_OR_THEAD_OR_TFOOT: case TD_OR_TH: case BODY: case HTML: break; default:
errEndWithUnclosedElements(name); break uncloseloop2;
}
}
}
mode = AFTER_BODY; continue; case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU: case UL_OR_OL_OR_DL: case PRE_OR_LISTING: case FIELDSET: case BUTTON: case ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIALOG_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SEARCH_OR_SECTION_OR_SUMMARY:
eltPos = findLastInScope(name); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
errStrayEndTag(name);
} else {
generateImpliedEndTags(); if (errorHandler != null && !isCurrent(name)) {
errUnclosedElements(eltPos, name);
} while (currentPtr >= eltPos) {
pop();
}
} break endtagloop; case FORM: 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;
} case P:
eltPos = findLastInButtonScope("p"); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
errNoElementToCloseButEndTagSeen("p"); // XXX Can the 'in foreign' case happen anymore? if (isInForeign()) {
errHtmlStartTagInForeignContext(name); // Check for currentPtr for the fragment // case. while (currentPtr >= 0 && stack[currentPtr].ns != "http://www.w3.org/1999/xhtml") {
pop();
}
}
appendVoidElementToCurrentMayFoster(
elementName,
HtmlAttributes.EMPTY_ATTRIBUTES); break endtagloop;
}
generateImpliedEndTagsExceptFor("p"); assert eltPos != TreeBuilder.NOT_FOUND_ON_STACK; if (errorHandler != null && eltPos != currentPtr) {
errUnclosedElements(eltPos, name);
} while (currentPtr >= eltPos) {
pop();
} break endtagloop; case LI:
eltPos = findLastInListScope(name); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
errNoElementToCloseButEndTagSeen(name);
} else {
generateImpliedEndTagsExceptFor(name); if (errorHandler != null
&& eltPos != currentPtr) {
errUnclosedElements(eltPos, name);
} while (currentPtr >= eltPos) {
pop();
}
} break endtagloop; case DD_OR_DT:
eltPos = findLastInScope(name); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
errNoElementToCloseButEndTagSeen(name);
} else {
generateImpliedEndTagsExceptFor(name); if (errorHandler != null
&& eltPos != currentPtr) {
errUnclosedElements(eltPos, name);
} while (currentPtr >= eltPos) {
pop();
}
} break endtagloop; case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6:
eltPos = findLastInScopeHn(); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
errStrayEndTag(name);
} else {
generateImpliedEndTags(); if (errorHandler != null && !isCurrent(name)) {
errUnclosedElements(eltPos, name);
} while (currentPtr >= eltPos) {
pop();
}
} break endtagloop; case OBJECT: case MARQUEE_OR_APPLET:
eltPos = findLastInScope(name); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
errStrayEndTag(name);
} else {
generateImpliedEndTags(); if (errorHandler != null && !isCurrent(name)) {
errUnclosedElements(eltPos, name);
} while (currentPtr >= eltPos) {
pop();
}
clearTheListOfActiveFormattingElementsUpToTheLastMarker();
} break endtagloop; case BR:
errEndTagBr(); if (isInForeign()) { // XXX can this happen anymore?
errHtmlStartTagInForeignContext(name); // Check for currentPtr for the fragment // case. while (currentPtr >= 0 && stack[currentPtr].ns != "http://www.w3.org/1999/xhtml") {
pop();
}
}
reconstructTheActiveFormattingElements();
appendVoidElementToCurrentMayFoster(
elementName,
HtmlAttributes.EMPTY_ATTRIBUTES); break endtagloop; case TEMPLATE: // fall through to IN_HEAD; break; case AREA_OR_WBR: case KEYGEN: // XXX?? case PARAM_OR_SOURCE_OR_TRACK: case EMBED: case IMG: case IMAGE: case INPUT: case HR: case IFRAME: case NOEMBED: // XXX??? case NOFRAMES: // XXX?? case SELECT: case TABLE: case TEXTAREA: // XXX??
errStrayEndTag(name); break endtagloop; case NOSCRIPT: if (scriptingEnabled) {
errStrayEndTag(name); break endtagloop;
} // CPPONLY: MOZ_FALLTHROUGH; 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 // CPPONLY: MOZ_FALLTHROUGH; default: if (isCurrent(name)) {
pop(); break endtagloop;
}
eltPos = currentPtr; for (;;) {
StackNode<T> node = stack[eltPos]; if (node.ns == "http://www.w3.org/1999/xhtml" && node.name == name) {
generateImpliedEndTags(); if (errorHandler != null
&& !isCurrent(name)) {
errUnclosedElements(eltPos, name);
} while (currentPtr >= eltPos) {
pop();
} break endtagloop;
} elseif (eltPos == 0 || node.isSpecial()) {
errStrayEndTag(name); break endtagloop;
}
eltPos--;
}
} // CPPONLY: MOZ_FALLTHROUGH; case IN_HEAD: switch (group) { case HEAD:
pop();
mode = AFTER_HEAD; break endtagloop; case BR: case HTML: case BODY:
pop();
mode = AFTER_HEAD; continue; case TEMPLATE:
endTagTemplateInHead(); break endtagloop; default:
errStrayEndTag(name); break endtagloop;
} case IN_HEAD_NOSCRIPT: switch (group) { case NOSCRIPT:
pop();
mode = IN_HEAD; break endtagloop; case BR:
errStrayEndTag(name);
pop();
mode = IN_HEAD; continue; default:
errStrayEndTag(name); break endtagloop;
} case IN_COLUMN_GROUP: switch (group) { case COLGROUP: if (currentPtr == 0 || stack[currentPtr].getGroup() ==
TreeBuilder.TEMPLATE) { assert fragment || isTemplateContents();
errGarbageInColgroup(); break endtagloop;
}
pop();
mode = IN_TABLE; break endtagloop; case COL:
errStrayEndTag(name); break endtagloop; case TEMPLATE:
endTagTemplateInHead(); break endtagloop; default: if (currentPtr == 0 || stack[currentPtr].getGroup() ==
TreeBuilder.TEMPLATE) { assert fragment || isTemplateContents();
errGarbageInColgroup(); break endtagloop;
}
pop();
mode = IN_TABLE; continue;
} case IN_SELECT_IN_TABLE: switch (group) { case CAPTION: case TABLE: case TBODY_OR_THEAD_OR_TFOOT: case TR: case TD_OR_TH:
errEndTagSeenWithSelectOpen(name); if (findLastInTableScope(name) != TreeBuilder.NOT_FOUND_ON_STACK) {
eltPos = findLastInTableScope("select"); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { assert fragment; break endtagloop; // http://www.w3.org/Bugs/Public/show_bug.cgi?id=8375
} while (currentPtr >= eltPos) {
pop();
}
resetTheInsertionMode(); continue;
} else { break endtagloop;
} default: // fall through to IN_SELECT
} // CPPONLY: MOZ_FALLTHROUGH; case IN_SELECT: switch (group) { case OPTION: if (isCurrent("option")) {
pop(); break endtagloop;
} else {
errStrayEndTag(name); break endtagloop;
} case OPTGROUP: if (isCurrent("option")
&& "optgroup" == stack[currentPtr - 1].name) {
pop();
} if (isCurrent("optgroup")) {
pop();
} else {
errStrayEndTag(name);
} break endtagloop; case SELECT:
eltPos = findLastInTableScope("select"); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { assert fragment;
errStrayEndTag(name); break endtagloop;
} while (currentPtr >= eltPos) {
pop();
}
resetTheInsertionMode(); break endtagloop; case TEMPLATE:
endTagTemplateInHead(); break endtagloop; default:
errStrayEndTag(name); break endtagloop;
} case AFTER_BODY: switch (group) { case HTML: if (fragment) {
errStrayEndTag(name); break endtagloop;
} else {
mode = AFTER_AFTER_BODY; break endtagloop;
} default:
errEndTagAfterBody();
mode = framesetOk ? FRAMESET_OK : IN_BODY; continue;
} case IN_FRAMESET: switch (group) { case FRAMESET: if (currentPtr == 0) { assert fragment;
errStrayEndTag(name); break endtagloop;
}
pop(); if ((!fragment) && !isCurrent("frameset")) {
mode = AFTER_FRAMESET;
} break endtagloop; default:
errStrayEndTag(name); break endtagloop;
} case AFTER_FRAMESET: switch (group) { case HTML:
mode = AFTER_AFTER_FRAMESET; break endtagloop; default:
errStrayEndTag(name); break endtagloop;
} case INITIAL: /* * Parse error.
*/
errEndTagSeenWithoutDoctype(); /* * * Set the document to quirks mode.
*/
documentModeInternal(DocumentMode.QUIRKS_MODE, null, null); /* * Then, switch to the root element mode of the tree * construction stage
*/
mode = BEFORE_HTML; /* * and reprocess the current token.
*/ continue; case BEFORE_HTML: switch (group) { case HEAD: case BR: case HTML: case BODY: /* * Create an HTMLElement node with the tag name * html, in the HTML namespace. Append it to the * Document object.
*/
appendHtmlElementToDocumentAndPush(); /* Switch to the main mode */
mode = BEFORE_HEAD; /* * reprocess the current token.
*/ continue; default:
errStrayEndTag(name); break endtagloop;
} case BEFORE_HEAD: switch (group) { case HEAD: case BR: case HTML: case BODY:
appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES);
mode = IN_HEAD; continue; default:
errStrayEndTag(name); break endtagloop;
} case AFTER_HEAD: switch (group) { case TEMPLATE:
endTagTemplateInHead(); break endtagloop; case HTML: case BODY: case BR:
appendToCurrentNodeAndPushBodyElement();
mode = FRAMESET_OK; continue; default:
errStrayEndTag(name); break endtagloop;
} case AFTER_AFTER_BODY:
errStrayEndTag(name);
mode = framesetOk ? FRAMESET_OK : IN_BODY; continue; case AFTER_AFTER_FRAMESET:
errStrayEndTag(name); break endtagloop; case TEXT: // XXX need to manage insertion point here
pop(); if (originalMode == AFTER_HEAD) {
silentPop();
}
mode = originalMode; break endtagloop;
}
} // endtagloop
}
privatevoid endTagTemplateInHead() throws SAXException { int eltPos = findLast("template"); if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) {
errStrayEndTag("template"); return;
}
generateImpliedEndTagsThoroughly(); if (errorHandler != null && !isCurrent("template")) {
errUnclosedElements(eltPos, "template");
} while (currentPtr >= eltPos) {
pop();
}
clearTheListOfActiveFormattingElementsUpToTheLastMarker();
popTemplateMode();
resetTheInsertionMode();
}
privateint findLastInTableScopeOrRootTemplateTbodyTheadTfoot() { for (int i = currentPtr; i > 0; i--) { if (stack[i].ns == "http://www.w3.org/1999/xhtml"
&& (stack[i].getGroup() == TreeBuilder.TBODY_OR_THEAD_OR_TFOOT
|| stack[i].getGroup() == TreeBuilder.TEMPLATE)) { return i;
}
} return 0;
}
privateint findLast(@Local String name) { for (int i = currentPtr; i > 0; i--) { if (stack[i].ns == "http://www.w3.org/1999/xhtml" && stack[i].name == name) { return i;
}
} return TreeBuilder.NOT_FOUND_ON_STACK;
}
privateint findLastInTableScope(@Local String name) { for (int i = currentPtr; i > 0; i--) { if (stack[i].ns == "http://www.w3.org/1999/xhtml") { if (stack[i].name == name) { return i;
} elseif (stack[i].name == "table" || stack[i].name == "template") { return TreeBuilder.NOT_FOUND_ON_STACK;
}
}
} return TreeBuilder.NOT_FOUND_ON_STACK;
}
privateint findLastInButtonScope(@Local String name) { for (int i = currentPtr; i > 0; i--) { if (stack[i].ns == "http://www.w3.org/1999/xhtml") { if (stack[i].name == name) { return i;
} elseif (stack[i].name == "button") { return TreeBuilder.NOT_FOUND_ON_STACK;
}
}
if (stack[i].isScoping()) { return TreeBuilder.NOT_FOUND_ON_STACK;
}
} return TreeBuilder.NOT_FOUND_ON_STACK;
}
privateint findLastInScope(@Local String name) { for (int i = currentPtr; i > 0; i--) { if (stack[i].ns == "http://www.w3.org/1999/xhtml" && stack[i].name == name) { return i;
} elseif (stack[i].isScoping()) { return TreeBuilder.NOT_FOUND_ON_STACK;
}
} return TreeBuilder.NOT_FOUND_ON_STACK;
}
privateint findLastInListScope(@Local String name) { for (int i = currentPtr; i > 0; i--) { if (stack[i].ns == "http://www.w3.org/1999/xhtml") { if (stack[i].name == name) { return i;
} elseif (stack[i].name == "ul" || stack[i].name == "ol") { return TreeBuilder.NOT_FOUND_ON_STACK;
}
}
if (stack[i].isScoping()) { return TreeBuilder.NOT_FOUND_ON_STACK;
}
} return TreeBuilder.NOT_FOUND_ON_STACK;
}
privateint findLastInScopeHn() { for (int i = currentPtr; i > 0; i--) { if (stack[i].getGroup() == TreeBuilder.H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) { return i;
} elseif (stack[i].isScoping()) { return TreeBuilder.NOT_FOUND_ON_STACK;
}
} return TreeBuilder.NOT_FOUND_ON_STACK;
}
privatevoid generateImpliedEndTagsExceptFor(@Local String name) throws SAXException { for (;;) {
StackNode<T> node = stack[currentPtr]; switch (node.getGroup()) { case P: case LI: case DD_OR_DT: case OPTION: case OPTGROUP: case RB_OR_RTC: case RT_OR_RP: if (node.ns == "http://www.w3.org/1999/xhtml" && node.name == name) { return;
}
pop(); continue; default: return;
}
}
}
privatevoid generateImpliedEndTags() throws SAXException { for (;;) { switch (stack[currentPtr].getGroup()) { case P: case LI: case DD_OR_DT: case OPTION: case OPTGROUP: case RB_OR_RTC: case RT_OR_RP:
pop(); continue; default: return;
}
}
}
privatevoid generateImpliedEndTagsThoroughly() throws SAXException { for (;;) { switch (stack[currentPtr].getGroup()) { case CAPTION: case COLGROUP: case DD_OR_DT: case LI: case OPTGROUP: case OPTION: case P: case RB_OR_RTC: case RT_OR_RP: case TBODY_OR_THEAD_OR_TFOOT: case TD_OR_TH: case TR:
pop(); continue; default: return;
}
}
}
/** * Adoption agency algorithm. * * @param name subject as described in the specified algorithm. * @return Returns true if the algorithm has completed and there is nothing remaining to * be done. Returns false if the algorithm needs to "act as described in the 'any other * end tag' entry" as described in the specified algorithm. * @throws SAXException
*/ privateboolean adoptionAgencyEndTag(@Local String name) throws SAXException { // This check intends to ensure that for properly nested tags, closing tags will match // against the stack instead of the listOfActiveFormattingElements. if (stack[currentPtr].ns == "http://www.w3.org/1999/xhtml" &&
stack[currentPtr].name == name &&
findInListOfActiveFormattingElements(stack[currentPtr]) == -1) { // If the current element matches the name but isn't on the list of active // formatting elements, then it is possible that the list was mangled by the Noah's Ark // clause. In this case, we want to match the end tag against the stack instead of // proceeding with the AAA algorithm that may match against the list of // active formatting elements (and possibly mangle the tree in unexpected ways).
pop(); returntrue;
}
// If you crash around here, perhaps some stack node variable claimed to // be a weak ref isn't. for (int i = 0; i < 8; ++i) { int formattingEltListPos = listPtr; while (formattingEltListPos > -1) {
StackNode<T> listNode = listOfActiveFormattingElements[formattingEltListPos]; // weak ref if (listNode == null) {
formattingEltListPos = -1; break;
} elseif (listNode.name == name) { break;
}
formattingEltListPos--;
} if (formattingEltListPos == -1) { returnfalse;
} // this *looks* like a weak ref to the list of formatting elements
StackNode<T> formattingElt = listOfActiveFormattingElements[formattingEltListPos]; int formattingEltStackPos = currentPtr; boolean inScope = true; while (formattingEltStackPos > -1) {
StackNode<T> node = stack[formattingEltStackPos]; // weak ref if (node == formattingElt) { break;
} elseif (node.isScoping()) {
inScope = false;
}
formattingEltStackPos--;
} if (formattingEltStackPos == -1) {
errNoElementToCloseButEndTagSeen(name);
removeFromListOfActiveFormattingElements(formattingEltListPos); returntrue;
} if (!inScope) {
errNoElementToCloseButEndTagSeen(name); returntrue;
} // stackPos now points to the formatting element and it is in scope if (formattingEltStackPos != currentPtr) {
errEndTagViolatesNestingRules(name);
} int furthestBlockPos = formattingEltStackPos + 1; while (furthestBlockPos <= currentPtr) {
StackNode<T> node = stack[furthestBlockPos]; // weak ref assert furthestBlockPos > 0: "How is formattingEltStackPos + 1 not > 0?"; if (node.isSpecial()) { break;
}
furthestBlockPos++;
} if (furthestBlockPos > currentPtr) { // no furthest block while (currentPtr >= formattingEltStackPos) {
pop();
}
removeFromListOfActiveFormattingElements(formattingEltListPos); returntrue;
} // commonAncestor is used for running the algorithm and // insertionCommonAncestor is used for the actual insertions to // keep them depth-limited.
StackNode<T> commonAncestor = stack[formattingEltStackPos - 1]; // weak ref
T insertionCommonAncestor = nodeFromStackWithBlinkCompat(formattingEltStackPos - 1); // weak ref
StackNode<T> furthestBlock = stack[furthestBlockPos]; // weak ref // detachFromParent(furthestBlock.node); XXX AAA CHANGE int bookmark = formattingEltListPos; int nodePos = furthestBlockPos;
StackNode<T> lastNode = furthestBlock; // weak ref int j = 0; for (;;) {
++j;
nodePos--; if (nodePos == formattingEltStackPos) { break;
}
StackNode<T> node = stack[nodePos]; // weak ref int nodeListPos = findInListOfActiveFormattingElements(node);
if (j > 3 && nodeListPos != -1) {
removeFromListOfActiveFormattingElements(nodeListPos);
// Adjust the indices into the list to account // for the removal of nodeListPos. if (nodeListPos <= formattingEltListPos) {
formattingEltListPos--;
} if (nodeListPos <= bookmark) {
bookmark--;
}
// Update position to reflect removal from list.
nodeListPos = -1;
}
if (nodeListPos == -1) { assert formattingEltStackPos < nodePos; assert bookmark < nodePos; assert furthestBlockPos > nodePos;
removeFromStack(nodePos); // node is now a bad pointer in C++
furthestBlockPos--; continue;
} // now node is both on stack and in the list if (nodePos == furthestBlockPos) {
bookmark = nodeListPos + 1;
} // if (hasChildren(node.node)) { XXX AAA CHANGE assert node == listOfActiveFormattingElements[nodeListPos]; assert node == stack[nodePos];
T clone = createElement("http://www.w3.org/1999/xhtml",
node.name, node.attributes.cloneAttributes(), insertionCommonAncestor // CPPONLY: , htmlCreator(node.getHtmlCreator())
);
StackNode<T> newNode = createStackNode(node.getFlags(), node.ns,
node.name, clone, node.popName, node.attributes // CPPONLY: , node.getHtmlCreator() // [NOCPP[
, node.getLocator() // ]NOCPP]
); // creation ownership goes to stack
node.dropAttributes(); // adopt ownership to newNode
stack[nodePos] = newNode;
newNode.retain(); // retain for list
listOfActiveFormattingElements[nodeListPos] = newNode;
node.release(this); // release from stack
node.release(this); // release from list
node = newNode; // } XXX AAA CHANGE
detachFromParent(lastNode.node);
appendElement(lastNode.node, nodeFromStackWithBlinkCompat(nodePos));
lastNode = node;
} // If we insert into a foster parent, for simplicity, we insert // accoding to the spec without Blink's depth limit. if (commonAncestor.isFosterParenting()) {
fatal();
detachFromParent(lastNode.node);
insertIntoFosterParent(lastNode.node);
} else {
detachFromParent(lastNode.node);
appendElement(lastNode.node, insertionCommonAncestor);
}
T clone = createElement("http://www.w3.org/1999/xhtml",
formattingElt.name,
formattingElt.attributes.cloneAttributes(), furthestBlock.node // CPPONLY: , htmlCreator(formattingElt.getHtmlCreator())
);
StackNode<T> formattingClone = createStackNode(
formattingElt.getFlags(), formattingElt.ns,
formattingElt.name, clone, formattingElt.popName,
formattingElt.attributes // CPPONLY: , formattingElt.getHtmlCreator() // [NOCPP[
, errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) // ]NOCPP]
); // Ownership transfers to stack below
formattingElt.dropAttributes(); // transfer ownership to // formattingClone
appendChildrenToNewParent(furthestBlock.node, clone);
appendElement(clone, furthestBlock.node);
removeFromListOfActiveFormattingElements(formattingEltListPos);
insertIntoListOfActiveFormattingElements(formattingClone, bookmark); assert formattingEltStackPos < furthestBlockPos;
removeFromStack(formattingEltStackPos); // furthestBlockPos is now off by one and points to the slot after // it
insertIntoStack(formattingClone, furthestBlockPos);
} returntrue;
}
entry.dropAttributes(); // transfer ownership to entryClone
push(entryClone); // stack takes ownership of the local variable
listOfActiveFormattingElements[entryPos] = entryClone; // overwriting the old entry on the list, so release & retain
entry.release(this);
entryClone.retain();
}
}
void notifyUnusedStackNode(int idxInStackNodes) { // stackNodesIdx is the earliest possible index of a stack node that might be unused, // so update the index if necessary. if (idxInStackNodes < stackNodesIdx) {
stackNodesIdx = idxInStackNodes;
}
}
@SuppressWarnings("unchecked") private StackNode<T> getUnusedStackNode() { // Search for an unused stack node. while (stackNodesIdx < numStackNodes) { if (stackNodes[stackNodesIdx].isUnused()) { return stackNodes[stackNodesIdx++];
}
stackNodesIdx++;
}
if (stackNodesIdx < stackNodes.length) { // No unused stack nodes, but there is still space in the storage array.
stackNodes[stackNodesIdx] = new StackNode<T>(stackNodesIdx);
numStackNodes++; return stackNodes[stackNodesIdx++];
}
// Could not find an unused stack node and storage array is full.
StackNode<T>[] newStack = new StackNode[stackNodes.length + 64];
System.arraycopy(stackNodes, 0, newStack, 0, stackNodes.length);
stackNodes = newStack;
// Create a new stack node and return it.
stackNodes[stackNodesIdx] = new StackNode<T>(stackNodesIdx);
numStackNodes++; return stackNodes[stackNodesIdx++];
}
// [NOCPP[ privatevoid checkAttributes(HtmlAttributes attributes, @NsUri String ns) throws SAXException { if (errorHandler != null) { int len = attributes.getXmlnsLength(); for (int i = 0; i < len; i++) {
AttributeName name = attributes.getXmlnsAttributeName(i); if (name == AttributeName.XMLNS) {
String xmlns = attributes.getXmlnsValue(i); if (!ns.equals(xmlns)) {
err("Bad value \u201C"
+ xmlns
+ "\u201D for the attribute \u201Cxmlns\u201D (only \u201C"
+ ns + "\u201D permitted here)."); switch (namePolicy) { case ALTER_INFOSET: // fall through case ALLOW:
warn("Attribute \u201Cxmlns\u201D is not serializable as XML 1.0."); break; case FATAL:
fatal("Attribute \u201Cxmlns\u201D is not serializable as XML 1.0."); break;
}
}
} elseif (ns != "http://www.w3.org/1999/xhtml"
&& name == AttributeName.XMLNS_XLINK) {
String xmlns = attributes.getXmlnsValue(i); if (!"http://www.w3.org/1999/xlink".equals(xmlns)) {
err("Bad value \u201C"
+ xmlns
+ "\u201D for the attribute \u201Cxmlns:link\u201D (only \u201Chttp://www.w3.org/1999/xlink\u201D permitted here)."); switch (namePolicy) { case ALTER_INFOSET: // fall through case ALLOW:
warn("Attribute \u201Cxmlns:xlink\u201D with a value other than \u201Chttp://www.w3.org/1999/xlink\u201D is not serializable as XML 1.0 without changing document semantics."); break; case FATAL:
fatal("Attribute \u201Cxmlns:xlink\u201D with a value other than \u201Chttp://www.w3.org/1999/xlink\u201D is not serializable as XML 1.0 without changing document semantics."); break;
}
}
} else {
err("Attribute \u201C" + attributes.getXmlnsLocalName(i)
+ "\u201D not allowed here."); switch (namePolicy) { case ALTER_INFOSET: // fall through case ALLOW:
warn("Attribute with the local name \u201C"
+ attributes.getXmlnsLocalName(i)
+ "\u201D is not serializable as XML 1.0."); break; case FATAL:
fatal("Attribute with the local name \u201C"
+ attributes.getXmlnsLocalName(i)
+ "\u201D is not serializable as XML 1.0."); break;
}
}
}
}
attributes.processNonNcNames(this, namePolicy);
}
private String checkPopName(@Local String name) throws SAXException { if (NCName.isNCName(name)) { return name;
} else { switch (namePolicy) { case ALLOW:
warn("Element name \u201C" + name
+ "\u201D cannot be represented as XML 1.0."); return name; case ALTER_INFOSET:
warn("Element name \u201C" + name
+ "\u201D cannot be represented as XML 1.0."); return NCName.escapeName(name); case FATAL:
fatal("Element name \u201C" + name
+ "\u201D cannot be represented as XML 1.0.");
}
} returnnull; // keep compiler happy
}
@Override publicvoid ensureBufferSpace(int inputLength) throws SAXException { // TODO: Unify Tokenizer.strBuf and TreeBuilder.charBuffer so that // this method becomes unnecessary. int worstCase = charBufferLen + inputLength; if (charBuffer == null) { // Add an arbitrary small value to avoid immediate reallocation // once there are a few characters in the buffer.
charBuffer = newchar[worstCase + 128];
} elseif (worstCase > charBuffer.length) { // HotSpot reportedly allocates memory with 8-byte accuracy, so // there's no point in trying to do math here to avoid slop. // Maybe we should add some small constant to worstCase here // but not doing that without profiling. In C++ with jemalloc, // the corresponding method should do math to round up here // to avoid slop. char[] newBuf = newchar[worstCase];
System.arraycopy(charBuffer, 0, newBuf, 0, charBufferLen);
charBuffer = newBuf;
}
}
// ]NOCPP]
protectedvoid accumulateCharacters(@Const @NoLength char[] buf, int start, int length) throws SAXException {
appendCharacters(stack[currentPtr].node, buf, start, length);
}
protectedabstractvoid appendElement(T child, T newParent) throws SAXException;
protectedabstractvoid appendChildrenToNewParent(T oldParent, T newParent) throws SAXException;
protectedabstractvoid insertFosterParentedChild(T child, T table,
T stackParent) throws SAXException;
// We don't generate CPP code for this method because it is not used in generated CPP // code. Instead, the form owner version of this method is called with a null form owner. // [NOCPP[
protectedabstract T createAndInsertFosterParentedElement(@NsUri String ns, @Local String name,
HtmlAttributes attributes, T table, T stackParent) throws SAXException;
// ]NOCPP]
protected T createAndInsertFosterParentedElement(@NsUri String ns, @Local String name,
HtmlAttributes attributes, T form, T table, T stackParent // CPPONLY: , @Creator Object creator
) throws SAXException { return createAndInsertFosterParentedElement(ns, name, attributes, table, stackParent);
};
protectedabstractvoid insertFosterParentedCharacters(
@NoLength char[] buf, int start, int length, T table, T stackParent) throws SAXException;
protectedabstractvoid appendCharacters(T parent, @NoLength char[] buf, int start, int length) throws SAXException;
protectedabstractvoid appendComment(T parent, @NoLength char[] buf, int start, int length) throws SAXException;
protectedabstractvoid appendCommentToDocument(@NoLength char[] buf, int start, int length) throws SAXException;
privateint findInArray(StackNode<T> node, StackNode<T>[] arr) { for (int i = listPtr; i >= 0; i--) { if (node == arr[i]) { return i;
}
} return -1;
}
/** * Returns <code>stack[stackPos].node</code> if <code>stackPos</code> is * smaller than Blink's magic limit or the node at Blink's magic limit * otherwise. * * In order to get Blink-compatible handling of excessive deeply-nested * markup, this method must be used to obtain the node that is used as the * parent node of an insertion. * * Blink's magic number is 512, but our counting is off by one compared to * Blink's way of counting, so in order to get the same * externally-observable outcome, we use 511 as our magic number. * * @param stackPos the stack position to attempt to read * @return node at the position capped to Blink's magic number * @throws SAXException
*/ private T nodeFromStackWithBlinkCompat(int stackPos) throws SAXException { // Magic number if off by one relative to Blink's magic number, but the // outcome is the same, because the counting is different by one. if (stackPos > 511) {
errDeepTree(); return stack[511].node;
} return stack[stackPos].node;
} /** * @see nu.validator.htmlparser.impl.TreeBuilderState#getFormPointer()
*/
@Override public T getFormPointer() { return formPointer;
}
/** * Returns the headPointer. * * @return the headPointer
*/
@Override public T getHeadPointer() { return headPointer;
}
/** * Complains about an over-deep tree. Theoretically this should just be * a warning, but in practice authors should take this as an error. * * @throws SAXException
*/ privatevoid errDeepTree() throws SAXException {
err("The document tree is more than 513 elements deep, which causes Firefox and Chrome to flatten the tree.");
}
/** * Reports a stray start tag. * @param name the name of the stray tag * * @throws SAXException
*/ privatevoid errStrayStartTag(@Local String name) throws SAXException {
err("Stray start tag \u201C" + name + "\u201D.");
}
/** * Reports a stray end tag. * @param name the name of the stray tag * * @throws SAXException
*/ privatevoid errStrayEndTag(@Local String name) throws SAXException {
err("Stray end tag \u201C" + name + "\u201D.");
}
/** * Reports a state when elements expected to be closed were not. * * @param eltPos the position of the start tag on the stack of the element * being closed. * @param name the name of the end tag * * @throws SAXException
*/ privatevoid errUnclosedElements(int eltPos, @Local String name) throws SAXException {
errNoCheck("End tag \u201C" + name + "\u201D seen, but there were open elements.");
errListUnclosedStartTags(eltPos);
}
/** * Reports a state when elements expected to be closed ahead of an implied * end tag but were not. * * @param eltPos the position of the start tag on the stack of the element * being closed. * @param name the name of the end tag * * @throws SAXException
*/ privatevoid errUnclosedElementsImplied(int eltPos, String name) throws SAXException {
errNoCheck("End tag \u201C" + name + "\u201D implied, but there were open elements.");
errListUnclosedStartTags(eltPos);
}
/** * Reports a state when elements expected to be closed ahead of an implied * table cell close. * * @param eltPos the position of the start tag on the stack of the element * being closed. * @throws SAXException
*/ privatevoid errUnclosedElementsCell(int eltPos) throws SAXException {
errNoCheck("A table cell was implicitly closed, but there were open elements.");
errListUnclosedStartTags(eltPos);
}
privatevoid errFooBetweenHeadAndBody(@Local String name) throws SAXException { if (errorHandler == null) { return;
}
errNoCheck("\u201C" + name + "\u201D element between \u201Chead\u201D and \u201Cbody\u201D.");
}
privatevoid errStartTagWithoutDoctype() throws SAXException { if (!forceNoQuirks) {
err("Start tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D.");
}
}
privatevoid errStartSelectWhereEndSelectExpected() throws SAXException {
err("\u201Cselect\u201D start tag where end tag expected.");
}
privatevoid errStartTagWithSelectOpen(@Local String name) throws SAXException { if (errorHandler == null) { return;
}
errNoCheck("\u201C" + name
+ "\u201D start tag with \u201Cselect\u201D open.");
}
privatevoid errBadStartTagInNoscriptInHead(@Local String name) throws SAXException { if (errorHandler == null) { return;
}
errNoCheck("Bad start tag in \u201C" + name
+ "\u201D in \u201Cnoscript\u201D in \u201Chead\u201D.");
}
privatevoid errImage() throws SAXException {
err("Saw a start tag \u201Cimage\u201D.");
}
privatevoid errFooSeenWhenFooOpen(@Local String name) throws SAXException { if (errorHandler == null) { return;
}
errNoCheck("Start tag \u201C" + name + "\u201D seen but an element of the same type was already open.");
}
privatevoid errHeadingWhenHeadingOpen() throws SAXException {
err("Heading cannot be a child of another heading.");
}
privatevoid errFramesetStart() throws SAXException {
err("\u201Cframeset\u201D start tag seen.");
}
privatevoid errNoCellToClose() throws SAXException {
err("No cell to close.");
}
privatevoid errStartTagInTable(@Local String name) throws SAXException { if (errorHandler == null) { return;
}
errNoCheck("Start tag \u201C" + name
+ "\u201D seen in \u201Ctable\u201D.");
}
privatevoid errFormWhenFormOpen() throws SAXException {
err("Saw a \u201Cform\u201D start tag, but there was already an active \u201Cform\u201D element. Nested forms are not allowed. Ignoring the tag.");
}
privatevoid errTableSeenWhileTableOpen() throws SAXException {
err("Start tag for \u201Ctable\u201D seen but the previous \u201Ctable\u201D is still open.");
}
privatevoid errStartTagInTableBody(@Local String name) throws SAXException { if (errorHandler == null) { return;
}
errNoCheck("\u201C" + name + "\u201D start tag in table body.");
}
privatevoid errEndTagSeenWithoutDoctype() throws SAXException { if (!forceNoQuirks) {
err("End tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D.");
}
}
privatevoid errEndTagAfterBody() throws SAXException {
err("Saw an end tag after \u201Cbody\u201D had been closed.");
}
privatevoid errEndTagSeenWithSelectOpen(@Local String name) throws SAXException { if (errorHandler == null) { return;
}
errNoCheck("\u201C" + name
+ "\u201D end tag with \u201Cselect\u201D open.");
}
privatevoid errGarbageInColgroup() throws SAXException {
err("Garbage in \u201Ccolgroup\u201D fragment.");
}
privatevoid errEndTagBr() throws SAXException {
err("End tag \u201Cbr\u201D.");
}
privatevoid errNoElementToCloseButEndTagSeen(@Local String name) throws SAXException { if (errorHandler == null) { return;
}
errNoCheck("No \u201C" + name + "\u201D element in scope but a \u201C"
+ name + "\u201D end tag seen.");
}
privatevoid errHtmlStartTagInForeignContext(@Local String name) throws SAXException { if (errorHandler == null) { return;
}
errNoCheck("HTML start tag \u201C" + name
+ "\u201D in a foreign namespace context.");
}
privatevoid errUnclosedChildrenInRuby() throws SAXException { if (errorHandler == null) { return;
}
errNoCheck("Unclosed children in \u201Cruby\u201D.");
}
privatevoid errStartTagSeenWithoutRuby(@Local String name) throws SAXException { if (errorHandler == null) { return;
}
errNoCheck("Start tag \u201C"
+ name
+ "\u201D seen without a \u201Cruby\u201D element being open.");
}
privatevoid errSelfClosing() throws SAXException { if (errorHandler == null) { return;
}
errNoCheck("Self-closing syntax (\u201C/>\u201D) used on a non-void HTML element. Ignoring the slash and treating as a start tag.");
}
privatevoid errNoCheckUnclosedElementsOnStack() throws SAXException {
errNoCheck("Unclosed elements on stack.");
}
privatevoid errEndTagDidNotMatchCurrentOpenElement(@Local String name,
@Local String currOpenName) throws SAXException { if (errorHandler == null) { return;
}
errNoCheck("End tag \u201C"
+ name
+ "\u201D did not match the name of the current open element (\u201C"
+ currOpenName + "\u201D).");
}
privatevoid errEndTagViolatesNestingRules(@Local String name) throws SAXException { if (errorHandler == null) { return;
}
errNoCheck("End tag \u201C" + name + "\u201D violates nesting rules.");
}
privatevoid errEofWithUnclosedElements() throws SAXException { if (errorHandler == null) { return;
}
errNoCheck("End of file seen and there were open elements."); // just report all remaining unclosed elements
errListUnclosedStartTags(0);
}
/** * Reports arriving at/near end of document with unclosed elements remaining. * * @param message * the message * @throws SAXException
*/ privatevoid errEndWithUnclosedElements(@Local String name) throws SAXException { if (errorHandler == null) { return;
}
errNoCheck("End tag for \u201C"
+ name
+ "\u201D seen, but there were unclosed elements."); // just report all remaining unclosed elements
errListUnclosedStartTags(0);
}
}
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.360Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-04-26)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.