michael@0: /* michael@0: * Copyright (c) 2007 Henri Sivonen michael@0: * Copyright (c) 2007-2011 Mozilla Foundation michael@0: * Portions of comments Copyright 2004-2008 Apple Computer, Inc., Mozilla michael@0: * Foundation, and Opera Software ASA. michael@0: * michael@0: * Permission is hereby granted, free of charge, to any person obtaining a michael@0: * copy of this software and associated documentation files (the "Software"), michael@0: * to deal in the Software without restriction, including without limitation michael@0: * the rights to use, copy, modify, merge, publish, distribute, sublicense, michael@0: * and/or sell copies of the Software, and to permit persons to whom the michael@0: * Software is furnished to do so, subject to the following conditions: michael@0: * michael@0: * The above copyright notice and this permission notice shall be included in michael@0: * all copies or substantial portions of the Software. michael@0: * michael@0: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR michael@0: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, michael@0: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL michael@0: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER michael@0: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING michael@0: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER michael@0: * DEALINGS IN THE SOFTWARE. michael@0: */ michael@0: michael@0: /* michael@0: * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT. michael@0: * Please edit TreeBuilder.java instead and regenerate. michael@0: */ michael@0: michael@0: #define nsHtml5TreeBuilder_cpp__ michael@0: michael@0: #include "nsContentUtils.h" michael@0: #include "nsIAtom.h" michael@0: #include "nsHtml5AtomTable.h" michael@0: #include "nsITimer.h" michael@0: #include "nsString.h" michael@0: #include "nsNameSpaceManager.h" michael@0: #include "nsIContent.h" michael@0: #include "nsTraceRefcnt.h" michael@0: #include "jArray.h" michael@0: #include "nsHtml5DocumentMode.h" michael@0: #include "nsHtml5ArrayCopy.h" michael@0: #include "nsHtml5Parser.h" michael@0: #include "nsHtml5Atoms.h" michael@0: #include "nsHtml5TreeOperation.h" michael@0: #include "nsHtml5PendingNotification.h" michael@0: #include "nsHtml5StateSnapshot.h" michael@0: #include "nsHtml5StackNode.h" michael@0: #include "nsHtml5TreeOpExecutor.h" michael@0: #include "nsHtml5StreamParser.h" michael@0: #include "nsAHtml5TreeBuilderState.h" michael@0: #include "nsHtml5Highlighter.h" michael@0: #include "nsHtml5PlainTextUtils.h" michael@0: #include "nsHtml5ViewSourceUtils.h" michael@0: #include "mozilla/Likely.h" michael@0: #include "nsIContentHandle.h" michael@0: #include "nsHtml5OplessBuilder.h" michael@0: michael@0: #include "nsHtml5Tokenizer.h" michael@0: #include "nsHtml5MetaScanner.h" michael@0: #include "nsHtml5AttributeName.h" michael@0: #include "nsHtml5ElementName.h" michael@0: #include "nsHtml5HtmlAttributes.h" michael@0: #include "nsHtml5StackNode.h" michael@0: #include "nsHtml5UTF16Buffer.h" michael@0: #include "nsHtml5StateSnapshot.h" michael@0: #include "nsHtml5Portability.h" michael@0: michael@0: #include "nsHtml5TreeBuilder.h" michael@0: michael@0: char16_t nsHtml5TreeBuilder::REPLACEMENT_CHARACTER[] = { 0xfffd }; michael@0: 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//" }; michael@0: staticJArray nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS = { QUIRKY_PUBLIC_IDS_DATA, MOZ_ARRAY_LENGTH(QUIRKY_PUBLIC_IDS_DATA) }; michael@0: void michael@0: nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self) michael@0: { michael@0: tokenizer = self; michael@0: stack = jArray::newJArray(64); michael@0: templateModeStack = jArray::newJArray(64); michael@0: listOfActiveFormattingElements = jArray::newJArray(64); michael@0: needToDropLF = false; michael@0: originalMode = NS_HTML5TREE_BUILDER_INITIAL; michael@0: templateModePtr = -1; michael@0: currentPtr = -1; michael@0: listPtr = -1; michael@0: formPointer = nullptr; michael@0: headPointer = nullptr; michael@0: deepTreeSurrogateParent = nullptr; michael@0: start(fragment); michael@0: charBufferLen = 0; michael@0: charBuffer = jArray::newJArray(1024); michael@0: framesetOk = true; michael@0: if (fragment) { michael@0: nsIContentHandle* elt; michael@0: if (contextNode) { michael@0: elt = contextNode; michael@0: } else { michael@0: elt = createHtmlElementSetAsRoot(tokenizer->emptyAttributes()); michael@0: } michael@0: nsHtml5StackNode* node = new nsHtml5StackNode(nsHtml5ElementName::ELT_HTML, elt); michael@0: currentPtr++; michael@0: stack[currentPtr] = node; michael@0: if (nsHtml5Atoms::template_ == contextName) { michael@0: pushTemplateMode(NS_HTML5TREE_BUILDER_IN_TEMPLATE); michael@0: } michael@0: resetTheInsertionMode(); michael@0: formPointer = getFormPointerForContext(contextNode); michael@0: if (nsHtml5Atoms::title == contextName || nsHtml5Atoms::textarea == contextName) { michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RCDATA, contextName); michael@0: } else if (nsHtml5Atoms::style == contextName || nsHtml5Atoms::xmp == contextName || nsHtml5Atoms::iframe == contextName || nsHtml5Atoms::noembed == contextName || nsHtml5Atoms::noframes == contextName || (scriptingEnabled && nsHtml5Atoms::noscript == contextName)) { michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RAWTEXT, contextName); michael@0: } else if (nsHtml5Atoms::plaintext == contextName) { michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_PLAINTEXT, contextName); michael@0: } else if (nsHtml5Atoms::script == contextName) { michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_SCRIPT_DATA, contextName); michael@0: } else { michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_DATA, contextName); michael@0: } michael@0: contextName = nullptr; michael@0: contextNode = nullptr; michael@0: } else { michael@0: mode = NS_HTML5TREE_BUILDER_INITIAL; michael@0: if (tokenizer->isViewingXmlSource()) { michael@0: nsIContentHandle* elt = createElement(kNameSpaceID_SVG, nsHtml5Atoms::svg, tokenizer->emptyAttributes()); michael@0: nsHtml5StackNode* node = new nsHtml5StackNode(nsHtml5ElementName::ELT_SVG, nsHtml5Atoms::svg, elt); michael@0: currentPtr++; michael@0: stack[currentPtr] = node; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::doctype(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier, bool forceQuirks) michael@0: { michael@0: needToDropLF = false; michael@0: if (!isInForeign() && mode == NS_HTML5TREE_BUILDER_INITIAL) { michael@0: nsString* emptyString = nsHtml5Portability::newEmptyString(); michael@0: appendDoctypeToDocument(!name ? nsHtml5Atoms::emptystring : name, !publicIdentifier ? emptyString : publicIdentifier, !systemIdentifier ? emptyString : systemIdentifier); michael@0: nsHtml5Portability::releaseString(emptyString); michael@0: if (isQuirky(name, publicIdentifier, systemIdentifier, forceQuirks)) { michael@0: errQuirkyDoctype(); michael@0: documentModeInternal(QUIRKS_MODE, publicIdentifier, systemIdentifier, false); michael@0: } else if (isAlmostStandards(publicIdentifier, systemIdentifier)) { michael@0: errAlmostStandardsDoctype(); michael@0: documentModeInternal(ALMOST_STANDARDS_MODE, publicIdentifier, systemIdentifier, false); michael@0: } else { michael@0: documentModeInternal(STANDARDS_MODE, publicIdentifier, systemIdentifier, false); michael@0: } michael@0: mode = NS_HTML5TREE_BUILDER_BEFORE_HTML; michael@0: return; michael@0: } michael@0: errStrayDoctype(); michael@0: return; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::comment(char16_t* buf, int32_t start, int32_t length) michael@0: { michael@0: needToDropLF = false; michael@0: if (!isInForeign()) { michael@0: switch(mode) { michael@0: case NS_HTML5TREE_BUILDER_INITIAL: michael@0: case NS_HTML5TREE_BUILDER_BEFORE_HTML: michael@0: case NS_HTML5TREE_BUILDER_AFTER_AFTER_BODY: michael@0: case NS_HTML5TREE_BUILDER_AFTER_AFTER_FRAMESET: { michael@0: appendCommentToDocument(buf, start, length); michael@0: return; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_BODY: { michael@0: flushCharacters(); michael@0: appendComment(stack[0]->node, buf, start, length); michael@0: return; michael@0: } michael@0: default: { michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: flushCharacters(); michael@0: appendComment(stack[currentPtr]->node, buf, start, length); michael@0: return; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::characters(const char16_t* buf, int32_t start, int32_t length) michael@0: { michael@0: if (tokenizer->isViewingXmlSource()) { michael@0: return; michael@0: } michael@0: if (needToDropLF) { michael@0: needToDropLF = false; michael@0: if (buf[start] == '\n') { michael@0: start++; michael@0: length--; michael@0: if (!length) { michael@0: return; michael@0: } michael@0: } michael@0: } michael@0: switch(mode) { michael@0: case NS_HTML5TREE_BUILDER_IN_BODY: michael@0: case NS_HTML5TREE_BUILDER_IN_CELL: michael@0: case NS_HTML5TREE_BUILDER_IN_CAPTION: { michael@0: if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) { michael@0: reconstructTheActiveFormattingElements(); michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TEXT: { michael@0: accumulateCharacters(buf, start, length); michael@0: return; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_TABLE: michael@0: case NS_HTML5TREE_BUILDER_IN_TABLE_BODY: michael@0: case NS_HTML5TREE_BUILDER_IN_ROW: { michael@0: accumulateCharactersForced(buf, start, length); michael@0: return; michael@0: } michael@0: default: { michael@0: int32_t end = start + length; michael@0: for (int32_t i = start; i < end; i++) { michael@0: switch(buf[i]) { michael@0: case ' ': michael@0: case '\t': michael@0: case '\n': michael@0: case '\r': michael@0: case '\f': { michael@0: switch(mode) { michael@0: case NS_HTML5TREE_BUILDER_INITIAL: michael@0: case NS_HTML5TREE_BUILDER_BEFORE_HTML: michael@0: case NS_HTML5TREE_BUILDER_BEFORE_HEAD: { michael@0: start = i + 1; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_HEAD: michael@0: case NS_HTML5TREE_BUILDER_IN_HEAD_NOSCRIPT: michael@0: case NS_HTML5TREE_BUILDER_AFTER_HEAD: michael@0: case NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP: michael@0: case NS_HTML5TREE_BUILDER_IN_FRAMESET: michael@0: case NS_HTML5TREE_BUILDER_AFTER_FRAMESET: { michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_FRAMESET_OK: michael@0: case NS_HTML5TREE_BUILDER_IN_TEMPLATE: michael@0: case NS_HTML5TREE_BUILDER_IN_BODY: michael@0: case NS_HTML5TREE_BUILDER_IN_CELL: michael@0: case NS_HTML5TREE_BUILDER_IN_CAPTION: { michael@0: if (start < i) { michael@0: accumulateCharacters(buf, start, i - start); michael@0: start = i; michael@0: } michael@0: if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) { michael@0: flushCharacters(); michael@0: reconstructTheActiveFormattingElements(); michael@0: } michael@0: NS_HTML5_BREAK(charactersloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_SELECT: michael@0: case NS_HTML5TREE_BUILDER_IN_SELECT_IN_TABLE: { michael@0: NS_HTML5_BREAK(charactersloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_TABLE: michael@0: case NS_HTML5TREE_BUILDER_IN_TABLE_BODY: michael@0: case NS_HTML5TREE_BUILDER_IN_ROW: { michael@0: accumulateCharactersForced(buf, i, 1); michael@0: start = i + 1; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_BODY: michael@0: case NS_HTML5TREE_BUILDER_AFTER_AFTER_BODY: michael@0: case NS_HTML5TREE_BUILDER_AFTER_AFTER_FRAMESET: { michael@0: if (start < i) { michael@0: accumulateCharacters(buf, start, i - start); michael@0: start = i; michael@0: } michael@0: flushCharacters(); michael@0: reconstructTheActiveFormattingElements(); michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: default: { michael@0: switch(mode) { michael@0: case NS_HTML5TREE_BUILDER_INITIAL: { michael@0: documentModeInternal(QUIRKS_MODE, nullptr, nullptr, false); michael@0: mode = NS_HTML5TREE_BUILDER_BEFORE_HTML; michael@0: i--; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BEFORE_HTML: { michael@0: appendHtmlElementToDocumentAndPush(); michael@0: mode = NS_HTML5TREE_BUILDER_BEFORE_HEAD; michael@0: i--; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BEFORE_HEAD: { michael@0: if (start < i) { michael@0: accumulateCharacters(buf, start, i - start); michael@0: start = i; michael@0: } michael@0: flushCharacters(); michael@0: appendToCurrentNodeAndPushHeadElement(nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES); michael@0: mode = NS_HTML5TREE_BUILDER_IN_HEAD; michael@0: i--; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_HEAD: { michael@0: if (start < i) { michael@0: accumulateCharacters(buf, start, i - start); michael@0: start = i; michael@0: } michael@0: flushCharacters(); michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_AFTER_HEAD; michael@0: i--; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_HEAD_NOSCRIPT: { michael@0: if (start < i) { michael@0: accumulateCharacters(buf, start, i - start); michael@0: start = i; michael@0: } michael@0: errNonSpaceInNoscriptInHead(); michael@0: flushCharacters(); michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_HEAD; michael@0: i--; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_HEAD: { michael@0: if (start < i) { michael@0: accumulateCharacters(buf, start, i - start); michael@0: start = i; michael@0: } michael@0: flushCharacters(); michael@0: appendToCurrentNodeAndPushBodyElement(); michael@0: mode = NS_HTML5TREE_BUILDER_FRAMESET_OK; michael@0: i--; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_FRAMESET_OK: { michael@0: framesetOk = false; michael@0: mode = NS_HTML5TREE_BUILDER_IN_BODY; michael@0: i--; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_TEMPLATE: michael@0: case NS_HTML5TREE_BUILDER_IN_BODY: michael@0: case NS_HTML5TREE_BUILDER_IN_CELL: michael@0: case NS_HTML5TREE_BUILDER_IN_CAPTION: { michael@0: if (start < i) { michael@0: accumulateCharacters(buf, start, i - start); michael@0: start = i; michael@0: } michael@0: if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) { michael@0: flushCharacters(); michael@0: reconstructTheActiveFormattingElements(); michael@0: } michael@0: NS_HTML5_BREAK(charactersloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_TABLE: michael@0: case NS_HTML5TREE_BUILDER_IN_TABLE_BODY: michael@0: case NS_HTML5TREE_BUILDER_IN_ROW: { michael@0: accumulateCharactersForced(buf, i, 1); michael@0: start = i + 1; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP: { michael@0: if (start < i) { michael@0: accumulateCharacters(buf, start, i - start); michael@0: start = i; michael@0: } michael@0: if (!currentPtr || stack[currentPtr]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE) { michael@0: errNonSpaceInColgroupInFragment(); michael@0: start = i + 1; michael@0: continue; michael@0: } michael@0: flushCharacters(); michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE; michael@0: i--; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_SELECT: michael@0: case NS_HTML5TREE_BUILDER_IN_SELECT_IN_TABLE: { michael@0: NS_HTML5_BREAK(charactersloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_BODY: { michael@0: errNonSpaceAfterBody(); michael@0: michael@0: mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY; michael@0: i--; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_FRAMESET: { michael@0: if (start < i) { michael@0: accumulateCharacters(buf, start, i - start); michael@0: start = i; michael@0: } michael@0: errNonSpaceInFrameset(); michael@0: start = i + 1; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_FRAMESET: { michael@0: if (start < i) { michael@0: accumulateCharacters(buf, start, i - start); michael@0: start = i; michael@0: } michael@0: errNonSpaceAfterFrameset(); michael@0: start = i + 1; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_AFTER_BODY: { michael@0: errNonSpaceInTrailer(); michael@0: mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY; michael@0: i--; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_AFTER_FRAMESET: { michael@0: errNonSpaceInTrailer(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_FRAMESET; michael@0: i--; michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: charactersloop_end: ; michael@0: if (start < end) { michael@0: accumulateCharacters(buf, start, end - start); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::zeroOriginatingReplacementCharacter() michael@0: { michael@0: if (mode == NS_HTML5TREE_BUILDER_TEXT) { michael@0: accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1); michael@0: return; michael@0: } michael@0: if (currentPtr >= 0) { michael@0: if (isSpecialParentInForeign(stack[currentPtr])) { michael@0: return; michael@0: } michael@0: accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::eof() michael@0: { michael@0: flushCharacters(); michael@0: for (; ; ) { michael@0: switch(mode) { michael@0: case NS_HTML5TREE_BUILDER_INITIAL: { michael@0: documentModeInternal(QUIRKS_MODE, nullptr, nullptr, false); michael@0: mode = NS_HTML5TREE_BUILDER_BEFORE_HTML; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BEFORE_HTML: { michael@0: appendHtmlElementToDocumentAndPush(); michael@0: mode = NS_HTML5TREE_BUILDER_BEFORE_HEAD; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BEFORE_HEAD: { michael@0: appendToCurrentNodeAndPushHeadElement(nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES); michael@0: mode = NS_HTML5TREE_BUILDER_IN_HEAD; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_HEAD: { michael@0: while (currentPtr > 0) { michael@0: popOnEof(); michael@0: } michael@0: mode = NS_HTML5TREE_BUILDER_AFTER_HEAD; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_HEAD_NOSCRIPT: { michael@0: while (currentPtr > 1) { michael@0: popOnEof(); michael@0: } michael@0: mode = NS_HTML5TREE_BUILDER_IN_HEAD; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_HEAD: { michael@0: appendToCurrentNodeAndPushBodyElement(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_BODY; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_TABLE_BODY: michael@0: case NS_HTML5TREE_BUILDER_IN_ROW: michael@0: case NS_HTML5TREE_BUILDER_IN_TABLE: michael@0: case NS_HTML5TREE_BUILDER_IN_SELECT_IN_TABLE: michael@0: case NS_HTML5TREE_BUILDER_IN_SELECT: michael@0: case NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP: michael@0: case NS_HTML5TREE_BUILDER_FRAMESET_OK: michael@0: case NS_HTML5TREE_BUILDER_IN_CAPTION: michael@0: case NS_HTML5TREE_BUILDER_IN_CELL: michael@0: case NS_HTML5TREE_BUILDER_IN_BODY: { michael@0: if (isTemplateModeStackEmpty()) { michael@0: NS_HTML5_BREAK(eofloop); michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_TEMPLATE: { michael@0: int32_t eltPos = findLast(nsHtml5Atoms::template_); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: MOZ_ASSERT(fragment); michael@0: NS_HTML5_BREAK(eofloop); michael@0: } michael@0: if (MOZ_UNLIKELY(mViewSource)) { michael@0: errUnclosedElements(eltPos, nsHtml5Atoms::template_); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: clearTheListOfActiveFormattingElementsUpToTheLastMarker(); michael@0: popTemplateMode(); michael@0: resetTheInsertionMode(); michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TEXT: { michael@0: if (originalMode == NS_HTML5TREE_BUILDER_AFTER_HEAD) { michael@0: popOnEof(); michael@0: } michael@0: popOnEof(); michael@0: mode = originalMode; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_FRAMESET: { michael@0: NS_HTML5_BREAK(eofloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_BODY: michael@0: case NS_HTML5TREE_BUILDER_AFTER_FRAMESET: michael@0: case NS_HTML5TREE_BUILDER_AFTER_AFTER_BODY: michael@0: case NS_HTML5TREE_BUILDER_AFTER_AFTER_FRAMESET: michael@0: default: { michael@0: NS_HTML5_BREAK(eofloop); michael@0: } michael@0: } michael@0: } michael@0: eofloop_end: ; michael@0: while (currentPtr > 0) { michael@0: popOnEof(); michael@0: } michael@0: if (!fragment) { michael@0: popOnEof(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::endTokenization() michael@0: { michael@0: formPointer = nullptr; michael@0: headPointer = nullptr; michael@0: deepTreeSurrogateParent = nullptr; michael@0: templateModeStack = nullptr; michael@0: if (stack) { michael@0: while (currentPtr > -1) { michael@0: stack[currentPtr]->release(); michael@0: currentPtr--; michael@0: } michael@0: stack = nullptr; michael@0: } michael@0: if (listOfActiveFormattingElements) { michael@0: while (listPtr > -1) { michael@0: if (listOfActiveFormattingElements[listPtr]) { michael@0: listOfActiveFormattingElements[listPtr]->release(); michael@0: } michael@0: listPtr--; michael@0: } michael@0: listOfActiveFormattingElements = nullptr; michael@0: } michael@0: charBuffer = nullptr; michael@0: end(); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes, bool selfClosing) michael@0: { michael@0: flushCharacters(); michael@0: int32_t eltPos; michael@0: needToDropLF = false; michael@0: starttagloop: for (; ; ) { michael@0: int32_t group = elementName->getGroup(); michael@0: nsIAtom* name = elementName->name; michael@0: if (isInForeign()) { michael@0: nsHtml5StackNode* currentNode = stack[currentPtr]; michael@0: int32_t currNs = currentNode->ns; michael@0: if (!(currentNode->isHtmlIntegrationPoint() || (currNs == kNameSpaceID_MathML && ((currentNode->getGroup() == NS_HTML5TREE_BUILDER_MI_MO_MN_MS_MTEXT && group != NS_HTML5TREE_BUILDER_MGLYPH_OR_MALIGNMARK) || (currentNode->getGroup() == NS_HTML5TREE_BUILDER_ANNOTATION_XML && group == NS_HTML5TREE_BUILDER_SVG))))) { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U: michael@0: case NS_HTML5TREE_BUILDER_DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU: michael@0: case NS_HTML5TREE_BUILDER_BODY: michael@0: case NS_HTML5TREE_BUILDER_BR: michael@0: case NS_HTML5TREE_BUILDER_RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR: michael@0: case NS_HTML5TREE_BUILDER_DD_OR_DT: michael@0: case NS_HTML5TREE_BUILDER_UL_OR_OL_OR_DL: michael@0: case NS_HTML5TREE_BUILDER_EMBED: michael@0: case NS_HTML5TREE_BUILDER_IMG: michael@0: case NS_HTML5TREE_BUILDER_H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: michael@0: case NS_HTML5TREE_BUILDER_HEAD: michael@0: case NS_HTML5TREE_BUILDER_HR: michael@0: case NS_HTML5TREE_BUILDER_LI: michael@0: case NS_HTML5TREE_BUILDER_META: michael@0: case NS_HTML5TREE_BUILDER_NOBR: michael@0: case NS_HTML5TREE_BUILDER_P: michael@0: case NS_HTML5TREE_BUILDER_PRE_OR_LISTING: michael@0: case NS_HTML5TREE_BUILDER_TABLE: { michael@0: errHtmlStartTagInForeignContext(name); michael@0: while (!isSpecialParentInForeign(stack[currentPtr])) { michael@0: pop(); michael@0: } michael@0: NS_HTML5_CONTINUE(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_FONT: { michael@0: if (attributes->contains(nsHtml5AttributeName::ATTR_COLOR) || attributes->contains(nsHtml5AttributeName::ATTR_FACE) || attributes->contains(nsHtml5AttributeName::ATTR_SIZE)) { michael@0: errHtmlStartTagInForeignContext(name); michael@0: while (!isSpecialParentInForeign(stack[currentPtr])) { michael@0: pop(); michael@0: } michael@0: NS_HTML5_CONTINUE(starttagloop); michael@0: } michael@0: } michael@0: default: { michael@0: if (kNameSpaceID_SVG == currNs) { michael@0: attributes->adjustForSvg(); michael@0: if (selfClosing) { michael@0: appendVoidElementToCurrentMayFosterSVG(elementName, attributes); michael@0: selfClosing = false; michael@0: } else { michael@0: appendToCurrentNodeAndPushElementMayFosterSVG(elementName, attributes); michael@0: } michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } else { michael@0: attributes->adjustForMath(); michael@0: if (selfClosing) { michael@0: appendVoidElementToCurrentMayFosterMathML(elementName, attributes); michael@0: selfClosing = false; michael@0: } else { michael@0: appendToCurrentNodeAndPushElementMayFosterMathML(elementName, attributes); michael@0: } michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: switch(mode) { michael@0: case NS_HTML5TREE_BUILDER_IN_TEMPLATE: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_COL: { michael@0: popTemplateMode(); michael@0: pushTemplateMode(NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP); michael@0: mode = NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_CAPTION: michael@0: case NS_HTML5TREE_BUILDER_COLGROUP: michael@0: case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: { michael@0: popTemplateMode(); michael@0: pushTemplateMode(NS_HTML5TREE_BUILDER_IN_TABLE); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TR: { michael@0: popTemplateMode(); michael@0: pushTemplateMode(NS_HTML5TREE_BUILDER_IN_TABLE_BODY); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE_BODY; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TD_OR_TH: { michael@0: popTemplateMode(); michael@0: pushTemplateMode(NS_HTML5TREE_BUILDER_IN_ROW); michael@0: mode = NS_HTML5TREE_BUILDER_IN_ROW; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_META: { michael@0: checkMetaCharset(attributes); michael@0: appendVoidElementToCurrentMayFoster(elementName, attributes); michael@0: selfClosing = false; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TITLE: { michael@0: startTagTitleInHead(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BASE: michael@0: case NS_HTML5TREE_BUILDER_LINK_OR_BASEFONT_OR_BGSOUND: { michael@0: appendVoidElementToCurrentMayFoster(elementName, attributes); michael@0: selfClosing = false; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_SCRIPT: { michael@0: startTagScriptInHead(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_NOFRAMES: michael@0: case NS_HTML5TREE_BUILDER_STYLE: { michael@0: startTagGenericRawText(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TEMPLATE: { michael@0: startTagTemplateInHead(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: default: { michael@0: popTemplateMode(); michael@0: pushTemplateMode(NS_HTML5TREE_BUILDER_IN_BODY); michael@0: mode = NS_HTML5TREE_BUILDER_IN_BODY; michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_ROW: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_TD_OR_TH: { michael@0: clearStackBackTo(findLastOrRoot(NS_HTML5TREE_BUILDER_TR)); michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: mode = NS_HTML5TREE_BUILDER_IN_CELL; michael@0: insertMarker(); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_CAPTION: michael@0: case NS_HTML5TREE_BUILDER_COL: michael@0: case NS_HTML5TREE_BUILDER_COLGROUP: michael@0: case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: michael@0: case NS_HTML5TREE_BUILDER_TR: { michael@0: eltPos = findLastOrRoot(NS_HTML5TREE_BUILDER_TR); michael@0: if (!eltPos) { michael@0: MOZ_ASSERT(fragment || isTemplateContents()); michael@0: errNoTableRowToClose(); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: clearStackBackTo(eltPos); michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE_BODY; michael@0: continue; michael@0: } michael@0: default: michael@0: ; // fall through michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_TABLE_BODY: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_TR: { michael@0: clearStackBackTo(findLastInTableScopeOrRootTemplateTbodyTheadTfoot()); michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: mode = NS_HTML5TREE_BUILDER_IN_ROW; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TD_OR_TH: { michael@0: errStartTagInTableBody(name); michael@0: clearStackBackTo(findLastInTableScopeOrRootTemplateTbodyTheadTfoot()); michael@0: appendToCurrentNodeAndPushElement(nsHtml5ElementName::ELT_TR, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES); michael@0: mode = NS_HTML5TREE_BUILDER_IN_ROW; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_CAPTION: michael@0: case NS_HTML5TREE_BUILDER_COL: michael@0: case NS_HTML5TREE_BUILDER_COLGROUP: michael@0: case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: { michael@0: eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot(); michael@0: if (!eltPos || stack[eltPos]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE) { michael@0: MOZ_ASSERT(fragment || isTemplateContents()); michael@0: errStrayStartTag(name); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } else { michael@0: clearStackBackTo(eltPos); michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE; michael@0: continue; michael@0: } michael@0: } michael@0: default: michael@0: ; // fall through michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_TABLE: { michael@0: for (; ; ) { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_CAPTION: { michael@0: clearStackBackTo(findLastOrRoot(NS_HTML5TREE_BUILDER_TABLE)); michael@0: insertMarker(); michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: mode = NS_HTML5TREE_BUILDER_IN_CAPTION; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_COLGROUP: { michael@0: clearStackBackTo(findLastOrRoot(NS_HTML5TREE_BUILDER_TABLE)); michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: mode = NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_COL: { michael@0: clearStackBackTo(findLastOrRoot(NS_HTML5TREE_BUILDER_TABLE)); michael@0: appendToCurrentNodeAndPushElement(nsHtml5ElementName::ELT_COLGROUP, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES); michael@0: mode = NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP; michael@0: NS_HTML5_CONTINUE(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: { michael@0: clearStackBackTo(findLastOrRoot(NS_HTML5TREE_BUILDER_TABLE)); michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE_BODY; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TR: michael@0: case NS_HTML5TREE_BUILDER_TD_OR_TH: { michael@0: clearStackBackTo(findLastOrRoot(NS_HTML5TREE_BUILDER_TABLE)); michael@0: appendToCurrentNodeAndPushElement(nsHtml5ElementName::ELT_TBODY, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE_BODY; michael@0: NS_HTML5_CONTINUE(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TEMPLATE: { michael@0: NS_HTML5_BREAK(intableloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TABLE: { michael@0: errTableSeenWhileTableOpen(); michael@0: eltPos = findLastInTableScope(name); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: MOZ_ASSERT(fragment || isTemplateContents()); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: generateImpliedEndTags(); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(nsHtml5Atoms::table)) { michael@0: errNoCheckUnclosedElementsOnStack(); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: resetTheInsertionMode(); michael@0: NS_HTML5_CONTINUE(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_SCRIPT: { michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: originalMode = mode; michael@0: mode = NS_HTML5TREE_BUILDER_TEXT; michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_SCRIPT_DATA, elementName); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_STYLE: { michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: originalMode = mode; michael@0: mode = NS_HTML5TREE_BUILDER_TEXT; michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RAWTEXT, elementName); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_INPUT: { michael@0: errStartTagInTable(name); michael@0: if (!nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("hidden", attributes->getValue(nsHtml5AttributeName::ATTR_TYPE))) { michael@0: NS_HTML5_BREAK(intableloop); michael@0: } michael@0: appendVoidElementToCurrent(name, attributes, formPointer); michael@0: selfClosing = false; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_FORM: { michael@0: if (!!formPointer || isTemplateContents()) { michael@0: errFormWhenFormOpen(); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } else { michael@0: errStartTagInTable(name); michael@0: appendVoidFormToCurrent(attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: } michael@0: default: { michael@0: errStartTagInTable(name); michael@0: NS_HTML5_BREAK(intableloop); michael@0: } michael@0: } michael@0: } michael@0: intableloop_end: ; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_CAPTION: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_CAPTION: michael@0: case NS_HTML5TREE_BUILDER_COL: michael@0: case NS_HTML5TREE_BUILDER_COLGROUP: michael@0: case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: michael@0: case NS_HTML5TREE_BUILDER_TR: michael@0: case NS_HTML5TREE_BUILDER_TD_OR_TH: { michael@0: errStrayStartTag(name); michael@0: eltPos = findLastInTableScope(nsHtml5Atoms::caption); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: generateImpliedEndTags(); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) { michael@0: errNoCheckUnclosedElementsOnStack(); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: clearTheListOfActiveFormattingElementsUpToTheLastMarker(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE; michael@0: continue; michael@0: } michael@0: default: michael@0: ; // fall through michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_CELL: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_CAPTION: michael@0: case NS_HTML5TREE_BUILDER_COL: michael@0: case NS_HTML5TREE_BUILDER_COLGROUP: michael@0: case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: michael@0: case NS_HTML5TREE_BUILDER_TR: michael@0: case NS_HTML5TREE_BUILDER_TD_OR_TH: { michael@0: eltPos = findLastInTableScopeTdTh(); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: errNoCellToClose(); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } else { michael@0: closeTheCell(eltPos); michael@0: continue; michael@0: } michael@0: } michael@0: default: michael@0: ; // fall through michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_FRAMESET_OK: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_FRAMESET: { michael@0: if (mode == NS_HTML5TREE_BUILDER_FRAMESET_OK) { michael@0: if (!currentPtr || stack[1]->getGroup() != NS_HTML5TREE_BUILDER_BODY) { michael@0: MOZ_ASSERT(fragment || isTemplateContents()); michael@0: errStrayStartTag(name); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } else { michael@0: errFramesetStart(); michael@0: detachFromParent(stack[1]->node); michael@0: while (currentPtr > 0) { michael@0: pop(); michael@0: } michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: mode = NS_HTML5TREE_BUILDER_IN_FRAMESET; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: } else { michael@0: errStrayStartTag(name); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_PRE_OR_LISTING: michael@0: case NS_HTML5TREE_BUILDER_LI: michael@0: case NS_HTML5TREE_BUILDER_DD_OR_DT: michael@0: case NS_HTML5TREE_BUILDER_BUTTON: michael@0: case NS_HTML5TREE_BUILDER_MARQUEE_OR_APPLET: michael@0: case NS_HTML5TREE_BUILDER_OBJECT: michael@0: case NS_HTML5TREE_BUILDER_TABLE: michael@0: case NS_HTML5TREE_BUILDER_AREA_OR_WBR: michael@0: case NS_HTML5TREE_BUILDER_BR: michael@0: case NS_HTML5TREE_BUILDER_EMBED: michael@0: case NS_HTML5TREE_BUILDER_IMG: michael@0: case NS_HTML5TREE_BUILDER_INPUT: michael@0: case NS_HTML5TREE_BUILDER_KEYGEN: michael@0: case NS_HTML5TREE_BUILDER_HR: michael@0: case NS_HTML5TREE_BUILDER_TEXTAREA: michael@0: case NS_HTML5TREE_BUILDER_XMP: michael@0: case NS_HTML5TREE_BUILDER_IFRAME: michael@0: case NS_HTML5TREE_BUILDER_SELECT: { michael@0: if (mode == NS_HTML5TREE_BUILDER_FRAMESET_OK && !(group == NS_HTML5TREE_BUILDER_INPUT && nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("hidden", attributes->getValue(nsHtml5AttributeName::ATTR_TYPE)))) { michael@0: framesetOk = false; michael@0: mode = NS_HTML5TREE_BUILDER_IN_BODY; michael@0: } michael@0: } michael@0: default: michael@0: ; // fall through michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_BODY: { michael@0: for (; ; ) { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_HTML: { michael@0: errStrayStartTag(name); michael@0: if (!fragment && !isTemplateContents()) { michael@0: addAttributesToHtml(attributes); michael@0: attributes = nullptr; michael@0: } michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BASE: michael@0: case NS_HTML5TREE_BUILDER_LINK_OR_BASEFONT_OR_BGSOUND: michael@0: case NS_HTML5TREE_BUILDER_META: michael@0: case NS_HTML5TREE_BUILDER_STYLE: michael@0: case NS_HTML5TREE_BUILDER_SCRIPT: michael@0: case NS_HTML5TREE_BUILDER_TITLE: michael@0: case NS_HTML5TREE_BUILDER_TEMPLATE: { michael@0: NS_HTML5_BREAK(inbodyloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BODY: { michael@0: if (!currentPtr || stack[1]->getGroup() != NS_HTML5TREE_BUILDER_BODY || isTemplateContents()) { michael@0: MOZ_ASSERT(fragment || isTemplateContents()); michael@0: errStrayStartTag(name); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: errFooSeenWhenFooOpen(name); michael@0: framesetOk = false; michael@0: if (mode == NS_HTML5TREE_BUILDER_FRAMESET_OK) { michael@0: mode = NS_HTML5TREE_BUILDER_IN_BODY; michael@0: } michael@0: if (addAttributesToBody(attributes)) { michael@0: attributes = nullptr; michael@0: } michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_P: michael@0: case NS_HTML5TREE_BUILDER_DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU: michael@0: case NS_HTML5TREE_BUILDER_UL_OR_OL_OR_DL: michael@0: case NS_HTML5TREE_BUILDER_ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SECTION_OR_SUMMARY: { michael@0: implicitlyCloseP(); michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: { michael@0: implicitlyCloseP(); michael@0: if (stack[currentPtr]->getGroup() == NS_HTML5TREE_BUILDER_H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) { michael@0: errHeadingWhenHeadingOpen(); michael@0: pop(); michael@0: } michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_FIELDSET: { michael@0: implicitlyCloseP(); michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes, formPointer); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_PRE_OR_LISTING: { michael@0: implicitlyCloseP(); michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); michael@0: needToDropLF = true; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_FORM: { michael@0: if (!!formPointer && !isTemplateContents()) { michael@0: errFormWhenFormOpen(); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } else { michael@0: implicitlyCloseP(); michael@0: appendToCurrentNodeAndPushFormElementMayFoster(attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_LI: michael@0: case NS_HTML5TREE_BUILDER_DD_OR_DT: { michael@0: eltPos = currentPtr; michael@0: for (; ; ) { michael@0: nsHtml5StackNode* node = stack[eltPos]; michael@0: if (node->getGroup() == group) { michael@0: generateImpliedEndTagsExceptFor(node->name); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) { michael@0: errUnclosedElementsImplied(eltPos, name); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: break; michael@0: } else if (node->isSpecial() && (node->ns != kNameSpaceID_XHTML || (node->name != nsHtml5Atoms::p && node->name != nsHtml5Atoms::address && node->name != nsHtml5Atoms::div))) { michael@0: break; michael@0: } michael@0: eltPos--; michael@0: } michael@0: implicitlyCloseP(); michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_PLAINTEXT: { michael@0: implicitlyCloseP(); michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_PLAINTEXT, elementName); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_A: { michael@0: int32_t activeAPos = findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker(nsHtml5Atoms::a); michael@0: if (activeAPos != -1) { michael@0: errFooSeenWhenFooOpen(name); michael@0: nsHtml5StackNode* activeA = listOfActiveFormattingElements[activeAPos]; michael@0: activeA->retain(); michael@0: adoptionAgencyEndTag(nsHtml5Atoms::a); michael@0: removeFromStack(activeA); michael@0: activeAPos = findInListOfActiveFormattingElements(activeA); michael@0: if (activeAPos != -1) { michael@0: removeFromListOfActiveFormattingElements(activeAPos); michael@0: } michael@0: activeA->release(); michael@0: } michael@0: reconstructTheActiveFormattingElements(); michael@0: appendToCurrentNodeAndPushFormattingElementMayFoster(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U: michael@0: case NS_HTML5TREE_BUILDER_FONT: { michael@0: reconstructTheActiveFormattingElements(); michael@0: maybeForgetEarlierDuplicateFormattingElement(elementName->name, attributes); michael@0: appendToCurrentNodeAndPushFormattingElementMayFoster(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_NOBR: { michael@0: reconstructTheActiveFormattingElements(); michael@0: if (NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK != findLastInScope(nsHtml5Atoms::nobr)) { michael@0: errFooSeenWhenFooOpen(name); michael@0: adoptionAgencyEndTag(nsHtml5Atoms::nobr); michael@0: reconstructTheActiveFormattingElements(); michael@0: } michael@0: appendToCurrentNodeAndPushFormattingElementMayFoster(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BUTTON: { michael@0: eltPos = findLastInScope(name); michael@0: if (eltPos != NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: errFooSeenWhenFooOpen(name); michael@0: generateImpliedEndTags(); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) { michael@0: errUnclosedElementsImplied(eltPos, name); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: NS_HTML5_CONTINUE(starttagloop); michael@0: } else { michael@0: reconstructTheActiveFormattingElements(); michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes, formPointer); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_OBJECT: { michael@0: reconstructTheActiveFormattingElements(); michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes, formPointer); michael@0: insertMarker(); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_MARQUEE_OR_APPLET: { michael@0: reconstructTheActiveFormattingElements(); michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); michael@0: insertMarker(); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TABLE: { michael@0: if (!quirks) { michael@0: implicitlyCloseP(); michael@0: } michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BR: michael@0: case NS_HTML5TREE_BUILDER_EMBED: michael@0: case NS_HTML5TREE_BUILDER_AREA_OR_WBR: { michael@0: reconstructTheActiveFormattingElements(); michael@0: } michael@0: #ifdef ENABLE_VOID_MENUITEM michael@0: case NS_HTML5TREE_BUILDER_MENUITEM: michael@0: #endif michael@0: case NS_HTML5TREE_BUILDER_PARAM_OR_SOURCE_OR_TRACK: { michael@0: appendVoidElementToCurrentMayFoster(elementName, attributes); michael@0: selfClosing = false; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_HR: { michael@0: implicitlyCloseP(); michael@0: appendVoidElementToCurrentMayFoster(elementName, attributes); michael@0: selfClosing = false; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IMAGE: { michael@0: errImage(); michael@0: elementName = nsHtml5ElementName::ELT_IMG; michael@0: NS_HTML5_CONTINUE(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IMG: michael@0: case NS_HTML5TREE_BUILDER_KEYGEN: michael@0: case NS_HTML5TREE_BUILDER_INPUT: { michael@0: reconstructTheActiveFormattingElements(); michael@0: appendVoidElementToCurrentMayFoster(name, attributes, formPointer); michael@0: selfClosing = false; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_ISINDEX: { michael@0: errIsindex(); michael@0: if (!!formPointer && !isTemplateContents()) { michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: implicitlyCloseP(); michael@0: nsHtml5HtmlAttributes* formAttrs = new nsHtml5HtmlAttributes(0); michael@0: int32_t actionIndex = attributes->getIndex(nsHtml5AttributeName::ATTR_ACTION); michael@0: if (actionIndex > -1) { michael@0: formAttrs->addAttribute(nsHtml5AttributeName::ATTR_ACTION, attributes->getValueNoBoundsCheck(actionIndex)); michael@0: } michael@0: appendToCurrentNodeAndPushFormElementMayFoster(formAttrs); michael@0: appendVoidElementToCurrentMayFoster(nsHtml5ElementName::ELT_HR, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES); michael@0: appendToCurrentNodeAndPushElementMayFoster(nsHtml5ElementName::ELT_LABEL, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES); michael@0: int32_t promptIndex = attributes->getIndex(nsHtml5AttributeName::ATTR_PROMPT); michael@0: if (promptIndex > -1) { michael@0: autoJArray prompt = nsHtml5Portability::newCharArrayFromString(attributes->getValueNoBoundsCheck(promptIndex)); michael@0: appendCharacters(stack[currentPtr]->node, prompt, 0, prompt.length); michael@0: } else { michael@0: appendIsindexPrompt(stack[currentPtr]->node); michael@0: } michael@0: nsHtml5HtmlAttributes* inputAttributes = new nsHtml5HtmlAttributes(0); michael@0: inputAttributes->addAttribute(nsHtml5AttributeName::ATTR_NAME, nsHtml5Portability::newStringFromLiteral("isindex")); michael@0: for (int32_t i = 0; i < attributes->getLength(); i++) { michael@0: nsHtml5AttributeName* attributeQName = attributes->getAttributeNameNoBoundsCheck(i); michael@0: if (nsHtml5AttributeName::ATTR_NAME == attributeQName || nsHtml5AttributeName::ATTR_PROMPT == attributeQName) { michael@0: attributes->releaseValue(i); michael@0: } else if (nsHtml5AttributeName::ATTR_ACTION != attributeQName) { michael@0: inputAttributes->addAttribute(attributeQName, attributes->getValueNoBoundsCheck(i)); michael@0: } michael@0: } michael@0: attributes->clearWithoutReleasingContents(); michael@0: appendVoidElementToCurrentMayFoster(nsHtml5Atoms::input, inputAttributes, formPointer); michael@0: pop(); michael@0: appendVoidElementToCurrentMayFoster(nsHtml5ElementName::ELT_HR, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES); michael@0: pop(); michael@0: if (!isTemplateContents()) { michael@0: formPointer = nullptr; michael@0: } michael@0: selfClosing = false; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TEXTAREA: { michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes, formPointer); michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RCDATA, elementName); michael@0: originalMode = mode; michael@0: mode = NS_HTML5TREE_BUILDER_TEXT; michael@0: needToDropLF = true; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_XMP: { michael@0: implicitlyCloseP(); michael@0: reconstructTheActiveFormattingElements(); michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); michael@0: originalMode = mode; michael@0: mode = NS_HTML5TREE_BUILDER_TEXT; michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RAWTEXT, elementName); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_NOSCRIPT: { michael@0: if (!scriptingEnabled) { michael@0: reconstructTheActiveFormattingElements(); michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } else { michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_NOFRAMES: michael@0: case NS_HTML5TREE_BUILDER_IFRAME: michael@0: case NS_HTML5TREE_BUILDER_NOEMBED: { michael@0: startTagGenericRawText(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_SELECT: { michael@0: reconstructTheActiveFormattingElements(); michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes, formPointer); michael@0: switch(mode) { michael@0: case NS_HTML5TREE_BUILDER_IN_TABLE: michael@0: case NS_HTML5TREE_BUILDER_IN_CAPTION: michael@0: case NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP: michael@0: case NS_HTML5TREE_BUILDER_IN_TABLE_BODY: michael@0: case NS_HTML5TREE_BUILDER_IN_ROW: michael@0: case NS_HTML5TREE_BUILDER_IN_CELL: { michael@0: mode = NS_HTML5TREE_BUILDER_IN_SELECT_IN_TABLE; michael@0: break; michael@0: } michael@0: default: { michael@0: mode = NS_HTML5TREE_BUILDER_IN_SELECT; michael@0: break; michael@0: } michael@0: } michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_OPTGROUP: michael@0: case NS_HTML5TREE_BUILDER_OPTION: { michael@0: if (isCurrent(nsHtml5Atoms::option)) { michael@0: pop(); michael@0: } michael@0: reconstructTheActiveFormattingElements(); michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_RT_OR_RP: { michael@0: eltPos = findLastInScope(nsHtml5Atoms::ruby); michael@0: if (eltPos != NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: generateImpliedEndTags(); michael@0: } michael@0: if (eltPos != currentPtr) { michael@0: if (eltPos != NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: errStartTagSeenWithoutRuby(name); michael@0: } else { michael@0: errUnclosedChildrenInRuby(); michael@0: } michael@0: } michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_MATH: { michael@0: reconstructTheActiveFormattingElements(); michael@0: attributes->adjustForMath(); michael@0: if (selfClosing) { michael@0: appendVoidElementToCurrentMayFosterMathML(elementName, attributes); michael@0: selfClosing = false; michael@0: } else { michael@0: appendToCurrentNodeAndPushElementMayFosterMathML(elementName, attributes); michael@0: } michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_SVG: { michael@0: reconstructTheActiveFormattingElements(); michael@0: attributes->adjustForSvg(); michael@0: if (selfClosing) { michael@0: appendVoidElementToCurrentMayFosterSVG(elementName, attributes); michael@0: selfClosing = false; michael@0: } else { michael@0: appendToCurrentNodeAndPushElementMayFosterSVG(elementName, attributes); michael@0: } michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_CAPTION: michael@0: case NS_HTML5TREE_BUILDER_COL: michael@0: case NS_HTML5TREE_BUILDER_COLGROUP: michael@0: case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: michael@0: case NS_HTML5TREE_BUILDER_TR: michael@0: case NS_HTML5TREE_BUILDER_TD_OR_TH: michael@0: case NS_HTML5TREE_BUILDER_FRAME: michael@0: case NS_HTML5TREE_BUILDER_FRAMESET: michael@0: case NS_HTML5TREE_BUILDER_HEAD: { michael@0: errStrayStartTag(name); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_OUTPUT_OR_LABEL: { michael@0: reconstructTheActiveFormattingElements(); michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes, formPointer); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: default: { michael@0: reconstructTheActiveFormattingElements(); michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: } michael@0: } michael@0: inbodyloop_end: ; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_HEAD: { michael@0: for (; ; ) { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_HTML: { michael@0: errStrayStartTag(name); michael@0: if (!fragment && !isTemplateContents()) { michael@0: addAttributesToHtml(attributes); michael@0: attributes = nullptr; michael@0: } michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BASE: michael@0: case NS_HTML5TREE_BUILDER_LINK_OR_BASEFONT_OR_BGSOUND: { michael@0: appendVoidElementToCurrentMayFoster(elementName, attributes); michael@0: selfClosing = false; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_META: { michael@0: NS_HTML5_BREAK(inheadloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TITLE: { michael@0: startTagTitleInHead(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_NOSCRIPT: { michael@0: if (scriptingEnabled) { michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: originalMode = mode; michael@0: mode = NS_HTML5TREE_BUILDER_TEXT; michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RAWTEXT, elementName); michael@0: } else { michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); michael@0: mode = NS_HTML5TREE_BUILDER_IN_HEAD_NOSCRIPT; michael@0: } michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_SCRIPT: { michael@0: startTagScriptInHead(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_STYLE: michael@0: case NS_HTML5TREE_BUILDER_NOFRAMES: { michael@0: startTagGenericRawText(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_HEAD: { michael@0: errFooSeenWhenFooOpen(name); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TEMPLATE: { michael@0: startTagTemplateInHead(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: default: { michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_AFTER_HEAD; michael@0: NS_HTML5_CONTINUE(starttagloop); michael@0: } michael@0: } michael@0: } michael@0: inheadloop_end: ; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_HEAD_NOSCRIPT: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_HTML: { michael@0: errStrayStartTag(name); michael@0: if (!fragment && !isTemplateContents()) { michael@0: addAttributesToHtml(attributes); michael@0: attributes = nullptr; michael@0: } michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_LINK_OR_BASEFONT_OR_BGSOUND: { michael@0: appendVoidElementToCurrentMayFoster(elementName, attributes); michael@0: selfClosing = false; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_META: { michael@0: checkMetaCharset(attributes); michael@0: appendVoidElementToCurrentMayFoster(elementName, attributes); michael@0: selfClosing = false; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_STYLE: michael@0: case NS_HTML5TREE_BUILDER_NOFRAMES: { michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: originalMode = mode; michael@0: mode = NS_HTML5TREE_BUILDER_TEXT; michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RAWTEXT, elementName); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_HEAD: { michael@0: errFooSeenWhenFooOpen(name); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_NOSCRIPT: { michael@0: errFooSeenWhenFooOpen(name); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: default: { michael@0: errBadStartTagInHead(name); michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_HEAD; michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_HTML: { michael@0: errStrayStartTag(name); michael@0: if (!fragment && !isTemplateContents()) { michael@0: addAttributesToHtml(attributes); michael@0: attributes = nullptr; michael@0: } michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_COL: { michael@0: appendVoidElementToCurrentMayFoster(elementName, attributes); michael@0: selfClosing = false; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TEMPLATE: { michael@0: startTagTemplateInHead(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: default: { michael@0: if (!currentPtr || stack[currentPtr]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE) { michael@0: MOZ_ASSERT(fragment || isTemplateContents()); michael@0: errGarbageInColgroup(); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE; michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_SELECT_IN_TABLE: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_CAPTION: michael@0: case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: michael@0: case NS_HTML5TREE_BUILDER_TR: michael@0: case NS_HTML5TREE_BUILDER_TD_OR_TH: michael@0: case NS_HTML5TREE_BUILDER_TABLE: { michael@0: errStartTagWithSelectOpen(name); michael@0: eltPos = findLastInTableScope(nsHtml5Atoms::select); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: MOZ_ASSERT(fragment); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: resetTheInsertionMode(); michael@0: continue; michael@0: } michael@0: default: michael@0: ; // fall through michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_SELECT: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_HTML: { michael@0: errStrayStartTag(name); michael@0: if (!fragment) { michael@0: addAttributesToHtml(attributes); michael@0: attributes = nullptr; michael@0: } michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_OPTION: { michael@0: if (isCurrent(nsHtml5Atoms::option)) { michael@0: pop(); michael@0: } michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_OPTGROUP: { michael@0: if (isCurrent(nsHtml5Atoms::option)) { michael@0: pop(); michael@0: } michael@0: if (isCurrent(nsHtml5Atoms::optgroup)) { michael@0: pop(); michael@0: } michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_SELECT: { michael@0: errStartSelectWhereEndSelectExpected(); michael@0: eltPos = findLastInTableScope(name); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: MOZ_ASSERT(fragment); michael@0: errNoSelectInTableScope(); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } else { michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: resetTheInsertionMode(); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_INPUT: michael@0: case NS_HTML5TREE_BUILDER_TEXTAREA: michael@0: case NS_HTML5TREE_BUILDER_KEYGEN: { michael@0: errStartTagWithSelectOpen(name); michael@0: eltPos = findLastInTableScope(nsHtml5Atoms::select); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: MOZ_ASSERT(fragment); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: resetTheInsertionMode(); michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_SCRIPT: { michael@0: startTagScriptInHead(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TEMPLATE: { michael@0: startTagTemplateInHead(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: default: { michael@0: errStrayStartTag(name); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_BODY: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_HTML: { michael@0: errStrayStartTag(name); michael@0: if (!fragment && !isTemplateContents()) { michael@0: addAttributesToHtml(attributes); michael@0: attributes = nullptr; michael@0: } michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: default: { michael@0: errStrayStartTag(name); michael@0: mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY; michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_FRAMESET: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_FRAMESET: { michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_FRAME: { michael@0: appendVoidElementToCurrentMayFoster(elementName, attributes); michael@0: selfClosing = false; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: default: michael@0: ; // fall through michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_FRAMESET: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_HTML: { michael@0: errStrayStartTag(name); michael@0: if (!fragment && !isTemplateContents()) { michael@0: addAttributesToHtml(attributes); michael@0: attributes = nullptr; michael@0: } michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_NOFRAMES: { michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: originalMode = mode; michael@0: mode = NS_HTML5TREE_BUILDER_TEXT; michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RAWTEXT, elementName); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: default: { michael@0: errStrayStartTag(name); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_INITIAL: { michael@0: errStartTagWithoutDoctype(); michael@0: documentModeInternal(QUIRKS_MODE, nullptr, nullptr, false); michael@0: mode = NS_HTML5TREE_BUILDER_BEFORE_HTML; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BEFORE_HTML: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_HTML: { michael@0: if (attributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) { michael@0: appendHtmlElementToDocumentAndPush(); michael@0: } else { michael@0: appendHtmlElementToDocumentAndPush(attributes); michael@0: } michael@0: mode = NS_HTML5TREE_BUILDER_BEFORE_HEAD; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: default: { michael@0: appendHtmlElementToDocumentAndPush(); michael@0: mode = NS_HTML5TREE_BUILDER_BEFORE_HEAD; michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BEFORE_HEAD: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_HTML: { michael@0: errStrayStartTag(name); michael@0: if (!fragment && !isTemplateContents()) { michael@0: addAttributesToHtml(attributes); michael@0: attributes = nullptr; michael@0: } michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_HEAD: { michael@0: appendToCurrentNodeAndPushHeadElement(attributes); michael@0: mode = NS_HTML5TREE_BUILDER_IN_HEAD; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: default: { michael@0: appendToCurrentNodeAndPushHeadElement(nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES); michael@0: mode = NS_HTML5TREE_BUILDER_IN_HEAD; michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_HEAD: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_HTML: { michael@0: errStrayStartTag(name); michael@0: if (!fragment && !isTemplateContents()) { michael@0: addAttributesToHtml(attributes); michael@0: attributes = nullptr; michael@0: } michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BODY: { michael@0: if (!attributes->getLength()) { michael@0: appendToCurrentNodeAndPushBodyElement(); michael@0: } else { michael@0: appendToCurrentNodeAndPushBodyElement(attributes); michael@0: } michael@0: framesetOk = false; michael@0: mode = NS_HTML5TREE_BUILDER_IN_BODY; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_FRAMESET: { michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: mode = NS_HTML5TREE_BUILDER_IN_FRAMESET; michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TEMPLATE: { michael@0: errFooBetweenHeadAndBody(name); michael@0: pushHeadPointerOntoStack(); michael@0: nsHtml5StackNode* headOnStack = stack[currentPtr]; michael@0: startTagTemplateInHead(elementName, attributes); michael@0: removeFromStack(headOnStack); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BASE: michael@0: case NS_HTML5TREE_BUILDER_LINK_OR_BASEFONT_OR_BGSOUND: { michael@0: errFooBetweenHeadAndBody(name); michael@0: pushHeadPointerOntoStack(); michael@0: appendVoidElementToCurrentMayFoster(elementName, attributes); michael@0: selfClosing = false; michael@0: pop(); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_META: { michael@0: errFooBetweenHeadAndBody(name); michael@0: checkMetaCharset(attributes); michael@0: pushHeadPointerOntoStack(); michael@0: appendVoidElementToCurrentMayFoster(elementName, attributes); michael@0: selfClosing = false; michael@0: pop(); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_SCRIPT: { michael@0: errFooBetweenHeadAndBody(name); michael@0: pushHeadPointerOntoStack(); michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: originalMode = mode; michael@0: mode = NS_HTML5TREE_BUILDER_TEXT; michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_SCRIPT_DATA, elementName); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_STYLE: michael@0: case NS_HTML5TREE_BUILDER_NOFRAMES: { michael@0: errFooBetweenHeadAndBody(name); michael@0: pushHeadPointerOntoStack(); michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: originalMode = mode; michael@0: mode = NS_HTML5TREE_BUILDER_TEXT; michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RAWTEXT, elementName); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TITLE: { michael@0: errFooBetweenHeadAndBody(name); michael@0: pushHeadPointerOntoStack(); michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: originalMode = mode; michael@0: mode = NS_HTML5TREE_BUILDER_TEXT; michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RCDATA, elementName); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_HEAD: { michael@0: errStrayStartTag(name); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: default: { michael@0: appendToCurrentNodeAndPushBodyElement(); michael@0: mode = NS_HTML5TREE_BUILDER_FRAMESET_OK; michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_AFTER_BODY: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_HTML: { michael@0: errStrayStartTag(name); michael@0: if (!fragment && !isTemplateContents()) { michael@0: addAttributesToHtml(attributes); michael@0: attributes = nullptr; michael@0: } michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: default: { michael@0: errStrayStartTag(name); michael@0: michael@0: mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY; michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_AFTER_FRAMESET: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_HTML: { michael@0: errStrayStartTag(name); michael@0: if (!fragment && !isTemplateContents()) { michael@0: addAttributesToHtml(attributes); michael@0: attributes = nullptr; michael@0: } michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_NOFRAMES: { michael@0: startTagGenericRawText(elementName, attributes); michael@0: attributes = nullptr; michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: default: { michael@0: errStrayStartTag(name); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TEXT: { michael@0: MOZ_ASSERT(false); michael@0: NS_HTML5_BREAK(starttagloop); michael@0: } michael@0: } michael@0: } michael@0: starttagloop_end: ; michael@0: if (selfClosing) { michael@0: errSelfClosing(); michael@0: } michael@0: if (!mBuilder && attributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) { michael@0: delete attributes; michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::startTagTitleInHead(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); michael@0: originalMode = mode; michael@0: mode = NS_HTML5TREE_BUILDER_TEXT; michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RCDATA, elementName); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::startTagGenericRawText(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); michael@0: originalMode = mode; michael@0: mode = NS_HTML5TREE_BUILDER_TEXT; michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RAWTEXT, elementName); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::startTagScriptInHead(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); michael@0: originalMode = mode; michael@0: mode = NS_HTML5TREE_BUILDER_TEXT; michael@0: tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_SCRIPT_DATA, elementName); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::startTagTemplateInHead(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: appendToCurrentNodeAndPushElement(elementName, attributes); michael@0: insertMarker(); michael@0: framesetOk = false; michael@0: originalMode = mode; michael@0: mode = NS_HTML5TREE_BUILDER_IN_TEMPLATE; michael@0: pushTemplateMode(NS_HTML5TREE_BUILDER_IN_TEMPLATE); michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::isTemplateContents() michael@0: { michael@0: return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK != findLast(nsHtml5Atoms::template_); michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::isTemplateModeStackEmpty() michael@0: { michael@0: return templateModePtr == -1; michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::isSpecialParentInForeign(nsHtml5StackNode* stackNode) michael@0: { michael@0: int32_t ns = stackNode->ns; michael@0: return (kNameSpaceID_XHTML == ns) || (stackNode->isHtmlIntegrationPoint()) || ((kNameSpaceID_MathML == ns) && (stackNode->getGroup() == NS_HTML5TREE_BUILDER_MI_MO_MN_MS_MTEXT)); michael@0: } michael@0: michael@0: nsString* michael@0: nsHtml5TreeBuilder::extractCharsetFromContent(nsString* attributeValue) michael@0: { michael@0: int32_t charsetState = NS_HTML5TREE_BUILDER_CHARSET_INITIAL; michael@0: int32_t start = -1; michael@0: int32_t end = -1; michael@0: autoJArray buffer = nsHtml5Portability::newCharArrayFromString(attributeValue); michael@0: for (int32_t i = 0; i < buffer.length; i++) { michael@0: char16_t c = buffer[i]; michael@0: switch(charsetState) { michael@0: case NS_HTML5TREE_BUILDER_CHARSET_INITIAL: { michael@0: switch(c) { michael@0: case 'c': michael@0: case 'C': { michael@0: charsetState = NS_HTML5TREE_BUILDER_CHARSET_C; michael@0: continue; michael@0: } michael@0: default: { michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_CHARSET_C: { michael@0: switch(c) { michael@0: case 'h': michael@0: case 'H': { michael@0: charsetState = NS_HTML5TREE_BUILDER_CHARSET_H; michael@0: continue; michael@0: } michael@0: default: { michael@0: charsetState = NS_HTML5TREE_BUILDER_CHARSET_INITIAL; michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_CHARSET_H: { michael@0: switch(c) { michael@0: case 'a': michael@0: case 'A': { michael@0: charsetState = NS_HTML5TREE_BUILDER_CHARSET_A; michael@0: continue; michael@0: } michael@0: default: { michael@0: charsetState = NS_HTML5TREE_BUILDER_CHARSET_INITIAL; michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_CHARSET_A: { michael@0: switch(c) { michael@0: case 'r': michael@0: case 'R': { michael@0: charsetState = NS_HTML5TREE_BUILDER_CHARSET_R; michael@0: continue; michael@0: } michael@0: default: { michael@0: charsetState = NS_HTML5TREE_BUILDER_CHARSET_INITIAL; michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_CHARSET_R: { michael@0: switch(c) { michael@0: case 's': michael@0: case 'S': { michael@0: charsetState = NS_HTML5TREE_BUILDER_CHARSET_S; michael@0: continue; michael@0: } michael@0: default: { michael@0: charsetState = NS_HTML5TREE_BUILDER_CHARSET_INITIAL; michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_CHARSET_S: { michael@0: switch(c) { michael@0: case 'e': michael@0: case 'E': { michael@0: charsetState = NS_HTML5TREE_BUILDER_CHARSET_E; michael@0: continue; michael@0: } michael@0: default: { michael@0: charsetState = NS_HTML5TREE_BUILDER_CHARSET_INITIAL; michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_CHARSET_E: { michael@0: switch(c) { michael@0: case 't': michael@0: case 'T': { michael@0: charsetState = NS_HTML5TREE_BUILDER_CHARSET_T; michael@0: continue; michael@0: } michael@0: default: { michael@0: charsetState = NS_HTML5TREE_BUILDER_CHARSET_INITIAL; michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_CHARSET_T: { michael@0: switch(c) { michael@0: case '\t': michael@0: case '\n': michael@0: case '\f': michael@0: case '\r': michael@0: case ' ': { michael@0: continue; michael@0: } michael@0: case '=': { michael@0: charsetState = NS_HTML5TREE_BUILDER_CHARSET_EQUALS; michael@0: continue; michael@0: } michael@0: default: { michael@0: return nullptr; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_CHARSET_EQUALS: { michael@0: switch(c) { michael@0: case '\t': michael@0: case '\n': michael@0: case '\f': michael@0: case '\r': michael@0: case ' ': { michael@0: continue; michael@0: } michael@0: case '\'': { michael@0: start = i + 1; michael@0: charsetState = NS_HTML5TREE_BUILDER_CHARSET_SINGLE_QUOTED; michael@0: continue; michael@0: } michael@0: case '\"': { michael@0: start = i + 1; michael@0: charsetState = NS_HTML5TREE_BUILDER_CHARSET_DOUBLE_QUOTED; michael@0: continue; michael@0: } michael@0: default: { michael@0: start = i; michael@0: charsetState = NS_HTML5TREE_BUILDER_CHARSET_UNQUOTED; michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_CHARSET_SINGLE_QUOTED: { michael@0: switch(c) { michael@0: case '\'': { michael@0: end = i; michael@0: NS_HTML5_BREAK(charsetloop); michael@0: } michael@0: default: { michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_CHARSET_DOUBLE_QUOTED: { michael@0: switch(c) { michael@0: case '\"': { michael@0: end = i; michael@0: NS_HTML5_BREAK(charsetloop); michael@0: } michael@0: default: { michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_CHARSET_UNQUOTED: { michael@0: switch(c) { michael@0: case '\t': michael@0: case '\n': michael@0: case '\f': michael@0: case '\r': michael@0: case ' ': michael@0: case ';': { michael@0: end = i; michael@0: NS_HTML5_BREAK(charsetloop); michael@0: } michael@0: default: { michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: charsetloop_end: ; michael@0: nsString* charset = nullptr; michael@0: if (start != -1) { michael@0: if (end == -1) { michael@0: end = buffer.length; michael@0: } michael@0: charset = nsHtml5Portability::newStringFromBuffer(buffer, start, end - start); michael@0: } michael@0: return charset; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::checkMetaCharset(nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: nsString* charset = attributes->getValue(nsHtml5AttributeName::ATTR_CHARSET); michael@0: if (charset) { michael@0: if (tokenizer->internalEncodingDeclaration(charset)) { michael@0: requestSuspension(); michael@0: return; michael@0: } michael@0: return; michael@0: } michael@0: if (!nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("content-type", attributes->getValue(nsHtml5AttributeName::ATTR_HTTP_EQUIV))) { michael@0: return; michael@0: } michael@0: nsString* content = attributes->getValue(nsHtml5AttributeName::ATTR_CONTENT); michael@0: if (content) { michael@0: nsString* extract = nsHtml5TreeBuilder::extractCharsetFromContent(content); michael@0: if (extract) { michael@0: if (tokenizer->internalEncodingDeclaration(extract)) { michael@0: requestSuspension(); michael@0: } michael@0: } michael@0: nsHtml5Portability::releaseString(extract); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName) michael@0: { michael@0: flushCharacters(); michael@0: needToDropLF = false; michael@0: int32_t eltPos; michael@0: int32_t group = elementName->getGroup(); michael@0: nsIAtom* name = elementName->name; michael@0: for (; ; ) { michael@0: if (isInForeign()) { michael@0: if (stack[currentPtr]->name != name) { michael@0: errEndTagDidNotMatchCurrentOpenElement(name, stack[currentPtr]->popName); michael@0: } michael@0: eltPos = currentPtr; michael@0: for (; ; ) { michael@0: if (stack[eltPos]->name == name) { michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: if (stack[--eltPos]->ns == kNameSpaceID_XHTML) { michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: switch(mode) { michael@0: case NS_HTML5TREE_BUILDER_IN_TEMPLATE: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_TEMPLATE: { michael@0: break; michael@0: } michael@0: default: { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_ROW: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_TR: { michael@0: eltPos = findLastOrRoot(NS_HTML5TREE_BUILDER_TR); michael@0: if (!eltPos) { michael@0: MOZ_ASSERT(fragment || isTemplateContents()); michael@0: errNoTableRowToClose(); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: clearStackBackTo(eltPos); michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE_BODY; michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TABLE: { michael@0: eltPos = findLastOrRoot(NS_HTML5TREE_BUILDER_TR); michael@0: if (!eltPos) { michael@0: MOZ_ASSERT(fragment || isTemplateContents()); michael@0: errNoTableRowToClose(); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: clearStackBackTo(eltPos); michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE_BODY; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: { michael@0: if (findLastInTableScope(name) == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: eltPos = findLastOrRoot(NS_HTML5TREE_BUILDER_TR); michael@0: if (!eltPos) { michael@0: MOZ_ASSERT(fragment || isTemplateContents()); michael@0: errNoTableRowToClose(); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: clearStackBackTo(eltPos); michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE_BODY; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BODY: michael@0: case NS_HTML5TREE_BUILDER_CAPTION: michael@0: case NS_HTML5TREE_BUILDER_COL: michael@0: case NS_HTML5TREE_BUILDER_COLGROUP: michael@0: case NS_HTML5TREE_BUILDER_HTML: michael@0: case NS_HTML5TREE_BUILDER_TD_OR_TH: { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: default: michael@0: ; // fall through michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_TABLE_BODY: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: { michael@0: eltPos = findLastOrRoot(name); michael@0: if (!eltPos) { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: clearStackBackTo(eltPos); michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE; michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TABLE: { michael@0: eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot(); michael@0: if (!eltPos || stack[eltPos]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE) { michael@0: MOZ_ASSERT(fragment || isTemplateContents()); michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: clearStackBackTo(eltPos); michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BODY: michael@0: case NS_HTML5TREE_BUILDER_CAPTION: michael@0: case NS_HTML5TREE_BUILDER_COL: michael@0: case NS_HTML5TREE_BUILDER_COLGROUP: michael@0: case NS_HTML5TREE_BUILDER_HTML: michael@0: case NS_HTML5TREE_BUILDER_TD_OR_TH: michael@0: case NS_HTML5TREE_BUILDER_TR: { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: default: michael@0: ; // fall through michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_TABLE: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_TABLE: { michael@0: eltPos = findLast(nsHtml5Atoms::table); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: MOZ_ASSERT(fragment || isTemplateContents()); michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: resetTheInsertionMode(); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BODY: michael@0: case NS_HTML5TREE_BUILDER_CAPTION: michael@0: case NS_HTML5TREE_BUILDER_COL: michael@0: case NS_HTML5TREE_BUILDER_COLGROUP: michael@0: case NS_HTML5TREE_BUILDER_HTML: michael@0: case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: michael@0: case NS_HTML5TREE_BUILDER_TD_OR_TH: michael@0: case NS_HTML5TREE_BUILDER_TR: { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TEMPLATE: { michael@0: break; michael@0: } michael@0: default: { michael@0: errStrayEndTag(name); michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_CAPTION: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_CAPTION: { michael@0: eltPos = findLastInTableScope(nsHtml5Atoms::caption); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: generateImpliedEndTags(); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) { michael@0: errUnclosedElements(eltPos, name); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: clearTheListOfActiveFormattingElementsUpToTheLastMarker(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE; michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TABLE: { michael@0: errTableClosedWhileCaptionOpen(); michael@0: eltPos = findLastInTableScope(nsHtml5Atoms::caption); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: generateImpliedEndTags(); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && currentPtr != eltPos) { michael@0: errUnclosedElements(eltPos, name); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: clearTheListOfActiveFormattingElementsUpToTheLastMarker(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BODY: michael@0: case NS_HTML5TREE_BUILDER_COL: michael@0: case NS_HTML5TREE_BUILDER_COLGROUP: michael@0: case NS_HTML5TREE_BUILDER_HTML: michael@0: case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: michael@0: case NS_HTML5TREE_BUILDER_TD_OR_TH: michael@0: case NS_HTML5TREE_BUILDER_TR: { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: default: michael@0: ; // fall through michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_CELL: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_TD_OR_TH: { michael@0: eltPos = findLastInTableScope(name); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: generateImpliedEndTags(); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) { michael@0: errUnclosedElements(eltPos, name); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: clearTheListOfActiveFormattingElementsUpToTheLastMarker(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_ROW; michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TABLE: michael@0: case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: michael@0: case NS_HTML5TREE_BUILDER_TR: { michael@0: if (findLastInTableScope(name) == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: MOZ_ASSERT(name == nsHtml5Atoms::tbody || name == nsHtml5Atoms::tfoot || name == nsHtml5Atoms::thead || fragment || isTemplateContents()); michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: closeTheCell(findLastInTableScopeTdTh()); michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BODY: michael@0: case NS_HTML5TREE_BUILDER_CAPTION: michael@0: case NS_HTML5TREE_BUILDER_COL: michael@0: case NS_HTML5TREE_BUILDER_COLGROUP: michael@0: case NS_HTML5TREE_BUILDER_HTML: { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: default: michael@0: ; // fall through michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_FRAMESET_OK: michael@0: case NS_HTML5TREE_BUILDER_IN_BODY: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_BODY: { michael@0: if (!isSecondOnStackBody()) { michael@0: MOZ_ASSERT(fragment || isTemplateContents()); michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: MOZ_ASSERT(currentPtr >= 1); michael@0: if (MOZ_UNLIKELY(mViewSource)) { michael@0: for (int32_t i = 2; i <= currentPtr; i++) { michael@0: switch(stack[i]->getGroup()) { michael@0: case NS_HTML5TREE_BUILDER_DD_OR_DT: michael@0: case NS_HTML5TREE_BUILDER_LI: michael@0: case NS_HTML5TREE_BUILDER_OPTGROUP: michael@0: case NS_HTML5TREE_BUILDER_OPTION: michael@0: case NS_HTML5TREE_BUILDER_P: michael@0: case NS_HTML5TREE_BUILDER_RT_OR_RP: michael@0: case NS_HTML5TREE_BUILDER_TD_OR_TH: michael@0: case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: { michael@0: break; michael@0: } michael@0: default: { michael@0: errEndWithUnclosedElements(name); michael@0: NS_HTML5_BREAK(uncloseloop1); michael@0: } michael@0: } michael@0: } michael@0: uncloseloop1_end: ; michael@0: } michael@0: mode = NS_HTML5TREE_BUILDER_AFTER_BODY; michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_HTML: { michael@0: if (!isSecondOnStackBody()) { michael@0: MOZ_ASSERT(fragment || isTemplateContents()); michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: if (MOZ_UNLIKELY(mViewSource)) { michael@0: for (int32_t i = 0; i <= currentPtr; i++) { michael@0: switch(stack[i]->getGroup()) { michael@0: case NS_HTML5TREE_BUILDER_DD_OR_DT: michael@0: case NS_HTML5TREE_BUILDER_LI: michael@0: case NS_HTML5TREE_BUILDER_P: michael@0: case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: michael@0: case NS_HTML5TREE_BUILDER_TD_OR_TH: michael@0: case NS_HTML5TREE_BUILDER_BODY: michael@0: case NS_HTML5TREE_BUILDER_HTML: { michael@0: break; michael@0: } michael@0: default: { michael@0: errEndWithUnclosedElements(name); michael@0: NS_HTML5_BREAK(uncloseloop2); michael@0: } michael@0: } michael@0: } michael@0: uncloseloop2_end: ; michael@0: } michael@0: mode = NS_HTML5TREE_BUILDER_AFTER_BODY; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU: michael@0: case NS_HTML5TREE_BUILDER_UL_OR_OL_OR_DL: michael@0: case NS_HTML5TREE_BUILDER_PRE_OR_LISTING: michael@0: case NS_HTML5TREE_BUILDER_FIELDSET: michael@0: case NS_HTML5TREE_BUILDER_BUTTON: michael@0: case NS_HTML5TREE_BUILDER_ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SECTION_OR_SUMMARY: { michael@0: eltPos = findLastInScope(name); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: errStrayEndTag(name); michael@0: } else { michael@0: generateImpliedEndTags(); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) { michael@0: errUnclosedElements(eltPos, name); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: } michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_FORM: { michael@0: if (!isTemplateContents()) { michael@0: if (!formPointer) { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: formPointer = nullptr; michael@0: eltPos = findLastInScope(name); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: generateImpliedEndTags(); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) { michael@0: errUnclosedElements(eltPos, name); michael@0: } michael@0: removeFromStack(eltPos); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } else { michael@0: eltPos = findLastInScope(name); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: generateImpliedEndTags(); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) { michael@0: errUnclosedElements(eltPos, name); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_P: { michael@0: eltPos = findLastInButtonScope(nsHtml5Atoms::p); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: errNoElementToCloseButEndTagSeen(nsHtml5Atoms::p); michael@0: if (isInForeign()) { michael@0: errHtmlStartTagInForeignContext(name); michael@0: while (stack[currentPtr]->ns != kNameSpaceID_XHTML) { michael@0: pop(); michael@0: } michael@0: } michael@0: appendVoidElementToCurrentMayFoster(elementName, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: generateImpliedEndTagsExceptFor(nsHtml5Atoms::p); michael@0: MOZ_ASSERT(eltPos != NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) { michael@0: errUnclosedElements(eltPos, name); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_LI: { michael@0: eltPos = findLastInListScope(name); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: errNoElementToCloseButEndTagSeen(name); michael@0: } else { michael@0: generateImpliedEndTagsExceptFor(name); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) { michael@0: errUnclosedElements(eltPos, name); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: } michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_DD_OR_DT: { michael@0: eltPos = findLastInScope(name); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: errNoElementToCloseButEndTagSeen(name); michael@0: } else { michael@0: generateImpliedEndTagsExceptFor(name); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) { michael@0: errUnclosedElements(eltPos, name); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: } michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: { michael@0: eltPos = findLastInScopeHn(); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: errStrayEndTag(name); michael@0: } else { michael@0: generateImpliedEndTags(); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) { michael@0: errUnclosedElements(eltPos, name); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: } michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_OBJECT: michael@0: case NS_HTML5TREE_BUILDER_MARQUEE_OR_APPLET: { michael@0: eltPos = findLastInScope(name); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: errStrayEndTag(name); michael@0: } else { michael@0: generateImpliedEndTags(); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) { michael@0: errUnclosedElements(eltPos, name); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: clearTheListOfActiveFormattingElementsUpToTheLastMarker(); michael@0: } michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BR: { michael@0: errEndTagBr(); michael@0: if (isInForeign()) { michael@0: errHtmlStartTagInForeignContext(name); michael@0: while (stack[currentPtr]->ns != kNameSpaceID_XHTML) { michael@0: pop(); michael@0: } michael@0: } michael@0: reconstructTheActiveFormattingElements(); michael@0: appendVoidElementToCurrentMayFoster(elementName, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TEMPLATE: { michael@0: break; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AREA_OR_WBR: michael@0: #ifdef ENABLE_VOID_MENUITEM michael@0: case NS_HTML5TREE_BUILDER_MENUITEM: michael@0: #endif michael@0: case NS_HTML5TREE_BUILDER_PARAM_OR_SOURCE_OR_TRACK: michael@0: case NS_HTML5TREE_BUILDER_EMBED: michael@0: case NS_HTML5TREE_BUILDER_IMG: michael@0: case NS_HTML5TREE_BUILDER_IMAGE: michael@0: case NS_HTML5TREE_BUILDER_INPUT: michael@0: case NS_HTML5TREE_BUILDER_KEYGEN: michael@0: case NS_HTML5TREE_BUILDER_HR: michael@0: case NS_HTML5TREE_BUILDER_ISINDEX: michael@0: case NS_HTML5TREE_BUILDER_IFRAME: michael@0: case NS_HTML5TREE_BUILDER_NOEMBED: michael@0: case NS_HTML5TREE_BUILDER_NOFRAMES: michael@0: case NS_HTML5TREE_BUILDER_SELECT: michael@0: case NS_HTML5TREE_BUILDER_TABLE: michael@0: case NS_HTML5TREE_BUILDER_TEXTAREA: { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_NOSCRIPT: { michael@0: if (scriptingEnabled) { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } else { michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_A: michael@0: case NS_HTML5TREE_BUILDER_B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U: michael@0: case NS_HTML5TREE_BUILDER_FONT: michael@0: case NS_HTML5TREE_BUILDER_NOBR: { michael@0: if (adoptionAgencyEndTag(name)) { michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: } michael@0: default: { michael@0: if (isCurrent(name)) { michael@0: pop(); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: eltPos = currentPtr; michael@0: for (; ; ) { michael@0: nsHtml5StackNode* node = stack[eltPos]; michael@0: if (node->ns == kNameSpaceID_XHTML && node->name == name) { michael@0: generateImpliedEndTags(); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(name)) { michael@0: errUnclosedElements(eltPos, name); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } else if (node->isSpecial()) { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: eltPos--; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_HEAD: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_HEAD: { michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_AFTER_HEAD; michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BR: michael@0: case NS_HTML5TREE_BUILDER_HTML: michael@0: case NS_HTML5TREE_BUILDER_BODY: { michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_AFTER_HEAD; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TEMPLATE: { michael@0: endTagTemplateInHead(); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: default: { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_HEAD_NOSCRIPT: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_NOSCRIPT: { michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_HEAD; michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BR: { michael@0: errStrayEndTag(name); michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_HEAD; michael@0: continue; michael@0: } michael@0: default: { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_COLGROUP: { michael@0: if (!currentPtr || stack[currentPtr]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE) { michael@0: MOZ_ASSERT(fragment || isTemplateContents()); michael@0: errGarbageInColgroup(); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE; michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_COL: { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TEMPLATE: { michael@0: endTagTemplateInHead(); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: default: { michael@0: if (!currentPtr || stack[currentPtr]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE) { michael@0: MOZ_ASSERT(fragment || isTemplateContents()); michael@0: errGarbageInColgroup(); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: pop(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE; michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_SELECT_IN_TABLE: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_CAPTION: michael@0: case NS_HTML5TREE_BUILDER_TABLE: michael@0: case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: michael@0: case NS_HTML5TREE_BUILDER_TR: michael@0: case NS_HTML5TREE_BUILDER_TD_OR_TH: { michael@0: errEndTagSeenWithSelectOpen(name); michael@0: if (findLastInTableScope(name) != NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: eltPos = findLastInTableScope(nsHtml5Atoms::select); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: MOZ_ASSERT(fragment); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: resetTheInsertionMode(); michael@0: continue; michael@0: } else { michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: } michael@0: default: michael@0: ; // fall through michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_SELECT: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_OPTION: { michael@0: if (isCurrent(nsHtml5Atoms::option)) { michael@0: pop(); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } else { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_OPTGROUP: { michael@0: if (isCurrent(nsHtml5Atoms::option) && nsHtml5Atoms::optgroup == stack[currentPtr - 1]->name) { michael@0: pop(); michael@0: } michael@0: if (isCurrent(nsHtml5Atoms::optgroup)) { michael@0: pop(); michael@0: } else { michael@0: errStrayEndTag(name); michael@0: } michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_SELECT: { michael@0: eltPos = findLastInTableScope(nsHtml5Atoms::select); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: MOZ_ASSERT(fragment); michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: resetTheInsertionMode(); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TEMPLATE: { michael@0: endTagTemplateInHead(); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: default: { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_BODY: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_HTML: { michael@0: if (fragment) { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } else { michael@0: mode = NS_HTML5TREE_BUILDER_AFTER_AFTER_BODY; michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: } michael@0: default: { michael@0: errEndTagAfterBody(); michael@0: mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY; michael@0: continue; michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_IN_FRAMESET: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_FRAMESET: { michael@0: if (!currentPtr) { michael@0: MOZ_ASSERT(fragment); michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: pop(); michael@0: if ((!fragment) && !isCurrent(nsHtml5Atoms::frameset)) { michael@0: mode = NS_HTML5TREE_BUILDER_AFTER_FRAMESET; michael@0: } michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: default: { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_FRAMESET: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_HTML: { michael@0: mode = NS_HTML5TREE_BUILDER_AFTER_AFTER_FRAMESET; michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: default: { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_INITIAL: { michael@0: errEndTagSeenWithoutDoctype(); michael@0: documentModeInternal(QUIRKS_MODE, nullptr, nullptr, false); michael@0: mode = NS_HTML5TREE_BUILDER_BEFORE_HTML; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BEFORE_HTML: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_HEAD: michael@0: case NS_HTML5TREE_BUILDER_BR: michael@0: case NS_HTML5TREE_BUILDER_HTML: michael@0: case NS_HTML5TREE_BUILDER_BODY: { michael@0: appendHtmlElementToDocumentAndPush(); michael@0: mode = NS_HTML5TREE_BUILDER_BEFORE_HEAD; michael@0: continue; michael@0: } michael@0: default: { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_BEFORE_HEAD: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_HEAD: michael@0: case NS_HTML5TREE_BUILDER_BR: michael@0: case NS_HTML5TREE_BUILDER_HTML: michael@0: case NS_HTML5TREE_BUILDER_BODY: { michael@0: appendToCurrentNodeAndPushHeadElement(nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES); michael@0: mode = NS_HTML5TREE_BUILDER_IN_HEAD; michael@0: continue; michael@0: } michael@0: default: { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_HEAD: { michael@0: switch(group) { michael@0: case NS_HTML5TREE_BUILDER_TEMPLATE: { michael@0: endTagTemplateInHead(); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_HTML: michael@0: case NS_HTML5TREE_BUILDER_BODY: michael@0: case NS_HTML5TREE_BUILDER_BR: { michael@0: appendToCurrentNodeAndPushBodyElement(); michael@0: mode = NS_HTML5TREE_BUILDER_FRAMESET_OK; michael@0: continue; michael@0: } michael@0: default: { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: } michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_AFTER_BODY: { michael@0: errStrayEndTag(name); michael@0: mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY; michael@0: continue; michael@0: } michael@0: case NS_HTML5TREE_BUILDER_AFTER_AFTER_FRAMESET: { michael@0: errStrayEndTag(name); michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: case NS_HTML5TREE_BUILDER_TEXT: { michael@0: pop(); michael@0: if (originalMode == NS_HTML5TREE_BUILDER_AFTER_HEAD) { michael@0: silentPop(); michael@0: } michael@0: mode = originalMode; michael@0: NS_HTML5_BREAK(endtagloop); michael@0: } michael@0: } michael@0: } michael@0: endtagloop_end: ; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::endTagTemplateInHead() michael@0: { michael@0: int32_t eltPos = findLast(nsHtml5Atoms::template_); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: errStrayEndTag(nsHtml5Atoms::template_); michael@0: return; michael@0: } michael@0: generateImpliedEndTags(); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && !isCurrent(nsHtml5Atoms::template_)) { michael@0: errUnclosedElements(eltPos, nsHtml5Atoms::template_); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: clearTheListOfActiveFormattingElementsUpToTheLastMarker(); michael@0: popTemplateMode(); michael@0: resetTheInsertionMode(); michael@0: } michael@0: michael@0: int32_t michael@0: nsHtml5TreeBuilder::findLastInTableScopeOrRootTemplateTbodyTheadTfoot() michael@0: { michael@0: for (int32_t i = currentPtr; i > 0; i--) { michael@0: if (stack[i]->getGroup() == NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT || stack[i]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE) { michael@0: return i; michael@0: } michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: int32_t michael@0: nsHtml5TreeBuilder::findLast(nsIAtom* name) michael@0: { michael@0: for (int32_t i = currentPtr; i > 0; i--) { michael@0: if (stack[i]->ns == kNameSpaceID_XHTML && stack[i]->name == name) { michael@0: return i; michael@0: } michael@0: } michael@0: return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK; michael@0: } michael@0: michael@0: int32_t michael@0: nsHtml5TreeBuilder::findLastInTableScope(nsIAtom* name) michael@0: { michael@0: for (int32_t i = currentPtr; i > 0; i--) { michael@0: if (stack[i]->ns == kNameSpaceID_XHTML) { michael@0: if (stack[i]->name == name) { michael@0: return i; michael@0: } else if (stack[i]->name == nsHtml5Atoms::table || stack[i]->name == nsHtml5Atoms::template_) { michael@0: return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK; michael@0: } michael@0: } michael@0: } michael@0: return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK; michael@0: } michael@0: michael@0: int32_t michael@0: nsHtml5TreeBuilder::findLastInButtonScope(nsIAtom* name) michael@0: { michael@0: for (int32_t i = currentPtr; i > 0; i--) { michael@0: if (stack[i]->ns == kNameSpaceID_XHTML) { michael@0: if (stack[i]->name == name) { michael@0: return i; michael@0: } else if (stack[i]->name == nsHtml5Atoms::button) { michael@0: return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK; michael@0: } michael@0: } michael@0: if (stack[i]->isScoping()) { michael@0: return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK; michael@0: } michael@0: } michael@0: return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK; michael@0: } michael@0: michael@0: int32_t michael@0: nsHtml5TreeBuilder::findLastInScope(nsIAtom* name) michael@0: { michael@0: for (int32_t i = currentPtr; i > 0; i--) { michael@0: if (stack[i]->ns == kNameSpaceID_XHTML && stack[i]->name == name) { michael@0: return i; michael@0: } else if (stack[i]->isScoping()) { michael@0: return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK; michael@0: } michael@0: } michael@0: return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK; michael@0: } michael@0: michael@0: int32_t michael@0: nsHtml5TreeBuilder::findLastInListScope(nsIAtom* name) michael@0: { michael@0: for (int32_t i = currentPtr; i > 0; i--) { michael@0: if (stack[i]->ns == kNameSpaceID_XHTML) { michael@0: if (stack[i]->name == name) { michael@0: return i; michael@0: } else if (stack[i]->name == nsHtml5Atoms::ul || stack[i]->name == nsHtml5Atoms::ol) { michael@0: return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK; michael@0: } michael@0: } michael@0: if (stack[i]->isScoping()) { michael@0: return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK; michael@0: } michael@0: } michael@0: return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK; michael@0: } michael@0: michael@0: int32_t michael@0: nsHtml5TreeBuilder::findLastInScopeHn() michael@0: { michael@0: for (int32_t i = currentPtr; i > 0; i--) { michael@0: if (stack[i]->getGroup() == NS_HTML5TREE_BUILDER_H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) { michael@0: return i; michael@0: } else if (stack[i]->isScoping()) { michael@0: return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK; michael@0: } michael@0: } michael@0: return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::generateImpliedEndTagsExceptFor(nsIAtom* name) michael@0: { michael@0: for (; ; ) { michael@0: nsHtml5StackNode* node = stack[currentPtr]; michael@0: switch(node->getGroup()) { michael@0: case NS_HTML5TREE_BUILDER_P: michael@0: case NS_HTML5TREE_BUILDER_LI: michael@0: case NS_HTML5TREE_BUILDER_DD_OR_DT: michael@0: case NS_HTML5TREE_BUILDER_OPTION: michael@0: case NS_HTML5TREE_BUILDER_OPTGROUP: michael@0: case NS_HTML5TREE_BUILDER_RT_OR_RP: { michael@0: if (node->ns == kNameSpaceID_XHTML && node->name == name) { michael@0: return; michael@0: } michael@0: pop(); michael@0: continue; michael@0: } michael@0: default: { michael@0: return; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::generateImpliedEndTags() michael@0: { michael@0: for (; ; ) { michael@0: switch(stack[currentPtr]->getGroup()) { michael@0: case NS_HTML5TREE_BUILDER_P: michael@0: case NS_HTML5TREE_BUILDER_LI: michael@0: case NS_HTML5TREE_BUILDER_DD_OR_DT: michael@0: case NS_HTML5TREE_BUILDER_OPTION: michael@0: case NS_HTML5TREE_BUILDER_OPTGROUP: michael@0: case NS_HTML5TREE_BUILDER_RT_OR_RP: { michael@0: pop(); michael@0: continue; michael@0: } michael@0: default: { michael@0: return; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::isSecondOnStackBody() michael@0: { michael@0: return currentPtr >= 1 && stack[1]->getGroup() == NS_HTML5TREE_BUILDER_BODY; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::documentModeInternal(nsHtml5DocumentMode m, nsString* publicIdentifier, nsString* systemIdentifier, bool html4SpecificAdditionalErrorChecks) michael@0: { michael@0: if (isSrcdocDocument) { michael@0: quirks = false; michael@0: if (this) { michael@0: this->documentMode(STANDARDS_MODE); michael@0: } michael@0: return; michael@0: } michael@0: quirks = (m == QUIRKS_MODE); michael@0: if (this) { michael@0: this->documentMode(m); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::isAlmostStandards(nsString* publicIdentifier, nsString* systemIdentifier) michael@0: { michael@0: if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("-//w3c//dtd xhtml 1.0 transitional//en", publicIdentifier)) { michael@0: return true; michael@0: } michael@0: if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("-//w3c//dtd xhtml 1.0 frameset//en", publicIdentifier)) { michael@0: return true; michael@0: } michael@0: if (systemIdentifier) { michael@0: if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("-//w3c//dtd html 4.01 transitional//en", publicIdentifier)) { michael@0: return true; michael@0: } michael@0: if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("-//w3c//dtd html 4.01 frameset//en", publicIdentifier)) { michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::isQuirky(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier, bool forceQuirks) michael@0: { michael@0: if (forceQuirks) { michael@0: return true; michael@0: } michael@0: if (name != nsHtml5Atoms::html) { michael@0: return true; michael@0: } michael@0: if (publicIdentifier) { michael@0: for (int32_t i = 0; i < nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS.length; i++) { michael@0: if (nsHtml5Portability::lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS[i], publicIdentifier)) { michael@0: return true; michael@0: } michael@0: } michael@0: 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)) { michael@0: return true; michael@0: } michael@0: } michael@0: if (!systemIdentifier) { michael@0: if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("-//w3c//dtd html 4.01 transitional//en", publicIdentifier)) { michael@0: return true; michael@0: } else if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("-//w3c//dtd html 4.01 frameset//en", publicIdentifier)) { michael@0: return true; michael@0: } michael@0: } else if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd", systemIdentifier)) { michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::closeTheCell(int32_t eltPos) michael@0: { michael@0: generateImpliedEndTags(); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) { michael@0: errUnclosedElementsCell(eltPos); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: clearTheListOfActiveFormattingElementsUpToTheLastMarker(); michael@0: mode = NS_HTML5TREE_BUILDER_IN_ROW; michael@0: return; michael@0: } michael@0: michael@0: int32_t michael@0: nsHtml5TreeBuilder::findLastInTableScopeTdTh() michael@0: { michael@0: for (int32_t i = currentPtr; i > 0; i--) { michael@0: nsIAtom* name = stack[i]->name; michael@0: if (stack[i]->ns == kNameSpaceID_XHTML) { michael@0: if (nsHtml5Atoms::td == name || nsHtml5Atoms::th == name) { michael@0: return i; michael@0: } else if (name == nsHtml5Atoms::table || name == nsHtml5Atoms::template_) { michael@0: return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK; michael@0: } michael@0: } michael@0: } michael@0: return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::clearStackBackTo(int32_t eltPos) michael@0: { michael@0: int32_t eltGroup = stack[eltPos]->getGroup(); michael@0: while (currentPtr > eltPos) { michael@0: if (stack[currentPtr]->ns == kNameSpaceID_XHTML && stack[currentPtr]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE && (eltGroup == NS_HTML5TREE_BUILDER_TABLE || eltGroup == NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT || eltGroup == NS_HTML5TREE_BUILDER_TR || eltGroup == NS_HTML5TREE_BUILDER_HTML)) { michael@0: return; michael@0: } michael@0: pop(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::resetTheInsertionMode() michael@0: { michael@0: nsHtml5StackNode* node; michael@0: nsIAtom* name; michael@0: int32_t ns; michael@0: for (int32_t i = currentPtr; i >= 0; i--) { michael@0: node = stack[i]; michael@0: name = node->name; michael@0: ns = node->ns; michael@0: if (!i) { michael@0: if (!(contextNamespace == kNameSpaceID_XHTML && (contextName == nsHtml5Atoms::td || contextName == nsHtml5Atoms::th))) { michael@0: if (fragment) { michael@0: name = contextName; michael@0: ns = contextNamespace; michael@0: } michael@0: } else { michael@0: mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY; michael@0: return; michael@0: } michael@0: } michael@0: if (nsHtml5Atoms::select == name) { michael@0: int32_t ancestorIndex = i; michael@0: while (ancestorIndex > 0) { michael@0: nsHtml5StackNode* ancestor = stack[ancestorIndex--]; michael@0: if (kNameSpaceID_XHTML == ancestor->ns) { michael@0: if (nsHtml5Atoms::template_ == ancestor->name) { michael@0: break; michael@0: } michael@0: if (nsHtml5Atoms::table == ancestor->name) { michael@0: mode = NS_HTML5TREE_BUILDER_IN_SELECT_IN_TABLE; michael@0: return; michael@0: } michael@0: } michael@0: } michael@0: mode = NS_HTML5TREE_BUILDER_IN_SELECT; michael@0: return; michael@0: } else if (nsHtml5Atoms::td == name || nsHtml5Atoms::th == name) { michael@0: mode = NS_HTML5TREE_BUILDER_IN_CELL; michael@0: return; michael@0: } else if (nsHtml5Atoms::tr == name) { michael@0: mode = NS_HTML5TREE_BUILDER_IN_ROW; michael@0: return; michael@0: } else if (nsHtml5Atoms::tbody == name || nsHtml5Atoms::thead == name || nsHtml5Atoms::tfoot == name) { michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE_BODY; michael@0: return; michael@0: } else if (nsHtml5Atoms::caption == name) { michael@0: mode = NS_HTML5TREE_BUILDER_IN_CAPTION; michael@0: return; michael@0: } else if (nsHtml5Atoms::colgroup == name) { michael@0: mode = NS_HTML5TREE_BUILDER_IN_COLUMN_GROUP; michael@0: return; michael@0: } else if (nsHtml5Atoms::table == name) { michael@0: mode = NS_HTML5TREE_BUILDER_IN_TABLE; michael@0: return; michael@0: } else if (kNameSpaceID_XHTML != ns) { michael@0: mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY; michael@0: return; michael@0: } else if (nsHtml5Atoms::template_ == name) { michael@0: MOZ_ASSERT(templateModePtr >= 0); michael@0: mode = templateModeStack[templateModePtr]; michael@0: return; michael@0: } else if (nsHtml5Atoms::head == name) { michael@0: if (name == contextName) { michael@0: mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY; michael@0: } else { michael@0: mode = NS_HTML5TREE_BUILDER_IN_HEAD; michael@0: } michael@0: return; michael@0: } else if (nsHtml5Atoms::body == name) { michael@0: mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY; michael@0: return; michael@0: } else if (nsHtml5Atoms::frameset == name) { michael@0: mode = NS_HTML5TREE_BUILDER_IN_FRAMESET; michael@0: return; michael@0: } else if (nsHtml5Atoms::html == name) { michael@0: if (!headPointer) { michael@0: mode = NS_HTML5TREE_BUILDER_BEFORE_HEAD; michael@0: } else { michael@0: mode = NS_HTML5TREE_BUILDER_AFTER_HEAD; michael@0: } michael@0: return; michael@0: } else if (!i) { michael@0: mode = framesetOk ? NS_HTML5TREE_BUILDER_FRAMESET_OK : NS_HTML5TREE_BUILDER_IN_BODY; michael@0: return; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::implicitlyCloseP() michael@0: { michael@0: int32_t eltPos = findLastInButtonScope(nsHtml5Atoms::p); michael@0: if (eltPos == NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { michael@0: return; michael@0: } michael@0: generateImpliedEndTagsExceptFor(nsHtml5Atoms::p); michael@0: if (!!MOZ_UNLIKELY(mViewSource) && eltPos != currentPtr) { michael@0: errUnclosedElementsImplied(eltPos, nsHtml5Atoms::p); michael@0: } michael@0: while (currentPtr >= eltPos) { michael@0: pop(); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::debugOnlyClearLastStackSlot() michael@0: { michael@0: stack[currentPtr] = nullptr; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::debugOnlyClearLastListSlot() michael@0: { michael@0: listOfActiveFormattingElements[listPtr] = nullptr; michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::pushTemplateMode(int32_t mode) michael@0: { michael@0: templateModePtr++; michael@0: if (templateModePtr == templateModeStack.length) { michael@0: jArray newStack = jArray::newJArray(templateModeStack.length + 64); michael@0: nsHtml5ArrayCopy::arraycopy(templateModeStack, newStack, templateModeStack.length); michael@0: templateModeStack = newStack; michael@0: } michael@0: templateModeStack[templateModePtr] = mode; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::push(nsHtml5StackNode* node) michael@0: { michael@0: currentPtr++; michael@0: if (currentPtr == stack.length) { michael@0: jArray newStack = jArray::newJArray(stack.length + 64); michael@0: nsHtml5ArrayCopy::arraycopy(stack, newStack, stack.length); michael@0: stack = newStack; michael@0: } michael@0: stack[currentPtr] = node; michael@0: elementPushed(node->ns, node->popName, node->node); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::silentPush(nsHtml5StackNode* node) michael@0: { michael@0: currentPtr++; michael@0: if (currentPtr == stack.length) { michael@0: jArray newStack = jArray::newJArray(stack.length + 64); michael@0: nsHtml5ArrayCopy::arraycopy(stack, newStack, stack.length); michael@0: stack = newStack; michael@0: } michael@0: stack[currentPtr] = node; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::append(nsHtml5StackNode* node) michael@0: { michael@0: listPtr++; michael@0: if (listPtr == listOfActiveFormattingElements.length) { michael@0: jArray newList = jArray::newJArray(listOfActiveFormattingElements.length + 64); michael@0: nsHtml5ArrayCopy::arraycopy(listOfActiveFormattingElements, newList, listOfActiveFormattingElements.length); michael@0: listOfActiveFormattingElements = newList; michael@0: } michael@0: listOfActiveFormattingElements[listPtr] = node; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::clearTheListOfActiveFormattingElementsUpToTheLastMarker() michael@0: { michael@0: while (listPtr > -1) { michael@0: if (!listOfActiveFormattingElements[listPtr]) { michael@0: --listPtr; michael@0: return; michael@0: } michael@0: listOfActiveFormattingElements[listPtr]->release(); michael@0: --listPtr; michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::removeFromStack(int32_t pos) michael@0: { michael@0: if (currentPtr == pos) { michael@0: pop(); michael@0: } else { michael@0: michael@0: stack[pos]->release(); michael@0: nsHtml5ArrayCopy::arraycopy(stack, pos + 1, pos, currentPtr - pos); michael@0: MOZ_ASSERT(debugOnlyClearLastStackSlot()); michael@0: currentPtr--; michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::removeFromStack(nsHtml5StackNode* node) michael@0: { michael@0: if (stack[currentPtr] == node) { michael@0: pop(); michael@0: } else { michael@0: int32_t pos = currentPtr - 1; michael@0: while (pos >= 0 && stack[pos] != node) { michael@0: pos--; michael@0: } michael@0: if (pos == -1) { michael@0: return; michael@0: } michael@0: michael@0: node->release(); michael@0: nsHtml5ArrayCopy::arraycopy(stack, pos + 1, pos, currentPtr - pos); michael@0: currentPtr--; michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::removeFromListOfActiveFormattingElements(int32_t pos) michael@0: { michael@0: MOZ_ASSERT(!!listOfActiveFormattingElements[pos]); michael@0: listOfActiveFormattingElements[pos]->release(); michael@0: if (pos == listPtr) { michael@0: MOZ_ASSERT(debugOnlyClearLastListSlot()); michael@0: listPtr--; michael@0: return; michael@0: } michael@0: MOZ_ASSERT(pos < listPtr); michael@0: nsHtml5ArrayCopy::arraycopy(listOfActiveFormattingElements, pos + 1, pos, listPtr - pos); michael@0: MOZ_ASSERT(debugOnlyClearLastListSlot()); michael@0: listPtr--; michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::adoptionAgencyEndTag(nsIAtom* name) michael@0: { michael@0: if (stack[currentPtr]->ns == kNameSpaceID_XHTML && stack[currentPtr]->name == name && findInListOfActiveFormattingElements(stack[currentPtr]) == -1) { michael@0: pop(); michael@0: return true; michael@0: } michael@0: for (int32_t i = 0; i < 8; ++i) { michael@0: int32_t formattingEltListPos = listPtr; michael@0: while (formattingEltListPos > -1) { michael@0: nsHtml5StackNode* listNode = listOfActiveFormattingElements[formattingEltListPos]; michael@0: if (!listNode) { michael@0: formattingEltListPos = -1; michael@0: break; michael@0: } else if (listNode->name == name) { michael@0: break; michael@0: } michael@0: formattingEltListPos--; michael@0: } michael@0: if (formattingEltListPos == -1) { michael@0: return false; michael@0: } michael@0: nsHtml5StackNode* formattingElt = listOfActiveFormattingElements[formattingEltListPos]; michael@0: int32_t formattingEltStackPos = currentPtr; michael@0: bool inScope = true; michael@0: while (formattingEltStackPos > -1) { michael@0: nsHtml5StackNode* node = stack[formattingEltStackPos]; michael@0: if (node == formattingElt) { michael@0: break; michael@0: } else if (node->isScoping()) { michael@0: inScope = false; michael@0: } michael@0: formattingEltStackPos--; michael@0: } michael@0: if (formattingEltStackPos == -1) { michael@0: errNoElementToCloseButEndTagSeen(name); michael@0: removeFromListOfActiveFormattingElements(formattingEltListPos); michael@0: return true; michael@0: } michael@0: if (!inScope) { michael@0: errNoElementToCloseButEndTagSeen(name); michael@0: return true; michael@0: } michael@0: if (formattingEltStackPos != currentPtr) { michael@0: errEndTagViolatesNestingRules(name); michael@0: } michael@0: int32_t furthestBlockPos = formattingEltStackPos + 1; michael@0: while (furthestBlockPos <= currentPtr) { michael@0: nsHtml5StackNode* node = stack[furthestBlockPos]; michael@0: if (node->isSpecial()) { michael@0: break; michael@0: } michael@0: furthestBlockPos++; michael@0: } michael@0: if (furthestBlockPos > currentPtr) { michael@0: while (currentPtr >= formattingEltStackPos) { michael@0: pop(); michael@0: } michael@0: removeFromListOfActiveFormattingElements(formattingEltListPos); michael@0: return true; michael@0: } michael@0: nsHtml5StackNode* commonAncestor = stack[formattingEltStackPos - 1]; michael@0: nsHtml5StackNode* furthestBlock = stack[furthestBlockPos]; michael@0: int32_t bookmark = formattingEltListPos; michael@0: int32_t nodePos = furthestBlockPos; michael@0: nsHtml5StackNode* lastNode = furthestBlock; michael@0: int32_t j = 0; michael@0: for (; ; ) { michael@0: ++j; michael@0: nodePos--; michael@0: if (nodePos == formattingEltStackPos) { michael@0: break; michael@0: } michael@0: nsHtml5StackNode* node = stack[nodePos]; michael@0: int32_t nodeListPos = findInListOfActiveFormattingElements(node); michael@0: if (j > 3 && nodeListPos != -1) { michael@0: removeFromListOfActiveFormattingElements(nodeListPos); michael@0: if (nodeListPos <= formattingEltListPos) { michael@0: formattingEltListPos--; michael@0: } michael@0: if (nodeListPos <= bookmark) { michael@0: bookmark--; michael@0: } michael@0: nodeListPos = -1; michael@0: } michael@0: if (nodeListPos == -1) { michael@0: MOZ_ASSERT(formattingEltStackPos < nodePos); michael@0: MOZ_ASSERT(bookmark < nodePos); michael@0: MOZ_ASSERT(furthestBlockPos > nodePos); michael@0: removeFromStack(nodePos); michael@0: furthestBlockPos--; michael@0: continue; michael@0: } michael@0: if (nodePos == furthestBlockPos) { michael@0: bookmark = nodeListPos + 1; michael@0: } michael@0: MOZ_ASSERT(node == listOfActiveFormattingElements[nodeListPos]); michael@0: MOZ_ASSERT(node == stack[nodePos]); michael@0: nsIContentHandle* clone = createElement(kNameSpaceID_XHTML, node->name, node->attributes->cloneAttributes(nullptr)); michael@0: nsHtml5StackNode* newNode = new nsHtml5StackNode(node->getFlags(), node->ns, node->name, clone, node->popName, node->attributes); michael@0: node->dropAttributes(); michael@0: stack[nodePos] = newNode; michael@0: newNode->retain(); michael@0: listOfActiveFormattingElements[nodeListPos] = newNode; michael@0: node->release(); michael@0: node->release(); michael@0: node = newNode; michael@0: detachFromParent(lastNode->node); michael@0: appendElement(lastNode->node, node->node); michael@0: lastNode = node; michael@0: } michael@0: if (commonAncestor->isFosterParenting()) { michael@0: michael@0: detachFromParent(lastNode->node); michael@0: insertIntoFosterParent(lastNode->node); michael@0: } else { michael@0: detachFromParent(lastNode->node); michael@0: appendElement(lastNode->node, commonAncestor->node); michael@0: } michael@0: nsIContentHandle* clone = createElement(kNameSpaceID_XHTML, formattingElt->name, formattingElt->attributes->cloneAttributes(nullptr)); michael@0: nsHtml5StackNode* formattingClone = new nsHtml5StackNode(formattingElt->getFlags(), formattingElt->ns, formattingElt->name, clone, formattingElt->popName, formattingElt->attributes); michael@0: formattingElt->dropAttributes(); michael@0: appendChildrenToNewParent(furthestBlock->node, clone); michael@0: appendElement(clone, furthestBlock->node); michael@0: removeFromListOfActiveFormattingElements(formattingEltListPos); michael@0: insertIntoListOfActiveFormattingElements(formattingClone, bookmark); michael@0: MOZ_ASSERT(formattingEltStackPos < furthestBlockPos); michael@0: removeFromStack(formattingEltStackPos); michael@0: insertIntoStack(formattingClone, furthestBlockPos); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::insertIntoStack(nsHtml5StackNode* node, int32_t position) michael@0: { michael@0: MOZ_ASSERT(currentPtr + 1 < stack.length); michael@0: MOZ_ASSERT(position <= currentPtr + 1); michael@0: if (position == currentPtr + 1) { michael@0: push(node); michael@0: } else { michael@0: nsHtml5ArrayCopy::arraycopy(stack, position, position + 1, (currentPtr - position) + 1); michael@0: currentPtr++; michael@0: stack[position] = node; michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::insertIntoListOfActiveFormattingElements(nsHtml5StackNode* formattingClone, int32_t bookmark) michael@0: { michael@0: formattingClone->retain(); michael@0: MOZ_ASSERT(listPtr + 1 < listOfActiveFormattingElements.length); michael@0: if (bookmark <= listPtr) { michael@0: nsHtml5ArrayCopy::arraycopy(listOfActiveFormattingElements, bookmark, bookmark + 1, (listPtr - bookmark) + 1); michael@0: } michael@0: listPtr++; michael@0: listOfActiveFormattingElements[bookmark] = formattingClone; michael@0: } michael@0: michael@0: int32_t michael@0: nsHtml5TreeBuilder::findInListOfActiveFormattingElements(nsHtml5StackNode* node) michael@0: { michael@0: for (int32_t i = listPtr; i >= 0; i--) { michael@0: if (node == listOfActiveFormattingElements[i]) { michael@0: return i; michael@0: } michael@0: } michael@0: return -1; michael@0: } michael@0: michael@0: int32_t michael@0: nsHtml5TreeBuilder::findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker(nsIAtom* name) michael@0: { michael@0: for (int32_t i = listPtr; i >= 0; i--) { michael@0: nsHtml5StackNode* node = listOfActiveFormattingElements[i]; michael@0: if (!node) { michael@0: return -1; michael@0: } else if (node->name == name) { michael@0: return i; michael@0: } michael@0: } michael@0: return -1; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::maybeForgetEarlierDuplicateFormattingElement(nsIAtom* name, nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: int32_t candidate = -1; michael@0: int32_t count = 0; michael@0: for (int32_t i = listPtr; i >= 0; i--) { michael@0: nsHtml5StackNode* node = listOfActiveFormattingElements[i]; michael@0: if (!node) { michael@0: break; michael@0: } michael@0: if (node->name == name && node->attributes->equalsAnother(attributes)) { michael@0: candidate = i; michael@0: ++count; michael@0: } michael@0: } michael@0: if (count >= 3) { michael@0: removeFromListOfActiveFormattingElements(candidate); michael@0: } michael@0: } michael@0: michael@0: int32_t michael@0: nsHtml5TreeBuilder::findLastOrRoot(nsIAtom* name) michael@0: { michael@0: for (int32_t i = currentPtr; i > 0; i--) { michael@0: if (stack[i]->ns == kNameSpaceID_XHTML && stack[i]->name == name) { michael@0: return i; michael@0: } michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: int32_t michael@0: nsHtml5TreeBuilder::findLastOrRoot(int32_t group) michael@0: { michael@0: for (int32_t i = currentPtr; i > 0; i--) { michael@0: if (stack[i]->getGroup() == group) { michael@0: return i; michael@0: } michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::addAttributesToBody(nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: if (currentPtr >= 1) { michael@0: nsHtml5StackNode* body = stack[1]; michael@0: if (body->getGroup() == NS_HTML5TREE_BUILDER_BODY) { michael@0: addAttributesToElement(body->node, attributes); michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::addAttributesToHtml(nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: addAttributesToElement(stack[0]->node, attributes); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::pushHeadPointerOntoStack() michael@0: { michael@0: MOZ_ASSERT(!!headPointer); michael@0: MOZ_ASSERT(mode == NS_HTML5TREE_BUILDER_AFTER_HEAD); michael@0: michael@0: silentPush(new nsHtml5StackNode(nsHtml5ElementName::ELT_HEAD, headPointer)); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::reconstructTheActiveFormattingElements() michael@0: { michael@0: if (listPtr == -1) { michael@0: return; michael@0: } michael@0: nsHtml5StackNode* mostRecent = listOfActiveFormattingElements[listPtr]; michael@0: if (!mostRecent || isInStack(mostRecent)) { michael@0: return; michael@0: } michael@0: int32_t entryPos = listPtr; michael@0: for (; ; ) { michael@0: entryPos--; michael@0: if (entryPos == -1) { michael@0: break; michael@0: } michael@0: if (!listOfActiveFormattingElements[entryPos]) { michael@0: break; michael@0: } michael@0: if (isInStack(listOfActiveFormattingElements[entryPos])) { michael@0: break; michael@0: } michael@0: } michael@0: while (entryPos < listPtr) { michael@0: entryPos++; michael@0: nsHtml5StackNode* entry = listOfActiveFormattingElements[entryPos]; michael@0: nsIContentHandle* clone = createElement(kNameSpaceID_XHTML, entry->name, entry->attributes->cloneAttributes(nullptr)); michael@0: nsHtml5StackNode* entryClone = new nsHtml5StackNode(entry->getFlags(), entry->ns, entry->name, clone, entry->popName, entry->attributes); michael@0: entry->dropAttributes(); michael@0: nsHtml5StackNode* currentNode = stack[currentPtr]; michael@0: if (currentNode->isFosterParenting()) { michael@0: insertIntoFosterParent(clone); michael@0: } else { michael@0: appendElement(clone, currentNode->node); michael@0: } michael@0: push(entryClone); michael@0: listOfActiveFormattingElements[entryPos] = entryClone; michael@0: entry->release(); michael@0: entryClone->retain(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::insertIntoFosterParent(nsIContentHandle* child) michael@0: { michael@0: int32_t tablePos = findLastOrRoot(NS_HTML5TREE_BUILDER_TABLE); michael@0: int32_t templatePos = findLastOrRoot(NS_HTML5TREE_BUILDER_TEMPLATE); michael@0: if (templatePos >= tablePos) { michael@0: appendElement(child, stack[templatePos]->node); michael@0: return; michael@0: } michael@0: nsHtml5StackNode* node = stack[tablePos]; michael@0: insertFosterParentedChild(child, node->node, stack[tablePos - 1]->node); michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::isInStack(nsHtml5StackNode* node) michael@0: { michael@0: for (int32_t i = currentPtr; i >= 0; i--) { michael@0: if (stack[i] == node) { michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::popTemplateMode() michael@0: { michael@0: templateModePtr--; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::pop() michael@0: { michael@0: nsHtml5StackNode* node = stack[currentPtr]; michael@0: MOZ_ASSERT(debugOnlyClearLastStackSlot()); michael@0: currentPtr--; michael@0: elementPopped(node->ns, node->popName, node->node); michael@0: node->release(); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::silentPop() michael@0: { michael@0: nsHtml5StackNode* node = stack[currentPtr]; michael@0: MOZ_ASSERT(debugOnlyClearLastStackSlot()); michael@0: currentPtr--; michael@0: node->release(); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::popOnEof() michael@0: { michael@0: nsHtml5StackNode* node = stack[currentPtr]; michael@0: MOZ_ASSERT(debugOnlyClearLastStackSlot()); michael@0: currentPtr--; michael@0: markMalformedIfScript(node->node); michael@0: elementPopped(node->ns, node->popName, node->node); michael@0: node->release(); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::appendHtmlElementToDocumentAndPush(nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: nsIContentHandle* elt = createHtmlElementSetAsRoot(attributes); michael@0: nsHtml5StackNode* node = new nsHtml5StackNode(nsHtml5ElementName::ELT_HTML, elt); michael@0: push(node); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::appendHtmlElementToDocumentAndPush() michael@0: { michael@0: appendHtmlElementToDocumentAndPush(tokenizer->emptyAttributes()); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::appendToCurrentNodeAndPushHeadElement(nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: nsIContentHandle* elt = createElement(kNameSpaceID_XHTML, nsHtml5Atoms::head, attributes); michael@0: appendElement(elt, stack[currentPtr]->node); michael@0: headPointer = elt; michael@0: nsHtml5StackNode* node = new nsHtml5StackNode(nsHtml5ElementName::ELT_HEAD, elt); michael@0: push(node); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::appendToCurrentNodeAndPushBodyElement(nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: appendToCurrentNodeAndPushElement(nsHtml5ElementName::ELT_BODY, attributes); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::appendToCurrentNodeAndPushBodyElement() michael@0: { michael@0: appendToCurrentNodeAndPushBodyElement(tokenizer->emptyAttributes()); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::appendToCurrentNodeAndPushFormElementMayFoster(nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: nsIContentHandle* elt = createElement(kNameSpaceID_XHTML, nsHtml5Atoms::form, attributes); michael@0: if (!isTemplateContents()) { michael@0: formPointer = elt; michael@0: } michael@0: nsHtml5StackNode* current = stack[currentPtr]; michael@0: if (current->isFosterParenting()) { michael@0: michael@0: insertIntoFosterParent(elt); michael@0: } else { michael@0: appendElement(elt, current->node); michael@0: } michael@0: nsHtml5StackNode* node = new nsHtml5StackNode(nsHtml5ElementName::ELT_FORM, elt); michael@0: push(node); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::appendToCurrentNodeAndPushFormattingElementMayFoster(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: nsHtml5HtmlAttributes* clone = attributes->cloneAttributes(nullptr); michael@0: nsIContentHandle* elt = createElement(kNameSpaceID_XHTML, elementName->name, attributes); michael@0: nsHtml5StackNode* current = stack[currentPtr]; michael@0: if (current->isFosterParenting()) { michael@0: michael@0: insertIntoFosterParent(elt); michael@0: } else { michael@0: appendElement(elt, current->node); michael@0: } michael@0: nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt, clone); michael@0: push(node); michael@0: append(node); michael@0: node->retain(); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::appendToCurrentNodeAndPushElement(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: nsIContentHandle* elt = createElement(kNameSpaceID_XHTML, elementName->name, attributes); michael@0: appendElement(elt, stack[currentPtr]->node); michael@0: if (nsHtml5ElementName::ELT_TEMPLATE == elementName) { michael@0: elt = getDocumentFragmentForTemplate(elt); michael@0: } michael@0: nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt); michael@0: push(node); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFoster(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: nsIAtom* popName = elementName->name; michael@0: nsIContentHandle* elt = createElement(kNameSpaceID_XHTML, popName, attributes); michael@0: nsHtml5StackNode* current = stack[currentPtr]; michael@0: if (current->isFosterParenting()) { michael@0: michael@0: insertIntoFosterParent(elt); michael@0: } else { michael@0: appendElement(elt, current->node); michael@0: } michael@0: nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt, popName); michael@0: push(node); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFosterMathML(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: nsIAtom* popName = elementName->name; michael@0: bool markAsHtmlIntegrationPoint = false; michael@0: if (nsHtml5ElementName::ELT_ANNOTATION_XML == elementName && annotationXmlEncodingPermitsHtml(attributes)) { michael@0: markAsHtmlIntegrationPoint = true; michael@0: } michael@0: nsIContentHandle* elt = createElement(kNameSpaceID_MathML, popName, attributes); michael@0: nsHtml5StackNode* current = stack[currentPtr]; michael@0: if (current->isFosterParenting()) { michael@0: michael@0: insertIntoFosterParent(elt); michael@0: } else { michael@0: appendElement(elt, current->node); michael@0: } michael@0: nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt, popName, markAsHtmlIntegrationPoint); michael@0: push(node); michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::annotationXmlEncodingPermitsHtml(nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: nsString* encoding = attributes->getValue(nsHtml5AttributeName::ATTR_ENCODING); michael@0: if (!encoding) { michael@0: return false; michael@0: } michael@0: return nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("application/xhtml+xml", encoding) || nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString("text/html", encoding); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFosterSVG(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: nsIAtom* popName = elementName->camelCaseName; michael@0: nsIContentHandle* elt = createElement(kNameSpaceID_SVG, popName, attributes); michael@0: nsHtml5StackNode* current = stack[currentPtr]; michael@0: if (current->isFosterParenting()) { michael@0: michael@0: insertIntoFosterParent(elt); michael@0: } else { michael@0: appendElement(elt, current->node); michael@0: } michael@0: nsHtml5StackNode* node = new nsHtml5StackNode(elementName, popName, elt); michael@0: push(node); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFoster(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes, nsIContentHandle* form) michael@0: { michael@0: nsIContentHandle* elt = createElement(kNameSpaceID_XHTML, elementName->name, attributes, !form || fragment || isTemplateContents() ? nullptr : form); michael@0: nsHtml5StackNode* current = stack[currentPtr]; michael@0: if (current->isFosterParenting()) { michael@0: michael@0: insertIntoFosterParent(elt); michael@0: } else { michael@0: appendElement(elt, current->node); michael@0: } michael@0: nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt); michael@0: push(node); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::appendVoidElementToCurrentMayFoster(nsIAtom* name, nsHtml5HtmlAttributes* attributes, nsIContentHandle* form) michael@0: { michael@0: nsIContentHandle* elt = createElement(kNameSpaceID_XHTML, name, attributes, !form || fragment || isTemplateContents() ? nullptr : form); michael@0: nsHtml5StackNode* current = stack[currentPtr]; michael@0: if (current->isFosterParenting()) { michael@0: michael@0: insertIntoFosterParent(elt); michael@0: } else { michael@0: appendElement(elt, current->node); michael@0: } michael@0: elementPushed(kNameSpaceID_XHTML, name, elt); michael@0: elementPopped(kNameSpaceID_XHTML, name, elt); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::appendVoidElementToCurrentMayFoster(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: nsIAtom* popName = elementName->name; michael@0: nsIContentHandle* elt = createElement(kNameSpaceID_XHTML, popName, attributes); michael@0: nsHtml5StackNode* current = stack[currentPtr]; michael@0: if (current->isFosterParenting()) { michael@0: michael@0: insertIntoFosterParent(elt); michael@0: } else { michael@0: appendElement(elt, current->node); michael@0: } michael@0: elementPushed(kNameSpaceID_XHTML, popName, elt); michael@0: elementPopped(kNameSpaceID_XHTML, popName, elt); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::appendVoidElementToCurrentMayFosterSVG(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: nsIAtom* popName = elementName->camelCaseName; michael@0: nsIContentHandle* elt = createElement(kNameSpaceID_SVG, popName, attributes); michael@0: nsHtml5StackNode* current = stack[currentPtr]; michael@0: if (current->isFosterParenting()) { michael@0: michael@0: insertIntoFosterParent(elt); michael@0: } else { michael@0: appendElement(elt, current->node); michael@0: } michael@0: elementPushed(kNameSpaceID_SVG, popName, elt); michael@0: elementPopped(kNameSpaceID_SVG, popName, elt); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::appendVoidElementToCurrentMayFosterMathML(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: nsIAtom* popName = elementName->name; michael@0: nsIContentHandle* elt = createElement(kNameSpaceID_MathML, popName, attributes); michael@0: nsHtml5StackNode* current = stack[currentPtr]; michael@0: if (current->isFosterParenting()) { michael@0: michael@0: insertIntoFosterParent(elt); michael@0: } else { michael@0: appendElement(elt, current->node); michael@0: } michael@0: elementPushed(kNameSpaceID_MathML, popName, elt); michael@0: elementPopped(kNameSpaceID_MathML, popName, elt); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::appendVoidElementToCurrent(nsIAtom* name, nsHtml5HtmlAttributes* attributes, nsIContentHandle* form) michael@0: { michael@0: nsIContentHandle* elt = createElement(kNameSpaceID_XHTML, name, attributes, !form || fragment || isTemplateContents() ? nullptr : form); michael@0: nsHtml5StackNode* current = stack[currentPtr]; michael@0: appendElement(elt, current->node); michael@0: elementPushed(kNameSpaceID_XHTML, name, elt); michael@0: elementPopped(kNameSpaceID_XHTML, name, elt); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::appendVoidFormToCurrent(nsHtml5HtmlAttributes* attributes) michael@0: { michael@0: nsIContentHandle* elt = createElement(kNameSpaceID_XHTML, nsHtml5Atoms::form, attributes); michael@0: formPointer = elt; michael@0: nsHtml5StackNode* current = stack[currentPtr]; michael@0: appendElement(elt, current->node); michael@0: elementPushed(kNameSpaceID_XHTML, nsHtml5Atoms::form, elt); michael@0: elementPopped(kNameSpaceID_XHTML, nsHtml5Atoms::form, elt); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::requestSuspension() michael@0: { michael@0: tokenizer->requestSuspension(); michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::isInForeign() michael@0: { michael@0: return currentPtr >= 0 && stack[currentPtr]->ns != kNameSpaceID_XHTML; michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::isInForeignButNotHtmlOrMathTextIntegrationPoint() michael@0: { michael@0: if (currentPtr < 0) { michael@0: return false; michael@0: } michael@0: return !isSpecialParentInForeign(stack[currentPtr]); michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::setFragmentContext(nsIAtom* context, int32_t ns, nsIContentHandle* node, bool quirks) michael@0: { michael@0: this->contextName = context; michael@0: this->contextNamespace = ns; michael@0: this->contextNode = node; michael@0: this->fragment = (!!contextName); michael@0: this->quirks = quirks; michael@0: } michael@0: michael@0: nsIContentHandle* michael@0: nsHtml5TreeBuilder::currentNode() michael@0: { michael@0: return stack[currentPtr]->node; michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::isScriptingEnabled() michael@0: { michael@0: return scriptingEnabled; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::setScriptingEnabled(bool scriptingEnabled) michael@0: { michael@0: this->scriptingEnabled = scriptingEnabled; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::setIsSrcdocDocument(bool isSrcdocDocument) michael@0: { michael@0: this->isSrcdocDocument = isSrcdocDocument; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::flushCharacters() michael@0: { michael@0: if (charBufferLen > 0) { michael@0: if ((mode == NS_HTML5TREE_BUILDER_IN_TABLE || mode == NS_HTML5TREE_BUILDER_IN_TABLE_BODY || mode == NS_HTML5TREE_BUILDER_IN_ROW) && charBufferContainsNonWhitespace()) { michael@0: errNonSpaceInTable(); michael@0: reconstructTheActiveFormattingElements(); michael@0: if (!stack[currentPtr]->isFosterParenting()) { michael@0: appendCharacters(currentNode(), charBuffer, 0, charBufferLen); michael@0: charBufferLen = 0; michael@0: return; michael@0: } michael@0: int32_t tablePos = findLastOrRoot(NS_HTML5TREE_BUILDER_TABLE); michael@0: int32_t templatePos = findLastOrRoot(NS_HTML5TREE_BUILDER_TEMPLATE); michael@0: if (templatePos >= tablePos) { michael@0: appendCharacters(stack[templatePos]->node, charBuffer, 0, charBufferLen); michael@0: charBufferLen = 0; michael@0: return; michael@0: } michael@0: nsHtml5StackNode* tableElt = stack[tablePos]; michael@0: insertFosterParentedCharacters(charBuffer, 0, charBufferLen, tableElt->node, stack[tablePos - 1]->node); michael@0: charBufferLen = 0; michael@0: return; michael@0: } michael@0: appendCharacters(currentNode(), charBuffer, 0, charBufferLen); michael@0: charBufferLen = 0; michael@0: } michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::charBufferContainsNonWhitespace() michael@0: { michael@0: for (int32_t i = 0; i < charBufferLen; i++) { michael@0: switch(charBuffer[i]) { michael@0: case ' ': michael@0: case '\t': michael@0: case '\n': michael@0: case '\r': michael@0: case '\f': { michael@0: continue; michael@0: } michael@0: default: { michael@0: return true; michael@0: } michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: nsAHtml5TreeBuilderState* michael@0: nsHtml5TreeBuilder::newSnapshot() michael@0: { michael@0: jArray listCopy = jArray::newJArray(listPtr + 1); michael@0: for (int32_t i = 0; i < listCopy.length; i++) { michael@0: nsHtml5StackNode* node = listOfActiveFormattingElements[i]; michael@0: if (node) { michael@0: nsHtml5StackNode* newNode = new nsHtml5StackNode(node->getFlags(), node->ns, node->name, node->node, node->popName, node->attributes->cloneAttributes(nullptr)); michael@0: listCopy[i] = newNode; michael@0: } else { michael@0: listCopy[i] = nullptr; michael@0: } michael@0: } michael@0: jArray stackCopy = jArray::newJArray(currentPtr + 1); michael@0: for (int32_t i = 0; i < stackCopy.length; i++) { michael@0: nsHtml5StackNode* node = stack[i]; michael@0: int32_t listIndex = findInListOfActiveFormattingElements(node); michael@0: if (listIndex == -1) { michael@0: nsHtml5StackNode* newNode = new nsHtml5StackNode(node->getFlags(), node->ns, node->name, node->node, node->popName, nullptr); michael@0: stackCopy[i] = newNode; michael@0: } else { michael@0: stackCopy[i] = listCopy[listIndex]; michael@0: stackCopy[i]->retain(); michael@0: } michael@0: } michael@0: jArray templateModeStackCopy = jArray::newJArray(templateModePtr + 1); michael@0: nsHtml5ArrayCopy::arraycopy(templateModeStack, templateModeStackCopy, templateModeStackCopy.length); michael@0: return new nsHtml5StateSnapshot(stackCopy, listCopy, templateModeStackCopy, formPointer, headPointer, deepTreeSurrogateParent, mode, originalMode, framesetOk, needToDropLF, quirks); michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::snapshotMatches(nsAHtml5TreeBuilderState* snapshot) michael@0: { michael@0: jArray stackCopy = snapshot->getStack(); michael@0: int32_t stackLen = snapshot->getStackLength(); michael@0: jArray listCopy = snapshot->getListOfActiveFormattingElements(); michael@0: int32_t listLen = snapshot->getListOfActiveFormattingElementsLength(); michael@0: jArray templateModeStackCopy = snapshot->getTemplateModeStack(); michael@0: int32_t templateModeStackLen = snapshot->getTemplateModeStackLength(); michael@0: if (stackLen != currentPtr + 1 || listLen != listPtr + 1 || templateModeStackLen != templateModePtr + 1 || formPointer != snapshot->getFormPointer() || headPointer != snapshot->getHeadPointer() || deepTreeSurrogateParent != snapshot->getDeepTreeSurrogateParent() || mode != snapshot->getMode() || originalMode != snapshot->getOriginalMode() || framesetOk != snapshot->isFramesetOk() || needToDropLF != snapshot->isNeedToDropLF() || quirks != snapshot->isQuirks()) { michael@0: return false; michael@0: } michael@0: for (int32_t i = listLen - 1; i >= 0; i--) { michael@0: if (!listCopy[i] && !listOfActiveFormattingElements[i]) { michael@0: continue; michael@0: } else if (!listCopy[i] || !listOfActiveFormattingElements[i]) { michael@0: return false; michael@0: } michael@0: if (listCopy[i]->node != listOfActiveFormattingElements[i]->node) { michael@0: return false; michael@0: } michael@0: } michael@0: for (int32_t i = stackLen - 1; i >= 0; i--) { michael@0: if (stackCopy[i]->node != stack[i]->node) { michael@0: return false; michael@0: } michael@0: } michael@0: for (int32_t i = templateModeStackLen - 1; i >= 0; i--) { michael@0: if (templateModeStackCopy[i] != templateModeStack[i]) { michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::loadState(nsAHtml5TreeBuilderState* snapshot, nsHtml5AtomTable* interner) michael@0: { michael@0: jArray stackCopy = snapshot->getStack(); michael@0: int32_t stackLen = snapshot->getStackLength(); michael@0: jArray listCopy = snapshot->getListOfActiveFormattingElements(); michael@0: int32_t listLen = snapshot->getListOfActiveFormattingElementsLength(); michael@0: jArray templateModeStackCopy = snapshot->getTemplateModeStack(); michael@0: int32_t templateModeStackLen = snapshot->getTemplateModeStackLength(); michael@0: for (int32_t i = 0; i <= listPtr; i++) { michael@0: if (listOfActiveFormattingElements[i]) { michael@0: listOfActiveFormattingElements[i]->release(); michael@0: } michael@0: } michael@0: if (listOfActiveFormattingElements.length < listLen) { michael@0: listOfActiveFormattingElements = jArray::newJArray(listLen); michael@0: } michael@0: listPtr = listLen - 1; michael@0: for (int32_t i = 0; i <= currentPtr; i++) { michael@0: stack[i]->release(); michael@0: } michael@0: if (stack.length < stackLen) { michael@0: stack = jArray::newJArray(stackLen); michael@0: } michael@0: currentPtr = stackLen - 1; michael@0: if (templateModeStack.length < templateModeStackLen) { michael@0: templateModeStack = jArray::newJArray(templateModeStackLen); michael@0: } michael@0: templateModePtr = templateModeStackLen - 1; michael@0: for (int32_t i = 0; i < listLen; i++) { michael@0: nsHtml5StackNode* node = listCopy[i]; michael@0: if (node) { michael@0: nsHtml5StackNode* newNode = new nsHtml5StackNode(node->getFlags(), node->ns, nsHtml5Portability::newLocalFromLocal(node->name, interner), node->node, nsHtml5Portability::newLocalFromLocal(node->popName, interner), node->attributes->cloneAttributes(nullptr)); michael@0: listOfActiveFormattingElements[i] = newNode; michael@0: } else { michael@0: listOfActiveFormattingElements[i] = nullptr; michael@0: } michael@0: } michael@0: for (int32_t i = 0; i < stackLen; i++) { michael@0: nsHtml5StackNode* node = stackCopy[i]; michael@0: int32_t listIndex = findInArray(node, listCopy); michael@0: if (listIndex == -1) { michael@0: nsHtml5StackNode* newNode = new nsHtml5StackNode(node->getFlags(), node->ns, nsHtml5Portability::newLocalFromLocal(node->name, interner), node->node, nsHtml5Portability::newLocalFromLocal(node->popName, interner), nullptr); michael@0: stack[i] = newNode; michael@0: } else { michael@0: stack[i] = listOfActiveFormattingElements[listIndex]; michael@0: stack[i]->retain(); michael@0: } michael@0: } michael@0: nsHtml5ArrayCopy::arraycopy(templateModeStackCopy, templateModeStack, templateModeStackLen); michael@0: formPointer = snapshot->getFormPointer(); michael@0: headPointer = snapshot->getHeadPointer(); michael@0: deepTreeSurrogateParent = snapshot->getDeepTreeSurrogateParent(); michael@0: mode = snapshot->getMode(); michael@0: originalMode = snapshot->getOriginalMode(); michael@0: framesetOk = snapshot->isFramesetOk(); michael@0: needToDropLF = snapshot->isNeedToDropLF(); michael@0: quirks = snapshot->isQuirks(); michael@0: } michael@0: michael@0: int32_t michael@0: nsHtml5TreeBuilder::findInArray(nsHtml5StackNode* node, jArray arr) michael@0: { michael@0: for (int32_t i = listPtr; i >= 0; i--) { michael@0: if (node == arr[i]) { michael@0: return i; michael@0: } michael@0: } michael@0: return -1; michael@0: } michael@0: michael@0: nsIContentHandle* michael@0: nsHtml5TreeBuilder::getFormPointer() michael@0: { michael@0: return formPointer; michael@0: } michael@0: michael@0: nsIContentHandle* michael@0: nsHtml5TreeBuilder::getHeadPointer() michael@0: { michael@0: return headPointer; michael@0: } michael@0: michael@0: nsIContentHandle* michael@0: nsHtml5TreeBuilder::getDeepTreeSurrogateParent() michael@0: { michael@0: return deepTreeSurrogateParent; michael@0: } michael@0: michael@0: jArray michael@0: nsHtml5TreeBuilder::getListOfActiveFormattingElements() michael@0: { michael@0: return listOfActiveFormattingElements; michael@0: } michael@0: michael@0: jArray michael@0: nsHtml5TreeBuilder::getStack() michael@0: { michael@0: return stack; michael@0: } michael@0: michael@0: jArray michael@0: nsHtml5TreeBuilder::getTemplateModeStack() michael@0: { michael@0: return templateModeStack; michael@0: } michael@0: michael@0: int32_t michael@0: nsHtml5TreeBuilder::getMode() michael@0: { michael@0: return mode; michael@0: } michael@0: michael@0: int32_t michael@0: nsHtml5TreeBuilder::getOriginalMode() michael@0: { michael@0: return originalMode; michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::isFramesetOk() michael@0: { michael@0: return framesetOk; michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::isNeedToDropLF() michael@0: { michael@0: return needToDropLF; michael@0: } michael@0: michael@0: bool michael@0: nsHtml5TreeBuilder::isQuirks() michael@0: { michael@0: return quirks; michael@0: } michael@0: michael@0: int32_t michael@0: nsHtml5TreeBuilder::getListOfActiveFormattingElementsLength() michael@0: { michael@0: return listPtr + 1; michael@0: } michael@0: michael@0: int32_t michael@0: nsHtml5TreeBuilder::getStackLength() michael@0: { michael@0: return currentPtr + 1; michael@0: } michael@0: michael@0: int32_t michael@0: nsHtml5TreeBuilder::getTemplateModeStackLength() michael@0: { michael@0: return templateModePtr + 1; michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::initializeStatics() michael@0: { michael@0: } michael@0: michael@0: void michael@0: nsHtml5TreeBuilder::releaseStatics() michael@0: { michael@0: } michael@0: michael@0: michael@0: #include "nsHtml5TreeBuilderCppSupplement.h" michael@0: