summaryrefslogtreecommitdiffstats
path: root/parser/html/nsHtml5TreeBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'parser/html/nsHtml5TreeBuilder.cpp')
-rw-r--r--parser/html/nsHtml5TreeBuilder.cpp4776
1 files changed, 4776 insertions, 0 deletions
diff --git a/parser/html/nsHtml5TreeBuilder.cpp b/parser/html/nsHtml5TreeBuilder.cpp
new file mode 100644
index 0000000000..af29910501
--- /dev/null
+++ b/parser/html/nsHtml5TreeBuilder.cpp
@@ -0,0 +1,4776 @@
+/*
+ * 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.
+ */
+
+/*
+ * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
+ * Please edit TreeBuilder.java instead and regenerate.
+ */
+
+#define nsHtml5TreeBuilder_cpp__
+
+#include "nsHtml5AttributeName.h"
+#include "nsHtml5ElementName.h"
+#include "nsHtml5Tokenizer.h"
+#include "nsHtml5StackNode.h"
+#include "nsHtml5UTF16Buffer.h"
+#include "nsHtml5StateSnapshot.h"
+#include "nsHtml5Portability.h"
+
+#include "nsHtml5TreeBuilder.h"
+
+char16_t nsHtml5TreeBuilder::REPLACEMENT_CHARACTER[] = {0xfffd};
+static const char* const QUIRKY_PUBLIC_IDS_DATA[] = {
+ "+//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//"};
+staticJArray<const char*, int32_t> nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS = {
+ QUIRKY_PUBLIC_IDS_DATA, MOZ_ARRAY_LENGTH(QUIRKY_PUBLIC_IDS_DATA)};
+void nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self) {
+ tokenizer = self;
+ stackNodes = jArray<nsHtml5StackNode*, int32_t>::newJArray(64);
+ stack = jArray<nsHtml5StackNode*, int32_t>::newJArray(64);
+ templateModeStack = jArray<int32_t, int32_t>::newJArray(64);
+ listOfActiveFormattingElements =
+ jArray<nsHtml5StackNode*, int32_t>::newJArray(64);
+ needToDropLF = false;
+ originalMode = INITIAL;
+ templateModePtr = -1;
+ stackNodesIdx = 0;
+ numStackNodes = 0;
+ currentPtr = -1;
+ listPtr = -1;
+ formPointer = nullptr;
+ headPointer = nullptr;
+ start(fragment);
+ charBufferLen = 0;
+ charBuffer = nullptr;
+ framesetOk = true;
+ if (fragment) {
+ nsIContentHandle* elt;
+ if (contextNode) {
+ elt = contextNode;
+ } else {
+ elt = createHtmlElementSetAsRoot(tokenizer->emptyAttributes());
+ }
+ if (contextNamespace == kNameSpaceID_SVG) {
+ nsHtml5ElementName* elementName = nsHtml5ElementName::ELT_SVG;
+ if (nsGkAtoms::title == contextName || nsGkAtoms::desc == contextName ||
+ nsGkAtoms::foreignObject == contextName) {
+ elementName = nsHtml5ElementName::ELT_FOREIGNOBJECT;
+ }
+ nsHtml5StackNode* node =
+ createStackNode(elementName, elementName->getCamelCaseName(), elt);
+ currentPtr++;
+ stack[currentPtr] = node;
+ tokenizer->setState(nsHtml5Tokenizer::DATA);
+ mode = FRAMESET_OK;
+ } else if (contextNamespace == kNameSpaceID_MathML) {
+ nsHtml5ElementName* elementName = nsHtml5ElementName::ELT_MATH;
+ if (nsGkAtoms::mi_ == contextName || nsGkAtoms::mo_ == contextName ||
+ nsGkAtoms::mn_ == contextName || nsGkAtoms::ms_ == contextName ||
+ nsGkAtoms::mtext_ == contextName) {
+ elementName = nsHtml5ElementName::ELT_MTEXT;
+ } else if (nsGkAtoms::annotation_xml_ == contextName) {
+ elementName = nsHtml5ElementName::ELT_ANNOTATION_XML;
+ }
+ nsHtml5StackNode* node =
+ createStackNode(elementName, elt, elementName->getName(), false);
+ currentPtr++;
+ stack[currentPtr] = node;
+ tokenizer->setState(nsHtml5Tokenizer::DATA);
+ mode = FRAMESET_OK;
+ } else {
+ nsHtml5StackNode* node =
+ createStackNode(nsHtml5ElementName::ELT_HTML, elt);
+ currentPtr++;
+ stack[currentPtr] = node;
+ if (nsGkAtoms::_template == contextName) {
+ pushTemplateMode(IN_TEMPLATE);
+ }
+ resetTheInsertionMode();
+ formPointer = getFormPointerForContext(contextNode);
+ if (nsGkAtoms::title == contextName ||
+ nsGkAtoms::textarea == contextName) {
+ tokenizer->setState(nsHtml5Tokenizer::RCDATA);
+ } else if (nsGkAtoms::style == contextName ||
+ nsGkAtoms::xmp == contextName ||
+ nsGkAtoms::iframe == contextName ||
+ nsGkAtoms::noembed == contextName ||
+ nsGkAtoms::noframes == contextName ||
+ (scriptingEnabled && nsGkAtoms::noscript == contextName)) {
+ tokenizer->setState(nsHtml5Tokenizer::RAWTEXT);
+ } else if (nsGkAtoms::plaintext == contextName) {
+ tokenizer->setState(nsHtml5Tokenizer::PLAINTEXT);
+ } else if (nsGkAtoms::script == contextName) {
+ tokenizer->setState(nsHtml5Tokenizer::SCRIPT_DATA);
+ } else {
+ tokenizer->setState(nsHtml5Tokenizer::DATA);
+ }
+ }
+ } else {
+ mode = INITIAL;
+ if (tokenizer->isViewingXmlSource()) {
+ nsIContentHandle* elt = createElement(
+ kNameSpaceID_SVG, nsGkAtoms::svg, tokenizer->emptyAttributes(),
+ nullptr, svgCreator(NS_NewSVGSVGElement));
+ nsHtml5StackNode* node =
+ createStackNode(nsHtml5ElementName::ELT_SVG, nsGkAtoms::svg, elt);
+ currentPtr++;
+ stack[currentPtr] = node;
+ }
+ }
+}
+
+void nsHtml5TreeBuilder::doctype(nsAtom* name, nsHtml5String publicIdentifier,
+ nsHtml5String systemIdentifier,
+ bool forceQuirks) {
+ needToDropLF = false;
+ if (!isInForeign() && mode == INITIAL) {
+ nsHtml5String emptyString = nsHtml5Portability::newEmptyString();
+ appendDoctypeToDocument(!name ? nsGkAtoms::_empty : name,
+ !publicIdentifier ? emptyString : publicIdentifier,
+ !systemIdentifier ? emptyString : systemIdentifier);
+ emptyString.Release();
+ if (isQuirky(name, publicIdentifier, systemIdentifier, forceQuirks)) {
+ errQuirkyDoctype();
+ documentModeInternal(QUIRKS_MODE, publicIdentifier, systemIdentifier);
+ } else if (isAlmostStandards(publicIdentifier, systemIdentifier)) {
+ errAlmostStandardsDoctype();
+ documentModeInternal(ALMOST_STANDARDS_MODE, publicIdentifier,
+ systemIdentifier);
+ } else {
+ documentModeInternal(STANDARDS_MODE, publicIdentifier, systemIdentifier);
+ }
+ mode = BEFORE_HTML;
+ return;
+ }
+ errStrayDoctype();
+ return;
+}
+
+void nsHtml5TreeBuilder::comment(char16_t* buf, int32_t start, int32_t length) {
+ needToDropLF = false;
+ if (!isInForeign()) {
+ switch (mode) {
+ case INITIAL:
+ case BEFORE_HTML:
+ case AFTER_AFTER_BODY:
+ case AFTER_AFTER_FRAMESET: {
+ appendCommentToDocument(buf, start, length);
+ return;
+ }
+ case AFTER_BODY: {
+ flushCharacters();
+ appendComment(stack[0]->node, buf, start, length);
+ return;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ flushCharacters();
+ appendComment(stack[currentPtr]->node, buf, start, length);
+ return;
+}
+
+void nsHtml5TreeBuilder::characters(const char16_t* buf, int32_t start,
+ int32_t length) {
+ if (tokenizer->isViewingXmlSource()) {
+ return;
+ }
+ if (needToDropLF) {
+ needToDropLF = false;
+ if (buf[start] == '\n') {
+ start++;
+ length--;
+ if (!length) {
+ return;
+ }
+ }
+ }
+ switch (mode) {
+ case IN_BODY:
+ case IN_CELL:
+ case IN_CAPTION: {
+ if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
+ reconstructTheActiveFormattingElements();
+ }
+ [[fallthrough]];
+ }
+ case TEXT: {
+ accumulateCharacters(buf, start, length);
+ return;
+ }
+ case IN_TABLE:
+ case IN_TABLE_BODY:
+ case IN_ROW: {
+ accumulateCharactersForced(buf, start, length);
+ return;
+ }
+ default: {
+ int32_t end = start + length;
+ for (int32_t i = start; i < end; i++) {
+ switch (buf[i]) {
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ case '\f': {
+ switch (mode) {
+ case INITIAL:
+ case BEFORE_HTML:
+ case BEFORE_HEAD: {
+ start = i + 1;
+ continue;
+ }
+ case IN_HEAD:
+ case IN_HEAD_NOSCRIPT:
+ case AFTER_HEAD:
+ case IN_COLUMN_GROUP:
+ case IN_FRAMESET:
+ case AFTER_FRAMESET: {
+ 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;
+ }
+ if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
+ flushCharacters();
+ reconstructTheActiveFormattingElements();
+ }
+ NS_HTML5_BREAK(charactersloop);
+ }
+ case IN_SELECT:
+ case IN_SELECT_IN_TABLE: {
+ NS_HTML5_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;
+ }
+ flushCharacters();
+ reconstructTheActiveFormattingElements();
+ continue;
+ }
+ }
+ MOZ_FALLTHROUGH_ASSERT();
+ }
+ default: {
+ switch (mode) {
+ case INITIAL: {
+ documentModeInternal(QUIRKS_MODE, nullptr, nullptr);
+ mode = BEFORE_HTML;
+ i--;
+ continue;
+ }
+ case BEFORE_HTML: {
+ appendHtmlElementToDocumentAndPush();
+ mode = BEFORE_HEAD;
+ i--;
+ continue;
+ }
+ case BEFORE_HEAD: {
+ if (start < i) {
+ accumulateCharacters(buf, start, i - start);
+ start = i;
+ }
+ flushCharacters();
+ appendToCurrentNodeAndPushHeadElement(
+ nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
+ mode = IN_HEAD;
+ i--;
+ continue;
+ }
+ case IN_HEAD: {
+ if (start < i) {
+ accumulateCharacters(buf, start, i - start);
+ start = i;
+ }
+ flushCharacters();
+ pop();
+ mode = AFTER_HEAD;
+ i--;
+ continue;
+ }
+ case IN_HEAD_NOSCRIPT: {
+ if (start < i) {
+ accumulateCharacters(buf, start, i - start);
+ start = i;
+ }
+ errNonSpaceInNoscriptInHead();
+ flushCharacters();
+ pop();
+ mode = IN_HEAD;
+ i--;
+ continue;
+ }
+ case AFTER_HEAD: {
+ if (start < i) {
+ accumulateCharacters(buf, start, i - start);
+ start = i;
+ }
+ flushCharacters();
+ appendToCurrentNodeAndPushBodyElement();
+ mode = FRAMESET_OK;
+ 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;
+ }
+ if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
+ flushCharacters();
+ reconstructTheActiveFormattingElements();
+ }
+ NS_HTML5_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;
+ }
+ if (!currentPtr || stack[currentPtr]->getGroup() ==
+ nsHtml5TreeBuilder::TEMPLATE) {
+ errNonSpaceInColgroupInFragment();
+ start = i + 1;
+ continue;
+ }
+ flushCharacters();
+ pop();
+ mode = IN_TABLE;
+ i--;
+ continue;
+ }
+ case IN_SELECT:
+ case IN_SELECT_IN_TABLE: {
+ NS_HTML5_BREAK(charactersloop);
+ }
+ case AFTER_BODY: {
+ errNonSpaceAfterBody();
+
+ mode = framesetOk ? FRAMESET_OK : IN_BODY;
+ i--;
+ continue;
+ }
+ case IN_FRAMESET: {
+ if (start < i) {
+ accumulateCharacters(buf, start, i - start);
+ }
+ errNonSpaceInFrameset();
+ start = i + 1;
+ continue;
+ }
+ case AFTER_FRAMESET: {
+ if (start < i) {
+ accumulateCharacters(buf, start, i - start);
+ }
+ errNonSpaceAfterFrameset();
+ start = i + 1;
+ continue;
+ }
+ case AFTER_AFTER_BODY: {
+ errNonSpaceInTrailer();
+ mode = framesetOk ? FRAMESET_OK : IN_BODY;
+ i--;
+ continue;
+ }
+ case AFTER_AFTER_FRAMESET: {
+ if (start < i) {
+ accumulateCharacters(buf, start, i - start);
+ }
+ errNonSpaceInTrailer();
+ start = i + 1;
+ continue;
+ }
+ }
+ }
+ }
+ }
+ charactersloop_end:;
+ if (start < end) {
+ accumulateCharacters(buf, start, end - start);
+ }
+ }
+ }
+}
+
+void nsHtml5TreeBuilder::zeroOriginatingReplacementCharacter() {
+ if (mode == TEXT) {
+ accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1);
+ return;
+ }
+ if (currentPtr >= 0) {
+ if (isSpecialParentInForeign(stack[currentPtr])) {
+ return;
+ }
+ accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1);
+ }
+}
+
+void nsHtml5TreeBuilder::zeroOrReplacementCharacter() {
+ zeroOriginatingReplacementCharacter();
+}
+
+void nsHtml5TreeBuilder::eof() {
+ flushCharacters();
+ for (;;) {
+ switch (mode) {
+ case INITIAL: {
+ documentModeInternal(QUIRKS_MODE, nullptr, nullptr);
+ mode = BEFORE_HTML;
+ continue;
+ }
+ case BEFORE_HTML: {
+ appendHtmlElementToDocumentAndPush();
+ mode = BEFORE_HEAD;
+ continue;
+ }
+ case BEFORE_HEAD: {
+ appendToCurrentNodeAndPushHeadElement(
+ nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
+ mode = IN_HEAD;
+ continue;
+ }
+ case IN_HEAD: {
+ while (currentPtr > 0) {
+ popOnEof();
+ }
+ mode = AFTER_HEAD;
+ continue;
+ }
+ case IN_HEAD_NOSCRIPT: {
+ 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: {
+ if (isTemplateModeStackEmpty()) {
+ NS_HTML5_BREAK(eofloop);
+ }
+ [[fallthrough]];
+ }
+ case IN_TEMPLATE: {
+ int32_t eltPos = findLast(nsGkAtoms::_template);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ MOZ_ASSERT(fragment);
+ NS_HTML5_BREAK(eofloop);
+ }
+ if (MOZ_UNLIKELY(mViewSource)) {
+ errListUnclosedStartTags(0);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ clearTheListOfActiveFormattingElementsUpToTheLastMarker();
+ popTemplateMode();
+ resetTheInsertionMode();
+ continue;
+ }
+ case TEXT: {
+ if (originalMode == AFTER_HEAD) {
+ popOnEof();
+ }
+ popOnEof();
+ mode = originalMode;
+ continue;
+ }
+ case IN_FRAMESET: {
+ NS_HTML5_BREAK(eofloop);
+ }
+ case AFTER_BODY:
+ case AFTER_FRAMESET:
+ case AFTER_AFTER_BODY:
+ case AFTER_AFTER_FRAMESET:
+ default: {
+ NS_HTML5_BREAK(eofloop);
+ }
+ }
+ }
+eofloop_end:;
+ while (currentPtr > 0) {
+ popOnEof();
+ }
+ if (!fragment) {
+ popOnEof();
+ }
+}
+
+void nsHtml5TreeBuilder::endTokenization() {
+ formPointer = nullptr;
+ headPointer = nullptr;
+ contextName = nullptr;
+ contextNode = nullptr;
+ templateModeStack = nullptr;
+ if (stack) {
+ while (currentPtr > -1) {
+ stack[currentPtr]->release(this);
+ currentPtr--;
+ }
+ stack = nullptr;
+ }
+ if (listOfActiveFormattingElements) {
+ while (listPtr > -1) {
+ if (listOfActiveFormattingElements[listPtr]) {
+ listOfActiveFormattingElements[listPtr]->release(this);
+ }
+ listPtr--;
+ }
+ listOfActiveFormattingElements = nullptr;
+ }
+ if (stackNodes) {
+ for (int32_t i = 0; i < numStackNodes; i++) {
+ MOZ_ASSERT(stackNodes[i]->isUnused());
+ delete stackNodes[i];
+ }
+ numStackNodes = 0;
+ stackNodesIdx = 0;
+ stackNodes = nullptr;
+ }
+ charBuffer = nullptr;
+ end();
+}
+
+void nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName,
+ nsHtml5HtmlAttributes* attributes,
+ bool selfClosing) {
+ flushCharacters();
+ int32_t eltPos;
+ needToDropLF = false;
+starttagloop:
+ for (;;) {
+ int32_t group = elementName->getGroup();
+ nsAtom* name = elementName->getName();
+ if (isInForeign()) {
+ nsHtml5StackNode* currentNode = stack[currentPtr];
+ int32_t currNs = currentNode->ns;
+ if (!(currentNode->isHtmlIntegrationPoint() ||
+ (currNs == kNameSpaceID_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: {
+ if (!(group == FONT &&
+ !(attributes->contains(nsHtml5AttributeName::ATTR_COLOR) ||
+ attributes->contains(nsHtml5AttributeName::ATTR_FACE) ||
+ attributes->contains(nsHtml5AttributeName::ATTR_SIZE)))) {
+ errHtmlStartTagInForeignContext(name);
+ if (!fragment) {
+ while (!isSpecialParentInForeign(stack[currentPtr])) {
+ popForeign(-1, -1);
+ }
+ NS_HTML5_CONTINUE(starttagloop);
+ }
+ }
+ [[fallthrough]];
+ }
+ default: {
+ if (kNameSpaceID_SVG == currNs) {
+ attributes->adjustForSvg();
+ if (selfClosing) {
+ appendVoidElementToCurrentMayFosterSVG(elementName, attributes);
+ selfClosing = false;
+ } else {
+ appendToCurrentNodeAndPushElementMayFosterSVG(elementName,
+ attributes);
+ }
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ } else {
+ attributes->adjustForMath();
+ if (selfClosing) {
+ appendVoidElementToCurrentMayFosterMathML(elementName,
+ attributes);
+ selfClosing = false;
+ } else {
+ appendToCurrentNodeAndPushElementMayFosterMathML(elementName,
+ attributes);
+ }
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ }
+ }
+ }
+ }
+ switch (mode) {
+ case IN_TEMPLATE: {
+ switch (group) {
+ case COL: {
+ popTemplateMode();
+ pushTemplateMode(IN_COLUMN_GROUP);
+ mode = IN_COLUMN_GROUP;
+ continue;
+ }
+ case CAPTION:
+ case COLGROUP:
+ case TBODY_OR_THEAD_OR_TFOOT: {
+ popTemplateMode();
+ pushTemplateMode(IN_TABLE);
+ mode = IN_TABLE;
+ continue;
+ }
+ case TR: {
+ popTemplateMode();
+ pushTemplateMode(IN_TABLE_BODY);
+ mode = IN_TABLE_BODY;
+ continue;
+ }
+ case TD_OR_TH: {
+ popTemplateMode();
+ pushTemplateMode(IN_ROW);
+ mode = IN_ROW;
+ continue;
+ }
+ case META: {
+ checkMetaCharset(attributes);
+ appendVoidElementToCurrentMayFoster(elementName, attributes);
+ selfClosing = false;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case TITLE: {
+ startTagTitleInHead(elementName, attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case BASE:
+ case LINK_OR_BASEFONT_OR_BGSOUND: {
+ appendVoidElementToCurrentMayFoster(elementName, attributes);
+ selfClosing = false;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case SCRIPT: {
+ startTagScriptInHead(elementName, attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case NOFRAMES:
+ case STYLE: {
+ startTagGenericRawText(elementName, attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case TEMPLATE: {
+ startTagTemplateInHead(elementName, attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ default: {
+ popTemplateMode();
+ pushTemplateMode(IN_BODY);
+ mode = IN_BODY;
+ continue;
+ }
+ }
+ }
+ case IN_ROW: {
+ switch (group) {
+ case TD_OR_TH: {
+ clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TR));
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ mode = IN_CELL;
+ insertMarker();
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case CAPTION:
+ case COL:
+ case COLGROUP:
+ case TBODY_OR_THEAD_OR_TFOOT:
+ case TR: {
+ eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
+ if (!eltPos) {
+ MOZ_ASSERT(fragment || isTemplateContents());
+ errNoTableRowToClose();
+ NS_HTML5_BREAK(starttagloop);
+ }
+ clearStackBackTo(eltPos);
+ pop();
+ mode = IN_TABLE_BODY;
+ continue;
+ }
+ default:; // fall through
+ }
+ [[fallthrough]];
+ }
+ case IN_TABLE_BODY: {
+ switch (group) {
+ case TR: {
+ clearStackBackTo(
+ findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ mode = IN_ROW;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case TD_OR_TH: {
+ errStartTagInTableBody(name);
+ clearStackBackTo(
+ findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
+ appendToCurrentNodeAndPushElement(
+ nsHtml5ElementName::ELT_TR,
+ nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
+ mode = IN_ROW;
+ continue;
+ }
+ case CAPTION:
+ case COL:
+ case COLGROUP:
+ case TBODY_OR_THEAD_OR_TFOOT: {
+ eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
+ if (!eltPos || stack[eltPos]->getGroup() == TEMPLATE) {
+ MOZ_ASSERT(fragment || isTemplateContents());
+ errStrayStartTag(name);
+ NS_HTML5_BREAK(starttagloop);
+ } else {
+ clearStackBackTo(eltPos);
+ pop();
+ mode = IN_TABLE;
+ continue;
+ }
+ }
+ default:; // fall through
+ }
+ [[fallthrough]];
+ }
+ case IN_TABLE: {
+ for (;;) {
+ switch (group) {
+ case CAPTION: {
+ clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
+ insertMarker();
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ mode = IN_CAPTION;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case COLGROUP: {
+ clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ mode = IN_COLUMN_GROUP;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case COL: {
+ clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
+ appendToCurrentNodeAndPushElement(
+ nsHtml5ElementName::ELT_COLGROUP,
+ nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
+ mode = IN_COLUMN_GROUP;
+ NS_HTML5_CONTINUE(starttagloop);
+ }
+ case TBODY_OR_THEAD_OR_TFOOT: {
+ clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ mode = IN_TABLE_BODY;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case TR:
+ case TD_OR_TH: {
+ clearStackBackTo(findLastOrRoot(nsHtml5TreeBuilder::TABLE));
+ appendToCurrentNodeAndPushElement(
+ nsHtml5ElementName::ELT_TBODY,
+ nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
+ mode = IN_TABLE_BODY;
+ NS_HTML5_CONTINUE(starttagloop);
+ }
+ case TEMPLATE: {
+ NS_HTML5_BREAK(intableloop);
+ }
+ case TABLE: {
+ errTableSeenWhileTableOpen();
+ eltPos = findLastInTableScope(name);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ MOZ_ASSERT(fragment || isTemplateContents());
+ NS_HTML5_BREAK(starttagloop);
+ }
+ generateImpliedEndTags();
+ if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(nsGkAtoms::table)) {
+ errNoCheckUnclosedElementsOnStack();
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ resetTheInsertionMode();
+ NS_HTML5_CONTINUE(starttagloop);
+ }
+ case SCRIPT: {
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ originalMode = mode;
+ mode = TEXT;
+ tokenizer->setStateAndEndTagExpectation(
+ nsHtml5Tokenizer::SCRIPT_DATA, elementName);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case STYLE: {
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ originalMode = mode;
+ mode = TEXT;
+ tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
+ elementName);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case INPUT: {
+ errStartTagInTable(name);
+ if (!nsHtml5Portability::
+ lowerCaseLiteralEqualsIgnoreAsciiCaseString(
+ "hidden", attributes->getValue(
+ nsHtml5AttributeName::ATTR_TYPE))) {
+ NS_HTML5_BREAK(intableloop);
+ }
+ appendVoidInputToCurrent(attributes, formPointer);
+ selfClosing = false;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case FORM: {
+ if (!!formPointer || isTemplateContents()) {
+ errFormWhenFormOpen();
+ NS_HTML5_BREAK(starttagloop);
+ } else {
+ errStartTagInTable(name);
+ appendVoidFormToCurrent(attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ }
+ default: {
+ errStartTagInTable(name);
+ NS_HTML5_BREAK(intableloop);
+ }
+ }
+ }
+ intableloop_end:;
+ [[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(nsGkAtoms::caption);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ MOZ_ASSERT(fragment || isTemplateContents());
+ errStrayStartTag(name);
+ NS_HTML5_BREAK(starttagloop);
+ }
+ generateImpliedEndTags();
+ if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) {
+ errNoCheckUnclosedElementsOnStack();
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ clearTheListOfActiveFormattingElementsUpToTheLastMarker();
+ mode = IN_TABLE;
+ continue;
+ }
+ default:; // fall through
+ }
+ [[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 == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ errNoCellToClose();
+ NS_HTML5_BREAK(starttagloop);
+ } else {
+ closeTheCell(eltPos);
+ continue;
+ }
+ }
+ default:; // fall through
+ }
+ [[fallthrough]];
+ }
+ case FRAMESET_OK: {
+ switch (group) {
+ case FRAMESET: {
+ if (mode == FRAMESET_OK) {
+ if (!currentPtr || stack[1]->getGroup() != BODY) {
+ MOZ_ASSERT(fragment || isTemplateContents());
+ errStrayStartTag(name);
+ NS_HTML5_BREAK(starttagloop);
+ } else {
+ errFramesetStart();
+ detachFromParent(stack[1]->node);
+ while (currentPtr > 0) {
+ pop();
+ }
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ mode = IN_FRAMESET;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ } else {
+ errStrayStartTag(name);
+ NS_HTML5_BREAK(starttagloop);
+ }
+ }
+ 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 &&
+ nsHtml5Portability::
+ lowerCaseLiteralEqualsIgnoreAsciiCaseString(
+ "hidden", attributes->getValue(
+ nsHtml5AttributeName::ATTR_TYPE)))) {
+ framesetOk = false;
+ mode = IN_BODY;
+ }
+ [[fallthrough]];
+ }
+ default:; // fall through
+ }
+ [[fallthrough]];
+ }
+ case IN_BODY: {
+ for (;;) {
+ switch (group) {
+ case HTML: {
+ errStrayStartTag(name);
+ if (!fragment && !isTemplateContents()) {
+ addAttributesToHtml(attributes);
+ attributes = nullptr;
+ }
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case BASE:
+ case LINK_OR_BASEFONT_OR_BGSOUND:
+ case META:
+ case STYLE:
+ case SCRIPT:
+ case TITLE:
+ case TEMPLATE: {
+ NS_HTML5_BREAK(inbodyloop);
+ }
+ case BODY: {
+ if (!currentPtr || stack[1]->getGroup() != BODY ||
+ isTemplateContents()) {
+ MOZ_ASSERT(fragment || isTemplateContents());
+ errStrayStartTag(name);
+ NS_HTML5_BREAK(starttagloop);
+ }
+ errFooSeenWhenFooOpen(name);
+ framesetOk = false;
+ if (mode == FRAMESET_OK) {
+ mode = IN_BODY;
+ }
+ if (addAttributesToBody(attributes)) {
+ attributes = nullptr;
+ }
+ NS_HTML5_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 = nullptr;
+ NS_HTML5_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 = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case FIELDSET: {
+ implicitlyCloseP();
+ appendToCurrentNodeAndPushElementMayFoster(
+ elementName, attributes, formPointer);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case PRE_OR_LISTING: {
+ implicitlyCloseP();
+ appendToCurrentNodeAndPushElementMayFoster(elementName,
+ attributes);
+ needToDropLF = true;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case FORM: {
+ if (!!formPointer && !isTemplateContents()) {
+ errFormWhenFormOpen();
+ NS_HTML5_BREAK(starttagloop);
+ } else {
+ implicitlyCloseP();
+ appendToCurrentNodeAndPushFormElementMayFoster(attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ }
+ case LI:
+ case DD_OR_DT: {
+ eltPos = currentPtr;
+ for (;;) {
+ nsHtml5StackNode* node = stack[eltPos];
+ if (node->getGroup() == group) {
+ generateImpliedEndTagsExceptFor(node->name);
+ if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
+ errUnclosedElementsImplied(eltPos, name);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ break;
+ } else if (!eltPos || (node->isSpecial() &&
+ (node->ns != kNameSpaceID_XHTML ||
+ (node->name != nsGkAtoms::p &&
+ node->name != nsGkAtoms::address &&
+ node->name != nsGkAtoms::div)))) {
+ break;
+ }
+ eltPos--;
+ }
+ implicitlyCloseP();
+ appendToCurrentNodeAndPushElementMayFoster(elementName,
+ attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case PLAINTEXT: {
+ implicitlyCloseP();
+ appendToCurrentNodeAndPushElementMayFoster(elementName,
+ attributes);
+ tokenizer->setStateAndEndTagExpectation(
+ nsHtml5Tokenizer::PLAINTEXT, elementName);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case A: {
+ int32_t activeAPos =
+ findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker(
+ nsGkAtoms::a);
+ if (activeAPos != -1) {
+ errFooSeenWhenFooOpen(name);
+ nsHtml5StackNode* activeA =
+ listOfActiveFormattingElements[activeAPos];
+ activeA->retain();
+ adoptionAgencyEndTag(nsGkAtoms::a);
+ removeFromStack(activeA);
+ activeAPos = findInListOfActiveFormattingElements(activeA);
+ if (activeAPos != -1) {
+ removeFromListOfActiveFormattingElements(activeAPos);
+ }
+ activeA->release(this);
+ }
+ reconstructTheActiveFormattingElements();
+ appendToCurrentNodeAndPushFormattingElementMayFoster(elementName,
+ attributes);
+ attributes = nullptr;
+ NS_HTML5_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 = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case NOBR: {
+ reconstructTheActiveFormattingElements();
+ if (nsHtml5TreeBuilder::NOT_FOUND_ON_STACK !=
+ findLastInScope(nsGkAtoms::nobr)) {
+ errFooSeenWhenFooOpen(name);
+ adoptionAgencyEndTag(nsGkAtoms::nobr);
+ reconstructTheActiveFormattingElements();
+ }
+ appendToCurrentNodeAndPushFormattingElementMayFoster(elementName,
+ attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case BUTTON: {
+ eltPos = findLastInScope(name);
+ if (eltPos != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ errFooSeenWhenFooOpen(name);
+ generateImpliedEndTags();
+ if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
+ errUnclosedElementsImplied(eltPos, name);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ NS_HTML5_CONTINUE(starttagloop);
+ } else {
+ reconstructTheActiveFormattingElements();
+ appendToCurrentNodeAndPushElementMayFoster(
+ elementName, attributes, formPointer);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ }
+ case OBJECT: {
+ reconstructTheActiveFormattingElements();
+ appendToCurrentNodeAndPushElementMayFoster(
+ elementName, attributes, formPointer);
+ insertMarker();
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case MARQUEE_OR_APPLET: {
+ reconstructTheActiveFormattingElements();
+ appendToCurrentNodeAndPushElementMayFoster(elementName,
+ attributes);
+ insertMarker();
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case TABLE: {
+ if (!quirks) {
+ implicitlyCloseP();
+ }
+ appendToCurrentNodeAndPushElementMayFoster(elementName,
+ attributes);
+ mode = IN_TABLE;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case BR:
+ case EMBED:
+ case AREA_OR_WBR:
+ case KEYGEN: {
+ reconstructTheActiveFormattingElements();
+ [[fallthrough]];
+ }
+ case PARAM_OR_SOURCE_OR_TRACK: {
+ appendVoidElementToCurrentMayFoster(elementName, attributes);
+ selfClosing = false;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case HR: {
+ implicitlyCloseP();
+ appendVoidElementToCurrentMayFoster(elementName, attributes);
+ selfClosing = false;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case IMAGE: {
+ errImage();
+ elementName = nsHtml5ElementName::ELT_IMG;
+ NS_HTML5_CONTINUE(starttagloop);
+ }
+ case IMG:
+ case INPUT: {
+ reconstructTheActiveFormattingElements();
+ appendVoidElementToCurrentMayFoster(elementName, attributes,
+ formPointer);
+ selfClosing = false;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case TEXTAREA: {
+ appendToCurrentNodeAndPushElementMayFoster(
+ elementName, attributes, formPointer);
+ tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RCDATA,
+ elementName);
+ originalMode = mode;
+ mode = TEXT;
+ needToDropLF = true;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case XMP: {
+ implicitlyCloseP();
+ reconstructTheActiveFormattingElements();
+ appendToCurrentNodeAndPushElementMayFoster(elementName,
+ attributes);
+ originalMode = mode;
+ mode = TEXT;
+ tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
+ elementName);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case NOSCRIPT: {
+ if (!scriptingEnabled) {
+ reconstructTheActiveFormattingElements();
+ appendToCurrentNodeAndPushElementMayFoster(elementName,
+ attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ [[fallthrough]];
+ }
+ case NOFRAMES:
+ case IFRAME:
+ case NOEMBED: {
+ startTagGenericRawText(elementName, attributes);
+ attributes = nullptr;
+ NS_HTML5_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 = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case OPTGROUP:
+ case OPTION: {
+ if (isCurrent(nsGkAtoms::option)) {
+ pop();
+ }
+ reconstructTheActiveFormattingElements();
+ appendToCurrentNodeAndPushElementMayFoster(elementName,
+ attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case RB_OR_RTC: {
+ eltPos = findLastInScope(nsGkAtoms::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 = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case RT_OR_RP: {
+ eltPos = findLastInScope(nsGkAtoms::ruby);
+ if (eltPos != NOT_FOUND_ON_STACK) {
+ generateImpliedEndTagsExceptFor(nsGkAtoms::rtc);
+ }
+ if (eltPos != currentPtr) {
+ if (!isCurrent(nsGkAtoms::rtc)) {
+ if (eltPos == NOT_FOUND_ON_STACK) {
+ errStartTagSeenWithoutRuby(name);
+ } else {
+ errUnclosedChildrenInRuby();
+ }
+ }
+ }
+ appendToCurrentNodeAndPushElementMayFoster(elementName,
+ attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case MATH: {
+ reconstructTheActiveFormattingElements();
+ attributes->adjustForMath();
+ if (selfClosing) {
+ appendVoidElementToCurrentMayFosterMathML(elementName,
+ attributes);
+ selfClosing = false;
+ } else {
+ appendToCurrentNodeAndPushElementMayFosterMathML(elementName,
+ attributes);
+ }
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case SVG: {
+ reconstructTheActiveFormattingElements();
+ attributes->adjustForSvg();
+ if (selfClosing) {
+ appendVoidElementToCurrentMayFosterSVG(elementName, attributes);
+ selfClosing = false;
+ } else {
+ appendToCurrentNodeAndPushElementMayFosterSVG(elementName,
+ attributes);
+ }
+ attributes = nullptr;
+ NS_HTML5_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);
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case OUTPUT: {
+ reconstructTheActiveFormattingElements();
+ appendToCurrentNodeAndPushElementMayFoster(
+ elementName, attributes, formPointer);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ default: {
+ reconstructTheActiveFormattingElements();
+ appendToCurrentNodeAndPushElementMayFoster(elementName,
+ attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ }
+ }
+ inbodyloop_end:;
+ [[fallthrough]];
+ }
+ case IN_HEAD: {
+ for (;;) {
+ switch (group) {
+ case HTML: {
+ errStrayStartTag(name);
+ if (!fragment && !isTemplateContents()) {
+ addAttributesToHtml(attributes);
+ attributes = nullptr;
+ }
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case BASE:
+ case LINK_OR_BASEFONT_OR_BGSOUND: {
+ appendVoidElementToCurrentMayFoster(elementName, attributes);
+ selfClosing = false;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case META: {
+ NS_HTML5_BREAK(inheadloop);
+ }
+ case TITLE: {
+ startTagTitleInHead(elementName, attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case NOSCRIPT: {
+ if (scriptingEnabled) {
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ originalMode = mode;
+ mode = TEXT;
+ tokenizer->setStateAndEndTagExpectation(
+ nsHtml5Tokenizer::RAWTEXT, elementName);
+ } else {
+ appendToCurrentNodeAndPushElementMayFoster(elementName,
+ attributes);
+ mode = IN_HEAD_NOSCRIPT;
+ }
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case SCRIPT: {
+ startTagScriptInHead(elementName, attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case STYLE:
+ case NOFRAMES: {
+ startTagGenericRawText(elementName, attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case HEAD: {
+ errFooSeenWhenFooOpen(name);
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case TEMPLATE: {
+ startTagTemplateInHead(elementName, attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ default: {
+ pop();
+ mode = AFTER_HEAD;
+ NS_HTML5_CONTINUE(starttagloop);
+ }
+ }
+ }
+ inheadloop_end:;
+ [[fallthrough]];
+ }
+ case IN_HEAD_NOSCRIPT: {
+ switch (group) {
+ case HTML: {
+ errStrayStartTag(name);
+ if (!fragment && !isTemplateContents()) {
+ addAttributesToHtml(attributes);
+ attributes = nullptr;
+ }
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case LINK_OR_BASEFONT_OR_BGSOUND: {
+ appendVoidElementToCurrentMayFoster(elementName, attributes);
+ selfClosing = false;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case META: {
+ checkMetaCharset(attributes);
+ appendVoidElementToCurrentMayFoster(elementName, attributes);
+ selfClosing = false;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case STYLE:
+ case NOFRAMES: {
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ originalMode = mode;
+ mode = TEXT;
+ tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
+ elementName);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case HEAD: {
+ errFooSeenWhenFooOpen(name);
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case NOSCRIPT: {
+ errFooSeenWhenFooOpen(name);
+ NS_HTML5_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 = nullptr;
+ }
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case COL: {
+ appendVoidElementToCurrentMayFoster(elementName, attributes);
+ selfClosing = false;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case TEMPLATE: {
+ startTagTemplateInHead(elementName, attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ default: {
+ if (!currentPtr || stack[currentPtr]->getGroup() == TEMPLATE) {
+ MOZ_ASSERT(fragment || isTemplateContents());
+ errGarbageInColgroup();
+ NS_HTML5_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(nsGkAtoms::select);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ MOZ_ASSERT(fragment);
+ NS_HTML5_BREAK(starttagloop);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ resetTheInsertionMode();
+ continue;
+ }
+ default:; // fall through
+ }
+ [[fallthrough]];
+ }
+ case IN_SELECT: {
+ switch (group) {
+ case HTML: {
+ errStrayStartTag(name);
+ if (!fragment) {
+ addAttributesToHtml(attributes);
+ attributes = nullptr;
+ }
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case OPTION: {
+ if (isCurrent(nsGkAtoms::option)) {
+ pop();
+ }
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case OPTGROUP: {
+ if (isCurrent(nsGkAtoms::option)) {
+ pop();
+ }
+ if (isCurrent(nsGkAtoms::optgroup)) {
+ pop();
+ }
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case SELECT: {
+ errStartSelectWhereEndSelectExpected();
+ eltPos = findLastInTableScope(name);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ MOZ_ASSERT(fragment);
+ errNoSelectInTableScope();
+ NS_HTML5_BREAK(starttagloop);
+ } else {
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ resetTheInsertionMode();
+ NS_HTML5_BREAK(starttagloop);
+ }
+ }
+ case INPUT:
+ case TEXTAREA: {
+ errStartTagWithSelectOpen(name);
+ eltPos = findLastInTableScope(nsGkAtoms::select);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ MOZ_ASSERT(fragment);
+ NS_HTML5_BREAK(starttagloop);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ resetTheInsertionMode();
+ continue;
+ }
+ case SCRIPT: {
+ startTagScriptInHead(elementName, attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case TEMPLATE: {
+ startTagTemplateInHead(elementName, attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case HR: {
+ if (isCurrent(nsGkAtoms::option)) {
+ pop();
+ }
+ if (isCurrent(nsGkAtoms::optgroup)) {
+ pop();
+ }
+ appendVoidElementToCurrent(elementName, attributes);
+ selfClosing = false;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ default: {
+ errStrayStartTag(name);
+ NS_HTML5_BREAK(starttagloop);
+ }
+ }
+ }
+ case AFTER_BODY: {
+ switch (group) {
+ case HTML: {
+ errStrayStartTag(name);
+ if (!fragment && !isTemplateContents()) {
+ addAttributesToHtml(attributes);
+ attributes = nullptr;
+ }
+ NS_HTML5_BREAK(starttagloop);
+ }
+ default: {
+ errStrayStartTag(name);
+ mode = framesetOk ? FRAMESET_OK : IN_BODY;
+ continue;
+ }
+ }
+ }
+ case IN_FRAMESET: {
+ switch (group) {
+ case FRAMESET: {
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case FRAME: {
+ appendVoidElementToCurrentMayFoster(elementName, attributes);
+ selfClosing = false;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ default:; // fall through
+ }
+ [[fallthrough]];
+ }
+ case AFTER_FRAMESET: {
+ switch (group) {
+ case HTML: {
+ errStrayStartTag(name);
+ if (!fragment && !isTemplateContents()) {
+ addAttributesToHtml(attributes);
+ attributes = nullptr;
+ }
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case NOFRAMES: {
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ originalMode = mode;
+ mode = TEXT;
+ tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
+ elementName);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ default: {
+ errStrayStartTag(name);
+ NS_HTML5_BREAK(starttagloop);
+ }
+ }
+ }
+ case INITIAL: {
+ errStartTagWithoutDoctype();
+ documentModeInternal(QUIRKS_MODE, nullptr, nullptr);
+ mode = BEFORE_HTML;
+ continue;
+ }
+ case BEFORE_HTML: {
+ switch (group) {
+ case HTML: {
+ if (attributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
+ appendHtmlElementToDocumentAndPush();
+ } else {
+ appendHtmlElementToDocumentAndPush(attributes);
+ }
+ mode = BEFORE_HEAD;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ default: {
+ appendHtmlElementToDocumentAndPush();
+ mode = BEFORE_HEAD;
+ continue;
+ }
+ }
+ }
+ case BEFORE_HEAD: {
+ switch (group) {
+ case HTML: {
+ errStrayStartTag(name);
+ if (!fragment && !isTemplateContents()) {
+ addAttributesToHtml(attributes);
+ attributes = nullptr;
+ }
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case HEAD: {
+ appendToCurrentNodeAndPushHeadElement(attributes);
+ mode = IN_HEAD;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ default: {
+ appendToCurrentNodeAndPushHeadElement(
+ nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
+ mode = IN_HEAD;
+ continue;
+ }
+ }
+ }
+ case AFTER_HEAD: {
+ switch (group) {
+ case HTML: {
+ errStrayStartTag(name);
+ if (!fragment && !isTemplateContents()) {
+ addAttributesToHtml(attributes);
+ attributes = nullptr;
+ }
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case BODY: {
+ if (!attributes->getLength()) {
+ appendToCurrentNodeAndPushBodyElement();
+ } else {
+ appendToCurrentNodeAndPushBodyElement(attributes);
+ }
+ framesetOk = false;
+ mode = IN_BODY;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case FRAMESET: {
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ mode = IN_FRAMESET;
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case TEMPLATE: {
+ errFooBetweenHeadAndBody(name);
+ pushHeadPointerOntoStack();
+ nsHtml5StackNode* headOnStack = stack[currentPtr];
+ startTagTemplateInHead(elementName, attributes);
+ removeFromStack(headOnStack);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case BASE:
+ case LINK_OR_BASEFONT_OR_BGSOUND: {
+ errFooBetweenHeadAndBody(name);
+ pushHeadPointerOntoStack();
+ appendVoidElementToCurrentMayFoster(elementName, attributes);
+ selfClosing = false;
+ pop();
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case META: {
+ errFooBetweenHeadAndBody(name);
+ checkMetaCharset(attributes);
+ pushHeadPointerOntoStack();
+ appendVoidElementToCurrentMayFoster(elementName, attributes);
+ selfClosing = false;
+ pop();
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case SCRIPT: {
+ errFooBetweenHeadAndBody(name);
+ pushHeadPointerOntoStack();
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ originalMode = mode;
+ mode = TEXT;
+ tokenizer->setStateAndEndTagExpectation(
+ nsHtml5Tokenizer::SCRIPT_DATA, elementName);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case STYLE:
+ case NOFRAMES: {
+ errFooBetweenHeadAndBody(name);
+ pushHeadPointerOntoStack();
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ originalMode = mode;
+ mode = TEXT;
+ tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
+ elementName);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case TITLE: {
+ errFooBetweenHeadAndBody(name);
+ pushHeadPointerOntoStack();
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ originalMode = mode;
+ mode = TEXT;
+ tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RCDATA,
+ elementName);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case HEAD: {
+ errStrayStartTag(name);
+ NS_HTML5_BREAK(starttagloop);
+ }
+ default: {
+ appendToCurrentNodeAndPushBodyElement();
+ mode = FRAMESET_OK;
+ continue;
+ }
+ }
+ }
+ case AFTER_AFTER_BODY: {
+ switch (group) {
+ case HTML: {
+ errStrayStartTag(name);
+ if (!fragment && !isTemplateContents()) {
+ addAttributesToHtml(attributes);
+ attributes = nullptr;
+ }
+ NS_HTML5_BREAK(starttagloop);
+ }
+ default: {
+ errStrayStartTag(name);
+
+ mode = framesetOk ? FRAMESET_OK : IN_BODY;
+ continue;
+ }
+ }
+ }
+ case AFTER_AFTER_FRAMESET: {
+ switch (group) {
+ case HTML: {
+ errStrayStartTag(name);
+ if (!fragment && !isTemplateContents()) {
+ addAttributesToHtml(attributes);
+ attributes = nullptr;
+ }
+ NS_HTML5_BREAK(starttagloop);
+ }
+ case NOFRAMES: {
+ startTagGenericRawText(elementName, attributes);
+ attributes = nullptr;
+ NS_HTML5_BREAK(starttagloop);
+ }
+ default: {
+ errStrayStartTag(name);
+ NS_HTML5_BREAK(starttagloop);
+ }
+ }
+ }
+ case TEXT: {
+ MOZ_ASSERT(false);
+ NS_HTML5_BREAK(starttagloop);
+ }
+ }
+ }
+starttagloop_end:;
+ if (selfClosing) {
+ errSelfClosing();
+ }
+ if (!mBuilder && attributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
+ delete attributes;
+ }
+}
+
+void nsHtml5TreeBuilder::startTagTitleInHead(
+ nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
+ appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
+ originalMode = mode;
+ mode = TEXT;
+ tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RCDATA,
+ elementName);
+}
+
+void nsHtml5TreeBuilder::startTagGenericRawText(
+ nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
+ appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
+ originalMode = mode;
+ mode = TEXT;
+ tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::RAWTEXT,
+ elementName);
+}
+
+void nsHtml5TreeBuilder::startTagScriptInHead(
+ nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
+ appendToCurrentNodeAndPushElementMayFoster(elementName, attributes);
+ originalMode = mode;
+ mode = TEXT;
+ tokenizer->setStateAndEndTagExpectation(nsHtml5Tokenizer::SCRIPT_DATA,
+ elementName);
+}
+
+void nsHtml5TreeBuilder::startTagTemplateInHead(
+ nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
+ appendToCurrentNodeAndPushElement(elementName, attributes);
+ insertMarker();
+ framesetOk = false;
+ originalMode = mode;
+ mode = IN_TEMPLATE;
+ pushTemplateMode(IN_TEMPLATE);
+}
+
+bool nsHtml5TreeBuilder::isTemplateContents() {
+ return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK !=
+ findLast(nsGkAtoms::_template);
+}
+
+bool nsHtml5TreeBuilder::isTemplateModeStackEmpty() {
+ return templateModePtr == -1;
+}
+
+bool nsHtml5TreeBuilder::isSpecialParentInForeign(nsHtml5StackNode* stackNode) {
+ int32_t ns = stackNode->ns;
+ return (kNameSpaceID_XHTML == ns) || (stackNode->isHtmlIntegrationPoint()) ||
+ ((kNameSpaceID_MathML == ns) &&
+ (stackNode->getGroup() == MI_MO_MN_MS_MTEXT));
+}
+
+nsIContentHandle* nsHtml5TreeBuilder::getDeclarativeShadowRoot(
+ nsIContentHandle* currentNode, nsIContentHandle* templateNode,
+ nsHtml5HtmlAttributes* attributes) {
+ if (!isAllowDeclarativeShadowRoots()) {
+ return nullptr;
+ }
+ nsHtml5String shadowRootMode =
+ attributes->getValue(nsHtml5AttributeName::ATTR_SHADOWROOTMODE);
+ if (!shadowRootMode) {
+ return nullptr;
+ }
+ bool shadowRootDelegatesFocus =
+ attributes->contains(nsHtml5AttributeName::ATTR_SHADOWROOTDELEGATESFOCUS);
+ return getShadowRootFromHost(currentNode, templateNode, shadowRootMode,
+ shadowRootDelegatesFocus);
+}
+
+nsHtml5String nsHtml5TreeBuilder::extractCharsetFromContent(
+ nsHtml5String attributeValue, nsHtml5TreeBuilder* tb) {
+ int32_t charsetState = CHARSET_INITIAL;
+ int32_t start = -1;
+ int32_t end = -1;
+ autoJArray<char16_t, int32_t> buffer =
+ nsHtml5Portability::newCharArrayFromString(attributeValue);
+ for (int32_t i = 0; i < buffer.length; i++) {
+ char16_t c = buffer[i];
+ switch (charsetState) {
+ case CHARSET_INITIAL: {
+ switch (c) {
+ case 'c':
+ case 'C': {
+ charsetState = CHARSET_C;
+ continue;
+ }
+ default: {
+ continue;
+ }
+ }
+ }
+ case CHARSET_C: {
+ switch (c) {
+ case 'h':
+ case 'H': {
+ charsetState = CHARSET_H;
+ continue;
+ }
+ default: {
+ charsetState = CHARSET_INITIAL;
+ continue;
+ }
+ }
+ }
+ case CHARSET_H: {
+ switch (c) {
+ case 'a':
+ case 'A': {
+ charsetState = CHARSET_A;
+ continue;
+ }
+ default: {
+ charsetState = CHARSET_INITIAL;
+ continue;
+ }
+ }
+ }
+ case CHARSET_A: {
+ switch (c) {
+ case 'r':
+ case 'R': {
+ charsetState = CHARSET_R;
+ continue;
+ }
+ default: {
+ charsetState = CHARSET_INITIAL;
+ continue;
+ }
+ }
+ }
+ case CHARSET_R: {
+ switch (c) {
+ case 's':
+ case 'S': {
+ charsetState = CHARSET_S;
+ continue;
+ }
+ default: {
+ charsetState = CHARSET_INITIAL;
+ continue;
+ }
+ }
+ }
+ case CHARSET_S: {
+ switch (c) {
+ case 'e':
+ case 'E': {
+ charsetState = CHARSET_E;
+ continue;
+ }
+ default: {
+ charsetState = CHARSET_INITIAL;
+ continue;
+ }
+ }
+ }
+ case CHARSET_E: {
+ switch (c) {
+ case 't':
+ case 'T': {
+ charsetState = CHARSET_T;
+ continue;
+ }
+ default: {
+ charsetState = CHARSET_INITIAL;
+ continue;
+ }
+ }
+ }
+ case CHARSET_T: {
+ switch (c) {
+ case '\t':
+ case '\n':
+ case '\f':
+ case '\r':
+ case ' ': {
+ continue;
+ }
+ case '=': {
+ charsetState = CHARSET_EQUALS;
+ continue;
+ }
+ default: {
+ return nullptr;
+ }
+ }
+ }
+ case CHARSET_EQUALS: {
+ switch (c) {
+ case '\t':
+ case '\n':
+ case '\f':
+ case '\r':
+ case ' ': {
+ continue;
+ }
+ case '\'': {
+ start = i + 1;
+ charsetState = CHARSET_SINGLE_QUOTED;
+ continue;
+ }
+ case '\"': {
+ start = i + 1;
+ charsetState = CHARSET_DOUBLE_QUOTED;
+ continue;
+ }
+ default: {
+ start = i;
+ charsetState = CHARSET_UNQUOTED;
+ continue;
+ }
+ }
+ }
+ case CHARSET_SINGLE_QUOTED: {
+ switch (c) {
+ case '\'': {
+ end = i;
+ NS_HTML5_BREAK(charsetloop);
+ }
+ default: {
+ continue;
+ }
+ }
+ }
+ case CHARSET_DOUBLE_QUOTED: {
+ switch (c) {
+ case '\"': {
+ end = i;
+ NS_HTML5_BREAK(charsetloop);
+ }
+ default: {
+ continue;
+ }
+ }
+ }
+ case CHARSET_UNQUOTED: {
+ switch (c) {
+ case '\t':
+ case '\n':
+ case '\f':
+ case '\r':
+ case ' ':
+ case ';': {
+ end = i;
+ NS_HTML5_BREAK(charsetloop);
+ }
+ default: {
+ continue;
+ }
+ }
+ }
+ }
+ }
+charsetloop_end:;
+ if (start != -1) {
+ if (end == -1) {
+ if (charsetState == CHARSET_UNQUOTED) {
+ end = buffer.length;
+ } else {
+ return nullptr;
+ }
+ }
+ return nsHtml5Portability::newStringFromBuffer(buffer, start, end - start,
+ tb, false);
+ }
+ return nullptr;
+}
+
+void nsHtml5TreeBuilder::checkMetaCharset(nsHtml5HtmlAttributes* attributes) {
+ nsHtml5String charset =
+ attributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
+ if (charset) {
+ if (tokenizer->internalEncodingDeclaration(charset)) {
+ requestSuspension();
+ return;
+ }
+ return;
+ }
+ if (!nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
+ "content-type",
+ attributes->getValue(nsHtml5AttributeName::ATTR_HTTP_EQUIV))) {
+ return;
+ }
+ nsHtml5String content =
+ attributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
+ if (content) {
+ nsHtml5String extract =
+ nsHtml5TreeBuilder::extractCharsetFromContent(content, this);
+ if (extract) {
+ if (tokenizer->internalEncodingDeclaration(extract)) {
+ requestSuspension();
+ }
+ }
+ extract.Release();
+ }
+}
+
+void nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName) {
+ flushCharacters();
+ needToDropLF = false;
+ int32_t eltPos;
+ int32_t group = elementName->getGroup();
+ nsAtom* name = elementName->getName();
+ for (;;) {
+ if (isInForeign()) {
+ if (stack[currentPtr]->name != name) {
+ if (!currentPtr) {
+ errStrayEndTag(name);
+ } else {
+ errEndTagDidNotMatchCurrentOpenElement(name,
+ stack[currentPtr]->popName);
+ }
+ }
+ eltPos = currentPtr;
+ int32_t origPos = currentPtr;
+ for (;;) {
+ if (!eltPos) {
+ MOZ_ASSERT(fragment,
+ "We can get this close to the root of the stack in "
+ "foreign content only in the fragment case.");
+ NS_HTML5_BREAK(endtagloop);
+ }
+ if (stack[eltPos]->name == name) {
+ while (currentPtr >= eltPos) {
+ popForeign(origPos, eltPos);
+ }
+ NS_HTML5_BREAK(endtagloop);
+ }
+ if (stack[--eltPos]->ns == kNameSpaceID_XHTML) {
+ break;
+ }
+ }
+ }
+ switch (mode) {
+ case IN_TEMPLATE: {
+ switch (group) {
+ case TEMPLATE: {
+ break;
+ }
+ default: {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ }
+ [[fallthrough]];
+ }
+ case IN_ROW: {
+ switch (group) {
+ case TR: {
+ eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
+ if (!eltPos) {
+ MOZ_ASSERT(fragment || isTemplateContents());
+ errNoTableRowToClose();
+ NS_HTML5_BREAK(endtagloop);
+ }
+ clearStackBackTo(eltPos);
+ pop();
+ mode = IN_TABLE_BODY;
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case TABLE: {
+ eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
+ if (!eltPos) {
+ MOZ_ASSERT(fragment || isTemplateContents());
+ errNoTableRowToClose();
+ NS_HTML5_BREAK(endtagloop);
+ }
+ clearStackBackTo(eltPos);
+ pop();
+ mode = IN_TABLE_BODY;
+ continue;
+ }
+ case TBODY_OR_THEAD_OR_TFOOT: {
+ if (findLastInTableScope(name) ==
+ nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ eltPos = findLastOrRoot(nsHtml5TreeBuilder::TR);
+ if (!eltPos) {
+ MOZ_ASSERT(fragment || isTemplateContents());
+ errNoTableRowToClose();
+ NS_HTML5_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);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ default:; // fall through
+ }
+ [[fallthrough]];
+ }
+ case IN_TABLE_BODY: {
+ switch (group) {
+ case TBODY_OR_THEAD_OR_TFOOT: {
+ eltPos = findLastOrRoot(name);
+ if (!eltPos) {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ clearStackBackTo(eltPos);
+ pop();
+ mode = IN_TABLE;
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case TABLE: {
+ eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
+ if (!eltPos || stack[eltPos]->getGroup() == TEMPLATE) {
+ MOZ_ASSERT(fragment || isTemplateContents());
+ errStrayEndTag(name);
+ NS_HTML5_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);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ default:; // fall through
+ }
+ [[fallthrough]];
+ }
+ case IN_TABLE: {
+ switch (group) {
+ case TABLE: {
+ eltPos = findLast(nsGkAtoms::table);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ MOZ_ASSERT(fragment || isTemplateContents());
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ resetTheInsertionMode();
+ NS_HTML5_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);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case TEMPLATE: {
+ break;
+ }
+ default: {
+ errStrayEndTag(name);
+ }
+ }
+ [[fallthrough]];
+ }
+ case IN_CAPTION: {
+ switch (group) {
+ case CAPTION: {
+ eltPos = findLastInTableScope(nsGkAtoms::caption);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ NS_HTML5_BREAK(endtagloop);
+ }
+ generateImpliedEndTags();
+ if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) {
+ errUnclosedElements(eltPos, name);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ clearTheListOfActiveFormattingElementsUpToTheLastMarker();
+ mode = IN_TABLE;
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case TABLE: {
+ eltPos = findLastInTableScope(nsGkAtoms::caption);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ MOZ_ASSERT(fragment || isTemplateContents());
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ generateImpliedEndTags();
+ if (!!MOZ_UNLIKELY(mViewSource) && 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);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ default:; // fall through
+ }
+ [[fallthrough]];
+ }
+ case IN_CELL: {
+ switch (group) {
+ case TD_OR_TH: {
+ eltPos = findLastInTableScope(name);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ generateImpliedEndTags();
+ if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
+ errUnclosedElements(eltPos, name);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ clearTheListOfActiveFormattingElementsUpToTheLastMarker();
+ mode = IN_ROW;
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case TABLE:
+ case TBODY_OR_THEAD_OR_TFOOT:
+ case TR: {
+ if (findLastInTableScope(name) ==
+ nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ MOZ_ASSERT(name == nsGkAtoms::tbody || name == nsGkAtoms::tfoot ||
+ name == nsGkAtoms::thead || fragment ||
+ isTemplateContents());
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ closeTheCell(findLastInTableScopeTdTh());
+ continue;
+ }
+ case BODY:
+ case CAPTION:
+ case COL:
+ case COLGROUP:
+ case HTML: {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ default:; // fall through
+ }
+ [[fallthrough]];
+ }
+ case FRAMESET_OK:
+ case IN_BODY: {
+ switch (group) {
+ case BODY: {
+ if (!isSecondOnStackBody()) {
+ MOZ_ASSERT(fragment || isTemplateContents());
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ MOZ_ASSERT(currentPtr >= 1);
+ if (MOZ_UNLIKELY(mViewSource)) {
+ for (int32_t i = 2; i <= currentPtr; i++) {
+ switch (stack[i]->getGroup()) {
+ case DD_OR_DT:
+ case LI:
+ case OPTGROUP:
+ case OPTION:
+ case P:
+ case RB_OR_RTC:
+ case RT_OR_RP:
+ case TD_OR_TH:
+ case TBODY_OR_THEAD_OR_TFOOT: {
+ break;
+ }
+ default: {
+ errEndWithUnclosedElements(name);
+ NS_HTML5_BREAK(uncloseloop1);
+ }
+ }
+ }
+ uncloseloop1_end:;
+ }
+ mode = AFTER_BODY;
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case HTML: {
+ if (!isSecondOnStackBody()) {
+ MOZ_ASSERT(fragment || isTemplateContents());
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ if (MOZ_UNLIKELY(mViewSource)) {
+ for (int32_t 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);
+ NS_HTML5_BREAK(uncloseloop2);
+ }
+ }
+ }
+ uncloseloop2_end:;
+ }
+ 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 == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ errStrayEndTag(name);
+ } else {
+ generateImpliedEndTags();
+ if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
+ errUnclosedElements(eltPos, name);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ }
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case FORM: {
+ if (!isTemplateContents()) {
+ if (!formPointer) {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ formPointer = nullptr;
+ eltPos = findLastInScope(name);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ generateImpliedEndTags();
+ if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
+ errUnclosedElements(eltPos, name);
+ }
+ removeFromStack(eltPos);
+ NS_HTML5_BREAK(endtagloop);
+ } else {
+ eltPos = findLastInScope(name);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ generateImpliedEndTags();
+ if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
+ errUnclosedElements(eltPos, name);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ NS_HTML5_BREAK(endtagloop);
+ }
+ }
+ case P: {
+ eltPos = findLastInButtonScope(nsGkAtoms::p);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ errNoElementToCloseButEndTagSeen(nsGkAtoms::p);
+ if (isInForeign()) {
+ errHtmlStartTagInForeignContext(name);
+ while (currentPtr >= 0 &&
+ stack[currentPtr]->ns != kNameSpaceID_XHTML) {
+ pop();
+ }
+ }
+ appendVoidElementToCurrentMayFoster(
+ elementName, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ generateImpliedEndTagsExceptFor(nsGkAtoms::p);
+ MOZ_ASSERT(eltPos != nsHtml5TreeBuilder::NOT_FOUND_ON_STACK);
+ if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
+ errUnclosedElements(eltPos, name);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case LI: {
+ eltPos = findLastInListScope(name);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ errNoElementToCloseButEndTagSeen(name);
+ } else {
+ generateImpliedEndTagsExceptFor(name);
+ if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
+ errUnclosedElements(eltPos, name);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ }
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case DD_OR_DT: {
+ eltPos = findLastInScope(name);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ errNoElementToCloseButEndTagSeen(name);
+ } else {
+ generateImpliedEndTagsExceptFor(name);
+ if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
+ errUnclosedElements(eltPos, name);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ }
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: {
+ eltPos = findLastInScopeHn();
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ errStrayEndTag(name);
+ } else {
+ generateImpliedEndTags();
+ if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
+ errUnclosedElements(eltPos, name);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ }
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case OBJECT:
+ case MARQUEE_OR_APPLET: {
+ eltPos = findLastInScope(name);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ errStrayEndTag(name);
+ } else {
+ generateImpliedEndTags();
+ if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
+ errUnclosedElements(eltPos, name);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ clearTheListOfActiveFormattingElementsUpToTheLastMarker();
+ }
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case BR: {
+ errEndTagBr();
+ if (isInForeign()) {
+ errHtmlStartTagInForeignContext(name);
+ while (currentPtr >= 0 &&
+ stack[currentPtr]->ns != kNameSpaceID_XHTML) {
+ pop();
+ }
+ }
+ reconstructTheActiveFormattingElements();
+ appendVoidElementToCurrentMayFoster(
+ elementName, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case TEMPLATE: {
+ break;
+ }
+ case AREA_OR_WBR:
+ case KEYGEN:
+ case PARAM_OR_SOURCE_OR_TRACK:
+ case EMBED:
+ case IMG:
+ case IMAGE:
+ case INPUT:
+ case HR:
+ case IFRAME:
+ case NOEMBED:
+ case NOFRAMES:
+ case SELECT:
+ case TABLE:
+ case TEXTAREA: {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case NOSCRIPT: {
+ if (scriptingEnabled) {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ [[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)) {
+ NS_HTML5_BREAK(endtagloop);
+ }
+ [[fallthrough]];
+ }
+ default: {
+ if (isCurrent(name)) {
+ pop();
+ NS_HTML5_BREAK(endtagloop);
+ }
+ eltPos = currentPtr;
+ for (;;) {
+ nsHtml5StackNode* node = stack[eltPos];
+ if (node->ns == kNameSpaceID_XHTML && node->name == name) {
+ generateImpliedEndTags();
+ if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) {
+ errUnclosedElements(eltPos, name);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ NS_HTML5_BREAK(endtagloop);
+ } else if (!eltPos || node->isSpecial()) {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ eltPos--;
+ }
+ }
+ }
+ [[fallthrough]];
+ }
+ case IN_HEAD: {
+ switch (group) {
+ case HEAD: {
+ pop();
+ mode = AFTER_HEAD;
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case BR:
+ case HTML:
+ case BODY: {
+ pop();
+ mode = AFTER_HEAD;
+ continue;
+ }
+ case TEMPLATE: {
+ endTagTemplateInHead();
+ NS_HTML5_BREAK(endtagloop);
+ }
+ default: {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ }
+ }
+ case IN_HEAD_NOSCRIPT: {
+ switch (group) {
+ case NOSCRIPT: {
+ pop();
+ mode = IN_HEAD;
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case BR: {
+ errStrayEndTag(name);
+ pop();
+ mode = IN_HEAD;
+ continue;
+ }
+ default: {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ }
+ }
+ case IN_COLUMN_GROUP: {
+ switch (group) {
+ case COLGROUP: {
+ if (!currentPtr ||
+ stack[currentPtr]->getGroup() == nsHtml5TreeBuilder::TEMPLATE) {
+ MOZ_ASSERT(fragment || isTemplateContents());
+ errGarbageInColgroup();
+ NS_HTML5_BREAK(endtagloop);
+ }
+ pop();
+ mode = IN_TABLE;
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case COL: {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case TEMPLATE: {
+ endTagTemplateInHead();
+ NS_HTML5_BREAK(endtagloop);
+ }
+ default: {
+ if (!currentPtr ||
+ stack[currentPtr]->getGroup() == nsHtml5TreeBuilder::TEMPLATE) {
+ MOZ_ASSERT(fragment || isTemplateContents());
+ errGarbageInColgroup();
+ NS_HTML5_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) !=
+ nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ eltPos = findLastInTableScope(nsGkAtoms::select);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ MOZ_ASSERT(fragment);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ resetTheInsertionMode();
+ continue;
+ } else {
+ NS_HTML5_BREAK(endtagloop);
+ }
+ }
+ default:; // fall through
+ }
+ [[fallthrough]];
+ }
+ case IN_SELECT: {
+ switch (group) {
+ case OPTION: {
+ if (isCurrent(nsGkAtoms::option)) {
+ pop();
+ NS_HTML5_BREAK(endtagloop);
+ } else {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ }
+ case OPTGROUP: {
+ if (isCurrent(nsGkAtoms::option) &&
+ nsGkAtoms::optgroup == stack[currentPtr - 1]->name) {
+ pop();
+ }
+ if (isCurrent(nsGkAtoms::optgroup)) {
+ pop();
+ } else {
+ errStrayEndTag(name);
+ }
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case SELECT: {
+ eltPos = findLastInTableScope(nsGkAtoms::select);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ MOZ_ASSERT(fragment);
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ resetTheInsertionMode();
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case TEMPLATE: {
+ endTagTemplateInHead();
+ NS_HTML5_BREAK(endtagloop);
+ }
+ default: {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ }
+ }
+ case AFTER_BODY: {
+ switch (group) {
+ case HTML: {
+ if (fragment) {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ } else {
+ mode = AFTER_AFTER_BODY;
+ NS_HTML5_BREAK(endtagloop);
+ }
+ }
+ default: {
+ errEndTagAfterBody();
+ mode = framesetOk ? FRAMESET_OK : IN_BODY;
+ continue;
+ }
+ }
+ }
+ case IN_FRAMESET: {
+ switch (group) {
+ case FRAMESET: {
+ if (!currentPtr) {
+ MOZ_ASSERT(fragment);
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ pop();
+ if ((!fragment) && !isCurrent(nsGkAtoms::frameset)) {
+ mode = AFTER_FRAMESET;
+ }
+ NS_HTML5_BREAK(endtagloop);
+ }
+ default: {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ }
+ }
+ case AFTER_FRAMESET: {
+ switch (group) {
+ case HTML: {
+ mode = AFTER_AFTER_FRAMESET;
+ NS_HTML5_BREAK(endtagloop);
+ }
+ default: {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ }
+ }
+ case INITIAL: {
+ errEndTagSeenWithoutDoctype();
+ documentModeInternal(QUIRKS_MODE, nullptr, nullptr);
+ mode = BEFORE_HTML;
+ continue;
+ }
+ case BEFORE_HTML: {
+ switch (group) {
+ case HEAD:
+ case BR:
+ case HTML:
+ case BODY: {
+ appendHtmlElementToDocumentAndPush();
+ mode = BEFORE_HEAD;
+ continue;
+ }
+ default: {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ }
+ }
+ case BEFORE_HEAD: {
+ switch (group) {
+ case HEAD:
+ case BR:
+ case HTML:
+ case BODY: {
+ appendToCurrentNodeAndPushHeadElement(
+ nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
+ mode = IN_HEAD;
+ continue;
+ }
+ default: {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ }
+ }
+ case AFTER_HEAD: {
+ switch (group) {
+ case TEMPLATE: {
+ endTagTemplateInHead();
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case HTML:
+ case BODY:
+ case BR: {
+ appendToCurrentNodeAndPushBodyElement();
+ mode = FRAMESET_OK;
+ continue;
+ }
+ default: {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ }
+ }
+ case AFTER_AFTER_BODY: {
+ errStrayEndTag(name);
+ mode = framesetOk ? FRAMESET_OK : IN_BODY;
+ continue;
+ }
+ case AFTER_AFTER_FRAMESET: {
+ errStrayEndTag(name);
+ NS_HTML5_BREAK(endtagloop);
+ }
+ case TEXT: {
+ pop();
+ if (originalMode == AFTER_HEAD) {
+ silentPop();
+ }
+ mode = originalMode;
+ NS_HTML5_BREAK(endtagloop);
+ }
+ }
+ }
+endtagloop_end:;
+}
+
+void nsHtml5TreeBuilder::endTagTemplateInHead() {
+ int32_t eltPos = findLast(nsGkAtoms::_template);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ errStrayEndTag(nsGkAtoms::_template);
+ return;
+ }
+ generateImpliedEndTagsThoroughly();
+ if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(nsGkAtoms::_template)) {
+ errUnclosedElements(eltPos, nsGkAtoms::_template);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ clearTheListOfActiveFormattingElementsUpToTheLastMarker();
+ popTemplateMode();
+ resetTheInsertionMode();
+}
+
+int32_t
+nsHtml5TreeBuilder::findLastInTableScopeOrRootTemplateTbodyTheadTfoot() {
+ for (int32_t i = currentPtr; i > 0; i--) {
+ if (stack[i]->ns == kNameSpaceID_XHTML &&
+ (stack[i]->getGroup() == nsHtml5TreeBuilder::TBODY_OR_THEAD_OR_TFOOT ||
+ stack[i]->getGroup() == nsHtml5TreeBuilder::TEMPLATE)) {
+ return i;
+ }
+ }
+ return 0;
+}
+
+int32_t nsHtml5TreeBuilder::findLast(nsAtom* name) {
+ for (int32_t i = currentPtr; i > 0; i--) {
+ if (stack[i]->ns == kNameSpaceID_XHTML && stack[i]->name == name) {
+ return i;
+ }
+ }
+ return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
+}
+
+int32_t nsHtml5TreeBuilder::findLastInTableScope(nsAtom* name) {
+ for (int32_t i = currentPtr; i > 0; i--) {
+ if (stack[i]->ns == kNameSpaceID_XHTML) {
+ if (stack[i]->name == name) {
+ return i;
+ } else if (stack[i]->name == nsGkAtoms::table ||
+ stack[i]->name == nsGkAtoms::_template) {
+ return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
+ }
+ }
+ }
+ return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
+}
+
+int32_t nsHtml5TreeBuilder::findLastInButtonScope(nsAtom* name) {
+ for (int32_t i = currentPtr; i > 0; i--) {
+ if (stack[i]->ns == kNameSpaceID_XHTML) {
+ if (stack[i]->name == name) {
+ return i;
+ } else if (stack[i]->name == nsGkAtoms::button) {
+ return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
+ }
+ }
+ if (stack[i]->isScoping()) {
+ return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
+ }
+ }
+ return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
+}
+
+int32_t nsHtml5TreeBuilder::findLastInScope(nsAtom* name) {
+ for (int32_t i = currentPtr; i > 0; i--) {
+ if (stack[i]->ns == kNameSpaceID_XHTML && stack[i]->name == name) {
+ return i;
+ } else if (stack[i]->isScoping()) {
+ return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
+ }
+ }
+ return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
+}
+
+int32_t nsHtml5TreeBuilder::findLastInListScope(nsAtom* name) {
+ for (int32_t i = currentPtr; i > 0; i--) {
+ if (stack[i]->ns == kNameSpaceID_XHTML) {
+ if (stack[i]->name == name) {
+ return i;
+ } else if (stack[i]->name == nsGkAtoms::ul ||
+ stack[i]->name == nsGkAtoms::ol) {
+ return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
+ }
+ }
+ if (stack[i]->isScoping()) {
+ return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
+ }
+ }
+ return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
+}
+
+int32_t nsHtml5TreeBuilder::findLastInScopeHn() {
+ for (int32_t i = currentPtr; i > 0; i--) {
+ if (stack[i]->getGroup() ==
+ nsHtml5TreeBuilder::H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) {
+ return i;
+ } else if (stack[i]->isScoping()) {
+ return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
+ }
+ }
+ return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
+}
+
+void nsHtml5TreeBuilder::generateImpliedEndTagsExceptFor(nsAtom* name) {
+ for (;;) {
+ nsHtml5StackNode* 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 == kNameSpaceID_XHTML && node->name == name) {
+ return;
+ }
+ pop();
+ continue;
+ }
+ default: {
+ return;
+ }
+ }
+ }
+}
+
+void nsHtml5TreeBuilder::generateImpliedEndTags() {
+ 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;
+ }
+ }
+ }
+}
+
+void nsHtml5TreeBuilder::generateImpliedEndTagsThoroughly() {
+ 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;
+ }
+ }
+ }
+}
+
+bool nsHtml5TreeBuilder::isSecondOnStackBody() {
+ return currentPtr >= 1 && stack[1]->getGroup() == nsHtml5TreeBuilder::BODY;
+}
+
+void nsHtml5TreeBuilder::documentModeInternal(nsHtml5DocumentMode m,
+ nsHtml5String publicIdentifier,
+ nsHtml5String systemIdentifier) {
+ if (forceNoQuirks) {
+ quirks = false;
+ this->documentMode(STANDARDS_MODE);
+ return;
+ }
+ quirks = (m == QUIRKS_MODE);
+ this->documentMode(m);
+}
+
+bool nsHtml5TreeBuilder::isAlmostStandards(nsHtml5String publicIdentifier,
+ nsHtml5String systemIdentifier) {
+ if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
+ "-//w3c//dtd xhtml 1.0 transitional//", publicIdentifier)) {
+ return true;
+ }
+ if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
+ "-//w3c//dtd xhtml 1.0 frameset//", publicIdentifier)) {
+ return true;
+ }
+ if (systemIdentifier) {
+ if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
+ "-//w3c//dtd html 4.01 transitional//", publicIdentifier)) {
+ return true;
+ }
+ if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
+ "-//w3c//dtd html 4.01 frameset//", publicIdentifier)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool nsHtml5TreeBuilder::isQuirky(nsAtom* name, nsHtml5String publicIdentifier,
+ nsHtml5String systemIdentifier,
+ bool forceQuirks) {
+ if (forceQuirks) {
+ return true;
+ }
+ if (name != nsGkAtoms::html) {
+ return true;
+ }
+ if (publicIdentifier) {
+ for (int32_t i = 0; i < nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS.length; i++) {
+ if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
+ nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS[i], publicIdentifier)) {
+ return true;
+ }
+ }
+ if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
+ "-//w3o//dtd w3 html strict 3.0//en//", publicIdentifier) ||
+ nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
+ "-/w3c/dtd html 4.0 transitional/en", publicIdentifier) ||
+ nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
+ "html", publicIdentifier)) {
+ return true;
+ }
+ }
+ if (!systemIdentifier) {
+ if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
+ "-//w3c//dtd html 4.01 transitional//", publicIdentifier)) {
+ return true;
+ } else if (nsHtml5Portability::
+ lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
+ "-//w3c//dtd html 4.01 frameset//", publicIdentifier)) {
+ return true;
+ }
+ } else if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
+ "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd",
+ systemIdentifier)) {
+ return true;
+ }
+ return false;
+}
+
+void nsHtml5TreeBuilder::closeTheCell(int32_t eltPos) {
+ generateImpliedEndTags();
+ if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
+ errUnclosedElementsCell(eltPos);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+ clearTheListOfActiveFormattingElementsUpToTheLastMarker();
+ mode = IN_ROW;
+ return;
+}
+
+int32_t nsHtml5TreeBuilder::findLastInTableScopeTdTh() {
+ for (int32_t i = currentPtr; i > 0; i--) {
+ nsAtom* name = stack[i]->name;
+ if (stack[i]->ns == kNameSpaceID_XHTML) {
+ if (nsGkAtoms::td == name || nsGkAtoms::th == name) {
+ return i;
+ } else if (name == nsGkAtoms::table || name == nsGkAtoms::_template) {
+ return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
+ }
+ }
+ }
+ return nsHtml5TreeBuilder::NOT_FOUND_ON_STACK;
+}
+
+void nsHtml5TreeBuilder::clearStackBackTo(int32_t eltPos) {
+ int32_t eltGroup = stack[eltPos]->getGroup();
+ while (currentPtr > eltPos) {
+ if (stack[currentPtr]->ns == kNameSpaceID_XHTML &&
+ stack[currentPtr]->getGroup() == TEMPLATE &&
+ (eltGroup == TABLE || eltGroup == TBODY_OR_THEAD_OR_TFOOT ||
+ eltGroup == TR || !eltPos)) {
+ return;
+ }
+ pop();
+ }
+}
+
+void nsHtml5TreeBuilder::resetTheInsertionMode() {
+ nsHtml5StackNode* node;
+ nsAtom* name;
+ int32_t ns;
+ for (int32_t i = currentPtr; i >= 0; i--) {
+ node = stack[i];
+ name = node->name;
+ ns = node->ns;
+ if (!i) {
+ if (!(contextNamespace == kNameSpaceID_XHTML &&
+ (contextName == nsGkAtoms::td || contextName == nsGkAtoms::th))) {
+ if (fragment) {
+ name = contextName;
+ ns = contextNamespace;
+ }
+ } else {
+ mode = framesetOk ? FRAMESET_OK : IN_BODY;
+ return;
+ }
+ }
+ if (nsGkAtoms::select == name) {
+ int32_t ancestorIndex = i;
+ while (ancestorIndex > 0) {
+ nsHtml5StackNode* ancestor = stack[ancestorIndex--];
+ if (kNameSpaceID_XHTML == ancestor->ns) {
+ if (nsGkAtoms::_template == ancestor->name) {
+ break;
+ }
+ if (nsGkAtoms::table == ancestor->name) {
+ mode = IN_SELECT_IN_TABLE;
+ return;
+ }
+ }
+ }
+ mode = IN_SELECT;
+ return;
+ } else if (nsGkAtoms::td == name || nsGkAtoms::th == name) {
+ mode = IN_CELL;
+ return;
+ } else if (nsGkAtoms::tr == name) {
+ mode = IN_ROW;
+ return;
+ } else if (nsGkAtoms::tbody == name || nsGkAtoms::thead == name ||
+ nsGkAtoms::tfoot == name) {
+ mode = IN_TABLE_BODY;
+ return;
+ } else if (nsGkAtoms::caption == name) {
+ mode = IN_CAPTION;
+ return;
+ } else if (nsGkAtoms::colgroup == name) {
+ mode = IN_COLUMN_GROUP;
+ return;
+ } else if (nsGkAtoms::table == name) {
+ mode = IN_TABLE;
+ return;
+ } else if (kNameSpaceID_XHTML != ns) {
+ mode = framesetOk ? FRAMESET_OK : IN_BODY;
+ return;
+ } else if (nsGkAtoms::_template == name) {
+ MOZ_ASSERT(templateModePtr >= 0);
+ mode = templateModeStack[templateModePtr];
+ return;
+ } else if (nsGkAtoms::head == name) {
+ if (name == contextName) {
+ mode = framesetOk ? FRAMESET_OK : IN_BODY;
+ } else {
+ mode = IN_HEAD;
+ }
+ return;
+ } else if (nsGkAtoms::body == name) {
+ mode = framesetOk ? FRAMESET_OK : IN_BODY;
+ return;
+ } else if (nsGkAtoms::frameset == name) {
+ mode = IN_FRAMESET;
+ return;
+ } else if (nsGkAtoms::html == name) {
+ if (!headPointer) {
+ mode = BEFORE_HEAD;
+ } else {
+ mode = AFTER_HEAD;
+ }
+ return;
+ } else if (!i) {
+ mode = framesetOk ? FRAMESET_OK : IN_BODY;
+ return;
+ }
+ }
+}
+
+void nsHtml5TreeBuilder::implicitlyCloseP() {
+ int32_t eltPos = findLastInButtonScope(nsGkAtoms::p);
+ if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
+ return;
+ }
+ generateImpliedEndTagsExceptFor(nsGkAtoms::p);
+ if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) {
+ errUnclosedElementsImplied(eltPos, nsGkAtoms::p);
+ }
+ while (currentPtr >= eltPos) {
+ pop();
+ }
+}
+
+bool nsHtml5TreeBuilder::debugOnlyClearLastStackSlot() {
+ stack[currentPtr] = nullptr;
+ return true;
+}
+
+bool nsHtml5TreeBuilder::debugOnlyClearLastListSlot() {
+ listOfActiveFormattingElements[listPtr] = nullptr;
+ return true;
+}
+
+void nsHtml5TreeBuilder::pushTemplateMode(int32_t mode) {
+ templateModePtr++;
+ if (templateModePtr == templateModeStack.length) {
+ jArray<int32_t, int32_t> newStack =
+ jArray<int32_t, int32_t>::newJArray(templateModeStack.length + 64);
+ nsHtml5ArrayCopy::arraycopy(templateModeStack, newStack,
+ templateModeStack.length);
+ templateModeStack = newStack;
+ }
+ templateModeStack[templateModePtr] = mode;
+}
+
+void nsHtml5TreeBuilder::push(nsHtml5StackNode* node) {
+ currentPtr++;
+ if (currentPtr == stack.length) {
+ jArray<nsHtml5StackNode*, int32_t> newStack =
+ jArray<nsHtml5StackNode*, int32_t>::newJArray(stack.length + 64);
+ nsHtml5ArrayCopy::arraycopy(stack, newStack, stack.length);
+ stack = newStack;
+ }
+ stack[currentPtr] = node;
+ elementPushed(node->ns, node->popName, node->node);
+}
+
+void nsHtml5TreeBuilder::silentPush(nsHtml5StackNode* node) {
+ currentPtr++;
+ if (currentPtr == stack.length) {
+ jArray<nsHtml5StackNode*, int32_t> newStack =
+ jArray<nsHtml5StackNode*, int32_t>::newJArray(stack.length + 64);
+ nsHtml5ArrayCopy::arraycopy(stack, newStack, stack.length);
+ stack = newStack;
+ }
+ stack[currentPtr] = node;
+}
+
+void nsHtml5TreeBuilder::append(nsHtml5StackNode* node) {
+ listPtr++;
+ if (listPtr == listOfActiveFormattingElements.length) {
+ jArray<nsHtml5StackNode*, int32_t> newList =
+ jArray<nsHtml5StackNode*, int32_t>::newJArray(
+ listOfActiveFormattingElements.length + 64);
+ nsHtml5ArrayCopy::arraycopy(listOfActiveFormattingElements, newList,
+ listOfActiveFormattingElements.length);
+ listOfActiveFormattingElements = newList;
+ }
+ listOfActiveFormattingElements[listPtr] = node;
+}
+
+void nsHtml5TreeBuilder::
+ clearTheListOfActiveFormattingElementsUpToTheLastMarker() {
+ while (listPtr > -1) {
+ if (!listOfActiveFormattingElements[listPtr]) {
+ --listPtr;
+ return;
+ }
+ listOfActiveFormattingElements[listPtr]->release(this);
+ --listPtr;
+ }
+}
+
+void nsHtml5TreeBuilder::removeFromStack(int32_t pos) {
+ if (currentPtr == pos) {
+ pop();
+ } else {
+ stack[pos]->release(this);
+ nsHtml5ArrayCopy::arraycopy(stack, pos + 1, pos, currentPtr - pos);
+ MOZ_ASSERT(debugOnlyClearLastStackSlot());
+ currentPtr--;
+ }
+}
+
+void nsHtml5TreeBuilder::removeFromStack(nsHtml5StackNode* node) {
+ if (stack[currentPtr] == node) {
+ pop();
+ } else {
+ int32_t pos = currentPtr - 1;
+ while (pos >= 0 && stack[pos] != node) {
+ pos--;
+ }
+ if (pos == -1) {
+ return;
+ }
+
+ node->release(this);
+ nsHtml5ArrayCopy::arraycopy(stack, pos + 1, pos, currentPtr - pos);
+ currentPtr--;
+ }
+}
+
+void nsHtml5TreeBuilder::removeFromListOfActiveFormattingElements(int32_t pos) {
+ MOZ_ASSERT(!!listOfActiveFormattingElements[pos]);
+ listOfActiveFormattingElements[pos]->release(this);
+ if (pos == listPtr) {
+ MOZ_ASSERT(debugOnlyClearLastListSlot());
+ listPtr--;
+ return;
+ }
+ MOZ_ASSERT(pos < listPtr);
+ nsHtml5ArrayCopy::arraycopy(listOfActiveFormattingElements, pos + 1, pos,
+ listPtr - pos);
+ MOZ_ASSERT(debugOnlyClearLastListSlot());
+ listPtr--;
+}
+
+bool nsHtml5TreeBuilder::adoptionAgencyEndTag(nsAtom* name) {
+ if (stack[currentPtr]->ns == kNameSpaceID_XHTML &&
+ stack[currentPtr]->name == name &&
+ findInListOfActiveFormattingElements(stack[currentPtr]) == -1) {
+ pop();
+ return true;
+ }
+ for (int32_t i = 0; i < 8; ++i) {
+ int32_t formattingEltListPos = listPtr;
+ while (formattingEltListPos > -1) {
+ nsHtml5StackNode* listNode =
+ listOfActiveFormattingElements[formattingEltListPos];
+ if (!listNode) {
+ formattingEltListPos = -1;
+ break;
+ } else if (listNode->name == name) {
+ break;
+ }
+ formattingEltListPos--;
+ }
+ if (formattingEltListPos == -1) {
+ return false;
+ }
+ nsHtml5StackNode* formattingElt =
+ listOfActiveFormattingElements[formattingEltListPos];
+ int32_t formattingEltStackPos = currentPtr;
+ bool inScope = true;
+ while (formattingEltStackPos > -1) {
+ nsHtml5StackNode* node = stack[formattingEltStackPos];
+ if (node == formattingElt) {
+ break;
+ } else if (node->isScoping()) {
+ inScope = false;
+ }
+ formattingEltStackPos--;
+ }
+ if (formattingEltStackPos == -1) {
+ errNoElementToCloseButEndTagSeen(name);
+ removeFromListOfActiveFormattingElements(formattingEltListPos);
+ return true;
+ }
+ if (!inScope) {
+ errNoElementToCloseButEndTagSeen(name);
+ return true;
+ }
+ if (formattingEltStackPos != currentPtr) {
+ errEndTagViolatesNestingRules(name);
+ }
+ int32_t furthestBlockPos = formattingEltStackPos + 1;
+ while (furthestBlockPos <= currentPtr) {
+ nsHtml5StackNode* node = stack[furthestBlockPos];
+ MOZ_ASSERT(furthestBlockPos > 0,
+ "How is formattingEltStackPos + 1 not > 0?");
+ if (node->isSpecial()) {
+ break;
+ }
+ furthestBlockPos++;
+ }
+ if (furthestBlockPos > currentPtr) {
+ while (currentPtr >= formattingEltStackPos) {
+ pop();
+ }
+ removeFromListOfActiveFormattingElements(formattingEltListPos);
+ return true;
+ }
+ nsHtml5StackNode* commonAncestor = stack[formattingEltStackPos - 1];
+ nsIContentHandle* insertionCommonAncestor =
+ nodeFromStackWithBlinkCompat(formattingEltStackPos - 1);
+ nsHtml5StackNode* furthestBlock = stack[furthestBlockPos];
+ int32_t bookmark = formattingEltListPos;
+ int32_t nodePos = furthestBlockPos;
+ nsHtml5StackNode* lastNode = furthestBlock;
+ int32_t j = 0;
+ for (;;) {
+ ++j;
+ nodePos--;
+ if (nodePos == formattingEltStackPos) {
+ break;
+ }
+ nsHtml5StackNode* node = stack[nodePos];
+ int32_t nodeListPos = findInListOfActiveFormattingElements(node);
+ if (j > 3 && nodeListPos != -1) {
+ removeFromListOfActiveFormattingElements(nodeListPos);
+ if (nodeListPos <= formattingEltListPos) {
+ formattingEltListPos--;
+ }
+ if (nodeListPos <= bookmark) {
+ bookmark--;
+ }
+ nodeListPos = -1;
+ }
+ if (nodeListPos == -1) {
+ MOZ_ASSERT(formattingEltStackPos < nodePos);
+ MOZ_ASSERT(bookmark < nodePos);
+ MOZ_ASSERT(furthestBlockPos > nodePos);
+ removeFromStack(nodePos);
+ furthestBlockPos--;
+ continue;
+ }
+ if (nodePos == furthestBlockPos) {
+ bookmark = nodeListPos + 1;
+ }
+ MOZ_ASSERT(node == listOfActiveFormattingElements[nodeListPos]);
+ MOZ_ASSERT(node == stack[nodePos]);
+ nsIContentHandle* clone = createElement(
+ kNameSpaceID_XHTML, node->name, node->attributes->cloneAttributes(),
+ insertionCommonAncestor, htmlCreator(node->getHtmlCreator()));
+ nsHtml5StackNode* newNode = createStackNode(
+ node->getFlags(), node->ns, node->name, clone, node->popName,
+ node->attributes, node->getHtmlCreator());
+ node->dropAttributes();
+ stack[nodePos] = newNode;
+ newNode->retain();
+ listOfActiveFormattingElements[nodeListPos] = newNode;
+ node->release(this);
+ node->release(this);
+ node = newNode;
+ detachFromParent(lastNode->node);
+ appendElement(lastNode->node, nodeFromStackWithBlinkCompat(nodePos));
+ lastNode = node;
+ }
+ if (commonAncestor->isFosterParenting()) {
+ detachFromParent(lastNode->node);
+ insertIntoFosterParent(lastNode->node);
+ } else {
+ detachFromParent(lastNode->node);
+ appendElement(lastNode->node, insertionCommonAncestor);
+ }
+ nsIContentHandle* clone = createElement(
+ kNameSpaceID_XHTML, formattingElt->name,
+ formattingElt->attributes->cloneAttributes(), furthestBlock->node,
+ htmlCreator(formattingElt->getHtmlCreator()));
+ nsHtml5StackNode* formattingClone = createStackNode(
+ formattingElt->getFlags(), formattingElt->ns, formattingElt->name,
+ clone, formattingElt->popName, formattingElt->attributes,
+ formattingElt->getHtmlCreator());
+ formattingElt->dropAttributes();
+ appendChildrenToNewParent(furthestBlock->node, clone);
+ appendElement(clone, furthestBlock->node);
+ removeFromListOfActiveFormattingElements(formattingEltListPos);
+ insertIntoListOfActiveFormattingElements(formattingClone, bookmark);
+ MOZ_ASSERT(formattingEltStackPos < furthestBlockPos);
+ removeFromStack(formattingEltStackPos);
+ insertIntoStack(formattingClone, furthestBlockPos);
+ }
+ return true;
+}
+
+void nsHtml5TreeBuilder::insertIntoStack(nsHtml5StackNode* node,
+ int32_t position) {
+ MOZ_ASSERT(currentPtr + 1 < stack.length);
+ MOZ_ASSERT(position <= currentPtr + 1);
+ if (position == currentPtr + 1) {
+ push(node);
+ } else {
+ nsHtml5ArrayCopy::arraycopy(stack, position, position + 1,
+ (currentPtr - position) + 1);
+ currentPtr++;
+ stack[position] = node;
+ }
+}
+
+void nsHtml5TreeBuilder::insertIntoListOfActiveFormattingElements(
+ nsHtml5StackNode* formattingClone, int32_t bookmark) {
+ formattingClone->retain();
+ MOZ_ASSERT(listPtr + 1 < listOfActiveFormattingElements.length);
+ if (bookmark <= listPtr) {
+ nsHtml5ArrayCopy::arraycopy(listOfActiveFormattingElements, bookmark,
+ bookmark + 1, (listPtr - bookmark) + 1);
+ }
+ listPtr++;
+ listOfActiveFormattingElements[bookmark] = formattingClone;
+}
+
+int32_t nsHtml5TreeBuilder::findInListOfActiveFormattingElements(
+ nsHtml5StackNode* node) {
+ for (int32_t i = listPtr; i >= 0; i--) {
+ if (node == listOfActiveFormattingElements[i]) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int32_t nsHtml5TreeBuilder::
+ findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker(
+ nsAtom* name) {
+ for (int32_t i = listPtr; i >= 0; i--) {
+ nsHtml5StackNode* node = listOfActiveFormattingElements[i];
+ if (!node) {
+ return -1;
+ } else if (node->name == name) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void nsHtml5TreeBuilder::maybeForgetEarlierDuplicateFormattingElement(
+ nsAtom* name, nsHtml5HtmlAttributes* attributes) {
+ int32_t candidate = -1;
+ int32_t count = 0;
+ for (int32_t i = listPtr; i >= 0; i--) {
+ nsHtml5StackNode* node = listOfActiveFormattingElements[i];
+ if (!node) {
+ break;
+ }
+ if (node->name == name && node->attributes->equalsAnother(attributes)) {
+ candidate = i;
+ ++count;
+ }
+ }
+ if (count >= 3) {
+ removeFromListOfActiveFormattingElements(candidate);
+ }
+}
+
+int32_t nsHtml5TreeBuilder::findLastOrRoot(nsAtom* name) {
+ for (int32_t i = currentPtr; i > 0; i--) {
+ if (stack[i]->ns == kNameSpaceID_XHTML && stack[i]->name == name) {
+ return i;
+ }
+ }
+ return 0;
+}
+
+int32_t nsHtml5TreeBuilder::findLastOrRoot(int32_t group) {
+ for (int32_t i = currentPtr; i > 0; i--) {
+ if (stack[i]->ns == kNameSpaceID_XHTML && stack[i]->getGroup() == group) {
+ return i;
+ }
+ }
+ return 0;
+}
+
+bool nsHtml5TreeBuilder::addAttributesToBody(
+ nsHtml5HtmlAttributes* attributes) {
+ if (currentPtr >= 1) {
+ nsHtml5StackNode* body = stack[1];
+ if (body->getGroup() == nsHtml5TreeBuilder::BODY) {
+ addAttributesToElement(body->node, attributes);
+ return true;
+ }
+ }
+ return false;
+}
+
+void nsHtml5TreeBuilder::addAttributesToHtml(
+ nsHtml5HtmlAttributes* attributes) {
+ addAttributesToElement(stack[0]->node, attributes);
+}
+
+void nsHtml5TreeBuilder::pushHeadPointerOntoStack() {
+ MOZ_ASSERT(!!headPointer);
+ MOZ_ASSERT(mode == AFTER_HEAD);
+
+ silentPush(createStackNode(nsHtml5ElementName::ELT_HEAD, headPointer));
+}
+
+void nsHtml5TreeBuilder::reconstructTheActiveFormattingElements() {
+ if (listPtr == -1) {
+ return;
+ }
+ nsHtml5StackNode* mostRecent = listOfActiveFormattingElements[listPtr];
+ if (!mostRecent || isInStack(mostRecent)) {
+ return;
+ }
+ int32_t entryPos = listPtr;
+ for (;;) {
+ entryPos--;
+ if (entryPos == -1) {
+ break;
+ }
+ if (!listOfActiveFormattingElements[entryPos]) {
+ break;
+ }
+ if (isInStack(listOfActiveFormattingElements[entryPos])) {
+ break;
+ }
+ }
+ while (entryPos < listPtr) {
+ entryPos++;
+ nsHtml5StackNode* entry = listOfActiveFormattingElements[entryPos];
+ nsHtml5StackNode* current = stack[currentPtr];
+ nsIContentHandle* clone;
+ if (current->isFosterParenting()) {
+ clone = createAndInsertFosterParentedElement(
+ kNameSpaceID_XHTML, entry->name, entry->attributes->cloneAttributes(),
+ htmlCreator(entry->getHtmlCreator()));
+ } else {
+ nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
+ clone = createElement(kNameSpaceID_XHTML, entry->name,
+ entry->attributes->cloneAttributes(), currentNode,
+ htmlCreator(entry->getHtmlCreator()));
+ appendElement(clone, currentNode);
+ }
+ nsHtml5StackNode* entryClone = createStackNode(
+ entry->getFlags(), entry->ns, entry->name, clone, entry->popName,
+ entry->attributes, entry->getHtmlCreator());
+ entry->dropAttributes();
+ push(entryClone);
+ listOfActiveFormattingElements[entryPos] = entryClone;
+ entry->release(this);
+ entryClone->retain();
+ }
+}
+
+void nsHtml5TreeBuilder::notifyUnusedStackNode(int32_t idxInStackNodes) {
+ if (idxInStackNodes < stackNodesIdx) {
+ stackNodesIdx = idxInStackNodes;
+ }
+}
+
+nsHtml5StackNode* nsHtml5TreeBuilder::getUnusedStackNode() {
+ while (stackNodesIdx < numStackNodes) {
+ if (stackNodes[stackNodesIdx]->isUnused()) {
+ return stackNodes[stackNodesIdx++];
+ }
+ stackNodesIdx++;
+ }
+ if (stackNodesIdx < stackNodes.length) {
+ stackNodes[stackNodesIdx] = new nsHtml5StackNode(stackNodesIdx);
+ numStackNodes++;
+ return stackNodes[stackNodesIdx++];
+ }
+ jArray<nsHtml5StackNode*, int32_t> newStack =
+ jArray<nsHtml5StackNode*, int32_t>::newJArray(stackNodes.length + 64);
+ nsHtml5ArrayCopy::arraycopy(stackNodes, newStack, stackNodes.length);
+ stackNodes = newStack;
+ stackNodes[stackNodesIdx] = new nsHtml5StackNode(stackNodesIdx);
+ numStackNodes++;
+ return stackNodes[stackNodesIdx++];
+}
+
+nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
+ int32_t flags, int32_t ns, nsAtom* name, nsIContentHandle* node,
+ nsAtom* popName, nsHtml5HtmlAttributes* attributes,
+ mozilla::dom::HTMLContentCreatorFunction htmlCreator) {
+ nsHtml5StackNode* instance = getUnusedStackNode();
+ instance->setValues(flags, ns, name, node, popName, attributes, htmlCreator);
+ return instance;
+}
+
+nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
+ nsHtml5ElementName* elementName, nsIContentHandle* node) {
+ nsHtml5StackNode* instance = getUnusedStackNode();
+ instance->setValues(elementName, node);
+ return instance;
+}
+
+nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
+ nsHtml5ElementName* elementName, nsIContentHandle* node,
+ nsHtml5HtmlAttributes* attributes) {
+ nsHtml5StackNode* instance = getUnusedStackNode();
+ instance->setValues(elementName, node, attributes);
+ return instance;
+}
+
+nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
+ nsHtml5ElementName* elementName, nsIContentHandle* node, nsAtom* popName) {
+ nsHtml5StackNode* instance = getUnusedStackNode();
+ instance->setValues(elementName, node, popName);
+ return instance;
+}
+
+nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
+ nsHtml5ElementName* elementName, nsAtom* popName, nsIContentHandle* node) {
+ nsHtml5StackNode* instance = getUnusedStackNode();
+ instance->setValues(elementName, popName, node);
+ return instance;
+}
+
+nsHtml5StackNode* nsHtml5TreeBuilder::createStackNode(
+ nsHtml5ElementName* elementName, nsIContentHandle* node, nsAtom* popName,
+ bool markAsIntegrationPoint) {
+ nsHtml5StackNode* instance = getUnusedStackNode();
+ instance->setValues(elementName, node, popName, markAsIntegrationPoint);
+ return instance;
+}
+
+void nsHtml5TreeBuilder::insertIntoFosterParent(nsIContentHandle* child) {
+ int32_t tablePos = findLastOrRoot(nsHtml5TreeBuilder::TABLE);
+ int32_t templatePos = findLastOrRoot(nsHtml5TreeBuilder::TEMPLATE);
+ if (templatePos >= tablePos) {
+ appendElement(child, stack[templatePos]->node);
+ return;
+ }
+ nsHtml5StackNode* node = stack[tablePos];
+ insertFosterParentedChild(child, node->node, stack[tablePos - 1]->node);
+}
+
+nsIContentHandle* nsHtml5TreeBuilder::createAndInsertFosterParentedElement(
+ int32_t ns, nsAtom* name, nsHtml5HtmlAttributes* attributes,
+ nsHtml5ContentCreatorFunction creator) {
+ return createAndInsertFosterParentedElement(ns, name, attributes, nullptr,
+ creator);
+}
+
+nsIContentHandle* nsHtml5TreeBuilder::createAndInsertFosterParentedElement(
+ int32_t ns, nsAtom* name, nsHtml5HtmlAttributes* attributes,
+ nsIContentHandle* form, nsHtml5ContentCreatorFunction creator) {
+ int32_t tablePos = findLastOrRoot(nsHtml5TreeBuilder::TABLE);
+ int32_t templatePos = findLastOrRoot(nsHtml5TreeBuilder::TEMPLATE);
+ if (templatePos >= tablePos) {
+ nsIContentHandle* child = createElement(ns, name, attributes, form,
+ stack[templatePos]->node, creator);
+ appendElement(child, stack[templatePos]->node);
+ return child;
+ }
+ nsHtml5StackNode* node = stack[tablePos];
+ return createAndInsertFosterParentedElement(
+ ns, name, attributes, form, node->node, stack[tablePos - 1]->node,
+ creator);
+}
+
+bool nsHtml5TreeBuilder::isInStack(nsHtml5StackNode* node) {
+ for (int32_t i = currentPtr; i >= 0; i--) {
+ if (stack[i] == node) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void nsHtml5TreeBuilder::popTemplateMode() { templateModePtr--; }
+
+void nsHtml5TreeBuilder::pop() {
+ nsHtml5StackNode* node = stack[currentPtr];
+ MOZ_ASSERT(debugOnlyClearLastStackSlot());
+ currentPtr--;
+ elementPopped(node->ns, node->popName, node->node);
+ node->release(this);
+}
+
+void nsHtml5TreeBuilder::popForeign(int32_t origPos, int32_t eltPos) {
+ nsHtml5StackNode* node = stack[currentPtr];
+ if (origPos != currentPtr || eltPos != currentPtr) {
+ markMalformedIfScript(node->node);
+ }
+ MOZ_ASSERT(debugOnlyClearLastStackSlot());
+ currentPtr--;
+ elementPopped(node->ns, node->popName, node->node);
+ node->release(this);
+}
+
+void nsHtml5TreeBuilder::silentPop() {
+ nsHtml5StackNode* node = stack[currentPtr];
+ MOZ_ASSERT(debugOnlyClearLastStackSlot());
+ currentPtr--;
+ node->release(this);
+}
+
+void nsHtml5TreeBuilder::popOnEof() {
+ nsHtml5StackNode* node = stack[currentPtr];
+ MOZ_ASSERT(debugOnlyClearLastStackSlot());
+ currentPtr--;
+ markMalformedIfScript(node->node);
+ elementPopped(node->ns, node->popName, node->node);
+ node->release(this);
+}
+
+void nsHtml5TreeBuilder::appendHtmlElementToDocumentAndPush(
+ nsHtml5HtmlAttributes* attributes) {
+ nsIContentHandle* elt = createHtmlElementSetAsRoot(attributes);
+ nsHtml5StackNode* node = createStackNode(nsHtml5ElementName::ELT_HTML, elt);
+ push(node);
+}
+
+void nsHtml5TreeBuilder::appendHtmlElementToDocumentAndPush() {
+ appendHtmlElementToDocumentAndPush(tokenizer->emptyAttributes());
+}
+
+void nsHtml5TreeBuilder::appendToCurrentNodeAndPushHeadElement(
+ nsHtml5HtmlAttributes* attributes) {
+ nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
+ nsIContentHandle* elt =
+ createElement(kNameSpaceID_XHTML, nsGkAtoms::head, attributes,
+ currentNode, htmlCreator(NS_NewHTMLSharedElement));
+ appendElement(elt, currentNode);
+ headPointer = elt;
+ nsHtml5StackNode* node = createStackNode(nsHtml5ElementName::ELT_HEAD, elt);
+ push(node);
+}
+
+void nsHtml5TreeBuilder::appendToCurrentNodeAndPushBodyElement(
+ nsHtml5HtmlAttributes* attributes) {
+ appendToCurrentNodeAndPushElement(nsHtml5ElementName::ELT_BODY, attributes);
+}
+
+void nsHtml5TreeBuilder::appendToCurrentNodeAndPushBodyElement() {
+ appendToCurrentNodeAndPushBodyElement(tokenizer->emptyAttributes());
+}
+
+void nsHtml5TreeBuilder::appendToCurrentNodeAndPushFormElementMayFoster(
+ nsHtml5HtmlAttributes* attributes) {
+ nsIContentHandle* elt;
+ nsHtml5StackNode* current = stack[currentPtr];
+ if (current->isFosterParenting()) {
+ elt = createAndInsertFosterParentedElement(
+ kNameSpaceID_XHTML, nsGkAtoms::form, attributes,
+ htmlCreator(NS_NewHTMLFormElement));
+ } else {
+ nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
+ elt = createElement(kNameSpaceID_XHTML, nsGkAtoms::form, attributes,
+ currentNode, htmlCreator(NS_NewHTMLFormElement));
+ appendElement(elt, currentNode);
+ }
+ if (!isTemplateContents()) {
+ formPointer = elt;
+ }
+ nsHtml5StackNode* node = createStackNode(nsHtml5ElementName::ELT_FORM, elt);
+ push(node);
+}
+
+void nsHtml5TreeBuilder::appendToCurrentNodeAndPushFormattingElementMayFoster(
+ nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
+ nsHtml5HtmlAttributes* clone = attributes->cloneAttributes();
+ nsIContentHandle* elt;
+ nsHtml5StackNode* current = stack[currentPtr];
+ if (current->isFosterParenting()) {
+ elt = createAndInsertFosterParentedElement(
+ kNameSpaceID_XHTML, elementName->getName(), attributes,
+ htmlCreator(elementName->getHtmlCreator()));
+ } else {
+ nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
+ elt =
+ createElement(kNameSpaceID_XHTML, elementName->getName(), attributes,
+ currentNode, htmlCreator(elementName->getHtmlCreator()));
+ appendElement(elt, currentNode);
+ }
+ nsHtml5StackNode* node = createStackNode(elementName, elt, clone);
+ push(node);
+ append(node);
+ node->retain();
+}
+
+void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElement(
+ nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
+ nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
+ nsIContentHandle* elt =
+ createElement(kNameSpaceID_XHTML, elementName->getName(), attributes,
+ currentNode, htmlCreator(elementName->getHtmlCreator()));
+ if (nsHtml5ElementName::ELT_TEMPLATE == elementName) {
+ nsIContentHandle* root =
+ getDeclarativeShadowRoot(currentNode, elt, attributes);
+ if (root) {
+ setDocumentFragmentForTemplate(elt, root);
+ elt = root;
+ } else {
+ appendElement(elt, currentNode);
+ elt = getDocumentFragmentForTemplate(elt);
+ }
+ } else {
+ appendElement(elt, currentNode);
+ }
+ nsHtml5StackNode* node = createStackNode(elementName, elt);
+ push(node);
+}
+
+void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFoster(
+ nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
+ nsAtom* popName = elementName->getName();
+ nsIContentHandle* elt;
+ nsHtml5StackNode* current = stack[currentPtr];
+ if (current->isFosterParenting()) {
+ elt = createAndInsertFosterParentedElement(
+ kNameSpaceID_XHTML, popName, attributes,
+ htmlCreator(elementName->getHtmlCreator()));
+ } else {
+ nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
+ elt = createElement(kNameSpaceID_XHTML, popName, attributes, currentNode,
+ htmlCreator(elementName->getHtmlCreator()));
+ appendElement(elt, currentNode);
+ }
+ nsHtml5StackNode* node = createStackNode(elementName, elt, popName);
+ push(node);
+}
+
+void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFosterMathML(
+ nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
+ nsAtom* popName = elementName->getName();
+ bool markAsHtmlIntegrationPoint = false;
+ if (nsHtml5ElementName::ELT_ANNOTATION_XML == elementName &&
+ annotationXmlEncodingPermitsHtml(attributes)) {
+ markAsHtmlIntegrationPoint = true;
+ }
+ nsIContentHandle* elt;
+ nsHtml5StackNode* current = stack[currentPtr];
+ if (current->isFosterParenting()) {
+ elt = createAndInsertFosterParentedElement(
+ kNameSpaceID_MathML, popName, attributes, htmlCreator(nullptr));
+ } else {
+ nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
+ elt = createElement(kNameSpaceID_MathML, popName, attributes, currentNode,
+ htmlCreator(nullptr));
+ appendElement(elt, currentNode);
+ }
+ nsHtml5StackNode* node =
+ createStackNode(elementName, elt, popName, markAsHtmlIntegrationPoint);
+ push(node);
+}
+
+bool nsHtml5TreeBuilder::annotationXmlEncodingPermitsHtml(
+ nsHtml5HtmlAttributes* attributes) {
+ nsHtml5String encoding =
+ attributes->getValue(nsHtml5AttributeName::ATTR_ENCODING);
+ if (!encoding) {
+ return false;
+ }
+ return nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
+ "application/xhtml+xml", encoding) ||
+ nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
+ "text/html", encoding);
+}
+
+void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFosterSVG(
+ nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
+ nsAtom* popName = elementName->getCamelCaseName();
+ nsIContentHandle* elt;
+ nsHtml5StackNode* current = stack[currentPtr];
+ if (current->isFosterParenting()) {
+ elt = createAndInsertFosterParentedElement(
+ kNameSpaceID_SVG, popName, attributes,
+ svgCreator(elementName->getSvgCreator()));
+ } else {
+ nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
+ elt = createElement(kNameSpaceID_SVG, popName, attributes, currentNode,
+ svgCreator(elementName->getSvgCreator()));
+ appendElement(elt, currentNode);
+ }
+ nsHtml5StackNode* node = createStackNode(elementName, popName, elt);
+ push(node);
+}
+
+void nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFoster(
+ nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes,
+ nsIContentHandle* form) {
+ nsIContentHandle* elt;
+ nsIContentHandle* formOwner =
+ !form || fragment || isTemplateContents() ? nullptr : form;
+ nsHtml5StackNode* current = stack[currentPtr];
+ if (current->isFosterParenting()) {
+ elt = createAndInsertFosterParentedElement(
+ kNameSpaceID_XHTML, elementName->getName(), attributes, formOwner,
+ htmlCreator(elementName->getHtmlCreator()));
+ } else {
+ nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
+ elt = createElement(kNameSpaceID_XHTML, elementName->getName(), attributes,
+ formOwner, currentNode,
+ htmlCreator(elementName->getHtmlCreator()));
+ appendElement(elt, currentNode);
+ }
+ nsHtml5StackNode* node = createStackNode(elementName, elt);
+ push(node);
+}
+
+void nsHtml5TreeBuilder::appendVoidElementToCurrent(
+ nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
+ nsAtom* popName = elementName->getName();
+ nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
+ nsIContentHandle* elt =
+ createElement(kNameSpaceID_XHTML, popName, attributes, currentNode,
+ htmlCreator(elementName->getHtmlCreator()));
+ appendElement(elt, currentNode);
+ elementPushed(kNameSpaceID_XHTML, popName, elt);
+ elementPopped(kNameSpaceID_XHTML, popName, elt);
+}
+
+void nsHtml5TreeBuilder::appendVoidElementToCurrentMayFoster(
+ nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes,
+ nsIContentHandle* form) {
+ nsAtom* name = elementName->getName();
+ nsIContentHandle* elt;
+ nsIContentHandle* formOwner =
+ !form || fragment || isTemplateContents() ? nullptr : form;
+ nsHtml5StackNode* current = stack[currentPtr];
+ if (current->isFosterParenting()) {
+ elt = createAndInsertFosterParentedElement(
+ kNameSpaceID_XHTML, name, attributes, formOwner,
+ htmlCreator(elementName->getHtmlCreator()));
+ } else {
+ nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
+ elt =
+ createElement(kNameSpaceID_XHTML, name, attributes, formOwner,
+ currentNode, htmlCreator(elementName->getHtmlCreator()));
+ appendElement(elt, currentNode);
+ }
+ elementPushed(kNameSpaceID_XHTML, name, elt);
+ elementPopped(kNameSpaceID_XHTML, name, elt);
+}
+
+void nsHtml5TreeBuilder::appendVoidElementToCurrentMayFoster(
+ nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
+ nsAtom* popName = elementName->getName();
+ nsIContentHandle* elt;
+ nsHtml5StackNode* current = stack[currentPtr];
+ if (current->isFosterParenting()) {
+ elt = createAndInsertFosterParentedElement(
+ kNameSpaceID_XHTML, popName, attributes,
+ htmlCreator(elementName->getHtmlCreator()));
+ } else {
+ nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
+ elt = createElement(kNameSpaceID_XHTML, popName, attributes, currentNode,
+ htmlCreator(elementName->getHtmlCreator()));
+ appendElement(elt, currentNode);
+ }
+ elementPushed(kNameSpaceID_XHTML, popName, elt);
+ elementPopped(kNameSpaceID_XHTML, popName, elt);
+}
+
+void nsHtml5TreeBuilder::appendVoidElementToCurrentMayFosterSVG(
+ nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
+ nsAtom* popName = elementName->getCamelCaseName();
+ nsIContentHandle* elt;
+ nsHtml5StackNode* current = stack[currentPtr];
+ if (current->isFosterParenting()) {
+ elt = createAndInsertFosterParentedElement(
+ kNameSpaceID_SVG, popName, attributes,
+ svgCreator(elementName->getSvgCreator()));
+ } else {
+ nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
+ elt = createElement(kNameSpaceID_SVG, popName, attributes, currentNode,
+ svgCreator(elementName->getSvgCreator()));
+ appendElement(elt, currentNode);
+ }
+ elementPushed(kNameSpaceID_SVG, popName, elt);
+ elementPopped(kNameSpaceID_SVG, popName, elt);
+}
+
+void nsHtml5TreeBuilder::appendVoidElementToCurrentMayFosterMathML(
+ nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) {
+ nsAtom* popName = elementName->getName();
+ nsIContentHandle* elt;
+ nsHtml5StackNode* current = stack[currentPtr];
+ if (current->isFosterParenting()) {
+ elt = createAndInsertFosterParentedElement(
+ kNameSpaceID_MathML, popName, attributes, htmlCreator(nullptr));
+ } else {
+ nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
+ elt = createElement(kNameSpaceID_MathML, popName, attributes, currentNode,
+ htmlCreator(nullptr));
+ appendElement(elt, currentNode);
+ }
+ elementPushed(kNameSpaceID_MathML, popName, elt);
+ elementPopped(kNameSpaceID_MathML, popName, elt);
+}
+
+void nsHtml5TreeBuilder::appendVoidInputToCurrent(
+ nsHtml5HtmlAttributes* attributes, nsIContentHandle* form) {
+ nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
+ nsIContentHandle* elt =
+ createElement(kNameSpaceID_XHTML, nsGkAtoms::input, attributes,
+ !form || fragment || isTemplateContents() ? nullptr : form,
+ currentNode, htmlCreator(NS_NewHTMLInputElement));
+ appendElement(elt, currentNode);
+ elementPushed(kNameSpaceID_XHTML, nsGkAtoms::input, elt);
+ elementPopped(kNameSpaceID_XHTML, nsGkAtoms::input, elt);
+}
+
+void nsHtml5TreeBuilder::appendVoidFormToCurrent(
+ nsHtml5HtmlAttributes* attributes) {
+ nsIContentHandle* currentNode = nodeFromStackWithBlinkCompat(currentPtr);
+ nsIContentHandle* elt =
+ createElement(kNameSpaceID_XHTML, nsGkAtoms::form, attributes,
+ currentNode, htmlCreator(NS_NewHTMLFormElement));
+ formPointer = elt;
+ appendElement(elt, currentNode);
+ elementPushed(kNameSpaceID_XHTML, nsGkAtoms::form, elt);
+ elementPopped(kNameSpaceID_XHTML, nsGkAtoms::form, elt);
+}
+
+void nsHtml5TreeBuilder::requestSuspension() {
+ tokenizer->requestSuspension();
+}
+
+;
+bool nsHtml5TreeBuilder::isInForeign() {
+ return currentPtr >= 0 && stack[currentPtr]->ns != kNameSpaceID_XHTML;
+}
+
+bool nsHtml5TreeBuilder::isInForeignButNotHtmlOrMathTextIntegrationPoint() {
+ if (currentPtr < 0) {
+ return false;
+ }
+ return !isSpecialParentInForeign(stack[currentPtr]);
+}
+
+void nsHtml5TreeBuilder::setFragmentContext(nsAtom* context, int32_t ns,
+ nsIContentHandle* node,
+ bool quirks) {
+ this->contextName = context;
+ this->contextNamespace = ns;
+ this->contextNode = node;
+ this->fragment = (!!contextName);
+ this->quirks = quirks;
+}
+
+nsIContentHandle* nsHtml5TreeBuilder::currentNode() {
+ return stack[currentPtr]->node;
+}
+
+bool nsHtml5TreeBuilder::isScriptingEnabled() { return scriptingEnabled; }
+
+void nsHtml5TreeBuilder::setScriptingEnabled(bool scriptingEnabled) {
+ this->scriptingEnabled = scriptingEnabled;
+}
+
+void nsHtml5TreeBuilder::setForceNoQuirks(bool forceNoQuirks) {
+ this->forceNoQuirks = forceNoQuirks;
+}
+
+void nsHtml5TreeBuilder::setIsSrcdocDocument(bool isSrcdocDocument) {
+ this->setForceNoQuirks(isSrcdocDocument);
+}
+
+bool nsHtml5TreeBuilder::isAllowDeclarativeShadowRoots() {
+ return allowDeclarativeShadowRoots;
+}
+
+void nsHtml5TreeBuilder::setAllowDeclarativeShadowRoots(bool allow) {
+ allowDeclarativeShadowRoots = allow;
+}
+
+void nsHtml5TreeBuilder::flushCharacters() {
+ if (charBufferLen > 0) {
+ if ((mode == IN_TABLE || mode == IN_TABLE_BODY || mode == IN_ROW) &&
+ charBufferContainsNonWhitespace()) {
+ errNonSpaceInTable();
+ reconstructTheActiveFormattingElements();
+ if (!stack[currentPtr]->isFosterParenting()) {
+ appendCharacters(currentNode(), charBuffer, 0, charBufferLen);
+ charBufferLen = 0;
+ return;
+ }
+ int32_t tablePos = findLastOrRoot(nsHtml5TreeBuilder::TABLE);
+ int32_t templatePos = findLastOrRoot(nsHtml5TreeBuilder::TEMPLATE);
+ if (templatePos >= tablePos) {
+ appendCharacters(stack[templatePos]->node, charBuffer, 0,
+ charBufferLen);
+ charBufferLen = 0;
+ return;
+ }
+ nsHtml5StackNode* tableElt = stack[tablePos];
+ insertFosterParentedCharacters(charBuffer, 0, charBufferLen,
+ tableElt->node, stack[tablePos - 1]->node);
+ charBufferLen = 0;
+ return;
+ }
+ appendCharacters(currentNode(), charBuffer, 0, charBufferLen);
+ charBufferLen = 0;
+ }
+}
+
+bool nsHtml5TreeBuilder::charBufferContainsNonWhitespace() {
+ for (int32_t i = 0; i < charBufferLen; i++) {
+ switch (charBuffer[i]) {
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ case '\f': {
+ continue;
+ }
+ default: {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+nsAHtml5TreeBuilderState* nsHtml5TreeBuilder::newSnapshot() {
+ jArray<nsHtml5StackNode*, int32_t> listCopy =
+ jArray<nsHtml5StackNode*, int32_t>::newJArray(listPtr + 1);
+ for (int32_t i = 0; i < listCopy.length; i++) {
+ nsHtml5StackNode* node = listOfActiveFormattingElements[i];
+ if (node) {
+ nsHtml5StackNode* newNode = new nsHtml5StackNode(-1);
+ newNode->setValues(node->getFlags(), node->ns, node->name, node->node,
+ node->popName, node->attributes->cloneAttributes(),
+ node->getHtmlCreator());
+ listCopy[i] = newNode;
+ } else {
+ listCopy[i] = nullptr;
+ }
+ }
+ jArray<nsHtml5StackNode*, int32_t> stackCopy =
+ jArray<nsHtml5StackNode*, int32_t>::newJArray(currentPtr + 1);
+ for (int32_t i = 0; i < stackCopy.length; i++) {
+ nsHtml5StackNode* node = stack[i];
+ int32_t listIndex = findInListOfActiveFormattingElements(node);
+ if (listIndex == -1) {
+ nsHtml5StackNode* newNode = new nsHtml5StackNode(-1);
+ newNode->setValues(node->getFlags(), node->ns, node->name, node->node,
+ node->popName, nullptr, node->getHtmlCreator());
+ stackCopy[i] = newNode;
+ } else {
+ stackCopy[i] = listCopy[listIndex];
+ stackCopy[i]->retain();
+ }
+ }
+ jArray<int32_t, int32_t> templateModeStackCopy =
+ jArray<int32_t, int32_t>::newJArray(templateModePtr + 1);
+ nsHtml5ArrayCopy::arraycopy(templateModeStack, templateModeStackCopy,
+ templateModeStackCopy.length);
+ return new nsHtml5StateSnapshot(stackCopy, listCopy, templateModeStackCopy,
+ formPointer, headPointer, mode, originalMode,
+ framesetOk, needToDropLF, quirks);
+}
+
+bool nsHtml5TreeBuilder::snapshotMatches(nsAHtml5TreeBuilderState* snapshot) {
+ jArray<nsHtml5StackNode*, int32_t> stackCopy = snapshot->getStack();
+ int32_t stackLen = snapshot->getStackLength();
+ jArray<nsHtml5StackNode*, int32_t> listCopy =
+ snapshot->getListOfActiveFormattingElements();
+ int32_t listLen = snapshot->getListOfActiveFormattingElementsLength();
+ jArray<int32_t, int32_t> templateModeStackCopy =
+ snapshot->getTemplateModeStack();
+ int32_t templateModeStackLen = snapshot->getTemplateModeStackLength();
+ if (stackLen != currentPtr + 1 || listLen != listPtr + 1 ||
+ templateModeStackLen != templateModePtr + 1 ||
+ formPointer != snapshot->getFormPointer() ||
+ headPointer != snapshot->getHeadPointer() ||
+ mode != snapshot->getMode() ||
+ originalMode != snapshot->getOriginalMode() ||
+ framesetOk != snapshot->isFramesetOk() ||
+ needToDropLF != snapshot->isNeedToDropLF() ||
+ quirks != snapshot->isQuirks()) {
+ return false;
+ }
+ for (int32_t i = listLen - 1; i >= 0; i--) {
+ if (!listCopy[i] && !listOfActiveFormattingElements[i]) {
+ continue;
+ } else if (!listCopy[i] || !listOfActiveFormattingElements[i]) {
+ return false;
+ }
+ if (listCopy[i]->node != listOfActiveFormattingElements[i]->node) {
+ return false;
+ }
+ }
+ for (int32_t i = stackLen - 1; i >= 0; i--) {
+ if (stackCopy[i]->node != stack[i]->node) {
+ return false;
+ }
+ }
+ for (int32_t i = templateModeStackLen - 1; i >= 0; i--) {
+ if (templateModeStackCopy[i] != templateModeStack[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void nsHtml5TreeBuilder::loadState(nsAHtml5TreeBuilderState* snapshot) {
+ mCurrentHtmlScriptCannotDocumentWriteOrBlock = false;
+ jArray<nsHtml5StackNode*, int32_t> stackCopy = snapshot->getStack();
+ int32_t stackLen = snapshot->getStackLength();
+ jArray<nsHtml5StackNode*, int32_t> listCopy =
+ snapshot->getListOfActiveFormattingElements();
+ int32_t listLen = snapshot->getListOfActiveFormattingElementsLength();
+ jArray<int32_t, int32_t> templateModeStackCopy =
+ snapshot->getTemplateModeStack();
+ int32_t templateModeStackLen = snapshot->getTemplateModeStackLength();
+ for (int32_t i = 0; i <= listPtr; i++) {
+ if (listOfActiveFormattingElements[i]) {
+ listOfActiveFormattingElements[i]->release(this);
+ }
+ }
+ if (listOfActiveFormattingElements.length < listLen) {
+ listOfActiveFormattingElements =
+ jArray<nsHtml5StackNode*, int32_t>::newJArray(listLen);
+ }
+ listPtr = listLen - 1;
+ for (int32_t i = 0; i <= currentPtr; i++) {
+ stack[i]->release(this);
+ }
+ if (stack.length < stackLen) {
+ stack = jArray<nsHtml5StackNode*, int32_t>::newJArray(stackLen);
+ }
+ currentPtr = stackLen - 1;
+ if (templateModeStack.length < templateModeStackLen) {
+ templateModeStack =
+ jArray<int32_t, int32_t>::newJArray(templateModeStackLen);
+ }
+ templateModePtr = templateModeStackLen - 1;
+ for (int32_t i = 0; i < listLen; i++) {
+ nsHtml5StackNode* node = listCopy[i];
+ if (node) {
+ nsHtml5StackNode* newNode = createStackNode(
+ node->getFlags(), node->ns, node->name, node->node, node->popName,
+ node->attributes->cloneAttributes(), node->getHtmlCreator());
+ listOfActiveFormattingElements[i] = newNode;
+ } else {
+ listOfActiveFormattingElements[i] = nullptr;
+ }
+ }
+ for (int32_t i = 0; i < stackLen; i++) {
+ nsHtml5StackNode* node = stackCopy[i];
+ int32_t listIndex = findInArray(node, listCopy);
+ if (listIndex == -1) {
+ nsHtml5StackNode* newNode =
+ createStackNode(node->getFlags(), node->ns, node->name, node->node,
+ node->popName, nullptr, node->getHtmlCreator());
+ stack[i] = newNode;
+ } else {
+ stack[i] = listOfActiveFormattingElements[listIndex];
+ stack[i]->retain();
+ }
+ }
+ nsHtml5ArrayCopy::arraycopy(templateModeStackCopy, templateModeStack,
+ templateModeStackLen);
+ formPointer = snapshot->getFormPointer();
+ headPointer = snapshot->getHeadPointer();
+ mode = snapshot->getMode();
+ originalMode = snapshot->getOriginalMode();
+ framesetOk = snapshot->isFramesetOk();
+ needToDropLF = snapshot->isNeedToDropLF();
+ quirks = snapshot->isQuirks();
+}
+
+int32_t nsHtml5TreeBuilder::findInArray(
+ nsHtml5StackNode* node, jArray<nsHtml5StackNode*, int32_t> arr) {
+ for (int32_t i = listPtr; i >= 0; i--) {
+ if (node == arr[i]) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+nsIContentHandle* nsHtml5TreeBuilder::nodeFromStackWithBlinkCompat(
+ int32_t stackPos) {
+ if (stackPos > 511) {
+ errDeepTree();
+ return stack[511]->node;
+ }
+ return stack[stackPos]->node;
+}
+
+nsIContentHandle* nsHtml5TreeBuilder::getFormPointer() { return formPointer; }
+
+nsIContentHandle* nsHtml5TreeBuilder::getHeadPointer() { return headPointer; }
+
+jArray<nsHtml5StackNode*, int32_t>
+nsHtml5TreeBuilder::getListOfActiveFormattingElements() {
+ return listOfActiveFormattingElements;
+}
+
+jArray<nsHtml5StackNode*, int32_t> nsHtml5TreeBuilder::getStack() {
+ return stack;
+}
+
+jArray<int32_t, int32_t> nsHtml5TreeBuilder::getTemplateModeStack() {
+ return templateModeStack;
+}
+
+int32_t nsHtml5TreeBuilder::getMode() { return mode; }
+
+int32_t nsHtml5TreeBuilder::getOriginalMode() { return originalMode; }
+
+bool nsHtml5TreeBuilder::isFramesetOk() { return framesetOk; }
+
+bool nsHtml5TreeBuilder::isNeedToDropLF() { return needToDropLF; }
+
+bool nsHtml5TreeBuilder::isQuirks() { return quirks; }
+
+int32_t nsHtml5TreeBuilder::getListOfActiveFormattingElementsLength() {
+ return listPtr + 1;
+}
+
+int32_t nsHtml5TreeBuilder::getStackLength() { return currentPtr + 1; }
+
+int32_t nsHtml5TreeBuilder::getTemplateModeStackLength() {
+ return templateModePtr + 1;
+}
+
+void nsHtml5TreeBuilder::initializeStatics() {}
+
+void nsHtml5TreeBuilder::releaseStatics() {}
+
+#include "nsHtml5TreeBuilderCppSupplement.h"