gecko-dev/parser/html/nsHtml5TreeBuilder.cpp
Gabriele Svelto 5dc21d568c Bug 1600545 - Remove useless inclusions of header files generated from IDL files in modules/, netwerk/, parser/, security/, startupcache/, storage/, toolkit/, tools/, uriloader/, widget/, xpcom/ and xpfe/ r=Ehsan
The inclusions were removed with the following very crude script and the
resulting breakage was fixed up by hand. The manual fixups did either
revert the changes done by the script, replace a generic header with a more
specific one or replace a header with a forward declaration.

find . -name "*.idl" | grep -v web-platform | grep -v third_party | while read path; do
    interfaces=$(grep "^\(class\|interface\).*:.*" "$path" | cut -d' ' -f2)
    if [ -n "$interfaces" ]; then
        if [[ "$interfaces" == *$'\n'* ]]; then
          regexp="\("
          for i in $interfaces; do regexp="$regexp$i\|"; done
          regexp="${regexp%%\\\|}\)"
        else
          regexp="$interfaces"
        fi
        interface=$(basename "$path")
        rg -l "#include.*${interface%%.idl}.h" . | while read path2; do
            hits=$(grep -v "#include.*${interface%%.idl}.h" "$path2" | grep -c "$regexp" )
            if [ $hits -eq 0 ]; then
                echo "Removing ${interface} from ${path2}"
                grep -v "#include.*${interface%%.idl}.h" "$path2" > "$path2".tmp
                mv -f "$path2".tmp "$path2"
            fi
        done
    fi
done

Differential Revision: https://phabricator.services.mozilla.com/D55444

--HG--
extra : moz-landing-system : lando
2019-12-06 09:17:57 +00:00

4717 lines
153 KiB
C++

/*
* Copyright (c) 2007 Henri Sivonen
* Copyright (c) 2007-2015 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 "nsContentUtils.h"
#include "nsAtom.h"
#include "nsHtml5AtomTable.h"
#include "nsHtml5String.h"
#include "nsNameSpaceManager.h"
#include "nsIContent.h"
#include "nsTraceRefcnt.h"
#include "jArray.h"
#include "nsHtml5DocumentMode.h"
#include "nsHtml5ArrayCopy.h"
#include "nsHtml5Parser.h"
#include "nsGkAtoms.h"
#include "nsHtml5TreeOperation.h"
#include "nsHtml5StateSnapshot.h"
#include "nsHtml5StackNode.h"
#include "nsHtml5TreeOpExecutor.h"
#include "nsHtml5StreamParser.h"
#include "nsAHtml5TreeBuilderState.h"
#include "nsHtml5Highlighter.h"
#include "nsHtml5PlainTextUtils.h"
#include "nsHtml5ViewSourceUtils.h"
#include "mozilla/ImportScanner.h"
#include "mozilla/Likely.h"
#include "nsIContentHandle.h"
#include "nsHtml5OplessBuilder.h"
#include "nsHtml5AttributeName.h"
#include "nsHtml5ElementName.h"
#include "nsHtml5Tokenizer.h"
#include "nsHtml5MetaScanner.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);
}
}
contextName = nullptr;
contextNode = nullptr;
} 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,
false);
} else if (isAlmostStandards(publicIdentifier, systemIdentifier)) {
errAlmostStandardsDoctype();
documentModeInternal(ALMOST_STANDARDS_MODE, publicIdentifier,
systemIdentifier, false);
} else {
documentModeInternal(STANDARDS_MODE, publicIdentifier, systemIdentifier,
false);
}
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();
}
MOZ_FALLTHROUGH;
}
case TEXT: {
accumulateCharacters(buf, start, length);
return;
}
case IN_TABLE:
case IN_TABLE_BODY:
case IN_ROW: {
accumulateCharactersForced(buf, start, length);
return;
}
default: {
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, false);
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::eof() {
flushCharacters();
for (;;) {
switch (mode) {
case INITIAL: {
documentModeInternal(QUIRKS_MODE, nullptr, nullptr, false);
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);
}
MOZ_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)) {
errUnclosedElements(eltPos, nsGkAtoms::_template);
}
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;
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);
}
}
MOZ_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
}
MOZ_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
}
MOZ_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:;
MOZ_FALLTHROUGH;
}
case IN_CAPTION: {
switch (group) {
case CAPTION:
case COL:
case COLGROUP:
case TBODY_OR_THEAD_OR_TFOOT:
case TR:
case TD_OR_TH: {
errStrayStartTag(name);
eltPos = findLastInTableScope(nsGkAtoms::caption);
if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
NS_HTML5_BREAK(starttagloop);
}
generateImpliedEndTags();
if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) {
errNoCheckUnclosedElementsOnStack();
}
while (currentPtr >= eltPos) {
pop();
}
clearTheListOfActiveFormattingElementsUpToTheLastMarker();
mode = IN_TABLE;
continue;
}
default:; // fall through
}
MOZ_FALLTHROUGH;
}
case IN_CELL: {
switch (group) {
case CAPTION:
case COL:
case COLGROUP:
case TBODY_OR_THEAD_OR_TFOOT:
case TR:
case TD_OR_TH: {
eltPos = findLastInTableScopeTdTh();
if (eltPos == nsHtml5TreeBuilder::NOT_FOUND_ON_STACK) {
errNoCellToClose();
NS_HTML5_BREAK(starttagloop);
} else {
closeTheCell(eltPos);
continue;
}
}
default:; // fall through
}
MOZ_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;
}
MOZ_FALLTHROUGH;
}
default:; // fall through
}
MOZ_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_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();
MOZ_FALLTHROUGH;
}
#ifdef ENABLE_VOID_MENUITEM
case MENUITEM:
#endif
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);
}
MOZ_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:;
MOZ_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:;
MOZ_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: {
errBadStartTagInHead(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
}
MOZ_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);
}
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
}
MOZ_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, false);
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));
}
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);
}
}
MOZ_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
}
MOZ_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
}
MOZ_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);
}
}
MOZ_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: {
errTableClosedWhileCaptionOpen();
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;
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
}
MOZ_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
}
MOZ_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_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:
#ifdef ENABLE_VOID_MENUITEM
case MENUITEM:
#endif
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);
}
MOZ_FALLTHROUGH;
}
case A:
case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U:
case FONT:
case NOBR: {
if (adoptionAgencyEndTag(name)) {
NS_HTML5_BREAK(endtagloop);
}
MOZ_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--;
}
}
}
MOZ_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
}
MOZ_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, false);
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;
}
generateImpliedEndTags();
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]->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;
}
}
}
}
bool nsHtml5TreeBuilder::isSecondOnStackBody() {
return currentPtr >= 1 && stack[1]->getGroup() == nsHtml5TreeBuilder::BODY;
}
void nsHtml5TreeBuilder::documentModeInternal(
nsHtml5DocumentMode m, nsHtml5String publicIdentifier,
nsHtml5String systemIdentifier, bool html4SpecificAdditionalErrorChecks) {
if (isSrcdocDocument) {
quirks = false;
this->documentMode(STANDARDS_MODE);
return;
}
quirks = (m == QUIRKS_MODE);
this->documentMode(m);
}
bool nsHtml5TreeBuilder::isAlmostStandards(nsHtml5String publicIdentifier,
nsHtml5String systemIdentifier) {
if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
"-//w3c//dtd xhtml 1.0 transitional//en", publicIdentifier)) {
return true;
}
if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
"-//w3c//dtd xhtml 1.0 frameset//en", publicIdentifier)) {
return true;
}
if (systemIdentifier) {
if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
"-//w3c//dtd html 4.01 transitional//en", publicIdentifier)) {
return true;
}
if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
"-//w3c//dtd html 4.01 frameset//en", 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::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
"-//w3c//dtd html 4.01 transitional//en", publicIdentifier)) {
return true;
} else if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
"-//w3c//dtd html 4.01 frameset//en", 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]->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()));
appendElement(elt, currentNode);
if (nsHtml5ElementName::ELT_TEMPLATE == elementName) {
elt = getDocumentFragmentForTemplate(elt);
}
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::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::setIsSrcdocDocument(bool isSrcdocDocument) {
this->isSrcdocDocument = isSrcdocDocument;
}
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) {
mCurrentHtmlScriptIsAsyncOrDefer = 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"